Compare commits

...

219 Commits

Author SHA1 Message Date
(no author)
be26a5288e This commit was manufactured by cvs2svn to create tag
'release_0_5_1'.

git-svn-id: svn://svn.savannah.nongnu.org/qemu/tags/release_0_5_1@502 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-04 16:10:34 +00:00
bellard
82c7e2a4c6 update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@501 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-04 16:10:33 +00:00
bellard
546cdbd77d first multi target test (lauches 'ls')
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@500 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-04 16:08:39 +00:00
bellard
c265508067 more precise PIT gate emulation
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@499 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-04 16:07:06 +00:00
bellard
dd4e27d810 removed test code
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@498 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-04 15:58:16 +00:00
bellard
a41bc9af8f explicited S3 specific code - added more debug code
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@497 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-04 15:55:00 +00:00
bellard
3bfd9da14f termios support for SPARC and PPC
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@496 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-04 15:52:31 +00:00
bellard
c573ff6752 stat64 fix - added getpagesize()
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@495 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-04 15:51:36 +00:00
bellard
060366c5ad SPARC fixes : syscall fixes - added user register window exception support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@494 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-04 15:50:01 +00:00
bellard
6da41eafc4 added CPU callbacks
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@493 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-04 15:48:38 +00:00
bellard
0124311e00 more generic TLB support - began to fix unlikely interrupt issues
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@492 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-04 15:48:17 +00:00
bellard
f515528907 aligned stack on 16 byte boundary - PPC target fixes - SPARC target fixes
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@491 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-04 15:46:50 +00:00
bellard
b453b70bd8 sparc fixes
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@490 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-04 15:45:21 +00:00
bellard
0ac4bd56a8 float access fixes
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@489 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-04 15:44:17 +00:00
bellard
3811a291e2 update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@488 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-04 15:27:57 +00:00
bellard
3415a4ddb4 invd and wbinvd support - fixed code gen logic for invlpg - simpler exception handling in load_seg()
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@487 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-04 15:21:33 +00:00
bellard
b7f0f463a5 debug fixes - use more generic TLB mappings
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@486 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-04 15:20:25 +00:00
bellard
8e682019e3 correct zero segment values when coming from VM86 mode - cache infos in CPUID - simpler exception handling in load_seg() - validate segments after lret/iret
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@485 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-04 15:18:37 +00:00
bellard
cf495bcf9f SPARC fixes: corrected PC/NPC logic (now slower but can be optimized a lot) - fixed flags computations - added register window exceptions support - fixed mul and div - added mulscc - fixed immediate field decoding
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@484 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-04 15:01:44 +00:00
bellard
fb0eaffc6d PowerPC fixes (Jocelyn Mayer)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@483 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-04 14:57:11 +00:00
bellard
07ad1b93a3 disable keyboard interrupts if keyboard clock disabled (may not be fully correct) - added keyboard ID for extended keyboard
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@482 c046a42c-6fe2-441c-8c8c-71466251a162
2003-12-02 22:18:10 +00:00
bellard
d36cd60e6c P4 style multiplication eflags
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@481 c046a42c-6fe2-441c-8c8c-71466251a162
2003-12-02 22:01:31 +00:00
bellard
5e809a8095 dump irq inhibit flag as it is a part of the cpu state
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@480 c046a42c-6fe2-441c-8c8c-71466251a162
2003-12-02 21:59:21 +00:00
bellard
791c2261d6 more complete eflags testing for multiplication (P4 case only)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@479 c046a42c-6fe2-441c-8c8c-71466251a162
2003-12-02 21:55:34 +00:00
bellard
163a7cb620 imull fix (suggested by Robert J. Harley)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@478 c046a42c-6fe2-441c-8c8c-71466251a162
2003-11-30 19:40:08 +00:00
bellard
6bb705711b a20 fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@477 c046a42c-6fe2-441c-8c8c-71466251a162
2003-11-23 23:26:39 +00:00
bellard
4136f33c7e fixed eflags IF/IOPL update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@476 c046a42c-6fe2-441c-8c8c-71466251a162
2003-11-23 23:09:40 +00:00
bellard
6dca2016fc fixed PPC state reloading
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@475 c046a42c-6fe2-441c-8c8c-71466251a162
2003-11-23 17:32:06 +00:00
bellard
678673089d PowerPC target support (Jocelyn Mayer) - added better support for uid16
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@474 c046a42c-6fe2-441c-8c8c-71466251a162
2003-11-23 17:05:30 +00:00
bellard
28b6751f30 suppressed use of gen_multi - use intermediate FT0 register for floats - use T0 temporary for fpscr update - use PARAM1 for spr access - added untested single load/store support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@473 c046a42c-6fe2-441c-8c8c-71466251a162
2003-11-23 16:58:08 +00:00
bellard
79aceca54a PowerPC support (Jocelyn Mayer)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@472 c046a42c-6fe2-441c-8c8c-71466251a162
2003-11-23 14:55:54 +00:00
bellard
6a8c397deb FTST instruction fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@471 c046a42c-6fe2-441c-8c8c-71466251a162
2003-11-22 23:57:34 +00:00
bellard
9cdf757fd5 more fcmovxx tests
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@470 c046a42c-6fe2-441c-8c8c-71466251a162
2003-11-19 22:12:47 +00:00
bellard
36bdbe5479 fixed TB linking in case of code invalidation (fixes random segfaults)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@469 c046a42c-6fe2-441c-8c8c-71466251a162
2003-11-19 22:12:02 +00:00
bellard
8004340674 added fcmovxx support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@468 c046a42c-6fe2-441c-8c8c-71466251a162
2003-11-19 22:09:03 +00:00
bellard
a2cc3b2433 added fcmovxx support (fixes segfaults in some recent linux tools) - fixed irq inhibit logic : the irqs are inhibited only for one instruction after, even if the next one also inhibit irqs - stop translation after irq inhibition stops to give a chance to irqs (fixes install NT kernel startup)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@467 c046a42c-6fe2-441c-8c8c-71466251a162
2003-11-19 22:08:13 +00:00
bellard
afa05eb15e always completely redefine the TLB in case of MMU fault
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@466 c046a42c-6fe2-441c-8c8c-71466251a162
2003-11-19 22:04:21 +00:00
bellard
de5eaa6452 static config for SDL
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@465 c046a42c-6fe2-441c-8c8c-71466251a162
2003-11-16 23:18:17 +00:00
bellard
7517502475 fcmovx support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@464 c046a42c-6fe2-441c-8c8c-71466251a162
2003-11-16 20:18:52 +00:00
bellard
8f2b1fb008 more hack for CMOS interruption (enable linux /dev/rtc not to hang) - auto boot on cdrom if only device present
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@463 c046a42c-6fe2-441c-8c8c-71466251a162
2003-11-16 19:46:01 +00:00
bellard
891b38e446 more precise stack operations in call/int gates (16 bit wrapping is handled in all cases) - makes all call/int gates operations restartable in case of exception
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@462 c046a42c-6fe2-441c-8c8c-71466251a162
2003-11-16 16:06:03 +00:00
bellard
7dea1da4ae quick and dirty CMOS irq emulation (windows install uses it) - emm386 keyboard fix (need a better way...) - better serial emulation (windows install uses it) - LDT and TR caches init fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@461 c046a42c-6fe2-441c-8c8c-71466251a162
2003-11-16 15:59:30 +00:00
bellard
4ce900b44c make windows happier
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@460 c046a42c-6fe2-441c-8c8c-71466251a162
2003-11-16 15:46:05 +00:00
bellard
f3f2d9be03 call gate fix - verr and verw fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@459 c046a42c-6fe2-441c-8c8c-71466251a162
2003-11-13 23:15:36 +00:00
bellard
77729c2445 fixed pop %sp bug
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@458 c046a42c-6fe2-441c-8c8c-71466251a162
2003-11-13 23:09:07 +00:00
bellard
d71b9a8b2f fixed lmsw instruction
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@457 c046a42c-6fe2-441c-8c8c-71466251a162
2003-11-13 02:48:18 +00:00
bellard
181f1558cd update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@456 c046a42c-6fe2-441c-8c8c-71466251a162
2003-11-13 01:47:16 +00:00
bellard
2750332396 Soundblaster 16 support (malc)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@455 c046a42c-6fe2-441c-8c8c-71466251a162
2003-11-13 01:46:15 +00:00
bellard
f115e911d7 iret and int fix for vm86 - added undefined instructions for real and vm86 modes - added verr, verrw, arpl - added port io map
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@454 c046a42c-6fe2-441c-8c8c-71466251a162
2003-11-13 01:43:28 +00:00
bellard
3ab493de4c added verr, verw, arpl - more precise segment rights checks
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@453 c046a42c-6fe2-441c-8c8c-71466251a162
2003-11-13 01:42:19 +00:00
bellard
3e25f9515a io map checks
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@452 c046a42c-6fe2-441c-8c8c-71466251a162
2003-11-13 00:13:08 +00:00
bellard
246d897f4c dump more registers
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@451 c046a42c-6fe2-441c-8c8c-71466251a162
2003-11-12 23:55:40 +00:00
bellard
7e84c2498f full TSS support - IO map check support - conforming segment check fixes - iret in vm86 mode fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@450 c046a42c-6fe2-441c-8c8c-71466251a162
2003-11-12 23:39:19 +00:00
bellard
e670b89e3b added comments and TSS bit
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@449 c046a42c-6fe2-441c-8c8c-71466251a162
2003-11-12 23:23:42 +00:00
bellard
bd0d90b21d make Knoppix CD-ROM probe happy
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@448 c046a42c-6fe2-441c-8c8c-71466251a162
2003-11-12 22:23:01 +00:00
bellard
1a0636f8d7 new VGA bios
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@447 c046a42c-6fe2-441c-8c8c-71466251a162
2003-11-11 14:20:17 +00:00
bellard
2e134c9c55 64-bit multiplication fix (Ulrich Hecht)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@446 c046a42c-6fe2-441c-8c8c-71466251a162
2003-11-11 13:55:33 +00:00
bellard
5391d80669 moved IDE driver to ide.c
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@445 c046a42c-6fe2-441c-8c8c-71466251a162
2003-11-11 13:48:59 +00:00
bellard
36b486bb74 hardware level IDE CD-ROM emulation - added second IDE interface for up to 4 IDE disks emulation - added -boot command to enable CD boot
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@444 c046a42c-6fe2-441c-8c8c-71466251a162
2003-11-11 13:36:08 +00:00
bellard
4ad06a29b2 soft mmu fix (aka debian random seg fault fix)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@443 c046a42c-6fe2-441c-8c8c-71466251a162
2003-11-09 16:58:12 +00:00
bellard
e58143b355 ppc fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@442 c046a42c-6fe2-441c-8c8c-71466251a162
2003-11-09 14:42:54 +00:00
bellard
1f5476fcce a20 support - keyboard led fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@441 c046a42c-6fe2-441c-8c8c-71466251a162
2003-11-04 23:35:20 +00:00
bellard
461c0471af a20 support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@440 c046a42c-6fe2-441c-8c8c-71466251a162
2003-11-04 23:34:23 +00:00
bellard
9c3ad57432 update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@439 c046a42c-6fe2-441c-8c8c-71466251a162
2003-11-04 23:33:13 +00:00
bellard
e748ba4f53 ARM half word load/store fix (Ulrich Hecht)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@438 c046a42c-6fe2-441c-8c8c-71466251a162
2003-11-03 22:25:25 +00:00
bellard
b8ed223bfe big endian fixes
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@437 c046a42c-6fe2-441c-8c8c-71466251a162
2003-10-30 22:10:22 +00:00
bellard
c970a162e7 temporary hack for PowerPC system emulation
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@436 c046a42c-6fe2-441c-8c8c-71466251a162
2003-10-30 01:21:44 +00:00
bellard
c321f67309 enabled system emulator build on PowerPC - increased portability of soft mmu code
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@435 c046a42c-6fe2-441c-8c8c-71466251a162
2003-10-30 01:18:42 +00:00
bellard
7f7f987341 endianness and portability fixes
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@434 c046a42c-6fe2-441c-8c8c-71466251a162
2003-10-30 01:11:23 +00:00
bellard
aebcb60e55 no need for locks in system mode
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@433 c046a42c-6fe2-441c-8c8c-71466251a162
2003-10-30 01:08:17 +00:00
bellard
1a18c71b50 unused functions in system mode
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@432 c046a42c-6fe2-441c-8c8c-71466251a162
2003-10-30 01:07:51 +00:00
bellard
03a6c5103d cannot simply write segment registers in system mode
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@431 c046a42c-6fe2-441c-8c8c-71466251a162
2003-10-30 01:07:22 +00:00
bellard
128b346e0a cmov fix (bug on PowerPC)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@430 c046a42c-6fe2-441c-8c8c-71466251a162
2003-10-30 01:05:49 +00:00
bellard
415fa2ea77 soft MMU performance fix (oops)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@429 c046a42c-6fe2-441c-8c8c-71466251a162
2003-10-30 00:39:38 +00:00
bellard
9951bf39f9 fixed long double accesses when using soft MMU
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@428 c046a42c-6fe2-441c-8c8c-71466251a162
2003-10-28 23:06:17 +00:00
bellard
8948b5d613 fixed ldq() macros
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@427 c046a42c-6fe2-441c-8c8c-71466251a162
2003-10-28 23:04:30 +00:00
bellard
5086347239 CONFIG_STATIC patch
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@426 c046a42c-6fe2-441c-8c8c-71466251a162
2003-10-28 23:04:01 +00:00
bellard
9d4520d0e0 update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@425 c046a42c-6fe2-441c-8c8c-71466251a162
2003-10-28 01:38:57 +00:00
bellard
5b9f457a89 update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@424 c046a42c-6fe2-441c-8c8c-71466251a162
2003-10-28 00:49:54 +00:00
bellard
3a4739d651 static link
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@423 c046a42c-6fe2-441c-8c8c-71466251a162
2003-10-28 00:48:22 +00:00
bellard
76b62fd001 added binary archive
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@422 c046a42c-6fe2-441c-8c8c-71466251a162
2003-10-28 00:47:44 +00:00
bellard
b1f645758a redhat 9 fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@421 c046a42c-6fe2-441c-8c8c-71466251a162
2003-10-28 00:47:19 +00:00
bellard
bc1b050d85 fixed distclean target
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@420 c046a42c-6fe2-441c-8c8c-71466251a162
2003-10-28 00:12:52 +00:00
bellard
03d5f74aee update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@419 c046a42c-6fe2-441c-8c8c-71466251a162
2003-10-28 00:09:43 +00:00
bellard
9f05cc34df fixed big endian ops
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@418 c046a42c-6fe2-441c-8c8c-71466251a162
2003-10-28 00:09:28 +00:00
bellard
285dc330bd update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@417 c046a42c-6fe2-441c-8c8c-71466251a162
2003-10-27 23:58:04 +00:00
bellard
baf8ebf01a fixed virtual memory access
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@416 c046a42c-6fe2-441c-8c8c-71466251a162
2003-10-27 23:57:40 +00:00
bellard
9d16dd550e make cpu test static
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@415 c046a42c-6fe2-441c-8c8c-71466251a162
2003-10-27 23:56:59 +00:00
bellard
78d6da976c license
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@414 c046a42c-6fe2-441c-8c8c-71466251a162
2003-10-27 23:55:20 +00:00
bellard
dd6ee15c37 fixed idt/gdt relocation bug - added support for Redhat kernels
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@413 c046a42c-6fe2-441c-8c8c-71466251a162
2003-10-27 23:36:59 +00:00
bellard
0db634747e qemu with softmmu is now the default executable
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@412 c046a42c-6fe2-441c-8c8c-71466251a162
2003-10-27 21:37:46 +00:00
bellard
6e59c1db89 full soft mmu support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@411 c046a42c-6fe2-441c-8c8c-71466251a162
2003-10-27 21:24:54 +00:00
bellard
61382a500a full softmmu support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@410 c046a42c-6fe2-441c-8c8c-71466251a162
2003-10-27 21:22:23 +00:00
bellard
3a51dee658 disabled signal hacks for softmmu version (qemu should be much more portable now...)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@409 c046a42c-6fe2-441c-8c8c-71466251a162
2003-10-27 21:18:35 +00:00
bellard
cc38b844d7 factorized debug code
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@408 c046a42c-6fe2-441c-8c8c-71466251a162
2003-10-27 21:16:14 +00:00
bellard
c6105c0a04 added correct memory access code for system emulation
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@407 c046a42c-6fe2-441c-8c8c-71466251a162
2003-10-27 21:13:58 +00:00
bellard
93a40ea926 fixed mmu fault priviledge logic
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@406 c046a42c-6fe2-441c-8c8c-71466251a162
2003-10-27 21:13:06 +00:00
bellard
db8d746688 comments
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@405 c046a42c-6fe2-441c-8c8c-71466251a162
2003-10-27 21:12:17 +00:00
bellard
997344f303 added i386 user only target
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@404 c046a42c-6fe2-441c-8c8c-71466251a162
2003-10-27 21:10:39 +00:00
bellard
16e9b7de41 filename fixes
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@403 c046a42c-6fe2-441c-8c8c-71466251a162
2003-10-27 21:09:52 +00:00
bellard
3486513433 log activation from gdb - gdb single step support for x86 - stop timer when cpu is being debugged
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@402 c046a42c-6fe2-441c-8c8c-71466251a162
2003-10-05 14:28:56 +00:00
bellard
0806e3f66f updated
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@401 c046a42c-6fe2-441c-8c8c-71466251a162
2003-10-01 00:15:32 +00:00
bellard
39b4da28b3 bios binary images
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@400 c046a42c-6fe2-441c-8c8c-71466251a162
2003-10-01 00:14:04 +00:00
bellard
5a67135a0b automatic man page generation - BIOS installation
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@399 c046a42c-6fe2-441c-8c8c-71466251a162
2003-10-01 00:13:48 +00:00
bellard
42f1e0e49b tun-fd option support for external tundev config (Rusty Russell)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@398 c046a42c-6fe2-441c-8c8c-71466251a162
2003-09-30 22:11:17 +00:00
bellard
27c3f2cb9b buffer overflow fix - handle case where stdin is closed (Rusty Russell)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@397 c046a42c-6fe2-441c-8c8c-71466251a162
2003-09-30 21:40:47 +00:00
bellard
a07cf92aed multiscan/doublescan fix (malc)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@396 c046a42c-6fe2-441c-8c8c-71466251a162
2003-09-30 21:29:03 +00:00
bellard
01e3b763a6 removed SIGIOT
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@395 c046a42c-6fe2-441c-8c8c-71466251a162
2003-09-30 21:10:14 +00:00
bellard
0ae04d7367 allow Ctrl-C to be pressed when using gdb stub and SDL
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@394 c046a42c-6fe2-441c-8c8c-71466251a162
2003-09-30 21:09:16 +00:00
bellard
ebc054881f added utime syscall - fixed nanosleep exact behaviour
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@393 c046a42c-6fe2-441c-8c8c-71466251a162
2003-09-30 21:08:41 +00:00
bellard
a20dd508aa simplified invocation - added automatic IDE disk geometry guessing to reuse old disk images directly
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@392 c046a42c-6fe2-441c-8c8c-71466251a162
2003-09-30 21:07:02 +00:00
bellard
6180a1818a new directory structure
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@391 c046a42c-6fe2-441c-8c8c-71466251a162
2003-09-30 21:04:53 +00:00
bellard
d3eead2eec new directory structure
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@390 c046a42c-6fe2-441c-8c8c-71466251a162
2003-09-30 20:59:51 +00:00
bellard
853d6f7a83 sparc support - hack to fix case where real_host_page_size < TARGET_PAGE_SIZE (typically sparc target case)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@389 c046a42c-6fe2-441c-8c8c-71466251a162
2003-09-30 20:58:32 +00:00
bellard
93ac68bca5 sparc emulation target (thanx to Thomas M. Ogrisegg)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@388 c046a42c-6fe2-441c-8c8c-71466251a162
2003-09-30 20:57:29 +00:00
bellard
1e43adfc89 new directory structure - changed naming of qemu and vl
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@387 c046a42c-6fe2-441c-8c8c-71466251a162
2003-09-30 20:54:24 +00:00
bellard
7a3f194486 sparc emulation target (thanx to Thomas M. Ogrisegg)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@386 c046a42c-6fe2-441c-8c8c-71466251a162
2003-09-30 20:36:07 +00:00
bellard
2c0262afa7 new directory structure
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@385 c046a42c-6fe2-441c-8c8c-71466251a162
2003-09-30 20:34:21 +00:00
bellard
196ad10903 portable Linux test
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@384 c046a42c-6fe2-441c-8c8c-71466251a162
2003-09-28 18:59:32 +00:00
bellard
b7dda06abf Redhat 9 fixes
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@383 c046a42c-6fe2-441c-8c8c-71466251a162
2003-09-17 22:57:56 +00:00
bellard
fcf8fcc8e5 update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@382 c046a42c-6fe2-441c-8c8c-71466251a162
2003-09-17 22:56:56 +00:00
bellard
dbc5594cb6 finished simplifying string operations - correct TF flag handling for string operations and ss loading - simplified basic block exit code generation
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@381 c046a42c-6fe2-441c-8c8c-71466251a162
2003-09-17 22:56:30 +00:00
bellard
4cbb86e1c4 added JUMP_TB2 for a third basic block exit jump point
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@380 c046a42c-6fe2-441c-8c8c-71466251a162
2003-09-17 22:53:29 +00:00
bellard
f513a41a3d finished simplifying string operations
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@379 c046a42c-6fe2-441c-8c8c-71466251a162
2003-09-17 22:52:47 +00:00
bellard
c106152d26 added two more jump points
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@378 c046a42c-6fe2-441c-8c8c-71466251a162
2003-09-17 22:51:45 +00:00
bellard
facc68be25 removed x86 hacks
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@377 c046a42c-6fe2-441c-8c8c-71466251a162
2003-09-17 22:51:18 +00:00
bellard
3ff0631ed9 added linux < 2.4.21 vm86 bug workaround - added extensive TF flag test
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@376 c046a42c-6fe2-441c-8c8c-71466251a162
2003-09-17 22:49:51 +00:00
bellard
b1ba65744e depth 32 fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@375 c046a42c-6fe2-441c-8c8c-71466251a162
2003-09-16 21:47:08 +00:00
bellard
b67d59594e glibc 2.3.x fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@374 c046a42c-6fe2-441c-8c8c-71466251a162
2003-09-16 21:46:04 +00:00
bellard
2e255c6b9f faster and more accurate segment handling
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@373 c046a42c-6fe2-441c-8c8c-71466251a162
2003-08-21 23:25:21 +00:00
bellard
3f33731662 pop ss, mov ss, x and sti disable irqs for the next instruction - began dispatch optimization by adding new x86 cpu 'hidden' flags
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@372 c046a42c-6fe2-441c-8c8c-71466251a162
2003-08-20 23:02:09 +00:00
bellard
d05e66d217 no error code if hardware interrupt
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@371 c046a42c-6fe2-441c-8c8c-71466251a162
2003-08-20 21:34:35 +00:00
bellard
2d80ae8987 avoid problems if make clean was not made before updating
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@370 c046a42c-6fe2-441c-8c8c-71466251a162
2003-08-11 23:01:33 +00:00
bellard
17383a2a2a gcc 3.x is mandatory now on PowerPC
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@369 c046a42c-6fe2-441c-8c8c-71466251a162
2003-08-11 22:28:58 +00:00
bellard
9257a9e49c workaround for gcc 3.3 bug or overoptimisation if a label is not used
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@368 c046a42c-6fe2-441c-8c8c-71466251a162
2003-08-11 22:21:18 +00:00
bellard
70a194b930 fixed invalid Linux asm/unistd.h header for PowerPC and gcc 3.3
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@367 c046a42c-6fe2-441c-8c8c-71466251a162
2003-08-11 22:20:16 +00:00
bellard
2573109866 pass function name to JMUP_TB()
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@366 c046a42c-6fe2-441c-8c8c-71466251a162
2003-08-11 22:19:11 +00:00
bellard
9dfa5b421d 64 bit fixes (Falk Hueffner)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@365 c046a42c-6fe2-441c-8c8c-71466251a162
2003-08-11 20:35:58 +00:00
bellard
9da8ba18e6 mode X double scan fix (malc)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@364 c046a42c-6fe2-441c-8c8c-71466251a162
2003-08-11 20:33:04 +00:00
bellard
76bc683820 updated
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@363 c046a42c-6fe2-441c-8c8c-71466251a162
2003-08-10 23:41:46 +00:00
bellard
3b22c4707d fixed invalid ESP usage (Jon Nall)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@362 c046a42c-6fe2-441c-8c8c-71466251a162
2003-08-10 23:40:50 +00:00
bellard
96e6e05372 fixed invalid code gen
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@361 c046a42c-6fe2-441c-8c8c-71466251a162
2003-08-10 23:39:55 +00:00
bellard
e2222c3924 removed warnings
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@360 c046a42c-6fe2-441c-8c8c-71466251a162
2003-08-10 23:39:03 +00:00
bellard
31e8f3c894 PowerPC fix (Jon Nall)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@359 c046a42c-6fe2-441c-8c8c-71466251a162
2003-08-10 22:52:34 +00:00
bellard
9368caf64d updated
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@358 c046a42c-6fe2-441c-8c8c-71466251a162
2003-08-10 22:15:31 +00:00
bellard
38e584a072 m68k host port (Richard Zidlicky)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@357 c046a42c-6fe2-441c-8c8c-71466251a162
2003-08-10 22:14:22 +00:00
bellard
313aa56710 added VGA emulation - added PS/2 mouse and keyboard emulation - use SDL for VGA display
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@356 c046a42c-6fe2-441c-8c8c-71466251a162
2003-08-10 21:52:11 +00:00
bellard
4cbf74b6b8 soft mmu support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@355 c046a42c-6fe2-441c-8c8c-71466251a162
2003-08-10 21:48:43 +00:00
bellard
33417e7025 soft mmu support - Memory I/O API - synthetize string instructions
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@354 c046a42c-6fe2-441c-8c8c-71466251a162
2003-08-10 21:47:01 +00:00
bellard
4021dab059 soft mmu support - moved unrelated code to help2-i386.c - synthetize string instructions
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@353 c046a42c-6fe2-441c-8c8c-71466251a162
2003-08-10 21:41:46 +00:00
bellard
626df76abb build all targets at the same time
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@352 c046a42c-6fe2-441c-8c8c-71466251a162
2003-08-10 21:39:31 +00:00
bellard
abcd5da72e use bswap.h
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@351 c046a42c-6fe2-441c-8c8c-71466251a162
2003-08-10 21:38:48 +00:00
bellard
97a847bc03 build all targets at the same time - SDL probe support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@350 c046a42c-6fe2-441c-8c8c-71466251a162
2003-08-10 21:36:04 +00:00
bellard
ab93bbe2ae soft mmu support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@349 c046a42c-6fe2-441c-8c8c-71466251a162
2003-08-10 21:35:13 +00:00
bellard
0f0b726444 SDL support for VGA, keyboard and mouse
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@348 c046a42c-6fe2-441c-8c8c-71466251a162
2003-08-09 18:26:36 +00:00
bellard
b92e5a22ec Software MMU support (used for memory mapped devices such as VGA)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@347 c046a42c-6fe2-441c-8c8c-71466251a162
2003-08-08 23:58:05 +00:00
bellard
17b0018b42 Full VGA support, including old CGA modes, VGA planar and mode X
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@346 c046a42c-6fe2-441c-8c8c-71466251a162
2003-08-08 23:50:57 +00:00
bellard
39cf780327 fixed graphical VGA 16 color mode - fixed 9 pixel wide text mode
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@345 c046a42c-6fe2-441c-8c8c-71466251a162
2003-08-05 23:06:22 +00:00
bellard
e89f66eca9 Hardware level VGA emulation (only text mode is tested)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@344 c046a42c-6fe2-441c-8c8c-71466251a162
2003-08-04 23:30:47 +00:00
bellard
b6d78bfa0d correct CPL support (should fix flat real mode support)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@343 c046a42c-6fe2-441c-8c8c-71466251a162
2003-07-29 20:53:01 +00:00
bellard
c33a346edf first part of single stepping support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@342 c046a42c-6fe2-441c-8c8c-71466251a162
2003-07-29 20:50:33 +00:00
bellard
61a2ad53cb refresh clock dummy emulation (netbsd boot fix)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@341 c046a42c-6fe2-441c-8c8c-71466251a162
2003-07-27 22:19:00 +00:00
bellard
2c1794c42e more generic ljmp and lcall - fixed REPNZ usage for non compare string ops (FreeDos boot loader fix)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@340 c046a42c-6fe2-441c-8c8c-71466251a162
2003-07-27 21:11:27 +00:00
bellard
8a4c1cc411 fixed ss segment load - added ICEBP instruction
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@339 c046a42c-6fe2-441c-8c8c-71466251a162
2003-07-26 20:34:00 +00:00
bellard
330d0414a5 keyboard emulation - accepts to boot with Bochs BIOS and LGPL'ed VGA BIOS
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@338 c046a42c-6fe2-441c-8c8c-71466251a162
2003-07-26 18:11:40 +00:00
bellard
3802ce26a1 set to protected mode
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@337 c046a42c-6fe2-441c-8c8c-71466251a162
2003-07-26 18:02:28 +00:00
bellard
4abe615b84 removed debug
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@336 c046a42c-6fe2-441c-8c8c-71466251a162
2003-07-26 18:01:58 +00:00
bellard
a412ac572f real mode support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@335 c046a42c-6fe2-441c-8c8c-71466251a162
2003-07-26 18:01:40 +00:00
bellard
b2b5fb228f popw (%esp) test)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@334 c046a42c-6fe2-441c-8c8c-71466251a162
2003-07-26 18:00:58 +00:00
bellard
8f186479e2 real mode support (now boots from BOCHS BIOS and LGPL'ed VGA BIOS)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@333 c046a42c-6fe2-441c-8c8c-71466251a162
2003-07-26 17:59:00 +00:00
bellard
4c3a88a284 gdb stub breakpoints support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@332 c046a42c-6fe2-441c-8c8c-71466251a162
2003-07-26 12:06:08 +00:00
bellard
d6b4936796 update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@331 c046a42c-6fe2-441c-8c8c-71466251a162
2003-07-13 22:37:44 +00:00
bellard
9d0fe224f4 update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@330 c046a42c-6fe2-441c-8c8c-71466251a162
2003-07-13 22:08:50 +00:00
bellard
6e0374f6b5 debug print
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@329 c046a42c-6fe2-441c-8c8c-71466251a162
2003-07-13 17:34:37 +00:00
bellard
9e5f5284b3 convert signal numbers
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@328 c046a42c-6fe2-441c-8c8c-71466251a162
2003-07-13 17:33:54 +00:00
bellard
c596ed1713 times() fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@327 c046a42c-6fe2-441c-8c8c-71466251a162
2003-07-13 17:32:31 +00:00
bellard
91cf4d88fb gcc 3.2.2 bug workaround (RedHat 9 fix)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@326 c046a42c-6fe2-441c-8c8c-71466251a162
2003-07-13 17:31:01 +00:00
bellard
a96fc003bd sparc fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@325 c046a42c-6fe2-441c-8c8c-71466251a162
2003-07-13 17:30:15 +00:00
bellard
d44b29c21e address printing fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@324 c046a42c-6fe2-441c-8c8c-71466251a162
2003-07-13 17:29:55 +00:00
bellard
070893f425 RedHat 9 fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@323 c046a42c-6fe2-441c-8c8c-71466251a162
2003-07-13 17:27:19 +00:00
bellard
9621339dca changed basic block exit generation
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@322 c046a42c-6fe2-441c-8c8c-71466251a162
2003-07-11 15:17:41 +00:00
bellard
ede28208d8 added nop test for exception
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@321 c046a42c-6fe2-441c-8c8c-71466251a162
2003-07-11 14:49:58 +00:00
bellard
7739f36e38 fixed EIP exception bug in case of nop operations (kernel 2.5.74 copy_from_user() bug)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@320 c046a42c-6fe2-441c-8c8c-71466251a162
2003-07-11 14:49:22 +00:00
bellard
f8c8799840 added return for ARM case (may be incorrect - need checking)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@319 c046a42c-6fe2-441c-8c8c-71466251a162
2003-07-09 19:41:41 +00:00
bellard
43fff2384e ARM signal support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@318 c046a42c-6fe2-441c-8c8c-71466251a162
2003-07-09 19:31:39 +00:00
bellard
1b21b62ab4 ARM fixes
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@317 c046a42c-6fe2-441c-8c8c-71466251a162
2003-07-09 17:16:27 +00:00
bellard
a1516e92b6 ARM init fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@316 c046a42c-6fe2-441c-8c8c-71466251a162
2003-07-09 17:13:37 +00:00
bellard
6fb883e8e3 ARM fix: mmap
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@315 c046a42c-6fe2-441c-8c8c-71466251a162
2003-07-09 17:12:39 +00:00
bellard
6e295807ac ARM fixes
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@314 c046a42c-6fe2-441c-8c8c-71466251a162
2003-07-09 17:10:32 +00:00
bellard
f2674e31e0 old select support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@313 c046a42c-6fe2-441c-8c8c-71466251a162
2003-07-09 12:26:09 +00:00
bellard
4690764bba update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@312 c046a42c-6fe2-441c-8c8c-71466251a162
2003-07-07 12:17:46 +00:00
bellard
3c1cf9fa86 dummy rdmsr and wrmsr support - xor reg, reg optimization
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@311 c046a42c-6fe2-441c-8c8c-71466251a162
2003-07-07 11:30:47 +00:00
bellard
1f47a9223e added disk image help
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@310 c046a42c-6fe2-441c-8c8c-71466251a162
2003-07-06 19:01:55 +00:00
bellard
33e3963e1b added user mode Linux Copy On Write disk image support - added -snapshot support (initial patch by Rusty Russell)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@309 c046a42c-6fe2-441c-8c8c-71466251a162
2003-07-06 17:15:21 +00:00
bellard
cd4c3e888a added IDE WIN_READ_NATIVE_MAX command (2.5.xx fix) - added support for proper system shutdown
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@308 c046a42c-6fe2-441c-8c8c-71466251a162
2003-07-04 14:38:25 +00:00
bellard
7916e2245d allow up to 256 MB of ram
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@307 c046a42c-6fe2-441c-8c8c-71466251a162
2003-07-01 16:27:45 +00:00
bellard
abd0aaff03 fixed date storage in CMOS
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@306 c046a42c-6fe2-441c-8c8c-71466251a162
2003-07-01 15:07:57 +00:00
bellard
c39d5b78f6 make FPU load exception safe
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@305 c046a42c-6fe2-441c-8c8c-71466251a162
2003-07-01 15:07:14 +00:00
bellard
4d40895f2c more accurate bcd convert - fixed FPU exceptions
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@304 c046a42c-6fe2-441c-8c8c-71466251a162
2003-07-01 15:05:19 +00:00
bellard
e477b8b81b correct eflags evaluation order for all operations - fixed important CPU state restoring bug in some exception cases - disabled unsafe inc flags optimisation
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@303 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-30 23:36:57 +00:00
bellard
b118d61e55 added PIC debug
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@302 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-30 23:36:21 +00:00
bellard
2f62b397b5 dummy label to avoid gcc optimisations
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@301 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-30 23:18:59 +00:00
bellard
907a5b2690 fixed invalid irq jump chaining
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@300 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-30 23:18:22 +00:00
bellard
0849bf0821 allow read only images
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@299 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-30 23:17:31 +00:00
bellard
305034817d removed unused assignment
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@298 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-30 23:17:08 +00:00
bellard
ec410fc9ce update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@297 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-30 23:16:33 +00:00
bellard
68a7931591 reduced irq latency
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@296 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-30 13:12:32 +00:00
bellard
c9159e5321 added IDE mult support - reduced irq latency (IDE should have good performances now)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@295 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-30 13:06:39 +00:00
bellard
8c9b861e74 added block.c
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@294 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-30 10:12:19 +00:00
bellard
5797fa5d7e first step to fix precise eflags update in case of exception
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@293 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-30 10:11:50 +00:00
bellard
8ef9a8ece3 added nop operations
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@292 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-30 10:04:47 +00:00
bellard
fc01f7e7f9 IDE emulation
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@291 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-30 10:03:06 +00:00
bellard
3b0dca51b0 gdb stub defines
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@290 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-27 18:52:23 +00:00
bellard
da415d54bf gdb usage information
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@289 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-27 18:50:50 +00:00
bellard
b4608c0455 added gdb support to vl
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@288 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-27 17:34:32 +00:00
bellard
d5a0b50c6f update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@287 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-27 12:02:03 +00:00
bellard
87858c89ca more precise timer emulation - fixed NE2000 probe problems - added VLTMPDIR support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@286 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-27 12:01:39 +00:00
bellard
a6f816d697 fixed endianness (Jocelyn Mayer)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@285 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-26 17:09:07 +00:00
bellard
0ad041d476 fixed inline pb
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@284 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-25 22:11:41 +00:00
97 changed files with 28187 additions and 5541 deletions

View File

@@ -1,3 +1,63 @@
version 0.5.1:
- float access fixes when using soft mmu
- PC emulation support on PowerPC
- A20 support
- IDE CD-ROM emulation
- ARM fixes (Ulrich Hecht)
- SB16 emulation (malc)
- IRET and INT fixes in VM86 mode with IOPL=3
- Port I/Os use TSS io map
- Full task switching/task gate support
- added verr, verw, arpl, fcmovxx
- PowerPC target support (Jocelyn Mayer)
- Major SPARC target fixes (dynamically linked programs begin to work)
version 0.5.0:
- full hardware level VGA emulation
- graphical display with SDL
- added PS/2 mouse and keyboard emulation
- popw (%esp) fix
- mov to/from segment data width fix
- added real mode support
- added Bochs BIOS and LGPL'ed VGA BIOS loader in qemu
- m68k host port (Richard Zidlicky)
- partial soft MMU support for memory mapped I/Os
- multi-target build
- fixed: no error code in hardware interrupts
- fixed: pop ss, mov ss, x and sti disable hardware irqs for the next insn
- correct single stepping thru string operations
- preliminary SPARC target support (Thomas M. Ogrisegg)
- tun-fd option (Rusty Russell)
- automatic IDE geometry detection
- renamed 'vl' to qemu[-fast] and user qemu to qemu-{cpu}.
- added man page
- added full soft mmu mode to launch unpatched OSes.
version 0.4.3:
- x86 exception fix in case of nop instruction.
- gcc 3.2.2 bug workaround (RedHat 9 fix)
- sparc and Alpha host fixes
- many ARM target fixes: 'ls' and 'bash' can be launched.
version 0.4.2:
- many exception handling fixes (can compile a Linux kernel inside vl)
- IDE emulation support
- initial GDB stub support
- deferred update support for disk images (Rusty Russell)
- accept User Mode Linux Copy On Write disk images
- SMP kernels can at least be booted
version 0.4.1:
- more accurate timer support in vl.
- more reliable NE2000 probe in vl.
- added 2.5.66 kernel in vl-test.
- added VLTMPDIR environment variable in vl.
version 0.4:
- initial support for ring 0 x86 processor emulation

262
Makefile
View File

@@ -1,198 +1,52 @@
include config.mak
include config-host.mak
CFLAGS=-Wall -O2 -g
LDFLAGS=-g
LIBS=
DEFINES=-DHAVE_BYTESWAP_H
HELPER_CFLAGS=$(CFLAGS)
PROGS=qemu
ifdef CONFIG_STATIC
LDFLAGS+=-static
endif
ifeq ($(ARCH),i386)
CFLAGS+=-fomit-frame-pointer
OP_CFLAGS=$(CFLAGS) -mpreferred-stack-boundary=2
ifeq ($(HAVE_GCC3_OPTIONS),yes)
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
ifeq ($(TARGET_ARCH), i386)
PROGS+=vl
endif
endif
ifeq ($(ARCH),ppc)
OP_CFLAGS=$(CFLAGS)
LDFLAGS+=-Wl,-T,ppc.ld
endif
ifeq ($(ARCH),s390)
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
HELPER_CFLAGS=$(CFLAGS) -ffixed-i0 -mflat
LDFLAGS+=-Wl,-T,sparc.ld
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
LDFLAGS+=-Wl,-T,alpha.ld
endif
ifeq ($(ARCH),ia64)
OP_CFLAGS=$(CFLAGS)
endif
ifeq ($(ARCH),arm)
OP_CFLAGS=$(CFLAGS) -mno-sched-prolog
LDFLAGS+=-Wl,-T,arm.ld
endif
ifeq ($(HAVE_GCC3_OPTIONS),yes)
# very important to generate a return at the end of every operation
OP_CFLAGS+=-fno-reorder-blocks -fno-optimize-sibling-calls
endif
#########################################################
DEFINES+=-D_GNU_SOURCE
LIBS+=-lm
TOOLS=qemu-mkcow
# profiling code
ifdef TARGET_GPROF
LDFLAGS+=-p
main.o: CFLAGS+=-p
endif
all: dyngen $(TOOLS) qemu-doc.html qemu.1
for d in $(TARGET_DIRS); do \
make -C $$d $@ || exit 1 ; \
done
OBJS= elfload.o main.o syscall.o mmap.o signal.o path.o
ifeq ($(TARGET_ARCH), i386)
OBJS+= vm86.o
endif
SRCS:= $(OBJS:.o=.c)
OBJS+= libqemu.a
qemu-mkcow: qemu-mkcow.o
$(HOST_CC) -o $@ $^ $(LIBS)
# cpu emulator library
LIBOBJS=thunk.o exec.o translate.o cpu-exec.o
ifeq ($(TARGET_ARCH), i386)
LIBOBJS+=translate-i386.o op-i386.o helper-i386.o
endif
ifeq ($(TARGET_ARCH), arm)
LIBOBJS+=translate-arm.o op-arm.o
endif
# NOTE: the disassembler code is only needed for debugging
LIBOBJS+=disas.o
ifeq ($(findstring i386, $(TARGET_ARCH) $(ARCH)),i386)
LIBOBJS+=i386-dis.o
endif
ifeq ($(findstring alpha, $(TARGET_ARCH) $(ARCH)),alpha)
LIBOBJS+=alpha-dis.o
endif
ifeq ($(findstring ppc, $(TARGET_ARCH) $(ARCH)),ppc)
LIBOBJS+=ppc-dis.o
endif
ifeq ($(findstring sparc, $(TARGET_ARCH) $(ARCH)),sparc)
LIBOBJS+=sparc-dis.o
endif
ifeq ($(findstring arm, $(TARGET_ARCH) $(ARCH)),arm)
LIBOBJS+=arm-dis.o
endif
ifeq ($(ARCH),ia64)
OBJS += ia64-syscall.o
endif
all: $(PROGS) 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
# must use static linking to avoid leaving stuff in virtual address space
vl: vl.o libqemu.a
$(CC) -static -Wl,-T,i386-vl.ld -o $@ $^ $(LIBS)
depend: $(SRCS)
$(CC) -MM $(CFLAGS) $^ 1>.depend
# libqemu
libqemu.a: $(LIBOBJS)
rm -f $@
$(AR) rcs $@ $(LIBOBJS)
dyngen: dyngen.c
$(HOST_CC) -O2 -Wall -g $< -o $@
translate-$(TARGET_ARCH).o: translate-$(TARGET_ARCH).c gen-op-$(TARGET_ARCH).h opc-$(TARGET_ARCH).h cpu-$(TARGET_ARCH).h
translate.o: translate.c op-$(TARGET_ARCH).h opc-$(TARGET_ARCH).h cpu-$(TARGET_ARCH).h
op-$(TARGET_ARCH).h: op-$(TARGET_ARCH).o dyngen
./dyngen -o $@ $<
opc-$(TARGET_ARCH).h: op-$(TARGET_ARCH).o dyngen
./dyngen -c -o $@ $<
gen-op-$(TARGET_ARCH).h: op-$(TARGET_ARCH).o dyngen
./dyngen -g -o $@ $<
op-$(TARGET_ARCH).o: op-$(TARGET_ARCH).c
$(CC) $(OP_CFLAGS) $(DEFINES) -c -o $@ $<
helper-$(TARGET_ARCH).o: helper-$(TARGET_ARCH).c
$(CC) $(HELPER_CFLAGS) $(DEFINES) -c -o $@ $<
op-i386.o: op-i386.c opreg_template.h ops_template.h
op-arm.o: op-arm.c op-arm-template.h
dyngen: dyngen.o
$(HOST_CC) -o $@ $^ $(LIBS)
%.o: %.c
$(CC) $(CFLAGS) $(DEFINES) -c -o $@ $<
$(HOST_CC) $(CFLAGS) $(DEFINES) -c -o $@ $<
clean:
$(MAKE) -C tests clean
rm -f *.o *.a *~ qemu dyngen TAGS
# avoid old build problems by removing potentially incorrect old files
rm -f config.mak config.h op-i386.h opc-i386.h gen-op-i386.h op-arm.h opc-arm.h gen-op-arm.h
rm -f *.o *.a $(TOOLS) dyngen TAGS qemu.pod
for d in $(TARGET_DIRS); do \
make -C $$d $@ || exit 1 ; \
done
distclean: clean
rm -f config.mak config.h
rm -f config-host.mak config-host.h
for d in $(TARGET_DIRS); do \
rm -rf $$d || exit 1 ; \
done
install: $(PROGS)
install -m 755 -s $(PROGS) $(prefix)/bin
install: all
mkdir -p $(prefix)/bin
install -m 755 -s $(TOOLS) $(prefix)/bin
mkdir -p $(sharedir)
install -m 644 pc-bios/bios.bin pc-bios/vgabios.bin $(sharedir)
mkdir -p $(mandir)/man1
install qemu.1 $(mandir)/man1
for d in $(TARGET_DIRS); do \
make -C $$d $@ || exit 1 ; \
done
# various test targets
test speed: qemu
test speed test2: all
make -C tests $@
TAGS:
@@ -202,49 +56,29 @@ TAGS:
qemu-doc.html: qemu-doc.texi
texi2html -monolithic -number $<
FILES= \
README README.distrib COPYING COPYING.LIB TODO Changelog VERSION \
configure \
dyngen.c dyngen.h dyngen-exec.h ioctls.h syscall_types.h \
Makefile elf.h elfload.c main.c signal.c qemu.h \
syscall.c syscall_defs.h vm86.c path.c mmap.c \
i386.ld ppc.ld alpha.ld s390.ld sparc.ld arm.ld\
vl.c i386-vl.ld\
thunk.c cpu-exec.c translate.c cpu-all.h thunk.h exec.h\
exec.c cpu-exec.c\
cpu-i386.h op-i386.c helper-i386.c syscall-i386.h translate-i386.c \
exec-i386.h ops_template.h op_string.h opreg_template.h \
cpu-arm.h syscall-arm.h exec-arm.h op-arm.c translate-arm.c op-arm-template.h \
dis-asm.h disas.c disas.h alpha-dis.c ppc-dis.c i386-dis.c sparc-dis.c \
arm-dis.c \
tests/Makefile \
tests/test-i386.c tests/test-i386-shift.h tests/test-i386.h \
tests/test-i386-muldiv.h tests/test-i386-code16.S tests/test-i386-vm86.S \
tests/hello-i386.c tests/hello-i386 \
tests/hello-arm.c tests/hello-arm \
tests/sha1.c \
tests/testsig.c tests/testclone.c tests/testthread.c \
tests/runcom.c tests/pi_10.com \
tests/test_path.c \
qemu-doc.texi qemu-doc.html
qemu.1: qemu-doc.texi
./texi2pod.pl $< qemu.pod
pod2man --section=1 --center=" " --release=" " qemu.pod > $@
FILE=qemu-$(VERSION)
FILE=qemu-$(shell cat VERSION)
# tar release (use 'make -k tar' on a checkouted tree)
tar:
rm -rf /tmp/$(FILE)
mkdir -p /tmp/$(FILE)
cp -P $(FILES) /tmp/$(FILE)
( cd /tmp ; tar zcvf ~/$(FILE).tar.gz $(FILE) )
cp -r . /tmp/$(FILE)
( cd /tmp ; tar zcvf ~/$(FILE).tar.gz $(FILE) --exclude CVS )
rm -rf /tmp/$(FILE)
# generate a binary distribution including the test binary environnment
BINPATH=/usr/local/qemu-i386
# generate a binary distribution
tarbin:
tar zcvf /tmp/qemu-$(VERSION)-i386-glibc21.tar.gz \
$(BINPATH)/etc $(BINPATH)/lib $(BINPATH)/bin $(BINPATH)/usr
tar zcvf /tmp/qemu-$(VERSION)-i386-wine.tar.gz \
$(BINPATH)/wine
( cd / ; tar zcvf ~/qemu-$(VERSION)-i386.tar.gz \
$(prefix)/bin/qemu $(prefix)/bin/qemu-fast \
$(prefix)/bin/qemu-i386 \
$(prefix)/bin/qemu-arm \
$(prefix)/bin/qemu-sparc \
$(sharedir)/bios.bin \
$(sharedir)/vgabios.bin \
$(mandir)/man1/qemu.1 )
ifneq ($(wildcard .depend),)
include .depend

260
Makefile.target Normal file
View File

@@ -0,0 +1,260 @@
include config.mak
TARGET_PATH=$(SRC_PATH)/target-$(TARGET_ARCH)
VPATH=$(SRC_PATH):$(TARGET_PATH)
CFLAGS=-Wall -O2 -g
LDFLAGS=-g
LIBS=
DEFINES=-I. -I$(TARGET_PATH) -I$(SRC_PATH)
HELPER_CFLAGS=$(CFLAGS)
DYNGEN=../dyngen
# user emulator name
QEMU_USER=qemu-$(TARGET_ARCH)
# system emulator name
ifdef CONFIG_SOFTMMU
QEMU_SYSTEM=qemu
else
QEMU_SYSTEM=qemu-fast
endif
ifdef CONFIG_USER_ONLY
PROGS=$(QEMU_USER)
else
ifeq ($(TARGET_ARCH), i386)
ifeq ($(ARCH), i386)
PROGS+=$(QEMU_SYSTEM)
ifndef CONFIG_SOFTMMU
CONFIG_STATIC=y
endif
endif
ifeq ($(ARCH), ppc)
ifdef CONFIG_SOFTMMU
PROGS+=$(QEMU_SYSTEM)
endif
endif
endif
endif
ifdef CONFIG_STATIC
LDFLAGS+=-static
endif
ifeq ($(ARCH),i386)
CFLAGS+=-fomit-frame-pointer
OP_CFLAGS=$(CFLAGS) -mpreferred-stack-boundary=2
ifeq ($(HAVE_GCC3_OPTIONS),yes)
OP_CFLAGS+= -falign-functions=0
else
OP_CFLAGS+= -malign-functions=0
endif
ifdef TARGET_GPROF
USE_I386_LD=y
endif
ifdef CONFIG_STATIC
USE_I386_LD=y
endif
ifdef USE_I386_LD
LDFLAGS+=-Wl,-T,$(SRC_PATH)/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)
LDFLAGS+=-Wl,-T,$(SRC_PATH)/ppc.ld
endif
ifeq ($(ARCH),s390)
OP_CFLAGS=$(CFLAGS)
LDFLAGS+=-Wl,-T,$(SRC_PATH)/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
HELPER_CFLAGS=$(CFLAGS) -ffixed-i0 -mflat
# -static is used to avoid g1/g3 usage by the dynamic linker
LDFLAGS+=-Wl,-T,$(SRC_PATH)/sparc.ld -static
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
LDFLAGS+=-Wl,-T,$(SRC_PATH)/alpha.ld
endif
ifeq ($(ARCH),ia64)
OP_CFLAGS=$(CFLAGS)
endif
ifeq ($(ARCH),arm)
OP_CFLAGS=$(CFLAGS) -mno-sched-prolog
LDFLAGS+=-Wl,-T,$(SRC_PATH)/arm.ld
endif
ifeq ($(ARCH),m68k)
OP_CFLAGS=$(CFLAGS) -fomit-frame-pointer
LDFLAGS+=-Wl,-T,m68k.ld
endif
ifeq ($(HAVE_GCC3_OPTIONS),yes)
# very important to generate a return at the end of every operation
OP_CFLAGS+=-fno-reorder-blocks -fno-optimize-sibling-calls
endif
#########################################################
DEFINES+=-D_GNU_SOURCE
LIBS+=-lm
# profiling code
ifdef TARGET_GPROF
LDFLAGS+=-p
main.o: CFLAGS+=-p
endif
OBJS= elfload.o main.o syscall.o mmap.o signal.o path.o
ifeq ($(TARGET_ARCH), i386)
OBJS+= vm86.o
endif
SRCS:= $(OBJS:.o=.c)
OBJS+= libqemu.a
# cpu emulator library
LIBOBJS=thunk.o exec.o translate-all.o cpu-exec.o gdbstub.o \
translate.o op.o
ifeq ($(TARGET_ARCH), i386)
LIBOBJS+=helper.o helper2.o
endif
ifeq ($(TARGET_ARCH), ppc)
LIBOBJS+=helper.o
endif
# NOTE: the disassembler code is only needed for debugging
LIBOBJS+=disas.o
ifeq ($(findstring i386, $(TARGET_ARCH) $(ARCH)),i386)
LIBOBJS+=i386-dis.o
endif
ifeq ($(findstring alpha, $(TARGET_ARCH) $(ARCH)),alpha)
LIBOBJS+=alpha-dis.o
endif
ifeq ($(findstring ppc, $(TARGET_ARCH) $(ARCH)),ppc)
LIBOBJS+=ppc-dis.o
endif
ifeq ($(findstring sparc, $(TARGET_ARCH) $(ARCH)),sparc)
LIBOBJS+=sparc-dis.o
endif
ifeq ($(findstring arm, $(TARGET_ARCH) $(ARCH)),arm)
LIBOBJS+=arm-dis.o
endif
ifeq ($(ARCH),ia64)
OBJS += ia64-syscall.o
endif
all: $(PROGS)
$(QEMU_USER): $(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
# must use static linking to avoid leaving stuff in virtual address space
VL_OBJS=vl.o block.o ide.o vga.o sb16.o dma.o oss.o
ifdef CONFIG_SDL
VL_OBJS+=sdl.o
ifdef CONFIG_STATIC
SDL_LIBS:=$(SDL_STATIC_LIBS)
endif
endif
VL_LDFLAGS=
# specific flags are needed for non soft mmu emulator
ifdef CONFIG_STATIC
VL_LDFLAGS+=-static
endif
ifndef CONFIG_SOFTMMU
VL_LDFLAGS+=-Wl,-T,$(SRC_PATH)/i386-vl.ld
endif
$(QEMU_SYSTEM): $(VL_OBJS) libqemu.a
$(CC) $(VL_LDFLAGS) -o $@ $^ $(LIBS) $(SDL_LIBS)
sdl.o: sdl.c
$(CC) $(CFLAGS) $(DEFINES) $(SDL_CFLAGS) -c -o $@ $<
depend: $(SRCS)
$(CC) -MM $(CFLAGS) $(DEFINES) $^ 1>.depend
# libqemu
libqemu.a: $(LIBOBJS)
rm -f $@
$(AR) rcs $@ $(LIBOBJS)
translate.o: translate.c gen-op.h opc.h cpu.h
translate-all.o: translate-all.c op.h opc.h cpu.h
op.h: op.o $(DYNGEN)
$(DYNGEN) -o $@ $<
opc.h: op.o $(DYNGEN)
$(DYNGEN) -c -o $@ $<
gen-op.h: op.o $(DYNGEN)
$(DYNGEN) -g -o $@ $<
op.o: op.c
$(CC) $(OP_CFLAGS) $(DEFINES) -c -o $@ $<
helper.o: helper.c
$(CC) $(HELPER_CFLAGS) $(DEFINES) -c -o $@ $<
ifeq ($(TARGET_ARCH), i386)
op.o: op.c opreg_template.h ops_template.h ops_template_mem.h ops_mem.h
endif
ifeq ($(TARGET_ARCH), arm)
op.o: op.c op_template.h
endif
ifeq ($(TARGET_ARCH), sparc)
op.o: op.c op_template.h
endif
%.o: %.c
$(CC) $(CFLAGS) $(DEFINES) -c -o $@ $<
clean:
rm -f *.o *.a *~ $(PROGS) gen-op.h opc.h op.h
install: all
install -m 755 -s $(PROGS) $(prefix)/bin
ifneq ($(wildcard .depend),)
include .depend
endif

33
README
View File

@@ -6,35 +6,17 @@ INSTALLATION
Type
./configure --interp-prefix=/usr/local/qemu-i386
./configure
make
to build qemu and libqemu.a.
to build qemu, qemu-CPU and libqemu.a (CPU is the name of the various
supported target CPUs).
Type
make install
to install QEMU in /usr/local/bin
* On x86 you should be able to launch any program by using the
libraries installed on your PC. For example:
./qemu -L / /bin/ls
* On non x86 CPUs, you need first to download at least an x86 glibc
(qemu-XXX-i386-glibc21.tar.gz on the qemu web page). Ensure that
LD_LIBRARY_PATH is not set:
unset LD_LIBRARY_PATH
Then you can launch the precompiled 'ls' x86 executable:
./qemu /usr/local/qemu-i386/bin/ls-i386
You can look at /usr/local/qemu-i386/bin/qemu-conf.sh so that QEMU is
automatically launched by the Linux kernel when you try to launch x86
executables.
to install QEMU in /usr/local
Tested tool versions
--------------------
@@ -50,8 +32,10 @@ host gcc binutils glibc linux distribution
x86 2.95.2 2.13.2 2.1.3 2.4.18
3.2 2.13.2 2.1.3 2.4.18
2.96 2.11.93.0.2 2.2.5 2.4.18 Red Hat 7.3
3.2.2 2.13.90.0.18 2.3.2 2.4.20 Red Hat 9
PowerPC 2.95.4 2.12.90.0.1 2.2.5 2.4.20-pre2 Debian 3.0
PowerPC 3.3 [4] 2.13.90.0.18 2.3.1 2.4.20briq
3.2
Alpha 3.3 [1] 2.14.90.0.4 2.2.5 2.2.20 [2] Debian 3.0
@@ -65,6 +49,9 @@ ARM 2.95.4 2.12.90.0.1 2.2.5 2.4.9 [3] Debian 3.0
(untested).
[3] 2.4.9-ac10-rmk2-np1-cerf2
[4] gcc 2.95.x generates invalid code when using too many register
variables. You must use gcc 3.x on PowerPC.
Documentation
-------------

View File

@@ -6,11 +6,11 @@ x86 binary distribution:
* wine-20020411 tarball
./configure --prefix=/usr/local/qemu-i386/wine
./configure --prefix=/usr/local/wine-i386
All exe and libs were stripped. Some compile time tools and the
includes were deleted.
* ldconfig was launched to build the library links:
./qemu /usr/local/qemu-i386/bin/ldconfig-i386 -C /usr/local/qemu-i386/etc/ld.so.cache
qemu-i386 /usr/gnemul/qemu-i386/bin/ldconfig-i386 -C /usr/gnemul/qemu-i386/etc/ld.so.cache

19
TODO
View File

@@ -1,16 +1,23 @@
- user/kernel PUSHL/POPL in helper.c
- keyboard output buffer filling timing emulation
- verify tb_flush() with a20 and TLBs
- finish segment ops (call far, ret far, load_seg suppressed)
- fix arm fpu rounding (at least for float->integer conversions)
- cmos clock update and timers
- test ldt limit < 7 ?
- tests for each target CPU
- optimize FPU operations (evaluate x87 stack pointer statically) and
fix cr0.TS emulation
- fix some 16 bit sp push/pop overflow (pusha/popa, lcall lret)
- sysenter/sysexit emulation
- fix CCOP optimisation
- optimize FPU operations (evaluate x87 stack pointer statically)
- fpush not before mem load restarting
- fix all remaining thread lock issues (must put TBs in a specific invalid
state, find a solution for tb_flush()).
- add gcc 2.96 test configure (some gcc3 flags are needed)
- add IPC syscalls
- fix arm fpu rounding (at least for float->integer conversions)
lower priority:
--------------
- add IPC syscalls
- SMP support
- use -msoft-float on ARM
- use kernel traps for unaligned accesses on ARM ?
- handle rare page fault cases (in particular if page fault in heplers or

View File

@@ -1 +1 @@
0.4
0.5.1

View File

@@ -560,8 +560,8 @@ static arm_regname regnames[] =
{ "a1", "a2", "a3", "a4", "v1", "v2", "v3", "WR", "v5", "SB", "SL", "FP", "IP", "SP", "LR", "PC" }}
};
/* Default to GCC register name set. */
static unsigned int regname_selected = 1;
/* Default to STD register name set. */
static unsigned int regname_selected = 2;
#define NUM_ARM_REGNAMES NUM_ELEM (regnames)
#define arm_regnames regnames[regname_selected].reg_names

326
block.c Normal file
View File

@@ -0,0 +1,326 @@
/*
* QEMU System Emulator block driver
*
* Copyright (c) 2003 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <getopt.h>
#include <inttypes.h>
#include <unistd.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <signal.h>
#include <time.h>
#include <sys/time.h>
#include <malloc.h>
#include <termios.h>
#include <sys/poll.h>
#include <errno.h>
#include <sys/wait.h>
#include <netinet/in.h>
#include "vl.h"
#define NO_THUNK_TYPE_SIZE
#include "thunk.h"
struct BlockDriverState {
int fd; /* if -1, only COW mappings */
int64_t total_sectors;
int read_only;
uint8_t *cow_bitmap; /* if non NULL, COW mappings are used first */
uint8_t *cow_bitmap_addr; /* mmap address of cow_bitmap */
int cow_bitmap_size;
int cow_fd;
int64_t cow_sectors_offset;
char filename[1024];
};
BlockDriverState *bdrv_open(const char *filename, int snapshot)
{
BlockDriverState *bs;
int fd, cow_fd;
int64_t size;
char template[] = "/tmp/vl.XXXXXX";
struct cow_header_v2 cow_header;
struct stat st;
bs = malloc(sizeof(BlockDriverState));
if(!bs)
return NULL;
bs->read_only = 0;
bs->fd = -1;
bs->cow_fd = -1;
bs->cow_bitmap = NULL;
strcpy(bs->filename, filename);
/* open standard HD image */
fd = open(filename, O_RDWR | O_LARGEFILE);
if (fd < 0) {
/* read only image on disk */
fd = open(filename, O_RDONLY | O_LARGEFILE);
if (fd < 0) {
perror(filename);
goto fail;
}
if (!snapshot)
bs->read_only = 1;
}
bs->fd = fd;
/* see if it is a cow image */
if (read(fd, &cow_header, sizeof(cow_header)) != sizeof(cow_header)) {
fprintf(stderr, "%s: could not read header\n", filename);
goto fail;
}
if (cow_header.magic == htonl(COW_MAGIC) &&
cow_header.version == htonl(COW_VERSION)) {
/* cow image found */
size = cow_header.size;
#ifndef WORDS_BIGENDIAN
size = bswap64(size);
#endif
bs->total_sectors = size / 512;
bs->cow_fd = fd;
bs->fd = -1;
if (cow_header.backing_file[0] != '\0') {
if (stat(cow_header.backing_file, &st) != 0) {
fprintf(stderr, "%s: could not find original disk image '%s'\n", filename, cow_header.backing_file);
goto fail;
}
if (st.st_mtime != htonl(cow_header.mtime)) {
fprintf(stderr, "%s: original raw disk image '%s' does not match saved timestamp\n", filename, cow_header.backing_file);
goto fail;
}
fd = open(cow_header.backing_file, O_RDONLY | O_LARGEFILE);
if (fd < 0)
goto fail;
bs->fd = fd;
}
/* mmap the bitmap */
bs->cow_bitmap_size = ((bs->total_sectors + 7) >> 3) + sizeof(cow_header);
bs->cow_bitmap_addr = mmap(get_mmap_addr(bs->cow_bitmap_size),
bs->cow_bitmap_size,
PROT_READ | PROT_WRITE,
MAP_SHARED, bs->cow_fd, 0);
if (bs->cow_bitmap_addr == MAP_FAILED)
goto fail;
bs->cow_bitmap = bs->cow_bitmap_addr + sizeof(cow_header);
bs->cow_sectors_offset = (bs->cow_bitmap_size + 511) & ~511;
snapshot = 0;
} else {
/* standard raw image */
size = lseek64(fd, 0, SEEK_END);
bs->total_sectors = size / 512;
bs->fd = fd;
}
if (snapshot) {
/* create a temporary COW file */
cow_fd = mkstemp(template);
if (cow_fd < 0)
goto fail;
bs->cow_fd = cow_fd;
unlink(template);
/* just need to allocate bitmap */
bs->cow_bitmap_size = (bs->total_sectors + 7) >> 3;
bs->cow_bitmap_addr = mmap(get_mmap_addr(bs->cow_bitmap_size),
bs->cow_bitmap_size,
PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (bs->cow_bitmap_addr == MAP_FAILED)
goto fail;
bs->cow_bitmap = bs->cow_bitmap_addr;
bs->cow_sectors_offset = 0;
}
return bs;
fail:
bdrv_close(bs);
return NULL;
}
void bdrv_close(BlockDriverState *bs)
{
/* we unmap the mapping so that it is written to the COW file */
if (bs->cow_bitmap_addr)
munmap(bs->cow_bitmap_addr, bs->cow_bitmap_size);
if (bs->cow_fd >= 0)
close(bs->cow_fd);
if (bs->fd >= 0)
close(bs->fd);
free(bs);
}
static inline void set_bit(uint8_t *bitmap, int64_t bitnum)
{
bitmap[bitnum / 8] |= (1 << (bitnum%8));
}
static inline int is_bit_set(const uint8_t *bitmap, int64_t bitnum)
{
return !!(bitmap[bitnum / 8] & (1 << (bitnum%8)));
}
/* Return true if first block has been changed (ie. current version is
* in COW file). Set the number of continuous blocks for which that
* is true. */
static int is_changed(uint8_t *bitmap,
int64_t sector_num, int nb_sectors,
int *num_same)
{
int changed;
if (!bitmap || nb_sectors == 0) {
*num_same = nb_sectors;
return 0;
}
changed = is_bit_set(bitmap, sector_num);
for (*num_same = 1; *num_same < nb_sectors; (*num_same)++) {
if (is_bit_set(bitmap, sector_num + *num_same) != changed)
break;
}
return changed;
}
/* commit COW file into the raw image */
int bdrv_commit(BlockDriverState *bs)
{
int64_t i;
uint8_t *cow_bitmap;
if (!bs->cow_bitmap) {
fprintf(stderr, "Already committed to %s\n", bs->filename);
return 0;
}
if (bs->read_only) {
fprintf(stderr, "Can't commit to %s: read-only\n", bs->filename);
return -1;
}
cow_bitmap = bs->cow_bitmap;
for (i = 0; i < bs->total_sectors; i++) {
if (is_bit_set(cow_bitmap, i)) {
unsigned char sector[512];
if (bdrv_read(bs, i, sector, 1) != 0) {
fprintf(stderr, "Error reading sector %lli: aborting commit\n",
(long long)i);
return -1;
}
/* Make bdrv_write write to real file for a moment. */
bs->cow_bitmap = NULL;
if (bdrv_write(bs, i, sector, 1) != 0) {
fprintf(stderr, "Error writing sector %lli: aborting commit\n",
(long long)i);
bs->cow_bitmap = cow_bitmap;
return -1;
}
bs->cow_bitmap = cow_bitmap;
}
}
fprintf(stderr, "Committed snapshot to %s\n", bs->filename);
return 0;
}
/* return -1 if error */
int bdrv_read(BlockDriverState *bs, int64_t sector_num,
uint8_t *buf, int nb_sectors)
{
int ret, n, fd;
int64_t offset;
while (nb_sectors > 0) {
if (is_changed(bs->cow_bitmap, sector_num, nb_sectors, &n)) {
fd = bs->cow_fd;
offset = bs->cow_sectors_offset;
} else {
fd = bs->fd;
offset = 0;
}
if (fd < 0) {
/* no file, just return empty sectors */
memset(buf, 0, n * 512);
} else {
offset += sector_num * 512;
lseek64(fd, offset, SEEK_SET);
ret = read(fd, buf, n * 512);
if (ret != n * 512) {
return -1;
}
}
nb_sectors -= n;
sector_num += n;
buf += n * 512;
}
return 0;
}
/* return -1 if error */
int bdrv_write(BlockDriverState *bs, int64_t sector_num,
const uint8_t *buf, int nb_sectors)
{
int ret, fd, i;
int64_t offset, retl;
if (bs->read_only)
return -1;
if (bs->cow_bitmap) {
fd = bs->cow_fd;
offset = bs->cow_sectors_offset;
} else {
fd = bs->fd;
offset = 0;
}
offset += sector_num * 512;
retl = lseek64(fd, offset, SEEK_SET);
if (retl == -1) {
return -1;
}
ret = write(fd, buf, nb_sectors * 512);
if (ret != nb_sectors * 512) {
return -1;
}
if (bs->cow_bitmap) {
for (i = 0; i < nb_sectors; i++)
set_bit(bs->cow_bitmap, sector_num + i);
}
return 0;
}
void bdrv_get_geometry(BlockDriverState *bs, int64_t *nb_sectors_ptr)
{
*nb_sectors_ptr = bs->total_sectors;
}

84
bswap.h Normal file
View File

@@ -0,0 +1,84 @@
#ifndef BSWAP_H
#define BSWAP_H
#include "config-host.h"
#include <inttypes.h>
#ifdef HAVE_BYTESWAP_H
#include <byteswap.h>
#else
#define bswap_16(x) \
({ \
uint16_t __x = (x); \
((uint16_t)( \
(((uint16_t)(__x) & (uint16_t)0x00ffU) << 8) | \
(((uint16_t)(__x) & (uint16_t)0xff00U) >> 8) )); \
})
#define bswap_32(x) \
({ \
uint32_t __x = (x); \
((uint32_t)( \
(((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
(((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \
(((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \
(((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) )); \
})
#define bswap_64(x) \
({ \
uint64_t __x = (x); \
((uint64_t)( \
(uint64_t)(((uint64_t)(__x) & (uint64_t)0x00000000000000ffULL) << 56) | \
(uint64_t)(((uint64_t)(__x) & (uint64_t)0x000000000000ff00ULL) << 40) | \
(uint64_t)(((uint64_t)(__x) & (uint64_t)0x0000000000ff0000ULL) << 24) | \
(uint64_t)(((uint64_t)(__x) & (uint64_t)0x00000000ff000000ULL) << 8) | \
(uint64_t)(((uint64_t)(__x) & (uint64_t)0x000000ff00000000ULL) >> 8) | \
(uint64_t)(((uint64_t)(__x) & (uint64_t)0x0000ff0000000000ULL) >> 24) | \
(uint64_t)(((uint64_t)(__x) & (uint64_t)0x00ff000000000000ULL) >> 40) | \
(uint64_t)(((uint64_t)(__x) & (uint64_t)0xff00000000000000ULL) >> 56) )); \
})
#endif /* !HAVE_BYTESWAP_H */
#if defined(__alpha__) || defined (__ia64__)
#define HOST_LONG_BITS 64
#else
#define HOST_LONG_BITS 32
#endif
#define HOST_LONG_SIZE (HOST_LONG_BITS / 8)
static inline uint16_t bswap16(uint16_t x)
{
return bswap_16(x);
}
static inline uint32_t bswap32(uint32_t x)
{
return bswap_32(x);
}
static inline uint64_t bswap64(uint64_t x)
{
return bswap_64(x);
}
static inline void bswap16s(uint16_t *s)
{
*s = bswap16(*s);
}
static inline void bswap32s(uint32_t *s)
{
*s = bswap32(*s);
}
static inline void bswap64s(uint64_t *s)
{
*s = bswap64(*s);
}
#endif /* BSWAP_H */

270
configure vendored
View File

@@ -15,11 +15,10 @@ TMPC="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}.c"
TMPO="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}.o"
TMPE="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}"
TMPS="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}.S"
TMPH="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}.h"
# default parameters
prefix="/usr/local"
interp_prefix="/usr/gnemul/qemu-i386"
interp_prefix="/usr/gnemul/qemu-%M"
static="no"
cross_prefix=""
cc="gcc"
@@ -27,12 +26,11 @@ host_cc="gcc"
ar="ar"
make="make"
strip="strip"
target_cpu="x86"
target_bigendian="default"
cpu=`uname -m`
target_list="i386-user i386 i386-softmmu arm-user sparc-user ppc-user"
case "$cpu" in
i386|i486|i586|i686|i86pc|BePC)
cpu="x86"
cpu="i386"
;;
armv4l)
cpu="armv4l"
@@ -58,6 +56,9 @@ case "$cpu" in
ia64)
cpu="ia64"
;;
m68k)
cpu="m68k"
;;
*)
cpu="unknown"
;;
@@ -71,6 +72,26 @@ case $targetos in
*) ;;
esac
##########################################
# SDL probe
cat > $TMPC << EOF
#include <SDL.h>
#undef main /* We don't want SDL to override our main() */
int main( void ) { return SDL_Init (SDL_INIT_VIDEO); }
EOF
sdl_too_old=no
sdl=no
if $cc -o $TMPE `sdl-config --cflags` $TMPC `sdl-config --libs` 2> /dev/null ; then
_sdlversion=`sdl-config --version | sed 's/[^0-9]//g'`
if test "$_sdlversion" -lt 121 ; then
sdl_too_old=yes
else
sdl=yes
fi
fi
# find source path
# XXX: we assume an absolute path is given when launching configure,
# except in './configure' case.
@@ -104,16 +125,14 @@ for opt do
;;
--cpu=*) cpu=`echo $opt | cut -d '=' -f 2`
;;
--target-cpu=*) target_cpu=`echo $opt | cut -d '=' -f 2`
;;
--target-big-endian) target_bigendian="yes"
;;
--target-little-endian) target_bigendian="no"
--target-list=*) target_list=${opt#--target-list=}
;;
--enable-gprof) gprof="yes"
;;
--static) static="yes"
;;
--disable-sdl) sdl="no"
;;
esac
done
@@ -147,7 +166,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" -o "$cpu" = "sparc" -o "$cpu" = "sparc64"; then
if test "$cpu" = "powerpc" -o "$cpu" = "mips" -o "$cpu" = "s390" -o "$cpu" = "sparc" -o "$cpu" = "sparc64" -o "$cpu" = "m68k"; then
bigendian="yes"
fi
@@ -164,16 +183,6 @@ if $cc -fno-reorder-blocks -fno-optimize-sibling-calls -o $TMPO $TMPC 2> /dev/nu
have_gcc3_options="yes"
fi
if test "$target_bigendian" = "default" ; then
if test "$target_cpu" = "x86" ; then
target_bigendian="no"
elif test "$target_cpu" = "arm" ; then
target_bigendian="no"
else
target_bigendian="no"
fi
fi
if test x"$1" = x"-h" -o x"$1" = x"--help" ; then
cat << EOF
@@ -184,8 +193,9 @@ EOF
echo "Standard options:"
echo " --help print this message"
echo " --prefix=PREFIX install in PREFIX [$prefix]"
echo " --interp-prefix=PREFIX where to find shared libraries, etc. [$interp_prefix]"
echo " --target_cpu=CPU set target cpu (x86 or arm) [$target_cpu]"
echo " --interp-prefix=PREFIX where to find shared libraries, etc."
echo " use %M for cpu name [$interp_prefix]"
echo " --target-list=LIST set target list [$target_list]"
echo ""
echo "Advanced options (experts only):"
echo " --source-path=PATH path of source code [$source_path]"
@@ -198,101 +208,179 @@ echo "NOTE: The object files are build at the place where configure is launched"
exit 1
fi
mandir="$prefix/share/man"
sharedir="$prefix/share/qemu"
echo "Install prefix $prefix"
echo "Source path $source_path"
echo "Manual directory $mandir"
echo "BIOS directory $sharedir"
echo "ELF interp prefix $interp_prefix"
echo "Source path $source_path"
echo "C compiler $cc"
echo "make $make"
echo "host CPU $cpu"
echo "host big endian $bigendian"
echo "target CPU $target_cpu"
echo "target big endian $target_bigendian"
echo "target list $target_list"
echo "gprof enabled $gprof"
echo "static build $static"
echo "Creating config.mak and config.h"
echo "# Automatically generated by configure - do not modify" > config.mak
echo "/* Automatically generated by configure - do not modify */" > $TMPH
echo "prefix=$prefix" >> config.mak
echo "#define CONFIG_QEMU_PREFIX \"$interp_prefix\"" >> $TMPH
echo "MAKE=$make" >> config.mak
echo "CC=$cc" >> config.mak
if test "$have_gcc3_options" = "yes" ; then
echo "HAVE_GCC3_OPTIONS=yes" >> config.mak
echo "SDL support $sdl"
if test $sdl_too_old = "yes"; then
echo "-> Your SDL version is too old - please upgrade to have FFplay/SDL support"
fi
echo "HOST_CC=$host_cc" >> config.mak
echo "AR=$ar" >> config.mak
echo "STRIP=$strip -s -R .comment -R .note" >> config.mak
echo "CFLAGS=$CFLAGS" >> config.mak
echo "LDFLAGS=$LDFLAGS" >> config.mak
if test "$cpu" = "x86" ; then
echo "ARCH=i386" >> config.mak
echo "#define HOST_I386 1" >> $TMPH
config_mak="config-host.mak"
config_h="config-host.h"
echo "Creating $config_mak and $config_h"
echo "# Automatically generated by configure - do not modify" > $config_mak
echo "/* Automatically generated by configure - do not modify */" > $config_h
echo "prefix=$prefix" >> $config_mak
echo "mandir=$mandir" >> $config_mak
echo "sharedir=$sharedir" >> $config_mak
echo "#define CONFIG_QEMU_SHAREDIR \"$sharedir\"" >> $config_h
echo "MAKE=$make" >> $config_mak
echo "CC=$cc" >> $config_mak
if test "$have_gcc3_options" = "yes" ; then
echo "HAVE_GCC3_OPTIONS=yes" >> $config_mak
fi
echo "HOST_CC=$host_cc" >> $config_mak
echo "AR=$ar" >> $config_mak
echo "STRIP=$strip -s -R .comment -R .note" >> $config_mak
echo "CFLAGS=$CFLAGS" >> $config_mak
echo "LDFLAGS=$LDFLAGS" >> $config_mak
if test "$cpu" = "i386" ; then
echo "ARCH=i386" >> $config_mak
echo "#define HOST_I386 1" >> $config_h
elif test "$cpu" = "armv4l" ; then
echo "ARCH=arm" >> config.mak
echo "#define HOST_ARM 1" >> $TMPH
echo "ARCH=arm" >> $config_mak
echo "#define HOST_ARM 1" >> $config_h
elif test "$cpu" = "powerpc" ; then
echo "ARCH=ppc" >> config.mak
echo "#define HOST_PPC 1" >> $TMPH
echo "ARCH=ppc" >> $config_mak
echo "#define HOST_PPC 1" >> $config_h
elif test "$cpu" = "mips" ; then
echo "ARCH=mips" >> config.mak
echo "#define HOST_MIPS 1" >> $TMPH
echo "ARCH=mips" >> $config_mak
echo "#define HOST_MIPS 1" >> $config_h
elif test "$cpu" = "s390" ; then
echo "ARCH=s390" >> config.mak
echo "#define HOST_S390 1" >> $TMPH
echo "ARCH=s390" >> $config_mak
echo "#define HOST_S390 1" >> $config_h
elif test "$cpu" = "alpha" ; then
echo "ARCH=alpha" >> config.mak
echo "#define HOST_ALPHA 1" >> $TMPH
echo "ARCH=alpha" >> $config_mak
echo "#define HOST_ALPHA 1" >> $config_h
elif test "$cpu" = "sparc" ; then
echo "ARCH=sparc" >> config.mak
echo "#define HOST_SPARC 1" >> $TMPH
echo "ARCH=sparc" >> $config_mak
echo "#define HOST_SPARC 1" >> $config_h
elif test "$cpu" = "sparc64" ; then
echo "ARCH=sparc64" >> config.mak
echo "#define HOST_SPARC64 1" >> $TMPH
echo "ARCH=sparc64" >> $config_mak
echo "#define HOST_SPARC64 1" >> $config_h
elif test "$cpu" = "ia64" ; then
echo "ARCH=ia64" >> config.mak
echo "#define HOST_IA64 1" >> $TMPH
echo "ARCH=ia64" >> $config_mak
echo "#define HOST_IA64 1" >> $config_h
elif test "$cpu" = "m68k" ; then
echo "ARCH=m68k" >> config.mak
echo "#define HOST_M68K 1" >> $TMPH
else
echo "Unsupported CPU"
exit 1
fi
if test "$bigendian" = "yes" ; then
echo "WORDS_BIGENDIAN=yes" >> config.mak
echo "#define WORDS_BIGENDIAN 1" >> $TMPH
echo "WORDS_BIGENDIAN=yes" >> $config_mak
echo "#define WORDS_BIGENDIAN 1" >> $config_h
fi
echo "#define HAVE_BYTESWAP_H 1" >> $config_h
if test "$gprof" = "yes" ; then
echo "TARGET_GPROF=yes" >> $config_mak
echo "#define HAVE_GPROF 1" >> $config_h
fi
if test "$static" = "yes" ; then
echo "CONFIG_STATIC=yes" >> $config_mak
echo "#define CONFIG_STATIC 1" >> $config_h
fi
if test "$sdl" = "yes" ; then
echo "CONFIG_SDL=yes" >> $config_mak
echo "#define CONFIG_SDL 1" >> $config_h
echo "SDL_LIBS=`sdl-config --libs`" >> $config_mak
echo "SDL_STATIC_LIBS=`sdl-config --static-libs`" >> $config_mak
echo "SDL_CFLAGS=`sdl-config --cflags`" >> $config_mak
fi
echo -n "VERSION=" >>$config_mak
head $source_path/VERSION >>$config_mak
echo "" >>$config_mak
echo -n "#define QEMU_VERSION \"" >> $config_h
head $source_path/VERSION >> $config_h
echo "\"" >> $config_h
echo "SRC_PATH=$source_path" >> $config_mak
echo "TARGET_DIRS=$target_list" >> $config_mak
for target in $target_list; do
target_dir="$target"
config_mak=$target_dir/config.mak
config_h=$target_dir/config.h
target_cpu=`echo $target | cut -d '-' -f 1`
target_bigendian="no"
[ "$target_cpu" = "sparc" ] && target_bigendian=yes
[ "$target_cpu" = "ppc" ] && target_bigendian=yes
target_softmmu="no"
if expr $target : '.*-softmmu' > /dev/null ; then
target_softmmu="yes"
fi
target_user_only="no"
if expr $target : '.*-user' > /dev/null ; then
target_user_only="yes"
fi
if test "$target_cpu" = "x86" ; then
echo "TARGET_ARCH=i386" >> config.mak
echo "#define TARGET_ARCH \"i386\"" >> $TMPH
echo "#define TARGET_I386 1" >> $TMPH
echo "Creating $config_mak, $config_h and $target_dir/Makefile"
mkdir -p $target_dir
ln -sf $source_path/Makefile.target $target_dir/Makefile
echo "# Automatically generated by configure - do not modify" > $config_mak
echo "/* Automatically generated by configure - do not modify */" > $config_h
echo "include ../config-host.mak" >> $config_mak
echo "#include \"../config-host.h\"" >> $config_h
interp_prefix1=`echo "$interp_prefix" | sed "s/%M/$target_cpu/g"`
echo "#define CONFIG_QEMU_PREFIX \"$interp_prefix1\"" >> $config_h
if test "$target_cpu" = "i386" ; then
echo "TARGET_ARCH=i386" >> $config_mak
echo "#define TARGET_ARCH \"i386\"" >> $config_h
echo "#define TARGET_I386 1" >> $config_h
elif test "$target_cpu" = "arm" ; then
echo "TARGET_ARCH=arm" >> config.mak
echo "#define TARGET_ARCH \"arm\"" >> $TMPH
echo "#define TARGET_ARM 1" >> $TMPH
echo "TARGET_ARCH=arm" >> $config_mak
echo "#define TARGET_ARCH \"arm\"" >> $config_h
echo "#define TARGET_ARM 1" >> $config_h
elif test "$target_cpu" = "sparc" ; then
echo "TARGET_ARCH=sparc" >> $config_mak
echo "#define TARGET_ARCH \"sparc\"" >> $config_h
echo "#define TARGET_SPARC 1" >> $config_h
elif test "$target_cpu" = "ppc" ; then
echo "TARGET_ARCH=ppc" >> $config_mak
echo "#define TARGET_ARCH \"ppc\"" >> $config_h
echo "#define TARGET_PPC 1" >> $config_h
else
echo "Unsupported target CPU"
exit 1
fi
if test "$target_bigendian" = "yes" ; then
echo "TARGET_WORDS_BIGENDIAN=yes" >> config.mak
echo "#define TARGET_WORDS_BIGENDIAN 1" >> $TMPH
echo "TARGET_WORDS_BIGENDIAN=yes" >> $config_mak
echo "#define TARGET_WORDS_BIGENDIAN 1" >> $config_h
fi
if test "$target_softmmu" = "yes" ; then
echo "CONFIG_SOFTMMU=yes" >> $config_mak
echo "#define CONFIG_SOFTMMU 1" >> $config_h
fi
if test "$target_user_only" = "yes" ; then
echo "CONFIG_USER_ONLY=yes" >> $config_mak
echo "#define CONFIG_USER_ONLY 1" >> $config_h
fi
if test "$gprof" = "yes" ; then
echo "TARGET_GPROF=yes" >> config.mak
echo "#define HAVE_GPROF 1" >> $TMPH
fi
if test "$static" = "yes" ; then
echo "CONFIG_STATIC=yes" >> config.mak
fi
echo -n "VERSION=" >>config.mak
head $source_path/VERSION >>config.mak
echo "" >>config.mak
echo -n "#define QEMU_VERSION \"" >> $TMPH
head $source_path/VERSION >> $TMPH
echo "\"" >> $TMPH
done # for target in $targets
# build tree in object directory if source path is different from current one
if test "$source_path_used" = "yes" ; then
@@ -305,13 +393,5 @@ if test "$source_path_used" = "yes" ; then
ln -sf $source_path/$f $f
done
fi
echo "SRC_PATH=$source_path" >> config.mak
diff $TMPH config.h >/dev/null 2>&1
if test $? -ne 0 ; then
mv -f $TMPH config.h
else
echo "config.h is unchanged"
fi
rm -f $TMPO $TMPC $TMPE $TMPS $TMPH
rm -f $TMPO $TMPC $TMPE $TMPS

302
cpu-all.h
View File

@@ -20,18 +20,53 @@
#ifndef CPU_ALL_H
#define CPU_ALL_H
/* all CPU memory access use these macros */
static inline int ldub(void *ptr)
#if defined(__arm__) || defined(__sparc__)
#define WORDS_ALIGNED
#endif
/* some important defines:
*
* WORDS_ALIGNED : if defined, the host cpu can only make word aligned
* memory accesses.
*
* WORDS_BIGENDIAN : if defined, the host cpu is big endian and
* otherwise little endian.
*
* (TARGET_WORDS_ALIGNED : same for target cpu (not supported yet))
*
* TARGET_WORDS_BIGENDIAN : same for target cpu
*/
/* NOTE: arm is horrible as double 32 bit words are stored in big endian ! */
typedef union {
double d;
#if !defined(WORDS_BIGENDIAN) && !defined(__arm__)
struct {
uint32_t lower;
uint32_t upper;
} l;
#else
struct {
uint32_t upper;
uint32_t lower;
} l;
#endif
uint64_t ll;
} CPU_DoubleU;
/* CPU memory access without any memory or io remapping */
static inline int ldub_raw(void *ptr)
{
return *(uint8_t *)ptr;
}
static inline int ldsb(void *ptr)
static inline int ldsb_raw(void *ptr)
{
return *(int8_t *)ptr;
}
static inline void stb(void *ptr, int v)
static inline void stb_raw(void *ptr, int v)
{
*(uint8_t *)ptr = v;
}
@@ -39,10 +74,10 @@ static inline void stb(void *ptr, int v)
/* NOTE: on arm, putting 2 in /proc/sys/debug/alignment so that the
kernel handles unaligned load/stores may give better results, but
it is a system wide setting : bad */
#if defined(WORDS_BIGENDIAN) || defined(__arm__)
#if !defined(TARGET_WORDS_BIGENDIAN) && (defined(WORDS_BIGENDIAN) || defined(WORDS_ALIGNED))
/* conservative code for little endian unaligned accesses */
static inline int lduw(void *ptr)
static inline int lduw_raw(void *ptr)
{
#ifdef __powerpc__
int val;
@@ -54,7 +89,7 @@ static inline int lduw(void *ptr)
#endif
}
static inline int ldsw(void *ptr)
static inline int ldsw_raw(void *ptr)
{
#ifdef __powerpc__
int val;
@@ -66,7 +101,7 @@ static inline int ldsw(void *ptr)
#endif
}
static inline int ldl(void *ptr)
static inline int ldl_raw(void *ptr)
{
#ifdef __powerpc__
int val;
@@ -78,16 +113,16 @@ static inline int ldl(void *ptr)
#endif
}
static inline uint64_t ldq(void *ptr)
static inline uint64_t ldq_raw(void *ptr)
{
uint8_t *p = ptr;
uint32_t v1, v2;
v1 = ldl(p);
v2 = ldl(p + 4);
v1 = ldl_raw(p);
v2 = ldl_raw(p + 4);
return v1 | ((uint64_t)v2 << 32);
}
static inline void stw(void *ptr, int v)
static inline void stw_raw(void *ptr, int v)
{
#ifdef __powerpc__
__asm__ __volatile__ ("sthbrx %1,0,%2" : "=m" (*(uint16_t *)ptr) : "r" (v), "r" (ptr));
@@ -98,7 +133,7 @@ static inline void stw(void *ptr, int v)
#endif
}
static inline void stl(void *ptr, int v)
static inline void stl_raw(void *ptr, int v)
{
#ifdef __powerpc__
__asm__ __volatile__ ("stwbrx %1,0,%2" : "=m" (*(uint32_t *)ptr) : "r" (v), "r" (ptr));
@@ -111,142 +146,241 @@ static inline void stl(void *ptr, int v)
#endif
}
static inline void stq(void *ptr, uint64_t v)
static inline void stq_raw(void *ptr, uint64_t v)
{
uint8_t *p = ptr;
stl(p, (uint32_t)v);
stl(p + 4, v >> 32);
stl_raw(p, (uint32_t)v);
stl_raw(p + 4, v >> 32);
}
/* float access */
static inline float ldfl(void *ptr)
static inline float ldfl_raw(void *ptr)
{
union {
float f;
uint32_t i;
} u;
u.i = ldl(ptr);
u.i = ldl_raw(ptr);
return u.f;
}
static inline void stfl(void *ptr, float v)
static inline void stfl_raw(void *ptr, float v)
{
union {
float f;
uint32_t i;
} u;
u.f = v;
stl(ptr, u.i);
stl_raw(ptr, u.i);
}
#if defined(__arm__) && !defined(WORDS_BIGENDIAN)
/* NOTE: arm is horrible as double 32 bit words are stored in big endian ! */
static inline double ldfq(void *ptr)
static inline double ldfq_raw(void *ptr)
{
union {
double d;
uint32_t tab[2];
} u;
u.tab[1] = ldl(ptr);
u.tab[0] = ldl(ptr + 4);
CPU_DoubleU u;
u.l.lower = ldl_raw(ptr);
u.l.upper = ldl_raw(ptr + 4);
return u.d;
}
static inline void stfq(void *ptr, double v)
static inline void stfq_raw(void *ptr, double v)
{
union {
double d;
uint32_t tab[2];
} u;
CPU_DoubleU u;
u.d = v;
stl(ptr, u.tab[1]);
stl(ptr + 4, u.tab[0]);
stl_raw(ptr, u.l.lower);
stl_raw(ptr + 4, u.l.upper);
}
#else
static inline double ldfq(void *ptr)
#elif defined(TARGET_WORDS_BIGENDIAN) && (!defined(WORDS_BIGENDIAN) || defined(WORDS_ALIGNED))
static inline int lduw_raw(void *ptr)
{
uint8_t *b = (uint8_t *) ptr;
return (b[0]<<8|b[1]);
}
static inline int ldsw_raw(void *ptr)
{
int8_t *b = (int8_t *) ptr;
return (b[0]<<8|b[1]);
}
static inline int ldl_raw(void *ptr)
{
uint8_t *b = (uint8_t *) ptr;
return (b[0]<<24|b[1]<<16|b[2]<<8|b[3]);
}
static inline uint64_t ldq_raw(void *ptr)
{
uint32_t a,b;
a = ldl_raw(ptr);
b = ldl_raw(ptr+4);
return (((uint64_t)a<<32)|b);
}
static inline void stw_raw(void *ptr, int v)
{
uint8_t *d = (uint8_t *) ptr;
d[0] = v >> 8;
d[1] = v;
}
static inline void stl_raw(void *ptr, int v)
{
uint8_t *d = (uint8_t *) ptr;
d[0] = v >> 24;
d[1] = v >> 16;
d[2] = v >> 8;
d[3] = v;
}
static inline void stq_raw(void *ptr, uint64_t v)
{
stl_raw(ptr, v >> 32);
stl_raw(ptr + 4, v);
}
/* float access */
static inline float ldfl_raw(void *ptr)
{
union {
double d;
uint64_t i;
float f;
uint32_t i;
} u;
u.i = ldq(ptr);
u.i = ldl_raw(ptr);
return u.f;
}
static inline void stfl_raw(void *ptr, float v)
{
union {
float f;
uint32_t i;
} u;
u.f = v;
stl_raw(ptr, u.i);
}
static inline double ldfq_raw(void *ptr)
{
CPU_DoubleU u;
u.l.upper = ldl_raw(ptr);
u.l.lower = ldl_raw(ptr + 4);
return u.d;
}
static inline void stfq(void *ptr, double v)
static inline void stfq_raw(void *ptr, double v)
{
union {
double d;
uint64_t i;
} u;
CPU_DoubleU u;
u.d = v;
stq(ptr, u.i);
stl_raw(ptr, u.l.upper);
stl_raw(ptr + 4, u.l.lower);
}
#endif
#else
static inline int lduw(void *ptr)
static inline int lduw_raw(void *ptr)
{
return *(uint16_t *)ptr;
}
static inline int ldsw(void *ptr)
static inline int ldsw_raw(void *ptr)
{
return *(int16_t *)ptr;
}
static inline int ldl(void *ptr)
static inline int ldl_raw(void *ptr)
{
return *(uint32_t *)ptr;
}
static inline uint64_t ldq(void *ptr)
static inline uint64_t ldq_raw(void *ptr)
{
return *(uint64_t *)ptr;
}
static inline void stw(void *ptr, int v)
static inline void stw_raw(void *ptr, int v)
{
*(uint16_t *)ptr = v;
}
static inline void stl(void *ptr, int v)
static inline void stl_raw(void *ptr, int v)
{
*(uint32_t *)ptr = v;
}
static inline void stq(void *ptr, uint64_t v)
static inline void stq_raw(void *ptr, uint64_t v)
{
*(uint64_t *)ptr = v;
}
/* float access */
static inline float ldfl(void *ptr)
static inline float ldfl_raw(void *ptr)
{
return *(float *)ptr;
}
static inline double ldfq(void *ptr)
static inline double ldfq_raw(void *ptr)
{
return *(double *)ptr;
}
static inline void stfl(void *ptr, float v)
static inline void stfl_raw(void *ptr, float v)
{
*(float *)ptr = v;
}
static inline void stfq(void *ptr, double v)
static inline void stfq_raw(void *ptr, double v)
{
*(double *)ptr = v;
}
#endif
/* MMU memory access macros */
#if defined(CONFIG_USER_ONLY)
/* if user mode, no other memory access functions */
#define ldub(p) ldub_raw(p)
#define ldsb(p) ldsb_raw(p)
#define lduw(p) lduw_raw(p)
#define ldsw(p) ldsw_raw(p)
#define ldl(p) ldl_raw(p)
#define ldq(p) ldq_raw(p)
#define ldfl(p) ldfl_raw(p)
#define ldfq(p) ldfq_raw(p)
#define stb(p, v) stb_raw(p, v)
#define stw(p, v) stw_raw(p, v)
#define stl(p, v) stl_raw(p, v)
#define stq(p, v) stq_raw(p, v)
#define stfl(p, v) stfl_raw(p, v)
#define stfq(p, v) stfq_raw(p, v)
#define ldub_code(p) ldub_raw(p)
#define ldsb_code(p) ldsb_raw(p)
#define lduw_code(p) lduw_raw(p)
#define ldsw_code(p) ldsw_raw(p)
#define ldl_code(p) ldl_raw(p)
#define ldub_kernel(p) ldub_raw(p)
#define ldsb_kernel(p) ldsb_raw(p)
#define lduw_kernel(p) lduw_raw(p)
#define ldsw_kernel(p) ldsw_raw(p)
#define ldl_kernel(p) ldl_raw(p)
#define ldfl_kernel(p) ldfl_raw(p)
#define ldfq_kernel(p) ldfq_raw(p)
#define stb_kernel(p, v) stb_raw(p, v)
#define stw_kernel(p, v) stw_raw(p, v)
#define stl_kernel(p, v) stl_raw(p, v)
#define stq_kernel(p, v) stq_raw(p, v)
#define stfl_kernel(p, v) stfl_raw(p, v)
#define stfq_kernel(p, vt) stfq_raw(p, v)
#endif /* defined(CONFIG_USER_ONLY) */
/* page related stuff */
#define TARGET_PAGE_SIZE (1 << TARGET_PAGE_BITS)
@@ -296,6 +430,24 @@ void page_unprotect_range(uint8_t *data, unsigned long data_size);
#define cpu_interrupt cpu_arm_interrupt
#define cpu_signal_handler cpu_arm_signal_handler
#elif defined(TARGET_SPARC)
#define CPUState CPUSPARCState
#define cpu_init cpu_sparc_init
#define cpu_exec cpu_sparc_exec
#define cpu_gen_code cpu_sparc_gen_code
#define cpu_interrupt cpu_sparc_interrupt
#define cpu_signal_handler cpu_sparc_signal_handler
#elif defined(TARGET_PPC)
#define CPUState CPUPPCState
#define cpu_init cpu_ppc_init
#define cpu_exec cpu_ppc_exec
#define cpu_gen_code cpu_ppc_gen_code
#define cpu_interrupt cpu_ppc_interrupt
#define cpu_signal_handler cpu_ppc_signal_handler
#else
#error unsupported target CPU
@@ -304,7 +456,37 @@ void page_unprotect_range(uint8_t *data, unsigned long data_size);
#endif /* SINGLE_CPU_DEFINES */
#define DEFAULT_GDBSTUB_PORT 1234
void cpu_abort(CPUState *env, const char *fmt, ...);
extern CPUState *cpu_single_env;
#define CPU_INTERRUPT_EXIT 0x01 /* wants exit from main loop */
#define CPU_INTERRUPT_HARD 0x02 /* hardware interrupt pending */
void cpu_interrupt(CPUState *s, int mask);
int cpu_breakpoint_insert(CPUState *env, uint32_t pc);
int cpu_breakpoint_remove(CPUState *env, uint32_t pc);
void cpu_single_step(CPUState *env, int enabled);
#define CPU_LOG_ALL 1
void cpu_set_log(int log_flags);
void cpu_set_log_filename(const char *filename);
/* memory API */
typedef void CPUWriteMemoryFunc(uint32_t addr, uint32_t value);
typedef uint32_t CPUReadMemoryFunc(uint32_t addr);
void cpu_register_physical_memory(unsigned long start_addr, unsigned long size,
long phys_offset);
int cpu_register_io_memory(int io_index,
CPUReadMemoryFunc **mem_read,
CPUWriteMemoryFunc **mem_write);
/* gdb stub API */
extern int gdbstub_fd;
CPUState *cpu_gdbstub_get_env(void *opaque);
int cpu_gdbstub(void *opaque, int (*main_loop)(void *opaque), int port);
#endif /* CPU_ALL_H */

46
cpu-defs.h Normal file
View File

@@ -0,0 +1,46 @@
/*
* common defines for all CPUs
*
* Copyright (c) 2003 Fabrice Bellard
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef CPU_DEFS_H
#define CPU_DEFS_H
#include "config.h"
#include <setjmp.h>
#define EXCP_INTERRUPT 256 /* async interruption */
#define EXCP_HLT 257 /* hlt instruction reached */
#define EXCP_DEBUG 258 /* cpu stopped after a breakpoint or singlestep */
#define MAX_BREAKPOINTS 32
#define CPU_TLB_SIZE 256
typedef struct CPUTLBEntry {
/* bit 31 to TARGET_PAGE_BITS : virtual address
bit TARGET_PAGE_BITS-1..IO_MEM_SHIFT : if non zero, memory io
zone number
bit 3 : indicates that the entry is invalid
bit 2..0 : zero
*/
uint32_t address;
/* addend to virtual address to get physical address */
uint32_t addend;
} CPUTLBEntry;
#endif

View File

@@ -18,19 +18,15 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "config.h"
#ifdef TARGET_I386
#include "exec-i386.h"
#endif
#ifdef TARGET_ARM
#include "exec-arm.h"
#endif
#include "exec.h"
#include "disas.h"
int tb_invalidated_flag;
//#define DEBUG_EXEC
//#define DEBUG_SIGNAL
#if defined(TARGET_ARM)
#if defined(TARGET_ARM) || defined(TARGET_SPARC)
/* XXX: unify with i386 target */
void cpu_loop_exit(void)
{
@@ -71,7 +67,7 @@ int cpu_exec(CPUState *env1)
#ifdef __sparc__
int saved_i7, tmp_T0;
#endif
int code_gen_size, ret;
int code_gen_size, ret, interrupt_request;
void (*gen_func)(void);
TranslationBlock *tb, **ptb;
uint8_t *tc_ptr, *cs_base, *pc;
@@ -136,10 +132,11 @@ int cpu_exec(CPUState *env1)
env->VF = (psr << 3) & 0x80000000;
env->cpsr = psr & ~0xf0000000;
}
#elif defined(TARGET_SPARC)
#elif defined(TARGET_PPC)
#else
#error unsupported target CPU
#endif
env->interrupt_request = 0;
env->exception_index = -1;
/* prepare setjmp context for exception handling */
@@ -171,33 +168,45 @@ int cpu_exec(CPUState *env1)
do_interrupt(env->exception_index,
env->exception_is_int,
env->error_code,
env->exception_next_eip);
env->exception_next_eip, 0);
#endif
}
env->exception_index = -1;
}
#if defined(TARGET_I386)
/* if hardware interrupt pending, we execute it */
if (env->hard_interrupt_request &&
(env->eflags & IF_MASK)) {
int intno;
intno = cpu_x86_get_pic_interrupt(env);
if (loglevel) {
fprintf(logfile, "Servicing hardware INT=0x%02x\n", intno);
}
do_interrupt(intno, 0, 0, 0);
env->hard_interrupt_request = 0;
}
#endif
T0 = 0; /* force lookup of first TB */
for(;;) {
#ifdef __sparc__
/* g1 can be modified by some libc? functions */
tmp_T0 = T0;
#endif
if (env->interrupt_request) {
env->exception_index = EXCP_INTERRUPT;
cpu_loop_exit();
interrupt_request = env->interrupt_request;
if (__builtin_expect(interrupt_request, 0)) {
#if defined(TARGET_I386)
/* if hardware interrupt pending, we execute it */
if ((interrupt_request & CPU_INTERRUPT_HARD) &&
(env->eflags & IF_MASK) &&
!(env->hflags & HF_INHIBIT_IRQ_MASK)) {
int intno;
intno = cpu_x86_get_pic_interrupt(env);
if (loglevel) {
fprintf(logfile, "Servicing hardware INT=0x%02x\n", intno);
}
do_interrupt(intno, 0, 0, 0, 1);
env->interrupt_request &= ~CPU_INTERRUPT_HARD;
/* ensure that no TB jump will be modified as
the program flow was changed */
#ifdef __sparc__
tmp_T0 = 0;
#else
T0 = 0;
#endif
}
#endif
if (interrupt_request & CPU_INTERRUPT_EXIT) {
env->interrupt_request &= ~CPU_INTERRUPT_EXIT;
env->exception_index = EXCP_INTERRUPT;
cpu_loop_exit();
}
}
#ifdef DEBUG_EXEC
if (loglevel) {
@@ -212,40 +221,41 @@ int cpu_exec(CPUState *env1)
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);
cpu_x86_dump_state(env, logfile, X86_DUMP_CCOP);
env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
#elif defined(TARGET_ARM)
env->cpsr = compute_cpsr();
cpu_arm_dump_state(env, logfile, 0);
env->cpsr &= ~0xf0000000;
#elif defined(TARGET_SPARC)
cpu_sparc_dump_state (env, logfile, 0);
#elif defined(TARGET_PPC)
cpu_ppc_dump_state(env, logfile, 0);
#else
#error unsupported target CPU
#endif
}
#endif
/* we compute the CPU state. We assume it will not
change during the whole generated block. */
/* we record a subset of the CPU state. It will
always be the same before a given translated block
is executed. */
#if defined(TARGET_I386)
flags = (env->segs[R_CS].flags & DESC_B_MASK)
>> (DESC_B_SHIFT - GEN_FLAG_CODE32_SHIFT);
flags |= (env->segs[R_SS].flags & DESC_B_MASK)
>> (DESC_B_SHIFT - GEN_FLAG_SS32_SHIFT);
flags |= (((unsigned long)env->segs[R_DS].base |
(unsigned long)env->segs[R_ES].base |
(unsigned long)env->segs[R_SS].base) != 0) <<
GEN_FLAG_ADDSEG_SHIFT;
if (!(env->eflags & VM_MASK)) {
flags |= (env->segs[R_CS].selector & 3) << GEN_FLAG_CPL_SHIFT;
} else {
/* NOTE: a dummy CPL is kept */
flags |= (1 << GEN_FLAG_VM_SHIFT);
flags |= (3 << GEN_FLAG_CPL_SHIFT);
}
flags |= (env->eflags & (IOPL_MASK | TF_MASK));
flags = env->hflags;
flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK));
cs_base = env->segs[R_CS].base;
pc = cs_base + env->eip;
#elif defined(TARGET_ARM)
flags = 0;
cs_base = 0;
pc = (uint8_t *)env->regs[15];
#elif defined(TARGET_SPARC)
flags = 0;
cs_base = env->npc;
pc = (uint8_t *) env->pc;
#elif defined(TARGET_PPC)
flags = 0;
cs_base = 0;
pc = (uint8_t *)env->nip;
#else
#error unsupported CPU
#endif
@@ -257,7 +267,7 @@ int cpu_exec(CPUState *env1)
tb = tb_alloc((unsigned long)pc);
if (!tb) {
/* flush must be done */
tb_flush();
tb_flush(env);
/* cannot fail at this point */
tb = tb_alloc((unsigned long)pc);
/* don't forget to invalidate previous TB info */
@@ -268,17 +278,17 @@ int cpu_exec(CPUState *env1)
tb->tc_ptr = tc_ptr;
tb->cs_base = (unsigned long)cs_base;
tb->flags = flags;
ret = cpu_gen_code(tb, CODE_GEN_MAX_SIZE, &code_gen_size);
#if defined(TARGET_I386)
/* XXX: suppress that, this is incorrect */
/* if invalid instruction, signal it */
if (ret != 0) {
/* NOTE: the tb is allocated but not linked, so we
can leave it */
spin_unlock(&tb_lock);
raise_exception(EXCP06_ILLOP);
tb_invalidated_flag = 0;
cpu_gen_code(env, tb, CODE_GEN_MAX_SIZE, &code_gen_size);
if (tb_invalidated_flag) {
/* as some TB could have been invalidated because
of memory exceptions while generating the code, we
must recompute the hash index here */
ptb = &tb_hash[tb_hash_func((unsigned long)pc)];
while (*ptb != NULL)
ptb = &(*ptb)->hash_next;
T0 = 0;
}
#endif
*ptb = tb;
tb->hash_next = NULL;
tb_link(tb);
@@ -295,12 +305,8 @@ int cpu_exec(CPUState *env1)
#ifdef __sparc__
T0 = tmp_T0;
#endif
/* see if we can patch the calling TB. XXX: remove TF test */
if (T0 != 0
#if defined(TARGET_I386)
&& !(env->eflags & TF_MASK)
#endif
) {
/* see if we can patch the calling TB. */
if (T0 != 0) {
spin_lock(&tb_lock);
tb_add_jump((TranslationBlock *)(T0 & ~3), T0 & 3, tb);
spin_unlock(&tb_lock);
@@ -326,6 +332,15 @@ int cpu_exec(CPUState *env1)
gen_func();
#endif
env->current_tb = NULL;
/* reset soft MMU for next block (it can currently
only be set by a memory fault) */
#if defined(TARGET_I386) && !defined(CONFIG_SOFTMMU)
if (env->hflags & HF_SOFTMMU_MASK) {
env->hflags &= ~HF_SOFTMMU_MASK;
/* do not allow linking to another block */
T0 = 0;
}
#endif
}
} else {
}
@@ -362,12 +377,9 @@ int cpu_exec(CPUState *env1)
EDI = saved_EDI;
#endif
#elif defined(TARGET_ARM)
{
int ZF;
ZF = (env->NZF == 0);
env->cpsr = env->cpsr | (env->NZF & 0x80000000) | (ZF << 30) |
(env->CF << 29) | ((env->VF & 0x80000000) >> 3);
}
env->cpsr = compute_cpsr();
#elif defined(TARGET_SPARC)
#elif defined(TARGET_PPC)
#else
#error unsupported target CPU
#endif
@@ -381,7 +393,7 @@ int cpu_exec(CPUState *env1)
return ret;
}
#if defined(TARGET_I386)
#if defined(TARGET_I386) && defined(CONFIG_USER_ONLY)
void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector)
{
@@ -389,18 +401,12 @@ void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector)
saved_env = env;
env = s;
if (env->eflags & VM_MASK) {
SegmentCache *sc;
if (!(env->cr[0] & CR0_PE_MASK) || (env->eflags & VM_MASK)) {
selector &= 0xffff;
sc = &env->segs[seg_reg];
/* NOTE: in VM86 mode, limit and flags are never reloaded,
so we must load them here */
sc->base = (void *)(selector << 4);
sc->limit = 0xffff;
sc->flags = 0;
sc->selector = selector;
cpu_x86_load_seg_cache(env, seg_reg, selector,
(uint8_t *)(selector << 4), 0xffff, 0);
} else {
load_seg(seg_reg, selector, 0);
load_seg(seg_reg, selector);
}
env = saved_env;
}
@@ -454,7 +460,7 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
{
TranslationBlock *tb;
int ret;
if (cpu_single_env)
env = cpu_single_env; /* XXX: find a correct solution for multithread */
#if defined(DEBUG_SIGNAL)
@@ -466,7 +472,8 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
return 1;
}
/* see if it is an MMU fault */
ret = cpu_x86_handle_mmu_fault(env, address, is_write);
ret = cpu_x86_handle_mmu_fault(env, address, is_write,
((env->hflags & HF_CPL_MASK) == 3), 0);
if (ret < 0)
return 0; /* not an MMU fault */
if (ret == 0)
@@ -478,6 +485,68 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
a virtual CPU fault */
cpu_restore_state(tb, env, pc);
}
if (ret == 1) {
#if 0
printf("PF exception: EIP=0x%08x CR2=0x%08x error=0x%x\n",
env->eip, env->cr[2], env->error_code);
#endif
/* we restore the process signal mask as the sigreturn should
do it (XXX: use sigsetjmp) */
sigprocmask(SIG_SETMASK, old_set, NULL);
raise_exception_err(EXCP0E_PAGE, env->error_code);
} else {
/* activate soft MMU for this block */
env->hflags |= HF_SOFTMMU_MASK;
sigprocmask(SIG_SETMASK, old_set, NULL);
cpu_loop_exit();
}
/* never comes here */
return 1;
}
#elif defined(TARGET_ARM)
static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
int is_write, sigset_t *old_set)
{
/* XXX: do more */
return 0;
}
#elif defined(TARGET_SPARC)
static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
int is_write, sigset_t *old_set)
{
/* XXX: locking issue */
if (is_write && page_unprotect(address)) {
return 1;
}
return 0;
}
#elif defined (TARGET_PPC)
static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
int is_write, sigset_t *old_set)
{
TranslationBlock *tb;
#if 0
if (cpu_single_env)
env = cpu_single_env; /* XXX: find a correct solution for multithread */
#endif
#if defined(DEBUG_SIGNAL)
printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
pc, address, is_write, *(unsigned long *)old_set);
#endif
/* XXX: locking issue */
if (is_write && page_unprotect(address)) {
return 1;
}
/* now we have a real cpu fault */
tb = tb_find_pc(pc);
if (tb) {
/* the PC is inside the translated code. It means that we have
a virtual CPU fault */
cpu_restore_state(tb, env, pc);
}
#if 0
printf("PF exception: EIP=0x%08x CR2=0x%08x error=0x%x\n",
env->eip, env->cr[2], env->error_code);
@@ -485,18 +554,10 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
/* we restore the process signal mask as the sigreturn should
do it (XXX: use sigsetjmp) */
sigprocmask(SIG_SETMASK, old_set, NULL);
raise_exception_err(EXCP0E_PAGE, env->error_code);
raise_exception_err(EXCP_PROGRAM, env->error_code);
/* never comes here */
return 1;
}
#elif defined(TARGET_ARM)
static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
int is_write, sigset_t *old_set)
{
/* XXX: do more */
return 0;
}
#else
#error unsupported target CPU
#endif
@@ -625,6 +686,23 @@ int cpu_signal_handler(int host_signum, struct siginfo *info,
&uc->uc_sigmask);
}
#elif defined(__mc68000)
int cpu_signal_handler(int host_signum, struct siginfo *info,
void *puc)
{
struct ucontext *uc = puc;
unsigned long pc;
int is_write;
pc = uc->uc_mcontext.gregs[16];
/* XXX: compute is_write */
is_write = 0;
return handle_cpu_signal(pc, (unsigned long)info->si_addr,
is_write,
&uc->uc_sigmask);
}
#else
#error host CPU specific signal handler needed

47
disas.c
View File

@@ -5,6 +5,9 @@
#include "elf.h"
#include <errno.h>
#include "cpu.h"
#include "exec-all.h"
/* Filled in by elfload.c. Simplistic, but will do for now. */
unsigned int disas_num_syms;
void *disas_symtab;
@@ -19,14 +22,32 @@ buffer_read_memory (memaddr, myaddr, length, info)
int length;
struct disassemble_info *info;
{
if (memaddr < info->buffer_vma
|| memaddr + length > info->buffer_vma + info->buffer_length)
/* Out of bounds. Use EIO because GDB uses it. */
return EIO;
memcpy (myaddr, info->buffer + (memaddr - info->buffer_vma), length);
return 0;
if (memaddr < info->buffer_vma
|| memaddr + length > info->buffer_vma + info->buffer_length)
/* Out of bounds. Use EIO because GDB uses it. */
return EIO;
memcpy (myaddr, info->buffer + (memaddr - info->buffer_vma), length);
return 0;
}
#if !defined(CONFIG_USER_ONLY)
/* Get LENGTH bytes from info's buffer, at target address memaddr.
Transfer them to myaddr. */
static int
target_read_memory (memaddr, myaddr, length, info)
bfd_vma memaddr;
bfd_byte *myaddr;
int length;
struct disassemble_info *info;
{
int i;
for(i = 0; i < length; i++) {
myaddr[i] = ldub_code((void *)((long)memaddr + i));
}
return 0;
}
#endif
/* Print an error message. We can assume that this is in response to
an error return from buffer_read_memory. */
void
@@ -42,7 +63,7 @@ perror_memory (status, memaddr, info)
/* Actually, address between memaddr and memaddr + len was
out of bounds. */
(*info->fprintf_func) (info->stream,
"Address 0x%x is out of bounds.\n", memaddr);
"Address 0x%llx is out of bounds.\n", memaddr);
}
/* This could be in a separate file, to save miniscule amounts of space
@@ -57,7 +78,7 @@ generic_print_address (addr, info)
bfd_vma addr;
struct disassemble_info *info;
{
(*info->fprintf_func) (info->stream, "0x%x", addr);
(*info->fprintf_func) (info->stream, "0x%llx", addr);
}
/* Just return the given address. */
@@ -103,6 +124,12 @@ void disas(FILE *out, void *code, unsigned long size, int is_host, int flags)
INIT_DISASSEMBLE_INFO(disasm_info, out, fprintf);
#if !defined(CONFIG_USER_ONLY)
if (!is_host) {
disasm_info.read_memory_func = target_read_memory;
}
#endif
disasm_info.buffer = code;
disasm_info.buffer_vma = (unsigned long)code;
disasm_info.buffer_length = size;
@@ -142,6 +169,10 @@ void disas(FILE *out, void *code, unsigned long size, int is_host, int flags)
print_insn = print_insn_i386;
#elif defined(TARGET_ARM)
print_insn = print_insn_arm;
#elif defined(TARGET_SPARC)
print_insn = print_insn_sparc;
#elif defined(TARGET_PPC)
print_insn = print_insn_ppc;
#else
fprintf(out, "Asm output not supported on this arch\n");
return;

View File

@@ -17,6 +17,9 @@
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#if !defined(__DYNGEN_EXEC_H__)
#define __DYNGEN_EXEC_H__
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
@@ -27,6 +30,19 @@ typedef signed short int16_t;
typedef signed int int32_t;
typedef signed long long int64_t;
#define INT8_MIN (-128)
#define INT16_MIN (-32767-1)
#define INT32_MIN (-2147483647-1)
#define INT64_MIN (-(int64_t)(9223372036854775807)-1)
#define INT8_MAX (127)
#define INT16_MAX (32767)
#define INT32_MAX (2147483647)
#define INT64_MAX ((int64_t)(9223372036854775807))
#define UINT8_MAX (255)
#define UINT16_MAX (65535)
#define UINT32_MAX (4294967295U)
#define UINT64_MAX ((uint64_t)(18446744073709551615))
#define bswap32(x) \
({ \
uint32_t __x = (x); \
@@ -54,6 +70,8 @@ extern int printf(const char *, ...);
#define AREG1 "r24"
#define AREG2 "r25"
#define AREG3 "r26"
/* XXX: suppress this hack */
#if defined(CONFIG_USER_ONLY)
#define AREG4 "r16"
#define AREG5 "r17"
#define AREG6 "r18"
@@ -62,6 +80,7 @@ extern int printf(const char *, ...);
#define AREG9 "r21"
#define AREG10 "r22"
#define AREG11 "r23"
#endif
#define USE_INT_TO_FLOAT_HELPERS
#define BUGGY_GCC_DIV64
#endif
@@ -109,6 +128,13 @@ extern int printf(const char *, ...);
#define AREG5 "$13"
#define AREG6 "$14"
#endif
#ifdef __mc68000
#define AREG0 "%a5"
#define AREG1 "%a4"
#define AREG2 "%d7"
#define AREG3 "%d6"
#define AREG4 "%d5"
#endif
#ifdef __ia64__
#define AREG0 "r27"
#define AREG1 "r24"
@@ -125,6 +151,8 @@ extern int printf(const char *, ...);
#define xglue(x, y) x ## y
#define glue(x, y) xglue(x, y)
#define stringify(s) tostring(s)
#define tostring(s) #s
#ifdef __alpha__
/* the symbols are considered non exported so a br immediate is generated */
@@ -152,4 +180,32 @@ extern int __op_param1, __op_param2, __op_param3;
#define PARAM3 ((long)(&__op_param3))
#endif
extern int __op_jmp0, __op_jmp1;
extern int __op_jmp0, __op_jmp1, __op_jmp2, __op_jmp3;
#ifdef __i386__
#define EXIT_TB() asm volatile ("ret")
#endif
#ifdef __powerpc__
#define EXIT_TB() asm volatile ("blr")
#endif
#ifdef __s390__
#define EXIT_TB() asm volatile ("br %r14")
#endif
#ifdef __alpha__
#define EXIT_TB() asm volatile ("ret")
#endif
#ifdef __ia64__
#define EXIT_TB() asm volatile ("br.ret.sptk.many b0;;")
#endif
#ifdef __sparc__
#define EXIT_TB() asm volatile ("jmpl %i0 + 8, %g0\n" \
"nop")
#endif
#ifdef __arm__
#define EXIT_TB() asm volatile ("b exec_loop")
#endif
#ifdef __mc68000
#define EXIT_TB() asm volatile ("rts")
#endif
#endif /* !defined(__DYNGEN_EXEC_H__) */

118
dyngen.c
View File

@@ -25,7 +25,7 @@
#include <unistd.h>
#include <fcntl.h>
#include "config.h"
#include "config-host.h"
/* elf format definitions. We use these macros to test the CPU to
allow cross compilation (this tool must be ran on the build
@@ -86,6 +86,13 @@
#define elf_check_arch(x) ((x) == EM_ARM)
#define ELF_USES_RELOC
#elif defined(HOST_M68K)
#define ELF_CLASS ELFCLASS32
#define ELF_ARCH EM_68K
#define elf_check_arch(x) ((x) == EM_68K)
#define ELF_USES_RELOCA
#else
#error unsupported CPU - please update the code
#endif
@@ -108,7 +115,7 @@ typedef uint64_t host_ulong;
#define SHT_RELOC SHT_REL
#endif
#include "thunk.h"
#include "bswap.h"
enum {
OUT_GEN_OP,
@@ -575,6 +582,21 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
relocs, nb_relocs);
break;
#endif
case EM_68K:
{
uint8_t *p;
p = (void *)(p_end - 2);
if (p == p_start)
error("empty code for %s", name);
// remove NOP's, probably added for alignment
while ((get16((uint16_t *)p) == 0x4e71) &&
(p>p_start))
p -= 2;
if (get16((uint16_t *)p) != 0x4e75)
error("rts expected at the end of %s", name);
copy_size = p - p_start;
}
break;
default:
error("unknown ELF architecture");
}
@@ -647,7 +669,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
{
ElfW(Sym) *sym;
const char *sym_name, *p;
target_ulong val;
unsigned long val;
int n;
for(i = 0, sym = symtab; i < nb_syms; i++, sym++) {
@@ -662,7 +684,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
if (!ptr)
error("__op_labelN in invalid section");
offset = sym->st_value;
val = *(target_ulong *)(ptr + offset);
val = *(unsigned long *)(ptr + offset);
#ifdef ELF_USES_RELOCA
{
int reloc_shndx, nb_relocs1, j;
@@ -686,7 +708,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
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);
fprintf(outfile, " label_offsets[%d] = %ld + (gen_code_ptr - gen_code_buf);\n", n, val - start_offset);
}
}
}
@@ -1062,6 +1084,41 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
}
}
}
#elif defined(HOST_M68K)
{
char name[256];
int type;
int addend;
Elf32_Sym *sym;
for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
if (rel->r_offset >= start_offset &&
rel->r_offset < start_offset + copy_size) {
sym = &(symtab[ELFW(R_SYM)(rel->r_info)]);
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 {
snprintf(name, sizeof(name), "(long)(&%s)", sym_name);
}
type = ELF32_R_TYPE(rel->r_info);
addend = get32((uint32_t *)(text + rel->r_offset)) + rel->r_addend;
switch(type) {
case R_68K_32:
fprintf(outfile, " /* R_68K_32 RELOC, offset %x */\n", rel->r_offset) ;
fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %#x;\n",
rel->r_offset - start_offset, name, addend );
break;
case R_68K_PC32:
fprintf(outfile, " /* R_68K_PC32 RELOC, offset %x */\n", rel->r_offset);
fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s - (long)(gen_code_ptr + %#x) + %#x;\n",
rel->r_offset - start_offset, name, rel->r_offset - start_offset, /*sym->st_value+*/ addend);
break;
default:
error("unsupported m68k relocation (%d)", type);
}
}
}
}
#else
#error unsupported CPU
#endif
@@ -1200,6 +1257,10 @@ int load_elf(const char *filename, FILE *outfile, int out_type)
if (out_type == OUT_INDEX_OP) {
fprintf(outfile, "DEF(end, 0, 0)\n");
fprintf(outfile, "DEF(nop, 0, 0)\n");
fprintf(outfile, "DEF(nop1, 1, 0)\n");
fprintf(outfile, "DEF(nop2, 2, 0)\n");
fprintf(outfile, "DEF(nop3, 3, 0)\n");
for(i = 0, sym = symtab; i < nb_syms; i++, sym++) {
const char *name, *p;
name = strtab + sym->st_name;
@@ -1269,6 +1330,17 @@ fprintf(outfile,
}
fprintf(outfile,
" case INDEX_op_nop:\n"
" break;\n"
" case INDEX_op_nop1:\n"
" opparam_ptr++;\n"
" break;\n"
" case INDEX_op_nop2:\n"
" opparam_ptr += 2;\n"
" break;\n"
" case INDEX_op_nop3:\n"
" opparam_ptr += 3;\n"
" break;\n"
" default:\n"
" goto the_end;\n"
" }\n");
@@ -1290,38 +1362,10 @@ fprintf(outfile,
" the_end:\n"
);
/* generate epilogue */
switch(ELF_ARCH) {
case EM_386:
fprintf(outfile, "*gen_code_ptr++ = 0xc3; /* ret */\n");
break;
case EM_PPC:
fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0x4e800020; /* blr */\n");
break;
case EM_S390:
fprintf(outfile, "*((uint16_t *)gen_code_ptr)++ = 0x07fe; /* br %%r14 */\n");
break;
case EM_ALPHA:
fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0x6bfa8001; /* ret */\n");
break;
case EM_IA_64:
fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0x00840008; /* br.ret.sptk.many b0;; */\n");
break;
case EM_SPARC:
case EM_SPARC32PLUS:
fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0x81c62008; /* jmpl %%i0 + 8, %%g0 */\n");
fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0x01000000; /* nop */\n");
break;
case EM_SPARCV9:
fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0x81c7e008; /* ret */\n");
fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0x81e80000; /* restore */\n");
break;
case EM_ARM:
fprintf(outfile, "gen_code_ptr = arm_flush_ldr(gen_code_ptr, arm_ldr_table, arm_ldr_ptr, arm_data_table, arm_data_ptr, 0);\n");
break;
default:
error("unknown ELF architecture");
}
/* generate some code patching */
#ifdef HOST_ARM
fprintf(outfile, "gen_code_ptr = arm_flush_ldr(gen_code_ptr, arm_ldr_table, arm_ldr_ptr, arm_data_table, arm_data_ptr, 0);\n");
#endif
/* flush instruction cache */
fprintf(outfile, "flush_icache_range((unsigned long)gen_code_buf, (unsigned long)gen_code_ptr);\n");

View File

@@ -19,7 +19,7 @@
*/
int __op_param1, __op_param2, __op_param3;
int __op_jmp0, __op_jmp1;
int __op_jmp0, __op_jmp1, __op_jmp2, __op_jmp3;
#ifdef __i386__
static inline void flush_icache_range(unsigned long start, unsigned long stop)
@@ -94,6 +94,14 @@ static inline void flush_icache_range(unsigned long start, unsigned long stop)
}
#endif
#ifdef __mc68000
#include <asm/cachectl.h>
static inline void flush_icache_range(unsigned long start, unsigned long stop)
{
cacheflush(start,FLUSH_SCOPE_LINE,FLUSH_CACHE_BOTH,stop-start+16);
}
#endif
#ifdef __alpha__
register int gp asm("$29");
@@ -152,11 +160,7 @@ static uint8_t *arm_flush_ldr(uint8_t *gen_code_ptr,
data_size = (uint8_t *)data_end - (uint8_t *)data_start;
if (!gen_jmp) {
/* b exec_loop */
arm_reloc_pc24((uint32_t *)gen_code_ptr, 0xeafffffe, (long)(&exec_loop));
gen_code_ptr += 4;
} else {
if (gen_jmp) {
/* generate branch to skip the data */
if (data_size == 0)
return gen_code_ptr;

View File

@@ -21,6 +21,23 @@
/* allow to see translation results - the slowdown should be negligible, so we leave it */
#define DEBUG_DISAS
#ifndef glue
#define xglue(x, y) x ## y
#define glue(x, y) xglue(x, y)
#define stringify(s) tostring(s)
#define tostring(s) #s
#endif
#if GCC_MAJOR < 3
#define __builtin_expect(x, n) (x)
#endif
#ifdef __i386__
#define REGPARM(n) __attribute((regparm(n)))
#else
#define REGPARM(n)
#endif
/* is_jmp field values */
#define DISAS_NEXT 0 /* next instruction can be analyzed */
#define DISAS_JUMP 1 /* only pc was modified dynamically */
@@ -44,30 +61,26 @@ extern uint8_t gen_opc_instr_start[OPC_BUF_SIZE];
#if defined(TARGET_I386)
#define GEN_FLAG_CODE32_SHIFT 0
#define GEN_FLAG_ADDSEG_SHIFT 1
#define GEN_FLAG_SS32_SHIFT 2
#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 */
void optimize_flags_init(void);
#endif
extern FILE *logfile;
extern int loglevel;
int gen_intermediate_code(struct TranslationBlock *tb);
int gen_intermediate_code_pc(struct TranslationBlock *tb);
int gen_intermediate_code(CPUState *env, struct TranslationBlock *tb);
int gen_intermediate_code_pc(CPUState *env, struct TranslationBlock *tb);
void dump_ops(const uint16_t *opc_buf, const uint32_t *opparam_buf);
int cpu_gen_code(struct TranslationBlock *tb,
int cpu_gen_code(CPUState *env, struct TranslationBlock *tb,
int max_code_size, int *gen_code_size_ptr);
int cpu_restore_state(struct TranslationBlock *tb,
CPUState *env, unsigned long searched_pc);
void cpu_exec_init(void);
int page_unprotect(unsigned long address);
void page_unmap(void);
void tb_invalidate_page(unsigned long address);
void tlb_flush_page(CPUState *env, uint32_t addr);
void tlb_flush_page_write(CPUState *env, uint32_t addr);
void tlb_flush(CPUState *env);
#define CODE_GEN_MAX_SIZE 65536
#define CODE_GEN_ALIGN 16 /* must be >= of the size of a icache line */
@@ -96,7 +109,7 @@ typedef struct TranslationBlock {
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 */
uint16_t tb_jmp_offset[4]; /* offset of jump instruction */
#else
uint32_t tb_next[2]; /* address of jump generated code */
#endif
@@ -114,7 +127,7 @@ static inline unsigned int tb_hash_func(unsigned long pc)
}
TranslationBlock *tb_alloc(unsigned long pc);
void tb_flush(void);
void tb_flush(CPUState *env);
void tb_link(TranslationBlock *tb);
extern TranslationBlock *tb_hash[CODE_GEN_HASH_SIZE];
@@ -148,18 +161,14 @@ static inline TranslationBlock *tb_find(TranslationBlock ***pptb,
#if defined(__powerpc__)
static inline void tb_set_jmp_target(TranslationBlock *tb,
int n, unsigned long addr)
static inline void tb_set_jmp_target1(unsigned long jmp_addr, 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;
ptr = (uint32_t *)jmp_addr;
val = *ptr;
val = (val & ~0x03fffffc) | ((addr - offset) & 0x03fffffc);
val = (val & ~0x03fffffc) | ((addr - jmp_addr) & 0x03fffffc);
*ptr = val;
/* flush icache */
asm volatile ("dcbst 0,%0" : : "r"(ptr) : "memory");
@@ -169,6 +178,18 @@ static inline void tb_set_jmp_target(TranslationBlock *tb,
asm volatile ("isync" : : : "memory");
}
static inline void tb_set_jmp_target(TranslationBlock *tb,
int n, unsigned long addr)
{
unsigned long offset;
offset = tb->tb_jmp_offset[n];
tb_set_jmp_target1((unsigned long)(tb->tc_ptr + offset), addr);
offset = tb->tb_jmp_offset[n + 2];
if (offset != 0xffff)
tb_set_jmp_target1((unsigned long)(tb->tc_ptr + offset), addr);
}
#else
/* set the jump target */
@@ -203,30 +224,59 @@ TranslationBlock *tb_find_pc(unsigned long pc_ptr);
#if defined(__powerpc__)
/* on PowerPC we patch the jump instruction directly */
#define JUMP_TB(tbparam, n, eip)\
#define JUMP_TB(opname, tbparam, n, eip)\
do {\
static void __attribute__((unused)) *__op_label ## n = &&label ## n;\
asm volatile ("b %0" : : "i" (&__op_jmp ## n));\
label ## n:\
asm volatile (".section \".data\"\n"\
"__op_label" #n "." stringify(opname) ":\n"\
".long 1f\n"\
".previous\n"\
"b __op_jmp" #n "\n"\
"1:\n");\
T0 = (long)(tbparam) + (n);\
EIP = eip;\
EXIT_TB();\
} while (0)
#define JUMP_TB2(opname, tbparam, n)\
do {\
asm volatile ("b __op_jmp%0\n" : : "i" (n + 2));\
} 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)\
#define JUMP_TB(opname, tbparam, n, eip)\
do {\
static void __attribute__((unused)) *__op_label ## n = &&label ## n;\
static void __attribute__((unused)) *dummy ## n = &&dummy_label ## n;\
goto *(void *)(((TranslationBlock *)tbparam)->tb_next[n]);\
label ## n:\
T0 = (long)(tbparam) + (n);\
EIP = eip;\
dummy_label ## n:\
EXIT_TB();\
} while (0)
/* second jump to same destination 'n' */
#define JUMP_TB2(opname, tbparam, n)\
do {\
goto *(void *)(((TranslationBlock *)tbparam)->tb_next[n]);\
} while (0)
#endif
/* physical memory access */
#define IO_MEM_NB_ENTRIES 256
#define TLB_INVALID_MASK (1 << 3)
#define IO_MEM_SHIFT 4
#define IO_MEM_UNASSIGNED (1 << IO_MEM_SHIFT)
unsigned long physpage_find(unsigned long page);
extern CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4];
extern CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4];
#ifdef __powerpc__
static inline int testandset (int *p)
{
@@ -318,10 +368,23 @@ static inline int testandset (int *spinlock)
}
#endif
#ifdef __mc68000
static inline int testandset (int *p)
{
char ret;
__asm__ __volatile__("tas %1; sne %0"
: "=r" (ret)
: "m" (p)
: "cc","memory");
return ret == 0;
}
#endif
typedef int spinlock_t;
#define SPIN_LOCK_UNLOCKED 0
#if defined(CONFIG_USER_ONLY)
static inline void spin_lock(spinlock_t *lock)
{
while (testandset(lock));
@@ -336,6 +399,45 @@ static inline int spin_trylock(spinlock_t *lock)
{
return !testandset(lock);
}
#else
static inline void spin_lock(spinlock_t *lock)
{
}
static inline void spin_unlock(spinlock_t *lock)
{
}
static inline int spin_trylock(spinlock_t *lock)
{
return 1;
}
#endif
extern spinlock_t tb_lock;
extern int tb_invalidated_flag;
#if defined(TARGET_I386) && !defined(CONFIG_USER_ONLY)
void tlb_fill(unsigned long addr, int is_write, int is_user,
void *retaddr);
#define ACCESS_TYPE 3
#define MEMSUFFIX _code
#define env cpu_single_env
#define DATA_SIZE 1
#include "softmmu_header.h"
#define DATA_SIZE 2
#include "softmmu_header.h"
#define DATA_SIZE 4
#include "softmmu_header.h"
#undef ACCESS_TYPE
#undef MEMSUFFIX
#undef env
#endif

379
exec.c
View File

@@ -27,13 +27,8 @@
#include <sys/mman.h>
#include "config.h"
#ifdef TARGET_I386
#include "cpu-i386.h"
#endif
#ifdef TARGET_ARM
#include "cpu-arm.h"
#endif
#include "exec.h"
#include "cpu.h"
#include "exec-all.h"
//#define DEBUG_TB_INVALIDATE
//#define DEBUG_FLUSH
@@ -67,7 +62,7 @@ typedef struct PageDesc {
#define L1_SIZE (1 << L1_BITS)
#define L2_SIZE (1 << L2_BITS)
static void tb_invalidate_page(unsigned long address);
static void io_mem_init(void);
unsigned long real_host_page_size;
unsigned long host_page_bits;
@@ -76,6 +71,17 @@ unsigned long host_page_mask;
static PageDesc *l1_map[L1_SIZE];
/* io memory support */
static unsigned long *l1_physmap[L1_SIZE];
CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4];
CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4];
static int io_mem_nb;
/* log support */
char *logfilename = "/tmp/qemu.log";
FILE *logfile;
int loglevel;
static void page_init(void)
{
/* NOTE: we can always suppose that host_page_size >=
@@ -201,6 +207,7 @@ void cpu_exec_init(void)
if (!code_gen_ptr) {
code_gen_ptr = code_gen_buffer;
page_init();
io_mem_init();
}
}
@@ -221,15 +228,19 @@ static void page_flush_tb(void)
/* flush all the translation blocks */
/* XXX: tb_flush is currently not thread safe */
void tb_flush(void)
void tb_flush(CPUState *env)
{
int i;
#ifdef DEBUG_FLUSH
#if defined(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);
nb_tbs > 0 ? (code_gen_ptr - code_gen_buffer) / nb_tbs : 0);
#endif
/* must reset current TB so that interrupts cannot modify the
links while we are modifying them */
env->current_tb = NULL;
nb_tbs = 0;
for(i = 0;i < CODE_GEN_HASH_SIZE; i++)
tb_hash[i] = NULL;
@@ -354,6 +365,8 @@ static inline void tb_invalidate(TranslationBlock *tb, int parity)
unsigned int h, n1;
TranslationBlock *tb1, *tb2;
tb_invalidated_flag = 1;
/* remove the TB from the hash list */
h = tb_hash_func(tb->pc);
tb_remove(&tb_hash[h], tb,
@@ -392,7 +405,7 @@ static inline void tb_invalidate(TranslationBlock *tb, int parity)
}
/* invalidate all TBs which intersect with the target page starting at addr */
static void tb_invalidate_page(unsigned long address)
void tb_invalidate_page(unsigned long address)
{
TranslationBlock *tb_next, *tb;
unsigned int page_index;
@@ -436,16 +449,20 @@ static inline void tb_alloc_page(TranslationBlock *tb, unsigned int page_index)
prot = 0;
for(addr = host_start; addr < host_end; addr += TARGET_PAGE_SIZE)
prot |= page_get_flags(addr);
#if !defined(CONFIG_SOFTMMU)
mprotect((void *)host_start, host_page_size,
(prot & PAGE_BITS) & ~PAGE_WRITE);
#endif
#if !defined(CONFIG_USER_ONLY)
/* suppress soft TLB */
/* XXX: must flush on all processor with same address space */
tlb_flush_page_write(cpu_single_env, host_start);
#endif
#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
}
}
@@ -475,6 +492,9 @@ void tb_link(TranslationBlock *tb)
if (page_index2 != page_index1) {
tb_alloc_page(tb, page_index2);
}
#ifdef DEBUG_TB_CHECK
tb_page_check();
#endif
tb->jmp_first = (TranslationBlock *)((long)tb | 2);
tb->jmp_next[0] = NULL;
tb->jmp_next[1] = NULL;
@@ -509,20 +529,23 @@ int page_unprotect(unsigned long address)
/* 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);
if (!(p1[pindex].flags & PAGE_WRITE)) {
#if !defined(CONFIG_SOFTMMU)
mprotect((void *)host_start, host_page_size,
(prot & PAGE_BITS) | PAGE_WRITE);
#endif
return 1;
} else {
return 0;
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;
}
}
return 0;
}
/* call this function when system calls directly modify a memory area */
@@ -606,7 +629,7 @@ static inline void tb_reset_jump_recursive2(TranslationBlock *tb, int n)
/* suppress the jump to next tb in generated code */
tb_reset_jump(tb, n);
/* suppress jumps in the tb on which we could have jump */
/* suppress jumps in the tb on which we could have jumped */
tb_reset_jump_recursive(tb_next);
}
}
@@ -617,11 +640,87 @@ static void tb_reset_jump_recursive(TranslationBlock *tb)
tb_reset_jump_recursive2(tb, 1);
}
void cpu_interrupt(CPUState *env)
/* add a breakpoint. EXCP_DEBUG is returned by the CPU loop if a
breakpoint is reached */
int cpu_breakpoint_insert(CPUState *env, uint32_t pc)
{
#if defined(TARGET_I386)
int i;
for(i = 0; i < env->nb_breakpoints; i++) {
if (env->breakpoints[i] == pc)
return 0;
}
if (env->nb_breakpoints >= MAX_BREAKPOINTS)
return -1;
env->breakpoints[env->nb_breakpoints++] = pc;
tb_invalidate_page(pc);
return 0;
#else
return -1;
#endif
}
/* remove a breakpoint */
int cpu_breakpoint_remove(CPUState *env, uint32_t pc)
{
#if defined(TARGET_I386)
int i;
for(i = 0; i < env->nb_breakpoints; i++) {
if (env->breakpoints[i] == pc)
goto found;
}
return -1;
found:
memmove(&env->breakpoints[i], &env->breakpoints[i + 1],
(env->nb_breakpoints - (i + 1)) * sizeof(env->breakpoints[0]));
env->nb_breakpoints--;
tb_invalidate_page(pc);
return 0;
#else
return -1;
#endif
}
/* enable or disable single step mode. EXCP_DEBUG is returned by the
CPU loop after each instruction */
void cpu_single_step(CPUState *env, int enabled)
{
#if defined(TARGET_I386)
if (env->singlestep_enabled != enabled) {
env->singlestep_enabled = enabled;
/* must flush all the translated code to avoid inconsistancies */
tb_flush(env);
}
#endif
}
/* enable or disable low levels log */
void cpu_set_log(int log_flags)
{
loglevel = log_flags;
if (loglevel && !logfile) {
logfile = fopen(logfilename, "w");
if (!logfile) {
perror(logfilename);
_exit(1);
}
setvbuf(logfile, NULL, _IOLBF, 0);
}
}
void cpu_set_log_filename(const char *filename)
{
logfilename = strdup(filename);
}
/* mask must never be zero, except for A20 change call */
void cpu_interrupt(CPUState *env, int mask)
{
TranslationBlock *tb;
env->interrupt_request = 1;
env->interrupt_request |= mask;
/* if the cpu is currently executing code, we must unlink it and
all the potentially executing TB */
tb = env->current_tb;
@@ -646,17 +745,22 @@ void cpu_abort(CPUState *env, const char *fmt, ...)
abort();
}
#ifdef TARGET_I386
#if !defined(CONFIG_USER_ONLY)
/* unmap all maped pages and flush all associated code */
void page_unmap(void)
static void page_unmap(CPUState *env)
{
PageDesc *p, *pmap;
unsigned long addr;
int i, j, ret, j1;
PageDesc *pmap;
int i;
for(i = 0; i < L1_SIZE; i++) {
pmap = l1_map[i];
if (pmap) {
#if !defined(CONFIG_SOFTMMU)
PageDesc *p;
unsigned long addr;
int j, ret, j1;
p = pmap;
for(j = 0;j < L2_SIZE;) {
if (p->flags & PAGE_VALID) {
@@ -679,10 +783,213 @@ void page_unmap(void)
j++;
}
}
#endif
free(pmap);
l1_map[i] = NULL;
}
}
tb_flush();
tb_flush(env);
}
void tlb_flush(CPUState *env)
{
int i;
/* must reset current TB so that interrupts cannot modify the
links while we are modifying them */
env->current_tb = NULL;
for(i = 0; i < CPU_TLB_SIZE; i++) {
env->tlb_read[0][i].address = -1;
env->tlb_write[0][i].address = -1;
env->tlb_read[1][i].address = -1;
env->tlb_write[1][i].address = -1;
}
/* XXX: avoid flushing the TBs */
page_unmap(env);
}
static inline void tlb_flush_entry(CPUTLBEntry *tlb_entry, uint32_t addr)
{
if (addr == (tlb_entry->address &
(TARGET_PAGE_MASK | TLB_INVALID_MASK)))
tlb_entry->address = -1;
}
void tlb_flush_page(CPUState *env, uint32_t addr)
{
int i, flags;
/* must reset current TB so that interrupts cannot modify the
links while we are modifying them */
env->current_tb = NULL;
addr &= TARGET_PAGE_MASK;
i = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
tlb_flush_entry(&env->tlb_read[0][i], addr);
tlb_flush_entry(&env->tlb_write[0][i], addr);
tlb_flush_entry(&env->tlb_read[1][i], addr);
tlb_flush_entry(&env->tlb_write[1][i], addr);
flags = page_get_flags(addr);
if (flags & PAGE_VALID) {
#if !defined(CONFIG_SOFTMMU)
munmap((void *)addr, TARGET_PAGE_SIZE);
#endif
page_set_flags(addr, addr + TARGET_PAGE_SIZE, 0);
}
}
/* make all write to page 'addr' trigger a TLB exception to detect
self modifying code */
void tlb_flush_page_write(CPUState *env, uint32_t addr)
{
int i;
addr &= TARGET_PAGE_MASK;
i = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
tlb_flush_entry(&env->tlb_write[0][i], addr);
tlb_flush_entry(&env->tlb_write[1][i], addr);
}
#else
void tlb_flush(CPUState *env)
{
}
void tlb_flush_page(CPUState *env, uint32_t addr)
{
}
void tlb_flush_page_write(CPUState *env, uint32_t addr)
{
}
#endif /* defined(CONFIG_USER_ONLY) */
static inline unsigned long *physpage_find_alloc(unsigned int page)
{
unsigned long **lp, *p;
unsigned int index, i;
index = page >> TARGET_PAGE_BITS;
lp = &l1_physmap[index >> L2_BITS];
p = *lp;
if (!p) {
/* allocate if not found */
p = malloc(sizeof(unsigned long) * L2_SIZE);
for(i = 0; i < L2_SIZE; i++)
p[i] = IO_MEM_UNASSIGNED;
*lp = p;
}
return p + (index & (L2_SIZE - 1));
}
/* return NULL if no page defined (unused memory) */
unsigned long physpage_find(unsigned long page)
{
unsigned long *p;
unsigned int index;
index = page >> TARGET_PAGE_BITS;
p = l1_physmap[index >> L2_BITS];
if (!p)
return IO_MEM_UNASSIGNED;
return p[index & (L2_SIZE - 1)];
}
/* register physical memory. 'size' must be a multiple of the target
page size. If (phys_offset & ~TARGET_PAGE_MASK) != 0, then it is an
io memory page */
void cpu_register_physical_memory(unsigned long start_addr, unsigned long size,
long phys_offset)
{
unsigned long addr, end_addr;
unsigned long *p;
end_addr = start_addr + size;
for(addr = start_addr; addr < end_addr; addr += TARGET_PAGE_SIZE) {
p = physpage_find_alloc(addr);
*p = phys_offset;
if ((phys_offset & ~TARGET_PAGE_MASK) == 0)
phys_offset += TARGET_PAGE_SIZE;
}
}
static uint32_t unassigned_mem_readb(uint32_t addr)
{
return 0;
}
static void unassigned_mem_writeb(uint32_t addr, uint32_t val)
{
}
static CPUReadMemoryFunc *unassigned_mem_read[3] = {
unassigned_mem_readb,
unassigned_mem_readb,
unassigned_mem_readb,
};
static CPUWriteMemoryFunc *unassigned_mem_write[3] = {
unassigned_mem_writeb,
unassigned_mem_writeb,
unassigned_mem_writeb,
};
static void io_mem_init(void)
{
io_mem_nb = 1;
cpu_register_io_memory(0, unassigned_mem_read, unassigned_mem_write);
}
/* mem_read and mem_write are arrays of functions containing the
function to access byte (index 0), word (index 1) and dword (index
2). All functions must be supplied. If io_index is non zero, the
corresponding io zone is modified. If it is zero, a new io zone is
allocated. The return value can be used with
cpu_register_physical_memory(). (-1) is returned if error. */
int cpu_register_io_memory(int io_index,
CPUReadMemoryFunc **mem_read,
CPUWriteMemoryFunc **mem_write)
{
int i;
if (io_index <= 0) {
if (io_index >= IO_MEM_NB_ENTRIES)
return -1;
io_index = io_mem_nb++;
} else {
if (io_index >= IO_MEM_NB_ENTRIES)
return -1;
}
for(i = 0;i < 3; i++) {
io_mem_read[io_index][i] = mem_read[i];
io_mem_write[io_index][i] = mem_write[i];
}
return io_index << IO_MEM_SHIFT;
}
#if !defined(CONFIG_USER_ONLY)
#define MMUSUFFIX _cmmu
#define GETPC() NULL
#define env cpu_single_env
#define SHIFT 0
#include "softmmu_template.h"
#define SHIFT 1
#include "softmmu_template.h"
#define SHIFT 2
#include "softmmu_template.h"
#define SHIFT 3
#include "softmmu_template.h"
#undef env
#endif

533
gdbstub.c Normal file
View File

@@ -0,0 +1,533 @@
/*
* gdb server stub
*
* Copyright (c) 2003 Fabrice Bellard
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <signal.h>
#include "config.h"
#include "cpu.h"
#include "thunk.h"
#include "exec-all.h"
//#define DEBUG_GDB
int gdbstub_fd = -1;
/* return 0 if OK */
static int gdbstub_open(int port)
{
struct sockaddr_in sockaddr;
socklen_t len;
int fd, val, ret;
fd = socket(PF_INET, SOCK_STREAM, 0);
if (fd < 0) {
perror("socket");
return -1;
}
/* allow fast reuse */
val = 1;
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
sockaddr.sin_family = AF_INET;
sockaddr.sin_port = htons(port);
sockaddr.sin_addr.s_addr = 0;
ret = bind(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr));
if (ret < 0) {
perror("bind");
return -1;
}
ret = listen(fd, 0);
if (ret < 0) {
perror("listen");
return -1;
}
/* now wait for one connection */
for(;;) {
len = sizeof(sockaddr);
gdbstub_fd = accept(fd, (struct sockaddr *)&sockaddr, &len);
if (gdbstub_fd < 0 && errno != EINTR) {
perror("accept");
return -1;
} else if (gdbstub_fd >= 0) {
break;
}
}
/* set short latency */
val = 1;
setsockopt(gdbstub_fd, SOL_TCP, TCP_NODELAY, &val, sizeof(val));
return 0;
}
static int get_char(void)
{
uint8_t ch;
int ret;
for(;;) {
ret = read(gdbstub_fd, &ch, 1);
if (ret < 0) {
if (errno != EINTR && errno != EAGAIN)
return -1;
} else if (ret == 0) {
return -1;
} else {
break;
}
}
return ch;
}
static void put_buffer(const uint8_t *buf, int len)
{
int ret;
while (len > 0) {
ret = write(gdbstub_fd, buf, len);
if (ret < 0) {
if (errno != EINTR && errno != EAGAIN)
return;
} else {
buf += ret;
len -= ret;
}
}
}
static inline int fromhex(int v)
{
if (v >= '0' && v <= '9')
return v - '0';
else if (v >= 'A' && v <= 'F')
return v - 'A' + 10;
else if (v >= 'a' && v <= 'f')
return v - 'a' + 10;
else
return 0;
}
static inline int tohex(int v)
{
if (v < 10)
return v + '0';
else
return v - 10 + 'a';
}
static void memtohex(char *buf, const uint8_t *mem, int len)
{
int i, c;
char *q;
q = buf;
for(i = 0; i < len; i++) {
c = mem[i];
*q++ = tohex(c >> 4);
*q++ = tohex(c & 0xf);
}
*q = '\0';
}
static void hextomem(uint8_t *mem, const char *buf, int len)
{
int i;
for(i = 0; i < len; i++) {
mem[i] = (fromhex(buf[0]) << 4) | fromhex(buf[1]);
buf += 2;
}
}
/* return -1 if error or EOF */
static int get_packet(char *buf, int buf_size)
{
int ch, len, csum, csum1;
char reply[1];
for(;;) {
for(;;) {
ch = get_char();
if (ch < 0)
return -1;
if (ch == '$')
break;
}
len = 0;
csum = 0;
for(;;) {
ch = get_char();
if (ch < 0)
return -1;
if (ch == '#')
break;
if (len > buf_size - 1)
return -1;
buf[len++] = ch;
csum += ch;
}
buf[len] = '\0';
ch = get_char();
if (ch < 0)
return -1;
csum1 = fromhex(ch) << 4;
ch = get_char();
if (ch < 0)
return -1;
csum1 |= fromhex(ch);
if ((csum & 0xff) != csum1) {
reply[0] = '-';
put_buffer(reply, 1);
} else {
reply[0] = '+';
put_buffer(reply, 1);
break;
}
}
#ifdef DEBUG_GDB
printf("command='%s'\n", buf);
#endif
return len;
}
/* return -1 if error, 0 if OK */
static int put_packet(char *buf)
{
char buf1[3];
int len, csum, ch, i;
#ifdef DEBUG_GDB
printf("reply='%s'\n", buf);
#endif
for(;;) {
buf1[0] = '$';
put_buffer(buf1, 1);
len = strlen(buf);
put_buffer(buf, len);
csum = 0;
for(i = 0; i < len; i++) {
csum += buf[i];
}
buf1[0] = '#';
buf1[1] = tohex((csum >> 4) & 0xf);
buf1[2] = tohex((csum) & 0xf);
put_buffer(buf1, 3);
ch = get_char();
if (ch < 0)
return -1;
if (ch == '+')
break;
}
return 0;
}
/* better than nothing for SOFTMMU : we use physical addresses */
#ifdef CONFIG_SOFTMMU
static int memory_rw(uint8_t *buf, uint32_t addr, int len, int is_write)
{
uint8_t *ptr;
if (addr >= phys_ram_size ||
((int64_t)addr + len > phys_ram_size))
return -1;
ptr = phys_ram_base + addr;
if (is_write)
memcpy(ptr, buf, len);
else
memcpy(buf, ptr, len);
return 0;
}
#else
static int memory_rw(uint8_t *buf, uint32_t addr, int len, int is_write)
{
int l, flags;
uint32_t page;
while (len > 0) {
page = addr & TARGET_PAGE_MASK;
l = (page + TARGET_PAGE_SIZE) - addr;
if (l > len)
l = len;
flags = page_get_flags(page);
if (!(flags & PAGE_VALID))
return -1;
if (is_write) {
if (!(flags & PAGE_WRITE))
return -1;
memcpy((uint8_t *)addr, buf, l);
} else {
if (!(flags & PAGE_READ))
return -1;
memcpy(buf, (uint8_t *)addr, l);
}
len -= l;
buf += l;
addr += l;
}
return 0;
}
#endif
#if defined(TARGET_I386)
static void to_le32(uint8_t *p, int v)
{
p[0] = v;
p[1] = v >> 8;
p[2] = v >> 16;
p[3] = v >> 24;
}
static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf)
{
int i, fpus;
for(i = 0; i < 8; i++) {
to_le32(mem_buf + i * 4, env->regs[i]);
}
to_le32(mem_buf + 8 * 4, env->eip);
to_le32(mem_buf + 9 * 4, env->eflags);
to_le32(mem_buf + 10 * 4, env->segs[R_CS].selector);
to_le32(mem_buf + 11 * 4, env->segs[R_SS].selector);
to_le32(mem_buf + 12 * 4, env->segs[R_DS].selector);
to_le32(mem_buf + 13 * 4, env->segs[R_ES].selector);
to_le32(mem_buf + 14 * 4, env->segs[R_FS].selector);
to_le32(mem_buf + 15 * 4, env->segs[R_GS].selector);
/* XXX: convert floats */
for(i = 0; i < 8; i++) {
memcpy(mem_buf + 16 * 4 + i * 10, &env->fpregs[i], 10);
}
to_le32(mem_buf + 36 * 4, env->fpuc);
fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
to_le32(mem_buf + 37 * 4, fpus);
to_le32(mem_buf + 38 * 4, 0); /* XXX: convert tags */
to_le32(mem_buf + 39 * 4, 0); /* fiseg */
to_le32(mem_buf + 40 * 4, 0); /* fioff */
to_le32(mem_buf + 41 * 4, 0); /* foseg */
to_le32(mem_buf + 42 * 4, 0); /* fooff */
to_le32(mem_buf + 43 * 4, 0); /* fop */
return 44 * 4;
}
static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size)
{
uint32_t *registers = (uint32_t *)mem_buf;
int i;
for(i = 0; i < 8; i++) {
env->regs[i] = tswapl(registers[i]);
}
env->eip = registers[8];
env->eflags = registers[9];
#if defined(CONFIG_USER_ONLY)
#define LOAD_SEG(index, sreg)\
if (tswapl(registers[index]) != env->segs[sreg].selector)\
cpu_x86_load_seg(env, sreg, tswapl(registers[index]));
LOAD_SEG(10, R_CS);
LOAD_SEG(11, R_SS);
LOAD_SEG(12, R_DS);
LOAD_SEG(13, R_ES);
LOAD_SEG(14, R_FS);
LOAD_SEG(15, R_GS);
#endif
}
#else
static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf)
{
return 0;
}
static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size)
{
}
#endif
/* port = 0 means default port */
int cpu_gdbstub(void *opaque, int (*main_loop)(void *opaque), int port)
{
CPUState *env;
const char *p;
int ret, ch, reg_size, type;
char buf[4096];
uint8_t mem_buf[2000];
uint32_t *registers;
uint32_t addr, len;
printf("Waiting gdb connection on port %d\n", port);
if (gdbstub_open(port) < 0)
return -1;
printf("Connected\n");
for(;;) {
ret = get_packet(buf, sizeof(buf));
if (ret < 0)
break;
p = buf;
ch = *p++;
switch(ch) {
case '?':
snprintf(buf, sizeof(buf), "S%02x", SIGTRAP);
put_packet(buf);
break;
case 'c':
if (*p != '\0') {
addr = strtoul(p, (char **)&p, 16);
env = cpu_gdbstub_get_env(opaque);
#if defined(TARGET_I386)
env->eip = addr;
#endif
}
ret = main_loop(opaque);
if (ret == EXCP_DEBUG)
ret = SIGTRAP;
else
ret = 0;
snprintf(buf, sizeof(buf), "S%02x", ret);
put_packet(buf);
break;
case 's':
env = cpu_gdbstub_get_env(opaque);
if (*p != '\0') {
addr = strtoul(p, (char **)&p, 16);
#if defined(TARGET_I386)
env->eip = addr;
#endif
}
cpu_single_step(env, 1);
ret = main_loop(opaque);
cpu_single_step(env, 0);
if (ret == EXCP_DEBUG)
ret = SIGTRAP;
else
ret = 0;
snprintf(buf, sizeof(buf), "S%02x", ret);
put_packet(buf);
break;
case 'g':
env = cpu_gdbstub_get_env(opaque);
reg_size = cpu_gdb_read_registers(env, mem_buf);
memtohex(buf, mem_buf, reg_size);
put_packet(buf);
break;
case 'G':
env = cpu_gdbstub_get_env(opaque);
registers = (void *)mem_buf;
len = strlen(p) / 2;
hextomem((uint8_t *)registers, p, len);
cpu_gdb_write_registers(env, mem_buf, len);
put_packet("OK");
break;
case 'm':
addr = strtoul(p, (char **)&p, 16);
if (*p == ',')
p++;
len = strtoul(p, NULL, 16);
if (memory_rw(mem_buf, addr, len, 0) != 0)
memset(mem_buf, 0, len);
memtohex(buf, mem_buf, len);
put_packet(buf);
break;
case 'M':
addr = strtoul(p, (char **)&p, 16);
if (*p == ',')
p++;
len = strtoul(p, (char **)&p, 16);
if (*p == ',')
p++;
hextomem(mem_buf, p, len);
if (memory_rw(mem_buf, addr, len, 1) != 0)
put_packet("ENN");
else
put_packet("OK");
break;
case 'Z':
type = strtoul(p, (char **)&p, 16);
if (*p == ',')
p++;
addr = strtoul(p, (char **)&p, 16);
if (*p == ',')
p++;
len = strtoul(p, (char **)&p, 16);
if (type == 0 || type == 1) {
env = cpu_gdbstub_get_env(opaque);
if (cpu_breakpoint_insert(env, addr) < 0)
goto breakpoint_error;
put_packet("OK");
} else {
breakpoint_error:
put_packet("ENN");
}
break;
case 'z':
type = strtoul(p, (char **)&p, 16);
if (*p == ',')
p++;
addr = strtoul(p, (char **)&p, 16);
if (*p == ',')
p++;
len = strtoul(p, (char **)&p, 16);
if (type == 0 || type == 1) {
env = cpu_gdbstub_get_env(opaque);
cpu_breakpoint_remove(env, addr);
put_packet("OK");
} else {
goto breakpoint_error;
}
break;
case 'Q':
if (!strncmp(p, "Tinit", 5)) {
/* init traces */
put_packet("OK");
} else if (!strncmp(p, "TStart", 6)) {
/* start log (gdb 'tstart' command) */
env = cpu_gdbstub_get_env(opaque);
tb_flush(env);
cpu_set_log(CPU_LOG_ALL);
put_packet("OK");
} else if (!strncmp(p, "TStop", 5)) {
/* stop log (gdb 'tstop' command) */
cpu_set_log(0);
put_packet("OK");
} else {
goto unknown_command;
}
break;
default:
unknown_command:
/* put empty packet */
buf[0] = '\0';
put_packet(buf);
break;
}
}
return 0;
}

File diff suppressed because it is too large Load Diff

395
hw/dma.c Normal file
View File

@@ -0,0 +1,395 @@
/*
* QEMU DMA emulation
*
* Copyright (c) 2003 Vassili Karpov (malc)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
#include "vl.h"
#include "cpu.h"
#define log(...) fprintf (stderr, "dma: " __VA_ARGS__)
#ifdef DEBUG_DMA
#define lwarn(...) fprintf (stderr, "dma: " __VA_ARGS__)
#define linfo(...) fprintf (stderr, "dma: " __VA_ARGS__)
#define ldebug(...) fprintf (stderr, "dma: " __VA_ARGS__)
#else
#define lwarn(...)
#define linfo(...)
#define ldebug(...)
#endif
#define MEM_REAL(addr) ((addr)+(uint32_t)(phys_ram_base))
#define LENOFA(a) ((int) (sizeof(a)/sizeof(a[0])))
struct dma_regs {
int now[2];
uint16_t base[2];
uint8_t mode;
uint8_t page;
uint8_t dack;
uint8_t eop;
DMA_read_handler read_handler;
DMA_misc_handler misc_handler;
};
#define ADDR 0
#define COUNT 1
static struct dma_cont {
uint8_t status;
uint8_t command;
uint8_t mask;
uint8_t flip_flop;
struct dma_regs regs[4];
} dma_controllers[2];
enum {
CMD_MEMORY_TO_MEMORY = 0x01,
CMD_FIXED_ADDRESS = 0x02,
CMD_BLOCK_CONTROLLER = 0x04,
CMD_COMPRESSED_TIME = 0x08,
CMD_CYCLIC_PRIORITY = 0x10,
CMD_EXTENDED_WRITE = 0x20,
CMD_LOW_DREQ = 0x40,
CMD_LOW_DACK = 0x80,
CMD_NOT_SUPPORTED = CMD_MEMORY_TO_MEMORY | CMD_FIXED_ADDRESS
| CMD_COMPRESSED_TIME | CMD_CYCLIC_PRIORITY | CMD_EXTENDED_WRITE
| CMD_LOW_DREQ | CMD_LOW_DACK
};
static void write_page (struct CPUX86State *env, uint32_t nport, uint32_t data)
{
int ichan;
int ncont;
static int channels[8] = {-1, 2, 3, 1, -1, -1, -1, 0};
ncont = nport > 0x87;
ichan = channels[nport - 0x80 - (ncont << 3)];
if (-1 == ichan) {
log ("invalid channel %#x %#x\n", nport, data);
return;
}
dma_controllers[ncont].regs[ichan].page = data;
}
static void init_chan (int ncont, int ichan)
{
struct dma_regs *r;
r = dma_controllers[ncont].regs + ichan;
r->now[ADDR] = r->base[0] << ncont;
r->now[COUNT] = 0;
}
static inline int getff (int ncont)
{
int ff;
ff = dma_controllers[ncont].flip_flop;
dma_controllers[ncont].flip_flop = !ff;
return ff;
}
static uint32_t read_chan (struct CPUX86State *env, uint32_t nport)
{
int ff;
int ncont, ichan, nreg;
struct dma_regs *r;
int val;
ncont = nport > 7;
ichan = (nport >> (1 + ncont)) & 3;
nreg = (nport >> ncont) & 1;
r = dma_controllers[ncont].regs + ichan;
ff = getff (ncont);
if (nreg)
val = (r->base[COUNT] << ncont) - r->now[COUNT];
else
val = r->now[ADDR] + r->now[COUNT];
return (val >> (ncont + (ff << 3))) & 0xff;
}
static void write_chan (uint32_t nport, int size, uint32_t data)
{
int ncont, ichan, nreg;
struct dma_regs *r;
ncont = nport > 7;
ichan = (nport >> (1 + ncont)) & 3;
nreg = (nport >> ncont) & 1;
r = dma_controllers[ncont].regs + ichan;
if (2 == size) {
r->base[nreg] = data;
init_chan (ncont, ichan);
}
else {
if (getff (ncont)) {
r->base[nreg] = (r->base[nreg] & 0xff) | ((data << 8) & 0xff00);
init_chan (ncont, ichan);
}
else {
r->base[nreg] = (r->base[nreg] & 0xff00) | (data & 0xff);
}
}
}
static void write_chanb (struct CPUX86State *env, uint32_t nport, uint32_t data)
{
write_chan (nport, 1, data);
}
static void write_chanw (struct CPUX86State *env, uint32_t nport, uint32_t data)
{
write_chan (nport, 2, data);
}
static void write_cont (struct CPUX86State *env, uint32_t nport, uint32_t data)
{
int iport, ichan, ncont;
struct dma_cont *d;
ncont = nport > 0xf;
ichan = -1;
d = dma_controllers + ncont;
if (ncont) {
iport = ((nport - 0xd0) >> 1) + 8;
}
else {
iport = nport;
}
switch (iport) {
case 8: /* command */
if (data && (data | CMD_NOT_SUPPORTED)) {
log ("command %#x not supported\n", data);
goto error;
}
d->command = data;
break;
case 9:
ichan = data & 3;
if (data & 4) {
d->status |= 1 << (ichan + 4);
}
else {
d->status &= ~(1 << (ichan + 4));
}
d->status &= ~(1 << ichan);
break;
case 0xa: /* single mask */
if (data & 4)
d->mask |= 1 << (data & 3);
else
d->mask &= ~(1 << (data & 3));
break;
case 0xb: /* mode */
{
#ifdef DMA_DEBUG
int op;
int ai;
int dir;
int opmode;
ichan = val & 3;
op = (val >> 2) & 3;
ai = (val >> 4) & 1;
dir = (val >> 5) & 1;
opmode = (val >> 6) & 3;
linfo ("ichan %d, op %d, ai %d, dir %d, opmode %d\n",
ichan, op, ai, dir, opmode);
#endif
d->regs[ichan].mode = data;
break;
}
case 0xc: /* clear flip flop */
d->flip_flop = 0;
break;
case 0xd: /* reset */
d->flip_flop = 0;
d->mask = ~0;
d->status = 0;
d->command = 0;
break;
case 0xe: /* clear mask for all channels */
d->mask = 0;
break;
case 0xf: /* write mask for all channels */
d->mask = data;
break;
default:
log ("dma: unknown iport %#x\n", iport);
goto error;
}
#ifdef DMA_DEBUG
if (0xc != iport) {
linfo ("nport %#06x, ncont %d, ichan % 2d, val %#06x\n",
nport, d != dma_controllers, ichan, data);
}
#endif
return;
error:
abort ();
}
int DMA_get_channel_mode (int nchan)
{
return dma_controllers[nchan > 3].regs[nchan & 3].mode;
}
void DMA_hold_DREQ (int nchan)
{
int ncont, ichan;
ncont = nchan > 3;
ichan = nchan & 3;
linfo ("held cont=%d chan=%d\n", ncont, ichan);
dma_controllers[ncont].status |= 1 << (ichan + 4);
}
void DMA_release_DREQ (int nchan)
{
int ncont, ichan;
ncont = nchan > 3;
ichan = nchan & 3;
linfo ("released cont=%d chan=%d\n", ncont, ichan);
dma_controllers[ncont].status &= ~(1 << (ichan + 4));
}
static void channel_run (int ncont, int ichan)
{
struct dma_regs *r;
int n;
int irq;
uint32_t addr;
/* int ai, dir; */
r = dma_controllers[ncont].regs + ichan;
/* ai = r->mode & 16; */
/* dir = r->mode & 32 ? -1 : 1; */
addr = MEM_REAL ((r->page << 16) | r->now[ADDR]);
irq = -1;
n = r->read_handler (addr, (r->base[COUNT] << ncont) + (1 << ncont), &irq);
r->now[COUNT] = n;
ldebug ("dma_pos %d irq %d size %d\n",
n, irq, (r->base[1] << ncont) + (1 << ncont));
if (-1 != irq) {
pic_set_irq (irq, 1);
}
}
void DMA_run (void)
{
static int in_dma;
struct dma_cont *d;
int icont, ichan;
if (in_dma) {
log ("attempt to re-enter dma\n");
return;
}
in_dma = 1;
d = dma_controllers;
for (icont = 0; icont < 2; icont++, d++) {
for (ichan = 0; ichan < 4; ichan++) {
int mask;
mask = 1 << ichan;
if ((0 == (d->mask & mask)) && (0 != (d->status & (mask << 4))))
channel_run (icont, ichan);
}
}
in_dma = 0;
}
void DMA_register_channel (int nchan,
DMA_read_handler read_handler,
DMA_misc_handler misc_handler)
{
struct dma_regs *r;
int ichan, ncont;
ncont = nchan > 3;
ichan = nchan & 3;
r = dma_controllers[ncont].regs + ichan;
r->read_handler = read_handler;
r->misc_handler = misc_handler;
}
void DMA_init (void)
{
int i;
int page_port_list[] = { 0x1, 0x2, 0x3, 0x7 };
for (i = 0; i < 8; i++) {
register_ioport_write (i, 1, write_chanb, 1);
register_ioport_write (i, 1, write_chanw, 2);
register_ioport_write (0xc0 + (i << 1), 1, write_chanb, 1);
register_ioport_write (0xc0 + (i << 1), 1, write_chanw, 2);
register_ioport_read (i, 1, read_chan, 1);
register_ioport_read (0xc0 + (i << 1), 1, read_chan, 2);
}
for (i = 0; i < LENOFA (page_port_list); i++) {
register_ioport_write (page_port_list[i] + 0x80, 1, write_page, 1);
register_ioport_write (page_port_list[i] + 0x88, 1, write_page, 1);
}
for (i = 0; i < 8; i++) {
register_ioport_write (i + 8, 1, write_cont, 1);
register_ioport_write (0xd0 + (i << 1), 1, write_cont, 1);
}
write_cont (NULL, 0xd, 0);
write_cont (NULL, 0xdd, 0);
}

1453
hw/ide.c Normal file

File diff suppressed because it is too large Load Diff

723
hw/sb16.c Normal file
View File

@@ -0,0 +1,723 @@
/*
* QEMU Soundblaster 16 emulation
*
* Copyright (c) 2003 Vassili Karpov (malc)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
#include "vl.h"
#define MIN(a, b) ((a)>(b)?(b):(a))
#define LENOFA(a) ((int) (sizeof(a)/sizeof(a[0])))
#define DEREF(x) (void)x
#define log(...) fprintf (stderr, "sb16: " __VA_ARGS__)
#define Fail(...) do { \
fprintf (stderr, "sb16: " __VA_ARGS__); \
abort (); \
} while (0)
#ifdef DEBUG_SB16
#define lwarn(...) fprintf (stderr, "sb16: " __VA_ARGS__)
#define linfo(...) fprintf (stderr, "sb16: " __VA_ARGS__)
#define ldebug(...) fprintf (stderr, "sb16: " __VA_ARGS__)
#else
#define lwarn(...)
#define linfo(...)
#define ldebug(...)
#endif
#define IO_READ_PROTO(name) \
uint32_t name (struct CPUX86State *env, uint32_t nport)
#define IO_WRITE_PROTO(name) \
void name (struct CPUX86State *env, uint32_t nport, uint32_t val)
static struct {
int ver_lo;
int ver_hi;
int irq;
int dma;
int hdma;
int port;
int mix_block;
} sb = {4, 5, 5, 1, 5, 0x220, -1};
static int mix_block, noirq;
static struct mixer {
int nreg;
uint8_t regs[0x83];
} mixer;
static struct dsp {
int in_index;
int out_data_len;
int fmt_stereo;
int fmt_signed;
int fmt_bits;
int dma_auto;
int dma_buffer_size;
int fifo;
int freq;
int time_const;
int speaker;
int needed_bytes;
int cmd;
int dma_pos;
int use_hdma;
int v2x6;
uint8_t in_data[10];
uint8_t out_data[10];
int left_till_irq;
} dsp;
#define nocmd ~0
static void log_dsp (const char *cap)
{
DEREF (cap);
linfo ("%c:%c:%d:%c:dmabuf=%d:pos=%d:freq=%d:timeconst=%d:speaker=%d\n",
dsp.fmt_stereo ? 'S' : 'M',
dsp.fmt_signed ? 'S' : 'U',
dsp.fmt_bits,
dsp.dma_auto ? 'a' : 's',
dsp.dma_buffer_size,
dsp.dma_pos,
dsp.freq,
dsp.time_const,
dsp.speaker);
}
static void control (int hold)
{
linfo ("%d high %d\n", hold, dsp.use_hdma);
if (hold) {
if (dsp.use_hdma)
DMA_hold_DREQ (sb.hdma);
else
DMA_hold_DREQ (sb.dma);
}
else {
if (dsp.use_hdma)
DMA_release_DREQ (sb.hdma);
else
DMA_release_DREQ (sb.dma);
}
}
static void dma_cmd (uint8_t cmd, uint8_t d0, int dma_len)
{
int bps;
audfmt_e fmt;
dsp.use_hdma = cmd < 0xc0;
dsp.fifo = (cmd >> 1) & 1;
dsp.dma_auto = (cmd >> 2) & 1;
switch (cmd >> 4) {
case 11:
dsp.fmt_bits = 16;
break;
case 12:
dsp.fmt_bits = 8;
break;
}
dsp.fmt_signed = (d0 >> 4) & 1;
dsp.fmt_stereo = (d0 >> 5) & 1;
if (-1 != dsp.time_const) {
int tmp;
tmp = 256 - dsp.time_const;
dsp.freq = (1000000 + (tmp / 2)) / tmp;
}
bps = 1 << (16 == dsp.fmt_bits);
if (-1 != dma_len)
dsp.dma_buffer_size = (dma_len + 1) * bps;
linfo ("frequency %d, stereo %d, signed %d, bits %d, size %d, auto %d\n",
dsp.freq, dsp.fmt_stereo, dsp.fmt_signed, dsp.fmt_bits,
dsp.dma_buffer_size, dsp.dma_auto);
if (16 == dsp.fmt_bits) {
if (dsp.fmt_signed) {
fmt = AUD_FMT_S16;
}
else {
fmt = AUD_FMT_U16;
}
}
else {
if (dsp.fmt_signed) {
fmt = AUD_FMT_S8;
}
else {
fmt = AUD_FMT_U8;
}
}
dsp.dma_pos = 0;
dsp.left_till_irq = dsp.dma_buffer_size;
if (sb.mix_block) {
mix_block = sb.mix_block;
}
else {
int align;
align = bps << dsp.fmt_stereo;
mix_block = ((dsp.freq * align) / 100) & ~(align - 1);
}
AUD_reset (dsp.freq, 1 << dsp.fmt_stereo, fmt);
control (1);
dsp.speaker = 1;
}
static void command (uint8_t cmd)
{
char *msg;
msg = (char *)-1;
linfo ("%#x\n", cmd);
if (cmd > 0xaf && cmd < 0xd0) {
if (cmd & 8)
goto error;
switch (cmd >> 4) {
case 11:
case 12:
break;
default:
msg = "wrong bits";
goto error;
}
dsp.needed_bytes = 3;
}
else {
switch (cmd) {
case 0x10:
dsp.needed_bytes = 1;
break;
case 0x14:
dsp.needed_bytes = 2;
dsp.dma_buffer_size = 0;
break;
case 0x20:
dsp.out_data[dsp.out_data_len++] = 0xff;
break;
case 0x35:
lwarn ("MIDI commands not implemented\n");
break;
case 0x40:
dsp.freq = -1;
dsp.time_const = -1;
dsp.needed_bytes = 1;
break;
case 0x41:
case 0x42:
dsp.freq = -1;
dsp.time_const = -1;
dsp.needed_bytes = 2;
break;
case 0x47: /* Continue Auto-Initialize DMA 16bit */
break;
case 0x48:
dsp.needed_bytes = 2;
break;
case 0x27: /* ????????? */
case 0x4e:
return;
case 0x80:
cmd = nocmd;
break;
case 0x90:
case 0x91:
{
uint8_t d0;
d0 = 4;
if (dsp.fmt_signed) d0 |= 16;
if (dsp.fmt_stereo) d0 |= 32;
dma_cmd (cmd == 0x90 ? 0xc4 : 0xc0, d0, -1);
cmd = nocmd;
break;
}
case 0xd0: /* XXX */
control (0);
return;
case 0xd1:
dsp.speaker = 1;
break;
case 0xd3:
dsp.speaker = 0;
return;
case 0xd4:
control (1);
break;
case 0xd5:
control (0);
break;
case 0xd6:
control (1);
break;
case 0xd9:
control (0);
dsp.dma_auto = 0;
return;
case 0xda:
control (0);
dsp.dma_auto = 0;
break;
case 0xe0:
dsp.needed_bytes = 1;
break;
case 0xe1:
dsp.out_data[dsp.out_data_len++] = sb.ver_lo;
dsp.out_data[dsp.out_data_len++] = sb.ver_hi;
return;
case 0xf2:
dsp.out_data[dsp.out_data_len++] = 0xaa;
mixer.regs[0x82] |= 1;
pic_set_irq (sb.irq, 1);
return;
default:
msg = "is unknown";
goto error;
}
}
dsp.cmd = cmd;
return;
error:
Fail ("%#x %s", cmd, msg);
return;
}
static void complete (void)
{
linfo ("complete command %#x, in_index %d, needed_bytes %d\n",
dsp.cmd, dsp.in_index, dsp.needed_bytes);
if (dsp.cmd > 0xaf && dsp.cmd < 0xd0) {
int d0, d1, d2;
d0 = dsp.in_data[0];
d1 = dsp.in_data[1];
d2 = dsp.in_data[2];
ldebug ("d0 = %d, d1 = %d, d2 = %d\n",
d0, d1, d2);
dma_cmd (dsp.cmd, d0, d1 + (d2 << 8));
}
else {
switch (dsp.cmd) {
case 0x10:
break;
case 0x14:
{
int d0, d1;
int save_left;
int save_pos;
d0 = dsp.in_data[0];
d1 = dsp.in_data[1];
save_left = dsp.left_till_irq;
save_pos = dsp.dma_pos;
dma_cmd (0xc0, 0, d0 + (d1 << 8));
dsp.left_till_irq = save_left;
dsp.dma_pos = save_pos;
linfo ("set buffer size data[%d, %d] %d pos %d\n",
d0, d1, dsp.dma_buffer_size, dsp.dma_pos);
break;
}
case 0x40:
dsp.time_const = dsp.in_data[0];
linfo ("set time const %d\n", dsp.time_const);
break;
case 0x41:
case 0x42:
dsp.freq = dsp.in_data[1] + (dsp.in_data[0] << 8);
linfo ("set freq %#x, %#x = %d\n",
dsp.in_data[1], dsp.in_data[0], dsp.freq);
break;
case 0x48:
dsp.dma_buffer_size = dsp.in_data[1] + (dsp.in_data[0] << 8);
linfo ("set dma len %#x, %#x = %d\n",
dsp.in_data[1], dsp.in_data[0], dsp.dma_buffer_size);
break;
case 0xe0:
dsp.out_data_len = 1;
linfo ("data = %#x\n", dsp.in_data[0]);
dsp.out_data[0] = dsp.in_data[0] ^ 0xff;
break;
default:
goto error;
}
}
dsp.cmd = -1;
return;
error:
Fail ("unrecognized command %#x", dsp.cmd);
}
static IO_WRITE_PROTO (dsp_write)
{
int iport;
iport = nport - sb.port;
switch (iport) {
case 0x6:
if (0 == val)
dsp.v2x6 = 0;
else if ((1 == val) && (0 == dsp.v2x6)) {
dsp.v2x6 = 1;
dsp.out_data[dsp.out_data_len++] = 0xaa;
}
else
dsp.v2x6 = ~0;
break;
case 0xc: /* write data or command | write status */
if (0 == dsp.needed_bytes) {
command (val);
if (0 == dsp.needed_bytes) {
log_dsp (__func__);
}
}
else {
dsp.in_data[dsp.in_index++] = val;
if (dsp.in_index == dsp.needed_bytes) {
dsp.needed_bytes = 0;
dsp.in_index = 0;
complete ();
log_dsp (__func__);
}
}
break;
default:
Fail ("(nport=%#x, val=%#x)", nport, val);
}
}
static IO_READ_PROTO (dsp_read)
{
char *msg;
int iport, retval;
msg = (char *) -1;
iport = nport - sb.port;
switch (iport) {
case 0x6: /* reset */
return 0;
case 0xa: /* read data */
if (dsp.out_data_len) {
retval = dsp.out_data[--dsp.out_data_len];
}
else {
#if 1
lwarn ("empty output buffer\n");
retval = 0;
#else
msg = "empty output buffer";
goto error;
#endif
}
break;
case 0xc: /* 0 can write */
retval = 0;
break;
case 0xd: /* timer interrupt clear */
goto error;
case 0xe: /* data available status | irq 8 ack */
retval = (0 == dsp.out_data_len) ? 0 : 0x80;
break;
case 0xf: /* irq 16 ack */
retval = 0xff;
mixer.regs[0x82] &= ~2;
ldebug ("16 ack\n");
break;
default:
goto error;
}
if ((0xc != iport) && (0xe != iport)) {
ldebug ("(nport=%#x, size=%d) iport %#x = %#x\n",
nport, size, iport, retval);
}
return retval;
error:
Fail ("(nport=%#x) %s", nport, msg);
}
static IO_WRITE_PROTO(mixer_write_indexb)
{
mixer.nreg = val & 0xff;
}
static IO_WRITE_PROTO(mixer_write_datab)
{
mixer.regs[mixer.nreg] = val;
}
static IO_WRITE_PROTO(mixer_write_indexw)
{
mixer_write_indexb (env, nport, val & 0xff);
mixer_write_datab (env, nport, (val >> 8) & 0xff);
}
static IO_READ_PROTO(mixer_read)
{
return mixer.regs[mixer.nreg];
}
void SB16_run (void)
{
if (0 == dsp.speaker)
return;
AUD_run ();
}
static int write_audio (uint32_t addr, int len, int size)
{
int temp, net;
temp = size;
net = 0;
while (temp) {
int left_till_end;
int to_copy;
int copied;
left_till_end = len - dsp.dma_pos;
to_copy = MIN (temp, left_till_end);
copied = AUD_write ((void *) (addr + dsp.dma_pos), to_copy);
temp -= copied;
dsp.dma_pos += copied;
if (dsp.dma_pos == len) {
dsp.dma_pos = 0;
}
net += copied;
if (copied != to_copy)
return net;
}
return net;
}
static int SB_read_DMA (uint32_t addr, int size, int *_irq)
{
int free, till, copy, written;
if (0 == dsp.speaker)
return 0;
if (dsp.left_till_irq < 0) {
dsp.left_till_irq += dsp.dma_buffer_size;
return dsp.dma_pos;
}
free = AUD_get_free ();
if ((free <= 0) || (0 == size)) {
return dsp.dma_pos;
}
if (mix_block > 0) {
copy = MIN (free, mix_block);
}
else {
copy = free;
}
till = dsp.left_till_irq;
ldebug ("addr:%#010x free:%d till:%d size:%d\n",
addr, free, till, size);
/* linfo ("pos %d free %d size %d till %d copy %d auto %d noirq %d\n", */
/* dsp.dma_pos, free, size, till, copy, dsp.dma_auto, noirq); */
if (till <= copy) {
if (0 == dsp.dma_auto) {
copy = till;
}
}
written = write_audio (addr, size, copy);
dsp.left_till_irq -= written;
AUD_adjust_estimate (free - written);
if (dsp.left_till_irq <= 0) {
mixer.regs[0x82] |= mixer.regs[0x80];
if (0 == noirq)
*_irq = sb.irq;
if (0 == dsp.dma_auto) {
control (0);
}
}
ldebug ("pos %5d free %5d size %5d till % 5d copy %5d dma size %5d\n",
dsp.dma_pos, free, size, dsp.left_till_irq, copy,
dsp.dma_buffer_size);
if (dsp.left_till_irq <= 0) {
dsp.left_till_irq += dsp.dma_buffer_size;
}
return dsp.dma_pos;
}
static int dma_misc_handler (int moo)
{
return -1;
}
static int magic_of_irq (int irq)
{
switch (irq) {
case 2:
return 1;
case 5:
return 2;
case 7:
return 4;
case 10:
return 8;
default:
log ("bad irq %d\n", irq);
return 2;
}
}
static int irq_of_magic (int magic)
{
switch (magic) {
case 1:
return 2;
case 2:
return 5;
case 4:
return 7;
case 8:
return 10;
default:
log ("bad irq magic %d\n", magic);
return 2;
}
}
void SB16_init (void)
{
int i;
static const uint8_t dsp_write_ports[] = {0x6, 0xc};
static const uint8_t dsp_read_ports[] = {0x6, 0xa, 0xc, 0xd, 0xe, 0xf};
mixer.regs[0x0e] = ~0;
mixer.regs[0x80] = magic_of_irq (sb.irq);
mixer.regs[0x81] = 0x20 | (sb.dma << 1);
DEREF (irq_of_magic);
for (i = 0x30; i < 0x48; i++) {
mixer.regs[i] = 0x20;
}
for (i = 0; i < LENOFA (dsp_write_ports); i++) {
register_ioport_write (sb.port + dsp_write_ports[i], 1, dsp_write, 1);
}
for (i = 0; i < LENOFA (dsp_read_ports); i++) {
register_ioport_read (sb.port + dsp_read_ports[i], 1, dsp_read, 1);
}
register_ioport_write (sb.port + 0x4, 1, mixer_write_indexb, 1);
register_ioport_write (sb.port + 0x4, 1, mixer_write_indexw, 2);
register_ioport_read (sb.port + 0x5, 1, mixer_read, 1);
register_ioport_write (sb.port + 0x5, 1, mixer_write_datab, 1);
DMA_register_channel (sb.hdma, SB_read_DMA, dma_misc_handler);
DMA_register_channel (sb.dma, SB_read_DMA, dma_misc_handler);
}

1422
hw/vga.c Normal file

File diff suppressed because it is too large Load Diff

420
hw/vga_template.h Normal file
View File

@@ -0,0 +1,420 @@
/*
* QEMU VGA Emulator templates
*
* Copyright (c) 2003 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#if DEPTH == 8
#define BPP 1
#define PIXEL_TYPE uint8_t
#elif DEPTH == 15 || DEPTH == 16
#define BPP 2
#define PIXEL_TYPE uint16_t
#elif DEPTH == 32
#define BPP 4
#define PIXEL_TYPE uint32_t
#else
#error unsupport depth
#endif
#if DEPTH != 15
static inline void glue(vga_draw_glyph_line_, DEPTH)(uint8_t *d,
uint32_t font_data,
uint32_t xorcol,
uint32_t bgcol)
{
#if BPP == 1
((uint32_t *)d)[0] = (dmask16[(font_data >> 4)] & xorcol) ^ bgcol;
((uint32_t *)d)[3] = (dmask16[(font_data >> 0) & 0xf] & xorcol) ^ bgcol;
#elif BPP == 2
((uint32_t *)d)[0] = (dmask4[(font_data >> 6)] & xorcol) ^ bgcol;
((uint32_t *)d)[1] = (dmask4[(font_data >> 4) & 3] & xorcol) ^ bgcol;
((uint32_t *)d)[2] = (dmask4[(font_data >> 2) & 3] & xorcol) ^ bgcol;
((uint32_t *)d)[3] = (dmask4[(font_data >> 0) & 3] & xorcol) ^ bgcol;
#else
((uint32_t *)d)[0] = (-((font_data >> 7)) & xorcol) ^ bgcol;
((uint32_t *)d)[1] = (-((font_data >> 6) & 1) & xorcol) ^ bgcol;
((uint32_t *)d)[2] = (-((font_data >> 5) & 1) & xorcol) ^ bgcol;
((uint32_t *)d)[3] = (-((font_data >> 4) & 1) & xorcol) ^ bgcol;
((uint32_t *)d)[4] = (-((font_data >> 3) & 1) & xorcol) ^ bgcol;
((uint32_t *)d)[5] = (-((font_data >> 2) & 1) & xorcol) ^ bgcol;
((uint32_t *)d)[6] = (-((font_data >> 1) & 1) & xorcol) ^ bgcol;
((uint32_t *)d)[7] = (-((font_data >> 0) & 1) & xorcol) ^ bgcol;
#endif
}
static void glue(vga_draw_glyph8_, DEPTH)(uint8_t *d, int linesize,
const uint8_t *font_ptr, int h,
uint32_t fgcol, uint32_t bgcol)
{
uint32_t font_data, xorcol;
xorcol = bgcol ^ fgcol;
do {
font_data = font_ptr[0];
glue(vga_draw_glyph_line_, DEPTH)(d, font_data, xorcol, bgcol);
font_ptr += 4;
d += linesize;
} while (--h);
}
static void glue(vga_draw_glyph16_, DEPTH)(uint8_t *d, int linesize,
const uint8_t *font_ptr, int h,
uint32_t fgcol, uint32_t bgcol)
{
uint32_t font_data, xorcol;
xorcol = bgcol ^ fgcol;
do {
font_data = font_ptr[0];
glue(vga_draw_glyph_line_, DEPTH)(d,
expand4to8[font_data >> 4],
xorcol, bgcol);
glue(vga_draw_glyph_line_, DEPTH)(d + 8 * BPP,
expand4to8[font_data & 0x0f],
xorcol, bgcol);
font_ptr += 4;
d += linesize;
} while (--h);
}
static void glue(vga_draw_glyph9_, DEPTH)(uint8_t *d, int linesize,
const uint8_t *font_ptr, int h,
uint32_t fgcol, uint32_t bgcol, int dup9)
{
uint32_t font_data, xorcol, v;
xorcol = bgcol ^ fgcol;
do {
font_data = font_ptr[0];
/* XXX: unaligned accesses are done */
#if BPP == 1
((uint32_t *)d)[0] = (dmask16[(font_data >> 4)] & xorcol) ^ bgcol;
v = (dmask16[(font_data >> 0) & 0xf] & xorcol) ^ bgcol;
((uint32_t *)d)[3] = v;
if (dup9)
((uint8_t *)d)[8] = v >> (24 * (1 - BIG));
else
((uint8_t *)d)[8] = bgcol;
#elif BPP == 2
((uint32_t *)d)[0] = (dmask4[(font_data >> 6)] & xorcol) ^ bgcol;
((uint32_t *)d)[1] = (dmask4[(font_data >> 4) & 3] & xorcol) ^ bgcol;
((uint32_t *)d)[2] = (dmask4[(font_data >> 2) & 3] & xorcol) ^ bgcol;
v = (dmask4[(font_data >> 0) & 3] & xorcol) ^ bgcol;
((uint32_t *)d)[3] = v;
if (dup9)
((uint16_t *)d)[8] = v >> (16 * (1 - BIG));
else
((uint16_t *)d)[8] = bgcol;
#else
((uint32_t *)d)[0] = ((-(font_data >> 7)) & xorcol) ^ bgcol;
((uint32_t *)d)[1] = ((-(font_data >> 6) & 1) & xorcol) ^ bgcol;
((uint32_t *)d)[2] = ((-(font_data >> 5) & 1) & xorcol) ^ bgcol;
((uint32_t *)d)[3] = ((-(font_data >> 4) & 1) & xorcol) ^ bgcol;
((uint32_t *)d)[4] = ((-(font_data >> 3) & 1) & xorcol) ^ bgcol;
((uint32_t *)d)[5] = ((-(font_data >> 2) & 1) & xorcol) ^ bgcol;
((uint32_t *)d)[6] = ((-(font_data >> 1) & 1) & xorcol) ^ bgcol;
v = ((-(font_data >> 0) & 1) & xorcol) ^ bgcol;
((uint32_t *)d)[7] = v;
if (dup9)
((uint32_t *)d)[8] = v;
else
((uint32_t *)d)[8] = bgcol;
#endif
font_ptr += 4;
d += linesize;
} while (--h);
}
/*
* 4 color mode
*/
static void glue(vga_draw_line2_, DEPTH)(VGAState *s1, uint8_t *d,
const uint8_t *s, int width)
{
uint32_t plane_mask, *palette, data, v;
int x;
palette = s1->last_palette;
plane_mask = mask16[s1->ar[0x12] & 0xf];
width >>= 3;
for(x = 0; x < width; x++) {
data = ((uint32_t *)s)[0];
data &= plane_mask;
v = expand2[GET_PLANE(data, 0)];
v |= expand2[GET_PLANE(data, 2)] << 2;
((PIXEL_TYPE *)d)[0] = palette[v >> 12];
((PIXEL_TYPE *)d)[1] = palette[(v >> 8) & 0xf];
((PIXEL_TYPE *)d)[2] = palette[(v >> 4) & 0xf];
((PIXEL_TYPE *)d)[3] = palette[(v >> 0) & 0xf];
v = expand2[GET_PLANE(data, 1)];
v |= expand2[GET_PLANE(data, 3)] << 2;
((PIXEL_TYPE *)d)[4] = palette[v >> 12];
((PIXEL_TYPE *)d)[5] = palette[(v >> 8) & 0xf];
((PIXEL_TYPE *)d)[6] = palette[(v >> 4) & 0xf];
((PIXEL_TYPE *)d)[7] = palette[(v >> 0) & 0xf];
d += BPP * 8;
s += 4;
}
}
#if BPP == 1
#define PUT_PIXEL2(d, n, v) ((uint16_t *)d)[(n)] = (v)
#elif BPP == 2
#define PUT_PIXEL2(d, n, v) ((uint32_t *)d)[(n)] = (v)
#else
#define PUT_PIXEL2(d, n, v) \
((uint32_t *)d)[2*(n)] = ((uint32_t *)d)[2*(n)+1] = (v)
#endif
/*
* 4 color mode, dup2 horizontal
*/
static void glue(vga_draw_line2d2_, DEPTH)(VGAState *s1, uint8_t *d,
const uint8_t *s, int width)
{
uint32_t plane_mask, *palette, data, v;
int x;
palette = s1->last_palette;
plane_mask = mask16[s1->ar[0x12] & 0xf];
width >>= 3;
for(x = 0; x < width; x++) {
data = ((uint32_t *)s)[0];
data &= plane_mask;
v = expand2[GET_PLANE(data, 0)];
v |= expand2[GET_PLANE(data, 2)] << 2;
PUT_PIXEL2(d, 0, palette[v >> 12]);
PUT_PIXEL2(d, 1, palette[(v >> 8) & 0xf]);
PUT_PIXEL2(d, 2, palette[(v >> 4) & 0xf]);
PUT_PIXEL2(d, 3, palette[(v >> 0) & 0xf]);
v = expand2[GET_PLANE(data, 1)];
v |= expand2[GET_PLANE(data, 3)] << 2;
PUT_PIXEL2(d, 4, palette[v >> 12]);
PUT_PIXEL2(d, 5, palette[(v >> 8) & 0xf]);
PUT_PIXEL2(d, 6, palette[(v >> 4) & 0xf]);
PUT_PIXEL2(d, 7, palette[(v >> 0) & 0xf]);
d += BPP * 16;
s += 4;
}
}
/*
* 16 color mode
*/
static void glue(vga_draw_line4_, DEPTH)(VGAState *s1, uint8_t *d,
const uint8_t *s, int width)
{
uint32_t plane_mask, data, v, *palette;
int x;
palette = s1->last_palette;
plane_mask = mask16[s1->ar[0x12] & 0xf];
width >>= 3;
for(x = 0; x < width; x++) {
data = ((uint32_t *)s)[0];
data &= plane_mask;
v = expand4[GET_PLANE(data, 0)];
v |= expand4[GET_PLANE(data, 1)] << 1;
v |= expand4[GET_PLANE(data, 2)] << 2;
v |= expand4[GET_PLANE(data, 3)] << 3;
((PIXEL_TYPE *)d)[0] = palette[v >> 28];
((PIXEL_TYPE *)d)[1] = palette[(v >> 24) & 0xf];
((PIXEL_TYPE *)d)[2] = palette[(v >> 20) & 0xf];
((PIXEL_TYPE *)d)[3] = palette[(v >> 16) & 0xf];
((PIXEL_TYPE *)d)[4] = palette[(v >> 12) & 0xf];
((PIXEL_TYPE *)d)[5] = palette[(v >> 8) & 0xf];
((PIXEL_TYPE *)d)[6] = palette[(v >> 4) & 0xf];
((PIXEL_TYPE *)d)[7] = palette[(v >> 0) & 0xf];
d += BPP * 8;
s += 4;
}
}
/*
* 16 color mode, dup2 horizontal
*/
static void glue(vga_draw_line4d2_, DEPTH)(VGAState *s1, uint8_t *d,
const uint8_t *s, int width)
{
uint32_t plane_mask, data, v, *palette;
int x;
palette = s1->last_palette;
plane_mask = mask16[s1->ar[0x12] & 0xf];
width >>= 3;
for(x = 0; x < width; x++) {
data = ((uint32_t *)s)[0];
data &= plane_mask;
v = expand4[GET_PLANE(data, 0)];
v |= expand4[GET_PLANE(data, 1)] << 1;
v |= expand4[GET_PLANE(data, 2)] << 2;
v |= expand4[GET_PLANE(data, 3)] << 3;
PUT_PIXEL2(d, 0, palette[v >> 28]);
PUT_PIXEL2(d, 1, palette[(v >> 24) & 0xf]);
PUT_PIXEL2(d, 2, palette[(v >> 20) & 0xf]);
PUT_PIXEL2(d, 3, palette[(v >> 16) & 0xf]);
PUT_PIXEL2(d, 4, palette[(v >> 12) & 0xf]);
PUT_PIXEL2(d, 5, palette[(v >> 8) & 0xf]);
PUT_PIXEL2(d, 6, palette[(v >> 4) & 0xf]);
PUT_PIXEL2(d, 7, palette[(v >> 0) & 0xf]);
d += BPP * 16;
s += 4;
}
}
/*
* 256 color mode, double pixels
*
* XXX: add plane_mask support (never used in standard VGA modes)
*/
static void glue(vga_draw_line8d2_, DEPTH)(VGAState *s1, uint8_t *d,
const uint8_t *s, int width)
{
uint32_t *palette;
int x;
palette = s1->last_palette;
width >>= 3;
for(x = 0; x < width; x++) {
PUT_PIXEL2(d, 0, palette[s[0]]);
PUT_PIXEL2(d, 1, palette[s[1]]);
PUT_PIXEL2(d, 2, palette[s[2]]);
PUT_PIXEL2(d, 3, palette[s[3]]);
d += BPP * 8;
s += 4;
}
}
/*
* standard 256 color mode
*
* XXX: add plane_mask support (never used in standard VGA modes)
*/
static void glue(vga_draw_line8_, DEPTH)(VGAState *s1, uint8_t *d,
const uint8_t *s, int width)
{
uint32_t *palette;
int x;
palette = s1->last_palette;
width >>= 3;
for(x = 0; x < width; x++) {
((PIXEL_TYPE *)d)[0] = palette[s[0]];
((PIXEL_TYPE *)d)[1] = palette[s[1]];
((PIXEL_TYPE *)d)[2] = palette[s[2]];
((PIXEL_TYPE *)d)[3] = palette[s[3]];
((PIXEL_TYPE *)d)[4] = palette[s[4]];
((PIXEL_TYPE *)d)[5] = palette[s[5]];
((PIXEL_TYPE *)d)[6] = palette[s[6]];
((PIXEL_TYPE *)d)[7] = palette[s[7]];
d += BPP * 8;
s += 8;
}
}
#endif /* DEPTH != 15 */
/* XXX: optimize */
/*
* 15 bit color
*/
static void glue(vga_draw_line15_, DEPTH)(VGAState *s1, uint8_t *d,
const uint8_t *s, int width)
{
#if DEPTH == 15 && !defined(WORDS_BIGENDIAN)
memcpy(d, s, width * 2);
#else
int w;
uint32_t v, r, g, b;
w = width;
do {
v = lduw_raw((void *)s);
r = (v >> 7) & 0xf8;
g = (v >> 2) & 0xf8;
b = (v << 3) & 0xf8;
((PIXEL_TYPE *)d)[0] = glue(rgb_to_pixel, DEPTH)(r, g, b);
s += 2;
d += BPP;
} while (--w != 0);
#endif
}
/*
* 16 bit color
*/
static void glue(vga_draw_line16_, DEPTH)(VGAState *s1, uint8_t *d,
const uint8_t *s, int width)
{
#if DEPTH == 16 && !defined(WORDS_BIGENDIAN)
memcpy(d, s, width * 2);
#else
int w;
uint32_t v, r, g, b;
w = width;
do {
v = lduw_raw((void *)s);
r = (v >> 8) & 0xf8;
g = (v >> 3) & 0xfc;
b = (v << 3) & 0xf8;
((PIXEL_TYPE *)d)[0] = glue(rgb_to_pixel, DEPTH)(r, g, b);
s += 2;
d += BPP;
} while (--w != 0);
#endif
}
/*
* 32 bit color
*/
static void glue(vga_draw_line32_, DEPTH)(VGAState *s1, uint8_t *d,
const uint8_t *s, int width)
{
#if DEPTH == 32 && !defined(WORDS_BIGENDIAN)
memcpy(d, s, width * 4);
#else
int w;
uint32_t r, g, b;
w = width;
do {
b = s[0];
g = s[1];
r = s[2];
((PIXEL_TYPE *)d)[0] = glue(rgb_to_pixel, DEPTH)(r, g, b);
s += 4;
d += BPP;
} while (--w != 0);
#endif
}
#undef PUT_PIXEL2
#undef DEPTH
#undef BPP
#undef PIXEL_TYPE

View File

@@ -8,7 +8,7 @@ ENTRY(_start)
SECTIONS
{
/* Read-only sections, merged into text segment: */
. = 0xa0000000 + SIZEOF_HEADERS;
. = 0xa8000000 + SIZEOF_HEADERS;
.interp : { *(.interp) }
.hash : { *(.hash) }
.dynsym : { *(.dynsym) }

10
i386.ld
View File

@@ -53,6 +53,16 @@ SECTIONS
_etext = .;
PROVIDE (etext = .);
.fini : { *(.fini) } =0x47ff041f
. = 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 = .);
.rodata : { *(.rodata) *(.gnu.linkonce.r*) }
.rodata1 : { *(.rodata1) }
.reginfo : { *(.reginfo) }

View File

@@ -25,3 +25,4 @@ struct target_pt_regs {
#define ARM_r0 uregs[0]
#define ARM_ORIG_r0 uregs[17]
#define ARM_SYSCALL_BASE 0x900000

261
linux-user/arm/syscall_nr.h Normal file
View File

@@ -0,0 +1,261 @@
/*
* This file contains the system call numbers.
*/
#define TARGET_NR_restart_syscall ( 0)
#define TARGET_NR_exit ( 1)
#define TARGET_NR_fork ( 2)
#define TARGET_NR_read ( 3)
#define TARGET_NR_write ( 4)
#define TARGET_NR_open ( 5)
#define TARGET_NR_close ( 6)
#define TARGET_NR_waitpid ( 7) /* removed */
#define TARGET_NR_creat ( 8)
#define TARGET_NR_link ( 9)
#define TARGET_NR_unlink ( 10)
#define TARGET_NR_execve ( 11)
#define TARGET_NR_chdir ( 12)
#define TARGET_NR_time ( 13)
#define TARGET_NR_mknod ( 14)
#define TARGET_NR_chmod ( 15)
#define TARGET_NR_lchown ( 16)
#define TARGET_NR_break ( 17) /* removed */
/* 18 was sys_stat */
#define TARGET_NR_lseek ( 19)
#define TARGET_NR_getpid ( 20)
#define TARGET_NR_mount ( 21)
#define TARGET_NR_umount ( 22)
#define TARGET_NR_setuid ( 23)
#define TARGET_NR_getuid ( 24)
#define TARGET_NR_stime ( 25)
#define TARGET_NR_ptrace ( 26)
#define TARGET_NR_alarm ( 27)
#define TARGET_NR_pause ( 29)
#define TARGET_NR_utime ( 30)
#define TARGET_NR_stty ( 31) /* removed */
#define TARGET_NR_gtty ( 32) /* removed */
#define TARGET_NR_access ( 33)
#define TARGET_NR_nice ( 34)
#define TARGET_NR_ftime ( 35) /* removed */
#define TARGET_NR_sync ( 36)
#define TARGET_NR_kill ( 37)
#define TARGET_NR_rename ( 38)
#define TARGET_NR_mkdir ( 39)
#define TARGET_NR_rmdir ( 40)
#define TARGET_NR_dup ( 41)
#define TARGET_NR_pipe ( 42)
#define TARGET_NR_times ( 43)
#define TARGET_NR_prof ( 44) /* removed */
#define TARGET_NR_brk ( 45)
#define TARGET_NR_setgid ( 46)
#define TARGET_NR_getgid ( 47)
#define TARGET_NR_signal ( 48) /* removed */
#define TARGET_NR_geteuid ( 49)
#define TARGET_NR_getegid ( 50)
#define TARGET_NR_acct ( 51)
#define TARGET_NR_umount2 ( 52)
#define TARGET_NR_lock ( 53) /* removed */
#define TARGET_NR_ioctl ( 54)
#define TARGET_NR_fcntl ( 55)
#define TARGET_NR_mpx ( 56) /* removed */
#define TARGET_NR_setpgid ( 57)
#define TARGET_NR_ulimit ( 58) /* removed */
/* 59 was sys_olduname */
#define TARGET_NR_umask ( 60)
#define TARGET_NR_chroot ( 61)
#define TARGET_NR_ustat ( 62)
#define TARGET_NR_dup2 ( 63)
#define TARGET_NR_getppid ( 64)
#define TARGET_NR_getpgrp ( 65)
#define TARGET_NR_setsid ( 66)
#define TARGET_NR_sigaction ( 67)
#define TARGET_NR_sgetmask ( 68) /* removed */
#define TARGET_NR_ssetmask ( 69) /* removed */
#define TARGET_NR_setreuid ( 70)
#define TARGET_NR_setregid ( 71)
#define TARGET_NR_sigsuspend ( 72)
#define TARGET_NR_sigpending ( 73)
#define TARGET_NR_sethostname ( 74)
#define TARGET_NR_setrlimit ( 75)
#define TARGET_NR_getrlimit ( 76) /* Back compat 2GB limited rlimit */
#define TARGET_NR_getrusage ( 77)
#define TARGET_NR_gettimeofday ( 78)
#define TARGET_NR_settimeofday ( 79)
#define TARGET_NR_getgroups ( 80)
#define TARGET_NR_setgroups ( 81)
#define TARGET_NR_select ( 82)
#define TARGET_NR_symlink ( 83)
/* 84 was sys_lstat */
#define TARGET_NR_readlink ( 85)
#define TARGET_NR_uselib ( 86)
#define TARGET_NR_swapon ( 87)
#define TARGET_NR_reboot ( 88)
#define TARGET_NR_readdir ( 89)
#define TARGET_NR_mmap ( 90)
#define TARGET_NR_munmap ( 91)
#define TARGET_NR_truncate ( 92)
#define TARGET_NR_ftruncate ( 93)
#define TARGET_NR_fchmod ( 94)
#define TARGET_NR_fchown ( 95)
#define TARGET_NR_getpriority ( 96)
#define TARGET_NR_setpriority ( 97)
#define TARGET_NR_profil ( 98) /* removed */
#define TARGET_NR_statfs ( 99)
#define TARGET_NR_fstatfs (100)
#define TARGET_NR_ioperm (101)
#define TARGET_NR_socketcall (102)
#define TARGET_NR_syslog (103)
#define TARGET_NR_setitimer (104)
#define TARGET_NR_getitimer (105)
#define TARGET_NR_stat (106)
#define TARGET_NR_lstat (107)
#define TARGET_NR_fstat (108)
/* 109 was sys_uname */
/* 110 was sys_iopl */
#define TARGET_NR_vhangup (111)
#define TARGET_NR_idle (112)
#define TARGET_NR_syscall (113) /* syscall to call a syscall! */
#define TARGET_NR_wait4 (114)
#define TARGET_NR_swapoff (115)
#define TARGET_NR_sysinfo (116)
#define TARGET_NR_ipc (117)
#define TARGET_NR_fsync (118)
#define TARGET_NR_sigreturn (119)
#define TARGET_NR_clone (120)
#define TARGET_NR_setdomainname (121)
#define TARGET_NR_uname (122)
#define TARGET_NR_modify_ldt (123)
#define TARGET_NR_adjtimex (124)
#define TARGET_NR_mprotect (125)
#define TARGET_NR_sigprocmask (126)
#define TARGET_NR_create_module (127) /* removed */
#define TARGET_NR_init_module (128)
#define TARGET_NR_delete_module (129)
#define TARGET_NR_get_kernel_syms (130) /* removed */
#define TARGET_NR_quotactl (131)
#define TARGET_NR_getpgid (132)
#define TARGET_NR_fchdir (133)
#define TARGET_NR_bdflush (134)
#define TARGET_NR_sysfs (135)
#define TARGET_NR_personality (136)
#define TARGET_NR_afs_syscall (137) /* Syscall for Andrew File System */
#define TARGET_NR_setfsuid (138)
#define TARGET_NR_setfsgid (139)
#define TARGET_NR__llseek (140)
#define TARGET_NR_getdents (141)
#define TARGET_NR__newselect (142)
#define TARGET_NR_flock (143)
#define TARGET_NR_msync (144)
#define TARGET_NR_readv (145)
#define TARGET_NR_writev (146)
#define TARGET_NR_getsid (147)
#define TARGET_NR_fdatasync (148)
#define TARGET_NR__sysctl (149)
#define TARGET_NR_mlock (150)
#define TARGET_NR_munlock (151)
#define TARGET_NR_mlockall (152)
#define TARGET_NR_munlockall (153)
#define TARGET_NR_sched_setparam (154)
#define TARGET_NR_sched_getparam (155)
#define TARGET_NR_sched_setscheduler (156)
#define TARGET_NR_sched_getscheduler (157)
#define TARGET_NR_sched_yield (158)
#define TARGET_NR_sched_get_priority_max (159)
#define TARGET_NR_sched_get_priority_min (160)
#define TARGET_NR_sched_rr_get_interval (161)
#define TARGET_NR_nanosleep (162)
#define TARGET_NR_mremap (163)
#define TARGET_NR_setresuid (164)
#define TARGET_NR_getresuid (165)
#define TARGET_NR_vm86 (166) /* removed */
#define TARGET_NR_query_module (167) /* removed */
#define TARGET_NR_poll (168)
#define TARGET_NR_nfsservctl (169)
#define TARGET_NR_setresgid (170)
#define TARGET_NR_getresgid (171)
#define TARGET_NR_prctl (172)
#define TARGET_NR_rt_sigreturn (173)
#define TARGET_NR_rt_sigaction (174)
#define TARGET_NR_rt_sigprocmask (175)
#define TARGET_NR_rt_sigpending (176)
#define TARGET_NR_rt_sigtimedwait (177)
#define TARGET_NR_rt_sigqueueinfo (178)
#define TARGET_NR_rt_sigsuspend (179)
#define TARGET_NR_pread (180)
#define TARGET_NR_pwrite (181)
#define TARGET_NR_chown (182)
#define TARGET_NR_getcwd (183)
#define TARGET_NR_capget (184)
#define TARGET_NR_capset (185)
#define TARGET_NR_sigaltstack (186)
#define TARGET_NR_sendfile (187)
/* 188 reserved */
/* 189 reserved */
#define TARGET_NR_vfork (190)
#define TARGET_NR_ugetrlimit (191) /* SuS compliant getrlimit */
#define TARGET_NR_mmap2 (192)
#define TARGET_NR_truncate64 (193)
#define TARGET_NR_ftruncate64 (194)
#define TARGET_NR_stat64 (195)
#define TARGET_NR_lstat64 (196)
#define TARGET_NR_fstat64 (197)
#define TARGET_NR_lchown32 (198)
#define TARGET_NR_getuid32 (199)
#define TARGET_NR_getgid32 (200)
#define TARGET_NR_geteuid32 (201)
#define TARGET_NR_getegid32 (202)
#define TARGET_NR_setreuid32 (203)
#define TARGET_NR_setregid32 (204)
#define TARGET_NR_getgroups32 (205)
#define TARGET_NR_setgroups32 (206)
#define TARGET_NR_fchown32 (207)
#define TARGET_NR_setresuid32 (208)
#define TARGET_NR_getresuid32 (209)
#define TARGET_NR_setresgid32 (210)
#define TARGET_NR_getresgid32 (211)
#define TARGET_NR_chown32 (212)
#define TARGET_NR_setuid32 (213)
#define TARGET_NR_setgid32 (214)
#define TARGET_NR_setfsuid32 (215)
#define TARGET_NR_setfsgid32 (216)
#define TARGET_NR_getdents64 (217)
#define TARGET_NR_pivot_root (218)
#define TARGET_NR_mincore (219)
#define TARGET_NR_madvise (220)
#define TARGET_NR_fcntl64 (221)
/* 222 for tux */
/* 223 is unused */
#define TARGET_NR_gettid (224)
#define TARGET_NR_readahead (225)
#define TARGET_NR_setxattr (226)
#define TARGET_NR_lsetxattr (227)
#define TARGET_NR_fsetxattr (228)
#define TARGET_NR_getxattr (229)
#define TARGET_NR_lgetxattr (230)
#define TARGET_NR_fgetxattr (231)
#define TARGET_NR_listxattr (232)
#define TARGET_NR_llistxattr (233)
#define TARGET_NR_flistxattr (234)
#define TARGET_NR_removexattr (235)
#define TARGET_NR_lremovexattr (236)
#define TARGET_NR_fremovexattr (237)
#define TARGET_NR_tkill (238)
#define TARGET_NR_sendfile64 (239)
#define TARGET_NR_futex (240)
#define TARGET_NR_sched_setaffinity (241)
#define TARGET_NR_sched_getaffinity (242)
#define TARGET_NR_io_setup (243)
#define TARGET_NR_io_destroy (244)
#define TARGET_NR_io_getevents (245)
#define TARGET_NR_io_submit (246)
#define TARGET_NR_io_cancel (247)
#define TARGET_NR_exit_group (248)
#define TARGET_NR_lookup_dcookie (249)
#define TARGET_NR_epoll_create (250)
#define TARGET_NR_epoll_ctl (251)
#define TARGET_NR_epoll_wait (252)
#define TARGET_NR_remap_file_pages (253)
/* 254 for set_thread_area */
/* 255 for get_thread_area */
/* 256 for set_tid_address */

215
linux-user/arm/termbits.h Normal file
View File

@@ -0,0 +1,215 @@
/* from asm/termbits.h */
/* NOTE: exactly the same as i386 */
#define TARGET_NCCS 19
struct target_termios {
unsigned int c_iflag; /* input mode flags */
unsigned int c_oflag; /* output mode flags */
unsigned int c_cflag; /* control mode flags */
unsigned int c_lflag; /* local mode flags */
unsigned char c_line; /* line discipline */
unsigned char c_cc[TARGET_NCCS]; /* control characters */
};
/* c_iflag bits */
#define TARGET_IGNBRK 0000001
#define TARGET_BRKINT 0000002
#define TARGET_IGNPAR 0000004
#define TARGET_PARMRK 0000010
#define TARGET_INPCK 0000020
#define TARGET_ISTRIP 0000040
#define TARGET_INLCR 0000100
#define TARGET_IGNCR 0000200
#define TARGET_ICRNL 0000400
#define TARGET_IUCLC 0001000
#define TARGET_IXON 0002000
#define TARGET_IXANY 0004000
#define TARGET_IXOFF 0010000
#define TARGET_IMAXBEL 0020000
/* c_oflag bits */
#define TARGET_OPOST 0000001
#define TARGET_OLCUC 0000002
#define TARGET_ONLCR 0000004
#define TARGET_OCRNL 0000010
#define TARGET_ONOCR 0000020
#define TARGET_ONLRET 0000040
#define TARGET_OFILL 0000100
#define TARGET_OFDEL 0000200
#define TARGET_NLDLY 0000400
#define TARGET_NL0 0000000
#define TARGET_NL1 0000400
#define TARGET_CRDLY 0003000
#define TARGET_CR0 0000000
#define TARGET_CR1 0001000
#define TARGET_CR2 0002000
#define TARGET_CR3 0003000
#define TARGET_TABDLY 0014000
#define TARGET_TAB0 0000000
#define TARGET_TAB1 0004000
#define TARGET_TAB2 0010000
#define TARGET_TAB3 0014000
#define TARGET_XTABS 0014000
#define TARGET_BSDLY 0020000
#define TARGET_BS0 0000000
#define TARGET_BS1 0020000
#define TARGET_VTDLY 0040000
#define TARGET_VT0 0000000
#define TARGET_VT1 0040000
#define TARGET_FFDLY 0100000
#define TARGET_FF0 0000000
#define TARGET_FF1 0100000
/* c_cflag bit meaning */
#define TARGET_CBAUD 0010017
#define TARGET_B0 0000000 /* hang up */
#define TARGET_B50 0000001
#define TARGET_B75 0000002
#define TARGET_B110 0000003
#define TARGET_B134 0000004
#define TARGET_B150 0000005
#define TARGET_B200 0000006
#define TARGET_B300 0000007
#define TARGET_B600 0000010
#define TARGET_B1200 0000011
#define TARGET_B1800 0000012
#define TARGET_B2400 0000013
#define TARGET_B4800 0000014
#define TARGET_B9600 0000015
#define TARGET_B19200 0000016
#define TARGET_B38400 0000017
#define TARGET_EXTA B19200
#define TARGET_EXTB B38400
#define TARGET_CSIZE 0000060
#define TARGET_CS5 0000000
#define TARGET_CS6 0000020
#define TARGET_CS7 0000040
#define TARGET_CS8 0000060
#define TARGET_CSTOPB 0000100
#define TARGET_CREAD 0000200
#define TARGET_PARENB 0000400
#define TARGET_PARODD 0001000
#define TARGET_HUPCL 0002000
#define TARGET_CLOCAL 0004000
#define TARGET_CBAUDEX 0010000
#define TARGET_B57600 0010001
#define TARGET_B115200 0010002
#define TARGET_B230400 0010003
#define TARGET_B460800 0010004
#define TARGET_CIBAUD 002003600000 /* input baud rate (not used) */
#define TARGET_CRTSCTS 020000000000 /* flow control */
/* c_lflag bits */
#define TARGET_ISIG 0000001
#define TARGET_ICANON 0000002
#define TARGET_XCASE 0000004
#define TARGET_ECHO 0000010
#define TARGET_ECHOE 0000020
#define TARGET_ECHOK 0000040
#define TARGET_ECHONL 0000100
#define TARGET_NOFLSH 0000200
#define TARGET_TOSTOP 0000400
#define TARGET_ECHOCTL 0001000
#define TARGET_ECHOPRT 0002000
#define TARGET_ECHOKE 0004000
#define TARGET_FLUSHO 0010000
#define TARGET_PENDIN 0040000
#define TARGET_IEXTEN 0100000
/* c_cc character offsets */
#define TARGET_VINTR 0
#define TARGET_VQUIT 1
#define TARGET_VERASE 2
#define TARGET_VKILL 3
#define TARGET_VEOF 4
#define TARGET_VTIME 5
#define TARGET_VMIN 6
#define TARGET_VSWTC 7
#define TARGET_VSTART 8
#define TARGET_VSTOP 9
#define TARGET_VSUSP 10
#define TARGET_VEOL 11
#define TARGET_VREPRINT 12
#define TARGET_VDISCARD 13
#define TARGET_VWERASE 14
#define TARGET_VLNEXT 15
#define TARGET_VEOL2 16
/* ioctls */
#define TARGET_TCGETS 0x5401
#define TARGET_TCSETS 0x5402
#define TARGET_TCSETSW 0x5403
#define TARGET_TCSETSF 0x5404
#define TARGET_TCGETA 0x5405
#define TARGET_TCSETA 0x5406
#define TARGET_TCSETAW 0x5407
#define TARGET_TCSETAF 0x5408
#define TARGET_TCSBRK 0x5409
#define TARGET_TCXONC 0x540A
#define TARGET_TCFLSH 0x540B
#define TARGET_TIOCEXCL 0x540C
#define TARGET_TIOCNXCL 0x540D
#define TARGET_TIOCSCTTY 0x540E
#define TARGET_TIOCGPGRP 0x540F
#define TARGET_TIOCSPGRP 0x5410
#define TARGET_TIOCOUTQ 0x5411
#define TARGET_TIOCSTI 0x5412
#define TARGET_TIOCGWINSZ 0x5413
#define TARGET_TIOCSWINSZ 0x5414
#define TARGET_TIOCMGET 0x5415
#define TARGET_TIOCMBIS 0x5416
#define TARGET_TIOCMBIC 0x5417
#define TARGET_TIOCMSET 0x5418
#define TARGET_TIOCGSOFTCAR 0x5419
#define TARGET_TIOCSSOFTCAR 0x541A
#define TARGET_FIONREAD 0x541B
#define TARGET_TIOCINQ TARGET_FIONREAD
#define TARGET_TIOCLINUX 0x541C
#define TARGET_TIOCCONS 0x541D
#define TARGET_TIOCGSERIAL 0x541E
#define TARGET_TIOCSSERIAL 0x541F
#define TARGET_TIOCPKT 0x5420
#define TARGET_FIONBIO 0x5421
#define TARGET_TIOCNOTTY 0x5422
#define TARGET_TIOCSETD 0x5423
#define TARGET_TIOCGETD 0x5424
#define TARGET_TCSBRKP 0x5425 /* Needed for POSIX tcsendbreak() */
#define TARGET_TIOCTTYGSTRUCT 0x5426 /* For debugging only */
#define TARGET_TIOCSBRK 0x5427 /* BSD compatibility */
#define TARGET_TIOCCBRK 0x5428 /* BSD compatibility */
#define TARGET_TIOCGSID 0x5429 /* Return the session ID of FD */
#define TARGET_TIOCGPTN TARGET_IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */
#define TARGET_TIOCSPTLCK TARGET_IOW('T',0x31, int) /* Lock/unlock Pty */
#define TARGET_FIONCLEX 0x5450 /* these numbers need to be adjusted. */
#define TARGET_FIOCLEX 0x5451
#define TARGET_FIOASYNC 0x5452
#define TARGET_TIOCSERCONFIG 0x5453
#define TARGET_TIOCSERGWILD 0x5454
#define TARGET_TIOCSERSWILD 0x5455
#define TARGET_TIOCGLCKTRMIOS 0x5456
#define TARGET_TIOCSLCKTRMIOS 0x5457
#define TARGET_TIOCSERGSTRUCT 0x5458 /* For debugging only */
#define TARGET_TIOCSERGETLSR 0x5459 /* Get line status register */
#define TARGET_TIOCSERGETMULTI 0x545A /* Get multiport config */
#define TARGET_TIOCSERSETMULTI 0x545B /* Set multiport config */
#define TARGET_TIOCMIWAIT 0x545C /* wait for a change on serial input line(s) */
#define TARGET_TIOCGICOUNT 0x545D /* read serial port inline interrupt counts */
#define TARGET_TIOCGHAYESESP 0x545E /* Get Hayes ESP configuration */
#define TARGET_TIOCSHAYESESP 0x545F /* Set Hayes ESP configuration */
/* Used for packet mode */
#define TARGET_TIOCPKT_DATA 0
#define TARGET_TIOCPKT_FLUSHREAD 1
#define TARGET_TIOCPKT_FLUSHWRITE 2
#define TARGET_TIOCPKT_STOP 4
#define TARGET_TIOCPKT_START 8
#define TARGET_TIOCPKT_NOSTOP 16
#define TARGET_TIOCPKT_DOSTOP 32
#define TARGET_TIOCSER_TEMT 0x01 /* Transmitter physically empty */

View File

@@ -74,7 +74,105 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i
regs->ARM_sp = infop->start_stack;
regs->ARM_r2 = tswapl(stack[2]); /* envp */
regs->ARM_r1 = tswapl(stack[1]); /* argv */
regs->ARM_r0 = tswapl(stack[0]); /* argc */
/* XXX: it seems that r0 is zeroed after ! */
// regs->ARM_r0 = tswapl(stack[0]); /* argc */
}
#define USE_ELF_CORE_DUMP
#define ELF_EXEC_PAGESIZE 4096
#endif
#ifdef TARGET_SPARC
#define ELF_START_MMAP 0x80000000
#define elf_check_arch(x) ( (x) == EM_SPARC )
#define ELF_CLASS ELFCLASS32
#define ELF_DATA ELFDATA2MSB
#define ELF_ARCH EM_SPARC
/*XXX*/
#define ELF_PLAT_INIT(_r)
static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
{
regs->psr = 0;
regs->pc = infop->entry;
regs->npc = regs->pc + 4;
regs->y = 0;
regs->u_regs[14] = infop->start_stack - 16 * 4;
}
#endif
#ifdef TARGET_PPC
#define ELF_START_MMAP 0x80000000
#define elf_check_arch(x) ( (x) == EM_PPC )
#define ELF_CLASS ELFCLASS32
#ifdef TARGET_WORDS_BIGENDIAN
#define ELF_DATA ELFDATA2MSB
#else
#define ELF_DATA ELFDATA2LSB
#endif
#define ELF_ARCH EM_PPC
/* Note that isn't exactly what regular kernel does
* but this is what the ABI wants and is needed to allow
* execution of PPC BSD programs.
*/
#define ELF_PLAT_INIT(_r) \
do { \
unsigned long *pos = (unsigned long *)bprm->p, tmp = 1; \
_r->gpr[3] = bprm->argc; \
_r->gpr[4] = (unsigned long)++pos; \
for (; tmp != 0; pos++) \
tmp = *pos; \
_r->gpr[5] = (unsigned long)pos; \
} while (0)
/*
* We need to put in some extra aux table entries to tell glibc what
* the cache block size is, so it can use the dcbz instruction safely.
*/
#define AT_DCACHEBSIZE 19
#define AT_ICACHEBSIZE 20
#define AT_UCACHEBSIZE 21
/* A special ignored type value for PPC, for glibc compatibility. */
#define AT_IGNOREPPC 22
/*
* The requirements here are:
* - keep the final alignment of sp (sp & 0xf)
* - make sure the 32-bit value at the first 16 byte aligned position of
* AUXV is greater than 16 for glibc compatibility.
* AT_IGNOREPPC is used for that.
* - for compatibility with glibc ARCH_DLINFO must always be defined on PPC,
* even if DLINFO_ARCH_ITEMS goes to zero or is undefined.
*/
#define DLINFO_ARCH_ITEMS 3
#define ARCH_DLINFO \
do { \
sp -= DLINFO_ARCH_ITEMS * 2; \
NEW_AUX_ENT(0, AT_DCACHEBSIZE, 0x20); \
NEW_AUX_ENT(1, AT_ICACHEBSIZE, 0x20); \
NEW_AUX_ENT(2, AT_UCACHEBSIZE, 0); \
/* \
* Now handle glibc compatibility. \
*/ \
sp -= 2*2; \
NEW_AUX_ENT(0, AT_IGNOREPPC, AT_IGNOREPPC); \
NEW_AUX_ENT(1, AT_IGNOREPPC, AT_IGNOREPPC); \
} while (0)
static inline void init_thread(struct target_pt_regs *_regs, struct image_info *infop)
{
_regs->msr = 1 << MSR_PR; /* Set user mode */
_regs->gpr[1] = infop->start_stack;
_regs->nip = infop->entry;
}
#define USE_ELF_CORE_DUMP
@@ -163,7 +261,7 @@ struct exec
#define INTERPRETER_AOUT 1
#define INTERPRETER_ELF 2
#define DLINFO_ITEMS 12
#define DLINFO_ITEMS 11
#define put_user(x,ptr) (void)(*(ptr) = (typeof(*ptr))(x))
#define get_user(ptr) (typeof(*ptr))(*(ptr))
@@ -455,18 +553,32 @@ static void set_brk(unsigned long start, unsigned long end)
}
/* We need to explicitly zero any fractional pages
after the data section (i.e. bss). This would
contain the junk from the file that should not
be in memory */
/* We need to explicitly zero any fractional pages after the data
section (i.e. bss). This would contain the junk from the file that
should not be in memory. */
static void padzero(unsigned long elf_bss)
{
unsigned long nbyte;
char * fpnt;
nbyte = elf_bss & (host_page_size-1); /* was TARGET_PAGE_SIZE - JRP */
/* XXX: this is really a hack : if the real host page size is
smaller than the target page size, some pages after the end
of the file may not be mapped. A better fix would be to
patch target_mmap(), but it is more complicated as the file
size must be known */
if (real_host_page_size < host_page_size) {
unsigned long end_addr, end_addr1;
end_addr1 = (elf_bss + real_host_page_size - 1) &
~(real_host_page_size - 1);
end_addr = HOST_PAGE_ALIGN(elf_bss);
if (end_addr1 < end_addr) {
mmap((void *)end_addr1, end_addr - end_addr1,
PROT_READ|PROT_WRITE|PROT_EXEC,
MAP_FIXED|MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
}
}
nbyte = elf_bss & (host_page_size-1);
if (nbyte) {
nbyte = host_page_size - nbyte;
fpnt = (char *) elf_bss;
@@ -483,15 +595,51 @@ static unsigned int * create_elf_tables(char *p, int argc, int envc,
unsigned long interp_load_addr, int ibcs,
struct image_info *info)
{
target_ulong *argv, *envp, *dlinfo;
target_ulong *sp;
/*
* Force 16 byte alignment here for generality.
*/
target_ulong *argv, *envp;
target_ulong *sp, *csp;
/*
* Force 16 byte _final_ alignment here for generality.
*/
sp = (unsigned int *) (~15UL & (unsigned long) p);
sp -= exec ? DLINFO_ITEMS*2 : 2;
dlinfo = sp;
csp = sp;
csp -= (DLINFO_ITEMS + 1) * 2;
#ifdef DLINFO_ARCH_ITEMS
csp -= DLINFO_ARCH_ITEMS*2;
#endif
csp -= envc+1;
csp -= argc+1;
csp -= (!ibcs ? 3 : 1); /* argc itself */
if ((unsigned long)csp & 15UL)
sp -= ((unsigned long)csp & 15UL) / sizeof(*sp);
#define NEW_AUX_ENT(nr, id, val) \
put_user (tswapl(id), sp + (nr * 2)); \
put_user (tswapl(val), sp + (nr * 2 + 1))
sp -= 2;
NEW_AUX_ENT (0, AT_NULL, 0);
sp -= DLINFO_ITEMS*2;
NEW_AUX_ENT( 0, AT_PHDR, (target_ulong)(load_addr + exec->e_phoff));
NEW_AUX_ENT( 1, AT_PHENT, (target_ulong)(sizeof (struct elf_phdr)));
NEW_AUX_ENT( 2, AT_PHNUM, (target_ulong)(exec->e_phnum));
NEW_AUX_ENT( 3, AT_PAGESZ, (target_ulong)(TARGET_PAGE_SIZE));
NEW_AUX_ENT( 4, AT_BASE, (target_ulong)(interp_load_addr));
NEW_AUX_ENT( 5, AT_FLAGS, (target_ulong)0);
NEW_AUX_ENT( 6, AT_ENTRY, load_bias + exec->e_entry);
NEW_AUX_ENT( 7, AT_UID, (target_ulong) getuid());
NEW_AUX_ENT( 8, AT_EUID, (target_ulong) geteuid());
NEW_AUX_ENT( 9, AT_GID, (target_ulong) getgid());
NEW_AUX_ENT(11, AT_EGID, (target_ulong) getegid());
#ifdef ARCH_DLINFO
/*
* ARCH_DLINFO must come last so platform specific code can enforce
* special alignment requirements on the AUXV if necessary (eg. PPC).
*/
ARCH_DLINFO;
#endif
#undef NEW_AUX_ENT
sp -= envc+1;
envp = sp;
sp -= argc+1;
@@ -500,26 +648,6 @@ static unsigned int * create_elf_tables(char *p, int argc, int envc,
put_user(tswapl((target_ulong)envp),--sp);
put_user(tswapl((target_ulong)argv),--sp);
}
#define NEW_AUX_ENT(id, val) \
put_user (tswapl(id), dlinfo++); \
put_user (tswapl(val), dlinfo++)
if (exec) { /* Put this here for an ELF program interpreter */
NEW_AUX_ENT (AT_PHDR, (target_ulong)(load_addr + exec->e_phoff));
NEW_AUX_ENT (AT_PHENT, (target_ulong)(sizeof (struct elf_phdr)));
NEW_AUX_ENT (AT_PHNUM, (target_ulong)(exec->e_phnum));
NEW_AUX_ENT (AT_PAGESZ, (target_ulong)(TARGET_PAGE_SIZE));
NEW_AUX_ENT (AT_BASE, (target_ulong)(interp_load_addr));
NEW_AUX_ENT (AT_FLAGS, (target_ulong)0);
NEW_AUX_ENT (AT_ENTRY, load_bias + exec->e_entry);
NEW_AUX_ENT (AT_UID, (target_ulong) getuid());
NEW_AUX_ENT (AT_EUID, (target_ulong) geteuid());
NEW_AUX_ENT (AT_GID, (target_ulong) getgid());
NEW_AUX_ENT (AT_EGID, (target_ulong) getegid());
}
NEW_AUX_ENT (AT_NULL, 0);
#undef NEW_AUX_ENT
put_user(tswapl(argc),--sp);
info->arg_start = (unsigned int)((unsigned long)p & 0xffffffff);
while (argc-->0) {
@@ -1087,7 +1215,7 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r
create_elf_tables((char *)bprm->p,
bprm->argc,
bprm->envc,
(interpreter_type == INTERPRETER_ELF ? &elf_ex : NULL),
&elf_ex,
load_addr, load_bias,
interp_load_addr,
(interpreter_type == INTERPRETER_AOUT ? 0 : 1),

View File

@@ -0,0 +1,273 @@
/*
* This file contains the system call numbers.
*/
#define TARGET_NR_restart_syscall 0
#define TARGET_NR_exit 1
#define TARGET_NR_fork 2
#define TARGET_NR_read 3
#define TARGET_NR_write 4
#define TARGET_NR_open 5
#define TARGET_NR_close 6
#define TARGET_NR_waitpid 7
#define TARGET_NR_creat 8
#define TARGET_NR_link 9
#define TARGET_NR_unlink 10
#define TARGET_NR_execve 11
#define TARGET_NR_chdir 12
#define TARGET_NR_time 13
#define TARGET_NR_mknod 14
#define TARGET_NR_chmod 15
#define TARGET_NR_lchown 16
#define TARGET_NR_break 17
#define TARGET_NR_oldstat 18
#define TARGET_NR_lseek 19
#define TARGET_NR_getpid 20
#define TARGET_NR_mount 21
#define TARGET_NR_umount 22
#define TARGET_NR_setuid 23
#define TARGET_NR_getuid 24
#define TARGET_NR_stime 25
#define TARGET_NR_ptrace 26
#define TARGET_NR_alarm 27
#define TARGET_NR_oldfstat 28
#define TARGET_NR_pause 29
#define TARGET_NR_utime 30
#define TARGET_NR_stty 31
#define TARGET_NR_gtty 32
#define TARGET_NR_access 33
#define TARGET_NR_nice 34
#define TARGET_NR_ftime 35
#define TARGET_NR_sync 36
#define TARGET_NR_kill 37
#define TARGET_NR_rename 38
#define TARGET_NR_mkdir 39
#define TARGET_NR_rmdir 40
#define TARGET_NR_dup 41
#define TARGET_NR_pipe 42
#define TARGET_NR_times 43
#define TARGET_NR_prof 44
#define TARGET_NR_brk 45
#define TARGET_NR_setgid 46
#define TARGET_NR_getgid 47
#define TARGET_NR_signal 48
#define TARGET_NR_geteuid 49
#define TARGET_NR_getegid 50
#define TARGET_NR_acct 51
#define TARGET_NR_umount2 52
#define TARGET_NR_lock 53
#define TARGET_NR_ioctl 54
#define TARGET_NR_fcntl 55
#define TARGET_NR_mpx 56
#define TARGET_NR_setpgid 57
#define TARGET_NR_ulimit 58
#define TARGET_NR_oldolduname 59
#define TARGET_NR_umask 60
#define TARGET_NR_chroot 61
#define TARGET_NR_ustat 62
#define TARGET_NR_dup2 63
#define TARGET_NR_getppid 64
#define TARGET_NR_getpgrp 65
#define TARGET_NR_setsid 66
#define TARGET_NR_sigaction 67
#define TARGET_NR_sgetmask 68
#define TARGET_NR_ssetmask 69
#define TARGET_NR_setreuid 70
#define TARGET_NR_setregid 71
#define TARGET_NR_sigsuspend 72
#define TARGET_NR_sigpending 73
#define TARGET_NR_sethostname 74
#define TARGET_NR_setrlimit 75
#define TARGET_NR_getrlimit 76 /* Back compatible 2Gig limited rlimit */
#define TARGET_NR_getrusage 77
#define TARGET_NR_gettimeofday 78
#define TARGET_NR_settimeofday 79
#define TARGET_NR_getgroups 80
#define TARGET_NR_setgroups 81
#define TARGET_NR_select 82
#define TARGET_NR_symlink 83
#define TARGET_NR_oldlstat 84
#define TARGET_NR_readlink 85
#define TARGET_NR_uselib 86
#define TARGET_NR_swapon 87
#define TARGET_NR_reboot 88
#define TARGET_NR_readdir 89
#define TARGET_NR_mmap 90
#define TARGET_NR_munmap 91
#define TARGET_NR_truncate 92
#define TARGET_NR_ftruncate 93
#define TARGET_NR_fchmod 94
#define TARGET_NR_fchown 95
#define TARGET_NR_getpriority 96
#define TARGET_NR_setpriority 97
#define TARGET_NR_profil 98
#define TARGET_NR_statfs 99
#define TARGET_NR_fstatfs 100
#define TARGET_NR_ioperm 101
#define TARGET_NR_socketcall 102
#define TARGET_NR_syslog 103
#define TARGET_NR_setitimer 104
#define TARGET_NR_getitimer 105
#define TARGET_NR_stat 106
#define TARGET_NR_lstat 107
#define TARGET_NR_fstat 108
#define TARGET_NR_olduname 109
#define TARGET_NR_iopl 110
#define TARGET_NR_vhangup 111
#define TARGET_NR_idle 112
#define TARGET_NR_vm86old 113
#define TARGET_NR_wait4 114
#define TARGET_NR_swapoff 115
#define TARGET_NR_sysinfo 116
#define TARGET_NR_ipc 117
#define TARGET_NR_fsync 118
#define TARGET_NR_sigreturn 119
#define TARGET_NR_clone 120
#define TARGET_NR_setdomainname 121
#define TARGET_NR_uname 122
#define TARGET_NR_modify_ldt 123
#define TARGET_NR_adjtimex 124
#define TARGET_NR_mprotect 125
#define TARGET_NR_sigprocmask 126
#define TARGET_NR_create_module 127
#define TARGET_NR_init_module 128
#define TARGET_NR_delete_module 129
#define TARGET_NR_get_kernel_syms 130
#define TARGET_NR_quotactl 131
#define TARGET_NR_getpgid 132
#define TARGET_NR_fchdir 133
#define TARGET_NR_bdflush 134
#define TARGET_NR_sysfs 135
#define TARGET_NR_personality 136
#define TARGET_NR_afs_syscall 137 /* Syscall for Andrew File System */
#define TARGET_NR_setfsuid 138
#define TARGET_NR_setfsgid 139
#define TARGET_NR__llseek 140
#define TARGET_NR_getdents 141
#define TARGET_NR__newselect 142
#define TARGET_NR_flock 143
#define TARGET_NR_msync 144
#define TARGET_NR_readv 145
#define TARGET_NR_writev 146
#define TARGET_NR_getsid 147
#define TARGET_NR_fdatasync 148
#define TARGET_NR__sysctl 149
#define TARGET_NR_mlock 150
#define TARGET_NR_munlock 151
#define TARGET_NR_mlockall 152
#define TARGET_NR_munlockall 153
#define TARGET_NR_sched_setparam 154
#define TARGET_NR_sched_getparam 155
#define TARGET_NR_sched_setscheduler 156
#define TARGET_NR_sched_getscheduler 157
#define TARGET_NR_sched_yield 158
#define TARGET_NR_sched_get_priority_max 159
#define TARGET_NR_sched_get_priority_min 160
#define TARGET_NR_sched_rr_get_interval 161
#define TARGET_NR_nanosleep 162
#define TARGET_NR_mremap 163
#define TARGET_NR_setresuid 164
#define TARGET_NR_getresuid 165
#define TARGET_NR_vm86 166
#define TARGET_NR_query_module 167
#define TARGET_NR_poll 168
#define TARGET_NR_nfsservctl 169
#define TARGET_NR_setresgid 170
#define TARGET_NR_getresgid 171
#define TARGET_NR_prctl 172
#define TARGET_NR_rt_sigreturn 173
#define TARGET_NR_rt_sigaction 174
#define TARGET_NR_rt_sigprocmask 175
#define TARGET_NR_rt_sigpending 176
#define TARGET_NR_rt_sigtimedwait 177
#define TARGET_NR_rt_sigqueueinfo 178
#define TARGET_NR_rt_sigsuspend 179
#define TARGET_NR_pread 180
#define TARGET_NR_pwrite 181
#define TARGET_NR_chown 182
#define TARGET_NR_getcwd 183
#define TARGET_NR_capget 184
#define TARGET_NR_capset 185
#define TARGET_NR_sigaltstack 186
#define TARGET_NR_sendfile 187
#define TARGET_NR_getpmsg 188 /* some people actually want streams */
#define TARGET_NR_putpmsg 189 /* some people actually want streams */
#define TARGET_NR_vfork 190
#define TARGET_NR_ugetrlimit 191 /* SuS compliant getrlimit */
#define TARGET_NR_mmap2 192
#define TARGET_NR_truncate64 193
#define TARGET_NR_ftruncate64 194
#define TARGET_NR_stat64 195
#define TARGET_NR_lstat64 196
#define TARGET_NR_fstat64 197
#define TARGET_NR_lchown32 198
#define TARGET_NR_getuid32 199
#define TARGET_NR_getgid32 200
#define TARGET_NR_geteuid32 201
#define TARGET_NR_getegid32 202
#define TARGET_NR_setreuid32 203
#define TARGET_NR_setregid32 204
#define TARGET_NR_getgroups32 205
#define TARGET_NR_setgroups32 206
#define TARGET_NR_fchown32 207
#define TARGET_NR_setresuid32 208
#define TARGET_NR_getresuid32 209
#define TARGET_NR_setresgid32 210
#define TARGET_NR_getresgid32 211
#define TARGET_NR_chown32 212
#define TARGET_NR_setuid32 213
#define TARGET_NR_setgid32 214
#define TARGET_NR_setfsuid32 215
#define TARGET_NR_setfsgid32 216
#define TARGET_NR_pivot_root 217
#define TARGET_NR_mincore 218
#define TARGET_NR_madvise 219
#define TARGET_NR_madvise1 219 /* delete when C lib stub is removed */
#define TARGET_NR_getdents64 220
#define TARGET_NR_fcntl64 221
/* 223 is unused */
#define TARGET_NR_gettid 224
#define TARGET_NR_readahead 225
#define TARGET_NR_setxattr 226
#define TARGET_NR_lsetxattr 227
#define TARGET_NR_fsetxattr 228
#define TARGET_NR_getxattr 229
#define TARGET_NR_lgetxattr 230
#define TARGET_NR_fgetxattr 231
#define TARGET_NR_listxattr 232
#define TARGET_NR_llistxattr 233
#define TARGET_NR_flistxattr 234
#define TARGET_NR_removexattr 235
#define TARGET_NR_lremovexattr 236
#define TARGET_NR_fremovexattr 237
#define TARGET_NR_tkill 238
#define TARGET_NR_sendfile64 239
#define TARGET_NR_futex 240
#define TARGET_NR_sched_setaffinity 241
#define TARGET_NR_sched_getaffinity 242
#define TARGET_NR_set_thread_area 243
#define TARGET_NR_get_thread_area 244
#define TARGET_NR_io_setup 245
#define TARGET_NR_io_destroy 246
#define TARGET_NR_io_getevents 247
#define TARGET_NR_io_submit 248
#define TARGET_NR_io_cancel 249
#define TARGET_NR_fadvise64 250
#define TARGET_NR_exit_group 252
#define TARGET_NR_lookup_dcookie 253
#define TARGET_NR_epoll_create 254
#define TARGET_NR_epoll_ctl 255
#define TARGET_NR_epoll_wait 256
#define TARGET_NR_remap_file_pages 257
#define TARGET_NR_set_tid_address 258
#define TARGET_NR_timer_create 259
#define TARGET_NR_timer_settime (TARGET_NR_timer_create+1)
#define TARGET_NR_timer_gettime (TARGET_NR_timer_create+2)
#define TARGET_NR_timer_getoverrun (TARGET_NR_timer_create+3)
#define TARGET_NR_timer_delete (TARGET_NR_timer_create+4)
#define TARGET_NR_clock_settime (TARGET_NR_timer_create+5)
#define TARGET_NR_clock_gettime (TARGET_NR_timer_create+6)
#define TARGET_NR_clock_getres (TARGET_NR_timer_create+7)
#define TARGET_NR_clock_nanosleep (TARGET_NR_timer_create+8)

214
linux-user/i386/termbits.h Normal file
View File

@@ -0,0 +1,214 @@
/* from asm/termbits.h */
#define TARGET_NCCS 19
struct target_termios {
unsigned int c_iflag; /* input mode flags */
unsigned int c_oflag; /* output mode flags */
unsigned int c_cflag; /* control mode flags */
unsigned int c_lflag; /* local mode flags */
unsigned char c_line; /* line discipline */
unsigned char c_cc[TARGET_NCCS]; /* control characters */
};
/* c_iflag bits */
#define TARGET_IGNBRK 0000001
#define TARGET_BRKINT 0000002
#define TARGET_IGNPAR 0000004
#define TARGET_PARMRK 0000010
#define TARGET_INPCK 0000020
#define TARGET_ISTRIP 0000040
#define TARGET_INLCR 0000100
#define TARGET_IGNCR 0000200
#define TARGET_ICRNL 0000400
#define TARGET_IUCLC 0001000
#define TARGET_IXON 0002000
#define TARGET_IXANY 0004000
#define TARGET_IXOFF 0010000
#define TARGET_IMAXBEL 0020000
/* c_oflag bits */
#define TARGET_OPOST 0000001
#define TARGET_OLCUC 0000002
#define TARGET_ONLCR 0000004
#define TARGET_OCRNL 0000010
#define TARGET_ONOCR 0000020
#define TARGET_ONLRET 0000040
#define TARGET_OFILL 0000100
#define TARGET_OFDEL 0000200
#define TARGET_NLDLY 0000400
#define TARGET_NL0 0000000
#define TARGET_NL1 0000400
#define TARGET_CRDLY 0003000
#define TARGET_CR0 0000000
#define TARGET_CR1 0001000
#define TARGET_CR2 0002000
#define TARGET_CR3 0003000
#define TARGET_TABDLY 0014000
#define TARGET_TAB0 0000000
#define TARGET_TAB1 0004000
#define TARGET_TAB2 0010000
#define TARGET_TAB3 0014000
#define TARGET_XTABS 0014000
#define TARGET_BSDLY 0020000
#define TARGET_BS0 0000000
#define TARGET_BS1 0020000
#define TARGET_VTDLY 0040000
#define TARGET_VT0 0000000
#define TARGET_VT1 0040000
#define TARGET_FFDLY 0100000
#define TARGET_FF0 0000000
#define TARGET_FF1 0100000
/* c_cflag bit meaning */
#define TARGET_CBAUD 0010017
#define TARGET_B0 0000000 /* hang up */
#define TARGET_B50 0000001
#define TARGET_B75 0000002
#define TARGET_B110 0000003
#define TARGET_B134 0000004
#define TARGET_B150 0000005
#define TARGET_B200 0000006
#define TARGET_B300 0000007
#define TARGET_B600 0000010
#define TARGET_B1200 0000011
#define TARGET_B1800 0000012
#define TARGET_B2400 0000013
#define TARGET_B4800 0000014
#define TARGET_B9600 0000015
#define TARGET_B19200 0000016
#define TARGET_B38400 0000017
#define TARGET_EXTA B19200
#define TARGET_EXTB B38400
#define TARGET_CSIZE 0000060
#define TARGET_CS5 0000000
#define TARGET_CS6 0000020
#define TARGET_CS7 0000040
#define TARGET_CS8 0000060
#define TARGET_CSTOPB 0000100
#define TARGET_CREAD 0000200
#define TARGET_PARENB 0000400
#define TARGET_PARODD 0001000
#define TARGET_HUPCL 0002000
#define TARGET_CLOCAL 0004000
#define TARGET_CBAUDEX 0010000
#define TARGET_B57600 0010001
#define TARGET_B115200 0010002
#define TARGET_B230400 0010003
#define TARGET_B460800 0010004
#define TARGET_CIBAUD 002003600000 /* input baud rate (not used) */
#define TARGET_CRTSCTS 020000000000 /* flow control */
/* c_lflag bits */
#define TARGET_ISIG 0000001
#define TARGET_ICANON 0000002
#define TARGET_XCASE 0000004
#define TARGET_ECHO 0000010
#define TARGET_ECHOE 0000020
#define TARGET_ECHOK 0000040
#define TARGET_ECHONL 0000100
#define TARGET_NOFLSH 0000200
#define TARGET_TOSTOP 0000400
#define TARGET_ECHOCTL 0001000
#define TARGET_ECHOPRT 0002000
#define TARGET_ECHOKE 0004000
#define TARGET_FLUSHO 0010000
#define TARGET_PENDIN 0040000
#define TARGET_IEXTEN 0100000
/* c_cc character offsets */
#define TARGET_VINTR 0
#define TARGET_VQUIT 1
#define TARGET_VERASE 2
#define TARGET_VKILL 3
#define TARGET_VEOF 4
#define TARGET_VTIME 5
#define TARGET_VMIN 6
#define TARGET_VSWTC 7
#define TARGET_VSTART 8
#define TARGET_VSTOP 9
#define TARGET_VSUSP 10
#define TARGET_VEOL 11
#define TARGET_VREPRINT 12
#define TARGET_VDISCARD 13
#define TARGET_VWERASE 14
#define TARGET_VLNEXT 15
#define TARGET_VEOL2 16
/* ioctls */
#define TARGET_TCGETS 0x5401
#define TARGET_TCSETS 0x5402
#define TARGET_TCSETSW 0x5403
#define TARGET_TCSETSF 0x5404
#define TARGET_TCGETA 0x5405
#define TARGET_TCSETA 0x5406
#define TARGET_TCSETAW 0x5407
#define TARGET_TCSETAF 0x5408
#define TARGET_TCSBRK 0x5409
#define TARGET_TCXONC 0x540A
#define TARGET_TCFLSH 0x540B
#define TARGET_TIOCEXCL 0x540C
#define TARGET_TIOCNXCL 0x540D
#define TARGET_TIOCSCTTY 0x540E
#define TARGET_TIOCGPGRP 0x540F
#define TARGET_TIOCSPGRP 0x5410
#define TARGET_TIOCOUTQ 0x5411
#define TARGET_TIOCSTI 0x5412
#define TARGET_TIOCGWINSZ 0x5413
#define TARGET_TIOCSWINSZ 0x5414
#define TARGET_TIOCMGET 0x5415
#define TARGET_TIOCMBIS 0x5416
#define TARGET_TIOCMBIC 0x5417
#define TARGET_TIOCMSET 0x5418
#define TARGET_TIOCGSOFTCAR 0x5419
#define TARGET_TIOCSSOFTCAR 0x541A
#define TARGET_FIONREAD 0x541B
#define TARGET_TIOCINQ TARGET_FIONREAD
#define TARGET_TIOCLINUX 0x541C
#define TARGET_TIOCCONS 0x541D
#define TARGET_TIOCGSERIAL 0x541E
#define TARGET_TIOCSSERIAL 0x541F
#define TARGET_TIOCPKT 0x5420
#define TARGET_FIONBIO 0x5421
#define TARGET_TIOCNOTTY 0x5422
#define TARGET_TIOCSETD 0x5423
#define TARGET_TIOCGETD 0x5424
#define TARGET_TCSBRKP 0x5425 /* Needed for POSIX tcsendbreak() */
#define TARGET_TIOCTTYGSTRUCT 0x5426 /* For debugging only */
#define TARGET_TIOCSBRK 0x5427 /* BSD compatibility */
#define TARGET_TIOCCBRK 0x5428 /* BSD compatibility */
#define TARGET_TIOCGSID 0x5429 /* Return the session ID of FD */
#define TARGET_TIOCGPTN TARGET_IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */
#define TARGET_TIOCSPTLCK TARGET_IOW('T',0x31, int) /* Lock/unlock Pty */
#define TARGET_FIONCLEX 0x5450 /* these numbers need to be adjusted. */
#define TARGET_FIOCLEX 0x5451
#define TARGET_FIOASYNC 0x5452
#define TARGET_TIOCSERCONFIG 0x5453
#define TARGET_TIOCSERGWILD 0x5454
#define TARGET_TIOCSERSWILD 0x5455
#define TARGET_TIOCGLCKTRMIOS 0x5456
#define TARGET_TIOCSLCKTRMIOS 0x5457
#define TARGET_TIOCSERGSTRUCT 0x5458 /* For debugging only */
#define TARGET_TIOCSERGETLSR 0x5459 /* Get line status register */
#define TARGET_TIOCSERGETMULTI 0x545A /* Get multiport config */
#define TARGET_TIOCSERSETMULTI 0x545B /* Set multiport config */
#define TARGET_TIOCMIWAIT 0x545C /* wait for a change on serial input line(s) */
#define TARGET_TIOCGICOUNT 0x545D /* read serial port inline interrupt counts */
#define TARGET_TIOCGHAYESESP 0x545E /* Get Hayes ESP configuration */
#define TARGET_TIOCSHAYESESP 0x545F /* Set Hayes ESP configuration */
/* Used for packet mode */
#define TARGET_TIOCPKT_DATA 0
#define TARGET_TIOCPKT_FLUSHREAD 1
#define TARGET_TIOCPKT_FLUSHWRITE 2
#define TARGET_TIOCPKT_STOP 4
#define TARGET_TIOCPKT_START 8
#define TARGET_TIOCPKT_NOSTOP 16
#define TARGET_TIOCPKT_DOSTOP 32
#define TARGET_TIOCSER_TEMT 0x01 /* Transmitter physically empty */

View File

@@ -1,5 +1,5 @@
/*
* qemu main
* qemu user main
*
* Copyright (c) 2003 Fabrice Bellard
*
@@ -28,17 +28,15 @@
#define DEBUG_LOGFILE "/tmp/qemu.log"
FILE *logfile = NULL;
int loglevel;
static const char *interp_prefix = CONFIG_QEMU_PREFIX;
#ifdef __i386__
#if defined(__i386__) && !defined(CONFIG_STATIC)
/* Force usage of an ELF interpreter even if it is an ELF shared
object ! */
const char interp[] __attribute__((section(".interp"))) = "/lib/ld-linux.so.2";
#endif
/* for recent libc, we add these dummies symbol which are not declared
/* for recent libc, we add these dummy symbols which are not declared
when generating a linked object (bug in ld ?) */
#if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 3)
long __init_array_start[0];
@@ -246,8 +244,6 @@ void cpu_loop(CPUX86State *env)
#ifdef TARGET_ARM
#define ARM_SYSCALL_BASE 0x900000
void cpu_loop(CPUARMState *env)
{
int trapnr;
@@ -285,6 +281,9 @@ void cpu_loop(CPUARMState *env)
}
}
break;
case EXCP_INTERRUPT:
/* just indicate that signals should be handled asap */
break;
default:
error:
fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n",
@@ -298,10 +297,258 @@ void cpu_loop(CPUARMState *env)
#endif
#ifdef TARGET_SPARC
//#define DEBUG_WIN
/* WARNING: dealing with register windows _is_ complicated */
static inline int get_reg_index(CPUSPARCState *env, int cwp, int index)
{
index = (index + cwp * 16) & (16 * NWINDOWS - 1);
/* wrap handling : if cwp is on the last window, then we use the
registers 'after' the end */
if (index < 8 && env->cwp == (NWINDOWS - 1))
index += (16 * NWINDOWS);
return index;
}
static inline void save_window_offset(CPUSPARCState *env, int offset)
{
unsigned int new_wim, i, cwp1;
uint32_t *sp_ptr;
new_wim = ((env->wim >> 1) | (env->wim << (NWINDOWS - 1))) &
((1LL << NWINDOWS) - 1);
/* save the window */
cwp1 = (env->cwp + offset) & (NWINDOWS - 1);
sp_ptr = (uint32_t *)(env->regbase[get_reg_index(env, cwp1, 6)]);
#if defined(DEBUG_WIN)
printf("win_overflow: sp_ptr=0x%x save_cwp=%d\n",
(int)sp_ptr, cwp1);
#endif
for(i = 0; i < 16; i++)
stl_raw(sp_ptr + i, env->regbase[get_reg_index(env, cwp1, 8 + i)]);
env->wim = new_wim;
}
static void save_window(CPUSPARCState *env)
{
save_window_offset(env, 2);
}
static void restore_window(CPUSPARCState *env)
{
unsigned int new_wim, i, cwp1;
uint32_t *sp_ptr;
new_wim = ((env->wim << 1) | (env->wim >> (NWINDOWS - 1))) &
((1LL << NWINDOWS) - 1);
/* restore the invalid window */
cwp1 = (env->cwp + 1) & (NWINDOWS - 1);
sp_ptr = (uint32_t *)(env->regbase[get_reg_index(env, cwp1, 6)]);
#if defined(DEBUG_WIN)
printf("win_underflow: sp_ptr=0x%x load_cwp=%d\n",
(int)sp_ptr, cwp1);
#endif
for(i = 0; i < 16; i++)
env->regbase[get_reg_index(env, cwp1, 8 + i)] = ldl_raw(sp_ptr + i);
env->wim = new_wim;
}
static void flush_windows(CPUSPARCState *env)
{
int offset, cwp1;
#if defined(DEBUG_WIN)
printf("flush_windows:\n");
#endif
offset = 2;
for(;;) {
/* if restore would invoke restore_window(), then we can stop */
cwp1 = (env->cwp + 1) & (NWINDOWS - 1);
if (env->wim & (1 << cwp1))
break;
#if defined(DEBUG_WIN)
printf("offset=%d: ", offset);
#endif
save_window_offset(env, offset);
offset++;
}
}
void cpu_loop (CPUSPARCState *env)
{
int trapnr, ret;
while (1) {
trapnr = cpu_sparc_exec (env);
switch (trapnr) {
case 0x88:
case 0x90:
ret = do_syscall (env, env->gregs[1],
env->regwptr[0], env->regwptr[1],
env->regwptr[2], env->regwptr[3],
env->regwptr[4], env->regwptr[5]);
if ((unsigned int)ret >= (unsigned int)(-515)) {
env->psr |= PSR_CARRY;
ret = -ret;
} else {
env->psr &= ~PSR_CARRY;
}
env->regwptr[0] = ret;
/* next instruction */
env->pc = env->npc;
env->npc = env->npc + 4;
break;
case 0x83: /* flush windows */
// flush_windows(env);
/* next instruction */
env->pc = env->npc;
env->npc = env->npc + 4;
break;
case TT_WIN_OVF: /* window overflow */
save_window(env);
break;
case TT_WIN_UNF: /* window underflow */
restore_window(env);
break;
default:
printf ("Unhandled trap: 0x%x\n", trapnr);
cpu_sparc_dump_state(env, stderr, 0);
exit (1);
}
process_pending_signals (env);
}
}
#endif
#ifdef TARGET_PPC
void cpu_loop(CPUPPCState *env)
{
int trapnr;
target_siginfo_t info;
for(;;) {
trapnr = cpu_ppc_exec(env);
switch(trapnr) {
case EXCP_NONE:
case EXCP_INTERRUPT:
case EXCP_MTMSR: /* mtmsr instruction: */
case EXCP_BRANCH: /* branch instruction */
/* Single step mode */
break;
#if 0
case EXCP_RESET: /* System reset */
fprintf(stderr, "RESET asked... Stop emulation\n");
cpu_ppc_dump_state(env, stderr, 0);
abort();
#endif
case EXCP_MACHINE_CHECK: /* Machine check exception */
fprintf(stderr, "Machine check exeption... "
"See you in kernel code !\n");
cpu_ppc_dump_state(env, stderr, 0);
abort();
case EXCP_DSI: /* Impossible memory access */
fprintf(stderr, "Invalid memory access\n");
info.si_signo = SIGSEGV;
info.si_errno = 0;
info.si_code = TARGET_ILL_ILLOPN;
info._sifields._sigfault._addr = env->nip;
queue_signal(info.si_signo, &info);
break;
case EXCP_ISI: /* Impossible instruction fetch */
fprintf(stderr, "Invalid instruction fetch\n");
info.si_signo = SIGBUS;
info.si_errno = 0;
info.si_code = TARGET_ILL_ILLOPN;
info._sifields._sigfault._addr = env->nip;
queue_signal(info.si_signo, &info);
break;
case EXCP_EXTERNAL: /* External interruption */
fprintf(stderr, "External access exeption\n");
cpu_ppc_dump_state(env, stderr, 0);
abort();
case EXCP_ALIGN: /* Alignment exception */
fprintf(stderr, "Alignment exception\n");
cpu_ppc_dump_state(env, stderr, 0);
abort();
case EXCP_PROGRAM: /* Program exception */
fprintf(stderr, "Program exception\n");
cpu_ppc_dump_state(env, stderr, 0);
abort();
break;
/* Trap */
case EXCP_TRAP: /* Trap */
case EXCP_TRACE: /* Trace exception (optional) */
info.si_signo = SIGTRAP;
info.si_errno = 0;
info.si_code = TARGET_ILL_ILLOPN;
info._sifields._sigfault._addr = env->nip;
queue_signal(info.si_signo, &info);
break;
/* Invalid instruction */
case EXCP_INVAL:
info.si_signo = SIGILL;
info.si_errno = 0;
info.si_code = TARGET_ILL_ILLOPN;
info._sifields._sigfault._addr = env->nip;
queue_signal(info.si_signo, &info);
break;
/* Privileged instruction */
case EXCP_PRIV: /* Privileged instruction */
info.si_signo = SIGILL;
info.si_errno = 0;
info.si_code = TARGET_ILL_ILLOPN;
info._sifields._sigfault._addr = env->nip;
queue_signal(info.si_signo, &info);
break;
case EXCP_NO_FP: /* No floating point */
case EXCP_DECR: /* Decrementer exception */
case EXCP_RESA: /* Implementation specific */
case EXCP_RESB: /* Implementation specific */
case EXCP_FP_ASSIST: /* Floating-point assist (optional) */
fprintf(stderr, "Misc expt...\n");
cpu_ppc_dump_state(env, stderr, 0);
abort();
case EXCP_SYSCALL:
{
uint32_t ret;
/* system call */
/* WARNING:
* PPC ABI uses overflow flag in cr0 to signal an error
* in syscalls.
*/
env->crf[0] &= ~0x1;
ret = do_syscall(env, env->gpr[0], env->gpr[3], env->gpr[4],
env->gpr[5], env->gpr[6], env->gpr[7],
env->gpr[8]);
if (ret > (uint32_t)(-515)) {
env->crf[0] |= 0x1;
ret = -ret;
}
env->gpr[3] = ret;
break;
}
default:
// error:
fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n",
trapnr);
cpu_ppc_dump_state(env, stderr, 0);
abort();
}
process_pending_signals(env);
}
}
#endif
void usage(void)
{
printf("qemu version " QEMU_VERSION ", Copyright (c) 2003 Fabrice Bellard\n"
"usage: qemu [-h] [-d] [-L path] [-s size] program [arguments...]\n"
printf("qemu-" TARGET_ARCH " version " QEMU_VERSION ", Copyright (c) 2003 Fabrice Bellard\n"
"usage: qemu-" TARGET_ARCH " [-h] [-d] [-L path] [-s size] program [arguments...]\n"
"Linux CPU emulator (compiled for %s emulation)\n"
"\n"
"-h print this help\n"
@@ -339,7 +586,9 @@ int main(int argc, char **argv)
if (argc <= 1)
usage();
loglevel = 0;
/* init debug */
cpu_set_log_filename(DEBUG_LOGFILE);
optind = 1;
for(;;) {
if (optind >= argc)
@@ -352,7 +601,7 @@ int main(int argc, char **argv)
if (!strcmp(r, "-")) {
break;
} else if (!strcmp(r, "d")) {
loglevel = 1;
cpu_set_log(CPU_LOG_ALL);
} else if (!strcmp(r, "s")) {
r = argv[optind++];
x86_stack_size = strtol(r, (char **)&r, 0);
@@ -379,16 +628,6 @@ int main(int argc, char **argv)
usage();
filename = argv[optind];
/* init debug */
if (loglevel) {
logfile = fopen(DEBUG_LOGFILE, "w");
if (!logfile) {
perror(DEBUG_LOGFILE);
_exit(1);
}
setvbuf(logfile, NULL, _IOLBF, 0);
}
/* Zero out regs */
memset(regs, 0, sizeof(struct target_pt_regs));
@@ -432,6 +671,10 @@ int main(int argc, char **argv)
env->user_mode_only = 1;
#if defined(TARGET_I386)
cpu_x86_set_cpl(env, 3);
env->cr[0] = CR0_PG_MASK | CR0_WP_MASK | CR0_PE_MASK;
/* linux register setup */
env->regs[R_EAX] = regs->eax;
env->regs[R_EBX] = regs->ebx;
@@ -492,6 +735,27 @@ int main(int argc, char **argv)
}
env->cpsr = regs->uregs[16];
}
#elif defined(TARGET_SPARC)
{
int i;
env->pc = regs->pc;
env->npc = regs->npc;
env->y = regs->y;
for(i = 0; i < 8; i++)
env->gregs[i] = regs->u_regs[i];
for(i = 0; i < 8; i++)
env->regwptr[i] = regs->u_regs[i + 8];
}
#elif defined(TARGET_PPC)
{
int i;
for (i = 0; i < 32; i++)
env->msr[i] = (regs->msr >> i) & 1;
env->nip = regs->nip;
for(i = 0; i < 32; i++) {
env->gpr[i] = regs->gpr[i];
}
}
#else
#error unsupported target CPU
#endif

129
linux-user/ppc/syscall.h Normal file
View File

@@ -0,0 +1,129 @@
/*
* PPC emulation for qemu: syscall definitions.
*
* Copyright (c) 2003 Jocelyn Mayer
*
* 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
*/
/* XXX: ABSOLUTELY BUGGY:
* for now, this is quite just a cut-and-paste from i386 target...
*/
/* default linux values for the selectors */
#define __USER_DS (1)
struct target_pt_regs {
unsigned long gpr[32];
unsigned long nip;
unsigned long msr;
unsigned long orig_gpr3; /* Used for restarting system calls */
unsigned long ctr;
unsigned long link;
unsigned long xer;
unsigned long ccr;
unsigned long mq; /* 601 only (not used at present) */
/* Used on APUS to hold IPL value. */
unsigned long trap; /* Reason for being here */
unsigned long dar; /* Fault registers */
unsigned long dsisr;
unsigned long result; /* Result of a system call */
};
/* ioctls */
struct target_revectored_struct {
target_ulong __map[8]; /* 256 bits */
};
/*
* flags masks
*/
/* ipcs */
#define TARGET_SEMOP 1
#define TARGET_SEMGET 2
#define TARGET_SEMCTL 3
#define TARGET_MSGSND 11
#define TARGET_MSGRCV 12
#define TARGET_MSGGET 13
#define TARGET_MSGCTL 14
#define TARGET_SHMAT 21
#define TARGET_SHMDT 22
#define TARGET_SHMGET 23
#define TARGET_SHMCTL 24
struct target_msgbuf {
int mtype;
char mtext[1];
};
struct target_ipc_kludge {
unsigned int msgp; /* Really (struct msgbuf *) */
int msgtyp;
};
struct target_ipc_perm {
int key;
unsigned short uid;
unsigned short gid;
unsigned short cuid;
unsigned short cgid;
unsigned short mode;
unsigned short seq;
};
struct target_msqid_ds {
struct target_ipc_perm msg_perm;
unsigned int msg_first; /* really struct target_msg* */
unsigned int msg_last; /* really struct target_msg* */
unsigned int msg_stime; /* really target_time_t */
unsigned int msg_rtime; /* really target_time_t */
unsigned int msg_ctime; /* really target_time_t */
unsigned int wwait; /* really struct wait_queue* */
unsigned int rwait; /* really struct wait_queue* */
unsigned short msg_cbytes;
unsigned short msg_qnum;
unsigned short msg_qbytes;
unsigned short msg_lspid;
unsigned short msg_lrpid;
};
struct target_shmid_ds {
struct target_ipc_perm shm_perm;
int shm_segsz;
unsigned int shm_atime; /* really target_time_t */
unsigned int shm_dtime; /* really target_time_t */
unsigned int shm_ctime; /* really target_time_t */
unsigned short shm_cpid;
unsigned short shm_lpid;
short shm_nattch;
unsigned short shm_npages;
unsigned long *shm_pages;
void *attaches; /* really struct shm_desc * */
};
#define TARGET_IPC_RMID 0
#define TARGET_IPC_SET 1
#define TARGET_IPC_STAT 2
union target_semun {
int val;
unsigned int buf; /* really struct semid_ds * */
unsigned int array; /* really unsigned short * */
unsigned int __buf; /* really struct seminfo * */
unsigned int __pad; /* really void* */
};

258
linux-user/ppc/syscall_nr.h Normal file
View File

@@ -0,0 +1,258 @@
/*
* This file contains the system call numbers.
*/
#define TARGET_NR_restart_syscall 0
#define TARGET_NR_exit 1
#define TARGET_NR_fork 2
#define TARGET_NR_read 3
#define TARGET_NR_write 4
#define TARGET_NR_open 5
#define TARGET_NR_close 6
#define TARGET_NR_waitpid 7
#define TARGET_NR_creat 8
#define TARGET_NR_link 9
#define TARGET_NR_unlink 10
#define TARGET_NR_execve 11
#define TARGET_NR_chdir 12
#define TARGET_NR_time 13
#define TARGET_NR_mknod 14
#define TARGET_NR_chmod 15
#define TARGET_NR_lchown32 16
#define TARGET_NR_break 17
#define TARGET_NR_oldstat 18
#define TARGET_NR_lseek 19
#define TARGET_NR_getpid 20
#define TARGET_NR_mount 21
#define TARGET_NR_umount 22
#define TARGET_NR_setuid32 23
#define TARGET_NR_getuid32 24
#define TARGET_NR_stime 25
#define TARGET_NR_ptrace 26
#define TARGET_NR_alarm 27
#define TARGET_NR_oldfstat 28
#define TARGET_NR_pause 29
#define TARGET_NR_utime 30
#define TARGET_NR_stty 31
#define TARGET_NR_gtty 32
#define TARGET_NR_access 33
#define TARGET_NR_nice 34
#define TARGET_NR_ftime 35
#define TARGET_NR_sync 36
#define TARGET_NR_kill 37
#define TARGET_NR_rename 38
#define TARGET_NR_mkdir 39
#define TARGET_NR_rmdir 40
#define TARGET_NR_dup 41
#define TARGET_NR_pipe 42
#define TARGET_NR_times 43
#define TARGET_NR_prof 44
#define TARGET_NR_brk 45
#define TARGET_NR_setgid32 46
#define TARGET_NR_getgid32 47
#define TARGET_NR_signal 48
#define TARGET_NR_geteuid32 49
#define TARGET_NR_getegid32 50
#define TARGET_NR_acct 51
#define TARGET_NR_umount2 52
#define TARGET_NR_lock 53
#define TARGET_NR_ioctl 54
#define TARGET_NR_fcntl 55
#define TARGET_NR_mpx 56
#define TARGET_NR_setpgid 57
#define TARGET_NR_ulimit 58
#define TARGET_NR_oldolduname 59
#define TARGET_NR_umask 60
#define TARGET_NR_chroot 61
#define TARGET_NR_ustat 62
#define TARGET_NR_dup2 63
#define TARGET_NR_getppid 64
#define TARGET_NR_getpgrp 65
#define TARGET_NR_setsid 66
#define TARGET_NR_sigaction 67
#define TARGET_NR_sgetmask 68
#define TARGET_NR_ssetmask 69
#define TARGET_NR_setreuid32 70
#define TARGET_NR_setregid32 71
#define TARGET_NR_sigsuspend 72
#define TARGET_NR_sigpending 73
#define TARGET_NR_sethostname 74
#define TARGET_NR_setrlimit 75
#define TARGET_NR_getrlimit 76
#define TARGET_NR_getrusage 77
#define TARGET_NR_gettimeofday 78
#define TARGET_NR_settimeofday 79
#define TARGET_NR_getgroups32 80
#define TARGET_NR_setgroups32 81
#define TARGET_NR_select 82
#define TARGET_NR_symlink 83
#define TARGET_NR_oldlstat 84
#define TARGET_NR_readlink 85
#define TARGET_NR_uselib 86
#define TARGET_NR_swapon 87
#define TARGET_NR_reboot 88
#define TARGET_NR_readdir 89
#define TARGET_NR_mmap 90
#define TARGET_NR_munmap 91
#define TARGET_NR_truncate 92
#define TARGET_NR_ftruncate 93
#define TARGET_NR_fchmod 94
#define TARGET_NR_fchown32 95
#define TARGET_NR_getpriority 96
#define TARGET_NR_setpriority 97
#define TARGET_NR_profil 98
#define TARGET_NR_statfs 99
#define TARGET_NR_fstatfs 100
#define TARGET_NR_ioperm 101
#define TARGET_NR_socketcall 102
#define TARGET_NR_syslog 103
#define TARGET_NR_setitimer 104
#define TARGET_NR_getitimer 105
#define TARGET_NR_stat 106
#define TARGET_NR_lstat 107
#define TARGET_NR_fstat 108
#define TARGET_NR_olduname 109
#define TARGET_NR_iopl 110
#define TARGET_NR_vhangup 111
#define TARGET_NR_idle 112
#define TARGET_NR_vm86 113
#define TARGET_NR_wait4 114
#define TARGET_NR_swapoff 115
#define TARGET_NR_sysinfo 116
#define TARGET_NR_ipc 117
#define TARGET_NR_fsync 118
#define TARGET_NR_sigreturn 119
#define TARGET_NR_clone 120
#define TARGET_NR_setdomainname 121
#define TARGET_NR_uname 122
#define TARGET_NR_modify_ldt 123
#define TARGET_NR_adjtimex 124
#define TARGET_NR_mprotect 125
#define TARGET_NR_sigprocmask 126
#define TARGET_NR_create_module 127
#define TARGET_NR_init_module 128
#define TARGET_NR_delete_module 129
#define TARGET_NR_get_kernel_syms 130
#define TARGET_NR_quotactl 131
#define TARGET_NR_getpgid 132
#define TARGET_NR_fchdir 133
#define TARGET_NR_bdflush 134
#define TARGET_NR_sysfs 135
#define TARGET_NR_personality 136
#define TARGET_NR_afs_syscall 137 /* Syscall for Andrew File System */
#define TARGET_NR_setfsuid32 138
#define TARGET_NR_setfsgid32 139
#define TARGET_NR__llseek 140
#define TARGET_NR_getdents 141
#define TARGET_NR__newselect 142
#define TARGET_NR_flock 143
#define TARGET_NR_msync 144
#define TARGET_NR_readv 145
#define TARGET_NR_writev 146
#define TARGET_NR_getsid 147
#define TARGET_NR_fdatasync 148
#define TARGET_NR__sysctl 149
#define TARGET_NR_mlock 150
#define TARGET_NR_munlock 151
#define TARGET_NR_mlockall 152
#define TARGET_NR_munlockall 153
#define TARGET_NR_sched_setparam 154
#define TARGET_NR_sched_getparam 155
#define TARGET_NR_sched_setscheduler 156
#define TARGET_NR_sched_getscheduler 157
#define TARGET_NR_sched_yield 158
#define TARGET_NR_sched_get_priority_max 159
#define TARGET_NR_sched_get_priority_min 160
#define TARGET_NR_sched_rr_get_interval 161
#define TARGET_NR_nanosleep 162
#define TARGET_NR_mremap 163
#define TARGET_NR_setresuid32 164
#define TARGET_NR_getresuid32 165
#define TARGET_NR_query_module 166
#define TARGET_NR_poll 167
#define TARGET_NR_nfsservctl 168
#define TARGET_NR_setresgid32 169
#define TARGET_NR_getresgid32 170
#define TARGET_NR_prctl 171
#define TARGET_NR_rt_sigreturn 172
#define TARGET_NR_rt_sigaction 173
#define TARGET_NR_rt_sigprocmask 174
#define TARGET_NR_rt_sigpending 175
#define TARGET_NR_rt_sigtimedwait 176
#define TARGET_NR_rt_sigqueueinfo 177
#define TARGET_NR_rt_sigsuspend 178
#define TARGET_NR_pread64 179
#define TARGET_NR_pwrite64 180
#define TARGET_NR_chown32 181
#define TARGET_NR_getcwd 182
#define TARGET_NR_capget 183
#define TARGET_NR_capset 184
#define TARGET_NR_sigaltstack 185
#define TARGET_NR_sendfile 186
#define TARGET_NR_getpmsg 187 /* some people actually want streams */
#define TARGET_NR_putpmsg 188 /* some people actually want streams */
#define TARGET_NR_vfork 189
#define TARGET_NR_ugetrlimit 190 /* SuS compliant getrlimit */
#define TARGET_NR_readahead 191
#define TARGET_NR_mmap2 192
#define TARGET_NR_truncate64 193
#define TARGET_NR_ftruncate64 194
#define TARGET_NR_stat64 195
#define TARGET_NR_lstat64 196
#define TARGET_NR_fstat64 197
#define TARGET_NR_pciconfig_read 198
#define TARGET_NR_pciconfig_write 199
#define TARGET_NR_pciconfig_iobase 200
#define TARGET_NR_multiplexer 201
#define TARGET_NR_getdents64 202
#define TARGET_NR_pivot_root 203
#define TARGET_NR_fcntl64 204
#define TARGET_NR_madvise 205
#define TARGET_NR_mincore 206
#define TARGET_NR_gettid 207
#define TARGET_NR_tkill 208
#define TARGET_NR_setxattr 209
#define TARGET_NR_lsetxattr 210
#define TARGET_NR_fsetxattr 211
#define TARGET_NR_getxattr 212
#define TARGET_NR_lgetxattr 213
#define TARGET_NR_fgetxattr 214
#define TARGET_NR_listxattr 215
#define TARGET_NR_llistxattr 216
#define TARGET_NR_flistxattr 217
#define TARGET_NR_removexattr 218
#define TARGET_NR_lremovexattr 219
#define TARGET_NR_fremovexattr 220
#define TARGET_NR_futex 221
#define TARGET_NR_sched_setaffinity 222
#define TARGET_NR_sched_getaffinity 223
/* 224 currently unused */
#define TARGET_NR_tuxcall 225
#define TARGET_NR_sendfile64 226
#define TARGET_NR_io_setup 227
#define TARGET_NR_io_destroy 228
#define TARGET_NR_io_getevents 229
#define TARGET_NR_io_submit 230
#define TARGET_NR_io_cancel 231
#define TARGET_NR_set_tid_address 232
#define TARGET_NR_fadvise64 233
#define TARGET_NR_exit_group 234
#define TARGET_NR_lookup_dcookie 235
#define TARGET_NR_epoll_create 236
#define TARGET_NR_epoll_ctl 237
#define TARGET_NR_epoll_wait 238
#define TARGET_NR_remap_file_pages 239
#define TARGET_NR_timer_create 240
#define TARGET_NR_timer_settime 241
#define TARGET_NR_timer_gettime 242
#define TARGET_NR_timer_getoverrun 243
#define TARGET_NR_timer_delete 244
#define TARGET_NR_clock_settime 245
#define TARGET_NR_clock_gettime 246
#define TARGET_NR_clock_getres 247
#define TARGET_NR_clock_nanosleep 248
#define TARGET_NR_swapcontext 249
#define TARGET_NR_tgkill 250
#define TARGET_NR_utimes 251
#define TARGET_NR_statfs64 252
#define TARGET_NR_fstatfs64 253
#define TARGET_NR_fadvise64_64 254

235
linux-user/ppc/termbits.h Normal file
View File

@@ -0,0 +1,235 @@
/* from asm/termbits.h */
#define TARGET_NCCS 19
struct target_termios {
unsigned int c_iflag; /* input mode flags */
unsigned int c_oflag; /* output mode flags */
unsigned int c_cflag; /* control mode flags */
unsigned int c_lflag; /* local mode flags */
unsigned char c_line; /* line discipline */
unsigned char c_cc[TARGET_NCCS]; /* control characters */
unsigned int c_ispeed; /* input speed */
unsigned int c_ospeed; /* output speed */
};
/* c_cc character offsets */
#define TARGET_VINTR 0
#define TARGET_VQUIT 1
#define TARGET_VERASE 2
#define TARGET_VKILL 3
#define TARGET_VEOF 4
#define TARGET_VMIN 5
#define TARGET_VEOL 6
#define TARGET_VTIME 7
#define TARGET_VEOL2 8
#define TARGET_VSWTC 9
#define TARGET_VWERASE 10
#define TARGET_VREPRINT 11
#define TARGET_VSUSP 12
#define TARGET_VSTART 13
#define TARGET_VSTOP 14
#define TARGET_VLNEXT 15
#define TARGET_VDISCARD 16
#define TARGET_IGNBRK 0000001
#define TARGET_BRKINT 0000002
#define TARGET_IGNPAR 0000004
#define TARGET_PARMRK 0000010
#define TARGET_INPCK 0000020
#define TARGET_ISTRIP 0000040
#define TARGET_INLCR 0000100
#define TARGET_IGNCR 0000200
#define TARGET_ICRNL 0000400
#define TARGET_IXON 0001000
#define TARGET_IXOFF 0002000
#define TARGET_IXANY 0004000
#define TARGET_IUCLC 0010000
#define TARGET_IMAXBEL 0020000
/* c_oflag bits */
#define TARGET_OPOST 0000001
#define TARGET_ONLCR 0000002
#define TARGET_OLCUC 0000004
#define TARGET_OCRNL 0000010
#define TARGET_ONOCR 0000020
#define TARGET_ONLRET 0000040
#define TARGET_OFILL 00000100
#define TARGET_OFDEL 00000200
#define TARGET_NLDLY 00001400
#define TARGET_NL0 00000000
#define TARGET_NL1 00000400
#define TARGET_NL2 00001000
#define TARGET_NL3 00001400
#define TARGET_TABDLY 00006000
#define TARGET_TAB0 00000000
#define TARGET_TAB1 00002000
#define TARGET_TAB2 00004000
#define TARGET_TAB3 00006000
#define TARGET_CRDLY 00030000
#define TARGET_CR0 00000000
#define TARGET_CR1 00010000
#define TARGET_CR2 00020000
#define TARGET_CR3 00030000
#define TARGET_FFDLY 00040000
#define TARGET_FF0 00000000
#define TARGET_FF1 00040000
#define TARGET_BSDLY 00100000
#define TARGET_BS0 00000000
#define TARGET_BS1 00100000
#define TARGET_VTDLY 00200000
#define TARGET_VT0 00000000
#define TARGET_VT1 00200000
#define TARGET_XTABS 01000000 /* Hmm.. Linux/i386 considers this part of TABDLY.. */
/* c_cflag bit meaning */
#define TARGET_CBAUD 0000377
#define TARGET_B0 0000000 /* hang up */
#define TARGET_B50 0000001
#define TARGET_B75 0000002
#define TARGET_B110 0000003
#define TARGET_B134 0000004
#define TARGET_B150 0000005
#define TARGET_B200 0000006
#define TARGET_B300 0000007
#define TARGET_B600 0000010
#define TARGET_B1200 0000011
#define TARGET_B1800 0000012
#define TARGET_B2400 0000013
#define TARGET_B4800 0000014
#define TARGET_B9600 0000015
#define TARGET_B19200 0000016
#define TARGET_B38400 0000017
#define TARGET_EXTA B19200
#define TARGET_EXTB B38400
#define TARGET_CBAUDEX 0000000
#define TARGET_B57600 00020
#define TARGET_B115200 00021
#define TARGET_B230400 00022
#define TARGET_B460800 00023
#define TARGET_B500000 00024
#define TARGET_B576000 00025
#define TARGET_B921600 00026
#define TARGET_B1000000 00027
#define TARGET_B1152000 00030
#define TARGET_B1500000 00031
#define TARGET_B2000000 00032
#define TARGET_B2500000 00033
#define TARGET_B3000000 00034
#define TARGET_B3500000 00035
#define TARGET_B4000000 00036
#define TARGET_CSIZE 00001400
#define TARGET_CS5 00000000
#define TARGET_CS6 00000400
#define TARGET_CS7 00001000
#define TARGET_CS8 00001400
#define TARGET_CSTOPB 00002000
#define TARGET_CREAD 00004000
#define TARGET_PARENB 00010000
#define TARGET_PARODD 00020000
#define TARGET_HUPCL 00040000
#define TARGET_CLOCAL 00100000
#define TARGET_CRTSCTS 020000000000 /* flow control */
/* c_lflag bits */
#define TARGET_ISIG 0x00000080
#define TARGET_ICANON 0x00000100
#define TARGET_XCASE 0x00004000
#define TARGET_ECHO 0x00000008
#define TARGET_ECHOE 0x00000002
#define TARGET_ECHOK 0x00000004
#define TARGET_ECHONL 0x00000010
#define TARGET_NOFLSH 0x80000000
#define TARGET_TOSTOP 0x00400000
#define TARGET_ECHOCTL 0x00000040
#define TARGET_ECHOPRT 0x00000020
#define TARGET_ECHOKE 0x00000001
#define TARGET_FLUSHO 0x00800000
#define TARGET_PENDIN 0x20000000
#define TARGET_IEXTEN 0x00000400
/* ioctls */
#define TARGET_FIOCLEX TARGET_IO('f', 1)
#define TARGET_FIONCLEX TARGET_IO('f', 2)
#define TARGET_FIOASYNC TARGET_IOW('f', 125, int)
#define TARGET_FIONBIO TARGET_IOW('f', 126, int)
#define TARGET_FIONREAD TARGET_IOR('f', 127, int)
#define TARGET_TIOCINQ TARGET_FIONREAD
//#define TARGET_FIOQSIZE TARGET_IOR('f', 128, loff_t)
#define TARGET_TCGETS TARGET_IOR('t', 19, struct target_termios)
#define TARGET_TCSETS TARGET_IOW('t', 20, struct target_termios)
#define TARGET_TCSETSW TARGET_IOW('t', 21, struct target_termios)
#define TARGET_TCSETSF TARGET_IOW('t', 22, struct target_termios)
#define TARGET_TCGETA TARGET_IOR('t', 23, struct target_termio)
#define TARGET_TCSETA TARGET_IOW('t', 24, struct target_termio)
#define TARGET_TCSETAW TARGET_IOW('t', 25, struct target_termio)
#define TARGET_TCSETAF TARGET_IOW('t', 28, struct target_termio)
#define TARGET_TCSBRK TARGET_IO('t', 29)
#define TARGET_TCXONC TARGET_IO('t', 30)
#define TARGET_TCFLSH TARGET_IO('t', 31)
#define TARGET_TIOCSWINSZ TARGET_IOW('t', 103, struct target_winsize)
#define TARGET_TIOCGWINSZ TARGET_IOR('t', 104, struct target_winsize)
#define TARGET_TIOCSTART TARGET_IO('t', 110) /* start output, like ^Q */
#define TARGET_TIOCSTOP TARGET_IO('t', 111) /* stop output, like ^S */
#define TARGET_TIOCOUTQ TARGET_IOR('t', 115, int) /* output queue size */
#define TARGET_TIOCGLTC TARGET_IOR('t', 116, struct target_ltchars)
#define TARGET_TIOCSLTC TARGET_IOW('t', 117, struct target_ltchars)
#define TARGET_TIOCSPGRP TARGET_IOW('t', 118, int)
#define TARGET_TIOCGPGRP TARGET_IOR('t', 119, int)
#define TARGET_TIOCEXCL 0x540C
#define TARGET_TIOCNXCL 0x540D
#define TARGET_TIOCSCTTY 0x540E
#define TARGET_TIOCSTI 0x5412
#define TARGET_TIOCMGET 0x5415
#define TARGET_TIOCMBIS 0x5416
#define TARGET_TIOCMBIC 0x5417
#define TARGET_TIOCMSET 0x5418
#define TARGET_TIOCGSOFTCAR 0x5419
#define TARGET_TIOCSSOFTCAR 0x541A
#define TARGET_TIOCLINUX 0x541C
#define TARGET_TIOCCONS 0x541D
#define TARGET_TIOCGSERIAL 0x541E
#define TARGET_TIOCSSERIAL 0x541F
#define TARGET_TIOCPKT 0x5420
#define TARGET_TIOCNOTTY 0x5422
#define TARGET_TIOCSETD 0x5423
#define TARGET_TIOCGETD 0x5424
#define TARGET_TCSBRKP 0x5425 /* Needed for POSIX tcsendbreak() */
#define TARGET_TIOCTTYGSTRUCT 0x5426 /* For debugging only */
#define TARGET_TIOCSBRK 0x5427 /* BSD compatibility */
#define TARGET_TIOCCBRK 0x5428 /* BSD compatibility */
#define TARGET_TIOCGSID 0x5429 /* Return the session ID of FD */
#define TARGET_TIOCGPTN TARGET_IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */
#define TARGET_TIOCSPTLCK TARGET_IOW('T',0x31, int) /* Lock/unlock Pty */
#define TARGET_TIOCSERCONFIG 0x5453
#define TARGET_TIOCSERGWILD 0x5454
#define TARGET_TIOCSERSWILD 0x5455
#define TARGET_TIOCGLCKTRMIOS 0x5456
#define TARGET_TIOCSLCKTRMIOS 0x5457
#define TARGET_TIOCSERGSTRUCT 0x5458 /* For debugging only */
#define TARGET_TIOCSERGETLSR 0x5459 /* Get line status register */
/* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */
# define TARGET_TIOCSER_TEMT 0x01 /* Transmitter physically empty */
#define TARGET_TIOCSERGETMULTI 0x545A /* Get multiport config */
#define TARGET_TIOCSERSETMULTI 0x545B /* Set multiport config */
#define TARGET_TIOCMIWAIT 0x545C /* wait for a change on serial input line(s) */
#define TARGET_TIOCGICOUNT 0x545D /* read serial port inline interrupt counts */

View File

@@ -6,15 +6,8 @@
#include <signal.h>
#include "syscall_defs.h"
#if defined(TARGET_I386)
#include "cpu-i386.h"
#include "syscall-i386.h"
#elif defined(TARGET_ARM)
#include "cpu-arm.h"
#include "syscall-arm.h"
#else
#error unsupported target CPU
#endif
#include "cpu.h"
#include "syscall.h"
/* This struct is used to hold certain information about the image.
* Basically, it replicates in user space what would be certain

View File

@@ -60,44 +60,122 @@ static int signal_pending; /* non zero if a signal may be pending */
static void host_signal_handler(int host_signum, siginfo_t *info,
void *puc);
/* XXX: do it properly */
static uint8_t host_to_target_signal_table[65] = {
[SIGHUP] = TARGET_SIGHUP,
[SIGINT] = TARGET_SIGINT,
[SIGQUIT] = TARGET_SIGQUIT,
[SIGILL] = TARGET_SIGILL,
[SIGTRAP] = TARGET_SIGTRAP,
[SIGABRT] = TARGET_SIGABRT,
/* [SIGIOT] = TARGET_SIGIOT,*/
[SIGBUS] = TARGET_SIGBUS,
[SIGFPE] = TARGET_SIGFPE,
[SIGKILL] = TARGET_SIGKILL,
[SIGUSR1] = TARGET_SIGUSR1,
[SIGSEGV] = TARGET_SIGSEGV,
[SIGUSR2] = TARGET_SIGUSR2,
[SIGPIPE] = TARGET_SIGPIPE,
[SIGALRM] = TARGET_SIGALRM,
[SIGTERM] = TARGET_SIGTERM,
#ifdef SIGSTKFLT
[SIGSTKFLT] = TARGET_SIGSTKFLT,
#endif
[SIGCHLD] = TARGET_SIGCHLD,
[SIGCONT] = TARGET_SIGCONT,
[SIGSTOP] = TARGET_SIGSTOP,
[SIGTSTP] = TARGET_SIGTSTP,
[SIGTTIN] = TARGET_SIGTTIN,
[SIGTTOU] = TARGET_SIGTTOU,
[SIGURG] = TARGET_SIGURG,
[SIGXCPU] = TARGET_SIGXCPU,
[SIGXFSZ] = TARGET_SIGXFSZ,
[SIGVTALRM] = TARGET_SIGVTALRM,
[SIGPROF] = TARGET_SIGPROF,
[SIGWINCH] = TARGET_SIGWINCH,
[SIGIO] = TARGET_SIGIO,
[SIGPWR] = TARGET_SIGPWR,
[SIGSYS] = TARGET_SIGSYS,
/* next signals stay the same */
};
static uint8_t target_to_host_signal_table[65];
static inline int host_to_target_signal(int sig)
{
return sig;
return host_to_target_signal_table[sig];
}
static inline int target_to_host_signal(int sig)
{
return sig;
return target_to_host_signal_table[sig];
}
void host_to_target_sigset(target_sigset_t *d, sigset_t *s)
void host_to_target_sigset(target_sigset_t *d, const sigset_t *s)
{
int i;
for(i = 0;i < TARGET_NSIG_WORDS; i++) {
unsigned long sigmask;
uint32_t target_sigmask;
sigmask = ((unsigned long *)s)[0];
target_sigmask = 0;
for(i = 0; i < 32; i++) {
if (sigmask & (1 << i))
target_sigmask |= 1 << (host_to_target_signal(i + 1) - 1);
}
#if TARGET_LONG_BITS == 32 && HOST_LONG_BITS == 32
d->sig[0] = tswapl(target_sigmask);
for(i = 1;i < TARGET_NSIG_WORDS; i++) {
d->sig[i] = tswapl(((unsigned long *)s)[i]);
}
#elif TARGET_LONG_BITS == 32 && HOST_LONG_BITS == 64 && TARGET_NSIG_WORDS == 2
d->sig[0] = tswapl(target_sigmask);
d->sig[1] = tswapl(sigmask >> 32);
#else
#error host_to_target_sigset
#endif
}
void target_to_host_sigset(sigset_t *d, target_sigset_t *s)
void target_to_host_sigset(sigset_t *d, const target_sigset_t *s)
{
int i;
for(i = 0;i < TARGET_NSIG_WORDS; i++) {
unsigned long sigmask;
target_ulong target_sigmask;
target_sigmask = tswapl(s->sig[0]);
sigmask = 0;
for(i = 0; i < 32; i++) {
if (target_sigmask & (1 << i))
sigmask |= 1 << (target_to_host_signal(i + 1) - 1);
}
#if TARGET_LONG_BITS == 32 && HOST_LONG_BITS == 32
((unsigned long *)d)[0] = sigmask;
for(i = 1;i < TARGET_NSIG_WORDS; i++) {
((unsigned long *)d)[i] = tswapl(s->sig[i]);
}
#elif TARGET_LONG_BITS == 32 && HOST_LONG_BITS == 64 && TARGET_NSIG_WORDS == 2
((unsigned long *)d)[0] = sigmask | ((unsigned long)tswapl(s->sig[1]) << 32);
#else
#error target_to_host_sigset
#endif /* TARGET_LONG_BITS */
}
void host_to_target_old_sigset(target_ulong *old_sigset,
const sigset_t *sigset)
{
*old_sigset = tswap32(*(unsigned long *)sigset & 0xffffffff);
target_sigset_t d;
host_to_target_sigset(&d, sigset);
*old_sigset = d.sig[0];
}
void target_to_host_old_sigset(sigset_t *sigset,
const target_ulong *old_sigset)
{
sigemptyset(sigset);
*(unsigned long *)sigset = tswapl(*old_sigset);
target_sigset_t d;
int i;
d.sig[0] = *old_sigset;
for(i = 1;i < TARGET_NSIG_WORDS; i++)
d.sig[i] = 0;
target_to_host_sigset(sigset, &d);
}
/* siginfo conversion */
@@ -167,8 +245,18 @@ void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo)
void signal_init(void)
{
struct sigaction act;
int i;
int i, j;
/* generate signal conversion tables */
for(i = 1; i <= 64; i++) {
if (host_to_target_signal_table[i] == 0)
host_to_target_signal_table[i] = i;
}
for(i = 1; i <= 64; i++) {
j = host_to_target_signal_table[i];
target_to_host_signal_table[j] = i;
}
/* set all host signal handlers. ALL signals are blocked during
the handlers to serialize them. */
sigfillset(&act.sa_mask);
@@ -333,7 +421,7 @@ static void host_signal_handler(int host_signum, siginfo_t *info,
host_to_target_siginfo_noswap(&tinfo, info);
if (queue_signal(sig, &tinfo) == 1) {
/* interrupt the virtual CPU as soon as possible */
cpu_interrupt(global_env);
cpu_interrupt(global_env, CPU_INTERRUPT_EXIT);
}
}
@@ -364,6 +452,80 @@ int do_sigaction(int sig, const struct target_sigaction *act,
return 0;
}
#define __put_user(x,ptr)\
({\
int size = sizeof(*ptr);\
switch(size) {\
case 1:\
stb(ptr, (typeof(*ptr))(x));\
break;\
case 2:\
stw(ptr, (typeof(*ptr))(x));\
break;\
case 4:\
stl(ptr, (typeof(*ptr))(x));\
break;\
case 8:\
stq(ptr, (typeof(*ptr))(x));\
break;\
default:\
abort();\
}\
0;\
})
#define __get_user(x, ptr) \
({\
int size = sizeof(*ptr);\
switch(size) {\
case 1:\
x = (typeof(*ptr))ldub(ptr);\
break;\
case 2:\
x = (typeof(*ptr))lduw(ptr);\
break;\
case 4:\
x = (typeof(*ptr))ldl(ptr);\
break;\
case 8:\
x = (typeof(*ptr))ldq(ptr);\
break;\
default:\
abort();\
}\
0;\
})
#define __copy_to_user(dst, src, size)\
({\
memcpy(dst, src, size);\
0;\
})
#define __copy_from_user(dst, src, size)\
({\
memcpy(dst, src, size);\
0;\
})
#define __clear_user(dst, size)\
({\
memset(dst, 0, size);\
0;\
})
#ifndef offsetof
#define offsetof(type, field) ((size_t) &((type *)0)->field)
#endif
static inline int copy_siginfo_to_user(target_siginfo_t *tinfo,
const target_siginfo_t *info)
{
tswap_siginfo(tinfo, info);
return 0;
}
#ifdef TARGET_I386
/* from the Linux kernel */
@@ -472,44 +634,6 @@ struct rt_sigframe
* Set up a signal frame.
*/
#define __put_user(x,ptr)\
({\
int size = sizeof(*ptr);\
switch(size) {\
case 1:\
stb(ptr, (typeof(*ptr))(x));\
break;\
case 2:\
stw(ptr, (typeof(*ptr))(x));\
break;\
case 4:\
stl(ptr, (typeof(*ptr))(x));\
break;\
case 8:\
stq(ptr, (typeof(*ptr))(x));\
break;\
default:\
abort();\
}\
0;\
})
#define get_user(val, ptr) (typeof(*ptr))(*(ptr))
#define __copy_to_user(dst, src, size)\
({\
memcpy(dst, src, size);\
0;\
})
static inline int copy_siginfo_to_user(target_siginfo_t *tinfo,
const target_siginfo_t *info)
{
tswap_siginfo(tinfo, info);
return 0;
}
/* XXX: save x87 state */
static int
setup_sigcontext(struct target_sigcontext *sc, struct target_fpstate *fpstate,
@@ -825,6 +949,377 @@ badframe:
return 0;
}
#elif defined(TARGET_ARM)
struct target_sigcontext {
target_ulong trap_no;
target_ulong error_code;
target_ulong oldmask;
target_ulong arm_r0;
target_ulong arm_r1;
target_ulong arm_r2;
target_ulong arm_r3;
target_ulong arm_r4;
target_ulong arm_r5;
target_ulong arm_r6;
target_ulong arm_r7;
target_ulong arm_r8;
target_ulong arm_r9;
target_ulong arm_r10;
target_ulong arm_fp;
target_ulong arm_ip;
target_ulong arm_sp;
target_ulong arm_lr;
target_ulong arm_pc;
target_ulong arm_cpsr;
target_ulong fault_address;
};
typedef struct target_sigaltstack {
target_ulong ss_sp;
int ss_flags;
target_ulong ss_size;
} target_stack_t;
struct target_ucontext {
target_ulong uc_flags;
target_ulong uc_link;
target_stack_t uc_stack;
struct target_sigcontext uc_mcontext;
target_sigset_t uc_sigmask; /* mask last for extensibility */
};
struct sigframe
{
struct target_sigcontext sc;
target_ulong extramask[TARGET_NSIG_WORDS-1];
target_ulong retcode;
};
struct rt_sigframe
{
struct target_siginfo *pinfo;
void *puc;
struct target_siginfo info;
struct target_ucontext uc;
target_ulong retcode;
};
#define TARGET_CONFIG_CPU_32 1
/*
* For ARM syscalls, we encode the syscall number into the instruction.
*/
#define SWI_SYS_SIGRETURN (0xef000000|(TARGET_NR_sigreturn + ARM_SYSCALL_BASE))
#define SWI_SYS_RT_SIGRETURN (0xef000000|(TARGET_NR_rt_sigreturn + ARM_SYSCALL_BASE))
/*
* For Thumb syscalls, we pass the syscall number via r7. We therefore
* need two 16-bit instructions.
*/
#define SWI_THUMB_SIGRETURN (0xdf00 << 16 | 0x2700 | (TARGET_NR_sigreturn))
#define SWI_THUMB_RT_SIGRETURN (0xdf00 << 16 | 0x2700 | (TARGET_NR_rt_sigreturn))
static const target_ulong retcodes[4] = {
SWI_SYS_SIGRETURN, SWI_THUMB_SIGRETURN,
SWI_SYS_RT_SIGRETURN, SWI_THUMB_RT_SIGRETURN
};
#define __put_user_error(x,p,e) __put_user(x, p)
#define __get_user_error(x,p,e) __get_user(x, p)
static inline int valid_user_regs(CPUState *regs)
{
return 1;
}
static int
setup_sigcontext(struct target_sigcontext *sc, /*struct _fpstate *fpstate,*/
CPUState *env, unsigned long mask)
{
int err = 0;
__put_user_error(env->regs[0], &sc->arm_r0, err);
__put_user_error(env->regs[1], &sc->arm_r1, err);
__put_user_error(env->regs[2], &sc->arm_r2, err);
__put_user_error(env->regs[3], &sc->arm_r3, err);
__put_user_error(env->regs[4], &sc->arm_r4, err);
__put_user_error(env->regs[5], &sc->arm_r5, err);
__put_user_error(env->regs[6], &sc->arm_r6, err);
__put_user_error(env->regs[7], &sc->arm_r7, err);
__put_user_error(env->regs[8], &sc->arm_r8, err);
__put_user_error(env->regs[9], &sc->arm_r9, err);
__put_user_error(env->regs[10], &sc->arm_r10, err);
__put_user_error(env->regs[11], &sc->arm_fp, err);
__put_user_error(env->regs[12], &sc->arm_ip, err);
__put_user_error(env->regs[13], &sc->arm_sp, err);
__put_user_error(env->regs[14], &sc->arm_lr, err);
__put_user_error(env->regs[15], &sc->arm_pc, err);
#ifdef TARGET_CONFIG_CPU_32
__put_user_error(env->cpsr, &sc->arm_cpsr, err);
#endif
__put_user_error(/* current->thread.trap_no */ 0, &sc->trap_no, err);
__put_user_error(/* current->thread.error_code */ 0, &sc->error_code, err);
__put_user_error(/* current->thread.address */ 0, &sc->fault_address, err);
__put_user_error(mask, &sc->oldmask, err);
return err;
}
static inline void *
get_sigframe(struct emulated_sigaction *ka, CPUState *regs, int framesize)
{
unsigned long sp = regs->regs[13];
#if 0
/*
* This is the X/Open sanctioned signal stack switching.
*/
if ((ka->sa.sa_flags & SA_ONSTACK) && !sas_ss_flags(sp))
sp = current->sas_ss_sp + current->sas_ss_size;
#endif
/*
* ATPCS B01 mandates 8-byte alignment
*/
return (void *)((sp - framesize) & ~7);
}
static int
setup_return(CPUState *env, struct emulated_sigaction *ka,
target_ulong *rc, void *frame, int usig)
{
target_ulong handler = (target_ulong)ka->sa._sa_handler;
target_ulong retcode;
int thumb = 0;
#if defined(TARGET_CONFIG_CPU_32)
target_ulong cpsr = env->cpsr;
#if 0
/*
* Maybe we need to deliver a 32-bit signal to a 26-bit task.
*/
if (ka->sa.sa_flags & SA_THIRTYTWO)
cpsr = (cpsr & ~MODE_MASK) | USR_MODE;
#ifdef CONFIG_ARM_THUMB
if (elf_hwcap & HWCAP_THUMB) {
/*
* The LSB of the handler determines if we're going to
* be using THUMB or ARM mode for this signal handler.
*/
thumb = handler & 1;
if (thumb)
cpsr |= T_BIT;
else
cpsr &= ~T_BIT;
}
#endif
#endif
#endif /* TARGET_CONFIG_CPU_32 */
if (ka->sa.sa_flags & TARGET_SA_RESTORER) {
retcode = (target_ulong)ka->sa.sa_restorer;
} else {
unsigned int idx = thumb;
if (ka->sa.sa_flags & TARGET_SA_SIGINFO)
idx += 2;
if (__put_user(retcodes[idx], rc))
return 1;
#if 0
flush_icache_range((target_ulong)rc,
(target_ulong)(rc + 1));
#endif
retcode = ((target_ulong)rc) + thumb;
}
env->regs[0] = usig;
env->regs[13] = (target_ulong)frame;
env->regs[14] = retcode;
env->regs[15] = handler & (thumb ? ~1 : ~3);
#ifdef TARGET_CONFIG_CPU_32
env->cpsr = cpsr;
#endif
return 0;
}
static void setup_frame(int usig, struct emulated_sigaction *ka,
target_sigset_t *set, CPUState *regs)
{
struct sigframe *frame = get_sigframe(ka, regs, sizeof(*frame));
int err = 0;
err |= setup_sigcontext(&frame->sc, /*&frame->fpstate,*/ regs, set->sig[0]);
if (TARGET_NSIG_WORDS > 1) {
err |= __copy_to_user(frame->extramask, &set->sig[1],
sizeof(frame->extramask));
}
if (err == 0)
err = setup_return(regs, ka, &frame->retcode, frame, usig);
// return err;
}
static void setup_rt_frame(int usig, struct emulated_sigaction *ka,
target_siginfo_t *info,
target_sigset_t *set, CPUState *env)
{
struct rt_sigframe *frame = get_sigframe(ka, env, sizeof(*frame));
int err = 0;
#if 0
if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame)))
return 1;
#endif
__put_user_error(&frame->info, (target_ulong *)&frame->pinfo, err);
__put_user_error(&frame->uc, (target_ulong *)&frame->puc, err);
err |= copy_siginfo_to_user(&frame->info, info);
/* Clear all the bits of the ucontext we don't use. */
err |= __clear_user(&frame->uc, offsetof(struct ucontext, uc_mcontext));
err |= setup_sigcontext(&frame->uc.uc_mcontext, /*&frame->fpstate,*/
env, set->sig[0]);
err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
if (err == 0)
err = setup_return(env, ka, &frame->retcode, frame, usig);
if (err == 0) {
/*
* For realtime signals we must also set the second and third
* arguments for the signal handler.
* -- Peter Maydell <pmaydell@chiark.greenend.org.uk> 2000-12-06
*/
env->regs[1] = (target_ulong)frame->pinfo;
env->regs[2] = (target_ulong)frame->puc;
}
// return err;
}
static int
restore_sigcontext(CPUState *env, struct target_sigcontext *sc)
{
int err = 0;
__get_user_error(env->regs[0], &sc->arm_r0, err);
__get_user_error(env->regs[1], &sc->arm_r1, err);
__get_user_error(env->regs[2], &sc->arm_r2, err);
__get_user_error(env->regs[3], &sc->arm_r3, err);
__get_user_error(env->regs[4], &sc->arm_r4, err);
__get_user_error(env->regs[5], &sc->arm_r5, err);
__get_user_error(env->regs[6], &sc->arm_r6, err);
__get_user_error(env->regs[7], &sc->arm_r7, err);
__get_user_error(env->regs[8], &sc->arm_r8, err);
__get_user_error(env->regs[9], &sc->arm_r9, err);
__get_user_error(env->regs[10], &sc->arm_r10, err);
__get_user_error(env->regs[11], &sc->arm_fp, err);
__get_user_error(env->regs[12], &sc->arm_ip, err);
__get_user_error(env->regs[13], &sc->arm_sp, err);
__get_user_error(env->regs[14], &sc->arm_lr, err);
__get_user_error(env->regs[15], &sc->arm_pc, err);
#ifdef TARGET_CONFIG_CPU_32
__get_user_error(env->cpsr, &sc->arm_cpsr, err);
#endif
err |= !valid_user_regs(env);
return err;
}
long do_sigreturn(CPUState *env)
{
struct sigframe *frame;
target_sigset_t set;
sigset_t host_set;
/*
* Since we stacked the signal on a 64-bit boundary,
* then 'sp' should be word aligned here. If it's
* not, then the user is trying to mess with us.
*/
if (env->regs[13] & 7)
goto badframe;
frame = (struct sigframe *)env->regs[13];
#if 0
if (verify_area(VERIFY_READ, frame, sizeof (*frame)))
goto badframe;
#endif
if (__get_user(set.sig[0], &frame->sc.oldmask)
|| (TARGET_NSIG_WORDS > 1
&& __copy_from_user(&set.sig[1], &frame->extramask,
sizeof(frame->extramask))))
goto badframe;
target_to_host_sigset(&host_set, &set);
sigprocmask(SIG_SETMASK, &host_set, NULL);
if (restore_sigcontext(env, &frame->sc))
goto badframe;
#if 0
/* Send SIGTRAP if we're single-stepping */
if (ptrace_cancel_bpt(current))
send_sig(SIGTRAP, current, 1);
#endif
return env->regs[0];
badframe:
force_sig(SIGSEGV /* , current */);
return 0;
}
long do_rt_sigreturn(CPUState *env)
{
struct rt_sigframe *frame;
target_sigset_t set;
sigset_t host_set;
/*
* Since we stacked the signal on a 64-bit boundary,
* then 'sp' should be word aligned here. If it's
* not, then the user is trying to mess with us.
*/
if (env->regs[13] & 7)
goto badframe;
frame = (struct rt_sigframe *)env->regs[13];
#if 0
if (verify_area(VERIFY_READ, frame, sizeof (*frame)))
goto badframe;
#endif
if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
goto badframe;
target_to_host_sigset(&host_set, &set);
sigprocmask(SIG_SETMASK, &host_set, NULL);
if (restore_sigcontext(env, &frame->uc.uc_mcontext))
goto badframe;
#if 0
/* Send SIGTRAP if we're single-stepping */
if (ptrace_cancel_bpt(current))
send_sig(SIGTRAP, current, 1);
#endif
return env->regs[0];
badframe:
force_sig(SIGSEGV /* , current */);
return 0;
}
#else
static void setup_frame(int sig, struct emulated_sigaction *ka,

View File

@@ -0,0 +1,7 @@
struct target_pt_regs {
target_ulong psr;
target_ulong pc;
target_ulong npc;
target_ulong y;
target_ulong u_regs[16];
};

View File

@@ -0,0 +1,220 @@
#define TARGET_NR_exit 1 /* Common */
#define TARGET_NR_fork 2 /* Common */
#define TARGET_NR_read 3 /* Common */
#define TARGET_NR_write 4 /* Common */
#define TARGET_NR_open 5 /* Common */
#define TARGET_NR_close 6 /* Common */
#define TARGET_NR_wait4 7 /* Common */
#define TARGET_NR_creat 8 /* Common */
#define TARGET_NR_link 9 /* Common */
#define TARGET_NR_unlink 10 /* Common */
#define TARGET_NR_execv 11 /* SunOS Specific */
#define TARGET_NR_chdir 12 /* Common */
#define TARGET_NR_chown 13 /* Common */
#define TARGET_NR_mknod 14 /* Common */
#define TARGET_NR_chmod 15 /* Common */
#define TARGET_NR_lchown 16 /* Common */
#define TARGET_NR_brk 17 /* Common */
#define TARGET_NR_perfctr 18 /* Performance counter operations */
#define TARGET_NR_lseek 19 /* Common */
#define TARGET_NR_getpid 20 /* Common */
#define TARGET_NR_capget 21 /* Linux Specific */
#define TARGET_NR_capset 22 /* Linux Specific */
#define TARGET_NR_setuid 23 /* Implemented via setreuid in SunOS */
#define TARGET_NR_getuid 24 /* Common */
#define TARGET_NR_ptrace 26 /* Common */
#define TARGET_NR_alarm 27 /* Implemented via setitimer in SunOS */
#define TARGET_NR_sigaltstack 28 /* Common */
#define TARGET_NR_pause 29 /* Is sigblock(0)->sigpause() in SunOS */
#define TARGET_NR_utime 30 /* Implemented via utimes() under SunOS */
#define TARGET_NR_lchown32 31 /* Linux sparc32 specific */
#define TARGET_NR_fchown32 32 /* Linux sparc32 specific */
#define TARGET_NR_access 33 /* Common */
#define TARGET_NR_nice 34 /* Implemented via get/setpriority() in SunOS */
#define TARGET_NR_chown32 35 /* Linux sparc32 specific */
#define TARGET_NR_sync 36 /* Common */
#define TARGET_NR_kill 37 /* Common */
#define TARGET_NR_stat 38 /* Common */
#define TARGET_NR_sendfile 39 /* Linux Specific */
#define TARGET_NR_lstat 40 /* Common */
#define TARGET_NR_dup 41 /* Common */
#define TARGET_NR_pipe 42 /* Common */
#define TARGET_NR_times 43 /* Implemented via getrusage() in SunOS */
#define TARGET_NR_getuid32 44 /* Linux sparc32 specific */
#define TARGET_NR_umount2 45 /* Linux Specific */
#define TARGET_NR_setgid 46 /* Implemented via setregid() in SunOS */
#define TARGET_NR_getgid 47 /* Common */
#define TARGET_NR_signal 48 /* Implemented via sigvec() in SunOS */
#define TARGET_NR_geteuid 49 /* SunOS calls getuid() */
#define TARGET_NR_getegid 50 /* SunOS calls getgid() */
#define TARGET_NR_acct 51 /* Common */
#define TARGET_NR_getgid32 53 /* Linux sparc32 specific */
#define TARGET_NR_ioctl 54 /* Common */
#define TARGET_NR_reboot 55 /* Common */
#define TARGET_NR_mmap2 56 /* Linux sparc32 Specific */
#define TARGET_NR_symlink 57 /* Common */
#define TARGET_NR_readlink 58 /* Common */
#define TARGET_NR_execve 59 /* Common */
#define TARGET_NR_umask 60 /* Common */
#define TARGET_NR_chroot 61 /* Common */
#define TARGET_NR_fstat 62 /* Common */
#define TARGET_NR_fstat64 63 /* Linux sparc32 Specific */
#define TARGET_NR_getpagesize 64 /* Common */
#define TARGET_NR_msync 65 /* Common in newer 1.3.x revs... */
#define TARGET_NR_vfork 66 /* Common */
#define TARGET_NR_pread 67 /* Linux Specific */
#define TARGET_NR_pwrite 68 /* Linux Specific */
#define TARGET_NR_geteuid32 69 /* Linux sparc32, sbrk under SunOS */
#define TARGET_NR_getegid32 70 /* Linux sparc32, sstk under SunOS */
#define TARGET_NR_mmap 71 /* Common */
#define TARGET_NR_setreuid32 72 /* Linux sparc32, vadvise under SunOS */
#define TARGET_NR_munmap 73 /* Common */
#define TARGET_NR_mprotect 74 /* Common */
#define TARGET_NR_madvise 75 /* Common */
#define TARGET_NR_vhangup 76 /* Common */
#define TARGET_NR_truncate64 77 /* Linux sparc32 Specific */
#define TARGET_NR_mincore 78 /* Common */
#define TARGET_NR_getgroups 79 /* Common */
#define TARGET_NR_setgroups 80 /* Common */
#define TARGET_NR_getpgrp 81 /* Common */
#define TARGET_NR_setgroups32 82 /* Linux sparc32, setpgrp under SunOS */
#define TARGET_NR_setitimer 83 /* Common */
#define TARGET_NR_ftruncate64 84 /* Linux sparc32 Specific */
#define TARGET_NR_swapon 85 /* Common */
#define TARGET_NR_getitimer 86 /* Common */
#define TARGET_NR_setuid32 87 /* Linux sparc32, gethostname under SunOS */
#define TARGET_NR_sethostname 88 /* Common */
#define TARGET_NR_setgid32 89 /* Linux sparc32, getdtablesize under SunOS */
#define TARGET_NR_dup2 90 /* Common */
#define TARGET_NR_setfsuid32 91 /* Linux sparc32, getdopt under SunOS */
#define TARGET_NR_fcntl 92 /* Common */
#define TARGET_NR_select 93 /* Common */
#define TARGET_NR_setfsgid32 94 /* Linux sparc32, setdopt under SunOS */
#define TARGET_NR_fsync 95 /* Common */
#define TARGET_NR_setpriority 96 /* Common */
#define TARGET_NR_socket 97 /* Common */
#define TARGET_NR_connect 98 /* Common */
#define TARGET_NR_accept 99 /* Common */
#define TARGET_NR_getpriority 100 /* Common */
#define TARGET_NR_rt_sigreturn 101 /* Linux Specific */
#define TARGET_NR_rt_sigaction 102 /* Linux Specific */
#define TARGET_NR_rt_sigprocmask 103 /* Linux Specific */
#define TARGET_NR_rt_sigpending 104 /* Linux Specific */
#define TARGET_NR_rt_sigtimedwait 105 /* Linux Specific */
#define TARGET_NR_rt_sigqueueinfo 106 /* Linux Specific */
#define TARGET_NR_rt_sigsuspend 107 /* Linux Specific */
#define TARGET_NR_setresuid32 108 /* Linux Specific, sigvec under SunOS */
#define TARGET_NR_getresuid32 109 /* Linux Specific, sigblock under SunOS */
#define TARGET_NR_setresgid32 110 /* Linux Specific, sigsetmask under SunOS */
#define TARGET_NR_getresgid32 111 /* Linux Specific, sigpause under SunOS */
#define TARGET_NR_setregid32 112 /* Linux sparc32, sigstack under SunOS */
#define TARGET_NR_recvmsg 113 /* Common */
#define TARGET_NR_sendmsg 114 /* Common */
#define TARGET_NR_getgroups32 115 /* Linux sparc32, vtrace under SunOS */
#define TARGET_NR_gettimeofday 116 /* Common */
#define TARGET_NR_getrusage 117 /* Common */
#define TARGET_NR_getsockopt 118 /* Common */
#define TARGET_NR_getcwd 119 /* Linux Specific */
#define TARGET_NR_readv 120 /* Common */
#define TARGET_NR_writev 121 /* Common */
#define TARGET_NR_settimeofday 122 /* Common */
#define TARGET_NR_fchown 123 /* Common */
#define TARGET_NR_fchmod 124 /* Common */
#define TARGET_NR_recvfrom 125 /* Common */
#define TARGET_NR_setreuid 126 /* Common */
#define TARGET_NR_setregid 127 /* Common */
#define TARGET_NR_rename 128 /* Common */
#define TARGET_NR_truncate 129 /* Common */
#define TARGET_NR_ftruncate 130 /* Common */
#define TARGET_NR_flock 131 /* Common */
#define TARGET_NR_lstat64 132 /* Linux sparc32 Specific */
#define TARGET_NR_sendto 133 /* Common */
#define TARGET_NR_shutdown 134 /* Common */
#define TARGET_NR_socketpair 135 /* Common */
#define TARGET_NR_mkdir 136 /* Common */
#define TARGET_NR_rmdir 137 /* Common */
#define TARGET_NR_utimes 138 /* SunOS Specific */
#define TARGET_NR_stat64 139 /* Linux sparc32 Specific */
#define TARGET_NR_getpeername 141 /* Common */
#define TARGET_NR_gettid 143 /* ENOSYS under SunOS */
#define TARGET_NR_getrlimit 144 /* Common */
#define TARGET_NR_setrlimit 145 /* Common */
#define TARGET_NR_pivot_root 146 /* Linux Specific, killpg under SunOS */
#define TARGET_NR_prctl 147 /* ENOSYS under SunOS */
#define TARGET_NR_pciconfig_read 148 /* ENOSYS under SunOS */
#define TARGET_NR_pciconfig_write 149 /* ENOSYS under SunOS */
#define TARGET_NR_getsockname 150 /* Common */
#define TARGET_NR_poll 153 /* Common */
#define TARGET_NR_getdents64 154 /* Linux specific */
#define TARGET_NR_fcntl64 155 /* Linux sparc32 Specific */
#define TARGET_NR_statfs 157 /* Common */
#define TARGET_NR_fstatfs 158 /* Common */
#define TARGET_NR_umount 159 /* Common */
#define TARGET_NR_getdomainname 162 /* SunOS Specific */
#define TARGET_NR_setdomainname 163 /* Common */
#define TARGET_NR_quotactl 165 /* Common */
#define TARGET_NR_mount 167 /* Common */
#define TARGET_NR_ustat 168 /* Common */
#define TARGET_NR_getdents 174 /* Common */
#define TARGET_NR_setsid 175 /* Common */
#define TARGET_NR_fchdir 176 /* Common */
#define TARGET_NR_sigpending 183 /* Common */
#define TARGET_NR_query_module 184 /* Linux Specific */
#define TARGET_NR_setpgid 185 /* Common */
#define TARGET_NR_tkill 187 /* SunOS: fpathconf */
#define TARGET_NR_exit_group 188 /* Linux specific, sysconf undef SunOS */
#define TARGET_NR_uname 189 /* Linux Specific */
#define TARGET_NR_init_module 190 /* Linux Specific */
#define TARGET_NR_personality 191 /* Linux Specific */
#define TARGET_NR_getppid 197 /* Linux Specific */
#define TARGET_NR_sigaction 198 /* Linux Specific */
#define TARGET_NR_sgetmask 199 /* Linux Specific */
#define TARGET_NR_ssetmask 200 /* Linux Specific */
#define TARGET_NR_sigsuspend 201 /* Linux Specific */
#define TARGET_NR_oldlstat 202 /* Linux Specific */
#define TARGET_NR_uselib 203 /* Linux Specific */
#define TARGET_NR_readdir 204 /* Linux Specific */
#define TARGET_NR_readahead 205 /* Linux Specific */
#define TARGET_NR_socketcall 206 /* Linux Specific */
#define TARGET_NR_syslog 207 /* Linux Specific */
#define TARGET_NR_waitpid 212 /* Linux Specific */
#define TARGET_NR_swapoff 213 /* Linux Specific */
#define TARGET_NR_sysinfo 214 /* Linux Specific */
#define TARGET_NR_ipc 215 /* Linux Specific */
#define TARGET_NR_sigreturn 216 /* Linux Specific */
#define TARGET_NR_clone 217 /* Linux Specific */
#define TARGET_NR_adjtimex 219 /* Linux Specific */
#define TARGET_NR_sigprocmask 220 /* Linux Specific */
#define TARGET_NR_create_module 221 /* Linux Specific */
#define TARGET_NR_delete_module 222 /* Linux Specific */
#define TARGET_NR_get_kernel_syms 223 /* Linux Specific */
#define TARGET_NR_getpgid 224 /* Linux Specific */
#define TARGET_NR_bdflush 225 /* Linux Specific */
#define TARGET_NR_sysfs 226 /* Linux Specific */
#define TARGET_NR_afs_syscall 227 /* Linux Specific */
#define TARGET_NR_setfsuid 228 /* Linux Specific */
#define TARGET_NR_setfsgid 229 /* Linux Specific */
#define TARGET_NR__newselect 230 /* Linux Specific */
#define TARGET_NR_time 231 /* Linux Specific */
#define TARGET_NR_stime 233 /* Linux Specific */
#define TARGET_NR__llseek 236 /* Linux Specific */
#define TARGET_NR_mlock 237
#define TARGET_NR_munlock 238
#define TARGET_NR_mlockall 239
#define TARGET_NR_munlockall 240
#define TARGET_NR_sched_setparam 241
#define TARGET_NR_sched_getparam 242
#define TARGET_NR_sched_setscheduler 243
#define TARGET_NR_sched_getscheduler 244
#define TARGET_NR_sched_yield 245
#define TARGET_NR_sched_get_priority_max 246
#define TARGET_NR_sched_get_priority_min 247
#define TARGET_NR_sched_rr_get_interval 248
#define TARGET_NR_nanosleep 249
#define TARGET_NR_mremap 250
#define TARGET_NR__sysctl 251
#define TARGET_NR_getsid 252
#define TARGET_NR_fdatasync 253
#define TARGET_NR_nfsservctl 254
#define TARGET_NR_aplib 255
#define TARGET_NR__exit TARGET_NR_exit

279
linux-user/sparc/termbits.h Normal file
View File

@@ -0,0 +1,279 @@
/* from asm/termbits.h */
#define TARGET_NCCS 19
struct target_termios {
unsigned int c_iflag; /* input mode flags */
unsigned int c_oflag; /* output mode flags */
unsigned int c_cflag; /* control mode flags */
unsigned int c_lflag; /* local mode flags */
unsigned char c_line; /* line discipline */
unsigned char c_cc[TARGET_NCCS]; /* control characters */
};
/* c_cc characters */
#define TARGET_VINTR 0
#define TARGET_VQUIT 1
#define TARGET_VERASE 2
#define TARGET_VKILL 3
#define TARGET_VEOF 4
#define TARGET_VEOL 5
#define TARGET_VEOL2 6
#define TARGET_VSWTC 7
#define TARGET_VSTART 8
#define TARGET_VSTOP 9
#define TARGET_VSUSP 10
#define TARGET_VDSUSP 11 /* SunOS POSIX nicety I do believe... */
#define TARGET_VREPRINT 12
#define TARGET_VDISCARD 13
#define TARGET_VWERASE 14
#define TARGET_VLNEXT 15
/* Kernel keeps vmin/vtime separated, user apps assume vmin/vtime is
* shared with eof/eol
*/
#define TARGET_VMIN TARGET_VEOF
#define TARGET_VTIME TARGET_VEOL
/* c_iflag bits */
#define TARGET_IGNBRK 0x00000001
#define TARGET_BRKINT 0x00000002
#define TARGET_IGNPAR 0x00000004
#define TARGET_PARMRK 0x00000008
#define TARGET_INPCK 0x00000010
#define TARGET_ISTRIP 0x00000020
#define TARGET_INLCR 0x00000040
#define TARGET_IGNCR 0x00000080
#define TARGET_ICRNL 0x00000100
#define TARGET_IUCLC 0x00000200
#define TARGET_IXON 0x00000400
#define TARGET_IXANY 0x00000800
#define TARGET_IXOFF 0x00001000
#define TARGET_IMAXBEL 0x00002000
/* c_oflag bits */
#define TARGET_OPOST 0x00000001
#define TARGET_OLCUC 0x00000002
#define TARGET_ONLCR 0x00000004
#define TARGET_OCRNL 0x00000008
#define TARGET_ONOCR 0x00000010
#define TARGET_ONLRET 0x00000020
#define TARGET_OFILL 0x00000040
#define TARGET_OFDEL 0x00000080
#define TARGET_NLDLY 0x00000100
#define TARGET_NL0 0x00000000
#define TARGET_NL1 0x00000100
#define TARGET_CRDLY 0x00000600
#define TARGET_CR0 0x00000000
#define TARGET_CR1 0x00000200
#define TARGET_CR2 0x00000400
#define TARGET_CR3 0x00000600
#define TARGET_TABDLY 0x00001800
#define TARGET_TAB0 0x00000000
#define TARGET_TAB1 0x00000800
#define TARGET_TAB2 0x00001000
#define TARGET_TAB3 0x00001800
#define TARGET_XTABS 0x00001800
#define TARGET_BSDLY 0x00002000
#define TARGET_BS0 0x00000000
#define TARGET_BS1 0x00002000
#define TARGET_VTDLY 0x00004000
#define TARGET_VT0 0x00000000
#define TARGET_VT1 0x00004000
#define TARGET_FFDLY 0x00008000
#define TARGET_FF0 0x00000000
#define TARGET_FF1 0x00008000
#define TARGET_PAGEOUT 0x00010000 /* SUNOS specific */
#define TARGET_WRAP 0x00020000 /* SUNOS specific */
/* c_cflag bit meaning */
#define TARGET_CBAUD 0x0000100f
#define TARGET_B0 0x00000000 /* hang up */
#define TARGET_B50 0x00000001
#define TARGET_B75 0x00000002
#define TARGET_B110 0x00000003
#define TARGET_B134 0x00000004
#define TARGET_B150 0x00000005
#define TARGET_B200 0x00000006
#define TARGET_B300 0x00000007
#define TARGET_B600 0x00000008
#define TARGET_B1200 0x00000009
#define TARGET_B1800 0x0000000a
#define TARGET_B2400 0x0000000b
#define TARGET_B4800 0x0000000c
#define TARGET_B9600 0x0000000d
#define TARGET_B19200 0x0000000e
#define TARGET_B38400 0x0000000f
#define TARGET_EXTA B19200
#define TARGET_EXTB B38400
#define TARGET_CSIZE 0x00000030
#define TARGET_CS5 0x00000000
#define TARGET_CS6 0x00000010
#define TARGET_CS7 0x00000020
#define TARGET_CS8 0x00000030
#define TARGET_CSTOPB 0x00000040
#define TARGET_CREAD 0x00000080
#define TARGET_PARENB 0x00000100
#define TARGET_PARODD 0x00000200
#define TARGET_HUPCL 0x00000400
#define TARGET_CLOCAL 0x00000800
#define TARGET_CBAUDEX 0x00001000
/* We'll never see these speeds with the Zilogs, but for completeness... */
#define TARGET_B57600 0x00001001
#define TARGET_B115200 0x00001002
#define TARGET_B230400 0x00001003
#define TARGET_B460800 0x00001004
/* This is what we can do with the Zilogs. */
#define TARGET_B76800 0x00001005
/* This is what we can do with the SAB82532. */
#define TARGET_B153600 0x00001006
#define TARGET_B307200 0x00001007
#define TARGET_B614400 0x00001008
#define TARGET_B921600 0x00001009
/* And these are the rest... */
#define TARGET_B500000 0x0000100a
#define TARGET_B576000 0x0000100b
#define TARGET_B1000000 0x0000100c
#define TARGET_B1152000 0x0000100d
#define TARGET_B1500000 0x0000100e
#define TARGET_B2000000 0x0000100f
/* These have totally bogus values and nobody uses them
so far. Later on we'd have to use say 0x10000x and
adjust CBAUD constant and drivers accordingly.
#define B2500000 0x00001010
#define B3000000 0x00001011
#define B3500000 0x00001012
#define B4000000 0x00001013 */
#define TARGET_CIBAUD 0x100f0000 /* input baud rate (not used) */
#define TARGET_CMSPAR 0x40000000 /* mark or space (stick) parity */
#define TARGET_CRTSCTS 0x80000000 /* flow control */
/* c_lflag bits */
#define TARGET_ISIG 0x00000001
#define TARGET_ICANON 0x00000002
#define TARGET_XCASE 0x00000004
#define TARGET_ECHO 0x00000008
#define TARGET_ECHOE 0x00000010
#define TARGET_ECHOK 0x00000020
#define TARGET_ECHONL 0x00000040
#define TARGET_NOFLSH 0x00000080
#define TARGET_TOSTOP 0x00000100
#define TARGET_ECHOCTL 0x00000200
#define TARGET_ECHOPRT 0x00000400
#define TARGET_ECHOKE 0x00000800
#define TARGET_DEFECHO 0x00001000 /* SUNOS thing, what is it? */
#define TARGET_FLUSHO 0x00002000
#define TARGET_PENDIN 0x00004000
#define TARGET_IEXTEN 0x00008000
/* ioctls */
/* Big T */
#define TARGET_TCGETA TARGET_IOR('T', 1, struct target_termio)
#define TARGET_TCSETA TARGET_IOW('T', 2, struct target_termio)
#define TARGET_TCSETAW TARGET_IOW('T', 3, struct target_termio)
#define TARGET_TCSETAF TARGET_IOW('T', 4, struct target_termio)
#define TARGET_TCSBRK TARGET_IO('T', 5)
#define TARGET_TCXONC TARGET_IO('T', 6)
#define TARGET_TCFLSH TARGET_IO('T', 7)
#define TARGET_TCGETS TARGET_IOR('T', 8, struct target_termios)
#define TARGET_TCSETS TARGET_IOW('T', 9, struct target_termios)
#define TARGET_TCSETSW TARGET_IOW('T', 10, struct target_termios)
#define TARGET_TCSETSF TARGET_IOW('T', 11, struct target_termios)
/* Note that all the ioctls that are not available in Linux have a
* double underscore on the front to: a) avoid some programs to
* thing we support some ioctls under Linux (autoconfiguration stuff)
*/
/* Little t */
#define TARGET_TIOCGETD TARGET_IOR('t', 0, int)
#define TARGET_TIOCSETD TARGET_IOW('t', 1, int)
//#define __TIOCHPCL _IO('t', 2) /* SunOS Specific */
//#define __TIOCMODG _IOR('t', 3, int) /* SunOS Specific */
//#define __TIOCMODS _IOW('t', 4, int) /* SunOS Specific */
//#define __TIOCGETP _IOR('t', 8, struct sgttyb) /* SunOS Specific */
//#define __TIOCSETP _IOW('t', 9, struct sgttyb) /* SunOS Specific */
//#define __TIOCSETN _IOW('t', 10, struct sgttyb) /* SunOS Specific */
#define TARGET_TIOCEXCL TARGET_IO('t', 13)
#define TARGET_TIOCNXCL TARGET_IO('t', 14)
//#define __TIOCFLUSH _IOW('t', 16, int) /* SunOS Specific */
//#define __TIOCSETC _IOW('t', 17, struct tchars) /* SunOS Specific */
//#define __TIOCGETC _IOR('t', 18, struct tchars) /* SunOS Specific */
//#define __TIOCTCNTL _IOW('t', 32, int) /* SunOS Specific */
//#define __TIOCSIGNAL _IOW('t', 33, int) /* SunOS Specific */
//#define __TIOCSETX _IOW('t', 34, int) /* SunOS Specific */
//#define __TIOCGETX _IOR('t', 35, int) /* SunOS Specific */
#define TARGET_TIOCCONS TARGET_IO('t', 36)
//#define __TIOCSSIZE _IOW('t', 37, struct sunos_ttysize) /* SunOS Specific */
//#define __TIOCGSIZE _IOR('t', 38, struct sunos_ttysize) /* SunOS Specific */
#define TARGET_TIOCGSOFTCAR TARGET_IOR('t', 100, int)
#define TARGET_TIOCSSOFTCAR TARGET_IOW('t', 101, int)
//#define __TIOCUCNTL _IOW('t', 102, int) /* SunOS Specific */
#define TARGET_TIOCSWINSZ TARGET_IOW('t', 103, struct winsize)
#define TARGET_TIOCGWINSZ TARGET_IOR('t', 104, struct winsize)
//#define __TIOCREMOTE _IOW('t', 105, int) /* SunOS Specific */
#define TARGET_TIOCMGET TARGET_IOR('t', 106, int)
#define TARGET_TIOCMBIC TARGET_IOW('t', 107, int)
#define TARGET_TIOCMBIS TARGET_IOW('t', 108, int)
#define TARGET_TIOCMSET TARGET_IOW('t', 109, int)
#define TARGET_TIOCSTART TARGET_IO('t', 110)
#define TARGET_TIOCSTOP TARGET_IO('t', 111)
#define TARGET_TIOCPKT TARGET_IOW('t', 112, int)
#define TARGET_TIOCNOTTY TARGET_IO('t', 113)
#define TARGET_TIOCSTI TARGET_IOW('t', 114, char)
#define TARGET_TIOCOUTQ TARGET_IOR('t', 115, int)
//#define __TIOCGLTC _IOR('t', 116, struct ltchars) /* SunOS Specific */
//#define __TIOCSLTC _IOW('t', 117, struct ltchars) /* SunOS Specific */
/* 118 is the non-posix setpgrp tty ioctl */
/* 119 is the non-posix getpgrp tty ioctl */
//#define __TIOCCDTR TARGET_IO('t', 120) /* SunOS Specific */
//#define __TIOCSDTR TARGET_IO('t', 121) /* SunOS Specific */
#define TARGET_TIOCCBRK TARGET_IO('t', 122)
#define TARGET_TIOCSBRK TARGET_IO('t', 123)
//#define __TIOCLGET TARGET_IOW('t', 124, int) /* SunOS Specific */
//#define __TIOCLSET TARGET_IOW('t', 125, int) /* SunOS Specific */
//#define __TIOCLBIC TARGET_IOW('t', 126, int) /* SunOS Specific */
//#define __TIOCLBIS TARGET_IOW('t', 127, int) /* SunOS Specific */
//#define __TIOCISPACE TARGET_IOR('t', 128, int) /* SunOS Specific */
//#define __TIOCISIZE TARGET_IOR('t', 129, int) /* SunOS Specific */
#define TARGET_TIOCSPGRP TARGET_IOW('t', 130, int)
#define TARGET_TIOCGPGRP TARGET_IOR('t', 131, int)
#define TARGET_TIOCSCTTY TARGET_IO('t', 132)
#define TARGET_TIOCGSID TARGET_IOR('t', 133, int)
/* Get minor device of a pty master's FD -- Solaris equiv is ISPTM */
#define TARGET_TIOCGPTN TARGET_IOR('t', 134, unsigned int) /* Get Pty Number */
#define TARGET_TIOCSPTLCK TARGET_IOW('t', 135, int) /* Lock/unlock PTY */
/* Little f */
#define TARGET_FIOCLEX TARGET_IO('f', 1)
#define TARGET_FIONCLEX TARGET_IO('f', 2)
#define TARGET_FIOASYNC TARGET_IOW('f', 125, int)
#define TARGET_FIONBIO TARGET_IOW('f', 126, int)
#define TARGET_FIONREAD TARGET_IOR('f', 127, int)
#define TARGET_TIOCINQ TARGET_FIONREAD
/* SCARY Rutgers local SunOS kernel hackery, perhaps I will support it
* someday. This is completely bogus, I know...
*/
//#define __TCGETSTAT TARGET_IO('T', 200) /* Rutgers specific */
//#define __TCSETSTAT TARGET_IO('T', 201) /* Rutgers specific */
/* Linux specific, no SunOS equivalent. */
#define TARGET_TIOCLINUX 0x541C
#define TARGET_TIOCGSERIAL 0x541E
#define TARGET_TIOCSSERIAL 0x541F
#define TARGET_TCSBRKP 0x5425
#define TARGET_TIOCTTYGSTRUCT 0x5426
#define TARGET_TIOCSERCONFIG 0x5453
#define TARGET_TIOCSERGWILD 0x5454
#define TARGET_TIOCSERSWILD 0x5455
#define TARGET_TIOCGLCKTRMIOS 0x5456
#define TARGET_TIOCSLCKTRMIOS 0x5457
#define TARGET_TIOCSERGSTRUCT 0x5458 /* For debugging only */
#define TARGET_TIOCSERGETLSR 0x5459 /* Get line status register */
#define TARGET_TIOCSERGETMULTI 0x545A /* Get multiport config */
#define TARGET_TIOCSERSETMULTI 0x545B /* Set multiport config */
#define TARGET_TIOCMIWAIT 0x545C /* Wait input */
#define TARGET_TIOCGICOUNT 0x545D /* Read serial port inline interrupt counts */

View File

@@ -41,6 +41,7 @@
#include <sys/uio.h>
#include <sys/poll.h>
#include <sys/times.h>
#include <utime.h>
//#include <sys/user.h>
#include <netinet/tcp.h>
@@ -64,10 +65,138 @@
//#define DEBUG
#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SPARC)
/* 16 bit uid wrappers emulation */
#define USE_UID16
#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])
#if defined(__powerpc__)
#undef __syscall_nr
#undef __sc_loadargs_0
#undef __sc_loadargs_1
#undef __sc_loadargs_2
#undef __sc_loadargs_3
#undef __sc_loadargs_4
#undef __sc_loadargs_5
#undef __sc_asm_input_0
#undef __sc_asm_input_1
#undef __sc_asm_input_2
#undef __sc_asm_input_3
#undef __sc_asm_input_4
#undef __sc_asm_input_5
#undef _syscall0
#undef _syscall1
#undef _syscall2
#undef _syscall3
#undef _syscall4
#undef _syscall5
/* need to redefine syscalls as Linux kernel defines are incorrect for
the clobber list */
/* On powerpc a system call basically clobbers the same registers like a
* function call, with the exception of LR (which is needed for the
* "sc; bnslr" sequence) and CR (where only CR0.SO is clobbered to signal
* an error return status).
*/
#define __syscall_nr(nr, type, name, args...) \
unsigned long __sc_ret, __sc_err; \
{ \
register unsigned long __sc_0 __asm__ ("r0"); \
register unsigned long __sc_3 __asm__ ("r3"); \
register unsigned long __sc_4 __asm__ ("r4"); \
register unsigned long __sc_5 __asm__ ("r5"); \
register unsigned long __sc_6 __asm__ ("r6"); \
register unsigned long __sc_7 __asm__ ("r7"); \
\
__sc_loadargs_##nr(name, args); \
__asm__ __volatile__ \
("sc \n\t" \
"mfcr %0 " \
: "=&r" (__sc_0), \
"=&r" (__sc_3), "=&r" (__sc_4), \
"=&r" (__sc_5), "=&r" (__sc_6), \
"=&r" (__sc_7) \
: __sc_asm_input_##nr \
: "cr0", "ctr", "memory", \
"r8", "r9", "r10","r11", "r12"); \
__sc_ret = __sc_3; \
__sc_err = __sc_0; \
} \
if (__sc_err & 0x10000000) \
{ \
errno = __sc_ret; \
__sc_ret = -1; \
} \
return (type) __sc_ret
#define __sc_loadargs_0(name, dummy...) \
__sc_0 = __NR_##name
#define __sc_loadargs_1(name, arg1) \
__sc_loadargs_0(name); \
__sc_3 = (unsigned long) (arg1)
#define __sc_loadargs_2(name, arg1, arg2) \
__sc_loadargs_1(name, arg1); \
__sc_4 = (unsigned long) (arg2)
#define __sc_loadargs_3(name, arg1, arg2, arg3) \
__sc_loadargs_2(name, arg1, arg2); \
__sc_5 = (unsigned long) (arg3)
#define __sc_loadargs_4(name, arg1, arg2, arg3, arg4) \
__sc_loadargs_3(name, arg1, arg2, arg3); \
__sc_6 = (unsigned long) (arg4)
#define __sc_loadargs_5(name, arg1, arg2, arg3, arg4, arg5) \
__sc_loadargs_4(name, arg1, arg2, arg3, arg4); \
__sc_7 = (unsigned long) (arg5)
#define __sc_asm_input_0 "0" (__sc_0)
#define __sc_asm_input_1 __sc_asm_input_0, "1" (__sc_3)
#define __sc_asm_input_2 __sc_asm_input_1, "2" (__sc_4)
#define __sc_asm_input_3 __sc_asm_input_2, "3" (__sc_5)
#define __sc_asm_input_4 __sc_asm_input_3, "4" (__sc_6)
#define __sc_asm_input_5 __sc_asm_input_4, "5" (__sc_7)
#define _syscall0(type,name) \
type name(void) \
{ \
__syscall_nr(0, type, name); \
}
#define _syscall1(type,name,type1,arg1) \
type name(type1 arg1) \
{ \
__syscall_nr(1, type, name, arg1); \
}
#define _syscall2(type,name,type1,arg1,type2,arg2) \
type name(type1 arg1, type2 arg2) \
{ \
__syscall_nr(2, type, name, arg1, arg2); \
}
#define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \
type name(type1 arg1, type2 arg2, type3 arg3) \
{ \
__syscall_nr(3, type, name, arg1, arg2, arg3); \
}
#define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \
type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4) \
{ \
__syscall_nr(4, type, name, arg1, arg2, arg3, arg4); \
}
#define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4,type5,arg5) \
type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5) \
{ \
__syscall_nr(5, type, name, arg1, arg2, arg3, arg4, arg5); \
}
#endif
#define __NR_sys_uname __NR_uname
#define __NR_sys_getcwd1 __NR_getcwd
#define __NR_sys_statfs __NR_statfs
@@ -110,6 +239,27 @@ extern int setresgid(gid_t, gid_t, gid_t);
extern int getresgid(gid_t *, gid_t *, gid_t *);
extern int setgroups(int, gid_t *);
#define put_user(x,ptr)\
({\
int size = sizeof(*ptr);\
switch(size) {\
case 1:\
stb(ptr, (typeof(*ptr))(x));\
break;\
case 2:\
stw(ptr, (typeof(*ptr))(x));\
break;\
case 4:\
stl(ptr, (typeof(*ptr))(x));\
break;\
case 8:\
stq(ptr, (typeof(*ptr))(x));\
break;\
default:\
abort();\
}\
0;\
})
static inline long get_errno(long ret)
{
if (ret == -1)
@@ -210,6 +360,21 @@ static inline void host_to_target_fds(target_long *target_fds,
#endif
}
#if defined(__alpha__)
#define HOST_HZ 1024
#else
#define HOST_HZ 100
#endif
static inline long host_to_target_clock_t(long ticks)
{
#if HOST_HZ == TARGET_HZ
return ticks;
#else
return ((int64_t)ticks * TARGET_HZ) / HOST_HZ;
#endif
}
static inline void host_to_target_rusage(struct target_rusage *target_rusage,
const struct rusage *rusage)
{
@@ -1124,6 +1289,17 @@ int do_fork(CPUState *env, unsigned int flags, unsigned long newsp)
newsp = env->regs[13];
new_env->regs[13] = newsp;
new_env->regs[0] = 0;
#elif defined(TARGET_SPARC)
printf ("HELPME: %s:%d\n", __FILE__, __LINE__);
#elif defined(TARGET_PPC)
if (!newsp)
newsp = env->gpr[1];
new_env->gpr[1] = newsp;
{
int i;
for (i = 7; i < 32; i++)
new_env->gpr[i] = 0;
}
#else
#error unsupported target CPU
#endif
@@ -1184,11 +1360,41 @@ static long do_fcntl(int fd, int cmd, unsigned long arg)
return ret;
}
#ifdef USE_UID16
#define high2lowuid(x) (x)
#define high2lowgid(x) (x)
#define low2highuid(x) (x)
#define low2highgid(x) (x)
static inline int high2lowuid(int uid)
{
if (uid > 65535)
return 65534;
else
return uid;
}
static inline int high2lowgid(int gid)
{
if (gid > 65535)
return 65534;
else
return gid;
}
static inline int low2highuid(int uid)
{
if ((int16_t)uid == -1)
return -1;
else
return uid;
}
static inline int low2highgid(int gid)
{
if ((int16_t)gid == -1)
return -1;
else
return gid;
}
#endif /* USE_UID16 */
void syscall_init(void)
{
@@ -1230,7 +1436,7 @@ void syscall_init(void)
ie++;
}
}
long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
long arg4, long arg5, long arg6)
{
@@ -1239,7 +1445,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
struct kernel_statfs *stfs;
#ifdef DEBUG
gemu_log("syscall %d\n", num);
gemu_log("syscall %d", num);
#endif
switch(num) {
case TARGET_NR_exit:
@@ -1331,13 +1537,14 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
case TARGET_NR_chmod:
ret = get_errno(chmod((const char *)arg1, arg2));
break;
case TARGET_NR_lchown:
ret = get_errno(chown((const char *)arg1, arg2, arg3));
break;
#ifdef TARGET_NR_break
case TARGET_NR_break:
goto unimplemented;
#endif
#ifdef TARGET_NR_oldstat
case TARGET_NR_oldstat:
goto unimplemented;
#endif
case TARGET_NR_lseek:
ret = get_errno(lseek(arg1, arg2, arg3));
break;
@@ -1350,12 +1557,6 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
case TARGET_NR_umount:
ret = get_errno(umount((const char *)arg1));
break;
case TARGET_NR_setuid:
ret = get_errno(setuid(low2highuid(arg1)));
break;
case TARGET_NR_getuid:
ret = get_errno(getuid());
break;
case TARGET_NR_stime:
{
int *time_ptr = (int *)arg1;
@@ -1369,25 +1570,40 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
case TARGET_NR_alarm:
ret = alarm(arg1);
break;
#ifdef TARGET_NR_oldfstat
case TARGET_NR_oldfstat:
goto unimplemented;
#endif
case TARGET_NR_pause:
ret = get_errno(pause());
break;
case TARGET_NR_utime:
goto unimplemented;
{
struct utimbuf tbuf;
struct target_utimbuf *target_tbuf = (void *)arg2;
tbuf.actime = tswapl(target_tbuf->actime);
tbuf.modtime = tswapl(target_tbuf->modtime);
ret = get_errno(utime((const char *)arg1, &tbuf));
}
break;
#ifdef TARGET_NR_stty
case TARGET_NR_stty:
goto unimplemented;
#endif
#ifdef TARGET_NR_gtty
case TARGET_NR_gtty:
goto unimplemented;
#endif
case TARGET_NR_access:
ret = get_errno(access((const char *)arg1, arg2));
break;
case TARGET_NR_nice:
ret = get_errno(nice(arg1));
break;
#ifdef TARGET_NR_ftime
case TARGET_NR_ftime:
goto unimplemented;
#endif
case TARGET_NR_sync:
sync();
ret = 0;
@@ -1423,51 +1639,52 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
struct tms tms;
ret = get_errno(times(&tms));
if (tmsp) {
tmsp->tms_utime = tswapl(tms.tms_utime);
tmsp->tms_stime = tswapl(tms.tms_stime);
tmsp->tms_cutime = tswapl(tms.tms_cutime);
tmsp->tms_cstime = tswapl(tms.tms_cstime);
tmsp->tms_utime = tswapl(host_to_target_clock_t(tms.tms_utime));
tmsp->tms_stime = tswapl(host_to_target_clock_t(tms.tms_stime));
tmsp->tms_cutime = tswapl(host_to_target_clock_t(tms.tms_cutime));
tmsp->tms_cstime = tswapl(host_to_target_clock_t(tms.tms_cstime));
}
if (!is_error(ret))
ret = host_to_target_clock_t(ret);
}
break;
#ifdef TARGET_NR_prof
case TARGET_NR_prof:
goto unimplemented;
case TARGET_NR_setgid:
ret = get_errno(setgid(low2highgid(arg1)));
break;
case TARGET_NR_getgid:
ret = get_errno(getgid());
break;
#endif
case TARGET_NR_signal:
goto unimplemented;
case TARGET_NR_geteuid:
ret = get_errno(geteuid());
break;
case TARGET_NR_getegid:
ret = get_errno(getegid());
break;
case TARGET_NR_acct:
goto unimplemented;
case TARGET_NR_umount2:
ret = get_errno(umount2((const char *)arg1, arg2));
break;
#ifdef TARGET_NR_lock
case TARGET_NR_lock:
goto unimplemented;
#endif
case TARGET_NR_ioctl:
ret = do_ioctl(arg1, arg2, arg3);
break;
case TARGET_NR_fcntl:
ret = get_errno(do_fcntl(arg1, arg2, arg3));
break;
#ifdef TARGET_NR_mpx
case TARGET_NR_mpx:
goto unimplemented;
#endif
case TARGET_NR_setpgid:
ret = get_errno(setpgid(arg1, arg2));
break;
#ifdef TARGET_NR_ulimit
case TARGET_NR_ulimit:
goto unimplemented;
#endif
#ifdef TARGET_NR_oldolduname
case TARGET_NR_oldolduname:
goto unimplemented;
#endif
case TARGET_NR_umask:
ret = get_errno(umask(arg1));
break;
@@ -1672,12 +1889,6 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
/* NOTE: ret is eax, so not transcoding must be done */
ret = do_rt_sigreturn(cpu_env);
break;
case TARGET_NR_setreuid:
ret = get_errno(setreuid(arg1, arg2));
break;
case TARGET_NR_setregid:
ret = get_errno(setregid(arg1, arg2));
break;
case TARGET_NR_sethostname:
ret = get_errno(sethostname((const char *)arg1, arg2));
break;
@@ -1734,41 +1945,25 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
ret = get_errno(settimeofday(&tv, NULL));
}
break;
case TARGET_NR_getgroups:
{
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:
{
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;
{
struct target_sel_arg_struct *sel = (void *)arg1;
sel->n = tswapl(sel->n);
sel->inp = tswapl(sel->inp);
sel->outp = tswapl(sel->outp);
sel->exp = tswapl(sel->exp);
sel->tvp = tswapl(sel->tvp);
ret = do_select(sel->n, (void *)sel->inp, (void *)sel->outp,
(void *)sel->exp, (void *)sel->tvp);
}
break;
case TARGET_NR_symlink:
ret = get_errno(symlink((const char *)arg1, (const char *)arg2));
break;
#ifdef TARGET_NR_oldlstat
case TARGET_NR_oldlstat:
goto unimplemented;
#endif
case TARGET_NR_readlink:
ret = get_errno(readlink(path((const char *)arg1), (char *)arg2, arg3));
break;
@@ -1781,8 +1976,8 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
goto unimplemented;
case TARGET_NR_readdir:
goto unimplemented;
#ifdef TARGET_I386
case TARGET_NR_mmap:
#if defined(TARGET_I386) || defined(TARGET_ARM)
{
uint32_t v1, v2, v3, v4, v5, v6, *vptr;
vptr = (uint32_t *)arg1;
@@ -1796,17 +1991,23 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
target_to_host_bitmask(v4, mmap_flags_tbl),
v5, v6));
}
break;
#endif
#ifdef TARGET_I386
case TARGET_NR_mmap2:
#else
case TARGET_NR_mmap:
ret = get_errno(target_mmap(arg1, arg2, arg3,
target_to_host_bitmask(arg4, mmap_flags_tbl),
arg5,
arg6));
#endif
break;
case TARGET_NR_mmap2:
#if defined(TARGET_SPARC)
#define MMAP_SHIFT 12
#else
#define MMAP_SHIFT TARGET_PAGE_BITS
#endif
ret = get_errno(target_mmap(arg1, arg2, arg3,
target_to_host_bitmask(arg4, mmap_flags_tbl),
arg5,
arg6 << TARGET_PAGE_BITS));
arg6 << MMAP_SHIFT));
break;
case TARGET_NR_munmap:
ret = get_errno(target_munmap(arg1, arg2));
@@ -1841,17 +2042,16 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
case TARGET_NR_fchmod:
ret = get_errno(fchmod(arg1, arg2));
break;
case TARGET_NR_fchown:
ret = get_errno(fchown(arg1, arg2, arg3));
break;
case TARGET_NR_getpriority:
ret = get_errno(getpriority(arg1, arg2));
break;
case TARGET_NR_setpriority:
ret = get_errno(setpriority(arg1, arg2, arg3));
break;
#ifdef TARGET_NR_profil
case TARGET_NR_profil:
goto unimplemented;
#endif
case TARGET_NR_statfs:
stfs = (void *)arg2;
ret = get_errno(sys_statfs(path((const char *)arg1), stfs));
@@ -1873,8 +2073,10 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
stfs = (void *)arg2;
ret = get_errno(sys_fstatfs(arg1, stfs));
goto convert_statfs;
#ifdef TARGET_NR_ioperm
case TARGET_NR_ioperm:
goto unimplemented;
#endif
case TARGET_NR_socketcall:
ret = do_socketcall(arg1, (int32_t *)arg2);
break;
@@ -1932,10 +2134,16 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
struct target_stat *target_st = (void *)arg2;
target_st->st_dev = tswap16(st.st_dev);
target_st->st_ino = tswapl(st.st_ino);
#if defined(TARGET_PPC)
target_st->st_mode = tswapl(st.st_mode); /* XXX: check this */
target_st->st_uid = tswap32(st.st_uid);
target_st->st_gid = tswap32(st.st_gid);
#else
target_st->st_mode = tswap16(st.st_mode);
target_st->st_nlink = tswap16(st.st_nlink);
target_st->st_uid = tswap16(st.st_uid);
target_st->st_gid = tswap16(st.st_gid);
#endif
target_st->st_nlink = tswap16(st.st_nlink);
target_st->st_rdev = tswap16(st.st_rdev);
target_st->st_size = tswapl(st.st_size);
target_st->st_blksize = tswapl(st.st_blksize);
@@ -1946,15 +2154,21 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
}
}
break;
#ifdef TARGET_NR_olduname
case TARGET_NR_olduname:
goto unimplemented;
#endif
#ifdef TARGET_NR_iopl
case TARGET_NR_iopl:
goto unimplemented;
#endif
case TARGET_NR_vhangup:
ret = get_errno(vhangup());
break;
#ifdef TARGET_NR_idle
case TARGET_NR_idle:
goto unimplemented;
#endif
case TARGET_NR_wait4:
{
int status;
@@ -2035,12 +2249,6 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
break;
case TARGET_NR_afs_syscall:
goto unimplemented;
case TARGET_NR_setfsuid:
ret = get_errno(setfsuid(arg1));
break;
case TARGET_NR_setfsgid:
ret = get_errno(setfsgid(arg1));
break;
case TARGET_NR__llseek:
{
int64_t res;
@@ -2264,50 +2472,19 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
req.tv_sec = tswapl(target_req->tv_sec);
req.tv_nsec = tswapl(target_req->tv_nsec);
ret = get_errno(nanosleep(&req, &rem));
if (target_rem) {
if (is_error(ret) && target_rem) {
target_rem->tv_sec = tswapl(rem.tv_sec);
target_rem->tv_nsec = tswapl(rem.tv_nsec);
}
}
break;
case TARGET_NR_setresuid:
ret = get_errno(setresuid(low2highuid(arg1),
low2highuid(arg2),
low2highuid(arg3)));
break;
case TARGET_NR_getresuid:
{
int ruid, euid, suid;
ret = get_errno(getresuid(&ruid, &euid, &suid));
if (!is_error(ret)) {
*(uint16_t *)arg1 = tswap16(high2lowuid(ruid));
*(uint16_t *)arg2 = tswap16(high2lowuid(euid));
*(uint16_t *)arg3 = tswap16(high2lowuid(suid));
}
}
break;
case TARGET_NR_setresgid:
ret = get_errno(setresgid(low2highgid(arg1),
low2highgid(arg2),
low2highgid(arg3)));
break;
case TARGET_NR_getresgid:
{
int rgid, egid, sgid;
ret = get_errno(getresgid(&rgid, &egid, &sgid));
if (!is_error(ret)) {
*(uint16_t *)arg1 = high2lowgid(tswap16(rgid));
*(uint16_t *)arg2 = high2lowgid(tswap16(egid));
*(uint16_t *)arg3 = high2lowgid(tswap16(sgid));
}
}
break;
case TARGET_NR_query_module:
goto unimplemented;
case TARGET_NR_nfsservctl:
goto unimplemented;
case TARGET_NR_prctl:
goto unimplemented;
#ifdef TARGET_NR_pread
case TARGET_NR_pread:
page_unprotect_range((void *)arg2, arg3);
ret = get_errno(pread(arg1, (void *)arg2, arg3, arg4));
@@ -2315,9 +2492,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
case TARGET_NR_pwrite:
ret = get_errno(pwrite(arg1, (void *)arg2, arg3, arg4));
break;
case TARGET_NR_chown:
ret = get_errno(chown((const char *)arg1, arg2, arg3));
break;
#endif
case TARGET_NR_getcwd:
ret = get_errno(sys_getcwd1((char *)arg1, arg2));
break;
@@ -2329,13 +2504,18 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
goto unimplemented;
case TARGET_NR_sendfile:
goto unimplemented;
#ifdef TARGET_NR_getpmsg
case TARGET_NR_getpmsg:
goto unimplemented;
#endif
#ifdef TARGET_NR_putpmsg
case TARGET_NR_putpmsg:
goto unimplemented;
#endif
case TARGET_NR_vfork:
ret = get_errno(do_fork(cpu_env, CLONE_VFORK | CLONE_VM | SIGCHLD, 0));
break;
#ifdef TARGET_NR_ugetrlimit
case TARGET_NR_ugetrlimit:
{
struct rlimit rlim;
@@ -2347,6 +2527,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
}
break;
}
#endif
case TARGET_NR_truncate64:
goto unimplemented;
case TARGET_NR_ftruncate64:
@@ -2364,27 +2545,137 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
if (!is_error(ret)) {
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 = tswap64(st.st_ino);
put_user(st.st_dev, &target_st->st_dev);
put_user(st.st_ino, &target_st->st_ino);
#ifdef TARGET_STAT64_HAS_BROKEN_ST_INO
target_st->__st_ino = tswapl(st.st_ino);
put_user(st.st_ino, &target_st->__st_ino);
#endif
target_st->st_mode = tswap32(st.st_mode);
target_st->st_nlink = tswap32(st.st_nlink);
target_st->st_uid = tswapl(st.st_uid);
target_st->st_gid = tswapl(st.st_gid);
target_st->st_rdev = tswap16(st.st_rdev);
put_user(st.st_mode, &target_st->st_mode);
put_user(st.st_nlink, &target_st->st_nlink);
put_user(st.st_uid, &target_st->st_uid);
put_user(st.st_gid, &target_st->st_gid);
put_user(st.st_rdev, &target_st->st_rdev);
/* XXX: better use of kernel struct */
target_st->st_size = tswap64(st.st_size);
target_st->st_blksize = tswapl(st.st_blksize);
target_st->st_blocks = tswapl(st.st_blocks);
target_st->target_st_atime = tswapl(st.st_atime);
target_st->target_st_mtime = tswapl(st.st_mtime);
target_st->target_st_ctime = tswapl(st.st_ctime);
put_user(st.st_size, &target_st->st_size);
put_user(st.st_blksize, &target_st->st_blksize);
put_user(st.st_blocks, &target_st->st_blocks);
put_user(st.st_atime, &target_st->target_st_atime);
put_user(st.st_mtime, &target_st->target_st_mtime);
put_user(st.st_ctime, &target_st->target_st_ctime);
}
}
break;
#ifdef USE_UID16
case TARGET_NR_lchown:
ret = get_errno(lchown((const char *)arg1, low2highuid(arg2), low2highgid(arg3)));
break;
case TARGET_NR_getuid:
ret = get_errno(high2lowuid(getuid()));
break;
case TARGET_NR_getgid:
ret = get_errno(high2lowgid(getgid()));
break;
case TARGET_NR_geteuid:
ret = get_errno(high2lowuid(geteuid()));
break;
case TARGET_NR_getegid:
ret = get_errno(high2lowgid(getegid()));
break;
case TARGET_NR_setreuid:
ret = get_errno(setreuid(low2highuid(arg1), low2highuid(arg2)));
break;
case TARGET_NR_setregid:
ret = get_errno(setregid(low2highgid(arg1), low2highgid(arg2)));
break;
case TARGET_NR_getgroups:
{
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:
{
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_fchown:
ret = get_errno(fchown(arg1, low2highuid(arg2), low2highgid(arg3)));
break;
#ifdef TARGET_NR_setresuid
case TARGET_NR_setresuid:
ret = get_errno(setresuid(low2highuid(arg1),
low2highuid(arg2),
low2highuid(arg3)));
break;
#endif
#ifdef TARGET_NR_getresuid
case TARGET_NR_getresuid:
{
int ruid, euid, suid;
ret = get_errno(getresuid(&ruid, &euid, &suid));
if (!is_error(ret)) {
*(uint16_t *)arg1 = tswap16(high2lowuid(ruid));
*(uint16_t *)arg2 = tswap16(high2lowuid(euid));
*(uint16_t *)arg3 = tswap16(high2lowuid(suid));
}
}
break;
#endif
#ifdef TARGET_NR_getresgid
case TARGET_NR_setresgid:
ret = get_errno(setresgid(low2highgid(arg1),
low2highgid(arg2),
low2highgid(arg3)));
break;
#endif
#ifdef TARGET_NR_getresgid
case TARGET_NR_getresgid:
{
int rgid, egid, sgid;
ret = get_errno(getresgid(&rgid, &egid, &sgid));
if (!is_error(ret)) {
*(uint16_t *)arg1 = tswap16(high2lowgid(rgid));
*(uint16_t *)arg2 = tswap16(high2lowgid(egid));
*(uint16_t *)arg3 = tswap16(high2lowgid(sgid));
}
}
break;
#endif
case TARGET_NR_chown:
ret = get_errno(chown((const char *)arg1, low2highuid(arg2), low2highgid(arg3)));
break;
case TARGET_NR_setuid:
ret = get_errno(setuid(low2highuid(arg1)));
break;
case TARGET_NR_setgid:
ret = get_errno(setgid(low2highgid(arg1)));
break;
case TARGET_NR_setfsuid:
ret = get_errno(setfsuid(arg1));
break;
case TARGET_NR_setfsgid:
ret = get_errno(setfsgid(arg1));
break;
#endif /* USE_UID16 */
case TARGET_NR_lchown32:
ret = get_errno(lchown((const char *)arg1, arg2, arg3));
break;
@@ -2456,6 +2747,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
case TARGET_NR_setfsgid32:
ret = get_errno(setfsgid(arg1));
break;
case TARGET_NR_pivot_root:
goto unimplemented;
case TARGET_NR_mincore:
@@ -2496,13 +2788,21 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
break;
}
#endif
#ifdef TARGET_NR_security
case TARGET_NR_security:
goto unimplemented;
#endif
#ifdef TARGET_NR_getpagesize
case TARGET_NR_getpagesize:
ret = TARGET_PAGE_SIZE;
break;
#endif
case TARGET_NR_gettid:
ret = get_errno(gettid());
break;
case TARGET_NR_readahead:
goto unimplemented;
#ifdef TARGET_NR_setxattr
case TARGET_NR_setxattr:
case TARGET_NR_lsetxattr:
case TARGET_NR_fsetxattr:
@@ -2516,9 +2816,12 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
case TARGET_NR_lremovexattr:
case TARGET_NR_fremovexattr:
goto unimplemented_nowarn;
#endif
#ifdef TARGET_NR_set_thread_area
case TARGET_NR_set_thread_area:
case TARGET_NR_get_thread_area:
goto unimplemented_nowarn;
#endif
default:
unimplemented:
gemu_log("qemu: Unsupported syscall: %d\n", num);
@@ -2527,6 +2830,9 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
break;
}
fail:
#ifdef DEBUG
gemu_log(" = %ld\n", ret);
#endif
return ret;
}

View File

@@ -4,284 +4,7 @@
most of them stay the same, so we handle it by puting ifdefs if
necessary */
#define TARGET_NR_exit 1
#define TARGET_NR_fork 2
#define TARGET_NR_read 3
#define TARGET_NR_write 4
#define TARGET_NR_open 5
#define TARGET_NR_close 6
#define TARGET_NR_waitpid 7
#define TARGET_NR_creat 8
#define TARGET_NR_link 9
#define TARGET_NR_unlink 10
#define TARGET_NR_execve 11
#define TARGET_NR_chdir 12
#define TARGET_NR_time 13
#define TARGET_NR_mknod 14
#define TARGET_NR_chmod 15
#define TARGET_NR_lchown 16
#define TARGET_NR_break 17
#define TARGET_NR_oldstat 18
#define TARGET_NR_lseek 19
#define TARGET_NR_getpid 20
#define TARGET_NR_mount 21
#define TARGET_NR_umount 22
#define TARGET_NR_setuid 23
#define TARGET_NR_getuid 24
#define TARGET_NR_stime 25
#define TARGET_NR_ptrace 26
#define TARGET_NR_alarm 27
#define TARGET_NR_oldfstat 28
#define TARGET_NR_pause 29
#define TARGET_NR_utime 30
#define TARGET_NR_stty 31
#define TARGET_NR_gtty 32
#define TARGET_NR_access 33
#define TARGET_NR_nice 34
#define TARGET_NR_ftime 35
#define TARGET_NR_sync 36
#define TARGET_NR_kill 37
#define TARGET_NR_rename 38
#define TARGET_NR_mkdir 39
#define TARGET_NR_rmdir 40
#define TARGET_NR_dup 41
#define TARGET_NR_pipe 42
#define TARGET_NR_times 43
#define TARGET_NR_prof 44
#define TARGET_NR_brk 45
#define TARGET_NR_setgid 46
#define TARGET_NR_getgid 47
#define TARGET_NR_signal 48
#define TARGET_NR_geteuid 49
#define TARGET_NR_getegid 50
#define TARGET_NR_acct 51
#define TARGET_NR_umount2 52
#define TARGET_NR_lock 53
#define TARGET_NR_ioctl 54
#define TARGET_NR_fcntl 55
#define TARGET_NR_mpx 56
#define TARGET_NR_setpgid 57
#define TARGET_NR_ulimit 58
#define TARGET_NR_oldolduname 59
#define TARGET_NR_umask 60
#define TARGET_NR_chroot 61
#define TARGET_NR_ustat 62
#define TARGET_NR_dup2 63
#define TARGET_NR_getppid 64
#define TARGET_NR_getpgrp 65
#define TARGET_NR_setsid 66
#define TARGET_NR_sigaction 67
#define TARGET_NR_sgetmask 68
#define TARGET_NR_ssetmask 69
#define TARGET_NR_setreuid 70
#define TARGET_NR_setregid 71
#define TARGET_NR_sigsuspend 72
#define TARGET_NR_sigpending 73
#define TARGET_NR_sethostname 74
#define TARGET_NR_setrlimit 75
#define TARGET_NR_getrlimit 76 /* Back compatible 2Gig limited rlimit */
#define TARGET_NR_getrusage 77
#define TARGET_NR_gettimeofday 78
#define TARGET_NR_settimeofday 79
#define TARGET_NR_getgroups 80
#define TARGET_NR_setgroups 81
#define TARGET_NR_select 82
#define TARGET_NR_symlink 83
#define TARGET_NR_oldlstat 84
#define TARGET_NR_readlink 85
#define TARGET_NR_uselib 86
#define TARGET_NR_swapon 87
#define TARGET_NR_reboot 88
#define TARGET_NR_readdir 89
#define TARGET_NR_mmap 90
#define TARGET_NR_munmap 91
#define TARGET_NR_truncate 92
#define TARGET_NR_ftruncate 93
#define TARGET_NR_fchmod 94
#define TARGET_NR_fchown 95
#define TARGET_NR_getpriority 96
#define TARGET_NR_setpriority 97
#define TARGET_NR_profil 98
#define TARGET_NR_statfs 99
#define TARGET_NR_fstatfs 100
#define TARGET_NR_ioperm 101
#define TARGET_NR_socketcall 102
#define TARGET_NR_syslog 103
#define TARGET_NR_setitimer 104
#define TARGET_NR_getitimer 105
#define TARGET_NR_stat 106
#define TARGET_NR_lstat 107
#define TARGET_NR_fstat 108
#define TARGET_NR_olduname 109
#define TARGET_NR_iopl 110
#define TARGET_NR_vhangup 111
#define TARGET_NR_idle 112
#define TARGET_NR_vm86old 113
#define TARGET_NR_wait4 114
#define TARGET_NR_swapoff 115
#define TARGET_NR_sysinfo 116
#define TARGET_NR_ipc 117
#define TARGET_NR_fsync 118
#define TARGET_NR_sigreturn 119
#define TARGET_NR_clone 120
#define TARGET_NR_setdomainname 121
#define TARGET_NR_uname 122
#define TARGET_NR_modify_ldt 123
#define TARGET_NR_adjtimex 124
#define TARGET_NR_mprotect 125
#define TARGET_NR_sigprocmask 126
#define TARGET_NR_create_module 127
#define TARGET_NR_init_module 128
#define TARGET_NR_delete_module 129
#define TARGET_NR_get_kernel_syms 130
#define TARGET_NR_quotactl 131
#define TARGET_NR_getpgid 132
#define TARGET_NR_fchdir 133
#define TARGET_NR_bdflush 134
#define TARGET_NR_sysfs 135
#define TARGET_NR_personality 136
#define TARGET_NR_afs_syscall 137 /* Syscall for Andrew File System */
#define TARGET_NR_setfsuid 138
#define TARGET_NR_setfsgid 139
#define TARGET_NR__llseek 140
#define TARGET_NR_getdents 141
#define TARGET_NR__newselect 142
#define TARGET_NR_flock 143
#define TARGET_NR_msync 144
#define TARGET_NR_readv 145
#define TARGET_NR_writev 146
#define TARGET_NR_getsid 147
#define TARGET_NR_fdatasync 148
#define TARGET_NR__sysctl 149
#define TARGET_NR_mlock 150
#define TARGET_NR_munlock 151
#define TARGET_NR_mlockall 152
#define TARGET_NR_munlockall 153
#define TARGET_NR_sched_setparam 154
#define TARGET_NR_sched_getparam 155
#define TARGET_NR_sched_setscheduler 156
#define TARGET_NR_sched_getscheduler 157
#define TARGET_NR_sched_yield 158
#define TARGET_NR_sched_get_priority_max 159
#define TARGET_NR_sched_get_priority_min 160
#define TARGET_NR_sched_rr_get_interval 161
#define TARGET_NR_nanosleep 162
#define TARGET_NR_mremap 163
#define TARGET_NR_setresuid 164
#define TARGET_NR_getresuid 165
#define TARGET_NR_vm86 166
#define TARGET_NR_query_module 167
#define TARGET_NR_poll 168
#define TARGET_NR_nfsservctl 169
#define TARGET_NR_setresgid 170
#define TARGET_NR_getresgid 171
#define TARGET_NR_prctl 172
#define TARGET_NR_rt_sigreturn 173
#define TARGET_NR_rt_sigaction 174
#define TARGET_NR_rt_sigprocmask 175
#define TARGET_NR_rt_sigpending 176
#define TARGET_NR_rt_sigtimedwait 177
#define TARGET_NR_rt_sigqueueinfo 178
#define TARGET_NR_rt_sigsuspend 179
#define TARGET_NR_pread 180
#define TARGET_NR_pwrite 181
#define TARGET_NR_chown 182
#define TARGET_NR_getcwd 183
#define TARGET_NR_capget 184
#define TARGET_NR_capset 185
#define TARGET_NR_sigaltstack 186
#define TARGET_NR_sendfile 187
#define TARGET_NR_getpmsg 188 /* some people actually want streams */
#define TARGET_NR_putpmsg 189 /* some people actually want streams */
#define TARGET_NR_vfork 190
#define TARGET_NR_ugetrlimit 191 /* SuS compliant getrlimit */
#define TARGET_NR_mmap2 192
#define TARGET_NR_truncate64 193
#define TARGET_NR_ftruncate64 194
#define TARGET_NR_stat64 195
#define TARGET_NR_lstat64 196
#define TARGET_NR_fstat64 197
#define TARGET_NR_lchown32 198
#define TARGET_NR_getuid32 199
#define TARGET_NR_getgid32 200
#define TARGET_NR_geteuid32 201
#define TARGET_NR_getegid32 202
#define TARGET_NR_setreuid32 203
#define TARGET_NR_setregid32 204
#define TARGET_NR_getgroups32 205
#define TARGET_NR_setgroups32 206
#define TARGET_NR_fchown32 207
#define TARGET_NR_setresuid32 208
#define TARGET_NR_getresuid32 209
#define TARGET_NR_setresgid32 210
#define TARGET_NR_getresgid32 211
#define TARGET_NR_chown32 212
#define TARGET_NR_setuid32 213
#define TARGET_NR_setgid32 214
#define TARGET_NR_setfsuid32 215
#define TARGET_NR_setfsgid32 216
#if defined(TARGET_I386)
#define TARGET_NR_pivot_root 217
#define TARGET_NR_mincore 218
#define TARGET_NR_madvise 219
#define TARGET_NR_madvise1 219 /* delete when C lib stub is removed */
#define TARGET_NR_getdents64 220
#endif
#if defined(TARGET_ARM)
#define TARGET_NR_getdents64 217
#define TARGET_NR_pivot_root 218
#define TARGET_NR_mincore 219
#define TARGET_NR_madvise 220
#endif
#define TARGET_NR_fcntl64 221
#define TARGET_NR_security 223 /* syscall for security modules */
#define TARGET_NR_gettid 224
#define TARGET_NR_readahead 225
#define TARGET_NR_setxattr 226
#define TARGET_NR_lsetxattr 227
#define TARGET_NR_fsetxattr 228
#define TARGET_NR_getxattr 229
#define TARGET_NR_lgetxattr 230
#define TARGET_NR_fgetxattr 231
#define TARGET_NR_listxattr 232
#define TARGET_NR_llistxattr 233
#define TARGET_NR_flistxattr 234
#define TARGET_NR_removexattr 235
#define TARGET_NR_lremovexattr 236
#define TARGET_NR_fremovexattr 237
#define TARGET_NR_tkill 238
#define TARGET_NR_sendfile64 239
#define TARGET_NR_futex 240
#define TARGET_NR_sched_setaffinity 241
#define TARGET_NR_sched_getaffinity 242
#define TARGET_NR_set_thread_area 243
#define TARGET_NR_get_thread_area 244
#define TARGET_NR_io_setup 245
#define TARGET_NR_io_destroy 246
#define TARGET_NR_io_getevents 247
#define TARGET_NR_io_submit 248
#define TARGET_NR_io_cancel 249
#define TARGET_NR_fadvise64 250
#define TARGET_NR_exit_group 252
#define TARGET_NR_lookup_dcookie 253
#define TARGET_NR_epoll_create 254
#define TARGET_NR_epoll_ctl 255
#define TARGET_NR_epoll_wait 256
#define TARGET_NR_remap_file_pages 257
#define TARGET_NR_set_tid_address 258
#define TARGET_NR_timer_create 259
#define TARGET_NR_timer_settime (TARGET_NR_timer_create+1)
#define TARGET_NR_timer_gettime (TARGET_NR_timer_create+2)
#define TARGET_NR_timer_getoverrun (TARGET_NR_timer_create+3)
#define TARGET_NR_timer_delete (TARGET_NR_timer_create+4)
#define TARGET_NR_clock_settime (TARGET_NR_timer_create+5)
#define TARGET_NR_clock_gettime (TARGET_NR_timer_create+6)
#define TARGET_NR_clock_getres (TARGET_NR_timer_create+7)
#define TARGET_NR_clock_nanosleep (TARGET_NR_timer_create+8)
#include "syscall_nr.h"
#define SOCKOP_socket 1
#define SOCKOP_bind 2
@@ -321,7 +44,7 @@
#define TARGET_IOC_WRITE 1U
#define TARGET_IOC_READ 2U
#elif defined(TARGET_PPC) || defined(TARGET_ALPHA)
#elif defined(TARGET_PPC) || defined(TARGET_ALPHA) || defined(TARGET_SPARC)
#define TARGET_IOC_SIZEBITS 13
#define TARGET_IOC_DIRBITS 3
@@ -383,6 +106,8 @@ struct target_itimerval {
typedef target_long target_clock_t;
#define TARGET_HZ 100
struct target_tms {
target_clock_t tms_utime;
target_clock_t tms_stime;
@@ -390,6 +115,17 @@ struct target_tms {
target_clock_t tms_cstime;
};
struct target_utimbuf {
target_long actime;
target_long modtime;
};
struct target_sel_arg_struct {
target_long n;
target_long inp, outp, exp;
target_long tvp;
};
struct target_iovec {
target_long iov_base; /* Starting address */
target_long iov_len; /* Number of bytes */
@@ -533,8 +269,8 @@ static inline void target_siginitset(target_sigset_t *d, target_ulong set)
d->sig[i] = 0;
}
void host_to_target_sigset(target_sigset_t *d, sigset_t *s);
void target_to_host_sigset(sigset_t *d, target_sigset_t *s);
void host_to_target_sigset(target_sigset_t *d, const sigset_t *s);
void target_to_host_sigset(sigset_t *d, const target_sigset_t *s);
void host_to_target_old_sigset(target_ulong *old_sigset,
const sigset_t *sigset);
void target_to_host_old_sigset(sigset_t *sigset,
@@ -543,7 +279,7 @@ struct target_sigaction;
int do_sigaction(int sig, const struct target_sigaction *act,
struct target_sigaction *oact);
#if defined(TARGET_I386) || defined(TARGET_ARM)
#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SPARC) || defined(TARGET_PPC)
#define TARGET_SA_NOCLDSTOP 0x00000001
#define TARGET_SA_NOCLDWAIT 0x00000002 /* not supported yet */
@@ -584,6 +320,8 @@ int do_sigaction(int sig, const struct target_sigaction *act,
#define TARGET_SIGPROF 27
#define TARGET_SIGWINCH 28
#define TARGET_SIGIO 29
#define TARGET_SIGPWR 30
#define TARGET_SIGSYS 31
#define TARGET_SIGRTMIN 32
#define TARGET_SIG_BLOCK 0 /* for blocking signals */
@@ -926,220 +664,26 @@ struct target_pollfd {
#define TARGET_HDIO_SET_PIO_MODE 0x0327 /* reconfig interface to new speed */
#if defined(TARGET_I386) || defined(TARGET_ARM)
/* 0x54 is just a magic number to make these relatively unique ('T') */
#define TARGET_TCGETS 0x5401
#define TARGET_TCSETS 0x5402
#define TARGET_TCSETSW 0x5403
#define TARGET_TCSETSF 0x5404
#define TARGET_TCGETA 0x5405
#define TARGET_TCSETA 0x5406
#define TARGET_TCSETAW 0x5407
#define TARGET_TCSETAF 0x5408
#define TARGET_TCSBRK 0x5409
#define TARGET_TCXONC 0x540A
#define TARGET_TCFLSH 0x540B
#define TARGET_TIOCEXCL 0x540C
#define TARGET_TIOCNXCL 0x540D
#define TARGET_TIOCSCTTY 0x540E
#define TARGET_TIOCGPGRP 0x540F
#define TARGET_TIOCSPGRP 0x5410
#define TARGET_TIOCOUTQ 0x5411
#define TARGET_TIOCSTI 0x5412
#define TARGET_TIOCGWINSZ 0x5413
#define TARGET_TIOCSWINSZ 0x5414
#define TARGET_TIOCMGET 0x5415
#define TARGET_TIOCMBIS 0x5416
#define TARGET_TIOCMBIC 0x5417
#define TARGET_TIOCMSET 0x5418
#define TARGET_TIOCGSOFTCAR 0x5419
#define TARGET_TIOCSSOFTCAR 0x541A
#define TARGET_FIONREAD 0x541B
#define TARGET_TIOCINQ FIONREAD
#define TARGET_TIOCLINUX 0x541C
#define TARGET_TIOCCONS 0x541D
#define TARGET_TIOCGSERIAL 0x541E
#define TARGET_TIOCSSERIAL 0x541F
#define TARGET_TIOCPKT 0x5420
#define TARGET_FIONBIO 0x5421
#define TARGET_TIOCNOTTY 0x5422
#define TARGET_TIOCSETD 0x5423
#define TARGET_TIOCGETD 0x5424
#define TARGET_TCSBRKP 0x5425 /* Needed for POSIX tcsendbreak() */
#define TARGET_TIOCTTYGSTRUCT 0x5426 /* For debugging only */
#define TARGET_TIOCSBRK 0x5427 /* BSD compatibility */
#define TARGET_TIOCCBRK 0x5428 /* BSD compatibility */
#define TARGET_TIOCGSID 0x5429 /* Return the session ID of FD */
#define TARGET_TIOCGPTN TARGET_IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */
#define TARGET_TIOCSPTLCK TARGET_IOW('T',0x31, int) /* Lock/unlock Pty */
#define TARGET_FIONCLEX 0x5450 /* these numbers need to be adjusted. */
#define TARGET_FIOCLEX 0x5451
#define TARGET_FIOASYNC 0x5452
#define TARGET_TIOCSERCONFIG 0x5453
#define TARGET_TIOCSERGWILD 0x5454
#define TARGET_TIOCSERSWILD 0x5455
#define TARGET_TIOCGLCKTRMIOS 0x5456
#define TARGET_TIOCSLCKTRMIOS 0x5457
#define TARGET_TIOCSERGSTRUCT 0x5458 /* For debugging only */
#define TARGET_TIOCSERGETLSR 0x5459 /* Get line status register */
#define TARGET_TIOCSERGETMULTI 0x545A /* Get multiport config */
#define TARGET_TIOCSERSETMULTI 0x545B /* Set multiport config */
#define TARGET_TIOCMIWAIT 0x545C /* wait for a change on serial input line(s) */
#define TARGET_TIOCGICOUNT 0x545D /* read serial port inline interrupt counts */
#define TARGET_TIOCGHAYESESP 0x545E /* Get Hayes ESP configuration */
#define TARGET_TIOCSHAYESESP 0x545F /* Set Hayes ESP configuration */
/* Used for packet mode */
#define TARGET_TIOCPKT_DATA 0
#define TARGET_TIOCPKT_FLUSHREAD 1
#define TARGET_TIOCPKT_FLUSHWRITE 2
#define TARGET_TIOCPKT_STOP 4
#define TARGET_TIOCPKT_START 8
#define TARGET_TIOCPKT_NOSTOP 16
#define TARGET_TIOCPKT_DOSTOP 32
#define TARGET_TIOCSER_TEMT 0x01 /* Transmitter physically empty */
/* from asm/termbits.h */
#define TARGET_NCCS 19
struct target_termios {
unsigned int c_iflag; /* input mode flags */
unsigned int c_oflag; /* output mode flags */
unsigned int c_cflag; /* control mode flags */
unsigned int c_lflag; /* local mode flags */
unsigned char c_line; /* line discipline */
unsigned char c_cc[TARGET_NCCS]; /* control characters */
#define TARGET_NCC 8
struct target_termio {
unsigned short c_iflag; /* input mode flags */
unsigned short c_oflag; /* output mode flags */
unsigned short c_cflag; /* control mode flags */
unsigned short c_lflag; /* local mode flags */
unsigned char c_line; /* line discipline */
unsigned char c_cc[TARGET_NCC]; /* control characters */
};
/* c_iflag bits */
#define TARGET_IGNBRK 0000001
#define TARGET_BRKINT 0000002
#define TARGET_IGNPAR 0000004
#define TARGET_PARMRK 0000010
#define TARGET_INPCK 0000020
#define TARGET_ISTRIP 0000040
#define TARGET_INLCR 0000100
#define TARGET_IGNCR 0000200
#define TARGET_ICRNL 0000400
#define TARGET_IUCLC 0001000
#define TARGET_IXON 0002000
#define TARGET_IXANY 0004000
#define TARGET_IXOFF 0010000
#define TARGET_IMAXBEL 0020000
struct target_winsize {
unsigned short ws_row;
unsigned short ws_col;
unsigned short ws_xpixel;
unsigned short ws_ypixel;
};
/* c_oflag bits */
#define TARGET_OPOST 0000001
#define TARGET_OLCUC 0000002
#define TARGET_ONLCR 0000004
#define TARGET_OCRNL 0000010
#define TARGET_ONOCR 0000020
#define TARGET_ONLRET 0000040
#define TARGET_OFILL 0000100
#define TARGET_OFDEL 0000200
#define TARGET_NLDLY 0000400
#define TARGET_NL0 0000000
#define TARGET_NL1 0000400
#define TARGET_CRDLY 0003000
#define TARGET_CR0 0000000
#define TARGET_CR1 0001000
#define TARGET_CR2 0002000
#define TARGET_CR3 0003000
#define TARGET_TABDLY 0014000
#define TARGET_TAB0 0000000
#define TARGET_TAB1 0004000
#define TARGET_TAB2 0010000
#define TARGET_TAB3 0014000
#define TARGET_XTABS 0014000
#define TARGET_BSDLY 0020000
#define TARGET_BS0 0000000
#define TARGET_BS1 0020000
#define TARGET_VTDLY 0040000
#define TARGET_VT0 0000000
#define TARGET_VT1 0040000
#define TARGET_FFDLY 0100000
#define TARGET_FF0 0000000
#define TARGET_FF1 0100000
/* c_cflag bit meaning */
#define TARGET_CBAUD 0010017
#define TARGET_B0 0000000 /* hang up */
#define TARGET_B50 0000001
#define TARGET_B75 0000002
#define TARGET_B110 0000003
#define TARGET_B134 0000004
#define TARGET_B150 0000005
#define TARGET_B200 0000006
#define TARGET_B300 0000007
#define TARGET_B600 0000010
#define TARGET_B1200 0000011
#define TARGET_B1800 0000012
#define TARGET_B2400 0000013
#define TARGET_B4800 0000014
#define TARGET_B9600 0000015
#define TARGET_B19200 0000016
#define TARGET_B38400 0000017
#define TARGET_EXTA B19200
#define TARGET_EXTB B38400
#define TARGET_CSIZE 0000060
#define TARGET_CS5 0000000
#define TARGET_CS6 0000020
#define TARGET_CS7 0000040
#define TARGET_CS8 0000060
#define TARGET_CSTOPB 0000100
#define TARGET_CREAD 0000200
#define TARGET_PARENB 0000400
#define TARGET_PARODD 0001000
#define TARGET_HUPCL 0002000
#define TARGET_CLOCAL 0004000
#define TARGET_CBAUDEX 0010000
#define TARGET_B57600 0010001
#define TARGET_B115200 0010002
#define TARGET_B230400 0010003
#define TARGET_B460800 0010004
#define TARGET_CIBAUD 002003600000 /* input baud rate (not used) */
#define TARGET_CRTSCTS 020000000000 /* flow control */
/* c_lflag bits */
#define TARGET_ISIG 0000001
#define TARGET_ICANON 0000002
#define TARGET_XCASE 0000004
#define TARGET_ECHO 0000010
#define TARGET_ECHOE 0000020
#define TARGET_ECHOK 0000040
#define TARGET_ECHONL 0000100
#define TARGET_NOFLSH 0000200
#define TARGET_TOSTOP 0000400
#define TARGET_ECHOCTL 0001000
#define TARGET_ECHOPRT 0002000
#define TARGET_ECHOKE 0004000
#define TARGET_FLUSHO 0010000
#define TARGET_PENDIN 0040000
#define TARGET_IEXTEN 0100000
/* c_cc character offsets */
#define TARGET_VINTR 0
#define TARGET_VQUIT 1
#define TARGET_VERASE 2
#define TARGET_VKILL 3
#define TARGET_VEOF 4
#define TARGET_VTIME 5
#define TARGET_VMIN 6
#define TARGET_VSWTC 7
#define TARGET_VSTART 8
#define TARGET_VSTOP 9
#define TARGET_VSUSP 10
#define TARGET_VEOL 11
#define TARGET_VREPRINT 12
#define TARGET_VDISCARD 13
#define TARGET_VWERASE 14
#define TARGET_VLNEXT 15
#define TARGET_VEOL2 16
#include "termbits.h"
#define TARGET_MAP_SHARED 0x01 /* Share changes */
#define TARGET_MAP_PRIVATE 0x02 /* Changes are private */
@@ -1153,6 +697,7 @@ struct target_termios {
#define TARGET_MAP_LOCKED 0x2000 /* pages are locked */
#define TARGET_MAP_NORESERVE 0x4000 /* don't check for reservations */
#if defined(TARGET_I386) || defined(TARGET_ARM)
struct target_stat {
unsigned short st_dev;
unsigned short __pad1;
@@ -1213,7 +758,111 @@ struct target_stat64 {
unsigned long long st_ino;
} __attribute__((packed));
#endif /* defined(TARGET_I386) || defined(TARGET_ARM) */
#elif defined(TARGET_SPARC)
struct target_stat {
unsigned short st_dev;
target_ulong st_ino;
unsigned short st_mode;
short st_nlink;
unsigned short st_uid;
unsigned short st_gid;
unsigned short st_rdev;
target_long st_size;
target_long target_st_atime;
target_ulong __unused1;
target_long target_st_mtime;
target_ulong __unused2;
target_long target_st_ctime;
target_ulong __unused3;
target_long st_blksize;
target_long st_blocks;
target_ulong __unused4[2];
};
struct target_stat64 {
unsigned char __pad0[6];
unsigned short st_dev;
uint64_t st_ino;
unsigned int st_mode;
unsigned int st_nlink;
unsigned int st_uid;
unsigned int st_gid;
unsigned char __pad2[6];
unsigned short st_rdev;
unsigned char __pad3[8];
int64_t st_size;
unsigned int st_blksize;
unsigned char __pad4[8];
unsigned int st_blocks;
unsigned int target_st_atime;
unsigned int __unused1;
unsigned int target_st_mtime;
unsigned int __unused2;
unsigned int target_st_ctime;
unsigned int __unused3;
unsigned int __unused4;
unsigned int __unused5;
};
#elif defined(TARGET_PPC)
struct target_stat {
unsigned short st_dev;
target_ulong st_ino;
unsigned int st_mode;
unsigned short st_nlink;
unsigned int st_uid;
unsigned int st_gid;
unsigned short st_rdev;
target_ulong st_size;
target_ulong st_blksize;
target_ulong st_blocks;
target_ulong target_st_atime;
target_ulong __unused1;
target_ulong target_st_mtime;
target_ulong __unused2;
target_ulong target_st_ctime;
target_ulong __unused3;
target_ulong __unused4;
target_ulong __unused5;
};
struct target_stat64 {
unsigned long long st_dev;
unsigned long long st_ino;
unsigned int st_mode;
unsigned int st_nlink;
unsigned int st_uid;
unsigned int st_gid;
unsigned long long st_rdev;
long long pad0;
long long st_size;
target_ulong st_blksize;
target_ulong pad1;
long long st_blocks; /* Number 512-byte blocks allocated. */
target_ulong target_st_atime;
target_ulong target_st_atime_nsec;
target_ulong target_st_mtime;
target_ulong target_st_mtime_nsec;
target_ulong target_st_ctime;
target_ulong target_st_ctime_nsec;
target_ulong __unused4;
target_ulong __unused5;
};
#endif /* defined(TARGET_PPC) */
#define TARGET_F_DUPFD 0 /* dup */
#define TARGET_F_GETFD 1 /* get close_on_exec */

177
m68k.ld Normal file
View File

@@ -0,0 +1,177 @@
/* Script for -z combreloc: combine and sort reloc sections */
OUTPUT_FORMAT("elf32-m68k", "elf32-m68k",
"elf32-m68k")
OUTPUT_ARCH(m68k)
ENTRY(_start)
SEARCH_DIR("/usr/local/m68k-linux/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.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.bss .rela.bss.* .rela.gnu.linkonce.b.*)
}
.rel.plt : { *(.rel.plt) }
.rela.plt : { *(.rela.plt) }
.init :
{
KEEP (*(.init))
} =0x4e754e75
.plt : { *(.plt) }
.text :
{
*(.text .stub .text.* .gnu.linkonce.t.*)
/* .gnu.warning sections are handled specially by elf32.em. */
*(.gnu.warning)
} =0x4e754e75
.fini :
{
KEEP (*(.fini))
} =0x4e754e75
PROVIDE (__etext = .);
PROVIDE (_etext = .);
PROVIDE (etext = .);
.rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
.rodata1 : { *(.rodata1) }
.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(0x2000) + (. & (0x2000 - 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) }
_edata = .;
PROVIDE (edata = .);
__bss_start = .;
.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

@@ -1,245 +0,0 @@
void OPPROTO glue(glue(op_movs, SUFFIX), STRING_SUFFIX)(void)
{
int v, inc;
inc = (DF << SHIFT);
v = glue(ldu, SUFFIX)(SI_ADDR);
glue(st, SUFFIX)(DI_ADDR, v);
inc = (DF << SHIFT);
INC_SI();
INC_DI();
}
void OPPROTO glue(glue(op_rep_movs, SUFFIX), STRING_SUFFIX)(void)
{
int v, inc;
inc = (DF << SHIFT);
while (CX != 0) {
v = glue(ldu, SUFFIX)(SI_ADDR);
glue(st, SUFFIX)(DI_ADDR, v);
INC_SI();
INC_DI();
DEC_CX();
}
FORCE_RET();
}
void OPPROTO glue(glue(op_stos, SUFFIX), STRING_SUFFIX)(void)
{
int inc;
glue(st, SUFFIX)(DI_ADDR, EAX);
inc = (DF << SHIFT);
INC_DI();
}
void OPPROTO glue(glue(op_rep_stos, SUFFIX), STRING_SUFFIX)(void)
{
int inc;
inc = (DF << SHIFT);
while (CX != 0) {
glue(st, SUFFIX)(DI_ADDR, EAX);
INC_DI();
DEC_CX();
}
FORCE_RET();
}
void OPPROTO glue(glue(op_lods, SUFFIX), STRING_SUFFIX)(void)
{
int v, inc;
v = glue(ldu, SUFFIX)(SI_ADDR);
#if SHIFT == 0
EAX = (EAX & ~0xff) | v;
#elif SHIFT == 1
EAX = (EAX & ~0xffff) | v;
#else
EAX = v;
#endif
inc = (DF << SHIFT);
INC_SI();
}
/* don't know if it is used */
void OPPROTO glue(glue(op_rep_lods, SUFFIX), STRING_SUFFIX)(void)
{
int v, inc;
inc = (DF << SHIFT);
while (CX != 0) {
v = glue(ldu, SUFFIX)(SI_ADDR);
#if SHIFT == 0
EAX = (EAX & ~0xff) | v;
#elif SHIFT == 1
EAX = (EAX & ~0xffff) | v;
#else
EAX = v;
#endif
INC_SI();
DEC_CX();
}
FORCE_RET();
}
void OPPROTO glue(glue(op_scas, SUFFIX), STRING_SUFFIX)(void)
{
int v, inc;
v = glue(ldu, SUFFIX)(DI_ADDR);
inc = (DF << SHIFT);
INC_DI();
CC_SRC = EAX;
CC_DST = EAX - v;
}
void OPPROTO glue(glue(op_repz_scas, SUFFIX), STRING_SUFFIX)(void)
{
int v1, v2, inc;
if (CX != 0) {
/* NOTE: the flags are not modified if CX == 0 */
v1 = EAX & DATA_MASK;
inc = (DF << SHIFT);
do {
v2 = glue(ldu, SUFFIX)(DI_ADDR);
INC_DI();
DEC_CX();
if (v1 != v2)
break;
} while (CX != 0);
CC_SRC = v1;
CC_DST = v1 - v2;
CC_OP = CC_OP_SUBB + SHIFT;
}
FORCE_RET();
}
void OPPROTO glue(glue(op_repnz_scas, SUFFIX), STRING_SUFFIX)(void)
{
int v1, v2, inc;
if (CX != 0) {
/* NOTE: the flags are not modified if CX == 0 */
v1 = EAX & DATA_MASK;
inc = (DF << SHIFT);
do {
v2 = glue(ldu, SUFFIX)(DI_ADDR);
INC_DI();
DEC_CX();
if (v1 == v2)
break;
} while (CX != 0);
CC_SRC = v1;
CC_DST = v1 - v2;
CC_OP = CC_OP_SUBB + SHIFT;
}
FORCE_RET();
}
void OPPROTO glue(glue(op_cmps, SUFFIX), STRING_SUFFIX)(void)
{
int v1, v2, inc;
v1 = glue(ldu, SUFFIX)(SI_ADDR);
v2 = glue(ldu, SUFFIX)(DI_ADDR);
inc = (DF << SHIFT);
INC_SI();
INC_DI();
CC_SRC = v1;
CC_DST = v1 - v2;
}
void OPPROTO glue(glue(op_repz_cmps, SUFFIX), STRING_SUFFIX)(void)
{
int v1, v2, inc;
if (CX != 0) {
inc = (DF << SHIFT);
do {
v1 = glue(ldu, SUFFIX)(SI_ADDR);
v2 = glue(ldu, SUFFIX)(DI_ADDR);
INC_SI();
INC_DI();
DEC_CX();
if (v1 != v2)
break;
} while (CX != 0);
CC_SRC = v1;
CC_DST = v1 - v2;
CC_OP = CC_OP_SUBB + SHIFT;
}
FORCE_RET();
}
void OPPROTO glue(glue(op_repnz_cmps, SUFFIX), STRING_SUFFIX)(void)
{
int v1, v2, inc;
if (CX != 0) {
inc = (DF << SHIFT);
do {
v1 = glue(ldu, SUFFIX)(SI_ADDR);
v2 = glue(ldu, SUFFIX)(DI_ADDR);
INC_SI();
INC_DI();
DEC_CX();
if (v1 == v2)
break;
} while (CX != 0);
CC_SRC = v1;
CC_DST = v1 - v2;
CC_OP = CC_OP_SUBB + SHIFT;
}
FORCE_RET();
}
void OPPROTO glue(glue(op_outs, SUFFIX), STRING_SUFFIX)(void)
{
int v, dx, inc;
dx = EDX & 0xffff;
v = glue(ldu, SUFFIX)(SI_ADDR);
glue(cpu_x86_out, SUFFIX)(env, dx, v);
inc = (DF << SHIFT);
INC_SI();
}
void OPPROTO glue(glue(op_rep_outs, SUFFIX), STRING_SUFFIX)(void)
{
int v, dx, inc;
inc = (DF << SHIFT);
dx = EDX & 0xffff;
while (CX != 0) {
v = glue(ldu, SUFFIX)(SI_ADDR);
glue(cpu_x86_out, SUFFIX)(env, dx, v);
INC_SI();
DEC_CX();
}
FORCE_RET();
}
void OPPROTO glue(glue(op_ins, SUFFIX), STRING_SUFFIX)(void)
{
int v, dx, inc;
dx = EDX & 0xffff;
v = glue(cpu_x86_in, SUFFIX)(env, dx);
glue(st, SUFFIX)(DI_ADDR, v);
inc = (DF << SHIFT);
INC_DI();
}
void OPPROTO glue(glue(op_rep_ins, SUFFIX), STRING_SUFFIX)(void)
{
int v, dx, inc;
inc = (DF << SHIFT);
dx = EDX & 0xffff;
while (CX != 0) {
v = glue(cpu_x86_in, SUFFIX)(env, dx);
glue(st, SUFFIX)(DI_ADDR, v);
INC_DI();
DEC_CX();
}
FORCE_RET();
}
#undef STRING_SUFFIX
#undef SI_ADDR
#undef DI_ADDR
#undef INC_SI
#undef INC_DI
#undef CX
#undef DEC_CX

512
oss.c Normal file
View File

@@ -0,0 +1,512 @@
/*
* QEMU OSS Audio output driver
*
* Copyright (c) 2003 Vassili Karpov (malc)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <fcntl.h>
#include <errno.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <limits.h>
#include <inttypes.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/soundcard.h>
#include "vl.h"
/* http://www.df.lth.se/~john_e/gems/gem002d.html */
/* http://www.multi-platforms.com/Tips/PopCount.htm */
static inline uint32_t popcount (uint32_t u)
{
u = ((u&0x55555555) + ((u>>1)&0x55555555));
u = ((u&0x33333333) + ((u>>2)&0x33333333));
u = ((u&0x0f0f0f0f) + ((u>>4)&0x0f0f0f0f));
u = ((u&0x00ff00ff) + ((u>>8)&0x00ff00ff));
u = ( u&0x0000ffff) + (u>>16);
return u;
}
static inline uint32_t lsbindex (uint32_t u)
{
return popcount ((u&-u)-1);
}
#define MIN(a, b) ((a)>(b)?(b):(a))
#define MAX(a, b) ((a)<(b)?(b):(a))
#define DEREF(x) (void)x
#define log(...) fprintf (stderr, "oss: " __VA_ARGS__)
#define ERRFail(...) do { \
int _errno = errno; \
fprintf (stderr, "oss: " __VA_ARGS__); \
fprintf (stderr, "system error: %s\n", strerror (_errno)); \
abort (); \
} while (0)
#define Fail(...) do { \
fprintf (stderr, "oss: " __VA_ARGS__); \
fprintf (stderr, "\n"); \
abort (); \
} while (0)
#ifdef DEBUG_OSS
#define lwarn(...) fprintf (stderr, "oss: " __VA_ARGS__)
#define linfo(...) fprintf (stderr, "oss: " __VA_ARGS__)
#define ldebug(...) fprintf (stderr, "oss: " __VA_ARGS__)
#else
#define lwarn(...)
#define linfo(...)
#define ldebug(...)
#endif
#define IOCTL(args) do { \
int ret = ioctl args; \
if (-1 == ret) { \
ERRFail (#args); \
} \
ldebug ("ioctl " #args " = %d\n", ret); \
} while (0)
static int audio_fd = -1;
static int freq;
static int conf_nfrags = 4;
static int conf_fragsize;
static int nfrags;
static int fragsize;
static int bufsize;
static int nchannels;
static int fmt;
static int rpos;
static int wpos;
static int atom;
static int live;
static int leftover;
static int bytes_per_second;
static void *buf;
static enum {DONT, DSP, TID} estimate = TID;
static void (*copy_fn)(void *, void *, int);
static void copy_no_conversion (void *dst, void *src, int size)
{
memcpy (dst, src, size);
}
static void copy_u16_to_s16 (void *dst, void *src, int size)
{
int i;
uint16_t *out, *in;
out = dst;
in = src;
for (i = 0; i < size / 2; i++) {
out[i] = in[i] + 0x8000;
}
}
static void pab (struct audio_buf_info *abinfo)
{
DEREF (abinfo);
ldebug ("fragments %d, fragstotal %d, fragsize %d, bytes %d\n"
"rpos %d, wpos %d, live %d\n",
abinfo->fragments,
abinfo->fragstotal,
abinfo->fragsize,
abinfo->bytes,
rpos, wpos, live);
}
void AUD_reset (int rfreq, int rnchannels, audfmt_e rfmt)
{
int fmt_;
int bits16;
if (-1 == audio_fd) {
AUD_open (rfreq, rnchannels, rfmt);
return;
}
switch (rfmt) {
case AUD_FMT_U8:
bits16 = 0;
fmt_ = AFMT_U8;
copy_fn = copy_no_conversion;
atom = 1;
break;
case AUD_FMT_S8:
Fail ("can not play 8bit signed");
case AUD_FMT_S16:
bits16 = 1;
fmt_ = AFMT_S16_LE;
copy_fn = copy_no_conversion;
atom = 2;
break;
case AUD_FMT_U16:
bits16 = 1;
fmt_ = AFMT_S16_LE;
copy_fn = copy_u16_to_s16;
atom = 2;
break;
default:
abort ();
}
if ((fmt_ == fmt) && (bits16 + 1 == nchannels) && (rfreq == freq))
return;
else {
AUD_open (rfreq, rnchannels, rfmt);
}
}
void AUD_open (int rfreq, int rnchannels, audfmt_e rfmt)
{
int fmt_;
int mmmmssss;
struct audio_buf_info abinfo;
int _fmt;
int _freq;
int _nchannels;
int bits16;
bits16 = 0;
switch (rfmt) {
case AUD_FMT_U8:
bits16 = 0;
fmt_ = AFMT_U8;
copy_fn = copy_no_conversion;
atom = 1;
break;
case AUD_FMT_S8:
Fail ("can not play 8bit signed");
case AUD_FMT_S16:
bits16 = 1;
fmt_ = AFMT_S16_LE;
copy_fn = copy_no_conversion;
atom = 2;
break;
case AUD_FMT_U16:
bits16 = 1;
fmt_ = AFMT_S16_LE;
copy_fn = copy_u16_to_s16;
atom = 2;
break;
default:
abort ();
}
if (buf) {
free (buf);
buf = 0;
}
if (-1 != audio_fd)
close (audio_fd);
audio_fd = open ("/dev/dsp", O_WRONLY | O_NONBLOCK);
if (-1 == audio_fd) {
ERRFail ("can not open /dev/dsp");
}
_fmt = fmt_;
_freq = rfreq;
_nchannels = rnchannels;
IOCTL ((audio_fd, SNDCTL_DSP_RESET, 1));
IOCTL ((audio_fd, SNDCTL_DSP_SAMPLESIZE, &_fmt));
IOCTL ((audio_fd, SNDCTL_DSP_CHANNELS, &_nchannels));
IOCTL ((audio_fd, SNDCTL_DSP_SPEED, &_freq));
IOCTL ((audio_fd, SNDCTL_DSP_NONBLOCK));
/* from oss.pdf:
The argument to this call is an integer encoded as 0xMMMMSSSS (in
hex). The 16 least significant bits determine the fragment
size. The size is 2^SSSS. For examp le SSSS=0008 gives fragment
size of 256 bytes (2^8). The minimum is 16 bytes (SSSS=4) and the
maximum is total_buffer_size/2. Some devices or processor
architectures may require larger fragments - in this case the
requested fragment size is automatically increased.
So ahem... 4096 = 2^12, and grand total 0x0004000c
*/
mmmmssss = (conf_nfrags << 16) | conf_fragsize;
IOCTL ((audio_fd, SNDCTL_DSP_SETFRAGMENT, &mmmmssss));
linfo ("_fmt = %d, fmt = %d\n"
"_channels = %d, rnchannels = %d\n"
"_freq = %d, freq = %d\n",
_fmt, fmt_,
_nchannels, rnchannels,
_freq, rfreq);
if (_fmt != fmt_) {
Fail ("format %d != %d", _fmt, fmt_);
}
if (_nchannels != rnchannels) {
Fail ("channels %d != %d", _nchannels, rnchannels);
}
if (_freq != rfreq) {
Fail ("freq %d != %d", _freq, rfreq);
}
IOCTL ((audio_fd, SNDCTL_DSP_GETOSPACE, &abinfo));
nfrags = abinfo.fragstotal;
fragsize = abinfo.fragsize;
freq = _freq;
fmt = _fmt;
nchannels = rnchannels;
atom <<= nchannels >> 1;
bufsize = nfrags * fragsize;
bytes_per_second = (freq << (nchannels >> 1)) << bits16;
linfo ("bytes per second %d\n", bytes_per_second);
linfo ("fragments %d, fragstotal %d, fragsize %d, bytes %d, bufsize %d\n",
abinfo.fragments,
abinfo.fragstotal,
abinfo.fragsize,
abinfo.bytes,
bufsize);
if (NULL == buf) {
buf = malloc (bufsize);
if (NULL == buf) {
abort ();
}
}
rpos = 0;
wpos = 0;
live = 0;
}
int AUD_write (void *in_buf, int size)
{
int to_copy, temp;
uint8_t *in, *out;
to_copy = MIN (bufsize - live, size);
temp = to_copy;
in = in_buf;
out = buf;
while (temp) {
int copy;
copy = MIN (temp, bufsize - wpos);
copy_fn (out + wpos, in, copy);
wpos += copy;
if (wpos == bufsize) {
wpos = 0;
}
temp -= copy;
in += copy;
live += copy;
}
return to_copy;
}
void AUD_run (void)
{
int res;
int bytes;
struct audio_buf_info abinfo;
if (0 == live)
return;
res = ioctl (audio_fd, SNDCTL_DSP_GETOSPACE, &abinfo);
if (-1 == res) {
int err;
err = errno;
lwarn ("SNDCTL_DSP_GETOSPACE failed with %s\n", strerror (err));
}
bytes = abinfo.bytes;
bytes = MIN (live, bytes);
#if 0
bytes = (bytes / fragsize) * fragsize;
#endif
while (bytes) {
int left, play, written;
left = bufsize - rpos;
play = MIN (left, bytes);
written = write (audio_fd, (void *) ((uint32_t) buf + rpos), play);
if (-1 == written) {
if (EAGAIN == errno || EINTR == errno) {
return;
}
else {
ERRFail ("write audio");
}
}
play = written;
live -= play;
rpos += play;
bytes -= play;
if (rpos == bufsize) {
rpos = 0;
}
}
}
static int get_dsp_bytes (void)
{
int res;
struct count_info info;
res = ioctl (audio_fd, SNDCTL_DSP_GETOPTR, &info);
if (-1 == res) {
int err;
err = errno;
lwarn ("SNDCTL_DSP_GETOPTR failed with %s\n", strerror (err));
return -1;
}
else {
ldebug ("bytes %d\n", info.bytes);
return info.bytes;
}
}
void AUD_adjust_estimate (int _leftover)
{
leftover = _leftover;
}
int AUD_get_free (void)
{
int free, elapsed;
free = bufsize - live;
if (0 == free)
return 0;
elapsed = free;
switch (estimate) {
case DONT:
break;
case DSP:
{
static int old_bytes;
int bytes;
bytes = get_dsp_bytes ();
if (bytes <= 0)
return free;
elapsed = bytes - old_bytes;
old_bytes = bytes;
ldebug ("dsp elapsed %d bytes\n", elapsed);
break;
}
case TID:
{
static uint64_t old_ticks;
uint64_t ticks, delta;
uint64_t ua_elapsed;
uint64_t al_elapsed;
ticks = cpu_get_ticks ();
delta = ticks - old_ticks;
old_ticks = ticks;
ua_elapsed = (delta * bytes_per_second) / ticks_per_sec;
al_elapsed = ua_elapsed & ~3ULL;
ldebug ("tid elapsed %llu bytes\n", ua_elapsed);
if (al_elapsed > (uint64_t) INT_MAX)
elapsed = INT_MAX;
else
elapsed = al_elapsed;
elapsed += leftover;
}
}
if (elapsed > free) {
lwarn ("audio can not keep up elapsed %d free %d\n", elapsed, free);
return free;
}
else {
return elapsed;
}
}
int AUD_get_live (void)
{
return live;
}
int AUD_get_buffer_size (void)
{
return bufsize;
}
void AUD_init (void)
{
int fsp;
int _fragsize = 4096;
DEREF (pab);
fsp = _fragsize;
if (0 != (fsp & (fsp - 1))) {
Fail ("fragment size %d is not power of 2", fsp);
}
conf_fragsize = lsbindex (fsp);
}

4
pc-bios/README Normal file
View File

@@ -0,0 +1,4 @@
- The PC BIOS comes from the Bochs project
(http://bochs.sourceforge.net/).
- The VGA BIOS comes from the LGPL VGA bios project
(http://www.nongnu.org/vgabios/).

BIN
pc-bios/bios.bin Normal file

Binary file not shown.

BIN
pc-bios/vgabios.bin Normal file

Binary file not shown.

View File

@@ -3074,7 +3074,8 @@ static int print_insn_powerpc(FILE *, unsigned long insn, unsigned memaddr, int
int print_insn_ppc (bfd_vma pc, disassemble_info *info)
{
return print_insn_powerpc (info->stream, *(unsigned *)(long)pc, pc,
return print_insn_powerpc (info->stream,
(unsigned int)bfd_getb32((bfd_byte *)pc), pc,
PPC_OPCODE_PPC | PPC_OPCODE_601);
}

3
qemu-binfmt-conf.sh Normal file
View File

@@ -0,0 +1,3 @@
# enable automatic i386 program execution by the kernel (must enable binfmt_misc)
echo ':i386:M::\x7fELF\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x03:\xff\xff\xff\xff\xff\xfe\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfb\xff\xff:/usr/local/bin/qemu-i386:' > /proc/sys/fs/binfmt_misc/register
echo ':i486:M::\x7fELF\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x06:\xff\xff\xff\xff\xff\xfe\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfb\xff\xff:/usr/local/bin/qemu-i386:' > /proc/sys/fs/binfmt_misc/register

View File

@@ -1,11 +1,13 @@
\input texinfo @c -*- texinfo -*-
@iftex
@settitle QEMU CPU Emulator Reference Documentation
@titlepage
@sp 7
@center @titlefont{QEMU CPU Emulator Reference Documentation}
@sp 3
@end titlepage
@end iftex
@chapter Introduction
@@ -16,14 +18,18 @@ achieves a reasonnable speed while being easy to port on new host
CPUs.
QEMU has two operating modes:
@itemize
@item User mode emulation. In this mode, QEMU can launch Linux processes
@itemize @minus
@item
User mode emulation. In this mode, QEMU can launch Linux processes
compiled for one CPU on another CPU. Linux system calls are converted
because of endianness and 32/64 bit mismatches. The Wine Windows API
emulator (@url{http://www.winehq.org}) and the DOSEMU DOS emulator
(@url{www.dosemu.org}) are the main targets for QEMU.
@item Full system emulation. In this mode, QEMU emulates a full
@item
Full system emulation. In this mode, QEMU emulates a full
system, including a processor and various peripherials. Currently, it
is only used to launch an x86 Linux kernel on an x86 Linux system. It
enables easier testing and debugging of system code. It can also be
@@ -47,7 +53,7 @@ QEMU generic features:
@item Self-modifying code support.
@item Precise exception support.
@item Precise exceptions support.
@item The virtual CPU is a library (@code{libqemu}) which can be used
in other projects.
@@ -66,7 +72,7 @@ QEMU user mode emulation features:
QEMU full system emulation features:
@itemize
@item Using mmap() system calls to simulate the MMU
@item QEMU can either use a full software MMU for maximum portability or use the host system call mmap() to simulate the target MMU.
@end itemize
@section x86 emulation
@@ -104,14 +110,7 @@ memory access.
10 byte @code{long double}s of x86 for floating point emulation to get
maximum performances.
@item Full system emulation only works if no data are mapped above the virtual address
0xc0000000 (yet).
@item Some priviledged instructions or behaviors are missing. Only the ones
needed for proper Linux kernel operation are emulated.
@item No memory separation between the kernel and the user processes is done.
It will be implemented very soon.
@item Some priviledged instructions or behaviors are missing, especially for segment protection testing (yet).
@end itemize
@@ -128,13 +127,27 @@ generic dynamic code generation architecture of QEMU.
@end itemize
@chapter QEMU User space emulation invocation
@section SPARC emulation
The SPARC emulation is currently in development.
@chapter Installation
If you want to compile QEMU, please read the @file{README} which gives
the related information. Otherwise just download the binary
distribution (@file{qemu-XXX-i386.tar.gz}) and untar it as root in
@file{/}:
@example
su
cd /
tar zxvf /tmp/qemu-XXX-i386.tar.gz
@end example
@chapter QEMU User space emulator invocation
@section Quick Start
If you need to compile QEMU, please read the @file{README} which gives
the related information.
In order to launch a Linux process, QEMU needs the process executable
itself and all the target (x86) dynamic libraries used by it.
@@ -144,20 +157,20 @@ itself and all the target (x86) dynamic libraries used by it.
libraries:
@example
qemu -L / /bin/ls
qemu-i386 -L / /bin/ls
@end example
@code{-L /} tells that the x86 dynamic linker must be searched with a
@file{/} prefix.
@item Since QEMU is also a linux process, you can launch qemu with qemu:
@item Since QEMU is also a linux process, you can launch qemu with qemu (NOTE: you can only do that if you compiled QEMU from the sources):
@example
qemu -L / qemu -L / /bin/ls
qemu-i386 -L / qemu-i386 -L / /bin/ls
@end example
@item On non x86 CPUs, you need first to download at least an x86 glibc
(@file{qemu-XXX-i386-glibc21.tar.gz} on the QEMU web page). Ensure that
(@file{qemu-runtime-i386-XXX-.tar.gz} on the QEMU web page). Ensure that
@code{LD_LIBRARY_PATH} is not set:
@example
@@ -167,16 +180,16 @@ unset LD_LIBRARY_PATH
Then you can launch the precompiled @file{ls} x86 executable:
@example
qemu /usr/local/qemu-i386/bin/ls-i386
qemu-i386 tests/i386/ls
@end example
You can look at @file{/usr/local/qemu-i386/bin/qemu-conf.sh} so that
You can look at @file{qemu-binfmt-conf.sh} so that
QEMU is automatically launched by the Linux kernel when you try to
launch x86 executables. It requires the @code{binfmt_misc} module in the
Linux kernel.
@item The x86 version of QEMU is also included. You can try weird things such as:
@example
qemu /usr/local/qemu-i386/bin/qemu-i386 /usr/local/qemu-i386/bin/ls-i386
qemu-i386 /usr/local/qemu-i386/bin/qemu-i386 /usr/local/qemu-i386/bin/ls-i386
@end example
@end itemize
@@ -190,7 +203,7 @@ distribution (see previous section). In order to verify it, you must be
able to do:
@example
qemu /usr/local/qemu-i386/bin/ls-i386
qemu-i386 /usr/local/qemu-i386/bin/ls-i386
@end example
@item Download the binary x86 Wine install
@@ -203,7 +216,7 @@ qemu /usr/local/qemu-i386/bin/ls-i386
@item Then you can try the example @file{putty.exe}:
@example
qemu /usr/local/qemu-i386/wine/bin/wine /usr/local/qemu-i386/wine/c/Program\ Files/putty.exe
qemu-i386 /usr/local/qemu-i386/wine/bin/wine /usr/local/qemu-i386/wine/c/Program\ Files/putty.exe
@end example
@end itemize
@@ -211,7 +224,7 @@ qemu /usr/local/qemu-i386/wine/bin/wine /usr/local/qemu-i386/wine/c/Program\ Fil
@section Command line options
@example
usage: qemu [-h] [-d] [-L path] [-s size] program [arguments...]
usage: qemu-i386 [-h] [-d] [-L path] [-s size] program [arguments...]
@end example
@table @option
@@ -234,20 +247,82 @@ Act as if the host page size was 'pagesize' bytes
@chapter QEMU System emulator invocation
@section Introduction
@c man begin DESCRIPTION
The QEMU System emulator simulates a complete PC. It can either boot
directly a Linux kernel (without any BIOS or boot loader) or boot like a
real PC with the included BIOS.
In order to meet specific user needs, two versions of QEMU are
available:
@enumerate
@item
@code{qemu-fast} uses the host Memory Management Unit (MMU) to simulate
the x86 MMU. It is @emph{fast} but has limitations because the whole 4 GB
address space cannot be used and some memory mapped peripherials
cannot be emulated accurately yet. Therefore, a specific Linux kernel
must be used (@xref{linux_compile}).
@item
@code{qemu} uses a software MMU. It is about @emph{two times
slower} but gives a more accurate emulation.
@end enumerate
QEMU emulates the following PC peripherials:
@itemize @minus
@item
VGA (hardware level, including all non standard modes)
@item
PS/2 mouse and keyboard
@item
2 IDE interfaces with hard disk and CD-ROM support
@item
NE2000 network adapter (port=0x300, irq=9)
@item
Serial port
@item
Soundblaster 16 card
@item
PIC (interrupt controler)
@item
PIT (timers)
@item
CMOS memory
@end itemize
@c man end
@section Quick Start
This section explains how to launch a Linux kernel inside QEMU.
Download and uncompress the linux image (@file{linux.img}) and type:
@example
qemu linux.img
@end example
Linux should boot and give you a prompt.
@section Direct Linux Boot and Network emulation
This section explains how to launch a Linux kernel inside QEMU without
having to make a full bootable image. It is very useful for fast Linux
kernel testing. The QEMU network configuration is also explained.
@enumerate
@item
Download the archive @file{vl-test-xxx.tar.gz} containing a Linux kernel
and an initrd (initial Ram Disk). The archive also contains a
precompiled version of @file{vl}, the QEMU System emulator.
Download the archive @file{linux-test-xxx.tar.gz} containing a Linux
kernel and a disk image.
@item Optional: If you want network support (for example to launch X11 examples), you
must copy the script @file{vl-ifup} in @file{/etc} and configure
must copy the script @file{qemu-ifup} in @file{/etc} and configure
properly @code{sudo} so that the command @code{ifconfig} contained in
@file{vl-ifup} can be executed as root. You must verify that your host
@file{qemu-ifup} can be executed as root. You must verify that your host
kernel supports the TUN/TAP network interfaces: the device
@file{/dev/net/tun} must be present.
@@ -256,29 +331,33 @@ the host kernel and the emulated kernel. The emulated kernel is seen
from the host kernel at IP address 172.20.0.2 and the host kernel is
seen from the emulated kernel at IP address 172.20.0.1.
@item Launch @code{vl.sh}. You should have the following output:
@item Launch @code{qemu.sh}. You should have the following output:
@example
> ./vl.sh
connected to host network interface: tun0
Uncompressing Linux... Ok, booting the kernel.
Linux version 2.4.20 (bellard@voyager) (gcc version 2.95.2 20000220 (Debian GNU/Linux)) #42 Wed Jun 25 14:16:12 CEST 2003
> ./qemu.sh
Connected to host network interface: tun0
Linux version 2.4.21 (bellard@voyager.localdomain) (gcc version 3.2.2 20030222 (Red Hat Linux 3.2.2-5)) #5 Tue Nov 11 18:18:53 CET 2003
BIOS-provided physical RAM map:
BIOS-88: 0000000000000000 - 000000000009f000 (usable)
BIOS-88: 0000000000100000 - 0000000002000000 (usable)
BIOS-e801: 0000000000000000 - 000000000009f000 (usable)
BIOS-e801: 0000000000100000 - 0000000002000000 (usable)
32MB LOWMEM available.
On node 0 totalpages: 8192
zone(0): 4096 pages.
zone(1): 4096 pages.
zone(2): 0 pages.
Kernel command line: root=/dev/ram ramdisk_size=6144
Kernel command line: root=/dev/hda sb=0x220,5,1,5 ide2=noprobe ide3=noprobe ide4=noprobe ide5=noprobe console=ttyS0
ide_setup: ide2=noprobe
ide_setup: ide3=noprobe
ide_setup: ide4=noprobe
ide_setup: ide5=noprobe
Initializing CPU#0
Detected 501.785 MHz processor.
Calibrating delay loop... 973.20 BogoMIPS
Memory: 24776k/32768k available (725k kernel code, 7604k reserved, 151k data, 48k init, 0k highmem)
Detected 2399.621 MHz processor.
Console: colour EGA 80x25
Calibrating delay loop... 4744.80 BogoMIPS
Memory: 28872k/32768k available (1210k kernel code, 3508k reserved, 266k data, 64k init, 0k highmem)
Dentry cache hash table entries: 4096 (order: 3, 32768 bytes)
Inode cache hash table entries: 2048 (order: 2, 16384 bytes)
Mount-cache hash table entries: 512 (order: 0, 4096 bytes)
Mount cache hash table entries: 512 (order: 0, 4096 bytes)
Buffer-cache hash table entries: 1024 (order: 0, 4096 bytes)
Page-cache hash table entries: 8192 (order: 3, 32768 bytes)
CPU: Intel Pentium Pro stepping 03
@@ -289,6 +368,8 @@ Based upon Swansea University Computer Society NET3.039
Initializing RT netlink socket
apm: BIOS not found.
Starting kswapd
Journalled Block Device driver loaded
Detected PS/2 Mouse Port.
pty: 256 Unix98 ptys configured
Serial driver version 5.05c (2001-07-08) with no serial options enabled
ttyS00 at 0x03f8 (irq = 4) is a 16450
@@ -296,26 +377,40 @@ ne.c:v1.10 9/23/94 Donald Becker (becker@scyld.com)
Last modified Nov 1, 2000 by Paul Gortmaker
NE*000 ethercard probe at 0x300: 52 54 00 12 34 56
eth0: NE2000 found at 0x300, using IRQ 9.
RAMDISK driver initialized: 16 RAM disks of 6144K size 1024 blocksize
RAMDISK driver initialized: 16 RAM disks of 4096K size 1024 blocksize
Uniform Multi-Platform E-IDE driver Revision: 7.00beta4-2.4
ide: Assuming 50MHz system bus speed for PIO modes; override with idebus=xx
hda: QEMU HARDDISK, ATA DISK drive
ide0 at 0x1f0-0x1f7,0x3f6 on irq 14
hda: attached ide-disk driver.
hda: 20480 sectors (10 MB) w/256KiB Cache, CHS=20/16/63
Partition check:
hda:
Soundblaster audio driver Copyright (C) by Hannu Savolainen 1993-1996
NET4: Linux TCP/IP 1.0 for NET4.0
IP Protocols: ICMP, UDP, TCP, IGMP
IP: routing cache hash table of 512 buckets, 4Kbytes
TCP: Hash tables configured (established 2048 bind 2048)
TCP: Hash tables configured (established 2048 bind 4096)
NET4: Unix domain sockets 1.0/SMP for Linux NET4.0.
RAMDISK: ext2 filesystem found at block 0
RAMDISK: Loading 6144 blocks [1 disk] into ram disk... done.
Freeing initrd memory: 6144k freed
EXT2-fs warning: mounting unchecked fs, running e2fsck is recommended
VFS: Mounted root (ext2 filesystem).
Freeing unused kernel memory: 48k freed
sh: can't access tty; job control turned off
#
Freeing unused kernel memory: 64k freed
Linux version 2.4.21 (bellard@voyager.localdomain) (gcc version 3.2.2 20030222 (Red Hat Linux 3.2.2-5)) #5 Tue Nov 11 18:18:53 CET 2003
QEMU Linux test distribution (based on Redhat 9)
Type 'exit' to halt the system
sh-2.05b#
@end example
@item
Then you can play with the kernel inside the virtual serial console. You
can launch @code{ls} for example. Type @key{Ctrl-a h} to have an help
about the keys you can type inside the virtual serial console. In
particular @key{Ctrl-a b} is the Magic SysRq key.
particular, use @key{Ctrl-a x} to exit QEMU and use @key{Ctrl-a b} as
the Magic SysRq key.
@item
If the network is enabled, launch the script @file{/etc/linuxrc} in the
@@ -334,16 +429,235 @@ a real Virtual Linux system !
@end enumerate
NOTE: the example initrd is a modified version of the one made by Kevin
NOTES:
@enumerate
@item
A 2.5.74 kernel is also included in the archive. Just
replace the bzImage in qemu.sh to try it.
@item
qemu creates a temporary file in @var{$QEMU_TMPDIR} (@file{/tmp} is the
default) containing all the simulated PC memory. If possible, try to use
a temporary directory using the tmpfs filesystem to avoid too many
unnecessary disk accesses.
@item
In order to exit cleanly from qemu, you can do a @emph{shutdown} inside
qemu. qemu will automatically exit when the Linux shutdown is done.
@item
You can boot slightly faster by disabling the probe of non present IDE
interfaces. To do so, add the following options on the kernel command
line:
@example
ide1=noprobe ide2=noprobe ide3=noprobe ide4=noprobe ide5=noprobe
@end example
@item
The example disk image is a modified version of the one made by Kevin
Lawton for the plex86 Project (@url{www.plex86.org}).
@section Kernel Compilation
@end enumerate
You can use any Linux kernel within QEMU provided it is mapped at
address 0x90000000 (the default is 0xc0000000). You must modify only two
lines in the kernel source:
@section Invocation
In asm/page.h, replace
@example
@c man begin SYNOPSIS
usage: qemu [options] [disk_image]
@c man end
@end example
@c man begin OPTIONS
@var{disk_image} is a raw hard disk image for IDE hard disk 0.
General options:
@table @option
@item -hda file
@item -hdb file
@item -hdc file
@item -hdd file
Use @var{file} as hard disk 0, 1, 2 or 3 image (@xref{disk_images}).
@item -cdrom file
Use @var{file} as CD-ROM image (you cannot use @option{-hdc} and and
@option{-cdrom} at the same time).
@item -boot [c|d]
Boot on hard disk (c) or CD-ROM (d). Hard disk boot is the default.
@item -snapshot
Write to temporary files instead of disk image files. In this case,
the raw disk image you use is not written back. You can however force
the write back by pressing @key{C-a s} (@xref{disk_images}).
@item -m megs
Set virtual RAM size to @var{megs} megabytes.
@item -n script
Set network init script [default=/etc/qemu-ifup]. This script is
launched to configure the host network interface (usually tun0)
corresponding to the virtual NE2000 card.
@item -initrd file
Use @var{file} as initial ram disk.
@item -tun-fd fd
Assumes @var{fd} talks to tap/tun and use it. Read
@url{http://bellard.org/qemu/tetrinet.html} to have an example of its
use.
@item -nographic
Normally, QEMU uses SDL to display the VGA output. With this option,
you can totally disable graphical output so that QEMU is a simple
command line application. The emulated serial port is redirected on
the console. Therefore, you can still use QEMU to debug a Linux kernel
with a serial console.
@end table
Linux boot specific (does not require a full PC boot with a BIOS):
@table @option
@item -kernel bzImage
Use @var{bzImage} as kernel image.
@item -append cmdline
Use @var{cmdline} as kernel command line
@item -initrd file
Use @var{file} as initial ram disk.
@end table
Debug options:
@table @option
@item -s
Wait gdb connection to port 1234 (@xref{gdb_usage}).
@item -p port
Change gdb connection port.
@item -d
Output log in /tmp/qemu.log
@end table
During emulation, use @key{C-a h} to get terminal commands:
@table @key
@item C-a h
Print this help
@item C-a x
Exit emulatior
@item C-a s
Save disk data back to file (if -snapshot)
@item C-a b
Send break (magic sysrq)
@item C-a C-a
Send C-a
@end table
@c man end
@ignore
@setfilename qemu
@settitle QEMU System Emulator
@c man begin SEEALSO
The HTML documentation of QEMU for more precise information and Linux
user mode emulator invocation.
@c man end
@c man begin AUTHOR
Fabrice Bellard
@c man end
@end ignore
@end ignore
@node disk_images
@section Disk Images
@subsection Raw disk images
The disk images can simply be raw images of the hard disk. You can
create them with the command:
@example
dd if=/dev/zero of=myimage bs=1024 count=mysize
@end example
where @var{myimage} is the image filename and @var{mysize} is its size
in kilobytes.
@subsection Snapshot mode
If you use the option @option{-snapshot}, all disk images are
considered as read only. When sectors in written, they are written in
a temporary file created in @file{/tmp}. You can however force the
write back to the raw disk images by pressing @key{C-a s}.
NOTE: The snapshot mode only works with raw disk images.
@subsection Copy On Write disk images
QEMU also supports user mode Linux
(@url{http://user-mode-linux.sourceforge.net/}) Copy On Write (COW)
disk images. The COW disk images are much smaller than normal images
as they store only modified sectors. They also permit the use of the
same disk image template for many users.
To create a COW disk images, use the command:
@example
qemu-mkcow -f myrawimage.bin mycowimage.cow
@end example
@file{myrawimage.bin} is a raw image you want to use as original disk
image. It will never be written to.
@file{mycowimage.cow} is the COW disk image which is created by
@code{qemu-mkcow}. You can use it directly with the @option{-hdx}
options. You must not modify the original raw disk image if you use
COW images, as COW images only store the modified sectors from the raw
disk image. QEMU stores the original raw disk image name and its
modified time in the COW disk image so that chances of mistakes are
reduced.
If the raw disk image is not read-only, by pressing @key{C-a s} you
can flush the COW disk image back into the raw disk image, as in
snapshot mode.
COW disk images can also be created without a corresponding raw disk
image. It is useful to have a big initial virtual disk image without
using much disk space. Use:
@example
qemu-mkcow mycowimage.cow 1024
@end example
to create a 1 gigabyte empty COW disk image.
NOTES:
@enumerate
@item
COW disk images must be created on file systems supporting
@emph{holes} such as ext2 or ext3.
@item
Since holes are used, the displayed size of the COW disk image is not
the real one. To know it, use the @code{ls -ls} command.
@end enumerate
@node linux_compile
@section Linux Kernel Compilation
You can use any linux kernel with QEMU. However, if you want to use
@code{qemu-fast} to get maximum performances, you should make the
following changes to the Linux kernel (only 2.4.x and 2.5.x were
tested):
@enumerate
@item
The kernel must be mapped at 0x90000000 (the default is
0xc0000000). You must modify only two lines in the kernel source:
In @file{include/asm/page.h}, replace
@example
#define __PAGE_OFFSET (0xc0000000)
@end example
@@ -352,7 +666,7 @@ by
#define __PAGE_OFFSET (0x90000000)
@end example
And in arch/i386/vmlinux.lds, replace
And in @file{arch/i386/vmlinux.lds}, replace
@example
. = 0xc0000000 + 0x100000;
@end example
@@ -361,7 +675,37 @@ by
. = 0x90000000 + 0x100000;
@end example
The file config-2.4.20 gives the configuration of the example kernel.
@item
If you want to enable SMP (Symmetric Multi-Processing) support, you
must make the following change in @file{include/asm/fixmap.h}. Replace
@example
#define FIXADDR_TOP (0xffffX000UL)
@end example
by
@example
#define FIXADDR_TOP (0xa7ffX000UL)
@end example
(X is 'e' or 'f' depending on the kernel version). Although you can
use an SMP kernel with QEMU, it only supports one CPU.
@item
If you are not using a 2.5 kernel as host kernel but if you use a target
2.5 kernel, you must also ensure that the 'HZ' define is set to 100
(1000 is the default) as QEMU cannot currently emulate timers at
frequencies greater than 100 Hz on host Linux systems < 2.5. In
@file{include/asm/param.h}, replace:
@example
# define HZ 1000 /* Internal kernel timer frequency */
@end example
by
@example
# define HZ 100 /* Internal kernel timer frequency */
@end example
@end enumerate
The file config-2.x.x gives the configuration of the example kernels.
Just type
@example
@@ -372,24 +716,46 @@ As you would do to make a real kernel. Then you can use with QEMU
exactly the same kernel as you would boot on your PC (in
@file{arch/i386/boot/bzImage}).
@section PC Emulation
@node gdb_usage
@section GDB usage
QEMU emulates the following PC peripherials:
QEMU has a primitive support to work with gdb, so that you can do
'Ctrl-C' while the virtual machine is running and inspect its state.
@itemize
In order to use gdb, launch qemu with the '-s' option. It will wait for a
gdb connection:
@example
> qemu -s arch/i386/boot/bzImage -hda root-2.4.20.img root=/dev/hda
Connected to host network interface: tun0
Waiting gdb connection on port 1234
@end example
Then launch gdb on the 'vmlinux' executable:
@example
> gdb vmlinux
@end example
In gdb, connect to QEMU:
@example
(gdb) target remote locahost:1234
@end example
Then you can use gdb normally. For example, type 'c' to launch the kernel:
@example
(gdb) c
@end example
Here are some useful tips in order to use gdb on system code:
@enumerate
@item
PIC (interrupt controler)
Use @code{info reg} to display all the CPU registers.
@item
PIT (timers)
@item
CMOS memory
Use @code{x/10i $eip} to display the code at the PC position.
@item
Serial port (port=0x3f8, irq=4)
@item
NE2000 network adapter (port=0x300, irq=9)
@item
Dumb VGA (to print the @code{uncompressing Linux kernel} message)
@end itemize
Use @code{set architecture i8086} to dump 16 bit code. Then use
@code{x/10i $cs*16+*eip} to dump the code at the PC position.
@end enumerate
@chapter QEMU Internals
@@ -405,9 +771,9 @@ Like Valgrind [2], QEMU does user space emulation and dynamic
translation. Valgrind is mainly a memory debugger while QEMU has no
support for it (QEMU could be used to detect out of bound memory
accesses as Valgrind, but it has no support to track uninitialised data
as Valgrind does). Valgrind dynamic translator generates better code
as Valgrind does). The Valgrind dynamic translator generates better code
than QEMU (in particular it does register allocation) but it is closely
tied to an x86 host and target and has no support for precise exception
tied to an x86 host and target and has no support for precise exceptions
and system emulation.
EM86 [4] is the closest project to user space QEMU (and QEMU still uses
@@ -433,8 +799,8 @@ system emulator. It requires a patched Linux kernel to work (you cannot
launch the same kernel on your PC), but the patches are really small. As
it is a PC virtualizer (no emulation is done except for some priveledged
instructions), it has the potential of being faster than QEMU. The
downside is that a complicated (and potentially unsafe) kernel patch is
needed.
downside is that a complicated (and potentially unsafe) host kernel
patch is needed.
@section Portable dynamic translation
@@ -540,7 +906,7 @@ Correct translated code invalidation is done efficiently by maintaining
a linked list of every translated block contained in a given page. Other
linked lists are also maintained to undo direct block chaining.
Althought the overhead of doing @code{mprotect()} calls is important,
Although the overhead of doing @code{mprotect()} calls is important,
most MSDOS programs can be emulated at reasonnable speed with QEMU and
DOSEMU.
@@ -609,7 +975,7 @@ reentrancy.
@section Self-virtualization
QEMU was conceived so that ultimately it can emulate itself. Althought
QEMU was conceived so that ultimately it can emulate itself. Although
it is not very useful, it is an important test to show the power of the
emulator.
@@ -673,16 +1039,6 @@ The new Plex86 project.
In the directory @file{tests/}, various interesting testing programs
are available. There are used for regression testing.
@section @file{hello-i386}
Very simple statically linked x86 program, just to test QEMU during a
port to a new host CPU.
@section @file{hello-arm}
Very simple statically linked ARM program, just to test QEMU during a
port to a new host CPU.
@section @file{test-i386}
This program executes most of the 16 bit and 32 bit x86 instructions and
@@ -698,6 +1054,22 @@ The Linux system call @code{vm86()} is used to test vm86 emulation.
Various exceptions are raised to test most of the x86 user space
exception reporting.
@section @file{linux-test}
This program tests various Linux system calls. It is used to verify
that the system call parameters are correctly converted between target
and host CPUs.
@section @file{hello-i386}
Very simple statically linked x86 program, just to test QEMU during a
port to a new host CPU.
@section @file{hello-arm}
Very simple statically linked ARM program, just to test QEMU during a
port to a new host CPU.
@section @file{sha1}
It is a simple benchmark. Care must be taken to interpret the results

143
qemu-mkcow.c Normal file
View File

@@ -0,0 +1,143 @@
/*
* create a COW disk image
*
* Copyright (c) 2003 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <getopt.h>
#include <inttypes.h>
#include <unistd.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <signal.h>
#include <time.h>
#include <sys/time.h>
#include <malloc.h>
#include <termios.h>
#include <sys/poll.h>
#include <errno.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <netinet/in.h>
#include "vl.h"
#include "bswap.h"
int cow_create(int cow_fd, const char *image_filename,
int64_t image_sectors)
{
struct cow_header_v2 cow_header;
int fd;
struct stat st;
memset(&cow_header, 0, sizeof(cow_header));
cow_header.magic = htonl(COW_MAGIC);
cow_header.version = htonl(COW_VERSION);
if (image_filename) {
fd = open(image_filename, O_RDONLY);
if (fd < 0) {
perror(image_filename);
exit(1);
}
image_sectors = lseek64(fd, 0, SEEK_END);
if (fstat(fd, &st) != 0) {
close(fd);
return -1;
}
close(fd);
image_sectors /= 512;
cow_header.mtime = htonl(st.st_mtime);
realpath(image_filename, cow_header.backing_file);
}
cow_header.sectorsize = htonl(512);
cow_header.size = image_sectors * 512;
#ifndef WORDS_BIGENDIAN
cow_header.size = bswap64(cow_header.size);
#endif
write(cow_fd, &cow_header, sizeof(cow_header));
/* resize to include at least all the bitmap */
ftruncate(cow_fd, sizeof(cow_header) + ((image_sectors + 7) >> 3));
lseek(cow_fd, 0, SEEK_SET);
return 0;
}
void help(void)
{
printf("vlmkcow version " QEMU_VERSION ", Copyright (c) 2003 Fabrice Bellard\n"
"usage: vlmkcow [-h] [-f disk_image] cow_image [cow_size]\n"
"Create a Copy On Write disk image from an optional raw disk image\n"
"\n"
"-f disk_image set the raw disk image name\n"
"cow_image the created cow_image\n"
"cow_size the create cow_image size in MB if no raw disk image is used\n"
"\n"
"Once the cow_image is created from a raw disk image, you must not modify the original raw disk image\n"
);
exit(1);
}
int main(int argc, char **argv)
{
const char *image_filename, *cow_filename;
int cow_fd, c, nb_args;
int64_t image_size;
image_filename = NULL;
image_size = 0;
for(;;) {
c = getopt(argc, argv, "hf:");
if (c == -1)
break;
switch(c) {
case 'h':
help();
break;
case 'f':
image_filename = optarg;
break;
}
}
if (!image_filename)
nb_args = 2;
else
nb_args = 1;
if (optind + nb_args != argc)
help();
cow_filename = argv[optind];
if (nb_args == 2) {
image_size = (int64_t)atoi(argv[optind + 1]) * 2 * 1024;
}
cow_fd = open(cow_filename, O_RDWR | O_CREAT | O_TRUNC, 0644);
if (!cow_fd < 0)
return -1;
if (cow_create(cow_fd, image_filename, image_size) < 0) {
fprintf(stderr, "%s: error while formating\n", cow_filename);
exit(1);
}
close(cow_fd);
return 0;
}

279
sdl.c Normal file
View File

@@ -0,0 +1,279 @@
/*
* QEMU SDL display driver
*
* Copyright (c) 2003 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <getopt.h>
#include <inttypes.h>
#include <unistd.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <signal.h>
#include <time.h>
#include <sys/time.h>
#include <malloc.h>
#include <termios.h>
#include <sys/poll.h>
#include <errno.h>
#include <sys/wait.h>
#include <netinet/in.h>
#include <SDL.h>
#include "cpu.h"
#include "exec-all.h"
#include "vl.h"
static SDL_Surface *screen;
static int gui_grab; /* if true, all keyboard/mouse events are grabbed */
static void sdl_update(DisplayState *ds, int x, int y, int w, int h)
{
SDL_UpdateRect(screen, x, y, w, h);
}
static void sdl_resize(DisplayState *ds, int w, int h)
{
int flags;
// printf("resizing to %d %d\n", w, h);
flags = SDL_HWSURFACE|SDL_ASYNCBLIT|SDL_HWACCEL;
flags |= SDL_RESIZABLE;
screen = SDL_SetVideoMode(w, h, 0, flags);
if (!screen) {
fprintf(stderr, "Could not open SDL display\n");
exit(1);
}
ds->data = screen->pixels;
ds->linesize = screen->pitch;
ds->depth = screen->format->BitsPerPixel;
}
static const uint32_t x_keycode_to_pc_keycode[61] = {
0x47e0, /* 97 Home */
0x48e0, /* 98 Up */
0x49e0, /* 99 PgUp */
0x4be0, /* 100 Left */
0x4c, /* 101 KP-5 */
0x4de0, /* 102 Right */
0x4fe0, /* 103 End */
0x50e0, /* 104 Down */
0x51e0, /* 105 PgDn */
0x52e0, /* 106 Ins */
0x53e0, /* 107 Del */
0x1ce0, /* 108 Enter */
0x1de0, /* 109 Ctrl-R */
0x451de1, /* 110 Pause */
0x37e0, /* 111 Print */
0x35e0, /* 112 Divide */
0x38e0, /* 113 Alt-R */
0x46e0, /* 114 Break */
0x0, /* 115 */
0x0, /* 116 */
0x0, /* 117 */
0x0, /* 118 */
0x0, /* 119 */
0x0, /* 120 */
0x0, /* 121 */
0x0, /* 122 */
0x0, /* 123 */
0x0, /* 124 */
0x0, /* 125 */
0x0, /* 126 */
0x0, /* 127 */
0x0, /* 128 */
0x0, /* 129 */
0x0, /* 130 */
0x0, /* 131 */
0x0, /* 132 */
0x0, /* 133 */
0x0, /* 134 */
0x0, /* 135 */
0x47, /* 136 KP_7 */
0x48, /* 137 KP_8 */
0x49, /* 138 KP_9 */
0x4b, /* 139 KP_4 */
0x4c, /* 140 KP_5 */
0x4d, /* 141 KP_6 */
0x4f, /* 142 KP_1 */
0x50, /* 143 KP_2 */
0x51, /* 144 KP_3 */
0x52, /* 145 KP_0 */
0x53, /* 146 KP_. */
0x47, /* 147 KP_HOME */
0x48, /* 148 KP_UP */
0x49, /* 149 KP_PgUp */
0x4b, /* 150 KP_Left */
0x4c, /* 151 KP_ */
0x4d, /* 152 KP_Right */
0x4f, /* 153 KP_End */
0x50, /* 154 KP_Down */
0x51, /* 155 KP_PgDn */
0x52, /* 156 KP_Ins */
0x53, /* 157 KP_Del */
};
static void sdl_process_key(SDL_KeyboardEvent *ev)
{
int keycode, v;
/* XXX: not portable, but avoids complicated mappings */
keycode = ev->keysym.scancode;
if (keycode < 9) {
keycode = 0;
} else if (keycode < 97) {
keycode -= 8; /* just an offset */
} else if (keycode < 158) {
/* use conversion table */
keycode = x_keycode_to_pc_keycode[keycode - 97];
} else {
keycode = 0;
}
/* now send the key code */
while (keycode != 0) {
v = keycode & 0xff;
if (ev->type == SDL_KEYUP)
v |= 0x80;
kbd_put_keycode(v);
keycode >>= 8;
}
}
static void sdl_grab_start(void)
{
SDL_WM_SetCaption("QEMU - Press Ctrl-Shift to exit grab", "QEMU");
SDL_ShowCursor(0);
SDL_WM_GrabInput(SDL_GRAB_ON);
/* dummy read to avoid moving the mouse */
SDL_GetRelativeMouseState(NULL, NULL);
gui_grab = 1;
}
static void sdl_grab_end(void)
{
SDL_WM_SetCaption("QEMU", "QEMU");
SDL_WM_GrabInput(SDL_GRAB_OFF);
SDL_ShowCursor(1);
gui_grab = 0;
}
static void sdl_send_mouse_event(void)
{
int dx, dy, dz, state, buttons;
state = SDL_GetRelativeMouseState(&dx, &dy);
buttons = 0;
if (state & SDL_BUTTON(SDL_BUTTON_LEFT))
buttons |= MOUSE_EVENT_LBUTTON;
if (state & SDL_BUTTON(SDL_BUTTON_RIGHT))
buttons |= MOUSE_EVENT_RBUTTON;
if (state & SDL_BUTTON(SDL_BUTTON_MIDDLE))
buttons |= MOUSE_EVENT_MBUTTON;
/* XXX: test wheel */
dz = 0;
if (state & SDL_BUTTON(SDL_BUTTON_WHEELUP))
dz--;
if (state & SDL_BUTTON(SDL_BUTTON_WHEELDOWN))
dz++;
kbd_mouse_event(dx, dy, dz, buttons);
}
static void sdl_refresh(DisplayState *ds)
{
SDL_Event ev1, *ev = &ev1;
vga_update_display();
while (SDL_PollEvent(ev)) {
switch (ev->type) {
case SDL_VIDEOEXPOSE:
sdl_update(ds, 0, 0, screen->w, screen->h);
break;
case SDL_KEYDOWN:
case SDL_KEYUP:
if (ev->type == SDL_KEYDOWN) {
if ((SDL_GetModState() & (KMOD_LSHIFT | KMOD_LCTRL)) ==
(KMOD_LSHIFT | KMOD_LCTRL)) {
/* exit/enter grab if pressing Ctrl-Shift */
if (!gui_grab)
sdl_grab_start();
else
sdl_grab_end();
}
}
sdl_process_key(&ev->key);
break;
case SDL_QUIT:
reset_requested = 1;
break;
case SDL_MOUSEMOTION:
if (gui_grab) {
sdl_send_mouse_event();
}
break;
case SDL_MOUSEBUTTONDOWN:
case SDL_MOUSEBUTTONUP:
{
SDL_MouseButtonEvent *bev = &ev->button;
if (!gui_grab) {
if (ev->type == SDL_MOUSEBUTTONDOWN &&
(bev->state & SDL_BUTTON_LMASK)) {
/* start grabbing all events */
sdl_grab_start();
}
} else {
sdl_send_mouse_event();
}
}
break;
default:
break;
}
}
}
void sdl_display_init(DisplayState *ds)
{
int flags;
flags = SDL_INIT_VIDEO | SDL_INIT_NOPARACHUTE;
if (SDL_Init (flags)) {
fprintf(stderr, "Could not initialize SDL - exiting\n");
exit(1);
}
/* NOTE: we still want Ctrl-C to work, so we undo the SDL redirections */
signal(SIGINT, SIG_DFL);
signal(SIGQUIT, SIG_DFL);
ds->dpy_update = sdl_update;
ds->dpy_resize = sdl_resize;
ds->dpy_refresh = sdl_refresh;
sdl_resize(ds, 640, 400);
SDL_WM_SetCaption("QEMU", "QEMU");
SDL_EnableKeyRepeat(250, 50);
gui_grab = 0;
}

143
softmmu_header.h Normal file
View File

@@ -0,0 +1,143 @@
/*
* Software MMU support
*
* 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
*/
#if DATA_SIZE == 8
#define SUFFIX q
#define USUFFIX q
#define DATA_TYPE uint64_t
#elif DATA_SIZE == 4
#define SUFFIX l
#define USUFFIX l
#define DATA_TYPE uint32_t
#elif DATA_SIZE == 2
#define SUFFIX w
#define USUFFIX uw
#define DATA_TYPE uint16_t
#define DATA_STYPE int16_t
#elif DATA_SIZE == 1
#define SUFFIX b
#define USUFFIX ub
#define DATA_TYPE uint8_t
#define DATA_STYPE int8_t
#else
#error unsupported data size
#endif
#if ACCESS_TYPE == 0
#define CPU_MEM_INDEX 0
#define MMUSUFFIX _mmu
#elif ACCESS_TYPE == 1
#define CPU_MEM_INDEX 1
#define MMUSUFFIX _mmu
#elif ACCESS_TYPE == 2
#define CPU_MEM_INDEX ((env->hflags & HF_CPL_MASK) == 3)
#define MMUSUFFIX _mmu
#elif ACCESS_TYPE == 3
#define CPU_MEM_INDEX ((env->hflags & HF_CPL_MASK) == 3)
#define MMUSUFFIX _cmmu
#else
#error invalid ACCESS_TYPE
#endif
#if DATA_SIZE == 8
#define RES_TYPE uint64_t
#else
#define RES_TYPE int
#endif
DATA_TYPE REGPARM(1) glue(glue(__ld, SUFFIX), MMUSUFFIX)(unsigned long addr,
int is_user);
void REGPARM(2) glue(glue(__st, SUFFIX), MMUSUFFIX)(unsigned long addr, DATA_TYPE v, int is_user);
static inline RES_TYPE glue(glue(ld, USUFFIX), MEMSUFFIX)(void *ptr)
{
int index;
RES_TYPE res;
unsigned long addr, physaddr;
int is_user;
addr = (unsigned long)ptr;
index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
is_user = CPU_MEM_INDEX;
if (__builtin_expect(env->tlb_read[is_user][index].address !=
(addr & (TARGET_PAGE_MASK | (DATA_SIZE - 1))), 0)) {
res = glue(glue(__ld, SUFFIX), MMUSUFFIX)(addr, is_user);
} else {
physaddr = addr + env->tlb_read[is_user][index].addend;
res = glue(glue(ld, USUFFIX), _raw)((uint8_t *)physaddr);
}
return res;
}
#if DATA_SIZE <= 2
static inline int glue(glue(lds, SUFFIX), MEMSUFFIX)(void *ptr)
{
int res, index;
unsigned long addr, physaddr;
int is_user;
addr = (unsigned long)ptr;
index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
is_user = CPU_MEM_INDEX;
if (__builtin_expect(env->tlb_read[is_user][index].address !=
(addr & (TARGET_PAGE_MASK | (DATA_SIZE - 1))), 0)) {
res = (DATA_STYPE)glue(glue(__ld, SUFFIX), MMUSUFFIX)(addr, is_user);
} else {
physaddr = addr + env->tlb_read[is_user][index].addend;
res = glue(glue(lds, SUFFIX), _raw)((uint8_t *)physaddr);
}
return res;
}
#endif
static inline void glue(glue(st, SUFFIX), MEMSUFFIX)(void *ptr, RES_TYPE v)
{
int index;
unsigned long addr, physaddr;
int is_user;
addr = (unsigned long)ptr;
index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
is_user = CPU_MEM_INDEX;
if (__builtin_expect(env->tlb_write[is_user][index].address !=
(addr & (TARGET_PAGE_MASK | (DATA_SIZE - 1))), 0)) {
glue(glue(__st, SUFFIX), MMUSUFFIX)(addr, v, is_user);
} else {
physaddr = addr + env->tlb_write[is_user][index].addend;
glue(glue(st, SUFFIX), _raw)((uint8_t *)physaddr, v);
}
}
#undef RES_TYPE
#undef DATA_TYPE
#undef DATA_STYPE
#undef SUFFIX
#undef USUFFIX
#undef DATA_SIZE
#undef CPU_MEM_INDEX
#undef MMUSUFFIX

259
softmmu_template.h Normal file
View File

@@ -0,0 +1,259 @@
/*
* Software MMU support
*
* Copyright (c) 2003 Fabrice Bellard
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#define DATA_SIZE (1 << SHIFT)
#if DATA_SIZE == 8
#define SUFFIX q
#define USUFFIX q
#define DATA_TYPE uint64_t
#elif DATA_SIZE == 4
#define SUFFIX l
#define USUFFIX l
#define DATA_TYPE uint32_t
#elif DATA_SIZE == 2
#define SUFFIX w
#define USUFFIX uw
#define DATA_TYPE uint16_t
#elif DATA_SIZE == 1
#define SUFFIX b
#define USUFFIX ub
#define DATA_TYPE uint8_t
#else
#error unsupported data size
#endif
static DATA_TYPE glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(unsigned long addr,
int is_user,
void *retaddr);
static void glue(glue(slow_st, SUFFIX), MMUSUFFIX)(unsigned long addr,
DATA_TYPE val,
int is_user,
void *retaddr);
static inline DATA_TYPE glue(io_read, SUFFIX)(unsigned long physaddr,
unsigned long tlb_addr)
{
DATA_TYPE res;
int index;
index = (tlb_addr >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
#if SHIFT <= 2
res = io_mem_read[index][SHIFT](physaddr);
#else
#ifdef TARGET_WORDS_BIGENDIAN
res = (uint64_t)io_mem_read[index][2](physaddr) << 32;
res |= io_mem_read[index][2](physaddr + 4);
#else
res = io_mem_read[index][2](physaddr);
res |= (uint64_t)io_mem_read[index][2](physaddr + 4) << 32;
#endif
#endif /* SHIFT > 2 */
return res;
}
static inline void glue(io_write, SUFFIX)(unsigned long physaddr,
DATA_TYPE val,
unsigned long tlb_addr)
{
int index;
index = (tlb_addr >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
#if SHIFT <= 2
io_mem_write[index][SHIFT](physaddr, val);
#else
#ifdef TARGET_WORDS_BIGENDIAN
io_mem_write[index][2](physaddr, val >> 32);
io_mem_write[index][2](physaddr + 4, val);
#else
io_mem_write[index][2](physaddr, val);
io_mem_write[index][2](physaddr + 4, val >> 32);
#endif
#endif /* SHIFT > 2 */
}
/* handle all cases except unaligned access which span two pages */
DATA_TYPE REGPARM(1) glue(glue(__ld, SUFFIX), MMUSUFFIX)(unsigned long addr,
int is_user)
{
DATA_TYPE res;
int index;
unsigned long physaddr, tlb_addr;
void *retaddr;
/* test if there is match for unaligned or IO access */
/* XXX: could done more in memory macro in a non portable way */
index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
redo:
tlb_addr = env->tlb_read[is_user][index].address;
if ((addr & TARGET_PAGE_MASK) == (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) {
physaddr = addr + env->tlb_read[is_user][index].addend;
if (tlb_addr & ~TARGET_PAGE_MASK) {
/* IO access */
if ((addr & (DATA_SIZE - 1)) != 0)
goto do_unaligned_access;
res = glue(io_read, SUFFIX)(physaddr, tlb_addr);
} else if (((addr & 0xfff) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) {
/* slow unaligned access (it spans two pages or IO) */
do_unaligned_access:
retaddr = GETPC();
res = glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(addr,
is_user, retaddr);
} else {
/* unaligned access in the same page */
res = glue(glue(ld, USUFFIX), _raw)((uint8_t *)physaddr);
}
} else {
/* the page is not in the TLB : fill it */
retaddr = GETPC();
tlb_fill(addr, 0, is_user, retaddr);
goto redo;
}
return res;
}
/* handle all unaligned cases */
static DATA_TYPE glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(unsigned long addr,
int is_user,
void *retaddr)
{
DATA_TYPE res, res1, res2;
int index, shift;
unsigned long physaddr, tlb_addr, addr1, addr2;
index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
redo:
tlb_addr = env->tlb_read[is_user][index].address;
if ((addr & TARGET_PAGE_MASK) == (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) {
physaddr = addr + env->tlb_read[is_user][index].addend;
if (tlb_addr & ~TARGET_PAGE_MASK) {
/* IO access */
if ((addr & (DATA_SIZE - 1)) != 0)
goto do_unaligned_access;
res = glue(io_read, SUFFIX)(physaddr, tlb_addr);
} else if (((addr & 0xfff) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) {
do_unaligned_access:
/* slow unaligned access (it spans two pages) */
addr1 = addr & ~(DATA_SIZE - 1);
addr2 = addr1 + DATA_SIZE;
res1 = glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(addr1,
is_user, retaddr);
res2 = glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(addr2,
is_user, retaddr);
shift = (addr & (DATA_SIZE - 1)) * 8;
#ifdef TARGET_WORDS_BIGENDIAN
res = (res1 << shift) | (res2 >> ((DATA_SIZE * 8) - shift));
#else
res = (res1 >> shift) | (res2 << ((DATA_SIZE * 8) - shift));
#endif
} else {
/* unaligned/aligned access in the same page */
res = glue(glue(ld, USUFFIX), _raw)((uint8_t *)physaddr);
}
} else {
/* the page is not in the TLB : fill it */
tlb_fill(addr, 0, is_user, retaddr);
goto redo;
}
return res;
}
void REGPARM(2) glue(glue(__st, SUFFIX), MMUSUFFIX)(unsigned long addr,
DATA_TYPE val,
int is_user)
{
unsigned long physaddr, tlb_addr;
void *retaddr;
int index;
index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
redo:
tlb_addr = env->tlb_write[is_user][index].address;
if ((addr & TARGET_PAGE_MASK) == (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) {
physaddr = addr + env->tlb_write[is_user][index].addend;
if (tlb_addr & ~TARGET_PAGE_MASK) {
/* IO access */
if ((addr & (DATA_SIZE - 1)) != 0)
goto do_unaligned_access;
glue(io_write, SUFFIX)(physaddr, val, tlb_addr);
} else if (((addr & 0xfff) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) {
do_unaligned_access:
retaddr = GETPC();
glue(glue(slow_st, SUFFIX), MMUSUFFIX)(addr, val,
is_user, retaddr);
} else {
/* aligned/unaligned access in the same page */
glue(glue(st, SUFFIX), _raw)((uint8_t *)physaddr, val);
}
} else {
/* the page is not in the TLB : fill it */
retaddr = GETPC();
tlb_fill(addr, 1, is_user, retaddr);
goto redo;
}
}
/* handles all unaligned cases */
static void glue(glue(slow_st, SUFFIX), MMUSUFFIX)(unsigned long addr,
DATA_TYPE val,
int is_user,
void *retaddr)
{
unsigned long physaddr, tlb_addr;
int index, i;
index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
redo:
tlb_addr = env->tlb_write[is_user][index].address;
if ((addr & TARGET_PAGE_MASK) == (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) {
physaddr = addr + env->tlb_write[is_user][index].addend;
if (tlb_addr & ~TARGET_PAGE_MASK) {
/* IO access */
if ((addr & (DATA_SIZE - 1)) != 0)
goto do_unaligned_access;
glue(io_write, SUFFIX)(physaddr, val, tlb_addr);
} else if (((addr & 0xfff) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) {
do_unaligned_access:
/* XXX: not efficient, but simple */
for(i = 0;i < DATA_SIZE; i++) {
#ifdef TARGET_WORDS_BIGENDIAN
glue(slow_stb, MMUSUFFIX)(addr + i, val >> (((DATA_SIZE - 1) * 8) - (i * 8)),
is_user, retaddr);
#else
glue(slow_stb, MMUSUFFIX)(addr + i, val >> (i * 8),
is_user, retaddr);
#endif
}
} else {
/* aligned/unaligned access in the same page */
glue(glue(st, SUFFIX), _raw)((uint8_t *)physaddr, val);
}
} else {
/* the page is not in the TLB : fill it */
tlb_fill(addr, 1, is_user, retaddr);
goto redo;
}
}
#undef SHIFT
#undef DATA_TYPE
#undef SUFFIX
#undef USUFFIX
#undef DATA_SIZE

View File

@@ -20,12 +20,10 @@
#ifndef CPU_ARM_H
#define CPU_ARM_H
#include "config.h"
#include <setjmp.h>
#include "cpu-defs.h"
#define EXCP_UDEF 1 /* undefined instruction */
#define EXCP_SWI 2 /* software interrupt */
#define EXCP_INTERRUPT 256 /* async interruption */
typedef struct CPUARMState {
uint32_t regs[16];
@@ -49,7 +47,6 @@ typedef struct CPUARMState {
CPUARMState *cpu_arm_init(void);
int cpu_arm_exec(CPUARMState *s);
void cpu_arm_interrupt(CPUARMState *s);
void cpu_arm_close(CPUARMState *s);
/* you can call this signal handler from your SIGBUS and SIGSEGV
signal handlers to inform the virtual CPU of exceptions. non zero

View File

@@ -24,9 +24,17 @@ register uint32_t T0 asm(AREG1);
register uint32_t T1 asm(AREG2);
register uint32_t T2 asm(AREG3);
#include "cpu-arm.h"
#include "exec.h"
#include "cpu.h"
#include "exec-all.h"
void cpu_lock(void);
void cpu_unlock(void);
void cpu_loop_exit(void);
static inline int compute_cpsr(void)
{
int ZF;
ZF = (env->NZF == 0);
return env->cpsr | (env->NZF & 0x80000000) | (ZF << 30) |
(env->CF << 29) | ((env->VF & 0x80000000) >> 3);
}

View File

@@ -17,71 +17,71 @@
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "exec-arm.h"
#include "exec.h"
#define REGNAME r0
#define REG (env->regs[0])
#include "op-arm-template.h"
#include "op_template.h"
#define REGNAME r1
#define REG (env->regs[1])
#include "op-arm-template.h"
#include "op_template.h"
#define REGNAME r2
#define REG (env->regs[2])
#include "op-arm-template.h"
#include "op_template.h"
#define REGNAME r3
#define REG (env->regs[3])
#include "op-arm-template.h"
#include "op_template.h"
#define REGNAME r4
#define REG (env->regs[4])
#include "op-arm-template.h"
#include "op_template.h"
#define REGNAME r5
#define REG (env->regs[5])
#include "op-arm-template.h"
#include "op_template.h"
#define REGNAME r6
#define REG (env->regs[6])
#include "op-arm-template.h"
#include "op_template.h"
#define REGNAME r7
#define REG (env->regs[7])
#include "op-arm-template.h"
#include "op_template.h"
#define REGNAME r8
#define REG (env->regs[8])
#include "op-arm-template.h"
#include "op_template.h"
#define REGNAME r9
#define REG (env->regs[9])
#include "op-arm-template.h"
#include "op_template.h"
#define REGNAME r10
#define REG (env->regs[10])
#include "op-arm-template.h"
#include "op_template.h"
#define REGNAME r11
#define REG (env->regs[11])
#include "op-arm-template.h"
#include "op_template.h"
#define REGNAME r12
#define REG (env->regs[12])
#include "op-arm-template.h"
#include "op_template.h"
#define REGNAME r13
#define REG (env->regs[13])
#include "op-arm-template.h"
#include "op_template.h"
#define REGNAME r14
#define REG (env->regs[14])
#include "op-arm-template.h"
#include "op_template.h"
#define REGNAME r15
#define REG (env->regs[15])
#include "op-arm-template.h"
#include "op_template.h"
void OPPROTO op_movl_T0_0(void)
{
@@ -154,11 +154,11 @@ void OPPROTO op_adcl_T0_T1_cc(void)
FORCE_RET();
}
#define OPSUB(sub, sbc, T0, T1) \
#define OPSUB(sub, sbc, res, T0, T1) \
\
void OPPROTO op_ ## sub ## l_T0_T1(void) \
{ \
T0 -= T1; \
res = T0 - T1; \
} \
\
void OPPROTO op_ ## sub ## l_T0_T1_cc(void) \
@@ -167,13 +167,14 @@ void OPPROTO op_ ## sub ## l_T0_T1_cc(void) \
src1 = T0; \
T0 -= T1; \
env->NZF = T0; \
env->CF = src1 < T1; \
env->CF = src1 >= T1; \
env->VF = (src1 ^ T1) & (src1 ^ T0); \
res = T0; \
} \
\
void OPPROTO op_ ## sbc ## l_T0_T1(void) \
{ \
T0 = T0 - T1 + env->CF - 1; \
res = T0 - T1 + env->CF - 1; \
} \
\
void OPPROTO op_ ## sbc ## l_T0_T1_cc(void) \
@@ -182,20 +183,20 @@ void OPPROTO op_ ## sbc ## l_T0_T1_cc(void) \
src1 = T0; \
if (!env->CF) { \
T0 = T0 - T1 - 1; \
T0 += T1; \
env->CF = src1 < T1; \
env->CF = src1 >= T1; \
} else { \
T0 = T0 - T1; \
env->CF = src1 <= T1; \
env->CF = src1 > T1; \
} \
env->VF = (src1 ^ T1) & (src1 ^ T0); \
env->NZF = T0; \
res = T0; \
FORCE_RET(); \
}
OPSUB(sub, sbc, T0, T1)
OPSUB(sub, sbc, T0, T0, T1)
OPSUB(rsb, rsc, T1, T0)
OPSUB(rsb, rsc, T0, T1, T0)
void OPPROTO op_andl_T0_T1(void)
{
@@ -222,122 +223,129 @@ void OPPROTO op_notl_T1(void)
T1 = ~T1;
}
void OPPROTO op_logic_cc(void)
void OPPROTO op_logic_T0_cc(void)
{
env->NZF = T0;
}
void OPPROTO op_logic_T1_cc(void)
{
env->NZF = T1;
}
#define EIP (env->regs[15])
void OPPROTO op_test_eq(void)
{
if (env->NZF == 0)
JUMP_TB(PARAM1, 0, PARAM2);
JUMP_TB(op_test_eq, PARAM1, 0, PARAM2);
FORCE_RET();
}
void OPPROTO op_test_ne(void)
{
if (env->NZF != 0)
JUMP_TB(PARAM1, 0, PARAM2);
JUMP_TB(op_test_ne, PARAM1, 0, PARAM2);
FORCE_RET();
}
void OPPROTO op_test_cs(void)
{
if (env->CF != 0)
JUMP_TB(PARAM1, 0, PARAM2);
JUMP_TB(op_test_cs, PARAM1, 0, PARAM2);
FORCE_RET();
}
void OPPROTO op_test_cc(void)
{
if (env->CF == 0)
JUMP_TB(PARAM1, 0, PARAM2);
JUMP_TB(op_test_cc, PARAM1, 0, PARAM2);
FORCE_RET();
}
void OPPROTO op_test_mi(void)
{
if ((env->NZF & 0x80000000) != 0)
JUMP_TB(PARAM1, 0, PARAM2);
JUMP_TB(op_test_mi, PARAM1, 0, PARAM2);
FORCE_RET();
}
void OPPROTO op_test_pl(void)
{
if ((env->NZF & 0x80000000) == 0)
JUMP_TB(PARAM1, 0, PARAM2);
JUMP_TB(op_test_pl, PARAM1, 0, PARAM2);
FORCE_RET();
}
void OPPROTO op_test_vs(void)
{
if ((env->VF & 0x80000000) != 0)
JUMP_TB(PARAM1, 0, PARAM2);
JUMP_TB(op_test_vs, PARAM1, 0, PARAM2);
FORCE_RET();
}
void OPPROTO op_test_vc(void)
{
if ((env->VF & 0x80000000) == 0)
JUMP_TB(PARAM1, 0, PARAM2);
JUMP_TB(op_test_vc, PARAM1, 0, PARAM2);
FORCE_RET();
}
void OPPROTO op_test_hi(void)
{
if (env->CF != 0 && env->NZF != 0)
JUMP_TB(PARAM1, 0, PARAM2);
JUMP_TB(op_test_hi, PARAM1, 0, PARAM2);
FORCE_RET();
}
void OPPROTO op_test_ls(void)
{
if (env->CF == 0 || env->NZF == 0)
JUMP_TB(PARAM1, 0, PARAM2);
JUMP_TB(op_test_ls, PARAM1, 0, PARAM2);
FORCE_RET();
}
void OPPROTO op_test_ge(void)
{
if (((env->VF ^ env->NZF) & 0x80000000) == 0)
JUMP_TB(PARAM1, 0, PARAM2);
JUMP_TB(op_test_ge, PARAM1, 0, PARAM2);
FORCE_RET();
}
void OPPROTO op_test_lt(void)
{
if (((env->VF ^ env->NZF) & 0x80000000) != 0)
JUMP_TB(PARAM1, 0, PARAM2);
JUMP_TB(op_test_lt, PARAM1, 0, PARAM2);
FORCE_RET();
}
void OPPROTO op_test_gt(void)
{
if (env->NZF != 0 && ((env->VF ^ env->NZF) & 0x80000000) == 0)
JUMP_TB(PARAM1, 0, PARAM2);
JUMP_TB(op_test_gt, PARAM1, 0, PARAM2);
FORCE_RET();
}
void OPPROTO op_test_le(void)
{
if (env->NZF == 0 || ((env->VF ^ env->NZF) & 0x80000000) != 0)
JUMP_TB(PARAM1, 0, PARAM2);
JUMP_TB(op_test_le, PARAM1, 0, PARAM2);
FORCE_RET();
}
void OPPROTO op_jmp(void)
{
JUMP_TB(PARAM1, 1, PARAM2);
JUMP_TB(op_jmp, PARAM1, 1, PARAM2);
}
void OPPROTO op_exit_tb(void)
{
EXIT_TB();
}
void OPPROTO op_movl_T0_psr(void)
{
int ZF;
ZF = (env->NZF == 0);
T0 = env->cpsr | (env->NZF & 0x80000000) | (ZF << 30) |
(env->CF << 29) | ((env->VF & 0x80000000) >> 3);
T0 = compute_cpsr();
}
/* NOTE: N = 1 and Z = 1 cannot be stored currently */
@@ -360,7 +368,7 @@ void OPPROTO op_mul_T0_T1(void)
void OPPROTO op_mull_T0_T1(void)
{
uint64_t res;
res = T0 * T1;
res = (uint64_t)T0 * (uint64_t)T1;
T1 = res >> 32;
T0 = res;
}
@@ -369,7 +377,7 @@ void OPPROTO op_mull_T0_T1(void)
void OPPROTO op_imull_T0_T1(void)
{
uint64_t res;
res = (int32_t)T0 * (int32_t)T1;
res = (int64_t)((int32_t)T0) * (int64_t)((int32_t)T1);
T1 = res >> 32;
T0 = res;
}

View File

@@ -23,8 +23,8 @@
#include <string.h>
#include <inttypes.h>
#include "cpu-arm.h"
#include "exec.h"
#include "cpu.h"
#include "exec-all.h"
#include "disas.h"
/* internal defines */
@@ -34,6 +34,8 @@ typedef struct DisasContext {
struct TranslationBlock *tb;
} DisasContext;
#define DISAS_JUMP_NEXT 4
/* XXX: move that elsewhere */
static uint16_t *gen_opc_ptr;
static uint32_t *gen_opparam_ptr;
@@ -42,12 +44,12 @@ extern int loglevel;
enum {
#define DEF(s, n, copy_size) INDEX_op_ ## s,
#include "opc-arm.h"
#include "opc.h"
#undef DEF
NB_OPS,
};
#include "gen-op-arm.h"
#include "gen-op.h"
typedef void (GenOpFunc)(void);
typedef void (GenOpFunc1)(long);
@@ -333,10 +335,11 @@ static void disas_arm_insn(DisasContext *s)
/* if not always execute, we generate a conditional jump to
next instruction */
gen_test_cc[cond ^ 1]((long)s->tb, (long)s->pc);
s->is_jmp = 1;
s->is_jmp = DISAS_JUMP_NEXT;
}
if ((insn & 0x0c000000) == 0 &&
(insn & 0x00000090) != 0x90) {
if (((insn & 0x0e000000) == 0 &&
(insn & 0x00000090) != 0x90) ||
((insn & 0x0e000000) == (1 << 25))) {
int set_cc, logic_cc, shiftop;
op1 = (insn >> 21) & 0xf;
@@ -367,7 +370,7 @@ static void disas_arm_insn(DisasContext *s)
}
}
} else {
rs = (insn >> 16) & 0xf;
rs = (insn >> 8) & 0xf;
gen_movl_T0_reg(s, rs);
if (logic_cc) {
gen_shift_T1_T0_cc[shiftop]();
@@ -385,10 +388,14 @@ static void disas_arm_insn(DisasContext *s)
case 0x00:
gen_op_andl_T0_T1();
gen_movl_reg_T0(s, rd);
if (logic_cc)
gen_op_logic_T0_cc();
break;
case 0x01:
gen_op_xorl_T0_T1();
gen_movl_reg_T0(s, rd);
if (logic_cc)
gen_op_logic_T0_cc();
break;
case 0x02:
if (set_cc)
@@ -435,11 +442,13 @@ static void disas_arm_insn(DisasContext *s)
case 0x08:
if (set_cc) {
gen_op_andl_T0_T1();
gen_op_logic_T0_cc();
}
break;
case 0x09:
if (set_cc) {
gen_op_xorl_T0_T1();
gen_op_logic_T0_cc();
}
break;
case 0x0a:
@@ -455,22 +464,28 @@ static void disas_arm_insn(DisasContext *s)
case 0x0c:
gen_op_orl_T0_T1();
gen_movl_reg_T0(s, rd);
if (logic_cc)
gen_op_logic_T0_cc();
break;
case 0x0d:
gen_movl_reg_T1(s, rd);
if (logic_cc)
gen_op_logic_T1_cc();
break;
case 0x0e:
gen_op_bicl_T0_T1();
gen_movl_reg_T0(s, rd);
if (logic_cc)
gen_op_logic_T0_cc();
break;
default:
case 0x0f:
gen_op_notl_T1();
gen_movl_reg_T1(s, rd);
if (logic_cc)
gen_op_logic_T1_cc();
break;
}
if (logic_cc)
gen_op_logic_cc();
} else {
/* other instructions */
op1 = (insn >> 24) & 0xf;
@@ -494,16 +509,16 @@ static void disas_arm_insn(DisasContext *s)
gen_op_addl_T0_T1();
}
if (insn & (1 << 20))
gen_op_logic_cc();
gen_op_logic_T0_cc();
gen_movl_reg_T0(s, rd);
} else {
/* 64 bit mul */
gen_movl_T0_reg(s, rs);
gen_movl_T1_reg(s, rm);
if (insn & (1 << 22))
gen_op_mull_T0_T1();
else
gen_op_imull_T0_T1();
else
gen_op_mull_T0_T1();
if (insn & (1 << 21))
gen_op_addq_T0_T1(rn, rd);
if (insn & (1 << 20))
@@ -531,8 +546,7 @@ static void disas_arm_insn(DisasContext *s)
rn = (insn >> 16) & 0xf;
rd = (insn >> 12) & 0xf;
gen_movl_T1_reg(s, rn);
if (insn & (1 << 25))
gen_add_datah_offset(s, insn);
gen_add_datah_offset(s, insn);
if (insn & (1 << 20)) {
/* load */
switch(sh) {
@@ -547,14 +561,18 @@ static void disas_arm_insn(DisasContext *s)
gen_op_ldsw_T0_T1();
break;
}
gen_movl_reg_T0(s, rd);
} else {
/* store */
gen_movl_T0_reg(s, rd);
gen_op_stw_T0_T1();
}
if (!(insn & (1 << 24)))
if (!(insn & (1 << 24))) {
gen_add_datah_offset(s, insn);
if (insn & (1 << 21))
gen_movl_reg_T1(s, rn);
} else if (insn & (1 << 21)) {
gen_movl_reg_T1(s, rn);
}
}
break;
case 0x4:
@@ -582,40 +600,94 @@ static void disas_arm_insn(DisasContext *s)
else
gen_op_stl_T0_T1();
}
if (!(insn & (1 << 24)))
if (!(insn & (1 << 24))) {
gen_add_data_offset(s, insn);
if (insn & (1 << 21))
gen_movl_reg_T1(s, rn);
} else if (insn & (1 << 21))
gen_movl_reg_T1(s, rn); {
}
break;
case 0x08:
case 0x09:
/* load/store multiple words */
if (insn & (1 << 22))
goto illegal_op; /* only usable in supervisor mode */
rn = (insn >> 16) & 0xf;
gen_movl_T1_reg(s, rn);
val = 4;
if (!(insn & (1 << 23)))
val = -val;
for(i=0;i<16;i++) {
if (insn & (1 << i)) {
if (insn & (1 << 24))
gen_op_addl_T1_im(val);
if (insn & (1 << 20)) {
/* load */
gen_op_ldl_T0_T1();
gen_movl_reg_T0(s, i);
{
int j, n;
/* load/store multiple words */
/* XXX: store correct base if write back */
if (insn & (1 << 22))
goto illegal_op; /* only usable in supervisor mode */
rn = (insn >> 16) & 0xf;
gen_movl_T1_reg(s, rn);
/* compute total size */
n = 0;
for(i=0;i<16;i++) {
if (insn & (1 << i))
n++;
}
/* XXX: test invalid n == 0 case ? */
if (insn & (1 << 23)) {
if (insn & (1 << 24)) {
/* pre increment */
gen_op_addl_T1_im(4);
} else {
/* store */
gen_movl_T0_reg(s, i);
gen_op_stl_T0_T1();
/* post increment */
}
if (!(insn & (1 << 24)))
gen_op_addl_T1_im(val);
} else {
if (insn & (1 << 24)) {
/* pre decrement */
gen_op_addl_T1_im(-(n * 4));
} else {
/* post decrement */
if (n != 1)
gen_op_addl_T1_im(-((n - 1) * 4));
}
}
j = 0;
for(i=0;i<16;i++) {
if (insn & (1 << i)) {
if (insn & (1 << 20)) {
/* load */
gen_op_ldl_T0_T1();
gen_movl_reg_T0(s, i);
} else {
/* store */
if (i == 15) {
/* special case: r15 = PC + 12 */
val = (long)s->pc + 8;
gen_op_movl_TN_im[0](val);
} else {
gen_movl_T0_reg(s, i);
}
gen_op_stl_T0_T1();
}
j++;
/* no need to add after the last transfer */
if (j != n)
gen_op_addl_T1_im(4);
}
}
if (insn & (1 << 21)) {
/* write back */
if (insn & (1 << 23)) {
if (insn & (1 << 24)) {
/* pre increment */
} else {
/* post increment */
gen_op_addl_T1_im(4);
}
} else {
if (insn & (1 << 24)) {
/* pre decrement */
if (n != 1)
gen_op_addl_T1_im(-((n - 1) * 4));
} else {
/* post decrement */
gen_op_addl_T1_im(-(n * 4));
}
}
gen_movl_reg_T1(s, rn);
}
}
if (insn & (1 << 21))
gen_movl_reg_T1(s, rn);
break;
case 0xa:
case 0xb:
@@ -641,6 +713,66 @@ static void disas_arm_insn(DisasContext *s)
gen_op_swi();
s->is_jmp = DISAS_JUMP;
break;
case 0xc:
case 0xd:
rd = (insn >> 12) & 0x7;
rn = (insn >> 16) & 0xf;
gen_movl_T1_reg(s, rn);
val = (insn) & 0xff;
if (!(insn & (1 << 23)))
val = -val;
switch((insn >> 8) & 0xf) {
case 0x1:
/* load/store */
if ((insn & (1 << 24)))
gen_op_addl_T1_im(val);
/* XXX: do it */
if (!(insn & (1 << 24)))
gen_op_addl_T1_im(val);
if (insn & (1 << 21))
gen_movl_reg_T1(s, rn);
break;
case 0x2:
{
int n, i;
/* load store multiple */
if ((insn & (1 << 24)))
gen_op_addl_T1_im(val);
switch(insn & 0x00408000) {
case 0x00008000: n = 1; break;
case 0x00400000: n = 2; break;
case 0x00408000: n = 3; break;
default: n = 4; break;
}
for(i = 0;i < n; i++) {
/* XXX: do it */
}
if (!(insn & (1 << 24)))
gen_op_addl_T1_im(val);
if (insn & (1 << 21))
gen_movl_reg_T1(s, rn);
}
break;
default:
goto illegal_op;
}
break;
case 0x0e:
/* float ops */
/* XXX: do it */
switch((insn >> 20) & 0xf) {
case 0x2: /* wfs */
break;
case 0x3: /* rfs */
break;
case 0x4: /* wfc */
break;
case 0x5: /* rfc */
break;
default:
goto illegal_op;
}
break;
default:
illegal_op:
gen_op_movl_T0_im((long)s->pc - 4);
@@ -655,7 +787,9 @@ static void disas_arm_insn(DisasContext *s)
/* generate intermediate code in gen_opc_buf and gen_opparam_buf for
basic block 'tb'. If search_pc is TRUE, also generate PC
information for each intermediate instruction. */
static inline int gen_intermediate_code_internal(TranslationBlock *tb, int search_pc)
static inline int gen_intermediate_code_internal(CPUState *env,
TranslationBlock *tb,
int search_pc)
{
DisasContext dc1, *dc = &dc1;
uint16_t *gen_opc_end;
@@ -681,22 +815,27 @@ static inline int gen_intermediate_code_internal(TranslationBlock *tb, int searc
lj++;
while (lj < j)
gen_opc_instr_start[lj++] = 0;
gen_opc_pc[lj] = (uint32_t)dc->pc;
gen_opc_instr_start[lj] = 1;
}
gen_opc_pc[lj] = (uint32_t)dc->pc;
gen_opc_instr_start[lj] = 1;
}
disas_arm_insn(dc);
} while (!dc->is_jmp && gen_opc_ptr < gen_opc_end &&
(dc->pc - pc_start) < (TARGET_PAGE_SIZE - 32));
/* we must store the eflags state if it is not already done */
if (dc->is_jmp != DISAS_TB_JUMP &&
dc->is_jmp != DISAS_JUMP) {
gen_op_movl_T0_im((long)dc->pc - 4);
gen_op_movl_reg_TN[0][15]();
}
if (dc->is_jmp != DISAS_TB_JUMP) {
switch(dc->is_jmp) {
case DISAS_JUMP_NEXT:
case DISAS_NEXT:
gen_op_jmp((long)dc->tb, (long)dc->pc);
break;
default:
case DISAS_JUMP:
/* indicate that the hash table must be used to find the next TB */
gen_op_movl_T0_0();
gen_op_exit_tb();
break;
case DISAS_TB_JUMP:
/* nothing more to generate */
break;
}
*gen_opc_ptr = INDEX_op_end;
@@ -717,14 +856,14 @@ static inline int gen_intermediate_code_internal(TranslationBlock *tb, int searc
return 0;
}
int gen_intermediate_code(TranslationBlock *tb)
int gen_intermediate_code(CPUState *env, TranslationBlock *tb)
{
return gen_intermediate_code_internal(tb, 0);
return gen_intermediate_code_internal(env, tb, 0);
}
int gen_intermediate_code_pc(TranslationBlock *tb)
int gen_intermediate_code_pc(CPUState *env, TranslationBlock *tb)
{
return gen_intermediate_code_internal(tb, 1);
return gen_intermediate_code_internal(env, tb, 1);
}
CPUARMState *cpu_arm_init(void)
@@ -756,5 +895,10 @@ void cpu_arm_dump_state(CPUARMState *env, FILE *f, int flags)
else
fprintf(f, " ");
}
fprintf(f, "CPSR=%08x", env->cpsr);
fprintf(f, "PSR=%08x %c%c%c%c\n",
env->cpsr,
env->cpsr & (1 << 31) ? 'N' : '-',
env->cpsr & (1 << 30) ? 'Z' : '-',
env->cpsr & (1 << 29) ? 'C' : '-',
env->cpsr & (1 << 28) ? 'V' : '-');
}

View File

@@ -20,8 +20,7 @@
#ifndef CPU_I386_H
#define CPU_I386_H
#include "config.h"
#include <setjmp.h>
#include "cpu-defs.h"
#define R_EAX 0
#define R_ECX 1
@@ -59,12 +58,14 @@
#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_CS_MASK (1 << 11) /* 1=code segment 0=data segment */
#define DESC_C_MASK (1 << 10) /* code: conforming */
#define DESC_R_MASK (1 << 9) /* code: readable */
#define DESC_E_MASK (1 << 10)
#define DESC_W_MASK (1 << 9)
#define DESC_E_MASK (1 << 10) /* data: expansion direction */
#define DESC_W_MASK (1 << 9) /* data: writable */
#define DESC_TSS_BUSY_MASK (1 << 9)
/* eflags masks */
#define CC_C 0x0001
@@ -74,6 +75,10 @@
#define CC_S 0x0080
#define CC_O 0x0800
#define TF_SHIFT 8
#define IOPL_SHIFT 12
#define VM_SHIFT 17
#define TF_MASK 0x00000100
#define IF_MASK 0x00000200
#define DF_MASK 0x00000400
@@ -86,6 +91,29 @@
#define VIP_MASK 0x00100000
#define ID_MASK 0x00200000
/* hidden flags - used internally by qemu to represent additionnal cpu
states. Only the CPL and INHIBIT_IRQ are not redundant. We avoid
using the IOPL_MASK, TF_MASK and VM_MASK bit position to ease oring
with eflags. */
/* current cpl */
#define HF_CPL_SHIFT 0
/* true if soft mmu is being used */
#define HF_SOFTMMU_SHIFT 2
/* true if hardware interrupts must be disabled for next instruction */
#define HF_INHIBIT_IRQ_SHIFT 3
/* 16 or 32 segments */
#define HF_CS32_SHIFT 4
#define HF_SS32_SHIFT 5
/* zero base for DS, ES and SS */
#define HF_ADDSEG_SHIFT 6
#define HF_CPL_MASK (3 << HF_CPL_SHIFT)
#define HF_SOFTMMU_MASK (1 << HF_SOFTMMU_SHIFT)
#define HF_INHIBIT_IRQ_MASK (1 << HF_INHIBIT_IRQ_SHIFT)
#define HF_CS32_MASK (1 << HF_CS32_SHIFT)
#define HF_SS32_MASK (1 << HF_SS32_SHIFT)
#define HF_ADDSEG_MASK (1 << HF_ADDSEG_SHIFT)
#define CR0_PE_MASK (1 << 0)
#define CR0_TS_MASK (1 << 3)
#define CR0_WP_MASK (1 << 16)
@@ -125,6 +153,15 @@
#define PG_ERROR_U_MASK 0x04
#define PG_ERROR_RSVD_MASK 0x08
#define MSR_IA32_APICBASE 0x1b
#define MSR_IA32_APICBASE_BSP (1<<8)
#define MSR_IA32_APICBASE_ENABLE (1<<11)
#define MSR_IA32_APICBASE_BASE (0xfffff<<12)
#define MSR_IA32_SYSENTER_CS 0x174
#define MSR_IA32_SYSENTER_ESP 0x175
#define MSR_IA32_SYSENTER_EIP 0x176
#define EXCP00_DIVZ 0
#define EXCP01_SSTP 1
#define EXCP02_NMI 2
@@ -144,13 +181,13 @@
#define EXCP11_ALGN 17
#define EXCP12_MCHK 18
#define EXCP_INTERRUPT 256 /* async interruption */
#define EXCP_HLT 257 /* hlt instruction reached */
enum {
CC_OP_DYNAMIC, /* must use dynamic code to get cc_op */
CC_OP_EFLAGS, /* all cc are explicitely computed, CC_SRC = flags */
CC_OP_MUL, /* modify all flags, C, O = (CC_SRC != 0) */
CC_OP_MULB, /* modify all flags, C, O = (CC_SRC != 0) */
CC_OP_MULW,
CC_OP_MULL,
CC_OP_ADDB, /* modify all flags, CC_DST = res, CC_SRC = src1 */
CC_OP_ADDW,
@@ -221,6 +258,7 @@ typedef struct CPUX86State {
uint32_t cc_dst;
uint32_t cc_op;
int32_t df; /* D flag : 1 if D = 0, -1 if D = 1 */
uint32_t hflags; /* hidden flags, see HF_xxx constants */
/* FPU state */
unsigned int fpstt; /* top of stack index */
@@ -245,6 +283,11 @@ typedef struct CPUX86State {
SegmentCache gdt; /* only base and limit are used */
SegmentCache idt; /* only base and limit are used */
/* sysenter registers */
uint32_t sysenter_cs;
uint32_t sysenter_esp;
uint32_t sysenter_eip;
/* exception/interrupt handling */
jmp_buf jmp_env;
int exception_index;
@@ -254,12 +297,19 @@ typedef struct CPUX86State {
struct TranslationBlock *current_tb; /* currently executing TB */
uint32_t cr[5]; /* NOTE: cr1 is unused */
uint32_t dr[8]; /* debug registers */
int interrupt_request; /* if true, will exit from cpu_exec() ASAP */
/* if true, will call cpu_x86_get_pic_interrupt() ASAP to get the
request interrupt number */
int hard_interrupt_request;
int interrupt_request;
int user_mode_only; /* user mode only simulation */
/* soft mmu support */
/* 0 = kernel, 1 = user */
CPUTLBEntry tlb_read[2][CPU_TLB_SIZE];
CPUTLBEntry tlb_write[2][CPU_TLB_SIZE];
/* ice debug support */
uint32_t breakpoints[MAX_BREAKPOINTS];
int nb_breakpoints;
int singlestep_enabled;
/* user data */
void *opaque;
} CPUX86State;
@@ -275,14 +325,60 @@ int cpu_x86_inl(CPUX86State *env, int addr);
CPUX86State *cpu_x86_init(void);
int cpu_x86_exec(CPUX86State *s);
void cpu_x86_interrupt(CPUX86State *s);
void cpu_x86_close(CPUX86State *s);
int cpu_x86_get_pic_interrupt(CPUX86State *s);
/* needed to load some predefinied segment registers */
void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector);
/* this function must always be used to load data in the segment
cache: it synchronizes the hflags with the segment cache values */
static inline void cpu_x86_load_seg_cache(CPUX86State *env,
int seg_reg, unsigned int selector,
uint8_t *base, unsigned int limit,
unsigned int flags)
{
SegmentCache *sc;
unsigned int new_hflags;
sc = &env->segs[seg_reg];
sc->selector = selector;
sc->base = base;
sc->limit = limit;
sc->flags = flags;
/* simulate fsave/frstor */
/* update the hidden flags */
new_hflags = (env->segs[R_CS].flags & DESC_B_MASK)
>> (DESC_B_SHIFT - HF_CS32_SHIFT);
new_hflags |= (env->segs[R_SS].flags & DESC_B_MASK)
>> (DESC_B_SHIFT - HF_SS32_SHIFT);
if (!(env->cr[0] & CR0_PE_MASK) || (env->eflags & VM_MASK)) {
/* XXX: try to avoid this test. The problem comes from the
fact that is real mode or vm86 mode we only modify the
'base' and 'selector' fields of the segment cache to go
faster. A solution may be to force addseg to one in
translate-i386.c. */
new_hflags |= HF_ADDSEG_MASK;
} else {
new_hflags |= (((unsigned long)env->segs[R_DS].base |
(unsigned long)env->segs[R_ES].base |
(unsigned long)env->segs[R_SS].base) != 0) <<
HF_ADDSEG_SHIFT;
}
env->hflags = (env->hflags &
~(HF_CS32_MASK | HF_SS32_MASK | HF_ADDSEG_MASK)) | new_hflags;
}
/* wrapper, just in case memory mappings must be changed */
static inline void cpu_x86_set_cpl(CPUX86State *s, int cpl)
{
#if HF_CPL_MASK == 3
s->hflags = (s->hflags & ~HF_CPL_MASK) | cpl;
#else
#error HF_CPL_MASK is hardcoded
#endif
}
/* the following helpers are only usable in user mode simulation as
they can trigger unexpected exceptions */
void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector);
void cpu_x86_fsave(CPUX86State *s, uint8_t *ptr, int data32);
void cpu_x86_frstor(CPUX86State *s, uint8_t *ptr, int data32);
@@ -298,6 +394,9 @@ void cpu_x86_init_mmu(CPUX86State *env);
extern int phys_ram_size;
extern int phys_ram_fd;
extern uint8_t *phys_ram_base;
extern int a20_enabled;
void cpu_x86_set_a20(CPUX86State *env, int a20_state);
/* used to debug */
#define X86_DUMP_FPU 0x0001 /* dump FPU state too */

View File

@@ -112,8 +112,8 @@ extern int loglevel;
#define FP_CONVERT (env->fp_convert)
#endif
#include "cpu-i386.h"
#include "exec.h"
#include "cpu.h"
#include "exec-all.h"
typedef struct CCTable {
int (*compute_all)(void); /* return all the flags */
@@ -122,9 +122,13 @@ typedef struct CCTable {
extern CCTable cc_table[];
void load_seg(int seg_reg, int selector, unsigned cur_eip);
void jmp_seg(int selector, unsigned int new_eip);
void load_seg(int seg_reg, int selector);
void helper_ljmp_protected_T0_T1(void);
void helper_lcall_real_T0_T1(int shift, int next_eip);
void helper_lcall_protected_T0_T1(int shift, int next_eip);
void helper_iret_real(int shift);
void helper_iret_protected(int shift);
void helper_lret_protected(int shift, int addend);
void helper_lldt_T0(void);
void helper_ltr_T0(void);
void helper_movl_crN_T0(int reg);
@@ -133,11 +137,14 @@ void helper_invlpg(unsigned int addr);
void cpu_x86_update_cr0(CPUX86State *env);
void cpu_x86_update_cr3(CPUX86State *env);
void cpu_x86_flush_tlb(CPUX86State *env, uint32_t addr);
int cpu_x86_handle_mmu_fault(CPUX86State *env, uint32_t addr, int is_write);
int cpu_x86_handle_mmu_fault(CPUX86State *env, uint32_t addr,
int is_write, int is_user, int is_softmmu);
void tlb_fill(unsigned long addr, int is_write, int is_user,
void *retaddr);
void __hidden cpu_lock(void);
void __hidden cpu_unlock(void);
void do_interrupt(int intno, int is_int, int error_code,
unsigned int next_eip);
unsigned int next_eip, int is_hw);
void do_interrupt_user(int intno, int is_int, int error_code,
unsigned int next_eip);
void raise_interrupt(int intno, int is_int, int error_code,
@@ -159,8 +166,128 @@ void helper_idivl_EAX_T0(uint32_t eip);
void helper_cmpxchg8b(void);
void helper_cpuid(void);
void helper_rdtsc(void);
void helper_rdmsr(void);
void helper_wrmsr(void);
void helper_lsl(void);
void helper_lar(void);
void helper_verr(void);
void helper_verw(void);
void check_iob_T0(void);
void check_iow_T0(void);
void check_iol_T0(void);
void check_iob_DX(void);
void check_iow_DX(void);
void check_iol_DX(void);
/* XXX: move that to a generic header */
#if !defined(CONFIG_USER_ONLY)
#define ldul_user ldl_user
#define ldul_kernel ldl_kernel
#define ACCESS_TYPE 0
#define MEMSUFFIX _kernel
#define DATA_SIZE 1
#include "softmmu_header.h"
#define DATA_SIZE 2
#include "softmmu_header.h"
#define DATA_SIZE 4
#include "softmmu_header.h"
#define DATA_SIZE 8
#include "softmmu_header.h"
#undef ACCESS_TYPE
#undef MEMSUFFIX
#define ACCESS_TYPE 1
#define MEMSUFFIX _user
#define DATA_SIZE 1
#include "softmmu_header.h"
#define DATA_SIZE 2
#include "softmmu_header.h"
#define DATA_SIZE 4
#include "softmmu_header.h"
#define DATA_SIZE 8
#include "softmmu_header.h"
#undef ACCESS_TYPE
#undef MEMSUFFIX
/* these access are slower, they must be as rare as possible */
#define ACCESS_TYPE 2
#define MEMSUFFIX _data
#define DATA_SIZE 1
#include "softmmu_header.h"
#define DATA_SIZE 2
#include "softmmu_header.h"
#define DATA_SIZE 4
#include "softmmu_header.h"
#define DATA_SIZE 8
#include "softmmu_header.h"
#undef ACCESS_TYPE
#undef MEMSUFFIX
#define ldub(p) ldub_data(p)
#define ldsb(p) ldsb_data(p)
#define lduw(p) lduw_data(p)
#define ldsw(p) ldsw_data(p)
#define ldl(p) ldl_data(p)
#define ldq(p) ldq_data(p)
#define stb(p, v) stb_data(p, v)
#define stw(p, v) stw_data(p, v)
#define stl(p, v) stl_data(p, v)
#define stq(p, v) stq_data(p, v)
static inline double ldfq(void *ptr)
{
union {
double d;
uint64_t i;
} u;
u.i = ldq(ptr);
return u.d;
}
static inline void stfq(void *ptr, double v)
{
union {
double d;
uint64_t i;
} u;
u.d = v;
stq(ptr, u.i);
}
static inline float ldfl(void *ptr)
{
union {
float f;
uint32_t i;
} u;
u.i = ldl(ptr);
return u.f;
}
static inline void stfl(void *ptr, float v)
{
union {
float f;
uint32_t i;
} u;
u.f = v;
stl(ptr, u.i);
}
#endif /* !defined(CONFIG_USER_ONLY) */
#ifdef USE_X86LDOUBLE
/* use long double functions */
@@ -308,7 +435,47 @@ static inline void helper_fstt(CPU86_LDouble f, uint8_t *ptr)
e |= SIGND(temp) >> 16;
stw(ptr + 8, e);
}
#endif
#else
/* XXX: same endianness assumed */
#ifdef CONFIG_USER_ONLY
static inline CPU86_LDouble helper_fldt(uint8_t *ptr)
{
return *(CPU86_LDouble *)ptr;
}
static inline void helper_fstt(CPU86_LDouble f, uint8_t *ptr)
{
*(CPU86_LDouble *)ptr = f;
}
#else
/* we use memory access macros */
static inline CPU86_LDouble helper_fldt(uint8_t *ptr)
{
CPU86_LDoubleU temp;
temp.l.lower = ldq(ptr);
temp.l.upper = lduw(ptr + 8);
return temp.d;
}
static inline void helper_fstt(CPU86_LDouble f, uint8_t *ptr)
{
CPU86_LDoubleU temp;
temp.d = f;
stq(ptr, temp.l.lower);
stw(ptr + 8, temp.l.upper);
}
#endif /* !CONFIG_USER_ONLY */
#endif /* USE_X86LDOUBLE */
const CPU86_LDouble f15rk[7];
@@ -345,11 +512,6 @@ static inline uint32_t compute_eflags(void)
return env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
}
#define FL_UPDATE_MASK32 (TF_MASK | AC_MASK | ID_MASK)
#define FL_UPDATE_CPL0_MASK (TF_MASK | IF_MASK | IOPL_MASK | NT_MASK | \
RF_MASK | AC_MASK | ID_MASK)
/* NOTE: CC_OP must be modified manually to CC_OP_EFLAGS */
static inline void load_eflags(int eflags, int update_mask)
{
@@ -358,3 +520,4 @@ static inline void load_eflags(int eflags, int update_mask)
env->eflags = (env->eflags & ~update_mask) |
(eflags & update_mask);
}

2454
target-i386/helper.c Normal file

File diff suppressed because it is too large Load Diff

444
target-i386/helper2.c Normal file
View File

@@ -0,0 +1,444 @@
/*
* i386 helpers (without register variable usage)
*
* Copyright (c) 2003 Fabrice Bellard
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <inttypes.h>
#include <signal.h>
#include <assert.h>
#include <sys/mman.h>
#include "cpu.h"
#include "exec-all.h"
//#define DEBUG_MMU
CPUX86State *cpu_x86_init(void)
{
CPUX86State *env;
int i;
static int inited;
cpu_exec_init();
env = malloc(sizeof(CPUX86State));
if (!env)
return NULL;
memset(env, 0, sizeof(CPUX86State));
/* basic FPU init */
for(i = 0;i < 8; i++)
env->fptags[i] = 1;
env->fpuc = 0x37f;
/* flags setup : we activate the IRQs by default as in user mode */
env->eflags = 0x2 | IF_MASK;
tlb_flush(env);
#ifdef CONFIG_SOFTMMU
env->hflags |= HF_SOFTMMU_MASK;
#endif
/* init various static tables */
if (!inited) {
inited = 1;
optimize_flags_init();
}
return env;
}
void cpu_x86_close(CPUX86State *env)
{
free(env);
}
/***********************************************************/
/* x86 debug */
static const char *cc_op_str[] = {
"DYNAMIC",
"EFLAGS",
"MULB",
"MULW",
"MULL",
"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",
};
void cpu_x86_dump_state(CPUX86State *env, FILE *f, int flags)
{
int eflags, i;
char cc_op_name[32];
static const char *seg_name[6] = { "ES", "CS", "SS", "DS", "FS", "GS" };
eflags = env->eflags;
fprintf(f, "EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n"
"ESI=%08x EDI=%08x EBP=%08x ESP=%08x\n"
"EIP=%08x EFL=%08x [%c%c%c%c%c%c%c] CPL=%d II=%d\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->eip, eflags,
eflags & DF_MASK ? '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->hflags & HF_CPL_MASK,
(env->hflags >> HF_INHIBIT_IRQ_SHIFT) & 1);
for(i = 0; i < 6; i++) {
SegmentCache *sc = &env->segs[i];
fprintf(f, "%s =%04x %08x %08x %08x\n",
seg_name[i],
sc->selector,
(int)sc->base,
sc->limit,
sc->flags);
}
fprintf(f, "LDT=%04x %08x %08x %08x\n",
env->ldt.selector,
(int)env->ldt.base,
env->ldt.limit,
env->ldt.flags);
fprintf(f, "TR =%04x %08x %08x %08x\n",
env->tr.selector,
(int)env->tr.base,
env->tr.limit,
env->tr.flags);
fprintf(f, "GDT= %08x %08x\n",
(int)env->gdt.base, env->gdt.limit);
fprintf(f, "IDT= %08x %08x\n",
(int)env->idt.base, env->idt.limit);
fprintf(f, "CR0=%08x CR2=%08x CR3=%08x CR4=%08x\n",
env->cr[0], env->cr[2], env->cr[3], env->cr[4]);
if (flags & X86_DUMP_CCOP) {
if ((unsigned)env->cc_op < CC_OP_NB)
strcpy(cc_op_name, cc_op_str[env->cc_op]);
else
snprintf(cc_op_name, sizeof(cc_op_name), "[%d]", env->cc_op);
fprintf(f, "CCS=%08x CCD=%08x CCO=%-8s\n",
env->cc_src, env->cc_dst, cc_op_name);
}
if (flags & X86_DUMP_FPU) {
fprintf(f, "ST0=%f ST1=%f ST2=%f ST3=%f\n",
(double)env->fpregs[0],
(double)env->fpregs[1],
(double)env->fpregs[2],
(double)env->fpregs[3]);
fprintf(f, "ST4=%f ST5=%f ST6=%f ST7=%f\n",
(double)env->fpregs[4],
(double)env->fpregs[5],
(double)env->fpregs[7],
(double)env->fpregs[8]);
}
}
/***********************************************************/
/* x86 mmu */
/* XXX: add PGE support */
/* called when cr3 or PG bit are modified */
static int last_pg_state = -1;
static int last_pe_state = 0;
static uint32_t a20_mask;
int a20_enabled;
int phys_ram_size;
int phys_ram_fd;
uint8_t *phys_ram_base;
void cpu_x86_set_a20(CPUX86State *env, int a20_state)
{
a20_state = (a20_state != 0);
if (a20_state != a20_enabled) {
#if defined(DEBUG_MMU)
printf("A20 update: a20=%d\n", a20_state);
#endif
/* if the cpu is currently executing code, we must unlink it and
all the potentially executing TB */
cpu_interrupt(env, 0);
/* when a20 is changed, all the MMU mappings are invalid, so
we must flush everything */
tlb_flush(env);
a20_enabled = a20_state;
if (a20_enabled)
a20_mask = 0xffffffff;
else
a20_mask = 0xffefffff;
}
}
void cpu_x86_update_cr0(CPUX86State *env)
{
int pg_state, pe_state;
#if defined(DEBUG_MMU)
printf("CR0 update: CR0=0x%08x\n", env->cr[0]);
#endif
pg_state = env->cr[0] & CR0_PG_MASK;
if (pg_state != last_pg_state) {
tlb_flush(env);
last_pg_state = pg_state;
}
pe_state = env->cr[0] & CR0_PE_MASK;
if (last_pe_state != pe_state) {
tb_flush(env);
last_pe_state = pe_state;
}
}
void cpu_x86_update_cr3(CPUX86State *env)
{
if (env->cr[0] & CR0_PG_MASK) {
#if defined(DEBUG_MMU)
printf("CR3 update: CR3=%08x\n", env->cr[3]);
#endif
tlb_flush(env);
}
}
void cpu_x86_init_mmu(CPUX86State *env)
{
a20_enabled = 1;
a20_mask = 0xffffffff;
last_pg_state = -1;
cpu_x86_update_cr0(env);
}
/* XXX: also flush 4MB pages */
void cpu_x86_flush_tlb(CPUX86State *env, uint32_t addr)
{
tlb_flush_page(env, addr);
}
/* return value:
-1 = cannot handle fault
0 = nothing more to do
1 = generate PF fault
2 = soft MMU activation required for this block
*/
int cpu_x86_handle_mmu_fault(CPUX86State *env, uint32_t addr,
int is_write, int is_user, int is_softmmu)
{
uint8_t *pde_ptr, *pte_ptr;
uint32_t pde, pte, virt_addr;
int error_code, is_dirty, prot, page_size, ret;
unsigned long pd;
#ifdef DEBUG_MMU
printf("MMU fault: addr=0x%08x w=%d u=%d eip=%08x\n",
addr, is_write, is_user, env->eip);
#endif
if (env->user_mode_only) {
/* user mode only emulation */
error_code = 0;
goto do_fault;
}
if (!(env->cr[0] & CR0_PG_MASK)) {
pte = addr;
virt_addr = addr & TARGET_PAGE_MASK;
prot = PROT_READ | PROT_WRITE;
page_size = 4096;
goto do_mapping;
}
/* page directory entry */
pde_ptr = phys_ram_base +
(((env->cr[3] & ~0xfff) + ((addr >> 20) & ~3)) & a20_mask);
pde = ldl_raw(pde_ptr);
if (!(pde & PG_PRESENT_MASK)) {
error_code = 0;
goto do_fault;
}
if (is_user) {
if (!(pde & PG_USER_MASK))
goto do_fault_protect;
if (is_write && !(pde & PG_RW_MASK))
goto do_fault_protect;
} else {
if ((env->cr[0] & CR0_WP_MASK) && (pde & PG_USER_MASK) &&
is_write && !(pde & PG_RW_MASK))
goto do_fault_protect;
}
/* if PSE bit is set, then we use a 4MB page */
if ((pde & PG_PSE_MASK) && (env->cr[4] & CR4_PSE_MASK)) {
is_dirty = is_write && !(pde & PG_DIRTY_MASK);
if (!(pde & PG_ACCESSED_MASK)) {
pde |= PG_ACCESSED_MASK;
if (is_dirty)
pde |= PG_DIRTY_MASK;
stl_raw(pde_ptr, pde);
}
pte = pde & ~0x003ff000; /* align to 4MB */
page_size = 4096 * 1024;
virt_addr = addr & ~0x003fffff;
} else {
if (!(pde & PG_ACCESSED_MASK)) {
pde |= PG_ACCESSED_MASK;
stl_raw(pde_ptr, pde);
}
/* page directory entry */
pte_ptr = phys_ram_base +
(((pde & ~0xfff) + ((addr >> 10) & 0xffc)) & a20_mask);
pte = ldl_raw(pte_ptr);
if (!(pte & PG_PRESENT_MASK)) {
error_code = 0;
goto do_fault;
}
if (is_user) {
if (!(pte & PG_USER_MASK))
goto do_fault_protect;
if (is_write && !(pte & PG_RW_MASK))
goto do_fault_protect;
} else {
if ((env->cr[0] & CR0_WP_MASK) && (pte & PG_USER_MASK) &&
is_write && !(pte & PG_RW_MASK))
goto do_fault_protect;
}
is_dirty = is_write && !(pte & PG_DIRTY_MASK);
if (!(pte & PG_ACCESSED_MASK) || is_dirty) {
pte |= PG_ACCESSED_MASK;
if (is_dirty)
pte |= PG_DIRTY_MASK;
stl_raw(pte_ptr, pte);
}
page_size = 4096;
virt_addr = addr & ~0xfff;
}
/* the page can be put in the TLB */
prot = PROT_READ;
if (is_user) {
if (pte & PG_RW_MASK)
prot |= PROT_WRITE;
} else {
if (!(env->cr[0] & CR0_WP_MASK) || !(pte & PG_USER_MASK) ||
(pte & PG_RW_MASK))
prot |= PROT_WRITE;
}
do_mapping:
pte = pte & a20_mask;
#if !defined(CONFIG_SOFTMMU)
if (is_softmmu)
#endif
{
unsigned long paddr, vaddr, address, addend, page_offset;
int index;
/* software MMU case. Even if 4MB pages, we map only one 4KB
page in the cache to avoid filling it too fast */
page_offset = (addr & TARGET_PAGE_MASK) & (page_size - 1);
paddr = (pte & TARGET_PAGE_MASK) + page_offset;
vaddr = virt_addr + page_offset;
index = (addr >> 12) & (CPU_TLB_SIZE - 1);
pd = physpage_find(paddr);
if (pd & 0xfff) {
/* IO memory case */
address = vaddr | pd;
addend = paddr;
} else {
/* standard memory */
address = vaddr;
addend = (unsigned long)phys_ram_base + pd;
}
addend -= vaddr;
env->tlb_read[is_user][index].address = address;
env->tlb_read[is_user][index].addend = addend;
if (prot & PROT_WRITE) {
env->tlb_write[is_user][index].address = address;
env->tlb_write[is_user][index].addend = addend;
} else {
env->tlb_write[is_user][index].address = -1;
env->tlb_write[is_user][index].addend = -1;
}
page_set_flags(vaddr, vaddr + TARGET_PAGE_SIZE,
PAGE_VALID | PAGE_EXEC | prot);
ret = 0;
}
#if !defined(CONFIG_SOFTMMU)
else {
ret = 0;
/* XXX: incorrect for 4MB pages */
pd = physpage_find(pte & ~0xfff);
if ((pd & 0xfff) != 0) {
/* IO access: no mapping is done as it will be handled by the
soft MMU */
if (!(env->hflags & HF_SOFTMMU_MASK))
ret = 2;
} else {
void *map_addr;
map_addr = mmap((void *)virt_addr, page_size, prot,
MAP_SHARED | MAP_FIXED, phys_ram_fd, pd);
if (map_addr == MAP_FAILED) {
fprintf(stderr,
"mmap failed when mapped physical address 0x%08x to virtual address 0x%08x\n",
pte & ~0xfff, virt_addr);
exit(1);
}
#ifdef DEBUG_MMU
printf("mmaping 0x%08x to virt 0x%08x pse=%d\n",
pte & ~0xfff, virt_addr, (page_size != 4096));
#endif
page_set_flags(virt_addr, virt_addr + page_size,
PAGE_VALID | PAGE_EXEC | prot);
}
}
#endif
return ret;
do_fault_protect:
error_code = PG_ERROR_P_MASK;
do_fault:
env->cr[2] = addr;
env->error_code = (is_write << PG_ERROR_W_BIT) | error_code;
if (is_user)
env->error_code |= PG_ERROR_U_MASK;
return 1;
}

View File

@@ -17,7 +17,7 @@
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "exec-i386.h"
#include "exec.h"
/* n must be a constant to be efficient */
static inline int lshift(int x, int n)
@@ -80,62 +80,34 @@ static inline int lshift(int x, int n)
/* operations with flags */
void OPPROTO op_addl_T0_T1_cc(void)
/* update flags with T0 and T1 (add/sub case) */
void OPPROTO op_update2_cc(void)
{
CC_SRC = T0;
T0 += T1;
CC_SRC = T1;
CC_DST = T0;
}
void OPPROTO op_orl_T0_T1_cc(void)
/* update flags with T0 (logic operation case) */
void OPPROTO op_update1_cc(void)
{
T0 |= T1;
CC_DST = T0;
}
void OPPROTO op_andl_T0_T1_cc(void)
void OPPROTO op_update_neg_cc(void)
{
T0 &= T1;
CC_DST = T0;
}
void OPPROTO op_subl_T0_T1_cc(void)
{
CC_SRC = T0;
T0 -= T1;
CC_DST = T0;
}
void OPPROTO op_xorl_T0_T1_cc(void)
{
T0 ^= T1;
CC_SRC = -T0;
CC_DST = T0;
}
void OPPROTO op_cmpl_T0_T1_cc(void)
{
CC_SRC = T0;
CC_SRC = T1;
CC_DST = T0 - T1;
}
void OPPROTO op_negl_T0_cc(void)
{
CC_SRC = 0;
T0 = -T0;
CC_DST = T0;
}
void OPPROTO op_incl_T0_cc(void)
void OPPROTO op_update_inc_cc(void)
{
CC_SRC = cc_table[CC_OP].compute_c();
T0++;
CC_DST = T0;
}
void OPPROTO op_decl_T0_cc(void)
{
CC_SRC = cc_table[CC_OP].compute_c();
T0--;
CC_DST = T0;
}
@@ -197,11 +169,16 @@ void OPPROTO op_bswapl_T0(void)
}
/* multiply/divide */
/* XXX: add eflags optimizations */
/* XXX: add non P4 style flags */
void OPPROTO op_mulb_AL_T0(void)
{
unsigned int res;
res = (uint8_t)EAX * (uint8_t)T0;
EAX = (EAX & 0xffff0000) | res;
CC_DST = res;
CC_SRC = (res & 0xff00);
}
@@ -210,6 +187,7 @@ void OPPROTO op_imulb_AL_T0(void)
int res;
res = (int8_t)EAX * (int8_t)T0;
EAX = (EAX & 0xffff0000) | (res & 0xffff);
CC_DST = res;
CC_SRC = (res != (int8_t)res);
}
@@ -219,6 +197,7 @@ void OPPROTO op_mulw_AX_T0(void)
res = (uint16_t)EAX * (uint16_t)T0;
EAX = (EAX & 0xffff0000) | (res & 0xffff);
EDX = (EDX & 0xffff0000) | ((res >> 16) & 0xffff);
CC_DST = res;
CC_SRC = res >> 16;
}
@@ -228,6 +207,7 @@ void OPPROTO op_imulw_AX_T0(void)
res = (int16_t)EAX * (int16_t)T0;
EAX = (EAX & 0xffff0000) | (res & 0xffff);
EDX = (EDX & 0xffff0000) | ((res >> 16) & 0xffff);
CC_DST = res;
CC_SRC = (res != (int16_t)res);
}
@@ -237,6 +217,7 @@ void OPPROTO op_mull_EAX_T0(void)
res = (uint64_t)((uint32_t)EAX) * (uint64_t)((uint32_t)T0);
EAX = res;
EDX = res >> 32;
CC_DST = res;
CC_SRC = res >> 32;
}
@@ -246,6 +227,7 @@ void OPPROTO op_imull_EAX_T0(void)
res = (int64_t)((int32_t)EAX) * (int64_t)((int32_t)T0);
EAX = res;
EDX = res >> 32;
CC_DST = res;
CC_SRC = (res != (int32_t)res);
}
@@ -254,6 +236,7 @@ void OPPROTO op_imulw_T0_T1(void)
int res;
res = (int16_t)T0 * (int16_t)T1;
T0 = res;
CC_DST = res;
CC_SRC = (res != (int16_t)res);
}
@@ -262,6 +245,7 @@ void OPPROTO op_imull_T0_T1(void)
int64_t res;
res = (int64_t)((int32_t)T0) * (int64_t)((int32_t)T1);
T0 = res;
CC_DST = res;
CC_SRC = (res != (int32_t)res);
}
@@ -404,70 +388,16 @@ void OPPROTO op_andl_A0_ffff(void)
/* memory access */
void OPPROTO op_ldub_T0_A0(void)
{
T0 = ldub((uint8_t *)A0);
}
#define MEMSUFFIX _raw
#include "ops_mem.h"
void OPPROTO op_ldsb_T0_A0(void)
{
T0 = ldsb((int8_t *)A0);
}
#if !defined(CONFIG_USER_ONLY)
#define MEMSUFFIX _user
#include "ops_mem.h"
void OPPROTO op_lduw_T0_A0(void)
{
T0 = lduw((uint8_t *)A0);
}
void OPPROTO op_ldsw_T0_A0(void)
{
T0 = ldsw((int8_t *)A0);
}
void OPPROTO op_ldl_T0_A0(void)
{
T0 = ldl((uint8_t *)A0);
}
void OPPROTO op_ldub_T1_A0(void)
{
T1 = ldub((uint8_t *)A0);
}
void OPPROTO op_ldsb_T1_A0(void)
{
T1 = ldsb((int8_t *)A0);
}
void OPPROTO op_lduw_T1_A0(void)
{
T1 = lduw((uint8_t *)A0);
}
void OPPROTO op_ldsw_T1_A0(void)
{
T1 = ldsw((int8_t *)A0);
}
void OPPROTO op_ldl_T1_A0(void)
{
T1 = ldl((uint8_t *)A0);
}
void OPPROTO op_stb_T0_A0(void)
{
stb((uint8_t *)A0, T0);
}
void OPPROTO op_stw_T0_A0(void)
{
stw((uint8_t *)A0, T0);
}
void OPPROTO op_stl_T0_A0(void)
{
stl((uint8_t *)A0, T0);
}
#define MEMSUFFIX _kernel
#include "ops_mem.h"
#endif
/* used for bit operations */
@@ -499,6 +429,12 @@ void OPPROTO op_hlt(void)
cpu_loop_exit();
}
void OPPROTO op_debug(void)
{
env->exception_index = EXCP_DEBUG;
cpu_loop_exit();
}
void OPPROTO op_raise_interrupt(void)
{
int intno;
@@ -535,6 +471,16 @@ void OPPROTO op_sti(void)
env->eflags |= IF_MASK;
}
void OPPROTO op_set_inhibit_irq(void)
{
env->hflags |= HF_INHIBIT_IRQ_MASK;
}
void OPPROTO op_reset_inhibit_irq(void)
{
env->hflags &= ~HF_INHIBIT_IRQ_MASK;
}
#if 0
/* vm86plus instructions */
void OPPROTO op_cli_vm(void)
@@ -584,9 +530,9 @@ void OPPROTO op_cmpxchg8b(void)
helper_cmpxchg8b();
}
void OPPROTO op_jmp_tb_next(void)
void OPPROTO op_jmp(void)
{
JUMP_TB(PARAM1, 0, PARAM2);
JUMP_TB(op_jmp, PARAM1, 0, PARAM2);
}
void OPPROTO op_movl_T0_0(void)
@@ -594,6 +540,11 @@ void OPPROTO op_movl_T0_0(void)
T0 = 0;
}
void OPPROTO op_exit_tb(void)
{
EXIT_TB();
}
/* multiple size ops */
#define ldul ldl
@@ -652,6 +603,38 @@ void OPPROTO op_movswl_DX_AX(void)
EDX = (EDX & 0xffff0000) | (((int16_t)EAX >> 15) & 0xffff);
}
/* string ops helpers */
void OPPROTO op_addl_ESI_T0(void)
{
ESI += T0;
}
void OPPROTO op_addw_ESI_T0(void)
{
ESI = (ESI & ~0xffff) | ((ESI + T0) & 0xffff);
}
void OPPROTO op_addl_EDI_T0(void)
{
EDI += T0;
}
void OPPROTO op_addw_EDI_T0(void)
{
EDI = (EDI & ~0xffff) | ((EDI + T0) & 0xffff);
}
void OPPROTO op_decl_ECX(void)
{
ECX--;
}
void OPPROTO op_decw_ECX(void)
{
ECX = (ECX & ~0xffff) | ((ECX - 1) & 0xffff);
}
/* push/pop */
void op_pushl_T0(void)
@@ -779,6 +762,16 @@ void OPPROTO op_cpuid(void)
helper_cpuid();
}
void OPPROTO op_rdmsr(void)
{
helper_rdmsr();
}
void OPPROTO op_wrmsr(void)
{
helper_wrmsr();
}
/* bcd */
/* XXX: exception */
@@ -911,9 +904,10 @@ void OPPROTO op_das(void)
/* segment handling */
/* never use it with R_CS */
void OPPROTO op_movl_seg_T0(void)
{
load_seg(PARAM1, T0 & 0xffff, PARAM2);
load_seg(PARAM1, T0);
}
/* faster VM86 version */
@@ -954,10 +948,54 @@ void OPPROTO op_lar(void)
helper_lar();
}
/* T0: segment, T1:eip */
void OPPROTO op_ljmp_T0_T1(void)
void OPPROTO op_verr(void)
{
jmp_seg(T0 & 0xffff, T1);
helper_verr();
}
void OPPROTO op_verw(void)
{
helper_verw();
}
void OPPROTO op_arpl(void)
{
if ((T0 & 3) < (T1 & 3)) {
/* XXX: emulate bug or 0xff3f0000 oring as in bochs ? */
T0 = (T0 & ~3) | (T1 & 3);
T1 = CC_Z;
} else {
T1 = 0;
}
FORCE_RET();
}
void OPPROTO op_arpl_update(void)
{
int eflags;
eflags = cc_table[CC_OP].compute_all();
CC_SRC = (eflags & ~CC_Z) | T1;
}
/* T0: segment, T1:eip */
void OPPROTO op_ljmp_protected_T0_T1(void)
{
helper_ljmp_protected_T0_T1();
}
void OPPROTO op_lcall_real_T0_T1(void)
{
helper_lcall_real_T0_T1(PARAM1, PARAM2);
}
void OPPROTO op_lcall_protected_T0_T1(void)
{
helper_lcall_protected_T0_T1(PARAM1, PARAM2);
}
void OPPROTO op_iret_real(void)
{
helper_iret_real(PARAM1);
}
void OPPROTO op_iret_protected(void)
@@ -965,6 +1003,11 @@ void OPPROTO op_iret_protected(void)
helper_iret_protected(PARAM1);
}
void OPPROTO op_lret_protected(void)
{
helper_lret_protected(PARAM1, PARAM2);
}
void OPPROTO op_lldt_T0(void)
{
helper_lldt_T0();
@@ -1027,9 +1070,18 @@ void OPPROTO op_clts(void)
void OPPROTO op_jcc(void)
{
if (T0)
JUMP_TB(PARAM1, 0, PARAM2);
JUMP_TB(op_jcc, PARAM1, 0, PARAM2);
else
JUMP_TB(PARAM1, 1, PARAM3);
JUMP_TB(op_jcc, PARAM1, 1, PARAM3);
FORCE_RET();
}
void OPPROTO op_jcc_im(void)
{
if (T0)
EIP = PARAM1;
else
EIP = PARAM2;
FORCE_RET();
}
@@ -1098,38 +1150,36 @@ void OPPROTO op_set_cc_op(void)
CC_OP = PARAM1;
}
#define FL_UPDATE_MASK16 (FL_UPDATE_MASK32 & 0xffff)
/* XXX: clear VIF/VIP in all ops ? */
void OPPROTO op_movl_eflags_T0(void)
{
int eflags;
eflags = T0;
CC_SRC = eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
DF = 1 - (2 * ((eflags >> 10) & 1));
/* we also update some system flags as in user mode */
env->eflags = (env->eflags & ~FL_UPDATE_MASK32) |
(eflags & FL_UPDATE_MASK32);
load_eflags(T0, (TF_MASK | AC_MASK | ID_MASK));
}
void OPPROTO op_movw_eflags_T0(void)
{
int eflags;
eflags = T0;
CC_SRC = eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
DF = 1 - (2 * ((eflags >> 10) & 1));
/* we also update some system flags as in user mode */
env->eflags = (env->eflags & ~FL_UPDATE_MASK16) |
(eflags & FL_UPDATE_MASK16);
load_eflags(T0, (TF_MASK | AC_MASK | ID_MASK) & 0xffff);
}
void OPPROTO op_movl_eflags_T0_io(void)
{
load_eflags(T0, (TF_MASK | AC_MASK | ID_MASK | IF_MASK));
}
void OPPROTO op_movw_eflags_T0_io(void)
{
load_eflags(T0, (TF_MASK | AC_MASK | ID_MASK | IF_MASK) & 0xffff);
}
void OPPROTO op_movl_eflags_T0_cpl0(void)
{
load_eflags(T0, FL_UPDATE_CPL0_MASK);
load_eflags(T0, (TF_MASK | AC_MASK | ID_MASK | IF_MASK | IOPL_MASK));
}
void OPPROTO op_movw_eflags_T0_cpl0(void)
{
load_eflags(T0, FL_UPDATE_CPL0_MASK & 0xffff);
load_eflags(T0, (TF_MASK | AC_MASK | ID_MASK | IF_MASK | IOPL_MASK) & 0xffff);
}
#if 0
@@ -1255,31 +1305,14 @@ static int compute_c_eflags(void)
return CC_SRC & CC_C;
}
static int compute_c_mul(void)
{
int cf;
cf = (CC_SRC != 0);
return cf;
}
static int compute_all_mul(void)
{
int cf, pf, af, zf, sf, of;
cf = (CC_SRC != 0);
pf = 0; /* undefined */
af = 0; /* undefined */
zf = 0; /* undefined */
sf = 0; /* undefined */
of = cf << 11;
return cf | pf | af | zf | sf | of;
}
CCTable cc_table[CC_OP_NB] = {
[CC_OP_DYNAMIC] = { /* should never happen */ },
[CC_OP_EFLAGS] = { compute_all_eflags, compute_c_eflags },
[CC_OP_MUL] = { compute_all_mul, compute_c_mul },
[CC_OP_MULB] = { compute_all_mulb, compute_c_mull },
[CC_OP_MULW] = { compute_all_mulw, compute_c_mull },
[CC_OP_MULL] = { compute_all_mull, compute_c_mull },
[CC_OP_ADDB] = { compute_all_addb, compute_c_addb },
[CC_OP_ADDW] = { compute_all_addw, compute_c_addw },
@@ -1434,52 +1467,65 @@ void OPPROTO op_fildll_FT0_A0(void)
void OPPROTO op_flds_ST0_A0(void)
{
int new_fpstt;
new_fpstt = (env->fpstt - 1) & 7;
#ifdef USE_FP_CONVERT
FP_CONVERT.i32 = ldl((void *)A0);
ST0 = FP_CONVERT.f;
env->fpregs[new_fpstt] = FP_CONVERT.f;
#else
ST0 = ldfl((void *)A0);
env->fpregs[new_fpstt] = ldfl((void *)A0);
#endif
env->fpstt = new_fpstt;
env->fptags[new_fpstt] = 0; /* validate stack entry */
}
void OPPROTO op_fldl_ST0_A0(void)
{
int new_fpstt;
new_fpstt = (env->fpstt - 1) & 7;
#ifdef USE_FP_CONVERT
FP_CONVERT.i64 = ldq((void *)A0);
ST0 = FP_CONVERT.d;
env->fpregs[new_fpstt] = FP_CONVERT.d;
#else
ST0 = ldfq((void *)A0);
env->fpregs[new_fpstt] = ldfq((void *)A0);
#endif
env->fpstt = new_fpstt;
env->fptags[new_fpstt] = 0; /* validate stack entry */
}
#ifdef USE_X86LDOUBLE
void OPPROTO op_fldt_ST0_A0(void)
{
ST0 = *(long double *)A0;
}
#else
void OPPROTO op_fldt_ST0_A0(void)
{
helper_fldt_ST0_A0();
}
#endif
/* helpers are needed to avoid static constant reference. XXX: find a better way */
#ifdef USE_INT_TO_FLOAT_HELPERS
void helper_fild_ST0_A0(void)
{
ST0 = (CPU86_LDouble)ldsw((void *)A0);
int new_fpstt;
new_fpstt = (env->fpstt - 1) & 7;
env->fpregs[new_fpstt] = (CPU86_LDouble)ldsw((void *)A0);
env->fpstt = new_fpstt;
env->fptags[new_fpstt] = 0; /* validate stack entry */
}
void helper_fildl_ST0_A0(void)
{
ST0 = (CPU86_LDouble)((int32_t)ldl((void *)A0));
int new_fpstt;
new_fpstt = (env->fpstt - 1) & 7;
env->fpregs[new_fpstt] = (CPU86_LDouble)((int32_t)ldl((void *)A0));
env->fpstt = new_fpstt;
env->fptags[new_fpstt] = 0; /* validate stack entry */
}
void helper_fildll_ST0_A0(void)
{
ST0 = (CPU86_LDouble)((int64_t)ldq((void *)A0));
int new_fpstt;
new_fpstt = (env->fpstt - 1) & 7;
env->fpregs[new_fpstt] = (CPU86_LDouble)((int64_t)ldq((void *)A0));
env->fpstt = new_fpstt;
env->fptags[new_fpstt] = 0; /* validate stack entry */
}
void OPPROTO op_fild_ST0_A0(void)
@@ -1501,32 +1547,44 @@ void OPPROTO op_fildll_ST0_A0(void)
void OPPROTO op_fild_ST0_A0(void)
{
int new_fpstt;
new_fpstt = (env->fpstt - 1) & 7;
#ifdef USE_FP_CONVERT
FP_CONVERT.i32 = ldsw((void *)A0);
ST0 = (CPU86_LDouble)FP_CONVERT.i32;
env->fpregs[new_fpstt] = (CPU86_LDouble)FP_CONVERT.i32;
#else
ST0 = (CPU86_LDouble)ldsw((void *)A0);
env->fpregs[new_fpstt] = (CPU86_LDouble)ldsw((void *)A0);
#endif
env->fpstt = new_fpstt;
env->fptags[new_fpstt] = 0; /* validate stack entry */
}
void OPPROTO op_fildl_ST0_A0(void)
{
int new_fpstt;
new_fpstt = (env->fpstt - 1) & 7;
#ifdef USE_FP_CONVERT
FP_CONVERT.i32 = (int32_t) ldl((void *)A0);
ST0 = (CPU86_LDouble)FP_CONVERT.i32;
env->fpregs[new_fpstt] = (CPU86_LDouble)FP_CONVERT.i32;
#else
ST0 = (CPU86_LDouble)((int32_t)ldl((void *)A0));
env->fpregs[new_fpstt] = (CPU86_LDouble)((int32_t)ldl((void *)A0));
#endif
env->fpstt = new_fpstt;
env->fptags[new_fpstt] = 0; /* validate stack entry */
}
void OPPROTO op_fildll_ST0_A0(void)
{
int new_fpstt;
new_fpstt = (env->fpstt - 1) & 7;
#ifdef USE_FP_CONVERT
FP_CONVERT.i64 = (int64_t) ldq((void *)A0);
ST0 = (CPU86_LDouble)FP_CONVERT.i64;
env->fpregs[new_fpstt] = (CPU86_LDouble)FP_CONVERT.i64;
#else
ST0 = (CPU86_LDouble)((int64_t)ldq((void *)A0));
env->fpregs[new_fpstt] = (CPU86_LDouble)((int64_t)ldq((void *)A0));
#endif
env->fpstt = new_fpstt;
env->fptags[new_fpstt] = 0; /* validate stack entry */
}
#endif
@@ -1548,17 +1606,10 @@ void OPPROTO op_fstl_ST0_A0(void)
stfq((void *)A0, (double)ST0);
}
#ifdef USE_X86LDOUBLE
void OPPROTO op_fstt_ST0_A0(void)
{
*(long double *)A0 = ST0;
}
#else
void OPPROTO op_fstt_ST0_A0(void)
{
helper_fstt_ST0_A0();
}
#endif
void OPPROTO op_fist_ST0_A0(void)
{
@@ -1718,6 +1769,14 @@ void OPPROTO op_fucomi_ST0_FT0(void)
FORCE_RET();
}
void OPPROTO op_fcmov_ST0_STN_T0(void)
{
if (T0) {
ST0 = ST(PARAM1);
}
FORCE_RET();
}
void OPPROTO op_fadd_ST0_FT0(void)
{
ST0 += FT0;
@@ -1837,7 +1896,7 @@ void OPPROTO op_fldz_ST0(void)
void OPPROTO op_fldz_FT0(void)
{
ST0 = f15rk[0];
FT0 = f15rk[0];
}
/* associated heplers to reduce generated code length and to simplify

View File

@@ -83,12 +83,14 @@ void OPPROTO glue(glue(op_cmovw,REGNAME),_T1_T0)(void)
{
if (T0)
REG = (REG & 0xffff0000) | (T1 & 0xffff);
FORCE_RET();
}
void OPPROTO glue(glue(op_cmovl,REGNAME),_T1_T0)(void)
{
if (T0)
REG = T1;
FORCE_RET();
}
/* NOTE: T0 high order bits are ignored */

66
target-i386/ops_mem.h Normal file
View File

@@ -0,0 +1,66 @@
void OPPROTO glue(glue(op_ldub, MEMSUFFIX), _T0_A0)(void)
{
T0 = glue(ldub, MEMSUFFIX)((uint8_t *)A0);
}
void OPPROTO glue(glue(op_ldsb, MEMSUFFIX), _T0_A0)(void)
{
T0 = glue(ldsb, MEMSUFFIX)((int8_t *)A0);
}
void OPPROTO glue(glue(op_lduw, MEMSUFFIX), _T0_A0)(void)
{
T0 = glue(lduw, MEMSUFFIX)((uint8_t *)A0);
}
void OPPROTO glue(glue(op_ldsw, MEMSUFFIX), _T0_A0)(void)
{
T0 = glue(ldsw, MEMSUFFIX)((int8_t *)A0);
}
void OPPROTO glue(glue(op_ldl, MEMSUFFIX), _T0_A0)(void)
{
T0 = glue(ldl, MEMSUFFIX)((uint8_t *)A0);
}
void OPPROTO glue(glue(op_ldub, MEMSUFFIX), _T1_A0)(void)
{
T1 = glue(ldub, MEMSUFFIX)((uint8_t *)A0);
}
void OPPROTO glue(glue(op_ldsb, MEMSUFFIX), _T1_A0)(void)
{
T1 = glue(ldsb, MEMSUFFIX)((int8_t *)A0);
}
void OPPROTO glue(glue(op_lduw, MEMSUFFIX), _T1_A0)(void)
{
T1 = glue(lduw, MEMSUFFIX)((uint8_t *)A0);
}
void OPPROTO glue(glue(op_ldsw, MEMSUFFIX), _T1_A0)(void)
{
T1 = glue(ldsw, MEMSUFFIX)((int8_t *)A0);
}
void OPPROTO glue(glue(op_ldl, MEMSUFFIX), _T1_A0)(void)
{
T1 = glue(ldl, MEMSUFFIX)((uint8_t *)A0);
}
void OPPROTO glue(glue(op_stb, MEMSUFFIX), _T0_A0)(void)
{
glue(stb, MEMSUFFIX)((uint8_t *)A0, T0);
}
void OPPROTO glue(glue(op_stw, MEMSUFFIX), _T0_A0)(void)
{
glue(stw, MEMSUFFIX)((uint8_t *)A0, T0);
}
void OPPROTO glue(glue(op_stl, MEMSUFFIX), _T0_A0)(void)
{
glue(stl, MEMSUFFIX)((uint8_t *)A0, T0);
}
#undef MEMSUFFIX

View File

@@ -93,8 +93,8 @@ static int glue(compute_all_sub, SUFFIX)(void)
{
int cf, pf, af, zf, sf, of;
int src1, src2;
src1 = CC_SRC;
src2 = CC_SRC - CC_DST;
src1 = CC_DST + CC_SRC;
src2 = CC_SRC;
cf = (DATA_TYPE)src1 < (DATA_TYPE)src2;
pf = parity_table[(uint8_t)CC_DST];
af = (CC_DST ^ src1 ^ src2) & 0x10;
@@ -107,8 +107,8 @@ static int glue(compute_all_sub, SUFFIX)(void)
static int glue(compute_c_sub, SUFFIX)(void)
{
int src1, src2, cf;
src1 = CC_SRC;
src2 = CC_SRC - CC_DST;
src1 = CC_DST + CC_SRC;
src2 = CC_SRC;
cf = (DATA_TYPE)src1 < (DATA_TYPE)src2;
return cf;
}
@@ -117,8 +117,8 @@ static int glue(compute_all_sbb, SUFFIX)(void)
{
int cf, pf, af, zf, sf, of;
int src1, src2;
src1 = CC_SRC;
src2 = CC_SRC - CC_DST - 1;
src1 = CC_DST + CC_SRC + 1;
src2 = CC_SRC;
cf = (DATA_TYPE)src1 <= (DATA_TYPE)src2;
pf = parity_table[(uint8_t)CC_DST];
af = (CC_DST ^ src1 ^ src2) & 0x10;
@@ -131,8 +131,8 @@ static int glue(compute_all_sbb, SUFFIX)(void)
static int glue(compute_c_sbb, SUFFIX)(void)
{
int src1, src2, cf;
src1 = CC_SRC;
src2 = CC_SRC - CC_DST - 1;
src1 = CC_DST + CC_SRC + 1;
src2 = CC_SRC;
cf = (DATA_TYPE)src1 <= (DATA_TYPE)src2;
return cf;
}
@@ -229,75 +229,98 @@ static int glue(compute_all_sar, SUFFIX)(void)
return cf | pf | af | zf | sf | of;
}
#if DATA_BITS == 32
static int glue(compute_c_mul, SUFFIX)(void)
{
int cf;
cf = (CC_SRC != 0);
return cf;
}
#endif
/* NOTE: we compute the flags like the P4. On olders CPUs, only OF and
CF are modified and it is slower to do that. */
static int glue(compute_all_mul, SUFFIX)(void)
{
int cf, pf, af, zf, sf, of;
cf = (CC_SRC != 0);
pf = parity_table[(uint8_t)CC_DST];
af = 0; /* undefined */
zf = ((DATA_TYPE)CC_DST == 0) << 6;
sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80;
of = cf << 11;
return cf | pf | af | zf | sf | of;
}
/* various optimized jumps cases */
void OPPROTO glue(op_jb_sub, SUFFIX)(void)
{
int src1, src2;
src1 = CC_SRC;
src2 = CC_SRC - CC_DST;
src1 = CC_DST + CC_SRC;
src2 = CC_SRC;
if ((DATA_TYPE)src1 < (DATA_TYPE)src2)
JUMP_TB(PARAM1, 0, PARAM2);
JUMP_TB(glue(op_jb_sub, SUFFIX), PARAM1, 0, PARAM2);
else
JUMP_TB(PARAM1, 1, PARAM3);
JUMP_TB(glue(op_jb_sub, SUFFIX), PARAM1, 1, PARAM3);
FORCE_RET();
}
void OPPROTO glue(op_jz_sub, SUFFIX)(void)
{
if ((DATA_TYPE)CC_DST == 0)
JUMP_TB(PARAM1, 0, PARAM2);
JUMP_TB(glue(op_jz_sub, SUFFIX), PARAM1, 0, PARAM2);
else
JUMP_TB(PARAM1, 1, PARAM3);
JUMP_TB(glue(op_jz_sub, SUFFIX), PARAM1, 1, PARAM3);
FORCE_RET();
}
void OPPROTO glue(op_jbe_sub, SUFFIX)(void)
{
int src1, src2;
src1 = CC_SRC;
src2 = CC_SRC - CC_DST;
src1 = CC_DST + CC_SRC;
src2 = CC_SRC;
if ((DATA_TYPE)src1 <= (DATA_TYPE)src2)
JUMP_TB(PARAM1, 0, PARAM2);
JUMP_TB(glue(op_jbe_sub, SUFFIX), PARAM1, 0, PARAM2);
else
JUMP_TB(PARAM1, 1, PARAM3);
JUMP_TB(glue(op_jbe_sub, SUFFIX), PARAM1, 1, PARAM3);
FORCE_RET();
}
void OPPROTO glue(op_js_sub, SUFFIX)(void)
{
if (CC_DST & SIGN_MASK)
JUMP_TB(PARAM1, 0, PARAM2);
JUMP_TB(glue(op_js_sub, SUFFIX), PARAM1, 0, PARAM2);
else
JUMP_TB(PARAM1, 1, PARAM3);
JUMP_TB(glue(op_js_sub, SUFFIX), PARAM1, 1, PARAM3);
FORCE_RET();
}
void OPPROTO glue(op_jl_sub, SUFFIX)(void)
{
int src1, src2;
src1 = CC_SRC;
src2 = CC_SRC - CC_DST;
src1 = CC_DST + CC_SRC;
src2 = CC_SRC;
if ((DATA_STYPE)src1 < (DATA_STYPE)src2)
JUMP_TB(PARAM1, 0, PARAM2);
JUMP_TB(glue(op_jl_sub, SUFFIX), PARAM1, 0, PARAM2);
else
JUMP_TB(PARAM1, 1, PARAM3);
JUMP_TB(glue(op_jl_sub, SUFFIX), PARAM1, 1, PARAM3);
FORCE_RET();
}
void OPPROTO glue(op_jle_sub, SUFFIX)(void)
{
int src1, src2;
src1 = CC_SRC;
src2 = CC_SRC - CC_DST;
src1 = CC_DST + CC_SRC;
src2 = CC_SRC;
if ((DATA_STYPE)src1 <= (DATA_STYPE)src2)
JUMP_TB(PARAM1, 0, PARAM2);
JUMP_TB(glue(op_jle_sub, SUFFIX), PARAM1, 0, PARAM2);
else
JUMP_TB(PARAM1, 1, PARAM3);
JUMP_TB(glue(op_jle_sub, SUFFIX), PARAM1, 1, PARAM3);
FORCE_RET();
}
@@ -361,8 +384,8 @@ void OPPROTO glue(op_jecxz, SUFFIX)(void)
void OPPROTO glue(op_setb_T0_sub, SUFFIX)(void)
{
int src1, src2;
src1 = CC_SRC;
src2 = CC_SRC - CC_DST;
src1 = CC_DST + CC_SRC;
src2 = CC_SRC;
T0 = ((DATA_TYPE)src1 < (DATA_TYPE)src2);
}
@@ -375,8 +398,8 @@ void OPPROTO glue(op_setz_T0_sub, SUFFIX)(void)
void OPPROTO glue(op_setbe_T0_sub, SUFFIX)(void)
{
int src1, src2;
src1 = CC_SRC;
src2 = CC_SRC - CC_DST;
src1 = CC_DST + CC_SRC;
src2 = CC_SRC;
T0 = ((DATA_TYPE)src1 <= (DATA_TYPE)src2);
}
@@ -389,8 +412,8 @@ void OPPROTO glue(op_sets_T0_sub, SUFFIX)(void)
void OPPROTO glue(op_setl_T0_sub, SUFFIX)(void)
{
int src1, src2;
src1 = CC_SRC;
src2 = CC_SRC - CC_DST;
src1 = CC_DST + CC_SRC;
src2 = CC_SRC;
T0 = ((DATA_STYPE)src1 < (DATA_STYPE)src2);
}
@@ -398,135 +421,14 @@ void OPPROTO glue(op_setl_T0_sub, SUFFIX)(void)
void OPPROTO glue(op_setle_T0_sub, SUFFIX)(void)
{
int src1, src2;
src1 = CC_SRC;
src2 = CC_SRC - CC_DST;
src1 = CC_DST + CC_SRC;
src2 = CC_SRC;
T0 = ((DATA_STYPE)src1 <= (DATA_STYPE)src2);
}
/* shifts */
void OPPROTO glue(glue(op_rol, SUFFIX), _T0_T1_cc)(void)
{
int count, src;
count = T1 & SHIFT_MASK;
if (count) {
CC_SRC = cc_table[CC_OP].compute_all() & ~(CC_O | CC_C);
src = T0;
T0 &= DATA_MASK;
T0 = (T0 << count) | (T0 >> (DATA_BITS - count));
CC_SRC |= (lshift(src ^ T0, 11 - (DATA_BITS - 1)) & CC_O) |
(T0 & CC_C);
CC_OP = CC_OP_EFLAGS;
}
FORCE_RET();
}
void OPPROTO glue(glue(op_rol, SUFFIX), _T0_T1)(void)
{
int count;
count = T1 & SHIFT_MASK;
if (count) {
T0 &= DATA_MASK;
T0 = (T0 << count) | (T0 >> (DATA_BITS - count));
}
FORCE_RET();
}
void OPPROTO glue(glue(op_ror, SUFFIX), _T0_T1_cc)(void)
{
int count, src;
count = T1 & SHIFT_MASK;
if (count) {
CC_SRC = cc_table[CC_OP].compute_all() & ~(CC_O | CC_C);
src = T0;
T0 &= DATA_MASK;
T0 = (T0 >> count) | (T0 << (DATA_BITS - count));
CC_SRC |= (lshift(src ^ T0, 11 - (DATA_BITS - 1)) & CC_O) |
((T0 >> (DATA_BITS - 1)) & CC_C);
CC_OP = CC_OP_EFLAGS;
}
FORCE_RET();
}
void OPPROTO glue(glue(op_ror, SUFFIX), _T0_T1)(void)
{
int count;
count = T1 & SHIFT_MASK;
if (count) {
T0 &= DATA_MASK;
T0 = (T0 >> count) | (T0 << (DATA_BITS - count));
}
FORCE_RET();
}
void OPPROTO glue(glue(op_rcl, SUFFIX), _T0_T1_cc)(void)
{
int count, res, eflags;
unsigned int src;
count = T1 & 0x1f;
#if DATA_BITS == 16
count = rclw_table[count];
#elif DATA_BITS == 8
count = rclb_table[count];
#endif
if (count) {
eflags = cc_table[CC_OP].compute_all();
T0 &= DATA_MASK;
src = T0;
res = (T0 << count) | ((eflags & CC_C) << (count - 1));
if (count > 1)
res |= T0 >> (DATA_BITS + 1 - count);
T0 = res;
CC_SRC = (eflags & ~(CC_C | CC_O)) |
(lshift(src ^ T0, 11 - (DATA_BITS - 1)) & CC_O) |
((src >> (DATA_BITS - count)) & CC_C);
CC_OP = CC_OP_EFLAGS;
}
FORCE_RET();
}
void OPPROTO glue(glue(op_rcr, SUFFIX), _T0_T1_cc)(void)
{
int count, res, eflags;
unsigned int src;
count = T1 & 0x1f;
#if DATA_BITS == 16
count = rclw_table[count];
#elif DATA_BITS == 8
count = rclb_table[count];
#endif
if (count) {
eflags = cc_table[CC_OP].compute_all();
T0 &= DATA_MASK;
src = T0;
res = (T0 >> count) | ((eflags & CC_C) << (DATA_BITS - count));
if (count > 1)
res |= T0 << (DATA_BITS + 1 - count);
T0 = res;
CC_SRC = (eflags & ~(CC_C | CC_O)) |
(lshift(src ^ T0, 11 - (DATA_BITS - 1)) & CC_O) |
((src >> (count - 1)) & CC_C);
CC_OP = CC_OP_EFLAGS;
}
FORCE_RET();
}
void OPPROTO glue(glue(op_shl, SUFFIX), _T0_T1_cc)(void)
{
int count;
count = T1 & 0x1f;
if (count) {
CC_SRC = (DATA_TYPE)T0 << (count - 1);
T0 = T0 << count;
CC_DST = T0;
CC_OP = CC_OP_SHLB + SHIFT;
}
FORCE_RET();
}
void OPPROTO glue(glue(op_shl, SUFFIX), _T0_T1)(void)
{
int count;
@@ -535,20 +437,6 @@ void OPPROTO glue(glue(op_shl, SUFFIX), _T0_T1)(void)
FORCE_RET();
}
void OPPROTO glue(glue(op_shr, SUFFIX), _T0_T1_cc)(void)
{
int count;
count = T1 & 0x1f;
if (count) {
T0 &= DATA_MASK;
CC_SRC = T0 >> (count - 1);
T0 = T0 >> count;
CC_DST = T0;
CC_OP = CC_OP_SARB + SHIFT;
}
FORCE_RET();
}
void OPPROTO glue(glue(op_shr, SUFFIX), _T0_T1)(void)
{
int count;
@@ -558,20 +446,6 @@ void OPPROTO glue(glue(op_shr, SUFFIX), _T0_T1)(void)
FORCE_RET();
}
void OPPROTO glue(glue(op_sar, SUFFIX), _T0_T1_cc)(void)
{
int count, src;
count = T1 & 0x1f;
if (count) {
src = (DATA_STYPE)T0;
CC_SRC = src >> (count - 1);
T0 = src >> count;
CC_DST = T0;
CC_OP = CC_OP_SARB + SHIFT;
}
FORCE_RET();
}
void OPPROTO glue(glue(op_sar, SUFFIX), _T0_T1)(void)
{
int count, src;
@@ -581,166 +455,11 @@ void OPPROTO glue(glue(op_sar, SUFFIX), _T0_T1)(void)
FORCE_RET();
}
#if DATA_BITS == 16
/* XXX: overflow flag might be incorrect in some cases in shldw */
void OPPROTO glue(glue(op_shld, SUFFIX), _T0_T1_im_cc)(void)
{
int count;
unsigned int res;
count = PARAM1;
T1 &= 0xffff;
res = T1 | (T0 << 16);
CC_SRC = res >> (32 - count);
res <<= count;
if (count > 16)
res |= T1 << (count - 16);
T0 = res >> 16;
CC_DST = T0;
}
#undef MEM_WRITE
#include "ops_template_mem.h"
void OPPROTO glue(glue(op_shld, SUFFIX), _T0_T1_ECX_cc)(void)
{
int count;
unsigned int res;
count = ECX & 0x1f;
if (count) {
T1 &= 0xffff;
res = T1 | (T0 << 16);
CC_SRC = res >> (32 - count);
res <<= count;
if (count > 16)
res |= T1 << (count - 16);
T0 = res >> 16;
CC_DST = T0;
CC_OP = CC_OP_SARB + SHIFT;
}
FORCE_RET();
}
void OPPROTO glue(glue(op_shrd, SUFFIX), _T0_T1_im_cc)(void)
{
int count;
unsigned int res;
count = PARAM1;
res = (T0 & 0xffff) | (T1 << 16);
CC_SRC = res >> (count - 1);
res >>= count;
if (count > 16)
res |= T1 << (32 - count);
T0 = res;
CC_DST = T0;
}
void OPPROTO glue(glue(op_shrd, SUFFIX), _T0_T1_ECX_cc)(void)
{
int count;
unsigned int res;
count = ECX & 0x1f;
if (count) {
res = (T0 & 0xffff) | (T1 << 16);
CC_SRC = res >> (count - 1);
res >>= count;
if (count > 16)
res |= T1 << (32 - count);
T0 = res;
CC_DST = T0;
CC_OP = CC_OP_SARB + SHIFT;
}
FORCE_RET();
}
#endif
#if DATA_BITS == 32
void OPPROTO glue(glue(op_shld, SUFFIX), _T0_T1_im_cc)(void)
{
int count;
count = PARAM1;
T0 &= DATA_MASK;
T1 &= DATA_MASK;
CC_SRC = T0 << (count - 1);
T0 = (T0 << count) | (T1 >> (DATA_BITS - count));
CC_DST = T0;
}
void OPPROTO glue(glue(op_shld, SUFFIX), _T0_T1_ECX_cc)(void)
{
int count;
count = ECX & 0x1f;
if (count) {
T0 &= DATA_MASK;
T1 &= DATA_MASK;
CC_SRC = T0 << (count - 1);
T0 = (T0 << count) | (T1 >> (DATA_BITS - count));
CC_DST = T0;
CC_OP = CC_OP_SHLB + SHIFT;
}
FORCE_RET();
}
void OPPROTO glue(glue(op_shrd, SUFFIX), _T0_T1_im_cc)(void)
{
int count;
count = PARAM1;
T0 &= DATA_MASK;
T1 &= DATA_MASK;
CC_SRC = T0 >> (count - 1);
T0 = (T0 >> count) | (T1 << (DATA_BITS - count));
CC_DST = T0;
}
void OPPROTO glue(glue(op_shrd, SUFFIX), _T0_T1_ECX_cc)(void)
{
int count;
count = ECX & 0x1f;
if (count) {
T0 &= DATA_MASK;
T1 &= DATA_MASK;
CC_SRC = T0 >> (count - 1);
T0 = (T0 >> count) | (T1 << (DATA_BITS - count));
CC_DST = T0;
CC_OP = CC_OP_SARB + SHIFT;
}
FORCE_RET();
}
#endif
/* carry add/sub (we only need to set CC_OP differently) */
void OPPROTO glue(glue(op_adc, SUFFIX), _T0_T1_cc)(void)
{
int cf;
cf = cc_table[CC_OP].compute_c();
CC_SRC = T0;
T0 = T0 + T1 + cf;
CC_DST = T0;
CC_OP = CC_OP_ADDB + SHIFT + cf * 3;
}
void OPPROTO glue(glue(op_sbb, SUFFIX), _T0_T1_cc)(void)
{
int cf;
cf = cc_table[CC_OP].compute_c();
CC_SRC = T0;
T0 = T0 - T1 - cf;
CC_DST = T0;
CC_OP = CC_OP_SUBB + SHIFT + cf * 3;
}
void OPPROTO glue(glue(op_cmpxchg, SUFFIX), _T0_T1_EAX_cc)(void)
{
CC_SRC = EAX;
CC_DST = EAX - T0;
if ((DATA_TYPE)CC_DST == 0) {
T0 = T1;
} else {
EAX = (EAX & ~DATA_MASK) | (T0 & DATA_MASK);
}
FORCE_RET();
}
#define MEM_WRITE
#include "ops_template_mem.h"
/* bit operations */
#if DATA_BITS >= 16
@@ -756,7 +475,7 @@ void OPPROTO glue(glue(op_bts, SUFFIX), _T0_T1_cc)(void)
{
int count;
count = T1 & SHIFT_MASK;
CC_SRC = T0 >> count;
T1 = T0 >> count;
T0 |= (1 << count);
}
@@ -764,7 +483,7 @@ void OPPROTO glue(glue(op_btr, SUFFIX), _T0_T1_cc)(void)
{
int count;
count = T1 & SHIFT_MASK;
CC_SRC = T0 >> count;
T1 = T0 >> count;
T0 &= ~(1 << count);
}
@@ -772,7 +491,7 @@ void OPPROTO glue(glue(op_btc, SUFFIX), _T0_T1_cc)(void)
{
int count;
count = T1 & SHIFT_MASK;
CC_SRC = T0 >> count;
T1 = T0 >> count;
T0 ^= (1 << count);
}
@@ -814,35 +533,81 @@ void OPPROTO glue(glue(op_bsr, SUFFIX), _T0_cc)(void)
#endif
#if DATA_BITS == 32
void OPPROTO op_update_bt_cc(void)
{
CC_SRC = T1;
}
#endif
/* string operations */
/* XXX: maybe use lower level instructions to ease 16 bit / segment handling */
#define STRING_SUFFIX _fast
#define SI_ADDR (void *)ESI
#define DI_ADDR (void *)EDI
#define INC_SI() ESI += inc
#define INC_DI() EDI += inc
#define CX ECX
#define DEC_CX() ECX--
#include "op_string.h"
void OPPROTO glue(op_movl_T0_Dshift, SUFFIX)(void)
{
T0 = DF << SHIFT;
}
#define STRING_SUFFIX _a32
#define SI_ADDR (uint8_t *)A0 + ESI
#define DI_ADDR env->segs[R_ES].base + EDI
#define INC_SI() ESI += inc
#define INC_DI() EDI += inc
#define CX ECX
#define DEC_CX() ECX--
#include "op_string.h"
void OPPROTO glue(op_string_jz_sub, SUFFIX)(void)
{
if ((DATA_TYPE)CC_DST == 0)
JUMP_TB2(glue(op_string_jz_sub, SUFFIX), PARAM1, 1);
FORCE_RET();
}
#define STRING_SUFFIX _a16
#define SI_ADDR (uint8_t *)A0 + (ESI & 0xffff)
#define DI_ADDR env->segs[R_ES].base + (EDI & 0xffff)
#define INC_SI() ESI = (ESI & ~0xffff) | ((ESI + inc) & 0xffff)
#define INC_DI() EDI = (EDI & ~0xffff) | ((EDI + inc) & 0xffff)
#define CX (ECX & 0xffff)
#define DEC_CX() ECX = (ECX & ~0xffff) | ((ECX - 1) & 0xffff)
#include "op_string.h"
void OPPROTO glue(op_string_jnz_sub, SUFFIX)(void)
{
if ((DATA_TYPE)CC_DST != 0)
JUMP_TB2(glue(op_string_jnz_sub, SUFFIX), PARAM1, 1);
FORCE_RET();
}
void OPPROTO glue(glue(op_string_jz_sub, SUFFIX), _im)(void)
{
if ((DATA_TYPE)CC_DST == 0) {
EIP = PARAM1;
if (env->eflags & TF_MASK) {
raise_exception(EXCP01_SSTP);
}
T0 = 0;
EXIT_TB();
}
FORCE_RET();
}
void OPPROTO glue(glue(op_string_jnz_sub, SUFFIX), _im)(void)
{
if ((DATA_TYPE)CC_DST != 0) {
EIP = PARAM1;
if (env->eflags & TF_MASK) {
raise_exception(EXCP01_SSTP);
}
T0 = 0;
EXIT_TB();
}
FORCE_RET();
}
#if DATA_BITS >= 16
void OPPROTO glue(op_jz_ecx, SUFFIX)(void)
{
if ((DATA_TYPE)ECX == 0)
JUMP_TB(glue(op_jz_ecx, SUFFIX), PARAM1, 1, PARAM2);
FORCE_RET();
}
void OPPROTO glue(glue(op_jz_ecx, SUFFIX), _im)(void)
{
if ((DATA_TYPE)ECX == 0) {
EIP = PARAM1;
if (env->eflags & TF_MASK) {
raise_exception(EXCP01_SSTP);
}
T0 = 0;
EXIT_TB();
}
FORCE_RET();
}
#endif
/* port I/O */
@@ -856,6 +621,26 @@ void OPPROTO glue(glue(op_in, SUFFIX), _T0_T1)(void)
T1 = glue(cpu_x86_in, SUFFIX)(env, T0 & 0xffff);
}
void OPPROTO glue(glue(op_in, SUFFIX), _DX_T0)(void)
{
T0 = glue(cpu_x86_in, SUFFIX)(env, EDX & 0xffff);
}
void OPPROTO glue(glue(op_out, SUFFIX), _DX_T0)(void)
{
glue(cpu_x86_out, SUFFIX)(env, EDX & 0xffff, T0);
}
void OPPROTO glue(glue(op_check_io, SUFFIX), _T0)(void)
{
glue(glue(check_io, SUFFIX), _T0)();
}
void OPPROTO glue(glue(op_check_io, SUFFIX), _DX)(void)
{
glue(glue(check_io, SUFFIX), _DX)();
}
#undef DATA_BITS
#undef SHIFT_MASK
#undef SIGN_MASK

View File

@@ -0,0 +1,429 @@
/*
* i386 micro operations (included several times to generate
* different operand sizes)
*
* Copyright (c) 2003 Fabrice Bellard
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifdef MEM_WRITE
#if DATA_BITS == 8
#define MEM_SUFFIX b_mem
#elif DATA_BITS == 16
#define MEM_SUFFIX w_mem
#elif DATA_BITS == 32
#define MEM_SUFFIX l_mem
#endif
#else
#define MEM_SUFFIX SUFFIX
#endif
void OPPROTO glue(glue(op_rol, MEM_SUFFIX), _T0_T1_cc)(void)
{
int count, src;
count = T1 & SHIFT_MASK;
if (count) {
src = T0;
T0 &= DATA_MASK;
T0 = (T0 << count) | (T0 >> (DATA_BITS - count));
#ifdef MEM_WRITE
glue(st, SUFFIX)((uint8_t *)A0, T0);
#else
/* gcc 3.2 workaround. This is really a bug in gcc. */
asm volatile("" : : "r" (T0));
#endif
CC_SRC = (cc_table[CC_OP].compute_all() & ~(CC_O | CC_C)) |
(lshift(src ^ T0, 11 - (DATA_BITS - 1)) & CC_O) |
(T0 & CC_C);
CC_OP = CC_OP_EFLAGS;
}
FORCE_RET();
}
void OPPROTO glue(glue(op_ror, MEM_SUFFIX), _T0_T1_cc)(void)
{
int count, src;
count = T1 & SHIFT_MASK;
if (count) {
src = T0;
T0 &= DATA_MASK;
T0 = (T0 >> count) | (T0 << (DATA_BITS - count));
#ifdef MEM_WRITE
glue(st, SUFFIX)((uint8_t *)A0, T0);
#else
/* gcc 3.2 workaround. This is really a bug in gcc. */
asm volatile("" : : "r" (T0));
#endif
CC_SRC = (cc_table[CC_OP].compute_all() & ~(CC_O | CC_C)) |
(lshift(src ^ T0, 11 - (DATA_BITS - 1)) & CC_O) |
((T0 >> (DATA_BITS - 1)) & CC_C);
CC_OP = CC_OP_EFLAGS;
}
FORCE_RET();
}
void OPPROTO glue(glue(op_rol, MEM_SUFFIX), _T0_T1)(void)
{
int count;
count = T1 & SHIFT_MASK;
if (count) {
T0 &= DATA_MASK;
T0 = (T0 << count) | (T0 >> (DATA_BITS - count));
#ifdef MEM_WRITE
glue(st, SUFFIX)((uint8_t *)A0, T0);
#endif
}
FORCE_RET();
}
void OPPROTO glue(glue(op_ror, MEM_SUFFIX), _T0_T1)(void)
{
int count;
count = T1 & SHIFT_MASK;
if (count) {
T0 &= DATA_MASK;
T0 = (T0 >> count) | (T0 << (DATA_BITS - count));
#ifdef MEM_WRITE
glue(st, SUFFIX)((uint8_t *)A0, T0);
#endif
}
FORCE_RET();
}
void OPPROTO glue(glue(op_rcl, MEM_SUFFIX), _T0_T1_cc)(void)
{
int count, res, eflags;
unsigned int src;
count = T1 & 0x1f;
#if DATA_BITS == 16
count = rclw_table[count];
#elif DATA_BITS == 8
count = rclb_table[count];
#endif
if (count) {
eflags = cc_table[CC_OP].compute_all();
T0 &= DATA_MASK;
src = T0;
res = (T0 << count) | ((eflags & CC_C) << (count - 1));
if (count > 1)
res |= T0 >> (DATA_BITS + 1 - count);
T0 = res;
#ifdef MEM_WRITE
glue(st, SUFFIX)((uint8_t *)A0, T0);
#endif
CC_SRC = (eflags & ~(CC_C | CC_O)) |
(lshift(src ^ T0, 11 - (DATA_BITS - 1)) & CC_O) |
((src >> (DATA_BITS - count)) & CC_C);
CC_OP = CC_OP_EFLAGS;
}
FORCE_RET();
}
void OPPROTO glue(glue(op_rcr, MEM_SUFFIX), _T0_T1_cc)(void)
{
int count, res, eflags;
unsigned int src;
count = T1 & 0x1f;
#if DATA_BITS == 16
count = rclw_table[count];
#elif DATA_BITS == 8
count = rclb_table[count];
#endif
if (count) {
eflags = cc_table[CC_OP].compute_all();
T0 &= DATA_MASK;
src = T0;
res = (T0 >> count) | ((eflags & CC_C) << (DATA_BITS - count));
if (count > 1)
res |= T0 << (DATA_BITS + 1 - count);
T0 = res;
#ifdef MEM_WRITE
glue(st, SUFFIX)((uint8_t *)A0, T0);
#endif
CC_SRC = (eflags & ~(CC_C | CC_O)) |
(lshift(src ^ T0, 11 - (DATA_BITS - 1)) & CC_O) |
((src >> (count - 1)) & CC_C);
CC_OP = CC_OP_EFLAGS;
}
FORCE_RET();
}
void OPPROTO glue(glue(op_shl, MEM_SUFFIX), _T0_T1_cc)(void)
{
int count, src;
count = T1 & 0x1f;
if (count) {
src = (DATA_TYPE)T0 << (count - 1);
T0 = T0 << count;
#ifdef MEM_WRITE
glue(st, SUFFIX)((uint8_t *)A0, T0);
#endif
CC_SRC = src;
CC_DST = T0;
CC_OP = CC_OP_SHLB + SHIFT;
}
FORCE_RET();
}
void OPPROTO glue(glue(op_shr, MEM_SUFFIX), _T0_T1_cc)(void)
{
int count, src;
count = T1 & 0x1f;
if (count) {
T0 &= DATA_MASK;
src = T0 >> (count - 1);
T0 = T0 >> count;
#ifdef MEM_WRITE
glue(st, SUFFIX)((uint8_t *)A0, T0);
#endif
CC_SRC = src;
CC_DST = T0;
CC_OP = CC_OP_SARB + SHIFT;
}
FORCE_RET();
}
void OPPROTO glue(glue(op_sar, MEM_SUFFIX), _T0_T1_cc)(void)
{
int count, src;
count = T1 & 0x1f;
if (count) {
src = (DATA_STYPE)T0;
T0 = src >> count;
src = src >> (count - 1);
#ifdef MEM_WRITE
glue(st, SUFFIX)((uint8_t *)A0, T0);
#endif
CC_SRC = src;
CC_DST = T0;
CC_OP = CC_OP_SARB + SHIFT;
}
FORCE_RET();
}
#if DATA_BITS == 16
/* XXX: overflow flag might be incorrect in some cases in shldw */
void OPPROTO glue(glue(op_shld, MEM_SUFFIX), _T0_T1_im_cc)(void)
{
int count;
unsigned int res, tmp;
count = PARAM1;
T1 &= 0xffff;
res = T1 | (T0 << 16);
tmp = res >> (32 - count);
res <<= count;
if (count > 16)
res |= T1 << (count - 16);
T0 = res >> 16;
#ifdef MEM_WRITE
glue(st, SUFFIX)((uint8_t *)A0, T0);
#endif
CC_SRC = tmp;
CC_DST = T0;
}
void OPPROTO glue(glue(op_shld, MEM_SUFFIX), _T0_T1_ECX_cc)(void)
{
int count;
unsigned int res, tmp;
count = ECX & 0x1f;
if (count) {
T1 &= 0xffff;
res = T1 | (T0 << 16);
tmp = res >> (32 - count);
res <<= count;
if (count > 16)
res |= T1 << (count - 16);
T0 = res >> 16;
#ifdef MEM_WRITE
glue(st, SUFFIX)((uint8_t *)A0, T0);
#endif
CC_SRC = tmp;
CC_DST = T0;
CC_OP = CC_OP_SARB + SHIFT;
}
FORCE_RET();
}
void OPPROTO glue(glue(op_shrd, MEM_SUFFIX), _T0_T1_im_cc)(void)
{
int count;
unsigned int res, tmp;
count = PARAM1;
res = (T0 & 0xffff) | (T1 << 16);
tmp = res >> (count - 1);
res >>= count;
if (count > 16)
res |= T1 << (32 - count);
T0 = res;
#ifdef MEM_WRITE
glue(st, SUFFIX)((uint8_t *)A0, T0);
#endif
CC_SRC = tmp;
CC_DST = T0;
}
void OPPROTO glue(glue(op_shrd, MEM_SUFFIX), _T0_T1_ECX_cc)(void)
{
int count;
unsigned int res, tmp;
count = ECX & 0x1f;
if (count) {
res = (T0 & 0xffff) | (T1 << 16);
tmp = res >> (count - 1);
res >>= count;
if (count > 16)
res |= T1 << (32 - count);
T0 = res;
#ifdef MEM_WRITE
glue(st, SUFFIX)((uint8_t *)A0, T0);
#endif
CC_SRC = tmp;
CC_DST = T0;
CC_OP = CC_OP_SARB + SHIFT;
}
FORCE_RET();
}
#endif
#if DATA_BITS == 32
void OPPROTO glue(glue(op_shld, MEM_SUFFIX), _T0_T1_im_cc)(void)
{
int count, tmp;
count = PARAM1;
T0 &= DATA_MASK;
T1 &= DATA_MASK;
tmp = T0 << (count - 1);
T0 = (T0 << count) | (T1 >> (DATA_BITS - count));
#ifdef MEM_WRITE
glue(st, SUFFIX)((uint8_t *)A0, T0);
#endif
CC_SRC = tmp;
CC_DST = T0;
}
void OPPROTO glue(glue(op_shld, MEM_SUFFIX), _T0_T1_ECX_cc)(void)
{
int count, tmp;
count = ECX & 0x1f;
if (count) {
T0 &= DATA_MASK;
T1 &= DATA_MASK;
tmp = T0 << (count - 1);
T0 = (T0 << count) | (T1 >> (DATA_BITS - count));
#ifdef MEM_WRITE
glue(st, SUFFIX)((uint8_t *)A0, T0);
#endif
CC_SRC = tmp;
CC_DST = T0;
CC_OP = CC_OP_SHLB + SHIFT;
}
FORCE_RET();
}
void OPPROTO glue(glue(op_shrd, MEM_SUFFIX), _T0_T1_im_cc)(void)
{
int count, tmp;
count = PARAM1;
T0 &= DATA_MASK;
T1 &= DATA_MASK;
tmp = T0 >> (count - 1);
T0 = (T0 >> count) | (T1 << (DATA_BITS - count));
#ifdef MEM_WRITE
glue(st, SUFFIX)((uint8_t *)A0, T0);
#endif
CC_SRC = tmp;
CC_DST = T0;
}
void OPPROTO glue(glue(op_shrd, MEM_SUFFIX), _T0_T1_ECX_cc)(void)
{
int count, tmp;
count = ECX & 0x1f;
if (count) {
T0 &= DATA_MASK;
T1 &= DATA_MASK;
tmp = T0 >> (count - 1);
T0 = (T0 >> count) | (T1 << (DATA_BITS - count));
#ifdef MEM_WRITE
glue(st, SUFFIX)((uint8_t *)A0, T0);
#endif
CC_SRC = tmp;
CC_DST = T0;
CC_OP = CC_OP_SARB + SHIFT;
}
FORCE_RET();
}
#endif
/* carry add/sub (we only need to set CC_OP differently) */
void OPPROTO glue(glue(op_adc, MEM_SUFFIX), _T0_T1_cc)(void)
{
int cf;
cf = cc_table[CC_OP].compute_c();
T0 = T0 + T1 + cf;
#ifdef MEM_WRITE
glue(st, SUFFIX)((uint8_t *)A0, T0);
#endif
CC_SRC = T1;
CC_DST = T0;
CC_OP = CC_OP_ADDB + SHIFT + cf * 3;
}
void OPPROTO glue(glue(op_sbb, MEM_SUFFIX), _T0_T1_cc)(void)
{
int cf;
cf = cc_table[CC_OP].compute_c();
T0 = T0 - T1 - cf;
#ifdef MEM_WRITE
glue(st, SUFFIX)((uint8_t *)A0, T0);
#endif
CC_SRC = T1;
CC_DST = T0;
CC_OP = CC_OP_SUBB + SHIFT + cf * 3;
}
void OPPROTO glue(glue(op_cmpxchg, MEM_SUFFIX), _T0_T1_EAX_cc)(void)
{
unsigned int src, dst;
src = T0;
dst = EAX - T0;
if ((DATA_TYPE)dst == 0) {
T0 = T1;
} else {
EAX = (EAX & ~DATA_MASK) | (T0 & DATA_MASK);
}
#ifdef MEM_WRITE
glue(st, SUFFIX)((uint8_t *)A0, T0);
#endif
CC_SRC = src;
CC_DST = dst;
FORCE_RET();
}
#undef MEM_SUFFIX
#undef MEM_WRITE

File diff suppressed because it is too large Load Diff

380
target-ppc/cpu.h Normal file
View File

@@ -0,0 +1,380 @@
/*
* PPC emulation cpu definitions for qemu.
*
* Copyright (c) 2003 Jocelyn Mayer
*
* 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
*/
#if !defined (__CPU_PPC_H__)
#define __CPU_PPC_H__
#include <endian.h>
#include <asm/byteorder.h>
#include "cpu-defs.h"
/*** Sign extend constants ***/
/* 8 to 32 bits */
static inline int32_t s_ext8 (uint8_t value)
{
int8_t *tmp = &value;
return *tmp;
}
/* 16 to 32 bits */
static inline int32_t s_ext16 (uint16_t value)
{
int16_t *tmp = &value;
return *tmp;
}
/* 24 to 32 bits */
static inline int32_t s_ext24 (uint32_t value)
{
uint16_t utmp = (value >> 8) & 0xFFFF;
int16_t *tmp = &utmp;
return (*tmp << 8) | (value & 0xFF);
}
#include "config.h"
#include <setjmp.h>
/* Floting point status and control register */
#define FPSCR_FX 31
#define FPSCR_FEX 30
#define FPSCR_VX 29
#define FPSCR_OX 28
#define FPSCR_UX 27
#define FPSCR_ZX 26
#define FPSCR_XX 25
#define FPSCR_VXSNAN 24
#define FPSCR_VXISI 26
#define FPSCR_VXIDI 25
#define FPSCR_VXZDZ 21
#define FPSCR_VXIMZ 20
#define FPSCR_VXVC 18
#define FPSCR_FR 17
#define FPSCR_FI 16
#define FPSCR_FPRF 11
#define FPSCR_VXSOFT 9
#define FPSCR_VXSQRT 8
#define FPSCR_VXCVI 7
#define FPSCR_OE 6
#define FPSCR_UE 5
#define FPSCR_ZE 4
#define FPSCR_XE 3
#define FPSCR_NI 2
#define FPSCR_RN 0
#define fpscr_fx env->fpscr[FPSCR_FX]
#define fpscr_fex env->fpscr[FPSCR_FEX]
#define fpscr_vx env->fpscr[FPSCR_VX]
#define fpscr_ox env->fpscr[FPSCR_OX]
#define fpscr_ux env->fpscr[FPSCR_UX]
#define fpscr_zx env->fpscr[FPSCR_ZX]
#define fpscr_xx env->fpscr[FPSCR_XX]
#define fpscr_vsxnan env->fpscr[FPSCR_VXSNAN]
#define fpscr_vxisi env->fpscr[FPSCR_VXISI]
#define fpscr_vxidi env->fpscr[FPSCR_VXIDI]
#define fpscr_vxzdz env->fpscr[FPSCR_VXZDZ]
#define fpscr_vximz env->fpscr[FPSCR_VXIMZ]
#define fpscr_fr env->fpscr[FPSCR_FR]
#define fpscr_fi env->fpscr[FPSCR_FI]
#define fpscr_fprf env->fpscr[FPSCR_FPRF]
#define fpscr_vxsoft env->fpscr[FPSCR_VXSOFT]
#define fpscr_vxsqrt env->fpscr[FPSCR_VXSQRT]
#define fpscr_oe env->fpscr[FPSCR_OE]
#define fpscr_ue env->fpscr[FPSCR_UE]
#define fpscr_ze env->fpscr[FPSCR_ZE]
#define fpscr_xe env->fpscr[FPSCR_XE]
#define fpscr_ni env->fpscr[FPSCR_NI]
#define fpscr_rn env->fpscr[FPSCR_RN]
/* Supervisor mode registers */
/* Machine state register */
#define MSR_POW 18
#define MSR_ILE 16
#define MSR_EE 15
#define MSR_PR 14
#define MSR_FP 13
#define MSR_ME 12
#define MSR_FE0 11
#define MSR_SE 10
#define MSR_BE 9
#define MSR_FE1 8
#define MSR_IP 6
#define MSR_IR 5
#define MSR_DR 4
#define MSR_RI 1
#define MSR_LE 0
#define msr_pow env->msr[MSR_POW]
#define msr_ile env->msr[MSR_ILE]
#define msr_ee env->msr[MSR_EE]
#define msr_pr env->msr[MSR_PR]
#define msr_fp env->msr[MSR_FP]
#define msr_me env->msr[MSR_ME]
#define msr_fe0 env->msr[MSR_FE0]
#define msr_se env->msr[MSR_SE]
#define msr_be env->msr[MSR_BE]
#define msr_fe1 env->msr[MSR_FE1]
#define msr_ip env->msr[MSR_IP]
#define msr_ir env->msr[MSR_IR]
#define msr_dr env->msr[MSR_DR]
#define msr_ri env->msr[MSR_RI]
#define msr_le env->msr[MSR_LE]
/* Segment registers */
typedef struct ppc_sr_t {
uint32_t t:1;
uint32_t ks:1;
uint32_t kp:1;
uint32_t n:1;
uint32_t res:4;
uint32_t vsid:24;
} ppc_sr_t;
typedef struct CPUPPCState {
/* general purpose registers */
uint32_t gpr[32];
/* floating point registers */
double fpr[32];
/* segment registers */
ppc_sr_t sr[16];
/* special purpose registers */
uint32_t spr[1024];
/* XER */
uint8_t xer[32];
/* Reservation address */
uint32_t reserve;
/* machine state register */
uint8_t msr[32];
/* condition register */
uint8_t crf[8];
/* floating point status and control register */
uint8_t fpscr[32];
uint32_t nip;
/* CPU exception code */
uint32_t exception;
/* qemu dedicated */
/* temporary float registers */
double ft0;
double ft1;
double ft2;
int interrupt_request;
jmp_buf jmp_env;
int exception_index;
int error_code;
int user_mode_only; /* user mode only simulation */
struct TranslationBlock *current_tb; /* currently executing TB */
/* user data */
void *opaque;
} CPUPPCState;
CPUPPCState *cpu_ppc_init(void);
int cpu_ppc_exec(CPUPPCState *s);
void cpu_ppc_close(CPUPPCState *s);
/* you can call this signal handler from your SIGBUS and SIGSEGV
signal handlers to inform the virtual CPU of exceptions. non zero
is returned if the signal was handled by the virtual CPU. */
struct siginfo;
int cpu_ppc_signal_handler(int host_signum, struct siginfo *info,
void *puc);
void cpu_ppc_dump_state(CPUPPCState *env, FILE *f, int flags);
#define TARGET_PAGE_BITS 12
#include "cpu-all.h"
#define ugpr(n) (env->gpr[n])
#define fpr(n) (env->fpr[n])
#define SPR_ENCODE(sprn) \
(((sprn) >> 5) | (((sprn) & 0x1F) << 5))
/* User mode SPR */
#define spr(n) env->spr[n]
//#define XER spr[1]
#define XER env->xer
#define XER_SO 31
#define XER_OV 30
#define XER_CA 29
#define XER_BC 0
#define xer_so env->xer[XER_SO]
#define xer_ov env->xer[XER_OV]
#define xer_ca env->xer[XER_CA]
#define xer_bc env->xer[XER_BC]
#define LR spr[SPR_ENCODE(8)]
#define CTR spr[SPR_ENCODE(9)]
/* VEA mode SPR */
#define V_TBL spr[SPR_ENCODE(268)]
#define V_TBU spr[SPR_ENCODE(269)]
/* supervisor mode SPR */
#define DSISR spr[SPR_ENCODE(18)]
#define DAR spr[SPR_ENCODE(19)]
#define DEC spr[SPR_ENCODE(22)]
#define SDR1 spr[SPR_ENCODE(25)]
typedef struct ppc_sdr1_t {
uint32_t htaborg:16;
uint32_t res:7;
uint32_t htabmask:9;
} ppc_sdr1_t;
#define SRR0 spr[SPR_ENCODE(26)]
#define SRR0_MASK 0xFFFFFFFC
#define SRR1 spr[SPR_ENCODE(27)]
#define SPRG0 spr[SPR_ENCODE(272)]
#define SPRG1 spr[SPR_ENCODE(273)]
#define SPRG2 spr[SPR_ENCODE(274)]
#define SPRG3 spr[SPR_ENCODE(275)]
#define EAR spr[SPR_ENCODE(282)]
typedef struct ppc_ear_t {
uint32_t e:1;
uint32_t res:25;
uint32_t rid:6;
} ppc_ear_t;
#define TBL spr[SPR_ENCODE(284)]
#define TBU spr[SPR_ENCODE(285)]
#define PVR spr[SPR_ENCODE(287)]
typedef struct ppc_pvr_t {
uint32_t version:16;
uint32_t revision:16;
} ppc_pvr_t;
#define IBAT0U spr[SPR_ENCODE(528)]
#define IBAT0L spr[SPR_ENCODE(529)]
#define IBAT1U spr[SPR_ENCODE(530)]
#define IBAT1L spr[SPR_ENCODE(531)]
#define IBAT2U spr[SPR_ENCODE(532)]
#define IBAT2L spr[SPR_ENCODE(533)]
#define IBAT3U spr[SPR_ENCODE(534)]
#define IBAT3L spr[SPR_ENCODE(535)]
#define DBAT0U spr[SPR_ENCODE(536)]
#define DBAT0L spr[SPR_ENCODE(537)]
#define DBAT1U spr[SPR_ENCODE(538)]
#define DBAT1L spr[SPR_ENCODE(539)]
#define DBAT2U spr[SPR_ENCODE(540)]
#define DBAT2L spr[SPR_ENCODE(541)]
#define DBAT3U spr[SPR_ENCODE(542)]
#define DBAT3L spr[SPR_ENCODE(543)]
typedef struct ppc_ubat_t {
uint32_t bepi:15;
uint32_t res:4;
uint32_t bl:11;
uint32_t vs:1;
uint32_t vp:1;
} ppc_ubat_t;
typedef struct ppc_lbat_t {
uint32_t brpn:15;
uint32_t res0:10;
uint32_t w:1;
uint32_t i:1;
uint32_t m:1;
uint32_t g:1;
uint32_t res1:1;
uint32_t pp:2;
} ppc_lbat_t;
#define DABR spr[SPR_ENCODE(1013)]
#define DABR_MASK 0xFFFFFFF8
typedef struct ppc_dabr_t {
uint32_t dab:29;
uint32_t bt:1;
uint32_t dw:1;
uint32_t dr:1;
} ppc_dabr_t;
#define FPECR spr[SPR_ENCODE(1022)]
#define PIR spr[SPR_ENCODE(1023)]
#define TARGET_PAGE_BITS 12
#include "cpu-all.h"
CPUPPCState *cpu_ppc_init(void);
int cpu_ppc_exec(CPUPPCState *s);
void cpu_ppc_close(CPUPPCState *s);
void cpu_ppc_dump_state(CPUPPCState *env, FILE *f, int flags);
/* Exeptions */
enum {
EXCP_NONE = 0x00,
/* PPC hardware exceptions : exception vector / 0x100 */
EXCP_RESET = 0x01, /* System reset */
EXCP_MACHINE_CHECK = 0x02, /* Machine check exception */
EXCP_DSI = 0x03, /* Impossible memory access */
EXCP_ISI = 0x04, /* Impossible instruction fetch */
EXCP_EXTERNAL = 0x05, /* External interruption */
EXCP_ALIGN = 0x06, /* Alignment exception */
EXCP_PROGRAM = 0x07, /* Program exception */
EXCP_NO_FP = 0x08, /* No floating point */
EXCP_DECR = 0x09, /* Decrementer exception */
EXCP_RESA = 0x0A, /* Implementation specific */
EXCP_RESB = 0x0B, /* Implementation specific */
EXCP_SYSCALL = 0x0C, /* System call */
EXCP_TRACE = 0x0D, /* Trace exception (optional) */
EXCP_FP_ASSIST = 0x0E, /* Floating-point assist (optional) */
#if 0
/* Exeption subtypes for EXCP_DSI */
EXCP_DSI_TRANSLATE = 0x10301, /* Data address can't be translated */
EXCP_DSI_NOTSUP = 0x10302, /* Access type not supported */
EXCP_DSI_PROT = 0x10303, /* Memory protection violation */
EXCP_DSI_EXTERNAL = 0x10304, /* External access disabled */
EXCP_DSI_DABR = 0x10305, /* Data address breakpoint */
/* Exeption subtypes for EXCP_ISI */
EXCP_ISI_TRANSLATE = 0x10401, /* Code address can't be translated */
EXCP_ISI_NOTSUP = 0x10402, /* Access type not supported */
EXCP_ISI_PROT = 0x10403, /* Memory protection violation */
EXCP_ISI_GUARD = 0x10404, /* Fetch into guarded memory */
/* Exeption subtypes for EXCP_ALIGN */
EXCP_ALIGN_FP = 0x10601, /* FP alignment exception */
EXCP_ALIGN_LST = 0x10602, /* Unaligned memory load/store */
EXCP_ALIGN_LE = 0x10603, /* Unaligned little-endian access */
EXCP_ALIGN_PROT = 0x10604, /* Access cross protection boundary */
EXCP_ALIGN_BAT = 0x10605, /* Access cross a BAT/seg boundary */
EXCP_ALIGN_CACHE = 0x10606, /* Impossible dcbz access */
/* Exeption subtypes for EXCP_PROGRAM */
/* FP exceptions */
EXCP_FP_OX = 0x10701, /* FP overflow */
EXCP_FP_UX = 0x10702, /* FP underflow */
EXCP_FP_ZX = 0x10703, /* FP divide by zero */
EXCP_FP_XX = 0x10704, /* FP inexact */
EXCP_FP_VXNAN = 0x10705, /* FP invalid SNaN op */
EXCP_FP_VXISI = 0x10706, /* FP invalid infinite substraction */
EXCP_FP_VXIDI = 0x10707, /* FP invalid infinite divide */
EXCP_FP_VXZDZ = 0x10708, /* FP invalid zero divide */
EXCP_FP_VXIMZ = 0x10709, /* FP invalid infinite * zero */
EXCP_FP_VXVC = 0x1070A, /* FP invalid compare */
EXCP_FP_VXSOFT = 0x1070B, /* FP invalid operation */
EXCP_FP_VXSQRT = 0x1070C, /* FP invalid square root */
EXCP_FP_VXCVI = 0x1070D, /* FP invalid integer conversion */
/* Invalid instruction */
EXCP_INVAL_INVAL = 0x10711, /* Invalid instruction */
EXCP_INVAL_LSWX = 0x10712, /* Invalid lswx instruction */
EXCP_INVAL_SPR = 0x10713, /* Invalid SPR access */
EXCP_INVAL_FP = 0x10714, /* Unimplemented mandatory fp instr */
#endif
EXCP_INVAL = 0x70, /* Invalid instruction */
/* Privileged instruction */
EXCP_PRIV = 0x71, /* Privileged instruction */
/* Trap */
EXCP_TRAP = 0x72, /* Trap */
/* Special cases where we want to stop translation */
EXCP_MTMSR = 0x103, /* mtmsr instruction: */
/* may change privilege level */
EXCP_BRANCH = 0x104, /* branch instruction */
};
#endif /* !defined (__CPU_PPC_H__) */

166
target-ppc/exec.h Normal file
View File

@@ -0,0 +1,166 @@
/*
* PPC emulation definitions for qemu.
*
* Copyright (c) 2003 Jocelyn Mayer
*
* 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
*/
#if !defined (__PPC_H__)
#define __PPC_H__
#include "dyngen-exec.h"
register struct CPUPPCState *env asm(AREG0);
register uint32_t T0 asm(AREG1);
register uint32_t T1 asm(AREG2);
register uint32_t T2 asm(AREG3);
#define PARAM(n) ((uint32_t)PARAM##n)
#define SPARAM(n) ((int32_t)PARAM##n)
#define FT0 (env->ft0)
#define FT1 (env->ft1)
#define FT2 (env->ft2)
#define FTS0 ((float)env->ft0)
#define FTS1 ((float)env->ft1)
#define FTS2 ((float)env->ft2)
#define RETURN() __asm__ __volatile__("");
#include "cpu.h"
#include "exec-all.h"
static inline uint8_t ld8 (uint32_t EA)
{
return *((uint8_t *)EA);
}
static inline uint16_t ld16 (uint32_t EA)
{
return __be16_to_cpu(*((uint16_t *)EA));
}
static inline uint16_t ld16r (uint32_t EA)
{
return __le16_to_cpu(*((uint16_t *)EA));
}
static inline uint32_t ld32 (uint32_t EA)
{
return __be32_to_cpu(*((uint32_t *)EA));
}
static inline uint32_t ld32r (uint32_t EA)
{
return __le32_to_cpu(*((uint32_t *)EA));
}
static inline uint64_t ld64 (uint32_t EA)
{
return __be64_to_cpu(*((uint64_t *)EA));
}
static inline uint64_t ld64r (uint32_t EA)
{
return __le64_to_cpu(*((uint64_t *)EA));
}
static inline void st8 (uint32_t EA, uint8_t data)
{
*((uint8_t *)EA) = data;
}
static inline void st16 (uint32_t EA, uint16_t data)
{
*((uint16_t *)EA) = __cpu_to_be16(data);
}
static inline void st16r (uint32_t EA, uint16_t data)
{
*((uint16_t *)EA) = __cpu_to_le16(data);
}
static inline void st32 (uint32_t EA, uint32_t data)
{
*((uint32_t *)EA) = __cpu_to_be32(data);
}
static inline void st32r (uint32_t EA, uint32_t data)
{
*((uint32_t *)EA) = __cpu_to_le32(data);
}
static inline void st64 (uint32_t EA, uint64_t data)
{
*((uint64_t *)EA) = __cpu_to_be64(data);
}
static inline void st64r (uint32_t EA, uint64_t data)
{
*((uint64_t *)EA) = __cpu_to_le64(data);
}
static inline void set_CRn(int n, uint8_t value)
{
env->crf[n] = value;
}
static inline void set_carry (void)
{
xer_ca = 1;
}
static inline void reset_carry (void)
{
xer_ca = 0;
}
static inline void set_overflow (void)
{
xer_so = 1;
xer_ov = 1;
}
static inline void reset_overflow (void)
{
xer_ov = 0;
}
static inline uint32_t rotl (uint32_t i, int n)
{
return ((i << n) | (i >> (32 - n)));
}
void raise_exception (int exception_index);
void raise_exception_err (int exception_index, int error_code);
uint32_t do_load_cr (void);
void do_store_cr (uint32_t crn, uint32_t value);
uint32_t do_load_xer (void);
void do_store_xer (uint32_t value);
uint32_t do_load_msr (void);
void do_store_msr (uint32_t msr_value);
void do_load_fpscr (void);
void do_store_fpscr (uint32_t mask);
int32_t do_sraw(int32_t Ta, uint32_t Tb);
void do_lmw (int reg, uint32_t src);
void do_stmw (int reg, uint32_t dest);
void do_lsw (uint32_t reg, int count, uint32_t src);
void do_stsw (uint32_t reg, int count, uint32_t dest);
void do_dcbz (void);
void do_icbi (void);
#endif /* !defined (__PPC_H__) */

267
target-ppc/helper.c Normal file
View File

@@ -0,0 +1,267 @@
/*
* PPC emulation helpers for qemu.
*
* Copyright (c) 2003 Jocelyn Mayer
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "exec.h"
extern FILE *logfile;
void cpu_loop_exit(void)
{
longjmp(env->jmp_env, 1);
}
/* shortcuts to generate exceptions */
void raise_exception_err (int exception_index, int error_code)
{
env->exception_index = exception_index;
env->error_code = error_code;
cpu_loop_exit();
}
void raise_exception (int exception_index)
{
env->exception_index = exception_index;
env->error_code = 0;
cpu_loop_exit();
}
/* Helpers for "fat" micro operations */
uint32_t do_load_cr (void)
{
return (env->crf[0] << 28) |
(env->crf[1] << 24) |
(env->crf[2] << 20) |
(env->crf[3] << 16) |
(env->crf[4] << 12) |
(env->crf[5] << 8) |
(env->crf[6] << 4) |
(env->crf[7] << 0);
}
void do_store_cr (uint32_t crn, uint32_t value)
{
int i, sh;
for (i = 0, sh = 7; i < 8; i++, sh --) {
if (crn & (1 << sh))
env->crf[i] = (value >> (sh * 4)) & 0xF;
}
}
uint32_t do_load_xer (void)
{
return (xer_so << XER_SO) |
(xer_ov << XER_OV) |
(xer_ca << XER_CA) |
(xer_bc << XER_BC);
}
void do_store_xer (uint32_t value)
{
xer_so = (value >> XER_SO) & 0x01;
xer_ov = (value >> XER_OV) & 0x01;
xer_ca = (value >> XER_CA) & 0x01;
xer_bc = (value >> XER_BC) & 0x1f;
}
uint32_t do_load_msr (void)
{
return (msr_pow << MSR_POW) |
(msr_ile << MSR_ILE) |
(msr_ee << MSR_EE) |
(msr_pr << MSR_PR) |
(msr_fp << MSR_FP) |
(msr_me << MSR_ME) |
(msr_fe0 << MSR_FE0) |
(msr_se << MSR_SE) |
(msr_be << MSR_BE) |
(msr_fe1 << MSR_FE1) |
(msr_ip << MSR_IP) |
(msr_ir << MSR_IR) |
(msr_dr << MSR_DR) |
(msr_ri << MSR_RI) |
(msr_le << MSR_LE);
}
void do_store_msr (uint32_t msr_value)
{
msr_pow = (msr_value >> MSR_POW) & 0x03;
msr_ile = (msr_value >> MSR_ILE) & 0x01;
msr_ee = (msr_value >> MSR_EE) & 0x01;
msr_pr = (msr_value >> MSR_PR) & 0x01;
msr_fp = (msr_value >> MSR_FP) & 0x01;
msr_me = (msr_value >> MSR_ME) & 0x01;
msr_fe0 = (msr_value >> MSR_FE0) & 0x01;
msr_se = (msr_value >> MSR_SE) & 0x01;
msr_be = (msr_value >> MSR_BE) & 0x01;
msr_fe1 = (msr_value >> MSR_FE1) & 0x01;
msr_ip = (msr_value >> MSR_IP) & 0x01;
msr_ir = (msr_value >> MSR_IR) & 0x01;
msr_dr = (msr_value >> MSR_DR) & 0x01;
msr_ri = (msr_value >> MSR_RI) & 0x01;
msr_le = (msr_value >> MSR_LE) & 0x01;
}
/* The 32 MSB of the target fpr are undefined. They'll be zero... */
/* Floating point operations helpers */
void do_load_fpscr (void)
{
/* The 32 MSB of the target fpr are undefined.
* They'll be zero...
*/
union {
double d;
struct {
uint32_t u[2];
} s;
} u;
int i;
u.s.u[0] = 0;
u.s.u[1] = 0;
for (i = 0; i < 8; i++)
u.s.u[1] |= env->fpscr[i] << (4 * i);
FT0 = u.d;
}
void do_store_fpscr (uint32_t mask)
{
/*
* We use only the 32 LSB of the incoming fpr
*/
union {
double d;
struct {
uint32_t u[2];
} s;
} u;
int i;
u.d = FT0;
if (mask & 0x80)
env->fpscr[0] = (env->fpscr[0] & 0x9) | ((u.s.u[1] >> 28) & ~0x9);
for (i = 1; i < 7; i++) {
if (mask & (1 << (7 - i)))
env->fpscr[i] = (u.s.u[1] >> (4 * (7 - i))) & 0xF;
}
/* TODO: update FEX & VX */
/* Set rounding mode */
switch (env->fpscr[0] & 0x3) {
case 0:
/* Best approximation (round to nearest) */
fesetround(FE_TONEAREST);
break;
case 1:
/* Smaller magnitude (round toward zero) */
fesetround(FE_TOWARDZERO);
break;
case 2:
/* Round toward +infinite */
fesetround(FE_UPWARD);
break;
case 3:
/* Round toward -infinite */
fesetround(FE_DOWNWARD);
break;
}
}
int32_t do_sraw(int32_t value, uint32_t shift)
{
int32_t ret;
xer_ca = 0;
if (shift & 0x20) {
ret = (-1) * ((uint32_t)value >> 31);
if (ret < 0)
xer_ca = 1;
} else {
ret = value >> (shift & 0x1f);
if (ret < 0 && (value & ((1 << shift) - 1)) != 0)
xer_ca = 1;
}
return ret;
}
void do_lmw (int reg, uint32_t src)
{
for (; reg <= 31; reg++, src += 4)
ugpr(reg) = ld32(src);
}
void do_stmw (int reg, uint32_t dest)
{
for (; reg <= 31; reg++, dest += 4)
st32(dest, ugpr(reg));
}
void do_lsw (uint32_t reg, int count, uint32_t src)
{
uint32_t tmp;
int sh;
for (; count > 3; count -= 4, src += 4) {
ugpr(reg++) = ld32(src);
if (T2 == 32)
T2 = 0;
}
if (count > 0) {
tmp = 0;
for (sh = 24; count > 0; count--, src++, sh -= 8) {
tmp |= ld8(src) << sh;
}
ugpr(reg) = tmp;
}
}
void do_stsw (uint32_t reg, int count, uint32_t dest)
{
int sh;
for (; count > 3; count -= 4, dest += 4) {
st32(dest, ugpr(reg++));
if (reg == 32)
reg = 0;
}
if (count > 0) {
for (sh = 24; count > 0; count--, dest++, sh -= 8) {
st8(dest, (ugpr(reg) >> sh) & 0xFF);
}
}
}
void do_dcbz (void)
{
int i;
/* Assume cache line size is 32 */
for (i = 0; i < 8; i++) {
st32(T0, 0);
T0 += 4;
}
}
/* Instruction cache invalidation helper */
void do_icbi (void)
{
tb_invalidate_page(T0);
}

1418
target-ppc/op.c Normal file

File diff suppressed because it is too large Load Diff

159
target-ppc/op_template.h Normal file
View File

@@ -0,0 +1,159 @@
/*
* PPC emulation micro-operations for qemu.
*
* Copyright (c) 2003 Jocelyn Mayer
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
void OPPROTO glue(op_load_gpr_T0_gpr, REG)(void)
{
T0 = regs->gpr[REG];
}
void OPPROTO glue(op_load_gpr_T1_gpr, REG)(void)
{
T1 = regs->gpr[REG];
}
void OPPROTO glue(op_load_gpr_T2_gpr, REG)(void)
{
T2 = regs->gpr[REG];
}
void OPPROTO glue(op_store_T0_gpr_gpr, REG)(void)
{
regs->gpr[REG] = T0;
}
void OPPROTO glue(op_store_T1_gpr_gpr, REG)(void)
{
regs->gpr[REG] = T1;
}
void OPPROTO glue(op_store_T2_gpr_gpr, REG)(void)
{
regs->gpr[REG] = T2;
}
#if REG <= 7
void OPPROTO glue(op_load_crf_T0_crf, REG)(void)
{
T0 = regs->crf[REG];
}
void OPPROTO glue(op_load_crf_T1_crf, REG)(void)
{
T1 = regs->crf[REG];
}
void OPPROTO glue(op_store_T0_crf_crf, REG)(void)
{
regs->crf[REG] = T0;
}
void OPPROTO glue(op_store_T1_crf_crf, REG)(void)
{
regs->crf[REG] = T1;
}
/* Floating point condition and status register moves */
void OPPROTO glue(op_load_fpscr_T0_fpscr, REG)(void)
{
T0 = regs->fpscr[REG];
RETURN();
}
#if REG == 0
void OPPROTO glue(op_store_T0_fpscr_fpscr, REG)(void)
{
regs->fpscr[REG] = (regs->fpscr[REG] & 0x9) | (T0 & ~0x9);
RETURN();
}
void OPPROTO glue(op_store_T0_fpscri_fpscr, REG)(void)
{
regs->fpscr[REG] = (regs->fpscr[REG] & ~0x9) | (PARAM(1) & 0x9);
RETURN();
}
void OPPROTO glue(op_clear_fpscr_fpscr, REG)(void)
{
regs->fpscr[REG] = (regs->fpscr[REG] & 0x9);
RETURN();
}
#else
void OPPROTO glue(op_store_T0_fpscr_fpscr, REG)(void)
{
regs->fpscr[REG] = T0;
RETURN();
}
void OPPROTO glue(op_store_T0_fpscri_fpscr, REG)(void)
{
regs->fpscr[REG] = PARAM(1);
RETURN();
}
void OPPROTO glue(op_clear_fpscr_fpscr, REG)(void)
{
regs->fpscr[REG] = 0x0;
RETURN();
}
#endif
#endif /* REG <= 7 */
/* float moves */
/* floating point registers moves */
void OPPROTO glue(op_load_fpr_FT0_fpr, REG)(void)
{
FT0 = env->fpr[REG];
RETURN();
}
void OPPROTO glue(op_store_FT0_fpr_fpr, REG)(void)
{
env->fpr[REG] = FT0;
RETURN();
}
void OPPROTO glue(op_load_fpr_FT1_fpr, REG)(void)
{
FT1 = env->fpr[REG];
RETURN();
}
void OPPROTO glue(op_store_FT1_fpr_fpr, REG)(void)
{
env->fpr[REG] = FT1;
RETURN();
}
void OPPROTO glue(op_load_fpr_FT2_fpr, REG)(void)
{
FT2 = env->fpr[REG];
RETURN();
}
void OPPROTO glue(op_store_FT2_fpr_fpr, REG)(void)
{
env->fpr[REG] = FT2;
RETURN();
}
#undef REG

2485
target-ppc/translate.c Normal file

File diff suppressed because it is too large Load Diff

59
target-sparc/cpu.h Normal file
View File

@@ -0,0 +1,59 @@
#ifndef CPU_SPARC_H
#define CPU_SPARC_H
#include <setjmp.h>
#include "config.h"
#include "cpu-defs.h"
/*#define EXCP_INTERRUPT 0x100*/
/* trap definitions */
#define TT_ILL_INSN 0x02
#define TT_WIN_OVF 0x05
#define TT_WIN_UNF 0x06
#define TT_DIV_ZERO 0x2a
#define TT_TRAP 0x80
#define PSR_NEG (1<<23)
#define PSR_ZERO (1<<22)
#define PSR_OVF (1<<21)
#define PSR_CARRY (1<<20)
#define NWINDOWS 32
typedef struct CPUSPARCState {
uint32_t gregs[8]; /* general registers */
uint32_t *regwptr; /* pointer to current register window */
double *regfptr; /* floating point registers */
uint32_t pc; /* program counter */
uint32_t npc; /* next program counter */
uint32_t sp; /* stack pointer */
uint32_t y; /* multiply/divide register */
uint32_t psr; /* processor state register */
uint32_t T2;
uint32_t cwp; /* index of current register window (extracted
from PSR) */
uint32_t wim; /* window invalid mask */
jmp_buf jmp_env;
int user_mode_only;
int exception_index;
int interrupt_index;
int interrupt_request;
struct TranslationBlock *current_tb;
void *opaque;
/* NOTE: we allow 8 more registers to handle wrapping */
uint32_t regbase[NWINDOWS * 16 + 8];
} CPUSPARCState;
CPUSPARCState *cpu_sparc_init(void);
int cpu_sparc_exec(CPUSPARCState *s);
int cpu_sparc_close(CPUSPARCState *s);
struct siginfo;
int cpu_sparc_signal_handler(int hostsignum, struct siginfo *info, void *puc);
void cpu_sparc_dump_state(CPUSPARCState *env, FILE *f, int flags);
#define TARGET_PAGE_BITS 13
#include "cpu-all.h"
#endif

16
target-sparc/exec.h Normal file
View File

@@ -0,0 +1,16 @@
#ifndef EXEC_SPARC_H
#define EXEC_SPARC_H 1
#include "dyngen-exec.h"
register struct CPUSPARCState *env asm(AREG0);
register uint32_t T0 asm(AREG1);
register uint32_t T1 asm(AREG2);
register uint32_t T2 asm(AREG3);
#include "cpu.h"
#include "exec-all.h"
void cpu_lock(void);
void cpu_unlock(void);
void cpu_loop_exit(void);
#endif

661
target-sparc/op.c Normal file
View File

@@ -0,0 +1,661 @@
/*
SPARC micro operations
Copyright (C) 2003 Thomas M. Ogrisegg <tom@fnord.at>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "exec.h"
/*XXX*/
#define REGNAME g0
#define REG (env->gregs[0])
#include "op_template.h"
#define REGNAME g1
#define REG (env->gregs[1])
#include "op_template.h"
#define REGNAME g2
#define REG (env->gregs[2])
#include "op_template.h"
#define REGNAME g3
#define REG (env->gregs[3])
#include "op_template.h"
#define REGNAME g4
#define REG (env->gregs[4])
#include "op_template.h"
#define REGNAME g5
#define REG (env->gregs[5])
#include "op_template.h"
#define REGNAME g6
#define REG (env->gregs[6])
#include "op_template.h"
#define REGNAME g7
#define REG (env->gregs[7])
#include "op_template.h"
#define REGNAME i0
#define REG (env->regwptr[16])
#include "op_template.h"
#define REGNAME i1
#define REG (env->regwptr[17])
#include "op_template.h"
#define REGNAME i2
#define REG (env->regwptr[18])
#include "op_template.h"
#define REGNAME i3
#define REG (env->regwptr[19])
#include "op_template.h"
#define REGNAME i4
#define REG (env->regwptr[20])
#include "op_template.h"
#define REGNAME i5
#define REG (env->regwptr[21])
#include "op_template.h"
#define REGNAME i6
#define REG (env->regwptr[22])
#include "op_template.h"
#define REGNAME i7
#define REG (env->regwptr[23])
#include "op_template.h"
#define REGNAME l0
#define REG (env->regwptr[8])
#include "op_template.h"
#define REGNAME l1
#define REG (env->regwptr[9])
#include "op_template.h"
#define REGNAME l2
#define REG (env->regwptr[10])
#include "op_template.h"
#define REGNAME l3
#define REG (env->regwptr[11])
#include "op_template.h"
#define REGNAME l4
#define REG (env->regwptr[12])
#include "op_template.h"
#define REGNAME l5
#define REG (env->regwptr[13])
#include "op_template.h"
#define REGNAME l6
#define REG (env->regwptr[14])
#include "op_template.h"
#define REGNAME l7
#define REG (env->regwptr[15])
#include "op_template.h"
#define REGNAME o0
#define REG (env->regwptr[0])
#include "op_template.h"
#define REGNAME o1
#define REG (env->regwptr[1])
#include "op_template.h"
#define REGNAME o2
#define REG (env->regwptr[2])
#include "op_template.h"
#define REGNAME o3
#define REG (env->regwptr[3])
#include "op_template.h"
#define REGNAME o4
#define REG (env->regwptr[4])
#include "op_template.h"
#define REGNAME o5
#define REG (env->regwptr[5])
#include "op_template.h"
#define REGNAME o6
#define REG (env->regwptr[6])
#include "op_template.h"
#define REGNAME o7
#define REG (env->regwptr[7])
#include "op_template.h"
#define EIP (env->pc)
#define FLAG_SET(x) (env->psr&x)?1:0
#define GET_FLAGS unsigned int Z = FLAG_SET(PSR_ZERO), N = FLAG_SET(PSR_NEG), V = FLAG_SET(PSR_OVF), C = FLAG_SET(PSR_CARRY)
void OPPROTO op_movl_T0_0(void)
{
T0 = 0;
}
void OPPROTO op_movl_T0_1(void)
{
T0 = 1;
}
void OPPROTO op_movl_T0_im(void)
{
T0 = PARAM1;
}
void OPPROTO op_movl_T1_im(void)
{
T1 = PARAM1;
}
void OPPROTO op_movl_T2_im(void)
{
T2 = PARAM1;
}
void OPPROTO op_addl_T1_im(void)
{
T1 += PARAM1;
}
void OPPROTO op_addl_T1_T2(void)
{
T1 += T2;
}
void OPPROTO op_subl_T1_T2(void)
{
T1 -= T2;
}
void OPPROTO op_add_T1_T0(void)
{
T0 += T1;
}
void OPPROTO op_add_T1_T0_cc(void)
{
unsigned int src1;
src1 = T0;
T0 += T1;
env->psr = 0;
if (!T0)
env->psr |= PSR_ZERO;
if ((int) T0 < 0)
env->psr |= PSR_NEG;
if (T0 < src1)
env->psr |= PSR_CARRY;
if (((src1 ^ T1 ^ -1) & (src1 ^ T0)) & (1 << 31))
env->psr |= PSR_OVF;
FORCE_RET();
}
void OPPROTO op_sub_T1_T0(void)
{
T0 -= T1;
}
void OPPROTO op_sub_T1_T0_cc(void)
{
unsigned int src1;
src1 = T0;
T0 -= T1;
env->psr = 0;
if (!T0)
env->psr |= PSR_ZERO;
if ((int) T0 < 0)
env->psr |= PSR_NEG;
if (src1 < T1)
env->psr |= PSR_CARRY;
if (((src1 ^ T1) & (src1 ^ T0)) & (1 << 31))
env->psr |= PSR_OVF;
FORCE_RET();
}
void OPPROTO op_and_T1_T0(void)
{
T0 &= T1;
}
void OPPROTO op_or_T1_T0(void)
{
T0 |= T1;
}
void OPPROTO op_xor_T1_T0(void)
{
T0 ^= T1;
}
void OPPROTO op_andn_T1_T0(void)
{
T0 &= ~T1;
}
void OPPROTO op_orn_T1_T0(void)
{
T0 |= ~T1;
}
void OPPROTO op_xnor_T1_T0(void)
{
T0 ^= ~T1;
}
void OPPROTO op_addx_T1_T0(void)
{
T0 += T1 + ((env->psr & PSR_CARRY) ? 1 : 0);
}
void OPPROTO op_umul_T1_T0(void)
{
uint64_t res;
res = (uint64_t) T0 *(uint64_t) T1;
T0 = res & 0xffffffff;
env->y = res >> 32;
}
void OPPROTO op_smul_T1_T0(void)
{
uint64_t res;
res = (int64_t) ((int32_t) T0) * (int64_t) ((int32_t) T1);
T0 = res & 0xffffffff;
env->y = res >> 32;
}
void OPPROTO op_mulscc_T1_T0(void)
{
unsigned int b1, C, V, b2, src1;
C = FLAG_SET(PSR_CARRY);
V = FLAG_SET(PSR_OVF);
b1 = C ^ V;
b2 = T0 & 1;
T0 = (b1 << 31) | (T0 >> 1);
if (!(env->y & 1))
T1 = 0;
/* do addition and update flags */
src1 = T0;
T0 += T1;
env->psr = 0;
if (!T0)
env->psr |= PSR_ZERO;
if ((int) T0 < 0)
env->psr |= PSR_NEG;
if (T0 < src1)
env->psr |= PSR_CARRY;
if (((src1 ^ T1 ^ -1) & (src1 ^ T0)) & (1 << 31))
env->psr |= PSR_OVF;
env->y = (b2 << 31) | (env->y >> 1);
FORCE_RET();
}
void OPPROTO op_udiv_T1_T0(void)
{
uint64_t x0;
uint32_t x1;
x0 = T0 | ((uint64_t) (env->y) << 32);
x1 = T1;
x0 = x0 / x1;
if (x0 > 0xffffffff) {
T0 = 0xffffffff;
T1 = 1;
} else {
T0 = x0;
T1 = 0;
}
FORCE_RET();
}
void OPPROTO op_sdiv_T1_T0(void)
{
int64_t x0;
int32_t x1;
x0 = T0 | ((uint64_t) (env->y) << 32);
x1 = T1;
x0 = x0 / x1;
if ((int32_t) x0 != x0) {
T0 = x0 >> 63;
T1 = 1;
} else {
T0 = x0;
T1 = 0;
}
FORCE_RET();
}
void OPPROTO op_div_cc(void)
{
env->psr = 0;
if (!T0)
env->psr |= PSR_ZERO;
if ((int) T0 < 0)
env->psr |= PSR_NEG;
if (T1)
env->psr |= PSR_OVF;
FORCE_RET();
}
void OPPROTO op_subx_T1_T0(void)
{
T0 -= T1 + ((env->psr & PSR_CARRY) ? 1 : 0);
}
void OPPROTO op_logic_T0_cc(void)
{
env->psr = 0;
if (!T0)
env->psr |= PSR_ZERO;
if ((int) T0 < 0)
env->psr |= PSR_NEG;
FORCE_RET();
}
void OPPROTO op_set_flags(void)
{
env->psr = 0;
if (!T0)
env->psr |= PSR_ZERO;
if ((unsigned int) T0 < (unsigned int) T1)
env->psr |= PSR_CARRY;
if ((int) T0 < (int) T1)
env->psr |= PSR_OVF;
if ((int) T0 < 0)
env->psr |= PSR_NEG;
FORCE_RET();
}
void OPPROTO op_sll(void)
{
T0 <<= T1;
}
void OPPROTO op_srl(void)
{
T0 >>= T1;
}
void OPPROTO op_sra(void)
{
T0 = ((int32_t) T0) >> T1;
}
void OPPROTO op_st(void)
{
stl((void *) T0, T1);
}
void OPPROTO op_stb(void)
{
stb((void *) T0, T1);
}
void OPPROTO op_sth(void)
{
stw((void *) T0, T1);
}
void OPPROTO op_std(void)
{
stl((void *) T0, T1);
stl((void *) (T0 + 4), T2);
}
void OPPROTO op_ld(void)
{
T1 = ldl((void *) T0);
}
void OPPROTO op_ldub(void)
{
T1 = ldub((void *) T0);
}
void OPPROTO op_lduh(void)
{
T1 = lduw((void *) T0);
}
void OPPROTO op_ldsb(void)
{
T1 = ldsb((void *) T0);
}
void OPPROTO op_ldsh(void)
{
T1 = ldsw((void *) T0);
}
void OPPROTO op_ldstub(void)
{
T1 = ldub((void *) T0);
stb((void *) T0, 0xff); /* XXX: Should be Atomically */
}
void OPPROTO op_swap(void)
{
unsigned int tmp = ldl((void *) T0);
stl((void *) T0, T1); /* XXX: Should be Atomically */
T1 = tmp;
}
void OPPROTO op_ldd(void)
{
T1 = ldl((void *) T0);
T0 = ldl((void *) (T0 + 4));
}
void OPPROTO op_wry(void)
{
env->y = T0;
}
void OPPROTO op_rdy(void)
{
T0 = env->y;
}
void raise_exception(int tt)
{
env->exception_index = tt;
cpu_loop_exit();
}
void memcpy32(uint32_t *dst, const uint32_t *src)
{
dst[0] = src[0];
dst[1] = src[1];
dst[2] = src[2];
dst[3] = src[3];
dst[4] = src[4];
dst[5] = src[5];
dst[6] = src[6];
dst[7] = src[7];
}
static inline void set_cwp(int new_cwp)
{
/* put the modified wrap registers at their proper location */
if (env->cwp == (NWINDOWS - 1))
memcpy32(env->regbase, env->regbase + NWINDOWS * 16);
env->cwp = new_cwp;
/* put the wrap registers at their temporary location */
if (new_cwp == (NWINDOWS - 1))
memcpy32(env->regbase + NWINDOWS * 16, env->regbase);
env->regwptr = env->regbase + (new_cwp * 16);
}
/* XXX: use another pointer for %iN registers to avoid slow wrapping
handling ? */
void OPPROTO op_save(void)
{
int cwp;
cwp = (env->cwp - 1) & (NWINDOWS - 1);
if (env->wim & (1 << cwp)) {
raise_exception(TT_WIN_OVF);
}
set_cwp(cwp);
FORCE_RET();
}
void OPPROTO op_restore(void)
{
int cwp;
cwp = (env->cwp + 1) & (NWINDOWS - 1);
if (env->wim & (1 << cwp)) {
raise_exception(TT_WIN_UNF);
}
set_cwp(cwp);
FORCE_RET();
}
void OPPROTO op_exception(void)
{
env->exception_index = PARAM1;
cpu_loop_exit();
}
void OPPROTO op_trap_T0(void)
{
env->exception_index = TT_TRAP + (T0 & 0x7f);
cpu_loop_exit();
}
void OPPROTO op_trapcc_T0(void)
{
if (T2) {
env->exception_index = TT_TRAP + (T0 & 0x7f);
cpu_loop_exit();
}
FORCE_RET();
}
void OPPROTO op_exit_tb(void)
{
EXIT_TB();
}
void OPPROTO op_eval_be(void)
{
T2 = (env->psr & PSR_ZERO);
}
void OPPROTO op_eval_ble(void)
{
GET_FLAGS;
T2 = Z | (N ^ V);
}
void OPPROTO op_eval_bl(void)
{
GET_FLAGS;
T2 = N ^ V;
}
void OPPROTO op_eval_bleu(void)
{
GET_FLAGS;
T2 = C | Z;
}
void OPPROTO op_eval_bcs(void)
{
T2 = (env->psr & PSR_CARRY);
}
void OPPROTO op_eval_bvs(void)
{
T2 = (env->psr & PSR_OVF);
}
void OPPROTO op_eval_bneg(void)
{
T2 = (env->psr & PSR_NEG);
}
void OPPROTO op_eval_bne(void)
{
T2 = !(env->psr & PSR_ZERO);
}
void OPPROTO op_eval_bg(void)
{
GET_FLAGS;
T2 = !(Z | (N ^ V));
}
void OPPROTO op_eval_bge(void)
{
GET_FLAGS;
T2 = !(N ^ V);
}
void OPPROTO op_eval_bgu(void)
{
GET_FLAGS;
T2 = !(C | Z);
}
void OPPROTO op_eval_bcc(void)
{
T2 = !(env->psr & PSR_CARRY);
}
void OPPROTO op_eval_bpos(void)
{
T2 = !(env->psr & PSR_NEG);
}
void OPPROTO op_eval_bvc(void)
{
T2 = !(env->psr & PSR_OVF);
}
void OPPROTO op_movl_T2_0(void)
{
T2 = 0;
}
void OPPROTO op_movl_T2_1(void)
{
T2 = 1;
}
void OPPROTO op_jmp_im(void)
{
env->pc = PARAM1;
}
void OPPROTO op_movl_npc_im(void)
{
env->npc = PARAM1;
}
void OPPROTO op_movl_npc_T0(void)
{
env->npc = T0;
}
void OPPROTO op_next_insn(void)
{
env->pc = env->npc;
env->npc = env->npc + 4;
}
void OPPROTO op_generic_branch(void)
{
if (T2) {
env->npc = PARAM1;
} else {
env->npc = PARAM2;
}
FORCE_RET();
}
void OPPROTO op_generic_branch_a(void)
{
if (T2) {
env->pc = PARAM2;
env->npc = PARAM1;
} else {
env->pc = PARAM2 + 4;
env->npc = PARAM2 + 8;
}
FORCE_RET();
}

View File

@@ -0,0 +1,48 @@
/*
* SPARC micro operations (templates for various register related
* operations)
*
* Copyright (c) 2003 Fabrice Bellard
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
void OPPROTO glue(op_movl_T0_, REGNAME)(void)
{
T0 = REG;
}
void OPPROTO glue(op_movl_T1_, REGNAME)(void)
{
T1 = REG;
}
void OPPROTO glue(op_movl_T2_, REGNAME)(void)
{
T2 = REG;
}
void OPPROTO glue(glue(op_movl_, REGNAME), _T0)(void)
{
REG = T0;
}
void OPPROTO glue(glue(op_movl_, REGNAME), _T1)(void)
{
REG = T1;
}
#undef REG
#undef REGNAME

865
target-sparc/translate.c Normal file
View File

@@ -0,0 +1,865 @@
/*
SPARC translation
Copyright (C) 2003 Thomas M. Ogrisegg <tom@fnord.at>
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
*/
/*
SPARC has two pitfalls: Delay slots and (a)nullification.
This is currently solved as follows:
'call' instructions simply execute the delay slot before the actual
control transfer instructions.
'jmpl' instructions execute calculate the destination, then execute
the delay slot and then do the control transfer.
(conditional) branch instructions are the most difficult ones, as the
delay slot may be nullified (ie. not executed). This happens when a
conditional branch is not executed (thus no control transfer happens)
and the 'anull' bit in the branch instruction opcode is set. This is
currently solved by doing a jump after the delay slot instruction.
TODO-list:
Register window overflow/underflow check
FPU-Instructions
Coprocessor-Instructions
Check signedness issues
Privileged instructions
Optimize synthetic instructions
Optional alignment and privileged instruction check
-- TMO, 09/03/03
*/
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <inttypes.h>
#include "cpu.h"
#include "exec-all.h"
#include "disas.h"
#define DEBUG_DISAS
typedef struct DisasContext {
uint8_t *pc; /* NULL means dynamic value */
uint8_t *npc; /* NULL means dynamic value */
int is_br;
struct TranslationBlock *tb;
} DisasContext;
static uint16_t *gen_opc_ptr;
static uint32_t *gen_opparam_ptr;
extern FILE *logfile;
extern int loglevel;
enum {
#define DEF(s,n,copy_size) INDEX_op_ ## s,
#include "opc.h"
#undef DEF
NB_OPS
};
#include "gen-op.h"
#define GET_FIELD(X, FROM, TO) \
((X) >> (31 - (TO)) & ((1 << ((TO) - (FROM) + 1)) - 1))
#define IS_IMM (insn & (1<<13))
static void disas_sparc_insn(DisasContext * dc);
typedef void (GenOpFunc) (void);
typedef void (GenOpFunc1) (long);
typedef void (GenOpFunc2) (long, long);
typedef void (GenOpFunc3) (long, long, long);
static GenOpFunc *gen_op_movl_TN_reg[2][32] = {
{
gen_op_movl_g0_T0,
gen_op_movl_g1_T0,
gen_op_movl_g2_T0,
gen_op_movl_g3_T0,
gen_op_movl_g4_T0,
gen_op_movl_g5_T0,
gen_op_movl_g6_T0,
gen_op_movl_g7_T0,
gen_op_movl_o0_T0,
gen_op_movl_o1_T0,
gen_op_movl_o2_T0,
gen_op_movl_o3_T0,
gen_op_movl_o4_T0,
gen_op_movl_o5_T0,
gen_op_movl_o6_T0,
gen_op_movl_o7_T0,
gen_op_movl_l0_T0,
gen_op_movl_l1_T0,
gen_op_movl_l2_T0,
gen_op_movl_l3_T0,
gen_op_movl_l4_T0,
gen_op_movl_l5_T0,
gen_op_movl_l6_T0,
gen_op_movl_l7_T0,
gen_op_movl_i0_T0,
gen_op_movl_i1_T0,
gen_op_movl_i2_T0,
gen_op_movl_i3_T0,
gen_op_movl_i4_T0,
gen_op_movl_i5_T0,
gen_op_movl_i6_T0,
gen_op_movl_i7_T0,
},
{
gen_op_movl_g0_T1,
gen_op_movl_g1_T1,
gen_op_movl_g2_T1,
gen_op_movl_g3_T1,
gen_op_movl_g4_T1,
gen_op_movl_g5_T1,
gen_op_movl_g6_T1,
gen_op_movl_g7_T1,
gen_op_movl_o0_T1,
gen_op_movl_o1_T1,
gen_op_movl_o2_T1,
gen_op_movl_o3_T1,
gen_op_movl_o4_T1,
gen_op_movl_o5_T1,
gen_op_movl_o6_T1,
gen_op_movl_o7_T1,
gen_op_movl_l0_T1,
gen_op_movl_l1_T1,
gen_op_movl_l2_T1,
gen_op_movl_l3_T1,
gen_op_movl_l4_T1,
gen_op_movl_l5_T1,
gen_op_movl_l6_T1,
gen_op_movl_l7_T1,
gen_op_movl_i0_T1,
gen_op_movl_i1_T1,
gen_op_movl_i2_T1,
gen_op_movl_i3_T1,
gen_op_movl_i4_T1,
gen_op_movl_i5_T1,
gen_op_movl_i6_T1,
gen_op_movl_i7_T1,
}
};
static GenOpFunc *gen_op_movl_reg_TN[3][32] = {
{
gen_op_movl_T0_g0,
gen_op_movl_T0_g1,
gen_op_movl_T0_g2,
gen_op_movl_T0_g3,
gen_op_movl_T0_g4,
gen_op_movl_T0_g5,
gen_op_movl_T0_g6,
gen_op_movl_T0_g7,
gen_op_movl_T0_o0,
gen_op_movl_T0_o1,
gen_op_movl_T0_o2,
gen_op_movl_T0_o3,
gen_op_movl_T0_o4,
gen_op_movl_T0_o5,
gen_op_movl_T0_o6,
gen_op_movl_T0_o7,
gen_op_movl_T0_l0,
gen_op_movl_T0_l1,
gen_op_movl_T0_l2,
gen_op_movl_T0_l3,
gen_op_movl_T0_l4,
gen_op_movl_T0_l5,
gen_op_movl_T0_l6,
gen_op_movl_T0_l7,
gen_op_movl_T0_i0,
gen_op_movl_T0_i1,
gen_op_movl_T0_i2,
gen_op_movl_T0_i3,
gen_op_movl_T0_i4,
gen_op_movl_T0_i5,
gen_op_movl_T0_i6,
gen_op_movl_T0_i7,
},
{
gen_op_movl_T1_g0,
gen_op_movl_T1_g1,
gen_op_movl_T1_g2,
gen_op_movl_T1_g3,
gen_op_movl_T1_g4,
gen_op_movl_T1_g5,
gen_op_movl_T1_g6,
gen_op_movl_T1_g7,
gen_op_movl_T1_o0,
gen_op_movl_T1_o1,
gen_op_movl_T1_o2,
gen_op_movl_T1_o3,
gen_op_movl_T1_o4,
gen_op_movl_T1_o5,
gen_op_movl_T1_o6,
gen_op_movl_T1_o7,
gen_op_movl_T1_l0,
gen_op_movl_T1_l1,
gen_op_movl_T1_l2,
gen_op_movl_T1_l3,
gen_op_movl_T1_l4,
gen_op_movl_T1_l5,
gen_op_movl_T1_l6,
gen_op_movl_T1_l7,
gen_op_movl_T1_i0,
gen_op_movl_T1_i1,
gen_op_movl_T1_i2,
gen_op_movl_T1_i3,
gen_op_movl_T1_i4,
gen_op_movl_T1_i5,
gen_op_movl_T1_i6,
gen_op_movl_T1_i7,
},
{
gen_op_movl_T2_g0,
gen_op_movl_T2_g1,
gen_op_movl_T2_g2,
gen_op_movl_T2_g3,
gen_op_movl_T2_g4,
gen_op_movl_T2_g5,
gen_op_movl_T2_g6,
gen_op_movl_T2_g7,
gen_op_movl_T2_o0,
gen_op_movl_T2_o1,
gen_op_movl_T2_o2,
gen_op_movl_T2_o3,
gen_op_movl_T2_o4,
gen_op_movl_T2_o5,
gen_op_movl_T2_o6,
gen_op_movl_T2_o7,
gen_op_movl_T2_l0,
gen_op_movl_T2_l1,
gen_op_movl_T2_l2,
gen_op_movl_T2_l3,
gen_op_movl_T2_l4,
gen_op_movl_T2_l5,
gen_op_movl_T2_l6,
gen_op_movl_T2_l7,
gen_op_movl_T2_i0,
gen_op_movl_T2_i1,
gen_op_movl_T2_i2,
gen_op_movl_T2_i3,
gen_op_movl_T2_i4,
gen_op_movl_T2_i5,
gen_op_movl_T2_i6,
gen_op_movl_T2_i7,
}
};
static GenOpFunc1 *gen_op_movl_TN_im[3] = {
gen_op_movl_T0_im,
gen_op_movl_T1_im,
gen_op_movl_T2_im
};
static inline void gen_movl_imm_TN(int reg, int imm)
{
gen_op_movl_TN_im[reg] (imm);
}
static inline void gen_movl_imm_T1(int val)
{
gen_movl_imm_TN(1, val);
}
static inline void gen_movl_imm_T0(int val)
{
gen_movl_imm_TN(0, val);
}
static inline void gen_movl_reg_TN(int reg, int t)
{
if (reg)
gen_op_movl_reg_TN[t][reg] ();
else
gen_movl_imm_TN(t, 0);
}
static inline void gen_movl_reg_T0(int reg)
{
gen_movl_reg_TN(reg, 0);
}
static inline void gen_movl_reg_T1(int reg)
{
gen_movl_reg_TN(reg, 1);
}
static inline void gen_movl_reg_T2(int reg)
{
gen_movl_reg_TN(reg, 2);
}
static inline void gen_movl_TN_reg(int reg, int t)
{
if (reg)
gen_op_movl_TN_reg[t][reg] ();
}
static inline void gen_movl_T0_reg(int reg)
{
gen_movl_TN_reg(reg, 0);
}
static inline void gen_movl_T1_reg(int reg)
{
gen_movl_TN_reg(reg, 1);
}
static void gen_cond(int cond)
{
switch (cond) {
case 0x0:
gen_op_movl_T2_0();
break;
case 0x1:
gen_op_eval_be();
break;
case 0x2:
gen_op_eval_ble();
break;
case 0x3:
gen_op_eval_bl();
break;
case 0x4:
gen_op_eval_bleu();
break;
case 0x5:
gen_op_eval_bcs();
break;
case 0x6:
gen_op_eval_bneg();
break;
case 0x7:
gen_op_eval_bvs();
break;
case 0x8:
gen_op_movl_T2_1();
break;
case 0x9:
gen_op_eval_bne();
break;
case 0xa:
gen_op_eval_bg();
break;
case 0xb:
gen_op_eval_bge();
break;
case 0xc:
gen_op_eval_bgu();
break;
case 0xd:
gen_op_eval_bcc();
break;
case 0xe:
gen_op_eval_bpos();
break;
default:
case 0xf:
gen_op_eval_bvc();
break;
}
}
static void do_branch(DisasContext * dc, uint32_t target, uint32_t insn)
{
unsigned int cond = GET_FIELD(insn, 3, 6), a = (insn & (1 << 29));
target += (uint32_t) dc->pc;
if (cond == 0x0) {
/* unconditional not taken */
if (a) {
dc->pc = dc->npc + 4;
dc->npc = dc->pc + 4;
} else {
dc->pc = dc->npc;
dc->npc = dc->pc + 4;
}
} else if (cond == 0x8) {
/* unconditional taken */
if (a) {
dc->pc = (uint8_t *) target;
dc->npc = dc->pc + 4;
} else {
dc->pc = dc->npc;
dc->npc = (uint8_t *) target;
}
} else {
gen_cond(cond);
if (a) {
gen_op_generic_branch_a((uint32_t) target,
(uint32_t) (dc->npc));
dc->is_br = 1;
dc->pc = NULL;
dc->npc = NULL;
} else {
dc->pc = dc->npc;
gen_op_generic_branch((uint32_t) target,
(uint32_t) (dc->npc + 4));
dc->npc = NULL;
}
}
}
#define GET_FIELDs(x,a,b) sign_extend (GET_FIELD(x,a,b), (b) - (a) + 1)
static int sign_extend(int x, int len)
{
len = 32 - len;
return (x << len) >> len;
}
static inline void save_state(DisasContext * dc)
{
gen_op_jmp_im((uint32_t)dc->pc);
if (dc->npc != NULL)
gen_op_movl_npc_im((long) dc->npc);
}
static void disas_sparc_insn(DisasContext * dc)
{
unsigned int insn, opc, rs1, rs2, rd;
insn = ldl_code(dc->pc);
opc = GET_FIELD(insn, 0, 1);
rd = GET_FIELD(insn, 2, 6);
switch (opc) {
case 0: /* branches/sethi */
{
unsigned int xop = GET_FIELD(insn, 7, 9);
int target;
target = GET_FIELD(insn, 10, 31);
switch (xop) {
case 0x0:
case 0x1: /* UNIMPL */
goto illegal_insn;
case 0x2: /* BN+x */
{
target <<= 2;
target = sign_extend(target, 22);
do_branch(dc, target, insn);
goto jmp_insn;
}
case 0x3: /* FBN+x */
break;
case 0x4: /* SETHI */
gen_movl_imm_T0(target << 10);
gen_movl_T0_reg(rd);
break;
case 0x5: /*CBN+x */
break;
}
break;
}
case 1:
/*CALL*/ {
unsigned int target = GET_FIELDs(insn, 2, 31) << 2;
gen_op_movl_T0_im((long) (dc->pc));
gen_movl_T0_reg(15);
target = (long) dc->pc + target;
dc->pc = dc->npc;
dc->npc = (uint8_t *) target;
}
goto jmp_insn;
case 2: /* FPU & Logical Operations */
{
unsigned int xop = GET_FIELD(insn, 7, 12);
if (xop == 0x3a) { /* generate trap */
int cond;
rs1 = GET_FIELD(insn, 13, 17);
gen_movl_reg_T0(rs1);
if (IS_IMM) {
gen_movl_imm_T1(GET_FIELD(insn, 25, 31));
} else {
rs2 = GET_FIELD(insn, 27, 31);
gen_movl_reg_T1(rs2);
}
gen_op_add_T1_T0();
save_state(dc);
cond = GET_FIELD(insn, 3, 6);
if (cond == 0x8) {
gen_op_trap_T0();
dc->is_br = 1;
goto jmp_insn;
} else {
gen_op_trapcc_T0();
}
} else if (xop == 0x28) {
rs1 = GET_FIELD(insn, 13, 17);
switch(rs1) {
case 0: /* rdy */
gen_op_rdy();
gen_movl_T0_reg(rd);
break;
default:
goto illegal_insn;
}
} else if (xop == 0x34 || xop == 0x35) { /* FPU Operations */
goto illegal_insn;
} else {
rs1 = GET_FIELD(insn, 13, 17);
gen_movl_reg_T0(rs1);
if (IS_IMM) { /* immediate */
rs2 = GET_FIELDs(insn, 19, 31);
gen_movl_imm_T1(rs2);
} else { /* register */
rs2 = GET_FIELD(insn, 27, 31);
gen_movl_reg_T1(rs2);
}
if (xop < 0x20) {
switch (xop & ~0x10) {
case 0x0:
if (xop & 0x10)
gen_op_add_T1_T0_cc();
else
gen_op_add_T1_T0();
break;
case 0x1:
gen_op_and_T1_T0();
if (xop & 0x10)
gen_op_logic_T0_cc();
break;
case 0x2:
gen_op_or_T1_T0();
if (xop & 0x10)
gen_op_logic_T0_cc();
break;
case 0x3:
gen_op_xor_T1_T0();
if (xop & 0x10)
gen_op_logic_T0_cc();
break;
case 0x4:
if (xop & 0x10)
gen_op_sub_T1_T0_cc();
else
gen_op_sub_T1_T0();
break;
case 0x5:
gen_op_andn_T1_T0();
if (xop & 0x10)
gen_op_logic_T0_cc();
break;
case 0x6:
gen_op_orn_T1_T0();
if (xop & 0x10)
gen_op_logic_T0_cc();
break;
case 0x7:
gen_op_xnor_T1_T0();
if (xop & 0x10)
gen_op_logic_T0_cc();
break;
case 0x8:
gen_op_addx_T1_T0();
if (xop & 0x10)
gen_op_set_flags();
break;
case 0xa:
gen_op_umul_T1_T0();
if (xop & 0x10)
gen_op_logic_T0_cc();
break;
case 0xb:
gen_op_smul_T1_T0();
if (xop & 0x10)
gen_op_logic_T0_cc();
break;
case 0xc:
gen_op_subx_T1_T0();
if (xop & 0x10)
gen_op_set_flags();
break;
case 0xe:
gen_op_udiv_T1_T0();
if (xop & 0x10)
gen_op_div_cc();
break;
case 0xf:
gen_op_sdiv_T1_T0();
if (xop & 0x10)
gen_op_div_cc();
break;
default:
goto illegal_insn;
}
gen_movl_T0_reg(rd);
} else {
switch (xop) {
case 0x24: /* mulscc */
gen_op_mulscc_T1_T0();
gen_movl_T0_reg(rd);
break;
case 0x25: /* SLL */
gen_op_sll();
gen_movl_T0_reg(rd);
break;
case 0x26:
gen_op_srl();
gen_movl_T0_reg(rd);
break;
case 0x27:
gen_op_sra();
gen_movl_T0_reg(rd);
break;
case 0x30:
{
gen_op_xor_T1_T0();
switch(rd) {
case 0:
gen_op_wry();
break;
default:
goto illegal_insn;
}
}
break;
case 0x38: /* jmpl */
{
gen_op_add_T1_T0();
gen_op_movl_npc_T0();
if (rd != 0) {
gen_op_movl_T0_im((long) (dc->pc));
gen_movl_T0_reg(rd);
}
dc->pc = dc->npc;
dc->npc = NULL;
}
goto jmp_insn;
case 0x3b: /* flush */
/* nothing to do */
break;
case 0x3c: /* save */
save_state(dc);
gen_op_add_T1_T0();
gen_op_save();
gen_movl_T0_reg(rd);
break;
case 0x3d: /* restore */
save_state(dc);
gen_op_add_T1_T0();
gen_op_restore();
gen_movl_T0_reg(rd);
break;
default:
goto illegal_insn;
}
}
}
break;
}
case 3: /* load/store instructions */
{
unsigned int xop = GET_FIELD(insn, 7, 12);
rs1 = GET_FIELD(insn, 13, 17);
gen_movl_reg_T0(rs1);
if (IS_IMM) { /* immediate */
rs2 = GET_FIELDs(insn, 19, 31);
gen_movl_imm_T1(rs2);
} else { /* register */
rs2 = GET_FIELD(insn, 27, 31);
gen_movl_reg_T1(rs2);
}
gen_op_add_T1_T0();
if (xop < 4 || xop > 7) {
switch (xop) {
case 0x0: /* load word */
gen_op_ld();
break;
case 0x1: /* load unsigned byte */
gen_op_ldub();
break;
case 0x2: /* load unsigned halfword */
gen_op_lduh();
break;
case 0x3: /* load double word */
gen_op_ldd();
gen_movl_T0_reg(rd + 1);
break;
case 0x9: /* load signed byte */
gen_op_ldsb();
break;
case 0xa: /* load signed halfword */
gen_op_ldsh();
break;
case 0xd: /* ldstub -- XXX: should be atomically */
gen_op_ldstub();
break;
case 0x0f: /* swap register with memory. Also atomically */
gen_op_swap();
break;
}
gen_movl_T1_reg(rd);
} else if (xop < 8) {
gen_movl_reg_T1(rd);
switch (xop) {
case 0x4:
gen_op_st();
break;
case 0x5:
gen_op_stb();
break;
case 0x6:
gen_op_sth();
break;
case 0x7:
gen_movl_reg_T2(rd + 1);
gen_op_std();
break;
}
}
}
}
/* default case for non jump instructions */
if (dc->npc != NULL) {
dc->pc = dc->npc;
dc->npc = dc->npc + 4;
} else {
dc->pc = NULL;
gen_op_next_insn();
}
jmp_insn:;
return;
illegal_insn:
gen_op_jmp_im((uint32_t)dc->pc);
if (dc->npc != NULL)
gen_op_movl_npc_im((long) dc->npc);
gen_op_exception(TT_ILL_INSN);
dc->is_br = 1;
}
static inline int gen_intermediate_code_internal(TranslationBlock * tb,
int spc)
{
uint8_t *pc_start, *last_pc;
uint16_t *gen_opc_end;
DisasContext dc1, *dc = &dc1;
memset(dc, 0, sizeof(DisasContext));
if (spc) {
printf("SearchPC not yet supported\n");
exit(0);
}
dc->tb = tb;
pc_start = (uint8_t *) tb->pc;
dc->pc = pc_start;
dc->npc = (uint8_t *) tb->cs_base;
gen_opc_ptr = gen_opc_buf;
gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
gen_opparam_ptr = gen_opparam_buf;
do {
last_pc = dc->pc;
disas_sparc_insn(dc);
if (dc->is_br)
break;
/* if the next PC is different, we abort now */
if (dc->pc != (last_pc + 4))
break;
} while ((gen_opc_ptr < gen_opc_end) &&
(dc->pc - pc_start) < (TARGET_PAGE_SIZE - 32));
if (dc->pc != NULL)
gen_op_jmp_im((long) dc->pc);
if (dc->npc != NULL)
gen_op_movl_npc_im((long) dc->npc);
gen_op_movl_T0_0();
gen_op_exit_tb();
*gen_opc_ptr = INDEX_op_end;
#ifdef DEBUG_DISAS
if (loglevel) {
fprintf(logfile, "--------------\n");
fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start));
disas(logfile, pc_start, last_pc + 4 - pc_start, 0, 0);
fprintf(logfile, "\n");
fprintf(logfile, "OP:\n");
dump_ops(gen_opc_buf, gen_opparam_buf);
fprintf(logfile, "\n");
}
#endif
return 0;
}
int gen_intermediate_code(CPUSPARCState * env, TranslationBlock * tb)
{
return gen_intermediate_code_internal(tb, 0);
}
int gen_intermediate_code_pc(CPUSPARCState * env, TranslationBlock * tb)
{
return gen_intermediate_code_internal(tb, 1);
}
CPUSPARCState *cpu_sparc_init(void)
{
CPUSPARCState *env;
cpu_exec_init();
if (!(env = malloc(sizeof(CPUSPARCState))))
return (NULL);
memset(env, 0, sizeof(*env));
env->cwp = 0;
env->wim = 1;
env->regwptr = env->regbase + (env->cwp * 16);
env->user_mode_only = 1;
return (env);
}
#define GET_FLAG(a,b) ((env->psr & a)?b:'-')
void cpu_sparc_dump_state(CPUSPARCState * env, FILE * f, int flags)
{
int i, x;
fprintf(f, "pc: 0x%08x npc: 0x%08x\n", (int) env->pc, (int) env->npc);
fprintf(f, "General Registers:\n");
for (i = 0; i < 4; i++)
fprintf(f, "%%g%c: 0x%08x\t", i + '0', env->gregs[i]);
fprintf(f, "\n");
for (; i < 8; i++)
fprintf(f, "%%g%c: 0x%08x\t", i + '0', env->gregs[i]);
fprintf(f, "\nCurrent Register Window:\n");
for (x = 0; x < 3; x++) {
for (i = 0; i < 4; i++)
fprintf(f, "%%%c%d: 0x%08x\t",
(x == 0 ? 'o' : (x == 1 ? 'l' : 'i')), i,
env->regwptr[i + x * 8]);
fprintf(f, "\n");
for (; i < 8; i++)
fprintf(f, "%%%c%d: 0x%08x\t",
(x == 0 ? 'o' : x == 1 ? 'l' : 'i'), i,
env->regwptr[i + x * 8]);
fprintf(f, "\n");
}
fprintf(f, "psr: 0x%08x -> %c%c%c%c wim: 0x%08x\n", env->psr | env->cwp,
GET_FLAG(PSR_ZERO, 'Z'), GET_FLAG(PSR_OVF, 'V'),
GET_FLAG(PSR_NEG, 'N'), GET_FLAG(PSR_CARRY, 'C'),
env->wim);
}

View File

@@ -1,14 +1,15 @@
include ../config.mak
include ../config-host.mak
CFLAGS=-Wall -O2 -g
LDFLAGS=
ifeq ($(ARCH),i386)
TESTS=testclone testsig testthread sha1-i386 test-i386 runcom
TESTS=linux-test testthread sha1-i386 test-i386 runcom
endif
TESTS+=sha1 test_path
TESTS+=sha1# test_path
#TESTS+=test_path
QEMU=../qemu
QEMU=../i386-user/qemu-i386
all: $(TESTS)
@@ -16,12 +17,6 @@ hello-i386: hello-i386.c
$(CC) -nostdlib $(CFLAGS) -static $(LDFLAGS) -o $@ $<
strip $@
testclone: testclone.c
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $<
testsig: testsig.c
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $<
testthread: testthread.c
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< -lpthread
@@ -32,7 +27,7 @@ test_path: test_path.c
# i386 emulation test (test various opcodes) */
test-i386: test-i386.c test-i386-code16.S test-i386-vm86.S \
test-i386.h test-i386-shift.h test-i386-muldiv.h
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ test-i386.c \
$(CC) $(CFLAGS) $(LDFLAGS) -static -o $@ test-i386.c \
test-i386-code16.S test-i386-vm86.S -lm
ifeq ($(ARCH),i386)
@@ -44,6 +39,10 @@ endif
$(QEMU) test-i386 > test-i386.out
@if diff -u test-i386.ref test-i386.out ; then echo "Auto Test OK"; fi
# generic Linux and CPU test
linux-test: linux-test.c
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< -lm
# speed test
sha1-i386: sha1.c
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $<
@@ -66,5 +65,11 @@ hello-arm: hello-arm.o
hello-arm.o: hello-arm.c
arm-linux-gcc -Wall -g -O2 -c -o $@ $<
# XXX: find a way to compile easily a test for each arch
test2:
@for arch in i386 arm sparc ppc; do \
../$${arch}-user/qemu-$${arch} $${arch}/ls -l linux-test.c ; \
done
clean:
rm -f *~ *.o $(TESTS)

509
tests/linux-test.c Normal file
View File

@@ -0,0 +1,509 @@
/*
* linux and CPU test
*
* 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 <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <inttypes.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <errno.h>
#include <utime.h>
#include <time.h>
#include <sys/time.h>
#include <sys/uio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sched.h>
#include <dirent.h>
#include <setjmp.h>
#define TESTPATH "/tmp/linux-test.tmp"
#define TESTPORT 7654
#define STACK_SIZE 16384
void error1(const char *filename, int line, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
fprintf(stderr, "%s:%d: ", filename, line);
vfprintf(stderr, fmt, ap);
fprintf(stderr, "\n");
va_end(ap);
exit(1);
}
int __chk_error(const char *filename, int line, int ret)
{
if (ret < 0) {
error1(filename, line, "%m (ret=%d, errno=%d)",
ret, errno);
}
return ret;
}
#define error(fmt, args...) error1(__FILE__, __LINE__, fmt, ##args)
#define chk_error(ret) __chk_error(__FILE__, __LINE__, (ret))
/*******************************************************/
#define FILE_BUF_SIZE 300
void test_file(void)
{
int fd, i, len, ret;
uint8_t buf[FILE_BUF_SIZE];
uint8_t buf2[FILE_BUF_SIZE];
uint8_t buf3[FILE_BUF_SIZE];
char cur_dir[1024];
struct stat st;
struct utimbuf tbuf;
struct iovec vecs[2];
DIR *dir;
struct dirent *de;
/* clean up, just in case */
unlink(TESTPATH "/file1");
unlink(TESTPATH "/file2");
unlink(TESTPATH "/file3");
rmdir(TESTPATH);
if (getcwd(cur_dir, sizeof(cur_dir)) == NULL)
error("getcwd");
chk_error(mkdir(TESTPATH, 0755));
chk_error(chdir(TESTPATH));
/* open/read/write/close/readv/writev/lseek */
fd = chk_error(open("file1", O_WRONLY | O_TRUNC | O_CREAT, 0644));
for(i=0;i < FILE_BUF_SIZE; i++)
buf[i] = i;
len = chk_error(write(fd, buf, FILE_BUF_SIZE / 2));
if (len != (FILE_BUF_SIZE / 2))
error("write");
vecs[0].iov_base = buf + (FILE_BUF_SIZE / 2);
vecs[0].iov_len = 16;
vecs[1].iov_base = buf + (FILE_BUF_SIZE / 2) + 16;
vecs[1].iov_len = (FILE_BUF_SIZE / 2) - 16;
len = chk_error(writev(fd, vecs, 2));
if (len != (FILE_BUF_SIZE / 2))
error("writev");
chk_error(close(fd));
chk_error(rename("file1", "file2"));
fd = chk_error(open("file2", O_RDONLY));
len = chk_error(read(fd, buf2, FILE_BUF_SIZE));
if (len != FILE_BUF_SIZE)
error("read");
if (memcmp(buf, buf2, FILE_BUF_SIZE) != 0)
error("memcmp");
#define FOFFSET 16
ret = chk_error(lseek(fd, FOFFSET, SEEK_SET));
if (ret != 16)
error("lseek");
vecs[0].iov_base = buf3;
vecs[0].iov_len = 32;
vecs[1].iov_base = buf3 + 32;
vecs[1].iov_len = FILE_BUF_SIZE - FOFFSET - 32;
len = chk_error(readv(fd, vecs, 2));
if (len != FILE_BUF_SIZE - FOFFSET)
error("readv");
if (memcmp(buf + FOFFSET, buf3, FILE_BUF_SIZE - FOFFSET) != 0)
error("memcmp");
chk_error(close(fd));
/* access */
chk_error(access("file2", R_OK));
/* stat/chmod/utime/truncate */
chk_error(chmod("file2", 0600));
tbuf.actime = 1001;
tbuf.modtime = 1000;
chk_error(truncate("file2", 100));
chk_error(utime("file2", &tbuf));
chk_error(stat("file2", &st));
if (st.st_size != 100)
error("stat size");
if (!S_ISREG(st.st_mode))
error("stat mode");
if ((st.st_mode & 0777) != 0600)
error("stat mode2");
if (st.st_atime != 1001 ||
st.st_mtime != 1000)
error("stat time");
chk_error(stat(TESTPATH, &st));
if (!S_ISDIR(st.st_mode))
error("stat mode");
/* fstat */
fd = chk_error(open("file2", O_RDWR));
chk_error(ftruncate(fd, 50));
chk_error(fstat(fd, &st));
chk_error(close(fd));
if (st.st_size != 50)
error("stat size");
if (!S_ISREG(st.st_mode))
error("stat mode");
/* symlink/lstat */
chk_error(symlink("file2", "file3"));
chk_error(lstat("file3", &st));
if (!S_ISLNK(st.st_mode))
error("stat mode");
/* getdents */
dir = opendir(TESTPATH);
if (!dir)
error("opendir");
len = 0;
for(;;) {
de = readdir(dir);
if (!de)
break;
if (strcmp(de->d_name, ".") != 0 &&
strcmp(de->d_name, "..") != 0 &&
strcmp(de->d_name, "file2") != 0 &&
strcmp(de->d_name, "file3") != 0)
error("readdir");
len++;
}
closedir(dir);
if (len != 4)
error("readdir");
chk_error(unlink("file3"));
chk_error(unlink("file2"));
chk_error(chdir(cur_dir));
chk_error(rmdir(TESTPATH));
}
void test_fork(void)
{
int pid, status;
pid = chk_error(fork());
if (pid == 0) {
/* child */
exit(2);
}
chk_error(waitpid(pid, &status, 0));
if (!WIFEXITED(status) || WEXITSTATUS(status) != 2)
error("waitpid status=0x%x", status);
}
void test_time(void)
{
struct timeval tv, tv2;
struct timespec ts, rem;
struct rusage rusg1, rusg2;
int ti, i;
chk_error(gettimeofday(&tv, NULL));
rem.tv_sec = 1;
ts.tv_sec = 0;
ts.tv_nsec = 20 * 1000000;
chk_error(nanosleep(&ts, &rem));
if (rem.tv_sec != 1)
error("nanosleep");
chk_error(gettimeofday(&tv2, NULL));
ti = tv2.tv_sec - tv.tv_sec;
if (ti >= 2)
error("gettimeofday");
chk_error(getrusage(RUSAGE_SELF, &rusg1));
for(i = 0;i < 10000; i++);
chk_error(getrusage(RUSAGE_SELF, &rusg2));
if ((rusg2.ru_utime.tv_sec - rusg1.ru_utime.tv_sec) < 0 ||
(rusg2.ru_stime.tv_sec - rusg1.ru_stime.tv_sec) < 0)
error("getrusage");
}
void pstrcpy(char *buf, int buf_size, const char *str)
{
int c;
char *q = buf;
if (buf_size <= 0)
return;
for(;;) {
c = *str++;
if (c == 0 || q >= buf + buf_size - 1)
break;
*q++ = c;
}
*q = '\0';
}
/* strcat and truncate. */
char *pstrcat(char *buf, int buf_size, const char *s)
{
int len;
len = strlen(buf);
if (len < buf_size)
pstrcpy(buf + len, buf_size - len, s);
return buf;
}
int server_socket(void)
{
int val, fd;
struct sockaddr_in sockaddr;
/* server socket */
fd = chk_error(socket(PF_INET, SOCK_STREAM, 0));
val = 1;
chk_error(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)));
sockaddr.sin_family = AF_INET;
sockaddr.sin_port = htons(TESTPORT);
sockaddr.sin_addr.s_addr = 0;
chk_error(bind(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr)));
chk_error(listen(fd, 0));
return fd;
}
int client_socket(void)
{
int fd;
struct sockaddr_in sockaddr;
/* server socket */
fd = chk_error(socket(PF_INET, SOCK_STREAM, 0));
sockaddr.sin_family = AF_INET;
sockaddr.sin_port = htons(TESTPORT);
inet_aton("127.0.0.1", &sockaddr.sin_addr);
chk_error(connect(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr)));
return fd;
}
const char socket_msg[] = "hello socket\n";
void test_socket(void)
{
int server_fd, client_fd, fd, pid, ret;
struct sockaddr_in sockaddr;
socklen_t len;
char buf[512];
server_fd = server_socket();
pid = chk_error(fork());
if (pid == 0) {
client_fd = client_socket();
send(client_fd, socket_msg, sizeof(socket_msg), 0);
close(client_fd);
exit(0);
}
len = sizeof(sockaddr);
fd = chk_error(accept(server_fd, (struct sockaddr *)&sockaddr, &len));
ret = chk_error(recv(fd, buf, sizeof(buf), 0));
if (ret != sizeof(socket_msg))
error("recv");
if (memcmp(buf, socket_msg, sizeof(socket_msg)) != 0)
error("socket_msg");
chk_error(close(fd));
chk_error(close(server_fd));
}
#define WCOUNT_MAX 512
void test_pipe(void)
{
fd_set rfds, wfds;
int fds[2], fd_max, ret;
uint8_t ch;
int wcount, rcount;
chk_error(pipe(fds));
chk_error(fcntl(fds[0], F_SETFL, O_NONBLOCK));
chk_error(fcntl(fds[1], F_SETFL, O_NONBLOCK));
wcount = 0;
rcount = 0;
for(;;) {
FD_ZERO(&rfds);
fd_max = fds[0];
FD_SET(fds[0], &rfds);
FD_ZERO(&wfds);
FD_SET(fds[1], &wfds);
if (fds[1] > fd_max)
fd_max = fds[1];
ret = chk_error(select(fd_max + 1, &rfds, &wfds, NULL, NULL));
if (ret > 0) {
if (FD_ISSET(fds[0], &rfds)) {
chk_error(read(fds[0], &ch, 1));
rcount++;
if (rcount >= WCOUNT_MAX)
break;
}
if (FD_ISSET(fds[1], &wfds)) {
ch = 'a';
chk_error(write(fds[0], &ch, 1));
wcount++;
}
}
}
chk_error(close(fds[0]));
chk_error(close(fds[1]));
}
int thread1_res;
int thread2_res;
int thread1_func(void *arg)
{
int i;
for(i=0;i<5;i++) {
thread1_res++;
usleep(10 * 1000);
}
return 0;
}
int thread2_func(void *arg)
{
int i;
for(i=0;i<6;i++) {
thread2_res++;
usleep(10 * 1000);
}
return 0;
}
void test_clone(void)
{
uint8_t *stack1, *stack2;
int pid1, pid2, status1, status2;
stack1 = malloc(STACK_SIZE);
pid1 = chk_error(clone(thread1_func, stack1 + STACK_SIZE,
CLONE_VM | CLONE_FS | CLONE_FILES | SIGCHLD, "hello1"));
stack2 = malloc(STACK_SIZE);
pid2 = chk_error(clone(thread2_func, stack2 + STACK_SIZE,
CLONE_VM | CLONE_FS | CLONE_FILES | SIGCHLD, "hello2"));
while (waitpid(pid1, &status1, 0) != pid1);
while (waitpid(pid2, &status2, 0) != pid2);
if (thread1_res != 5 ||
thread2_res != 6)
error("clone");
}
/***********************************/
volatile int alarm_count;
jmp_buf jmp_env;
void sig_alarm(int sig)
{
if (sig != SIGALRM)
error("signal");
alarm_count++;
}
void sig_segv(int sig, siginfo_t *info, void *puc)
{
if (sig != SIGSEGV)
error("signal");
longjmp(jmp_env, 1);
}
void test_signal(void)
{
struct sigaction act;
struct itimerval it, oit;
/* timer test */
alarm_count = 0;
act.sa_handler = sig_alarm;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
chk_error(sigaction(SIGALRM, &act, NULL));
it.it_interval.tv_sec = 0;
it.it_interval.tv_usec = 10 * 1000;
it.it_value.tv_sec = 0;
it.it_value.tv_usec = 10 * 1000;
chk_error(setitimer(ITIMER_REAL, &it, NULL));
chk_error(getitimer(ITIMER_REAL, &oit));
if (oit.it_value.tv_sec != it.it_value.tv_sec ||
oit.it_value.tv_usec != it.it_value.tv_usec)
error("itimer");
while (alarm_count < 5) {
usleep(10 * 1000);
}
it.it_interval.tv_sec = 0;
it.it_interval.tv_usec = 0;
it.it_value.tv_sec = 0;
it.it_value.tv_usec = 0;
memset(&oit, 0xff, sizeof(oit));
chk_error(setitimer(ITIMER_REAL, &it, &oit));
if (oit.it_value.tv_sec != 0 ||
oit.it_value.tv_usec != 10 * 1000)
error("setitimer");
/* SIGSEGV test */
act.sa_sigaction = sig_segv;
sigemptyset(&act.sa_mask);
act.sa_flags = SA_SIGINFO;
chk_error(sigaction(SIGSEGV, &act, NULL));
if (setjmp(jmp_env) == 0) {
*(uint8_t *)0 = 0;
}
act.sa_handler = SIG_DFL;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
chk_error(sigaction(SIGSEGV, &act, NULL));
}
int main(int argc, char **argv)
{
test_file();
test_fork();
test_time();
test_socket();
test_clone();
test_signal();
return 0;
}

242
tests/sha1.c Normal file
View File

@@ -0,0 +1,242 @@
/* from valgrind tests */
/* ================ sha1.c ================ */
/*
SHA-1 in C
By Steve Reid <steve@edmweb.com>
100% Public Domain
Test Vectors (from FIPS PUB 180-1)
"abc"
A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D
"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1
A million repetitions of "a"
34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F
*/
/* #define LITTLE_ENDIAN * This should be #define'd already, if true. */
/* #define SHA1HANDSOFF * Copies data before messing with it. */
#define SHA1HANDSOFF
#include <stdio.h>
#include <string.h>
#include <sys/types.h> /* for u_int*_t */
/* ================ sha1.h ================ */
/*
SHA-1 in C
By Steve Reid <steve@edmweb.com>
100% Public Domain
*/
typedef struct {
u_int32_t state[5];
u_int32_t count[2];
unsigned char buffer[64];
} SHA1_CTX;
void SHA1Transform(u_int32_t state[5], const unsigned char buffer[64]);
void SHA1Init(SHA1_CTX* context);
void SHA1Update(SHA1_CTX* context, const unsigned char* data, u_int32_t len);
void SHA1Final(unsigned char digest[20], SHA1_CTX* context);
/* ================ end of sha1.h ================ */
#include <endian.h>
#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
/* blk0() and blk() perform the initial expand. */
/* I got the idea of expanding during the round function from SSLeay */
#if BYTE_ORDER == LITTLE_ENDIAN
#define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) \
|(rol(block->l[i],8)&0x00FF00FF))
#elif BYTE_ORDER == BIG_ENDIAN
#define blk0(i) block->l[i]
#else
#error "Endianness not defined!"
#endif
#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \
^block->l[(i+2)&15]^block->l[i&15],1))
/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */
#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30);
#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30);
#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30);
#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30);
#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);
/* Hash a single 512-bit block. This is the core of the algorithm. */
void SHA1Transform(u_int32_t state[5], const unsigned char buffer[64])
{
u_int32_t a, b, c, d, e;
typedef union {
unsigned char c[64];
u_int32_t l[16];
} CHAR64LONG16;
#ifdef SHA1HANDSOFF
CHAR64LONG16 block[1]; /* use array to appear as a pointer */
memcpy(block, buffer, 64);
#else
/* The following had better never be used because it causes the
* pointer-to-const buffer to be cast into a pointer to non-const.
* And the result is written through. I threw a "const" in, hoping
* this will cause a diagnostic.
*/
CHAR64LONG16* block = (const CHAR64LONG16*)buffer;
#endif
/* Copy context->state[] to working vars */
a = state[0];
b = state[1];
c = state[2];
d = state[3];
e = state[4];
/* 4 rounds of 20 operations each. Loop unrolled. */
R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3);
R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7);
R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11);
R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15);
R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19);
R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23);
R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27);
R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31);
R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35);
R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39);
R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43);
R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47);
R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51);
R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55);
R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59);
R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63);
R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67);
R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71);
R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75);
R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79);
/* Add the working vars back into context.state[] */
state[0] += a;
state[1] += b;
state[2] += c;
state[3] += d;
state[4] += e;
/* Wipe variables */
a = b = c = d = e = 0;
#ifdef SHA1HANDSOFF
memset(block, '\0', sizeof(block));
#endif
}
/* SHA1Init - Initialize new context */
void SHA1Init(SHA1_CTX* context)
{
/* SHA1 initialization constants */
context->state[0] = 0x67452301;
context->state[1] = 0xEFCDAB89;
context->state[2] = 0x98BADCFE;
context->state[3] = 0x10325476;
context->state[4] = 0xC3D2E1F0;
context->count[0] = context->count[1] = 0;
}
/* Run your data through this. */
void SHA1Update(SHA1_CTX* context, const unsigned char* data, u_int32_t len)
{
u_int32_t i;
u_int32_t j;
j = context->count[0];
if ((context->count[0] += len << 3) < j)
context->count[1]++;
context->count[1] += (len>>29);
j = (j >> 3) & 63;
if ((j + len) > 63) {
memcpy(&context->buffer[j], data, (i = 64-j));
SHA1Transform(context->state, context->buffer);
for ( ; i + 63 < len; i += 64) {
SHA1Transform(context->state, &data[i]);
}
j = 0;
}
else i = 0;
memcpy(&context->buffer[j], &data[i], len - i);
}
/* Add padding and return the message digest. */
void SHA1Final(unsigned char digest[20], SHA1_CTX* context)
{
unsigned i;
unsigned char finalcount[8];
unsigned char c;
#if 0 /* untested "improvement" by DHR */
/* Convert context->count to a sequence of bytes
* in finalcount. Second element first, but
* big-endian order within element.
* But we do it all backwards.
*/
unsigned char *fcp = &finalcount[8];
for (i = 0; i < 2; i++)
{
u_int32_t t = context->count[i];
int j;
for (j = 0; j < 4; t >>= 8, j++)
*--fcp = (unsigned char) t
}
#else
for (i = 0; i < 8; i++) {
finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)]
>> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */
}
#endif
c = 0200;
SHA1Update(context, &c, 1);
while ((context->count[0] & 504) != 448) {
c = 0000;
SHA1Update(context, &c, 1);
}
SHA1Update(context, finalcount, 8); /* Should cause a SHA1Transform() */
for (i = 0; i < 20; i++) {
digest[i] = (unsigned char)
((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255);
}
/* Wipe variables */
memset(context, '\0', sizeof(*context));
memset(&finalcount, '\0', sizeof(finalcount));
}
/* ================ end of sha1.c ================ */
#define BUFSIZE 4096
int
main(int argc, char **argv)
{
SHA1_CTX ctx;
unsigned char hash[20], buf[BUFSIZE];
int i;
for(i=0;i<BUFSIZE;i++)
buf[i] = i;
SHA1Init(&ctx);
for(i=0;i<1000;i++)
SHA1Update(&ctx, buf, BUFSIZE);
SHA1Final(hash, &ctx);
printf("SHA1=");
for(i=0;i<20;i++)
printf("%02x", hash[i]);
printf("\n");
return 0;
}

View File

@@ -1,3 +1,22 @@
/*
* x86 CPU test
*
* 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.
*/
#define _GNU_SOURCE
#include <stdlib.h>
#include <stdio.h>
@@ -6,12 +25,15 @@
#include <math.h>
#include <signal.h>
#include <setjmp.h>
#include <errno.h>
#include <sys/ucontext.h>
#include <sys/mman.h>
#include <asm/vm86.h>
#define TEST_CMOV 0
#define TEST_FCOMI 0
//#define LINUX_VM86_IOPL_FIX
//#define TEST_P4_FLAGS
#define xglue(x, y) x ## y
#define glue(x, y) xglue(x, y)
@@ -331,7 +353,11 @@ void test_jcc(void)
}
#undef CC_MASK
#ifdef TEST_P4_FLAGS
#define CC_MASK (CC_C | CC_P | CC_Z | CC_S | CC_O | CC_A)
#else
#define CC_MASK (CC_O | CC_C)
#endif
#define OP mul
#include "test-i386-muldiv.h"
@@ -339,15 +365,6 @@ void test_jcc(void)
#define OP imul
#include "test-i386-muldiv.h"
#undef CC_MASK
#define CC_MASK (0)
#define OP div
#include "test-i386-muldiv.h"
#define OP idiv
#include "test-i386-muldiv.h"
void test_imulw2(int op0, int op1)
{
int res, s1, s0, flags;
@@ -384,6 +401,15 @@ void test_imull2(int op0, int op1)
"imull", s0, s1, res, flags & CC_MASK);
}
#undef CC_MASK
#define CC_MASK (0)
#define OP div
#include "test-i386-muldiv.h"
#define OP idiv
#include "test-i386-muldiv.h"
void test_mul(void)
{
test_imulb(0x1234561d, 4);
@@ -637,6 +663,45 @@ void test_fenv(void)
TEST_ENV(&float_env32, "");
}
#define TEST_FCMOV(a, b, eflags, CC)\
{\
double res;\
asm("push %3\n"\
"popf\n"\
"fcmov" CC " %2, %0\n"\
: "=t" (res)\
: "0" (a), "u" (b), "g" (eflags));\
printf("fcmov%s eflags=0x%04x-> %f\n", \
CC, eflags, res);\
}
void test_fcmov(void)
{
double a, b;
int eflags, i;
a = 1.0;
b = 2.0;
for(i = 0; i < 4; i++) {
eflags = 0;
if (i & 1)
eflags |= CC_C;
if (i & 2)
eflags |= CC_Z;
TEST_FCMOV(a, b, eflags, "b");
TEST_FCMOV(a, b, eflags, "e");
TEST_FCMOV(a, b, eflags, "be");
TEST_FCMOV(a, b, eflags, "nb");
TEST_FCMOV(a, b, eflags, "ne");
TEST_FCMOV(a, b, eflags, "nbe");
}
TEST_FCMOV(a, b, 0, "u");
TEST_FCMOV(a, b, CC_P, "u");
TEST_FCMOV(a, b, 0, "nu");
TEST_FCMOV(a, b, CC_P, "nu");
}
void test_floats(void)
{
test_fops(2, 3);
@@ -654,6 +719,9 @@ void test_floats(void)
test_fbcd(1234567890123456);
test_fbcd(-123451234567890);
test_fenv();
if (TEST_CMOV) {
test_fcmov();
}
}
/**********************************************/
@@ -855,7 +923,6 @@ void test_segs(void)
#endif
/* do some tests with fs or gs */
asm volatile ("movl %0, %%fs" : : "r" (MK_SEL(1)));
asm volatile ("movl %0, %%gs" : : "r" (MK_SEL(2)));
seg_data1[1] = 0xaa;
seg_data2[1] = 0x55;
@@ -863,7 +930,12 @@ void test_segs(void)
asm volatile ("fs movzbl 0x1, %0" : "=r" (res));
printf("FS[1] = %02x\n", res);
asm volatile ("gs movzbl 0x1, %0" : "=r" (res));
asm volatile ("pushl %%gs\n"
"movl %1, %%gs\n"
"gs movzbl 0x1, %0\n"
"popl %%gs\n"
: "=r" (res)
: "r" (MK_SEL(2)));
printf("GS[1] = %02x\n", res);
/* tests with ds/ss (implicit segment case) */
@@ -965,6 +1037,11 @@ void test_misc(void)
asm volatile ("pushl $12345432 ; pushl $0x9abcdef ; popl (%%esp) ; popl %0"
: "=g" (res));
printf("popl esp=%x\n", res);
/* specific popw test */
asm volatile ("pushl $12345432 ; pushl $0x9abcdef ; popw (%%esp) ; addl $2, %%esp ; popl %0"
: "=g" (res));
printf("popw esp=%x\n", res);
}
uint8_t str_buffer[4096];
@@ -1096,7 +1173,7 @@ void test_vm86(void)
switch(VM86_TYPE(ret)) {
case VM86_INTx:
{
int int_num, ah;
int int_num, ah, v;
int_num = VM86_ARG(ret);
if (int_num != 0x21)
@@ -1124,8 +1201,12 @@ void test_vm86(void)
r->eax = (r->eax & ~0xff) | '$';
}
break;
case 0xff: /* extension: write hex number in edx */
printf("%08x\n", (int)r->edx);
case 0xff: /* extension: write eflags number in edx */
v = (int)r->edx;
#ifndef LINUX_VM86_IOPL_FIX
v &= ~0x3000;
#endif
printf("%08x\n", v);
break;
default:
unknown_int:
@@ -1250,6 +1331,8 @@ void test_exceptions(void)
printf("PF exception:\n");
if (setjmp(jmp_env) == 0) {
val = 1;
/* we add a nop to test a weird PC retrieval case */
asm volatile ("nop");
/* now store in an invalid address */
*(char *)0x1234 = 1;
}
@@ -1344,6 +1427,90 @@ void test_exceptions(void)
printf("val=0x%x\n", val);
}
/* specific precise single step test */
void sig_trap_handler(int sig, siginfo_t *info, void *puc)
{
struct ucontext *uc = puc;
printf("EIP=0x%08x\n", uc->uc_mcontext.gregs[REG_EIP]);
}
const uint8_t sstep_buf1[4] = { 1, 2, 3, 4};
uint8_t sstep_buf2[4];
void test_single_step(void)
{
struct sigaction act;
volatile int val;
int i;
val = 0;
act.sa_sigaction = sig_trap_handler;
sigemptyset(&act.sa_mask);
act.sa_flags = SA_SIGINFO;
sigaction(SIGTRAP, &act, NULL);
asm volatile ("pushf\n"
"orl $0x00100, (%%esp)\n"
"popf\n"
"movl $0xabcd, %0\n"
/* jmp test */
"movl $3, %%ecx\n"
"1:\n"
"addl $1, %0\n"
"decl %%ecx\n"
"jnz 1b\n"
/* movsb: the single step should stop at each movsb iteration */
"movl $sstep_buf1, %%esi\n"
"movl $sstep_buf2, %%edi\n"
"movl $0, %%ecx\n"
"rep movsb\n"
"movl $3, %%ecx\n"
"rep movsb\n"
"movl $1, %%ecx\n"
"rep movsb\n"
/* cmpsb: the single step should stop at each cmpsb iteration */
"movl $sstep_buf1, %%esi\n"
"movl $sstep_buf2, %%edi\n"
"movl $0, %%ecx\n"
"rep cmpsb\n"
"movl $4, %%ecx\n"
"rep cmpsb\n"
/* getpid() syscall: single step should skip one
instruction */
"movl $20, %%eax\n"
"int $0x80\n"
"movl $0, %%eax\n"
/* when modifying SS, trace is not done on the next
instruction */
"movl %%ss, %%ecx\n"
"movl %%ecx, %%ss\n"
"addl $1, %0\n"
"movl $1, %%eax\n"
"movl %%ecx, %%ss\n"
"jmp 1f\n"
"addl $1, %0\n"
"1:\n"
"movl $1, %%eax\n"
"pushl %%ecx\n"
"popl %%ss\n"
"addl $1, %0\n"
"movl $1, %%eax\n"
"pushf\n"
"andl $~0x00100, (%%esp)\n"
"popf\n"
: "=m" (val)
:
: "cc", "memory", "eax", "ecx", "esi", "edi");
printf("val=%d\n", val);
for(i = 0; i < 4; i++)
printf("sstep_buf2[%d] = %d\n", i, sstep_buf2[i]);
}
/* self modifying code test */
uint8_t code[] = {
0xb8, 0x1, 0x00, 0x00, 0x00, /* movl $1, %eax */
@@ -1390,5 +1557,6 @@ int main(int argc, char **argv)
test_vm86();
test_exceptions();
test_self_modifying_code();
test_single_step();
return 0;
}

View File

@@ -1,62 +0,0 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <unistd.h>
#include <inttypes.h>
#include <pthread.h>
#include <sys/wait.h>
#include <sched.h>
int thread1_func(void *arg)
{
int i;
char buf[512];
for(i=0;i<10;i++) {
snprintf(buf, sizeof(buf), "thread1: %d %s\n", i, (char *)arg);
write(1, buf, strlen(buf));
usleep(100 * 1000);
}
return 0;
}
int thread2_func(void *arg)
{
int i;
char buf[512];
for(i=0;i<20;i++) {
snprintf(buf, sizeof(buf), "thread2: %d %s\n", i, (char *)arg);
write(1, buf, strlen(buf));
usleep(120 * 1000);
}
return 0;
}
#define STACK_SIZE 16384
void test_clone(void)
{
uint8_t *stack1, *stack2;
int pid1, pid2, status1, status2;
stack1 = malloc(STACK_SIZE);
pid1 = clone(thread1_func, stack1 + STACK_SIZE,
CLONE_VM | CLONE_FS | CLONE_FILES | SIGCHLD, "hello1");
stack2 = malloc(STACK_SIZE);
pid2 = clone(thread2_func, stack2 + STACK_SIZE,
CLONE_VM | CLONE_FS | CLONE_FILES | SIGCHLD, "hello2");
while (waitpid(pid1, &status1, 0) != pid1);
while (waitpid(pid2, &status2, 0) != pid2);
printf("status1=0x%x\n", status1);
printf("status2=0x%x\n", status2);
printf("End of clone test.\n");
}
int main(int argc, char **argv)
{
test_clone();
return 0;
}

View File

@@ -1,194 +0,0 @@
#define _GNU_SOURCE
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <unistd.h>
#include <setjmp.h>
#include <sys/ucontext.h>
jmp_buf jmp_env;
void alarm_handler(int sig)
{
printf("alarm signal=%d\n", sig);
alarm(1);
}
#ifndef REG_EAX
#define REG_EAX EAX
#define REG_EBX EBX
#define REG_ECX ECX
#define REG_EDX EDX
#define REG_ESI ESI
#define REG_EDI EDI
#define REG_EBP EBP
#define REG_ESP ESP
#define REG_EIP EIP
#define REG_EFL EFL
#define REG_TRAPNO TRAPNO
#define REG_ERR ERR
#endif
void dump_regs(struct ucontext *uc)
{
printf("EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n"
"ESI=%08x EDI=%08x EBP=%08x ESP=%08x\n"
"EFL=%08x EIP=%08x trapno=%02x err=%08x\n",
uc->uc_mcontext.gregs[REG_EAX],
uc->uc_mcontext.gregs[REG_EBX],
uc->uc_mcontext.gregs[REG_ECX],
uc->uc_mcontext.gregs[REG_EDX],
uc->uc_mcontext.gregs[REG_ESI],
uc->uc_mcontext.gregs[REG_EDI],
uc->uc_mcontext.gregs[REG_EBP],
uc->uc_mcontext.gregs[REG_ESP],
uc->uc_mcontext.gregs[REG_EFL],
uc->uc_mcontext.gregs[REG_EIP],
uc->uc_mcontext.gregs[REG_TRAPNO],
uc->uc_mcontext.gregs[REG_ERR]);
}
void sig_handler(int sig, siginfo_t *info, void *puc)
{
struct ucontext *uc = puc;
printf("%s: si_signo=%d si_errno=%d si_code=%d si_addr=0x%08lx\n",
strsignal(info->si_signo),
info->si_signo, info->si_errno, info->si_code,
(unsigned long)info->si_addr);
dump_regs(uc);
longjmp(jmp_env, 1);
}
int v1;
int tab[2];
int main(int argc, char **argv)
{
struct sigaction act;
volatile int val;
act.sa_sigaction = sig_handler;
sigemptyset(&act.sa_mask);
act.sa_flags = SA_SIGINFO;
sigaction(SIGFPE, &act, NULL);
sigaction(SIGILL, &act, NULL);
sigaction(SIGSEGV, &act, NULL);
sigaction(SIGTRAP, &act, NULL);
/* test division by zero reporting */
if (setjmp(jmp_env) == 0) {
/* now divide by zero */
v1 = 0;
v1 = 2 / v1;
}
/* test illegal instruction reporting */
if (setjmp(jmp_env) == 0) {
/* now execute an invalid instruction */
asm volatile("ud2");
}
/* test SEGV reporting */
if (setjmp(jmp_env) == 0) {
/* now store in an invalid address */
*(char *)0x1234 = 1;
}
/* test SEGV reporting */
if (setjmp(jmp_env) == 0) {
/* read from an invalid address */
v1 = *(char *)0x1234;
}
printf("segment GPF exception:\n");
if (setjmp(jmp_env) == 0) {
/* load an invalid segment */
asm volatile ("movl %0, %%fs" : : "r" ((0x1234 << 3) | 0));
}
printf("INT exception:\n");
if (setjmp(jmp_env) == 0) {
asm volatile ("int $0xfd");
}
printf("INT3 exception:\n");
if (setjmp(jmp_env) == 0) {
asm volatile ("int3");
}
printf("CLI exception:\n");
if (setjmp(jmp_env) == 0) {
asm volatile ("cli");
}
printf("STI exception:\n");
if (setjmp(jmp_env) == 0) {
asm volatile ("cli");
}
printf("INTO exception:\n");
if (setjmp(jmp_env) == 0) {
/* overflow exception */
asm volatile ("addl $1, %0 ; into" : : "r" (0x7fffffff));
}
printf("BOUND exception:\n");
if (setjmp(jmp_env) == 0) {
/* bound exception */
tab[0] = 1;
tab[1] = 10;
asm volatile ("bound %0, %1" : : "r" (11), "m" (tab));
}
printf("OUTB exception:\n");
if (setjmp(jmp_env) == 0) {
asm volatile ("outb %%al, %%dx" : : "d" (0x4321), "a" (0));
}
printf("INB exception:\n");
if (setjmp(jmp_env) == 0) {
asm volatile ("inb %%dx, %%al" : "=a" (val) : "d" (0x4321));
}
printf("REP OUTSB exception:\n");
if (setjmp(jmp_env) == 0) {
asm volatile ("rep outsb" : : "d" (0x4321), "S" (tab), "c" (1));
}
printf("REP INSB exception:\n");
if (setjmp(jmp_env) == 0) {
asm volatile ("rep insb" : : "d" (0x4321), "D" (tab), "c" (1));
}
printf("HLT exception:\n");
if (setjmp(jmp_env) == 0) {
asm volatile ("hlt");
}
printf("single step exception:\n");
val = 0;
if (setjmp(jmp_env) == 0) {
asm volatile ("pushf\n"
"orl $0x00100, (%%esp)\n"
"popf\n"
"movl $0xabcd, %0\n" : "=m" (val) : : "cc", "memory");
}
printf("val=0x%x\n", val);
#if 1
{
int i;
act.sa_handler = alarm_handler;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
sigaction(SIGALRM, &act, NULL);
alarm(1);
for(i = 0;i < 2; i++) {
sleep(1);
}
}
#endif
return 0;
}

428
texi2pod.pl Executable file
View File

@@ -0,0 +1,428 @@
#! /usr/bin/perl -w
# Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.
# This file is part of GNU CC.
# GNU CC 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, or (at your option)
# any later version.
# GNU CC 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 GNU CC; see the file COPYING. If not, write to
# the Free Software Foundation, 59 Temple Place - Suite 330,
# Boston MA 02111-1307, USA.
# This does trivial (and I mean _trivial_) conversion of Texinfo
# markup to Perl POD format. It's intended to be used to extract
# something suitable for a manpage from a Texinfo document.
$output = 0;
$skipping = 0;
%sects = ();
$section = "";
@icstack = ();
@endwstack = ();
@skstack = ();
@instack = ();
$shift = "";
%defs = ();
$fnno = 1;
$inf = "";
$ibase = "";
while ($_ = shift) {
if (/^-D(.*)$/) {
if ($1 ne "") {
$flag = $1;
} else {
$flag = shift;
}
$value = "";
($flag, $value) = ($flag =~ /^([^=]+)(?:=(.+))?/);
die "no flag specified for -D\n"
unless $flag ne "";
die "flags may only contain letters, digits, hyphens, dashes and underscores\n"
unless $flag =~ /^[a-zA-Z0-9_-]+$/;
$defs{$flag} = $value;
} elsif (/^-/) {
usage();
} else {
$in = $_, next unless defined $in;
$out = $_, next unless defined $out;
usage();
}
}
if (defined $in) {
$inf = gensym();
open($inf, "<$in") or die "opening \"$in\": $!\n";
$ibase = $1 if $in =~ m|^(.+)/[^/]+$|;
} else {
$inf = \*STDIN;
}
if (defined $out) {
open(STDOUT, ">$out") or die "opening \"$out\": $!\n";
}
while(defined $inf) {
while(<$inf>) {
# Certain commands are discarded without further processing.
/^\@(?:
[a-z]+index # @*index: useful only in complete manual
|need # @need: useful only in printed manual
|(?:end\s+)?group # @group .. @end group: ditto
|page # @page: ditto
|node # @node: useful only in .info file
|(?:end\s+)?ifnottex # @ifnottex .. @end ifnottex: use contents
)\b/x and next;
chomp;
# Look for filename and title markers.
/^\@setfilename\s+([^.]+)/ and $fn = $1, next;
/^\@settitle\s+([^.]+)/ and $tl = postprocess($1), next;
# Identify a man title but keep only the one we are interested in.
/^\@c\s+man\s+title\s+([A-Za-z0-9-]+)\s+(.+)/ and do {
if (exists $defs{$1}) {
$fn = $1;
$tl = postprocess($2);
}
next;
};
# Look for blocks surrounded by @c man begin SECTION ... @c man end.
# This really oughta be @ifman ... @end ifman and the like, but such
# would require rev'ing all other Texinfo translators.
/^\@c\s+man\s+begin\s+([A-Z]+)\s+([A-Za-z0-9-]+)/ and do {
$output = 1 if exists $defs{$2};
$sect = $1;
next;
};
/^\@c\s+man\s+begin\s+([A-Z]+)/ and $sect = $1, $output = 1, next;
/^\@c\s+man\s+end/ and do {
$sects{$sect} = "" unless exists $sects{$sect};
$sects{$sect} .= postprocess($section);
$section = "";
$output = 0;
next;
};
# handle variables
/^\@set\s+([a-zA-Z0-9_-]+)\s*(.*)$/ and do {
$defs{$1} = $2;
next;
};
/^\@clear\s+([a-zA-Z0-9_-]+)/ and do {
delete $defs{$1};
next;
};
next unless $output;
# Discard comments. (Can't do it above, because then we'd never see
# @c man lines.)
/^\@c\b/ and next;
# End-block handler goes up here because it needs to operate even
# if we are skipping.
/^\@end\s+([a-z]+)/ and do {
# Ignore @end foo, where foo is not an operation which may
# cause us to skip, if we are presently skipping.
my $ended = $1;
next if $skipping && $ended !~ /^(?:ifset|ifclear|ignore|menu|iftex)$/;
die "\@end $ended without \@$ended at line $.\n" unless defined $endw;
die "\@$endw ended by \@end $ended at line $.\n" unless $ended eq $endw;
$endw = pop @endwstack;
if ($ended =~ /^(?:ifset|ifclear|ignore|menu|iftex)$/) {
$skipping = pop @skstack;
next;
} elsif ($ended =~ /^(?:example|smallexample|display)$/) {
$shift = "";
$_ = ""; # need a paragraph break
} elsif ($ended =~ /^(?:itemize|enumerate|[fv]?table)$/) {
$_ = "\n=back\n";
$ic = pop @icstack;
} else {
die "unknown command \@end $ended at line $.\n";
}
};
# We must handle commands which can cause skipping even while we
# are skipping, otherwise we will not process nested conditionals
# correctly.
/^\@ifset\s+([a-zA-Z0-9_-]+)/ and do {
push @endwstack, $endw;
push @skstack, $skipping;
$endw = "ifset";
$skipping = 1 unless exists $defs{$1};
next;
};
/^\@ifclear\s+([a-zA-Z0-9_-]+)/ and do {
push @endwstack, $endw;
push @skstack, $skipping;
$endw = "ifclear";
$skipping = 1 if exists $defs{$1};
next;
};
/^\@(ignore|menu|iftex)\b/ and do {
push @endwstack, $endw;
push @skstack, $skipping;
$endw = $1;
$skipping = 1;
next;
};
next if $skipping;
# Character entities. First the ones that can be replaced by raw text
# or discarded outright:
s/\@copyright\{\}/(c)/g;
s/\@dots\{\}/.../g;
s/\@enddots\{\}/..../g;
s/\@([.!? ])/$1/g;
s/\@[:-]//g;
s/\@bullet(?:\{\})?/*/g;
s/\@TeX\{\}/TeX/g;
s/\@pounds\{\}/\#/g;
s/\@minus(?:\{\})?/-/g;
s/\\,/,/g;
# Now the ones that have to be replaced by special escapes
# (which will be turned back into text by unmunge())
s/&/&amp;/g;
s/\@\{/&lbrace;/g;
s/\@\}/&rbrace;/g;
s/\@\@/&at;/g;
# Inside a verbatim block, handle @var specially.
if ($shift ne "") {
s/\@var\{([^\}]*)\}/<$1>/g;
}
# POD doesn't interpret E<> inside a verbatim block.
if ($shift eq "") {
s/</&lt;/g;
s/>/&gt;/g;
} else {
s/</&LT;/g;
s/>/&GT;/g;
}
# Single line command handlers.
/^\@include\s+(.+)$/ and do {
push @instack, $inf;
$inf = gensym();
# Try cwd and $ibase.
open($inf, "<" . $1)
or open($inf, "<" . $ibase . "/" . $1)
or die "cannot open $1 or $ibase/$1: $!\n";
next;
};
/^\@(?:section|unnumbered|unnumberedsec|center)\s+(.+)$/
and $_ = "\n=head2 $1\n";
/^\@subsection\s+(.+)$/
and $_ = "\n=head3 $1\n";
# Block command handlers:
/^\@itemize\s+(\@[a-z]+|\*|-)/ and do {
push @endwstack, $endw;
push @icstack, $ic;
$ic = $1;
$_ = "\n=over 4\n";
$endw = "itemize";
};
/^\@enumerate(?:\s+([a-zA-Z0-9]+))?/ and do {
push @endwstack, $endw;
push @icstack, $ic;
if (defined $1) {
$ic = $1 . ".";
} else {
$ic = "1.";
}
$_ = "\n=over 4\n";
$endw = "enumerate";
};
/^\@([fv]?table)\s+(\@[a-z]+)/ and do {
push @endwstack, $endw;
push @icstack, $ic;
$endw = $1;
$ic = $2;
$ic =~ s/\@(?:samp|strong|key|gcctabopt|option|env)/B/;
$ic =~ s/\@(?:code|kbd)/C/;
$ic =~ s/\@(?:dfn|var|emph|cite|i)/I/;
$ic =~ s/\@(?:file)/F/;
$_ = "\n=over 4\n";
};
/^\@((?:small)?example|display)/ and do {
push @endwstack, $endw;
$endw = $1;
$shift = "\t";
$_ = ""; # need a paragraph break
};
/^\@itemx?\s*(.+)?$/ and do {
if (defined $1) {
# Entity escapes prevent munging by the <> processing below.
# print "$ic\n";
$_ = "\n=item $ic\&LT;$1\&GT;\n";
} else {
$_ = "\n=item $ic\n";
$ic =~ y/A-Ya-y/B-Zb-z/;
$ic =~ s/(\d+)/$1 + 1/eg;
}
};
$section .= $shift.$_."\n";
}
# End of current file.
close($inf);
$inf = pop @instack;
}
die "No filename or title\n" unless defined $fn && defined $tl;
$sects{NAME} = "$fn \- $tl\n";
$sects{FOOTNOTES} .= "=back\n" if exists $sects{FOOTNOTES};
for $sect (qw(NAME SYNOPSIS DESCRIPTION OPTIONS ENVIRONMENT FILES
BUGS NOTES FOOTNOTES SEEALSO AUTHOR COPYRIGHT)) {
if(exists $sects{$sect}) {
$head = $sect;
$head =~ s/SEEALSO/SEE ALSO/;
print "=head1 $head\n\n";
print scalar unmunge ($sects{$sect});
print "\n";
}
}
sub usage
{
die "usage: $0 [-D toggle...] [infile [outfile]]\n";
}
sub postprocess
{
local $_ = $_[0];
# @value{foo} is replaced by whatever 'foo' is defined as.
while (m/(\@value\{([a-zA-Z0-9_-]+)\})/g) {
if (! exists $defs{$2}) {
print STDERR "Option $2 not defined\n";
s/\Q$1\E//;
} else {
$value = $defs{$2};
s/\Q$1\E/$value/;
}
}
# Formatting commands.
# Temporary escape for @r.
s/\@r\{([^\}]*)\}/R<$1>/g;
s/\@(?:dfn|var|emph|cite|i)\{([^\}]*)\}/I<$1>/g;
s/\@(?:code|kbd)\{([^\}]*)\}/C<$1>/g;
s/\@(?:gccoptlist|samp|strong|key|option|env|command|b)\{([^\}]*)\}/B<$1>/g;
s/\@sc\{([^\}]*)\}/\U$1/g;
s/\@file\{([^\}]*)\}/F<$1>/g;
s/\@w\{([^\}]*)\}/S<$1>/g;
s/\@(?:dmn|math)\{([^\}]*)\}/$1/g;
# Cross references are thrown away, as are @noindent and @refill.
# (@noindent is impossible in .pod, and @refill is unnecessary.)
# @* is also impossible in .pod; we discard it and any newline that
# follows it. Similarly, our macro @gol must be discarded.
s/\(?\@xref\{(?:[^\}]*)\}(?:[^.<]|(?:<[^<>]*>))*\.\)?//g;
s/\s+\(\@pxref\{(?:[^\}]*)\}\)//g;
s/;\s+\@pxref\{(?:[^\}]*)\}//g;
s/\@noindent\s*//g;
s/\@refill//g;
s/\@gol//g;
s/\@\*\s*\n?//g;
# @uref can take one, two, or three arguments, with different
# semantics each time. @url and @email are just like @uref with
# one argument, for our purposes.
s/\@(?:uref|url|email)\{([^\},]*)\}/&lt;B<$1>&gt;/g;
s/\@uref\{([^\},]*),([^\},]*)\}/$2 (C<$1>)/g;
s/\@uref\{([^\},]*),([^\},]*),([^\},]*)\}/$3/g;
# Turn B<blah I<blah> blah> into B<blah> I<blah> B<blah> to
# match Texinfo semantics of @emph inside @samp. Also handle @r
# inside bold.
s/&LT;/</g;
s/&GT;/>/g;
1 while s/B<((?:[^<>]|I<[^<>]*>)*)R<([^>]*)>/B<$1>${2}B</g;
1 while (s/B<([^<>]*)I<([^>]+)>/B<$1>I<$2>B</g);
1 while (s/I<([^<>]*)B<([^>]+)>/I<$1>B<$2>I</g);
s/[BI]<>//g;
s/([BI])<(\s+)([^>]+)>/$2$1<$3>/g;
s/([BI])<([^>]+?)(\s+)>/$1<$2>$3/g;
# Extract footnotes. This has to be done after all other
# processing because otherwise the regexp will choke on formatting
# inside @footnote.
while (/\@footnote/g) {
s/\@footnote\{([^\}]+)\}/[$fnno]/;
add_footnote($1, $fnno);
$fnno++;
}
return $_;
}
sub unmunge
{
# Replace escaped symbols with their equivalents.
local $_ = $_[0];
s/&lt;/E<lt>/g;
s/&gt;/E<gt>/g;
s/&lbrace;/\{/g;
s/&rbrace;/\}/g;
s/&at;/\@/g;
s/&amp;/&/g;
return $_;
}
sub add_footnote
{
unless (exists $sects{FOOTNOTES}) {
$sects{FOOTNOTES} = "\n=over 4\n\n";
}
$sects{FOOTNOTES} .= "=item $fnno.\n\n"; $fnno++;
$sects{FOOTNOTES} .= $_[0];
$sects{FOOTNOTES} .= "\n\n";
}
# stolen from Symbol.pm
{
my $genseq = 0;
sub gensym
{
my $name = "GEN" . $genseq++;
my $ref = \*{$name};
delete $::{$name};
return $ref;
}
}

78
thunk.h
View File

@@ -23,43 +23,7 @@
#include <inttypes.h>
#include "config.h"
#ifdef HAVE_BYTESWAP_H
#include <byteswap.h>
#else
#define bswap_16(x) \
({ \
uint16_t __x = (x); \
((uint16_t)( \
(((uint16_t)(__x) & (uint16_t)0x00ffU) << 8) | \
(((uint16_t)(__x) & (uint16_t)0xff00U) >> 8) )); \
})
#define bswap_32(x) \
({ \
uint32_t __x = (x); \
((uint32_t)( \
(((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
(((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \
(((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \
(((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) )); \
})
#define bswap_64(x) \
({ \
uint64_t __x = (x); \
((uint64_t)( \
(uint64_t)(((uint64_t)(__x) & (uint64_t)0x00000000000000ffULL) << 56) | \
(uint64_t)(((uint64_t)(__x) & (uint64_t)0x000000000000ff00ULL) << 40) | \
(uint64_t)(((uint64_t)(__x) & (uint64_t)0x0000000000ff0000ULL) << 24) | \
(uint64_t)(((uint64_t)(__x) & (uint64_t)0x00000000ff000000ULL) << 8) | \
(uint64_t)(((uint64_t)(__x) & (uint64_t)0x000000ff00000000ULL) >> 8) | \
(uint64_t)(((uint64_t)(__x) & (uint64_t)0x0000ff0000000000ULL) >> 24) | \
(uint64_t)(((uint64_t)(__x) & (uint64_t)0x00ff000000000000ULL) >> 40) | \
(uint64_t)(((uint64_t)(__x) & (uint64_t)0xff00000000000000ULL) >> 56) )); \
})
#endif
#include "bswap.h"
#if defined(WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
#define BSWAP_NEEDED
@@ -68,44 +32,7 @@
/* XXX: autoconf */
#define TARGET_LONG_BITS 32
#if defined(__alpha__) || defined (__ia64__)
#define HOST_LONG_BITS 64
#else
#define HOST_LONG_BITS 32
#endif
#define TARGET_LONG_SIZE (TARGET_LONG_BITS / 8)
#define HOST_LONG_SIZE (HOST_LONG_BITS / 8)
static inline uint16_t bswap16(uint16_t x)
{
return bswap_16(x);
}
static inline uint32_t bswap32(uint32_t x)
{
return bswap_32(x);
}
static inline uint64_t bswap64(uint64_t x)
{
return bswap_64(x);
}
static inline void bswap16s(uint16_t *s)
{
*s = bswap16(*s);
}
static inline void bswap32s(uint32_t *s)
{
*s = bswap32(*s);
}
static inline void bswap64s(uint64_t *s)
{
*s = bswap64(*s);
}
#ifdef BSWAP_NEEDED
@@ -236,6 +163,7 @@ void thunk_register_struct(int id, const char *name, const argtype *types);
void thunk_register_struct_direct(int id, const char *name, StructEntry *se1);
const argtype *thunk_convert(void *dst, const void *src,
const argtype *type_ptr, int to_host);
#ifndef NO_THUNK_TYPE_SIZE
extern StructEntry struct_entries[];
@@ -312,6 +240,8 @@ static inline int thunk_type_align(const argtype *type_ptr, int is_host)
}
}
#endif /* NO_THUNK_TYPE_SIZE */
unsigned int target_to_host_bitmask(unsigned int x86_mask,
bitmask_transtbl * trans_tbl);
unsigned int host_to_target_bitmask(unsigned int alpha_mask,

View File

@@ -26,34 +26,19 @@
#include "config.h"
#define IN_OP_I386
#if defined(TARGET_I386)
#include "cpu-i386.h"
#define OPC_CPU_H "opc-i386.h"
#elif defined(TARGET_ARM)
#include "cpu-arm.h"
#define OPC_CPU_H "opc-arm.h"
#else
#error unsupported target CPU
#endif
#include "exec.h"
#include "cpu.h"
#include "exec-all.h"
#include "disas.h"
enum {
#define DEF(s, n, copy_size) INDEX_op_ ## s,
#include OPC_CPU_H
#include "opc.h"
#undef DEF
NB_OPS,
};
#include "dyngen.h"
#if defined(TARGET_I386)
#include "op-i386.h"
#elif defined(TARGET_ARM)
#include "op-arm.h"
#else
#error unsupported target CPU
#endif
#include "op.h"
uint16_t gen_opc_buf[OPC_BUF_SIZE];
uint32_t gen_opparam_buf[OPPARAM_BUF_SIZE];
@@ -66,13 +51,13 @@ uint8_t gen_opc_cc_op[OPC_BUF_SIZE];
#ifdef DEBUG_DISAS
static const char *op_str[] = {
#define DEF(s, n, copy_size) #s,
#include OPC_CPU_H
#include "opc.h"
#undef DEF
};
static uint8_t op_nb_args[] = {
#define DEF(s, n, copy_size) n,
#include OPC_CPU_H
#include "opc.h"
#undef DEF
};
@@ -107,19 +92,24 @@ void dump_ops(const uint16_t *opc_buf, const uint32_t *opparam_buf)
'*gen_code_size_ptr' contains the size of the generated code (host
code).
*/
int cpu_gen_code(TranslationBlock *tb,
int cpu_gen_code(CPUState *env, TranslationBlock *tb,
int max_code_size, int *gen_code_size_ptr)
{
uint8_t *gen_code_buf;
int gen_code_size;
if (gen_intermediate_code(tb) < 0)
if (gen_intermediate_code(env, tb) < 0)
return -1;
/* generate machine code */
tb->tb_next_offset[0] = 0xffff;
tb->tb_next_offset[1] = 0xffff;
gen_code_buf = tb->tc_ptr;
#ifdef USE_DIRECT_JUMP
/* the following two entries are optional (only used for string ops) */
tb->tb_jmp_offset[2] = 0xffff;
tb->tb_jmp_offset[3] = 0xffff;
#endif
gen_code_size = dyngen_code(gen_code_buf, tb->tb_next_offset,
#ifdef USE_DIRECT_JUMP
tb->tb_jmp_offset,
@@ -141,7 +131,7 @@ int cpu_gen_code(TranslationBlock *tb,
static const unsigned short opc_copy_size[] = {
#define DEF(s, n, copy_size) copy_size,
#include OPC_CPU_H
#include "opc.h"
#undef DEF
};
@@ -154,7 +144,7 @@ int cpu_restore_state(TranslationBlock *tb,
unsigned long tc_ptr;
uint16_t *opc_ptr;
if (gen_intermediate_code_pc(tb) < 0)
if (gen_intermediate_code_pc(env, tb) < 0)
return -1;
/* find opc index corresponding to search_pc */
@@ -179,7 +169,19 @@ int cpu_restore_state(TranslationBlock *tb,
#if defined(TARGET_I386)
{
int cc_op;
#ifdef DEBUG_DISAS
if (loglevel) {
int i;
fprintf(logfile, "RESTORE:\n");
for(i=0;i<=j; i++) {
if (gen_opc_instr_start[i]) {
fprintf(logfile, "0x%04x: 0x%08x\n", i, gen_opc_pc[i]);
}
}
fprintf(logfile, "spc=0x%08lx j=0x%x eip=0x%lx cs_base=%lx\n",
searched_pc, j, gen_opc_pc[j] - tb->cs_base, tb->cs_base);
}
#endif
env->eip = gen_opc_pc[j] - tb->cs_base;
cc_op = gen_opc_cc_op[j];
if (cc_op != CC_OP_DYNAMIC)
@@ -187,8 +189,10 @@ int cpu_restore_state(TranslationBlock *tb,
}
#elif defined(TARGET_ARM)
env->regs[15] = gen_opc_pc[j];
#elif defined(TARGET_SPARC)
env->pc = gen_opc_pc[j];
#elif defined(TARGET_PPC)
env->nip = gen_opc_pc[j];
#endif
return 0;
}

2215
vl.c

File diff suppressed because it is too large Load Diff

147
vl.h Normal file
View File

@@ -0,0 +1,147 @@
/*
* QEMU System Emulator header
*
* Copyright (c) 2003 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef VL_H
#define VL_H
/* vl.c */
struct CPUX86State;
extern int reset_requested;
extern int64_t ticks_per_sec;
typedef void (IOPortWriteFunc)(struct CPUX86State *env, uint32_t address, uint32_t data);
typedef uint32_t (IOPortReadFunc)(struct CPUX86State *env, uint32_t address);
void *get_mmap_addr(unsigned long size);
int register_ioport_read(int start, int length, IOPortReadFunc *func, int size);
int register_ioport_write(int start, int length, IOPortWriteFunc *func, int size);
void pic_set_irq(int irq, int level);
int64_t cpu_get_ticks(void);
void kbd_put_keycode(int keycode);
#define MOUSE_EVENT_LBUTTON 0x01
#define MOUSE_EVENT_RBUTTON 0x02
#define MOUSE_EVENT_MBUTTON 0x04
void kbd_mouse_event(int dx, int dy, int dz, int buttons_state);
/* block.c */
typedef struct BlockDriverState BlockDriverState;
BlockDriverState *bdrv_open(const char *filename, int snapshot);
void bdrv_close(BlockDriverState *bs);
int bdrv_read(BlockDriverState *bs, int64_t sector_num,
uint8_t *buf, int nb_sectors);
int bdrv_write(BlockDriverState *bs, int64_t sector_num,
const uint8_t *buf, int nb_sectors);
void bdrv_get_geometry(BlockDriverState *bs, int64_t *nb_sectors_ptr);
int bdrv_commit(BlockDriverState *bs);
/* user mode linux compatible COW file */
#define COW_MAGIC 0x4f4f4f4d /* MOOO */
#define COW_VERSION 2
struct cow_header_v2 {
uint32_t magic;
uint32_t version;
char backing_file[1024];
int32_t mtime;
uint64_t size;
uint32_t sectorsize;
};
/* vga.c */
#define VGA_RAM_SIZE (8192 * 1024)
typedef struct DisplayState {
uint8_t *data;
int linesize;
int depth;
void (*dpy_update)(struct DisplayState *s, int x, int y, int w, int h);
void (*dpy_resize)(struct DisplayState *s, int w, int h);
void (*dpy_refresh)(struct DisplayState *s);
} DisplayState;
static inline void dpy_update(DisplayState *s, int x, int y, int w, int h)
{
s->dpy_update(s, x, y, w, h);
}
static inline void dpy_resize(DisplayState *s, int w, int h)
{
s->dpy_resize(s, w, h);
}
int vga_init(DisplayState *ds, uint8_t *vga_ram_base,
unsigned long vga_ram_offset, int vga_ram_size);
void vga_update_display(void);
/* sdl.c */
void sdl_display_init(DisplayState *ds);
/* ide.c */
#define MAX_DISKS 4
extern BlockDriverState *bs_table[MAX_DISKS];
void ide_init(void);
void ide_set_geometry(int n, int cyls, int heads, int secs);
void ide_set_cdrom(int n, int is_cdrom);
/* oss.c */
typedef enum {
AUD_FMT_U8,
AUD_FMT_S8,
AUD_FMT_U16,
AUD_FMT_S16
} audfmt_e;
void AUD_open (int rfreq, int rnchannels, audfmt_e rfmt);
void AUD_reset (int rfreq, int rnchannels, audfmt_e rfmt);
int AUD_write (void *in_buf, int size);
void AUD_run (void);
void AUD_adjust_estimate (int _leftover);
int AUD_get_free (void);
int AUD_get_live (void);
int AUD_get_buffer_size (void);
void AUD_init (void);
/* dma.c */
typedef int (*DMA_read_handler) (uint32_t addr, int size, int *irq);
typedef int (*DMA_misc_handler) (int);
int DMA_get_channel_mode (int nchan);
void DMA_hold_DREQ (int nchan);
void DMA_release_DREQ (int nchan);
void DMA_run (void);
void DMA_init (void);
void DMA_register_channel (int nchan,
DMA_read_handler read_handler,
DMA_misc_handler misc_handler);
/* sb16.c */
void SB16_run (void);
void SB16_init (void);
#endif /* VL_H */