Compare commits

..
195 Commits
Author SHA1 Message Date
bellard df0f11a03b update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@197 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-28 00:27:57 +00:00
bellard 2d92f0b8f0 autogen opc-i386.h
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@196 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-28 00:24:44 +00:00
bellard aad13cd131 segment defines
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@195 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-27 23:30:06 +00:00
bellard a513fe19ac precise exceptions
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@194 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-27 23:29:48 +00:00
bellard f4beb510a4 precise exceptions - more accurate interrupt semantics
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@193 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-27 23:28:08 +00:00
bellard d731dae8e3 currently generated
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@192 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-27 23:26:25 +00:00
bellard c9087c2a60 cr2 update (dosemu VGA support fix)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@191 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-27 23:25:41 +00:00
bellard 14ae3ba7f9 mmap2 fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@190 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-27 23:25:06 +00:00
bellard 5a91de8c90 precise exception support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@189 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-27 23:24:27 +00:00
bellard e3b32540df more exception tests - support for precise exceptions
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@188 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-27 23:23:22 +00:00
bellard a37904dd86 fwait fix (aka DOS Navigator fix)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@187 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-25 23:10:30 +00:00
bellard cf25629d1e more efficient locking
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@186 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-25 19:20:31 +00:00
bellard 0ca790b92e direct chaining for PowerPC and i386
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@185 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-25 16:51:57 +00:00
bellard d1fe2b2459 self modifying code also tests translation block chaining invalidation
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@184 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-25 16:47:16 +00:00
bellard d4e8164f7e direct chaining for PowerPC and i386
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@183 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-25 16:46:15 +00:00
bellard 08351fb37a fixed cast
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@182 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-25 16:42:20 +00:00
bellard 85e53d4108 update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@181 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-25 16:41:52 +00:00
bellard aa05ae6fec added exec.h
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@180 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-25 16:41:18 +00:00
bellard 1565b7bcd7 fixed page_unprotect() if host_page_size > TARGET_PAGE_SIZE
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@179 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-16 16:07:10 +00:00
bellard b409186b8d added getrusage
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@178 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-16 15:39:34 +00:00
bellard 418a97afa1 fixed 32 bit popf/iret emulation in vm86 mode
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@177 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-16 15:12:51 +00:00
bellard 5132455efe test-i386 update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@176 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-16 13:58:37 +00:00
bellard c0ad5542a8 fixed popf TF flag bug (should never hapen in user code except in test-i386!)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@175 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-16 13:46:28 +00:00
bellard 3a27ad0b57 added vm86, exceptions and self modifying regression tests
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@174 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-16 13:43:31 +00:00
bellard 2b413144dc cosmetics
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@173 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-14 23:01:10 +00:00
bellard 3ebcc707d2 removed invalid eip update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@172 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-14 22:47:15 +00:00
bellard 7775e9ecc2 added do_fcntl()
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@171 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-14 22:46:48 +00:00
bellard 03d843ddf2 fixed invalid signal masking
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@170 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-14 22:41:55 +00:00
bellard eb51d102bb better locks
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@169 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-14 21:51:13 +00:00
bellard 25eb44841e better locking - added PowerPC signal handler (add it for the other archs too because it needed for full exception support)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@168 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-14 21:50:54 +00:00
bellard b333af0666 removed trace - merged 2.4.20 vm86 patches
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@167 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-14 21:48:51 +00:00
bellard 76c8b7710b file list update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@166 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-14 19:48:46 +00:00
bellard 70e198602b update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@165 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-14 19:02:49 +00:00
bellard 206f0fa759 pread/pwrite syscalls - use page_unprotect_range() in vital cases to avoid problems if the kernel writes data in protected page (needed for self-modifying code support)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@164 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-14 19:01:56 +00:00
bellard fd6ce8f660 self-modifying code support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@163 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-14 19:00:11 +00:00
bellard 727d01d4f6 return code size
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@162 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-14 18:58:05 +00:00
bellard ae22853141 Sparc update (David S. Miller)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@161 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-13 18:59:59 +00:00
bellard d418c81eff fixed small page handling
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@160 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-13 00:57:50 +00:00
bellard 2a29ca73c9 more exception tests
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@159 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-13 00:29:04 +00:00
bellard 54936004fd mmap emulation
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@158 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-13 00:25:15 +00:00
bellard 74c95119f2 Alpha fixes (Falk Hueffner)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@157 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-11 12:27:31 +00:00
bellard 366c1b8bfa warning fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@156 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-11 12:27:02 +00:00
bellard a993ba85cf alpha disas (Falk Hueffner)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@155 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-11 12:25:45 +00:00
bellard 226c91327d fixed from 2.4.20 kernel
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@154 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-10 21:41:47 +00:00
bellard b8bf3e3aac eflags fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@153 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-10 21:39:42 +00:00
bellard 288426fe3c added LAR/LSL tests
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@152 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-10 21:39:12 +00:00
bellard 72cc388104 fixed SHL C flag computation
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@151 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-10 21:38:19 +00:00
bellard 378180d8dc added LAR/LSL
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@150 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-10 21:37:51 +00:00
bellard 78c34e98cd added LAR/LSL - fixed INT3 and INTO EIP computation
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@149 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-10 21:37:05 +00:00
bellard 2792c4f2af added EIP return to INTO - fixed SHL C flag computation - added LAR/LSL
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@148 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-10 21:35:30 +00:00
bellard 447db2139a sigtrap support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@147 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-10 15:10:36 +00:00
bellard 564c8f9978 simplified exception support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@146 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-10 15:10:02 +00:00
bellard c50c0c3fbf TF flag support - fixed eflags computation before exception
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@145 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-10 15:07:51 +00:00
bellard cabb4d616d TF flag support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@144 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-10 15:07:00 +00:00
bellard 631271d716 added vm86.c
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@143 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-10 13:14:52 +00:00
bellard 9d27abd94f fixed invalid CPL logic in vm86 mode - use generic CPU dump state function
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@142 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-10 13:13:54 +00:00
bellard 148dfc2a8b fixed GPF generation - fixed 'lret im' instruction (main fix for dosemu) - fixed HLT instruction
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@141 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-10 13:09:33 +00:00
bellard 3acace1333 removed unnecessary VME support - fixed selector GPF exception
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@140 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-10 12:39:11 +00:00
bellard 0221cfcd71 more console ioctls
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@139 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-10 12:38:16 +00:00
bellard f351077efb added dump function
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@138 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-10 12:37:32 +00:00
bellard e84be9dbca added vm86.c
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@137 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-10 12:37:12 +00:00
bellard 46ddf5511d vm86 emulation closer to Linux kernel code - added correct IRQ emulation for dosemu
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@136 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-10 12:36:41 +00:00
bellard 89e957e7a2 moved vm86 stuff to vm86.c
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@135 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-10 12:33:15 +00:00
bellard 982b431579 added CPL/IOPL support - fixed subtle inc/dec flag optimisation bug - added HLT instruction
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@134 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-08 15:44:24 +00:00
bellard bf7c65bdf4 changed I/O function prototype to include emulator state
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@133 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-08 15:42:38 +00:00
bellard 8e5a0667f8 added KDGKBTYPE
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@132 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-08 15:42:10 +00:00
bellard 19b84f3c35 added setgroups and getgroups syscalls
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@131 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-08 15:41:49 +00:00
bellard 08fc60898b more siginfo constants
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@130 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-08 15:41:15 +00:00
bellard 082391983e added op_gpf
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@129 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-08 15:40:45 +00:00
bellard 504e56ebdc more accurate GPF generation
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@128 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-08 15:39:48 +00:00
bellard 455b761956 added raise_exception_err()
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@127 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-08 15:38:21 +00:00
bellard b56dad1c7b added raise_exception_err() - added cr2 update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@126 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-08 15:38:04 +00:00
bellard 9ba5695ce5 added CPL and IOPL as translation time constants - changed I/O function prototype to include emulator state - added error_code and cr2 support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@125 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-08 15:35:34 +00:00
bellard 66099dd9af added trapno and error_code report in ucontext
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@124 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-08 15:34:02 +00:00
bellard b689bc57d6 more accurate signal handling
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@123 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-08 15:33:33 +00:00
bellard a69d83b60b systematic exception test
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@122 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-08 15:32:33 +00:00
bellard 86840ae241 update (test)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@121 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-08 15:30:27 +00:00
bellard 3c51961e0e update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@120 c046a42c-6fe2-441c-8c8c-71466251a162
2003-04-29 21:34:02 +00:00
bellard d014c98c8d sparc support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@119 c046a42c-6fe2-441c-8c8c-71466251a162
2003-04-29 21:26:53 +00:00
bellard a98fd896cd target cpu definition
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@118 c046a42c-6fe2-441c-8c8c-71466251a162
2003-04-29 21:24:12 +00:00
bellard d6cdca958e alpha support - ia64 support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@117 c046a42c-6fe2-441c-8c8c-71466251a162
2003-04-29 21:24:00 +00:00
bellard efdea7bf19 ia64 support - alpha support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@116 c046a42c-6fe2-441c-8c8c-71466251a162
2003-04-29 21:12:28 +00:00
bellard 0d3301964d ia64 support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@115 c046a42c-6fe2-441c-8c8c-71466251a162
2003-04-29 21:10:09 +00:00
bellard fe1e3ce3e9 fcntl constants
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@114 c046a42c-6fe2-441c-8c8c-71466251a162
2003-04-29 21:09:46 +00:00
bellard bb326a3749 fix _start routine name
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@113 c046a42c-6fe2-441c-8c8c-71466251a162
2003-04-29 21:08:48 +00:00
bellard 27725c1d74 ia64 support - fcntl uses TARGET_ constants
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@112 c046a42c-6fe2-441c-8c8c-71466251a162
2003-04-29 21:08:18 +00:00
bellard e026db5893 alpha support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@111 c046a42c-6fe2-441c-8c8c-71466251a162
2003-04-29 21:07:28 +00:00
bellard 43f04c233c alpha support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@110 c046a42c-6fe2-441c-8c8c-71466251a162
2003-04-29 20:53:42 +00:00
bellard a8baa8c555 ia64 support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@109 c046a42c-6fe2-441c-8c8c-71466251a162
2003-04-29 20:53:31 +00:00
bellard 728584be27 fstat64 fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@108 c046a42c-6fe2-441c-8c8c-71466251a162
2003-04-29 20:43:36 +00:00
bellard b9adb4a6bc PowerPC disas code
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@107 c046a42c-6fe2-441c-8c8c-71466251a162
2003-04-29 20:41:16 +00:00
bellard ae48a07313 flock
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@106 c046a42c-6fe2-441c-8c8c-71466251a162
2003-04-29 20:41:02 +00:00
bellard 956034d7e5 log fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@105 c046a42c-6fe2-441c-8c8c-71466251a162
2003-04-29 20:40:53 +00:00
bellard 6cd9f35b9b update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@104 c046a42c-6fe2-441c-8c8c-71466251a162
2003-04-29 20:40:35 +00:00
bellard 689f936f7e symbol fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@103 c046a42c-6fe2-441c-8c8c-71466251a162
2003-04-29 20:40:07 +00:00
bellard 6977fbfd8b loglevel export
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@102 c046a42c-6fe2-441c-8c8c-71466251a162
2003-04-29 20:39:23 +00:00
bellard 77e4672d8d flock support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@101 c046a42c-6fe2-441c-8c8c-71466251a162
2003-04-29 20:39:06 +00:00
bellard d34720fd7d comment
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@100 c046a42c-6fe2-441c-8c8c-71466251a162
2003-04-29 20:37:44 +00:00
bellard d9c4d1cc1a cleanup
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@99 c046a42c-6fe2-441c-8c8c-71466251a162
2003-04-29 20:37:14 +00:00
bellard f644caa51a update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@98 c046a42c-6fe2-441c-8c8c-71466251a162
2003-04-11 01:17:32 +00:00
bellard 1eb87257da update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@97 c046a42c-6fe2-441c-8c8c-71466251a162
2003-04-11 01:12:28 +00:00
bellard 32ce63371a path patch
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@96 c046a42c-6fe2-441c-8c8c-71466251a162
2003-04-11 00:16:16 +00:00
bellard ec86b0fb3a stat patches - path patches - added exit_group() syscall
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@95 c046a42c-6fe2-441c-8c8c-71466251a162
2003-04-11 00:15:04 +00:00
bellard 1d346ae63a added prefix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@94 c046a42c-6fe2-441c-8c8c-71466251a162
2003-04-11 00:14:24 +00:00
bellard 74cd30b811 RH9 fix - path patch
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@93 c046a42c-6fe2-441c-8c8c-71466251a162
2003-04-11 00:13:41 +00:00
bellard 7fb9a24e39 update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@92 c046a42c-6fe2-441c-8c8c-71466251a162
2003-04-11 00:13:04 +00:00
bellard afeb6ee377 suppressed undefined shldw shrdw
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@91 c046a42c-6fe2-441c-8c8c-71466251a162
2003-04-11 00:12:54 +00:00
bellard f29042b531 TIOCGPTN and TIOCSPTLCK ioctls
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@90 c046a42c-6fe2-441c-8c8c-71466251a162
2003-04-10 00:12:45 +00:00
bellard 09bfb054fb first self virtualizable version
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@89 c046a42c-6fe2-441c-8c8c-71466251a162
2003-04-10 00:03:40 +00:00
bellard 2677e107e6 warning fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@88 c046a42c-6fe2-441c-8c8c-71466251a162
2003-04-10 00:03:27 +00:00
bellard 66cd58461d update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@87 c046a42c-6fe2-441c-8c8c-71466251a162
2003-04-10 00:02:58 +00:00
bellard bb0ebb1f2d ISO C fixes
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@86 c046a42c-6fe2-441c-8c8c-71466251a162
2003-04-10 00:02:33 +00:00
bellard 27c75a9a90 update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@85 c046a42c-6fe2-441c-8c8c-71466251a162
2003-04-07 21:35:21 +00:00
bellard d0cd3b8d84 64 bit fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@84 c046a42c-6fe2-441c-8c8c-71466251a162
2003-04-07 21:35:13 +00:00
bellard 9af9eaaa76 endian fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@83 c046a42c-6fe2-441c-8c8c-71466251a162
2003-04-07 21:34:41 +00:00
bellard 8c8f42f76c clock_t fixes
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@82 c046a42c-6fe2-441c-8c8c-71466251a162
2003-04-07 21:34:27 +00:00
bellard 51fe68905b powerpc div and rint fixes
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@81 c046a42c-6fe2-441c-8c8c-71466251a162
2003-04-07 21:34:14 +00:00
bellard 7fe70ecc56 powerpc fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@80 c046a42c-6fe2-441c-8c8c-71466251a162
2003-04-07 21:33:40 +00:00
bellard d03cda5923 alpha fix - powerpc fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@79 c046a42c-6fe2-441c-8c8c-71466251a162
2003-04-07 21:33:21 +00:00
bellard 30ac07d4f0 moved i386 specific stuff outside elf.h
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@78 c046a42c-6fe2-441c-8c8c-71466251a162
2003-04-07 21:33:03 +00:00
bellard 8857052055 more cpu support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@77 c046a42c-6fe2-441c-8c8c-71466251a162
2003-04-07 21:32:32 +00:00
bellard ce11fedc6e 64 bit support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@76 c046a42c-6fe2-441c-8c8c-71466251a162
2003-04-07 21:32:22 +00:00
bellard 43d4145a98 bfd.h dependancy removed
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@75 c046a42c-6fe2-441c-8c8c-71466251a162
2003-04-07 21:31:44 +00:00
bellard 295defa5f1 alpha addition
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@74 c046a42c-6fe2-441c-8c8c-71466251a162
2003-04-07 21:31:29 +00:00
bellard f801f97e04 personality fix - i386 interpreter fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@73 c046a42c-6fe2-441c-8c8c-71466251a162
2003-04-07 21:31:06 +00:00
bellard f48c3dd51a -statis for test-i386
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@72 c046a42c-6fe2-441c-8c8c-71466251a162
2003-04-07 21:30:39 +00:00
bellard 62296fe351 added runcom test
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@71 c046a42c-6fe2-441c-8c8c-71466251a162
2003-03-30 21:41:51 +00:00
bellard 32f36bcefc added SIOCATMARK and times() syscall
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@70 c046a42c-6fe2-441c-8c8c-71466251a162
2003-03-30 21:29:48 +00:00
bellard bc8a22cc30 better vm86 support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@69 c046a42c-6fe2-441c-8c8c-71466251a162
2003-03-30 21:02:40 +00:00
bellard f631ef9bd2 better vm86 support - added iret - fixed push/pop fs/gs
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@68 c046a42c-6fe2-441c-8c8c-71466251a162
2003-03-30 21:01:16 +00:00
bellard f7341ff400 fixed execve bug
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@67 c046a42c-6fe2-441c-8c8c-71466251a162
2003-03-30 21:00:25 +00:00
bellard fd429f2f6c update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@66 c046a42c-6fe2-441c-8c8c-71466251a162
2003-03-30 20:59:46 +00:00
bellard fb3e5849bb s390 support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@65 c046a42c-6fe2-441c-8c8c-71466251a162
2003-03-29 17:32:36 +00:00
bellard 7854b05654 endian fixes by Ulrich weigand
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@64 c046a42c-6fe2-441c-8c8c-71466251a162
2003-03-29 17:22:23 +00:00
bellard 500dab07e8 update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@63 c046a42c-6fe2-441c-8c8c-71466251a162
2003-03-29 16:58:09 +00:00
bellard f6630e791b version
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@62 c046a42c-6fe2-441c-8c8c-71466251a162
2003-03-29 16:57:48 +00:00
bellard 168485b75b wine help
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@61 c046a42c-6fe2-441c-8c8c-71466251a162
2003-03-29 16:57:34 +00:00
bellard 5cd4393b14 first vm86 support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@60 c046a42c-6fe2-441c-8c8c-71466251a162
2003-03-29 16:54:36 +00:00
bellard 7ed601b782 more syscalls
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@59 c046a42c-6fe2-441c-8c8c-71466251a162
2003-03-29 16:54:05 +00:00
bellard d1f2367bc0 changed flag names
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@58 c046a42c-6fe2-441c-8c8c-71466251a162
2003-03-29 16:53:34 +00:00
bellard 851e67a1b4 primitive vm86 support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@57 c046a42c-6fe2-441c-8c8c-71466251a162
2003-03-29 16:53:14 +00:00
bellard fc2b4c4879 eflags update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@56 c046a42c-6fe2-441c-8c8c-71466251a162
2003-03-29 16:52:44 +00:00
bellard 9c605cb135 added cmpxchg8b, cpuid, bound, eflags support, vm86 mode, 16bit/override string ops
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@55 c046a42c-6fe2-441c-8c8c-71466251a162
2003-03-29 16:51:35 +00:00
bellard 24f9e90b0e 16bit/override support in string operations
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@54 c046a42c-6fe2-441c-8c8c-71466251a162
2003-03-29 16:50:40 +00:00
bellard a4a0ffdb2b added cmpxchg8b, cpuid, bound, eflags support, vm86 mode
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@53 c046a42c-6fe2-441c-8c8c-71466251a162
2003-03-29 16:49:21 +00:00
bellard 0ea00c9a3c added number of arguments
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@52 c046a42c-6fe2-441c-8c8c-71466251a162
2003-03-29 16:47:34 +00:00
bellard e1d4294a45 more tests
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@51 c046a42c-6fe2-441c-8c8c-71466251a162
2003-03-29 16:45:07 +00:00
bellard c3c7c29246 added runcom
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@50 c046a42c-6fe2-441c-8c8c-71466251a162
2003-03-29 16:44:42 +00:00
bellard 31bb950be6 xchg lock, xlat instr
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@49 c046a42c-6fe2-441c-8c8c-71466251a162
2003-03-26 22:33:47 +00:00
bellard 8083a3e508 dirent fixes
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@48 c046a42c-6fe2-441c-8c8c-71466251a162
2003-03-24 23:12:16 +00:00
bellard 644c433cb3 ld.so load fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@47 c046a42c-6fe2-441c-8c8c-71466251a162
2003-03-24 23:00:36 +00:00
bellard d691f66983 glibc2.2 fixes - more command line options - misc doc fixes
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@46 c046a42c-6fe2-441c-8c8c-71466251a162
2003-03-24 21:58:34 +00:00
bellard 386405f786 documentation
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@45 c046a42c-6fe2-441c-8c8c-71466251a162
2003-03-23 21:28:45 +00:00
bellard 3ef693a032 distribution patches
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@44 c046a42c-6fe2-441c-8c8c-71466251a162
2003-03-23 20:17:16 +00:00
bellard b03c60f351 more syscalls
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@43 c046a42c-6fe2-441c-8c8c-71466251a162
2003-03-23 17:19:56 +00:00
bellard 9de5e440b9 better signal/exception support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@42 c046a42c-6fe2-441c-8c8c-71466251a162
2003-03-23 16:49:39 +00:00
bellard 66fb9763af basic signal handling
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@41 c046a42c-6fe2-441c-8c8c-71466251a162
2003-03-23 01:06:05 +00:00
bellard 1b6b029e40 basic clone() support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@40 c046a42c-6fe2-441c-8c8c-71466251a162
2003-03-22 17:31:38 +00:00
bellard 612384d771 added libgemu.a build
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@39 c046a42c-6fe2-441c-8c8c-71466251a162
2003-03-22 17:31:19 +00:00
bellard dab2ed991a better 16 bit code support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@38 c046a42c-6fe2-441c-8c8c-71466251a162
2003-03-22 15:23:14 +00:00
bellard e591824733 added code16 tests
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@37 c046a42c-6fe2-441c-8c8c-71466251a162
2003-03-22 15:20:50 +00:00
bellard 04369ff2f5 ppc port
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@36 c046a42c-6fe2-441c-8c8c-71466251a162
2003-03-20 22:33:23 +00:00
bellard 68decc7c7f added file
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@35 c046a42c-6fe2-441c-8c8c-71466251a162
2003-03-19 00:05:32 +00:00
bellard dc99065b5f added flags computation optimization
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@34 c046a42c-6fe2-441c-8c8c-71466251a162
2003-03-19 00:00:28 +00:00
bellard ca735206e0 gcc 3.x fixes
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@33 c046a42c-6fe2-441c-8c8c-71466251a162
2003-03-18 20:41:34 +00:00
bellard 5dd9488c09 added cmov instruction
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@32 c046a42c-6fe2-441c-8c8c-71466251a162
2003-03-16 22:54:06 +00:00
bellard 60cd49d5d7 added stat64
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@31 c046a42c-6fe2-441c-8c8c-71466251a162
2003-03-16 22:53:56 +00:00
bellard a300e69170 cmpxchg test
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@30 c046a42c-6fe2-441c-8c8c-71466251a162
2003-03-16 20:34:20 +00:00
bellard 1a9353d258 added loop/xadd/cmpxchg support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@29 c046a42c-6fe2-441c-8c8c-71466251a162
2003-03-16 20:28:50 +00:00
bellard 6dbad63eef added minimal segment support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@28 c046a42c-6fe2-441c-8c8c-71466251a162
2003-03-16 18:05:05 +00:00
bellard 27362c82e9 added pusha/popa/rdtsc/bcd ops
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@27 c046a42c-6fe2-441c-8c8c-71466251a162
2003-03-16 11:29:31 +00:00
bellard 55480af80e added bcd test
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@26 c046a42c-6fe2-441c-8c8c-71466251a162
2003-03-16 11:29:17 +00:00
bellard 7d13299d07 added translation cache
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@25 c046a42c-6fe2-441c-8c8c-71466251a162
2003-03-06 23:23:54 +00:00
bellard 1017ebe9cb convert several x86 instructions at the same time
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@24 c046a42c-6fe2-441c-8c8c-71466251a162
2003-03-05 23:26:16 +00:00
bellard 77f8dd5add float fixes - added bsr/bsf support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@23 c046a42c-6fe2-441c-8c8c-71466251a162
2003-03-05 22:24:48 +00:00
bellard c5e9815da4 added bcd tests
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@22 c046a42c-6fe2-441c-8c8c-71466251a162
2003-03-05 22:24:26 +00:00
bellard 9d8e9c0993 bsx/float tests
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@21 c046a42c-6fe2-441c-8c8c-71466251a162
2003-03-05 20:57:02 +00:00
bellard d57c4e0120 added shiftd support - improved auto test
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@20 c046a42c-6fe2-441c-8c8c-71466251a162
2003-03-04 01:14:13 +00:00
bellard 4b74fe1f00 many fixes
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@19 c046a42c-6fe2-441c-8c8c-71466251a162
2003-03-03 23:23:09 +00:00
bellard 586314f2aa better debug support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@18 c046a42c-6fe2-441c-8c8c-71466251a162
2003-03-03 15:02:29 +00:00
bellard 0ecfa9930c prints hello world
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@17 c046a42c-6fe2-441c-8c8c-71466251a162
2003-03-03 14:32:43 +00:00
bellard ba1c6e37fc test infrastructure
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@16 c046a42c-6fe2-441c-8c8c-71466251a162
2003-03-03 11:58:28 +00:00
bellard 927f621e79 added float support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@15 c046a42c-6fe2-441c-8c8c-71466251a162
2003-03-02 19:39:42 +00:00
bellard 367e86e847 new x86 CPU core
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@14 c046a42c-6fe2-441c-8c8c-71466251a162
2003-03-01 17:13:26 +00:00
bellard 7bfdb6d18c new i386 emulator core
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@13 c046a42c-6fe2-441c-8c8c-71466251a162
2003-03-01 14:27:54 +00:00
bellard 379ca80d34 added shift tests
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@12 c046a42c-6fe2-441c-8c8c-71466251a162
2003-02-24 23:43:02 +00:00
bellard 4d1135e486 i386 emulator test
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@11 c046a42c-6fe2-441c-8c8c-71466251a162
2003-02-24 20:14:06 +00:00
bellard 5147f5aac0 added NO_TRACE_MSGS ifdef
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@10 c046a42c-6fe2-441c-8c8c-71466251a162
2003-02-22 15:48:43 +00:00
bellard 766a487abf ppc build
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@9 c046a42c-6fe2-441c-8c8c-71466251a162
2003-02-18 23:35:48 +00:00
bellard 72f0390014 suppressed clashes
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@8 c046a42c-6fe2-441c-8c8c-71466251a162
2003-02-18 23:33:18 +00:00
bellard b17780d521 endianness fixes
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@7 c046a42c-6fe2-441c-8c8c-71466251a162
2003-02-18 23:32:15 +00:00
bellard 3431395696 fixed endianness
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@6 c046a42c-6fe2-441c-8c8c-71466251a162
2003-02-18 23:03:03 +00:00
bellard 01ffc75bc9 avoid pt_regs clash
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@5 c046a42c-6fe2-441c-8c8c-71466251a162
2003-02-18 23:00:51 +00:00
bellard 31e31b8a24 This commit was generated by cvs2svn to compensate for changes in r2,
which included commits to RCS files with non-trunk default branches.


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3 c046a42c-6fe2-441c-8c8c-71466251a162
2003-02-18 22:55:36 +00:00
(no author) e63c3dc74b Standard project directories initialized by cvs2svn.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1 c046a42c-6fe2-441c-8c8c-71466251a162
2003-02-18 22:55:36 +00:00
61 changed files with 29269 additions and 979 deletions
+339
View File
@@ -0,0 +1,339 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
675 Mass Ave, Cambridge, MA 02139, USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) 19yy <name of author>
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., 675 Mass Ave, Cambridge, MA 02139, USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) 19yy name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.
+111 -111
View File
@@ -1,36 +1,14 @@
------------------------------------------------------------------------------
NOTE:
Some code of the Twin package was modified for DOSEMU by the DOSEMU-team.
The original is 'Copyright 1997 Willows Software, Inc.' and generously
was put under the GNU Library General Public License.
( for more information see http://www.willows.com/ )
GNU LESSER GENERAL PUBLIC LICENSE
Version 2.1, February 1999
We make use of section 3 of the GNU Library General Public License
('...opt to apply the terms of the ordinary GNU General Public License...'),
because the resulting product is an integrated part of DOSEMU and
can not be considered to be a 'library' in the terms of Library License.
Therefore, the below GNU LIBRARY GENERAL PUBLIC LICENSE applies only to the
_unchanged_ Twin package from Willows. For the DOSEMU-changed parts the normal
GNU GENERAL PUBLIC LICENSE applies. This GPL (file COPYING) can be found in
the root directory of the DOSEMU distribution.
The act of transformation to GPL was indicated to the maintainer of the Twin
package (Rob Penrose <rob@Canopy.Com>) and he acknowledge agreement.
Nov. 1 1997, The DOSEMU team.
------------------------------------------------------------------------------
GNU LIBRARY GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1991 Free Software Foundation, Inc.
675 Mass Ave, Cambridge, MA 02139, USA
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
[This is the first released version of the library GPL. It is
numbered 2 because it goes with version 2 of the ordinary GPL.]
[This is the first released version of the Lesser GPL. It also counts
as the successor of the GNU Library Public License, version 2, hence
the version number 2.1.]
Preamble
@@ -39,97 +17,109 @@ freedom to share and change it. By contrast, the GNU General Public
Licenses are intended to guarantee your freedom to share and change
free software--to make sure the software is free for all its users.
This license, the Library General Public License, applies to some
specially designated Free Software Foundation software, and to any
other libraries whose authors decide to use it. You can use it for
your libraries, too.
This license, the Lesser General Public License, applies to some
specially designated software packages--typically libraries--of the
Free Software Foundation and other authors who decide to use it. You
can use it too, but we suggest you first think carefully about whether
this license or the ordinary General Public License is the better
strategy to use in any particular case, based on the explanations below.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
When we speak of free software, we are referring to freedom of use,
not price. Our General Public Licenses are designed to make sure that
you have the freedom to distribute copies of free software (and charge
for this service if you wish); that you receive source code or can get
it if you want it; that you can change the software and use pieces of
it in new free programs; and that you are informed that you can do
these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if
you distribute copies of the library, or if you modify it.
distributors to deny you these rights or to ask you to surrender these
rights. These restrictions translate to certain responsibilities for
you if you distribute copies of the library or if you modify it.
For example, if you distribute copies of the library, whether gratis
or for a fee, you must give the recipients all the rights that we gave
you. You must make sure that they, too, receive or can get the source
code. If you link a program with the library, you must provide
complete object files to the recipients so that they can relink them
with the library, after making changes to the library and recompiling
code. If you link other code with the library, you must provide
complete object files to the recipients, so that they can relink them
with the library after making changes to the library and recompiling
it. And you must show them these terms so they know their rights.
Our method of protecting your rights has two steps: (1) copyright
the library, and (2) offer you this license which gives you legal
We protect your rights with a two-step method: (1) we copyright the
library, and (2) we offer you this license, which gives you legal
permission to copy, distribute and/or modify the library.
Also, for each distributor's protection, we want to make certain
that everyone understands that there is no warranty for this free
library. If the library is modified by someone else and passed on, we
want its recipients to know that what they have is not the original
version, so that any problems introduced by others will not reflect on
the original authors' reputations.
To protect each distributor, we want to make it very clear that
there is no warranty for the free library. Also, if the library is
modified by someone else and passed on, the recipients should know
that what they have is not the original version, so that the original
author's reputation will not be affected by problems that might be
introduced by others.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that companies distributing free
software will individually obtain patent licenses, thus in effect
transforming the program into proprietary software. To prevent this,
we have made it clear that any patent must be licensed for everyone's
free use or not licensed at all.
Finally, software patents pose a constant threat to the existence of
any free program. We wish to make sure that a company cannot
effectively restrict the users of a free program by obtaining a
restrictive license from a patent holder. Therefore, we insist that
any patent license obtained for a version of the library must be
consistent with the full freedom of use specified in this license.
Most GNU software, including some libraries, is covered by the ordinary
GNU General Public License, which was designed for utility programs. This
license, the GNU Library General Public License, applies to certain
designated libraries. This license is quite different from the ordinary
one; be sure to read it in full, and don't assume that anything in it is
the same as in the ordinary license.
Most GNU software, including some libraries, is covered by the
ordinary GNU General Public License. This license, the GNU Lesser
General Public License, applies to certain designated libraries, and
is quite different from the ordinary General Public License. We use
this license for certain libraries in order to permit linking those
libraries into non-free programs.
The reason we have a separate public license for some libraries is that
they blur the distinction we usually make between modifying or adding to a
program and simply using it. Linking a program with a library, without
changing the library, is in some sense simply using the library, and is
analogous to running a utility program or application program. However, in
a textual and legal sense, the linked executable is a combined work, a
derivative of the original library, and the ordinary General Public License
treats it as such.
When a program is linked with a library, whether statically or using
a shared library, the combination of the two is legally speaking a
combined work, a derivative of the original library. The ordinary
General Public License therefore permits such linking only if the
entire combination fits its criteria of freedom. The Lesser General
Public License permits more lax criteria for linking other code with
the library.
Because of this blurred distinction, using the ordinary General
Public License for libraries did not effectively promote software
sharing, because most developers did not use the libraries. We
concluded that weaker conditions might promote sharing better.
We call this license the "Lesser" General Public License because it
does Less to protect the user's freedom than the ordinary General
Public License. It also provides other free software developers Less
of an advantage over competing non-free programs. These disadvantages
are the reason we use the ordinary General Public License for many
libraries. However, the Lesser license provides advantages in certain
special circumstances.
However, unrestricted linking of non-free programs would deprive the
users of those programs of all benefit from the free status of the
libraries themselves. This Library General Public License is intended to
permit developers of non-free programs to use free libraries, while
preserving your freedom as a user of such programs to change the free
libraries that are incorporated in them. (We have not seen how to achieve
this as regards changes in header files, but we have achieved it as regards
changes in the actual functions of the Library.) The hope is that this
will lead to faster development of free libraries.
For example, on rare occasions, there may be a special need to
encourage the widest possible use of a certain library, so that it becomes
a de-facto standard. To achieve this, non-free programs must be
allowed to use the library. A more frequent case is that a free
library does the same job as widely used non-free libraries. In this
case, there is little to gain by limiting the free library to free
software only, so we use the Lesser General Public License.
In other cases, permission to use a particular library in non-free
programs enables a greater number of people to use a large body of
free software. For example, permission to use the GNU C Library in
non-free programs enables many more people to use the whole GNU
operating system, as well as its variant, the GNU/Linux operating
system.
Although the Lesser General Public License is Less protective of the
users' freedom, it does ensure that the user of a program that is
linked with the Library has the freedom and the wherewithal to run
that program using a modified version of the Library.
The precise terms and conditions for copying, distribution and
modification follow. Pay close attention to the difference between a
"work based on the library" and a "work that uses the library". The
former contains code derived from the library, while the latter only
works together with the library.
Note that it is possible for a library to be covered by the ordinary
General Public License rather than by this special one.
former contains code derived from the library, whereas the latter must
be combined with the library in order to run.
GNU LIBRARY GENERAL PUBLIC LICENSE
GNU LESSER GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License Agreement applies to any software library which
contains a notice placed by the copyright holder or other authorized
party saying it may be distributed under the terms of this Library
General Public License (also called "this License"). Each licensee is
addressed as "you".
0. This License Agreement applies to any software library or other
program which contains a notice placed by the copyright holder or
other authorized party saying it may be distributed under the terms of
this Lesser General Public License (also called "this License").
Each licensee is addressed as "you".
A "library" means a collection of software functions and/or data
prepared so as to be conveniently linked with application programs
@@ -278,7 +268,7 @@ distribute the object code for the work under the terms of Section 6.
Any executables containing that work also fall under Section 6,
whether or not they are linked directly with the Library itself.
6. As an exception to the Sections above, you may also compile or
6. As an exception to the Sections above, you may also combine or
link a "work that uses the Library" with the Library to produce a
work containing portions of the Library, and distribute that work
under terms of your choice, provided that the terms permit
@@ -305,23 +295,31 @@ of these things:
Library will not necessarily be able to recompile the application
to use the modified definitions.)
b) Accompany the work with a written offer, valid for at
b) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (1) uses at run time a
copy of the library already present on the user's computer system,
rather than copying library functions into the executable, and (2)
will operate properly with a modified version of the library, if
the user installs one, as long as the modified version is
interface-compatible with the version that the work was made with.
c) Accompany the work with a written offer, valid for at
least three years, to give the same user the materials
specified in Subsection 6a, above, for a charge no more
than the cost of performing this distribution.
c) If distribution of the work is made by offering access to copy
d) If distribution of the work is made by offering access to copy
from a designated place, offer equivalent access to copy the above
specified materials from the same place.
d) Verify that the user has already received a copy of these
e) Verify that the user has already received a copy of these
materials or that you have already sent this user a copy.
For an executable, the required form of the "work that uses the
Library" must include any data and utility programs needed for
reproducing the executable from it. However, as a special exception,
the source code distributed need not include anything that is normally
distributed (in either source or binary form) with the major
the materials to be distributed need not include anything that is
normally distributed (in either source or binary form) with the major
components (compiler, kernel, and so on) of the operating system on
which the executable runs, unless that component itself accompanies
the executable.
@@ -370,7 +368,7 @@ Library), the recipient automatically receives a license from the
original licensor to copy, distribute, link with or modify the Library
subject to these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
You are not responsible for enforcing compliance by third parties with
this License.
11. If, as a consequence of a court judgment or allegation of patent
@@ -413,7 +411,7 @@ excluded. In such case, this License incorporates the limitation as if
written in the body of this License.
13. The Free Software Foundation may publish revised and/or new
versions of the Library General Public License from time to time.
versions of the Lesser General Public License from time to time.
Such new versions will be similar in spirit to the present version,
but may differ in detail to address new problems or concerns.
@@ -459,7 +457,7 @@ DAMAGES.
END OF TERMS AND CONDITIONS
Appendix: How to Apply These Terms to Your New Libraries
How to Apply These Terms to Your New Libraries
If you develop a new library, and you want it to be of the greatest
possible use to the public, we recommend making it free software that
@@ -476,18 +474,18 @@ convey the exclusion of warranty; and each file should have at least the
Copyright (C) <year> <name of author>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
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
Library General Public License for more details.
Lesser General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
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
Also add information on how to contact you by electronic and paper mail.
@@ -502,3 +500,5 @@ necessary. Here is a sample; alter the names:
Ty Coon, President of Vice
That's all there is to it!
+82
View File
@@ -0,0 +1,82 @@
version 0.2:
- PowerPC disassembly and ELF symbols output (Rusty Russel)
- flock support (Rusty Russel)
- ugetrlimit support (Rusty Russel)
- fstat64 fix (Rusty Russel)
- initial Alpha port (Falk Hueffner)
- initial IA64 port (Matt Wilson)
- initial Sparc and Sparc64 port (David S. Miller)
- added HLT instruction
- LRET instruction fix.
- added GPF generation for I/Os.
- added INT3 and TF flag support.
- SHL instruction C flag fix.
- mmap emulation for host page size > 4KB
- self-modifying code support
- better VM86 support (dosemu works on non trivial programs)
- precise exception support (EIP is computed correctly in most cases)
- more precise LDT/GDT/IDT emulation
- faster segment load in vm86 mode
- direct chaining of basic blocks (faster emulation)
version 0.1.6:
- automatic library search system. QEMU can now work with unpatched
ELF dynamic loader and libc (Rusty Russell).
- ISO C warning fixes (Alistair Strachan)
- first self-virtualizable version (works only as long as the
translation cache is not flushed)
- RH9 fixes
version 0.1.5:
- ppc64 support + personality() patch (Rusty Russell)
- first Alpha CPU patches (Falk Hueffner)
- removed bfd.h dependancy
- fixed shrd, shld, idivl and divl on PowerPC.
- fixed buggy glibc PowerPC rint() function (test-i386 passes now on PowerPC).
version 0.1.4:
- more accurate VM86 emulation (can launch small DOS 16 bit
executables in wine).
- fixed push/pop fs/gs
- added iret instruction.
- added times() syscall and SIOCATMARK ioctl.
version 0.1.3:
- S390 support (Ulrich Weigand)
- glibc 2.3.x compile fix (Ulrich Weigand)
- socketcall endian fix (Ulrich Weigand)
- struct sockaddr endian fix (Ulrich Weigand)
- sendmsg/recvmsg endian fix (Ulrich Weigand)
- execve endian fix (Ulrich Weigand)
- fdset endian fix (Ulrich Weigand)
- partial setsockopt syscall support (Ulrich Weigand)
- more accurate pushf/popf emulation
- first partial vm86() syscall support (can be used with runcom example).
- added bound, cmpxchg8b, cpuid instructions
- added 16 bit addressing support/override for string operations
- poll() fix
version 0.1.2:
- compile fixes
- xlat instruction
- xchg instruction memory lock
- added simple vm86 example (not working with QEMU yet). The 54 byte
DOS executable 'pi_10.com' program was released by Bertram
Felgenhauer (more information at http://www.boo.net/~jasonp/pipage.html).
version 0.1.1:
- glibc 2.2 compilation fixes
- added -s and -L options
- binary distribution of x86 glibc and wine
- big endian fixes in ELF loader and getdents.
version 0.1:
- initial public release.
+170 -16
View File
@@ -1,36 +1,190 @@
include config.mak
CFLAGS=-Wall -O2 -g
LDFLAGS=-g
DEFINES=-D_GNU_SOURCE -DGEMU -DDOSEMU #-DNO_TRACE_MSGS
LIBS=
DEFINES=-DHAVE_BYTESWAP_H
OBJS= i386/fp87.o i386/interp_main.o i386/interp_modrm.o i386/interp_16_32.o \
i386/interp_32_16.o i386/interp_32_32.o i386/emu-utils.o \
i386/dis8086.o i386/emu-ldt.o
OBJS+= elfload.o main.o thunk.o syscall.o
ifeq ($(ARCH),i386)
CFLAGS+=-fomit-frame-pointer
OP_CFLAGS=$(CFLAGS) -mpreferred-stack-boundary=2
ifeq ($(GCC_MAJOR),3)
OP_CFLAGS+= -falign-functions=0
else
OP_CFLAGS+= -malign-functions=0
endif
ifdef TARGET_GPROF
LDFLAGS+=-Wl,-T,i386.ld
else
# WARNING: this LDFLAGS is _very_ tricky : qemu is an ELF shared object
# that the kernel ELF loader considers as an executable. I think this
# is the simplest way to make it self virtualizable!
LDFLAGS+=-Wl,-shared
endif
endif
SRCS = $(OBJS:.o=.c)
ifeq ($(ARCH),ppc)
OP_CFLAGS=$(CFLAGS)
LDFLAGS+=-Wl,-T,ppc.ld
endif
all: gemu
ifeq ($(ARCH),s390)
OP_CFLAGS=$(CFLAGS)
LDFLAGS+=-Wl,-T,s390.ld
endif
gemu: $(OBJS)
$(CC) -Wl,-T,i386.ld $(LDFLAGS) -o $@ $(OBJS)
ifeq ($(ARCH),sparc)
CFLAGS+=-m32 -ffixed-g1 -ffixed-g2 -ffixed-g3 -ffixed-g6
LDFLAGS+=-m32
OP_CFLAGS=$(CFLAGS) -fno-delayed-branch -ffixed-i0
endif
ifeq ($(ARCH),sparc64)
CFLAGS+=-m64 -ffixed-g1 -ffixed-g2 -ffixed-g3 -ffixed-g6
LDFLAGS+=-m64
OP_CFLAGS=$(CFLAGS) -fno-delayed-branch -ffixed-i0
endif
ifeq ($(ARCH),alpha)
# -msmall-data is not used because we want two-instruction relocations
# for the constant constructions
OP_CFLAGS=-Wall -O2 -g
# Ensure there's only a single GP
CFLAGS += -msmall-data -msmall-text
LDFLAGS+=-Wl,-T,alpha.ld
endif
ifeq ($(ARCH),ia64)
OP_CFLAGS=$(CFLAGS)
endif
ifeq ($(GCC_MAJOR),3)
# very important to generate a return at the end of every operation
OP_CFLAGS+=-fno-reorder-blocks -fno-optimize-sibling-calls
endif
#########################################################
DEFINES+=-D_GNU_SOURCE
LIBS+=-lm
# profiling code
ifdef TARGET_GPROF
LDFLAGS+=-p
main.o: CFLAGS+=-p
endif
OBJS= elfload.o main.o syscall.o mmap.o signal.o vm86.o path.o
SRCS:= $(OBJS:.o=.c)
OBJS+= libqemu.a
LIBOBJS+=thunk.o translate-i386.o op-i386.o exec-i386.o exec.o
# NOTE: the disassembler code is only needed for debugging
LIBOBJS+=disas.o i386-dis.o dis-buf.o
ifeq ($(ARCH),alpha)
LIBOBJS+=alpha-dis.o
endif
ifeq ($(ARCH),ppc)
LIBOBJS+=ppc-dis.o
endif
ifeq ($(ARCH),ia64)
OBJS += ia64-syscall.o
endif
all: qemu qemu-doc.html
qemu: $(OBJS)
$(CC) $(LDFLAGS) -o $@ $^ $(LIBS)
ifeq ($(ARCH),alpha)
# Mark as 32 bit binary, i. e. it will be mapped into the low 31 bit of
# the address space (31 bit so sign extending doesn't matter)
echo -ne '\001\000\000\000' | dd of=qemu bs=1 seek=48 count=4 conv=notrunc
endif
depend: $(SRCS)
$(CC) -MM $(CFLAGS) $^ 1>.depend
# libqemu
libqemu.a: $(LIBOBJS)
rm -f $@
$(AR) rcs $@ $(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
op-i386.h: op-i386.o dyngen
./dyngen -o $@ $<
opc-i386.h: op-i386.o dyngen
./dyngen -c -o $@ $<
op-i386.o: op-i386.c opreg_template.h ops_template.h
$(CC) $(OP_CFLAGS) $(DEFINES) -c -o $@ $<
%.o: %.c
$(CC) $(CFLAGS) $(DEFINES) -c -o $@ $<
clean:
rm -f *.o *~ i386/*.o i386/*~ gemu hello test1 test2 TAGS
$(MAKE) -C tests clean
rm -f *.o *.a *~ qemu dyngen TAGS
hello: hello.c
$(CC) -nostdlib $(CFLAGS) -static $(LDFLAGS) -o $@ $<
distclean: clean
rm -f config.mak config.h
test1: test1.c
$(CC) $(CFLAGS) -static $(LDFLAGS) -o $@ $<
install: qemu
install -m 755 -s qemu $(prefix)/bin
test2: test2.c
$(CC) $(CFLAGS) -static $(LDFLAGS) -o $@ $<
# various test targets
test speed: qemu
make -C tests $@
TAGS:
etags *.[ch] tests/*.[ch]
# documentation
qemu-doc.html: qemu-doc.texi
texi2html -monolithic -number $<
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 \
tests/testsig.c tests/testclone.c tests/testthread.c \
tests/runcom.c tests/pi_10.com \
tests/test_path.c \
qemu-doc.texi qemu-doc.html
FILE=qemu-$(VERSION)
tar:
rm -rf /tmp/$(FILE)
mkdir -p /tmp/$(FILE)
cp -P $(FILES) /tmp/$(FILE)
( cd /tmp ; tar zcvf ~/$(FILE).tar.gz $(FILE) )
rm -rf /tmp/$(FILE)
# generate a binary distribution including the test binary environnment
BINPATH=/usr/local/qemu-i386
tarbin:
tar zcvf /tmp/qemu-$(VERSION)-i386-glibc21.tar.gz \
$(BINPATH)/etc $(BINPATH)/lib $(BINPATH)/bin $(BINPATH)/usr
tar zcvf /tmp/qemu-$(VERSION)-i386-wine.tar.gz \
$(BINPATH)/wine
ifneq ($(wildcard .depend),)
include .depend
+45
View File
@@ -0,0 +1,45 @@
The QEMU x86 emulator
---------------------
INSTALLATION
------------
Type
./configure --interp-prefix=/usr/local/qemu-i386
make
to build qemu and libqemu.a.
Type
make install
to install QEMU in /usr/local/bin
* On x86 you should be able to launch any program by using the
libraries installed on your PC. For example:
./qemu -L / /bin/ls
* On non x86 CPUs, you need first to download at least an x86 glibc
(qemu-XXX-i386-glibc21.tar.gz on the qemu web page). Ensure that
LD_LIBRARY_PATH is not set:
unset LD_LIBRARY_PATH
Then you can launch the precompiled 'ls' x86 executable:
./qemu /usr/local/qemu-i386/bin/ls-i386
You can look at /usr/local/qemu-i386/bin/qemu-conf.sh so that QEMU is
automatically launched by the Linux kernel when you try to launch x86
executables.
Documentation
-------------
Read the documentation in qemu-doc.html.
Fabrice Bellard.
+16
View File
@@ -0,0 +1,16 @@
Information about the various packages used to build the current qemu
x86 binary distribution:
* gcc 2.95.2 was used for the build. A glibc 2.1.3 Debian distribution
was used to get most of the binary packages.
* wine-20020411 tarball
./configure --prefix=/usr/local/qemu-i386/wine
All exe and libs were stripped. Some compile time tools and the
includes were deleted.
* ldconfig was launched to build the library links:
./qemu /usr/local/qemu-i386/bin/ldconfig-i386 -C /usr/local/qemu-i386/etc/ld.so.cache
+22 -2
View File
@@ -1,2 +1,22 @@
- swap all elf paramters
- fix printf for doubles (fp87.c bug ?)
- fix iret/lret/fpush not before mem load restarting
- fix all remaining thread lock issues (must put TBs in a specific invalid
state, find a solution for tb_flush()).
- handle fp87 state in signals
- add gcc 2.96 test configure (some gcc3 flags are needed)
- optimize FPU operations (evaluate x87 stack pointer statically)
- add IPC syscalls
- submit a patch to fix DOSEMU coopthreads
lower priority:
--------------
- 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)
- more syscalls (in particular all 64 bit ones, IPCs, fix 64 bit
issues, fix 16 bit uid issues)
- use page_unprotect_range in every suitable syscall to handle all
cases of self modifying code.
- use gcc as a backend to generate better code (easy to do by using
op-i386.c operations as local inline functions).
- add SSE2/MMX operations
+1
View File
@@ -0,0 +1 @@
0.2
+1976
View File
File diff suppressed because it is too large Load Diff
+128
View File
@@ -0,0 +1,128 @@
OUTPUT_FORMAT("elf64-alpha", "elf64-alpha",
"elf64-alpha")
OUTPUT_ARCH(alpha)
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 . */
}
Vendored Executable
+274
View File
@@ -0,0 +1,274 @@
#!/bin/sh
#
# qemu configure script (c) 2003 Fabrice Bellard
#
# set temporary file name
if test ! -z "$TMPDIR" ; then
TMPDIR1="${TMPDIR}"
elif test ! -z "$TEMPDIR" ; then
TMPDIR1="${TEMPDIR}"
else
TMPDIR1="/tmp"
fi
TMPC="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}.c"
TMPO="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}.o"
TMPE="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}"
TMPS="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}.S"
TMPH="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}.h"
# default parameters
prefix="/usr/local"
interp_prefix="/usr/gnemul/qemu-i386"
cross_prefix=""
cc="gcc"
host_cc="gcc"
ar="ar"
make="make"
strip="strip"
target_cpu="x86"
cpu=`uname -m`
case "$cpu" in
i386|i486|i586|i686|i86pc|BePC)
cpu="x86"
;;
armv4l)
cpu="armv4l"
;;
alpha)
cpu="alpha"
;;
"Power Macintosh"|ppc|ppc64)
cpu="powerpc"
;;
mips)
cpu="mips"
;;
s390)
cpu="s390"
;;
sparc)
cpu="sparc"
;;
sparc64)
cpu="sparc64"
;;
ia64)
cpu="ia64"
;;
*)
cpu="unknown"
;;
esac
gprof="no"
bigendian="no"
# OS specific
targetos=`uname -s`
case $targetos in
*) ;;
esac
# find source path
# XXX: we assume an absolute path is given when launching configure,
# except in './configure' case.
source_path=${0%configure}
source_path=${source_path%/}
source_path_used="yes"
if test -z "$source_path" -o "$source_path" = "." ; then
source_path=`pwd`
source_path_used="no"
fi
for opt do
case "$opt" in
--prefix=*) prefix=`echo $opt | cut -d '=' -f 2`
;;
--interp-prefix=*) interp_prefix=`echo $opt | cut -d '=' -f 2`
;;
--source-path=*) source_path=`echo $opt | cut -d '=' -f 2`
;;
--cross-prefix=*) cross_prefix=`echo $opt | cut -d '=' -f 2`
;;
--cc=*) cc=`echo $opt | cut -d '=' -f 2`
;;
--make=*) make=`echo $opt | cut -d '=' -f 2`
;;
--extra-cflags=*) CFLAGS="${opt#--extra-cflags=}"
;;
--extra-ldflags=*) LDFLAGS="${opt#--extra-ldflags=}"
;;
--extra-libs=*) extralibs=${opt#--extra-libs=}
;;
--cpu=*) cpu=`echo $opt | cut -d '=' -f 2`
;;
--enable-gprof) gprof="yes"
;;
esac
done
# Checking for CFLAGS
if test -z "$CFLAGS"; then
CFLAGS="-O2"
fi
cc="${cross_prefix}${cc}"
ar="${cross_prefix}${ar}"
strip="${cross_prefix}${strip}"
if test -z "$cross_prefix" ; then
# ---
# big/little endian test
cat > $TMPC << EOF
#include <inttypes.h>
int main(int argc, char ** argv){
volatile uint32_t i=0x01234567;
return (*((uint8_t*)(&i))) == 0x67;
}
EOF
if $cc -o $TMPE $TMPC 2>/dev/null ; then
$TMPE && bigendian="yes"
else
echo big/little test failed
fi
else
# if cross compiling, cannot launch a program, so make a static guess
if test "$cpu" = "powerpc" -o "$cpu" = "mips" -o "$cpu" = "s390" -o "$cpu" = "sparc" -o "$cpu" = "sparc64"; then
bigendian="yes"
fi
fi
# check gcc version
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"
fi
if test x"$1" = x"-h" -o x"$1" = x"--help" ; then
cat << EOF
Usage: configure [options]
Options: [defaults in brackets after descriptions]
EOF
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 ""
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 ""
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 "Creating config.mak and config.h"
echo "# Automatically generated by configure - do not modify" > config.mak
echo "/* Automatically generated by configure - do not modify */" > $TMPH
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
echo "HOST_CC=$host_cc" >> config.mak
echo "AR=$ar" >> config.mak
echo "STRIP=$strip -s -R .comment -R .note" >> config.mak
echo "CFLAGS=$CFLAGS" >> config.mak
echo "LDFLAGS=$LDFLAGS" >> config.mak
if test "$cpu" = "x86" ; then
echo "ARCH=i386" >> config.mak
echo "#define HOST_I386 1" >> $TMPH
elif test "$cpu" = "armv4l" ; then
echo "ARCH=arm" >> config.mak
echo "#define HOST_ARM 1" >> $TMPH
elif test "$cpu" = "powerpc" ; then
echo "ARCH=ppc" >> config.mak
echo "#define HOST_PPC 1" >> $TMPH
elif test "$cpu" = "mips" ; then
echo "ARCH=mips" >> config.mak
echo "#define HOST_MIPS 1" >> $TMPH
elif test "$cpu" = "s390" ; then
echo "ARCH=s390" >> config.mak
echo "#define HOST_S390 1" >> $TMPH
elif test "$cpu" = "alpha" ; then
echo "ARCH=alpha" >> config.mak
echo "#define HOST_ALPHA 1" >> $TMPH
elif test "$cpu" = "sparc" ; then
echo "ARCH=sparc" >> config.mak
echo "#define HOST_SPARC 1" >> $TMPH
elif test "$cpu" = "sparc64" ; then
echo "ARCH=sparc64" >> config.mak
echo "#define HOST_SPARC64 1" >> $TMPH
elif test "$cpu" = "ia64" ; then
echo "ARCH=ia64" >> config.mak
echo "#define HOST_IA64 1" >> $TMPH
else
echo "Unsupported CPU"
exit 1
fi
if test "$bigendian" = "yes" ; then
echo "WORDS_BIGENDIAN=yes" >> config.mak
echo "#define WORDS_BIGENDIAN 1" >> $TMPH
fi
if test "$gprof" = "yes" ; then
echo "TARGET_GPROF=yes" >> config.mak
echo "#define HAVE_GPROF 1" >> $TMPH
fi
echo -n "VERSION=" >>config.mak
head $source_path/VERSION >>config.mak
echo "" >>config.mak
echo -n "#define QEMU_VERSION \"" >> $TMPH
head $source_path/VERSION >> $TMPH
echo "\"" >> $TMPH
# build tree in object directory if source path is different from current one
if test "$source_path_used" = "yes" ; then
DIRS="tests"
FILES="Makefile tests/Makefile"
for dir in $DIRS ; do
mkdir -p $dir
done
for f in $FILES ; do
ln -sf $source_path/$f $f
done
fi
echo "SRC_PATH=$source_path" >> config.mak
diff $TMPH config.h >/dev/null 2>&1
if test $? -ne 0 ; then
mv -f $TMPH config.h
else
echo "config.h is unchanged"
fi
rm -f $TMPO $TMPC $TMPE $TMPS $TMPH
+479
View File
@@ -0,0 +1,479 @@
/*
* i386 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_I386_H
#define CPU_I386_H
#include "config.h"
#include <setjmp.h>
#define R_EAX 0
#define R_ECX 1
#define R_EDX 2
#define R_EBX 3
#define R_ESP 4
#define R_EBP 5
#define R_ESI 6
#define R_EDI 7
#define R_AL 0
#define R_CL 1
#define R_DL 2
#define R_BL 3
#define R_AH 4
#define R_CH 5
#define R_DH 6
#define R_BH 7
#define R_ES 0
#define R_CS 1
#define R_SS 2
#define R_DS 3
#define R_FS 4
#define R_GS 5
/* segment descriptor fields */
#define DESC_G_MASK (1 << 23)
#define DESC_B_MASK (1 << 22)
#define DESC_AVL_MASK (1 << 20)
#define DESC_P_MASK (1 << 15)
#define DESC_DPL_SHIFT 13
#define DESC_S_MASK (1 << 12)
#define DESC_TYPE_SHIFT 8
#define DESC_A_MASK (1 << 8)
#define DESC_CS_MASK (1 << 11)
#define DESC_C_MASK (1 << 10)
#define DESC_R_MASK (1 << 9)
#define DESC_E_MASK (1 << 10)
#define DESC_W_MASK (1 << 9)
/* eflags masks */
#define CC_C 0x0001
#define CC_P 0x0004
#define CC_A 0x0010
#define CC_Z 0x0040
#define CC_S 0x0080
#define CC_O 0x0800
#define TF_MASK 0x00000100
#define IF_MASK 0x00000200
#define DF_MASK 0x00000400
#define IOPL_MASK 0x00003000
#define NT_MASK 0x00004000
#define RF_MASK 0x00010000
#define VM_MASK 0x00020000
#define AC_MASK 0x00040000
#define VIF_MASK 0x00080000
#define VIP_MASK 0x00100000
#define ID_MASK 0x00200000
#define EXCP00_DIVZ 0
#define EXCP01_SSTP 1
#define EXCP02_NMI 2
#define EXCP03_INT3 3
#define EXCP04_INTO 4
#define EXCP05_BOUND 5
#define EXCP06_ILLOP 6
#define EXCP07_PREX 7
#define EXCP08_DBLE 8
#define EXCP09_XERR 9
#define EXCP0A_TSS 10
#define EXCP0B_NOSEG 11
#define EXCP0C_STACK 12
#define EXCP0D_GPF 13
#define EXCP0E_PAGE 14
#define EXCP10_COPR 16
#define EXCP11_ALGN 17
#define EXCP12_MCHK 18
#define EXCP_INTERRUPT 256 /* async interruption */
enum {
CC_OP_DYNAMIC, /* must use dynamic code to get cc_op */
CC_OP_EFLAGS, /* all cc are explicitely computed, CC_SRC = flags */
CC_OP_MUL, /* modify all flags, C, O = (CC_SRC != 0) */
CC_OP_ADDB, /* modify all flags, CC_DST = res, CC_SRC = src1 */
CC_OP_ADDW,
CC_OP_ADDL,
CC_OP_ADCB, /* modify all flags, CC_DST = res, CC_SRC = src1 */
CC_OP_ADCW,
CC_OP_ADCL,
CC_OP_SUBB, /* modify all flags, CC_DST = res, CC_SRC = src1 */
CC_OP_SUBW,
CC_OP_SUBL,
CC_OP_SBBB, /* modify all flags, CC_DST = res, CC_SRC = src1 */
CC_OP_SBBW,
CC_OP_SBBL,
CC_OP_LOGICB, /* modify all flags, CC_DST = res */
CC_OP_LOGICW,
CC_OP_LOGICL,
CC_OP_INCB, /* modify all flags except, CC_DST = res, CC_SRC = C */
CC_OP_INCW,
CC_OP_INCL,
CC_OP_DECB, /* modify all flags except, CC_DST = res, CC_SRC = C */
CC_OP_DECW,
CC_OP_DECL,
CC_OP_SHLB, /* modify all flags, CC_DST = res, CC_SRC.lsb = C */
CC_OP_SHLW,
CC_OP_SHLL,
CC_OP_SARB, /* modify all flags, CC_DST = res, CC_SRC.lsb = C */
CC_OP_SARW,
CC_OP_SARL,
CC_OP_NB,
};
#ifdef __i386__
#define USE_X86LDOUBLE
#endif
#ifdef USE_X86LDOUBLE
typedef long double CPU86_LDouble;
#else
typedef double CPU86_LDouble;
#endif
typedef struct SegmentCache {
uint8_t *base;
unsigned long limit;
uint8_t seg_32bit;
} 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];
uint32_t eip;
uint32_t eflags; /* eflags register. During CPU emulation, CC
flags and DF are set to zero because they are
stored elsewhere */
/* emulator internal eflags handling */
uint32_t cc_src;
uint32_t cc_dst;
uint32_t cc_op;
int32_t df; /* D flag : 1 if D = 0, -1 if D = 1 */
/* FPU state */
unsigned int fpstt; /* top of stack index */
unsigned int fpus;
unsigned int fpuc;
uint8_t fptags[8]; /* 0 = valid, 1 = empty */
CPU86_LDouble fpregs[8];
/* emulator internal variables */
CPU86_LDouble ft0;
union {
float f;
double d;
int i32;
int64_t i64;
} fp_convert;
/* segments */
uint32_t segs[6]; /* selector values */
SegmentCache seg_cache[6]; /* info taken from LDT/GDT */
SegmentDescriptorTable gdt;
SegmentDescriptorTable ldt;
SegmentDescriptorTable idt;
/* exception/interrupt handling */
jmp_buf jmp_env;
int exception_index;
int error_code;
uint32_t cr2;
int interrupt_request;
/* 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);
void cpu_x86_outl(CPUX86State *env, int addr, int val);
int cpu_x86_inb(CPUX86State *env, int addr);
int cpu_x86_inw(CPUX86State *env, int addr);
int cpu_x86_inl(CPUX86State *env, int addr);
#endif
CPUX86State *cpu_x86_init(void);
int cpu_x86_exec(CPUX86State *s);
void cpu_x86_interrupt(CPUX86State *s);
void cpu_x86_close(CPUX86State *s);
/* needed to load some predefinied segment registers */
void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector);
/* 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_x86_signal_handler(int host_signum, struct siginfo *info,
void *puc);
/* 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);
#endif /* CPU_I386_H */
+386
View File
@@ -0,0 +1,386 @@
/* Interface between the opcode library and its callers.
Written by Cygnus Support, 1993.
The opcode library (libopcodes.a) provides instruction decoders for
a large variety of instruction sets, callable with an identical
interface, for making instruction-processing programs more independent
of the instruction set being processed. */
#ifndef DIS_ASM_H
#define DIS_ASM_H
#include <stdio.h>
#include <string.h>
#include <inttypes.h>
#define PARAMS(x) x
typedef void *PTR;
typedef uint64_t bfd_vma;
typedef uint8_t bfd_byte;
enum bfd_flavour {
bfd_target_unknown_flavour,
bfd_target_aout_flavour,
bfd_target_coff_flavour,
bfd_target_ecoff_flavour,
bfd_target_elf_flavour,
bfd_target_ieee_flavour,
bfd_target_nlm_flavour,
bfd_target_oasys_flavour,
bfd_target_tekhex_flavour,
bfd_target_srec_flavour,
bfd_target_ihex_flavour,
bfd_target_som_flavour,
bfd_target_os9k_flavour,
bfd_target_versados_flavour,
bfd_target_msdos_flavour,
bfd_target_evax_flavour
};
enum bfd_endian { BFD_ENDIAN_BIG, BFD_ENDIAN_LITTLE, BFD_ENDIAN_UNKNOWN };
enum bfd_architecture
{
bfd_arch_unknown, /* File arch not known */
bfd_arch_obscure, /* Arch known, not one of these */
bfd_arch_m68k, /* Motorola 68xxx */
#define bfd_mach_m68000 1
#define bfd_mach_m68008 2
#define bfd_mach_m68010 3
#define bfd_mach_m68020 4
#define bfd_mach_m68030 5
#define bfd_mach_m68040 6
#define bfd_mach_m68060 7
bfd_arch_vax, /* DEC Vax */
bfd_arch_i960, /* Intel 960 */
/* The order of the following is important.
lower number indicates a machine type that
only accepts a subset of the instructions
available to machines with higher numbers.
The exception is the "ca", which is
incompatible with all other machines except
"core". */
#define bfd_mach_i960_core 1
#define bfd_mach_i960_ka_sa 2
#define bfd_mach_i960_kb_sb 3
#define bfd_mach_i960_mc 4
#define bfd_mach_i960_xa 5
#define bfd_mach_i960_ca 6
#define bfd_mach_i960_jx 7
#define bfd_mach_i960_hx 8
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. */
#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_v9_p(mach) \
((mach) >= bfd_mach_sparc_v8plus && (mach) <= bfd_mach_sparc_v9a)
bfd_arch_mips, /* MIPS Rxxxx */
#define bfd_mach_mips3000 3000
#define bfd_mach_mips3900 3900
#define bfd_mach_mips4000 4000
#define bfd_mach_mips4010 4010
#define bfd_mach_mips4100 4100
#define bfd_mach_mips4300 4300
#define bfd_mach_mips4400 4400
#define bfd_mach_mips4600 4600
#define bfd_mach_mips4650 4650
#define bfd_mach_mips5000 5000
#define bfd_mach_mips6000 6000
#define bfd_mach_mips8000 8000
#define bfd_mach_mips10000 10000
#define bfd_mach_mips16 16
bfd_arch_i386, /* Intel 386 */
#define bfd_mach_i386_i386 0
#define bfd_mach_i386_i8086 1
bfd_arch_we32k, /* AT&T WE32xxx */
bfd_arch_tahoe, /* CCI/Harris Tahoe */
bfd_arch_i860, /* Intel 860 */
bfd_arch_romp, /* IBM ROMP PC/RT */
bfd_arch_alliant, /* Alliant */
bfd_arch_convex, /* Convex */
bfd_arch_m88k, /* Motorola 88xxx */
bfd_arch_pyramid, /* Pyramid Technology */
bfd_arch_h8300, /* Hitachi H8/300 */
#define bfd_mach_h8300 1
#define bfd_mach_h8300h 2
#define bfd_mach_h8300s 3
bfd_arch_powerpc, /* PowerPC */
bfd_arch_rs6000, /* IBM RS/6000 */
bfd_arch_hppa, /* HP PA RISC */
bfd_arch_d10v, /* Mitsubishi D10V */
bfd_arch_z8k, /* Zilog Z8000 */
#define bfd_mach_z8001 1
#define bfd_mach_z8002 2
bfd_arch_h8500, /* Hitachi H8/500 */
bfd_arch_sh, /* Hitachi SH */
#define bfd_mach_sh 0
#define bfd_mach_sh3 0x30
#define bfd_mach_sh3e 0x3e
#define bfd_mach_sh4 0x40
bfd_arch_alpha, /* Dec Alpha */
bfd_arch_arm, /* Advanced Risc Machines ARM */
#define bfd_mach_arm_2 1
#define bfd_mach_arm_2a 2
#define bfd_mach_arm_3 3
#define bfd_mach_arm_3M 4
#define bfd_mach_arm_4 5
#define bfd_mach_arm_4T 6
bfd_arch_ns32k, /* National Semiconductors ns32000 */
bfd_arch_w65, /* WDC 65816 */
bfd_arch_tic30, /* Texas Instruments TMS320C30 */
bfd_arch_v850, /* NEC V850 */
#define bfd_mach_v850 0
bfd_arch_arc, /* Argonaut RISC Core */
#define bfd_mach_arc_base 0
bfd_arch_m32r, /* Mitsubishi M32R/D */
#define bfd_mach_m32r 0 /* backwards compatibility */
bfd_arch_mn10200, /* Matsushita MN10200 */
bfd_arch_mn10300, /* Matsushita MN10300 */
bfd_arch_last
};
typedef struct symbol_cache_entry
{
const char *name;
union
{
PTR p;
bfd_vma i;
} udata;
} asymbol;
typedef int (*fprintf_ftype) PARAMS((FILE*, const char*, ...));
enum dis_insn_type {
dis_noninsn, /* Not a valid instruction */
dis_nonbranch, /* Not a branch instruction */
dis_branch, /* Unconditional branch */
dis_condbranch, /* Conditional branch */
dis_jsr, /* Jump to subroutine */
dis_condjsr, /* Conditional jump to subroutine */
dis_dref, /* Data reference instruction */
dis_dref2 /* Two data references in instruction */
};
/* This struct is passed into the instruction decoding routine,
and is passed back out into each callback. The various fields are used
for conveying information from your main routine into your callbacks,
for passing information into the instruction decoders (such as the
addresses of the callback functions), or for passing information
back from the instruction decoders to their callers.
It must be initialized before it is first passed; this can be done
by hand, or using one of the initialization macros below. */
typedef struct disassemble_info {
fprintf_ftype fprintf_func;
FILE *stream;
PTR application_data;
/* Target description. We could replace this with a pointer to the bfd,
but that would require one. There currently isn't any such requirement
so to avoid introducing one we record these explicitly. */
/* The bfd_flavour. This can be bfd_target_unknown_flavour. */
enum bfd_flavour flavour;
/* The bfd_arch value. */
enum bfd_architecture arch;
/* The bfd_mach value. */
unsigned long mach;
/* Endianness (for bi-endian cpus). Mono-endian cpus can ignore this. */
enum bfd_endian endian;
/* An array of pointers to symbols either at the location being disassembled
or at the start of the function being disassembled. The array is sorted
so that the first symbol is intended to be the one used. The others are
present for any misc. purposes. This is not set reliably, but if it is
not NULL, it is correct. */
asymbol **symbols;
/* Number of symbols in array. */
int num_symbols;
/* For use by the disassembler.
The top 16 bits are reserved for public use (and are documented here).
The bottom 16 bits are for the internal use of the disassembler. */
unsigned long flags;
#define INSN_HAS_RELOC 0x80000000
PTR private_data;
/* Function used to get bytes to disassemble. MEMADDR is the
address of the stuff to be disassembled, MYADDR is the address to
put the bytes in, and LENGTH is the number of bytes to read.
INFO is a pointer to this struct.
Returns an errno value or 0 for success. */
int (*read_memory_func)
PARAMS ((bfd_vma memaddr, bfd_byte *myaddr, int length,
struct disassemble_info *info));
/* Function which should be called if we get an error that we can't
recover from. STATUS is the errno value from read_memory_func and
MEMADDR is the address that we were trying to read. INFO is a
pointer to this struct. */
void (*memory_error_func)
PARAMS ((int status, bfd_vma memaddr, struct disassemble_info *info));
/* Function called to print ADDR. */
void (*print_address_func)
PARAMS ((bfd_vma addr, struct disassemble_info *info));
/* Function called to determine if there is a symbol at the given ADDR.
If there is, the function returns 1, otherwise it returns 0.
This is used by ports which support an overlay manager where
the overlay number is held in the top part of an address. In
some circumstances we want to include the overlay number in the
address, (normally because there is a symbol associated with
that address), but sometimes we want to mask out the overlay bits. */
int (* symbol_at_address_func)
PARAMS ((bfd_vma addr, struct disassemble_info * info));
/* These are for buffer_read_memory. */
bfd_byte *buffer;
bfd_vma buffer_vma;
int buffer_length;
/* This variable may be set by the instruction decoder. It suggests
the number of bytes objdump should display on a single line. If
the instruction decoder sets this, it should always set it to
the same value in order to get reasonable looking output. */
int bytes_per_line;
/* the next two variables control the way objdump displays the raw data */
/* For example, if bytes_per_line is 8 and bytes_per_chunk is 4, the */
/* output will look like this:
00: 00000000 00000000
with the chunks displayed according to "display_endian". */
int bytes_per_chunk;
enum bfd_endian display_endian;
/* Results from instruction decoders. Not all decoders yet support
this information. This info is set each time an instruction is
decoded, and is only valid for the last such instruction.
To determine whether this decoder supports this information, set
insn_info_valid to 0, decode an instruction, then check it. */
char insn_info_valid; /* Branch info has been set. */
char branch_delay_insns; /* How many sequential insn's will run before
a branch takes effect. (0 = normal) */
char data_size; /* Size of data reference in insn, in bytes */
enum dis_insn_type insn_type; /* Type of instruction */
bfd_vma target; /* Target address of branch or dref, if known;
zero if unknown. */
bfd_vma target2; /* Second target address for dref2 */
} disassemble_info;
/* Standard disassemblers. Disassemble one instruction at the given
target address. Return number of bytes processed. */
typedef int (*disassembler_ftype)
PARAMS((bfd_vma, disassemble_info *));
extern int print_insn_big_mips PARAMS ((bfd_vma, disassemble_info*));
extern int print_insn_little_mips PARAMS ((bfd_vma, disassemble_info*));
extern int print_insn_i386 PARAMS ((bfd_vma, disassemble_info*));
extern int print_insn_m68k PARAMS ((bfd_vma, disassemble_info*));
extern int print_insn_z8001 PARAMS ((bfd_vma, disassemble_info*));
extern int print_insn_z8002 PARAMS ((bfd_vma, disassemble_info*));
extern int print_insn_h8300 PARAMS ((bfd_vma, disassemble_info*));
extern int print_insn_h8300h PARAMS ((bfd_vma, disassemble_info*));
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_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*));
extern int print_insn_i960 PARAMS ((bfd_vma, disassemble_info*));
extern int print_insn_sh PARAMS ((bfd_vma, disassemble_info*));
extern int print_insn_shl PARAMS ((bfd_vma, disassemble_info*));
extern int print_insn_hppa PARAMS ((bfd_vma, disassemble_info*));
extern int print_insn_m32r PARAMS ((bfd_vma, disassemble_info*));
extern int print_insn_m88k PARAMS ((bfd_vma, disassemble_info*));
extern int print_insn_mn10200 PARAMS ((bfd_vma, disassemble_info*));
extern int print_insn_mn10300 PARAMS ((bfd_vma, disassemble_info*));
extern int print_insn_ns32k PARAMS ((bfd_vma, disassemble_info*));
extern int print_insn_big_powerpc PARAMS ((bfd_vma, disassemble_info*));
extern int print_insn_little_powerpc PARAMS ((bfd_vma, disassemble_info*));
extern int print_insn_rs6000 PARAMS ((bfd_vma, disassemble_info*));
extern int print_insn_w65 PARAMS ((bfd_vma, disassemble_info*));
extern int print_insn_d10v PARAMS ((bfd_vma, disassemble_info*));
extern int print_insn_v850 PARAMS ((bfd_vma, disassemble_info*));
extern int print_insn_tic30 PARAMS ((bfd_vma, disassemble_info*));
extern int print_insn_ppc PARAMS ((bfd_vma, disassemble_info*));
#if 0
/* Fetch the disassembler for a given BFD, if that support is available. */
extern disassembler_ftype disassembler PARAMS ((bfd *));
#endif
/* This block of definitions is for particular callers who read instructions
into a buffer before calling the instruction decoder. */
/* Here is a function which callers may wish to use for read_memory_func.
It gets bytes from a buffer. */
extern int buffer_read_memory
PARAMS ((bfd_vma, bfd_byte *, int, struct disassemble_info *));
/* This function goes with buffer_read_memory.
It prints a message using info->fprintf_func and info->stream. */
extern void perror_memory PARAMS ((int, bfd_vma, struct disassemble_info *));
/* Just print the address in hex. This is included for completeness even
though both GDB and objdump provide their own (to print symbolic
addresses). */
extern void generic_print_address
PARAMS ((bfd_vma, struct disassemble_info *));
/* Always true. */
extern int generic_symbol_at_address
PARAMS ((bfd_vma, struct disassemble_info *));
/* Macro to initialize a disassemble_info struct. This should be called
by all applications creating such a struct. */
#define INIT_DISASSEMBLE_INFO(INFO, STREAM, FPRINTF_FUNC) \
(INFO).flavour = bfd_target_unknown_flavour, \
(INFO).arch = bfd_arch_unknown, \
(INFO).mach = 0, \
(INFO).endian = BFD_ENDIAN_UNKNOWN, \
INIT_DISASSEMBLE_INFO_NO_ARCH(INFO, STREAM, FPRINTF_FUNC)
/* Call this macro to initialize only the internal variables for the
disassembler. Architecture dependent things such as byte order, or machine
variant are not touched by this macro. This makes things much easier for
GDB which must initialize these things seperatly. */
#define INIT_DISASSEMBLE_INFO_NO_ARCH(INFO, STREAM, FPRINTF_FUNC) \
(INFO).fprintf_func = (FPRINTF_FUNC), \
(INFO).stream = (STREAM), \
(INFO).symbols = NULL, \
(INFO).num_symbols = 0, \
(INFO).buffer = NULL, \
(INFO).buffer_vma = 0, \
(INFO).buffer_length = 0, \
(INFO).read_memory_func = buffer_read_memory, \
(INFO).memory_error_func = perror_memory, \
(INFO).print_address_func = generic_print_address, \
(INFO).symbol_at_address_func = generic_symbol_at_address, \
(INFO).flags = 0, \
(INFO).bytes_per_line = 0, \
(INFO).bytes_per_chunk = 0, \
(INFO).display_endian = BFD_ENDIAN_UNKNOWN, \
(INFO).insn_info_valid = 0
#endif /* ! defined (DIS_ASM_H) */
+79
View File
@@ -0,0 +1,79 @@
/* 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;
}
+81
View File
@@ -0,0 +1,81 @@
/* General "disassemble this chunk" code. Used for debugging. */
#include "dis-asm.h"
#include "disas.h"
#include "elf.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)
{
uint8_t *pc;
int count;
struct disassemble_info disasm_info;
int (*print_insn)(bfd_vma pc, disassemble_info *info);
INIT_DISASSEMBLE_INFO(disasm_info, out, fprintf);
disasm_info.buffer = code;
disasm_info.buffer_vma = (unsigned long)code;
disasm_info.buffer_length = size;
if (type == DISAS_TARGET) {
#ifdef WORDS_BIGENDIAN
disasm_info.endian = BFD_ENDIAN_BIG;
#else
disasm_info.endian = BFD_ENDIAN_LITTLE;
#endif
#ifdef __i386__
disasm_info.mach = bfd_mach_i386_i386;
print_insn = print_insn_i386;
#elif defined(__powerpc__)
print_insn = print_insn_ppc;
#elif defined(__alpha__)
print_insn = print_insn_alpha;
#else
fprintf(out, "Asm output not supported on this arch\n");
return;
#endif
} else {
/* Currently only source supported in x86. */
disasm_info.endian = BFD_ENDIAN_LITTLE;
if (type == DISAS_I386_I386)
disasm_info.mach = bfd_mach_i386_i386;
else
disasm_info.mach = bfd_mach_i386_i8086;
print_insn = print_insn_i386;
}
for (pc = code; pc < (uint8_t *)code + size; pc += count) {
fprintf(out, "0x%08lx: ", (long)pc);
count = print_insn((unsigned long)pc, &disasm_info);
fprintf(out, "\n");
if (count < 0)
break;
}
}
/* Look up symbol for debugging purpose. Returns "" if unknown. */
const char *lookup_symbol(void *orig_addr)
{
unsigned int i;
/* Hack, because we know this is x86. */
Elf32_Sym *sym = disas_symtab;
for (i = 0; i < disas_num_syms; i++) {
if (sym[i].st_shndx == SHN_UNDEF
|| sym[i].st_shndx >= SHN_LORESERVE)
continue;
if (ELF_ST_TYPE(sym[i].st_info) != STT_FUNC)
continue;
if ((long)orig_addr >= sym[i].st_value
&& (long)orig_addr < sym[i].st_value + sym[i].st_size)
return disas_strtab + sym[i].st_name;
}
return "";
}
+20
View File
@@ -0,0 +1,20 @@
#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);
/* Look up symbol for debugging purpose. Returns "" if unknown. */
const char *lookup_symbol(void *orig_addr);
/* Filled in by elfload.c. Simplistic, but will do for now. */
extern unsigned int disas_num_syms;
extern void *disas_symtab; /* FIXME: includes are a mess --RR */
extern const char *disas_strtab;
#endif /* _QEMU_DISAS_H */
+1173
View File
File diff suppressed because it is too large Load Diff
+818 -101
View File
File diff suppressed because it is too large Load Diff
+430
View File
@@ -0,0 +1,430 @@
/*
* 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
+230
View File
@@ -0,0 +1,230 @@
/*
* i386 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
*/
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) )); \
})
#define NULL 0
#include <fenv.h>
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])
#endif
#ifndef reg_ECX
#define ECX (env->regs[R_ECX])
#endif
#ifndef reg_EDX
#define EDX (env->regs[R_EDX])
#endif
#ifndef reg_EBX
#define EBX (env->regs[R_EBX])
#endif
#ifndef reg_ESP
#define ESP (env->regs[R_ESP])
#endif
#ifndef reg_EBP
#define EBP (env->regs[R_EBP])
#endif
#ifndef reg_ESI
#define ESI (env->regs[R_ESI])
#endif
#ifndef reg_EDI
#define EDI (env->regs[R_EDI])
#endif
#define EIP (env->eip)
#define DF (env->df)
#define CC_SRC (env->cc_src)
#define CC_DST (env->cc_dst)
#define CC_OP (env->cc_op)
/* float macros */
#define FT0 (env->ft0)
#define ST0 (env->fpregs[env->fpstt])
#define ST(n) (env->fpregs[(env->fpstt + (n)) & 7])
#define ST1 ST(1)
#ifdef USE_FP_CONVERT
#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"
typedef struct CCTable {
int (*compute_all)(void); /* return all the flags */
int (*compute_c)(void); /* return the C flag */
} 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 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 OPPROTO op_movl_eflags_T0(void);
void OPPROTO op_movl_T0_eflags(void);
+564
View File
@@ -0,0 +1,564 @@
/*
* virtual page mapping and translated block handling
*
* 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 <stdarg.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <inttypes.h>
#include <sys/mman.h>
#include "cpu-i386.h"
#include "exec.h"
//#define DEBUG_TB_INVALIDATE
#define DEBUG_FLUSH
/* make various TB consistency checks */
//#define DEBUG_TB_CHECK
/* threshold to flush the translated code buffer */
#define CODE_GEN_BUFFER_MAX_SIZE (CODE_GEN_BUFFER_SIZE - CODE_GEN_MAX_SIZE)
#define CODE_GEN_MAX_BLOCKS (CODE_GEN_BUFFER_SIZE / 64)
TranslationBlock tbs[CODE_GEN_MAX_BLOCKS];
TranslationBlock *tb_hash[CODE_GEN_HASH_SIZE];
int nb_tbs;
/* any access to the tbs or the page table must use this lock */
spinlock_t tb_lock = SPIN_LOCK_UNLOCKED;
uint8_t code_gen_buffer[CODE_GEN_BUFFER_SIZE];
uint8_t *code_gen_ptr;
/* XXX: pack the flags in the low bits of the pointer ? */
typedef struct PageDesc {
unsigned long flags;
TranslationBlock *first_tb;
} PageDesc;
#define L2_BITS 10
#define L1_BITS (32 - L2_BITS - TARGET_PAGE_BITS)
#define L1_SIZE (1 << L1_BITS)
#define L2_SIZE (1 << L2_BITS)
static void tb_invalidate_page(unsigned long address);
unsigned long real_host_page_size;
unsigned long host_page_bits;
unsigned long host_page_size;
unsigned long host_page_mask;
static PageDesc *l1_map[L1_SIZE];
void page_init(void)
{
/* NOTE: we can always suppose that host_page_size >=
TARGET_PAGE_SIZE */
real_host_page_size = getpagesize();
if (host_page_size == 0)
host_page_size = real_host_page_size;
if (host_page_size < TARGET_PAGE_SIZE)
host_page_size = TARGET_PAGE_SIZE;
host_page_bits = 0;
while ((1 << host_page_bits) < host_page_size)
host_page_bits++;
host_page_mask = ~(host_page_size - 1);
}
/* dump memory mappings */
void page_dump(FILE *f)
{
unsigned long start, end;
int i, j, prot, prot1;
PageDesc *p;
fprintf(f, "%-8s %-8s %-8s %s\n",
"start", "end", "size", "prot");
start = -1;
end = -1;
prot = 0;
for(i = 0; i <= L1_SIZE; i++) {
if (i < L1_SIZE)
p = l1_map[i];
else
p = NULL;
for(j = 0;j < L2_SIZE; j++) {
if (!p)
prot1 = 0;
else
prot1 = p[j].flags;
if (prot1 != prot) {
end = (i << (32 - L1_BITS)) | (j << TARGET_PAGE_BITS);
if (start != -1) {
fprintf(f, "%08lx-%08lx %08lx %c%c%c\n",
start, end, end - start,
prot & PAGE_READ ? 'r' : '-',
prot & PAGE_WRITE ? 'w' : '-',
prot & PAGE_EXEC ? 'x' : '-');
}
if (prot1 != 0)
start = end;
else
start = -1;
prot = prot1;
}
if (!p)
break;
}
}
}
static inline PageDesc *page_find_alloc(unsigned int index)
{
PageDesc **lp, *p;
lp = &l1_map[index >> L2_BITS];
p = *lp;
if (!p) {
/* allocate if not found */
p = malloc(sizeof(PageDesc) * L2_SIZE);
memset(p, 0, sizeof(PageDesc) * L2_SIZE);
*lp = p;
}
return p + (index & (L2_SIZE - 1));
}
static inline PageDesc *page_find(unsigned int index)
{
PageDesc *p;
p = l1_map[index >> L2_BITS];
if (!p)
return 0;
return p + (index & (L2_SIZE - 1));
}
int page_get_flags(unsigned long address)
{
PageDesc *p;
p = page_find(address >> TARGET_PAGE_BITS);
if (!p)
return 0;
return p->flags;
}
/* modify the flags of a page and invalidate the code if
necessary. The flag PAGE_WRITE_ORG is positionned automatically
depending on PAGE_WRITE */
void page_set_flags(unsigned long start, unsigned long end, int flags)
{
PageDesc *p;
unsigned long addr;
start = start & TARGET_PAGE_MASK;
end = TARGET_PAGE_ALIGN(end);
if (flags & PAGE_WRITE)
flags |= PAGE_WRITE_ORG;
spin_lock(&tb_lock);
for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) {
p = page_find_alloc(addr >> TARGET_PAGE_BITS);
/* if the write protection is set, then we invalidate the code
inside */
if (!(p->flags & PAGE_WRITE) &&
(flags & PAGE_WRITE) &&
p->first_tb) {
tb_invalidate_page(addr);
}
p->flags = flags;
}
spin_unlock(&tb_lock);
}
void cpu_x86_tblocks_init(void)
{
if (!code_gen_ptr) {
code_gen_ptr = code_gen_buffer;
}
}
/* set to NULL all the 'first_tb' fields in all PageDescs */
static void page_flush_tb(void)
{
int i, j;
PageDesc *p;
for(i = 0; i < L1_SIZE; i++) {
p = l1_map[i];
if (p) {
for(j = 0; j < L2_SIZE; j++)
p[j].first_tb = NULL;
}
}
}
/* flush all the translation blocks */
/* XXX: tb_flush is currently not thread safe */
void tb_flush(void)
{
int i;
#ifdef DEBUG_FLUSH
printf("qemu: flush code_size=%d nb_tbs=%d avg_tb_size=%d\n",
code_gen_ptr - code_gen_buffer,
nb_tbs,
(code_gen_ptr - code_gen_buffer) / nb_tbs);
#endif
nb_tbs = 0;
for(i = 0;i < CODE_GEN_HASH_SIZE; i++)
tb_hash[i] = NULL;
page_flush_tb();
code_gen_ptr = code_gen_buffer;
/* XXX: flush processor icache at this point if cache flush is
expensive */
}
#ifdef DEBUG_TB_CHECK
static void tb_invalidate_check(unsigned long address)
{
TranslationBlock *tb;
int i;
address &= TARGET_PAGE_MASK;
for(i = 0;i < CODE_GEN_HASH_SIZE; i++) {
for(tb = tb_hash[i]; tb != NULL; tb = tb->hash_next) {
if (!(address + TARGET_PAGE_SIZE <= tb->pc ||
address >= tb->pc + tb->size)) {
printf("ERROR invalidate: address=%08lx PC=%08lx size=%04x\n",
address, tb->pc, tb->size);
}
}
}
}
/* verify that all the pages have correct rights for code */
static void tb_page_check(void)
{
TranslationBlock *tb;
int i, flags1, flags2;
for(i = 0;i < CODE_GEN_HASH_SIZE; i++) {
for(tb = tb_hash[i]; tb != NULL; tb = tb->hash_next) {
flags1 = page_get_flags(tb->pc);
flags2 = page_get_flags(tb->pc + tb->size - 1);
if ((flags1 & PAGE_WRITE) || (flags2 & PAGE_WRITE)) {
printf("ERROR page flags: PC=%08lx size=%04x f1=%x f2=%x\n",
tb->pc, tb->size, flags1, flags2);
}
}
}
}
void tb_jmp_check(TranslationBlock *tb)
{
TranslationBlock *tb1;
unsigned int n1;
/* suppress any remaining jumps to this TB */
tb1 = tb->jmp_first;
for(;;) {
n1 = (long)tb1 & 3;
tb1 = (TranslationBlock *)((long)tb1 & ~3);
if (n1 == 2)
break;
tb1 = tb1->jmp_next[n1];
}
/* check end of list */
if (tb1 != tb) {
printf("ERROR: jmp_list from 0x%08lx\n", (long)tb);
}
}
#endif
/* invalidate one TB */
static inline void tb_remove(TranslationBlock **ptb, TranslationBlock *tb,
int next_offset)
{
TranslationBlock *tb1;
for(;;) {
tb1 = *ptb;
if (tb1 == tb) {
*ptb = *(TranslationBlock **)((char *)tb1 + next_offset);
break;
}
ptb = (TranslationBlock **)((char *)tb1 + next_offset);
}
}
static inline void tb_jmp_remove(TranslationBlock *tb, int n)
{
TranslationBlock *tb1, **ptb;
unsigned int n1;
ptb = &tb->jmp_next[n];
tb1 = *ptb;
if (tb1) {
/* find tb(n) in circular list */
for(;;) {
tb1 = *ptb;
n1 = (long)tb1 & 3;
tb1 = (TranslationBlock *)((long)tb1 & ~3);
if (n1 == n && tb1 == tb)
break;
if (n1 == 2) {
ptb = &tb1->jmp_first;
} else {
ptb = &tb1->jmp_next[n1];
}
}
/* now we can suppress tb(n) from the list */
*ptb = tb->jmp_next[n];
tb->jmp_next[n] = NULL;
}
}
/* reset the jump entry 'n' of a TB so that it is not chained to
another TB */
static inline void tb_reset_jump(TranslationBlock *tb, int n)
{
tb_set_jmp_target(tb, n, (unsigned long)(tb->tc_ptr + tb->tb_next_offset[n]));
}
static inline void tb_invalidate(TranslationBlock *tb, int parity)
{
PageDesc *p;
unsigned int page_index1, page_index2;
unsigned int h, n1;
TranslationBlock *tb1, *tb2;
/* remove the TB from the hash list */
h = tb_hash_func(tb->pc);
tb_remove(&tb_hash[h], tb,
offsetof(TranslationBlock, hash_next));
/* remove the TB from the page list */
page_index1 = tb->pc >> TARGET_PAGE_BITS;
if ((page_index1 & 1) == parity) {
p = page_find(page_index1);
tb_remove(&p->first_tb, tb,
offsetof(TranslationBlock, page_next[page_index1 & 1]));
}
page_index2 = (tb->pc + tb->size - 1) >> TARGET_PAGE_BITS;
if ((page_index2 & 1) == parity) {
p = page_find(page_index2);
tb_remove(&p->first_tb, tb,
offsetof(TranslationBlock, page_next[page_index2 & 1]));
}
/* suppress this TB from the two jump lists */
tb_jmp_remove(tb, 0);
tb_jmp_remove(tb, 1);
/* suppress any remaining jumps to this TB */
tb1 = tb->jmp_first;
for(;;) {
n1 = (long)tb1 & 3;
if (n1 == 2)
break;
tb1 = (TranslationBlock *)((long)tb1 & ~3);
tb2 = tb1->jmp_next[n1];
tb_reset_jump(tb1, n1);
tb1->jmp_next[n1] = NULL;
tb1 = tb2;
}
tb->jmp_first = (TranslationBlock *)((long)tb | 2); /* fail safe */
}
/* invalidate all TBs which intersect with the target page starting at addr */
static void tb_invalidate_page(unsigned long address)
{
TranslationBlock *tb_next, *tb;
unsigned int page_index;
int parity1, parity2;
PageDesc *p;
#ifdef DEBUG_TB_INVALIDATE
printf("tb_invalidate_page: %lx\n", address);
#endif
page_index = address >> TARGET_PAGE_BITS;
p = page_find(page_index);
if (!p)
return;
tb = p->first_tb;
parity1 = page_index & 1;
parity2 = parity1 ^ 1;
while (tb != NULL) {
tb_next = tb->page_next[parity1];
tb_invalidate(tb, parity2);
tb = tb_next;
}
p->first_tb = NULL;
}
/* add the tb in the target page and protect it if necessary */
static inline void tb_alloc_page(TranslationBlock *tb, unsigned int page_index)
{
PageDesc *p;
unsigned long host_start, host_end, addr, page_addr;
int prot;
p = page_find_alloc(page_index);
tb->page_next[page_index & 1] = p->first_tb;
p->first_tb = tb;
if (p->flags & PAGE_WRITE) {
/* force the host page as non writable (writes will have a
page fault + mprotect overhead) */
page_addr = (page_index << TARGET_PAGE_BITS);
host_start = page_addr & host_page_mask;
host_end = host_start + host_page_size;
prot = 0;
for(addr = host_start; addr < host_end; addr += TARGET_PAGE_SIZE)
prot |= page_get_flags(addr);
mprotect((void *)host_start, host_page_size,
(prot & PAGE_BITS) & ~PAGE_WRITE);
#ifdef DEBUG_TB_INVALIDATE
printf("protecting code page: 0x%08lx\n",
host_start);
#endif
p->flags &= ~PAGE_WRITE;
#ifdef DEBUG_TB_CHECK
tb_page_check();
#endif
}
}
/* Allocate a new translation block. Flush the translation buffer if
too many translation blocks or too much generated code. */
TranslationBlock *tb_alloc(unsigned long pc)
{
TranslationBlock *tb;
if (nb_tbs >= CODE_GEN_MAX_BLOCKS ||
(code_gen_ptr - code_gen_buffer) >= CODE_GEN_BUFFER_MAX_SIZE)
return NULL;
tb = &tbs[nb_tbs++];
tb->pc = pc;
return tb;
}
/* link the tb with the other TBs */
void tb_link(TranslationBlock *tb)
{
unsigned int page_index1, page_index2;
/* add in the page list */
page_index1 = tb->pc >> TARGET_PAGE_BITS;
tb_alloc_page(tb, page_index1);
page_index2 = (tb->pc + tb->size - 1) >> TARGET_PAGE_BITS;
if (page_index2 != page_index1) {
tb_alloc_page(tb, page_index2);
}
tb->jmp_first = (TranslationBlock *)((long)tb | 2);
tb->jmp_next[0] = NULL;
tb->jmp_next[1] = NULL;
/* init original jump addresses */
if (tb->tb_next_offset[0] != 0xffff)
tb_reset_jump(tb, 0);
if (tb->tb_next_offset[1] != 0xffff)
tb_reset_jump(tb, 1);
}
/* called from signal handler: invalidate the code and unprotect the
page. Return TRUE if the fault was succesfully handled. */
int page_unprotect(unsigned long address)
{
unsigned int page_index, prot, pindex;
PageDesc *p, *p1;
unsigned long host_start, host_end, addr;
host_start = address & host_page_mask;
page_index = host_start >> TARGET_PAGE_BITS;
p1 = page_find(page_index);
if (!p1)
return 0;
host_end = host_start + host_page_size;
p = p1;
prot = 0;
for(addr = host_start;addr < host_end; addr += TARGET_PAGE_SIZE) {
prot |= p->flags;
p++;
}
/* if the page was really writable, then we change its
protection back to writable */
if (prot & PAGE_WRITE_ORG) {
mprotect((void *)host_start, host_page_size,
(prot & PAGE_BITS) | PAGE_WRITE);
pindex = (address - host_start) >> TARGET_PAGE_BITS;
p1[pindex].flags |= PAGE_WRITE;
/* and since the content will be modified, we must invalidate
the corresponding translated code. */
tb_invalidate_page(address);
#ifdef DEBUG_TB_CHECK
tb_invalidate_check(address);
#endif
return 1;
} else {
return 0;
}
}
/* call this function when system calls directly modify a memory area */
void page_unprotect_range(uint8_t *data, unsigned long data_size)
{
unsigned long start, end, addr;
start = (unsigned long)data;
end = start + data_size;
start &= TARGET_PAGE_MASK;
end = TARGET_PAGE_ALIGN(end);
for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) {
page_unprotect(addr);
}
}
/* find the TB 'tb' such that tb[0].tc_ptr <= tc_ptr <
tb[1].tc_ptr. Return NULL if not found */
TranslationBlock *tb_find_pc(unsigned long tc_ptr)
{
int m_min, m_max, m;
unsigned long v;
TranslationBlock *tb;
if (nb_tbs <= 0)
return NULL;
if (tc_ptr < (unsigned long)code_gen_buffer ||
tc_ptr >= (unsigned long)code_gen_ptr)
return NULL;
/* binary search (cf Knuth) */
m_min = 0;
m_max = nb_tbs - 1;
while (m_min <= m_max) {
m = (m_min + m_max) >> 1;
tb = &tbs[m];
v = (unsigned long)tb->tc_ptr;
if (v == tc_ptr)
return tb;
else if (tc_ptr < v) {
m_max = m - 1;
} else {
m_min = m + 1;
}
}
return &tbs[m_max];
}
+269
View File
@@ -0,0 +1,269 @@
/*
* internal execution defines for qemu
*
* 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
*/
#define GEN_FLAG_CODE32_SHIFT 0
#define GEN_FLAG_ADDSEG_SHIFT 1
#define GEN_FLAG_SS32_SHIFT 2
#define GEN_FLAG_VM_SHIFT 3
#define GEN_FLAG_ST_SHIFT 4
#define GEN_FLAG_TF_SHIFT 8 /* same position as eflags */
#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);
int page_unprotect(unsigned long address);
#define CODE_GEN_MAX_SIZE 65536
#define CODE_GEN_ALIGN 16 /* must be >= of the size of a icache line */
#define CODE_GEN_HASH_BITS 15
#define CODE_GEN_HASH_SIZE (1 << CODE_GEN_HASH_BITS)
/* maximum total translate dcode allocated */
#define CODE_GEN_BUFFER_SIZE (2048 * 1024)
//#define CODE_GEN_BUFFER_SIZE (128 * 1024)
#if defined(__powerpc__)
#define USE_DIRECT_JUMP
#endif
typedef struct TranslationBlock {
unsigned long pc; /* simulated PC corresponding to this block (EIP + CS base) */
unsigned long cs_base; /* CS base for this block */
unsigned int flags; /* flags defining in which context the code was generated */
uint16_t size; /* size of target code for this block (1 <=
size <= TARGET_PAGE_SIZE) */
uint8_t *tc_ptr; /* pointer to the translated code */
struct TranslationBlock *hash_next; /* next matching block */
struct TranslationBlock *page_next[2]; /* next blocks in even/odd page */
/* the following data are used to directly call another TB from
the code of this one. */
uint16_t tb_next_offset[2]; /* offset of original jump target */
#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 */
#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
the next pointer: 0 = jmp_next[0], 1 = jmp_next[1], 2 =
jmp_first */
struct TranslationBlock *jmp_next[2];
struct TranslationBlock *jmp_first;
} TranslationBlock;
static inline unsigned int tb_hash_func(unsigned long pc)
{
return pc & (CODE_GEN_HASH_SIZE - 1);
}
TranslationBlock *tb_alloc(unsigned long pc);
void tb_flush(void);
void tb_link(TranslationBlock *tb);
extern TranslationBlock *tb_hash[CODE_GEN_HASH_SIZE];
extern uint8_t code_gen_buffer[CODE_GEN_BUFFER_SIZE];
extern uint8_t *code_gen_ptr;
/* find a translation block in the translation cache. If not found,
return NULL and the pointer to the last element of the list in pptb */
static inline TranslationBlock *tb_find(TranslationBlock ***pptb,
unsigned long pc,
unsigned long cs_base,
unsigned int flags)
{
TranslationBlock **ptb, *tb;
unsigned int h;
h = tb_hash_func(pc);
ptb = &tb_hash[h];
for(;;) {
tb = *ptb;
if (!tb)
break;
if (tb->pc == pc && tb->cs_base == cs_base && tb->flags == flags)
return tb;
ptb = &tb->hash_next;
}
*pptb = ptb;
return NULL;
}
#if defined(__powerpc__)
static inline void tb_set_jmp_target(TranslationBlock *tb,
int n, unsigned long addr)
{
uint32_t val, *ptr;
unsigned long offset;
offset = (unsigned long)(tb->tc_ptr + tb->tb_jmp_offset[n]);
/* patch the branch destination */
ptr = (uint32_t *)offset;
val = *ptr;
val = (val & ~0x03fffffc) | ((addr - offset) & 0x03fffffc);
*ptr = val;
/* flush icache */
asm volatile ("dcbst 0,%0" : : "r"(ptr) : "memory");
asm volatile ("sync" : : : "memory");
asm volatile ("icbi 0,%0" : : "r"(ptr) : "memory");
asm volatile ("sync" : : : "memory");
asm volatile ("isync" : : : "memory");
}
#else
/* set the jump target */
static inline void tb_set_jmp_target(TranslationBlock *tb,
int n, unsigned long addr)
{
tb->tb_next[n] = (void *)addr;
}
#endif
static inline void tb_add_jump(TranslationBlock *tb, int n,
TranslationBlock *tb_next)
{
/* NOTE: this test is only needed for thread safety */
if (!tb->jmp_next[n]) {
/* patch the native jump address */
tb_set_jmp_target(tb, n, (unsigned long)tb_next->tc_ptr);
/* add in TB jmp circular list */
tb->jmp_next[n] = tb_next->jmp_first;
tb_next->jmp_first = (TranslationBlock *)((long)(tb) | (n));
}
}
TranslationBlock *tb_find_pc(unsigned long pc_ptr);
#ifndef offsetof
#define offsetof(type, field) ((size_t) &((type *)0)->field)
#endif
#ifdef __powerpc__
static inline int testandset (int *p)
{
int ret;
__asm__ __volatile__ (
"0: lwarx %0,0,%1 ;"
" xor. %0,%3,%0;"
" bne 1f;"
" stwcx. %2,0,%1;"
" bne- 0b;"
"1: "
: "=&r" (ret)
: "r" (p), "r" (1), "r" (0)
: "cr0", "memory");
return ret;
}
#endif
#ifdef __i386__
static inline int testandset (int *p)
{
char ret;
long int readval;
__asm__ __volatile__ ("lock; cmpxchgl %3, %1; sete %0"
: "=q" (ret), "=m" (*p), "=a" (readval)
: "r" (1), "m" (*p), "a" (0)
: "memory");
return ret;
}
#endif
#ifdef __s390__
static inline int testandset (int *p)
{
int ret;
__asm__ __volatile__ ("0: cs %0,%1,0(%2)\n"
" jl 0b"
: "=&d" (ret)
: "r" (1), "a" (p), "0" (*p)
: "cc", "memory" );
return ret;
}
#endif
#ifdef __alpha__
int testandset (int *p)
{
int ret;
unsigned long one;
__asm__ __volatile__ ("0: mov 1,%2\n"
" ldl_l %0,%1\n"
" stl_c %2,%1\n"
" beq %2,1f\n"
".subsection 2\n"
"1: br 0b\n"
".previous"
: "=r" (ret), "=m" (*p), "=r" (one)
: "m" (*p));
return ret;
}
#endif
#ifdef __sparc__
static inline int testandset (int *p)
{
int ret;
__asm__ __volatile__("ldstub [%1], %0"
: "=r" (ret)
: "r" (p)
: "memory");
return (ret ? 1 : 0);
}
#endif
typedef int spinlock_t;
#define SPIN_LOCK_UNLOCKED 0
static inline void spin_lock(spinlock_t *lock)
{
while (testandset(lock));
}
static inline void spin_unlock(spinlock_t *lock)
{
*lock = 0;
}
static inline int spin_trylock(spinlock_t *lock)
{
return !testandset(lock);
}
extern spinlock_t tb_lock;
+2300
View File
File diff suppressed because it is too large Load Diff
+32
View File
@@ -0,0 +1,32 @@
/* derived from glibc sysdeps/unix/sysv/linux/ia64/sysdep.S */
#define __ASSEMBLY__
#include <asm/asmmacro.h>
#include <asm/unistd.h>
ENTRY(__syscall_error)
.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(0)
alloc r33=ar.pfs, 0, 4, 0, 0
mov r32=rp
.body
mov r35=r8
mov r34=r1
;;
br.call.sptk.many b0 = __errno_location
.Lret0: /* force new bundle */
st4 [r8]=r35
mov r1=r34
mov rp=r32
mov r8=-1
mov ar.pfs=r33
br.ret.sptk.few b0
END(__syscall_error)
GLOBAL_ENTRY(__ia64_syscall)
mov r15=r37 /* syscall number */
break __BREAK_SYSCALL
cmp.eq p6,p0=-1,r10 /* r10 = -1 on error */
(p6) br.cond.spnt.few __syscall_error
br.ret.sptk.few b0
.endp __ia64_syscall
+378 -174
View File
@@ -10,30 +10,122 @@
#include <stdlib.h>
#include <string.h>
#include "gemu.h"
#include "qemu.h"
#include "disas.h"
#ifdef TARGET_I386
#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.
*/
#define elf_check_arch(x) ( ((x) == EM_386) || ((x) == EM_486) )
/*
* These are used to set parameters in the core dumps.
*/
#define ELF_CLASS ELFCLASS32
#define ELF_DATA ELFDATA2LSB
#define ELF_ARCH EM_386
/* SVR4/i386 ABI (pages 3-31, 3-32) says that when the program
starts %edx contains a pointer to a function which might be
registered using `atexit'. This provides a mean for the
dynamic linker to call DT_FINI functions for shared libraries
that have been loaded before the code runs.
A value of 0 tells we have no such handler. */
#define ELF_PLAT_INIT(_r) _r->edx = 0
#define USE_ELF_CORE_DUMP
#define ELF_EXEC_PAGESIZE 4096
#endif
#include "linux_bin.h"
#include "elf.h"
#include "segment.h"
/*
* MAX_ARG_PAGES defines the number of pages allocated for arguments
* and envelope for the new program. 32 should suffice, this gives
* a maximum env+arg of 128kB w/4KB pages!
*/
#define MAX_ARG_PAGES 32
/*
* This structure is used to hold the arguments that are
* used when loading binaries.
*/
struct linux_binprm {
char buf[128];
unsigned long page[MAX_ARG_PAGES];
unsigned long p;
int sh_bang;
int fd;
int e_uid, e_gid;
int argc, envc;
char * filename; /* Name of binary */
unsigned long loader, exec;
int dont_iput; /* binfmt handler has put inode */
};
struct exec
{
unsigned int a_info; /* Use macros N_MAGIC, etc for access */
unsigned int a_text; /* length of text, in bytes */
unsigned int a_data; /* length of data, in bytes */
unsigned int a_bss; /* length of uninitialized data area, in bytes */
unsigned int a_syms; /* length of symbol table data in file, in bytes */
unsigned int a_entry; /* start address */
unsigned int a_trsize; /* length of relocation info for text, in bytes */
unsigned int a_drsize; /* length of relocation info for data, in bytes */
};
#define N_MAGIC(exec) ((exec).a_info & 0xffff)
#define OMAGIC 0407
#define NMAGIC 0410
#define ZMAGIC 0413
#define QMAGIC 0314
/* max code+data+bss space allocated to elf interpreter */
#define INTERP_MAP_SIZE (32 * 1024 * 1024)
/* max code+data+bss+brk space allocated to ET_DYN executables */
#define ET_DYN_MAP_SIZE (128 * 1024 * 1024)
/* from personality.h */
/* Flags for bug emulation. These occupy the top three bytes. */
#define STICKY_TIMEOUTS 0x4000000
#define WHOLE_SECONDS 0x2000000
/* Personality types. These go in the low byte. Avoid using the top bit,
* it will conflict with error returns.
*/
#define PER_MASK (0x00ff)
#define PER_LINUX (0x0000)
#define PER_SVR4 (0x0001 | STICKY_TIMEOUTS)
#define PER_SVR3 (0x0002 | STICKY_TIMEOUTS)
#define PER_SCOSVR3 (0x0003 | STICKY_TIMEOUTS | WHOLE_SECONDS)
#define PER_WYSEV386 (0x0004 | STICKY_TIMEOUTS)
#define PER_ISCR4 (0x0005 | STICKY_TIMEOUTS)
#define PER_BSD (0x0006)
#define PER_XENIX (0x0007 | STICKY_TIMEOUTS)
/* Necessary parameters */
#define ALPHA_PAGE_SIZE 4096
#define X86_PAGE_SIZE 4096
#define ALPHA_PAGE_MASK (~(ALPHA_PAGE_SIZE-1))
#define X86_PAGE_MASK (~(X86_PAGE_SIZE-1))
#define ALPHA_PAGE_ALIGN(addr) ((((addr)+ALPHA_PAGE_SIZE)-1)&ALPHA_PAGE_MASK)
#define X86_PAGE_ALIGN(addr) ((((addr)+X86_PAGE_SIZE)-1)&X86_PAGE_MASK)
#define NGROUPS 32
#define X86_ELF_EXEC_PAGESIZE X86_PAGE_SIZE
#define X86_ELF_PAGESTART(_v) ((_v) & ~(unsigned long)(X86_ELF_EXEC_PAGESIZE-1))
#define X86_ELF_PAGEOFFSET(_v) ((_v) & (X86_ELF_EXEC_PAGESIZE-1))
#define ALPHA_ELF_PAGESTART(_v) ((_v) & ~(unsigned long)(ALPHA_PAGE_SIZE-1))
#define ALPHA_ELF_PAGEOFFSET(_v) ((_v) & (ALPHA_PAGE_SIZE-1))
#define TARGET_ELF_EXEC_PAGESIZE TARGET_PAGE_SIZE
#define TARGET_ELF_PAGESTART(_v) ((_v) & ~(unsigned long)(TARGET_ELF_EXEC_PAGESIZE-1))
#define TARGET_ELF_PAGEOFFSET(_v) ((_v) & (TARGET_ELF_EXEC_PAGESIZE-1))
#define INTERPRETER_NONE 0
#define INTERPRETER_AOUT 1
@@ -41,12 +133,18 @@
#define DLINFO_ITEMS 12
/* Where we find X86 libraries... */
//#define X86_DEFAULT_LIB_DIR "/usr/x86/"
#define X86_DEFAULT_LIB_DIR "/"
#define put_user(x,ptr) (void)(*(ptr) = (typeof(*ptr))(x))
#define get_user(ptr) (typeof(*ptr))(*(ptr))
//extern void * mmap4k();
#define mmap4k(a, b, c, d, e, f) mmap((void *)(a), b, c, d, e, f)
static inline void memcpy_fromfs(void * to, const void * from, unsigned long n)
{
memcpy(to, from, n);
}
static inline void memcpy_tofs(void * to, const void * from, unsigned long n)
{
memcpy(to, from, n);
}
extern unsigned long x86_stack_size;
@@ -81,6 +179,28 @@ static void bswap_phdr(Elf32_Phdr *phdr)
bswap32s(&phdr->p_flags); /* Segment flags */
bswap32s(&phdr->p_align); /* Segment alignment */
}
static void bswap_shdr(Elf32_Shdr *shdr)
{
bswap32s(&shdr->sh_name);
bswap32s(&shdr->sh_type);
bswap32s(&shdr->sh_flags);
bswap32s(&shdr->sh_addr);
bswap32s(&shdr->sh_offset);
bswap32s(&shdr->sh_size);
bswap32s(&shdr->sh_link);
bswap32s(&shdr->sh_info);
bswap32s(&shdr->sh_addralign);
bswap32s(&shdr->sh_entsize);
}
static void bswap_sym(Elf32_Sym *sym)
{
bswap32s(&sym->st_name);
bswap32s(&sym->st_value);
bswap32s(&sym->st_size);
bswap16s(&sym->st_shndx);
}
#endif
static void * get_free_page(void)
@@ -90,8 +210,8 @@ static void * get_free_page(void)
/* User-space version of kernel get_free_page. Returns a page-aligned
* page-sized chunk of memory.
*/
retval = mmap4k(0, ALPHA_PAGE_SIZE, PROT_READ|PROT_WRITE,
MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
retval = (void *)target_mmap(0, host_page_size, PROT_READ|PROT_WRITE,
MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
if((long)retval == -1) {
perror("get_free_page");
@@ -104,7 +224,7 @@ static void * get_free_page(void)
static void free_page(void * pageaddr)
{
(void)munmap(pageaddr, ALPHA_PAGE_SIZE);
target_munmap((unsigned long)pageaddr, host_page_size);
}
/*
@@ -135,9 +255,9 @@ static unsigned long copy_strings(int argc,char ** argv,unsigned long *page,
while (len) {
--p; --tmp; --len;
if (--offset < 0) {
offset = p % X86_PAGE_SIZE;
if (!(pag = (char *) page[p/X86_PAGE_SIZE]) &&
!(pag = (char *) page[p/X86_PAGE_SIZE] =
offset = p % TARGET_PAGE_SIZE;
if (!(pag = (char *) page[p/TARGET_PAGE_SIZE]) &&
!(pag = (char *) page[p/TARGET_PAGE_SIZE] =
(unsigned long *) get_free_page())) {
return 0;
}
@@ -246,48 +366,43 @@ static int prepare_binprm(struct linux_binprm *bprm)
unsigned long setup_arg_pages(unsigned long p, struct linux_binprm * bprm,
struct image_info * info)
{
unsigned long stack_base;
unsigned long stack_base, size, error;
int i;
extern unsigned long stktop;
stack_base = X86_STACK_TOP - MAX_ARG_PAGES*X86_PAGE_SIZE;
/* Create enough stack to hold everything. If we don't use
* it for args, we'll use it for something else...
*/
size = x86_stack_size;
if (size < MAX_ARG_PAGES*TARGET_PAGE_SIZE)
size = MAX_ARG_PAGES*TARGET_PAGE_SIZE;
error = target_mmap(0,
size + host_page_size,
PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS,
-1, 0);
if (error == -1) {
perror("stk mmap");
exit(-1);
}
/* we reserve one extra page at the top of the stack as guard */
target_mprotect(error + size, host_page_size, PROT_NONE);
stack_base = error + size - MAX_ARG_PAGES*TARGET_PAGE_SIZE;
p += stack_base;
if (bprm->loader) {
bprm->loader += stack_base;
}
bprm->exec += stack_base;
/* Create enough stack to hold everything. If we don't use
* it for args, we'll use it for something else...
*/
if(x86_stack_size > MAX_ARG_PAGES*X86_PAGE_SIZE) {
if((long)mmap4k((void *)(X86_STACK_TOP-x86_stack_size), x86_stack_size + X86_PAGE_SIZE,
PROT_READ | PROT_WRITE,
MAP_GROWSDOWN | MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0) == -1) {
perror("stk mmap");
exit(-1);
}
}
else {
if((long)mmap4k((void *)stack_base, (MAX_ARG_PAGES+1)*X86_PAGE_SIZE,
PROT_READ | PROT_WRITE,
MAP_GROWSDOWN | MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0) == -1) {
perror("stk mmap");
exit(-1);
}
}
stktop = stack_base;
for (i = 0 ; i < MAX_ARG_PAGES ; i++) {
if (bprm->page[i]) {
info->rss++;
memcpy((void *)stack_base, (void *)bprm->page[i], X86_PAGE_SIZE);
memcpy((void *)stack_base, (void *)bprm->page[i], TARGET_PAGE_SIZE);
free_page((void *)bprm->page[i]);
}
stack_base += X86_PAGE_SIZE;
stack_base += TARGET_PAGE_SIZE;
}
return p;
}
@@ -295,13 +410,13 @@ unsigned long setup_arg_pages(unsigned long p, struct linux_binprm * bprm,
static void set_brk(unsigned long start, unsigned long end)
{
/* page-align the start and end addresses... */
start = ALPHA_PAGE_ALIGN(start);
end = ALPHA_PAGE_ALIGN(end);
start = HOST_PAGE_ALIGN(start);
end = HOST_PAGE_ALIGN(end);
if (end <= start)
return;
if((long)mmap4k(start, end - start,
PROT_READ | PROT_WRITE | PROT_EXEC,
MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0) == -1) {
if(target_mmap(start, end - start,
PROT_READ | PROT_WRITE | PROT_EXEC,
MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0) == -1) {
perror("cannot mmap brk");
exit(-1);
}
@@ -319,9 +434,9 @@ static void padzero(unsigned long elf_bss)
unsigned long nbyte;
char * fpnt;
nbyte = elf_bss & (ALPHA_PAGE_SIZE-1); /* was X86_PAGE_SIZE - JRP */
nbyte = elf_bss & (host_page_size-1); /* was TARGET_PAGE_SIZE - JRP */
if (nbyte) {
nbyte = ALPHA_PAGE_SIZE - nbyte;
nbyte = host_page_size - nbyte;
fpnt = (char *) elf_bss;
do {
*fpnt++ = 0;
@@ -330,14 +445,14 @@ static void padzero(unsigned long elf_bss)
}
static unsigned int * create_elf_tables(char *p, int argc, int envc,
struct elfhdr * exec,
unsigned long load_addr,
unsigned long interp_load_addr, int ibcs,
struct image_info *info)
struct elfhdr * exec,
unsigned long load_addr,
unsigned long load_bias,
unsigned long interp_load_addr, int ibcs,
struct image_info *info)
{
unsigned int *argv, *envp, *dlinfo;
unsigned int *sp;
char **alpha_envp;
target_ulong *argv, *envp, *dlinfo;
target_ulong *sp;
/*
* Force 16 byte alignment here for generality.
@@ -350,49 +465,42 @@ static unsigned int * create_elf_tables(char *p, int argc, int envc,
sp -= argc+1;
argv = sp;
if (!ibcs) {
put_user(envp,--sp);
put_user(argv,--sp);
put_user(tswapl((target_ulong)envp),--sp);
put_user(tswapl((target_ulong)argv),--sp);
}
alpha_envp = (char **)malloc((envc+1) * sizeof(char *));
#define NEW_AUX_ENT(id, val) \
put_user ((id), dlinfo++); \
put_user ((val), dlinfo++)
put_user (tswapl(id), dlinfo++); \
put_user (tswapl(val), dlinfo++)
if (exec) { /* Put this here for an ELF program interpreter */
struct elf_phdr * eppnt;
eppnt = (struct elf_phdr *)((unsigned long)exec->e_phoff);
NEW_AUX_ENT (AT_PHDR, (unsigned int)(load_addr + exec->e_phoff));
NEW_AUX_ENT (AT_PHENT, (unsigned int)(sizeof (struct elf_phdr)));
NEW_AUX_ENT (AT_PHNUM, (unsigned int)(exec->e_phnum));
NEW_AUX_ENT (AT_PAGESZ, (unsigned int)(ALPHA_PAGE_SIZE));
NEW_AUX_ENT (AT_BASE, (unsigned int)(interp_load_addr));
NEW_AUX_ENT (AT_FLAGS, (unsigned int)0);
NEW_AUX_ENT (AT_ENTRY, (unsigned int) exec->e_entry);
NEW_AUX_ENT (AT_UID, (unsigned int) getuid());
NEW_AUX_ENT (AT_EUID, (unsigned int) geteuid());
NEW_AUX_ENT (AT_GID, (unsigned int) getgid());
NEW_AUX_ENT (AT_EGID, (unsigned int) getegid());
NEW_AUX_ENT (AT_PHDR, (target_ulong)(load_addr + exec->e_phoff));
NEW_AUX_ENT (AT_PHENT, (target_ulong)(sizeof (struct elf_phdr)));
NEW_AUX_ENT (AT_PHNUM, (target_ulong)(exec->e_phnum));
NEW_AUX_ENT (AT_PAGESZ, (target_ulong)(TARGET_PAGE_SIZE));
NEW_AUX_ENT (AT_BASE, (target_ulong)(interp_load_addr));
NEW_AUX_ENT (AT_FLAGS, (target_ulong)0);
NEW_AUX_ENT (AT_ENTRY, load_bias + exec->e_entry);
NEW_AUX_ENT (AT_UID, (target_ulong) getuid());
NEW_AUX_ENT (AT_EUID, (target_ulong) geteuid());
NEW_AUX_ENT (AT_GID, (target_ulong) getgid());
NEW_AUX_ENT (AT_EGID, (target_ulong) getegid());
}
NEW_AUX_ENT (AT_NULL, 0);
#undef NEW_AUX_ENT
put_user((unsigned int)argc,--sp);
put_user(tswapl(argc),--sp);
info->arg_start = (unsigned int)((unsigned long)p & 0xffffffff);
while (argc-->0) {
put_user(p,argv++);
put_user(tswapl((target_ulong)p),argv++);
while (get_user(p++)) /* nothing */ ;
}
put_user(0,argv);
info->arg_end = info->env_start = (unsigned int)((unsigned long)p & 0xffffffff);
__environ = alpha_envp;
while (envc-->0) {
*alpha_envp++ = (char *)p;
put_user(p,envp++);
put_user(tswapl((target_ulong)p),envp++);
while (get_user(p++)) /* nothing */ ;
}
put_user(0,envp);
*alpha_envp = 0;
info->env_end = (unsigned int)((unsigned long)p & 0xffffffff);
return sp;
}
@@ -405,7 +513,7 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex,
{
struct elf_phdr *elf_phdata = NULL;
struct elf_phdr *eppnt;
unsigned long load_addr;
unsigned long load_addr = 0;
int load_addr_set = 0;
int retval;
unsigned long last_bss, elf_bss;
@@ -416,21 +524,20 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex,
last_bss = 0;
error = 0;
/* We put this here so that mmap will search for the *first*
* available memory...
*/
load_addr = INTERP_LOADADDR;
#ifdef BSWAP_NEEDED
bswap_ehdr(interp_elf_ex);
#endif
/* First of all, some simple consistency checks */
if ((interp_elf_ex->e_type != ET_EXEC &&
interp_elf_ex->e_type != ET_DYN) ||
interp_elf_ex->e_type != ET_DYN) ||
!elf_check_arch(interp_elf_ex->e_machine)) {
return ~0UL;
}
/* Now read in all of the header information */
if (sizeof(struct elf_phdr) * interp_elf_ex->e_phnum > X86_PAGE_SIZE)
if (sizeof(struct elf_phdr) * interp_elf_ex->e_phnum > TARGET_PAGE_SIZE)
return ~0UL;
elf_phdata = (struct elf_phdr *)
@@ -443,11 +550,10 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex,
* If the size of this structure has changed, then punt, since
* we will be doing the wrong thing.
*/
if (interp_elf_ex->e_phentsize != sizeof(struct elf_phdr))
{
if (interp_elf_ex->e_phentsize != sizeof(struct elf_phdr)) {
free(elf_phdata);
return ~0UL;
}
}
retval = lseek(interpreter_fd, interp_elf_ex->e_phoff, SEEK_SET);
if(retval >= 0) {
@@ -455,7 +561,6 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex,
(char *) elf_phdata,
sizeof(struct elf_phdr) * interp_elf_ex->e_phnum);
}
if (retval < 0) {
perror("load_elf_interp");
exit(-1);
@@ -468,6 +573,21 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex,
bswap_phdr(eppnt);
}
#endif
if (interp_elf_ex->e_type == ET_DYN) {
/* in order to avoid harcoding the interpreter load
address in qemu, we allocate a big enough memory zone */
error = target_mmap(0, INTERP_MAP_SIZE,
PROT_NONE, MAP_PRIVATE | MAP_ANON,
-1, 0);
if (error == -1) {
perror("mmap");
exit(-1);
}
load_addr = error;
load_addr_set = 1;
}
eppnt = elf_phdata;
for(i=0; i<interp_elf_ex->e_phnum; i++, eppnt++)
if (eppnt->p_type == PT_LOAD) {
@@ -483,12 +603,12 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex,
elf_type |= MAP_FIXED;
vaddr = eppnt->p_vaddr;
}
error = (unsigned long)mmap4k(load_addr+X86_ELF_PAGESTART(vaddr),
eppnt->p_filesz + X86_ELF_PAGEOFFSET(eppnt->p_vaddr),
error = target_mmap(load_addr+TARGET_ELF_PAGESTART(vaddr),
eppnt->p_filesz + TARGET_ELF_PAGEOFFSET(eppnt->p_vaddr),
elf_prot,
elf_type,
interpreter_fd,
eppnt->p_offset - X86_ELF_PAGEOFFSET(eppnt->p_vaddr));
eppnt->p_offset - TARGET_ELF_PAGEOFFSET(eppnt->p_vaddr));
if (error > -1024UL) {
/* Real error */
@@ -528,13 +648,13 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex,
* bss page.
*/
padzero(elf_bss);
elf_bss = X86_ELF_PAGESTART(elf_bss + ALPHA_PAGE_SIZE - 1); /* What we have mapped so far */
elf_bss = TARGET_ELF_PAGESTART(elf_bss + host_page_size - 1); /* What we have mapped so far */
/* Map the last of the bss segment */
if (last_bss > elf_bss) {
mmap4k(elf_bss, last_bss-elf_bss,
PROT_READ|PROT_WRITE|PROT_EXEC,
MAP_FIXED|MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
target_mmap(elf_bss, last_bss-elf_bss,
PROT_READ|PROT_WRITE|PROT_EXEC,
MAP_FIXED|MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
}
free(elf_phdata);
@@ -542,21 +662,70 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex,
return ((unsigned long) interp_elf_ex->e_entry) + load_addr;
}
/* Best attempt to load symbols from this ELF object. */
static void load_symbols(struct elfhdr *hdr, int fd)
{
unsigned int i;
struct elf_shdr sechdr, symtab, strtab;
char *strings;
lseek(fd, hdr->e_shoff, SEEK_SET);
for (i = 0; i < hdr->e_shnum; i++) {
if (read(fd, &sechdr, sizeof(sechdr)) != sizeof(sechdr))
return;
#ifdef BSWAP_NEEDED
bswap_shdr(&sechdr);
#endif
if (sechdr.sh_type == SHT_SYMTAB) {
symtab = sechdr;
lseek(fd, hdr->e_shoff
+ sizeof(sechdr) * sechdr.sh_link, SEEK_SET);
if (read(fd, &strtab, sizeof(strtab))
!= sizeof(strtab))
return;
#ifdef BSWAP_NEEDED
bswap_shdr(&strtab);
#endif
goto found;
}
}
return; /* Shouldn't happen... */
static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs,
struct image_info * info)
found:
/* Now know where the strtab and symtab are. Snarf them. */
disas_symtab = malloc(symtab.sh_size);
disas_strtab = strings = malloc(strtab.sh_size);
if (!disas_symtab || !disas_strtab)
return;
lseek(fd, symtab.sh_offset, SEEK_SET);
if (read(fd, disas_symtab, symtab.sh_size) != symtab.sh_size)
return;
#ifdef BSWAP_NEEDED
for (i = 0; i < symtab.sh_size / sizeof(struct elf_sym); i++)
bswap_sym(disas_symtab + sizeof(struct elf_sym)*i);
#endif
lseek(fd, strtab.sh_offset, SEEK_SET);
if (read(fd, strings, strtab.sh_size) != strtab.sh_size)
return;
disas_num_syms = symtab.sh_size / sizeof(struct elf_sym);
}
static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
struct image_info * info)
{
struct elfhdr elf_ex;
struct elfhdr interp_elf_ex;
struct exec interp_ex;
int interpreter_fd = -1; /* avoid warning */
unsigned long load_addr;
unsigned long load_addr, load_bias;
int load_addr_set = 0;
unsigned int interpreter_type = INTERPRETER_NONE;
unsigned char ibcs2_interpreter;
int i;
void * mapped_addr;
unsigned long mapped_addr;
struct elf_phdr * elf_ppnt;
struct elf_phdr *elf_phdata;
unsigned long elf_bss, k, elf_brk;
@@ -571,6 +740,7 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs,
ibcs2_interpreter = 0;
status = 0;
load_addr = 0;
load_bias = 0;
elf_ex = *((struct elfhdr *) bprm->buf); /* exec-header */
#ifdef BSWAP_NEEDED
bswap_ehdr(&elf_ex);
@@ -581,7 +751,6 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs,
return -ENOEXEC;
}
/* First of all, some simple consistency checks */
if ((elf_ex.e_type != ET_EXEC && elf_ex.e_type != ET_DYN) ||
(! elf_check_arch(elf_ex.e_machine))) {
@@ -608,6 +777,12 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs,
return -errno;
}
#ifdef BSWAP_NEEDED
elf_ppnt = elf_phdata;
for (i=0; i<elf_ex.e_phnum; i++, elf_ppnt++) {
bswap_phdr(elf_ppnt);
}
#endif
elf_ppnt = elf_phdata;
elf_bss = 0;
@@ -635,7 +810,7 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs,
* is an a.out format binary
*/
elf_interpreter = (char *)malloc(elf_ppnt->p_filesz+strlen(X86_DEFAULT_LIB_DIR));
elf_interpreter = (char *)malloc(elf_ppnt->p_filesz);
if (elf_interpreter == NULL) {
free (elf_phdata);
@@ -643,12 +818,9 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs,
return -ENOMEM;
}
strcpy(elf_interpreter, X86_DEFAULT_LIB_DIR);
retval = lseek(bprm->fd, elf_ppnt->p_offset, SEEK_SET);
if(retval >= 0) {
retval = read(bprm->fd,
elf_interpreter+strlen(X86_DEFAULT_LIB_DIR),
elf_ppnt->p_filesz);
retval = read(bprm->fd, elf_interpreter, elf_ppnt->p_filesz);
}
if(retval < 0) {
perror("load_elf_binary2");
@@ -670,7 +842,7 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs,
printf("Using ELF interpreter %s\n", elf_interpreter);
#endif
if (retval >= 0) {
retval = open(elf_interpreter, O_RDONLY);
retval = open(path(elf_interpreter), O_RDONLY);
if(retval >= 0) {
interpreter_fd = retval;
}
@@ -770,56 +942,85 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs,
* address.
*/
for(i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum; i++, elf_ppnt++) {
if (elf_ppnt->p_type == PT_LOAD) {
int elf_prot = 0;
if (elf_ppnt->p_flags & PF_R) elf_prot |= PROT_READ;
if (elf_ppnt->p_flags & PF_W) elf_prot |= PROT_WRITE;
if (elf_ppnt->p_flags & PF_X) elf_prot |= PROT_EXEC;
mapped_addr = mmap4k(X86_ELF_PAGESTART(elf_ppnt->p_vaddr),
(elf_ppnt->p_filesz +
X86_ELF_PAGEOFFSET(elf_ppnt->p_vaddr)),
elf_prot,
(MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE),
bprm->fd,
(elf_ppnt->p_offset -
X86_ELF_PAGEOFFSET(elf_ppnt->p_vaddr)));
if((unsigned long)mapped_addr == 0xffffffffffffffff) {
perror("mmap");
exit(-1);
}
int elf_prot = 0;
int elf_flags = 0;
unsigned long error;
if (elf_ppnt->p_type != PT_LOAD)
continue;
if (elf_ppnt->p_flags & PF_R) elf_prot |= PROT_READ;
if (elf_ppnt->p_flags & PF_W) elf_prot |= PROT_WRITE;
if (elf_ppnt->p_flags & PF_X) elf_prot |= PROT_EXEC;
elf_flags = MAP_PRIVATE | MAP_DENYWRITE;
if (elf_ex.e_type == ET_EXEC || load_addr_set) {
elf_flags |= MAP_FIXED;
} else if (elf_ex.e_type == ET_DYN) {
/* Try and get dynamic programs out of the way of the default mmap
base, as well as whatever program they might try to exec. This
is because the brk will follow the loader, and is not movable. */
/* NOTE: for qemu, we do a big mmap to get enough space
without harcoding any address */
error = target_mmap(0, ET_DYN_MAP_SIZE,
PROT_NONE, MAP_PRIVATE | MAP_ANON,
-1, 0);
if (error == -1) {
perror("mmap");
exit(-1);
}
load_bias = TARGET_ELF_PAGESTART(error - elf_ppnt->p_vaddr);
}
error = target_mmap(TARGET_ELF_PAGESTART(load_bias + elf_ppnt->p_vaddr),
(elf_ppnt->p_filesz +
TARGET_ELF_PAGEOFFSET(elf_ppnt->p_vaddr)),
elf_prot,
(MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE),
bprm->fd,
(elf_ppnt->p_offset -
TARGET_ELF_PAGEOFFSET(elf_ppnt->p_vaddr)));
if (error == -1) {
perror("mmap");
exit(-1);
}
#ifdef LOW_ELF_STACK
if (X86_ELF_PAGESTART(elf_ppnt->p_vaddr) < elf_stack)
elf_stack = X86_ELF_PAGESTART(elf_ppnt->p_vaddr);
if (TARGET_ELF_PAGESTART(elf_ppnt->p_vaddr) < elf_stack)
elf_stack = TARGET_ELF_PAGESTART(elf_ppnt->p_vaddr);
#endif
if (!load_addr_set) {
load_addr = elf_ppnt->p_vaddr - elf_ppnt->p_offset;
load_addr_set = 1;
}
k = elf_ppnt->p_vaddr;
if (k < start_code) start_code = k;
k = elf_ppnt->p_vaddr + elf_ppnt->p_filesz;
if (k > elf_bss) elf_bss = k;
#if 1
if ((elf_ppnt->p_flags & PF_X) && end_code < k)
#else
if ( !(elf_ppnt->p_flags & PF_W) && end_code < k)
#endif
end_code = k;
if (end_data < k) end_data = k;
k = elf_ppnt->p_vaddr + elf_ppnt->p_memsz;
if (k > elf_brk) elf_brk = k;
}
if (!load_addr_set) {
load_addr_set = 1;
load_addr = elf_ppnt->p_vaddr - elf_ppnt->p_offset;
if (elf_ex.e_type == ET_DYN) {
load_bias += error -
TARGET_ELF_PAGESTART(load_bias + elf_ppnt->p_vaddr);
load_addr += load_bias;
}
}
k = elf_ppnt->p_vaddr;
if (k < start_code)
start_code = k;
k = elf_ppnt->p_vaddr + elf_ppnt->p_filesz;
if (k > elf_bss)
elf_bss = k;
if ((elf_ppnt->p_flags & PF_X) && end_code < k)
end_code = k;
if (end_data < k)
end_data = k;
k = elf_ppnt->p_vaddr + elf_ppnt->p_memsz;
if (k > elf_brk) elf_brk = k;
}
elf_entry += load_bias;
elf_bss += load_bias;
elf_brk += load_bias;
start_code += load_bias;
end_code += load_bias;
// start_data += load_bias;
end_data += load_bias;
if (elf_interpreter) {
if (interpreter_type & 1) {
elf_entry = load_aout_interp(&interp_ex, interpreter_fd);
@@ -842,6 +1043,9 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs,
free(elf_phdata);
if (loglevel)
load_symbols(&elf_ex, bprm->fd);
if (interpreter_type != INTERPRETER_AOUT) close(bprm->fd);
info->personality = (ibcs2_interpreter ? PER_SVR4 : PER_LINUX);
@@ -853,7 +1057,7 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs,
bprm->argc,
bprm->envc,
(interpreter_type == INTERPRETER_ELF ? &elf_ex : NULL),
load_addr,
load_addr, load_bias,
interp_load_addr,
(interpreter_type == INTERPRETER_AOUT ? 0 : 1),
info);
@@ -886,8 +1090,8 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs,
and some applications "depend" upon this behavior.
Since we do not have the power to recompile these, we
emulate the SVr4 behavior. Sigh. */
mapped_addr = mmap4k(NULL, ALPHA_PAGE_SIZE, PROT_READ | PROT_EXEC,
MAP_FIXED | MAP_PRIVATE, -1, 0);
mapped_addr = target_mmap(0, host_page_size, PROT_READ | PROT_EXEC,
MAP_FIXED | MAP_PRIVATE, -1, 0);
}
#ifdef ELF_PLAT_INIT
@@ -909,13 +1113,13 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs,
int elf_exec(const char * filename, char ** argv, char ** envp,
struct pt_regs * regs, struct image_info *infop)
struct target_pt_regs * regs, struct image_info *infop)
{
struct linux_binprm bprm;
int retval;
int i;
bprm.p = X86_PAGE_SIZE*MAX_ARG_PAGES-sizeof(unsigned int);
bprm.p = TARGET_PAGE_SIZE*MAX_ARG_PAGES-sizeof(unsigned int);
for (i=0 ; i<MAX_ARG_PAGES ; i++) /* clear page-table */
bprm.page[i] = 0;
retval = open(filename, O_RDONLY);
+17 -1
View File
@@ -1,7 +1,7 @@
/* emulated ioctl list */
IOCTL(TCGETS, IOC_R, MK_PTR(MK_STRUCT(STRUCT_termios)))
IOCTL(TCGETS, IOC_W, MK_PTR(MK_STRUCT(STRUCT_termios)))
IOCTL(TCSETS, IOC_W, MK_PTR(MK_STRUCT(STRUCT_termios)))
IOCTL(TCSETSF, IOC_W, MK_PTR(MK_STRUCT(STRUCT_termios)))
IOCTL(TCSETSW, IOC_W, MK_PTR(MK_STRUCT(STRUCT_termios)))
IOCTL(TIOCGWINSZ, IOC_R, MK_PTR(MK_STRUCT(STRUCT_winsize)))
@@ -37,6 +37,8 @@
IOCTL(TIOCNOTTY, 0, TYPE_NULL)
IOCTL(TIOCGETD, IOC_R, MK_PTR(TYPE_INT))
IOCTL(TIOCSETD, IOC_W, MK_PTR(TYPE_INT))
IOCTL(TIOCGPTN, IOC_R, MK_PTR(TYPE_INT))
IOCTL(TIOCSPTLCK, IOC_W, MK_PTR(TYPE_INT))
IOCTL(FIOCLEX, 0, TYPE_NULL)
IOCTL(FIONCLEX, 0, TYPE_NULL)
IOCTL(FIOASYNC, IOC_W, MK_PTR(TYPE_INT))
@@ -49,6 +51,12 @@
IOCTL(TIOCMIWAIT, 0, TYPE_INT)
IOCTL(TIOCGICOUNT, IOC_R, MK_PTR(MK_STRUCT(STRUCT_serial_icounter_struct)))
IOCTL(KIOCSOUND, 0, TYPE_INT)
IOCTL(KDMKTONE, 0, TYPE_INT)
IOCTL(KDGKBTYPE, IOC_R, MK_PTR(TYPE_CHAR))
IOCTL(KDGKBENT, IOC_RW, MK_PTR(MK_STRUCT(STRUCT_kbentry)))
IOCTL(KDGKBSENT, IOC_RW, TYPE_PTRVOID)
IOCTL(BLKROSET, IOC_W, MK_PTR(TYPE_INT))
IOCTL(BLKROGET, IOC_R, MK_PTR(TYPE_INT))
IOCTL(BLKRRPART, 0, TYPE_NULL)
@@ -66,6 +74,7 @@
IOCTL(FIGETBSZ, IOC_R, MK_PTR(TYPE_LONG))
#endif
IOCTL(SIOCATMARK, 0, TYPE_NULL)
IOCTL(SIOCADDRT, IOC_W, MK_PTR(MK_STRUCT(STRUCT_rtentry)))
IOCTL(SIOCDELRT, IOC_W, MK_PTR(MK_STRUCT(STRUCT_rtentry)))
IOCTL(SIOCGIFNAME, IOC_RW, MK_PTR(TYPE_INT))
@@ -199,8 +208,12 @@
IOCTL(SNDCTL_TMR_METRONOME, IOC_W, MK_PTR(TYPE_INT))
IOCTL(SNDCTL_TMR_SELECT, IOC_W, MK_PTR(TYPE_INT))
IOCTL(SNDCTL_TMR_SOURCE, IOC_RW, MK_PTR(TYPE_INT))
#if 0
/* we invalidate these defines because they have a same number as
termios ioctls */
IOCTL(SNDCTL_TMR_START, 0, TYPE_NULL)
IOCTL(SNDCTL_TMR_STOP, 0, TYPE_NULL)
#endif
IOCTL(SNDCTL_TMR_TEMPO, IOC_RW, MK_PTR(TYPE_INT))
IOCTL(SNDCTL_TMR_TIMEBASE, IOC_RW, MK_PTR(TYPE_INT))
@@ -280,3 +293,6 @@
IOCTL(HDIO_SET_DMA, 0, TYPE_INT)
IOCTL(HDIO_SET_32BIT, 0, TYPE_INT)
IOCTL(HDIO_SET_PIO_MODE, 0, TYPE_INT)
IOCTL(VFAT_IOCTL_READDIR_BOTH, IOC_R, MK_PTR(MK_ARRAY(MK_STRUCT(STRUCT_dirent), 2)))
IOCTL(VFAT_IOCTL_READDIR_SHORT, IOC_R, MK_PTR(MK_ARRAY(MK_STRUCT(STRUCT_dirent), 2)))
+336 -219
View File
@@ -1,5 +1,5 @@
/*
* emu main
* qemu main
*
* Copyright (c) 2003 Fabrice Bellard
*
@@ -20,16 +20,40 @@
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <elf.h>
#include <endian.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include "gemu.h"
#include "qemu.h"
#include "i386/hsw_interp.h"
#include "cpu-i386.h"
unsigned long x86_stack_size;
unsigned long stktop;
#define DEBUG_LOGFILE "/tmp/qemu.log"
FILE *logfile = NULL;
int loglevel;
static const char *interp_prefix = CONFIG_QEMU_PREFIX;
#ifdef __i386__
/* 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";
/* for recent libc, we add these dummies symbol which are not declared
when generating a linked object (bug in ld ?) */
#if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 3)
long __init_array_start[0];
long __init_array_end[0];
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 */
unsigned long x86_stack_size = 512 * 1024;
void gemu_log(const char *fmt, ...)
{
@@ -40,271 +64,364 @@ void gemu_log(const char *fmt, ...)
va_end(ap);
}
/* virtual x86 CPU stuff */
/***********************************************************/
/* CPUX86 core interface */
extern int invoke_code16(Interp_ENV *, int, int);
extern int invoke_code32(Interp_ENV *, int);
extern char *e_print_cpuemu_regs(ENVPARAMS, int is32);
extern char *e_emu_disasm(ENVPARAMS, unsigned char *org, int is32);
extern void init_npu(void);
Interp_ENV env_global;
Interp_ENV *envp_global;
QWORD EMUtime = 0;
int CEmuStat = 0;
long instr_count;
/* who will initialize this? */
unsigned long io_bitmap[IO_BITMAP_SIZE+1];
/* debug flag, 0=disable 1..9=level */
int d_emu = 0;
unsigned long CRs[5] =
void cpu_x86_outb(CPUX86State *env, int addr, int val)
{
0x00000013, /* valid bits: 0xe005003f */
0x00000000, /* invalid */
0x00000000,
0x00000000,
0x00000000
};
/*
* DR0-3 = linear address of breakpoint 0-3
* DR4=5 = reserved
* DR6 b0-b3 = BP active
* b13 = BD
* b14 = BS
* b15 = BT
* DR7 b0-b1 = G:L bp#0
* b2-b3 = G:L bp#1
* b4-b5 = G:L bp#2
* b6-b7 = G:L bp#3
* b8-b9 = GE:LE
* b13 = GD
* b16-19= LLRW bp#0 LL=00(1),01(2),11(4)
* b20-23= LLRW bp#1 RW=00(x),01(w),11(rw)
* b24-27= LLRW bp#2
* b28-31= LLRW bp#3
*/
unsigned long DRs[8] =
{
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0xffff1ff0,
0x00000400,
0xffff1ff0,
0x00000400
};
unsigned long TRs[2] =
{
0x00000000,
0x00000000
};
void FatalAppExit(UINT wAction, LPCSTR lpText)
{
fprintf(stderr, "Fatal error '%s' in CPU\n", lpText);
exit(1);
fprintf(stderr, "outb: port=0x%04x, data=%02x\n", addr, val);
}
int e_debug_check(unsigned char *PC)
void cpu_x86_outw(CPUX86State *env, int addr, int val)
{
register unsigned long d7 = DRs[7];
fprintf(stderr, "outw: port=0x%04x, data=%04x\n", addr, val);
}
if (d7&0x03) {
if (d7&0x30000) return 0; /* only execute(00) bkp */
if ((long)PC==DRs[0]) {
e_printf("DBRK: DR0 hit at %p\n",PC);
DRs[6] |= 1;
return 1;
}
}
if (d7&0x0c) {
if (d7&0x300000) return 0;
if ((long)PC==DRs[1]) {
e_printf("DBRK: DR1 hit at %p\n",PC);
DRs[6] |= 2;
return 1;
}
}
if (d7&0x30) {
if (d7&0x3000000) return 0;
if ((long)PC==DRs[2]) {
e_printf("DBRK: DR2 hit at %p\n",PC);
DRs[6] |= 4;
return 1;
}
}
if (d7&0xc0) {
if (d7&0x30000000) return 0;
if ((long)PC==DRs[3]) {
e_printf("DBRK: DR3 hit at %p\n",PC);
DRs[6] |= 8;
return 1;
}
}
void cpu_x86_outl(CPUX86State *env, int addr, int val)
{
fprintf(stderr, "outl: port=0x%04x, data=%08x\n", addr, val);
}
int cpu_x86_inb(CPUX86State *env, int addr)
{
fprintf(stderr, "inb: port=0x%04x\n", addr);
return 0;
}
/* Debug stuff */
void logstr(unsigned long mask, const char *fmt,...)
int cpu_x86_inw(CPUX86State *env, int addr)
{
va_list ap;
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
fprintf(stderr, "inw: port=0x%04x\n", addr);
return 0;
}
/* unconditional message into debug log and stderr */
#undef error
void error(const char *fmt, ...)
int cpu_x86_inl(CPUX86State *env, int addr)
{
va_list ap;
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
exit(1);
fprintf(stderr, "inl: port=0x%04x\n", addr);
return 0;
}
int PortIO(DWORD port, DWORD value, UINT size, BOOL is_write)
static void write_dt(void *ptr, unsigned long addr, unsigned long limit,
int flags)
{
fprintf(stderr, "IO: %s port=0x%lx value=0x%lx size=%d",
is_write ? "write" : "read", port, value, size);
return value;
unsigned int e1, e2;
e1 = (addr << 16) | (limit & 0xffff);
e2 = ((addr >> 16) & 0xff) | (addr & 0xff000000) | (limit & 0x000f0000);
e2 |= flags;
stl((uint8_t *)ptr, e1);
stl((uint8_t *)ptr + 4, e2);
}
void LogProcName(WORD wSel, WORD wOff, WORD wAction)
static void set_gate(void *ptr, unsigned int type, unsigned int dpl,
unsigned long addr, unsigned int sel)
{
unsigned int e1, e2;
e1 = (addr & 0xffff) | (sel << 16);
e2 = (addr & 0xffff0000) | 0x8000 | (dpl << 13) | (type << 8);
stl((uint8_t *)ptr, e1);
stl((uint8_t *)ptr + 4, e2);
}
void INT_handler(int num, void *env)
uint64_t gdt_table[6];
uint64_t idt_table[256];
/* only dpl matters as we do only user space emulation */
static void set_idt(int n, unsigned int dpl)
{
fprintf(stderr, "EM86: int %d\n", num);
set_gate(idt_table + n, 0, dpl, 0, 0);
}
/***********************************************************/
void cpu_loop(CPUX86State *env)
{
int trapnr;
uint8_t *pc;
target_siginfo_t info;
/* XXX: currently we use LDT entries */
#define __USER_CS (0x23|4)
#define __USER_DS (0x2B|4)
for(;;) {
trapnr = cpu_x86_exec(env);
switch(trapnr) {
case 0x80:
/* linux syscall */
env->regs[R_EAX] = do_syscall(env,
env->regs[R_EAX],
env->regs[R_EBX],
env->regs[R_ECX],
env->regs[R_EDX],
env->regs[R_ESI],
env->regs[R_EDI],
env->regs[R_EBP]);
break;
case EXCP0B_NOSEG:
case EXCP0C_STACK:
info.si_signo = SIGBUS;
info.si_errno = 0;
info.si_code = TARGET_SI_KERNEL;
info._sifields._sigfault._addr = 0;
queue_signal(info.si_signo, &info);
break;
case EXCP0D_GPF:
if (env->eflags & VM_MASK) {
handle_vm86_fault(env);
} else {
info.si_signo = SIGSEGV;
info.si_errno = 0;
info.si_code = TARGET_SI_KERNEL;
info._sifields._sigfault._addr = 0;
queue_signal(info.si_signo, &info);
}
break;
case EXCP0E_PAGE:
info.si_signo = SIGSEGV;
info.si_errno = 0;
if (!(env->error_code & 1))
info.si_code = TARGET_SEGV_MAPERR;
else
info.si_code = TARGET_SEGV_ACCERR;
info._sifields._sigfault._addr = env->cr2;
queue_signal(info.si_signo, &info);
break;
case EXCP00_DIVZ:
if (env->eflags & VM_MASK) {
handle_vm86_trap(env, trapnr);
} else {
/* division by zero */
info.si_signo = SIGFPE;
info.si_errno = 0;
info.si_code = TARGET_FPE_INTDIV;
info._sifields._sigfault._addr = env->eip;
queue_signal(info.si_signo, &info);
}
break;
case EXCP01_SSTP:
case EXCP03_INT3:
if (env->eflags & VM_MASK) {
handle_vm86_trap(env, trapnr);
} else {
info.si_signo = SIGTRAP;
info.si_errno = 0;
if (trapnr == EXCP01_SSTP) {
info.si_code = TARGET_TRAP_BRKPT;
info._sifields._sigfault._addr = env->eip;
} else {
info.si_code = TARGET_SI_KERNEL;
info._sifields._sigfault._addr = 0;
}
queue_signal(info.si_signo, &info);
}
break;
case EXCP04_INTO:
case EXCP05_BOUND:
if (env->eflags & VM_MASK) {
handle_vm86_trap(env, trapnr);
} else {
info.si_signo = SIGSEGV;
info.si_errno = 0;
info.si_code = TARGET_SI_KERNEL;
info._sifields._sigfault._addr = 0;
queue_signal(info.si_signo, &info);
}
break;
case EXCP06_ILLOP:
info.si_signo = SIGILL;
info.si_errno = 0;
info.si_code = TARGET_ILL_ILLOPN;
info._sifields._sigfault._addr = env->eip;
queue_signal(info.si_signo, &info);
break;
case EXCP_INTERRUPT:
/* just indicate that signals should be handled asap */
break;
default:
pc = env->seg_cache[R_CS].base + env->eip;
fprintf(stderr, "qemu: 0x%08lx: unhandled CPU exception 0x%x - aborting\n",
(long)pc, trapnr);
abort();
}
process_pending_signals(env);
}
}
void usage(void)
{
printf("gemu version 0.1, Copyright (c) 2003 Fabrice Bellard\n"
"usage: gemu program [arguments...]\n"
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"
);
exit(1);
"\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"
"\n"
"debug options:\n"
"-d activate log (logfile=%s)\n"
"-p pagesize set the host page size to 'pagesize'\n",
interp_prefix,
x86_stack_size,
DEBUG_LOGFILE);
_exit(1);
}
/* XXX: currently only used for async signals (see signal.c) */
CPUX86State *global_env;
/* used to free thread contexts */
TaskState *first_task_state;
int main(int argc, char **argv)
{
const char *filename;
struct pt_regs regs1, *regs = &regs1;
struct target_pt_regs regs1, *regs = &regs1;
struct image_info info1, *info = &info1;
Interp_ENV *env;
TaskState ts1, *ts = &ts1;
CPUX86State *env;
int optind;
const char *r;
if (argc <= 1)
usage();
filename = argv[1];
loglevel = 0;
optind = 1;
for(;;) {
if (optind >= argc)
break;
r = argv[optind];
if (r[0] != '-')
break;
optind++;
r++;
if (!strcmp(r, "-")) {
break;
} else if (!strcmp(r, "d")) {
loglevel = 1;
} else if (!strcmp(r, "s")) {
r = argv[optind++];
x86_stack_size = strtol(r, (char **)&r, 0);
if (x86_stack_size <= 0)
usage();
if (*r == 'M')
x86_stack_size *= 1024 * 1024;
else if (*r == 'k' || *r == 'K')
x86_stack_size *= 1024;
} else if (!strcmp(r, "L")) {
interp_prefix = argv[optind++];
} else if (!strcmp(r, "p")) {
host_page_size = atoi(argv[optind++]);
if (host_page_size == 0 ||
(host_page_size & (host_page_size - 1)) != 0) {
fprintf(stderr, "page size must be a power of two\n");
exit(1);
}
} else {
usage();
}
}
if (optind >= argc)
usage();
filename = argv[optind];
/* init debug */
if (loglevel) {
logfile = fopen(DEBUG_LOGFILE, "w");
if (!logfile) {
perror(DEBUG_LOGFILE);
_exit(1);
}
setvbuf(logfile, NULL, _IOLBF, 0);
}
/* Zero out regs */
memset(regs, 0, sizeof(struct pt_regs));
memset(regs, 0, sizeof(struct target_pt_regs));
/* Zero out image_info */
memset(info, 0, sizeof(struct image_info));
if(elf_exec(filename, argv+1, __environ, regs, info) != 0) {
/* Scan interp_prefix dir for replacement files. */
init_paths(interp_prefix);
/* NOTE: we need to init the CPU at this stage to get the
host_page_size */
env = cpu_x86_init();
if (elf_exec(filename, argv+optind, environ, regs, info) != 0) {
printf("Error loading %s\n", filename);
exit(1);
_exit(1);
}
#if 0
printf("start_brk 0x%08lx\n" , info->start_brk);
printf("end_code 0x%08lx\n" , info->end_code);
printf("start_code 0x%08lx\n" , info->start_code);
printf("end_data 0x%08lx\n" , info->end_data);
printf("start_stack 0x%08lx\n" , info->start_stack);
printf("brk 0x%08lx\n" , info->brk);
printf("esp 0x%08lx\n" , regs->esp);
printf("eip 0x%08lx\n" , regs->eip);
#endif
if (loglevel) {
page_dump(logfile);
fprintf(logfile, "start_brk 0x%08lx\n" , info->start_brk);
fprintf(logfile, "end_code 0x%08lx\n" , info->end_code);
fprintf(logfile, "start_code 0x%08lx\n" , info->start_code);
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);
}
target_set_brk((char *)info->brk);
syscall_init();
signal_init();
env = &env_global;
envp_global = env;
memset(env, 0, sizeof(Interp_ENV));
global_env = env;
env->rax.e = regs->eax;
env->rbx.e = regs->ebx;
env->rcx.e = regs->ecx;
env->rdx.e = regs->edx;
env->rsi.esi = regs->esi;
env->rdi.edi = regs->edi;
env->rbp.ebp = regs->ebp;
env->rsp.esp = regs->esp;
env->cs.cs = __USER_CS;
env->ds.ds = __USER_DS;
env->es.es = __USER_DS;
env->ss.ss = __USER_DS;
env->fs.fs = __USER_DS;
env->gs.gs = __USER_DS;
env->trans_addr = regs->eip;
/* build Task State */
memset(ts, 0, sizeof(TaskState));
env->opaque = ts;
ts->used = 1;
/* linux register setup */
env->regs[R_EAX] = regs->eax;
env->regs[R_EBX] = regs->ebx;
env->regs[R_ECX] = regs->ecx;
env->regs[R_EDX] = regs->edx;
env->regs[R_ESI] = regs->esi;
env->regs[R_EDI] = regs->edi;
env->regs[R_EBP] = regs->ebp;
env->regs[R_ESP] = regs->esp;
env->eip = regs->eip;
LDT[__USER_CS >> 3].w86Flags = DF_PRESENT | DF_PAGES | DF_32;
LDT[__USER_CS >> 3].dwSelLimit = 0xfffff;
LDT[__USER_CS >> 3].lpSelBase = NULL;
/* linux interrupt setup */
env->idt.base = (void *)idt_table;
env->idt.limit = sizeof(idt_table) - 1;
set_idt(0, 0);
set_idt(1, 0);
set_idt(2, 0);
set_idt(3, 3);
set_idt(4, 3);
set_idt(5, 3);
set_idt(6, 0);
set_idt(7, 0);
set_idt(8, 0);
set_idt(9, 0);
set_idt(10, 0);
set_idt(11, 0);
set_idt(12, 0);
set_idt(13, 0);
set_idt(14, 0);
set_idt(15, 0);
set_idt(16, 0);
set_idt(17, 0);
set_idt(18, 0);
set_idt(19, 0);
set_idt(0x80, 3);
LDT[__USER_DS >> 3].w86Flags = DF_PRESENT | DF_PAGES | DF_32;
LDT[__USER_DS >> 3].dwSelLimit = 0xfffff;
LDT[__USER_DS >> 3].lpSelBase = NULL;
init_npu();
/* linux segment setup */
env->gdt.base = (void *)gdt_table;
env->gdt.limit = sizeof(gdt_table) - 1;
write_dt(&gdt_table[__USER_CS >> 3], 0, 0xfffff,
DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK |
(3 << DESC_DPL_SHIFT) | (0xa << DESC_TYPE_SHIFT));
write_dt(&gdt_table[__USER_DS >> 3], 0, 0xfffff,
DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK |
(3 << DESC_DPL_SHIFT) | (0x2 << DESC_TYPE_SHIFT));
cpu_x86_load_seg(env, R_CS, __USER_CS);
cpu_x86_load_seg(env, R_DS, __USER_DS);
cpu_x86_load_seg(env, R_ES, __USER_DS);
cpu_x86_load_seg(env, R_SS, __USER_DS);
cpu_x86_load_seg(env, R_FS, __USER_DS);
cpu_x86_load_seg(env, R_GS, __USER_DS);
for(;;) {
int err;
uint8_t *pc;
err = invoke_code32(env, -1);
env->trans_addr = env->return_addr;
pc = env->seg_regs[0] + env->trans_addr;
switch(err) {
case EXCP0D_GPF:
if (pc[0] == 0xcd && pc[1] == 0x80) {
/* syscall */
env->trans_addr += 2;
env->rax.e = do_syscall(env->rax.e,
env->rbx.e,
env->rcx.e,
env->rdx.e,
env->rsi.esi,
env->rdi.edi,
env->rbp.ebp);
} else {
goto trap_error;
}
break;
default:
trap_error:
fprintf(stderr, "GEMU: Unknown error %d, aborting\n", err);
d_emu = 9;
fprintf(stderr, "%s\n%s\n",
e_print_cpuemu_regs(env, 1),
e_emu_disasm(env,pc,1));
abort();
}
}
cpu_loop(env);
/* never exits */
return 0;
}
+381
View File
@@ -0,0 +1,381 @@
/*
* mmap support for qemu
*
* Copyright (c) 2003 Fabrice Bellard
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/mman.h>
#include "qemu.h"
//#define DEBUG_MMAP
/* NOTE: all the constants are the HOST ones */
int target_mprotect(unsigned long start, unsigned long len, int prot)
{
unsigned long end, host_start, host_end, addr;
int prot1, ret;
#ifdef DEBUG_MMAP
printf("mprotect: start=0x%lx len=0x%lx prot=%c%c%c\n", start, len,
prot & PROT_READ ? 'r' : '-',
prot & PROT_WRITE ? 'w' : '-',
prot & PROT_EXEC ? 'x' : '-');
#endif
if ((start & ~TARGET_PAGE_MASK) != 0)
return -EINVAL;
len = TARGET_PAGE_ALIGN(len);
end = start + len;
if (end < start)
return -EINVAL;
if (prot & ~(PROT_READ | PROT_WRITE | PROT_EXEC))
return -EINVAL;
if (len == 0)
return 0;
host_start = start & host_page_mask;
host_end = HOST_PAGE_ALIGN(end);
if (start > host_start) {
/* handle host page containing start */
prot1 = prot;
for(addr = host_start; addr < start; addr += TARGET_PAGE_SIZE) {
prot1 |= page_get_flags(addr);
}
if (host_end == host_start + host_page_size) {
for(addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) {
prot1 |= page_get_flags(addr);
}
end = host_end;
}
ret = mprotect((void *)host_start, host_page_size, prot1 & PAGE_BITS);
if (ret != 0)
return ret;
host_start += host_page_size;
}
if (end < host_end) {
prot1 = prot;
for(addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) {
prot1 |= page_get_flags(addr);
}
ret = mprotect((void *)(host_end - host_page_size), host_page_size,
prot1 & PAGE_BITS);
if (ret != 0)
return ret;
host_end -= host_page_size;
}
/* handle the pages in the middle */
if (host_start < host_end) {
ret = mprotect((void *)host_start, host_end - host_start, prot);
if (ret != 0)
return ret;
}
page_set_flags(start, start + len, prot | PAGE_VALID);
return 0;
}
/* map an incomplete host page */
int mmap_frag(unsigned long host_start,
unsigned long start, unsigned long end,
int prot, int flags, int fd, unsigned long offset)
{
unsigned long host_end, ret, addr;
int prot1, prot_new;
host_end = host_start + host_page_size;
/* get the protection of the target pages outside the mapping */
prot1 = 0;
for(addr = host_start; addr < host_end; addr++) {
if (addr < start || addr >= end)
prot1 |= page_get_flags(addr);
}
if (prot1 == 0) {
/* no page was there, so we allocate one */
ret = (long)mmap((void *)host_start, host_page_size, prot,
flags | MAP_ANONYMOUS, -1, 0);
if (ret == -1)
return ret;
}
prot1 &= PAGE_BITS;
prot_new = prot | prot1;
if (!(flags & MAP_ANONYMOUS)) {
/* msync() won't work here, so we return an error if write is
possible while it is a shared mapping */
if ((flags & MAP_TYPE) == MAP_SHARED &&
(prot & PROT_WRITE))
return -EINVAL;
/* adjust protection to be able to read */
if (!(prot1 & PROT_WRITE))
mprotect((void *)host_start, host_page_size, prot1 | PROT_WRITE);
/* read the corresponding file data */
pread(fd, (void *)start, end - start, offset);
/* put final protection */
if (prot_new != (prot1 | PROT_WRITE))
mprotect((void *)host_start, host_page_size, prot_new);
} else {
/* just update the protection */
if (prot_new != prot1) {
mprotect((void *)host_start, host_page_size, prot_new);
}
}
return 0;
}
/* NOTE: all the constants are the HOST ones */
long target_mmap(unsigned long start, unsigned long len, int prot,
int flags, int fd, unsigned long offset)
{
unsigned long ret, end, host_start, host_end, retaddr, host_offset, host_len;
#ifdef DEBUG_MMAP
{
printf("mmap: start=0x%lx len=0x%lx prot=%c%c%c flags=",
start, len,
prot & PROT_READ ? 'r' : '-',
prot & PROT_WRITE ? 'w' : '-',
prot & PROT_EXEC ? 'x' : '-');
if (flags & MAP_FIXED)
printf("MAP_FIXED ");
if (flags & MAP_ANONYMOUS)
printf("MAP_ANON ");
switch(flags & MAP_TYPE) {
case MAP_PRIVATE:
printf("MAP_PRIVATE ");
break;
case MAP_SHARED:
printf("MAP_SHARED ");
break;
default:
printf("[MAP_TYPE=0x%x] ", flags & MAP_TYPE);
break;
}
printf("fd=%d offset=%lx\n", fd, offset);
}
#endif
if (offset & ~TARGET_PAGE_MASK)
return -EINVAL;
len = TARGET_PAGE_ALIGN(len);
if (len == 0)
return start;
host_start = start & host_page_mask;
if (!(flags & MAP_FIXED)) {
if (host_page_size != real_host_page_size) {
/* NOTE: this code is only for debugging with '-p' option */
/* reserve a memory area */
host_len = HOST_PAGE_ALIGN(len) + host_page_size - TARGET_PAGE_SIZE;
host_start = (long)mmap((void *)host_start, host_len, PROT_NONE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (host_start == -1)
return host_start;
host_end = host_start + host_len;
start = HOST_PAGE_ALIGN(host_start);
end = start + HOST_PAGE_ALIGN(len);
if (start > host_start)
munmap((void *)host_start, start - host_start);
if (end < host_end)
munmap((void *)end, host_end - end);
/* use it as a fixed mapping */
flags |= MAP_FIXED;
} else {
/* if not fixed, no need to do anything */
host_offset = offset & host_page_mask;
host_len = len + offset - host_offset;
start = (long)mmap((void *)host_start, host_len,
prot, flags, fd, host_offset);
if (start == -1)
return start;
/* update start so that it points to the file position at 'offset' */
if (!(flags & MAP_ANONYMOUS))
start += offset - host_offset;
goto the_end1;
}
}
if (start & ~TARGET_PAGE_MASK)
return -EINVAL;
end = start + len;
host_end = HOST_PAGE_ALIGN(end);
/* worst case: we cannot map the file because the offset is not
aligned, so we read it */
if (!(flags & MAP_ANONYMOUS) &&
(offset & ~host_page_mask) != (start & ~host_page_mask)) {
/* msync() won't work here, so we return an error if write is
possible while it is a shared mapping */
if ((flags & MAP_TYPE) == MAP_SHARED &&
(prot & PROT_WRITE))
return -EINVAL;
retaddr = target_mmap(start, len, prot | PROT_WRITE,
MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS,
-1, 0);
if (retaddr == -1)
return retaddr;
pread(fd, (void *)start, len, offset);
if (!(prot & PROT_WRITE)) {
ret = target_mprotect(start, len, prot);
if (ret != 0)
return ret;
}
goto the_end;
}
/* handle the start of the mapping */
if (start > host_start) {
if (host_end == host_start + host_page_size) {
/* one single host page */
ret = mmap_frag(host_start, start, end,
prot, flags, fd, offset);
if (ret == -1)
return ret;
goto the_end1;
}
ret = mmap_frag(host_start, start, host_start + host_page_size,
prot, flags, fd, offset);
if (ret == -1)
return ret;
host_start += host_page_size;
}
/* handle the end of the mapping */
if (end < host_end) {
ret = mmap_frag(host_end - host_page_size,
host_end - host_page_size, host_end,
prot, flags, fd,
offset + host_end - host_page_size - start);
if (ret == -1)
return ret;
host_end -= host_page_size;
}
/* map the middle (easier) */
if (host_start < host_end) {
ret = (long)mmap((void *)host_start, host_end - host_start,
prot, flags, fd, offset + host_start - start);
if (ret == -1)
return ret;
}
the_end1:
page_set_flags(start, start + len, prot | PAGE_VALID);
the_end:
#ifdef DEBUG_MMAP
page_dump(stdout);
printf("\n");
#endif
return start;
}
int target_munmap(unsigned long start, unsigned long len)
{
unsigned long end, host_start, host_end, addr;
int prot, ret;
#ifdef DEBUG_MMAP
printf("munmap: start=0x%lx len=0x%lx\n", start, len);
#endif
if (start & ~TARGET_PAGE_MASK)
return -EINVAL;
len = TARGET_PAGE_ALIGN(len);
if (len == 0)
return -EINVAL;
end = start + len;
host_start = start & host_page_mask;
host_end = HOST_PAGE_ALIGN(end);
if (start > host_start) {
/* handle host page containing start */
prot = 0;
for(addr = host_start; addr < start; addr += TARGET_PAGE_SIZE) {
prot |= page_get_flags(addr);
}
if (host_end == host_start + host_page_size) {
for(addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) {
prot |= page_get_flags(addr);
}
end = host_end;
}
if (prot != 0)
host_start += host_page_size;
}
if (end < host_end) {
prot = 0;
for(addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) {
prot |= page_get_flags(addr);
}
if (prot != 0)
host_end -= host_page_size;
}
/* unmap what we can */
if (host_start < host_end) {
ret = munmap((void *)host_start, host_end - host_start);
if (ret != 0)
return ret;
}
page_set_flags(start, start + len, 0);
return 0;
}
/* XXX: currently, we only handle MAP_ANONYMOUS and not MAP_FIXED
blocks which have been allocated starting on a host page */
long target_mremap(unsigned long old_addr, unsigned long old_size,
unsigned long new_size, unsigned long flags,
unsigned long new_addr)
{
int prot;
/* XXX: use 5 args syscall */
new_addr = (long)mremap((void *)old_addr, old_size, new_size, flags);
if (new_addr == -1)
return new_addr;
prot = page_get_flags(old_addr);
page_set_flags(old_addr, old_addr + old_size, 0);
page_set_flags(new_addr, new_addr + new_size, prot | PAGE_VALID);
return new_addr;
}
int target_msync(unsigned long start, unsigned long len, int flags)
{
unsigned long end;
if (start & ~TARGET_PAGE_MASK)
return -EINVAL;
len = TARGET_PAGE_ALIGN(len);
end = start + len;
if (end < start)
return -EINVAL;
if (end == start)
return 0;
start &= host_page_mask;
return msync((void *)start, end - start, flags);
}
+142
View File
@@ -0,0 +1,142 @@
/* Code to mangle pathnames into those matching a given prefix.
eg. open("/lib/foo.so") => open("/usr/gnemul/i386-linux/lib/foo.so");
The assumption is that this area does not change.
*/
#include <sys/types.h>
#include <dirent.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
#include "qemu.h"
struct pathelem
{
/* Name of this, eg. lib */
char *name;
/* Full path name, eg. /usr/gnemul/x86-linux/lib. */
char *pathname;
struct pathelem *parent;
/* Children */
unsigned int num_entries;
struct pathelem *entries[0];
};
static struct pathelem *base;
/* First N chars of S1 match S2, and S2 is N chars long. */
static int strneq(const char *s1, unsigned int n, const char *s2)
{
unsigned int i;
for (i = 0; i < n; i++)
if (s1[i] != s2[i])
return 0;
return s2[i] == 0;
}
static struct pathelem *add_entry(struct pathelem *root, const char *name);
static struct pathelem *new_entry(const char *root,
struct pathelem *parent,
const char *name)
{
struct pathelem *new = malloc(sizeof(*new));
new->name = strdup(name);
asprintf(&new->pathname, "%s/%s", root, name);
new->num_entries = 0;
return new;
}
#define streq(a,b) (strcmp((a), (b)) == 0)
static struct pathelem *add_dir_maybe(struct pathelem *path)
{
DIR *dir;
if ((dir = opendir(path->pathname)) != NULL) {
struct dirent *dirent;
while ((dirent = readdir(dir)) != NULL) {
if (!streq(dirent->d_name,".") && !streq(dirent->d_name,"..")){
path = add_entry(path, dirent->d_name);
}
}
closedir(dir);
}
return path;
}
static struct pathelem *add_entry(struct pathelem *root, const char *name)
{
root->num_entries++;
root = realloc(root, sizeof(*root)
+ sizeof(root->entries[0])*root->num_entries);
root->entries[root->num_entries-1] = new_entry(root->pathname, root, name);
root->entries[root->num_entries-1]
= add_dir_maybe(root->entries[root->num_entries-1]);
return root;
}
/* This needs to be done after tree is stabalized (ie. no more reallocs!). */
static void set_parents(struct pathelem *child, struct pathelem *parent)
{
unsigned int i;
child->parent = parent;
for (i = 0; i < child->num_entries; i++)
set_parents(child->entries[i], child);
}
void init_paths(const char *prefix)
{
if (prefix[0] != '/' ||
prefix[0] == '\0' ||
!strcmp(prefix, "/"))
return;
base = new_entry("", NULL, prefix+1);
base = add_dir_maybe(base);
set_parents(base, base);
}
/* FIXME: Doesn't handle DIR/.. where DIR is not in emulated dir. */
static const char *
follow_path(const struct pathelem *cursor, const char *name)
{
unsigned int i, namelen;
name += strspn(name, "/");
namelen = strcspn(name, "/");
if (namelen == 0)
return cursor->pathname;
if (strneq(name, namelen, ".."))
return follow_path(cursor->parent, name + namelen);
if (strneq(name, namelen, "."))
return follow_path(cursor, name + namelen);
for (i = 0; i < cursor->num_entries; i++)
if (strneq(name, namelen, cursor->entries[i]->name))
return follow_path(cursor->entries[i], name + namelen);
/* Not found */
return NULL;
}
/* Look for path in emulation dir, otherwise return name. */
const char *path(const char *name)
{
/* Only do absolute paths: quick and dirty, but should mostly be OK.
Could do relative by tracking cwd. */
if (!base || name[0] != '/')
return name;
return follow_path(base, name) ?: name;
}
+64 -19
View File
@@ -3,23 +3,13 @@
#include "thunk.h"
struct pt_regs {
long ebx;
long ecx;
long edx;
long esi;
long edi;
long ebp;
long eax;
int xds;
int xes;
long orig_eax;
long eip;
int xcs;
long eflags;
long esp;
int xss;
};
#include <signal.h>
#include "syscall_defs.h"
#ifdef TARGET_I386
#include "cpu-i386.h"
#include "syscall-i386.h"
#endif
/* This struct is used to hold certain information about the image.
* Basically, it replicates in user space what would be certain
@@ -43,15 +33,70 @@ struct image_info {
int personality;
};
/* Information about the current linux thread */
struct vm86_saved_state {
uint32_t eax; /* return code */
uint32_t ebx;
uint32_t ecx;
uint32_t edx;
uint32_t esi;
uint32_t edi;
uint32_t ebp;
uint32_t esp;
uint32_t eflags;
uint32_t eip;
uint16_t cs, ss, ds, es, fs, gs;
};
/* NOTE: we force a big alignment so that the stack stored after is
aligned too */
typedef struct TaskState {
struct TaskState *next;
struct target_vm86plus_struct *target_v86;
struct vm86_saved_state vm86_saved_regs;
struct target_vm86plus_struct vm86plus;
uint32_t v86flags;
uint32_t v86mask;
int used; /* non zero if used */
uint8_t stack[0];
} __attribute__((aligned(16))) TaskState;
extern TaskState *first_task_state;
int elf_exec(const char * filename, char ** argv, char ** envp,
struct pt_regs * regs, struct image_info *infop);
struct target_pt_regs * regs, struct image_info *infop);
void target_set_brk(char *new_brk);
void syscall_init(void);
long do_syscall(int num, long arg1, long arg2, long arg3,
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);
void init_paths(const char *prefix);
const char *path(const char *pathname);
extern int loglevel;
extern FILE *logfile;
/* 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);
/* mmap.c */
int target_mprotect(unsigned long start, unsigned long len, int prot);
long target_mmap(unsigned long start, unsigned long len, int prot,
int flags, int fd, unsigned long offset);
int target_munmap(unsigned long start, unsigned long len);
long target_mremap(unsigned long old_addr, unsigned long old_size,
unsigned long new_size, unsigned long flags,
unsigned long new_addr);
int target_msync(unsigned long start, unsigned long len, int flags);
#endif
+854 -31
View File
@@ -1,5 +1,5 @@
/*
* Emulation of Linux signal handling
* Emulation of Linux signals
*
* Copyright (c) 2003 Fabrice Bellard
*
@@ -19,22 +19,48 @@
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <unistd.h>
#include <signal.h>
#include <errno.h>
#include <sys/ucontext.h>
/* Algorithm strongly inspired from em86 : we queue the signals so
that we can handle them at precise points in the emulated code. */
#ifdef __ia64__
#undef uc_mcontext
#undef uc_sigmask
#undef uc_stack
#undef uc_link
#endif
#include "qemu.h"
//#define DEBUG_SIGNAL
#define MAX_SIGQUEUE_SIZE 1024
struct sigqueue {
struct sigqueue *next;
target_siginfo_t info;
};
struct emulated_sigaction {
struct target_sigaction sa;
int nb_pending;
struct target_siginfo info;
int pending; /* true if signal is pending */
struct sigqueue *first;
struct sigqueue info; /* in order to always have memory for the
first signal, we put it here */
};
struct emulated_sigaction sigact_table[NSIG];
int signal_pending;
static struct emulated_sigaction sigact_table[TARGET_NSIG];
static struct sigqueue sigqueue_table[MAX_SIGQUEUE_SIZE]; /* siginfo queue */
static struct sigqueue *first_free; /* first free siginfo queue entry */
static int signal_pending; /* non zero if a signal may be pending */
static void host_signal_handler(int host_signum, siginfo_t *info,
void *puc);
/* XXX: do it properly */
static inline int host_to_target_signal(int sig)
{
return sig;
@@ -45,61 +71,858 @@ static inline int target_to_host_signal(int sig)
return sig;
}
void host_to_target_sigset(target_sigset_t *d, sigset_t *s)
{
int i;
for(i = 0;i < TARGET_NSIG_WORDS; i++) {
d->sig[i] = tswapl(((unsigned long *)s)[i]);
}
}
void target_to_host_sigset(sigset_t *d, target_sigset_t *s)
{
int i;
for(i = 0;i < TARGET_NSIG_WORDS; i++) {
((unsigned long *)d)[i] = tswapl(s->sig[i]);
}
}
void host_to_target_old_sigset(target_ulong *old_sigset,
const sigset_t *sigset)
{
*old_sigset = tswap32(*(unsigned long *)sigset & 0xffffffff);
}
void target_to_host_old_sigset(sigset_t *sigset,
const target_ulong *old_sigset)
{
sigemptyset(sigset);
*(unsigned long *)sigset = tswapl(*old_sigset);
}
/* siginfo conversion */
static inline void host_to_target_siginfo_noswap(target_siginfo_t *tinfo,
const siginfo_t *info)
{
int sig;
sig = host_to_target_signal(info->si_signo);
tinfo->si_signo = sig;
tinfo->si_errno = 0;
tinfo->si_code = 0;
if (sig == SIGILL || sig == SIGFPE || sig == SIGSEGV ||
sig == SIGBUS || sig == SIGTRAP) {
/* should never come here, but who knows. The information for
the target is irrelevant */
tinfo->_sifields._sigfault._addr = 0;
} else if (sig >= TARGET_SIGRTMIN) {
tinfo->_sifields._rt._pid = info->si_pid;
tinfo->_sifields._rt._uid = info->si_uid;
/* XXX: potential problem if 64 bit */
tinfo->_sifields._rt._sigval.sival_ptr =
(target_ulong)info->si_value.sival_ptr;
}
}
static void tswap_siginfo(target_siginfo_t *tinfo,
const target_siginfo_t *info)
{
int sig;
sig = info->si_signo;
tinfo->si_signo = tswap32(sig);
tinfo->si_errno = tswap32(info->si_errno);
tinfo->si_code = tswap32(info->si_code);
if (sig == SIGILL || sig == SIGFPE || sig == SIGSEGV ||
sig == SIGBUS || sig == SIGTRAP) {
tinfo->_sifields._sigfault._addr =
tswapl(info->_sifields._sigfault._addr);
} else if (sig >= TARGET_SIGRTMIN) {
tinfo->_sifields._rt._pid = tswap32(info->_sifields._rt._pid);
tinfo->_sifields._rt._uid = tswap32(info->_sifields._rt._uid);
tinfo->_sifields._rt._sigval.sival_ptr =
tswapl(info->_sifields._rt._sigval.sival_ptr);
}
}
void host_to_target_siginfo(target_siginfo_t *tinfo, const siginfo_t *info)
{
host_to_target_siginfo_noswap(tinfo, info);
tswap_siginfo(tinfo, tinfo);
}
/* XXX: we support only POSIX RT signals are used. */
/* XXX: find a solution for 64 bit (additionnal malloced data is needed) */
void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo)
{
info->si_signo = tswap32(tinfo->si_signo);
info->si_errno = tswap32(tinfo->si_errno);
info->si_code = tswap32(tinfo->si_code);
info->si_pid = tswap32(tinfo->_sifields._rt._pid);
info->si_uid = tswap32(tinfo->_sifields._rt._uid);
info->si_value.sival_ptr =
(void *)tswapl(tinfo->_sifields._rt._sigval.sival_ptr);
}
void signal_init(void)
{
struct sigaction act;
int i;
/* set all host signal handlers */
sigemptyset(&act.sa_mask);
/* set all host signal handlers. ALL signals are blocked during
the handlers to serialize them. */
sigfillset(&act.sa_mask);
act.sa_flags = SA_SIGINFO;
act.sa_sigaction = host_signal_handler;
for(i = 1; i < NSIG; i++) {
sigaction(i, &sa, NULL);
sigaction(i, &act, NULL);
}
memset(sigact_table, 0, sizeof(sigact_table));
first_free = &sigqueue_table[0];
for(i = 0; i < MAX_SIGQUEUE_SIZE - 1; i++)
sigqueue_table[i].next = &sigqueue_table[i + 1];
sigqueue_table[MAX_SIGQUEUE_SIZE - 1].next = NULL;
}
/* signal queue handling */
static inline struct sigqueue *alloc_sigqueue(void)
{
struct sigqueue *q = first_free;
if (!q)
return NULL;
first_free = q->next;
return q;
}
static inline void free_sigqueue(struct sigqueue *q)
{
q->next = first_free;
first_free = q;
}
/* abort execution with signal */
void __attribute((noreturn)) force_sig(int sig)
{
int host_sig;
host_sig = target_to_host_signal(sig);
fprintf(stderr, "qemu: uncaught target signal %d (%s) - exiting\n",
sig, strsignal(host_sig));
#if 1
_exit(-host_sig);
#else
{
struct sigaction act;
sigemptyset(&act.sa_mask);
act.sa_flags = SA_SIGINFO;
act.sa_sigaction = SIG_DFL;
sigaction(SIGABRT, &act, NULL);
abort();
}
#endif
}
/* queue a signal so that it will be send to the virtual CPU as soon
as possible */
int queue_signal(int sig, target_siginfo_t *info)
{
struct emulated_sigaction *k;
struct sigqueue *q, **pq;
target_ulong handler;
#if defined(DEBUG_SIGNAL)
fprintf(stderr, "queue_signal: sig=%d\n",
sig);
#endif
k = &sigact_table[sig - 1];
handler = k->sa._sa_handler;
if (handler == TARGET_SIG_DFL) {
/* default handler : ignore some signal. The other are fatal */
if (sig != TARGET_SIGCHLD &&
sig != TARGET_SIGURG &&
sig != TARGET_SIGWINCH) {
force_sig(sig);
} else {
return 0; /* indicate ignored */
}
} else if (handler == TARGET_SIG_IGN) {
/* ignore signal */
return 0;
} else if (handler == TARGET_SIG_ERR) {
force_sig(sig);
} else {
pq = &k->first;
if (sig < TARGET_SIGRTMIN) {
/* if non real time signal, we queue exactly one signal */
if (!k->pending)
q = &k->info;
else
return 0;
} else {
if (!k->pending) {
/* first signal */
q = &k->info;
} else {
q = alloc_sigqueue();
if (!q)
return -EAGAIN;
while (*pq != NULL)
pq = &(*pq)->next;
}
}
*pq = q;
q->info = *info;
q->next = NULL;
k->pending = 1;
/* signal that a new signal is pending */
signal_pending = 1;
return 1; /* indicates that the signal was queued */
}
}
#if defined(DEBUG_SIGNAL)
#ifdef __i386__
static void dump_regs(struct ucontext *uc)
{
fprintf(stderr,
"EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n"
"ESI=%08x EDI=%08x EBP=%08x ESP=%08x\n"
"EFL=%08x EIP=%08x\n",
uc->uc_mcontext.gregs[EAX],
uc->uc_mcontext.gregs[EBX],
uc->uc_mcontext.gregs[ECX],
uc->uc_mcontext.gregs[EDX],
uc->uc_mcontext.gregs[ESI],
uc->uc_mcontext.gregs[EDI],
uc->uc_mcontext.gregs[EBP],
uc->uc_mcontext.gregs[ESP],
uc->uc_mcontext.gregs[EFL],
uc->uc_mcontext.gregs[EIP]);
}
#else
static void dump_regs(struct ucontext *uc)
{
}
#endif
#endif
static void host_signal_handler(int host_signum, siginfo_t *info,
void *puc)
{
struct ucontext *uc = puc;
int signum;
int sig;
target_siginfo_t tinfo;
/* 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))
return;
}
/* get target signal number */
signum = host_to_target(host_signum);
if (signum >= TARGET_NSIG)
sig = host_to_target_signal(host_signum);
if (sig < 1 || sig > TARGET_NSIG)
return;
/* we save the old mask */
#if defined(DEBUG_SIGNAL)
fprintf(stderr, "qemu: got signal %d\n", sig);
dump_regs(puc);
#endif
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);
}
}
void process_pending_signals(void)
int do_sigaction(int sig, const struct target_sigaction *act,
struct target_sigaction *oact)
{
int signum;
target_ulong _sa_handler;
struct emulated_sigaction *k;
struct emulated_sigaction *esig;
if (sig < 1 || sig > TARGET_NSIG)
return -EINVAL;
k = &sigact_table[sig - 1];
#if defined(DEBUG_SIGNAL) && 0
fprintf(stderr, "sigaction sig=%d act=0x%08x, oact=0x%08x\n",
sig, (int)act, (int)oact);
#endif
if (oact) {
oact->_sa_handler = tswapl(k->sa._sa_handler);
oact->sa_flags = tswapl(k->sa.sa_flags);
oact->sa_restorer = tswapl(k->sa.sa_restorer);
oact->sa_mask = k->sa.sa_mask;
}
if (act) {
k->sa._sa_handler = tswapl(act->_sa_handler);
k->sa.sa_flags = tswapl(act->sa_flags);
k->sa.sa_restorer = tswapl(act->sa_restorer);
k->sa.sa_mask = act->sa_mask;
}
return 0;
}
#ifdef TARGET_I386
/* from the Linux kernel */
struct target_fpreg {
uint16_t significand[4];
uint16_t exponent;
};
struct target_fpxreg {
uint16_t significand[4];
uint16_t exponent;
uint16_t padding[3];
};
struct target_xmmreg {
target_ulong element[4];
};
struct target_fpstate {
/* Regular FPU environment */
target_ulong cw;
target_ulong sw;
target_ulong tag;
target_ulong ipoff;
target_ulong cssel;
target_ulong dataoff;
target_ulong datasel;
struct target_fpreg _st[8];
uint16_t status;
uint16_t magic; /* 0xffff = regular FPU data only */
/* FXSR FPU environment */
target_ulong _fxsr_env[6]; /* FXSR FPU env is ignored */
target_ulong mxcsr;
target_ulong reserved;
struct target_fpxreg _fxsr_st[8]; /* FXSR FPU reg data is ignored */
struct target_xmmreg _xmm[8];
target_ulong padding[56];
};
#define X86_FXSR_MAGIC 0x0000
struct target_sigcontext {
uint16_t gs, __gsh;
uint16_t fs, __fsh;
uint16_t es, __esh;
uint16_t ds, __dsh;
target_ulong edi;
target_ulong esi;
target_ulong ebp;
target_ulong esp;
target_ulong ebx;
target_ulong edx;
target_ulong ecx;
target_ulong eax;
target_ulong trapno;
target_ulong err;
target_ulong eip;
uint16_t cs, __csh;
target_ulong eflags;
target_ulong esp_at_signal;
uint16_t ss, __ssh;
target_ulong fpstate; /* pointer */
target_ulong oldmask;
target_ulong cr2;
};
typedef struct target_sigaltstack {
target_ulong ss_sp;
int ss_flags;
target_ulong ss_size;
} target_stack_t;
struct target_ucontext {
target_ulong uc_flags;
target_ulong uc_link;
target_stack_t uc_stack;
struct target_sigcontext uc_mcontext;
target_sigset_t uc_sigmask; /* mask last for extensibility */
};
struct sigframe
{
target_ulong pretcode;
int sig;
struct target_sigcontext sc;
struct target_fpstate fpstate;
target_ulong extramask[TARGET_NSIG_WORDS-1];
char retcode[8];
};
struct rt_sigframe
{
target_ulong pretcode;
int sig;
target_ulong pinfo;
target_ulong puc;
struct target_siginfo info;
struct target_ucontext uc;
struct target_fpstate fpstate;
char retcode[8];
};
/*
* Set up a signal frame.
*/
#define __put_user(x,ptr)\
({\
int size = sizeof(*ptr);\
switch(size) {\
case 1:\
stb(ptr, (typeof(*ptr))(x));\
break;\
case 2:\
stw(ptr, (typeof(*ptr))(x));\
break;\
case 4:\
stl(ptr, (typeof(*ptr))(x));\
break;\
case 8:\
stq(ptr, (typeof(*ptr))(x));\
break;\
default:\
abort();\
}\
0;\
})
#define get_user(val, ptr) (typeof(*ptr))(*(ptr))
#define __copy_to_user(dst, src, size)\
({\
memcpy(dst, src, size);\
0;\
})
static inline int copy_siginfo_to_user(target_siginfo_t *tinfo,
const target_siginfo_t *info)
{
tswap_siginfo(tinfo, info);
return 0;
}
/* XXX: save x87 state */
static int
setup_sigcontext(struct target_sigcontext *sc, struct target_fpstate *fpstate,
CPUX86State *env, unsigned long mask)
{
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->regs[R_EDI], &sc->edi);
err |= __put_user(env->regs[R_ESI], &sc->esi);
err |= __put_user(env->regs[R_EBP], &sc->ebp);
err |= __put_user(env->regs[R_ESP], &sc->esp);
err |= __put_user(env->regs[R_EBX], &sc->ebx);
err |= __put_user(env->regs[R_EDX], &sc->edx);
err |= __put_user(env->regs[R_ECX], &sc->ecx);
err |= __put_user(env->regs[R_EAX], &sc->eax);
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->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
/* non-iBCS2 extensions.. */
err |= __put_user(mask, &sc->oldmask);
err |= __put_user(env->cr2, &sc->cr2);
return err;
}
/*
* Determine which stack to use..
*/
static inline void *
get_sigframe(struct emulated_sigaction *ka, CPUX86State *env, size_t frame_size)
{
unsigned long esp;
/* Default to using normal stack */
esp = env->regs[R_ESP];
#if 0
/* This is the X/Open sanctioned signal stack switching. */
if (ka->sa.sa_flags & SA_ONSTACK) {
if (sas_ss_flags(esp) == 0)
esp = current->sas_ss_sp + current->sas_ss_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;
}
#endif
return (void *)((esp - frame_size) & -8ul);
}
static void setup_frame(int sig, struct emulated_sigaction *ka,
target_sigset_t *set, CPUX86State *env)
{
struct sigframe *frame;
int err = 0;
frame = get_sigframe(ka, env, sizeof(*frame));
#if 0
if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
goto give_sigsegv;
#endif
err |= __put_user((/*current->exec_domain
&& current->exec_domain->signal_invmap
&& sig < 32
? current->exec_domain->signal_invmap[sig]
: */ sig),
&frame->sig);
if (err)
goto give_sigsegv;
setup_sigcontext(&frame->sc, &frame->fpstate, env, set->sig[0]);
if (err)
goto give_sigsegv;
if (TARGET_NSIG_WORDS > 1) {
err |= __copy_to_user(frame->extramask, &set->sig[1],
sizeof(frame->extramask));
}
if (err)
goto give_sigsegv;
/* Set up to return from userspace. If provided, use a stub
already in userspace. */
if (ka->sa.sa_flags & TARGET_SA_RESTORER) {
err |= __put_user(ka->sa.sa_restorer, &frame->pretcode);
} else {
err |= __put_user(frame->retcode, &frame->pretcode);
/* This is popl %eax ; movl $,%eax ; int $0x80 */
err |= __put_user(0xb858, (short *)(frame->retcode+0));
err |= __put_user(TARGET_NR_sigreturn, (int *)(frame->retcode+2));
err |= __put_user(0x80cd, (short *)(frame->retcode+6));
}
if (err)
goto give_sigsegv;
/* Set up registers for signal handler */
env->regs[R_ESP] = (unsigned long) frame;
env->eip = (unsigned long) ka->sa._sa_handler;
cpu_x86_load_seg(env, R_DS, __USER_DS);
cpu_x86_load_seg(env, R_ES, __USER_DS);
cpu_x86_load_seg(env, R_SS, __USER_DS);
cpu_x86_load_seg(env, R_CS, __USER_CS);
env->eflags &= ~TF_MASK;
return;
give_sigsegv:
if (sig == TARGET_SIGSEGV)
ka->sa._sa_handler = TARGET_SIG_DFL;
force_sig(TARGET_SIGSEGV /* , current */);
}
static void setup_rt_frame(int sig, struct emulated_sigaction *ka,
target_siginfo_t *info,
target_sigset_t *set, CPUX86State *env)
{
struct rt_sigframe *frame;
int err = 0;
frame = get_sigframe(ka, env, sizeof(*frame));
#if 0
if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
goto give_sigsegv;
#endif
err |= __put_user((/*current->exec_domain
&& current->exec_domain->signal_invmap
&& sig < 32
? current->exec_domain->signal_invmap[sig]
: */sig),
&frame->sig);
err |= __put_user((target_ulong)&frame->info, &frame->pinfo);
err |= __put_user((target_ulong)&frame->uc, &frame->puc);
err |= copy_siginfo_to_user(&frame->info, info);
if (err)
goto give_sigsegv;
/* Create the ucontext. */
err |= __put_user(0, &frame->uc.uc_flags);
err |= __put_user(0, &frame->uc.uc_link);
err |= __put_user(/*current->sas_ss_sp*/ 0, &frame->uc.uc_stack.ss_sp);
err |= __put_user(/* sas_ss_flags(regs->esp) */ 0,
&frame->uc.uc_stack.ss_flags);
err |= __put_user(/* current->sas_ss_size */ 0, &frame->uc.uc_stack.ss_size);
err |= setup_sigcontext(&frame->uc.uc_mcontext, &frame->fpstate,
env, set->sig[0]);
err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
if (err)
goto give_sigsegv;
/* Set up to return from userspace. If provided, use a stub
already in userspace. */
if (ka->sa.sa_flags & TARGET_SA_RESTORER) {
err |= __put_user(ka->sa.sa_restorer, &frame->pretcode);
} else {
err |= __put_user(frame->retcode, &frame->pretcode);
/* This is movl $,%eax ; int $0x80 */
err |= __put_user(0xb8, (char *)(frame->retcode+0));
err |= __put_user(TARGET_NR_rt_sigreturn, (int *)(frame->retcode+1));
err |= __put_user(0x80cd, (short *)(frame->retcode+5));
}
if (err)
goto give_sigsegv;
/* Set up registers for signal handler */
env->regs[R_ESP] = (unsigned long) frame;
env->eip = (unsigned long) ka->sa._sa_handler;
cpu_x86_load_seg(env, R_DS, __USER_DS);
cpu_x86_load_seg(env, R_ES, __USER_DS);
cpu_x86_load_seg(env, R_SS, __USER_DS);
cpu_x86_load_seg(env, R_CS, __USER_CS);
env->eflags &= ~TF_MASK;
return;
give_sigsegv:
if (sig == TARGET_SIGSEGV)
ka->sa._sa_handler = TARGET_SIG_DFL;
force_sig(TARGET_SIGSEGV /* , current */);
}
static int
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));
cpu_x86_load_seg(env, R_DS, lduw(&sc->ds));
env->regs[R_EDI] = ldl(&sc->edi);
env->regs[R_ESI] = ldl(&sc->esi);
env->regs[R_EBP] = ldl(&sc->ebp);
env->regs[R_ESP] = ldl(&sc->esp);
env->regs[R_EBX] = ldl(&sc->ebx);
env->regs[R_EDX] = ldl(&sc->edx);
env->regs[R_ECX] = ldl(&sc->ecx);
env->eip = ldl(&sc->eip);
cpu_x86_load_seg(env, R_CS, lduw(&sc->cs) | 3);
cpu_x86_load_seg(env, R_SS, lduw(&sc->ss) | 3);
{
unsigned int tmpflags;
tmpflags = ldl(&sc->eflags);
env->eflags = (env->eflags & ~0x40DD5) | (tmpflags & 0x40DD5);
// regs->orig_eax = -1; /* disable syscall checks */
}
#if 0
{
struct _fpstate * buf;
err |= __get_user(buf, &sc->fpstate);
if (buf) {
if (verify_area(VERIFY_READ, buf, sizeof(*buf)))
goto badframe;
err |= restore_i387(buf);
}
}
#endif
*peax = ldl(&sc->eax);
return err;
#if 0
badframe:
return 1;
#endif
}
long do_sigreturn(CPUX86State *env)
{
struct sigframe *frame = (struct sigframe *)(env->regs[R_ESP] - 8);
target_sigset_t target_set;
sigset_t set;
int eax, i;
#if defined(DEBUG_SIGNAL)
fprintf(stderr, "do_sigreturn\n");
#endif
/* set blocked signals */
target_set.sig[0] = frame->sc.oldmask;
for(i = 1; i < TARGET_NSIG_WORDS; i++)
target_set.sig[i] = frame->extramask[i - 1];
target_to_host_sigset(&set, &target_set);
sigprocmask(SIG_SETMASK, &set, NULL);
/* restore registers */
if (restore_sigcontext(env, &frame->sc, &eax))
goto badframe;
return eax;
badframe:
force_sig(TARGET_SIGSEGV);
return 0;
}
long do_rt_sigreturn(CPUX86State *env)
{
struct rt_sigframe *frame = (struct rt_sigframe *)(env->regs[R_ESP] - 4);
target_sigset_t target_set;
sigset_t set;
// stack_t st;
int eax;
#if 0
if (verify_area(VERIFY_READ, frame, sizeof(*frame)))
goto badframe;
#endif
memcpy(&target_set, &frame->uc.uc_sigmask, sizeof(target_sigset_t));
target_to_host_sigset(&set, &target_set);
sigprocmask(SIG_SETMASK, &set, NULL);
if (restore_sigcontext(env, &frame->uc.uc_mcontext, &eax))
goto badframe;
#if 0
if (__copy_from_user(&st, &frame->uc.uc_stack, sizeof(st)))
goto badframe;
/* It is more difficult to avoid calling this function than to
call it and ignore errors. */
do_sigaltstack(&st, NULL, regs->esp);
#endif
return eax;
badframe:
force_sig(TARGET_SIGSEGV);
return 0;
}
#endif
void process_pending_signals(void *cpu_env)
{
int sig;
target_ulong handler;
sigset_t set, old_set;
target_sigset_t target_old_set;
struct emulated_sigaction *k;
struct sigqueue *q;
if (!signal_pending)
return;
esig = sigact_table;
for(signum = 1; signum < TARGET_NSIG; signum++) {
if (esig->nb_pending != 0)
k = sigact_table;
for(sig = 1; sig <= TARGET_NSIG; sig++) {
if (k->pending)
goto handle_signal;
esig++;
k++;
}
/* if no signal is pending, just return */
signal_pending = 0;
return;
handle_signal:
_sa_handler = esig->sa._sa_handler;
if (_sa_handler == TARGET_SIG_DFL) {
/* default handling
#ifdef DEBUG_SIGNAL
fprintf(stderr, "qemu: process signal %d\n", sig);
#endif
/* dequeue signal */
q = k->first;
k->first = q->next;
if (!k->first)
k->pending = 0;
handler = k->sa._sa_handler;
if (handler == TARGET_SIG_DFL) {
/* default handler : ignore some signal. The other are fatal */
if (sig != TARGET_SIGCHLD &&
sig != TARGET_SIGURG &&
sig != TARGET_SIGWINCH) {
force_sig(sig);
}
} else if (handler == TARGET_SIG_IGN) {
/* ignore sig */
} else if (handler == TARGET_SIG_ERR) {
force_sig(sig);
} else {
/* compute the blocked signals during the handler execution */
target_to_host_sigset(&set, &k->sa.sa_mask);
/* SA_NODEFER indicates that the current signal should not be
blocked during the handler */
if (!(k->sa.sa_flags & TARGET_SA_NODEFER))
sigaddset(&set, target_to_host_signal(sig));
/* block signals in the handler using Linux */
sigprocmask(SIG_BLOCK, &set, &old_set);
/* save the previous blocked signal state to restore it at the
end of the signal execution (see do_sigreturn) */
host_to_target_sigset(&target_old_set, &old_set);
/* if the CPU is in VM86 mode, we restore the 32 bit values */
#ifdef TARGET_I386
{
CPUX86State *env = cpu_env;
if (env->eflags & VM_MASK)
save_v86_state(env);
}
#endif
/* prepare the stack frame of the virtual CPU */
if (k->sa.sa_flags & TARGET_SA_SIGINFO)
setup_rt_frame(sig, k, &q->info, &target_old_set, cpu_env);
else
setup_frame(sig, k, &target_old_set, cpu_env);
if (k->sa.sa_flags & TARGET_SA_RESETHAND)
k->sa._sa_handler = TARGET_SIG_DFL;
}
if (q != &k->info)
free_sigqueue(q);
}
+1330 -240
View File
File diff suppressed because it is too large Load Diff
+138 -1
View File
@@ -19,16 +19,87 @@
#define SOCKOP_sendmsg 16
#define SOCKOP_recvmsg 17
struct target_sockaddr {
uint16_t sa_family;
uint8_t sa_data[14];
};
struct target_timeval {
target_long tv_sec;
target_long tv_usec;
};
struct target_timespec {
target_long tv_sec;
target_long tv_nsec;
};
struct target_itimerval {
struct target_timeval it_interval;
struct target_timeval it_value;
};
typedef target_long target_clock_t;
struct target_tms {
target_clock_t tms_utime;
target_clock_t tms_stime;
target_clock_t tms_cutime;
target_clock_t tms_cstime;
};
struct target_iovec {
target_long iov_base; /* Starting address */
target_long iov_len; /* Number of bytes */
};
struct target_msghdr {
target_long msg_name; /* Socket name */
int msg_namelen; /* Length of name */
target_long msg_iov; /* Data blocks */
target_long msg_iovlen; /* Number of blocks */
target_long msg_control; /* Per protocol magic (eg BSD file descriptor passing) */
target_long msg_controllen; /* Length of cmsg list */
unsigned int msg_flags;
};
struct target_cmsghdr {
target_long cmsg_len;
int cmsg_level;
int cmsg_type;
};
#define TARGET_CMSG_DATA(cmsg) ((unsigned char *) ((struct target_cmsghdr *) (cmsg) + 1))
#define TARGET_CMSG_NXTHDR(mhdr, cmsg) __target_cmsg_nxthdr (mhdr, cmsg)
#define TARGET_CMSG_FIRSTHDR(mhdr) \
((size_t) tswapl((mhdr)->msg_controllen) >= sizeof (struct target_cmsghdr) \
? (struct target_cmsghdr *) tswapl((mhdr)->msg_control) : (struct target_cmsghdr *) NULL)
#define TARGET_CMSG_ALIGN(len) (((len) + sizeof (target_long) - 1) \
& (size_t) ~(sizeof (target_long) - 1))
#define TARGET_CMSG_SPACE(len) (TARGET_CMSG_ALIGN (len) \
+ TARGET_CMSG_ALIGN (sizeof (struct target_cmsghdr)))
#define TARGET_CMSG_LEN(len) (TARGET_CMSG_ALIGN (sizeof (struct target_cmsghdr)) + (len))
static __inline__ struct target_cmsghdr *
__target_cmsg_nxthdr (struct target_msghdr *__mhdr, struct target_cmsghdr *__cmsg)
{
if (tswapl(__cmsg->cmsg_len) < sizeof (struct target_cmsghdr))
/* The kernel header does this so there may be a reason. */
return 0;
__cmsg = (struct target_cmsghdr *) ((unsigned char *) __cmsg
+ TARGET_CMSG_ALIGN (tswapl(__cmsg->cmsg_len)));
if ((unsigned char *) (__cmsg + 1) > ((unsigned char *) tswapl(__mhdr->msg_control)
+ tswapl(__mhdr->msg_controllen))
|| ((unsigned char *) __cmsg + TARGET_CMSG_ALIGN (tswapl(__cmsg->cmsg_len))
> ((unsigned char *) tswapl(__mhdr->msg_control)
+ tswapl(__mhdr->msg_controllen))))
/* No more entries. */
return 0;
return __cmsg;
}
struct target_rusage {
struct target_timeval ru_utime; /* user time used */
struct target_timeval ru_stime; /* system time used */
@@ -52,7 +123,7 @@ typedef struct {
int val[2];
} kernel_fsid_t;
struct statfs {
struct kernel_statfs {
int f_type;
int f_bsize;
int f_blocks;
@@ -65,6 +136,22 @@ struct statfs {
int f_spare[6];
};
struct target_dirent {
target_long d_ino;
target_long d_off;
unsigned short d_reclen;
char d_name[256]; /* We must not include limits.h! */
};
struct target_dirent64 {
uint64_t d_ino;
int64_t d_off;
unsigned short d_reclen;
unsigned char d_type;
char d_name[256];
};
/* mostly generic signal stuff */
#define TARGET_SIG_DFL ((target_long)0) /* default signal handling */
#define TARGET_SIG_IGN ((target_long)1) /* ignore signal */
@@ -82,6 +169,56 @@ typedef struct {
target_ulong sig[TARGET_NSIG_WORDS];
} target_sigset_t;
#ifdef BSWAP_NEEDED
static inline void tswap_sigset(target_sigset_t *d, const target_sigset_t *s)
{
int i;
for(i = 0;i < TARGET_NSIG_WORDS; i++)
d->sig[i] = tswapl(s->sig[i]);
}
#else
static inline void tswap_sigset(target_sigset_t *d, const target_sigset_t *s)
{
*d = *s;
}
#endif
static inline void target_siginitset(target_sigset_t *d, target_ulong set)
{
int i;
d->sig[0] = set;
for(i = 1;i < TARGET_NSIG_WORDS; i++)
d->sig[i] = 0;
}
void host_to_target_sigset(target_sigset_t *d, sigset_t *s);
void target_to_host_sigset(sigset_t *d, target_sigset_t *s);
void host_to_target_old_sigset(target_ulong *old_sigset,
const sigset_t *sigset);
void target_to_host_old_sigset(sigset_t *sigset,
const target_ulong *old_sigset);
struct target_sigaction;
int do_sigaction(int sig, const struct target_sigaction *act,
struct target_sigaction *oact);
struct target_rlimit {
target_ulong rlim_cur;
target_ulong rlim_max;
};
struct target_pollfd {
int fd; /* file descriptor */
short events; /* requested events */
short revents; /* returned events */
};
/* virtual terminal ioctls */
#define TARGET_KIOCSOUND 0x4B2F /* start sound generation (0 for off) */
#define TARGET_KDMKTONE 0x4B30 /* generate tone */
#define TARGET_KDGKBTYPE 0x4b33
#define TARGET_KDGKBENT 0x4B46 /* gets one entry in translation table */
#define TARGET_KDGKBSENT 0x4B48 /* gets one function key string entry */
/* Networking ioctls */
#define TARGET_SIOCADDRT 0x890B /* add routing table entry */
#define TARGET_SIOCDELRT 0x890C /* delete routing table entry */
+5
View File
@@ -62,3 +62,8 @@ STRUCT(cdrom_read_audio,
STRUCT(hd_geometry,
TYPE_CHAR, TYPE_CHAR, TYPE_SHORT, TYPE_ULONG)
STRUCT(dirent,
TYPE_LONG, TYPE_LONG, TYPE_SHORT, MK_ARRAY(TYPE_CHAR, 256))
STRUCT(kbentry,
TYPE_CHAR, TYPE_CHAR, TYPE_SHORT)
+475
View File
@@ -0,0 +1,475 @@
/*
* vm86 linux syscall support
*
* Copyright (c) 2003 Fabrice Bellard
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include "qemu.h"
//#define DEBUG_VM86
#define set_flags(X,new,mask) \
((X) = ((X) & ~(mask)) | ((new) & (mask)))
#define SAFE_MASK (0xDD5)
#define RETURN_MASK (0xDFF)
static inline int is_revectored(int nr, struct target_revectored_struct *bitmap)
{
return (((uint8_t *)bitmap)[nr >> 3] >> (nr & 7)) & 1;
}
static inline void vm_putw(uint8_t *segptr, unsigned int reg16, unsigned int val)
{
*(uint16_t *)(segptr + (reg16 & 0xffff)) = tswap16(val);
}
static inline void vm_putl(uint8_t *segptr, unsigned int reg16, unsigned int val)
{
*(uint32_t *)(segptr + (reg16 & 0xffff)) = tswap32(val);
}
static inline unsigned int vm_getw(uint8_t *segptr, unsigned int reg16)
{
return tswap16(*(uint16_t *)(segptr + (reg16 & 0xffff)));
}
static inline unsigned int vm_getl(uint8_t *segptr, unsigned int reg16)
{
return tswap32(*(uint32_t *)(segptr + (reg16 & 0xffff)));
}
void save_v86_state(CPUX86State *env)
{
TaskState *ts = env->opaque;
/* put the VM86 registers in the userspace register structure */
ts->target_v86->regs.eax = tswap32(env->regs[R_EAX]);
ts->target_v86->regs.ebx = tswap32(env->regs[R_EBX]);
ts->target_v86->regs.ecx = tswap32(env->regs[R_ECX]);
ts->target_v86->regs.edx = tswap32(env->regs[R_EDX]);
ts->target_v86->regs.esi = tswap32(env->regs[R_ESI]);
ts->target_v86->regs.edi = tswap32(env->regs[R_EDI]);
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]);
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);
#endif
/* restore 32 bit registers */
env->regs[R_EAX] = ts->vm86_saved_regs.eax;
env->regs[R_EBX] = ts->vm86_saved_regs.ebx;
env->regs[R_ECX] = ts->vm86_saved_regs.ecx;
env->regs[R_EDX] = ts->vm86_saved_regs.edx;
env->regs[R_ESI] = ts->vm86_saved_regs.esi;
env->regs[R_EDI] = ts->vm86_saved_regs.edi;
env->regs[R_EBP] = ts->vm86_saved_regs.ebp;
env->regs[R_ESP] = ts->vm86_saved_regs.esp;
env->eflags = ts->vm86_saved_regs.eflags;
env->eip = ts->vm86_saved_regs.eip;
cpu_x86_load_seg(env, R_CS, ts->vm86_saved_regs.cs);
cpu_x86_load_seg(env, R_SS, ts->vm86_saved_regs.ss);
cpu_x86_load_seg(env, R_DS, ts->vm86_saved_regs.ds);
cpu_x86_load_seg(env, R_ES, ts->vm86_saved_regs.es);
cpu_x86_load_seg(env, R_FS, ts->vm86_saved_regs.fs);
cpu_x86_load_seg(env, R_GS, ts->vm86_saved_regs.gs);
}
/* return from vm86 mode to 32 bit. The vm86() syscall will return
'retval' */
static inline void return_to_32bit(CPUX86State *env, int retval)
{
#ifdef DEBUG_VM86
fprintf(logfile, "return_to_32bit: ret=0x%x\n", retval);
#endif
save_v86_state(env);
env->regs[R_EAX] = retval;
}
static inline int set_IF(CPUX86State *env)
{
TaskState *ts = env->opaque;
ts->v86flags |= VIF_MASK;
if (ts->v86flags & VIP_MASK) {
return_to_32bit(env, TARGET_VM86_STI);
return 1;
}
return 0;
}
static inline void clear_IF(CPUX86State *env)
{
TaskState *ts = env->opaque;
ts->v86flags &= ~VIF_MASK;
}
static inline void clear_TF(CPUX86State *env)
{
env->eflags &= ~TF_MASK;
}
static inline void clear_AC(CPUX86State *env)
{
env->eflags &= ~AC_MASK;
}
static inline int set_vflags_long(unsigned long eflags, CPUX86State *env)
{
TaskState *ts = env->opaque;
set_flags(ts->v86flags, eflags, ts->v86mask);
set_flags(env->eflags, eflags, SAFE_MASK);
if (eflags & IF_MASK)
return set_IF(env);
else
clear_IF(env);
return 0;
}
static inline int set_vflags_short(unsigned short flags, CPUX86State *env)
{
TaskState *ts = env->opaque;
set_flags(ts->v86flags, flags, ts->v86mask & 0xffff);
set_flags(env->eflags, flags, SAFE_MASK);
if (flags & IF_MASK)
return set_IF(env);
else
clear_IF(env);
return 0;
}
static inline unsigned int get_vflags(CPUX86State *env)
{
TaskState *ts = env->opaque;
unsigned int flags;
flags = env->eflags & RETURN_MASK;
if (ts->v86flags & VIF_MASK)
flags |= IF_MASK;
return flags | (ts->v86flags & ts->v86mask);
}
#define ADD16(reg, val) reg = (reg & ~0xffff) | ((reg + (val)) & 0xffff)
/* handle VM86 interrupt (NOTE: the CPU core currently does not
support TSS interrupt revectoring, so this code is always executed) */
static void do_int(CPUX86State *env, int intno)
{
TaskState *ts = env->opaque;
uint32_t *int_ptr, segoffs;
uint8_t *ssp;
unsigned int sp;
if (env->segs[R_CS] == TARGET_BIOSSEG)
goto cannot_handle;
if (is_revectored(intno, &ts->vm86plus.int_revectored))
goto cannot_handle;
if (intno == 0x21 && is_revectored((env->regs[R_EAX] >> 8) & 0xff,
&ts->vm86plus.int21_revectored))
goto cannot_handle;
int_ptr = (uint32_t *)(intno << 2);
segoffs = tswap32(*int_ptr);
if ((segoffs >> 16) == TARGET_BIOSSEG)
goto cannot_handle;
#if defined(DEBUG_VM86)
fprintf(logfile, "VM86: emulating int 0x%x. CS:IP=%04x:%04x\n",
intno, segoffs >> 16, segoffs & 0xffff);
#endif
/* save old state */
ssp = (uint8_t *)(env->segs[R_SS] << 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 - 6, env->eip);
ADD16(env->regs[R_ESP], -6);
/* goto interrupt handler */
env->eip = segoffs & 0xffff;
cpu_x86_load_seg(env, R_CS, segoffs >> 16);
clear_TF(env);
clear_IF(env);
clear_AC(env);
return;
cannot_handle:
#if defined(DEBUG_VM86)
fprintf(logfile, "VM86: return to 32 bits int 0x%x\n", intno);
#endif
return_to_32bit(env, TARGET_VM86_INTx | (intno << 8));
}
void handle_vm86_trap(CPUX86State *env, int trapno)
{
if (trapno == 1 || trapno == 3) {
return_to_32bit(env, TARGET_VM86_TRAP + (trapno << 8));
} else {
do_int(env, trapno);
}
}
#define CHECK_IF_IN_TRAP() \
if ((ts->vm86plus.vm86plus.flags & TARGET_vm86dbg_active) && \
(ts->vm86plus.vm86plus.flags & TARGET_vm86dbg_TFpendig)) \
newflags |= TF_MASK
#define VM86_FAULT_RETURN \
if ((ts->vm86plus.vm86plus.flags & TARGET_force_return_for_pic) && \
(ts->v86flags & (IF_MASK | VIF_MASK))) \
return_to_32bit(env, TARGET_VM86_PICRETURN); \
return
void handle_vm86_fault(CPUX86State *env)
{
TaskState *ts = env->opaque;
uint8_t *csp, *pc, *ssp;
unsigned int ip, sp, newflags, newip, newcs, opcode, intno;
int data32, pref_done;
csp = (uint8_t *)(env->segs[R_CS] << 4);
ip = env->eip & 0xffff;
pc = csp + ip;
ssp = (uint8_t *)(env->segs[R_SS] << 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]);
#endif
data32 = 0;
pref_done = 0;
do {
opcode = csp[ip];
ADD16(ip, 1);
switch (opcode) {
case 0x66: /* 32-bit data */ data32=1; break;
case 0x67: /* 32-bit address */ break;
case 0x2e: /* CS */ break;
case 0x3e: /* DS */ break;
case 0x26: /* ES */ break;
case 0x36: /* SS */ break;
case 0x65: /* GS */ break;
case 0x64: /* FS */ break;
case 0xf2: /* repnz */ break;
case 0xf3: /* rep */ break;
default: pref_done = 1;
}
} while (!pref_done);
/* VM86 mode */
switch(opcode) {
case 0x9c: /* pushf */
if (data32) {
vm_putl(ssp, sp - 4, get_vflags(env));
ADD16(env->regs[R_ESP], -4);
} else {
vm_putw(ssp, sp - 2, get_vflags(env));
ADD16(env->regs[R_ESP], -2);
}
env->eip = ip;
VM86_FAULT_RETURN;
case 0x9d: /* popf */
if (data32) {
newflags = vm_getl(ssp, sp);
ADD16(env->regs[R_ESP], 4);
} else {
newflags = vm_getw(ssp, sp);
ADD16(env->regs[R_ESP], 2);
}
env->eip = ip;
CHECK_IF_IN_TRAP();
if (data32) {
if (set_vflags_long(newflags, env))
return;
} else {
if (set_vflags_short(newflags, env))
return;
}
VM86_FAULT_RETURN;
case 0xcd: /* int */
intno = csp[ip];
ADD16(ip, 1);
env->eip = ip;
if (ts->vm86plus.vm86plus.flags & TARGET_vm86dbg_active) {
if ( (ts->vm86plus.vm86plus.vm86dbg_intxxtab[intno >> 3] >>
(intno &7)) & 1) {
return_to_32bit(env, TARGET_VM86_INTx + (intno << 8));
return;
}
}
do_int(env, intno);
break;
case 0xcf: /* iret */
if (data32) {
newip = vm_getl(ssp, sp) & 0xffff;
newcs = vm_getl(ssp, sp + 4) & 0xffff;
newflags = vm_getl(ssp, sp + 8);
ADD16(env->regs[R_ESP], 12);
} else {
newip = vm_getw(ssp, sp);
newcs = vm_getw(ssp, sp + 2);
newflags = vm_getw(ssp, sp + 4);
ADD16(env->regs[R_ESP], 6);
}
env->eip = newip;
cpu_x86_load_seg(env, R_CS, newcs);
CHECK_IF_IN_TRAP();
if (data32) {
if (set_vflags_long(newflags, env))
return;
} else {
if (set_vflags_short(newflags, env))
return;
}
VM86_FAULT_RETURN;
case 0xfa: /* cli */
env->eip = ip;
clear_IF(env);
VM86_FAULT_RETURN;
case 0xfb: /* sti */
env->eip = ip;
if (set_IF(env))
return;
VM86_FAULT_RETURN;
default:
/* real VM86 GPF exception */
return_to_32bit(env, TARGET_VM86_UNKNOWN);
break;
}
}
int do_vm86(CPUX86State *env, long subfunction,
struct target_vm86plus_struct * target_v86)
{
TaskState *ts = env->opaque;
int ret;
switch (subfunction) {
case TARGET_VM86_REQUEST_IRQ:
case TARGET_VM86_FREE_IRQ:
case TARGET_VM86_GET_IRQ_BITS:
case TARGET_VM86_GET_AND_RESET_IRQ:
gemu_log("qemu: unsupported vm86 subfunction (%ld)\n", subfunction);
ret = -EINVAL;
goto out;
case TARGET_VM86_PLUS_INSTALL_CHECK:
/* NOTE: on old vm86 stuff this will return the error
from verify_area(), because the subfunction is
interpreted as (invalid) address to vm86_struct.
So the installation check works.
*/
ret = 0;
goto out;
}
ts->target_v86 = target_v86;
/* save current CPU regs */
ts->vm86_saved_regs.eax = 0; /* default vm86 syscall return code */
ts->vm86_saved_regs.ebx = env->regs[R_EBX];
ts->vm86_saved_regs.ecx = env->regs[R_ECX];
ts->vm86_saved_regs.edx = env->regs[R_EDX];
ts->vm86_saved_regs.esi = env->regs[R_ESI];
ts->vm86_saved_regs.edi = env->regs[R_EDI];
ts->vm86_saved_regs.ebp = env->regs[R_EBP];
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];
/* build vm86 CPU state */
ts->v86flags = tswap32(target_v86->regs.eflags);
env->eflags = (env->eflags & ~SAFE_MASK) |
(tswap32(target_v86->regs.eflags) & SAFE_MASK) | VM_MASK;
ts->vm86plus.cpu_type = tswapl(target_v86->cpu_type);
switch (ts->vm86plus.cpu_type) {
case TARGET_CPU_286:
ts->v86mask = 0;
break;
case TARGET_CPU_386:
ts->v86mask = NT_MASK | IOPL_MASK;
break;
case TARGET_CPU_486:
ts->v86mask = AC_MASK | NT_MASK | IOPL_MASK;
break;
default:
ts->v86mask = ID_MASK | AC_MASK | NT_MASK | IOPL_MASK;
break;
}
env->regs[R_EBX] = tswap32(target_v86->regs.ebx);
env->regs[R_ECX] = tswap32(target_v86->regs.ecx);
env->regs[R_EDX] = tswap32(target_v86->regs.edx);
env->regs[R_ESI] = tswap32(target_v86->regs.esi);
env->regs[R_EDI] = tswap32(target_v86->regs.edi);
env->regs[R_EBP] = tswap32(target_v86->regs.ebp);
env->regs[R_ESP] = tswap32(target_v86->regs.esp);
env->eip = tswap32(target_v86->regs.eip);
cpu_x86_load_seg(env, R_CS, tswap16(target_v86->regs.cs));
cpu_x86_load_seg(env, R_SS, tswap16(target_v86->regs.ss));
cpu_x86_load_seg(env, R_DS, tswap16(target_v86->regs.ds));
cpu_x86_load_seg(env, R_ES, tswap16(target_v86->regs.es));
cpu_x86_load_seg(env, R_FS, tswap16(target_v86->regs.fs));
cpu_x86_load_seg(env, R_GS, tswap16(target_v86->regs.gs));
ret = tswap32(target_v86->regs.eax); /* eax will be restored at
the end of the syscall */
memcpy(&ts->vm86plus.int_revectored,
&target_v86->int_revectored, 32);
memcpy(&ts->vm86plus.int21_revectored,
&target_v86->int21_revectored, 32);
ts->vm86plus.vm86plus.flags = tswapl(target_v86->vm86plus.flags);
memcpy(&ts->vm86plus.vm86plus.vm86dbg_intxxtab,
target_v86->vm86plus.vm86dbg_intxxtab, 32);
#ifdef DEBUG_VM86
fprintf(logfile, "do_vm86: cs:ip=%04x:%04x\n", env->segs[R_CS], env->eip);
#endif
/* now the virtual CPU is ready for vm86 execution ! */
out:
return ret;
}
+2762
View File
File diff suppressed because it is too large Load Diff
+245
View File
@@ -0,0 +1,245 @@
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);
INC_SI();
INC_DI();
}
void OPPROTO glue(glue(op_rep_movs, SUFFIX), STRING_SUFFIX)(void)
{
int v, inc;
inc = (DF << SHIFT);
while (CX != 0) {
v = glue(ldu, SUFFIX)(SI_ADDR);
glue(st, SUFFIX)(DI_ADDR, v);
INC_SI();
INC_DI();
DEC_CX();
}
FORCE_RET();
}
void OPPROTO glue(glue(op_stos, SUFFIX), STRING_SUFFIX)(void)
{
int inc;
glue(st, SUFFIX)(DI_ADDR, EAX);
inc = (DF << SHIFT);
INC_DI();
}
void OPPROTO glue(glue(op_rep_stos, SUFFIX), STRING_SUFFIX)(void)
{
int inc;
inc = (DF << SHIFT);
while (CX != 0) {
glue(st, SUFFIX)(DI_ADDR, EAX);
INC_DI();
DEC_CX();
}
FORCE_RET();
}
void OPPROTO glue(glue(op_lods, SUFFIX), STRING_SUFFIX)(void)
{
int v, inc;
v = glue(ldu, SUFFIX)(SI_ADDR);
#if SHIFT == 0
EAX = (EAX & ~0xff) | v;
#elif SHIFT == 1
EAX = (EAX & ~0xffff) | v;
#else
EAX = v;
#endif
inc = (DF << SHIFT);
INC_SI();
}
/* don't know if it is used */
void OPPROTO glue(glue(op_rep_lods, SUFFIX), STRING_SUFFIX)(void)
{
int v, inc;
inc = (DF << SHIFT);
while (CX != 0) {
v = glue(ldu, SUFFIX)(SI_ADDR);
#if SHIFT == 0
EAX = (EAX & ~0xff) | v;
#elif SHIFT == 1
EAX = (EAX & ~0xffff) | v;
#else
EAX = v;
#endif
INC_SI();
DEC_CX();
}
FORCE_RET();
}
void OPPROTO glue(glue(op_scas, SUFFIX), STRING_SUFFIX)(void)
{
int v, inc;
v = glue(ldu, SUFFIX)(DI_ADDR);
inc = (DF << SHIFT);
INC_DI();
CC_SRC = EAX;
CC_DST = EAX - v;
}
void OPPROTO glue(glue(op_repz_scas, SUFFIX), STRING_SUFFIX)(void)
{
int v1, v2, inc;
if (CX != 0) {
/* NOTE: the flags are not modified if CX == 0 */
v1 = EAX & DATA_MASK;
inc = (DF << SHIFT);
do {
v2 = glue(ldu, SUFFIX)(DI_ADDR);
INC_DI();
DEC_CX();
if (v1 != v2)
break;
} while (CX != 0);
CC_SRC = v1;
CC_DST = v1 - v2;
CC_OP = CC_OP_SUBB + SHIFT;
}
FORCE_RET();
}
void OPPROTO glue(glue(op_repnz_scas, SUFFIX), STRING_SUFFIX)(void)
{
int v1, v2, inc;
if (CX != 0) {
/* NOTE: the flags are not modified if CX == 0 */
v1 = EAX & DATA_MASK;
inc = (DF << SHIFT);
do {
v2 = glue(ldu, SUFFIX)(DI_ADDR);
INC_DI();
DEC_CX();
if (v1 == v2)
break;
} while (CX != 0);
CC_SRC = v1;
CC_DST = v1 - v2;
CC_OP = CC_OP_SUBB + SHIFT;
}
FORCE_RET();
}
void OPPROTO glue(glue(op_cmps, SUFFIX), STRING_SUFFIX)(void)
{
int v1, v2, inc;
v1 = glue(ldu, SUFFIX)(SI_ADDR);
v2 = glue(ldu, SUFFIX)(DI_ADDR);
inc = (DF << SHIFT);
INC_SI();
INC_DI();
CC_SRC = v1;
CC_DST = v1 - v2;
}
void OPPROTO glue(glue(op_repz_cmps, SUFFIX), STRING_SUFFIX)(void)
{
int v1, v2, inc;
if (CX != 0) {
inc = (DF << SHIFT);
do {
v1 = glue(ldu, SUFFIX)(SI_ADDR);
v2 = glue(ldu, SUFFIX)(DI_ADDR);
INC_SI();
INC_DI();
DEC_CX();
if (v1 != v2)
break;
} while (CX != 0);
CC_SRC = v1;
CC_DST = v1 - v2;
CC_OP = CC_OP_SUBB + SHIFT;
}
FORCE_RET();
}
void OPPROTO glue(glue(op_repnz_cmps, SUFFIX), STRING_SUFFIX)(void)
{
int v1, v2, inc;
if (CX != 0) {
inc = (DF << SHIFT);
do {
v1 = glue(ldu, SUFFIX)(SI_ADDR);
v2 = glue(ldu, SUFFIX)(DI_ADDR);
INC_SI();
INC_DI();
DEC_CX();
if (v1 == v2)
break;
} while (CX != 0);
CC_SRC = v1;
CC_DST = v1 - v2;
CC_OP = CC_OP_SUBB + SHIFT;
}
FORCE_RET();
}
void OPPROTO glue(glue(op_outs, SUFFIX), STRING_SUFFIX)(void)
{
int v, dx, inc;
dx = EDX & 0xffff;
v = glue(ldu, SUFFIX)(SI_ADDR);
glue(cpu_x86_out, SUFFIX)(env, dx, v);
inc = (DF << SHIFT);
INC_SI();
}
void OPPROTO glue(glue(op_rep_outs, SUFFIX), STRING_SUFFIX)(void)
{
int v, dx, inc;
inc = (DF << SHIFT);
dx = EDX & 0xffff;
while (CX != 0) {
v = glue(ldu, SUFFIX)(SI_ADDR);
glue(cpu_x86_out, SUFFIX)(env, dx, v);
INC_SI();
DEC_CX();
}
FORCE_RET();
}
void OPPROTO glue(glue(op_ins, SUFFIX), STRING_SUFFIX)(void)
{
int v, dx, inc;
dx = EDX & 0xffff;
v = glue(cpu_x86_in, SUFFIX)(env, dx);
glue(st, SUFFIX)(DI_ADDR, v);
inc = (DF << SHIFT);
INC_DI();
}
void OPPROTO glue(glue(op_rep_ins, SUFFIX), STRING_SUFFIX)(void)
{
int v, dx, inc;
inc = (DF << SHIFT);
dx = EDX & 0xffff;
while (CX != 0) {
v = glue(cpu_x86_in, SUFFIX)(env, dx);
glue(st, SUFFIX)(DI_ADDR, v);
INC_DI();
DEC_CX();
}
FORCE_RET();
}
#undef STRING_SUFFIX
#undef SI_ADDR
#undef DI_ADDR
#undef INC_SI
#undef INC_DI
#undef CX
#undef DEC_CX
+134
View File
@@ -0,0 +1,134 @@
/*
* i386 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_A0,REGNAME)(void)
{
A0 = REG;
}
void OPPROTO glue(op_addl_A0,REGNAME)(void)
{
A0 += REG;
}
void OPPROTO glue(glue(op_addl_A0,REGNAME),_s1)(void)
{
A0 += REG << 1;
}
void OPPROTO glue(glue(op_addl_A0,REGNAME),_s2)(void)
{
A0 += REG << 2;
}
void OPPROTO glue(glue(op_addl_A0,REGNAME),_s3)(void)
{
A0 += REG << 3;
}
void OPPROTO glue(op_movl_T0,REGNAME)(void)
{
T0 = REG;
}
void OPPROTO glue(op_movl_T1,REGNAME)(void)
{
T1 = REG;
}
void OPPROTO glue(op_movh_T0,REGNAME)(void)
{
T0 = REG >> 8;
}
void OPPROTO glue(op_movh_T1,REGNAME)(void)
{
T1 = REG >> 8;
}
void OPPROTO glue(glue(op_movl,REGNAME),_T0)(void)
{
REG = T0;
}
void OPPROTO glue(glue(op_movl,REGNAME),_T1)(void)
{
REG = T1;
}
void OPPROTO glue(glue(op_movl,REGNAME),_A0)(void)
{
REG = A0;
}
/* mov T1 to REG if T0 is true */
void OPPROTO glue(glue(op_cmovw,REGNAME),_T1_T0)(void)
{
if (T0)
REG = (REG & 0xffff0000) | (T1 & 0xffff);
}
void OPPROTO glue(glue(op_cmovl,REGNAME),_T1_T0)(void)
{
if (T0)
REG = T1;
}
/* NOTE: T0 high order bits are ignored */
void OPPROTO glue(glue(op_movw,REGNAME),_T0)(void)
{
REG = (REG & 0xffff0000) | (T0 & 0xffff);
}
/* NOTE: T0 high order bits are ignored */
void OPPROTO glue(glue(op_movw,REGNAME),_T1)(void)
{
REG = (REG & 0xffff0000) | (T1 & 0xffff);
}
/* NOTE: A0 high order bits are ignored */
void OPPROTO glue(glue(op_movw,REGNAME),_A0)(void)
{
REG = (REG & 0xffff0000) | (A0 & 0xffff);
}
/* NOTE: T0 high order bits are ignored */
void OPPROTO glue(glue(op_movb,REGNAME),_T0)(void)
{
REG = (REG & 0xffffff00) | (T0 & 0xff);
}
/* NOTE: T0 high order bits are ignored */
void OPPROTO glue(glue(op_movh,REGNAME),_T0)(void)
{
REG = (REG & 0xffff00ff) | ((T0 & 0xff) << 8);
}
/* NOTE: T1 high order bits are ignored */
void OPPROTO glue(glue(op_movb,REGNAME),_T1)(void)
{
REG = (REG & 0xffffff00) | (T1 & 0xff);
}
/* NOTE: T1 high order bits are ignored */
void OPPROTO glue(glue(op_movh,REGNAME),_T1)(void)
{
REG = (REG & 0xffff00ff) | ((T1 & 0xff) << 8);
}
+865
View File
@@ -0,0 +1,865 @@
/*
* 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
*/
#define DATA_BITS (1 << (3 + SHIFT))
#define SHIFT_MASK (DATA_BITS - 1)
#define SIGN_MASK (1 << (DATA_BITS - 1))
#if DATA_BITS == 8
#define SUFFIX b
#define DATA_TYPE uint8_t
#define DATA_STYPE int8_t
#define DATA_MASK 0xff
#elif DATA_BITS == 16
#define SUFFIX w
#define DATA_TYPE uint16_t
#define DATA_STYPE int16_t
#define DATA_MASK 0xffff
#elif DATA_BITS == 32
#define SUFFIX l
#define DATA_TYPE uint32_t
#define DATA_STYPE int32_t
#define DATA_MASK 0xffffffff
#else
#error unhandled operand size
#endif
/* dynamic flags computation */
static int glue(compute_all_add, SUFFIX)(void)
{
int cf, pf, af, zf, sf, of;
int src1, src2;
src1 = CC_SRC;
src2 = CC_DST - CC_SRC;
cf = (DATA_TYPE)CC_DST < (DATA_TYPE)src1;
pf = parity_table[(uint8_t)CC_DST];
af = (CC_DST ^ src1 ^ src2) & 0x10;
zf = ((DATA_TYPE)CC_DST == 0) << 6;
sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80;
of = lshift((src1 ^ src2 ^ -1) & (src1 ^ CC_DST), 12 - DATA_BITS) & CC_O;
return cf | pf | af | zf | sf | of;
}
static int glue(compute_c_add, SUFFIX)(void)
{
int src1, cf;
src1 = CC_SRC;
cf = (DATA_TYPE)CC_DST < (DATA_TYPE)src1;
return cf;
}
static int glue(compute_all_adc, SUFFIX)(void)
{
int cf, pf, af, zf, sf, of;
int src1, src2;
src1 = CC_SRC;
src2 = CC_DST - CC_SRC - 1;
cf = (DATA_TYPE)CC_DST <= (DATA_TYPE)src1;
pf = parity_table[(uint8_t)CC_DST];
af = (CC_DST ^ src1 ^ src2) & 0x10;
zf = ((DATA_TYPE)CC_DST == 0) << 6;
sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80;
of = lshift((src1 ^ src2 ^ -1) & (src1 ^ CC_DST), 12 - DATA_BITS) & CC_O;
return cf | pf | af | zf | sf | of;
}
static int glue(compute_c_adc, SUFFIX)(void)
{
int src1, cf;
src1 = CC_SRC;
cf = (DATA_TYPE)CC_DST <= (DATA_TYPE)src1;
return cf;
}
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;
cf = (DATA_TYPE)src1 < (DATA_TYPE)src2;
pf = parity_table[(uint8_t)CC_DST];
af = (CC_DST ^ src1 ^ src2) & 0x10;
zf = ((DATA_TYPE)CC_DST == 0) << 6;
sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80;
of = lshift((src1 ^ src2) & (src1 ^ CC_DST), 12 - DATA_BITS) & CC_O;
return cf | pf | af | zf | sf | of;
}
static int glue(compute_c_sub, SUFFIX)(void)
{
int src1, src2, cf;
src1 = CC_SRC;
src2 = CC_SRC - CC_DST;
cf = (DATA_TYPE)src1 < (DATA_TYPE)src2;
return cf;
}
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;
cf = (DATA_TYPE)src1 <= (DATA_TYPE)src2;
pf = parity_table[(uint8_t)CC_DST];
af = (CC_DST ^ src1 ^ src2) & 0x10;
zf = ((DATA_TYPE)CC_DST == 0) << 6;
sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80;
of = lshift((src1 ^ src2) & (src1 ^ CC_DST), 12 - DATA_BITS) & CC_O;
return cf | pf | af | zf | sf | of;
}
static int glue(compute_c_sbb, SUFFIX)(void)
{
int src1, src2, cf;
src1 = CC_SRC;
src2 = CC_SRC - CC_DST - 1;
cf = (DATA_TYPE)src1 <= (DATA_TYPE)src2;
return cf;
}
static int glue(compute_all_logic, SUFFIX)(void)
{
int cf, pf, af, zf, sf, of;
cf = 0;
pf = parity_table[(uint8_t)CC_DST];
af = 0;
zf = ((DATA_TYPE)CC_DST == 0) << 6;
sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80;
of = 0;
return cf | pf | af | zf | sf | of;
}
static int glue(compute_c_logic, SUFFIX)(void)
{
return 0;
}
static int glue(compute_all_inc, SUFFIX)(void)
{
int cf, pf, af, zf, sf, of;
int src1, src2;
src1 = CC_DST - 1;
src2 = 1;
cf = CC_SRC;
pf = parity_table[(uint8_t)CC_DST];
af = (CC_DST ^ src1 ^ src2) & 0x10;
zf = ((DATA_TYPE)CC_DST == 0) << 6;
sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80;
of = ((CC_DST & DATA_MASK) == SIGN_MASK) << 11;
return cf | pf | af | zf | sf | of;
}
#if DATA_BITS == 32
static int glue(compute_c_inc, SUFFIX)(void)
{
return CC_SRC;
}
#endif
static int glue(compute_all_dec, SUFFIX)(void)
{
int cf, pf, af, zf, sf, of;
int src1, src2;
src1 = CC_DST + 1;
src2 = 1;
cf = CC_SRC;
pf = parity_table[(uint8_t)CC_DST];
af = (CC_DST ^ src1 ^ src2) & 0x10;
zf = ((DATA_TYPE)CC_DST == 0) << 6;
sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80;
of = ((CC_DST & DATA_MASK) == ((uint32_t)SIGN_MASK - 1)) << 11;
return cf | pf | af | zf | sf | of;
}
static int glue(compute_all_shl, SUFFIX)(void)
{
int cf, pf, af, zf, sf, of;
cf = (CC_SRC >> (DATA_BITS - 1)) & CC_C;
pf = parity_table[(uint8_t)CC_DST];
af = 0; /* undefined */
zf = ((DATA_TYPE)CC_DST == 0) << 6;
sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80;
/* of is defined if shift count == 1 */
of = lshift(CC_SRC ^ CC_DST, 12 - DATA_BITS) & CC_O;
return cf | pf | af | zf | sf | of;
}
static int glue(compute_c_shl, SUFFIX)(void)
{
return (CC_SRC >> (DATA_BITS - 1)) & CC_C;
}
#if DATA_BITS == 32
static int glue(compute_c_sar, SUFFIX)(void)
{
return CC_SRC & 1;
}
#endif
static int glue(compute_all_sar, SUFFIX)(void)
{
int cf, pf, af, zf, sf, of;
cf = CC_SRC & 1;
pf = parity_table[(uint8_t)CC_DST];
af = 0; /* undefined */
zf = ((DATA_TYPE)CC_DST == 0) << 6;
sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80;
/* of is defined if shift count == 1 */
of = lshift(CC_SRC ^ CC_DST, 12 - DATA_BITS) & CC_O;
return cf | pf | af | zf | sf | of;
}
/* various optimized jumps cases */
void OPPROTO glue(op_jb_sub, SUFFIX)(void)
{
int src1, src2;
src1 = CC_SRC;
src2 = CC_SRC - CC_DST;
if ((DATA_TYPE)src1 < (DATA_TYPE)src2)
JUMP_TB(PARAM1, 0, PARAM2);
else
JUMP_TB(PARAM1, 1, PARAM3);
FORCE_RET();
}
void OPPROTO glue(op_jz_sub, SUFFIX)(void)
{
if ((DATA_TYPE)CC_DST == 0)
JUMP_TB(PARAM1, 0, PARAM2);
else
JUMP_TB(PARAM1, 1, PARAM3);
FORCE_RET();
}
void OPPROTO glue(op_jbe_sub, SUFFIX)(void)
{
int src1, src2;
src1 = CC_SRC;
src2 = CC_SRC - CC_DST;
if ((DATA_TYPE)src1 <= (DATA_TYPE)src2)
JUMP_TB(PARAM1, 0, PARAM2);
else
JUMP_TB(PARAM1, 1, PARAM3);
FORCE_RET();
}
void OPPROTO glue(op_js_sub, SUFFIX)(void)
{
if (CC_DST & SIGN_MASK)
JUMP_TB(PARAM1, 0, PARAM2);
else
JUMP_TB(PARAM1, 1, PARAM3);
FORCE_RET();
}
void OPPROTO glue(op_jl_sub, SUFFIX)(void)
{
int src1, src2;
src1 = CC_SRC;
src2 = CC_SRC - CC_DST;
if ((DATA_STYPE)src1 < (DATA_STYPE)src2)
JUMP_TB(PARAM1, 0, PARAM2);
else
JUMP_TB(PARAM1, 1, PARAM3);
FORCE_RET();
}
void OPPROTO glue(op_jle_sub, SUFFIX)(void)
{
int src1, src2;
src1 = CC_SRC;
src2 = CC_SRC - CC_DST;
if ((DATA_STYPE)src1 <= (DATA_STYPE)src2)
JUMP_TB(PARAM1, 0, PARAM2);
else
JUMP_TB(PARAM1, 1, PARAM3);
FORCE_RET();
}
/* oldies */
#if DATA_BITS >= 16
void OPPROTO glue(op_loopnz, SUFFIX)(void)
{
unsigned int tmp;
int eflags;
eflags = cc_table[CC_OP].compute_all();
tmp = (ECX - 1) & DATA_MASK;
ECX = (ECX & ~DATA_MASK) | tmp;
if (tmp != 0 && !(eflags & CC_Z))
EIP = PARAM1;
else
EIP = PARAM2;
FORCE_RET();
}
void OPPROTO glue(op_loopz, SUFFIX)(void)
{
unsigned int tmp;
int eflags;
eflags = cc_table[CC_OP].compute_all();
tmp = (ECX - 1) & DATA_MASK;
ECX = (ECX & ~DATA_MASK) | tmp;
if (tmp != 0 && (eflags & CC_Z))
EIP = PARAM1;
else
EIP = PARAM2;
FORCE_RET();
}
void OPPROTO glue(op_loop, SUFFIX)(void)
{
unsigned int tmp;
tmp = (ECX - 1) & DATA_MASK;
ECX = (ECX & ~DATA_MASK) | tmp;
if (tmp != 0)
EIP = PARAM1;
else
EIP = PARAM2;
FORCE_RET();
}
void OPPROTO glue(op_jecxz, SUFFIX)(void)
{
if ((DATA_TYPE)ECX == 0)
EIP = PARAM1;
else
EIP = PARAM2;
FORCE_RET();
}
#endif
/* various optimized set cases */
void OPPROTO glue(op_setb_T0_sub, SUFFIX)(void)
{
int src1, src2;
src1 = CC_SRC;
src2 = CC_SRC - CC_DST;
T0 = ((DATA_TYPE)src1 < (DATA_TYPE)src2);
}
void OPPROTO glue(op_setz_T0_sub, SUFFIX)(void)
{
T0 = ((DATA_TYPE)CC_DST == 0);
}
void OPPROTO glue(op_setbe_T0_sub, SUFFIX)(void)
{
int src1, src2;
src1 = CC_SRC;
src2 = CC_SRC - CC_DST;
T0 = ((DATA_TYPE)src1 <= (DATA_TYPE)src2);
}
void OPPROTO glue(op_sets_T0_sub, SUFFIX)(void)
{
T0 = lshift(CC_DST, -(DATA_BITS - 1)) & 1;
}
void OPPROTO glue(op_setl_T0_sub, SUFFIX)(void)
{
int src1, src2;
src1 = CC_SRC;
src2 = CC_SRC - CC_DST;
T0 = ((DATA_STYPE)src1 < (DATA_STYPE)src2);
}
void OPPROTO glue(op_setle_T0_sub, SUFFIX)(void)
{
int src1, src2;
src1 = CC_SRC;
src2 = CC_SRC - CC_DST;
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;
count = T1 & 0x1f;
T0 = T0 << count;
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;
count = T1 & 0x1f;
T0 &= DATA_MASK;
T0 = T0 >> count;
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;
count = T1 & 0x1f;
src = (DATA_STYPE)T0;
T0 = src >> count;
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;
}
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();
}
/* bit operations */
#if DATA_BITS >= 16
void OPPROTO glue(glue(op_bt, SUFFIX), _T0_T1_cc)(void)
{
int count;
count = T1 & SHIFT_MASK;
CC_SRC = T0 >> count;
}
void OPPROTO glue(glue(op_bts, SUFFIX), _T0_T1_cc)(void)
{
int count;
count = T1 & SHIFT_MASK;
CC_SRC = T0 >> count;
T0 |= (1 << count);
}
void OPPROTO glue(glue(op_btr, SUFFIX), _T0_T1_cc)(void)
{
int count;
count = T1 & SHIFT_MASK;
CC_SRC = T0 >> count;
T0 &= ~(1 << count);
}
void OPPROTO glue(glue(op_btc, SUFFIX), _T0_T1_cc)(void)
{
int count;
count = T1 & SHIFT_MASK;
CC_SRC = T0 >> count;
T0 ^= (1 << count);
}
void OPPROTO glue(glue(op_bsf, SUFFIX), _T0_cc)(void)
{
int res, count;
res = T0 & DATA_MASK;
if (res != 0) {
count = 0;
while ((res & 1) == 0) {
count++;
res >>= 1;
}
T0 = count;
CC_DST = 1; /* ZF = 1 */
} else {
CC_DST = 0; /* ZF = 1 */
}
FORCE_RET();
}
void OPPROTO glue(glue(op_bsr, SUFFIX), _T0_cc)(void)
{
int res, count;
res = T0 & DATA_MASK;
if (res != 0) {
count = DATA_BITS - 1;
while ((res & SIGN_MASK) == 0) {
count--;
res <<= 1;
}
T0 = count;
CC_DST = 1; /* ZF = 1 */
} else {
CC_DST = 0; /* ZF = 1 */
}
FORCE_RET();
}
#endif
/* string operations */
/* XXX: maybe use lower level instructions to ease 16 bit / segment handling */
#define STRING_SUFFIX _fast
#define SI_ADDR (void *)ESI
#define DI_ADDR (void *)EDI
#define INC_SI() ESI += inc
#define INC_DI() EDI += inc
#define CX ECX
#define DEC_CX() ECX--
#include "op_string.h"
#define STRING_SUFFIX _a32
#define SI_ADDR (uint8_t *)A0 + ESI
#define DI_ADDR env->seg_cache[R_ES].base + EDI
#define INC_SI() ESI += inc
#define INC_DI() EDI += inc
#define CX ECX
#define DEC_CX() ECX--
#include "op_string.h"
#define STRING_SUFFIX _a16
#define SI_ADDR (uint8_t *)A0 + (ESI & 0xffff)
#define DI_ADDR env->seg_cache[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)
#define DEC_CX() ECX = (ECX & ~0xffff) | ((ECX - 1) & 0xffff)
#include "op_string.h"
/* port I/O */
void OPPROTO glue(glue(op_out, SUFFIX), _T0_T1)(void)
{
glue(cpu_x86_out, SUFFIX)(env, T0 & 0xffff, T1 & DATA_MASK);
}
void OPPROTO glue(glue(op_in, SUFFIX), _T0_T1)(void)
{
T1 = glue(cpu_x86_in, SUFFIX)(env, T0 & 0xffff);
}
#undef DATA_BITS
#undef SHIFT_MASK
#undef SIGN_MASK
#undef DATA_TYPE
#undef DATA_STYPE
#undef DATA_MASK
#undef SUFFIX
+3231
View File
File diff suppressed because it is too large Load Diff
+130
View File
@@ -0,0 +1,130 @@
/* ld script to make i386 Linux kernel
* Written by Martin Mares <mj@atrey.karlin.mff.cuni.cz>;
*/
OUTPUT_FORMAT("elf32-powerpc", "elf32-powerpc", "elf32-powerpc")
OUTPUT_ARCH(powerpc)
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 . */
}
+447
View File
@@ -0,0 +1,447 @@
\input texinfo @c -*- texinfo -*-
@settitle QEMU x86 Emulator Reference Documentation
@titlepage
@sp 7
@center @titlefont{QEMU x86 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.
QEMU features:
@itemize
@item User space only x86 emulator.
@item Currently ported on i386, PowerPC. Work in progress for S390, Alpha and Sparc.
@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 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 Precise user space x86 exceptions.
@item Self-modifying code support.
@item Support of host page sizes bigger than 4KB.
@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.
@end itemize
Current QEMU limitations:
@itemize
@item No SSE/MMX support (yet).
@item No x86-64 support.
@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).
@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.
@end itemize
@chapter Invocation
@section Quick Start
In order to launch a Linux process, QEMU needs the process executable
itself and all the target (x86) dynamic libraries used by it.
@itemize
@item On x86, you can just try to launch any process by using the native
libraries:
@example
qemu -L / /bin/ls
@end example
@code{-L /} tells that the x86 dynamic linker must be searched with a
@file{/} prefix.
@item Since QEMU is also a linux process, you can launch qemu with qemu:
@example
qemu -L / qemu -L / /bin/ls
@end example
@item On non x86 CPUs, you need first to download at least an x86 glibc
(@file{qemu-XXX-i386-glibc21.tar.gz} on the QEMU web page). Ensure that
@code{LD_LIBRARY_PATH} is not set:
@example
unset LD_LIBRARY_PATH
@end example
Then you can launch the precompiled @file{ls} x86 executable:
@example
qemu /usr/local/qemu-i386/bin/ls-i386
@end example
You can look at @file{/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. It requires the @code{binfmt_misc} module in the
Linux kernel.
@item The x86 version of QEMU is also included. You can try weird things such as:
@example
qemu /usr/local/qemu-i386/bin/qemu-i386 /usr/local/qemu-i386/bin/ls-i386
@end example
@end itemize
@section Wine launch
@itemize
@item Ensure that you have a working QEMU with the x86 glibc
distribution (see previous section). In order to verify it, you must be
able to do:
@example
qemu /usr/local/qemu-i386/bin/ls-i386
@end example
@item Download the binary x86 Wine install
(@file{qemu-XXX-i386-wine.tar.gz} on the QEMU web page).
@item Configure Wine on your account. Look at the provided script
@file{/usr/local/qemu-i386/bin/wine-conf.sh}. Your previous
@code{$@{HOME@}/.wine} directory is saved to @code{$@{HOME@}/.wine.org}.
@item Then you can try the example @file{putty.exe}:
@example
qemu /usr/local/qemu-i386/wine/bin/wine /usr/local/qemu-i386/wine/c/Program\ Files/putty.exe
@end example
@end itemize
@section Command line options
@example
usage: qemu [-h] [-d] [-L path] [-s size] program [arguments...]
@end example
@table @option
@item -h
Print the help
@item -L path
Set the x86 elf interpreter prefix (default=/usr/local/qemu-i386)
@item -s size
Set the x86 stack size in bytes (default=524288)
@end table
Debug options:
@table @option
@item -d
Activate log (logfile=/tmp/qemu.log)
@item -p pagesize
Act as if the host page size was 'pagesize' bytes
@end table
@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 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.
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]).
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
executables. Such an approach as greater potential because most of the
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.
@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
which make it relatively easily portable and simple while achieving good
performances.
The basic idea is to split every x86 instruction into fewer simpler
instructions. Each simple instruction is implemented by a piece of C
code (see @file{op-i386.c}). Then a compile time tool (@file{dyngen})
takes the corresponding object file (@file{op-i386.o}) to generate a
dynamic code generator which concatenates the simple instructions to
build a function (see @file{op-i386.h:dyngen_code()}).
In essence, the process is similar to [1], but more work is done at
compile time.
A key idea to get optimal performances is that constant parameters can
be passed to the simple operations. For that purpose, dummy ELF
relocations are generated with gcc for each constant parameter. Then,
the tool (@file{dyngen}) can locate the relocations and generate the
appriopriate C code to resolve them when building the dynamic code.
That way, QEMU is no more difficult to port than a dynamic linker.
To go even faster, GCC static register variables are used to keep the
state of the virtual CPU.
@section Register allocation
Since QEMU uses fixed simple instructions, no efficient register
allocation can be done. However, because RISC CPUs have a lot of
register, most of the virtual CPU state can be put in registers without
doing complicated register allocation.
@section Condition code optimisations
Good CPU condition codes emulation (@code{EFLAGS} register on x86) is a
critical point to get good performances. QEMU uses lazy condition code
evaluation: instead of computing the condition codes after each x86
instruction, it just stores one operand (called @code{CC_SRC}), the
result (called @code{CC_DST}) and the type of operation (called
@code{CC_OP}).
@code{CC_OP} is almost never explicitely set in the generated code
because it is known at translation time.
In order to increase performances, a backward pass is performed on the
generated simple instructions (see
@code{translate-i386.c:optimize_flags()}). When it can be proved that
the condition codes are not needed by the next instructions, no
condition codes are computed at all.
@section CPU state optimisations
The x86 CPU has many internal states which change the way it evaluates
instructions. In order to achieve a good speed, the translation phase
considers that some state information of the virtual x86 CPU cannot
change in it. For example, if the SS, DS and ES segments have a zero
base, then the translator does not even generate an addition for the
segment base.
[The FPU stack pointer register is not handled that way yet].
@section Translation cache
A 2MByte cache holds the most recently used translations. For
simplicity, it is completely flushed when it is full. A translation unit
contains just a single basic block (a block of x86 instructions
terminated by a jump or by a virtual CPU state change which the
translator cannot deduce statically).
@section Direct block chaining
After each translated basic block is executed, QEMU uses the simulated
Program Counter (PC) and other cpu state informations (such as the CS
segment base value) to find the next basic block.
In order to accelerate the most common cases where the new simulated PC
is known, QEMU can patch a basic block so that it jumps directly to the
next one.
The most portable code uses an indirect jump. An indirect jump makes it
easier to make the jump target modification atomic. On some
architectures (such as PowerPC), the @code{JUMP} opcode is directly
patched so that the block chaining has no overhead.
@section Self-modifying code and translated code invalidation
Self-modifying code is a special challenge in x86 emulation because no
instruction cache invalidation is signaled by the application when code
is modified.
When translated code is generated for a basic block, the corresponding
host page is write protected if it is not already read-only (with the
system call @code{mprotect()}). Then, if a write access is done to the
page, Linux raises a SEGV signal. QEMU then invalidates all the
translated code in the page and enables write accesses to the page.
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,
most MSDOS programs can be emulated at reasonnable speed with QEMU and
DOSEMU.
Note that QEMU also invalidates pages of translated code when it detects
that memory mappings are modified with @code{mmap()} or @code{munmap()}.
@section Exception support
longjmp() is used when an exception such as division by zero is
encountered.
The host SIGSEGV and SIGBUS signal handlers are used to get invalid
memory accesses. The exact CPU state can be retrieved because all the
x86 registers are stored in fixed host registers. The simulated program
counter is found by retranslating the corresponding basic block and by
looking where the host program counter was at the exception point.
The virtual CPU cannot retrieve the exact @code{EFLAGS} register because
in some cases it is not computed because of condition code
optimisations. It is not a big concern because the emulated code can
still be restarted in any cases.
@section Linux system call translation
QEMU includes a generic system call translator for Linux. It means that
the parameters of the system calls can be converted to fix the
endianness and 32/64 bit issues. The IOCTLs are converted with a generic
type description system (see @file{ioctls.h} and @file{thunk.c}).
QEMU supports host CPUs which have pages bigger than 4KB. It records all
the mappings the process does and try to emulated the @code{mmap()}
system calls in cases where the host @code{mmap()} call would fail
because of bad page alignment.
@section Linux signals
Normal and real-time signals are queued along with their information
(@code{siginfo_t}) as it is done in the Linux kernel. Then an interrupt
request is done to the virtual CPU. When it is interrupted, one queued
signal is handled by generating a stack frame in the virtual CPU as the
Linux kernel does. The @code{sigreturn()} system call is emulated to return
from the virtual signal handler.
Some signals (such as SIGALRM) directly come from the host. Other
signals are synthetized from the virtual CPU exceptions such as SIGFPE
when a division by zero is done (see @code{main.c:cpu_loop()}).
The blocked signal mask is still handled by the host Linux kernel so
that most signal system calls can be redirected directly to the host
Linux kernel. Only the @code{sigaction()} and @code{sigreturn()} system
calls need to be fully emulated (see @file{signal.c}).
@section clone() system call and threads
The Linux clone() system call is usually used to create a thread. QEMU
uses the host clone() system call so that real host threads are created
for each emulated thread. One virtual CPU instance is created for each
thread.
The virtual x86 CPU atomic operations are emulated with a global lock so
that their semantic is preserved.
Note that currently there are still some locking issues in QEMU. In
particular, the translated cache flush is not protected yet against
reentrancy.
@section Self-virtualization
QEMU was conceived so that ultimately it can emulate itself. Althought
it is not very useful, it is an important test to show the power of the
emulator.
Achieving self-virtualization is not easy because there may be address
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 Bibliography
@table @asis
@item [1]
@url{http://citeseer.nj.nec.com/piumarta98optimizing.html}, Optimizing
direct threaded code by selective inlining (1998) by Ian Piumarta, Fabio
Riccardi.
@item [2]
@url{http://developer.kde.org/~sewardj/}, Valgrind, an open-source
memory debugger for x86-GNU/Linux, by Julian Seward.
@item [3]
@url{http://bochs.sourceforge.net/}, the Bochs IA-32 Emulator Project,
by Kevin Lawton et al.
@item [4]
@url{http://www.cs.rose-hulman.edu/~donaldlf/em86/index.html}, the EM86
x86 emulator on Alpha-Linux.
@item [5]
@url{http://www.usenix.org/publications/library/proceedings/usenix-nt97/full_papers/chernoff/chernoff.pdf},
DIGITAL FX!32: Running 32-Bit x86 Applications on Alpha NT, by Anton
Chernoff and Ray Hookway.
@item [6]
@url{http://www.willows.com/}, Windows API library emulation from
Willows Software.
@end table
@chapter Regression Tests
In the directory @file{tests/}, various interesting x86 testing programs
are available. There are used for regression testing.
@section @file{hello}
Very simple statically linked x86 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
generates a text output. It can be compared with the output obtained with
a real CPU or another emulator. The target @code{make test} runs this
program and a @code{diff} on the generated output.
The Linux system call @code{modify_ldt()} is used to create x86 selectors
to test some 16 bit addressing and 32 bit with segmentation cases.
The Linux system call @code{vm86()} is used to test vm86 emulation.
Various exceptions are raised to test most of the x86 user space
exception reporting.
@section @file{sha1}
It is a simple benchmark. Care must be taken to interpret the results
because it mostly tests the ability of the virtual CPU to optimize the
@code{rol} x86 instruction and the condition code computations.
+204
View File
@@ -0,0 +1,204 @@
OUTPUT_FORMAT("elf32-s390", "elf32-s390",
"elf32-s390")
OUTPUT_ARCH(s390:31-bit)
ENTRY(_start)
SEARCH_DIR("/usr/s390-redhat-linux/lib"); SEARCH_DIR("/usr/lib"); SEARCH_DIR("/usr/local/lib"); SEARCH_DIR("/lib");
/* Do we need any of these for elf?
__DYNAMIC = 0; */
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.dyn :
{
*(.rel.init)
*(.rel.text .rel.text.* .rel.gnu.linkonce.t.*)
*(.rel.fini)
*(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*)
*(.rel.data .rel.data.* .rel.gnu.linkonce.d.*)
*(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*)
*(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*)
*(.rel.ctors)
*(.rel.dtors)
*(.rel.got)
*(.rel.sdata .rel.sdata.* .rel.gnu.linkonce.s.*)
*(.rel.sbss .rel.sbss.* .rel.gnu.linkonce.sb.*)
*(.rel.sdata2 .rel.sdata2.* .rel.gnu.linkonce.s2.*)
*(.rel.sbss2 .rel.sbss2.* .rel.gnu.linkonce.sb2.*)
*(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*)
}
.rela.dyn :
{
*(.rela.init)
*(.rela.text .rela.text.* .rela.gnu.linkonce.t.*)
*(.rela.fini)
*(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*)
*(.rela.data .rela.data.* .rela.gnu.linkonce.d.*)
*(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*)
*(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*)
*(.rela.ctors)
*(.rela.dtors)
*(.rela.got)
*(.rela.sdata .rela.sdata.* .rela.gnu.linkonce.s.*)
*(.rela.sbss .rela.sbss.* .rela.gnu.linkonce.sb.*)
*(.rela.sdata2 .rela.sdata2.* .rela.gnu.linkonce.s2.*)
*(.rela.sbss2 .rela.sbss2.* .rela.gnu.linkonce.sb2.*)
*(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*)
}
.rel.plt : { *(.rel.plt) }
.rela.plt : { *(.rela.plt) }
.init :
{
KEEP (*(.init))
} =0x07070707
.plt : { *(.plt) }
.text :
{
*(.text .stub .text.* .gnu.linkonce.t.*)
/* .gnu.warning sections are handled specially by elf32.em. */
*(.gnu.warning)
} =0x07070707
.fini :
{
KEEP (*(.fini))
} =0x07070707
PROVIDE (__etext = .);
PROVIDE (_etext = .);
PROVIDE (etext = .);
.rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
.rodata1 : { *(.rodata1) }
.sdata2 : { *(.sdata2 .sdata2.* .gnu.linkonce.s2.*) }
.sbss2 : { *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*) }
.eh_frame_hdr : { *(.eh_frame_hdr) }
/* 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(0x1000) + (. & (0x1000 - 1));
/* Ensure the __preinit_array_start label is properly aligned. We
could instead move the label definition inside the section, but
the linker would then create the section even if it turns out to
be empty, which isn't pretty. */
. = ALIGN(32 / 8);
PROVIDE (__preinit_array_start = .);
.preinit_array : { *(.preinit_array) }
PROVIDE (__preinit_array_end = .);
PROVIDE (__init_array_start = .);
.init_array : { *(.init_array) }
PROVIDE (__init_array_end = .);
PROVIDE (__fini_array_start = .);
.fini_array : { *(.fini_array) }
PROVIDE (__fini_array_end = .);
.data :
{
*(.data .data.* .gnu.linkonce.d.*)
SORT(CONSTRUCTORS)
}
.data1 : { *(.data1) }
.tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) }
.tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
.eh_frame : { KEEP (*(.eh_frame)) }
.gcc_except_table : { *(.gcc_except_table) }
.dynamic : { *(.dynamic) }
.ctors :
{
/* gcc uses crtbegin.o to find the start of
the constructors, so we make sure it is
first. Because this is a wildcard, it
doesn't matter if the user does not
actually link against crtbegin.o; the
linker won't look for a file to match a
wildcard. The wildcard also means that it
doesn't matter which directory crtbegin.o
is in. */
KEEP (*crtbegin.o(.ctors))
/* We don't want to include the .ctor section from
from the crtend.o file until after the sorted ctors.
The .ctor section from the crtend file contains the
end of ctors marker and it must be last */
KEEP (*(EXCLUDE_FILE (*crtend.o ) .ctors))
KEEP (*(SORT(.ctors.*)))
KEEP (*(.ctors))
}
.dtors :
{
KEEP (*crtbegin.o(.dtors))
KEEP (*(EXCLUDE_FILE (*crtend.o ) .dtors))
KEEP (*(SORT(.dtors.*)))
KEEP (*(.dtors))
}
.jcr : { KEEP (*(.jcr)) }
.got : { *(.got.plt) *(.got) }
/* 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 .sdata.* .gnu.linkonce.s.*)
}
_edata = .;
PROVIDE (edata = .);
__bss_start = .;
.sbss :
{
PROVIDE (__sbss_start = .);
PROVIDE (___sbss_start = .);
*(.dynsbss)
*(.sbss .sbss.* .gnu.linkonce.sb.*)
*(.scommon)
PROVIDE (__sbss_end = .);
PROVIDE (___sbss_end = .);
}
.bss :
{
*(.dynbss)
*(.bss .bss.* .gnu.linkonce.b.*)
*(COMMON)
/* Align here to ensure that the .bss section occupies space up to
_end. Align after .bss to ensure correct alignment even if the
.bss section disappears because there are no input sections. */
. = ALIGN(32 / 8);
}
. = ALIGN(32 / 8);
_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 .gnu.linkonce.wi.*) }
.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) }
}
+410 -36
View File
@@ -237,6 +237,36 @@
#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 */
@@ -245,24 +275,24 @@
struct target_stat {
unsigned short st_dev;
unsigned short __pad1;
unsigned long st_ino;
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;
unsigned long st_size;
unsigned long st_blksize;
unsigned long st_blocks;
unsigned long st_atime;
unsigned long __unused1;
unsigned long st_mtime;
unsigned long __unused2;
unsigned long st_ctime;
unsigned long __unused3;
unsigned long __unused4;
unsigned long __unused5;
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
@@ -272,55 +302,94 @@ struct target_stat64 {
unsigned short st_dev;
unsigned char __pad0[10];
#define STAT64_HAS_BROKEN_ST_INO 1
unsigned long __st_ino;
#define TARGET_STAT64_HAS_BROKEN_ST_INO 1
target_ulong __st_ino;
unsigned int st_mode;
unsigned int st_nlink;
unsigned long st_uid;
unsigned long st_gid;
target_ulong st_uid;
target_ulong st_gid;
unsigned short st_rdev;
unsigned char __pad3[10];
long long st_size;
unsigned long st_blksize;
target_ulong st_blksize;
unsigned long st_blocks; /* Number 512-byte blocks allocated. */
unsigned long __pad4; /* future possible st_blocks high bits */
target_ulong st_blocks; /* Number 512-byte blocks allocated. */
target_ulong __pad4; /* future possible st_blocks high bits */
unsigned long st_atime;
unsigned long __pad5;
target_ulong target_st_atime;
target_ulong __pad5;
unsigned long st_mtime;
unsigned long __pad6;
target_ulong target_st_mtime;
target_ulong __pad6;
unsigned long st_ctime;
unsigned long __pad7; /* will be high 32 bits of ctime someday */
target_ulong target_st_ctime;
target_ulong __pad7; /* will be high 32 bits of ctime someday */
unsigned long long st_ino;
};
} __attribute__((packed));
typedef unsigned long old_sigset_t; /* at least 32 bits */
#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;
void (*sa_restorer)(void);
target_ulong sa_restorer;
};
struct target_sigaction {
target_ulong _sa_handler;
target_sigset_t sa_mask;
target_ulong sa_flags;
target_ulong sa_restorer;
target_sigset_t sa_mask;
};
typedef union target_sigval {
int sival_int;
void *sival_ptr;
target_ulong sival_ptr;
} target_sigval_t;
#define TARGET_SI_MAX_SIZE 128
@@ -350,7 +419,7 @@ typedef struct target_siginfo {
struct {
pid_t _pid; /* sender's pid */
uid_t _uid; /* sender's uid */
sigval_t _sigval;
target_sigval_t _sigval;
} _rt;
/* SIGCHLD */
@@ -358,13 +427,13 @@ typedef struct target_siginfo {
pid_t _pid; /* which child */
uid_t _uid; /* sender's uid */
int _status; /* exit code */
clock_t _utime;
clock_t _stime;
target_clock_t _utime;
target_clock_t _stime;
} _sigchld;
/* SIGILL, SIGFPE, SIGSEGV, SIGBUS */
struct {
void *_addr; /* faulting insn/memory ref. */
target_ulong _addr; /* faulting insn/memory ref. */
} _sigfault;
/* SIGPOLL */
@@ -375,6 +444,70 @@ typedef struct target_siginfo {
} _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)
struct target_pt_regs {
long ebx;
long ecx;
long edx;
long esi;
long edi;
long ebp;
long eax;
int xds;
int xes;
long orig_eax;
long eip;
int xcs;
long eflags;
long esp;
int xss;
};
/* ioctls */
/*
@@ -463,8 +596,8 @@ typedef struct target_siginfo {
#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 _IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */
#define TARGET_TIOCSPTLCK _IOW('T',0x31, int) /* Lock/unlock Pty */
#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
@@ -632,6 +765,242 @@ struct target_termios {
#define TARGET_VLNEXT 15
#define TARGET_VEOL2 16
#define TARGET_LDT_ENTRIES 8192
#define TARGET_LDT_ENTRY_SIZE 8
#define TARGET_GDT_ENTRY_TLS_ENTRIES 3
#define TARGET_GDT_ENTRY_TLS_MIN 6
#define TARGET_GDT_ENTRY_TLS_MAX (TARGET_GDT_ENTRY_TLS_MIN + TARGET_GDT_ENTRY_TLS_ENTRIES - 1)
struct target_modify_ldt_ldt_s {
unsigned int entry_number;
target_ulong base_addr;
unsigned int limit;
unsigned int flags;
};
/* vm86 defines */
#define TARGET_BIOSSEG 0x0f000
#define TARGET_CPU_086 0
#define TARGET_CPU_186 1
#define TARGET_CPU_286 2
#define TARGET_CPU_386 3
#define TARGET_CPU_486 4
#define TARGET_CPU_586 5
#define TARGET_VM86_SIGNAL 0 /* return due to signal */
#define TARGET_VM86_UNKNOWN 1 /* unhandled GP fault - IO-instruction or similar */
#define TARGET_VM86_INTx 2 /* int3/int x instruction (ARG = x) */
#define TARGET_VM86_STI 3 /* sti/popf/iret instruction enabled virtual interrupts */
/*
* Additional return values when invoking new vm86()
*/
#define TARGET_VM86_PICRETURN 4 /* return due to pending PIC request */
#define TARGET_VM86_TRAP 6 /* return due to DOS-debugger request */
/*
* function codes when invoking new vm86()
*/
#define TARGET_VM86_PLUS_INSTALL_CHECK 0
#define TARGET_VM86_ENTER 1
#define TARGET_VM86_ENTER_NO_BYPASS 2
#define TARGET_VM86_REQUEST_IRQ 3
#define TARGET_VM86_FREE_IRQ 4
#define TARGET_VM86_GET_IRQ_BITS 5
#define TARGET_VM86_GET_AND_RESET_IRQ 6
/*
* This is the stack-layout seen by the user space program when we have
* done a translation of "SAVE_ALL" from vm86 mode. The real kernel layout
* is 'kernel_vm86_regs' (see below).
*/
struct target_vm86_regs {
/*
* normal regs, with special meaning for the segment descriptors..
*/
target_long ebx;
target_long ecx;
target_long edx;
target_long esi;
target_long edi;
target_long ebp;
target_long eax;
target_long __null_ds;
target_long __null_es;
target_long __null_fs;
target_long __null_gs;
target_long orig_eax;
target_long eip;
unsigned short cs, __csh;
target_long eflags;
target_long esp;
unsigned short ss, __ssh;
/*
* these are specific to v86 mode:
*/
unsigned short es, __esh;
unsigned short ds, __dsh;
unsigned short fs, __fsh;
unsigned short gs, __gsh;
};
struct target_revectored_struct {
target_ulong __map[8]; /* 256 bits */
};
struct target_vm86_struct {
struct target_vm86_regs regs;
target_ulong flags;
target_ulong screen_bitmap;
target_ulong cpu_type;
struct target_revectored_struct int_revectored;
struct target_revectored_struct int21_revectored;
};
/*
* flags masks
*/
#define TARGET_VM86_SCREEN_BITMAP 0x0001
struct target_vm86plus_info_struct {
target_ulong flags;
#define TARGET_force_return_for_pic (1 << 0)
#define TARGET_vm86dbg_active (1 << 1) /* for debugger */
#define TARGET_vm86dbg_TFpendig (1 << 2) /* for debugger */
#define TARGET_is_vm86pus (1 << 31) /* for vm86 internal use */
unsigned char vm86dbg_intxxtab[32]; /* for debugger */
};
struct target_vm86plus_struct {
struct target_vm86_regs regs;
target_ulong flags;
target_ulong screen_bitmap;
target_ulong cpu_type;
struct target_revectored_struct int_revectored;
struct target_revectored_struct int21_revectored;
struct target_vm86plus_info_struct vm86plus;
};
/* ipcs */
#define TARGET_SEMOP 1
#define TARGET_SEMGET 2
#define TARGET_SEMCTL 3
#define TARGET_MSGSND 11
#define TARGET_MSGRCV 12
#define TARGET_MSGGET 13
#define TARGET_MSGCTL 14
#define TARGET_SHMAT 21
#define TARGET_SHMDT 22
#define TARGET_SHMGET 23
#define TARGET_SHMCTL 24
struct target_msgbuf {
int mtype;
char mtext[1];
};
struct target_ipc_kludge {
unsigned int msgp; /* Really (struct msgbuf *) */
int msgtyp;
};
struct alpha_msgbuf {
long mtype;
char mtext[4096];
};
struct target_ipc_perm {
int key;
unsigned short uid;
unsigned short gid;
unsigned short cuid;
unsigned short cgid;
unsigned short mode;
unsigned short seq;
};
struct target_msqid_ds {
struct target_ipc_perm msg_perm;
unsigned int msg_first; /* really struct target_msg* */
unsigned int msg_last; /* really struct target_msg* */
unsigned int msg_stime; /* really target_time_t */
unsigned int msg_rtime; /* really target_time_t */
unsigned int msg_ctime; /* really target_time_t */
unsigned int wwait; /* really struct wait_queue* */
unsigned int rwait; /* really struct wait_queue* */
unsigned short msg_cbytes;
unsigned short msg_qnum;
unsigned short msg_qbytes;
unsigned short msg_lspid;
unsigned short msg_lrpid;
};
struct target_shmid_ds {
struct target_ipc_perm shm_perm;
int shm_segsz;
unsigned int shm_atime; /* really target_time_t */
unsigned int shm_dtime; /* really target_time_t */
unsigned int shm_ctime; /* really target_time_t */
unsigned short shm_cpid;
unsigned short shm_lpid;
short shm_nattch;
unsigned short shm_npages;
unsigned long *shm_pages;
void *attaches; /* really struct shm_desc * */
};
#define TARGET_IPC_RMID 0
#define TARGET_IPC_SET 1
#define TARGET_IPC_STAT 2
union target_semun {
int val;
unsigned int buf; /* really struct semid_ds * */
unsigned int array; /* really unsigned short * */
unsigned int __buf; /* really struct seminfo * */
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
@@ -758,3 +1127,8 @@ struct target_termios {
#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
+22
View File
@@ -0,0 +1,22 @@
gmon.out
testsig
hello
sha1.test.c
sha1.c
test-i386
sha1
testclone
.gdb_history
testthread
test-i386.s
test-i386.ref
sha1-i386
runcom
debug.com
test-i386.out
speed.txt
test-i386.ref.P3
pi_10.com
test-i386.ref.P4
ldso.c
test_path
+61
View File
@@ -0,0 +1,61 @@
include ../config.mak
CFLAGS=-Wall -O2 -g
LDFLAGS=
ifeq ($(ARCH),i386)
TESTS=testclone testsig testthread sha1-i386 test-i386 runcom
endif
TESTS+=sha1 test_path
QEMU=../qemu
all: $(TESTS)
hello: hello.c
$(CC) -nostdlib $(CFLAGS) -static $(LDFLAGS) -o $@ $<
strip hello
testclone: testclone.c
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $<
testsig: testsig.c
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $<
testthread: testthread.c
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< -lpthread
test_path: test_path.c
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $<
./$@ || { rm $@; exit 1; }
# i386 emulation test (test various opcodes) */
test-i386: test-i386.c test-i386-code16.S test-i386-vm86.S \
test-i386.h test-i386-shift.h test-i386-muldiv.h
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ test-i386.c \
test-i386-code16.S test-i386-vm86.S -lm
test: test-i386
ifeq ($(ARCH),i386)
./test-i386 > test-i386.ref
endif
$(QEMU) test-i386 > test-i386.out
@if diff -u test-i386.ref test-i386.out ; then echo "Auto Test OK"; fi
# speed test
sha1-i386: sha1.c
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $<
sha1: sha1.c
$(HOST_CC) $(CFLAGS) $(LDFLAGS) -o $@ $<
speed: sha1 sha1-i386
time ./sha1
time $(QEMU) ./sha1-i386
# vm86 test
runcom: runcom.c
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $<
clean:
rm -f *~ *.o $(TESTS)
+26
View File
@@ -0,0 +1,26 @@
#include <asm/unistd.h>
extern inline volatile void exit(int status)
{
int __res;
__asm__ volatile ("movl %%ecx,%%ebx\n"\
"int $0x80" \
: "=a" (__res) : "0" (__NR_exit),"c" ((long)(status)));
}
extern inline int write(int fd, const char * buf, int len)
{
int status;
__asm__ volatile ("pushl %%ebx\n"\
"movl %%esi,%%ebx\n"\
"int $0x80\n" \
"popl %%ebx\n"\
: "=a" (status) \
: "0" (__NR_write),"S" ((long)(fd)),"c" ((long)(buf)),"d" ((long)(len)));
}
void _start(void)
{
write(1, "Hello World\n", 12);
exit(0);
}
+195
View File
@@ -0,0 +1,195 @@
/*
* Simple example of use of vm86: launch a basic .com DOS executable
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <inttypes.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <signal.h>
#include <linux/unistd.h>
#include <asm/vm86.h>
//#define SIGTEST
#undef __syscall_return
#define __syscall_return(type, res) \
do { \
return (type) (res); \
} while (0)
_syscall2(int, vm86, int, func, struct vm86plus_struct *, v86)
#define COM_BASE_ADDR 0x10100
void usage(void)
{
printf("runcom version 0.1 (c) 2003 Fabrice Bellard\n"
"usage: runcom file.com\n"
"VM86 Run simple .com DOS executables (linux vm86 test mode)\n");
exit(1);
}
static inline void set_bit(uint8_t *a, unsigned int bit)
{
a[bit / 8] |= (1 << (bit % 8));
}
static inline uint8_t *seg_to_linear(unsigned int seg, unsigned int reg)
{
return (uint8_t *)((seg << 4) + (reg & 0xffff));
}
static inline void pushw(struct vm86_regs *r, int val)
{
r->esp = (r->esp & ~0xffff) | ((r->esp - 2) & 0xffff);
*(uint16_t *)seg_to_linear(r->ss, r->esp) = val;
}
void dump_regs(struct vm86_regs *r)
{
fprintf(stderr,
"EAX=%08lx EBX=%08lx ECX=%08lx EDX=%08lx\n"
"ESI=%08lx EDI=%08lx EBP=%08lx ESP=%08lx\n"
"EIP=%08lx EFL=%08lx\n"
"CS=%04x DS=%04x ES=%04x SS=%04x FS=%04x GS=%04x\n",
r->eax, r->ebx, r->ecx, r->edx, r->esi, r->edi, r->ebp, r->esp,
r->eip, r->eflags,
r->cs, r->ds, r->es, r->ss, r->fs, r->gs);
}
#ifdef SIGTEST
void alarm_handler(int sig)
{
fprintf(stderr, "alarm signal=%d\n", sig);
alarm(1);
}
#endif
int main(int argc, char **argv)
{
uint8_t *vm86_mem;
const char *filename;
int fd, ret, seg;
struct vm86plus_struct ctx;
struct vm86_regs *r;
if (argc != 2)
usage();
filename = argv[1];
vm86_mem = mmap((void *)0x00000000, 0x110000,
PROT_WRITE | PROT_READ | PROT_EXEC,
MAP_FIXED | MAP_ANON | MAP_PRIVATE, -1, 0);
if (vm86_mem == MAP_FAILED) {
perror("mmap");
exit(1);
}
#ifdef SIGTEST
{
struct sigaction act;
act.sa_handler = alarm_handler;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
sigaction(SIGALRM, &act, NULL);
alarm(1);
}
#endif
/* load the MSDOS .com executable */
fd = open(filename, O_RDONLY);
if (fd < 0) {
perror(filename);
exit(1);
}
ret = read(fd, vm86_mem + COM_BASE_ADDR, 65536 - 256);
if (ret < 0) {
perror("read");
exit(1);
}
close(fd);
memset(&ctx, 0, sizeof(ctx));
/* init basic registers */
r = &ctx.regs;
r->eip = 0x100;
r->esp = 0xfffe;
seg = (COM_BASE_ADDR - 0x100) >> 4;
r->cs = seg;
r->ss = seg;
r->ds = seg;
r->es = seg;
r->fs = seg;
r->gs = seg;
r->eflags = VIF_MASK;
/* put return code */
set_bit((uint8_t *)&ctx.int_revectored, 0x21);
*seg_to_linear(r->cs, 0) = 0xb4; /* mov ah, $0 */
*seg_to_linear(r->cs, 1) = 0x00;
*seg_to_linear(r->cs, 2) = 0xcd; /* int $0x21 */
*seg_to_linear(r->cs, 3) = 0x21;
pushw(&ctx.regs, 0x0000);
/* the value of these registers seem to be assumed by pi_10.com */
r->esi = 0x100;
r->ecx = 0xff;
r->ebp = 0x0900;
r->edi = 0xfffe;
for(;;) {
ret = vm86(VM86_ENTER, &ctx);
switch(VM86_TYPE(ret)) {
case VM86_INTx:
{
int int_num, ah;
int_num = VM86_ARG(ret);
if (int_num != 0x21)
goto unknown_int;
ah = (r->eax >> 8) & 0xff;
switch(ah) {
case 0x00: /* exit */
exit(0);
case 0x02: /* write char */
{
uint8_t c = r->edx;
write(1, &c, 1);
}
break;
case 0x09: /* write string */
{
uint8_t c;
for(;;) {
c = *seg_to_linear(r->ds, r->edx);
if (c == '$')
break;
write(1, &c, 1);
}
r->eax = (r->eax & ~0xff) | '$';
}
break;
default:
unknown_int:
fprintf(stderr, "unsupported int 0x%02x\n", int_num);
dump_regs(&ctx.regs);
// exit(1);
}
}
break;
case VM86_SIGNAL:
/* a signal came, we just ignore that */
break;
case VM86_STI:
break;
default:
fprintf(stderr, "unhandled vm86 return code (0x%x)\n", ret);
dump_regs(&ctx.regs);
exit(1);
}
}
}
+80
View File
@@ -0,0 +1,80 @@
.code16
.globl code16_start
.globl code16_end
CS_SEG = 0xf
code16_start:
.globl code16_func1
/* basic test */
code16_func1 = . - code16_start
mov $1, %eax
data32 lret
/* test push/pop in 16 bit mode */
.globl code16_func2
code16_func2 = . - code16_start
xor %eax, %eax
mov $0x12345678, %ebx
movl %esp, %ecx
push %bx
subl %esp, %ecx
pop %ax
data32 lret
/* test various jmp opcodes */
.globl code16_func3
code16_func3 = . - code16_start
jmp 1f
nop
1:
mov $4, %eax
mov $0x12345678, %ebx
xor %bx, %bx
jz 2f
add $2, %ax
2:
call myfunc
lcall $CS_SEG, $(myfunc2 - code16_start)
ljmp $CS_SEG, $(myjmp1 - code16_start)
myjmp1_next:
cs lcall myfunc2_addr - code16_start
cs ljmp myjmp2_addr - code16_start
myjmp2_next:
data32 lret
myfunc2_addr:
.short myfunc2 - code16_start
.short CS_SEG
myjmp2_addr:
.short myjmp2 - code16_start
.short CS_SEG
myjmp1:
add $8, %ax
jmp myjmp1_next
myjmp2:
add $16, %ax
jmp myjmp2_next
myfunc:
add $1, %ax
ret
myfunc2:
add $4, %ax
lret
code16_end:
+56
View File
@@ -0,0 +1,56 @@
void glue(glue(test_, OP), b)(int op0, int op1)
{
int res, s1, s0, flags;
s0 = op0;
s1 = op1;
res = s0;
flags = 0;
asm ("push %4\n\t"
"popf\n\t"
stringify(OP)"b %b2\n\t"
"pushf\n\t"
"popl %1\n\t"
: "=a" (res), "=g" (flags)
: "q" (s1), "0" (res), "1" (flags));
printf("%-10s A=%08x B=%08x R=%08x CC=%04x\n",
stringify(OP) "b", s0, s1, res, flags & CC_MASK);
}
void glue(glue(test_, OP), w)(int op0h, int op0, int op1)
{
int res, s1, flags, resh;
s1 = op1;
resh = op0h;
res = op0;
flags = 0;
asm ("push %5\n\t"
"popf\n\t"
stringify(OP) "w %w3\n\t"
"pushf\n\t"
"popl %1\n\t"
: "=a" (res), "=g" (flags), "=d" (resh)
: "q" (s1), "0" (res), "1" (flags), "2" (resh));
printf("%-10s AH=%08x AL=%08x B=%08x RH=%08x RL=%08x CC=%04x\n",
stringify(OP) "w", op0h, op0, s1, resh, res, flags & CC_MASK);
}
void glue(glue(test_, OP), l)(int op0h, int op0, int op1)
{
int res, s1, flags, resh;
s1 = op1;
resh = op0h;
res = op0;
flags = 0;
asm ("push %5\n\t"
"popf\n\t"
stringify(OP) "l %3\n\t"
"pushf\n\t"
"popl %1\n\t"
: "=a" (res), "=g" (flags), "=d" (resh)
: "q" (s1), "0" (res), "1" (flags), "2" (resh));
printf("%-10s AH=%08x AL=%08x B=%08x RH=%08x RL=%08x CC=%04x\n",
stringify(OP) "l", op0h, op0, s1, resh, res, flags & CC_MASK);
}
#undef OP
+143
View File
@@ -0,0 +1,143 @@
#define exec_op glue(exec_, OP)
#define exec_opl glue(glue(exec_, OP), l)
#define exec_opw glue(glue(exec_, OP), w)
#define exec_opb glue(glue(exec_, OP), b)
#ifndef OP_SHIFTD
#ifdef OP_NOBYTE
#define EXECSHIFT(size, res, s1, s2, flags) \
asm ("push %4\n\t"\
"popf\n\t"\
stringify(OP) size " %" size "2, %" size "0\n\t" \
"pushf\n\t"\
"popl %1\n\t"\
: "=g" (res), "=g" (flags)\
: "r" (s1), "0" (res), "1" (flags));
#else
#define EXECSHIFT(size, res, s1, s2, flags) \
asm ("push %4\n\t"\
"popf\n\t"\
stringify(OP) size " %%cl, %" size "0\n\t" \
"pushf\n\t"\
"popl %1\n\t"\
: "=q" (res), "=g" (flags)\
: "c" (s1), "0" (res), "1" (flags));
#endif
void exec_opl(int s2, int s0, int s1, int iflags)
{
int res, flags;
res = s0;
flags = iflags;
EXECSHIFT("", res, s1, s2, flags);
/* overflow is undefined if count != 1 */
if (s1 != 1)
flags &= ~CC_O;
printf("%-10s A=%08x B=%08x R=%08x CCIN=%04x CC=%04x\n",
stringify(OP) "l", s0, s1, res, iflags, flags & CC_MASK);
}
void exec_opw(int s2, int s0, int s1, int iflags)
{
int res, flags;
res = s0;
flags = iflags;
EXECSHIFT("w", res, s1, s2, flags);
/* overflow is undefined if count != 1 */
if (s1 != 1)
flags &= ~CC_O;
printf("%-10s A=%08x B=%08x R=%08x CCIN=%04x CC=%04x\n",
stringify(OP) "w", s0, s1, res, iflags, flags & CC_MASK);
}
#else
#define EXECSHIFT(size, res, s1, s2, flags) \
asm ("push %4\n\t"\
"popf\n\t"\
stringify(OP) size " %%cl, %" size "5, %" size "0\n\t" \
"pushf\n\t"\
"popl %1\n\t"\
: "=g" (res), "=g" (flags)\
: "c" (s1), "0" (res), "1" (flags), "r" (s2));
void exec_opl(int s2, int s0, int s1, int iflags)
{
int res, flags;
res = s0;
flags = iflags;
EXECSHIFT("", res, s1, s2, flags);
/* overflow is undefined if count != 1 */
if (s1 != 1)
flags &= ~CC_O;
printf("%-10s A=%08x B=%08x C=%08x R=%08x CCIN=%04x CC=%04x\n",
stringify(OP) "l", s0, s2, s1, res, iflags, flags & CC_MASK);
}
void exec_opw(int s2, int s0, int s1, int iflags)
{
int res, flags;
res = s0;
flags = iflags;
EXECSHIFT("w", res, s1, s2, flags);
/* overflow is undefined if count != 1 */
if (s1 != 1)
flags &= ~CC_O;
printf("%-10s A=%08x B=%08x C=%08x R=%08x CCIN=%04x CC=%04x\n",
stringify(OP) "w", s0, s2, s1, res, iflags, flags & CC_MASK);
}
#endif
#ifndef OP_NOBYTE
void exec_opb(int s0, int s1, int iflags)
{
int res, flags;
res = s0;
flags = iflags;
EXECSHIFT("b", res, s1, 0, flags);
/* overflow is undefined if count != 1 */
if (s1 != 1)
flags &= ~CC_O;
printf("%-10s A=%08x B=%08x R=%08x CCIN=%04x CC=%04x\n",
stringify(OP) "b", s0, s1, res, iflags, flags & CC_MASK);
}
#endif
void exec_op(int s2, int s0, int s1)
{
exec_opl(s2, s0, s1, 0);
#ifdef OP_SHIFTD
if (s1 <= 15)
exec_opw(s2, s0, s1, 0);
#else
exec_opw(s2, s0, s1, 0);
#endif
#ifndef OP_NOBYTE
exec_opb(s0, s1, 0);
#endif
#ifdef OP_CC
exec_opl(s2, s0, s1, CC_C);
exec_opw(s2, s0, s1, CC_C);
exec_opb(s0, s1, CC_C);
#endif
}
void glue(test_, OP)(void)
{
int i;
for(i = 0; i < 32; i++)
exec_op(0x21ad3d34, 0x12345678, i);
for(i = 0; i < 32; i++)
exec_op(0x813f3421, 0x82345678, i);
}
void *glue(_test_, OP) __init_call = glue(test_, OP);
#undef OP
#undef OP_CC
#undef OP_SHIFTD
#undef OP_NOBYTE
#undef EXECSHIFT
+104
View File
@@ -0,0 +1,104 @@
.code16
.globl vm86_code_start
.globl vm86_code_end
#define GET_OFFSET(x) ((x) - vm86_code_start + 0x100)
vm86_code_start:
movw $GET_OFFSET(hello_world), %dx
movb $0x09, %ah
int $0x21
/* prepare int 0x90 vector */
xorw %ax, %ax
movw %ax, %es
es movw $GET_OFFSET(int90_test), 0x90 * 4
es movw %cs, 0x90 * 4 + 2
/* launch int 0x90 */
int $0x90
/* test IF support */
movw $GET_OFFSET(IF_msg), %dx
movb $0x09, %ah
int $0x21
pushf
popw %dx
movb $0xff, %ah
int $0x21
cli
pushf
popw %dx
movb $0xff, %ah
int $0x21
sti
pushfl
popl %edx
movb $0xff, %ah
int $0x21
#if 0
movw $GET_OFFSET(IF_msg1), %dx
movb $0x09, %ah
int $0x21
pushf
movw %sp, %bx
andw $~0x200, (%bx)
popf
#else
cli
#endif
pushf
popw %dx
movb $0xff, %ah
int $0x21
pushfl
movw %sp, %bx
orw $0x200, (%bx)
popfl
pushfl
popl %edx
movb $0xff, %ah
int $0x21
movb $0x00, %ah
int $0x21
int90_test:
pushf
pop %dx
movb $0xff, %ah
int $0x21
movw %sp, %bx
movw 4(%bx), %dx
movb $0xff, %ah
int $0x21
movw $GET_OFFSET(int90_msg), %dx
movb $0x09, %ah
int $0x21
iret
int90_msg:
.string "INT90 started\n$"
hello_world:
.string "Hello VM86 world\n$"
IF_msg:
.string "VM86 IF test\n$"
IF_msg1:
.string "If you see a diff here, your Linux kernel is buggy, please update to 2.4.20 kernel\n$"
vm86_code_end:
+1291
View File
File diff suppressed because it is too large Load Diff
+131
View File
@@ -0,0 +1,131 @@
#define exec_op glue(exec_, OP)
#define exec_opl glue(glue(exec_, OP), l)
#define exec_opw glue(glue(exec_, OP), w)
#define exec_opb glue(glue(exec_, OP), b)
#define EXECOP2(size, res, s1, flags) \
asm ("push %4\n\t"\
"popf\n\t"\
stringify(OP) size " %" size "2, %" size "0\n\t" \
"pushf\n\t"\
"popl %1\n\t"\
: "=q" (res), "=g" (flags)\
: "q" (s1), "0" (res), "1" (flags));
#define EXECOP1(size, res, flags) \
asm ("push %3\n\t"\
"popf\n\t"\
stringify(OP) size " %" size "0\n\t" \
"pushf\n\t"\
"popl %1\n\t"\
: "=q" (res), "=g" (flags)\
: "0" (res), "1" (flags));
#ifdef OP1
void exec_opl(int s0, int s1, int iflags)
{
int res, flags;
res = s0;
flags = iflags;
EXECOP1("", res, flags);
printf("%-10s A=%08x R=%08x CCIN=%04x CC=%04x\n",
stringify(OP) "l", s0, res, iflags, flags & CC_MASK);
}
void exec_opw(int s0, int s1, int iflags)
{
int res, flags;
res = s0;
flags = iflags;
EXECOP1("w", res, flags);
printf("%-10s A=%08x R=%08x CCIN=%04x CC=%04x\n",
stringify(OP) "w", s0, res, iflags, flags & CC_MASK);
}
void exec_opb(int s0, int s1, int iflags)
{
int res, flags;
res = s0;
flags = iflags;
EXECOP1("b", res, flags);
printf("%-10s A=%08x R=%08x CCIN=%04x CC=%04x\n",
stringify(OP) "b", s0, res, iflags, flags & CC_MASK);
}
#else
void exec_opl(int s0, int s1, int iflags)
{
int res, flags;
res = s0;
flags = iflags;
EXECOP2("", res, s1, flags);
printf("%-10s A=%08x B=%08x R=%08x CCIN=%04x CC=%04x\n",
stringify(OP) "l", s0, s1, res, iflags, flags & CC_MASK);
}
void exec_opw(int s0, int s1, int iflags)
{
int res, flags;
res = s0;
flags = iflags;
EXECOP2("w", res, s1, flags);
printf("%-10s A=%08x B=%08x R=%08x CCIN=%04x CC=%04x\n",
stringify(OP) "w", s0, s1, res, iflags, flags & CC_MASK);
}
void exec_opb(int s0, int s1, int iflags)
{
int res, flags;
res = s0;
flags = iflags;
EXECOP2("b", res, s1, flags);
printf("%-10s A=%08x B=%08x R=%08x CCIN=%04x CC=%04x\n",
stringify(OP) "b", s0, s1, res, iflags, flags & CC_MASK);
}
#endif
void exec_op(int s0, int s1)
{
exec_opl(s0, s1, 0);
exec_opw(s0, s1, 0);
exec_opb(s0, s1, 0);
#ifdef OP_CC
exec_opl(s0, s1, CC_C);
exec_opw(s0, s1, CC_C);
exec_opb(s0, s1, CC_C);
#endif
}
void glue(test_, OP)(void)
{
exec_op(0x12345678, 0x812FADA);
exec_op(0x12341, 0x12341);
exec_op(0x12341, -0x12341);
exec_op(0xffffffff, 0);
exec_op(0xffffffff, -1);
exec_op(0xffffffff, 1);
exec_op(0xffffffff, 2);
exec_op(0x7fffffff, 0);
exec_op(0x7fffffff, 1);
exec_op(0x7fffffff, -1);
exec_op(0x80000000, -1);
exec_op(0x80000000, 1);
exec_op(0x80000000, -2);
exec_op(0x12347fff, 0);
exec_op(0x12347fff, 1);
exec_op(0x12347fff, -1);
exec_op(0x12348000, -1);
exec_op(0x12348000, 1);
exec_op(0x12348000, -2);
exec_op(0x12347f7f, 0);
exec_op(0x12347f7f, 1);
exec_op(0x12347f7f, -1);
exec_op(0x12348080, -1);
exec_op(0x12348080, 1);
exec_op(0x12348080, -2);
}
void *glue(_test_, OP) __init_call = glue(test_, OP);
#undef OP
#undef OP_CC
+152
View File
@@ -0,0 +1,152 @@
/* Test path override code */
#define _GNU_SOURCE
#include "../path.c"
#include <stdarg.h>
#include <sys/stat.h>
#include <fcntl.h>
/* Any log message kills the test. */
void gemu_log(const char *fmt, ...)
{
va_list ap;
fprintf(stderr, "FATAL: ");
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
exit(1);
}
#define NO_CHANGE(_path) \
do { \
if (strcmp(path(_path), _path) != 0) return __LINE__; \
} while(0)
#define CHANGE_TO(_path, _newpath) \
do { \
if (strcmp(path(_path), _newpath) != 0) return __LINE__; \
} while(0)
static void cleanup(void)
{
unlink("/tmp/qemu-test_path/DIR1/DIR2/FILE");
unlink("/tmp/qemu-test_path/DIR1/DIR2/FILE2");
unlink("/tmp/qemu-test_path/DIR1/DIR2/FILE3");
unlink("/tmp/qemu-test_path/DIR1/DIR2/FILE4");
unlink("/tmp/qemu-test_path/DIR1/DIR2/FILE5");
rmdir("/tmp/qemu-test_path/DIR1/DIR2");
rmdir("/tmp/qemu-test_path/DIR1/DIR3");
rmdir("/tmp/qemu-test_path/DIR1");
rmdir("/tmp/qemu-test_path");
}
static unsigned int do_test(void)
{
if (mkdir("/tmp/qemu-test_path", 0700) != 0)
return __LINE__;
if (mkdir("/tmp/qemu-test_path/DIR1", 0700) != 0)
return __LINE__;
if (mkdir("/tmp/qemu-test_path/DIR1/DIR2", 0700) != 0)
return __LINE__;
if (mkdir("/tmp/qemu-test_path/DIR1/DIR3", 0700) != 0)
return __LINE__;
if (close(creat("/tmp/qemu-test_path/DIR1/DIR2/FILE", 0600)) != 0)
return __LINE__;
if (close(creat("/tmp/qemu-test_path/DIR1/DIR2/FILE2", 0600)) != 0)
return __LINE__;
if (close(creat("/tmp/qemu-test_path/DIR1/DIR2/FILE3", 0600)) != 0)
return __LINE__;
if (close(creat("/tmp/qemu-test_path/DIR1/DIR2/FILE4", 0600)) != 0)
return __LINE__;
if (close(creat("/tmp/qemu-test_path/DIR1/DIR2/FILE5", 0600)) != 0)
return __LINE__;
init_paths("/tmp/qemu-test_path");
NO_CHANGE("/tmp");
NO_CHANGE("/tmp/");
NO_CHANGE("/tmp/qemu-test_path");
NO_CHANGE("/tmp/qemu-test_path/");
NO_CHANGE("/tmp/qemu-test_path/D");
NO_CHANGE("/tmp/qemu-test_path/DI");
NO_CHANGE("/tmp/qemu-test_path/DIR");
NO_CHANGE("/tmp/qemu-test_path/DIR1");
NO_CHANGE("/tmp/qemu-test_path/DIR1/");
NO_CHANGE("/D");
NO_CHANGE("/DI");
NO_CHANGE("/DIR");
NO_CHANGE("/DIR2");
NO_CHANGE("/DIR1.");
CHANGE_TO("/DIR1", "/tmp/qemu-test_path/DIR1");
CHANGE_TO("/DIR1/", "/tmp/qemu-test_path/DIR1");
NO_CHANGE("/DIR1/D");
NO_CHANGE("/DIR1/DI");
NO_CHANGE("/DIR1/DIR");
NO_CHANGE("/DIR1/DIR1");
CHANGE_TO("/DIR1/DIR2", "/tmp/qemu-test_path/DIR1/DIR2");
CHANGE_TO("/DIR1/DIR2/", "/tmp/qemu-test_path/DIR1/DIR2");
CHANGE_TO("/DIR1/DIR3", "/tmp/qemu-test_path/DIR1/DIR3");
CHANGE_TO("/DIR1/DIR3/", "/tmp/qemu-test_path/DIR1/DIR3");
NO_CHANGE("/DIR1/DIR2/F");
NO_CHANGE("/DIR1/DIR2/FI");
NO_CHANGE("/DIR1/DIR2/FIL");
NO_CHANGE("/DIR1/DIR2/FIL.");
CHANGE_TO("/DIR1/DIR2/FILE", "/tmp/qemu-test_path/DIR1/DIR2/FILE");
CHANGE_TO("/DIR1/DIR2/FILE2", "/tmp/qemu-test_path/DIR1/DIR2/FILE2");
CHANGE_TO("/DIR1/DIR2/FILE3", "/tmp/qemu-test_path/DIR1/DIR2/FILE3");
CHANGE_TO("/DIR1/DIR2/FILE4", "/tmp/qemu-test_path/DIR1/DIR2/FILE4");
CHANGE_TO("/DIR1/DIR2/FILE5", "/tmp/qemu-test_path/DIR1/DIR2/FILE5");
NO_CHANGE("/DIR1/DIR2/FILE6");
NO_CHANGE("/DIR1/DIR2/FILE/X");
CHANGE_TO("/DIR1/../DIR1", "/tmp/qemu-test_path/DIR1");
CHANGE_TO("/DIR1/../DIR1/", "/tmp/qemu-test_path/DIR1");
CHANGE_TO("/../DIR1", "/tmp/qemu-test_path/DIR1");
CHANGE_TO("/../DIR1/", "/tmp/qemu-test_path/DIR1");
CHANGE_TO("/DIR1/DIR2/../DIR2", "/tmp/qemu-test_path/DIR1/DIR2");
CHANGE_TO("/DIR1/DIR2/../DIR2/../../DIR1/DIR2/FILE", "/tmp/qemu-test_path/DIR1/DIR2/FILE");
CHANGE_TO("/DIR1/DIR2/../DIR2/FILE", "/tmp/qemu-test_path/DIR1/DIR2/FILE");
NO_CHANGE("/DIR1/DIR2/../DIR1");
NO_CHANGE("/DIR1/DIR2/../FILE");
CHANGE_TO("/./DIR1/DIR2/FILE", "/tmp/qemu-test_path/DIR1/DIR2/FILE");
CHANGE_TO("/././DIR1/DIR2/FILE", "/tmp/qemu-test_path/DIR1/DIR2/FILE");
CHANGE_TO("/DIR1/./DIR2/FILE", "/tmp/qemu-test_path/DIR1/DIR2/FILE");
CHANGE_TO("/DIR1/././DIR2/FILE", "/tmp/qemu-test_path/DIR1/DIR2/FILE");
CHANGE_TO("/DIR1/DIR2/./FILE", "/tmp/qemu-test_path/DIR1/DIR2/FILE");
CHANGE_TO("/DIR1/DIR2/././FILE", "/tmp/qemu-test_path/DIR1/DIR2/FILE");
CHANGE_TO("/./DIR1/./DIR2/./FILE", "/tmp/qemu-test_path/DIR1/DIR2/FILE");
return 0;
}
int main(int argc, char *argv[])
{
int ret;
ret = do_test();
cleanup();
if (ret) {
fprintf(stderr, "test_path: failed on line %i\n", ret);
return 1;
}
return 0;
}
+62
View File
@@ -0,0 +1,62 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <unistd.h>
#include <inttypes.h>
#include <pthread.h>
#include <sys/wait.h>
#include <sched.h>
int thread1_func(void *arg)
{
int i;
char buf[512];
for(i=0;i<10;i++) {
snprintf(buf, sizeof(buf), "thread1: %d %s\n", i, (char *)arg);
write(1, buf, strlen(buf));
usleep(100 * 1000);
}
return 0;
}
int thread2_func(void *arg)
{
int i;
char buf[512];
for(i=0;i<20;i++) {
snprintf(buf, sizeof(buf), "thread2: %d %s\n", i, (char *)arg);
write(1, buf, strlen(buf));
usleep(120 * 1000);
}
return 0;
}
#define STACK_SIZE 16384
void test_clone(void)
{
uint8_t *stack1, *stack2;
int pid1, pid2, status1, status2;
stack1 = malloc(STACK_SIZE);
pid1 = clone(thread1_func, stack1 + STACK_SIZE,
CLONE_VM | CLONE_FS | CLONE_FILES | SIGCHLD, "hello1");
stack2 = malloc(STACK_SIZE);
pid2 = clone(thread2_func, stack2 + STACK_SIZE,
CLONE_VM | CLONE_FS | CLONE_FILES | SIGCHLD, "hello2");
while (waitpid(pid1, &status1, 0) != pid1);
while (waitpid(pid2, &status2, 0) != pid2);
printf("status1=0x%x\n", status1);
printf("status2=0x%x\n", status2);
printf("End of clone test.\n");
}
int main(int argc, char **argv)
{
test_clone();
return 0;
}
+194
View File
@@ -0,0 +1,194 @@
#define _GNU_SOURCE
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <unistd.h>
#include <setjmp.h>
#include <sys/ucontext.h>
jmp_buf jmp_env;
void alarm_handler(int sig)
{
printf("alarm signal=%d\n", sig);
alarm(1);
}
#ifndef REG_EAX
#define REG_EAX EAX
#define REG_EBX EBX
#define REG_ECX ECX
#define REG_EDX EDX
#define REG_ESI ESI
#define REG_EDI EDI
#define REG_EBP EBP
#define REG_ESP ESP
#define REG_EIP EIP
#define REG_EFL EFL
#define REG_TRAPNO TRAPNO
#define REG_ERR ERR
#endif
void dump_regs(struct ucontext *uc)
{
printf("EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n"
"ESI=%08x EDI=%08x EBP=%08x ESP=%08x\n"
"EFL=%08x EIP=%08x trapno=%02x err=%08x\n",
uc->uc_mcontext.gregs[REG_EAX],
uc->uc_mcontext.gregs[REG_EBX],
uc->uc_mcontext.gregs[REG_ECX],
uc->uc_mcontext.gregs[REG_EDX],
uc->uc_mcontext.gregs[REG_ESI],
uc->uc_mcontext.gregs[REG_EDI],
uc->uc_mcontext.gregs[REG_EBP],
uc->uc_mcontext.gregs[REG_ESP],
uc->uc_mcontext.gregs[REG_EFL],
uc->uc_mcontext.gregs[REG_EIP],
uc->uc_mcontext.gregs[REG_TRAPNO],
uc->uc_mcontext.gregs[REG_ERR]);
}
void sig_handler(int sig, siginfo_t *info, void *puc)
{
struct ucontext *uc = puc;
printf("%s: si_signo=%d si_errno=%d si_code=%d si_addr=0x%08lx\n",
strsignal(info->si_signo),
info->si_signo, info->si_errno, info->si_code,
(unsigned long)info->si_addr);
dump_regs(uc);
longjmp(jmp_env, 1);
}
int v1;
int tab[2];
int main(int argc, char **argv)
{
struct sigaction act;
volatile int val;
act.sa_sigaction = sig_handler;
sigemptyset(&act.sa_mask);
act.sa_flags = SA_SIGINFO;
sigaction(SIGFPE, &act, NULL);
sigaction(SIGILL, &act, NULL);
sigaction(SIGSEGV, &act, NULL);
sigaction(SIGTRAP, &act, NULL);
/* test division by zero reporting */
if (setjmp(jmp_env) == 0) {
/* now divide by zero */
v1 = 0;
v1 = 2 / v1;
}
/* test illegal instruction reporting */
if (setjmp(jmp_env) == 0) {
/* now execute an invalid instruction */
asm volatile("ud2");
}
/* test SEGV reporting */
if (setjmp(jmp_env) == 0) {
/* now store in an invalid address */
*(char *)0x1234 = 1;
}
/* test SEGV reporting */
if (setjmp(jmp_env) == 0) {
/* read from an invalid address */
v1 = *(char *)0x1234;
}
printf("segment GPF exception:\n");
if (setjmp(jmp_env) == 0) {
/* load an invalid segment */
asm volatile ("movl %0, %%fs" : : "r" ((0x1234 << 3) | 0));
}
printf("INT exception:\n");
if (setjmp(jmp_env) == 0) {
asm volatile ("int $0xfd");
}
printf("INT3 exception:\n");
if (setjmp(jmp_env) == 0) {
asm volatile ("int3");
}
printf("CLI exception:\n");
if (setjmp(jmp_env) == 0) {
asm volatile ("cli");
}
printf("STI exception:\n");
if (setjmp(jmp_env) == 0) {
asm volatile ("cli");
}
printf("INTO exception:\n");
if (setjmp(jmp_env) == 0) {
/* overflow exception */
asm volatile ("addl $1, %0 ; into" : : "r" (0x7fffffff));
}
printf("BOUND exception:\n");
if (setjmp(jmp_env) == 0) {
/* bound exception */
tab[0] = 1;
tab[1] = 10;
asm volatile ("bound %0, %1" : : "r" (11), "m" (tab));
}
printf("OUTB exception:\n");
if (setjmp(jmp_env) == 0) {
asm volatile ("outb %%al, %%dx" : : "d" (0x4321), "a" (0));
}
printf("INB exception:\n");
if (setjmp(jmp_env) == 0) {
asm volatile ("inb %%dx, %%al" : "=a" (val) : "d" (0x4321));
}
printf("REP OUTSB exception:\n");
if (setjmp(jmp_env) == 0) {
asm volatile ("rep outsb" : : "d" (0x4321), "S" (tab), "c" (1));
}
printf("REP INSB exception:\n");
if (setjmp(jmp_env) == 0) {
asm volatile ("rep insb" : : "d" (0x4321), "D" (tab), "c" (1));
}
printf("HLT exception:\n");
if (setjmp(jmp_env) == 0) {
asm volatile ("hlt");
}
printf("single step exception:\n");
val = 0;
if (setjmp(jmp_env) == 0) {
asm volatile ("pushf\n"
"orl $0x00100, (%%esp)\n"
"popf\n"
"movl $0xabcd, %0\n" : "=m" (val) : : "cc", "memory");
}
printf("val=0x%x\n", val);
#if 1
{
int i;
act.sa_handler = alarm_handler;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
sigaction(SIGALRM, &act, NULL);
alarm(1);
for(i = 0;i < 2; i++) {
sleep(1);
}
}
#endif
return 0;
}
+51
View File
@@ -0,0 +1,51 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <unistd.h>
#include <inttypes.h>
#include <pthread.h>
#include <sys/wait.h>
#include <sched.h>
void *thread1_func(void *arg)
{
int i;
char buf[512];
for(i=0;i<10;i++) {
snprintf(buf, sizeof(buf), "thread1: %d %s\n", i, (char *)arg);
write(1, buf, strlen(buf));
usleep(100 * 1000);
}
return NULL;
}
void *thread2_func(void *arg)
{
int i;
char buf[512];
for(i=0;i<20;i++) {
snprintf(buf, sizeof(buf), "thread2: %d %s\n", i, (char *)arg);
write(1, buf, strlen(buf));
usleep(150 * 1000);
}
return NULL;
}
void test_pthread(void)
{
pthread_t tid1, tid2;
pthread_create(&tid1, NULL, thread1_func, "hello1");
pthread_create(&tid2, NULL, thread2_func, "hello2");
pthread_join(tid1, NULL);
pthread_join(tid2, NULL);
printf("End of pthread test.\n");
}
int main(int argc, char **argv)
{
test_pthread();
return 0;
}
+13 -13
View File
@@ -3,25 +3,25 @@
*
* Copyright (c) 2003 Fabrice Bellard
*
* 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 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 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.
* 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 General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
* 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 <stdarg.h>
#include "gemu.h"
#include "qemu.h"
#include "thunk.h"
//#define DEBUG
@@ -218,7 +218,7 @@ const argtype *thunk_convert(void *dst, const void *src,
case TYPE_LONG:
case TYPE_ULONG:
case TYPE_PTRVOID:
if (target_to_host) {
if (to_host) {
*(uint64_t *)dst = tswap32(*(uint32_t *)src);
} else {
*(uint32_t *)dst = tswap32(*(uint64_t *)src & 0xffffffff);
+67 -15
View File
@@ -1,24 +1,76 @@
/*
* Generic thunking code to convert data between host and target CPU
*
* 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 THUNK_H
#define THUNK_H
#include <inttypes.h>
#include "config.h"
#ifdef HAVE_BYTESWAP_H
#include <byteswap.h>
#else
#define bswap_16(x) \
({ \
uint16_t __x = (x); \
((uint16_t)( \
(((uint16_t)(__x) & (uint16_t)0x00ffU) << 8) | \
(((uint16_t)(__x) & (uint16_t)0xff00U) >> 8) )); \
})
#define bswap_32(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 bswap_64(x) \
({ \
uint64_t __x = (x); \
((uint64_t)( \
(uint64_t)(((uint64_t)(__x) & (uint64_t)0x00000000000000ffULL) << 56) | \
(uint64_t)(((uint64_t)(__x) & (uint64_t)0x000000000000ff00ULL) << 40) | \
(uint64_t)(((uint64_t)(__x) & (uint64_t)0x0000000000ff0000ULL) << 24) | \
(uint64_t)(((uint64_t)(__x) & (uint64_t)0x00000000ff000000ULL) << 8) | \
(uint64_t)(((uint64_t)(__x) & (uint64_t)0x000000ff00000000ULL) >> 8) | \
(uint64_t)(((uint64_t)(__x) & (uint64_t)0x0000ff0000000000ULL) >> 24) | \
(uint64_t)(((uint64_t)(__x) & (uint64_t)0x00ff000000000000ULL) >> 40) | \
(uint64_t)(((uint64_t)(__x) & (uint64_t)0xff00000000000000ULL) >> 56) )); \
})
#undef WORDS_BIGENDIAN
#if __BYTE_ORDER == __BIG_ENDIAN
#define WORDS_BIGENDIAN
#endif
#ifdef WORD_BIGENDIAN
#ifdef WORDS_BIGENDIAN
#define BSWAP_NEEDED
#endif
/* XXX: auto autoconf */
/* XXX: autoconf */
#define TARGET_I386
#define TARGET_LONG_BITS 32
#if defined(__alpha__)
#if defined(__alpha__) || defined (__ia64__)
#define HOST_LONG_BITS 64
#else
#define HOST_LONG_BITS 32
@@ -42,17 +94,17 @@ static inline uint64_t bswap64(uint64_t x)
return bswap_64(x);
}
static void inline bswap16s(uint16_t *s)
static inline void bswap16s(uint16_t *s)
{
*s = bswap16(*s);
}
static void inline bswap32s(uint32_t *s)
static inline void bswap32s(uint32_t *s)
{
*s = bswap32(*s);
}
static void inline bswap64s(uint64_t *s)
static inline void bswap64s(uint64_t *s)
{
*s = bswap64(*s);
}
@@ -74,17 +126,17 @@ static inline uint64_t tswap64(uint64_t s)
return bswap64(s);
}
static void inline tswap16s(uint16_t *s)
static inline void tswap16s(uint16_t *s)
{
*s = bswap16(*s);
}
static void inline tswap32s(uint32_t *s)
static inline void tswap32s(uint32_t *s)
{
*s = bswap32(*s);
}
static void inline tswap64s(uint64_t *s)
static inline void tswap64s(uint64_t *s)
{
*s = bswap64(*s);
}
@@ -106,15 +158,15 @@ static inline uint64_t tswap64(uint64_t s)
return s;
}
static void inline tswap16s(uint16_t *s)
static inline void tswap16s(uint16_t *s)
{
}
static void inline tswap32s(uint32_t *s)
static inline void tswap32s(uint32_t *s)
{
}
static void inline tswap64s(uint64_t *s)
static inline void tswap64s(uint64_t *s)
{
}
+4048
View File
File diff suppressed because it is too large Load Diff