Compare commits

...

100 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
48 changed files with 10676 additions and 2035 deletions

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!

View File

@@ -1,3 +1,25 @@
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

View File

@@ -13,11 +13,15 @@ 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
ifeq ($(ARCH),ppc)
OP_CFLAGS=$(CFLAGS)
@@ -29,6 +33,31 @@ OP_CFLAGS=$(CFLAGS)
LDFLAGS+=-Wl,-T,s390.ld
endif
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
@@ -45,18 +74,34 @@ LDFLAGS+=-p
main.o: CFLAGS+=-p
endif
OBJS= elfload.o main.o syscall.o signal.o path.o
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
LIBOBJS+=thunk.o translate-i386.o op-i386.o exec-i386.o exec.o
# NOTE: the disassembler code is only needed for debugging
LIBOBJS+=i386-dis.o dis-buf.o
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
@@ -70,11 +115,14 @@ libqemu.a: $(LIBOBJS)
dyngen: dyngen.c
$(HOST_CC) -O2 -Wall -g $< -o $@
translate-i386.o: translate-i386.c op-i386.h cpu-i386.h
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 $@ $<
@@ -96,7 +144,7 @@ test speed: qemu
make -C tests $@
TAGS:
etags *.[ch] i386/*.[ch]
etags *.[ch] tests/*.[ch]
# documentation
qemu-doc.html: qemu-doc.texi
@@ -106,11 +154,11 @@ 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\
cpu-i386.h qemu.h op-i386.c opc-i386.h syscall-i386.h translate-i386.c\
dis-asm.h gen-i386.h syscall.c\
dis-buf.c i386-dis.c opreg_template.h syscall_defs.h\
ppc.ld s390.ld exec-i386.h exec-i386.c path.c configure \
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\

16
README.distrib Normal file
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

30
TODO
View File

@@ -1,12 +1,22 @@
- fix thread locks
- optimize translated cache chaining (DLL PLT-like system)
- fix thread stack liberation (use kernel 2.5.xxx CLONE_CHILD_CLEARTID)
- fix x86 stack allocation
- fix iret/lret restarting
- 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)
- finish signal handing (fp87 state, more siginfo conversions)
- verify thread support (clone() and various locks)
- make it self runnable (handle self modifying code, relocate stack
and dyn loader)
- fix FPU exceptions (in particular: gen_op_fpush not before mem load)
- 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

View File

@@ -1 +1 @@
0.1.6
0.2

1976
alpha-dis.c Normal file

File diff suppressed because it is too large Load Diff

128
alpha.ld Normal file
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 . */
}

44
configure vendored
View File

@@ -26,6 +26,7 @@ host_cc="gcc"
ar="ar"
make="make"
strip="strip"
target_cpu="x86"
cpu=`uname -m`
case "$cpu" in
i386|i486|i586|i686|i86pc|BePC)
@@ -46,6 +47,15 @@ case "$cpu" in
s390)
cpu="s390"
;;
sparc)
cpu="sparc"
;;
sparc64)
cpu="sparc64"
;;
ia64)
cpu="ia64"
;;
*)
cpu="unknown"
;;
@@ -56,22 +66,6 @@ bigendian="no"
# OS specific
targetos=`uname -s`
case $targetos in
BeOS)
prefix="/boot/home/config"
# helps building libavcodec
CFLAGS="-O2 -DPIC"
# no need for libm, but the inet stuff
# Check for BONE
if (echo $BEINCLUDES|grep 'headers/be/bone' >/dev/null); then
extralibs="-lbind -lsocket"
else
echo "Not sure building for net_server will succeed... good luck."
extralibs="-lsocket"
fi ;;
BSD/OS)
extralibs="-lpoll -lgnugetopt -lm"
make="gmake"
;;
*) ;;
esac
@@ -143,7 +137,7 @@ fi
else
# if cross compiling, cannot launch a program, so make a static guess
if test "$cpu" = "powerpc" -o "$cpu" = "mips" -o "$cpu" = "s390" ; then
if test "$cpu" = "powerpc" -o "$cpu" = "mips" -o "$cpu" = "s390" -o "$cpu" = "sparc" -o "$cpu" = "sparc64"; then
bigendian="yes"
fi
@@ -191,8 +185,9 @@ echo "Install prefix $prefix"
echo "Source path $source_path"
echo "C compiler $cc"
echo "make $make"
echo "CPU $cpu"
echo "host CPU $cpu"
echo "Big Endian $bigendian"
echo "target CPU $target_cpu"
echo "gprof enabled $gprof"
echo "Creating config.mak and config.h"
@@ -228,6 +223,15 @@ elif test "$cpu" = "s390" ; then
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
@@ -246,10 +250,6 @@ echo "" >>config.mak
echo -n "#define QEMU_VERSION \"" >> $TMPH
head $source_path/VERSION >> $TMPH
echo "\"" >> $TMPH
if test "$network" = "yes" ; then
echo "#define CONFIG_NETWORK 1" >> $TMPH
echo "CONFIG_NETWORK=yes" >> config.mak
fi
# build tree in object directory if source path is different from current one
if test "$source_path_used" = "yes" ; then

View File

@@ -48,6 +48,23 @@
#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
@@ -163,7 +180,7 @@ typedef struct CPUX86State {
uint32_t eip;
uint32_t eflags; /* eflags register. During CPU emulation, CC
flags and DF are set to zero because they are
store elsewhere */
stored elsewhere */
/* emulator internal eflags handling */
uint32_t cc_src;
@@ -180,6 +197,12 @@ typedef struct CPUX86State {
/* 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 */
@@ -191,6 +214,8 @@ typedef struct CPUX86State {
/* exception/interrupt handling */
jmp_buf jmp_env;
int exception_index;
int error_code;
uint32_t cr2;
int interrupt_request;
/* user data */
@@ -395,12 +420,12 @@ static inline void stfq(void *ptr, double v)
#endif
#ifndef IN_OP_I386
void cpu_x86_outb(int addr, int val);
void cpu_x86_outw(int addr, int val);
void cpu_x86_outl(int addr, int val);
int cpu_x86_inb(int addr);
int cpu_x86_inw(int addr);
int cpu_x86_inl(int addr);
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);
@@ -418,17 +443,37 @@ struct siginfo;
int cpu_x86_signal_handler(int host_signum, struct siginfo *info,
void *puc);
/* internal functions */
/* 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);
#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
/* 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)
int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size,
int *gen_code_size_ptr,
uint8_t *pc_start, uint8_t *cs_base, int flags);
void cpu_x86_tblocks_init(void);
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 */

View File

@@ -320,6 +320,7 @@ 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. */

81
disas.c Normal file
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
disas.h Normal file
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 */

564
dyngen.c
View File

@@ -58,20 +58,43 @@
#define elf_check_arch(x) ((x) == EM_ALPHA)
#define ELF_USES_RELOCA
#elif defined(HOST_IA64)
#define ELF_CLASS ELFCLASS64
#define ELF_ARCH EM_IA_64
#define elf_check_arch(x) ((x) == EM_IA_64)
#define ELF_USES_RELOCA
#elif defined(HOST_SPARC)
#define ELF_CLASS ELFCLASS32
#define ELF_ARCH EM_SPARC
#define elf_check_arch(x) ((x) == EM_SPARC || (x) == EM_SPARC32PLUS)
#define ELF_USES_RELOCA
#elif defined(HOST_SPARC64)
#define ELF_CLASS ELFCLASS64
#define ELF_ARCH EM_SPARCV9
#define elf_check_arch(x) ((x) == EM_SPARCV9)
#define ELF_USES_RELOCA
#else
#error unsupported CPU - please update the code
#endif
#include "elf.h"
#if ELF_CLASS == ELFCLASS32
typedef int32_t host_long;
typedef uint32_t host_ulong;
#define swabls(x) swab32s(x)
#else
typedef int64_t host_long;
typedef uint64_t host_ulong;
#define swabls(x) swab64s(x)
#endif
#include "elf.h"
#include "thunk.h"
/* all dynamically generated functions begin with this code */
@@ -104,12 +127,6 @@ void swab64s(uint64_t *p)
*p = bswap64(*p);
}
#if ELF_CLASS == ELFCLASS32
#define swabls(x) swab32s(x)
#else
#define swabls(x) swab64s(x)
#endif
void elf_swap_ehdr(struct elfhdr *h)
{
swab16s(&h->e_type); /* Object file type */
@@ -153,7 +170,16 @@ void elf_swap_phdr(struct elf_phdr *h)
swabls(&h->p_align); /* Segment alignment */
}
/* ELF file info */
int do_swap;
struct elf_shdr *shdr;
struct elfhdr ehdr;
ElfW(Sym) *symtab;
int nb_syms;
char *strtab;
/* data section */
uint8_t *data_data;
int data_shndx;
uint16_t get16(uint16_t *p)
{
@@ -187,7 +213,7 @@ void put32(uint32_t *p, uint32_t val)
*p = val;
}
void __attribute__((noreturn)) error(const char *fmt, ...)
void __attribute__((noreturn)) __attribute__((format (printf, 1, 2))) error(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
@@ -253,28 +279,37 @@ int strstart(const char *str, const char *val, const char **ptr)
/* generate op code */
void gen_code(const char *name, host_ulong offset, host_ulong size,
FILE *outfile, uint8_t *text, ELF_RELOC *relocs, int nb_relocs, int reloc_sh_type,
ElfW(Sym) *symtab, char *strtab, int gen_switch)
int gen_switch)
{
int copy_size = 0;
uint8_t *p_start, *p_end;
host_ulong start_offset;
int nb_args, i, n;
uint8_t args_present[MAX_ARGS];
const char *sym_name, *p;
ELF_RELOC *rel;
/* compute exact size excluding return instruction */
/* Compute exact size excluding prologue and epilogue instructions.
* Increment start_offset to skip epilogue instructions, then compute
* copy_size the indicate the size of the remaining instructions (in
* bytes).
*/
p_start = text + offset;
p_end = p_start + size;
start_offset = offset;
switch(ELF_ARCH) {
case EM_386:
{
uint8_t *p;
p = p_end - 1;
if (p == p_start)
int len;
len = p_end - p_start;
if (len == 0)
error("empty code for %s", name);
if (p[0] != 0xc3)
error("ret expected at the end of %s", name);
copy_size = p - p_start;
if (p_end[-1] == 0xc3) {
len--;
} else {
error("ret or jmp expected at the end of %s", name);
}
copy_size = len;
}
break;
case EM_PPC:
@@ -295,10 +330,99 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
if (p == p_start)
error("empty code for %s", name);
if (get16((uint16_t *)p) != 0x07fe && get16((uint16_t *)p) != 0x07f4)
error("br %r14 expected at the end of %s", name);
error("br %%r14 expected at the end of %s", name);
copy_size = p - p_start;
}
break;
case EM_ALPHA:
{
uint8_t *p;
p = p_end - 4;
if (p == p_start)
error("empty code for %s", name);
if (get32((uint32_t *)p) != 0x6bfa8001)
error("ret expected at the end of %s", name);
copy_size = p - p_start;
}
break;
case EM_IA_64:
{
uint8_t *p;
p = (void *)(p_end - 4);
if (p == p_start)
error("empty code for %s", name);
/* br.ret.sptk.many b0;; */
/* 08 00 84 00 */
if (get32((uint32_t *)p) != 0x00840008)
error("br.ret.sptk.many b0;; expected at the end of %s", name);
copy_size = p - p_start;
}
break;
case EM_SPARC:
case EM_SPARC32PLUS:
{
uint32_t start_insn, end_insn1, end_insn2, skip_insn;
uint8_t *p;
p = (void *)(p_end - 8);
if (p <= p_start)
error("empty code for %s", name);
start_insn = get32((uint32_t *)(p_start + 0x0));
end_insn1 = get32((uint32_t *)(p + 0x0));
end_insn2 = get32((uint32_t *)(p + 0x4));
if ((start_insn & ~0x1fff) == 0x9de3a000) {
p_start += 0x4;
start_offset += 0x4;
if ((int)(start_insn | ~0x1fff) < -128)
error("Found bogus save at the start of %s", name);
if (end_insn1 != 0x81c7e008 || end_insn2 != 0x81e80000)
error("ret; restore; not found at end of %s", name);
} else {
error("No save at the beginning of %s", name);
}
/* Skip a preceeding nop, if present. */
if (p > p_start) {
skip_insn = get32((uint32_t *)(p - 0x4));
if (skip_insn == 0x01000000)
p -= 4;
}
copy_size = p - p_start;
}
break;
case EM_SPARCV9:
{
uint32_t start_insn, end_insn1, end_insn2, skip_insn;
uint8_t *p;
p = (void *)(p_end - 8);
if (p <= p_start)
error("empty code for %s", name);
start_insn = get32((uint32_t *)(p_start + 0x0));
end_insn1 = get32((uint32_t *)(p + 0x0));
end_insn2 = get32((uint32_t *)(p + 0x4));
if ((start_insn & ~0x1fff) == 0x9de3a000) {
p_start += 0x4;
start_offset += 0x4;
if ((int)(start_insn | ~0x1fff) < -256)
error("Found bogus save at the start of %s", name);
if (end_insn1 != 0x81c7e008 || end_insn2 != 0x81e80000)
error("ret; restore; not found at end of %s", name);
} else {
error("No save at the beginning of %s", name);
}
/* Skip a preceeding nop, if present. */
if (p > p_start) {
skip_insn = get32((uint32_t *)(p - 0x4));
if (skip_insn == 0x01000000)
p -= 4;
}
copy_size = p - p_start;
}
break;
default:
error("unknown ELF architecture");
}
/* compute the number of arguments by looking at the relocations */
@@ -306,11 +430,12 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
args_present[i] = 0;
for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
if (rel->r_offset >= offset && rel->r_offset < offset + copy_size) {
if (rel->r_offset >= start_offset &&
rel->r_offset < start_offset + copy_size) {
sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name;
if (strstart(sym_name, "__op_param", &p)) {
n = strtoul(p, NULL, 10);
if (n >= MAX_ARGS)
if (n > MAX_ARGS)
error("too many arguments in %s", name);
args_present[n - 1] = 1;
}
@@ -326,7 +451,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
}
if (gen_switch == 2) {
fprintf(outfile, "DEF(%s, %d)\n", name + 3, nb_args);
fprintf(outfile, "DEF(%s, %d, %d)\n", name + 3, nb_args, copy_size);
} else if (gen_switch == 1) {
/* output C code */
@@ -343,15 +468,51 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
fprintf(outfile, " extern void %s();\n", name);
for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
if (rel->r_offset >= offset && rel->r_offset < offset + copy_size) {
sym_name = strtab + symtab[ELF32_R_SYM(rel->r_info)].st_name;
if (!strstart(sym_name, "__op_param", &p)) {
if (rel->r_offset >= start_offset &&
rel->r_offset < start_offset + copy_size) {
sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name;
if (*sym_name &&
!strstart(sym_name, "__op_param", NULL) &&
!strstart(sym_name, "__op_jmp", NULL)) {
#if defined(HOST_SPARC)
if (sym_name[0] == '.') {
fprintf(outfile,
"extern char __dot_%s __asm__(\"%s\");\n",
sym_name+1, sym_name);
continue;
}
#endif
fprintf(outfile, "extern char %s;\n", sym_name);
}
}
}
fprintf(outfile, " memcpy(gen_code_ptr, &%s, %d);\n", name, copy_size);
fprintf(outfile, " memcpy(gen_code_ptr, (void *)((char *)&%s+%d), %d);\n", name, start_offset - offset, copy_size);
/* emit code offset information */
{
ElfW(Sym) *sym;
const char *sym_name, *p;
target_ulong val;
int n;
for(i = 0, sym = symtab; i < nb_syms; i++, sym++) {
sym_name = strtab + sym->st_name;
if (strstart(sym_name, "__op_label", &p)) {
/* test if the variable refers to a label inside
the code we are generating */
if (sym->st_shndx != data_shndx)
error("__op_labelN symbols must be in .data or .sdata section");
val = *(target_ulong *)(data_data + sym->st_value);
if (val >= start_offset && val < start_offset + copy_size) {
n = strtol(p, NULL, 10);
fprintf(outfile, " label_offsets[%d] = %d + (gen_code_ptr - gen_code_buf);\n", n, val - start_offset);
}
}
}
}
/* load parameres in variables */
for(i = 0; i < nb_args; i++) {
fprintf(outfile, " param%d = *opparam_ptr++;\n", i + 1);
}
@@ -363,8 +524,9 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
int type;
int addend;
for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
if (rel->r_offset >= offset && rel->r_offset < offset + copy_size) {
sym_name = strtab + symtab[ELF32_R_SYM(rel->r_info)].st_name;
if (rel->r_offset >= start_offset &&
rel->r_offset < start_offset + copy_size) {
sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name;
if (strstart(sym_name, "__op_param", &p)) {
snprintf(name, sizeof(name), "param%s", p);
} else {
@@ -375,11 +537,11 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
switch(type) {
case R_386_32:
fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n",
rel->r_offset - offset, name, addend);
rel->r_offset - start_offset, name, addend);
break;
case R_386_PC32:
fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s - (long)(gen_code_ptr + %d) + %d;\n",
rel->r_offset - offset, name, rel->r_offset - offset, addend);
rel->r_offset - start_offset, name, rel->r_offset - start_offset, addend);
break;
default:
error("unsupported i386 relocation (%d)", type);
@@ -393,8 +555,21 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
int type;
int addend;
for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
if (rel->r_offset >= offset && rel->r_offset < offset + copy_size) {
sym_name = strtab + symtab[ELF32_R_SYM(rel->r_info)].st_name;
if (rel->r_offset >= start_offset &&
rel->r_offset < start_offset + copy_size) {
sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name;
if (strstart(sym_name, "__op_jmp", &p)) {
int n;
n = strtol(p, NULL, 10);
/* __op_jmp relocations are done at
runtime to do translated block
chaining: the offset of the instruction
needs to be stored */
fprintf(outfile, " jmp_offsets[%d] = %d + (gen_code_ptr - gen_code_buf);\n",
n, rel->r_offset - start_offset);
continue;
}
if (strstart(sym_name, "__op_param", &p)) {
snprintf(name, sizeof(name), "param%s", p);
} else {
@@ -405,24 +580,24 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
switch(type) {
case R_PPC_ADDR32:
fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n",
rel->r_offset - offset, name, addend);
rel->r_offset - start_offset, name, addend);
break;
case R_PPC_ADDR16_LO:
fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %d) = (%s + %d);\n",
rel->r_offset - offset, name, addend);
rel->r_offset - start_offset, name, addend);
break;
case R_PPC_ADDR16_HI:
fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %d) = (%s + %d) >> 16;\n",
rel->r_offset - offset, name, addend);
rel->r_offset - start_offset, name, addend);
break;
case R_PPC_ADDR16_HA:
fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %d) = (%s + %d + 0x8000) >> 16;\n",
rel->r_offset - offset, name, addend);
rel->r_offset - start_offset, name, addend);
break;
case R_PPC_REL24:
/* warning: must be at 32 MB distancy */
fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = (*(uint32_t *)(gen_code_ptr + %d) & ~0x03fffffc) | ((%s - (long)(gen_code_ptr + %d) + %d) & 0x03fffffc);\n",
rel->r_offset - offset, rel->r_offset - offset, name, rel->r_offset - offset, addend);
rel->r_offset - start_offset, rel->r_offset - start_offset, name, rel->r_offset - start_offset, addend);
break;
default:
error("unsupported powerpc relocation (%d)", type);
@@ -436,8 +611,9 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
int type;
int addend;
for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
if (rel->r_offset >= offset && rel->r_offset < offset + copy_size) {
sym_name = strtab + symtab[ELF32_R_SYM(rel->r_info)].st_name;
if (rel->r_offset >= start_offset &&
rel->r_offset < start_offset + copy_size) {
sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name;
if (strstart(sym_name, "__op_param", &p)) {
snprintf(name, sizeof(name), "param%s", p);
} else {
@@ -448,15 +624,15 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
switch(type) {
case R_390_32:
fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n",
rel->r_offset - offset, name, addend);
rel->r_offset - start_offset, name, addend);
break;
case R_390_16:
fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %d) = %s + %d;\n",
rel->r_offset - offset, name, addend);
rel->r_offset - start_offset, name, addend);
break;
case R_390_8:
fprintf(outfile, " *(uint8_t *)(gen_code_ptr + %d) = %s + %d;\n",
rel->r_offset - offset, name, addend);
rel->r_offset - start_offset, name, addend);
break;
default:
error("unsupported s390 relocation (%d)", type);
@@ -464,6 +640,210 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
}
}
}
#elif defined(HOST_ALPHA)
{
for (i = 0, rel = relocs; i < nb_relocs; i++, rel++) {
if (rel->r_offset >= start_offset && rel->r_offset < start_offset + copy_size) {
int type;
type = ELF64_R_TYPE(rel->r_info);
sym_name = strtab + symtab[ELF64_R_SYM(rel->r_info)].st_name;
switch (type) {
case R_ALPHA_GPDISP:
/* The gp is just 32 bit, and never changes, so it's easiest to emit it
as an immediate instead of constructing it from the pv or ra. */
fprintf(outfile, " immediate_ldah(gen_code_ptr + %ld, gp);\n",
rel->r_offset - start_offset);
fprintf(outfile, " immediate_lda(gen_code_ptr + %ld, gp);\n",
rel->r_offset - start_offset + rel->r_addend);
break;
case R_ALPHA_LITUSE:
/* jsr to literal hint. Could be used to optimize to bsr. Ignore for
now, since some called functions (libc) need pv to be set up. */
break;
case R_ALPHA_HINT:
/* Branch target prediction hint. Ignore for now. Should be already
correct for in-function jumps. */
break;
case R_ALPHA_LITERAL:
/* Load a literal from the GOT relative to the gp. Since there's only a
single gp, nothing is to be done. */
break;
case R_ALPHA_GPRELHIGH:
/* Handle fake relocations against __op_param symbol. Need to emit the
high part of the immediate value instead. Other symbols need no
special treatment. */
if (strstart(sym_name, "__op_param", &p))
fprintf(outfile, " immediate_ldah(gen_code_ptr + %ld, param%s);\n",
rel->r_offset - start_offset, p);
break;
case R_ALPHA_GPRELLOW:
if (strstart(sym_name, "__op_param", &p))
fprintf(outfile, " immediate_lda(gen_code_ptr + %ld, param%s);\n",
rel->r_offset - start_offset, p);
break;
case R_ALPHA_BRSGP:
/* PC-relative jump. Tweak offset to skip the two instructions that try to
set up the gp from the pv. */
fprintf(outfile, " fix_bsr(gen_code_ptr + %ld, (uint8_t *) &%s - (gen_code_ptr + %ld) + 4);\n",
rel->r_offset - start_offset, sym_name, rel->r_offset - start_offset);
break;
default:
error("unsupported Alpha relocation (%d)", type);
}
}
}
}
#elif defined(HOST_IA64)
{
char name[256];
int type;
int addend;
for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
if (rel->r_offset >= start_offset && rel->r_offset < start_offset + copy_size) {
sym_name = strtab + symtab[ELF64_R_SYM(rel->r_info)].st_name;
if (strstart(sym_name, "__op_param", &p)) {
snprintf(name, sizeof(name), "param%s", p);
} else {
snprintf(name, sizeof(name), "(long)(&%s)", sym_name);
}
type = ELF64_R_TYPE(rel->r_info);
addend = rel->r_addend;
switch(type) {
case R_IA64_LTOFF22:
error("must implemnt R_IA64_LTOFF22 relocation");
case R_IA64_PCREL21B:
error("must implemnt R_IA64_PCREL21B relocation");
default:
error("unsupported ia64 relocation (%d)", type);
}
}
}
}
#elif defined(HOST_SPARC)
{
char name[256];
int type;
int addend;
for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
if (rel->r_offset >= start_offset &&
rel->r_offset < start_offset + copy_size) {
sym_name = strtab + symtab[ELF32_R_SYM(rel->r_info)].st_name;
if (strstart(sym_name, "__op_param", &p)) {
snprintf(name, sizeof(name), "param%s", p);
} else {
if (sym_name[0] == '.')
snprintf(name, sizeof(name),
"(long)(&__dot_%s)",
sym_name + 1);
else
snprintf(name, sizeof(name),
"(long)(&%s)", sym_name);
}
type = ELF32_R_TYPE(rel->r_info);
addend = rel->r_addend;
switch(type) {
case R_SPARC_32:
fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n",
rel->r_offset - start_offset, name, addend);
break;
case R_SPARC_HI22:
fprintf(outfile,
" *(uint32_t *)(gen_code_ptr + %d) = "
"((*(uint32_t *)(gen_code_ptr + %d)) "
" & ~0x3fffff) "
" | (((%s + %d) >> 10) & 0x3fffff);\n",
rel->r_offset - start_offset,
rel->r_offset - start_offset,
name, addend);
break;
case R_SPARC_LO10:
fprintf(outfile,
" *(uint32_t *)(gen_code_ptr + %d) = "
"((*(uint32_t *)(gen_code_ptr + %d)) "
" & ~0x3ff) "
" | ((%s + %d) & 0x3ff);\n",
rel->r_offset - start_offset,
rel->r_offset - start_offset,
name, addend);
break;
case R_SPARC_WDISP30:
fprintf(outfile,
" *(uint32_t *)(gen_code_ptr + %d) = "
"((*(uint32_t *)(gen_code_ptr + %d)) "
" & ~0x3fffffff) "
" | ((((%s + %d) - (long)(gen_code_ptr + %d))>>2) "
" & 0x3fffffff);\n",
rel->r_offset - start_offset,
rel->r_offset - start_offset,
name, addend,
rel->r_offset - start_offset);
break;
default:
error("unsupported sparc relocation (%d)", type);
}
}
}
}
#elif defined(HOST_SPARC64)
{
char name[256];
int type;
int addend;
for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
if (rel->r_offset >= start_offset &&
rel->r_offset < start_offset + copy_size) {
sym_name = strtab + symtab[ELF64_R_SYM(rel->r_info)].st_name;
if (strstart(sym_name, "__op_param", &p)) {
snprintf(name, sizeof(name), "param%s", p);
} else {
snprintf(name, sizeof(name), "(long)(&%s)", sym_name);
}
type = ELF64_R_TYPE(rel->r_info);
addend = rel->r_addend;
switch(type) {
case R_SPARC_32:
fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n",
rel->r_offset - start_offset, name, addend);
break;
case R_SPARC_HI22:
fprintf(outfile,
" *(uint32_t *)(gen_code_ptr + %d) = "
"((*(uint32_t *)(gen_code_ptr + %d)) "
" & ~0x3fffff) "
" | (((%s + %d) >> 10) & 0x3fffff);\n",
rel->r_offset - start_offset,
rel->r_offset - start_offset,
name, addend);
break;
case R_SPARC_LO10:
fprintf(outfile,
" *(uint32_t *)(gen_code_ptr + %d) = "
"((*(uint32_t *)(gen_code_ptr + %d)) "
" & ~0x3ff) "
" | ((%s + %d) & 0x3ff);\n",
rel->r_offset - start_offset,
rel->r_offset - start_offset,
name, addend);
break;
case R_SPARC_WDISP30:
fprintf(outfile,
" *(uint32_t *)(gen_code_ptr + %d) = "
"((*(uint32_t *)(gen_code_ptr + %d)) "
" & ~0x3fffffff) "
" | ((((%s + %d) - (long)(gen_code_ptr + %d))>>2) "
" & 0x3fffffff);\n",
rel->r_offset - start_offset,
rel->r_offset - start_offset,
name, addend,
rel->r_offset - start_offset);
break;
default:
error("unsupported sparc64 relocation (%d)", type);
}
}
}
}
#else
#error unsupported CPU
#endif
@@ -495,11 +875,10 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
int load_elf(const char *filename, FILE *outfile, int do_print_enum)
{
int fd;
struct elfhdr ehdr;
struct elf_shdr *sec, *shdr, *symtab_sec, *strtab_sec, *text_sec;
int i, j, nb_syms;
ElfW(Sym) *symtab, *sym;
char *shstr, *strtab;
struct elf_shdr *sec, *symtab_sec, *strtab_sec, *text_sec;
int i, j;
ElfW(Sym) *sym;
char *shstr, *data_name;
uint8_t *text;
void *relocs;
int nb_relocs, reloc_sh_type;
@@ -551,6 +930,17 @@ int load_elf(const char *filename, FILE *outfile, int do_print_enum)
error("could not find .text section");
text = load_data(fd, text_sec->sh_offset, text_sec->sh_size);
#if defined(HOST_PPC)
data_name = ".sdata";
#else
data_name = ".data";
#endif
sec = find_elf_section(shdr, ehdr.e_shnum, shstr, data_name);
if (!sec)
error("could not find %s section", data_name);
data_shndx = sec - shdr;
data_data = load_data(fd, sec->sh_offset, sec->sh_size);
/* find text relocations, if any */
nb_relocs = 0;
relocs = NULL;
@@ -564,17 +954,17 @@ int load_elf(const char *filename, FILE *outfile, int do_print_enum)
nb_relocs = sec->sh_size / sec->sh_entsize;
if (do_swap) {
if (sec->sh_type == SHT_REL) {
Elf32_Rel *rel = relocs;
ElfW(Rel) *rel = relocs;
for(j = 0, rel = relocs; j < nb_relocs; j++, rel++) {
swab32s(&rel->r_offset);
swab32s(&rel->r_info);
swabls(&rel->r_offset);
swabls(&rel->r_info);
}
} else {
Elf32_Rela *rel = relocs;
ElfW(Rela) *rel = relocs;
for(j = 0, rel = relocs; j < nb_relocs; j++, rel++) {
swab32s(&rel->r_offset);
swab32s(&rel->r_info);
swab32s(&rel->r_addend);
swabls(&rel->r_offset);
swabls(&rel->r_info);
swabls(&rel->r_addend);
}
}
}
@@ -590,7 +980,7 @@ int load_elf(const char *filename, FILE *outfile, int do_print_enum)
symtab = load_data(fd, symtab_sec->sh_offset, symtab_sec->sh_size);
strtab = load_data(fd, strtab_sec->sh_offset, strtab_sec->sh_size);
nb_syms = symtab_sec->sh_size / sizeof(Elf32_Sym);
nb_syms = symtab_sec->sh_size / sizeof(ElfW(Sym));
if (do_swap) {
for(i = 0, sym = symtab; i < nb_syms; i++, sym++) {
swab32s(&sym->st_name);
@@ -601,19 +991,40 @@ int load_elf(const char *filename, FILE *outfile, int do_print_enum)
}
if (do_print_enum) {
fprintf(outfile, "DEF(end, 0)\n");
fprintf(outfile, "DEF(end, 0, 0)\n");
for(i = 0, sym = symtab; i < nb_syms; i++, sym++) {
const char *name, *p;
name = strtab + sym->st_name;
if (strstart(name, OP_PREFIX, &p)) {
gen_code(name, sym->st_value, sym->st_size, outfile,
text, relocs, nb_relocs, reloc_sh_type, symtab, strtab, 2);
text, relocs, nb_relocs, reloc_sh_type, 2);
}
}
} else {
/* generate big code generation switch */
#ifdef HOST_ALPHA
fprintf(outfile,
"register int gp asm(\"$29\");\n"
"static inline void immediate_ldah(void *p, int val) {\n"
" uint32_t *dest = p;\n"
" long high = ((val >> 16) + ((val >> 15) & 1)) & 0xffff;\n"
"\n"
" *dest &= ~0xffff;\n"
" *dest |= high;\n"
" *dest |= 31 << 16;\n"
"}\n"
"static inline void immediate_lda(void *dest, int val) {\n"
" *(uint16_t *) dest = val;\n"
"}\n"
"void fix_bsr(void *p, int offset) {\n"
" uint32_t *dest = p;\n"
" *dest &= ~((1 << 21) - 1);\n"
" *dest |= (offset >> 2) & ((1 << 21) - 1);\n"
"}\n");
#endif
fprintf(outfile,
"int dyngen_code(uint8_t *gen_code_buf,\n"
" uint16_t *label_offsets, uint16_t *jmp_offsets,\n"
" const uint16_t *opc_buf, const uint32_t *opparam_buf)\n"
"{\n"
" uint8_t *gen_code_ptr;\n"
@@ -621,7 +1032,22 @@ fprintf(outfile,
" const uint32_t *opparam_ptr;\n"
" gen_code_ptr = gen_code_buf;\n"
" opc_ptr = opc_buf;\n"
" opparam_ptr = opparam_buf;\n"
" opparam_ptr = opparam_buf;\n");
/* Generate prologue, if needed. */
switch(ELF_ARCH) {
case EM_SPARC:
fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0x9c23a080; /* sub %%sp, 128, %%sp */\n");
fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0xbc27a080; /* sub %%fp, 128, %%fp */\n");
break;
case EM_SPARCV9:
fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0x9c23a100; /* sub %%sp, 256, %%sp */\n");
fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0xbc27a100; /* sub %%fp, 256, %%fp */\n");
break;
};
fprintf(outfile,
" for(;;) {\n"
" switch(*opc_ptr++) {\n"
);
@@ -637,7 +1063,7 @@ fprintf(outfile,
if (sym->st_shndx != (text_sec - shdr))
error("invalid section for opcode (0x%x)", sym->st_shndx);
gen_code(name, sym->st_value, sym->st_size, outfile,
text, relocs, nb_relocs, reloc_sh_type, symtab, strtab, 1);
text, relocs, nb_relocs, reloc_sh_type, 1);
}
}
@@ -649,7 +1075,7 @@ fprintf(outfile,
" the_end:\n"
);
/* generate a return */
/* generate epilogue */
switch(ELF_ARCH) {
case EM_386:
fprintf(outfile, "*gen_code_ptr++ = 0xc3; /* ret */\n");
@@ -660,6 +1086,24 @@ fprintf(outfile,
case EM_S390:
fprintf(outfile, "*((uint16_t *)gen_code_ptr)++ = 0x07fe; /* br %%r14 */\n");
break;
case EM_ALPHA:
fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0x6bfa8001; /* ret */\n");
break;
case EM_IA_64:
fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0x00840008; /* br.ret.sptk.many b0;; */\n");
break;
case EM_SPARC:
case EM_SPARC32PLUS:
fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0xbc07a080; /* add %%fp, 256, %%fp */\n");
fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0x81c62008; /* jmpl %%i0 + 8, %%g0 */\n");
fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0x9c03a080; /* add %%sp, 256, %%sp */\n");
break;
case EM_SPARCV9:
fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0x81c7e008; /* ret */\n");
fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0x81e80000; /* restore */\n");
break;
default:
error("unknown ELF architecture");
}
fprintf(outfile, "return gen_code_ptr - gen_code_buf;\n");
@@ -674,7 +1118,7 @@ fprintf(outfile,
if (sym->st_shndx != (text_sec - shdr))
error("invalid section for opcode (0x%x)", sym->st_shndx);
gen_code(name, sym->st_value, sym->st_size, outfile,
text, relocs, nb_relocs, reloc_sh_type, symtab, strtab, 0);
text, relocs, nb_relocs, reloc_sh_type, 0);
}
}
}

116
elf.h
View File

@@ -1,5 +1,5 @@
#ifndef _ELF_H
#define _ELF_H
#ifndef _QEMU_ELF_H
#define _QEMU_ELF_H
#include <inttypes.h>
@@ -767,6 +767,114 @@ typedef struct {
#define PF_HP_LAZYSWAP 0x04000000
#define PF_HP_SBP 0x08000000
/* IA-64 specific declarations. */
/* Processor specific flags for the Ehdr e_flags field. */
#define EF_IA_64_MASKOS 0x0000000f /* os-specific flags */
#define EF_IA_64_ABI64 0x00000010 /* 64-bit ABI */
#define EF_IA_64_ARCH 0xff000000 /* arch. version mask */
/* Processor specific values for the Phdr p_type field. */
#define PT_IA_64_ARCHEXT (PT_LOPROC + 0) /* arch extension bits */
#define PT_IA_64_UNWIND (PT_LOPROC + 1) /* ia64 unwind bits */
/* Processor specific flags for the Phdr p_flags field. */
#define PF_IA_64_NORECOV 0x80000000 /* spec insns w/o recovery */
/* Processor specific values for the Shdr sh_type field. */
#define SHT_IA_64_EXT (SHT_LOPROC + 0) /* extension bits */
#define SHT_IA_64_UNWIND (SHT_LOPROC + 1) /* unwind bits */
/* Processor specific flags for the Shdr sh_flags field. */
#define SHF_IA_64_SHORT 0x10000000 /* section near gp */
#define SHF_IA_64_NORECOV 0x20000000 /* spec insns w/o recovery */
/* Processor specific values for the Dyn d_tag field. */
#define DT_IA_64_PLT_RESERVE (DT_LOPROC + 0)
#define DT_IA_64_NUM 1
/* IA-64 relocations. */
#define R_IA64_NONE 0x00 /* none */
#define R_IA64_IMM14 0x21 /* symbol + addend, add imm14 */
#define R_IA64_IMM22 0x22 /* symbol + addend, add imm22 */
#define R_IA64_IMM64 0x23 /* symbol + addend, mov imm64 */
#define R_IA64_DIR32MSB 0x24 /* symbol + addend, data4 MSB */
#define R_IA64_DIR32LSB 0x25 /* symbol + addend, data4 LSB */
#define R_IA64_DIR64MSB 0x26 /* symbol + addend, data8 MSB */
#define R_IA64_DIR64LSB 0x27 /* symbol + addend, data8 LSB */
#define R_IA64_GPREL22 0x2a /* @gprel(sym + add), add imm22 */
#define R_IA64_GPREL64I 0x2b /* @gprel(sym + add), mov imm64 */
#define R_IA64_GPREL32MSB 0x2c /* @gprel(sym + add), data4 MSB */
#define R_IA64_GPREL32LSB 0x2d /* @gprel(sym + add), data4 LSB */
#define R_IA64_GPREL64MSB 0x2e /* @gprel(sym + add), data8 MSB */
#define R_IA64_GPREL64LSB 0x2f /* @gprel(sym + add), data8 LSB */
#define R_IA64_LTOFF22 0x32 /* @ltoff(sym + add), add imm22 */
#define R_IA64_LTOFF64I 0x33 /* @ltoff(sym + add), mov imm64 */
#define R_IA64_PLTOFF22 0x3a /* @pltoff(sym + add), add imm22 */
#define R_IA64_PLTOFF64I 0x3b /* @pltoff(sym + add), mov imm64 */
#define R_IA64_PLTOFF64MSB 0x3e /* @pltoff(sym + add), data8 MSB */
#define R_IA64_PLTOFF64LSB 0x3f /* @pltoff(sym + add), data8 LSB */
#define R_IA64_FPTR64I 0x43 /* @fptr(sym + add), mov imm64 */
#define R_IA64_FPTR32MSB 0x44 /* @fptr(sym + add), data4 MSB */
#define R_IA64_FPTR32LSB 0x45 /* @fptr(sym + add), data4 LSB */
#define R_IA64_FPTR64MSB 0x46 /* @fptr(sym + add), data8 MSB */
#define R_IA64_FPTR64LSB 0x47 /* @fptr(sym + add), data8 LSB */
#define R_IA64_PCREL60B 0x48 /* @pcrel(sym + add), brl */
#define R_IA64_PCREL21B 0x49 /* @pcrel(sym + add), ptb, call */
#define R_IA64_PCREL21M 0x4a /* @pcrel(sym + add), chk.s */
#define R_IA64_PCREL21F 0x4b /* @pcrel(sym + add), fchkf */
#define R_IA64_PCREL32MSB 0x4c /* @pcrel(sym + add), data4 MSB */
#define R_IA64_PCREL32LSB 0x4d /* @pcrel(sym + add), data4 LSB */
#define R_IA64_PCREL64MSB 0x4e /* @pcrel(sym + add), data8 MSB */
#define R_IA64_PCREL64LSB 0x4f /* @pcrel(sym + add), data8 LSB */
#define R_IA64_LTOFF_FPTR22 0x52 /* @ltoff(@fptr(s+a)), imm22 */
#define R_IA64_LTOFF_FPTR64I 0x53 /* @ltoff(@fptr(s+a)), imm64 */
#define R_IA64_LTOFF_FPTR32MSB 0x54 /* @ltoff(@fptr(s+a)), data4 MSB */
#define R_IA64_LTOFF_FPTR32LSB 0x55 /* @ltoff(@fptr(s+a)), data4 LSB */
#define R_IA64_LTOFF_FPTR64MSB 0x56 /* @ltoff(@fptr(s+a)), data8 MSB */
#define R_IA64_LTOFF_FPTR64LSB 0x57 /* @ltoff(@fptr(s+a)), data8 LSB */
#define R_IA64_SEGREL32MSB 0x5c /* @segrel(sym + add), data4 MSB */
#define R_IA64_SEGREL32LSB 0x5d /* @segrel(sym + add), data4 LSB */
#define R_IA64_SEGREL64MSB 0x5e /* @segrel(sym + add), data8 MSB */
#define R_IA64_SEGREL64LSB 0x5f /* @segrel(sym + add), data8 LSB */
#define R_IA64_SECREL32MSB 0x64 /* @secrel(sym + add), data4 MSB */
#define R_IA64_SECREL32LSB 0x65 /* @secrel(sym + add), data4 LSB */
#define R_IA64_SECREL64MSB 0x66 /* @secrel(sym + add), data8 MSB */
#define R_IA64_SECREL64LSB 0x67 /* @secrel(sym + add), data8 LSB */
#define R_IA64_REL32MSB 0x6c /* data 4 + REL */
#define R_IA64_REL32LSB 0x6d /* data 4 + REL */
#define R_IA64_REL64MSB 0x6e /* data 8 + REL */
#define R_IA64_REL64LSB 0x6f /* data 8 + REL */
#define R_IA64_LTV32MSB 0x74 /* symbol + addend, data4 MSB */
#define R_IA64_LTV32LSB 0x75 /* symbol + addend, data4 LSB */
#define R_IA64_LTV64MSB 0x76 /* symbol + addend, data8 MSB */
#define R_IA64_LTV64LSB 0x77 /* symbol + addend, data8 LSB */
#define R_IA64_PCREL21BI 0x79 /* @pcrel(sym + add), 21bit inst */
#define R_IA64_PCREL22 0x7a /* @pcrel(sym + add), 22bit inst */
#define R_IA64_PCREL64I 0x7b /* @pcrel(sym + add), 64bit inst */
#define R_IA64_IPLTMSB 0x80 /* dynamic reloc, imported PLT, MSB */
#define R_IA64_IPLTLSB 0x81 /* dynamic reloc, imported PLT, LSB */
#define R_IA64_COPY 0x84 /* copy relocation */
#define R_IA64_SUB 0x85 /* Addend and symbol difference */
#define R_IA64_LTOFF22X 0x86 /* LTOFF22, relaxable. */
#define R_IA64_LDXMOV 0x87 /* Use of LTOFF22X. */
#define R_IA64_TPREL14 0x91 /* @tprel(sym + add), imm14 */
#define R_IA64_TPREL22 0x92 /* @tprel(sym + add), imm22 */
#define R_IA64_TPREL64I 0x93 /* @tprel(sym + add), imm64 */
#define R_IA64_TPREL64MSB 0x96 /* @tprel(sym + add), data8 MSB */
#define R_IA64_TPREL64LSB 0x97 /* @tprel(sym + add), data8 LSB */
#define R_IA64_LTOFF_TPREL22 0x9a /* @ltoff(@tprel(s+a)), imm2 */
#define R_IA64_DTPMOD64MSB 0xa6 /* @dtpmod(sym + add), data8 MSB */
#define R_IA64_DTPMOD64LSB 0xa7 /* @dtpmod(sym + add), data8 LSB */
#define R_IA64_LTOFF_DTPMOD22 0xaa /* @ltoff(@dtpmod(sym + add)), imm22 */
#define R_IA64_DTPREL14 0xb1 /* @dtprel(sym + add), imm14 */
#define R_IA64_DTPREL22 0xb2 /* @dtprel(sym + add), imm22 */
#define R_IA64_DTPREL64I 0xb3 /* @dtprel(sym + add), imm64 */
#define R_IA64_DTPREL32MSB 0xb4 /* @dtprel(sym + add), data4 MSB */
#define R_IA64_DTPREL32LSB 0xb5 /* @dtprel(sym + add), data4 LSB */
#define R_IA64_DTPREL64MSB 0xb6 /* @dtprel(sym + add), data8 MSB */
#define R_IA64_DTPREL64LSB 0xb7 /* @dtprel(sym + add), data8 LSB */
#define R_IA64_LTOFF_DTPREL22 0xba /* @ltoff(@dtprel(s+a)), imm22 */
typedef struct elf32_rel {
Elf32_Addr r_offset;
@@ -996,6 +1104,7 @@ typedef struct elf64_note {
#define elf_phdr elf32_phdr
#define elf_note elf32_note
#define elf_shdr elf32_shdr
#define elf_sym elf32_sym
#ifdef ELF_USES_RELOCA
# define ELF_RELOC Elf32_Rela
@@ -1009,6 +1118,7 @@ typedef struct elf64_note {
#define elf_phdr elf64_phdr
#define elf_note elf64_note
#define elf_shdr elf64_shdr
#define elf_sym elf64_sym
#ifdef ELF_USES_RELOCA
# define ELF_RELOC Elf64_Rela
@@ -1029,4 +1139,4 @@ typedef struct elf64_note {
#endif
#endif /* _ELF_H */
#endif /* _QEMU_ELF_H */

View File

@@ -18,107 +18,38 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "exec-i386.h"
#include "disas.h"
//#define DEBUG_EXEC
#define DEBUG_FLUSH
//#define DEBUG_SIGNAL
/* main execution loop */
/* maximum total translate dcode allocated */
#define CODE_GEN_BUFFER_SIZE (2048 * 1024)
//#define CODE_GEN_BUFFER_SIZE (128 * 1024)
#define CODE_GEN_MAX_SIZE 65536
#define CODE_GEN_ALIGN 16 /* must be >= of the size of a icache line */
/* 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)
#define CODE_GEN_HASH_BITS 15
#define CODE_GEN_HASH_SIZE (1 << CODE_GEN_HASH_BITS)
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 */
uint8_t *tc_ptr; /* pointer to the translated code */
struct TranslationBlock *hash_next; /* next matching block */
} TranslationBlock;
TranslationBlock tbs[CODE_GEN_MAX_BLOCKS];
TranslationBlock *tb_hash[CODE_GEN_HASH_SIZE];
int nb_tbs;
uint8_t code_gen_buffer[CODE_GEN_BUFFER_SIZE];
uint8_t *code_gen_ptr;
/* thread support */
#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
int global_cpu_lock = 0;
spinlock_t global_cpu_lock = SPIN_LOCK_UNLOCKED;
void cpu_lock(void)
{
while (testandset(&global_cpu_lock));
spin_lock(&global_cpu_lock);
}
void cpu_unlock(void)
{
global_cpu_lock = 0;
spin_unlock(&global_cpu_lock);
}
/* exception support */
/* NOTE: not static to force relocation generation by GCC */
void raise_exception(int exception_index)
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
@@ -143,133 +74,9 @@ void raise_exception(int exception_index)
#ifdef reg_EDI
env->regs[R_EDI] = EDI;
#endif
env->exception_index = exception_index;
longjmp(env->jmp_env, 1);
}
#if defined(DEBUG_EXEC)
static const char *cc_op_str[] = {
"DYNAMIC",
"EFLAGS",
"MUL",
"ADDB",
"ADDW",
"ADDL",
"ADCB",
"ADCW",
"ADCL",
"SUBB",
"SUBW",
"SUBL",
"SBBB",
"SBBW",
"SBBL",
"LOGICB",
"LOGICW",
"LOGICL",
"INCB",
"INCW",
"INCL",
"DECB",
"DECW",
"DECL",
"SHLB",
"SHLW",
"SHLL",
"SARB",
"SARW",
"SARL",
};
static void cpu_x86_dump_state(FILE *f)
{
int eflags;
eflags = cc_table[CC_OP].compute_all();
eflags |= (DF & DIRECTION_FLAG);
fprintf(f,
"EAX=%08x EBX=%08X ECX=%08x EDX=%08x\n"
"ESI=%08x EDI=%08X EBP=%08x ESP=%08x\n"
"CCS=%08x CCD=%08x CCO=%-8s EFL=%c%c%c%c%c%c%c\n"
"EIP=%08x\n",
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], env->regs[R_ESP],
env->cc_src, env->cc_dst, cc_op_str[env->cc_op],
eflags & DIRECTION_FLAG ? 'D' : '-',
eflags & CC_O ? 'O' : '-',
eflags & CC_S ? 'S' : '-',
eflags & CC_Z ? 'Z' : '-',
eflags & CC_A ? 'A' : '-',
eflags & CC_P ? 'P' : '-',
eflags & CC_C ? 'C' : '-',
env->eip);
#if 1
fprintf(f, "ST0=%f ST1=%f ST2=%f ST3=%f\n",
(double)ST0, (double)ST1, (double)ST(2), (double)ST(3));
#endif
}
#endif
void cpu_x86_tblocks_init(void)
{
if (!code_gen_ptr) {
code_gen_ptr = code_gen_buffer;
}
}
/* flush all the translation blocks */
static void tb_flush(void)
{
int i;
#ifdef DEBUG_FLUSH
printf("gemu: 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;
code_gen_ptr = code_gen_buffer;
/* XXX: flush processor icache at this point */
}
/* 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 = pc & (CODE_GEN_HASH_SIZE - 1);
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;
}
/* allocate a new translation block. flush the translation buffer if
too many translation blocks or too much generated code */
static inline TranslationBlock *tb_alloc(void)
{
TranslationBlock *tb;
if (nb_tbs >= CODE_GEN_MAX_BLOCKS ||
(code_gen_ptr - code_gen_buffer) >= CODE_GEN_BUFFER_MAX_SIZE)
tb_flush();
tb = &tbs[nb_tbs++];
return tb;
}
int cpu_x86_exec(CPUX86State *env1)
{
int saved_T0, saved_T1, saved_A0;
@@ -303,7 +110,7 @@ int cpu_x86_exec(CPUX86State *env1)
TranslationBlock *tb, **ptb;
uint8_t *tc_ptr, *cs_base, *pc;
unsigned int flags;
/* first we save global registers */
saved_T0 = T0;
saved_T1 = T1;
@@ -349,16 +156,30 @@ int cpu_x86_exec(CPUX86State *env1)
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) {
raise_exception(EXCP_INTERRUPT);
env->exception_index = EXCP_INTERRUPT;
cpu_loop_exit();
}
#ifdef DEBUG_EXEC
if (loglevel) {
cpu_x86_dump_state(logfile);
/* 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
@@ -369,38 +190,76 @@ int cpu_x86_exec(CPUX86State *env1)
(unsigned long)env->seg_cache[R_ES].base |
(unsigned long)env->seg_cache[R_SS].base) != 0) <<
GEN_FLAG_ADDSEG_SHIFT;
flags |= (env->eflags & VM_MASK) >> (17 - GEN_FLAG_VM_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 */
/* XXX: very inefficient: we lock all the cpus when
generating code */
cpu_lock();
tc_ptr = code_gen_ptr;
ret = cpu_x86_gen_code(code_gen_ptr, CODE_GEN_MAX_SIZE,
&code_gen_size, pc, cs_base, flags);
/* if invalid instruction, signal it */
if (ret != 0) {
cpu_unlock();
raise_exception(EXCP06_ILLOP);
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;
}
tb = tb_alloc();
*ptb = tb;
tb->pc = (unsigned long)pc;
tc_ptr = code_gen_ptr;
tb->tc_ptr = tc_ptr;
tb->cs_base = (unsigned long)cs_base;
tb->flags = flags;
tb->tc_ptr = tc_ptr;
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));
cpu_unlock();
spin_unlock(&tb_lock);
}
/* execute the generated code */
#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;
@@ -452,7 +311,19 @@ void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector)
saved_env = env;
env = s;
load_seg(seg_reg, selector);
if (env->eflags & VM_MASK) {
SegmentCache *sc;
selector &= 0xffff;
sc = &env->seg_cache[seg_reg];
/* NOTE: in VM86 mode, limit and seg_32bit are never reloaded,
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;
}
@@ -468,23 +339,38 @@ void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector)
#include <signal.h>
#include <sys/ucontext.h>
static inline int handle_cpu_signal(unsigned long pc,
sigset_t *old_set)
/* '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)
{
#ifdef DEBUG_SIGNAL
printf("gemu: SIGSEGV pc=0x%08lx oldset=0x%08lx\n",
pc, *(unsigned long *)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
if (pc >= (unsigned long)code_gen_buffer &&
pc < (unsigned long)code_gen_buffer + CODE_GEN_BUFFER_SIZE) {
/* 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 */
do it (XXX: use sigsetjmp) */
sigprocmask(SIG_SETMASK, old_set, NULL);
/* XXX: need to compute virtual pc position by retranslating
code. The rest of the CPU state should be correct. */
raise_exception(EXCP0D_GPF);
raise_exception_err(EXCP0E_PAGE, 4 | (is_write << 1));
/* never comes here */
return 1;
} else {
@@ -492,23 +378,53 @@ static inline int handle_cpu_signal(unsigned long pc,
}
}
#if defined(__i386__)
int cpu_x86_signal_handler(int host_signum, struct siginfo *info,
void *puc)
{
#if defined(__i386__)
struct ucontext *uc = puc;
unsigned long pc;
sigset_t *pold_set;
#ifndef REG_EIP
/* for glibc 2.1 */
#define REG_EIP EIP
#define REG_EIP EIP
#define REG_ERR ERR
#define REG_TRAPNO TRAPNO
#endif
pc = uc->uc_mcontext.gregs[REG_EIP];
pold_set = &uc->uc_sigmask;
return handle_cpu_signal(pc, pold_set);
#else
#warning No CPU specific signal handler: cannot handle target SIGSEGV events
return 0;
#endif
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

View File

@@ -89,10 +89,27 @@ register unsigned int A0 asm("s2");
register struct CPUX86State *env asm("s3");
#endif
#ifdef __sparc__
register unsigned int T0 asm("l0");
register unsigned int T1 asm("l1");
register unsigned int A0 asm("l2");
register struct CPUX86State *env asm("l3");
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");
@@ -104,7 +121,19 @@ register struct CPUX86State *env asm("r10");
register unsigned int T0 asm("$9");
register unsigned int T1 asm("$10");
register unsigned int A0 asm("$11");
register struct CPUX86State *env asm("$12");
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 */
@@ -154,12 +183,32 @@ register struct CPUX86State *env asm("$12");
#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 */
@@ -168,10 +217,14 @@ typedef struct CCTable {
extern CCTable cc_table[];
void load_seg(int seg_reg, int selector);
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
exec.c Normal file
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
exec.h Normal file
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;

View File

32
ia64-syscall.S Normal file
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

View File

@@ -11,6 +11,7 @@
#include <string.h>
#include "qemu.h"
#include "disas.h"
#ifdef TARGET_I386
@@ -94,8 +95,6 @@ struct exec
#define ZMAGIC 0413
#define QMAGIC 0314
#define X86_STACK_TOP 0x7d000000
/* max code+data+bss space allocated to elf interpreter */
#define INTERP_MAP_SIZE (32 * 1024 * 1024)
@@ -122,23 +121,11 @@ struct exec
#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
@@ -159,9 +146,6 @@ static inline void memcpy_tofs(void * to, const void * from, unsigned long n)
memcpy(to, from, n);
}
//extern void * mmap4k();
#define mmap4k(a, b, c, d, e, f) mmap((void *)(a), b, c, d, e, f)
extern unsigned long x86_stack_size;
static int load_aout_interp(void * exptr, int interp_fd);
@@ -195,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)
@@ -204,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");
@@ -218,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);
}
/*
@@ -249,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;
}
@@ -367,21 +373,21 @@ unsigned long setup_arg_pages(unsigned long p, struct linux_binprm * bprm,
* it for args, we'll use it for something else...
*/
size = x86_stack_size;
if (size < MAX_ARG_PAGES*X86_PAGE_SIZE)
size = MAX_ARG_PAGES*X86_PAGE_SIZE;
error = (unsigned long)mmap4k(NULL,
size + X86_PAGE_SIZE,
PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS,
-1, 0);
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 */
mprotect((void *)(error + size), X86_PAGE_SIZE, PROT_NONE);
target_mprotect(error + size, host_page_size, PROT_NONE);
stack_base = error + size - MAX_ARG_PAGES*X86_PAGE_SIZE;
stack_base = error + size - MAX_ARG_PAGES*TARGET_PAGE_SIZE;
p += stack_base;
if (bprm->loader) {
@@ -393,10 +399,10 @@ unsigned long setup_arg_pages(unsigned long p, struct linux_binprm * bprm,
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;
}
@@ -404,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);
}
@@ -428,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;
@@ -471,7 +477,7 @@ static unsigned int * create_elf_tables(char *p, int argc, int envc,
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)(ALPHA_PAGE_SIZE));
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);
@@ -531,7 +537,7 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex,
/* 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 *)
@@ -571,9 +577,9 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex,
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 = (unsigned long)mmap4k(NULL, INTERP_MAP_SIZE,
PROT_NONE, MAP_PRIVATE | MAP_ANON,
-1, 0);
error = target_mmap(0, INTERP_MAP_SIZE,
PROT_NONE, MAP_PRIVATE | MAP_ANON,
-1, 0);
if (error == -1) {
perror("mmap");
exit(-1);
@@ -597,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 */
@@ -642,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);
@@ -656,7 +662,56 @@ 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... */
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)
@@ -670,7 +725,7 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r
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;
@@ -907,33 +962,32 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r
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 = (unsigned long)mmap4k(NULL, ET_DYN_MAP_SIZE,
PROT_NONE, MAP_PRIVATE | MAP_ANON,
-1, 0);
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 = X86_ELF_PAGESTART(error - elf_ppnt->p_vaddr);
load_bias = TARGET_ELF_PAGESTART(error - elf_ppnt->p_vaddr);
}
error = (unsigned long)mmap4k(
X86_ELF_PAGESTART(load_bias + 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)));
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) {
@@ -941,7 +995,7 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r
load_addr = elf_ppnt->p_vaddr - elf_ppnt->p_offset;
if (elf_ex.e_type == ET_DYN) {
load_bias += error -
X86_ELF_PAGESTART(load_bias + elf_ppnt->p_vaddr);
TARGET_ELF_PAGESTART(load_bias + elf_ppnt->p_vaddr);
load_addr += load_bias;
}
}
@@ -989,6 +1043,9 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r
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);
@@ -1033,8 +1090,8 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r
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
@@ -1062,7 +1119,7 @@ int elf_exec(const char * filename, char ** argv, char ** envp,
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);

View File

@@ -51,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)

View File

@@ -67,181 +67,70 @@ void gemu_log(const char *fmt, ...)
/***********************************************************/
/* CPUX86 core interface */
void cpu_x86_outb(int addr, int val)
void cpu_x86_outb(CPUX86State *env, int addr, int val)
{
fprintf(stderr, "outb: port=0x%04x, data=%02x\n", addr, val);
}
void cpu_x86_outw(int addr, int val)
void cpu_x86_outw(CPUX86State *env, int addr, int val)
{
fprintf(stderr, "outw: port=0x%04x, data=%04x\n", addr, val);
}
void cpu_x86_outl(int addr, int val)
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(int addr)
int cpu_x86_inb(CPUX86State *env, int addr)
{
fprintf(stderr, "inb: port=0x%04x\n", addr);
return 0;
}
int cpu_x86_inw(int addr)
int cpu_x86_inw(CPUX86State *env, int addr)
{
fprintf(stderr, "inw: port=0x%04x\n", addr);
return 0;
}
int cpu_x86_inl(int addr)
int cpu_x86_inl(CPUX86State *env, int addr)
{
fprintf(stderr, "inl: port=0x%04x\n", addr);
return 0;
}
void write_dt(void *ptr, unsigned long addr, unsigned long limit,
int seg32_bit)
static void write_dt(void *ptr, unsigned long addr, unsigned long limit,
int flags)
{
unsigned int e1, e2, limit_in_pages;
limit_in_pages = 0;
if (limit > 0xffff) {
limit = limit >> 12;
limit_in_pages = 1;
}
unsigned int e1, e2;
e1 = (addr << 16) | (limit & 0xffff);
e2 = ((addr >> 16) & 0xff) | (addr & 0xff000000) | (limit & 0x000f0000);
e2 |= limit_in_pages << 23; /* byte granularity */
e2 |= seg32_bit << 22; /* 32 bit segment */
e2 |= flags;
stl((uint8_t *)ptr, e1);
stl((uint8_t *)ptr + 4, e2);
}
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);
}
uint64_t gdt_table[6];
uint64_t idt_table[256];
//#define DEBUG_VM86
static inline int is_revectored(int nr, struct target_revectored_struct *bitmap)
/* only dpl matters as we do only user space emulation */
static void set_idt(int n, unsigned int dpl)
{
return (tswap32(bitmap->__map[nr >> 5]) >> (nr & 0x1f)) & 1;
set_gate(idt_table + n, 0, dpl, 0, 0);
}
static inline uint8_t *seg_to_linear(unsigned int seg, unsigned int reg)
{
return (uint8_t *)((seg << 4) + (reg & 0xffff));
}
static inline void pushw(CPUX86State *env, int val)
{
env->regs[R_ESP] = (env->regs[R_ESP] & ~0xffff) |
((env->regs[R_ESP] - 2) & 0xffff);
*(uint16_t *)seg_to_linear(env->segs[R_SS], env->regs[R_ESP]) = val;
}
static inline unsigned int get_vflags(CPUX86State *env)
{
unsigned int eflags;
eflags = env->eflags & ~(VM_MASK | RF_MASK | IF_MASK);
if (eflags & VIF_MASK)
eflags |= IF_MASK;
return eflags;
}
void save_v86_state(CPUX86State *env)
{
TaskState *ts = env->opaque;
#ifdef DEBUG_VM86
printf("save_v86_state\n");
#endif
/* 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]);
ts->target_v86->regs.eflags = tswap32(env->eflags);
/* 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
printf("return_to_32bit: ret=0x%x\n", retval);
#endif
save_v86_state(env);
env->regs[R_EAX] = retval;
}
/* 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;
if (env->segs[R_CS] == TARGET_BIOSSEG)
goto cannot_handle; /* XXX: I am not sure this is really useful */
if (is_revectored(intno, &ts->target_v86->int_revectored))
goto cannot_handle;
if (intno == 0x21 && is_revectored((env->regs[R_EAX] >> 8) & 0xff,
&ts->target_v86->int21_revectored))
goto cannot_handle;
int_ptr = (uint32_t *)(intno << 2);
segoffs = tswap32(*int_ptr);
if ((segoffs >> 16) == TARGET_BIOSSEG)
goto cannot_handle;
#ifdef DEBUG_VM86
printf("VM86: emulating int 0x%x. CS:IP=%04x:%04x\n",
intno, segoffs >> 16, segoffs & 0xffff);
#endif
/* save old state */
pushw(env, get_vflags(env));
pushw(env, env->segs[R_CS]);
pushw(env, env->eip);
/* goto interrupt handler */
env->eip = segoffs & 0xffff;
cpu_x86_load_seg(env, R_CS, segoffs >> 16);
env->eflags &= ~(VIF_MASK | TF_MASK);
return;
cannot_handle:
#ifdef DEBUG_VM86
printf("VM86: return to 32 bits int 0x%x\n", intno);
#endif
return_to_32bit(env, TARGET_VM86_INTx | (intno << 8));
}
void cpu_loop(struct CPUX86State *env)
void cpu_loop(CPUX86State *env)
{
int trapnr;
uint8_t *pc;
@@ -249,69 +138,50 @@ void cpu_loop(struct CPUX86State *env)
for(;;) {
trapnr = cpu_x86_exec(env);
pc = env->seg_cache[R_CS].base + env->eip;
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) {
#ifdef DEBUG_VM86
printf("VM86 exception %04x:%08x %02x %02x\n",
env->segs[R_CS], env->eip, pc[0], pc[1]);
#endif
/* VM86 mode */
switch(pc[0]) {
case 0xcd: /* int */
env->eip += 2;
do_int(env, pc[1]);
break;
case 0x66:
switch(pc[1]) {
case 0xfb: /* sti */
case 0x9d: /* popf */
case 0xcf: /* iret */
env->eip += 2;
return_to_32bit(env, TARGET_VM86_STI);
break;
default:
goto vm86_gpf;
}
break;
case 0xfb: /* sti */
case 0x9d: /* popf */
case 0xcf: /* iret */
env->eip++;
return_to_32bit(env, TARGET_VM86_STI);
break;
default:
vm86_gpf:
/* real VM86 GPF exception */
return_to_32bit(env, TARGET_VM86_UNKNOWN);
break;
}
handle_vm86_fault(env);
} else {
if (pc[0] == 0xcd && pc[1] == 0x80) {
/* syscall */
env->eip += 2;
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]);
} else {
/* XXX: more precise info */
info.si_signo = SIGSEGV;
info.si_errno = 0;
info.si_code = 0;
info._sifields._sigfault._addr = 0;
queue_signal(info.si_signo, &info);
}
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) {
do_int(env, trapnr);
handle_vm86_trap(env, trapnr);
} else {
/* division by zero */
info.si_signo = SIGFPE;
@@ -321,14 +191,31 @@ void cpu_loop(struct CPUX86State *env)
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) {
do_int(env, trapnr);
handle_vm86_trap(env, trapnr);
} else {
info.si_signo = SIGSEGV;
info.si_errno = 0;
info.si_code = 0;
info.si_code = TARGET_SI_KERNEL;
info._sifields._sigfault._addr = 0;
queue_signal(info.si_signo, &info);
}
@@ -344,6 +231,7 @@ void cpu_loop(struct CPUX86State *env)
/* 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();
@@ -358,13 +246,16 @@ void usage(void)
"usage: qemu [-h] [-d] [-L path] [-s size] program [arguments...]\n"
"Linux x86 emulator\n"
"\n"
"-h print this help\n"
"-d activate log (logfile=%s)\n"
"-L path set the x86 elf interpreter prefix (default=%s)\n"
"-s size set the x86 stack size in bytes (default=%ld)\n",
DEBUG_LOGFILE,
"-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);
x86_stack_size,
DEBUG_LOGFILE);
_exit(1);
}
@@ -411,6 +302,13 @@ int main(int argc, char **argv)
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();
}
@@ -438,12 +336,18 @@ int main(int argc, char **argv)
/* 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);
}
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);
@@ -458,7 +362,6 @@ int main(int argc, char **argv)
syscall_init();
signal_init();
env = cpu_x86_init();
global_env = env;
/* build Task State */
@@ -477,11 +380,40 @@ int main(int argc, char **argv)
env->regs[R_ESP] = regs->esp;
env->eip = regs->eip;
/* 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);
/* linux segment setup */
env->gdt.base = (void *)gdt_table;
env->gdt.limit = sizeof(gdt_table) - 1;
write_dt(&gdt_table[__USER_CS >> 3], 0, 0xffffffff, 1);
write_dt(&gdt_table[__USER_DS >> 3], 0, 0xffffffff, 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);

381
linux-user/mmap.c Normal file
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);
}

View File

@@ -54,6 +54,9 @@ 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;
@@ -73,7 +76,27 @@ 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 save_v86_state(CPUX86State *env);
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

View File

@@ -26,6 +26,13 @@
#include <errno.h>
#include <sys/ucontext.h>
#ifdef __ia64__
#undef uc_mcontext
#undef uc_sigmask
#undef uc_stack
#undef uc_link
#endif
#include "qemu.h"
//#define DEBUG_SIGNAL
@@ -103,7 +110,8 @@ static inline void host_to_target_siginfo_noswap(target_siginfo_t *tinfo,
tinfo->si_signo = sig;
tinfo->si_errno = 0;
tinfo->si_code = 0;
if (sig == SIGILL || sig == SIGFPE || sig == SIGSEGV || sig == SIGBUS) {
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;
@@ -124,7 +132,8 @@ static void tswap_siginfo(target_siginfo_t *tinfo,
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) {
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) {
@@ -166,7 +175,7 @@ void signal_init(void)
act.sa_flags = SA_SIGINFO;
act.sa_sigaction = host_signal_handler;
for(i = 1; i < NSIG; i++) {
sigaction(i, &act, NULL);
sigaction(i, &act, NULL);
}
memset(sigact_table, 0, sizeof(sigact_table));
@@ -520,8 +529,8 @@ setup_sigcontext(struct target_sigcontext *sc, struct target_fpstate *fpstate,
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(/*current->thread.trap_no*/ 0, &sc->trapno);
err |= __put_user(/*current->thread.error_code*/ 0, &sc->err);
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);
@@ -538,7 +547,7 @@ setup_sigcontext(struct target_sigcontext *sc, struct target_fpstate *fpstate,
#endif
/* non-iBCS2 extensions.. */
err |= __put_user(mask, &sc->oldmask);
err |= __put_user(/*current->thread.cr2*/ 0, &sc->cr2);
err |= __put_user(env->cr2, &sc->cr2);
return err;
}
@@ -781,6 +790,9 @@ long do_sigreturn(CPUX86State *env)
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++)

View File

@@ -58,16 +58,12 @@
#include <linux/hdreg.h>
#include <linux/soundcard.h>
#include <linux/dirent.h>
#include <linux/kd.h>
#include "qemu.h"
//#define DEBUG
#ifndef PAGE_SIZE
#define PAGE_SIZE 4096
#define PAGE_MASK ~(PAGE_SIZE - 1)
#endif
//#include <linux/msdos_fs.h>
#define VFAT_IOCTL_READDIR_BOTH _IOR('r', 1, struct dirent [2])
#define VFAT_IOCTL_READDIR_SHORT _IOR('r', 2, struct dirent [2])
@@ -85,7 +81,7 @@ long do_rt_sigreturn(CPUX86State *env);
#define __NR_sys_getdents64 __NR_getdents64
#define __NR_sys_rt_sigqueueinfo __NR_rt_sigqueueinfo
#ifdef __alpha__
#if defined(__alpha__) || defined (__ia64__)
#define __NR__llseek __NR_lseek
#endif
@@ -117,6 +113,7 @@ extern int setresuid(uid_t, uid_t, uid_t);
extern int getresuid(uid_t *, uid_t *, uid_t *);
extern int setresgid(gid_t, gid_t, gid_t);
extern int getresgid(gid_t *, gid_t *, gid_t *);
extern int setgroups(int, gid_t *);
static inline long get_errno(long ret)
{
@@ -151,7 +148,7 @@ static long do_brk(char *new_brk)
if (new_brk < target_original_brk)
return -ENOMEM;
brk_page = (char *)(((unsigned long)target_brk + PAGE_SIZE - 1) & PAGE_MASK);
brk_page = (char *)HOST_PAGE_ALIGN((unsigned long)target_brk);
/* If the new brk is less than this, set it and we're done... */
if (new_brk < brk_page) {
@@ -160,11 +157,10 @@ static long do_brk(char *new_brk)
}
/* We need to allocate more memory after the brk... */
new_alloc_size = ((new_brk - brk_page + 1)+(PAGE_SIZE-1)) & PAGE_MASK;
mapped_addr = get_errno((long)mmap((caddr_t)brk_page, new_alloc_size,
PROT_READ|PROT_WRITE,
MAP_ANON|MAP_FIXED|MAP_PRIVATE, 0, 0));
new_alloc_size = HOST_PAGE_ALIGN(new_brk - brk_page + 1);
mapped_addr = get_errno(target_mmap((unsigned long)brk_page, new_alloc_size,
PROT_READ|PROT_WRITE,
MAP_ANON|MAP_FIXED|MAP_PRIVATE, 0, 0));
if (is_error(mapped_addr)) {
return mapped_addr;
} else {
@@ -219,6 +215,29 @@ static inline void host_to_target_fds(target_long *target_fds,
#endif
}
static inline void host_to_target_rusage(struct target_rusage *target_rusage,
const struct rusage *rusage)
{
target_rusage->ru_utime.tv_sec = tswapl(rusage->ru_utime.tv_sec);
target_rusage->ru_utime.tv_usec = tswapl(rusage->ru_utime.tv_usec);
target_rusage->ru_stime.tv_sec = tswapl(rusage->ru_stime.tv_sec);
target_rusage->ru_stime.tv_usec = tswapl(rusage->ru_stime.tv_usec);
target_rusage->ru_maxrss = tswapl(rusage->ru_maxrss);
target_rusage->ru_ixrss = tswapl(rusage->ru_ixrss);
target_rusage->ru_idrss = tswapl(rusage->ru_idrss);
target_rusage->ru_isrss = tswapl(rusage->ru_isrss);
target_rusage->ru_minflt = tswapl(rusage->ru_minflt);
target_rusage->ru_majflt = tswapl(rusage->ru_majflt);
target_rusage->ru_nswap = tswapl(rusage->ru_nswap);
target_rusage->ru_inblock = tswapl(rusage->ru_inblock);
target_rusage->ru_oublock = tswapl(rusage->ru_oublock);
target_rusage->ru_msgsnd = tswapl(rusage->ru_msgsnd);
target_rusage->ru_msgrcv = tswapl(rusage->ru_msgrcv);
target_rusage->ru_nsignals = tswapl(rusage->ru_nsignals);
target_rusage->ru_nvcsw = tswapl(rusage->ru_nvcsw);
target_rusage->ru_nivcsw = tswapl(rusage->ru_nivcsw);
}
static inline void target_to_host_timeval(struct timeval *tv,
const struct target_timeval *target_tv)
{
@@ -1028,7 +1047,7 @@ static int write_ldt(CPUX86State *env,
0x7000;
if (!oldmode)
entry_2 |= (useable << 20);
/* Install the new entry ... */
install:
lp = (uint32_t *)(ldt_table + (ldt_info.entry_number << 3));
@@ -1056,78 +1075,6 @@ int do_modify_ldt(CPUX86State *env, int func, void *ptr, unsigned long bytecount
return ret;
}
/* vm86 emulation */
#define SAFE_MASK (0xDD5)
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 */
env->eflags = (env->eflags & ~SAFE_MASK) |
(tswap32(target_v86->regs.eflags) & SAFE_MASK) | VM_MASK;
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 */
/* now the virtual CPU is ready for vm86 execution ! */
out:
return ret;
}
/* this stack is the equivalent of the kernel stack associated with a
thread/process */
#define NEW_STACK_SIZE 8192
@@ -1163,7 +1110,11 @@ int do_fork(CPUX86State *env, unsigned int flags, unsigned long newsp)
new_env->regs[R_ESP] = newsp;
new_env->regs[R_EAX] = 0;
new_env->opaque = ts;
ret = clone(clone_func, new_stack + NEW_STACK_SIZE, flags, new_env);
#ifdef __ia64__
ret = clone2(clone_func, new_stack + NEW_STACK_SIZE, flags, new_env);
#else
ret = clone(clone_func, new_stack + NEW_STACK_SIZE, flags, new_env);
#endif
} else {
/* if no CLONE_VM, we consider it is a fork */
if ((flags & ~CSIGNAL) != 0)
@@ -1175,6 +1126,49 @@ int do_fork(CPUX86State *env, unsigned int flags, unsigned long newsp)
#endif
static long do_fcntl(int fd, int cmd, unsigned long arg)
{
struct flock fl;
struct target_flock *target_fl = (void *)arg;
long ret;
switch(cmd) {
case TARGET_F_GETLK:
ret = fcntl(fd, cmd, &fl);
if (ret == 0) {
target_fl->l_type = tswap16(fl.l_type);
target_fl->l_whence = tswap16(fl.l_whence);
target_fl->l_start = tswapl(fl.l_start);
target_fl->l_len = tswapl(fl.l_len);
target_fl->l_pid = tswapl(fl.l_pid);
}
break;
case TARGET_F_SETLK:
case TARGET_F_SETLKW:
fl.l_type = tswap16(target_fl->l_type);
fl.l_whence = tswap16(target_fl->l_whence);
fl.l_start = tswapl(target_fl->l_start);
fl.l_len = tswapl(target_fl->l_len);
fl.l_pid = tswapl(target_fl->l_pid);
ret = fcntl(fd, cmd, &fl);
break;
case TARGET_F_GETLK64:
case TARGET_F_SETLK64:
case TARGET_F_SETLKW64:
ret = -1;
errno = EINVAL;
break;
default:
ret = fcntl(fd, cmd, arg);
break;
}
return ret;
}
#define high2lowuid(x) (x)
#define high2lowgid(x) (x)
#define low2highuid(x) (x)
@@ -1209,6 +1203,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
ret = 0; /* avoid warning */
break;
case TARGET_NR_read:
page_unprotect_range((void *)arg2, arg3);
ret = get_errno(read(arg1, (void *)arg2, arg3));
break;
case TARGET_NR_write:
@@ -1414,15 +1409,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
ret = do_ioctl(arg1, arg2, arg3);
break;
case TARGET_NR_fcntl:
switch(arg2) {
case F_GETLK:
case F_SETLK:
case F_SETLKW:
goto unimplemented;
default:
ret = get_errno(fcntl(arg1, arg2, arg3));
break;
}
ret = get_errno(do_fcntl(arg1, arg2, arg3));
break;
case TARGET_NR_mpx:
goto unimplemented;
@@ -1672,7 +1659,15 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
}
break;
case TARGET_NR_getrusage:
goto unimplemented;
{
struct rusage rusage;
struct target_rusage *target_rusage = (void *)arg2;
ret = get_errno(getrusage(arg1, &rusage));
if (!is_error(ret)) {
host_to_target_rusage(target_rusage, &rusage);
}
}
break;
case TARGET_NR_gettimeofday:
{
struct target_timeval *target_tv = (void *)arg1;
@@ -1692,9 +1687,33 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
}
break;
case TARGET_NR_getgroups:
goto unimplemented;
{
int gidsetsize = arg1;
uint16_t *target_grouplist = (void *)arg2;
gid_t *grouplist;
int i;
grouplist = alloca(gidsetsize * sizeof(gid_t));
ret = get_errno(getgroups(gidsetsize, grouplist));
if (!is_error(ret)) {
for(i = 0;i < gidsetsize; i++)
target_grouplist[i] = tswap16(grouplist[i]);
}
}
break;
case TARGET_NR_setgroups:
goto unimplemented;
{
int gidsetsize = arg1;
uint16_t *target_grouplist = (void *)arg2;
gid_t *grouplist;
int i;
grouplist = alloca(gidsetsize * sizeof(gid_t));
for(i = 0;i < gidsetsize; i++)
grouplist[i] = tswap16(target_grouplist[i]);
ret = get_errno(setgroups(gidsetsize, grouplist));
}
break;
case TARGET_NR_select:
goto unimplemented;
case TARGET_NR_symlink:
@@ -1725,7 +1744,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
v4 = tswap32(vptr[3]);
v5 = tswap32(vptr[4]);
v6 = tswap32(vptr[5]);
ret = get_errno((long)mmap((void *)v1, v2, v3, v4, v5, v6));
ret = get_errno(target_mmap(v1, v2, v3, v4, v5, v6));
}
break;
#endif
@@ -1734,16 +1753,17 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
#else
case TARGET_NR_mmap:
#endif
ret = get_errno((long)mmap((void *)arg1, arg2, arg3, arg4, arg5, arg6));
ret = get_errno(target_mmap(arg1, arg2, arg3, arg4, arg5,
arg6 << TARGET_PAGE_BITS));
break;
case TARGET_NR_munmap:
ret = get_errno(munmap((void *)arg1, arg2));
ret = get_errno(target_munmap(arg1, arg2));
break;
case TARGET_NR_mprotect:
ret = get_errno(mprotect((void *)arg1, arg2, arg3));
ret = get_errno(target_mprotect(arg1, arg2, arg3));
break;
case TARGET_NR_mremap:
ret = get_errno((long)mremap((void *)arg1, arg2, arg3, arg4));
ret = get_errno(target_mremap(arg1, arg2, arg3, arg4, arg5));
break;
case TARGET_NR_msync:
ret = get_errno(msync((void *)arg1, arg2, arg3));
@@ -1898,24 +1918,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
if (status_ptr)
*status_ptr = tswap32(status);
if (target_rusage) {
target_rusage->ru_utime.tv_sec = tswapl(rusage.ru_utime.tv_sec);
target_rusage->ru_utime.tv_usec = tswapl(rusage.ru_utime.tv_usec);
target_rusage->ru_stime.tv_sec = tswapl(rusage.ru_stime.tv_sec);
target_rusage->ru_stime.tv_usec = tswapl(rusage.ru_stime.tv_usec);
target_rusage->ru_maxrss = tswapl(rusage.ru_maxrss);
target_rusage->ru_ixrss = tswapl(rusage.ru_ixrss);
target_rusage->ru_idrss = tswapl(rusage.ru_idrss);
target_rusage->ru_isrss = tswapl(rusage.ru_isrss);
target_rusage->ru_minflt = tswapl(rusage.ru_minflt);
target_rusage->ru_majflt = tswapl(rusage.ru_majflt);
target_rusage->ru_nswap = tswapl(rusage.ru_nswap);
target_rusage->ru_inblock = tswapl(rusage.ru_inblock);
target_rusage->ru_oublock = tswapl(rusage.ru_oublock);
target_rusage->ru_msgsnd = tswapl(rusage.ru_msgsnd);
target_rusage->ru_msgrcv = tswapl(rusage.ru_msgrcv);
target_rusage->ru_nsignals = tswapl(rusage.ru_nsignals);
target_rusage->ru_nvcsw = tswapl(rusage.ru_nvcsw);
target_rusage->ru_nivcsw = tswapl(rusage.ru_nivcsw);
host_to_target_rusage(target_rusage, &rusage);
}
}
}
@@ -2213,9 +2216,12 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
case TARGET_NR_prctl:
goto unimplemented;
case TARGET_NR_pread:
goto unimplemented;
page_unprotect_range((void *)arg2, arg3);
ret = get_errno(pread(arg1, (void *)arg2, arg3, arg4));
break;
case TARGET_NR_pwrite:
goto unimplemented;
ret = get_errno(pwrite(arg1, (void *)arg2, arg3, arg4));
break;
case TARGET_NR_chown:
ret = get_errno(chown((const char *)arg1, arg2, arg3));
break;
@@ -2238,7 +2244,16 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
ret = get_errno(do_fork(cpu_env, CLONE_VFORK | CLONE_VM | SIGCHLD, 0));
break;
case TARGET_NR_ugetrlimit:
goto unimplemented;
{
struct rlimit rlim;
ret = get_errno(getrlimit(arg1, &rlim));
if (!is_error(ret)) {
struct target_rlimit *target_rlim = (void *)arg2;
target_rlim->rlim_cur = tswapl(rlim.rlim_cur);
target_rlim->rlim_max = tswapl(rlim.rlim_max);
}
break;
}
case TARGET_NR_truncate64:
goto unimplemented;
case TARGET_NR_ftruncate64:
@@ -2257,7 +2272,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
struct target_stat64 *target_st = (void *)arg2;
memset(target_st, 0, sizeof(struct target_stat64));
target_st->st_dev = tswap16(st.st_dev);
target_st->st_ino = tswapl(st.st_ino);
target_st->st_ino = tswap64(st.st_ino);
#ifdef TARGET_STAT64_HAS_BROKEN_ST_INO
target_st->__st_ino = tswapl(st.st_ino);
#endif
@@ -2356,16 +2371,37 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
goto unimplemented;
#if TARGET_LONG_BITS == 32
case TARGET_NR_fcntl64:
{
struct flock64 fl;
struct target_flock64 *target_fl = (void *)arg3;
switch(arg2) {
case F_GETLK64:
ret = get_errno(fcntl(arg1, arg2, &fl));
if (ret == 0) {
target_fl->l_type = tswap16(fl.l_type);
target_fl->l_whence = tswap16(fl.l_whence);
target_fl->l_start = tswap64(fl.l_start);
target_fl->l_len = tswap64(fl.l_len);
target_fl->l_pid = tswapl(fl.l_pid);
}
break;
case F_SETLK64:
case F_SETLKW64:
goto unimplemented;
fl.l_type = tswap16(target_fl->l_type);
fl.l_whence = tswap16(target_fl->l_whence);
fl.l_start = tswap64(target_fl->l_start);
fl.l_len = tswap64(target_fl->l_len);
fl.l_pid = tswapl(target_fl->l_pid);
ret = get_errno(fcntl(arg1, arg2, &fl));
break;
default:
ret = get_errno(fcntl(arg1, arg2, arg3));
ret = get_errno(do_fcntl(arg1, arg2, arg3));
break;
}
break;
break;
}
#endif
case TARGET_NR_security:
goto unimplemented;

View File

@@ -212,6 +212,13 @@ struct target_pollfd {
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 */

View File

@@ -64,3 +64,6 @@ STRUCT(hd_geometry,
STRUCT(dirent,
TYPE_LONG, TYPE_LONG, TYPE_SHORT, MK_ARRAY(TYPE_CHAR, 256))
STRUCT(kbentry,
TYPE_CHAR, TYPE_CHAR, TYPE_SHORT)

475
linux-user/vm86.c Normal file
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;
}

506
op-i386.c
View File

@@ -364,8 +364,10 @@ void OPPROTO op_divb_AL_T0(void)
num = (EAX & 0xffff);
den = (T0 & 0xff);
if (den == 0)
if (den == 0) {
EIP = PARAM1;
raise_exception(EXCP00_DIVZ);
}
q = (num / den) & 0xff;
r = (num % den) & 0xff;
EAX = (EAX & 0xffff0000) | (r << 8) | q;
@@ -377,8 +379,10 @@ void OPPROTO op_idivb_AL_T0(void)
num = (int16_t)EAX;
den = (int8_t)T0;
if (den == 0)
if (den == 0) {
EIP = PARAM1;
raise_exception(EXCP00_DIVZ);
}
q = (num / den) & 0xff;
r = (num % den) & 0xff;
EAX = (EAX & 0xffff0000) | (r << 8) | q;
@@ -390,8 +394,10 @@ void OPPROTO op_divw_AX_T0(void)
num = (EAX & 0xffff) | ((EDX & 0xffff) << 16);
den = (T0 & 0xffff);
if (den == 0)
if (den == 0) {
EIP = PARAM1;
raise_exception(EXCP00_DIVZ);
}
q = (num / den) & 0xffff;
r = (num % den) & 0xffff;
EAX = (EAX & 0xffff0000) | q;
@@ -404,8 +410,10 @@ void OPPROTO op_idivw_AX_T0(void)
num = (EAX & 0xffff) | ((EDX & 0xffff) << 16);
den = (int16_t)T0;
if (den == 0)
if (den == 0) {
EIP = PARAM1;
raise_exception(EXCP00_DIVZ);
}
q = (num / den) & 0xffff;
r = (num % den) & 0xffff;
EAX = (EAX & 0xffff0000) | q;
@@ -435,8 +443,10 @@ void OPPROTO op_divl_EAX_T0(void)
num = EAX | ((uint64_t)EDX << 32);
den = T0;
if (den == 0)
if (den == 0) {
EIP = PARAM1;
raise_exception(EXCP00_DIVZ);
}
#ifdef BUGGY_GCC_DIV64
r = div64(&q, num, den);
#else
@@ -454,8 +464,10 @@ void OPPROTO op_idivl_EAX_T0(void)
num = EAX | ((uint64_t)EDX << 32);
den = T0;
if (den == 0)
if (den == 0) {
EIP = PARAM1;
raise_exception(EXCP00_DIVZ);
}
#ifdef BUGGY_GCC_DIV64
r = idiv64(&q, num, den);
#else
@@ -614,16 +626,109 @@ void OPPROTO op_jmp_im(void)
EIP = PARAM1;
}
void OPPROTO op_int_im(void)
#if 0
/* full interrupt support (only useful for real CPU emulation, not
finished) - I won't do it any time soon, finish it if you want ! */
void raise_interrupt(int intno, int is_int, int error_code,
unsigned int next_eip)
{
EIP = PARAM1;
raise_exception(EXCP0D_GPF);
SegmentDescriptorTable *dt;
uint8_t *ptr;
int type, dpl, cpl;
uint32_t e1, e2;
dt = &env->idt;
if (intno * 8 + 7 > dt->limit)
raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
ptr = dt->base + intno * 8;
e1 = ldl(ptr);
e2 = ldl(ptr + 4);
/* check gate type */
type = (e2 >> DESC_TYPE_SHIFT) & 0x1f;
switch(type) {
case 5: /* task gate */
case 6: /* 286 interrupt gate */
case 7: /* 286 trap gate */
case 14: /* 386 interrupt gate */
case 15: /* 386 trap gate */
break;
default:
raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
break;
}
dpl = (e2 >> DESC_DPL_SHIFT) & 3;
cpl = env->segs[R_CS] & 3;
/* check privledge if software int */
if (is_int && dpl < cpl)
raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
/* check valid bit */
if (!(e2 & DESC_P_MASK))
raise_exception_err(EXCP0B_NOSEG, intno * 8 + 2);
}
void OPPROTO op_int3(void)
#else
/*
* is_int is TRUE if coming from the int instruction. next_eip is the
* EIP value AFTER the interrupt instruction. It is only relevant if
* is_int is TRUE.
*/
void raise_interrupt(int intno, int is_int, int error_code,
unsigned int next_eip)
{
EIP = PARAM1;
raise_exception(EXCP03_INT3);
SegmentDescriptorTable *dt;
uint8_t *ptr;
int dpl, cpl;
uint32_t e2;
dt = &env->idt;
ptr = dt->base + (intno * 8);
e2 = ldl(ptr + 4);
dpl = (e2 >> DESC_DPL_SHIFT) & 3;
cpl = 3;
/* check privledge if software int */
if (is_int && dpl < cpl)
raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
/* Since we emulate only user space, we cannot do more than
exiting the emulation with the suitable exception and error
code */
if (is_int)
EIP = next_eip;
env->exception_index = intno;
env->error_code = error_code;
cpu_loop_exit();
}
#endif
/* shortcuts to generate exceptions */
void raise_exception_err(int exception_index, int error_code)
{
raise_interrupt(exception_index, 0, error_code, 0);
}
void raise_exception(int exception_index)
{
raise_interrupt(exception_index, 0, 0, 0);
}
void OPPROTO op_raise_interrupt(void)
{
int intno;
unsigned int next_eip;
intno = PARAM1;
next_eip = PARAM2;
raise_interrupt(intno, 1, 0, next_eip);
}
void OPPROTO op_raise_exception(void)
{
int exception_index;
exception_index = PARAM1;
raise_exception(exception_index);
}
void OPPROTO op_into(void)
@@ -631,24 +736,23 @@ void OPPROTO op_into(void)
int eflags;
eflags = cc_table[CC_OP].compute_all();
if (eflags & CC_O) {
raise_exception(EXCP04_INTO);
raise_interrupt(EXCP04_INTO, 1, 0, PARAM1);
}
FORCE_RET();
}
/* XXX: add IOPL/CPL tests */
void OPPROTO op_cli(void)
{
raise_exception(EXCP0D_GPF);
env->eflags &= ~IF_MASK;
}
/* XXX: add IOPL/CPL tests */
void OPPROTO op_sti(void)
{
raise_exception(EXCP0D_GPF);
env->eflags |= IF_MASK;
}
#if 0
/* vm86plus instructions */
void OPPROTO op_cli_vm(void)
{
env->eflags &= ~VIF_MASK;
@@ -663,6 +767,7 @@ void OPPROTO op_sti_vm(void)
}
FORCE_RET();
}
#endif
void OPPROTO op_boundw(void)
{
@@ -670,8 +775,10 @@ void OPPROTO op_boundw(void)
low = ldsw((uint8_t *)A0);
high = ldsw((uint8_t *)A0 + 2);
v = (int16_t)T0;
if (v < low || v > high)
if (v < low || v > high) {
EIP = PARAM1;
raise_exception(EXCP05_BOUND);
}
FORCE_RET();
}
@@ -681,8 +788,10 @@ void OPPROTO op_boundl(void)
low = ldl((uint8_t *)A0);
high = ldl((uint8_t *)A0 + 4);
v = T0;
if (v < low || v > high)
if (v < low || v > high) {
EIP = PARAM1;
raise_exception(EXCP05_BOUND);
}
FORCE_RET();
}
@@ -705,7 +814,44 @@ void OPPROTO op_cmpxchg8b(void)
FORCE_RET();
}
/* string ops */
#if defined(__powerpc__)
/* on PowerPC we patch the jump instruction directly */
#define JUMP_TB(tbparam, n, eip)\
do {\
static void __attribute__((unused)) *__op_label ## n = &&label ## n;\
asm volatile ("b %0" : : "i" (&__op_jmp ## n));\
label ## n:\
T0 = (long)(tbparam) + (n);\
EIP = eip;\
} while (0)
#else
/* jump to next block operations (more portable code, does not need
cache flushing, but slower because of indirect jump) */
#define JUMP_TB(tbparam, n, eip)\
do {\
static void __attribute__((unused)) *__op_label ## n = &&label ## n;\
goto *((TranslationBlock *)tbparam)->tb_next[n];\
label ## n:\
T0 = (long)(tbparam) + (n);\
EIP = eip;\
} while (0)
#endif
void OPPROTO op_jmp_tb_next(void)
{
JUMP_TB(PARAM1, 0, PARAM2);
}
void OPPROTO op_movl_T0_0(void)
{
T0 = 0;
}
/* multiple size ops */
#define ldul ldl
@@ -932,7 +1078,7 @@ void helper_cpuid(void)
EAX = 0x52b;
EBX = 0;
ECX = 0;
EDX = CPUID_FP87 | CPUID_VME | CPUID_DE | CPUID_PSE |
EDX = CPUID_FP87 | CPUID_DE | CPUID_PSE |
CPUID_TSC | CPUID_MSR | CPUID_MCE |
CPUID_CX8;
}
@@ -1075,8 +1221,8 @@ void OPPROTO op_das(void)
/* segment handling */
/* XXX: use static VM86 information */
void load_seg(int seg_reg, int selector)
/* only works if protected mode and not VM86 */
void load_seg(int seg_reg, int selector, unsigned cur_eip)
{
SegmentCache *sc;
SegmentDescriptorTable *dt;
@@ -1084,23 +1230,57 @@ void load_seg(int seg_reg, int selector)
uint32_t e1, e2;
uint8_t *ptr;
env->segs[seg_reg] = selector;
sc = &env->seg_cache[seg_reg];
if (env->eflags & VM_MASK) {
sc->base = (void *)(selector << 4);
sc->limit = 0xffff;
sc->seg_32bit = 0;
if ((selector & 0xfffc) == 0) {
/* null selector case */
if (seg_reg == R_SS) {
EIP = cur_eip;
raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
} else {
/* XXX: each access should trigger an exception */
sc->base = NULL;
sc->limit = 0;
sc->seg_32bit = 1;
}
} else {
if (selector & 0x4)
dt = &env->ldt;
else
dt = &env->gdt;
index = selector & ~7;
if ((index + 7) > dt->limit)
raise_exception(EXCP0D_GPF);
if ((index + 7) > dt->limit) {
EIP = cur_eip;
raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
}
ptr = dt->base + index;
e1 = ldl(ptr);
e2 = ldl(ptr + 4);
if (!(e2 & DESC_S_MASK) ||
(e2 & (DESC_CS_MASK | DESC_R_MASK)) == DESC_CS_MASK) {
EIP = cur_eip;
raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
}
if (seg_reg == R_SS) {
if ((e2 & (DESC_CS_MASK | DESC_W_MASK)) == 0) {
EIP = cur_eip;
raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
}
} else {
if ((e2 & (DESC_CS_MASK | DESC_R_MASK)) == DESC_CS_MASK) {
EIP = cur_eip;
raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
}
}
if (!(e2 & DESC_P_MASK)) {
EIP = cur_eip;
if (seg_reg == R_SS)
raise_exception_err(EXCP0C_STACK, selector & 0xfffc);
else
raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
}
sc->base = (void *)((e1 >> 16) | ((e2 & 0xff) << 16) | (e2 & 0xff000000));
sc->limit = (e1 & 0xffff) | (e2 & 0x000f0000);
if (e2 & (1 << 23))
@@ -1111,11 +1291,24 @@ void load_seg(int seg_reg, int selector)
selector, (unsigned long)sc->base, sc->limit, sc->seg_32bit);
#endif
}
env->segs[seg_reg] = selector;
}
void OPPROTO op_movl_seg_T0(void)
{
load_seg(PARAM1, T0 & 0xffff);
load_seg(PARAM1, T0 & 0xffff, PARAM2);
}
/* faster VM86 version */
void OPPROTO op_movl_seg_T0_vm(void)
{
int selector;
selector = T0 & 0xffff;
/* env->segs[] access */
*(uint32_t *)((char *)env + PARAM1) = selector;
/* env->seg_cache[] access */
((SegmentCache *)((char *)env + PARAM2))->base = (void *)(selector << 4);
}
void OPPROTO op_movl_T0_seg(void)
@@ -1133,92 +1326,77 @@ void OPPROTO op_addl_A0_seg(void)
A0 += *(unsigned long *)((char *)env + PARAM1);
}
void helper_lsl(void)
{
unsigned int selector, limit;
SegmentDescriptorTable *dt;
int index;
uint32_t e1, e2;
uint8_t *ptr;
CC_SRC = cc_table[CC_OP].compute_all() & ~CC_Z;
selector = T0 & 0xffff;
if (selector & 0x4)
dt = &env->ldt;
else
dt = &env->gdt;
index = selector & ~7;
if ((index + 7) > dt->limit)
return;
ptr = dt->base + index;
e1 = ldl(ptr);
e2 = ldl(ptr + 4);
limit = (e1 & 0xffff) | (e2 & 0x000f0000);
if (e2 & (1 << 23))
limit = (limit << 12) | 0xfff;
T1 = limit;
CC_SRC |= CC_Z;
}
void OPPROTO op_lsl(void)
{
helper_lsl();
}
void helper_lar(void)
{
unsigned int selector;
SegmentDescriptorTable *dt;
int index;
uint32_t e2;
uint8_t *ptr;
CC_SRC = cc_table[CC_OP].compute_all() & ~CC_Z;
selector = T0 & 0xffff;
if (selector & 0x4)
dt = &env->ldt;
else
dt = &env->gdt;
index = selector & ~7;
if ((index + 7) > dt->limit)
return;
ptr = dt->base + index;
e2 = ldl(ptr + 4);
T1 = e2 & 0x00f0ff00;
CC_SRC |= CC_Z;
}
void OPPROTO op_lar(void)
{
helper_lar();
}
/* flags handling */
/* slow jumps cases (compute x86 flags) */
void OPPROTO op_jo_cc(void)
/* slow jumps cases : in order to avoid calling a function with a
pointer (which can generate a stack frame on PowerPC), we use
op_setcc to set T0 and then call op_jcc. */
void OPPROTO op_jcc(void)
{
int eflags;
eflags = cc_table[CC_OP].compute_all();
if (eflags & CC_O)
EIP = PARAM1;
if (T0)
JUMP_TB(PARAM1, 0, PARAM2);
else
EIP = PARAM2;
FORCE_RET();
}
void OPPROTO op_jb_cc(void)
{
if (cc_table[CC_OP].compute_c())
EIP = PARAM1;
else
EIP = PARAM2;
FORCE_RET();
}
void OPPROTO op_jz_cc(void)
{
int eflags;
eflags = cc_table[CC_OP].compute_all();
if (eflags & CC_Z)
EIP = PARAM1;
else
EIP = PARAM2;
FORCE_RET();
}
void OPPROTO op_jbe_cc(void)
{
int eflags;
eflags = cc_table[CC_OP].compute_all();
if (eflags & (CC_Z | CC_C))
EIP = PARAM1;
else
EIP = PARAM2;
FORCE_RET();
}
void OPPROTO op_js_cc(void)
{
int eflags;
eflags = cc_table[CC_OP].compute_all();
if (eflags & CC_S)
EIP = PARAM1;
else
EIP = PARAM2;
FORCE_RET();
}
void OPPROTO op_jp_cc(void)
{
int eflags;
eflags = cc_table[CC_OP].compute_all();
if (eflags & CC_P)
EIP = PARAM1;
else
EIP = PARAM2;
FORCE_RET();
}
void OPPROTO op_jl_cc(void)
{
int eflags;
eflags = cc_table[CC_OP].compute_all();
if ((eflags ^ (eflags >> 4)) & 0x80)
EIP = PARAM1;
else
EIP = PARAM2;
FORCE_RET();
}
void OPPROTO op_jle_cc(void)
{
int eflags;
eflags = cc_table[CC_OP].compute_all();
if (((eflags ^ (eflags >> 4)) & 0x80) || (eflags & CC_Z))
EIP = PARAM1;
else
EIP = PARAM2;
JUMP_TB(PARAM1, 1, PARAM3);
FORCE_RET();
}
@@ -1310,7 +1488,8 @@ void OPPROTO op_movw_eflags_T0(void)
env->eflags = (env->eflags & ~FL_UPDATE_MASK16) | (eflags & FL_UPDATE_MASK16);
}
/* vm86 version */
#if 0
/* vm86plus version */
void OPPROTO op_movw_eflags_T0_vm(void)
{
int eflags;
@@ -1348,6 +1527,7 @@ void OPPROTO op_movl_eflags_T0_vm(void)
}
FORCE_RET();
}
#endif
/* XXX: compute only O flag */
void OPPROTO op_movb_eflags_T0(void)
@@ -1366,7 +1546,8 @@ void OPPROTO op_movl_T0_eflags(void)
T0 = eflags;
}
/* vm86 version */
/* vm86plus version */
#if 0
void OPPROTO op_movl_T0_eflags_vm(void)
{
int eflags;
@@ -1377,6 +1558,7 @@ void OPPROTO op_movl_T0_eflags_vm(void)
eflags |= IF_MASK;
T0 = eflags;
}
#endif
void OPPROTO op_cld(void)
{
@@ -1483,13 +1665,13 @@ CCTable cc_table[CC_OP_NB] = {
[CC_OP_DECW] = { compute_all_decw, compute_c_incl },
[CC_OP_DECL] = { compute_all_decl, compute_c_incl },
[CC_OP_SHLB] = { compute_all_shlb, compute_c_shll },
[CC_OP_SHLW] = { compute_all_shlw, compute_c_shll },
[CC_OP_SHLB] = { compute_all_shlb, compute_c_shlb },
[CC_OP_SHLW] = { compute_all_shlw, compute_c_shlw },
[CC_OP_SHLL] = { compute_all_shll, compute_c_shll },
[CC_OP_SARB] = { compute_all_sarb, compute_c_shll },
[CC_OP_SARW] = { compute_all_sarw, compute_c_shll },
[CC_OP_SARL] = { compute_all_sarl, compute_c_shll },
[CC_OP_SARB] = { compute_all_sarb, compute_c_sarl },
[CC_OP_SARW] = { compute_all_sarw, compute_c_sarl },
[CC_OP_SARL] = { compute_all_sarl, compute_c_sarl },
};
/* floating point support. Some of the code for complicated x87
@@ -1605,12 +1787,22 @@ typedef union {
void OPPROTO op_flds_FT0_A0(void)
{
#ifdef USE_FP_CONVERT
FP_CONVERT.i32 = ldl((void *)A0);
FT0 = FP_CONVERT.f;
#else
FT0 = ldfl((void *)A0);
#endif
}
void OPPROTO op_fldl_FT0_A0(void)
{
#ifdef USE_FP_CONVERT
FP_CONVERT.i64 = ldq((void *)A0);
FT0 = FP_CONVERT.d;
#else
FT0 = ldfq((void *)A0);
#endif
}
/* helpers are needed to avoid static constant reference. XXX: find a better way */
@@ -1650,17 +1842,32 @@ void OPPROTO op_fildll_FT0_A0(void)
void OPPROTO op_fild_FT0_A0(void)
{
#ifdef USE_FP_CONVERT
FP_CONVERT.i32 = ldsw((void *)A0);
FT0 = (CPU86_LDouble)FP_CONVERT.i32;
#else
FT0 = (CPU86_LDouble)ldsw((void *)A0);
#endif
}
void OPPROTO op_fildl_FT0_A0(void)
{
#ifdef USE_FP_CONVERT
FP_CONVERT.i32 = (int32_t) ldl((void *)A0);
FT0 = (CPU86_LDouble)FP_CONVERT.i32;
#else
FT0 = (CPU86_LDouble)((int32_t)ldl((void *)A0));
#endif
}
void OPPROTO op_fildll_FT0_A0(void)
{
#ifdef USE_FP_CONVERT
FP_CONVERT.i64 = (int64_t) ldq((void *)A0);
FT0 = (CPU86_LDouble)FP_CONVERT.i64;
#else
FT0 = (CPU86_LDouble)((int64_t)ldq((void *)A0));
#endif
}
#endif
@@ -1668,12 +1875,22 @@ void OPPROTO op_fildll_FT0_A0(void)
void OPPROTO op_flds_ST0_A0(void)
{
#ifdef USE_FP_CONVERT
FP_CONVERT.i32 = ldl((void *)A0);
ST0 = FP_CONVERT.f;
#else
ST0 = ldfl((void *)A0);
#endif
}
void OPPROTO op_fldl_ST0_A0(void)
{
#ifdef USE_FP_CONVERT
FP_CONVERT.i64 = ldq((void *)A0);
ST0 = FP_CONVERT.d;
#else
ST0 = ldfq((void *)A0);
#endif
}
#ifdef USE_X86LDOUBLE
@@ -1738,17 +1955,32 @@ void OPPROTO op_fildll_ST0_A0(void)
void OPPROTO op_fild_ST0_A0(void)
{
#ifdef USE_FP_CONVERT
FP_CONVERT.i32 = ldsw((void *)A0);
ST0 = (CPU86_LDouble)FP_CONVERT.i32;
#else
ST0 = (CPU86_LDouble)ldsw((void *)A0);
#endif
}
void OPPROTO op_fildl_ST0_A0(void)
{
#ifdef USE_FP_CONVERT
FP_CONVERT.i32 = (int32_t) ldl((void *)A0);
ST0 = (CPU86_LDouble)FP_CONVERT.i32;
#else
ST0 = (CPU86_LDouble)((int32_t)ldl((void *)A0));
#endif
}
void OPPROTO op_fildll_ST0_A0(void)
{
#ifdef USE_FP_CONVERT
FP_CONVERT.i64 = (int64_t) ldq((void *)A0);
ST0 = (CPU86_LDouble)FP_CONVERT.i64;
#else
ST0 = (CPU86_LDouble)((int64_t)ldq((void *)A0));
#endif
}
#endif
@@ -1757,7 +1989,12 @@ void OPPROTO op_fildll_ST0_A0(void)
void OPPROTO op_fsts_ST0_A0(void)
{
#ifdef USE_FP_CONVERT
FP_CONVERT.d = ST0;
stfl((void *)A0, FP_CONVERT.f);
#else
stfl((void *)A0, (float)ST0);
#endif
}
void OPPROTO op_fstl_ST0_A0(void)
@@ -1792,22 +2029,43 @@ void OPPROTO op_fstt_ST0_A0(void)
void OPPROTO op_fist_ST0_A0(void)
{
#if defined(__sparc__) && !defined(__sparc_v9__)
register CPU86_LDouble d asm("o0");
#else
CPU86_LDouble d;
#endif
int val;
val = lrint(ST0);
d = ST0;
val = lrint(d);
stw((void *)A0, val);
}
void OPPROTO op_fistl_ST0_A0(void)
{
#if defined(__sparc__) && !defined(__sparc_v9__)
register CPU86_LDouble d asm("o0");
#else
CPU86_LDouble d;
#endif
int val;
val = lrint(ST0);
d = ST0;
val = lrint(d);
stl((void *)A0, val);
}
void OPPROTO op_fistll_ST0_A0(void)
{
#if defined(__sparc__) && !defined(__sparc_v9__)
register CPU86_LDouble d asm("o0");
#else
CPU86_LDouble d;
#endif
int64_t val;
val = llrint(ST0);
d = ST0;
val = llrint(d);
stq((void *)A0, val);
}

View File

@@ -193,7 +193,7 @@ 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)(dx, v);
glue(cpu_x86_out, SUFFIX)(env, dx, v);
inc = (DF << SHIFT);
INC_SI();
}
@@ -205,7 +205,7 @@ void OPPROTO glue(glue(op_rep_outs, SUFFIX), STRING_SUFFIX)(void)
dx = EDX & 0xffff;
while (CX != 0) {
v = glue(ldu, SUFFIX)(SI_ADDR);
glue(cpu_x86_out, SUFFIX)(dx, v);
glue(cpu_x86_out, SUFFIX)(env, dx, v);
INC_SI();
DEC_CX();
}
@@ -216,7 +216,7 @@ void OPPROTO glue(glue(op_ins, SUFFIX), STRING_SUFFIX)(void)
{
int v, dx, inc;
dx = EDX & 0xffff;
v = glue(cpu_x86_in, SUFFIX)(dx);
v = glue(cpu_x86_in, SUFFIX)(env, dx);
glue(st, SUFFIX)(DI_ADDR, v);
inc = (DF << SHIFT);
INC_DI();
@@ -228,7 +228,7 @@ void OPPROTO glue(glue(op_rep_ins, SUFFIX), STRING_SUFFIX)(void)
inc = (DF << SHIFT);
dx = EDX & 0xffff;
while (CX != 0) {
v = glue(cpu_x86_in, SUFFIX)(dx);
v = glue(cpu_x86_in, SUFFIX)(env, dx);
glue(st, SUFFIX)(DI_ADDR, v);
INC_DI();
DEC_CX();

View File

@@ -1,644 +0,0 @@
DEF(end, 0)
DEF(movl_A0_EAX, 0)
DEF(addl_A0_EAX, 0)
DEF(addl_A0_EAX_s1, 0)
DEF(addl_A0_EAX_s2, 0)
DEF(addl_A0_EAX_s3, 0)
DEF(movl_T0_EAX, 0)
DEF(movl_T1_EAX, 0)
DEF(movh_T0_EAX, 0)
DEF(movh_T1_EAX, 0)
DEF(movl_EAX_T0, 0)
DEF(movl_EAX_T1, 0)
DEF(movl_EAX_A0, 0)
DEF(cmovw_EAX_T1_T0, 0)
DEF(cmovl_EAX_T1_T0, 0)
DEF(movw_EAX_T0, 0)
DEF(movw_EAX_T1, 0)
DEF(movw_EAX_A0, 0)
DEF(movb_EAX_T0, 0)
DEF(movh_EAX_T0, 0)
DEF(movb_EAX_T1, 0)
DEF(movh_EAX_T1, 0)
DEF(movl_A0_ECX, 0)
DEF(addl_A0_ECX, 0)
DEF(addl_A0_ECX_s1, 0)
DEF(addl_A0_ECX_s2, 0)
DEF(addl_A0_ECX_s3, 0)
DEF(movl_T0_ECX, 0)
DEF(movl_T1_ECX, 0)
DEF(movh_T0_ECX, 0)
DEF(movh_T1_ECX, 0)
DEF(movl_ECX_T0, 0)
DEF(movl_ECX_T1, 0)
DEF(movl_ECX_A0, 0)
DEF(cmovw_ECX_T1_T0, 0)
DEF(cmovl_ECX_T1_T0, 0)
DEF(movw_ECX_T0, 0)
DEF(movw_ECX_T1, 0)
DEF(movw_ECX_A0, 0)
DEF(movb_ECX_T0, 0)
DEF(movh_ECX_T0, 0)
DEF(movb_ECX_T1, 0)
DEF(movh_ECX_T1, 0)
DEF(movl_A0_EDX, 0)
DEF(addl_A0_EDX, 0)
DEF(addl_A0_EDX_s1, 0)
DEF(addl_A0_EDX_s2, 0)
DEF(addl_A0_EDX_s3, 0)
DEF(movl_T0_EDX, 0)
DEF(movl_T1_EDX, 0)
DEF(movh_T0_EDX, 0)
DEF(movh_T1_EDX, 0)
DEF(movl_EDX_T0, 0)
DEF(movl_EDX_T1, 0)
DEF(movl_EDX_A0, 0)
DEF(cmovw_EDX_T1_T0, 0)
DEF(cmovl_EDX_T1_T0, 0)
DEF(movw_EDX_T0, 0)
DEF(movw_EDX_T1, 0)
DEF(movw_EDX_A0, 0)
DEF(movb_EDX_T0, 0)
DEF(movh_EDX_T0, 0)
DEF(movb_EDX_T1, 0)
DEF(movh_EDX_T1, 0)
DEF(movl_A0_EBX, 0)
DEF(addl_A0_EBX, 0)
DEF(addl_A0_EBX_s1, 0)
DEF(addl_A0_EBX_s2, 0)
DEF(addl_A0_EBX_s3, 0)
DEF(movl_T0_EBX, 0)
DEF(movl_T1_EBX, 0)
DEF(movh_T0_EBX, 0)
DEF(movh_T1_EBX, 0)
DEF(movl_EBX_T0, 0)
DEF(movl_EBX_T1, 0)
DEF(movl_EBX_A0, 0)
DEF(cmovw_EBX_T1_T0, 0)
DEF(cmovl_EBX_T1_T0, 0)
DEF(movw_EBX_T0, 0)
DEF(movw_EBX_T1, 0)
DEF(movw_EBX_A0, 0)
DEF(movb_EBX_T0, 0)
DEF(movh_EBX_T0, 0)
DEF(movb_EBX_T1, 0)
DEF(movh_EBX_T1, 0)
DEF(movl_A0_ESP, 0)
DEF(addl_A0_ESP, 0)
DEF(addl_A0_ESP_s1, 0)
DEF(addl_A0_ESP_s2, 0)
DEF(addl_A0_ESP_s3, 0)
DEF(movl_T0_ESP, 0)
DEF(movl_T1_ESP, 0)
DEF(movh_T0_ESP, 0)
DEF(movh_T1_ESP, 0)
DEF(movl_ESP_T0, 0)
DEF(movl_ESP_T1, 0)
DEF(movl_ESP_A0, 0)
DEF(cmovw_ESP_T1_T0, 0)
DEF(cmovl_ESP_T1_T0, 0)
DEF(movw_ESP_T0, 0)
DEF(movw_ESP_T1, 0)
DEF(movw_ESP_A0, 0)
DEF(movb_ESP_T0, 0)
DEF(movh_ESP_T0, 0)
DEF(movb_ESP_T1, 0)
DEF(movh_ESP_T1, 0)
DEF(movl_A0_EBP, 0)
DEF(addl_A0_EBP, 0)
DEF(addl_A0_EBP_s1, 0)
DEF(addl_A0_EBP_s2, 0)
DEF(addl_A0_EBP_s3, 0)
DEF(movl_T0_EBP, 0)
DEF(movl_T1_EBP, 0)
DEF(movh_T0_EBP, 0)
DEF(movh_T1_EBP, 0)
DEF(movl_EBP_T0, 0)
DEF(movl_EBP_T1, 0)
DEF(movl_EBP_A0, 0)
DEF(cmovw_EBP_T1_T0, 0)
DEF(cmovl_EBP_T1_T0, 0)
DEF(movw_EBP_T0, 0)
DEF(movw_EBP_T1, 0)
DEF(movw_EBP_A0, 0)
DEF(movb_EBP_T0, 0)
DEF(movh_EBP_T0, 0)
DEF(movb_EBP_T1, 0)
DEF(movh_EBP_T1, 0)
DEF(movl_A0_ESI, 0)
DEF(addl_A0_ESI, 0)
DEF(addl_A0_ESI_s1, 0)
DEF(addl_A0_ESI_s2, 0)
DEF(addl_A0_ESI_s3, 0)
DEF(movl_T0_ESI, 0)
DEF(movl_T1_ESI, 0)
DEF(movh_T0_ESI, 0)
DEF(movh_T1_ESI, 0)
DEF(movl_ESI_T0, 0)
DEF(movl_ESI_T1, 0)
DEF(movl_ESI_A0, 0)
DEF(cmovw_ESI_T1_T0, 0)
DEF(cmovl_ESI_T1_T0, 0)
DEF(movw_ESI_T0, 0)
DEF(movw_ESI_T1, 0)
DEF(movw_ESI_A0, 0)
DEF(movb_ESI_T0, 0)
DEF(movh_ESI_T0, 0)
DEF(movb_ESI_T1, 0)
DEF(movh_ESI_T1, 0)
DEF(movl_A0_EDI, 0)
DEF(addl_A0_EDI, 0)
DEF(addl_A0_EDI_s1, 0)
DEF(addl_A0_EDI_s2, 0)
DEF(addl_A0_EDI_s3, 0)
DEF(movl_T0_EDI, 0)
DEF(movl_T1_EDI, 0)
DEF(movh_T0_EDI, 0)
DEF(movh_T1_EDI, 0)
DEF(movl_EDI_T0, 0)
DEF(movl_EDI_T1, 0)
DEF(movl_EDI_A0, 0)
DEF(cmovw_EDI_T1_T0, 0)
DEF(cmovl_EDI_T1_T0, 0)
DEF(movw_EDI_T0, 0)
DEF(movw_EDI_T1, 0)
DEF(movw_EDI_A0, 0)
DEF(movb_EDI_T0, 0)
DEF(movh_EDI_T0, 0)
DEF(movb_EDI_T1, 0)
DEF(movh_EDI_T1, 0)
DEF(addl_T0_T1_cc, 0)
DEF(orl_T0_T1_cc, 0)
DEF(andl_T0_T1_cc, 0)
DEF(subl_T0_T1_cc, 0)
DEF(xorl_T0_T1_cc, 0)
DEF(cmpl_T0_T1_cc, 0)
DEF(negl_T0_cc, 0)
DEF(incl_T0_cc, 0)
DEF(decl_T0_cc, 0)
DEF(testl_T0_T1_cc, 0)
DEF(addl_T0_T1, 0)
DEF(orl_T0_T1, 0)
DEF(andl_T0_T1, 0)
DEF(subl_T0_T1, 0)
DEF(xorl_T0_T1, 0)
DEF(negl_T0, 0)
DEF(incl_T0, 0)
DEF(decl_T0, 0)
DEF(notl_T0, 0)
DEF(bswapl_T0, 0)
DEF(mulb_AL_T0, 0)
DEF(imulb_AL_T0, 0)
DEF(mulw_AX_T0, 0)
DEF(imulw_AX_T0, 0)
DEF(mull_EAX_T0, 0)
DEF(imull_EAX_T0, 0)
DEF(imulw_T0_T1, 0)
DEF(imull_T0_T1, 0)
DEF(divb_AL_T0, 0)
DEF(idivb_AL_T0, 0)
DEF(divw_AX_T0, 0)
DEF(idivw_AX_T0, 0)
DEF(divl_EAX_T0, 0)
DEF(idivl_EAX_T0, 0)
DEF(movl_T0_im, 1)
DEF(addl_T0_im, 1)
DEF(andl_T0_ffff, 0)
DEF(movl_T0_T1, 0)
DEF(movl_T1_im, 1)
DEF(addl_T1_im, 1)
DEF(movl_T1_A0, 0)
DEF(movl_A0_im, 1)
DEF(addl_A0_im, 1)
DEF(addl_A0_AL, 0)
DEF(andl_A0_ffff, 0)
DEF(ldub_T0_A0, 0)
DEF(ldsb_T0_A0, 0)
DEF(lduw_T0_A0, 0)
DEF(ldsw_T0_A0, 0)
DEF(ldl_T0_A0, 0)
DEF(ldub_T1_A0, 0)
DEF(ldsb_T1_A0, 0)
DEF(lduw_T1_A0, 0)
DEF(ldsw_T1_A0, 0)
DEF(ldl_T1_A0, 0)
DEF(stb_T0_A0, 0)
DEF(stw_T0_A0, 0)
DEF(stl_T0_A0, 0)
DEF(add_bitw_A0_T1, 0)
DEF(add_bitl_A0_T1, 0)
DEF(jmp_T0, 0)
DEF(jmp_im, 1)
DEF(int_im, 1)
DEF(int3, 1)
DEF(into, 0)
DEF(cli, 0)
DEF(sti, 0)
DEF(cli_vm, 0)
DEF(sti_vm, 1)
DEF(boundw, 0)
DEF(boundl, 0)
DEF(cmpxchg8b, 0)
DEF(jb_subb, 2)
DEF(jz_subb, 2)
DEF(jbe_subb, 2)
DEF(js_subb, 2)
DEF(jl_subb, 2)
DEF(jle_subb, 2)
DEF(setb_T0_subb, 0)
DEF(setz_T0_subb, 0)
DEF(setbe_T0_subb, 0)
DEF(sets_T0_subb, 0)
DEF(setl_T0_subb, 0)
DEF(setle_T0_subb, 0)
DEF(rolb_T0_T1_cc, 0)
DEF(rolb_T0_T1, 0)
DEF(rorb_T0_T1_cc, 0)
DEF(rorb_T0_T1, 0)
DEF(rclb_T0_T1_cc, 0)
DEF(rcrb_T0_T1_cc, 0)
DEF(shlb_T0_T1_cc, 0)
DEF(shlb_T0_T1, 0)
DEF(shrb_T0_T1_cc, 0)
DEF(shrb_T0_T1, 0)
DEF(sarb_T0_T1_cc, 0)
DEF(sarb_T0_T1, 0)
DEF(adcb_T0_T1_cc, 0)
DEF(sbbb_T0_T1_cc, 0)
DEF(cmpxchgb_T0_T1_EAX_cc, 0)
DEF(movsb_fast, 0)
DEF(rep_movsb_fast, 0)
DEF(stosb_fast, 0)
DEF(rep_stosb_fast, 0)
DEF(lodsb_fast, 0)
DEF(rep_lodsb_fast, 0)
DEF(scasb_fast, 0)
DEF(repz_scasb_fast, 0)
DEF(repnz_scasb_fast, 0)
DEF(cmpsb_fast, 0)
DEF(repz_cmpsb_fast, 0)
DEF(repnz_cmpsb_fast, 0)
DEF(outsb_fast, 0)
DEF(rep_outsb_fast, 0)
DEF(insb_fast, 0)
DEF(rep_insb_fast, 0)
DEF(movsb_a32, 0)
DEF(rep_movsb_a32, 0)
DEF(stosb_a32, 0)
DEF(rep_stosb_a32, 0)
DEF(lodsb_a32, 0)
DEF(rep_lodsb_a32, 0)
DEF(scasb_a32, 0)
DEF(repz_scasb_a32, 0)
DEF(repnz_scasb_a32, 0)
DEF(cmpsb_a32, 0)
DEF(repz_cmpsb_a32, 0)
DEF(repnz_cmpsb_a32, 0)
DEF(outsb_a32, 0)
DEF(rep_outsb_a32, 0)
DEF(insb_a32, 0)
DEF(rep_insb_a32, 0)
DEF(movsb_a16, 0)
DEF(rep_movsb_a16, 0)
DEF(stosb_a16, 0)
DEF(rep_stosb_a16, 0)
DEF(lodsb_a16, 0)
DEF(rep_lodsb_a16, 0)
DEF(scasb_a16, 0)
DEF(repz_scasb_a16, 0)
DEF(repnz_scasb_a16, 0)
DEF(cmpsb_a16, 0)
DEF(repz_cmpsb_a16, 0)
DEF(repnz_cmpsb_a16, 0)
DEF(outsb_a16, 0)
DEF(rep_outsb_a16, 0)
DEF(insb_a16, 0)
DEF(rep_insb_a16, 0)
DEF(outb_T0_T1, 0)
DEF(inb_T0_T1, 0)
DEF(jb_subw, 2)
DEF(jz_subw, 2)
DEF(jbe_subw, 2)
DEF(js_subw, 2)
DEF(jl_subw, 2)
DEF(jle_subw, 2)
DEF(loopnzw, 2)
DEF(loopzw, 2)
DEF(loopw, 2)
DEF(jecxzw, 2)
DEF(setb_T0_subw, 0)
DEF(setz_T0_subw, 0)
DEF(setbe_T0_subw, 0)
DEF(sets_T0_subw, 0)
DEF(setl_T0_subw, 0)
DEF(setle_T0_subw, 0)
DEF(rolw_T0_T1_cc, 0)
DEF(rolw_T0_T1, 0)
DEF(rorw_T0_T1_cc, 0)
DEF(rorw_T0_T1, 0)
DEF(rclw_T0_T1_cc, 0)
DEF(rcrw_T0_T1_cc, 0)
DEF(shlw_T0_T1_cc, 0)
DEF(shlw_T0_T1, 0)
DEF(shrw_T0_T1_cc, 0)
DEF(shrw_T0_T1, 0)
DEF(sarw_T0_T1_cc, 0)
DEF(sarw_T0_T1, 0)
DEF(shldw_T0_T1_im_cc, 1)
DEF(shldw_T0_T1_ECX_cc, 0)
DEF(shrdw_T0_T1_im_cc, 1)
DEF(shrdw_T0_T1_ECX_cc, 0)
DEF(adcw_T0_T1_cc, 0)
DEF(sbbw_T0_T1_cc, 0)
DEF(cmpxchgw_T0_T1_EAX_cc, 0)
DEF(btw_T0_T1_cc, 0)
DEF(btsw_T0_T1_cc, 0)
DEF(btrw_T0_T1_cc, 0)
DEF(btcw_T0_T1_cc, 0)
DEF(bsfw_T0_cc, 0)
DEF(bsrw_T0_cc, 0)
DEF(movsw_fast, 0)
DEF(rep_movsw_fast, 0)
DEF(stosw_fast, 0)
DEF(rep_stosw_fast, 0)
DEF(lodsw_fast, 0)
DEF(rep_lodsw_fast, 0)
DEF(scasw_fast, 0)
DEF(repz_scasw_fast, 0)
DEF(repnz_scasw_fast, 0)
DEF(cmpsw_fast, 0)
DEF(repz_cmpsw_fast, 0)
DEF(repnz_cmpsw_fast, 0)
DEF(outsw_fast, 0)
DEF(rep_outsw_fast, 0)
DEF(insw_fast, 0)
DEF(rep_insw_fast, 0)
DEF(movsw_a32, 0)
DEF(rep_movsw_a32, 0)
DEF(stosw_a32, 0)
DEF(rep_stosw_a32, 0)
DEF(lodsw_a32, 0)
DEF(rep_lodsw_a32, 0)
DEF(scasw_a32, 0)
DEF(repz_scasw_a32, 0)
DEF(repnz_scasw_a32, 0)
DEF(cmpsw_a32, 0)
DEF(repz_cmpsw_a32, 0)
DEF(repnz_cmpsw_a32, 0)
DEF(outsw_a32, 0)
DEF(rep_outsw_a32, 0)
DEF(insw_a32, 0)
DEF(rep_insw_a32, 0)
DEF(movsw_a16, 0)
DEF(rep_movsw_a16, 0)
DEF(stosw_a16, 0)
DEF(rep_stosw_a16, 0)
DEF(lodsw_a16, 0)
DEF(rep_lodsw_a16, 0)
DEF(scasw_a16, 0)
DEF(repz_scasw_a16, 0)
DEF(repnz_scasw_a16, 0)
DEF(cmpsw_a16, 0)
DEF(repz_cmpsw_a16, 0)
DEF(repnz_cmpsw_a16, 0)
DEF(outsw_a16, 0)
DEF(rep_outsw_a16, 0)
DEF(insw_a16, 0)
DEF(rep_insw_a16, 0)
DEF(outw_T0_T1, 0)
DEF(inw_T0_T1, 0)
DEF(jb_subl, 2)
DEF(jz_subl, 2)
DEF(jbe_subl, 2)
DEF(js_subl, 2)
DEF(jl_subl, 2)
DEF(jle_subl, 2)
DEF(loopnzl, 2)
DEF(loopzl, 2)
DEF(loopl, 2)
DEF(jecxzl, 2)
DEF(setb_T0_subl, 0)
DEF(setz_T0_subl, 0)
DEF(setbe_T0_subl, 0)
DEF(sets_T0_subl, 0)
DEF(setl_T0_subl, 0)
DEF(setle_T0_subl, 0)
DEF(roll_T0_T1_cc, 0)
DEF(roll_T0_T1, 0)
DEF(rorl_T0_T1_cc, 0)
DEF(rorl_T0_T1, 0)
DEF(rcll_T0_T1_cc, 0)
DEF(rcrl_T0_T1_cc, 0)
DEF(shll_T0_T1_cc, 0)
DEF(shll_T0_T1, 0)
DEF(shrl_T0_T1_cc, 0)
DEF(shrl_T0_T1, 0)
DEF(sarl_T0_T1_cc, 0)
DEF(sarl_T0_T1, 0)
DEF(shldl_T0_T1_im_cc, 1)
DEF(shldl_T0_T1_ECX_cc, 0)
DEF(shrdl_T0_T1_im_cc, 1)
DEF(shrdl_T0_T1_ECX_cc, 0)
DEF(adcl_T0_T1_cc, 0)
DEF(sbbl_T0_T1_cc, 0)
DEF(cmpxchgl_T0_T1_EAX_cc, 0)
DEF(btl_T0_T1_cc, 0)
DEF(btsl_T0_T1_cc, 0)
DEF(btrl_T0_T1_cc, 0)
DEF(btcl_T0_T1_cc, 0)
DEF(bsfl_T0_cc, 0)
DEF(bsrl_T0_cc, 0)
DEF(movsl_fast, 0)
DEF(rep_movsl_fast, 0)
DEF(stosl_fast, 0)
DEF(rep_stosl_fast, 0)
DEF(lodsl_fast, 0)
DEF(rep_lodsl_fast, 0)
DEF(scasl_fast, 0)
DEF(repz_scasl_fast, 0)
DEF(repnz_scasl_fast, 0)
DEF(cmpsl_fast, 0)
DEF(repz_cmpsl_fast, 0)
DEF(repnz_cmpsl_fast, 0)
DEF(outsl_fast, 0)
DEF(rep_outsl_fast, 0)
DEF(insl_fast, 0)
DEF(rep_insl_fast, 0)
DEF(movsl_a32, 0)
DEF(rep_movsl_a32, 0)
DEF(stosl_a32, 0)
DEF(rep_stosl_a32, 0)
DEF(lodsl_a32, 0)
DEF(rep_lodsl_a32, 0)
DEF(scasl_a32, 0)
DEF(repz_scasl_a32, 0)
DEF(repnz_scasl_a32, 0)
DEF(cmpsl_a32, 0)
DEF(repz_cmpsl_a32, 0)
DEF(repnz_cmpsl_a32, 0)
DEF(outsl_a32, 0)
DEF(rep_outsl_a32, 0)
DEF(insl_a32, 0)
DEF(rep_insl_a32, 0)
DEF(movsl_a16, 0)
DEF(rep_movsl_a16, 0)
DEF(stosl_a16, 0)
DEF(rep_stosl_a16, 0)
DEF(lodsl_a16, 0)
DEF(rep_lodsl_a16, 0)
DEF(scasl_a16, 0)
DEF(repz_scasl_a16, 0)
DEF(repnz_scasl_a16, 0)
DEF(cmpsl_a16, 0)
DEF(repz_cmpsl_a16, 0)
DEF(repnz_cmpsl_a16, 0)
DEF(outsl_a16, 0)
DEF(rep_outsl_a16, 0)
DEF(insl_a16, 0)
DEF(rep_insl_a16, 0)
DEF(outl_T0_T1, 0)
DEF(inl_T0_T1, 0)
DEF(movsbl_T0_T0, 0)
DEF(movzbl_T0_T0, 0)
DEF(movswl_T0_T0, 0)
DEF(movzwl_T0_T0, 0)
DEF(movswl_EAX_AX, 0)
DEF(movsbw_AX_AL, 0)
DEF(movslq_EDX_EAX, 0)
DEF(movswl_DX_AX, 0)
DEF(pushl_T0, 0)
DEF(pushw_T0, 0)
DEF(pushl_ss32_T0, 0)
DEF(pushw_ss32_T0, 0)
DEF(pushl_ss16_T0, 0)
DEF(pushw_ss16_T0, 0)
DEF(popl_T0, 0)
DEF(popw_T0, 0)
DEF(popl_ss32_T0, 0)
DEF(popw_ss32_T0, 0)
DEF(popl_ss16_T0, 0)
DEF(popw_ss16_T0, 0)
DEF(addl_ESP_4, 0)
DEF(addl_ESP_2, 0)
DEF(addw_ESP_4, 0)
DEF(addw_ESP_2, 0)
DEF(addl_ESP_im, 1)
DEF(addw_ESP_im, 1)
DEF(rdtsc, 0)
DEF(cpuid, 0)
DEF(aam, 1)
DEF(aad, 1)
DEF(aaa, 0)
DEF(aas, 0)
DEF(daa, 0)
DEF(das, 0)
DEF(movl_seg_T0, 1)
DEF(movl_T0_seg, 1)
DEF(movl_A0_seg, 1)
DEF(addl_A0_seg, 1)
DEF(jo_cc, 2)
DEF(jb_cc, 2)
DEF(jz_cc, 2)
DEF(jbe_cc, 2)
DEF(js_cc, 2)
DEF(jp_cc, 2)
DEF(jl_cc, 2)
DEF(jle_cc, 2)
DEF(seto_T0_cc, 0)
DEF(setb_T0_cc, 0)
DEF(setz_T0_cc, 0)
DEF(setbe_T0_cc, 0)
DEF(sets_T0_cc, 0)
DEF(setp_T0_cc, 0)
DEF(setl_T0_cc, 0)
DEF(setle_T0_cc, 0)
DEF(xor_T0_1, 0)
DEF(set_cc_op, 1)
DEF(movl_eflags_T0, 0)
DEF(movw_eflags_T0, 0)
DEF(movw_eflags_T0_vm, 1)
DEF(movl_eflags_T0_vm, 1)
DEF(movb_eflags_T0, 0)
DEF(movl_T0_eflags, 0)
DEF(movl_T0_eflags_vm, 0)
DEF(cld, 0)
DEF(std, 0)
DEF(clc, 0)
DEF(stc, 0)
DEF(cmc, 0)
DEF(salc, 0)
DEF(flds_FT0_A0, 0)
DEF(fldl_FT0_A0, 0)
DEF(fild_FT0_A0, 0)
DEF(fildl_FT0_A0, 0)
DEF(fildll_FT0_A0, 0)
DEF(flds_ST0_A0, 0)
DEF(fldl_ST0_A0, 0)
DEF(fldt_ST0_A0, 0)
DEF(fild_ST0_A0, 0)
DEF(fildl_ST0_A0, 0)
DEF(fildll_ST0_A0, 0)
DEF(fsts_ST0_A0, 0)
DEF(fstl_ST0_A0, 0)
DEF(fstt_ST0_A0, 0)
DEF(fist_ST0_A0, 0)
DEF(fistl_ST0_A0, 0)
DEF(fistll_ST0_A0, 0)
DEF(fbld_ST0_A0, 0)
DEF(fbst_ST0_A0, 0)
DEF(fpush, 0)
DEF(fpop, 0)
DEF(fdecstp, 0)
DEF(fincstp, 0)
DEF(fmov_ST0_FT0, 0)
DEF(fmov_FT0_STN, 1)
DEF(fmov_ST0_STN, 1)
DEF(fmov_STN_ST0, 1)
DEF(fxchg_ST0_STN, 1)
DEF(fcom_ST0_FT0, 0)
DEF(fucom_ST0_FT0, 0)
DEF(fadd_ST0_FT0, 0)
DEF(fmul_ST0_FT0, 0)
DEF(fsub_ST0_FT0, 0)
DEF(fsubr_ST0_FT0, 0)
DEF(fdiv_ST0_FT0, 0)
DEF(fdivr_ST0_FT0, 0)
DEF(fadd_STN_ST0, 1)
DEF(fmul_STN_ST0, 1)
DEF(fsub_STN_ST0, 1)
DEF(fsubr_STN_ST0, 1)
DEF(fdiv_STN_ST0, 1)
DEF(fdivr_STN_ST0, 1)
DEF(fchs_ST0, 0)
DEF(fabs_ST0, 0)
DEF(fxam_ST0, 0)
DEF(fld1_ST0, 0)
DEF(fldl2t_ST0, 0)
DEF(fldl2e_ST0, 0)
DEF(fldpi_ST0, 0)
DEF(fldlg2_ST0, 0)
DEF(fldln2_ST0, 0)
DEF(fldz_ST0, 0)
DEF(fldz_FT0, 0)
DEF(f2xm1, 0)
DEF(fyl2x, 0)
DEF(fptan, 0)
DEF(fpatan, 0)
DEF(fxtract, 0)
DEF(fprem1, 0)
DEF(fprem, 0)
DEF(fyl2xp1, 0)
DEF(fsqrt, 0)
DEF(fsincos, 0)
DEF(frndint, 0)
DEF(fscale, 0)
DEF(fsin, 0)
DEF(fcos, 0)
DEF(fnstsw_A0, 0)
DEF(fnstsw_EAX, 0)
DEF(fnstcw_A0, 0)
DEF(fldcw_A0, 0)
DEF(fclex, 0)
DEF(fninit, 0)
DEF(lock, 0)
DEF(unlock, 0)

View File

@@ -204,8 +204,13 @@ static int glue(compute_all_shl, SUFFIX)(void)
return cf | pf | af | zf | sf | of;
}
#if DATA_BITS == 32
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;
}
@@ -233,18 +238,18 @@ void OPPROTO glue(op_jb_sub, SUFFIX)(void)
src2 = CC_SRC - CC_DST;
if ((DATA_TYPE)src1 < (DATA_TYPE)src2)
EIP = PARAM1;
JUMP_TB(PARAM1, 0, PARAM2);
else
EIP = PARAM2;
JUMP_TB(PARAM1, 1, PARAM3);
FORCE_RET();
}
void OPPROTO glue(op_jz_sub, SUFFIX)(void)
{
if ((DATA_TYPE)CC_DST == 0)
EIP = PARAM1;
JUMP_TB(PARAM1, 0, PARAM2);
else
EIP = PARAM2;
JUMP_TB(PARAM1, 1, PARAM3);
FORCE_RET();
}
@@ -255,18 +260,18 @@ void OPPROTO glue(op_jbe_sub, SUFFIX)(void)
src2 = CC_SRC - CC_DST;
if ((DATA_TYPE)src1 <= (DATA_TYPE)src2)
EIP = PARAM1;
JUMP_TB(PARAM1, 0, PARAM2);
else
EIP = PARAM2;
JUMP_TB(PARAM1, 1, PARAM3);
FORCE_RET();
}
void OPPROTO glue(op_js_sub, SUFFIX)(void)
{
if (CC_DST & SIGN_MASK)
EIP = PARAM1;
JUMP_TB(PARAM1, 0, PARAM2);
else
EIP = PARAM2;
JUMP_TB(PARAM1, 1, PARAM3);
FORCE_RET();
}
@@ -277,9 +282,9 @@ void OPPROTO glue(op_jl_sub, SUFFIX)(void)
src2 = CC_SRC - CC_DST;
if ((DATA_STYPE)src1 < (DATA_STYPE)src2)
EIP = PARAM1;
JUMP_TB(PARAM1, 0, PARAM2);
else
EIP = PARAM2;
JUMP_TB(PARAM1, 1, PARAM3);
FORCE_RET();
}
@@ -290,9 +295,9 @@ void OPPROTO glue(op_jle_sub, SUFFIX)(void)
src2 = CC_SRC - CC_DST;
if ((DATA_STYPE)src1 <= (DATA_STYPE)src2)
EIP = PARAM1;
JUMP_TB(PARAM1, 0, PARAM2);
else
EIP = PARAM2;
JUMP_TB(PARAM1, 1, PARAM3);
FORCE_RET();
}
@@ -843,12 +848,12 @@ void OPPROTO glue(glue(op_bsr, SUFFIX), _T0_cc)(void)
void OPPROTO glue(glue(op_out, SUFFIX), _T0_T1)(void)
{
glue(cpu_x86_out, SUFFIX)(T0 & 0xffff, T1 & DATA_MASK);
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)(T0 & 0xffff);
T1 = glue(cpu_x86_in, SUFFIX)(env, T0 & 0xffff);
}
#undef DATA_BITS

3231
ppc-dis.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -10,11 +10,11 @@
@chapter Introduction
QEMU is an x86 processor emulator. Its purpose is to run x86 Linux
processes on non-x86 Linux architectures such as PowerPC or ARM. 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}) on
non-x86 CPUs.
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:
@@ -22,21 +22,26 @@ QEMU features:
@item User space only x86 emulator.
@item Currently ported on i386, PowerPC and S390.
@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
(experimental).
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 Accurate signal handling by remapping host signals to virtual x86 signals.
@item QEMU can emulate itself on x86 (experimental).
@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.
@@ -46,19 +51,15 @@ It can be used to test other x86 virtual CPUs.
@end itemize
Current QEMU Limitations:
Current QEMU limitations:
@itemize
@item Not all x86 exceptions are precise (yet). [Very few programs need that].
@item No support for self-modifying code (yet). [Very few programs need that, a notable exception is QEMU itself !].
@item No SSE/MMX support (yet).
@item No x86-64 support.
@item Some Linux syscalls are missing.
@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).
@@ -119,7 +120,7 @@ qemu /usr/local/qemu-i386/bin/qemu-i386 /usr/local/qemu-i386/bin/ls-i386
@end itemize
@section Wine launch (Currently only tested when emulating x86 on x86)
@section Wine launch
@itemize
@@ -152,17 +153,24 @@ qemu /usr/local/qemu-i386/wine/bin/wine /usr/local/qemu-i386/wine/c/Program\ Fil
usage: qemu [-h] [-d] [-L path] [-s size] program [arguments...]
@end example
@table @samp
@table @option
@item -h
Print the help
@item -d
Activate log (logfile=/tmp/qemu.log)
@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
@@ -265,17 +273,59 @@ 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).
[Currently, the translated code is not patched if it jumps to another
translated code].
@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.
encountered.
[Currently, the virtual CPU cannot retrieve the exact CPU state in some
exceptions, although it could except for the @code{EFLAGS} register].
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
@@ -284,6 +334,11 @@ 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
@@ -312,6 +367,10 @@ 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
@@ -319,13 +378,9 @@ 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 ELF shared object
as the ld-linux.so ELF interpreter. That way, it can be relocated at
load time.
Since self-modifying code is not supported yet, QEMU cannot self
virtualize itself in case of translation cache flush. This limitation
will be suppressed soon.
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
@@ -379,19 +434,10 @@ 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.
@section @file{testsig}
The Linux system call @code{vm86()} is used to test vm86 emulation.
This program tests various signal cases, including SIGFPE, SIGSEGV and
SIGILL.
@section @file{testclone}
Tests the @code{clone()} system call (basic test).
@section @file{testthread}
Tests the glibc threads (more complicated than @code{clone()} because signals
are also used).
Various exceptions are raised to test most of the x86 user space
exception reporting.
@section @file{sha1}
@@ -399,9 +445,3 @@ 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.
@section @file{runcom}
A very simple MSDOS emulator to test the Linux vm86() system call
emulation. The excellent 54 byte @file{pi_10.com} PI number calculator
can be launched with it. @file{pi_10.com} was written by Bertram
Felgenhauer (more information at @url{http://www.boo.net/~jasonp/pipage.html}).

204
s390.ld Normal file
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) }
}

View File

@@ -330,7 +330,7 @@ struct target_stat64 {
target_ulong __pad7; /* will be high 32 bits of ctime someday */
unsigned long long st_ino;
};
} __attribute__((packed));
#define TARGET_SA_NOCLDSTOP 0x00000001
#define TARGET_SA_NOCLDWAIT 0x00000002 /* not supported yet */
@@ -444,6 +444,18 @@ 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
*/
@@ -462,6 +474,18 @@ typedef struct target_siginfo {
#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)
@@ -760,6 +784,13 @@ struct target_modify_ldt_ldt_s {
#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) */
@@ -936,6 +967,40 @@ union target_semun {
unsigned int __pad; /* really void* */
};
#define TARGET_F_DUPFD 0 /* dup */
#define TARGET_F_GETFD 1 /* get close_on_exec */
#define TARGET_F_SETFD 2 /* set/clear close_on_exec */
#define TARGET_F_GETFL 3 /* get file->f_flags */
#define TARGET_F_SETFL 4 /* set file->f_flags */
#define TARGET_F_GETLK 5
#define TARGET_F_SETLK 6
#define TARGET_F_SETLKW 7
#define TARGET_F_SETOWN 8 /* for sockets. */
#define TARGET_F_GETOWN 9 /* for sockets. */
#define TARGET_F_SETSIG 10 /* for sockets. */
#define TARGET_F_GETSIG 11 /* for sockets. */
#define TARGET_F_GETLK64 12 /* using 'struct flock64' */
#define TARGET_F_SETLK64 13
#define TARGET_F_SETLKW64 14
struct target_flock {
short l_type;
short l_whence;
target_ulong l_start;
target_ulong l_len;
int l_pid;
};
struct target_flock64 {
short l_type;
short l_whence;
unsigned long long l_start;
unsigned long long l_len;
int l_pid;
};
/* soundcard defines (XXX: move them to generic file syscall_defs.h) */
#define TARGET_SNDCTL_COPR_HALT 0xc0144307

View File

@@ -3,16 +3,10 @@
hello
sha1.test.c
sha1.c
op.c
test-i386
sha1
testclone
interp.h
interploop.c
.gdb_history
cachegrind.out
interp.c
interp
testthread
test-i386.s
test-i386.ref

View File

@@ -30,9 +30,10 @@ test_path: test_path.c
./$@ || { rm $@; exit 1; }
# i386 emulation test (test various opcodes) */
test-i386: test-i386.c test-i386-code16.S \
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) -static -o $@ test-i386.c test-i386-code16.S -lm
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ test-i386.c \
test-i386-code16.S test-i386-vm86.S -lm
test: test-i386
ifeq ($(ARCH),i386)

View File

@@ -19,7 +19,7 @@ extern inline int write(int fd, const char * buf, int len)
: "0" (__NR_write),"S" ((long)(fd)),"c" ((long)(buf)),"d" ((long)(len)));
}
void _startup(void)
void _start(void)
{
write(1, "Hello World\n", 12);
exit(0);

View File

@@ -125,7 +125,7 @@ int main(int argc, char **argv)
r->es = seg;
r->fs = seg;
r->gs = seg;
r->eflags = (IF_MASK | IOPL_MASK);
r->eflags = VIF_MASK;
/* put return code */
set_bit((uint8_t *)&ctx.int_revectored, 0x21);

104
tests/test-i386-vm86.S Normal file
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:

View File

@@ -1,7 +1,13 @@
#define _GNU_SOURCE
#include <stdlib.h>
#include <stdio.h>
#include <inttypes.h>
#include <math.h>
#include <signal.h>
#include <setjmp.h>
#include <sys/ucontext.h>
#include <sys/mman.h>
#include <asm/vm86.h>
#define TEST_CMOV 0
@@ -707,6 +713,19 @@ uint8_t seg_data2[4096];
#define MK_SEL(n) (((n) << 3) | 7)
#define TEST_LR(op, size, seg, mask)\
{\
int res, res2;\
res = 0x12345678;\
asm (op " %" size "2, %" size "0\n" \
"movl $0, %1\n"\
"jnz 1f\n"\
"movl $1, %1\n"\
"1:\n"\
: "=r" (res), "=r" (res2) : "m" (seg), "0" (res));\
printf(op ": Z=%d %08x\n", res2, res & ~(mask));\
}
/* NOTE: we use Linux modify_ldt syscall */
void test_segs(void)
{
@@ -784,6 +803,16 @@ void test_segs(void)
: "=r" (res), "=g" (res2)
: "m" (segoff));
printf("FS:reg = %04x:%08x\n", res2, res);
TEST_LR("larw", "w", MK_SEL(2), 0x0100);
TEST_LR("larl", "", MK_SEL(2), 0x0100);
TEST_LR("lslw", "w", MK_SEL(2), 0);
TEST_LR("lsll", "", MK_SEL(2), 0);
TEST_LR("larw", "w", 0xfff8, 0);
TEST_LR("larl", "", 0xfff8, 0);
TEST_LR("lslw", "w", 0xfff8, 0);
TEST_LR("lsll", "", 0xfff8, 0);
}
/* 16 bit code test */
@@ -890,6 +919,348 @@ void test_string(void)
TEST_STRING(cmps, "repnz ");
}
/* VM86 test */
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;
}
#undef __syscall_return
#define __syscall_return(type, res) \
do { \
return (type) (res); \
} while (0)
_syscall2(int, vm86, int, func, struct vm86plus_struct *, v86)
extern char vm86_code_start;
extern char vm86_code_end;
#define VM86_CODE_CS 0x100
#define VM86_CODE_IP 0x100
void test_vm86(void)
{
struct vm86plus_struct ctx;
struct vm86_regs *r;
uint8_t *vm86_mem;
int seg, ret;
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) {
printf("ERROR: could not map vm86 memory");
return;
}
memset(&ctx, 0, sizeof(ctx));
/* init basic registers */
r = &ctx.regs;
r->eip = VM86_CODE_IP;
r->esp = 0xfffe;
seg = VM86_CODE_CS;
r->cs = seg;
r->ss = seg;
r->ds = seg;
r->es = seg;
r->fs = seg;
r->gs = seg;
r->eflags = VIF_MASK;
/* move code to proper address. We use the same layout as a .com
dos program. */
memcpy(vm86_mem + (VM86_CODE_CS << 4) + VM86_CODE_IP,
&vm86_code_start, &vm86_code_end - &vm86_code_start);
/* mark int 0x21 as being emulated */
set_bit((uint8_t *)&ctx.int_revectored, 0x21);
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 */
goto the_end;
case 0x02: /* write char */
{
uint8_t c = r->edx;
putchar(c);
}
break;
case 0x09: /* write string */
{
uint8_t c, *ptr;
ptr = seg_to_linear(r->ds, r->edx);
for(;;) {
c = *ptr++;
if (c == '$')
break;
putchar(c);
}
r->eax = (r->eax & ~0xff) | '$';
}
break;
case 0xff: /* extension: write hex number in edx */
printf("%08x\n", (int)r->edx);
break;
default:
unknown_int:
printf("unsupported int 0x%02x\n", int_num);
goto the_end;
}
}
break;
case VM86_SIGNAL:
/* a signal came, we just ignore that */
break;
case VM86_STI:
break;
default:
printf("ERROR: unhandled vm86 return code (0x%x)\n", ret);
goto the_end;
}
}
the_end:
printf("VM86 end\n");
munmap(vm86_mem, 0x110000);
}
/* exception tests */
#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
jmp_buf jmp_env;
int v1;
int tab[2];
void sig_handler(int sig, siginfo_t *info, void *puc)
{
struct ucontext *uc = puc;
printf("si_signo=%d si_errno=%d si_code=%d",
info->si_signo, info->si_errno, info->si_code);
printf(" si_addr=0x%08lx",
(unsigned long)info->si_addr);
printf("\n");
printf("trapno=0x%02x err=0x%08x",
uc->uc_mcontext.gregs[REG_TRAPNO],
uc->uc_mcontext.gregs[REG_ERR]);
printf(" EIP=0x%08x", uc->uc_mcontext.gregs[REG_EIP]);
printf("\n");
longjmp(jmp_env, 1);
}
void test_exceptions(void)
{
struct modify_ldt_ldt_s ldt;
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(SIGBUS, &act, NULL);
sigaction(SIGTRAP, &act, NULL);
/* test division by zero reporting */
printf("DIVZ exception:\n");
if (setjmp(jmp_env) == 0) {
/* now divide by zero */
v1 = 0;
v1 = 2 / v1;
}
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("segment exceptions:\n");
if (setjmp(jmp_env) == 0) {
/* load an invalid segment */
asm volatile ("movl %0, %%fs" : : "r" ((0x1234 << 3) | 1));
}
if (setjmp(jmp_env) == 0) {
/* null data segment is valid */
asm volatile ("movl %0, %%fs" : : "r" (3));
/* null stack segment */
asm volatile ("movl %0, %%ss" : : "r" (3));
}
ldt.entry_number = 1;
ldt.base_addr = (unsigned long)&seg_data1;
ldt.limit = (sizeof(seg_data1) + 0xfff) >> 12;
ldt.seg_32bit = 1;
ldt.contents = MODIFY_LDT_CONTENTS_DATA;
ldt.read_exec_only = 0;
ldt.limit_in_pages = 1;
ldt.seg_not_present = 1;
ldt.useable = 1;
modify_ldt(1, &ldt, sizeof(ldt)); /* write ldt entry */
if (setjmp(jmp_env) == 0) {
/* segment not present */
asm volatile ("movl %0, %%fs" : : "r" (MK_SEL(1)));
}
/* test SEGV reporting */
printf("PF exception:\n");
if (setjmp(jmp_env) == 0) {
val = 1;
/* now store in an invalid address */
*(char *)0x1234 = 1;
}
/* test SEGV reporting */
printf("PF exception:\n");
if (setjmp(jmp_env) == 0) {
val = 1;
/* read from an invalid address */
v1 = *(char *)0x1234;
}
/* test illegal instruction reporting */
printf("UD2 exception:\n");
if (setjmp(jmp_env) == 0) {
/* now execute an invalid instruction */
asm volatile("ud2");
}
printf("INT exception:\n");
if (setjmp(jmp_env) == 0) {
asm volatile ("int $0xfd");
}
if (setjmp(jmp_env) == 0) {
asm volatile ("int $0x01");
}
if (setjmp(jmp_env) == 0) {
asm volatile (".byte 0xcd, 0x03");
}
if (setjmp(jmp_env) == 0) {
asm volatile ("int $0x04");
}
if (setjmp(jmp_env) == 0) {
asm volatile ("int $0x05");
}
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("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"
"movl $0x0, %0\n" : "=m" (val) : : "cc", "memory");
}
printf("val=0x%x\n", val);
}
/* self modifying code test */
uint8_t code[] = {
0xb8, 0x1, 0x00, 0x00, 0x00, /* movl $1, %eax */
0xc3, /* ret */
};
typedef int FuncType(void);
void test_self_modifying_code(void)
{
int i;
printf("self modifying code:\n");
printf("func1 = 0x%x\n", ((FuncType *)code)());
for(i = 2; i <= 4; i++) {
code[1] = i;
printf("func%d = 0x%x\n", i, ((FuncType *)code)());
}
}
static void *call_end __init_call = NULL;
int main(int argc, char **argv)
@@ -913,5 +1284,8 @@ int main(int argc, char **argv)
test_lea();
test_segs();
test_code16();
test_vm86();
test_exceptions();
test_self_modifying_code();
return 0;
}

View File

@@ -26,13 +26,15 @@ void alarm_handler(int sig)
#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\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],
@@ -42,7 +44,9 @@ void dump_regs(struct ucontext *uc)
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_EIP],
uc->uc_mcontext.gregs[REG_TRAPNO],
uc->uc_mcontext.gregs[REG_ERR]);
}
void sig_handler(int sig, siginfo_t *info, void *puc)
@@ -58,19 +62,23 @@ void sig_handler(int sig, siginfo_t *info, void *puc)
}
int v1;
int tab[2];
int main(int argc, char **argv)
{
struct sigaction act;
int i;
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) {
act.sa_sigaction = sig_handler;
sigemptyset(&act.sa_mask);
act.sa_flags = SA_SIGINFO | SA_ONESHOT;
sigaction(SIGFPE, &act, NULL);
/* now divide by zero */
v1 = 0;
v1 = 2 / v1;
@@ -78,33 +86,109 @@ int main(int argc, char **argv)
/* test illegal instruction reporting */
if (setjmp(jmp_env) == 0) {
act.sa_sigaction = sig_handler;
sigemptyset(&act.sa_mask);
act.sa_flags = SA_SIGINFO | SA_ONESHOT;
sigaction(SIGILL, &act, NULL);
/* now execute an invalid instruction */
asm volatile("ud2");
}
/* test SEGV reporting */
if (setjmp(jmp_env) == 0) {
act.sa_sigaction = sig_handler;
sigemptyset(&act.sa_mask);
act.sa_flags = SA_SIGINFO | SA_ONESHOT;
sigaction(SIGSEGV, &act, NULL);
/* now store in an invalid address */
*(char *)0x1234 = 1;
}
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);
/* 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;
}

View File

@@ -70,7 +70,7 @@
#define TARGET_LONG_BITS 32
#if defined(__alpha__)
#if defined(__alpha__) || defined (__ia64__)
#define HOST_LONG_BITS 64
#else
#define HOST_LONG_BITS 32

File diff suppressed because it is too large Load Diff