Compare commits

..

320 Commits

Author SHA1 Message Date
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
bellard
1eb20527c8 update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@283 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-25 16:21:49 +00:00
bellard
e3e86d56c4 gcc3 compile fixes
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@282 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-25 16:21:11 +00:00
bellard
1df912cf9e VL license of the day is MIT/BSD
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@281 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-25 16:20:35 +00:00
bellard
4351832355 added invlpg emulation
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@280 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-25 16:19:50 +00:00
bellard
59faf6d6a6 compile fixes
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@279 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-25 16:18:50 +00:00
bellard
725af7d460 untested RH9 fixes
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@278 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-25 16:18:32 +00:00
bellard
a363e34cc5 fixed VM86 support in Virtual Linux - fixed compilation issues with gcc 2.96 - cpuid returns now pentium pro in order to avoid F00F bug workaround in Linux kernel
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@277 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-25 16:18:05 +00:00
bellard
ea041c0e33 more precise cpu_interrupt()
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@276 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-25 16:16:50 +00:00
bellard
83479e770d suppressed ring 0 hacks
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@275 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-25 16:12:37 +00:00
bellard
e2f2289897 arm fixes
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@274 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-25 16:09:48 +00:00
bellard
844c72eccc more compiler tests
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@273 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-25 16:09:14 +00:00
bellard
6b1534cc67 fixed compilation for gcc 2.96 - added QEMU system emulator
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@272 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-25 16:08:39 +00:00
bellard
e8cd23de30 fixed compilation for gcc 2.96
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@271 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-25 16:08:13 +00:00
bellard
7c2d6a781c faster task switch
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@270 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-25 00:08:13 +00:00
bellard
f1510b2cc3 added NE2000 emulation
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@269 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-25 00:07:40 +00:00
bellard
357a94326c added link script for vl
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@268 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-24 14:39:12 +00:00
bellard
0824d6fc67 for hard core developpers only: a new user mode linux project :-)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@267 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-24 13:42:40 +00:00
bellard
6c0372d30b updated
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@266 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-24 13:40:52 +00:00
bellard
92ccca6aa8 declare user mode only simulation for QEMU
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@265 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-24 13:30:31 +00:00
bellard
dd3587f38e iret and popl (%esp) tests
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@264 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-24 13:29:40 +00:00
bellard
7d83131cc5 use inline function
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@263 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-24 13:28:48 +00:00
bellard
66e85a21c7 MMU support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@262 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-24 13:28:12 +00:00
bellard
90a9fdae1f more ring 0 operations
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@261 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-24 13:27:18 +00:00
bellard
3fb2ded1d5 hardware interrupt support - support forfull ring 0 exception simulation
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@260 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-24 13:22:59 +00:00
bellard
f76af4b3f3 correct restoring of CC_OP in case of exception
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@259 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-24 13:21:23 +00:00
bellard
717fc2ad8d more ring 0 instructions - full x86 MMU emulation based on mmap() syscall - fixed popl (%esp)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@258 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-24 13:20:53 +00:00
bellard
c05bab779e force IOPL=3
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@257 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-21 13:14:43 +00:00
bellard
a52c757c9f fixed case where SS != USER_DS (fixes dosemu DPMI emulation)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@256 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-21 13:14:12 +00:00
bellard
970a87a6bb new segment access
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@255 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-21 13:13:25 +00:00
bellard
d8bc1fd0ae ring 0 ops
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@254 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-21 13:13:13 +00:00
bellard
7501267e22 cpu_abort()
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@253 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-21 13:11:07 +00:00
bellard
13b55754af ring 0 data structures
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@252 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-21 13:09:53 +00:00
bellard
972ddf7840 added cpu_abort()
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@251 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-21 13:08:39 +00:00
bellard
322d0c6657 update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@250 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-15 23:29:28 +00:00
bellard
2054396a04 fixed include macro pb
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@249 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-15 23:28:43 +00:00
bellard
039de852ec fixed op_label computation on ppc
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@248 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-15 22:50:44 +00:00
bellard
144c345daf consistent hello naming
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@247 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-15 20:42:31 +00:00
bellard
de83cd02e0 arm emulation support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@246 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-15 20:25:43 +00:00
bellard
6380ab5e26 added missing link scripts
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@245 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-15 20:25:04 +00:00
bellard
b346ff468e ARM emulation support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@244 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-15 20:05:50 +00:00
bellard
5a9fdfec7e factorized cpu defines
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@243 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-15 20:02:25 +00:00
bellard
d19893dab5 extracted generic code
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@242 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-15 19:58:51 +00:00
bellard
2521d69883 factorized more definitions - suppressed broken sound ioctls
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@241 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-15 19:58:13 +00:00
bellard
2ab83ea784 automatic ioctl number conversion - minimum ARM fork() support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@240 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-15 19:56:46 +00:00
bellard
2437490100 fixed serious ioctl parameter conversion issue - exported type size and align functions
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@239 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-15 19:52:54 +00:00
bellard
e4533c7a8c main cpu loop is target independent
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@238 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-15 19:51:39 +00:00
bellard
1e5ffbedde fixed float to int overflow bug - added ARM host correct roundings for float rounding
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@237 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-15 19:49:16 +00:00
bellard
79638566e5 moved dyngen generic code to dyngen-exec.h
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@236 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-15 19:46:57 +00:00
bellard
03daf0e361 moved cache flush to dyngen header
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@235 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-15 19:45:20 +00:00
bellard
d219f7e7ed output gen_op_xxx() in a separate file
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@234 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-15 19:44:49 +00:00
bellard
95cbfc643d changed disas() prototype for multi target support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@233 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-15 19:44:10 +00:00
bellard
5898e81684 ARM emulation support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@232 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-15 19:42:24 +00:00
bellard
394411ac74 added hello world for ARM
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@231 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-15 19:37:07 +00:00
bellard
ea76864009 more precise float rounding tests
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@230 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-15 19:36:33 +00:00
bellard
43ce4dfe9e added static build option
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@229 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-09 19:53:12 +00:00
bellard
ebc06f87ca alpha fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@228 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-09 19:46:12 +00:00
bellard
5bbe92995c disas endian fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@227 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-09 19:38:38 +00:00
bellard
411bffc41c update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@226 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-09 15:38:23 +00:00
bellard
ff1f20a3ee arm support - suppressed possibly unsafe sparc nop deletion
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@225 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-09 15:34:19 +00:00
bellard
9c5d1246c7 use -mflat for helper-i386.c on sparc - use custom ld script on sparc to free zero memory addresses for vm86 emulation - arm support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@224 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-09 15:33:05 +00:00
bellard
8dd7cb0621 moved to disas.c
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@223 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-09 15:31:02 +00:00
bellard
d30329297b removed unused dependancy if non x86
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@222 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-09 15:30:37 +00:00
bellard
a95c67907c arm support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@221 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-09 15:29:55 +00:00
bellard
0f533160c7 removed unused code
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@220 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-09 15:29:20 +00:00
bellard
e163bca720 weird arm double format support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@219 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-09 15:28:45 +00:00
bellard
8c6939c0b0 arm support - modified sparc to work with direct chaining
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@218 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-09 15:28:00 +00:00
bellard
2d0e9143e2 more code moved to helpers - sipmplified x86 float constants definitions
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@217 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-09 15:25:54 +00:00
bellard
87f4827e1d more code moved to helpers
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@216 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-09 15:24:58 +00:00
bellard
4a585ccb2f avoid unaligned file offset in anonymous mapping
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@215 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-09 15:24:18 +00:00
bellard
aa0aa4fa31 added ARM and Sparc disassemblers
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@214 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-09 15:23:31 +00:00
bellard
84fa15d854 big endian/unaligned fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@213 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-09 15:20:55 +00:00
bellard
4add45b4f6 getdents for 64 bit cpus
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@212 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-05 01:52:59 +00:00
bellard
4f101ad7ff 64 bit fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@211 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-05 01:52:19 +00:00
bellard
c1db2eb8c3 tested tools
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@210 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-05 01:05:11 +00:00
bellard
82d19dafe4 added helper-i386.c - alpha fixes
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@209 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-05 00:58:28 +00:00
bellard
5286db75a8 convert mmap flags (alpha fix)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@208 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-05 00:57:30 +00:00
bellard
917f95fd4d alpha fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@207 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-05 00:56:37 +00:00
bellard
fe31975692 fixed __op_label handling if RELA relocations are used
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@206 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-05 00:56:05 +00:00
bellard
95f7652d65 use 32 bit pointer for tb_next even on 64 bit archs
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@205 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-05 00:54:44 +00:00
bellard
3ec9c4fcc6 separated helpers from micro operations
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@204 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-05 00:54:09 +00:00
bellard
2f87c60799 Alpha update (Falk Hueffner)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@203 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-02 20:38:09 +00:00
bellard
03bfca946a more FPU tests
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@202 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-29 20:06:57 +00:00
bellard
ed2dcdf68e save FPU state in signal handler
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@201 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-29 20:06:27 +00:00
bellard
4304763ba2 misplaced #endif
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@200 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-29 20:05:35 +00:00
bellard
c1e42a1397 search data in both .data and .sdata
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@199 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-29 20:05:18 +00:00
bellard
d0a1ffc957 added fsave/frstor/fstenv/fldenv/fcomi - fixed cpuid - make lret/iret restartable
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@198 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-29 20:04:28 +00:00
bellard
df0f11a03b update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@197 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-28 00:27:57 +00:00
bellard
2d92f0b8f0 autogen opc-i386.h
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@196 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-28 00:24:44 +00:00
bellard
aad13cd131 segment defines
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@195 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-27 23:30:06 +00:00
bellard
a513fe19ac precise exceptions
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@194 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-27 23:29:48 +00:00
bellard
f4beb510a4 precise exceptions - more accurate interrupt semantics
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@193 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-27 23:28:08 +00:00
bellard
d731dae8e3 currently generated
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@192 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-27 23:26:25 +00:00
bellard
c9087c2a60 cr2 update (dosemu VGA support fix)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@191 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-27 23:25:41 +00:00
bellard
14ae3ba7f9 mmap2 fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@190 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-27 23:25:06 +00:00
bellard
5a91de8c90 precise exception support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@189 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-27 23:24:27 +00:00
bellard
e3b32540df more exception tests - support for precise exceptions
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@188 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-27 23:23:22 +00:00
bellard
a37904dd86 fwait fix (aka DOS Navigator fix)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@187 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-25 23:10:30 +00:00
bellard
cf25629d1e more efficient locking
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@186 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-25 19:20:31 +00:00
bellard
0ca790b92e direct chaining for PowerPC and i386
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@185 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-25 16:51:57 +00:00
bellard
d1fe2b2459 self modifying code also tests translation block chaining invalidation
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@184 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-25 16:47:16 +00:00
bellard
d4e8164f7e direct chaining for PowerPC and i386
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@183 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-25 16:46:15 +00:00
bellard
08351fb37a fixed cast
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@182 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-25 16:42:20 +00:00
bellard
85e53d4108 update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@181 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-25 16:41:52 +00:00
bellard
aa05ae6fec added exec.h
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@180 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-25 16:41:18 +00:00
bellard
1565b7bcd7 fixed page_unprotect() if host_page_size > TARGET_PAGE_SIZE
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@179 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-16 16:07:10 +00:00
bellard
b409186b8d added getrusage
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@178 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-16 15:39:34 +00:00
bellard
418a97afa1 fixed 32 bit popf/iret emulation in vm86 mode
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@177 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-16 15:12:51 +00:00
bellard
5132455efe test-i386 update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@176 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-16 13:58:37 +00:00
bellard
c0ad5542a8 fixed popf TF flag bug (should never hapen in user code except in test-i386!)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@175 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-16 13:46:28 +00:00
bellard
3a27ad0b57 added vm86, exceptions and self modifying regression tests
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@174 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-16 13:43:31 +00:00
bellard
2b413144dc cosmetics
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@173 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-14 23:01:10 +00:00
bellard
3ebcc707d2 removed invalid eip update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@172 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-14 22:47:15 +00:00
bellard
7775e9ecc2 added do_fcntl()
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@171 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-14 22:46:48 +00:00
bellard
03d843ddf2 fixed invalid signal masking
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@170 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-14 22:41:55 +00:00
bellard
eb51d102bb better locks
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@169 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-14 21:51:13 +00:00
bellard
25eb44841e better locking - added PowerPC signal handler (add it for the other archs too because it needed for full exception support)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@168 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-14 21:50:54 +00:00
bellard
b333af0666 removed trace - merged 2.4.20 vm86 patches
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@167 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-14 21:48:51 +00:00
bellard
76c8b7710b file list update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@166 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-14 19:48:46 +00:00
bellard
70e198602b update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@165 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-14 19:02:49 +00:00
bellard
206f0fa759 pread/pwrite syscalls - use page_unprotect_range() in vital cases to avoid problems if the kernel writes data in protected page (needed for self-modifying code support)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@164 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-14 19:01:56 +00:00
bellard
fd6ce8f660 self-modifying code support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@163 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-14 19:00:11 +00:00
bellard
727d01d4f6 return code size
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@162 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-14 18:58:05 +00:00
bellard
ae22853141 Sparc update (David S. Miller)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@161 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-13 18:59:59 +00:00
bellard
d418c81eff fixed small page handling
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@160 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-13 00:57:50 +00:00
bellard
2a29ca73c9 more exception tests
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@159 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-13 00:29:04 +00:00
bellard
54936004fd mmap emulation
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@158 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-13 00:25:15 +00:00
bellard
74c95119f2 Alpha fixes (Falk Hueffner)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@157 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-11 12:27:31 +00:00
bellard
366c1b8bfa warning fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@156 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-11 12:27:02 +00:00
bellard
a993ba85cf alpha disas (Falk Hueffner)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@155 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-11 12:25:45 +00:00
bellard
226c91327d fixed from 2.4.20 kernel
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@154 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-10 21:41:47 +00:00
bellard
b8bf3e3aac eflags fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@153 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-10 21:39:42 +00:00
bellard
288426fe3c added LAR/LSL tests
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@152 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-10 21:39:12 +00:00
bellard
72cc388104 fixed SHL C flag computation
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@151 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-10 21:38:19 +00:00
bellard
378180d8dc added LAR/LSL
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@150 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-10 21:37:51 +00:00
bellard
78c34e98cd added LAR/LSL - fixed INT3 and INTO EIP computation
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@149 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-10 21:37:05 +00:00
bellard
2792c4f2af added EIP return to INTO - fixed SHL C flag computation - added LAR/LSL
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@148 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-10 21:35:30 +00:00
bellard
447db2139a sigtrap support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@147 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-10 15:10:36 +00:00
bellard
564c8f9978 simplified exception support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@146 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-10 15:10:02 +00:00
bellard
c50c0c3fbf TF flag support - fixed eflags computation before exception
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@145 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-10 15:07:51 +00:00
bellard
cabb4d616d TF flag support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@144 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-10 15:07:00 +00:00
bellard
631271d716 added vm86.c
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@143 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-10 13:14:52 +00:00
bellard
9d27abd94f fixed invalid CPL logic in vm86 mode - use generic CPU dump state function
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@142 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-10 13:13:54 +00:00
bellard
148dfc2a8b fixed GPF generation - fixed 'lret im' instruction (main fix for dosemu) - fixed HLT instruction
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@141 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-10 13:09:33 +00:00
bellard
3acace1333 removed unnecessary VME support - fixed selector GPF exception
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@140 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-10 12:39:11 +00:00
bellard
0221cfcd71 more console ioctls
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@139 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-10 12:38:16 +00:00
bellard
f351077efb added dump function
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@138 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-10 12:37:32 +00:00
bellard
e84be9dbca added vm86.c
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@137 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-10 12:37:12 +00:00
bellard
46ddf5511d vm86 emulation closer to Linux kernel code - added correct IRQ emulation for dosemu
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@136 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-10 12:36:41 +00:00
bellard
89e957e7a2 moved vm86 stuff to vm86.c
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@135 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-10 12:33:15 +00:00
bellard
982b431579 added CPL/IOPL support - fixed subtle inc/dec flag optimisation bug - added HLT instruction
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@134 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-08 15:44:24 +00:00
bellard
bf7c65bdf4 changed I/O function prototype to include emulator state
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@133 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-08 15:42:38 +00:00
bellard
8e5a0667f8 added KDGKBTYPE
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@132 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-08 15:42:10 +00:00
bellard
19b84f3c35 added setgroups and getgroups syscalls
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@131 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-08 15:41:49 +00:00
bellard
08fc60898b more siginfo constants
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@130 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-08 15:41:15 +00:00
bellard
082391983e added op_gpf
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@129 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-08 15:40:45 +00:00
bellard
504e56ebdc more accurate GPF generation
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@128 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-08 15:39:48 +00:00
bellard
455b761956 added raise_exception_err()
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@127 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-08 15:38:21 +00:00
bellard
b56dad1c7b added raise_exception_err() - added cr2 update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@126 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-08 15:38:04 +00:00
bellard
9ba5695ce5 added CPL and IOPL as translation time constants - changed I/O function prototype to include emulator state - added error_code and cr2 support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@125 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-08 15:35:34 +00:00
bellard
66099dd9af added trapno and error_code report in ucontext
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@124 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-08 15:34:02 +00:00
bellard
b689bc57d6 more accurate signal handling
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@123 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-08 15:33:33 +00:00
bellard
a69d83b60b systematic exception test
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@122 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-08 15:32:33 +00:00
bellard
86840ae241 update (test)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@121 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-08 15:30:27 +00:00
bellard
3c51961e0e update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@120 c046a42c-6fe2-441c-8c8c-71466251a162
2003-04-29 21:34:02 +00:00
bellard
d014c98c8d sparc support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@119 c046a42c-6fe2-441c-8c8c-71466251a162
2003-04-29 21:26:53 +00:00
bellard
a98fd896cd target cpu definition
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@118 c046a42c-6fe2-441c-8c8c-71466251a162
2003-04-29 21:24:12 +00:00
bellard
d6cdca958e alpha support - ia64 support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@117 c046a42c-6fe2-441c-8c8c-71466251a162
2003-04-29 21:24:00 +00:00
bellard
efdea7bf19 ia64 support - alpha support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@116 c046a42c-6fe2-441c-8c8c-71466251a162
2003-04-29 21:12:28 +00:00
bellard
0d3301964d ia64 support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@115 c046a42c-6fe2-441c-8c8c-71466251a162
2003-04-29 21:10:09 +00:00
bellard
fe1e3ce3e9 fcntl constants
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@114 c046a42c-6fe2-441c-8c8c-71466251a162
2003-04-29 21:09:46 +00:00
bellard
bb326a3749 fix _start routine name
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@113 c046a42c-6fe2-441c-8c8c-71466251a162
2003-04-29 21:08:48 +00:00
bellard
27725c1d74 ia64 support - fcntl uses TARGET_ constants
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@112 c046a42c-6fe2-441c-8c8c-71466251a162
2003-04-29 21:08:18 +00:00
bellard
e026db5893 alpha support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@111 c046a42c-6fe2-441c-8c8c-71466251a162
2003-04-29 21:07:28 +00:00
bellard
43f04c233c alpha support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@110 c046a42c-6fe2-441c-8c8c-71466251a162
2003-04-29 20:53:42 +00:00
bellard
a8baa8c555 ia64 support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@109 c046a42c-6fe2-441c-8c8c-71466251a162
2003-04-29 20:53:31 +00:00
bellard
728584be27 fstat64 fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@108 c046a42c-6fe2-441c-8c8c-71466251a162
2003-04-29 20:43:36 +00:00
bellard
b9adb4a6bc PowerPC disas code
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@107 c046a42c-6fe2-441c-8c8c-71466251a162
2003-04-29 20:41:16 +00:00
bellard
ae48a07313 flock
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@106 c046a42c-6fe2-441c-8c8c-71466251a162
2003-04-29 20:41:02 +00:00
bellard
956034d7e5 log fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@105 c046a42c-6fe2-441c-8c8c-71466251a162
2003-04-29 20:40:53 +00:00
bellard
6cd9f35b9b update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@104 c046a42c-6fe2-441c-8c8c-71466251a162
2003-04-29 20:40:35 +00:00
bellard
689f936f7e symbol fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@103 c046a42c-6fe2-441c-8c8c-71466251a162
2003-04-29 20:40:07 +00:00
bellard
6977fbfd8b loglevel export
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@102 c046a42c-6fe2-441c-8c8c-71466251a162
2003-04-29 20:39:23 +00:00
bellard
77e4672d8d flock support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@101 c046a42c-6fe2-441c-8c8c-71466251a162
2003-04-29 20:39:06 +00:00
bellard
d34720fd7d comment
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@100 c046a42c-6fe2-441c-8c8c-71466251a162
2003-04-29 20:37:44 +00:00
bellard
d9c4d1cc1a cleanup
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@99 c046a42c-6fe2-441c-8c8c-71466251a162
2003-04-29 20:37:14 +00:00
bellard
f644caa51a update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@98 c046a42c-6fe2-441c-8c8c-71466251a162
2003-04-11 01:17:32 +00:00
107 changed files with 39285 additions and 6810 deletions

View File

@@ -1,36 +1,14 @@
------------------------------------------------------------------------------
NOTE:
Some code of the Twin package was modified for DOSEMU by the DOSEMU-team.
The original is 'Copyright 1997 Willows Software, Inc.' and generously
was put under the GNU Library General Public License.
( for more information see http://www.willows.com/ )
GNU LESSER GENERAL PUBLIC LICENSE
Version 2.1, February 1999
We make use of section 3 of the GNU Library General Public License
('...opt to apply the terms of the ordinary GNU General Public License...'),
because the resulting product is an integrated part of DOSEMU and
can not be considered to be a 'library' in the terms of Library License.
Therefore, the below GNU LIBRARY GENERAL PUBLIC LICENSE applies only to the
_unchanged_ Twin package from Willows. For the DOSEMU-changed parts the normal
GNU GENERAL PUBLIC LICENSE applies. This GPL (file COPYING) can be found in
the root directory of the DOSEMU distribution.
The act of transformation to GPL was indicated to the maintainer of the Twin
package (Rob Penrose <rob@Canopy.Com>) and he acknowledge agreement.
Nov. 1 1997, The DOSEMU team.
------------------------------------------------------------------------------
GNU LIBRARY GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1991 Free Software Foundation, Inc.
675 Mass Ave, Cambridge, MA 02139, USA
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
[This is the first released version of the library GPL. It is
numbered 2 because it goes with version 2 of the ordinary GPL.]
[This is the first released version of the Lesser GPL. It also counts
as the successor of the GNU Library Public License, version 2, hence
the version number 2.1.]
Preamble
@@ -39,97 +17,109 @@ freedom to share and change it. By contrast, the GNU General Public
Licenses are intended to guarantee your freedom to share and change
free software--to make sure the software is free for all its users.
This license, the Library General Public License, applies to some
specially designated Free Software Foundation software, and to any
other libraries whose authors decide to use it. You can use it for
your libraries, too.
This license, the Lesser General Public License, applies to some
specially designated software packages--typically libraries--of the
Free Software Foundation and other authors who decide to use it. You
can use it too, but we suggest you first think carefully about whether
this license or the ordinary General Public License is the better
strategy to use in any particular case, based on the explanations below.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
When we speak of free software, we are referring to freedom of use,
not price. Our General Public Licenses are designed to make sure that
you have the freedom to distribute copies of free software (and charge
for this service if you wish); that you receive source code or can get
it if you want it; that you can change the software and use pieces of
it in new free programs; and that you are informed that you can do
these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if
you distribute copies of the library, or if you modify it.
distributors to deny you these rights or to ask you to surrender these
rights. These restrictions translate to certain responsibilities for
you if you distribute copies of the library or if you modify it.
For example, if you distribute copies of the library, whether gratis
or for a fee, you must give the recipients all the rights that we gave
you. You must make sure that they, too, receive or can get the source
code. If you link a program with the library, you must provide
complete object files to the recipients so that they can relink them
with the library, after making changes to the library and recompiling
code. If you link other code with the library, you must provide
complete object files to the recipients, so that they can relink them
with the library after making changes to the library and recompiling
it. And you must show them these terms so they know their rights.
Our method of protecting your rights has two steps: (1) copyright
the library, and (2) offer you this license which gives you legal
We protect your rights with a two-step method: (1) we copyright the
library, and (2) we offer you this license, which gives you legal
permission to copy, distribute and/or modify the library.
Also, for each distributor's protection, we want to make certain
that everyone understands that there is no warranty for this free
library. If the library is modified by someone else and passed on, we
want its recipients to know that what they have is not the original
version, so that any problems introduced by others will not reflect on
the original authors' reputations.
To protect each distributor, we want to make it very clear that
there is no warranty for the free library. Also, if the library is
modified by someone else and passed on, the recipients should know
that what they have is not the original version, so that the original
author's reputation will not be affected by problems that might be
introduced by others.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that companies distributing free
software will individually obtain patent licenses, thus in effect
transforming the program into proprietary software. To prevent this,
we have made it clear that any patent must be licensed for everyone's
free use or not licensed at all.
Finally, software patents pose a constant threat to the existence of
any free program. We wish to make sure that a company cannot
effectively restrict the users of a free program by obtaining a
restrictive license from a patent holder. Therefore, we insist that
any patent license obtained for a version of the library must be
consistent with the full freedom of use specified in this license.
Most GNU software, including some libraries, is covered by the ordinary
GNU General Public License, which was designed for utility programs. This
license, the GNU Library General Public License, applies to certain
designated libraries. This license is quite different from the ordinary
one; be sure to read it in full, and don't assume that anything in it is
the same as in the ordinary license.
Most GNU software, including some libraries, is covered by the
ordinary GNU General Public License. This license, the GNU Lesser
General Public License, applies to certain designated libraries, and
is quite different from the ordinary General Public License. We use
this license for certain libraries in order to permit linking those
libraries into non-free programs.
The reason we have a separate public license for some libraries is that
they blur the distinction we usually make between modifying or adding to a
program and simply using it. Linking a program with a library, without
changing the library, is in some sense simply using the library, and is
analogous to running a utility program or application program. However, in
a textual and legal sense, the linked executable is a combined work, a
derivative of the original library, and the ordinary General Public License
treats it as such.
When a program is linked with a library, whether statically or using
a shared library, the combination of the two is legally speaking a
combined work, a derivative of the original library. The ordinary
General Public License therefore permits such linking only if the
entire combination fits its criteria of freedom. The Lesser General
Public License permits more lax criteria for linking other code with
the library.
Because of this blurred distinction, using the ordinary General
Public License for libraries did not effectively promote software
sharing, because most developers did not use the libraries. We
concluded that weaker conditions might promote sharing better.
We call this license the "Lesser" General Public License because it
does Less to protect the user's freedom than the ordinary General
Public License. It also provides other free software developers Less
of an advantage over competing non-free programs. These disadvantages
are the reason we use the ordinary General Public License for many
libraries. However, the Lesser license provides advantages in certain
special circumstances.
However, unrestricted linking of non-free programs would deprive the
users of those programs of all benefit from the free status of the
libraries themselves. This Library General Public License is intended to
permit developers of non-free programs to use free libraries, while
preserving your freedom as a user of such programs to change the free
libraries that are incorporated in them. (We have not seen how to achieve
this as regards changes in header files, but we have achieved it as regards
changes in the actual functions of the Library.) The hope is that this
will lead to faster development of free libraries.
For example, on rare occasions, there may be a special need to
encourage the widest possible use of a certain library, so that it becomes
a de-facto standard. To achieve this, non-free programs must be
allowed to use the library. A more frequent case is that a free
library does the same job as widely used non-free libraries. In this
case, there is little to gain by limiting the free library to free
software only, so we use the Lesser General Public License.
In other cases, permission to use a particular library in non-free
programs enables a greater number of people to use a large body of
free software. For example, permission to use the GNU C Library in
non-free programs enables many more people to use the whole GNU
operating system, as well as its variant, the GNU/Linux operating
system.
Although the Lesser General Public License is Less protective of the
users' freedom, it does ensure that the user of a program that is
linked with the Library has the freedom and the wherewithal to run
that program using a modified version of the Library.
The precise terms and conditions for copying, distribution and
modification follow. Pay close attention to the difference between a
"work based on the library" and a "work that uses the library". The
former contains code derived from the library, while the latter only
works together with the library.
Note that it is possible for a library to be covered by the ordinary
General Public License rather than by this special one.
former contains code derived from the library, whereas the latter must
be combined with the library in order to run.
GNU LIBRARY GENERAL PUBLIC LICENSE
GNU LESSER GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License Agreement applies to any software library which
contains a notice placed by the copyright holder or other authorized
party saying it may be distributed under the terms of this Library
General Public License (also called "this License"). Each licensee is
addressed as "you".
0. This License Agreement applies to any software library or other
program which contains a notice placed by the copyright holder or
other authorized party saying it may be distributed under the terms of
this Lesser General Public License (also called "this License").
Each licensee is addressed as "you".
A "library" means a collection of software functions and/or data
prepared so as to be conveniently linked with application programs
@@ -278,7 +268,7 @@ distribute the object code for the work under the terms of Section 6.
Any executables containing that work also fall under Section 6,
whether or not they are linked directly with the Library itself.
6. As an exception to the Sections above, you may also compile or
6. As an exception to the Sections above, you may also combine or
link a "work that uses the Library" with the Library to produce a
work containing portions of the Library, and distribute that work
under terms of your choice, provided that the terms permit
@@ -305,23 +295,31 @@ of these things:
Library will not necessarily be able to recompile the application
to use the modified definitions.)
b) Accompany the work with a written offer, valid for at
b) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (1) uses at run time a
copy of the library already present on the user's computer system,
rather than copying library functions into the executable, and (2)
will operate properly with a modified version of the library, if
the user installs one, as long as the modified version is
interface-compatible with the version that the work was made with.
c) Accompany the work with a written offer, valid for at
least three years, to give the same user the materials
specified in Subsection 6a, above, for a charge no more
than the cost of performing this distribution.
c) If distribution of the work is made by offering access to copy
d) If distribution of the work is made by offering access to copy
from a designated place, offer equivalent access to copy the above
specified materials from the same place.
d) Verify that the user has already received a copy of these
e) Verify that the user has already received a copy of these
materials or that you have already sent this user a copy.
For an executable, the required form of the "work that uses the
Library" must include any data and utility programs needed for
reproducing the executable from it. However, as a special exception,
the source code distributed need not include anything that is normally
distributed (in either source or binary form) with the major
the materials to be distributed need not include anything that is
normally distributed (in either source or binary form) with the major
components (compiler, kernel, and so on) of the operating system on
which the executable runs, unless that component itself accompanies
the executable.
@@ -370,7 +368,7 @@ Library), the recipient automatically receives a license from the
original licensor to copy, distribute, link with or modify the Library
subject to these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
You are not responsible for enforcing compliance by third parties with
this License.
11. If, as a consequence of a court judgment or allegation of patent
@@ -413,7 +411,7 @@ excluded. In such case, this License incorporates the limitation as if
written in the body of this License.
13. The Free Software Foundation may publish revised and/or new
versions of the Library General Public License from time to time.
versions of the Lesser General Public License from time to time.
Such new versions will be similar in spirit to the present version,
but may differ in detail to address new problems or concerns.
@@ -459,7 +457,7 @@ DAMAGES.
END OF TERMS AND CONDITIONS
Appendix: How to Apply These Terms to Your New Libraries
How to Apply These Terms to Your New Libraries
If you develop a new library, and you want it to be of the greatest
possible use to the public, we recommend making it free software that
@@ -476,18 +474,18 @@ convey the exclusion of warranty; and each file should have at least the
Copyright (C) <year> <name of author>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
Lesser General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Also add information on how to contact you by electronic and paper mail.
@@ -502,3 +500,5 @@ necessary. Here is a sample; alter the names:
Ty Coon, President of Vice
That's all there is to it!

View File

@@ -1,3 +1,88 @@
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 mmy 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
- fixed signal handling for correct dosemu DPMI emulation
- fast x86 MMU emulation with mmap()
- fixed popl (%esp) case
- Linux kernel can be executed by QEMU with the 'vl' command.
version 0.3:
- initial support for ARM emulation
- added fnsave, frstor, fnstenv, fldenv FPU instructions
- added FPU register save in signal emulation
- initial ARM port
- Sparc and Alpha ports work on the regression test
- generic ioctl number conversion
- fixed ioctl type conversion
version 0.2:
- PowerPC disassembly and ELF symbols output (Rusty Russell)
- flock support (Rusty Russell)
- ugetrlimit support (Rusty Russell)
- fstat64 fix (Rusty Russell)
- initial Alpha port (Falk Hueffner)
- initial IA64 port (Matt Wilson)
- initial Sparc and Sparc64 port (David S. Miller)
- added HLT instruction
- LRET instruction fix.
- added GPF generation for I/Os.
- added INT3 and TF flag support.
- SHL instruction C flag fix.
- mmap emulation for host page size > 4KB
- self-modifying code support
- better VM86 support (dosemu works on non trivial programs)
- precise exception support (EIP is computed correctly in most cases)
- more precise LDT/GDT/IDT emulation
- faster segment load in vm86 mode
- direct chaining of basic blocks (faster emulation)
version 0.1.6:
- automatic library search system. QEMU can now work with unpatched

138
Makefile
View File

@@ -1,131 +1,71 @@
include config.mak
include config-host.mak
CFLAGS=-Wall -O2 -g
LDFLAGS=-g
LIBS=
DEFINES=-DHAVE_BYTESWAP_H
ifeq ($(ARCH),i386)
CFLAGS+=-fomit-frame-pointer
OP_CFLAGS=$(CFLAGS) -mpreferred-stack-boundary=2
ifeq ($(GCC_MAJOR),3)
OP_CFLAGS+= -falign-functions=0
else
OP_CFLAGS+= -malign-functions=0
endif
# 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 ($(ARCH),ppc)
OP_CFLAGS=$(CFLAGS)
LDFLAGS+=-Wl,-T,ppc.ld
endif
ifeq ($(ARCH),s390)
OP_CFLAGS=$(CFLAGS)
LDFLAGS+=-Wl,-T,s390.ld
endif
ifeq ($(GCC_MAJOR),3)
# very important to generate a return at the end of every operation
OP_CFLAGS+=-fno-reorder-blocks -fno-optimize-sibling-calls
endif
#########################################################
DEFINES+=-D_GNU_SOURCE
LIBS+=-lm
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 signal.o path.o
SRCS:= $(OBJS:.o=.c)
OBJS+= libqemu.a
qemu-mkcow: qemu-mkcow.o
$(HOST_CC) -o $@ $^ $(LIBS)
LIBOBJS+=thunk.o translate-i386.o op-i386.o exec-i386.o
# NOTE: the disassembler code is only needed for debugging
LIBOBJS+=i386-dis.o dis-buf.o
all: qemu qemu-doc.html
qemu: $(OBJS)
$(CC) $(LDFLAGS) -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-i386.o: translate-i386.c op-i386.h cpu-i386.h
op-i386.h: op-i386.o dyngen
./dyngen -o $@ $<
op-i386.o: op-i386.c opreg_template.h ops_template.h
$(CC) $(OP_CFLAGS) $(DEFINES) -c -o $@ $<
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 -f $$d/config.h $$d/config.mak || exit 1 ; \
done
install: qemu
install -m 755 -s qemu $(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: all
make -C tests $@
TAGS:
etags *.[ch] i386/*.[ch]
etags *.[ch] tests/*.[ch]
# documentation
qemu-doc.html: qemu-doc.texi
texi2html -monolithic -number $<
FILES= \
README README.distrib COPYING COPYING.LIB TODO Changelog VERSION \
dyngen.c ioctls.h ops_template.h op_string.h syscall_types.h\
Makefile elf.h thunk.c\
elfload.c main.c signal.c thunk.h\
cpu-i386.h qemu.h op-i386.c opc-i386.h syscall-i386.h translate-i386.c\
dis-asm.h gen-i386.h syscall.c\
dis-buf.c i386-dis.c opreg_template.h syscall_defs.h\
ppc.ld s390.ld exec-i386.h exec-i386.c path.c configure \
tests/Makefile\
tests/test-i386.c tests/test-i386-shift.h tests/test-i386.h\
tests/test-i386-muldiv.h tests/test-i386-code16.S\
tests/hello.c tests/hello tests/sha1.c \
tests/testsig.c tests/testclone.c tests/testthread.c \
tests/runcom.c tests/pi_10.com \
tests/test_path.c \
qemu-doc.texi qemu-doc.html
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)
cp -r . /tmp/$(FILE)
( cd /tmp ; tar zcvf ~/$(FILE).tar.gz $(FILE) )
rm -rf /tmp/$(FILE)

227
Makefile.target Normal file
View File

@@ -0,0 +1,227 @@
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 ($(ARCH),i386)
ifeq ($(TARGET_ARCH), i386)
PROGS+=$(QEMU_SYSTEM)
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
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
# 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 vga.o
ifdef CONFIG_SDL
VL_OBJS+=sdl.o
SDL_LIBS+=-L/usr/X11R6/lib -lX11 -lXext -lXv -ldl -lm
endif
$(QEMU_SYSTEM): $(VL_OBJS) libqemu.a
$(CC) -static -Wl,-T,$(SRC_PATH)/i386-vl.ld -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

46
README
View File

@@ -6,35 +6,51 @@ 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
to install QEMU in /usr/local
* On x86 you should be able to launch any program by using the
libraries installed on your PC. For example:
Tested tool versions
--------------------
./qemu -L / /bin/ls
In order to compile QEMU succesfully, it is very important that you
have the right tools. The most important one is gcc. I cannot guaranty
that QEMU works if you do not use a tested gcc version. Look at
'configure' and 'Makefile' if you want to make a different gcc
version work.
* 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:
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
unset LD_LIBRARY_PATH
PowerPC 3.3 [4] 2.13.90.0.18 2.3.1 2.4.20briq
3.2
Then you can launch the precompiled 'ls' x86 executable:
Alpha 3.3 [1] 2.14.90.0.4 2.2.5 2.2.20 [2] Debian 3.0
./qemu /usr/local/qemu-i386/bin/ls-i386
Sparc32 2.95.4 2.12.90.0.1 2.2.5 2.4.18 Debian 3.0
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.
ARM 2.95.4 2.12.90.0.1 2.2.5 2.4.9 [3] Debian 3.0
[1] On Alpha, QEMU needs the gcc 'visibility' attribute only available
for gcc version >= 3.3.
[2] Linux >= 2.4.20 is necessary for precise exception support
(untested).
[3] 2.4.9-ac10-rmk2-np1-cerf2
[4] gcc 2.95.x generates invalid code when using too many register
variables. You must use gcc 3.x on PowerPC.
Documentation
-------------

16
README.distrib Normal file
View File

@@ -0,0 +1,16 @@
Information about the various packages used to build the current qemu
x86 binary distribution:
* gcc 2.95.2 was used for the build. A glibc 2.1.3 Debian distribution
was used to get most of the binary packages.
* wine-20020411 tarball
./configure --prefix=/usr/local/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-i386 /usr/gnemul/qemu-i386/bin/ldconfig-i386 -C /usr/gnemul/qemu-i386/etc/ld.so.cache

37
TODO
View File

@@ -1,12 +1,29 @@
- fix thread locks
- optimize translated cache chaining (DLL PLT-like system)
- fix thread stack liberation (use kernel 2.5.xxx CLONE_CHILD_CLEARTID)
- fix x86 stack allocation
- fix iret/lret restarting
- tests for each target CPU
- ppc qemu test
- optimize FPU operations (evaluate x87 stack pointer statically) and
fix cr0.TS emulation
- fix some 16 bit sp push/pop overflow
- sysenter/sysexit emulation
- finish segment ops (call far, ret far, load_seg suppressed)
- fix CCOP optimisation
- fix all remaining thread lock issues (must put TBs in a specific invalid
state, find a solution for tb_flush()).
- cpu loop optimisation (optimise ret case as the cpu state does not change)
- 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
in syscall emulation code).
- fix thread stack freeing (use kernel 2.5.x CLONE_CHILD_CLEARTID)
- more syscalls (in particular all 64 bit ones, IPCs, fix 64 bit
issues, fix 16 bit uid issues)
- finish signal handing (fp87 state, more siginfo conversions)
- verify thread support (clone() and various locks)
- make it self runnable (handle self modifying code, relocate stack
and dyn loader)
- fix FPU exceptions (in particular: gen_op_fpush not before mem load)
- use page_unprotect_range in every suitable syscall to handle all
cases of self modifying code.
- use gcc as a backend to generate better code (easy to do by using
op-i386.c operations as local inline functions).
- add SSE2/MMX operations

View File

@@ -1 +1 @@
0.1.6
0.5.0

1963
alpha-dis.c Normal file

File diff suppressed because it is too large Load Diff

128
alpha.ld Normal file
View File

@@ -0,0 +1,128 @@
OUTPUT_FORMAT("elf64-alpha", "elf64-alpha",
"elf64-alpha")
OUTPUT_ARCH(alpha)
ENTRY(__start)
SEARCH_DIR(/lib); SEARCH_DIR(/usr/lib); SEARCH_DIR(/usr/local/lib); SEARCH_DIR(/usr/alpha-unknown-linux-gnu/lib);
SECTIONS
{
/* Read-only sections, merged into text segment: */
. = 0x60000000 + SIZEOF_HEADERS;
.interp : { *(.interp) }
.hash : { *(.hash) }
.dynsym : { *(.dynsym) }
.dynstr : { *(.dynstr) }
.gnu.version : { *(.gnu.version) }
.gnu.version_d : { *(.gnu.version_d) }
.gnu.version_r : { *(.gnu.version_r) }
.rel.text :
{ *(.rel.text) *(.rel.gnu.linkonce.t*) }
.rela.text :
{ *(.rela.text) *(.rela.gnu.linkonce.t*) }
.rel.data :
{ *(.rel.data) *(.rel.gnu.linkonce.d*) }
.rela.data :
{ *(.rela.data) *(.rela.gnu.linkonce.d*) }
.rel.rodata :
{ *(.rel.rodata) *(.rel.gnu.linkonce.r*) }
.rela.rodata :
{ *(.rela.rodata) *(.rela.gnu.linkonce.r*) }
.rel.got : { *(.rel.got) }
.rela.got : { *(.rela.got) }
.rel.ctors : { *(.rel.ctors) }
.rela.ctors : { *(.rela.ctors) }
.rel.dtors : { *(.rel.dtors) }
.rela.dtors : { *(.rela.dtors) }
.rel.init : { *(.rel.init) }
.rela.init : { *(.rela.init) }
.rel.fini : { *(.rel.fini) }
.rela.fini : { *(.rela.fini) }
.rel.bss : { *(.rel.bss) }
.rela.bss : { *(.rela.bss) }
.rel.plt : { *(.rel.plt) }
.rela.plt : { *(.rela.plt) }
.init : { *(.init) } =0x47ff041f
.text :
{
*(.text)
/* .gnu.warning sections are handled specially by elf32.em. */
*(.gnu.warning)
*(.gnu.linkonce.t*)
} =0x47ff041f
_etext = .;
PROVIDE (etext = .);
.fini : { *(.fini) } =0x47ff041f
.rodata : { *(.rodata) *(.gnu.linkonce.r*) }
.rodata1 : { *(.rodata1) }
.reginfo : { *(.reginfo) }
/* Adjust the address for the data segment. We want to adjust up to
the same address within the page on the next page up. */
. = ALIGN(0x100000) + (. & (0x100000 - 1));
.data :
{
*(.data)
*(.gnu.linkonce.d*)
CONSTRUCTORS
}
.data1 : { *(.data1) }
.ctors :
{
*(.ctors)
}
.dtors :
{
*(.dtors)
}
.plt : { *(.plt) }
.got : { *(.got.plt) *(.got) }
.dynamic : { *(.dynamic) }
/* We want the small data sections together, so single-instruction offsets
can access them all, and initialized data all before uninitialized, so
we can shorten the on-disk segment size. */
.sdata : { *(.sdata) }
_edata = .;
PROVIDE (edata = .);
__bss_start = .;
.sbss : { *(.sbss) *(.scommon) }
.bss :
{
*(.dynbss)
*(.bss)
*(COMMON)
}
_end = . ;
PROVIDE (end = .);
/* Stabs debugging sections. */
.stab 0 : { *(.stab) }
.stabstr 0 : { *(.stabstr) }
.stab.excl 0 : { *(.stab.excl) }
.stab.exclstr 0 : { *(.stab.exclstr) }
.stab.index 0 : { *(.stab.index) }
.stab.indexstr 0 : { *(.stab.indexstr) }
.comment 0 : { *(.comment) }
/* DWARF debug sections.
Symbols in the DWARF debugging sections are relative to the beginning
of the section so we begin them at 0. */
/* DWARF 1 */
.debug 0 : { *(.debug) }
.line 0 : { *(.line) }
/* GNU DWARF 1 extensions */
.debug_srcinfo 0 : { *(.debug_srcinfo) }
.debug_sfnames 0 : { *(.debug_sfnames) }
/* DWARF 1.1 and DWARF 2 */
.debug_aranges 0 : { *(.debug_aranges) }
.debug_pubnames 0 : { *(.debug_pubnames) }
/* DWARF 2 */
.debug_info 0 : { *(.debug_info) }
.debug_abbrev 0 : { *(.debug_abbrev) }
.debug_line 0 : { *(.debug_line) }
.debug_frame 0 : { *(.debug_frame) }
.debug_str 0 : { *(.debug_str) }
.debug_loc 0 : { *(.debug_loc) }
.debug_macinfo 0 : { *(.debug_macinfo) }
/* SGI/MIPS DWARF 2 extensions */
.debug_weaknames 0 : { *(.debug_weaknames) }
.debug_funcnames 0 : { *(.debug_funcnames) }
.debug_typenames 0 : { *(.debug_typenames) }
.debug_varnames 0 : { *(.debug_varnames) }
/* These must appear regardless of . */
}

1675
arm-dis.c Normal file

File diff suppressed because it is too large Load Diff

128
arm.ld Normal file
View File

@@ -0,0 +1,128 @@
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm",
"elf32-littlearm")
OUTPUT_ARCH(arm)
ENTRY(_start)
SEARCH_DIR(/lib); SEARCH_DIR(/usr/lib); SEARCH_DIR(/usr/local/lib); SEARCH_DIR(/usr/alpha-unknown-linux-gnu/lib);
SECTIONS
{
/* Read-only sections, merged into text segment: */
. = 0x60000000 + SIZEOF_HEADERS;
.interp : { *(.interp) }
.hash : { *(.hash) }
.dynsym : { *(.dynsym) }
.dynstr : { *(.dynstr) }
.gnu.version : { *(.gnu.version) }
.gnu.version_d : { *(.gnu.version_d) }
.gnu.version_r : { *(.gnu.version_r) }
.rel.text :
{ *(.rel.text) *(.rel.gnu.linkonce.t*) }
.rela.text :
{ *(.rela.text) *(.rela.gnu.linkonce.t*) }
.rel.data :
{ *(.rel.data) *(.rel.gnu.linkonce.d*) }
.rela.data :
{ *(.rela.data) *(.rela.gnu.linkonce.d*) }
.rel.rodata :
{ *(.rel.rodata) *(.rel.gnu.linkonce.r*) }
.rela.rodata :
{ *(.rela.rodata) *(.rela.gnu.linkonce.r*) }
.rel.got : { *(.rel.got) }
.rela.got : { *(.rela.got) }
.rel.ctors : { *(.rel.ctors) }
.rela.ctors : { *(.rela.ctors) }
.rel.dtors : { *(.rel.dtors) }
.rela.dtors : { *(.rela.dtors) }
.rel.init : { *(.rel.init) }
.rela.init : { *(.rela.init) }
.rel.fini : { *(.rel.fini) }
.rela.fini : { *(.rela.fini) }
.rel.bss : { *(.rel.bss) }
.rela.bss : { *(.rela.bss) }
.rel.plt : { *(.rel.plt) }
.rela.plt : { *(.rela.plt) }
.init : { *(.init) } =0x47ff041f
.text :
{
*(.text)
/* .gnu.warning sections are handled specially by elf32.em. */
*(.gnu.warning)
*(.gnu.linkonce.t*)
} =0x47ff041f
_etext = .;
PROVIDE (etext = .);
.fini : { *(.fini) } =0x47ff041f
.rodata : { *(.rodata) *(.gnu.linkonce.r*) }
.rodata1 : { *(.rodata1) }
.reginfo : { *(.reginfo) }
/* Adjust the address for the data segment. We want to adjust up to
the same address within the page on the next page up. */
. = ALIGN(0x100000) + (. & (0x100000 - 1));
.data :
{
*(.data)
*(.gnu.linkonce.d*)
CONSTRUCTORS
}
.data1 : { *(.data1) }
.ctors :
{
*(.ctors)
}
.dtors :
{
*(.dtors)
}
.plt : { *(.plt) }
.got : { *(.got.plt) *(.got) }
.dynamic : { *(.dynamic) }
/* We want the small data sections together, so single-instruction offsets
can access them all, and initialized data all before uninitialized, so
we can shorten the on-disk segment size. */
.sdata : { *(.sdata) }
_edata = .;
PROVIDE (edata = .);
__bss_start = .;
.sbss : { *(.sbss) *(.scommon) }
.bss :
{
*(.dynbss)
*(.bss)
*(COMMON)
}
_end = . ;
PROVIDE (end = .);
/* Stabs debugging sections. */
.stab 0 : { *(.stab) }
.stabstr 0 : { *(.stabstr) }
.stab.excl 0 : { *(.stab.excl) }
.stab.exclstr 0 : { *(.stab.exclstr) }
.stab.index 0 : { *(.stab.index) }
.stab.indexstr 0 : { *(.stab.indexstr) }
.comment 0 : { *(.comment) }
/* DWARF debug sections.
Symbols in the DWARF debugging sections are relative to the beginning
of the section so we begin them at 0. */
/* DWARF 1 */
.debug 0 : { *(.debug) }
.line 0 : { *(.line) }
/* GNU DWARF 1 extensions */
.debug_srcinfo 0 : { *(.debug_srcinfo) }
.debug_sfnames 0 : { *(.debug_sfnames) }
/* DWARF 1.1 and DWARF 2 */
.debug_aranges 0 : { *(.debug_aranges) }
.debug_pubnames 0 : { *(.debug_pubnames) }
/* DWARF 2 */
.debug_info 0 : { *(.debug_info) }
.debug_abbrev 0 : { *(.debug_abbrev) }
.debug_line 0 : { *(.debug_line) }
.debug_frame 0 : { *(.debug_frame) }
.debug_str 0 : { *(.debug_str) }
.debug_loc 0 : { *(.debug_loc) }
.debug_macinfo 0 : { *(.debug_macinfo) }
/* SGI/MIPS DWARF 2 extensions */
.debug_weaknames 0 : { *(.debug_weaknames) }
.debug_funcnames 0 : { *(.debug_funcnames) }
.debug_typenames 0 : { *(.debug_typenames) }
.debug_varnames 0 : { *(.debug_varnames) }
/* These must appear regardless of . */
}

326
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 */

286
configure vendored
View File

@@ -15,11 +15,11 @@ 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"
host_cc="gcc"
@@ -27,9 +27,10 @@ ar="ar"
make="make"
strip="strip"
cpu=`uname -m`
target_list="i386-user i386 i386-softmmu arm-user sparc-user"
case "$cpu" in
i386|i486|i586|i686|i86pc|BePC)
cpu="x86"
cpu="i386"
;;
armv4l)
cpu="armv4l"
@@ -46,6 +47,18 @@ case "$cpu" in
s390)
cpu="s390"
;;
sparc)
cpu="sparc"
;;
sparc64)
cpu="sparc64"
;;
ia64)
cpu="ia64"
;;
m68k)
cpu="m68k"
;;
*)
cpu="unknown"
;;
@@ -56,25 +69,29 @@ bigendian="no"
# OS specific
targetos=`uname -s`
case $targetos in
BeOS)
prefix="/boot/home/config"
# helps building libavcodec
CFLAGS="-O2 -DPIC"
# no need for libm, but the inet stuff
# Check for BONE
if (echo $BEINCLUDES|grep 'headers/be/bone' >/dev/null); then
extralibs="-lbind -lsocket"
else
echo "Not sure building for net_server will succeed... good luck."
extralibs="-lsocket"
fi ;;
BSD/OS)
extralibs="-lpoll -lgnugetopt -lm"
make="gmake"
;;
*) ;;
esac
##########################################
# 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.
@@ -108,8 +125,14 @@ for opt do
;;
--cpu=*) cpu=`echo $opt | cut -d '=' -f 2`
;;
--target-list=*) target_list=${opt#--target-list=}
;;
--enable-gprof) gprof="yes"
;;
--static) static="yes"
;;
--disable-sdl) sdl="no"
;;
esac
done
@@ -143,26 +166,21 @@ fi
else
# if cross compiling, cannot launch a program, so make a static guess
if test "$cpu" = "powerpc" -o "$cpu" = "mips" -o "$cpu" = "s390" ; then
if test "$cpu" = "powerpc" -o "$cpu" = "mips" -o "$cpu" = "s390" -o "$cpu" = "sparc" -o "$cpu" = "sparc64" -o "$cpu" = "m68k"; then
bigendian="yes"
fi
fi
# check gcc version
# check gcc options support
cat > $TMPC <<EOF
int main(void) {
#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 2)
return 0;
#else
#error gcc < 3.2
#endif
}
EOF
gcc_major="2"
if $cc -o $TMPO $TMPC 2> /dev/null ; then
gcc_major="3"
have_gcc3_options="no"
if $cc -fno-reorder-blocks -fno-optimize-sibling-calls -o $TMPO $TMPC 2> /dev/null ; then
have_gcc3_options="yes"
fi
if test x"$1" = x"-h" -o x"$1" = x"--help" ; then
@@ -175,81 +193,187 @@ 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 " --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]"
echo " --cross-prefix=PREFIX use PREFIX for compile tools [$cross_prefix]"
echo " --cc=CC use C compiler CC [$cc]"
echo " --make=MAKE use specified make [$make]"
echo " --static enable static build [$static]"
echo ""
echo "NOTE: The object files are build at the place where configure is launched"
exit 1
fi
echo "Install prefix $prefix"
echo "Source path $source_path"
echo "C compiler $cc"
echo "make $make"
echo "CPU $cpu"
echo "Big Endian $bigendian"
echo "gprof enabled $gprof"
mandir="$prefix/share/man"
sharedir="$prefix/share/qemu"
echo "Creating config.mak and config.h"
echo "Install prefix $prefix"
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 list $target_list"
echo "gprof enabled $gprof"
echo "static build $static"
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 "# Automatically generated by configure - do not modify" > config.mak
echo "/* Automatically generated by configure - do not modify */" > $TMPH
config_mak="config-host.mak"
config_h="config-host.h"
echo "prefix=$prefix" >> config.mak
echo "#define CONFIG_QEMU_PREFIX \"$interp_prefix\"" >> $TMPH
echo "MAKE=$make" >> config.mak
echo "CC=$cc" >> config.mak
echo "GCC_MAJOR=$gcc_major" >> config.mak
echo "HOST_CC=$host_cc" >> config.mak
echo "AR=$ar" >> config.mak
echo "STRIP=$strip -s -R .comment -R .note" >> config.mak
echo "CFLAGS=$CFLAGS" >> config.mak
echo "LDFLAGS=$LDFLAGS" >> config.mak
if test "$cpu" = "x86" ; then
echo "ARCH=i386" >> config.mak
echo "#define HOST_I386 1" >> $TMPH
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" >> $config_h
elif test "$cpu" = "sparc64" ; then
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" >> $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" >> $TMPH
echo "TARGET_GPROF=yes" >> $config_mak
echo "#define HAVE_GPROF 1" >> $config_h
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
if test "$network" = "yes" ; then
echo "#define CONFIG_NETWORK 1" >> $TMPH
echo "CONFIG_NETWORK=yes" >> config.mak
if test "$static" = "yes" ; then
echo "CONFIG_STATIC=yes" >> $config_mak
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_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_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
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\"" >> $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
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" >> $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
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
@@ -262,13 +386,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

439
cpu-all.h Normal file
View File

@@ -0,0 +1,439 @@
/*
* defines common to all virtual CPUs
*
* Copyright (c) 2003 Fabrice Bellard
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef CPU_ALL_H
#define CPU_ALL_H
/* CPU memory access without any memory or io remapping */
static inline int ldub_raw(void *ptr)
{
return *(uint8_t *)ptr;
}
static inline int ldsb_raw(void *ptr)
{
return *(int8_t *)ptr;
}
static inline void stb_raw(void *ptr, int v)
{
*(uint8_t *)ptr = v;
}
/* NOTE: on arm, putting 2 in /proc/sys/debug/alignment so that the
kernel handles unaligned load/stores may give better results, but
it is a system wide setting : bad */
#if defined(WORDS_BIGENDIAN) || defined(__arm__)
/* conservative code for little endian unaligned accesses */
static inline int lduw_raw(void *ptr)
{
#ifdef __powerpc__
int val;
__asm__ __volatile__ ("lhbrx %0,0,%1" : "=r" (val) : "r" (ptr));
return val;
#else
uint8_t *p = ptr;
return p[0] | (p[1] << 8);
#endif
}
static inline int ldsw_raw(void *ptr)
{
#ifdef __powerpc__
int val;
__asm__ __volatile__ ("lhbrx %0,0,%1" : "=r" (val) : "r" (ptr));
return (int16_t)val;
#else
uint8_t *p = ptr;
return (int16_t)(p[0] | (p[1] << 8));
#endif
}
static inline int ldl_raw(void *ptr)
{
#ifdef __powerpc__
int val;
__asm__ __volatile__ ("lwbrx %0,0,%1" : "=r" (val) : "r" (ptr));
return val;
#else
uint8_t *p = ptr;
return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
#endif
}
static inline uint64_t ldq_raw(void *ptr)
{
uint8_t *p = ptr;
uint32_t v1, v2;
v1 = ldl_raw(p);
v2 = ldl_raw(p + 4);
return v1 | ((uint64_t)v2 << 32);
}
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));
#else
uint8_t *p = ptr;
p[0] = v;
p[1] = v >> 8;
#endif
}
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));
#else
uint8_t *p = ptr;
p[0] = v;
p[1] = v >> 8;
p[2] = v >> 16;
p[3] = v >> 24;
#endif
}
static inline void stq_raw(void *ptr, uint64_t v)
{
uint8_t *p = ptr;
stl_raw(p, (uint32_t)v);
stl_raw(p + 4, v >> 32);
}
/* float access */
static inline float ldfl_raw(void *ptr)
{
union {
float f;
uint32_t i;
} u;
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);
}
#if defined(__arm__) && !defined(WORDS_BIGENDIAN)
/* NOTE: arm is horrible as double 32 bit words are stored in big endian ! */
static inline double ldfq_raw(void *ptr)
{
union {
double d;
uint32_t tab[2];
} u;
u.tab[1] = ldl_raw(ptr);
u.tab[0] = ldl_raw(ptr + 4);
return u.d;
}
static inline void stfq_raw(void *ptr, double v)
{
union {
double d;
uint32_t tab[2];
} u;
u.d = v;
stl_raw(ptr, u.tab[1]);
stl_raw(ptr + 4, u.tab[0]);
}
#else
static inline double ldfq_raw(void *ptr)
{
union {
double d;
uint64_t i;
} u;
u.i = ldq_raw(ptr);
return u.d;
}
static inline void stfq_raw(void *ptr, double v)
{
union {
double d;
uint64_t i;
} u;
u.d = v;
stq_raw(ptr, u.i);
}
#endif
#elif defined(TARGET_WORDS_BIGENDIAN) && !defined(WORDS_BIGENDIAN)
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 (ptr);
b = ldl (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 (ptr, v);
stl (ptr+4, v >> 32);
}
#else
static inline int lduw_raw(void *ptr)
{
return *(uint16_t *)ptr;
}
static inline int ldsw_raw(void *ptr)
{
return *(int16_t *)ptr;
}
static inline int ldl_raw(void *ptr)
{
return *(uint32_t *)ptr;
}
static inline uint64_t ldq_raw(void *ptr)
{
return *(uint64_t *)ptr;
}
static inline void stw_raw(void *ptr, int v)
{
*(uint16_t *)ptr = v;
}
static inline void stl_raw(void *ptr, int v)
{
*(uint32_t *)ptr = v;
}
static inline void stq_raw(void *ptr, uint64_t v)
{
*(uint64_t *)ptr = v;
}
/* float access */
static inline float ldfl_raw(void *ptr)
{
return *(float *)ptr;
}
static inline double ldfq_raw(void *ptr)
{
return *(double *)ptr;
}
static inline void stfl_raw(void *ptr, float v)
{
*(float *)ptr = 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 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)
#endif /* defined(CONFIG_USER_ONLY) */
/* page related stuff */
#define TARGET_PAGE_SIZE (1 << TARGET_PAGE_BITS)
#define TARGET_PAGE_MASK ~(TARGET_PAGE_SIZE - 1)
#define TARGET_PAGE_ALIGN(addr) (((addr) + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK)
extern unsigned long real_host_page_size;
extern unsigned long host_page_bits;
extern unsigned long host_page_size;
extern unsigned long host_page_mask;
#define HOST_PAGE_ALIGN(addr) (((addr) + host_page_size - 1) & host_page_mask)
/* same as PROT_xxx */
#define PAGE_READ 0x0001
#define PAGE_WRITE 0x0002
#define PAGE_EXEC 0x0004
#define PAGE_BITS (PAGE_READ | PAGE_WRITE | PAGE_EXEC)
#define PAGE_VALID 0x0008
/* original state of the write flag (used when tracking self-modifying
code */
#define PAGE_WRITE_ORG 0x0010
void page_dump(FILE *f);
int page_get_flags(unsigned long address);
void page_set_flags(unsigned long start, unsigned long end, int flags);
void page_unprotect_range(uint8_t *data, unsigned long data_size);
#define SINGLE_CPU_DEFINES
#ifdef SINGLE_CPU_DEFINES
#if defined(TARGET_I386)
#define CPUState CPUX86State
#define cpu_init cpu_x86_init
#define cpu_exec cpu_x86_exec
#define cpu_gen_code cpu_x86_gen_code
#define cpu_interrupt cpu_x86_interrupt
#define cpu_signal_handler cpu_x86_signal_handler
#elif defined(TARGET_ARM)
#define CPUState CPUARMState
#define cpu_init cpu_arm_init
#define cpu_exec cpu_arm_exec
#define cpu_gen_code cpu_arm_gen_code
#define cpu_interrupt cpu_arm_interrupt
#define cpu_signal_handler cpu_arm_signal_handler
#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
#else
#error unsupported target CPU
#endif
#endif /* SINGLE_CPU_DEFINES */
#define DEFAULT_GDBSTUB_PORT 1234
void cpu_abort(CPUState *env, const char *fmt, ...);
extern CPUState *cpu_single_env;
#define CPU_INTERRUPT_EXIT 0x01 /* wants exit from main loop */
#define CPU_INTERRUPT_HARD 0x02 /* hardware interrupt pending */
void cpu_interrupt(CPUState *s, int mask);
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

654
cpu-exec.c Normal file
View File

@@ -0,0 +1,654 @@
/*
* i386 emulator main execution loop
*
* Copyright (c) 2003 Fabrice Bellard
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "config.h"
#include "exec.h"
#include "disas.h"
//#define DEBUG_EXEC
//#define DEBUG_SIGNAL
#if defined(TARGET_ARM) || defined(TARGET_SPARC)
/* XXX: unify with i386 target */
void cpu_loop_exit(void)
{
longjmp(env->jmp_env, 1);
}
#endif
/* main execution loop */
int cpu_exec(CPUState *env1)
{
int saved_T0, saved_T1, saved_T2;
CPUState *saved_env;
#ifdef reg_EAX
int saved_EAX;
#endif
#ifdef reg_ECX
int saved_ECX;
#endif
#ifdef reg_EDX
int saved_EDX;
#endif
#ifdef reg_EBX
int saved_EBX;
#endif
#ifdef reg_ESP
int saved_ESP;
#endif
#ifdef reg_EBP
int saved_EBP;
#endif
#ifdef reg_ESI
int saved_ESI;
#endif
#ifdef reg_EDI
int saved_EDI;
#endif
#ifdef __sparc__
int saved_i7, tmp_T0;
#endif
int code_gen_size, ret, interrupt_request;
void (*gen_func)(void);
TranslationBlock *tb, **ptb;
uint8_t *tc_ptr, *cs_base, *pc;
unsigned int flags;
/* first we save global registers */
saved_T0 = T0;
saved_T1 = T1;
saved_T2 = T2;
saved_env = env;
env = env1;
#ifdef __sparc__
/* we also save i7 because longjmp may not restore it */
asm volatile ("mov %%i7, %0" : "=r" (saved_i7));
#endif
#if defined(TARGET_I386)
#ifdef reg_EAX
saved_EAX = EAX;
EAX = env->regs[R_EAX];
#endif
#ifdef reg_ECX
saved_ECX = ECX;
ECX = env->regs[R_ECX];
#endif
#ifdef reg_EDX
saved_EDX = EDX;
EDX = env->regs[R_EDX];
#endif
#ifdef reg_EBX
saved_EBX = EBX;
EBX = env->regs[R_EBX];
#endif
#ifdef reg_ESP
saved_ESP = ESP;
ESP = env->regs[R_ESP];
#endif
#ifdef reg_EBP
saved_EBP = EBP;
EBP = env->regs[R_EBP];
#endif
#ifdef reg_ESI
saved_ESI = ESI;
ESI = env->regs[R_ESI];
#endif
#ifdef reg_EDI
saved_EDI = EDI;
EDI = env->regs[R_EDI];
#endif
/* put eflags in CPU temporary format */
CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
DF = 1 - (2 * ((env->eflags >> 10) & 1));
CC_OP = CC_OP_EFLAGS;
env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
#elif defined(TARGET_ARM)
{
unsigned int psr;
psr = env->cpsr;
env->CF = (psr >> 29) & 1;
env->NZF = (psr & 0xc0000000) ^ 0x40000000;
env->VF = (psr << 3) & 0x80000000;
env->cpsr = psr & ~0xf0000000;
}
#elif defined(TARGET_SPARC)
#else
#error unsupported target CPU
#endif
env->exception_index = -1;
/* prepare setjmp context for exception handling */
for(;;) {
if (setjmp(env->jmp_env) == 0) {
/* if an exception is pending, we execute it here */
if (env->exception_index >= 0) {
if (env->exception_index >= EXCP_INTERRUPT) {
/* exit request from the cpu execution loop */
ret = env->exception_index;
break;
} else if (env->user_mode_only) {
/* if user mode only, we simulate a fake exception
which will be hanlded outside the cpu execution
loop */
#if defined(TARGET_I386)
do_interrupt_user(env->exception_index,
env->exception_is_int,
env->error_code,
env->exception_next_eip);
#endif
ret = env->exception_index;
break;
} else {
#if defined(TARGET_I386)
/* simulate a real cpu exception. On i386, it can
trigger new exceptions, but we do not handle
double or triple faults yet. */
do_interrupt(env->exception_index,
env->exception_is_int,
env->error_code,
env->exception_next_eip, 0);
#endif
}
env->exception_index = -1;
}
T0 = 0; /* force lookup of first TB */
for(;;) {
#ifdef __sparc__
/* g1 can be modified by some libc? functions */
tmp_T0 = T0;
#endif
interrupt_request = env->interrupt_request;
if (__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) {
#if defined(TARGET_I386)
/* restore flags in standard format */
env->regs[R_EAX] = EAX;
env->regs[R_EBX] = EBX;
env->regs[R_ECX] = ECX;
env->regs[R_EDX] = EDX;
env->regs[R_ESI] = ESI;
env->regs[R_EDI] = EDI;
env->regs[R_EBP] = EBP;
env->regs[R_ESP] = ESP;
env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
cpu_x86_dump_state(env, logfile, X86_DUMP_CCOP);
env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
#elif defined(TARGET_ARM)
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);
#else
#error unsupported target CPU
#endif
}
#endif
/* 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->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 = 0;
if (env->npc) {
env->pc = env->npc;
env->npc = 0;
}
pc = (uint8_t *) env->pc;
#else
#error unsupported CPU
#endif
tb = tb_find(&ptb, (unsigned long)pc, (unsigned long)cs_base,
flags);
if (!tb) {
spin_lock(&tb_lock);
/* if no translated code available, then translate it now */
tb = tb_alloc((unsigned long)pc);
if (!tb) {
/* flush must be done */
tb_flush();
/* cannot fail at this point */
tb = tb_alloc((unsigned long)pc);
/* don't forget to invalidate previous TB info */
ptb = &tb_hash[tb_hash_func((unsigned long)pc)];
T0 = 0;
}
tc_ptr = code_gen_ptr;
tb->tc_ptr = tc_ptr;
tb->cs_base = (unsigned long)cs_base;
tb->flags = flags;
/* XXX: an MMU exception can occur here */
cpu_gen_code(env, tb, CODE_GEN_MAX_SIZE, &code_gen_size);
*ptb = tb;
tb->hash_next = NULL;
tb_link(tb);
code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1));
spin_unlock(&tb_lock);
}
#ifdef DEBUG_EXEC
if (loglevel) {
fprintf(logfile, "Trace 0x%08lx [0x%08lx] %s\n",
(long)tb->tc_ptr, (long)tb->pc,
lookup_symbol((void *)tb->pc));
}
#endif
#ifdef __sparc__
T0 = tmp_T0;
#endif
/* see if we can patch the calling TB. */
if (T0 != 0) {
spin_lock(&tb_lock);
tb_add_jump((TranslationBlock *)(T0 & ~3), T0 & 3, tb);
spin_unlock(&tb_lock);
}
tc_ptr = tb->tc_ptr;
env->current_tb = tb;
/* execute the generated code */
gen_func = (void *)tc_ptr;
#if defined(__sparc__)
__asm__ __volatile__("call %0\n\t"
"mov %%o7,%%i0"
: /* no outputs */
: "r" (gen_func)
: "i0", "i1", "i2", "i3", "i4", "i5");
#elif defined(__arm__)
asm volatile ("mov pc, %0\n\t"
".global exec_loop\n\t"
"exec_loop:\n\t"
: /* no outputs */
: "r" (gen_func)
: "r1", "r2", "r3", "r8", "r9", "r10", "r12", "r14");
#else
gen_func();
#endif
env->current_tb = NULL;
/* 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 {
}
} /* for(;;) */
#if defined(TARGET_I386)
/* restore flags in standard format */
env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
/* restore global registers */
#ifdef reg_EAX
EAX = saved_EAX;
#endif
#ifdef reg_ECX
ECX = saved_ECX;
#endif
#ifdef reg_EDX
EDX = saved_EDX;
#endif
#ifdef reg_EBX
EBX = saved_EBX;
#endif
#ifdef reg_ESP
ESP = saved_ESP;
#endif
#ifdef reg_EBP
EBP = saved_EBP;
#endif
#ifdef reg_ESI
ESI = saved_ESI;
#endif
#ifdef reg_EDI
EDI = saved_EDI;
#endif
#elif defined(TARGET_ARM)
env->cpsr = compute_cpsr();
#elif defined(TARGET_SPARC)
#else
#error unsupported target CPU
#endif
#ifdef __sparc__
asm volatile ("mov %0, %%i7" : : "r" (saved_i7));
#endif
T0 = saved_T0;
T1 = saved_T1;
T2 = saved_T2;
env = saved_env;
return ret;
}
#if defined(TARGET_I386)
void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector)
{
CPUX86State *saved_env;
saved_env = env;
env = s;
if (!(env->cr[0] & CR0_PE_MASK) || (env->eflags & VM_MASK)) {
selector &= 0xffff;
cpu_x86_load_seg_cache(env, seg_reg, selector,
(uint8_t *)(selector << 4), 0xffff, 0);
} else {
load_seg(seg_reg, selector, 0);
}
env = saved_env;
}
void cpu_x86_fsave(CPUX86State *s, uint8_t *ptr, int data32)
{
CPUX86State *saved_env;
saved_env = env;
env = s;
helper_fsave(ptr, data32);
env = saved_env;
}
void cpu_x86_frstor(CPUX86State *s, uint8_t *ptr, int data32)
{
CPUX86State *saved_env;
saved_env = env;
env = s;
helper_frstor(ptr, data32);
env = saved_env;
}
#endif /* TARGET_I386 */
#undef EAX
#undef ECX
#undef EDX
#undef EBX
#undef ESP
#undef EBP
#undef ESI
#undef EDI
#undef EIP
#include <signal.h>
#include <sys/ucontext.h>
#if defined(TARGET_I386)
/* 'pc' is the host PC at which the exception was raised. 'address' is
the effective address of the memory exception. 'is_write' is 1 if a
write caused the exception and otherwise 0'. 'old_set' is the
signal set which should be restored */
static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
int is_write, sigset_t *old_set)
{
TranslationBlock *tb;
int ret;
if (cpu_single_env)
env = cpu_single_env; /* XXX: find a correct solution for multithread */
#if defined(DEBUG_SIGNAL)
printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
pc, address, is_write, *(unsigned long *)old_set);
#endif
/* XXX: locking issue */
if (is_write && page_unprotect(address)) {
return 1;
}
/* see if it is an MMU fault */
ret = cpu_x86_handle_mmu_fault(env, address, is_write,
((env->hflags & HF_CPL_MASK) == 3), 0);
if (ret < 0)
return 0; /* not an MMU fault */
if (ret == 0)
return 1; /* the MMU fault was handled without causing real CPU fault */
/* now we have a real cpu fault */
tb = tb_find_pc(pc);
if (tb) {
/* the PC is inside the translated code. It means that we have
a virtual CPU fault */
cpu_restore_state(tb, env, pc);
}
if (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)
{
return 0;
}
#else
#error unsupported target CPU
#endif
#if defined(__i386__)
int cpu_signal_handler(int host_signum, struct siginfo *info,
void *puc)
{
struct ucontext *uc = puc;
unsigned long pc;
#ifndef REG_EIP
/* for glibc 2.1 */
#define REG_EIP EIP
#define REG_ERR ERR
#define REG_TRAPNO TRAPNO
#endif
pc = uc->uc_mcontext.gregs[REG_EIP];
return handle_cpu_signal(pc, (unsigned long)info->si_addr,
uc->uc_mcontext.gregs[REG_TRAPNO] == 0xe ?
(uc->uc_mcontext.gregs[REG_ERR] >> 1) & 1 : 0,
&uc->uc_sigmask);
}
#elif defined(__powerpc)
int cpu_signal_handler(int host_signum, struct siginfo *info,
void *puc)
{
struct ucontext *uc = puc;
struct pt_regs *regs = uc->uc_mcontext.regs;
unsigned long pc;
int is_write;
pc = regs->nip;
is_write = 0;
#if 0
/* ppc 4xx case */
if (regs->dsisr & 0x00800000)
is_write = 1;
#else
if (regs->trap != 0x400 && (regs->dsisr & 0x02000000))
is_write = 1;
#endif
return handle_cpu_signal(pc, (unsigned long)info->si_addr,
is_write, &uc->uc_sigmask);
}
#elif defined(__alpha__)
int cpu_signal_handler(int host_signum, struct siginfo *info,
void *puc)
{
struct ucontext *uc = puc;
uint32_t *pc = uc->uc_mcontext.sc_pc;
uint32_t insn = *pc;
int is_write = 0;
/* XXX: need kernel patch to get write flag faster */
switch (insn >> 26) {
case 0x0d: // stw
case 0x0e: // stb
case 0x0f: // stq_u
case 0x24: // stf
case 0x25: // stg
case 0x26: // sts
case 0x27: // stt
case 0x2c: // stl
case 0x2d: // stq
case 0x2e: // stl_c
case 0x2f: // stq_c
is_write = 1;
}
return handle_cpu_signal(pc, (unsigned long)info->si_addr,
is_write, &uc->uc_sigmask);
}
#elif defined(__sparc__)
int cpu_signal_handler(int host_signum, struct siginfo *info,
void *puc)
{
uint32_t *regs = (uint32_t *)(info + 1);
void *sigmask = (regs + 20);
unsigned long pc;
int is_write;
uint32_t insn;
/* XXX: is there a standard glibc define ? */
pc = regs[1];
/* XXX: need kernel patch to get write flag faster */
is_write = 0;
insn = *(uint32_t *)pc;
if ((insn >> 30) == 3) {
switch((insn >> 19) & 0x3f) {
case 0x05: // stb
case 0x06: // sth
case 0x04: // st
case 0x07: // std
case 0x24: // stf
case 0x27: // stdf
case 0x25: // stfsr
is_write = 1;
break;
}
}
return handle_cpu_signal(pc, (unsigned long)info->si_addr,
is_write, sigmask);
}
#elif defined(__arm__)
int cpu_signal_handler(int host_signum, struct siginfo *info,
void *puc)
{
struct ucontext *uc = puc;
unsigned long pc;
int is_write;
pc = uc->uc_mcontext.gregs[R15];
/* XXX: compute is_write */
is_write = 0;
return handle_cpu_signal(pc, (unsigned long)info->si_addr,
is_write,
&uc->uc_sigmask);
}
#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
#endif

View File

@@ -1,434 +0,0 @@
/*
* i386 virtual CPU header
*
* Copyright (c) 2003 Fabrice Bellard
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef CPU_I386_H
#define CPU_I386_H
#include "config.h"
#include <setjmp.h>
#define R_EAX 0
#define R_ECX 1
#define R_EDX 2
#define R_EBX 3
#define R_ESP 4
#define R_EBP 5
#define R_ESI 6
#define R_EDI 7
#define R_AL 0
#define R_CL 1
#define R_DL 2
#define R_BL 3
#define R_AH 4
#define R_CH 5
#define R_DH 6
#define R_BH 7
#define R_ES 0
#define R_CS 1
#define R_SS 2
#define R_DS 3
#define R_FS 4
#define R_GS 5
/* eflags masks */
#define CC_C 0x0001
#define CC_P 0x0004
#define CC_A 0x0010
#define CC_Z 0x0040
#define CC_S 0x0080
#define CC_O 0x0800
#define TF_MASK 0x00000100
#define IF_MASK 0x00000200
#define DF_MASK 0x00000400
#define IOPL_MASK 0x00003000
#define NT_MASK 0x00004000
#define RF_MASK 0x00010000
#define VM_MASK 0x00020000
#define AC_MASK 0x00040000
#define VIF_MASK 0x00080000
#define VIP_MASK 0x00100000
#define ID_MASK 0x00200000
#define EXCP00_DIVZ 0
#define EXCP01_SSTP 1
#define EXCP02_NMI 2
#define EXCP03_INT3 3
#define EXCP04_INTO 4
#define EXCP05_BOUND 5
#define EXCP06_ILLOP 6
#define EXCP07_PREX 7
#define EXCP08_DBLE 8
#define EXCP09_XERR 9
#define EXCP0A_TSS 10
#define EXCP0B_NOSEG 11
#define EXCP0C_STACK 12
#define EXCP0D_GPF 13
#define EXCP0E_PAGE 14
#define EXCP10_COPR 16
#define EXCP11_ALGN 17
#define EXCP12_MCHK 18
#define EXCP_INTERRUPT 256 /* async interruption */
enum {
CC_OP_DYNAMIC, /* must use dynamic code to get cc_op */
CC_OP_EFLAGS, /* all cc are explicitely computed, CC_SRC = flags */
CC_OP_MUL, /* modify all flags, C, O = (CC_SRC != 0) */
CC_OP_ADDB, /* modify all flags, CC_DST = res, CC_SRC = src1 */
CC_OP_ADDW,
CC_OP_ADDL,
CC_OP_ADCB, /* modify all flags, CC_DST = res, CC_SRC = src1 */
CC_OP_ADCW,
CC_OP_ADCL,
CC_OP_SUBB, /* modify all flags, CC_DST = res, CC_SRC = src1 */
CC_OP_SUBW,
CC_OP_SUBL,
CC_OP_SBBB, /* modify all flags, CC_DST = res, CC_SRC = src1 */
CC_OP_SBBW,
CC_OP_SBBL,
CC_OP_LOGICB, /* modify all flags, CC_DST = res */
CC_OP_LOGICW,
CC_OP_LOGICL,
CC_OP_INCB, /* modify all flags except, CC_DST = res, CC_SRC = C */
CC_OP_INCW,
CC_OP_INCL,
CC_OP_DECB, /* modify all flags except, CC_DST = res, CC_SRC = C */
CC_OP_DECW,
CC_OP_DECL,
CC_OP_SHLB, /* modify all flags, CC_DST = res, CC_SRC.lsb = C */
CC_OP_SHLW,
CC_OP_SHLL,
CC_OP_SARB, /* modify all flags, CC_DST = res, CC_SRC.lsb = C */
CC_OP_SARW,
CC_OP_SARL,
CC_OP_NB,
};
#ifdef __i386__
#define USE_X86LDOUBLE
#endif
#ifdef USE_X86LDOUBLE
typedef long double CPU86_LDouble;
#else
typedef double CPU86_LDouble;
#endif
typedef struct SegmentCache {
uint8_t *base;
unsigned long limit;
uint8_t seg_32bit;
} SegmentCache;
typedef struct SegmentDescriptorTable {
uint8_t *base;
unsigned long limit;
/* this is the returned base when reading the register, just to
avoid that the emulated program modifies it */
unsigned long emu_base;
} SegmentDescriptorTable;
typedef struct CPUX86State {
/* standard registers */
uint32_t regs[8];
uint32_t eip;
uint32_t eflags; /* eflags register. During CPU emulation, CC
flags and DF are set to zero because they are
store elsewhere */
/* emulator internal eflags handling */
uint32_t cc_src;
uint32_t cc_dst;
uint32_t cc_op;
int32_t df; /* D flag : 1 if D = 0, -1 if D = 1 */
/* FPU state */
unsigned int fpstt; /* top of stack index */
unsigned int fpus;
unsigned int fpuc;
uint8_t fptags[8]; /* 0 = valid, 1 = empty */
CPU86_LDouble fpregs[8];
/* emulator internal variables */
CPU86_LDouble ft0;
/* segments */
uint32_t segs[6]; /* selector values */
SegmentCache seg_cache[6]; /* info taken from LDT/GDT */
SegmentDescriptorTable gdt;
SegmentDescriptorTable ldt;
SegmentDescriptorTable idt;
/* exception/interrupt handling */
jmp_buf jmp_env;
int exception_index;
int interrupt_request;
/* user data */
void *opaque;
} CPUX86State;
/* all CPU memory access use these macros */
static inline int ldub(void *ptr)
{
return *(uint8_t *)ptr;
}
static inline int ldsb(void *ptr)
{
return *(int8_t *)ptr;
}
static inline void stb(void *ptr, int v)
{
*(uint8_t *)ptr = v;
}
#ifdef WORDS_BIGENDIAN
/* conservative code for little endian unaligned accesses */
static inline int lduw(void *ptr)
{
#ifdef __powerpc__
int val;
__asm__ __volatile__ ("lhbrx %0,0,%1" : "=r" (val) : "r" (ptr));
return val;
#else
uint8_t *p = ptr;
return p[0] | (p[1] << 8);
#endif
}
static inline int ldsw(void *ptr)
{
#ifdef __powerpc__
int val;
__asm__ __volatile__ ("lhbrx %0,0,%1" : "=r" (val) : "r" (ptr));
return (int16_t)val;
#else
uint8_t *p = ptr;
return (int16_t)(p[0] | (p[1] << 8));
#endif
}
static inline int ldl(void *ptr)
{
#ifdef __powerpc__
int val;
__asm__ __volatile__ ("lwbrx %0,0,%1" : "=r" (val) : "r" (ptr));
return val;
#else
uint8_t *p = ptr;
return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
#endif
}
static inline uint64_t ldq(void *ptr)
{
uint8_t *p = ptr;
uint32_t v1, v2;
v1 = ldl(p);
v2 = ldl(p + 4);
return v1 | ((uint64_t)v2 << 32);
}
static inline void stw(void *ptr, int v)
{
#ifdef __powerpc__
__asm__ __volatile__ ("sthbrx %1,0,%2" : "=m" (*(uint16_t *)ptr) : "r" (v), "r" (ptr));
#else
uint8_t *p = ptr;
p[0] = v;
p[1] = v >> 8;
#endif
}
static inline void stl(void *ptr, int v)
{
#ifdef __powerpc__
__asm__ __volatile__ ("stwbrx %1,0,%2" : "=m" (*(uint32_t *)ptr) : "r" (v), "r" (ptr));
#else
uint8_t *p = ptr;
p[0] = v;
p[1] = v >> 8;
p[2] = v >> 16;
p[3] = v >> 24;
#endif
}
static inline void stq(void *ptr, uint64_t v)
{
uint8_t *p = ptr;
stl(p, (uint32_t)v);
stl(p + 4, v >> 32);
}
/* float access */
static inline float ldfl(void *ptr)
{
union {
float f;
uint32_t i;
} u;
u.i = ldl(ptr);
return u.f;
}
static inline double ldfq(void *ptr)
{
union {
double d;
uint64_t i;
} u;
u.i = ldq(ptr);
return u.d;
}
static inline void stfl(void *ptr, float v)
{
union {
float f;
uint32_t i;
} u;
u.f = v;
stl(ptr, u.i);
}
static inline void stfq(void *ptr, double v)
{
union {
double d;
uint64_t i;
} u;
u.d = v;
stq(ptr, u.i);
}
#else
static inline int lduw(void *ptr)
{
return *(uint16_t *)ptr;
}
static inline int ldsw(void *ptr)
{
return *(int16_t *)ptr;
}
static inline int ldl(void *ptr)
{
return *(uint32_t *)ptr;
}
static inline uint64_t ldq(void *ptr)
{
return *(uint64_t *)ptr;
}
static inline void stw(void *ptr, int v)
{
*(uint16_t *)ptr = v;
}
static inline void stl(void *ptr, int v)
{
*(uint32_t *)ptr = v;
}
static inline void stq(void *ptr, uint64_t v)
{
*(uint64_t *)ptr = v;
}
/* float access */
static inline float ldfl(void *ptr)
{
return *(float *)ptr;
}
static inline double ldfq(void *ptr)
{
return *(double *)ptr;
}
static inline void stfl(void *ptr, float v)
{
*(float *)ptr = v;
}
static inline void stfq(void *ptr, double v)
{
*(double *)ptr = v;
}
#endif
#ifndef IN_OP_I386
void cpu_x86_outb(int addr, int val);
void cpu_x86_outw(int addr, int val);
void cpu_x86_outl(int addr, int val);
int cpu_x86_inb(int addr);
int cpu_x86_inw(int addr);
int cpu_x86_inl(int addr);
#endif
CPUX86State *cpu_x86_init(void);
int cpu_x86_exec(CPUX86State *s);
void cpu_x86_interrupt(CPUX86State *s);
void cpu_x86_close(CPUX86State *s);
/* needed to load some predefinied segment registers */
void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector);
/* you can call this signal handler from your SIGBUS and SIGSEGV
signal handlers to inform the virtual CPU of exceptions. non zero
is returned if the signal was handled by the virtual CPU. */
struct siginfo;
int cpu_x86_signal_handler(int host_signum, struct siginfo *info,
void *puc);
/* internal functions */
#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
int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size,
int *gen_code_size_ptr,
uint8_t *pc_start, uint8_t *cs_base, int flags);
void cpu_x86_tblocks_init(void);
#endif /* CPU_I386_H */

View File

@@ -73,16 +73,20 @@ enum bfd_architecture
bfd_arch_a29k, /* AMD 29000 */
bfd_arch_sparc, /* SPARC */
#define bfd_mach_sparc 1
/* The difference between v8plus and v9 is that v9 is a true 64 bit env. */
/* The difference between v8plus and v9 is that v9 is a true 64 bit env. */
#define bfd_mach_sparc_sparclet 2
#define bfd_mach_sparc_sparclite 3
#define bfd_mach_sparc_v8plus 4
#define bfd_mach_sparc_v8plusa 5 /* with ultrasparc add'ns */
#define bfd_mach_sparc_v9 6
#define bfd_mach_sparc_v9a 7 /* with ultrasparc add'ns */
/* Nonzero if MACH has the v9 instruction set. */
#define bfd_mach_sparc_v8plusa 5 /* with ultrasparc add'ns. */
#define bfd_mach_sparc_sparclite_le 6
#define bfd_mach_sparc_v9 7
#define bfd_mach_sparc_v9a 8 /* with ultrasparc add'ns. */
#define bfd_mach_sparc_v8plusb 9 /* with cheetah add'ns. */
#define bfd_mach_sparc_v9b 10 /* with cheetah add'ns. */
/* Nonzero if MACH has the v9 instruction set. */
#define bfd_mach_sparc_v9_p(mach) \
((mach) >= bfd_mach_sparc_v8plus && (mach) <= bfd_mach_sparc_v9a)
((mach) >= bfd_mach_sparc_v8plus && (mach) <= bfd_mach_sparc_v9b \
&& (mach) != bfd_mach_sparc_sparclite_le)
bfd_arch_mips, /* MIPS Rxxxx */
#define bfd_mach_mips3000 3000
#define bfd_mach_mips3900 3900
@@ -279,6 +283,9 @@ typedef struct disassemble_info {
zero if unknown. */
bfd_vma target2; /* Second target address for dref2 */
/* Command line options specific to the target disassembler. */
char * disassembler_options;
} disassemble_info;
@@ -299,8 +306,7 @@ extern int print_insn_h8300s PARAMS ((bfd_vma, disassemble_info*));
extern int print_insn_h8500 PARAMS ((bfd_vma, disassemble_info*));
extern int print_insn_alpha PARAMS ((bfd_vma, disassemble_info*));
extern disassembler_ftype arc_get_disassembler PARAMS ((int, int));
extern int print_insn_big_arm PARAMS ((bfd_vma, disassemble_info*));
extern int print_insn_little_arm PARAMS ((bfd_vma, disassemble_info*));
extern int print_insn_arm PARAMS ((bfd_vma, disassemble_info*));
extern int print_insn_sparc PARAMS ((bfd_vma, disassemble_info*));
extern int print_insn_big_a29k PARAMS ((bfd_vma, disassemble_info*));
extern int print_insn_little_a29k PARAMS ((bfd_vma, disassemble_info*));
@@ -320,6 +326,7 @@ extern int print_insn_w65 PARAMS ((bfd_vma, disassemble_info*));
extern int print_insn_d10v PARAMS ((bfd_vma, disassemble_info*));
extern int print_insn_v850 PARAMS ((bfd_vma, disassemble_info*));
extern int print_insn_tic30 PARAMS ((bfd_vma, disassemble_info*));
extern int print_insn_ppc PARAMS ((bfd_vma, disassemble_info*));
#if 0
/* Fetch the disassembler for a given BFD, if that support is available. */
@@ -380,6 +387,15 @@ extern int generic_symbol_at_address
(INFO).bytes_per_line = 0, \
(INFO).bytes_per_chunk = 0, \
(INFO).display_endian = BFD_ENDIAN_UNKNOWN, \
(INFO).disassembler_options = NULL, \
(INFO).insn_info_valid = 0
#define _(x) x
/* from libbfd */
bfd_vma bfd_getl32 (const bfd_byte *addr);
bfd_vma bfd_getb32 (const bfd_byte *addr);
typedef enum bfd_boolean {false, true} boolean;
#endif /* ! defined (DIS_ASM_H) */

View File

@@ -1,79 +0,0 @@
/* Disassemble from a buffer, for GNU.
Copyright (C) 1993, 1994 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#include "dis-asm.h"
#include <errno.h>
/* Get LENGTH bytes from info's buffer, at target address memaddr.
Transfer them to myaddr. */
int
buffer_read_memory (memaddr, myaddr, length, info)
bfd_vma memaddr;
bfd_byte *myaddr;
int length;
struct disassemble_info *info;
{
if (memaddr < info->buffer_vma
|| memaddr + length > info->buffer_vma + info->buffer_length)
/* Out of bounds. Use EIO because GDB uses it. */
return EIO;
memcpy (myaddr, info->buffer + (memaddr - info->buffer_vma), length);
return 0;
}
/* Print an error message. We can assume that this is in response to
an error return from buffer_read_memory. */
void
perror_memory (status, memaddr, info)
int status;
bfd_vma memaddr;
struct disassemble_info *info;
{
if (status != EIO)
/* Can't happen. */
(*info->fprintf_func) (info->stream, "Unknown error %d\n", status);
else
/* Actually, address between memaddr and memaddr + len was
out of bounds. */
(*info->fprintf_func) (info->stream,
"Address 0x%x is out of bounds.\n", memaddr);
}
/* This could be in a separate file, to save miniscule amounts of space
in statically linked executables. */
/* Just print the address is hex. This is included for completeness even
though both GDB and objdump provide their own (to print symbolic
addresses). */
void
generic_print_address (addr, info)
bfd_vma addr;
struct disassemble_info *info;
{
(*info->fprintf_func) (info->stream, "0x%x", addr);
}
/* Just return the given address. */
int
generic_symbol_at_address (addr, info)
bfd_vma addr;
struct disassemble_info * info;
{
return 1;
}

216
disas.c Normal file
View File

@@ -0,0 +1,216 @@
/* General "disassemble this chunk" code. Used for debugging. */
#include "config.h"
#include "dis-asm.h"
#include "disas.h"
#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;
const char *disas_strtab;
/* Get LENGTH bytes from info's buffer, at target address memaddr.
Transfer them to myaddr. */
int
buffer_read_memory (memaddr, myaddr, length, info)
bfd_vma memaddr;
bfd_byte *myaddr;
int length;
struct disassemble_info *info;
{
if (memaddr < info->buffer_vma
|| memaddr + length > info->buffer_vma + info->buffer_length)
/* Out of bounds. Use EIO because GDB uses it. */
return EIO;
memcpy (myaddr, info->buffer + (memaddr - info->buffer_vma), length);
return 0;
}
#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
perror_memory (status, memaddr, info)
int status;
bfd_vma memaddr;
struct disassemble_info *info;
{
if (status != EIO)
/* Can't happen. */
(*info->fprintf_func) (info->stream, "Unknown error %d\n", status);
else
/* Actually, address between memaddr and memaddr + len was
out of bounds. */
(*info->fprintf_func) (info->stream,
"Address 0x%llx is out of bounds.\n", memaddr);
}
/* This could be in a separate file, to save miniscule amounts of space
in statically linked executables. */
/* Just print the address is hex. This is included for completeness even
though both GDB and objdump provide their own (to print symbolic
addresses). */
void
generic_print_address (addr, info)
bfd_vma addr;
struct disassemble_info *info;
{
(*info->fprintf_func) (info->stream, "0x%llx", addr);
}
/* Just return the given address. */
int
generic_symbol_at_address (addr, info)
bfd_vma addr;
struct disassemble_info * info;
{
return 1;
}
bfd_vma bfd_getl32 (const bfd_byte *addr)
{
unsigned long v;
v = (unsigned long) addr[0];
v |= (unsigned long) addr[1] << 8;
v |= (unsigned long) addr[2] << 16;
v |= (unsigned long) addr[3] << 24;
return (bfd_vma) v;
}
bfd_vma bfd_getb32 (const bfd_byte *addr)
{
unsigned long v;
v = (unsigned long) addr[0] << 24;
v |= (unsigned long) addr[1] << 16;
v |= (unsigned long) addr[2] << 8;
v |= (unsigned long) addr[3];
return (bfd_vma) v;
}
/* Disassemble this for me please... (debugging). 'flags' is only used
for i386: non zero means 16 bit code */
void disas(FILE *out, void *code, unsigned long size, int is_host, int flags)
{
uint8_t *pc;
int count;
struct disassemble_info disasm_info;
int (*print_insn)(bfd_vma pc, disassemble_info *info);
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;
if (is_host) {
#ifdef WORDS_BIGENDIAN
disasm_info.endian = BFD_ENDIAN_BIG;
#else
disasm_info.endian = BFD_ENDIAN_LITTLE;
#endif
#ifdef __i386__
disasm_info.mach = bfd_mach_i386_i386;
print_insn = print_insn_i386;
#elif defined(__powerpc__)
print_insn = print_insn_ppc;
#elif defined(__alpha__)
print_insn = print_insn_alpha;
#elif defined(__sparc__)
print_insn = print_insn_sparc;
#elif defined(__arm__)
print_insn = print_insn_arm;
#else
fprintf(out, "Asm output not supported on this arch\n");
return;
#endif
} else {
#ifdef TARGET_WORDS_BIGENDIAN
disasm_info.endian = BFD_ENDIAN_BIG;
#else
disasm_info.endian = BFD_ENDIAN_LITTLE;
#endif
#if defined(TARGET_I386)
if (!flags)
disasm_info.mach = bfd_mach_i386_i386;
else
disasm_info.mach = bfd_mach_i386_i8086;
print_insn = print_insn_i386;
#elif defined(TARGET_ARM)
print_insn = print_insn_arm;
#elif defined(TARGET_SPARC)
print_insn = print_insn_sparc;
#else
fprintf(out, "Asm output not supported on this arch\n");
return;
#endif
}
for (pc = code; pc < (uint8_t *)code + size; pc += count) {
fprintf(out, "0x%08lx: ", (long)pc);
#ifdef __arm__
/* since data are included in the code, it is better to
display code data too */
if (is_host) {
fprintf(out, "%08x ", (int)bfd_getl32((const bfd_byte *)pc));
}
#endif
count = print_insn((unsigned long)pc, &disasm_info);
fprintf(out, "\n");
if (count < 0)
break;
}
}
/* Look up symbol for debugging purpose. Returns "" if unknown. */
const char *lookup_symbol(void *orig_addr)
{
unsigned int i;
/* Hack, because we know this is x86. */
Elf32_Sym *sym = disas_symtab;
for (i = 0; i < disas_num_syms; i++) {
if (sym[i].st_shndx == SHN_UNDEF
|| sym[i].st_shndx >= SHN_LORESERVE)
continue;
if (ELF_ST_TYPE(sym[i].st_info) != STT_FUNC)
continue;
if ((long)orig_addr >= sym[i].st_value
&& (long)orig_addr < sym[i].st_value + sym[i].st_size)
return disas_strtab + sym[i].st_name;
}
return "";
}

14
disas.h Normal file
View File

@@ -0,0 +1,14 @@
#ifndef _QEMU_DISAS_H
#define _QEMU_DISAS_H
/* Disassemble this for me please... (debugging). */
void disas(FILE *out, void *code, unsigned long size, int is_host, int flags);
/* Look up symbol for debugging purpose. Returns "" if unknown. */
const char *lookup_symbol(void *orig_addr);
/* Filled in by elfload.c. Simplistic, but will do for now. */
extern unsigned int disas_num_syms;
extern void *disas_symtab; /* FIXME: includes are a mess --RR */
extern const char *disas_strtab;
#endif /* _QEMU_DISAS_H */

190
dyngen-exec.h Normal file
View File

@@ -0,0 +1,190 @@
/*
* dyngen defines for micro operation code
*
* Copyright (c) 2003 Fabrice Bellard
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
typedef unsigned long long uint64_t;
typedef signed char int8_t;
typedef signed short int16_t;
typedef signed int int32_t;
typedef signed long long int64_t;
#define bswap32(x) \
({ \
uint32_t __x = (x); \
((uint32_t)( \
(((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
(((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \
(((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \
(((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) )); \
})
typedef struct FILE FILE;
extern int fprintf(FILE *, const char *, ...);
extern int printf(const char *, ...);
#define NULL 0
#include <fenv.h>
#ifdef __i386__
#define AREG0 "ebp"
#define AREG1 "ebx"
#define AREG2 "esi"
#define AREG3 "edi"
#endif
#ifdef __powerpc__
#define AREG0 "r27"
#define AREG1 "r24"
#define AREG2 "r25"
#define AREG3 "r26"
#define AREG4 "r16"
#define AREG5 "r17"
#define AREG6 "r18"
#define AREG7 "r19"
#define AREG8 "r20"
#define AREG9 "r21"
#define AREG10 "r22"
#define AREG11 "r23"
#define USE_INT_TO_FLOAT_HELPERS
#define BUGGY_GCC_DIV64
#endif
#ifdef __arm__
#define AREG0 "r7"
#define AREG1 "r4"
#define AREG2 "r5"
#define AREG3 "r6"
#endif
#ifdef __mips__
#define AREG0 "s3"
#define AREG1 "s0"
#define AREG2 "s1"
#define AREG3 "s2"
#endif
#ifdef __sparc__
#define AREG0 "g6"
#define AREG1 "g1"
#define AREG2 "g2"
#define AREG3 "g3"
#define AREG4 "l0"
#define AREG5 "l1"
#define AREG6 "l2"
#define AREG7 "l3"
#define AREG8 "l4"
#define AREG9 "l5"
#define AREG10 "l6"
#define AREG11 "l7"
#define USE_FP_CONVERT
#endif
#ifdef __s390__
#define AREG0 "r10"
#define AREG1 "r7"
#define AREG2 "r8"
#define AREG3 "r9"
#endif
#ifdef __alpha__
/* Note $15 is the frame pointer, so anything in op-i386.c that would
require a frame pointer, like alloca, would probably loose. */
#define AREG0 "$15"
#define AREG1 "$9"
#define AREG2 "$10"
#define AREG3 "$11"
#define AREG4 "$12"
#define AREG5 "$13"
#define AREG6 "$14"
#endif
#ifdef __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"
#define AREG2 "r25"
#define AREG3 "r26"
#endif
/* force GCC to generate only one epilog at the end of the function */
#define FORCE_RET() asm volatile ("");
#ifndef OPPROTO
#define OPPROTO
#endif
#define xglue(x, y) x ## y
#define glue(x, y) xglue(x, y)
#define stringify(s) tostring(s)
#define tostring(s) #s
#ifdef __alpha__
/* the symbols are considered non exported so a br immediate is generated */
#define __hidden __attribute__((visibility("hidden")))
#else
#define __hidden
#endif
#ifdef __alpha__
/* Suggested by Richard Henderson. This will result in code like
ldah $0,__op_param1($29) !gprelhigh
lda $0,__op_param1($0) !gprellow
We can then conveniently change $29 to $31 and adapt the offsets to
emit the appropriate constant. */
extern int __op_param1 __hidden;
extern int __op_param2 __hidden;
extern int __op_param3 __hidden;
#define PARAM1 ({ int _r; asm("" : "=r"(_r) : "0" (&__op_param1)); _r; })
#define PARAM2 ({ int _r; asm("" : "=r"(_r) : "0" (&__op_param2)); _r; })
#define PARAM3 ({ int _r; asm("" : "=r"(_r) : "0" (&__op_param3)); _r; })
#else
extern int __op_param1, __op_param2, __op_param3;
#define PARAM1 ((long)(&__op_param1))
#define PARAM2 ((long)(&__op_param2))
#define PARAM3 ((long)(&__op_param3))
#endif
extern int __op_jmp0, __op_jmp1, __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

941
dyngen.c

File diff suppressed because it is too large Load Diff

202
dyngen.h Normal file
View File

@@ -0,0 +1,202 @@
/*
* dyngen helpers
*
* Copyright (c) 2003 Fabrice Bellard
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
int __op_param1, __op_param2, __op_param3;
int __op_jmp0, __op_jmp1, __op_jmp2, __op_jmp3;
#ifdef __i386__
static inline void flush_icache_range(unsigned long start, unsigned long stop)
{
}
#endif
#ifdef __s390__
static inline void flush_icache_range(unsigned long start, unsigned long stop)
{
}
#endif
#ifdef __ia64__
static inline void flush_icache_range(unsigned long start, unsigned long stop)
{
}
#endif
#ifdef __powerpc__
#define MIN_CACHE_LINE_SIZE 8 /* conservative value */
static void inline flush_icache_range(unsigned long start, unsigned long stop)
{
unsigned long p;
p = start & ~(MIN_CACHE_LINE_SIZE - 1);
stop = (stop + MIN_CACHE_LINE_SIZE - 1) & ~(MIN_CACHE_LINE_SIZE - 1);
for (p = start; p < stop; p += MIN_CACHE_LINE_SIZE) {
asm volatile ("dcbst 0,%0" : : "r"(p) : "memory");
}
asm volatile ("sync" : : : "memory");
for (p = start; p < stop; p += MIN_CACHE_LINE_SIZE) {
asm volatile ("icbi 0,%0" : : "r"(p) : "memory");
}
asm volatile ("sync" : : : "memory");
asm volatile ("isync" : : : "memory");
}
#endif
#ifdef __alpha__
static inline void flush_icache_range(unsigned long start, unsigned long stop)
{
asm ("imb");
}
#endif
#ifdef __sparc__
static void inline flush_icache_range(unsigned long start, unsigned long stop)
{
unsigned long p;
p = start & ~(8UL - 1UL);
stop = (stop + (8UL - 1UL)) & ~(8UL - 1UL);
for (; p < stop; p += 8)
__asm__ __volatile__("flush\t%0" : : "r" (p));
}
#endif
#ifdef __arm__
static inline void flush_icache_range(unsigned long start, unsigned long stop)
{
register unsigned long _beg __asm ("a1") = start;
register unsigned long _end __asm ("a2") = stop;
register unsigned long _flg __asm ("a3") = 0;
__asm __volatile__ ("swi 0x9f0002" : : "r" (_beg), "r" (_end), "r" (_flg));
}
#endif
#ifdef __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");
static inline void immediate_ldah(void *p, int val) {
uint32_t *dest = p;
long high = ((val >> 16) + ((val >> 15) & 1)) & 0xffff;
*dest &= ~0xffff;
*dest |= high;
*dest |= 31 << 16;
}
static inline void immediate_lda(void *dest, int val) {
*(uint16_t *) dest = val;
}
void fix_bsr(void *p, int offset) {
uint32_t *dest = p;
*dest &= ~((1 << 21) - 1);
*dest |= (offset >> 2) & ((1 << 21) - 1);
}
#endif /* __alpha__ */
#ifdef __arm__
#define MAX_OP_SIZE (128 * 4) /* in bytes */
/* max size of the code that can be generated without calling arm_flush_ldr */
#define MAX_FRAG_SIZE (1024 * 4)
//#define MAX_FRAG_SIZE (135 * 4) /* for testing */
typedef struct LDREntry {
uint8_t *ptr;
uint32_t *data_ptr;
} LDREntry;
static LDREntry arm_ldr_table[1024];
static uint32_t arm_data_table[1024];
extern char exec_loop;
static inline void arm_reloc_pc24(uint32_t *ptr, uint32_t insn, int val)
{
*ptr = (insn & ~0xffffff) | ((insn + ((val - (int)ptr) >> 2)) & 0xffffff);
}
static uint8_t *arm_flush_ldr(uint8_t *gen_code_ptr,
LDREntry *ldr_start, LDREntry *ldr_end,
uint32_t *data_start, uint32_t *data_end,
int gen_jmp)
{
LDREntry *le;
uint32_t *ptr;
int offset, data_size, target;
uint8_t *data_ptr;
uint32_t insn;
data_size = (uint8_t *)data_end - (uint8_t *)data_start;
if (gen_jmp) {
/* generate branch to skip the data */
if (data_size == 0)
return gen_code_ptr;
target = (long)gen_code_ptr + data_size + 4;
arm_reloc_pc24((uint32_t *)gen_code_ptr, 0xeafffffe, target);
gen_code_ptr += 4;
}
/* copy the data */
data_ptr = gen_code_ptr;
memcpy(gen_code_ptr, data_start, data_size);
gen_code_ptr += data_size;
/* patch the ldr to point to the data */
for(le = ldr_start; le < ldr_end; le++) {
ptr = (uint32_t *)le->ptr;
offset = ((unsigned long)(le->data_ptr) - (unsigned long)data_start) +
(unsigned long)data_ptr -
(unsigned long)ptr - 8;
insn = *ptr & ~(0xfff | 0x00800000);
if (offset < 0) {
offset = - offset;
} else {
insn |= 0x00800000;
}
if (offset > 0xfff) {
fprintf(stderr, "Error ldr offset\n");
abort();
}
insn |= offset;
*ptr = insn;
}
return gen_code_ptr;
}
#endif /* __arm__ */

116
elf.h
View File

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

442
exec-all.h Normal file
View File

@@ -0,0 +1,442 @@
/*
* internal execution defines for qemu
*
* Copyright (c) 2003 Fabrice Bellard
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/* 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 */
#define DISAS_UPDATE 2 /* cpu state was modified dynamically */
#define DISAS_TB_JUMP 3 /* only pc was modified statically */
struct TranslationBlock;
/* XXX: make safe guess about sizes */
#define MAX_OP_PER_INSTR 32
#define OPC_BUF_SIZE 512
#define OPC_MAX_SIZE (OPC_BUF_SIZE - MAX_OP_PER_INSTR)
#define OPPARAM_BUF_SIZE (OPC_BUF_SIZE * 3)
extern uint16_t gen_opc_buf[OPC_BUF_SIZE];
extern uint32_t gen_opparam_buf[OPPARAM_BUF_SIZE];
extern uint32_t gen_opc_pc[OPC_BUF_SIZE];
extern uint8_t gen_opc_cc_op[OPC_BUF_SIZE];
extern uint8_t gen_opc_instr_start[OPC_BUF_SIZE];
#if defined(TARGET_I386)
void optimize_flags_init(void);
#endif
extern FILE *logfile;
extern int loglevel;
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(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 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 */
#define CODE_GEN_HASH_BITS 15
#define CODE_GEN_HASH_SIZE (1 << CODE_GEN_HASH_BITS)
/* maximum total translate dcode allocated */
#define CODE_GEN_BUFFER_SIZE (2048 * 1024)
//#define CODE_GEN_BUFFER_SIZE (128 * 1024)
#if defined(__powerpc__)
#define USE_DIRECT_JUMP
#endif
typedef struct TranslationBlock {
unsigned long pc; /* simulated PC corresponding to this block (EIP + CS base) */
unsigned long cs_base; /* CS base for this block */
unsigned int flags; /* flags defining in which context the code was generated */
uint16_t size; /* size of target code for this block (1 <=
size <= TARGET_PAGE_SIZE) */
uint8_t *tc_ptr; /* pointer to the translated code */
struct TranslationBlock *hash_next; /* next matching block */
struct TranslationBlock *page_next[2]; /* next blocks in even/odd page */
/* the following data are used to directly call another TB from
the code of this one. */
uint16_t tb_next_offset[2]; /* offset of original jump target */
#ifdef USE_DIRECT_JUMP
uint16_t tb_jmp_offset[4]; /* offset of jump instruction */
#else
uint32_t tb_next[2]; /* address of jump generated code */
#endif
/* list of TBs jumping to this one. This is a circular list using
the two least significant bits of the pointers to tell what is
the next pointer: 0 = jmp_next[0], 1 = jmp_next[1], 2 =
jmp_first */
struct TranslationBlock *jmp_next[2];
struct TranslationBlock *jmp_first;
} TranslationBlock;
static inline unsigned int tb_hash_func(unsigned long pc)
{
return pc & (CODE_GEN_HASH_SIZE - 1);
}
TranslationBlock *tb_alloc(unsigned long pc);
void tb_flush(void);
void tb_link(TranslationBlock *tb);
extern TranslationBlock *tb_hash[CODE_GEN_HASH_SIZE];
extern uint8_t code_gen_buffer[CODE_GEN_BUFFER_SIZE];
extern uint8_t *code_gen_ptr;
/* find a translation block in the translation cache. If not found,
return NULL and the pointer to the last element of the list in pptb */
static inline TranslationBlock *tb_find(TranslationBlock ***pptb,
unsigned long pc,
unsigned long cs_base,
unsigned int flags)
{
TranslationBlock **ptb, *tb;
unsigned int h;
h = tb_hash_func(pc);
ptb = &tb_hash[h];
for(;;) {
tb = *ptb;
if (!tb)
break;
if (tb->pc == pc && tb->cs_base == cs_base && tb->flags == flags)
return tb;
ptb = &tb->hash_next;
}
*pptb = ptb;
return NULL;
}
#if defined(__powerpc__)
static inline void tb_set_jmp_target1(unsigned long jmp_addr, unsigned long addr)
{
uint32_t val, *ptr;
/* patch the branch destination */
ptr = (uint32_t *)jmp_addr;
val = *ptr;
val = (val & ~0x03fffffc) | ((addr - jmp_addr) & 0x03fffffc);
*ptr = val;
/* flush icache */
asm volatile ("dcbst 0,%0" : : "r"(ptr) : "memory");
asm volatile ("sync" : : : "memory");
asm volatile ("icbi 0,%0" : : "r"(ptr) : "memory");
asm volatile ("sync" : : : "memory");
asm volatile ("isync" : : : "memory");
}
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 */
static inline void tb_set_jmp_target(TranslationBlock *tb,
int n, unsigned long addr)
{
tb->tb_next[n] = addr;
}
#endif
static inline void tb_add_jump(TranslationBlock *tb, int n,
TranslationBlock *tb_next)
{
/* NOTE: this test is only needed for thread safety */
if (!tb->jmp_next[n]) {
/* patch the native jump address */
tb_set_jmp_target(tb, n, (unsigned long)tb_next->tc_ptr);
/* add in TB jmp circular list */
tb->jmp_next[n] = tb_next->jmp_first;
tb_next->jmp_first = (TranslationBlock *)((long)(tb) | (n));
}
}
TranslationBlock *tb_find_pc(unsigned long pc_ptr);
#ifndef offsetof
#define offsetof(type, field) ((size_t) &((type *)0)->field)
#endif
#if defined(__powerpc__)
/* on PowerPC we patch the jump instruction directly */
#define JUMP_TB(opname, tbparam, n, eip)\
do {\
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(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)
{
int ret;
__asm__ __volatile__ (
"0: lwarx %0,0,%1 ;"
" xor. %0,%3,%0;"
" bne 1f;"
" stwcx. %2,0,%1;"
" bne- 0b;"
"1: "
: "=&r" (ret)
: "r" (p), "r" (1), "r" (0)
: "cr0", "memory");
return ret;
}
#endif
#ifdef __i386__
static inline int testandset (int *p)
{
char ret;
long int readval;
__asm__ __volatile__ ("lock; cmpxchgl %3, %1; sete %0"
: "=q" (ret), "=m" (*p), "=a" (readval)
: "r" (1), "m" (*p), "a" (0)
: "memory");
return ret;
}
#endif
#ifdef __s390__
static inline int testandset (int *p)
{
int ret;
__asm__ __volatile__ ("0: cs %0,%1,0(%2)\n"
" jl 0b"
: "=&d" (ret)
: "r" (1), "a" (p), "0" (*p)
: "cc", "memory" );
return ret;
}
#endif
#ifdef __alpha__
static inline int testandset (int *p)
{
int ret;
unsigned long one;
__asm__ __volatile__ ("0: mov 1,%2\n"
" ldl_l %0,%1\n"
" stl_c %2,%1\n"
" beq %2,1f\n"
".subsection 2\n"
"1: br 0b\n"
".previous"
: "=r" (ret), "=m" (*p), "=r" (one)
: "m" (*p));
return ret;
}
#endif
#ifdef __sparc__
static inline int testandset (int *p)
{
int ret;
__asm__ __volatile__("ldstub [%1], %0"
: "=r" (ret)
: "r" (p)
: "memory");
return (ret ? 1 : 0);
}
#endif
#ifdef __arm__
static inline int testandset (int *spinlock)
{
register unsigned int ret;
__asm__ __volatile__("swp %0, %1, [%2]"
: "=r"(ret)
: "0"(1), "r"(spinlock));
return ret;
}
#endif
#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 1
static inline void spin_lock(spinlock_t *lock)
{
while (testandset(lock));
}
static inline void spin_unlock(spinlock_t *lock)
{
*lock = 0;
}
static inline int spin_trylock(spinlock_t *lock)
{
return !testandset(lock);
}
#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;
#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

View File

@@ -1,514 +0,0 @@
/*
* i386 emulator main execution loop
*
* Copyright (c) 2003 Fabrice Bellard
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "exec-i386.h"
//#define DEBUG_EXEC
#define DEBUG_FLUSH
//#define DEBUG_SIGNAL
/* main execution loop */
/* maximum total translate dcode allocated */
#define CODE_GEN_BUFFER_SIZE (2048 * 1024)
//#define CODE_GEN_BUFFER_SIZE (128 * 1024)
#define CODE_GEN_MAX_SIZE 65536
#define CODE_GEN_ALIGN 16 /* must be >= of the size of a icache line */
/* threshold to flush the translated code buffer */
#define CODE_GEN_BUFFER_MAX_SIZE (CODE_GEN_BUFFER_SIZE - CODE_GEN_MAX_SIZE)
#define CODE_GEN_MAX_BLOCKS (CODE_GEN_BUFFER_SIZE / 64)
#define CODE_GEN_HASH_BITS 15
#define CODE_GEN_HASH_SIZE (1 << CODE_GEN_HASH_BITS)
typedef struct TranslationBlock {
unsigned long pc; /* simulated PC corresponding to this block (EIP + CS base) */
unsigned long cs_base; /* CS base for this block */
unsigned int flags; /* flags defining in which context the code was generated */
uint8_t *tc_ptr; /* pointer to the translated code */
struct TranslationBlock *hash_next; /* next matching block */
} TranslationBlock;
TranslationBlock tbs[CODE_GEN_MAX_BLOCKS];
TranslationBlock *tb_hash[CODE_GEN_HASH_SIZE];
int nb_tbs;
uint8_t code_gen_buffer[CODE_GEN_BUFFER_SIZE];
uint8_t *code_gen_ptr;
/* thread support */
#ifdef __powerpc__
static inline int testandset (int *p)
{
int ret;
__asm__ __volatile__ (
"0: lwarx %0,0,%1 ;"
" xor. %0,%3,%0;"
" bne 1f;"
" stwcx. %2,0,%1;"
" bne- 0b;"
"1: "
: "=&r" (ret)
: "r" (p), "r" (1), "r" (0)
: "cr0", "memory");
return ret;
}
#endif
#ifdef __i386__
static inline int testandset (int *p)
{
char ret;
long int readval;
__asm__ __volatile__ ("lock; cmpxchgl %3, %1; sete %0"
: "=q" (ret), "=m" (*p), "=a" (readval)
: "r" (1), "m" (*p), "a" (0)
: "memory");
return ret;
}
#endif
#ifdef __s390__
static inline int testandset (int *p)
{
int ret;
__asm__ __volatile__ ("0: cs %0,%1,0(%2)\n"
" jl 0b"
: "=&d" (ret)
: "r" (1), "a" (p), "0" (*p)
: "cc", "memory" );
return ret;
}
#endif
int global_cpu_lock = 0;
void cpu_lock(void)
{
while (testandset(&global_cpu_lock));
}
void cpu_unlock(void)
{
global_cpu_lock = 0;
}
/* exception support */
/* NOTE: not static to force relocation generation by GCC */
void raise_exception(int exception_index)
{
/* NOTE: the register at this point must be saved by hand because
longjmp restore them */
#ifdef reg_EAX
env->regs[R_EAX] = EAX;
#endif
#ifdef reg_ECX
env->regs[R_ECX] = ECX;
#endif
#ifdef reg_EDX
env->regs[R_EDX] = EDX;
#endif
#ifdef reg_EBX
env->regs[R_EBX] = EBX;
#endif
#ifdef reg_ESP
env->regs[R_ESP] = ESP;
#endif
#ifdef reg_EBP
env->regs[R_EBP] = EBP;
#endif
#ifdef reg_ESI
env->regs[R_ESI] = ESI;
#endif
#ifdef reg_EDI
env->regs[R_EDI] = EDI;
#endif
env->exception_index = exception_index;
longjmp(env->jmp_env, 1);
}
#if defined(DEBUG_EXEC)
static const char *cc_op_str[] = {
"DYNAMIC",
"EFLAGS",
"MUL",
"ADDB",
"ADDW",
"ADDL",
"ADCB",
"ADCW",
"ADCL",
"SUBB",
"SUBW",
"SUBL",
"SBBB",
"SBBW",
"SBBL",
"LOGICB",
"LOGICW",
"LOGICL",
"INCB",
"INCW",
"INCL",
"DECB",
"DECW",
"DECL",
"SHLB",
"SHLW",
"SHLL",
"SARB",
"SARW",
"SARL",
};
static void cpu_x86_dump_state(FILE *f)
{
int eflags;
eflags = cc_table[CC_OP].compute_all();
eflags |= (DF & DIRECTION_FLAG);
fprintf(f,
"EAX=%08x EBX=%08X ECX=%08x EDX=%08x\n"
"ESI=%08x EDI=%08X EBP=%08x ESP=%08x\n"
"CCS=%08x CCD=%08x CCO=%-8s EFL=%c%c%c%c%c%c%c\n"
"EIP=%08x\n",
env->regs[R_EAX], env->regs[R_EBX], env->regs[R_ECX], env->regs[R_EDX],
env->regs[R_ESI], env->regs[R_EDI], env->regs[R_EBP], env->regs[R_ESP],
env->cc_src, env->cc_dst, cc_op_str[env->cc_op],
eflags & DIRECTION_FLAG ? 'D' : '-',
eflags & CC_O ? 'O' : '-',
eflags & CC_S ? 'S' : '-',
eflags & CC_Z ? 'Z' : '-',
eflags & CC_A ? 'A' : '-',
eflags & CC_P ? 'P' : '-',
eflags & CC_C ? 'C' : '-',
env->eip);
#if 1
fprintf(f, "ST0=%f ST1=%f ST2=%f ST3=%f\n",
(double)ST0, (double)ST1, (double)ST(2), (double)ST(3));
#endif
}
#endif
void cpu_x86_tblocks_init(void)
{
if (!code_gen_ptr) {
code_gen_ptr = code_gen_buffer;
}
}
/* flush all the translation blocks */
static void tb_flush(void)
{
int i;
#ifdef DEBUG_FLUSH
printf("gemu: flush code_size=%d nb_tbs=%d avg_tb_size=%d\n",
code_gen_ptr - code_gen_buffer,
nb_tbs,
(code_gen_ptr - code_gen_buffer) / nb_tbs);
#endif
nb_tbs = 0;
for(i = 0;i < CODE_GEN_HASH_SIZE; i++)
tb_hash[i] = NULL;
code_gen_ptr = code_gen_buffer;
/* XXX: flush processor icache at this point */
}
/* find a translation block in the translation cache. If not found,
return NULL and the pointer to the last element of the list in pptb */
static inline TranslationBlock *tb_find(TranslationBlock ***pptb,
unsigned long pc,
unsigned long cs_base,
unsigned int flags)
{
TranslationBlock **ptb, *tb;
unsigned int h;
h = pc & (CODE_GEN_HASH_SIZE - 1);
ptb = &tb_hash[h];
for(;;) {
tb = *ptb;
if (!tb)
break;
if (tb->pc == pc && tb->cs_base == cs_base && tb->flags == flags)
return tb;
ptb = &tb->hash_next;
}
*pptb = ptb;
return NULL;
}
/* allocate a new translation block. flush the translation buffer if
too many translation blocks or too much generated code */
static inline TranslationBlock *tb_alloc(void)
{
TranslationBlock *tb;
if (nb_tbs >= CODE_GEN_MAX_BLOCKS ||
(code_gen_ptr - code_gen_buffer) >= CODE_GEN_BUFFER_MAX_SIZE)
tb_flush();
tb = &tbs[nb_tbs++];
return tb;
}
int cpu_x86_exec(CPUX86State *env1)
{
int saved_T0, saved_T1, saved_A0;
CPUX86State *saved_env;
#ifdef reg_EAX
int saved_EAX;
#endif
#ifdef reg_ECX
int saved_ECX;
#endif
#ifdef reg_EDX
int saved_EDX;
#endif
#ifdef reg_EBX
int saved_EBX;
#endif
#ifdef reg_ESP
int saved_ESP;
#endif
#ifdef reg_EBP
int saved_EBP;
#endif
#ifdef reg_ESI
int saved_ESI;
#endif
#ifdef reg_EDI
int saved_EDI;
#endif
int code_gen_size, ret;
void (*gen_func)(void);
TranslationBlock *tb, **ptb;
uint8_t *tc_ptr, *cs_base, *pc;
unsigned int flags;
/* first we save global registers */
saved_T0 = T0;
saved_T1 = T1;
saved_A0 = A0;
saved_env = env;
env = env1;
#ifdef reg_EAX
saved_EAX = EAX;
EAX = env->regs[R_EAX];
#endif
#ifdef reg_ECX
saved_ECX = ECX;
ECX = env->regs[R_ECX];
#endif
#ifdef reg_EDX
saved_EDX = EDX;
EDX = env->regs[R_EDX];
#endif
#ifdef reg_EBX
saved_EBX = EBX;
EBX = env->regs[R_EBX];
#endif
#ifdef reg_ESP
saved_ESP = ESP;
ESP = env->regs[R_ESP];
#endif
#ifdef reg_EBP
saved_EBP = EBP;
EBP = env->regs[R_EBP];
#endif
#ifdef reg_ESI
saved_ESI = ESI;
ESI = env->regs[R_ESI];
#endif
#ifdef reg_EDI
saved_EDI = EDI;
EDI = env->regs[R_EDI];
#endif
/* put eflags in CPU temporary format */
CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
DF = 1 - (2 * ((env->eflags >> 10) & 1));
CC_OP = CC_OP_EFLAGS;
env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
env->interrupt_request = 0;
/* prepare setjmp context for exception handling */
if (setjmp(env->jmp_env) == 0) {
for(;;) {
if (env->interrupt_request) {
raise_exception(EXCP_INTERRUPT);
}
#ifdef DEBUG_EXEC
if (loglevel) {
cpu_x86_dump_state(logfile);
}
#endif
/* we compute the CPU state. We assume it will not
change during the whole generated block. */
flags = env->seg_cache[R_CS].seg_32bit << GEN_FLAG_CODE32_SHIFT;
flags |= env->seg_cache[R_SS].seg_32bit << GEN_FLAG_SS32_SHIFT;
flags |= (((unsigned long)env->seg_cache[R_DS].base |
(unsigned long)env->seg_cache[R_ES].base |
(unsigned long)env->seg_cache[R_SS].base) != 0) <<
GEN_FLAG_ADDSEG_SHIFT;
flags |= (env->eflags & VM_MASK) >> (17 - GEN_FLAG_VM_SHIFT);
cs_base = env->seg_cache[R_CS].base;
pc = cs_base + env->eip;
tb = tb_find(&ptb, (unsigned long)pc, (unsigned long)cs_base,
flags);
if (!tb) {
/* if no translated code available, then translate it now */
/* XXX: very inefficient: we lock all the cpus when
generating code */
cpu_lock();
tc_ptr = code_gen_ptr;
ret = cpu_x86_gen_code(code_gen_ptr, CODE_GEN_MAX_SIZE,
&code_gen_size, pc, cs_base, flags);
/* if invalid instruction, signal it */
if (ret != 0) {
cpu_unlock();
raise_exception(EXCP06_ILLOP);
}
tb = tb_alloc();
*ptb = tb;
tb->pc = (unsigned long)pc;
tb->cs_base = (unsigned long)cs_base;
tb->flags = flags;
tb->tc_ptr = tc_ptr;
tb->hash_next = NULL;
code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1));
cpu_unlock();
}
/* execute the generated code */
tc_ptr = tb->tc_ptr;
gen_func = (void *)tc_ptr;
gen_func();
}
}
ret = env->exception_index;
/* restore flags in standard format */
env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
/* restore global registers */
#ifdef reg_EAX
EAX = saved_EAX;
#endif
#ifdef reg_ECX
ECX = saved_ECX;
#endif
#ifdef reg_EDX
EDX = saved_EDX;
#endif
#ifdef reg_EBX
EBX = saved_EBX;
#endif
#ifdef reg_ESP
ESP = saved_ESP;
#endif
#ifdef reg_EBP
EBP = saved_EBP;
#endif
#ifdef reg_ESI
ESI = saved_ESI;
#endif
#ifdef reg_EDI
EDI = saved_EDI;
#endif
T0 = saved_T0;
T1 = saved_T1;
A0 = saved_A0;
env = saved_env;
return ret;
}
void cpu_x86_interrupt(CPUX86State *s)
{
s->interrupt_request = 1;
}
void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector)
{
CPUX86State *saved_env;
saved_env = env;
env = s;
load_seg(seg_reg, selector);
env = saved_env;
}
#undef EAX
#undef ECX
#undef EDX
#undef EBX
#undef ESP
#undef EBP
#undef ESI
#undef EDI
#undef EIP
#include <signal.h>
#include <sys/ucontext.h>
static inline int handle_cpu_signal(unsigned long pc,
sigset_t *old_set)
{
#ifdef DEBUG_SIGNAL
printf("gemu: SIGSEGV pc=0x%08lx oldset=0x%08lx\n",
pc, *(unsigned long *)old_set);
#endif
if (pc >= (unsigned long)code_gen_buffer &&
pc < (unsigned long)code_gen_buffer + CODE_GEN_BUFFER_SIZE) {
/* the PC is inside the translated code. It means that we have
a virtual CPU fault */
/* we restore the process signal mask as the sigreturn should
do it */
sigprocmask(SIG_SETMASK, old_set, NULL);
/* XXX: need to compute virtual pc position by retranslating
code. The rest of the CPU state should be correct. */
raise_exception(EXCP0D_GPF);
/* never comes here */
return 1;
} else {
return 0;
}
}
int cpu_x86_signal_handler(int host_signum, struct siginfo *info,
void *puc)
{
#if defined(__i386__)
struct ucontext *uc = puc;
unsigned long pc;
sigset_t *pold_set;
#ifndef REG_EIP
/* for glibc 2.1 */
#define REG_EIP EIP
#endif
pc = uc->uc_mcontext.gregs[REG_EIP];
pold_set = &uc->uc_sigmask;
return handle_cpu_signal(pc, pold_set);
#else
#warning No CPU specific signal handler: cannot handle target SIGSEGV events
return 0;
#endif
}

View File

@@ -1,177 +0,0 @@
/*
* i386 execution defines
*
* Copyright (c) 2003 Fabrice Bellard
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
typedef unsigned long long uint64_t;
typedef signed char int8_t;
typedef signed short int16_t;
typedef signed int int32_t;
typedef signed long long int64_t;
#define bswap32(x) \
({ \
uint32_t __x = (x); \
((uint32_t)( \
(((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
(((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \
(((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \
(((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) )); \
})
#define NULL 0
#include <fenv.h>
typedef struct FILE FILE;
extern FILE *logfile;
extern int loglevel;
extern int fprintf(FILE *, const char *, ...);
extern int printf(const char *, ...);
#ifdef __i386__
register unsigned int T0 asm("ebx");
register unsigned int T1 asm("esi");
register unsigned int A0 asm("edi");
register struct CPUX86State *env asm("ebp");
#endif
#ifdef __powerpc__
register unsigned int EAX asm("r16");
register unsigned int ECX asm("r17");
register unsigned int EDX asm("r18");
register unsigned int EBX asm("r19");
register unsigned int ESP asm("r20");
register unsigned int EBP asm("r21");
register unsigned int ESI asm("r22");
register unsigned int EDI asm("r23");
register unsigned int T0 asm("r24");
register unsigned int T1 asm("r25");
register unsigned int A0 asm("r26");
register struct CPUX86State *env asm("r27");
#define USE_INT_TO_FLOAT_HELPERS
#define BUGGY_GCC_DIV64
#define reg_EAX
#define reg_ECX
#define reg_EDX
#define reg_EBX
#define reg_ESP
#define reg_EBP
#define reg_ESI
#define reg_EDI
#endif
#ifdef __arm__
register unsigned int T0 asm("r4");
register unsigned int T1 asm("r5");
register unsigned int A0 asm("r6");
register struct CPUX86State *env asm("r7");
#endif
#ifdef __mips__
register unsigned int T0 asm("s0");
register unsigned int T1 asm("s1");
register unsigned int A0 asm("s2");
register struct CPUX86State *env asm("s3");
#endif
#ifdef __sparc__
register unsigned int T0 asm("l0");
register unsigned int T1 asm("l1");
register unsigned int A0 asm("l2");
register struct CPUX86State *env asm("l3");
#endif
#ifdef __s390__
register unsigned int T0 asm("r7");
register unsigned int T1 asm("r8");
register unsigned int A0 asm("r9");
register struct CPUX86State *env asm("r10");
#endif
#ifdef __alpha__
register unsigned int T0 asm("$9");
register unsigned int T1 asm("$10");
register unsigned int A0 asm("$11");
register struct CPUX86State *env asm("$12");
#endif
/* force GCC to generate only one epilog at the end of the function */
#define FORCE_RET() asm volatile ("");
#ifndef OPPROTO
#define OPPROTO
#endif
#define xglue(x, y) x ## y
#define glue(x, y) xglue(x, y)
#ifndef reg_EAX
#define EAX (env->regs[R_EAX])
#endif
#ifndef reg_ECX
#define ECX (env->regs[R_ECX])
#endif
#ifndef reg_EDX
#define EDX (env->regs[R_EDX])
#endif
#ifndef reg_EBX
#define EBX (env->regs[R_EBX])
#endif
#ifndef reg_ESP
#define ESP (env->regs[R_ESP])
#endif
#ifndef reg_EBP
#define EBP (env->regs[R_EBP])
#endif
#ifndef reg_ESI
#define ESI (env->regs[R_ESI])
#endif
#ifndef reg_EDI
#define EDI (env->regs[R_EDI])
#endif
#define EIP (env->eip)
#define DF (env->df)
#define CC_SRC (env->cc_src)
#define CC_DST (env->cc_dst)
#define CC_OP (env->cc_op)
/* float macros */
#define FT0 (env->ft0)
#define ST0 (env->fpregs[env->fpstt])
#define ST(n) (env->fpregs[(env->fpstt + (n)) & 7])
#define ST1 ST(1)
extern int __op_param1, __op_param2, __op_param3;
#define PARAM1 ((long)(&__op_param1))
#define PARAM2 ((long)(&__op_param2))
#define PARAM3 ((long)(&__op_param3))
#include "cpu-i386.h"
typedef struct CCTable {
int (*compute_all)(void); /* return all the flags */
int (*compute_c)(void); /* return the C flag */
} CCTable;
extern CCTable cc_table[];
void load_seg(int seg_reg, int selector);
void cpu_lock(void);
void cpu_unlock(void);
void raise_exception(int exception_index);
void OPPROTO op_movl_eflags_T0(void);
void OPPROTO op_movl_T0_eflags(void);

961
exec.c Normal file
View File

@@ -0,0 +1,961 @@
/*
* virtual page mapping and translated block handling
*
* Copyright (c) 2003 Fabrice Bellard
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <inttypes.h>
#include <sys/mman.h>
#include "config.h"
#include "cpu.h"
#include "exec-all.h"
//#define DEBUG_TB_INVALIDATE
//#define DEBUG_FLUSH
/* make various TB consistency checks */
//#define DEBUG_TB_CHECK
/* threshold to flush the translated code buffer */
#define CODE_GEN_BUFFER_MAX_SIZE (CODE_GEN_BUFFER_SIZE - CODE_GEN_MAX_SIZE)
#define CODE_GEN_MAX_BLOCKS (CODE_GEN_BUFFER_SIZE / 64)
TranslationBlock tbs[CODE_GEN_MAX_BLOCKS];
TranslationBlock *tb_hash[CODE_GEN_HASH_SIZE];
int nb_tbs;
/* any access to the tbs or the page table must use this lock */
spinlock_t tb_lock = SPIN_LOCK_UNLOCKED;
uint8_t code_gen_buffer[CODE_GEN_BUFFER_SIZE];
uint8_t *code_gen_ptr;
/* XXX: pack the flags in the low bits of the pointer ? */
typedef struct PageDesc {
unsigned long flags;
TranslationBlock *first_tb;
} PageDesc;
#define L2_BITS 10
#define L1_BITS (32 - L2_BITS - TARGET_PAGE_BITS)
#define L1_SIZE (1 << L1_BITS)
#define L2_SIZE (1 << L2_BITS)
static void tb_invalidate_page(unsigned long address);
static void io_mem_init(void);
unsigned long real_host_page_size;
unsigned long host_page_bits;
unsigned long host_page_size;
unsigned long host_page_mask;
static PageDesc *l1_map[L1_SIZE];
/* 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 >=
TARGET_PAGE_SIZE */
real_host_page_size = getpagesize();
if (host_page_size == 0)
host_page_size = real_host_page_size;
if (host_page_size < TARGET_PAGE_SIZE)
host_page_size = TARGET_PAGE_SIZE;
host_page_bits = 0;
while ((1 << host_page_bits) < host_page_size)
host_page_bits++;
host_page_mask = ~(host_page_size - 1);
}
/* dump memory mappings */
void page_dump(FILE *f)
{
unsigned long start, end;
int i, j, prot, prot1;
PageDesc *p;
fprintf(f, "%-8s %-8s %-8s %s\n",
"start", "end", "size", "prot");
start = -1;
end = -1;
prot = 0;
for(i = 0; i <= L1_SIZE; i++) {
if (i < L1_SIZE)
p = l1_map[i];
else
p = NULL;
for(j = 0;j < L2_SIZE; j++) {
if (!p)
prot1 = 0;
else
prot1 = p[j].flags;
if (prot1 != prot) {
end = (i << (32 - L1_BITS)) | (j << TARGET_PAGE_BITS);
if (start != -1) {
fprintf(f, "%08lx-%08lx %08lx %c%c%c\n",
start, end, end - start,
prot & PAGE_READ ? 'r' : '-',
prot & PAGE_WRITE ? 'w' : '-',
prot & PAGE_EXEC ? 'x' : '-');
}
if (prot1 != 0)
start = end;
else
start = -1;
prot = prot1;
}
if (!p)
break;
}
}
}
static inline PageDesc *page_find_alloc(unsigned int index)
{
PageDesc **lp, *p;
lp = &l1_map[index >> L2_BITS];
p = *lp;
if (!p) {
/* allocate if not found */
p = malloc(sizeof(PageDesc) * L2_SIZE);
memset(p, 0, sizeof(PageDesc) * L2_SIZE);
*lp = p;
}
return p + (index & (L2_SIZE - 1));
}
static inline PageDesc *page_find(unsigned int index)
{
PageDesc *p;
p = l1_map[index >> L2_BITS];
if (!p)
return 0;
return p + (index & (L2_SIZE - 1));
}
int page_get_flags(unsigned long address)
{
PageDesc *p;
p = page_find(address >> TARGET_PAGE_BITS);
if (!p)
return 0;
return p->flags;
}
/* modify the flags of a page and invalidate the code if
necessary. The flag PAGE_WRITE_ORG is positionned automatically
depending on PAGE_WRITE */
void page_set_flags(unsigned long start, unsigned long end, int flags)
{
PageDesc *p;
unsigned long addr;
start = start & TARGET_PAGE_MASK;
end = TARGET_PAGE_ALIGN(end);
if (flags & PAGE_WRITE)
flags |= PAGE_WRITE_ORG;
spin_lock(&tb_lock);
for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) {
p = page_find_alloc(addr >> TARGET_PAGE_BITS);
/* if the write protection is set, then we invalidate the code
inside */
if (!(p->flags & PAGE_WRITE) &&
(flags & PAGE_WRITE) &&
p->first_tb) {
tb_invalidate_page(addr);
}
p->flags = flags;
}
spin_unlock(&tb_lock);
}
void cpu_exec_init(void)
{
if (!code_gen_ptr) {
code_gen_ptr = code_gen_buffer;
page_init();
io_mem_init();
}
}
/* set to NULL all the 'first_tb' fields in all PageDescs */
static void page_flush_tb(void)
{
int i, j;
PageDesc *p;
for(i = 0; i < L1_SIZE; i++) {
p = l1_map[i];
if (p) {
for(j = 0; j < L2_SIZE; j++)
p[j].first_tb = NULL;
}
}
}
/* flush all the translation blocks */
/* XXX: tb_flush is currently not thread safe */
void tb_flush(void)
{
int i;
#ifdef DEBUG_FLUSH
printf("qemu: flush code_size=%d nb_tbs=%d avg_tb_size=%d\n",
code_gen_ptr - code_gen_buffer,
nb_tbs,
(code_gen_ptr - code_gen_buffer) / nb_tbs);
#endif
nb_tbs = 0;
for(i = 0;i < CODE_GEN_HASH_SIZE; i++)
tb_hash[i] = NULL;
page_flush_tb();
code_gen_ptr = code_gen_buffer;
/* XXX: flush processor icache at this point if cache flush is
expensive */
}
#ifdef DEBUG_TB_CHECK
static void tb_invalidate_check(unsigned long address)
{
TranslationBlock *tb;
int i;
address &= TARGET_PAGE_MASK;
for(i = 0;i < CODE_GEN_HASH_SIZE; i++) {
for(tb = tb_hash[i]; tb != NULL; tb = tb->hash_next) {
if (!(address + TARGET_PAGE_SIZE <= tb->pc ||
address >= tb->pc + tb->size)) {
printf("ERROR invalidate: address=%08lx PC=%08lx size=%04x\n",
address, tb->pc, tb->size);
}
}
}
}
/* verify that all the pages have correct rights for code */
static void tb_page_check(void)
{
TranslationBlock *tb;
int i, flags1, flags2;
for(i = 0;i < CODE_GEN_HASH_SIZE; i++) {
for(tb = tb_hash[i]; tb != NULL; tb = tb->hash_next) {
flags1 = page_get_flags(tb->pc);
flags2 = page_get_flags(tb->pc + tb->size - 1);
if ((flags1 & PAGE_WRITE) || (flags2 & PAGE_WRITE)) {
printf("ERROR page flags: PC=%08lx size=%04x f1=%x f2=%x\n",
tb->pc, tb->size, flags1, flags2);
}
}
}
}
void tb_jmp_check(TranslationBlock *tb)
{
TranslationBlock *tb1;
unsigned int n1;
/* suppress any remaining jumps to this TB */
tb1 = tb->jmp_first;
for(;;) {
n1 = (long)tb1 & 3;
tb1 = (TranslationBlock *)((long)tb1 & ~3);
if (n1 == 2)
break;
tb1 = tb1->jmp_next[n1];
}
/* check end of list */
if (tb1 != tb) {
printf("ERROR: jmp_list from 0x%08lx\n", (long)tb);
}
}
#endif
/* invalidate one TB */
static inline void tb_remove(TranslationBlock **ptb, TranslationBlock *tb,
int next_offset)
{
TranslationBlock *tb1;
for(;;) {
tb1 = *ptb;
if (tb1 == tb) {
*ptb = *(TranslationBlock **)((char *)tb1 + next_offset);
break;
}
ptb = (TranslationBlock **)((char *)tb1 + next_offset);
}
}
static inline void tb_jmp_remove(TranslationBlock *tb, int n)
{
TranslationBlock *tb1, **ptb;
unsigned int n1;
ptb = &tb->jmp_next[n];
tb1 = *ptb;
if (tb1) {
/* find tb(n) in circular list */
for(;;) {
tb1 = *ptb;
n1 = (long)tb1 & 3;
tb1 = (TranslationBlock *)((long)tb1 & ~3);
if (n1 == n && tb1 == tb)
break;
if (n1 == 2) {
ptb = &tb1->jmp_first;
} else {
ptb = &tb1->jmp_next[n1];
}
}
/* now we can suppress tb(n) from the list */
*ptb = tb->jmp_next[n];
tb->jmp_next[n] = NULL;
}
}
/* reset the jump entry 'n' of a TB so that it is not chained to
another TB */
static inline void tb_reset_jump(TranslationBlock *tb, int n)
{
tb_set_jmp_target(tb, n, (unsigned long)(tb->tc_ptr + tb->tb_next_offset[n]));
}
static inline void tb_invalidate(TranslationBlock *tb, int parity)
{
PageDesc *p;
unsigned int page_index1, page_index2;
unsigned int h, n1;
TranslationBlock *tb1, *tb2;
/* remove the TB from the hash list */
h = tb_hash_func(tb->pc);
tb_remove(&tb_hash[h], tb,
offsetof(TranslationBlock, hash_next));
/* remove the TB from the page list */
page_index1 = tb->pc >> TARGET_PAGE_BITS;
if ((page_index1 & 1) == parity) {
p = page_find(page_index1);
tb_remove(&p->first_tb, tb,
offsetof(TranslationBlock, page_next[page_index1 & 1]));
}
page_index2 = (tb->pc + tb->size - 1) >> TARGET_PAGE_BITS;
if ((page_index2 & 1) == parity) {
p = page_find(page_index2);
tb_remove(&p->first_tb, tb,
offsetof(TranslationBlock, page_next[page_index2 & 1]));
}
/* suppress this TB from the two jump lists */
tb_jmp_remove(tb, 0);
tb_jmp_remove(tb, 1);
/* suppress any remaining jumps to this TB */
tb1 = tb->jmp_first;
for(;;) {
n1 = (long)tb1 & 3;
if (n1 == 2)
break;
tb1 = (TranslationBlock *)((long)tb1 & ~3);
tb2 = tb1->jmp_next[n1];
tb_reset_jump(tb1, n1);
tb1->jmp_next[n1] = NULL;
tb1 = tb2;
}
tb->jmp_first = (TranslationBlock *)((long)tb | 2); /* fail safe */
}
/* invalidate all TBs which intersect with the target page starting at addr */
static void tb_invalidate_page(unsigned long address)
{
TranslationBlock *tb_next, *tb;
unsigned int page_index;
int parity1, parity2;
PageDesc *p;
#ifdef DEBUG_TB_INVALIDATE
printf("tb_invalidate_page: %lx\n", address);
#endif
page_index = address >> TARGET_PAGE_BITS;
p = page_find(page_index);
if (!p)
return;
tb = p->first_tb;
parity1 = page_index & 1;
parity2 = parity1 ^ 1;
while (tb != NULL) {
tb_next = tb->page_next[parity1];
tb_invalidate(tb, parity2);
tb = tb_next;
}
p->first_tb = NULL;
}
/* add the tb in the target page and protect it if necessary */
static inline void tb_alloc_page(TranslationBlock *tb, unsigned int page_index)
{
PageDesc *p;
unsigned long host_start, host_end, addr, page_addr;
int prot;
p = page_find_alloc(page_index);
tb->page_next[page_index & 1] = p->first_tb;
p->first_tb = tb;
if (p->flags & PAGE_WRITE) {
/* force the host page as non writable (writes will have a
page fault + mprotect overhead) */
page_addr = (page_index << TARGET_PAGE_BITS);
host_start = page_addr & host_page_mask;
host_end = host_start + host_page_size;
prot = 0;
for(addr = host_start; addr < host_end; addr += TARGET_PAGE_SIZE)
prot |= page_get_flags(addr);
#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;
}
}
/* Allocate a new translation block. Flush the translation buffer if
too many translation blocks or too much generated code. */
TranslationBlock *tb_alloc(unsigned long pc)
{
TranslationBlock *tb;
if (nb_tbs >= CODE_GEN_MAX_BLOCKS ||
(code_gen_ptr - code_gen_buffer) >= CODE_GEN_BUFFER_MAX_SIZE)
return NULL;
tb = &tbs[nb_tbs++];
tb->pc = pc;
return tb;
}
/* link the tb with the other TBs */
void tb_link(TranslationBlock *tb)
{
unsigned int page_index1, page_index2;
/* add in the page list */
page_index1 = tb->pc >> TARGET_PAGE_BITS;
tb_alloc_page(tb, page_index1);
page_index2 = (tb->pc + tb->size - 1) >> TARGET_PAGE_BITS;
if (page_index2 != page_index1) {
tb_alloc_page(tb, page_index2);
}
#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;
/* init original jump addresses */
if (tb->tb_next_offset[0] != 0xffff)
tb_reset_jump(tb, 0);
if (tb->tb_next_offset[1] != 0xffff)
tb_reset_jump(tb, 1);
}
/* called from signal handler: invalidate the code and unprotect the
page. Return TRUE if the fault was succesfully handled. */
int page_unprotect(unsigned long address)
{
unsigned int page_index, prot, pindex;
PageDesc *p, *p1;
unsigned long host_start, host_end, addr;
host_start = address & host_page_mask;
page_index = host_start >> TARGET_PAGE_BITS;
p1 = page_find(page_index);
if (!p1)
return 0;
host_end = host_start + host_page_size;
p = p1;
prot = 0;
for(addr = host_start;addr < host_end; addr += TARGET_PAGE_SIZE) {
prot |= p->flags;
p++;
}
/* if the page was really writable, then we change its
protection back to writable */
if (prot & PAGE_WRITE_ORG) {
pindex = (address - host_start) >> TARGET_PAGE_BITS;
if (!(p1[pindex].flags & PAGE_WRITE)) {
#if !defined(CONFIG_SOFTMMU)
mprotect((void *)host_start, host_page_size,
(prot & PAGE_BITS) | PAGE_WRITE);
#endif
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 */
void page_unprotect_range(uint8_t *data, unsigned long data_size)
{
unsigned long start, end, addr;
start = (unsigned long)data;
end = start + data_size;
start &= TARGET_PAGE_MASK;
end = TARGET_PAGE_ALIGN(end);
for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) {
page_unprotect(addr);
}
}
/* find the TB 'tb' such that tb[0].tc_ptr <= tc_ptr <
tb[1].tc_ptr. Return NULL if not found */
TranslationBlock *tb_find_pc(unsigned long tc_ptr)
{
int m_min, m_max, m;
unsigned long v;
TranslationBlock *tb;
if (nb_tbs <= 0)
return NULL;
if (tc_ptr < (unsigned long)code_gen_buffer ||
tc_ptr >= (unsigned long)code_gen_ptr)
return NULL;
/* binary search (cf Knuth) */
m_min = 0;
m_max = nb_tbs - 1;
while (m_min <= m_max) {
m = (m_min + m_max) >> 1;
tb = &tbs[m];
v = (unsigned long)tb->tc_ptr;
if (v == tc_ptr)
return tb;
else if (tc_ptr < v) {
m_max = m - 1;
} else {
m_min = m + 1;
}
}
return &tbs[m_max];
}
static void tb_reset_jump_recursive(TranslationBlock *tb);
static inline void tb_reset_jump_recursive2(TranslationBlock *tb, int n)
{
TranslationBlock *tb1, *tb_next, **ptb;
unsigned int n1;
tb1 = tb->jmp_next[n];
if (tb1 != NULL) {
/* find head of list */
for(;;) {
n1 = (long)tb1 & 3;
tb1 = (TranslationBlock *)((long)tb1 & ~3);
if (n1 == 2)
break;
tb1 = tb1->jmp_next[n1];
}
/* we are now sure now that tb jumps to tb1 */
tb_next = tb1;
/* remove tb from the jmp_first list */
ptb = &tb_next->jmp_first;
for(;;) {
tb1 = *ptb;
n1 = (long)tb1 & 3;
tb1 = (TranslationBlock *)((long)tb1 & ~3);
if (n1 == n && tb1 == tb)
break;
ptb = &tb1->jmp_next[n1];
}
*ptb = tb->jmp_next[n];
tb->jmp_next[n] = NULL;
/* suppress the jump to next tb in generated code */
tb_reset_jump(tb, n);
/* suppress jumps in the tb on which we could have jump */
tb_reset_jump_recursive(tb_next);
}
}
static void tb_reset_jump_recursive(TranslationBlock *tb)
{
tb_reset_jump_recursive2(tb, 0);
tb_reset_jump_recursive2(tb, 1);
}
/* 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();
}
#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 */
void cpu_interrupt(CPUState *env, int mask)
{
TranslationBlock *tb;
env->interrupt_request |= mask;
/* if the cpu is currently executing code, we must unlink it and
all the potentially executing TB */
tb = env->current_tb;
if (tb) {
tb_reset_jump_recursive(tb);
}
}
void cpu_abort(CPUState *env, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
fprintf(stderr, "qemu: fatal: ");
vfprintf(stderr, fmt, ap);
fprintf(stderr, "\n");
#ifdef TARGET_I386
cpu_x86_dump_state(env, stderr, X86_DUMP_FPU | X86_DUMP_CCOP);
#endif
va_end(ap);
abort();
}
#ifdef TARGET_I386
/* unmap all maped pages and flush all associated code */
void page_unmap(void)
{
PageDesc *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) {
addr = (i << (32 - L1_BITS)) | (j << TARGET_PAGE_BITS);
/* we try to find a range to make less syscalls */
j1 = j;
p++;
j++;
while (j < L2_SIZE && (p->flags & PAGE_VALID)) {
p++;
j++;
}
ret = munmap((void *)addr, (j - j1) << TARGET_PAGE_BITS);
if (ret != 0) {
fprintf(stderr, "Could not unmap page 0x%08lx\n", addr);
exit(1);
}
} else {
p++;
j++;
}
}
#endif
free(pmap);
l1_map[i] = NULL;
}
}
tb_flush();
}
#endif
void tlb_flush(CPUState *env)
{
#if !defined(CONFIG_USER_ONLY)
int i;
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;
}
#endif
}
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)
{
#if !defined(CONFIG_USER_ONLY)
int i;
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);
#endif
}
/* 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)
{
#if !defined(CONFIG_USER_ONLY)
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);
#endif
}
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

465
gdbstub.c Normal file
View File

@@ -0,0 +1,465 @@
/*
* 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;
}
static int memory_rw(uint8_t *buf, uint32_t addr, int len, int is_write)
{
int l, flags;
uint32_t page;
while (len > 0) {
page = addr & TARGET_PAGE_MASK;
l = (page + TARGET_PAGE_SIZE) - addr;
if (l > len)
l = len;
flags = page_get_flags(page);
if (!(flags & PAGE_VALID))
return -1;
if (is_write) {
if (!(flags & PAGE_WRITE))
return -1;
memcpy((uint8_t *)addr, buf, l);
} else {
if (!(flags & PAGE_READ))
return -1;
memcpy(buf, (uint8_t *)addr, l);
}
len -= l;
buf += l;
addr += l;
}
return 0;
}
/* port = 0 means default port */
int cpu_gdbstub(void *opaque, int (*main_loop)(void *opaque), int port)
{
CPUState *env;
const char *p;
int ret, ch, nb_regs, i, 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);
registers = (void *)mem_buf;
#if defined(TARGET_I386)
for(i = 0; i < 8; i++) {
registers[i] = tswapl(env->regs[i]);
}
registers[8] = env->eip;
registers[9] = env->eflags;
registers[10] = env->segs[R_CS].selector;
registers[11] = env->segs[R_SS].selector;
registers[12] = env->segs[R_DS].selector;
registers[13] = env->segs[R_ES].selector;
registers[14] = env->segs[R_FS].selector;
registers[15] = env->segs[R_GS].selector;
nb_regs = 16;
#endif
memtohex(buf, (const uint8_t *)registers,
sizeof(registers[0]) * nb_regs);
put_packet(buf);
break;
case 'G':
env = cpu_gdbstub_get_env(opaque);
registers = (void *)mem_buf;
#if defined(TARGET_I386)
hextomem((uint8_t *)registers, p, 16 * 4);
for(i = 0; i < 8; i++) {
env->regs[i] = tswapl(registers[i]);
}
env->eip = registers[8];
env->eflags = registers[9];
#define LOAD_SEG(index, sreg)\
if (tswapl(registers[index]) != env->segs[sreg].selector)\
cpu_x86_load_seg(env, sreg, tswapl(registers[index]));
LOAD_SEG(10, R_CS);
LOAD_SEG(11, R_SS);
LOAD_SEG(12, R_DS);
LOAD_SEG(13, R_ES);
LOAD_SEG(14, R_FS);
LOAD_SEG(15, R_GS);
#endif
put_packet("OK");
break;
case 'm':
addr = strtoul(p, (char **)&p, 16);
if (*p == ',')
p++;
len = strtoul(p, NULL, 16);
if (memory_rw(mem_buf, addr, len, 0) != 0)
memset(mem_buf, 0, len);
memtohex(buf, mem_buf, len);
put_packet(buf);
break;
case 'M':
addr = strtoul(p, (char **)&p, 16);
if (*p == ',')
p++;
len = strtoul(p, (char **)&p, 16);
if (*p == ',')
p++;
hextomem(mem_buf, p, len);
if (memory_rw(mem_buf, addr, len, 1) != 0)
put_packet("ENN");
else
put_packet("OK");
break;
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) */
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;
}

View File

1386
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

@@ -1164,8 +1164,8 @@ int
print_insn_x86 (pc, info, aflag, dflag)
bfd_vma pc;
disassemble_info *info;
int aflag;
int dflag;
int volatile aflag;
int volatile dflag;
{
struct dis386 *dp;
int i;

140
i386-vl.ld Normal file
View File

@@ -0,0 +1,140 @@
/* ld script to make i386 Linux kernel
* Written by Martin Mares <mj@atrey.karlin.mff.cuni.cz>;
*/
OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
OUTPUT_ARCH(i386)
SEARCH_DIR(/lib); SEARCH_DIR(/usr/lib); SEARCH_DIR(/usr/local/lib); SEARCH_DIR(/usr/alpha-unknown-linux-gnu/lib);
ENTRY(_start)
SECTIONS
{
/* Read-only sections, merged into text segment: */
. = 0xa8000000 + SIZEOF_HEADERS;
.interp : { *(.interp) }
.hash : { *(.hash) }
.dynsym : { *(.dynsym) }
.dynstr : { *(.dynstr) }
.gnu.version : { *(.gnu.version) }
.gnu.version_d : { *(.gnu.version_d) }
.gnu.version_r : { *(.gnu.version_r) }
.rel.text :
{ *(.rel.text) *(.rel.gnu.linkonce.t*) }
.rela.text :
{ *(.rela.text) *(.rela.gnu.linkonce.t*) }
.rel.data :
{ *(.rel.data) *(.rel.gnu.linkonce.d*) }
.rela.data :
{ *(.rela.data) *(.rela.gnu.linkonce.d*) }
.rel.rodata :
{ *(.rel.rodata) *(.rel.gnu.linkonce.r*) }
.rela.rodata :
{ *(.rela.rodata) *(.rela.gnu.linkonce.r*) }
.rel.got : { *(.rel.got) }
.rela.got : { *(.rela.got) }
.rel.ctors : { *(.rel.ctors) }
.rela.ctors : { *(.rela.ctors) }
.rel.dtors : { *(.rel.dtors) }
.rela.dtors : { *(.rela.dtors) }
.rel.init : { *(.rel.init) }
.rela.init : { *(.rela.init) }
.rel.fini : { *(.rel.fini) }
.rela.fini : { *(.rela.fini) }
.rel.bss : { *(.rel.bss) }
.rela.bss : { *(.rela.bss) }
.rel.plt : { *(.rel.plt) }
.rela.plt : { *(.rela.plt) }
.init : { *(.init) } =0x47ff041f
.text :
{
*(.text)
/* .gnu.warning sections are handled specially by elf32.em. */
*(.gnu.warning)
*(.gnu.linkonce.t*)
} =0x47ff041f
_etext = .;
PROVIDE (etext = .);
.fini : { *(.fini) } =0x47ff041f
.rodata : { *(.rodata) *(.gnu.linkonce.r*) }
.rodata1 : { *(.rodata1) }
.reginfo : { *(.reginfo) }
__preinit_array_start = .;
.preinit_array : { *(.preinit_array) }
__preinit_array_end = .;
__init_array_start = .;
.init_array : { *(.init_array) }
__init_array_end = .;
__fini_array_start = .;
.fini_array : { *(.fini_array) }
__fini_array_end = .;
/* Adjust the address for the data segment. We want to adjust up to
the same address within the page on the next page up. */
. = ALIGN(0x100000) + (. & (0x100000 - 1));
.data :
{
*(.data)
*(.gnu.linkonce.d*)
CONSTRUCTORS
}
.data1 : { *(.data1) }
.ctors :
{
*(.ctors)
}
.dtors :
{
*(.dtors)
}
.plt : { *(.plt) }
.got : { *(.got.plt) *(.got) }
.dynamic : { *(.dynamic) }
/* We want the small data sections together, so single-instruction offsets
can access them all, and initialized data all before uninitialized, so
we can shorten the on-disk segment size. */
.sdata : { *(.sdata) }
_edata = .;
PROVIDE (edata = .);
__bss_start = .;
.sbss : { *(.sbss) *(.scommon) }
.bss :
{
*(.dynbss)
*(.bss)
*(COMMON)
}
_end = . ;
PROVIDE (end = .);
/* Stabs debugging sections. */
.stab 0 : { *(.stab) }
.stabstr 0 : { *(.stabstr) }
.stab.excl 0 : { *(.stab.excl) }
.stab.exclstr 0 : { *(.stab.exclstr) }
.stab.index 0 : { *(.stab.index) }
.stab.indexstr 0 : { *(.stab.indexstr) }
.comment 0 : { *(.comment) }
/* DWARF debug sections.
Symbols in the DWARF debugging sections are relative to the beginning
of the section so we begin them at 0. */
/* DWARF 1 */
.debug 0 : { *(.debug) }
.line 0 : { *(.line) }
/* GNU DWARF 1 extensions */
.debug_srcinfo 0 : { *(.debug_srcinfo) }
.debug_sfnames 0 : { *(.debug_sfnames) }
/* DWARF 1.1 and DWARF 2 */
.debug_aranges 0 : { *(.debug_aranges) }
.debug_pubnames 0 : { *(.debug_pubnames) }
/* DWARF 2 */
.debug_info 0 : { *(.debug_info) }
.debug_abbrev 0 : { *(.debug_abbrev) }
.debug_line 0 : { *(.debug_line) }
.debug_frame 0 : { *(.debug_frame) }
.debug_str 0 : { *(.debug_str) }
.debug_loc 0 : { *(.debug_loc) }
.debug_macinfo 0 : { *(.debug_macinfo) }
/* SGI/MIPS DWARF 2 extensions */
.debug_weaknames 0 : { *(.debug_weaknames) }
.debug_funcnames 0 : { *(.debug_funcnames) }
.debug_typenames 0 : { *(.debug_typenames) }
.debug_varnames 0 : { *(.debug_varnames) }
/* These must appear regardless of . */
}

32
ia64-syscall.S Normal file
View File

@@ -0,0 +1,32 @@
/* derived from glibc sysdeps/unix/sysv/linux/ia64/sysdep.S */
#define __ASSEMBLY__
#include <asm/asmmacro.h>
#include <asm/unistd.h>
ENTRY(__syscall_error)
.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(0)
alloc r33=ar.pfs, 0, 4, 0, 0
mov r32=rp
.body
mov r35=r8
mov r34=r1
;;
br.call.sptk.many b0 = __errno_location
.Lret0: /* force new bundle */
st4 [r8]=r35
mov r1=r34
mov rp=r32
mov r8=-1
mov ar.pfs=r33
br.ret.sptk.few b0
END(__syscall_error)
GLOBAL_ENTRY(__ia64_syscall)
mov r15=r37 /* syscall number */
break __BREAK_SYSCALL
cmp.eq p6,p0=-1,r10 /* r10 = -1 on error */
(p6) br.cond.spnt.few __syscall_error
br.ret.sptk.few b0
.endp __ia64_syscall

28
linux-user/arm/syscall.h Normal file
View File

@@ -0,0 +1,28 @@
/* this struct defines the way the registers are stored on the
stack during a system call. */
struct target_pt_regs {
target_long uregs[18];
};
#define ARM_cpsr uregs[16]
#define ARM_pc uregs[15]
#define ARM_lr uregs[14]
#define ARM_sp uregs[13]
#define ARM_ip uregs[12]
#define ARM_fp uregs[11]
#define ARM_r10 uregs[10]
#define ARM_r9 uregs[9]
#define ARM_r8 uregs[8]
#define ARM_r7 uregs[7]
#define ARM_r6 uregs[6]
#define ARM_r5 uregs[5]
#define ARM_r4 uregs[4]
#define ARM_r3 uregs[3]
#define ARM_r2 uregs[2]
#define ARM_r1 uregs[1]
#define ARM_r0 uregs[0]
#define ARM_ORIG_r0 uregs[17]
#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 */

View File

@@ -11,18 +11,12 @@
#include <string.h>
#include "qemu.h"
#include "disas.h"
#ifdef TARGET_I386
#define ELF_START_MMAP 0x80000000
typedef uint32_t elf_greg_t;
#define ELF_NGREG (sizeof (struct target_pt_regs) / sizeof(elf_greg_t))
typedef elf_greg_t elf_gregset_t[ELF_NGREG];
typedef struct user_i387_struct elf_fpregset_t;
/*
* This is used to ensure we don't load something for the wrong architecture.
*/
@@ -44,11 +38,72 @@ typedef struct user_i387_struct elf_fpregset_t;
A value of 0 tells we have no such handler. */
#define ELF_PLAT_INIT(_r) _r->edx = 0
static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
{
regs->esp = infop->start_stack;
regs->eip = infop->entry;
}
#define USE_ELF_CORE_DUMP
#define ELF_EXEC_PAGESIZE 4096
#endif
#ifdef TARGET_ARM
#define ELF_START_MMAP 0x80000000
#define elf_check_arch(x) ( (x) == EM_ARM )
#define ELF_CLASS ELFCLASS32
#ifdef TARGET_WORDS_BIGENDIAN
#define ELF_DATA ELFDATA2MSB
#else
#define ELF_DATA ELFDATA2LSB
#endif
#define ELF_ARCH EM_ARM
#define ELF_PLAT_INIT(_r) _r->ARM_r0 = 0
static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
{
target_long *stack = (void *)infop->start_stack;
memset(regs, 0, sizeof(*regs));
regs->ARM_cpsr = 0x10;
regs->ARM_pc = infop->entry;
regs->ARM_sp = infop->start_stack;
regs->ARM_r2 = tswapl(stack[2]); /* envp */
regs->ARM_r1 = tswapl(stack[1]); /* argv */
/* 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->u_regs[0] = infop->entry;
regs->u_regs[1] = infop->start_stack;
}
#endif
#include "elf.h"
/*
@@ -94,8 +149,6 @@ struct exec
#define ZMAGIC 0413
#define QMAGIC 0314
#define X86_STACK_TOP 0x7d000000
/* max code+data+bss space allocated to elf interpreter */
#define INTERP_MAP_SIZE (32 * 1024 * 1024)
@@ -122,23 +175,11 @@ struct exec
#define PER_XENIX (0x0007 | STICKY_TIMEOUTS)
/* Necessary parameters */
#define ALPHA_PAGE_SIZE 4096
#define X86_PAGE_SIZE 4096
#define ALPHA_PAGE_MASK (~(ALPHA_PAGE_SIZE-1))
#define X86_PAGE_MASK (~(X86_PAGE_SIZE-1))
#define ALPHA_PAGE_ALIGN(addr) ((((addr)+ALPHA_PAGE_SIZE)-1)&ALPHA_PAGE_MASK)
#define X86_PAGE_ALIGN(addr) ((((addr)+X86_PAGE_SIZE)-1)&X86_PAGE_MASK)
#define NGROUPS 32
#define X86_ELF_EXEC_PAGESIZE X86_PAGE_SIZE
#define X86_ELF_PAGESTART(_v) ((_v) & ~(unsigned long)(X86_ELF_EXEC_PAGESIZE-1))
#define X86_ELF_PAGEOFFSET(_v) ((_v) & (X86_ELF_EXEC_PAGESIZE-1))
#define ALPHA_ELF_PAGESTART(_v) ((_v) & ~(unsigned long)(ALPHA_PAGE_SIZE-1))
#define ALPHA_ELF_PAGEOFFSET(_v) ((_v) & (ALPHA_PAGE_SIZE-1))
#define TARGET_ELF_EXEC_PAGESIZE TARGET_PAGE_SIZE
#define TARGET_ELF_PAGESTART(_v) ((_v) & ~(unsigned long)(TARGET_ELF_EXEC_PAGESIZE-1))
#define TARGET_ELF_PAGEOFFSET(_v) ((_v) & (TARGET_ELF_EXEC_PAGESIZE-1))
#define INTERPRETER_NONE 0
#define INTERPRETER_AOUT 1
@@ -159,9 +200,6 @@ static inline void memcpy_tofs(void * to, const void * from, unsigned long n)
memcpy(to, from, n);
}
//extern void * mmap4k();
#define mmap4k(a, b, c, d, e, f) mmap((void *)(a), b, c, d, e, f)
extern unsigned long x86_stack_size;
static int load_aout_interp(void * exptr, int interp_fd);
@@ -195,6 +233,28 @@ static void bswap_phdr(Elf32_Phdr *phdr)
bswap32s(&phdr->p_flags); /* Segment flags */
bswap32s(&phdr->p_align); /* Segment alignment */
}
static void bswap_shdr(Elf32_Shdr *shdr)
{
bswap32s(&shdr->sh_name);
bswap32s(&shdr->sh_type);
bswap32s(&shdr->sh_flags);
bswap32s(&shdr->sh_addr);
bswap32s(&shdr->sh_offset);
bswap32s(&shdr->sh_size);
bswap32s(&shdr->sh_link);
bswap32s(&shdr->sh_info);
bswap32s(&shdr->sh_addralign);
bswap32s(&shdr->sh_entsize);
}
static void bswap_sym(Elf32_Sym *sym)
{
bswap32s(&sym->st_name);
bswap32s(&sym->st_value);
bswap32s(&sym->st_size);
bswap16s(&sym->st_shndx);
}
#endif
static void * get_free_page(void)
@@ -204,8 +264,8 @@ static void * get_free_page(void)
/* User-space version of kernel get_free_page. Returns a page-aligned
* page-sized chunk of memory.
*/
retval = mmap4k(0, ALPHA_PAGE_SIZE, PROT_READ|PROT_WRITE,
MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
retval = (void *)target_mmap(0, host_page_size, PROT_READ|PROT_WRITE,
MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
if((long)retval == -1) {
perror("get_free_page");
@@ -218,7 +278,7 @@ static void * get_free_page(void)
static void free_page(void * pageaddr)
{
(void)munmap(pageaddr, ALPHA_PAGE_SIZE);
target_munmap((unsigned long)pageaddr, host_page_size);
}
/*
@@ -249,9 +309,9 @@ static unsigned long copy_strings(int argc,char ** argv,unsigned long *page,
while (len) {
--p; --tmp; --len;
if (--offset < 0) {
offset = p % X86_PAGE_SIZE;
if (!(pag = (char *) page[p/X86_PAGE_SIZE]) &&
!(pag = (char *) page[p/X86_PAGE_SIZE] =
offset = p % TARGET_PAGE_SIZE;
if (!(pag = (char *) page[p/TARGET_PAGE_SIZE]) &&
!(pag = (char *) page[p/TARGET_PAGE_SIZE] =
(unsigned long *) get_free_page())) {
return 0;
}
@@ -367,21 +427,21 @@ unsigned long setup_arg_pages(unsigned long p, struct linux_binprm * bprm,
* it for args, we'll use it for something else...
*/
size = x86_stack_size;
if (size < MAX_ARG_PAGES*X86_PAGE_SIZE)
size = MAX_ARG_PAGES*X86_PAGE_SIZE;
error = (unsigned long)mmap4k(NULL,
size + X86_PAGE_SIZE,
PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS,
-1, 0);
if (size < MAX_ARG_PAGES*TARGET_PAGE_SIZE)
size = MAX_ARG_PAGES*TARGET_PAGE_SIZE;
error = target_mmap(0,
size + host_page_size,
PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS,
-1, 0);
if (error == -1) {
perror("stk mmap");
exit(-1);
}
/* we reserve one extra page at the top of the stack as guard */
mprotect((void *)(error + size), X86_PAGE_SIZE, PROT_NONE);
target_mprotect(error + size, host_page_size, PROT_NONE);
stack_base = error + size - MAX_ARG_PAGES*X86_PAGE_SIZE;
stack_base = error + size - MAX_ARG_PAGES*TARGET_PAGE_SIZE;
p += stack_base;
if (bprm->loader) {
@@ -393,10 +453,10 @@ unsigned long setup_arg_pages(unsigned long p, struct linux_binprm * bprm,
if (bprm->page[i]) {
info->rss++;
memcpy((void *)stack_base, (void *)bprm->page[i], X86_PAGE_SIZE);
memcpy((void *)stack_base, (void *)bprm->page[i], TARGET_PAGE_SIZE);
free_page((void *)bprm->page[i]);
}
stack_base += X86_PAGE_SIZE;
stack_base += TARGET_PAGE_SIZE;
}
return p;
}
@@ -404,33 +464,47 @@ unsigned long setup_arg_pages(unsigned long p, struct linux_binprm * bprm,
static void set_brk(unsigned long start, unsigned long end)
{
/* page-align the start and end addresses... */
start = ALPHA_PAGE_ALIGN(start);
end = ALPHA_PAGE_ALIGN(end);
start = HOST_PAGE_ALIGN(start);
end = HOST_PAGE_ALIGN(end);
if (end <= start)
return;
if((long)mmap4k(start, end - start,
PROT_READ | PROT_WRITE | PROT_EXEC,
MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0) == -1) {
if(target_mmap(start, end - start,
PROT_READ | PROT_WRITE | PROT_EXEC,
MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0) == -1) {
perror("cannot mmap brk");
exit(-1);
}
}
/* 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 & (ALPHA_PAGE_SIZE-1); /* was X86_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 = ALPHA_PAGE_SIZE - nbyte;
nbyte = host_page_size - nbyte;
fpnt = (char *) elf_bss;
do {
*fpnt++ = 0;
@@ -452,7 +526,7 @@ static unsigned int * create_elf_tables(char *p, int argc, int envc,
* Force 16 byte alignment here for generality.
*/
sp = (unsigned int *) (~15UL & (unsigned long) p);
sp -= exec ? DLINFO_ITEMS*2 : 2;
sp -= DLINFO_ITEMS*2;
dlinfo = sp;
sp -= envc+1;
envp = sp;
@@ -467,21 +541,20 @@ static unsigned int * create_elf_tables(char *p, int argc, int envc,
put_user (tswapl(id), dlinfo++); \
put_user (tswapl(val), dlinfo++)
if (exec) { /* Put this here for an ELF program interpreter */
NEW_AUX_ENT (AT_PHDR, (target_ulong)(load_addr + exec->e_phoff));
NEW_AUX_ENT (AT_PHENT, (target_ulong)(sizeof (struct elf_phdr)));
NEW_AUX_ENT (AT_PHNUM, (target_ulong)(exec->e_phnum));
NEW_AUX_ENT (AT_PAGESZ, (target_ulong)(ALPHA_PAGE_SIZE));
NEW_AUX_ENT (AT_BASE, (target_ulong)(interp_load_addr));
NEW_AUX_ENT (AT_FLAGS, (target_ulong)0);
NEW_AUX_ENT (AT_ENTRY, load_bias + exec->e_entry);
NEW_AUX_ENT (AT_UID, (target_ulong) getuid());
NEW_AUX_ENT (AT_EUID, (target_ulong) geteuid());
NEW_AUX_ENT (AT_GID, (target_ulong) getgid());
NEW_AUX_ENT (AT_EGID, (target_ulong) getegid());
}
NEW_AUX_ENT (AT_PHDR, (target_ulong)(load_addr + exec->e_phoff));
NEW_AUX_ENT (AT_PHENT, (target_ulong)(sizeof (struct elf_phdr)));
NEW_AUX_ENT (AT_PHNUM, (target_ulong)(exec->e_phnum));
NEW_AUX_ENT (AT_PAGESZ, (target_ulong)(TARGET_PAGE_SIZE));
NEW_AUX_ENT (AT_BASE, (target_ulong)(interp_load_addr));
NEW_AUX_ENT (AT_FLAGS, (target_ulong)0);
NEW_AUX_ENT (AT_ENTRY, load_bias + exec->e_entry);
NEW_AUX_ENT (AT_UID, (target_ulong) getuid());
NEW_AUX_ENT (AT_EUID, (target_ulong) geteuid());
NEW_AUX_ENT (AT_GID, (target_ulong) getgid());
NEW_AUX_ENT (AT_EGID, (target_ulong) getegid());
NEW_AUX_ENT (AT_NULL, 0);
#undef NEW_AUX_ENT
put_user(tswapl(argc),--sp);
info->arg_start = (unsigned int)((unsigned long)p & 0xffffffff);
while (argc-->0) {
@@ -531,7 +604,7 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex,
/* Now read in all of the header information */
if (sizeof(struct elf_phdr) * interp_elf_ex->e_phnum > X86_PAGE_SIZE)
if (sizeof(struct elf_phdr) * interp_elf_ex->e_phnum > TARGET_PAGE_SIZE)
return ~0UL;
elf_phdata = (struct elf_phdr *)
@@ -571,9 +644,9 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex,
if (interp_elf_ex->e_type == ET_DYN) {
/* in order to avoid harcoding the interpreter load
address in qemu, we allocate a big enough memory zone */
error = (unsigned long)mmap4k(NULL, INTERP_MAP_SIZE,
PROT_NONE, MAP_PRIVATE | MAP_ANON,
-1, 0);
error = target_mmap(0, INTERP_MAP_SIZE,
PROT_NONE, MAP_PRIVATE | MAP_ANON,
-1, 0);
if (error == -1) {
perror("mmap");
exit(-1);
@@ -597,12 +670,12 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex,
elf_type |= MAP_FIXED;
vaddr = eppnt->p_vaddr;
}
error = (unsigned long)mmap4k(load_addr+X86_ELF_PAGESTART(vaddr),
eppnt->p_filesz + X86_ELF_PAGEOFFSET(eppnt->p_vaddr),
error = target_mmap(load_addr+TARGET_ELF_PAGESTART(vaddr),
eppnt->p_filesz + TARGET_ELF_PAGEOFFSET(eppnt->p_vaddr),
elf_prot,
elf_type,
interpreter_fd,
eppnt->p_offset - X86_ELF_PAGEOFFSET(eppnt->p_vaddr));
eppnt->p_offset - TARGET_ELF_PAGEOFFSET(eppnt->p_vaddr));
if (error > -1024UL) {
/* Real error */
@@ -642,13 +715,13 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex,
* bss page.
*/
padzero(elf_bss);
elf_bss = X86_ELF_PAGESTART(elf_bss + ALPHA_PAGE_SIZE - 1); /* What we have mapped so far */
elf_bss = TARGET_ELF_PAGESTART(elf_bss + host_page_size - 1); /* What we have mapped so far */
/* Map the last of the bss segment */
if (last_bss > elf_bss) {
mmap4k(elf_bss, last_bss-elf_bss,
PROT_READ|PROT_WRITE|PROT_EXEC,
MAP_FIXED|MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
target_mmap(elf_bss, last_bss-elf_bss,
PROT_READ|PROT_WRITE|PROT_EXEC,
MAP_FIXED|MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
}
free(elf_phdata);
@@ -656,7 +729,56 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex,
return ((unsigned long) interp_elf_ex->e_entry) + load_addr;
}
/* Best attempt to load symbols from this ELF object. */
static void load_symbols(struct elfhdr *hdr, int fd)
{
unsigned int i;
struct elf_shdr sechdr, symtab, strtab;
char *strings;
lseek(fd, hdr->e_shoff, SEEK_SET);
for (i = 0; i < hdr->e_shnum; i++) {
if (read(fd, &sechdr, sizeof(sechdr)) != sizeof(sechdr))
return;
#ifdef BSWAP_NEEDED
bswap_shdr(&sechdr);
#endif
if (sechdr.sh_type == SHT_SYMTAB) {
symtab = sechdr;
lseek(fd, hdr->e_shoff
+ sizeof(sechdr) * sechdr.sh_link, SEEK_SET);
if (read(fd, &strtab, sizeof(strtab))
!= sizeof(strtab))
return;
#ifdef BSWAP_NEEDED
bswap_shdr(&strtab);
#endif
goto found;
}
}
return; /* Shouldn't happen... */
found:
/* Now know where the strtab and symtab are. Snarf them. */
disas_symtab = malloc(symtab.sh_size);
disas_strtab = strings = malloc(strtab.sh_size);
if (!disas_symtab || !disas_strtab)
return;
lseek(fd, symtab.sh_offset, SEEK_SET);
if (read(fd, disas_symtab, symtab.sh_size) != symtab.sh_size)
return;
#ifdef BSWAP_NEEDED
for (i = 0; i < symtab.sh_size / sizeof(struct elf_sym); i++)
bswap_sym(disas_symtab + sizeof(struct elf_sym)*i);
#endif
lseek(fd, strtab.sh_offset, SEEK_SET);
if (read(fd, strings, strtab.sh_size) != strtab.sh_size)
return;
disas_num_syms = symtab.sh_size / sizeof(struct elf_sym);
}
static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
struct image_info * info)
@@ -670,7 +792,7 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r
unsigned int interpreter_type = INTERPRETER_NONE;
unsigned char ibcs2_interpreter;
int i;
void * mapped_addr;
unsigned long mapped_addr;
struct elf_phdr * elf_ppnt;
struct elf_phdr *elf_phdata;
unsigned long elf_bss, k, elf_brk;
@@ -703,7 +825,6 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r
}
/* Now read in all of the header information */
elf_phdata = (struct elf_phdr *)malloc(elf_ex.e_phentsize*elf_ex.e_phnum);
if (elf_phdata == NULL) {
return -ENOMEM;
@@ -907,33 +1028,32 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r
is because the brk will follow the loader, and is not movable. */
/* NOTE: for qemu, we do a big mmap to get enough space
without harcoding any address */
error = (unsigned long)mmap4k(NULL, ET_DYN_MAP_SIZE,
PROT_NONE, MAP_PRIVATE | MAP_ANON,
-1, 0);
error = target_mmap(0, ET_DYN_MAP_SIZE,
PROT_NONE, MAP_PRIVATE | MAP_ANON,
-1, 0);
if (error == -1) {
perror("mmap");
exit(-1);
}
load_bias = X86_ELF_PAGESTART(error - elf_ppnt->p_vaddr);
load_bias = TARGET_ELF_PAGESTART(error - elf_ppnt->p_vaddr);
}
error = (unsigned long)mmap4k(
X86_ELF_PAGESTART(load_bias + elf_ppnt->p_vaddr),
(elf_ppnt->p_filesz +
X86_ELF_PAGEOFFSET(elf_ppnt->p_vaddr)),
elf_prot,
(MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE),
bprm->fd,
(elf_ppnt->p_offset -
X86_ELF_PAGEOFFSET(elf_ppnt->p_vaddr)));
error = target_mmap(TARGET_ELF_PAGESTART(load_bias + elf_ppnt->p_vaddr),
(elf_ppnt->p_filesz +
TARGET_ELF_PAGEOFFSET(elf_ppnt->p_vaddr)),
elf_prot,
(MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE),
bprm->fd,
(elf_ppnt->p_offset -
TARGET_ELF_PAGEOFFSET(elf_ppnt->p_vaddr)));
if (error == -1) {
perror("mmap");
exit(-1);
}
#ifdef LOW_ELF_STACK
if (X86_ELF_PAGESTART(elf_ppnt->p_vaddr) < elf_stack)
elf_stack = X86_ELF_PAGESTART(elf_ppnt->p_vaddr);
if (TARGET_ELF_PAGESTART(elf_ppnt->p_vaddr) < elf_stack)
elf_stack = TARGET_ELF_PAGESTART(elf_ppnt->p_vaddr);
#endif
if (!load_addr_set) {
@@ -941,7 +1061,7 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r
load_addr = elf_ppnt->p_vaddr - elf_ppnt->p_offset;
if (elf_ex.e_type == ET_DYN) {
load_bias += error -
X86_ELF_PAGESTART(load_bias + elf_ppnt->p_vaddr);
TARGET_ELF_PAGESTART(load_bias + elf_ppnt->p_vaddr);
load_addr += load_bias;
}
}
@@ -989,6 +1109,9 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r
free(elf_phdata);
if (loglevel)
load_symbols(&elf_ex, bprm->fd);
if (interpreter_type != INTERPRETER_AOUT) close(bprm->fd);
info->personality = (ibcs2_interpreter ? PER_SVR4 : PER_LINUX);
@@ -999,7 +1122,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),
@@ -1033,8 +1156,8 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r
and some applications "depend" upon this behavior.
Since we do not have the power to recompile these, we
emulate the SVr4 behavior. Sigh. */
mapped_addr = mmap4k(NULL, ALPHA_PAGE_SIZE, PROT_READ | PROT_EXEC,
MAP_FIXED | MAP_PRIVATE, -1, 0);
mapped_addr = target_mmap(0, host_page_size, PROT_READ | PROT_EXEC,
MAP_FIXED | MAP_PRIVATE, -1, 0);
}
#ifdef ELF_PLAT_INIT
@@ -1062,7 +1185,7 @@ int elf_exec(const char * filename, char ** argv, char ** envp,
int retval;
int i;
bprm.p = X86_PAGE_SIZE*MAX_ARG_PAGES-sizeof(unsigned int);
bprm.p = TARGET_PAGE_SIZE*MAX_ARG_PAGES-sizeof(unsigned int);
for (i=0 ; i<MAX_ARG_PAGES ; i++) /* clear page-table */
bprm.page[i] = 0;
retval = open(filename, O_RDONLY);
@@ -1099,8 +1222,7 @@ int elf_exec(const char * filename, char ** argv, char ** envp,
}
if(retval>=0) {
/* success. Initialize important registers */
regs->esp = infop->start_stack;
regs->eip = infop->entry;
init_thread(regs, infop);
return retval;
}

220
linux-user/i386/syscall.h Normal file
View File

@@ -0,0 +1,220 @@
/* default linux values for the selectors */
#define __USER_CS (0x23)
#define __USER_DS (0x2B)
struct target_pt_regs {
long ebx;
long ecx;
long edx;
long esi;
long edi;
long ebp;
long eax;
int xds;
int xes;
long orig_eax;
long eip;
int xcs;
long eflags;
long esp;
int xss;
};
/* ioctls */
#define TARGET_LDT_ENTRIES 8192
#define TARGET_LDT_ENTRY_SIZE 8
#define TARGET_GDT_ENTRY_TLS_ENTRIES 3
#define TARGET_GDT_ENTRY_TLS_MIN 6
#define TARGET_GDT_ENTRY_TLS_MAX (TARGET_GDT_ENTRY_TLS_MIN + TARGET_GDT_ENTRY_TLS_ENTRIES - 1)
struct target_modify_ldt_ldt_s {
unsigned int entry_number;
target_ulong base_addr;
unsigned int limit;
unsigned int flags;
};
/* vm86 defines */
#define TARGET_BIOSSEG 0x0f000
#define TARGET_CPU_086 0
#define TARGET_CPU_186 1
#define TARGET_CPU_286 2
#define TARGET_CPU_386 3
#define TARGET_CPU_486 4
#define TARGET_CPU_586 5
#define TARGET_VM86_SIGNAL 0 /* return due to signal */
#define TARGET_VM86_UNKNOWN 1 /* unhandled GP fault - IO-instruction or similar */
#define TARGET_VM86_INTx 2 /* int3/int x instruction (ARG = x) */
#define TARGET_VM86_STI 3 /* sti/popf/iret instruction enabled virtual interrupts */
/*
* Additional return values when invoking new vm86()
*/
#define TARGET_VM86_PICRETURN 4 /* return due to pending PIC request */
#define TARGET_VM86_TRAP 6 /* return due to DOS-debugger request */
/*
* function codes when invoking new vm86()
*/
#define TARGET_VM86_PLUS_INSTALL_CHECK 0
#define TARGET_VM86_ENTER 1
#define TARGET_VM86_ENTER_NO_BYPASS 2
#define TARGET_VM86_REQUEST_IRQ 3
#define TARGET_VM86_FREE_IRQ 4
#define TARGET_VM86_GET_IRQ_BITS 5
#define TARGET_VM86_GET_AND_RESET_IRQ 6
/*
* This is the stack-layout seen by the user space program when we have
* done a translation of "SAVE_ALL" from vm86 mode. The real kernel layout
* is 'kernel_vm86_regs' (see below).
*/
struct target_vm86_regs {
/*
* normal regs, with special meaning for the segment descriptors..
*/
target_long ebx;
target_long ecx;
target_long edx;
target_long esi;
target_long edi;
target_long ebp;
target_long eax;
target_long __null_ds;
target_long __null_es;
target_long __null_fs;
target_long __null_gs;
target_long orig_eax;
target_long eip;
unsigned short cs, __csh;
target_long eflags;
target_long esp;
unsigned short ss, __ssh;
/*
* these are specific to v86 mode:
*/
unsigned short es, __esh;
unsigned short ds, __dsh;
unsigned short fs, __fsh;
unsigned short gs, __gsh;
};
struct target_revectored_struct {
target_ulong __map[8]; /* 256 bits */
};
struct target_vm86_struct {
struct target_vm86_regs regs;
target_ulong flags;
target_ulong screen_bitmap;
target_ulong cpu_type;
struct target_revectored_struct int_revectored;
struct target_revectored_struct int21_revectored;
};
/*
* flags masks
*/
#define TARGET_VM86_SCREEN_BITMAP 0x0001
struct target_vm86plus_info_struct {
target_ulong flags;
#define TARGET_force_return_for_pic (1 << 0)
#define TARGET_vm86dbg_active (1 << 1) /* for debugger */
#define TARGET_vm86dbg_TFpendig (1 << 2) /* for debugger */
#define TARGET_is_vm86pus (1 << 31) /* for vm86 internal use */
unsigned char vm86dbg_intxxtab[32]; /* for debugger */
};
struct target_vm86plus_struct {
struct target_vm86_regs regs;
target_ulong flags;
target_ulong screen_bitmap;
target_ulong cpu_type;
struct target_revectored_struct int_revectored;
struct target_revectored_struct int21_revectored;
struct target_vm86plus_info_struct vm86plus;
};
/* ipcs */
#define TARGET_SEMOP 1
#define TARGET_SEMGET 2
#define TARGET_SEMCTL 3
#define TARGET_MSGSND 11
#define TARGET_MSGRCV 12
#define TARGET_MSGGET 13
#define TARGET_MSGCTL 14
#define TARGET_SHMAT 21
#define TARGET_SHMDT 22
#define TARGET_SHMGET 23
#define TARGET_SHMCTL 24
struct target_msgbuf {
int mtype;
char mtext[1];
};
struct target_ipc_kludge {
unsigned int msgp; /* Really (struct msgbuf *) */
int msgtyp;
};
struct 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* */
};

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)

View File

@@ -51,6 +51,12 @@
IOCTL(TIOCMIWAIT, 0, TYPE_INT)
IOCTL(TIOCGICOUNT, IOC_R, MK_PTR(MK_STRUCT(STRUCT_serial_icounter_struct)))
IOCTL(KIOCSOUND, 0, TYPE_INT)
IOCTL(KDMKTONE, 0, TYPE_INT)
IOCTL(KDGKBTYPE, IOC_R, MK_PTR(TYPE_CHAR))
IOCTL(KDGKBENT, IOC_RW, MK_PTR(MK_STRUCT(STRUCT_kbentry)))
IOCTL(KDGKBSENT, IOC_RW, TYPE_PTRVOID)
IOCTL(BLKROSET, IOC_W, MK_PTR(TYPE_INT))
IOCTL(BLKROGET, IOC_R, MK_PTR(TYPE_INT))
IOCTL(BLKRRPART, 0, TYPE_NULL)
@@ -144,6 +150,7 @@
IOCTL(CDROM_DISC_STATUS, 0, TYPE_NULL)
IOCTL(CDROMAUDIOBUFSIZ, 0, TYPE_INT)
#if 0
IOCTL(SNDCTL_COPR_HALT, IOC_RW, MK_PTR(TYPE_INT))
IOCTL(SNDCTL_COPR_LOAD, IOC_RW, MK_PTR(TYPE_INT))
IOCTL(SNDCTL_COPR_RCODE, IOC_RW, MK_PTR(TYPE_INT))
@@ -154,14 +161,15 @@
IOCTL(SNDCTL_COPR_SENDMSG, IOC_RW, MK_PTR(TYPE_INT))
IOCTL(SNDCTL_COPR_WCODE, IOC_W, MK_PTR(TYPE_INT))
IOCTL(SNDCTL_COPR_WDATA, IOC_W, MK_PTR(TYPE_INT))
#endif
IOCTL(SNDCTL_DSP_CHANNELS, IOC_RW, MK_PTR(TYPE_INT))
IOCTL(SNDCTL_DSP_GETBLKSIZE, IOC_RW, MK_PTR(TYPE_INT))
IOCTL(SNDCTL_DSP_GETCAPS, IOC_R, MK_PTR(TYPE_INT))
IOCTL(SNDCTL_DSP_GETFMTS, IOC_R, MK_PTR(TYPE_INT))
IOCTL(SNDCTL_DSP_GETIPTR, IOC_R, MK_PTR(TYPE_INT))
IOCTL(SNDCTL_DSP_GETISPACE, IOC_R, MK_PTR(TYPE_INT))
IOCTL(SNDCTL_DSP_GETOPTR, IOC_R, MK_PTR(TYPE_INT))
IOCTL(SNDCTL_DSP_GETOSPACE, IOC_R, MK_PTR(TYPE_INT))
IOCTL(SNDCTL_DSP_GETIPTR, IOC_R, MK_PTR(MK_STRUCT(STRUCT_count_info)))
IOCTL(SNDCTL_DSP_GETOPTR, IOC_R, MK_PTR(MK_STRUCT(STRUCT_count_info)))
IOCTL(SNDCTL_DSP_GETISPACE, IOC_R, MK_PTR(MK_STRUCT(STRUCT_audio_buf_info)))
IOCTL(SNDCTL_DSP_GETOSPACE, IOC_R, MK_PTR(MK_STRUCT(STRUCT_audio_buf_info)))
IOCTL(SNDCTL_DSP_GETTRIGGER, IOC_R, MK_PTR(TYPE_INT))
IOCTL(SNDCTL_DSP_MAPINBUF, IOC_R, MK_PTR(TYPE_INT))
IOCTL(SNDCTL_DSP_MAPOUTBUF, IOC_R, MK_PTR(TYPE_INT))
@@ -177,6 +185,7 @@
IOCTL(SNDCTL_DSP_STEREO, IOC_RW, MK_PTR(TYPE_INT))
IOCTL(SNDCTL_DSP_SUBDIVIDE, IOC_RW, MK_PTR(TYPE_INT))
IOCTL(SNDCTL_DSP_SYNC, 0, TYPE_NULL)
#if 0
IOCTL(SNDCTL_FM_4OP_ENABLE, IOC_W, MK_PTR(TYPE_INT))
IOCTL(SNDCTL_FM_LOAD_INSTR, IOC_W, MK_PTR(TYPE_INT))
IOCTL(SNDCTL_MIDI_INFO, IOC_RW, MK_PTR(TYPE_INT))
@@ -216,6 +225,7 @@
IOCTL(SOUND_PCM_READ_CHANNELS, IOC_R, MK_PTR(TYPE_INT))
IOCTL(SOUND_PCM_READ_BITS, IOC_R, MK_PTR(TYPE_INT))
IOCTL(SOUND_PCM_READ_FILTER, IOC_R, MK_PTR(TYPE_INT))
#endif
IOCTL(SOUND_MIXER_INFO, IOC_R, MK_PTR(TYPE_INT))
IOCTL(SOUND_MIXER_ACCESS, 0, TYPE_PTRVOID)
IOCTL(SOUND_MIXER_PRIVATE1, IOC_RW, MK_PTR(TYPE_INT))

View File

@@ -1,5 +1,5 @@
/*
* qemu main
* qemu user main
*
* Copyright (c) 2003 Fabrice Bellard
*
@@ -26,20 +26,17 @@
#include "qemu.h"
#include "cpu-i386.h"
#define DEBUG_LOGFILE "/tmp/qemu.log"
FILE *logfile = NULL;
int loglevel;
static const char *interp_prefix = CONFIG_QEMU_PREFIX;
#ifdef __i386__
/* Force usage of an ELF interpreter even if it is an ELF shared
object ! */
const char interp[] __attribute__((section(".interp"))) = "/lib/ld-linux.so.2";
#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];
@@ -48,8 +45,6 @@ long __fini_array_start[0];
long __fini_array_end[0];
#endif
#endif
/* XXX: on x86 MAP_GROWSDOWN only works if ESP <= address + 32, so
we allocate a bigger stack. Need a better solution, for example
by remapping the process stack directly at the right place */
@@ -64,184 +59,79 @@ void gemu_log(const char *fmt, ...)
va_end(ap);
}
#ifdef TARGET_I386
/***********************************************************/
/* CPUX86 core interface */
void cpu_x86_outb(int addr, int val)
void cpu_x86_outb(CPUX86State *env, int addr, int val)
{
fprintf(stderr, "outb: port=0x%04x, data=%02x\n", addr, val);
}
void cpu_x86_outw(int addr, int val)
void cpu_x86_outw(CPUX86State *env, int addr, int val)
{
fprintf(stderr, "outw: port=0x%04x, data=%04x\n", addr, val);
}
void cpu_x86_outl(int addr, int val)
void cpu_x86_outl(CPUX86State *env, int addr, int val)
{
fprintf(stderr, "outl: port=0x%04x, data=%08x\n", addr, val);
}
int cpu_x86_inb(int addr)
int cpu_x86_inb(CPUX86State *env, int addr)
{
fprintf(stderr, "inb: port=0x%04x\n", addr);
return 0;
}
int cpu_x86_inw(int addr)
int cpu_x86_inw(CPUX86State *env, int addr)
{
fprintf(stderr, "inw: port=0x%04x\n", addr);
return 0;
}
int cpu_x86_inl(int addr)
int cpu_x86_inl(CPUX86State *env, int addr)
{
fprintf(stderr, "inl: port=0x%04x\n", addr);
return 0;
}
void write_dt(void *ptr, unsigned long addr, unsigned long limit,
int seg32_bit)
int cpu_x86_get_pic_interrupt(CPUX86State *env)
{
unsigned int e1, e2, limit_in_pages;
limit_in_pages = 0;
if (limit > 0xffff) {
limit = limit >> 12;
limit_in_pages = 1;
}
return -1;
}
static void write_dt(void *ptr, unsigned long addr, unsigned long limit,
int flags)
{
unsigned int e1, e2;
e1 = (addr << 16) | (limit & 0xffff);
e2 = ((addr >> 16) & 0xff) | (addr & 0xff000000) | (limit & 0x000f0000);
e2 |= limit_in_pages << 23; /* byte granularity */
e2 |= seg32_bit << 22; /* 32 bit segment */
e2 |= flags;
stl((uint8_t *)ptr, e1);
stl((uint8_t *)ptr + 4, e2);
}
static void set_gate(void *ptr, unsigned int type, unsigned int dpl,
unsigned long addr, unsigned int sel)
{
unsigned int e1, e2;
e1 = (addr & 0xffff) | (sel << 16);
e2 = (addr & 0xffff0000) | 0x8000 | (dpl << 13) | (type << 8);
stl((uint8_t *)ptr, e1);
stl((uint8_t *)ptr + 4, e2);
}
uint64_t gdt_table[6];
uint64_t idt_table[256];
//#define DEBUG_VM86
static inline int is_revectored(int nr, struct target_revectored_struct *bitmap)
/* only dpl matters as we do only user space emulation */
static void set_idt(int n, unsigned int dpl)
{
return (tswap32(bitmap->__map[nr >> 5]) >> (nr & 0x1f)) & 1;
set_gate(idt_table + n, 0, dpl, 0, 0);
}
static inline uint8_t *seg_to_linear(unsigned int seg, unsigned int reg)
{
return (uint8_t *)((seg << 4) + (reg & 0xffff));
}
static inline void pushw(CPUX86State *env, int val)
{
env->regs[R_ESP] = (env->regs[R_ESP] & ~0xffff) |
((env->regs[R_ESP] - 2) & 0xffff);
*(uint16_t *)seg_to_linear(env->segs[R_SS], env->regs[R_ESP]) = val;
}
static inline unsigned int get_vflags(CPUX86State *env)
{
unsigned int eflags;
eflags = env->eflags & ~(VM_MASK | RF_MASK | IF_MASK);
if (eflags & VIF_MASK)
eflags |= IF_MASK;
return eflags;
}
void save_v86_state(CPUX86State *env)
{
TaskState *ts = env->opaque;
#ifdef DEBUG_VM86
printf("save_v86_state\n");
#endif
/* put the VM86 registers in the userspace register structure */
ts->target_v86->regs.eax = tswap32(env->regs[R_EAX]);
ts->target_v86->regs.ebx = tswap32(env->regs[R_EBX]);
ts->target_v86->regs.ecx = tswap32(env->regs[R_ECX]);
ts->target_v86->regs.edx = tswap32(env->regs[R_EDX]);
ts->target_v86->regs.esi = tswap32(env->regs[R_ESI]);
ts->target_v86->regs.edi = tswap32(env->regs[R_EDI]);
ts->target_v86->regs.ebp = tswap32(env->regs[R_EBP]);
ts->target_v86->regs.esp = tswap32(env->regs[R_ESP]);
ts->target_v86->regs.eip = tswap32(env->eip);
ts->target_v86->regs.cs = tswap16(env->segs[R_CS]);
ts->target_v86->regs.ss = tswap16(env->segs[R_SS]);
ts->target_v86->regs.ds = tswap16(env->segs[R_DS]);
ts->target_v86->regs.es = tswap16(env->segs[R_ES]);
ts->target_v86->regs.fs = tswap16(env->segs[R_FS]);
ts->target_v86->regs.gs = tswap16(env->segs[R_GS]);
ts->target_v86->regs.eflags = tswap32(env->eflags);
/* restore 32 bit registers */
env->regs[R_EAX] = ts->vm86_saved_regs.eax;
env->regs[R_EBX] = ts->vm86_saved_regs.ebx;
env->regs[R_ECX] = ts->vm86_saved_regs.ecx;
env->regs[R_EDX] = ts->vm86_saved_regs.edx;
env->regs[R_ESI] = ts->vm86_saved_regs.esi;
env->regs[R_EDI] = ts->vm86_saved_regs.edi;
env->regs[R_EBP] = ts->vm86_saved_regs.ebp;
env->regs[R_ESP] = ts->vm86_saved_regs.esp;
env->eflags = ts->vm86_saved_regs.eflags;
env->eip = ts->vm86_saved_regs.eip;
cpu_x86_load_seg(env, R_CS, ts->vm86_saved_regs.cs);
cpu_x86_load_seg(env, R_SS, ts->vm86_saved_regs.ss);
cpu_x86_load_seg(env, R_DS, ts->vm86_saved_regs.ds);
cpu_x86_load_seg(env, R_ES, ts->vm86_saved_regs.es);
cpu_x86_load_seg(env, R_FS, ts->vm86_saved_regs.fs);
cpu_x86_load_seg(env, R_GS, ts->vm86_saved_regs.gs);
}
/* return from vm86 mode to 32 bit. The vm86() syscall will return
'retval' */
static inline void return_to_32bit(CPUX86State *env, int retval)
{
#ifdef DEBUG_VM86
printf("return_to_32bit: ret=0x%x\n", retval);
#endif
save_v86_state(env);
env->regs[R_EAX] = retval;
}
/* handle VM86 interrupt (NOTE: the CPU core currently does not
support TSS interrupt revectoring, so this code is always executed) */
static void do_int(CPUX86State *env, int intno)
{
TaskState *ts = env->opaque;
uint32_t *int_ptr, segoffs;
if (env->segs[R_CS] == TARGET_BIOSSEG)
goto cannot_handle; /* XXX: I am not sure this is really useful */
if (is_revectored(intno, &ts->target_v86->int_revectored))
goto cannot_handle;
if (intno == 0x21 && is_revectored((env->regs[R_EAX] >> 8) & 0xff,
&ts->target_v86->int21_revectored))
goto cannot_handle;
int_ptr = (uint32_t *)(intno << 2);
segoffs = tswap32(*int_ptr);
if ((segoffs >> 16) == TARGET_BIOSSEG)
goto cannot_handle;
#ifdef DEBUG_VM86
printf("VM86: emulating int 0x%x. CS:IP=%04x:%04x\n",
intno, segoffs >> 16, segoffs & 0xffff);
#endif
/* save old state */
pushw(env, get_vflags(env));
pushw(env, env->segs[R_CS]);
pushw(env, env->eip);
/* goto interrupt handler */
env->eip = segoffs & 0xffff;
cpu_x86_load_seg(env, R_CS, segoffs >> 16);
env->eflags &= ~(VIF_MASK | TF_MASK);
return;
cannot_handle:
#ifdef DEBUG_VM86
printf("VM86: return to 32 bits int 0x%x\n", intno);
#endif
return_to_32bit(env, TARGET_VM86_INTx | (intno << 8));
}
void cpu_loop(struct CPUX86State *env)
void cpu_loop(CPUX86State *env)
{
int trapnr;
uint8_t *pc;
@@ -249,69 +139,50 @@ void cpu_loop(struct CPUX86State *env)
for(;;) {
trapnr = cpu_x86_exec(env);
pc = env->seg_cache[R_CS].base + env->eip;
switch(trapnr) {
case 0x80:
/* linux syscall */
env->regs[R_EAX] = do_syscall(env,
env->regs[R_EAX],
env->regs[R_EBX],
env->regs[R_ECX],
env->regs[R_EDX],
env->regs[R_ESI],
env->regs[R_EDI],
env->regs[R_EBP]);
break;
case EXCP0B_NOSEG:
case EXCP0C_STACK:
info.si_signo = SIGBUS;
info.si_errno = 0;
info.si_code = TARGET_SI_KERNEL;
info._sifields._sigfault._addr = 0;
queue_signal(info.si_signo, &info);
break;
case EXCP0D_GPF:
if (env->eflags & VM_MASK) {
#ifdef DEBUG_VM86
printf("VM86 exception %04x:%08x %02x %02x\n",
env->segs[R_CS], env->eip, pc[0], pc[1]);
#endif
/* VM86 mode */
switch(pc[0]) {
case 0xcd: /* int */
env->eip += 2;
do_int(env, pc[1]);
break;
case 0x66:
switch(pc[1]) {
case 0xfb: /* sti */
case 0x9d: /* popf */
case 0xcf: /* iret */
env->eip += 2;
return_to_32bit(env, TARGET_VM86_STI);
break;
default:
goto vm86_gpf;
}
break;
case 0xfb: /* sti */
case 0x9d: /* popf */
case 0xcf: /* iret */
env->eip++;
return_to_32bit(env, TARGET_VM86_STI);
break;
default:
vm86_gpf:
/* real VM86 GPF exception */
return_to_32bit(env, TARGET_VM86_UNKNOWN);
break;
}
handle_vm86_fault(env);
} else {
if (pc[0] == 0xcd && pc[1] == 0x80) {
/* syscall */
env->eip += 2;
env->regs[R_EAX] = do_syscall(env,
env->regs[R_EAX],
env->regs[R_EBX],
env->regs[R_ECX],
env->regs[R_EDX],
env->regs[R_ESI],
env->regs[R_EDI],
env->regs[R_EBP]);
} else {
/* XXX: more precise info */
info.si_signo = SIGSEGV;
info.si_errno = 0;
info.si_code = 0;
info._sifields._sigfault._addr = 0;
queue_signal(info.si_signo, &info);
}
info.si_signo = SIGSEGV;
info.si_errno = 0;
info.si_code = TARGET_SI_KERNEL;
info._sifields._sigfault._addr = 0;
queue_signal(info.si_signo, &info);
}
break;
case EXCP0E_PAGE:
info.si_signo = SIGSEGV;
info.si_errno = 0;
if (!(env->error_code & 1))
info.si_code = TARGET_SEGV_MAPERR;
else
info.si_code = TARGET_SEGV_ACCERR;
info._sifields._sigfault._addr = env->cr[2];
queue_signal(info.si_signo, &info);
break;
case EXCP00_DIVZ:
if (env->eflags & VM_MASK) {
do_int(env, trapnr);
handle_vm86_trap(env, trapnr);
} else {
/* division by zero */
info.si_signo = SIGFPE;
@@ -321,14 +192,31 @@ void cpu_loop(struct CPUX86State *env)
queue_signal(info.si_signo, &info);
}
break;
case EXCP01_SSTP:
case EXCP03_INT3:
if (env->eflags & VM_MASK) {
handle_vm86_trap(env, trapnr);
} else {
info.si_signo = SIGTRAP;
info.si_errno = 0;
if (trapnr == EXCP01_SSTP) {
info.si_code = TARGET_TRAP_BRKPT;
info._sifields._sigfault._addr = env->eip;
} else {
info.si_code = TARGET_SI_KERNEL;
info._sifields._sigfault._addr = 0;
}
queue_signal(info.si_signo, &info);
}
break;
case EXCP04_INTO:
case EXCP05_BOUND:
if (env->eflags & VM_MASK) {
do_int(env, trapnr);
handle_vm86_trap(env, trapnr);
} else {
info.si_signo = SIGSEGV;
info.si_errno = 0;
info.si_code = 0;
info.si_code = TARGET_SI_KERNEL;
info._sifields._sigfault._addr = 0;
queue_signal(info.si_signo, &info);
}
@@ -344,6 +232,7 @@ void cpu_loop(struct CPUX86State *env)
/* just indicate that signals should be handled asap */
break;
default:
pc = env->segs[R_CS].base + env->eip;
fprintf(stderr, "qemu: 0x%08lx: unhandled CPU exception 0x%x - aborting\n",
(long)pc, trapnr);
abort();
@@ -351,25 +240,115 @@ void cpu_loop(struct CPUX86State *env)
process_pending_signals(env);
}
}
#endif
#ifdef TARGET_ARM
void cpu_loop(CPUARMState *env)
{
int trapnr;
unsigned int n, insn;
target_siginfo_t info;
for(;;) {
trapnr = cpu_arm_exec(env);
switch(trapnr) {
case EXCP_UDEF:
info.si_signo = SIGILL;
info.si_errno = 0;
info.si_code = TARGET_ILL_ILLOPN;
info._sifields._sigfault._addr = env->regs[15];
queue_signal(info.si_signo, &info);
break;
case EXCP_SWI:
{
/* system call */
insn = ldl((void *)(env->regs[15] - 4));
n = insn & 0xffffff;
if (n >= ARM_SYSCALL_BASE) {
/* linux syscall */
n -= ARM_SYSCALL_BASE;
env->regs[0] = do_syscall(env,
n,
env->regs[0],
env->regs[1],
env->regs[2],
env->regs[3],
env->regs[4],
0);
} else {
goto error;
}
}
break;
case EXCP_INTERRUPT:
/* just indicate that signals should be handled asap */
break;
default:
error:
fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n",
trapnr);
cpu_arm_dump_state(env, stderr, 0);
abort();
}
process_pending_signals(env);
}
}
#endif
#ifdef TARGET_SPARC
void cpu_loop (CPUSPARCState *env)
{
int trapnr;
while (1) {
trapnr = cpu_sparc_exec (env);
switch (trapnr) {
case 0x8: case 0x10:
env->regwptr[0] = do_syscall (env, env->gregs[1],
env->regwptr[0], env->regwptr[1], env->regwptr[2],
env->regwptr[3], env->regwptr[4], env->regwptr[13]);
if (env->regwptr[0] >= 0xffffffe0)
env->psr |= PSR_CARRY;
break;
default:
printf ("Invalid trap: %d\n", trapnr);
exit (1);
}
process_pending_signals (env);
}
}
#endif
void usage(void)
{
printf("qemu version " QEMU_VERSION ", Copyright (c) 2003 Fabrice Bellard\n"
"usage: qemu [-h] [-d] [-L path] [-s size] program [arguments...]\n"
"Linux x86 emulator\n"
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"
"-d activate log (logfile=%s)\n"
"-L path set the x86 elf interpreter prefix (default=%s)\n"
"-s size set the x86 stack size in bytes (default=%ld)\n",
DEBUG_LOGFILE,
"-h print this help\n"
"-L path set the elf interpreter prefix (default=%s)\n"
"-s size set the stack size in bytes (default=%ld)\n"
"\n"
"debug options:\n"
"-d activate log (logfile=%s)\n"
"-p pagesize set the host page size to 'pagesize'\n",
TARGET_ARCH,
interp_prefix,
x86_stack_size);
x86_stack_size,
DEBUG_LOGFILE);
_exit(1);
}
/* XXX: currently only used for async signals (see signal.c) */
CPUX86State *global_env;
CPUState *global_env;
/* used only if single thread */
CPUState *cpu_single_env = NULL;
/* used to free thread contexts */
TaskState *first_task_state;
@@ -379,14 +358,16 @@ int main(int argc, char **argv)
struct target_pt_regs regs1, *regs = &regs1;
struct image_info info1, *info = &info1;
TaskState ts1, *ts = &ts1;
CPUX86State *env;
CPUState *env;
int optind;
const char *r;
if (argc <= 1)
usage();
loglevel = 0;
/* init debug */
cpu_set_log_filename(DEBUG_LOGFILE);
optind = 1;
for(;;) {
if (optind >= argc)
@@ -399,7 +380,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);
@@ -411,6 +392,13 @@ int main(int argc, char **argv)
x86_stack_size *= 1024;
} else if (!strcmp(r, "L")) {
interp_prefix = argv[optind++];
} else if (!strcmp(r, "p")) {
host_page_size = atoi(argv[optind++]);
if (host_page_size == 0 ||
(host_page_size & (host_page_size - 1)) != 0) {
fprintf(stderr, "page size must be a power of two\n");
exit(1);
}
} else {
usage();
}
@@ -419,16 +407,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));
@@ -438,34 +416,44 @@ int main(int argc, char **argv)
/* Scan interp_prefix dir for replacement files. */
init_paths(interp_prefix);
/* NOTE: we need to init the CPU at this stage to get the
host_page_size */
env = cpu_init();
if (elf_exec(filename, argv+optind, environ, regs, info) != 0) {
printf("Error loading %s\n", filename);
_exit(1);
}
if (loglevel) {
page_dump(logfile);
fprintf(logfile, "start_brk 0x%08lx\n" , info->start_brk);
fprintf(logfile, "end_code 0x%08lx\n" , info->end_code);
fprintf(logfile, "start_code 0x%08lx\n" , info->start_code);
fprintf(logfile, "end_data 0x%08lx\n" , info->end_data);
fprintf(logfile, "start_stack 0x%08lx\n" , info->start_stack);
fprintf(logfile, "brk 0x%08lx\n" , info->brk);
fprintf(logfile, "esp 0x%08lx\n" , regs->esp);
fprintf(logfile, "eip 0x%08lx\n" , regs->eip);
fprintf(logfile, "entry 0x%08lx\n" , info->entry);
}
target_set_brk((char *)info->brk);
syscall_init();
signal_init();
env = cpu_x86_init();
global_env = env;
/* build Task State */
memset(ts, 0, sizeof(TaskState));
env->opaque = ts;
ts->used = 1;
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;
@@ -477,11 +465,40 @@ int main(int argc, char **argv)
env->regs[R_ESP] = regs->esp;
env->eip = regs->eip;
/* linux interrupt setup */
env->idt.base = (void *)idt_table;
env->idt.limit = sizeof(idt_table) - 1;
set_idt(0, 0);
set_idt(1, 0);
set_idt(2, 0);
set_idt(3, 3);
set_idt(4, 3);
set_idt(5, 3);
set_idt(6, 0);
set_idt(7, 0);
set_idt(8, 0);
set_idt(9, 0);
set_idt(10, 0);
set_idt(11, 0);
set_idt(12, 0);
set_idt(13, 0);
set_idt(14, 0);
set_idt(15, 0);
set_idt(16, 0);
set_idt(17, 0);
set_idt(18, 0);
set_idt(19, 0);
set_idt(0x80, 3);
/* linux segment setup */
env->gdt.base = (void *)gdt_table;
env->gdt.limit = sizeof(gdt_table) - 1;
write_dt(&gdt_table[__USER_CS >> 3], 0, 0xffffffff, 1);
write_dt(&gdt_table[__USER_DS >> 3], 0, 0xffffffff, 1);
write_dt(&gdt_table[__USER_CS >> 3], 0, 0xfffff,
DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK |
(3 << DESC_DPL_SHIFT) | (0xa << DESC_TYPE_SHIFT));
write_dt(&gdt_table[__USER_DS >> 3], 0, 0xfffff,
DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK |
(3 << DESC_DPL_SHIFT) | (0x2 << DESC_TYPE_SHIFT));
cpu_x86_load_seg(env, R_CS, __USER_CS);
cpu_x86_load_seg(env, R_DS, __USER_DS);
cpu_x86_load_seg(env, R_ES, __USER_DS);
@@ -489,6 +506,21 @@ int main(int argc, char **argv)
cpu_x86_load_seg(env, R_FS, __USER_DS);
cpu_x86_load_seg(env, R_GS, __USER_DS);
#elif defined(TARGET_ARM)
{
int i;
for(i = 0; i < 16; i++) {
env->regs[i] = regs->uregs[i];
}
env->cpsr = regs->uregs[16];
}
#elif defined(TARGET_SPARC)
env->pc = regs->u_regs[0];
env->regwptr[6] = regs->u_regs[1]-0x40;
#else
#error unsupported target CPU
#endif
cpu_loop(env);
/* never exits */
return 0;

392
linux-user/mmap.c Normal file
View File

@@ -0,0 +1,392 @@
/*
* mmap support for qemu
*
* Copyright (c) 2003 Fabrice Bellard
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/mman.h>
#include "qemu.h"
//#define DEBUG_MMAP
/* NOTE: all the constants are the HOST ones */
int target_mprotect(unsigned long start, unsigned long len, int prot)
{
unsigned long end, host_start, host_end, addr;
int prot1, ret;
#ifdef DEBUG_MMAP
printf("mprotect: start=0x%lx len=0x%lx prot=%c%c%c\n", start, len,
prot & PROT_READ ? 'r' : '-',
prot & PROT_WRITE ? 'w' : '-',
prot & PROT_EXEC ? 'x' : '-');
#endif
if ((start & ~TARGET_PAGE_MASK) != 0)
return -EINVAL;
len = TARGET_PAGE_ALIGN(len);
end = start + len;
if (end < start)
return -EINVAL;
if (prot & ~(PROT_READ | PROT_WRITE | PROT_EXEC))
return -EINVAL;
if (len == 0)
return 0;
host_start = start & host_page_mask;
host_end = HOST_PAGE_ALIGN(end);
if (start > host_start) {
/* handle host page containing start */
prot1 = prot;
for(addr = host_start; addr < start; addr += TARGET_PAGE_SIZE) {
prot1 |= page_get_flags(addr);
}
if (host_end == host_start + host_page_size) {
for(addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) {
prot1 |= page_get_flags(addr);
}
end = host_end;
}
ret = mprotect((void *)host_start, host_page_size, prot1 & PAGE_BITS);
if (ret != 0)
return ret;
host_start += host_page_size;
}
if (end < host_end) {
prot1 = prot;
for(addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) {
prot1 |= page_get_flags(addr);
}
ret = mprotect((void *)(host_end - host_page_size), host_page_size,
prot1 & PAGE_BITS);
if (ret != 0)
return ret;
host_end -= host_page_size;
}
/* handle the pages in the middle */
if (host_start < host_end) {
ret = mprotect((void *)host_start, host_end - host_start, prot);
if (ret != 0)
return ret;
}
page_set_flags(start, start + len, prot | PAGE_VALID);
return 0;
}
/* map an incomplete host page */
int mmap_frag(unsigned long host_start,
unsigned long start, unsigned long end,
int prot, int flags, int fd, unsigned long offset)
{
unsigned long host_end, ret, addr;
int prot1, prot_new;
host_end = host_start + host_page_size;
/* get the protection of the target pages outside the mapping */
prot1 = 0;
for(addr = host_start; addr < host_end; addr++) {
if (addr < start || addr >= end)
prot1 |= page_get_flags(addr);
}
if (prot1 == 0) {
/* no page was there, so we allocate one */
ret = (long)mmap((void *)host_start, host_page_size, prot,
flags | MAP_ANONYMOUS, -1, 0);
if (ret == -1)
return ret;
}
prot1 &= PAGE_BITS;
prot_new = prot | prot1;
if (!(flags & MAP_ANONYMOUS)) {
/* msync() won't work here, so we return an error if write is
possible while it is a shared mapping */
if ((flags & MAP_TYPE) == MAP_SHARED &&
(prot & PROT_WRITE))
return -EINVAL;
/* adjust protection to be able to read */
if (!(prot1 & PROT_WRITE))
mprotect((void *)host_start, host_page_size, prot1 | PROT_WRITE);
/* read the corresponding file data */
pread(fd, (void *)start, end - start, offset);
/* put final protection */
if (prot_new != (prot1 | PROT_WRITE))
mprotect((void *)host_start, host_page_size, prot_new);
} else {
/* just update the protection */
if (prot_new != prot1) {
mprotect((void *)host_start, host_page_size, prot_new);
}
}
return 0;
}
/* NOTE: all the constants are the HOST ones */
long target_mmap(unsigned long start, unsigned long len, int prot,
int flags, int fd, unsigned long offset)
{
unsigned long ret, end, host_start, host_end, retaddr, host_offset, host_len;
#ifdef DEBUG_MMAP
{
printf("mmap: start=0x%lx len=0x%lx prot=%c%c%c flags=",
start, len,
prot & PROT_READ ? 'r' : '-',
prot & PROT_WRITE ? 'w' : '-',
prot & PROT_EXEC ? 'x' : '-');
if (flags & MAP_FIXED)
printf("MAP_FIXED ");
if (flags & MAP_ANONYMOUS)
printf("MAP_ANON ");
switch(flags & MAP_TYPE) {
case MAP_PRIVATE:
printf("MAP_PRIVATE ");
break;
case MAP_SHARED:
printf("MAP_SHARED ");
break;
default:
printf("[MAP_TYPE=0x%x] ", flags & MAP_TYPE);
break;
}
printf("fd=%d offset=%lx\n", fd, offset);
}
#endif
if (offset & ~TARGET_PAGE_MASK)
return -EINVAL;
len = TARGET_PAGE_ALIGN(len);
if (len == 0)
return start;
host_start = start & host_page_mask;
if (!(flags & MAP_FIXED)) {
#if defined(__alpha__) || defined(__sparc__)
/* tell the kenel to search at the same place as i386 */
if (host_start == 0)
host_start = 0x40000000;
#endif
if (host_page_size != real_host_page_size) {
/* NOTE: this code is only for debugging with '-p' option */
/* reserve a memory area */
host_len = HOST_PAGE_ALIGN(len) + host_page_size - TARGET_PAGE_SIZE;
host_start = (long)mmap((void *)host_start, host_len, PROT_NONE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (host_start == -1)
return host_start;
host_end = host_start + host_len;
start = HOST_PAGE_ALIGN(host_start);
end = start + HOST_PAGE_ALIGN(len);
if (start > host_start)
munmap((void *)host_start, start - host_start);
if (end < host_end)
munmap((void *)end, host_end - end);
/* use it as a fixed mapping */
flags |= MAP_FIXED;
} else {
/* if not fixed, no need to do anything */
host_offset = offset & host_page_mask;
host_len = len + offset - host_offset;
start = (long)mmap((void *)host_start, host_len,
prot, flags, fd, host_offset);
if (start == -1)
return start;
/* update start so that it points to the file position at 'offset' */
if (!(flags & MAP_ANONYMOUS))
start += offset - host_offset;
goto the_end1;
}
}
if (start & ~TARGET_PAGE_MASK)
return -EINVAL;
end = start + len;
host_end = HOST_PAGE_ALIGN(end);
/* worst case: we cannot map the file because the offset is not
aligned, so we read it */
if (!(flags & MAP_ANONYMOUS) &&
(offset & ~host_page_mask) != (start & ~host_page_mask)) {
/* msync() won't work here, so we return an error if write is
possible while it is a shared mapping */
if ((flags & MAP_TYPE) == MAP_SHARED &&
(prot & PROT_WRITE))
return -EINVAL;
retaddr = target_mmap(start, len, prot | PROT_WRITE,
MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS,
-1, 0);
if (retaddr == -1)
return retaddr;
pread(fd, (void *)start, len, offset);
if (!(prot & PROT_WRITE)) {
ret = target_mprotect(start, len, prot);
if (ret != 0)
return ret;
}
goto the_end;
}
/* handle the start of the mapping */
if (start > host_start) {
if (host_end == host_start + host_page_size) {
/* one single host page */
ret = mmap_frag(host_start, start, end,
prot, flags, fd, offset);
if (ret == -1)
return ret;
goto the_end1;
}
ret = mmap_frag(host_start, start, host_start + host_page_size,
prot, flags, fd, offset);
if (ret == -1)
return ret;
host_start += host_page_size;
}
/* handle the end of the mapping */
if (end < host_end) {
ret = mmap_frag(host_end - host_page_size,
host_end - host_page_size, host_end,
prot, flags, fd,
offset + host_end - host_page_size - start);
if (ret == -1)
return ret;
host_end -= host_page_size;
}
/* map the middle (easier) */
if (host_start < host_end) {
unsigned long offset1;
if (flags & MAP_ANONYMOUS)
offset1 = 0;
else
offset1 = offset + host_start - start;
ret = (long)mmap((void *)host_start, host_end - host_start,
prot, flags, fd, offset1);
if (ret == -1)
return ret;
}
the_end1:
page_set_flags(start, start + len, prot | PAGE_VALID);
the_end:
#ifdef DEBUG_MMAP
printf("ret=0x%lx\n", (long)start);
page_dump(stdout);
printf("\n");
#endif
return start;
}
int target_munmap(unsigned long start, unsigned long len)
{
unsigned long end, host_start, host_end, addr;
int prot, ret;
#ifdef DEBUG_MMAP
printf("munmap: start=0x%lx len=0x%lx\n", start, len);
#endif
if (start & ~TARGET_PAGE_MASK)
return -EINVAL;
len = TARGET_PAGE_ALIGN(len);
if (len == 0)
return -EINVAL;
end = start + len;
host_start = start & host_page_mask;
host_end = HOST_PAGE_ALIGN(end);
if (start > host_start) {
/* handle host page containing start */
prot = 0;
for(addr = host_start; addr < start; addr += TARGET_PAGE_SIZE) {
prot |= page_get_flags(addr);
}
if (host_end == host_start + host_page_size) {
for(addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) {
prot |= page_get_flags(addr);
}
end = host_end;
}
if (prot != 0)
host_start += host_page_size;
}
if (end < host_end) {
prot = 0;
for(addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) {
prot |= page_get_flags(addr);
}
if (prot != 0)
host_end -= host_page_size;
}
/* unmap what we can */
if (host_start < host_end) {
ret = munmap((void *)host_start, host_end - host_start);
if (ret != 0)
return ret;
}
page_set_flags(start, start + len, 0);
return 0;
}
/* XXX: currently, we only handle MAP_ANONYMOUS and not MAP_FIXED
blocks which have been allocated starting on a host page */
long target_mremap(unsigned long old_addr, unsigned long old_size,
unsigned long new_size, unsigned long flags,
unsigned long new_addr)
{
int prot;
/* XXX: use 5 args syscall */
new_addr = (long)mremap((void *)old_addr, old_size, new_size, flags);
if (new_addr == -1)
return new_addr;
prot = page_get_flags(old_addr);
page_set_flags(old_addr, old_addr + old_size, 0);
page_set_flags(new_addr, new_addr + new_size, prot | PAGE_VALID);
return new_addr;
}
int target_msync(unsigned long start, unsigned long len, int flags)
{
unsigned long end;
if (start & ~TARGET_PAGE_MASK)
return -EINVAL;
len = TARGET_PAGE_ALIGN(len);
end = start + len;
if (end < start)
return -EINVAL;
if (end == start)
return 0;
start &= host_page_mask;
return msync((void *)start, end - start, flags);
}

View File

@@ -6,10 +6,8 @@
#include <signal.h>
#include "syscall_defs.h"
#ifdef TARGET_I386
#include "cpu-i386.h"
#include "syscall-i386.h"
#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
@@ -33,6 +31,7 @@ struct image_info {
int personality;
};
#ifdef TARGET_I386
/* Information about the current linux thread */
struct vm86_saved_state {
uint32_t eax; /* return code */
@@ -47,13 +46,19 @@ struct vm86_saved_state {
uint32_t eip;
uint16_t cs, ss, ds, es, fs, gs;
};
#endif
/* NOTE: we force a big alignment so that the stack stored after is
aligned too */
typedef struct TaskState {
struct TaskState *next;
#ifdef TARGET_I386
struct target_vm86plus_struct *target_v86;
struct vm86_saved_state vm86_saved_regs;
struct target_vm86plus_struct vm86plus;
uint32_t v86flags;
uint32_t v86mask;
#endif
int used; /* non zero if used */
uint8_t stack[0];
} __attribute__((aligned(16))) TaskState;
@@ -68,12 +73,40 @@ void syscall_init(void);
long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
long arg4, long arg5, long arg6);
void gemu_log(const char *fmt, ...) __attribute__((format(printf,1,2)));
extern CPUX86State *global_env;
void cpu_loop(CPUX86State *env);
extern CPUState *global_env;
void cpu_loop(CPUState *env);
void init_paths(const char *prefix);
const char *path(const char *pathname);
extern int loglevel;
extern FILE *logfile;
/* signal.c */
void process_pending_signals(void *cpu_env);
void signal_init(void);
int queue_signal(int sig, target_siginfo_t *info);
void host_to_target_siginfo(target_siginfo_t *tinfo, const siginfo_t *info);
void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo);
long do_sigreturn(CPUState *env);
long do_rt_sigreturn(CPUState *env);
#ifdef TARGET_I386
/* vm86.c */
void save_v86_state(CPUX86State *env);
void init_paths(const char *prefix);
const char *path(const char *pathname);
void handle_vm86_trap(CPUX86State *env, int trapno);
void handle_vm86_fault(CPUX86State *env);
int do_vm86(CPUX86State *env, long subfunction,
struct target_vm86plus_struct * target_v86);
#endif
/* mmap.c */
int target_mprotect(unsigned long start, unsigned long len, int prot);
long target_mmap(unsigned long start, unsigned long len, int prot,
int flags, int fd, unsigned long offset);
int target_munmap(unsigned long start, unsigned long len);
long target_mremap(unsigned long old_addr, unsigned long old_size,
unsigned long new_size, unsigned long flags,
unsigned long new_addr);
int target_msync(unsigned long start, unsigned long len, int flags);
#endif

View File

@@ -26,6 +26,13 @@
#include <errno.h>
#include <sys/ucontext.h>
#ifdef __ia64__
#undef uc_mcontext
#undef uc_sigmask
#undef uc_stack
#undef uc_link
#endif
#include "qemu.h"
//#define DEBUG_SIGNAL
@@ -53,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 */
@@ -103,7 +188,8 @@ static inline void host_to_target_siginfo_noswap(target_siginfo_t *tinfo,
tinfo->si_signo = sig;
tinfo->si_errno = 0;
tinfo->si_code = 0;
if (sig == SIGILL || sig == SIGFPE || sig == SIGSEGV || sig == SIGBUS) {
if (sig == SIGILL || sig == SIGFPE || sig == SIGSEGV ||
sig == SIGBUS || sig == SIGTRAP) {
/* should never come here, but who knows. The information for
the target is irrelevant */
tinfo->_sifields._sigfault._addr = 0;
@@ -124,7 +210,8 @@ static void tswap_siginfo(target_siginfo_t *tinfo,
tinfo->si_signo = tswap32(sig);
tinfo->si_errno = tswap32(info->si_errno);
tinfo->si_code = tswap32(info->si_code);
if (sig == SIGILL || sig == SIGFPE || sig == SIGSEGV || sig == SIGBUS) {
if (sig == SIGILL || sig == SIGFPE || sig == SIGSEGV ||
sig == SIGBUS || sig == SIGTRAP) {
tinfo->_sifields._sigfault._addr =
tswapl(info->_sifields._sigfault._addr);
} else if (sig >= TARGET_SIGRTMIN) {
@@ -158,15 +245,25 @@ 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);
act.sa_flags = SA_SIGINFO;
act.sa_sigaction = host_signal_handler;
for(i = 1; i < NSIG; i++) {
sigaction(i, &act, NULL);
sigaction(i, &act, NULL);
}
memset(sigact_table, 0, sizeof(sigact_table));
@@ -309,7 +406,7 @@ static void host_signal_handler(int host_signum, siginfo_t *info,
/* the CPU emulator uses some host signals to detect exceptions,
we we forward to it some signals */
if (host_signum == SIGSEGV || host_signum == SIGBUS) {
if (cpu_x86_signal_handler(host_signum, info, puc))
if (cpu_signal_handler(host_signum, info, puc))
return;
}
@@ -324,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_x86_interrupt(global_env);
cpu_interrupt(global_env, CPU_INTERRUPT_EXIT);
}
}
@@ -355,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 */
@@ -463,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,
@@ -508,10 +641,10 @@ setup_sigcontext(struct target_sigcontext *sc, struct target_fpstate *fpstate,
{
int err = 0;
err |= __put_user(env->segs[R_GS], (unsigned int *)&sc->gs);
err |= __put_user(env->segs[R_FS], (unsigned int *)&sc->fs);
err |= __put_user(env->segs[R_ES], (unsigned int *)&sc->es);
err |= __put_user(env->segs[R_DS], (unsigned int *)&sc->ds);
err |= __put_user(env->segs[R_GS].selector, (unsigned int *)&sc->gs);
err |= __put_user(env->segs[R_FS].selector, (unsigned int *)&sc->fs);
err |= __put_user(env->segs[R_ES].selector, (unsigned int *)&sc->es);
err |= __put_user(env->segs[R_DS].selector, (unsigned int *)&sc->ds);
err |= __put_user(env->regs[R_EDI], &sc->edi);
err |= __put_user(env->regs[R_ESI], &sc->esi);
err |= __put_user(env->regs[R_EBP], &sc->ebp);
@@ -520,25 +653,22 @@ setup_sigcontext(struct target_sigcontext *sc, struct target_fpstate *fpstate,
err |= __put_user(env->regs[R_EDX], &sc->edx);
err |= __put_user(env->regs[R_ECX], &sc->ecx);
err |= __put_user(env->regs[R_EAX], &sc->eax);
err |= __put_user(/*current->thread.trap_no*/ 0, &sc->trapno);
err |= __put_user(/*current->thread.error_code*/ 0, &sc->err);
err |= __put_user(env->exception_index, &sc->trapno);
err |= __put_user(env->error_code, &sc->err);
err |= __put_user(env->eip, &sc->eip);
err |= __put_user(env->segs[R_CS], (unsigned int *)&sc->cs);
err |= __put_user(env->segs[R_CS].selector, (unsigned int *)&sc->cs);
err |= __put_user(env->eflags, &sc->eflags);
err |= __put_user(env->regs[R_ESP], &sc->esp_at_signal);
err |= __put_user(env->segs[R_SS], (unsigned int *)&sc->ss);
#if 0
tmp = save_i387(fpstate);
if (tmp < 0)
err = 1;
else
err |= __put_user(tmp ? fpstate : NULL, &sc->fpstate);
#else
err |= __put_user(0, &sc->fpstate);
#endif
err |= __put_user(env->segs[R_SS].selector, (unsigned int *)&sc->ss);
cpu_x86_fsave(env, (void *)fpstate, 1);
fpstate->status = fpstate->sw;
err |= __put_user(0xffff, &fpstate->magic);
err |= __put_user(fpstate, &sc->fpstate);
/* non-iBCS2 extensions.. */
err |= __put_user(mask, &sc->oldmask);
err |= __put_user(/*current->thread.cr2*/ 0, &sc->cr2);
err |= __put_user(env->cr[2], &sc->cr2);
return err;
}
@@ -561,13 +691,14 @@ get_sigframe(struct emulated_sigaction *ka, CPUX86State *env, size_t frame_size)
}
/* This is the legacy signal stack switching. */
else if ((regs->xss & 0xffff) != __USER_DS &&
!(ka->sa.sa_flags & SA_RESTORER) &&
ka->sa.sa_restorer) {
esp = (unsigned long) ka->sa.sa_restorer;
}
else
#endif
return (void *)((esp - frame_size) & -8ul);
if ((env->segs[R_SS].selector & 0xffff) != __USER_DS &&
!(ka->sa.sa_flags & TARGET_SA_RESTORER) &&
ka->sa.sa_restorer) {
esp = (unsigned long) ka->sa.sa_restorer;
}
return (void *)((esp - frame_size) & -8ul);
}
static void setup_frame(int sig, struct emulated_sigaction *ka,
@@ -712,25 +843,6 @@ restore_sigcontext(CPUX86State *env, struct target_sigcontext *sc, int *peax)
{
unsigned int err = 0;
#define COPY(x) err |= __get_user(regs->x, &sc->x)
#define COPY_SEG(seg) \
{ unsigned short tmp; \
err |= __get_user(tmp, &sc->seg); \
regs->x##seg = tmp; }
#define COPY_SEG_STRICT(seg) \
{ unsigned short tmp; \
err |= __get_user(tmp, &sc->seg); \
regs->x##seg = tmp|3; }
#define GET_SEG(seg) \
{ unsigned short tmp; \
err |= __get_user(tmp, &sc->seg); \
loadsegment(seg,tmp); }
cpu_x86_load_seg(env, R_GS, lduw(&sc->gs));
cpu_x86_load_seg(env, R_FS, lduw(&sc->fs));
cpu_x86_load_seg(env, R_ES, lduw(&sc->es));
@@ -755,17 +867,18 @@ restore_sigcontext(CPUX86State *env, struct target_sigcontext *sc, int *peax)
// regs->orig_eax = -1; /* disable syscall checks */
}
#if 0
{
struct _fpstate * buf;
err |= __get_user(buf, &sc->fpstate);
buf = (void *)ldl(&sc->fpstate);
if (buf) {
#if 0
if (verify_area(VERIFY_READ, buf, sizeof(*buf)))
goto badframe;
err |= restore_i387(buf);
#endif
cpu_x86_frstor(env, (void *)buf, 1);
}
}
#endif
*peax = ldl(&sc->eax);
return err;
#if 0
@@ -781,6 +894,9 @@ long do_sigreturn(CPUX86State *env)
sigset_t set;
int eax, i;
#if defined(DEBUG_SIGNAL)
fprintf(stderr, "do_sigreturn\n");
#endif
/* set blocked signals */
target_set.sig[0] = frame->sc.oldmask;
for(i = 1; i < TARGET_NSIG_WORDS; i++)
@@ -833,6 +949,404 @@ 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,
target_sigset_t *set, CPUState *env)
{
fprintf(stderr, "setup_frame: not implemented\n");
}
static void setup_rt_frame(int sig, struct emulated_sigaction *ka,
target_siginfo_t *info,
target_sigset_t *set, CPUState *env)
{
fprintf(stderr, "setup_rt_frame: not implemented\n");
}
long do_sigreturn(CPUState *env)
{
fprintf(stderr, "do_sigreturn: not implemented\n");
return -ENOSYS;
}
long do_rt_sigreturn(CPUState *env)
{
fprintf(stderr, "do_rt_sigreturn: not implemented\n");
return -ENOSYS;
}
#endif
void process_pending_signals(void *cpu_env)

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

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,11 @@
/* common syscall defines for all architectures */
/* Note: although the syscall numbers change between architectures,
most of them stay the same, so we handle it by puting ifdefs if
necessary */
#include "syscall_nr.h"
#define SOCKOP_socket 1
#define SOCKOP_bind 2
#define SOCKOP_connect 3
@@ -19,6 +24,66 @@
#define SOCKOP_sendmsg 16
#define SOCKOP_recvmsg 17
/*
* The following is for compatibility across the various Linux
* platforms. The i386 ioctl numbering scheme doesn't really enforce
* a type field. De facto, however, the top 8 bits of the lower 16
* bits are indeed used as a type field, so we might just as well make
* this explicit here. Please be sure to use the decoding macros
* below from now on.
*/
#define TARGET_IOC_NRBITS 8
#define TARGET_IOC_TYPEBITS 8
#if defined(TARGET_I386) || defined(TARGET_ARM)
#define TARGET_IOC_SIZEBITS 14
#define TARGET_IOC_DIRBITS 2
#define TARGET_IOC_NONE 0U
#define TARGET_IOC_WRITE 1U
#define TARGET_IOC_READ 2U
#elif defined(TARGET_PPC) || defined(TARGET_ALPHA) || defined(TARGET_SPARC)
#define TARGET_IOC_SIZEBITS 13
#define TARGET_IOC_DIRBITS 3
#define TARGET_IOC_NONE 1U
#define TARGET_IOC_READ 2U
#define TARGET_IOC_WRITE 4U
#else
#error unsupported CPU
#endif
#define TARGET_IOC_NRMASK ((1 << TARGET_IOC_NRBITS)-1)
#define TARGET_IOC_TYPEMASK ((1 << TARGET_IOC_TYPEBITS)-1)
#define TARGET_IOC_SIZEMASK ((1 << TARGET_IOC_SIZEBITS)-1)
#define TARGET_IOC_DIRMASK ((1 << TARGET_IOC_DIRBITS)-1)
#define TARGET_IOC_NRSHIFT 0
#define TARGET_IOC_TYPESHIFT (TARGET_IOC_NRSHIFT+TARGET_IOC_NRBITS)
#define TARGET_IOC_SIZESHIFT (TARGET_IOC_TYPESHIFT+TARGET_IOC_TYPEBITS)
#define TARGET_IOC_DIRSHIFT (TARGET_IOC_SIZESHIFT+TARGET_IOC_SIZEBITS)
#define TARGET_IOC(dir,type,nr,size) \
(((dir) << TARGET_IOC_DIRSHIFT) | \
((type) << TARGET_IOC_TYPESHIFT) | \
((nr) << TARGET_IOC_NRSHIFT) | \
((size) << TARGET_IOC_SIZESHIFT))
/* used to create numbers */
#define TARGET_IO(type,nr) TARGET_IOC(TARGET_IOC_NONE,(type),(nr),0)
#define TARGET_IOR(type,nr,size) TARGET_IOC(TARGET_IOC_READ,(type),(nr),sizeof(size))
#define TARGET_IOW(type,nr,size) TARGET_IOC(TARGET_IOC_WRITE,(type),(nr),sizeof(size))
#define TARGET_IOWR(type,nr,size) TARGET_IOC(TARGET_IOC_READ|TARGET_IOC_WRITE,(type),(nr),sizeof(size))
/* the size is automatically computed for these defines */
#define TARGET_IORU(type,nr) TARGET_IOC(TARGET_IOC_READ,(type),(nr),TARGET_IOC_SIZEMASK)
#define TARGET_IOWU(type,nr) TARGET_IOC(TARGET_IOC_WRITE,(type),(nr),TARGET_IOC_SIZEMASK)
#define TARGET_IOWRU(type,nr) TARGET_IOC(TARGET_IOC_READ|TARGET_IOC_WRITE,(type),(nr),TARGET_IOC_SIZEMASK)
struct target_sockaddr {
uint16_t sa_family;
uint8_t sa_data[14];
@@ -41,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;
@@ -48,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 */
@@ -191,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,
@@ -201,6 +279,170 @@ struct target_sigaction;
int do_sigaction(int sig, const struct target_sigaction *act,
struct target_sigaction *oact);
#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SPARC)
#define TARGET_SA_NOCLDSTOP 0x00000001
#define TARGET_SA_NOCLDWAIT 0x00000002 /* not supported yet */
#define TARGET_SA_SIGINFO 0x00000004
#define TARGET_SA_ONSTACK 0x08000000
#define TARGET_SA_RESTART 0x10000000
#define TARGET_SA_NODEFER 0x40000000
#define TARGET_SA_RESETHAND 0x80000000
#define TARGET_SA_RESTORER 0x04000000
#define TARGET_SIGHUP 1
#define TARGET_SIGINT 2
#define TARGET_SIGQUIT 3
#define TARGET_SIGILL 4
#define TARGET_SIGTRAP 5
#define TARGET_SIGABRT 6
#define TARGET_SIGIOT 6
#define TARGET_SIGBUS 7
#define TARGET_SIGFPE 8
#define TARGET_SIGKILL 9
#define TARGET_SIGUSR1 10
#define TARGET_SIGSEGV 11
#define TARGET_SIGUSR2 12
#define TARGET_SIGPIPE 13
#define TARGET_SIGALRM 14
#define TARGET_SIGTERM 15
#define TARGET_SIGSTKFLT 16
#define TARGET_SIGCHLD 17
#define TARGET_SIGCONT 18
#define TARGET_SIGSTOP 19
#define TARGET_SIGTSTP 20
#define TARGET_SIGTTIN 21
#define TARGET_SIGTTOU 22
#define TARGET_SIGURG 23
#define TARGET_SIGXCPU 24
#define TARGET_SIGXFSZ 25
#define TARGET_SIGVTALRM 26
#define TARGET_SIGPROF 27
#define TARGET_SIGWINCH 28
#define TARGET_SIGIO 29
#define TARGET_SIGPWR 30
#define TARGET_SIGSYS 31
#define TARGET_SIGRTMIN 32
#define TARGET_SIG_BLOCK 0 /* for blocking signals */
#define TARGET_SIG_UNBLOCK 1 /* for unblocking signals */
#define TARGET_SIG_SETMASK 2 /* for setting the signal mask */
struct target_old_sigaction {
target_ulong _sa_handler;
target_ulong sa_mask;
target_ulong sa_flags;
target_ulong sa_restorer;
};
struct target_sigaction {
target_ulong _sa_handler;
target_ulong sa_flags;
target_ulong sa_restorer;
target_sigset_t sa_mask;
};
typedef union target_sigval {
int sival_int;
target_ulong sival_ptr;
} target_sigval_t;
#define TARGET_SI_MAX_SIZE 128
#define TARGET_SI_PAD_SIZE ((TARGET_SI_MAX_SIZE/sizeof(int)) - 3)
typedef struct target_siginfo {
int si_signo;
int si_errno;
int si_code;
union {
int _pad[TARGET_SI_PAD_SIZE];
/* kill() */
struct {
pid_t _pid; /* sender's pid */
uid_t _uid; /* sender's uid */
} _kill;
/* POSIX.1b timers */
struct {
unsigned int _timer1;
unsigned int _timer2;
} _timer;
/* POSIX.1b signals */
struct {
pid_t _pid; /* sender's pid */
uid_t _uid; /* sender's uid */
target_sigval_t _sigval;
} _rt;
/* SIGCHLD */
struct {
pid_t _pid; /* which child */
uid_t _uid; /* sender's uid */
int _status; /* exit code */
target_clock_t _utime;
target_clock_t _stime;
} _sigchld;
/* SIGILL, SIGFPE, SIGSEGV, SIGBUS */
struct {
target_ulong _addr; /* faulting insn/memory ref. */
} _sigfault;
/* SIGPOLL */
struct {
int _band; /* POLL_IN, POLL_OUT, POLL_MSG */
int _fd;
} _sigpoll;
} _sifields;
} target_siginfo_t;
/*
* si_code values
* Digital reserves positive values for kernel-generated signals.
*/
#define TARGET_SI_USER 0 /* sent by kill, sigsend, raise */
#define TARGET_SI_KERNEL 0x80 /* sent by the kernel from somewhere */
#define TARGET_SI_QUEUE -1 /* sent by sigqueue */
#define TARGET_SI_TIMER -2 /* sent by timer expiration */
#define TARGET_SI_MESGQ -3 /* sent by real time mesq state change */
#define TARGET_SI_ASYNCIO -4 /* sent by AIO completion */
#define TARGET_SI_SIGIO -5 /* sent by queued SIGIO */
/*
* SIGILL si_codes
*/
#define TARGET_ILL_ILLOPN (2) /* illegal operand */
/*
* SIGFPE si_codes
*/
#define TARGET_FPE_INTDIV (1) /* integer divide by zero */
#define TARGET_FPE_INTOVF (2) /* integer overflow */
#define TARGET_FPE_FLTDIV (3) /* floating point divide by zero */
#define TARGET_FPE_FLTOVF (4) /* floating point overflow */
#define TARGET_FPE_FLTUND (5) /* floating point underflow */
#define TARGET_FPE_FLTRES (6) /* floating point inexact result */
#define TARGET_FPE_FLTINV (7) /* floating point invalid operation */
#define TARGET_FPE_FLTSUB (8) /* subscript out of range */
#define TARGET_NSIGFPE 8
/*
* SIGSEGV si_codes
*/
#define TARGET_SEGV_MAPERR (1) /* address not mapped to object */
#define TARGET_SEGV_ACCERR (2) /* invalid permissions for mapped object */
/*
* SIGTRAP si_codes
*/
#define TARGET_TRAP_BRKPT (1) /* process breakpoint */
#define TARGET_TRAP_TRACE (2) /* process trace trap */
#endif /* defined(TARGET_I386) || defined(TARGET_ARM) */
struct target_rlimit {
target_ulong rlim_cur;
target_ulong rlim_max;
@@ -212,6 +454,15 @@ struct target_pollfd {
short revents; /* returned events */
};
/* virtual terminal ioctls */
#define TARGET_KIOCSOUND 0x4B2F /* start sound generation (0 for off) */
#define TARGET_KDMKTONE 0x4B30 /* generate tone */
#define TARGET_KDGKBTYPE 0x4b33
#define TARGET_KDGKBENT 0x4B46 /* gets one entry in translation table */
#define TARGET_KDGKBSENT 0x4B48 /* gets one function key string entry */
#define TARGET_SIOCATMARK 0x8905
/* Networking ioctls */
#define TARGET_SIOCADDRT 0x890B /* add routing table entry */
#define TARGET_SIOCDELRT 0x890C /* delete routing table entry */
@@ -396,11 +647,11 @@ struct target_pollfd {
#define TARGET_HDIO_GETGEO 0x0301 /* get device geometry */
#define TARGET_HDIO_GET_UNMASKINTR 0x0302 /* get current unmask setting */
#define TARGET_HDIO_GET_MULTCOUNT 0x0304 /* get current IDE blockmode setting */
#define TARGET_HDIO_GET_IDENTITY 0x0307 /* get IDE identification info */
#define TARGET_HDIO_GET_KEEPSETTINGS 0x0308 /* get keep-settings-on-reset flag */
#define TARGET_HDIO_GET_32BIT 0x0309 /* get current io_32bit setting */
#define TARGET_HDIO_GET_NOWERR 0x030a /* get ignore-write-error flag */
#define TARGET_HDIO_GET_DMA 0x030b /* get use-dma flag */
#define TARGET_HDIO_GET_IDENTITY 0x030d /* get IDE identification info */
#define TARGET_HDIO_DRIVE_CMD 0x031f /* execute a special drive command */
/* hd/ide ctl's that pass (arg) non-ptr values are numbered 0x032n/0x033n */
@@ -411,3 +662,480 @@ struct target_pollfd {
#define TARGET_HDIO_SET_NOWERR 0x0325 /* change ignore-write-error flag */
#define TARGET_HDIO_SET_DMA 0x0326 /* change use-dma flag */
#define TARGET_HDIO_SET_PIO_MODE 0x0327 /* reconfig interface to new speed */
#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SPARC)
/* 0x54 is just a magic number to make these relatively unique ('T') */
#define TARGET_TCGETS 0x5401
#define TARGET_TCSETS 0x5402
#define TARGET_TCSETSW 0x5403
#define TARGET_TCSETSF 0x5404
#define TARGET_TCGETA 0x5405
#define TARGET_TCSETA 0x5406
#define TARGET_TCSETAW 0x5407
#define TARGET_TCSETAF 0x5408
#define TARGET_TCSBRK 0x5409
#define TARGET_TCXONC 0x540A
#define TARGET_TCFLSH 0x540B
#define TARGET_TIOCEXCL 0x540C
#define TARGET_TIOCNXCL 0x540D
#define TARGET_TIOCSCTTY 0x540E
#define TARGET_TIOCGPGRP 0x540F
#define TARGET_TIOCSPGRP 0x5410
#define TARGET_TIOCOUTQ 0x5411
#define TARGET_TIOCSTI 0x5412
#define TARGET_TIOCGWINSZ 0x5413
#define TARGET_TIOCSWINSZ 0x5414
#define TARGET_TIOCMGET 0x5415
#define TARGET_TIOCMBIS 0x5416
#define TARGET_TIOCMBIC 0x5417
#define TARGET_TIOCMSET 0x5418
#define TARGET_TIOCGSOFTCAR 0x5419
#define TARGET_TIOCSSOFTCAR 0x541A
#define TARGET_FIONREAD 0x541B
#define TARGET_TIOCINQ FIONREAD
#define TARGET_TIOCLINUX 0x541C
#define TARGET_TIOCCONS 0x541D
#define TARGET_TIOCGSERIAL 0x541E
#define TARGET_TIOCSSERIAL 0x541F
#define TARGET_TIOCPKT 0x5420
#define TARGET_FIONBIO 0x5421
#define TARGET_TIOCNOTTY 0x5422
#define TARGET_TIOCSETD 0x5423
#define TARGET_TIOCGETD 0x5424
#define TARGET_TCSBRKP 0x5425 /* Needed for POSIX tcsendbreak() */
#define TARGET_TIOCTTYGSTRUCT 0x5426 /* For debugging only */
#define TARGET_TIOCSBRK 0x5427 /* BSD compatibility */
#define TARGET_TIOCCBRK 0x5428 /* BSD compatibility */
#define TARGET_TIOCGSID 0x5429 /* Return the session ID of FD */
#define TARGET_TIOCGPTN TARGET_IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */
#define TARGET_TIOCSPTLCK TARGET_IOW('T',0x31, int) /* Lock/unlock Pty */
#define TARGET_FIONCLEX 0x5450 /* these numbers need to be adjusted. */
#define TARGET_FIOCLEX 0x5451
#define TARGET_FIOASYNC 0x5452
#define TARGET_TIOCSERCONFIG 0x5453
#define TARGET_TIOCSERGWILD 0x5454
#define TARGET_TIOCSERSWILD 0x5455
#define TARGET_TIOCGLCKTRMIOS 0x5456
#define TARGET_TIOCSLCKTRMIOS 0x5457
#define TARGET_TIOCSERGSTRUCT 0x5458 /* For debugging only */
#define TARGET_TIOCSERGETLSR 0x5459 /* Get line status register */
#define TARGET_TIOCSERGETMULTI 0x545A /* Get multiport config */
#define TARGET_TIOCSERSETMULTI 0x545B /* Set multiport config */
#define TARGET_TIOCMIWAIT 0x545C /* wait for a change on serial input line(s) */
#define TARGET_TIOCGICOUNT 0x545D /* read serial port inline interrupt counts */
#define TARGET_TIOCGHAYESESP 0x545E /* Get Hayes ESP configuration */
#define TARGET_TIOCSHAYESESP 0x545F /* Set Hayes ESP configuration */
/* Used for packet mode */
#define TARGET_TIOCPKT_DATA 0
#define TARGET_TIOCPKT_FLUSHREAD 1
#define TARGET_TIOCPKT_FLUSHWRITE 2
#define TARGET_TIOCPKT_STOP 4
#define TARGET_TIOCPKT_START 8
#define TARGET_TIOCPKT_NOSTOP 16
#define TARGET_TIOCPKT_DOSTOP 32
#define TARGET_TIOCSER_TEMT 0x01 /* Transmitter physically empty */
/* from asm/termbits.h */
#define TARGET_NCCS 19
struct target_termios {
unsigned int c_iflag; /* input mode flags */
unsigned int c_oflag; /* output mode flags */
unsigned int c_cflag; /* control mode flags */
unsigned int c_lflag; /* local mode flags */
unsigned char c_line; /* line discipline */
unsigned char c_cc[TARGET_NCCS]; /* control characters */
};
/* c_iflag bits */
#define TARGET_IGNBRK 0000001
#define TARGET_BRKINT 0000002
#define TARGET_IGNPAR 0000004
#define TARGET_PARMRK 0000010
#define TARGET_INPCK 0000020
#define TARGET_ISTRIP 0000040
#define TARGET_INLCR 0000100
#define TARGET_IGNCR 0000200
#define TARGET_ICRNL 0000400
#define TARGET_IUCLC 0001000
#define TARGET_IXON 0002000
#define TARGET_IXANY 0004000
#define TARGET_IXOFF 0010000
#define TARGET_IMAXBEL 0020000
/* c_oflag bits */
#define TARGET_OPOST 0000001
#define TARGET_OLCUC 0000002
#define TARGET_ONLCR 0000004
#define TARGET_OCRNL 0000010
#define TARGET_ONOCR 0000020
#define TARGET_ONLRET 0000040
#define TARGET_OFILL 0000100
#define TARGET_OFDEL 0000200
#define TARGET_NLDLY 0000400
#define TARGET_NL0 0000000
#define TARGET_NL1 0000400
#define TARGET_CRDLY 0003000
#define TARGET_CR0 0000000
#define TARGET_CR1 0001000
#define TARGET_CR2 0002000
#define TARGET_CR3 0003000
#define TARGET_TABDLY 0014000
#define TARGET_TAB0 0000000
#define TARGET_TAB1 0004000
#define TARGET_TAB2 0010000
#define TARGET_TAB3 0014000
#define TARGET_XTABS 0014000
#define TARGET_BSDLY 0020000
#define TARGET_BS0 0000000
#define TARGET_BS1 0020000
#define TARGET_VTDLY 0040000
#define TARGET_VT0 0000000
#define TARGET_VT1 0040000
#define TARGET_FFDLY 0100000
#define TARGET_FF0 0000000
#define TARGET_FF1 0100000
/* c_cflag bit meaning */
#define TARGET_CBAUD 0010017
#define TARGET_B0 0000000 /* hang up */
#define TARGET_B50 0000001
#define TARGET_B75 0000002
#define TARGET_B110 0000003
#define TARGET_B134 0000004
#define TARGET_B150 0000005
#define TARGET_B200 0000006
#define TARGET_B300 0000007
#define TARGET_B600 0000010
#define TARGET_B1200 0000011
#define TARGET_B1800 0000012
#define TARGET_B2400 0000013
#define TARGET_B4800 0000014
#define TARGET_B9600 0000015
#define TARGET_B19200 0000016
#define TARGET_B38400 0000017
#define TARGET_EXTA B19200
#define TARGET_EXTB B38400
#define TARGET_CSIZE 0000060
#define TARGET_CS5 0000000
#define TARGET_CS6 0000020
#define TARGET_CS7 0000040
#define TARGET_CS8 0000060
#define TARGET_CSTOPB 0000100
#define TARGET_CREAD 0000200
#define TARGET_PARENB 0000400
#define TARGET_PARODD 0001000
#define TARGET_HUPCL 0002000
#define TARGET_CLOCAL 0004000
#define TARGET_CBAUDEX 0010000
#define TARGET_B57600 0010001
#define TARGET_B115200 0010002
#define TARGET_B230400 0010003
#define TARGET_B460800 0010004
#define TARGET_CIBAUD 002003600000 /* input baud rate (not used) */
#define TARGET_CRTSCTS 020000000000 /* flow control */
/* c_lflag bits */
#define TARGET_ISIG 0000001
#define TARGET_ICANON 0000002
#define TARGET_XCASE 0000004
#define TARGET_ECHO 0000010
#define TARGET_ECHOE 0000020
#define TARGET_ECHOK 0000040
#define TARGET_ECHONL 0000100
#define TARGET_NOFLSH 0000200
#define TARGET_TOSTOP 0000400
#define TARGET_ECHOCTL 0001000
#define TARGET_ECHOPRT 0002000
#define TARGET_ECHOKE 0004000
#define TARGET_FLUSHO 0010000
#define TARGET_PENDIN 0040000
#define TARGET_IEXTEN 0100000
/* c_cc character offsets */
#define TARGET_VINTR 0
#define TARGET_VQUIT 1
#define TARGET_VERASE 2
#define TARGET_VKILL 3
#define TARGET_VEOF 4
#define TARGET_VTIME 5
#define TARGET_VMIN 6
#define TARGET_VSWTC 7
#define TARGET_VSTART 8
#define TARGET_VSTOP 9
#define TARGET_VSUSP 10
#define TARGET_VEOL 11
#define TARGET_VREPRINT 12
#define TARGET_VDISCARD 13
#define TARGET_VWERASE 14
#define TARGET_VLNEXT 15
#define TARGET_VEOL2 16
#define TARGET_MAP_SHARED 0x01 /* Share changes */
#define TARGET_MAP_PRIVATE 0x02 /* Changes are private */
#define TARGET_MAP_TYPE 0x0f /* Mask for type of mapping */
#define TARGET_MAP_FIXED 0x10 /* Interpret addr exactly */
#define TARGET_MAP_ANONYMOUS 0x20 /* don't use a file */
#define TARGET_MAP_GROWSDOWN 0x0100 /* stack-like segment */
#define TARGET_MAP_DENYWRITE 0x0800 /* ETXTBSY */
#define TARGET_MAP_EXECUTABLE 0x1000 /* mark it as an executable */
#define TARGET_MAP_LOCKED 0x2000 /* pages are locked */
#define TARGET_MAP_NORESERVE 0x4000 /* don't check for reservations */
struct target_stat {
unsigned short st_dev;
unsigned short __pad1;
target_ulong st_ino;
unsigned short st_mode;
unsigned short st_nlink;
unsigned short st_uid;
unsigned short st_gid;
unsigned short st_rdev;
unsigned short __pad2;
target_ulong st_size;
target_ulong st_blksize;
target_ulong st_blocks;
target_ulong target_st_atime;
target_ulong __unused1;
target_ulong target_st_mtime;
target_ulong __unused2;
target_ulong target_st_ctime;
target_ulong __unused3;
target_ulong __unused4;
target_ulong __unused5;
};
/* This matches struct stat64 in glibc2.1, hence the absolutely
* insane amounts of padding around dev_t's.
*/
struct target_stat64 {
unsigned short st_dev;
unsigned char __pad0[10];
#define TARGET_STAT64_HAS_BROKEN_ST_INO 1
target_ulong __st_ino;
unsigned int st_mode;
unsigned int st_nlink;
target_ulong st_uid;
target_ulong st_gid;
unsigned short st_rdev;
unsigned char __pad3[10];
long long st_size;
target_ulong st_blksize;
target_ulong st_blocks; /* Number 512-byte blocks allocated. */
target_ulong __pad4; /* future possible st_blocks high bits */
target_ulong target_st_atime;
target_ulong __pad5;
target_ulong target_st_mtime;
target_ulong __pad6;
target_ulong target_st_ctime;
target_ulong __pad7; /* will be high 32 bits of ctime someday */
unsigned long long st_ino;
} __attribute__((packed));
#endif /* defined(TARGET_I386) || defined(TARGET_ARM) */
#define TARGET_F_DUPFD 0 /* dup */
#define TARGET_F_GETFD 1 /* get close_on_exec */
#define TARGET_F_SETFD 2 /* set/clear close_on_exec */
#define TARGET_F_GETFL 3 /* get file->f_flags */
#define TARGET_F_SETFL 4 /* set file->f_flags */
#if defined(TARGET_ALPHA)
#define TARGET_F_GETLK 7
#define TARGET_F_SETLK 8
#define TARGET_F_SETLKW 9
#define TARGET_F_SETOWN 5 /* for sockets. */
#define TARGET_F_GETOWN 6 /* for sockets. */
#else
#define TARGET_F_GETLK 5
#define TARGET_F_SETLK 6
#define TARGET_F_SETLKW 7
#define TARGET_F_SETOWN 8 /* for sockets. */
#define TARGET_F_GETOWN 9 /* for sockets. */
#endif
#define TARGET_F_SETSIG 10 /* for sockets. */
#define TARGET_F_GETSIG 11 /* for sockets. */
#define TARGET_F_GETLK64 12 /* using 'struct flock64' */
#define TARGET_F_SETLK64 13
#define TARGET_F_SETLKW64 14
struct target_flock {
short l_type;
short l_whence;
target_ulong l_start;
target_ulong l_len;
int l_pid;
};
struct target_flock64 {
short l_type;
short l_whence;
unsigned long long l_start;
unsigned long long l_len;
int l_pid;
};
/* soundcard defines */
/* XXX: convert them all to arch indepedent entries */
#define TARGET_SNDCTL_COPR_HALT TARGET_IOWR('C', 7, int);
#define TARGET_SNDCTL_COPR_LOAD 0xcfb04301
#define TARGET_SNDCTL_COPR_RCODE 0xc0144303
#define TARGET_SNDCTL_COPR_RCVMSG 0x8fa44309
#define TARGET_SNDCTL_COPR_RDATA 0xc0144302
#define TARGET_SNDCTL_COPR_RESET 0x00004300
#define TARGET_SNDCTL_COPR_RUN 0xc0144306
#define TARGET_SNDCTL_COPR_SENDMSG 0xcfa44308
#define TARGET_SNDCTL_COPR_WCODE 0x40144305
#define TARGET_SNDCTL_COPR_WDATA 0x40144304
#define TARGET_SNDCTL_DSP_RESET TARGET_IO('P', 0)
#define TARGET_SNDCTL_DSP_SYNC TARGET_IO('P', 1)
#define TARGET_SNDCTL_DSP_SPEED TARGET_IOWR('P', 2, int)
#define TARGET_SNDCTL_DSP_STEREO TARGET_IOWR('P', 3, int)
#define TARGET_SNDCTL_DSP_GETBLKSIZE TARGET_IOWR('P', 4, int)
#define TARGET_SNDCTL_DSP_SETFMT TARGET_IOWR('P', 5, int)
#define TARGET_SNDCTL_DSP_CHANNELS TARGET_IOWR('P', 6, int)
#define TARGET_SOUND_PCM_WRITE_FILTER TARGET_IOWR('P', 7, int)
#define TARGET_SNDCTL_DSP_POST TARGET_IO('P', 8)
#define TARGET_SNDCTL_DSP_SUBDIVIDE TARGET_IOWR('P', 9, int)
#define TARGET_SNDCTL_DSP_SETFRAGMENT TARGET_IOWR('P',10, int)
#define TARGET_SNDCTL_DSP_GETFMTS TARGET_IOR('P', 11, int)
#define TARGET_SNDCTL_DSP_GETOSPACE TARGET_IORU('P',12)
#define TARGET_SNDCTL_DSP_GETISPACE TARGET_IORU('P',13)
#define TARGET_SNDCTL_DSP_GETCAPS TARGET_IOR('P', 15, int)
#define TARGET_SNDCTL_DSP_GETTRIGGER TARGET_IOR('P',16, int)
#define TARGET_SNDCTL_DSP_GETIPTR TARGET_IORU('P',17)
#define TARGET_SNDCTL_DSP_GETOPTR TARGET_IORU('P',18)
#define TARGET_SNDCTL_DSP_MAPINBUF 0x80085013
#define TARGET_SNDCTL_DSP_MAPOUTBUF 0x80085014
#define TARGET_SNDCTL_DSP_NONBLOCK 0x0000500e
#define TARGET_SNDCTL_DSP_SAMPLESIZE 0xc0045005
#define TARGET_SNDCTL_DSP_SETDUPLEX 0x00005016
#define TARGET_SNDCTL_DSP_SETSYNCRO 0x00005015
#define TARGET_SNDCTL_DSP_SETTRIGGER 0x40045010
#define TARGET_SNDCTL_FM_4OP_ENABLE 0x4004510f
#define TARGET_SNDCTL_FM_LOAD_INSTR 0x40285107
#define TARGET_SNDCTL_MIDI_INFO 0xc074510c
#define TARGET_SNDCTL_MIDI_MPUCMD 0xc0216d02
#define TARGET_SNDCTL_MIDI_MPUMODE 0xc0046d01
#define TARGET_SNDCTL_MIDI_PRETIME 0xc0046d00
#define TARGET_SNDCTL_PMGR_ACCESS 0xcfb85110
#define TARGET_SNDCTL_PMGR_IFACE 0xcfb85001
#define TARGET_SNDCTL_SEQ_CTRLRATE 0xc0045103
#define TARGET_SNDCTL_SEQ_GETINCOUNT 0x80045105
#define TARGET_SNDCTL_SEQ_GETOUTCOUNT 0x80045104
#define TARGET_SNDCTL_SEQ_NRMIDIS 0x8004510b
#define TARGET_SNDCTL_SEQ_NRSYNTHS 0x8004510a
#define TARGET_SNDCTL_SEQ_OUTOFBAND 0x40085112
#define TARGET_SNDCTL_SEQ_PANIC 0x00005111
#define TARGET_SNDCTL_SEQ_PERCMODE 0x40045106
#define TARGET_SNDCTL_SEQ_RESET 0x00005100
#define TARGET_SNDCTL_SEQ_RESETSAMPLES 0x40045109
#define TARGET_SNDCTL_SEQ_SYNC 0x00005101
#define TARGET_SNDCTL_SEQ_TESTMIDI 0x40045108
#define TARGET_SNDCTL_SEQ_THRESHOLD 0x4004510d
#define TARGET_SNDCTL_SEQ_TRESHOLD 0x4004510d
#define TARGET_SNDCTL_SYNTH_INFO 0xc08c5102
#define TARGET_SNDCTL_SYNTH_MEMAVL 0xc004510e
#define TARGET_SNDCTL_TMR_CONTINUE 0x00005404
#define TARGET_SNDCTL_TMR_METRONOME 0x40045407
#define TARGET_SNDCTL_TMR_SELECT 0x40045408
#define TARGET_SNDCTL_TMR_SOURCE 0xc0045406
#define TARGET_SNDCTL_TMR_START 0x00005402
#define TARGET_SNDCTL_TMR_STOP 0x00005403
#define TARGET_SNDCTL_TMR_TEMPO 0xc0045405
#define TARGET_SNDCTL_TMR_TIMEBASE 0xc0045401
#define TARGET_SOUND_PCM_READ_RATE 0x80045002
#define TARGET_SOUND_PCM_READ_CHANNELS 0x80045006
#define TARGET_SOUND_PCM_READ_BITS 0x80045005
#define TARGET_SOUND_PCM_READ_FILTER 0x80045007
#define TARGET_SOUND_MIXER_INFO TARGET_IOR ('M', 101, mixer_info)
#define TARGET_SOUND_MIXER_ACCESS 0xc0804d66
#define TARGET_SOUND_MIXER_PRIVATE1 TARGET_IOWR('M', 111, int)
#define TARGET_SOUND_MIXER_PRIVATE2 TARGET_IOWR('M', 112, int)
#define TARGET_SOUND_MIXER_PRIVATE3 TARGET_IOWR('M', 113, int)
#define TARGET_SOUND_MIXER_PRIVATE4 TARGET_IOWR('M', 114, int)
#define TARGET_SOUND_MIXER_PRIVATE5 TARGET_IOWR('M', 115, int)
#define TARGET_MIXER_READ(dev) TARGET_IOR('M', dev, int)
#define TARGET_SOUND_MIXER_READ_VOLUME TARGET_MIXER_READ(SOUND_MIXER_VOLUME)
#define TARGET_SOUND_MIXER_READ_BASS TARGET_MIXER_READ(SOUND_MIXER_BASS)
#define TARGET_SOUND_MIXER_READ_TREBLE TARGET_MIXER_READ(SOUND_MIXER_TREBLE)
#define TARGET_SOUND_MIXER_READ_SYNTH TARGET_MIXER_READ(SOUND_MIXER_SYNTH)
#define TARGET_SOUND_MIXER_READ_PCM TARGET_MIXER_READ(SOUND_MIXER_PCM)
#define TARGET_SOUND_MIXER_READ_SPEAKER TARGET_MIXER_READ(SOUND_MIXER_SPEAKER)
#define TARGET_SOUND_MIXER_READ_LINE TARGET_MIXER_READ(SOUND_MIXER_LINE)
#define TARGET_SOUND_MIXER_READ_MIC TARGET_MIXER_READ(SOUND_MIXER_MIC)
#define TARGET_SOUND_MIXER_READ_CD TARGET_MIXER_READ(SOUND_MIXER_CD)
#define TARGET_SOUND_MIXER_READ_IMIX TARGET_MIXER_READ(SOUND_MIXER_IMIX)
#define TARGET_SOUND_MIXER_READ_ALTPCM TARGET_MIXER_READ(SOUND_MIXER_ALTPCM)
#define TARGET_SOUND_MIXER_READ_RECLEV TARGET_MIXER_READ(SOUND_MIXER_RECLEV)
#define TARGET_SOUND_MIXER_READ_IGAIN TARGET_MIXER_READ(SOUND_MIXER_IGAIN)
#define TARGET_SOUND_MIXER_READ_OGAIN TARGET_MIXER_READ(SOUND_MIXER_OGAIN)
#define TARGET_SOUND_MIXER_READ_LINE1 TARGET_MIXER_READ(SOUND_MIXER_LINE1)
#define TARGET_SOUND_MIXER_READ_LINE2 TARGET_MIXER_READ(SOUND_MIXER_LINE2)
#define TARGET_SOUND_MIXER_READ_LINE3 TARGET_MIXER_READ(SOUND_MIXER_LINE3)
/* Obsolete macros */
#define TARGET_SOUND_MIXER_READ_MUTE TARGET_MIXER_READ(SOUND_MIXER_MUTE)
#define TARGET_SOUND_MIXER_READ_ENHANCE TARGET_MIXER_READ(SOUND_MIXER_ENHANCE)
#define TARGET_SOUND_MIXER_READ_LOUD TARGET_MIXER_READ(SOUND_MIXER_LOUD)
#define TARGET_SOUND_MIXER_READ_RECSRC TARGET_MIXER_READ(SOUND_MIXER_RECSRC)
#define TARGET_SOUND_MIXER_READ_DEVMASK TARGET_MIXER_READ(SOUND_MIXER_DEVMASK)
#define TARGET_SOUND_MIXER_READ_RECMASK TARGET_MIXER_READ(SOUND_MIXER_RECMASK)
#define TARGET_SOUND_MIXER_READ_STEREODEVS TARGET_MIXER_READ(SOUND_MIXER_STEREODEVS)
#define TARGET_SOUND_MIXER_READ_CAPS TARGET_MIXER_READ(SOUND_MIXER_CAPS)
#define TARGET_MIXER_WRITE(dev) TARGET_IOWR('M', dev, int)
#define TARGET_SOUND_MIXER_WRITE_VOLUME TARGET_MIXER_WRITE(SOUND_MIXER_VOLUME)
#define TARGET_SOUND_MIXER_WRITE_BASS TARGET_MIXER_WRITE(SOUND_MIXER_BASS)
#define TARGET_SOUND_MIXER_WRITE_TREBLE TARGET_MIXER_WRITE(SOUND_MIXER_TREBLE)
#define TARGET_SOUND_MIXER_WRITE_SYNTH TARGET_MIXER_WRITE(SOUND_MIXER_SYNTH)
#define TARGET_SOUND_MIXER_WRITE_PCM TARGET_MIXER_WRITE(SOUND_MIXER_PCM)
#define TARGET_SOUND_MIXER_WRITE_SPEAKER TARGET_MIXER_WRITE(SOUND_MIXER_SPEAKER)
#define TARGET_SOUND_MIXER_WRITE_LINE TARGET_MIXER_WRITE(SOUND_MIXER_LINE)
#define TARGET_SOUND_MIXER_WRITE_MIC TARGET_MIXER_WRITE(SOUND_MIXER_MIC)
#define TARGET_SOUND_MIXER_WRITE_CD TARGET_MIXER_WRITE(SOUND_MIXER_CD)
#define TARGET_SOUND_MIXER_WRITE_IMIX TARGET_MIXER_WRITE(SOUND_MIXER_IMIX)
#define TARGET_SOUND_MIXER_WRITE_ALTPCM TARGET_MIXER_WRITE(SOUND_MIXER_ALTPCM)
#define TARGET_SOUND_MIXER_WRITE_RECLEV TARGET_MIXER_WRITE(SOUND_MIXER_RECLEV)
#define TARGET_SOUND_MIXER_WRITE_IGAIN TARGET_MIXER_WRITE(SOUND_MIXER_IGAIN)
#define TARGET_SOUND_MIXER_WRITE_OGAIN TARGET_MIXER_WRITE(SOUND_MIXER_OGAIN)
#define TARGET_SOUND_MIXER_WRITE_LINE1 TARGET_MIXER_WRITE(SOUND_MIXER_LINE1)
#define TARGET_SOUND_MIXER_WRITE_LINE2 TARGET_MIXER_WRITE(SOUND_MIXER_LINE2)
#define TARGET_SOUND_MIXER_WRITE_LINE3 TARGET_MIXER_WRITE(SOUND_MIXER_LINE3)
/* Obsolete macros */
#define TARGET_SOUND_MIXER_WRITE_MUTE TARGET_MIXER_WRITE(SOUND_MIXER_MUTE)
#define TARGET_SOUND_MIXER_WRITE_ENHANCE TARGET_MIXER_WRITE(SOUND_MIXER_ENHANCE)
#define TARGET_SOUND_MIXER_WRITE_LOUD TARGET_MIXER_WRITE(SOUND_MIXER_LOUD)
#define TARGET_SOUND_MIXER_WRITE_RECSRC TARGET_MIXER_WRITE(SOUND_MIXER_RECSRC)
/* vfat ioctls */
#define TARGET_VFAT_IOCTL_READDIR_BOTH TARGET_IORU('r', 1)
#define TARGET_VFAT_IOCTL_READDIR_SHORT TARGET_IORU('r', 2)

View File

@@ -64,3 +64,15 @@ STRUCT(hd_geometry,
STRUCT(dirent,
TYPE_LONG, TYPE_LONG, TYPE_SHORT, MK_ARRAY(TYPE_CHAR, 256))
STRUCT(kbentry,
TYPE_CHAR, TYPE_CHAR, TYPE_SHORT)
STRUCT(audio_buf_info,
TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT)
STRUCT(count_info,
TYPE_INT, TYPE_INT, TYPE_INT)
STRUCT(mixer_info,
MK_ARRAY(TYPE_CHAR, 16), MK_ARRAY(TYPE_CHAR, 32), TYPE_INT, MK_ARRAY(TYPE_INT, 10))

477
linux-user/vm86.c Normal file
View File

@@ -0,0 +1,477 @@
/*
* vm86 linux syscall support
*
* Copyright (c) 2003 Fabrice Bellard
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include "qemu.h"
//#define DEBUG_VM86
#define set_flags(X,new,mask) \
((X) = ((X) & ~(mask)) | ((new) & (mask)))
#define SAFE_MASK (0xDD5)
#define RETURN_MASK (0xDFF)
static inline int is_revectored(int nr, struct target_revectored_struct *bitmap)
{
return (((uint8_t *)bitmap)[nr >> 3] >> (nr & 7)) & 1;
}
static inline void vm_putw(uint8_t *segptr, unsigned int reg16, unsigned int val)
{
stw(segptr + (reg16 & 0xffff), val);
}
static inline void vm_putl(uint8_t *segptr, unsigned int reg16, unsigned int val)
{
stl(segptr + (reg16 & 0xffff), val);
}
static inline unsigned int vm_getw(uint8_t *segptr, unsigned int reg16)
{
return lduw(segptr + (reg16 & 0xffff));
}
static inline unsigned int vm_getl(uint8_t *segptr, unsigned int reg16)
{
return ldl(segptr + (reg16 & 0xffff));
}
void save_v86_state(CPUX86State *env)
{
TaskState *ts = env->opaque;
/* put the VM86 registers in the userspace register structure */
ts->target_v86->regs.eax = tswap32(env->regs[R_EAX]);
ts->target_v86->regs.ebx = tswap32(env->regs[R_EBX]);
ts->target_v86->regs.ecx = tswap32(env->regs[R_ECX]);
ts->target_v86->regs.edx = tswap32(env->regs[R_EDX]);
ts->target_v86->regs.esi = tswap32(env->regs[R_ESI]);
ts->target_v86->regs.edi = tswap32(env->regs[R_EDI]);
ts->target_v86->regs.ebp = tswap32(env->regs[R_EBP]);
ts->target_v86->regs.esp = tswap32(env->regs[R_ESP]);
ts->target_v86->regs.eip = tswap32(env->eip);
ts->target_v86->regs.cs = tswap16(env->segs[R_CS].selector);
ts->target_v86->regs.ss = tswap16(env->segs[R_SS].selector);
ts->target_v86->regs.ds = tswap16(env->segs[R_DS].selector);
ts->target_v86->regs.es = tswap16(env->segs[R_ES].selector);
ts->target_v86->regs.fs = tswap16(env->segs[R_FS].selector);
ts->target_v86->regs.gs = tswap16(env->segs[R_GS].selector);
set_flags(env->eflags, ts->v86flags, VIF_MASK | ts->v86mask);
ts->target_v86->regs.eflags = tswap32(env->eflags);
#ifdef DEBUG_VM86
fprintf(logfile, "save_v86_state: eflags=%08x cs:ip=%04x:%04x\n",
env->eflags, env->segs[R_CS].selector, env->eip);
#endif
/* restore 32 bit registers */
env->regs[R_EAX] = ts->vm86_saved_regs.eax;
env->regs[R_EBX] = ts->vm86_saved_regs.ebx;
env->regs[R_ECX] = ts->vm86_saved_regs.ecx;
env->regs[R_EDX] = ts->vm86_saved_regs.edx;
env->regs[R_ESI] = ts->vm86_saved_regs.esi;
env->regs[R_EDI] = ts->vm86_saved_regs.edi;
env->regs[R_EBP] = ts->vm86_saved_regs.ebp;
env->regs[R_ESP] = ts->vm86_saved_regs.esp;
env->eflags = ts->vm86_saved_regs.eflags;
env->eip = ts->vm86_saved_regs.eip;
cpu_x86_load_seg(env, R_CS, ts->vm86_saved_regs.cs);
cpu_x86_load_seg(env, R_SS, ts->vm86_saved_regs.ss);
cpu_x86_load_seg(env, R_DS, ts->vm86_saved_regs.ds);
cpu_x86_load_seg(env, R_ES, ts->vm86_saved_regs.es);
cpu_x86_load_seg(env, R_FS, ts->vm86_saved_regs.fs);
cpu_x86_load_seg(env, R_GS, ts->vm86_saved_regs.gs);
}
/* return from vm86 mode to 32 bit. The vm86() syscall will return
'retval' */
static inline void return_to_32bit(CPUX86State *env, int retval)
{
#ifdef DEBUG_VM86
fprintf(logfile, "return_to_32bit: ret=0x%x\n", retval);
#endif
save_v86_state(env);
env->regs[R_EAX] = retval;
}
static inline int set_IF(CPUX86State *env)
{
TaskState *ts = env->opaque;
ts->v86flags |= VIF_MASK;
if (ts->v86flags & VIP_MASK) {
return_to_32bit(env, TARGET_VM86_STI);
return 1;
}
return 0;
}
static inline void clear_IF(CPUX86State *env)
{
TaskState *ts = env->opaque;
ts->v86flags &= ~VIF_MASK;
}
static inline void clear_TF(CPUX86State *env)
{
env->eflags &= ~TF_MASK;
}
static inline void clear_AC(CPUX86State *env)
{
env->eflags &= ~AC_MASK;
}
static inline int set_vflags_long(unsigned long eflags, CPUX86State *env)
{
TaskState *ts = env->opaque;
set_flags(ts->v86flags, eflags, ts->v86mask);
set_flags(env->eflags, eflags, SAFE_MASK);
if (eflags & IF_MASK)
return set_IF(env);
else
clear_IF(env);
return 0;
}
static inline int set_vflags_short(unsigned short flags, CPUX86State *env)
{
TaskState *ts = env->opaque;
set_flags(ts->v86flags, flags, ts->v86mask & 0xffff);
set_flags(env->eflags, flags, SAFE_MASK);
if (flags & IF_MASK)
return set_IF(env);
else
clear_IF(env);
return 0;
}
static inline unsigned int get_vflags(CPUX86State *env)
{
TaskState *ts = env->opaque;
unsigned int flags;
flags = env->eflags & RETURN_MASK;
if (ts->v86flags & VIF_MASK)
flags |= IF_MASK;
flags |= IOPL_MASK;
return flags | (ts->v86flags & ts->v86mask);
}
#define ADD16(reg, val) reg = (reg & ~0xffff) | ((reg + (val)) & 0xffff)
/* handle VM86 interrupt (NOTE: the CPU core currently does not
support TSS interrupt revectoring, so this code is always executed) */
static void do_int(CPUX86State *env, int intno)
{
TaskState *ts = env->opaque;
uint32_t *int_ptr, segoffs;
uint8_t *ssp;
unsigned int sp;
if (env->segs[R_CS].selector == TARGET_BIOSSEG)
goto cannot_handle;
if (is_revectored(intno, &ts->vm86plus.int_revectored))
goto cannot_handle;
if (intno == 0x21 && is_revectored((env->regs[R_EAX] >> 8) & 0xff,
&ts->vm86plus.int21_revectored))
goto cannot_handle;
int_ptr = (uint32_t *)(intno << 2);
segoffs = tswap32(*int_ptr);
if ((segoffs >> 16) == TARGET_BIOSSEG)
goto cannot_handle;
#if defined(DEBUG_VM86)
fprintf(logfile, "VM86: emulating int 0x%x. CS:IP=%04x:%04x\n",
intno, segoffs >> 16, segoffs & 0xffff);
#endif
/* save old state */
ssp = (uint8_t *)(env->segs[R_SS].selector << 4);
sp = env->regs[R_ESP] & 0xffff;
vm_putw(ssp, sp - 2, get_vflags(env));
vm_putw(ssp, sp - 4, env->segs[R_CS].selector);
vm_putw(ssp, sp - 6, env->eip);
ADD16(env->regs[R_ESP], -6);
/* goto interrupt handler */
env->eip = segoffs & 0xffff;
cpu_x86_load_seg(env, R_CS, segoffs >> 16);
clear_TF(env);
clear_IF(env);
clear_AC(env);
return;
cannot_handle:
#if defined(DEBUG_VM86)
fprintf(logfile, "VM86: return to 32 bits int 0x%x\n", intno);
#endif
return_to_32bit(env, TARGET_VM86_INTx | (intno << 8));
}
void handle_vm86_trap(CPUX86State *env, int trapno)
{
if (trapno == 1 || trapno == 3) {
return_to_32bit(env, TARGET_VM86_TRAP + (trapno << 8));
} else {
do_int(env, trapno);
}
}
#define CHECK_IF_IN_TRAP() \
if ((ts->vm86plus.vm86plus.flags & TARGET_vm86dbg_active) && \
(ts->vm86plus.vm86plus.flags & TARGET_vm86dbg_TFpendig)) \
newflags |= TF_MASK
#define VM86_FAULT_RETURN \
if ((ts->vm86plus.vm86plus.flags & TARGET_force_return_for_pic) && \
(ts->v86flags & (IF_MASK | VIF_MASK))) \
return_to_32bit(env, TARGET_VM86_PICRETURN); \
return
void handle_vm86_fault(CPUX86State *env)
{
TaskState *ts = env->opaque;
uint8_t *csp, *pc, *ssp;
unsigned int ip, sp, newflags, newip, newcs, opcode, intno;
int data32, pref_done;
csp = (uint8_t *)(env->segs[R_CS].selector << 4);
ip = env->eip & 0xffff;
pc = csp + ip;
ssp = (uint8_t *)(env->segs[R_SS].selector << 4);
sp = env->regs[R_ESP] & 0xffff;
#if defined(DEBUG_VM86)
fprintf(logfile, "VM86 exception %04x:%08x %02x %02x\n",
env->segs[R_CS].selector, env->eip, pc[0], pc[1]);
#endif
data32 = 0;
pref_done = 0;
do {
opcode = csp[ip];
ADD16(ip, 1);
switch (opcode) {
case 0x66: /* 32-bit data */ data32=1; break;
case 0x67: /* 32-bit address */ break;
case 0x2e: /* CS */ break;
case 0x3e: /* DS */ break;
case 0x26: /* ES */ break;
case 0x36: /* SS */ break;
case 0x65: /* GS */ break;
case 0x64: /* FS */ break;
case 0xf2: /* repnz */ break;
case 0xf3: /* rep */ break;
default: pref_done = 1;
}
} while (!pref_done);
/* VM86 mode */
switch(opcode) {
case 0x9c: /* pushf */
if (data32) {
vm_putl(ssp, sp - 4, get_vflags(env));
ADD16(env->regs[R_ESP], -4);
} else {
vm_putw(ssp, sp - 2, get_vflags(env));
ADD16(env->regs[R_ESP], -2);
}
env->eip = ip;
VM86_FAULT_RETURN;
case 0x9d: /* popf */
if (data32) {
newflags = vm_getl(ssp, sp);
ADD16(env->regs[R_ESP], 4);
} else {
newflags = vm_getw(ssp, sp);
ADD16(env->regs[R_ESP], 2);
}
env->eip = ip;
CHECK_IF_IN_TRAP();
if (data32) {
if (set_vflags_long(newflags, env))
return;
} else {
if (set_vflags_short(newflags, env))
return;
}
VM86_FAULT_RETURN;
case 0xcd: /* int */
intno = csp[ip];
ADD16(ip, 1);
env->eip = ip;
if (ts->vm86plus.vm86plus.flags & TARGET_vm86dbg_active) {
if ( (ts->vm86plus.vm86plus.vm86dbg_intxxtab[intno >> 3] >>
(intno &7)) & 1) {
return_to_32bit(env, TARGET_VM86_INTx + (intno << 8));
return;
}
}
do_int(env, intno);
break;
case 0xcf: /* iret */
if (data32) {
newip = vm_getl(ssp, sp) & 0xffff;
newcs = vm_getl(ssp, sp + 4) & 0xffff;
newflags = vm_getl(ssp, sp + 8);
ADD16(env->regs[R_ESP], 12);
} else {
newip = vm_getw(ssp, sp);
newcs = vm_getw(ssp, sp + 2);
newflags = vm_getw(ssp, sp + 4);
ADD16(env->regs[R_ESP], 6);
}
env->eip = newip;
cpu_x86_load_seg(env, R_CS, newcs);
CHECK_IF_IN_TRAP();
if (data32) {
if (set_vflags_long(newflags, env))
return;
} else {
if (set_vflags_short(newflags, env))
return;
}
VM86_FAULT_RETURN;
case 0xfa: /* cli */
env->eip = ip;
clear_IF(env);
VM86_FAULT_RETURN;
case 0xfb: /* sti */
env->eip = ip;
if (set_IF(env))
return;
VM86_FAULT_RETURN;
default:
/* real VM86 GPF exception */
return_to_32bit(env, TARGET_VM86_UNKNOWN);
break;
}
}
int do_vm86(CPUX86State *env, long subfunction,
struct target_vm86plus_struct * target_v86)
{
TaskState *ts = env->opaque;
int ret;
switch (subfunction) {
case TARGET_VM86_REQUEST_IRQ:
case TARGET_VM86_FREE_IRQ:
case TARGET_VM86_GET_IRQ_BITS:
case TARGET_VM86_GET_AND_RESET_IRQ:
gemu_log("qemu: unsupported vm86 subfunction (%ld)\n", subfunction);
ret = -EINVAL;
goto out;
case TARGET_VM86_PLUS_INSTALL_CHECK:
/* NOTE: on old vm86 stuff this will return the error
from verify_area(), because the subfunction is
interpreted as (invalid) address to vm86_struct.
So the installation check works.
*/
ret = 0;
goto out;
}
ts->target_v86 = target_v86;
/* save current CPU regs */
ts->vm86_saved_regs.eax = 0; /* default vm86 syscall return code */
ts->vm86_saved_regs.ebx = env->regs[R_EBX];
ts->vm86_saved_regs.ecx = env->regs[R_ECX];
ts->vm86_saved_regs.edx = env->regs[R_EDX];
ts->vm86_saved_regs.esi = env->regs[R_ESI];
ts->vm86_saved_regs.edi = env->regs[R_EDI];
ts->vm86_saved_regs.ebp = env->regs[R_EBP];
ts->vm86_saved_regs.esp = env->regs[R_ESP];
ts->vm86_saved_regs.eflags = env->eflags;
ts->vm86_saved_regs.eip = env->eip;
ts->vm86_saved_regs.cs = env->segs[R_CS].selector;
ts->vm86_saved_regs.ss = env->segs[R_SS].selector;
ts->vm86_saved_regs.ds = env->segs[R_DS].selector;
ts->vm86_saved_regs.es = env->segs[R_ES].selector;
ts->vm86_saved_regs.fs = env->segs[R_FS].selector;
ts->vm86_saved_regs.gs = env->segs[R_GS].selector;
/* build vm86 CPU state */
ts->v86flags = tswap32(target_v86->regs.eflags);
env->eflags = (env->eflags & ~SAFE_MASK) |
(tswap32(target_v86->regs.eflags) & SAFE_MASK) | VM_MASK;
ts->vm86plus.cpu_type = tswapl(target_v86->cpu_type);
switch (ts->vm86plus.cpu_type) {
case TARGET_CPU_286:
ts->v86mask = 0;
break;
case TARGET_CPU_386:
ts->v86mask = NT_MASK | IOPL_MASK;
break;
case TARGET_CPU_486:
ts->v86mask = AC_MASK | NT_MASK | IOPL_MASK;
break;
default:
ts->v86mask = ID_MASK | AC_MASK | NT_MASK | IOPL_MASK;
break;
}
env->regs[R_EBX] = tswap32(target_v86->regs.ebx);
env->regs[R_ECX] = tswap32(target_v86->regs.ecx);
env->regs[R_EDX] = tswap32(target_v86->regs.edx);
env->regs[R_ESI] = tswap32(target_v86->regs.esi);
env->regs[R_EDI] = tswap32(target_v86->regs.edi);
env->regs[R_EBP] = tswap32(target_v86->regs.ebp);
env->regs[R_ESP] = tswap32(target_v86->regs.esp);
env->eip = tswap32(target_v86->regs.eip);
cpu_x86_load_seg(env, R_CS, tswap16(target_v86->regs.cs));
cpu_x86_load_seg(env, R_SS, tswap16(target_v86->regs.ss));
cpu_x86_load_seg(env, R_DS, tswap16(target_v86->regs.ds));
cpu_x86_load_seg(env, R_ES, tswap16(target_v86->regs.es));
cpu_x86_load_seg(env, R_FS, tswap16(target_v86->regs.fs));
cpu_x86_load_seg(env, R_GS, tswap16(target_v86->regs.gs));
ret = tswap32(target_v86->regs.eax); /* eax will be restored at
the end of the syscall */
memcpy(&ts->vm86plus.int_revectored,
&target_v86->int_revectored, 32);
memcpy(&ts->vm86plus.int21_revectored,
&target_v86->int21_revectored, 32);
ts->vm86plus.vm86plus.flags = tswapl(target_v86->vm86plus.flags);
memcpy(&ts->vm86plus.vm86plus.vm86dbg_intxxtab,
target_v86->vm86plus.vm86dbg_intxxtab, 32);
#ifdef DEBUG_VM86
fprintf(logfile, "do_vm86: cs:ip=%04x:%04x\n",
env->segs[R_CS].selector, env->eip);
#endif
/* now the virtual CPU is ready for vm86 execution ! */
out:
return ret;
}

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)(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)(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)(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)(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

View File

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

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.

3232
ppc-dis.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,78 +1,143 @@
\input texinfo @c -*- texinfo -*-
@settitle QEMU x86 Emulator Reference Documentation
@iftex
@settitle QEMU CPU Emulator Reference Documentation
@titlepage
@sp 7
@center @titlefont{QEMU x86 Emulator Reference Documentation}
@center @titlefont{QEMU CPU Emulator Reference Documentation}
@sp 3
@end titlepage
@end iftex
@chapter Introduction
QEMU is an x86 processor emulator. Its purpose is to run x86 Linux
processes on non-x86 Linux architectures such as PowerPC or ARM. By
using dynamic translation it achieves a reasonnable speed while being
easy to port on new host CPUs. Its main goal is to be able to launch the
@code{Wine} Windows API emulator (@url{http://www.winehq.org}) on
non-x86 CPUs.
@section Features
QEMU features:
QEMU is a FAST! processor emulator. By using dynamic translation it
achieves a reasonnable speed while being easy to port on new host
CPUs.
QEMU has two operating modes:
@itemize @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
system, including a processor and various peripherials. Currently, it
is only used to launch an x86 Linux kernel on an x86 Linux system. It
enables easier testing and debugging of system code. It can also be
used to provide virtual hosting of several virtual PCs on a single
server.
@end itemize
As QEMU requires no host kernel patches to run, it is very safe and
easy to use.
QEMU generic features:
@itemize
@item User space only x86 emulator.
@item Currently ported on i386, PowerPC and S390.
@item User space only or full system emulation.
@item Using dynamic translation to native code for reasonnable speed.
@item The virtual x86 CPU supports 16 bit and 32 bit addressing with segmentation.
User space LDT and GDT are emulated. VM86 mode is also supported
(experimental).
@item Working on x86 and PowerPC hosts. Being tested on ARM, Sparc32, Alpha and S390.
@item Self-modifying code support.
@item Precise exceptions support.
@item The virtual CPU is a library (@code{libqemu}) which can be used
in other projects.
@end itemize
QEMU user mode emulation features:
@itemize
@item Generic Linux system call converter, including most ioctls.
@item clone() emulation using native CPU clone() to use Linux scheduler for threads.
@item Accurate signal handling by remapping host signals to virtual x86 signals.
@item Accurate signal handling by remapping host signals to target signals.
@end itemize
@end itemize
@item QEMU can emulate itself on x86 (experimental).
QEMU full system emulation features:
@itemize
@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
@item The virtual x86 CPU is a library (@code{libqemu}) which can be used
in other projects.
@section x86 emulation
QEMU x86 target features:
@itemize
@item The virtual x86 CPU supports 16 bit and 32 bit addressing with segmentation.
LDT/GDT and IDT are emulated. VM86 mode is also supported to run DOSEMU.
@item Support of host page sizes bigger than 4KB in user mode emulation.
@item QEMU can emulate itself on x86.
@item An extensive Linux x86 CPU test program is included @file{tests/test-i386}.
It can be used to test other x86 virtual CPUs.
@end itemize
Current QEMU Limitations:
Current QEMU limitations:
@itemize
@item Not all x86 exceptions are precise (yet). [Very few programs need that].
@item No support for self-modifying code (yet). [Very few programs need that, a notable exception is QEMU itself !].
@item No SSE/MMX support (yet).
@item No x86-64 support.
@item Some Linux syscalls are missing.
@item IPC syscalls are missing.
@item The x86 segment limits and access rights are not tested at every
memory access (and will never be to have good performances).
memory access.
@item On non x86 host CPUs, @code{double}s are used instead of the non standard
10 byte @code{long double}s of x86 for floating point emulation to get
maximum performances.
@item Some priviledged instructions or behaviors are missing, especially for segment protection testing (yet).
@end itemize
@chapter Invocation
@section ARM emulation
@itemize
@item ARM emulation can currently launch small programs while using the
generic dynamic code generation architecture of QEMU.
@item No FPU support (yet).
@item No automatic regression testing (yet).
@end itemize
@section SPARC emulation
The SPARC emulation is currently in development.
@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.
@@ -82,7 +147,7 @@ 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
@@ -91,7 +156,7 @@ qemu -L / /bin/ls
@item Since QEMU is also a linux process, you can launch qemu with qemu:
@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
@@ -105,21 +170,21 @@ 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
@section Wine launch (Currently only tested when emulating x86 on x86)
@section Wine launch
@itemize
@@ -128,7 +193,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
@@ -141,7 +206,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
@@ -149,41 +214,544 @@ 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 @samp
@table @option
@item -h
Print the help
@item -d
Activate log (logfile=/tmp/qemu.log)
@item -L path
Set the x86 elf interpreter prefix (default=/usr/local/qemu-i386)
@item -s size
Set the x86 stack size in bytes (default=524288)
@end table
Debug options:
@table @option
@item -d
Activate log (logfile=/tmp/qemu.log)
@item -p pagesize
Act as if the host page size was 'pagesize' bytes
@end table
@chapter QEMU 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
IDE disk interface (port=0x1f0, irq=14)
@item
NE2000 network adapter (port=0x300, irq=9)
@item
Serial port (port=0x3f8, irq=4)
@item
PIC (interrupt controler)
@item
PIT (timers)
@item
CMOS memory
@end itemize
@c man end
@section Quick Start
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{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{qemu-ifup} in @file{/etc} and configure
properly @code{sudo} so that the command @code{ifconfig} contained in
@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.
When network is enabled, there is a virtual network connection between
the host kernel and the emulated kernel. The emulated kernel is seen
from the host kernel at IP address 172.20.0.2 and the host kernel is
seen from the emulated kernel at IP address 172.20.0.1.
@item Launch @code{qemu.sh}. You should have the following output:
@example
> ./qemu.sh
connected to host network interface: tun0
Uncompressing Linux... Ok, booting the kernel.
Linux version 2.4.20 (fabrice@localhost.localdomain) (gcc version 2.96 20000731 (Red Hat Linux 7.3 2.96-110)) #22 lun jui 7 13:37:41 CEST 2003
BIOS-provided physical RAM map:
BIOS-e801: 0000000000000000 - 000000000009f000 (usable)
BIOS-e801: 0000000000100000 - 0000000002000000 (usable)
32MB LOWMEM available.
On node 0 totalpages: 8192
zone(0): 4096 pages.
zone(1): 4096 pages.
zone(2): 0 pages.
Kernel command line: root=/dev/hda ide1=noprobe ide2=noprobe ide3=noprobe ide4=noprobe ide5=noprobe
ide_setup: ide1=noprobe
ide_setup: ide2=noprobe
ide_setup: ide3=noprobe
ide_setup: ide4=noprobe
ide_setup: ide5=noprobe
Initializing CPU#0
Detected 501.285 MHz processor.
Calibrating delay loop... 989.59 BogoMIPS
Memory: 29268k/32768k available (907k kernel code, 3112k reserved, 212k data, 52k init, 0k highmem)
Dentry cache hash table entries: 4096 (order: 3, 32768 bytes)
Inode cache hash table entries: 2048 (order: 2, 16384 bytes)
Mount-cache hash table entries: 512 (order: 0, 4096 bytes)
Buffer-cache hash table entries: 1024 (order: 0, 4096 bytes)
Page-cache hash table entries: 8192 (order: 3, 32768 bytes)
CPU: Intel Pentium Pro stepping 03
Checking 'hlt' instruction... OK.
POSIX conformance testing by UNIFIX
Linux NET4.0 for Linux 2.4
Based upon Swansea University Computer Society NET3.039
Initializing RT netlink socket
apm: BIOS not found.
Starting kswapd
Journalled Block Device driver loaded
pty: 256 Unix98 ptys configured
Serial driver version 5.05c (2001-07-08) with no serial options enabled
ttyS00 at 0x03f8 (irq = 4) is a 16450
Uniform Multi-Platform E-IDE driver Revision: 6.31
ide: Assuming 50MHz system bus speed for PIO modes; override with idebus=xx
hda: QEMU HARDDISK, ATA DISK drive
ide0 at 0x1f0-0x1f7,0x3f6 on irq 14
hda: 12288 sectors (6 MB) w/256KiB Cache, CHS=12/16/63
Partition check:
hda: unknown partition table
ne.c:v1.10 9/23/94 Donald Becker (becker@scyld.com)
Last modified Nov 1, 2000 by Paul Gortmaker
NE*000 ethercard probe at 0x300: 52 54 00 12 34 56
eth0: NE2000 found at 0x300, using IRQ 9.
RAMDISK driver initialized: 16 RAM disks of 4096K size 1024 blocksize
NET4: Linux TCP/IP 1.0 for NET4.0
IP Protocols: ICMP, UDP, TCP, IGMP
IP: routing cache hash table of 512 buckets, 4Kbytes
TCP: Hash tables configured (established 2048 bind 4096)
NET4: Unix domain sockets 1.0/SMP for Linux NET4.0.
EXT2-fs warning: mounting unchecked fs, running e2fsck is recommended
VFS: Mounted root (ext2 filesystem).
Freeing unused kernel memory: 52k freed
sh: can't access tty; job control turned off
#
@end example
@item
Then you can play with the kernel inside the virtual serial console. You
can launch @code{ls} for example. Type @key{Ctrl-a h} to have an help
about the keys you can type inside the virtual serial console. In
particular, use @key{Ctrl-a x} to exit QEMU and use @key{Ctrl-a b} as
the Magic SysRq key.
@item
If the network is enabled, launch the script @file{/etc/linuxrc} in the
emulator (don't forget the leading dot):
@example
. /etc/linuxrc
@end example
Then enable X11 connections on your PC from the emulated Linux:
@example
xhost +172.20.0.2
@end example
You can now launch @file{xterm} or @file{xlogo} and verify that you have
a real Virtual Linux system !
@end enumerate
NOTES:
@enumerate
@item
A 2.5.74 kernel is also included in the archive. Just
replace the bzImage in qemu.sh to try it.
@item
vl 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 for vl, you can do a @emph{shutdown} inside
vl. vl will automatically exit when the Linux shutdown is done.
@item
You can boot slightly faster by disabling the probe of non present IDE
interfaces. To do so, add the following options on the kernel command
line:
@example
ide1=noprobe ide2=noprobe ide3=noprobe ide4=noprobe ide5=noprobe
@end example
@item
The example disk image is a modified version of the one made by Kevin
Lawton for the plex86 Project (@url{www.plex86.org}).
@end enumerate
@section Invocation
@example
@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 image image for IDE hard disk 0.
General options:
@table @option
@item -hda file
@item -hdb file
Use @var{file} as hard disk 0 or 1 image (@xref{disk_images}).
@item -snapshot
Write to temporary files instead of disk image files. In this case,
the raw disk image you use is not written back. You can however force
the write back by pressing @key{C-a s} (@xref{disk_images}).
@item -m megs
Set virtual RAM size to @var{megs} megabytes.
@item -n script
Set network init script [default=/etc/vl-ifup]. This script is
launched to configure the host network interface (usually tun0)
corresponding to the virtual NE2000 card.
@item -initrd file
Use @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/vl.log
@end table
During emulation, use @key{C-a h} to get terminal commands:
@table @key
@item C-a h
Print this help
@item C-a x
Exit emulatior
@item C-a s
Save disk data back to file (if -snapshot)
@item C-a b
Send break (magic sysrq)
@item C-a C-a
Send C-a
@end table
@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
by
@example
#define __PAGE_OFFSET (0x90000000)
@end example
And in @file{arch/i386/vmlinux.lds}, replace
@example
. = 0xc0000000 + 0x100000;
@end example
by
@example
. = 0x90000000 + 0x100000;
@end example
@item
If you want to enable SMP (Symmetric Multi-Processing) support, you
must make the following change in @file{include/asm/fixmap.h}. Replace
@example
#define FIXADDR_TOP (0xffffX000UL)
@end example
by
@example
#define FIXADDR_TOP (0xa7ffX000UL)
@end example
(X is 'e' or 'f' depending on the kernel version). Although you can
use an SMP kernel with QEMU, it only supports one CPU.
@item
If you are not using a 2.5 kernel as host kernel but if you use a target
2.5 kernel, you must also ensure that the 'HZ' define is set to 100
(1000 is the default) as QEMU cannot currently emulate timers at
frequencies greater than 100 Hz on host Linux systems < 2.5. In
@file{include/asm/param.h}, replace:
@example
# define HZ 1000 /* Internal kernel timer frequency */
@end example
by
@example
# define HZ 100 /* Internal kernel timer frequency */
@end example
@end enumerate
The file config-2.x.x gives the configuration of the example kernels.
Just type
@example
make bzImage
@end example
As you would do to make a real kernel. Then you can use with QEMU
exactly the same kernel as you would boot on your PC (in
@file{arch/i386/boot/bzImage}).
@node gdb_usage
@section GDB usage
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.
In order to use gdb, launch vl with the '-s' option. It will wait for a
gdb connection:
@example
> vl -s arch/i386/boot/bzImage -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
Use @code{info reg} to display all the CPU registers.
@item
Use @code{x/10i $eip} to display the code at the PC position.
@item
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
@section QEMU compared to other emulators
Unlike bochs [3], QEMU emulates only a user space x86 CPU. It means that
you cannot launch an operating system with it. The benefit is that it is
simpler and faster due to the fact that some of the low level CPU state
can be ignored (in particular, no virtual memory needs to be emulated).
Like bochs [3], QEMU emulates an x86 CPU. But QEMU is much faster than
bochs as it uses dynamic compilation and because it uses the host MMU to
simulate the x86 MMU. The downside is that currently the emulation is
not as accurate as bochs (for example, you cannot currently run Windows
inside QEMU).
Like Valgrind [2], QEMU does user space emulation and dynamic
translation. Valgrind is mainly a memory debugger while QEMU has no
support for it (QEMU could be used to detect out of bound memory accesses
as Valgrind, but it has no support to track uninitialised data as
Valgrind does). Valgrind dynamic translator generates better code than
QEMU (in particular it does register allocation) but it is closely tied
to an x86 host.
support for it (QEMU could be used to detect out of bound memory
accesses as Valgrind, but it has no support to track uninitialised data
as Valgrind does). The Valgrind dynamic translator generates better code
than QEMU (in particular it does register allocation) but it is closely
tied to an x86 host and target and has no support for precise exceptions
and system emulation.
EM86 [4] is the closest project to QEMU (and QEMU still uses some of its
code, in particular the ELF file loader). EM86 was limited to an alpha
host and used a proprietary and slow interpreter (the interpreter part
of the FX!32 Digital Win32 code translator [5]).
EM86 [4] is the closest project to user space QEMU (and QEMU still uses
some of its code, in particular the ELF file loader). EM86 was limited
to an alpha host and used a proprietary and slow interpreter (the
interpreter part of the FX!32 Digital Win32 code translator [5]).
TWIN [6] is a Windows API emulator like Wine. It is less accurate than
Wine but includes a protected mode x86 interpreter to launch x86 Windows
@@ -192,11 +760,25 @@ Windows API is executed natively but it is far more difficult to develop
because all the data structures and function parameters exchanged
between the API and the x86 code must be converted.
User mode Linux [7] was the only solution before QEMU to launch a Linux
kernel as a process while not needing any host kernel patches. However,
user mode Linux requires heavy kernel patches while QEMU accepts
unpatched Linux kernels. It would be interesting to compare the
performance of the two approaches.
The new Plex86 [8] PC virtualizer is done in the same spirit as the QEMU
system emulator. It requires a patched Linux kernel to work (you cannot
launch the same kernel on your PC), but the patches are really small. As
it is a PC virtualizer (no emulation is done except for some priveledged
instructions), it has the potential of being faster than QEMU. The
downside is that a complicated (and potentially unsafe) host kernel
patch is needed.
@section Portable dynamic translation
QEMU is a dynamic translator. When it first encounters a piece of code,
it converts it to the host instruction set. Usually dynamic translators
are very complicated and highly CPU dependant. QEMU uses some tricks
are very complicated and highly CPU dependent. QEMU uses some tricks
which make it relatively easily portable and simple while achieving good
performances.
@@ -265,17 +847,59 @@ contains just a single basic block (a block of x86 instructions
terminated by a jump or by a virtual CPU state change which the
translator cannot deduce statically).
[Currently, the translated code is not patched if it jumps to another
translated code].
@section Direct block chaining
After each translated basic block is executed, QEMU uses the simulated
Program Counter (PC) and other cpu state informations (such as the CS
segment base value) to find the next basic block.
In order to accelerate the most common cases where the new simulated PC
is known, QEMU can patch a basic block so that it jumps directly to the
next one.
The most portable code uses an indirect jump. An indirect jump makes it
easier to make the jump target modification atomic. On some
architectures (such as PowerPC), the @code{JUMP} opcode is directly
patched so that the block chaining has no overhead.
@section Self-modifying code and translated code invalidation
Self-modifying code is a special challenge in x86 emulation because no
instruction cache invalidation is signaled by the application when code
is modified.
When translated code is generated for a basic block, the corresponding
host page is write protected if it is not already read-only (with the
system call @code{mprotect()}). Then, if a write access is done to the
page, Linux raises a SEGV signal. QEMU then invalidates all the
translated code in the page and enables write accesses to the page.
Correct translated code invalidation is done efficiently by maintaining
a linked list of every translated block contained in a given page. Other
linked lists are also maintained to undo direct block chaining.
Although the overhead of doing @code{mprotect()} calls is important,
most MSDOS programs can be emulated at reasonnable speed with QEMU and
DOSEMU.
Note that QEMU also invalidates pages of translated code when it detects
that memory mappings are modified with @code{mmap()} or @code{munmap()}.
@section Exception support
longjmp() is used when an exception such as division by zero is
encountered. The host SIGSEGV and SIGBUS signal handlers are used to get
invalid memory accesses.
encountered.
[Currently, the virtual CPU cannot retrieve the exact CPU state in some
exceptions, although it could except for the @code{EFLAGS} register].
The host SIGSEGV and SIGBUS signal handlers are used to get invalid
memory accesses. The exact CPU state can be retrieved because all the
x86 registers are stored in fixed host registers. The simulated program
counter is found by retranslating the corresponding basic block and by
looking where the host program counter was at the exception point.
The virtual CPU cannot retrieve the exact @code{EFLAGS} register because
in some cases it is not computed because of condition code
optimisations. It is not a big concern because the emulated code can
still be restarted in any cases.
@section Linux system call translation
@@ -284,6 +908,11 @@ the parameters of the system calls can be converted to fix the
endianness and 32/64 bit issues. The IOCTLs are converted with a generic
type description system (see @file{ioctls.h} and @file{thunk.c}).
QEMU supports host CPUs which have pages bigger than 4KB. It records all
the mappings the process does and try to emulated the @code{mmap()}
system calls in cases where the host @code{mmap()} call would fail
because of bad page alignment.
@section Linux signals
Normal and real-time signals are queued along with their information
@@ -312,20 +941,30 @@ thread.
The virtual x86 CPU atomic operations are emulated with a global lock so
that their semantic is preserved.
Note that currently there are still some locking issues in QEMU. In
particular, the translated cache flush is not protected yet against
reentrancy.
@section Self-virtualization
QEMU was conceived so that ultimately it can emulate itself. Althought
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.
Achieving self-virtualization is not easy because there may be address
space conflicts. QEMU solves this problem by being an ELF shared object
as the ld-linux.so ELF interpreter. That way, it can be relocated at
load time.
space conflicts. QEMU solves this problem by being an executable ELF
shared object as the ld-linux.so ELF interpreter. That way, it can be
relocated at load time.
Since self-modifying code is not supported yet, QEMU cannot self
virtualize itself in case of translation cache flush. This limitation
will be suppressed soon.
@section MMU emulation
For system emulation, QEMU uses the mmap() system call to emulate the
target CPU MMU. It works as long the emulated OS does not use an area
reserved by the host OS (such as the area above 0xc0000000 on x86
Linux).
It is planned to add a slower but more precise MMU emulation
with a software MMU.
@section Bibliography
@@ -357,18 +996,21 @@ Chernoff and Ray Hookway.
@url{http://www.willows.com/}, Windows API library emulation from
Willows Software.
@item [7]
@url{http://user-mode-linux.sourceforge.net/},
The User-mode Linux Kernel.
@item [8]
@url{http://www.plex86.org/},
The new Plex86 project.
@end table
@chapter Regression Tests
In the directory @file{tests/}, various interesting x86 testing programs
In the directory @file{tests/}, various interesting testing programs
are available. There are used for regression testing.
@section @file{hello}
Very simple statically linked x86 program, just to test QEMU during a
port to a new host CPU.
@section @file{test-i386}
This program executes most of the 16 bit and 32 bit x86 instructions and
@@ -379,19 +1021,26 @@ program and a @code{diff} on the generated output.
The Linux system call @code{modify_ldt()} is used to create x86 selectors
to test some 16 bit addressing and 32 bit with segmentation cases.
@section @file{testsig}
The Linux system call @code{vm86()} is used to test vm86 emulation.
This program tests various signal cases, including SIGFPE, SIGSEGV and
SIGILL.
Various exceptions are raised to test most of the x86 user space
exception reporting.
@section @file{testclone}
@section @file{linux-test}
Tests the @code{clone()} system call (basic 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{testthread}
@section @file{hello-i386}
Tests the glibc threads (more complicated than @code{clone()} because signals
are also used).
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}
@@ -399,9 +1048,3 @@ It is a simple benchmark. Care must be taken to interpret the results
because it mostly tests the ability of the virtual CPU to optimize the
@code{rol} x86 instruction and the condition code computations.
@section @file{runcom}
A very simple MSDOS emulator to test the Linux vm86() system call
emulation. The excellent 54 byte @file{pi_10.com} PI number calculator
can be launched with it. @file{pi_10.com} was written by Bertram
Felgenhauer (more information at @url{http://www.boo.net/~jasonp/pipage.html}).

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;
}

204
s390.ld Normal file
View File

@@ -0,0 +1,204 @@
OUTPUT_FORMAT("elf32-s390", "elf32-s390",
"elf32-s390")
OUTPUT_ARCH(s390:31-bit)
ENTRY(_start)
SEARCH_DIR("/usr/s390-redhat-linux/lib"); SEARCH_DIR("/usr/lib"); SEARCH_DIR("/usr/local/lib"); SEARCH_DIR("/lib");
/* Do we need any of these for elf?
__DYNAMIC = 0; */
SECTIONS
{
/* Read-only sections, merged into text segment: */
. = 0x60000000 + SIZEOF_HEADERS;
.interp : { *(.interp) }
.hash : { *(.hash) }
.dynsym : { *(.dynsym) }
.dynstr : { *(.dynstr) }
.gnu.version : { *(.gnu.version) }
.gnu.version_d : { *(.gnu.version_d) }
.gnu.version_r : { *(.gnu.version_r) }
.rel.dyn :
{
*(.rel.init)
*(.rel.text .rel.text.* .rel.gnu.linkonce.t.*)
*(.rel.fini)
*(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*)
*(.rel.data .rel.data.* .rel.gnu.linkonce.d.*)
*(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*)
*(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*)
*(.rel.ctors)
*(.rel.dtors)
*(.rel.got)
*(.rel.sdata .rel.sdata.* .rel.gnu.linkonce.s.*)
*(.rel.sbss .rel.sbss.* .rel.gnu.linkonce.sb.*)
*(.rel.sdata2 .rel.sdata2.* .rel.gnu.linkonce.s2.*)
*(.rel.sbss2 .rel.sbss2.* .rel.gnu.linkonce.sb2.*)
*(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*)
}
.rela.dyn :
{
*(.rela.init)
*(.rela.text .rela.text.* .rela.gnu.linkonce.t.*)
*(.rela.fini)
*(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*)
*(.rela.data .rela.data.* .rela.gnu.linkonce.d.*)
*(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*)
*(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*)
*(.rela.ctors)
*(.rela.dtors)
*(.rela.got)
*(.rela.sdata .rela.sdata.* .rela.gnu.linkonce.s.*)
*(.rela.sbss .rela.sbss.* .rela.gnu.linkonce.sb.*)
*(.rela.sdata2 .rela.sdata2.* .rela.gnu.linkonce.s2.*)
*(.rela.sbss2 .rela.sbss2.* .rela.gnu.linkonce.sb2.*)
*(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*)
}
.rel.plt : { *(.rel.plt) }
.rela.plt : { *(.rela.plt) }
.init :
{
KEEP (*(.init))
} =0x07070707
.plt : { *(.plt) }
.text :
{
*(.text .stub .text.* .gnu.linkonce.t.*)
/* .gnu.warning sections are handled specially by elf32.em. */
*(.gnu.warning)
} =0x07070707
.fini :
{
KEEP (*(.fini))
} =0x07070707
PROVIDE (__etext = .);
PROVIDE (_etext = .);
PROVIDE (etext = .);
.rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
.rodata1 : { *(.rodata1) }
.sdata2 : { *(.sdata2 .sdata2.* .gnu.linkonce.s2.*) }
.sbss2 : { *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*) }
.eh_frame_hdr : { *(.eh_frame_hdr) }
/* Adjust the address for the data segment. We want to adjust up to
the same address within the page on the next page up. */
. = ALIGN(0x1000) + (. & (0x1000 - 1));
/* Ensure the __preinit_array_start label is properly aligned. We
could instead move the label definition inside the section, but
the linker would then create the section even if it turns out to
be empty, which isn't pretty. */
. = ALIGN(32 / 8);
PROVIDE (__preinit_array_start = .);
.preinit_array : { *(.preinit_array) }
PROVIDE (__preinit_array_end = .);
PROVIDE (__init_array_start = .);
.init_array : { *(.init_array) }
PROVIDE (__init_array_end = .);
PROVIDE (__fini_array_start = .);
.fini_array : { *(.fini_array) }
PROVIDE (__fini_array_end = .);
.data :
{
*(.data .data.* .gnu.linkonce.d.*)
SORT(CONSTRUCTORS)
}
.data1 : { *(.data1) }
.tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) }
.tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
.eh_frame : { KEEP (*(.eh_frame)) }
.gcc_except_table : { *(.gcc_except_table) }
.dynamic : { *(.dynamic) }
.ctors :
{
/* gcc uses crtbegin.o to find the start of
the constructors, so we make sure it is
first. Because this is a wildcard, it
doesn't matter if the user does not
actually link against crtbegin.o; the
linker won't look for a file to match a
wildcard. The wildcard also means that it
doesn't matter which directory crtbegin.o
is in. */
KEEP (*crtbegin.o(.ctors))
/* We don't want to include the .ctor section from
from the crtend.o file until after the sorted ctors.
The .ctor section from the crtend file contains the
end of ctors marker and it must be last */
KEEP (*(EXCLUDE_FILE (*crtend.o ) .ctors))
KEEP (*(SORT(.ctors.*)))
KEEP (*(.ctors))
}
.dtors :
{
KEEP (*crtbegin.o(.dtors))
KEEP (*(EXCLUDE_FILE (*crtend.o ) .dtors))
KEEP (*(SORT(.dtors.*)))
KEEP (*(.dtors))
}
.jcr : { KEEP (*(.jcr)) }
.got : { *(.got.plt) *(.got) }
/* We want the small data sections together, so single-instruction offsets
can access them all, and initialized data all before uninitialized, so
we can shorten the on-disk segment size. */
.sdata :
{
*(.sdata .sdata.* .gnu.linkonce.s.*)
}
_edata = .;
PROVIDE (edata = .);
__bss_start = .;
.sbss :
{
PROVIDE (__sbss_start = .);
PROVIDE (___sbss_start = .);
*(.dynsbss)
*(.sbss .sbss.* .gnu.linkonce.sb.*)
*(.scommon)
PROVIDE (__sbss_end = .);
PROVIDE (___sbss_end = .);
}
.bss :
{
*(.dynbss)
*(.bss .bss.* .gnu.linkonce.b.*)
*(COMMON)
/* Align here to ensure that the .bss section occupies space up to
_end. Align after .bss to ensure correct alignment even if the
.bss section disappears because there are no input sections. */
. = ALIGN(32 / 8);
}
. = ALIGN(32 / 8);
_end = .;
PROVIDE (end = .);
/* Stabs debugging sections. */
.stab 0 : { *(.stab) }
.stabstr 0 : { *(.stabstr) }
.stab.excl 0 : { *(.stab.excl) }
.stab.exclstr 0 : { *(.stab.exclstr) }
.stab.index 0 : { *(.stab.index) }
.stab.indexstr 0 : { *(.stab.indexstr) }
.comment 0 : { *(.comment) }
/* DWARF debug sections.
Symbols in the DWARF debugging sections are relative to the beginning
of the section so we begin them at 0. */
/* DWARF 1 */
.debug 0 : { *(.debug) }
.line 0 : { *(.line) }
/* GNU DWARF 1 extensions */
.debug_srcinfo 0 : { *(.debug_srcinfo) }
.debug_sfnames 0 : { *(.debug_sfnames) }
/* DWARF 1.1 and DWARF 2 */
.debug_aranges 0 : { *(.debug_aranges) }
.debug_pubnames 0 : { *(.debug_pubnames) }
/* DWARF 2 */
.debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
.debug_abbrev 0 : { *(.debug_abbrev) }
.debug_line 0 : { *(.debug_line) }
.debug_frame 0 : { *(.debug_frame) }
.debug_str 0 : { *(.debug_str) }
.debug_loc 0 : { *(.debug_loc) }
.debug_macinfo 0 : { *(.debug_macinfo) }
/* SGI/MIPS DWARF 2 extensions */
.debug_weaknames 0 : { *(.debug_weaknames) }
.debug_funcnames 0 : { *(.debug_funcnames) }
.debug_typenames 0 : { *(.debug_typenames) }
.debug_varnames 0 : { *(.debug_varnames) }
}

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 int 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_read[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_read[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

3214
sparc-dis.c Normal file

File diff suppressed because it is too large Load Diff

128
sparc.ld Normal file
View File

@@ -0,0 +1,128 @@
OUTPUT_FORMAT("elf32-sparc", "elf32-sparc",
"elf32-sparc")
OUTPUT_ARCH(sparc)
SEARCH_DIR(/lib); SEARCH_DIR(/usr/lib); SEARCH_DIR(/usr/local/lib); SEARCH_DIR(/usr/alpha-unknown-linux-gnu/lib);
ENTRY(_start)
SECTIONS
{
/* Read-only sections, merged into text segment: */
. = 0x60000000 + SIZEOF_HEADERS;
.interp : { *(.interp) }
.hash : { *(.hash) }
.dynsym : { *(.dynsym) }
.dynstr : { *(.dynstr) }
.gnu.version : { *(.gnu.version) }
.gnu.version_d : { *(.gnu.version_d) }
.gnu.version_r : { *(.gnu.version_r) }
.rel.text :
{ *(.rel.text) *(.rel.gnu.linkonce.t*) }
.rela.text :
{ *(.rela.text) *(.rela.gnu.linkonce.t*) }
.rel.data :
{ *(.rel.data) *(.rel.gnu.linkonce.d*) }
.rela.data :
{ *(.rela.data) *(.rela.gnu.linkonce.d*) }
.rel.rodata :
{ *(.rel.rodata) *(.rel.gnu.linkonce.r*) }
.rela.rodata :
{ *(.rela.rodata) *(.rela.gnu.linkonce.r*) }
.rel.got : { *(.rel.got) }
.rela.got : { *(.rela.got) }
.rel.ctors : { *(.rel.ctors) }
.rela.ctors : { *(.rela.ctors) }
.rel.dtors : { *(.rel.dtors) }
.rela.dtors : { *(.rela.dtors) }
.rel.init : { *(.rel.init) }
.rela.init : { *(.rela.init) }
.rel.fini : { *(.rel.fini) }
.rela.fini : { *(.rela.fini) }
.rel.bss : { *(.rel.bss) }
.rela.bss : { *(.rela.bss) }
.rel.plt : { *(.rel.plt) }
.rela.plt : { *(.rela.plt) }
.init : { *(.init) } =0x47ff041f
.text :
{
*(.text)
/* .gnu.warning sections are handled specially by elf32.em. */
*(.gnu.warning)
*(.gnu.linkonce.t*)
} =0x47ff041f
_etext = .;
PROVIDE (etext = .);
.fini : { *(.fini) } =0x47ff041f
.rodata : { *(.rodata) *(.gnu.linkonce.r*) }
.rodata1 : { *(.rodata1) }
.reginfo : { *(.reginfo) }
/* Adjust the address for the data segment. We want to adjust up to
the same address within the page on the next page up. */
. = ALIGN(0x100000) + (. & (0x100000 - 1));
.data :
{
*(.data)
*(.gnu.linkonce.d*)
CONSTRUCTORS
}
.data1 : { *(.data1) }
.ctors :
{
*(.ctors)
}
.dtors :
{
*(.dtors)
}
.plt : { *(.plt) }
.got : { *(.got.plt) *(.got) }
.dynamic : { *(.dynamic) }
/* We want the small data sections together, so single-instruction offsets
can access them all, and initialized data all before uninitialized, so
we can shorten the on-disk segment size. */
.sdata : { *(.sdata) }
_edata = .;
PROVIDE (edata = .);
__bss_start = .;
.sbss : { *(.sbss) *(.scommon) }
.bss :
{
*(.dynbss)
*(.bss)
*(COMMON)
}
_end = . ;
PROVIDE (end = .);
/* Stabs debugging sections. */
.stab 0 : { *(.stab) }
.stabstr 0 : { *(.stabstr) }
.stab.excl 0 : { *(.stab.excl) }
.stab.exclstr 0 : { *(.stab.exclstr) }
.stab.index 0 : { *(.stab.index) }
.stab.indexstr 0 : { *(.stab.indexstr) }
.comment 0 : { *(.comment) }
/* DWARF debug sections.
Symbols in the DWARF debugging sections are relative to the beginning
of the section so we begin them at 0. */
/* DWARF 1 */
.debug 0 : { *(.debug) }
.line 0 : { *(.line) }
/* GNU DWARF 1 extensions */
.debug_srcinfo 0 : { *(.debug_srcinfo) }
.debug_sfnames 0 : { *(.debug_sfnames) }
/* DWARF 1.1 and DWARF 2 */
.debug_aranges 0 : { *(.debug_aranges) }
.debug_pubnames 0 : { *(.debug_pubnames) }
/* DWARF 2 */
.debug_info 0 : { *(.debug_info) }
.debug_abbrev 0 : { *(.debug_abbrev) }
.debug_line 0 : { *(.debug_line) }
.debug_frame 0 : { *(.debug_frame) }
.debug_str 0 : { *(.debug_str) }
.debug_loc 0 : { *(.debug_loc) }
.debug_macinfo 0 : { *(.debug_macinfo) }
/* SGI/MIPS DWARF 2 extensions */
.debug_weaknames 0 : { *(.debug_weaknames) }
.debug_funcnames 0 : { *(.debug_funcnames) }
.debug_typenames 0 : { *(.debug_typenames) }
.debug_varnames 0 : { *(.debug_varnames) }
/* These must appear regardless of . */
}

File diff suppressed because it is too large Load Diff

63
target-arm/cpu.h Normal file
View File

@@ -0,0 +1,63 @@
/*
* ARM virtual CPU header
*
* Copyright (c) 2003 Fabrice Bellard
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef CPU_ARM_H
#define CPU_ARM_H
#include "cpu-defs.h"
#define EXCP_UDEF 1 /* undefined instruction */
#define EXCP_SWI 2 /* software interrupt */
typedef struct CPUARMState {
uint32_t regs[16];
uint32_t cpsr;
/* cpsr flag cache for faster execution */
uint32_t CF; /* 0 or 1 */
uint32_t VF; /* V is the bit 31. All other bits are undefined */
uint32_t NZF; /* N is bit 31. Z is computed from NZF */
/* exception/interrupt handling */
jmp_buf jmp_env;
int exception_index;
int interrupt_request;
struct TranslationBlock *current_tb;
int user_mode_only;
/* user data */
void *opaque;
} CPUARMState;
CPUARMState *cpu_arm_init(void);
int cpu_arm_exec(CPUARMState *s);
void cpu_arm_close(CPUARMState *s);
/* you can call this signal handler from your SIGBUS and SIGSEGV
signal handlers to inform the virtual CPU of exceptions. non zero
is returned if the signal was handled by the virtual CPU. */
struct siginfo;
int cpu_arm_signal_handler(int host_signum, struct siginfo *info,
void *puc);
void cpu_arm_dump_state(CPUARMState *env, FILE *f, int flags);
#define TARGET_PAGE_BITS 12
#include "cpu-all.h"
#endif

40
target-arm/exec.h Normal file
View File

@@ -0,0 +1,40 @@
/*
* ARM execution defines
*
* Copyright (c) 2003 Fabrice Bellard
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "dyngen-exec.h"
register struct CPUARMState *env asm(AREG0);
register uint32_t T0 asm(AREG1);
register uint32_t T1 asm(AREG2);
register uint32_t T2 asm(AREG3);
#include "cpu.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);
}

673
target-arm/op.c Normal file
View File

@@ -0,0 +1,673 @@
/*
* ARM micro operations
*
* Copyright (c) 2003 Fabrice Bellard
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "exec.h"
#define REGNAME r0
#define REG (env->regs[0])
#include "op_template.h"
#define REGNAME r1
#define REG (env->regs[1])
#include "op_template.h"
#define REGNAME r2
#define REG (env->regs[2])
#include "op_template.h"
#define REGNAME r3
#define REG (env->regs[3])
#include "op_template.h"
#define REGNAME r4
#define REG (env->regs[4])
#include "op_template.h"
#define REGNAME r5
#define REG (env->regs[5])
#include "op_template.h"
#define REGNAME r6
#define REG (env->regs[6])
#include "op_template.h"
#define REGNAME r7
#define REG (env->regs[7])
#include "op_template.h"
#define REGNAME r8
#define REG (env->regs[8])
#include "op_template.h"
#define REGNAME r9
#define REG (env->regs[9])
#include "op_template.h"
#define REGNAME r10
#define REG (env->regs[10])
#include "op_template.h"
#define REGNAME r11
#define REG (env->regs[11])
#include "op_template.h"
#define REGNAME r12
#define REG (env->regs[12])
#include "op_template.h"
#define REGNAME r13
#define REG (env->regs[13])
#include "op_template.h"
#define REGNAME r14
#define REG (env->regs[14])
#include "op_template.h"
#define REGNAME r15
#define REG (env->regs[15])
#include "op_template.h"
void OPPROTO op_movl_T0_0(void)
{
T0 = 0;
}
void OPPROTO op_movl_T0_im(void)
{
T0 = PARAM1;
}
void OPPROTO op_movl_T1_im(void)
{
T1 = PARAM1;
}
void OPPROTO op_movl_T2_im(void)
{
T2 = PARAM1;
}
void OPPROTO op_addl_T1_im(void)
{
T1 += PARAM1;
}
void OPPROTO op_addl_T1_T2(void)
{
T1 += T2;
}
void OPPROTO op_subl_T1_T2(void)
{
T1 -= T2;
}
void OPPROTO op_addl_T0_T1(void)
{
T0 += T1;
}
void OPPROTO op_addl_T0_T1_cc(void)
{
unsigned int src1;
src1 = T0;
T0 += T1;
env->NZF = T0;
env->CF = T0 < src1;
env->VF = (src1 ^ T1 ^ -1) & (src1 ^ T0);
}
void OPPROTO op_adcl_T0_T1(void)
{
T0 += T1 + env->CF;
}
void OPPROTO op_adcl_T0_T1_cc(void)
{
unsigned int src1;
src1 = T0;
if (!env->CF) {
T0 += T1;
env->CF = T0 < src1;
} else {
T0 += T1 + 1;
env->CF = T0 <= src1;
}
env->VF = (src1 ^ T1 ^ -1) & (src1 ^ T0);
env->NZF = T0;
FORCE_RET();
}
#define OPSUB(sub, sbc, res, T0, T1) \
\
void OPPROTO op_ ## sub ## l_T0_T1(void) \
{ \
res = T0 - T1; \
} \
\
void OPPROTO op_ ## sub ## l_T0_T1_cc(void) \
{ \
unsigned int src1; \
src1 = T0; \
T0 -= T1; \
env->NZF = T0; \
env->CF = src1 >= T1; \
env->VF = (src1 ^ T1) & (src1 ^ T0); \
res = T0; \
} \
\
void OPPROTO op_ ## sbc ## l_T0_T1(void) \
{ \
res = T0 - T1 + env->CF - 1; \
} \
\
void OPPROTO op_ ## sbc ## l_T0_T1_cc(void) \
{ \
unsigned int src1; \
src1 = T0; \
if (!env->CF) { \
T0 = T0 - T1 - 1; \
env->CF = src1 >= T1; \
} else { \
T0 = T0 - T1; \
env->CF = src1 > T1; \
} \
env->VF = (src1 ^ T1) & (src1 ^ T0); \
env->NZF = T0; \
res = T0; \
FORCE_RET(); \
}
OPSUB(sub, sbc, T0, T0, T1)
OPSUB(rsb, rsc, T0, T1, T0)
void OPPROTO op_andl_T0_T1(void)
{
T0 &= T1;
}
void OPPROTO op_xorl_T0_T1(void)
{
T0 ^= T1;
}
void OPPROTO op_orl_T0_T1(void)
{
T0 |= T1;
}
void OPPROTO op_bicl_T0_T1(void)
{
T0 &= ~T1;
}
void OPPROTO op_notl_T1(void)
{
T1 = ~T1;
}
void OPPROTO op_logic_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(op_test_eq, PARAM1, 0, PARAM2);
FORCE_RET();
}
void OPPROTO op_test_ne(void)
{
if (env->NZF != 0)
JUMP_TB(op_test_ne, PARAM1, 0, PARAM2);
FORCE_RET();
}
void OPPROTO op_test_cs(void)
{
if (env->CF != 0)
JUMP_TB(op_test_cs, PARAM1, 0, PARAM2);
FORCE_RET();
}
void OPPROTO op_test_cc(void)
{
if (env->CF == 0)
JUMP_TB(op_test_cc, PARAM1, 0, PARAM2);
FORCE_RET();
}
void OPPROTO op_test_mi(void)
{
if ((env->NZF & 0x80000000) != 0)
JUMP_TB(op_test_mi, PARAM1, 0, PARAM2);
FORCE_RET();
}
void OPPROTO op_test_pl(void)
{
if ((env->NZF & 0x80000000) == 0)
JUMP_TB(op_test_pl, PARAM1, 0, PARAM2);
FORCE_RET();
}
void OPPROTO op_test_vs(void)
{
if ((env->VF & 0x80000000) != 0)
JUMP_TB(op_test_vs, PARAM1, 0, PARAM2);
FORCE_RET();
}
void OPPROTO op_test_vc(void)
{
if ((env->VF & 0x80000000) == 0)
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(op_test_hi, PARAM1, 0, PARAM2);
FORCE_RET();
}
void OPPROTO op_test_ls(void)
{
if (env->CF == 0 || env->NZF == 0)
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(op_test_ge, PARAM1, 0, PARAM2);
FORCE_RET();
}
void OPPROTO op_test_lt(void)
{
if (((env->VF ^ env->NZF) & 0x80000000) != 0)
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(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(op_test_le, PARAM1, 0, PARAM2);
FORCE_RET();
}
void OPPROTO op_jmp(void)
{
JUMP_TB(op_jmp, PARAM1, 1, PARAM2);
}
void OPPROTO op_exit_tb(void)
{
EXIT_TB();
}
void OPPROTO op_movl_T0_psr(void)
{
T0 = compute_cpsr();
}
/* NOTE: N = 1 and Z = 1 cannot be stored currently */
void OPPROTO op_movl_psr_T0(void)
{
unsigned int psr;
psr = T0;
env->CF = (psr >> 29) & 1;
env->NZF = (psr & 0xc0000000) ^ 0x40000000;
env->VF = (psr << 3) & 0x80000000;
/* for user mode we do not update other state info */
}
void OPPROTO op_mul_T0_T1(void)
{
T0 = T0 * T1;
}
/* 64 bit unsigned mul */
void OPPROTO op_mull_T0_T1(void)
{
uint64_t res;
res = T0 * T1;
T1 = res >> 32;
T0 = res;
}
/* 64 bit signed mul */
void OPPROTO op_imull_T0_T1(void)
{
uint64_t res;
res = (int32_t)T0 * (int32_t)T1;
T1 = res >> 32;
T0 = res;
}
void OPPROTO op_addq_T0_T1(void)
{
uint64_t res;
res = ((uint64_t)T1 << 32) | T0;
res += ((uint64_t)(env->regs[PARAM2]) << 32) | (env->regs[PARAM1]);
T1 = res >> 32;
T0 = res;
}
void OPPROTO op_logicq_cc(void)
{
env->NZF = (T1 & 0x80000000) | ((T0 | T1) != 0);
}
/* memory access */
void OPPROTO op_ldub_T0_T1(void)
{
T0 = ldub((void *)T1);
}
void OPPROTO op_ldsb_T0_T1(void)
{
T0 = ldsb((void *)T1);
}
void OPPROTO op_lduw_T0_T1(void)
{
T0 = lduw((void *)T1);
}
void OPPROTO op_ldsw_T0_T1(void)
{
T0 = ldsw((void *)T1);
}
void OPPROTO op_ldl_T0_T1(void)
{
T0 = ldl((void *)T1);
}
void OPPROTO op_stb_T0_T1(void)
{
stb((void *)T1, T0);
}
void OPPROTO op_stw_T0_T1(void)
{
stw((void *)T1, T0);
}
void OPPROTO op_stl_T0_T1(void)
{
stl((void *)T1, T0);
}
void OPPROTO op_swpb_T0_T1(void)
{
int tmp;
cpu_lock();
tmp = ldub((void *)T1);
stb((void *)T1, T0);
T0 = tmp;
cpu_unlock();
}
void OPPROTO op_swpl_T0_T1(void)
{
int tmp;
cpu_lock();
tmp = ldl((void *)T1);
stl((void *)T1, T0);
T0 = tmp;
cpu_unlock();
}
/* shifts */
/* T1 based */
void OPPROTO op_shll_T1_im(void)
{
T1 = T1 << PARAM1;
}
void OPPROTO op_shrl_T1_im(void)
{
T1 = (uint32_t)T1 >> PARAM1;
}
void OPPROTO op_sarl_T1_im(void)
{
T1 = (int32_t)T1 >> PARAM1;
}
void OPPROTO op_rorl_T1_im(void)
{
int shift;
shift = PARAM1;
T1 = ((uint32_t)T1 >> shift) | (T1 << (32 - shift));
}
/* T1 based, set C flag */
void OPPROTO op_shll_T1_im_cc(void)
{
env->CF = (T1 >> (32 - PARAM1)) & 1;
T1 = T1 << PARAM1;
}
void OPPROTO op_shrl_T1_im_cc(void)
{
env->CF = (T1 >> (PARAM1 - 1)) & 1;
T1 = (uint32_t)T1 >> PARAM1;
}
void OPPROTO op_sarl_T1_im_cc(void)
{
env->CF = (T1 >> (PARAM1 - 1)) & 1;
T1 = (int32_t)T1 >> PARAM1;
}
void OPPROTO op_rorl_T1_im_cc(void)
{
int shift;
shift = PARAM1;
env->CF = (T1 >> (shift - 1)) & 1;
T1 = ((uint32_t)T1 >> shift) | (T1 << (32 - shift));
}
/* T2 based */
void OPPROTO op_shll_T2_im(void)
{
T2 = T2 << PARAM1;
}
void OPPROTO op_shrl_T2_im(void)
{
T2 = (uint32_t)T2 >> PARAM1;
}
void OPPROTO op_sarl_T2_im(void)
{
T2 = (int32_t)T2 >> PARAM1;
}
void OPPROTO op_rorl_T2_im(void)
{
int shift;
shift = PARAM1;
T2 = ((uint32_t)T2 >> shift) | (T2 << (32 - shift));
}
/* T1 based, use T0 as shift count */
void OPPROTO op_shll_T1_T0(void)
{
int shift;
shift = T0 & 0xff;
if (shift >= 32)
T1 = 0;
else
T1 = T1 << shift;
FORCE_RET();
}
void OPPROTO op_shrl_T1_T0(void)
{
int shift;
shift = T0 & 0xff;
if (shift >= 32)
T1 = 0;
else
T1 = (uint32_t)T1 >> shift;
FORCE_RET();
}
void OPPROTO op_sarl_T1_T0(void)
{
int shift;
shift = T0 & 0xff;
if (shift >= 32)
shift = 31;
T1 = (int32_t)T1 >> shift;
}
void OPPROTO op_rorl_T1_T0(void)
{
int shift;
shift = T0 & 0x1f;
if (shift) {
T1 = ((uint32_t)T1 >> shift) | (T1 << (32 - shift));
}
FORCE_RET();
}
/* T1 based, use T0 as shift count and compute CF */
void OPPROTO op_shll_T1_T0_cc(void)
{
int shift;
shift = T0 & 0xff;
if (shift >= 32) {
if (shift == 32)
env->CF = T1 & 1;
else
env->CF = 0;
T1 = 0;
} else if (shift != 0) {
env->CF = (T1 >> (32 - shift)) & 1;
T1 = T1 << shift;
}
FORCE_RET();
}
void OPPROTO op_shrl_T1_T0_cc(void)
{
int shift;
shift = T0 & 0xff;
if (shift >= 32) {
if (shift == 32)
env->CF = (T1 >> 31) & 1;
else
env->CF = 0;
T1 = 0;
} else if (shift != 0) {
env->CF = (T1 >> (shift - 1)) & 1;
T1 = (uint32_t)T1 >> shift;
}
FORCE_RET();
}
void OPPROTO op_sarl_T1_T0_cc(void)
{
int shift;
shift = T0 & 0xff;
if (shift >= 32) {
env->CF = (T1 >> 31) & 1;
T1 = (int32_t)T1 >> 31;
} else {
env->CF = (T1 >> (shift - 1)) & 1;
T1 = (int32_t)T1 >> shift;
}
FORCE_RET();
}
void OPPROTO op_rorl_T1_T0_cc(void)
{
int shift1, shift;
shift1 = T0 & 0xff;
shift = shift1 & 0x1f;
if (shift == 0) {
if (shift1 != 0)
env->CF = (T1 >> 31) & 1;
} else {
env->CF = (T1 >> (shift - 1)) & 1;
T1 = ((uint32_t)T1 >> shift) | (T1 << (32 - shift));
}
FORCE_RET();
}
/* exceptions */
void OPPROTO op_swi(void)
{
env->exception_index = EXCP_SWI;
cpu_loop_exit();
}
void OPPROTO op_undef_insn(void)
{
env->exception_index = EXCP_UDEF;
cpu_loop_exit();
}
/* thread support */
spinlock_t global_cpu_lock = SPIN_LOCK_UNLOCKED;
void cpu_lock(void)
{
spin_lock(&global_cpu_lock);
}
void cpu_unlock(void)
{
spin_unlock(&global_cpu_lock);
}

48
target-arm/op_template.h Normal file
View File

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

903
target-arm/translate.c Normal file
View File

@@ -0,0 +1,903 @@
/*
* ARM translation
*
* Copyright (c) 2003 Fabrice Bellard
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <inttypes.h>
#include "cpu.h"
#include "exec-all.h"
#include "disas.h"
/* internal defines */
typedef struct DisasContext {
uint8_t *pc;
int is_jmp;
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;
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"
typedef void (GenOpFunc)(void);
typedef void (GenOpFunc1)(long);
typedef void (GenOpFunc2)(long, long);
typedef void (GenOpFunc3)(long, long, long);
static GenOpFunc2 *gen_test_cc[14] = {
gen_op_test_eq,
gen_op_test_ne,
gen_op_test_cs,
gen_op_test_cc,
gen_op_test_mi,
gen_op_test_pl,
gen_op_test_vs,
gen_op_test_vc,
gen_op_test_hi,
gen_op_test_ls,
gen_op_test_ge,
gen_op_test_lt,
gen_op_test_gt,
gen_op_test_le,
};
const uint8_t table_logic_cc[16] = {
1, /* and */
1, /* xor */
0, /* sub */
0, /* rsb */
0, /* add */
0, /* adc */
0, /* sbc */
0, /* rsc */
1, /* andl */
1, /* xorl */
0, /* cmp */
0, /* cmn */
1, /* orr */
1, /* mov */
1, /* bic */
1, /* mvn */
};
static GenOpFunc1 *gen_shift_T1_im[4] = {
gen_op_shll_T1_im,
gen_op_shrl_T1_im,
gen_op_sarl_T1_im,
gen_op_rorl_T1_im,
};
static GenOpFunc1 *gen_shift_T2_im[4] = {
gen_op_shll_T2_im,
gen_op_shrl_T2_im,
gen_op_sarl_T2_im,
gen_op_rorl_T2_im,
};
static GenOpFunc1 *gen_shift_T1_im_cc[4] = {
gen_op_shll_T1_im_cc,
gen_op_shrl_T1_im_cc,
gen_op_sarl_T1_im_cc,
gen_op_rorl_T1_im_cc,
};
static GenOpFunc *gen_shift_T1_T0[4] = {
gen_op_shll_T1_T0,
gen_op_shrl_T1_T0,
gen_op_sarl_T1_T0,
gen_op_rorl_T1_T0,
};
static GenOpFunc *gen_shift_T1_T0_cc[4] = {
gen_op_shll_T1_T0_cc,
gen_op_shrl_T1_T0_cc,
gen_op_sarl_T1_T0_cc,
gen_op_rorl_T1_T0_cc,
};
static GenOpFunc *gen_op_movl_TN_reg[3][16] = {
{
gen_op_movl_T0_r0,
gen_op_movl_T0_r1,
gen_op_movl_T0_r2,
gen_op_movl_T0_r3,
gen_op_movl_T0_r4,
gen_op_movl_T0_r5,
gen_op_movl_T0_r6,
gen_op_movl_T0_r7,
gen_op_movl_T0_r8,
gen_op_movl_T0_r9,
gen_op_movl_T0_r10,
gen_op_movl_T0_r11,
gen_op_movl_T0_r12,
gen_op_movl_T0_r13,
gen_op_movl_T0_r14,
gen_op_movl_T0_r15,
},
{
gen_op_movl_T1_r0,
gen_op_movl_T1_r1,
gen_op_movl_T1_r2,
gen_op_movl_T1_r3,
gen_op_movl_T1_r4,
gen_op_movl_T1_r5,
gen_op_movl_T1_r6,
gen_op_movl_T1_r7,
gen_op_movl_T1_r8,
gen_op_movl_T1_r9,
gen_op_movl_T1_r10,
gen_op_movl_T1_r11,
gen_op_movl_T1_r12,
gen_op_movl_T1_r13,
gen_op_movl_T1_r14,
gen_op_movl_T1_r15,
},
{
gen_op_movl_T2_r0,
gen_op_movl_T2_r1,
gen_op_movl_T2_r2,
gen_op_movl_T2_r3,
gen_op_movl_T2_r4,
gen_op_movl_T2_r5,
gen_op_movl_T2_r6,
gen_op_movl_T2_r7,
gen_op_movl_T2_r8,
gen_op_movl_T2_r9,
gen_op_movl_T2_r10,
gen_op_movl_T2_r11,
gen_op_movl_T2_r12,
gen_op_movl_T2_r13,
gen_op_movl_T2_r14,
gen_op_movl_T2_r15,
},
};
static GenOpFunc *gen_op_movl_reg_TN[2][16] = {
{
gen_op_movl_r0_T0,
gen_op_movl_r1_T0,
gen_op_movl_r2_T0,
gen_op_movl_r3_T0,
gen_op_movl_r4_T0,
gen_op_movl_r5_T0,
gen_op_movl_r6_T0,
gen_op_movl_r7_T0,
gen_op_movl_r8_T0,
gen_op_movl_r9_T0,
gen_op_movl_r10_T0,
gen_op_movl_r11_T0,
gen_op_movl_r12_T0,
gen_op_movl_r13_T0,
gen_op_movl_r14_T0,
gen_op_movl_r15_T0,
},
{
gen_op_movl_r0_T1,
gen_op_movl_r1_T1,
gen_op_movl_r2_T1,
gen_op_movl_r3_T1,
gen_op_movl_r4_T1,
gen_op_movl_r5_T1,
gen_op_movl_r6_T1,
gen_op_movl_r7_T1,
gen_op_movl_r8_T1,
gen_op_movl_r9_T1,
gen_op_movl_r10_T1,
gen_op_movl_r11_T1,
gen_op_movl_r12_T1,
gen_op_movl_r13_T1,
gen_op_movl_r14_T1,
gen_op_movl_r15_T1,
},
};
static GenOpFunc1 *gen_op_movl_TN_im[3] = {
gen_op_movl_T0_im,
gen_op_movl_T1_im,
gen_op_movl_T2_im,
};
static inline void gen_movl_TN_reg(DisasContext *s, int reg, int t)
{
int val;
if (reg == 15) {
/* normaly, since we updated PC, we need only to add 4 */
val = (long)s->pc + 4;
gen_op_movl_TN_im[t](val);
} else {
gen_op_movl_TN_reg[t][reg]();
}
}
static inline void gen_movl_T0_reg(DisasContext *s, int reg)
{
gen_movl_TN_reg(s, reg, 0);
}
static inline void gen_movl_T1_reg(DisasContext *s, int reg)
{
gen_movl_TN_reg(s, reg, 1);
}
static inline void gen_movl_T2_reg(DisasContext *s, int reg)
{
gen_movl_TN_reg(s, reg, 2);
}
static inline void gen_movl_reg_TN(DisasContext *s, int reg, int t)
{
gen_op_movl_reg_TN[t][reg]();
if (reg == 15) {
s->is_jmp = DISAS_JUMP;
}
}
static inline void gen_movl_reg_T0(DisasContext *s, int reg)
{
gen_movl_reg_TN(s, reg, 0);
}
static inline void gen_movl_reg_T1(DisasContext *s, int reg)
{
gen_movl_reg_TN(s, reg, 1);
}
static inline void gen_add_data_offset(DisasContext *s, unsigned int insn)
{
int val, rm, shift;
if (!(insn & (1 << 25))) {
/* immediate */
val = insn & 0xfff;
if (!(insn & (1 << 23)))
val = -val;
gen_op_addl_T1_im(val);
} else {
/* shift/register */
rm = (insn) & 0xf;
shift = (insn >> 7) & 0x1f;
gen_movl_T2_reg(s, rm);
if (shift != 0) {
gen_shift_T2_im[(insn >> 5) & 3](shift);
}
if (!(insn & (1 << 23)))
gen_op_subl_T1_T2();
else
gen_op_addl_T1_T2();
}
}
static inline void gen_add_datah_offset(DisasContext *s, unsigned int insn)
{
int val, rm;
if (insn & (1 << 22)) {
/* immediate */
val = (insn & 0xf) | ((insn >> 4) & 0xf0);
if (!(insn & (1 << 23)))
val = -val;
gen_op_addl_T1_im(val);
} else {
/* register */
rm = (insn) & 0xf;
gen_movl_T2_reg(s, rm);
if (!(insn & (1 << 23)))
gen_op_subl_T1_T2();
else
gen_op_addl_T1_T2();
}
}
static void disas_arm_insn(DisasContext *s)
{
unsigned int cond, insn, val, op1, i, shift, rm, rs, rn, rd, sh;
insn = ldl(s->pc);
s->pc += 4;
cond = insn >> 28;
if (cond == 0xf)
goto illegal_op;
if (cond != 0xe) {
/* if not always execute, we generate a conditional jump to
next instruction */
gen_test_cc[cond ^ 1]((long)s->tb, (long)s->pc);
s->is_jmp = DISAS_JUMP_NEXT;
}
if (((insn & 0x0e000000) == 0 &&
(insn & 0x00000090) != 0x90) ||
((insn & 0x0e000000) == (1 << 25))) {
int set_cc, logic_cc, shiftop;
op1 = (insn >> 21) & 0xf;
set_cc = (insn >> 20) & 1;
logic_cc = table_logic_cc[op1] & set_cc;
/* data processing instruction */
if (insn & (1 << 25)) {
/* immediate operand */
val = insn & 0xff;
shift = ((insn >> 8) & 0xf) * 2;
if (shift)
val = (val >> shift) | (val << (32 - shift));
gen_op_movl_T1_im(val);
/* XXX: is CF modified ? */
} else {
/* register */
rm = (insn) & 0xf;
gen_movl_T1_reg(s, rm);
shiftop = (insn >> 5) & 3;
if (!(insn & (1 << 4))) {
shift = (insn >> 7) & 0x1f;
if (shift != 0) {
if (logic_cc) {
gen_shift_T1_im_cc[shiftop](shift);
} else {
gen_shift_T1_im[shiftop](shift);
}
}
} else {
rs = (insn >> 8) & 0xf;
gen_movl_T0_reg(s, rs);
if (logic_cc) {
gen_shift_T1_T0_cc[shiftop]();
} else {
gen_shift_T1_T0[shiftop]();
}
}
}
if (op1 != 0x0f && op1 != 0x0d) {
rn = (insn >> 16) & 0xf;
gen_movl_T0_reg(s, rn);
}
rd = (insn >> 12) & 0xf;
switch(op1) {
case 0x00:
gen_op_andl_T0_T1();
gen_movl_reg_T0(s, rd);
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)
gen_op_subl_T0_T1_cc();
else
gen_op_subl_T0_T1();
gen_movl_reg_T0(s, rd);
break;
case 0x03:
if (set_cc)
gen_op_rsbl_T0_T1_cc();
else
gen_op_rsbl_T0_T1();
gen_movl_reg_T0(s, rd);
break;
case 0x04:
if (set_cc)
gen_op_addl_T0_T1_cc();
else
gen_op_addl_T0_T1();
gen_movl_reg_T0(s, rd);
break;
case 0x05:
if (set_cc)
gen_op_adcl_T0_T1_cc();
else
gen_op_adcl_T0_T1();
gen_movl_reg_T0(s, rd);
break;
case 0x06:
if (set_cc)
gen_op_sbcl_T0_T1_cc();
else
gen_op_sbcl_T0_T1();
gen_movl_reg_T0(s, rd);
break;
case 0x07:
if (set_cc)
gen_op_rscl_T0_T1_cc();
else
gen_op_rscl_T0_T1();
gen_movl_reg_T0(s, rd);
break;
case 0x08:
if (set_cc) {
gen_op_andl_T0_T1();
gen_op_logic_T0_cc();
}
break;
case 0x09:
if (set_cc) {
gen_op_xorl_T0_T1();
gen_op_logic_T0_cc();
}
break;
case 0x0a:
if (set_cc) {
gen_op_subl_T0_T1_cc();
}
break;
case 0x0b:
if (set_cc) {
gen_op_addl_T0_T1_cc();
}
break;
case 0x0c:
gen_op_orl_T0_T1();
gen_movl_reg_T0(s, rd);
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;
}
} else {
/* other instructions */
op1 = (insn >> 24) & 0xf;
switch(op1) {
case 0x0:
case 0x1:
sh = (insn >> 5) & 3;
if (sh == 0) {
if (op1 == 0x0) {
rd = (insn >> 16) & 0xf;
rn = (insn >> 12) & 0xf;
rs = (insn >> 8) & 0xf;
rm = (insn) & 0xf;
if (!(insn & (1 << 23))) {
/* 32 bit mul */
gen_movl_T0_reg(s, rs);
gen_movl_T1_reg(s, rm);
gen_op_mul_T0_T1();
if (insn & (1 << 21)) {
gen_movl_T1_reg(s, rn);
gen_op_addl_T0_T1();
}
if (insn & (1 << 20))
gen_op_logic_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();
if (insn & (1 << 21))
gen_op_addq_T0_T1(rn, rd);
if (insn & (1 << 20))
gen_op_logicq_cc();
gen_movl_reg_T0(s, rn);
gen_movl_reg_T1(s, rd);
}
} else {
/* SWP instruction */
rn = (insn >> 16) & 0xf;
rd = (insn >> 12) & 0xf;
rm = (insn) & 0xf;
gen_movl_T0_reg(s, rm);
gen_movl_T1_reg(s, rn);
if (insn & (1 << 22)) {
gen_op_swpb_T0_T1();
} else {
gen_op_swpl_T0_T1();
}
gen_movl_reg_T0(s, rd);
}
} else {
/* load/store half word */
rn = (insn >> 16) & 0xf;
rd = (insn >> 12) & 0xf;
gen_movl_T1_reg(s, rn);
if (insn & (1 << 25))
gen_add_datah_offset(s, insn);
if (insn & (1 << 20)) {
/* load */
switch(sh) {
case 1:
gen_op_lduw_T0_T1();
break;
case 2:
gen_op_ldsb_T0_T1();
break;
default:
case 3:
gen_op_ldsw_T0_T1();
break;
}
} else {
/* store */
gen_op_stw_T0_T1();
}
if (!(insn & (1 << 24))) {
gen_add_datah_offset(s, insn);
gen_movl_reg_T1(s, rn);
} else if (insn & (1 << 21)) {
gen_movl_reg_T1(s, rn);
}
}
break;
case 0x4:
case 0x5:
case 0x6:
case 0x7:
/* load/store byte/word */
rn = (insn >> 16) & 0xf;
rd = (insn >> 12) & 0xf;
gen_movl_T1_reg(s, rn);
if (insn & (1 << 24))
gen_add_data_offset(s, insn);
if (insn & (1 << 20)) {
/* load */
if (insn & (1 << 22))
gen_op_ldub_T0_T1();
else
gen_op_ldl_T0_T1();
gen_movl_reg_T0(s, rd);
} else {
/* store */
gen_movl_T0_reg(s, rd);
if (insn & (1 << 22))
gen_op_stb_T0_T1();
else
gen_op_stl_T0_T1();
}
if (!(insn & (1 << 24))) {
gen_add_data_offset(s, insn);
gen_movl_reg_T1(s, rn);
} else if (insn & (1 << 21))
gen_movl_reg_T1(s, rn); {
}
break;
case 0x08:
case 0x09:
{
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 {
/* post increment */
}
} 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);
}
}
break;
case 0xa:
case 0xb:
{
int offset;
/* branch (and link) */
val = (int)s->pc;
if (insn & (1 << 24)) {
gen_op_movl_T0_im(val);
gen_op_movl_reg_TN[0][14]();
}
offset = (((int)insn << 8) >> 8);
val += (offset << 2) + 4;
gen_op_jmp((long)s->tb, val);
s->is_jmp = DISAS_TB_JUMP;
}
break;
case 0xf:
/* swi */
gen_op_movl_T0_im((long)s->pc);
gen_op_movl_reg_TN[0][15]();
gen_op_swi();
s->is_jmp = DISAS_JUMP;
break;
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);
gen_op_movl_reg_TN[0][15]();
gen_op_undef_insn();
s->is_jmp = DISAS_JUMP;
break;
}
}
}
/* generate intermediate code in gen_opc_buf and gen_opparam_buf for
basic block 'tb'. If search_pc is TRUE, also generate PC
information for each intermediate instruction. */
static inline int gen_intermediate_code_internal(CPUState *env,
TranslationBlock *tb,
int search_pc)
{
DisasContext dc1, *dc = &dc1;
uint16_t *gen_opc_end;
int j, lj;
uint8_t *pc_start;
/* generate intermediate code */
pc_start = (uint8_t *)tb->pc;
dc->tb = tb;
gen_opc_ptr = gen_opc_buf;
gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
gen_opparam_ptr = gen_opparam_buf;
dc->is_jmp = DISAS_NEXT;
dc->pc = pc_start;
lj = -1;
do {
if (search_pc) {
j = gen_opc_ptr - gen_opc_buf;
if (lj < j) {
lj++;
while (lj < j)
gen_opc_instr_start[lj++] = 0;
}
gen_opc_pc[lj] = (uint32_t)dc->pc;
gen_opc_instr_start[lj] = 1;
}
disas_arm_insn(dc);
} while (!dc->is_jmp && gen_opc_ptr < gen_opc_end &&
(dc->pc - pc_start) < (TARGET_PAGE_SIZE - 32));
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;
#ifdef DEBUG_DISAS
if (loglevel) {
fprintf(logfile, "----------------\n");
fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start));
disas(logfile, pc_start, dc->pc - pc_start, 0, 0);
fprintf(logfile, "\n");
fprintf(logfile, "OP:\n");
dump_ops(gen_opc_buf, gen_opparam_buf);
fprintf(logfile, "\n");
}
#endif
if (!search_pc)
tb->size = dc->pc - pc_start;
return 0;
}
int gen_intermediate_code(CPUState *env, TranslationBlock *tb)
{
return gen_intermediate_code_internal(env, tb, 0);
}
int gen_intermediate_code_pc(CPUState *env, TranslationBlock *tb)
{
return gen_intermediate_code_internal(env, tb, 1);
}
CPUARMState *cpu_arm_init(void)
{
CPUARMState *env;
cpu_exec_init();
env = malloc(sizeof(CPUARMState));
if (!env)
return NULL;
memset(env, 0, sizeof(CPUARMState));
return env;
}
void cpu_arm_close(CPUARMState *env)
{
free(env);
}
void cpu_arm_dump_state(CPUARMState *env, FILE *f, int flags)
{
int i;
for(i=0;i<16;i++) {
fprintf(f, "R%02d=%08x", i, env->regs[i]);
if ((i % 4) == 3)
fprintf(f, "\n");
else
fprintf(f, " ");
}
fprintf(f, "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' : '-');
}

401
target-i386/cpu.h Normal file
View File

@@ -0,0 +1,401 @@
/*
* i386 virtual CPU header
*
* Copyright (c) 2003 Fabrice Bellard
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef CPU_I386_H
#define CPU_I386_H
#include "cpu-defs.h"
#define R_EAX 0
#define R_ECX 1
#define R_EDX 2
#define R_EBX 3
#define R_ESP 4
#define R_EBP 5
#define R_ESI 6
#define R_EDI 7
#define R_AL 0
#define R_CL 1
#define R_DL 2
#define R_BL 3
#define R_AH 4
#define R_CH 5
#define R_DH 6
#define R_BH 7
#define R_ES 0
#define R_CS 1
#define R_SS 2
#define R_DS 3
#define R_FS 4
#define R_GS 5
/* segment descriptor fields */
#define DESC_G_MASK (1 << 23)
#define DESC_B_SHIFT 22
#define DESC_B_MASK (1 << DESC_B_SHIFT)
#define DESC_AVL_MASK (1 << 20)
#define DESC_P_MASK (1 << 15)
#define DESC_DPL_SHIFT 13
#define DESC_S_MASK (1 << 12)
#define DESC_TYPE_SHIFT 8
#define DESC_A_MASK (1 << 8)
#define DESC_CS_MASK (1 << 11)
#define DESC_C_MASK (1 << 10)
#define DESC_R_MASK (1 << 9)
#define DESC_E_MASK (1 << 10)
#define DESC_W_MASK (1 << 9)
/* eflags masks */
#define CC_C 0x0001
#define CC_P 0x0004
#define CC_A 0x0010
#define CC_Z 0x0040
#define CC_S 0x0080
#define CC_O 0x0800
#define TF_SHIFT 8
#define IOPL_SHIFT 12
#define VM_SHIFT 17
#define TF_MASK 0x00000100
#define IF_MASK 0x00000200
#define DF_MASK 0x00000400
#define IOPL_MASK 0x00003000
#define NT_MASK 0x00004000
#define RF_MASK 0x00010000
#define VM_MASK 0x00020000
#define AC_MASK 0x00040000
#define VIF_MASK 0x00080000
#define VIP_MASK 0x00100000
#define ID_MASK 0x00200000
/* 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)
#define CR0_AM_MASK (1 << 18)
#define CR0_PG_MASK (1 << 31)
#define CR4_VME_MASK (1 << 0)
#define CR4_PVI_MASK (1 << 1)
#define CR4_TSD_MASK (1 << 2)
#define CR4_DE_MASK (1 << 3)
#define CR4_PSE_MASK (1 << 4)
#define PG_PRESENT_BIT 0
#define PG_RW_BIT 1
#define PG_USER_BIT 2
#define PG_PWT_BIT 3
#define PG_PCD_BIT 4
#define PG_ACCESSED_BIT 5
#define PG_DIRTY_BIT 6
#define PG_PSE_BIT 7
#define PG_GLOBAL_BIT 8
#define PG_PRESENT_MASK (1 << PG_PRESENT_BIT)
#define PG_RW_MASK (1 << PG_RW_BIT)
#define PG_USER_MASK (1 << PG_USER_BIT)
#define PG_PWT_MASK (1 << PG_PWT_BIT)
#define PG_PCD_MASK (1 << PG_PCD_BIT)
#define PG_ACCESSED_MASK (1 << PG_ACCESSED_BIT)
#define PG_DIRTY_MASK (1 << PG_DIRTY_BIT)
#define PG_PSE_MASK (1 << PG_PSE_BIT)
#define PG_GLOBAL_MASK (1 << PG_GLOBAL_BIT)
#define PG_ERROR_W_BIT 1
#define PG_ERROR_P_MASK 0x01
#define PG_ERROR_W_MASK (1 << PG_ERROR_W_BIT)
#define PG_ERROR_U_MASK 0x04
#define PG_ERROR_RSVD_MASK 0x08
#define MSR_IA32_APICBASE 0x1b
#define MSR_IA32_APICBASE_BSP (1<<8)
#define MSR_IA32_APICBASE_ENABLE (1<<11)
#define MSR_IA32_APICBASE_BASE (0xfffff<<12)
#define MSR_IA32_SYSENTER_CS 0x174
#define MSR_IA32_SYSENTER_ESP 0x175
#define MSR_IA32_SYSENTER_EIP 0x176
#define EXCP00_DIVZ 0
#define EXCP01_SSTP 1
#define EXCP02_NMI 2
#define EXCP03_INT3 3
#define EXCP04_INTO 4
#define EXCP05_BOUND 5
#define EXCP06_ILLOP 6
#define EXCP07_PREX 7
#define EXCP08_DBLE 8
#define EXCP09_XERR 9
#define EXCP0A_TSS 10
#define EXCP0B_NOSEG 11
#define EXCP0C_STACK 12
#define EXCP0D_GPF 13
#define EXCP0E_PAGE 14
#define EXCP10_COPR 16
#define EXCP11_ALGN 17
#define EXCP12_MCHK 18
enum {
CC_OP_DYNAMIC, /* must use dynamic code to get cc_op */
CC_OP_EFLAGS, /* all cc are explicitely computed, CC_SRC = flags */
CC_OP_MUL, /* modify all flags, C, O = (CC_SRC != 0) */
CC_OP_ADDB, /* modify all flags, CC_DST = res, CC_SRC = src1 */
CC_OP_ADDW,
CC_OP_ADDL,
CC_OP_ADCB, /* modify all flags, CC_DST = res, CC_SRC = src1 */
CC_OP_ADCW,
CC_OP_ADCL,
CC_OP_SUBB, /* modify all flags, CC_DST = res, CC_SRC = src1 */
CC_OP_SUBW,
CC_OP_SUBL,
CC_OP_SBBB, /* modify all flags, CC_DST = res, CC_SRC = src1 */
CC_OP_SBBW,
CC_OP_SBBL,
CC_OP_LOGICB, /* modify all flags, CC_DST = res */
CC_OP_LOGICW,
CC_OP_LOGICL,
CC_OP_INCB, /* modify all flags except, CC_DST = res, CC_SRC = C */
CC_OP_INCW,
CC_OP_INCL,
CC_OP_DECB, /* modify all flags except, CC_DST = res, CC_SRC = C */
CC_OP_DECW,
CC_OP_DECL,
CC_OP_SHLB, /* modify all flags, CC_DST = res, CC_SRC.lsb = C */
CC_OP_SHLW,
CC_OP_SHLL,
CC_OP_SARB, /* modify all flags, CC_DST = res, CC_SRC.lsb = C */
CC_OP_SARW,
CC_OP_SARL,
CC_OP_NB,
};
#ifdef __i386__
#define USE_X86LDOUBLE
#endif
#ifdef USE_X86LDOUBLE
typedef long double CPU86_LDouble;
#else
typedef double CPU86_LDouble;
#endif
typedef struct SegmentCache {
uint32_t selector;
uint8_t *base;
uint32_t limit;
uint32_t flags;
} SegmentCache;
typedef struct CPUX86State {
/* standard registers */
uint32_t regs[8];
uint32_t eip;
uint32_t eflags; /* eflags register. During CPU emulation, CC
flags and DF are set to zero because they are
stored elsewhere */
/* emulator internal eflags handling */
uint32_t cc_src;
uint32_t cc_dst;
uint32_t cc_op;
int32_t df; /* D flag : 1 if D = 0, -1 if D = 1 */
uint32_t hflags; /* hidden flags, see HF_xxx constants */
/* FPU state */
unsigned int fpstt; /* top of stack index */
unsigned int fpus;
unsigned int fpuc;
uint8_t fptags[8]; /* 0 = valid, 1 = empty */
CPU86_LDouble fpregs[8];
/* emulator internal variables */
CPU86_LDouble ft0;
union {
float f;
double d;
int i32;
int64_t i64;
} fp_convert;
/* segments */
SegmentCache segs[6]; /* selector values */
SegmentCache ldt;
SegmentCache tr;
SegmentCache gdt; /* only base and limit are used */
SegmentCache idt; /* only base and limit are used */
/* sysenter registers */
uint32_t sysenter_cs;
uint32_t sysenter_esp;
uint32_t sysenter_eip;
/* exception/interrupt handling */
jmp_buf jmp_env;
int exception_index;
int error_code;
int exception_is_int;
int exception_next_eip;
struct TranslationBlock *current_tb; /* currently executing TB */
uint32_t cr[5]; /* NOTE: cr1 is unused */
uint32_t dr[8]; /* debug registers */
int interrupt_request;
int user_mode_only; /* user mode only simulation */
/* 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;
#ifndef IN_OP_I386
void cpu_x86_outb(CPUX86State *env, int addr, int val);
void cpu_x86_outw(CPUX86State *env, int addr, int val);
void cpu_x86_outl(CPUX86State *env, int addr, int val);
int cpu_x86_inb(CPUX86State *env, int addr);
int cpu_x86_inw(CPUX86State *env, int addr);
int cpu_x86_inl(CPUX86State *env, int addr);
#endif
CPUX86State *cpu_x86_init(void);
int cpu_x86_exec(CPUX86State *s);
void cpu_x86_close(CPUX86State *s);
int cpu_x86_get_pic_interrupt(CPUX86State *s);
/* 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;
/* 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);
/* you can call this signal handler from your SIGBUS and SIGSEGV
signal handlers to inform the virtual CPU of exceptions. non zero
is returned if the signal was handled by the virtual CPU. */
struct siginfo;
int cpu_x86_signal_handler(int host_signum, struct siginfo *info,
void *puc);
/* MMU defines */
void cpu_x86_init_mmu(CPUX86State *env);
extern int phys_ram_size;
extern int phys_ram_fd;
extern uint8_t *phys_ram_base;
/* used to debug */
#define X86_DUMP_FPU 0x0001 /* dump FPU state too */
#define X86_DUMP_CCOP 0x0002 /* dump qemu flag cache */
void cpu_x86_dump_state(CPUX86State *env, FILE *f, int flags);
#define TARGET_PAGE_BITS 12
#include "cpu-all.h"
#endif /* CPU_I386_H */

478
target-i386/exec.h Normal file
View File

@@ -0,0 +1,478 @@
/*
* i386 execution defines
*
* Copyright (c) 2003 Fabrice Bellard
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "dyngen-exec.h"
/* at least 4 register variables are defines */
register struct CPUX86State *env asm(AREG0);
register uint32_t T0 asm(AREG1);
register uint32_t T1 asm(AREG2);
register uint32_t T2 asm(AREG3);
#define A0 T2
/* if more registers are available, we define some registers too */
#ifdef AREG4
register uint32_t EAX asm(AREG4);
#define reg_EAX
#endif
#ifdef AREG5
register uint32_t ESP asm(AREG5);
#define reg_ESP
#endif
#ifdef AREG6
register uint32_t EBP asm(AREG6);
#define reg_EBP
#endif
#ifdef AREG7
register uint32_t ECX asm(AREG7);
#define reg_ECX
#endif
#ifdef AREG8
register uint32_t EDX asm(AREG8);
#define reg_EDX
#endif
#ifdef AREG9
register uint32_t EBX asm(AREG9);
#define reg_EBX
#endif
#ifdef AREG10
register uint32_t ESI asm(AREG10);
#define reg_ESI
#endif
#ifdef AREG11
register uint32_t EDI asm(AREG11);
#define reg_EDI
#endif
extern FILE *logfile;
extern int loglevel;
#ifndef reg_EAX
#define EAX (env->regs[R_EAX])
#endif
#ifndef reg_ECX
#define ECX (env->regs[R_ECX])
#endif
#ifndef reg_EDX
#define EDX (env->regs[R_EDX])
#endif
#ifndef reg_EBX
#define EBX (env->regs[R_EBX])
#endif
#ifndef reg_ESP
#define ESP (env->regs[R_ESP])
#endif
#ifndef reg_EBP
#define EBP (env->regs[R_EBP])
#endif
#ifndef reg_ESI
#define ESI (env->regs[R_ESI])
#endif
#ifndef reg_EDI
#define EDI (env->regs[R_EDI])
#endif
#define EIP (env->eip)
#define DF (env->df)
#define CC_SRC (env->cc_src)
#define CC_DST (env->cc_dst)
#define CC_OP (env->cc_op)
/* float macros */
#define FT0 (env->ft0)
#define ST0 (env->fpregs[env->fpstt])
#define ST(n) (env->fpregs[(env->fpstt + (n)) & 7])
#define ST1 ST(1)
#ifdef USE_FP_CONVERT
#define FP_CONVERT (env->fp_convert)
#endif
#include "cpu.h"
#include "exec-all.h"
typedef struct CCTable {
int (*compute_all)(void); /* return all the flags */
int (*compute_c)(void); /* return the C flag */
} CCTable;
extern CCTable cc_table[];
void load_seg(int seg_reg, int selector, unsigned cur_eip);
void 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);
void helper_movl_drN_T0(int reg);
void helper_invlpg(unsigned int addr);
void cpu_x86_update_cr0(CPUX86State *env);
void cpu_x86_update_cr3(CPUX86State *env);
void cpu_x86_flush_tlb(CPUX86State *env, uint32_t addr);
int cpu_x86_handle_mmu_fault(CPUX86State *env, uint32_t addr,
int is_write, 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, 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,
unsigned int next_eip);
void raise_exception_err(int exception_index, int error_code);
void raise_exception(int exception_index);
void __hidden cpu_loop_exit(void);
void helper_fsave(uint8_t *ptr, int data32);
void helper_frstor(uint8_t *ptr, int data32);
void OPPROTO op_movl_eflags_T0(void);
void OPPROTO op_movl_T0_eflags(void);
void raise_interrupt(int intno, int is_int, int error_code,
unsigned int next_eip);
void raise_exception_err(int exception_index, int error_code);
void raise_exception(int exception_index);
void helper_divl_EAX_T0(uint32_t eip);
void helper_idivl_EAX_T0(uint32_t eip);
void helper_cmpxchg8b(void);
void helper_cpuid(void);
void helper_rdtsc(void);
void helper_rdmsr(void);
void helper_wrmsr(void);
void helper_lsl(void);
void helper_lar(void);
#ifdef USE_X86LDOUBLE
/* use long double functions */
#define lrint lrintl
#define llrint llrintl
#define fabs fabsl
#define sin sinl
#define cos cosl
#define sqrt sqrtl
#define pow powl
#define log logl
#define tan tanl
#define atan2 atan2l
#define floor floorl
#define ceil ceill
#define rint rintl
#endif
extern int lrint(CPU86_LDouble x);
extern int64_t llrint(CPU86_LDouble x);
extern CPU86_LDouble fabs(CPU86_LDouble x);
extern CPU86_LDouble sin(CPU86_LDouble x);
extern CPU86_LDouble cos(CPU86_LDouble x);
extern CPU86_LDouble sqrt(CPU86_LDouble x);
extern CPU86_LDouble pow(CPU86_LDouble, CPU86_LDouble);
extern CPU86_LDouble log(CPU86_LDouble x);
extern CPU86_LDouble tan(CPU86_LDouble x);
extern CPU86_LDouble atan2(CPU86_LDouble, CPU86_LDouble);
extern CPU86_LDouble floor(CPU86_LDouble x);
extern CPU86_LDouble ceil(CPU86_LDouble x);
extern CPU86_LDouble rint(CPU86_LDouble x);
#define RC_MASK 0xc00
#define RC_NEAR 0x000
#define RC_DOWN 0x400
#define RC_UP 0x800
#define RC_CHOP 0xc00
#define MAXTAN 9223372036854775808.0
#ifdef __arm__
/* we have no way to do correct rounding - a FPU emulator is needed */
#define FE_DOWNWARD FE_TONEAREST
#define FE_UPWARD FE_TONEAREST
#define FE_TOWARDZERO FE_TONEAREST
#endif
#ifdef USE_X86LDOUBLE
/* only for x86 */
typedef union {
long double d;
struct {
unsigned long long lower;
unsigned short upper;
} l;
} CPU86_LDoubleU;
/* the following deal with x86 long double-precision numbers */
#define MAXEXPD 0x7fff
#define EXPBIAS 16383
#define EXPD(fp) (fp.l.upper & 0x7fff)
#define SIGND(fp) ((fp.l.upper) & 0x8000)
#define MANTD(fp) (fp.l.lower)
#define BIASEXPONENT(fp) fp.l.upper = (fp.l.upper & ~(0x7fff)) | EXPBIAS
#else
/* NOTE: arm is horrible as double 32 bit words are stored in big endian ! */
typedef union {
double d;
#if !defined(WORDS_BIGENDIAN) && !defined(__arm__)
struct {
uint32_t lower;
int32_t upper;
} l;
#else
struct {
int32_t upper;
uint32_t lower;
} l;
#endif
#ifndef __arm__
int64_t ll;
#endif
} CPU86_LDoubleU;
/* the following deal with IEEE double-precision numbers */
#define MAXEXPD 0x7ff
#define EXPBIAS 1023
#define EXPD(fp) (((fp.l.upper) >> 20) & 0x7FF)
#define SIGND(fp) ((fp.l.upper) & 0x80000000)
#ifdef __arm__
#define MANTD(fp) (fp.l.lower | ((uint64_t)(fp.l.upper & ((1 << 20) - 1)) << 32))
#else
#define MANTD(fp) (fp.ll & ((1LL << 52) - 1))
#endif
#define BIASEXPONENT(fp) fp.l.upper = (fp.l.upper & ~(0x7ff << 20)) | (EXPBIAS << 20)
#endif
static inline void fpush(void)
{
env->fpstt = (env->fpstt - 1) & 7;
env->fptags[env->fpstt] = 0; /* validate stack entry */
}
static inline void fpop(void)
{
env->fptags[env->fpstt] = 1; /* invvalidate stack entry */
env->fpstt = (env->fpstt + 1) & 7;
}
#ifndef USE_X86LDOUBLE
static inline CPU86_LDouble helper_fldt(uint8_t *ptr)
{
CPU86_LDoubleU temp;
int upper, e;
uint64_t ll;
/* mantissa */
upper = lduw(ptr + 8);
/* XXX: handle overflow ? */
e = (upper & 0x7fff) - 16383 + EXPBIAS; /* exponent */
e |= (upper >> 4) & 0x800; /* sign */
ll = (ldq(ptr) >> 11) & ((1LL << 52) - 1);
#ifdef __arm__
temp.l.upper = (e << 20) | (ll >> 32);
temp.l.lower = ll;
#else
temp.ll = ll | ((uint64_t)e << 52);
#endif
return temp.d;
}
static inline void helper_fstt(CPU86_LDouble f, uint8_t *ptr)
{
CPU86_LDoubleU temp;
int e;
temp.d = f;
/* mantissa */
stq(ptr, (MANTD(temp) << 11) | (1LL << 63));
/* exponent + sign */
e = EXPD(temp) - EXPBIAS + 16383;
e |= SIGND(temp) >> 16;
stw(ptr + 8, e);
}
#endif
const CPU86_LDouble f15rk[7];
void helper_fldt_ST0_A0(void);
void helper_fstt_ST0_A0(void);
void helper_fbld_ST0_A0(void);
void helper_fbst_ST0_A0(void);
void helper_f2xm1(void);
void helper_fyl2x(void);
void helper_fptan(void);
void helper_fpatan(void);
void helper_fxtract(void);
void helper_fprem1(void);
void helper_fprem(void);
void helper_fyl2xp1(void);
void helper_fsqrt(void);
void helper_fsincos(void);
void helper_frndint(void);
void helper_fscale(void);
void helper_fsin(void);
void helper_fcos(void);
void helper_fxam_ST0(void);
void helper_fstenv(uint8_t *ptr, int data32);
void helper_fldenv(uint8_t *ptr, int data32);
void helper_fsave(uint8_t *ptr, int data32);
void helper_frstor(uint8_t *ptr, int data32);
const uint8_t parity_table[256];
const uint8_t rclw_table[32];
const uint8_t rclb_table[32];
static inline uint32_t compute_eflags(void)
{
return env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
}
#define FL_UPDATE_MASK32 (TF_MASK | AC_MASK | ID_MASK)
#define FL_UPDATE_CPL0_MASK (TF_MASK | IF_MASK | IOPL_MASK | NT_MASK | \
RF_MASK | AC_MASK | ID_MASK)
/* NOTE: CC_OP must be modified manually to CC_OP_EFLAGS */
static inline void load_eflags(int eflags, int update_mask)
{
CC_SRC = eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
DF = 1 - (2 * ((eflags >> 10) & 1));
env->eflags = (env->eflags & ~update_mask) |
(eflags & update_mask);
}
/* 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) */

1827
target-i386/helper.c Normal file

File diff suppressed because it is too large Load Diff

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

@@ -0,0 +1,400 @@
/*
* 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",
"MUL",
"ADDB",
"ADDW",
"ADDL",
"ADCB",
"ADCW",
"ADCL",
"SUBB",
"SUBW",
"SUBL",
"SBBB",
"SBBW",
"SBBL",
"LOGICB",
"LOGICW",
"LOGICL",
"INCB",
"INCW",
"INCL",
"DECB",
"DECW",
"DECL",
"SHLB",
"SHLW",
"SHLL",
"SARB",
"SARW",
"SARL",
};
void cpu_x86_dump_state(CPUX86State *env, FILE *f, int flags)
{
int eflags;
char cc_op_name[32];
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]\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' : '-');
fprintf(f, "CS=%04x SS=%04x DS=%04x ES=%04x FS=%04x GS=%04x\n",
env->segs[R_CS].selector,
env->segs[R_SS].selector,
env->segs[R_DS].selector,
env->segs[R_ES].selector,
env->segs[R_FS].selector,
env->segs[R_GS].selector);
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;
int phys_ram_size;
int phys_ram_fd;
uint8_t *phys_ram_base;
void cpu_x86_update_cr0(CPUX86State *env)
{
int pg_state, pe_state;
#ifdef 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) {
page_unmap();
tlb_flush(env);
last_pg_state = pg_state;
}
pe_state = env->cr[0] & CR0_PE_MASK;
if (last_pe_state != pe_state) {
tb_flush();
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
page_unmap();
tlb_flush(env);
}
}
void cpu_x86_init_mmu(CPUX86State *env)
{
last_pg_state = -1;
cpu_x86_update_cr0(env);
}
/* XXX: also flush 4MB pages */
void cpu_x86_flush_tlb(CPUX86State *env, uint32_t addr)
{
int flags;
unsigned long virt_addr;
tlb_flush_page(env, addr);
flags = page_get_flags(addr);
if (flags & PAGE_VALID) {
virt_addr = addr & ~0xfff;
#if !defined(CONFIG_SOFTMMU)
munmap((void *)virt_addr, 4096);
#endif
page_set_flags(virt_addr, virt_addr + 4096, 0);
}
}
/* 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 & ~0xfff;
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));
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));
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:
#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 & ~0xfff) & (page_size - 1);
paddr = (pte & ~0xfff) + 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;
}
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;
}

File diff suppressed because it is too large Load Diff

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;
}
@@ -204,8 +204,13 @@ static int glue(compute_all_shl, SUFFIX)(void)
return cf | pf | af | zf | sf | of;
}
#if DATA_BITS == 32
static int glue(compute_c_shl, SUFFIX)(void)
{
return (CC_SRC >> (DATA_BITS - 1)) & CC_C;
}
#if DATA_BITS == 32
static int glue(compute_c_sar, SUFFIX)(void)
{
return CC_SRC & 1;
}
@@ -229,70 +234,70 @@ static int glue(compute_all_sar, SUFFIX)(void)
void OPPROTO glue(op_jb_sub, SUFFIX)(void)
{
int src1, src2;
src1 = CC_SRC;
src2 = CC_SRC - CC_DST;
src1 = CC_DST + CC_SRC;
src2 = CC_SRC;
if ((DATA_TYPE)src1 < (DATA_TYPE)src2)
EIP = PARAM1;
JUMP_TB(glue(op_jb_sub, SUFFIX), PARAM1, 0, PARAM2);
else
EIP = PARAM2;
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)
EIP = PARAM1;
JUMP_TB(glue(op_jz_sub, SUFFIX), PARAM1, 0, PARAM2);
else
EIP = PARAM2;
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)
EIP = PARAM1;
JUMP_TB(glue(op_jbe_sub, SUFFIX), PARAM1, 0, PARAM2);
else
EIP = PARAM2;
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)
EIP = PARAM1;
JUMP_TB(glue(op_js_sub, SUFFIX), PARAM1, 0, PARAM2);
else
EIP = PARAM2;
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)
EIP = PARAM1;
JUMP_TB(glue(op_jl_sub, SUFFIX), PARAM1, 0, PARAM2);
else
EIP = PARAM2;
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)
EIP = PARAM1;
JUMP_TB(glue(op_jle_sub, SUFFIX), PARAM1, 0, PARAM2);
else
EIP = PARAM2;
JUMP_TB(glue(op_jle_sub, SUFFIX), PARAM1, 1, PARAM3);
FORCE_RET();
}
@@ -356,8 +361,8 @@ void OPPROTO glue(op_jecxz, SUFFIX)(void)
void OPPROTO glue(op_setb_T0_sub, SUFFIX)(void)
{
int src1, src2;
src1 = CC_SRC;
src2 = CC_SRC - CC_DST;
src1 = CC_DST + CC_SRC;
src2 = CC_SRC;
T0 = ((DATA_TYPE)src1 < (DATA_TYPE)src2);
}
@@ -370,8 +375,8 @@ void OPPROTO glue(op_setz_T0_sub, SUFFIX)(void)
void OPPROTO glue(op_setbe_T0_sub, SUFFIX)(void)
{
int src1, src2;
src1 = CC_SRC;
src2 = CC_SRC - CC_DST;
src1 = CC_DST + CC_SRC;
src2 = CC_SRC;
T0 = ((DATA_TYPE)src1 <= (DATA_TYPE)src2);
}
@@ -384,8 +389,8 @@ void OPPROTO glue(op_sets_T0_sub, SUFFIX)(void)
void OPPROTO glue(op_setl_T0_sub, SUFFIX)(void)
{
int src1, src2;
src1 = CC_SRC;
src2 = CC_SRC - CC_DST;
src1 = CC_DST + CC_SRC;
src2 = CC_SRC;
T0 = ((DATA_STYPE)src1 < (DATA_STYPE)src2);
}
@@ -393,135 +398,14 @@ void OPPROTO glue(op_setl_T0_sub, SUFFIX)(void)
void OPPROTO glue(op_setle_T0_sub, SUFFIX)(void)
{
int src1, src2;
src1 = CC_SRC;
src2 = CC_SRC - CC_DST;
src1 = CC_DST + CC_SRC;
src2 = CC_SRC;
T0 = ((DATA_STYPE)src1 <= (DATA_STYPE)src2);
}
/* shifts */
void OPPROTO glue(glue(op_rol, SUFFIX), _T0_T1_cc)(void)
{
int count, src;
count = T1 & SHIFT_MASK;
if (count) {
CC_SRC = cc_table[CC_OP].compute_all() & ~(CC_O | CC_C);
src = T0;
T0 &= DATA_MASK;
T0 = (T0 << count) | (T0 >> (DATA_BITS - count));
CC_SRC |= (lshift(src ^ T0, 11 - (DATA_BITS - 1)) & CC_O) |
(T0 & CC_C);
CC_OP = CC_OP_EFLAGS;
}
FORCE_RET();
}
void OPPROTO glue(glue(op_rol, SUFFIX), _T0_T1)(void)
{
int count;
count = T1 & SHIFT_MASK;
if (count) {
T0 &= DATA_MASK;
T0 = (T0 << count) | (T0 >> (DATA_BITS - count));
}
FORCE_RET();
}
void OPPROTO glue(glue(op_ror, SUFFIX), _T0_T1_cc)(void)
{
int count, src;
count = T1 & SHIFT_MASK;
if (count) {
CC_SRC = cc_table[CC_OP].compute_all() & ~(CC_O | CC_C);
src = T0;
T0 &= DATA_MASK;
T0 = (T0 >> count) | (T0 << (DATA_BITS - count));
CC_SRC |= (lshift(src ^ T0, 11 - (DATA_BITS - 1)) & CC_O) |
((T0 >> (DATA_BITS - 1)) & CC_C);
CC_OP = CC_OP_EFLAGS;
}
FORCE_RET();
}
void OPPROTO glue(glue(op_ror, SUFFIX), _T0_T1)(void)
{
int count;
count = T1 & SHIFT_MASK;
if (count) {
T0 &= DATA_MASK;
T0 = (T0 >> count) | (T0 << (DATA_BITS - count));
}
FORCE_RET();
}
void OPPROTO glue(glue(op_rcl, SUFFIX), _T0_T1_cc)(void)
{
int count, res, eflags;
unsigned int src;
count = T1 & 0x1f;
#if DATA_BITS == 16
count = rclw_table[count];
#elif DATA_BITS == 8
count = rclb_table[count];
#endif
if (count) {
eflags = cc_table[CC_OP].compute_all();
T0 &= DATA_MASK;
src = T0;
res = (T0 << count) | ((eflags & CC_C) << (count - 1));
if (count > 1)
res |= T0 >> (DATA_BITS + 1 - count);
T0 = res;
CC_SRC = (eflags & ~(CC_C | CC_O)) |
(lshift(src ^ T0, 11 - (DATA_BITS - 1)) & CC_O) |
((src >> (DATA_BITS - count)) & CC_C);
CC_OP = CC_OP_EFLAGS;
}
FORCE_RET();
}
void OPPROTO glue(glue(op_rcr, SUFFIX), _T0_T1_cc)(void)
{
int count, res, eflags;
unsigned int src;
count = T1 & 0x1f;
#if DATA_BITS == 16
count = rclw_table[count];
#elif DATA_BITS == 8
count = rclb_table[count];
#endif
if (count) {
eflags = cc_table[CC_OP].compute_all();
T0 &= DATA_MASK;
src = T0;
res = (T0 >> count) | ((eflags & CC_C) << (DATA_BITS - count));
if (count > 1)
res |= T0 << (DATA_BITS + 1 - count);
T0 = res;
CC_SRC = (eflags & ~(CC_C | CC_O)) |
(lshift(src ^ T0, 11 - (DATA_BITS - 1)) & CC_O) |
((src >> (count - 1)) & CC_C);
CC_OP = CC_OP_EFLAGS;
}
FORCE_RET();
}
void OPPROTO glue(glue(op_shl, SUFFIX), _T0_T1_cc)(void)
{
int count;
count = T1 & 0x1f;
if (count) {
CC_SRC = (DATA_TYPE)T0 << (count - 1);
T0 = T0 << count;
CC_DST = T0;
CC_OP = CC_OP_SHLB + SHIFT;
}
FORCE_RET();
}
void OPPROTO glue(glue(op_shl, SUFFIX), _T0_T1)(void)
{
int count;
@@ -530,20 +414,6 @@ void OPPROTO glue(glue(op_shl, SUFFIX), _T0_T1)(void)
FORCE_RET();
}
void OPPROTO glue(glue(op_shr, SUFFIX), _T0_T1_cc)(void)
{
int count;
count = T1 & 0x1f;
if (count) {
T0 &= DATA_MASK;
CC_SRC = T0 >> (count - 1);
T0 = T0 >> count;
CC_DST = T0;
CC_OP = CC_OP_SARB + SHIFT;
}
FORCE_RET();
}
void OPPROTO glue(glue(op_shr, SUFFIX), _T0_T1)(void)
{
int count;
@@ -553,20 +423,6 @@ void OPPROTO glue(glue(op_shr, SUFFIX), _T0_T1)(void)
FORCE_RET();
}
void OPPROTO glue(glue(op_sar, SUFFIX), _T0_T1_cc)(void)
{
int count, src;
count = T1 & 0x1f;
if (count) {
src = (DATA_STYPE)T0;
CC_SRC = src >> (count - 1);
T0 = src >> count;
CC_DST = T0;
CC_OP = CC_OP_SARB + SHIFT;
}
FORCE_RET();
}
void OPPROTO glue(glue(op_sar, SUFFIX), _T0_T1)(void)
{
int count, src;
@@ -576,166 +432,11 @@ void OPPROTO glue(glue(op_sar, SUFFIX), _T0_T1)(void)
FORCE_RET();
}
#if DATA_BITS == 16
/* XXX: overflow flag might be incorrect in some cases in shldw */
void OPPROTO glue(glue(op_shld, SUFFIX), _T0_T1_im_cc)(void)
{
int count;
unsigned int res;
count = PARAM1;
T1 &= 0xffff;
res = T1 | (T0 << 16);
CC_SRC = res >> (32 - count);
res <<= count;
if (count > 16)
res |= T1 << (count - 16);
T0 = res >> 16;
CC_DST = T0;
}
#undef MEM_WRITE
#include "ops_template_mem.h"
void OPPROTO glue(glue(op_shld, SUFFIX), _T0_T1_ECX_cc)(void)
{
int count;
unsigned int res;
count = ECX & 0x1f;
if (count) {
T1 &= 0xffff;
res = T1 | (T0 << 16);
CC_SRC = res >> (32 - count);
res <<= count;
if (count > 16)
res |= T1 << (count - 16);
T0 = res >> 16;
CC_DST = T0;
CC_OP = CC_OP_SARB + SHIFT;
}
FORCE_RET();
}
void OPPROTO glue(glue(op_shrd, SUFFIX), _T0_T1_im_cc)(void)
{
int count;
unsigned int res;
count = PARAM1;
res = (T0 & 0xffff) | (T1 << 16);
CC_SRC = res >> (count - 1);
res >>= count;
if (count > 16)
res |= T1 << (32 - count);
T0 = res;
CC_DST = T0;
}
void OPPROTO glue(glue(op_shrd, SUFFIX), _T0_T1_ECX_cc)(void)
{
int count;
unsigned int res;
count = ECX & 0x1f;
if (count) {
res = (T0 & 0xffff) | (T1 << 16);
CC_SRC = res >> (count - 1);
res >>= count;
if (count > 16)
res |= T1 << (32 - count);
T0 = res;
CC_DST = T0;
CC_OP = CC_OP_SARB + SHIFT;
}
FORCE_RET();
}
#endif
#if DATA_BITS == 32
void OPPROTO glue(glue(op_shld, SUFFIX), _T0_T1_im_cc)(void)
{
int count;
count = PARAM1;
T0 &= DATA_MASK;
T1 &= DATA_MASK;
CC_SRC = T0 << (count - 1);
T0 = (T0 << count) | (T1 >> (DATA_BITS - count));
CC_DST = T0;
}
void OPPROTO glue(glue(op_shld, SUFFIX), _T0_T1_ECX_cc)(void)
{
int count;
count = ECX & 0x1f;
if (count) {
T0 &= DATA_MASK;
T1 &= DATA_MASK;
CC_SRC = T0 << (count - 1);
T0 = (T0 << count) | (T1 >> (DATA_BITS - count));
CC_DST = T0;
CC_OP = CC_OP_SHLB + SHIFT;
}
FORCE_RET();
}
void OPPROTO glue(glue(op_shrd, SUFFIX), _T0_T1_im_cc)(void)
{
int count;
count = PARAM1;
T0 &= DATA_MASK;
T1 &= DATA_MASK;
CC_SRC = T0 >> (count - 1);
T0 = (T0 >> count) | (T1 << (DATA_BITS - count));
CC_DST = T0;
}
void OPPROTO glue(glue(op_shrd, SUFFIX), _T0_T1_ECX_cc)(void)
{
int count;
count = ECX & 0x1f;
if (count) {
T0 &= DATA_MASK;
T1 &= DATA_MASK;
CC_SRC = T0 >> (count - 1);
T0 = (T0 >> count) | (T1 << (DATA_BITS - count));
CC_DST = T0;
CC_OP = CC_OP_SARB + SHIFT;
}
FORCE_RET();
}
#endif
/* carry add/sub (we only need to set CC_OP differently) */
void OPPROTO glue(glue(op_adc, SUFFIX), _T0_T1_cc)(void)
{
int cf;
cf = cc_table[CC_OP].compute_c();
CC_SRC = T0;
T0 = T0 + T1 + cf;
CC_DST = T0;
CC_OP = CC_OP_ADDB + SHIFT + cf * 3;
}
void OPPROTO glue(glue(op_sbb, SUFFIX), _T0_T1_cc)(void)
{
int cf;
cf = cc_table[CC_OP].compute_c();
CC_SRC = T0;
T0 = T0 - T1 - cf;
CC_DST = T0;
CC_OP = CC_OP_SUBB + SHIFT + cf * 3;
}
void OPPROTO glue(glue(op_cmpxchg, SUFFIX), _T0_T1_EAX_cc)(void)
{
CC_SRC = EAX;
CC_DST = EAX - T0;
if ((DATA_TYPE)CC_DST == 0) {
T0 = T1;
} else {
EAX = (EAX & ~DATA_MASK) | (T0 & DATA_MASK);
}
FORCE_RET();
}
#define MEM_WRITE
#include "ops_template_mem.h"
/* bit operations */
#if DATA_BITS >= 16
@@ -751,7 +452,7 @@ void OPPROTO glue(glue(op_bts, SUFFIX), _T0_T1_cc)(void)
{
int count;
count = T1 & SHIFT_MASK;
CC_SRC = T0 >> count;
T1 = T0 >> count;
T0 |= (1 << count);
}
@@ -759,7 +460,7 @@ void OPPROTO glue(glue(op_btr, SUFFIX), _T0_T1_cc)(void)
{
int count;
count = T1 & SHIFT_MASK;
CC_SRC = T0 >> count;
T1 = T0 >> count;
T0 &= ~(1 << count);
}
@@ -767,7 +468,7 @@ void OPPROTO glue(glue(op_btc, SUFFIX), _T0_T1_cc)(void)
{
int count;
count = T1 & SHIFT_MASK;
CC_SRC = T0 >> count;
T1 = T0 >> count;
T0 ^= (1 << count);
}
@@ -809,46 +510,102 @@ 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->seg_cache[R_ES].base + EDI
#define INC_SI() ESI += inc
#define INC_DI() EDI += inc
#define CX ECX
#define DEC_CX() ECX--
#include "op_string.h"
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->seg_cache[R_ES].base + (EDI & 0xffff)
#define INC_SI() ESI = (ESI & ~0xffff) | ((ESI + inc) & 0xffff)
#define INC_DI() EDI = (EDI & ~0xffff) | ((EDI + inc) & 0xffff)
#define CX (ECX & 0xffff)
#define DEC_CX() ECX = (ECX & ~0xffff) | ((ECX - 1) & 0xffff)
#include "op_string.h"
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 */
void OPPROTO glue(glue(op_out, SUFFIX), _T0_T1)(void)
{
glue(cpu_x86_out, SUFFIX)(T0 & 0xffff, T1 & DATA_MASK);
glue(cpu_x86_out, SUFFIX)(env, T0 & 0xffff, T1 & DATA_MASK);
}
void OPPROTO glue(glue(op_in, SUFFIX), _T0_T1)(void)
{
T1 = glue(cpu_x86_in, SUFFIX)(T0 & 0xffff);
T1 = glue(cpu_x86_in, SUFFIX)(env, T0 & 0xffff);
}
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);
}
#undef DATA_BITS

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

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

@@ -0,0 +1,46 @@
#ifndef CPU_SPARC_H
#define CPU_SPARC_H
#include <setjmp.h>
#include "config.h"
#include "cpu-defs.h"
/*#define EXCP_INTERRUPT 0x100*/
#define PSR_NEG (1<<23)
#define PSR_ZERO (1<<22)
#define PSR_OVF (1<<21)
#define PSR_CARRY (1<<20)
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;
jmp_buf jmp_env;
int user_mode_only;
int exception_index;
int interrupt_index;
int interrupt_request;
struct TranslationBlock *current_tb;
void *opaque;
} 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

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

@@ -0,0 +1,500 @@
/*
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)
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_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_sub_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)
{
unsigned long long res = T0*T1;
T0 = res & 0xffffffff;
env->y = res >> 32;
}
void OPPROTO op_smul_T1_T0 (void)
{
long long res = T0*T1;
T0 = res & 0xffffffff;
env->y = res >> 32;
}
void OPPROTO op_udiv_T1_T0 (void)
{
unsigned long long x0 = T0 * env->y;
unsigned int x1 = T1;
T0 = x0 / x1;
}
void OPPROTO op_sdiv_T1_T0 (void)
{
long long x0 = T0 * env->y;
int x1 = T1;
T0 = x0 / x1;
}
void OPPROTO op_subx_T1_T0 (void)
{
T0 -= T1+((env->psr & PSR_CARRY)?1:0);
}
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;
}
void OPPROTO op_sll (void)
{
T0 <<= T1;
}
void OPPROTO op_srl (void)
{
T0 >>= T1;
}
void OPPROTO op_sra (void)
{
int x = T0 >> T1;
T0 = x;
}
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_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^T1;
}
void OPPROTO op_rdy (void)
{
T0 = env->y;
}
#define regwptr (env->regwptr)
void OPPROTO op_save (void)
{
regwptr -= 16;
}
void OPPROTO op_restore (void)
{
regwptr += 16;
}
void OPPROTO op_trap (void)
{
env->exception_index = PARAM1;
cpu_loop_exit ();
}
void OPPROTO op_exit_tb (void)
{
EXIT_TB ();
}
void OPPROTO op_eval_be (void)
{
T0 = (env->psr & PSR_ZERO);
}
#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_eval_ble (void)
{
GET_FLAGS;
T0 = Z | (N^V);
}
void OPPROTO op_eval_bl (void)
{
GET_FLAGS;
T0 = N^V;
}
void OPPROTO op_eval_bleu (void)
{
GET_FLAGS;
T0 = C|Z;
}
void OPPROTO op_eval_bcs (void)
{
T0 = (env->psr & PSR_CARRY);
}
void OPPROTO op_eval_bvs (void)
{
T0 = (env->psr & PSR_OVF);
}
void OPPROTO op_eval_bneg (void)
{
T0 = (env->psr & PSR_NEG);
}
void OPPROTO op_eval_bne (void)
{
T0 = !(env->psr & PSR_ZERO);
}
void OPPROTO op_eval_bg (void)
{
GET_FLAGS;
T0 = !(Z | (N^V));
}
/*XXX: This seems to be documented wrong in the SPARC V8 Manual
The manual states: !(N^V)
but I assume Z | !(N^V) to be correct */
void OPPROTO op_eval_bge (void)
{
GET_FLAGS;
T0 = Z | !(N^V);
}
void OPPROTO op_eval_bgu (void)
{
GET_FLAGS;
T0 = !(C | Z);
}
void OPPROTO op_eval_bcc (void)
{
T0 = !(env->psr & PSR_CARRY);
}
void OPPROTO op_eval_bpos (void)
{
T0 = !(env->psr & PSR_NEG);
}
void OPPROTO op_eval_bvc (void)
{
T0 = !(env->psr & PSR_OVF);
}
void OPPROTO op_jmp_im (void)
{
env->pc = PARAM1;
}
void OPPROTO op_call (void)
{
regwptr[7] = PARAM1-4;
env->pc = PARAM1+PARAM2;
}
void OPPROTO op_jmpl (void)
{
env->npc = T0;
}
void OPPROTO op_generic_jmp_1 (void)
{
T1 = PARAM1;
env->pc = PARAM1+PARAM2;
}
void OPPROTO op_generic_jmp_2 (void)
{
T1 = PARAM1;
env->pc = env->npc;
}
unsigned long old_T0;
void OPPROTO op_save_T0 (void)
{
old_T0 = T0;
}
void OPPROTO op_restore_T0 (void)
{
T0 = old_T0;
}
void OPPROTO op_generic_branch (void)
{
if (T0)
JUMP_TB (__func__, PARAM1, 0, PARAM2);
else
JUMP_TB (__func__, PARAM1, 1, PARAM3);
FORCE_RET ();
}
void OPPROTO op_generic_branch_a (void)
{
if (T0)
env->npc = PARAM3;
else
JUMP_TB (__func__, PARAM1, 0, PARAM2);
FORCE_RET ();
}
void OPPROTO op_noop (void)
{
}

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

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

@@ -0,0 +1,744 @@
/*
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.
There is also one big (currently unsolved) bug in the branch code:
If a delay slot modifies the condition codes then the new condition
codes, instead of the old ones will be used.
TODO-list:
FPU-Instructions
Coprocessor-Instructions
Fix above bug
Check signedness issues
Privileged instructions
Register window overflow/underflow check
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;
uint8_t *npc;
void (*branch) (struct DisasContext *, uint32_t, uint32_t);
unsigned int delay_slot:2;
uint32_t insn;
uint32_t target;
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 do_branch (DisasContext *dc, uint32_t target, uint32_t insn)
{
unsigned int cond = GET_FIELD (insn, 3, 6), a = (insn & (1<<29)), ib = 0;
target += (uint32_t) dc->pc-4;
if (!a) disas_sparc_insn (dc);
switch (cond) {
case 0x0: gen_op_movl_T0_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_T0_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;
case 0xf: gen_op_eval_bvc (); break;
}
if (a && ((cond|0x8) != 0x8)) {
gen_op_generic_branch_a ((uint32_t) dc->tb,
(uint32_t) dc->pc+4, target);
disas_sparc_insn (dc);
ib = 1;
}
else
if (cond && !a) {
gen_op_generic_branch ((uint32_t) dc->tb, (uint32_t) target,
(uint32_t) dc->pc);
ib = 1;
}
if (ib) dc->is_br = DISAS_JUMP;
}
/* target == 0x1 means CALL- else JMPL-instruction */
static void do_jump (DisasContext *dc, uint32_t target, uint32_t rd)
{
uint32_t orig_pc = (uint32_t) dc->pc-8;
if (target != 0x1)
gen_op_generic_jmp_1 (orig_pc, target);
else
gen_op_generic_jmp_2 (orig_pc);
gen_movl_T1_reg (rd);
dc->is_br = DISAS_JUMP;
gen_op_movl_T0_0 ();
}
#define GET_FIELDs(x,a,b) sign_extend (GET_FIELD(x,a,b), b-a)
static int
sign_extend (x, len)
int x, len;
{
int signbit = (1 << (len - 1));
int mask = (signbit << 1) - 1;
return ((x & mask) ^ signbit) - signbit;
}
static void disas_sparc_insn (DisasContext *dc)
{
unsigned int insn, opc, rs1, rs2, rd;
if (dc->delay_slot == 1) {
insn = dc->insn;
} else {
if (dc->delay_slot) dc->delay_slot--;
insn = htonl (*(unsigned int *) (dc->pc));
dc->pc += 4;
}
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 */
printf ("UNIMPLEMENTED: %p\n", dc->pc-4);
exit (23);
break;
case 0x2: /* BN+x */
{
target <<= 2;
target = sign_extend (target, 22);
do_branch (dc, target, insn);
break;
}
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;
if (dc->delay_slot) {
do_jump (dc, target, 15);
dc->delay_slot = 0;
} else {
dc->insn = insn;
dc->delay_slot = 2;
}
break;
}
case 2: /* FPU & Logical Operations */
{
unsigned int xop = GET_FIELD (insn, 7, 12);
if (xop == 58) { /* generate trap */
dc->is_br = DISAS_JUMP;
gen_op_jmp_im ((uint32_t) dc->pc);
if (IS_IMM) gen_op_trap (GET_FIELD (insn, 25, 31));
/* else XXX*/
gen_op_movl_T0_0 ();
break;
}
if (xop == 0x34 || xop == 0x35) { /* FPU Operations */
exit (33);
}
rs1 = GET_FIELD (insn, 13, 17);
gen_movl_reg_T0 (rs1);
if (IS_IMM) { /* immediate */
rs2 = GET_FIELDs (insn, 20, 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:
gen_op_add_T1_T0 ();
break;
case 0x1:
gen_op_and_T1_T0 ();
break;
case 0x2:
gen_op_or_T1_T0 ();
break;
case 0x3:
gen_op_xor_T1_T0 ();
break;
case 0x4:
gen_op_sub_T1_T0 ();
break;
case 0x5:
gen_op_andn_T1_T0 ();
break;
case 0x6:
gen_op_orn_T1_T0 ();
break;
case 0x7:
gen_op_xnor_T1_T0 ();
break;
case 0x8:
gen_op_addx_T1_T0 ();
break;
case 0xa:
gen_op_umul_T1_T0 ();
break;
case 0xb:
gen_op_smul_T1_T0 ();
break;
case 0xc:
gen_op_subx_T1_T0 ();
break;
case 0xe:
gen_op_udiv_T1_T0 ();
break;
case 0xf:
gen_op_sdiv_T1_T0 ();
break;
default:
exit (17);
break;
}
gen_movl_T0_reg (rd);
if (xop & 0x10) {
gen_op_set_flags ();
}
} else {
switch (xop) {
case 0x25: /* SLL */
gen_op_sll ();
break;
case 0x26:
gen_op_srl ();
break;
case 0x27:
gen_op_sra ();
break;
case 0x28: case 0x30:
{
unsigned int rdi = GET_FIELD (insn, 13, 17);
if (!rdi) (xop==0x28?gen_op_rdy ():gen_op_wry());
/* else gen_op_su_trap (); */
break;
}
/* Problem with jmpl: if restore is executed in the delay
slot, then the wrong registers are beeing used */
case 0x38: /* jmpl */
{
if (dc->delay_slot) {
gen_op_add_T1_T0 ();
do_jump (dc, 1, rd);
dc->delay_slot = 0;
} else {
gen_op_add_T1_T0 ();
gen_op_jmpl ();
dc->insn = insn;
dc->delay_slot = 2;
}
break;
}
case 0x3c: /* save */
gen_op_add_T1_T0 ();
gen_op_save ();
gen_movl_T0_reg (rd);
break;
case 0x3d: /* restore */
gen_op_add_T1_T0 ();
gen_op_restore ();
gen_movl_T0_reg (rd);
break;
}
}
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, 20, 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_op_st ();
gen_movl_reg_T1 (rd+1);
gen_op_st ();
break;
}
}
}
}
}
static inline int gen_intermediate_code_internal (TranslationBlock *tb, int spc)
{
uint8_t *pc_start = (uint8_t *) tb->pc;
uint16_t *gen_opc_end;
DisasContext dc;
memset (&dc, 0, sizeof (dc));
if (spc) {
printf ("SearchPC not yet supported\n");
exit (0);
}
dc.tb = tb;
dc.pc = pc_start;
gen_opc_ptr = gen_opc_buf;
gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
gen_opparam_ptr = gen_opparam_buf;
do {
disas_sparc_insn (&dc);
} while (!dc.is_br && (gen_opc_ptr < gen_opc_end) &&
(dc.pc - pc_start) < (TARGET_PAGE_SIZE - 32));
switch (dc.is_br) {
case DISAS_JUMP:
case DISAS_TB_JUMP:
gen_op_exit_tb ();
break;
}
*gen_opc_ptr = INDEX_op_end;
#ifdef DEBUG_DISAS
if (loglevel) {
fprintf (logfile, "--------------\n");
fprintf (logfile, "IN: %s\n", lookup_symbol (pc_start));
disas(logfile, pc_start, dc.pc - pc_start, 0, 0);
fprintf(logfile, "\n");
fprintf(logfile, "OP:\n");
dump_ops(gen_opc_buf, gen_opparam_buf);
fprintf(logfile, "\n");
}
#endif
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);
}
void *mycpu;
CPUSPARCState *cpu_sparc_init (void)
{
CPUSPARCState *env;
cpu_exec_init ();
if (!(env = malloc (sizeof(CPUSPARCState))))
return (NULL);
memset (env, 0, sizeof (*env));
if (!(env->regwptr = malloc (0x2000)))
return (NULL);
memset (env->regwptr, 0, 0x2000);
env->regwptr += 127;
env->user_mode_only = 1;
mycpu = env;
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: %p\n", (void *) env->pc);
fprintf (f, "General Registers:\n");
for (i=0;i<4;i++)
fprintf (f, "%%g%c: %%%08x\t", i+'0', env->gregs[i]);
fprintf (f, "\n");
for (;i<8;i++)
fprintf (f, "%%g%c: %%%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: %%%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: %%%08x\t", (x==0?'o':x==1?'l':'i'), i, env->regwptr[i+x*8]);
fprintf (f, "\n");
}
fprintf (f, "PSR: %x -> %c%c%c%c\n", env->psr,
GET_FLAG(PSR_ZERO, 'Z'), GET_FLAG(PSR_OVF, 'V'),
GET_FLAG(PSR_NEG, 'N'), GET_FLAG(PSR_CARRY, 'C'));
}

View File

@@ -1,18 +1,13 @@
gmon.out
testsig
hello
hello-i386
hello-arm
sha1.test.c
sha1.c
op.c
test-i386
sha1
testclone
interp.h
interploop.c
.gdb_history
cachegrind.out
interp.c
interp
testthread
test-i386.s
test-i386.ref

View File

@@ -1,26 +1,21 @@
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/qemu-i386
all: $(TESTS)
hello: hello.c
hello-i386: hello-i386.c
$(CC) -nostdlib $(CFLAGS) -static $(LDFLAGS) -o $@ $<
strip hello
testclone: testclone.c
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $<
testsig: testsig.c
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $<
strip $@
testthread: testthread.c
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< -lpthread
@@ -30,17 +25,24 @@ test_path: test_path.c
./$@ || { rm $@; exit 1; }
# i386 emulation test (test various opcodes) */
test-i386: test-i386.c test-i386-code16.S \
test-i386: test-i386.c test-i386-code16.S test-i386-vm86.S \
test-i386.h test-i386-shift.h test-i386-muldiv.h
$(CC) $(CFLAGS) $(LDFLAGS) -static -o $@ test-i386.c test-i386-code16.S -lm
$(CC) $(CFLAGS) $(LDFLAGS) -static -o $@ test-i386.c \
test-i386-code16.S test-i386-vm86.S -lm
test: test-i386
ifeq ($(ARCH),i386)
test: test-i386
./test-i386 > test-i386.ref
else
test:
endif
$(QEMU) test-i386 > test-i386.out
@if diff -u test-i386.ref test-i386.out ; then echo "Auto Test OK"; fi
# 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 $@ $<
@@ -56,5 +58,12 @@ speed: sha1 sha1-i386
runcom: runcom.c
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $<
# arm test
hello-arm: hello-arm.o
arm-linux-ld -o $@ $<
hello-arm.o: hello-arm.c
arm-linux-gcc -Wall -g -O2 -c -o $@ $<
clean:
rm -f *~ *.o $(TESTS)

113
tests/hello-arm.c Normal file
View File

@@ -0,0 +1,113 @@
#define __NR_SYSCALL_BASE 0x900000
#define __NR_exit1 (__NR_SYSCALL_BASE+ 1)
#define __NR_write (__NR_SYSCALL_BASE+ 4)
#define __sys2(x) #x
#define __sys1(x) __sys2(x)
#ifndef __syscall
#define __syscall(name) "swi\t" __sys1(__NR_##name) "\n\t"
#endif
#define __syscall_return(type, res) \
do { \
return (type) (res); \
} while (0)
#define _syscall0(type,name) \
type name(void) { \
long __res; \
__asm__ __volatile__ ( \
__syscall(name) \
"mov %0,r0" \
:"=r" (__res) : : "r0","lr"); \
__syscall_return(type,__res); \
}
#define _syscall1(type,name,type1,arg1) \
type name(type1 arg1) { \
long __res; \
__asm__ __volatile__ ( \
"mov\tr0,%1\n\t" \
__syscall(name) \
"mov %0,r0" \
: "=r" (__res) \
: "r" ((long)(arg1)) \
: "r0","lr"); \
__syscall_return(type,__res); \
}
#define _syscall2(type,name,type1,arg1,type2,arg2) \
type name(type1 arg1,type2 arg2) { \
long __res; \
__asm__ __volatile__ ( \
"mov\tr0,%1\n\t" \
"mov\tr1,%2\n\t" \
__syscall(name) \
"mov\t%0,r0" \
: "=r" (__res) \
: "r" ((long)(arg1)),"r" ((long)(arg2)) \
: "r0","r1","lr"); \
__syscall_return(type,__res); \
}
#define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \
type name(type1 arg1,type2 arg2,type3 arg3) { \
long __res; \
__asm__ __volatile__ ( \
"mov\tr0,%1\n\t" \
"mov\tr1,%2\n\t" \
"mov\tr2,%3\n\t" \
__syscall(name) \
"mov\t%0,r0" \
: "=r" (__res) \
: "r" ((long)(arg1)),"r" ((long)(arg2)),"r" ((long)(arg3)) \
: "r0","r1","r2","lr"); \
__syscall_return(type,__res); \
}
#define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \
type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4) { \
long __res; \
__asm__ __volatile__ ( \
"mov\tr0,%1\n\t" \
"mov\tr1,%2\n\t" \
"mov\tr2,%3\n\t" \
"mov\tr3,%4\n\t" \
__syscall(name) \
"mov\t%0,r0" \
: "=r" (__res) \
: "r" ((long)(arg1)),"r" ((long)(arg2)),"r" ((long)(arg3)),"r" ((long)(arg4)) \
: "r0","r1","r2","r3","lr"); \
__syscall_return(type,__res); \
}
#define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4,type5,arg5) \
type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5) { \
long __res; \
__asm__ __volatile__ ( \
"mov\tr0,%1\n\t" \
"mov\tr1,%2\n\t" \
"mov\tr2,%3\n\t" \
"mov\tr3,%4\n\t" \
"mov\tr4,%5\n\t" \
__syscall(name) \
"mov\t%0,r0" \
: "=r" (__res) \
: "r" ((long)(arg1)),"r" ((long)(arg2)),"r" ((long)(arg3)),"r" ((long)(arg4)), \
"r" ((long)(arg5)) \
: "r0","r1","r2","r3","r4","lr"); \
__syscall_return(type,__res); \
}
_syscall1(int,exit1,int,status);
_syscall3(int,write,int,fd,const char *,buf, int, len);
void _start(void)
{
write(1, "Hello World\n", 12);
exit1(0);
}

View File

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

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;
}

View File

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

View File

@@ -77,4 +77,21 @@ myfunc2:
code16_end:
/* other 32 bits tests */
.code32
.globl func_lret32
func_lret32:
movl $0x87654321, %eax
lret
.globl func_iret32
func_iret32:
movl $0xabcd4321, %eax
iret

104
tests/test-i386-vm86.S Normal file
View File

@@ -0,0 +1,104 @@
.code16
.globl vm86_code_start
.globl vm86_code_end
#define GET_OFFSET(x) ((x) - vm86_code_start + 0x100)
vm86_code_start:
movw $GET_OFFSET(hello_world), %dx
movb $0x09, %ah
int $0x21
/* prepare int 0x90 vector */
xorw %ax, %ax
movw %ax, %es
es movw $GET_OFFSET(int90_test), 0x90 * 4
es movw %cs, 0x90 * 4 + 2
/* launch int 0x90 */
int $0x90
/* test IF support */
movw $GET_OFFSET(IF_msg), %dx
movb $0x09, %ah
int $0x21
pushf
popw %dx
movb $0xff, %ah
int $0x21
cli
pushf
popw %dx
movb $0xff, %ah
int $0x21
sti
pushfl
popl %edx
movb $0xff, %ah
int $0x21
#if 0
movw $GET_OFFSET(IF_msg1), %dx
movb $0x09, %ah
int $0x21
pushf
movw %sp, %bx
andw $~0x200, (%bx)
popf
#else
cli
#endif
pushf
popw %dx
movb $0xff, %ah
int $0x21
pushfl
movw %sp, %bx
orw $0x200, (%bx)
popfl
pushfl
popl %edx
movb $0xff, %ah
int $0x21
movb $0x00, %ah
int $0x21
int90_test:
pushf
pop %dx
movb $0xff, %ah
int $0x21
movw %sp, %bx
movw 4(%bx), %dx
movb $0xff, %ah
int $0x21
movw $GET_OFFSET(int90_msg), %dx
movb $0x09, %ah
int $0x21
iret
int90_msg:
.string "INT90 started\n$"
hello_world:
.string "Hello VM86 world\n$"
IF_msg:
.string "VM86 IF test\n$"
IF_msg1:
.string "If you see a diff here, your Linux kernel is buggy, please update to 2.4.20 kernel\n$"
vm86_code_end:

View File

@@ -1,9 +1,38 @@
/*
* 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>
#include <string.h>
#include <inttypes.h>
#include <math.h>
#include <signal.h>
#include <setjmp.h>
#include <errno.h>
#include <sys/ucontext.h>
#include <sys/mman.h>
#include <asm/vm86.h>
#define TEST_CMOV 0
#define TEST_CMOV 0
#define TEST_FCOMI 0
//#define LINUX_VM86_IOPL_FIX
#define xglue(x, y) x ## y
#define glue(x, y) xglue(x, y)
@@ -504,12 +533,28 @@ void test_fcmp(double a, double b)
a, b, a > b);
printf("(%f<=%f)=%d\n",
a, b, a >= b);
if (TEST_FCOMI) {
unsigned int eflags;
/* test f(u)comi instruction */
asm("fcomi %2, %1\n"
"pushf\n"
"pop %0\n"
: "=r" (eflags)
: "t" (a), "u" (b));
printf("fcomi(%f %f)=%08x\n", a, b, eflags & (CC_Z | CC_P | CC_C));
}
}
void test_fcvt(double a)
{
float fa;
long double la;
int16_t fpuc;
int i;
int64_t lla;
int ia;
int16_t wa;
double ra;
fa = a;
la = a;
@@ -518,9 +563,21 @@ void test_fcvt(double a)
printf("a=%016Lx\n", *(long long *)&a);
printf("la=%016Lx %04x\n", *(long long *)&la,
*(unsigned short *)((char *)(&la) + 8));
printf("a=%f floor(a)=%f\n", a, floor(a));
printf("a=%f ceil(a)=%f\n", a, ceil(a));
printf("a=%f rint(a)=%f\n", a, rint(a));
/* test all roundings */
asm volatile ("fstcw %0" : "=m" (fpuc));
for(i=0;i<4;i++) {
asm volatile ("fldcw %0" : : "m" ((fpuc & ~0x0c00) | (i << 10)));
asm volatile ("fist %0" : "=m" (wa) : "t" (a));
asm volatile ("fistl %0" : "=m" (ia) : "t" (a));
asm volatile ("fistpll %0" : "=m" (lla) : "t" (a) : "st");
asm volatile ("frndint ; fstl %0" : "=m" (ra) : "t" (a));
asm volatile ("fldcw %0" : : "m" (fpuc));
printf("(short)a = %d\n", wa);
printf("(int)a = %d\n", ia);
printf("(int64_t)a = %Ld\n", lla);
printf("rint(a) = %f\n", ra);
}
}
#define TEST(N) \
@@ -550,6 +607,57 @@ void test_fbcd(double a)
a, bcd[4], bcd[3], bcd[2], bcd[1], bcd[0], b);
}
#define TEST_ENV(env, prefix)\
{\
memset((env), 0xaa, sizeof(*(env)));\
asm("fld1\n"\
prefix "fnstenv %1\n"\
prefix "fldenv %1\n"\
: "=t" (res) : "m" (*(env)));\
printf("res=%f\n", res);\
printf("fpuc=%04x fpus=%04x fptag=%04x\n",\
(env)->fpuc,\
(env)->fpus & 0xff00,\
(env)->fptag);\
memset((env), 0xaa, sizeof(*(env)));\
asm("fld1\n"\
prefix "fnsave %1\n"\
prefix "frstor %1\n"\
: "=t" (res) : "m" (*(env)));\
printf("res=%f\n", res);\
printf("fpuc=%04x fpus=%04x fptag=%04x\n",\
(env)->fpuc,\
(env)->fpus & 0xff00,\
(env)->fptag);\
printf("ST(0) = %Lf\n",\
(env)->fpregs[0]);\
}
void test_fenv(void)
{
struct __attribute__((packed)) {
uint16_t fpuc;
uint16_t dummy1;
uint16_t fpus;
uint16_t dummy2;
uint16_t fptag;
uint16_t dummy3;
uint32_t ignored[4];
long double fpregs[8];
} float_env32;
struct __attribute__((packed)) {
uint16_t fpuc;
uint16_t fpus;
uint16_t fptag;
uint16_t ignored[4];
long double fpregs[8];
} float_env16;
double res;
TEST_ENV(&float_env16, "data16 ");
TEST_ENV(&float_env32, "");
}
void test_floats(void)
{
test_fops(2, 3);
@@ -557,12 +665,16 @@ void test_floats(void)
test_fcmp(2, -1);
test_fcmp(2, 2);
test_fcmp(2, 3);
test_fcvt(0.5);
test_fcvt(-0.5);
test_fcvt(1.0/7.0);
test_fcvt(-1.0/9.0);
test_fcvt(1e30);
test_fcvt(32768);
test_fcvt(-1e20);
test_fconst();
test_fbcd(1234567890123456);
test_fbcd(-123451234567890);
test_fenv();
}
/**********************************************/
@@ -707,6 +819,19 @@ uint8_t seg_data2[4096];
#define MK_SEL(n) (((n) << 3) | 7)
#define TEST_LR(op, size, seg, mask)\
{\
int res, res2;\
res = 0x12345678;\
asm (op " %" size "2, %" size "0\n" \
"movl $0, %1\n"\
"jnz 1f\n"\
"movl $1, %1\n"\
"1:\n"\
: "=r" (res), "=r" (res2) : "m" (seg), "0" (res));\
printf(op ": Z=%d %08x\n", res2, res & ~(mask));\
}
/* NOTE: we use Linux modify_ldt syscall */
void test_segs(void)
{
@@ -751,7 +876,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;
@@ -759,7 +883,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) */
@@ -784,6 +913,16 @@ void test_segs(void)
: "=r" (res), "=g" (res2)
: "m" (segoff));
printf("FS:reg = %04x:%08x\n", res2, res);
TEST_LR("larw", "w", MK_SEL(2), 0x0100);
TEST_LR("larl", "", MK_SEL(2), 0x0100);
TEST_LR("lslw", "w", MK_SEL(2), 0);
TEST_LR("lsll", "", MK_SEL(2), 0);
TEST_LR("larw", "w", 0xfff8, 0);
TEST_LR("larl", "", 0xfff8, 0);
TEST_LR("lslw", "w", 0xfff8, 0);
TEST_LR("lsll", "", 0xfff8, 0);
}
/* 16 bit code test */
@@ -824,6 +963,9 @@ void test_code16(void)
printf("func3() = 0x%08x\n", res);
}
extern char func_lret32;
extern char func_iret32;
void test_misc(void)
{
char table[256];
@@ -833,6 +975,26 @@ void test_misc(void)
res = 0x12345678;
asm ("xlat" : "=a" (res) : "b" (table), "0" (res));
printf("xlat: EAX=%08x\n", res);
asm volatile ("pushl %%cs ; call %1"
: "=a" (res)
: "m" (func_lret32): "memory", "cc");
printf("func_lret32=%x\n", res);
asm volatile ("pushfl ; pushl %%cs ; call %1"
: "=a" (res)
: "m" (func_iret32): "memory", "cc");
printf("func_iret32=%x\n", res);
/* specific popl test */
asm volatile ("pushl $12345432 ; pushl $0x9abcdef ; popl (%%esp) ; popl %0"
: "=g" (res));
printf("popl esp=%x\n", res);
/* 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];
@@ -890,6 +1052,438 @@ void test_string(void)
TEST_STRING(cmps, "repnz ");
}
/* VM86 test */
static inline void set_bit(uint8_t *a, unsigned int bit)
{
a[bit / 8] |= (1 << (bit % 8));
}
static inline uint8_t *seg_to_linear(unsigned int seg, unsigned int reg)
{
return (uint8_t *)((seg << 4) + (reg & 0xffff));
}
static inline void pushw(struct vm86_regs *r, int val)
{
r->esp = (r->esp & ~0xffff) | ((r->esp - 2) & 0xffff);
*(uint16_t *)seg_to_linear(r->ss, r->esp) = val;
}
#undef __syscall_return
#define __syscall_return(type, res) \
do { \
return (type) (res); \
} while (0)
_syscall2(int, vm86, int, func, struct vm86plus_struct *, v86)
extern char vm86_code_start;
extern char vm86_code_end;
#define VM86_CODE_CS 0x100
#define VM86_CODE_IP 0x100
void test_vm86(void)
{
struct vm86plus_struct ctx;
struct vm86_regs *r;
uint8_t *vm86_mem;
int seg, ret;
vm86_mem = mmap((void *)0x00000000, 0x110000,
PROT_WRITE | PROT_READ | PROT_EXEC,
MAP_FIXED | MAP_ANON | MAP_PRIVATE, -1, 0);
if (vm86_mem == MAP_FAILED) {
printf("ERROR: could not map vm86 memory");
return;
}
memset(&ctx, 0, sizeof(ctx));
/* init basic registers */
r = &ctx.regs;
r->eip = VM86_CODE_IP;
r->esp = 0xfffe;
seg = VM86_CODE_CS;
r->cs = seg;
r->ss = seg;
r->ds = seg;
r->es = seg;
r->fs = seg;
r->gs = seg;
r->eflags = VIF_MASK;
/* move code to proper address. We use the same layout as a .com
dos program. */
memcpy(vm86_mem + (VM86_CODE_CS << 4) + VM86_CODE_IP,
&vm86_code_start, &vm86_code_end - &vm86_code_start);
/* mark int 0x21 as being emulated */
set_bit((uint8_t *)&ctx.int_revectored, 0x21);
for(;;) {
ret = vm86(VM86_ENTER, &ctx);
switch(VM86_TYPE(ret)) {
case VM86_INTx:
{
int int_num, ah, v;
int_num = VM86_ARG(ret);
if (int_num != 0x21)
goto unknown_int;
ah = (r->eax >> 8) & 0xff;
switch(ah) {
case 0x00: /* exit */
goto the_end;
case 0x02: /* write char */
{
uint8_t c = r->edx;
putchar(c);
}
break;
case 0x09: /* write string */
{
uint8_t c, *ptr;
ptr = seg_to_linear(r->ds, r->edx);
for(;;) {
c = *ptr++;
if (c == '$')
break;
putchar(c);
}
r->eax = (r->eax & ~0xff) | '$';
}
break;
case 0xff: /* extension: write eflags number in edx */
v = (int)r->edx;
#ifndef LINUX_VM86_IOPL_FIX
v &= ~0x3000;
#endif
printf("%08x\n", v);
break;
default:
unknown_int:
printf("unsupported int 0x%02x\n", int_num);
goto the_end;
}
}
break;
case VM86_SIGNAL:
/* a signal came, we just ignore that */
break;
case VM86_STI:
break;
default:
printf("ERROR: unhandled vm86 return code (0x%x)\n", ret);
goto the_end;
}
}
the_end:
printf("VM86 end\n");
munmap(vm86_mem, 0x110000);
}
/* exception tests */
#ifndef REG_EAX
#define REG_EAX EAX
#define REG_EBX EBX
#define REG_ECX ECX
#define REG_EDX EDX
#define REG_ESI ESI
#define REG_EDI EDI
#define REG_EBP EBP
#define REG_ESP ESP
#define REG_EIP EIP
#define REG_EFL EFL
#define REG_TRAPNO TRAPNO
#define REG_ERR ERR
#endif
jmp_buf jmp_env;
int v1;
int tab[2];
void sig_handler(int sig, siginfo_t *info, void *puc)
{
struct ucontext *uc = puc;
printf("si_signo=%d si_errno=%d si_code=%d",
info->si_signo, info->si_errno, info->si_code);
printf(" si_addr=0x%08lx",
(unsigned long)info->si_addr);
printf("\n");
printf("trapno=0x%02x err=0x%08x",
uc->uc_mcontext.gregs[REG_TRAPNO],
uc->uc_mcontext.gregs[REG_ERR]);
printf(" EIP=0x%08x", uc->uc_mcontext.gregs[REG_EIP]);
printf("\n");
longjmp(jmp_env, 1);
}
void test_exceptions(void)
{
struct modify_ldt_ldt_s ldt;
struct sigaction act;
volatile int val;
act.sa_sigaction = sig_handler;
sigemptyset(&act.sa_mask);
act.sa_flags = SA_SIGINFO;
sigaction(SIGFPE, &act, NULL);
sigaction(SIGILL, &act, NULL);
sigaction(SIGSEGV, &act, NULL);
sigaction(SIGBUS, &act, NULL);
sigaction(SIGTRAP, &act, NULL);
/* test division by zero reporting */
printf("DIVZ exception:\n");
if (setjmp(jmp_env) == 0) {
/* now divide by zero */
v1 = 0;
v1 = 2 / v1;
}
printf("BOUND exception:\n");
if (setjmp(jmp_env) == 0) {
/* bound exception */
tab[0] = 1;
tab[1] = 10;
asm volatile ("bound %0, %1" : : "r" (11), "m" (tab));
}
printf("segment exceptions:\n");
if (setjmp(jmp_env) == 0) {
/* load an invalid segment */
asm volatile ("movl %0, %%fs" : : "r" ((0x1234 << 3) | 1));
}
if (setjmp(jmp_env) == 0) {
/* null data segment is valid */
asm volatile ("movl %0, %%fs" : : "r" (3));
/* null stack segment */
asm volatile ("movl %0, %%ss" : : "r" (3));
}
ldt.entry_number = 1;
ldt.base_addr = (unsigned long)&seg_data1;
ldt.limit = (sizeof(seg_data1) + 0xfff) >> 12;
ldt.seg_32bit = 1;
ldt.contents = MODIFY_LDT_CONTENTS_DATA;
ldt.read_exec_only = 0;
ldt.limit_in_pages = 1;
ldt.seg_not_present = 1;
ldt.useable = 1;
modify_ldt(1, &ldt, sizeof(ldt)); /* write ldt entry */
if (setjmp(jmp_env) == 0) {
/* segment not present */
asm volatile ("movl %0, %%fs" : : "r" (MK_SEL(1)));
}
/* test SEGV reporting */
printf("PF exception:\n");
if (setjmp(jmp_env) == 0) {
val = 1;
/* we add a nop to test a weird PC retrieval case */
asm volatile ("nop");
/* now store in an invalid address */
*(char *)0x1234 = 1;
}
/* test SEGV reporting */
printf("PF exception:\n");
if (setjmp(jmp_env) == 0) {
val = 1;
/* read from an invalid address */
v1 = *(char *)0x1234;
}
/* test illegal instruction reporting */
printf("UD2 exception:\n");
if (setjmp(jmp_env) == 0) {
/* now execute an invalid instruction */
asm volatile("ud2");
}
printf("INT exception:\n");
if (setjmp(jmp_env) == 0) {
asm volatile ("int $0xfd");
}
if (setjmp(jmp_env) == 0) {
asm volatile ("int $0x01");
}
if (setjmp(jmp_env) == 0) {
asm volatile (".byte 0xcd, 0x03");
}
if (setjmp(jmp_env) == 0) {
asm volatile ("int $0x04");
}
if (setjmp(jmp_env) == 0) {
asm volatile ("int $0x05");
}
printf("INT3 exception:\n");
if (setjmp(jmp_env) == 0) {
asm volatile ("int3");
}
printf("CLI exception:\n");
if (setjmp(jmp_env) == 0) {
asm volatile ("cli");
}
printf("STI exception:\n");
if (setjmp(jmp_env) == 0) {
asm volatile ("cli");
}
printf("INTO exception:\n");
if (setjmp(jmp_env) == 0) {
/* overflow exception */
asm volatile ("addl $1, %0 ; into" : : "r" (0x7fffffff));
}
printf("OUTB exception:\n");
if (setjmp(jmp_env) == 0) {
asm volatile ("outb %%al, %%dx" : : "d" (0x4321), "a" (0));
}
printf("INB exception:\n");
if (setjmp(jmp_env) == 0) {
asm volatile ("inb %%dx, %%al" : "=a" (val) : "d" (0x4321));
}
printf("REP OUTSB exception:\n");
if (setjmp(jmp_env) == 0) {
asm volatile ("rep outsb" : : "d" (0x4321), "S" (tab), "c" (1));
}
printf("REP INSB exception:\n");
if (setjmp(jmp_env) == 0) {
asm volatile ("rep insb" : : "d" (0x4321), "D" (tab), "c" (1));
}
printf("HLT exception:\n");
if (setjmp(jmp_env) == 0) {
asm volatile ("hlt");
}
printf("single step exception:\n");
val = 0;
if (setjmp(jmp_env) == 0) {
asm volatile ("pushf\n"
"orl $0x00100, (%%esp)\n"
"popf\n"
"movl $0xabcd, %0\n"
"movl $0x0, %0\n" : "=m" (val) : : "cc", "memory");
}
printf("val=0x%x\n", val);
}
/* 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 */
0xc3, /* ret */
};
typedef int FuncType(void);
void test_self_modifying_code(void)
{
int i;
printf("self modifying code:\n");
printf("func1 = 0x%x\n", ((FuncType *)code)());
for(i = 2; i <= 4; i++) {
code[1] = i;
printf("func%d = 0x%x\n", i, ((FuncType *)code)());
}
}
static void *call_end __init_call = NULL;
int main(int argc, char **argv)
@@ -913,5 +1507,9 @@ int main(int argc, char **argv)
test_lea();
test_segs();
test_code16();
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;
}

Some files were not shown because too many files have changed in this diff Show More