Compare commits

...

730 Commits

Author SHA1 Message Date
(no author)
2f5ab9e8cd This commit was manufactured by cvs2svn to create tag
'release_0_6_1'.

git-svn-id: svn://svn.savannah.nongnu.org/qemu/tags/release_0_6_1@1149 c046a42c-6fe2-441c-8c8c-71466251a162
2004-11-14 20:52:55 +00:00
bellard
c72a345f5b do not remove docs
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1148 c046a42c-6fe2-441c-8c8c-71466251a162
2004-11-14 20:52:54 +00:00
bellard
102a52e471 FMOD configure options (malc)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1147 c046a42c-6fe2-441c-8c8c-71466251a162
2004-11-14 19:57:29 +00:00
bellard
c76338c34f update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1146 c046a42c-6fe2-441c-8c8c-71466251a162
2004-11-14 19:52:18 +00:00
bellard
bf2b84e4a7 better ctrl-alt handling, at least for SDL/X11
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1145 c046a42c-6fe2-441c-8c8c-71466251a162
2004-11-14 19:46:35 +00:00
bellard
9f059eca52 win32/SDL build fixes
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1144 c046a42c-6fe2-441c-8c8c-71466251a162
2004-11-14 18:59:52 +00:00
bellard
53360e00e2 update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1143 c046a42c-6fe2-441c-8c8c-71466251a162
2004-11-14 18:58:40 +00:00
bellard
ef6ff6b71e removed warning
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1142 c046a42c-6fe2-441c-8c8c-71466251a162
2004-11-14 18:58:04 +00:00
bellard
546fa6abd1 vga font change detection
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1141 c046a42c-6fe2-441c-8c8c-71466251a162
2004-11-14 17:52:01 +00:00
bellard
e875c40a15 indent fixes
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1140 c046a42c-6fe2-441c-8c8c-71466251a162
2004-11-14 17:30:35 +00:00
bellard
a98d49b136 Mac OS compile fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1139 c046a42c-6fe2-441c-8c8c-71466251a162
2004-11-14 16:22:05 +00:00
bellard
44a095a77c mmap audio fix (malc)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1138 c046a42c-6fe2-441c-8c8c-71466251a162
2004-11-14 16:02:51 +00:00
bellard
15b6147000 audio fix (malc)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1137 c046a42c-6fe2-441c-8c8c-71466251a162
2004-11-14 16:02:09 +00:00
bellard
9e89a4be8e boot device 'b' is not supported
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1136 c046a42c-6fe2-441c-8c8c-71466251a162
2004-11-14 15:42:27 +00:00
bellard
61a8c4ec3a enter insn fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1135 c046a42c-6fe2-441c-8c8c-71466251a162
2004-11-14 15:39:16 +00:00
bellard
9746b15b4e 'info mem' monitor command fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1134 c046a42c-6fe2-441c-8c8c-71466251a162
2004-11-11 18:30:24 +00:00
bellard
7372f88dc1 audio fixes (malc)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1133 c046a42c-6fe2-441c-8c8c-71466251a162
2004-11-11 16:55:09 +00:00
bellard
d7382233d8 audio clean up (initial patch by malc)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1132 c046a42c-6fe2-441c-8c8c-71466251a162
2004-11-10 00:16:34 +00:00
bellard
fb065187e4 audio clean up (initial patch by malc)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1131 c046a42c-6fe2-441c-8c8c-71466251a162
2004-11-09 23:09:44 +00:00
bellard
bf71c9d9b6 disabled again register usage for ppc because my previous patch seems still buggy
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1130 c046a42c-6fe2-441c-8c8c-71466251a162
2004-11-09 22:12:08 +00:00
bellard
7a987127f4 bit mask conversion fix (Harald Welte
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1129 c046a42c-6fe2-441c-8c8c-71466251a162
2004-11-09 22:08:48 +00:00
bellard
e0fe67aa72 enabled DMA
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1128 c046a42c-6fe2-441c-8c8c-71466251a162
2004-11-09 22:04:05 +00:00
bellard
f6c958c865 CRTC register write protection fix - line_compare, multi_scan and double_scan fixes
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1127 c046a42c-6fe2-441c-8c8c-71466251a162
2004-11-07 22:57:20 +00:00
bellard
9bb34eac8b CRTC register write protection fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1126 c046a42c-6fe2-441c-8c8c-71466251a162
2004-11-07 22:54:14 +00:00
bellard
85571bc741 audio merge (malc)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1125 c046a42c-6fe2-441c-8c8c-71466251a162
2004-11-07 18:04:02 +00:00
bellard
8f46820d92 update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1124 c046a42c-6fe2-441c-8c8c-71466251a162
2004-11-07 17:44:42 +00:00
bellard
dbb2c92142 SDL config fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1123 c046a42c-6fe2-441c-8c8c-71466251a162
2004-10-24 22:17:47 +00:00
bellard
0d1a29f9fc correct handling of saved host registers
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1122 c046a42c-6fe2-441c-8c8c-71466251a162
2004-10-12 22:01:28 +00:00
bellard
b8b5ac6376 do not assume signed char
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1121 c046a42c-6fe2-441c-8c8c-71466251a162
2004-10-12 21:52:40 +00:00
bellard
40b6ecc6bc no need to use LARGE translation
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1120 c046a42c-6fe2-441c-8c8c-71466251a162
2004-10-12 21:50:05 +00:00
bellard
f3ff649d3b openpty fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1119 c046a42c-6fe2-441c-8c8c-71466251a162
2004-10-10 18:00:00 +00:00
bellard
953569d21b fdc fix (Mike Nordell)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1118 c046a42c-6fe2-441c-8c8c-71466251a162
2004-10-10 17:51:13 +00:00
bellard
a0c4cb4a70 sparc fixes
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1117 c046a42c-6fe2-441c-8c8c-71466251a162
2004-10-10 17:46:24 +00:00
bellard
188d857911 limited 8 bit support - removed unaligned memory accesses in VGA (initial patch by Johannes Schindelin)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1116 c046a42c-6fe2-441c-8c8c-71466251a162
2004-10-10 15:44:19 +00:00
bellard
9bc9d1c75a info version command
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1115 c046a42c-6fe2-441c-8c8c-71466251a162
2004-10-10 15:15:51 +00:00
bellard
8926b517e9 faster Cirrus VGA VRAM access
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1114 c046a42c-6fe2-441c-8c8c-71466251a162
2004-10-10 15:14:20 +00:00
bellard
6d46bf8ae3 win32 fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1113 c046a42c-6fe2-441c-8c8c-71466251a162
2004-10-09 22:57:43 +00:00
bellard
032a8c9e35 help fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1112 c046a42c-6fe2-441c-8c8c-71466251a162
2004-10-09 22:56:44 +00:00
bellard
a7dfe172fa IDE standby fix for Linux 2.6 guest - segfault fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1111 c046a42c-6fe2-441c-8c8c-71466251a162
2004-10-09 20:27:55 +00:00
bellard
7fe48483cd monitor fixes
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1110 c046a42c-6fe2-441c-8c8c-71466251a162
2004-10-09 18:08:01 +00:00
bellard
8e3a9fd280 monitor fixes (Johannes Schindelin)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1109 c046a42c-6fe2-441c-8c8c-71466251a162
2004-10-09 17:32:58 +00:00
bellard
d75d9f6be9 SDL Audio support and SB16 fixes (malc)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1108 c046a42c-6fe2-441c-8c8c-71466251a162
2004-10-09 17:20:54 +00:00
bellard
769bec7271 IDE fix for NT4 (Ben Pfaf)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1107 c046a42c-6fe2-441c-8c8c-71466251a162
2004-10-09 16:48:57 +00:00
bellard
655aa52a90 update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1106 c046a42c-6fe2-441c-8c8c-71466251a162
2004-10-09 16:48:17 +00:00
bellard
ba6c23778c cmos init for IDE (Ben Pfaf)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1105 c046a42c-6fe2-441c-8c8c-71466251a162
2004-10-09 16:47:59 +00:00
bellard
4b19ec0c2b spelling fixes
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1104 c046a42c-6fe2-441c-8c8c-71466251a162
2004-10-09 16:44:33 +00:00
bellard
e388818682 BSD getopt fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1103 c046a42c-6fe2-441c-8c8c-71466251a162
2004-10-09 16:44:06 +00:00
bellard
02d2c54cd3 windows fixes (Gregory Alexander)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1102 c046a42c-6fe2-441c-8c8c-71466251a162
2004-10-07 23:27:35 +00:00
bellard
890fa6bebb floppy fixes (initial patch by Mike Nordell)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1101 c046a42c-6fe2-441c-8c8c-71466251a162
2004-10-07 23:10:29 +00:00
bellard
a4c4785b93 floppy fix from Volker Ruppert
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1100 c046a42c-6fe2-441c-8c8c-71466251a162
2004-10-07 21:27:06 +00:00
bellard
7993f8bc51 sparc merge (Blue Swirl)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1099 c046a42c-6fe2-441c-8c8c-71466251a162
2004-10-04 23:42:21 +00:00
bellard
8d5f07fa3b sparc merge (Blue Swirl)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1098 c046a42c-6fe2-441c-8c8c-71466251a162
2004-10-04 21:23:09 +00:00
bellard
023fcb9507 update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1097 c046a42c-6fe2-441c-8c8c-71466251a162
2004-10-03 21:48:00 +00:00
bellard
a5ba1ca608 BIOS floppy fix for NT4 (Mike Nordell, Derek Fawcus)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1096 c046a42c-6fe2-441c-8c8c-71466251a162
2004-10-03 21:47:33 +00:00
bellard
b769d8fef6 removed access_type hack
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1095 c046a42c-6fe2-441c-8c8c-71466251a162
2004-10-03 15:07:13 +00:00
bellard
32ff25bf68 ctrl-alt is the default grab key - reset modifiers when toggling grab state
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1094 c046a42c-6fe2-441c-8c8c-71466251a162
2004-10-03 14:33:54 +00:00
bellard
f98593103b update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1093 c046a42c-6fe2-441c-8c8c-71466251a162
2004-10-03 14:33:10 +00:00
bellard
30ca2aab8e ne2000 savevm support (Johannes Schindelin)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1092 c046a42c-6fe2-441c-8c8c-71466251a162
2004-10-03 13:56:00 +00:00
bellard
8a8a608f6e use memset() (Daniel Egger)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1091 c046a42c-6fe2-441c-8c8c-71466251a162
2004-10-03 13:36:49 +00:00
bellard
d63d307f6e -loadvm and -full-screen options
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1090 c046a42c-6fe2-441c-8c8c-71466251a162
2004-10-03 13:29:03 +00:00
bellard
487be8a1a7 hack for bootp support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1089 c046a42c-6fe2-441c-8c8c-71466251a162
2004-10-03 11:44:41 +00:00
bellard
2518bd0dc2 update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1088 c046a42c-6fe2-441c-8c8c-71466251a162
2004-09-30 22:35:13 +00:00
bellard
e95c8d51c2 full system SPARC emulation (Blue Swirl)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1087 c046a42c-6fe2-441c-8c8c-71466251a162
2004-09-30 22:22:08 +00:00
bellard
4971b827da pointer arith fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1086 c046a42c-6fe2-441c-8c8c-71466251a162
2004-09-30 22:19:55 +00:00
bellard
420557e898 full system SPARC emulation (Blue Swirl)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1085 c046a42c-6fe2-441c-8c8c-71466251a162
2004-09-30 22:13:50 +00:00
bellard
6d5e216de9 SPARC fixes (Blue Swirl)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1084 c046a42c-6fe2-441c-8c8c-71466251a162
2004-09-30 22:04:13 +00:00
bellard
e8af50a30e full system SPARC emulation (Blue Swirl)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1083 c046a42c-6fe2-441c-8c8c-71466251a162
2004-09-30 21:55:55 +00:00
bellard
525d67bcc8 update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1082 c046a42c-6fe2-441c-8c8c-71466251a162
2004-09-30 18:58:48 +00:00
bellard
d981b88344 give a new address at DHCPREQUEST too (useful if the OS remembers its IP address
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1081 c046a42c-6fe2-441c-8c8c-71466251a162
2004-09-30 18:57:28 +00:00
bellard
4a4883b84d update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1080 c046a42c-6fe2-441c-8c8c-71466251a162
2004-09-29 22:47:43 +00:00
bellard
16c460b154 update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1079 c046a42c-6fe2-441c-8c8c-71466251a162
2004-09-29 21:56:51 +00:00
bellard
0ecf89aae3 level triggered IRQ fix (Steve Wormley)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1078 c046a42c-6fe2-441c-8c8c-71466251a162
2004-09-29 21:55:52 +00:00
bellard
28d34b8246 zlib.h is an external header
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1077 c046a42c-6fe2-441c-8c8c-71466251a162
2004-09-29 21:30:43 +00:00
bellard
3c56521b70 cloop driver (Johannes Schindelin)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1076 c046a42c-6fe2-441c-8c8c-71466251a162
2004-09-29 21:29:14 +00:00
bellard
096b7ea42b win32 load_kernel() fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1075 c046a42c-6fe2-441c-8c8c-71466251a162
2004-09-29 21:19:16 +00:00
bellard
d5a8f07c52 no data exec support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1074 c046a42c-6fe2-441c-8c8c-71466251a162
2004-09-29 21:15:28 +00:00
bellard
345fbaa3ca removed unused prototype
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1073 c046a42c-6fe2-441c-8c8c-71466251a162
2004-09-18 19:36:08 +00:00
bellard
1d96905d76 fixed stdio write
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1072 c046a42c-6fe2-441c-8c8c-71466251a162
2004-09-18 19:34:39 +00:00
bellard
99679ececc removed warning
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1071 c046a42c-6fe2-441c-8c8c-71466251a162
2004-09-18 19:33:56 +00:00
bellard
eb45f5fec4 prototype fixed
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1070 c046a42c-6fe2-441c-8c8c-71466251a162
2004-09-18 19:33:09 +00:00
bellard
b86bda5bb1 adde TLB dump
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1069 c046a42c-6fe2-441c-8c8c-71466251a162
2004-09-18 19:32:46 +00:00
bellard
e2731add29 fixed block close() method prototype
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1068 c046a42c-6fe2-441c-8c8c-71466251a162
2004-09-18 19:32:11 +00:00
bellard
c9a621176e memory leak fix (Juergen Keil)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1067 c046a42c-6fe2-441c-8c8c-71466251a162
2004-09-13 21:42:51 +00:00
bellard
cf720db33a uname fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1066 c046a42c-6fe2-441c-8c8c-71466251a162
2004-09-13 21:41:39 +00:00
bellard
29e619b1e8 uname + sysctl fix (Paul Brook)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1065 c046a42c-6fe2-441c-8c8c-71466251a162
2004-09-13 21:41:04 +00:00
bellard
6f28fb86c9 zero file case (Paul Brook)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1064 c046a42c-6fe2-441c-8c8c-71466251a162
2004-09-13 21:39:32 +00:00
bellard
c94c8d6499 win32 + Mac OS X compile
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1063 c046a42c-6fe2-441c-8c8c-71466251a162
2004-09-13 21:37:34 +00:00
bellard
01038d2a76 monitor fix (Derek Fawcus)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1062 c046a42c-6fe2-441c-8c8c-71466251a162
2004-09-13 21:36:46 +00:00
bellard
03ffbb69a8 smb config fix for NT
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1061 c046a42c-6fe2-441c-8c8c-71466251a162
2004-09-06 00:14:04 +00:00
bellard
a3d4af03bb allow inetd like program exec
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1060 c046a42c-6fe2-441c-8c8c-71466251a162
2004-09-05 23:10:26 +00:00
bellard
9d728e8c4e smb support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1059 c046a42c-6fe2-441c-8c8c-71466251a162
2004-09-05 23:09:03 +00:00
bellard
36d54d15e1 update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1058 c046a42c-6fe2-441c-8c8c-71466251a162
2004-09-05 16:04:16 +00:00
bellard
c4dfa5b7be removed duplicated option
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1057 c046a42c-6fe2-441c-8c8c-71466251a162
2004-08-29 13:10:18 +00:00
bellard
75c2380584 fixed image creation with base filename
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1056 c046a42c-6fe2-441c-8c8c-71466251a162
2004-08-27 21:28:58 +00:00
bellard
7c08dbf325 endianness fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1055 c046a42c-6fe2-441c-8c8c-71466251a162
2004-08-25 22:30:56 +00:00
bellard
9bf05444b2 port redirection support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1054 c046a42c-6fe2-441c-8c8c-71466251a162
2004-08-25 22:12:49 +00:00
bellard
a3504c87ca removed gettimeofday usage
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1053 c046a42c-6fe2-441c-8c8c-71466251a162
2004-08-25 20:55:44 +00:00
bellard
7143c62c95 vmdk 3 fixes
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1052 c046a42c-6fe2-441c-8c8c-71466251a162
2004-08-25 20:50:14 +00:00
bellard
4e8b5da233 MULSCC fix (Blue Swirl)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1051 c046a42c-6fe2-441c-8c8c-71466251a162
2004-08-24 22:06:03 +00:00
bellard
c7f746434f TFTP support (Magnus Damm)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1050 c046a42c-6fe2-441c-8c8c-71466251a162
2004-08-24 21:57:12 +00:00
bellard
60e336dbb8 serial interrupt fix (Hampa Hug)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1049 c046a42c-6fe2-441c-8c8c-71466251a162
2004-08-24 21:55:28 +00:00
bellard
8d11df9e5a multiple serial port support - terminal init fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1048 c046a42c-6fe2-441c-8c8c-71466251a162
2004-08-24 21:13:40 +00:00
bellard
05d5818c5c update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1047 c046a42c-6fe2-441c-8c8c-71466251a162
2004-08-24 21:12:04 +00:00
bellard
cabf23c380 bound instruction fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1046 c046a42c-6fe2-441c-8c8c-71466251a162
2004-08-15 14:51:07 +00:00
bellard
e82d8ade13 fixed bound memory reference
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1045 c046a42c-6fe2-441c-8c8c-71466251a162
2004-08-15 14:47:30 +00:00
bellard
d2bfb39ad2 use the kernel sigaction syscall to avoid relying on glibc one
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1044 c046a42c-6fe2-441c-8c8c-71466251a162
2004-08-03 22:09:30 +00:00
bellard
3611a29c09 -fno-gcse option for opcodes to use asm macros with gcc >= 3.3 on i386 (Piotr Krysik)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1043 c046a42c-6fe2-441c-8c8c-71466251a162
2004-08-03 21:42:45 +00:00
bellard
0f6e3eb211 enabled asm memory helpers
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1042 c046a42c-6fe2-441c-8c8c-71466251a162
2004-08-03 21:37:41 +00:00
bellard
57d1a2b62c win32 port
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1041 c046a42c-6fe2-441c-8c8c-71466251a162
2004-08-03 21:15:11 +00:00
bellard
d5249393ef 64 bit file I/O by default
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1040 c046a42c-6fe2-441c-8c8c-71466251a162
2004-08-03 21:14:23 +00:00
bellard
11c0315f9b update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1039 c046a42c-6fe2-441c-8c8c-71466251a162
2004-08-01 22:05:00 +00:00
bellard
a3fb0cf907 removed unneeded tools
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1038 c046a42c-6fe2-441c-8c8c-71466251a162
2004-08-01 22:00:34 +00:00
bellard
ea2384d36e new disk image layer
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1037 c046a42c-6fe2-441c-8c8c-71466251a162
2004-08-01 21:59:26 +00:00
bellard
e4d4fe3c34 AES crypto support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1036 c046a42c-6fe2-441c-8c8c-71466251a162
2004-08-01 21:54:53 +00:00
bellard
5905b2e5fd password input support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1035 c046a42c-6fe2-441c-8c8c-71466251a162
2004-08-01 21:53:26 +00:00
bellard
7e2515e87c separated readline from monitor code - added password input support - added output buffer
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1034 c046a42c-6fe2-441c-8c8c-71466251a162
2004-08-01 21:52:19 +00:00
bellard
3d2cfdf169 output disassembled code to monitor console
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1033 c046a42c-6fe2-441c-8c8c-71466251a162
2004-08-01 21:49:07 +00:00
bellard
6fcfafb742 console focus support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1032 c046a42c-6fe2-441c-8c8c-71466251a162
2004-08-01 21:48:30 +00:00
bellard
af8ffdfd2b byte swap functions
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1031 c046a42c-6fe2-441c-8c8c-71466251a162
2004-08-01 21:48:12 +00:00
bellard
b932caba32 new disk image layer
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1030 c046a42c-6fe2-441c-8c8c-71466251a162
2004-08-01 21:46:49 +00:00
bellard
3eb2619fe5 update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1029 c046a42c-6fe2-441c-8c8c-71466251a162
2004-07-14 19:20:07 +00:00
bellard
3e11db9a0c update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1028 c046a42c-6fe2-441c-8c8c-71466251a162
2004-07-14 17:47:14 +00:00
bellard
c6f37d0e4f virtual console
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1027 c046a42c-6fe2-441c-8c8c-71466251a162
2004-07-14 17:39:50 +00:00
bellard
a0a821a4c0 update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1026 c046a42c-6fe2-441c-8c8c-71466251a162
2004-07-14 17:38:57 +00:00
bellard
49b3b9fb1a update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1025 c046a42c-6fe2-441c-8c8c-71466251a162
2004-07-14 17:31:32 +00:00
bellard
e7f0ad58c1 virtual console
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1024 c046a42c-6fe2-441c-8c8c-71466251a162
2004-07-14 17:28:59 +00:00
bellard
82c643ff50 char device support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1023 c046a42c-6fe2-441c-8c8c-71466251a162
2004-07-14 17:28:13 +00:00
bellard
457831f4bc virtual console support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1022 c046a42c-6fe2-441c-8c8c-71466251a162
2004-07-14 17:22:33 +00:00
bellard
2571929a77 added qemu_strdup()
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1021 c046a42c-6fe2-441c-8c8c-71466251a162
2004-07-14 17:21:57 +00:00
bellard
81d0912d2d completion support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1020 c046a42c-6fe2-441c-8c8c-71466251a162
2004-07-14 17:21:37 +00:00
bellard
d1d9f42119 compile fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1019 c046a42c-6fe2-441c-8c8c-71466251a162
2004-07-14 17:20:55 +00:00
bellard
450e18b8b8 slirp for win32 support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1018 c046a42c-6fe2-441c-8c8c-71466251a162
2004-07-14 17:20:11 +00:00
bellard
3db38e87a0 virtual console support - slirp for win32 support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1017 c046a42c-6fe2-441c-8c8c-71466251a162
2004-07-14 17:19:55 +00:00
bellard
379ff53dc9 win32 compile
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1016 c046a42c-6fe2-441c-8c8c-71466251a162
2004-07-12 22:33:07 +00:00
bellard
ce93da6ffe win32 compile
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1015 c046a42c-6fe2-441c-8c8c-71466251a162
2004-07-12 21:21:31 +00:00
bellard
ee2654ac24 removed unused includes - BSD port
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1014 c046a42c-6fe2-441c-8c8c-71466251a162
2004-07-12 21:11:45 +00:00
bellard
354ff22657 avoid warning
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1013 c046a42c-6fe2-441c-8c8c-71466251a162
2004-07-12 20:40:05 +00:00
bellard
6b65279459 comment
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1012 c046a42c-6fe2-441c-8c8c-71466251a162
2004-07-12 20:33:47 +00:00
bellard
12c28fed49 adb fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1011 c046a42c-6fe2-441c-8c8c-71466251a162
2004-07-12 20:26:20 +00:00
bellard
38f0b147a5 fixed ADB error reporting
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1010 c046a42c-6fe2-441c-8c8c-71466251a162
2004-07-12 20:16:00 +00:00
bellard
bec9d989db fixed register 0 usage - fixed mouse buttons
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1009 c046a42c-6fe2-441c-8c8c-71466251a162
2004-07-12 20:15:26 +00:00
bellard
cab84d9844 Mac OS X port (Pierre d'Herbemont)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1008 c046a42c-6fe2-441c-8c8c-71466251a162
2004-07-12 18:51:50 +00:00
bellard
1b039c09fe OS X port
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1007 c046a42c-6fe2-441c-8c8c-71466251a162
2004-07-12 18:39:45 +00:00
bellard
fbf59244b8 static build fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1005 c046a42c-6fe2-441c-8c8c-71466251a162
2004-07-10 18:18:19 +00:00
bellard
fa36761d7f ppc bios version 0.3
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1004 c046a42c-6fe2-441c-8c8c-71466251a162
2004-07-10 16:57:29 +00:00
bellard
d08c49aae0 update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1003 c046a42c-6fe2-441c-8c8c-71466251a162
2004-07-10 16:40:19 +00:00
bellard
fcc941fe20 added .cvsignore
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1002 c046a42c-6fe2-441c-8c8c-71466251a162
2004-07-10 16:28:35 +00:00
bellard
96bcd4f884 Mac OS X port
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1001 c046a42c-6fe2-441c-8c8c-71466251a162
2004-07-10 16:26:15 +00:00
bellard
e3371e62f3 update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1000 c046a42c-6fe2-441c-8c8c-71466251a162
2004-07-10 16:26:02 +00:00
bellard
82eec0a174 Mac OS X port (Pierre d'Herbemont)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@999 c046a42c-6fe2-441c-8c8c-71466251a162
2004-07-10 16:22:18 +00:00
bellard
933dc6ebc4 Mac OS X port
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@998 c046a42c-6fe2-441c-8c8c-71466251a162
2004-07-10 15:33:29 +00:00
bellard
1e6cae953d comment
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@997 c046a42c-6fe2-441c-8c8c-71466251a162
2004-07-10 15:31:19 +00:00
bellard
6d463de2b3 removed stdout reference (not portable)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@996 c046a42c-6fe2-441c-8c8c-71466251a162
2004-07-10 15:28:48 +00:00
bellard
bbbc4663d1 removed unused definitions
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@995 c046a42c-6fe2-441c-8c8c-71466251a162
2004-07-10 15:27:59 +00:00
bellard
02e1ec9bc4 Mac OS X port (Pierre d'Herbemont)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@994 c046a42c-6fe2-441c-8c8c-71466251a162
2004-07-10 15:15:39 +00:00
bellard
3df3f6fd7b odd memory access fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@993 c046a42c-6fe2-441c-8c8c-71466251a162
2004-07-10 14:45:19 +00:00
bellard
2c6ab8329e load/save state support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@992 c046a42c-6fe2-441c-8c8c-71466251a162
2004-07-10 13:41:46 +00:00
bellard
675376f2b4 kbd save/restore
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@991 c046a42c-6fe2-441c-8c8c-71466251a162
2004-07-10 13:39:53 +00:00
bellard
15a34c6364 doc update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@990 c046a42c-6fe2-441c-8c8c-71466251a162
2004-07-08 21:26:26 +00:00
bellard
1bfe856eb2 Cirrus VGA is the default - 128 MB default memory - 800x600 default PPC resolution
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@989 c046a42c-6fe2-441c-8c8c-71466251a162
2004-07-08 21:17:50 +00:00
bellard
7e71f16f9a update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@988 c046a42c-6fe2-441c-8c8c-71466251a162
2004-07-08 21:16:21 +00:00
bellard
38a64f9dfe fixed b[l] decoding
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@987 c046a42c-6fe2-441c-8c8c-71466251a162
2004-07-07 22:06:01 +00:00
bellard
e02aa6869e suppressed unused function
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@986 c046a42c-6fe2-441c-8c8c-71466251a162
2004-07-07 22:04:21 +00:00
bellard
7db4eea691 removed unused code
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@985 c046a42c-6fe2-441c-8c8c-71466251a162
2004-07-06 20:57:47 +00:00
bellard
b30d4608da 24 bpp fixes
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@984 c046a42c-6fe2-441c-8c8c-71466251a162
2004-07-06 01:50:49 +00:00
bellard
81ca79911a 24 bpp mode fixes
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@983 c046a42c-6fe2-441c-8c8c-71466251a162
2004-07-06 01:47:47 +00:00
bellard
e58d12ed5b Darwin patch
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@982 c046a42c-6fe2-441c-8c8c-71466251a162
2004-07-05 22:13:07 +00:00
bellard
d549f7d98f Darwin patch (initial patch by Pierre d'Herbemont)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@981 c046a42c-6fe2-441c-8c8c-71466251a162
2004-07-05 21:47:44 +00:00
bellard
83fb7adf6c Darwin patch (initial patch by Pierre d'Herbemont)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@980 c046a42c-6fe2-441c-8c8c-71466251a162
2004-07-05 21:25:26 +00:00
bellard
1d43a71773 forgot fclose()
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@979 c046a42c-6fe2-441c-8c8c-71466251a162
2004-07-05 21:18:42 +00:00
bellard
ae184e4ab7 dac write index register is r/w - CR1D access fix (Volker Ruppert)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@978 c046a42c-6fe2-441c-8c8c-71466251a162
2004-06-26 16:13:19 +00:00
bellard
e6eccb38eb dac write index register is r/w (Volker Ruppert)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@977 c046a42c-6fe2-441c-8c8c-71466251a162
2004-06-26 16:12:26 +00:00
bellard
9da9886121 fixed case where ram < 16 MB
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@976 c046a42c-6fe2-441c-8c8c-71466251a162
2004-06-26 15:53:17 +00:00
bellard
a1968d7196 RT signal may not be a good idea
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@975 c046a42c-6fe2-441c-8c8c-71466251a162
2004-06-25 17:06:27 +00:00
bellard
7f5d44e0ff new Cirrus VGA BIOS from the LGPL'ed VGA BIOS project including VESA support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@974 c046a42c-6fe2-441c-8c8c-71466251a162
2004-06-25 15:02:13 +00:00
bellard
acf5feac80 hlt instruction fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@973 c046a42c-6fe2-441c-8c8c-71466251a162
2004-06-25 14:58:58 +00:00
bellard
d187d4b218 configure BMDMA
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@972 c046a42c-6fe2-441c-8c8c-71466251a162
2004-06-25 14:55:10 +00:00
bellard
9808745072 BMDMA support - CDROM fixes
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@971 c046a42c-6fe2-441c-8c8c-71466251a162
2004-06-25 14:54:19 +00:00
bellard
02ba45c536 use RT signal for /dev/rtc - restore stdin flags (Bob Barry) - cpu save fix (Johannes Schindelin)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@970 c046a42c-6fe2-441c-8c8c-71466251a162
2004-06-25 14:46:23 +00:00
bellard
107db44327 consider that all archs have SMC (workaround)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@969 c046a42c-6fe2-441c-8c8c-71466251a162
2004-06-22 18:48:46 +00:00
bellard
dc5d0b3d1b disable buggy tb_invalidate_page_range()
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@968 c046a42c-6fe2-441c-8c8c-71466251a162
2004-06-22 18:43:30 +00:00
bellard
7496f5266c cpu_single_env init
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@967 c046a42c-6fe2-441c-8c8c-71466251a162
2004-06-22 10:56:50 +00:00
bellard
91d848ebf3 disable PCI device for PMAC
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@966 c046a42c-6fe2-441c-8c8c-71466251a162
2004-06-21 22:46:48 +00:00
bellard
e2733d20b2 ADB fixes
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@965 c046a42c-6fe2-441c-8c8c-71466251a162
2004-06-21 22:46:10 +00:00
bellard
637f6cd735 ppc bios
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@964 c046a42c-6fe2-441c-8c8c-71466251a162
2004-06-21 19:54:47 +00:00
bellard
638260eb8e update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@963 c046a42c-6fe2-441c-8c8c-71466251a162
2004-06-21 19:54:19 +00:00
bellard
30468f786c added PCI bus - added IRQ support for PowerPC bridges - suppressed PREP PCI bios init
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@962 c046a42c-6fe2-441c-8c8c-71466251a162
2004-06-21 19:45:35 +00:00
bellard
46e50e9d58 added PCI bus
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@961 c046a42c-6fe2-441c-8c8c-71466251a162
2004-06-21 19:43:00 +00:00
bellard
7c29d0c0cf dma init fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@960 c046a42c-6fe2-441c-8c8c-71466251a162
2004-06-21 16:58:50 +00:00
bellard
514fb8c10e removed traces
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@959 c046a42c-6fe2-441c-8c8c-71466251a162
2004-06-21 16:57:45 +00:00
bellard
53c862a88e endianness fixes
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@958 c046a42c-6fe2-441c-8c8c-71466251a162
2004-06-21 16:56:45 +00:00
bellard
b6b8bd1819 ppc init fixes
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@957 c046a42c-6fe2-441c-8c8c-71466251a162
2004-06-21 16:55:53 +00:00
bellard
fd0bbb12c3 cmdline init fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@956 c046a42c-6fe2-441c-8c8c-71466251a162
2004-06-21 16:53:42 +00:00
bellard
f2aa58c6f4 UniNorth PCI bridge support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@955 c046a42c-6fe2-441c-8c8c-71466251a162
2004-06-21 16:52:24 +00:00
bellard
611493d966 openpic fixes
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@954 c046a42c-6fe2-441c-8c8c-71466251a162
2004-06-21 16:50:43 +00:00
bellard
e1bb04f740 memory mapped NVRAM (Jocelyn Mayer)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@953 c046a42c-6fe2-441c-8c8c-71466251a162
2004-06-21 16:49:53 +00:00
bellard
1ade1de223 pmac macio based ide support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@952 c046a42c-6fe2-441c-8c8c-71466251a162
2004-06-21 16:48:36 +00:00
bellard
b0bda528c3 high page register support for PPC PREP
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@951 c046a42c-6fe2-441c-8c8c-71466251a162
2004-06-21 16:47:42 +00:00
bellard
819e712bfe cuda fixes
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@950 c046a42c-6fe2-441c-8c8c-71466251a162
2004-06-21 16:47:13 +00:00
bellard
28b9b5af25 ppc update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@949 c046a42c-6fe2-441c-8c8c-71466251a162
2004-06-21 16:46:35 +00:00
bellard
e9b137c2dd added -g option for OF initial resolution
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@948 c046a42c-6fe2-441c-8c8c-71466251a162
2004-06-21 16:46:10 +00:00
bellard
95ea3fa19c added open pic for PPC
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@947 c046a42c-6fe2-441c-8c8c-71466251a162
2004-06-21 16:44:21 +00:00
bellard
7587cf4401 accept bigger PC BIOSes
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@946 c046a42c-6fe2-441c-8c8c-71466251a162
2004-06-20 13:43:27 +00:00
bellard
7086749072 update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@945 c046a42c-6fe2-441c-8c8c-71466251a162
2004-06-20 13:42:16 +00:00
bellard
63b7e03697 boot to top of 4GB space
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@944 c046a42c-6fe2-441c-8c8c-71466251a162
2004-06-20 13:38:54 +00:00
bellard
678f2df60f update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@943 c046a42c-6fe2-441c-8c8c-71466251a162
2004-06-20 13:12:23 +00:00
bellard
9e57f14d60 added APM support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@942 c046a42c-6fe2-441c-8c8c-71466251a162
2004-06-20 13:06:36 +00:00
bellard
987c1c6921 update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@941 c046a42c-6fe2-441c-8c8c-71466251a162
2004-06-20 13:02:46 +00:00
bellard
ffddfee379 added cpu_reset()
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@940 c046a42c-6fe2-441c-8c8c-71466251a162
2004-06-20 13:01:25 +00:00
bellard
a2f659ee48 new reset API - shutdown support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@939 c046a42c-6fe2-441c-8c8c-71466251a162
2004-06-20 13:00:26 +00:00
bellard
d7d02e3c3a new reset API
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@938 c046a42c-6fe2-441c-8c8c-71466251a162
2004-06-20 12:58:36 +00:00
bellard
bb0c6722b6 reset and shutdown support - PCI is now the default
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@937 c046a42c-6fe2-441c-8c8c-71466251a162
2004-06-20 12:37:32 +00:00
bellard
979a54fb20 new reset API
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@936 c046a42c-6fe2-441c-8c8c-71466251a162
2004-06-20 12:36:04 +00:00
bellard
e4f9082b9a added system_reset command
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@935 c046a42c-6fe2-441c-8c8c-71466251a162
2004-06-20 12:35:44 +00:00
bellard
d95dc32d13 added cpu_reset()
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@934 c046a42c-6fe2-441c-8c8c-71466251a162
2004-06-20 12:35:26 +00:00
bellard
53ad66e8c3 print error messages if boot error
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@933 c046a42c-6fe2-441c-8c8c-71466251a162
2004-06-19 17:35:07 +00:00
bellard
eba2af633f buffer overflow fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@932 c046a42c-6fe2-441c-8c8c-71466251a162
2004-06-19 17:23:39 +00:00
bellard
95ce326e5b buffer overflow fix - printf format fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@931 c046a42c-6fe2-441c-8c8c-71466251a162
2004-06-19 17:22:53 +00:00
bellard
a5448a7de5 sysinfo syscall (Francois Guimond)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@930 c046a42c-6fe2-441c-8c8c-71466251a162
2004-06-19 16:59:03 +00:00
bellard
9231944d96 sigset_t endianness fix in signal context
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@929 c046a42c-6fe2-441c-8c8c-71466251a162
2004-06-19 16:58:13 +00:00
bellard
d69d1fa01a const fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@928 c046a42c-6fe2-441c-8c8c-71466251a162
2004-06-19 16:57:17 +00:00
bellard
05efe46eaa VMware 4 disk images support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@927 c046a42c-6fe2-441c-8c8c-71466251a162
2004-06-16 20:34:33 +00:00
bellard
dbda808a4a OpenPIC support (Jocelyn Mayer)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@926 c046a42c-6fe2-441c-8c8c-71466251a162
2004-06-15 21:38:40 +00:00
bellard
a049791855 compile fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@925 c046a42c-6fe2-441c-8c8c-71466251a162
2004-06-14 19:33:16 +00:00
bellard
ea1c18022e fixed self modifying code in case of asynchronous interrupt
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@924 c046a42c-6fe2-441c-8c8c-71466251a162
2004-06-14 18:56:36 +00:00
bellard
516633dc42 jump to gate fix (aka OS/2 Warp install bug)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@923 c046a42c-6fe2-441c-8c8c-71466251a162
2004-06-13 15:20:01 +00:00
bellard
dc196a57e3 fixed 16 bit segment optimisations
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@922 c046a42c-6fe2-441c-8c8c-71466251a162
2004-06-13 13:26:14 +00:00
bellard
2a2820560d IDE ATA identify fix (aka FreeBSD 4.10 fix)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@921 c046a42c-6fe2-441c-8c8c-71466251a162
2004-06-12 22:23:16 +00:00
bellard
665656a99b ffree test
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@920 c046a42c-6fe2-441c-8c8c-71466251a162
2004-06-12 11:38:00 +00:00
bellard
658c8bdadc added ffree - added cpu log option
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@919 c046a42c-6fe2-441c-8c8c-71466251a162
2004-06-12 11:35:12 +00:00
bellard
5fef40fb4d added ffree
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@918 c046a42c-6fe2-441c-8c8c-71466251a162
2004-06-12 11:34:10 +00:00
bellard
e69390cee7 pattern fill fixes and optimization
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@917 c046a42c-6fe2-441c-8c8c-71466251a162
2004-06-09 23:12:09 +00:00
bellard
7f647cf68f IDE1 init fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@916 c046a42c-6fe2-441c-8c8c-71466251a162
2004-06-09 21:28:36 +00:00
bellard
a130a41e69 interlace support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@915 c046a42c-6fe2-441c-8c8c-71466251a162
2004-06-08 00:59:19 +00:00
bellard
78e127efdb set memory size to 4MB for 5446 - fixed memory size probe (aka Win2000 bug) - fixed interlace support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@914 c046a42c-6fe2-441c-8c8c-71466251a162
2004-06-08 00:58:26 +00:00
bellard
ee38b4c813 fixed full screen refresh
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@913 c046a42c-6fe2-441c-8c8c-71466251a162
2004-06-08 00:56:42 +00:00
bellard
3440557b6d ioport read command
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@912 c046a42c-6fe2-441c-8c8c-71466251a162
2004-06-08 00:55:58 +00:00
bellard
d329a6fb22 audip fixes (malc)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@911 c046a42c-6fe2-441c-8c8c-71466251a162
2004-06-07 20:58:31 +00:00
bellard
7ebb5e4139 debug
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@910 c046a42c-6fe2-441c-8c8c-71466251a162
2004-06-07 20:51:58 +00:00
bellard
57ccbabecb allow 32 but unaligned access (aka Win PCI network bug - initial patch by Renzo Davoli)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@909 c046a42c-6fe2-441c-8c8c-71466251a162
2004-06-07 20:45:42 +00:00
bellard
eb26db16d7 endianness functions for unaligned memory accesses
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@908 c046a42c-6fe2-441c-8c8c-71466251a162
2004-06-07 20:43:57 +00:00
bellard
4c8732d71b cirrus blitter fixes
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@907 c046a42c-6fe2-441c-8c8c-71466251a162
2004-06-07 19:46:45 +00:00
bellard
1cc98a5f04 hardware cursor depth = 15 fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@906 c046a42c-6fe2-441c-8c8c-71466251a162
2004-06-06 16:06:33 +00:00
bellard
de9258a87f specific VGA BIOS for Cirrus VGA Card
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@905 c046a42c-6fe2-441c-8c8c-71466251a162
2004-06-06 15:50:03 +00:00
bellard
37f53b4c05 update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@904 c046a42c-6fe2-441c-8c8c-71466251a162
2004-06-06 15:48:55 +00:00
bellard
a8aa669ba4 generic hardware cursor support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@903 c046a42c-6fe2-441c-8c8c-71466251a162
2004-06-06 15:17:19 +00:00
bellard
a5082316e9 hardware cursor support - fill with rop support - color expand and color expand with transparent support - various optimisations
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@902 c046a42c-6fe2-441c-8c8c-71466251a162
2004-06-06 15:16:19 +00:00
bellard
20ba3ae101 better to use different ID for ISA and PCI
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@901 c046a42c-6fe2-441c-8c8c-71466251a162
2004-06-05 18:50:58 +00:00
bellard
4c7634bcb3 init VGA with default config
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@900 c046a42c-6fe2-441c-8c8c-71466251a162
2004-06-05 18:49:26 +00:00
bellard
a21ae81d8a change ID to CLGD5446 - added solidfill support - fixed hidden dac access
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@899 c046a42c-6fe2-441c-8c8c-71466251a162
2004-06-05 17:59:37 +00:00
bellard
aeb3c85f59 Cirrus fixes
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@898 c046a42c-6fe2-441c-8c8c-71466251a162
2004-06-05 14:26:11 +00:00
bellard
1f04275ec1 -cirrusvga option
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@897 c046a42c-6fe2-441c-8c8c-71466251a162
2004-06-05 13:46:47 +00:00
bellard
4e3e9d0b4d avoid using anonymous struct extension (not supported by all gcc 3.x)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@896 c046a42c-6fe2-441c-8c8c-71466251a162
2004-06-05 13:18:45 +00:00
bellard
358c640721 host bridge config fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@895 c046a42c-6fe2-441c-8c8c-71466251a162
2004-06-05 12:49:34 +00:00
bellard
e36f36e15f mmio support for vga registers - line offset fix - (aka XFree86 4.3.0 fixes)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@894 c046a42c-6fe2-441c-8c8c-71466251a162
2004-06-05 12:47:01 +00:00
bellard
7b17d41e96 Cirrus VGA display fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@893 c046a42c-6fe2-441c-8c8c-71466251a162
2004-06-05 11:06:28 +00:00
bellard
d6bfa22f72 Cirrus VGA emulation
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@892 c046a42c-6fe2-441c-8c8c-71466251a162
2004-06-05 10:32:30 +00:00
bellard
e6e5ad80d8 Cirrus VGA emulation (initial patch by Suzu - heavily modified for easier merge)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@891 c046a42c-6fe2-441c-8c8c-71466251a162
2004-06-05 10:31:55 +00:00
bellard
798b0c25cc generic VGA API layer
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@890 c046a42c-6fe2-441c-8c8c-71466251a162
2004-06-05 10:30:49 +00:00
bellard
22a56b8a87 sdl keyboard fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@889 c046a42c-6fe2-441c-8c8c-71466251a162
2004-06-05 08:32:36 +00:00
bellard
44bbf73f92 dhcp packet size fix (aka pump fix)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@888 c046a42c-6fe2-441c-8c8c-71466251a162
2004-06-04 15:30:48 +00:00
bellard
00ffa62a91 added some keys
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@887 c046a42c-6fe2-441c-8c8c-71466251a162
2004-06-04 13:25:15 +00:00
bellard
de2200d36d fixed window switch - fixed caps lock and num lock - simplified keycodes (initial idea by Mark Jonckheere)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@886 c046a42c-6fe2-441c-8c8c-71466251a162
2004-06-04 13:15:06 +00:00
bellard
710c15a2e9 lmsw fix (aka dos4gw bug)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@885 c046a42c-6fe2-441c-8c8c-71466251a162
2004-06-04 11:20:49 +00:00
bellard
443f1376bc slirp is enabled by default
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@884 c046a42c-6fe2-441c-8c8c-71466251a162
2004-06-04 11:13:20 +00:00
bellard
a3a91a355b sendkey command
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@883 c046a42c-6fe2-441c-8c8c-71466251a162
2004-06-04 11:06:21 +00:00
bellard
ab2572d7ea added -fno-strict-aliasing
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@882 c046a42c-6fe2-441c-8c8c-71466251a162
2004-06-03 19:07:57 +00:00
bellard
267002cd28 CUDA + ADB support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@881 c046a42c-6fe2-441c-8c8c-71466251a162
2004-06-03 18:46:20 +00:00
bellard
63066f4f13 hid event handling
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@880 c046a42c-6fe2-441c-8c8c-71466251a162
2004-06-03 18:45:02 +00:00
bellard
caf9a12e9a CUDA + ADB support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@879 c046a42c-6fe2-441c-8c8c-71466251a162
2004-06-03 18:35:40 +00:00
bellard
1f62d9383f fixed PCI config default write permissions
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@878 c046a42c-6fe2-441c-8c8c-71466251a162
2004-06-03 16:40:20 +00:00
bellard
7727994d21 support for opaque data on memory I/Os
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@877 c046a42c-6fe2-441c-8c8c-71466251a162
2004-06-03 14:08:36 +00:00
bellard
8a8696a3c4 support for opaque data on memory I/Os - PCI ROM memory support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@876 c046a42c-6fe2-441c-8c8c-71466251a162
2004-06-03 14:06:32 +00:00
bellard
8998028497 -localtime option
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@875 c046a42c-6fe2-441c-8c8c-71466251a162
2004-06-03 14:04:03 +00:00
bellard
a4193c8a4b support for opaque data on memory I/Os
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@874 c046a42c-6fe2-441c-8c8c-71466251a162
2004-06-03 14:01:43 +00:00
bellard
170c6f8705 header fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@873 c046a42c-6fe2-441c-8c8c-71466251a162
2004-06-03 12:53:17 +00:00
bellard
43f493afb4 more accurate emulation (do not depend on localtime() or gmtime()
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@872 c046a42c-6fe2-441c-8c8c-71466251a162
2004-06-03 12:51:19 +00:00
bellard
ee22c2f7db -localtime option
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@871 c046a42c-6fe2-441c-8c8c-71466251a162
2004-06-03 12:49:50 +00:00
bellard
be3edd9590 update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@870 c046a42c-6fe2-441c-8c8c-71466251a162
2004-06-03 12:48:45 +00:00
bellard
023fe10d24 fnop FPU exception support (aka FreeBSD FPU probe) - sysenter/sysexit support (untested, not enabled in cpuid)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@869 c046a42c-6fe2-441c-8c8c-71466251a162
2004-05-29 11:08:52 +00:00
bellard
f66723fab9 put ready it after write command (aka FreeBSD HD access fix) - access 16 mult sector count
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@868 c046a42c-6fe2-441c-8c8c-71466251a162
2004-05-29 11:04:25 +00:00
bellard
8cc43feffc compile fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@867 c046a42c-6fe2-441c-8c8c-71466251a162
2004-05-26 23:29:15 +00:00
bellard
09a79b4974 partial big endian fixes - change VESA VBE ports for non i386 targets to avoid unaligned accesses
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@866 c046a42c-6fe2-441c-8c8c-71466251a162
2004-05-26 22:58:01 +00:00
bellard
642012017c PowerPC prep/chrp/pmac support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@865 c046a42c-6fe2-441c-8c8c-71466251a162
2004-05-26 22:55:16 +00:00
bellard
2444ca413b trace fixes
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@864 c046a42c-6fe2-441c-8c8c-71466251a162
2004-05-26 22:16:35 +00:00
bellard
77d4bc349a PowerPC prep/chrp/pmac support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@863 c046a42c-6fe2-441c-8c8c-71466251a162
2004-05-26 22:13:53 +00:00
bellard
a2a444d6e0 PowerPC merge
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@862 c046a42c-6fe2-441c-8c8c-71466251a162
2004-05-23 22:34:16 +00:00
bellard
4b3686faee PowerPC merge
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@861 c046a42c-6fe2-441c-8c8c-71466251a162
2004-05-23 22:18:12 +00:00
bellard
85c4adf65f PowerPC merge
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@860 c046a42c-6fe2-441c-8c8c-71466251a162
2004-05-23 21:25:39 +00:00
bellard
b69fedff84 PowerPC merge
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@859 c046a42c-6fe2-441c-8c8c-71466251a162
2004-05-23 21:17:08 +00:00
bellard
5fd386f698 PowerPC merge
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@858 c046a42c-6fe2-441c-8c8c-71466251a162
2004-05-23 21:11:22 +00:00
bellard
0ced658970 PowerPC merge
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@857 c046a42c-6fe2-441c-8c8c-71466251a162
2004-05-23 21:06:12 +00:00
bellard
b415a4078d update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@856 c046a42c-6fe2-441c-8c8c-71466251a162
2004-05-23 21:04:06 +00:00
bellard
f18ac341fe cleanup
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@855 c046a42c-6fe2-441c-8c8c-71466251a162
2004-05-23 21:00:55 +00:00
bellard
63ce9e0a42 pci empty device read fix - piix3 ide init
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@854 c046a42c-6fe2-441c-8c8c-71466251a162
2004-05-23 19:12:03 +00:00
bellard
e1c485be84 use PIIX3 like IDE controller
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@853 c046a42c-6fe2-441c-8c8c-71466251a162
2004-05-23 19:10:46 +00:00
bellard
34e538ae5d added PIIX3 like IDE controller - PCI irq generation - SETFEATURES IDE command support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@852 c046a42c-6fe2-441c-8c8c-71466251a162
2004-05-23 19:10:26 +00:00
bellard
9995c51ffd pixx3 ide controller
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@851 c046a42c-6fe2-441c-8c8c-71466251a162
2004-05-23 19:09:22 +00:00
bellard
e58a7c24ac int13 cdrom 32 bit register update fix (aka FreeBSD CDROM boot)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@850 c046a42c-6fe2-441c-8c8c-71466251a162
2004-05-23 16:28:35 +00:00
bellard
777428f2d2 fixed 2.88 MB boot (aka FreeBSD 5.2.1 boot fix)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@849 c046a42c-6fe2-441c-8c8c-71466251a162
2004-05-23 16:26:20 +00:00
bellard
5b60212f2a typos (Pavel Janik)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@848 c046a42c-6fe2-441c-8c8c-71466251a162
2004-05-22 21:41:05 +00:00
bellard
a00bad7ed4 default ram size define (Pavel Janik)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@847 c046a42c-6fe2-441c-8c8c-71466251a162
2004-05-22 21:39:06 +00:00
bellard
25b42e9d53 added missing copyright file
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@846 c046a42c-6fe2-441c-8c8c-71466251a162
2004-05-22 18:30:22 +00:00
bellard
8d6c7eb896 receive status register support (aka GRUB netboot fix)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@845 c046a42c-6fe2-441c-8c8c-71466251a162
2004-05-22 16:52:29 +00:00
bellard
7bf5be70f7 pci memory mapping fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@844 c046a42c-6fe2-441c-8c8c-71466251a162
2004-05-22 16:28:18 +00:00
bellard
fb9f944458 PCI BIOS fixes
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@843 c046a42c-6fe2-441c-8c8c-71466251a162
2004-05-22 16:27:00 +00:00
bellard
92e873b996 support for non continuous RAM or ROM
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@842 c046a42c-6fe2-441c-8c8c-71466251a162
2004-05-21 14:52:29 +00:00
bellard
9fddaa0c0c PowerPC merge: real time TB and decrementer - faster and simpler exception handling (Jocelyn Mayer)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@841 c046a42c-6fe2-441c-8c8c-71466251a162
2004-05-21 12:59:32 +00:00
bellard
4a0fb71e67 irq statistics code (initial patch by Jocelyn Mayer)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@840 c046a42c-6fe2-441c-8c8c-71466251a162
2004-05-21 11:39:07 +00:00
bellard
274da6b24b 64 bit fix (Jocelyn Mayer)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@839 c046a42c-6fe2-441c-8c8c-71466251a162
2004-05-20 21:56:27 +00:00
bellard
15aeac3805 PIC spurious irq support (aka Solaris install bug)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@838 c046a42c-6fe2-441c-8c8c-71466251a162
2004-05-20 16:12:05 +00:00
bellard
28ab0e2edb added cpu_get_tsc()
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@837 c046a42c-6fe2-441c-8c8c-71466251a162
2004-05-20 14:02:14 +00:00
bellard
b54ad0498e PIC reset fix (initial patch by Hidemi KAWAI)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@836 c046a42c-6fe2-441c-8c8c-71466251a162
2004-05-20 13:42:52 +00:00
bellard
4399059e4d update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@835 c046a42c-6fe2-441c-8c8c-71466251a162
2004-05-20 13:24:37 +00:00
bellard
43003046cb BSD fix + ppc-softmmu support for win32
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@834 c046a42c-6fe2-441c-8c8c-71466251a162
2004-05-20 13:23:39 +00:00
bellard
d157e205e9 win32 fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@833 c046a42c-6fe2-441c-8c8c-71466251a162
2004-05-20 13:22:36 +00:00
bellard
5f21aef2b0 suppressed unneeded header
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@832 c046a42c-6fe2-441c-8c8c-71466251a162
2004-05-20 13:20:55 +00:00
bellard
829309c70c BSD fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@831 c046a42c-6fe2-441c-8c8c-71466251a162
2004-05-20 13:20:12 +00:00
bellard
c6a1c22ba6 fixed invalid includes
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@830 c046a42c-6fe2-441c-8c8c-71466251a162
2004-05-20 13:10:49 +00:00
bellard
b71e95fc2c win32 patch (kazu)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@829 c046a42c-6fe2-441c-8c8c-71466251a162
2004-05-20 13:08:06 +00:00
bellard
04a3b84c83 64 bit support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@828 c046a42c-6fe2-441c-8c8c-71466251a162
2004-05-20 12:51:57 +00:00
bellard
86e0c04896 info pci command
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@827 c046a42c-6fe2-441c-8c8c-71466251a162
2004-05-20 12:49:21 +00:00
bellard
5ce276a11a VGA PCI support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@826 c046a42c-6fe2-441c-8c8c-71466251a162
2004-05-20 12:48:53 +00:00
bellard
5768f5aca6 PCI interrupt support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@825 c046a42c-6fe2-441c-8c8c-71466251a162
2004-05-20 12:47:45 +00:00
bellard
1078f663ae dummy VGA PCI support - VGA font selection fix (Daniel Serpell)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@824 c046a42c-6fe2-441c-8c8c-71466251a162
2004-05-20 12:46:38 +00:00
bellard
0ac32c8375 PCI interrupt support - PCI BIOS interrupt remapping - more accurate memory mapping - 'info pci' monitor command
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@823 c046a42c-6fe2-441c-8c8c-71466251a162
2004-05-20 12:45:00 +00:00
bellard
4a9c9687c6 PCI irq support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@822 c046a42c-6fe2-441c-8c8c-71466251a162
2004-05-20 12:43:25 +00:00
bellard
73c11f630b cleanup
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@821 c046a42c-6fe2-441c-8c8c-71466251a162
2004-05-20 12:42:19 +00:00
bellard
660de33686 PIIX ELCR register support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@820 c046a42c-6fe2-441c-8c8c-71466251a162
2004-05-20 12:41:21 +00:00
bellard
69135b5c04 suppressed pci2isa.c
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@819 c046a42c-6fe2-441c-8c8c-71466251a162
2004-05-20 12:40:26 +00:00
bellard
69b910399a PCI support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@818 c046a42c-6fe2-441c-8c8c-71466251a162
2004-05-18 23:05:28 +00:00
bellard
158156d13d -user-net is optional - EAGAIN fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@817 c046a42c-6fe2-441c-8c8c-71466251a162
2004-05-17 21:13:42 +00:00
bellard
e63c59cb34 ppc fix (Jocelyn Mayer)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@816 c046a42c-6fe2-441c-8c8c-71466251a162
2004-05-17 21:05:06 +00:00
bellard
13ab5daa86 NVRAM fixes (Jocelyn Mayer)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@815 c046a42c-6fe2-441c-8c8c-71466251a162
2004-05-17 20:21:49 +00:00
bellard
ef792f9ddb added CPU_INTERRUPT_TIMER
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@814 c046a42c-6fe2-441c-8c8c-71466251a162
2004-05-17 20:19:32 +00:00
bellard
47cea614a1 vmdk2raw: convert VMware disk images to raw images
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@813 c046a42c-6fe2-441c-8c8c-71466251a162
2004-05-17 20:06:42 +00:00
bellard
aedf53821f different serial number for each drive (initial patch by Mike Nordell)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@812 c046a42c-6fe2-441c-8c8c-71466251a162
2004-05-17 19:56:47 +00:00
bellard
7f5e145212 BSR/BSF 'undefined behaviour' test
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@811 c046a42c-6fe2-441c-8c8c-71466251a162
2004-05-16 16:02:40 +00:00
bellard
f528bfd45d update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@810 c046a42c-6fe2-441c-8c8c-71466251a162
2004-05-16 15:57:26 +00:00
bellard
686f3f266b BSR/BSF undefined behaviour fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@809 c046a42c-6fe2-441c-8c8c-71466251a162
2004-05-16 15:56:04 +00:00
bellard
5b1214a48e int15, ah=86 BIOS fix (aka Solaris x86 hardware probe hang up fix)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@808 c046a42c-6fe2-441c-8c8c-71466251a162
2004-05-16 15:52:12 +00:00
bellard
3f433d2c87 int13 CDROM BIOS fix (aka Solaris x86 install CD fix)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@807 c046a42c-6fe2-441c-8c8c-71466251a162
2004-05-16 14:21:17 +00:00
bellard
1a084f3d51 update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@806 c046a42c-6fe2-441c-8c8c-71466251a162
2004-05-13 22:34:49 +00:00
bellard
cd6f11693a custom option parsing to have same behavior on all OSes
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@805 c046a42c-6fe2-441c-8c8c-71466251a162
2004-05-13 22:02:20 +00:00
bellard
b939777cec floppy fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@804 c046a42c-6fe2-441c-8c8c-71466251a162
2004-05-12 22:07:40 +00:00
bellard
d6b86f4d85 -tun-fd option fix (Renzo Davoli)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@803 c046a42c-6fe2-441c-8c8c-71466251a162
2004-05-12 19:59:20 +00:00
bellard
3a1bc175ea allow '-nics 0'
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@802 c046a42c-6fe2-441c-8c8c-71466251a162
2004-05-12 19:54:43 +00:00
bellard
db45c29a65 faster I/Os - default 16 bit I/O fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@801 c046a42c-6fe2-441c-8c8c-71466251a162
2004-05-12 19:50:26 +00:00
bellard
7d3505c55a bsd port (Markus Niemisto)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@800 c046a42c-6fe2-441c-8c8c-71466251a162
2004-05-12 19:32:15 +00:00
bellard
fd872598d8 primitive ioport debug - /dev/rtc fast timer support (needed for better simulation accuracy with Linux 2.4)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@799 c046a42c-6fe2-441c-8c8c-71466251a162
2004-05-12 19:11:15 +00:00
bellard
8cd0ac2fe1 update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@798 c046a42c-6fe2-441c-8c8c-71466251a162
2004-05-12 19:09:16 +00:00
bellard
7efa43875d better packaging support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@797 c046a42c-6fe2-441c-8c8c-71466251a162
2004-05-12 18:54:06 +00:00
bellard
44c513c4c9 update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@796 c046a42c-6fe2-441c-8c8c-71466251a162
2004-05-08 21:24:35 +00:00
bellard
2ee73ac3a8 division by zero FPU exception support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@795 c046a42c-6fe2-441c-8c8c-71466251a162
2004-05-08 21:08:41 +00:00
bellard
28c3ee3fed cr0.ET fix (Win95 boot fix)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@794 c046a42c-6fe2-441c-8c8c-71466251a162
2004-05-08 21:05:19 +00:00
bellard
f929aad6e3 MSDOS compatibility mode FPU exception support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@793 c046a42c-6fe2-441c-8c8c-71466251a162
2004-05-08 21:03:41 +00:00
bellard
e309de25a6 SPECIFY command fix (Jocelyn Mayer)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@792 c046a42c-6fe2-441c-8c8c-71466251a162
2004-05-08 21:01:23 +00:00
bellard
10d315a8f2 update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@791 c046a42c-6fe2-441c-8c8c-71466251a162
2004-05-08 21:00:00 +00:00
bellard
2b64948eb5 64 bit fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@790 c046a42c-6fe2-441c-8c8c-71466251a162
2004-05-08 15:27:20 +00:00
bellard
1f50f8d1d4 better install
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@789 c046a42c-6fe2-441c-8c8c-71466251a162
2004-05-08 14:44:43 +00:00
bellard
a1b74fe8fe update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@788 c046a42c-6fe2-441c-8c8c-71466251a162
2004-05-08 13:26:35 +00:00
bellard
ed5fd2cce4 timer for READ_ID (win98 floppy fix) - simpler irq handling
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@787 c046a42c-6fe2-441c-8c8c-71466251a162
2004-05-08 13:14:18 +00:00
bellard
bee3290936 typo
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@786 c046a42c-6fe2-441c-8c8c-71466251a162
2004-05-05 18:50:02 +00:00
bellard
beddab753d arm load/store half word fix (Ulrich Hecht)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@785 c046a42c-6fe2-441c-8c8c-71466251a162
2004-05-05 18:36:10 +00:00
bellard
512176dbd8 fixed dhcp for windows client
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@784 c046a42c-6fe2-441c-8c8c-71466251a162
2004-05-04 03:14:47 +00:00
bellard
fb6cf1d09c fixed floppy reset (aka win98 floppy probe fix)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@783 c046a42c-6fe2-441c-8c8c-71466251a162
2004-05-04 02:04:17 +00:00
bellard
66201e2ddf ide slave fixes (aka Win98 CD-ROM detection fix)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@782 c046a42c-6fe2-441c-8c8c-71466251a162
2004-05-04 01:29:51 +00:00
bellard
ec844b96c0 pit fixes
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@781 c046a42c-6fe2-441c-8c8c-71466251a162
2004-05-03 23:18:25 +00:00
bellard
f72e8ff4a6 utime fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@780 c046a42c-6fe2-441c-8c8c-71466251a162
2004-05-03 19:23:07 +00:00
bellard
b06eddd39d update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@779 c046a42c-6fe2-441c-8c8c-71466251a162
2004-04-29 22:34:24 +00:00
bellard
6f51f6b593 keyboard irq generation fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@778 c046a42c-6fe2-441c-8c8c-71466251a162
2004-04-29 22:23:55 +00:00
bellard
0294ffb9c8 disable grab if the window no longer has the focus (Windows case) (Mike Nordell)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@777 c046a42c-6fe2-441c-8c8c-71466251a162
2004-04-29 22:15:15 +00:00
bellard
d8d8aa4e2c SDL static config fix (Roman Zippel)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@776 c046a42c-6fe2-441c-8c8c-71466251a162
2004-04-29 20:14:07 +00:00
bellard
141253b254 Bochs VBE emulation fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@775 c046a42c-6fe2-441c-8c8c-71466251a162
2004-04-29 19:21:16 +00:00
bellard
646be93b4c Bochs VBE emulation fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@774 c046a42c-6fe2-441c-8c8c-71466251a162
2004-04-28 22:38:47 +00:00
bellard
26aa7d72cc isa memory remapping support (aka PPC PREP VGA support)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@773 c046a42c-6fe2-441c-8c8c-71466251a162
2004-04-28 22:26:05 +00:00
bellard
8e9c4afe70 full screen support (initial patch by malc)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@772 c046a42c-6fe2-441c-8c8c-71466251a162
2004-04-28 19:33:40 +00:00
bellard
bbc9d34839 update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@771 c046a42c-6fe2-441c-8c8c-71466251a162
2004-04-26 21:15:11 +00:00
bellard
a8c490cda5 update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@770 c046a42c-6fe2-441c-8c8c-71466251a162
2004-04-26 20:59:17 +00:00
bellard
4606bb3f06 copyright update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@769 c046a42c-6fe2-441c-8c8c-71466251a162
2004-04-26 20:58:11 +00:00
bellard
aaaa7df625 added temporary option -enable-audio
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@768 c046a42c-6fe2-441c-8c8c-71466251a162
2004-04-26 20:56:53 +00:00
bellard
9d4fb82e3c update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@767 c046a42c-6fe2-441c-8c8c-71466251a162
2004-04-26 20:55:38 +00:00
bellard
9fafc9eaf0 avoid errno variable name
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@766 c046a42c-6fe2-441c-8c8c-71466251a162
2004-04-26 19:50:09 +00:00
bellard
1ef59d0acf ppc fixes (Jocelyn Mayer)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@765 c046a42c-6fe2-441c-8c8c-71466251a162
2004-04-26 19:48:05 +00:00
bellard
7fd7b91fac amd64 port
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@764 c046a42c-6fe2-441c-8c8c-71466251a162
2004-04-26 19:46:45 +00:00
bellard
d927637dca init dummy net if tun/tap network error
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@763 c046a42c-6fe2-441c-8c8c-71466251a162
2004-04-26 19:44:57 +00:00
bellard
4f2ac23784 amd64 port (Jocelyn Mayer)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@762 c046a42c-6fe2-441c-8c8c-71466251a162
2004-04-26 19:44:02 +00:00
bellard
f658b4db79 isa bridge endianness fixes
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@761 c046a42c-6fe2-441c-8c8c-71466251a162
2004-04-25 22:10:09 +00:00
bellard
0c4ad8dc2a ide endianness fixes
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@760 c046a42c-6fe2-441c-8c8c-71466251a162
2004-04-25 22:09:16 +00:00
bellard
165c6fc8ce more endianness macros
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@759 c046a42c-6fe2-441c-8c8c-71466251a162
2004-04-25 22:08:49 +00:00
bellard
2e12669a4c consistent use of target_ulong and target_phys_addr_t
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@758 c046a42c-6fe2-441c-8c8c-71466251a162
2004-04-25 21:28:44 +00:00
bellard
52c00a5f15 update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@757 c046a42c-6fe2-441c-8c8c-71466251a162
2004-04-25 21:27:03 +00:00
bellard
ab6d960ffa added target_phys_addr_t
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@756 c046a42c-6fe2-441c-8c8c-71466251a162
2004-04-25 21:25:15 +00:00
bellard
fbf9eeb34d added cpu_resume_from_signal() - irq fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@755 c046a42c-6fe2-441c-8c8c-71466251a162
2004-04-25 21:21:33 +00:00
bellard
046d6672e2 avoid unneeded casts
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@754 c046a42c-6fe2-441c-8c8c-71466251a162
2004-04-25 21:15:35 +00:00
bellard
75dfaa1e64 x86-64 port (Jocelyn Mayer)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@753 c046a42c-6fe2-441c-8c8c-71466251a162
2004-04-25 19:04:19 +00:00
bellard
1115dde719 x86-64 port (Jocelyn Mayer)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@752 c046a42c-6fe2-441c-8c8c-71466251a162
2004-04-25 18:57:49 +00:00
bellard
57206fd42a more register values in monitor
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@751 c046a42c-6fe2-441c-8c8c-71466251a162
2004-04-25 18:54:52 +00:00
bellard
4c27ba27c5 added 'info pic' - added 16/32 bit x86 instruction dump
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@750 c046a42c-6fe2-441c-8c8c-71466251a162
2004-04-25 18:05:08 +00:00
bellard
ba91cd80d5 fixed very unlikely irq bug
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@749 c046a42c-6fe2-441c-8c8c-71466251a162
2004-04-25 18:03:53 +00:00
bellard
6f1f31c069 ARM cache flush support (untested) - '-d' option fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@748 c046a42c-6fe2-441c-8c8c-71466251a162
2004-04-25 18:00:45 +00:00
bellard
5467a72294 disabled S3 VGA
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@747 c046a42c-6fe2-441c-8c8c-71466251a162
2004-04-25 17:59:00 +00:00
bellard
1b8eb456eb avoid error if too many sectors in non LBA mode
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@746 c046a42c-6fe2-441c-8c8c-71466251a162
2004-04-25 17:58:25 +00:00
bellard
d720b93d0b precise self modifying code support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@745 c046a42c-6fe2-441c-8c8c-71466251a162
2004-04-25 17:57:43 +00:00
bellard
eeab3a558f dump A20 state
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@744 c046a42c-6fe2-441c-8c8c-71466251a162
2004-04-25 17:56:46 +00:00
bellard
658138bcbc flush insn support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@743 c046a42c-6fe2-441c-8c8c-71466251a162
2004-04-25 17:56:08 +00:00
bellard
1190935d98 precise self modifying code test
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@742 c046a42c-6fe2-441c-8c8c-71466251a162
2004-04-25 17:54:32 +00:00
bellard
bfbc9133eb 64 bit seek for win32 (Mike Nordell)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@741 c046a42c-6fe2-441c-8c8c-71466251a162
2004-04-25 14:43:10 +00:00
bellard
ad6a4837f8 update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@740 c046a42c-6fe2-441c-8c8c-71466251a162
2004-04-24 00:16:28 +00:00
bellard
039d3da365 added user mode libqemu usage example
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@739 c046a42c-6fe2-441c-8c8c-71466251a162
2004-04-24 00:11:51 +00:00
bellard
a7e61ed446 create slirp directory
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@738 c046a42c-6fe2-441c-8c8c-71466251a162
2004-04-22 21:46:47 +00:00
bellard
b5075d29a8 more imul tests
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@737 c046a42c-6fe2-441c-8c8c-71466251a162
2004-04-22 21:37:55 +00:00
bellard
91caaa612a update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@736 c046a42c-6fe2-441c-8c8c-71466251a162
2004-04-22 21:36:13 +00:00
bellard
d64477afa1 imul imm8 fix - 0x82 opcode support (Hidemi KAWAI)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@735 c046a42c-6fe2-441c-8c8c-71466251a162
2004-04-22 21:34:25 +00:00
bellard
f6bac3809f fixed options definition
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@734 c046a42c-6fe2-441c-8c8c-71466251a162
2004-04-22 00:35:09 +00:00
bellard
f0cbd3ec9f initial user mode network support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@733 c046a42c-6fe2-441c-8c8c-71466251a162
2004-04-22 00:10:48 +00:00
bellard
7c1f25b46a probe static SDL link
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@732 c046a42c-6fe2-441c-8c8c-71466251a162
2004-04-22 00:02:08 +00:00
bellard
ee9dbb297d NE2000 fixes for windows (Renzo Davoli)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@731 c046a42c-6fe2-441c-8c8c-71466251a162
2004-04-21 23:29:33 +00:00
bellard
c20709aa32 initial user mode network support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@730 c046a42c-6fe2-441c-8c8c-71466251a162
2004-04-21 23:27:19 +00:00
bellard
92cb7d5423 NT mouse fix (Mark Jonckheere)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@729 c046a42c-6fe2-441c-8c8c-71466251a162
2004-04-16 22:17:49 +00:00
bellard
202a456a2b safer sb16 code
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@728 c046a42c-6fe2-441c-8c8c-71466251a162
2004-04-16 22:09:02 +00:00
bellard
3294b949eb avoid segfault if transient invalid text resolution
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@727 c046a42c-6fe2-441c-8c8c-71466251a162
2004-04-15 22:35:16 +00:00
bellard
2aebb3eb2b blanking support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@726 c046a42c-6fe2-441c-8c8c-71466251a162
2004-04-15 22:28:04 +00:00
bellard
95917e3f57 suppressed no longer needed vm86 segment hack (Mike Nordell)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@725 c046a42c-6fe2-441c-8c8c-71466251a162
2004-04-15 22:13:27 +00:00
bellard
f186904281 update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@724 c046a42c-6fe2-441c-8c8c-71466251a162
2004-04-12 20:58:23 +00:00
bellard
c5df018e56 ppc: suppressed unneeded globals and headers - added explicit type for ppc nvram
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@723 c046a42c-6fe2-441c-8c8c-71466251a162
2004-04-12 20:54:52 +00:00
bellard
a541f297a3 PowerPC system emulation fixes (Jocelyn Mayer)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@722 c046a42c-6fe2-441c-8c8c-71466251a162
2004-04-12 20:39:29 +00:00
bellard
df475d18d8 fixed invalid command test
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@721 c046a42c-6fe2-441c-8c8c-71466251a162
2004-04-12 19:07:27 +00:00
bellard
2f0c934ef9 update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@720 c046a42c-6fe2-441c-8c8c-71466251a162
2004-04-11 14:55:01 +00:00
bellard
fd836909df VM86 EIP masking fix (aka NT5 install fix) (Mike Nordell)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@719 c046a42c-6fe2-441c-8c8c-71466251a162
2004-04-11 14:54:42 +00:00
bellard
289e09e77b fixed keyboard random bug (Mike Nordell)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@718 c046a42c-6fe2-441c-8c8c-71466251a162
2004-04-10 19:04:48 +00:00
bellard
7ae9862745 ide select logic fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@717 c046a42c-6fe2-441c-8c8c-71466251a162
2004-04-07 22:13:51 +00:00
bellard
41b9be476c preserve partition table when using -linux option
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@716 c046a42c-6fe2-441c-8c8c-71466251a162
2004-04-07 21:30:08 +00:00
bellard
52302d7274 fix the no device case
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@715 c046a42c-6fe2-441c-8c8c-71466251a162
2004-04-07 21:01:17 +00:00
bellard
333190eb97 base memory size in cmos
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@714 c046a42c-6fe2-441c-8c8c-71466251a162
2004-04-07 20:51:30 +00:00
bellard
eccabc6ee0 vga 9 pixel wide text char fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@713 c046a42c-6fe2-441c-8c8c-71466251a162
2004-04-07 20:31:38 +00:00
bellard
bb058620c3 refuse write accesses in BIOS area (aka EMM386.EXE fix) (Mike Nordell)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@712 c046a42c-6fe2-441c-8c8c-71466251a162
2004-04-07 20:21:16 +00:00
bellard
9eb153f18f dma clean up - added missing read accesses
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@711 c046a42c-6fe2-441c-8c8c-71466251a162
2004-04-06 22:43:01 +00:00
bellard
aaba6c1516 win32: correct keycode remapping
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@710 c046a42c-6fe2-441c-8c8c-71466251a162
2004-04-06 19:30:16 +00:00
bellard
38e205a25b win32: do not use all cpu time
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@709 c046a42c-6fe2-441c-8c8c-71466251a162
2004-04-06 19:29:17 +00:00
bellard
e1a237441d port 92 access
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@708 c046a42c-6fe2-441c-8c8c-71466251a162
2004-04-05 20:26:03 +00:00
bellard
57c3072482 fixing free
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@707 c046a42c-6fe2-441c-8c8c-71466251a162
2004-04-04 20:36:29 +00:00
bellard
73332e5ccd qemu fast fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@706 c046a42c-6fe2-441c-8c8c-71466251a162
2004-04-04 20:22:28 +00:00
bellard
1f673135ac doc update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@705 c046a42c-6fe2-441c-8c8c-71466251a162
2004-04-04 15:21:17 +00:00
bellard
aa455485c9 history support (Jocelyn Mayer)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@704 c046a42c-6fe2-441c-8c8c-71466251a162
2004-04-04 13:07:25 +00:00
bellard
9307c4c1d9 improved monitor: type check, expression evaluator, memory dump, disassembly
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@703 c046a42c-6fe2-441c-8c8c-71466251a162
2004-04-04 12:57:25 +00:00
bellard
40c3bac35a win32 port (Kazu)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@702 c046a42c-6fe2-441c-8c8c-71466251a162
2004-04-04 12:56:28 +00:00
bellard
6eaee46144 update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@701 c046a42c-6fe2-441c-8c8c-71466251a162
2004-04-04 12:55:00 +00:00
bellard
0f2f112156 tun-fd fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@700 c046a42c-6fe2-441c-8c8c-71466251a162
2004-04-04 09:37:47 +00:00
bellard
4721c45750 UIP update fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@699 c046a42c-6fe2-441c-8c8c-71466251a162
2004-04-03 12:27:31 +00:00
bellard
a6e022ad13 fixed SDL probing for cross compilation
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@698 c046a42c-6fe2-441c-8c8c-71466251a162
2004-04-02 21:55:47 +00:00
bellard
702c651c4a added -macaddr option
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@697 c046a42c-6fe2-441c-8c8c-71466251a162
2004-04-02 21:21:32 +00:00
bellard
1154e441aa avoid rounding problems
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@696 c046a42c-6fe2-441c-8c8c-71466251a162
2004-04-02 20:58:56 +00:00
bellard
e463b581ea rdtsc fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@695 c046a42c-6fe2-441c-8c8c-71466251a162
2004-04-02 20:57:58 +00:00
bellard
11d9f695e7 win32 cross compile fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@694 c046a42c-6fe2-441c-8c8c-71466251a162
2004-04-02 20:55:59 +00:00
bellard
0c607d5728 win32 port (initial patch by kazu)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@693 c046a42c-6fe2-441c-8c8c-71466251a162
2004-03-31 23:54:52 +00:00
bellard
67b915a5dd win32 port (initial patch by kazu)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@692 c046a42c-6fe2-441c-8c8c-71466251a162
2004-03-31 23:37:16 +00:00
bellard
bb27c19087 update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@691 c046a42c-6fe2-441c-8c8c-71466251a162
2004-03-31 19:05:07 +00:00
bellard
8a7ddc38a6 new timer API - new API to save/restore the virtual machine state
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@690 c046a42c-6fe2-441c-8c8c-71466251a162
2004-03-31 19:00:16 +00:00
bellard
b0a21b5334 use new timer API
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@689 c046a42c-6fe2-441c-8c8c-71466251a162
2004-03-31 18:58:38 +00:00
bellard
dff38e7b40 more precise RTC emulation (periodic timers + time updates)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@688 c046a42c-6fe2-441c-8c8c-71466251a162
2004-03-31 18:57:29 +00:00
bellard
1f1af9fd7f added cpu_get_fp80() and cpu_set_fp80()
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@687 c046a42c-6fe2-441c-8c8c-71466251a162
2004-03-31 18:56:43 +00:00
bellard
858693c638 moved gdbstub to qemu - new asynchronous gdbstub
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@686 c046a42c-6fe2-441c-8c8c-71466251a162
2004-03-31 18:52:07 +00:00
bellard
9b14bb04ca install fix (Rusty Russel)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@685 c046a42c-6fe2-441c-8c8c-71466251a162
2004-03-26 22:43:34 +00:00
bellard
c101c49c54 added qemu-mkcow man page
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@684 c046a42c-6fe2-441c-8c8c-71466251a162
2004-03-26 22:42:54 +00:00
bellard
4bb2fcc7c9 gcc 2.95.4 compile fix (Petter Reinholdtsen)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@683 c046a42c-6fe2-441c-8c8c-71466251a162
2004-03-26 22:38:57 +00:00
bellard
08cea4eef8 fixed ljmp and iret to TSS
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@682 c046a42c-6fe2-441c-8c8c-71466251a162
2004-03-26 22:26:53 +00:00
bellard
883da8e219 task switch fixes
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@681 c046a42c-6fe2-441c-8c8c-71466251a162
2004-03-24 00:50:26 +00:00
bellard
78ebca6e13 fixed IDE probe
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@680 c046a42c-6fe2-441c-8c8c-71466251a162
2004-03-23 22:42:43 +00:00
bellard
5e2a644399 removed most of global context uses - removed unneeded abort() which cause problems during win95 hardware scan
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@679 c046a42c-6fe2-441c-8c8c-71466251a162
2004-03-23 22:42:11 +00:00
bellard
11774f549e protected lret x86 'bug' emulation
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@678 c046a42c-6fe2-441c-8c8c-71466251a162
2004-03-21 18:28:57 +00:00
bellard
d9d849fc5d update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@677 c046a42c-6fe2-441c-8c8c-71466251a162
2004-03-21 17:12:48 +00:00
bellard
e19e89a5d4 more log items
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@676 c046a42c-6fe2-441c-8c8c-71466251a162
2004-03-21 17:08:23 +00:00
bellard
f193c7979c do not depend on thunk.h - more log items
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@675 c046a42c-6fe2-441c-8c8c-71466251a162
2004-03-21 17:06:25 +00:00
bellard
3035f7ff83 use new directory layout
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@674 c046a42c-6fe2-441c-8c8c-71466251a162
2004-03-21 17:02:00 +00:00
bellard
4afa64828b fixed protected lret imm insn (one more OS/2 fix)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@673 c046a42c-6fe2-441c-8c8c-71466251a162
2004-03-20 22:04:16 +00:00
bellard
c45c3d0059 write to both IDE drives - return 0 for not present drives
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@672 c046a42c-6fe2-441c-8c8c-71466251a162
2004-03-20 22:01:15 +00:00
bellard
baca51faff updated floppy driver: formatting code, disk geometry auto detect (Jocelyn Mayer)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@671 c046a42c-6fe2-441c-8c8c-71466251a162
2004-03-19 23:05:34 +00:00
bellard
bc51c5c989 initial x86-64 host support (Gwenole Beauchesne)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@670 c046a42c-6fe2-441c-8c8c-71466251a162
2004-03-17 23:46:04 +00:00
bellard
5069146392 update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@669 c046a42c-6fe2-441c-8c8c-71466251a162
2004-03-17 23:44:10 +00:00
bellard
59a983b921 device independent VGA screen dump
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@668 c046a42c-6fe2-441c-8c8c-71466251a162
2004-03-17 23:17:16 +00:00
bellard
4e463d8d50 tun-fd option fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@667 c046a42c-6fe2-441c-8c8c-71466251a162
2004-03-16 00:02:58 +00:00
bellard
94fe4f9fa3 update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@666 c046a42c-6fe2-441c-8c8c-71466251a162
2004-03-14 21:49:05 +00:00
bellard
0fb48229a7 added qemu_mallocz()
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@665 c046a42c-6fe2-441c-8c8c-71466251a162
2004-03-14 21:48:47 +00:00
bellard
b41a2cd1e4 io port API change
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@664 c046a42c-6fe2-441c-8c8c-71466251a162
2004-03-14 21:46:48 +00:00
bellard
c4b1fcc0f9 added I/O API - io port API change - added multiple network interface support - redirect serial port to a pseudo terminal if using graphical mode
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@663 c046a42c-6fe2-441c-8c8c-71466251a162
2004-03-14 21:44:30 +00:00
bellard
0f35920cd8 io port API change - removed dumb console redraw (not useful)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@662 c046a42c-6fe2-441c-8c8c-71466251a162
2004-03-14 21:42:10 +00:00
bellard
7d977de7e1 io port API change
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@661 c046a42c-6fe2-441c-8c8c-71466251a162
2004-03-14 21:41:34 +00:00
bellard
07d898662d added qemu_mallocz()
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@660 c046a42c-6fe2-441c-8c8c-71466251a162
2004-03-14 21:41:12 +00:00
bellard
caed880216 removable device support - io port API change
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@659 c046a42c-6fe2-441c-8c8c-71466251a162
2004-03-14 21:40:43 +00:00
bellard
b338082b3f remoable device support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@658 c046a42c-6fe2-441c-8c8c-71466251a162
2004-03-14 21:38:54 +00:00
bellard
9dc39cbae3 added a command line monitor
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@657 c046a42c-6fe2-441c-8c8c-71466251a162
2004-03-14 21:38:27 +00:00
bellard
80cabfad16 separated more devices from emulator
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@656 c046a42c-6fe2-441c-8c8c-71466251a162
2004-03-14 12:20:30 +00:00
bellard
38ca2abc2e m68k compile fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@655 c046a42c-6fe2-441c-8c8c-71466251a162
2004-03-13 18:32:13 +00:00
bellard
73bdea1951 2.6 kernel compile fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@654 c046a42c-6fe2-441c-8c8c-71466251a162
2004-03-04 22:50:52 +00:00
bellard
00af2b2680 added cow.h
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@653 c046a42c-6fe2-441c-8c8c-71466251a162
2004-02-26 00:20:56 +00:00
bellard
a735aa3139 added precompiled linux boot sector
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@652 c046a42c-6fe2-441c-8c8c-71466251a162
2004-02-25 23:54:25 +00:00
bellard
6b2b6112f8 more FPU context save tests
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@651 c046a42c-6fe2-441c-8c8c-71466251a162
2004-02-25 23:34:07 +00:00
bellard
bf08806145 native FPU support in code copy mode
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@650 c046a42c-6fe2-441c-8c8c-71466251a162
2004-02-25 23:33:36 +00:00
bellard
f9e92e973f use physical memory access functions for DMA
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@649 c046a42c-6fe2-441c-8c8c-71466251a162
2004-02-25 23:32:01 +00:00
bellard
8dc75d7535 moved DMA and SB16 outside timer (may break SB16)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@648 c046a42c-6fe2-441c-8c8c-71466251a162
2004-02-25 23:30:56 +00:00
bellard
03857e318e native FPU support in code copy mode
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@647 c046a42c-6fe2-441c-8c8c-71466251a162
2004-02-25 23:26:33 +00:00
bellard
16f62432c4 DMA API change
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@646 c046a42c-6fe2-441c-8c8c-71466251a162
2004-02-25 23:25:55 +00:00
bellard
8b1f24b090 new physical memory access API (used by DMA accesses)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@645 c046a42c-6fe2-441c-8c8c-71466251a162
2004-02-25 23:24:38 +00:00
bellard
b448f2f36c new physical memory access API (used by DMA accesses) - code copy FP fixes
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@644 c046a42c-6fe2-441c-8c8c-71466251a162
2004-02-25 23:24:04 +00:00
bellard
97eb5b14dc native FPU support in code copy mode
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@643 c046a42c-6fe2-441c-8c8c-71466251a162
2004-02-25 23:19:55 +00:00
bellard
7eee2a509a CR0.MP/EM/TS support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@642 c046a42c-6fe2-441c-8c8c-71466251a162
2004-02-25 23:17:58 +00:00
bellard
42c3c0cced native FPU support (disabled)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@641 c046a42c-6fe2-441c-8c8c-71466251a162
2004-02-25 23:17:25 +00:00
bellard
9588b95a08 CR0.MP/EM/TS support - native fpu support in code copy mode
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@640 c046a42c-6fe2-441c-8c8c-71466251a162
2004-02-25 23:15:55 +00:00
bellard
2edcdce334 fpu fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@639 c046a42c-6fe2-441c-8c8c-71466251a162
2004-02-25 23:15:06 +00:00
bellard
8853f86e1d shm support, more setsockopt and getsockopt calls, fds fix (initial patch by Paul McKerras)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@638 c046a42c-6fe2-441c-8c8c-71466251a162
2004-02-22 14:57:26 +00:00
bellard
e374bfa35b shm tests - disabled clone test
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@637 c046a42c-6fe2-441c-8c8c-71466251a162
2004-02-22 14:54:18 +00:00
bellard
b88e4a9a3b small test optimisations
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@636 c046a42c-6fe2-441c-8c8c-71466251a162
2004-02-22 13:41:47 +00:00
bellard
537730b956 zero offset optimisation
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@635 c046a42c-6fe2-441c-8c8c-71466251a162
2004-02-22 13:40:57 +00:00
bellard
edf779ffcc use kernel like macros for user access (will be useful someday to have a better error checking
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@634 c046a42c-6fe2-441c-8c8c-71466251a162
2004-02-22 13:40:13 +00:00
bellard
121061dcdf O_DIRECT compile fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@633 c046a42c-6fe2-441c-8c8c-71466251a162
2004-02-22 11:56:01 +00:00
bellard
83d7396850 faster big endian accesses on i386 - big endian ldsw_raw fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@632 c046a42c-6fe2-441c-8c8c-71466251a162
2004-02-22 11:53:50 +00:00
bellard
6b2d3e3c96 fixed blr/bctr cases
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@631 c046a42c-6fe2-441c-8c8c-71466251a162
2004-02-21 15:41:09 +00:00
bellard
e98a6e40a9 adding direct block chaining support - simplified branch code gen
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@630 c046a42c-6fe2-441c-8c8c-71466251a162
2004-02-21 15:35:00 +00:00
bellard
28fbe299c3 lwarx fix (Jocelyn Mayer)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@629 c046a42c-6fe2-441c-8c8c-71466251a162
2004-02-21 14:13:13 +00:00
bellard
297d8e6227 Fix check for lswi (Jocelyn Mayer)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@628 c046a42c-6fe2-441c-8c8c-71466251a162
2004-02-21 14:11:27 +00:00
bellard
004bc62c28 update nip when processing exceptions (Jocelyn Mayer)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@627 c046a42c-6fe2-441c-8c8c-71466251a162
2004-02-21 14:10:04 +00:00
bellard
ed1c0bcb0c use osdep.h
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@626 c046a42c-6fe2-441c-8c8c-71466251a162
2004-02-16 22:17:43 +00:00
bellard
22a46c55e4 update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@625 c046a42c-6fe2-441c-8c8c-71466251a162
2004-02-16 22:13:24 +00:00
bellard
ea88812f4f added OS dependent functions (temporary as most functions are generic in fact)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@624 c046a42c-6fe2-441c-8c8c-71466251a162
2004-02-16 22:12:40 +00:00
bellard
58fe2f10f0 experimental code copy support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@623 c046a42c-6fe2-441c-8c8c-71466251a162
2004-02-16 22:11:32 +00:00
bellard
3a1d9b8bbb fixed lea exception
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@622 c046a42c-6fe2-441c-8c8c-71466251a162
2004-02-16 22:10:33 +00:00
bellard
0e4b179d33 experimental code copy support - fixed A20 emulation
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@621 c046a42c-6fe2-441c-8c8c-71466251a162
2004-02-16 22:08:32 +00:00
bellard
77fef8c148 experimental code copy support - added new Linux kernel loader
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@620 c046a42c-6fe2-441c-8c8c-71466251a162
2004-02-16 22:05:46 +00:00
bellard
59817ccb2c use qemu memory allocation - added dirty bit support when using host MMU
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@619 c046a42c-6fe2-441c-8c8c-71466251a162
2004-02-16 22:01:13 +00:00
bellard
bf3e8bf11e experimental code copy support - CPU_INTERRUPT_EXITTB support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@618 c046a42c-6fe2-441c-8c8c-71466251a162
2004-02-16 21:58:54 +00:00
bellard
9acbed0605 added CPU_INTERRUPT_EXITTB and code_copy_enabled
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@617 c046a42c-6fe2-441c-8c8c-71466251a162
2004-02-16 21:57:02 +00:00
bellard
cf98951b82 force boot sector feature
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@616 c046a42c-6fe2-441c-8c8c-71466251a162
2004-02-16 21:56:36 +00:00
bellard
f72b519c86 added osdep.o and nwfpe
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@615 c046a42c-6fe2-441c-8c8c-71466251a162
2004-02-16 21:55:35 +00:00
bellard
07ce05eaa9 fast Linux boot support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@614 c046a42c-6fe2-441c-8c8c-71466251a162
2004-02-16 21:55:09 +00:00
bellard
b324e814a9 suppressed unused variables
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@613 c046a42c-6fe2-441c-8c8c-71466251a162
2004-02-16 21:54:14 +00:00
bellard
c69810559b arm nwfpe support - added code no-code-copy option - __preinit_array_start bug fix (untested)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@612 c046a42c-6fe2-441c-8c8c-71466251a162
2004-02-16 21:49:03 +00:00
bellard
28c4f361ac arm nwfpe support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@611 c046a42c-6fe2-441c-8c8c-71466251a162
2004-02-16 21:47:43 +00:00
bellard
3d57da2a70 suppressed dummy FPU ops
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@610 c046a42c-6fe2-441c-8c8c-71466251a162
2004-02-16 21:47:14 +00:00
bellard
00406dff19 added arm nwfpe support (initial patch by Ulrich Hecht)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@609 c046a42c-6fe2-441c-8c8c-71466251a162
2004-02-16 21:43:58 +00:00
bellard
69de927c6c arm nwfpe support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@608 c046a42c-6fe2-441c-8c8c-71466251a162
2004-02-16 21:40:43 +00:00
bellard
72cbca10e1 direct chaining support for SPARC
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@607 c046a42c-6fe2-441c-8c8c-71466251a162
2004-02-16 20:30:05 +00:00
bellard
34f715e754 fixed WP semantics
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@606 c046a42c-6fe2-441c-8c8c-71466251a162
2004-02-07 20:42:14 +00:00
bellard
cae61cef89 bochs vbe: virtual screen support and bank switch (untested)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@605 c046a42c-6fe2-441c-8c8c-71466251a162
2004-02-06 23:58:08 +00:00
bellard
6411cfb6f3 update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@604 c046a42c-6fe2-441c-8c8c-71466251a162
2004-02-06 19:57:09 +00:00
bellard
898712a85c sdl_cleanup fix (Martin Garton)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@603 c046a42c-6fe2-441c-8c8c-71466251a162
2004-02-06 19:56:42 +00:00
bellard
4fa0f5d292 added bochs VBE support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@602 c046a42c-6fe2-441c-8c8c-71466251a162
2004-02-06 19:47:52 +00:00
bellard
1ccde1cb94 added generic physical memory dirty bit support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@601 c046a42c-6fe2-441c-8c8c-71466251a162
2004-02-06 19:46:14 +00:00
bellard
ad08132319 added tlb_flush() flags
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@600 c046a42c-6fe2-441c-8c8c-71466251a162
2004-02-03 23:39:42 +00:00
bellard
415e561f1d cleanup
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@599 c046a42c-6fe2-441c-8c8c-71466251a162
2004-02-03 23:37:12 +00:00
bellard
ee8b7021da temporary interrupt locking fix (need rework)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@598 c046a42c-6fe2-441c-8c8c-71466251a162
2004-02-03 23:35:10 +00:00
bellard
625976dac8 update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@597 c046a42c-6fe2-441c-8c8c-71466251a162
2004-02-03 23:30:47 +00:00
bellard
1ac157da77 more precise TLB invalidation - init cleanup
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@596 c046a42c-6fe2-441c-8c8c-71466251a162
2004-02-03 23:28:30 +00:00
bellard
64a595f26a cleanup
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@595 c046a42c-6fe2-441c-8c8c-71466251a162
2004-02-03 23:27:13 +00:00
bellard
3ad9a57e4f ide identify fix (initial patch by Jens Axboe)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@594 c046a42c-6fe2-441c-8c8c-71466251a162
2004-02-01 17:55:47 +00:00
bellard
7f777bf385 fixed atapi error codes (initial patch by Jens Axboe)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@593 c046a42c-6fe2-441c-8c8c-71466251a162
2004-02-01 17:37:48 +00:00
bellard
56bf1d37a0 SEEK_STAT bit ata reset fix (Jens Axboe)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@592 c046a42c-6fe2-441c-8c8c-71466251a162
2004-02-01 17:24:11 +00:00
bellard
c92b2e845f vga memory address fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@591 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-27 00:14:11 +00:00
bellard
68e73e391f clean tests dir
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@590 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-25 15:47:27 +00:00
bellard
c0637b3794 update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@589 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-25 15:38:01 +00:00
bellard
e98c87213e update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@588 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-25 15:26:12 +00:00
bellard
3d4b4c0f4b update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@587 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-25 15:22:15 +00:00
bellard
8145122b08 correct NT flag behavior - zero ldt task switch bug fix - task switch thru call insn bug fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@586 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-24 16:27:56 +00:00
bellard
7399c5a9be fixed eflags optimisations with string operation (aka linux 2.6.2rc1 fix) - removed warnings
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@585 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-24 16:24:06 +00:00
bellard
10f0e412f8 combine PDE and PTE protections as in intel specs - added cpu_get_phys_page_debug()
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@584 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-24 15:29:03 +00:00
bellard
4b7aba5173 correct NT flag behavior
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@583 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-24 15:27:58 +00:00
bellard
35b66fc4f9 correct target_ulong definition
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@582 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-24 15:26:06 +00:00
bellard
13eb76e091 virtual memory access for gdbstub
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@581 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-24 15:23:36 +00:00
bellard
3cf1e035ba added TARGET_LONG_BITS
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@580 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-24 15:19:09 +00:00
bellard
a6b025d37d added cpu_get_phys_page_debug()
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@579 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-24 15:18:16 +00:00
bellard
edfcbd9937 added cpu_get_phys_page_debug()
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@578 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-24 15:11:05 +00:00
bellard
612b477d48 removed warnings
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@577 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-24 15:10:18 +00:00
bellard
6c9bf8936a update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@576 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-24 13:46:56 +00:00
bellard
bb551faa4a increased physical RAM limit to 2047 MB in soft MMU mode
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@575 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-24 13:42:26 +00:00
bellard
a136e5a8b1 ATAPI transfer size fix (NetBSD CDROM access fix) - added WIN_CHECKPOWERMODE1 - set error to zero in some cases
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@574 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-22 23:52:27 +00:00
bellard
4796f5e9bc interrupt to conforming segment fix (QNX boot fix)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@573 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-19 23:46:39 +00:00
bellard
3504fe171b 16 bit DMA fix (malc)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@572 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-19 21:11:02 +00:00
bellard
ab1f142ba0 L4 fix for rep nop (should handle all cases)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@571 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-19 20:31:37 +00:00
bellard
4120b61d00 test at least one invalid lock op code
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@570 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-19 20:29:34 +00:00
bellard
7f957d280b PowerPC merge (Jocelyn Mayer)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@569 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-18 23:19:48 +00:00
bellard
2be3bc02dd update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@568 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-18 23:14:25 +00:00
bellard
c27357906a avoid exiting directly if file not found
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@567 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-18 22:55:23 +00:00
bellard
985a19d6d1 PowerPC merge (Jocelyn Mayer)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@566 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-18 22:49:57 +00:00
bellard
3f5dcc340c PowerPC merge (Jocelyn Mayer)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@565 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-18 22:44:01 +00:00
bellard
f09936ac82 ARM fcntl flag fixes (Lennert Buytenhek)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@564 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-18 22:39:25 +00:00
bellard
d030931173 automatic floppy boot
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@563 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-18 22:35:25 +00:00
bellard
825bd5f8e5 temporary gcc 3.3 fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@562 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-18 22:25:49 +00:00
bellard
bc0b1dc1eb sb16 patch (malc)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@561 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-18 22:19:31 +00:00
bellard
630be16f6c alpha fix (Falk Hueffner)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@560 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-18 22:06:47 +00:00
bellard
44a91cae10 suppressed cast to lvalue
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@559 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-18 22:05:44 +00:00
bellard
d575b78aab more xadd tests - cmpxchg8b test
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@558 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-18 21:57:29 +00:00
bellard
6e44ba7fa2 cmos return current date - current irq priority in PIC (L4 Pistachio support) - help fixes
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@557 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-18 21:56:49 +00:00
bellard
6986f88c3f cast to return type
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@556 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-18 21:53:18 +00:00
bellard
988578886e fixed tlb invalidation
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@555 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-18 21:52:14 +00:00
bellard
c4c7e3e610 ppc code gen size fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@554 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-18 21:50:28 +00:00
bellard
b516f85ca8 simpler second page physical address test
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@553 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-18 21:50:04 +00:00
bellard
1e4fe7cee2 fixed potential exception pb on cmpxchg
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@552 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-18 21:44:40 +00:00
bellard
debf7a7c7e comments fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@551 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-18 21:43:36 +00:00
bellard
5a1388b6df xadd fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@550 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-18 21:41:29 +00:00
bellard
777aca2fd3 fixed dirty bit support for 4M pages (L4 Pistachio fix)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@549 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-18 21:39:51 +00:00
bellard
69e5bc9068 generate read error if no image (win XP install boot)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@548 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-18 21:37:47 +00:00
bellard
c8135d9af6 fixed subtle bug: in some cases PG_DIRTY was not set correctly
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@547 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-13 00:00:25 +00:00
bellard
9e62fd7f26 ppc support (Jocelyn Mayer)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@546 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-05 22:49:06 +00:00
bellard
8977f3c107 Floppy disk emulation (Jocelyn Mayer)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@545 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-05 00:09:06 +00:00
bellard
728c9fd5a9 update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@544 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-05 00:08:14 +00:00
bellard
bd49793889 use generic GenOpFunc
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@543 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-05 00:06:41 +00:00
bellard
16d17fdb8e debug fixes
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@542 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-05 00:05:50 +00:00
bellard
4487d0ac49 changed cpu_x86_in/out to cpu_in/out
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@541 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-05 00:05:04 +00:00
bellard
7138fcfbf7 use CPUState
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@540 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-05 00:02:28 +00:00
bellard
c45886db19 PowerPC system emulation (Jocelyn Mayer) - PIC poll mode (Jocelyn Mayer) - use CPUState - Floppy support (Jocelyn Mayer) - command line debug (Jocelyn Mayer)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@539 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-05 00:02:06 +00:00
bellard
ffa65c3b70 fcntl flags convertion (Jocelyn Mayer)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@538 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-04 23:57:22 +00:00
bellard
2d603d2216 PowerPC support - float macros
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@537 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-04 23:56:24 +00:00
bellard
61190b14fc PowerPC update (Jocelyn Mayer)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@536 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-04 23:54:31 +00:00
bellard
9886cc165a factorized GenOpFunc
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@535 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-04 23:53:54 +00:00
bellard
ce09776be2 PowerPC System emulation (Jocelyn Mayer)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@534 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-04 23:53:18 +00:00
bellard
5be1a8e065 ppc fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@533 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-04 23:51:58 +00:00
bellard
09683d3597 changed cpu_x86_in/out to cpu_in/out
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@532 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-04 23:49:41 +00:00
bellard
590b7eed18 aalib support with SDL
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@531 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-04 23:49:02 +00:00
bellard
af5ad10728 infer access type
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@530 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-04 23:28:12 +00:00
bellard
ac9eb0731a suppressed explicit access type and use the exception routine to infer it from the micro operation
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@529 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-04 23:26:24 +00:00
bellard
9a64fbe4d8 PowerPC system emulation (Jocelyn Mayer) - modified patch to use new TLB api
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@528 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-04 22:58:38 +00:00
bellard
efe160c502 update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@527 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-04 18:28:47 +00:00
bellard
dc887a4dae make the bios be a ROM memory - glibc hacks for setvbuf and signals - correct century storage in CMOS emulation
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@526 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-04 18:18:57 +00:00
bellard
b9f1950797 hack for target_ulong define
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@525 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-04 18:17:13 +00:00
bellard
e16c53fabb assembly soft MMU defines on i386
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@524 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-04 18:15:29 +00:00
bellard
8351d2d481 WHEEL defines may not be available in SDL
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@523 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-04 18:15:01 +00:00
bellard
08785f48b7 updated so that PPC/ARM/SPARC executables are automatically launched when invoked
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@522 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-04 18:12:46 +00:00
bellard
75c6215f98 correct cpu state
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@521 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-04 18:08:37 +00:00
bellard
6b136f9e8f CD-ROM detection fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@520 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-04 18:08:12 +00:00
bellard
2ddbbd10de (temporary) only physical dump is possible in gdb
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@519 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-04 18:07:27 +00:00
bellard
9fa3e85353 new generic TLB support - faster self modifying code support - added ROM memory support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@518 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-04 18:06:42 +00:00
bellard
4390df5107 added support for direct patching on i386 host (faster emulation) - increased translation buffer size - added new TLB support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@517 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-04 18:03:10 +00:00
bellard
ecd854fdb4 added support for direct patching on i386 host (faster emulation)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@516 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-04 17:45:05 +00:00
bellard
513b500f75 include stddef.h for size_t definition
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@515 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-04 17:44:08 +00:00
bellard
edf75d592c export more memory defines
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@514 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-04 17:43:30 +00:00
bellard
1376847f9f support for new TLB handling
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@513 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-04 17:43:01 +00:00
bellard
17348a7f5e waiting for TARGET_HAS_SMC patch
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@512 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-04 17:36:11 +00:00
bellard
4f31916ffb added raw/user/kernel memory accesses for shifts/adc/sbb/cmpxchg/push/pop (faster emulation) - make 'call Ev' exception safe - in/out dx fix - PE flag is static
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@511 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-04 17:35:00 +00:00
bellard
943144d91a added raw/user/kernel memory accesses (faster emulation)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@510 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-04 17:31:11 +00:00
bellard
34e01bbf07 fixed dx based protected in/outs (win98 install) - changed JUMP_TB2 branch number arg
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@509 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-04 17:30:14 +00:00
bellard
7f1135b9a4 added stx_T1_A0 micro ops
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@508 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-04 17:28:06 +00:00
bellard
f68dd77007 fixed word bit operations with memory offset - suppressed push/pop micro operations
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@507 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-04 17:27:42 +00:00
bellard
436d8b892a correct value for ADDSEG is real mode (fixes GRUB boot) - update static protected mode state - use generic tlb_set_page()
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@506 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-04 17:26:31 +00:00
bellard
dc6f57fd55 debug updates - page_unprotect() is no longer needed in softmmu case
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@505 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-04 17:24:35 +00:00
bellard
65262d5738 added PE to static CPU state (avoids flushing translated code when swiching between protected and real mode) - moved memory defs to cpu-all.h
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@504 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-04 17:20:53 +00:00
bellard
773b93ee06 signal fix: update the host signal 'signal ignored' state to avoid unexpected -EINTR values (ash fix)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@503 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-04 17:15:59 +00:00
bellard
82c7e2a4c6 update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@501 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-04 16:10:33 +00:00
bellard
546cdbd77d first multi target test (lauches 'ls')
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@500 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-04 16:08:39 +00:00
bellard
c265508067 more precise PIT gate emulation
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@499 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-04 16:07:06 +00:00
bellard
dd4e27d810 removed test code
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@498 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-04 15:58:16 +00:00
bellard
a41bc9af8f explicited S3 specific code - added more debug code
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@497 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-04 15:55:00 +00:00
bellard
3bfd9da14f termios support for SPARC and PPC
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@496 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-04 15:52:31 +00:00
bellard
c573ff6752 stat64 fix - added getpagesize()
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@495 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-04 15:51:36 +00:00
bellard
060366c5ad SPARC fixes : syscall fixes - added user register window exception support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@494 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-04 15:50:01 +00:00
bellard
6da41eafc4 added CPU callbacks
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@493 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-04 15:48:38 +00:00
bellard
0124311e00 more generic TLB support - began to fix unlikely interrupt issues
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@492 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-04 15:48:17 +00:00
bellard
f515528907 aligned stack on 16 byte boundary - PPC target fixes - SPARC target fixes
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@491 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-04 15:46:50 +00:00
bellard
b453b70bd8 sparc fixes
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@490 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-04 15:45:21 +00:00
bellard
0ac4bd56a8 float access fixes
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@489 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-04 15:44:17 +00:00
bellard
3811a291e2 update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@488 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-04 15:27:57 +00:00
bellard
3415a4ddb4 invd and wbinvd support - fixed code gen logic for invlpg - simpler exception handling in load_seg()
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@487 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-04 15:21:33 +00:00
bellard
b7f0f463a5 debug fixes - use more generic TLB mappings
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@486 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-04 15:20:25 +00:00
bellard
8e682019e3 correct zero segment values when coming from VM86 mode - cache infos in CPUID - simpler exception handling in load_seg() - validate segments after lret/iret
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@485 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-04 15:18:37 +00:00
bellard
cf495bcf9f SPARC fixes: corrected PC/NPC logic (now slower but can be optimized a lot) - fixed flags computations - added register window exceptions support - fixed mul and div - added mulscc - fixed immediate field decoding
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@484 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-04 15:01:44 +00:00
bellard
fb0eaffc6d PowerPC fixes (Jocelyn Mayer)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@483 c046a42c-6fe2-441c-8c8c-71466251a162
2004-01-04 14:57:11 +00:00
bellard
07ad1b93a3 disable keyboard interrupts if keyboard clock disabled (may not be fully correct) - added keyboard ID for extended keyboard
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@482 c046a42c-6fe2-441c-8c8c-71466251a162
2003-12-02 22:18:10 +00:00
bellard
d36cd60e6c P4 style multiplication eflags
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@481 c046a42c-6fe2-441c-8c8c-71466251a162
2003-12-02 22:01:31 +00:00
bellard
5e809a8095 dump irq inhibit flag as it is a part of the cpu state
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@480 c046a42c-6fe2-441c-8c8c-71466251a162
2003-12-02 21:59:21 +00:00
bellard
791c2261d6 more complete eflags testing for multiplication (P4 case only)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@479 c046a42c-6fe2-441c-8c8c-71466251a162
2003-12-02 21:55:34 +00:00
bellard
163a7cb620 imull fix (suggested by Robert J. Harley)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@478 c046a42c-6fe2-441c-8c8c-71466251a162
2003-11-30 19:40:08 +00:00
bellard
6bb705711b a20 fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@477 c046a42c-6fe2-441c-8c8c-71466251a162
2003-11-23 23:26:39 +00:00
bellard
4136f33c7e fixed eflags IF/IOPL update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@476 c046a42c-6fe2-441c-8c8c-71466251a162
2003-11-23 23:09:40 +00:00
bellard
6dca2016fc fixed PPC state reloading
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@475 c046a42c-6fe2-441c-8c8c-71466251a162
2003-11-23 17:32:06 +00:00
bellard
678673089d PowerPC target support (Jocelyn Mayer) - added better support for uid16
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@474 c046a42c-6fe2-441c-8c8c-71466251a162
2003-11-23 17:05:30 +00:00
bellard
28b6751f30 suppressed use of gen_multi - use intermediate FT0 register for floats - use T0 temporary for fpscr update - use PARAM1 for spr access - added untested single load/store support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@473 c046a42c-6fe2-441c-8c8c-71466251a162
2003-11-23 16:58:08 +00:00
bellard
79aceca54a PowerPC support (Jocelyn Mayer)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@472 c046a42c-6fe2-441c-8c8c-71466251a162
2003-11-23 14:55:54 +00:00
bellard
6a8c397deb FTST instruction fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@471 c046a42c-6fe2-441c-8c8c-71466251a162
2003-11-22 23:57:34 +00:00
bellard
9cdf757fd5 more fcmovxx tests
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@470 c046a42c-6fe2-441c-8c8c-71466251a162
2003-11-19 22:12:47 +00:00
bellard
36bdbe5479 fixed TB linking in case of code invalidation (fixes random segfaults)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@469 c046a42c-6fe2-441c-8c8c-71466251a162
2003-11-19 22:12:02 +00:00
bellard
8004340674 added fcmovxx support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@468 c046a42c-6fe2-441c-8c8c-71466251a162
2003-11-19 22:09:03 +00:00
bellard
a2cc3b2433 added fcmovxx support (fixes segfaults in some recent linux tools) - fixed irq inhibit logic : the irqs are inhibited only for one instruction after, even if the next one also inhibit irqs - stop translation after irq inhibition stops to give a chance to irqs (fixes install NT kernel startup)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@467 c046a42c-6fe2-441c-8c8c-71466251a162
2003-11-19 22:08:13 +00:00
bellard
afa05eb15e always completely redefine the TLB in case of MMU fault
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@466 c046a42c-6fe2-441c-8c8c-71466251a162
2003-11-19 22:04:21 +00:00
bellard
de5eaa6452 static config for SDL
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@465 c046a42c-6fe2-441c-8c8c-71466251a162
2003-11-16 23:18:17 +00:00
bellard
7517502475 fcmovx support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@464 c046a42c-6fe2-441c-8c8c-71466251a162
2003-11-16 20:18:52 +00:00
bellard
8f2b1fb008 more hack for CMOS interruption (enable linux /dev/rtc not to hang) - auto boot on cdrom if only device present
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@463 c046a42c-6fe2-441c-8c8c-71466251a162
2003-11-16 19:46:01 +00:00
bellard
891b38e446 more precise stack operations in call/int gates (16 bit wrapping is handled in all cases) - makes all call/int gates operations restartable in case of exception
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@462 c046a42c-6fe2-441c-8c8c-71466251a162
2003-11-16 16:06:03 +00:00
bellard
7dea1da4ae quick and dirty CMOS irq emulation (windows install uses it) - emm386 keyboard fix (need a better way...) - better serial emulation (windows install uses it) - LDT and TR caches init fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@461 c046a42c-6fe2-441c-8c8c-71466251a162
2003-11-16 15:59:30 +00:00
bellard
4ce900b44c make windows happier
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@460 c046a42c-6fe2-441c-8c8c-71466251a162
2003-11-16 15:46:05 +00:00
bellard
f3f2d9be03 call gate fix - verr and verw fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@459 c046a42c-6fe2-441c-8c8c-71466251a162
2003-11-13 23:15:36 +00:00
bellard
77729c2445 fixed pop %sp bug
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@458 c046a42c-6fe2-441c-8c8c-71466251a162
2003-11-13 23:09:07 +00:00
bellard
d71b9a8b2f fixed lmsw instruction
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@457 c046a42c-6fe2-441c-8c8c-71466251a162
2003-11-13 02:48:18 +00:00
bellard
181f1558cd update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@456 c046a42c-6fe2-441c-8c8c-71466251a162
2003-11-13 01:47:16 +00:00
bellard
2750332396 Soundblaster 16 support (malc)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@455 c046a42c-6fe2-441c-8c8c-71466251a162
2003-11-13 01:46:15 +00:00
bellard
f115e911d7 iret and int fix for vm86 - added undefined instructions for real and vm86 modes - added verr, verrw, arpl - added port io map
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@454 c046a42c-6fe2-441c-8c8c-71466251a162
2003-11-13 01:43:28 +00:00
bellard
3ab493de4c added verr, verw, arpl - more precise segment rights checks
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@453 c046a42c-6fe2-441c-8c8c-71466251a162
2003-11-13 01:42:19 +00:00
bellard
3e25f9515a io map checks
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@452 c046a42c-6fe2-441c-8c8c-71466251a162
2003-11-13 00:13:08 +00:00
bellard
246d897f4c dump more registers
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@451 c046a42c-6fe2-441c-8c8c-71466251a162
2003-11-12 23:55:40 +00:00
bellard
7e84c2498f full TSS support - IO map check support - conforming segment check fixes - iret in vm86 mode fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@450 c046a42c-6fe2-441c-8c8c-71466251a162
2003-11-12 23:39:19 +00:00
bellard
e670b89e3b added comments and TSS bit
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@449 c046a42c-6fe2-441c-8c8c-71466251a162
2003-11-12 23:23:42 +00:00
bellard
bd0d90b21d make Knoppix CD-ROM probe happy
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@448 c046a42c-6fe2-441c-8c8c-71466251a162
2003-11-12 22:23:01 +00:00
bellard
1a0636f8d7 new VGA bios
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@447 c046a42c-6fe2-441c-8c8c-71466251a162
2003-11-11 14:20:17 +00:00
bellard
2e134c9c55 64-bit multiplication fix (Ulrich Hecht)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@446 c046a42c-6fe2-441c-8c8c-71466251a162
2003-11-11 13:55:33 +00:00
bellard
5391d80669 moved IDE driver to ide.c
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@445 c046a42c-6fe2-441c-8c8c-71466251a162
2003-11-11 13:48:59 +00:00
bellard
36b486bb74 hardware level IDE CD-ROM emulation - added second IDE interface for up to 4 IDE disks emulation - added -boot command to enable CD boot
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@444 c046a42c-6fe2-441c-8c8c-71466251a162
2003-11-11 13:36:08 +00:00
bellard
4ad06a29b2 soft mmu fix (aka debian random seg fault fix)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@443 c046a42c-6fe2-441c-8c8c-71466251a162
2003-11-09 16:58:12 +00:00
bellard
e58143b355 ppc fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@442 c046a42c-6fe2-441c-8c8c-71466251a162
2003-11-09 14:42:54 +00:00
bellard
1f5476fcce a20 support - keyboard led fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@441 c046a42c-6fe2-441c-8c8c-71466251a162
2003-11-04 23:35:20 +00:00
bellard
461c0471af a20 support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@440 c046a42c-6fe2-441c-8c8c-71466251a162
2003-11-04 23:34:23 +00:00
bellard
9c3ad57432 update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@439 c046a42c-6fe2-441c-8c8c-71466251a162
2003-11-04 23:33:13 +00:00
bellard
e748ba4f53 ARM half word load/store fix (Ulrich Hecht)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@438 c046a42c-6fe2-441c-8c8c-71466251a162
2003-11-03 22:25:25 +00:00
bellard
b8ed223bfe big endian fixes
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@437 c046a42c-6fe2-441c-8c8c-71466251a162
2003-10-30 22:10:22 +00:00
bellard
c970a162e7 temporary hack for PowerPC system emulation
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@436 c046a42c-6fe2-441c-8c8c-71466251a162
2003-10-30 01:21:44 +00:00
bellard
c321f67309 enabled system emulator build on PowerPC - increased portability of soft mmu code
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@435 c046a42c-6fe2-441c-8c8c-71466251a162
2003-10-30 01:18:42 +00:00
bellard
7f7f987341 endianness and portability fixes
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@434 c046a42c-6fe2-441c-8c8c-71466251a162
2003-10-30 01:11:23 +00:00
bellard
aebcb60e55 no need for locks in system mode
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@433 c046a42c-6fe2-441c-8c8c-71466251a162
2003-10-30 01:08:17 +00:00
bellard
1a18c71b50 unused functions in system mode
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@432 c046a42c-6fe2-441c-8c8c-71466251a162
2003-10-30 01:07:51 +00:00
bellard
03a6c5103d cannot simply write segment registers in system mode
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@431 c046a42c-6fe2-441c-8c8c-71466251a162
2003-10-30 01:07:22 +00:00
bellard
128b346e0a cmov fix (bug on PowerPC)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@430 c046a42c-6fe2-441c-8c8c-71466251a162
2003-10-30 01:05:49 +00:00
bellard
415fa2ea77 soft MMU performance fix (oops)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@429 c046a42c-6fe2-441c-8c8c-71466251a162
2003-10-30 00:39:38 +00:00
bellard
9951bf39f9 fixed long double accesses when using soft MMU
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@428 c046a42c-6fe2-441c-8c8c-71466251a162
2003-10-28 23:06:17 +00:00
bellard
8948b5d613 fixed ldq() macros
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@427 c046a42c-6fe2-441c-8c8c-71466251a162
2003-10-28 23:04:30 +00:00
bellard
5086347239 CONFIG_STATIC patch
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@426 c046a42c-6fe2-441c-8c8c-71466251a162
2003-10-28 23:04:01 +00:00
bellard
9d4520d0e0 update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@425 c046a42c-6fe2-441c-8c8c-71466251a162
2003-10-28 01:38:57 +00:00
bellard
5b9f457a89 update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@424 c046a42c-6fe2-441c-8c8c-71466251a162
2003-10-28 00:49:54 +00:00
bellard
3a4739d651 static link
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@423 c046a42c-6fe2-441c-8c8c-71466251a162
2003-10-28 00:48:22 +00:00
bellard
76b62fd001 added binary archive
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@422 c046a42c-6fe2-441c-8c8c-71466251a162
2003-10-28 00:47:44 +00:00
bellard
b1f645758a redhat 9 fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@421 c046a42c-6fe2-441c-8c8c-71466251a162
2003-10-28 00:47:19 +00:00
bellard
bc1b050d85 fixed distclean target
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@420 c046a42c-6fe2-441c-8c8c-71466251a162
2003-10-28 00:12:52 +00:00
bellard
03d5f74aee update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@419 c046a42c-6fe2-441c-8c8c-71466251a162
2003-10-28 00:09:43 +00:00
bellard
9f05cc34df fixed big endian ops
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@418 c046a42c-6fe2-441c-8c8c-71466251a162
2003-10-28 00:09:28 +00:00
227 changed files with 93656 additions and 10764 deletions

15
.cvsignore Normal file
View File

@@ -0,0 +1,15 @@
arm-user
config-host.*
dyngen
i386
i386-softmmu
i386-user
ppc-softmmu
ppc-user
qemu-doc.html
qemu-tech.html
qemu.1
qemu.pod
sparc-user
qemu-img
sparc-softmmu

152
Changelog
View File

@@ -1,3 +1,153 @@
version 0.6.1:
- Mac OS X port (Pierre d'Herbemont)
- Virtual console support
- Better monitor line edition
- New block device layer
- New 'qcow' growable disk image support with AES encryption and
transparent decompression
- VMware 3 and 4 read-only disk image support (untested)
- Support for up to 4 serial ports
- TFTP server support (Magnus Damm)
- Port redirection support in user mode networking
- Support for not executable data sections
- Compressed loop disk image support (Johannes Schindelin)
- Level triggered IRQ fix (aka NE2000 PCI performance fix) (Steve
Wormley)
- Fixed Fedora Core 2 problems (now you can run qemu without any
LD_ASSUME_KERNEL tricks on FC2)
- DHCP fix for Windows (accept DHCPREQUEST alone)
- SPARC system emulation (Blue Swirl)
- Automatic Samba configuration for host file access from Windows.
- '-loadvm' and '-full-screen' options
- ne2000 savevm support (Johannes Schindelin)
- Ctrl-Alt is now the default grab key. Ctrl-Alt-[0-9] switches to
the virtual consoles.
- BIOS floppy fix for NT4 (Mike Nordell, Derek Fawcus, Volker Ruppert)
- Floppy fixes for NT4 and NT5 (Mike Nordell)
- NT4 IDE fixes (Ben Pfaf, Mike Nordell)
- SDL Audio support and SB16 fixes (malc)
- ENTER instruction bug fix (initial patch by Stefan Kisdaroczi)
- VGA font change fix
- VGA read-only CRTC register fix
version 0.6.0:
- minimalist FPU exception support (NetBSD FPU probe fix)
- cr0.ET fix (Win95 boot)
- *BSD port (Markus Niemisto)
- I/O access fix (signaled by Mark Jonckheere)
- IDE drives serial number fix (Mike Nordell)
- int13 CDROM BIOS fix (aka Solaris x86 install CD fix)
- int15, ah=86 BIOS fix (aka Solaris x86 hardware probe hang up fix)
- BSR/BSF "undefined behaviour" fix
- vmdk2raw: convert VMware disk images to raw images
- PCI support
- NE2K PCI support
- dummy VGA PCI support
- VGA font selection fix (Daniel Serpell)
- PIC reset fix (Hidemi KAWAI)
- PIC spurious irq support (aka Solaris install bug)
- added '-localtime' option
- Cirrus CL-GD54xx VGA support (initial patch by Makoto Suzuki (suzu))
- APM and system shutdown support
- Fixed system reset
- Support for other PC BIOSes
- Initial PowerMac hardware emulation
- PowerMac/PREP OpenFirmware compatible BIOS (Jocelyn Mayer)
- initial IDE BMDMA support (needed for Darwin x86)
- Set the default memory size for PC emulation to 128 MB
version 0.5.5:
- SDL full screen support (initial patch by malc)
- VGA support on PowerPC PREP
- VBE fixes (Matthew Mastracci)
- PIT fixes (aka Win98 hardware probe and "VGA slowness" bug)
- IDE master only fixes (aka Win98 CD-ROM probe bug)
- ARM load/store half word fix (Ulrich Hecht)
- FDC fixes for Win98
version 0.5.4:
- qemu-fast fixes
- BIOS area protection fix (aka EMM386.EXE fix) (Mike Nordell)
- keyboard/mouse fix (Mike Nordell)
- IDE fixes (Linux did not recognized slave drivers)
- VM86 EIP masking fix (aka NT5 install fix) (Mike Nordell)
- QEMU can now boot a PowerPC Linux kernel (Jocelyn Mayer)
- User mode network stack
- imul imm8 fix + 0x82 opcode support (Hidemi KAWAI)
- precise self modifying code (aka BeOS install bug)
version 0.5.3:
- added Bochs VESA VBE support
- VGA memory map mode 3 access fix (OS/2 install fix)
- IDE fixes (Jens Axboe)
- CPU interrupt fixes
- fixed various TLB invalidation cases (NT install)
- fixed cr0.WP semantics (XP install)
- direct chaining support for SPARC and PowerPC (faster)
- ARM NWFPE support (initial patch by Ulrich Hecht)
- added specific x86 to x86 translator (close to native performance
in qemu-i386 and qemu-fast)
- shm syscalls support (Paul McKerras)
- added accurate CR0.MP/ME/TS emulation
- fixed DMA memory write access (Win95 boot floppy fix)
- graphical x86 linux loader
- command line monitor
- generic removable device support
- support of CD-ROM change
- multiple network interface support
- initial x86-64 host support (Gwenole Beauchesne)
- lret to outer priviledge fix (OS/2 install fix)
- task switch fixes (SkyOS boot)
- VM save/restore commands
- new timer API
- more precise RTC emulation (periodic timers + time updates)
- Win32 port (initial patch by Kazu)
version 0.5.2:
- improved soft MMU speed (assembly functions and specializing)
- improved multitasking speed by avoiding flushing TBs when
switching tasks
- improved qemu-fast speed
- improved self modifying code handling (big performance gain in
softmmu mode).
- fixed IO checking
- fixed CD-ROM detection (win98 install CD)
- fixed addseg real mode bug (GRUB boot fix)
- added ROM memory support (win98 boot)
- fixed 'call Ev' in case of paging exception
- updated the script 'qemu-binfmt-conf.sh' to use QEMU automagically
when launching executables for the supported target CPUs.
- PowerPC system emulation update (Jocelyn Mayer)
- PC floppy emulation and DMA fixes (Jocelyn Mayer)
- polled mode for PIC (Jocelyn Mayer)
- fixed PTE dirty bit handling
- fixed xadd same reg bug
- fixed cmpxchg exception safeness
- access to virtual memory in gdb stub
- task gate and NT flag fixes
- eflags optimisation fix for string operations
version 0.5.1:
- float access fixes when using soft mmu
- PC emulation support on PowerPC
- A20 support
- IDE CD-ROM emulation
- ARM fixes (Ulrich Hecht)
- SB16 emulation (malc)
- IRET and INT fixes in VM86 mode with IOPL=3
- Port I/Os use TSS io map
- Full task switching/task gate support
- added verr, verw, arpl, fcmovxx
- PowerPC target support (Jocelyn Mayer)
- Major SPARC target fixes (dynamically linked programs begin to work)
version 0.5.0:
- full hardware level VGA emulation
@@ -18,7 +168,7 @@ version 0.5.0:
- 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.
- added full soft mmu mode to launch unpatched OSes.
version 0.4.3:

View File

@@ -1,59 +1,77 @@
include config-host.mak
-include config-host.mak
CFLAGS=-Wall -O2 -g
CFLAGS=-Wall -O2 -g -fno-strict-aliasing
ifdef CONFIG_DARWIN
CFLAGS+= -mdynamic-no-pic
endif
ifdef CONFIG_WIN32
CFLAGS+=-fpack-struct
endif
LDFLAGS=-g
LIBS=
DEFINES+=-D_GNU_SOURCE
TOOLS=qemu-mkcow
DEFINES+=-D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE
TOOLS=qemu-img
ifdef CONFIG_STATIC
LDFLAGS+=-static
endif
DOCS=qemu-doc.html qemu-tech.html qemu.1
all: dyngen $(TOOLS) qemu-doc.html qemu.1
all: dyngen$(EXESUF) $(TOOLS) $(DOCS)
for d in $(TARGET_DIRS); do \
make -C $$d $@ || exit 1 ; \
$(MAKE) -C $$d $@ || exit 1 ; \
done
qemu-mkcow: qemu-mkcow.o
$(HOST_CC) -o $@ $^ $(LIBS)
qemu-img: qemu-img.c block.c block-cow.c block-qcow.c aes.c block-vmdk.c block-cloop.c
$(CC) -DQEMU_TOOL $(CFLAGS) $(LDFLAGS) $(DEFINES) -o $@ $^ -lz $(LIBS)
dyngen: dyngen.o
$(HOST_CC) -o $@ $^ $(LIBS)
%.o: %.c
$(HOST_CC) $(CFLAGS) $(DEFINES) -c -o $@ $<
dyngen$(EXESUF): dyngen.c
$(HOST_CC) $(CFLAGS) $(DEFINES) -o $@ $^
clean:
# 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
rm -f *.o *.a $(TOOLS) dyngen$(EXESUF) TAGS qemu.pod *~ */*~
$(MAKE) -C tests clean
for d in $(TARGET_DIRS); do \
make -C $$d $@ || exit 1 ; \
$(MAKE) -C $$d $@ || exit 1 ; \
done
distclean: clean
rm -f config-host.mak config-host.h
for d in $(TARGET_DIRS); do \
rm -f $$d/config.h $$d/config.mak || exit 1 ; \
rm -rf $$d || exit 1 ; \
done
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
mkdir -p "$(bindir)"
ifndef CONFIG_WIN32
install -m 755 -s $(TOOLS) "$(bindir)"
endif
mkdir -p "$(datadir)"
install -m 644 pc-bios/bios.bin pc-bios/vgabios.bin \
pc-bios/vgabios-cirrus.bin \
pc-bios/ppc_rom.bin \
pc-bios/proll.bin \
pc-bios/linux_boot.bin "$(datadir)"
mkdir -p "$(docdir)"
install -m 644 qemu-doc.html qemu-tech.html "$(docdir)"
ifndef CONFIG_WIN32
mkdir -p "$(mandir)/man1"
install qemu.1 qemu-mkcow.1 "$(mandir)/man1"
endif
for d in $(TARGET_DIRS); do \
make -C $$d $@ || exit 1 ; \
$(MAKE) -C $$d $@ || exit 1 ; \
done
# various test targets
test speed: all
make -C tests $@
test speed test2: all
$(MAKE) -C tests $@
TAGS:
etags *.[ch] tests/*.[ch]
# documentation
qemu-doc.html: qemu-doc.texi
%.html: %.texi
texi2html -monolithic -number $<
qemu.1: qemu-doc.texi
@@ -66,17 +84,28 @@ FILE=qemu-$(shell cat VERSION)
tar:
rm -rf /tmp/$(FILE)
cp -r . /tmp/$(FILE)
( cd /tmp ; tar zcvf ~/$(FILE).tar.gz $(FILE) )
( cd /tmp ; tar zcvf ~/$(FILE).tar.gz $(FILE) --exclude CVS )
rm -rf /tmp/$(FILE)
# generate a binary distribution including the test binary environnment
BINPATH=/usr/local/qemu-i386
# generate a binary distribution
tarbin:
tar zcvf /tmp/qemu-$(VERSION)-i386-glibc21.tar.gz \
$(BINPATH)/etc $(BINPATH)/lib $(BINPATH)/bin $(BINPATH)/usr
tar zcvf /tmp/qemu-$(VERSION)-i386-wine.tar.gz \
$(BINPATH)/wine
( cd / ; tar zcvf ~/qemu-$(VERSION)-i386.tar.gz \
$(bindir)/qemu $(bindir)/qemu-fast \
$(bindir)/qemu-system-ppc \
$(bindir)/qemu-i386 \
$(bindir)/qemu-arm \
$(bindir)/qemu-sparc \
$(bindir)/qemu-ppc \
$(bindir)/qemu-img \
$(datadir)/bios.bin \
$(datadir)/vgabios.bin \
$(datadir)/vgabios-cirrus.bin \
$(datadir)/ppc_rom.bin \
$(datadir)/proll.bin \
$(datadir)/linux_boot.bin \
$(docdir)/qemu-doc.html \
$(docdir)/qemu-tech.html \
$(mandir)/man1/qemu.1 $(mandir)/man1/qemu-mkcow.1 )
ifneq ($(wildcard .depend),)
include .depend

View File

@@ -1,18 +1,26 @@
include config.mak
TARGET_PATH=$(SRC_PATH)/target-$(TARGET_ARCH)
VPATH=$(SRC_PATH):$(TARGET_PATH)
CFLAGS=-Wall -O2 -g
VPATH=$(SRC_PATH):$(TARGET_PATH):$(SRC_PATH)/hw:$(SRC_PATH)/audio
DEFINES=-I. -I$(TARGET_PATH) -I$(SRC_PATH)
ifdef CONFIG_USER_ONLY
VPATH+=:$(SRC_PATH)/linux-user
DEFINES+=-I$(SRC_PATH)/linux-user -I$(SRC_PATH)/linux-user/$(TARGET_ARCH)
endif
CFLAGS=-Wall -O2 -g -fno-strict-aliasing
LDFLAGS=-g
LIBS=
DEFINES=-I. -I$(TARGET_PATH) -I$(SRC_PATH)
HELPER_CFLAGS=$(CFLAGS)
DYNGEN=../dyngen
DYNGEN=../dyngen$(EXESUF)
# user emulator name
QEMU_USER=qemu-$(TARGET_ARCH)
# system emulator name
ifdef CONFIG_SOFTMMU
QEMU_SYSTEM=qemu
ifeq ($(TARGET_ARCH), i386)
QEMU_SYSTEM=qemu$(EXESUF)
else
QEMU_SYSTEM=qemu-system-$(TARGET_ARCH)$(EXESUF)
endif
else
QEMU_SYSTEM=qemu-fast
endif
@@ -20,12 +28,62 @@ endif
ifdef CONFIG_USER_ONLY
PROGS=$(QEMU_USER)
else
ifeq ($(ARCH),i386)
ifeq ($(TARGET_ARCH), i386)
ifeq ($(ARCH), i386)
PROGS+=$(QEMU_SYSTEM)
ifndef CONFIG_SOFTMMU
CONFIG_STATIC=y
endif
else
# the system emulator using soft mmu is portable
ifdef CONFIG_SOFTMMU
PROGS+=$(QEMU_SYSTEM)
endif
endif # ARCH != i386
endif # TARGET_ARCH = i386
ifeq ($(TARGET_ARCH), ppc)
ifeq ($(ARCH), ppc)
PROGS+=$(QEMU_SYSTEM)
endif
ifeq ($(ARCH), i386)
ifdef CONFIG_SOFTMMU
PROGS+=$(QEMU_SYSTEM)
endif
endif # ARCH = i386
ifeq ($(ARCH), amd64)
ifdef CONFIG_SOFTMMU
PROGS+=$(QEMU_SYSTEM)
endif
endif # ARCH = amd64
endif # TARGET_ARCH = ppc
ifeq ($(TARGET_ARCH), sparc)
ifeq ($(ARCH), ppc)
PROGS+=$(QEMU_SYSTEM)
endif
ifeq ($(ARCH), i386)
ifdef CONFIG_SOFTMMU
PROGS+=$(QEMU_SYSTEM)
endif
endif # ARCH = i386
ifeq ($(ARCH), amd64)
ifdef CONFIG_SOFTMMU
PROGS+=$(QEMU_SYSTEM)
endif
endif # ARCH = amd64
endif # TARGET_ARCH = sparc
endif # !CONFIG_USER_ONLY
ifdef CONFIG_STATIC
LDFLAGS+=-static
@@ -35,11 +93,18 @@ ifeq ($(ARCH),i386)
CFLAGS+=-fomit-frame-pointer
OP_CFLAGS=$(CFLAGS) -mpreferred-stack-boundary=2
ifeq ($(HAVE_GCC3_OPTIONS),yes)
OP_CFLAGS+= -falign-functions=0
OP_CFLAGS+= -falign-functions=0 -fno-gcse
else
OP_CFLAGS+= -malign-functions=0
endif
ifdef TARGET_GPROF
USE_I386_LD=y
endif
ifdef CONFIG_STATIC
USE_I386_LD=y
endif
ifdef USE_I386_LD
LDFLAGS+=-Wl,-T,$(SRC_PATH)/i386.ld
else
# WARNING: this LDFLAGS is _very_ tricky : qemu is an ELF shared object
@@ -49,7 +114,13 @@ LDFLAGS+=-Wl,-shared
endif
endif
ifeq ($(ARCH),amd64)
OP_CFLAGS=$(CFLAGS) -falign-functions=0
LDFLAGS+=-Wl,-T,$(SRC_PATH)/amd64.ld
endif
ifeq ($(ARCH),ppc)
CFLAGS+= -D__powerpc__
OP_CFLAGS=$(CFLAGS)
LDFLAGS+=-Wl,-T,$(SRC_PATH)/ppc.ld
endif
@@ -102,10 +173,20 @@ ifeq ($(HAVE_GCC3_OPTIONS),yes)
OP_CFLAGS+=-fno-reorder-blocks -fno-optimize-sibling-calls
endif
ifeq ($(CONFIG_DARWIN),yes)
OP_CFLAGS+= -mdynamic-no-pic
endif
#########################################################
DEFINES+=-D_GNU_SOURCE
DEFINES+=-D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE
LIBS+=-lm
ifndef CONFIG_USER_ONLY
LIBS+=-lz
endif
ifdef CONFIG_WIN32
LIBS+=-lwinmm -lws2_32 -liphlpapi
endif
# profiling code
ifdef TARGET_GPROF
@@ -113,24 +194,46 @@ LDFLAGS+=-p
main.o: CFLAGS+=-p
endif
OBJS= elfload.o main.o syscall.o mmap.o signal.o path.o
OBJS= elfload.o main.o syscall.o mmap.o signal.o path.o osdep.o thunk.o
ifeq ($(TARGET_ARCH), i386)
OBJS+= vm86.o
endif
ifeq ($(TARGET_ARCH), arm)
OBJS+=nwfpe/softfloat.o nwfpe/fpa11.o nwfpe/fpa11_cpdo.o \
nwfpe/fpa11_cpdt.o nwfpe/fpa11_cprt.o nwfpe/fpopcode.o nwfpe/single_cpdo.o \
nwfpe/double_cpdo.o nwfpe/extended_cpdo.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 \
LIBOBJS=exec.o translate-all.o cpu-exec.o\
translate.o op.o
ifeq ($(TARGET_ARCH), i386)
LIBOBJS+=helper.o helper2.o
ifeq ($(ARCH), i386)
LIBOBJS+=translate-copy.o
endif
endif
ifeq ($(TARGET_ARCH), ppc)
LIBOBJS+= op_helper.o helper.o
endif
ifeq ($(TARGET_ARCH), sparc)
LIBOBJS+= op_helper.o helper.o
endif
# NOTE: the disassembler code is only needed for debugging
LIBOBJS+=disas.o
ifeq ($(findstring i386, $(TARGET_ARCH) $(ARCH)),i386)
USE_I386_DIS=y
endif
ifeq ($(findstring amd64, $(TARGET_ARCH) $(ARCH)),amd64)
USE_I386_DIS=y
endif
ifdef USE_I386_DIS
LIBOBJS+=i386-dis.o
endif
ifeq ($(findstring alpha, $(TARGET_ARCH) $(ARCH)),alpha)
@@ -161,18 +264,81 @@ ifeq ($(ARCH),alpha)
endif
# must use static linking to avoid leaving stuff in virtual address space
VL_OBJS=vl.o block.o vga.o
VL_OBJS=vl.o osdep.o block.o readline.o monitor.o pci.o console.o
VL_OBJS+=block-cow.o block-qcow.o aes.o block-vmdk.o block-cloop.o
SOUND_HW = sb16.o
AUDIODRV = audio.o noaudio.o wavaudio.o
ifdef CONFIG_SDL
AUDIODRV += sdlaudio.o
endif
ifdef CONFIG_OSS
AUDIODRV += ossaudio.o
endif
pc.o: DEFINES := -DUSE_SB16 $(DEFINES)
ifdef CONFIG_ADLIB
SOUND_HW += fmopl.o adlib.o
endif
ifdef CONFIG_FMOD
AUDIODRV += fmodaudio.o
audio.o fmodaudio.o: DEFINES := -I$(CONFIG_FMOD_INC) $(DEFINES)
LIBS += $(CONFIG_FMOD_LIB)
endif
ifeq ($(TARGET_ARCH), i386)
# Hardware support
VL_OBJS+= ide.o ne2000.o pckbd.o vga.o $(SOUND_HW) dma.o $(AUDIODRV)
VL_OBJS+= fdc.o mc146818rtc.o serial.o i8259.o i8254.o pc.o
VL_OBJS+= cirrus_vga.o mixeng.o
endif
ifeq ($(TARGET_ARCH), ppc)
VL_OBJS+= ppc.o ide.o ne2000.o pckbd.o vga.o $(SOUND_HW) dma.o $(AUDIODRV)
VL_OBJS+= mc146818rtc.o serial.o i8259.o i8254.o fdc.o m48t59.o
VL_OBJS+= ppc_prep.o ppc_chrp.o cuda.o adb.o openpic.o mixeng.o
endif
ifeq ($(TARGET_ARCH), sparc)
VL_OBJS+= sun4m.o tcx.o lance.o iommu.o sched.o m48t08.o magic-load.o timer.o
endif
ifdef CONFIG_GDBSTUB
VL_OBJS+=gdbstub.o
endif
ifdef CONFIG_SDL
VL_OBJS+=sdl.o
SDL_LIBS+=-L/usr/X11R6/lib -lX11 -lXext -lXv -ldl -lm
endif
ifdef CONFIG_SLIRP
DEFINES+=-I$(SRC_PATH)/slirp
SLIRP_OBJS=cksum.o if.o ip_icmp.o ip_input.o ip_output.o \
slirp.o mbuf.o misc.o sbuf.o socket.o tcp_input.o tcp_output.o \
tcp_subr.o tcp_timer.o udp.o bootp.o debug.o tftp.o
VL_OBJS+=$(addprefix slirp/, $(SLIRP_OBJS))
endif
VL_LDFLAGS=
# specific flags are needed for non soft mmu emulator
ifdef CONFIG_STATIC
VL_LDFLAGS+=-static
endif
ifndef CONFIG_SOFTMMU
VL_LDFLAGS+=-Wl,-T,$(SRC_PATH)/i386-vl.ld
endif
ifndef CONFIG_DARWIN
ifndef CONFIG_WIN32
VL_LIBS=-lutil
endif
endif
$(QEMU_SYSTEM): $(VL_OBJS) libqemu.a
$(CC) -static -Wl,-T,$(SRC_PATH)/i386-vl.ld -o $@ $^ $(LIBS) $(SDL_LIBS)
$(CC) $(VL_LDFLAGS) -o $@ $^ $(LIBS) $(SDL_LIBS) $(VL_LIBS)
sdl.o: sdl.c
$(CC) $(CFLAGS) $(DEFINES) $(SDL_CFLAGS) -c -o $@ $<
sdlaudio.o: sdlaudio.c
$(CC) $(CFLAGS) $(DEFINES) $(SDL_CFLAGS) -c -o $@ $<
depend: $(SRCS)
$(CC) -MM $(CFLAGS) $(DEFINES) $^ 1>.depend
@@ -210,17 +376,29 @@ op.o: op.c op_template.h
endif
ifeq ($(TARGET_ARCH), sparc)
op.o: op.c op_template.h
op.o: op.c op_template.h op_mem.h
endif
ifeq ($(TARGET_ARCH), ppc)
op.o: op.c op_template.h op_mem.h
op_helper.o: op_helper_mem.h
endif
mixeng.o: mixeng.c mixeng.h mixeng_template.h
%.o: %.c
$(CC) $(CFLAGS) $(DEFINES) -c -o $@ $<
%.o: %.S
$(CC) $(DEFINES) -c -o $@ $<
clean:
rm -f *.o *.a *~ $(PROGS) gen-op.h opc.h op.h
rm -f *.o *.a *~ $(PROGS) gen-op.h opc.h op.h nwfpe/*.o slirp/*.o
install: all
install -m 755 -s $(PROGS) $(prefix)/bin
ifneq ($(PROGS),)
install -m 755 -s $(PROGS) "$(bindir)"
endif
ifneq ($(wildcard .depend),)
include .depend

55
TODO
View File

@@ -1,23 +1,60 @@
short term:
----------
- debug option in 'configure' script + disable -fomit-frame-pointer
- Solaris display error with Cirrus VGA
(http://lists.gnu.org/archive/html/qemu-devel/2004-10/msg00390.html).
- Precise VGA timings for old games/demos (malc patch)
- merge PIC spurious interrupt patch
- merge VNC keyboard patch
- merge Solaris patch
- merge ARM patches + self modifying code patch (Paul Brook)
- warning for OS/2: must not use 128 MB memory
- config file (at least for windows/Mac OS X)
- commit message if execution of code in IO memory
- update doc: PCI infos.
- VNC patch + Synaptic patch.
- basic VGA optimizations
- test sysenter/sysexit and fxsr for L4 pistachio 686
- physical memory cache (reduce qemu-fast address space size to about 32 MB)
- better code fetch (different exception handling + CS.limit support)
- do not resize vga if invalid size.
- avoid looping if only exceptions
- cycle counter for all archs
- TLB code protection support for PPC
- see openMosix Doc
- disable SMC handling for ARM/SPARC/PPC (not finished)
- see undefined flags for BTx insn
- user/kernel PUSHL/POPL in helper.c
- keyboard output buffer filling timing emulation
- return UD exception if LOCK prefix incorrectly used
- test ldt limit < 7 ?
- 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)
- SMP support
ppc specific:
------------
- TLB invalidate not needed if msr_pr changes
- endianness bugs in do_load_fpscr and do_store_fpscr
- SPR_ENCODE() not useful
- enable shift optimizations ?
lower priority:
--------------
- more friendly BIOS (logo)
- int15 ah=86: use better timing
- HDD geometry in CMOS (not used except for very old DOS programs)
- suppress shift_mem ops
- fix some 16 bit sp push/pop overflow (pusha/popa, lcall lret)
- sysenter/sysexit emulation
- optimize FPU operations (evaluate x87 stack pointer statically)
- 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
- handle rare page fault cases (in particular if page fault in helpers 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

View File

@@ -1 +1 @@
0.5.0
0.6.1

431
a.out.h Normal file
View File

@@ -0,0 +1,431 @@
/* a.out.h
Copyright 1997, 1998, 1999, 2001 Red Hat, Inc.
This file is part of Cygwin.
This software is a copyrighted work licensed under the terms of the
Cygwin license. Please consult the file "CYGWIN_LICENSE" for
details. */
#ifndef _A_OUT_H_
#define _A_OUT_H_
#ifdef __cplusplus
extern "C" {
#endif
#define COFF_IMAGE_WITH_PE
#define COFF_LONG_SECTION_NAMES
/*** coff information for Intel 386/486. */
/********************** FILE HEADER **********************/
struct external_filehdr {
short f_magic; /* magic number */
short f_nscns; /* number of sections */
unsigned long f_timdat; /* time & date stamp */
unsigned long f_symptr; /* file pointer to symtab */
unsigned long f_nsyms; /* number of symtab entries */
short f_opthdr; /* sizeof(optional hdr) */
short f_flags; /* flags */
};
/* Bits for f_flags:
* F_RELFLG relocation info stripped from file
* F_EXEC file is executable (no unresolved external references)
* F_LNNO line numbers stripped from file
* F_LSYMS local symbols stripped from file
* F_AR32WR file has byte ordering of an AR32WR machine (e.g. vax)
*/
#define F_RELFLG (0x0001)
#define F_EXEC (0x0002)
#define F_LNNO (0x0004)
#define F_LSYMS (0x0008)
#define I386MAGIC 0x14c
#define I386PTXMAGIC 0x154
#define I386AIXMAGIC 0x175
/* This is Lynx's all-platform magic number for executables. */
#define LYNXCOFFMAGIC 0415
#define I386BADMAG(x) (((x).f_magic != I386MAGIC) \
&& (x).f_magic != I386AIXMAGIC \
&& (x).f_magic != I386PTXMAGIC \
&& (x).f_magic != LYNXCOFFMAGIC)
#define FILHDR struct external_filehdr
#define FILHSZ 20
/********************** AOUT "OPTIONAL HEADER"=
**********************/
typedef struct
{
unsigned short magic; /* type of file */
unsigned short vstamp; /* version stamp */
unsigned long tsize; /* text size in bytes, padded to FW bdry*/
unsigned long dsize; /* initialized data " " */
unsigned long bsize; /* uninitialized data " " */
unsigned long entry; /* entry pt. */
unsigned long text_start; /* base of text used for this file */
unsigned long data_start; /* base of data used for this file=
*/
}
AOUTHDR;
#define AOUTSZ 28
#define AOUTHDRSZ 28
#define OMAGIC 0404 /* object files, eg as output */
#define ZMAGIC 0413 /* demand load format, eg normal ld output */
#define STMAGIC 0401 /* target shlib */
#define SHMAGIC 0443 /* host shlib */
/* define some NT default values */
/* #define NT_IMAGE_BASE 0x400000 moved to internal.h */
#define NT_SECTION_ALIGNMENT 0x1000
#define NT_FILE_ALIGNMENT 0x200
#define NT_DEF_RESERVE 0x100000
#define NT_DEF_COMMIT 0x1000
/********************** SECTION HEADER **********************/
struct external_scnhdr {
char s_name[8]; /* section name */
unsigned long s_paddr; /* physical address, offset
of last addr in scn */
unsigned long s_vaddr; /* virtual address */
unsigned long s_size; /* section size */
unsigned long s_scnptr; /* file ptr to raw data for section */
unsigned long s_relptr; /* file ptr to relocation */
unsigned long s_lnnoptr; /* file ptr to line numbers */
unsigned short s_nreloc; /* number of relocation entries */
unsigned short s_nlnno; /* number of line number entries*/
unsigned long s_flags; /* flags */
};
#define SCNHDR struct external_scnhdr
#define SCNHSZ 40
/*
* names of "special" sections
*/
#define _TEXT ".text"
#define _DATA ".data"
#define _BSS ".bss"
#define _COMMENT ".comment"
#define _LIB ".lib"
/********************** LINE NUMBERS **********************/
/* 1 line number entry for every "breakpointable" source line in a section.
* Line numbers are grouped on a per function basis; first entry in a function
* grouping will have l_lnno = 0 and in place of physical address will be the
* symbol table index of the function name.
*/
struct external_lineno {
union {
unsigned long l_symndx; /* function name symbol index, iff l_lnno 0 */
unsigned long l_paddr; /* (physical) address of line number */
} l_addr;
unsigned short l_lnno; /* line number */
};
#define LINENO struct external_lineno
#define LINESZ 6
/********************** SYMBOLS **********************/
#define E_SYMNMLEN 8 /* # characters in a symbol name */
#define E_FILNMLEN 14 /* # characters in a file name */
#define E_DIMNUM 4 /* # array dimensions in auxiliary entry */
struct external_syment
{
union {
char e_name[E_SYMNMLEN];
struct {
unsigned long e_zeroes;
unsigned long e_offset;
} e;
} e;
unsigned long e_value;
unsigned short e_scnum;
unsigned short e_type;
char e_sclass[1];
char e_numaux[1];
};
#define N_BTMASK (0xf)
#define N_TMASK (0x30)
#define N_BTSHFT (4)
#define N_TSHIFT (2)
union external_auxent {
struct {
unsigned long x_tagndx; /* str, un, or enum tag indx */
union {
struct {
unsigned short x_lnno; /* declaration line number */
unsigned short x_size; /* str/union/array size */
} x_lnsz;
unsigned long x_fsize; /* size of function */
} x_misc;
union {
struct { /* if ISFCN, tag, or .bb */
unsigned long x_lnnoptr;/* ptr to fcn line # */
unsigned long x_endndx; /* entry ndx past block end */
} x_fcn;
struct { /* if ISARY, up to 4 dimen. */
char x_dimen[E_DIMNUM][2];
} x_ary;
} x_fcnary;
unsigned short x_tvndx; /* tv index */
} x_sym;
union {
char x_fname[E_FILNMLEN];
struct {
unsigned long x_zeroes;
unsigned long x_offset;
} x_n;
} x_file;
struct {
unsigned long x_scnlen; /* section length */
unsigned short x_nreloc; /* # relocation entries */
unsigned short x_nlinno; /* # line numbers */
unsigned long x_checksum; /* section COMDAT checksum */
unsigned short x_associated;/* COMDAT associated section index */
char x_comdat[1]; /* COMDAT selection number */
} x_scn;
struct {
unsigned long x_tvfill; /* tv fill value */
unsigned short x_tvlen; /* length of .tv */
char x_tvran[2][2]; /* tv range */
} x_tv; /* info about .tv section (in auxent of symbol .tv)) */
};
#define SYMENT struct external_syment
#define SYMESZ 18
#define AUXENT union external_auxent
#define AUXESZ 18
#define _ETEXT "etext"
/********************** RELOCATION DIRECTIVES **********************/
struct external_reloc {
char r_vaddr[4];
char r_symndx[4];
char r_type[2];
};
#define RELOC struct external_reloc
#define RELSZ 10
/* end of coff/i386.h */
/* PE COFF header information */
#ifndef _PE_H
#define _PE_H
/* NT specific file attributes */
#define IMAGE_FILE_RELOCS_STRIPPED 0x0001
#define IMAGE_FILE_EXECUTABLE_IMAGE 0x0002
#define IMAGE_FILE_LINE_NUMS_STRIPPED 0x0004
#define IMAGE_FILE_LOCAL_SYMS_STRIPPED 0x0008
#define IMAGE_FILE_BYTES_REVERSED_LO 0x0080
#define IMAGE_FILE_32BIT_MACHINE 0x0100
#define IMAGE_FILE_DEBUG_STRIPPED 0x0200
#define IMAGE_FILE_SYSTEM 0x1000
#define IMAGE_FILE_DLL 0x2000
#define IMAGE_FILE_BYTES_REVERSED_HI 0x8000
/* additional flags to be set for section headers to allow the NT loader to
read and write to the section data (to replace the addresses of data in
dlls for one thing); also to execute the section in .text's case=
*/
#define IMAGE_SCN_MEM_DISCARDABLE 0x02000000
#define IMAGE_SCN_MEM_EXECUTE 0x20000000
#define IMAGE_SCN_MEM_READ 0x40000000
#define IMAGE_SCN_MEM_WRITE 0x80000000
/*
* Section characteristics added for ppc-nt
*/
#define IMAGE_SCN_TYPE_NO_PAD 0x00000008 /* Reserved. */
#define IMAGE_SCN_CNT_CODE 0x00000020 /* Section contains code. */
#define IMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040 /* Section contains initialized data. */
#define IMAGE_SCN_CNT_UNINITIALIZED_DATA 0x00000080 /* Section contains uninitialized data. */
#define IMAGE_SCN_LNK_OTHER 0x00000100 /* Reserved. */
#define IMAGE_SCN_LNK_INFO 0x00000200 /* Section contains comments or some other type of information. */
#define IMAGE_SCN_LNK_REMOVE 0x00000800 /* Section contents will not become part of image. */
#define IMAGE_SCN_LNK_COMDAT 0x00001000 /* Section contents comdat. */
#define IMAGE_SCN_MEM_FARDATA 0x00008000
#define IMAGE_SCN_MEM_PURGEABLE 0x00020000
#define IMAGE_SCN_MEM_16BIT 0x00020000
#define IMAGE_SCN_MEM_LOCKED 0x00040000
#define IMAGE_SCN_MEM_PRELOAD 0x00080000
#define IMAGE_SCN_ALIGN_1BYTES 0x00100000
#define IMAGE_SCN_ALIGN_2BYTES 0x00200000
#define IMAGE_SCN_ALIGN_4BYTES 0x00300000
#define IMAGE_SCN_ALIGN_8BYTES 0x00400000
#define IMAGE_SCN_ALIGN_16BYTES 0x00500000 /* Default alignment if no others are specified. */
#define IMAGE_SCN_ALIGN_32BYTES 0x00600000
#define IMAGE_SCN_ALIGN_64BYTES 0x00700000
#define IMAGE_SCN_LNK_NRELOC_OVFL 0x01000000 /* Section contains extended relocations. */
#define IMAGE_SCN_MEM_NOT_CACHED 0x04000000 /* Section is not cachable. */
#define IMAGE_SCN_MEM_NOT_PAGED 0x08000000 /* Section is not pageable. */
#define IMAGE_SCN_MEM_SHARED 0x10000000 /* Section is shareable. */
/* COMDAT selection codes. */
#define IMAGE_COMDAT_SELECT_NODUPLICATES (1) /* Warn if duplicates. */
#define IMAGE_COMDAT_SELECT_ANY (2) /* No warning. */
#define IMAGE_COMDAT_SELECT_SAME_SIZE (3) /* Warn if different size. */
#define IMAGE_COMDAT_SELECT_EXACT_MATCH (4) /* Warn if different. */
#define IMAGE_COMDAT_SELECT_ASSOCIATIVE (5) /* Base on other section. */
/* Magic values that are true for all dos/nt implementations */
#define DOSMAGIC 0x5a4d
#define NT_SIGNATURE 0x00004550
/* NT allows long filenames, we want to accommodate this. This may break
some of the bfd functions */
#undef FILNMLEN
#define FILNMLEN 18 /* # characters in a file name */
#ifdef COFF_IMAGE_WITH_PE
/* The filehdr is only weired in images */
#undef FILHDR
struct external_PE_filehdr
{
/* DOS header fields */
unsigned short e_magic; /* Magic number, 0x5a4d */
unsigned short e_cblp; /* Bytes on last page of file, 0x90 */
unsigned short e_cp; /* Pages in file, 0x3 */
unsigned short e_crlc; /* Relocations, 0x0 */
unsigned short e_cparhdr; /* Size of header in paragraphs, 0x4 */
unsigned short e_minalloc; /* Minimum extra paragraphs needed, 0x0 */
unsigned short e_maxalloc; /* Maximum extra paragraphs needed, 0xFFFF */
unsigned short e_ss; /* Initial (relative) SS value, 0x0 */
unsigned short e_sp; /* Initial SP value, 0xb8 */
unsigned short e_csum; /* Checksum, 0x0 */
unsigned short e_ip; /* Initial IP value, 0x0 */
unsigned short e_cs; /* Initial (relative) CS value, 0x0 */
unsigned short e_lfarlc; /* File address of relocation table, 0x40 */
unsigned short e_ovno; /* Overlay number, 0x0 */
char e_res[4][2]; /* Reserved words, all 0x0 */
unsigned short e_oemid; /* OEM identifier (for e_oeminfo), 0x0 */
unsigned short e_oeminfo; /* OEM information; e_oemid specific, 0x0 */
char e_res2[10][2]; /* Reserved words, all 0x0 */
unsigned long e_lfanew; /* File address of new exe header, 0x80 */
char dos_message[16][4]; /* other stuff, always follow DOS header */
unsigned int nt_signature; /* required NT signature, 0x4550 */
/* From standard header */
unsigned short f_magic; /* magic number */
unsigned short f_nscns; /* number of sections */
unsigned long f_timdat; /* time & date stamp */
unsigned long f_symptr; /* file pointer to symtab */
unsigned long f_nsyms; /* number of symtab entries */
unsigned short f_opthdr; /* sizeof(optional hdr) */
unsigned short f_flags; /* flags */
};
#define FILHDR struct external_PE_filehdr
#undef FILHSZ
#define FILHSZ 152
#endif
typedef struct
{
unsigned short magic; /* type of file */
unsigned short vstamp; /* version stamp */
unsigned long tsize; /* text size in bytes, padded to FW bdry*/
unsigned long dsize; /* initialized data " " */
unsigned long bsize; /* uninitialized data " " */
unsigned long entry; /* entry pt. */
unsigned long text_start; /* base of text used for this file */
unsigned long data_start; /* base of all data used for this file */
/* NT extra fields; see internal.h for descriptions */
unsigned long ImageBase;
unsigned long SectionAlignment;
unsigned long FileAlignment;
unsigned short MajorOperatingSystemVersion;
unsigned short MinorOperatingSystemVersion;
unsigned short MajorImageVersion;
unsigned short MinorImageVersion;
unsigned short MajorSubsystemVersion;
unsigned short MinorSubsystemVersion;
char Reserved1[4];
unsigned long SizeOfImage;
unsigned long SizeOfHeaders;
unsigned long CheckSum;
unsigned short Subsystem;
unsigned short DllCharacteristics;
unsigned long SizeOfStackReserve;
unsigned long SizeOfStackCommit;
unsigned long SizeOfHeapReserve;
unsigned long SizeOfHeapCommit;
unsigned long LoaderFlags;
unsigned long NumberOfRvaAndSizes;
/* IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; */
char DataDirectory[16][2][4]; /* 16 entries, 2 elements/entry, 4 chars */
} PEAOUTHDR;
#undef AOUTSZ
#define AOUTSZ (AOUTHDRSZ + 196)
#undef E_FILNMLEN
#define E_FILNMLEN 18 /* # characters in a file name */
#endif
/* end of coff/pe.h */
#define DT_NON (0) /* no derived type */
#define DT_PTR (1) /* pointer */
#define DT_FCN (2) /* function */
#define DT_ARY (3) /* array */
#define ISPTR(x) (((x) & N_TMASK) == (DT_PTR << N_BTSHFT))
#define ISFCN(x) (((x) & N_TMASK) == (DT_FCN << N_BTSHFT))
#define ISARY(x) (((x) & N_TMASK) == (DT_ARY << N_BTSHFT))
#ifdef __cplusplus
}
#endif
#endif /* _A_OUT_H_ */

1317
aes.c Normal file

File diff suppressed because it is too large Load Diff

26
aes.h Normal file
View File

@@ -0,0 +1,26 @@
#ifndef QEMU_AES_H
#define QEMU_AES_H
#define AES_MAXNR 14
#define AES_BLOCK_SIZE 16
struct aes_key_st {
uint32_t rd_key[4 *(AES_MAXNR + 1)];
int rounds;
};
typedef struct aes_key_st AES_KEY;
int AES_set_encrypt_key(const unsigned char *userKey, const int bits,
AES_KEY *key);
int AES_set_decrypt_key(const unsigned char *userKey, const int bits,
AES_KEY *key);
void AES_encrypt(const unsigned char *in, unsigned char *out,
const AES_KEY *key);
void AES_decrypt(const unsigned char *in, unsigned char *out,
const AES_KEY *key);
void AES_cbc_encrypt(const unsigned char *in, unsigned char *out,
const unsigned long length, const AES_KEY *key,
unsigned char *ivec, const int enc);
#endif

171
amd64.ld Normal file
View File

@@ -0,0 +1,171 @@
/* Default linker script, for normal executables */
OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64", "elf64-x86-64")
OUTPUT_ARCH(i386:x86-64)
ENTRY(_start)
SEARCH_DIR("/lib64"); SEARCH_DIR("/usr/lib64"); SEARCH_DIR("/usr/local/lib64");
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.init : { *(.rel.init) }
.rela.init : { *(.rela.init) }
.rel.text : { *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*) }
.rela.text : { *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) }
.rel.fini : { *(.rel.fini) }
.rela.fini : { *(.rela.fini) }
.rel.rodata : { *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*) }
.rela.rodata : { *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) }
.rel.data : { *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*) }
.rela.data : { *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) }
.rel.tdata : { *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*) }
.rela.tdata : { *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) }
.rel.tbss : { *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*) }
.rela.tbss : { *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) }
.rel.ctors : { *(.rel.ctors) }
.rela.ctors : { *(.rela.ctors) }
.rel.dtors : { *(.rel.dtors) }
.rela.dtors : { *(.rela.dtors) }
.rel.got : { *(.rel.got) }
.rela.got : { *(.rela.got) }
.rel.bss : { *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) }
.rela.bss : { *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) }
.rel.plt : { *(.rel.plt) }
.rela.plt : { *(.rela.plt) }
.init :
{
KEEP (*(.init))
} =0x90909090
.plt : { *(.plt) }
.text :
{
*(.text .stub .text.* .gnu.linkonce.t.*)
/* .gnu.warning sections are handled specially by elf32.em. */
*(.gnu.warning)
} =0x90909090
.fini :
{
KEEP (*(.fini))
} =0x90909090
PROVIDE (__etext = .);
PROVIDE (_etext = .);
PROVIDE (etext = .);
.rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
.rodata1 : { *(.rodata1) }
.eh_frame_hdr : { *(.eh_frame_hdr) }
.eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) }
.gcc_except_table : ONLY_IF_RO { *(.gcc_except_table) }
/* 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 - .) & (0x100000 - 1)); . = DATA_SEGMENT_ALIGN (0x100000, 0x1000);
/* 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(64 / 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 : ONLY_IF_RW { KEEP (*(.eh_frame)) }
.gcc_except_table : ONLY_IF_RW { *(.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(64 / 8);
}
. = ALIGN(64 / 8);
_end = .;
PROVIDE (end = .);
. = DATA_SEGMENT_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) }
}

910
audio/audio.c Normal file
View File

@@ -0,0 +1,910 @@
/*
* QEMU Audio subsystem
*
* Copyright (c) 2003-2004 Vassili Karpov (malc)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <assert.h>
#include "vl.h"
#define USE_WAV_AUDIO
#include "audio/audio_int.h"
#define dolog(...) AUD_log ("audio", __VA_ARGS__)
#ifdef DEBUG
#define ldebug(...) dolog (__VA_ARGS__)
#else
#define ldebug(...)
#endif
#define QC_AUDIO_DRV "QEMU_AUDIO_DRV"
#define QC_VOICES "QEMU_VOICES"
#define QC_FIXED_FORMAT "QEMU_FIXED_FORMAT"
#define QC_FIXED_FREQ "QEMU_FIXED_FREQ"
static HWVoice *hw_voices;
AudioState audio_state = {
1, /* use fixed settings */
44100, /* fixed frequency */
2, /* fixed channels */
AUD_FMT_S16, /* fixed format */
1, /* number of hw voices */
-1 /* voice size */
};
/* http://www.df.lth.se/~john_e/gems/gem002d.html */
/* http://www.multi-platforms.com/Tips/PopCount.htm */
uint32_t popcount (uint32_t u)
{
u = ((u&0x55555555) + ((u>>1)&0x55555555));
u = ((u&0x33333333) + ((u>>2)&0x33333333));
u = ((u&0x0f0f0f0f) + ((u>>4)&0x0f0f0f0f));
u = ((u&0x00ff00ff) + ((u>>8)&0x00ff00ff));
u = ( u&0x0000ffff) + (u>>16);
return u;
}
inline uint32_t lsbindex (uint32_t u)
{
return popcount ((u&-u)-1);
}
int audio_get_conf_int (const char *key, int defval)
{
int val = defval;
char *strval;
strval = getenv (key);
if (strval) {
val = atoi (strval);
}
return val;
}
const char *audio_get_conf_str (const char *key, const char *defval)
{
const char *val = getenv (key);
if (!val)
return defval;
else
return val;
}
void AUD_log (const char *cap, const char *fmt, ...)
{
va_list ap;
fprintf (stderr, "%s: ", cap);
va_start (ap, fmt);
vfprintf (stderr, fmt, ap);
va_end (ap);
}
/*
* Soft Voice
*/
void pcm_sw_free_resources (SWVoice *sw)
{
if (sw->buf) qemu_free (sw->buf);
if (sw->rate) st_rate_stop (sw->rate);
sw->buf = NULL;
sw->rate = NULL;
}
int pcm_sw_alloc_resources (SWVoice *sw)
{
sw->buf = qemu_mallocz (sw->hw->samples * sizeof (st_sample_t));
if (!sw->buf)
return -1;
sw->rate = st_rate_start (sw->freq, sw->hw->freq);
if (!sw->rate) {
qemu_free (sw->buf);
sw->buf = NULL;
return -1;
}
return 0;
}
void pcm_sw_fini (SWVoice *sw)
{
pcm_sw_free_resources (sw);
}
int pcm_sw_init (SWVoice *sw, HWVoice *hw, int freq,
int nchannels, audfmt_e fmt)
{
int bits = 8, sign = 0;
switch (fmt) {
case AUD_FMT_S8:
sign = 1;
case AUD_FMT_U8:
break;
case AUD_FMT_S16:
sign = 1;
case AUD_FMT_U16:
bits = 16;
break;
}
sw->hw = hw;
sw->freq = freq;
sw->fmt = fmt;
sw->nchannels = nchannels;
sw->shift = (nchannels == 2) + (bits == 16);
sw->align = (1 << sw->shift) - 1;
sw->left = 0;
sw->pos = 0;
sw->wpos = 0;
sw->live = 0;
sw->ratio = (sw->hw->freq * ((int64_t) INT_MAX)) / sw->freq;
sw->bytes_per_second = sw->freq << sw->shift;
sw->conv = mixeng_conv[nchannels == 2][sign][bits == 16];
pcm_sw_free_resources (sw);
return pcm_sw_alloc_resources (sw);
}
/* Hard voice */
void pcm_hw_free_resources (HWVoice *hw)
{
if (hw->mix_buf)
qemu_free (hw->mix_buf);
hw->mix_buf = NULL;
}
int pcm_hw_alloc_resources (HWVoice *hw)
{
hw->mix_buf = qemu_mallocz (hw->samples * sizeof (st_sample_t));
if (!hw->mix_buf)
return -1;
return 0;
}
void pcm_hw_fini (HWVoice *hw)
{
if (hw->active) {
ldebug ("pcm_hw_fini: %d %d %d\n", hw->freq, hw->nchannels, hw->fmt);
pcm_hw_free_resources (hw);
hw->pcm_ops->fini (hw);
memset (hw, 0, audio_state.drv->voice_size);
}
}
void pcm_hw_gc (HWVoice *hw)
{
if (hw->nb_voices)
return;
pcm_hw_fini (hw);
}
int pcm_hw_get_live (HWVoice *hw)
{
int i, alive = 0, live = hw->samples;
for (i = 0; i < hw->nb_voices; i++) {
if (hw->pvoice[i]->live) {
live = audio_MIN (hw->pvoice[i]->live, live);
alive += 1;
}
}
if (alive)
return live;
else
return -1;
}
int pcm_hw_get_live2 (HWVoice *hw, int *nb_active)
{
int i, alive = 0, live = hw->samples;
*nb_active = 0;
for (i = 0; i < hw->nb_voices; i++) {
if (hw->pvoice[i]->live) {
if (hw->pvoice[i]->live < live) {
*nb_active = hw->pvoice[i]->active != 0;
live = hw->pvoice[i]->live;
}
alive += 1;
}
}
if (alive)
return live;
else
return -1;
}
void pcm_hw_dec_live (HWVoice *hw, int decr)
{
int i;
for (i = 0; i < hw->nb_voices; i++) {
if (hw->pvoice[i]->live) {
hw->pvoice[i]->live -= decr;
}
}
}
void pcm_hw_clear (HWVoice *hw, void *buf, int len)
{
if (!len)
return;
switch (hw->fmt) {
case AUD_FMT_S16:
case AUD_FMT_S8:
memset (buf, len << hw->shift, 0x00);
break;
case AUD_FMT_U8:
memset (buf, len << hw->shift, 0x80);
break;
case AUD_FMT_U16:
{
unsigned int i;
uint16_t *p = buf;
int shift = hw->nchannels - 1;
for (i = 0; i < len << shift; i++) {
p[i] = INT16_MAX;
}
}
break;
}
}
int pcm_hw_write (SWVoice *sw, void *buf, int size)
{
int hwsamples, samples, isamp, osamp, wpos, live, dead, left, swlim, blck;
int ret = 0, pos = 0;
if (!sw)
return size;
hwsamples = sw->hw->samples;
samples = size >> sw->shift;
if (!sw->live) {
sw->wpos = sw->hw->rpos;
}
wpos = sw->wpos;
live = sw->live;
dead = hwsamples - live;
swlim = (dead * ((int64_t) INT_MAX)) / sw->ratio;
swlim = audio_MIN (swlim, samples);
ldebug ("size=%d live=%d dead=%d swlim=%d wpos=%d\n",
size, live, dead, swlim, wpos);
if (swlim)
sw->conv (sw->buf, buf, swlim);
while (swlim) {
dead = hwsamples - live;
left = hwsamples - wpos;
blck = audio_MIN (dead, left);
if (!blck) {
/* dolog ("swlim=%d\n", swlim); */
break;
}
isamp = swlim;
osamp = blck;
st_rate_flow (sw->rate, sw->buf + pos, sw->hw->mix_buf + wpos, &isamp, &osamp);
ret += isamp;
swlim -= isamp;
pos += isamp;
live += osamp;
wpos = (wpos + osamp) % hwsamples;
}
sw->wpos = wpos;
sw->live = live;
return ret << sw->shift;
}
int pcm_hw_init (HWVoice *hw, int freq, int nchannels, audfmt_e fmt)
{
int sign = 0, bits = 8;
pcm_hw_fini (hw);
ldebug ("pcm_hw_init: %d %d %d\n", freq, nchannels, fmt);
if (hw->pcm_ops->init (hw, freq, nchannels, fmt)) {
memset (hw, 0, audio_state.drv->voice_size);
return -1;
}
switch (hw->fmt) {
case AUD_FMT_S8:
sign = 1;
case AUD_FMT_U8:
break;
case AUD_FMT_S16:
sign = 1;
case AUD_FMT_U16:
bits = 16;
break;
}
hw->nb_voices = 0;
hw->active = 1;
hw->shift = (hw->nchannels == 2) + (bits == 16);
hw->bytes_per_second = hw->freq << hw->shift;
hw->align = (1 << hw->shift) - 1;
hw->samples = hw->bufsize >> hw->shift;
hw->clip = mixeng_clip[hw->nchannels == 2][sign][bits == 16];
if (pcm_hw_alloc_resources (hw)) {
pcm_hw_fini (hw);
return -1;
}
return 0;
}
static int dist (void *hw)
{
if (hw) {
return (((uint8_t *) hw - (uint8_t *) hw_voices)
/ audio_state.voice_size) + 1;
}
else {
return 0;
}
}
#define ADVANCE(hw) hw ? advance (hw, audio_state.voice_size) : hw_voices
HWVoice *pcm_hw_find_any (HWVoice *hw)
{
int i = dist (hw);
for (; i < audio_state.nb_hw_voices; i++) {
hw = ADVANCE (hw);
return hw;
}
return NULL;
}
HWVoice *pcm_hw_find_any_active (HWVoice *hw)
{
int i = dist (hw);
for (; i < audio_state.nb_hw_voices; i++) {
hw = ADVANCE (hw);
if (hw->active)
return hw;
}
return NULL;
}
HWVoice *pcm_hw_find_any_active_enabled (HWVoice *hw)
{
int i = dist (hw);
for (; i < audio_state.nb_hw_voices; i++) {
hw = ADVANCE (hw);
if (hw->active && hw->enabled)
return hw;
}
return NULL;
}
HWVoice *pcm_hw_find_any_passive (HWVoice *hw)
{
int i = dist (hw);
for (; i < audio_state.nb_hw_voices; i++) {
hw = ADVANCE (hw);
if (!hw->active)
return hw;
}
return NULL;
}
HWVoice *pcm_hw_find_specific (HWVoice *hw, int freq,
int nchannels, audfmt_e fmt)
{
while ((hw = pcm_hw_find_any_active (hw))) {
if (hw->freq == freq &&
hw->nchannels == nchannels &&
hw->fmt == fmt)
return hw;
}
return NULL;
}
HWVoice *pcm_hw_add (int freq, int nchannels, audfmt_e fmt)
{
HWVoice *hw;
if (audio_state.fixed_format) {
freq = audio_state.fixed_freq;
nchannels = audio_state.fixed_channels;
fmt = audio_state.fixed_fmt;
}
hw = pcm_hw_find_specific (NULL, freq, nchannels, fmt);
if (hw)
return hw;
hw = pcm_hw_find_any_passive (NULL);
if (hw) {
hw->pcm_ops = audio_state.drv->pcm_ops;
if (!hw->pcm_ops)
return NULL;
if (pcm_hw_init (hw, freq, nchannels, fmt)) {
pcm_hw_gc (hw);
return NULL;
}
else
return hw;
}
return pcm_hw_find_any (NULL);
}
int pcm_hw_add_sw (HWVoice *hw, SWVoice *sw)
{
SWVoice **pvoice = qemu_mallocz ((hw->nb_voices + 1) * sizeof (sw));
if (!pvoice)
return -1;
memcpy (pvoice, hw->pvoice, hw->nb_voices * sizeof (sw));
qemu_free (hw->pvoice);
hw->pvoice = pvoice;
hw->pvoice[hw->nb_voices++] = sw;
return 0;
}
int pcm_hw_del_sw (HWVoice *hw, SWVoice *sw)
{
int i, j;
if (hw->nb_voices > 1) {
SWVoice **pvoice = qemu_mallocz ((hw->nb_voices - 1) * sizeof (sw));
if (!pvoice) {
dolog ("Can not maintain consistent state (not enough memory)\n");
return -1;
}
for (i = 0, j = 0; i < hw->nb_voices; i++) {
if (j >= hw->nb_voices - 1) {
dolog ("Can not maintain consistent state "
"(invariant violated)\n");
return -1;
}
if (hw->pvoice[i] != sw)
pvoice[j++] = hw->pvoice[i];
}
qemu_free (hw->pvoice);
hw->pvoice = pvoice;
hw->nb_voices -= 1;
}
else {
qemu_free (hw->pvoice);
hw->pvoice = NULL;
hw->nb_voices = 0;
}
return 0;
}
SWVoice *pcm_create_voice_pair (int freq, int nchannels, audfmt_e fmt)
{
SWVoice *sw;
HWVoice *hw;
sw = qemu_mallocz (sizeof (*sw));
if (!sw)
goto err1;
hw = pcm_hw_add (freq, nchannels, fmt);
if (!hw)
goto err2;
if (pcm_hw_add_sw (hw, sw))
goto err3;
if (pcm_sw_init (sw, hw, freq, nchannels, fmt))
goto err4;
return sw;
err4:
pcm_hw_del_sw (hw, sw);
err3:
pcm_hw_gc (hw);
err2:
qemu_free (sw);
err1:
return NULL;
}
SWVoice *AUD_open (SWVoice *sw, const char *name,
int freq, int nchannels, audfmt_e fmt)
{
if (!audio_state.drv) {
return NULL;
}
if (sw && freq == sw->freq && sw->nchannels == nchannels && sw->fmt == fmt) {
return sw;
}
if (sw) {
ldebug ("Different format %s %d %d %d\n",
name,
sw->freq == freq,
sw->nchannels == nchannels,
sw->fmt == fmt);
}
if (nchannels != 1 && nchannels != 2) {
dolog ("Bogus channel count %d for voice %s\n", nchannels, name);
return NULL;
}
if (!audio_state.fixed_format && sw) {
pcm_sw_fini (sw);
pcm_hw_del_sw (sw->hw, sw);
pcm_hw_gc (sw->hw);
if (sw->name) {
qemu_free (sw->name);
sw->name = NULL;
}
qemu_free (sw);
sw = NULL;
}
if (sw) {
HWVoice *hw = sw->hw;
if (!hw) {
dolog ("Internal logic error voice %s has no hardware store\n",
name);
return sw;
}
if (pcm_sw_init (sw, hw, freq, nchannels, fmt)) {
pcm_sw_fini (sw);
pcm_hw_del_sw (hw, sw);
pcm_hw_gc (hw);
if (sw->name) {
qemu_free (sw->name);
sw->name = NULL;
}
qemu_free (sw);
return NULL;
}
}
else {
sw = pcm_create_voice_pair (freq, nchannels, fmt);
if (!sw) {
dolog ("Failed to create voice %s\n", name);
return NULL;
}
}
if (sw->name) {
qemu_free (sw->name);
sw->name = NULL;
}
sw->name = qemu_strdup (name);
return sw;
}
void AUD_close (SWVoice *sw)
{
if (!sw)
return;
pcm_sw_fini (sw);
pcm_hw_del_sw (sw->hw, sw);
pcm_hw_gc (sw->hw);
if (sw->name) {
qemu_free (sw->name);
sw->name = NULL;
}
qemu_free (sw);
}
int AUD_write (SWVoice *sw, void *buf, int size)
{
int bytes;
if (!sw->hw->enabled)
dolog ("Writing to disabled voice %s\n", sw->name);
bytes = sw->hw->pcm_ops->write (sw, buf, size);
return bytes;
}
void AUD_run (void)
{
HWVoice *hw = NULL;
while ((hw = pcm_hw_find_any_active_enabled (hw))) {
int i;
if (hw->pending_disable && pcm_hw_get_live (hw) <= 0) {
hw->enabled = 0;
hw->pcm_ops->ctl (hw, VOICE_DISABLE);
for (i = 0; i < hw->nb_voices; i++) {
hw->pvoice[i]->live = 0;
/* hw->pvoice[i]->old_ticks = 0; */
}
continue;
}
hw->pcm_ops->run (hw);
assert (hw->rpos < hw->samples);
for (i = 0; i < hw->nb_voices; i++) {
SWVoice *sw = hw->pvoice[i];
if (!sw->active && !sw->live && sw->old_ticks) {
int64_t delta = qemu_get_clock (vm_clock) - sw->old_ticks;
if (delta > audio_state.ticks_threshold) {
ldebug ("resetting old_ticks for %s\n", sw->name);
sw->old_ticks = 0;
}
}
}
}
}
int AUD_get_free (SWVoice *sw)
{
int free;
if (!sw)
return 4096;
free = ((sw->hw->samples - sw->live) << sw->hw->shift) * sw->ratio
/ INT_MAX;
free &= ~sw->hw->align;
if (!free) return 0;
return free;
}
int AUD_get_buffer_size (SWVoice *sw)
{
return sw->hw->bufsize;
}
void AUD_adjust (SWVoice *sw, int bytes)
{
if (!sw)
return;
sw->old_ticks += (ticks_per_sec * (int64_t) bytes) / sw->bytes_per_second;
}
void AUD_reset (SWVoice *sw)
{
sw->active = 0;
sw->old_ticks = 0;
}
int AUD_calc_elapsed (SWVoice *sw)
{
int64_t now, delta, bytes;
int dead, swlim;
if (!sw)
return 0;
now = qemu_get_clock (vm_clock);
delta = now - sw->old_ticks;
bytes = (delta * sw->bytes_per_second) / ticks_per_sec;
if (delta < 0) {
dolog ("whoops delta(<0)=%lld\n", delta);
return 0;
}
dead = sw->hw->samples - sw->live;
swlim = ((dead * (int64_t) INT_MAX) / sw->ratio);
if (bytes > swlim) {
return swlim;
}
else {
return bytes;
}
}
void AUD_enable (SWVoice *sw, int on)
{
int i;
HWVoice *hw;
if (!sw)
return;
hw = sw->hw;
if (on) {
if (!sw->live)
sw->wpos = sw->hw->rpos;
if (!sw->old_ticks) {
sw->old_ticks = qemu_get_clock (vm_clock);
}
}
if (sw->active != on) {
if (on) {
hw->pending_disable = 0;
if (!hw->enabled) {
hw->enabled = 1;
for (i = 0; i < hw->nb_voices; i++) {
ldebug ("resetting voice\n");
sw = hw->pvoice[i];
sw->old_ticks = qemu_get_clock (vm_clock);
}
hw->pcm_ops->ctl (hw, VOICE_ENABLE);
}
}
else {
if (hw->enabled && !hw->pending_disable) {
int nb_active = 0;
for (i = 0; i < hw->nb_voices; i++) {
nb_active += hw->pvoice[i]->active != 0;
}
if (nb_active == 1) {
hw->pending_disable = 1;
}
}
}
sw->active = on;
}
}
static struct audio_output_driver *drvtab[] = {
#ifdef CONFIG_OSS
&oss_output_driver,
#endif
#ifdef CONFIG_FMOD
&fmod_output_driver,
#endif
#ifdef CONFIG_SDL
&sdl_output_driver,
#endif
&no_output_driver,
#ifdef USE_WAV_AUDIO
&wav_output_driver,
#endif
};
static int voice_init (struct audio_output_driver *drv)
{
audio_state.opaque = drv->init ();
if (audio_state.opaque) {
if (audio_state.nb_hw_voices > drv->max_voices) {
dolog ("`%s' does not support %d multiple hardware channels\n"
"Resetting to %d\n",
drv->name, audio_state.nb_hw_voices, drv->max_voices);
audio_state.nb_hw_voices = drv->max_voices;
}
hw_voices = qemu_mallocz (audio_state.nb_hw_voices * drv->voice_size);
if (hw_voices) {
audio_state.drv = drv;
return 1;
}
else {
dolog ("Not enough memory for %d `%s' voices (each %d bytes)\n",
audio_state.nb_hw_voices, drv->name, drv->voice_size);
drv->fini (audio_state.opaque);
return 0;
}
}
else {
dolog ("Could not init `%s' audio\n", drv->name);
return 0;
}
}
static void audio_vm_stop_handler (void *opaque, int reason)
{
HWVoice *hw = NULL;
while ((hw = pcm_hw_find_any (hw))) {
if (!hw->pcm_ops)
continue;
hw->pcm_ops->ctl (hw, reason ? VOICE_ENABLE : VOICE_DISABLE);
}
}
static void audio_atexit (void)
{
HWVoice *hw = NULL;
while ((hw = pcm_hw_find_any (hw))) {
if (!hw->pcm_ops)
continue;
hw->pcm_ops->ctl (hw, VOICE_DISABLE);
hw->pcm_ops->fini (hw);
}
audio_state.drv->fini (audio_state.opaque);
}
static void audio_save (QEMUFile *f, void *opaque)
{
}
static int audio_load (QEMUFile *f, void *opaque, int version_id)
{
if (version_id != 1)
return -EINVAL;
return 0;
}
void AUD_init (void)
{
int i;
int done = 0;
const char *drvname;
audio_state.fixed_format =
!!audio_get_conf_int (QC_FIXED_FORMAT, audio_state.fixed_format);
audio_state.fixed_freq =
audio_get_conf_int (QC_FIXED_FREQ, audio_state.fixed_freq);
audio_state.nb_hw_voices =
audio_get_conf_int (QC_VOICES, audio_state.nb_hw_voices);
if (audio_state.nb_hw_voices <= 0) {
dolog ("Bogus number of voices %d, resetting to 1\n",
audio_state.nb_hw_voices);
}
drvname = audio_get_conf_str (QC_AUDIO_DRV, NULL);
if (drvname) {
int found = 0;
for (i = 0; i < sizeof (drvtab) / sizeof (drvtab[0]); i++) {
if (!strcmp (drvname, drvtab[i]->name)) {
done = voice_init (drvtab[i]);
found = 1;
break;
}
}
if (!found) {
dolog ("Unknown audio driver `%s'\n", drvname);
}
}
qemu_add_vm_stop_handler (audio_vm_stop_handler, NULL);
atexit (audio_atexit);
if (!done) {
for (i = 0; !done && i < sizeof (drvtab) / sizeof (drvtab[0]); i++) {
if (drvtab[i]->can_be_default)
done = voice_init (drvtab[i]);
}
}
audio_state.ticks_threshold = ticks_per_sec / 50;
audio_state.freq_threshold = 100;
register_savevm ("audio", 0, 1, audio_save, audio_load, NULL);
if (!done) {
dolog ("Can not initialize audio subsystem\n");
voice_init (&no_output_driver);
}
}

65
audio/audio.h Normal file
View File

@@ -0,0 +1,65 @@
/*
* QEMU Audio subsystem header
*
* Copyright (c) 2003-2004 Vassili Karpov (malc)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef QEMU_AUDIO_H
#define QEMU_AUDIO_H
#include "mixeng.h"
typedef enum {
AUD_FMT_U8,
AUD_FMT_S8,
AUD_FMT_U16,
AUD_FMT_S16
} audfmt_e;
typedef struct SWVoice SWVoice;
SWVoice * AUD_open (SWVoice *sw, const char *name, int freq,
int nchannels, audfmt_e fmt);
void AUD_init (void);
void AUD_log (const char *cap, const char *fmt, ...)
__attribute__ ((__format__ (__printf__, 2, 3)));;
void AUD_close (SWVoice *sw);
int AUD_write (SWVoice *sw, void *pcm_buf, int size);
void AUD_adjust (SWVoice *sw, int leftover);
void AUD_reset (SWVoice *sw);
int AUD_get_free (SWVoice *sw);
int AUD_get_buffer_size (SWVoice *sw);
void AUD_run (void);
void AUD_enable (SWVoice *sw, int on);
int AUD_calc_elapsed (SWVoice *sw);
static inline void *advance (void *p, int incr)
{
uint8_t *d = p;
return (d + incr);
}
uint32_t popcount (uint32_t u);
inline uint32_t lsbindex (uint32_t u);
#define audio_MIN(a, b) ((a)>(b)?(b):(a))
#define audio_MAX(a, b) ((a)<(b)?(b):(a))
#endif /* audio.h */

164
audio/audio_int.h Normal file
View File

@@ -0,0 +1,164 @@
/*
* QEMU Audio subsystem header
*
* Copyright (c) 2003-2004 Vassili Karpov (malc)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef QEMU_AUDIO_INT_H
#define QEMU_AUDIO_INT_H
#include "vl.h"
struct pcm_ops;
typedef struct HWVoice {
int active;
int enabled;
int pending_disable;
int valid;
int freq;
f_sample *clip;
audfmt_e fmt;
int nchannels;
int align;
int shift;
int rpos;
int bufsize;
int bytes_per_second;
st_sample_t *mix_buf;
int samples;
int64_t old_ticks;
int nb_voices;
struct SWVoice **pvoice;
struct pcm_ops *pcm_ops;
} HWVoice;
extern struct pcm_ops no_pcm_ops;
extern struct audio_output_driver no_output_driver;
extern struct pcm_ops oss_pcm_ops;
extern struct audio_output_driver oss_output_driver;
extern struct pcm_ops sdl_pcm_ops;
extern struct audio_output_driver sdl_output_driver;
extern struct pcm_ops wav_pcm_ops;
extern struct audio_output_driver wav_output_driver;
extern struct pcm_ops fmod_pcm_ops;
extern struct audio_output_driver fmod_output_driver;
struct audio_output_driver {
const char *name;
void *(*init) (void);
void (*fini) (void *);
struct pcm_ops *pcm_ops;
int can_be_default;
int max_voices;
int voice_size;
};
typedef struct AudioState {
int fixed_format;
int fixed_freq;
int fixed_channels;
int fixed_fmt;
int nb_hw_voices;
int voice_size;
int64_t ticks_threshold;
int freq_threshold;
void *opaque;
struct audio_output_driver *drv;
} AudioState;
extern AudioState audio_state;
struct SWVoice {
int freq;
audfmt_e fmt;
int nchannels;
int shift;
int align;
t_sample *conv;
int left;
int pos;
int bytes_per_second;
int64_t ratio;
st_sample_t *buf;
void *rate;
int wpos;
int live;
int active;
int64_t old_ticks;
HWVoice *hw;
char *name;
};
struct pcm_ops {
int (*init) (HWVoice *hw, int freq, int nchannels, audfmt_e fmt);
void (*fini) (HWVoice *hw);
void (*run) (HWVoice *hw);
int (*write) (SWVoice *sw, void *buf, int size);
int (*ctl) (HWVoice *hw, int cmd, ...);
};
void pcm_sw_free_resources (SWVoice *sw);
int pcm_sw_alloc_resources (SWVoice *sw);
void pcm_sw_fini (SWVoice *sw);
int pcm_sw_init (SWVoice *sw, HWVoice *hw, int freq,
int nchannels, audfmt_e fmt);
void pcm_hw_clear (HWVoice *hw, void *buf, int len);
HWVoice * pcm_hw_find_any (HWVoice *hw);
HWVoice * pcm_hw_find_any_active (HWVoice *hw);
HWVoice * pcm_hw_find_any_passive (HWVoice *hw);
HWVoice * pcm_hw_find_specific (HWVoice *hw, int freq,
int nchannels, audfmt_e fmt);
HWVoice * pcm_hw_add (int freq, int nchannels, audfmt_e fmt);
int pcm_hw_add_sw (HWVoice *hw, SWVoice *sw);
int pcm_hw_del_sw (HWVoice *hw, SWVoice *sw);
SWVoice * pcm_create_voice_pair (int freq, int nchannels, audfmt_e fmt);
void pcm_hw_free_resources (HWVoice *hw);
int pcm_hw_alloc_resources (HWVoice *hw);
void pcm_hw_fini (HWVoice *hw);
void pcm_hw_gc (HWVoice *hw);
int pcm_hw_get_live (HWVoice *hw);
int pcm_hw_get_live2 (HWVoice *hw, int *nb_active);
void pcm_hw_dec_live (HWVoice *hw, int decr);
int pcm_hw_write (SWVoice *sw, void *buf, int len);
int audio_get_conf_int (const char *key, int defval);
const char *audio_get_conf_str (const char *key, const char *defval);
struct audio_output_driver;
#define VOICE_ENABLE 1
#define VOICE_DISABLE 2
#endif /* audio_int.h */

469
audio/fmodaudio.c Normal file
View File

@@ -0,0 +1,469 @@
/*
* QEMU FMOD audio output driver
*
* Copyright (c) 2004 Vassili Karpov (malc)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <fmod.h>
#include <fmod_errors.h>
#include "vl.h"
#include "audio/audio_int.h"
typedef struct FMODVoice {
HWVoice hw;
unsigned int old_pos;
FSOUND_SAMPLE *fmod_sample;
int channel;
} FMODVoice;
#define dolog(...) AUD_log ("fmod", __VA_ARGS__)
#ifdef DEBUG
#define ldebug(...) dolog (__VA_ARGS__)
#else
#define ldebug(...)
#endif
#define QC_FMOD_DRV "QEMU_FMOD_DRV"
#define QC_FMOD_FREQ "QEMU_FMOD_FREQ"
#define QC_FMOD_SAMPLES "QEMU_FMOD_SAMPLES"
#define QC_FMOD_CHANNELS "QEMU_FMOD_CHANNELS"
#define QC_FMOD_BUFSIZE "QEMU_FMOD_BUFSIZE"
#define QC_FMOD_THRESHOLD "QEMU_FMOD_THRESHOLD"
static struct {
int nb_samples;
int freq;
int nb_channels;
int bufsize;
int threshold;
} conf = {
2048,
44100,
1,
0,
128
};
#define errstr() FMOD_ErrorString (FSOUND_GetError ())
static int fmod_hw_write (SWVoice *sw, void *buf, int len)
{
return pcm_hw_write (sw, buf, len);
}
static void fmod_clear_sample (FMODVoice *fmd)
{
HWVoice *hw = &fmd->hw;
int status;
void *p1 = 0, *p2 = 0;
unsigned int len1 = 0, len2 = 0;
status = FSOUND_Sample_Lock (
fmd->fmod_sample,
0,
hw->samples << hw->shift,
&p1,
&p2,
&len1,
&len2
);
if (!status) {
dolog ("Failed to lock sample\nReason: %s\n", errstr ());
return;
}
if ((len1 & hw->align) || (len2 & hw->align)) {
dolog ("Locking sample returned unaligned length %d, %d\n",
len1, len2);
goto fail;
}
if (len1 + len2 != hw->samples << hw->shift) {
dolog ("Locking sample returned incomplete length %d, %d\n",
len1 + len2, hw->samples << hw->shift);
goto fail;
}
pcm_hw_clear (hw, p1, hw->samples);
fail:
status = FSOUND_Sample_Unlock (fmd->fmod_sample, p1, p2, len1, len2);
if (!status) {
dolog ("Failed to unlock sample\nReason: %s\n", errstr ());
}
}
static int fmod_write_sample (HWVoice *hw, uint8_t *dst, st_sample_t *src,
int src_size, int src_pos, int dst_len)
{
int src_len1 = dst_len, src_len2 = 0, pos = src_pos + dst_len;
st_sample_t *src1 = src + src_pos, *src2 = 0;
if (src_pos + dst_len > src_size) {
src_len1 = src_size - src_pos;
src2 = src;
src_len2 = dst_len - src_len1;
pos = src_len2;
}
if (src_len1) {
hw->clip (dst, src1, src_len1);
memset (src1, 0, src_len1 * sizeof (st_sample_t));
advance (dst, src_len1);
}
if (src_len2) {
hw->clip (dst, src2, src_len2);
memset (src2, 0, src_len2 * sizeof (st_sample_t));
}
return pos;
}
static int fmod_unlock_sample (FMODVoice *fmd, void *p1, void *p2,
unsigned int blen1, unsigned int blen2)
{
int status = FSOUND_Sample_Unlock (fmd->fmod_sample, p1, p2, blen1, blen2);
if (!status) {
dolog ("Failed to unlock sample\nReason: %s\n", errstr ());
return -1;
}
return 0;
}
static int fmod_lock_sample (FMODVoice *fmd, int pos, int len,
void **p1, void **p2,
unsigned int *blen1, unsigned int *blen2)
{
HWVoice *hw = &fmd->hw;
int status;
status = FSOUND_Sample_Lock (
fmd->fmod_sample,
pos << hw->shift,
len << hw->shift,
p1,
p2,
blen1,
blen2
);
if (!status) {
dolog ("Failed to lock sample\nReason: %s\n", errstr ());
return -1;
}
if ((*blen1 & hw->align) || (*blen2 & hw->align)) {
dolog ("Locking sample returned unaligned length %d, %d\n",
*blen1, *blen2);
fmod_unlock_sample (fmd, *p1, *p2, *blen1, *blen2);
return -1;
}
return 0;
}
static void fmod_hw_run (HWVoice *hw)
{
FMODVoice *fmd = (FMODVoice *) hw;
int rpos, live, decr;
void *p1 = 0, *p2 = 0;
unsigned int blen1 = 0, blen2 = 0;
unsigned int len1 = 0, len2 = 0;
int nb_active;
live = pcm_hw_get_live2 (hw, &nb_active);
if (live <= 0) {
return;
}
if (!hw->pending_disable
&& nb_active
&& conf.threshold
&& live <= conf.threshold) {
ldebug ("live=%d nb_active=%d\n", live, nb_active);
return;
}
decr = live;
#if 1
if (fmd->channel >= 0) {
int pos2 = (fmd->old_pos + decr) % hw->samples;
int pos = FSOUND_GetCurrentPosition (fmd->channel);
if (fmd->old_pos < pos && pos2 >= pos) {
decr = pos - fmd->old_pos - (pos2 == pos) - 1;
}
else if (fmd->old_pos > pos && pos2 >= pos && pos2 < fmd->old_pos) {
decr = (hw->samples - fmd->old_pos) + pos - (pos2 == pos) - 1;
}
/* ldebug ("pos=%d pos2=%d old=%d live=%d decr=%d\n", */
/* pos, pos2, fmd->old_pos, live, decr); */
}
#endif
if (decr <= 0) {
return;
}
if (fmod_lock_sample (fmd, fmd->old_pos, decr, &p1, &p2, &blen1, &blen2)) {
return;
}
len1 = blen1 >> hw->shift;
len2 = blen2 >> hw->shift;
ldebug ("%p %p %d %d %d %d\n", p1, p2, len1, len2, blen1, blen2);
decr = len1 + len2;
rpos = hw->rpos;
if (len1) {
rpos = fmod_write_sample (hw, p1, hw->mix_buf, hw->samples, rpos, len1);
}
if (len2) {
rpos = fmod_write_sample (hw, p2, hw->mix_buf, hw->samples, rpos, len2);
}
fmod_unlock_sample (fmd, p1, p2, blen1, blen2);
pcm_hw_dec_live (hw, decr);
hw->rpos = rpos % hw->samples;
fmd->old_pos = (fmd->old_pos + decr) % hw->samples;
}
static int AUD_to_fmodfmt (audfmt_e fmt, int stereo)
{
int mode = FSOUND_LOOP_NORMAL;
switch (fmt) {
case AUD_FMT_S8:
mode |= FSOUND_SIGNED | FSOUND_8BITS;
break;
case AUD_FMT_U8:
mode |= FSOUND_UNSIGNED | FSOUND_8BITS;
break;
case AUD_FMT_S16:
mode |= FSOUND_SIGNED | FSOUND_16BITS;
break;
case AUD_FMT_U16:
mode |= FSOUND_UNSIGNED | FSOUND_16BITS;
break;
default:
dolog ("Internal logic error: Bad audio format %d\nAborting\n", fmt);
exit (EXIT_FAILURE);
}
mode |= stereo ? FSOUND_STEREO : FSOUND_MONO;
return mode;
}
static void fmod_hw_fini (HWVoice *hw)
{
FMODVoice *fmd = (FMODVoice *) hw;
if (fmd->fmod_sample) {
FSOUND_Sample_Free (fmd->fmod_sample);
fmd->fmod_sample = 0;
if (fmd->channel >= 0) {
FSOUND_StopSound (fmd->channel);
}
}
}
static int fmod_hw_init (HWVoice *hw, int freq, int nchannels, audfmt_e fmt)
{
int bits16, mode, channel;
FMODVoice *fmd = (FMODVoice *) hw;
mode = AUD_to_fmodfmt (fmt, nchannels == 2 ? 1 : 0);
fmd->fmod_sample = FSOUND_Sample_Alloc (
FSOUND_FREE, /* index */
conf.nb_samples, /* length */
mode, /* mode */
freq, /* freq */
255, /* volume */
128, /* pan */
255 /* priority */
);
if (!fmd->fmod_sample) {
dolog ("Failed to allocate FMOD sample\nReason: %s\n", errstr ());
return -1;
}
channel = FSOUND_PlaySoundEx (FSOUND_FREE, fmd->fmod_sample, 0, 1);
if (channel < 0) {
dolog ("Failed to start playing sound\nReason: %s\n", errstr ());
FSOUND_Sample_Free (fmd->fmod_sample);
return -1;
}
fmd->channel = channel;
hw->freq = freq;
hw->fmt = fmt;
hw->nchannels = nchannels;
bits16 = fmt == AUD_FMT_U16 || fmt == AUD_FMT_S16;
hw->bufsize = conf.nb_samples << (nchannels == 2) << bits16;
return 0;
}
static int fmod_hw_ctl (HWVoice *hw, int cmd, ...)
{
int status;
FMODVoice *fmd = (FMODVoice *) hw;
switch (cmd) {
case VOICE_ENABLE:
fmod_clear_sample (fmd);
status = FSOUND_SetPaused (fmd->channel, 0);
if (!status) {
dolog ("Failed to resume channel %d\nReason: %s\n",
fmd->channel, errstr ());
}
break;
case VOICE_DISABLE:
status = FSOUND_SetPaused (fmd->channel, 1);
if (!status) {
dolog ("Failed to pause channel %d\nReason: %s\n",
fmd->channel, errstr ());
}
break;
}
return 0;
}
static struct {
const char *name;
int type;
} drvtab[] = {
{"none", FSOUND_OUTPUT_NOSOUND},
#ifdef _WIN32
{"winmm", FSOUND_OUTPUT_WINMM},
{"dsound", FSOUND_OUTPUT_DSOUND},
{"a3d", FSOUND_OUTPUT_A3D},
{"asio", FSOUND_OUTPUT_ASIO},
#endif
#ifdef __linux__
{"oss", FSOUND_OUTPUT_OSS},
{"alsa", FSOUND_OUTPUT_ALSA},
{"esd", FSOUND_OUTPUT_ESD},
#endif
#ifdef __APPLE__
{"mac", FSOUND_OUTPUT_MAC},
#endif
#if 0
{"xbox", FSOUND_OUTPUT_XBOX},
{"ps2", FSOUND_OUTPUT_PS2},
{"gcube", FSOUND_OUTPUT_GC},
#endif
{"nort", FSOUND_OUTPUT_NOSOUND_NONREALTIME}
};
static void *fmod_audio_init (void)
{
int i;
double ver;
int status;
int output_type = -1;
const char *drv = audio_get_conf_str (QC_FMOD_DRV, NULL);
ver = FSOUND_GetVersion ();
if (ver < FMOD_VERSION) {
dolog ("Wrong FMOD version %f, need at least %f\n", ver, FMOD_VERSION);
return NULL;
}
if (drv) {
int found = 0;
for (i = 0; i < sizeof (drvtab) / sizeof (drvtab[0]); i++) {
if (!strcmp (drv, drvtab[i].name)) {
output_type = drvtab[i].type;
found = 1;
break;
}
}
if (!found) {
dolog ("Unknown FMOD output driver `%s'\n", drv);
}
}
if (output_type != -1) {
status = FSOUND_SetOutput (output_type);
if (!status) {
dolog ("FSOUND_SetOutput(%d) failed\nReason: %s\n",
output_type, errstr ());
return NULL;
}
}
conf.freq = audio_get_conf_int (QC_FMOD_FREQ, conf.freq);
conf.nb_samples = audio_get_conf_int (QC_FMOD_SAMPLES, conf.nb_samples);
conf.nb_channels =
audio_get_conf_int (QC_FMOD_CHANNELS,
(audio_state.nb_hw_voices > 1
? audio_state.nb_hw_voices
: conf.nb_channels));
conf.bufsize = audio_get_conf_int (QC_FMOD_BUFSIZE, conf.bufsize);
conf.threshold = audio_get_conf_int (QC_FMOD_THRESHOLD, conf.threshold);
if (conf.bufsize) {
status = FSOUND_SetBufferSize (conf.bufsize);
if (!status) {
dolog ("FSOUND_SetBufferSize (%d) failed\nReason: %s\n",
conf.bufsize, errstr ());
}
}
status = FSOUND_Init (conf.freq, conf.nb_channels, 0);
if (!status) {
dolog ("FSOUND_Init failed\nReason: %s\n", errstr ());
return NULL;
}
return &conf;
}
static void fmod_audio_fini (void *opaque)
{
FSOUND_Close ();
}
struct pcm_ops fmod_pcm_ops = {
fmod_hw_init,
fmod_hw_fini,
fmod_hw_run,
fmod_hw_write,
fmod_hw_ctl
};
struct audio_output_driver fmod_output_driver = {
"fmod",
fmod_audio_init,
fmod_audio_fini,
&fmod_pcm_ops,
1,
INT_MAX,
sizeof (FMODVoice)
};

255
audio/mixeng.c Normal file
View File

@@ -0,0 +1,255 @@
/*
* QEMU Mixing engine
*
* Copyright (c) 2004 Vassili Karpov (malc)
* Copyright (c) 1998 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 "vl.h"
//#define DEBUG_FP
#include "audio/mixeng.h"
#define IN_T int8_t
#define IN_MIN CHAR_MIN
#define IN_MAX CHAR_MAX
#define SIGNED
#include "mixeng_template.h"
#undef SIGNED
#undef IN_MAX
#undef IN_MIN
#undef IN_T
#define IN_T uint8_t
#define IN_MIN 0
#define IN_MAX UCHAR_MAX
#include "mixeng_template.h"
#undef IN_MAX
#undef IN_MIN
#undef IN_T
#define IN_T int16_t
#define IN_MIN SHRT_MIN
#define IN_MAX SHRT_MAX
#define SIGNED
#include "mixeng_template.h"
#undef SIGNED
#undef IN_MAX
#undef IN_MIN
#undef IN_T
#define IN_T uint16_t
#define IN_MIN 0
#define IN_MAX USHRT_MAX
#include "mixeng_template.h"
#undef IN_MAX
#undef IN_MIN
#undef IN_T
t_sample *mixeng_conv[2][2][2] = {
{
{
conv_uint8_t_to_mono,
conv_uint16_t_to_mono
},
{
conv_int8_t_to_mono,
conv_int16_t_to_mono
}
},
{
{
conv_uint8_t_to_stereo,
conv_uint16_t_to_stereo
},
{
conv_int8_t_to_stereo,
conv_int16_t_to_stereo
}
}
};
f_sample *mixeng_clip[2][2][2] = {
{
{
clip_uint8_t_from_mono,
clip_uint16_t_from_mono
},
{
clip_int8_t_from_mono,
clip_int16_t_from_mono
}
},
{
{
clip_uint8_t_from_stereo,
clip_uint16_t_from_stereo
},
{
clip_int8_t_from_stereo,
clip_int16_t_from_stereo
}
}
};
/*
* August 21, 1998
* Copyright 1998 Fabrice Bellard.
*
* [Rewrote completly the code of Lance Norskog And Sundry
* Contributors with a more efficient algorithm.]
*
* This source code is freely redistributable and may be used for
* any purpose. This copyright notice must be maintained.
* Lance Norskog And Sundry Contributors are not responsible for
* the consequences of using this software.
*/
/*
* Sound Tools rate change effect file.
*/
/*
* Linear Interpolation.
*
* The use of fractional increment allows us to use no buffer. It
* avoid the problems at the end of the buffer we had with the old
* method which stored a possibly big buffer of size
* lcm(in_rate,out_rate).
*
* Limited to 16 bit samples and sampling frequency <= 65535 Hz. If
* the input & output frequencies are equal, a delay of one sample is
* introduced. Limited to processing 32-bit count worth of samples.
*
* 1 << FRAC_BITS evaluating to zero in several places. Changed with
* an (unsigned long) cast to make it safe. MarkMLl 2/1/99
*/
/* Private data */
typedef struct ratestuff {
uint64_t opos;
uint64_t opos_inc;
uint32_t ipos; /* position in the input stream (integer) */
st_sample_t ilast; /* last sample in the input stream */
} *rate_t;
/*
* Prepare processing.
*/
void *st_rate_start (int inrate, int outrate)
{
rate_t rate = (rate_t) qemu_mallocz (sizeof (struct ratestuff));
if (!rate) {
exit (EXIT_FAILURE);
}
if (inrate == outrate) {
// exit (EXIT_FAILURE);
}
if (inrate >= 65535 || outrate >= 65535) {
// exit (EXIT_FAILURE);
}
rate->opos = 0;
/* increment */
rate->opos_inc = (inrate * ((int64_t) UINT_MAX)) / outrate;
rate->ipos = 0;
rate->ilast.l = 0;
rate->ilast.r = 0;
return rate;
}
/*
* Processed signed long samples from ibuf to obuf.
* Return number of samples processed.
*/
void st_rate_flow (void *opaque, st_sample_t *ibuf, st_sample_t *obuf,
int *isamp, int *osamp)
{
rate_t rate = (rate_t) opaque;
st_sample_t *istart, *iend;
st_sample_t *ostart, *oend;
st_sample_t ilast, icur, out;
int64_t t;
ilast = rate->ilast;
istart = ibuf;
iend = ibuf + *isamp;
ostart = obuf;
oend = obuf + *osamp;
if (rate->opos_inc == 1ULL << 32) {
int i, n = *isamp > *osamp ? *osamp : *isamp;
for (i = 0; i < n; i++) {
obuf[i].l += ibuf[i].r;
obuf[i].r += ibuf[i].r;
}
*isamp = n;
*osamp = n;
return;
}
while (obuf < oend) {
/* Safety catch to make sure we have input samples. */
if (ibuf >= iend)
break;
/* read as many input samples so that ipos > opos */
while (rate->ipos <= (rate->opos >> 32)) {
ilast = *ibuf++;
rate->ipos++;
/* See if we finished the input buffer yet */
if (ibuf >= iend) goto the_end;
}
icur = *ibuf;
/* interpolate */
t = rate->opos & 0xffffffff;
out.l = (ilast.l * (INT_MAX - t) + icur.l * t) / INT_MAX;
out.r = (ilast.r * (INT_MAX - t) + icur.r * t) / INT_MAX;
/* output sample & increment position */
#if 0
*obuf++ = out;
#else
obuf->l += out.l;
obuf->r += out.r;
obuf += 1;
#endif
rate->opos += rate->opos_inc;
}
the_end:
*isamp = ibuf - istart;
*osamp = obuf - ostart;
rate->ilast = ilast;
}
void st_rate_stop (void *opaque)
{
qemu_free (opaque);
}

39
audio/mixeng.h Normal file
View File

@@ -0,0 +1,39 @@
/*
* QEMU Mixing engine header
*
* Copyright (c) 2004 Vassili Karpov (malc)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef QEMU_MIXENG_H
#define QEMU_MIXENG_H
typedef void (t_sample) (void *dst, const void *src, int samples);
typedef void (f_sample) (void *dst, const void *src, int samples);
typedef struct { int64_t l; int64_t r; } st_sample_t;
extern t_sample *mixeng_conv[2][2][2];
extern f_sample *mixeng_clip[2][2][2];
void *st_rate_start (int inrate, int outrate);
void st_rate_flow (void *opaque, st_sample_t *ibuf, st_sample_t *obuf,
int *isamp, int *osamp);
void st_rate_stop (void *opaque);
#endif /* mixeng.h */

111
audio/mixeng_template.h Normal file
View File

@@ -0,0 +1,111 @@
/*
* QEMU Mixing engine
*
* Copyright (c) 2004 Vassili Karpov (malc)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
/*
* Tusen tack till Mike Nordell
* dec++'ified by Dscho
*/
#ifdef SIGNED
#define HALFT IN_MAX
#define HALF IN_MAX
#else
#define HALFT ((IN_MAX)>>1)
#define HALF HALFT
#endif
static int64_t inline glue(conv_,IN_T) (IN_T v)
{
#ifdef SIGNED
return (INT_MAX*(int64_t)v)/HALF;
#else
return (INT_MAX*((int64_t)v-HALFT))/HALF;
#endif
}
static IN_T inline glue(clip_,IN_T) (int64_t v)
{
if (v >= INT_MAX)
return IN_MAX;
else if (v < -INT_MAX)
return IN_MIN;
#ifdef SIGNED
return (IN_T) (v*HALF/INT_MAX);
#else
return (IN_T) (v+INT_MAX/2)*HALF/INT_MAX;
#endif
}
static void glue(glue(conv_,IN_T),_to_stereo) (void *dst, const void *src,
int samples)
{
st_sample_t *out = (st_sample_t *) dst;
IN_T *in = (IN_T *) src;
while (samples--) {
out->l = glue(conv_,IN_T) (*in++);
out->r = glue(conv_,IN_T) (*in++);
out += 1;
}
}
static void glue(glue(conv_,IN_T),_to_mono) (void *dst, const void *src,
int samples)
{
st_sample_t *out = (st_sample_t *) dst;
IN_T *in = (IN_T *) src;
while (samples--) {
out->l = glue(conv_,IN_T) (in[0]);
out->r = out->l;
out += 1;
in += 1;
}
}
static void glue(glue(clip_,IN_T),_from_stereo) (void *dst, const void *src,
int samples)
{
st_sample_t *in = (st_sample_t *) src;
IN_T *out = (IN_T *) dst;
while (samples--) {
*out++ = glue(clip_,IN_T) (in->l);
*out++ = glue(clip_,IN_T) (in->r);
in += 1;
}
}
static void glue(glue(clip_,IN_T),_from_mono) (void *dst, const void *src,
int samples)
{
st_sample_t *in = (st_sample_t *) src;
IN_T *out = (IN_T *) dst;
while (samples--) {
*out++ = glue(clip_,IN_T) (in->l + in->r);
in += 1;
}
}
#undef HALF
#undef HALFT

130
audio/noaudio.c Normal file
View File

@@ -0,0 +1,130 @@
/*
* QEMU NULL audio output driver
*
* Copyright (c) 2004 Vassili Karpov (malc)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "vl.h"
#include "audio/audio_int.h"
typedef struct NoVoice {
HWVoice hw;
int64_t old_ticks;
} NoVoice;
#define dolog(...) AUD_log ("noaudio", __VA_ARGS__)
#ifdef DEBUG
#define ldebug(...) dolog (__VA_ARGS__)
#else
#define ldebug(...)
#endif
static void no_hw_run (HWVoice *hw)
{
NoVoice *no = (NoVoice *) hw;
int rpos, live, decr, samples;
uint8_t *dst;
st_sample_t *src;
int64_t now = qemu_get_clock (vm_clock);
int64_t ticks = now - no->old_ticks;
int64_t bytes = (ticks * hw->bytes_per_second) / ticks_per_sec;
if (bytes > INT_MAX)
samples = INT_MAX >> hw->shift;
else
samples = bytes >> hw->shift;
live = pcm_hw_get_live (hw);
if (live <= 0)
return;
no->old_ticks = now;
decr = audio_MIN (live, samples);
samples = decr;
rpos = hw->rpos;
while (samples) {
int left_till_end_samples = hw->samples - rpos;
int convert_samples = audio_MIN (samples, left_till_end_samples);
src = advance (hw->mix_buf, rpos * sizeof (st_sample_t));
memset (src, 0, convert_samples * sizeof (st_sample_t));
rpos = (rpos + convert_samples) % hw->samples;
samples -= convert_samples;
}
pcm_hw_dec_live (hw, decr);
hw->rpos = rpos;
}
static int no_hw_write (SWVoice *sw, void *buf, int len)
{
return pcm_hw_write (sw, buf, len);
}
static int no_hw_init (HWVoice *hw, int freq, int nchannels, audfmt_e fmt)
{
NoVoice *no = (NoVoice *) hw;
hw->freq = freq;
hw->nchannels = nchannels;
hw->fmt = fmt;
hw->bufsize = 4096;
return 0;
}
static void no_hw_fini (HWVoice *hw)
{
(void) hw;
}
static int no_hw_ctl (HWVoice *hw, int cmd, ...)
{
(void) hw;
(void) cmd;
return 0;
}
static void *no_audio_init (void)
{
return &no_audio_init;
}
static void no_audio_fini (void *opaque)
{
}
struct pcm_ops no_pcm_ops = {
no_hw_init,
no_hw_fini,
no_hw_run,
no_hw_write,
no_hw_ctl
};
struct audio_output_driver no_output_driver = {
"none",
no_audio_init,
no_audio_fini,
&no_pcm_ops,
1,
1,
sizeof (NoVoice)
};

475
audio/ossaudio.c Normal file
View File

@@ -0,0 +1,475 @@
/*
* QEMU OSS audio output driver
*
* Copyright (c) 2003-2004 Vassili Karpov (malc)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/soundcard.h>
#include <assert.h>
#include "vl.h"
#include "audio/audio_int.h"
typedef struct OSSVoice {
HWVoice hw;
void *pcm_buf;
int fd;
int nfrags;
int fragsize;
int mmapped;
int old_optr;
} OSSVoice;
#define dolog(...) AUD_log ("oss", __VA_ARGS__)
#ifdef DEBUG
#define ldebug(...) dolog (__VA_ARGS__)
#else
#define ldebug(...)
#endif
#define QC_OSS_FRAGSIZE "QEMU_OSS_FRAGSIZE"
#define QC_OSS_NFRAGS "QEMU_OSS_NFRAGS"
#define QC_OSS_MMAP "QEMU_OSS_MMAP"
#define QC_OSS_DEV "QEMU_OSS_DEV"
#define errstr() strerror (errno)
static struct {
int try_mmap;
int nfrags;
int fragsize;
const char *dspname;
} conf = {
.try_mmap = 0,
.nfrags = 4,
.fragsize = 4096,
.dspname = "/dev/dsp"
};
struct oss_params {
int freq;
audfmt_e fmt;
int nchannels;
int nfrags;
int fragsize;
};
static int oss_hw_write (SWVoice *sw, void *buf, int len)
{
return pcm_hw_write (sw, buf, len);
}
static int AUD_to_ossfmt (audfmt_e fmt)
{
switch (fmt) {
case AUD_FMT_S8: return AFMT_S8;
case AUD_FMT_U8: return AFMT_U8;
case AUD_FMT_S16: return AFMT_S16_LE;
case AUD_FMT_U16: return AFMT_U16_LE;
default:
dolog ("Internal logic error: Bad audio format %d\nAborting\n", fmt);
exit (EXIT_FAILURE);
}
}
static int oss_to_audfmt (int fmt)
{
switch (fmt) {
case AFMT_S8: return AUD_FMT_S8;
case AFMT_U8: return AUD_FMT_U8;
case AFMT_S16_LE: return AUD_FMT_S16;
case AFMT_U16_LE: return AUD_FMT_U16;
default:
dolog ("Internal logic error: Unrecognized OSS audio format %d\n"
"Aborting\n",
fmt);
exit (EXIT_FAILURE);
}
}
#ifdef DEBUG_PCM
static void oss_dump_pcm_info (struct oss_params *req, struct oss_params *obt)
{
dolog ("parameter | requested value | obtained value\n");
dolog ("format | %10d | %10d\n", req->fmt, obt->fmt);
dolog ("channels | %10d | %10d\n", req->nchannels, obt->nchannels);
dolog ("frequency | %10d | %10d\n", req->freq, obt->freq);
dolog ("nfrags | %10d | %10d\n", req->nfrags, obt->nfrags);
dolog ("fragsize | %10d | %10d\n", req->fragsize, obt->fragsize);
}
#endif
static int oss_open (struct oss_params *req, struct oss_params *obt, int *pfd)
{
int fd;
int mmmmssss;
audio_buf_info abinfo;
int fmt, freq, nchannels;
const char *dspname = conf.dspname;
fd = open (dspname, O_RDWR | O_NONBLOCK);
if (-1 == fd) {
dolog ("Could not initialize audio hardware. Failed to open `%s':\n"
"Reason:%s\n",
dspname,
errstr ());
return -1;
}
freq = req->freq;
nchannels = req->nchannels;
fmt = req->fmt;
if (ioctl (fd, SNDCTL_DSP_SAMPLESIZE, &fmt)) {
dolog ("Could not initialize audio hardware\n"
"Failed to set sample size\n"
"Reason: %s\n",
errstr ());
goto err;
}
if (ioctl (fd, SNDCTL_DSP_CHANNELS, &nchannels)) {
dolog ("Could not initialize audio hardware\n"
"Failed to set number of channels\n"
"Reason: %s\n",
errstr ());
goto err;
}
if (ioctl (fd, SNDCTL_DSP_SPEED, &freq)) {
dolog ("Could not initialize audio hardware\n"
"Failed to set frequency\n"
"Reason: %s\n",
errstr ());
goto err;
}
if (ioctl (fd, SNDCTL_DSP_NONBLOCK)) {
dolog ("Could not initialize audio hardware\n"
"Failed to set non-blocking mode\n"
"Reason: %s\n",
errstr ());
goto err;
}
mmmmssss = (req->nfrags << 16) | lsbindex (req->fragsize);
if (ioctl (fd, SNDCTL_DSP_SETFRAGMENT, &mmmmssss)) {
dolog ("Could not initialize audio hardware\n"
"Failed to set buffer length (%d, %d)\n"
"Reason:%s\n",
conf.nfrags, conf.fragsize,
errstr ());
goto err;
}
if (ioctl (fd, SNDCTL_DSP_GETOSPACE, &abinfo)) {
dolog ("Could not initialize audio hardware\n"
"Failed to get buffer length\n"
"Reason:%s\n",
errstr ());
goto err;
}
obt->fmt = fmt;
obt->nchannels = nchannels;
obt->freq = freq;
obt->nfrags = abinfo.fragstotal;
obt->fragsize = abinfo.fragsize;
*pfd = fd;
if ((req->fmt != obt->fmt) ||
(req->nchannels != obt->nchannels) ||
(req->freq != obt->freq) ||
(req->fragsize != obt->fragsize) ||
(req->nfrags != obt->nfrags)) {
#ifdef DEBUG_PCM
dolog ("Audio parameters mismatch\n");
oss_dump_pcm_info (req, obt);
#endif
}
#ifdef DEBUG_PCM
oss_dump_pcm_info (req, obt);
#endif
return 0;
err:
close (fd);
return -1;
}
static void oss_hw_run (HWVoice *hw)
{
OSSVoice *oss = (OSSVoice *) hw;
int err, rpos, live, decr;
int samples;
uint8_t *dst;
st_sample_t *src;
struct audio_buf_info abinfo;
struct count_info cntinfo;
live = pcm_hw_get_live (hw);
if (live <= 0)
return;
if (oss->mmapped) {
int bytes;
err = ioctl (oss->fd, SNDCTL_DSP_GETOPTR, &cntinfo);
if (err < 0) {
dolog ("SNDCTL_DSP_GETOPTR failed\nReason: %s\n", errstr ());
return;
}
if (cntinfo.ptr == oss->old_optr) {
if (abs (hw->samples - live) < 64)
dolog ("overrun\n");
return;
}
if (cntinfo.ptr > oss->old_optr) {
bytes = cntinfo.ptr - oss->old_optr;
}
else {
bytes = hw->bufsize + cntinfo.ptr - oss->old_optr;
}
decr = audio_MIN (bytes >> hw->shift, live);
}
else {
err = ioctl (oss->fd, SNDCTL_DSP_GETOSPACE, &abinfo);
if (err < 0) {
dolog ("SNDCTL_DSP_GETOSPACE failed\nReason: %s\n", errstr ());
return;
}
decr = audio_MIN (abinfo.bytes >> hw->shift, live);
if (decr <= 0)
return;
}
samples = decr;
rpos = hw->rpos;
while (samples) {
int left_till_end_samples = hw->samples - rpos;
int convert_samples = audio_MIN (samples, left_till_end_samples);
src = advance (hw->mix_buf, rpos * sizeof (st_sample_t));
dst = advance (oss->pcm_buf, rpos << hw->shift);
hw->clip (dst, src, convert_samples);
if (!oss->mmapped) {
int written;
written = write (oss->fd, dst, convert_samples << hw->shift);
/* XXX: follow errno recommendations ? */
if (written == -1) {
dolog ("Failed to write audio\nReason: %s\n", errstr ());
continue;
}
if (written != convert_samples << hw->shift) {
int wsamples = written >> hw->shift;
int wbytes = wsamples << hw->shift;
if (wbytes != written) {
dolog ("Unaligned write %d, %d\n", wbytes, written);
}
memset (src, 0, wbytes);
decr -= samples;
rpos = (rpos + wsamples) % hw->samples;
break;
}
}
memset (src, 0, convert_samples * sizeof (st_sample_t));
rpos = (rpos + convert_samples) % hw->samples;
samples -= convert_samples;
}
if (oss->mmapped) {
oss->old_optr = cntinfo.ptr;
}
pcm_hw_dec_live (hw, decr);
hw->rpos = rpos;
}
static void oss_hw_fini (HWVoice *hw)
{
int err;
OSSVoice *oss = (OSSVoice *) hw;
ldebug ("oss_hw_fini\n");
err = close (oss->fd);
if (err) {
dolog ("Failed to close OSS descriptor\nReason: %s\n", errstr ());
}
oss->fd = -1;
if (oss->pcm_buf) {
if (oss->mmapped) {
err = munmap (oss->pcm_buf, hw->bufsize);
if (err) {
dolog ("Failed to unmap OSS buffer\nReason: %s\n",
errstr ());
}
}
else {
qemu_free (oss->pcm_buf);
}
oss->pcm_buf = NULL;
}
}
static int oss_hw_init (HWVoice *hw, int freq, int nchannels, audfmt_e fmt)
{
OSSVoice *oss = (OSSVoice *) hw;
struct oss_params req, obt;
assert (!oss->fd);
req.fmt = AUD_to_ossfmt (fmt);
req.freq = freq;
req.nchannels = nchannels;
req.fragsize = conf.fragsize;
req.nfrags = conf.nfrags;
if (oss_open (&req, &obt, &oss->fd))
return -1;
hw->freq = obt.freq;
hw->fmt = oss_to_audfmt (obt.fmt);
hw->nchannels = obt.nchannels;
oss->nfrags = obt.nfrags;
oss->fragsize = obt.fragsize;
hw->bufsize = obt.nfrags * obt.fragsize;
oss->mmapped = 0;
if (conf.try_mmap) {
oss->pcm_buf = mmap (0, hw->bufsize, PROT_READ | PROT_WRITE,
MAP_SHARED, oss->fd, 0);
if (oss->pcm_buf == MAP_FAILED) {
dolog ("Failed to mmap OSS device\nReason: %s\n",
errstr ());
} else {
int err;
int trig = 0;
if (ioctl (oss->fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
dolog ("SNDCTL_DSP_SETTRIGGER 0 failed\nReason: %s\n",
errstr ());
}
else {
trig = PCM_ENABLE_OUTPUT;
if (ioctl (oss->fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
dolog ("SNDCTL_DSP_SETTRIGGER PCM_ENABLE_OUTPUT failed\n"
"Reason: %s\n", errstr ());
}
else {
oss->mmapped = 1;
}
}
if (!oss->mmapped) {
err = munmap (oss->pcm_buf, hw->bufsize);
if (err) {
dolog ("Failed to unmap OSS device\nReason: %s\n",
errstr ());
}
}
}
}
if (!oss->mmapped) {
oss->pcm_buf = qemu_mallocz (hw->bufsize);
if (!oss->pcm_buf) {
close (oss->fd);
oss->fd = -1;
return -1;
}
}
return 0;
}
static int oss_hw_ctl (HWVoice *hw, int cmd, ...)
{
int trig;
OSSVoice *oss = (OSSVoice *) hw;
if (!oss->mmapped)
return 0;
switch (cmd) {
case VOICE_ENABLE:
ldebug ("enabling voice\n");
pcm_hw_clear (hw, oss->pcm_buf, hw->samples);
trig = PCM_ENABLE_OUTPUT;
if (ioctl (oss->fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
dolog ("SNDCTL_DSP_SETTRIGGER PCM_ENABLE_OUTPUT failed\n"
"Reason: %s\n", errstr ());
return -1;
}
break;
case VOICE_DISABLE:
ldebug ("disabling voice\n");
trig = 0;
if (ioctl (oss->fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
dolog ("SNDCTL_DSP_SETTRIGGER 0 failed\nReason: %s\n",
errstr ());
return -1;
}
break;
}
return 0;
}
static void *oss_audio_init (void)
{
conf.fragsize = audio_get_conf_int (QC_OSS_FRAGSIZE, conf.fragsize);
conf.nfrags = audio_get_conf_int (QC_OSS_NFRAGS, conf.nfrags);
conf.try_mmap = audio_get_conf_int (QC_OSS_MMAP, conf.try_mmap);
conf.dspname = audio_get_conf_str (QC_OSS_DEV, conf.dspname);
return &conf;
}
static void oss_audio_fini (void *opaque)
{
}
struct pcm_ops oss_pcm_ops = {
oss_hw_init,
oss_hw_fini,
oss_hw_run,
oss_hw_write,
oss_hw_ctl
};
struct audio_output_driver oss_output_driver = {
"oss",
oss_audio_init,
oss_audio_fini,
&oss_pcm_ops,
1,
INT_MAX,
sizeof (OSSVoice)
};

332
audio/sdlaudio.c Normal file
View File

@@ -0,0 +1,332 @@
/*
* QEMU SDL audio output driver
*
* Copyright (c) 2004 Vassili Karpov (malc)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <SDL.h>
#include <SDL_thread.h>
#include "vl.h"
#include "audio/audio_int.h"
typedef struct SDLVoice {
HWVoice hw;
} SDLVoice;
#define dolog(...) AUD_log ("sdl", __VA_ARGS__)
#ifdef DEBUG
#define ldebug(...) dolog (__VA_ARGS__)
#else
#define ldebug(...)
#endif
#define QC_SDL_SAMPLES "QEMU_SDL_SAMPLES"
#define errstr() SDL_GetError ()
static struct {
int nb_samples;
} conf = {
1024
};
struct SDLAudioState {
int exit;
SDL_mutex *mutex;
SDL_sem *sem;
int initialized;
} glob_sdl;
typedef struct SDLAudioState SDLAudioState;
static void sdl_hw_run (HWVoice *hw)
{
(void) hw;
}
static int sdl_lock (SDLAudioState *s)
{
if (SDL_LockMutex (s->mutex)) {
dolog ("SDL_LockMutex failed\nReason: %s\n", errstr ());
return -1;
}
return 0;
}
static int sdl_unlock (SDLAudioState *s)
{
if (SDL_UnlockMutex (s->mutex)) {
dolog ("SDL_UnlockMutex failed\nReason: %s\n", errstr ());
return -1;
}
return 0;
}
static int sdl_post (SDLAudioState *s)
{
if (SDL_SemPost (s->sem)) {
dolog ("SDL_SemPost failed\nReason: %s\n", errstr ());
return -1;
}
return 0;
}
static int sdl_wait (SDLAudioState *s)
{
if (SDL_SemWait (s->sem)) {
dolog ("SDL_SemWait failed\nReason: %s\n", errstr ());
return -1;
}
return 0;
}
static int sdl_unlock_and_post (SDLAudioState *s)
{
if (sdl_unlock (s))
return -1;
return sdl_post (s);
}
static int sdl_hw_write (SWVoice *sw, void *buf, int len)
{
int ret;
SDLAudioState *s = &glob_sdl;
sdl_lock (s);
ret = pcm_hw_write (sw, buf, len);
sdl_unlock_and_post (s);
return ret;
}
static int AUD_to_sdlfmt (audfmt_e fmt, int *shift)
{
*shift = 0;
switch (fmt) {
case AUD_FMT_S8: return AUDIO_S8;
case AUD_FMT_U8: return AUDIO_U8;
case AUD_FMT_S16: *shift = 1; return AUDIO_S16LSB;
case AUD_FMT_U16: *shift = 1; return AUDIO_U16LSB;
default:
dolog ("Internal logic error: Bad audio format %d\nAborting\n", fmt);
exit (EXIT_FAILURE);
}
}
static int sdl_to_audfmt (int fmt)
{
switch (fmt) {
case AUDIO_S8: return AUD_FMT_S8;
case AUDIO_U8: return AUD_FMT_U8;
case AUDIO_S16LSB: return AUD_FMT_S16;
case AUDIO_U16LSB: return AUD_FMT_U16;
default:
dolog ("Internal logic error: Unrecognized SDL audio format %d\n"
"Aborting\n", fmt);
exit (EXIT_FAILURE);
}
}
static int sdl_open (SDL_AudioSpec *req, SDL_AudioSpec *obt)
{
int status;
status = SDL_OpenAudio (req, obt);
if (status) {
dolog ("SDL_OpenAudio failed\nReason: %s\n", errstr ());
}
return status;
}
static void sdl_close (SDLAudioState *s)
{
if (s->initialized) {
sdl_lock (s);
s->exit = 1;
sdl_unlock_and_post (s);
SDL_PauseAudio (1);
SDL_CloseAudio ();
s->initialized = 0;
}
}
static void sdl_callback (void *opaque, Uint8 *buf, int len)
{
SDLVoice *sdl = opaque;
SDLAudioState *s = &glob_sdl;
HWVoice *hw = &sdl->hw;
int samples = len >> hw->shift;
if (s->exit) {
return;
}
while (samples) {
int to_mix, live, decr;
/* dolog ("in callback samples=%d\n", samples); */
sdl_wait (s);
if (s->exit) {
return;
}
sdl_lock (s);
live = pcm_hw_get_live (hw);
if (live <= 0)
goto again;
/* dolog ("in callback live=%d\n", live); */
to_mix = audio_MIN (samples, live);
decr = to_mix;
while (to_mix) {
int chunk = audio_MIN (to_mix, hw->samples - hw->rpos);
st_sample_t *src = hw->mix_buf + hw->rpos;
/* dolog ("in callback to_mix %d, chunk %d\n", to_mix, chunk); */
hw->clip (buf, src, chunk);
memset (src, 0, chunk * sizeof (st_sample_t));
hw->rpos = (hw->rpos + chunk) % hw->samples;
to_mix -= chunk;
buf += chunk << hw->shift;
}
samples -= decr;
pcm_hw_dec_live (hw, decr);
again:
sdl_unlock (s);
}
/* dolog ("done len=%d\n", len); */
}
static void sdl_hw_fini (HWVoice *hw)
{
ldebug ("sdl_hw_fini %d fixed=%d\n",
glob_sdl.initialized, audio_conf.fixed_format);
sdl_close (&glob_sdl);
}
static int sdl_hw_init (HWVoice *hw, int freq, int nchannels, audfmt_e fmt)
{
SDLVoice *sdl = (SDLVoice *) hw;
SDLAudioState *s = &glob_sdl;
SDL_AudioSpec req, obt;
int shift;
ldebug ("sdl_hw_init %d freq=%d fixed=%d\n",
s->initialized, freq, audio_conf.fixed_format);
if (nchannels != 2) {
dolog ("Bogus channel count %d\n", nchannels);
return -1;
}
req.freq = freq;
req.format = AUD_to_sdlfmt (fmt, &shift);
req.channels = nchannels;
req.samples = conf.nb_samples;
shift <<= nchannels == 2;
req.callback = sdl_callback;
req.userdata = sdl;
if (sdl_open (&req, &obt))
return -1;
hw->freq = obt.freq;
hw->fmt = sdl_to_audfmt (obt.format);
hw->nchannels = obt.channels;
hw->bufsize = obt.samples << shift;
s->initialized = 1;
s->exit = 0;
SDL_PauseAudio (0);
return 0;
}
static int sdl_hw_ctl (HWVoice *hw, int cmd, ...)
{
(void) hw;
switch (cmd) {
case VOICE_ENABLE:
SDL_PauseAudio (0);
break;
case VOICE_DISABLE:
SDL_PauseAudio (1);
break;
}
return 0;
}
static void *sdl_audio_init (void)
{
SDLAudioState *s = &glob_sdl;
conf.nb_samples = audio_get_conf_int (QC_SDL_SAMPLES, conf.nb_samples);
if (SDL_InitSubSystem (SDL_INIT_AUDIO)) {
dolog ("SDL failed to initialize audio subsystem\nReason: %s\n",
errstr ());
return NULL;
}
s->mutex = SDL_CreateMutex ();
if (!s->mutex) {
dolog ("Failed to create SDL mutex\nReason: %s\n", errstr ());
SDL_QuitSubSystem (SDL_INIT_AUDIO);
return NULL;
}
s->sem = SDL_CreateSemaphore (0);
if (!s->sem) {
dolog ("Failed to create SDL semaphore\nReason: %s\n", errstr ());
SDL_DestroyMutex (s->mutex);
SDL_QuitSubSystem (SDL_INIT_AUDIO);
return NULL;
}
return s;
}
static void sdl_audio_fini (void *opaque)
{
SDLAudioState *s = opaque;
sdl_close (s);
SDL_DestroySemaphore (s->sem);
SDL_DestroyMutex (s->mutex);
SDL_QuitSubSystem (SDL_INIT_AUDIO);
}
struct pcm_ops sdl_pcm_ops = {
sdl_hw_init,
sdl_hw_fini,
sdl_hw_run,
sdl_hw_write,
sdl_hw_ctl
};
struct audio_output_driver sdl_output_driver = {
"sdl",
sdl_audio_init,
sdl_audio_fini,
&sdl_pcm_ops,
1,
1,
sizeof (SDLVoice)
};

217
audio/wavaudio.c Normal file
View File

@@ -0,0 +1,217 @@
/*
* QEMU WAV audio output driver
*
* Copyright (c) 2004 Vassili Karpov (malc)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "vl.h"
#include "audio/audio_int.h"
typedef struct WAVVoice {
HWVoice hw;
QEMUFile *f;
int64_t old_ticks;
void *pcm_buf;
int total_samples;
} WAVVoice;
#define dolog(...) AUD_log ("wav", __VA_ARGS__)
#ifdef DEBUG
#define ldebug(...) dolog (__VA_ARGS__)
#else
#define ldebug(...)
#endif
static struct {
const char *wav_path;
} conf = {
.wav_path = "qemu.wav"
};
static void wav_hw_run (HWVoice *hw)
{
WAVVoice *wav = (WAVVoice *) hw;
int rpos, live, decr, samples;
uint8_t *dst;
st_sample_t *src;
int64_t now = qemu_get_clock (vm_clock);
int64_t ticks = now - wav->old_ticks;
int64_t bytes = (ticks * hw->bytes_per_second) / ticks_per_sec;
if (bytes > INT_MAX)
samples = INT_MAX >> hw->shift;
else
samples = bytes >> hw->shift;
live = pcm_hw_get_live (hw);
if (live <= 0)
return;
wav->old_ticks = now;
decr = audio_MIN (live, samples);
samples = decr;
rpos = hw->rpos;
while (samples) {
int left_till_end_samples = hw->samples - rpos;
int convert_samples = audio_MIN (samples, left_till_end_samples);
src = advance (hw->mix_buf, rpos * sizeof (st_sample_t));
dst = advance (wav->pcm_buf, rpos << hw->shift);
hw->clip (dst, src, convert_samples);
qemu_put_buffer (wav->f, dst, convert_samples << hw->shift);
memset (src, 0, convert_samples * sizeof (st_sample_t));
rpos = (rpos + convert_samples) % hw->samples;
samples -= convert_samples;
wav->total_samples += convert_samples;
}
pcm_hw_dec_live (hw, decr);
hw->rpos = rpos;
}
static int wav_hw_write (SWVoice *sw, void *buf, int len)
{
return pcm_hw_write (sw, buf, len);
}
/* VICE code: Store number as little endian. */
static void le_store (uint8_t *buf, uint32_t val, int len)
{
int i;
for (i = 0; i < len; i++) {
buf[i] = (uint8_t) (val & 0xff);
val >>= 8;
}
}
static int wav_hw_init (HWVoice *hw, int freq, int nchannels, audfmt_e fmt)
{
WAVVoice *wav = (WAVVoice *) hw;
int bits16 = 0, stereo = audio_state.fixed_channels == 2;
uint8_t hdr[] = {
0x52, 0x49, 0x46, 0x46, 0x00, 0x00, 0x00, 0x00, 0x57, 0x41, 0x56,
0x45, 0x66, 0x6d, 0x74, 0x20, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00,
0x02, 0x00, 0x44, 0xac, 0x00, 0x00, 0x10, 0xb1, 0x02, 0x00, 0x04,
0x00, 0x10, 0x00, 0x64, 0x61, 0x74, 0x61, 0x00, 0x00, 0x00, 0x00
};
switch (audio_state.fixed_fmt) {
case AUD_FMT_S8:
case AUD_FMT_U8:
break;
case AUD_FMT_S16:
case AUD_FMT_U16:
bits16 = 1;
break;
}
hdr[34] = bits16 ? 0x10 : 0x08;
hw->freq = 44100;
hw->nchannels = stereo ? 2 : 1;
hw->fmt = bits16 ? AUD_FMT_S16 : AUD_FMT_U8;
hw->bufsize = 4096;
wav->pcm_buf = qemu_mallocz (hw->bufsize);
if (!wav->pcm_buf)
return -1;
le_store (hdr + 22, hw->nchannels, 2);
le_store (hdr + 24, hw->freq, 4);
le_store (hdr + 28, hw->freq << (bits16 + stereo), 4);
le_store (hdr + 32, 1 << (bits16 + stereo), 2);
wav->f = fopen (conf.wav_path, "wb");
if (!wav->f) {
dolog ("failed to open wave file `%s'\nReason: %s\n",
conf.wav_path, strerror (errno));
qemu_free (wav->pcm_buf);
wav->pcm_buf = NULL;
return -1;
}
qemu_put_buffer (wav->f, hdr, sizeof (hdr));
return 0;
}
static void wav_hw_fini (HWVoice *hw)
{
WAVVoice *wav = (WAVVoice *) hw;
int stereo = hw->nchannels == 2;
uint8_t rlen[4];
uint8_t dlen[4];
uint32_t rifflen = (wav->total_samples << stereo) + 36;
uint32_t datalen = wav->total_samples << stereo;
if (!wav->f || !hw->active)
return;
le_store (rlen, rifflen, 4);
le_store (dlen, datalen, 4);
qemu_fseek (wav->f, 4, SEEK_SET);
qemu_put_buffer (wav->f, rlen, 4);
qemu_fseek (wav->f, 32, SEEK_CUR);
qemu_put_buffer (wav->f, dlen, 4);
fclose (wav->f);
wav->f = NULL;
qemu_free (wav->pcm_buf);
wav->pcm_buf = NULL;
}
static int wav_hw_ctl (HWVoice *hw, int cmd, ...)
{
(void) hw;
(void) cmd;
return 0;
}
static void *wav_audio_init (void)
{
return &conf;
}
static void wav_audio_fini (void *opaque)
{
ldebug ("wav_fini");
}
struct pcm_ops wav_pcm_ops = {
wav_hw_init,
wav_hw_fini,
wav_hw_run,
wav_hw_write,
wav_hw_ctl
};
struct audio_output_driver wav_output_driver = {
"wav",
wav_audio_init,
wav_audio_fini,
&wav_pcm_ops,
1,
1,
sizeof (WAVVoice)
};

167
block-cloop.c Normal file
View File

@@ -0,0 +1,167 @@
/*
* QEMU System Emulator block driver
*
* Copyright (c) 2004 Johannes E. Schindelin
*
* 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 "vl.h"
#include "block_int.h"
#include <zlib.h>
typedef struct BDRVCloopState {
int fd;
uint32_t block_size;
uint32_t n_blocks;
uint64_t* offsets;
uint32_t sectors_per_block;
uint32_t current_block;
char* compressed_block;
char* uncompressed_block;
z_stream zstream;
} BDRVCloopState;
static int cloop_probe(const uint8_t *buf, int buf_size, const char *filename)
{
const char* magic_version_2_0="#!/bin/sh\n"
"#V2.0 Format\n"
"modprobe cloop file=$0 && mount -r -t iso9660 /dev/cloop $1\n";
int length=strlen(magic_version_2_0);
if(length>buf_size)
length=buf_size;
if(!memcmp(magic_version_2_0,buf,length))
return 2;
return 0;
}
static int cloop_open(BlockDriverState *bs, const char *filename)
{
BDRVCloopState *s = bs->opaque;
uint32_t offsets_size,max_compressed_block_size=1,i;
s->fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE);
if (s->fd < 0)
return -1;
bs->read_only = 1;
/* read header */
if(lseek(s->fd,128,SEEK_SET)<0) {
cloop_close:
close(s->fd);
return -1;
}
if(read(s->fd,&s->block_size,4)<4)
goto cloop_close;
s->block_size=be32_to_cpu(s->block_size);
if(read(s->fd,&s->n_blocks,4)<4)
goto cloop_close;
s->n_blocks=be32_to_cpu(s->n_blocks);
/* read offsets */
offsets_size=s->n_blocks*sizeof(uint64_t);
if(!(s->offsets=(uint64_t*)malloc(offsets_size)))
goto cloop_close;
if(read(s->fd,s->offsets,offsets_size)<offsets_size)
goto cloop_close;
for(i=0;i<s->n_blocks;i++) {
s->offsets[i]=be64_to_cpu(s->offsets[i]);
if(i>0) {
uint32_t size=s->offsets[i]-s->offsets[i-1];
if(size>max_compressed_block_size)
max_compressed_block_size=size;
}
}
/* initialize zlib engine */
if(!(s->compressed_block=(char*)malloc(max_compressed_block_size+1)))
goto cloop_close;
if(!(s->uncompressed_block=(char*)malloc(s->block_size)))
goto cloop_close;
if(inflateInit(&s->zstream) != Z_OK)
goto cloop_close;
s->current_block=s->n_blocks;
s->sectors_per_block = s->block_size/512;
bs->total_sectors = s->n_blocks*s->sectors_per_block;
return 0;
}
static inline int cloop_read_block(BDRVCloopState *s,int block_num)
{
if(s->current_block != block_num) {
int ret;
uint32_t bytes = s->offsets[block_num+1]-s->offsets[block_num];
lseek(s->fd, s->offsets[block_num], SEEK_SET);
ret = read(s->fd, s->compressed_block, bytes);
if (ret != bytes)
return -1;
s->zstream.next_in = s->compressed_block;
s->zstream.avail_in = bytes;
s->zstream.next_out = s->uncompressed_block;
s->zstream.avail_out = s->block_size;
ret = inflateReset(&s->zstream);
if(ret != Z_OK)
return -1;
ret = inflate(&s->zstream, Z_FINISH);
if(ret != Z_STREAM_END || s->zstream.total_out != s->block_size)
return -1;
s->current_block = block_num;
}
return 0;
}
static int cloop_read(BlockDriverState *bs, int64_t sector_num,
uint8_t *buf, int nb_sectors)
{
BDRVCloopState *s = bs->opaque;
int i;
for(i=0;i<nb_sectors;i++) {
uint32_t sector_offset_in_block=((sector_num+i)%s->sectors_per_block),
block_num=(sector_num+i)/s->sectors_per_block;
if(cloop_read_block(s, block_num) != 0)
return -1;
memcpy(buf+i*512,s->uncompressed_block+sector_offset_in_block*512,512);
}
return 0;
}
static void cloop_close(BlockDriverState *bs)
{
BDRVCloopState *s = bs->opaque;
close(s->fd);
free(s->compressed_block);
free(s->uncompressed_block);
inflateEnd(&s->zstream);
}
BlockDriver bdrv_cloop = {
"cloop",
sizeof(BDRVCloopState),
cloop_probe,
cloop_open,
cloop_read,
NULL,
cloop_close,
};

263
block-cow.c Normal file
View File

@@ -0,0 +1,263 @@
/*
* Block driver for the COW format
*
* Copyright (c) 2004 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef _WIN32
#include "vl.h"
#include "block_int.h"
#include <sys/mman.h>
/**************************************************************/
/* COW block driver using file system holes */
/* user mode linux compatible COW file */
#define COW_MAGIC 0x4f4f4f4d /* MOOO */
#define COW_VERSION 2
struct cow_header_v2 {
uint32_t magic;
uint32_t version;
char backing_file[1024];
int32_t mtime;
uint64_t size;
uint32_t sectorsize;
};
typedef struct BDRVCowState {
int fd;
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;
int64_t cow_sectors_offset;
} BDRVCowState;
static int cow_probe(const uint8_t *buf, int buf_size, const char *filename)
{
const struct cow_header_v2 *cow_header = (const void *)buf;
if (be32_to_cpu(cow_header->magic) == COW_MAGIC &&
be32_to_cpu(cow_header->version) == COW_VERSION)
return 100;
else
return 0;
}
static int cow_open(BlockDriverState *bs, const char *filename)
{
BDRVCowState *s = bs->opaque;
int fd;
struct cow_header_v2 cow_header;
int64_t size;
fd = open(filename, O_RDWR | O_BINARY | O_LARGEFILE);
if (fd < 0) {
fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE);
if (fd < 0)
return -1;
}
s->fd = fd;
/* see if it is a cow image */
if (read(fd, &cow_header, sizeof(cow_header)) != sizeof(cow_header)) {
goto fail;
}
if (be32_to_cpu(cow_header.magic) != COW_MAGIC ||
be32_to_cpu(cow_header.version) != COW_VERSION) {
goto fail;
}
/* cow image found */
size = be64_to_cpu(cow_header.size);
bs->total_sectors = size / 512;
pstrcpy(bs->backing_file, sizeof(bs->backing_file),
cow_header.backing_file);
#if 0
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 != be32_to_cpu(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;
}
#endif
/* mmap the bitmap */
s->cow_bitmap_size = ((bs->total_sectors + 7) >> 3) + sizeof(cow_header);
s->cow_bitmap_addr = mmap(get_mmap_addr(s->cow_bitmap_size),
s->cow_bitmap_size,
PROT_READ | PROT_WRITE,
MAP_SHARED, s->fd, 0);
if (s->cow_bitmap_addr == MAP_FAILED)
goto fail;
s->cow_bitmap = s->cow_bitmap_addr + sizeof(cow_header);
s->cow_sectors_offset = (s->cow_bitmap_size + 511) & ~511;
return 0;
fail:
close(fd);
return -1;
}
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 inline 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;
}
static int cow_is_allocated(BlockDriverState *bs, int64_t sector_num,
int nb_sectors, int *pnum)
{
BDRVCowState *s = bs->opaque;
return is_changed(s->cow_bitmap, sector_num, nb_sectors, pnum);
}
static int cow_read(BlockDriverState *bs, int64_t sector_num,
uint8_t *buf, int nb_sectors)
{
BDRVCowState *s = bs->opaque;
int ret, n;
while (nb_sectors > 0) {
if (is_changed(s->cow_bitmap, sector_num, nb_sectors, &n)) {
lseek(s->fd, s->cow_sectors_offset + sector_num * 512, SEEK_SET);
ret = read(s->fd, buf, n * 512);
if (ret != n * 512)
return -1;
} else {
memset(buf, 0, n * 512);
}
nb_sectors -= n;
sector_num += n;
buf += n * 512;
}
return 0;
}
static int cow_write(BlockDriverState *bs, int64_t sector_num,
const uint8_t *buf, int nb_sectors)
{
BDRVCowState *s = bs->opaque;
int ret, i;
lseek(s->fd, s->cow_sectors_offset + sector_num * 512, SEEK_SET);
ret = write(s->fd, buf, nb_sectors * 512);
if (ret != nb_sectors * 512)
return -1;
for (i = 0; i < nb_sectors; i++)
set_bit(s->cow_bitmap, sector_num + i);
return 0;
}
static void cow_close(BlockDriverState *bs)
{
BDRVCowState *s = bs->opaque;
munmap(s->cow_bitmap_addr, s->cow_bitmap_size);
close(s->fd);
}
static int cow_create(const char *filename, int64_t image_sectors,
const char *image_filename, int flags)
{
int fd, cow_fd;
struct cow_header_v2 cow_header;
struct stat st;
if (flags)
return -ENOTSUP;
cow_fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE,
0644);
if (cow_fd < 0)
return -1;
memset(&cow_header, 0, sizeof(cow_header));
cow_header.magic = cpu_to_be32(COW_MAGIC);
cow_header.version = cpu_to_be32(COW_VERSION);
if (image_filename) {
fd = open(image_filename, O_RDONLY | O_BINARY);
if (fd < 0) {
close(cow_fd);
return -1;
}
if (fstat(fd, &st) != 0) {
close(fd);
return -1;
}
close(fd);
cow_header.mtime = cpu_to_be32(st.st_mtime);
realpath(image_filename, cow_header.backing_file);
}
cow_header.sectorsize = cpu_to_be32(512);
cow_header.size = cpu_to_be64(image_sectors * 512);
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));
close(cow_fd);
return 0;
}
BlockDriver bdrv_cow = {
"cow",
sizeof(BDRVCowState),
cow_probe,
cow_open,
cow_read,
cow_write,
cow_close,
cow_create,
cow_is_allocated,
};
#endif

677
block-qcow.c Normal file
View File

@@ -0,0 +1,677 @@
/*
* Block driver for the QCOW format
*
* Copyright (c) 2004 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 "vl.h"
#include "block_int.h"
#include <zlib.h>
#include "aes.h"
/**************************************************************/
/* QEMU COW block driver with compression and encryption support */
#define QCOW_MAGIC (('Q' << 24) | ('F' << 16) | ('I' << 8) | 0xfb)
#define QCOW_VERSION 1
#define QCOW_CRYPT_NONE 0
#define QCOW_CRYPT_AES 1
#define QCOW_OFLAG_COMPRESSED (1LL << 63)
typedef struct QCowHeader {
uint32_t magic;
uint32_t version;
uint64_t backing_file_offset;
uint32_t backing_file_size;
uint32_t mtime;
uint64_t size; /* in bytes */
uint8_t cluster_bits;
uint8_t l2_bits;
uint32_t crypt_method;
uint64_t l1_table_offset;
} QCowHeader;
#define L2_CACHE_SIZE 16
typedef struct BDRVQcowState {
int fd;
int cluster_bits;
int cluster_size;
int cluster_sectors;
int l2_bits;
int l2_size;
int l1_size;
uint64_t cluster_offset_mask;
uint64_t l1_table_offset;
uint64_t *l1_table;
uint64_t *l2_cache;
uint64_t l2_cache_offsets[L2_CACHE_SIZE];
uint32_t l2_cache_counts[L2_CACHE_SIZE];
uint8_t *cluster_cache;
uint8_t *cluster_data;
uint64_t cluster_cache_offset;
uint32_t crypt_method; /* current crypt method, 0 if no key yet */
uint32_t crypt_method_header;
AES_KEY aes_encrypt_key;
AES_KEY aes_decrypt_key;
} BDRVQcowState;
static int decompress_cluster(BDRVQcowState *s, uint64_t cluster_offset);
static int qcow_probe(const uint8_t *buf, int buf_size, const char *filename)
{
const QCowHeader *cow_header = (const void *)buf;
if (be32_to_cpu(cow_header->magic) == QCOW_MAGIC &&
be32_to_cpu(cow_header->version) == QCOW_VERSION)
return 100;
else
return 0;
}
static int qcow_open(BlockDriverState *bs, const char *filename)
{
BDRVQcowState *s = bs->opaque;
int fd, len, i, shift;
QCowHeader header;
fd = open(filename, O_RDWR | O_BINARY | O_LARGEFILE);
if (fd < 0) {
fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE);
if (fd < 0)
return -1;
}
s->fd = fd;
if (read(fd, &header, sizeof(header)) != sizeof(header))
goto fail;
be32_to_cpus(&header.magic);
be32_to_cpus(&header.version);
be64_to_cpus(&header.backing_file_offset);
be32_to_cpus(&header.backing_file_size);
be32_to_cpus(&header.mtime);
be64_to_cpus(&header.size);
be32_to_cpus(&header.crypt_method);
be64_to_cpus(&header.l1_table_offset);
if (header.magic != QCOW_MAGIC || header.version != QCOW_VERSION)
goto fail;
if (header.size <= 1 || header.cluster_bits < 9)
goto fail;
if (header.crypt_method > QCOW_CRYPT_AES)
goto fail;
s->crypt_method_header = header.crypt_method;
if (s->crypt_method_header)
bs->encrypted = 1;
s->cluster_bits = header.cluster_bits;
s->cluster_size = 1 << s->cluster_bits;
s->cluster_sectors = 1 << (s->cluster_bits - 9);
s->l2_bits = header.l2_bits;
s->l2_size = 1 << s->l2_bits;
bs->total_sectors = header.size / 512;
s->cluster_offset_mask = (1LL << (63 - s->cluster_bits)) - 1;
/* read the level 1 table */
shift = s->cluster_bits + s->l2_bits;
s->l1_size = (header.size + (1LL << shift) - 1) >> shift;
s->l1_table_offset = header.l1_table_offset;
s->l1_table = qemu_malloc(s->l1_size * sizeof(uint64_t));
if (!s->l1_table)
goto fail;
lseek(fd, s->l1_table_offset, SEEK_SET);
if (read(fd, s->l1_table, s->l1_size * sizeof(uint64_t)) !=
s->l1_size * sizeof(uint64_t))
goto fail;
for(i = 0;i < s->l1_size; i++) {
be64_to_cpus(&s->l1_table[i]);
}
/* alloc L2 cache */
s->l2_cache = qemu_malloc(s->l2_size * L2_CACHE_SIZE * sizeof(uint64_t));
if (!s->l2_cache)
goto fail;
s->cluster_cache = qemu_malloc(s->cluster_size);
if (!s->cluster_cache)
goto fail;
s->cluster_data = qemu_malloc(s->cluster_size);
if (!s->cluster_data)
goto fail;
s->cluster_cache_offset = -1;
/* read the backing file name */
if (header.backing_file_offset != 0) {
len = header.backing_file_size;
if (len > 1023)
len = 1023;
lseek(fd, header.backing_file_offset, SEEK_SET);
if (read(fd, bs->backing_file, len) != len)
goto fail;
bs->backing_file[len] = '\0';
}
return 0;
fail:
qemu_free(s->l1_table);
qemu_free(s->l2_cache);
qemu_free(s->cluster_cache);
qemu_free(s->cluster_data);
close(fd);
return -1;
}
static int qcow_set_key(BlockDriverState *bs, const char *key)
{
BDRVQcowState *s = bs->opaque;
uint8_t keybuf[16];
int len, i;
memset(keybuf, 0, 16);
len = strlen(key);
if (len > 16)
len = 16;
/* XXX: we could compress the chars to 7 bits to increase
entropy */
for(i = 0;i < len;i++) {
keybuf[i] = key[i];
}
s->crypt_method = s->crypt_method_header;
if (AES_set_encrypt_key(keybuf, 128, &s->aes_encrypt_key) != 0)
return -1;
if (AES_set_decrypt_key(keybuf, 128, &s->aes_decrypt_key) != 0)
return -1;
#if 0
/* test */
{
uint8_t in[16];
uint8_t out[16];
uint8_t tmp[16];
for(i=0;i<16;i++)
in[i] = i;
AES_encrypt(in, tmp, &s->aes_encrypt_key);
AES_decrypt(tmp, out, &s->aes_decrypt_key);
for(i = 0; i < 16; i++)
printf(" %02x", tmp[i]);
printf("\n");
for(i = 0; i < 16; i++)
printf(" %02x", out[i]);
printf("\n");
}
#endif
return 0;
}
/* The crypt function is compatible with the linux cryptoloop
algorithm for < 4 GB images. NOTE: out_buf == in_buf is
supported */
static void encrypt_sectors(BDRVQcowState *s, int64_t sector_num,
uint8_t *out_buf, const uint8_t *in_buf,
int nb_sectors, int enc,
const AES_KEY *key)
{
union {
uint64_t ll[2];
uint8_t b[16];
} ivec;
int i;
for(i = 0; i < nb_sectors; i++) {
ivec.ll[0] = cpu_to_le64(sector_num);
ivec.ll[1] = 0;
AES_cbc_encrypt(in_buf, out_buf, 512, key,
ivec.b, enc);
sector_num++;
in_buf += 512;
out_buf += 512;
}
}
/* 'allocate' is:
*
* 0 to not allocate.
*
* 1 to allocate a normal cluster (for sector indexes 'n_start' to
* 'n_end')
*
* 2 to allocate a compressed cluster of size
* 'compressed_size'. 'compressed_size' must be > 0 and <
* cluster_size
*
* return 0 if not allocated.
*/
static uint64_t get_cluster_offset(BlockDriverState *bs,
uint64_t offset, int allocate,
int compressed_size,
int n_start, int n_end)
{
BDRVQcowState *s = bs->opaque;
int min_index, i, j, l1_index, l2_index;
uint64_t l2_offset, *l2_table, cluster_offset, tmp;
uint32_t min_count;
int new_l2_table;
l1_index = offset >> (s->l2_bits + s->cluster_bits);
l2_offset = s->l1_table[l1_index];
new_l2_table = 0;
if (!l2_offset) {
if (!allocate)
return 0;
/* allocate a new l2 entry */
l2_offset = lseek(s->fd, 0, SEEK_END);
/* round to cluster size */
l2_offset = (l2_offset + s->cluster_size - 1) & ~(s->cluster_size - 1);
/* update the L1 entry */
s->l1_table[l1_index] = l2_offset;
tmp = cpu_to_be64(l2_offset);
lseek(s->fd, s->l1_table_offset + l1_index * sizeof(tmp), SEEK_SET);
if (write(s->fd, &tmp, sizeof(tmp)) != sizeof(tmp))
return 0;
new_l2_table = 1;
}
for(i = 0; i < L2_CACHE_SIZE; i++) {
if (l2_offset == s->l2_cache_offsets[i]) {
/* increment the hit count */
if (++s->l2_cache_counts[i] == 0xffffffff) {
for(j = 0; j < L2_CACHE_SIZE; j++) {
s->l2_cache_counts[j] >>= 1;
}
}
l2_table = s->l2_cache + (i << s->l2_bits);
goto found;
}
}
/* not found: load a new entry in the least used one */
min_index = 0;
min_count = 0xffffffff;
for(i = 0; i < L2_CACHE_SIZE; i++) {
if (s->l2_cache_counts[i] < min_count) {
min_count = s->l2_cache_counts[i];
min_index = i;
}
}
l2_table = s->l2_cache + (min_index << s->l2_bits);
lseek(s->fd, l2_offset, SEEK_SET);
if (new_l2_table) {
memset(l2_table, 0, s->l2_size * sizeof(uint64_t));
if (write(s->fd, l2_table, s->l2_size * sizeof(uint64_t)) !=
s->l2_size * sizeof(uint64_t))
return 0;
} else {
if (read(s->fd, l2_table, s->l2_size * sizeof(uint64_t)) !=
s->l2_size * sizeof(uint64_t))
return 0;
}
s->l2_cache_offsets[min_index] = l2_offset;
s->l2_cache_counts[min_index] = 1;
found:
l2_index = (offset >> s->cluster_bits) & (s->l2_size - 1);
cluster_offset = be64_to_cpu(l2_table[l2_index]);
if (!cluster_offset ||
((cluster_offset & QCOW_OFLAG_COMPRESSED) && allocate == 1)) {
if (!allocate)
return 0;
/* allocate a new cluster */
if ((cluster_offset & QCOW_OFLAG_COMPRESSED) &&
(n_end - n_start) < s->cluster_sectors) {
/* if the cluster is already compressed, we must
decompress it in the case it is not completely
overwritten */
if (decompress_cluster(s, cluster_offset) < 0)
return 0;
cluster_offset = lseek(s->fd, 0, SEEK_END);
cluster_offset = (cluster_offset + s->cluster_size - 1) &
~(s->cluster_size - 1);
/* write the cluster content */
lseek(s->fd, cluster_offset, SEEK_SET);
if (write(s->fd, s->cluster_cache, s->cluster_size) !=
s->cluster_size)
return -1;
} else {
cluster_offset = lseek(s->fd, 0, SEEK_END);
if (allocate == 1) {
/* round to cluster size */
cluster_offset = (cluster_offset + s->cluster_size - 1) &
~(s->cluster_size - 1);
ftruncate(s->fd, cluster_offset + s->cluster_size);
/* if encrypted, we must initialize the cluster
content which won't be written */
if (s->crypt_method &&
(n_end - n_start) < s->cluster_sectors) {
uint64_t start_sect;
start_sect = (offset & ~(s->cluster_size - 1)) >> 9;
memset(s->cluster_data + 512, 0xaa, 512);
for(i = 0; i < s->cluster_sectors; i++) {
if (i < n_start || i >= n_end) {
encrypt_sectors(s, start_sect + i,
s->cluster_data,
s->cluster_data + 512, 1, 1,
&s->aes_encrypt_key);
lseek(s->fd, cluster_offset + i * 512, SEEK_SET);
if (write(s->fd, s->cluster_data, 512) != 512)
return -1;
}
}
}
} else {
cluster_offset |= QCOW_OFLAG_COMPRESSED |
(uint64_t)compressed_size << (63 - s->cluster_bits);
}
}
/* update L2 table */
tmp = cpu_to_be64(cluster_offset);
l2_table[l2_index] = tmp;
lseek(s->fd, l2_offset + l2_index * sizeof(tmp), SEEK_SET);
if (write(s->fd, &tmp, sizeof(tmp)) != sizeof(tmp))
return 0;
}
return cluster_offset;
}
static int qcow_is_allocated(BlockDriverState *bs, int64_t sector_num,
int nb_sectors, int *pnum)
{
BDRVQcowState *s = bs->opaque;
int index_in_cluster, n;
uint64_t cluster_offset;
cluster_offset = get_cluster_offset(bs, sector_num << 9, 0, 0, 0, 0);
index_in_cluster = sector_num & (s->cluster_sectors - 1);
n = s->cluster_sectors - index_in_cluster;
if (n > nb_sectors)
n = nb_sectors;
*pnum = n;
return (cluster_offset != 0);
}
static int decompress_buffer(uint8_t *out_buf, int out_buf_size,
const uint8_t *buf, int buf_size)
{
z_stream strm1, *strm = &strm1;
int ret, out_len;
memset(strm, 0, sizeof(*strm));
strm->next_in = (uint8_t *)buf;
strm->avail_in = buf_size;
strm->next_out = out_buf;
strm->avail_out = out_buf_size;
ret = inflateInit2(strm, -12);
if (ret != Z_OK)
return -1;
ret = inflate(strm, Z_FINISH);
out_len = strm->next_out - out_buf;
if ((ret != Z_STREAM_END && ret != Z_BUF_ERROR) ||
out_len != out_buf_size) {
inflateEnd(strm);
return -1;
}
inflateEnd(strm);
return 0;
}
static int decompress_cluster(BDRVQcowState *s, uint64_t cluster_offset)
{
int ret, csize;
uint64_t coffset;
coffset = cluster_offset & s->cluster_offset_mask;
if (s->cluster_cache_offset != coffset) {
csize = cluster_offset >> (63 - s->cluster_bits);
csize &= (s->cluster_size - 1);
lseek(s->fd, coffset, SEEK_SET);
ret = read(s->fd, s->cluster_data, csize);
if (ret != csize)
return -1;
if (decompress_buffer(s->cluster_cache, s->cluster_size,
s->cluster_data, csize) < 0) {
return -1;
}
s->cluster_cache_offset = coffset;
}
return 0;
}
static int qcow_read(BlockDriverState *bs, int64_t sector_num,
uint8_t *buf, int nb_sectors)
{
BDRVQcowState *s = bs->opaque;
int ret, index_in_cluster, n;
uint64_t cluster_offset;
while (nb_sectors > 0) {
cluster_offset = get_cluster_offset(bs, sector_num << 9, 0, 0, 0, 0);
index_in_cluster = sector_num & (s->cluster_sectors - 1);
n = s->cluster_sectors - index_in_cluster;
if (n > nb_sectors)
n = nb_sectors;
if (!cluster_offset) {
memset(buf, 0, 512 * n);
} else if (cluster_offset & QCOW_OFLAG_COMPRESSED) {
if (decompress_cluster(s, cluster_offset) < 0)
return -1;
memcpy(buf, s->cluster_cache + index_in_cluster * 512, 512 * n);
} else {
lseek(s->fd, cluster_offset + index_in_cluster * 512, SEEK_SET);
ret = read(s->fd, buf, n * 512);
if (ret != n * 512)
return -1;
if (s->crypt_method) {
encrypt_sectors(s, sector_num, buf, buf, n, 0,
&s->aes_decrypt_key);
}
}
nb_sectors -= n;
sector_num += n;
buf += n * 512;
}
return 0;
}
static int qcow_write(BlockDriverState *bs, int64_t sector_num,
const uint8_t *buf, int nb_sectors)
{
BDRVQcowState *s = bs->opaque;
int ret, index_in_cluster, n;
uint64_t cluster_offset;
while (nb_sectors > 0) {
index_in_cluster = sector_num & (s->cluster_sectors - 1);
n = s->cluster_sectors - index_in_cluster;
if (n > nb_sectors)
n = nb_sectors;
cluster_offset = get_cluster_offset(bs, sector_num << 9, 1, 0,
index_in_cluster,
index_in_cluster + n);
if (!cluster_offset)
return -1;
lseek(s->fd, cluster_offset + index_in_cluster * 512, SEEK_SET);
if (s->crypt_method) {
encrypt_sectors(s, sector_num, s->cluster_data, buf, n, 1,
&s->aes_encrypt_key);
ret = write(s->fd, s->cluster_data, n * 512);
} else {
ret = write(s->fd, buf, n * 512);
}
if (ret != n * 512)
return -1;
nb_sectors -= n;
sector_num += n;
buf += n * 512;
}
s->cluster_cache_offset = -1; /* disable compressed cache */
return 0;
}
static void qcow_close(BlockDriverState *bs)
{
BDRVQcowState *s = bs->opaque;
qemu_free(s->l1_table);
qemu_free(s->l2_cache);
qemu_free(s->cluster_cache);
qemu_free(s->cluster_data);
close(s->fd);
}
static int qcow_create(const char *filename, int64_t total_size,
const char *backing_file, int flags)
{
int fd, header_size, backing_filename_len, l1_size, i, shift;
QCowHeader header;
char backing_filename[1024];
uint64_t tmp;
struct stat st;
fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE,
0644);
if (fd < 0)
return -1;
memset(&header, 0, sizeof(header));
header.magic = cpu_to_be32(QCOW_MAGIC);
header.version = cpu_to_be32(QCOW_VERSION);
header.size = cpu_to_be64(total_size * 512);
header_size = sizeof(header);
backing_filename_len = 0;
if (backing_file) {
realpath(backing_file, backing_filename);
if (stat(backing_filename, &st) != 0) {
return -1;
}
header.mtime = cpu_to_be32(st.st_mtime);
header.backing_file_offset = cpu_to_be64(header_size);
backing_filename_len = strlen(backing_filename);
header.backing_file_size = cpu_to_be32(backing_filename_len);
header_size += backing_filename_len;
header.cluster_bits = 9; /* 512 byte cluster to avoid copying
unmodifyed sectors */
header.l2_bits = 12; /* 32 KB L2 tables */
} else {
header.cluster_bits = 12; /* 4 KB clusters */
header.l2_bits = 9; /* 4 KB L2 tables */
}
header_size = (header_size + 7) & ~7;
shift = header.cluster_bits + header.l2_bits;
l1_size = ((total_size * 512) + (1LL << shift) - 1) >> shift;
header.l1_table_offset = cpu_to_be64(header_size);
if (flags) {
header.crypt_method = cpu_to_be32(QCOW_CRYPT_AES);
} else {
header.crypt_method = cpu_to_be32(QCOW_CRYPT_NONE);
}
/* write all the data */
write(fd, &header, sizeof(header));
if (backing_file) {
write(fd, backing_filename, backing_filename_len);
}
lseek(fd, header_size, SEEK_SET);
tmp = 0;
for(i = 0;i < l1_size; i++) {
write(fd, &tmp, sizeof(tmp));
}
close(fd);
return 0;
}
int qcow_get_cluster_size(BlockDriverState *bs)
{
BDRVQcowState *s = bs->opaque;
if (bs->drv != &bdrv_qcow)
return -1;
return s->cluster_size;
}
/* XXX: put compressed sectors first, then all the cluster aligned
tables to avoid losing bytes in alignment */
int qcow_compress_cluster(BlockDriverState *bs, int64_t sector_num,
const uint8_t *buf)
{
BDRVQcowState *s = bs->opaque;
z_stream strm;
int ret, out_len;
uint8_t *out_buf;
uint64_t cluster_offset;
if (bs->drv != &bdrv_qcow)
return -1;
out_buf = qemu_malloc(s->cluster_size + (s->cluster_size / 1000) + 128);
if (!out_buf)
return -1;
/* best compression, small window, no zlib header */
memset(&strm, 0, sizeof(strm));
ret = deflateInit2(&strm, Z_DEFAULT_COMPRESSION,
Z_DEFLATED, -12,
9, Z_DEFAULT_STRATEGY);
if (ret != 0) {
qemu_free(out_buf);
return -1;
}
strm.avail_in = s->cluster_size;
strm.next_in = (uint8_t *)buf;
strm.avail_out = s->cluster_size;
strm.next_out = out_buf;
ret = deflate(&strm, Z_FINISH);
if (ret != Z_STREAM_END && ret != Z_OK) {
qemu_free(out_buf);
deflateEnd(&strm);
return -1;
}
out_len = strm.next_out - out_buf;
deflateEnd(&strm);
if (ret != Z_STREAM_END || out_len >= s->cluster_size) {
/* could not compress: write normal cluster */
qcow_write(bs, sector_num, buf, s->cluster_sectors);
} else {
cluster_offset = get_cluster_offset(bs, sector_num << 9, 2,
out_len, 0, 0);
cluster_offset &= s->cluster_offset_mask;
lseek(s->fd, cluster_offset, SEEK_SET);
if (write(s->fd, out_buf, out_len) != out_len) {
qemu_free(out_buf);
return -1;
}
}
qemu_free(out_buf);
return 0;
}
BlockDriver bdrv_qcow = {
"qcow",
sizeof(BDRVQcowState),
qcow_probe,
qcow_open,
qcow_read,
qcow_write,
qcow_close,
qcow_create,
qcow_is_allocated,
qcow_set_key,
};

279
block-vmdk.c Normal file
View File

@@ -0,0 +1,279 @@
/*
* Block driver for the VMDK format
*
* Copyright (c) 2004 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 "vl.h"
#include "block_int.h"
/* XXX: this code is untested */
/* XXX: add write support */
#define VMDK3_MAGIC (('C' << 24) | ('O' << 16) | ('W' << 8) | 'D')
#define VMDK4_MAGIC (('K' << 24) | ('D' << 16) | ('M' << 8) | 'V')
typedef struct {
uint32_t version;
uint32_t flags;
uint32_t disk_sectors;
uint32_t granularity;
uint32_t l1dir_offset;
uint32_t l1dir_size;
uint32_t file_sectors;
uint32_t cylinders;
uint32_t heads;
uint32_t sectors_per_track;
} VMDK3Header;
typedef struct {
uint32_t version;
uint32_t flags;
int64_t capacity;
int64_t granularity;
int64_t desc_offset;
int64_t desc_size;
int32_t num_gtes_per_gte;
int64_t rgd_offset;
int64_t gd_offset;
int64_t grain_offset;
char filler[1];
char check_bytes[4];
} VMDK4Header;
#define L2_CACHE_SIZE 16
typedef struct BDRVVmdkState {
int fd;
int64_t l1_table_offset;
uint32_t *l1_table;
unsigned int l1_size;
uint32_t l1_entry_sectors;
unsigned int l2_size;
uint32_t *l2_cache;
uint32_t l2_cache_offsets[L2_CACHE_SIZE];
uint32_t l2_cache_counts[L2_CACHE_SIZE];
unsigned int cluster_sectors;
} BDRVVmdkState;
static int vmdk_probe(const uint8_t *buf, int buf_size, const char *filename)
{
uint32_t magic;
if (buf_size < 4)
return 0;
magic = be32_to_cpu(*(uint32_t *)buf);
if (magic == VMDK3_MAGIC ||
magic == VMDK4_MAGIC)
return 100;
else
return 0;
}
static int vmdk_open(BlockDriverState *bs, const char *filename)
{
BDRVVmdkState *s = bs->opaque;
int fd, i;
uint32_t magic;
int l1_size;
fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE);
if (fd < 0)
return -1;
if (read(fd, &magic, sizeof(magic)) != sizeof(magic))
goto fail;
magic = be32_to_cpu(magic);
if (magic == VMDK3_MAGIC) {
VMDK3Header header;
if (read(fd, &header, sizeof(header)) !=
sizeof(header))
goto fail;
s->cluster_sectors = le32_to_cpu(header.granularity);
s->l2_size = 1 << 9;
s->l1_size = 1 << 6;
bs->total_sectors = le32_to_cpu(header.disk_sectors);
s->l1_table_offset = le32_to_cpu(header.l1dir_offset) * 512;
s->l1_entry_sectors = s->l2_size * s->cluster_sectors;
} else if (magic == VMDK4_MAGIC) {
VMDK4Header header;
if (read(fd, &header, sizeof(header)) != sizeof(header))
goto fail;
bs->total_sectors = le32_to_cpu(header.capacity);
s->cluster_sectors = le32_to_cpu(header.granularity);
s->l2_size = le32_to_cpu(header.num_gtes_per_gte);
s->l1_entry_sectors = s->l2_size * s->cluster_sectors;
if (s->l1_entry_sectors <= 0)
goto fail;
s->l1_size = (bs->total_sectors + s->l1_entry_sectors - 1)
/ s->l1_entry_sectors;
s->l1_table_offset = le64_to_cpu(header.rgd_offset) * 512;
} else {
goto fail;
}
/* read the L1 table */
l1_size = s->l1_size * sizeof(uint32_t);
s->l1_table = qemu_malloc(l1_size);
if (!s->l1_table)
goto fail;
if (lseek(fd, s->l1_table_offset, SEEK_SET) == -1)
goto fail;
if (read(fd, s->l1_table, l1_size) != l1_size)
goto fail;
for(i = 0; i < s->l1_size; i++) {
le32_to_cpus(&s->l1_table[i]);
}
s->l2_cache = qemu_malloc(s->l2_size * L2_CACHE_SIZE * sizeof(uint32_t));
if (!s->l2_cache)
goto fail;
s->fd = fd;
/* XXX: currently only read only */
bs->read_only = 1;
return 0;
fail:
qemu_free(s->l1_table);
qemu_free(s->l2_cache);
close(fd);
return -1;
}
static uint64_t get_cluster_offset(BlockDriverState *bs,
uint64_t offset)
{
BDRVVmdkState *s = bs->opaque;
unsigned int l1_index, l2_offset, l2_index;
int min_index, i, j;
uint32_t min_count, *l2_table;
uint64_t cluster_offset;
l1_index = (offset >> 9) / s->l1_entry_sectors;
if (l1_index >= s->l1_size)
return 0;
l2_offset = s->l1_table[l1_index];
if (!l2_offset)
return 0;
for(i = 0; i < L2_CACHE_SIZE; i++) {
if (l2_offset == s->l2_cache_offsets[i]) {
/* increment the hit count */
if (++s->l2_cache_counts[i] == 0xffffffff) {
for(j = 0; j < L2_CACHE_SIZE; j++) {
s->l2_cache_counts[j] >>= 1;
}
}
l2_table = s->l2_cache + (i * s->l2_size);
goto found;
}
}
/* not found: load a new entry in the least used one */
min_index = 0;
min_count = 0xffffffff;
for(i = 0; i < L2_CACHE_SIZE; i++) {
if (s->l2_cache_counts[i] < min_count) {
min_count = s->l2_cache_counts[i];
min_index = i;
}
}
l2_table = s->l2_cache + (min_index * s->l2_size);
lseek(s->fd, (int64_t)l2_offset * 512, SEEK_SET);
if (read(s->fd, l2_table, s->l2_size * sizeof(uint32_t)) !=
s->l2_size * sizeof(uint32_t))
return 0;
s->l2_cache_offsets[min_index] = l2_offset;
s->l2_cache_counts[min_index] = 1;
found:
l2_index = ((offset >> 9) / s->cluster_sectors) % s->l2_size;
cluster_offset = le32_to_cpu(l2_table[l2_index]);
cluster_offset <<= 9;
return cluster_offset;
}
static int vmdk_is_allocated(BlockDriverState *bs, int64_t sector_num,
int nb_sectors, int *pnum)
{
BDRVVmdkState *s = bs->opaque;
int index_in_cluster, n;
uint64_t cluster_offset;
cluster_offset = get_cluster_offset(bs, sector_num << 9);
index_in_cluster = sector_num % s->cluster_sectors;
n = s->cluster_sectors - index_in_cluster;
if (n > nb_sectors)
n = nb_sectors;
*pnum = n;
return (cluster_offset != 0);
}
static int vmdk_read(BlockDriverState *bs, int64_t sector_num,
uint8_t *buf, int nb_sectors)
{
BDRVVmdkState *s = bs->opaque;
int ret, index_in_cluster, n;
uint64_t cluster_offset;
while (nb_sectors > 0) {
cluster_offset = get_cluster_offset(bs, sector_num << 9);
index_in_cluster = sector_num % s->cluster_sectors;
n = s->cluster_sectors - index_in_cluster;
if (n > nb_sectors)
n = nb_sectors;
if (!cluster_offset) {
memset(buf, 0, 512 * n);
} else {
lseek(s->fd, cluster_offset + index_in_cluster * 512, SEEK_SET);
ret = read(s->fd, buf, n * 512);
if (ret != n * 512)
return -1;
}
nb_sectors -= n;
sector_num += n;
buf += n * 512;
}
return 0;
}
static int vmdk_write(BlockDriverState *bs, int64_t sector_num,
const uint8_t *buf, int nb_sectors)
{
return -1;
}
static void vmdk_close(BlockDriverState *bs)
{
BDRVVmdkState *s = bs->opaque;
qemu_free(s->l1_table);
qemu_free(s->l2_cache);
close(s->fd);
}
BlockDriver bdrv_vmdk = {
"vmdk",
sizeof(BDRVVmdkState),
vmdk_probe,
vmdk_open,
vmdk_read,
vmdk_write,
vmdk_close,
NULL, /* no create yet */
vmdk_is_allocated,
};

760
block.c
View File

@@ -21,233 +21,250 @@
* 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"
#include "block_int.h"
#define NO_THUNK_TYPE_SIZE
#include "thunk.h"
static BlockDriverState *bdrv_first;
static BlockDriver *first_drv;
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)
void bdrv_register(BlockDriver *bdrv)
{
BlockDriverState *bs;
int fd, cow_fd;
int64_t size;
char template[] = "/tmp/vl.XXXXXX";
struct cow_header_v2 cow_header;
struct stat st;
bdrv->next = first_drv;
first_drv = bdrv;
}
bs = malloc(sizeof(BlockDriverState));
/* create a new block device (by default it is empty) */
BlockDriverState *bdrv_new(const char *device_name)
{
BlockDriverState **pbs, *bs;
bs = qemu_mallocz(sizeof(BlockDriverState));
if(!bs)
return NULL;
pstrcpy(bs->device_name, sizeof(bs->device_name), device_name);
if (device_name[0] != '\0') {
/* insert at the end */
pbs = &bdrv_first;
while (*pbs != NULL)
pbs = &(*pbs)->next;
*pbs = bs;
}
return bs;
}
BlockDriver *bdrv_find_format(const char *format_name)
{
BlockDriver *drv1;
for(drv1 = first_drv; drv1 != NULL; drv1 = drv1->next) {
if (!strcmp(drv1->format_name, format_name))
return drv1;
}
return NULL;
}
int bdrv_create(BlockDriver *drv,
const char *filename, int64_t size_in_sectors,
const char *backing_file, int flags)
{
if (!drv->bdrv_create)
return -ENOTSUP;
return drv->bdrv_create(filename, size_in_sectors, backing_file, flags);
}
#ifdef _WIN32
static void get_tmp_filename(char *filename, int size)
{
/* XXX: find a better function */
tmpnam(filename);
}
#else
static void get_tmp_filename(char *filename, int size)
{
int fd;
/* XXX: race condition possible */
pstrcpy(filename, size, "/tmp/vl.XXXXXX");
fd = mkstemp(filename);
close(fd);
}
#endif
static BlockDriver *find_image_format(const char *filename)
{
int fd, ret, score, score_max;
BlockDriver *drv1, *drv;
uint8_t buf[1024];
fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE);
if (fd < 0)
return NULL;
ret = read(fd, buf, sizeof(buf));
if (ret < 0) {
close(fd);
return NULL;
}
close(fd);
drv = NULL;
score_max = 0;
for(drv1 = first_drv; drv1 != NULL; drv1 = drv1->next) {
score = drv1->bdrv_probe(buf, ret, filename);
if (score > score_max) {
score_max = score;
drv = drv1;
}
}
return drv;
}
int bdrv_open(BlockDriverState *bs, const char *filename, int snapshot)
{
return bdrv_open2(bs, filename, snapshot, NULL);
}
int bdrv_open2(BlockDriverState *bs, const char *filename, int snapshot,
BlockDriver *drv)
{
int ret;
char tmp_filename[1024];
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;
}
bs->is_temporary = 0;
bs->encrypted = 0;
if (snapshot) {
/* create a temporary COW file */
cow_fd = mkstemp(template);
if (cow_fd < 0)
goto fail;
bs->cow_fd = cow_fd;
unlink(template);
BlockDriverState *bs1;
int64_t total_size;
/* 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;
/* if snapshot, we create a temporary backing file and open it
instead of opening 'filename' directly */
/* if there is a backing file, use it */
bs1 = bdrv_new("");
if (!bs1) {
return -1;
}
if (bdrv_open(bs1, filename, 0) < 0) {
bdrv_delete(bs1);
return -1;
}
total_size = bs1->total_sectors;
bdrv_delete(bs1);
get_tmp_filename(tmp_filename, sizeof(tmp_filename));
/* XXX: use cow for linux as it is more efficient ? */
if (bdrv_create(&bdrv_qcow, tmp_filename,
total_size, filename, 0) < 0) {
return -1;
}
filename = tmp_filename;
bs->is_temporary = 1;
}
return bs;
fail:
bdrv_close(bs);
return NULL;
pstrcpy(bs->filename, sizeof(bs->filename), filename);
if (!drv) {
drv = find_image_format(filename);
if (!drv)
return -1;
}
bs->drv = drv;
bs->opaque = qemu_mallocz(drv->instance_size);
if (bs->opaque == NULL && drv->instance_size > 0)
return -1;
ret = drv->bdrv_open(bs, filename);
if (ret < 0) {
qemu_free(bs->opaque);
return -1;
}
#ifndef _WIN32
if (bs->is_temporary) {
unlink(filename);
}
#endif
if (bs->backing_file[0] != '\0' && drv->bdrv_is_allocated) {
/* if there is a backing file, use it */
bs->backing_hd = bdrv_new("");
if (!bs->backing_hd) {
fail:
bdrv_close(bs);
return -1;
}
if (bdrv_open(bs->backing_hd, bs->backing_file, 0) < 0)
goto fail;
}
bs->inserted = 1;
/* call the change callback */
if (bs->change_cb)
bs->change_cb(bs->change_opaque);
return 0;
}
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);
}
if (bs->inserted) {
if (bs->backing_hd)
bdrv_delete(bs->backing_hd);
bs->drv->bdrv_close(bs);
qemu_free(bs->opaque);
#ifdef _WIN32
if (bs->is_temporary) {
unlink(bs->filename);
}
#endif
bs->opaque = NULL;
bs->drv = NULL;
bs->inserted = 0;
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;
/* call the change callback */
if (bs->change_cb)
bs->change_cb(bs->change_opaque);
}
}
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;
void bdrv_delete(BlockDriverState *bs)
{
/* XXX: remove the driver list */
bdrv_close(bs);
qemu_free(bs);
}
/* commit COW file into the raw image */
int bdrv_commit(BlockDriverState *bs)
{
int64_t i;
uint8_t *cow_bitmap;
int n, j;
unsigned char sector[512];
if (!bs->cow_bitmap) {
fprintf(stderr, "Already committed to %s\n", bs->filename);
return 0;
}
if (!bs->inserted)
return -ENOENT;
if (bs->read_only) {
fprintf(stderr, "Can't commit to %s: read-only\n", bs->filename);
return -1;
return -EACCES;
}
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;
}
if (!bs->backing_hd) {
return -ENOTSUP;
}
for (i = 0; i < bs->total_sectors;) {
if (bs->drv->bdrv_is_allocated(bs, i, 65536, &n)) {
for(j = 0; j < n; j++) {
if (bdrv_read(bs, i, sector, 1) != 0) {
return -EIO;
}
if (bdrv_write(bs->backing_hd, i, sector, 1) != 0) {
return -EIO;
}
i++;
}
} else {
i += n;
}
}
fprintf(stderr, "Committed snapshot to %s\n", bs->filename);
return 0;
}
@@ -255,28 +272,33 @@ int bdrv_commit(BlockDriverState *bs)
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;
}
int ret, n;
BlockDriver *drv = bs->drv;
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;
if (!bs->inserted)
return -1;
while (nb_sectors > 0) {
if (sector_num == 0 && bs->boot_sector_enabled) {
memcpy(buf, bs->boot_sector_data, 512);
n = 1;
} else if (bs->backing_hd) {
if (drv->bdrv_is_allocated(bs, sector_num, nb_sectors, &n)) {
ret = drv->bdrv_read(bs, sector_num, buf, n);
if (ret < 0)
return -1;
} else {
/* read from the base image */
ret = bdrv_read(bs->backing_hd, sector_num, buf, n);
if (ret < 0)
return -1;
}
} else {
ret = drv->bdrv_read(bs, sector_num, buf, nb_sectors);
if (ret < 0)
return -1;
/* no need to loop */
break;
}
nb_sectors -= n;
sector_num += n;
@@ -289,38 +311,290 @@ int bdrv_read(BlockDriverState *bs, int64_t sector_num,
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->inserted)
return -1;
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;
return bs->drv->bdrv_write(bs, sector_num, buf, nb_sectors);
}
void bdrv_get_geometry(BlockDriverState *bs, int64_t *nb_sectors_ptr)
{
*nb_sectors_ptr = bs->total_sectors;
}
/* force a given boot sector. */
void bdrv_set_boot_sector(BlockDriverState *bs, const uint8_t *data, int size)
{
bs->boot_sector_enabled = 1;
if (size > 512)
size = 512;
memcpy(bs->boot_sector_data, data, size);
memset(bs->boot_sector_data + size, 0, 512 - size);
}
void bdrv_set_geometry_hint(BlockDriverState *bs,
int cyls, int heads, int secs)
{
bs->cyls = cyls;
bs->heads = heads;
bs->secs = secs;
}
void bdrv_set_type_hint(BlockDriverState *bs, int type)
{
bs->type = type;
bs->removable = ((type == BDRV_TYPE_CDROM ||
type == BDRV_TYPE_FLOPPY));
}
void bdrv_get_geometry_hint(BlockDriverState *bs,
int *pcyls, int *pheads, int *psecs)
{
*pcyls = bs->cyls;
*pheads = bs->heads;
*psecs = bs->secs;
}
int bdrv_get_type_hint(BlockDriverState *bs)
{
return bs->type;
}
int bdrv_is_removable(BlockDriverState *bs)
{
return bs->removable;
}
int bdrv_is_read_only(BlockDriverState *bs)
{
return bs->read_only;
}
int bdrv_is_inserted(BlockDriverState *bs)
{
return bs->inserted;
}
int bdrv_is_locked(BlockDriverState *bs)
{
return bs->locked;
}
void bdrv_set_locked(BlockDriverState *bs, int locked)
{
bs->locked = locked;
}
void bdrv_set_change_cb(BlockDriverState *bs,
void (*change_cb)(void *opaque), void *opaque)
{
bs->change_cb = change_cb;
bs->change_opaque = opaque;
}
int bdrv_is_encrypted(BlockDriverState *bs)
{
if (bs->backing_hd && bs->backing_hd->encrypted)
return 1;
return bs->encrypted;
}
int bdrv_set_key(BlockDriverState *bs, const char *key)
{
int ret;
if (bs->backing_hd && bs->backing_hd->encrypted) {
ret = bdrv_set_key(bs->backing_hd, key);
if (ret < 0)
return ret;
if (!bs->encrypted)
return 0;
}
if (!bs->encrypted || !bs->drv || !bs->drv->bdrv_set_key)
return -1;
return bs->drv->bdrv_set_key(bs, key);
}
void bdrv_get_format(BlockDriverState *bs, char *buf, int buf_size)
{
if (!bs->inserted || !bs->drv) {
buf[0] = '\0';
} else {
pstrcpy(buf, buf_size, bs->drv->format_name);
}
}
void bdrv_iterate_format(void (*it)(void *opaque, const char *name),
void *opaque)
{
BlockDriver *drv;
for (drv = first_drv; drv != NULL; drv = drv->next) {
it(opaque, drv->format_name);
}
}
BlockDriverState *bdrv_find(const char *name)
{
BlockDriverState *bs;
for (bs = bdrv_first; bs != NULL; bs = bs->next) {
if (!strcmp(name, bs->device_name))
return bs;
}
return NULL;
}
void bdrv_iterate(void (*it)(void *opaque, const char *name), void *opaque)
{
BlockDriverState *bs;
for (bs = bdrv_first; bs != NULL; bs = bs->next) {
it(opaque, bs->device_name);
}
}
const char *bdrv_get_device_name(BlockDriverState *bs)
{
return bs->device_name;
}
void bdrv_info(void)
{
BlockDriverState *bs;
for (bs = bdrv_first; bs != NULL; bs = bs->next) {
term_printf("%s:", bs->device_name);
term_printf(" type=");
switch(bs->type) {
case BDRV_TYPE_HD:
term_printf("hd");
break;
case BDRV_TYPE_CDROM:
term_printf("cdrom");
break;
case BDRV_TYPE_FLOPPY:
term_printf("floppy");
break;
}
term_printf(" removable=%d", bs->removable);
if (bs->removable) {
term_printf(" locked=%d", bs->locked);
}
if (bs->inserted) {
term_printf(" file=%s", bs->filename);
if (bs->backing_file[0] != '\0')
term_printf(" backing_file=%s", bs->backing_file);
term_printf(" ro=%d", bs->read_only);
term_printf(" drv=%s", bs->drv->format_name);
if (bs->encrypted)
term_printf(" encrypted");
} else {
term_printf(" [not inserted]");
}
term_printf("\n");
}
}
/**************************************************************/
/* RAW block driver */
typedef struct BDRVRawState {
int fd;
} BDRVRawState;
static int raw_probe(const uint8_t *buf, int buf_size, const char *filename)
{
return 1; /* maybe */
}
static int raw_open(BlockDriverState *bs, const char *filename)
{
BDRVRawState *s = bs->opaque;
int fd;
int64_t size;
fd = open(filename, O_RDWR | O_BINARY | O_LARGEFILE);
if (fd < 0) {
fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE);
if (fd < 0)
return -1;
bs->read_only = 1;
}
size = lseek(fd, 0, SEEK_END);
bs->total_sectors = size / 512;
s->fd = fd;
return 0;
}
static int raw_read(BlockDriverState *bs, int64_t sector_num,
uint8_t *buf, int nb_sectors)
{
BDRVRawState *s = bs->opaque;
int ret;
lseek(s->fd, sector_num * 512, SEEK_SET);
ret = read(s->fd, buf, nb_sectors * 512);
if (ret != nb_sectors * 512)
return -1;
return 0;
}
static int raw_write(BlockDriverState *bs, int64_t sector_num,
const uint8_t *buf, int nb_sectors)
{
BDRVRawState *s = bs->opaque;
int ret;
lseek(s->fd, sector_num * 512, SEEK_SET);
ret = write(s->fd, buf, nb_sectors * 512);
if (ret != nb_sectors * 512)
return -1;
return 0;
}
static void raw_close(BlockDriverState *bs)
{
BDRVRawState *s = bs->opaque;
close(s->fd);
}
static int raw_create(const char *filename, int64_t total_size,
const char *backing_file, int flags)
{
int fd;
if (flags || backing_file)
return -ENOTSUP;
fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE,
0644);
if (fd < 0)
return -EIO;
ftruncate(fd, total_size * 512);
close(fd);
return 0;
}
BlockDriver bdrv_raw = {
"raw",
sizeof(BDRVRawState),
raw_probe,
raw_open,
raw_read,
raw_write,
raw_close,
raw_create,
};
void bdrv_init(void)
{
bdrv_register(&bdrv_raw);
#ifndef _WIN32
bdrv_register(&bdrv_cow);
#endif
bdrv_register(&bdrv_qcow);
bdrv_register(&bdrv_vmdk);
bdrv_register(&bdrv_cloop);
}

77
block_int.h Normal file
View File

@@ -0,0 +1,77 @@
/*
* 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.
*/
#ifndef BLOCK_INT_H
#define BLOCK_INT_H
struct BlockDriver {
const char *format_name;
int instance_size;
int (*bdrv_probe)(const uint8_t *buf, int buf_size, const char *filename);
int (*bdrv_open)(BlockDriverState *bs, const char *filename);
int (*bdrv_read)(BlockDriverState *bs, int64_t sector_num,
uint8_t *buf, int nb_sectors);
int (*bdrv_write)(BlockDriverState *bs, int64_t sector_num,
const uint8_t *buf, int nb_sectors);
void (*bdrv_close)(BlockDriverState *bs);
int (*bdrv_create)(const char *filename, int64_t total_sectors,
const char *backing_file, int flags);
int (*bdrv_is_allocated)(BlockDriverState *bs, int64_t sector_num,
int nb_sectors, int *pnum);
int (*bdrv_set_key)(BlockDriverState *bs, const char *key);
struct BlockDriver *next;
};
struct BlockDriverState {
int64_t total_sectors;
int read_only; /* if true, the media is read only */
int inserted; /* if true, the media is present */
int removable; /* if true, the media can be removed */
int locked; /* if true, the media cannot temporarily be ejected */
int encrypted; /* if true, the media is encrypted */
/* event callback when inserting/removing */
void (*change_cb)(void *opaque);
void *change_opaque;
BlockDriver *drv;
void *opaque;
int boot_sector_enabled;
uint8_t boot_sector_data[512];
char filename[1024];
char backing_file[1024]; /* if non zero, the image is a diff of
this file image */
int is_temporary;
BlockDriverState *backing_hd;
/* NOTE: the following infos are only hints for real hardware
drivers. They are not used by the block driver */
int cyls, heads, secs;
int type;
char device_name[32];
BlockDriverState *next;
};
#endif /* BLOCK_INT_H */

134
bswap.h
View File

@@ -43,14 +43,6 @@
#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);
@@ -81,4 +73,130 @@ static inline void bswap64s(uint64_t *s)
*s = bswap64(*s);
}
#if defined(WORDS_BIGENDIAN)
#define be_bswap(v, size) (v)
#define le_bswap(v, size) bswap ## size(v)
#define be_bswaps(v, size)
#define le_bswaps(p, size) *p = bswap ## size(*p);
#else
#define le_bswap(v, size) (v)
#define be_bswap(v, size) bswap ## size(v)
#define le_bswaps(v, size)
#define be_bswaps(p, size) *p = bswap ## size(*p);
#endif
#define CPU_CONVERT(endian, size, type)\
static inline type endian ## size ## _to_cpu(type v)\
{\
return endian ## _bswap(v, size);\
}\
\
static inline type cpu_to_ ## endian ## size(type v)\
{\
return endian ## _bswap(v, size);\
}\
\
static inline void endian ## size ## _to_cpus(type *p)\
{\
endian ## _bswaps(p, size)\
}\
\
static inline void cpu_to_ ## endian ## size ## s(type *p)\
{\
endian ## _bswaps(p, size)\
}\
\
static inline type endian ## size ## _to_cpup(const type *p)\
{\
return endian ## size ## _to_cpu(*p);\
}\
\
static inline void cpu_to_ ## endian ## size ## w(type *p, type v)\
{\
*p = cpu_to_ ## endian ## size(v);\
}
CPU_CONVERT(be, 16, uint16_t)
CPU_CONVERT(be, 32, uint32_t)
CPU_CONVERT(be, 64, uint64_t)
CPU_CONVERT(le, 16, uint16_t)
CPU_CONVERT(le, 32, uint32_t)
CPU_CONVERT(le, 64, uint64_t)
/* unaligned versions (optimized for frequent unaligned accesses)*/
#if defined(__i386__) || defined(__powerpc__)
#define cpu_to_le16wu(p, v) cpu_to_le16w(p, v)
#define cpu_to_le32wu(p, v) cpu_to_le32w(p, v)
#define le16_to_cpupu(p) le16_to_cpup(p)
#define le32_to_cpupu(p) le32_to_cpup(p)
#define cpu_to_be16wu(p, v) cpu_to_be16w(p, v)
#define cpu_to_be32wu(p, v) cpu_to_be32w(p, v)
#else
static inline void cpu_to_le16wu(uint16_t *p, uint16_t v)
{
uint8_t *p1 = (uint8_t *)p;
p1[0] = v;
p1[1] = v >> 8;
}
static inline void cpu_to_le32wu(uint32_t *p, uint32_t v)
{
uint8_t *p1 = (uint8_t *)p;
p1[0] = v;
p1[1] = v >> 8;
p1[2] = v >> 16;
p1[3] = v >> 24;
}
static inline uint16_t le16_to_cpupu(const uint16_t *p)
{
const uint8_t *p1 = (const uint8_t *)p;
return p1[0] | (p1[1] << 8);
}
static inline uint32_t le32_to_cpupu(const uint32_t *p)
{
const uint8_t *p1 = (const uint8_t *)p;
return p1[0] | (p1[1] << 8) | (p1[2] << 16) | (p1[3] << 24);
}
static inline void cpu_to_be16wu(uint16_t *p, uint16_t v)
{
uint8_t *p1 = (uint8_t *)p;
p1[0] = v >> 8;
p1[1] = v;
}
static inline void cpu_to_be32wu(uint32_t *p, uint32_t v)
{
uint8_t *p1 = (uint8_t *)p;
p1[0] = v >> 24;
p1[1] = v >> 16;
p1[2] = v >> 8;
p1[3] = v;
}
#endif
#ifdef WORDS_BIGENDIAN
#define cpu_to_32wu cpu_to_be32wu
#else
#define cpu_to_32wu cpu_to_le32wu
#endif
#undef le_bswap
#undef be_bswap
#undef le_bswaps
#undef be_bswaps
#endif /* BSWAP_H */

269
configure vendored
View File

@@ -17,7 +17,7 @@ TMPE="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}"
TMPS="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}.S"
# default parameters
prefix="/usr/local"
prefix=""
interp_prefix="/usr/gnemul/qemu-%M"
static="no"
cross_prefix=""
@@ -27,7 +27,7 @@ ar="ar"
make="make"
strip="strip"
cpu=`uname -m`
target_list="i386-user i386 i386-softmmu arm-user sparc-user"
target_list="i386-user i386 i386-softmmu arm-user sparc-user ppc-user ppc-softmmu sparc-softmmu"
case "$cpu" in
i386|i486|i586|i686|i86pc|BePC)
cpu="i386"
@@ -59,37 +59,57 @@ case "$cpu" in
m68k)
cpu="m68k"
;;
x86_64|amd64)
cpu="amd64"
;;
*)
cpu="unknown"
;;
esac
gprof="no"
bigendian="no"
mingw32="no"
EXESUF=""
gdbstub="yes"
slirp="yes"
adlib="no"
oss="no"
fmod="no"
fmod_lib=""
fmod_inc=""
# OS specific
targetos=`uname -s`
case $targetos in
*) ;;
MINGW32*)
mingw32="yes"
;;
FreeBSD)
bsd="yes"
oss="yes"
;;
NetBSD)
bsd="yes"
oss="yes"
;;
OpenBSD)
bsd="yes"
oss="yes"
;;
Darwin)
bsd="yes"
darwin="yes"
;;
*)
oss="yes"
;;
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
if [ "$bsd" = "yes" ] ; then
if [ ! "$darwin" = "yes" ] ; then
make="gmake"
fi
target_list="i386-softmmu ppc-softmmu sparc-softmmu"
fi
# find source path
@@ -133,6 +153,18 @@ for opt do
;;
--disable-sdl) sdl="no"
;;
--enable-fmod) fmod="yes"
;;
--fmod-lib=*) fmod_lib=${opt#--fmod-lib=}
;;
--fmod-inc=*) fmod_inc=${opt#--fmod-inc=}
;;
--enable-mingw32) mingw32="yes" ; cross_prefix="i386-mingw32-"
;;
--disable-slirp) slirp="no"
;;
--enable-adlib) adlib="yes"
;;
esac
done
@@ -145,6 +177,13 @@ cc="${cross_prefix}${cc}"
ar="${cross_prefix}${ar}"
strip="${cross_prefix}${strip}"
if test "$mingw32" = "yes" ; then
target_list="i386-softmmu ppc-softmmu sparc-softmmu"
EXESUF=".exe"
gdbstub="no"
oss="no"
fi
if test -z "$cross_prefix" ; then
# ---
@@ -183,6 +222,57 @@ if $cc -fno-reorder-blocks -fno-optimize-sibling-calls -o $TMPO $TMPC 2> /dev/nu
have_gcc3_options="yes"
fi
##########################################
# SDL probe
sdl_too_old=no
if test -z "$sdl" ; then
sdl_config="sdl-config"
sdl=no
sdl_static=no
if test "$mingw32" = "yes" -a ! -z "$cross_prefix" ; then
# win32 cross compilation case
sdl_config="i386-mingw32msvc-sdl-config"
sdl=yes
else
# normal 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
if $cc -o $TMPE `$sdl_config --cflags 2> /dev/null` $TMPC `$sdl_config --libs 2> /dev/null` 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
# static link with sdl ?
if test "$sdl" = "yes" ; then
aa="no"
`$sdl_config --static-libs | grep \\\-laa > /dev/null` && aa="yes"
sdl_static_libs=`$sdl_config --static-libs`
if [ "$aa" = "yes" ] ; then
sdl_static_libs="$sdl_static_libs `aalib-config --static-libs`"
fi
if $cc -o $TMPE `$sdl_config --cflags 2> /dev/null` $TMPC $sdl_static_libs 2> /dev/null; then
sdl_static=yes
fi
fi # static link
fi # sdl compile test
fi # cross compilation
fi # -z $sdl
if test x"$1" = x"-h" -o x"$1" = x"--help" ; then
cat << EOF
@@ -203,18 +293,40 @@ 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 " --enable-mingw32 enable Win32 cross compilation with mingw32"
echo " --enable-fmod enable FMOD audio output driver"
echo " --fmod-lib path to FMOD library"
echo " --fmod-inc path to FMOD includes"
echo ""
echo "NOTE: The object files are build at the place where configure is launched"
exit 1
fi
if test "$mingw32" = "yes" ; then
if test -z "$prefix" ; then
prefix="/c/Program Files/Qemu"
fi
mandir="$prefix"
datadir="$prefix"
docdir="$prefix"
bindir="$prefix"
else
if test -z "$prefix" ; then
prefix="/usr/local"
fi
mandir="$prefix/share/man"
sharedir="$prefix/share/qemu"
datadir="$prefix/share/qemu"
docdir="$prefix/share/doc/qemu"
bindir="$prefix/bin"
fi
echo "Install prefix $prefix"
echo "BIOS directory $datadir"
echo "binary directory $bindir"
if test "$mingw32" = "no" ; then
echo "Manual directory $mandir"
echo "BIOS directory $sharedir"
echo "ELF interp prefix $interp_prefix"
fi
echo "Source path $source_path"
echo "C compiler $cc"
echo "make $make"
@@ -224,22 +336,36 @@ echo "target list $target_list"
echo "gprof enabled $gprof"
echo "static build $static"
echo "SDL support $sdl"
echo "SDL static link $sdl_static"
echo "mingw32 support $mingw32"
echo "Adlib support $adlib"
echo -n "FMOD support $fmod"
if test $fmod = "yes"; then
echo -n " (lib='$fmod_lib' include='$fmod_inc')"
fi
echo ""
if test $sdl_too_old = "yes"; then
echo "-> Your SDL version is too old - please upgrade to have FFplay/SDL support"
fi
if test "$sdl_static" = "no"; then
echo "WARNING: cannot compile statically with SDL - qemu-fast won't have a graphical output"
fi
config_mak="config-host.mak"
config_h="config-host.h"
echo "Creating $config_mak and $config_h"
#echo "Creating $config_mak and $config_h"
echo "# Automatically generated by configure - do not modify" > $config_mak
echo "/* Automatically generated by configure - do not modify */" > $config_h
echo "prefix=$prefix" >> $config_mak
echo "bindir=$bindir" >> $config_mak
echo "mandir=$mandir" >> $config_mak
echo "sharedir=$sharedir" >> $config_mak
echo "#define CONFIG_QEMU_SHAREDIR \"$sharedir\"" >> $config_h
echo "datadir=$datadir" >> $config_mak
echo "docdir=$docdir" >> $config_mak
echo "#define CONFIG_QEMU_SHAREDIR \"$datadir\"" >> $config_h
echo "MAKE=$make" >> $config_mak
echo "CC=$cc" >> $config_mak
if test "$have_gcc3_options" = "yes" ; then
@@ -250,9 +376,13 @@ 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
echo "EXESUF=$EXESUF" >> $config_mak
if test "$cpu" = "i386" ; then
echo "ARCH=i386" >> $config_mak
echo "#define HOST_I386 1" >> $config_h
elif test "$cpu" = "amd64" ; then
echo "ARCH=amd64" >> $config_mak
echo "#define HOST_AMD64 1" >> $config_h
elif test "$cpu" = "armv4l" ; then
echo "ARCH=arm" >> $config_mak
echo "#define HOST_ARM 1" >> $config_h
@@ -278,8 +408,8 @@ 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
echo "ARCH=m68k" >> $config_mak
echo "#define HOST_M68K 1" >> $config_h
else
echo "Unsupported CPU"
exit 1
@@ -288,19 +418,45 @@ if test "$bigendian" = "yes" ; then
echo "WORDS_BIGENDIAN=yes" >> $config_mak
echo "#define WORDS_BIGENDIAN 1" >> $config_h
fi
echo "#define HAVE_BYTESWAP_H 1" >> $config_h
if test "$mingw32" = "yes" ; then
echo "CONFIG_WIN32=yes" >> $config_mak
echo "#define CONFIG_WIN32 1" >> $config_h
elif test -f "/usr/include/byteswap.h" ; then
echo "#define HAVE_BYTESWAP_H 1" >> $config_h
fi
if test "$darwin" = "yes" ; then
echo "CONFIG_DARWIN=yes" >> $config_mak
echo "#define CONFIG_DARWIN 1" >> $config_h
fi
if test "$gdbstub" = "yes" ; then
echo "CONFIG_GDBSTUB=yes" >> $config_mak
echo "#define CONFIG_GDBSTUB 1" >> $config_h
fi
if test "$gprof" = "yes" ; then
echo "TARGET_GPROF=yes" >> $config_mak
echo "#define HAVE_GPROF 1" >> $config_h
fi
if test "$static" = "yes" ; then
echo "CONFIG_STATIC=yes" >> $config_mak
echo "#define CONFIG_STATIC 1" >> $config_h
fi
if test "$sdl" = "yes" ; then
echo "CONFIG_SDL=yes" >> $config_mak
echo "#define CONFIG_SDL 1" >> $config_h
echo "SDL_LIBS=`sdl-config --libs`" >> $config_mak
echo "SDL_CFLAGS=`sdl-config --cflags`" >> $config_mak
if test "$slirp" = "yes" ; then
echo "CONFIG_SLIRP=yes" >> $config_mak
echo "#define CONFIG_SLIRP 1" >> $config_h
fi
if test "$adlib" = "yes" ; then
echo "CONFIG_ADLIB=yes" >> $config_mak
echo "#define CONFIG_ADLIB 1" >> $config_h
fi
if test "$oss" = "yes" ; then
echo "CONFIG_OSS=yes" >> $config_mak
echo "#define CONFIG_OSS 1" >> $config_h
fi
if test "$fmod" = "yes" ; then
echo "CONFIG_FMOD=yes" >> $config_mak
echo "CONFIG_FMOD_LIB=$fmod_lib" >> $config_mak
echo "CONFIG_FMOD_INC=$fmod_inc" >> $config_mak
echo "#define CONFIG_FMOD 1" >> $config_h
fi
echo -n "VERSION=" >>$config_mak
head $source_path/VERSION >>$config_mak
@@ -312,6 +468,13 @@ echo "\"" >> $config_h
echo "SRC_PATH=$source_path" >> $config_mak
echo "TARGET_DIRS=$target_list" >> $config_mak
# XXX: suppress that
if [ "$bsd" = "yes" ] ; then
echo "#define O_LARGEFILE 0" >> $config_h
echo "#define MAP_ANONYMOUS MAP_ANON" >> $config_h
echo "#define _BSD 1" >> $config_h
fi
for target in $target_list; do
target_dir="$target"
@@ -320,6 +483,7 @@ config_h=$target_dir/config.h
target_cpu=`echo $target | cut -d '-' -f 1`
target_bigendian="no"
[ "$target_cpu" = "sparc" ] && target_bigendian=yes
[ "$target_cpu" = "ppc" ] && target_bigendian=yes
target_softmmu="no"
if expr $target : '.*-softmmu' > /dev/null ; then
target_softmmu="yes"
@@ -329,9 +493,16 @@ if expr $target : '.*-user' > /dev/null ; then
target_user_only="yes"
fi
echo "Creating $config_mak, $config_h and $target_dir/Makefile"
#echo "Creating $config_mak, $config_h and $target_dir/Makefile"
mkdir -p $target_dir
if test "$target" = "arm-user" ; then
mkdir -p $target_dir/nwfpe
fi
if test "$target_user_only" = "no" ; then
mkdir -p $target_dir/slirp
fi
ln -sf $source_path/Makefile.target $target_dir/Makefile
echo "# Automatically generated by configure - do not modify" > $config_mak
@@ -356,6 +527,10 @@ elif test "$target_cpu" = "sparc" ; then
echo "TARGET_ARCH=sparc" >> $config_mak
echo "#define TARGET_ARCH \"sparc\"" >> $config_h
echo "#define TARGET_SPARC 1" >> $config_h
elif test "$target_cpu" = "ppc" ; then
echo "TARGET_ARCH=ppc" >> $config_mak
echo "#define TARGET_ARCH \"ppc\"" >> $config_h
echo "#define TARGET_PPC 1" >> $config_h
else
echo "Unsupported target CPU"
exit 1
@@ -373,6 +548,30 @@ if test "$target_user_only" = "yes" ; then
echo "#define CONFIG_USER_ONLY 1" >> $config_h
fi
# sdl defines
if test "$target_user_only" = "no"; then
if test "$target_softmmu" = "no" -o "$static" = "yes"; then
sdl1=$sdl_static
else
sdl1=$sdl
fi
if test "$sdl1" = "yes" ; then
echo "#define CONFIG_SDL 1" >> $config_h
echo "CONFIG_SDL=yes" >> $config_mak
if test "$target_softmmu" = "no" -o "$static" = "yes"; then
echo "SDL_LIBS=$sdl_static_libs" >> $config_mak
else
echo "SDL_LIBS=`$sdl_config --libs`" >> $config_mak
fi
echo -n "SDL_CFLAGS=`$sdl_config --cflags`" >> $config_mak
if [ "${aa}" = "yes" ] ; then
echo -n " `aalib-config --cflags`" >> $config_mak ;
fi
echo "" >> $config_mak
fi
fi
done # for target in $targets
# build tree in object directory if source path is different from current one

731
console.c Normal file
View File

@@ -0,0 +1,731 @@
/*
* QEMU graphical console
*
* Copyright (c) 2004 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 "vl.h"
#define DEFAULT_BACKSCROLL 512
#define MAX_CONSOLES 12
#define RGBA(r, g, b, a) (((a) << 24) | ((r) << 16) | ((g) << 8) | (b))
#define RGB(r, g, b) RGBA(r, g, b, 0xff)
typedef struct TextCell {
uint8_t ch;
uint8_t bgcol:4;
uint8_t fgcol:4;
} TextCell;
#define MAX_ESC_PARAMS 3
enum TTYState {
TTY_STATE_NORM,
TTY_STATE_ESC,
TTY_STATE_CSI,
};
struct TextConsole {
int text_console; /* true if text console */
DisplayState *ds;
int g_width, g_height;
int width;
int height;
int total_height;
int backscroll_height;
int fgcol;
int bgcol;
int x, y;
int y_displayed;
int y_base;
TextCell *cells;
enum TTYState state;
int esc_params[MAX_ESC_PARAMS];
int nb_esc_params;
/* kbd read handler */
IOReadHandler *fd_read;
void *fd_opaque;
};
static TextConsole *active_console;
static TextConsole *consoles[MAX_CONSOLES];
static int nb_consoles = 0;
/* convert a RGBA color to a color index usable in graphic primitives */
static unsigned int vga_get_color(DisplayState *ds, unsigned int rgba)
{
unsigned int r, g, b, color;
switch(ds->depth) {
#if 0
case 8:
r = (rgba >> 16) & 0xff;
g = (rgba >> 8) & 0xff;
b = (rgba) & 0xff;
color = (rgb_to_index[r] * 6 * 6) +
(rgb_to_index[g] * 6) +
(rgb_to_index[b]);
break;
#endif
case 15:
r = (rgba >> 16) & 0xff;
g = (rgba >> 8) & 0xff;
b = (rgba) & 0xff;
color = ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3);
break;
case 16:
r = (rgba >> 16) & 0xff;
g = (rgba >> 8) & 0xff;
b = (rgba) & 0xff;
color = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
break;
case 32:
default:
color = rgba;
break;
}
return color;
}
static void vga_fill_rect (DisplayState *ds,
int posx, int posy, int width, int height, uint32_t color)
{
uint8_t *d, *d1;
int x, y, bpp;
bpp = (ds->depth + 7) >> 3;
d1 = ds->data +
ds->linesize * posy + bpp * posx;
for (y = 0; y < height; y++) {
d = d1;
switch(bpp) {
case 1:
for (x = 0; x < width; x++) {
*((uint8_t *)d) = color;
d++;
}
break;
case 2:
for (x = 0; x < width; x++) {
*((uint16_t *)d) = color;
d += 2;
}
break;
case 4:
for (x = 0; x < width; x++) {
*((uint32_t *)d) = color;
d += 4;
}
break;
}
d1 += ds->linesize;
}
}
/* copy from (xs, ys) to (xd, yd) a rectangle of size (w, h) */
static void vga_bitblt(DisplayState *ds, int xs, int ys, int xd, int yd, int w, int h)
{
const uint8_t *s;
uint8_t *d;
int wb, y, bpp;
bpp = (ds->depth + 7) >> 3;
wb = w * bpp;
if (yd <= ys) {
s = ds->data +
ds->linesize * ys + bpp * xs;
d = ds->data +
ds->linesize * yd + bpp * xd;
for (y = 0; y < h; y++) {
memmove(d, s, wb);
d += ds->linesize;
s += ds->linesize;
}
} else {
s = ds->data +
ds->linesize * (ys + h - 1) + bpp * xs;
d = ds->data +
ds->linesize * (yd + h - 1) + bpp * xd;
for (y = 0; y < h; y++) {
memmove(d, s, wb);
d -= ds->linesize;
s -= ds->linesize;
}
}
}
/***********************************************************/
/* basic char display */
#define FONT_HEIGHT 16
#define FONT_WIDTH 8
#include "vgafont.h"
#define cbswap_32(__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) ))
#ifdef WORDS_BIGENDIAN
#define PAT(x) x
#else
#define PAT(x) cbswap_32(x)
#endif
static const uint32_t dmask16[16] = {
PAT(0x00000000),
PAT(0x000000ff),
PAT(0x0000ff00),
PAT(0x0000ffff),
PAT(0x00ff0000),
PAT(0x00ff00ff),
PAT(0x00ffff00),
PAT(0x00ffffff),
PAT(0xff000000),
PAT(0xff0000ff),
PAT(0xff00ff00),
PAT(0xff00ffff),
PAT(0xffff0000),
PAT(0xffff00ff),
PAT(0xffffff00),
PAT(0xffffffff),
};
static const uint32_t dmask4[4] = {
PAT(0x00000000),
PAT(0x0000ffff),
PAT(0xffff0000),
PAT(0xffffffff),
};
static uint32_t color_table[8];
static const uint32_t color_table_rgb[8] = {
RGB(0x00, 0x00, 0x00),
RGB(0xff, 0x00, 0x00),
RGB(0x00, 0xff, 0x00),
RGB(0xff, 0xff, 0x00),
RGB(0x00, 0x00, 0xff),
RGB(0xff, 0x00, 0xff),
RGB(0x00, 0xff, 0xff),
RGB(0xff, 0xff, 0xff),
};
static inline unsigned int col_expand(DisplayState *ds, unsigned int col)
{
switch(ds->depth) {
case 8:
col |= col << 8;
col |= col << 16;
break;
case 15:
case 16:
col |= col << 16;
break;
default:
break;
}
return col;
}
static void vga_putcharxy(DisplayState *ds, int x, int y, int ch,
unsigned int fgcol, unsigned int bgcol)
{
uint8_t *d;
const uint8_t *font_ptr;
unsigned int font_data, linesize, xorcol, bpp;
int i;
bpp = (ds->depth + 7) >> 3;
d = ds->data +
ds->linesize * y * FONT_HEIGHT + bpp * x * FONT_WIDTH;
linesize = ds->linesize;
font_ptr = vgafont16 + FONT_HEIGHT * ch;
xorcol = bgcol ^ fgcol;
switch(ds->depth) {
case 8:
for(i = 0; i < FONT_HEIGHT; i++) {
font_data = *font_ptr++;
((uint32_t *)d)[0] = (dmask16[(font_data >> 4)] & xorcol) ^ bgcol;
((uint32_t *)d)[1] = (dmask16[(font_data >> 0) & 0xf] & xorcol) ^ bgcol;
d += linesize;
}
break;
case 16:
case 15:
for(i = 0; i < FONT_HEIGHT; i++) {
font_data = *font_ptr++;
((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;
d += linesize;
}
break;
case 32:
for(i = 0; i < FONT_HEIGHT; i++) {
font_data = *font_ptr++;
((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;
d += linesize;
}
break;
}
}
static void text_console_resize(TextConsole *s)
{
TextCell *cells, *c, *c1;
int w1, x, y, last_width;
last_width = s->width;
s->width = s->g_width / FONT_WIDTH;
s->height = s->g_height / FONT_HEIGHT;
w1 = last_width;
if (s->width < w1)
w1 = s->width;
cells = qemu_malloc(s->width * s->total_height * sizeof(TextCell));
for(y = 0; y < s->total_height; y++) {
c = &cells[y * s->width];
if (w1 > 0) {
c1 = &s->cells[y * last_width];
for(x = 0; x < w1; x++) {
*c++ = *c1++;
}
}
for(x = w1; x < s->width; x++) {
c->ch = ' ';
c->fgcol = 7;
c->bgcol = 0;
c++;
}
}
free(s->cells);
s->cells = cells;
}
static void update_xy(TextConsole *s, int x, int y)
{
TextCell *c;
int y1, y2;
if (s == active_console) {
y1 = (s->y_base + y) % s->total_height;
y2 = y1 - s->y_displayed;
if (y2 < 0)
y2 += s->total_height;
if (y2 < s->height) {
c = &s->cells[y1 * s->width + x];
vga_putcharxy(s->ds, x, y2, c->ch,
color_table[c->fgcol], color_table[c->bgcol]);
dpy_update(s->ds, x * FONT_WIDTH, y2 * FONT_HEIGHT,
FONT_WIDTH, FONT_HEIGHT);
}
}
}
static void console_show_cursor(TextConsole *s, int show)
{
TextCell *c;
int y, y1;
if (s == active_console) {
y1 = (s->y_base + s->y) % s->total_height;
y = y1 - s->y_displayed;
if (y < 0)
y += s->total_height;
if (y < s->height) {
c = &s->cells[y1 * s->width + s->x];
if (show) {
vga_putcharxy(s->ds, s->x, y, c->ch,
color_table[0], color_table[7]);
} else {
vga_putcharxy(s->ds, s->x, y, c->ch,
color_table[c->fgcol], color_table[c->bgcol]);
}
dpy_update(s->ds, s->x * FONT_WIDTH, y * FONT_HEIGHT,
FONT_WIDTH, FONT_HEIGHT);
}
}
}
static void console_refresh(TextConsole *s)
{
TextCell *c;
int x, y, y1;
if (s != active_console)
return;
vga_fill_rect(s->ds, 0, 0, s->ds->width, s->ds->height,
color_table[0]);
y1 = s->y_displayed;
for(y = 0; y < s->height; y++) {
c = s->cells + y1 * s->width;
for(x = 0; x < s->width; x++) {
vga_putcharxy(s->ds, x, y, c->ch,
color_table[c->fgcol], color_table[c->bgcol]);
c++;
}
if (++y1 == s->total_height)
y1 = 0;
}
dpy_update(s->ds, 0, 0, s->ds->width, s->ds->height);
console_show_cursor(s, 1);
}
static void console_scroll(int ydelta)
{
TextConsole *s;
int i, y1;
s = active_console;
if (!s || !s->text_console)
return;
if (ydelta > 0) {
for(i = 0; i < ydelta; i++) {
if (s->y_displayed == s->y_base)
break;
if (++s->y_displayed == s->total_height)
s->y_displayed = 0;
}
} else {
ydelta = -ydelta;
i = s->backscroll_height;
if (i > s->total_height - s->height)
i = s->total_height - s->height;
y1 = s->y_base - i;
if (y1 < 0)
y1 += s->total_height;
for(i = 0; i < ydelta; i++) {
if (s->y_displayed == y1)
break;
if (--s->y_displayed < 0)
s->y_displayed = s->total_height - 1;
}
}
console_refresh(s);
}
static void console_put_lf(TextConsole *s)
{
TextCell *c;
int x, y1;
s->x = 0;
s->y++;
if (s->y >= s->height) {
s->y = s->height - 1;
if (s->y_displayed == s->y_base) {
if (++s->y_displayed == s->total_height)
s->y_displayed = 0;
}
if (++s->y_base == s->total_height)
s->y_base = 0;
if (s->backscroll_height < s->total_height)
s->backscroll_height++;
y1 = (s->y_base + s->height - 1) % s->total_height;
c = &s->cells[y1 * s->width];
for(x = 0; x < s->width; x++) {
c->ch = ' ';
c->fgcol = s->fgcol;
c->bgcol = s->bgcol;
c++;
}
if (s == active_console && s->y_displayed == s->y_base) {
vga_bitblt(s->ds, 0, FONT_HEIGHT, 0, 0,
s->width * FONT_WIDTH,
(s->height - 1) * FONT_HEIGHT);
vga_fill_rect(s->ds, 0, (s->height - 1) * FONT_HEIGHT,
s->width * FONT_WIDTH, FONT_HEIGHT,
color_table[s->bgcol]);
dpy_update(s->ds, 0, 0,
s->width * FONT_WIDTH, s->height * FONT_HEIGHT);
}
}
}
static void console_putchar(TextConsole *s, int ch)
{
TextCell *c;
int y1, i, x;
switch(s->state) {
case TTY_STATE_NORM:
switch(ch) {
case '\r':
s->x = 0;
break;
case '\n':
console_put_lf(s);
break;
case 27:
s->state = TTY_STATE_ESC;
break;
default:
y1 = (s->y_base + s->y) % s->total_height;
c = &s->cells[y1 * s->width + s->x];
c->ch = ch;
c->fgcol = s->fgcol;
c->bgcol = s->bgcol;
update_xy(s, s->x, s->y);
s->x++;
if (s->x >= s->width)
console_put_lf(s);
break;
}
break;
case TTY_STATE_ESC:
if (ch == '[') {
for(i=0;i<MAX_ESC_PARAMS;i++)
s->esc_params[i] = 0;
s->nb_esc_params = 0;
s->state = TTY_STATE_CSI;
} else {
s->state = TTY_STATE_NORM;
}
break;
case TTY_STATE_CSI:
if (ch >= '0' && ch <= '9') {
if (s->nb_esc_params < MAX_ESC_PARAMS) {
s->esc_params[s->nb_esc_params] =
s->esc_params[s->nb_esc_params] * 10 + ch - '0';
}
} else {
s->nb_esc_params++;
if (ch == ';')
break;
s->state = TTY_STATE_NORM;
switch(ch) {
case 'D':
if (s->x > 0)
s->x--;
break;
case 'C':
if (s->x < (s->width - 1))
s->x++;
break;
case 'K':
/* clear to eol */
y1 = (s->y_base + s->y) % s->total_height;
for(x = s->x; x < s->width; x++) {
c = &s->cells[y1 * s->width + x];
c->ch = ' ';
c->fgcol = s->fgcol;
c->bgcol = s->bgcol;
c++;
update_xy(s, x, s->y);
}
break;
default:
break;
}
break;
}
}
}
void console_select(unsigned int index)
{
TextConsole *s;
if (index >= MAX_CONSOLES)
return;
s = consoles[index];
if (s) {
active_console = s;
if (s->text_console) {
if (s->g_width != s->ds->width ||
s->g_height != s->ds->height) {
s->g_width = s->ds->width;
s->g_height = s->ds->height;
text_console_resize(s);
}
console_refresh(s);
}
}
}
static int console_puts(CharDriverState *chr, const uint8_t *buf, int len)
{
TextConsole *s = chr->opaque;
int i;
console_show_cursor(s, 0);
for(i = 0; i < len; i++) {
console_putchar(s, buf[i]);
}
console_show_cursor(s, 1);
return len;
}
static void console_chr_add_read_handler(CharDriverState *chr,
IOCanRWHandler *fd_can_read,
IOReadHandler *fd_read, void *opaque)
{
TextConsole *s = chr->opaque;
s->fd_read = fd_read;
s->fd_opaque = opaque;
}
static void console_send_event(CharDriverState *chr, int event)
{
TextConsole *s = chr->opaque;
int i;
if (event == CHR_EVENT_FOCUS) {
for(i = 0; i < nb_consoles; i++) {
if (consoles[i] == s) {
console_select(i);
break;
}
}
}
}
/* called when an ascii key is pressed */
void kbd_put_keysym(int keysym)
{
TextConsole *s;
uint8_t buf[16], *q;
int c;
s = active_console;
if (!s || !s->text_console)
return;
switch(keysym) {
case QEMU_KEY_CTRL_UP:
console_scroll(-1);
break;
case QEMU_KEY_CTRL_DOWN:
console_scroll(1);
break;
case QEMU_KEY_CTRL_PAGEUP:
console_scroll(-10);
break;
case QEMU_KEY_CTRL_PAGEDOWN:
console_scroll(10);
break;
default:
if (s->fd_read) {
/* convert the QEMU keysym to VT100 key string */
q = buf;
if (keysym >= 0xe100 && keysym <= 0xe11f) {
*q++ = '\033';
*q++ = '[';
c = keysym - 0xe100;
if (c >= 10)
*q++ = '0' + (c / 10);
*q++ = '0' + (c % 10);
*q++ = '~';
} else if (keysym >= 0xe120 && keysym <= 0xe17f) {
*q++ = '\033';
*q++ = '[';
*q++ = keysym & 0xff;
} else {
*q++ = keysym;
}
s->fd_read(s->fd_opaque, buf, q - buf);
}
break;
}
}
TextConsole *graphic_console_init(DisplayState *ds)
{
TextConsole *s;
if (nb_consoles >= MAX_CONSOLES)
return NULL;
s = qemu_mallocz(sizeof(TextConsole));
if (!s) {
return NULL;
}
if (!active_console)
active_console = s;
s->ds = ds;
consoles[nb_consoles++] = s;
return s;
}
int is_active_console(TextConsole *s)
{
return s == active_console;
}
CharDriverState *text_console_init(DisplayState *ds)
{
CharDriverState *chr;
TextConsole *s;
int i;
static int color_inited;
chr = qemu_mallocz(sizeof(CharDriverState));
if (!chr)
return NULL;
s = graphic_console_init(ds);
if (!s) {
free(chr);
return NULL;
}
s->text_console = 1;
chr->opaque = s;
chr->chr_write = console_puts;
chr->chr_add_read_handler = console_chr_add_read_handler;
chr->chr_send_event = console_send_event;
if (!color_inited) {
color_inited = 1;
for(i = 0; i < 8; i++) {
color_table[i] = col_expand(s->ds,
vga_get_color(s->ds, color_table_rgb[i]));
}
}
s->y_displayed = 0;
s->y_base = 0;
s->total_height = DEFAULT_BACKSCROLL;
s->x = 0;
s->y = 0;
s->fgcol = 7;
s->bgcol = 0;
s->g_width = s->ds->width;
s->g_height = s->ds->height;
text_console_resize(s);
return chr;
}

430
cpu-all.h
View File

@@ -20,8 +20,152 @@
#ifndef CPU_ALL_H
#define CPU_ALL_H
#if defined(__arm__) || defined(__sparc__)
#define WORDS_ALIGNED
#endif
/* some important defines:
*
* WORDS_ALIGNED : if defined, the host cpu can only make word aligned
* memory accesses.
*
* WORDS_BIGENDIAN : if defined, the host cpu is big endian and
* otherwise little endian.
*
* (TARGET_WORDS_ALIGNED : same for target cpu (not supported yet))
*
* TARGET_WORDS_BIGENDIAN : same for target cpu
*/
#include "bswap.h"
#if defined(WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
#define BSWAP_NEEDED
#endif
#ifdef BSWAP_NEEDED
static inline uint16_t tswap16(uint16_t s)
{
return bswap16(s);
}
static inline uint32_t tswap32(uint32_t s)
{
return bswap32(s);
}
static inline uint64_t tswap64(uint64_t s)
{
return bswap64(s);
}
static inline void tswap16s(uint16_t *s)
{
*s = bswap16(*s);
}
static inline void tswap32s(uint32_t *s)
{
*s = bswap32(*s);
}
static inline void tswap64s(uint64_t *s)
{
*s = bswap64(*s);
}
#else
static inline uint16_t tswap16(uint16_t s)
{
return s;
}
static inline uint32_t tswap32(uint32_t s)
{
return s;
}
static inline uint64_t tswap64(uint64_t s)
{
return s;
}
static inline void tswap16s(uint16_t *s)
{
}
static inline void tswap32s(uint32_t *s)
{
}
static inline void tswap64s(uint64_t *s)
{
}
#endif
#if TARGET_LONG_SIZE == 4
#define tswapl(s) tswap32(s)
#define tswapls(s) tswap32s((uint32_t *)(s))
#else
#define tswapl(s) tswap64(s)
#define tswapls(s) tswap64s((uint64_t *)(s))
#endif
/* NOTE: arm is horrible as double 32 bit words are stored in big endian ! */
typedef union {
double d;
#if !defined(WORDS_BIGENDIAN) && !defined(__arm__)
struct {
uint32_t lower;
uint32_t upper;
} l;
#else
struct {
uint32_t upper;
uint32_t lower;
} l;
#endif
uint64_t ll;
} CPU_DoubleU;
/* CPU memory access without any memory or io remapping */
/*
* the generic syntax for the memory accesses is:
*
* load: ld{type}{sign}{size}{endian}_{access_type}(ptr)
*
* store: st{type}{size}{endian}_{access_type}(ptr, val)
*
* type is:
* (empty): integer access
* f : float access
*
* sign is:
* (empty): for floats or 32 bit size
* u : unsigned
* s : signed
*
* size is:
* b: 8 bits
* w: 16 bits
* l: 32 bits
* q: 64 bits
*
* endian is:
* (empty): target cpu endianness or 8 bit access
* r : reversed target cpu endianness (not implemented yet)
* be : big endian (not implemented yet)
* le : little endian (not implemented yet)
*
* access_type is:
* raw : host memory access
* user : user mode access using soft MMU
* kernel : kernel mode access using soft MMU
*/
static inline int ldub_raw(void *ptr)
{
return *(uint8_t *)ptr;
@@ -40,7 +184,7 @@ static inline void stb_raw(void *ptr, int v)
/* NOTE: on arm, putting 2 in /proc/sys/debug/alignment so that the
kernel handles unaligned load/stores may give better results, but
it is a system wide setting : bad */
#if defined(WORDS_BIGENDIAN) || defined(__arm__)
#if !defined(TARGET_WORDS_BIGENDIAN) && (defined(WORDS_BIGENDIAN) || defined(WORDS_ALIGNED))
/* conservative code for little endian unaligned accesses */
static inline int lduw_raw(void *ptr)
@@ -141,102 +285,149 @@ static inline void stfl_raw(void *ptr, float 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);
CPU_DoubleU u;
u.l.lower = ldl_raw(ptr);
u.l.upper = ldl_raw(ptr + 4);
return u.d;
}
static inline void stfq_raw(void *ptr, double v)
{
union {
double d;
uint32_t tab[2];
} u;
CPU_DoubleU u;
u.d = v;
stl_raw(ptr, u.tab[1]);
stl_raw(ptr + 4, u.tab[0]);
stl_raw(ptr, u.l.lower);
stl_raw(ptr + 4, u.l.upper);
}
#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)
#elif defined(TARGET_WORDS_BIGENDIAN) && (!defined(WORDS_BIGENDIAN) || defined(WORDS_ALIGNED))
static inline int lduw_raw(void *ptr)
{
#if defined(__i386__)
int val;
asm volatile ("movzwl %1, %0\n"
"xchgb %b0, %h0\n"
: "=q" (val)
: "m" (*(uint16_t *)ptr));
return val;
#else
uint8_t *b = (uint8_t *) ptr;
return (b[0]<<8|b[1]);
return ((b[0] << 8) | b[1]);
#endif
}
static inline int ldsw_raw(void *ptr)
{
int8_t *b = (int8_t *) ptr;
return (b[0]<<8|b[1]);
#if defined(__i386__)
int val;
asm volatile ("movzwl %1, %0\n"
"xchgb %b0, %h0\n"
: "=q" (val)
: "m" (*(uint16_t *)ptr));
return (int16_t)val;
#else
uint8_t *b = (uint8_t *) ptr;
return (int16_t)((b[0] << 8) | b[1]);
#endif
}
static inline int ldl_raw(void *ptr)
{
#if defined(__i386__) || defined(__x86_64__)
int val;
asm volatile ("movl %1, %0\n"
"bswap %0\n"
: "=r" (val)
: "m" (*(uint32_t *)ptr));
return val;
#else
uint8_t *b = (uint8_t *) ptr;
return (b[0]<<24|b[1]<<16|b[2]<<8|b[3]);
return (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | b[3];
#endif
}
static inline uint64_t ldq_raw(void *ptr)
{
uint32_t a,b;
a = ldl (ptr);
b = ldl (ptr+4);
a = ldl_raw(ptr);
b = ldl_raw(ptr+4);
return (((uint64_t)a<<32)|b);
}
static inline void stw_raw(void *ptr, int v)
{
#if defined(__i386__)
asm volatile ("xchgb %b0, %h0\n"
"movw %w0, %1\n"
: "=q" (v)
: "m" (*(uint16_t *)ptr), "0" (v));
#else
uint8_t *d = (uint8_t *) ptr;
d[0] = v >> 8;
d[1] = v;
#endif
}
static inline void stl_raw(void *ptr, int v)
{
#if defined(__i386__) || defined(__x86_64__)
asm volatile ("bswap %0\n"
"movl %0, %1\n"
: "=r" (v)
: "m" (*(uint32_t *)ptr), "0" (v));
#else
uint8_t *d = (uint8_t *) ptr;
d[0] = v >> 24;
d[1] = v >> 16;
d[2] = v >> 8;
d[3] = v;
#endif
}
static inline void stq_raw(void *ptr, uint64_t v)
{
stl (ptr, v);
stl (ptr+4, v >> 32);
stl_raw(ptr, v >> 32);
stl_raw(ptr + 4, v);
}
/* 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);
}
static inline double ldfq_raw(void *ptr)
{
CPU_DoubleU u;
u.l.upper = ldl_raw(ptr);
u.l.lower = ldl_raw(ptr + 4);
return u.d;
}
static inline void stfq_raw(void *ptr, double v)
{
CPU_DoubleU u;
u.d = v;
stl_raw(ptr, u.l.upper);
stl_raw(ptr + 4, u.l.lower);
}
#else
@@ -330,10 +521,14 @@ static inline void stfq_raw(void *ptr, double v)
#define lduw_kernel(p) lduw_raw(p)
#define ldsw_kernel(p) ldsw_raw(p)
#define ldl_kernel(p) ldl_raw(p)
#define ldfl_kernel(p) ldfl_raw(p)
#define ldfq_kernel(p) ldfq_raw(p)
#define stb_kernel(p, v) stb_raw(p, v)
#define stw_kernel(p, v) stw_raw(p, v)
#define stl_kernel(p, v) stl_raw(p, v)
#define stq_kernel(p, v) stq_raw(p, v)
#define stfl_kernel(p, v) stfl_raw(p, v)
#define stfq_kernel(p, vt) stfq_raw(p, v)
#endif /* defined(CONFIG_USER_ONLY) */
@@ -343,12 +538,12 @@ static inline void stfq_raw(void *ptr, double v)
#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;
extern unsigned long qemu_real_host_page_size;
extern unsigned long qemu_host_page_bits;
extern unsigned long qemu_host_page_size;
extern unsigned long qemu_host_page_mask;
#define HOST_PAGE_ALIGN(addr) (((addr) + host_page_size - 1) & host_page_mask)
#define HOST_PAGE_ALIGN(addr) (((addr) + qemu_host_page_size - 1) & qemu_host_page_mask)
/* same as PROT_xxx */
#define PAGE_READ 0x0001
@@ -374,7 +569,6 @@ void page_unprotect_range(uint8_t *data, unsigned long data_size);
#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)
@@ -383,7 +577,6 @@ void page_unprotect_range(uint8_t *data, unsigned long data_size);
#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)
@@ -392,9 +585,16 @@ void page_unprotect_range(uint8_t *data, unsigned long data_size);
#define cpu_init cpu_sparc_init
#define cpu_exec cpu_sparc_exec
#define cpu_gen_code cpu_sparc_gen_code
#define cpu_interrupt cpu_sparc_interrupt
#define cpu_signal_handler cpu_sparc_signal_handler
#elif defined(TARGET_PPC)
#define CPUState CPUPPCState
#define cpu_init cpu_ppc_init
#define cpu_exec cpu_ppc_exec
#define cpu_gen_code cpu_ppc_gen_code
#define cpu_signal_handler cpu_ppc_signal_handler
#else
#error unsupported target CPU
@@ -403,37 +603,125 @@ void page_unprotect_range(uint8_t *data, unsigned long data_size);
#endif /* SINGLE_CPU_DEFINES */
#define DEFAULT_GDBSTUB_PORT 1234
void cpu_dump_state(CPUState *env, FILE *f,
int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
int flags);
void cpu_abort(CPUState *env, const char *fmt, ...);
extern CPUState *cpu_single_env;
extern int code_copy_enabled;
#define CPU_INTERRUPT_EXIT 0x01 /* wants exit from main loop */
#define CPU_INTERRUPT_HARD 0x02 /* hardware interrupt pending */
#define CPU_INTERRUPT_EXIT 0x01 /* wants exit from main loop */
#define CPU_INTERRUPT_HARD 0x02 /* hardware interrupt pending */
#define CPU_INTERRUPT_EXITTB 0x04 /* exit the current TB (use for x86 a20 case) */
#define CPU_INTERRUPT_TIMER 0x08 /* internal timer exception pending */
void cpu_interrupt(CPUState *s, int mask);
void cpu_reset_interrupt(CPUState *env, int mask);
int cpu_breakpoint_insert(CPUState *env, uint32_t pc);
int cpu_breakpoint_remove(CPUState *env, uint32_t pc);
int cpu_breakpoint_insert(CPUState *env, target_ulong pc);
int cpu_breakpoint_remove(CPUState *env, target_ulong pc);
void cpu_single_step(CPUState *env, int enabled);
void cpu_reset(CPUState *s);
/* Return the physical page corresponding to a virtual one. Use it
only for debugging because no protection checks are done. Return -1
if no page found. */
target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr);
#define CPU_LOG_TB_OUT_ASM (1 << 0)
#define CPU_LOG_TB_IN_ASM (1 << 1)
#define CPU_LOG_TB_OP (1 << 2)
#define CPU_LOG_TB_OP_OPT (1 << 3)
#define CPU_LOG_INT (1 << 4)
#define CPU_LOG_EXEC (1 << 5)
#define CPU_LOG_PCALL (1 << 6)
#define CPU_LOG_IOPORT (1 << 7)
#define CPU_LOG_TB_CPU (1 << 8)
/* define log items */
typedef struct CPULogItem {
int mask;
const char *name;
const char *help;
} CPULogItem;
extern CPULogItem cpu_log_items[];
#define CPU_LOG_ALL 1
void cpu_set_log(int log_flags);
void cpu_set_log_filename(const char *filename);
int cpu_str_to_log_mask(const char *str);
/* IO ports API */
/* NOTE: as these functions may be even used when there is an isa
brige on non x86 targets, we always defined them */
#ifndef NO_CPU_IO_DEFS
void cpu_outb(CPUState *env, int addr, int val);
void cpu_outw(CPUState *env, int addr, int val);
void cpu_outl(CPUState *env, int addr, int val);
int cpu_inb(CPUState *env, int addr);
int cpu_inw(CPUState *env, int addr);
int cpu_inl(CPUState *env, int addr);
#endif
/* memory API */
typedef void CPUWriteMemoryFunc(uint32_t addr, uint32_t value);
typedef uint32_t CPUReadMemoryFunc(uint32_t addr);
extern int phys_ram_size;
extern int phys_ram_fd;
extern uint8_t *phys_ram_base;
extern uint8_t *phys_ram_dirty;
void cpu_register_physical_memory(unsigned long start_addr, unsigned long size,
long phys_offset);
/* physical memory access */
#define IO_MEM_NB_ENTRIES 256
#define TLB_INVALID_MASK (1 << 3)
#define IO_MEM_SHIFT 4
#define IO_MEM_RAM (0 << IO_MEM_SHIFT) /* hardcoded offset */
#define IO_MEM_ROM (1 << IO_MEM_SHIFT) /* hardcoded offset */
#define IO_MEM_UNASSIGNED (2 << IO_MEM_SHIFT)
#define IO_MEM_CODE (3 << IO_MEM_SHIFT) /* used internally, never use directly */
#define IO_MEM_NOTDIRTY (4 << IO_MEM_SHIFT) /* used internally, never use directly */
typedef void CPUWriteMemoryFunc(void *opaque, target_phys_addr_t addr, uint32_t value);
typedef uint32_t CPUReadMemoryFunc(void *opaque, target_phys_addr_t addr);
void cpu_register_physical_memory(target_phys_addr_t start_addr,
unsigned long size,
unsigned long phys_offset);
int cpu_register_io_memory(int io_index,
CPUReadMemoryFunc **mem_read,
CPUWriteMemoryFunc **mem_write);
CPUWriteMemoryFunc **mem_write,
void *opaque);
CPUWriteMemoryFunc **cpu_get_io_memory_write(int io_index);
CPUReadMemoryFunc **cpu_get_io_memory_read(int io_index);
/* 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);
void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
int len, int is_write);
static inline void cpu_physical_memory_read(target_phys_addr_t addr,
uint8_t *buf, int len)
{
cpu_physical_memory_rw(addr, buf, len, 0);
}
static inline void cpu_physical_memory_write(target_phys_addr_t addr,
const uint8_t *buf, int len)
{
cpu_physical_memory_rw(addr, (uint8_t *)buf, len, 1);
}
int cpu_memory_rw_debug(CPUState *env, target_ulong addr,
uint8_t *buf, int len, int is_write);
/* read dirty bit (return 0 or 1) */
static inline int cpu_physical_memory_is_dirty(target_ulong addr)
{
return phys_ram_dirty[addr >> TARGET_PAGE_BITS];
}
static inline void cpu_physical_memory_set_dirty(target_ulong addr)
{
phys_ram_dirty[addr >> TARGET_PAGE_BITS] = 1;
}
void cpu_physical_memory_reset_dirty(target_ulong start, target_ulong end);
#endif /* CPU_ALL_H */

View File

@@ -22,6 +22,55 @@
#include "config.h"
#include <setjmp.h>
#include <inttypes.h>
#include "osdep.h"
#ifndef TARGET_LONG_BITS
#error TARGET_LONG_BITS must be defined before including this header
#endif
#if defined(__alpha__) || defined (__ia64__) || defined(__x86_64__)
#define HOST_LONG_BITS 64
#else
#define HOST_LONG_BITS 32
#endif
#ifndef TARGET_PHYS_ADDR_BITS
#if TARGET_LONG_BITS >= HOST_LONG_BITS
#define TARGET_PHYS_ADDR_BITS TARGET_LONG_BITS
#else
#define TARGET_PHYS_ADDR_BITS HOST_LONG_BITS
#endif
#endif
#define TARGET_LONG_SIZE (TARGET_LONG_BITS / 8)
/* target_ulong is the type of a virtual address */
#if TARGET_LONG_SIZE == 4
typedef int32_t target_long;
typedef uint32_t target_ulong;
#elif TARGET_LONG_SIZE == 8
typedef int64_t target_long;
typedef uint64_t target_ulong;
#else
#error TARGET_LONG_SIZE undefined
#endif
/* target_phys_addr_t is the type of a physical address (its size can
be different from 'target_ulong'). We have sizeof(target_phys_addr)
= max(sizeof(unsigned long),
sizeof(size_of_target_physical_address)) because we must pass a
host pointer to memory operations in some cases */
#if TARGET_PHYS_ADDR_BITS == 32
typedef uint32_t target_phys_addr_t;
#elif TARGET_PHYS_ADDR_BITS == 64
typedef uint64_t target_phys_addr_t;
#else
#error TARGET_PHYS_ADDR_BITS undefined
#endif
#define HOST_LONG_SIZE (HOST_LONG_BITS / 8)
#define EXCP_INTERRUPT 256 /* async interruption */
#define EXCP_HLT 257 /* hlt instruction reached */
@@ -38,9 +87,9 @@ typedef struct CPUTLBEntry {
bit 3 : indicates that the entry is invalid
bit 2..0 : zero
*/
uint32_t address;
target_ulong address;
/* addend to virtual address to get physical address */
uint32_t addend;
target_phys_addr_t addend;
} CPUTLBEntry;
#endif

View File

@@ -21,6 +21,22 @@
#include "exec.h"
#include "disas.h"
#if !defined(CONFIG_SOFTMMU)
#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>
#endif
int tb_invalidated_flag;
//#define DEBUG_EXEC
//#define DEBUG_SIGNAL
@@ -32,6 +48,28 @@ void cpu_loop_exit(void)
}
#endif
/* exit the current TB from a signal handler. The host registers are
restored in a state compatible with the CPU emulator
*/
void cpu_resume_from_signal(CPUState *env1, void *puc)
{
#if !defined(CONFIG_SOFTMMU)
struct ucontext *uc = puc;
#endif
env = env1;
/* XXX: restore cpu registers saved in host registers */
#if !defined(CONFIG_SOFTMMU)
if (puc) {
/* XXX: use siglongjmp ? */
sigprocmask(SIG_SETMASK, &uc->uc_sigmask, NULL);
}
#endif
longjmp(env->jmp_env, 1);
}
/* main execution loop */
int cpu_exec(CPUState *env1)
@@ -85,37 +123,30 @@ int cpu_exec(CPUState *env1)
#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
env_to_regs();
/* 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));
@@ -131,6 +162,7 @@ int cpu_exec(CPUState *env1)
env->cpsr = psr & ~0xf0000000;
}
#elif defined(TARGET_SPARC)
#elif defined(TARGET_PPC)
#else
#error unsupported target CPU
#endif
@@ -139,6 +171,7 @@ int cpu_exec(CPUState *env1)
/* prepare setjmp context for exception handling */
for(;;) {
if (setjmp(env->jmp_env) == 0) {
env->current_tb = NULL;
/* if an exception is pending, we execute it here */
if (env->exception_index >= 0) {
if (env->exception_index >= EXCP_INTERRUPT) {
@@ -166,6 +199,13 @@ int cpu_exec(CPUState *env1)
env->exception_is_int,
env->error_code,
env->exception_next_eip, 0);
#elif defined(TARGET_PPC)
do_interrupt(env);
#elif defined(TARGET_SPARC)
do_interrupt(env->exception_index,
0,
env->error_code,
env->exception_next_pc, 0);
#endif
}
env->exception_index = -1;
@@ -184,12 +224,12 @@ int cpu_exec(CPUState *env1)
(env->eflags & IF_MASK) &&
!(env->hflags & HF_INHIBIT_IRQ_MASK)) {
int intno;
intno = cpu_x86_get_pic_interrupt(env);
if (loglevel) {
env->interrupt_request &= ~CPU_INTERRUPT_HARD;
intno = cpu_get_pic_interrupt(env);
if (loglevel & CPU_LOG_TB_IN_ASM) {
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__
@@ -198,7 +238,46 @@ int cpu_exec(CPUState *env1)
T0 = 0;
#endif
}
#elif defined(TARGET_PPC)
#if 0
if ((interrupt_request & CPU_INTERRUPT_RESET)) {
cpu_ppc_reset(env);
}
#endif
if (msr_ee != 0) {
if ((interrupt_request & CPU_INTERRUPT_HARD)) {
/* Raise it */
env->exception_index = EXCP_EXTERNAL;
env->error_code = 0;
do_interrupt(env);
env->interrupt_request &= ~CPU_INTERRUPT_HARD;
} else if ((interrupt_request & CPU_INTERRUPT_TIMER)) {
/* Raise it */
env->exception_index = EXCP_DECR;
env->error_code = 0;
do_interrupt(env);
env->interrupt_request &= ~CPU_INTERRUPT_TIMER;
}
}
#elif defined(TARGET_SPARC)
if (interrupt_request & CPU_INTERRUPT_HARD) {
do_interrupt(0, 0, 0, 0, 0);
env->interrupt_request &= ~CPU_INTERRUPT_HARD;
} else if (interrupt_request & CPU_INTERRUPT_TIMER) {
//do_interrupt(0, 0, 0, 0, 0);
env->interrupt_request &= ~CPU_INTERRUPT_TIMER;
}
#endif
if (interrupt_request & CPU_INTERRUPT_EXITTB) {
env->interrupt_request &= ~CPU_INTERRUPT_EXITTB;
/* ensure that no TB jump will be modified as
the program flow was changed */
#ifdef __sparc__
tmp_T0 = 0;
#else
T0 = 0;
#endif
}
if (interrupt_request & CPU_INTERRUPT_EXIT) {
env->interrupt_request &= ~CPU_INTERRUPT_EXIT;
env->exception_index = EXCP_INTERRUPT;
@@ -206,7 +285,7 @@ int cpu_exec(CPUState *env1)
}
}
#ifdef DEBUG_EXEC
if (loglevel) {
if (loglevel & CPU_LOG_EXEC) {
#if defined(TARGET_I386)
/* restore flags in standard format */
env->regs[R_EAX] = EAX;
@@ -218,14 +297,16 @@ int cpu_exec(CPUState *env1)
env->regs[R_EBP] = EBP;
env->regs[R_ESP] = ESP;
env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
cpu_x86_dump_state(env, logfile, X86_DUMP_CCOP);
cpu_dump_state(env, logfile, fprintf, 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);
cpu_dump_state(env, logfile, fprintf, 0);
env->cpsr &= ~0xf0000000;
#elif defined(TARGET_SPARC)
cpu_sparc_dump_state (env, logfile, 0);
cpu_dump_state (env, logfile, fprintf, 0);
#elif defined(TARGET_PPC)
cpu_dump_state(env, logfile, fprintf, 0);
#else
#error unsupported target CPU
#endif
@@ -244,25 +325,63 @@ int cpu_exec(CPUState *env1)
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;
flags = 0;
cs_base = (uint8_t *)env->npc;
pc = (uint8_t *) env->pc;
#elif defined(TARGET_PPC)
flags = 0;
cs_base = 0;
pc = (uint8_t *)env->nip;
#else
#error unsupported CPU
#endif
tb = tb_find(&ptb, (unsigned long)pc, (unsigned long)cs_base,
flags);
if (!tb) {
TranslationBlock **ptb1;
unsigned int h;
target_ulong phys_pc, phys_page1, phys_page2, virt_page2;
spin_lock(&tb_lock);
tb_invalidated_flag = 0;
regs_to_env(); /* XXX: do it just before cpu_gen_code() */
/* find translated block using physical mappings */
phys_pc = get_phys_addr_code(env, (unsigned long)pc);
phys_page1 = phys_pc & TARGET_PAGE_MASK;
phys_page2 = -1;
h = tb_phys_hash_func(phys_pc);
ptb1 = &tb_phys_hash[h];
for(;;) {
tb = *ptb1;
if (!tb)
goto not_found;
if (tb->pc == (unsigned long)pc &&
tb->page_addr[0] == phys_page1 &&
tb->cs_base == (unsigned long)cs_base &&
tb->flags == flags) {
/* check next page if needed */
if (tb->page_addr[1] != -1) {
virt_page2 = ((unsigned long)pc & TARGET_PAGE_MASK) +
TARGET_PAGE_SIZE;
phys_page2 = get_phys_addr_code(env, virt_page2);
if (tb->page_addr[1] == phys_page2)
goto found;
} else {
goto found;
}
}
ptb1 = &tb->phys_hash_next;
}
not_found:
/* if no translated code available, then translate it now */
tb = tb_alloc((unsigned long)pc);
if (!tb) {
/* flush must be done */
tb_flush();
tb_flush(env);
/* cannot fail at this point */
tb = tb_alloc((unsigned long)pc);
/* don't forget to invalidate previous TB info */
@@ -273,16 +392,35 @@ int cpu_exec(CPUState *env1)
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);
code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1));
/* check next page if needed */
virt_page2 = ((unsigned long)pc + tb->size - 1) & TARGET_PAGE_MASK;
phys_page2 = -1;
if (((unsigned long)pc & TARGET_PAGE_MASK) != virt_page2) {
phys_page2 = get_phys_addr_code(env, virt_page2);
}
tb_link_phys(tb, phys_pc, phys_page2);
found:
if (tb_invalidated_flag) {
/* as some TB could have been invalidated because
of memory exceptions while generating the code, we
must recompute the hash index here */
ptb = &tb_hash[tb_hash_func((unsigned long)pc)];
while (*ptb != NULL)
ptb = &(*ptb)->hash_next;
T0 = 0;
}
/* we add the TB in the virtual pc hash table */
*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) {
if (loglevel & CPU_LOG_EXEC) {
fprintf(logfile, "Trace 0x%08lx [0x%08lx] %s\n",
(long)tb->tc_ptr, (long)tb->pc,
lookup_symbol((void *)tb->pc));
@@ -292,9 +430,19 @@ int cpu_exec(CPUState *env1)
T0 = tmp_T0;
#endif
/* see if we can patch the calling TB. */
if (T0 != 0) {
if (T0 != 0
#if defined(TARGET_I386) && defined(USE_CODE_COPY)
&& (tb->cflags & CF_CODE_COPY) ==
(((TranslationBlock *)(T0 & ~3))->cflags & CF_CODE_COPY)
#endif
) {
spin_lock(&tb_lock);
tb_add_jump((TranslationBlock *)(T0 & ~3), T0 & 3, tb);
#if defined(USE_CODE_COPY)
/* propagates the FP use info */
((TranslationBlock *)(T0 & ~3))->cflags |=
(tb->cflags & CF_FP_USED);
#endif
spin_unlock(&tb_lock);
}
tc_ptr = tb->tc_ptr;
@@ -314,6 +462,80 @@ int cpu_exec(CPUState *env1)
: /* no outputs */
: "r" (gen_func)
: "r1", "r2", "r3", "r8", "r9", "r10", "r12", "r14");
#elif defined(TARGET_I386) && defined(USE_CODE_COPY)
{
if (!(tb->cflags & CF_CODE_COPY)) {
if ((tb->cflags & CF_FP_USED) && env->native_fp_regs) {
save_native_fp_state(env);
}
gen_func();
} else {
if ((tb->cflags & CF_FP_USED) && !env->native_fp_regs) {
restore_native_fp_state(env);
}
/* we work with native eflags */
CC_SRC = cc_table[CC_OP].compute_all();
CC_OP = CC_OP_EFLAGS;
asm(".globl exec_loop\n"
"\n"
"debug1:\n"
" pushl %%ebp\n"
" fs movl %10, %9\n"
" fs movl %11, %%eax\n"
" andl $0x400, %%eax\n"
" fs orl %8, %%eax\n"
" pushl %%eax\n"
" popf\n"
" fs movl %%esp, %12\n"
" fs movl %0, %%eax\n"
" fs movl %1, %%ecx\n"
" fs movl %2, %%edx\n"
" fs movl %3, %%ebx\n"
" fs movl %4, %%esp\n"
" fs movl %5, %%ebp\n"
" fs movl %6, %%esi\n"
" fs movl %7, %%edi\n"
" fs jmp *%9\n"
"exec_loop:\n"
" fs movl %%esp, %4\n"
" fs movl %12, %%esp\n"
" fs movl %%eax, %0\n"
" fs movl %%ecx, %1\n"
" fs movl %%edx, %2\n"
" fs movl %%ebx, %3\n"
" fs movl %%ebp, %5\n"
" fs movl %%esi, %6\n"
" fs movl %%edi, %7\n"
" pushf\n"
" popl %%eax\n"
" movl %%eax, %%ecx\n"
" andl $0x400, %%ecx\n"
" shrl $9, %%ecx\n"
" andl $0x8d5, %%eax\n"
" fs movl %%eax, %8\n"
" movl $1, %%eax\n"
" subl %%ecx, %%eax\n"
" fs movl %%eax, %11\n"
" fs movl %9, %%ebx\n" /* get T0 value */
" popl %%ebp\n"
:
: "m" (*(uint8_t *)offsetof(CPUState, regs[0])),
"m" (*(uint8_t *)offsetof(CPUState, regs[1])),
"m" (*(uint8_t *)offsetof(CPUState, regs[2])),
"m" (*(uint8_t *)offsetof(CPUState, regs[3])),
"m" (*(uint8_t *)offsetof(CPUState, regs[4])),
"m" (*(uint8_t *)offsetof(CPUState, regs[5])),
"m" (*(uint8_t *)offsetof(CPUState, regs[6])),
"m" (*(uint8_t *)offsetof(CPUState, regs[7])),
"m" (*(uint8_t *)offsetof(CPUState, cc_src)),
"m" (*(uint8_t *)offsetof(CPUState, tmp0)),
"a" (gen_func),
"m" (*(uint8_t *)offsetof(CPUState, df)),
"m" (*(uint8_t *)offsetof(CPUState, saved_esp))
: "%ecx", "%edx"
);
}
}
#else
gen_func();
#endif
@@ -329,11 +551,17 @@ int cpu_exec(CPUState *env1)
#endif
}
} else {
env_to_regs();
}
} /* for(;;) */
#if defined(TARGET_I386)
#if defined(USE_CODE_COPY)
if (env->native_fp_regs) {
save_native_fp_state(env);
}
#endif
/* restore flags in standard format */
env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
@@ -365,6 +593,7 @@ int cpu_exec(CPUState *env1)
#elif defined(TARGET_ARM)
env->cpsr = compute_cpsr();
#elif defined(TARGET_SPARC)
#elif defined(TARGET_PPC)
#else
#error unsupported target CPU
#endif
@@ -378,7 +607,20 @@ int cpu_exec(CPUState *env1)
return ret;
}
#if defined(TARGET_I386)
/* must only be called from the generated code as an exception can be
generated */
void tb_invalidate_page_range(target_ulong start, target_ulong end)
{
/* XXX: cannot enable it yet because it yields to MMU exception
where NIP != read address on PowerPC */
#if 0
target_ulong phys_addr;
phys_addr = get_phys_addr_code(env, start);
tb_invalidate_phys_page_range(phys_addr, phys_addr + end - start, 0);
#endif
}
#if defined(TARGET_I386) && defined(CONFIG_USER_ONLY)
void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector)
{
@@ -391,7 +633,7 @@ void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector)
cpu_x86_load_seg_cache(env, seg_reg, selector,
(uint8_t *)(selector << 4), 0xffff, 0);
} else {
load_seg(seg_reg, selector, 0);
load_seg(seg_reg, selector);
}
env = saved_env;
}
@@ -422,17 +664,7 @@ void cpu_x86_frstor(CPUX86State *s, uint8_t *ptr, int data32)
#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(CONFIG_SOFTMMU)
#if defined(TARGET_I386)
@@ -441,7 +673,8 @@ void cpu_x86_frstor(CPUX86State *s, uint8_t *ptr, int data32)
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)
int is_write, sigset_t *old_set,
void *puc)
{
TranslationBlock *tb;
int ret;
@@ -449,13 +682,14 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
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);
qemu_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)) {
if (is_write && page_unprotect(address, pc, puc)) {
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);
@@ -468,7 +702,7 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
if (tb) {
/* the PC is inside the translated code. It means that we have
a virtual CPU fault */
cpu_restore_state(tb, env, pc);
cpu_restore_state(tb, env, pc, puc);
}
if (ret == 1) {
#if 0
@@ -482,8 +716,7 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
} else {
/* activate soft MMU for this block */
env->hflags |= HF_SOFTMMU_MASK;
sigprocmask(SIG_SETMASK, old_set, NULL);
cpu_loop_exit();
cpu_resume_from_signal(env, puc);
}
/* never comes here */
return 1;
@@ -491,16 +724,73 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
#elif defined(TARGET_ARM)
static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
int is_write, sigset_t *old_set)
int is_write, sigset_t *old_set,
void *puc)
{
/* 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)
int is_write, sigset_t *old_set,
void *puc)
{
return 0;
/* XXX: locking issue */
if (is_write && page_unprotect(address, pc, puc)) {
return 1;
}
return 0;
}
#elif defined (TARGET_PPC)
static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
int is_write, sigset_t *old_set,
void *puc)
{
TranslationBlock *tb;
int ret;
#if 1
if (cpu_single_env)
env = cpu_single_env; /* XXX: find a correct solution for multithread */
#endif
#if defined(DEBUG_SIGNAL)
printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
pc, address, is_write, *(unsigned long *)old_set);
#endif
/* XXX: locking issue */
if (is_write && page_unprotect(address, pc, puc)) {
return 1;
}
/* see if it is an MMU fault */
ret = cpu_ppc_handle_mmu_fault(env, address, is_write, msr_pr, 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, puc);
}
if (ret == 1) {
#if 0
printf("PF exception: NIP=0x%08x error=0x%x %p\n",
env->nip, env->error_code, tb);
#endif
/* we restore the process signal mask as the sigreturn should
do it (XXX: use sigsetjmp) */
sigprocmask(SIG_SETMASK, old_set, NULL);
do_raise_exception_err(env->exception_index, env->error_code);
} else {
/* activate soft MMU for this block */
cpu_resume_from_signal(env, puc);
}
/* never comes here */
return 1;
}
#else
#error unsupported target CPU
@@ -508,12 +798,33 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
#if defined(__i386__)
#if defined(USE_CODE_COPY)
static void cpu_send_trap(unsigned long pc, int trap,
struct ucontext *uc)
{
TranslationBlock *tb;
if (cpu_single_env)
env = cpu_single_env; /* XXX: find a correct solution for multithread */
/* 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, uc);
}
sigprocmask(SIG_SETMASK, &uc->uc_sigmask, NULL);
raise_exception_err(trap, env->error_code);
}
#endif
int cpu_signal_handler(int host_signum, struct siginfo *info,
void *puc)
{
struct ucontext *uc = puc;
unsigned long pc;
int trapno;
#ifndef REG_EIP
/* for glibc 2.1 */
#define REG_EIP EIP
@@ -521,34 +832,105 @@ int cpu_signal_handler(int host_signum, struct siginfo *info,
#define REG_TRAPNO TRAPNO
#endif
pc = uc->uc_mcontext.gregs[REG_EIP];
trapno = uc->uc_mcontext.gregs[REG_TRAPNO];
#if defined(TARGET_I386) && defined(USE_CODE_COPY)
if (trapno == 0x00 || trapno == 0x05) {
/* send division by zero or bound exception */
cpu_send_trap(pc, trapno, uc);
return 1;
} else
#endif
return handle_cpu_signal(pc, (unsigned long)info->si_addr,
trapno == 0xe ?
(uc->uc_mcontext.gregs[REG_ERR] >> 1) & 1 : 0,
&uc->uc_sigmask, puc);
}
#elif defined(__x86_64__)
int cpu_signal_handler(int host_signum, struct siginfo *info,
void *puc)
{
struct ucontext *uc = puc;
unsigned long pc;
pc = uc->uc_mcontext.gregs[REG_RIP];
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);
&uc->uc_sigmask, puc);
}
#elif defined(__powerpc)
#elif defined(__powerpc__)
/***********************************************************************
* signal context platform-specific definitions
* From Wine
*/
#ifdef linux
/* All Registers access - only for local access */
# define REG_sig(reg_name, context) ((context)->uc_mcontext.regs->reg_name)
/* Gpr Registers access */
# define GPR_sig(reg_num, context) REG_sig(gpr[reg_num], context)
# define IAR_sig(context) REG_sig(nip, context) /* Program counter */
# define MSR_sig(context) REG_sig(msr, context) /* Machine State Register (Supervisor) */
# define CTR_sig(context) REG_sig(ctr, context) /* Count register */
# define XER_sig(context) REG_sig(xer, context) /* User's integer exception register */
# define LR_sig(context) REG_sig(link, context) /* Link register */
# define CR_sig(context) REG_sig(ccr, context) /* Condition register */
/* Float Registers access */
# define FLOAT_sig(reg_num, context) (((double*)((char*)((context)->uc_mcontext.regs+48*4)))[reg_num])
# define FPSCR_sig(context) (*(int*)((char*)((context)->uc_mcontext.regs+(48+32*2)*4)))
/* Exception Registers access */
# define DAR_sig(context) REG_sig(dar, context)
# define DSISR_sig(context) REG_sig(dsisr, context)
# define TRAP_sig(context) REG_sig(trap, context)
#endif /* linux */
#ifdef __APPLE__
# include <sys/ucontext.h>
typedef struct ucontext SIGCONTEXT;
/* All Registers access - only for local access */
# define REG_sig(reg_name, context) ((context)->uc_mcontext->ss.reg_name)
# define FLOATREG_sig(reg_name, context) ((context)->uc_mcontext->fs.reg_name)
# define EXCEPREG_sig(reg_name, context) ((context)->uc_mcontext->es.reg_name)
# define VECREG_sig(reg_name, context) ((context)->uc_mcontext->vs.reg_name)
/* Gpr Registers access */
# define GPR_sig(reg_num, context) REG_sig(r##reg_num, context)
# define IAR_sig(context) REG_sig(srr0, context) /* Program counter */
# define MSR_sig(context) REG_sig(srr1, context) /* Machine State Register (Supervisor) */
# define CTR_sig(context) REG_sig(ctr, context)
# define XER_sig(context) REG_sig(xer, context) /* Link register */
# define LR_sig(context) REG_sig(lr, context) /* User's integer exception register */
# define CR_sig(context) REG_sig(cr, context) /* Condition register */
/* Float Registers access */
# define FLOAT_sig(reg_num, context) FLOATREG_sig(fpregs[reg_num], context)
# define FPSCR_sig(context) ((double)FLOATREG_sig(fpscr, context))
/* Exception Registers access */
# define DAR_sig(context) EXCEPREG_sig(dar, context) /* Fault registers for coredump */
# define DSISR_sig(context) EXCEPREG_sig(dsisr, context)
# define TRAP_sig(context) EXCEPREG_sig(exception, context) /* number of powerpc exception taken */
#endif /* __APPLE__ */
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;
pc = IAR_sig(uc);
is_write = 0;
#if 0
/* ppc 4xx case */
if (regs->dsisr & 0x00800000)
if (DSISR_sig(uc) & 0x00800000)
is_write = 1;
#else
if (regs->trap != 0x400 && (regs->dsisr & 0x02000000))
if (TRAP_sig(uc) != 0x400 && (DSISR_sig(uc) & 0x02000000))
is_write = 1;
#endif
return handle_cpu_signal(pc, (unsigned long)info->si_addr,
is_write, &uc->uc_sigmask);
is_write, &uc->uc_sigmask, puc);
}
#elif defined(__alpha__)
@@ -578,7 +960,7 @@ int cpu_signal_handler(int host_signum, struct siginfo *info,
}
return handle_cpu_signal(pc, (unsigned long)info->si_addr,
is_write, &uc->uc_sigmask);
is_write, &uc->uc_sigmask, puc);
}
#elif defined(__sparc__)
@@ -610,7 +992,7 @@ int cpu_signal_handler(int host_signum, struct siginfo *info,
}
}
return handle_cpu_signal(pc, (unsigned long)info->si_addr,
is_write, sigmask);
is_write, sigmask, NULL);
}
#elif defined(__arm__)
@@ -644,7 +1026,7 @@ int cpu_signal_handler(int host_signum, struct siginfo *info,
is_write = 0;
return handle_cpu_signal(pc, (unsigned long)info->si_addr,
is_write,
&uc->uc_sigmask);
&uc->uc_sigmask, puc);
}
#else
@@ -652,3 +1034,5 @@ int cpu_signal_handler(int host_signum, struct siginfo *info,
#error host CPU specific signal handler needed
#endif
#endif /* !defined(CONFIG_SOFTMMU) */

View File

@@ -16,7 +16,9 @@
#define PARAMS(x) x
typedef void *PTR;
typedef uint64_t bfd_vma;
typedef int64_t bfd_signed_vma;
typedef uint8_t bfd_byte;
#define sprintf_vma(s,x) sprintf (s, "%0" PRIx64, x)
enum bfd_flavour {
bfd_target_unknown_flavour,
@@ -105,6 +107,9 @@ enum bfd_architecture
bfd_arch_i386, /* Intel 386 */
#define bfd_mach_i386_i386 0
#define bfd_mach_i386_i8086 1
#define bfd_mach_i386_i386_intel_syntax 2
#define bfd_mach_x86_64 3
#define bfd_mach_x86_64_intel_syntax 4
bfd_arch_we32k, /* AT&T WE32xxx */
bfd_arch_tahoe, /* CCI/Harris Tahoe */
bfd_arch_i860, /* Intel 860 */

86
disas.c
View File

@@ -1,12 +1,12 @@
/* 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"
#include "disas.h"
/* Filled in by elfload.c. Simplistic, but will do for now. */
unsigned int disas_num_syms;
@@ -140,9 +140,12 @@ void disas(FILE *out, void *code, unsigned long size, int is_host, int flags)
#else
disasm_info.endian = BFD_ENDIAN_LITTLE;
#endif
#ifdef __i386__
#if defined(__i386__)
disasm_info.mach = bfd_mach_i386_i386;
print_insn = print_insn_i386;
#elif defined(__x86_64__)
disasm_info.mach = bfd_mach_x86_64;
print_insn = print_insn_i386;
#elif defined(__powerpc__)
print_insn = print_insn_ppc;
#elif defined(__alpha__)
@@ -171,6 +174,8 @@ void disas(FILE *out, void *code, unsigned long size, int is_host, int flags)
print_insn = print_insn_arm;
#elif defined(TARGET_SPARC)
print_insn = print_insn_sparc;
#elif defined(TARGET_PPC)
print_insn = print_insn_ppc;
#else
fprintf(out, "Asm output not supported on this arch\n");
return;
@@ -214,3 +219,80 @@ const char *lookup_symbol(void *orig_addr)
}
return "";
}
#if !defined(CONFIG_USER_ONLY)
void term_vprintf(const char *fmt, va_list ap);
void term_printf(const char *fmt, ...);
static int monitor_disas_is_physical;
static int
monitor_read_memory (memaddr, myaddr, length, info)
bfd_vma memaddr;
bfd_byte *myaddr;
int length;
struct disassemble_info *info;
{
if (monitor_disas_is_physical) {
cpu_physical_memory_rw(memaddr, myaddr, length, 0);
} else {
cpu_memory_rw_debug(cpu_single_env, memaddr,myaddr, length, 0);
}
return 0;
}
static int monitor_fprintf(FILE *stream, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
term_vprintf(fmt, ap);
va_end(ap);
return 0;
}
void monitor_disas(target_ulong pc, int nb_insn, int is_physical, int flags)
{
int count, i;
struct disassemble_info disasm_info;
int (*print_insn)(bfd_vma pc, disassemble_info *info);
INIT_DISASSEMBLE_INFO(disasm_info, NULL, monitor_fprintf);
monitor_disas_is_physical = is_physical;
disasm_info.read_memory_func = monitor_read_memory;
disasm_info.buffer_vma = pc;
#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;
#elif defined(TARGET_PPC)
print_insn = print_insn_ppc;
#else
term_printf("Asm output not supported on this arch\n");
return;
#endif
for(i = 0; i < nb_insn; i++) {
term_printf("0x%08lx: ", (unsigned long)pc);
count = print_insn(pc, &disasm_info);
term_printf("\n");
if (count < 0)
break;
pc += count;
}
}
#endif

View File

@@ -3,6 +3,7 @@
/* Disassemble this for me please... (debugging). */
void disas(FILE *out, void *code, unsigned long size, int is_host, int flags);
void monitor_disas(target_ulong pc, int nb_insn, int is_physical, int flags);
/* Look up symbol for debugging purpose. Returns "" if unknown. */
const char *lookup_symbol(void *orig_addr);

View File

@@ -17,31 +17,62 @@
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#if !defined(__DYNGEN_EXEC_H__)
#define __DYNGEN_EXEC_H__
/* NOTE: standard headers should be used with special care at this
point because host CPU registers are used as global variables. Some
host headers do not allow that. */
#include <stddef.h>
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
/* XXX may be done for all 64 bits targets ? */
#if defined (__x86_64__)
typedef unsigned long uint64_t;
#else
typedef unsigned long long uint64_t;
#endif
typedef signed char int8_t;
typedef signed short int16_t;
typedef signed int int32_t;
#if defined (__x86_64__)
typedef signed long int64_t;
#else
typedef signed long long int64_t;
#endif
#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 INT8_MIN (-128)
#define INT16_MIN (-32767-1)
#define INT32_MIN (-2147483647-1)
#define INT64_MIN (-(int64_t)(9223372036854775807)-1)
#define INT8_MAX (127)
#define INT16_MAX (32767)
#define INT32_MAX (2147483647)
#define INT64_MAX ((int64_t)(9223372036854775807))
#define UINT8_MAX (255)
#define UINT16_MAX (65535)
#define UINT32_MAX (4294967295U)
#define UINT64_MAX ((uint64_t)(18446744073709551615))
typedef struct FILE FILE;
extern int fprintf(FILE *, const char *, ...);
extern int printf(const char *, ...);
#undef NULL
#define NULL 0
#if defined(_BSD) && !defined(__APPLE__)
#include <ieeefp.h>
#define FE_TONEAREST FP_RN
#define FE_DOWNWARD FP_RM
#define FE_UPWARD FP_RP
#define FE_TOWARDZERO FP_RZ
#define fesetround(x) fpsetround(x)
#else
#include <fenv.h>
#endif
#ifdef __i386__
#define AREG0 "ebp"
@@ -49,11 +80,21 @@ extern int printf(const char *, ...);
#define AREG2 "esi"
#define AREG3 "edi"
#endif
#ifdef __x86_64__
#define AREG0 "rbp"
#define AREG1 "rbx"
#define AREG2 "r12"
#define AREG3 "r13"
#define AREG4 "r14"
#define AREG5 "r15"
#endif
#ifdef __powerpc__
#define AREG0 "r27"
#define AREG1 "r24"
#define AREG2 "r25"
#define AREG3 "r26"
/* XXX: suppress this hack */
#if defined(CONFIG_USER_ONLY)
#define AREG4 "r16"
#define AREG5 "r17"
#define AREG6 "r18"
@@ -62,6 +103,7 @@ extern int printf(const char *, ...);
#define AREG9 "r21"
#define AREG10 "r22"
#define AREG11 "r23"
#endif
#define USE_INT_TO_FLOAT_HELPERS
#define BUGGY_GCC_DIV64
#endif
@@ -142,7 +184,7 @@ extern int printf(const char *, ...);
#define __hidden
#endif
#ifdef __alpha__
#if defined(__alpha__)
/* Suggested by Richard Henderson. This will result in code like
ldah $0,__op_param1($29) !gprelhigh
lda $0,__op_param1($0) !gprellow
@@ -155,17 +197,24 @@ extern int __op_param3 __hidden;
#define PARAM2 ({ int _r; asm("" : "=r"(_r) : "0" (&__op_param2)); _r; })
#define PARAM3 ({ int _r; asm("" : "=r"(_r) : "0" (&__op_param3)); _r; })
#else
#if defined(__APPLE__)
static int __op_param1, __op_param2, __op_param3;
#else
extern int __op_param1, __op_param2, __op_param3;
#endif
#define PARAM1 ((long)(&__op_param1))
#define PARAM2 ((long)(&__op_param2))
#define PARAM3 ((long)(&__op_param3))
#endif
#endif /* !defined(__alpha__) */
extern int __op_jmp0, __op_jmp1, __op_jmp2, __op_jmp3;
#ifdef __i386__
#define EXIT_TB() asm volatile ("ret")
#endif
#ifdef __x86_64__
#define EXIT_TB() asm volatile ("ret")
#endif
#ifdef __powerpc__
#define EXIT_TB() asm volatile ("blr")
#endif
@@ -188,3 +237,5 @@ extern int __op_jmp0, __op_jmp1, __op_jmp2, __op_jmp3;
#ifdef __mc68000
#define EXIT_TB() asm volatile ("rts")
#endif
#endif /* !defined(__DYNGEN_EXEC_H__) */

1696
dyngen.c

File diff suppressed because it is too large Load Diff

View File

@@ -27,6 +27,12 @@ static inline void flush_icache_range(unsigned long start, unsigned long stop)
}
#endif
#ifdef __x86_64__
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)
{

View File

@@ -56,9 +56,15 @@ struct TranslationBlock;
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 uint32_t gen_opc_npc[OPC_BUF_SIZE];
extern uint8_t gen_opc_cc_op[OPC_BUF_SIZE];
extern uint8_t gen_opc_instr_start[OPC_BUF_SIZE];
typedef void (GenOpFunc)(void);
typedef void (GenOpFunc1)(long);
typedef void (GenOpFunc2)(long, long);
typedef void (GenOpFunc3)(long, long, long);
#if defined(TARGET_I386)
void optimize_flags_init(void);
@@ -74,13 +80,24 @@ 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);
CPUState *env, unsigned long searched_pc,
void *puc);
int cpu_gen_code_copy(CPUState *env, struct TranslationBlock *tb,
int max_code_size, int *gen_code_size_ptr);
int cpu_restore_state_copy(struct TranslationBlock *tb,
CPUState *env, unsigned long searched_pc,
void *puc);
void cpu_resume_from_signal(CPUState *env1, void *puc);
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);
int page_unprotect(unsigned long address, unsigned long pc, void *puc);
void tb_invalidate_phys_page_range(target_ulong start, target_ulong end,
int is_cpu_write_access);
void tb_invalidate_page_range(target_ulong start, target_ulong end);
void tlb_flush_page(CPUState *env, target_ulong addr);
void tlb_flush(CPUState *env, int flush_global);
int tlb_set_page(CPUState *env, target_ulong vaddr,
target_phys_addr_t paddr, int prot,
int is_user, int is_softmmu);
#define CODE_GEN_MAX_SIZE 65536
#define CODE_GEN_ALIGN 16 /* must be >= of the size of a icache line */
@@ -88,23 +105,71 @@ void tlb_flush(CPUState *env);
#define CODE_GEN_HASH_BITS 15
#define CODE_GEN_HASH_SIZE (1 << CODE_GEN_HASH_BITS)
#define CODE_GEN_PHYS_HASH_BITS 15
#define CODE_GEN_PHYS_HASH_SIZE (1 << CODE_GEN_PHYS_HASH_BITS)
/* maximum total translate dcode allocated */
#define CODE_GEN_BUFFER_SIZE (2048 * 1024)
/* NOTE: the translated code area cannot be too big because on some
archs the range of "fast" function calls is limited. Here is a
summary of the ranges:
i386 : signed 32 bits
arm : signed 26 bits
ppc : signed 24 bits
sparc : signed 32 bits
alpha : signed 23 bits
*/
#if defined(__alpha__)
#define CODE_GEN_BUFFER_SIZE (2 * 1024 * 1024)
#elif defined(__powerpc__)
#define CODE_GEN_BUFFER_SIZE (6 * 1024 * 1024)
#else
#define CODE_GEN_BUFFER_SIZE (8 * 1024 * 1024)
#endif
//#define CODE_GEN_BUFFER_SIZE (128 * 1024)
#if defined(__powerpc__)
/* estimated block size for TB allocation */
/* XXX: use a per code average code fragment size and modulate it
according to the host CPU */
#if defined(CONFIG_SOFTMMU)
#define CODE_GEN_AVG_BLOCK_SIZE 128
#else
#define CODE_GEN_AVG_BLOCK_SIZE 64
#endif
#define CODE_GEN_MAX_BLOCKS (CODE_GEN_BUFFER_SIZE / CODE_GEN_AVG_BLOCK_SIZE)
#if defined(__powerpc__)
#define USE_DIRECT_JUMP
#endif
#if defined(__i386__) && !defined(_WIN32)
#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 */
target_ulong pc; /* simulated PC corresponding to this block (EIP + CS base) */
target_ulong 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) */
uint16_t cflags; /* compile flags */
#define CF_CODE_COPY 0x0001 /* block was generated in code copy mode */
#define CF_TB_FP_USED 0x0002 /* fp ops are used in the TB */
#define CF_FP_USED 0x0004 /* fp ops are used in the TB or in a chained TB */
#define CF_SINGLE_INSN 0x0008 /* compile only a single instruction */
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 */
struct TranslationBlock *hash_next; /* next matching tb for virtual address */
/* next matching tb for physical address. */
struct TranslationBlock *phys_hash_next;
/* first and second physical page containing code. The lower bit
of the pointer tells the index in page_next[] */
struct TranslationBlock *page_next[2];
target_ulong page_addr[2];
/* 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 */
@@ -126,11 +191,19 @@ static inline unsigned int tb_hash_func(unsigned long pc)
return pc & (CODE_GEN_HASH_SIZE - 1);
}
static inline unsigned int tb_phys_hash_func(unsigned long pc)
{
return pc & (CODE_GEN_PHYS_HASH_SIZE - 1);
}
TranslationBlock *tb_alloc(unsigned long pc);
void tb_flush(void);
void tb_flush(CPUState *env);
void tb_link(TranslationBlock *tb);
void tb_link_phys(TranslationBlock *tb,
target_ulong phys_pc, target_ulong phys_page2);
extern TranslationBlock *tb_hash[CODE_GEN_HASH_SIZE];
extern TranslationBlock *tb_phys_hash[CODE_GEN_PHYS_HASH_SIZE];
extern uint8_t code_gen_buffer[CODE_GEN_BUFFER_SIZE];
extern uint8_t *code_gen_ptr;
@@ -138,8 +211,8 @@ 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,
target_ulong pc,
target_ulong cs_base,
unsigned int flags)
{
TranslationBlock **ptb, *tb;
@@ -159,8 +232,10 @@ static inline TranslationBlock *tb_find(TranslationBlock ***pptb,
return NULL;
}
#if defined(__powerpc__)
#if defined(USE_DIRECT_JUMP)
#if defined(__powerpc__)
static inline void tb_set_jmp_target1(unsigned long jmp_addr, unsigned long addr)
{
uint32_t val, *ptr;
@@ -177,6 +252,14 @@ static inline void tb_set_jmp_target1(unsigned long jmp_addr, unsigned long addr
asm volatile ("sync" : : : "memory");
asm volatile ("isync" : : : "memory");
}
#elif defined(__i386__)
static inline void tb_set_jmp_target1(unsigned long jmp_addr, unsigned long addr)
{
/* patch the branch destination */
*(uint32_t *)jmp_addr = addr - (jmp_addr + 4);
/* no need to flush icache explicitely */
}
#endif
static inline void tb_set_jmp_target(TranslationBlock *tb,
int n, unsigned long addr)
@@ -221,16 +304,29 @@ TranslationBlock *tb_find_pc(unsigned long pc_ptr);
#define offsetof(type, field) ((size_t) &((type *)0)->field)
#endif
#if defined(_WIN32)
#define ASM_DATA_SECTION ".section \".data\"\n"
#define ASM_PREVIOUS_SECTION ".section .text\n"
#elif defined(__APPLE__)
#define ASM_DATA_SECTION ".data\n"
#define ASM_PREVIOUS_SECTION ".text\n"
#define ASM_NAME(x) "_" #x
#else
#define ASM_DATA_SECTION ".section \".data\"\n"
#define ASM_PREVIOUS_SECTION ".previous\n"
#define ASM_NAME(x) stringify(x)
#endif
#if defined(__powerpc__)
/* on PowerPC we patch the jump instruction directly */
/* 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"\
asm volatile (ASM_DATA_SECTION\
ASM_NAME(__op_label) #n "." ASM_NAME(opname) ":\n"\
".long 1f\n"\
".previous\n"\
"b __op_jmp" #n "\n"\
ASM_PREVIOUS_SECTION \
"b " ASM_NAME(__op_jmp) #n "\n"\
"1:\n");\
T0 = (long)(tbparam) + (n);\
EIP = eip;\
@@ -239,7 +335,28 @@ do {\
#define JUMP_TB2(opname, tbparam, n)\
do {\
asm volatile ("b __op_jmp%0\n" : : "i" (n + 2));\
asm volatile ("b " ASM_NAME(__op_jmp) #n "\n");\
} while (0)
#elif defined(__i386__) && defined(USE_DIRECT_JUMP)
/* we patch the jump instruction directly */
#define JUMP_TB(opname, tbparam, n, eip)\
do {\
asm volatile (".section .data\n"\
ASM_NAME(__op_label) #n "." ASM_NAME(opname) ":\n"\
".long 1f\n"\
ASM_PREVIOUS_SECTION \
"jmp " ASM_NAME(__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 ("jmp " ASM_NAME(__op_jmp) #n "\n");\
} while (0)
#else
@@ -261,32 +378,25 @@ dummy_label ## n:\
/* second jump to same destination 'n' */
#define JUMP_TB2(opname, tbparam, n)\
do {\
goto *(void *)(((TranslationBlock *)tbparam)->tb_next[n]);\
goto *(void *)(((TranslationBlock *)tbparam)->tb_next[n - 2]);\
} 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];
extern void *io_mem_opaque[IO_MEM_NB_ENTRIES];
#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;"
"0: lwarx %0,0,%1\n"
" xor. %0,%3,%0\n"
" bne 1f\n"
" stwcx. %2,0,%1\n"
" bne- 0b\n"
"1: "
: "=&r" (ret)
: "r" (p), "r" (1), "r" (0)
@@ -309,6 +419,20 @@ static inline int testandset (int *p)
}
#endif
#ifdef __x86_64__
static inline int testandset (int *p)
{
char ret;
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)
{
@@ -384,7 +508,7 @@ typedef int spinlock_t;
#define SPIN_LOCK_UNLOCKED 0
#if 1
#if defined(CONFIG_USER_ONLY)
static inline void spin_lock(spinlock_t *lock)
{
while (testandset(lock));
@@ -416,8 +540,9 @@ static inline int spin_trylock(spinlock_t *lock)
extern spinlock_t tb_lock;
extern int tb_invalidated_flag;
#if defined(TARGET_I386) && !defined(CONFIG_USER_ONLY)
#if !defined(CONFIG_USER_ONLY)
void tlb_fill(unsigned long addr, int is_write, int is_user,
void *retaddr);
@@ -440,3 +565,35 @@ void tlb_fill(unsigned long addr, int is_write, int is_user,
#undef env
#endif
#if defined(CONFIG_USER_ONLY)
static inline target_ulong get_phys_addr_code(CPUState *env, target_ulong addr)
{
return addr;
}
#else
/* NOTE: this function can trigger an exception */
/* NOTE2: the returned address is not exactly the physical address: it
is the offset relative to phys_ram_base */
/* XXX: i386 target specific */
static inline target_ulong get_phys_addr_code(CPUState *env, target_ulong addr)
{
int is_user, index;
index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
#if defined(TARGET_I386)
is_user = ((env->hflags & HF_CPL_MASK) == 3);
#elif defined (TARGET_PPC)
is_user = msr_pr;
#elif defined (TARGET_SPARC)
is_user = (env->psrs == 0);
#else
#error "Unimplemented !"
#endif
if (__builtin_expect(env->tlb_read[is_user][index].address !=
(addr & TARGET_PAGE_MASK), 0)) {
ldub_code((void *)addr);
}
return addr + env->tlb_read[is_user][index].addend - (unsigned long)phys_ram_base;
}
#endif

1866
exec.c

File diff suppressed because it is too large Load Diff

803
gdbstub.c
View File

@@ -17,81 +17,39 @@
* 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 "vl.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;
enum RSState {
RS_IDLE,
RS_GETLINE,
RS_CHKSUM1,
RS_CHKSUM2,
};
/* return 0 if OK */
static int gdbstub_open(int port)
{
struct sockaddr_in sockaddr;
socklen_t len;
int fd, val, ret;
static int gdbserver_fd;
fd = socket(PF_INET, SOCK_STREAM, 0);
if (fd < 0) {
perror("socket");
return -1;
}
typedef struct GDBState {
enum RSState state;
int fd;
char line_buf[4096];
int line_buf_index;
int line_csum;
} GDBState;
/* 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)
static int get_char(GDBState *s)
{
uint8_t ch;
int ret;
for(;;) {
ret = read(gdbstub_fd, &ch, 1);
ret = read(s->fd, &ch, 1);
if (ret < 0) {
if (errno != EINTR && errno != EAGAIN)
return -1;
@@ -104,12 +62,12 @@ static int get_char(void)
return ch;
}
static void put_buffer(const uint8_t *buf, int len)
static void put_buffer(GDBState *s, const uint8_t *buf, int len)
{
int ret;
while (len > 0) {
ret = write(gdbstub_fd, buf, len);
ret = write(s->fd, buf, len);
if (ret < 0) {
if (errno != EINTR && errno != EAGAIN)
return;
@@ -163,59 +121,8 @@ static void hextomem(uint8_t *mem, const char *buf, int len)
}
}
/* 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)
static int put_packet(GDBState *s, char *buf)
{
char buf1[3];
int len, csum, ch, i;
@@ -226,9 +133,9 @@ static int put_packet(char *buf)
for(;;) {
buf1[0] = '$';
put_buffer(buf1, 1);
put_buffer(s, buf1, 1);
len = strlen(buf);
put_buffer(buf, len);
put_buffer(s, buf, len);
csum = 0;
for(i = 0; i < len; i++) {
csum += buf[i];
@@ -237,9 +144,9 @@ static int put_packet(char *buf)
buf1[1] = tohex((csum >> 4) & 0xf);
buf1[2] = tohex((csum) & 0xf);
put_buffer(buf1, 3);
put_buffer(s, buf1, 3);
ch = get_char();
ch = get_char(s);
if (ch < 0)
return -1;
if (ch == '+')
@@ -248,126 +155,56 @@ static int put_packet(char *buf)
return 0;
}
static int memory_rw(uint8_t *buf, uint32_t addr, int len, int is_write)
{
int l, flags;
uint32_t page;
#if defined(TARGET_I386)
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;
static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf)
{
uint32_t *registers = (uint32_t *)mem_buf;
int i, fpus;
for(i = 0; i < 8; i++) {
registers[i] = env->regs[i];
}
return 0;
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;
/* XXX: convert floats */
for(i = 0; i < 8; i++) {
memcpy(mem_buf + 16 * 4 + i * 10, &env->fpregs[i], 10);
}
registers[36] = env->fpuc;
fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
registers[37] = fpus;
registers[38] = 0; /* XXX: convert tags */
registers[39] = 0; /* fiseg */
registers[40] = 0; /* fioff */
registers[41] = 0; /* foseg */
registers[42] = 0; /* fooff */
registers[43] = 0; /* fop */
for(i = 0; i < 16; i++)
tswapls(&registers[i]);
for(i = 36; i < 44; i++)
tswapls(&registers[i]);
return 44 * 4;
}
/* port = 0 means default port */
int cpu_gdbstub(void *opaque, int (*main_loop)(void *opaque), int port)
static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size)
{
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];
uint32_t *registers = (uint32_t *)mem_buf;
int i;
for(i = 0; i < 8; i++) {
env->regs[i] = tswapl(registers[i]);
}
env->eip = tswapl(registers[8]);
env->eflags = tswapl(registers[9]);
#if defined(CONFIG_USER_ONLY)
#define LOAD_SEG(index, sreg)\
if (tswapl(registers[index]) != env->segs[sreg].selector)\
cpu_x86_load_seg(env, sreg, tswapl(registers[index]));
@@ -378,88 +215,444 @@ int cpu_gdbstub(void *opaque, int (*main_loop)(void *opaque), int port)
LOAD_SEG(14, R_FS);
LOAD_SEG(15, R_GS);
#endif
put_packet("OK");
break;
case 'm':
}
#elif defined (TARGET_PPC)
static uint32_t from_le32 (uint32_t *buf)
{
uint8_t *p = (uint8_t *)buf;
return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
}
static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf)
{
uint32_t *registers = (uint32_t *)mem_buf, tmp;
int i;
/* fill in gprs */
for(i = 0; i < 32; i++) {
registers[i] = tswapl(env->gpr[i]);
}
/* fill in fprs */
for (i = 0; i < 32; i++) {
registers[(i * 2) + 32] = tswapl(*((uint32_t *)&env->fpr[i]));
registers[(i * 2) + 33] = tswapl(*((uint32_t *)&env->fpr[i] + 1));
}
/* nip, msr, ccr, lnk, ctr, xer, mq */
registers[96] = tswapl(env->nip);
registers[97] = tswapl(_load_msr(env));
tmp = 0;
for (i = 0; i < 8; i++)
tmp |= env->crf[i] << (32 - ((i + 1) * 4));
registers[98] = tswapl(tmp);
registers[99] = tswapl(env->lr);
registers[100] = tswapl(env->ctr);
registers[101] = tswapl(_load_xer(env));
registers[102] = 0;
return 103 * 4;
}
static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size)
{
uint32_t *registers = (uint32_t *)mem_buf;
int i;
/* fill in gprs */
for (i = 0; i < 32; i++) {
env->gpr[i] = tswapl(registers[i]);
}
/* fill in fprs */
for (i = 0; i < 32; i++) {
*((uint32_t *)&env->fpr[i]) = tswapl(registers[(i * 2) + 32]);
*((uint32_t *)&env->fpr[i] + 1) = tswapl(registers[(i * 2) + 33]);
}
/* nip, msr, ccr, lnk, ctr, xer, mq */
env->nip = tswapl(registers[96]);
_store_msr(env, tswapl(registers[97]));
registers[98] = tswapl(registers[98]);
for (i = 0; i < 8; i++)
env->crf[i] = (registers[98] >> (32 - ((i + 1) * 4))) & 0xF;
env->lr = tswapl(registers[99]);
env->ctr = tswapl(registers[100]);
_store_xer(env, tswapl(registers[101]));
}
#elif defined (TARGET_SPARC)
static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf)
{
uint32_t *registers = (uint32_t *)mem_buf, tmp;
int i;
/* fill in g0..g7 */
for(i = 0; i < 7; i++) {
registers[i] = tswapl(env->gregs[i]);
}
/* fill in register window */
for(i = 0; i < 24; i++) {
registers[i + 8] = tswapl(env->regwptr[i]);
}
/* fill in fprs */
for (i = 0; i < 32; i++) {
registers[i + 32] = tswapl(*((uint32_t *)&env->fpr[i]));
}
/* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */
registers[64] = tswapl(env->y);
tmp = (0<<28) | (4<<24) | env->psr \
| (env->psrs? PSR_S : 0) \
| (env->psrs? PSR_PS : 0) \
| (env->psret? PSR_ET : 0) \
| env->cwp;
registers[65] = tswapl(tmp);
registers[66] = tswapl(env->wim);
registers[67] = tswapl(env->tbr);
registers[68] = tswapl(env->pc);
registers[69] = tswapl(env->npc);
registers[70] = tswapl(env->fsr);
registers[71] = 0; /* csr */
registers[72] = 0;
return 73 * 4;
}
static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size)
{
uint32_t *registers = (uint32_t *)mem_buf, tmp;
int i;
/* fill in g0..g7 */
for(i = 0; i < 7; i++) {
env->gregs[i] = tswapl(registers[i]);
}
/* fill in register window */
for(i = 0; i < 24; i++) {
env->regwptr[i] = tswapl(registers[i]);
}
/* fill in fprs */
for (i = 0; i < 32; i++) {
*((uint32_t *)&env->fpr[i]) = tswapl(registers[i + 32]);
}
/* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */
env->y = tswapl(registers[64]);
tmp = tswapl(registers[65]);
env->psr = tmp & ~PSR_ICC;
env->psrs = (tmp & PSR_S)? 1 : 0;
env->psrps = (tmp & PSR_PS)? 1 : 0;
env->psret = (tmp & PSR_ET)? 1 : 0;
env->cwp = (tmp & PSR_CWP);
env->wim = tswapl(registers[66]);
env->tbr = tswapl(registers[67]);
env->pc = tswapl(registers[68]);
env->npc = tswapl(registers[69]);
env->fsr = tswapl(registers[70]);
}
#else
static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf)
{
return 0;
}
static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size)
{
}
#endif
/* port = 0 means default port */
static int gdb_handle_packet(GDBState *s, const char *line_buf)
{
CPUState *env = cpu_single_env;
const char *p;
int ch, reg_size, type;
char buf[4096];
uint8_t mem_buf[2000];
uint32_t *registers;
uint32_t addr, len;
#ifdef DEBUG_GDB
printf("command='%s'\n", line_buf);
#endif
p = line_buf;
ch = *p++;
switch(ch) {
case '?':
snprintf(buf, sizeof(buf), "S%02x", SIGTRAP);
put_packet(s, buf);
break;
case 'c':
if (*p != '\0') {
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':
#if defined(TARGET_I386)
env->eip = addr;
#elif defined (TARGET_PPC)
env->nip = addr;
#elif defined (TARGET_SPARC)
env->pc = addr;
env->npc = addr + 4;
#endif
}
vm_start();
break;
case 's':
if (*p != '\0') {
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 {
#if defined(TARGET_I386)
env->eip = addr;
#elif defined (TARGET_PPC)
env->nip = addr;
#elif defined (TARGET_SPARC)
env->pc = addr;
env->npc = addr + 4;
#endif
}
cpu_single_step(env, 1);
vm_start();
break;
case 'g':
reg_size = cpu_gdb_read_registers(env, mem_buf);
memtohex(buf, mem_buf, reg_size);
put_packet(s, buf);
break;
case 'G':
registers = (void *)mem_buf;
len = strlen(p) / 2;
hextomem((uint8_t *)registers, p, len);
cpu_gdb_write_registers(env, mem_buf, len);
put_packet(s, "OK");
break;
case 'm':
addr = strtoul(p, (char **)&p, 16);
if (*p == ',')
p++;
len = strtoul(p, NULL, 16);
if (cpu_memory_rw_debug(env, addr, mem_buf, len, 0) != 0)
memset(mem_buf, 0, len);
memtohex(buf, mem_buf, len);
put_packet(s, 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 (cpu_memory_rw_debug(env, addr, mem_buf, len, 1) != 0)
put_packet(s, "ENN");
else
put_packet(s, "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) {
if (cpu_breakpoint_insert(env, addr) < 0)
goto breakpoint_error;
put_packet(s, "OK");
} else {
breakpoint_error:
put_packet(s, "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) {
cpu_breakpoint_remove(env, addr);
put_packet(s, "OK");
} else {
goto breakpoint_error;
}
break;
default:
// unknown_command:
/* put empty packet */
buf[0] = '\0';
put_packet(s, buf);
break;
}
return RS_IDLE;
}
static void gdb_vm_stopped(void *opaque, int reason)
{
GDBState *s = opaque;
char buf[256];
int ret;
/* disable single step if it was enable */
cpu_single_step(cpu_single_env, 0);
if (reason == EXCP_DEBUG)
ret = SIGTRAP;
else
ret = 0;
snprintf(buf, sizeof(buf), "S%02x", ret);
put_packet(s, buf);
}
static void gdb_read_byte(GDBState *s, int ch)
{
int i, csum;
char reply[1];
if (vm_running) {
/* when the CPU is running, we cannot do anything except stop
it when receiving a char */
vm_stop(EXCP_INTERRUPT);
} else {
switch(s->state) {
case RS_IDLE:
if (ch == '$') {
s->line_buf_index = 0;
s->state = RS_GETLINE;
}
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");
case RS_GETLINE:
if (ch == '#') {
s->state = RS_CHKSUM1;
} else if (s->line_buf_index >= sizeof(s->line_buf) - 1) {
s->state = RS_IDLE;
} else {
goto unknown_command;
s->line_buf[s->line_buf_index++] = ch;
}
break;
default:
unknown_command:
/* put empty packet */
buf[0] = '\0';
put_packet(buf);
case RS_CHKSUM1:
s->line_buf[s->line_buf_index] = '\0';
s->line_csum = fromhex(ch) << 4;
s->state = RS_CHKSUM2;
break;
case RS_CHKSUM2:
s->line_csum |= fromhex(ch);
csum = 0;
for(i = 0; i < s->line_buf_index; i++) {
csum += s->line_buf[i];
}
if (s->line_csum != (csum & 0xff)) {
reply[0] = '-';
put_buffer(s, reply, 1);
s->state = RS_IDLE;
} else {
reply[0] = '+';
put_buffer(s, reply, 1);
s->state = gdb_handle_packet(s, s->line_buf);
}
break;
}
}
}
static int gdb_can_read(void *opaque)
{
return 256;
}
static void gdb_read(void *opaque, const uint8_t *buf, int size)
{
GDBState *s = opaque;
int i;
if (size == 0) {
/* end of connection */
qemu_del_vm_stop_handler(gdb_vm_stopped, s);
qemu_del_fd_read_handler(s->fd);
qemu_free(s);
vm_start();
} else {
for(i = 0; i < size; i++)
gdb_read_byte(s, buf[i]);
}
}
static void gdb_accept(void *opaque, const uint8_t *buf, int size)
{
GDBState *s;
struct sockaddr_in sockaddr;
socklen_t len;
int val, fd;
for(;;) {
len = sizeof(sockaddr);
fd = accept(gdbserver_fd, (struct sockaddr *)&sockaddr, &len);
if (fd < 0 && errno != EINTR) {
perror("accept");
return;
} else if (fd >= 0) {
break;
}
}
/* set short latency */
val = 1;
setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val));
s = qemu_mallocz(sizeof(GDBState));
if (!s) {
close(fd);
return;
}
s->fd = fd;
fcntl(fd, F_SETFL, O_NONBLOCK);
/* stop the VM */
vm_stop(EXCP_INTERRUPT);
/* start handling I/O */
qemu_add_fd_read_handler(s->fd, gdb_can_read, gdb_read, s);
/* when the VM is stopped, the following callback is called */
qemu_add_vm_stop_handler(gdb_vm_stopped, s);
}
static int gdbserver_open(int port)
{
struct sockaddr_in sockaddr;
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;
}
fcntl(fd, F_SETFL, O_NONBLOCK);
return fd;
}
int gdbserver_start(int port)
{
gdbserver_fd = gdbserver_open(port);
if (gdbserver_fd < 0)
return -1;
/* accept connections */
qemu_add_fd_read_handler(gdbserver_fd, NULL, gdb_accept, NULL);
return 0;
}

386
hw/adb.c Normal file
View File

@@ -0,0 +1,386 @@
/*
* QEMU ADB support
*
* Copyright (c) 2004 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 "vl.h"
/* ADB commands */
#define ADB_BUSRESET 0x00
#define ADB_FLUSH 0x01
#define ADB_WRITEREG 0x08
#define ADB_READREG 0x0c
/* ADB device commands */
#define ADB_CMD_SELF_TEST 0xff
#define ADB_CMD_CHANGE_ID 0xfe
#define ADB_CMD_CHANGE_ID_AND_ACT 0xfd
#define ADB_CMD_CHANGE_ID_AND_ENABLE 0x00
/* ADB default device IDs (upper 4 bits of ADB command byte) */
#define ADB_DONGLE 1
#define ADB_KEYBOARD 2
#define ADB_MOUSE 3
#define ADB_TABLET 4
#define ADB_MODEM 5
#define ADB_MISC 7
/* error codes */
#define ADB_RET_NOTPRESENT (-2)
int adb_request(ADBBusState *s, uint8_t *obuf, const uint8_t *buf, int len)
{
ADBDevice *d;
int devaddr, cmd, i;
cmd = buf[0] & 0xf;
if (cmd == ADB_BUSRESET) {
for(i = 0; i < s->nb_devices; i++) {
d = &s->devices[i];
if (d->devreset) {
d->devreset(d);
}
}
return 0;
}
devaddr = buf[0] >> 4;
for(i = 0; i < s->nb_devices; i++) {
d = &s->devices[i];
if (d->devaddr == devaddr) {
return d->devreq(d, obuf, buf, len);
}
}
return ADB_RET_NOTPRESENT;
}
/* XXX: move that to cuda ? */
int adb_poll(ADBBusState *s, uint8_t *obuf)
{
ADBDevice *d;
int olen, i;
uint8_t buf[1];
olen = 0;
for(i = 0; i < s->nb_devices; i++) {
if (s->poll_index >= s->nb_devices)
s->poll_index = 0;
d = &s->devices[s->poll_index];
buf[0] = ADB_READREG | (d->devaddr << 4);
olen = adb_request(s, obuf + 1, buf, 1);
/* if there is data, we poll again the same device */
if (olen > 0) {
obuf[0] = buf[0];
olen++;
break;
}
s->poll_index++;
}
return olen;
}
ADBDevice *adb_register_device(ADBBusState *s, int devaddr,
ADBDeviceRequest *devreq,
ADBDeviceReset *devreset,
void *opaque)
{
ADBDevice *d;
if (s->nb_devices >= MAX_ADB_DEVICES)
return NULL;
d = &s->devices[s->nb_devices++];
d->bus = s;
d->devaddr = devaddr;
d->devreq = devreq;
d->devreset = devreset;
d->opaque = opaque;
return d;
}
/***************************************************************/
/* Keyboard ADB device */
typedef struct KBDState {
uint8_t data[128];
int rptr, wptr, count;
} KBDState;
static const uint8_t pc_to_adb_keycode[256] = {
0, 53, 18, 19, 20, 21, 23, 22, 26, 28, 25, 29, 27, 24, 51, 48,
12, 13, 14, 15, 17, 16, 32, 34, 31, 35, 33, 30, 36, 54, 0, 1,
2, 3, 5, 4, 38, 40, 37, 41, 39, 50, 56, 42, 6, 7, 8, 9,
11, 45, 46, 43, 47, 44,123, 67, 58, 49, 57,122,120, 99,118, 96,
97, 98,100,101,109, 71,107, 89, 91, 92, 78, 86, 87, 88, 69, 83,
84, 85, 82, 65, 0, 0, 10,103,111, 0, 0,110, 81, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 94, 0, 93, 0, 0, 0, 0, 0, 0,104,102, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 76,125, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,105, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 75, 0, 0,124, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0,115, 62,116, 0, 59, 0, 60, 0,119,
61,121,114,117, 0, 0, 0, 0, 0, 0, 0, 55,126, 0,127, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 95, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
};
static void adb_kbd_put_keycode(void *opaque, int keycode)
{
ADBDevice *d = opaque;
KBDState *s = d->opaque;
if (s->count < sizeof(s->data)) {
s->data[s->wptr] = keycode;
if (++s->wptr == sizeof(s->data))
s->wptr = 0;
s->count++;
}
}
static int adb_kbd_poll(ADBDevice *d, uint8_t *obuf)
{
static int ext_keycode;
KBDState *s = d->opaque;
int adb_keycode, keycode;
int olen;
olen = 0;
for(;;) {
if (s->count == 0)
break;
keycode = s->data[s->rptr];
if (++s->rptr == sizeof(s->data))
s->rptr = 0;
s->count--;
if (keycode == 0xe0) {
ext_keycode = 1;
} else {
if (ext_keycode)
adb_keycode = pc_to_adb_keycode[keycode | 0x80];
else
adb_keycode = pc_to_adb_keycode[keycode & 0x7f];
obuf[0] = adb_keycode | (keycode & 0x80);
/* NOTE: could put a second keycode if needed */
obuf[1] = 0xff;
olen = 2;
ext_keycode = 0;
break;
}
}
return olen;
}
static int adb_kbd_request(ADBDevice *d, uint8_t *obuf,
const uint8_t *buf, int len)
{
KBDState *s = d->opaque;
int cmd, reg, olen;
if ((buf[0] & 0x0f) == ADB_FLUSH) {
/* flush keyboard fifo */
s->wptr = s->rptr = s->count = 0;
return 0;
}
cmd = buf[0] & 0xc;
reg = buf[0] & 0x3;
olen = 0;
switch(cmd) {
case ADB_WRITEREG:
switch(reg) {
case 2:
/* LED status */
break;
case 3:
switch(buf[2]) {
case ADB_CMD_SELF_TEST:
break;
case ADB_CMD_CHANGE_ID:
case ADB_CMD_CHANGE_ID_AND_ACT:
case ADB_CMD_CHANGE_ID_AND_ENABLE:
d->devaddr = buf[1] & 0xf;
break;
default:
/* XXX: check this */
d->devaddr = buf[1] & 0xf;
d->handler = buf[2];
break;
}
}
break;
case ADB_READREG:
switch(reg) {
case 0:
olen = adb_kbd_poll(d, obuf);
break;
case 1:
break;
case 2:
obuf[0] = 0x00; /* XXX: check this */
obuf[1] = 0x07; /* led status */
olen = 2;
break;
case 3:
obuf[0] = d->handler;
obuf[1] = d->devaddr;
olen = 2;
break;
}
break;
}
return olen;
}
void adb_kbd_init(ADBBusState *bus)
{
ADBDevice *d;
KBDState *s;
s = qemu_mallocz(sizeof(KBDState));
d = adb_register_device(bus, ADB_KEYBOARD, adb_kbd_request, NULL, s);
d->handler = 1;
qemu_add_kbd_event_handler(adb_kbd_put_keycode, d);
}
/***************************************************************/
/* Mouse ADB device */
typedef struct MouseState {
int buttons_state, last_buttons_state;
int dx, dy, dz;
} MouseState;
static void adb_mouse_event(void *opaque,
int dx1, int dy1, int dz1, int buttons_state)
{
ADBDevice *d = opaque;
MouseState *s = d->opaque;
s->dx += dx1;
s->dy += dy1;
s->dz += dz1;
s->buttons_state = buttons_state;
}
static int adb_mouse_poll(ADBDevice *d, uint8_t *obuf)
{
MouseState *s = d->opaque;
int dx, dy;
if (s->last_buttons_state == s->buttons_state &&
s->dx == 0 && s->dy == 0)
return 0;
dx = s->dx;
if (dx < -63)
dx = -63;
else if (dx > 63)
dx = 63;
dy = s->dy;
if (dy < -63)
dy = -63;
else if (dy > 63)
dy = 63;
s->dx -= dx;
s->dy -= dy;
s->last_buttons_state = s->buttons_state;
dx &= 0x7f;
dy &= 0x7f;
if (!(s->buttons_state & MOUSE_EVENT_LBUTTON))
dy |= 0x80;
if (!(s->buttons_state & MOUSE_EVENT_RBUTTON))
dx |= 0x80;
obuf[0] = dy;
obuf[1] = dx;
return 2;
}
static int adb_mouse_request(ADBDevice *d, uint8_t *obuf,
const uint8_t *buf, int len)
{
MouseState *s = d->opaque;
int cmd, reg, olen;
if ((buf[0] & 0x0f) == ADB_FLUSH) {
/* flush mouse fifo */
s->buttons_state = s->last_buttons_state;
s->dx = 0;
s->dy = 0;
s->dz = 0;
return 0;
}
cmd = buf[0] & 0xc;
reg = buf[0] & 0x3;
olen = 0;
switch(cmd) {
case ADB_WRITEREG:
switch(reg) {
case 2:
break;
case 3:
switch(buf[2]) {
case ADB_CMD_SELF_TEST:
break;
case ADB_CMD_CHANGE_ID:
case ADB_CMD_CHANGE_ID_AND_ACT:
case ADB_CMD_CHANGE_ID_AND_ENABLE:
d->devaddr = buf[1] & 0xf;
break;
default:
/* XXX: check this */
d->devaddr = buf[1] & 0xf;
break;
}
}
break;
case ADB_READREG:
switch(reg) {
case 0:
olen = adb_mouse_poll(d, obuf);
break;
case 1:
break;
case 3:
obuf[0] = d->handler;
obuf[1] = d->devaddr;
olen = 2;
break;
}
break;
}
return olen;
}
void adb_mouse_init(ADBBusState *bus)
{
ADBDevice *d;
MouseState *s;
s = qemu_mallocz(sizeof(MouseState));
d = adb_register_device(bus, ADB_MOUSE, adb_mouse_request, NULL, s);
d->handler = 2;
qemu_add_mouse_event_handler(adb_mouse_event, d);
}

313
hw/adlib.c Normal file
View File

@@ -0,0 +1,313 @@
/*
* QEMU Adlib emulation
*
* Copyright (c) 2004 Vassili Karpov (malc)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "vl.h"
#define dolog(...) AUD_log ("adlib", __VA_ARGS__)
#ifdef DEBUG
#define ldebug(...) dolog (__VA_ARGS__)
#else
#define ldebug(...)
#endif
#ifdef USE_YMF262
#define HAS_YMF262 1
#include "ymf262.h"
void YMF262UpdateOneQEMU(int which, INT16 *dst, int length);
#define SHIFT 2
#else
#include "fmopl.h"
#define SHIFT 1
#endif
#ifdef _WIN32
#include <windows.h>
#define small_delay() Sleep (1)
#else
#define small_delay() usleep (1)
#endif
#define IO_READ_PROTO(name) \
uint32_t name (void *opaque, uint32_t nport)
#define IO_WRITE_PROTO(name) \
void name (void *opaque, uint32_t nport, uint32_t val)
static struct {
int port;
int freq;
} conf = {0x220, 44100};
typedef struct {
int enabled;
int active;
int cparam;
int64_t ticks;
int bufpos;
int16_t *mixbuf;
double interval;
QEMUTimer *ts, *opl_ts;
SWVoice *voice;
int left, pos, samples, bytes_per_second, old_free;
int refcount;
#ifndef USE_YMF262
FM_OPL *opl;
#endif
} AdlibState;
static AdlibState adlib;
static IO_WRITE_PROTO(adlib_write)
{
AdlibState *s = opaque;
int a = nport & 3;
int status;
s->ticks = qemu_get_clock (vm_clock);
s->active = 1;
AUD_enable (s->voice, 1);
#ifdef USE_YMF262
status = YMF262Write (0, a, val);
#else
status = OPLWrite (s->opl, a, val);
#endif
}
static IO_READ_PROTO(adlib_read)
{
AdlibState *s = opaque;
uint8_t data;
int a = nport & 3;
#ifdef USE_YMF262
(void) s;
data = YMF262Read (0, a);
#else
data = OPLRead (s->opl, a);
#endif
return data;
}
static void OPL_timer (void *opaque)
{
AdlibState *s = opaque;
#ifdef USE_YMF262
YMF262TimerOver (s->cparam >> 1, s->cparam & 1);
#else
OPLTimerOver (s->opl, s->cparam);
#endif
qemu_mod_timer (s->opl_ts, qemu_get_clock (vm_clock) + s->interval);
}
static void YMF262TimerHandler (int c, double interval_Sec)
{
AdlibState *s = &adlib;
if (interval_Sec == 0.0) {
qemu_del_timer (s->opl_ts);
return;
}
s->cparam = c;
s->interval = ticks_per_sec * interval_Sec;
qemu_mod_timer (s->opl_ts, qemu_get_clock (vm_clock) + s->interval);
small_delay ();
}
static int write_audio (AdlibState *s, int samples)
{
int net = 0;
int ss = samples;
while (samples) {
int nbytes = samples << SHIFT;
int wbytes = AUD_write (s->voice,
s->mixbuf + (s->pos << (SHIFT - 1)),
nbytes);
int wsampl = wbytes >> SHIFT;
samples -= wsampl;
s->pos = (s->pos + wsampl) % s->samples;
net += wsampl;
if (!wbytes)
break;
}
if (net > ss) {
dolog ("WARNING: net > ss\n");
}
return net;
}
static void timer (void *opaque)
{
AdlibState *s = opaque;
int elapsed, samples, net = 0;
if (s->refcount)
dolog ("refcount=%d\n", s->refcount);
s->refcount += 1;
if (!(s->active && s->enabled))
goto reset;
AUD_run ();
while (s->left) {
int written = write_audio (s, s->left);
net += written;
if (!written)
goto reset2;
s->left -= written;
}
s->pos = 0;
elapsed = AUD_calc_elapsed (s->voice);
if (!elapsed)
goto reset2;
/* elapsed = AUD_get_free (s->voice); */
samples = elapsed >> SHIFT;
if (!samples)
goto reset2;
samples = audio_MIN (samples, s->samples - s->pos);
if (s->left)
dolog ("left=%d samples=%d elapsed=%d free=%d\n",
s->left, samples, elapsed, AUD_get_free (s->voice));
if (!samples)
goto reset2;
#ifdef USE_YMF262
YMF262UpdateOneQEMU (0, s->mixbuf + s->pos * 2, samples);
#else
YM3812UpdateOne (s->opl, s->mixbuf + s->pos, samples);
#endif
while (samples) {
int written = write_audio (s, samples);
net += written;
if (!written)
break;
samples -= written;
}
if (!samples)
s->pos = 0;
s->left = samples;
reset2:
AUD_adjust (s->voice, net << SHIFT);
reset:
qemu_mod_timer (s->ts, qemu_get_clock (vm_clock) + ticks_per_sec / 1024);
s->refcount -= 1;
}
static void Adlib_fini (AdlibState *s)
{
#ifdef USE_YMF262
YMF262Shutdown ();
#else
if (s->opl) {
OPLDestroy (s->opl);
s->opl = NULL;
}
#endif
if (s->opl_ts)
qemu_free_timer (s->opl_ts);
if (s->ts)
qemu_free_timer (s->ts);
#define maybe_free(p) if (p) qemu_free (p)
maybe_free (s->mixbuf);
#undef maybe_free
s->active = 0;
s->enabled = 0;
}
void Adlib_init (void)
{
AdlibState *s = &adlib;
memset (s, 0, sizeof (*s));
#ifdef USE_YMF262
if (YMF262Init (1, 14318180, conf.freq)) {
dolog ("YMF262Init %d failed\n", conf.freq);
return;
}
else {
YMF262SetTimerHandler (0, YMF262TimerHandler, 0);
s->enabled = 1;
}
#else
s->opl = OPLCreate (OPL_TYPE_YM3812, 3579545, conf.freq);
if (!s->opl) {
dolog ("OPLCreate %d failed\n", conf.freq);
return;
}
else {
OPLSetTimerHandler (s->opl, YMF262TimerHandler, 0);
s->enabled = 1;
}
#endif
s->opl_ts = qemu_new_timer (vm_clock, OPL_timer, s);
if (!s->opl_ts) {
dolog ("Can not get timer for adlib emulation\n");
Adlib_fini (s);
return;
}
s->ts = qemu_new_timer (vm_clock, timer, s);
if (!s->opl_ts) {
dolog ("Can not get timer for adlib emulation\n");
Adlib_fini (s);
return;
}
s->voice = AUD_open (s->voice, "adlib", conf.freq, SHIFT, AUD_FMT_S16);
if (!s->voice) {
Adlib_fini (s);
return;
}
s->bytes_per_second = conf.freq << SHIFT;
s->samples = AUD_get_buffer_size (s->voice) >> SHIFT;
s->mixbuf = qemu_mallocz (s->samples << SHIFT);
if (!s->mixbuf) {
dolog ("not enough memory for adlib mixing buffer (%d)\n",
s->samples << SHIFT);
Adlib_fini (s);
return;
}
register_ioport_read (0x388, 4, 1, adlib_read, s);
register_ioport_write (0x388, 4, 1, adlib_write, s);
register_ioport_read (conf.port, 4, 1, adlib_read, s);
register_ioport_write (conf.port, 4, 1, adlib_write, s);
register_ioport_read (conf.port + 8, 2, 1, adlib_read, s);
register_ioport_write (conf.port + 8, 2, 1, adlib_write, s);
qemu_mod_timer (s->ts, qemu_get_clock (vm_clock) + 1);
}

3115
hw/cirrus_vga.c Normal file

File diff suppressed because it is too large Load Diff

78
hw/cirrus_vga_rop.h Normal file
View File

@@ -0,0 +1,78 @@
/*
* QEMU Cirrus CLGD 54xx VGA Emulator.
*
* Copyright (c) 2004 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.
*/
static void
glue(cirrus_bitblt_rop_fwd_, ROP_NAME)(CirrusVGAState *s,
uint8_t *dst,const uint8_t *src,
int dstpitch,int srcpitch,
int bltwidth,int bltheight)
{
int x,y;
dstpitch -= bltwidth;
srcpitch -= bltwidth;
for (y = 0; y < bltheight; y++) {
for (x = 0; x < bltwidth; x++) {
ROP_OP(*dst, *src);
dst++;
src++;
}
dst += dstpitch;
src += srcpitch;
}
}
static void
glue(cirrus_bitblt_rop_bkwd_, ROP_NAME)(CirrusVGAState *s,
uint8_t *dst,const uint8_t *src,
int dstpitch,int srcpitch,
int bltwidth,int bltheight)
{
int x,y;
dstpitch += bltwidth;
srcpitch += bltwidth;
for (y = 0; y < bltheight; y++) {
for (x = 0; x < bltwidth; x++) {
ROP_OP(*dst, *src);
dst--;
src--;
}
dst += dstpitch;
src += srcpitch;
}
}
#define DEPTH 8
#include "cirrus_vga_rop2.h"
#define DEPTH 16
#include "cirrus_vga_rop2.h"
#define DEPTH 24
#include "cirrus_vga_rop2.h"
#define DEPTH 32
#include "cirrus_vga_rop2.h"
#undef ROP_NAME
#undef ROP_OP

260
hw/cirrus_vga_rop2.h Normal file
View File

@@ -0,0 +1,260 @@
/*
* QEMU Cirrus CLGD 54xx VGA Emulator.
*
* Copyright (c) 2004 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 PUTPIXEL() ROP_OP(d[0], col)
#elif DEPTH == 16
#define PUTPIXEL() ROP_OP(((uint16_t *)d)[0], col);
#elif DEPTH == 24
#define PUTPIXEL() ROP_OP(d[0], col); \
ROP_OP(d[1], (col >> 8)); \
ROP_OP(d[2], (col >> 16))
#elif DEPTH == 32
#define PUTPIXEL() ROP_OP(((uint32_t *)d)[0], col)
#else
#error unsupported DEPTH
#endif
static void
glue(glue(glue(cirrus_patternfill_, ROP_NAME), _),DEPTH)
(CirrusVGAState * s, uint8_t * dst,
const uint8_t * src,
int dstpitch, int srcpitch,
int bltwidth, int bltheight)
{
uint8_t *d;
int x, y, pattern_y, pattern_pitch, pattern_x;
unsigned int col;
const uint8_t *src1;
#if DEPTH == 8
pattern_pitch = 8;
#elif DEPTH == 16
pattern_pitch = 16;
#else
pattern_pitch = 32;
#endif
pattern_y = s->cirrus_blt_srcaddr & 7;
pattern_x = 0;
for(y = 0; y < bltheight; y++) {
d = dst;
src1 = src + pattern_y * pattern_pitch;
for (x = 0; x < bltwidth; x += (DEPTH / 8)) {
#if DEPTH == 8
col = src1[pattern_x];
pattern_x = (pattern_x + 1) & 7;
#elif DEPTH == 16
col = ((uint16_t *)(src1 + pattern_x))[0];
pattern_x = (pattern_x + 2) & 15;
#elif DEPTH == 24
{
const uint8_t *src2 = src1 + pattern_x * 3;
col = src2[0] | (src2[1] << 8) | (src2[2] << 16);
pattern_x = (pattern_x + 1) & 7;
}
#else
col = ((uint32_t *)(src1 + pattern_x))[0];
pattern_x = (pattern_x + 4) & 31;
#endif
PUTPIXEL();
d += (DEPTH / 8);
}
pattern_y = (pattern_y + 1) & 7;
dst += dstpitch;
}
}
/* NOTE: srcpitch is ignored */
static void
glue(glue(glue(cirrus_colorexpand_transp_, ROP_NAME), _),DEPTH)
(CirrusVGAState * s, uint8_t * dst,
const uint8_t * src,
int dstpitch, int srcpitch,
int bltwidth, int bltheight)
{
uint8_t *d;
int x, y;
unsigned bits, bits_xor;
unsigned int col;
unsigned bitmask;
unsigned index;
int srcskipleft = 0;
if (s->cirrus_blt_modeext & CIRRUS_BLTMODEEXT_COLOREXPINV) {
bits_xor = 0xff;
col = s->cirrus_blt_bgcol;
} else {
bits_xor = 0x00;
col = s->cirrus_blt_fgcol;
}
for(y = 0; y < bltheight; y++) {
bitmask = 0x80 >> srcskipleft;
bits = *src++ ^ bits_xor;
d = dst;
for (x = 0; x < bltwidth; x += (DEPTH / 8)) {
if ((bitmask & 0xff) == 0) {
bitmask = 0x80;
bits = *src++ ^ bits_xor;
}
index = (bits & bitmask);
if (index) {
PUTPIXEL();
}
d += (DEPTH / 8);
bitmask >>= 1;
}
dst += dstpitch;
}
}
static void
glue(glue(glue(cirrus_colorexpand_, ROP_NAME), _),DEPTH)
(CirrusVGAState * s, uint8_t * dst,
const uint8_t * src,
int dstpitch, int srcpitch,
int bltwidth, int bltheight)
{
uint32_t colors[2];
uint8_t *d;
int x, y;
unsigned bits;
unsigned int col;
unsigned bitmask;
int srcskipleft = 0;
colors[0] = s->cirrus_blt_bgcol;
colors[1] = s->cirrus_blt_fgcol;
for(y = 0; y < bltheight; y++) {
bitmask = 0x80 >> srcskipleft;
bits = *src++;
d = dst;
for (x = 0; x < bltwidth; x += (DEPTH / 8)) {
if ((bitmask & 0xff) == 0) {
bitmask = 0x80;
bits = *src++;
}
col = colors[!!(bits & bitmask)];
PUTPIXEL();
d += (DEPTH / 8);
bitmask >>= 1;
}
dst += dstpitch;
}
}
static void
glue(glue(glue(cirrus_colorexpand_pattern_transp_, ROP_NAME), _),DEPTH)
(CirrusVGAState * s, uint8_t * dst,
const uint8_t * src,
int dstpitch, int srcpitch,
int bltwidth, int bltheight)
{
uint8_t *d;
int x, y, bitpos, pattern_y;
unsigned int bits, bits_xor;
unsigned int col;
if (s->cirrus_blt_modeext & CIRRUS_BLTMODEEXT_COLOREXPINV) {
bits_xor = 0xff;
col = s->cirrus_blt_bgcol;
} else {
bits_xor = 0x00;
col = s->cirrus_blt_fgcol;
}
pattern_y = s->cirrus_blt_srcaddr & 7;
for(y = 0; y < bltheight; y++) {
bits = src[pattern_y] ^ bits_xor;
bitpos = 7;
d = dst;
for (x = 0; x < bltwidth; x += (DEPTH / 8)) {
if ((bits >> bitpos) & 1) {
PUTPIXEL();
}
d += (DEPTH / 8);
bitpos = (bitpos - 1) & 7;
}
pattern_y = (pattern_y + 1) & 7;
dst += dstpitch;
}
}
static void
glue(glue(glue(cirrus_colorexpand_pattern_, ROP_NAME), _),DEPTH)
(CirrusVGAState * s, uint8_t * dst,
const uint8_t * src,
int dstpitch, int srcpitch,
int bltwidth, int bltheight)
{
uint32_t colors[2];
uint8_t *d;
int x, y, bitpos, pattern_y;
unsigned int bits;
unsigned int col;
colors[0] = s->cirrus_blt_bgcol;
colors[1] = s->cirrus_blt_fgcol;
pattern_y = s->cirrus_blt_srcaddr & 7;
for(y = 0; y < bltheight; y++) {
bits = src[pattern_y];
bitpos = 7;
d = dst;
for (x = 0; x < bltwidth; x += (DEPTH / 8)) {
col = colors[(bits >> bitpos) & 1];
PUTPIXEL();
d += (DEPTH / 8);
bitpos = (bitpos - 1) & 7;
}
pattern_y = (pattern_y + 1) & 7;
dst += dstpitch;
}
}
static void
glue(glue(glue(cirrus_fill_, ROP_NAME), _),DEPTH)
(CirrusVGAState *s,
uint8_t *dst, int dst_pitch,
int width, int height)
{
uint8_t *d, *d1;
uint32_t col;
int x, y;
col = s->cirrus_blt_fgcol;
d1 = dst;
for(y = 0; y < height; y++) {
d = d1;
for(x = 0; x < width; x += (DEPTH / 8)) {
PUTPIXEL();
d += (DEPTH / 8);
}
d1 += dst_pitch;
}
}
#undef DEPTH
#undef PUTPIXEL

614
hw/cuda.c Normal file
View File

@@ -0,0 +1,614 @@
/*
* QEMU CUDA support
*
* Copyright (c) 2004 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 "vl.h"
//#define DEBUG_CUDA
//#define DEBUG_CUDA_PACKET
/* Bits in B data register: all active low */
#define TREQ 0x08 /* Transfer request (input) */
#define TACK 0x10 /* Transfer acknowledge (output) */
#define TIP 0x20 /* Transfer in progress (output) */
/* Bits in ACR */
#define SR_CTRL 0x1c /* Shift register control bits */
#define SR_EXT 0x0c /* Shift on external clock */
#define SR_OUT 0x10 /* Shift out if 1 */
/* Bits in IFR and IER */
#define IER_SET 0x80 /* set bits in IER */
#define IER_CLR 0 /* clear bits in IER */
#define SR_INT 0x04 /* Shift register full/empty */
#define T1_INT 0x40 /* Timer 1 interrupt */
/* Bits in ACR */
#define T1MODE 0xc0 /* Timer 1 mode */
#define T1MODE_CONT 0x40 /* continuous interrupts */
/* commands (1st byte) */
#define ADB_PACKET 0
#define CUDA_PACKET 1
#define ERROR_PACKET 2
#define TIMER_PACKET 3
#define POWER_PACKET 4
#define MACIIC_PACKET 5
#define PMU_PACKET 6
/* CUDA commands (2nd byte) */
#define CUDA_WARM_START 0x0
#define CUDA_AUTOPOLL 0x1
#define CUDA_GET_6805_ADDR 0x2
#define CUDA_GET_TIME 0x3
#define CUDA_GET_PRAM 0x7
#define CUDA_SET_6805_ADDR 0x8
#define CUDA_SET_TIME 0x9
#define CUDA_POWERDOWN 0xa
#define CUDA_POWERUP_TIME 0xb
#define CUDA_SET_PRAM 0xc
#define CUDA_MS_RESET 0xd
#define CUDA_SEND_DFAC 0xe
#define CUDA_BATTERY_SWAP_SENSE 0x10
#define CUDA_RESET_SYSTEM 0x11
#define CUDA_SET_IPL 0x12
#define CUDA_FILE_SERVER_FLAG 0x13
#define CUDA_SET_AUTO_RATE 0x14
#define CUDA_GET_AUTO_RATE 0x16
#define CUDA_SET_DEVICE_LIST 0x19
#define CUDA_GET_DEVICE_LIST 0x1a
#define CUDA_SET_ONE_SECOND_MODE 0x1b
#define CUDA_SET_POWER_MESSAGES 0x21
#define CUDA_GET_SET_IIC 0x22
#define CUDA_WAKEUP 0x23
#define CUDA_TIMER_TICKLE 0x24
#define CUDA_COMBINED_FORMAT_IIC 0x25
#define CUDA_TIMER_FREQ (4700000 / 6)
#define CUDA_ADB_POLL_FREQ 50
typedef struct CUDATimer {
unsigned int latch;
uint16_t counter_value; /* counter value at load time */
int64_t load_time;
int64_t next_irq_time;
QEMUTimer *timer;
} CUDATimer;
typedef struct CUDAState {
/* cuda registers */
uint8_t b; /* B-side data */
uint8_t a; /* A-side data */
uint8_t dirb; /* B-side direction (1=output) */
uint8_t dira; /* A-side direction (1=output) */
uint8_t sr; /* Shift register */
uint8_t acr; /* Auxiliary control register */
uint8_t pcr; /* Peripheral control register */
uint8_t ifr; /* Interrupt flag register */
uint8_t ier; /* Interrupt enable register */
uint8_t anh; /* A-side data, no handshake */
CUDATimer timers[2];
uint8_t last_b; /* last value of B register */
uint8_t last_acr; /* last value of B register */
int data_in_size;
int data_in_index;
int data_out_index;
int irq;
openpic_t *openpic;
uint8_t autopoll;
uint8_t data_in[128];
uint8_t data_out[16];
QEMUTimer *adb_poll_timer;
} CUDAState;
static CUDAState cuda_state;
ADBBusState adb_bus;
static void cuda_update(CUDAState *s);
static void cuda_receive_packet_from_host(CUDAState *s,
const uint8_t *data, int len);
static void cuda_timer_update(CUDAState *s, CUDATimer *ti,
int64_t current_time);
static void cuda_update_irq(CUDAState *s)
{
if (s->ifr & s->ier & (SR_INT | T1_INT)) {
openpic_set_irq(s->openpic, s->irq, 1);
} else {
openpic_set_irq(s->openpic, s->irq, 0);
}
}
static unsigned int get_counter(CUDATimer *s)
{
int64_t d;
unsigned int counter;
d = muldiv64(qemu_get_clock(vm_clock) - s->load_time,
CUDA_TIMER_FREQ, ticks_per_sec);
if (d <= s->counter_value) {
counter = d;
} else {
counter = s->latch - 1 - ((d - s->counter_value) % s->latch);
}
return counter;
}
static void set_counter(CUDAState *s, CUDATimer *ti, unsigned int val)
{
#ifdef DEBUG_CUDA
printf("cuda: T%d.counter=%d\n",
1 + (ti->timer == NULL), val);
#endif
ti->load_time = qemu_get_clock(vm_clock);
ti->counter_value = val;
cuda_timer_update(s, ti, ti->load_time);
}
static int64_t get_next_irq_time(CUDATimer *s, int64_t current_time)
{
int64_t d, next_time, base;
/* current counter value */
d = muldiv64(current_time - s->load_time,
CUDA_TIMER_FREQ, ticks_per_sec);
if (d <= s->counter_value) {
next_time = s->counter_value + 1;
} else {
base = ((d - s->counter_value) / s->latch);
base = (base * s->latch) + s->counter_value;
next_time = base + s->latch;
}
#ifdef DEBUG_CUDA
printf("latch=%d counter=%lld delta_next=%lld\n",
s->latch, d, next_time - d);
#endif
next_time = muldiv64(next_time, ticks_per_sec, CUDA_TIMER_FREQ) +
s->load_time;
if (next_time <= current_time)
next_time = current_time + 1;
return next_time;
}
static void cuda_timer_update(CUDAState *s, CUDATimer *ti,
int64_t current_time)
{
if (!ti->timer)
return;
if ((s->acr & T1MODE) != T1MODE_CONT) {
qemu_del_timer(ti->timer);
} else {
ti->next_irq_time = get_next_irq_time(ti, current_time);
qemu_mod_timer(ti->timer, ti->next_irq_time);
}
}
static void cuda_timer1(void *opaque)
{
CUDAState *s = opaque;
CUDATimer *ti = &s->timers[0];
cuda_timer_update(s, ti, ti->next_irq_time);
s->ifr |= T1_INT;
cuda_update_irq(s);
}
static uint32_t cuda_readb(void *opaque, target_phys_addr_t addr)
{
CUDAState *s = opaque;
uint32_t val;
addr = (addr >> 9) & 0xf;
switch(addr) {
case 0:
val = s->b;
break;
case 1:
val = s->a;
break;
case 2:
val = s->dirb;
break;
case 3:
val = s->dira;
break;
case 4:
val = get_counter(&s->timers[0]) & 0xff;
s->ifr &= ~T1_INT;
cuda_update_irq(s);
break;
case 5:
val = get_counter(&s->timers[0]) >> 8;
s->ifr &= ~T1_INT;
cuda_update_irq(s);
break;
case 6:
val = s->timers[0].latch & 0xff;
break;
case 7:
val = (s->timers[0].latch >> 8) & 0xff;
break;
case 8:
val = get_counter(&s->timers[1]) & 0xff;
break;
case 9:
val = get_counter(&s->timers[1]) >> 8;
break;
case 10:
val = s->sr;
s->ifr &= ~SR_INT;
cuda_update_irq(s);
break;
case 11:
val = s->acr;
break;
case 12:
val = s->pcr;
break;
case 13:
val = s->ifr;
break;
case 14:
val = s->ier;
break;
default:
case 15:
val = s->anh;
break;
}
#ifdef DEBUG_CUDA
if (addr != 13 || val != 0)
printf("cuda: read: reg=0x%x val=%02x\n", addr, val);
#endif
return val;
}
static void cuda_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
{
CUDAState *s = opaque;
addr = (addr >> 9) & 0xf;
#ifdef DEBUG_CUDA
printf("cuda: write: reg=0x%x val=%02x\n", addr, val);
#endif
switch(addr) {
case 0:
s->b = val;
cuda_update(s);
break;
case 1:
s->a = val;
break;
case 2:
s->dirb = val;
break;
case 3:
s->dira = val;
break;
case 4:
val = val | (get_counter(&s->timers[0]) & 0xff00);
set_counter(s, &s->timers[0], val);
break;
case 5:
val = (val << 8) | (get_counter(&s->timers[0]) & 0xff);
set_counter(s, &s->timers[0], val);
break;
case 6:
s->timers[0].latch = (s->timers[0].latch & 0xff00) | val;
cuda_timer_update(s, &s->timers[0], qemu_get_clock(vm_clock));
break;
case 7:
s->timers[0].latch = (s->timers[0].latch & 0xff) | (val << 8);
cuda_timer_update(s, &s->timers[0], qemu_get_clock(vm_clock));
break;
case 8:
val = val | (get_counter(&s->timers[1]) & 0xff00);
set_counter(s, &s->timers[1], val);
break;
case 9:
val = (val << 8) | (get_counter(&s->timers[1]) & 0xff);
set_counter(s, &s->timers[1], val);
break;
case 10:
s->sr = val;
break;
case 11:
s->acr = val;
cuda_timer_update(s, &s->timers[0], qemu_get_clock(vm_clock));
cuda_update(s);
break;
case 12:
s->pcr = val;
break;
case 13:
/* reset bits */
s->ifr &= ~val;
cuda_update_irq(s);
break;
case 14:
if (val & IER_SET) {
/* set bits */
s->ier |= val & 0x7f;
} else {
/* reset bits */
s->ier &= ~val;
}
cuda_update_irq(s);
break;
default:
case 15:
s->anh = val;
break;
}
}
/* NOTE: TIP and TREQ are negated */
static void cuda_update(CUDAState *s)
{
int packet_received, len;
packet_received = 0;
if (!(s->b & TIP)) {
/* transfer requested from host */
if (s->acr & SR_OUT) {
/* data output */
if ((s->b & (TACK | TIP)) != (s->last_b & (TACK | TIP))) {
if (s->data_out_index < sizeof(s->data_out)) {
#ifdef DEBUG_CUDA
printf("cuda: send: %02x\n", s->sr);
#endif
s->data_out[s->data_out_index++] = s->sr;
s->ifr |= SR_INT;
cuda_update_irq(s);
}
}
} else {
if (s->data_in_index < s->data_in_size) {
/* data input */
if ((s->b & (TACK | TIP)) != (s->last_b & (TACK | TIP))) {
s->sr = s->data_in[s->data_in_index++];
#ifdef DEBUG_CUDA
printf("cuda: recv: %02x\n", s->sr);
#endif
/* indicate end of transfer */
if (s->data_in_index >= s->data_in_size) {
s->b = (s->b | TREQ);
}
s->ifr |= SR_INT;
cuda_update_irq(s);
}
}
}
} else {
/* no transfer requested: handle sync case */
if ((s->last_b & TIP) && (s->b & TACK) != (s->last_b & TACK)) {
/* update TREQ state each time TACK change state */
if (s->b & TACK)
s->b = (s->b | TREQ);
else
s->b = (s->b & ~TREQ);
s->ifr |= SR_INT;
cuda_update_irq(s);
} else {
if (!(s->last_b & TIP)) {
/* handle end of host to cuda transfert */
packet_received = (s->data_out_index > 0);
/* always an IRQ at the end of transfert */
s->ifr |= SR_INT;
cuda_update_irq(s);
}
/* signal if there is data to read */
if (s->data_in_index < s->data_in_size) {
s->b = (s->b & ~TREQ);
}
}
}
s->last_acr = s->acr;
s->last_b = s->b;
/* NOTE: cuda_receive_packet_from_host() can call cuda_update()
recursively */
if (packet_received) {
len = s->data_out_index;
s->data_out_index = 0;
cuda_receive_packet_from_host(s, s->data_out, len);
}
}
static void cuda_send_packet_to_host(CUDAState *s,
const uint8_t *data, int len)
{
#ifdef DEBUG_CUDA_PACKET
{
int i;
printf("cuda_send_packet_to_host:\n");
for(i = 0; i < len; i++)
printf(" %02x", data[i]);
printf("\n");
}
#endif
memcpy(s->data_in, data, len);
s->data_in_size = len;
s->data_in_index = 0;
cuda_update(s);
s->ifr |= SR_INT;
cuda_update_irq(s);
}
static void cuda_adb_poll(void *opaque)
{
CUDAState *s = opaque;
uint8_t obuf[ADB_MAX_OUT_LEN + 2];
int olen;
olen = adb_poll(&adb_bus, obuf + 2);
if (olen > 0) {
obuf[0] = ADB_PACKET;
obuf[1] = 0x40; /* polled data */
cuda_send_packet_to_host(s, obuf, olen + 2);
}
qemu_mod_timer(s->adb_poll_timer,
qemu_get_clock(vm_clock) +
(ticks_per_sec / CUDA_ADB_POLL_FREQ));
}
static void cuda_receive_packet(CUDAState *s,
const uint8_t *data, int len)
{
uint8_t obuf[16];
int ti, autopoll;
switch(data[0]) {
case CUDA_AUTOPOLL:
autopoll = (data[1] != 0);
if (autopoll != s->autopoll) {
s->autopoll = autopoll;
if (autopoll) {
qemu_mod_timer(s->adb_poll_timer,
qemu_get_clock(vm_clock) +
(ticks_per_sec / CUDA_ADB_POLL_FREQ));
} else {
qemu_del_timer(s->adb_poll_timer);
}
}
obuf[0] = CUDA_PACKET;
obuf[1] = data[1];
cuda_send_packet_to_host(s, obuf, 2);
break;
case CUDA_GET_TIME:
/* XXX: add time support ? */
ti = time(NULL);
obuf[0] = CUDA_PACKET;
obuf[1] = 0;
obuf[2] = 0;
obuf[3] = ti >> 24;
obuf[4] = ti >> 16;
obuf[5] = ti >> 8;
obuf[6] = ti;
cuda_send_packet_to_host(s, obuf, 7);
break;
case CUDA_SET_TIME:
case CUDA_FILE_SERVER_FLAG:
case CUDA_SET_DEVICE_LIST:
case CUDA_SET_AUTO_RATE:
case CUDA_SET_POWER_MESSAGES:
obuf[0] = CUDA_PACKET;
obuf[1] = 0;
cuda_send_packet_to_host(s, obuf, 2);
break;
default:
break;
}
}
static void cuda_receive_packet_from_host(CUDAState *s,
const uint8_t *data, int len)
{
#ifdef DEBUG_CUDA_PACKET
{
int i;
printf("cuda_receive_packet_to_host:\n");
for(i = 0; i < len; i++)
printf(" %02x", data[i]);
printf("\n");
}
#endif
switch(data[0]) {
case ADB_PACKET:
{
uint8_t obuf[ADB_MAX_OUT_LEN + 2];
int olen;
olen = adb_request(&adb_bus, obuf + 2, data + 1, len - 1);
if (olen > 0) {
obuf[0] = ADB_PACKET;
obuf[1] = 0x00;
} else {
/* error */
obuf[0] = ADB_PACKET;
obuf[1] = -olen;
olen = 0;
}
cuda_send_packet_to_host(s, obuf, olen + 2);
}
break;
case CUDA_PACKET:
cuda_receive_packet(s, data + 1, len - 1);
break;
}
}
static void cuda_writew (void *opaque, target_phys_addr_t addr, uint32_t value)
{
}
static void cuda_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
{
}
static uint32_t cuda_readw (void *opaque, target_phys_addr_t addr)
{
return 0;
}
static uint32_t cuda_readl (void *opaque, target_phys_addr_t addr)
{
return 0;
}
static CPUWriteMemoryFunc *cuda_write[] = {
&cuda_writeb,
&cuda_writew,
&cuda_writel,
};
static CPUReadMemoryFunc *cuda_read[] = {
&cuda_readb,
&cuda_readw,
&cuda_readl,
};
int cuda_init(openpic_t *openpic, int irq)
{
CUDAState *s = &cuda_state;
int cuda_mem_index;
s->openpic = openpic;
s->irq = irq;
s->timers[0].timer = qemu_new_timer(vm_clock, cuda_timer1, s);
s->timers[0].latch = 0x10000;
set_counter(s, &s->timers[0], 0xffff);
s->timers[1].latch = 0x10000;
s->ier = T1_INT | SR_INT;
set_counter(s, &s->timers[1], 0xffff);
s->adb_poll_timer = qemu_new_timer(vm_clock, cuda_adb_poll, s);
cuda_mem_index = cpu_register_io_memory(0, cuda_read, cuda_write, s);
return cuda_mem_index;
}

535
hw/dma.c Normal file
View File

@@ -0,0 +1,535 @@
/*
* QEMU DMA emulation
*
* Copyright (c) 2003-2004 Vassili Karpov (malc)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "vl.h"
/* #define DEBUG_DMA */
#define dolog(...) fprintf (stderr, "dma: " __VA_ARGS__)
#ifdef DEBUG_DMA
#define lwarn(...) fprintf (stderr, "dma: " __VA_ARGS__)
#define linfo(...) fprintf (stderr, "dma: " __VA_ARGS__)
#define ldebug(...) fprintf (stderr, "dma: " __VA_ARGS__)
#else
#define lwarn(...)
#define linfo(...)
#define ldebug(...)
#endif
#define LENOFA(a) ((int) (sizeof(a)/sizeof(a[0])))
struct dma_regs {
int now[2];
uint16_t base[2];
uint8_t mode;
uint8_t page;
uint8_t pageh;
uint8_t dack;
uint8_t eop;
DMA_transfer_handler transfer_handler;
void *opaque;
};
#define ADDR 0
#define COUNT 1
static struct dma_cont {
uint8_t status;
uint8_t command;
uint8_t mask;
uint8_t flip_flop;
int dshift;
struct dma_regs regs[4];
} dma_controllers[2];
enum {
CMD_MEMORY_TO_MEMORY = 0x01,
CMD_FIXED_ADDRESS = 0x02,
CMD_BLOCK_CONTROLLER = 0x04,
CMD_COMPRESSED_TIME = 0x08,
CMD_CYCLIC_PRIORITY = 0x10,
CMD_EXTENDED_WRITE = 0x20,
CMD_LOW_DREQ = 0x40,
CMD_LOW_DACK = 0x80,
CMD_NOT_SUPPORTED = CMD_MEMORY_TO_MEMORY | CMD_FIXED_ADDRESS
| CMD_COMPRESSED_TIME | CMD_CYCLIC_PRIORITY | CMD_EXTENDED_WRITE
| CMD_LOW_DREQ | CMD_LOW_DACK
};
static int channels[8] = {-1, 2, 3, 1, -1, -1, -1, 0};
static void write_page (void *opaque, uint32_t nport, uint32_t data)
{
struct dma_cont *d = opaque;
int ichan;
ichan = channels[nport & 7];
if (-1 == ichan) {
dolog ("invalid channel %#x %#x\n", nport, data);
return;
}
d->regs[ichan].page = data;
}
static void write_pageh (void *opaque, uint32_t nport, uint32_t data)
{
struct dma_cont *d = opaque;
int ichan;
ichan = channels[nport & 7];
if (-1 == ichan) {
dolog ("invalid channel %#x %#x\n", nport, data);
return;
}
d->regs[ichan].pageh = data;
}
static uint32_t read_page (void *opaque, uint32_t nport)
{
struct dma_cont *d = opaque;
int ichan;
ichan = channels[nport & 7];
if (-1 == ichan) {
dolog ("invalid channel read %#x\n", nport);
return 0;
}
return d->regs[ichan].page;
}
static uint32_t read_pageh (void *opaque, uint32_t nport)
{
struct dma_cont *d = opaque;
int ichan;
ichan = channels[nport & 7];
if (-1 == ichan) {
dolog ("invalid channel read %#x\n", nport);
return 0;
}
return d->regs[ichan].pageh;
}
static inline void init_chan (struct dma_cont *d, int ichan)
{
struct dma_regs *r;
r = d->regs + ichan;
r->now[ADDR] = r->base[ADDR] << d->dshift;
r->now[COUNT] = 0;
}
static inline int getff (struct dma_cont *d)
{
int ff;
ff = d->flip_flop;
d->flip_flop = !ff;
return ff;
}
static uint32_t read_chan (void *opaque, uint32_t nport)
{
struct dma_cont *d = opaque;
int ichan, nreg, iport, ff, val, dir;
struct dma_regs *r;
iport = (nport >> d->dshift) & 0x0f;
ichan = iport >> 1;
nreg = iport & 1;
r = d->regs + ichan;
dir = ((r->mode >> 5) & 1) ? -1 : 1;
ff = getff (d);
if (nreg)
val = (r->base[COUNT] << d->dshift) - r->now[COUNT];
else
val = r->now[ADDR] + r->now[COUNT] * dir;
ldebug ("read_chan %#x -> %d\n", iport, val);
return (val >> (d->dshift + (ff << 3))) & 0xff;
}
static void write_chan (void *opaque, uint32_t nport, uint32_t data)
{
struct dma_cont *d = opaque;
int iport, ichan, nreg;
struct dma_regs *r;
iport = (nport >> d->dshift) & 0x0f;
ichan = iport >> 1;
nreg = iport & 1;
r = d->regs + ichan;
if (getff (d)) {
r->base[nreg] = (r->base[nreg] & 0xff) | ((data << 8) & 0xff00);
init_chan (d, ichan);
} else {
r->base[nreg] = (r->base[nreg] & 0xff00) | (data & 0xff);
}
}
static void write_cont (void *opaque, uint32_t nport, uint32_t data)
{
struct dma_cont *d = opaque;
int iport, ichan = 0;
iport = (nport >> d->dshift) & 0x0f;
switch (iport) {
case 0x08: /* command */
if ((data != 0) && (data & CMD_NOT_SUPPORTED)) {
dolog ("command %#x not supported\n", data);
return;
}
d->command = data;
break;
case 0x09:
ichan = data & 3;
if (data & 4) {
d->status |= 1 << (ichan + 4);
}
else {
d->status &= ~(1 << (ichan + 4));
}
d->status &= ~(1 << ichan);
break;
case 0x0a: /* single mask */
if (data & 4)
d->mask |= 1 << (data & 3);
else
d->mask &= ~(1 << (data & 3));
break;
case 0x0b: /* mode */
{
ichan = data & 3;
#ifdef DEBUG_DMA
{
int op, ai, dir, opmode;
op = (data >> 2) & 3;
ai = (data >> 4) & 1;
dir = (data >> 5) & 1;
opmode = (data >> 6) & 3;
linfo ("ichan %d, op %d, ai %d, dir %d, opmode %d\n",
ichan, op, ai, dir, opmode);
}
#endif
d->regs[ichan].mode = data;
break;
}
case 0x0c: /* clear flip flop */
d->flip_flop = 0;
break;
case 0x0d: /* reset */
d->flip_flop = 0;
d->mask = ~0;
d->status = 0;
d->command = 0;
break;
case 0x0e: /* clear mask for all channels */
d->mask = 0;
break;
case 0x0f: /* write mask for all channels */
d->mask = data;
break;
default:
dolog ("unknown iport %#x\n", iport);
break;
}
#ifdef DEBUG_DMA
if (0xc != iport) {
linfo ("write_cont: nport %#06x, ichan % 2d, val %#06x\n",
nport, ichan, data);
}
#endif
}
static uint32_t read_cont (void *opaque, uint32_t nport)
{
struct dma_cont *d = opaque;
int iport, val;
iport = (nport >> d->dshift) & 0x0f;
switch (iport) {
case 0x08: /* status */
val = d->status;
d->status &= 0xf0;
break;
case 0x0f: /* mask */
val = d->mask;
break;
default:
val = 0;
break;
}
ldebug ("read_cont: nport %#06x, iport %#04x val %#x\n", nport, iport, val);
return val;
}
int DMA_get_channel_mode (int nchan)
{
return dma_controllers[nchan > 3].regs[nchan & 3].mode;
}
void DMA_hold_DREQ (int nchan)
{
int ncont, ichan;
ncont = nchan > 3;
ichan = nchan & 3;
linfo ("held cont=%d chan=%d\n", ncont, ichan);
dma_controllers[ncont].status |= 1 << (ichan + 4);
}
void DMA_release_DREQ (int nchan)
{
int ncont, ichan;
ncont = nchan > 3;
ichan = nchan & 3;
linfo ("released cont=%d chan=%d\n", ncont, ichan);
dma_controllers[ncont].status &= ~(1 << (ichan + 4));
}
static void channel_run (int ncont, int ichan)
{
int n;
struct dma_regs *r = &dma_controllers[ncont].regs[ichan];
#ifdef DEBUG_DMA
int dir, opmode;
dir = (r->mode >> 5) & 1;
opmode = (r->mode >> 6) & 3;
if (dir) {
dolog ("DMA in address decrement mode\n");
}
if (opmode != 1) {
dolog ("DMA not in single mode select %#x\n", opmode);
}
#endif
r = dma_controllers[ncont].regs + ichan;
n = r->transfer_handler (r->opaque, ichan + (ncont << 2),
r->now[COUNT], (r->base[COUNT] + 1) << ncont);
r->now[COUNT] = n;
ldebug ("dma_pos %d size %d\n", n, (r->base[COUNT] + 1) << ncont);
}
void DMA_run (void)
{
struct dma_cont *d;
int icont, ichan;
d = dma_controllers;
for (icont = 0; icont < 2; icont++, d++) {
for (ichan = 0; ichan < 4; ichan++) {
int mask;
mask = 1 << ichan;
if ((0 == (d->mask & mask)) && (0 != (d->status & (mask << 4))))
channel_run (icont, ichan);
}
}
}
void DMA_register_channel (int nchan,
DMA_transfer_handler transfer_handler,
void *opaque)
{
struct dma_regs *r;
int ichan, ncont;
ncont = nchan > 3;
ichan = nchan & 3;
r = dma_controllers[ncont].regs + ichan;
r->transfer_handler = transfer_handler;
r->opaque = opaque;
}
int DMA_read_memory (int nchan, void *buf, int pos, int len)
{
struct dma_regs *r = &dma_controllers[nchan > 3].regs[nchan & 3];
target_ulong addr = ((r->pageh & 0x7f) << 24) | (r->page << 16) | r->now[ADDR];
if (r->mode & 0x20) {
int i;
uint8_t *p = buf;
cpu_physical_memory_read (addr - pos - len, buf, len);
/* What about 16bit transfers? */
for (i = 0; i < len >> 1; i++) {
uint8_t b = p[len - i - 1];
p[i] = b;
}
}
else
cpu_physical_memory_read (addr + pos, buf, len);
return len;
}
int DMA_write_memory (int nchan, void *buf, int pos, int len)
{
struct dma_regs *r = &dma_controllers[nchan > 3].regs[nchan & 3];
target_ulong addr = ((r->pageh & 0x7f) << 24) | (r->page << 16) | r->now[ADDR];
if (r->mode & 0x20) {
int i;
uint8_t *p = buf;
cpu_physical_memory_write (addr - pos - len, buf, len);
/* What about 16bit transfers? */
for (i = 0; i < len; i++) {
uint8_t b = p[len - i - 1];
p[i] = b;
}
}
else
cpu_physical_memory_write (addr + pos, buf, len);
return len;
}
/* request the emulator to transfer a new DMA memory block ASAP */
void DMA_schedule(int nchan)
{
cpu_interrupt(cpu_single_env, CPU_INTERRUPT_EXIT);
}
static void dma_reset(void *opaque)
{
struct dma_cont *d = opaque;
write_cont (d, (0x0d << d->dshift), 0);
}
/* dshift = 0: 8 bit DMA, 1 = 16 bit DMA */
static void dma_init2(struct dma_cont *d, int base, int dshift,
int page_base, int pageh_base)
{
const static int page_port_list[] = { 0x1, 0x2, 0x3, 0x7 };
int i;
d->dshift = dshift;
for (i = 0; i < 8; i++) {
register_ioport_write (base + (i << dshift), 1, 1, write_chan, d);
register_ioport_read (base + (i << dshift), 1, 1, read_chan, d);
}
for (i = 0; i < LENOFA (page_port_list); i++) {
register_ioport_write (page_base + page_port_list[i], 1, 1,
write_page, d);
register_ioport_read (page_base + page_port_list[i], 1, 1,
read_page, d);
if (pageh_base >= 0) {
register_ioport_write (pageh_base + page_port_list[i], 1, 1,
write_pageh, d);
register_ioport_read (pageh_base + page_port_list[i], 1, 1,
read_pageh, d);
}
}
for (i = 0; i < 8; i++) {
register_ioport_write (base + ((i + 8) << dshift), 1, 1,
write_cont, d);
register_ioport_read (base + ((i + 8) << dshift), 1, 1,
read_cont, d);
}
qemu_register_reset(dma_reset, d);
dma_reset(d);
}
static void dma_save (QEMUFile *f, void *opaque)
{
struct dma_cont *d = opaque;
int i;
/* qemu_put_8s (f, &d->status); */
qemu_put_8s (f, &d->command);
qemu_put_8s (f, &d->mask);
qemu_put_8s (f, &d->flip_flop);
qemu_put_be32s (f, &d->dshift);
for (i = 0; i < 4; ++i) {
struct dma_regs *r = &d->regs[i];
qemu_put_be32s (f, &r->now[0]);
qemu_put_be32s (f, &r->now[1]);
qemu_put_be16s (f, &r->base[0]);
qemu_put_be16s (f, &r->base[1]);
qemu_put_8s (f, &r->mode);
qemu_put_8s (f, &r->page);
qemu_put_8s (f, &r->pageh);
qemu_put_8s (f, &r->dack);
qemu_put_8s (f, &r->eop);
}
}
static int dma_load (QEMUFile *f, void *opaque, int version_id)
{
struct dma_cont *d = opaque;
int i;
if (version_id != 1)
return -EINVAL;
/* qemu_get_8s (f, &d->status); */
qemu_get_8s (f, &d->command);
qemu_get_8s (f, &d->mask);
qemu_get_8s (f, &d->flip_flop);
qemu_get_be32s (f, &d->dshift);
for (i = 0; i < 4; ++i) {
struct dma_regs *r = &d->regs[i];
qemu_get_be32s (f, &r->now[0]);
qemu_get_be32s (f, &r->now[1]);
qemu_get_be16s (f, &r->base[0]);
qemu_get_be16s (f, &r->base[1]);
qemu_get_8s (f, &r->mode);
qemu_get_8s (f, &r->page);
qemu_get_8s (f, &r->pageh);
qemu_get_8s (f, &r->dack);
qemu_get_8s (f, &r->eop);
}
return 0;
}
void DMA_init (int high_page_enable)
{
dma_init2(&dma_controllers[0], 0x00, 0, 0x80,
high_page_enable ? 0x480 : -1);
dma_init2(&dma_controllers[1], 0xc0, 1, 0x88,
high_page_enable ? 0x488 : -1);
register_savevm ("dma", 0, 1, dma_save, dma_load, &dma_controllers[0]);
register_savevm ("dma", 1, 1, dma_save, dma_load, &dma_controllers[1]);
}

1719
hw/fdc.c Normal file

File diff suppressed because it is too large Load Diff

1390
hw/fmopl.c Normal file

File diff suppressed because it is too large Load Diff

174
hw/fmopl.h Normal file
View File

@@ -0,0 +1,174 @@
#ifndef __FMOPL_H_
#define __FMOPL_H_
/* --- select emulation chips --- */
#define BUILD_YM3812 (HAS_YM3812)
//#define BUILD_YM3526 (HAS_YM3526)
//#define BUILD_Y8950 (HAS_Y8950)
/* --- system optimize --- */
/* select bit size of output : 8 or 16 */
#define OPL_OUTPUT_BIT 16
/* compiler dependence */
#ifndef OSD_CPU_H
#define OSD_CPU_H
typedef unsigned char UINT8; /* unsigned 8bit */
typedef unsigned short UINT16; /* unsigned 16bit */
typedef unsigned int UINT32; /* unsigned 32bit */
typedef signed char INT8; /* signed 8bit */
typedef signed short INT16; /* signed 16bit */
typedef signed int INT32; /* signed 32bit */
#endif
#if (OPL_OUTPUT_BIT==16)
typedef INT16 OPLSAMPLE;
#endif
#if (OPL_OUTPUT_BIT==8)
typedef unsigned char OPLSAMPLE;
#endif
#if BUILD_Y8950
#include "ymdeltat.h"
#endif
typedef void (*OPL_TIMERHANDLER)(int channel,double interval_Sec);
typedef void (*OPL_IRQHANDLER)(int param,int irq);
typedef void (*OPL_UPDATEHANDLER)(int param,int min_interval_us);
typedef void (*OPL_PORTHANDLER_W)(int param,unsigned char data);
typedef unsigned char (*OPL_PORTHANDLER_R)(int param);
/* !!!!! here is private section , do not access there member direct !!!!! */
#define OPL_TYPE_WAVESEL 0x01 /* waveform select */
#define OPL_TYPE_ADPCM 0x02 /* DELTA-T ADPCM unit */
#define OPL_TYPE_KEYBOARD 0x04 /* keyboard interface */
#define OPL_TYPE_IO 0x08 /* I/O port */
/* Saving is necessary for member of the 'R' mark for suspend/resume */
/* ---------- OPL one of slot ---------- */
typedef struct fm_opl_slot {
INT32 TL; /* total level :TL << 8 */
INT32 TLL; /* adjusted now TL */
UINT8 KSR; /* key scale rate :(shift down bit) */
INT32 *AR; /* attack rate :&AR_TABLE[AR<<2] */
INT32 *DR; /* decay rate :&DR_TALBE[DR<<2] */
INT32 SL; /* sustin level :SL_TALBE[SL] */
INT32 *RR; /* release rate :&DR_TABLE[RR<<2] */
UINT8 ksl; /* keyscale level :(shift down bits) */
UINT8 ksr; /* key scale rate :kcode>>KSR */
UINT32 mul; /* multiple :ML_TABLE[ML] */
UINT32 Cnt; /* frequency count : */
UINT32 Incr; /* frequency step : */
/* envelope generator state */
UINT8 eg_typ; /* envelope type flag */
UINT8 evm; /* envelope phase */
INT32 evc; /* envelope counter */
INT32 eve; /* envelope counter end point */
INT32 evs; /* envelope counter step */
INT32 evsa; /* envelope step for AR :AR[ksr] */
INT32 evsd; /* envelope step for DR :DR[ksr] */
INT32 evsr; /* envelope step for RR :RR[ksr] */
/* LFO */
UINT8 ams; /* ams flag */
UINT8 vib; /* vibrate flag */
/* wave selector */
INT32 **wavetable;
}OPL_SLOT;
/* ---------- OPL one of channel ---------- */
typedef struct fm_opl_channel {
OPL_SLOT SLOT[2];
UINT8 CON; /* connection type */
UINT8 FB; /* feed back :(shift down bit) */
INT32 *connect1; /* slot1 output pointer */
INT32 *connect2; /* slot2 output pointer */
INT32 op1_out[2]; /* slot1 output for selfeedback */
/* phase generator state */
UINT32 block_fnum; /* block+fnum : */
UINT8 kcode; /* key code : KeyScaleCode */
UINT32 fc; /* Freq. Increment base */
UINT32 ksl_base; /* KeyScaleLevel Base step */
UINT8 keyon; /* key on/off flag */
} OPL_CH;
/* OPL state */
typedef struct fm_opl_f {
UINT8 type; /* chip type */
int clock; /* master clock (Hz) */
int rate; /* sampling rate (Hz) */
double freqbase; /* frequency base */
double TimerBase; /* Timer base time (==sampling time) */
UINT8 address; /* address register */
UINT8 status; /* status flag */
UINT8 statusmask; /* status mask */
UINT32 mode; /* Reg.08 : CSM , notesel,etc. */
/* Timer */
int T[2]; /* timer counter */
UINT8 st[2]; /* timer enable */
/* FM channel slots */
OPL_CH *P_CH; /* pointer of CH */
int max_ch; /* maximum channel */
/* Rythm sention */
UINT8 rythm; /* Rythm mode , key flag */
#if BUILD_Y8950
/* Delta-T ADPCM unit (Y8950) */
YM_DELTAT *deltat; /* DELTA-T ADPCM */
#endif
/* Keyboard / I/O interface unit (Y8950) */
UINT8 portDirection;
UINT8 portLatch;
OPL_PORTHANDLER_R porthandler_r;
OPL_PORTHANDLER_W porthandler_w;
int port_param;
OPL_PORTHANDLER_R keyboardhandler_r;
OPL_PORTHANDLER_W keyboardhandler_w;
int keyboard_param;
/* time tables */
INT32 AR_TABLE[75]; /* atttack rate tables */
INT32 DR_TABLE[75]; /* decay rate tables */
UINT32 FN_TABLE[1024]; /* fnumber -> increment counter */
/* LFO */
INT32 *ams_table;
INT32 *vib_table;
INT32 amsCnt;
INT32 amsIncr;
INT32 vibCnt;
INT32 vibIncr;
/* wave selector enable flag */
UINT8 wavesel;
/* external event callback handler */
OPL_TIMERHANDLER TimerHandler; /* TIMER handler */
int TimerParam; /* TIMER parameter */
OPL_IRQHANDLER IRQHandler; /* IRQ handler */
int IRQParam; /* IRQ parameter */
OPL_UPDATEHANDLER UpdateHandler; /* stream update handler */
int UpdateParam; /* stream update parameter */
} FM_OPL;
/* ---------- Generic interface section ---------- */
#define OPL_TYPE_YM3526 (0)
#define OPL_TYPE_YM3812 (OPL_TYPE_WAVESEL)
#define OPL_TYPE_Y8950 (OPL_TYPE_ADPCM|OPL_TYPE_KEYBOARD|OPL_TYPE_IO)
FM_OPL *OPLCreate(int type, int clock, int rate);
void OPLDestroy(FM_OPL *OPL);
void OPLSetTimerHandler(FM_OPL *OPL,OPL_TIMERHANDLER TimerHandler,int channelOffset);
void OPLSetIRQHandler(FM_OPL *OPL,OPL_IRQHANDLER IRQHandler,int param);
void OPLSetUpdateHandler(FM_OPL *OPL,OPL_UPDATEHANDLER UpdateHandler,int param);
/* Y8950 port handlers */
void OPLSetPortHandler(FM_OPL *OPL,OPL_PORTHANDLER_W PortHandler_w,OPL_PORTHANDLER_R PortHandler_r,int param);
void OPLSetKeyboardHandler(FM_OPL *OPL,OPL_PORTHANDLER_W KeyboardHandler_w,OPL_PORTHANDLER_R KeyboardHandler_r,int param);
void OPLResetChip(FM_OPL *OPL);
int OPLWrite(FM_OPL *OPL,int a,int v);
unsigned char OPLRead(FM_OPL *OPL,int a);
int OPLTimerOver(FM_OPL *OPL,int c);
/* YM3626/YM3812 local section */
void YM3812UpdateOne(FM_OPL *OPL, INT16 *buffer, int length);
void Y8950UpdateOne(FM_OPL *OPL, INT16 *buffer, int length);
#endif

470
hw/i8254.c Normal file
View File

@@ -0,0 +1,470 @@
/*
* QEMU 8253/8254 interval timer emulation
*
* Copyright (c) 2003-2004 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 "vl.h"
//#define DEBUG_PIT
#define RW_STATE_LSB 1
#define RW_STATE_MSB 2
#define RW_STATE_WORD0 3
#define RW_STATE_WORD1 4
typedef struct PITChannelState {
int count; /* can be 65536 */
uint16_t latched_count;
uint8_t count_latched;
uint8_t status_latched;
uint8_t status;
uint8_t read_state;
uint8_t write_state;
uint8_t write_latch;
uint8_t rw_mode;
uint8_t mode;
uint8_t bcd; /* not supported */
uint8_t gate; /* timer start */
int64_t count_load_time;
/* irq handling */
int64_t next_transition_time;
QEMUTimer *irq_timer;
int irq;
} PITChannelState;
struct PITState {
PITChannelState channels[3];
};
static PITState pit_state;
static void pit_irq_timer_update(PITChannelState *s, int64_t current_time);
static int pit_get_count(PITChannelState *s)
{
uint64_t d;
int counter;
d = muldiv64(qemu_get_clock(vm_clock) - s->count_load_time, PIT_FREQ, ticks_per_sec);
switch(s->mode) {
case 0:
case 1:
case 4:
case 5:
counter = (s->count - d) & 0xffff;
break;
case 3:
/* XXX: may be incorrect for odd counts */
counter = s->count - ((2 * d) % s->count);
break;
default:
counter = s->count - (d % s->count);
break;
}
return counter;
}
/* get pit output bit */
static int pit_get_out1(PITChannelState *s, int64_t current_time)
{
uint64_t d;
int out;
d = muldiv64(current_time - s->count_load_time, PIT_FREQ, ticks_per_sec);
switch(s->mode) {
default:
case 0:
out = (d >= s->count);
break;
case 1:
out = (d < s->count);
break;
case 2:
if ((d % s->count) == 0 && d != 0)
out = 1;
else
out = 0;
break;
case 3:
out = (d % s->count) < ((s->count + 1) >> 1);
break;
case 4:
case 5:
out = (d == s->count);
break;
}
return out;
}
int pit_get_out(PITState *pit, int channel, int64_t current_time)
{
PITChannelState *s = &pit->channels[channel];
return pit_get_out1(s, current_time);
}
/* return -1 if no transition will occur. */
static int64_t pit_get_next_transition_time(PITChannelState *s,
int64_t current_time)
{
uint64_t d, next_time, base;
int period2;
d = muldiv64(current_time - s->count_load_time, PIT_FREQ, ticks_per_sec);
switch(s->mode) {
default:
case 0:
case 1:
if (d < s->count)
next_time = s->count;
else
return -1;
break;
case 2:
base = (d / s->count) * s->count;
if ((d - base) == 0 && d != 0)
next_time = base + s->count;
else
next_time = base + s->count + 1;
break;
case 3:
base = (d / s->count) * s->count;
period2 = ((s->count + 1) >> 1);
if ((d - base) < period2)
next_time = base + period2;
else
next_time = base + s->count;
break;
case 4:
case 5:
if (d < s->count)
next_time = s->count;
else if (d == s->count)
next_time = s->count + 1;
else
return -1;
break;
}
/* convert to timer units */
next_time = s->count_load_time + muldiv64(next_time, ticks_per_sec, PIT_FREQ);
/* fix potential rounding problems */
/* XXX: better solution: use a clock at PIT_FREQ Hz */
if (next_time <= current_time)
next_time = current_time + 1;
return next_time;
}
/* val must be 0 or 1 */
void pit_set_gate(PITState *pit, int channel, int val)
{
PITChannelState *s = &pit->channels[channel];
switch(s->mode) {
default:
case 0:
case 4:
/* XXX: just disable/enable counting */
break;
case 1:
case 5:
if (s->gate < val) {
/* restart counting on rising edge */
s->count_load_time = qemu_get_clock(vm_clock);
pit_irq_timer_update(s, s->count_load_time);
}
break;
case 2:
case 3:
if (s->gate < val) {
/* restart counting on rising edge */
s->count_load_time = qemu_get_clock(vm_clock);
pit_irq_timer_update(s, s->count_load_time);
}
/* XXX: disable/enable counting */
break;
}
s->gate = val;
}
int pit_get_gate(PITState *pit, int channel)
{
PITChannelState *s = &pit->channels[channel];
return s->gate;
}
static inline void pit_load_count(PITChannelState *s, int val)
{
if (val == 0)
val = 0x10000;
s->count_load_time = qemu_get_clock(vm_clock);
s->count = val;
pit_irq_timer_update(s, s->count_load_time);
}
/* if already latched, do not latch again */
static void pit_latch_count(PITChannelState *s)
{
if (!s->count_latched) {
s->latched_count = pit_get_count(s);
s->count_latched = s->rw_mode;
}
}
static void pit_ioport_write(void *opaque, uint32_t addr, uint32_t val)
{
PITState *pit = opaque;
int channel, access;
PITChannelState *s;
addr &= 3;
if (addr == 3) {
channel = val >> 6;
if (channel == 3) {
/* read back command */
for(channel = 0; channel < 3; channel++) {
s = &pit->channels[channel];
if (val & (2 << channel)) {
if (!(val & 0x20)) {
pit_latch_count(s);
}
if (!(val & 0x10) && !s->status_latched) {
/* status latch */
/* XXX: add BCD and null count */
s->status = (pit_get_out1(s, qemu_get_clock(vm_clock)) << 7) |
(s->rw_mode << 4) |
(s->mode << 1) |
s->bcd;
s->status_latched = 1;
}
}
}
} else {
s = &pit->channels[channel];
access = (val >> 4) & 3;
if (access == 0) {
pit_latch_count(s);
} else {
s->rw_mode = access;
s->read_state = access;
s->write_state = access;
s->mode = (val >> 1) & 7;
s->bcd = val & 1;
/* XXX: update irq timer ? */
}
}
} else {
s = &pit->channels[addr];
switch(s->write_state) {
default:
case RW_STATE_LSB:
pit_load_count(s, val);
break;
case RW_STATE_MSB:
pit_load_count(s, val << 8);
break;
case RW_STATE_WORD0:
s->write_latch = val;
s->write_state = RW_STATE_WORD1;
break;
case RW_STATE_WORD1:
pit_load_count(s, s->write_latch | (val << 8));
s->write_state = RW_STATE_WORD0;
break;
}
}
}
static uint32_t pit_ioport_read(void *opaque, uint32_t addr)
{
PITState *pit = opaque;
int ret, count;
PITChannelState *s;
addr &= 3;
s = &pit->channels[addr];
if (s->status_latched) {
s->status_latched = 0;
ret = s->status;
} else if (s->count_latched) {
switch(s->count_latched) {
default:
case RW_STATE_LSB:
ret = s->latched_count & 0xff;
s->count_latched = 0;
break;
case RW_STATE_MSB:
ret = s->latched_count >> 8;
s->count_latched = 0;
break;
case RW_STATE_WORD0:
ret = s->latched_count & 0xff;
s->count_latched = RW_STATE_MSB;
break;
}
} else {
switch(s->read_state) {
default:
case RW_STATE_LSB:
count = pit_get_count(s);
ret = count & 0xff;
break;
case RW_STATE_MSB:
count = pit_get_count(s);
ret = (count >> 8) & 0xff;
break;
case RW_STATE_WORD0:
count = pit_get_count(s);
ret = count & 0xff;
s->read_state = RW_STATE_WORD1;
break;
case RW_STATE_WORD1:
count = pit_get_count(s);
ret = (count >> 8) & 0xff;
s->read_state = RW_STATE_WORD0;
break;
}
}
return ret;
}
static void pit_irq_timer_update(PITChannelState *s, int64_t current_time)
{
int64_t expire_time;
int irq_level;
if (!s->irq_timer)
return;
expire_time = pit_get_next_transition_time(s, current_time);
irq_level = pit_get_out1(s, current_time);
pic_set_irq(s->irq, irq_level);
#ifdef DEBUG_PIT
printf("irq_level=%d next_delay=%f\n",
irq_level,
(double)(expire_time - current_time) / ticks_per_sec);
#endif
s->next_transition_time = expire_time;
if (expire_time != -1)
qemu_mod_timer(s->irq_timer, expire_time);
else
qemu_del_timer(s->irq_timer);
}
static void pit_irq_timer(void *opaque)
{
PITChannelState *s = opaque;
pit_irq_timer_update(s, s->next_transition_time);
}
static void pit_save(QEMUFile *f, void *opaque)
{
PITState *pit = opaque;
PITChannelState *s;
int i;
for(i = 0; i < 3; i++) {
s = &pit->channels[i];
qemu_put_be32s(f, &s->count);
qemu_put_be16s(f, &s->latched_count);
qemu_put_8s(f, &s->count_latched);
qemu_put_8s(f, &s->status_latched);
qemu_put_8s(f, &s->status);
qemu_put_8s(f, &s->read_state);
qemu_put_8s(f, &s->write_state);
qemu_put_8s(f, &s->write_latch);
qemu_put_8s(f, &s->rw_mode);
qemu_put_8s(f, &s->mode);
qemu_put_8s(f, &s->bcd);
qemu_put_8s(f, &s->gate);
qemu_put_be64s(f, &s->count_load_time);
if (s->irq_timer) {
qemu_put_be64s(f, &s->next_transition_time);
qemu_put_timer(f, s->irq_timer);
}
}
}
static int pit_load(QEMUFile *f, void *opaque, int version_id)
{
PITState *pit = opaque;
PITChannelState *s;
int i;
if (version_id != 1)
return -EINVAL;
for(i = 0; i < 3; i++) {
s = &pit->channels[i];
qemu_get_be32s(f, &s->count);
qemu_get_be16s(f, &s->latched_count);
qemu_get_8s(f, &s->count_latched);
qemu_get_8s(f, &s->status_latched);
qemu_get_8s(f, &s->status);
qemu_get_8s(f, &s->read_state);
qemu_get_8s(f, &s->write_state);
qemu_get_8s(f, &s->write_latch);
qemu_get_8s(f, &s->rw_mode);
qemu_get_8s(f, &s->mode);
qemu_get_8s(f, &s->bcd);
qemu_get_8s(f, &s->gate);
qemu_get_be64s(f, &s->count_load_time);
if (s->irq_timer) {
qemu_get_be64s(f, &s->next_transition_time);
qemu_get_timer(f, s->irq_timer);
}
}
return 0;
}
static void pit_reset(void *opaque)
{
PITState *pit = opaque;
PITChannelState *s;
int i;
for(i = 0;i < 3; i++) {
s = &pit->channels[i];
s->mode = 3;
s->gate = (i != 2);
pit_load_count(s, 0);
}
}
PITState *pit_init(int base, int irq)
{
PITState *pit = &pit_state;
PITChannelState *s;
s = &pit->channels[0];
/* the timer 0 is connected to an IRQ */
s->irq_timer = qemu_new_timer(vm_clock, pit_irq_timer, s);
s->irq = irq;
register_savevm("i8254", base, 1, pit_save, pit_load, pit);
qemu_register_reset(pit_reset, pit);
register_ioport_write(base, 4, 1, pit_ioport_write, pit);
register_ioport_read(base, 3, 1, pit_ioport_read, pit);
pit_reset(pit);
return pit;
}

512
hw/i8259.c Normal file
View File

@@ -0,0 +1,512 @@
/*
* QEMU 8259 interrupt controller emulation
*
* Copyright (c) 2003-2004 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 "vl.h"
/* debug PIC */
//#define DEBUG_PIC
//#define DEBUG_IRQ_LATENCY
//#define DEBUG_IRQ_COUNT
typedef struct PicState {
uint8_t last_irr; /* edge detection */
uint8_t irr; /* interrupt request register */
uint8_t imr; /* interrupt mask register */
uint8_t isr; /* interrupt service register */
uint8_t priority_add; /* highest irq priority */
uint8_t irq_base;
uint8_t read_reg_select;
uint8_t poll;
uint8_t special_mask;
uint8_t init_state;
uint8_t auto_eoi;
uint8_t rotate_on_auto_eoi;
uint8_t special_fully_nested_mode;
uint8_t init4; /* true if 4 byte init */
uint8_t elcr; /* PIIX edge/trigger selection*/
uint8_t elcr_mask;
} PicState;
/* 0 is master pic, 1 is slave pic */
static PicState pics[2];
#if defined(DEBUG_PIC) || defined (DEBUG_IRQ_COUNT)
static int irq_level[16];
#endif
#ifdef DEBUG_IRQ_COUNT
static uint64_t irq_count[16];
#endif
/* set irq level. If an edge is detected, then the IRR is set to 1 */
static inline void pic_set_irq1(PicState *s, int irq, int level)
{
int mask;
mask = 1 << irq;
if (s->elcr & mask) {
/* level triggered */
if (level) {
s->irr |= mask;
s->last_irr |= mask;
} else {
s->irr &= ~mask;
s->last_irr &= ~mask;
}
} else {
/* edge triggered */
if (level) {
if ((s->last_irr & mask) == 0)
s->irr |= mask;
s->last_irr |= mask;
} else {
s->last_irr &= ~mask;
}
}
}
/* return the highest priority found in mask (highest = smallest
number). Return 8 if no irq */
static inline int get_priority(PicState *s, int mask)
{
int priority;
if (mask == 0)
return 8;
priority = 0;
while ((mask & (1 << ((priority + s->priority_add) & 7))) == 0)
priority++;
return priority;
}
/* return the pic wanted interrupt. return -1 if none */
static int pic_get_irq(PicState *s)
{
int mask, cur_priority, priority;
mask = s->irr & ~s->imr;
priority = get_priority(s, mask);
if (priority == 8)
return -1;
/* compute current priority. If special fully nested mode on the
master, the IRQ coming from the slave is not taken into account
for the priority computation. */
mask = s->isr;
if (s->special_fully_nested_mode && s == &pics[0])
mask &= ~(1 << 2);
cur_priority = get_priority(s, mask);
if (priority < cur_priority) {
/* higher priority found: an irq should be generated */
return (priority + s->priority_add) & 7;
} else {
return -1;
}
}
/* raise irq to CPU if necessary. must be called every time the active
irq may change */
static void pic_update_irq(void)
{
int irq2, irq;
/* first look at slave pic */
irq2 = pic_get_irq(&pics[1]);
if (irq2 >= 0) {
/* if irq request by slave pic, signal master PIC */
pic_set_irq1(&pics[0], 2, 1);
pic_set_irq1(&pics[0], 2, 0);
}
/* look at requested irq */
irq = pic_get_irq(&pics[0]);
if (irq >= 0) {
#if defined(DEBUG_PIC)
{
int i;
for(i = 0; i < 2; i++) {
printf("pic%d: imr=%x irr=%x padd=%d\n",
i, pics[i].imr, pics[i].irr, pics[i].priority_add);
}
}
printf("pic: cpu_interrupt\n");
#endif
cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HARD);
}
}
#ifdef DEBUG_IRQ_LATENCY
int64_t irq_time[16];
#endif
void pic_set_irq(int irq, int level)
{
#if defined(DEBUG_PIC) || defined(DEBUG_IRQ_COUNT)
if (level != irq_level[irq]) {
#if defined(DEBUG_PIC)
printf("pic_set_irq: irq=%d level=%d\n", irq, level);
#endif
irq_level[irq] = level;
#ifdef DEBUG_IRQ_COUNT
if (level == 1)
irq_count[irq]++;
#endif
}
#endif
#ifdef DEBUG_IRQ_LATENCY
if (level) {
irq_time[irq] = qemu_get_clock(vm_clock);
}
#endif
pic_set_irq1(&pics[irq >> 3], irq & 7, level);
pic_update_irq();
}
/* acknowledge interrupt 'irq' */
static inline void pic_intack(PicState *s, int irq)
{
if (s->auto_eoi) {
if (s->rotate_on_auto_eoi)
s->priority_add = (irq + 1) & 7;
} else {
s->isr |= (1 << irq);
}
/* We don't clear a level sensitive interrupt here */
if (!(s->elcr & (1 << irq)))
s->irr &= ~(1 << irq);
}
int cpu_get_pic_interrupt(CPUState *env)
{
int irq, irq2, intno;
/* read the irq from the PIC */
irq = pic_get_irq(&pics[0]);
if (irq >= 0) {
pic_intack(&pics[0], irq);
if (irq == 2) {
irq2 = pic_get_irq(&pics[1]);
if (irq2 >= 0) {
pic_intack(&pics[1], irq2);
} else {
/* spurious IRQ on slave controller */
irq2 = 7;
}
intno = pics[1].irq_base + irq2;
irq = irq2 + 8;
} else {
intno = pics[0].irq_base + irq;
}
} else {
/* spurious IRQ on host controller */
irq = 7;
intno = pics[0].irq_base + irq;
}
pic_update_irq();
#ifdef DEBUG_IRQ_LATENCY
printf("IRQ%d latency=%0.3fus\n",
irq,
(double)(qemu_get_clock(vm_clock) - irq_time[irq]) * 1000000.0 / ticks_per_sec);
#endif
#if defined(DEBUG_PIC)
printf("pic_interrupt: irq=%d\n", irq);
#endif
return intno;
}
static void pic_reset(void *opaque)
{
PicState *s = opaque;
int tmp;
tmp = s->elcr_mask;
memset(s, 0, sizeof(PicState));
s->elcr_mask = tmp;
}
static void pic_ioport_write(void *opaque, uint32_t addr, uint32_t val)
{
PicState *s = opaque;
int priority, cmd, irq;
#ifdef DEBUG_PIC
printf("pic_write: addr=0x%02x val=0x%02x\n", addr, val);
#endif
addr &= 1;
if (addr == 0) {
if (val & 0x10) {
/* init */
pic_reset(s);
/* deassert a pending interrupt */
cpu_reset_interrupt(cpu_single_env, CPU_INTERRUPT_HARD);
s->init_state = 1;
s->init4 = val & 1;
if (val & 0x02)
hw_error("single mode not supported");
if (val & 0x08)
hw_error("level sensitive irq not supported");
} else if (val & 0x08) {
if (val & 0x04)
s->poll = 1;
if (val & 0x02)
s->read_reg_select = val & 1;
if (val & 0x40)
s->special_mask = (val >> 5) & 1;
} else {
cmd = val >> 5;
switch(cmd) {
case 0:
case 4:
s->rotate_on_auto_eoi = cmd >> 2;
break;
case 1: /* end of interrupt */
case 5:
priority = get_priority(s, s->isr);
if (priority != 8) {
irq = (priority + s->priority_add) & 7;
s->isr &= ~(1 << irq);
if (cmd == 5)
s->priority_add = (irq + 1) & 7;
pic_update_irq();
}
break;
case 3:
irq = val & 7;
s->isr &= ~(1 << irq);
pic_update_irq();
break;
case 6:
s->priority_add = (val + 1) & 7;
pic_update_irq();
break;
case 7:
irq = val & 7;
s->isr &= ~(1 << irq);
s->priority_add = (irq + 1) & 7;
pic_update_irq();
break;
default:
/* no operation */
break;
}
}
} else {
switch(s->init_state) {
case 0:
/* normal mode */
s->imr = val;
pic_update_irq();
break;
case 1:
s->irq_base = val & 0xf8;
s->init_state = 2;
break;
case 2:
if (s->init4) {
s->init_state = 3;
} else {
s->init_state = 0;
}
break;
case 3:
s->special_fully_nested_mode = (val >> 4) & 1;
s->auto_eoi = (val >> 1) & 1;
s->init_state = 0;
break;
}
}
}
static uint32_t pic_poll_read (PicState *s, uint32_t addr1)
{
int ret;
ret = pic_get_irq(s);
if (ret >= 0) {
if (addr1 >> 7) {
pics[0].isr &= ~(1 << 2);
pics[0].irr &= ~(1 << 2);
}
s->irr &= ~(1 << ret);
s->isr &= ~(1 << ret);
if (addr1 >> 7 || ret != 2)
pic_update_irq();
} else {
ret = 0x07;
pic_update_irq();
}
return ret;
}
static uint32_t pic_ioport_read(void *opaque, uint32_t addr1)
{
PicState *s = opaque;
unsigned int addr;
int ret;
addr = addr1;
addr &= 1;
if (s->poll) {
ret = pic_poll_read(s, addr1);
s->poll = 0;
} else {
if (addr == 0) {
if (s->read_reg_select)
ret = s->isr;
else
ret = s->irr;
} else {
ret = s->imr;
}
}
#ifdef DEBUG_PIC
printf("pic_read: addr=0x%02x val=0x%02x\n", addr1, ret);
#endif
return ret;
}
/* memory mapped interrupt status */
uint32_t pic_intack_read(CPUState *env)
{
int ret;
ret = pic_poll_read(&pics[0], 0x00);
if (ret == 2)
ret = pic_poll_read(&pics[1], 0x80) + 8;
/* Prepare for ISR read */
pics[0].read_reg_select = 1;
return ret;
}
static void elcr_ioport_write(void *opaque, uint32_t addr, uint32_t val)
{
PicState *s = opaque;
s->elcr = val & s->elcr_mask;
}
static uint32_t elcr_ioport_read(void *opaque, uint32_t addr1)
{
PicState *s = opaque;
return s->elcr;
}
static void pic_save(QEMUFile *f, void *opaque)
{
PicState *s = opaque;
qemu_put_8s(f, &s->last_irr);
qemu_put_8s(f, &s->irr);
qemu_put_8s(f, &s->imr);
qemu_put_8s(f, &s->isr);
qemu_put_8s(f, &s->priority_add);
qemu_put_8s(f, &s->irq_base);
qemu_put_8s(f, &s->read_reg_select);
qemu_put_8s(f, &s->poll);
qemu_put_8s(f, &s->special_mask);
qemu_put_8s(f, &s->init_state);
qemu_put_8s(f, &s->auto_eoi);
qemu_put_8s(f, &s->rotate_on_auto_eoi);
qemu_put_8s(f, &s->special_fully_nested_mode);
qemu_put_8s(f, &s->init4);
qemu_put_8s(f, &s->elcr);
}
static int pic_load(QEMUFile *f, void *opaque, int version_id)
{
PicState *s = opaque;
if (version_id != 1)
return -EINVAL;
qemu_get_8s(f, &s->last_irr);
qemu_get_8s(f, &s->irr);
qemu_get_8s(f, &s->imr);
qemu_get_8s(f, &s->isr);
qemu_get_8s(f, &s->priority_add);
qemu_get_8s(f, &s->irq_base);
qemu_get_8s(f, &s->read_reg_select);
qemu_get_8s(f, &s->poll);
qemu_get_8s(f, &s->special_mask);
qemu_get_8s(f, &s->init_state);
qemu_get_8s(f, &s->auto_eoi);
qemu_get_8s(f, &s->rotate_on_auto_eoi);
qemu_get_8s(f, &s->special_fully_nested_mode);
qemu_get_8s(f, &s->init4);
qemu_get_8s(f, &s->elcr);
return 0;
}
/* XXX: add generic master/slave system */
static void pic_init1(int io_addr, int elcr_addr, PicState *s)
{
register_ioport_write(io_addr, 2, 1, pic_ioport_write, s);
register_ioport_read(io_addr, 2, 1, pic_ioport_read, s);
if (elcr_addr >= 0) {
register_ioport_write(elcr_addr, 1, 1, elcr_ioport_write, s);
register_ioport_read(elcr_addr, 1, 1, elcr_ioport_read, s);
}
register_savevm("i8259", io_addr, 1, pic_save, pic_load, s);
qemu_register_reset(pic_reset, s);
}
void pic_info(void)
{
int i;
PicState *s;
for(i=0;i<2;i++) {
s = &pics[i];
term_printf("pic%d: irr=%02x imr=%02x isr=%02x hprio=%d irq_base=%02x rr_sel=%d elcr=%02x fnm=%d\n",
i, s->irr, s->imr, s->isr, s->priority_add,
s->irq_base, s->read_reg_select, s->elcr,
s->special_fully_nested_mode);
}
}
void irq_info(void)
{
#ifndef DEBUG_IRQ_COUNT
term_printf("irq statistic code not compiled.\n");
#else
int i;
int64_t count;
term_printf("IRQ statistics:\n");
for (i = 0; i < 16; i++) {
count = irq_count[i];
if (count > 0)
term_printf("%2d: %lld\n", i, count);
}
#endif
}
void pic_init(void)
{
pic_init1(0x20, 0x4d0, &pics[0]);
pic_init1(0xa0, 0x4d1, &pics[1]);
pics[0].elcr_mask = 0xf8;
pics[1].elcr_mask = 0xde;
}

2318
hw/ide.c Normal file

File diff suppressed because it is too large Load Diff

218
hw/iommu.c Normal file
View File

@@ -0,0 +1,218 @@
/*
* QEMU SPARC iommu emulation
*
* 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 "vl.h"
/* debug iommu */
//#define DEBUG_IOMMU
/* The IOMMU registers occupy three pages in IO space. */
struct iommu_regs {
/* First page */
volatile unsigned long control; /* IOMMU control */
volatile unsigned long base; /* Physical base of iopte page table */
volatile unsigned long _unused1[3];
volatile unsigned long tlbflush; /* write only */
volatile unsigned long pageflush; /* write only */
volatile unsigned long _unused2[1017];
/* Second page */
volatile unsigned long afsr; /* Async-fault status register */
volatile unsigned long afar; /* Async-fault physical address */
volatile unsigned long _unused3[2];
volatile unsigned long sbuscfg0; /* SBUS configuration registers, per-slot */
volatile unsigned long sbuscfg1;
volatile unsigned long sbuscfg2;
volatile unsigned long sbuscfg3;
volatile unsigned long mfsr; /* Memory-fault status register */
volatile unsigned long mfar; /* Memory-fault physical address */
volatile unsigned long _unused4[1014];
/* Third page */
volatile unsigned long mid; /* IOMMU module-id */
};
#define IOMMU_CTRL_IMPL 0xf0000000 /* Implementation */
#define IOMMU_CTRL_VERS 0x0f000000 /* Version */
#define IOMMU_CTRL_RNGE 0x0000001c /* Mapping RANGE */
#define IOMMU_RNGE_16MB 0x00000000 /* 0xff000000 -> 0xffffffff */
#define IOMMU_RNGE_32MB 0x00000004 /* 0xfe000000 -> 0xffffffff */
#define IOMMU_RNGE_64MB 0x00000008 /* 0xfc000000 -> 0xffffffff */
#define IOMMU_RNGE_128MB 0x0000000c /* 0xf8000000 -> 0xffffffff */
#define IOMMU_RNGE_256MB 0x00000010 /* 0xf0000000 -> 0xffffffff */
#define IOMMU_RNGE_512MB 0x00000014 /* 0xe0000000 -> 0xffffffff */
#define IOMMU_RNGE_1GB 0x00000018 /* 0xc0000000 -> 0xffffffff */
#define IOMMU_RNGE_2GB 0x0000001c /* 0x80000000 -> 0xffffffff */
#define IOMMU_CTRL_ENAB 0x00000001 /* IOMMU Enable */
#define IOMMU_AFSR_ERR 0x80000000 /* LE, TO, or BE asserted */
#define IOMMU_AFSR_LE 0x40000000 /* SBUS reports error after transaction */
#define IOMMU_AFSR_TO 0x20000000 /* Write access took more than 12.8 us. */
#define IOMMU_AFSR_BE 0x10000000 /* Write access received error acknowledge */
#define IOMMU_AFSR_SIZE 0x0e000000 /* Size of transaction causing error */
#define IOMMU_AFSR_S 0x01000000 /* Sparc was in supervisor mode */
#define IOMMU_AFSR_RESV 0x00f00000 /* Reserver, forced to 0x8 by hardware */
#define IOMMU_AFSR_ME 0x00080000 /* Multiple errors occurred */
#define IOMMU_AFSR_RD 0x00040000 /* A read operation was in progress */
#define IOMMU_AFSR_FAV 0x00020000 /* IOMMU afar has valid contents */
#define IOMMU_SBCFG_SAB30 0x00010000 /* Phys-address bit 30 when bypass enabled */
#define IOMMU_SBCFG_BA16 0x00000004 /* Slave supports 16 byte bursts */
#define IOMMU_SBCFG_BA8 0x00000002 /* Slave supports 8 byte bursts */
#define IOMMU_SBCFG_BYPASS 0x00000001 /* Bypass IOMMU, treat all addresses
produced by this device as pure
physical. */
#define IOMMU_MFSR_ERR 0x80000000 /* One or more of PERR1 or PERR0 */
#define IOMMU_MFSR_S 0x01000000 /* Sparc was in supervisor mode */
#define IOMMU_MFSR_CPU 0x00800000 /* CPU transaction caused parity error */
#define IOMMU_MFSR_ME 0x00080000 /* Multiple parity errors occurred */
#define IOMMU_MFSR_PERR 0x00006000 /* high bit indicates parity error occurred
on the even word of the access, low bit
indicated odd word caused the parity error */
#define IOMMU_MFSR_BM 0x00001000 /* Error occurred while in boot mode */
#define IOMMU_MFSR_C 0x00000800 /* Address causing error was marked cacheable */
#define IOMMU_MFSR_RTYP 0x000000f0 /* Memory request transaction type */
#define IOMMU_MID_SBAE 0x001f0000 /* SBus arbitration enable */
#define IOMMU_MID_SE 0x00100000 /* Enables SCSI/ETHERNET arbitration */
#define IOMMU_MID_SB3 0x00080000 /* Enable SBUS device 3 arbitration */
#define IOMMU_MID_SB2 0x00040000 /* Enable SBUS device 2 arbitration */
#define IOMMU_MID_SB1 0x00020000 /* Enable SBUS device 1 arbitration */
#define IOMMU_MID_SB0 0x00010000 /* Enable SBUS device 0 arbitration */
#define IOMMU_MID_MID 0x0000000f /* Module-id, hardcoded to 0x8 */
/* The format of an iopte in the page tables */
#define IOPTE_PAGE 0x07ffff00 /* Physical page number (PA[30:12]) */
#define IOPTE_CACHE 0x00000080 /* Cached (in vme IOCACHE or Viking/MXCC) */
#define IOPTE_WRITE 0x00000004 /* Writeable */
#define IOPTE_VALID 0x00000002 /* IOPTE is valid */
#define IOPTE_WAZ 0x00000001 /* Write as zeros */
#define PAGE_SHIFT 12
#define PAGE_SIZE (1 << PAGE_SHIFT)
#define PAGE_MASK (PAGE_SIZE - 1)
typedef struct IOMMUState {
uint32_t addr;
uint32_t regs[sizeof(struct iommu_regs)];
uint32_t iostart;
} IOMMUState;
static IOMMUState *ps;
static uint32_t iommu_mem_readw(void *opaque, target_phys_addr_t addr)
{
IOMMUState *s = opaque;
uint32_t saddr;
saddr = (addr - s->addr) >> 2;
switch (saddr) {
default:
return s->regs[saddr];
break;
}
return 0;
}
static void iommu_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
{
IOMMUState *s = opaque;
uint32_t saddr;
saddr = (addr - s->addr) >> 2;
switch (saddr) {
case 0:
switch (val & IOMMU_CTRL_RNGE) {
case IOMMU_RNGE_16MB:
s->iostart = 0xff000000;
break;
case IOMMU_RNGE_32MB:
s->iostart = 0xfe000000;
break;
case IOMMU_RNGE_64MB:
s->iostart = 0xfc000000;
break;
case IOMMU_RNGE_128MB:
s->iostart = 0xf8000000;
break;
case IOMMU_RNGE_256MB:
s->iostart = 0xf0000000;
break;
case IOMMU_RNGE_512MB:
s->iostart = 0xe0000000;
break;
case IOMMU_RNGE_1GB:
s->iostart = 0xc0000000;
break;
default:
case IOMMU_RNGE_2GB:
s->iostart = 0x80000000;
break;
}
/* Fall through */
default:
s->regs[saddr] = val;
break;
}
}
static CPUReadMemoryFunc *iommu_mem_read[3] = {
iommu_mem_readw,
iommu_mem_readw,
iommu_mem_readw,
};
static CPUWriteMemoryFunc *iommu_mem_write[3] = {
iommu_mem_writew,
iommu_mem_writew,
iommu_mem_writew,
};
uint32_t iommu_translate(uint32_t addr)
{
uint32_t *iopte = (void *)(ps->regs[1] << 4), pa;
iopte += ((addr - ps->iostart) >> PAGE_SHIFT);
cpu_physical_memory_rw((uint32_t)iopte, (void *) &pa, 4, 0);
bswap32s(&pa);
pa = (pa & IOPTE_PAGE) << 4; /* Loose higher bits of 36 */
return pa + (addr & PAGE_MASK);
}
void iommu_init(uint32_t addr)
{
IOMMUState *s;
int iommu_io_memory;
s = qemu_mallocz(sizeof(IOMMUState));
if (!s)
return;
s->addr = addr;
iommu_io_memory = cpu_register_io_memory(0, iommu_mem_read, iommu_mem_write, s);
cpu_register_physical_memory(addr, sizeof(struct iommu_regs),
iommu_io_memory);
ps = s;
}

468
hw/lance.c Normal file
View File

@@ -0,0 +1,468 @@
/*
* QEMU Lance emulation
*
* Copyright (c) 2003-2004 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 "vl.h"
/* debug LANCE card */
//#define DEBUG_LANCE
#ifndef LANCE_LOG_TX_BUFFERS
#define LANCE_LOG_TX_BUFFERS 4
#define LANCE_LOG_RX_BUFFERS 4
#endif
#define CRC_POLYNOMIAL_BE 0x04c11db7UL /* Ethernet CRC, big endian */
#define CRC_POLYNOMIAL_LE 0xedb88320UL /* Ethernet CRC, little endian */
#define LE_CSR0 0
#define LE_CSR1 1
#define LE_CSR2 2
#define LE_CSR3 3
#define LE_MAXREG (LE_CSR3 + 1)
#define LE_RDP 0
#define LE_RAP 1
#define LE_MO_PROM 0x8000 /* Enable promiscuous mode */
#define LE_C0_ERR 0x8000 /* Error: set if BAB, SQE, MISS or ME is set */
#define LE_C0_BABL 0x4000 /* BAB: Babble: tx timeout. */
#define LE_C0_CERR 0x2000 /* SQE: Signal quality error */
#define LE_C0_MISS 0x1000 /* MISS: Missed a packet */
#define LE_C0_MERR 0x0800 /* ME: Memory error */
#define LE_C0_RINT 0x0400 /* Received interrupt */
#define LE_C0_TINT 0x0200 /* Transmitter Interrupt */
#define LE_C0_IDON 0x0100 /* IFIN: Init finished. */
#define LE_C0_INTR 0x0080 /* Interrupt or error */
#define LE_C0_INEA 0x0040 /* Interrupt enable */
#define LE_C0_RXON 0x0020 /* Receiver on */
#define LE_C0_TXON 0x0010 /* Transmitter on */
#define LE_C0_TDMD 0x0008 /* Transmitter demand */
#define LE_C0_STOP 0x0004 /* Stop the card */
#define LE_C0_STRT 0x0002 /* Start the card */
#define LE_C0_INIT 0x0001 /* Init the card */
#define LE_C3_BSWP 0x4 /* SWAP */
#define LE_C3_ACON 0x2 /* ALE Control */
#define LE_C3_BCON 0x1 /* Byte control */
/* Receive message descriptor 1 */
#define LE_R1_OWN 0x80 /* Who owns the entry */
#define LE_R1_ERR 0x40 /* Error: if FRA, OFL, CRC or BUF is set */
#define LE_R1_FRA 0x20 /* FRA: Frame error */
#define LE_R1_OFL 0x10 /* OFL: Frame overflow */
#define LE_R1_CRC 0x08 /* CRC error */
#define LE_R1_BUF 0x04 /* BUF: Buffer error */
#define LE_R1_SOP 0x02 /* Start of packet */
#define LE_R1_EOP 0x01 /* End of packet */
#define LE_R1_POK 0x03 /* Packet is complete: SOP + EOP */
#define LE_T1_OWN 0x80 /* Lance owns the packet */
#define LE_T1_ERR 0x40 /* Error summary */
#define LE_T1_EMORE 0x10 /* Error: more than one retry needed */
#define LE_T1_EONE 0x08 /* Error: one retry needed */
#define LE_T1_EDEF 0x04 /* Error: deferred */
#define LE_T1_SOP 0x02 /* Start of packet */
#define LE_T1_EOP 0x01 /* End of packet */
#define LE_T1_POK 0x03 /* Packet is complete: SOP + EOP */
#define LE_T3_BUF 0x8000 /* Buffer error */
#define LE_T3_UFL 0x4000 /* Error underflow */
#define LE_T3_LCOL 0x1000 /* Error late collision */
#define LE_T3_CLOS 0x0800 /* Error carrier loss */
#define LE_T3_RTY 0x0400 /* Error retry */
#define LE_T3_TDR 0x03ff /* Time Domain Reflectometry counter */
#define TX_RING_SIZE (1 << (LANCE_LOG_TX_BUFFERS))
#define TX_RING_MOD_MASK (TX_RING_SIZE - 1)
#define TX_RING_LEN_BITS ((LANCE_LOG_TX_BUFFERS) << 29)
#define RX_RING_SIZE (1 << (LANCE_LOG_RX_BUFFERS))
#define RX_RING_MOD_MASK (RX_RING_SIZE - 1)
#define RX_RING_LEN_BITS ((LANCE_LOG_RX_BUFFERS) << 29)
#define PKT_BUF_SZ 1544
#define RX_BUFF_SIZE PKT_BUF_SZ
#define TX_BUFF_SIZE PKT_BUF_SZ
struct lance_rx_desc {
unsigned short rmd0; /* low address of packet */
unsigned char rmd1_bits; /* descriptor bits */
unsigned char rmd1_hadr; /* high address of packet */
short length; /* This length is 2s complement (negative)!
* Buffer length
*/
unsigned short mblength; /* This is the actual number of bytes received */
};
struct lance_tx_desc {
unsigned short tmd0; /* low address of packet */
unsigned char tmd1_bits; /* descriptor bits */
unsigned char tmd1_hadr; /* high address of packet */
short length; /* Length is 2s complement (negative)! */
unsigned short misc;
};
/* The LANCE initialization block, described in databook. */
/* On the Sparc, this block should be on a DMA region */
struct lance_init_block {
unsigned short mode; /* Pre-set mode (reg. 15) */
unsigned char phys_addr[6]; /* Physical ethernet address */
unsigned filter[2]; /* Multicast filter. */
/* Receive and transmit ring base, along with extra bits. */
unsigned short rx_ptr; /* receive descriptor addr */
unsigned short rx_len; /* receive len and high addr */
unsigned short tx_ptr; /* transmit descriptor addr */
unsigned short tx_len; /* transmit len and high addr */
/* The Tx and Rx ring entries must aligned on 8-byte boundaries. */
struct lance_rx_desc brx_ring[RX_RING_SIZE];
struct lance_tx_desc btx_ring[TX_RING_SIZE];
char tx_buf [TX_RING_SIZE][TX_BUFF_SIZE];
char pad[2]; /* align rx_buf for copy_and_sum(). */
char rx_buf [RX_RING_SIZE][RX_BUFF_SIZE];
};
#define LEDMA_REGS 4
#if 0
/* Structure to describe the current status of DMA registers on the Sparc */
struct sparc_dma_registers {
uint32_t cond_reg; /* DMA condition register */
uint32_t st_addr; /* Start address of this transfer */
uint32_t cnt; /* How many bytes to transfer */
uint32_t dma_test; /* DMA test register */
};
#endif
typedef struct LEDMAState {
uint32_t addr;
uint32_t regs[LEDMA_REGS];
} LEDMAState;
typedef struct LANCEState {
uint32_t paddr;
NetDriverState *nd;
uint32_t leptr;
uint16_t addr;
uint16_t regs[LE_MAXREG];
uint8_t phys[6]; /* mac address */
int irq;
LEDMAState *ledma;
} LANCEState;
static unsigned int rxptr, txptr;
static void lance_send(void *opaque);
static void lance_reset(LANCEState *s)
{
memcpy(s->phys, s->nd->macaddr, 6);
rxptr = 0;
txptr = 0;
s->regs[LE_CSR0] = LE_C0_STOP;
}
static uint32_t lance_mem_readw(void *opaque, target_phys_addr_t addr)
{
LANCEState *s = opaque;
uint32_t saddr;
saddr = addr - s->paddr;
switch (saddr >> 1) {
case LE_RDP:
return s->regs[s->addr];
case LE_RAP:
return s->addr;
default:
break;
}
return 0;
}
static void lance_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
{
LANCEState *s = opaque;
uint32_t saddr;
uint16_t reg;
saddr = addr - s->paddr;
switch (saddr >> 1) {
case LE_RDP:
switch(s->addr) {
case LE_CSR0:
if (val & LE_C0_STOP) {
s->regs[LE_CSR0] = LE_C0_STOP;
break;
}
reg = s->regs[LE_CSR0];
// 1 = clear for some bits
reg &= ~(val & 0x7f00);
// generated bits
reg &= ~(LE_C0_ERR | LE_C0_INTR);
if (reg & 0x7100)
reg |= LE_C0_ERR;
if (reg & 0x7f00)
reg |= LE_C0_INTR;
// direct bit
reg &= ~LE_C0_INEA;
reg |= val & LE_C0_INEA;
// exclusive bits
if (val & LE_C0_INIT) {
reg |= LE_C0_IDON | LE_C0_INIT;
reg &= ~LE_C0_STOP;
}
else if (val & LE_C0_STRT) {
reg |= LE_C0_STRT | LE_C0_RXON | LE_C0_TXON;
reg &= ~LE_C0_STOP;
}
s->regs[LE_CSR0] = reg;
// trigger bits
//if (val & LE_C0_TDMD)
if ((s->regs[LE_CSR0] & LE_C0_INTR) && (s->regs[LE_CSR0] & LE_C0_INEA))
pic_set_irq(s->irq, 1);
break;
case LE_CSR1:
s->leptr = (s->leptr & 0xffff0000) | (val & 0xffff);
s->regs[s->addr] = val;
break;
case LE_CSR2:
s->leptr = (s->leptr & 0xffff) | ((val & 0xffff) << 16);
s->regs[s->addr] = val;
break;
case LE_CSR3:
s->regs[s->addr] = val;
break;
}
break;
case LE_RAP:
if (val < LE_MAXREG)
s->addr = val;
break;
default:
break;
}
lance_send(s);
}
static CPUReadMemoryFunc *lance_mem_read[3] = {
lance_mem_readw,
lance_mem_readw,
lance_mem_readw,
};
static CPUWriteMemoryFunc *lance_mem_write[3] = {
lance_mem_writew,
lance_mem_writew,
lance_mem_writew,
};
/* return the max buffer size if the LANCE can receive more data */
static int lance_can_receive(void *opaque)
{
LANCEState *s = opaque;
void *dmaptr = (void *) (s->leptr + s->ledma->regs[3]);
struct lance_init_block *ib;
int i;
uint16_t temp;
if ((s->regs[LE_CSR0] & LE_C0_STOP) == LE_C0_STOP)
return 0;
ib = (void *) iommu_translate(dmaptr);
for (i = 0; i < RX_RING_SIZE; i++) {
cpu_physical_memory_read(&ib->brx_ring[i].rmd1_bits, (void *) &temp, 1);
temp &= 0xff;
if (temp == (LE_R1_OWN)) {
#ifdef DEBUG_LANCE
fprintf(stderr, "lance: can receive %d\n", RX_BUFF_SIZE);
#endif
return RX_BUFF_SIZE;
}
}
#ifdef DEBUG_LANCE
fprintf(stderr, "lance: cannot receive\n");
#endif
return 0;
}
#define MIN_BUF_SIZE 60
static void lance_receive(void *opaque, const uint8_t *buf, int size)
{
LANCEState *s = opaque;
void *dmaptr = (void *) (s->leptr + s->ledma->regs[3]);
struct lance_init_block *ib;
unsigned int i, old_rxptr, j;
uint16_t temp;
if ((s->regs[LE_CSR0] & LE_C0_STOP) == LE_C0_STOP)
return;
ib = (void *) iommu_translate(dmaptr);
old_rxptr = rxptr;
for (i = rxptr; i != ((old_rxptr - 1) & RX_RING_MOD_MASK); i = (i + 1) & RX_RING_MOD_MASK) {
cpu_physical_memory_read(&ib->brx_ring[i].rmd1_bits, (void *) &temp, 1);
if (temp == (LE_R1_OWN)) {
rxptr = (rxptr + 1) & RX_RING_MOD_MASK;
temp = size;
bswap16s(&temp);
cpu_physical_memory_write(&ib->brx_ring[i].mblength, (void *) &temp, 2);
#if 0
cpu_physical_memory_write(&ib->rx_buf[i], buf, size);
#else
for (j = 0; j < size; j++) {
cpu_physical_memory_write(((void *)&ib->rx_buf[i]) + j, &buf[j], 1);
}
#endif
temp = LE_R1_POK;
cpu_physical_memory_write(&ib->brx_ring[i].rmd1_bits, (void *) &temp, 1);
s->regs[LE_CSR0] |= LE_C0_RINT | LE_C0_INTR;
if ((s->regs[LE_CSR0] & LE_C0_INTR) && (s->regs[LE_CSR0] & LE_C0_INEA))
pic_set_irq(s->irq, 1);
#ifdef DEBUG_LANCE
fprintf(stderr, "lance: got packet, len %d\n", size);
#endif
return;
}
}
}
static void lance_send(void *opaque)
{
LANCEState *s = opaque;
void *dmaptr = (void *) (s->leptr + s->ledma->regs[3]);
struct lance_init_block *ib;
unsigned int i, old_txptr, j;
uint16_t temp;
char pkt_buf[PKT_BUF_SZ];
if ((s->regs[LE_CSR0] & LE_C0_STOP) == LE_C0_STOP)
return;
ib = (void *) iommu_translate(dmaptr);
old_txptr = txptr;
for (i = txptr; i != ((old_txptr - 1) & TX_RING_MOD_MASK); i = (i + 1) & TX_RING_MOD_MASK) {
cpu_physical_memory_read(&ib->btx_ring[i].tmd1_bits, (void *) &temp, 1);
if (temp == (LE_T1_POK|LE_T1_OWN)) {
cpu_physical_memory_read(&ib->btx_ring[i].length, (void *) &temp, 2);
bswap16s(&temp);
temp = (~temp) + 1;
#if 0
cpu_physical_memory_read(&ib->tx_buf[i], pkt_buf, temp);
#else
for (j = 0; j < temp; j++) {
cpu_physical_memory_read(((void *)&ib->tx_buf[i]) + j, &pkt_buf[j], 1);
}
#endif
#ifdef DEBUG_LANCE
fprintf(stderr, "lance: sending packet, len %d\n", temp);
#endif
qemu_send_packet(s->nd, pkt_buf, temp);
temp = LE_T1_POK;
cpu_physical_memory_write(&ib->btx_ring[i].tmd1_bits, (void *) &temp, 1);
txptr = (txptr + 1) & TX_RING_MOD_MASK;
s->regs[LE_CSR0] |= LE_C0_TINT | LE_C0_INTR;
}
}
}
static uint32_t ledma_mem_readl(void *opaque, target_phys_addr_t addr)
{
LEDMAState *s = opaque;
uint32_t saddr;
saddr = (addr - s->addr) >> 2;
if (saddr < LEDMA_REGS)
return s->regs[saddr];
else
return 0;
}
static void ledma_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
{
LEDMAState *s = opaque;
uint32_t saddr;
saddr = (addr - s->addr) >> 2;
if (saddr < LEDMA_REGS)
s->regs[saddr] = val;
}
static CPUReadMemoryFunc *ledma_mem_read[3] = {
ledma_mem_readl,
ledma_mem_readl,
ledma_mem_readl,
};
static CPUWriteMemoryFunc *ledma_mem_write[3] = {
ledma_mem_writel,
ledma_mem_writel,
ledma_mem_writel,
};
void lance_init(NetDriverState *nd, int irq, uint32_t leaddr, uint32_t ledaddr)
{
LANCEState *s;
LEDMAState *led;
int lance_io_memory, ledma_io_memory;
s = qemu_mallocz(sizeof(LANCEState));
if (!s)
return;
s->paddr = leaddr;
s->nd = nd;
s->irq = irq;
lance_io_memory = cpu_register_io_memory(0, lance_mem_read, lance_mem_write, s);
cpu_register_physical_memory(leaddr, 8, lance_io_memory);
led = qemu_mallocz(sizeof(LEDMAState));
if (!led)
return;
s->ledma = led;
led->addr = ledaddr;
ledma_io_memory = cpu_register_io_memory(0, ledma_mem_read, ledma_mem_write, led);
cpu_register_physical_memory(ledaddr, 16, ledma_io_memory);
lance_reset(s);
qemu_add_read_packet(nd, lance_can_receive, lance_receive, s);
}

391
hw/m48t08.c Normal file
View File

@@ -0,0 +1,391 @@
/*
* QEMU M48T08 NVRAM emulation for Sparc platform
*
* Copyright (c) 2003-2004 Jocelyn Mayer
*
* 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 "vl.h"
#include "m48t08.h"
//#define DEBUG_NVRAM
#if defined(DEBUG_NVRAM)
#define NVRAM_PRINTF(fmt, args...) do { printf(fmt , ##args); } while (0)
#else
#define NVRAM_PRINTF(fmt, args...) do { } while (0)
#endif
#define NVRAM_MAX_MEM 0xfff0
struct m48t08_t {
/* Hardware parameters */
int mem_index;
uint32_t mem_base;
uint16_t size;
/* RTC management */
time_t time_offset;
time_t stop_time;
/* NVRAM storage */
uint8_t lock;
uint16_t addr;
uint8_t *buffer;
};
/* Fake timer functions */
/* Generic helpers for BCD */
static inline uint8_t toBCD (uint8_t value)
{
return (((value / 10) % 10) << 4) | (value % 10);
}
static inline uint8_t fromBCD (uint8_t BCD)
{
return ((BCD >> 4) * 10) + (BCD & 0x0F);
}
/* RTC management helpers */
static void get_time (m48t08_t *NVRAM, struct tm *tm)
{
time_t t;
t = time(NULL) + NVRAM->time_offset;
#ifdef _WIN32
memcpy(tm,localtime(&t),sizeof(*tm));
#else
localtime_r (&t, tm) ;
#endif
}
static void set_time (m48t08_t *NVRAM, struct tm *tm)
{
time_t now, new_time;
new_time = mktime(tm);
now = time(NULL);
NVRAM->time_offset = new_time - now;
}
/* Direct access to NVRAM */
void m48t08_write (m48t08_t *NVRAM, uint32_t val)
{
struct tm tm;
int tmp;
if (NVRAM->addr > NVRAM_MAX_MEM && NVRAM->addr < 0x2000)
NVRAM_PRINTF("%s: 0x%08x => 0x%08x\n", __func__, NVRAM->addr, val);
switch (NVRAM->addr) {
case 0x1FF8:
/* control */
NVRAM->buffer[0x1FF8] = (val & ~0xA0) | 0x90;
break;
case 0x1FF9:
/* seconds (BCD) */
tmp = fromBCD(val & 0x7F);
if (tmp >= 0 && tmp <= 59) {
get_time(NVRAM, &tm);
tm.tm_sec = tmp;
set_time(NVRAM, &tm);
}
if ((val & 0x80) ^ (NVRAM->buffer[0x1FF9] & 0x80)) {
if (val & 0x80) {
NVRAM->stop_time = time(NULL);
} else {
NVRAM->time_offset += NVRAM->stop_time - time(NULL);
NVRAM->stop_time = 0;
}
}
NVRAM->buffer[0x1FF9] = val & 0x80;
break;
case 0x1FFA:
/* minutes (BCD) */
tmp = fromBCD(val & 0x7F);
if (tmp >= 0 && tmp <= 59) {
get_time(NVRAM, &tm);
tm.tm_min = tmp;
set_time(NVRAM, &tm);
}
break;
case 0x1FFB:
/* hours (BCD) */
tmp = fromBCD(val & 0x3F);
if (tmp >= 0 && tmp <= 23) {
get_time(NVRAM, &tm);
tm.tm_hour = tmp;
set_time(NVRAM, &tm);
}
break;
case 0x1FFC:
/* day of the week / century */
tmp = fromBCD(val & 0x07);
get_time(NVRAM, &tm);
tm.tm_wday = tmp;
set_time(NVRAM, &tm);
NVRAM->buffer[0x1FFC] = val & 0x40;
break;
case 0x1FFD:
/* date */
tmp = fromBCD(val & 0x1F);
if (tmp != 0) {
get_time(NVRAM, &tm);
tm.tm_mday = tmp;
set_time(NVRAM, &tm);
}
break;
case 0x1FFE:
/* month */
tmp = fromBCD(val & 0x1F);
if (tmp >= 1 && tmp <= 12) {
get_time(NVRAM, &tm);
tm.tm_mon = tmp - 1;
set_time(NVRAM, &tm);
}
break;
case 0x1FFF:
/* year */
tmp = fromBCD(val);
if (tmp >= 0 && tmp <= 99) {
get_time(NVRAM, &tm);
tm.tm_year = fromBCD(val);
set_time(NVRAM, &tm);
}
break;
default:
/* Check lock registers state */
if (NVRAM->addr >= 0x20 && NVRAM->addr <= 0x2F && (NVRAM->lock & 1))
break;
if (NVRAM->addr >= 0x30 && NVRAM->addr <= 0x3F && (NVRAM->lock & 2))
break;
if (NVRAM->addr < NVRAM_MAX_MEM ||
(NVRAM->addr > 0x1FFF && NVRAM->addr < NVRAM->size)) {
NVRAM->buffer[NVRAM->addr] = val & 0xFF;
}
break;
}
}
uint32_t m48t08_read (m48t08_t *NVRAM)
{
struct tm tm;
uint32_t retval = 0xFF;
switch (NVRAM->addr) {
case 0x1FF8:
/* control */
goto do_read;
case 0x1FF9:
/* seconds (BCD) */
get_time(NVRAM, &tm);
retval = (NVRAM->buffer[0x1FF9] & 0x80) | toBCD(tm.tm_sec);
break;
case 0x1FFA:
/* minutes (BCD) */
get_time(NVRAM, &tm);
retval = toBCD(tm.tm_min);
break;
case 0x1FFB:
/* hours (BCD) */
get_time(NVRAM, &tm);
retval = toBCD(tm.tm_hour);
break;
case 0x1FFC:
/* day of the week / century */
get_time(NVRAM, &tm);
retval = NVRAM->buffer[0x1FFC] | tm.tm_wday;
break;
case 0x1FFD:
/* date */
get_time(NVRAM, &tm);
retval = toBCD(tm.tm_mday);
break;
case 0x1FFE:
/* month */
get_time(NVRAM, &tm);
retval = toBCD(tm.tm_mon + 1);
break;
case 0x1FFF:
/* year */
get_time(NVRAM, &tm);
retval = toBCD(tm.tm_year);
break;
default:
/* Check lock registers state */
if (NVRAM->addr >= 0x20 && NVRAM->addr <= 0x2F && (NVRAM->lock & 1))
break;
if (NVRAM->addr >= 0x30 && NVRAM->addr <= 0x3F && (NVRAM->lock & 2))
break;
if (NVRAM->addr < NVRAM_MAX_MEM ||
(NVRAM->addr > 0x1FFF && NVRAM->addr < NVRAM->size)) {
do_read:
retval = NVRAM->buffer[NVRAM->addr];
}
break;
}
if (NVRAM->addr > NVRAM_MAX_MEM + 1 && NVRAM->addr < 0x2000)
NVRAM_PRINTF("0x%08x <= 0x%08x\n", NVRAM->addr, retval);
return retval;
}
void m48t08_set_addr (m48t08_t *NVRAM, uint32_t addr)
{
NVRAM->addr = addr;
}
void m48t08_toggle_lock (m48t08_t *NVRAM, int lock)
{
NVRAM->lock ^= 1 << lock;
}
static void nvram_writeb (void *opaque, target_phys_addr_t addr, uint32_t value)
{
m48t08_t *NVRAM = opaque;
addr -= NVRAM->mem_base;
if (addr < NVRAM_MAX_MEM)
NVRAM->buffer[addr] = value;
}
static void nvram_writew (void *opaque, target_phys_addr_t addr, uint32_t value)
{
m48t08_t *NVRAM = opaque;
addr -= NVRAM->mem_base;
if (addr < NVRAM_MAX_MEM) {
NVRAM->buffer[addr] = value >> 8;
NVRAM->buffer[addr + 1] = value;
}
}
static void nvram_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
{
m48t08_t *NVRAM = opaque;
addr -= NVRAM->mem_base;
if (addr < NVRAM_MAX_MEM) {
NVRAM->buffer[addr] = value >> 24;
NVRAM->buffer[addr + 1] = value >> 16;
NVRAM->buffer[addr + 2] = value >> 8;
NVRAM->buffer[addr + 3] = value;
}
}
static uint32_t nvram_readb (void *opaque, target_phys_addr_t addr)
{
m48t08_t *NVRAM = opaque;
uint32_t retval = 0;
addr -= NVRAM->mem_base;
if (addr < NVRAM_MAX_MEM)
retval = NVRAM->buffer[addr];
return retval;
}
static uint32_t nvram_readw (void *opaque, target_phys_addr_t addr)
{
m48t08_t *NVRAM = opaque;
uint32_t retval = 0;
addr -= NVRAM->mem_base;
if (addr < NVRAM_MAX_MEM) {
retval = NVRAM->buffer[addr] << 8;
retval |= NVRAM->buffer[addr + 1];
}
return retval;
}
static uint32_t nvram_readl (void *opaque, target_phys_addr_t addr)
{
m48t08_t *NVRAM = opaque;
uint32_t retval = 0;
addr -= NVRAM->mem_base;
if (addr < NVRAM_MAX_MEM) {
retval = NVRAM->buffer[addr] << 24;
retval |= NVRAM->buffer[addr + 1] << 16;
retval |= NVRAM->buffer[addr + 2] << 8;
retval |= NVRAM->buffer[addr + 3];
}
return retval;
}
static CPUWriteMemoryFunc *nvram_write[] = {
&nvram_writeb,
&nvram_writew,
&nvram_writel,
};
static CPUReadMemoryFunc *nvram_read[] = {
&nvram_readb,
&nvram_readw,
&nvram_readl,
};
/* Initialisation routine */
m48t08_t *m48t08_init(uint32_t mem_base, uint16_t size, uint8_t *macaddr)
{
m48t08_t *s;
int i;
unsigned char tmp = 0;
s = qemu_mallocz(sizeof(m48t08_t));
if (!s)
return NULL;
s->buffer = qemu_mallocz(size);
if (!s->buffer) {
qemu_free(s);
return NULL;
}
s->size = size;
s->mem_base = mem_base;
s->addr = 0;
if (mem_base != 0) {
s->mem_index = cpu_register_io_memory(0, nvram_read, nvram_write, s);
cpu_register_physical_memory(mem_base, 0x4000, s->mem_index);
}
s->lock = 0;
i = 0x1fd8;
s->buffer[i++] = 0x01;
s->buffer[i++] = 0x80; /* Sun4m OBP */
memcpy(&s->buffer[i], macaddr, 6);
/* Calculate checksum */
for (i = 0x1fd8; i < 0x1fe7; i++) {
tmp ^= s->buffer[i];
}
s->buffer[0x1fe7] = tmp;
return s;
}
#if 0
struct idprom
{
unsigned char id_format; /* Format identifier (always 0x01) */
unsigned char id_machtype; /* Machine type */
unsigned char id_ethaddr[6]; /* Hardware ethernet address */
long id_date; /* Date of manufacture */
unsigned int id_sernum:24; /* Unique serial number */
unsigned char id_cksum; /* Checksum - xor of the data bytes */
unsigned char reserved[16];
};
#endif

12
hw/m48t08.h Normal file
View File

@@ -0,0 +1,12 @@
#if !defined (__M48T08_H__)
#define __M48T08_H__
typedef struct m48t08_t m48t08_t;
void m48t08_write (m48t08_t *NVRAM, uint32_t val);
uint32_t m48t08_read (m48t08_t *NVRAM);
void m48t08_set_addr (m48t08_t *NVRAM, uint32_t addr);
void m48t08_toggle_lock (m48t08_t *NVRAM, int lock);
m48t08_t *m48t08_init(uint32_t mem_base, uint16_t size, uint8_t *macaddr);
#endif /* !defined (__M48T08_H__) */

602
hw/m48t59.c Normal file
View File

@@ -0,0 +1,602 @@
/*
* QEMU M48T59 NVRAM emulation for PPC PREP platform
*
* Copyright (c) 2003-2004 Jocelyn Mayer
*
* 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 "vl.h"
#include "m48t59.h"
//#define DEBUG_NVRAM
#if defined(DEBUG_NVRAM)
#define NVRAM_PRINTF(fmt, args...) do { printf(fmt , ##args); } while (0)
#else
#define NVRAM_PRINTF(fmt, args...) do { } while (0)
#endif
struct m48t59_t {
/* Hardware parameters */
int IRQ;
int mem_index;
uint32_t mem_base;
uint32_t io_base;
uint16_t size;
/* RTC management */
time_t time_offset;
time_t stop_time;
/* Alarm & watchdog */
time_t alarm;
struct QEMUTimer *alrm_timer;
struct QEMUTimer *wd_timer;
/* NVRAM storage */
uint8_t lock;
uint16_t addr;
uint8_t *buffer;
};
/* Fake timer functions */
/* Generic helpers for BCD */
static inline uint8_t toBCD (uint8_t value)
{
return (((value / 10) % 10) << 4) | (value % 10);
}
static inline uint8_t fromBCD (uint8_t BCD)
{
return ((BCD >> 4) * 10) + (BCD & 0x0F);
}
/* RTC management helpers */
static void get_time (m48t59_t *NVRAM, struct tm *tm)
{
time_t t;
t = time(NULL) + NVRAM->time_offset;
#ifdef _WIN32
memcpy(tm,localtime(&t),sizeof(*tm));
#else
localtime_r (&t, tm) ;
#endif
}
static void set_time (m48t59_t *NVRAM, struct tm *tm)
{
time_t now, new_time;
new_time = mktime(tm);
now = time(NULL);
NVRAM->time_offset = new_time - now;
}
/* Alarm management */
static void alarm_cb (void *opaque)
{
struct tm tm, tm_now;
uint64_t next_time;
m48t59_t *NVRAM = opaque;
pic_set_irq(NVRAM->IRQ, 1);
if ((NVRAM->buffer[0x1FF5] & 0x80) == 0 &&
(NVRAM->buffer[0x1FF4] & 0x80) == 0 &&
(NVRAM->buffer[0x1FF3] & 0x80) == 0 &&
(NVRAM->buffer[0x1FF2] & 0x80) == 0) {
/* Repeat once a month */
get_time(NVRAM, &tm_now);
memcpy(&tm, &tm_now, sizeof(struct tm));
tm.tm_mon++;
if (tm.tm_mon == 13) {
tm.tm_mon = 1;
tm.tm_year++;
}
next_time = mktime(&tm);
} else if ((NVRAM->buffer[0x1FF5] & 0x80) != 0 &&
(NVRAM->buffer[0x1FF4] & 0x80) == 0 &&
(NVRAM->buffer[0x1FF3] & 0x80) == 0 &&
(NVRAM->buffer[0x1FF2] & 0x80) == 0) {
/* Repeat once a day */
next_time = 24 * 60 * 60 + mktime(&tm_now);
} else if ((NVRAM->buffer[0x1FF5] & 0x80) != 0 &&
(NVRAM->buffer[0x1FF4] & 0x80) != 0 &&
(NVRAM->buffer[0x1FF3] & 0x80) == 0 &&
(NVRAM->buffer[0x1FF2] & 0x80) == 0) {
/* Repeat once an hour */
next_time = 60 * 60 + mktime(&tm_now);
} else if ((NVRAM->buffer[0x1FF5] & 0x80) != 0 &&
(NVRAM->buffer[0x1FF4] & 0x80) != 0 &&
(NVRAM->buffer[0x1FF3] & 0x80) != 0 &&
(NVRAM->buffer[0x1FF2] & 0x80) == 0) {
/* Repeat once a minute */
next_time = 60 + mktime(&tm_now);
} else {
/* Repeat once a second */
next_time = 1 + mktime(&tm_now);
}
qemu_mod_timer(NVRAM->alrm_timer, next_time * 1000);
pic_set_irq(NVRAM->IRQ, 0);
}
static void get_alarm (m48t59_t *NVRAM, struct tm *tm)
{
#ifdef _WIN32
memcpy(tm,localtime(&NVRAM->alarm),sizeof(*tm));
#else
localtime_r (&NVRAM->alarm, tm);
#endif
}
static void set_alarm (m48t59_t *NVRAM, struct tm *tm)
{
NVRAM->alarm = mktime(tm);
if (NVRAM->alrm_timer != NULL) {
qemu_del_timer(NVRAM->alrm_timer);
NVRAM->alrm_timer = NULL;
}
if (NVRAM->alarm - time(NULL) > 0)
qemu_mod_timer(NVRAM->alrm_timer, NVRAM->alarm * 1000);
}
/* Watchdog management */
static void watchdog_cb (void *opaque)
{
m48t59_t *NVRAM = opaque;
NVRAM->buffer[0x1FF0] |= 0x80;
if (NVRAM->buffer[0x1FF7] & 0x80) {
NVRAM->buffer[0x1FF7] = 0x00;
NVRAM->buffer[0x1FFC] &= ~0x40;
/* May it be a hw CPU Reset instead ? */
qemu_system_reset_request();
} else {
pic_set_irq(NVRAM->IRQ, 1);
pic_set_irq(NVRAM->IRQ, 0);
}
}
static void set_up_watchdog (m48t59_t *NVRAM, uint8_t value)
{
uint64_t interval; /* in 1/16 seconds */
if (NVRAM->wd_timer != NULL) {
qemu_del_timer(NVRAM->wd_timer);
NVRAM->wd_timer = NULL;
}
NVRAM->buffer[0x1FF0] &= ~0x80;
if (value != 0) {
interval = (1 << (2 * (value & 0x03))) * ((value >> 2) & 0x1F);
qemu_mod_timer(NVRAM->wd_timer, ((uint64_t)time(NULL) * 1000) +
((interval * 1000) >> 4));
}
}
/* Direct access to NVRAM */
void m48t59_write (m48t59_t *NVRAM, uint32_t val)
{
struct tm tm;
int tmp;
if (NVRAM->addr > 0x1FF8 && NVRAM->addr < 0x2000)
NVRAM_PRINTF("%s: 0x%08x => 0x%08x\n", __func__, NVRAM->addr, val);
switch (NVRAM->addr) {
case 0x1FF0:
/* flags register : read-only */
break;
case 0x1FF1:
/* unused */
break;
case 0x1FF2:
/* alarm seconds */
tmp = fromBCD(val & 0x7F);
if (tmp >= 0 && tmp <= 59) {
get_alarm(NVRAM, &tm);
tm.tm_sec = tmp;
NVRAM->buffer[0x1FF2] = val;
set_alarm(NVRAM, &tm);
}
break;
case 0x1FF3:
/* alarm minutes */
tmp = fromBCD(val & 0x7F);
if (tmp >= 0 && tmp <= 59) {
get_alarm(NVRAM, &tm);
tm.tm_min = tmp;
NVRAM->buffer[0x1FF3] = val;
set_alarm(NVRAM, &tm);
}
break;
case 0x1FF4:
/* alarm hours */
tmp = fromBCD(val & 0x3F);
if (tmp >= 0 && tmp <= 23) {
get_alarm(NVRAM, &tm);
tm.tm_hour = tmp;
NVRAM->buffer[0x1FF4] = val;
set_alarm(NVRAM, &tm);
}
break;
case 0x1FF5:
/* alarm date */
tmp = fromBCD(val & 0x1F);
if (tmp != 0) {
get_alarm(NVRAM, &tm);
tm.tm_mday = tmp;
NVRAM->buffer[0x1FF5] = val;
set_alarm(NVRAM, &tm);
}
break;
case 0x1FF6:
/* interrupts */
NVRAM->buffer[0x1FF6] = val;
break;
case 0x1FF7:
/* watchdog */
NVRAM->buffer[0x1FF7] = val;
set_up_watchdog(NVRAM, val);
break;
case 0x1FF8:
/* control */
NVRAM->buffer[0x1FF8] = (val & ~0xA0) | 0x90;
break;
case 0x1FF9:
/* seconds (BCD) */
tmp = fromBCD(val & 0x7F);
if (tmp >= 0 && tmp <= 59) {
get_time(NVRAM, &tm);
tm.tm_sec = tmp;
set_time(NVRAM, &tm);
}
if ((val & 0x80) ^ (NVRAM->buffer[0x1FF9] & 0x80)) {
if (val & 0x80) {
NVRAM->stop_time = time(NULL);
} else {
NVRAM->time_offset += NVRAM->stop_time - time(NULL);
NVRAM->stop_time = 0;
}
}
NVRAM->buffer[0x1FF9] = val & 0x80;
break;
case 0x1FFA:
/* minutes (BCD) */
tmp = fromBCD(val & 0x7F);
if (tmp >= 0 && tmp <= 59) {
get_time(NVRAM, &tm);
tm.tm_min = tmp;
set_time(NVRAM, &tm);
}
break;
case 0x1FFB:
/* hours (BCD) */
tmp = fromBCD(val & 0x3F);
if (tmp >= 0 && tmp <= 23) {
get_time(NVRAM, &tm);
tm.tm_hour = tmp;
set_time(NVRAM, &tm);
}
break;
case 0x1FFC:
/* day of the week / century */
tmp = fromBCD(val & 0x07);
get_time(NVRAM, &tm);
tm.tm_wday = tmp;
set_time(NVRAM, &tm);
NVRAM->buffer[0x1FFC] = val & 0x40;
break;
case 0x1FFD:
/* date */
tmp = fromBCD(val & 0x1F);
if (tmp != 0) {
get_time(NVRAM, &tm);
tm.tm_mday = tmp;
set_time(NVRAM, &tm);
}
break;
case 0x1FFE:
/* month */
tmp = fromBCD(val & 0x1F);
if (tmp >= 1 && tmp <= 12) {
get_time(NVRAM, &tm);
tm.tm_mon = tmp - 1;
set_time(NVRAM, &tm);
}
break;
case 0x1FFF:
/* year */
tmp = fromBCD(val);
if (tmp >= 0 && tmp <= 99) {
get_time(NVRAM, &tm);
tm.tm_year = fromBCD(val);
set_time(NVRAM, &tm);
}
break;
default:
/* Check lock registers state */
if (NVRAM->addr >= 0x20 && NVRAM->addr <= 0x2F && (NVRAM->lock & 1))
break;
if (NVRAM->addr >= 0x30 && NVRAM->addr <= 0x3F && (NVRAM->lock & 2))
break;
if (NVRAM->addr < 0x1FF0 ||
(NVRAM->addr > 0x1FFF && NVRAM->addr < NVRAM->size)) {
NVRAM->buffer[NVRAM->addr] = val & 0xFF;
}
break;
}
}
uint32_t m48t59_read (m48t59_t *NVRAM)
{
struct tm tm;
uint32_t retval = 0xFF;
switch (NVRAM->addr) {
case 0x1FF0:
/* flags register */
goto do_read;
case 0x1FF1:
/* unused */
retval = 0;
break;
case 0x1FF2:
/* alarm seconds */
goto do_read;
case 0x1FF3:
/* alarm minutes */
goto do_read;
case 0x1FF4:
/* alarm hours */
goto do_read;
case 0x1FF5:
/* alarm date */
goto do_read;
case 0x1FF6:
/* interrupts */
goto do_read;
case 0x1FF7:
/* A read resets the watchdog */
set_up_watchdog(NVRAM, NVRAM->buffer[0x1FF7]);
goto do_read;
case 0x1FF8:
/* control */
goto do_read;
case 0x1FF9:
/* seconds (BCD) */
get_time(NVRAM, &tm);
retval = (NVRAM->buffer[0x1FF9] & 0x80) | toBCD(tm.tm_sec);
break;
case 0x1FFA:
/* minutes (BCD) */
get_time(NVRAM, &tm);
retval = toBCD(tm.tm_min);
break;
case 0x1FFB:
/* hours (BCD) */
get_time(NVRAM, &tm);
retval = toBCD(tm.tm_hour);
break;
case 0x1FFC:
/* day of the week / century */
get_time(NVRAM, &tm);
retval = NVRAM->buffer[0x1FFC] | tm.tm_wday;
break;
case 0x1FFD:
/* date */
get_time(NVRAM, &tm);
retval = toBCD(tm.tm_mday);
break;
case 0x1FFE:
/* month */
get_time(NVRAM, &tm);
retval = toBCD(tm.tm_mon + 1);
break;
case 0x1FFF:
/* year */
get_time(NVRAM, &tm);
retval = toBCD(tm.tm_year);
break;
default:
/* Check lock registers state */
if (NVRAM->addr >= 0x20 && NVRAM->addr <= 0x2F && (NVRAM->lock & 1))
break;
if (NVRAM->addr >= 0x30 && NVRAM->addr <= 0x3F && (NVRAM->lock & 2))
break;
if (NVRAM->addr < 0x1FF0 ||
(NVRAM->addr > 0x1FFF && NVRAM->addr < NVRAM->size)) {
do_read:
retval = NVRAM->buffer[NVRAM->addr];
}
break;
}
if (NVRAM->addr > 0x1FF9 && NVRAM->addr < 0x2000)
NVRAM_PRINTF("0x%08x <= 0x%08x\n", NVRAM->addr, retval);
return retval;
}
void m48t59_set_addr (m48t59_t *NVRAM, uint32_t addr)
{
NVRAM->addr = addr;
}
void m48t59_toggle_lock (m48t59_t *NVRAM, int lock)
{
NVRAM->lock ^= 1 << lock;
}
/* IO access to NVRAM */
static void NVRAM_writeb (void *opaque, uint32_t addr, uint32_t val)
{
m48t59_t *NVRAM = opaque;
addr -= NVRAM->io_base;
NVRAM_PRINTF("0x%08x => 0x%08x\n", addr, val);
switch (addr) {
case 0:
NVRAM->addr &= ~0x00FF;
NVRAM->addr |= val;
break;
case 1:
NVRAM->addr &= ~0xFF00;
NVRAM->addr |= val << 8;
break;
case 3:
m48t59_write(NVRAM, val);
NVRAM->addr = 0x0000;
break;
default:
break;
}
}
static uint32_t NVRAM_readb (void *opaque, uint32_t addr)
{
m48t59_t *NVRAM = opaque;
uint32_t retval;
addr -= NVRAM->io_base;
switch (addr) {
case 3:
retval = m48t59_read(NVRAM);
break;
default:
retval = -1;
break;
}
NVRAM_PRINTF("0x%08x <= 0x%08x\n", addr, retval);
return retval;
}
static void nvram_writeb (void *opaque, target_phys_addr_t addr, uint32_t value)
{
m48t59_t *NVRAM = opaque;
addr -= NVRAM->mem_base;
if (addr < 0x1FF0)
NVRAM->buffer[addr] = value;
}
static void nvram_writew (void *opaque, target_phys_addr_t addr, uint32_t value)
{
m48t59_t *NVRAM = opaque;
addr -= NVRAM->mem_base;
if (addr < 0x1FF0) {
NVRAM->buffer[addr] = value >> 8;
NVRAM->buffer[addr + 1] = value;
}
}
static void nvram_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
{
m48t59_t *NVRAM = opaque;
addr -= NVRAM->mem_base;
if (addr < 0x1FF0) {
NVRAM->buffer[addr] = value >> 24;
NVRAM->buffer[addr + 1] = value >> 16;
NVRAM->buffer[addr + 2] = value >> 8;
NVRAM->buffer[addr + 3] = value;
}
}
static uint32_t nvram_readb (void *opaque, target_phys_addr_t addr)
{
m48t59_t *NVRAM = opaque;
uint32_t retval = 0;
addr -= NVRAM->mem_base;
if (addr < 0x1FF0)
retval = NVRAM->buffer[addr];
return retval;
}
static uint32_t nvram_readw (void *opaque, target_phys_addr_t addr)
{
m48t59_t *NVRAM = opaque;
uint32_t retval = 0;
addr -= NVRAM->mem_base;
if (addr < 0x1FF0) {
retval = NVRAM->buffer[addr] << 8;
retval |= NVRAM->buffer[addr + 1];
}
return retval;
}
static uint32_t nvram_readl (void *opaque, target_phys_addr_t addr)
{
m48t59_t *NVRAM = opaque;
uint32_t retval = 0;
addr -= NVRAM->mem_base;
if (addr < 0x1FF0) {
retval = NVRAM->buffer[addr] << 24;
retval |= NVRAM->buffer[addr + 1] << 16;
retval |= NVRAM->buffer[addr + 2] << 8;
retval |= NVRAM->buffer[addr + 3];
}
return retval;
}
static CPUWriteMemoryFunc *nvram_write[] = {
&nvram_writeb,
&nvram_writew,
&nvram_writel,
};
static CPUReadMemoryFunc *nvram_read[] = {
&nvram_readb,
&nvram_readw,
&nvram_readl,
};
/* Initialisation routine */
m48t59_t *m48t59_init (int IRQ, uint32_t mem_base,
uint32_t io_base, uint16_t size)
{
m48t59_t *s;
s = qemu_mallocz(sizeof(m48t59_t));
if (!s)
return NULL;
s->buffer = qemu_mallocz(size);
if (!s->buffer) {
qemu_free(s);
return NULL;
}
s->IRQ = IRQ;
s->size = size;
s->mem_base = mem_base;
s->io_base = io_base;
s->addr = 0;
register_ioport_read(io_base, 0x04, 1, NVRAM_readb, s);
register_ioport_write(io_base, 0x04, 1, NVRAM_writeb, s);
if (mem_base != 0) {
s->mem_index = cpu_register_io_memory(0, nvram_read, nvram_write, s);
cpu_register_physical_memory(mem_base, 0x4000, s->mem_index);
}
s->alrm_timer = qemu_new_timer(vm_clock, &alarm_cb, s);
s->wd_timer = qemu_new_timer(vm_clock, &watchdog_cb, s);
s->lock = 0;
return s;
}

13
hw/m48t59.h Normal file
View File

@@ -0,0 +1,13 @@
#if !defined (__M48T59_H__)
#define __M48T59_H__
typedef struct m48t59_t m48t59_t;
void m48t59_write (m48t59_t *NVRAM, uint32_t val);
uint32_t m48t59_read (m48t59_t *NVRAM);
void m48t59_set_addr (m48t59_t *NVRAM, uint32_t addr);
void m48t59_toggle_lock (m48t59_t *NVRAM, int lock);
m48t59_t *m48t59_init (int IRQ, uint32_t io_base,
uint32_t mem_base, uint16_t size);
#endif /* !defined (__M48T59_H__) */

326
hw/magic-load.c Normal file
View File

@@ -0,0 +1,326 @@
#include "vl.h"
#include "disas.h"
#define ELF_CLASS ELFCLASS32
#define ELF_DATA ELFDATA2MSB
#define ELF_ARCH EM_SPARC
#include "elf.h"
#ifdef BSWAP_NEEDED
static void bswap_ehdr(Elf32_Ehdr *ehdr)
{
bswap16s(&ehdr->e_type); /* Object file type */
bswap16s(&ehdr->e_machine); /* Architecture */
bswap32s(&ehdr->e_version); /* Object file version */
bswap32s(&ehdr->e_entry); /* Entry point virtual address */
bswap32s(&ehdr->e_phoff); /* Program header table file offset */
bswap32s(&ehdr->e_shoff); /* Section header table file offset */
bswap32s(&ehdr->e_flags); /* Processor-specific flags */
bswap16s(&ehdr->e_ehsize); /* ELF header size in bytes */
bswap16s(&ehdr->e_phentsize); /* Program header table entry size */
bswap16s(&ehdr->e_phnum); /* Program header table entry count */
bswap16s(&ehdr->e_shentsize); /* Section header table entry size */
bswap16s(&ehdr->e_shnum); /* Section header table entry count */
bswap16s(&ehdr->e_shstrndx); /* Section header string table index */
}
static void bswap_phdr(Elf32_Phdr *phdr)
{
bswap32s(&phdr->p_type); /* Segment type */
bswap32s(&phdr->p_offset); /* Segment file offset */
bswap32s(&phdr->p_vaddr); /* Segment virtual address */
bswap32s(&phdr->p_paddr); /* Segment physical address */
bswap32s(&phdr->p_filesz); /* Segment size in file */
bswap32s(&phdr->p_memsz); /* Segment size in memory */
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);
}
#else
#define bswap_ehdr(e) do { } while (0)
#define bswap_phdr(e) do { } while (0)
#define bswap_shdr(e) do { } while (0)
#define bswap_sym(e) do { } while (0)
#endif
static int find_phdr(struct elfhdr *ehdr, int fd, struct elf_phdr *phdr, uint32_t type)
{
int i, retval;
retval = lseek(fd, ehdr->e_phoff, SEEK_SET);
if (retval < 0)
return -1;
for (i = 0; i < ehdr->e_phnum; i++) {
retval = read(fd, phdr, sizeof(*phdr));
if (retval < 0)
return -1;
bswap_phdr(phdr);
if (phdr->p_type == type)
return 0;
}
return -1;
}
static void *find_shdr(struct elfhdr *ehdr, int fd, struct elf_shdr *shdr, uint32_t type)
{
int i, retval;
retval = lseek(fd, ehdr->e_shoff, SEEK_SET);
if (retval < 0)
return NULL;
for (i = 0; i < ehdr->e_shnum; i++) {
retval = read(fd, shdr, sizeof(*shdr));
if (retval < 0)
return NULL;
bswap_shdr(shdr);
if (shdr->sh_type == type)
return qemu_malloc(shdr->sh_size);
}
return NULL;
}
static int find_strtab(struct elfhdr *ehdr, int fd, struct elf_shdr *shdr, struct elf_shdr *symtab)
{
int retval;
retval = lseek(fd, ehdr->e_shoff + sizeof(struct elf_shdr) * symtab->sh_link, SEEK_SET);
if (retval < 0)
return -1;
retval = read(fd, shdr, sizeof(*shdr));
if (retval < 0)
return -1;
bswap_shdr(shdr);
if (shdr->sh_type == SHT_STRTAB)
return qemu_malloc(shdr->sh_size);;
return 0;
}
static int read_program(int fd, struct elf_phdr *phdr, void *dst)
{
int retval;
retval = lseek(fd, 0x4000, SEEK_SET);
if (retval < 0)
return -1;
return read(fd, dst, phdr->p_filesz);
}
static int read_section(int fd, struct elf_shdr *s, void *dst)
{
int retval;
retval = lseek(fd, s->sh_offset, SEEK_SET);
if (retval < 0)
return -1;
retval = read(fd, dst, s->sh_size);
if (retval < 0)
return -1;
return 0;
}
static void *process_section(struct elfhdr *ehdr, int fd, struct elf_shdr *shdr, uint32_t type)
{
void *dst;
dst = find_shdr(ehdr, fd, shdr, type);
if (!dst)
goto error;
if (read_section(fd, shdr, dst))
goto error;
return dst;
error:
qemu_free(dst);
return NULL;
}
static void *process_strtab(struct elfhdr *ehdr, int fd, struct elf_shdr *shdr, struct elf_shdr *symtab)
{
void *dst;
dst = find_strtab(ehdr, fd, shdr, symtab);
if (!dst)
goto error;
if (read_section(fd, shdr, dst))
goto error;
return dst;
error:
qemu_free(dst);
return NULL;
}
static void load_symbols(struct elfhdr *ehdr, int fd)
{
struct elf_shdr symtab, strtab;
struct elf_sym *syms;
int nsyms, i;
char *str;
/* Symbol table */
syms = process_section(ehdr, fd, &symtab, SHT_SYMTAB);
if (!syms)
return;
nsyms = symtab.sh_size / sizeof(struct elf_sym);
for (i = 0; i < nsyms; i++)
bswap_sym(&syms[i]);
/* String table */
str = process_strtab(ehdr, fd, &strtab, &symtab);
if (!str)
goto error_freesyms;
/* Commit */
if (disas_symtab)
qemu_free(disas_symtab); /* XXX Merge with old symbols? */
if (disas_strtab)
qemu_free(disas_strtab);
disas_symtab = syms;
disas_num_syms = nsyms;
disas_strtab = str;
return;
error_freesyms:
qemu_free(syms);
return;
}
int load_elf(const char * filename, uint8_t *addr)
{
struct elfhdr ehdr;
struct elf_phdr phdr;
int retval, fd;
fd = open(filename, O_RDONLY | O_BINARY);
if (fd < 0)
goto error;
retval = read(fd, &ehdr, sizeof(ehdr));
if (retval < 0)
goto error;
bswap_ehdr(&ehdr);
if (ehdr.e_ident[0] != 0x7f || ehdr.e_ident[1] != 'E'
|| ehdr.e_ident[2] != 'L' || ehdr.e_ident[3] != 'F'
|| ehdr.e_machine != EM_SPARC)
goto error;
if (find_phdr(&ehdr, fd, &phdr, PT_LOAD))
goto error;
retval = read_program(fd, &phdr, addr);
if (retval < 0)
goto error;
load_symbols(&ehdr, fd);
close(fd);
return retval;
error:
close(fd);
return -1;
}
int load_kernel(const char *filename, uint8_t *addr)
{
int fd, size;
fd = open(filename, O_RDONLY | O_BINARY);
if (fd < 0)
return -1;
/* load 32 bit code */
size = read(fd, addr, 16 * 1024 * 1024);
if (size < 0)
goto fail;
close(fd);
return size;
fail:
close(fd);
return -1;
}
typedef struct MAGICState {
uint32_t addr;
uint32_t saved_addr;
int magic_state;
char saved_kfn[1024];
} MAGICState;
static uint32_t magic_mem_readl(void *opaque, target_phys_addr_t addr)
{
int ret;
MAGICState *s = opaque;
if (s->magic_state == 0) {
ret = load_elf(s->saved_kfn, (uint8_t *)s->saved_addr);
if (ret < 0)
ret = load_kernel(s->saved_kfn, (uint8_t *)s->saved_addr);
if (ret < 0) {
fprintf(stderr, "qemu: could not load kernel '%s'\n",
s->saved_kfn);
}
s->magic_state = 1; /* No more magic */
tb_flush();
return bswap32(ret);
}
return 0;
}
static void magic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
{
}
static CPUReadMemoryFunc *magic_mem_read[3] = {
magic_mem_readl,
magic_mem_readl,
magic_mem_readl,
};
static CPUWriteMemoryFunc *magic_mem_write[3] = {
magic_mem_writel,
magic_mem_writel,
magic_mem_writel,
};
void magic_init(const char *kfn, int kloadaddr, uint32_t addr)
{
int magic_io_memory;
MAGICState *s;
s = qemu_mallocz(sizeof(MAGICState));
if (!s)
return;
strcpy(s->saved_kfn, kfn);
s->saved_addr = kloadaddr;
s->magic_state = 0;
s->addr = addr;
magic_io_memory = cpu_register_io_memory(0, magic_mem_read, magic_mem_write, s);
cpu_register_physical_memory(addr, 4, magic_io_memory);
}

463
hw/mc146818rtc.c Normal file
View File

@@ -0,0 +1,463 @@
/*
* QEMU MC146818 RTC emulation
*
* Copyright (c) 2003-2004 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 "vl.h"
//#define DEBUG_CMOS
#define RTC_SECONDS 0
#define RTC_SECONDS_ALARM 1
#define RTC_MINUTES 2
#define RTC_MINUTES_ALARM 3
#define RTC_HOURS 4
#define RTC_HOURS_ALARM 5
#define RTC_ALARM_DONT_CARE 0xC0
#define RTC_DAY_OF_WEEK 6
#define RTC_DAY_OF_MONTH 7
#define RTC_MONTH 8
#define RTC_YEAR 9
#define RTC_REG_A 10
#define RTC_REG_B 11
#define RTC_REG_C 12
#define RTC_REG_D 13
#define REG_A_UIP 0x80
#define REG_B_SET 0x80
#define REG_B_PIE 0x40
#define REG_B_AIE 0x20
#define REG_B_UIE 0x10
struct RTCState {
uint8_t cmos_data[128];
uint8_t cmos_index;
struct tm current_tm;
int irq;
/* periodic timer */
QEMUTimer *periodic_timer;
int64_t next_periodic_time;
/* second update */
int64_t next_second_time;
QEMUTimer *second_timer;
QEMUTimer *second_timer2;
};
static void rtc_set_time(RTCState *s);
static void rtc_copy_date(RTCState *s);
static void rtc_timer_update(RTCState *s, int64_t current_time)
{
int period_code, period;
int64_t cur_clock, next_irq_clock;
period_code = s->cmos_data[RTC_REG_A] & 0x0f;
if (period_code != 0 &&
(s->cmos_data[RTC_REG_B] & REG_B_PIE)) {
if (period_code <= 2)
period_code += 7;
/* period in 32 Khz cycles */
period = 1 << (period_code - 1);
/* compute 32 khz clock */
cur_clock = muldiv64(current_time, 32768, ticks_per_sec);
next_irq_clock = (cur_clock & ~(period - 1)) + period;
s->next_periodic_time = muldiv64(next_irq_clock, ticks_per_sec, 32768) + 1;
qemu_mod_timer(s->periodic_timer, s->next_periodic_time);
} else {
qemu_del_timer(s->periodic_timer);
}
}
static void rtc_periodic_timer(void *opaque)
{
RTCState *s = opaque;
rtc_timer_update(s, s->next_periodic_time);
s->cmos_data[RTC_REG_C] |= 0xc0;
pic_set_irq(s->irq, 1);
}
static void cmos_ioport_write(void *opaque, uint32_t addr, uint32_t data)
{
RTCState *s = opaque;
if ((addr & 1) == 0) {
s->cmos_index = data & 0x7f;
} else {
#ifdef DEBUG_CMOS
printf("cmos: write index=0x%02x val=0x%02x\n",
s->cmos_index, data);
#endif
switch(s->cmos_index) {
case RTC_SECONDS_ALARM:
case RTC_MINUTES_ALARM:
case RTC_HOURS_ALARM:
/* XXX: not supported */
s->cmos_data[s->cmos_index] = data;
break;
case RTC_SECONDS:
case RTC_MINUTES:
case RTC_HOURS:
case RTC_DAY_OF_WEEK:
case RTC_DAY_OF_MONTH:
case RTC_MONTH:
case RTC_YEAR:
s->cmos_data[s->cmos_index] = data;
/* if in set mode, do not update the time */
if (!(s->cmos_data[RTC_REG_B] & REG_B_SET)) {
rtc_set_time(s);
}
break;
case RTC_REG_A:
/* UIP bit is read only */
s->cmos_data[RTC_REG_A] = (data & ~REG_A_UIP) |
(s->cmos_data[RTC_REG_A] & REG_A_UIP);
rtc_timer_update(s, qemu_get_clock(vm_clock));
break;
case RTC_REG_B:
if (data & REG_B_SET) {
/* set mode: reset UIP mode */
s->cmos_data[RTC_REG_A] &= ~REG_A_UIP;
data &= ~REG_B_UIE;
} else {
/* if disabling set mode, update the time */
if (s->cmos_data[RTC_REG_B] & REG_B_SET) {
rtc_set_time(s);
}
}
s->cmos_data[RTC_REG_B] = data;
rtc_timer_update(s, qemu_get_clock(vm_clock));
break;
case RTC_REG_C:
case RTC_REG_D:
/* cannot write to them */
break;
default:
s->cmos_data[s->cmos_index] = data;
break;
}
}
}
static inline int to_bcd(RTCState *s, int a)
{
if (s->cmos_data[RTC_REG_B] & 0x04) {
return a;
} else {
return ((a / 10) << 4) | (a % 10);
}
}
static inline int from_bcd(RTCState *s, int a)
{
if (s->cmos_data[RTC_REG_B] & 0x04) {
return a;
} else {
return ((a >> 4) * 10) + (a & 0x0f);
}
}
static void rtc_set_time(RTCState *s)
{
struct tm *tm = &s->current_tm;
tm->tm_sec = from_bcd(s, s->cmos_data[RTC_SECONDS]);
tm->tm_min = from_bcd(s, s->cmos_data[RTC_MINUTES]);
tm->tm_hour = from_bcd(s, s->cmos_data[RTC_HOURS] & 0x7f);
if (!(s->cmos_data[RTC_REG_B] & 0x02) &&
(s->cmos_data[RTC_HOURS] & 0x80)) {
tm->tm_hour += 12;
}
tm->tm_wday = from_bcd(s, s->cmos_data[RTC_DAY_OF_WEEK]);
tm->tm_mday = from_bcd(s, s->cmos_data[RTC_DAY_OF_MONTH]);
tm->tm_mon = from_bcd(s, s->cmos_data[RTC_MONTH]) - 1;
tm->tm_year = from_bcd(s, s->cmos_data[RTC_YEAR]) + 100;
}
static void rtc_copy_date(RTCState *s)
{
const struct tm *tm = &s->current_tm;
s->cmos_data[RTC_SECONDS] = to_bcd(s, tm->tm_sec);
s->cmos_data[RTC_MINUTES] = to_bcd(s, tm->tm_min);
if (s->cmos_data[RTC_REG_B] & 0x02) {
/* 24 hour format */
s->cmos_data[RTC_HOURS] = to_bcd(s, tm->tm_hour);
} else {
/* 12 hour format */
s->cmos_data[RTC_HOURS] = to_bcd(s, tm->tm_hour % 12);
if (tm->tm_hour >= 12)
s->cmos_data[RTC_HOURS] |= 0x80;
}
s->cmos_data[RTC_DAY_OF_WEEK] = to_bcd(s, tm->tm_wday);
s->cmos_data[RTC_DAY_OF_MONTH] = to_bcd(s, tm->tm_mday);
s->cmos_data[RTC_MONTH] = to_bcd(s, tm->tm_mon + 1);
s->cmos_data[RTC_YEAR] = to_bcd(s, tm->tm_year % 100);
}
/* month is between 0 and 11. */
static int get_days_in_month(int month, int year)
{
static const int days_tab[12] = {
31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
};
int d;
if ((unsigned )month >= 12)
return 31;
d = days_tab[month];
if (month == 1) {
if ((year % 4) == 0 && ((year % 100) != 0 || (year % 400) == 0))
d++;
}
return d;
}
/* update 'tm' to the next second */
static void rtc_next_second(struct tm *tm)
{
int days_in_month;
tm->tm_sec++;
if ((unsigned)tm->tm_sec >= 60) {
tm->tm_sec = 0;
tm->tm_min++;
if ((unsigned)tm->tm_min >= 60) {
tm->tm_min = 0;
tm->tm_hour++;
if ((unsigned)tm->tm_hour >= 24) {
tm->tm_hour = 0;
/* next day */
tm->tm_wday++;
if ((unsigned)tm->tm_wday >= 7)
tm->tm_wday = 0;
days_in_month = get_days_in_month(tm->tm_mon,
tm->tm_year + 1900);
tm->tm_mday++;
if (tm->tm_mday < 1) {
tm->tm_mday = 1;
} else if (tm->tm_mday > days_in_month) {
tm->tm_mday = 1;
tm->tm_mon++;
if (tm->tm_mon >= 12) {
tm->tm_mon = 0;
tm->tm_year++;
}
}
}
}
}
}
static void rtc_update_second(void *opaque)
{
RTCState *s = opaque;
int64_t delay;
/* if the oscillator is not in normal operation, we do not update */
if ((s->cmos_data[RTC_REG_A] & 0x70) != 0x20) {
s->next_second_time += ticks_per_sec;
qemu_mod_timer(s->second_timer, s->next_second_time);
} else {
rtc_next_second(&s->current_tm);
if (!(s->cmos_data[RTC_REG_B] & REG_B_SET)) {
/* update in progress bit */
s->cmos_data[RTC_REG_A] |= REG_A_UIP;
}
/* should be 244 us = 8 / 32768 seconds, but currently the
timers do not have the necessary resolution. */
delay = (ticks_per_sec * 1) / 100;
if (delay < 1)
delay = 1;
qemu_mod_timer(s->second_timer2,
s->next_second_time + delay);
}
}
static void rtc_update_second2(void *opaque)
{
RTCState *s = opaque;
if (!(s->cmos_data[RTC_REG_B] & REG_B_SET)) {
rtc_copy_date(s);
}
/* check alarm */
if (s->cmos_data[RTC_REG_B] & REG_B_AIE) {
if (((s->cmos_data[RTC_SECONDS_ALARM] & 0xc0) == 0xc0 ||
s->cmos_data[RTC_SECONDS_ALARM] == s->current_tm.tm_sec) &&
((s->cmos_data[RTC_MINUTES_ALARM] & 0xc0) == 0xc0 ||
s->cmos_data[RTC_MINUTES_ALARM] == s->current_tm.tm_mon) &&
((s->cmos_data[RTC_HOURS_ALARM] & 0xc0) == 0xc0 ||
s->cmos_data[RTC_HOURS_ALARM] == s->current_tm.tm_hour)) {
s->cmos_data[RTC_REG_C] |= 0xa0;
pic_set_irq(s->irq, 1);
}
}
/* update ended interrupt */
if (s->cmos_data[RTC_REG_B] & REG_B_UIE) {
s->cmos_data[RTC_REG_C] |= 0x90;
pic_set_irq(s->irq, 1);
}
/* clear update in progress bit */
s->cmos_data[RTC_REG_A] &= ~REG_A_UIP;
s->next_second_time += ticks_per_sec;
qemu_mod_timer(s->second_timer, s->next_second_time);
}
static uint32_t cmos_ioport_read(void *opaque, uint32_t addr)
{
RTCState *s = opaque;
int ret;
if ((addr & 1) == 0) {
return 0xff;
} else {
switch(s->cmos_index) {
case RTC_SECONDS:
case RTC_MINUTES:
case RTC_HOURS:
case RTC_DAY_OF_WEEK:
case RTC_DAY_OF_MONTH:
case RTC_MONTH:
case RTC_YEAR:
ret = s->cmos_data[s->cmos_index];
break;
case RTC_REG_A:
ret = s->cmos_data[s->cmos_index];
break;
case RTC_REG_C:
ret = s->cmos_data[s->cmos_index];
pic_set_irq(s->irq, 0);
s->cmos_data[RTC_REG_C] = 0x00;
break;
default:
ret = s->cmos_data[s->cmos_index];
break;
}
#ifdef DEBUG_CMOS
printf("cmos: read index=0x%02x val=0x%02x\n",
s->cmos_index, ret);
#endif
return ret;
}
}
void rtc_set_memory(RTCState *s, int addr, int val)
{
if (addr >= 0 && addr <= 127)
s->cmos_data[addr] = val;
}
void rtc_set_date(RTCState *s, const struct tm *tm)
{
s->current_tm = *tm;
rtc_copy_date(s);
}
static void rtc_save(QEMUFile *f, void *opaque)
{
RTCState *s = opaque;
qemu_put_buffer(f, s->cmos_data, 128);
qemu_put_8s(f, &s->cmos_index);
qemu_put_be32s(f, &s->current_tm.tm_sec);
qemu_put_be32s(f, &s->current_tm.tm_min);
qemu_put_be32s(f, &s->current_tm.tm_hour);
qemu_put_be32s(f, &s->current_tm.tm_wday);
qemu_put_be32s(f, &s->current_tm.tm_mday);
qemu_put_be32s(f, &s->current_tm.tm_mon);
qemu_put_be32s(f, &s->current_tm.tm_year);
qemu_put_timer(f, s->periodic_timer);
qemu_put_be64s(f, &s->next_periodic_time);
qemu_put_be64s(f, &s->next_second_time);
qemu_put_timer(f, s->second_timer);
qemu_put_timer(f, s->second_timer2);
}
static int rtc_load(QEMUFile *f, void *opaque, int version_id)
{
RTCState *s = opaque;
if (version_id != 1)
return -EINVAL;
qemu_get_buffer(f, s->cmos_data, 128);
qemu_get_8s(f, &s->cmos_index);
qemu_get_be32s(f, &s->current_tm.tm_sec);
qemu_get_be32s(f, &s->current_tm.tm_min);
qemu_get_be32s(f, &s->current_tm.tm_hour);
qemu_get_be32s(f, &s->current_tm.tm_wday);
qemu_get_be32s(f, &s->current_tm.tm_mday);
qemu_get_be32s(f, &s->current_tm.tm_mon);
qemu_get_be32s(f, &s->current_tm.tm_year);
qemu_get_timer(f, s->periodic_timer);
qemu_get_be64s(f, &s->next_periodic_time);
qemu_get_be64s(f, &s->next_second_time);
qemu_get_timer(f, s->second_timer);
qemu_get_timer(f, s->second_timer2);
return 0;
}
RTCState *rtc_init(int base, int irq)
{
RTCState *s;
s = qemu_mallocz(sizeof(RTCState));
if (!s)
return NULL;
s->irq = irq;
s->cmos_data[RTC_REG_A] = 0x26;
s->cmos_data[RTC_REG_B] = 0x02;
s->cmos_data[RTC_REG_C] = 0x00;
s->cmos_data[RTC_REG_D] = 0x80;
s->periodic_timer = qemu_new_timer(vm_clock,
rtc_periodic_timer, s);
s->second_timer = qemu_new_timer(vm_clock,
rtc_update_second, s);
s->second_timer2 = qemu_new_timer(vm_clock,
rtc_update_second2, s);
s->next_second_time = qemu_get_clock(vm_clock) + (ticks_per_sec * 99) / 100;
qemu_mod_timer(s->second_timer2, s->next_second_time);
register_ioport_write(base, 2, 1, cmos_ioport_write, s);
register_ioport_read(base, 2, 1, cmos_ioport_read, s);
register_savevm("mc146818rtc", base, 1, rtc_save, rtc_load, s);
return s;
}

684
hw/ne2000.c Normal file
View File

@@ -0,0 +1,684 @@
/*
* QEMU NE2000 emulation
*
* Copyright (c) 2003-2004 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 "vl.h"
/* debug NE2000 card */
//#define DEBUG_NE2000
#define MAX_ETH_FRAME_SIZE 1514
#define E8390_CMD 0x00 /* The command register (for all pages) */
/* Page 0 register offsets. */
#define EN0_CLDALO 0x01 /* Low byte of current local dma addr RD */
#define EN0_STARTPG 0x01 /* Starting page of ring bfr WR */
#define EN0_CLDAHI 0x02 /* High byte of current local dma addr RD */
#define EN0_STOPPG 0x02 /* Ending page +1 of ring bfr WR */
#define EN0_BOUNDARY 0x03 /* Boundary page of ring bfr RD WR */
#define EN0_TSR 0x04 /* Transmit status reg RD */
#define EN0_TPSR 0x04 /* Transmit starting page WR */
#define EN0_NCR 0x05 /* Number of collision reg RD */
#define EN0_TCNTLO 0x05 /* Low byte of tx byte count WR */
#define EN0_FIFO 0x06 /* FIFO RD */
#define EN0_TCNTHI 0x06 /* High byte of tx byte count WR */
#define EN0_ISR 0x07 /* Interrupt status reg RD WR */
#define EN0_CRDALO 0x08 /* low byte of current remote dma address RD */
#define EN0_RSARLO 0x08 /* Remote start address reg 0 */
#define EN0_CRDAHI 0x09 /* high byte, current remote dma address RD */
#define EN0_RSARHI 0x09 /* Remote start address reg 1 */
#define EN0_RCNTLO 0x0a /* Remote byte count reg WR */
#define EN0_RCNTHI 0x0b /* Remote byte count reg WR */
#define EN0_RSR 0x0c /* rx status reg RD */
#define EN0_RXCR 0x0c /* RX configuration reg WR */
#define EN0_TXCR 0x0d /* TX configuration reg WR */
#define EN0_COUNTER0 0x0d /* Rcv alignment error counter RD */
#define EN0_DCFG 0x0e /* Data configuration reg WR */
#define EN0_COUNTER1 0x0e /* Rcv CRC error counter RD */
#define EN0_IMR 0x0f /* Interrupt mask reg WR */
#define EN0_COUNTER2 0x0f /* Rcv missed frame error counter RD */
#define EN1_PHYS 0x11
#define EN1_CURPAG 0x17
#define EN1_MULT 0x18
/* Register accessed at EN_CMD, the 8390 base addr. */
#define E8390_STOP 0x01 /* Stop and reset the chip */
#define E8390_START 0x02 /* Start the chip, clear reset */
#define E8390_TRANS 0x04 /* Transmit a frame */
#define E8390_RREAD 0x08 /* Remote read */
#define E8390_RWRITE 0x10 /* Remote write */
#define E8390_NODMA 0x20 /* Remote DMA */
#define E8390_PAGE0 0x00 /* Select page chip registers */
#define E8390_PAGE1 0x40 /* using the two high-order bits */
#define E8390_PAGE2 0x80 /* Page 3 is invalid. */
/* Bits in EN0_ISR - Interrupt status register */
#define ENISR_RX 0x01 /* Receiver, no error */
#define ENISR_TX 0x02 /* Transmitter, no error */
#define ENISR_RX_ERR 0x04 /* Receiver, with error */
#define ENISR_TX_ERR 0x08 /* Transmitter, with error */
#define ENISR_OVER 0x10 /* Receiver overwrote the ring */
#define ENISR_COUNTERS 0x20 /* Counters need emptying */
#define ENISR_RDC 0x40 /* remote dma complete */
#define ENISR_RESET 0x80 /* Reset completed */
#define ENISR_ALL 0x3f /* Interrupts we will enable */
/* Bits in received packet status byte and EN0_RSR*/
#define ENRSR_RXOK 0x01 /* Received a good packet */
#define ENRSR_CRC 0x02 /* CRC error */
#define ENRSR_FAE 0x04 /* frame alignment error */
#define ENRSR_FO 0x08 /* FIFO overrun */
#define ENRSR_MPA 0x10 /* missed pkt */
#define ENRSR_PHY 0x20 /* physical/multicast address */
#define ENRSR_DIS 0x40 /* receiver disable. set in monitor mode */
#define ENRSR_DEF 0x80 /* deferring */
/* Transmitted packet status, EN0_TSR. */
#define ENTSR_PTX 0x01 /* Packet transmitted without error */
#define ENTSR_ND 0x02 /* The transmit wasn't deferred. */
#define ENTSR_COL 0x04 /* The transmit collided at least once. */
#define ENTSR_ABT 0x08 /* The transmit collided 16 times, and was deferred. */
#define ENTSR_CRS 0x10 /* The carrier sense was lost. */
#define ENTSR_FU 0x20 /* A "FIFO underrun" occurred during transmit. */
#define ENTSR_CDH 0x40 /* The collision detect "heartbeat" signal was lost. */
#define ENTSR_OWC 0x80 /* There was an out-of-window collision. */
#define NE2000_PMEM_SIZE (32*1024)
#define NE2000_PMEM_START (16*1024)
#define NE2000_PMEM_END (NE2000_PMEM_SIZE+NE2000_PMEM_START)
#define NE2000_MEM_SIZE NE2000_PMEM_END
typedef struct NE2000State {
uint8_t cmd;
uint32_t start;
uint32_t stop;
uint8_t boundary;
uint8_t tsr;
uint8_t tpsr;
uint16_t tcnt;
uint16_t rcnt;
uint32_t rsar;
uint8_t rsr;
uint8_t isr;
uint8_t dcfg;
uint8_t imr;
uint8_t phys[6]; /* mac address */
uint8_t curpag;
uint8_t mult[8]; /* multicast mask array */
int irq;
PCIDevice *pci_dev;
NetDriverState *nd;
uint8_t mem[NE2000_MEM_SIZE];
} NE2000State;
static void ne2000_reset(NE2000State *s)
{
int i;
s->isr = ENISR_RESET;
memcpy(s->mem, s->nd->macaddr, 6);
s->mem[14] = 0x57;
s->mem[15] = 0x57;
/* duplicate prom data */
for(i = 15;i >= 0; i--) {
s->mem[2 * i] = s->mem[i];
s->mem[2 * i + 1] = s->mem[i];
}
}
static void ne2000_update_irq(NE2000State *s)
{
int isr;
isr = s->isr & s->imr;
#if defined(DEBUG_NE2000)
printf("NE2000: Set IRQ line %d to %d (%02x %02x)\n",
s->irq, isr ? 1 : 0, s->isr, s->imr);
#endif
if (s->irq == 16) {
/* PCI irq */
pci_set_irq(s->pci_dev, 0, (isr != 0));
} else {
/* ISA irq */
pic_set_irq(s->irq, (isr != 0));
}
}
/* return the max buffer size if the NE2000 can receive more data */
static int ne2000_can_receive(void *opaque)
{
NE2000State *s = opaque;
int avail, index, boundary;
if (s->cmd & E8390_STOP)
return 0;
index = s->curpag << 8;
boundary = s->boundary << 8;
if (index < boundary)
avail = boundary - index;
else
avail = (s->stop - s->start) - (index - boundary);
if (avail < (MAX_ETH_FRAME_SIZE + 4))
return 0;
return MAX_ETH_FRAME_SIZE;
}
#define MIN_BUF_SIZE 60
static void ne2000_receive(void *opaque, const uint8_t *buf, int size)
{
NE2000State *s = opaque;
uint8_t *p;
int total_len, next, avail, len, index;
uint8_t buf1[60];
#if defined(DEBUG_NE2000)
printf("NE2000: received len=%d\n", size);
#endif
/* if too small buffer, then expand it */
if (size < MIN_BUF_SIZE) {
memcpy(buf1, buf, size);
memset(buf1 + size, 0, MIN_BUF_SIZE - size);
buf = buf1;
size = MIN_BUF_SIZE;
}
index = s->curpag << 8;
/* 4 bytes for header */
total_len = size + 4;
/* address for next packet (4 bytes for CRC) */
next = index + ((total_len + 4 + 255) & ~0xff);
if (next >= s->stop)
next -= (s->stop - s->start);
/* prepare packet header */
p = s->mem + index;
s->rsr = ENRSR_RXOK; /* receive status */
/* XXX: check this */
if (buf[0] & 0x01)
s->rsr |= ENRSR_PHY;
p[0] = s->rsr;
p[1] = next >> 8;
p[2] = total_len;
p[3] = total_len >> 8;
index += 4;
/* write packet data */
while (size > 0) {
avail = s->stop - index;
len = size;
if (len > avail)
len = avail;
memcpy(s->mem + index, buf, len);
buf += len;
index += len;
if (index == s->stop)
index = s->start;
size -= len;
}
s->curpag = next >> 8;
/* now we can signal we have receive something */
s->isr |= ENISR_RX;
ne2000_update_irq(s);
}
static void ne2000_ioport_write(void *opaque, uint32_t addr, uint32_t val)
{
NE2000State *s = opaque;
int offset, page;
addr &= 0xf;
#ifdef DEBUG_NE2000
printf("NE2000: write addr=0x%x val=0x%02x\n", addr, val);
#endif
if (addr == E8390_CMD) {
/* control register */
s->cmd = val;
if (val & E8390_START) {
s->isr &= ~ENISR_RESET;
/* test specific case: zero length transfert */
if ((val & (E8390_RREAD | E8390_RWRITE)) &&
s->rcnt == 0) {
s->isr |= ENISR_RDC;
ne2000_update_irq(s);
}
if (val & E8390_TRANS) {
qemu_send_packet(s->nd, s->mem + (s->tpsr << 8), s->tcnt);
/* signal end of transfert */
s->tsr = ENTSR_PTX;
s->isr |= ENISR_TX;
ne2000_update_irq(s);
}
}
} else {
page = s->cmd >> 6;
offset = addr | (page << 4);
switch(offset) {
case EN0_STARTPG:
s->start = val << 8;
break;
case EN0_STOPPG:
s->stop = val << 8;
break;
case EN0_BOUNDARY:
s->boundary = val;
break;
case EN0_IMR:
s->imr = val;
ne2000_update_irq(s);
break;
case EN0_TPSR:
s->tpsr = val;
break;
case EN0_TCNTLO:
s->tcnt = (s->tcnt & 0xff00) | val;
break;
case EN0_TCNTHI:
s->tcnt = (s->tcnt & 0x00ff) | (val << 8);
break;
case EN0_RSARLO:
s->rsar = (s->rsar & 0xff00) | val;
break;
case EN0_RSARHI:
s->rsar = (s->rsar & 0x00ff) | (val << 8);
break;
case EN0_RCNTLO:
s->rcnt = (s->rcnt & 0xff00) | val;
break;
case EN0_RCNTHI:
s->rcnt = (s->rcnt & 0x00ff) | (val << 8);
break;
case EN0_DCFG:
s->dcfg = val;
break;
case EN0_ISR:
s->isr &= ~(val & 0x7f);
ne2000_update_irq(s);
break;
case EN1_PHYS ... EN1_PHYS + 5:
s->phys[offset - EN1_PHYS] = val;
break;
case EN1_CURPAG:
s->curpag = val;
break;
case EN1_MULT ... EN1_MULT + 7:
s->mult[offset - EN1_MULT] = val;
break;
}
}
}
static uint32_t ne2000_ioport_read(void *opaque, uint32_t addr)
{
NE2000State *s = opaque;
int offset, page, ret;
addr &= 0xf;
if (addr == E8390_CMD) {
ret = s->cmd;
} else {
page = s->cmd >> 6;
offset = addr | (page << 4);
switch(offset) {
case EN0_TSR:
ret = s->tsr;
break;
case EN0_BOUNDARY:
ret = s->boundary;
break;
case EN0_ISR:
ret = s->isr;
break;
case EN0_RSARLO:
ret = s->rsar & 0x00ff;
break;
case EN0_RSARHI:
ret = s->rsar >> 8;
break;
case EN1_PHYS ... EN1_PHYS + 5:
ret = s->phys[offset - EN1_PHYS];
break;
case EN1_CURPAG:
ret = s->curpag;
break;
case EN1_MULT ... EN1_MULT + 7:
ret = s->mult[offset - EN1_MULT];
break;
case EN0_RSR:
ret = s->rsr;
break;
default:
ret = 0x00;
break;
}
}
#ifdef DEBUG_NE2000
printf("NE2000: read addr=0x%x val=%02x\n", addr, ret);
#endif
return ret;
}
static inline void ne2000_mem_writeb(NE2000State *s, uint32_t addr,
uint32_t val)
{
if (addr < 32 ||
(addr >= NE2000_PMEM_START && addr < NE2000_MEM_SIZE)) {
s->mem[addr] = val;
}
}
static inline void ne2000_mem_writew(NE2000State *s, uint32_t addr,
uint32_t val)
{
addr &= ~1; /* XXX: check exact behaviour if not even */
if (addr < 32 ||
(addr >= NE2000_PMEM_START && addr < NE2000_MEM_SIZE)) {
*(uint16_t *)(s->mem + addr) = cpu_to_le16(val);
}
}
static inline void ne2000_mem_writel(NE2000State *s, uint32_t addr,
uint32_t val)
{
addr &= ~1; /* XXX: check exact behaviour if not even */
if (addr < 32 ||
(addr >= NE2000_PMEM_START && addr < NE2000_MEM_SIZE)) {
cpu_to_le32wu((uint32_t *)(s->mem + addr), val);
}
}
static inline uint32_t ne2000_mem_readb(NE2000State *s, uint32_t addr)
{
if (addr < 32 ||
(addr >= NE2000_PMEM_START && addr < NE2000_MEM_SIZE)) {
return s->mem[addr];
} else {
return 0xff;
}
}
static inline uint32_t ne2000_mem_readw(NE2000State *s, uint32_t addr)
{
addr &= ~1; /* XXX: check exact behaviour if not even */
if (addr < 32 ||
(addr >= NE2000_PMEM_START && addr < NE2000_MEM_SIZE)) {
return le16_to_cpu(*(uint16_t *)(s->mem + addr));
} else {
return 0xffff;
}
}
static inline uint32_t ne2000_mem_readl(NE2000State *s, uint32_t addr)
{
addr &= ~1; /* XXX: check exact behaviour if not even */
if (addr < 32 ||
(addr >= NE2000_PMEM_START && addr < NE2000_MEM_SIZE)) {
return le32_to_cpupu((uint32_t *)(s->mem + addr));
} else {
return 0xffffffff;
}
}
static inline void ne2000_dma_update(NE2000State *s, int len)
{
s->rsar += len;
/* wrap */
/* XXX: check what to do if rsar > stop */
if (s->rsar == s->stop)
s->rsar = s->start;
if (s->rcnt <= len) {
s->rcnt = 0;
/* signal end of transfert */
s->isr |= ENISR_RDC;
ne2000_update_irq(s);
} else {
s->rcnt -= len;
}
}
static void ne2000_asic_ioport_write(void *opaque, uint32_t addr, uint32_t val)
{
NE2000State *s = opaque;
#ifdef DEBUG_NE2000
printf("NE2000: asic write val=0x%04x\n", val);
#endif
if (s->rcnt == 0)
return;
if (s->dcfg & 0x01) {
/* 16 bit access */
ne2000_mem_writew(s, s->rsar, val);
ne2000_dma_update(s, 2);
} else {
/* 8 bit access */
ne2000_mem_writeb(s, s->rsar, val);
ne2000_dma_update(s, 1);
}
}
static uint32_t ne2000_asic_ioport_read(void *opaque, uint32_t addr)
{
NE2000State *s = opaque;
int ret;
if (s->dcfg & 0x01) {
/* 16 bit access */
ret = ne2000_mem_readw(s, s->rsar);
ne2000_dma_update(s, 2);
} else {
/* 8 bit access */
ret = ne2000_mem_readb(s, s->rsar);
ne2000_dma_update(s, 1);
}
#ifdef DEBUG_NE2000
printf("NE2000: asic read val=0x%04x\n", ret);
#endif
return ret;
}
static void ne2000_asic_ioport_writel(void *opaque, uint32_t addr, uint32_t val)
{
NE2000State *s = opaque;
#ifdef DEBUG_NE2000
printf("NE2000: asic writel val=0x%04x\n", val);
#endif
if (s->rcnt == 0)
return;
/* 32 bit access */
ne2000_mem_writel(s, s->rsar, val);
ne2000_dma_update(s, 4);
}
static uint32_t ne2000_asic_ioport_readl(void *opaque, uint32_t addr)
{
NE2000State *s = opaque;
int ret;
/* 32 bit access */
ret = ne2000_mem_readl(s, s->rsar);
ne2000_dma_update(s, 4);
#ifdef DEBUG_NE2000
printf("NE2000: asic readl val=0x%04x\n", ret);
#endif
return ret;
}
static void ne2000_reset_ioport_write(void *opaque, uint32_t addr, uint32_t val)
{
/* nothing to do (end of reset pulse) */
}
static uint32_t ne2000_reset_ioport_read(void *opaque, uint32_t addr)
{
NE2000State *s = opaque;
ne2000_reset(s);
return 0;
}
static void ne2000_save(QEMUFile* f,void* opaque)
{
NE2000State* s=(NE2000State*)opaque;
qemu_put_8s(f, &s->cmd);
qemu_put_be32s(f, &s->start);
qemu_put_be32s(f, &s->stop);
qemu_put_8s(f, &s->boundary);
qemu_put_8s(f, &s->tsr);
qemu_put_8s(f, &s->tpsr);
qemu_put_be16s(f, &s->tcnt);
qemu_put_be16s(f, &s->rcnt);
qemu_put_be32s(f, &s->rsar);
qemu_put_8s(f, &s->rsr);
qemu_put_8s(f, &s->isr);
qemu_put_8s(f, &s->dcfg);
qemu_put_8s(f, &s->imr);
qemu_put_buffer(f, s->phys, 6);
qemu_put_8s(f, &s->curpag);
qemu_put_buffer(f, s->mult, 8);
qemu_put_be32s(f, &s->irq);
qemu_put_buffer(f, s->mem, NE2000_MEM_SIZE);
}
static int ne2000_load(QEMUFile* f,void* opaque,int version_id)
{
NE2000State* s=(NE2000State*)opaque;
if (version_id != 1)
return -EINVAL;
qemu_get_8s(f, &s->cmd);
qemu_get_be32s(f, &s->start);
qemu_get_be32s(f, &s->stop);
qemu_get_8s(f, &s->boundary);
qemu_get_8s(f, &s->tsr);
qemu_get_8s(f, &s->tpsr);
qemu_get_be16s(f, &s->tcnt);
qemu_get_be16s(f, &s->rcnt);
qemu_get_be32s(f, &s->rsar);
qemu_get_8s(f, &s->rsr);
qemu_get_8s(f, &s->isr);
qemu_get_8s(f, &s->dcfg);
qemu_get_8s(f, &s->imr);
qemu_get_buffer(f, s->phys, 6);
qemu_get_8s(f, &s->curpag);
qemu_get_buffer(f, s->mult, 8);
qemu_get_be32s(f, &s->irq);
qemu_get_buffer(f, s->mem, NE2000_MEM_SIZE);
return 0;
}
void isa_ne2000_init(int base, int irq, NetDriverState *nd)
{
NE2000State *s;
s = qemu_mallocz(sizeof(NE2000State));
if (!s)
return;
register_ioport_write(base, 16, 1, ne2000_ioport_write, s);
register_ioport_read(base, 16, 1, ne2000_ioport_read, s);
register_ioport_write(base + 0x10, 1, 1, ne2000_asic_ioport_write, s);
register_ioport_read(base + 0x10, 1, 1, ne2000_asic_ioport_read, s);
register_ioport_write(base + 0x10, 2, 2, ne2000_asic_ioport_write, s);
register_ioport_read(base + 0x10, 2, 2, ne2000_asic_ioport_read, s);
register_ioport_write(base + 0x1f, 1, 1, ne2000_reset_ioport_write, s);
register_ioport_read(base + 0x1f, 1, 1, ne2000_reset_ioport_read, s);
s->irq = irq;
s->nd = nd;
ne2000_reset(s);
qemu_add_read_packet(nd, ne2000_can_receive, ne2000_receive, s);
register_savevm("ne2000", 0, 1, ne2000_save, ne2000_load, s);
}
/***********************************************************/
/* PCI NE2000 definitions */
typedef struct PCINE2000State {
PCIDevice dev;
NE2000State ne2000;
} PCINE2000State;
static void ne2000_map(PCIDevice *pci_dev, int region_num,
uint32_t addr, uint32_t size, int type)
{
PCINE2000State *d = (PCINE2000State *)pci_dev;
NE2000State *s = &d->ne2000;
register_ioport_write(addr, 16, 1, ne2000_ioport_write, s);
register_ioport_read(addr, 16, 1, ne2000_ioport_read, s);
register_ioport_write(addr + 0x10, 1, 1, ne2000_asic_ioport_write, s);
register_ioport_read(addr + 0x10, 1, 1, ne2000_asic_ioport_read, s);
register_ioport_write(addr + 0x10, 2, 2, ne2000_asic_ioport_write, s);
register_ioport_read(addr + 0x10, 2, 2, ne2000_asic_ioport_read, s);
register_ioport_write(addr + 0x10, 4, 4, ne2000_asic_ioport_writel, s);
register_ioport_read(addr + 0x10, 4, 4, ne2000_asic_ioport_readl, s);
register_ioport_write(addr + 0x1f, 1, 1, ne2000_reset_ioport_write, s);
register_ioport_read(addr + 0x1f, 1, 1, ne2000_reset_ioport_read, s);
}
void pci_ne2000_init(PCIBus *bus, NetDriverState *nd)
{
PCINE2000State *d;
NE2000State *s;
uint8_t *pci_conf;
d = (PCINE2000State *)pci_register_device(bus,
"NE2000", sizeof(PCINE2000State),
-1,
NULL, NULL);
pci_conf = d->dev.config;
pci_conf[0x00] = 0xec; // Realtek 8029
pci_conf[0x01] = 0x10;
pci_conf[0x02] = 0x29;
pci_conf[0x03] = 0x80;
pci_conf[0x0a] = 0x00; // ethernet network controller
pci_conf[0x0b] = 0x02;
pci_conf[0x0e] = 0x00; // header_type
pci_conf[0x3d] = 1; // interrupt pin 0
pci_register_io_region(&d->dev, 0, 0x100,
PCI_ADDRESS_SPACE_IO, ne2000_map);
s = &d->ne2000;
s->irq = 16; // PCI interrupt
s->pci_dev = (PCIDevice *)d;
s->nd = nd;
ne2000_reset(s);
qemu_add_read_packet(nd, ne2000_can_receive, ne2000_receive, s);
/* XXX: instance number ? */
register_savevm("ne2000", 0, 1, ne2000_save, ne2000_load, s);
register_savevm("ne2000_pci", 0, 1, generic_pci_save, generic_pci_load,
&d->dev);
}

1023
hw/openpic.c Normal file

File diff suppressed because it is too large Load Diff

582
hw/pc.c Normal file
View File

@@ -0,0 +1,582 @@
/*
* QEMU PC System Emulator
*
* Copyright (c) 2003-2004 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 "vl.h"
/* output Bochs bios info messages */
//#define DEBUG_BIOS
#define BIOS_FILENAME "bios.bin"
#define VGABIOS_FILENAME "vgabios.bin"
#define VGABIOS_CIRRUS_FILENAME "vgabios-cirrus.bin"
#define LINUX_BOOT_FILENAME "linux_boot.bin"
#define KERNEL_LOAD_ADDR 0x00100000
#define INITRD_LOAD_ADDR 0x00400000
#define KERNEL_PARAMS_ADDR 0x00090000
#define KERNEL_CMDLINE_ADDR 0x00099000
int speaker_data_on;
int dummy_refresh_clock;
static fdctrl_t *floppy_controller;
static RTCState *rtc_state;
static PITState *pit;
static void ioport80_write(void *opaque, uint32_t addr, uint32_t data)
{
}
/* MSDOS compatibility mode FPU exception support */
/* XXX: add IGNNE support */
void cpu_set_ferr(CPUX86State *s)
{
pic_set_irq(13, 1);
}
static void ioportF0_write(void *opaque, uint32_t addr, uint32_t data)
{
pic_set_irq(13, 0);
}
/* TSC handling */
uint64_t cpu_get_tsc(CPUX86State *env)
{
return qemu_get_clock(vm_clock);
}
/* PC cmos mappings */
#define REG_EQUIPMENT_BYTE 0x14
#define REG_IBM_CENTURY_BYTE 0x32
#define REG_IBM_PS2_CENTURY_BYTE 0x37
static inline int to_bcd(RTCState *s, int a)
{
return ((a / 10) << 4) | (a % 10);
}
static int cmos_get_fd_drive_type(int fd0)
{
int val;
switch (fd0) {
case 0:
/* 1.44 Mb 3"5 drive */
val = 4;
break;
case 1:
/* 2.88 Mb 3"5 drive */
val = 5;
break;
case 2:
/* 1.2 Mb 5"5 drive */
val = 2;
break;
default:
val = 0;
break;
}
return val;
}
static void cmos_init_hd(int type_ofs, int info_ofs, BlockDriverState *hd)
{
RTCState *s = rtc_state;
int cylinders, heads, sectors;
bdrv_get_geometry_hint(hd, &cylinders, &heads, &sectors);
rtc_set_memory(s, type_ofs, 47);
rtc_set_memory(s, info_ofs, cylinders);
rtc_set_memory(s, info_ofs + 1, cylinders >> 8);
rtc_set_memory(s, info_ofs + 2, heads);
rtc_set_memory(s, info_ofs + 3, 0xff);
rtc_set_memory(s, info_ofs + 4, 0xff);
rtc_set_memory(s, info_ofs + 5, 0xc0 | ((heads > 8) << 3));
rtc_set_memory(s, info_ofs + 6, cylinders);
rtc_set_memory(s, info_ofs + 7, cylinders >> 8);
rtc_set_memory(s, info_ofs + 8, sectors);
}
/* hd_table must contain 4 block drivers */
static void cmos_init(int ram_size, int boot_device, BlockDriverState **hd_table)
{
RTCState *s = rtc_state;
int val;
int fd0, fd1, nb;
time_t ti;
struct tm *tm;
int i;
/* set the CMOS date */
time(&ti);
if (rtc_utc)
tm = gmtime(&ti);
else
tm = localtime(&ti);
rtc_set_date(s, tm);
val = to_bcd(s, (tm->tm_year / 100) + 19);
rtc_set_memory(s, REG_IBM_CENTURY_BYTE, val);
rtc_set_memory(s, REG_IBM_PS2_CENTURY_BYTE, val);
/* various important CMOS locations needed by PC/Bochs bios */
/* memory size */
val = 640; /* base memory in K */
rtc_set_memory(s, 0x15, val);
rtc_set_memory(s, 0x16, val >> 8);
val = (ram_size / 1024) - 1024;
if (val > 65535)
val = 65535;
rtc_set_memory(s, 0x17, val);
rtc_set_memory(s, 0x18, val >> 8);
rtc_set_memory(s, 0x30, val);
rtc_set_memory(s, 0x31, val >> 8);
if (ram_size > (16 * 1024 * 1024))
val = (ram_size / 65536) - ((16 * 1024 * 1024) / 65536);
else
val = 0;
if (val > 65535)
val = 65535;
rtc_set_memory(s, 0x34, val);
rtc_set_memory(s, 0x35, val >> 8);
switch(boot_device) {
case 'a':
case 'b':
rtc_set_memory(s, 0x3d, 0x01); /* floppy boot */
break;
default:
case 'c':
rtc_set_memory(s, 0x3d, 0x02); /* hard drive boot */
break;
case 'd':
rtc_set_memory(s, 0x3d, 0x03); /* CD-ROM boot */
break;
}
/* floppy type */
fd0 = fdctrl_get_drive_type(floppy_controller, 0);
fd1 = fdctrl_get_drive_type(floppy_controller, 1);
val = (cmos_get_fd_drive_type(fd0) << 4) | cmos_get_fd_drive_type(fd1);
rtc_set_memory(s, 0x10, val);
val = 0;
nb = 0;
if (fd0 < 3)
nb++;
if (fd1 < 3)
nb++;
switch (nb) {
case 0:
break;
case 1:
val |= 0x01; /* 1 drive, ready for boot */
break;
case 2:
val |= 0x41; /* 2 drives, ready for boot */
break;
}
val |= 0x02; /* FPU is there */
val |= 0x04; /* PS/2 mouse installed */
rtc_set_memory(s, REG_EQUIPMENT_BYTE, val);
/* hard drives */
rtc_set_memory(s, 0x12, (hd_table[0] ? 0xf0 : 0) | (hd_table[1] ? 0x0f : 0));
if (hd_table[0])
cmos_init_hd(0x19, 0x1b, hd_table[0]);
if (hd_table[1])
cmos_init_hd(0x1a, 0x24, hd_table[1]);
val = 0;
for (i = 0; i < 4; i++) {
if (hd_table[i]) {
int cylinders, heads, sectors;
uint8_t translation;
/* NOTE: bdrv_get_geometry_hint() returns the geometry
that the hard disk returns. It is always such that: 1 <=
sects <= 63, 1 <= heads <= 16, 1 <= cylinders <=
16383. The BIOS geometry can be different. */
bdrv_get_geometry_hint(hd_table[i], &cylinders, &heads, &sectors);
if (cylinders <= 1024 && heads <= 16 && sectors <= 63) {
/* No translation. */
translation = 0;
} else {
/* LBA translation. */
translation = 1;
}
val |= translation << (i * 2);
}
}
rtc_set_memory(s, 0x39, val);
/* Disable check of 0x55AA signature on the last two bytes of
first sector of disk. XXX: make it the default ? */
// rtc_set_memory(s, 0x38, 1);
}
static void speaker_ioport_write(void *opaque, uint32_t addr, uint32_t val)
{
speaker_data_on = (val >> 1) & 1;
pit_set_gate(pit, 2, val & 1);
}
static uint32_t speaker_ioport_read(void *opaque, uint32_t addr)
{
int out;
out = pit_get_out(pit, 2, qemu_get_clock(vm_clock));
dummy_refresh_clock ^= 1;
return (speaker_data_on << 1) | pit_get_gate(pit, 2) | (out << 5) |
(dummy_refresh_clock << 4);
}
static void ioport92_write(void *opaque, uint32_t addr, uint32_t val)
{
cpu_x86_set_a20(cpu_single_env, (val >> 1) & 1);
/* XXX: bit 0 is fast reset */
}
static uint32_t ioport92_read(void *opaque, uint32_t addr)
{
return ((cpu_single_env->a20_mask >> 20) & 1) << 1;
}
/***********************************************************/
/* Bochs BIOS debug ports */
void bochs_bios_write(void *opaque, uint32_t addr, uint32_t val)
{
static const char shutdown_str[8] = "Shutdown";
static int shutdown_index = 0;
switch(addr) {
/* Bochs BIOS messages */
case 0x400:
case 0x401:
fprintf(stderr, "BIOS panic at rombios.c, line %d\n", val);
exit(1);
case 0x402:
case 0x403:
#ifdef DEBUG_BIOS
fprintf(stderr, "%c", val);
#endif
break;
case 0x8900:
/* same as Bochs power off */
if (val == shutdown_str[shutdown_index]) {
shutdown_index++;
if (shutdown_index == 8) {
shutdown_index = 0;
qemu_system_shutdown_request();
}
} else {
shutdown_index = 0;
}
break;
/* LGPL'ed VGA BIOS messages */
case 0x501:
case 0x502:
fprintf(stderr, "VGA BIOS panic, line %d\n", val);
exit(1);
case 0x500:
case 0x503:
#ifdef DEBUG_BIOS
fprintf(stderr, "%c", val);
#endif
break;
}
}
void bochs_bios_init(void)
{
register_ioport_write(0x400, 1, 2, bochs_bios_write, NULL);
register_ioport_write(0x401, 1, 2, bochs_bios_write, NULL);
register_ioport_write(0x402, 1, 1, bochs_bios_write, NULL);
register_ioport_write(0x403, 1, 1, bochs_bios_write, NULL);
register_ioport_write(0x8900, 1, 1, bochs_bios_write, NULL);
register_ioport_write(0x501, 1, 2, bochs_bios_write, NULL);
register_ioport_write(0x502, 1, 2, bochs_bios_write, NULL);
register_ioport_write(0x500, 1, 1, bochs_bios_write, NULL);
register_ioport_write(0x503, 1, 1, bochs_bios_write, NULL);
}
int load_kernel(const char *filename, uint8_t *addr,
uint8_t *real_addr)
{
int fd, size;
int setup_sects;
fd = open(filename, O_RDONLY | O_BINARY);
if (fd < 0)
return -1;
/* load 16 bit code */
if (read(fd, real_addr, 512) != 512)
goto fail;
setup_sects = real_addr[0x1F1];
if (!setup_sects)
setup_sects = 4;
if (read(fd, real_addr + 512, setup_sects * 512) !=
setup_sects * 512)
goto fail;
/* load 32 bit code */
size = read(fd, addr, 16 * 1024 * 1024);
if (size < 0)
goto fail;
close(fd);
return size;
fail:
close(fd);
return -1;
}
static const int ide_iobase[2] = { 0x1f0, 0x170 };
static const int ide_iobase2[2] = { 0x3f6, 0x376 };
static const int ide_irq[2] = { 14, 15 };
#define NE2000_NB_MAX 6
static int ne2000_io[NE2000_NB_MAX] = { 0x300, 0x320, 0x340, 0x360, 0x280, 0x380 };
static int ne2000_irq[NE2000_NB_MAX] = { 9, 10, 11, 3, 4, 5 };
static int serial_io[MAX_SERIAL_PORTS] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8 };
static int serial_irq[MAX_SERIAL_PORTS] = { 4, 3, 4, 3 };
/* PC hardware initialisation */
void pc_init(int ram_size, int vga_ram_size, int boot_device,
DisplayState *ds, const char **fd_filename, int snapshot,
const char *kernel_filename, const char *kernel_cmdline,
const char *initrd_filename)
{
char buf[1024];
int ret, linux_boot, initrd_size, i, nb_nics1;
unsigned long bios_offset, vga_bios_offset;
int bios_size, isa_bios_size;
PCIBus *pci_bus;
linux_boot = (kernel_filename != NULL);
/* allocate RAM */
cpu_register_physical_memory(0, ram_size, 0);
/* BIOS load */
bios_offset = ram_size + vga_ram_size;
vga_bios_offset = bios_offset + 256 * 1024;
snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME);
bios_size = get_image_size(buf);
if (bios_size <= 0 ||
(bios_size % 65536) != 0 ||
bios_size > (256 * 1024)) {
goto bios_error;
}
ret = load_image(buf, phys_ram_base + bios_offset);
if (ret != bios_size) {
bios_error:
fprintf(stderr, "qemu: could not load PC bios '%s'\n", buf);
exit(1);
}
/* VGA BIOS load */
if (cirrus_vga_enabled) {
snprintf(buf, sizeof(buf), "%s/%s", bios_dir, VGABIOS_CIRRUS_FILENAME);
} else {
snprintf(buf, sizeof(buf), "%s/%s", bios_dir, VGABIOS_FILENAME);
}
ret = load_image(buf, phys_ram_base + vga_bios_offset);
/* setup basic memory access */
cpu_register_physical_memory(0xc0000, 0x10000,
vga_bios_offset | IO_MEM_ROM);
/* map the last 128KB of the BIOS in ISA space */
isa_bios_size = bios_size;
if (isa_bios_size > (128 * 1024))
isa_bios_size = 128 * 1024;
cpu_register_physical_memory(0xd0000, (192 * 1024) - isa_bios_size,
IO_MEM_UNASSIGNED);
cpu_register_physical_memory(0x100000 - isa_bios_size,
isa_bios_size,
(bios_offset + bios_size - isa_bios_size) | IO_MEM_ROM);
/* map all the bios at the top of memory */
cpu_register_physical_memory((uint32_t)(-bios_size),
bios_size, bios_offset | IO_MEM_ROM);
bochs_bios_init();
if (linux_boot) {
uint8_t bootsect[512];
uint8_t old_bootsect[512];
if (bs_table[0] == NULL) {
fprintf(stderr, "A disk image must be given for 'hda' when booting a Linux kernel\n");
exit(1);
}
snprintf(buf, sizeof(buf), "%s/%s", bios_dir, LINUX_BOOT_FILENAME);
ret = load_image(buf, bootsect);
if (ret != sizeof(bootsect)) {
fprintf(stderr, "qemu: could not load linux boot sector '%s'\n",
buf);
exit(1);
}
if (bdrv_read(bs_table[0], 0, old_bootsect, 1) >= 0) {
/* copy the MSDOS partition table */
memcpy(bootsect + 0x1be, old_bootsect + 0x1be, 0x40);
}
bdrv_set_boot_sector(bs_table[0], bootsect, sizeof(bootsect));
/* now we can load the kernel */
ret = load_kernel(kernel_filename,
phys_ram_base + KERNEL_LOAD_ADDR,
phys_ram_base + KERNEL_PARAMS_ADDR);
if (ret < 0) {
fprintf(stderr, "qemu: could not load kernel '%s'\n",
kernel_filename);
exit(1);
}
/* load initrd */
initrd_size = 0;
if (initrd_filename) {
initrd_size = load_image(initrd_filename, phys_ram_base + INITRD_LOAD_ADDR);
if (initrd_size < 0) {
fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
initrd_filename);
exit(1);
}
}
if (initrd_size > 0) {
stl_raw(phys_ram_base + KERNEL_PARAMS_ADDR + 0x218, INITRD_LOAD_ADDR);
stl_raw(phys_ram_base + KERNEL_PARAMS_ADDR + 0x21c, initrd_size);
}
pstrcpy(phys_ram_base + KERNEL_CMDLINE_ADDR, 4096,
kernel_cmdline);
stw_raw(phys_ram_base + KERNEL_PARAMS_ADDR + 0x20, 0xA33F);
stw_raw(phys_ram_base + KERNEL_PARAMS_ADDR + 0x22,
KERNEL_CMDLINE_ADDR - KERNEL_PARAMS_ADDR);
/* loader type */
stw_raw(phys_ram_base + KERNEL_PARAMS_ADDR + 0x210, 0x01);
}
if (pci_enabled) {
pci_bus = i440fx_init();
piix3_init(pci_bus);
} else {
pci_bus = NULL;
}
/* init basic PC hardware */
register_ioport_write(0x80, 1, 1, ioport80_write, NULL);
register_ioport_write(0xf0, 1, 1, ioportF0_write, NULL);
if (cirrus_vga_enabled) {
if (pci_enabled) {
pci_cirrus_vga_init(pci_bus,
ds, phys_ram_base + ram_size, ram_size,
vga_ram_size);
} else {
isa_cirrus_vga_init(ds, phys_ram_base + ram_size, ram_size,
vga_ram_size);
}
} else {
vga_initialize(pci_bus, ds, phys_ram_base + ram_size, ram_size,
vga_ram_size);
}
rtc_state = rtc_init(0x70, 8);
register_ioport_read(0x61, 1, 1, speaker_ioport_read, NULL);
register_ioport_write(0x61, 1, 1, speaker_ioport_write, NULL);
register_ioport_read(0x92, 1, 1, ioport92_read, NULL);
register_ioport_write(0x92, 1, 1, ioport92_write, NULL);
pic_init();
pit = pit_init(0x40, 0);
for(i = 0; i < MAX_SERIAL_PORTS; i++) {
if (serial_hds[i]) {
serial_init(serial_io[i], serial_irq[i], serial_hds[i]);
}
}
if (pci_enabled) {
for(i = 0; i < nb_nics; i++) {
pci_ne2000_init(pci_bus, &nd_table[i]);
}
pci_piix3_ide_init(pci_bus, bs_table);
} else {
nb_nics1 = nb_nics;
if (nb_nics1 > NE2000_NB_MAX)
nb_nics1 = NE2000_NB_MAX;
for(i = 0; i < nb_nics1; i++) {
isa_ne2000_init(ne2000_io[i], ne2000_irq[i], &nd_table[i]);
}
for(i = 0; i < 2; i++) {
isa_ide_init(ide_iobase[i], ide_iobase2[i], ide_irq[i],
bs_table[2 * i], bs_table[2 * i + 1]);
}
}
kbd_init();
DMA_init(0);
if (audio_enabled) {
AUD_init();
#ifdef USE_SB16
if (sb16_enabled)
SB16_init ();
#endif
#ifdef CONFIG_ADLIB
if (adlib_enabled)
Adlib_init ();
#endif
#ifdef USE_GUS
if (gus_enabled)
GUS_init ();
#endif
}
floppy_controller = fdctrl_init(6, 2, 0, 0x3f0, fd_table);
cmos_init(ram_size, boot_device, bs_table);
/* must be done after all PCI devices are instanciated */
/* XXX: should be done in the Bochs BIOS */
if (pci_enabled) {
pci_bios_init();
}
}

1524
hw/pci.c Normal file

File diff suppressed because it is too large Load Diff

706
hw/pckbd.c Normal file
View File

@@ -0,0 +1,706 @@
/*
* QEMU PC keyboard emulation
*
* 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 "vl.h"
/* debug PC keyboard */
//#define DEBUG_KBD
/* debug PC keyboard : only mouse */
//#define DEBUG_MOUSE
/* Keyboard Controller Commands */
#define KBD_CCMD_READ_MODE 0x20 /* Read mode bits */
#define KBD_CCMD_WRITE_MODE 0x60 /* Write mode bits */
#define KBD_CCMD_GET_VERSION 0xA1 /* Get controller version */
#define KBD_CCMD_MOUSE_DISABLE 0xA7 /* Disable mouse interface */
#define KBD_CCMD_MOUSE_ENABLE 0xA8 /* Enable mouse interface */
#define KBD_CCMD_TEST_MOUSE 0xA9 /* Mouse interface test */
#define KBD_CCMD_SELF_TEST 0xAA /* Controller self test */
#define KBD_CCMD_KBD_TEST 0xAB /* Keyboard interface test */
#define KBD_CCMD_KBD_DISABLE 0xAD /* Keyboard interface disable */
#define KBD_CCMD_KBD_ENABLE 0xAE /* Keyboard interface enable */
#define KBD_CCMD_READ_INPORT 0xC0 /* read input port */
#define KBD_CCMD_READ_OUTPORT 0xD0 /* read output port */
#define KBD_CCMD_WRITE_OUTPORT 0xD1 /* write output port */
#define KBD_CCMD_WRITE_OBUF 0xD2
#define KBD_CCMD_WRITE_AUX_OBUF 0xD3 /* Write to output buffer as if
initiated by the auxiliary device */
#define KBD_CCMD_WRITE_MOUSE 0xD4 /* Write the following byte to the mouse */
#define KBD_CCMD_DISABLE_A20 0xDD /* HP vectra only ? */
#define KBD_CCMD_ENABLE_A20 0xDF /* HP vectra only ? */
#define KBD_CCMD_RESET 0xFE
/* Keyboard Commands */
#define KBD_CMD_SET_LEDS 0xED /* Set keyboard leds */
#define KBD_CMD_ECHO 0xEE
#define KBD_CMD_GET_ID 0xF2 /* get keyboard ID */
#define KBD_CMD_SET_RATE 0xF3 /* Set typematic rate */
#define KBD_CMD_ENABLE 0xF4 /* Enable scanning */
#define KBD_CMD_RESET_DISABLE 0xF5 /* reset and disable scanning */
#define KBD_CMD_RESET_ENABLE 0xF6 /* reset and enable scanning */
#define KBD_CMD_RESET 0xFF /* Reset */
/* Keyboard Replies */
#define KBD_REPLY_POR 0xAA /* Power on reset */
#define KBD_REPLY_ACK 0xFA /* Command ACK */
#define KBD_REPLY_RESEND 0xFE /* Command NACK, send the cmd again */
/* Status Register Bits */
#define KBD_STAT_OBF 0x01 /* Keyboard output buffer full */
#define KBD_STAT_IBF 0x02 /* Keyboard input buffer full */
#define KBD_STAT_SELFTEST 0x04 /* Self test successful */
#define KBD_STAT_CMD 0x08 /* Last write was a command write (0=data) */
#define KBD_STAT_UNLOCKED 0x10 /* Zero if keyboard locked */
#define KBD_STAT_MOUSE_OBF 0x20 /* Mouse output buffer full */
#define KBD_STAT_GTO 0x40 /* General receive/xmit timeout */
#define KBD_STAT_PERR 0x80 /* Parity error */
/* Controller Mode Register Bits */
#define KBD_MODE_KBD_INT 0x01 /* Keyboard data generate IRQ1 */
#define KBD_MODE_MOUSE_INT 0x02 /* Mouse data generate IRQ12 */
#define KBD_MODE_SYS 0x04 /* The system flag (?) */
#define KBD_MODE_NO_KEYLOCK 0x08 /* The keylock doesn't affect the keyboard if set */
#define KBD_MODE_DISABLE_KBD 0x10 /* Disable keyboard interface */
#define KBD_MODE_DISABLE_MOUSE 0x20 /* Disable mouse interface */
#define KBD_MODE_KCC 0x40 /* Scan code conversion to PC format */
#define KBD_MODE_RFU 0x80
/* Mouse Commands */
#define AUX_SET_SCALE11 0xE6 /* Set 1:1 scaling */
#define AUX_SET_SCALE21 0xE7 /* Set 2:1 scaling */
#define AUX_SET_RES 0xE8 /* Set resolution */
#define AUX_GET_SCALE 0xE9 /* Get scaling factor */
#define AUX_SET_STREAM 0xEA /* Set stream mode */
#define AUX_POLL 0xEB /* Poll */
#define AUX_RESET_WRAP 0xEC /* Reset wrap mode */
#define AUX_SET_WRAP 0xEE /* Set wrap mode */
#define AUX_SET_REMOTE 0xF0 /* Set remote mode */
#define AUX_GET_TYPE 0xF2 /* Get type */
#define AUX_SET_SAMPLE 0xF3 /* Set sample rate */
#define AUX_ENABLE_DEV 0xF4 /* Enable aux device */
#define AUX_DISABLE_DEV 0xF5 /* Disable aux device */
#define AUX_SET_DEFAULT 0xF6
#define AUX_RESET 0xFF /* Reset aux device */
#define AUX_ACK 0xFA /* Command byte ACK. */
#define MOUSE_STATUS_REMOTE 0x40
#define MOUSE_STATUS_ENABLED 0x20
#define MOUSE_STATUS_SCALE21 0x10
#define KBD_QUEUE_SIZE 256
typedef struct {
uint8_t aux[KBD_QUEUE_SIZE];
uint8_t data[KBD_QUEUE_SIZE];
int rptr, wptr, count;
} KBDQueue;
typedef struct KBDState {
KBDQueue queue;
uint8_t write_cmd; /* if non zero, write data to port 60 is expected */
uint8_t status;
uint8_t mode;
/* keyboard state */
int kbd_write_cmd;
int scan_enabled;
/* mouse state */
int mouse_write_cmd;
uint8_t mouse_status;
uint8_t mouse_resolution;
uint8_t mouse_sample_rate;
uint8_t mouse_wrap;
uint8_t mouse_type; /* 0 = PS2, 3 = IMPS/2, 4 = IMEX */
uint8_t mouse_detect_state;
int mouse_dx; /* current values, needed for 'poll' mode */
int mouse_dy;
int mouse_dz;
uint8_t mouse_buttons;
} KBDState;
KBDState kbd_state;
/* update irq and KBD_STAT_[MOUSE_]OBF */
/* XXX: not generating the irqs if KBD_MODE_DISABLE_KBD is set may be
incorrect, but it avoids having to simulate exact delays */
static void kbd_update_irq(KBDState *s)
{
KBDQueue *q = &s->queue;
int irq12_level, irq1_level;
irq1_level = 0;
irq12_level = 0;
s->status &= ~(KBD_STAT_OBF | KBD_STAT_MOUSE_OBF);
if (q->count != 0) {
s->status |= KBD_STAT_OBF;
if (q->aux[q->rptr]) {
s->status |= KBD_STAT_MOUSE_OBF;
if (s->mode & KBD_MODE_MOUSE_INT)
irq12_level = 1;
} else {
if ((s->mode & KBD_MODE_KBD_INT) &&
!(s->mode & KBD_MODE_DISABLE_KBD))
irq1_level = 1;
}
}
pic_set_irq(1, irq1_level);
pic_set_irq(12, irq12_level);
}
static void kbd_queue(KBDState *s, int b, int aux)
{
KBDQueue *q = &s->queue;
#if defined(DEBUG_MOUSE) || defined(DEBUG_KBD)
if (aux)
printf("mouse event: 0x%02x\n", b);
#ifdef DEBUG_KBD
else
printf("kbd event: 0x%02x\n", b);
#endif
#endif
if (q->count >= KBD_QUEUE_SIZE)
return;
q->aux[q->wptr] = aux;
q->data[q->wptr] = b;
if (++q->wptr == KBD_QUEUE_SIZE)
q->wptr = 0;
q->count++;
kbd_update_irq(s);
}
static void pc_kbd_put_keycode(void *opaque, int keycode)
{
KBDState *s = opaque;
kbd_queue(s, keycode, 0);
}
static uint32_t kbd_read_status(void *opaque, uint32_t addr)
{
KBDState *s = opaque;
int val;
val = s->status;
#if defined(DEBUG_KBD)
printf("kbd: read status=0x%02x\n", val);
#endif
return val;
}
static void kbd_write_command(void *opaque, uint32_t addr, uint32_t val)
{
KBDState *s = opaque;
#ifdef DEBUG_KBD
printf("kbd: write cmd=0x%02x\n", val);
#endif
switch(val) {
case KBD_CCMD_READ_MODE:
kbd_queue(s, s->mode, 0);
break;
case KBD_CCMD_WRITE_MODE:
case KBD_CCMD_WRITE_OBUF:
case KBD_CCMD_WRITE_AUX_OBUF:
case KBD_CCMD_WRITE_MOUSE:
case KBD_CCMD_WRITE_OUTPORT:
s->write_cmd = val;
break;
case KBD_CCMD_MOUSE_DISABLE:
s->mode |= KBD_MODE_DISABLE_MOUSE;
break;
case KBD_CCMD_MOUSE_ENABLE:
s->mode &= ~KBD_MODE_DISABLE_MOUSE;
break;
case KBD_CCMD_TEST_MOUSE:
kbd_queue(s, 0x00, 0);
break;
case KBD_CCMD_SELF_TEST:
s->status |= KBD_STAT_SELFTEST;
kbd_queue(s, 0x55, 0);
break;
case KBD_CCMD_KBD_TEST:
kbd_queue(s, 0x00, 0);
break;
case KBD_CCMD_KBD_DISABLE:
s->mode |= KBD_MODE_DISABLE_KBD;
kbd_update_irq(s);
break;
case KBD_CCMD_KBD_ENABLE:
s->mode &= ~KBD_MODE_DISABLE_KBD;
kbd_update_irq(s);
break;
case KBD_CCMD_READ_INPORT:
kbd_queue(s, 0x00, 0);
break;
case KBD_CCMD_READ_OUTPORT:
/* XXX: check that */
#ifdef TARGET_I386
val = 0x01 | (((cpu_single_env->a20_mask >> 20) & 1) << 1);
#else
val = 0x01;
#endif
if (s->status & KBD_STAT_OBF)
val |= 0x10;
if (s->status & KBD_STAT_MOUSE_OBF)
val |= 0x20;
kbd_queue(s, val, 0);
break;
#ifdef TARGET_I386
case KBD_CCMD_ENABLE_A20:
cpu_x86_set_a20(cpu_single_env, 1);
break;
case KBD_CCMD_DISABLE_A20:
cpu_x86_set_a20(cpu_single_env, 0);
break;
#endif
case KBD_CCMD_RESET:
qemu_system_reset_request();
break;
case 0xff:
/* ignore that - I don't know what is its use */
break;
default:
fprintf(stderr, "qemu: unsupported keyboard cmd=0x%02x\n", val);
break;
}
}
static uint32_t kbd_read_data(void *opaque, uint32_t addr)
{
KBDState *s = opaque;
KBDQueue *q;
int val, index, aux;
q = &s->queue;
if (q->count == 0) {
/* NOTE: if no data left, we return the last keyboard one
(needed for EMM386) */
/* XXX: need a timer to do things correctly */
index = q->rptr - 1;
if (index < 0)
index = KBD_QUEUE_SIZE - 1;
val = q->data[index];
} else {
aux = q->aux[q->rptr];
val = q->data[q->rptr];
if (++q->rptr == KBD_QUEUE_SIZE)
q->rptr = 0;
q->count--;
/* reading deasserts IRQ */
if (aux)
pic_set_irq(12, 0);
else
pic_set_irq(1, 0);
}
/* reassert IRQs if data left */
kbd_update_irq(s);
#ifdef DEBUG_KBD
printf("kbd: read data=0x%02x\n", val);
#endif
return val;
}
static void kbd_reset_keyboard(KBDState *s)
{
s->scan_enabled = 1;
}
static void kbd_write_keyboard(KBDState *s, int val)
{
switch(s->kbd_write_cmd) {
default:
case -1:
switch(val) {
case 0x00:
kbd_queue(s, KBD_REPLY_ACK, 0);
break;
case 0x05:
kbd_queue(s, KBD_REPLY_RESEND, 0);
break;
case KBD_CMD_GET_ID:
kbd_queue(s, KBD_REPLY_ACK, 0);
kbd_queue(s, 0xab, 0);
kbd_queue(s, 0x83, 0);
break;
case KBD_CMD_ECHO:
kbd_queue(s, KBD_CMD_ECHO, 0);
break;
case KBD_CMD_ENABLE:
s->scan_enabled = 1;
kbd_queue(s, KBD_REPLY_ACK, 0);
break;
case KBD_CMD_SET_LEDS:
case KBD_CMD_SET_RATE:
s->kbd_write_cmd = val;
kbd_queue(s, KBD_REPLY_ACK, 0);
break;
case KBD_CMD_RESET_DISABLE:
kbd_reset_keyboard(s);
s->scan_enabled = 0;
kbd_queue(s, KBD_REPLY_ACK, 0);
break;
case KBD_CMD_RESET_ENABLE:
kbd_reset_keyboard(s);
s->scan_enabled = 1;
kbd_queue(s, KBD_REPLY_ACK, 0);
break;
case KBD_CMD_RESET:
kbd_reset_keyboard(s);
kbd_queue(s, KBD_REPLY_ACK, 0);
kbd_queue(s, KBD_REPLY_POR, 0);
break;
default:
kbd_queue(s, KBD_REPLY_ACK, 0);
break;
}
break;
case KBD_CMD_SET_LEDS:
kbd_queue(s, KBD_REPLY_ACK, 0);
s->kbd_write_cmd = -1;
break;
case KBD_CMD_SET_RATE:
kbd_queue(s, KBD_REPLY_ACK, 0);
s->kbd_write_cmd = -1;
break;
}
}
static void kbd_mouse_send_packet(KBDState *s)
{
unsigned int b;
int dx1, dy1, dz1;
dx1 = s->mouse_dx;
dy1 = s->mouse_dy;
dz1 = s->mouse_dz;
/* XXX: increase range to 8 bits ? */
if (dx1 > 127)
dx1 = 127;
else if (dx1 < -127)
dx1 = -127;
if (dy1 > 127)
dy1 = 127;
else if (dy1 < -127)
dy1 = -127;
b = 0x08 | ((dx1 < 0) << 4) | ((dy1 < 0) << 5) | (s->mouse_buttons & 0x07);
kbd_queue(s, b, 1);
kbd_queue(s, dx1 & 0xff, 1);
kbd_queue(s, dy1 & 0xff, 1);
/* extra byte for IMPS/2 or IMEX */
switch(s->mouse_type) {
default:
break;
case 3:
if (dz1 > 127)
dz1 = 127;
else if (dz1 < -127)
dz1 = -127;
kbd_queue(s, dz1 & 0xff, 1);
break;
case 4:
if (dz1 > 7)
dz1 = 7;
else if (dz1 < -7)
dz1 = -7;
b = (dz1 & 0x0f) | ((s->mouse_buttons & 0x18) << 1);
kbd_queue(s, b, 1);
break;
}
/* update deltas */
s->mouse_dx -= dx1;
s->mouse_dy -= dy1;
s->mouse_dz -= dz1;
}
static void pc_kbd_mouse_event(void *opaque,
int dx, int dy, int dz, int buttons_state)
{
KBDState *s = opaque;
/* check if deltas are recorded when disabled */
if (!(s->mouse_status & MOUSE_STATUS_ENABLED))
return;
s->mouse_dx += dx;
s->mouse_dy -= dy;
s->mouse_dz += dz;
/* XXX: SDL sometimes generates nul events: we delete them */
if (s->mouse_dx == 0 && s->mouse_dy == 0 && s->mouse_dz == 0 &&
s->mouse_buttons == buttons_state)
return;
s->mouse_buttons = buttons_state;
if (!(s->mouse_status & MOUSE_STATUS_REMOTE) &&
(s->queue.count < (KBD_QUEUE_SIZE - 16))) {
for(;;) {
/* if not remote, send event. Multiple events are sent if
too big deltas */
kbd_mouse_send_packet(s);
if (s->mouse_dx == 0 && s->mouse_dy == 0 && s->mouse_dz == 0)
break;
}
}
}
static void kbd_write_mouse(KBDState *s, int val)
{
#ifdef DEBUG_MOUSE
printf("kbd: write mouse 0x%02x\n", val);
#endif
switch(s->mouse_write_cmd) {
default:
case -1:
/* mouse command */
if (s->mouse_wrap) {
if (val == AUX_RESET_WRAP) {
s->mouse_wrap = 0;
kbd_queue(s, AUX_ACK, 1);
return;
} else if (val != AUX_RESET) {
kbd_queue(s, val, 1);
return;
}
}
switch(val) {
case AUX_SET_SCALE11:
s->mouse_status &= ~MOUSE_STATUS_SCALE21;
kbd_queue(s, AUX_ACK, 1);
break;
case AUX_SET_SCALE21:
s->mouse_status |= MOUSE_STATUS_SCALE21;
kbd_queue(s, AUX_ACK, 1);
break;
case AUX_SET_STREAM:
s->mouse_status &= ~MOUSE_STATUS_REMOTE;
kbd_queue(s, AUX_ACK, 1);
break;
case AUX_SET_WRAP:
s->mouse_wrap = 1;
kbd_queue(s, AUX_ACK, 1);
break;
case AUX_SET_REMOTE:
s->mouse_status |= MOUSE_STATUS_REMOTE;
kbd_queue(s, AUX_ACK, 1);
break;
case AUX_GET_TYPE:
kbd_queue(s, AUX_ACK, 1);
kbd_queue(s, s->mouse_type, 1);
break;
case AUX_SET_RES:
case AUX_SET_SAMPLE:
s->mouse_write_cmd = val;
kbd_queue(s, AUX_ACK, 1);
break;
case AUX_GET_SCALE:
kbd_queue(s, AUX_ACK, 1);
kbd_queue(s, s->mouse_status, 1);
kbd_queue(s, s->mouse_resolution, 1);
kbd_queue(s, s->mouse_sample_rate, 1);
break;
case AUX_POLL:
kbd_queue(s, AUX_ACK, 1);
kbd_mouse_send_packet(s);
break;
case AUX_ENABLE_DEV:
s->mouse_status |= MOUSE_STATUS_ENABLED;
kbd_queue(s, AUX_ACK, 1);
break;
case AUX_DISABLE_DEV:
s->mouse_status &= ~MOUSE_STATUS_ENABLED;
kbd_queue(s, AUX_ACK, 1);
break;
case AUX_SET_DEFAULT:
s->mouse_sample_rate = 100;
s->mouse_resolution = 2;
s->mouse_status = 0;
kbd_queue(s, AUX_ACK, 1);
break;
case AUX_RESET:
s->mouse_sample_rate = 100;
s->mouse_resolution = 2;
s->mouse_status = 0;
kbd_queue(s, AUX_ACK, 1);
kbd_queue(s, 0xaa, 1);
kbd_queue(s, s->mouse_type, 1);
break;
default:
break;
}
break;
case AUX_SET_SAMPLE:
s->mouse_sample_rate = val;
#if 0
/* detect IMPS/2 or IMEX */
switch(s->mouse_detect_state) {
default:
case 0:
if (val == 200)
s->mouse_detect_state = 1;
break;
case 1:
if (val == 100)
s->mouse_detect_state = 2;
else if (val == 200)
s->mouse_detect_state = 3;
else
s->mouse_detect_state = 0;
break;
case 2:
if (val == 80)
s->mouse_type = 3; /* IMPS/2 */
s->mouse_detect_state = 0;
break;
case 3:
if (val == 80)
s->mouse_type = 4; /* IMEX */
s->mouse_detect_state = 0;
break;
}
#endif
kbd_queue(s, AUX_ACK, 1);
s->mouse_write_cmd = -1;
break;
case AUX_SET_RES:
s->mouse_resolution = val;
kbd_queue(s, AUX_ACK, 1);
s->mouse_write_cmd = -1;
break;
}
}
void kbd_write_data(void *opaque, uint32_t addr, uint32_t val)
{
KBDState *s = opaque;
#ifdef DEBUG_KBD
printf("kbd: write data=0x%02x\n", val);
#endif
switch(s->write_cmd) {
case 0:
kbd_write_keyboard(s, val);
break;
case KBD_CCMD_WRITE_MODE:
s->mode = val;
kbd_update_irq(s);
break;
case KBD_CCMD_WRITE_OBUF:
kbd_queue(s, val, 0);
break;
case KBD_CCMD_WRITE_AUX_OBUF:
kbd_queue(s, val, 1);
break;
case KBD_CCMD_WRITE_OUTPORT:
#ifdef TARGET_I386
cpu_x86_set_a20(cpu_single_env, (val >> 1) & 1);
#endif
if (!(val & 1)) {
qemu_system_reset_request();
}
break;
case KBD_CCMD_WRITE_MOUSE:
kbd_write_mouse(s, val);
break;
default:
break;
}
s->write_cmd = 0;
}
static void kbd_reset(void *opaque)
{
KBDState *s = opaque;
KBDQueue *q;
s->kbd_write_cmd = -1;
s->mouse_write_cmd = -1;
s->mode = KBD_MODE_KBD_INT | KBD_MODE_MOUSE_INT;
s->status = KBD_STAT_CMD | KBD_STAT_UNLOCKED;
q = &s->queue;
q->rptr = 0;
q->wptr = 0;
q->count = 0;
}
static void kbd_save(QEMUFile* f, void* opaque)
{
KBDState *s = (KBDState*)opaque;
qemu_put_8s(f, &s->write_cmd);
qemu_put_8s(f, &s->status);
qemu_put_8s(f, &s->mode);
qemu_put_be32s(f, &s->kbd_write_cmd);
qemu_put_be32s(f, &s->scan_enabled);
qemu_put_be32s(f, &s->mouse_write_cmd);
qemu_put_8s(f, &s->mouse_status);
qemu_put_8s(f, &s->mouse_resolution);
qemu_put_8s(f, &s->mouse_sample_rate);
qemu_put_8s(f, &s->mouse_wrap);
qemu_put_8s(f, &s->mouse_type);
qemu_put_8s(f, &s->mouse_detect_state);
qemu_put_be32s(f, &s->mouse_dx);
qemu_put_be32s(f, &s->mouse_dy);
qemu_put_be32s(f, &s->mouse_dz);
qemu_put_8s(f, &s->mouse_buttons);
}
static int kbd_load(QEMUFile* f, void* opaque, int version_id)
{
KBDState *s = (KBDState*)opaque;
if (version_id != 1)
return -EINVAL;
qemu_get_8s(f, &s->write_cmd);
qemu_get_8s(f, &s->status);
qemu_get_8s(f, &s->mode);
qemu_get_be32s(f, &s->kbd_write_cmd);
qemu_get_be32s(f, &s->scan_enabled);
qemu_get_be32s(f, &s->mouse_write_cmd);
qemu_get_8s(f, &s->mouse_status);
qemu_get_8s(f, &s->mouse_resolution);
qemu_get_8s(f, &s->mouse_sample_rate);
qemu_get_8s(f, &s->mouse_wrap);
qemu_get_8s(f, &s->mouse_type);
qemu_get_8s(f, &s->mouse_detect_state);
qemu_get_be32s(f, &s->mouse_dx);
qemu_get_be32s(f, &s->mouse_dy);
qemu_get_be32s(f, &s->mouse_dz);
qemu_get_8s(f, &s->mouse_buttons);
return 0;
}
void kbd_init(void)
{
KBDState *s = &kbd_state;
kbd_reset(s);
register_savevm("pckbd", 0, 1, kbd_save, kbd_load, s);
register_ioport_read(0x60, 1, 1, kbd_read_data, s);
register_ioport_write(0x60, 1, 1, kbd_write_data, s);
register_ioport_read(0x64, 1, 1, kbd_read_status, s);
register_ioport_write(0x64, 1, 1, kbd_write_command, s);
qemu_add_kbd_event_handler(pc_kbd_put_keycode, s);
qemu_add_mouse_event_handler(pc_kbd_mouse_event, s);
qemu_register_reset(kbd_reset, s);
}

462
hw/ppc.c Normal file
View File

@@ -0,0 +1,462 @@
/*
* QEMU generic PPC hardware System Emulator
*
* Copyright (c) 2003-2004 Jocelyn Mayer
*
* 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 "vl.h"
#include "m48t59.h"
/*****************************************************************************/
/* PPC time base and decrementer emulation */
//#define DEBUG_TB
struct ppc_tb_t {
/* Time base management */
int64_t tb_offset; /* Compensation */
uint32_t tb_freq; /* TB frequency */
/* Decrementer management */
uint64_t decr_next; /* Tick for next decr interrupt */
struct QEMUTimer *decr_timer;
};
static inline uint64_t cpu_ppc_get_tb (ppc_tb_t *tb_env)
{
/* TB time in tb periods */
return muldiv64(qemu_get_clock(vm_clock) + tb_env->tb_offset,
tb_env->tb_freq, ticks_per_sec);
}
uint32_t cpu_ppc_load_tbl (CPUState *env)
{
ppc_tb_t *tb_env = env->tb_env;
uint64_t tb;
tb = cpu_ppc_get_tb(tb_env);
#ifdef DEBUG_TB
{
static int last_time;
int now;
now = time(NULL);
if (last_time != now) {
last_time = now;
printf("%s: tb=0x%016lx %d %08lx\n",
__func__, tb, now, tb_env->tb_offset);
}
}
#endif
return tb & 0xFFFFFFFF;
}
uint32_t cpu_ppc_load_tbu (CPUState *env)
{
ppc_tb_t *tb_env = env->tb_env;
uint64_t tb;
tb = cpu_ppc_get_tb(tb_env);
#ifdef DEBUG_TB
printf("%s: tb=0x%016lx\n", __func__, tb);
#endif
return tb >> 32;
}
static void cpu_ppc_store_tb (ppc_tb_t *tb_env, uint64_t value)
{
tb_env->tb_offset = muldiv64(value, ticks_per_sec, tb_env->tb_freq)
- qemu_get_clock(vm_clock);
#ifdef DEBUG_TB
printf("%s: tb=0x%016lx offset=%08x\n", __func__, value);
#endif
}
void cpu_ppc_store_tbu (CPUState *env, uint32_t value)
{
ppc_tb_t *tb_env = env->tb_env;
cpu_ppc_store_tb(tb_env,
((uint64_t)value << 32) | cpu_ppc_load_tbl(env));
}
void cpu_ppc_store_tbl (CPUState *env, uint32_t value)
{
ppc_tb_t *tb_env = env->tb_env;
cpu_ppc_store_tb(tb_env,
((uint64_t)cpu_ppc_load_tbu(env) << 32) | value);
}
uint32_t cpu_ppc_load_decr (CPUState *env)
{
ppc_tb_t *tb_env = env->tb_env;
uint32_t decr;
decr = muldiv64(tb_env->decr_next - qemu_get_clock(vm_clock),
tb_env->tb_freq, ticks_per_sec);
#if defined(DEBUG_TB)
printf("%s: 0x%08x\n", __func__, decr);
#endif
return decr;
}
/* When decrementer expires,
* all we need to do is generate or queue a CPU exception
*/
static inline void cpu_ppc_decr_excp (CPUState *env)
{
/* Raise it */
#ifdef DEBUG_TB
printf("raise decrementer exception\n");
#endif
cpu_interrupt(env, CPU_INTERRUPT_TIMER);
}
static void _cpu_ppc_store_decr (CPUState *env, uint32_t decr,
uint32_t value, int is_excp)
{
ppc_tb_t *tb_env = env->tb_env;
uint64_t now, next;
#ifdef DEBUG_TB
printf("%s: 0x%08x => 0x%08x\n", __func__, decr, value);
#endif
now = qemu_get_clock(vm_clock);
next = now + muldiv64(value, ticks_per_sec, tb_env->tb_freq);
if (is_excp)
next += tb_env->decr_next - now;
if (next == now)
next++;
tb_env->decr_next = next;
/* Adjust timer */
qemu_mod_timer(tb_env->decr_timer, next);
/* If we set a negative value and the decrementer was positive,
* raise an exception.
*/
if ((value & 0x80000000) && !(decr & 0x80000000))
cpu_ppc_decr_excp(env);
}
void cpu_ppc_store_decr (CPUState *env, uint32_t value)
{
_cpu_ppc_store_decr(env, cpu_ppc_load_decr(env), value, 0);
}
static void cpu_ppc_decr_cb (void *opaque)
{
_cpu_ppc_store_decr(opaque, 0x00000000, 0xFFFFFFFF, 1);
}
/* Set up (once) timebase frequency (in Hz) */
ppc_tb_t *cpu_ppc_tb_init (CPUState *env, uint32_t freq)
{
ppc_tb_t *tb_env;
tb_env = qemu_mallocz(sizeof(ppc_tb_t));
if (tb_env == NULL)
return NULL;
env->tb_env = tb_env;
if (tb_env->tb_freq == 0 || 1) {
tb_env->tb_freq = freq;
/* Create new timer */
tb_env->decr_timer =
qemu_new_timer(vm_clock, &cpu_ppc_decr_cb, env);
/* There is a bug in 2.4 kernels:
* if a decrementer exception is pending when it enables msr_ee,
* it's not ready to handle it...
*/
_cpu_ppc_store_decr(env, 0xFFFFFFFF, 0xFFFFFFFF, 0);
}
return tb_env;
}
#if 0
/*****************************************************************************/
/* Handle system reset (for now, just stop emulation) */
void cpu_ppc_reset (CPUState *env)
{
printf("Reset asked... Stop emulation\n");
abort();
}
#endif
static void PPC_io_writeb (void *opaque, target_phys_addr_t addr, uint32_t value)
{
cpu_outb(NULL, addr & 0xffff, value);
}
static uint32_t PPC_io_readb (void *opaque, target_phys_addr_t addr)
{
uint32_t ret = cpu_inb(NULL, addr & 0xffff);
return ret;
}
static void PPC_io_writew (void *opaque, target_phys_addr_t addr, uint32_t value)
{
#ifdef TARGET_WORDS_BIGENDIAN
value = bswap16(value);
#endif
cpu_outw(NULL, addr & 0xffff, value);
}
static uint32_t PPC_io_readw (void *opaque, target_phys_addr_t addr)
{
uint32_t ret = cpu_inw(NULL, addr & 0xffff);
#ifdef TARGET_WORDS_BIGENDIAN
ret = bswap16(ret);
#endif
return ret;
}
static void PPC_io_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
{
#ifdef TARGET_WORDS_BIGENDIAN
value = bswap32(value);
#endif
cpu_outl(NULL, addr & 0xffff, value);
}
static uint32_t PPC_io_readl (void *opaque, target_phys_addr_t addr)
{
uint32_t ret = cpu_inl(NULL, addr & 0xffff);
#ifdef TARGET_WORDS_BIGENDIAN
ret = bswap32(ret);
#endif
return ret;
}
CPUWriteMemoryFunc *PPC_io_write[] = {
&PPC_io_writeb,
&PPC_io_writew,
&PPC_io_writel,
};
CPUReadMemoryFunc *PPC_io_read[] = {
&PPC_io_readb,
&PPC_io_readw,
&PPC_io_readl,
};
/*****************************************************************************/
/* Debug port */
void PPC_debug_write (void *opaque, uint32_t addr, uint32_t val)
{
addr &= 0xF;
switch (addr) {
case 0:
printf("%c", val);
break;
case 1:
printf("\n");
fflush(stdout);
break;
case 2:
printf("Set loglevel to %04x\n", val);
cpu_set_log(val | 0x100);
break;
}
}
/*****************************************************************************/
/* NVRAM helpers */
void NVRAM_set_byte (m48t59_t *nvram, uint32_t addr, uint8_t value)
{
m48t59_set_addr(nvram, addr);
m48t59_write(nvram, value);
}
uint8_t NVRAM_get_byte (m48t59_t *nvram, uint32_t addr)
{
m48t59_set_addr(nvram, addr);
return m48t59_read(nvram);
}
void NVRAM_set_word (m48t59_t *nvram, uint32_t addr, uint16_t value)
{
m48t59_set_addr(nvram, addr);
m48t59_write(nvram, value >> 8);
m48t59_set_addr(nvram, addr + 1);
m48t59_write(nvram, value & 0xFF);
}
uint16_t NVRAM_get_word (m48t59_t *nvram, uint32_t addr)
{
uint16_t tmp;
m48t59_set_addr(nvram, addr);
tmp = m48t59_read(nvram) << 8;
m48t59_set_addr(nvram, addr + 1);
tmp |= m48t59_read(nvram);
return tmp;
}
void NVRAM_set_lword (m48t59_t *nvram, uint32_t addr, uint32_t value)
{
m48t59_set_addr(nvram, addr);
m48t59_write(nvram, value >> 24);
m48t59_set_addr(nvram, addr + 1);
m48t59_write(nvram, (value >> 16) & 0xFF);
m48t59_set_addr(nvram, addr + 2);
m48t59_write(nvram, (value >> 8) & 0xFF);
m48t59_set_addr(nvram, addr + 3);
m48t59_write(nvram, value & 0xFF);
}
uint32_t NVRAM_get_lword (m48t59_t *nvram, uint32_t addr)
{
uint32_t tmp;
m48t59_set_addr(nvram, addr);
tmp = m48t59_read(nvram) << 24;
m48t59_set_addr(nvram, addr + 1);
tmp |= m48t59_read(nvram) << 16;
m48t59_set_addr(nvram, addr + 2);
tmp |= m48t59_read(nvram) << 8;
m48t59_set_addr(nvram, addr + 3);
tmp |= m48t59_read(nvram);
return tmp;
}
void NVRAM_set_string (m48t59_t *nvram, uint32_t addr,
const unsigned char *str, uint32_t max)
{
int i;
for (i = 0; i < max && str[i] != '\0'; i++) {
m48t59_set_addr(nvram, addr + i);
m48t59_write(nvram, str[i]);
}
m48t59_set_addr(nvram, addr + max - 1);
m48t59_write(nvram, '\0');
}
int NVRAM_get_string (m48t59_t *nvram, uint8_t *dst, uint16_t addr, int max)
{
int i;
memset(dst, 0, max);
for (i = 0; i < max; i++) {
dst[i] = NVRAM_get_byte(nvram, addr + i);
if (dst[i] == '\0')
break;
}
return i;
}
static uint16_t NVRAM_crc_update (uint16_t prev, uint16_t value)
{
uint16_t tmp;
uint16_t pd, pd1, pd2;
tmp = prev >> 8;
pd = prev ^ value;
pd1 = pd & 0x000F;
pd2 = ((pd >> 4) & 0x000F) ^ pd1;
tmp ^= (pd1 << 3) | (pd1 << 8);
tmp ^= pd2 | (pd2 << 7) | (pd2 << 12);
return tmp;
}
uint16_t NVRAM_compute_crc (m48t59_t *nvram, uint32_t start, uint32_t count)
{
uint32_t i;
uint16_t crc = 0xFFFF;
int odd;
odd = count & 1;
count &= ~1;
for (i = 0; i != count; i++) {
crc = NVRAM_crc_update(crc, NVRAM_get_word(nvram, start + i));
}
if (odd) {
crc = NVRAM_crc_update(crc, NVRAM_get_byte(nvram, start + i) << 8);
}
return crc;
}
#define CMDLINE_ADDR 0x017ff000
int PPC_NVRAM_set_params (m48t59_t *nvram, uint16_t NVRAM_size,
const unsigned char *arch,
uint32_t RAM_size, int boot_device,
uint32_t kernel_image, uint32_t kernel_size,
const char *cmdline,
uint32_t initrd_image, uint32_t initrd_size,
uint32_t NVRAM_image,
int width, int height, int depth)
{
uint16_t crc;
/* Set parameters for Open Hack'Ware BIOS */
NVRAM_set_string(nvram, 0x00, "QEMU_BIOS", 16);
NVRAM_set_lword(nvram, 0x10, 0x00000002); /* structure v2 */
NVRAM_set_word(nvram, 0x14, NVRAM_size);
NVRAM_set_string(nvram, 0x20, arch, 16);
NVRAM_set_lword(nvram, 0x30, RAM_size);
NVRAM_set_byte(nvram, 0x34, boot_device);
NVRAM_set_lword(nvram, 0x38, kernel_image);
NVRAM_set_lword(nvram, 0x3C, kernel_size);
if (cmdline) {
/* XXX: put the cmdline in NVRAM too ? */
strcpy(phys_ram_base + CMDLINE_ADDR, cmdline);
NVRAM_set_lword(nvram, 0x40, CMDLINE_ADDR);
NVRAM_set_lword(nvram, 0x44, strlen(cmdline));
} else {
NVRAM_set_lword(nvram, 0x40, 0);
NVRAM_set_lword(nvram, 0x44, 0);
}
NVRAM_set_lword(nvram, 0x48, initrd_image);
NVRAM_set_lword(nvram, 0x4C, initrd_size);
NVRAM_set_lword(nvram, 0x50, NVRAM_image);
NVRAM_set_word(nvram, 0x54, width);
NVRAM_set_word(nvram, 0x56, height);
NVRAM_set_word(nvram, 0x58, depth);
crc = NVRAM_compute_crc(nvram, 0x00, 0xF8);
NVRAM_set_word(nvram, 0xFC, crc);
return 0;
}
/*****************************************************************************/
void ppc_init (int ram_size, int vga_ram_size, int boot_device,
DisplayState *ds, const char **fd_filename, int snapshot,
const char *kernel_filename, const char *kernel_cmdline,
const char *initrd_filename)
{
if (prep_enabled) {
ppc_prep_init(ram_size, vga_ram_size, boot_device, ds, fd_filename,
snapshot, kernel_filename, kernel_cmdline,
initrd_filename);
} else {
ppc_chrp_init(ram_size, vga_ram_size, boot_device, ds, fd_filename,
snapshot, kernel_filename, kernel_cmdline,
initrd_filename);
}
/* Special port to get debug messages from Open-Firmware */
register_ioport_write(0x0F00, 4, 1, &PPC_debug_write, NULL);
}

233
hw/ppc_chrp.c Normal file
View File

@@ -0,0 +1,233 @@
/*
* QEMU PPC CHRP/PMAC hardware System Emulator
*
* Copyright (c) 2004 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 "vl.h"
#define BIOS_FILENAME "ppc_rom.bin"
#define NVRAM_SIZE 0x2000
#define KERNEL_LOAD_ADDR 0x01000000
#define INITRD_LOAD_ADDR 0x01800000
/* MacIO devices (mapped inside the MacIO address space): CUDA, DBDMA,
NVRAM (not implemented). */
static int dbdma_mem_index;
static int cuda_mem_index;
static int ide0_mem_index;
static int ide1_mem_index;
static int openpic_mem_index;
/* DBDMA: currently no op - should suffice right now */
static void dbdma_writeb (void *opaque, target_phys_addr_t addr, uint32_t value)
{
printf("%s: 0x%08x <= 0x%08x\n", __func__, addr, value);
}
static void dbdma_writew (void *opaque, target_phys_addr_t addr, uint32_t value)
{
}
static void dbdma_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
{
}
static uint32_t dbdma_readb (void *opaque, target_phys_addr_t addr)
{
printf("%s: 0x%08x => 0x00000000\n", __func__, addr);
return 0;
}
static uint32_t dbdma_readw (void *opaque, target_phys_addr_t addr)
{
return 0;
}
static uint32_t dbdma_readl (void *opaque, target_phys_addr_t addr)
{
return 0;
}
static CPUWriteMemoryFunc *dbdma_write[] = {
&dbdma_writeb,
&dbdma_writew,
&dbdma_writel,
};
static CPUReadMemoryFunc *dbdma_read[] = {
&dbdma_readb,
&dbdma_readw,
&dbdma_readl,
};
static void macio_map(PCIDevice *pci_dev, int region_num,
uint32_t addr, uint32_t size, int type)
{
cpu_register_physical_memory(addr + 0x08000, 0x1000, dbdma_mem_index);
cpu_register_physical_memory(addr + 0x16000, 0x2000, cuda_mem_index);
cpu_register_physical_memory(addr + 0x1f000, 0x1000, ide0_mem_index);
cpu_register_physical_memory(addr + 0x20000, 0x1000, ide1_mem_index);
cpu_register_physical_memory(addr + 0x40000, 0x40000, openpic_mem_index);
}
static void macio_init(PCIBus *bus)
{
PCIDevice *d;
d = pci_register_device(bus, "macio", sizeof(PCIDevice),
-1, NULL, NULL);
/* Note: this code is strongly inspirated from the corresponding code
in PearPC */
d->config[0x00] = 0x6b; // vendor_id
d->config[0x01] = 0x10;
d->config[0x02] = 0x22;
d->config[0x03] = 0x00;
d->config[0x0a] = 0x00; // class_sub = pci2pci
d->config[0x0b] = 0xff; // class_base = bridge
d->config[0x0e] = 0x00; // header_type
d->config[0x3d] = 0x01; // interrupt on pin 1
dbdma_mem_index = cpu_register_io_memory(0, dbdma_read, dbdma_write, NULL);
pci_register_io_region(d, 0, 0x80000,
PCI_ADDRESS_SPACE_MEM, macio_map);
}
/* PowerPC PREP hardware initialisation */
void ppc_chrp_init(int ram_size, int vga_ram_size, int boot_device,
DisplayState *ds, const char **fd_filename, int snapshot,
const char *kernel_filename, const char *kernel_cmdline,
const char *initrd_filename)
{
char buf[1024];
openpic_t *openpic;
m48t59_t *nvram;
int PPC_io_memory;
int ret, linux_boot, i;
unsigned long bios_offset;
uint32_t kernel_base, kernel_size, initrd_base, initrd_size;
PCIBus *pci_bus;
linux_boot = (kernel_filename != NULL);
/* allocate RAM */
cpu_register_physical_memory(0, ram_size, IO_MEM_RAM);
/* allocate and load BIOS */
bios_offset = ram_size + vga_ram_size;
snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME);
ret = load_image(buf, phys_ram_base + bios_offset);
if (ret != BIOS_SIZE) {
fprintf(stderr, "qemu: could not load PPC PREP bios '%s'\n", buf);
exit(1);
}
cpu_register_physical_memory((uint32_t)(-BIOS_SIZE),
BIOS_SIZE, bios_offset | IO_MEM_ROM);
cpu_single_env->nip = 0xfffffffc;
if (linux_boot) {
kernel_base = KERNEL_LOAD_ADDR;
/* now we can load the kernel */
kernel_size = load_image(kernel_filename, phys_ram_base + kernel_base);
if (kernel_size < 0) {
fprintf(stderr, "qemu: could not load kernel '%s'\n",
kernel_filename);
exit(1);
}
/* load initrd */
if (initrd_filename) {
initrd_base = INITRD_LOAD_ADDR;
initrd_size = load_image(initrd_filename,
phys_ram_base + initrd_base);
if (initrd_size < 0) {
fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
initrd_filename);
exit(1);
}
} else {
initrd_base = 0;
initrd_size = 0;
}
boot_device = 'm';
} else {
kernel_base = 0;
kernel_size = 0;
initrd_base = 0;
initrd_size = 0;
}
/* Register CPU as a 74x/75x */
cpu_ppc_register(cpu_single_env, 0x00080000);
/* Set time-base frequency to 100 Mhz */
cpu_ppc_tb_init(cpu_single_env, 100UL * 1000UL * 1000UL);
isa_mem_base = 0x80000000;
pci_bus = pci_pmac_init();
/* Register 8 MB of ISA IO space */
PPC_io_memory = cpu_register_io_memory(0, PPC_io_read, PPC_io_write, NULL);
cpu_register_physical_memory(0xF2000000, 0x00800000, PPC_io_memory);
/* init basic PC hardware */
vga_initialize(pci_bus, ds, phys_ram_base + ram_size, ram_size,
vga_ram_size);
openpic = openpic_init(NULL, &openpic_mem_index, 1);
pci_pmac_set_openpic(pci_bus, openpic);
/* XXX: suppress that */
pic_init();
/* XXX: use Mac Serial port */
serial_init(0x3f8, 4, serial_hds[0]);
for(i = 0; i < nb_nics; i++) {
pci_ne2000_init(pci_bus, &nd_table[i]);
}
ide0_mem_index = pmac_ide_init(&bs_table[0], openpic, 0x13);
ide1_mem_index = pmac_ide_init(&bs_table[2], openpic, 0x13);
/* cuda also initialize ADB */
cuda_mem_index = cuda_init(openpic, 0x19);
adb_kbd_init(&adb_bus);
adb_mouse_init(&adb_bus);
macio_init(pci_bus);
nvram = m48t59_init(8, 0xFFF04000, 0x0074, NVRAM_SIZE);
if (graphic_depth != 15 && graphic_depth != 32 && graphic_depth != 8)
graphic_depth = 15;
PPC_NVRAM_set_params(nvram, NVRAM_SIZE, "CHRP", ram_size, boot_device,
kernel_base, kernel_size,
kernel_cmdline,
initrd_base, initrd_size,
/* XXX: need an option to load a NVRAM image */
0,
graphic_width, graphic_height, graphic_depth);
/* No PCI init: the BIOS will do it */
}

548
hw/ppc_prep.c Normal file
View File

@@ -0,0 +1,548 @@
/*
* QEMU PPC PREP hardware System Emulator
*
* Copyright (c) 2003-2004 Jocelyn Mayer
*
* 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 "vl.h"
//#define HARD_DEBUG_PPC_IO
//#define DEBUG_PPC_IO
#define BIOS_FILENAME "ppc_rom.bin"
#define KERNEL_LOAD_ADDR 0x01000000
#define INITRD_LOAD_ADDR 0x01800000
extern int loglevel;
extern FILE *logfile;
#if defined (HARD_DEBUG_PPC_IO) && !defined (DEBUG_PPC_IO)
#define DEBUG_PPC_IO
#endif
#if defined (HARD_DEBUG_PPC_IO)
#define PPC_IO_DPRINTF(fmt, args...) \
do { \
if (loglevel & CPU_LOG_IOPORT) { \
fprintf(logfile, "%s: " fmt, __func__ , ##args); \
} else { \
printf("%s : " fmt, __func__ , ##args); \
} \
} while (0)
#elif defined (DEBUG_PPC_IO)
#define PPC_IO_DPRINTF(fmt, args...) \
do { \
if (loglevel & CPU_LOG_IOPORT) { \
fprintf(logfile, "%s: " fmt, __func__ , ##args); \
} \
} while (0)
#else
#define PPC_IO_DPRINTF(fmt, args...) do { } while (0)
#endif
/* Constants for devices init */
static const int ide_iobase[2] = { 0x1f0, 0x170 };
static const int ide_iobase2[2] = { 0x3f6, 0x376 };
static const int ide_irq[2] = { 13, 13 };
#define NE2000_NB_MAX 6
static uint32_t ne2000_io[NE2000_NB_MAX] = { 0x300, 0x320, 0x340, 0x360, 0x280, 0x380 };
static int ne2000_irq[NE2000_NB_MAX] = { 9, 10, 11, 3, 4, 5 };
//static PITState *pit;
/* ISA IO ports bridge */
#define PPC_IO_BASE 0x80000000
/* Speaker port 0x61 */
int speaker_data_on;
int dummy_refresh_clock;
static void speaker_ioport_write(void *opaque, uint32_t addr, uint32_t val)
{
#if 0
speaker_data_on = (val >> 1) & 1;
pit_set_gate(pit, 2, val & 1);
#endif
}
static uint32_t speaker_ioport_read(void *opaque, uint32_t addr)
{
#if 0
int out;
out = pit_get_out(pit, 2, qemu_get_clock(vm_clock));
dummy_refresh_clock ^= 1;
return (speaker_data_on << 1) | pit_get_gate(pit, 2) | (out << 5) |
(dummy_refresh_clock << 4);
#endif
return 0;
}
/* PCI intack register */
/* Read-only register (?) */
static void _PPC_intack_write (void *opaque, target_phys_addr_t addr, uint32_t value)
{
// printf("%s: 0x%08x => 0x%08x\n", __func__, addr, value);
}
static inline uint32_t _PPC_intack_read (target_phys_addr_t addr)
{
uint32_t retval = 0;
if (addr == 0xBFFFFFF0)
retval = pic_intack_read(NULL);
// printf("%s: 0x%08x <= %d\n", __func__, addr, retval);
return retval;
}
static uint32_t PPC_intack_readb (void *opaque, target_phys_addr_t addr)
{
return _PPC_intack_read(addr);
}
static uint32_t PPC_intack_readw (void *opaque, target_phys_addr_t addr)
{
#ifdef TARGET_WORDS_BIGENDIAN
return bswap16(_PPC_intack_read(addr));
#else
return _PPC_intack_read(addr);
#endif
}
static uint32_t PPC_intack_readl (void *opaque, target_phys_addr_t addr)
{
#ifdef TARGET_WORDS_BIGENDIAN
return bswap32(_PPC_intack_read(addr));
#else
return _PPC_intack_read(addr);
#endif
}
static CPUWriteMemoryFunc *PPC_intack_write[] = {
&_PPC_intack_write,
&_PPC_intack_write,
&_PPC_intack_write,
};
static CPUReadMemoryFunc *PPC_intack_read[] = {
&PPC_intack_readb,
&PPC_intack_readw,
&PPC_intack_readl,
};
/* PowerPC control and status registers */
#if 0 // Not used
static struct {
/* IDs */
uint32_t veni_devi;
uint32_t revi;
/* Control and status */
uint32_t gcsr;
uint32_t xcfr;
uint32_t ct32;
uint32_t mcsr;
/* General purpose registers */
uint32_t gprg[6];
/* Exceptions */
uint32_t feen;
uint32_t fest;
uint32_t fema;
uint32_t fecl;
uint32_t eeen;
uint32_t eest;
uint32_t eecl;
uint32_t eeint;
uint32_t eemck0;
uint32_t eemck1;
/* Error diagnostic */
} XCSR;
static void PPC_XCSR_writeb (void *opaque, target_phys_addr_t addr, uint32_t value)
{
printf("%s: 0x%08lx => 0x%08x\n", __func__, (long)addr, value);
}
static void PPC_XCSR_writew (void *opaque, target_phys_addr_t addr, uint32_t value)
{
#ifdef TARGET_WORDS_BIGENDIAN
value = bswap16(value);
#endif
printf("%s: 0x%08lx => 0x%08x\n", __func__, (long)addr, value);
}
static void PPC_XCSR_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
{
#ifdef TARGET_WORDS_BIGENDIAN
value = bswap32(value);
#endif
printf("%s: 0x%08lx => 0x%08x\n", __func__, (long)addr, value);
}
static uint32_t PPC_XCSR_readb (void *opaque, target_phys_addr_t addr)
{
uint32_t retval = 0;
printf("%s: 0x%08lx <= %d\n", __func__, (long)addr, retval);
return retval;
}
static uint32_t PPC_XCSR_readw (void *opaque, target_phys_addr_t addr)
{
uint32_t retval = 0;
printf("%s: 0x%08lx <= %d\n", __func__, (long)addr, retval);
#ifdef TARGET_WORDS_BIGENDIAN
retval = bswap16(retval);
#endif
return retval;
}
static uint32_t PPC_XCSR_readl (void *opaque, target_phys_addr_t addr)
{
uint32_t retval = 0;
printf("%s: 0x%08lx <= %d\n", __func__, (long)addr, retval);
#ifdef TARGET_WORDS_BIGENDIAN
retval = bswap32(retval);
#endif
return retval;
}
static CPUWriteMemoryFunc *PPC_XCSR_write[] = {
&PPC_XCSR_writeb,
&PPC_XCSR_writew,
&PPC_XCSR_writel,
};
static CPUReadMemoryFunc *PPC_XCSR_read[] = {
&PPC_XCSR_readb,
&PPC_XCSR_readw,
&PPC_XCSR_readl,
};
#endif
/* Fake super-io ports for PREP platform (Intel 82378ZB) */
typedef struct sysctrl_t {
m48t59_t *nvram;
uint8_t state;
uint8_t syscontrol;
uint8_t fake_io[2];
} sysctrl_t;
enum {
STATE_HARDFILE = 0x01,
};
static sysctrl_t *sysctrl;
static void PREP_io_write (void *opaque, uint32_t addr, uint32_t val)
{
sysctrl_t *sysctrl = opaque;
PPC_IO_DPRINTF("0x%08lx => 0x%08x\n", (long)addr - PPC_IO_BASE, val);
sysctrl->fake_io[addr - 0x0398] = val;
}
static uint32_t PREP_io_read (void *opaque, uint32_t addr)
{
sysctrl_t *sysctrl = opaque;
PPC_IO_DPRINTF("0x%08lx <= 0x%08x\n", (long)addr - PPC_IO_BASE,
sysctrl->fake_io[addr - 0x0398]);
return sysctrl->fake_io[addr - 0x0398];
}
static void PREP_io_800_writeb (void *opaque, uint32_t addr, uint32_t val)
{
sysctrl_t *sysctrl = opaque;
PPC_IO_DPRINTF("0x%08lx => 0x%08x\n", (long)addr - PPC_IO_BASE, val);
switch (addr) {
case 0x0092:
/* Special port 92 */
/* Check soft reset asked */
if (val & 0x01) {
// cpu_interrupt(cpu_single_env, CPU_INTERRUPT_RESET);
}
/* Check LE mode */
if (val & 0x02) {
printf("Little Endian mode isn't supported (yet ?)\n");
abort();
}
break;
case 0x0800:
/* Motorola CPU configuration register : read-only */
break;
case 0x0802:
/* Motorola base module feature register : read-only */
break;
case 0x0803:
/* Motorola base module status register : read-only */
break;
case 0x0808:
/* Hardfile light register */
if (val & 1)
sysctrl->state |= STATE_HARDFILE;
else
sysctrl->state &= ~STATE_HARDFILE;
break;
case 0x0810:
/* Password protect 1 register */
if (sysctrl->nvram != NULL)
m48t59_toggle_lock(sysctrl->nvram, 1);
break;
case 0x0812:
/* Password protect 2 register */
if (sysctrl->nvram != NULL)
m48t59_toggle_lock(sysctrl->nvram, 2);
break;
case 0x0814:
/* L2 invalidate register */
// tlb_flush(cpu_single_env, 1);
break;
case 0x081C:
/* system control register */
sysctrl->syscontrol = val & 0x0F;
break;
case 0x0850:
/* I/O map type register */
if (!(val & 0x01)) {
printf("No support for non-continuous I/O map mode\n");
abort();
}
break;
default:
printf("ERROR: unaffected IO port write: %04lx => %02x\n",
(long)addr, val);
break;
}
}
static uint32_t PREP_io_800_readb (void *opaque, uint32_t addr)
{
sysctrl_t *sysctrl = opaque;
uint32_t retval = 0xFF;
switch (addr) {
case 0x0092:
/* Special port 92 */
retval = 0x00;
break;
case 0x0800:
/* Motorola CPU configuration register */
retval = 0xEF; /* MPC750 */
break;
case 0x0802:
/* Motorola Base module feature register */
retval = 0xAD; /* No ESCC, PMC slot neither ethernet */
break;
case 0x0803:
/* Motorola base module status register */
retval = 0xE0; /* Standard MPC750 */
break;
case 0x080C:
/* Equipment present register:
* no L2 cache
* no upgrade processor
* no cards in PCI slots
* SCSI fuse is bad
*/
retval = 0x3C;
break;
case 0x0810:
/* Motorola base module extended feature register */
retval = 0x39; /* No USB, CF and PCI bridge. NVRAM present */
break;
case 0x0818:
/* Keylock */
retval = 0x00;
break;
case 0x081C:
/* system control register
* 7 - 6 / 1 - 0: L2 cache enable
*/
retval = sysctrl->syscontrol;
break;
case 0x0823:
/* */
retval = 0x03; /* no L2 cache */
break;
case 0x0850:
/* I/O map type register */
retval = 0x01;
break;
default:
printf("ERROR: unaffected IO port: %04lx read\n", (long)addr);
break;
}
PPC_IO_DPRINTF("0x%08lx <= 0x%08x\n", (long)addr - PPC_IO_BASE, retval);
return retval;
}
extern CPUPPCState *global_env;
#define NVRAM_SIZE 0x2000
/* PowerPC PREP hardware initialisation */
void ppc_prep_init(int ram_size, int vga_ram_size, int boot_device,
DisplayState *ds, const char **fd_filename, int snapshot,
const char *kernel_filename, const char *kernel_cmdline,
const char *initrd_filename)
{
char buf[1024];
m48t59_t *nvram;
int PPC_io_memory;
int ret, linux_boot, i, nb_nics1;
unsigned long bios_offset;
uint32_t kernel_base, kernel_size, initrd_base, initrd_size;
PCIBus *pci_bus;
sysctrl = qemu_mallocz(sizeof(sysctrl_t));
if (sysctrl == NULL)
return;
linux_boot = (kernel_filename != NULL);
/* allocate RAM */
cpu_register_physical_memory(0, ram_size, IO_MEM_RAM);
/* allocate and load BIOS */
bios_offset = ram_size + vga_ram_size;
snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME);
ret = load_image(buf, phys_ram_base + bios_offset);
if (ret != BIOS_SIZE) {
fprintf(stderr, "qemu: could not load PPC PREP bios '%s'\n", buf);
exit(1);
}
cpu_register_physical_memory((uint32_t)(-BIOS_SIZE),
BIOS_SIZE, bios_offset | IO_MEM_ROM);
cpu_single_env->nip = 0xfffffffc;
if (linux_boot) {
kernel_base = KERNEL_LOAD_ADDR;
/* now we can load the kernel */
kernel_size = load_image(kernel_filename, phys_ram_base + kernel_base);
if (kernel_size < 0) {
fprintf(stderr, "qemu: could not load kernel '%s'\n",
kernel_filename);
exit(1);
}
/* load initrd */
if (initrd_filename) {
initrd_base = INITRD_LOAD_ADDR;
initrd_size = load_image(initrd_filename,
phys_ram_base + initrd_base);
if (initrd_size < 0) {
fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
initrd_filename);
exit(1);
}
} else {
initrd_base = 0;
initrd_size = 0;
}
boot_device = 'm';
} else {
kernel_base = 0;
kernel_size = 0;
initrd_base = 0;
initrd_size = 0;
}
/* Register CPU as a 74x/75x */
cpu_ppc_register(cpu_single_env, 0x00080000);
/* Set time-base frequency to 100 Mhz */
cpu_ppc_tb_init(cpu_single_env, 100UL * 1000UL * 1000UL);
isa_mem_base = 0xc0000000;
pci_bus = pci_prep_init();
/* Register 64 KB of ISA IO space */
PPC_io_memory = cpu_register_io_memory(0, PPC_io_read, PPC_io_write, NULL);
cpu_register_physical_memory(0x80000000, 0x00010000, PPC_io_memory);
/* init basic PC hardware */
vga_initialize(pci_bus, ds, phys_ram_base + ram_size, ram_size,
vga_ram_size);
rtc_init(0x70, 8);
// openpic = openpic_init(0x00000000, 0xF0000000, 1);
// pic_init(openpic);
pic_init();
// pit = pit_init(0x40, 0);
serial_init(0x3f8, 4, serial_hds[0]);
nb_nics1 = nb_nics;
if (nb_nics1 > NE2000_NB_MAX)
nb_nics1 = NE2000_NB_MAX;
for(i = 0; i < nb_nics1; i++) {
isa_ne2000_init(ne2000_io[i], ne2000_irq[i], &nd_table[i]);
}
for(i = 0; i < 2; i++) {
isa_ide_init(ide_iobase[i], ide_iobase2[i], ide_irq[i],
bs_table[2 * i], bs_table[2 * i + 1]);
}
kbd_init();
DMA_init(1);
// AUD_init();
// SB16_init();
fdctrl_init(6, 2, 0, 0x3f0, fd_table);
/* Register speaker port */
register_ioport_read(0x61, 1, 1, speaker_ioport_read, NULL);
register_ioport_write(0x61, 1, 1, speaker_ioport_write, NULL);
/* Register fake IO ports for PREP */
register_ioport_read(0x398, 2, 1, &PREP_io_read, sysctrl);
register_ioport_write(0x398, 2, 1, &PREP_io_write, sysctrl);
/* System control ports */
register_ioport_read(0x0092, 0x01, 1, &PREP_io_800_readb, sysctrl);
register_ioport_write(0x0092, 0x01, 1, &PREP_io_800_writeb, sysctrl);
register_ioport_read(0x0800, 0x52, 1, &PREP_io_800_readb, sysctrl);
register_ioport_write(0x0800, 0x52, 1, &PREP_io_800_writeb, sysctrl);
/* PCI intack location */
PPC_io_memory = cpu_register_io_memory(0, PPC_intack_read,
PPC_intack_write, NULL);
cpu_register_physical_memory(0xBFFFFFF0, 0x4, PPC_io_memory);
/* PowerPC control and status register group */
#if 0
PPC_io_memory = cpu_register_io_memory(0, PPC_XCSR_read, PPC_XCSR_write, NULL);
cpu_register_physical_memory(0xFEFF0000, 0x1000, PPC_io_memory);
#endif
nvram = m48t59_init(8, 0, 0x0074, NVRAM_SIZE);
if (nvram == NULL)
return;
sysctrl->nvram = nvram;
/* Initialise NVRAM */
PPC_NVRAM_set_params(nvram, NVRAM_SIZE, "PREP", ram_size, boot_device,
kernel_base, kernel_size,
kernel_cmdline,
initrd_base, initrd_size,
/* XXX: need an option to load a NVRAM image */
0,
graphic_width, graphic_height, graphic_depth);
}

1268
hw/sb16.c Normal file

File diff suppressed because it is too large Load Diff

268
hw/sched.c Normal file
View File

@@ -0,0 +1,268 @@
/*
* QEMU interrupt controller emulation
*
* Copyright (c) 2003-2004 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 "vl.h"
//#define DEBUG_IRQ_COUNT
/* These registers are used for sending/receiving irqs from/to
* different cpu's.
*/
struct sun4m_intreg_percpu {
unsigned int tbt; /* Intrs pending for this cpu, by PIL. */
/* These next two registers are WRITE-ONLY and are only
* "on bit" sensitive, "off bits" written have NO affect.
*/
unsigned int clear; /* Clear this cpus irqs here. */
unsigned int set; /* Set this cpus irqs here. */
};
/*
* djhr
* Actually the clear and set fields in this struct are misleading..
* according to the SLAVIO manual (and the same applies for the SEC)
* the clear field clears bits in the mask which will ENABLE that IRQ
* the set field sets bits in the mask to DISABLE the IRQ.
*
* Also the undirected_xx address in the SLAVIO is defined as
* RESERVED and write only..
*
* DAVEM_NOTE: The SLAVIO only specifies behavior on uniprocessor
* sun4m machines, for MP the layout makes more sense.
*/
struct sun4m_intreg_master {
unsigned int tbt; /* IRQ's that are pending, see sun4m masks. */
unsigned int irqs; /* Master IRQ bits. */
/* Again, like the above, two these registers are WRITE-ONLY. */
unsigned int clear; /* Clear master IRQ's by setting bits here. */
unsigned int set; /* Set master IRQ's by setting bits here. */
/* This register is both READ and WRITE. */
unsigned int undirected_target; /* Which cpu gets undirected irqs. */
};
#define SUN4M_INT_ENABLE 0x80000000
#define SUN4M_INT_E14 0x00000080
#define SUN4M_INT_E10 0x00080000
#define SUN4M_HARD_INT(x) (0x000000001 << (x))
#define SUN4M_SOFT_INT(x) (0x000010000 << (x))
#define SUN4M_INT_MASKALL 0x80000000 /* mask all interrupts */
#define SUN4M_INT_MODULE_ERR 0x40000000 /* module error */
#define SUN4M_INT_M2S_WRITE 0x20000000 /* write buffer error */
#define SUN4M_INT_ECC 0x10000000 /* ecc memory error */
#define SUN4M_INT_FLOPPY 0x00400000 /* floppy disk */
#define SUN4M_INT_MODULE 0x00200000 /* module interrupt */
#define SUN4M_INT_VIDEO 0x00100000 /* onboard video */
#define SUN4M_INT_REALTIME 0x00080000 /* system timer */
#define SUN4M_INT_SCSI 0x00040000 /* onboard scsi */
#define SUN4M_INT_AUDIO 0x00020000 /* audio/isdn */
#define SUN4M_INT_ETHERNET 0x00010000 /* onboard ethernet */
#define SUN4M_INT_SERIAL 0x00008000 /* serial ports */
#define SUN4M_INT_SBUSBITS 0x00003F80 /* sbus int bits */
#define SUN4M_INT_SBUS(x) (1 << (x+7))
#define SUN4M_INT_VME(x) (1 << (x))
typedef struct SCHEDState {
uint32_t addr, addrg;
uint32_t intreg_pending;
uint32_t intreg_enabled;
uint32_t intregm_pending;
uint32_t intregm_enabled;
} SCHEDState;
static SCHEDState *ps;
#ifdef DEBUG_IRQ_COUNT
static uint64_t irq_count[32];
#endif
static uint32_t intreg_mem_readl(void *opaque, target_phys_addr_t addr)
{
SCHEDState *s = opaque;
uint32_t saddr;
saddr = (addr - s->addr) >> 2;
switch (saddr) {
case 0:
return s->intreg_pending;
break;
default:
break;
}
return 0;
}
static void intreg_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
{
SCHEDState *s = opaque;
uint32_t saddr;
saddr = (addr - s->addr) >> 2;
switch (saddr) {
case 0:
s->intreg_pending = val;
break;
case 1: // clear
s->intreg_enabled &= ~val;
break;
case 2: // set
s->intreg_enabled |= val;
break;
default:
break;
}
}
static CPUReadMemoryFunc *intreg_mem_read[3] = {
intreg_mem_readl,
intreg_mem_readl,
intreg_mem_readl,
};
static CPUWriteMemoryFunc *intreg_mem_write[3] = {
intreg_mem_writel,
intreg_mem_writel,
intreg_mem_writel,
};
static uint32_t intregm_mem_readl(void *opaque, target_phys_addr_t addr)
{
SCHEDState *s = opaque;
uint32_t saddr;
saddr = (addr - s->addrg) >> 2;
switch (saddr) {
case 0:
return s->intregm_pending;
break;
case 1:
return s->intregm_enabled;
break;
default:
break;
}
return 0;
}
static void intregm_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
{
SCHEDState *s = opaque;
uint32_t saddr;
saddr = (addr - s->addrg) >> 2;
switch (saddr) {
case 0:
s->intregm_pending = val;
break;
case 1:
s->intregm_enabled = val;
break;
case 2: // clear
s->intregm_enabled &= ~val;
break;
case 3: // set
s->intregm_enabled |= val;
break;
default:
break;
}
}
static CPUReadMemoryFunc *intregm_mem_read[3] = {
intregm_mem_readl,
intregm_mem_readl,
intregm_mem_readl,
};
static CPUWriteMemoryFunc *intregm_mem_write[3] = {
intregm_mem_writel,
intregm_mem_writel,
intregm_mem_writel,
};
void pic_info(void)
{
term_printf("per-cpu: pending 0x%08x, enabled 0x%08x\n", ps->intreg_pending, ps->intreg_enabled);
term_printf("master: pending 0x%08x, enabled 0x%08x\n", ps->intregm_pending, ps->intregm_enabled);
}
void irq_info(void)
{
#ifndef DEBUG_IRQ_COUNT
term_printf("irq statistic code not compiled.\n");
#else
int i;
int64_t count;
term_printf("IRQ statistics:\n");
for (i = 0; i < 32; i++) {
count = irq_count[i];
if (count > 0)
term_printf("%2d: %lld\n", i, count);
}
#endif
}
static const unsigned int intr_to_mask[16] = {
0, 0, 0, 0, 0, 0, SUN4M_INT_ETHERNET, 0,
0, 0, 0, 0, 0, 0, 0, 0,
};
void pic_set_irq(int irq, int level)
{
if (irq < 16) {
unsigned int mask = intr_to_mask[irq];
ps->intreg_pending |= 1 << irq;
if (ps->intregm_enabled & mask) {
cpu_single_env->interrupt_index = irq;
cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HARD);
}
}
#ifdef DEBUG_IRQ_COUNT
if (level == 1)
irq_count[irq]++;
#endif
}
void sched_init(uint32_t addr, uint32_t addrg)
{
int intreg_io_memory, intregm_io_memory;
SCHEDState *s;
s = qemu_mallocz(sizeof(SCHEDState));
if (!s)
return;
s->addr = addr;
s->addrg = addrg;
intreg_io_memory = cpu_register_io_memory(0, intreg_mem_read, intreg_mem_write, s);
cpu_register_physical_memory(addr, 3, intreg_io_memory);
intregm_io_memory = cpu_register_io_memory(0, intregm_mem_read, intregm_mem_write, s);
cpu_register_physical_memory(addrg, 5, intregm_io_memory);
ps = s;
}

279
hw/serial.c Normal file
View File

@@ -0,0 +1,279 @@
/*
* QEMU 16450 UART emulation
*
* Copyright (c) 2003-2004 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 "vl.h"
//#define DEBUG_SERIAL
#define UART_LCR_DLAB 0x80 /* Divisor latch access bit */
#define UART_IER_MSI 0x08 /* Enable Modem status interrupt */
#define UART_IER_RLSI 0x04 /* Enable receiver line status interrupt */
#define UART_IER_THRI 0x02 /* Enable Transmitter holding register int. */
#define UART_IER_RDI 0x01 /* Enable receiver data interrupt */
#define UART_IIR_NO_INT 0x01 /* No interrupts pending */
#define UART_IIR_ID 0x06 /* Mask for the interrupt ID */
#define UART_IIR_MSI 0x00 /* Modem status interrupt */
#define UART_IIR_THRI 0x02 /* Transmitter holding register empty */
#define UART_IIR_RDI 0x04 /* Receiver data interrupt */
#define UART_IIR_RLSI 0x06 /* Receiver line status interrupt */
/*
* These are the definitions for the Modem Control Register
*/
#define UART_MCR_LOOP 0x10 /* Enable loopback test mode */
#define UART_MCR_OUT2 0x08 /* Out2 complement */
#define UART_MCR_OUT1 0x04 /* Out1 complement */
#define UART_MCR_RTS 0x02 /* RTS complement */
#define UART_MCR_DTR 0x01 /* DTR complement */
/*
* These are the definitions for the Modem Status Register
*/
#define UART_MSR_DCD 0x80 /* Data Carrier Detect */
#define UART_MSR_RI 0x40 /* Ring Indicator */
#define UART_MSR_DSR 0x20 /* Data Set Ready */
#define UART_MSR_CTS 0x10 /* Clear to Send */
#define UART_MSR_DDCD 0x08 /* Delta DCD */
#define UART_MSR_TERI 0x04 /* Trailing edge ring indicator */
#define UART_MSR_DDSR 0x02 /* Delta DSR */
#define UART_MSR_DCTS 0x01 /* Delta CTS */
#define UART_MSR_ANY_DELTA 0x0F /* Any of the delta bits! */
#define UART_LSR_TEMT 0x40 /* Transmitter empty */
#define UART_LSR_THRE 0x20 /* Transmit-hold-register empty */
#define UART_LSR_BI 0x10 /* Break interrupt indicator */
#define UART_LSR_FE 0x08 /* Frame error indicator */
#define UART_LSR_PE 0x04 /* Parity error indicator */
#define UART_LSR_OE 0x02 /* Overrun error indicator */
#define UART_LSR_DR 0x01 /* Receiver data ready */
struct SerialState {
uint8_t divider;
uint8_t rbr; /* receive register */
uint8_t ier;
uint8_t iir; /* read only */
uint8_t lcr;
uint8_t mcr;
uint8_t lsr; /* read only */
uint8_t msr;
uint8_t scr;
/* NOTE: this hidden state is necessary for tx irq generation as
it can be reset while reading iir */
int thr_ipending;
int irq;
CharDriverState *chr;
};
static void serial_update_irq(SerialState *s)
{
if ((s->lsr & UART_LSR_DR) && (s->ier & UART_IER_RDI)) {
s->iir = UART_IIR_RDI;
} else if (s->thr_ipending && (s->ier & UART_IER_THRI)) {
s->iir = UART_IIR_THRI;
} else {
s->iir = UART_IIR_NO_INT;
}
if (s->iir != UART_IIR_NO_INT) {
pic_set_irq(s->irq, 1);
} else {
pic_set_irq(s->irq, 0);
}
}
static void serial_ioport_write(void *opaque, uint32_t addr, uint32_t val)
{
SerialState *s = opaque;
unsigned char ch;
addr &= 7;
#ifdef DEBUG_SERIAL
printf("serial: write addr=0x%02x val=0x%02x\n", addr, val);
#endif
switch(addr) {
default:
case 0:
if (s->lcr & UART_LCR_DLAB) {
s->divider = (s->divider & 0xff00) | val;
} else {
s->thr_ipending = 0;
s->lsr &= ~UART_LSR_THRE;
serial_update_irq(s);
ch = val;
qemu_chr_write(s->chr, &ch, 1);
s->thr_ipending = 1;
s->lsr |= UART_LSR_THRE;
s->lsr |= UART_LSR_TEMT;
serial_update_irq(s);
}
break;
case 1:
if (s->lcr & UART_LCR_DLAB) {
s->divider = (s->divider & 0x00ff) | (val << 8);
} else {
s->ier = val & 0x0f;
if (s->lsr & UART_LSR_THRE) {
s->thr_ipending = 1;
}
serial_update_irq(s);
}
break;
case 2:
break;
case 3:
s->lcr = val;
break;
case 4:
s->mcr = val & 0x1f;
break;
case 5:
break;
case 6:
s->msr = val;
break;
case 7:
s->scr = val;
break;
}
}
static uint32_t serial_ioport_read(void *opaque, uint32_t addr)
{
SerialState *s = opaque;
uint32_t ret;
addr &= 7;
switch(addr) {
default:
case 0:
if (s->lcr & UART_LCR_DLAB) {
ret = s->divider & 0xff;
} else {
ret = s->rbr;
s->lsr &= ~(UART_LSR_DR | UART_LSR_BI);
serial_update_irq(s);
}
break;
case 1:
if (s->lcr & UART_LCR_DLAB) {
ret = (s->divider >> 8) & 0xff;
} else {
ret = s->ier;
}
break;
case 2:
ret = s->iir;
/* reset THR pending bit */
if ((ret & 0x7) == UART_IIR_THRI)
s->thr_ipending = 0;
serial_update_irq(s);
break;
case 3:
ret = s->lcr;
break;
case 4:
ret = s->mcr;
break;
case 5:
ret = s->lsr;
break;
case 6:
if (s->mcr & UART_MCR_LOOP) {
/* in loopback, the modem output pins are connected to the
inputs */
ret = (s->mcr & 0x0c) << 4;
ret |= (s->mcr & 0x02) << 3;
ret |= (s->mcr & 0x01) << 5;
} else {
ret = s->msr;
}
break;
case 7:
ret = s->scr;
break;
}
#ifdef DEBUG_SERIAL
printf("serial: read addr=0x%02x val=0x%02x\n", addr, ret);
#endif
return ret;
}
static int serial_can_receive(SerialState *s)
{
return !(s->lsr & UART_LSR_DR);
}
static void serial_receive_byte(SerialState *s, int ch)
{
s->rbr = ch;
s->lsr |= UART_LSR_DR;
serial_update_irq(s);
}
static void serial_receive_break(SerialState *s)
{
s->rbr = 0;
s->lsr |= UART_LSR_BI | UART_LSR_DR;
serial_update_irq(s);
}
static int serial_can_receive1(void *opaque)
{
SerialState *s = opaque;
return serial_can_receive(s);
}
static void serial_receive1(void *opaque, const uint8_t *buf, int size)
{
SerialState *s = opaque;
serial_receive_byte(s, buf[0]);
}
static void serial_event(void *opaque, int event)
{
SerialState *s = opaque;
if (event == CHR_EVENT_BREAK)
serial_receive_break(s);
}
/* If fd is zero, it means that the serial device uses the console */
SerialState *serial_init(int base, int irq, CharDriverState *chr)
{
SerialState *s;
s = qemu_mallocz(sizeof(SerialState));
if (!s)
return NULL;
s->irq = irq;
s->lsr = UART_LSR_TEMT | UART_LSR_THRE;
s->iir = UART_IIR_NO_INT;
register_ioport_write(base, 8, 1, serial_ioport_write, s);
register_ioport_read(base, 8, 1, serial_ioport_read, s);
s->chr = chr;
qemu_chr_add_read_handler(chr, serial_can_receive1, serial_receive1, s);
qemu_chr_add_event_handler(chr, serial_event);
return s;
}

113
hw/sun4m.c Normal file
View File

@@ -0,0 +1,113 @@
/*
* QEMU Sun4m System Emulator
*
* Copyright (c) 2003-2004 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 "vl.h"
#include "m48t08.h"
#define KERNEL_LOAD_ADDR 0x00004000
#define MMU_CONTEXT_TBL 0x00003000
#define MMU_L1PTP (MMU_CONTEXT_TBL + 0x0400)
#define MMU_L2PTP (MMU_CONTEXT_TBL + 0x0800)
#define PROM_ADDR 0xffd04000
#define PROM_FILENAMEB "proll.bin"
#define PROM_FILENAMEE "proll.elf"
#define PROLL_MAGIC_ADDR 0x20000000
#define PHYS_JJ_EEPROM 0x71200000 /* [2000] MK48T08 */
#define PHYS_JJ_IDPROM_OFF 0x1FD8
#define PHYS_JJ_EEPROM_SIZE 0x2000
#define PHYS_JJ_IOMMU 0x10000000 /* First page of sun4m IOMMU */
#define PHYS_JJ_TCX_FB 0x50800000 /* Start address, frame buffer body */
#define PHYS_JJ_TCX_0E 0x5E000000 /* Top address, one byte used. */
#define PHYS_JJ_IOMMU 0x10000000 /* First page of sun4m IOMMU */
#define PHYS_JJ_LEDMA 0x78400010 /* ledma, off by 10 from unused SCSI */
#define PHYS_JJ_LE 0x78C00000 /* LANCE, typical sun4m */
#define PHYS_JJ_LE_IRQ 6
#define PHYS_JJ_CLOCK 0x71D00000
#define PHYS_JJ_CLOCK_IRQ 10
#define PHYS_JJ_CLOCK1 0x71D10000
#define PHYS_JJ_CLOCK1_IRQ 14
#define PHYS_JJ_INTR0 0x71E00000 /* CPU0 interrupt control registers */
#define PHYS_JJ_INTR_G 0x71E10000 /* Master interrupt control registers */
/* TSC handling */
uint64_t cpu_get_tsc()
{
return qemu_get_clock(vm_clock);
}
void DMA_run() {}
void SB16_run() {}
int serial_can_receive(SerialState *s) { return 0; }
void serial_receive_byte(SerialState *s, int ch) {}
void serial_receive_break(SerialState *s) {}
static m48t08_t *nvram;
/* Sun4m hardware initialisation */
void sun4m_init(int ram_size, int vga_ram_size, int boot_device,
DisplayState *ds, const char **fd_filename, int snapshot,
const char *kernel_filename, const char *kernel_cmdline,
const char *initrd_filename)
{
char buf[1024];
int ret, linux_boot;
unsigned long bios_offset;
linux_boot = (kernel_filename != NULL);
/* allocate RAM */
cpu_register_physical_memory(0, ram_size, 0);
bios_offset = ram_size;
iommu_init(PHYS_JJ_IOMMU);
sched_init(PHYS_JJ_INTR0, PHYS_JJ_INTR_G);
tcx_init(ds, PHYS_JJ_TCX_FB);
lance_init(&nd_table[0], PHYS_JJ_LE_IRQ, PHYS_JJ_LE, PHYS_JJ_LEDMA);
nvram = m48t08_init(PHYS_JJ_EEPROM, PHYS_JJ_EEPROM_SIZE, &nd_table[0].macaddr);
timer_init(PHYS_JJ_CLOCK, PHYS_JJ_CLOCK_IRQ);
timer_init(PHYS_JJ_CLOCK1, PHYS_JJ_CLOCK1_IRQ);
magic_init(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR, PROLL_MAGIC_ADDR);
/* We load Proll as the kernel and start it. It will issue a magic
IO to load the real kernel */
if (linux_boot) {
snprintf(buf, sizeof(buf), "%s/%s", bios_dir, PROM_FILENAMEB);
ret = load_kernel(buf,
phys_ram_base + KERNEL_LOAD_ADDR);
if (ret < 0) {
fprintf(stderr, "qemu: could not load kernel '%s'\n",
buf);
exit(1);
}
}
/* Setup a MMU entry for entire address space */
stl_raw(phys_ram_base + MMU_CONTEXT_TBL, (MMU_L1PTP >> 4) | 1);
stl_raw(phys_ram_base + MMU_L1PTP, (MMU_L2PTP >> 4) | 1);
stl_raw(phys_ram_base + MMU_L1PTP + (0x01 << 2), (MMU_L2PTP >> 4) | 1); // 01.. == 00..
stl_raw(phys_ram_base + MMU_L1PTP + (0xff << 2), (MMU_L2PTP >> 4) | 1); // ff.. == 00..
stl_raw(phys_ram_base + MMU_L1PTP + (0xf0 << 2), (MMU_L2PTP >> 4) | 1); // f0.. == 00..
/* 3 = U:RWX S:RWX */
stl_raw(phys_ram_base + MMU_L2PTP, (3 << PTE_ACCESS_SHIFT) | 2);
stl_raw(phys_ram_base + MMU_L2PTP, ((0x01 << PTE_PPN_SHIFT) >> 4 ) | (3 << PTE_ACCESS_SHIFT) | 2);
}

207
hw/tcx.c Normal file
View File

@@ -0,0 +1,207 @@
/*
* QEMU Sun4m System Emulator
*
* Copyright (c) 2003-2004 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 "vl.h"
#define MAXX 1024
#define MAXY 768
#define XSZ (8*80)
#define YSZ (24*11)
#define XOFF (MAXX-XSZ)
#define YOFF (MAXY-YSZ)
typedef struct TCXState {
uint32_t addr;
DisplayState *ds;
uint8_t *vram;
} TCXState;
static TCXState *ts;
void vga_update_display()
{
dpy_update(ts->ds, 0, 0, XSZ, YSZ);
}
void vga_invalidate_display() {}
static uint32_t tcx_mem_readb(void *opaque, target_phys_addr_t addr)
{
TCXState *s = opaque;
uint32_t saddr;
unsigned int x, y;
saddr = addr - s->addr - YOFF*MAXX - XOFF;
y = saddr / MAXX;
x = saddr - y * MAXX;
if (x < XSZ && y < YSZ) {
return s->vram[y * XSZ + x];
}
return 0;
}
static uint32_t tcx_mem_readw(void *opaque, target_phys_addr_t addr)
{
uint32_t v;
#ifdef TARGET_WORDS_BIGENDIAN
v = tcx_mem_readb(opaque, addr) << 8;
v |= tcx_mem_readb(opaque, addr + 1);
#else
v = tcx_mem_readb(opaque, addr);
v |= tcx_mem_readb(opaque, addr + 1) << 8;
#endif
return v;
}
static uint32_t tcx_mem_readl(void *opaque, target_phys_addr_t addr)
{
uint32_t v;
#ifdef TARGET_WORDS_BIGENDIAN
v = tcx_mem_readb(opaque, addr) << 24;
v |= tcx_mem_readb(opaque, addr + 1) << 16;
v |= tcx_mem_readb(opaque, addr + 2) << 8;
v |= tcx_mem_readb(opaque, addr + 3);
#else
v = tcx_mem_readb(opaque, addr);
v |= tcx_mem_readb(opaque, addr + 1) << 8;
v |= tcx_mem_readb(opaque, addr + 2) << 16;
v |= tcx_mem_readb(opaque, addr + 3) << 24;
#endif
return v;
}
static void tcx_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
{
TCXState *s = opaque;
uint32_t saddr;
unsigned int x, y;
char *sptr;
saddr = addr - s->addr - YOFF*MAXX - XOFF;
y = saddr / MAXX;
x = saddr - y * MAXX;
if (x < XSZ && y < YSZ) {
sptr = s->ds->data;
if (sptr) {
if (s->ds->depth == 24 || s->ds->depth == 32) {
/* XXX need to do CLUT translation */
sptr[y * s->ds->linesize + x*4] = val & 0xff;
sptr[y * s->ds->linesize + x*4+1] = val & 0xff;
sptr[y * s->ds->linesize + x*4+2] = val & 0xff;
}
else if (s->ds->depth == 8) {
sptr[y * s->ds->linesize + x] = val & 0xff;
}
}
cpu_physical_memory_set_dirty(addr);
s->vram[y * XSZ + x] = val & 0xff;
}
}
static void tcx_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
{
#ifdef TARGET_WORDS_BIGENDIAN
tcx_mem_writeb(opaque, addr, (val >> 8) & 0xff);
tcx_mem_writeb(opaque, addr + 1, val & 0xff);
#else
tcx_mem_writeb(opaque, addr, val & 0xff);
tcx_mem_writeb(opaque, addr + 1, (val >> 8) & 0xff);
#endif
}
static void tcx_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
{
#ifdef TARGET_WORDS_BIGENDIAN
tcx_mem_writeb(opaque, addr, (val >> 24) & 0xff);
tcx_mem_writeb(opaque, addr + 1, (val >> 16) & 0xff);
tcx_mem_writeb(opaque, addr + 2, (val >> 8) & 0xff);
tcx_mem_writeb(opaque, addr + 3, val & 0xff);
#else
tcx_mem_writeb(opaque, addr, val & 0xff);
tcx_mem_writeb(opaque, addr + 1, (val >> 8) & 0xff);
tcx_mem_writeb(opaque, addr + 2, (val >> 16) & 0xff);
tcx_mem_writeb(opaque, addr + 3, (val >> 24) & 0xff);
#endif
}
static CPUReadMemoryFunc *tcx_mem_read[3] = {
tcx_mem_readb,
tcx_mem_readw,
tcx_mem_readl,
};
static CPUWriteMemoryFunc *tcx_mem_write[3] = {
tcx_mem_writeb,
tcx_mem_writew,
tcx_mem_writel,
};
void tcx_init(DisplayState *ds, uint32_t addr)
{
TCXState *s;
int tcx_io_memory;
s = qemu_mallocz(sizeof(TCXState));
if (!s)
return;
s->ds = ds;
s->addr = addr;
ts = s;
tcx_io_memory = cpu_register_io_memory(0, tcx_mem_read, tcx_mem_write, s);
cpu_register_physical_memory(addr, 0x100000,
tcx_io_memory);
s->vram = qemu_mallocz(XSZ*YSZ);
dpy_resize(s->ds, XSZ, YSZ);
}
void vga_screen_dump(const char *filename)
{
TCXState *s = ts;
FILE *f;
uint8_t *d, *d1;
unsigned int v;
int y, x;
f = fopen(filename, "wb");
if (!f)
return -1;
fprintf(f, "P6\n%d %d\n%d\n",
XSZ, YSZ, 255);
d1 = s->vram;
for(y = 0; y < YSZ; y++) {
d = d1;
for(x = 0; x < XSZ; x++) {
v = *d;
fputc((v) & 0xff, f);
fputc((v) & 0xff, f);
fputc((v) & 0xff, f);
d++;
}
d1 += XSZ;
}
fclose(f);
return;
}

97
hw/timer.c Normal file
View File

@@ -0,0 +1,97 @@
/*
* QEMU Sparc timer controller emulation
*
* Copyright (c) 2003-2004 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 "vl.h"
/*
* Registers of hardware timer in sun4m.
*/
struct sun4m_timer_percpu {
volatile unsigned int l14_timer_limit; /* Initial value is 0x009c4000 */
volatile unsigned int l14_cur_count;
};
struct sun4m_timer_global {
volatile unsigned int l10_timer_limit;
volatile unsigned int l10_cur_count;
};
typedef struct TIMERState {
uint32_t addr;
uint32_t timer_regs[2];
int irq;
} TIMERState;
static uint32_t timer_mem_readl(void *opaque, target_phys_addr_t addr)
{
TIMERState *s = opaque;
uint32_t saddr;
saddr = (addr - s->addr) >> 2;
switch (saddr) {
default:
return s->timer_regs[saddr];
break;
}
return 0;
}
static void timer_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
{
TIMERState *s = opaque;
uint32_t saddr;
saddr = (addr - s->addr) >> 2;
switch (saddr) {
default:
s->timer_regs[saddr] = val;
break;
}
}
static CPUReadMemoryFunc *timer_mem_read[3] = {
timer_mem_readl,
timer_mem_readl,
timer_mem_readl,
};
static CPUWriteMemoryFunc *timer_mem_write[3] = {
timer_mem_writel,
timer_mem_writel,
timer_mem_writel,
};
void timer_init(uint32_t addr, int irq)
{
int timer_io_memory;
TIMERState *s;
s = qemu_mallocz(sizeof(TIMERState));
if (!s)
return;
s->addr = addr;
s->irq = irq;
timer_io_memory = cpu_register_io_memory(0, timer_mem_read, timer_mem_write, s);
cpu_register_physical_memory(addr, 2, timer_io_memory);
}

1081
hw/vga.c

File diff suppressed because it is too large Load Diff

168
hw/vga_int.h Normal file
View File

@@ -0,0 +1,168 @@
/*
* QEMU internal VGA defines.
*
* Copyright (c) 2003-2004 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.
*/
#define MSR_COLOR_EMULATION 0x01
#define MSR_PAGE_SELECT 0x20
#define ST01_V_RETRACE 0x08
#define ST01_DISP_ENABLE 0x01
/* bochs VBE support */
#define CONFIG_BOCHS_VBE
#define VBE_DISPI_MAX_XRES 1024
#define VBE_DISPI_MAX_YRES 768
#define VBE_DISPI_INDEX_ID 0x0
#define VBE_DISPI_INDEX_XRES 0x1
#define VBE_DISPI_INDEX_YRES 0x2
#define VBE_DISPI_INDEX_BPP 0x3
#define VBE_DISPI_INDEX_ENABLE 0x4
#define VBE_DISPI_INDEX_BANK 0x5
#define VBE_DISPI_INDEX_VIRT_WIDTH 0x6
#define VBE_DISPI_INDEX_VIRT_HEIGHT 0x7
#define VBE_DISPI_INDEX_X_OFFSET 0x8
#define VBE_DISPI_INDEX_Y_OFFSET 0x9
#define VBE_DISPI_INDEX_NB 0xa
#define VBE_DISPI_ID0 0xB0C0
#define VBE_DISPI_ID1 0xB0C1
#define VBE_DISPI_ID2 0xB0C2
#define VBE_DISPI_DISABLED 0x00
#define VBE_DISPI_ENABLED 0x01
#define VBE_DISPI_LFB_ENABLED 0x40
#define VBE_DISPI_NOCLEARMEM 0x80
#define VBE_DISPI_LFB_PHYSICAL_ADDRESS 0xE0000000
#ifdef CONFIG_BOCHS_VBE
#define VGA_STATE_COMMON_BOCHS_VBE \
uint16_t vbe_index; \
uint16_t vbe_regs[VBE_DISPI_INDEX_NB]; \
uint32_t vbe_start_addr; \
uint32_t vbe_line_offset; \
uint32_t vbe_bank_mask;
#else
#define VGA_STATE_COMMON_BOCHS_VBE
#endif /* !CONFIG_BOCHS_VBE */
#define CH_ATTR_SIZE (160 * 100)
#define VGA_MAX_HEIGHT 1024
#define VGA_STATE_COMMON \
uint8_t *vram_ptr; \
unsigned long vram_offset; \
unsigned int vram_size; \
uint32_t latch; \
uint8_t sr_index; \
uint8_t sr[256]; \
uint8_t gr_index; \
uint8_t gr[256]; \
uint8_t ar_index; \
uint8_t ar[21]; \
int ar_flip_flop; \
uint8_t cr_index; \
uint8_t cr[256]; /* CRT registers */ \
uint8_t msr; /* Misc Output Register */ \
uint8_t fcr; /* Feature Control Register */ \
uint8_t st00; /* status 0 */ \
uint8_t st01; /* status 1 */ \
uint8_t dac_state; \
uint8_t dac_sub_index; \
uint8_t dac_read_index; \
uint8_t dac_write_index; \
uint8_t dac_cache[3]; /* used when writing */ \
uint8_t palette[768]; \
int32_t bank_offset; \
int (*get_bpp)(struct VGAState *s); \
void (*get_offsets)(struct VGAState *s, \
uint32_t *pline_offset, \
uint32_t *pstart_addr); \
void (*get_resolution)(struct VGAState *s, \
int *pwidth, \
int *pheight); \
VGA_STATE_COMMON_BOCHS_VBE \
/* display refresh support */ \
DisplayState *ds; \
uint32_t font_offsets[2]; \
int graphic_mode; \
uint8_t shift_control; \
uint8_t double_scan; \
uint32_t line_offset; \
uint32_t line_compare; \
uint32_t start_addr; \
uint32_t plane_updated; \
uint8_t last_cw, last_ch; \
uint32_t last_width, last_height; /* in chars or pixels */ \
uint32_t last_scr_width, last_scr_height; /* in pixels */ \
uint8_t cursor_start, cursor_end; \
uint32_t cursor_offset; \
unsigned int (*rgb_to_pixel)(unsigned int r, \
unsigned int g, unsigned b); \
/* hardware mouse cursor support */ \
uint32_t invalidated_y_table[VGA_MAX_HEIGHT / 32]; \
void (*cursor_invalidate)(struct VGAState *s); \
void (*cursor_draw_line)(struct VGAState *s, uint8_t *d, int y); \
/* tell for each page if it has been updated since the last time */ \
uint32_t last_palette[256]; \
uint32_t last_ch_attr[CH_ATTR_SIZE]; /* XXX: make it dynamic */
typedef struct VGAState {
VGA_STATE_COMMON
} VGAState;
static inline int c6_to_8(int v)
{
int b;
v &= 0x3f;
b = v & 1;
return (v << 2) | (b << 1) | b;
}
void vga_common_init(VGAState *s, DisplayState *ds, uint8_t *vga_ram_base,
unsigned long vga_ram_offset, int vga_ram_size);
uint32_t vga_mem_readb(void *opaque, target_phys_addr_t addr);
void vga_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val);
void vga_invalidate_scanlines(VGAState *s, int y1, int y2);
void vga_draw_cursor_line_8(uint8_t *d1, const uint8_t *src1,
int poffset, int w,
unsigned int color0, unsigned int color1,
unsigned int color_xor);
void vga_draw_cursor_line_16(uint8_t *d1, const uint8_t *src1,
int poffset, int w,
unsigned int color0, unsigned int color1,
unsigned int color_xor);
void vga_draw_cursor_line_32(uint8_t *d1, const uint8_t *src1,
int poffset, int w,
unsigned int color0, unsigned int color1,
unsigned int color_xor);
extern const uint8_t sr_mask[8];
extern const uint8_t gr_mask[16];

View File

@@ -44,7 +44,7 @@ static inline void glue(vga_draw_glyph_line_, DEPTH)(uint8_t *d,
{
#if BPP == 1
((uint32_t *)d)[0] = (dmask16[(font_data >> 4)] & xorcol) ^ bgcol;
((uint32_t *)d)[3] = (dmask16[(font_data >> 0) & 0xf] & xorcol) ^ bgcol;
((uint32_t *)d)[1] = (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;
@@ -106,35 +106,34 @@ static void glue(vga_draw_glyph9_, DEPTH)(uint8_t *d, int linesize,
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;
cpu_to_32wu((uint32_t *)d, (dmask16[(font_data >> 4)] & xorcol) ^ bgcol);
v = (dmask16[(font_data >> 0) & 0xf] & xorcol) ^ bgcol;
((uint32_t *)d)[3] = v;
cpu_to_32wu(((uint32_t *)d)+1, 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;
cpu_to_32wu(((uint32_t *)d)+0, (dmask4[(font_data >> 6)] & xorcol) ^ bgcol);
cpu_to_32wu(((uint32_t *)d)+1, (dmask4[(font_data >> 4) & 3] & xorcol) ^ bgcol);
cpu_to_32wu(((uint32_t *)d)+2, (dmask4[(font_data >> 2) & 3] & xorcol) ^ bgcol);
v = (dmask4[(font_data >> 0) & 3] & xorcol) ^ bgcol;
((uint32_t *)d)[3] = v;
cpu_to_32wu(((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)[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;
@@ -346,7 +345,7 @@ static void glue(vga_draw_line8_, DEPTH)(VGAState *s1, uint8_t *d,
static void glue(vga_draw_line15_, DEPTH)(VGAState *s1, uint8_t *d,
const uint8_t *s, int width)
{
#if DEPTH == 15 && !defined(WORDS_BIGENDIAN)
#if DEPTH == 15 && defined(WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN)
memcpy(d, s, width * 2);
#else
int w;
@@ -371,7 +370,7 @@ static void glue(vga_draw_line15_, DEPTH)(VGAState *s1, uint8_t *d,
static void glue(vga_draw_line16_, DEPTH)(VGAState *s1, uint8_t *d,
const uint8_t *s, int width)
{
#if DEPTH == 16 && !defined(WORDS_BIGENDIAN)
#if DEPTH == 16 && defined(WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN)
memcpy(d, s, width * 2);
#else
int w;
@@ -390,13 +389,39 @@ static void glue(vga_draw_line16_, DEPTH)(VGAState *s1, uint8_t *d,
#endif
}
/*
* 24 bit color
*/
static void glue(vga_draw_line24_, DEPTH)(VGAState *s1, uint8_t *d,
const uint8_t *s, int width)
{
int w;
uint32_t r, g, b;
w = width;
do {
#if defined(TARGET_WORDS_BIGENDIAN)
r = s[0];
g = s[1];
b = s[2];
#else
b = s[0];
g = s[1];
r = s[2];
#endif
((PIXEL_TYPE *)d)[0] = glue(rgb_to_pixel, DEPTH)(r, g, b);
s += 3;
d += BPP;
} while (--w != 0);
}
/*
* 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)
#if DEPTH == 32 && defined(WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN)
memcpy(d, s, width * 4);
#else
int w;
@@ -404,9 +429,15 @@ static void glue(vga_draw_line32_, DEPTH)(VGAState *s1, uint8_t *d,
w = width;
do {
#if defined(TARGET_WORDS_BIGENDIAN)
r = s[1];
g = s[2];
b = s[3];
#else
b = s[0];
g = s[1];
r = s[2];
#endif
((PIXEL_TYPE *)d)[0] = glue(rgb_to_pixel, DEPTH)(r, g, b);
s += 4;
d += BPP;
@@ -414,6 +445,74 @@ static void glue(vga_draw_line32_, DEPTH)(VGAState *s1, uint8_t *d,
#endif
}
#if DEPTH != 15
void glue(vga_draw_cursor_line_, DEPTH)(uint8_t *d1,
const uint8_t *src1,
int poffset, int w,
unsigned int color0,
unsigned int color1,
unsigned int color_xor)
{
const uint8_t *plane0, *plane1;
int x, b0, b1;
uint8_t *d;
d = d1;
plane0 = src1;
plane1 = src1 + poffset;
for(x = 0; x < w; x++) {
b0 = (plane0[x >> 3] >> (7 - (x & 7))) & 1;
b1 = (plane1[x >> 3] >> (7 - (x & 7))) & 1;
#if DEPTH == 8
switch(b0 | (b1 << 1)) {
case 0:
break;
case 1:
d[0] ^= color_xor;
break;
case 2:
d[0] = color0;
break;
case 3:
d[0] = color1;
break;
}
#elif DEPTH == 16
switch(b0 | (b1 << 1)) {
case 0:
break;
case 1:
((uint16_t *)d)[0] ^= color_xor;
break;
case 2:
((uint16_t *)d)[0] = color0;
break;
case 3:
((uint16_t *)d)[0] = color1;
break;
}
#elif DEPTH == 32
switch(b0 | (b1 << 1)) {
case 0:
break;
case 1:
((uint32_t *)d)[0] ^= color_xor;
break;
case 2:
((uint32_t *)d)[0] = color0;
break;
case 3:
((uint32_t *)d)[0] = color1;
break;
}
#else
#error unsupported depth
#endif
d += BPP;
}
}
#endif
#undef PUT_PIXEL2
#undef DEPTH
#undef BPP

4475
i386-dis.c

File diff suppressed because it is too large Load Diff

10
i386.ld
View File

@@ -53,6 +53,16 @@ SECTIONS
_etext = .;
PROVIDE (etext = .);
.fini : { *(.fini) } =0x47ff041f
. = ALIGN(32 / 8);
PROVIDE (__preinit_array_start = .);
.preinit_array : { *(.preinit_array) }
PROVIDE (__preinit_array_end = .);
PROVIDE (__init_array_start = .);
.init_array : { *(.init_array) }
PROVIDE (__init_array_end = .);
PROVIDE (__fini_array_start = .);
.fini_array : { *(.fini_array) }
PROVIDE (__fini_array_end = .);
.rodata : { *(.rodata) *(.gnu.linkonce.r*) }
.rodata1 : { *(.rodata1) }
.reginfo : { *(.reginfo) }

305
linux-2.6-qemu-fast.patch Normal file
View File

@@ -0,0 +1,305 @@
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .32324-linux-2.6.0/arch/i386/Kconfig .32324-linux-2.6.0.updated/arch/i386/Kconfig
--- .32324-linux-2.6.0/arch/i386/Kconfig 2003-10-09 18:02:48.000000000 +1000
+++ .32324-linux-2.6.0.updated/arch/i386/Kconfig 2003-12-26 16:46:49.000000000 +1100
@@ -307,6 +307,14 @@ config X86_GENERIC
when it has moderate overhead. This is intended for generic
distributions kernels.
+config QEMU
+ bool "Kernel to run under QEMU"
+ depends on EXPERIMENTAL
+ help
+ Select this if you want to boot the kernel inside qemu-fast,
+ the non-mmu version of the x86 emulator. See
+ <http://fabrice.bellard.free.fr/qemu/>. Say N.
+
#
# Define implied options from the CPU selection here
#
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .32324-linux-2.6.0/arch/i386/kernel/Makefile .32324-linux-2.6.0.updated/arch/i386/kernel/Makefile
--- .32324-linux-2.6.0/arch/i386/kernel/Makefile 2003-09-29 10:25:15.000000000 +1000
+++ .32324-linux-2.6.0.updated/arch/i386/kernel/Makefile 2003-12-26 16:46:49.000000000 +1100
@@ -46,12 +46,14 @@ quiet_cmd_syscall = SYSCALL $@
cmd_syscall = $(CC) -nostdlib $(SYSCFLAGS_$(@F)) \
-Wl,-T,$(filter-out FORCE,$^) -o $@
+export AFLAGS_vsyscall.lds.o += -P -C -U$(ARCH)
+
vsyscall-flags = -shared -s -Wl,-soname=linux-gate.so.1
SYSCFLAGS_vsyscall-sysenter.so = $(vsyscall-flags)
SYSCFLAGS_vsyscall-int80.so = $(vsyscall-flags)
$(obj)/vsyscall-int80.so $(obj)/vsyscall-sysenter.so: \
-$(obj)/vsyscall-%.so: $(src)/vsyscall.lds $(obj)/vsyscall-%.o FORCE
+$(obj)/vsyscall-%.so: $(src)/vsyscall.lds.s $(obj)/vsyscall-%.o FORCE
$(call if_changed,syscall)
# We also create a special relocatable object that should mirror the symbol
@@ -62,5 +64,5 @@ $(obj)/built-in.o: $(obj)/vsyscall-syms.
$(obj)/built-in.o: ld_flags += -R $(obj)/vsyscall-syms.o
SYSCFLAGS_vsyscall-syms.o = -r
-$(obj)/vsyscall-syms.o: $(src)/vsyscall.lds $(obj)/vsyscall-sysenter.o FORCE
+$(obj)/vsyscall-syms.o: $(src)/vsyscall.lds.s $(obj)/vsyscall-sysenter.o FORCE
$(call if_changed,syscall)
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .32324-linux-2.6.0/arch/i386/kernel/vmlinux.lds.S .32324-linux-2.6.0.updated/arch/i386/kernel/vmlinux.lds.S
--- .32324-linux-2.6.0/arch/i386/kernel/vmlinux.lds.S 2003-09-22 10:27:28.000000000 +1000
+++ .32324-linux-2.6.0.updated/arch/i386/kernel/vmlinux.lds.S 2003-12-26 16:46:49.000000000 +1100
@@ -3,6 +3,7 @@
*/
#include <asm-generic/vmlinux.lds.h>
+#include <asm/page.h>
OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
OUTPUT_ARCH(i386)
@@ -10,7 +11,7 @@ ENTRY(startup_32)
jiffies = jiffies_64;
SECTIONS
{
- . = 0xC0000000 + 0x100000;
+ . = __PAGE_OFFSET + 0x100000;
/* read-only */
_text = .; /* Text and read-only data */
.text : {
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .32324-linux-2.6.0/arch/i386/kernel/vsyscall.lds .32324-linux-2.6.0.updated/arch/i386/kernel/vsyscall.lds
--- .32324-linux-2.6.0/arch/i386/kernel/vsyscall.lds 2003-09-22 10:07:26.000000000 +1000
+++ .32324-linux-2.6.0.updated/arch/i386/kernel/vsyscall.lds 1970-01-01 10:00:00.000000000 +1000
@@ -1,67 +0,0 @@
-/*
- * Linker script for vsyscall DSO. The vsyscall page is an ELF shared
- * object prelinked to its virtual address, and with only one read-only
- * segment (that fits in one page). This script controls its layout.
- */
-
-/* This must match <asm/fixmap.h>. */
-VSYSCALL_BASE = 0xffffe000;
-
-SECTIONS
-{
- . = VSYSCALL_BASE + SIZEOF_HEADERS;
-
- .hash : { *(.hash) } :text
- .dynsym : { *(.dynsym) }
- .dynstr : { *(.dynstr) }
- .gnu.version : { *(.gnu.version) }
- .gnu.version_d : { *(.gnu.version_d) }
- .gnu.version_r : { *(.gnu.version_r) }
-
- /* This linker script is used both with -r and with -shared.
- For the layouts to match, we need to skip more than enough
- space for the dynamic symbol table et al. If this amount
- is insufficient, ld -shared will barf. Just increase it here. */
- . = VSYSCALL_BASE + 0x400;
-
- .text : { *(.text) } :text =0x90909090
-
- .eh_frame_hdr : { *(.eh_frame_hdr) } :text :eh_frame_hdr
- .eh_frame : { KEEP (*(.eh_frame)) } :text
- .dynamic : { *(.dynamic) } :text :dynamic
- .useless : {
- *(.got.plt) *(.got)
- *(.data .data.* .gnu.linkonce.d.*)
- *(.dynbss)
- *(.bss .bss.* .gnu.linkonce.b.*)
- } :text
-}
-
-/*
- * We must supply the ELF program headers explicitly to get just one
- * PT_LOAD segment, and set the flags explicitly to make segments read-only.
- */
-PHDRS
-{
- text PT_LOAD FILEHDR PHDRS FLAGS(5); /* PF_R|PF_X */
- dynamic PT_DYNAMIC FLAGS(4); /* PF_R */
- eh_frame_hdr 0x6474e550; /* PT_GNU_EH_FRAME, but ld doesn't match the name */
-}
-
-/*
- * This controls what symbols we export from the DSO.
- */
-VERSION
-{
- LINUX_2.5 {
- global:
- __kernel_vsyscall;
- __kernel_sigreturn;
- __kernel_rt_sigreturn;
-
- local: *;
- };
-}
-
-/* The ELF entry point can be used to set the AT_SYSINFO value. */
-ENTRY(__kernel_vsyscall);
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .32324-linux-2.6.0/arch/i386/kernel/vsyscall.lds.S .32324-linux-2.6.0.updated/arch/i386/kernel/vsyscall.lds.S
--- .32324-linux-2.6.0/arch/i386/kernel/vsyscall.lds.S 1970-01-01 10:00:00.000000000 +1000
+++ .32324-linux-2.6.0.updated/arch/i386/kernel/vsyscall.lds.S 2003-12-26 16:46:49.000000000 +1100
@@ -0,0 +1,67 @@
+/*
+ * Linker script for vsyscall DSO. The vsyscall page is an ELF shared
+ * object prelinked to its virtual address, and with only one read-only
+ * segment (that fits in one page). This script controls its layout.
+ */
+#include <asm/fixmap.h>
+
+VSYSCALL_BASE = __FIXADDR_TOP - 0x1000;
+
+SECTIONS
+{
+ . = VSYSCALL_BASE + SIZEOF_HEADERS;
+
+ .hash : { *(.hash) } :text
+ .dynsym : { *(.dynsym) }
+ .dynstr : { *(.dynstr) }
+ .gnu.version : { *(.gnu.version) }
+ .gnu.version_d : { *(.gnu.version_d) }
+ .gnu.version_r : { *(.gnu.version_r) }
+
+ /* This linker script is used both with -r and with -shared.
+ For the layouts to match, we need to skip more than enough
+ space for the dynamic symbol table et al. If this amount
+ is insufficient, ld -shared will barf. Just increase it here. */
+ . = VSYSCALL_BASE + 0x400;
+
+ .text : { *(.text) } :text =0x90909090
+
+ .eh_frame_hdr : { *(.eh_frame_hdr) } :text :eh_frame_hdr
+ .eh_frame : { KEEP (*(.eh_frame)) } :text
+ .dynamic : { *(.dynamic) } :text :dynamic
+ .useless : {
+ *(.got.plt) *(.got)
+ *(.data .data.* .gnu.linkonce.d.*)
+ *(.dynbss)
+ *(.bss .bss.* .gnu.linkonce.b.*)
+ } :text
+}
+
+/*
+ * We must supply the ELF program headers explicitly to get just one
+ * PT_LOAD segment, and set the flags explicitly to make segments read-only.
+ */
+PHDRS
+{
+ text PT_LOAD FILEHDR PHDRS FLAGS(5); /* PF_R|PF_X */
+ dynamic PT_DYNAMIC FLAGS(4); /* PF_R */
+ eh_frame_hdr 0x6474e550; /* PT_GNU_EH_FRAME, but ld doesn't match the name */
+}
+
+/*
+ * This controls what symbols we export from the DSO.
+ */
+VERSION
+{
+ LINUX_2.5 {
+ global:
+ __kernel_vsyscall;
+ __kernel_sigreturn;
+ __kernel_rt_sigreturn;
+
+ local: *;
+ };
+}
+
+/* The ELF entry point can be used to set the AT_SYSINFO value. */
+ENTRY(__kernel_vsyscall);
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .32324-linux-2.6.0/include/asm-i386/fixmap.h .32324-linux-2.6.0.updated/include/asm-i386/fixmap.h
--- .32324-linux-2.6.0/include/asm-i386/fixmap.h 2003-09-22 10:09:12.000000000 +1000
+++ .32324-linux-2.6.0.updated/include/asm-i386/fixmap.h 2003-12-26 16:46:49.000000000 +1100
@@ -14,6 +14,19 @@
#define _ASM_FIXMAP_H
#include <linux/config.h>
+
+/* used by vmalloc.c, vsyscall.lds.S.
+ *
+ * Leave one empty page between vmalloc'ed areas and
+ * the start of the fixmap.
+ */
+#ifdef CONFIG_QEMU
+#define __FIXADDR_TOP 0xa7fff000
+#else
+#define __FIXADDR_TOP 0xfffff000
+#endif
+
+#ifndef __ASSEMBLY__
#include <linux/kernel.h>
#include <asm/acpi.h>
#include <asm/apicdef.h>
@@ -94,13 +107,8 @@ extern void __set_fixmap (enum fixed_add
#define clear_fixmap(idx) \
__set_fixmap(idx, 0, __pgprot(0))
-/*
- * used by vmalloc.c.
- *
- * Leave one empty page between vmalloc'ed areas and
- * the start of the fixmap.
- */
-#define FIXADDR_TOP (0xfffff000UL)
+#define FIXADDR_TOP ((unsigned long)__FIXADDR_TOP)
+
#define __FIXADDR_SIZE (__end_of_permanent_fixed_addresses << PAGE_SHIFT)
#define FIXADDR_START (FIXADDR_TOP - __FIXADDR_SIZE)
@@ -145,4 +153,5 @@ static inline unsigned long virt_to_fix(
return __virt_to_fix(vaddr);
}
+#endif /* !__ASSEMBLY__ */
#endif
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .32324-linux-2.6.0/include/asm-i386/page.h .32324-linux-2.6.0.updated/include/asm-i386/page.h
--- .32324-linux-2.6.0/include/asm-i386/page.h 2003-09-22 10:06:42.000000000 +1000
+++ .32324-linux-2.6.0.updated/include/asm-i386/page.h 2003-12-26 16:46:49.000000000 +1100
@@ -10,10 +10,10 @@
#define LARGE_PAGE_SIZE (1UL << PMD_SHIFT)
#ifdef __KERNEL__
-#ifndef __ASSEMBLY__
-
#include <linux/config.h>
+#ifndef __ASSEMBLY__
+
#ifdef CONFIG_X86_USE_3DNOW
#include <asm/mmx.h>
@@ -115,12 +115,19 @@ static __inline__ int get_order(unsigned
#endif /* __ASSEMBLY__ */
#ifdef __ASSEMBLY__
+#ifdef CONFIG_QEMU
+#define __PAGE_OFFSET (0x90000000)
+#else
#define __PAGE_OFFSET (0xC0000000)
+#endif /* QEMU */
+#else
+#ifdef CONFIG_QEMU
+#define __PAGE_OFFSET (0x90000000UL)
#else
#define __PAGE_OFFSET (0xC0000000UL)
+#endif /* QEMU */
#endif
-
#define PAGE_OFFSET ((unsigned long)__PAGE_OFFSET)
#define VMALLOC_RESERVE ((unsigned long)__VMALLOC_RESERVE)
#define MAXMEM (-__PAGE_OFFSET-__VMALLOC_RESERVE)
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .32324-linux-2.6.0/include/asm-i386/param.h .32324-linux-2.6.0.updated/include/asm-i386/param.h
--- .32324-linux-2.6.0/include/asm-i386/param.h 2003-09-21 17:26:06.000000000 +1000
+++ .32324-linux-2.6.0.updated/include/asm-i386/param.h 2003-12-26 16:46:49.000000000 +1100
@@ -2,7 +2,12 @@
#define _ASMi386_PARAM_H
#ifdef __KERNEL__
-# define HZ 1000 /* Internal kernel timer frequency */
+# include <linux/config.h>
+# ifdef CONFIG_QEMU
+# define HZ 100
+# else
+# define HZ 1000 /* Internal kernel timer frequency */
+# endif
# define USER_HZ 100 /* .. some user interfaces are in "ticks" */
# define CLOCKS_PER_SEC (USER_HZ) /* like times() */
#endif

View File

@@ -26,3 +26,11 @@ struct target_pt_regs {
#define ARM_ORIG_r0 uregs[17]
#define ARM_SYSCALL_BASE 0x900000
#define ARM_NR_cacheflush (ARM_SYSCALL_BASE + 0xf0000 + 2)
#if defined(TARGET_WORDS_BIGENDIAN)
#define UNAME_MACHINE "armv4b"
#else
#define UNAME_MACHINE "armv4l"
#endif

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

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

View File

@@ -13,6 +13,16 @@
#include "qemu.h"
#include "disas.h"
/* this flag is uneffective under linux too, should be deleted */
#ifndef MAP_DENYWRITE
#define MAP_DENYWRITE 0
#endif
/* should probably go in elf.h */
#ifndef ELIBBAD
#define ELIBBAD 80
#endif
#ifdef TARGET_I386
#define ELF_START_MMAP 0x80000000
@@ -98,12 +108,88 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i
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;
regs->psr = 0;
regs->pc = infop->entry;
regs->npc = regs->pc + 4;
regs->y = 0;
regs->u_regs[14] = infop->start_stack - 16 * 4;
}
#endif
#ifdef TARGET_PPC
#define ELF_START_MMAP 0x80000000
#define elf_check_arch(x) ( (x) == EM_PPC )
#define ELF_CLASS ELFCLASS32
#ifdef TARGET_WORDS_BIGENDIAN
#define ELF_DATA ELFDATA2MSB
#else
#define ELF_DATA ELFDATA2LSB
#endif
#define ELF_ARCH EM_PPC
/* Note that isn't exactly what regular kernel does
* but this is what the ABI wants and is needed to allow
* execution of PPC BSD programs.
*/
#define ELF_PLAT_INIT(_r) \
do { \
target_ulong *pos = (target_ulong *)bprm->p, tmp = 1; \
_r->gpr[3] = bprm->argc; \
_r->gpr[4] = (unsigned long)++pos; \
for (; tmp != 0; pos++) \
tmp = *pos; \
_r->gpr[5] = (unsigned long)pos; \
} while (0)
/*
* We need to put in some extra aux table entries to tell glibc what
* the cache block size is, so it can use the dcbz instruction safely.
*/
#define AT_DCACHEBSIZE 19
#define AT_ICACHEBSIZE 20
#define AT_UCACHEBSIZE 21
/* A special ignored type value for PPC, for glibc compatibility. */
#define AT_IGNOREPPC 22
/*
* The requirements here are:
* - keep the final alignment of sp (sp & 0xf)
* - make sure the 32-bit value at the first 16 byte aligned position of
* AUXV is greater than 16 for glibc compatibility.
* AT_IGNOREPPC is used for that.
* - for compatibility with glibc ARCH_DLINFO must always be defined on PPC,
* even if DLINFO_ARCH_ITEMS goes to zero or is undefined.
*/
#define DLINFO_ARCH_ITEMS 3
#define ARCH_DLINFO \
do { \
sp -= DLINFO_ARCH_ITEMS * 2; \
NEW_AUX_ENT(0, AT_DCACHEBSIZE, 0x20); \
NEW_AUX_ENT(1, AT_ICACHEBSIZE, 0x20); \
NEW_AUX_ENT(2, AT_UCACHEBSIZE, 0); \
/* \
* Now handle glibc compatibility. \
*/ \
sp -= 2*2; \
NEW_AUX_ENT(0, AT_IGNOREPPC, AT_IGNOREPPC); \
NEW_AUX_ENT(1, AT_IGNOREPPC, AT_IGNOREPPC); \
} while (0)
static inline void init_thread(struct target_pt_regs *_regs, struct image_info *infop)
{
_regs->msr = 1 << MSR_PR; /* Set user mode */
_regs->gpr[1] = infop->start_stack;
_regs->nip = infop->entry;
}
#define USE_ELF_CORE_DUMP
#define ELF_EXEC_PAGESIZE 4096
#endif
#include "elf.h"
/*
@@ -185,21 +271,13 @@ struct exec
#define INTERPRETER_AOUT 1
#define INTERPRETER_ELF 2
#define DLINFO_ITEMS 12
#define put_user(x,ptr) (void)(*(ptr) = (typeof(*ptr))(x))
#define get_user(ptr) (typeof(*ptr))(*(ptr))
#define DLINFO_ITEMS 11
static inline void memcpy_fromfs(void * to, const void * from, unsigned long n)
{
memcpy(to, from, n);
}
static inline void memcpy_tofs(void * to, const void * from, unsigned long n)
{
memcpy(to, from, n);
}
extern unsigned long x86_stack_size;
static int load_aout_interp(void * exptr, int interp_fd);
@@ -264,7 +342,7 @@ static void * get_free_page(void)
/* User-space version of kernel get_free_page. Returns a page-aligned
* page-sized chunk of memory.
*/
retval = (void *)target_mmap(0, host_page_size, PROT_READ|PROT_WRITE,
retval = (void *)target_mmap(0, qemu_host_page_size, PROT_READ|PROT_WRITE,
MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
if((long)retval == -1) {
@@ -278,7 +356,7 @@ static void * get_free_page(void)
static void free_page(void * pageaddr)
{
target_munmap((unsigned long)pageaddr, host_page_size);
target_munmap((unsigned long)pageaddr, qemu_host_page_size);
}
/*
@@ -297,11 +375,13 @@ static unsigned long copy_strings(int argc,char ** argv,unsigned long *page,
return 0; /* bullet-proofing */
}
while (argc-- > 0) {
if (!(tmp1 = tmp = get_user(argv+argc))) {
tmp = argv[argc];
if (!tmp) {
fprintf(stderr, "VFS: argc is wrong");
exit(-1);
}
while (get_user(tmp++));
tmp1 = tmp;
while (*tmp++);
len = tmp - tmp1;
if (p < len) { /* this shouldn't happen - 128kB */
return 0;
@@ -310,14 +390,16 @@ static unsigned long copy_strings(int argc,char ** argv,unsigned long *page,
--p; --tmp; --len;
if (--offset < 0) {
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;
pag = (char *) page[p/TARGET_PAGE_SIZE];
if (!pag) {
pag = (char *)get_free_page();
page[p/TARGET_PAGE_SIZE] = (unsigned long)pag;
if (!pag)
return 0;
}
}
if (len == 0 || offset == 0) {
*(pag + offset) = get_user(tmp);
*(pag + offset) = *tmp;
}
else {
int bytes_to_copy = (len > offset) ? offset : len;
@@ -430,7 +512,7 @@ unsigned long setup_arg_pages(unsigned long p, struct linux_binprm * bprm,
if (size < MAX_ARG_PAGES*TARGET_PAGE_SIZE)
size = MAX_ARG_PAGES*TARGET_PAGE_SIZE;
error = target_mmap(0,
size + host_page_size,
size + qemu_host_page_size,
PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS,
-1, 0);
@@ -439,7 +521,7 @@ unsigned long setup_arg_pages(unsigned long p, struct linux_binprm * bprm,
exit(-1);
}
/* we reserve one extra page at the top of the stack as guard */
target_mprotect(error + size, host_page_size, PROT_NONE);
target_mprotect(error + size, qemu_host_page_size, PROT_NONE);
stack_base = error + size - MAX_ARG_PAGES*TARGET_PAGE_SIZE;
p += stack_base;
@@ -490,10 +572,10 @@ static void padzero(unsigned long elf_bss)
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) {
if (qemu_real_host_page_size < qemu_host_page_size) {
unsigned long end_addr, end_addr1;
end_addr1 = (elf_bss + real_host_page_size - 1) &
~(real_host_page_size - 1);
end_addr1 = (elf_bss + qemu_real_host_page_size - 1) &
~(qemu_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,
@@ -502,9 +584,9 @@ static void padzero(unsigned long elf_bss)
}
}
nbyte = elf_bss & (host_page_size-1);
nbyte = elf_bss & (qemu_host_page_size-1);
if (nbyte) {
nbyte = host_page_size - nbyte;
nbyte = qemu_host_page_size - nbyte;
fpnt = (char *) elf_bss;
do {
*fpnt++ = 0;
@@ -519,53 +601,77 @@ static unsigned int * create_elf_tables(char *p, int argc, int envc,
unsigned long interp_load_addr, int ibcs,
struct image_info *info)
{
target_ulong *argv, *envp, *dlinfo;
target_ulong *sp;
target_ulong *argv, *envp;
target_ulong *sp, *csp;
int v;
/*
* Force 16 byte alignment here for generality.
*/
/*
* Force 16 byte _final_ alignment here for generality.
*/
sp = (unsigned int *) (~15UL & (unsigned long) p);
sp -= DLINFO_ITEMS*2;
dlinfo = sp;
csp = sp;
csp -= (DLINFO_ITEMS + 1) * 2;
#ifdef DLINFO_ARCH_ITEMS
csp -= DLINFO_ARCH_ITEMS*2;
#endif
csp -= envc+1;
csp -= argc+1;
csp -= (!ibcs ? 3 : 1); /* argc itself */
if ((unsigned long)csp & 15UL)
sp -= ((unsigned long)csp & 15UL) / sizeof(*sp);
#define NEW_AUX_ENT(nr, id, val) \
put_user (id, sp + (nr * 2)); \
put_user (val, sp + (nr * 2 + 1))
sp -= 2;
NEW_AUX_ENT (0, AT_NULL, 0);
sp -= DLINFO_ITEMS*2;
NEW_AUX_ENT( 0, AT_PHDR, (target_ulong)(load_addr + exec->e_phoff));
NEW_AUX_ENT( 1, AT_PHENT, (target_ulong)(sizeof (struct elf_phdr)));
NEW_AUX_ENT( 2, AT_PHNUM, (target_ulong)(exec->e_phnum));
NEW_AUX_ENT( 3, AT_PAGESZ, (target_ulong)(TARGET_PAGE_SIZE));
NEW_AUX_ENT( 4, AT_BASE, (target_ulong)(interp_load_addr));
NEW_AUX_ENT( 5, AT_FLAGS, (target_ulong)0);
NEW_AUX_ENT( 6, AT_ENTRY, load_bias + exec->e_entry);
NEW_AUX_ENT( 7, AT_UID, (target_ulong) getuid());
NEW_AUX_ENT( 8, AT_EUID, (target_ulong) geteuid());
NEW_AUX_ENT( 9, AT_GID, (target_ulong) getgid());
NEW_AUX_ENT(11, AT_EGID, (target_ulong) getegid());
#ifdef ARCH_DLINFO
/*
* ARCH_DLINFO must come last so platform specific code can enforce
* special alignment requirements on the AUXV if necessary (eg. PPC).
*/
ARCH_DLINFO;
#endif
#undef NEW_AUX_ENT
sp -= envc+1;
envp = sp;
sp -= argc+1;
argv = sp;
if (!ibcs) {
put_user(tswapl((target_ulong)envp),--sp);
put_user(tswapl((target_ulong)argv),--sp);
put_user((target_ulong)envp,--sp);
put_user((target_ulong)argv,--sp);
}
#define NEW_AUX_ENT(id, val) \
put_user (tswapl(id), dlinfo++); \
put_user (tswapl(val), dlinfo++)
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);
put_user(argc,--sp);
info->arg_start = (unsigned int)((unsigned long)p & 0xffffffff);
while (argc-->0) {
put_user(tswapl((target_ulong)p),argv++);
while (get_user(p++)) /* nothing */ ;
put_user((target_ulong)p,argv++);
do {
get_user(v, p);
p++;
} while (v != 0);
}
put_user(0,argv);
info->arg_end = info->env_start = (unsigned int)((unsigned long)p & 0xffffffff);
while (envc-->0) {
put_user(tswapl((target_ulong)p),envp++);
while (get_user(p++)) /* nothing */ ;
put_user((target_ulong)p,envp++);
do {
get_user(v, p);
p++;
} while (v != 0);
}
put_user(0,envp);
info->env_end = (unsigned int)((unsigned long)p & 0xffffffff);
@@ -715,7 +821,7 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex,
* bss page.
*/
padzero(elf_bss);
elf_bss = TARGET_ELF_PAGESTART(elf_bss + host_page_size - 1); /* What we have mapped so far */
elf_bss = TARGET_ELF_PAGESTART(elf_bss + qemu_host_page_size - 1); /* What we have mapped so far */
/* Map the last of the bss segment */
if (last_bss > elf_bss) {
@@ -971,7 +1077,7 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r
char * passed_p;
if (interpreter_type == INTERPRETER_AOUT) {
sprintf(passed_fileno, "%d", bprm->fd);
snprintf(passed_fileno, sizeof(passed_fileno), "%d", bprm->fd);
passed_p = passed_fileno;
if (elf_interpreter) {
@@ -1156,7 +1262,7 @@ 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 = target_mmap(0, host_page_size, PROT_READ | PROT_EXEC,
mapped_addr = target_mmap(0, qemu_host_page_size, PROT_READ | PROT_EXEC,
MAP_FIXED | MAP_PRIVATE, -1, 0);
}
@@ -1189,14 +1295,9 @@ int elf_exec(const char * filename, char ** argv, char ** envp,
for (i=0 ; i<MAX_ARG_PAGES ; i++) /* clear page-table */
bprm.page[i] = 0;
retval = open(filename, O_RDONLY);
if (retval == -1) {
perror(filename);
exit(-1);
/* return retval; */
}
else {
bprm.fd = retval;
}
if (retval < 0)
return retval;
bprm.fd = retval;
bprm.filename = (char *)filename;
bprm.sh_bang = 0;
bprm.loader = 0;

View File

@@ -218,3 +218,4 @@ union target_semun {
unsigned int __pad; /* really void* */
};
#define UNAME_MACHINE "i686"

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

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

View File

@@ -28,9 +28,14 @@
#define DEBUG_LOGFILE "/tmp/qemu.log"
#ifdef __APPLE__
#include <crt_externs.h>
# define environ (*_NSGetEnviron())
#endif
static const char *interp_prefix = CONFIG_QEMU_PREFIX;
#ifdef __i386__
#if defined(__i386__) && !defined(CONFIG_STATIC)
/* Force usage of an ELF interpreter even if it is an ELF shared
object ! */
const char interp[] __attribute__((section(".interp"))) = "/lib/ld-linux.so.2";
@@ -38,7 +43,9 @@ const char interp[] __attribute__((section(".interp"))) = "/lib/ld-linux.so.2";
/* 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)
#if (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 3)) && !defined(CONFIG_STATIC)
long __preinit_array_start[0];
long __preinit_array_end[0];
long __init_array_start[0];
long __init_array_end[0];
long __fini_array_start[0];
@@ -59,48 +66,88 @@ void gemu_log(const char *fmt, ...)
va_end(ap);
}
#ifdef TARGET_I386
/***********************************************************/
/* CPUX86 core interface */
void cpu_x86_outb(CPUX86State *env, int addr, int val)
void cpu_outb(CPUState *env, int addr, int val)
{
fprintf(stderr, "outb: port=0x%04x, data=%02x\n", addr, val);
}
void cpu_x86_outw(CPUX86State *env, int addr, int val)
void cpu_outw(CPUState *env, int addr, int val)
{
fprintf(stderr, "outw: port=0x%04x, data=%04x\n", addr, val);
}
void cpu_x86_outl(CPUX86State *env, int addr, int val)
void cpu_outl(CPUState *env, int addr, int val)
{
fprintf(stderr, "outl: port=0x%04x, data=%08x\n", addr, val);
}
int cpu_x86_inb(CPUX86State *env, int addr)
int cpu_inb(CPUState *env, int addr)
{
fprintf(stderr, "inb: port=0x%04x\n", addr);
return 0;
}
int cpu_x86_inw(CPUX86State *env, int addr)
int cpu_inw(CPUState *env, int addr)
{
fprintf(stderr, "inw: port=0x%04x\n", addr);
return 0;
}
int cpu_x86_inl(CPUX86State *env, int addr)
int cpu_inl(CPUState *env, int addr)
{
fprintf(stderr, "inl: port=0x%04x\n", addr);
return 0;
}
int cpu_x86_get_pic_interrupt(CPUX86State *env)
int cpu_get_pic_interrupt(CPUState *env)
{
return -1;
}
/* timers for rdtsc */
#if defined(__i386__)
int64_t cpu_get_real_ticks(void)
{
int64_t val;
asm volatile ("rdtsc" : "=A" (val));
return val;
}
#elif defined(__x86_64__)
int64_t cpu_get_real_ticks(void)
{
uint32_t low,high;
int64_t val;
asm volatile("rdtsc" : "=a" (low), "=d" (high));
val = high;
val <<= 32;
val |= low;
return val;
}
#else
static uint64_t emu_time;
int64_t cpu_get_real_ticks(void)
{
return emu_time++;
}
#endif
#ifdef TARGET_I386
/***********************************************************/
/* CPUX86 core interface */
uint64_t cpu_get_tsc(CPUX86State *env)
{
return cpu_get_real_ticks();
}
static void write_dt(void *ptr, unsigned long addr, unsigned long limit,
int flags)
{
@@ -244,6 +291,27 @@ void cpu_loop(CPUX86State *env)
#ifdef TARGET_ARM
/* XXX: find a better solution */
extern void tb_invalidate_page_range(target_ulong start, target_ulong end);
static void arm_cache_flush(target_ulong start, target_ulong last)
{
target_ulong addr, last1;
if (last < start)
return;
addr = start;
for(;;) {
last1 = ((addr + TARGET_PAGE_SIZE) & TARGET_PAGE_MASK) - 1;
if (last1 > last)
last1 = last;
tb_invalidate_page_range(addr, last1 + 1);
if (last1 == last)
break;
addr = last1 + 1;
}
}
void cpu_loop(CPUARMState *env)
{
int trapnr;
@@ -254,18 +322,34 @@ void cpu_loop(CPUARMState *env)
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);
{
TaskState *ts = env->opaque;
uint32_t opcode;
/* we handle the FPU emulation here, as Linux */
/* we get the opcode */
opcode = ldl_raw((uint8_t *)env->regs[15]);
if (EmulateAll(opcode, &ts->fpa, env->regs) == 0) {
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);
} else {
/* increment PC */
env->regs[15] += 4;
}
}
break;
case EXCP_SWI:
{
/* system call */
insn = ldl((void *)(env->regs[15] - 4));
n = insn & 0xffffff;
if (n >= ARM_SYSCALL_BASE) {
if (n == ARM_NR_cacheflush) {
arm_cache_flush(env->regs[0], env->regs[1]);
} else if (n >= ARM_SYSCALL_BASE) {
/* linux syscall */
n -= ARM_SYSCALL_BASE;
env->regs[0] = do_syscall(env,
@@ -288,7 +372,7 @@ void cpu_loop(CPUARMState *env)
error:
fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n",
trapnr);
cpu_arm_dump_state(env, stderr, 0);
cpu_dump_state(env, stderr, fprintf, 0);
abort();
}
process_pending_signals(env);
@@ -299,35 +383,522 @@ void cpu_loop(CPUARMState *env)
#ifdef TARGET_SPARC
//#define DEBUG_WIN
/* WARNING: dealing with register windows _is_ complicated */
static inline int get_reg_index(CPUSPARCState *env, int cwp, int index)
{
index = (index + cwp * 16) & (16 * NWINDOWS - 1);
/* wrap handling : if cwp is on the last window, then we use the
registers 'after' the end */
if (index < 8 && env->cwp == (NWINDOWS - 1))
index += (16 * NWINDOWS);
return index;
}
static inline void save_window_offset(CPUSPARCState *env, int offset)
{
unsigned int new_wim, i, cwp1;
uint32_t *sp_ptr;
new_wim = ((env->wim >> 1) | (env->wim << (NWINDOWS - 1))) &
((1LL << NWINDOWS) - 1);
/* save the window */
cwp1 = (env->cwp + offset) & (NWINDOWS - 1);
sp_ptr = (uint32_t *)(env->regbase[get_reg_index(env, cwp1, 6)]);
#if defined(DEBUG_WIN)
printf("win_overflow: sp_ptr=0x%x save_cwp=%d\n",
(int)sp_ptr, cwp1);
#endif
for(i = 0; i < 16; i++)
stl_raw(sp_ptr + i, env->regbase[get_reg_index(env, cwp1, 8 + i)]);
env->wim = new_wim;
}
static void save_window(CPUSPARCState *env)
{
save_window_offset(env, 2);
}
static void restore_window(CPUSPARCState *env)
{
unsigned int new_wim, i, cwp1;
uint32_t *sp_ptr;
new_wim = ((env->wim << 1) | (env->wim >> (NWINDOWS - 1))) &
((1LL << NWINDOWS) - 1);
/* restore the invalid window */
cwp1 = (env->cwp + 1) & (NWINDOWS - 1);
sp_ptr = (uint32_t *)(env->regbase[get_reg_index(env, cwp1, 6)]);
#if defined(DEBUG_WIN)
printf("win_underflow: sp_ptr=0x%x load_cwp=%d\n",
(int)sp_ptr, cwp1);
#endif
for(i = 0; i < 16; i++)
env->regbase[get_reg_index(env, cwp1, 8 + i)] = ldl_raw(sp_ptr + i);
env->wim = new_wim;
}
static void flush_windows(CPUSPARCState *env)
{
int offset, cwp1;
#if defined(DEBUG_WIN)
printf("flush_windows:\n");
#endif
offset = 2;
for(;;) {
/* if restore would invoke restore_window(), then we can stop */
cwp1 = (env->cwp + 1) & (NWINDOWS - 1);
if (env->wim & (1 << cwp1))
break;
#if defined(DEBUG_WIN)
printf("offset=%d: ", offset);
#endif
save_window_offset(env, offset);
offset++;
}
}
void cpu_loop (CPUSPARCState *env)
{
int trapnr;
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);
}
int trapnr, ret;
while (1) {
trapnr = cpu_sparc_exec (env);
switch (trapnr) {
case 0x88:
case 0x90:
ret = do_syscall (env, env->gregs[1],
env->regwptr[0], env->regwptr[1],
env->regwptr[2], env->regwptr[3],
env->regwptr[4], env->regwptr[5]);
if ((unsigned int)ret >= (unsigned int)(-515)) {
env->psr |= PSR_CARRY;
ret = -ret;
} else {
env->psr &= ~PSR_CARRY;
}
env->regwptr[0] = ret;
/* next instruction */
env->pc = env->npc;
env->npc = env->npc + 4;
break;
case 0x83: /* flush windows */
// flush_windows(env);
/* next instruction */
env->pc = env->npc;
env->npc = env->npc + 4;
break;
case TT_WIN_OVF: /* window overflow */
save_window(env);
break;
case TT_WIN_UNF: /* window underflow */
restore_window(env);
break;
default:
printf ("Unhandled trap: 0x%x\n", trapnr);
cpu_dump_state(env, stderr, fprintf, 0);
exit (1);
}
process_pending_signals (env);
}
}
#endif
#ifdef TARGET_PPC
static inline uint64_t cpu_ppc_get_tb (CPUState *env)
{
/* TO FIX */
return 0;
}
uint32_t cpu_ppc_load_tbl (CPUState *env)
{
return cpu_ppc_get_tb(env) & 0xFFFFFFFF;
}
uint32_t cpu_ppc_load_tbu (CPUState *env)
{
return cpu_ppc_get_tb(env) >> 32;
}
static void cpu_ppc_store_tb (CPUState *env, uint64_t value)
{
/* TO FIX */
}
void cpu_ppc_store_tbu (CPUState *env, uint32_t value)
{
cpu_ppc_store_tb(env, ((uint64_t)value << 32) | cpu_ppc_load_tbl(env));
}
void cpu_ppc_store_tbl (CPUState *env, uint32_t value)
{
cpu_ppc_store_tb(env, ((uint64_t)cpu_ppc_load_tbl(env) << 32) | value);
}
uint32_t cpu_ppc_load_decr (CPUState *env)
{
/* TO FIX */
return -1;
}
void cpu_ppc_store_decr (CPUState *env, uint32_t value)
{
/* TO FIX */
}
void cpu_loop(CPUPPCState *env)
{
target_siginfo_t info;
int trapnr;
uint32_t ret;
for(;;) {
trapnr = cpu_ppc_exec(env);
if (trapnr != EXCP_SYSCALL_USER && trapnr != EXCP_BRANCH &&
trapnr != EXCP_TRACE) {
if (loglevel > 0) {
cpu_dump_state(env, logfile, fprintf, 0);
}
}
switch(trapnr) {
case EXCP_NONE:
break;
case EXCP_SYSCALL_USER:
/* system call */
/* WARNING:
* PPC ABI uses overflow flag in cr0 to signal an error
* in syscalls.
*/
#if 0
printf("syscall %d 0x%08x 0x%08x 0x%08x 0x%08x\n", env->gpr[0],
env->gpr[3], env->gpr[4], env->gpr[5], env->gpr[6]);
#endif
env->crf[0] &= ~0x1;
ret = do_syscall(env, env->gpr[0], env->gpr[3], env->gpr[4],
env->gpr[5], env->gpr[6], env->gpr[7],
env->gpr[8]);
if (ret > (uint32_t)(-515)) {
env->crf[0] |= 0x1;
ret = -ret;
}
env->gpr[3] = ret;
#if 0
printf("syscall returned 0x%08x (%d)\n", ret, ret);
#endif
break;
case EXCP_RESET:
/* Should not happen ! */
fprintf(stderr, "RESET asked... Stop emulation\n");
if (loglevel)
fprintf(logfile, "RESET asked... Stop emulation\n");
abort();
case EXCP_MACHINE_CHECK:
fprintf(stderr, "Machine check exeption... Stop emulation\n");
if (loglevel)
fprintf(logfile, "RESET asked... Stop emulation\n");
info.si_signo = TARGET_SIGBUS;
info.si_errno = 0;
info.si_code = TARGET_BUS_OBJERR;
info._sifields._sigfault._addr = env->nip - 4;
queue_signal(info.si_signo, &info);
case EXCP_DSI:
fprintf(stderr, "Invalid data memory access: 0x%08x\n", env->spr[DAR]);
if (loglevel) {
fprintf(logfile, "Invalid data memory access: 0x%08x\n",
env->spr[DAR]);
}
switch (env->error_code & 0xF) {
case EXCP_DSI_TRANSLATE:
info.si_signo = TARGET_SIGSEGV;
info.si_errno = 0;
info.si_code = TARGET_SEGV_MAPERR;
break;
case EXCP_DSI_NOTSUP:
case EXCP_DSI_EXTERNAL:
info.si_signo = TARGET_SIGILL;
info.si_errno = 0;
info.si_code = TARGET_ILL_ILLADR;
break;
case EXCP_DSI_PROT:
info.si_signo = TARGET_SIGSEGV;
info.si_errno = 0;
info.si_code = TARGET_SEGV_ACCERR;
break;
case EXCP_DSI_DABR:
info.si_signo = TARGET_SIGTRAP;
info.si_errno = 0;
info.si_code = TARGET_TRAP_BRKPT;
break;
default:
/* Let's send a regular segfault... */
fprintf(stderr, "Invalid segfault errno (%02x)\n",
env->error_code);
if (loglevel) {
fprintf(logfile, "Invalid segfault errno (%02x)\n",
env->error_code);
}
info.si_signo = TARGET_SIGSEGV;
info.si_errno = 0;
info.si_code = TARGET_SEGV_MAPERR;
break;
}
info._sifields._sigfault._addr = env->nip;
queue_signal(info.si_signo, &info);
break;
case EXCP_ISI:
fprintf(stderr, "Invalid instruction fetch\n");
if (loglevel)
fprintf(logfile, "Invalid instruction fetch\n");
switch (env->error_code) {
case EXCP_ISI_TRANSLATE:
info.si_signo = TARGET_SIGSEGV;
info.si_errno = 0;
info.si_code = TARGET_SEGV_MAPERR;
break;
case EXCP_ISI_GUARD:
info.si_signo = TARGET_SIGILL;
info.si_errno = 0;
info.si_code = TARGET_ILL_ILLADR;
break;
case EXCP_ISI_NOEXEC:
case EXCP_ISI_PROT:
info.si_signo = TARGET_SIGSEGV;
info.si_errno = 0;
info.si_code = TARGET_SEGV_ACCERR;
break;
default:
/* Let's send a regular segfault... */
fprintf(stderr, "Invalid segfault errno (%02x)\n",
env->error_code);
if (loglevel) {
fprintf(logfile, "Invalid segfault errno (%02x)\n",
env->error_code);
}
info.si_signo = TARGET_SIGSEGV;
info.si_errno = 0;
info.si_code = TARGET_SEGV_MAPERR;
break;
}
info._sifields._sigfault._addr = env->nip - 4;
queue_signal(info.si_signo, &info);
break;
case EXCP_EXTERNAL:
/* Should not happen ! */
fprintf(stderr, "External interruption... Stop emulation\n");
if (loglevel)
fprintf(logfile, "External interruption... Stop emulation\n");
abort();
case EXCP_ALIGN:
fprintf(stderr, "Invalid unaligned memory access\n");
if (loglevel)
fprintf(logfile, "Invalid unaligned memory access\n");
info.si_signo = TARGET_SIGBUS;
info.si_errno = 0;
info.si_code = TARGET_BUS_ADRALN;
info._sifields._sigfault._addr = env->nip - 4;
queue_signal(info.si_signo, &info);
break;
case EXCP_PROGRAM:
switch (env->error_code & ~0xF) {
case EXCP_FP:
fprintf(stderr, "Program exception\n");
if (loglevel)
fprintf(logfile, "Program exception\n");
/* Set FX */
env->fpscr[7] |= 0x8;
/* Finally, update FEX */
if ((((env->fpscr[7] & 0x3) << 3) | (env->fpscr[6] >> 1)) &
((env->fpscr[1] << 1) | (env->fpscr[0] >> 3)))
env->fpscr[7] |= 0x4;
info.si_signo = TARGET_SIGFPE;
info.si_errno = 0;
switch (env->error_code & 0xF) {
case EXCP_FP_OX:
info.si_code = TARGET_FPE_FLTOVF;
break;
case EXCP_FP_UX:
info.si_code = TARGET_FPE_FLTUND;
break;
case EXCP_FP_ZX:
case EXCP_FP_VXZDZ:
info.si_code = TARGET_FPE_FLTDIV;
break;
case EXCP_FP_XX:
info.si_code = TARGET_FPE_FLTRES;
break;
case EXCP_FP_VXSOFT:
info.si_code = TARGET_FPE_FLTINV;
break;
case EXCP_FP_VXNAN:
case EXCP_FP_VXISI:
case EXCP_FP_VXIDI:
case EXCP_FP_VXIMZ:
case EXCP_FP_VXVC:
case EXCP_FP_VXSQRT:
case EXCP_FP_VXCVI:
info.si_code = TARGET_FPE_FLTSUB;
break;
default:
fprintf(stderr, "Unknown floating point exception "
"(%02x)\n", env->error_code);
if (loglevel) {
fprintf(logfile, "Unknown floating point exception "
"(%02x)\n", env->error_code & 0xF);
}
}
break;
case EXCP_INVAL:
fprintf(stderr, "Invalid instruction\n");
if (loglevel)
fprintf(logfile, "Invalid instruction\n");
info.si_signo = TARGET_SIGILL;
info.si_errno = 0;
switch (env->error_code & 0xF) {
case EXCP_INVAL_INVAL:
info.si_code = TARGET_ILL_ILLOPC;
break;
case EXCP_INVAL_LSWX:
info.si_code = TARGET_ILL_ILLOPN;
break;
case EXCP_INVAL_SPR:
info.si_code = TARGET_ILL_PRVREG;
break;
case EXCP_INVAL_FP:
info.si_code = TARGET_ILL_COPROC;
break;
default:
fprintf(stderr, "Unknown invalid operation (%02x)\n",
env->error_code & 0xF);
if (loglevel) {
fprintf(logfile, "Unknown invalid operation (%02x)\n",
env->error_code & 0xF);
}
info.si_code = TARGET_ILL_ILLADR;
break;
}
break;
case EXCP_PRIV:
fprintf(stderr, "Privilege violation\n");
if (loglevel)
fprintf(logfile, "Privilege violation\n");
info.si_signo = TARGET_SIGILL;
info.si_errno = 0;
switch (env->error_code & 0xF) {
case EXCP_PRIV_OPC:
info.si_code = TARGET_ILL_PRVOPC;
break;
case EXCP_PRIV_REG:
info.si_code = TARGET_ILL_PRVREG;
break;
default:
fprintf(stderr, "Unknown privilege violation (%02x)\n",
env->error_code & 0xF);
info.si_code = TARGET_ILL_PRVOPC;
break;
}
break;
case EXCP_TRAP:
fprintf(stderr, "Tried to call a TRAP\n");
if (loglevel)
fprintf(logfile, "Tried to call a TRAP\n");
abort();
default:
/* Should not happen ! */
fprintf(stderr, "Unknown program exception (%02x)\n",
env->error_code);
if (loglevel) {
fprintf(logfile, "Unknwon program exception (%02x)\n",
env->error_code);
}
abort();
}
info._sifields._sigfault._addr = env->nip - 4;
queue_signal(info.si_signo, &info);
break;
case EXCP_NO_FP:
fprintf(stderr, "No floating point allowed\n");
if (loglevel)
fprintf(logfile, "No floating point allowed\n");
info.si_signo = TARGET_SIGILL;
info.si_errno = 0;
info.si_code = TARGET_ILL_COPROC;
info._sifields._sigfault._addr = env->nip - 4;
queue_signal(info.si_signo, &info);
break;
case EXCP_DECR:
/* Should not happen ! */
fprintf(stderr, "Decrementer exception\n");
if (loglevel)
fprintf(logfile, "Decrementer exception\n");
abort();
case EXCP_RESA: /* Implementation specific */
/* Should not happen ! */
fprintf(stderr, "RESA exception should never happen !\n");
if (loglevel)
fprintf(logfile, "RESA exception should never happen !\n");
abort();
case EXCP_RESB: /* Implementation specific */
/* Should not happen ! */
fprintf(stderr, "RESB exception should never happen !\n");
if (loglevel)
fprintf(logfile, "RESB exception should never happen !\n");
abort();
case EXCP_TRACE:
/* Do nothing: we use this to trace execution */
break;
case EXCP_FP_ASSIST:
/* Should not happen ! */
fprintf(stderr, "Floating point assist exception\n");
if (loglevel)
fprintf(logfile, "Floating point assist exception\n");
abort();
case EXCP_MTMSR:
/* We reloaded the msr, just go on */
if (msr_pr == 0) {
fprintf(stderr, "Tried to go into supervisor mode !\n");
if (loglevel)
fprintf(logfile, "Tried to go into supervisor mode !\n");
abort();
}
break;
case EXCP_BRANCH:
/* We stopped because of a jump... */
break;
case EXCP_RFI:
/* Should not occur: we always are in user mode */
fprintf(stderr, "Return from interrupt ?\n");
if (loglevel)
fprintf(logfile, "Return from interrupt ?\n");
abort();
case EXCP_INTERRUPT:
/* Don't know why this should ever happen... */
break;
case EXCP_DEBUG:
break;
default:
fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n",
trapnr);
if (loglevel) {
fprintf(logfile, "qemu: unhandled CPU exception 0x%02x - "
"0x%02x - aborting\n", trapnr, env->error_code);
}
abort();
}
process_pending_signals(env);
}
}
#endif
void usage(void)
{
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"
printf("qemu-" TARGET_ARCH " version " QEMU_VERSION ", Copyright (c) 2003-2004 Fabrice Bellard\n"
"usage: qemu-" TARGET_ARCH " [-h] [-d opts] [-L path] [-s size] program [arguments...]\n"
"Linux CPU emulator (compiled for %s emulation)\n"
"\n"
"-h print this help\n"
@@ -335,7 +906,10 @@ void usage(void)
"-s size set the stack size in bytes (default=%ld)\n"
"\n"
"debug options:\n"
"-d activate log (logfile=%s)\n"
#ifdef USE_CODE_COPY
"-no-code-copy disable code copy acceleration\n"
#endif
"-d options activate log (logfile=%s)\n"
"-p pagesize set the host page size to 'pagesize'\n",
TARGET_ARCH,
interp_prefix,
@@ -380,7 +954,22 @@ int main(int argc, char **argv)
if (!strcmp(r, "-")) {
break;
} else if (!strcmp(r, "d")) {
cpu_set_log(CPU_LOG_ALL);
int mask;
CPULogItem *item;
if (optind >= argc)
break;
r = argv[optind++];
mask = cpu_str_to_log_mask(r);
if (!mask) {
printf("Log items (comma separated):\n");
for(item = cpu_log_items; item->mask != 0; item++) {
printf("%-10s %s\n", item->name, item->help);
}
exit(1);
}
cpu_set_log(mask);
} else if (!strcmp(r, "s")) {
r = argv[optind++];
x86_stack_size = strtol(r, (char **)&r, 0);
@@ -393,13 +982,19 @@ int main(int argc, char **argv)
} 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) {
qemu_host_page_size = atoi(argv[optind++]);
if (qemu_host_page_size == 0 ||
(qemu_host_page_size & (qemu_host_page_size - 1)) != 0) {
fprintf(stderr, "page size must be a power of two\n");
exit(1);
}
} else {
} else
#ifdef USE_CODE_COPY
if (!strcmp(r, "no-code-copy")) {
code_copy_enabled = 0;
} else
#endif
{
usage();
}
}
@@ -416,8 +1011,8 @@ 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 */
/* NOTE: we need to init the CPU at this stage to get
qemu_host_page_size */
env = cpu_init();
if (elf_exec(filename, argv+optind, environ, regs, info) != 0) {
@@ -453,7 +1048,11 @@ int main(int argc, char **argv)
cpu_x86_set_cpl(env, 3);
env->cr[0] = CR0_PG_MASK | CR0_WP_MASK | CR0_PE_MASK;
env->hflags |= HF_PE_MASK;
/* flags setup : we activate the IRQs by default as in user mode */
env->eflags |= IF_MASK;
/* linux register setup */
env->regs[R_EAX] = regs->eax;
env->regs[R_EBX] = regs->ebx;
@@ -515,8 +1114,28 @@ int main(int argc, char **argv)
env->cpsr = regs->uregs[16];
}
#elif defined(TARGET_SPARC)
env->pc = regs->u_regs[0];
env->regwptr[6] = regs->u_regs[1]-0x40;
{
int i;
env->pc = regs->pc;
env->npc = regs->npc;
env->y = regs->y;
for(i = 0; i < 8; i++)
env->gregs[i] = regs->u_regs[i];
for(i = 0; i < 8; i++)
env->regwptr[i] = regs->u_regs[i + 8];
}
#elif defined(TARGET_PPC)
{
int i;
for (i = 0; i < 32; i++) {
if (i != 12 && i != 6)
env->msr[i] = (regs->msr >> i) & 1;
}
env->nip = regs->nip;
for(i = 0; i < 32; i++) {
env->gpr[i] = regs->gpr[i];
}
}
#else
#error unsupported target CPU
#endif

View File

@@ -53,7 +53,7 @@ int target_mprotect(unsigned long start, unsigned long len, int prot)
if (len == 0)
return 0;
host_start = start & host_page_mask;
host_start = start & qemu_host_page_mask;
host_end = HOST_PAGE_ALIGN(end);
if (start > host_start) {
/* handle host page containing start */
@@ -61,27 +61,27 @@ int target_mprotect(unsigned long start, unsigned long len, int prot)
for(addr = host_start; addr < start; addr += TARGET_PAGE_SIZE) {
prot1 |= page_get_flags(addr);
}
if (host_end == host_start + host_page_size) {
if (host_end == host_start + qemu_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);
ret = mprotect((void *)host_start, qemu_host_page_size, prot1 & PAGE_BITS);
if (ret != 0)
return ret;
host_start += host_page_size;
host_start += qemu_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,
ret = mprotect((void *)(host_end - qemu_host_page_size), qemu_host_page_size,
prot1 & PAGE_BITS);
if (ret != 0)
return ret;
host_end -= host_page_size;
host_end -= qemu_host_page_size;
}
/* handle the pages in the middle */
@@ -102,7 +102,7 @@ int mmap_frag(unsigned long host_start,
unsigned long host_end, ret, addr;
int prot1, prot_new;
host_end = host_start + host_page_size;
host_end = host_start + qemu_host_page_size;
/* get the protection of the target pages outside the mapping */
prot1 = 0;
@@ -113,7 +113,7 @@ int mmap_frag(unsigned long host_start,
if (prot1 == 0) {
/* no page was there, so we allocate one */
ret = (long)mmap((void *)host_start, host_page_size, prot,
ret = (long)mmap((void *)host_start, qemu_host_page_size, prot,
flags | MAP_ANONYMOUS, -1, 0);
if (ret == -1)
return ret;
@@ -130,18 +130,18 @@ int mmap_frag(unsigned long host_start,
/* adjust protection to be able to read */
if (!(prot1 & PROT_WRITE))
mprotect((void *)host_start, host_page_size, prot1 | PROT_WRITE);
mprotect((void *)host_start, qemu_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);
mprotect((void *)host_start, qemu_host_page_size, prot_new);
} else {
/* just update the protection */
if (prot_new != prot1) {
mprotect((void *)host_start, host_page_size, prot_new);
mprotect((void *)host_start, qemu_host_page_size, prot_new);
}
}
return 0;
@@ -152,6 +152,9 @@ 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;
#if defined(__alpha__) || defined(__sparc__) || defined(__x86_64__)
static unsigned long last_start = 0x40000000;
#endif
#ifdef DEBUG_MMAP
{
@@ -185,18 +188,20 @@ long target_mmap(unsigned long start, unsigned long len, int prot,
len = TARGET_PAGE_ALIGN(len);
if (len == 0)
return start;
host_start = start & host_page_mask;
host_start = start & qemu_host_page_mask;
if (!(flags & MAP_FIXED)) {
#if defined(__alpha__) || defined(__sparc__)
#if defined(__alpha__) || defined(__sparc__) || defined(__x86_64__)
/* tell the kenel to search at the same place as i386 */
if (host_start == 0)
host_start = 0x40000000;
if (host_start == 0) {
host_start = last_start;
last_start += HOST_PAGE_ALIGN(len);
}
#endif
if (host_page_size != real_host_page_size) {
if (qemu_host_page_size != qemu_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_len = HOST_PAGE_ALIGN(len) + qemu_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)
@@ -212,7 +217,7 @@ long target_mmap(unsigned long start, unsigned long len, int prot,
flags |= MAP_FIXED;
} else {
/* if not fixed, no need to do anything */
host_offset = offset & host_page_mask;
host_offset = offset & qemu_host_page_mask;
host_len = len + offset - host_offset;
start = (long)mmap((void *)host_start, host_len,
prot, flags, fd, host_offset);
@@ -233,7 +238,7 @@ long target_mmap(unsigned long start, unsigned long len, int prot,
/* 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)) {
(offset & ~qemu_host_page_mask) != (start & ~qemu_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 &&
@@ -255,7 +260,7 @@ long target_mmap(unsigned long start, unsigned long len, int prot,
/* handle the start of the mapping */
if (start > host_start) {
if (host_end == host_start + host_page_size) {
if (host_end == host_start + qemu_host_page_size) {
/* one single host page */
ret = mmap_frag(host_start, start, end,
prot, flags, fd, offset);
@@ -263,21 +268,21 @@ long target_mmap(unsigned long start, unsigned long len, int prot,
return ret;
goto the_end1;
}
ret = mmap_frag(host_start, start, host_start + host_page_size,
ret = mmap_frag(host_start, start, host_start + qemu_host_page_size,
prot, flags, fd, offset);
if (ret == -1)
return ret;
host_start += host_page_size;
host_start += qemu_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,
ret = mmap_frag(host_end - qemu_host_page_size,
host_end - qemu_host_page_size, host_end,
prot, flags, fd,
offset + host_end - host_page_size - start);
offset + host_end - qemu_host_page_size - start);
if (ret == -1)
return ret;
host_end -= host_page_size;
host_end -= qemu_host_page_size;
}
/* map the middle (easier) */
@@ -317,7 +322,7 @@ int target_munmap(unsigned long start, unsigned long len)
if (len == 0)
return -EINVAL;
end = start + len;
host_start = start & host_page_mask;
host_start = start & qemu_host_page_mask;
host_end = HOST_PAGE_ALIGN(end);
if (start > host_start) {
@@ -326,14 +331,14 @@ int target_munmap(unsigned long start, unsigned long len)
for(addr = host_start; addr < start; addr += TARGET_PAGE_SIZE) {
prot |= page_get_flags(addr);
}
if (host_end == host_start + host_page_size) {
if (host_end == host_start + qemu_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;
host_start += qemu_host_page_size;
}
if (end < host_end) {
prot = 0;
@@ -341,7 +346,7 @@ int target_munmap(unsigned long start, unsigned long len)
prot |= page_get_flags(addr);
}
if (prot != 0)
host_end -= host_page_size;
host_end -= qemu_host_page_size;
}
/* unmap what we can */
@@ -386,7 +391,7 @@ int target_msync(unsigned long start, unsigned long len, int flags)
if (end == start)
return 0;
start &= host_page_mask;
start &= qemu_host_page_mask;
return msync((void *)start, end - start, flags);
}

View File

@@ -101,7 +101,12 @@ void init_paths(const char *prefix)
base = new_entry("", NULL, prefix+1);
base = add_dir_maybe(base);
set_parents(base, base);
if (base->num_entries == 0) {
free (base);
base = NULL;
} else {
set_parents(base, base);
}
}
/* FIXME: Doesn't handle DIR/.. where DIR is not in emulated dir. */

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

@@ -0,0 +1,130 @@
/*
* PPC emulation for qemu: syscall definitions.
*
* Copyright (c) 2003 Jocelyn Mayer
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/* XXX: ABSOLUTELY BUGGY:
* for now, this is quite just a cut-and-paste from i386 target...
*/
/* default linux values for the selectors */
#define __USER_DS (1)
struct target_pt_regs {
unsigned long gpr[32];
unsigned long nip;
unsigned long msr;
unsigned long orig_gpr3; /* Used for restarting system calls */
unsigned long ctr;
unsigned long link;
unsigned long xer;
unsigned long ccr;
unsigned long mq; /* 601 only (not used at present) */
/* Used on APUS to hold IPL value. */
unsigned long trap; /* Reason for being here */
unsigned long dar; /* Fault registers */
unsigned long dsisr;
unsigned long result; /* Result of a system call */
};
/* ioctls */
struct target_revectored_struct {
target_ulong __map[8]; /* 256 bits */
};
/*
* flags masks
*/
/* ipcs */
#define TARGET_SEMOP 1
#define TARGET_SEMGET 2
#define TARGET_SEMCTL 3
#define TARGET_MSGSND 11
#define TARGET_MSGRCV 12
#define TARGET_MSGGET 13
#define TARGET_MSGCTL 14
#define TARGET_SHMAT 21
#define TARGET_SHMDT 22
#define TARGET_SHMGET 23
#define TARGET_SHMCTL 24
struct target_msgbuf {
int mtype;
char mtext[1];
};
struct target_ipc_kludge {
unsigned int msgp; /* Really (struct msgbuf *) */
int msgtyp;
};
struct target_ipc_perm {
int key;
unsigned short uid;
unsigned short gid;
unsigned short cuid;
unsigned short cgid;
unsigned short mode;
unsigned short seq;
};
struct target_msqid_ds {
struct target_ipc_perm msg_perm;
unsigned int msg_first; /* really struct target_msg* */
unsigned int msg_last; /* really struct target_msg* */
unsigned int msg_stime; /* really target_time_t */
unsigned int msg_rtime; /* really target_time_t */
unsigned int msg_ctime; /* really target_time_t */
unsigned int wwait; /* really struct wait_queue* */
unsigned int rwait; /* really struct wait_queue* */
unsigned short msg_cbytes;
unsigned short msg_qnum;
unsigned short msg_qbytes;
unsigned short msg_lspid;
unsigned short msg_lrpid;
};
struct target_shmid_ds {
struct target_ipc_perm shm_perm;
int shm_segsz;
unsigned int shm_atime; /* really target_time_t */
unsigned int shm_dtime; /* really target_time_t */
unsigned int shm_ctime; /* really target_time_t */
unsigned short shm_cpid;
unsigned short shm_lpid;
short shm_nattch;
unsigned short shm_npages;
unsigned long *shm_pages;
void *attaches; /* really struct shm_desc * */
};
#define TARGET_IPC_RMID 0
#define TARGET_IPC_SET 1
#define TARGET_IPC_STAT 2
union target_semun {
int val;
unsigned int buf; /* really struct semid_ds * */
unsigned int array; /* really unsigned short * */
unsigned int __buf; /* really struct seminfo * */
unsigned int __pad; /* really void* */
};
#define UNAME_MACHINE "ppc"

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

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

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

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

View File

@@ -4,6 +4,7 @@
#include "thunk.h"
#include <signal.h>
#include <string.h>
#include "syscall_defs.h"
#include "cpu.h"
@@ -48,10 +49,21 @@ struct vm86_saved_state {
};
#endif
#ifdef TARGET_ARM
/* FPU emulator */
#include "nwfpe/fpa11.h"
#undef put_user
#undef get_user
#endif
/* NOTE: we force a big alignment so that the stack stored after is
aligned too */
typedef struct TaskState {
struct TaskState *next;
#ifdef TARGET_ARM
/* FPA state */
FPA11 fpa;
#endif
#ifdef TARGET_I386
struct target_vm86plus_struct *target_v86;
struct vm86_saved_state vm86_saved_regs;
@@ -109,4 +121,121 @@ long target_mremap(unsigned long old_addr, unsigned long old_size,
unsigned long new_addr);
int target_msync(unsigned long start, unsigned long len, int flags);
/* user access */
#define VERIFY_READ 0
#define VERIFY_WRITE 1
#define access_ok(type,addr,size) (1)
#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((void *)ptr);\
break;\
case 2:\
x = (typeof(*ptr))lduw((void *)ptr);\
break;\
case 4:\
x = (typeof(*ptr))ldl((void *)ptr);\
break;\
case 8:\
x = (typeof(*ptr))ldq((void *)ptr);\
break;\
default:\
abort();\
}\
0;\
})
static inline unsigned long __copy_to_user(void *dst, const void *src,
unsigned long size)
{
memcpy(dst, src, size);
return 0;
}
static inline unsigned long __copy_from_user(void *dst, const void *src,
unsigned long size)
{
memcpy(dst, src, size);
return 0;
}
static inline unsigned long __clear_user(void *dst, unsigned long size)
{
memset(dst, 0, size);
return 0;
}
#define put_user(x,ptr)\
({\
int __ret;\
if (access_ok(VERIFY_WRITE, ptr, sizeof(*ptr)))\
__ret = __put_user(x, ptr);\
else\
__ret = -EFAULT;\
__ret;\
})
#define get_user(x,ptr)\
({\
int __ret;\
if (access_ok(VERIFY_READ, ptr, sizeof(*ptr)))\
__ret = __get_user(x, ptr);\
else\
__ret = -EFAULT;\
__ret;\
})
static inline unsigned long copy_to_user(void *dst, const void *src,
unsigned long size)
{
if (access_ok(VERIFY_WRITE, dst, size))
return __copy_to_user(dst, src, size);
else
return size;
}
static inline unsigned long copy_from_user(void *dst, const void *src,
unsigned long size)
{
if (access_ok(VERIFY_READ, src, size))
return __copy_from_user(dst, src, size);
else
return size;
}
static inline unsigned long clear_user(void *dst, unsigned long size)
{
if (access_ok(VERIFY_WRITE, dst, size))
return __clear_user(dst, size);
else
return size;
}
#endif

View File

@@ -109,7 +109,8 @@ static inline int target_to_host_signal(int sig)
return target_to_host_signal_table[sig];
}
void host_to_target_sigset(target_sigset_t *d, const sigset_t *s)
static void host_to_target_sigset_internal(target_sigset_t *d,
const sigset_t *s)
{
int i;
unsigned long sigmask;
@@ -122,25 +123,35 @@ void host_to_target_sigset(target_sigset_t *d, const sigset_t *s)
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);
d->sig[0] = target_sigmask;
for(i = 1;i < TARGET_NSIG_WORDS; i++) {
d->sig[i] = tswapl(((unsigned long *)s)[i]);
d->sig[i] = ((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);
d->sig[0] = target_sigmask;
d->sig[1] = sigmask >> 32;
#else
#error host_to_target_sigset
#endif
}
void target_to_host_sigset(sigset_t *d, const target_sigset_t *s)
void host_to_target_sigset(target_sigset_t *d, const sigset_t *s)
{
target_sigset_t d1;
int i;
host_to_target_sigset_internal(&d1, s);
for(i = 0;i < TARGET_NSIG_WORDS; i++)
__put_user(d1.sig[i], &d->sig[i]);
}
void target_to_host_sigset_internal(sigset_t *d, const target_sigset_t *s)
{
int i;
unsigned long sigmask;
target_ulong target_sigmask;
target_sigmask = tswapl(s->sig[0]);
target_sigmask = s->sig[0];
sigmask = 0;
for(i = 0; i < 32; i++) {
if (target_sigmask & (1 << i))
@@ -149,15 +160,25 @@ void target_to_host_sigset(sigset_t *d, const target_sigset_t *s)
#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]);
((unsigned long *)d)[i] = 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);
((unsigned long *)d)[0] = sigmask | ((unsigned long)(s->sig[1]) << 32);
#else
#error target_to_host_sigset
#endif /* TARGET_LONG_BITS */
}
void target_to_host_sigset(sigset_t *d, const target_sigset_t *s)
{
target_sigset_t s1;
int i;
for(i = 0;i < TARGET_NSIG_WORDS; i++)
__get_user(s1.sig[i], &s->sig[i]);
target_to_host_sigset_internal(d, &s1);
}
void host_to_target_old_sigset(target_ulong *old_sigset,
const sigset_t *sigset)
{
@@ -370,33 +391,6 @@ int queue_signal(int sig, target_siginfo_t *info)
}
}
#if defined(DEBUG_SIGNAL)
#ifdef __i386__
static void dump_regs(struct ucontext *uc)
{
fprintf(stderr,
"EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n"
"ESI=%08x EDI=%08x EBP=%08x ESP=%08x\n"
"EFL=%08x EIP=%08x\n",
uc->uc_mcontext.gregs[EAX],
uc->uc_mcontext.gregs[EBX],
uc->uc_mcontext.gregs[ECX],
uc->uc_mcontext.gregs[EDX],
uc->uc_mcontext.gregs[ESI],
uc->uc_mcontext.gregs[EDI],
uc->uc_mcontext.gregs[EBP],
uc->uc_mcontext.gregs[ESP],
uc->uc_mcontext.gregs[EFL],
uc->uc_mcontext.gregs[EIP]);
}
#else
static void dump_regs(struct ucontext *uc)
{
}
#endif
#endif
static void host_signal_handler(int host_signum, siginfo_t *info,
void *puc)
{
@@ -405,7 +399,11 @@ 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 (host_signum == SIGSEGV || host_signum == SIGBUS
#if defined(TARGET_I386) && defined(USE_CODE_COPY)
|| host_signum == SIGFPE
#endif
) {
if (cpu_signal_handler(host_signum, info, puc))
return;
}
@@ -416,7 +414,6 @@ static void host_signal_handler(int host_signum, siginfo_t *info,
return;
#if defined(DEBUG_SIGNAL)
fprintf(stderr, "qemu: got signal %d\n", sig);
dump_regs(puc);
#endif
host_to_target_siginfo_noswap(&tinfo, info);
if (queue_signal(sig, &tinfo) == 1) {
@@ -429,11 +426,13 @@ int do_sigaction(int sig, const struct target_sigaction *act,
struct target_sigaction *oact)
{
struct emulated_sigaction *k;
struct sigaction act1;
int host_sig;
if (sig < 1 || sig > TARGET_NSIG)
return -EINVAL;
k = &sigact_table[sig - 1];
#if defined(DEBUG_SIGNAL) && 0
#if defined(DEBUG_SIGNAL)
fprintf(stderr, "sigaction sig=%d act=0x%08x, oact=0x%08x\n",
sig, (int)act, (int)oact);
#endif
@@ -448,73 +447,30 @@ int do_sigaction(int sig, const struct target_sigaction *act,
k->sa.sa_flags = tswapl(act->sa_flags);
k->sa.sa_restorer = tswapl(act->sa_restorer);
k->sa.sa_mask = act->sa_mask;
/* we update the host linux signal state */
host_sig = target_to_host_signal(sig);
if (host_sig != SIGSEGV && host_sig != SIGBUS) {
sigfillset(&act1.sa_mask);
act1.sa_flags = SA_SIGINFO;
if (k->sa.sa_flags & TARGET_SA_RESTART)
act1.sa_flags |= SA_RESTART;
/* NOTE: it is important to update the host kernel signal
ignore state to avoid getting unexpected interrupted
syscalls */
if (k->sa._sa_handler == TARGET_SIG_IGN) {
act1.sa_sigaction = (void *)SIG_IGN;
} else if (k->sa._sa_handler == TARGET_SIG_DFL) {
act1.sa_sigaction = (void *)SIG_DFL;
} else {
act1.sa_sigaction = host_signal_handler;
}
sigaction(host_sig, &act1, NULL);
}
}
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
@@ -705,14 +661,12 @@ static void setup_frame(int sig, struct emulated_sigaction *ka,
target_sigset_t *set, CPUX86State *env)
{
struct sigframe *frame;
int err = 0;
int i, err = 0;
frame = get_sigframe(ka, env, sizeof(*frame));
#if 0
if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
goto give_sigsegv;
#endif
err |= __put_user((/*current->exec_domain
&& current->exec_domain->signal_invmap
&& sig < 32
@@ -726,12 +680,10 @@ static void setup_frame(int sig, struct emulated_sigaction *ka,
if (err)
goto give_sigsegv;
if (TARGET_NSIG_WORDS > 1) {
err |= __copy_to_user(frame->extramask, &set->sig[1],
sizeof(frame->extramask));
}
if (err)
goto give_sigsegv;
for(i = 1; i < TARGET_NSIG_WORDS; i++) {
if (__put_user(set->sig[i], &frame->extramask[i - 1]))
goto give_sigsegv;
}
/* Set up to return from userspace. If provided, use a stub
already in userspace. */
@@ -771,14 +723,12 @@ static void setup_rt_frame(int sig, struct emulated_sigaction *ka,
target_sigset_t *set, CPUX86State *env)
{
struct rt_sigframe *frame;
int err = 0;
int i, err = 0;
frame = get_sigframe(ka, env, sizeof(*frame));
#if 0
if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
goto give_sigsegv;
#endif
err |= __put_user((/*current->exec_domain
&& current->exec_domain->signal_invmap
@@ -801,9 +751,10 @@ static void setup_rt_frame(int sig, struct emulated_sigaction *ka,
err |= __put_user(/* current->sas_ss_size */ 0, &frame->uc.uc_stack.ss_size);
err |= setup_sigcontext(&frame->uc.uc_mcontext, &frame->fpstate,
env, set->sig[0]);
err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
if (err)
goto give_sigsegv;
for(i = 0; i < TARGET_NSIG_WORDS; i++) {
if (__put_user(set->sig[i], &frame->uc.uc_sigmask.sig[i]))
goto give_sigsegv;
}
/* Set up to return from userspace. If provided, use a stub
already in userspace. */
@@ -898,11 +849,14 @@ long do_sigreturn(CPUX86State *env)
fprintf(stderr, "do_sigreturn\n");
#endif
/* set blocked signals */
target_set.sig[0] = frame->sc.oldmask;
for(i = 1; i < TARGET_NSIG_WORDS; i++)
target_set.sig[i] = frame->extramask[i - 1];
if (__get_user(target_set.sig[0], &frame->sc.oldmask))
goto badframe;
for(i = 1; i < TARGET_NSIG_WORDS; i++) {
if (__get_user(target_set.sig[i], &frame->extramask[i - 1]))
goto badframe;
}
target_to_host_sigset(&set, &target_set);
target_to_host_sigset_internal(&set, &target_set);
sigprocmask(SIG_SETMASK, &set, NULL);
/* restore registers */
@@ -918,7 +872,6 @@ badframe:
long do_rt_sigreturn(CPUX86State *env)
{
struct rt_sigframe *frame = (struct rt_sigframe *)(env->regs[R_ESP] - 4);
target_sigset_t target_set;
sigset_t set;
// stack_t st;
int eax;
@@ -927,9 +880,7 @@ long do_rt_sigreturn(CPUX86State *env)
if (verify_area(VERIFY_READ, frame, sizeof(*frame)))
goto badframe;
#endif
memcpy(&target_set, &frame->uc.uc_sigmask, sizeof(target_sigset_t));
target_to_host_sigset(&set, &target_set);
target_to_host_sigset(&set, &frame->uc.uc_sigmask);
sigprocmask(SIG_SETMASK, &set, NULL);
if (restore_sigcontext(env, &frame->uc.uc_mcontext, &eax))
@@ -1153,13 +1104,13 @@ 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;
int i, 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));
for(i = 1; i < TARGET_NSIG_WORDS; i++) {
if (__put_user(set->sig[i], &frame->extramask[i - 1]))
return;
}
if (err == 0)
@@ -1172,12 +1123,11 @@ static void setup_rt_frame(int usig, struct emulated_sigaction *ka,
target_sigset_t *set, CPUState *env)
{
struct rt_sigframe *frame = get_sigframe(ka, env, sizeof(*frame));
int err = 0;
int i, err = 0;
#if 0
if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame)))
return 1;
#endif
return /* 1 */;
__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);
@@ -1187,7 +1137,10 @@ static void setup_rt_frame(int usig, struct emulated_sigaction *ka,
err |= setup_sigcontext(&frame->uc.uc_mcontext, /*&frame->fpstate,*/
env, set->sig[0]);
err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
for(i = 0; i < TARGET_NSIG_WORDS; i++) {
if (__put_user(set->sig[i], &frame->uc.uc_sigmask.sig[i]))
return;
}
if (err == 0)
err = setup_return(env, ka, &frame->retcode, frame, usig);
@@ -1240,6 +1193,7 @@ long do_sigreturn(CPUState *env)
struct sigframe *frame;
target_sigset_t set;
sigset_t host_set;
int i;
/*
* Since we stacked the signal on a 64-bit boundary,
@@ -1255,13 +1209,14 @@ long do_sigreturn(CPUState *env)
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;
if (__get_user(set.sig[0], &frame->sc.oldmask))
goto badframe;
for(i = 1; i < TARGET_NSIG_WORDS; i++) {
if (__get_user(set.sig[i], &frame->extramask[i - 1]))
goto badframe;
}
target_to_host_sigset(&host_set, &set);
target_to_host_sigset_internal(&host_set, &set);
sigprocmask(SIG_SETMASK, &host_set, NULL);
if (restore_sigcontext(env, &frame->sc))
@@ -1282,7 +1237,6 @@ badframe:
long do_rt_sigreturn(CPUState *env)
{
struct rt_sigframe *frame;
target_sigset_t set;
sigset_t host_set;
/*
@@ -1299,10 +1253,7 @@ long do_rt_sigreturn(CPUState *env)
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);
target_to_host_sigset(&host_set, &frame->uc.uc_sigmask);
sigprocmask(SIG_SETMASK, &host_set, NULL);
if (restore_sigcontext(env, &frame->uc.uc_mcontext))
@@ -1320,6 +1271,346 @@ badframe:
return 0;
}
#elif defined(TARGET_SPARC)
#define __SUNOS_MAXWIN 31
/* This is what SunOS does, so shall I. */
struct target_sigcontext {
target_ulong sigc_onstack; /* state to restore */
target_ulong sigc_mask; /* sigmask to restore */
target_ulong sigc_sp; /* stack pointer */
target_ulong sigc_pc; /* program counter */
target_ulong sigc_npc; /* next program counter */
target_ulong sigc_psr; /* for condition codes etc */
target_ulong sigc_g1; /* User uses these two registers */
target_ulong sigc_o0; /* within the trampoline code. */
/* Now comes information regarding the users window set
* at the time of the signal.
*/
target_ulong sigc_oswins; /* outstanding windows */
/* stack ptrs for each regwin buf */
char *sigc_spbuf[__SUNOS_MAXWIN];
/* Windows to restore after signal */
struct {
target_ulong locals[8];
target_ulong ins[8];
} sigc_wbuf[__SUNOS_MAXWIN];
};
/* A Sparc stack frame */
struct sparc_stackf {
target_ulong locals[8];
target_ulong ins[6];
struct sparc_stackf *fp;
target_ulong callers_pc;
char *structptr;
target_ulong xargs[6];
target_ulong xxargs[1];
};
typedef struct {
struct {
target_ulong psr;
target_ulong pc;
target_ulong npc;
target_ulong y;
target_ulong u_regs[16]; /* globals and ins */
} si_regs;
int si_mask;
} __siginfo_t;
typedef struct {
unsigned long si_float_regs [32];
unsigned long si_fsr;
unsigned long si_fpqdepth;
struct {
unsigned long *insn_addr;
unsigned long insn;
} si_fpqueue [16];
} __siginfo_fpu_t;
struct target_signal_frame {
struct sparc_stackf ss;
__siginfo_t info;
__siginfo_fpu_t *fpu_save;
target_ulong insns[2] __attribute__ ((aligned (8)));
target_ulong extramask[TARGET_NSIG_WORDS - 1];
target_ulong extra_size; /* Should be 0 */
__siginfo_fpu_t fpu_state;
};
struct target_rt_signal_frame {
struct sparc_stackf ss;
siginfo_t info;
target_ulong regs[20];
sigset_t mask;
__siginfo_fpu_t *fpu_save;
unsigned int insns[2];
stack_t stack;
unsigned int extra_size; /* Should be 0 */
__siginfo_fpu_t fpu_state;
};
#define UREG_O0 0
#define UREG_O6 6
#define UREG_I0 16
#define UREG_I1 17
#define UREG_I2 18
#define UREG_I6 22
#define UREG_I7 23
#define UREG_FP UREG_I6
#define UREG_SP UREG_O6
static inline void *get_sigframe(struct emulated_sigaction *sa, CPUState *env, unsigned long framesize)
{
unsigned long sp;
sp = env->regwptr[UREG_FP];
#if 0
/* This is the X/Open sanctioned signal stack switching. */
if (sa->sa_flags & TARGET_SA_ONSTACK) {
if (!on_sig_stack(sp) && !((current->sas_ss_sp + current->sas_ss_size) & 7))
sp = current->sas_ss_sp + current->sas_ss_size;
}
#endif
return (void *)(sp - framesize);
}
static int
setup___siginfo(__siginfo_t *si, CPUState *env, target_ulong mask)
{
int err = 0, i;
fprintf(stderr, "2.a %lx psr: %lx regs: %lx\n", si, env->psr, si->si_regs.psr);
err |= __put_user(env->psr, &si->si_regs.psr);
fprintf(stderr, "2.a1 pc:%lx\n", si->si_regs.pc);
err |= __put_user(env->pc, &si->si_regs.pc);
err |= __put_user(env->npc, &si->si_regs.npc);
err |= __put_user(env->y, &si->si_regs.y);
fprintf(stderr, "2.b\n");
for (i=0; i < 7; i++) {
err |= __put_user(env->gregs[i], &si->si_regs.u_regs[i]);
}
for (i=0; i < 7; i++) {
err |= __put_user(env->regwptr[i+16], &si->si_regs.u_regs[i+8]);
}
fprintf(stderr, "2.c\n");
err |= __put_user(mask, &si->si_mask);
return err;
}
static int
setup_sigcontext(struct target_sigcontext *sc, /*struct _fpstate *fpstate,*/
CPUState *env, unsigned long mask)
{
int err = 0;
err |= __put_user(mask, &sc->sigc_mask);
err |= __put_user(env->regwptr[UREG_SP], &sc->sigc_sp);
err |= __put_user(env->pc, &sc->sigc_pc);
err |= __put_user(env->npc, &sc->sigc_npc);
err |= __put_user(env->psr, &sc->sigc_psr);
err |= __put_user(env->gregs[1], &sc->sigc_g1);
err |= __put_user(env->regwptr[UREG_O0], &sc->sigc_o0);
return err;
}
#define NF_ALIGNEDSZ (((sizeof(struct target_signal_frame) + 7) & (~7)))
static void setup_frame(int sig, struct emulated_sigaction *ka,
target_sigset_t *set, CPUState *env)
{
struct target_signal_frame *sf;
int sigframe_size, err, i;
/* 1. Make sure everything is clean */
//synchronize_user_stack();
sigframe_size = NF_ALIGNEDSZ;
sf = (struct target_signal_frame *)
get_sigframe(ka, env, sigframe_size);
#if 0
if (invalid_frame_pointer(sf, sigframe_size))
goto sigill_and_return;
#endif
/* 2. Save the current process state */
err = setup___siginfo(&sf->info, env, set->sig[0]);
err |= __put_user(0, &sf->extra_size);
//err |= save_fpu_state(regs, &sf->fpu_state);
//err |= __put_user(&sf->fpu_state, &sf->fpu_save);
err |= __put_user(set->sig[0], &sf->info.si_mask);
for (i = 0; i < TARGET_NSIG_WORDS - 1; i++) {
err |= __put_user(set->sig[i + 1], &sf->extramask[i]);
}
for (i = 0; i < 7; i++) {
err |= __put_user(env->regwptr[i + 8], &sf->ss.locals[i]);
}
for (i = 0; i < 7; i++) {
err |= __put_user(env->regwptr[i + 16], &sf->ss.ins[i]);
}
//err |= __copy_to_user(sf, (char *) regs->u_regs[UREG_FP],
// sizeof(struct reg_window));
if (err)
goto sigsegv;
/* 3. signal handler back-trampoline and parameters */
env->regwptr[UREG_FP] = (target_ulong) sf;
env->regwptr[UREG_I0] = sig;
env->regwptr[UREG_I1] = (target_ulong) &sf->info;
env->regwptr[UREG_I2] = (target_ulong) &sf->info;
/* 4. signal handler */
env->pc = (unsigned long) ka->sa._sa_handler;
env->npc = (env->pc + 4);
/* 5. return to kernel instructions */
if (ka->sa.sa_restorer)
env->regwptr[UREG_I7] = (unsigned long)ka->sa.sa_restorer;
else {
env->regwptr[UREG_I7] = (unsigned long)(&(sf->insns[0]) - 2);
/* mov __NR_sigreturn, %g1 */
err |= __put_user(0x821020d8, &sf->insns[0]);
/* t 0x10 */
err |= __put_user(0x91d02010, &sf->insns[1]);
if (err)
goto sigsegv;
/* Flush instruction space. */
//flush_sig_insns(current->mm, (unsigned long) &(sf->insns[0]));
//tb_flush(env);
}
return;
sigill_and_return:
force_sig(TARGET_SIGILL);
sigsegv:
force_sig(TARGET_SIGSEGV);
}
static inline int
restore_fpu_state(CPUState *env, __siginfo_fpu_t *fpu)
{
int err;
#if 0
#ifdef CONFIG_SMP
if (current->flags & PF_USEDFPU)
regs->psr &= ~PSR_EF;
#else
if (current == last_task_used_math) {
last_task_used_math = 0;
regs->psr &= ~PSR_EF;
}
#endif
current->used_math = 1;
current->flags &= ~PF_USEDFPU;
#endif
#if 0
if (verify_area (VERIFY_READ, fpu, sizeof(*fpu)))
return -EFAULT;
#endif
err = __copy_from_user(&env->fpr[0], &fpu->si_float_regs[0],
(sizeof(unsigned long) * 32));
err |= __get_user(env->fsr, &fpu->si_fsr);
#if 0
err |= __get_user(current->thread.fpqdepth, &fpu->si_fpqdepth);
if (current->thread.fpqdepth != 0)
err |= __copy_from_user(&current->thread.fpqueue[0],
&fpu->si_fpqueue[0],
((sizeof(unsigned long) +
(sizeof(unsigned long *)))*16));
#endif
return err;
}
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)
{
struct target_signal_frame *sf;
unsigned long up_psr, pc, npc;
target_sigset_t set;
__siginfo_fpu_t *fpu_save;
int err;
sf = (struct new_signal_frame *) env->regwptr[UREG_FP];
fprintf(stderr, "sigreturn sf: %lx\n", &sf);
/* 1. Make sure we are not getting garbage from the user */
#if 0
if (verify_area (VERIFY_READ, sf, sizeof (*sf)))
goto segv_and_exit;
#endif
if (((uint) sf) & 3)
goto segv_and_exit;
err = __get_user(pc, &sf->info.si_regs.pc);
err |= __get_user(npc, &sf->info.si_regs.npc);
fprintf(stderr, "pc: %lx npc %lx\n", pc, npc);
if ((pc | npc) & 3)
goto segv_and_exit;
/* 2. Restore the state */
up_psr = env->psr;
//err |= __copy_from_user(regs, &sf->info.si_regs, sizeof (struct pt_regs)
//);
/* User can only change condition codes and FPU enabling in %psr. */
env->psr = (up_psr & ~(PSR_ICC /* | PSR_EF */))
| (env->psr & (PSR_ICC /* | PSR_EF */));
fprintf(stderr, "psr: %lx\n", env->psr);
err |= __get_user(fpu_save, &sf->fpu_save);
if (fpu_save)
err |= restore_fpu_state(env, fpu_save);
/* This is pretty much atomic, no amount locking would prevent
* the races which exist anyways.
*/
err |= __get_user(set.sig[0], &sf->info.si_mask);
//err |= __copy_from_user(&set.sig[1], &sf->extramask,
// (_NSIG_WORDS-1) * sizeof(unsigned int));
if (err)
goto segv_and_exit;
#if 0
sigdelsetmask(&set, ~_BLOCKABLE);
spin_lock_irq(&current->sigmask_lock);
current->blocked = set;
recalc_sigpending(current);
spin_unlock_irq(&current->sigmask_lock);
#endif
fprintf(stderr, "returning %lx\n", env->regwptr[0]);
return env->regwptr[0];
segv_and_exit:
force_sig(TARGET_SIGSEGV);
}
long do_rt_sigreturn(CPUState *env)
{
fprintf(stderr, "do_rt_sigreturn: not implemented\n");
return -ENOSYS;
}
#else
static void setup_frame(int sig, struct emulated_sigaction *ka,
@@ -1405,7 +1696,7 @@ void process_pending_signals(void *cpu_env)
sigprocmask(SIG_BLOCK, &set, &old_set);
/* save the previous blocked signal state to restore it at the
end of the signal execution (see do_sigreturn) */
host_to_target_sigset(&target_old_set, &old_set);
host_to_target_sigset_internal(&target_old_set, &old_set);
/* if the CPU is in VM86 mode, we restore the 32 bit values */
#ifdef TARGET_I386

View File

@@ -5,3 +5,5 @@ struct target_pt_regs {
target_ulong y;
target_ulong u_regs[16];
};
#define UNAME_MACHINE "sun4"

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

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

View File

@@ -41,8 +41,11 @@
#include <sys/uio.h>
#include <sys/poll.h>
#include <sys/times.h>
#include <sys/shm.h>
#include <utime.h>
#include <sys/sysinfo.h>
//#include <sys/user.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#define termios host_termios
@@ -65,6 +68,11 @@
//#define DEBUG
#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SPARC)
/* 16 bit uid wrappers emulation */
#define USE_UID16
#endif
//#include <linux/msdos_fs.h>
#define VFAT_IOCTL_READDIR_BOTH _IOR('r', 1, struct dirent [2])
#define VFAT_IOCTL_READDIR_SHORT _IOR('r', 2, struct dirent [2])
@@ -200,7 +208,7 @@ type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5) \
#define __NR_sys_getdents64 __NR_getdents64
#define __NR_sys_rt_sigqueueinfo __NR_rt_sigqueueinfo
#if defined(__alpha__) || defined (__ia64__)
#if defined(__alpha__) || defined (__ia64__) || defined(__x86_64__)
#define __NR__llseek __NR_lseek
#endif
@@ -320,7 +328,7 @@ static inline void host_to_target_fds(target_long *target_fds,
target_long v;
if (target_fds) {
nw = n / TARGET_LONG_BITS;
nw = (n + TARGET_LONG_BITS - 1) / TARGET_LONG_BITS;
k = 0;
for(i = 0;i < nw; i++) {
v = 0;
@@ -525,61 +533,116 @@ static inline void host_to_target_cmsg(struct target_msghdr *target_msgh,
static long do_setsockopt(int sockfd, int level, int optname,
void *optval, socklen_t optlen)
{
if (level == SOL_TCP) {
int val, ret;
switch(level) {
case SOL_TCP:
/* TCP options all take an 'int' value. */
int val;
if (optlen < sizeof(uint32_t))
return -EINVAL;
val = tswap32(*(uint32_t *)optval);
return get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
}
else if (level != SOL_SOCKET) {
gemu_log("Unsupported setsockopt level: %d\n", level);
return -ENOSYS;
}
switch (optname) {
/* Options with 'int' argument. */
case SO_DEBUG:
case SO_REUSEADDR:
case SO_TYPE:
case SO_ERROR:
case SO_DONTROUTE:
case SO_BROADCAST:
case SO_SNDBUF:
case SO_RCVBUF:
case SO_KEEPALIVE:
case SO_OOBINLINE:
case SO_NO_CHECK:
case SO_PRIORITY:
case SO_BSDCOMPAT:
case SO_PASSCRED:
case SO_TIMESTAMP:
case SO_RCVLOWAT:
case SO_RCVTIMEO:
case SO_SNDTIMEO:
{
int val;
if (optlen < sizeof(uint32_t))
return -EINVAL;
val = tswap32(*(uint32_t *)optval);
return get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
}
if (get_user(val, (uint32_t *)optval))
return -EFAULT;
ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
break;
case SOL_IP:
switch(optname) {
case IP_HDRINCL:
val = 0;
if (optlen >= sizeof(uint32_t)) {
if (get_user(val, (uint32_t *)optval))
return -EFAULT;
} else if (optlen >= 1) {
if (get_user(val, (uint8_t *)optval))
return -EFAULT;
}
ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
break;
default:
goto unimplemented;
}
break;
case SOL_SOCKET:
switch (optname) {
/* Options with 'int' argument. */
case SO_DEBUG:
case SO_REUSEADDR:
case SO_TYPE:
case SO_ERROR:
case SO_DONTROUTE:
case SO_BROADCAST:
case SO_SNDBUF:
case SO_RCVBUF:
case SO_KEEPALIVE:
case SO_OOBINLINE:
case SO_NO_CHECK:
case SO_PRIORITY:
case SO_BSDCOMPAT:
case SO_PASSCRED:
case SO_TIMESTAMP:
case SO_RCVLOWAT:
case SO_RCVTIMEO:
case SO_SNDTIMEO:
if (optlen < sizeof(uint32_t))
return -EINVAL;
if (get_user(val, (uint32_t *)optval))
return -EFAULT;
ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
break;
default:
goto unimplemented;
}
break;
default:
gemu_log("Unsupported setsockopt SOL_SOCKET option: %d\n", optname);
return -ENOSYS;
unimplemented:
gemu_log("Unsupported setsockopt level=%d optname=%d \n", level, optname);
ret = -ENOSYS;
}
return ret;
}
static long do_getsockopt(int sockfd, int level, int optname,
void *optval, socklen_t *optlen)
{
gemu_log("getsockopt not yet supported\n");
return -ENOSYS;
int len, lv, val, ret;
switch(level) {
case SOL_SOCKET:
switch (optname) {
case SO_LINGER:
case SO_RCVTIMEO:
case SO_SNDTIMEO:
case SO_PEERCRED:
case SO_PEERNAME:
/* These don't just return a single integer */
goto unimplemented;
default:
if (get_user(len, optlen))
return -EFAULT;
if (len < 0)
return -EINVAL;
lv = sizeof(int);
ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
if (ret < 0)
return ret;
val = tswap32(val);
if (len > lv)
len = lv;
if (copy_to_user(optval, &val, len))
return -EFAULT;
if (put_user(len, optlen))
return -EFAULT;
break;
}
break;
default:
unimplemented:
gemu_log("getsockopt level=%d optname=%d not yet supported\n",
level, optname);
ret = -ENOSYS;
break;
}
return ret;
}
static long do_socketcall(int num, int32_t *vptr)
@@ -802,12 +865,9 @@ static long do_socketcall(int num, int32_t *vptr)
int level = tswap32(vptr[1]);
int optname = tswap32(vptr[2]);
void *optval = (void *)tswap32(vptr[3]);
uint32_t *target_len = (void *)tswap32(vptr[4]);
socklen_t optlen = tswap32(*target_len);
uint32_t *poptlen = (void *)tswap32(vptr[4]);
ret = do_getsockopt(sockfd, level, optname, optval, &optlen);
if (!is_error(ret))
*target_len = tswap32(optlen);
ret = do_getsockopt(sockfd, level, optname, optval, poptlen);
}
break;
default:
@@ -818,6 +878,92 @@ static long do_socketcall(int num, int32_t *vptr)
return ret;
}
#define N_SHM_REGIONS 32
static struct shm_region {
uint32_t start;
uint32_t size;
} shm_regions[N_SHM_REGIONS];
static long do_ipc(long call, long first, long second, long third,
long ptr, long fifth)
{
int version;
long ret = 0;
unsigned long raddr;
struct shmid_ds shm_info;
int i;
version = call >> 16;
call &= 0xffff;
switch (call) {
case IPCOP_shmat:
/* SHM_* flags are the same on all linux platforms */
ret = get_errno((long) shmat(first, (void *) ptr, second));
if (is_error(ret))
break;
raddr = ret;
/* find out the length of the shared memory segment */
ret = get_errno(shmctl(first, IPC_STAT, &shm_info));
if (is_error(ret)) {
/* can't get length, bail out */
shmdt((void *) raddr);
break;
}
page_set_flags(raddr, raddr + shm_info.shm_segsz,
PAGE_VALID | PAGE_READ |
((second & SHM_RDONLY)? 0: PAGE_WRITE));
for (i = 0; i < N_SHM_REGIONS; ++i) {
if (shm_regions[i].start == 0) {
shm_regions[i].start = raddr;
shm_regions[i].size = shm_info.shm_segsz;
break;
}
}
if (put_user(raddr, (uint32_t *)third))
return -EFAULT;
ret = 0;
break;
case IPCOP_shmdt:
for (i = 0; i < N_SHM_REGIONS; ++i) {
if (shm_regions[i].start == ptr) {
shm_regions[i].start = 0;
page_set_flags(ptr, shm_regions[i].size, 0);
break;
}
}
ret = get_errno(shmdt((void *) ptr));
break;
case IPCOP_shmget:
/* IPC_* flag values are the same on all linux platforms */
ret = get_errno(shmget(first, second, third));
break;
/* IPC_* and SHM_* command values are the same on all linux platforms */
case IPCOP_shmctl:
switch(second) {
case IPC_RMID:
case SHM_LOCK:
case SHM_UNLOCK:
ret = get_errno(shmctl(first, second, NULL));
break;
default:
goto unimplemented;
}
break;
default:
unimplemented:
gemu_log("Unsupported ipc call: %ld (version %d)\n", call, version);
ret = -ENOSYS;
break;
}
return ret;
}
/* kernel structure types definitions */
#define IFNAMSIZ 16
@@ -1104,6 +1250,26 @@ static bitmask_transtbl mmap_flags_tbl[] = {
{ 0, 0, 0, 0 }
};
static bitmask_transtbl fcntl_flags_tbl[] = {
{ TARGET_O_ACCMODE, TARGET_O_WRONLY, O_ACCMODE, O_WRONLY, },
{ TARGET_O_ACCMODE, TARGET_O_RDWR, O_ACCMODE, O_RDWR, },
{ TARGET_O_CREAT, TARGET_O_CREAT, O_CREAT, O_CREAT, },
{ TARGET_O_EXCL, TARGET_O_EXCL, O_EXCL, O_EXCL, },
{ TARGET_O_NOCTTY, TARGET_O_NOCTTY, O_NOCTTY, O_NOCTTY, },
{ TARGET_O_TRUNC, TARGET_O_TRUNC, O_TRUNC, O_TRUNC, },
{ TARGET_O_APPEND, TARGET_O_APPEND, O_APPEND, O_APPEND, },
{ TARGET_O_NONBLOCK, TARGET_O_NONBLOCK, O_NONBLOCK, O_NONBLOCK, },
{ TARGET_O_SYNC, TARGET_O_SYNC, O_SYNC, O_SYNC, },
{ TARGET_FASYNC, TARGET_FASYNC, FASYNC, FASYNC, },
{ TARGET_O_DIRECTORY, TARGET_O_DIRECTORY, O_DIRECTORY, O_DIRECTORY, },
{ TARGET_O_NOFOLLOW, TARGET_O_NOFOLLOW, O_NOFOLLOW, O_NOFOLLOW, },
{ TARGET_O_LARGEFILE, TARGET_O_LARGEFILE, O_LARGEFILE, O_LARGEFILE, },
#if defined(O_DIRECT)
{ TARGET_O_DIRECT, TARGET_O_DIRECT, O_DIRECT, O_DIRECT, },
#endif
{ 0, 0, 0, 0 }
};
#if defined(TARGET_I386)
/* NOTE: there is really one LDT for all the threads */
@@ -1264,7 +1430,16 @@ int do_fork(CPUState *env, unsigned int flags, unsigned long newsp)
new_env->regs[13] = newsp;
new_env->regs[0] = 0;
#elif defined(TARGET_SPARC)
printf ("HELPME: %s:%d\n", __FILE__, __LINE__);
printf ("HELPME: %s:%d\n", __FILE__, __LINE__);
#elif defined(TARGET_PPC)
if (!newsp)
newsp = env->gpr[1];
new_env->gpr[1] = newsp;
{
int i;
for (i = 7; i < 32; i++)
new_env->gpr[i] = 0;
}
#else
#error unsupported target CPU
#endif
@@ -1318,6 +1493,15 @@ static long do_fcntl(int fd, int cmd, unsigned long arg)
errno = EINVAL;
break;
case F_GETFL:
ret = fcntl(fd, cmd, arg);
ret = host_to_target_bitmask(ret, fcntl_flags_tbl);
break;
case F_SETFL:
ret = fcntl(fd, cmd, target_to_host_bitmask(arg, fcntl_flags_tbl));
break;
default:
ret = fcntl(fd, cmd, arg);
break;
@@ -1325,11 +1509,41 @@ static long do_fcntl(int fd, int cmd, unsigned long arg)
return ret;
}
#ifdef USE_UID16
#define high2lowuid(x) (x)
#define high2lowgid(x) (x)
#define low2highuid(x) (x)
#define low2highgid(x) (x)
static inline int high2lowuid(int uid)
{
if (uid > 65535)
return 65534;
else
return uid;
}
static inline int high2lowgid(int gid)
{
if (gid > 65535)
return 65534;
else
return gid;
}
static inline int low2highuid(int uid)
{
if ((int16_t)uid == -1)
return -1;
else
return uid;
}
static inline int low2highgid(int gid)
{
if ((int16_t)gid == -1)
return -1;
else
return gid;
}
#endif /* USE_UID16 */
void syscall_init(void)
{
@@ -1371,7 +1585,7 @@ void syscall_init(void)
ie++;
}
}
long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
long arg4, long arg5, long arg6)
{
@@ -1380,7 +1594,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
struct kernel_statfs *stfs;
#ifdef DEBUG
gemu_log("syscall %d\n", num);
gemu_log("syscall %d", num);
#endif
switch(num) {
case TARGET_NR_exit:
@@ -1399,7 +1613,9 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
ret = get_errno(write(arg1, (void *)arg2, arg3));
break;
case TARGET_NR_open:
ret = get_errno(open(path((const char *)arg1), arg2, arg3));
ret = get_errno(open(path((const char *)arg1),
target_to_host_bitmask(arg2, fcntl_flags_tbl),
arg3));
break;
case TARGET_NR_close:
ret = get_errno(close(arg1));
@@ -1472,9 +1688,6 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
case TARGET_NR_chmod:
ret = get_errno(chmod((const char *)arg1, arg2));
break;
case TARGET_NR_lchown:
ret = get_errno(chown((const char *)arg1, arg2, arg3));
break;
#ifdef TARGET_NR_break
case TARGET_NR_break:
goto unimplemented;
@@ -1495,12 +1708,6 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
case TARGET_NR_umount:
ret = get_errno(umount((const char *)arg1));
break;
case TARGET_NR_setuid:
ret = get_errno(setuid(low2highuid(arg1)));
break;
case TARGET_NR_getuid:
ret = get_errno(getuid());
break;
case TARGET_NR_stime:
{
int *time_ptr = (int *)arg1;
@@ -1523,11 +1730,16 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
break;
case TARGET_NR_utime:
{
struct utimbuf tbuf;
struct utimbuf tbuf, *tbuf1;
struct target_utimbuf *target_tbuf = (void *)arg2;
tbuf.actime = tswapl(target_tbuf->actime);
tbuf.modtime = tswapl(target_tbuf->modtime);
ret = get_errno(utime((const char *)arg1, &tbuf));
if (target_tbuf) {
get_user(tbuf.actime, &target_tbuf->actime);
get_user(tbuf.modtime, &target_tbuf->modtime);
tbuf1 = &tbuf;
} else {
tbuf1 = NULL;
}
ret = get_errno(utime((const char *)arg1, tbuf1));
}
break;
#ifdef TARGET_NR_stty
@@ -1596,20 +1808,9 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
case TARGET_NR_prof:
goto unimplemented;
#endif
case TARGET_NR_setgid:
ret = get_errno(setgid(low2highgid(arg1)));
break;
case TARGET_NR_getgid:
ret = get_errno(getgid());
break;
case TARGET_NR_signal:
goto unimplemented;
case TARGET_NR_geteuid:
ret = get_errno(geteuid());
break;
case TARGET_NR_getegid:
ret = get_errno(getegid());
break;
case TARGET_NR_acct:
goto unimplemented;
case TARGET_NR_umount2:
@@ -1844,12 +2045,6 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
/* NOTE: ret is eax, so not transcoding must be done */
ret = do_rt_sigreturn(cpu_env);
break;
case TARGET_NR_setreuid:
ret = get_errno(setreuid(arg1, arg2));
break;
case TARGET_NR_setregid:
ret = get_errno(setregid(arg1, arg2));
break;
case TARGET_NR_sethostname:
ret = get_errno(sethostname((const char *)arg1, arg2));
break;
@@ -1906,34 +2101,6 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
ret = get_errno(settimeofday(&tv, NULL));
}
break;
case TARGET_NR_getgroups:
{
int gidsetsize = arg1;
uint16_t *target_grouplist = (void *)arg2;
gid_t *grouplist;
int i;
grouplist = alloca(gidsetsize * sizeof(gid_t));
ret = get_errno(getgroups(gidsetsize, grouplist));
if (!is_error(ret)) {
for(i = 0;i < gidsetsize; i++)
target_grouplist[i] = tswap16(grouplist[i]);
}
}
break;
case TARGET_NR_setgroups:
{
int gidsetsize = arg1;
uint16_t *target_grouplist = (void *)arg2;
gid_t *grouplist;
int i;
grouplist = alloca(gidsetsize * sizeof(gid_t));
for(i = 0;i < gidsetsize; i++)
grouplist[i] = tswap16(target_grouplist[i]);
ret = get_errno(setgroups(gidsetsize, grouplist));
}
break;
case TARGET_NR_select:
{
struct target_sel_arg_struct *sel = (void *)arg1;
@@ -1988,10 +2155,15 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
#endif
break;
case TARGET_NR_mmap2:
#if defined(TARGET_SPARC)
#define MMAP_SHIFT 12
#else
#define MMAP_SHIFT TARGET_PAGE_BITS
#endif
ret = get_errno(target_mmap(arg1, arg2, arg3,
target_to_host_bitmask(arg4, mmap_flags_tbl),
arg5,
arg6 << TARGET_PAGE_BITS));
arg6 << MMAP_SHIFT));
break;
case TARGET_NR_munmap:
ret = get_errno(target_munmap(arg1, arg2));
@@ -2026,9 +2198,6 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
case TARGET_NR_fchmod:
ret = get_errno(fchmod(arg1, arg2));
break;
case TARGET_NR_fchown:
ret = get_errno(fchown(arg1, arg2, arg3));
break;
case TARGET_NR_getpriority:
ret = get_errno(getpriority(arg1, arg2));
break;
@@ -2121,10 +2290,16 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
struct target_stat *target_st = (void *)arg2;
target_st->st_dev = tswap16(st.st_dev);
target_st->st_ino = tswapl(st.st_ino);
#if defined(TARGET_PPC)
target_st->st_mode = tswapl(st.st_mode); /* XXX: check this */
target_st->st_uid = tswap32(st.st_uid);
target_st->st_gid = tswap32(st.st_gid);
#else
target_st->st_mode = tswap16(st.st_mode);
target_st->st_nlink = tswap16(st.st_nlink);
target_st->st_uid = tswap16(st.st_uid);
target_st->st_gid = tswap16(st.st_gid);
#endif
target_st->st_nlink = tswap16(st.st_nlink);
target_st->st_rdev = tswap16(st.st_rdev);
target_st->st_size = tswapl(st.st_size);
target_st->st_blksize = tswapl(st.st_blksize);
@@ -2174,9 +2349,32 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
ret = get_errno(swapoff((const char *)arg1));
break;
case TARGET_NR_sysinfo:
goto unimplemented;
{
struct target_sysinfo *target_value = (void *)arg1;
struct sysinfo value;
ret = get_errno(sysinfo(&value));
if (!is_error(ret) && target_value)
{
__put_user(value.uptime, &target_value->uptime);
__put_user(value.loads[0], &target_value->loads[0]);
__put_user(value.loads[1], &target_value->loads[1]);
__put_user(value.loads[2], &target_value->loads[2]);
__put_user(value.totalram, &target_value->totalram);
__put_user(value.freeram, &target_value->freeram);
__put_user(value.sharedram, &target_value->sharedram);
__put_user(value.bufferram, &target_value->bufferram);
__put_user(value.totalswap, &target_value->totalswap);
__put_user(value.freeswap, &target_value->freeswap);
__put_user(value.procs, &target_value->procs);
__put_user(value.totalhigh, &target_value->totalhigh);
__put_user(value.freehigh, &target_value->freehigh);
__put_user(value.mem_unit, &target_value->mem_unit);
}
}
break;
case TARGET_NR_ipc:
goto unimplemented;
ret = do_ipc(arg1, arg2, arg3, arg4, arg5, arg6);
break;
case TARGET_NR_fsync:
ret = get_errno(fsync(arg1));
break;
@@ -2194,6 +2392,17 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
break;
case TARGET_NR_uname:
/* no need to transcode because we use the linux syscall */
{
struct new_utsname * buf;
buf = (struct new_utsname *)arg1;
ret = get_errno(sys_uname(buf));
if (!is_error(ret)) {
/* Overrite the native machine name with whatever is being
emulated. */
strcpy (buf->machine, UNAME_MACHINE);
}
}
ret = get_errno(sys_uname((struct new_utsname *)arg1));
break;
#ifdef TARGET_I386
@@ -2230,17 +2439,16 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
break;
case TARGET_NR_afs_syscall:
goto unimplemented;
case TARGET_NR_setfsuid:
ret = get_errno(setfsuid(arg1));
break;
case TARGET_NR_setfsgid:
ret = get_errno(setfsgid(arg1));
break;
case TARGET_NR__llseek:
{
#if defined (__x86_64__)
ret = get_errno(lseek(arg1, ((uint64_t )arg2 << 32) | arg3, arg5));
*(int64_t *)arg4 = ret;
#else
int64_t res;
ret = get_errno(_llseek(arg1, arg2, arg3, &res, arg5));
*(int64_t *)arg4 = tswap64(res);
#endif
}
break;
case TARGET_NR_getdents:
@@ -2311,6 +2519,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
}
#endif
break;
#ifdef TARGET_NR_getdents64
case TARGET_NR_getdents64:
{
struct dirent64 *dirp = (void *)arg2;
@@ -2334,6 +2543,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
}
}
break;
#endif /* TARGET_NR_getdents64 */
case TARGET_NR__newselect:
ret = do_select(arg1, (void *)arg2, (void *)arg3, (void *)arg4,
(void *)arg5);
@@ -2401,7 +2611,9 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
ret = get_errno(fdatasync(arg1));
break;
case TARGET_NR__sysctl:
goto unimplemented;
/* We don't implement this, but ENODIR is always a safe
return value. */
return -ENOTDIR;
case TARGET_NR_sched_setparam:
{
struct sched_param *target_schp = (void *)arg2;
@@ -2465,52 +2677,13 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
}
}
break;
#ifdef TARGET_NR_setresuid
case TARGET_NR_setresuid:
ret = get_errno(setresuid(low2highuid(arg1),
low2highuid(arg2),
low2highuid(arg3)));
break;
#endif
#ifdef TARGET_NR_getresuid
case TARGET_NR_getresuid:
{
int ruid, euid, suid;
ret = get_errno(getresuid(&ruid, &euid, &suid));
if (!is_error(ret)) {
*(uint16_t *)arg1 = tswap16(high2lowuid(ruid));
*(uint16_t *)arg2 = tswap16(high2lowuid(euid));
*(uint16_t *)arg3 = tswap16(high2lowuid(suid));
}
}
break;
#endif
#ifdef TARGET_NR_getresgid
case TARGET_NR_setresgid:
ret = get_errno(setresgid(low2highgid(arg1),
low2highgid(arg2),
low2highgid(arg3)));
break;
#endif
#ifdef TARGET_NR_getresgid
case TARGET_NR_getresgid:
{
int rgid, egid, sgid;
ret = get_errno(getresgid(&rgid, &egid, &sgid));
if (!is_error(ret)) {
*(uint16_t *)arg1 = high2lowgid(tswap16(rgid));
*(uint16_t *)arg2 = high2lowgid(tswap16(egid));
*(uint16_t *)arg3 = high2lowgid(tswap16(sgid));
}
}
break;
#endif
case TARGET_NR_query_module:
goto unimplemented;
case TARGET_NR_nfsservctl:
goto unimplemented;
case TARGET_NR_prctl:
goto unimplemented;
#ifdef TARGET_NR_pread
case TARGET_NR_pread:
page_unprotect_range((void *)arg2, arg3);
ret = get_errno(pread(arg1, (void *)arg2, arg3, arg4));
@@ -2518,9 +2691,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
case TARGET_NR_pwrite:
ret = get_errno(pwrite(arg1, (void *)arg2, arg3, arg4));
break;
case TARGET_NR_chown:
ret = get_errno(chown((const char *)arg1, arg2, arg3));
break;
#endif
case TARGET_NR_getcwd:
ret = get_errno(sys_getcwd1((char *)arg1, arg2));
break;
@@ -2573,27 +2744,137 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
if (!is_error(ret)) {
struct target_stat64 *target_st = (void *)arg2;
memset(target_st, 0, sizeof(struct target_stat64));
target_st->st_dev = tswap16(st.st_dev);
target_st->st_ino = tswap64(st.st_ino);
put_user(st.st_dev, &target_st->st_dev);
put_user(st.st_ino, &target_st->st_ino);
#ifdef TARGET_STAT64_HAS_BROKEN_ST_INO
target_st->__st_ino = tswapl(st.st_ino);
put_user(st.st_ino, &target_st->__st_ino);
#endif
target_st->st_mode = tswap32(st.st_mode);
target_st->st_nlink = tswap32(st.st_nlink);
target_st->st_uid = tswapl(st.st_uid);
target_st->st_gid = tswapl(st.st_gid);
target_st->st_rdev = tswap16(st.st_rdev);
put_user(st.st_mode, &target_st->st_mode);
put_user(st.st_nlink, &target_st->st_nlink);
put_user(st.st_uid, &target_st->st_uid);
put_user(st.st_gid, &target_st->st_gid);
put_user(st.st_rdev, &target_st->st_rdev);
/* XXX: better use of kernel struct */
target_st->st_size = tswap64(st.st_size);
target_st->st_blksize = tswapl(st.st_blksize);
target_st->st_blocks = tswapl(st.st_blocks);
target_st->target_st_atime = tswapl(st.st_atime);
target_st->target_st_mtime = tswapl(st.st_mtime);
target_st->target_st_ctime = tswapl(st.st_ctime);
put_user(st.st_size, &target_st->st_size);
put_user(st.st_blksize, &target_st->st_blksize);
put_user(st.st_blocks, &target_st->st_blocks);
put_user(st.st_atime, &target_st->target_st_atime);
put_user(st.st_mtime, &target_st->target_st_mtime);
put_user(st.st_ctime, &target_st->target_st_ctime);
}
}
break;
#ifdef USE_UID16
case TARGET_NR_lchown:
ret = get_errno(lchown((const char *)arg1, low2highuid(arg2), low2highgid(arg3)));
break;
case TARGET_NR_getuid:
ret = get_errno(high2lowuid(getuid()));
break;
case TARGET_NR_getgid:
ret = get_errno(high2lowgid(getgid()));
break;
case TARGET_NR_geteuid:
ret = get_errno(high2lowuid(geteuid()));
break;
case TARGET_NR_getegid:
ret = get_errno(high2lowgid(getegid()));
break;
case TARGET_NR_setreuid:
ret = get_errno(setreuid(low2highuid(arg1), low2highuid(arg2)));
break;
case TARGET_NR_setregid:
ret = get_errno(setregid(low2highgid(arg1), low2highgid(arg2)));
break;
case TARGET_NR_getgroups:
{
int gidsetsize = arg1;
uint16_t *target_grouplist = (void *)arg2;
gid_t *grouplist;
int i;
grouplist = alloca(gidsetsize * sizeof(gid_t));
ret = get_errno(getgroups(gidsetsize, grouplist));
if (!is_error(ret)) {
for(i = 0;i < gidsetsize; i++)
target_grouplist[i] = tswap16(grouplist[i]);
}
}
break;
case TARGET_NR_setgroups:
{
int gidsetsize = arg1;
uint16_t *target_grouplist = (void *)arg2;
gid_t *grouplist;
int i;
grouplist = alloca(gidsetsize * sizeof(gid_t));
for(i = 0;i < gidsetsize; i++)
grouplist[i] = tswap16(target_grouplist[i]);
ret = get_errno(setgroups(gidsetsize, grouplist));
}
break;
case TARGET_NR_fchown:
ret = get_errno(fchown(arg1, low2highuid(arg2), low2highgid(arg3)));
break;
#ifdef TARGET_NR_setresuid
case TARGET_NR_setresuid:
ret = get_errno(setresuid(low2highuid(arg1),
low2highuid(arg2),
low2highuid(arg3)));
break;
#endif
#ifdef TARGET_NR_getresuid
case TARGET_NR_getresuid:
{
int ruid, euid, suid;
ret = get_errno(getresuid(&ruid, &euid, &suid));
if (!is_error(ret)) {
*(uint16_t *)arg1 = tswap16(high2lowuid(ruid));
*(uint16_t *)arg2 = tswap16(high2lowuid(euid));
*(uint16_t *)arg3 = tswap16(high2lowuid(suid));
}
}
break;
#endif
#ifdef TARGET_NR_getresgid
case TARGET_NR_setresgid:
ret = get_errno(setresgid(low2highgid(arg1),
low2highgid(arg2),
low2highgid(arg3)));
break;
#endif
#ifdef TARGET_NR_getresgid
case TARGET_NR_getresgid:
{
int rgid, egid, sgid;
ret = get_errno(getresgid(&rgid, &egid, &sgid));
if (!is_error(ret)) {
*(uint16_t *)arg1 = tswap16(high2lowgid(rgid));
*(uint16_t *)arg2 = tswap16(high2lowgid(egid));
*(uint16_t *)arg3 = tswap16(high2lowgid(sgid));
}
}
break;
#endif
case TARGET_NR_chown:
ret = get_errno(chown((const char *)arg1, low2highuid(arg2), low2highgid(arg3)));
break;
case TARGET_NR_setuid:
ret = get_errno(setuid(low2highuid(arg1)));
break;
case TARGET_NR_setgid:
ret = get_errno(setgid(low2highgid(arg1)));
break;
case TARGET_NR_setfsuid:
ret = get_errno(setfsuid(arg1));
break;
case TARGET_NR_setfsgid:
ret = get_errno(setfsgid(arg1));
break;
#endif /* USE_UID16 */
case TARGET_NR_lchown32:
ret = get_errno(lchown((const char *)arg1, arg2, arg3));
break;
@@ -2665,12 +2946,17 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
case TARGET_NR_setfsgid32:
ret = get_errno(setfsgid(arg1));
break;
case TARGET_NR_pivot_root:
goto unimplemented;
#ifdef TARGET_NR_mincore
case TARGET_NR_mincore:
goto unimplemented;
#endif
#ifdef TARGET_NR_madvise
case TARGET_NR_madvise:
goto unimplemented;
#endif
#if TARGET_LONG_BITS == 32
case TARGET_NR_fcntl64:
{
@@ -2708,6 +2994,11 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
#ifdef TARGET_NR_security
case TARGET_NR_security:
goto unimplemented;
#endif
#ifdef TARGET_NR_getpagesize
case TARGET_NR_getpagesize:
ret = TARGET_PAGE_SIZE;
break;
#endif
case TARGET_NR_gettid:
ret = get_errno(gettid());
@@ -2742,6 +3033,9 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
break;
}
fail:
#ifdef DEBUG
gemu_log(" = %ld\n", ret);
#endif
return ret;
}

View File

@@ -24,6 +24,19 @@
#define SOCKOP_sendmsg 16
#define SOCKOP_recvmsg 17
#define IPCOP_semop 1
#define IPCOP_semget 2
#define IPCOP_semctl 3
#define IPCOP_semtimedop 4
#define IPCOP_msgsnd 11
#define IPCOP_msgrcv 12
#define IPCOP_msgget 13
#define IPCOP_msgctl 14
#define IPCOP_shmat 21
#define IPCOP_shmdt 22
#define IPCOP_shmget 23
#define IPCOP_shmctl 24
/*
* The following is for compatibility across the various Linux
* platforms. The i386 ioctl numbering scheme doesn't really enforce
@@ -279,8 +292,9 @@ 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)
#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SPARC) || defined(TARGET_PPC)
#if !defined(TARGET_SPARC)
#define TARGET_SA_NOCLDSTOP 0x00000001
#define TARGET_SA_NOCLDWAIT 0x00000002 /* not supported yet */
#define TARGET_SA_SIGINFO 0x00000004
@@ -289,6 +303,57 @@ int do_sigaction(int sig, const struct target_sigaction *act,
#define TARGET_SA_NODEFER 0x40000000
#define TARGET_SA_RESETHAND 0x80000000
#define TARGET_SA_RESTORER 0x04000000
#else /* TARGET_SPARC */
#define TARGET_SA_NOCLDSTOP 8u
#define TARGET_SA_NOCLDWAIT 0x100u
#define TARGET_SA_SIGINFO 0x200u
#define TARGET_SA_ONSTACK 1u
#define TARGET_SA_RESTART 2u
#define TARGET_SA_NODEFER 0x20u
#define TARGET_SA_RESETHAND 4u
#endif
#if defined(TARGET_SPARC)
#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_SIGSTKFLT 7 /* actually EMT */
#define TARGET_SIGFPE 8
#define TARGET_SIGKILL 9
#define TARGET_SIGBUS 10
#define TARGET_SIGSEGV 11
#define TARGET_SIGSYS 12
#define TARGET_SIGPIPE 13
#define TARGET_SIGALRM 14
#define TARGET_SIGTERM 15
#define TARGET_SIGURG 16
#define TARGET_SIGSTOP 17
#define TARGET_SIGTSTP 18
#define TARGET_SIGCONT 19
#define TARGET_SIGCHLD 20
#define TARGET_SIGTTIN 21
#define TARGET_SIGTTOU 22
#define TARGET_SIGIO 23
#define TARGET_SIGXCPU 24
#define TARGET_SIGXFSZ 25
#define TARGET_SIGVTALRM 26
#define TARGET_SIGPROF 27
#define TARGET_SIGWINCH 28
#define TARGET_SIGPWR 29
#define TARGET_SIGUSR1 30
#define TARGET_SIGUSR2 31
#define TARGET_SIGRTMIN 32
#define TARGET_SIG_BLOCK 0x01 /* for blocking signals */
#define TARGET_SIG_UNBLOCK 0x02 /* for unblocking signals */
#define TARGET_SIG_SETMASK 0x04 /* for setting the signal mask */
#else
#define TARGET_SIGHUP 1
#define TARGET_SIGINT 2
@@ -328,6 +393,8 @@ int do_sigaction(int sig, const struct target_sigaction *act,
#define TARGET_SIG_UNBLOCK 1 /* for unblocking signals */
#define TARGET_SIG_SETMASK 2 /* for setting the signal mask */
#endif
struct target_old_sigaction {
target_ulong _sa_handler;
target_ulong sa_mask;
@@ -346,6 +413,30 @@ typedef union target_sigval {
int sival_int;
target_ulong sival_ptr;
} target_sigval_t;
#if 0
#if defined (TARGET_SPARC)
typedef struct {
struct {
target_ulong psr;
target_ulong pc;
target_ulong npc;
target_ulong y;
target_ulong u_regs[16]; /* globals and ins */
} si_regs;
int si_mask;
} __siginfo_t;
typedef struct {
unsigned long si_float_regs [32];
unsigned long si_fsr;
unsigned long si_fpqdepth;
struct {
unsigned long *insn_addr;
unsigned long insn;
} si_fpqueue [16];
} __siginfo_fpu_t;
#endif
#endif
#define TARGET_SI_MAX_SIZE 128
#define TARGET_SI_PAD_SIZE ((TARGET_SI_MAX_SIZE/sizeof(int)) - 3)
@@ -414,7 +505,14 @@ typedef struct target_siginfo {
/*
* SIGILL si_codes
*/
#define TARGET_ILL_ILLOPC (1) /* illegal opcode */
#define TARGET_ILL_ILLOPN (2) /* illegal operand */
#define TARGET_ILL_ILLADR (3) /* illegal addressing mode */
#define TARGET_ILL_ILLTRP (4) /* illegal trap */
#define TARGET_ILL_PRVOPC (5) /* privileged opcode */
#define TARGET_ILL_PRVREG (6) /* privileged register */
#define TARGET_ILL_COPROC (7) /* coprocessor error */
#define TARGET_ILL_BADSTK (8) /* internal stack error */
/*
* SIGFPE si_codes
@@ -435,6 +533,13 @@ typedef struct target_siginfo {
#define TARGET_SEGV_MAPERR (1) /* address not mapped to object */
#define TARGET_SEGV_ACCERR (2) /* invalid permissions for mapped object */
/*
* SIGBUS si_codes
*/
#define TARGET_BUS_ADRALN (1) /* invalid address alignment */
#define TARGET_BUS_ADRERR (2) /* non-existant physical address */
#define TARGET_BUS_OBJERR (3) /* object specific hardware error */
/*
* SIGTRAP si_codes
*/
@@ -664,220 +769,26 @@ struct target_pollfd {
#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 */
#define TARGET_NCC 8
struct target_termio {
unsigned short c_iflag; /* input mode flags */
unsigned short c_oflag; /* output mode flags */
unsigned short c_cflag; /* control mode flags */
unsigned short c_lflag; /* local mode flags */
unsigned char c_line; /* line discipline */
unsigned char c_cc[TARGET_NCC]; /* control characters */
};
/* c_iflag bits */
#define TARGET_IGNBRK 0000001
#define TARGET_BRKINT 0000002
#define TARGET_IGNPAR 0000004
#define TARGET_PARMRK 0000010
#define TARGET_INPCK 0000020
#define TARGET_ISTRIP 0000040
#define TARGET_INLCR 0000100
#define TARGET_IGNCR 0000200
#define TARGET_ICRNL 0000400
#define TARGET_IUCLC 0001000
#define TARGET_IXON 0002000
#define TARGET_IXANY 0004000
#define TARGET_IXOFF 0010000
#define TARGET_IMAXBEL 0020000
struct target_winsize {
unsigned short ws_row;
unsigned short ws_col;
unsigned short ws_xpixel;
unsigned short ws_ypixel;
};
/* c_oflag bits */
#define TARGET_OPOST 0000001
#define TARGET_OLCUC 0000002
#define TARGET_ONLCR 0000004
#define TARGET_OCRNL 0000010
#define TARGET_ONOCR 0000020
#define TARGET_ONLRET 0000040
#define TARGET_OFILL 0000100
#define TARGET_OFDEL 0000200
#define TARGET_NLDLY 0000400
#define TARGET_NL0 0000000
#define TARGET_NL1 0000400
#define TARGET_CRDLY 0003000
#define TARGET_CR0 0000000
#define TARGET_CR1 0001000
#define TARGET_CR2 0002000
#define TARGET_CR3 0003000
#define TARGET_TABDLY 0014000
#define TARGET_TAB0 0000000
#define TARGET_TAB1 0004000
#define TARGET_TAB2 0010000
#define TARGET_TAB3 0014000
#define TARGET_XTABS 0014000
#define TARGET_BSDLY 0020000
#define TARGET_BS0 0000000
#define TARGET_BS1 0020000
#define TARGET_VTDLY 0040000
#define TARGET_VT0 0000000
#define TARGET_VT1 0040000
#define TARGET_FFDLY 0100000
#define TARGET_FF0 0000000
#define TARGET_FF1 0100000
/* c_cflag bit meaning */
#define TARGET_CBAUD 0010017
#define TARGET_B0 0000000 /* hang up */
#define TARGET_B50 0000001
#define TARGET_B75 0000002
#define TARGET_B110 0000003
#define TARGET_B134 0000004
#define TARGET_B150 0000005
#define TARGET_B200 0000006
#define TARGET_B300 0000007
#define TARGET_B600 0000010
#define TARGET_B1200 0000011
#define TARGET_B1800 0000012
#define TARGET_B2400 0000013
#define TARGET_B4800 0000014
#define TARGET_B9600 0000015
#define TARGET_B19200 0000016
#define TARGET_B38400 0000017
#define TARGET_EXTA B19200
#define TARGET_EXTB B38400
#define TARGET_CSIZE 0000060
#define TARGET_CS5 0000000
#define TARGET_CS6 0000020
#define TARGET_CS7 0000040
#define TARGET_CS8 0000060
#define TARGET_CSTOPB 0000100
#define TARGET_CREAD 0000200
#define TARGET_PARENB 0000400
#define TARGET_PARODD 0001000
#define TARGET_HUPCL 0002000
#define TARGET_CLOCAL 0004000
#define TARGET_CBAUDEX 0010000
#define TARGET_B57600 0010001
#define TARGET_B115200 0010002
#define TARGET_B230400 0010003
#define TARGET_B460800 0010004
#define TARGET_CIBAUD 002003600000 /* input baud rate (not used) */
#define TARGET_CRTSCTS 020000000000 /* flow control */
/* c_lflag bits */
#define TARGET_ISIG 0000001
#define TARGET_ICANON 0000002
#define TARGET_XCASE 0000004
#define TARGET_ECHO 0000010
#define TARGET_ECHOE 0000020
#define TARGET_ECHOK 0000040
#define TARGET_ECHONL 0000100
#define TARGET_NOFLSH 0000200
#define TARGET_TOSTOP 0000400
#define TARGET_ECHOCTL 0001000
#define TARGET_ECHOPRT 0002000
#define TARGET_ECHOKE 0004000
#define TARGET_FLUSHO 0010000
#define TARGET_PENDIN 0040000
#define TARGET_IEXTEN 0100000
/* c_cc character offsets */
#define TARGET_VINTR 0
#define TARGET_VQUIT 1
#define TARGET_VERASE 2
#define TARGET_VKILL 3
#define TARGET_VEOF 4
#define TARGET_VTIME 5
#define TARGET_VMIN 6
#define TARGET_VSWTC 7
#define TARGET_VSTART 8
#define TARGET_VSTOP 9
#define TARGET_VSUSP 10
#define TARGET_VEOL 11
#define TARGET_VREPRINT 12
#define TARGET_VDISCARD 13
#define TARGET_VWERASE 14
#define TARGET_VLNEXT 15
#define TARGET_VEOL2 16
#include "termbits.h"
#define TARGET_MAP_SHARED 0x01 /* Share changes */
#define TARGET_MAP_PRIVATE 0x02 /* Changes are private */
@@ -891,6 +802,7 @@ struct target_termios {
#define TARGET_MAP_LOCKED 0x2000 /* pages are locked */
#define TARGET_MAP_NORESERVE 0x4000 /* don't check for reservations */
#if defined(TARGET_I386) || defined(TARGET_ARM)
struct target_stat {
unsigned short st_dev;
unsigned short __pad1;
@@ -951,7 +863,111 @@ struct target_stat64 {
unsigned long long st_ino;
} __attribute__((packed));
#endif /* defined(TARGET_I386) || defined(TARGET_ARM) */
#elif defined(TARGET_SPARC)
struct target_stat {
unsigned short st_dev;
target_ulong st_ino;
unsigned short st_mode;
short st_nlink;
unsigned short st_uid;
unsigned short st_gid;
unsigned short st_rdev;
target_long st_size;
target_long target_st_atime;
target_ulong __unused1;
target_long target_st_mtime;
target_ulong __unused2;
target_long target_st_ctime;
target_ulong __unused3;
target_long st_blksize;
target_long st_blocks;
target_ulong __unused4[2];
};
struct target_stat64 {
unsigned char __pad0[6];
unsigned short st_dev;
uint64_t st_ino;
unsigned int st_mode;
unsigned int st_nlink;
unsigned int st_uid;
unsigned int st_gid;
unsigned char __pad2[6];
unsigned short st_rdev;
unsigned char __pad3[8];
int64_t st_size;
unsigned int st_blksize;
unsigned char __pad4[8];
unsigned int st_blocks;
unsigned int target_st_atime;
unsigned int __unused1;
unsigned int target_st_mtime;
unsigned int __unused2;
unsigned int target_st_ctime;
unsigned int __unused3;
unsigned int __unused4;
unsigned int __unused5;
};
#elif defined(TARGET_PPC)
struct target_stat {
unsigned short st_dev;
target_ulong st_ino;
unsigned int st_mode;
unsigned short st_nlink;
unsigned int st_uid;
unsigned int st_gid;
unsigned short st_rdev;
target_ulong st_size;
target_ulong st_blksize;
target_ulong st_blocks;
target_ulong target_st_atime;
target_ulong __unused1;
target_ulong target_st_mtime;
target_ulong __unused2;
target_ulong target_st_ctime;
target_ulong __unused3;
target_ulong __unused4;
target_ulong __unused5;
};
struct target_stat64 {
unsigned long long st_dev;
unsigned long long st_ino;
unsigned int st_mode;
unsigned int st_nlink;
unsigned int st_uid;
unsigned int st_gid;
unsigned long long st_rdev;
long long pad0;
long long st_size;
target_ulong st_blksize;
target_ulong pad1;
long long st_blocks; /* Number 512-byte blocks allocated. */
target_ulong target_st_atime;
target_ulong target_st_atime_nsec;
target_ulong target_st_mtime;
target_ulong target_st_mtime_nsec;
target_ulong target_st_ctime;
target_ulong target_st_ctime_nsec;
target_ulong __unused4;
target_ulong __unused5;
};
#endif /* defined(TARGET_PPC) */
#define TARGET_F_DUPFD 0 /* dup */
#define TARGET_F_GETFD 1 /* get close_on_exec */
@@ -980,6 +996,80 @@ struct target_stat64 {
#define TARGET_F_SETLK64 13
#define TARGET_F_SETLKW64 14
#if defined (TARGET_ARM)
#define TARGET_O_ACCMODE 0003
#define TARGET_O_RDONLY 00
#define TARGET_O_WRONLY 01
#define TARGET_O_RDWR 02
#define TARGET_O_CREAT 0100 /* not fcntl */
#define TARGET_O_EXCL 0200 /* not fcntl */
#define TARGET_O_NOCTTY 0400 /* not fcntl */
#define TARGET_O_TRUNC 01000 /* not fcntl */
#define TARGET_O_APPEND 02000
#define TARGET_O_NONBLOCK 04000
#define TARGET_O_NDELAY O_NONBLOCK
#define TARGET_O_SYNC 010000
#define TARGET_FASYNC 020000 /* fcntl, for BSD compatibility */
#define TARGET_O_DIRECTORY 040000 /* must be a directory */
#define TARGET_O_NOFOLLOW 0100000 /* don't follow links */
#define TARGET_O_DIRECT 0200000 /* direct disk access hint */
#define TARGET_O_LARGEFILE 0400000
#elif defined (TARGET_PPC)
#define TARGET_O_ACCMODE 0003
#define TARGET_O_RDONLY 00
#define TARGET_O_WRONLY 01
#define TARGET_O_RDWR 02
#define TARGET_O_CREAT 0100 /* not fcntl */
#define TARGET_O_EXCL 0200 /* not fcntl */
#define TARGET_O_NOCTTY 0400 /* not fcntl */
#define TARGET_O_TRUNC 01000 /* not fcntl */
#define TARGET_O_APPEND 02000
#define TARGET_O_NONBLOCK 04000
#define TARGET_O_NDELAY O_NONBLOCK
#define TARGET_O_SYNC 010000
#define TARGET_FASYNC 020000 /* fcntl, for BSD compatibility */
#define TARGET_O_DIRECTORY 040000 /* must be a directory */
#define TARGET_O_NOFOLLOW 0100000 /* don't follow links */
#define TARGET_O_LARGEFILE 0200000
#define TARGET_O_DIRECT 0400000 /* direct disk access hint */
#elif defined (TARGET_SPARC)
#define TARGET_O_RDONLY 0x0000
#define TARGET_O_WRONLY 0x0001
#define TARGET_O_RDWR 0x0002
#define TARGET_O_ACCMODE 0x0003
#define TARGET_O_APPEND 0x0008
#define TARGET_FASYNC 0x0040 /* fcntl, for BSD compatibility */
#define TARGET_O_CREAT 0x0200 /* not fcntl */
#define TARGET_O_TRUNC 0x0400 /* not fcntl */
#define TARGET_O_EXCL 0x0800 /* not fcntl */
#define TARGET_O_SYNC 0x2000
#define TARGET_O_NONBLOCK 0x4000
#define TARGET_O_NDELAY (0x0004 | O_NONBLOCK)
#define TARGET_O_NOCTTY 0x8000 /* not fcntl */
#define TARGET_O_DIRECTORY 0x10000 /* must be a directory */
#define TARGET_O_NOFOLLOW 0x20000 /* don't follow links */
#define TARGET_O_LARGEFILE 0x40000
#define TARGET_O_DIRECT 0x100000 /* direct disk access hint */
#else
#define TARGET_O_ACCMODE 0003
#define TARGET_O_RDONLY 00
#define TARGET_O_WRONLY 01
#define TARGET_O_RDWR 02
#define TARGET_O_CREAT 0100 /* not fcntl */
#define TARGET_O_EXCL 0200 /* not fcntl */
#define TARGET_O_NOCTTY 0400 /* not fcntl */
#define TARGET_O_TRUNC 01000 /* not fcntl */
#define TARGET_O_APPEND 02000
#define TARGET_O_NONBLOCK 04000
#define TARGET_O_NDELAY O_NONBLOCK
#define TARGET_O_SYNC 010000
#define TARGET_FASYNC 020000 /* fcntl, for BSD compatibility */
#define TARGET_O_DIRECT 040000 /* direct disk access hint */
#define TARGET_O_LARGEFILE 0100000
#define TARGET_O_DIRECTORY 0200000 /* must be a directory */
#define TARGET_O_NOFOLLOW 0400000 /* don't follow links */
#endif
struct target_flock {
short l_type;
short l_whence;
@@ -1139,3 +1229,20 @@ struct target_flock64 {
/* vfat ioctls */
#define TARGET_VFAT_IOCTL_READDIR_BOTH TARGET_IORU('r', 1)
#define TARGET_VFAT_IOCTL_READDIR_SHORT TARGET_IORU('r', 2)
struct target_sysinfo {
target_long uptime; /* Seconds since boot */
target_ulong loads[3]; /* 1, 5, and 15 minute load averages */
target_ulong totalram; /* Total usable main memory size */
target_ulong freeram; /* Available memory size */
target_ulong sharedram; /* Amount of shared memory */
target_ulong bufferram; /* Memory used by buffers */
target_ulong totalswap; /* Total swap space size */
target_ulong freeswap; /* swap space still available */
unsigned short procs; /* Number of current processes */
unsigned short pad; /* explicit padding for m68k */
target_ulong totalhigh; /* Total high memory size */
target_ulong freehigh; /* Available high memory size */
unsigned int mem_unit; /* Memory unit size in bytes */
char _f[20-2*sizeof(target_long)-sizeof(int)]; /* Padding: libc5 uses this.. */
};

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