Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2f5ab9e8cd | ||
|
|
c72a345f5b | ||
|
|
102a52e471 | ||
|
|
c76338c34f | ||
|
|
bf2b84e4a7 | ||
|
|
9f059eca52 | ||
|
|
53360e00e2 | ||
|
|
ef6ff6b71e | ||
|
|
546fa6abd1 | ||
|
|
e875c40a15 | ||
|
|
a98d49b136 | ||
|
|
44a095a77c | ||
|
|
15b6147000 | ||
|
|
9e89a4be8e | ||
|
|
61a8c4ec3a | ||
|
|
9746b15b4e | ||
|
|
7372f88dc1 | ||
|
|
d7382233d8 | ||
|
|
fb065187e4 | ||
|
|
bf71c9d9b6 | ||
|
|
7a987127f4 | ||
|
|
e0fe67aa72 | ||
|
|
f6c958c865 | ||
|
|
9bb34eac8b | ||
|
|
85571bc741 | ||
|
|
8f46820d92 | ||
|
|
dbb2c92142 | ||
|
|
0d1a29f9fc | ||
|
|
b8b5ac6376 | ||
|
|
40b6ecc6bc | ||
|
|
f3ff649d3b | ||
|
|
953569d21b | ||
|
|
a0c4cb4a70 | ||
|
|
188d857911 | ||
|
|
9bc9d1c75a | ||
|
|
8926b517e9 | ||
|
|
6d46bf8ae3 | ||
|
|
032a8c9e35 | ||
|
|
a7dfe172fa | ||
|
|
7fe48483cd | ||
|
|
8e3a9fd280 | ||
|
|
d75d9f6be9 | ||
|
|
769bec7271 | ||
|
|
655aa52a90 | ||
|
|
ba6c23778c | ||
|
|
4b19ec0c2b | ||
|
|
e388818682 | ||
|
|
02d2c54cd3 | ||
|
|
890fa6bebb | ||
|
|
a4c4785b93 | ||
|
|
7993f8bc51 | ||
|
|
8d5f07fa3b | ||
|
|
023fcb9507 | ||
|
|
a5ba1ca608 | ||
|
|
b769d8fef6 | ||
|
|
32ff25bf68 | ||
|
|
f98593103b | ||
|
|
30ca2aab8e | ||
|
|
8a8a608f6e | ||
|
|
d63d307f6e | ||
|
|
487be8a1a7 | ||
|
|
2518bd0dc2 | ||
|
|
e95c8d51c2 | ||
|
|
4971b827da | ||
|
|
420557e898 | ||
|
|
6d5e216de9 | ||
|
|
e8af50a30e | ||
|
|
525d67bcc8 | ||
|
|
d981b88344 | ||
|
|
4a4883b84d | ||
|
|
16c460b154 | ||
|
|
0ecf89aae3 | ||
|
|
28d34b8246 | ||
|
|
3c56521b70 | ||
|
|
096b7ea42b | ||
|
|
d5a8f07c52 | ||
|
|
345fbaa3ca | ||
|
|
1d96905d76 | ||
|
|
99679ececc | ||
|
|
eb45f5fec4 | ||
|
|
b86bda5bb1 | ||
|
|
e2731add29 | ||
|
|
c9a621176e | ||
|
|
cf720db33a | ||
|
|
29e619b1e8 | ||
|
|
6f28fb86c9 | ||
|
|
c94c8d6499 | ||
|
|
01038d2a76 | ||
|
|
03ffbb69a8 | ||
|
|
a3d4af03bb | ||
|
|
9d728e8c4e | ||
|
|
36d54d15e1 | ||
|
|
c4dfa5b7be | ||
|
|
75c2380584 | ||
|
|
7c08dbf325 | ||
|
|
9bf05444b2 | ||
|
|
a3504c87ca | ||
|
|
7143c62c95 | ||
|
|
4e8b5da233 | ||
|
|
c7f746434f | ||
|
|
60e336dbb8 | ||
|
|
8d11df9e5a | ||
|
|
05d5818c5c | ||
|
|
cabf23c380 | ||
|
|
e82d8ade13 | ||
|
|
d2bfb39ad2 | ||
|
|
3611a29c09 | ||
|
|
0f6e3eb211 | ||
|
|
57d1a2b62c | ||
|
|
d5249393ef | ||
|
|
11c0315f9b | ||
|
|
a3fb0cf907 | ||
|
|
ea2384d36e | ||
|
|
e4d4fe3c34 | ||
|
|
5905b2e5fd | ||
|
|
7e2515e87c | ||
|
|
3d2cfdf169 | ||
|
|
6fcfafb742 | ||
|
|
af8ffdfd2b | ||
|
|
b932caba32 | ||
|
|
3eb2619fe5 | ||
|
|
3e11db9a0c | ||
|
|
c6f37d0e4f | ||
|
|
a0a821a4c0 | ||
|
|
49b3b9fb1a | ||
|
|
e7f0ad58c1 | ||
|
|
82c643ff50 | ||
|
|
457831f4bc | ||
|
|
2571929a77 | ||
|
|
81d0912d2d | ||
|
|
d1d9f42119 | ||
|
|
450e18b8b8 | ||
|
|
3db38e87a0 | ||
|
|
379ff53dc9 | ||
|
|
ce93da6ffe | ||
|
|
ee2654ac24 | ||
|
|
354ff22657 | ||
|
|
6b65279459 | ||
|
|
12c28fed49 | ||
|
|
38f0b147a5 | ||
|
|
bec9d989db | ||
|
|
cab84d9844 | ||
|
|
1b039c09fe | ||
|
|
fbf59244b8 | ||
|
|
fa36761d7f | ||
|
|
d08c49aae0 | ||
|
|
fcc941fe20 | ||
|
|
96bcd4f884 | ||
|
|
e3371e62f3 | ||
|
|
82eec0a174 | ||
|
|
933dc6ebc4 | ||
|
|
1e6cae953d | ||
|
|
6d463de2b3 | ||
|
|
bbbc4663d1 | ||
|
|
02e1ec9bc4 | ||
|
|
3df3f6fd7b | ||
|
|
2c6ab8329e | ||
|
|
675376f2b4 | ||
|
|
15a34c6364 | ||
|
|
1bfe856eb2 | ||
|
|
7e71f16f9a | ||
|
|
38a64f9dfe | ||
|
|
e02aa6869e | ||
|
|
7db4eea691 | ||
|
|
b30d4608da | ||
|
|
81ca79911a | ||
|
|
e58d12ed5b | ||
|
|
d549f7d98f | ||
|
|
83fb7adf6c | ||
|
|
1d43a71773 | ||
|
|
ae184e4ab7 | ||
|
|
e6eccb38eb | ||
|
|
9da9886121 | ||
|
|
a1968d7196 | ||
|
|
7f5d44e0ff | ||
|
|
acf5feac80 | ||
|
|
d187d4b218 | ||
|
|
9808745072 | ||
|
|
02ba45c536 | ||
|
|
107db44327 | ||
|
|
dc5d0b3d1b | ||
|
|
7496f5266c | ||
|
|
91d848ebf3 | ||
|
|
e2733d20b2 | ||
|
|
637f6cd735 | ||
|
|
638260eb8e | ||
|
|
30468f786c | ||
|
|
46e50e9d58 | ||
|
|
7c29d0c0cf | ||
|
|
514fb8c10e | ||
|
|
53c862a88e | ||
|
|
b6b8bd1819 | ||
|
|
fd0bbb12c3 | ||
|
|
f2aa58c6f4 | ||
|
|
611493d966 | ||
|
|
e1bb04f740 | ||
|
|
1ade1de223 | ||
|
|
b0bda528c3 | ||
|
|
819e712bfe | ||
|
|
28b9b5af25 | ||
|
|
e9b137c2dd | ||
|
|
95ea3fa19c | ||
|
|
7587cf4401 | ||
|
|
7086749072 | ||
|
|
63b7e03697 | ||
|
|
678f2df60f | ||
|
|
9e57f14d60 | ||
|
|
987c1c6921 | ||
|
|
ffddfee379 | ||
|
|
a2f659ee48 | ||
|
|
d7d02e3c3a | ||
|
|
bb0c6722b6 | ||
|
|
979a54fb20 | ||
|
|
e4f9082b9a | ||
|
|
d95dc32d13 | ||
|
|
53ad66e8c3 | ||
|
|
eba2af633f | ||
|
|
95ce326e5b | ||
|
|
a5448a7de5 | ||
|
|
9231944d96 | ||
|
|
d69d1fa01a | ||
|
|
05efe46eaa | ||
|
|
dbda808a4a | ||
|
|
a049791855 | ||
|
|
ea1c18022e | ||
|
|
516633dc42 | ||
|
|
dc196a57e3 | ||
|
|
2a2820560d | ||
|
|
665656a99b | ||
|
|
658c8bdadc | ||
|
|
5fef40fb4d | ||
|
|
e69390cee7 | ||
|
|
7f647cf68f | ||
|
|
a130a41e69 | ||
|
|
78e127efdb | ||
|
|
ee38b4c813 | ||
|
|
3440557b6d | ||
|
|
d329a6fb22 | ||
|
|
7ebb5e4139 | ||
|
|
57ccbabecb | ||
|
|
eb26db16d7 | ||
|
|
4c8732d71b | ||
|
|
1cc98a5f04 | ||
|
|
de9258a87f | ||
|
|
37f53b4c05 | ||
|
|
a8aa669ba4 | ||
|
|
a5082316e9 | ||
|
|
20ba3ae101 | ||
|
|
4c7634bcb3 | ||
|
|
a21ae81d8a | ||
|
|
aeb3c85f59 | ||
|
|
1f04275ec1 | ||
|
|
4e3e9d0b4d | ||
|
|
358c640721 | ||
|
|
e36f36e15f | ||
|
|
7b17d41e96 | ||
|
|
d6bfa22f72 | ||
|
|
e6e5ad80d8 | ||
|
|
798b0c25cc | ||
|
|
22a56b8a87 | ||
|
|
44bbf73f92 | ||
|
|
00ffa62a91 | ||
|
|
de2200d36d | ||
|
|
710c15a2e9 | ||
|
|
443f1376bc | ||
|
|
a3a91a355b | ||
|
|
ab2572d7ea | ||
|
|
267002cd28 | ||
|
|
63066f4f13 | ||
|
|
caf9a12e9a | ||
|
|
1f62d9383f | ||
|
|
7727994d21 | ||
|
|
8a8696a3c4 | ||
|
|
8998028497 | ||
|
|
a4193c8a4b | ||
|
|
170c6f8705 | ||
|
|
43f493afb4 | ||
|
|
ee22c2f7db | ||
|
|
be3edd9590 | ||
|
|
023fe10d24 | ||
|
|
f66723fab9 | ||
|
|
8cc43feffc | ||
|
|
09a79b4974 | ||
|
|
642012017c | ||
|
|
2444ca413b | ||
|
|
77d4bc349a | ||
|
|
a2a444d6e0 | ||
|
|
4b3686faee | ||
|
|
85c4adf65f | ||
|
|
b69fedff84 | ||
|
|
5fd386f698 | ||
|
|
0ced658970 | ||
|
|
b415a4078d | ||
|
|
f18ac341fe | ||
|
|
63ce9e0a42 | ||
|
|
e1c485be84 | ||
|
|
34e538ae5d | ||
|
|
9995c51ffd | ||
|
|
e58a7c24ac | ||
|
|
777428f2d2 | ||
|
|
5b60212f2a | ||
|
|
a00bad7ed4 | ||
|
|
25b42e9d53 | ||
|
|
8d6c7eb896 | ||
|
|
7bf5be70f7 | ||
|
|
fb9f944458 | ||
|
|
92e873b996 | ||
|
|
9fddaa0c0c | ||
|
|
4a0fb71e67 | ||
|
|
274da6b24b | ||
|
|
15aeac3805 | ||
|
|
28ab0e2edb | ||
|
|
b54ad0498e | ||
|
|
4399059e4d | ||
|
|
43003046cb | ||
|
|
d157e205e9 | ||
|
|
5f21aef2b0 | ||
|
|
829309c70c | ||
|
|
c6a1c22ba6 | ||
|
|
b71e95fc2c | ||
|
|
04a3b84c83 | ||
|
|
86e0c04896 | ||
|
|
5ce276a11a | ||
|
|
5768f5aca6 | ||
|
|
1078f663ae | ||
|
|
0ac32c8375 | ||
|
|
4a9c9687c6 | ||
|
|
73c11f630b | ||
|
|
660de33686 | ||
|
|
69135b5c04 | ||
|
|
69b910399a | ||
|
|
158156d13d | ||
|
|
e63c59cb34 | ||
|
|
13ab5daa86 | ||
|
|
ef792f9ddb | ||
|
|
47cea614a1 | ||
|
|
aedf53821f | ||
|
|
7f5e145212 | ||
|
|
f528bfd45d | ||
|
|
686f3f266b | ||
|
|
5b1214a48e | ||
|
|
3f433d2c87 | ||
|
|
1a084f3d51 | ||
|
|
cd6f11693a | ||
|
|
b939777cec | ||
|
|
d6b86f4d85 | ||
|
|
3a1bc175ea | ||
|
|
db45c29a65 | ||
|
|
7d3505c55a | ||
|
|
fd872598d8 | ||
|
|
8cd0ac2fe1 | ||
|
|
7efa43875d | ||
|
|
44c513c4c9 | ||
|
|
2ee73ac3a8 | ||
|
|
28c3ee3fed | ||
|
|
f929aad6e3 | ||
|
|
e309de25a6 | ||
|
|
10d315a8f2 | ||
|
|
2b64948eb5 | ||
|
|
1f50f8d1d4 | ||
|
|
a1b74fe8fe | ||
|
|
ed5fd2cce4 | ||
|
|
bee3290936 | ||
|
|
beddab753d | ||
|
|
512176dbd8 | ||
|
|
fb6cf1d09c | ||
|
|
66201e2ddf | ||
|
|
ec844b96c0 | ||
|
|
f72e8ff4a6 | ||
|
|
b06eddd39d | ||
|
|
6f51f6b593 | ||
|
|
0294ffb9c8 | ||
|
|
d8d8aa4e2c | ||
|
|
141253b254 | ||
|
|
646be93b4c | ||
|
|
26aa7d72cc | ||
|
|
8e9c4afe70 | ||
|
|
bbc9d34839 | ||
|
|
a8c490cda5 | ||
|
|
4606bb3f06 | ||
|
|
aaaa7df625 | ||
|
|
9d4fb82e3c | ||
|
|
9fafc9eaf0 | ||
|
|
1ef59d0acf | ||
|
|
7fd7b91fac | ||
|
|
d927637dca | ||
|
|
4f2ac23784 | ||
|
|
f658b4db79 | ||
|
|
0c4ad8dc2a | ||
|
|
165c6fc8ce | ||
|
|
2e12669a4c | ||
|
|
52c00a5f15 | ||
|
|
ab6d960ffa | ||
|
|
fbf9eeb34d | ||
|
|
046d6672e2 | ||
|
|
75dfaa1e64 | ||
|
|
1115dde719 | ||
|
|
57206fd42a | ||
|
|
4c27ba27c5 | ||
|
|
ba91cd80d5 | ||
|
|
6f1f31c069 | ||
|
|
5467a72294 | ||
|
|
1b8eb456eb | ||
|
|
d720b93d0b | ||
|
|
eeab3a558f | ||
|
|
658138bcbc | ||
|
|
1190935d98 | ||
|
|
bfbc9133eb | ||
|
|
ad6a4837f8 | ||
|
|
039d3da365 | ||
|
|
a7e61ed446 | ||
|
|
b5075d29a8 | ||
|
|
91caaa612a | ||
|
|
d64477afa1 | ||
|
|
f6bac3809f | ||
|
|
f0cbd3ec9f | ||
|
|
7c1f25b46a | ||
|
|
ee9dbb297d | ||
|
|
c20709aa32 | ||
|
|
92cb7d5423 | ||
|
|
202a456a2b | ||
|
|
3294b949eb | ||
|
|
2aebb3eb2b | ||
|
|
95917e3f57 | ||
|
|
f186904281 | ||
|
|
c5df018e56 | ||
|
|
a541f297a3 | ||
|
|
df475d18d8 | ||
|
|
2f0c934ef9 | ||
|
|
fd836909df | ||
|
|
289e09e77b | ||
|
|
7ae9862745 | ||
|
|
41b9be476c | ||
|
|
52302d7274 | ||
|
|
333190eb97 | ||
|
|
eccabc6ee0 | ||
|
|
bb058620c3 | ||
|
|
9eb153f18f | ||
|
|
aaba6c1516 | ||
|
|
38e205a25b | ||
|
|
e1a237441d | ||
|
|
57c3072482 | ||
|
|
73332e5ccd | ||
|
|
1f673135ac | ||
|
|
aa455485c9 | ||
|
|
9307c4c1d9 | ||
|
|
40c3bac35a | ||
|
|
6eaee46144 | ||
|
|
0f2f112156 | ||
|
|
4721c45750 | ||
|
|
a6e022ad13 | ||
|
|
702c651c4a | ||
|
|
1154e441aa | ||
|
|
e463b581ea | ||
|
|
11d9f695e7 | ||
|
|
0c607d5728 | ||
|
|
67b915a5dd | ||
|
|
bb27c19087 | ||
|
|
8a7ddc38a6 | ||
|
|
b0a21b5334 | ||
|
|
dff38e7b40 | ||
|
|
1f1af9fd7f | ||
|
|
858693c638 | ||
|
|
9b14bb04ca | ||
|
|
c101c49c54 | ||
|
|
4bb2fcc7c9 | ||
|
|
08cea4eef8 | ||
|
|
883da8e219 | ||
|
|
78ebca6e13 | ||
|
|
5e2a644399 | ||
|
|
11774f549e | ||
|
|
d9d849fc5d | ||
|
|
e19e89a5d4 | ||
|
|
f193c7979c | ||
|
|
3035f7ff83 | ||
|
|
4afa64828b | ||
|
|
c45c3d0059 | ||
|
|
baca51faff | ||
|
|
bc51c5c989 | ||
|
|
5069146392 | ||
|
|
59a983b921 | ||
|
|
4e463d8d50 | ||
|
|
94fe4f9fa3 | ||
|
|
0fb48229a7 | ||
|
|
b41a2cd1e4 | ||
|
|
c4b1fcc0f9 | ||
|
|
0f35920cd8 | ||
|
|
7d977de7e1 | ||
|
|
07d898662d | ||
|
|
caed880216 | ||
|
|
b338082b3f | ||
|
|
9dc39cbae3 | ||
|
|
80cabfad16 | ||
|
|
38ca2abc2e | ||
|
|
73bdea1951 | ||
|
|
00af2b2680 | ||
|
|
a735aa3139 | ||
|
|
6b2b6112f8 | ||
|
|
bf08806145 | ||
|
|
f9e92e973f | ||
|
|
8dc75d7535 | ||
|
|
03857e318e | ||
|
|
16f62432c4 | ||
|
|
8b1f24b090 | ||
|
|
b448f2f36c | ||
|
|
97eb5b14dc | ||
|
|
7eee2a509a | ||
|
|
42c3c0cced | ||
|
|
9588b95a08 | ||
|
|
2edcdce334 | ||
|
|
8853f86e1d | ||
|
|
e374bfa35b | ||
|
|
b88e4a9a3b | ||
|
|
537730b956 | ||
|
|
edf779ffcc | ||
|
|
121061dcdf | ||
|
|
83d7396850 | ||
|
|
6b2d3e3c96 | ||
|
|
e98a6e40a9 | ||
|
|
28fbe299c3 | ||
|
|
297d8e6227 | ||
|
|
004bc62c28 | ||
|
|
ed1c0bcb0c | ||
|
|
22a46c55e4 | ||
|
|
ea88812f4f | ||
|
|
58fe2f10f0 | ||
|
|
3a1d9b8bbb | ||
|
|
0e4b179d33 | ||
|
|
77fef8c148 | ||
|
|
59817ccb2c | ||
|
|
bf3e8bf11e | ||
|
|
9acbed0605 | ||
|
|
cf98951b82 | ||
|
|
f72b519c86 | ||
|
|
07ce05eaa9 | ||
|
|
b324e814a9 | ||
|
|
c69810559b | ||
|
|
28c4f361ac | ||
|
|
3d57da2a70 | ||
|
|
00406dff19 | ||
|
|
69de927c6c | ||
|
|
72cbca10e1 | ||
|
|
34f715e754 | ||
|
|
cae61cef89 | ||
|
|
6411cfb6f3 | ||
|
|
898712a85c | ||
|
|
4fa0f5d292 | ||
|
|
1ccde1cb94 | ||
|
|
ad08132319 | ||
|
|
415e561f1d | ||
|
|
ee8b7021da | ||
|
|
625976dac8 | ||
|
|
1ac157da77 | ||
|
|
64a595f26a | ||
|
|
3ad9a57e4f | ||
|
|
7f777bf385 | ||
|
|
56bf1d37a0 | ||
|
|
c92b2e845f | ||
|
|
68e73e391f | ||
|
|
c0637b3794 | ||
|
|
e98c87213e | ||
|
|
3d4b4c0f4b | ||
|
|
8145122b08 | ||
|
|
7399c5a9be | ||
|
|
10f0e412f8 | ||
|
|
4b7aba5173 | ||
|
|
35b66fc4f9 | ||
|
|
13eb76e091 | ||
|
|
3cf1e035ba | ||
|
|
a6b025d37d | ||
|
|
edfcbd9937 | ||
|
|
612b477d48 | ||
|
|
6c9bf8936a | ||
|
|
bb551faa4a | ||
|
|
a136e5a8b1 | ||
|
|
4796f5e9bc | ||
|
|
3504fe171b | ||
|
|
ab1f142ba0 | ||
|
|
4120b61d00 | ||
|
|
7f957d280b | ||
|
|
2be3bc02dd | ||
|
|
c27357906a | ||
|
|
985a19d6d1 | ||
|
|
3f5dcc340c | ||
|
|
f09936ac82 | ||
|
|
d030931173 | ||
|
|
825bd5f8e5 | ||
|
|
bc0b1dc1eb | ||
|
|
630be16f6c | ||
|
|
44a91cae10 | ||
|
|
d575b78aab | ||
|
|
6e44ba7fa2 | ||
|
|
6986f88c3f | ||
|
|
988578886e | ||
|
|
c4c7e3e610 | ||
|
|
b516f85ca8 | ||
|
|
1e4fe7cee2 | ||
|
|
debf7a7c7e | ||
|
|
5a1388b6df | ||
|
|
777aca2fd3 | ||
|
|
69e5bc9068 | ||
|
|
c8135d9af6 | ||
|
|
9e62fd7f26 | ||
|
|
8977f3c107 | ||
|
|
728c9fd5a9 | ||
|
|
bd49793889 | ||
|
|
16d17fdb8e | ||
|
|
4487d0ac49 | ||
|
|
7138fcfbf7 | ||
|
|
c45886db19 | ||
|
|
ffa65c3b70 | ||
|
|
2d603d2216 | ||
|
|
61190b14fc | ||
|
|
9886cc165a | ||
|
|
ce09776be2 | ||
|
|
5be1a8e065 | ||
|
|
09683d3597 | ||
|
|
590b7eed18 | ||
|
|
af5ad10728 | ||
|
|
ac9eb0731a | ||
|
|
9a64fbe4d8 | ||
|
|
efe160c502 | ||
|
|
dc887a4dae | ||
|
|
b9f1950797 | ||
|
|
e16c53fabb | ||
|
|
8351d2d481 | ||
|
|
08785f48b7 | ||
|
|
75c6215f98 | ||
|
|
6b136f9e8f | ||
|
|
2ddbbd10de | ||
|
|
9fa3e85353 | ||
|
|
4390df5107 | ||
|
|
ecd854fdb4 | ||
|
|
513b500f75 | ||
|
|
edf75d592c | ||
|
|
1376847f9f | ||
|
|
17348a7f5e | ||
|
|
4f31916ffb | ||
|
|
943144d91a | ||
|
|
34e01bbf07 | ||
|
|
7f1135b9a4 | ||
|
|
f68dd77007 | ||
|
|
436d8b892a | ||
|
|
dc6f57fd55 | ||
|
|
65262d5738 | ||
|
|
773b93ee06 | ||
|
|
82c7e2a4c6 | ||
|
|
546cdbd77d | ||
|
|
c265508067 | ||
|
|
dd4e27d810 | ||
|
|
a41bc9af8f | ||
|
|
3bfd9da14f | ||
|
|
c573ff6752 | ||
|
|
060366c5ad | ||
|
|
6da41eafc4 | ||
|
|
0124311e00 | ||
|
|
f515528907 | ||
|
|
b453b70bd8 | ||
|
|
0ac4bd56a8 | ||
|
|
3811a291e2 | ||
|
|
3415a4ddb4 | ||
|
|
b7f0f463a5 | ||
|
|
8e682019e3 | ||
|
|
cf495bcf9f | ||
|
|
fb0eaffc6d | ||
|
|
07ad1b93a3 | ||
|
|
d36cd60e6c | ||
|
|
5e809a8095 | ||
|
|
791c2261d6 | ||
|
|
163a7cb620 | ||
|
|
6bb705711b | ||
|
|
4136f33c7e | ||
|
|
6dca2016fc | ||
|
|
678673089d | ||
|
|
28b6751f30 | ||
|
|
79aceca54a | ||
|
|
6a8c397deb | ||
|
|
9cdf757fd5 | ||
|
|
36bdbe5479 | ||
|
|
8004340674 | ||
|
|
a2cc3b2433 | ||
|
|
afa05eb15e | ||
|
|
de5eaa6452 | ||
|
|
7517502475 | ||
|
|
8f2b1fb008 | ||
|
|
891b38e446 | ||
|
|
7dea1da4ae | ||
|
|
4ce900b44c | ||
|
|
f3f2d9be03 | ||
|
|
77729c2445 | ||
|
|
d71b9a8b2f | ||
|
|
181f1558cd | ||
|
|
2750332396 | ||
|
|
f115e911d7 | ||
|
|
3ab493de4c | ||
|
|
3e25f9515a | ||
|
|
246d897f4c | ||
|
|
7e84c2498f | ||
|
|
e670b89e3b | ||
|
|
bd0d90b21d | ||
|
|
1a0636f8d7 | ||
|
|
2e134c9c55 | ||
|
|
5391d80669 | ||
|
|
36b486bb74 | ||
|
|
4ad06a29b2 | ||
|
|
e58143b355 | ||
|
|
1f5476fcce | ||
|
|
461c0471af | ||
|
|
9c3ad57432 | ||
|
|
e748ba4f53 | ||
|
|
b8ed223bfe | ||
|
|
c970a162e7 | ||
|
|
c321f67309 | ||
|
|
7f7f987341 | ||
|
|
aebcb60e55 | ||
|
|
1a18c71b50 | ||
|
|
03a6c5103d | ||
|
|
128b346e0a | ||
|
|
415fa2ea77 | ||
|
|
9951bf39f9 | ||
|
|
8948b5d613 | ||
|
|
5086347239 | ||
|
|
9d4520d0e0 | ||
|
|
5b9f457a89 | ||
|
|
3a4739d651 | ||
|
|
76b62fd001 | ||
|
|
b1f645758a | ||
|
|
bc1b050d85 | ||
|
|
03d5f74aee | ||
|
|
9f05cc34df | ||
|
|
285dc330bd | ||
|
|
baf8ebf01a | ||
|
|
9d16dd550e | ||
|
|
78d6da976c | ||
|
|
dd6ee15c37 | ||
|
|
0db634747e | ||
|
|
6e59c1db89 | ||
|
|
61382a500a | ||
|
|
3a51dee658 | ||
|
|
cc38b844d7 | ||
|
|
c6105c0a04 | ||
|
|
93a40ea926 | ||
|
|
db8d746688 | ||
|
|
997344f303 | ||
|
|
16e9b7de41 | ||
|
|
3486513433 | ||
|
|
0806e3f66f | ||
|
|
39b4da28b3 | ||
|
|
5a67135a0b | ||
|
|
42f1e0e49b | ||
|
|
27c3f2cb9b | ||
|
|
a07cf92aed | ||
|
|
01e3b763a6 | ||
|
|
0ae04d7367 | ||
|
|
ebc054881f | ||
|
|
a20dd508aa | ||
|
|
6180a1818a | ||
|
|
d3eead2eec | ||
|
|
853d6f7a83 | ||
|
|
93ac68bca5 | ||
|
|
1e43adfc89 | ||
|
|
7a3f194486 | ||
|
|
2c0262afa7 | ||
|
|
196ad10903 | ||
|
|
b7dda06abf | ||
|
|
fcf8fcc8e5 | ||
|
|
dbc5594cb6 | ||
|
|
4cbb86e1c4 | ||
|
|
f513a41a3d | ||
|
|
c106152d26 | ||
|
|
facc68be25 | ||
|
|
3ff0631ed9 | ||
|
|
b1ba65744e | ||
|
|
b67d59594e | ||
|
|
2e255c6b9f | ||
|
|
3f33731662 | ||
|
|
d05e66d217 | ||
|
|
2d80ae8987 | ||
|
|
17383a2a2a | ||
|
|
9257a9e49c | ||
|
|
70a194b930 | ||
|
|
2573109866 | ||
|
|
9dfa5b421d | ||
|
|
9da8ba18e6 | ||
|
|
76bc683820 | ||
|
|
3b22c4707d | ||
|
|
96e6e05372 | ||
|
|
e2222c3924 | ||
|
|
31e8f3c894 | ||
|
|
9368caf64d | ||
|
|
38e584a072 | ||
|
|
313aa56710 | ||
|
|
4cbf74b6b8 | ||
|
|
33417e7025 | ||
|
|
4021dab059 | ||
|
|
626df76abb | ||
|
|
abcd5da72e | ||
|
|
97a847bc03 | ||
|
|
ab93bbe2ae | ||
|
|
0f0b726444 | ||
|
|
b92e5a22ec | ||
|
|
17b0018b42 | ||
|
|
39cf780327 | ||
|
|
e89f66eca9 | ||
|
|
b6d78bfa0d | ||
|
|
c33a346edf | ||
|
|
61a2ad53cb | ||
|
|
2c1794c42e | ||
|
|
8a4c1cc411 | ||
|
|
330d0414a5 | ||
|
|
3802ce26a1 | ||
|
|
4abe615b84 | ||
|
|
a412ac572f | ||
|
|
b2b5fb228f | ||
|
|
8f186479e2 | ||
|
|
4c3a88a284 | ||
|
|
d6b4936796 | ||
|
|
9d0fe224f4 | ||
|
|
6e0374f6b5 | ||
|
|
9e5f5284b3 | ||
|
|
c596ed1713 | ||
|
|
91cf4d88fb | ||
|
|
a96fc003bd | ||
|
|
d44b29c21e | ||
|
|
070893f425 | ||
|
|
9621339dca | ||
|
|
ede28208d8 | ||
|
|
7739f36e38 | ||
|
|
f8c8799840 | ||
|
|
43fff2384e | ||
|
|
1b21b62ab4 | ||
|
|
a1516e92b6 | ||
|
|
6fb883e8e3 | ||
|
|
6e295807ac | ||
|
|
f2674e31e0 | ||
|
|
4690764bba | ||
|
|
3c1cf9fa86 | ||
|
|
1f47a9223e | ||
|
|
33e3963e1b | ||
|
|
cd4c3e888a | ||
|
|
7916e2245d | ||
|
|
abd0aaff03 | ||
|
|
c39d5b78f6 | ||
|
|
4d40895f2c | ||
|
|
e477b8b81b | ||
|
|
b118d61e55 | ||
|
|
2f62b397b5 | ||
|
|
907a5b2690 | ||
|
|
0849bf0821 | ||
|
|
305034817d | ||
|
|
ec410fc9ce | ||
|
|
68a7931591 | ||
|
|
c9159e5321 | ||
|
|
8c9b861e74 | ||
|
|
5797fa5d7e | ||
|
|
8ef9a8ece3 | ||
|
|
fc01f7e7f9 | ||
|
|
3b0dca51b0 | ||
|
|
da415d54bf | ||
|
|
b4608c0455 | ||
|
|
d5a0b50c6f | ||
|
|
87858c89ca | ||
|
|
a6f816d697 | ||
|
|
0ad041d476 | ||
|
|
1eb20527c8 | ||
|
|
e3e86d56c4 | ||
|
|
1df912cf9e | ||
|
|
4351832355 | ||
|
|
59faf6d6a6 | ||
|
|
725af7d460 | ||
|
|
a363e34cc5 | ||
|
|
ea041c0e33 | ||
|
|
83479e770d | ||
|
|
e2f2289897 | ||
|
|
844c72eccc | ||
|
|
6b1534cc67 | ||
|
|
e8cd23de30 | ||
|
|
7c2d6a781c | ||
|
|
f1510b2cc3 | ||
|
|
357a94326c | ||
|
|
0824d6fc67 | ||
|
|
6c0372d30b | ||
|
|
92ccca6aa8 | ||
|
|
dd3587f38e | ||
|
|
7d83131cc5 | ||
|
|
66e85a21c7 | ||
|
|
90a9fdae1f | ||
|
|
3fb2ded1d5 | ||
|
|
f76af4b3f3 | ||
|
|
717fc2ad8d | ||
|
|
c05bab779e | ||
|
|
a52c757c9f | ||
|
|
970a87a6bb | ||
|
|
d8bc1fd0ae | ||
|
|
7501267e22 | ||
|
|
13b55754af | ||
|
|
972ddf7840 | ||
|
|
322d0c6657 | ||
|
|
2054396a04 | ||
|
|
039de852ec | ||
|
|
144c345daf | ||
|
|
de83cd02e0 | ||
|
|
6380ab5e26 | ||
|
|
b346ff468e | ||
|
|
5a9fdfec7e | ||
|
|
d19893dab5 | ||
|
|
2521d69883 | ||
|
|
2ab83ea784 | ||
|
|
2437490100 | ||
|
|
e4533c7a8c | ||
|
|
1e5ffbedde | ||
|
|
79638566e5 | ||
|
|
03daf0e361 | ||
|
|
d219f7e7ed | ||
|
|
95cbfc643d | ||
|
|
5898e81684 | ||
|
|
394411ac74 | ||
|
|
ea76864009 | ||
|
|
43ce4dfe9e | ||
|
|
ebc06f87ca | ||
|
|
5bbe92995c | ||
|
|
411bffc41c | ||
|
|
ff1f20a3ee | ||
|
|
9c5d1246c7 | ||
|
|
8dd7cb0621 | ||
|
|
d30329297b | ||
|
|
a95c67907c | ||
|
|
0f533160c7 | ||
|
|
e163bca720 | ||
|
|
8c6939c0b0 | ||
|
|
2d0e9143e2 | ||
|
|
87f4827e1d | ||
|
|
4a585ccb2f | ||
|
|
aa0aa4fa31 | ||
|
|
84fa15d854 | ||
|
|
4add45b4f6 | ||
|
|
4f101ad7ff | ||
|
|
c1db2eb8c3 | ||
|
|
82d19dafe4 | ||
|
|
5286db75a8 | ||
|
|
917f95fd4d | ||
|
|
fe31975692 | ||
|
|
95f7652d65 | ||
|
|
3ec9c4fcc6 | ||
|
|
2f87c60799 | ||
|
|
03bfca946a | ||
|
|
ed2dcdf68e | ||
|
|
4304763ba2 | ||
|
|
c1e42a1397 | ||
|
|
d0a1ffc957 | ||
|
|
df0f11a03b | ||
|
|
2d92f0b8f0 | ||
|
|
aad13cd131 | ||
|
|
a513fe19ac | ||
|
|
f4beb510a4 | ||
|
|
d731dae8e3 | ||
|
|
c9087c2a60 | ||
|
|
14ae3ba7f9 | ||
|
|
5a91de8c90 | ||
|
|
e3b32540df | ||
|
|
a37904dd86 | ||
|
|
cf25629d1e | ||
|
|
0ca790b92e | ||
|
|
d1fe2b2459 | ||
|
|
d4e8164f7e | ||
|
|
08351fb37a | ||
|
|
85e53d4108 | ||
|
|
aa05ae6fec | ||
|
|
1565b7bcd7 | ||
|
|
b409186b8d | ||
|
|
418a97afa1 | ||
|
|
5132455efe | ||
|
|
c0ad5542a8 | ||
|
|
3a27ad0b57 | ||
|
|
2b413144dc | ||
|
|
3ebcc707d2 | ||
|
|
7775e9ecc2 | ||
|
|
03d843ddf2 | ||
|
|
eb51d102bb | ||
|
|
25eb44841e | ||
|
|
b333af0666 | ||
|
|
76c8b7710b | ||
|
|
70e198602b | ||
|
|
206f0fa759 | ||
|
|
fd6ce8f660 | ||
|
|
727d01d4f6 | ||
|
|
ae22853141 | ||
|
|
d418c81eff | ||
|
|
2a29ca73c9 | ||
|
|
54936004fd | ||
|
|
74c95119f2 | ||
|
|
366c1b8bfa | ||
|
|
a993ba85cf | ||
|
|
226c91327d | ||
|
|
b8bf3e3aac | ||
|
|
288426fe3c | ||
|
|
72cc388104 | ||
|
|
378180d8dc | ||
|
|
78c34e98cd | ||
|
|
2792c4f2af | ||
|
|
447db2139a | ||
|
|
564c8f9978 | ||
|
|
c50c0c3fbf | ||
|
|
cabb4d616d | ||
|
|
631271d716 | ||
|
|
9d27abd94f | ||
|
|
148dfc2a8b | ||
|
|
3acace1333 | ||
|
|
0221cfcd71 | ||
|
|
f351077efb | ||
|
|
e84be9dbca | ||
|
|
46ddf5511d | ||
|
|
89e957e7a2 | ||
|
|
982b431579 | ||
|
|
bf7c65bdf4 | ||
|
|
8e5a0667f8 | ||
|
|
19b84f3c35 | ||
|
|
08fc60898b | ||
|
|
082391983e | ||
|
|
504e56ebdc | ||
|
|
455b761956 | ||
|
|
b56dad1c7b | ||
|
|
9ba5695ce5 | ||
|
|
66099dd9af | ||
|
|
b689bc57d6 | ||
|
|
a69d83b60b | ||
|
|
86840ae241 | ||
|
|
3c51961e0e | ||
|
|
d014c98c8d | ||
|
|
a98fd896cd | ||
|
|
d6cdca958e | ||
|
|
efdea7bf19 | ||
|
|
0d3301964d | ||
|
|
fe1e3ce3e9 | ||
|
|
bb326a3749 | ||
|
|
27725c1d74 | ||
|
|
e026db5893 | ||
|
|
43f04c233c | ||
|
|
a8baa8c555 | ||
|
|
728584be27 | ||
|
|
b9adb4a6bc | ||
|
|
ae48a07313 | ||
|
|
956034d7e5 | ||
|
|
6cd9f35b9b | ||
|
|
689f936f7e | ||
|
|
6977fbfd8b | ||
|
|
77e4672d8d | ||
|
|
d34720fd7d | ||
|
|
d9c4d1cc1a | ||
|
|
f644caa51a | ||
|
|
1eb87257da | ||
|
|
32ce63371a | ||
|
|
ec86b0fb3a | ||
|
|
1d346ae63a | ||
|
|
74cd30b811 | ||
|
|
7fb9a24e39 | ||
|
|
afeb6ee377 | ||
|
|
f29042b531 | ||
|
|
09bfb054fb | ||
|
|
2677e107e6 | ||
|
|
66cd58461d | ||
|
|
bb0ebb1f2d | ||
|
|
27c75a9a90 | ||
|
|
d0cd3b8d84 | ||
|
|
9af9eaaa76 | ||
|
|
8c8f42f76c | ||
|
|
51fe68905b | ||
|
|
7fe70ecc56 | ||
|
|
d03cda5923 | ||
|
|
30ac07d4f0 | ||
|
|
8857052055 | ||
|
|
ce11fedc6e | ||
|
|
43d4145a98 | ||
|
|
295defa5f1 | ||
|
|
f801f97e04 | ||
|
|
f48c3dd51a | ||
|
|
62296fe351 | ||
|
|
32f36bcefc | ||
|
|
bc8a22cc30 | ||
|
|
f631ef9bd2 | ||
|
|
f7341ff400 | ||
|
|
fd429f2f6c | ||
|
|
fb3e5849bb | ||
|
|
7854b05654 | ||
|
|
500dab07e8 | ||
|
|
f6630e791b | ||
|
|
168485b75b | ||
|
|
5cd4393b14 | ||
|
|
7ed601b782 | ||
|
|
d1f2367bc0 | ||
|
|
851e67a1b4 | ||
|
|
fc2b4c4879 | ||
|
|
9c605cb135 | ||
|
|
24f9e90b0e | ||
|
|
a4a0ffdb2b | ||
|
|
0ea00c9a3c | ||
|
|
e1d4294a45 | ||
|
|
c3c7c29246 | ||
|
|
31bb950be6 | ||
|
|
8083a3e508 | ||
|
|
644c433cb3 | ||
|
|
d691f66983 | ||
|
|
386405f786 | ||
|
|
3ef693a032 | ||
|
|
b03c60f351 | ||
|
|
9de5e440b9 | ||
|
|
66fb9763af | ||
|
|
1b6b029e40 | ||
|
|
612384d771 | ||
|
|
dab2ed991a | ||
|
|
e591824733 | ||
|
|
04369ff2f5 | ||
|
|
68decc7c7f | ||
|
|
dc99065b5f | ||
|
|
ca735206e0 | ||
|
|
5dd9488c09 | ||
|
|
60cd49d5d7 | ||
|
|
a300e69170 | ||
|
|
1a9353d258 | ||
|
|
6dbad63eef | ||
|
|
27362c82e9 | ||
|
|
55480af80e | ||
|
|
7d13299d07 | ||
|
|
1017ebe9cb | ||
|
|
77f8dd5add | ||
|
|
c5e9815da4 | ||
|
|
9d8e9c0993 | ||
|
|
d57c4e0120 | ||
|
|
4b74fe1f00 | ||
|
|
586314f2aa | ||
|
|
0ecfa9930c | ||
|
|
ba1c6e37fc | ||
|
|
927f621e79 | ||
|
|
367e86e847 | ||
|
|
7bfdb6d18c | ||
|
|
379ca80d34 | ||
|
|
4d1135e486 | ||
|
|
5147f5aac0 | ||
|
|
766a487abf | ||
|
|
72f0390014 | ||
|
|
b17780d521 | ||
|
|
3431395696 | ||
|
|
01ffc75bc9 | ||
|
|
31e31b8a24 | ||
|
|
e63c3dc74b |
+15
@@ -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
|
||||
@@ -0,0 +1,339 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||
675 Mass Ave, Cambridge, MA 02139, USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Library General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) 19yy <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) 19yy name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Library General
|
||||
Public License instead of this License.
|
||||
+111
-111
@@ -1,36 +1,14 @@
|
||||
------------------------------------------------------------------------------
|
||||
NOTE:
|
||||
Some code of the Twin package was modified for DOSEMU by the DOSEMU-team.
|
||||
The original is 'Copyright 1997 Willows Software, Inc.' and generously
|
||||
was put under the GNU Library General Public License.
|
||||
( for more information see http://www.willows.com/ )
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 2.1, February 1999
|
||||
|
||||
We make use of section 3 of the GNU Library General Public License
|
||||
('...opt to apply the terms of the ordinary GNU General Public License...'),
|
||||
because the resulting product is an integrated part of DOSEMU and
|
||||
can not be considered to be a 'library' in the terms of Library License.
|
||||
|
||||
Therefore, the below GNU LIBRARY GENERAL PUBLIC LICENSE applies only to the
|
||||
_unchanged_ Twin package from Willows. For the DOSEMU-changed parts the normal
|
||||
GNU GENERAL PUBLIC LICENSE applies. This GPL (file COPYING) can be found in
|
||||
the root directory of the DOSEMU distribution.
|
||||
|
||||
The act of transformation to GPL was indicated to the maintainer of the Twin
|
||||
package (Rob Penrose <rob@Canopy.Com>) and he acknowledge agreement.
|
||||
|
||||
Nov. 1 1997, The DOSEMU team.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
GNU LIBRARY GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1991 Free Software Foundation, Inc.
|
||||
675 Mass Ave, Cambridge, MA 02139, USA
|
||||
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
|
||||
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
[This is the first released version of the library GPL. It is
|
||||
numbered 2 because it goes with version 2 of the ordinary GPL.]
|
||||
[This is the first released version of the Lesser GPL. It also counts
|
||||
as the successor of the GNU Library Public License, version 2, hence
|
||||
the version number 2.1.]
|
||||
|
||||
Preamble
|
||||
|
||||
@@ -39,97 +17,109 @@ freedom to share and change it. By contrast, the GNU General Public
|
||||
Licenses are intended to guarantee your freedom to share and change
|
||||
free software--to make sure the software is free for all its users.
|
||||
|
||||
This license, the Library General Public License, applies to some
|
||||
specially designated Free Software Foundation software, and to any
|
||||
other libraries whose authors decide to use it. You can use it for
|
||||
your libraries, too.
|
||||
This license, the Lesser General Public License, applies to some
|
||||
specially designated software packages--typically libraries--of the
|
||||
Free Software Foundation and other authors who decide to use it. You
|
||||
can use it too, but we suggest you first think carefully about whether
|
||||
this license or the ordinary General Public License is the better
|
||||
strategy to use in any particular case, based on the explanations below.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
When we speak of free software, we are referring to freedom of use,
|
||||
not price. Our General Public Licenses are designed to make sure that
|
||||
you have the freedom to distribute copies of free software (and charge
|
||||
for this service if you wish); that you receive source code or can get
|
||||
it if you want it; that you can change the software and use pieces of
|
||||
it in new free programs; and that you are informed that you can do
|
||||
these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if
|
||||
you distribute copies of the library, or if you modify it.
|
||||
distributors to deny you these rights or to ask you to surrender these
|
||||
rights. These restrictions translate to certain responsibilities for
|
||||
you if you distribute copies of the library or if you modify it.
|
||||
|
||||
For example, if you distribute copies of the library, whether gratis
|
||||
or for a fee, you must give the recipients all the rights that we gave
|
||||
you. You must make sure that they, too, receive or can get the source
|
||||
code. If you link a program with the library, you must provide
|
||||
complete object files to the recipients so that they can relink them
|
||||
with the library, after making changes to the library and recompiling
|
||||
code. If you link other code with the library, you must provide
|
||||
complete object files to the recipients, so that they can relink them
|
||||
with the library after making changes to the library and recompiling
|
||||
it. And you must show them these terms so they know their rights.
|
||||
|
||||
Our method of protecting your rights has two steps: (1) copyright
|
||||
the library, and (2) offer you this license which gives you legal
|
||||
We protect your rights with a two-step method: (1) we copyright the
|
||||
library, and (2) we offer you this license, which gives you legal
|
||||
permission to copy, distribute and/or modify the library.
|
||||
|
||||
Also, for each distributor's protection, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
library. If the library is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original
|
||||
version, so that any problems introduced by others will not reflect on
|
||||
the original authors' reputations.
|
||||
To protect each distributor, we want to make it very clear that
|
||||
there is no warranty for the free library. Also, if the library is
|
||||
modified by someone else and passed on, the recipients should know
|
||||
that what they have is not the original version, so that the original
|
||||
author's reputation will not be affected by problems that might be
|
||||
introduced by others.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that companies distributing free
|
||||
software will individually obtain patent licenses, thus in effect
|
||||
transforming the program into proprietary software. To prevent this,
|
||||
we have made it clear that any patent must be licensed for everyone's
|
||||
free use or not licensed at all.
|
||||
Finally, software patents pose a constant threat to the existence of
|
||||
any free program. We wish to make sure that a company cannot
|
||||
effectively restrict the users of a free program by obtaining a
|
||||
restrictive license from a patent holder. Therefore, we insist that
|
||||
any patent license obtained for a version of the library must be
|
||||
consistent with the full freedom of use specified in this license.
|
||||
|
||||
Most GNU software, including some libraries, is covered by the ordinary
|
||||
GNU General Public License, which was designed for utility programs. This
|
||||
license, the GNU Library General Public License, applies to certain
|
||||
designated libraries. This license is quite different from the ordinary
|
||||
one; be sure to read it in full, and don't assume that anything in it is
|
||||
the same as in the ordinary license.
|
||||
Most GNU software, including some libraries, is covered by the
|
||||
ordinary GNU General Public License. This license, the GNU Lesser
|
||||
General Public License, applies to certain designated libraries, and
|
||||
is quite different from the ordinary General Public License. We use
|
||||
this license for certain libraries in order to permit linking those
|
||||
libraries into non-free programs.
|
||||
|
||||
The reason we have a separate public license for some libraries is that
|
||||
they blur the distinction we usually make between modifying or adding to a
|
||||
program and simply using it. Linking a program with a library, without
|
||||
changing the library, is in some sense simply using the library, and is
|
||||
analogous to running a utility program or application program. However, in
|
||||
a textual and legal sense, the linked executable is a combined work, a
|
||||
derivative of the original library, and the ordinary General Public License
|
||||
treats it as such.
|
||||
When a program is linked with a library, whether statically or using
|
||||
a shared library, the combination of the two is legally speaking a
|
||||
combined work, a derivative of the original library. The ordinary
|
||||
General Public License therefore permits such linking only if the
|
||||
entire combination fits its criteria of freedom. The Lesser General
|
||||
Public License permits more lax criteria for linking other code with
|
||||
the library.
|
||||
|
||||
Because of this blurred distinction, using the ordinary General
|
||||
Public License for libraries did not effectively promote software
|
||||
sharing, because most developers did not use the libraries. We
|
||||
concluded that weaker conditions might promote sharing better.
|
||||
We call this license the "Lesser" General Public License because it
|
||||
does Less to protect the user's freedom than the ordinary General
|
||||
Public License. It also provides other free software developers Less
|
||||
of an advantage over competing non-free programs. These disadvantages
|
||||
are the reason we use the ordinary General Public License for many
|
||||
libraries. However, the Lesser license provides advantages in certain
|
||||
special circumstances.
|
||||
|
||||
However, unrestricted linking of non-free programs would deprive the
|
||||
users of those programs of all benefit from the free status of the
|
||||
libraries themselves. This Library General Public License is intended to
|
||||
permit developers of non-free programs to use free libraries, while
|
||||
preserving your freedom as a user of such programs to change the free
|
||||
libraries that are incorporated in them. (We have not seen how to achieve
|
||||
this as regards changes in header files, but we have achieved it as regards
|
||||
changes in the actual functions of the Library.) The hope is that this
|
||||
will lead to faster development of free libraries.
|
||||
For example, on rare occasions, there may be a special need to
|
||||
encourage the widest possible use of a certain library, so that it becomes
|
||||
a de-facto standard. To achieve this, non-free programs must be
|
||||
allowed to use the library. A more frequent case is that a free
|
||||
library does the same job as widely used non-free libraries. In this
|
||||
case, there is little to gain by limiting the free library to free
|
||||
software only, so we use the Lesser General Public License.
|
||||
|
||||
In other cases, permission to use a particular library in non-free
|
||||
programs enables a greater number of people to use a large body of
|
||||
free software. For example, permission to use the GNU C Library in
|
||||
non-free programs enables many more people to use the whole GNU
|
||||
operating system, as well as its variant, the GNU/Linux operating
|
||||
system.
|
||||
|
||||
Although the Lesser General Public License is Less protective of the
|
||||
users' freedom, it does ensure that the user of a program that is
|
||||
linked with the Library has the freedom and the wherewithal to run
|
||||
that program using a modified version of the Library.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow. Pay close attention to the difference between a
|
||||
"work based on the library" and a "work that uses the library". The
|
||||
former contains code derived from the library, while the latter only
|
||||
works together with the library.
|
||||
|
||||
Note that it is possible for a library to be covered by the ordinary
|
||||
General Public License rather than by this special one.
|
||||
former contains code derived from the library, whereas the latter must
|
||||
be combined with the library in order to run.
|
||||
|
||||
GNU LIBRARY GENERAL PUBLIC LICENSE
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License Agreement applies to any software library which
|
||||
contains a notice placed by the copyright holder or other authorized
|
||||
party saying it may be distributed under the terms of this Library
|
||||
General Public License (also called "this License"). Each licensee is
|
||||
addressed as "you".
|
||||
0. This License Agreement applies to any software library or other
|
||||
program which contains a notice placed by the copyright holder or
|
||||
other authorized party saying it may be distributed under the terms of
|
||||
this Lesser General Public License (also called "this License").
|
||||
Each licensee is addressed as "you".
|
||||
|
||||
A "library" means a collection of software functions and/or data
|
||||
prepared so as to be conveniently linked with application programs
|
||||
@@ -278,7 +268,7 @@ distribute the object code for the work under the terms of Section 6.
|
||||
Any executables containing that work also fall under Section 6,
|
||||
whether or not they are linked directly with the Library itself.
|
||||
|
||||
6. As an exception to the Sections above, you may also compile or
|
||||
6. As an exception to the Sections above, you may also combine or
|
||||
link a "work that uses the Library" with the Library to produce a
|
||||
work containing portions of the Library, and distribute that work
|
||||
under terms of your choice, provided that the terms permit
|
||||
@@ -305,23 +295,31 @@ of these things:
|
||||
Library will not necessarily be able to recompile the application
|
||||
to use the modified definitions.)
|
||||
|
||||
b) Accompany the work with a written offer, valid for at
|
||||
b) Use a suitable shared library mechanism for linking with the
|
||||
Library. A suitable mechanism is one that (1) uses at run time a
|
||||
copy of the library already present on the user's computer system,
|
||||
rather than copying library functions into the executable, and (2)
|
||||
will operate properly with a modified version of the library, if
|
||||
the user installs one, as long as the modified version is
|
||||
interface-compatible with the version that the work was made with.
|
||||
|
||||
c) Accompany the work with a written offer, valid for at
|
||||
least three years, to give the same user the materials
|
||||
specified in Subsection 6a, above, for a charge no more
|
||||
than the cost of performing this distribution.
|
||||
|
||||
c) If distribution of the work is made by offering access to copy
|
||||
d) If distribution of the work is made by offering access to copy
|
||||
from a designated place, offer equivalent access to copy the above
|
||||
specified materials from the same place.
|
||||
|
||||
d) Verify that the user has already received a copy of these
|
||||
e) Verify that the user has already received a copy of these
|
||||
materials or that you have already sent this user a copy.
|
||||
|
||||
For an executable, the required form of the "work that uses the
|
||||
Library" must include any data and utility programs needed for
|
||||
reproducing the executable from it. However, as a special exception,
|
||||
the source code distributed need not include anything that is normally
|
||||
distributed (in either source or binary form) with the major
|
||||
the materials to be distributed need not include anything that is
|
||||
normally distributed (in either source or binary form) with the major
|
||||
components (compiler, kernel, and so on) of the operating system on
|
||||
which the executable runs, unless that component itself accompanies
|
||||
the executable.
|
||||
@@ -370,7 +368,7 @@ Library), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute, link with or modify the Library
|
||||
subject to these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
You are not responsible for enforcing compliance by third parties with
|
||||
this License.
|
||||
|
||||
11. If, as a consequence of a court judgment or allegation of patent
|
||||
@@ -413,7 +411,7 @@ excluded. In such case, this License incorporates the limitation as if
|
||||
written in the body of this License.
|
||||
|
||||
13. The Free Software Foundation may publish revised and/or new
|
||||
versions of the Library General Public License from time to time.
|
||||
versions of the Lesser General Public License from time to time.
|
||||
Such new versions will be similar in spirit to the present version,
|
||||
but may differ in detail to address new problems or concerns.
|
||||
|
||||
@@ -459,7 +457,7 @@ DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
Appendix: How to Apply These Terms to Your New Libraries
|
||||
How to Apply These Terms to Your New Libraries
|
||||
|
||||
If you develop a new library, and you want it to be of the greatest
|
||||
possible use to the public, we recommend making it free software that
|
||||
@@ -476,18 +474,18 @@ convey the exclusion of warranty; and each file should have at least the
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with this library; if not, write to the Free
|
||||
Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
@@ -502,3 +500,5 @@ necessary. Here is a sample; alter the names:
|
||||
Ty Coon, President of Vice
|
||||
|
||||
That's all there is to it!
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,295 @@
|
||||
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
|
||||
- graphical display with SDL
|
||||
- added PS/2 mouse and keyboard emulation
|
||||
- popw (%esp) fix
|
||||
- mov to/from segment data width fix
|
||||
- added real mode support
|
||||
- added Bochs BIOS and LGPL'ed VGA BIOS loader in qemu
|
||||
- m68k host port (Richard Zidlicky)
|
||||
- partial soft MMU support for memory mapped I/Os
|
||||
- multi-target build
|
||||
- fixed: no error code in hardware interrupts
|
||||
- fixed: pop ss, mov ss, x and sti disable hardware irqs for the next insn
|
||||
- correct single stepping thru string operations
|
||||
- preliminary SPARC target support (Thomas M. Ogrisegg)
|
||||
- tun-fd option (Rusty Russell)
|
||||
- automatic IDE geometry detection
|
||||
- renamed 'vl' to qemu[-fast] and user qemu to qemu-{cpu}.
|
||||
- added man page
|
||||
- added full soft mmu mode to launch unpatched OSes.
|
||||
|
||||
version 0.4.3:
|
||||
|
||||
- x86 exception fix in case of nop instruction.
|
||||
- gcc 3.2.2 bug workaround (RedHat 9 fix)
|
||||
- sparc and Alpha host fixes
|
||||
- many ARM target fixes: 'ls' and 'bash' can be launched.
|
||||
|
||||
version 0.4.2:
|
||||
|
||||
- many exception handling fixes (can compile a Linux kernel inside vl)
|
||||
- IDE emulation support
|
||||
- initial GDB stub support
|
||||
- deferred update support for disk images (Rusty Russell)
|
||||
- accept User Mode Linux Copy On Write disk images
|
||||
- SMP kernels can at least be booted
|
||||
|
||||
version 0.4.1:
|
||||
|
||||
- more accurate timer support in vl.
|
||||
- more reliable NE2000 probe in vl.
|
||||
- added 2.5.66 kernel in vl-test.
|
||||
- added VLTMPDIR environment variable in vl.
|
||||
|
||||
version 0.4:
|
||||
|
||||
- initial support for ring 0 x86 processor emulation
|
||||
- fixed signal handling for correct dosemu DPMI emulation
|
||||
- fast x86 MMU emulation with mmap()
|
||||
- fixed popl (%esp) case
|
||||
- Linux kernel can be executed by QEMU with the 'vl' command.
|
||||
|
||||
version 0.3:
|
||||
|
||||
- initial support for ARM emulation
|
||||
- added fnsave, frstor, fnstenv, fldenv FPU instructions
|
||||
- added FPU register save in signal emulation
|
||||
- initial ARM port
|
||||
- Sparc and Alpha ports work on the regression test
|
||||
- generic ioctl number conversion
|
||||
- fixed ioctl type conversion
|
||||
|
||||
version 0.2:
|
||||
|
||||
- PowerPC disassembly and ELF symbols output (Rusty Russell)
|
||||
- flock support (Rusty Russell)
|
||||
- ugetrlimit support (Rusty Russell)
|
||||
- fstat64 fix (Rusty Russell)
|
||||
- initial Alpha port (Falk Hueffner)
|
||||
- initial IA64 port (Matt Wilson)
|
||||
- initial Sparc and Sparc64 port (David S. Miller)
|
||||
- added HLT instruction
|
||||
- LRET instruction fix.
|
||||
- added GPF generation for I/Os.
|
||||
- added INT3 and TF flag support.
|
||||
- SHL instruction C flag fix.
|
||||
- mmap emulation for host page size > 4KB
|
||||
- self-modifying code support
|
||||
- better VM86 support (dosemu works on non trivial programs)
|
||||
- precise exception support (EIP is computed correctly in most cases)
|
||||
- more precise LDT/GDT/IDT emulation
|
||||
- faster segment load in vm86 mode
|
||||
- direct chaining of basic blocks (faster emulation)
|
||||
|
||||
version 0.1.6:
|
||||
|
||||
- automatic library search system. QEMU can now work with unpatched
|
||||
ELF dynamic loader and libc (Rusty Russell).
|
||||
- ISO C warning fixes (Alistair Strachan)
|
||||
- first self-virtualizable version (works only as long as the
|
||||
translation cache is not flushed)
|
||||
- RH9 fixes
|
||||
|
||||
version 0.1.5:
|
||||
|
||||
- ppc64 support + personality() patch (Rusty Russell)
|
||||
- first Alpha CPU patches (Falk Hueffner)
|
||||
- removed bfd.h dependancy
|
||||
- fixed shrd, shld, idivl and divl on PowerPC.
|
||||
- fixed buggy glibc PowerPC rint() function (test-i386 passes now on PowerPC).
|
||||
|
||||
version 0.1.4:
|
||||
|
||||
- more accurate VM86 emulation (can launch small DOS 16 bit
|
||||
executables in wine).
|
||||
- fixed push/pop fs/gs
|
||||
- added iret instruction.
|
||||
- added times() syscall and SIOCATMARK ioctl.
|
||||
|
||||
version 0.1.3:
|
||||
|
||||
- S390 support (Ulrich Weigand)
|
||||
- glibc 2.3.x compile fix (Ulrich Weigand)
|
||||
- socketcall endian fix (Ulrich Weigand)
|
||||
- struct sockaddr endian fix (Ulrich Weigand)
|
||||
- sendmsg/recvmsg endian fix (Ulrich Weigand)
|
||||
- execve endian fix (Ulrich Weigand)
|
||||
- fdset endian fix (Ulrich Weigand)
|
||||
- partial setsockopt syscall support (Ulrich Weigand)
|
||||
- more accurate pushf/popf emulation
|
||||
- first partial vm86() syscall support (can be used with runcom example).
|
||||
- added bound, cmpxchg8b, cpuid instructions
|
||||
- added 16 bit addressing support/override for string operations
|
||||
- poll() fix
|
||||
|
||||
version 0.1.2:
|
||||
|
||||
- compile fixes
|
||||
- xlat instruction
|
||||
- xchg instruction memory lock
|
||||
- added simple vm86 example (not working with QEMU yet). The 54 byte
|
||||
DOS executable 'pi_10.com' program was released by Bertram
|
||||
Felgenhauer (more information at http://www.boo.net/~jasonp/pipage.html).
|
||||
|
||||
version 0.1.1:
|
||||
|
||||
- glibc 2.2 compilation fixes
|
||||
- added -s and -L options
|
||||
- binary distribution of x86 glibc and wine
|
||||
- big endian fixes in ELF loader and getdents.
|
||||
|
||||
version 0.1:
|
||||
|
||||
- initial public release.
|
||||
@@ -1,36 +1,111 @@
|
||||
CFLAGS=-Wall -O2 -g
|
||||
-include config-host.mak
|
||||
|
||||
CFLAGS=-Wall -O2 -g -fno-strict-aliasing
|
||||
ifdef CONFIG_DARWIN
|
||||
CFLAGS+= -mdynamic-no-pic
|
||||
endif
|
||||
ifdef CONFIG_WIN32
|
||||
CFLAGS+=-fpack-struct
|
||||
endif
|
||||
LDFLAGS=-g
|
||||
DEFINES=-D_GNU_SOURCE -DGEMU -DDOSEMU #-DNO_TRACE_MSGS
|
||||
LIBS=
|
||||
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
|
||||
|
||||
OBJS= i386/fp87.o i386/interp_main.o i386/interp_modrm.o i386/interp_16_32.o \
|
||||
i386/interp_32_16.o i386/interp_32_32.o i386/emu-utils.o \
|
||||
i386/dis8086.o i386/emu-ldt.o
|
||||
OBJS+= elfload.o main.o thunk.o syscall.o
|
||||
all: dyngen$(EXESUF) $(TOOLS) $(DOCS)
|
||||
for d in $(TARGET_DIRS); do \
|
||||
$(MAKE) -C $$d $@ || exit 1 ; \
|
||||
done
|
||||
|
||||
SRCS = $(OBJS:.o=.c)
|
||||
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)
|
||||
|
||||
all: gemu
|
||||
|
||||
gemu: $(OBJS)
|
||||
$(CC) -Wl,-T,i386.ld $(LDFLAGS) -o $@ $(OBJS)
|
||||
|
||||
depend: $(SRCS)
|
||||
$(CC) -MM $(CFLAGS) $^ 1>.depend
|
||||
|
||||
%.o: %.c
|
||||
$(CC) $(CFLAGS) $(DEFINES) -c -o $@ $<
|
||||
dyngen$(EXESUF): dyngen.c
|
||||
$(HOST_CC) $(CFLAGS) $(DEFINES) -o $@ $^
|
||||
|
||||
clean:
|
||||
rm -f *.o *~ i386/*.o i386/*~ gemu hello test1 test2 TAGS
|
||||
# avoid old build problems by removing potentially incorrect old files
|
||||
rm -f config.mak config.h op-i386.h opc-i386.h gen-op-i386.h op-arm.h opc-arm.h gen-op-arm.h
|
||||
rm -f *.o *.a $(TOOLS) dyngen$(EXESUF) TAGS qemu.pod *~ */*~
|
||||
$(MAKE) -C tests clean
|
||||
for d in $(TARGET_DIRS); do \
|
||||
$(MAKE) -C $$d $@ || exit 1 ; \
|
||||
done
|
||||
|
||||
hello: hello.c
|
||||
$(CC) -nostdlib $(CFLAGS) -static $(LDFLAGS) -o $@ $<
|
||||
distclean: clean
|
||||
rm -f config-host.mak config-host.h
|
||||
for d in $(TARGET_DIRS); do \
|
||||
rm -rf $$d || exit 1 ; \
|
||||
done
|
||||
|
||||
test1: test1.c
|
||||
$(CC) $(CFLAGS) -static $(LDFLAGS) -o $@ $<
|
||||
install: all
|
||||
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 ; \
|
||||
done
|
||||
|
||||
test2: test2.c
|
||||
$(CC) $(CFLAGS) -static $(LDFLAGS) -o $@ $<
|
||||
# various test targets
|
||||
test speed test2: all
|
||||
$(MAKE) -C tests $@
|
||||
|
||||
TAGS:
|
||||
etags *.[ch] tests/*.[ch]
|
||||
|
||||
# documentation
|
||||
%.html: %.texi
|
||||
texi2html -monolithic -number $<
|
||||
|
||||
qemu.1: qemu-doc.texi
|
||||
./texi2pod.pl $< qemu.pod
|
||||
pod2man --section=1 --center=" " --release=" " qemu.pod > $@
|
||||
|
||||
FILE=qemu-$(shell cat VERSION)
|
||||
|
||||
# tar release (use 'make -k tar' on a checkouted tree)
|
||||
tar:
|
||||
rm -rf /tmp/$(FILE)
|
||||
cp -r . /tmp/$(FILE)
|
||||
( cd /tmp ; tar zcvf ~/$(FILE).tar.gz $(FILE) --exclude CVS )
|
||||
rm -rf /tmp/$(FILE)
|
||||
|
||||
# generate a binary distribution
|
||||
tarbin:
|
||||
( 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
|
||||
|
||||
+405
@@ -0,0 +1,405 @@
|
||||
include config.mak
|
||||
|
||||
TARGET_PATH=$(SRC_PATH)/target-$(TARGET_ARCH)
|
||||
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=
|
||||
HELPER_CFLAGS=$(CFLAGS)
|
||||
DYNGEN=../dyngen$(EXESUF)
|
||||
# user emulator name
|
||||
QEMU_USER=qemu-$(TARGET_ARCH)
|
||||
# system emulator name
|
||||
ifdef CONFIG_SOFTMMU
|
||||
ifeq ($(TARGET_ARCH), i386)
|
||||
QEMU_SYSTEM=qemu$(EXESUF)
|
||||
else
|
||||
QEMU_SYSTEM=qemu-system-$(TARGET_ARCH)$(EXESUF)
|
||||
endif
|
||||
else
|
||||
QEMU_SYSTEM=qemu-fast
|
||||
endif
|
||||
|
||||
ifdef CONFIG_USER_ONLY
|
||||
PROGS=$(QEMU_USER)
|
||||
else
|
||||
ifeq ($(TARGET_ARCH), i386)
|
||||
|
||||
ifeq ($(ARCH), i386)
|
||||
PROGS+=$(QEMU_SYSTEM)
|
||||
ifndef CONFIG_SOFTMMU
|
||||
CONFIG_STATIC=y
|
||||
endif
|
||||
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
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH),i386)
|
||||
CFLAGS+=-fomit-frame-pointer
|
||||
OP_CFLAGS=$(CFLAGS) -mpreferred-stack-boundary=2
|
||||
ifeq ($(HAVE_GCC3_OPTIONS),yes)
|
||||
OP_CFLAGS+= -falign-functions=0 -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
|
||||
# that the kernel ELF loader considers as an executable. I think this
|
||||
# is the simplest way to make it self virtualizable!
|
||||
LDFLAGS+=-Wl,-shared
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH),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
|
||||
|
||||
ifeq ($(ARCH),s390)
|
||||
OP_CFLAGS=$(CFLAGS)
|
||||
LDFLAGS+=-Wl,-T,$(SRC_PATH)/s390.ld
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH),sparc)
|
||||
CFLAGS+=-m32 -ffixed-g1 -ffixed-g2 -ffixed-g3 -ffixed-g6
|
||||
LDFLAGS+=-m32
|
||||
OP_CFLAGS=$(CFLAGS) -fno-delayed-branch -ffixed-i0
|
||||
HELPER_CFLAGS=$(CFLAGS) -ffixed-i0 -mflat
|
||||
# -static is used to avoid g1/g3 usage by the dynamic linker
|
||||
LDFLAGS+=-Wl,-T,$(SRC_PATH)/sparc.ld -static
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH),sparc64)
|
||||
CFLAGS+=-m64 -ffixed-g1 -ffixed-g2 -ffixed-g3 -ffixed-g6
|
||||
LDFLAGS+=-m64
|
||||
OP_CFLAGS=$(CFLAGS) -fno-delayed-branch -ffixed-i0
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH),alpha)
|
||||
# -msmall-data is not used because we want two-instruction relocations
|
||||
# for the constant constructions
|
||||
OP_CFLAGS=-Wall -O2 -g
|
||||
# Ensure there's only a single GP
|
||||
CFLAGS += -msmall-data
|
||||
LDFLAGS+=-Wl,-T,$(SRC_PATH)/alpha.ld
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH),ia64)
|
||||
OP_CFLAGS=$(CFLAGS)
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH),arm)
|
||||
OP_CFLAGS=$(CFLAGS) -mno-sched-prolog
|
||||
LDFLAGS+=-Wl,-T,$(SRC_PATH)/arm.ld
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH),m68k)
|
||||
OP_CFLAGS=$(CFLAGS) -fomit-frame-pointer
|
||||
LDFLAGS+=-Wl,-T,m68k.ld
|
||||
endif
|
||||
|
||||
ifeq ($(HAVE_GCC3_OPTIONS),yes)
|
||||
# very important to generate a return at the end of every operation
|
||||
OP_CFLAGS+=-fno-reorder-blocks -fno-optimize-sibling-calls
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_DARWIN),yes)
|
||||
OP_CFLAGS+= -mdynamic-no-pic
|
||||
endif
|
||||
|
||||
#########################################################
|
||||
|
||||
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
|
||||
LDFLAGS+=-p
|
||||
main.o: CFLAGS+=-p
|
||||
endif
|
||||
|
||||
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=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)
|
||||
LIBOBJS+=alpha-dis.o
|
||||
endif
|
||||
ifeq ($(findstring ppc, $(TARGET_ARCH) $(ARCH)),ppc)
|
||||
LIBOBJS+=ppc-dis.o
|
||||
endif
|
||||
ifeq ($(findstring sparc, $(TARGET_ARCH) $(ARCH)),sparc)
|
||||
LIBOBJS+=sparc-dis.o
|
||||
endif
|
||||
ifeq ($(findstring arm, $(TARGET_ARCH) $(ARCH)),arm)
|
||||
LIBOBJS+=arm-dis.o
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH),ia64)
|
||||
OBJS += ia64-syscall.o
|
||||
endif
|
||||
|
||||
all: $(PROGS)
|
||||
|
||||
$(QEMU_USER): $(OBJS)
|
||||
$(CC) $(LDFLAGS) -o $@ $^ $(LIBS)
|
||||
ifeq ($(ARCH),alpha)
|
||||
# Mark as 32 bit binary, i. e. it will be mapped into the low 31 bit of
|
||||
# the address space (31 bit so sign extending doesn't matter)
|
||||
echo -ne '\001\000\000\000' | dd of=qemu bs=1 seek=48 count=4 conv=notrunc
|
||||
endif
|
||||
|
||||
# must use static linking to avoid leaving stuff in virtual address space
|
||||
VL_OBJS=vl.o 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
|
||||
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) $(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
|
||||
|
||||
# libqemu
|
||||
|
||||
libqemu.a: $(LIBOBJS)
|
||||
rm -f $@
|
||||
$(AR) rcs $@ $(LIBOBJS)
|
||||
|
||||
translate.o: translate.c gen-op.h opc.h cpu.h
|
||||
|
||||
translate-all.o: translate-all.c op.h opc.h cpu.h
|
||||
|
||||
op.h: op.o $(DYNGEN)
|
||||
$(DYNGEN) -o $@ $<
|
||||
|
||||
opc.h: op.o $(DYNGEN)
|
||||
$(DYNGEN) -c -o $@ $<
|
||||
|
||||
gen-op.h: op.o $(DYNGEN)
|
||||
$(DYNGEN) -g -o $@ $<
|
||||
|
||||
op.o: op.c
|
||||
$(CC) $(OP_CFLAGS) $(DEFINES) -c -o $@ $<
|
||||
|
||||
helper.o: helper.c
|
||||
$(CC) $(HELPER_CFLAGS) $(DEFINES) -c -o $@ $<
|
||||
|
||||
ifeq ($(TARGET_ARCH), i386)
|
||||
op.o: op.c opreg_template.h ops_template.h ops_template_mem.h ops_mem.h
|
||||
endif
|
||||
|
||||
ifeq ($(TARGET_ARCH), arm)
|
||||
op.o: op.c op_template.h
|
||||
endif
|
||||
|
||||
ifeq ($(TARGET_ARCH), sparc)
|
||||
op.o: op.c op_template.h 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 nwfpe/*.o slirp/*.o
|
||||
|
||||
install: all
|
||||
ifneq ($(PROGS),)
|
||||
install -m 755 -s $(PROGS) "$(bindir)"
|
||||
endif
|
||||
|
||||
ifneq ($(wildcard .depend),)
|
||||
include .depend
|
||||
endif
|
||||
@@ -0,0 +1,61 @@
|
||||
The QEMU x86 emulator
|
||||
---------------------
|
||||
|
||||
INSTALLATION
|
||||
------------
|
||||
|
||||
Type
|
||||
|
||||
./configure
|
||||
make
|
||||
|
||||
to build qemu, qemu-CPU and libqemu.a (CPU is the name of the various
|
||||
supported target CPUs).
|
||||
|
||||
Type
|
||||
|
||||
make install
|
||||
|
||||
to install QEMU in /usr/local
|
||||
|
||||
Tested tool versions
|
||||
--------------------
|
||||
|
||||
In order to compile QEMU succesfully, it is very important that you
|
||||
have the right tools. The most important one is gcc. I cannot guaranty
|
||||
that QEMU works if you do not use a tested gcc version. Look at
|
||||
'configure' and 'Makefile' if you want to make a different gcc
|
||||
version work.
|
||||
|
||||
host gcc binutils glibc linux distribution
|
||||
----------------------------------------------------------------------
|
||||
x86 2.95.2 2.13.2 2.1.3 2.4.18
|
||||
3.2 2.13.2 2.1.3 2.4.18
|
||||
2.96 2.11.93.0.2 2.2.5 2.4.18 Red Hat 7.3
|
||||
3.2.2 2.13.90.0.18 2.3.2 2.4.20 Red Hat 9
|
||||
|
||||
PowerPC 3.3 [4] 2.13.90.0.18 2.3.1 2.4.20briq
|
||||
3.2
|
||||
|
||||
Alpha 3.3 [1] 2.14.90.0.4 2.2.5 2.2.20 [2] Debian 3.0
|
||||
|
||||
Sparc32 2.95.4 2.12.90.0.1 2.2.5 2.4.18 Debian 3.0
|
||||
|
||||
ARM 2.95.4 2.12.90.0.1 2.2.5 2.4.9 [3] Debian 3.0
|
||||
|
||||
[1] On Alpha, QEMU needs the gcc 'visibility' attribute only available
|
||||
for gcc version >= 3.3.
|
||||
[2] Linux >= 2.4.20 is necessary for precise exception support
|
||||
(untested).
|
||||
[3] 2.4.9-ac10-rmk2-np1-cerf2
|
||||
|
||||
[4] gcc 2.95.x generates invalid code when using too many register
|
||||
variables. You must use gcc 3.x on PowerPC.
|
||||
|
||||
Documentation
|
||||
-------------
|
||||
|
||||
Read the documentation in qemu-doc.html.
|
||||
|
||||
|
||||
Fabrice Bellard.
|
||||
@@ -0,0 +1,16 @@
|
||||
Information about the various packages used to build the current qemu
|
||||
x86 binary distribution:
|
||||
|
||||
* gcc 2.95.2 was used for the build. A glibc 2.1.3 Debian distribution
|
||||
was used to get most of the binary packages.
|
||||
|
||||
* wine-20020411 tarball
|
||||
|
||||
./configure --prefix=/usr/local/wine-i386
|
||||
|
||||
All exe and libs were stripped. Some compile time tools and the
|
||||
includes were deleted.
|
||||
|
||||
* ldconfig was launched to build the library links:
|
||||
|
||||
qemu-i386 /usr/gnemul/qemu-i386/bin/ldconfig-i386 -C /usr/gnemul/qemu-i386/etc/ld.so.cache
|
||||
@@ -1,2 +1,66 @@
|
||||
- swap all elf paramters
|
||||
- fix printf for doubles (fp87.c bug ?)
|
||||
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
|
||||
- fix CCOP optimisation
|
||||
- fix all remaining thread lock issues (must put TBs in a specific invalid
|
||||
state, find a solution for tb_flush()).
|
||||
- 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
|
||||
- use -msoft-float on ARM
|
||||
- use kernel traps for unaligned accesses on ARM ?
|
||||
- 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
|
||||
issues, fix 16 bit uid issues)
|
||||
- use page_unprotect_range in every suitable syscall to handle all
|
||||
cases of self modifying code.
|
||||
- use gcc as a backend to generate better code (easy to do by using
|
||||
op-i386.c operations as local inline functions).
|
||||
- add SSE2/MMX operations
|
||||
|
||||
@@ -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_ */
|
||||
|
||||
@@ -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
|
||||
+1963
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,128 @@
|
||||
OUTPUT_FORMAT("elf64-alpha", "elf64-alpha",
|
||||
"elf64-alpha")
|
||||
OUTPUT_ARCH(alpha)
|
||||
ENTRY(__start)
|
||||
SEARCH_DIR(/lib); SEARCH_DIR(/usr/lib); SEARCH_DIR(/usr/local/lib); SEARCH_DIR(/usr/alpha-unknown-linux-gnu/lib);
|
||||
SECTIONS
|
||||
{
|
||||
/* Read-only sections, merged into text segment: */
|
||||
. = 0x60000000 + SIZEOF_HEADERS;
|
||||
.interp : { *(.interp) }
|
||||
.hash : { *(.hash) }
|
||||
.dynsym : { *(.dynsym) }
|
||||
.dynstr : { *(.dynstr) }
|
||||
.gnu.version : { *(.gnu.version) }
|
||||
.gnu.version_d : { *(.gnu.version_d) }
|
||||
.gnu.version_r : { *(.gnu.version_r) }
|
||||
.rel.text :
|
||||
{ *(.rel.text) *(.rel.gnu.linkonce.t*) }
|
||||
.rela.text :
|
||||
{ *(.rela.text) *(.rela.gnu.linkonce.t*) }
|
||||
.rel.data :
|
||||
{ *(.rel.data) *(.rel.gnu.linkonce.d*) }
|
||||
.rela.data :
|
||||
{ *(.rela.data) *(.rela.gnu.linkonce.d*) }
|
||||
.rel.rodata :
|
||||
{ *(.rel.rodata) *(.rel.gnu.linkonce.r*) }
|
||||
.rela.rodata :
|
||||
{ *(.rela.rodata) *(.rela.gnu.linkonce.r*) }
|
||||
.rel.got : { *(.rel.got) }
|
||||
.rela.got : { *(.rela.got) }
|
||||
.rel.ctors : { *(.rel.ctors) }
|
||||
.rela.ctors : { *(.rela.ctors) }
|
||||
.rel.dtors : { *(.rel.dtors) }
|
||||
.rela.dtors : { *(.rela.dtors) }
|
||||
.rel.init : { *(.rel.init) }
|
||||
.rela.init : { *(.rela.init) }
|
||||
.rel.fini : { *(.rel.fini) }
|
||||
.rela.fini : { *(.rela.fini) }
|
||||
.rel.bss : { *(.rel.bss) }
|
||||
.rela.bss : { *(.rela.bss) }
|
||||
.rel.plt : { *(.rel.plt) }
|
||||
.rela.plt : { *(.rela.plt) }
|
||||
.init : { *(.init) } =0x47ff041f
|
||||
.text :
|
||||
{
|
||||
*(.text)
|
||||
/* .gnu.warning sections are handled specially by elf32.em. */
|
||||
*(.gnu.warning)
|
||||
*(.gnu.linkonce.t*)
|
||||
} =0x47ff041f
|
||||
_etext = .;
|
||||
PROVIDE (etext = .);
|
||||
.fini : { *(.fini) } =0x47ff041f
|
||||
.rodata : { *(.rodata) *(.gnu.linkonce.r*) }
|
||||
.rodata1 : { *(.rodata1) }
|
||||
.reginfo : { *(.reginfo) }
|
||||
/* Adjust the address for the data segment. We want to adjust up to
|
||||
the same address within the page on the next page up. */
|
||||
. = ALIGN(0x100000) + (. & (0x100000 - 1));
|
||||
.data :
|
||||
{
|
||||
*(.data)
|
||||
*(.gnu.linkonce.d*)
|
||||
CONSTRUCTORS
|
||||
}
|
||||
.data1 : { *(.data1) }
|
||||
.ctors :
|
||||
{
|
||||
*(.ctors)
|
||||
}
|
||||
.dtors :
|
||||
{
|
||||
*(.dtors)
|
||||
}
|
||||
.plt : { *(.plt) }
|
||||
.got : { *(.got.plt) *(.got) }
|
||||
.dynamic : { *(.dynamic) }
|
||||
/* We want the small data sections together, so single-instruction offsets
|
||||
can access them all, and initialized data all before uninitialized, so
|
||||
we can shorten the on-disk segment size. */
|
||||
.sdata : { *(.sdata) }
|
||||
_edata = .;
|
||||
PROVIDE (edata = .);
|
||||
__bss_start = .;
|
||||
.sbss : { *(.sbss) *(.scommon) }
|
||||
.bss :
|
||||
{
|
||||
*(.dynbss)
|
||||
*(.bss)
|
||||
*(COMMON)
|
||||
}
|
||||
_end = . ;
|
||||
PROVIDE (end = .);
|
||||
/* Stabs debugging sections. */
|
||||
.stab 0 : { *(.stab) }
|
||||
.stabstr 0 : { *(.stabstr) }
|
||||
.stab.excl 0 : { *(.stab.excl) }
|
||||
.stab.exclstr 0 : { *(.stab.exclstr) }
|
||||
.stab.index 0 : { *(.stab.index) }
|
||||
.stab.indexstr 0 : { *(.stab.indexstr) }
|
||||
.comment 0 : { *(.comment) }
|
||||
/* DWARF debug sections.
|
||||
Symbols in the DWARF debugging sections are relative to the beginning
|
||||
of the section so we begin them at 0. */
|
||||
/* DWARF 1 */
|
||||
.debug 0 : { *(.debug) }
|
||||
.line 0 : { *(.line) }
|
||||
/* GNU DWARF 1 extensions */
|
||||
.debug_srcinfo 0 : { *(.debug_srcinfo) }
|
||||
.debug_sfnames 0 : { *(.debug_sfnames) }
|
||||
/* DWARF 1.1 and DWARF 2 */
|
||||
.debug_aranges 0 : { *(.debug_aranges) }
|
||||
.debug_pubnames 0 : { *(.debug_pubnames) }
|
||||
/* DWARF 2 */
|
||||
.debug_info 0 : { *(.debug_info) }
|
||||
.debug_abbrev 0 : { *(.debug_abbrev) }
|
||||
.debug_line 0 : { *(.debug_line) }
|
||||
.debug_frame 0 : { *(.debug_frame) }
|
||||
.debug_str 0 : { *(.debug_str) }
|
||||
.debug_loc 0 : { *(.debug_loc) }
|
||||
.debug_macinfo 0 : { *(.debug_macinfo) }
|
||||
/* SGI/MIPS DWARF 2 extensions */
|
||||
.debug_weaknames 0 : { *(.debug_weaknames) }
|
||||
.debug_funcnames 0 : { *(.debug_funcnames) }
|
||||
.debug_typenames 0 : { *(.debug_typenames) }
|
||||
.debug_varnames 0 : { *(.debug_varnames) }
|
||||
/* These must appear regardless of . */
|
||||
}
|
||||
@@ -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) }
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm",
|
||||
"elf32-littlearm")
|
||||
OUTPUT_ARCH(arm)
|
||||
ENTRY(_start)
|
||||
SEARCH_DIR(/lib); SEARCH_DIR(/usr/lib); SEARCH_DIR(/usr/local/lib); SEARCH_DIR(/usr/alpha-unknown-linux-gnu/lib);
|
||||
SECTIONS
|
||||
{
|
||||
/* Read-only sections, merged into text segment: */
|
||||
. = 0x60000000 + SIZEOF_HEADERS;
|
||||
.interp : { *(.interp) }
|
||||
.hash : { *(.hash) }
|
||||
.dynsym : { *(.dynsym) }
|
||||
.dynstr : { *(.dynstr) }
|
||||
.gnu.version : { *(.gnu.version) }
|
||||
.gnu.version_d : { *(.gnu.version_d) }
|
||||
.gnu.version_r : { *(.gnu.version_r) }
|
||||
.rel.text :
|
||||
{ *(.rel.text) *(.rel.gnu.linkonce.t*) }
|
||||
.rela.text :
|
||||
{ *(.rela.text) *(.rela.gnu.linkonce.t*) }
|
||||
.rel.data :
|
||||
{ *(.rel.data) *(.rel.gnu.linkonce.d*) }
|
||||
.rela.data :
|
||||
{ *(.rela.data) *(.rela.gnu.linkonce.d*) }
|
||||
.rel.rodata :
|
||||
{ *(.rel.rodata) *(.rel.gnu.linkonce.r*) }
|
||||
.rela.rodata :
|
||||
{ *(.rela.rodata) *(.rela.gnu.linkonce.r*) }
|
||||
.rel.got : { *(.rel.got) }
|
||||
.rela.got : { *(.rela.got) }
|
||||
.rel.ctors : { *(.rel.ctors) }
|
||||
.rela.ctors : { *(.rela.ctors) }
|
||||
.rel.dtors : { *(.rel.dtors) }
|
||||
.rela.dtors : { *(.rela.dtors) }
|
||||
.rel.init : { *(.rel.init) }
|
||||
.rela.init : { *(.rela.init) }
|
||||
.rel.fini : { *(.rel.fini) }
|
||||
.rela.fini : { *(.rela.fini) }
|
||||
.rel.bss : { *(.rel.bss) }
|
||||
.rela.bss : { *(.rela.bss) }
|
||||
.rel.plt : { *(.rel.plt) }
|
||||
.rela.plt : { *(.rela.plt) }
|
||||
.init : { *(.init) } =0x47ff041f
|
||||
.text :
|
||||
{
|
||||
*(.text)
|
||||
/* .gnu.warning sections are handled specially by elf32.em. */
|
||||
*(.gnu.warning)
|
||||
*(.gnu.linkonce.t*)
|
||||
} =0x47ff041f
|
||||
_etext = .;
|
||||
PROVIDE (etext = .);
|
||||
.fini : { *(.fini) } =0x47ff041f
|
||||
.rodata : { *(.rodata) *(.gnu.linkonce.r*) }
|
||||
.rodata1 : { *(.rodata1) }
|
||||
.reginfo : { *(.reginfo) }
|
||||
/* Adjust the address for the data segment. We want to adjust up to
|
||||
the same address within the page on the next page up. */
|
||||
. = ALIGN(0x100000) + (. & (0x100000 - 1));
|
||||
.data :
|
||||
{
|
||||
*(.data)
|
||||
*(.gnu.linkonce.d*)
|
||||
CONSTRUCTORS
|
||||
}
|
||||
.data1 : { *(.data1) }
|
||||
.ctors :
|
||||
{
|
||||
*(.ctors)
|
||||
}
|
||||
.dtors :
|
||||
{
|
||||
*(.dtors)
|
||||
}
|
||||
.plt : { *(.plt) }
|
||||
.got : { *(.got.plt) *(.got) }
|
||||
.dynamic : { *(.dynamic) }
|
||||
/* We want the small data sections together, so single-instruction offsets
|
||||
can access them all, and initialized data all before uninitialized, so
|
||||
we can shorten the on-disk segment size. */
|
||||
.sdata : { *(.sdata) }
|
||||
_edata = .;
|
||||
PROVIDE (edata = .);
|
||||
__bss_start = .;
|
||||
.sbss : { *(.sbss) *(.scommon) }
|
||||
.bss :
|
||||
{
|
||||
*(.dynbss)
|
||||
*(.bss)
|
||||
*(COMMON)
|
||||
}
|
||||
_end = . ;
|
||||
PROVIDE (end = .);
|
||||
/* Stabs debugging sections. */
|
||||
.stab 0 : { *(.stab) }
|
||||
.stabstr 0 : { *(.stabstr) }
|
||||
.stab.excl 0 : { *(.stab.excl) }
|
||||
.stab.exclstr 0 : { *(.stab.exclstr) }
|
||||
.stab.index 0 : { *(.stab.index) }
|
||||
.stab.indexstr 0 : { *(.stab.indexstr) }
|
||||
.comment 0 : { *(.comment) }
|
||||
/* DWARF debug sections.
|
||||
Symbols in the DWARF debugging sections are relative to the beginning
|
||||
of the section so we begin them at 0. */
|
||||
/* DWARF 1 */
|
||||
.debug 0 : { *(.debug) }
|
||||
.line 0 : { *(.line) }
|
||||
/* GNU DWARF 1 extensions */
|
||||
.debug_srcinfo 0 : { *(.debug_srcinfo) }
|
||||
.debug_sfnames 0 : { *(.debug_sfnames) }
|
||||
/* DWARF 1.1 and DWARF 2 */
|
||||
.debug_aranges 0 : { *(.debug_aranges) }
|
||||
.debug_pubnames 0 : { *(.debug_pubnames) }
|
||||
/* DWARF 2 */
|
||||
.debug_info 0 : { *(.debug_info) }
|
||||
.debug_abbrev 0 : { *(.debug_abbrev) }
|
||||
.debug_line 0 : { *(.debug_line) }
|
||||
.debug_frame 0 : { *(.debug_frame) }
|
||||
.debug_str 0 : { *(.debug_str) }
|
||||
.debug_loc 0 : { *(.debug_loc) }
|
||||
.debug_macinfo 0 : { *(.debug_macinfo) }
|
||||
/* SGI/MIPS DWARF 2 extensions */
|
||||
.debug_weaknames 0 : { *(.debug_weaknames) }
|
||||
.debug_funcnames 0 : { *(.debug_funcnames) }
|
||||
.debug_typenames 0 : { *(.debug_typenames) }
|
||||
.debug_varnames 0 : { *(.debug_varnames) }
|
||||
/* These must appear regardless of . */
|
||||
}
|
||||
+910
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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 */
|
||||
@@ -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 */
|
||||
@@ -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
@@ -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);
|
||||
}
|
||||
@@ -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 */
|
||||
@@ -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
@@ -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)
|
||||
};
|
||||
@@ -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)
|
||||
};
|
||||
@@ -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)
|
||||
};
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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,
|
||||
};
|
||||
@@ -0,0 +1,600 @@
|
||||
/*
|
||||
* QEMU System Emulator block driver
|
||||
*
|
||||
* Copyright (c) 2003 Fabrice Bellard
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#include "vl.h"
|
||||
#include "block_int.h"
|
||||
|
||||
static BlockDriverState *bdrv_first;
|
||||
static BlockDriver *first_drv;
|
||||
|
||||
void bdrv_register(BlockDriver *bdrv)
|
||||
{
|
||||
bdrv->next = first_drv;
|
||||
first_drv = bdrv;
|
||||
}
|
||||
|
||||
/* 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->is_temporary = 0;
|
||||
bs->encrypted = 0;
|
||||
|
||||
if (snapshot) {
|
||||
BlockDriverState *bs1;
|
||||
int64_t total_size;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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;
|
||||
|
||||
/* call the change callback */
|
||||
if (bs->change_cb)
|
||||
bs->change_cb(bs->change_opaque);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
int n, j;
|
||||
unsigned char sector[512];
|
||||
|
||||
if (!bs->inserted)
|
||||
return -ENOENT;
|
||||
|
||||
if (bs->read_only) {
|
||||
return -EACCES;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* return -1 if error */
|
||||
int bdrv_read(BlockDriverState *bs, int64_t sector_num,
|
||||
uint8_t *buf, int nb_sectors)
|
||||
{
|
||||
int ret, n;
|
||||
BlockDriver *drv = bs->drv;
|
||||
|
||||
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;
|
||||
buf += n * 512;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* return -1 if error */
|
||||
int bdrv_write(BlockDriverState *bs, int64_t sector_num,
|
||||
const uint8_t *buf, int nb_sectors)
|
||||
{
|
||||
if (!bs->inserted)
|
||||
return -1;
|
||||
if (bs->read_only)
|
||||
return -1;
|
||||
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
@@ -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 */
|
||||
@@ -0,0 +1,202 @@
|
||||
#ifndef BSWAP_H
|
||||
#define BSWAP_H
|
||||
|
||||
#include "config-host.h"
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
#ifdef HAVE_BYTESWAP_H
|
||||
#include <byteswap.h>
|
||||
#else
|
||||
|
||||
#define bswap_16(x) \
|
||||
({ \
|
||||
uint16_t __x = (x); \
|
||||
((uint16_t)( \
|
||||
(((uint16_t)(__x) & (uint16_t)0x00ffU) << 8) | \
|
||||
(((uint16_t)(__x) & (uint16_t)0xff00U) >> 8) )); \
|
||||
})
|
||||
|
||||
#define bswap_32(x) \
|
||||
({ \
|
||||
uint32_t __x = (x); \
|
||||
((uint32_t)( \
|
||||
(((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
|
||||
(((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \
|
||||
(((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \
|
||||
(((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) )); \
|
||||
})
|
||||
|
||||
#define bswap_64(x) \
|
||||
({ \
|
||||
uint64_t __x = (x); \
|
||||
((uint64_t)( \
|
||||
(uint64_t)(((uint64_t)(__x) & (uint64_t)0x00000000000000ffULL) << 56) | \
|
||||
(uint64_t)(((uint64_t)(__x) & (uint64_t)0x000000000000ff00ULL) << 40) | \
|
||||
(uint64_t)(((uint64_t)(__x) & (uint64_t)0x0000000000ff0000ULL) << 24) | \
|
||||
(uint64_t)(((uint64_t)(__x) & (uint64_t)0x00000000ff000000ULL) << 8) | \
|
||||
(uint64_t)(((uint64_t)(__x) & (uint64_t)0x000000ff00000000ULL) >> 8) | \
|
||||
(uint64_t)(((uint64_t)(__x) & (uint64_t)0x0000ff0000000000ULL) >> 24) | \
|
||||
(uint64_t)(((uint64_t)(__x) & (uint64_t)0x00ff000000000000ULL) >> 40) | \
|
||||
(uint64_t)(((uint64_t)(__x) & (uint64_t)0xff00000000000000ULL) >> 56) )); \
|
||||
})
|
||||
|
||||
#endif /* !HAVE_BYTESWAP_H */
|
||||
|
||||
static inline uint16_t bswap16(uint16_t x)
|
||||
{
|
||||
return bswap_16(x);
|
||||
}
|
||||
|
||||
static inline uint32_t bswap32(uint32_t x)
|
||||
{
|
||||
return bswap_32(x);
|
||||
}
|
||||
|
||||
static inline uint64_t bswap64(uint64_t x)
|
||||
{
|
||||
return bswap_64(x);
|
||||
}
|
||||
|
||||
static inline void bswap16s(uint16_t *s)
|
||||
{
|
||||
*s = bswap16(*s);
|
||||
}
|
||||
|
||||
static inline void bswap32s(uint32_t *s)
|
||||
{
|
||||
*s = bswap32(*s);
|
||||
}
|
||||
|
||||
static inline void bswap64s(uint64_t *s)
|
||||
{
|
||||
*s = bswap64(*s);
|
||||
}
|
||||
|
||||
#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 */
|
||||
@@ -0,0 +1,589 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# qemu configure script (c) 2003 Fabrice Bellard
|
||||
#
|
||||
# set temporary file name
|
||||
if test ! -z "$TMPDIR" ; then
|
||||
TMPDIR1="${TMPDIR}"
|
||||
elif test ! -z "$TEMPDIR" ; then
|
||||
TMPDIR1="${TEMPDIR}"
|
||||
else
|
||||
TMPDIR1="/tmp"
|
||||
fi
|
||||
|
||||
TMPC="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}.c"
|
||||
TMPO="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}.o"
|
||||
TMPE="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}"
|
||||
TMPS="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}.S"
|
||||
|
||||
# default parameters
|
||||
prefix=""
|
||||
interp_prefix="/usr/gnemul/qemu-%M"
|
||||
static="no"
|
||||
cross_prefix=""
|
||||
cc="gcc"
|
||||
host_cc="gcc"
|
||||
ar="ar"
|
||||
make="make"
|
||||
strip="strip"
|
||||
cpu=`uname -m`
|
||||
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"
|
||||
;;
|
||||
armv4l)
|
||||
cpu="armv4l"
|
||||
;;
|
||||
alpha)
|
||||
cpu="alpha"
|
||||
;;
|
||||
"Power Macintosh"|ppc|ppc64)
|
||||
cpu="powerpc"
|
||||
;;
|
||||
mips)
|
||||
cpu="mips"
|
||||
;;
|
||||
s390)
|
||||
cpu="s390"
|
||||
;;
|
||||
sparc)
|
||||
cpu="sparc"
|
||||
;;
|
||||
sparc64)
|
||||
cpu="sparc64"
|
||||
;;
|
||||
ia64)
|
||||
cpu="ia64"
|
||||
;;
|
||||
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
|
||||
|
||||
if [ "$bsd" = "yes" ] ; then
|
||||
if [ ! "$darwin" = "yes" ] ; then
|
||||
make="gmake"
|
||||
fi
|
||||
target_list="i386-softmmu ppc-softmmu sparc-softmmu"
|
||||
fi
|
||||
|
||||
# find source path
|
||||
# XXX: we assume an absolute path is given when launching configure,
|
||||
# except in './configure' case.
|
||||
source_path=${0%configure}
|
||||
source_path=${source_path%/}
|
||||
source_path_used="yes"
|
||||
if test -z "$source_path" -o "$source_path" = "." ; then
|
||||
source_path=`pwd`
|
||||
source_path_used="no"
|
||||
fi
|
||||
|
||||
for opt do
|
||||
case "$opt" in
|
||||
--prefix=*) prefix=`echo $opt | cut -d '=' -f 2`
|
||||
;;
|
||||
--interp-prefix=*) interp_prefix=`echo $opt | cut -d '=' -f 2`
|
||||
;;
|
||||
--source-path=*) source_path=`echo $opt | cut -d '=' -f 2`
|
||||
;;
|
||||
--cross-prefix=*) cross_prefix=`echo $opt | cut -d '=' -f 2`
|
||||
;;
|
||||
--cc=*) cc=`echo $opt | cut -d '=' -f 2`
|
||||
;;
|
||||
--make=*) make=`echo $opt | cut -d '=' -f 2`
|
||||
;;
|
||||
--extra-cflags=*) CFLAGS="${opt#--extra-cflags=}"
|
||||
;;
|
||||
--extra-ldflags=*) LDFLAGS="${opt#--extra-ldflags=}"
|
||||
;;
|
||||
--extra-libs=*) extralibs=${opt#--extra-libs=}
|
||||
;;
|
||||
--cpu=*) cpu=`echo $opt | cut -d '=' -f 2`
|
||||
;;
|
||||
--target-list=*) target_list=${opt#--target-list=}
|
||||
;;
|
||||
--enable-gprof) gprof="yes"
|
||||
;;
|
||||
--static) static="yes"
|
||||
;;
|
||||
--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
|
||||
|
||||
# Checking for CFLAGS
|
||||
if test -z "$CFLAGS"; then
|
||||
CFLAGS="-O2"
|
||||
fi
|
||||
|
||||
cc="${cross_prefix}${cc}"
|
||||
ar="${cross_prefix}${ar}"
|
||||
strip="${cross_prefix}${strip}"
|
||||
|
||||
if test "$mingw32" = "yes" ; then
|
||||
target_list="i386-softmmu ppc-softmmu sparc-softmmu"
|
||||
EXESUF=".exe"
|
||||
gdbstub="no"
|
||||
oss="no"
|
||||
fi
|
||||
|
||||
if test -z "$cross_prefix" ; then
|
||||
|
||||
# ---
|
||||
# big/little endian test
|
||||
cat > $TMPC << EOF
|
||||
#include <inttypes.h>
|
||||
int main(int argc, char ** argv){
|
||||
volatile uint32_t i=0x01234567;
|
||||
return (*((uint8_t*)(&i))) == 0x67;
|
||||
}
|
||||
EOF
|
||||
|
||||
if $cc -o $TMPE $TMPC 2>/dev/null ; then
|
||||
$TMPE && bigendian="yes"
|
||||
else
|
||||
echo big/little test failed
|
||||
fi
|
||||
|
||||
else
|
||||
|
||||
# if cross compiling, cannot launch a program, so make a static guess
|
||||
if test "$cpu" = "powerpc" -o "$cpu" = "mips" -o "$cpu" = "s390" -o "$cpu" = "sparc" -o "$cpu" = "sparc64" -o "$cpu" = "m68k"; then
|
||||
bigendian="yes"
|
||||
fi
|
||||
|
||||
fi
|
||||
|
||||
# check gcc options support
|
||||
cat > $TMPC <<EOF
|
||||
int main(void) {
|
||||
}
|
||||
EOF
|
||||
|
||||
have_gcc3_options="no"
|
||||
if $cc -fno-reorder-blocks -fno-optimize-sibling-calls -o $TMPO $TMPC 2> /dev/null ; then
|
||||
have_gcc3_options="yes"
|
||||
fi
|
||||
|
||||
##########################################
|
||||
# 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
|
||||
|
||||
Usage: configure [options]
|
||||
Options: [defaults in brackets after descriptions]
|
||||
|
||||
EOF
|
||||
echo "Standard options:"
|
||||
echo " --help print this message"
|
||||
echo " --prefix=PREFIX install in PREFIX [$prefix]"
|
||||
echo " --interp-prefix=PREFIX where to find shared libraries, etc."
|
||||
echo " use %M for cpu name [$interp_prefix]"
|
||||
echo " --target-list=LIST set target list [$target_list]"
|
||||
echo ""
|
||||
echo "Advanced options (experts only):"
|
||||
echo " --source-path=PATH path of source code [$source_path]"
|
||||
echo " --cross-prefix=PREFIX use PREFIX for compile tools [$cross_prefix]"
|
||||
echo " --cc=CC use C compiler CC [$cc]"
|
||||
echo " --make=MAKE use specified make [$make]"
|
||||
echo " --static enable static build [$static]"
|
||||
echo " --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"
|
||||
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 "ELF interp prefix $interp_prefix"
|
||||
fi
|
||||
echo "Source path $source_path"
|
||||
echo "C compiler $cc"
|
||||
echo "make $make"
|
||||
echo "host CPU $cpu"
|
||||
echo "host big endian $bigendian"
|
||||
echo "target list $target_list"
|
||||
echo "gprof enabled $gprof"
|
||||
echo "static build $static"
|
||||
echo "SDL support $sdl"
|
||||
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 "# 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 "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
|
||||
echo "HAVE_GCC3_OPTIONS=yes" >> $config_mak
|
||||
fi
|
||||
echo "HOST_CC=$host_cc" >> $config_mak
|
||||
echo "AR=$ar" >> $config_mak
|
||||
echo "STRIP=$strip -s -R .comment -R .note" >> $config_mak
|
||||
echo "CFLAGS=$CFLAGS" >> $config_mak
|
||||
echo "LDFLAGS=$LDFLAGS" >> $config_mak
|
||||
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
|
||||
elif test "$cpu" = "powerpc" ; then
|
||||
echo "ARCH=ppc" >> $config_mak
|
||||
echo "#define HOST_PPC 1" >> $config_h
|
||||
elif test "$cpu" = "mips" ; then
|
||||
echo "ARCH=mips" >> $config_mak
|
||||
echo "#define HOST_MIPS 1" >> $config_h
|
||||
elif test "$cpu" = "s390" ; then
|
||||
echo "ARCH=s390" >> $config_mak
|
||||
echo "#define HOST_S390 1" >> $config_h
|
||||
elif test "$cpu" = "alpha" ; then
|
||||
echo "ARCH=alpha" >> $config_mak
|
||||
echo "#define HOST_ALPHA 1" >> $config_h
|
||||
elif test "$cpu" = "sparc" ; then
|
||||
echo "ARCH=sparc" >> $config_mak
|
||||
echo "#define HOST_SPARC 1" >> $config_h
|
||||
elif test "$cpu" = "sparc64" ; then
|
||||
echo "ARCH=sparc64" >> $config_mak
|
||||
echo "#define HOST_SPARC64 1" >> $config_h
|
||||
elif test "$cpu" = "ia64" ; then
|
||||
echo "ARCH=ia64" >> $config_mak
|
||||
echo "#define HOST_IA64 1" >> $config_h
|
||||
elif test "$cpu" = "m68k" ; then
|
||||
echo "ARCH=m68k" >> $config_mak
|
||||
echo "#define HOST_M68K 1" >> $config_h
|
||||
else
|
||||
echo "Unsupported CPU"
|
||||
exit 1
|
||||
fi
|
||||
if test "$bigendian" = "yes" ; then
|
||||
echo "WORDS_BIGENDIAN=yes" >> $config_mak
|
||||
echo "#define WORDS_BIGENDIAN 1" >> $config_h
|
||||
fi
|
||||
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 "$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
|
||||
echo "" >>$config_mak
|
||||
echo -n "#define QEMU_VERSION \"" >> $config_h
|
||||
head $source_path/VERSION >> $config_h
|
||||
echo "\"" >> $config_h
|
||||
|
||||
echo "SRC_PATH=$source_path" >> $config_mak
|
||||
echo "TARGET_DIRS=$target_list" >> $config_mak
|
||||
|
||||
# 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"
|
||||
config_mak=$target_dir/config.mak
|
||||
config_h=$target_dir/config.h
|
||||
target_cpu=`echo $target | cut -d '-' -f 1`
|
||||
target_bigendian="no"
|
||||
[ "$target_cpu" = "sparc" ] && target_bigendian=yes
|
||||
[ "$target_cpu" = "ppc" ] && target_bigendian=yes
|
||||
target_softmmu="no"
|
||||
if expr $target : '.*-softmmu' > /dev/null ; then
|
||||
target_softmmu="yes"
|
||||
fi
|
||||
target_user_only="no"
|
||||
if expr $target : '.*-user' > /dev/null ; then
|
||||
target_user_only="yes"
|
||||
fi
|
||||
|
||||
#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
|
||||
echo "/* Automatically generated by configure - do not modify */" > $config_h
|
||||
|
||||
|
||||
echo "include ../config-host.mak" >> $config_mak
|
||||
echo "#include \"../config-host.h\"" >> $config_h
|
||||
|
||||
interp_prefix1=`echo "$interp_prefix" | sed "s/%M/$target_cpu/g"`
|
||||
echo "#define CONFIG_QEMU_PREFIX \"$interp_prefix1\"" >> $config_h
|
||||
|
||||
if test "$target_cpu" = "i386" ; then
|
||||
echo "TARGET_ARCH=i386" >> $config_mak
|
||||
echo "#define TARGET_ARCH \"i386\"" >> $config_h
|
||||
echo "#define TARGET_I386 1" >> $config_h
|
||||
elif test "$target_cpu" = "arm" ; then
|
||||
echo "TARGET_ARCH=arm" >> $config_mak
|
||||
echo "#define TARGET_ARCH \"arm\"" >> $config_h
|
||||
echo "#define TARGET_ARM 1" >> $config_h
|
||||
elif test "$target_cpu" = "sparc" ; then
|
||||
echo "TARGET_ARCH=sparc" >> $config_mak
|
||||
echo "#define TARGET_ARCH \"sparc\"" >> $config_h
|
||||
echo "#define TARGET_SPARC 1" >> $config_h
|
||||
elif test "$target_cpu" = "ppc" ; then
|
||||
echo "TARGET_ARCH=ppc" >> $config_mak
|
||||
echo "#define TARGET_ARCH \"ppc\"" >> $config_h
|
||||
echo "#define TARGET_PPC 1" >> $config_h
|
||||
else
|
||||
echo "Unsupported target CPU"
|
||||
exit 1
|
||||
fi
|
||||
if test "$target_bigendian" = "yes" ; then
|
||||
echo "TARGET_WORDS_BIGENDIAN=yes" >> $config_mak
|
||||
echo "#define TARGET_WORDS_BIGENDIAN 1" >> $config_h
|
||||
fi
|
||||
if test "$target_softmmu" = "yes" ; then
|
||||
echo "CONFIG_SOFTMMU=yes" >> $config_mak
|
||||
echo "#define CONFIG_SOFTMMU 1" >> $config_h
|
||||
fi
|
||||
if test "$target_user_only" = "yes" ; then
|
||||
echo "CONFIG_USER_ONLY=yes" >> $config_mak
|
||||
echo "#define CONFIG_USER_ONLY 1" >> $config_h
|
||||
fi
|
||||
|
||||
# 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
|
||||
if test "$source_path_used" = "yes" ; then
|
||||
DIRS="tests"
|
||||
FILES="Makefile tests/Makefile"
|
||||
for dir in $DIRS ; do
|
||||
mkdir -p $dir
|
||||
done
|
||||
for f in $FILES ; do
|
||||
ln -sf $source_path/$f $f
|
||||
done
|
||||
fi
|
||||
|
||||
rm -f $TMPO $TMPC $TMPE $TMPS
|
||||
@@ -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;
|
||||
}
|
||||
@@ -0,0 +1,727 @@
|
||||
/*
|
||||
* defines common to all virtual CPUs
|
||||
*
|
||||
* Copyright (c) 2003 Fabrice Bellard
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#ifndef CPU_ALL_H
|
||||
#define CPU_ALL_H
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
static inline int ldsb_raw(void *ptr)
|
||||
{
|
||||
return *(int8_t *)ptr;
|
||||
}
|
||||
|
||||
static inline void stb_raw(void *ptr, int v)
|
||||
{
|
||||
*(uint8_t *)ptr = v;
|
||||
}
|
||||
|
||||
/* NOTE: on arm, putting 2 in /proc/sys/debug/alignment so that the
|
||||
kernel handles unaligned load/stores may give better results, but
|
||||
it is a system wide setting : bad */
|
||||
#if !defined(TARGET_WORDS_BIGENDIAN) && (defined(WORDS_BIGENDIAN) || defined(WORDS_ALIGNED))
|
||||
|
||||
/* conservative code for little endian unaligned accesses */
|
||||
static inline int lduw_raw(void *ptr)
|
||||
{
|
||||
#ifdef __powerpc__
|
||||
int val;
|
||||
__asm__ __volatile__ ("lhbrx %0,0,%1" : "=r" (val) : "r" (ptr));
|
||||
return val;
|
||||
#else
|
||||
uint8_t *p = ptr;
|
||||
return p[0] | (p[1] << 8);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline int ldsw_raw(void *ptr)
|
||||
{
|
||||
#ifdef __powerpc__
|
||||
int val;
|
||||
__asm__ __volatile__ ("lhbrx %0,0,%1" : "=r" (val) : "r" (ptr));
|
||||
return (int16_t)val;
|
||||
#else
|
||||
uint8_t *p = ptr;
|
||||
return (int16_t)(p[0] | (p[1] << 8));
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline int ldl_raw(void *ptr)
|
||||
{
|
||||
#ifdef __powerpc__
|
||||
int val;
|
||||
__asm__ __volatile__ ("lwbrx %0,0,%1" : "=r" (val) : "r" (ptr));
|
||||
return val;
|
||||
#else
|
||||
uint8_t *p = ptr;
|
||||
return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline uint64_t ldq_raw(void *ptr)
|
||||
{
|
||||
uint8_t *p = ptr;
|
||||
uint32_t v1, v2;
|
||||
v1 = ldl_raw(p);
|
||||
v2 = ldl_raw(p + 4);
|
||||
return v1 | ((uint64_t)v2 << 32);
|
||||
}
|
||||
|
||||
static inline void stw_raw(void *ptr, int v)
|
||||
{
|
||||
#ifdef __powerpc__
|
||||
__asm__ __volatile__ ("sthbrx %1,0,%2" : "=m" (*(uint16_t *)ptr) : "r" (v), "r" (ptr));
|
||||
#else
|
||||
uint8_t *p = ptr;
|
||||
p[0] = v;
|
||||
p[1] = v >> 8;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void stl_raw(void *ptr, int v)
|
||||
{
|
||||
#ifdef __powerpc__
|
||||
__asm__ __volatile__ ("stwbrx %1,0,%2" : "=m" (*(uint32_t *)ptr) : "r" (v), "r" (ptr));
|
||||
#else
|
||||
uint8_t *p = ptr;
|
||||
p[0] = v;
|
||||
p[1] = v >> 8;
|
||||
p[2] = v >> 16;
|
||||
p[3] = v >> 24;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void stq_raw(void *ptr, uint64_t v)
|
||||
{
|
||||
uint8_t *p = ptr;
|
||||
stl_raw(p, (uint32_t)v);
|
||||
stl_raw(p + 4, v >> 32);
|
||||
}
|
||||
|
||||
/* float access */
|
||||
|
||||
static inline float ldfl_raw(void *ptr)
|
||||
{
|
||||
union {
|
||||
float f;
|
||||
uint32_t i;
|
||||
} u;
|
||||
u.i = ldl_raw(ptr);
|
||||
return u.f;
|
||||
}
|
||||
|
||||
static inline void stfl_raw(void *ptr, float v)
|
||||
{
|
||||
union {
|
||||
float f;
|
||||
uint32_t i;
|
||||
} u;
|
||||
u.f = v;
|
||||
stl_raw(ptr, u.i);
|
||||
}
|
||||
|
||||
static inline double ldfq_raw(void *ptr)
|
||||
{
|
||||
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)
|
||||
{
|
||||
CPU_DoubleU u;
|
||||
u.d = v;
|
||||
stl_raw(ptr, u.l.lower);
|
||||
stl_raw(ptr + 4, u.l.upper);
|
||||
}
|
||||
|
||||
#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]);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline int ldsw_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 (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];
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline uint64_t ldq_raw(void *ptr)
|
||||
{
|
||||
uint32_t a,b;
|
||||
a = ldl_raw(ptr);
|
||||
b = ldl_raw(ptr+4);
|
||||
return (((uint64_t)a<<32)|b);
|
||||
}
|
||||
|
||||
static inline void stw_raw(void *ptr, int v)
|
||||
{
|
||||
#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_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
|
||||
|
||||
static inline int lduw_raw(void *ptr)
|
||||
{
|
||||
return *(uint16_t *)ptr;
|
||||
}
|
||||
|
||||
static inline int ldsw_raw(void *ptr)
|
||||
{
|
||||
return *(int16_t *)ptr;
|
||||
}
|
||||
|
||||
static inline int ldl_raw(void *ptr)
|
||||
{
|
||||
return *(uint32_t *)ptr;
|
||||
}
|
||||
|
||||
static inline uint64_t ldq_raw(void *ptr)
|
||||
{
|
||||
return *(uint64_t *)ptr;
|
||||
}
|
||||
|
||||
static inline void stw_raw(void *ptr, int v)
|
||||
{
|
||||
*(uint16_t *)ptr = v;
|
||||
}
|
||||
|
||||
static inline void stl_raw(void *ptr, int v)
|
||||
{
|
||||
*(uint32_t *)ptr = v;
|
||||
}
|
||||
|
||||
static inline void stq_raw(void *ptr, uint64_t v)
|
||||
{
|
||||
*(uint64_t *)ptr = v;
|
||||
}
|
||||
|
||||
/* float access */
|
||||
|
||||
static inline float ldfl_raw(void *ptr)
|
||||
{
|
||||
return *(float *)ptr;
|
||||
}
|
||||
|
||||
static inline double ldfq_raw(void *ptr)
|
||||
{
|
||||
return *(double *)ptr;
|
||||
}
|
||||
|
||||
static inline void stfl_raw(void *ptr, float v)
|
||||
{
|
||||
*(float *)ptr = v;
|
||||
}
|
||||
|
||||
static inline void stfq_raw(void *ptr, double v)
|
||||
{
|
||||
*(double *)ptr = v;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* MMU memory access macros */
|
||||
|
||||
#if defined(CONFIG_USER_ONLY)
|
||||
|
||||
/* if user mode, no other memory access functions */
|
||||
#define ldub(p) ldub_raw(p)
|
||||
#define ldsb(p) ldsb_raw(p)
|
||||
#define lduw(p) lduw_raw(p)
|
||||
#define ldsw(p) ldsw_raw(p)
|
||||
#define ldl(p) ldl_raw(p)
|
||||
#define ldq(p) ldq_raw(p)
|
||||
#define ldfl(p) ldfl_raw(p)
|
||||
#define ldfq(p) ldfq_raw(p)
|
||||
#define stb(p, v) stb_raw(p, v)
|
||||
#define stw(p, v) stw_raw(p, v)
|
||||
#define stl(p, v) stl_raw(p, v)
|
||||
#define stq(p, v) stq_raw(p, v)
|
||||
#define stfl(p, v) stfl_raw(p, v)
|
||||
#define stfq(p, v) stfq_raw(p, v)
|
||||
|
||||
#define ldub_code(p) ldub_raw(p)
|
||||
#define ldsb_code(p) ldsb_raw(p)
|
||||
#define lduw_code(p) lduw_raw(p)
|
||||
#define ldsw_code(p) ldsw_raw(p)
|
||||
#define ldl_code(p) ldl_raw(p)
|
||||
|
||||
#define ldub_kernel(p) ldub_raw(p)
|
||||
#define ldsb_kernel(p) ldsb_raw(p)
|
||||
#define lduw_kernel(p) lduw_raw(p)
|
||||
#define ldsw_kernel(p) ldsw_raw(p)
|
||||
#define ldl_kernel(p) ldl_raw(p)
|
||||
#define ldfl_kernel(p) ldfl_raw(p)
|
||||
#define ldfq_kernel(p) ldfq_raw(p)
|
||||
#define stb_kernel(p, v) stb_raw(p, v)
|
||||
#define stw_kernel(p, v) stw_raw(p, v)
|
||||
#define stl_kernel(p, v) stl_raw(p, v)
|
||||
#define stq_kernel(p, v) stq_raw(p, v)
|
||||
#define stfl_kernel(p, v) stfl_raw(p, v)
|
||||
#define stfq_kernel(p, vt) stfq_raw(p, v)
|
||||
|
||||
#endif /* defined(CONFIG_USER_ONLY) */
|
||||
|
||||
/* page related stuff */
|
||||
|
||||
#define TARGET_PAGE_SIZE (1 << TARGET_PAGE_BITS)
|
||||
#define TARGET_PAGE_MASK ~(TARGET_PAGE_SIZE - 1)
|
||||
#define TARGET_PAGE_ALIGN(addr) (((addr) + TARGET_PAGE_SIZE - 1) & TARGET_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) + qemu_host_page_size - 1) & qemu_host_page_mask)
|
||||
|
||||
/* same as PROT_xxx */
|
||||
#define PAGE_READ 0x0001
|
||||
#define PAGE_WRITE 0x0002
|
||||
#define PAGE_EXEC 0x0004
|
||||
#define PAGE_BITS (PAGE_READ | PAGE_WRITE | PAGE_EXEC)
|
||||
#define PAGE_VALID 0x0008
|
||||
/* original state of the write flag (used when tracking self-modifying
|
||||
code */
|
||||
#define PAGE_WRITE_ORG 0x0010
|
||||
|
||||
void page_dump(FILE *f);
|
||||
int page_get_flags(unsigned long address);
|
||||
void page_set_flags(unsigned long start, unsigned long end, int flags);
|
||||
void page_unprotect_range(uint8_t *data, unsigned long data_size);
|
||||
|
||||
#define SINGLE_CPU_DEFINES
|
||||
#ifdef SINGLE_CPU_DEFINES
|
||||
|
||||
#if defined(TARGET_I386)
|
||||
|
||||
#define CPUState CPUX86State
|
||||
#define cpu_init cpu_x86_init
|
||||
#define cpu_exec cpu_x86_exec
|
||||
#define cpu_gen_code cpu_x86_gen_code
|
||||
#define cpu_signal_handler cpu_x86_signal_handler
|
||||
|
||||
#elif defined(TARGET_ARM)
|
||||
|
||||
#define CPUState CPUARMState
|
||||
#define cpu_init cpu_arm_init
|
||||
#define cpu_exec cpu_arm_exec
|
||||
#define cpu_gen_code cpu_arm_gen_code
|
||||
#define cpu_signal_handler cpu_arm_signal_handler
|
||||
|
||||
#elif defined(TARGET_SPARC)
|
||||
|
||||
#define CPUState CPUSPARCState
|
||||
#define cpu_init cpu_sparc_init
|
||||
#define cpu_exec cpu_sparc_exec
|
||||
#define cpu_gen_code cpu_sparc_gen_code
|
||||
#define cpu_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
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* SINGLE_CPU_DEFINES */
|
||||
|
||||
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_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, 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[];
|
||||
|
||||
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 */
|
||||
|
||||
extern int phys_ram_size;
|
||||
extern int phys_ram_fd;
|
||||
extern uint8_t *phys_ram_base;
|
||||
extern uint8_t *phys_ram_dirty;
|
||||
|
||||
/* 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,
|
||||
void *opaque);
|
||||
CPUWriteMemoryFunc **cpu_get_io_memory_write(int io_index);
|
||||
CPUReadMemoryFunc **cpu_get_io_memory_read(int io_index);
|
||||
|
||||
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 */
|
||||
+95
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* common defines for all CPUs
|
||||
*
|
||||
* Copyright (c) 2003 Fabrice Bellard
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#ifndef CPU_DEFS_H
|
||||
#define CPU_DEFS_H
|
||||
|
||||
#include "config.h"
|
||||
#include <setjmp.h>
|
||||
#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 */
|
||||
#define EXCP_DEBUG 258 /* cpu stopped after a breakpoint or singlestep */
|
||||
|
||||
#define MAX_BREAKPOINTS 32
|
||||
|
||||
#define CPU_TLB_SIZE 256
|
||||
|
||||
typedef struct CPUTLBEntry {
|
||||
/* bit 31 to TARGET_PAGE_BITS : virtual address
|
||||
bit TARGET_PAGE_BITS-1..IO_MEM_SHIFT : if non zero, memory io
|
||||
zone number
|
||||
bit 3 : indicates that the entry is invalid
|
||||
bit 2..0 : zero
|
||||
*/
|
||||
target_ulong address;
|
||||
/* addend to virtual address to get physical address */
|
||||
target_phys_addr_t addend;
|
||||
} CPUTLBEntry;
|
||||
|
||||
#endif
|
||||
+1038
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,406 @@
|
||||
/* Interface between the opcode library and its callers.
|
||||
Written by Cygnus Support, 1993.
|
||||
|
||||
The opcode library (libopcodes.a) provides instruction decoders for
|
||||
a large variety of instruction sets, callable with an identical
|
||||
interface, for making instruction-processing programs more independent
|
||||
of the instruction set being processed. */
|
||||
|
||||
#ifndef DIS_ASM_H
|
||||
#define DIS_ASM_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#define PARAMS(x) x
|
||||
typedef void *PTR;
|
||||
typedef uint64_t bfd_vma;
|
||||
typedef 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,
|
||||
bfd_target_aout_flavour,
|
||||
bfd_target_coff_flavour,
|
||||
bfd_target_ecoff_flavour,
|
||||
bfd_target_elf_flavour,
|
||||
bfd_target_ieee_flavour,
|
||||
bfd_target_nlm_flavour,
|
||||
bfd_target_oasys_flavour,
|
||||
bfd_target_tekhex_flavour,
|
||||
bfd_target_srec_flavour,
|
||||
bfd_target_ihex_flavour,
|
||||
bfd_target_som_flavour,
|
||||
bfd_target_os9k_flavour,
|
||||
bfd_target_versados_flavour,
|
||||
bfd_target_msdos_flavour,
|
||||
bfd_target_evax_flavour
|
||||
};
|
||||
|
||||
enum bfd_endian { BFD_ENDIAN_BIG, BFD_ENDIAN_LITTLE, BFD_ENDIAN_UNKNOWN };
|
||||
|
||||
enum bfd_architecture
|
||||
{
|
||||
bfd_arch_unknown, /* File arch not known */
|
||||
bfd_arch_obscure, /* Arch known, not one of these */
|
||||
bfd_arch_m68k, /* Motorola 68xxx */
|
||||
#define bfd_mach_m68000 1
|
||||
#define bfd_mach_m68008 2
|
||||
#define bfd_mach_m68010 3
|
||||
#define bfd_mach_m68020 4
|
||||
#define bfd_mach_m68030 5
|
||||
#define bfd_mach_m68040 6
|
||||
#define bfd_mach_m68060 7
|
||||
bfd_arch_vax, /* DEC Vax */
|
||||
bfd_arch_i960, /* Intel 960 */
|
||||
/* The order of the following is important.
|
||||
lower number indicates a machine type that
|
||||
only accepts a subset of the instructions
|
||||
available to machines with higher numbers.
|
||||
The exception is the "ca", which is
|
||||
incompatible with all other machines except
|
||||
"core". */
|
||||
|
||||
#define bfd_mach_i960_core 1
|
||||
#define bfd_mach_i960_ka_sa 2
|
||||
#define bfd_mach_i960_kb_sb 3
|
||||
#define bfd_mach_i960_mc 4
|
||||
#define bfd_mach_i960_xa 5
|
||||
#define bfd_mach_i960_ca 6
|
||||
#define bfd_mach_i960_jx 7
|
||||
#define bfd_mach_i960_hx 8
|
||||
|
||||
bfd_arch_a29k, /* AMD 29000 */
|
||||
bfd_arch_sparc, /* SPARC */
|
||||
#define bfd_mach_sparc 1
|
||||
/* The difference between v8plus and v9 is that v9 is a true 64 bit env. */
|
||||
#define bfd_mach_sparc_sparclet 2
|
||||
#define bfd_mach_sparc_sparclite 3
|
||||
#define bfd_mach_sparc_v8plus 4
|
||||
#define bfd_mach_sparc_v8plusa 5 /* with ultrasparc add'ns. */
|
||||
#define bfd_mach_sparc_sparclite_le 6
|
||||
#define bfd_mach_sparc_v9 7
|
||||
#define bfd_mach_sparc_v9a 8 /* with ultrasparc add'ns. */
|
||||
#define bfd_mach_sparc_v8plusb 9 /* with cheetah add'ns. */
|
||||
#define bfd_mach_sparc_v9b 10 /* with cheetah add'ns. */
|
||||
/* Nonzero if MACH has the v9 instruction set. */
|
||||
#define bfd_mach_sparc_v9_p(mach) \
|
||||
((mach) >= bfd_mach_sparc_v8plus && (mach) <= bfd_mach_sparc_v9b \
|
||||
&& (mach) != bfd_mach_sparc_sparclite_le)
|
||||
bfd_arch_mips, /* MIPS Rxxxx */
|
||||
#define bfd_mach_mips3000 3000
|
||||
#define bfd_mach_mips3900 3900
|
||||
#define bfd_mach_mips4000 4000
|
||||
#define bfd_mach_mips4010 4010
|
||||
#define bfd_mach_mips4100 4100
|
||||
#define bfd_mach_mips4300 4300
|
||||
#define bfd_mach_mips4400 4400
|
||||
#define bfd_mach_mips4600 4600
|
||||
#define bfd_mach_mips4650 4650
|
||||
#define bfd_mach_mips5000 5000
|
||||
#define bfd_mach_mips6000 6000
|
||||
#define bfd_mach_mips8000 8000
|
||||
#define bfd_mach_mips10000 10000
|
||||
#define bfd_mach_mips16 16
|
||||
bfd_arch_i386, /* Intel 386 */
|
||||
#define bfd_mach_i386_i386 0
|
||||
#define bfd_mach_i386_i8086 1
|
||||
#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 */
|
||||
bfd_arch_romp, /* IBM ROMP PC/RT */
|
||||
bfd_arch_alliant, /* Alliant */
|
||||
bfd_arch_convex, /* Convex */
|
||||
bfd_arch_m88k, /* Motorola 88xxx */
|
||||
bfd_arch_pyramid, /* Pyramid Technology */
|
||||
bfd_arch_h8300, /* Hitachi H8/300 */
|
||||
#define bfd_mach_h8300 1
|
||||
#define bfd_mach_h8300h 2
|
||||
#define bfd_mach_h8300s 3
|
||||
bfd_arch_powerpc, /* PowerPC */
|
||||
bfd_arch_rs6000, /* IBM RS/6000 */
|
||||
bfd_arch_hppa, /* HP PA RISC */
|
||||
bfd_arch_d10v, /* Mitsubishi D10V */
|
||||
bfd_arch_z8k, /* Zilog Z8000 */
|
||||
#define bfd_mach_z8001 1
|
||||
#define bfd_mach_z8002 2
|
||||
bfd_arch_h8500, /* Hitachi H8/500 */
|
||||
bfd_arch_sh, /* Hitachi SH */
|
||||
#define bfd_mach_sh 0
|
||||
#define bfd_mach_sh3 0x30
|
||||
#define bfd_mach_sh3e 0x3e
|
||||
#define bfd_mach_sh4 0x40
|
||||
bfd_arch_alpha, /* Dec Alpha */
|
||||
bfd_arch_arm, /* Advanced Risc Machines ARM */
|
||||
#define bfd_mach_arm_2 1
|
||||
#define bfd_mach_arm_2a 2
|
||||
#define bfd_mach_arm_3 3
|
||||
#define bfd_mach_arm_3M 4
|
||||
#define bfd_mach_arm_4 5
|
||||
#define bfd_mach_arm_4T 6
|
||||
bfd_arch_ns32k, /* National Semiconductors ns32000 */
|
||||
bfd_arch_w65, /* WDC 65816 */
|
||||
bfd_arch_tic30, /* Texas Instruments TMS320C30 */
|
||||
bfd_arch_v850, /* NEC V850 */
|
||||
#define bfd_mach_v850 0
|
||||
bfd_arch_arc, /* Argonaut RISC Core */
|
||||
#define bfd_mach_arc_base 0
|
||||
bfd_arch_m32r, /* Mitsubishi M32R/D */
|
||||
#define bfd_mach_m32r 0 /* backwards compatibility */
|
||||
bfd_arch_mn10200, /* Matsushita MN10200 */
|
||||
bfd_arch_mn10300, /* Matsushita MN10300 */
|
||||
bfd_arch_last
|
||||
};
|
||||
|
||||
typedef struct symbol_cache_entry
|
||||
{
|
||||
const char *name;
|
||||
union
|
||||
{
|
||||
PTR p;
|
||||
bfd_vma i;
|
||||
} udata;
|
||||
} asymbol;
|
||||
|
||||
typedef int (*fprintf_ftype) PARAMS((FILE*, const char*, ...));
|
||||
|
||||
enum dis_insn_type {
|
||||
dis_noninsn, /* Not a valid instruction */
|
||||
dis_nonbranch, /* Not a branch instruction */
|
||||
dis_branch, /* Unconditional branch */
|
||||
dis_condbranch, /* Conditional branch */
|
||||
dis_jsr, /* Jump to subroutine */
|
||||
dis_condjsr, /* Conditional jump to subroutine */
|
||||
dis_dref, /* Data reference instruction */
|
||||
dis_dref2 /* Two data references in instruction */
|
||||
};
|
||||
|
||||
/* This struct is passed into the instruction decoding routine,
|
||||
and is passed back out into each callback. The various fields are used
|
||||
for conveying information from your main routine into your callbacks,
|
||||
for passing information into the instruction decoders (such as the
|
||||
addresses of the callback functions), or for passing information
|
||||
back from the instruction decoders to their callers.
|
||||
|
||||
It must be initialized before it is first passed; this can be done
|
||||
by hand, or using one of the initialization macros below. */
|
||||
|
||||
typedef struct disassemble_info {
|
||||
fprintf_ftype fprintf_func;
|
||||
FILE *stream;
|
||||
PTR application_data;
|
||||
|
||||
/* Target description. We could replace this with a pointer to the bfd,
|
||||
but that would require one. There currently isn't any such requirement
|
||||
so to avoid introducing one we record these explicitly. */
|
||||
/* The bfd_flavour. This can be bfd_target_unknown_flavour. */
|
||||
enum bfd_flavour flavour;
|
||||
/* The bfd_arch value. */
|
||||
enum bfd_architecture arch;
|
||||
/* The bfd_mach value. */
|
||||
unsigned long mach;
|
||||
/* Endianness (for bi-endian cpus). Mono-endian cpus can ignore this. */
|
||||
enum bfd_endian endian;
|
||||
|
||||
/* An array of pointers to symbols either at the location being disassembled
|
||||
or at the start of the function being disassembled. The array is sorted
|
||||
so that the first symbol is intended to be the one used. The others are
|
||||
present for any misc. purposes. This is not set reliably, but if it is
|
||||
not NULL, it is correct. */
|
||||
asymbol **symbols;
|
||||
/* Number of symbols in array. */
|
||||
int num_symbols;
|
||||
|
||||
/* For use by the disassembler.
|
||||
The top 16 bits are reserved for public use (and are documented here).
|
||||
The bottom 16 bits are for the internal use of the disassembler. */
|
||||
unsigned long flags;
|
||||
#define INSN_HAS_RELOC 0x80000000
|
||||
PTR private_data;
|
||||
|
||||
/* Function used to get bytes to disassemble. MEMADDR is the
|
||||
address of the stuff to be disassembled, MYADDR is the address to
|
||||
put the bytes in, and LENGTH is the number of bytes to read.
|
||||
INFO is a pointer to this struct.
|
||||
Returns an errno value or 0 for success. */
|
||||
int (*read_memory_func)
|
||||
PARAMS ((bfd_vma memaddr, bfd_byte *myaddr, int length,
|
||||
struct disassemble_info *info));
|
||||
|
||||
/* Function which should be called if we get an error that we can't
|
||||
recover from. STATUS is the errno value from read_memory_func and
|
||||
MEMADDR is the address that we were trying to read. INFO is a
|
||||
pointer to this struct. */
|
||||
void (*memory_error_func)
|
||||
PARAMS ((int status, bfd_vma memaddr, struct disassemble_info *info));
|
||||
|
||||
/* Function called to print ADDR. */
|
||||
void (*print_address_func)
|
||||
PARAMS ((bfd_vma addr, struct disassemble_info *info));
|
||||
|
||||
/* Function called to determine if there is a symbol at the given ADDR.
|
||||
If there is, the function returns 1, otherwise it returns 0.
|
||||
This is used by ports which support an overlay manager where
|
||||
the overlay number is held in the top part of an address. In
|
||||
some circumstances we want to include the overlay number in the
|
||||
address, (normally because there is a symbol associated with
|
||||
that address), but sometimes we want to mask out the overlay bits. */
|
||||
int (* symbol_at_address_func)
|
||||
PARAMS ((bfd_vma addr, struct disassemble_info * info));
|
||||
|
||||
/* These are for buffer_read_memory. */
|
||||
bfd_byte *buffer;
|
||||
bfd_vma buffer_vma;
|
||||
int buffer_length;
|
||||
|
||||
/* This variable may be set by the instruction decoder. It suggests
|
||||
the number of bytes objdump should display on a single line. If
|
||||
the instruction decoder sets this, it should always set it to
|
||||
the same value in order to get reasonable looking output. */
|
||||
int bytes_per_line;
|
||||
|
||||
/* the next two variables control the way objdump displays the raw data */
|
||||
/* For example, if bytes_per_line is 8 and bytes_per_chunk is 4, the */
|
||||
/* output will look like this:
|
||||
00: 00000000 00000000
|
||||
with the chunks displayed according to "display_endian". */
|
||||
int bytes_per_chunk;
|
||||
enum bfd_endian display_endian;
|
||||
|
||||
/* Results from instruction decoders. Not all decoders yet support
|
||||
this information. This info is set each time an instruction is
|
||||
decoded, and is only valid for the last such instruction.
|
||||
|
||||
To determine whether this decoder supports this information, set
|
||||
insn_info_valid to 0, decode an instruction, then check it. */
|
||||
|
||||
char insn_info_valid; /* Branch info has been set. */
|
||||
char branch_delay_insns; /* How many sequential insn's will run before
|
||||
a branch takes effect. (0 = normal) */
|
||||
char data_size; /* Size of data reference in insn, in bytes */
|
||||
enum dis_insn_type insn_type; /* Type of instruction */
|
||||
bfd_vma target; /* Target address of branch or dref, if known;
|
||||
zero if unknown. */
|
||||
bfd_vma target2; /* Second target address for dref2 */
|
||||
|
||||
/* Command line options specific to the target disassembler. */
|
||||
char * disassembler_options;
|
||||
|
||||
} disassemble_info;
|
||||
|
||||
|
||||
/* Standard disassemblers. Disassemble one instruction at the given
|
||||
target address. Return number of bytes processed. */
|
||||
typedef int (*disassembler_ftype)
|
||||
PARAMS((bfd_vma, disassemble_info *));
|
||||
|
||||
extern int print_insn_big_mips PARAMS ((bfd_vma, disassemble_info*));
|
||||
extern int print_insn_little_mips PARAMS ((bfd_vma, disassemble_info*));
|
||||
extern int print_insn_i386 PARAMS ((bfd_vma, disassemble_info*));
|
||||
extern int print_insn_m68k PARAMS ((bfd_vma, disassemble_info*));
|
||||
extern int print_insn_z8001 PARAMS ((bfd_vma, disassemble_info*));
|
||||
extern int print_insn_z8002 PARAMS ((bfd_vma, disassemble_info*));
|
||||
extern int print_insn_h8300 PARAMS ((bfd_vma, disassemble_info*));
|
||||
extern int print_insn_h8300h PARAMS ((bfd_vma, disassemble_info*));
|
||||
extern int print_insn_h8300s PARAMS ((bfd_vma, disassemble_info*));
|
||||
extern int print_insn_h8500 PARAMS ((bfd_vma, disassemble_info*));
|
||||
extern int print_insn_alpha PARAMS ((bfd_vma, disassemble_info*));
|
||||
extern disassembler_ftype arc_get_disassembler PARAMS ((int, int));
|
||||
extern int print_insn_arm PARAMS ((bfd_vma, disassemble_info*));
|
||||
extern int print_insn_sparc PARAMS ((bfd_vma, disassemble_info*));
|
||||
extern int print_insn_big_a29k PARAMS ((bfd_vma, disassemble_info*));
|
||||
extern int print_insn_little_a29k PARAMS ((bfd_vma, disassemble_info*));
|
||||
extern int print_insn_i960 PARAMS ((bfd_vma, disassemble_info*));
|
||||
extern int print_insn_sh PARAMS ((bfd_vma, disassemble_info*));
|
||||
extern int print_insn_shl PARAMS ((bfd_vma, disassemble_info*));
|
||||
extern int print_insn_hppa PARAMS ((bfd_vma, disassemble_info*));
|
||||
extern int print_insn_m32r PARAMS ((bfd_vma, disassemble_info*));
|
||||
extern int print_insn_m88k PARAMS ((bfd_vma, disassemble_info*));
|
||||
extern int print_insn_mn10200 PARAMS ((bfd_vma, disassemble_info*));
|
||||
extern int print_insn_mn10300 PARAMS ((bfd_vma, disassemble_info*));
|
||||
extern int print_insn_ns32k PARAMS ((bfd_vma, disassemble_info*));
|
||||
extern int print_insn_big_powerpc PARAMS ((bfd_vma, disassemble_info*));
|
||||
extern int print_insn_little_powerpc PARAMS ((bfd_vma, disassemble_info*));
|
||||
extern int print_insn_rs6000 PARAMS ((bfd_vma, disassemble_info*));
|
||||
extern int print_insn_w65 PARAMS ((bfd_vma, disassemble_info*));
|
||||
extern int print_insn_d10v PARAMS ((bfd_vma, disassemble_info*));
|
||||
extern int print_insn_v850 PARAMS ((bfd_vma, disassemble_info*));
|
||||
extern int print_insn_tic30 PARAMS ((bfd_vma, disassemble_info*));
|
||||
extern int print_insn_ppc PARAMS ((bfd_vma, disassemble_info*));
|
||||
|
||||
#if 0
|
||||
/* Fetch the disassembler for a given BFD, if that support is available. */
|
||||
extern disassembler_ftype disassembler PARAMS ((bfd *));
|
||||
#endif
|
||||
|
||||
|
||||
/* This block of definitions is for particular callers who read instructions
|
||||
into a buffer before calling the instruction decoder. */
|
||||
|
||||
/* Here is a function which callers may wish to use for read_memory_func.
|
||||
It gets bytes from a buffer. */
|
||||
extern int buffer_read_memory
|
||||
PARAMS ((bfd_vma, bfd_byte *, int, struct disassemble_info *));
|
||||
|
||||
/* This function goes with buffer_read_memory.
|
||||
It prints a message using info->fprintf_func and info->stream. */
|
||||
extern void perror_memory PARAMS ((int, bfd_vma, struct disassemble_info *));
|
||||
|
||||
|
||||
/* Just print the address in hex. This is included for completeness even
|
||||
though both GDB and objdump provide their own (to print symbolic
|
||||
addresses). */
|
||||
extern void generic_print_address
|
||||
PARAMS ((bfd_vma, struct disassemble_info *));
|
||||
|
||||
/* Always true. */
|
||||
extern int generic_symbol_at_address
|
||||
PARAMS ((bfd_vma, struct disassemble_info *));
|
||||
|
||||
/* Macro to initialize a disassemble_info struct. This should be called
|
||||
by all applications creating such a struct. */
|
||||
#define INIT_DISASSEMBLE_INFO(INFO, STREAM, FPRINTF_FUNC) \
|
||||
(INFO).flavour = bfd_target_unknown_flavour, \
|
||||
(INFO).arch = bfd_arch_unknown, \
|
||||
(INFO).mach = 0, \
|
||||
(INFO).endian = BFD_ENDIAN_UNKNOWN, \
|
||||
INIT_DISASSEMBLE_INFO_NO_ARCH(INFO, STREAM, FPRINTF_FUNC)
|
||||
|
||||
/* Call this macro to initialize only the internal variables for the
|
||||
disassembler. Architecture dependent things such as byte order, or machine
|
||||
variant are not touched by this macro. This makes things much easier for
|
||||
GDB which must initialize these things seperatly. */
|
||||
|
||||
#define INIT_DISASSEMBLE_INFO_NO_ARCH(INFO, STREAM, FPRINTF_FUNC) \
|
||||
(INFO).fprintf_func = (FPRINTF_FUNC), \
|
||||
(INFO).stream = (STREAM), \
|
||||
(INFO).symbols = NULL, \
|
||||
(INFO).num_symbols = 0, \
|
||||
(INFO).buffer = NULL, \
|
||||
(INFO).buffer_vma = 0, \
|
||||
(INFO).buffer_length = 0, \
|
||||
(INFO).read_memory_func = buffer_read_memory, \
|
||||
(INFO).memory_error_func = perror_memory, \
|
||||
(INFO).print_address_func = generic_print_address, \
|
||||
(INFO).symbol_at_address_func = generic_symbol_at_address, \
|
||||
(INFO).flags = 0, \
|
||||
(INFO).bytes_per_line = 0, \
|
||||
(INFO).bytes_per_chunk = 0, \
|
||||
(INFO).display_endian = BFD_ENDIAN_UNKNOWN, \
|
||||
(INFO).disassembler_options = NULL, \
|
||||
(INFO).insn_info_valid = 0
|
||||
|
||||
#define _(x) x
|
||||
|
||||
/* from libbfd */
|
||||
|
||||
bfd_vma bfd_getl32 (const bfd_byte *addr);
|
||||
bfd_vma bfd_getb32 (const bfd_byte *addr);
|
||||
typedef enum bfd_boolean {false, true} boolean;
|
||||
|
||||
#endif /* ! defined (DIS_ASM_H) */
|
||||
@@ -0,0 +1,298 @@
|
||||
/* General "disassemble this chunk" code. Used for debugging. */
|
||||
#include "config.h"
|
||||
#include "dis-asm.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;
|
||||
void *disas_symtab;
|
||||
const char *disas_strtab;
|
||||
|
||||
/* Get LENGTH bytes from info's buffer, at target address memaddr.
|
||||
Transfer them to myaddr. */
|
||||
int
|
||||
buffer_read_memory (memaddr, myaddr, length, info)
|
||||
bfd_vma memaddr;
|
||||
bfd_byte *myaddr;
|
||||
int length;
|
||||
struct disassemble_info *info;
|
||||
{
|
||||
if (memaddr < info->buffer_vma
|
||||
|| memaddr + length > info->buffer_vma + info->buffer_length)
|
||||
/* Out of bounds. Use EIO because GDB uses it. */
|
||||
return EIO;
|
||||
memcpy (myaddr, info->buffer + (memaddr - info->buffer_vma), length);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
/* Get LENGTH bytes from info's buffer, at target address memaddr.
|
||||
Transfer them to myaddr. */
|
||||
static int
|
||||
target_read_memory (memaddr, myaddr, length, info)
|
||||
bfd_vma memaddr;
|
||||
bfd_byte *myaddr;
|
||||
int length;
|
||||
struct disassemble_info *info;
|
||||
{
|
||||
int i;
|
||||
for(i = 0; i < length; i++) {
|
||||
myaddr[i] = ldub_code((void *)((long)memaddr + i));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Print an error message. We can assume that this is in response to
|
||||
an error return from buffer_read_memory. */
|
||||
void
|
||||
perror_memory (status, memaddr, info)
|
||||
int status;
|
||||
bfd_vma memaddr;
|
||||
struct disassemble_info *info;
|
||||
{
|
||||
if (status != EIO)
|
||||
/* Can't happen. */
|
||||
(*info->fprintf_func) (info->stream, "Unknown error %d\n", status);
|
||||
else
|
||||
/* Actually, address between memaddr and memaddr + len was
|
||||
out of bounds. */
|
||||
(*info->fprintf_func) (info->stream,
|
||||
"Address 0x%llx is out of bounds.\n", memaddr);
|
||||
}
|
||||
|
||||
/* This could be in a separate file, to save miniscule amounts of space
|
||||
in statically linked executables. */
|
||||
|
||||
/* Just print the address is hex. This is included for completeness even
|
||||
though both GDB and objdump provide their own (to print symbolic
|
||||
addresses). */
|
||||
|
||||
void
|
||||
generic_print_address (addr, info)
|
||||
bfd_vma addr;
|
||||
struct disassemble_info *info;
|
||||
{
|
||||
(*info->fprintf_func) (info->stream, "0x%llx", addr);
|
||||
}
|
||||
|
||||
/* Just return the given address. */
|
||||
|
||||
int
|
||||
generic_symbol_at_address (addr, info)
|
||||
bfd_vma addr;
|
||||
struct disassemble_info * info;
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
bfd_vma bfd_getl32 (const bfd_byte *addr)
|
||||
{
|
||||
unsigned long v;
|
||||
|
||||
v = (unsigned long) addr[0];
|
||||
v |= (unsigned long) addr[1] << 8;
|
||||
v |= (unsigned long) addr[2] << 16;
|
||||
v |= (unsigned long) addr[3] << 24;
|
||||
return (bfd_vma) v;
|
||||
}
|
||||
|
||||
bfd_vma bfd_getb32 (const bfd_byte *addr)
|
||||
{
|
||||
unsigned long v;
|
||||
|
||||
v = (unsigned long) addr[0] << 24;
|
||||
v |= (unsigned long) addr[1] << 16;
|
||||
v |= (unsigned long) addr[2] << 8;
|
||||
v |= (unsigned long) addr[3];
|
||||
return (bfd_vma) v;
|
||||
}
|
||||
|
||||
/* Disassemble this for me please... (debugging). 'flags' is only used
|
||||
for i386: non zero means 16 bit code */
|
||||
void disas(FILE *out, void *code, unsigned long size, int is_host, int flags)
|
||||
{
|
||||
uint8_t *pc;
|
||||
int count;
|
||||
struct disassemble_info disasm_info;
|
||||
int (*print_insn)(bfd_vma pc, disassemble_info *info);
|
||||
|
||||
INIT_DISASSEMBLE_INFO(disasm_info, out, fprintf);
|
||||
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
if (!is_host) {
|
||||
disasm_info.read_memory_func = target_read_memory;
|
||||
}
|
||||
#endif
|
||||
|
||||
disasm_info.buffer = code;
|
||||
disasm_info.buffer_vma = (unsigned long)code;
|
||||
disasm_info.buffer_length = size;
|
||||
|
||||
if (is_host) {
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
disasm_info.endian = BFD_ENDIAN_BIG;
|
||||
#else
|
||||
disasm_info.endian = BFD_ENDIAN_LITTLE;
|
||||
#endif
|
||||
#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__)
|
||||
print_insn = print_insn_alpha;
|
||||
#elif defined(__sparc__)
|
||||
print_insn = print_insn_sparc;
|
||||
#elif defined(__arm__)
|
||||
print_insn = print_insn_arm;
|
||||
#else
|
||||
fprintf(out, "Asm output not supported on this arch\n");
|
||||
return;
|
||||
#endif
|
||||
} else {
|
||||
#ifdef TARGET_WORDS_BIGENDIAN
|
||||
disasm_info.endian = BFD_ENDIAN_BIG;
|
||||
#else
|
||||
disasm_info.endian = BFD_ENDIAN_LITTLE;
|
||||
#endif
|
||||
#if defined(TARGET_I386)
|
||||
if (!flags)
|
||||
disasm_info.mach = bfd_mach_i386_i386;
|
||||
else
|
||||
disasm_info.mach = bfd_mach_i386_i8086;
|
||||
print_insn = print_insn_i386;
|
||||
#elif defined(TARGET_ARM)
|
||||
print_insn = print_insn_arm;
|
||||
#elif defined(TARGET_SPARC)
|
||||
print_insn = print_insn_sparc;
|
||||
#elif defined(TARGET_PPC)
|
||||
print_insn = print_insn_ppc;
|
||||
#else
|
||||
fprintf(out, "Asm output not supported on this arch\n");
|
||||
return;
|
||||
#endif
|
||||
}
|
||||
|
||||
for (pc = code; pc < (uint8_t *)code + size; pc += count) {
|
||||
fprintf(out, "0x%08lx: ", (long)pc);
|
||||
#ifdef __arm__
|
||||
/* since data are included in the code, it is better to
|
||||
display code data too */
|
||||
if (is_host) {
|
||||
fprintf(out, "%08x ", (int)bfd_getl32((const bfd_byte *)pc));
|
||||
}
|
||||
#endif
|
||||
count = print_insn((unsigned long)pc, &disasm_info);
|
||||
fprintf(out, "\n");
|
||||
if (count < 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Look up symbol for debugging purpose. Returns "" if unknown. */
|
||||
const char *lookup_symbol(void *orig_addr)
|
||||
{
|
||||
unsigned int i;
|
||||
/* Hack, because we know this is x86. */
|
||||
Elf32_Sym *sym = disas_symtab;
|
||||
|
||||
for (i = 0; i < disas_num_syms; i++) {
|
||||
if (sym[i].st_shndx == SHN_UNDEF
|
||||
|| sym[i].st_shndx >= SHN_LORESERVE)
|
||||
continue;
|
||||
|
||||
if (ELF_ST_TYPE(sym[i].st_info) != STT_FUNC)
|
||||
continue;
|
||||
|
||||
if ((long)orig_addr >= sym[i].st_value
|
||||
&& (long)orig_addr < sym[i].st_value + sym[i].st_size)
|
||||
return disas_strtab + sym[i].st_name;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
#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
|
||||
@@ -0,0 +1,15 @@
|
||||
#ifndef _QEMU_DISAS_H
|
||||
#define _QEMU_DISAS_H
|
||||
|
||||
/* Disassemble this for me please... (debugging). */
|
||||
void disas(FILE *out, void *code, unsigned long size, int is_host, int flags);
|
||||
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);
|
||||
|
||||
/* Filled in by elfload.c. Simplistic, but will do for now. */
|
||||
extern unsigned int disas_num_syms;
|
||||
extern void *disas_symtab; /* FIXME: includes are a mess --RR */
|
||||
extern const char *disas_strtab;
|
||||
#endif /* _QEMU_DISAS_H */
|
||||
+241
@@ -0,0 +1,241 @@
|
||||
/*
|
||||
* dyngen defines for micro operation code
|
||||
*
|
||||
* Copyright (c) 2003 Fabrice Bellard
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#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 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"
|
||||
#define AREG1 "ebx"
|
||||
#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"
|
||||
#define AREG7 "r19"
|
||||
#define AREG8 "r20"
|
||||
#define AREG9 "r21"
|
||||
#define AREG10 "r22"
|
||||
#define AREG11 "r23"
|
||||
#endif
|
||||
#define USE_INT_TO_FLOAT_HELPERS
|
||||
#define BUGGY_GCC_DIV64
|
||||
#endif
|
||||
#ifdef __arm__
|
||||
#define AREG0 "r7"
|
||||
#define AREG1 "r4"
|
||||
#define AREG2 "r5"
|
||||
#define AREG3 "r6"
|
||||
#endif
|
||||
#ifdef __mips__
|
||||
#define AREG0 "s3"
|
||||
#define AREG1 "s0"
|
||||
#define AREG2 "s1"
|
||||
#define AREG3 "s2"
|
||||
#endif
|
||||
#ifdef __sparc__
|
||||
#define AREG0 "g6"
|
||||
#define AREG1 "g1"
|
||||
#define AREG2 "g2"
|
||||
#define AREG3 "g3"
|
||||
#define AREG4 "l0"
|
||||
#define AREG5 "l1"
|
||||
#define AREG6 "l2"
|
||||
#define AREG7 "l3"
|
||||
#define AREG8 "l4"
|
||||
#define AREG9 "l5"
|
||||
#define AREG10 "l6"
|
||||
#define AREG11 "l7"
|
||||
#define USE_FP_CONVERT
|
||||
#endif
|
||||
#ifdef __s390__
|
||||
#define AREG0 "r10"
|
||||
#define AREG1 "r7"
|
||||
#define AREG2 "r8"
|
||||
#define AREG3 "r9"
|
||||
#endif
|
||||
#ifdef __alpha__
|
||||
/* Note $15 is the frame pointer, so anything in op-i386.c that would
|
||||
require a frame pointer, like alloca, would probably loose. */
|
||||
#define AREG0 "$15"
|
||||
#define AREG1 "$9"
|
||||
#define AREG2 "$10"
|
||||
#define AREG3 "$11"
|
||||
#define AREG4 "$12"
|
||||
#define AREG5 "$13"
|
||||
#define AREG6 "$14"
|
||||
#endif
|
||||
#ifdef __mc68000
|
||||
#define AREG0 "%a5"
|
||||
#define AREG1 "%a4"
|
||||
#define AREG2 "%d7"
|
||||
#define AREG3 "%d6"
|
||||
#define AREG4 "%d5"
|
||||
#endif
|
||||
#ifdef __ia64__
|
||||
#define AREG0 "r27"
|
||||
#define AREG1 "r24"
|
||||
#define AREG2 "r25"
|
||||
#define AREG3 "r26"
|
||||
#endif
|
||||
|
||||
/* force GCC to generate only one epilog at the end of the function */
|
||||
#define FORCE_RET() asm volatile ("");
|
||||
|
||||
#ifndef OPPROTO
|
||||
#define OPPROTO
|
||||
#endif
|
||||
|
||||
#define xglue(x, y) x ## y
|
||||
#define glue(x, y) xglue(x, y)
|
||||
#define stringify(s) tostring(s)
|
||||
#define tostring(s) #s
|
||||
|
||||
#ifdef __alpha__
|
||||
/* the symbols are considered non exported so a br immediate is generated */
|
||||
#define __hidden __attribute__((visibility("hidden")))
|
||||
#else
|
||||
#define __hidden
|
||||
#endif
|
||||
|
||||
#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
|
||||
We can then conveniently change $29 to $31 and adapt the offsets to
|
||||
emit the appropriate constant. */
|
||||
extern int __op_param1 __hidden;
|
||||
extern int __op_param2 __hidden;
|
||||
extern int __op_param3 __hidden;
|
||||
#define PARAM1 ({ int _r; asm("" : "=r"(_r) : "0" (&__op_param1)); _r; })
|
||||
#define PARAM2 ({ int _r; asm("" : "=r"(_r) : "0" (&__op_param2)); _r; })
|
||||
#define PARAM3 ({ int _r; asm("" : "=r"(_r) : "0" (&__op_param3)); _r; })
|
||||
#else
|
||||
#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 /* !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
|
||||
#ifdef __s390__
|
||||
#define EXIT_TB() asm volatile ("br %r14")
|
||||
#endif
|
||||
#ifdef __alpha__
|
||||
#define EXIT_TB() asm volatile ("ret")
|
||||
#endif
|
||||
#ifdef __ia64__
|
||||
#define EXIT_TB() asm volatile ("br.ret.sptk.many b0;;")
|
||||
#endif
|
||||
#ifdef __sparc__
|
||||
#define EXIT_TB() asm volatile ("jmpl %i0 + 8, %g0\n" \
|
||||
"nop")
|
||||
#endif
|
||||
#ifdef __arm__
|
||||
#define EXIT_TB() asm volatile ("b exec_loop")
|
||||
#endif
|
||||
#ifdef __mc68000
|
||||
#define EXIT_TB() asm volatile ("rts")
|
||||
#endif
|
||||
|
||||
#endif /* !defined(__DYNGEN_EXEC_H__) */
|
||||
@@ -0,0 +1,208 @@
|
||||
/*
|
||||
* dyngen helpers
|
||||
*
|
||||
* Copyright (c) 2003 Fabrice Bellard
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
int __op_param1, __op_param2, __op_param3;
|
||||
int __op_jmp0, __op_jmp1, __op_jmp2, __op_jmp3;
|
||||
|
||||
#ifdef __i386__
|
||||
static inline void flush_icache_range(unsigned long start, unsigned long stop)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __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)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __ia64__
|
||||
static inline void flush_icache_range(unsigned long start, unsigned long stop)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __powerpc__
|
||||
|
||||
#define MIN_CACHE_LINE_SIZE 8 /* conservative value */
|
||||
|
||||
static void inline flush_icache_range(unsigned long start, unsigned long stop)
|
||||
{
|
||||
unsigned long p;
|
||||
|
||||
p = start & ~(MIN_CACHE_LINE_SIZE - 1);
|
||||
stop = (stop + MIN_CACHE_LINE_SIZE - 1) & ~(MIN_CACHE_LINE_SIZE - 1);
|
||||
|
||||
for (p = start; p < stop; p += MIN_CACHE_LINE_SIZE) {
|
||||
asm volatile ("dcbst 0,%0" : : "r"(p) : "memory");
|
||||
}
|
||||
asm volatile ("sync" : : : "memory");
|
||||
for (p = start; p < stop; p += MIN_CACHE_LINE_SIZE) {
|
||||
asm volatile ("icbi 0,%0" : : "r"(p) : "memory");
|
||||
}
|
||||
asm volatile ("sync" : : : "memory");
|
||||
asm volatile ("isync" : : : "memory");
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __alpha__
|
||||
static inline void flush_icache_range(unsigned long start, unsigned long stop)
|
||||
{
|
||||
asm ("imb");
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __sparc__
|
||||
|
||||
static void inline flush_icache_range(unsigned long start, unsigned long stop)
|
||||
{
|
||||
unsigned long p;
|
||||
|
||||
p = start & ~(8UL - 1UL);
|
||||
stop = (stop + (8UL - 1UL)) & ~(8UL - 1UL);
|
||||
|
||||
for (; p < stop; p += 8)
|
||||
__asm__ __volatile__("flush\t%0" : : "r" (p));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __arm__
|
||||
static inline void flush_icache_range(unsigned long start, unsigned long stop)
|
||||
{
|
||||
register unsigned long _beg __asm ("a1") = start;
|
||||
register unsigned long _end __asm ("a2") = stop;
|
||||
register unsigned long _flg __asm ("a3") = 0;
|
||||
__asm __volatile__ ("swi 0x9f0002" : : "r" (_beg), "r" (_end), "r" (_flg));
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __mc68000
|
||||
#include <asm/cachectl.h>
|
||||
static inline void flush_icache_range(unsigned long start, unsigned long stop)
|
||||
{
|
||||
cacheflush(start,FLUSH_SCOPE_LINE,FLUSH_CACHE_BOTH,stop-start+16);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __alpha__
|
||||
|
||||
register int gp asm("$29");
|
||||
|
||||
static inline void immediate_ldah(void *p, int val) {
|
||||
uint32_t *dest = p;
|
||||
long high = ((val >> 16) + ((val >> 15) & 1)) & 0xffff;
|
||||
|
||||
*dest &= ~0xffff;
|
||||
*dest |= high;
|
||||
*dest |= 31 << 16;
|
||||
}
|
||||
static inline void immediate_lda(void *dest, int val) {
|
||||
*(uint16_t *) dest = val;
|
||||
}
|
||||
void fix_bsr(void *p, int offset) {
|
||||
uint32_t *dest = p;
|
||||
*dest &= ~((1 << 21) - 1);
|
||||
*dest |= (offset >> 2) & ((1 << 21) - 1);
|
||||
}
|
||||
|
||||
#endif /* __alpha__ */
|
||||
|
||||
#ifdef __arm__
|
||||
|
||||
#define MAX_OP_SIZE (128 * 4) /* in bytes */
|
||||
/* max size of the code that can be generated without calling arm_flush_ldr */
|
||||
#define MAX_FRAG_SIZE (1024 * 4)
|
||||
//#define MAX_FRAG_SIZE (135 * 4) /* for testing */
|
||||
|
||||
typedef struct LDREntry {
|
||||
uint8_t *ptr;
|
||||
uint32_t *data_ptr;
|
||||
} LDREntry;
|
||||
|
||||
static LDREntry arm_ldr_table[1024];
|
||||
static uint32_t arm_data_table[1024];
|
||||
|
||||
extern char exec_loop;
|
||||
|
||||
static inline void arm_reloc_pc24(uint32_t *ptr, uint32_t insn, int val)
|
||||
{
|
||||
*ptr = (insn & ~0xffffff) | ((insn + ((val - (int)ptr) >> 2)) & 0xffffff);
|
||||
}
|
||||
|
||||
static uint8_t *arm_flush_ldr(uint8_t *gen_code_ptr,
|
||||
LDREntry *ldr_start, LDREntry *ldr_end,
|
||||
uint32_t *data_start, uint32_t *data_end,
|
||||
int gen_jmp)
|
||||
{
|
||||
LDREntry *le;
|
||||
uint32_t *ptr;
|
||||
int offset, data_size, target;
|
||||
uint8_t *data_ptr;
|
||||
uint32_t insn;
|
||||
|
||||
data_size = (uint8_t *)data_end - (uint8_t *)data_start;
|
||||
|
||||
if (gen_jmp) {
|
||||
/* generate branch to skip the data */
|
||||
if (data_size == 0)
|
||||
return gen_code_ptr;
|
||||
target = (long)gen_code_ptr + data_size + 4;
|
||||
arm_reloc_pc24((uint32_t *)gen_code_ptr, 0xeafffffe, target);
|
||||
gen_code_ptr += 4;
|
||||
}
|
||||
|
||||
/* copy the data */
|
||||
data_ptr = gen_code_ptr;
|
||||
memcpy(gen_code_ptr, data_start, data_size);
|
||||
gen_code_ptr += data_size;
|
||||
|
||||
/* patch the ldr to point to the data */
|
||||
for(le = ldr_start; le < ldr_end; le++) {
|
||||
ptr = (uint32_t *)le->ptr;
|
||||
offset = ((unsigned long)(le->data_ptr) - (unsigned long)data_start) +
|
||||
(unsigned long)data_ptr -
|
||||
(unsigned long)ptr - 8;
|
||||
insn = *ptr & ~(0xfff | 0x00800000);
|
||||
if (offset < 0) {
|
||||
offset = - offset;
|
||||
} else {
|
||||
insn |= 0x00800000;
|
||||
}
|
||||
if (offset > 0xfff) {
|
||||
fprintf(stderr, "Error ldr offset\n");
|
||||
abort();
|
||||
}
|
||||
insn |= offset;
|
||||
*ptr = insn;
|
||||
}
|
||||
return gen_code_ptr;
|
||||
}
|
||||
|
||||
#endif /* __arm__ */
|
||||
|
||||
|
||||
|
||||
+599
@@ -0,0 +1,599 @@
|
||||
/*
|
||||
* internal execution defines for qemu
|
||||
*
|
||||
* Copyright (c) 2003 Fabrice Bellard
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/* allow to see translation results - the slowdown should be negligible, so we leave it */
|
||||
#define DEBUG_DISAS
|
||||
|
||||
#ifndef glue
|
||||
#define xglue(x, y) x ## y
|
||||
#define glue(x, y) xglue(x, y)
|
||||
#define stringify(s) tostring(s)
|
||||
#define tostring(s) #s
|
||||
#endif
|
||||
|
||||
#if GCC_MAJOR < 3
|
||||
#define __builtin_expect(x, n) (x)
|
||||
#endif
|
||||
|
||||
#ifdef __i386__
|
||||
#define REGPARM(n) __attribute((regparm(n)))
|
||||
#else
|
||||
#define REGPARM(n)
|
||||
#endif
|
||||
|
||||
/* is_jmp field values */
|
||||
#define DISAS_NEXT 0 /* next instruction can be analyzed */
|
||||
#define DISAS_JUMP 1 /* only pc was modified dynamically */
|
||||
#define DISAS_UPDATE 2 /* cpu state was modified dynamically */
|
||||
#define DISAS_TB_JUMP 3 /* only pc was modified statically */
|
||||
|
||||
struct TranslationBlock;
|
||||
|
||||
/* XXX: make safe guess about sizes */
|
||||
#define MAX_OP_PER_INSTR 32
|
||||
#define OPC_BUF_SIZE 512
|
||||
#define OPC_MAX_SIZE (OPC_BUF_SIZE - MAX_OP_PER_INSTR)
|
||||
|
||||
#define OPPARAM_BUF_SIZE (OPC_BUF_SIZE * 3)
|
||||
|
||||
extern uint16_t gen_opc_buf[OPC_BUF_SIZE];
|
||||
extern uint32_t gen_opparam_buf[OPPARAM_BUF_SIZE];
|
||||
extern uint32_t gen_opc_pc[OPC_BUF_SIZE];
|
||||
extern 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);
|
||||
|
||||
#endif
|
||||
|
||||
extern FILE *logfile;
|
||||
extern int loglevel;
|
||||
|
||||
int gen_intermediate_code(CPUState *env, struct TranslationBlock *tb);
|
||||
int gen_intermediate_code_pc(CPUState *env, struct TranslationBlock *tb);
|
||||
void dump_ops(const uint16_t *opc_buf, const uint32_t *opparam_buf);
|
||||
int cpu_gen_code(CPUState *env, struct TranslationBlock *tb,
|
||||
int max_code_size, int *gen_code_size_ptr);
|
||||
int cpu_restore_state(struct TranslationBlock *tb,
|
||||
CPUState *env, unsigned long searched_pc,
|
||||
void *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, 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 */
|
||||
|
||||
#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 */
|
||||
|
||||
/* 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)
|
||||
|
||||
/* 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 {
|
||||
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 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 */
|
||||
#ifdef USE_DIRECT_JUMP
|
||||
uint16_t tb_jmp_offset[4]; /* offset of jump instruction */
|
||||
#else
|
||||
uint32_t tb_next[2]; /* address of jump generated code */
|
||||
#endif
|
||||
/* list of TBs jumping to this one. This is a circular list using
|
||||
the two least significant bits of the pointers to tell what is
|
||||
the next pointer: 0 = jmp_next[0], 1 = jmp_next[1], 2 =
|
||||
jmp_first */
|
||||
struct TranslationBlock *jmp_next[2];
|
||||
struct TranslationBlock *jmp_first;
|
||||
} TranslationBlock;
|
||||
|
||||
static inline unsigned int tb_hash_func(unsigned long pc)
|
||||
{
|
||||
return pc & (CODE_GEN_HASH_SIZE - 1);
|
||||
}
|
||||
|
||||
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(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;
|
||||
|
||||
/* 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,
|
||||
target_ulong pc,
|
||||
target_ulong cs_base,
|
||||
unsigned int flags)
|
||||
{
|
||||
TranslationBlock **ptb, *tb;
|
||||
unsigned int h;
|
||||
|
||||
h = tb_hash_func(pc);
|
||||
ptb = &tb_hash[h];
|
||||
for(;;) {
|
||||
tb = *ptb;
|
||||
if (!tb)
|
||||
break;
|
||||
if (tb->pc == pc && tb->cs_base == cs_base && tb->flags == flags)
|
||||
return tb;
|
||||
ptb = &tb->hash_next;
|
||||
}
|
||||
*pptb = ptb;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
#if defined(USE_DIRECT_JUMP)
|
||||
|
||||
#if defined(__powerpc__)
|
||||
static inline void tb_set_jmp_target1(unsigned long jmp_addr, unsigned long addr)
|
||||
{
|
||||
uint32_t val, *ptr;
|
||||
|
||||
/* patch the branch destination */
|
||||
ptr = (uint32_t *)jmp_addr;
|
||||
val = *ptr;
|
||||
val = (val & ~0x03fffffc) | ((addr - jmp_addr) & 0x03fffffc);
|
||||
*ptr = val;
|
||||
/* flush icache */
|
||||
asm volatile ("dcbst 0,%0" : : "r"(ptr) : "memory");
|
||||
asm volatile ("sync" : : : "memory");
|
||||
asm volatile ("icbi 0,%0" : : "r"(ptr) : "memory");
|
||||
asm volatile ("sync" : : : "memory");
|
||||
asm volatile ("isync" : : : "memory");
|
||||
}
|
||||
#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)
|
||||
{
|
||||
unsigned long offset;
|
||||
|
||||
offset = tb->tb_jmp_offset[n];
|
||||
tb_set_jmp_target1((unsigned long)(tb->tc_ptr + offset), addr);
|
||||
offset = tb->tb_jmp_offset[n + 2];
|
||||
if (offset != 0xffff)
|
||||
tb_set_jmp_target1((unsigned long)(tb->tc_ptr + offset), addr);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
/* set the jump target */
|
||||
static inline void tb_set_jmp_target(TranslationBlock *tb,
|
||||
int n, unsigned long addr)
|
||||
{
|
||||
tb->tb_next[n] = addr;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static inline void tb_add_jump(TranslationBlock *tb, int n,
|
||||
TranslationBlock *tb_next)
|
||||
{
|
||||
/* NOTE: this test is only needed for thread safety */
|
||||
if (!tb->jmp_next[n]) {
|
||||
/* patch the native jump address */
|
||||
tb_set_jmp_target(tb, n, (unsigned long)tb_next->tc_ptr);
|
||||
|
||||
/* add in TB jmp circular list */
|
||||
tb->jmp_next[n] = tb_next->jmp_first;
|
||||
tb_next->jmp_first = (TranslationBlock *)((long)(tb) | (n));
|
||||
}
|
||||
}
|
||||
|
||||
TranslationBlock *tb_find_pc(unsigned long pc_ptr);
|
||||
|
||||
#ifndef offsetof
|
||||
#define offsetof(type, field) ((size_t) &((type *)0)->field)
|
||||
#endif
|
||||
|
||||
#if defined(_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__)
|
||||
|
||||
/* we patch the jump instruction directly */
|
||||
#define JUMP_TB(opname, tbparam, n, eip)\
|
||||
do {\
|
||||
asm volatile (ASM_DATA_SECTION\
|
||||
ASM_NAME(__op_label) #n "." ASM_NAME(opname) ":\n"\
|
||||
".long 1f\n"\
|
||||
ASM_PREVIOUS_SECTION \
|
||||
"b " 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 ("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
|
||||
|
||||
/* jump to next block operations (more portable code, does not need
|
||||
cache flushing, but slower because of indirect jump) */
|
||||
#define JUMP_TB(opname, tbparam, n, eip)\
|
||||
do {\
|
||||
static void __attribute__((unused)) *__op_label ## n = &&label ## n;\
|
||||
static void __attribute__((unused)) *dummy ## n = &&dummy_label ## n;\
|
||||
goto *(void *)(((TranslationBlock *)tbparam)->tb_next[n]);\
|
||||
label ## n:\
|
||||
T0 = (long)(tbparam) + (n);\
|
||||
EIP = eip;\
|
||||
dummy_label ## n:\
|
||||
EXIT_TB();\
|
||||
} while (0)
|
||||
|
||||
/* second jump to same destination 'n' */
|
||||
#define JUMP_TB2(opname, tbparam, n)\
|
||||
do {\
|
||||
goto *(void *)(((TranslationBlock *)tbparam)->tb_next[n - 2]);\
|
||||
} while (0)
|
||||
|
||||
#endif
|
||||
|
||||
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\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)
|
||||
: "cr0", "memory");
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __i386__
|
||||
static inline int testandset (int *p)
|
||||
{
|
||||
char ret;
|
||||
long int readval;
|
||||
|
||||
__asm__ __volatile__ ("lock; cmpxchgl %3, %1; sete %0"
|
||||
: "=q" (ret), "=m" (*p), "=a" (readval)
|
||||
: "r" (1), "m" (*p), "a" (0)
|
||||
: "memory");
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __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)
|
||||
{
|
||||
int ret;
|
||||
|
||||
__asm__ __volatile__ ("0: cs %0,%1,0(%2)\n"
|
||||
" jl 0b"
|
||||
: "=&d" (ret)
|
||||
: "r" (1), "a" (p), "0" (*p)
|
||||
: "cc", "memory" );
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __alpha__
|
||||
static inline int testandset (int *p)
|
||||
{
|
||||
int ret;
|
||||
unsigned long one;
|
||||
|
||||
__asm__ __volatile__ ("0: mov 1,%2\n"
|
||||
" ldl_l %0,%1\n"
|
||||
" stl_c %2,%1\n"
|
||||
" beq %2,1f\n"
|
||||
".subsection 2\n"
|
||||
"1: br 0b\n"
|
||||
".previous"
|
||||
: "=r" (ret), "=m" (*p), "=r" (one)
|
||||
: "m" (*p));
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __sparc__
|
||||
static inline int testandset (int *p)
|
||||
{
|
||||
int ret;
|
||||
|
||||
__asm__ __volatile__("ldstub [%1], %0"
|
||||
: "=r" (ret)
|
||||
: "r" (p)
|
||||
: "memory");
|
||||
|
||||
return (ret ? 1 : 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __arm__
|
||||
static inline int testandset (int *spinlock)
|
||||
{
|
||||
register unsigned int ret;
|
||||
__asm__ __volatile__("swp %0, %1, [%2]"
|
||||
: "=r"(ret)
|
||||
: "0"(1), "r"(spinlock));
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __mc68000
|
||||
static inline int testandset (int *p)
|
||||
{
|
||||
char ret;
|
||||
__asm__ __volatile__("tas %1; sne %0"
|
||||
: "=r" (ret)
|
||||
: "m" (p)
|
||||
: "cc","memory");
|
||||
return ret == 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
typedef int spinlock_t;
|
||||
|
||||
#define SPIN_LOCK_UNLOCKED 0
|
||||
|
||||
#if defined(CONFIG_USER_ONLY)
|
||||
static inline void spin_lock(spinlock_t *lock)
|
||||
{
|
||||
while (testandset(lock));
|
||||
}
|
||||
|
||||
static inline void spin_unlock(spinlock_t *lock)
|
||||
{
|
||||
*lock = 0;
|
||||
}
|
||||
|
||||
static inline int spin_trylock(spinlock_t *lock)
|
||||
{
|
||||
return !testandset(lock);
|
||||
}
|
||||
#else
|
||||
static inline void spin_lock(spinlock_t *lock)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void spin_unlock(spinlock_t *lock)
|
||||
{
|
||||
}
|
||||
|
||||
static inline int spin_trylock(spinlock_t *lock)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
extern spinlock_t tb_lock;
|
||||
|
||||
extern int tb_invalidated_flag;
|
||||
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
|
||||
void tlb_fill(unsigned long addr, int is_write, int is_user,
|
||||
void *retaddr);
|
||||
|
||||
#define ACCESS_TYPE 3
|
||||
#define MEMSUFFIX _code
|
||||
#define env cpu_single_env
|
||||
|
||||
#define DATA_SIZE 1
|
||||
#include "softmmu_header.h"
|
||||
|
||||
#define DATA_SIZE 2
|
||||
#include "softmmu_header.h"
|
||||
|
||||
#define DATA_SIZE 4
|
||||
#include "softmmu_header.h"
|
||||
|
||||
#undef ACCESS_TYPE
|
||||
#undef MEMSUFFIX
|
||||
#undef env
|
||||
|
||||
#endif
|
||||
|
||||
#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
|
||||
@@ -0,0 +1,658 @@
|
||||
/*
|
||||
* gdb server stub
|
||||
*
|
||||
* Copyright (c) 2003 Fabrice Bellard
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#include "vl.h"
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <signal.h>
|
||||
|
||||
//#define DEBUG_GDB
|
||||
|
||||
enum RSState {
|
||||
RS_IDLE,
|
||||
RS_GETLINE,
|
||||
RS_CHKSUM1,
|
||||
RS_CHKSUM2,
|
||||
};
|
||||
|
||||
static int gdbserver_fd;
|
||||
|
||||
typedef struct GDBState {
|
||||
enum RSState state;
|
||||
int fd;
|
||||
char line_buf[4096];
|
||||
int line_buf_index;
|
||||
int line_csum;
|
||||
} GDBState;
|
||||
|
||||
static int get_char(GDBState *s)
|
||||
{
|
||||
uint8_t ch;
|
||||
int ret;
|
||||
|
||||
for(;;) {
|
||||
ret = read(s->fd, &ch, 1);
|
||||
if (ret < 0) {
|
||||
if (errno != EINTR && errno != EAGAIN)
|
||||
return -1;
|
||||
} else if (ret == 0) {
|
||||
return -1;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return ch;
|
||||
}
|
||||
|
||||
static void put_buffer(GDBState *s, const uint8_t *buf, int len)
|
||||
{
|
||||
int ret;
|
||||
|
||||
while (len > 0) {
|
||||
ret = write(s->fd, buf, len);
|
||||
if (ret < 0) {
|
||||
if (errno != EINTR && errno != EAGAIN)
|
||||
return;
|
||||
} else {
|
||||
buf += ret;
|
||||
len -= ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline int fromhex(int v)
|
||||
{
|
||||
if (v >= '0' && v <= '9')
|
||||
return v - '0';
|
||||
else if (v >= 'A' && v <= 'F')
|
||||
return v - 'A' + 10;
|
||||
else if (v >= 'a' && v <= 'f')
|
||||
return v - 'a' + 10;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int tohex(int v)
|
||||
{
|
||||
if (v < 10)
|
||||
return v + '0';
|
||||
else
|
||||
return v - 10 + 'a';
|
||||
}
|
||||
|
||||
static void memtohex(char *buf, const uint8_t *mem, int len)
|
||||
{
|
||||
int i, c;
|
||||
char *q;
|
||||
q = buf;
|
||||
for(i = 0; i < len; i++) {
|
||||
c = mem[i];
|
||||
*q++ = tohex(c >> 4);
|
||||
*q++ = tohex(c & 0xf);
|
||||
}
|
||||
*q = '\0';
|
||||
}
|
||||
|
||||
static void hextomem(uint8_t *mem, const char *buf, int len)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i = 0; i < len; i++) {
|
||||
mem[i] = (fromhex(buf[0]) << 4) | fromhex(buf[1]);
|
||||
buf += 2;
|
||||
}
|
||||
}
|
||||
|
||||
/* return -1 if error, 0 if OK */
|
||||
static int put_packet(GDBState *s, char *buf)
|
||||
{
|
||||
char buf1[3];
|
||||
int len, csum, ch, i;
|
||||
|
||||
#ifdef DEBUG_GDB
|
||||
printf("reply='%s'\n", buf);
|
||||
#endif
|
||||
|
||||
for(;;) {
|
||||
buf1[0] = '$';
|
||||
put_buffer(s, buf1, 1);
|
||||
len = strlen(buf);
|
||||
put_buffer(s, buf, len);
|
||||
csum = 0;
|
||||
for(i = 0; i < len; i++) {
|
||||
csum += buf[i];
|
||||
}
|
||||
buf1[0] = '#';
|
||||
buf1[1] = tohex((csum >> 4) & 0xf);
|
||||
buf1[2] = tohex((csum) & 0xf);
|
||||
|
||||
put_buffer(s, buf1, 3);
|
||||
|
||||
ch = get_char(s);
|
||||
if (ch < 0)
|
||||
return -1;
|
||||
if (ch == '+')
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(TARGET_I386)
|
||||
|
||||
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];
|
||||
}
|
||||
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(®isters[i]);
|
||||
for(i = 36; i < 44; i++)
|
||||
tswapls(®isters[i]);
|
||||
return 44 * 4;
|
||||
}
|
||||
|
||||
static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size)
|
||||
{
|
||||
uint32_t *registers = (uint32_t *)mem_buf;
|
||||
int i;
|
||||
|
||||
for(i = 0; i < 8; i++) {
|
||||
env->regs[i] = tswapl(registers[i]);
|
||||
}
|
||||
env->eip = 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]));
|
||||
LOAD_SEG(10, R_CS);
|
||||
LOAD_SEG(11, R_SS);
|
||||
LOAD_SEG(12, R_DS);
|
||||
LOAD_SEG(13, R_ES);
|
||||
LOAD_SEG(14, R_FS);
|
||||
LOAD_SEG(15, R_GS);
|
||||
#endif
|
||||
}
|
||||
|
||||
#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 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 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 RS_GETLINE:
|
||||
if (ch == '#') {
|
||||
s->state = RS_CHKSUM1;
|
||||
} else if (s->line_buf_index >= sizeof(s->line_buf) - 1) {
|
||||
s->state = RS_IDLE;
|
||||
} else {
|
||||
s->line_buf[s->line_buf_index++] = ch;
|
||||
}
|
||||
break;
|
||||
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;
|
||||
}
|
||||
@@ -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
@@ -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
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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]);
|
||||
}
|
||||
+1390
File diff suppressed because it is too large
Load Diff
+174
@@ -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
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
+218
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
File diff suppressed because it is too large
Load Diff
@@ -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, §ors);
|
||||
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, §ors);
|
||||
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();
|
||||
}
|
||||
}
|
||||
+706
@@ -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);
|
||||
}
|
||||
@@ -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
@@ -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
@@ -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);
|
||||
}
|
||||
+268
@@ -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
@@ -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
@@ -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);
|
||||
}
|
||||
@@ -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
@@ -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);
|
||||
}
|
||||
+168
@@ -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];
|
||||
@@ -0,0 +1,519 @@
|
||||
/*
|
||||
* QEMU VGA Emulator templates
|
||||
*
|
||||
* Copyright (c) 2003 Fabrice Bellard
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#if DEPTH == 8
|
||||
#define BPP 1
|
||||
#define PIXEL_TYPE uint8_t
|
||||
#elif DEPTH == 15 || DEPTH == 16
|
||||
#define BPP 2
|
||||
#define PIXEL_TYPE uint16_t
|
||||
#elif DEPTH == 32
|
||||
#define BPP 4
|
||||
#define PIXEL_TYPE uint32_t
|
||||
#else
|
||||
#error unsupport depth
|
||||
#endif
|
||||
|
||||
#if DEPTH != 15
|
||||
|
||||
static inline void glue(vga_draw_glyph_line_, DEPTH)(uint8_t *d,
|
||||
uint32_t font_data,
|
||||
uint32_t xorcol,
|
||||
uint32_t bgcol)
|
||||
{
|
||||
#if BPP == 1
|
||||
((uint32_t *)d)[0] = (dmask16[(font_data >> 4)] & xorcol) ^ bgcol;
|
||||
((uint32_t *)d)[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;
|
||||
((uint32_t *)d)[2] = (dmask4[(font_data >> 2) & 3] & xorcol) ^ bgcol;
|
||||
((uint32_t *)d)[3] = (dmask4[(font_data >> 0) & 3] & xorcol) ^ bgcol;
|
||||
#else
|
||||
((uint32_t *)d)[0] = (-((font_data >> 7)) & xorcol) ^ bgcol;
|
||||
((uint32_t *)d)[1] = (-((font_data >> 6) & 1) & xorcol) ^ bgcol;
|
||||
((uint32_t *)d)[2] = (-((font_data >> 5) & 1) & xorcol) ^ bgcol;
|
||||
((uint32_t *)d)[3] = (-((font_data >> 4) & 1) & xorcol) ^ bgcol;
|
||||
((uint32_t *)d)[4] = (-((font_data >> 3) & 1) & xorcol) ^ bgcol;
|
||||
((uint32_t *)d)[5] = (-((font_data >> 2) & 1) & xorcol) ^ bgcol;
|
||||
((uint32_t *)d)[6] = (-((font_data >> 1) & 1) & xorcol) ^ bgcol;
|
||||
((uint32_t *)d)[7] = (-((font_data >> 0) & 1) & xorcol) ^ bgcol;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void glue(vga_draw_glyph8_, DEPTH)(uint8_t *d, int linesize,
|
||||
const uint8_t *font_ptr, int h,
|
||||
uint32_t fgcol, uint32_t bgcol)
|
||||
{
|
||||
uint32_t font_data, xorcol;
|
||||
|
||||
xorcol = bgcol ^ fgcol;
|
||||
do {
|
||||
font_data = font_ptr[0];
|
||||
glue(vga_draw_glyph_line_, DEPTH)(d, font_data, xorcol, bgcol);
|
||||
font_ptr += 4;
|
||||
d += linesize;
|
||||
} while (--h);
|
||||
}
|
||||
|
||||
static void glue(vga_draw_glyph16_, DEPTH)(uint8_t *d, int linesize,
|
||||
const uint8_t *font_ptr, int h,
|
||||
uint32_t fgcol, uint32_t bgcol)
|
||||
{
|
||||
uint32_t font_data, xorcol;
|
||||
|
||||
xorcol = bgcol ^ fgcol;
|
||||
do {
|
||||
font_data = font_ptr[0];
|
||||
glue(vga_draw_glyph_line_, DEPTH)(d,
|
||||
expand4to8[font_data >> 4],
|
||||
xorcol, bgcol);
|
||||
glue(vga_draw_glyph_line_, DEPTH)(d + 8 * BPP,
|
||||
expand4to8[font_data & 0x0f],
|
||||
xorcol, bgcol);
|
||||
font_ptr += 4;
|
||||
d += linesize;
|
||||
} while (--h);
|
||||
}
|
||||
|
||||
static void glue(vga_draw_glyph9_, DEPTH)(uint8_t *d, int linesize,
|
||||
const uint8_t *font_ptr, int h,
|
||||
uint32_t fgcol, uint32_t bgcol, int dup9)
|
||||
{
|
||||
uint32_t font_data, xorcol, v;
|
||||
|
||||
xorcol = bgcol ^ fgcol;
|
||||
do {
|
||||
font_data = font_ptr[0];
|
||||
#if BPP == 1
|
||||
cpu_to_32wu((uint32_t *)d, (dmask16[(font_data >> 4)] & xorcol) ^ bgcol);
|
||||
v = (dmask16[(font_data >> 0) & 0xf] & xorcol) ^ bgcol;
|
||||
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
|
||||
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;
|
||||
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)[7] = v;
|
||||
if (dup9)
|
||||
((uint32_t *)d)[8] = v;
|
||||
else
|
||||
((uint32_t *)d)[8] = bgcol;
|
||||
#endif
|
||||
font_ptr += 4;
|
||||
d += linesize;
|
||||
} while (--h);
|
||||
}
|
||||
|
||||
/*
|
||||
* 4 color mode
|
||||
*/
|
||||
static void glue(vga_draw_line2_, DEPTH)(VGAState *s1, uint8_t *d,
|
||||
const uint8_t *s, int width)
|
||||
{
|
||||
uint32_t plane_mask, *palette, data, v;
|
||||
int x;
|
||||
|
||||
palette = s1->last_palette;
|
||||
plane_mask = mask16[s1->ar[0x12] & 0xf];
|
||||
width >>= 3;
|
||||
for(x = 0; x < width; x++) {
|
||||
data = ((uint32_t *)s)[0];
|
||||
data &= plane_mask;
|
||||
v = expand2[GET_PLANE(data, 0)];
|
||||
v |= expand2[GET_PLANE(data, 2)] << 2;
|
||||
((PIXEL_TYPE *)d)[0] = palette[v >> 12];
|
||||
((PIXEL_TYPE *)d)[1] = palette[(v >> 8) & 0xf];
|
||||
((PIXEL_TYPE *)d)[2] = palette[(v >> 4) & 0xf];
|
||||
((PIXEL_TYPE *)d)[3] = palette[(v >> 0) & 0xf];
|
||||
|
||||
v = expand2[GET_PLANE(data, 1)];
|
||||
v |= expand2[GET_PLANE(data, 3)] << 2;
|
||||
((PIXEL_TYPE *)d)[4] = palette[v >> 12];
|
||||
((PIXEL_TYPE *)d)[5] = palette[(v >> 8) & 0xf];
|
||||
((PIXEL_TYPE *)d)[6] = palette[(v >> 4) & 0xf];
|
||||
((PIXEL_TYPE *)d)[7] = palette[(v >> 0) & 0xf];
|
||||
d += BPP * 8;
|
||||
s += 4;
|
||||
}
|
||||
}
|
||||
|
||||
#if BPP == 1
|
||||
#define PUT_PIXEL2(d, n, v) ((uint16_t *)d)[(n)] = (v)
|
||||
#elif BPP == 2
|
||||
#define PUT_PIXEL2(d, n, v) ((uint32_t *)d)[(n)] = (v)
|
||||
#else
|
||||
#define PUT_PIXEL2(d, n, v) \
|
||||
((uint32_t *)d)[2*(n)] = ((uint32_t *)d)[2*(n)+1] = (v)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* 4 color mode, dup2 horizontal
|
||||
*/
|
||||
static void glue(vga_draw_line2d2_, DEPTH)(VGAState *s1, uint8_t *d,
|
||||
const uint8_t *s, int width)
|
||||
{
|
||||
uint32_t plane_mask, *palette, data, v;
|
||||
int x;
|
||||
|
||||
palette = s1->last_palette;
|
||||
plane_mask = mask16[s1->ar[0x12] & 0xf];
|
||||
width >>= 3;
|
||||
for(x = 0; x < width; x++) {
|
||||
data = ((uint32_t *)s)[0];
|
||||
data &= plane_mask;
|
||||
v = expand2[GET_PLANE(data, 0)];
|
||||
v |= expand2[GET_PLANE(data, 2)] << 2;
|
||||
PUT_PIXEL2(d, 0, palette[v >> 12]);
|
||||
PUT_PIXEL2(d, 1, palette[(v >> 8) & 0xf]);
|
||||
PUT_PIXEL2(d, 2, palette[(v >> 4) & 0xf]);
|
||||
PUT_PIXEL2(d, 3, palette[(v >> 0) & 0xf]);
|
||||
|
||||
v = expand2[GET_PLANE(data, 1)];
|
||||
v |= expand2[GET_PLANE(data, 3)] << 2;
|
||||
PUT_PIXEL2(d, 4, palette[v >> 12]);
|
||||
PUT_PIXEL2(d, 5, palette[(v >> 8) & 0xf]);
|
||||
PUT_PIXEL2(d, 6, palette[(v >> 4) & 0xf]);
|
||||
PUT_PIXEL2(d, 7, palette[(v >> 0) & 0xf]);
|
||||
d += BPP * 16;
|
||||
s += 4;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 16 color mode
|
||||
*/
|
||||
static void glue(vga_draw_line4_, DEPTH)(VGAState *s1, uint8_t *d,
|
||||
const uint8_t *s, int width)
|
||||
{
|
||||
uint32_t plane_mask, data, v, *palette;
|
||||
int x;
|
||||
|
||||
palette = s1->last_palette;
|
||||
plane_mask = mask16[s1->ar[0x12] & 0xf];
|
||||
width >>= 3;
|
||||
for(x = 0; x < width; x++) {
|
||||
data = ((uint32_t *)s)[0];
|
||||
data &= plane_mask;
|
||||
v = expand4[GET_PLANE(data, 0)];
|
||||
v |= expand4[GET_PLANE(data, 1)] << 1;
|
||||
v |= expand4[GET_PLANE(data, 2)] << 2;
|
||||
v |= expand4[GET_PLANE(data, 3)] << 3;
|
||||
((PIXEL_TYPE *)d)[0] = palette[v >> 28];
|
||||
((PIXEL_TYPE *)d)[1] = palette[(v >> 24) & 0xf];
|
||||
((PIXEL_TYPE *)d)[2] = palette[(v >> 20) & 0xf];
|
||||
((PIXEL_TYPE *)d)[3] = palette[(v >> 16) & 0xf];
|
||||
((PIXEL_TYPE *)d)[4] = palette[(v >> 12) & 0xf];
|
||||
((PIXEL_TYPE *)d)[5] = palette[(v >> 8) & 0xf];
|
||||
((PIXEL_TYPE *)d)[6] = palette[(v >> 4) & 0xf];
|
||||
((PIXEL_TYPE *)d)[7] = palette[(v >> 0) & 0xf];
|
||||
d += BPP * 8;
|
||||
s += 4;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 16 color mode, dup2 horizontal
|
||||
*/
|
||||
static void glue(vga_draw_line4d2_, DEPTH)(VGAState *s1, uint8_t *d,
|
||||
const uint8_t *s, int width)
|
||||
{
|
||||
uint32_t plane_mask, data, v, *palette;
|
||||
int x;
|
||||
|
||||
palette = s1->last_palette;
|
||||
plane_mask = mask16[s1->ar[0x12] & 0xf];
|
||||
width >>= 3;
|
||||
for(x = 0; x < width; x++) {
|
||||
data = ((uint32_t *)s)[0];
|
||||
data &= plane_mask;
|
||||
v = expand4[GET_PLANE(data, 0)];
|
||||
v |= expand4[GET_PLANE(data, 1)] << 1;
|
||||
v |= expand4[GET_PLANE(data, 2)] << 2;
|
||||
v |= expand4[GET_PLANE(data, 3)] << 3;
|
||||
PUT_PIXEL2(d, 0, palette[v >> 28]);
|
||||
PUT_PIXEL2(d, 1, palette[(v >> 24) & 0xf]);
|
||||
PUT_PIXEL2(d, 2, palette[(v >> 20) & 0xf]);
|
||||
PUT_PIXEL2(d, 3, palette[(v >> 16) & 0xf]);
|
||||
PUT_PIXEL2(d, 4, palette[(v >> 12) & 0xf]);
|
||||
PUT_PIXEL2(d, 5, palette[(v >> 8) & 0xf]);
|
||||
PUT_PIXEL2(d, 6, palette[(v >> 4) & 0xf]);
|
||||
PUT_PIXEL2(d, 7, palette[(v >> 0) & 0xf]);
|
||||
d += BPP * 16;
|
||||
s += 4;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 256 color mode, double pixels
|
||||
*
|
||||
* XXX: add plane_mask support (never used in standard VGA modes)
|
||||
*/
|
||||
static void glue(vga_draw_line8d2_, DEPTH)(VGAState *s1, uint8_t *d,
|
||||
const uint8_t *s, int width)
|
||||
{
|
||||
uint32_t *palette;
|
||||
int x;
|
||||
|
||||
palette = s1->last_palette;
|
||||
width >>= 3;
|
||||
for(x = 0; x < width; x++) {
|
||||
PUT_PIXEL2(d, 0, palette[s[0]]);
|
||||
PUT_PIXEL2(d, 1, palette[s[1]]);
|
||||
PUT_PIXEL2(d, 2, palette[s[2]]);
|
||||
PUT_PIXEL2(d, 3, palette[s[3]]);
|
||||
d += BPP * 8;
|
||||
s += 4;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* standard 256 color mode
|
||||
*
|
||||
* XXX: add plane_mask support (never used in standard VGA modes)
|
||||
*/
|
||||
static void glue(vga_draw_line8_, DEPTH)(VGAState *s1, uint8_t *d,
|
||||
const uint8_t *s, int width)
|
||||
{
|
||||
uint32_t *palette;
|
||||
int x;
|
||||
|
||||
palette = s1->last_palette;
|
||||
width >>= 3;
|
||||
for(x = 0; x < width; x++) {
|
||||
((PIXEL_TYPE *)d)[0] = palette[s[0]];
|
||||
((PIXEL_TYPE *)d)[1] = palette[s[1]];
|
||||
((PIXEL_TYPE *)d)[2] = palette[s[2]];
|
||||
((PIXEL_TYPE *)d)[3] = palette[s[3]];
|
||||
((PIXEL_TYPE *)d)[4] = palette[s[4]];
|
||||
((PIXEL_TYPE *)d)[5] = palette[s[5]];
|
||||
((PIXEL_TYPE *)d)[6] = palette[s[6]];
|
||||
((PIXEL_TYPE *)d)[7] = palette[s[7]];
|
||||
d += BPP * 8;
|
||||
s += 8;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* DEPTH != 15 */
|
||||
|
||||
|
||||
/* XXX: optimize */
|
||||
|
||||
/*
|
||||
* 15 bit color
|
||||
*/
|
||||
static void glue(vga_draw_line15_, DEPTH)(VGAState *s1, uint8_t *d,
|
||||
const uint8_t *s, int width)
|
||||
{
|
||||
#if DEPTH == 15 && defined(WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN)
|
||||
memcpy(d, s, width * 2);
|
||||
#else
|
||||
int w;
|
||||
uint32_t v, r, g, b;
|
||||
|
||||
w = width;
|
||||
do {
|
||||
v = lduw_raw((void *)s);
|
||||
r = (v >> 7) & 0xf8;
|
||||
g = (v >> 2) & 0xf8;
|
||||
b = (v << 3) & 0xf8;
|
||||
((PIXEL_TYPE *)d)[0] = glue(rgb_to_pixel, DEPTH)(r, g, b);
|
||||
s += 2;
|
||||
d += BPP;
|
||||
} while (--w != 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* 16 bit color
|
||||
*/
|
||||
static void glue(vga_draw_line16_, DEPTH)(VGAState *s1, uint8_t *d,
|
||||
const uint8_t *s, int width)
|
||||
{
|
||||
#if DEPTH == 16 && defined(WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN)
|
||||
memcpy(d, s, width * 2);
|
||||
#else
|
||||
int w;
|
||||
uint32_t v, r, g, b;
|
||||
|
||||
w = width;
|
||||
do {
|
||||
v = lduw_raw((void *)s);
|
||||
r = (v >> 8) & 0xf8;
|
||||
g = (v >> 3) & 0xfc;
|
||||
b = (v << 3) & 0xf8;
|
||||
((PIXEL_TYPE *)d)[0] = glue(rgb_to_pixel, DEPTH)(r, g, b);
|
||||
s += 2;
|
||||
d += BPP;
|
||||
} while (--w != 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* 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) == defined(TARGET_WORDS_BIGENDIAN)
|
||||
memcpy(d, s, width * 4);
|
||||
#else
|
||||
int w;
|
||||
uint32_t r, g, b;
|
||||
|
||||
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;
|
||||
} while (--w != 0);
|
||||
#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
|
||||
#undef PIXEL_TYPE
|
||||
+4143
File diff suppressed because it is too large
Load Diff
+140
@@ -0,0 +1,140 @@
|
||||
/* ld script to make i386 Linux kernel
|
||||
* Written by Martin Mares <mj@atrey.karlin.mff.cuni.cz>;
|
||||
*/
|
||||
OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
|
||||
OUTPUT_ARCH(i386)
|
||||
SEARCH_DIR(/lib); SEARCH_DIR(/usr/lib); SEARCH_DIR(/usr/local/lib); SEARCH_DIR(/usr/alpha-unknown-linux-gnu/lib);
|
||||
ENTRY(_start)
|
||||
SECTIONS
|
||||
{
|
||||
/* Read-only sections, merged into text segment: */
|
||||
. = 0xa8000000 + SIZEOF_HEADERS;
|
||||
.interp : { *(.interp) }
|
||||
.hash : { *(.hash) }
|
||||
.dynsym : { *(.dynsym) }
|
||||
.dynstr : { *(.dynstr) }
|
||||
.gnu.version : { *(.gnu.version) }
|
||||
.gnu.version_d : { *(.gnu.version_d) }
|
||||
.gnu.version_r : { *(.gnu.version_r) }
|
||||
.rel.text :
|
||||
{ *(.rel.text) *(.rel.gnu.linkonce.t*) }
|
||||
.rela.text :
|
||||
{ *(.rela.text) *(.rela.gnu.linkonce.t*) }
|
||||
.rel.data :
|
||||
{ *(.rel.data) *(.rel.gnu.linkonce.d*) }
|
||||
.rela.data :
|
||||
{ *(.rela.data) *(.rela.gnu.linkonce.d*) }
|
||||
.rel.rodata :
|
||||
{ *(.rel.rodata) *(.rel.gnu.linkonce.r*) }
|
||||
.rela.rodata :
|
||||
{ *(.rela.rodata) *(.rela.gnu.linkonce.r*) }
|
||||
.rel.got : { *(.rel.got) }
|
||||
.rela.got : { *(.rela.got) }
|
||||
.rel.ctors : { *(.rel.ctors) }
|
||||
.rela.ctors : { *(.rela.ctors) }
|
||||
.rel.dtors : { *(.rel.dtors) }
|
||||
.rela.dtors : { *(.rela.dtors) }
|
||||
.rel.init : { *(.rel.init) }
|
||||
.rela.init : { *(.rela.init) }
|
||||
.rel.fini : { *(.rel.fini) }
|
||||
.rela.fini : { *(.rela.fini) }
|
||||
.rel.bss : { *(.rel.bss) }
|
||||
.rela.bss : { *(.rela.bss) }
|
||||
.rel.plt : { *(.rel.plt) }
|
||||
.rela.plt : { *(.rela.plt) }
|
||||
.init : { *(.init) } =0x47ff041f
|
||||
.text :
|
||||
{
|
||||
*(.text)
|
||||
/* .gnu.warning sections are handled specially by elf32.em. */
|
||||
*(.gnu.warning)
|
||||
*(.gnu.linkonce.t*)
|
||||
} =0x47ff041f
|
||||
_etext = .;
|
||||
PROVIDE (etext = .);
|
||||
.fini : { *(.fini) } =0x47ff041f
|
||||
.rodata : { *(.rodata) *(.gnu.linkonce.r*) }
|
||||
.rodata1 : { *(.rodata1) }
|
||||
.reginfo : { *(.reginfo) }
|
||||
__preinit_array_start = .;
|
||||
.preinit_array : { *(.preinit_array) }
|
||||
__preinit_array_end = .;
|
||||
__init_array_start = .;
|
||||
.init_array : { *(.init_array) }
|
||||
__init_array_end = .;
|
||||
__fini_array_start = .;
|
||||
.fini_array : { *(.fini_array) }
|
||||
__fini_array_end = .;
|
||||
|
||||
/* Adjust the address for the data segment. We want to adjust up to
|
||||
the same address within the page on the next page up. */
|
||||
. = ALIGN(0x100000) + (. & (0x100000 - 1));
|
||||
.data :
|
||||
{
|
||||
*(.data)
|
||||
*(.gnu.linkonce.d*)
|
||||
CONSTRUCTORS
|
||||
}
|
||||
.data1 : { *(.data1) }
|
||||
.ctors :
|
||||
{
|
||||
*(.ctors)
|
||||
}
|
||||
.dtors :
|
||||
{
|
||||
*(.dtors)
|
||||
}
|
||||
.plt : { *(.plt) }
|
||||
.got : { *(.got.plt) *(.got) }
|
||||
.dynamic : { *(.dynamic) }
|
||||
/* We want the small data sections together, so single-instruction offsets
|
||||
can access them all, and initialized data all before uninitialized, so
|
||||
we can shorten the on-disk segment size. */
|
||||
.sdata : { *(.sdata) }
|
||||
_edata = .;
|
||||
PROVIDE (edata = .);
|
||||
__bss_start = .;
|
||||
.sbss : { *(.sbss) *(.scommon) }
|
||||
.bss :
|
||||
{
|
||||
*(.dynbss)
|
||||
*(.bss)
|
||||
*(COMMON)
|
||||
}
|
||||
_end = . ;
|
||||
PROVIDE (end = .);
|
||||
/* Stabs debugging sections. */
|
||||
.stab 0 : { *(.stab) }
|
||||
.stabstr 0 : { *(.stabstr) }
|
||||
.stab.excl 0 : { *(.stab.excl) }
|
||||
.stab.exclstr 0 : { *(.stab.exclstr) }
|
||||
.stab.index 0 : { *(.stab.index) }
|
||||
.stab.indexstr 0 : { *(.stab.indexstr) }
|
||||
.comment 0 : { *(.comment) }
|
||||
/* DWARF debug sections.
|
||||
Symbols in the DWARF debugging sections are relative to the beginning
|
||||
of the section so we begin them at 0. */
|
||||
/* DWARF 1 */
|
||||
.debug 0 : { *(.debug) }
|
||||
.line 0 : { *(.line) }
|
||||
/* GNU DWARF 1 extensions */
|
||||
.debug_srcinfo 0 : { *(.debug_srcinfo) }
|
||||
.debug_sfnames 0 : { *(.debug_sfnames) }
|
||||
/* DWARF 1.1 and DWARF 2 */
|
||||
.debug_aranges 0 : { *(.debug_aranges) }
|
||||
.debug_pubnames 0 : { *(.debug_pubnames) }
|
||||
/* DWARF 2 */
|
||||
.debug_info 0 : { *(.debug_info) }
|
||||
.debug_abbrev 0 : { *(.debug_abbrev) }
|
||||
.debug_line 0 : { *(.debug_line) }
|
||||
.debug_frame 0 : { *(.debug_frame) }
|
||||
.debug_str 0 : { *(.debug_str) }
|
||||
.debug_loc 0 : { *(.debug_loc) }
|
||||
.debug_macinfo 0 : { *(.debug_macinfo) }
|
||||
/* SGI/MIPS DWARF 2 extensions */
|
||||
.debug_weaknames 0 : { *(.debug_weaknames) }
|
||||
.debug_funcnames 0 : { *(.debug_funcnames) }
|
||||
.debug_typenames 0 : { *(.debug_typenames) }
|
||||
.debug_varnames 0 : { *(.debug_varnames) }
|
||||
/* These must appear regardless of . */
|
||||
}
|
||||
@@ -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) }
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
/* derived from glibc sysdeps/unix/sysv/linux/ia64/sysdep.S */
|
||||
|
||||
#define __ASSEMBLY__
|
||||
|
||||
#include <asm/asmmacro.h>
|
||||
#include <asm/unistd.h>
|
||||
|
||||
ENTRY(__syscall_error)
|
||||
.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(0)
|
||||
alloc r33=ar.pfs, 0, 4, 0, 0
|
||||
mov r32=rp
|
||||
.body
|
||||
mov r35=r8
|
||||
mov r34=r1
|
||||
;;
|
||||
br.call.sptk.many b0 = __errno_location
|
||||
.Lret0: /* force new bundle */
|
||||
st4 [r8]=r35
|
||||
mov r1=r34
|
||||
mov rp=r32
|
||||
mov r8=-1
|
||||
mov ar.pfs=r33
|
||||
br.ret.sptk.few b0
|
||||
END(__syscall_error)
|
||||
|
||||
GLOBAL_ENTRY(__ia64_syscall)
|
||||
mov r15=r37 /* syscall number */
|
||||
break __BREAK_SYSCALL
|
||||
cmp.eq p6,p0=-1,r10 /* r10 = -1 on error */
|
||||
(p6) br.cond.spnt.few __syscall_error
|
||||
br.ret.sptk.few b0
|
||||
.endp __ia64_syscall
|
||||
@@ -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
|
||||
@@ -0,0 +1,36 @@
|
||||
|
||||
/* this struct defines the way the registers are stored on the
|
||||
stack during a system call. */
|
||||
|
||||
struct target_pt_regs {
|
||||
target_long uregs[18];
|
||||
};
|
||||
|
||||
#define ARM_cpsr uregs[16]
|
||||
#define ARM_pc uregs[15]
|
||||
#define ARM_lr uregs[14]
|
||||
#define ARM_sp uregs[13]
|
||||
#define ARM_ip uregs[12]
|
||||
#define ARM_fp uregs[11]
|
||||
#define ARM_r10 uregs[10]
|
||||
#define ARM_r9 uregs[9]
|
||||
#define ARM_r8 uregs[8]
|
||||
#define ARM_r7 uregs[7]
|
||||
#define ARM_r6 uregs[6]
|
||||
#define ARM_r5 uregs[5]
|
||||
#define ARM_r4 uregs[4]
|
||||
#define ARM_r3 uregs[3]
|
||||
#define ARM_r2 uregs[2]
|
||||
#define ARM_r1 uregs[1]
|
||||
#define ARM_r0 uregs[0]
|
||||
#define ARM_ORIG_r0 uregs[17]
|
||||
|
||||
#define ARM_SYSCALL_BASE 0x900000
|
||||
|
||||
#define ARM_NR_cacheflush (ARM_SYSCALL_BASE + 0xf0000 + 2)
|
||||
|
||||
#if defined(TARGET_WORDS_BIGENDIAN)
|
||||
#define UNAME_MACHINE "armv4b"
|
||||
#else
|
||||
#define UNAME_MACHINE "armv4l"
|
||||
#endif
|
||||
@@ -0,0 +1,261 @@
|
||||
/*
|
||||
* This file contains the system call numbers.
|
||||
*/
|
||||
|
||||
#define TARGET_NR_restart_syscall ( 0)
|
||||
#define TARGET_NR_exit ( 1)
|
||||
#define TARGET_NR_fork ( 2)
|
||||
#define TARGET_NR_read ( 3)
|
||||
#define TARGET_NR_write ( 4)
|
||||
#define TARGET_NR_open ( 5)
|
||||
#define TARGET_NR_close ( 6)
|
||||
#define TARGET_NR_waitpid ( 7) /* removed */
|
||||
#define TARGET_NR_creat ( 8)
|
||||
#define TARGET_NR_link ( 9)
|
||||
#define TARGET_NR_unlink ( 10)
|
||||
#define TARGET_NR_execve ( 11)
|
||||
#define TARGET_NR_chdir ( 12)
|
||||
#define TARGET_NR_time ( 13)
|
||||
#define TARGET_NR_mknod ( 14)
|
||||
#define TARGET_NR_chmod ( 15)
|
||||
#define TARGET_NR_lchown ( 16)
|
||||
#define TARGET_NR_break ( 17) /* removed */
|
||||
/* 18 was sys_stat */
|
||||
#define TARGET_NR_lseek ( 19)
|
||||
#define TARGET_NR_getpid ( 20)
|
||||
#define TARGET_NR_mount ( 21)
|
||||
#define TARGET_NR_umount ( 22)
|
||||
#define TARGET_NR_setuid ( 23)
|
||||
#define TARGET_NR_getuid ( 24)
|
||||
#define TARGET_NR_stime ( 25)
|
||||
#define TARGET_NR_ptrace ( 26)
|
||||
#define TARGET_NR_alarm ( 27)
|
||||
|
||||
#define TARGET_NR_pause ( 29)
|
||||
#define TARGET_NR_utime ( 30)
|
||||
#define TARGET_NR_stty ( 31) /* removed */
|
||||
#define TARGET_NR_gtty ( 32) /* removed */
|
||||
#define TARGET_NR_access ( 33)
|
||||
#define TARGET_NR_nice ( 34)
|
||||
#define TARGET_NR_ftime ( 35) /* removed */
|
||||
#define TARGET_NR_sync ( 36)
|
||||
#define TARGET_NR_kill ( 37)
|
||||
#define TARGET_NR_rename ( 38)
|
||||
#define TARGET_NR_mkdir ( 39)
|
||||
#define TARGET_NR_rmdir ( 40)
|
||||
#define TARGET_NR_dup ( 41)
|
||||
#define TARGET_NR_pipe ( 42)
|
||||
#define TARGET_NR_times ( 43)
|
||||
#define TARGET_NR_prof ( 44) /* removed */
|
||||
#define TARGET_NR_brk ( 45)
|
||||
#define TARGET_NR_setgid ( 46)
|
||||
#define TARGET_NR_getgid ( 47)
|
||||
#define TARGET_NR_signal ( 48) /* removed */
|
||||
#define TARGET_NR_geteuid ( 49)
|
||||
#define TARGET_NR_getegid ( 50)
|
||||
#define TARGET_NR_acct ( 51)
|
||||
#define TARGET_NR_umount2 ( 52)
|
||||
#define TARGET_NR_lock ( 53) /* removed */
|
||||
#define TARGET_NR_ioctl ( 54)
|
||||
#define TARGET_NR_fcntl ( 55)
|
||||
#define TARGET_NR_mpx ( 56) /* removed */
|
||||
#define TARGET_NR_setpgid ( 57)
|
||||
#define TARGET_NR_ulimit ( 58) /* removed */
|
||||
/* 59 was sys_olduname */
|
||||
#define TARGET_NR_umask ( 60)
|
||||
#define TARGET_NR_chroot ( 61)
|
||||
#define TARGET_NR_ustat ( 62)
|
||||
#define TARGET_NR_dup2 ( 63)
|
||||
#define TARGET_NR_getppid ( 64)
|
||||
#define TARGET_NR_getpgrp ( 65)
|
||||
#define TARGET_NR_setsid ( 66)
|
||||
#define TARGET_NR_sigaction ( 67)
|
||||
#define TARGET_NR_sgetmask ( 68) /* removed */
|
||||
#define TARGET_NR_ssetmask ( 69) /* removed */
|
||||
#define TARGET_NR_setreuid ( 70)
|
||||
#define TARGET_NR_setregid ( 71)
|
||||
#define TARGET_NR_sigsuspend ( 72)
|
||||
#define TARGET_NR_sigpending ( 73)
|
||||
#define TARGET_NR_sethostname ( 74)
|
||||
#define TARGET_NR_setrlimit ( 75)
|
||||
#define TARGET_NR_getrlimit ( 76) /* Back compat 2GB limited rlimit */
|
||||
#define TARGET_NR_getrusage ( 77)
|
||||
#define TARGET_NR_gettimeofday ( 78)
|
||||
#define TARGET_NR_settimeofday ( 79)
|
||||
#define TARGET_NR_getgroups ( 80)
|
||||
#define TARGET_NR_setgroups ( 81)
|
||||
#define TARGET_NR_select ( 82)
|
||||
#define TARGET_NR_symlink ( 83)
|
||||
/* 84 was sys_lstat */
|
||||
#define TARGET_NR_readlink ( 85)
|
||||
#define TARGET_NR_uselib ( 86)
|
||||
#define TARGET_NR_swapon ( 87)
|
||||
#define TARGET_NR_reboot ( 88)
|
||||
#define TARGET_NR_readdir ( 89)
|
||||
#define TARGET_NR_mmap ( 90)
|
||||
#define TARGET_NR_munmap ( 91)
|
||||
#define TARGET_NR_truncate ( 92)
|
||||
#define TARGET_NR_ftruncate ( 93)
|
||||
#define TARGET_NR_fchmod ( 94)
|
||||
#define TARGET_NR_fchown ( 95)
|
||||
#define TARGET_NR_getpriority ( 96)
|
||||
#define TARGET_NR_setpriority ( 97)
|
||||
#define TARGET_NR_profil ( 98) /* removed */
|
||||
#define TARGET_NR_statfs ( 99)
|
||||
#define TARGET_NR_fstatfs (100)
|
||||
#define TARGET_NR_ioperm (101)
|
||||
#define TARGET_NR_socketcall (102)
|
||||
#define TARGET_NR_syslog (103)
|
||||
#define TARGET_NR_setitimer (104)
|
||||
#define TARGET_NR_getitimer (105)
|
||||
#define TARGET_NR_stat (106)
|
||||
#define TARGET_NR_lstat (107)
|
||||
#define TARGET_NR_fstat (108)
|
||||
/* 109 was sys_uname */
|
||||
/* 110 was sys_iopl */
|
||||
#define TARGET_NR_vhangup (111)
|
||||
#define TARGET_NR_idle (112)
|
||||
#define TARGET_NR_syscall (113) /* syscall to call a syscall! */
|
||||
#define TARGET_NR_wait4 (114)
|
||||
#define TARGET_NR_swapoff (115)
|
||||
#define TARGET_NR_sysinfo (116)
|
||||
#define TARGET_NR_ipc (117)
|
||||
#define TARGET_NR_fsync (118)
|
||||
#define TARGET_NR_sigreturn (119)
|
||||
#define TARGET_NR_clone (120)
|
||||
#define TARGET_NR_setdomainname (121)
|
||||
#define TARGET_NR_uname (122)
|
||||
#define TARGET_NR_modify_ldt (123)
|
||||
#define TARGET_NR_adjtimex (124)
|
||||
#define TARGET_NR_mprotect (125)
|
||||
#define TARGET_NR_sigprocmask (126)
|
||||
#define TARGET_NR_create_module (127) /* removed */
|
||||
#define TARGET_NR_init_module (128)
|
||||
#define TARGET_NR_delete_module (129)
|
||||
#define TARGET_NR_get_kernel_syms (130) /* removed */
|
||||
#define TARGET_NR_quotactl (131)
|
||||
#define TARGET_NR_getpgid (132)
|
||||
#define TARGET_NR_fchdir (133)
|
||||
#define TARGET_NR_bdflush (134)
|
||||
#define TARGET_NR_sysfs (135)
|
||||
#define TARGET_NR_personality (136)
|
||||
#define TARGET_NR_afs_syscall (137) /* Syscall for Andrew File System */
|
||||
#define TARGET_NR_setfsuid (138)
|
||||
#define TARGET_NR_setfsgid (139)
|
||||
#define TARGET_NR__llseek (140)
|
||||
#define TARGET_NR_getdents (141)
|
||||
#define TARGET_NR__newselect (142)
|
||||
#define TARGET_NR_flock (143)
|
||||
#define TARGET_NR_msync (144)
|
||||
#define TARGET_NR_readv (145)
|
||||
#define TARGET_NR_writev (146)
|
||||
#define TARGET_NR_getsid (147)
|
||||
#define TARGET_NR_fdatasync (148)
|
||||
#define TARGET_NR__sysctl (149)
|
||||
#define TARGET_NR_mlock (150)
|
||||
#define TARGET_NR_munlock (151)
|
||||
#define TARGET_NR_mlockall (152)
|
||||
#define TARGET_NR_munlockall (153)
|
||||
#define TARGET_NR_sched_setparam (154)
|
||||
#define TARGET_NR_sched_getparam (155)
|
||||
#define TARGET_NR_sched_setscheduler (156)
|
||||
#define TARGET_NR_sched_getscheduler (157)
|
||||
#define TARGET_NR_sched_yield (158)
|
||||
#define TARGET_NR_sched_get_priority_max (159)
|
||||
#define TARGET_NR_sched_get_priority_min (160)
|
||||
#define TARGET_NR_sched_rr_get_interval (161)
|
||||
#define TARGET_NR_nanosleep (162)
|
||||
#define TARGET_NR_mremap (163)
|
||||
#define TARGET_NR_setresuid (164)
|
||||
#define TARGET_NR_getresuid (165)
|
||||
#define TARGET_NR_vm86 (166) /* removed */
|
||||
#define TARGET_NR_query_module (167) /* removed */
|
||||
#define TARGET_NR_poll (168)
|
||||
#define TARGET_NR_nfsservctl (169)
|
||||
#define TARGET_NR_setresgid (170)
|
||||
#define TARGET_NR_getresgid (171)
|
||||
#define TARGET_NR_prctl (172)
|
||||
#define TARGET_NR_rt_sigreturn (173)
|
||||
#define TARGET_NR_rt_sigaction (174)
|
||||
#define TARGET_NR_rt_sigprocmask (175)
|
||||
#define TARGET_NR_rt_sigpending (176)
|
||||
#define TARGET_NR_rt_sigtimedwait (177)
|
||||
#define TARGET_NR_rt_sigqueueinfo (178)
|
||||
#define TARGET_NR_rt_sigsuspend (179)
|
||||
#define TARGET_NR_pread (180)
|
||||
#define TARGET_NR_pwrite (181)
|
||||
#define TARGET_NR_chown (182)
|
||||
#define TARGET_NR_getcwd (183)
|
||||
#define TARGET_NR_capget (184)
|
||||
#define TARGET_NR_capset (185)
|
||||
#define TARGET_NR_sigaltstack (186)
|
||||
#define TARGET_NR_sendfile (187)
|
||||
/* 188 reserved */
|
||||
/* 189 reserved */
|
||||
#define TARGET_NR_vfork (190)
|
||||
#define TARGET_NR_ugetrlimit (191) /* SuS compliant getrlimit */
|
||||
#define TARGET_NR_mmap2 (192)
|
||||
#define TARGET_NR_truncate64 (193)
|
||||
#define TARGET_NR_ftruncate64 (194)
|
||||
#define TARGET_NR_stat64 (195)
|
||||
#define TARGET_NR_lstat64 (196)
|
||||
#define TARGET_NR_fstat64 (197)
|
||||
#define TARGET_NR_lchown32 (198)
|
||||
#define TARGET_NR_getuid32 (199)
|
||||
#define TARGET_NR_getgid32 (200)
|
||||
#define TARGET_NR_geteuid32 (201)
|
||||
#define TARGET_NR_getegid32 (202)
|
||||
#define TARGET_NR_setreuid32 (203)
|
||||
#define TARGET_NR_setregid32 (204)
|
||||
#define TARGET_NR_getgroups32 (205)
|
||||
#define TARGET_NR_setgroups32 (206)
|
||||
#define TARGET_NR_fchown32 (207)
|
||||
#define TARGET_NR_setresuid32 (208)
|
||||
#define TARGET_NR_getresuid32 (209)
|
||||
#define TARGET_NR_setresgid32 (210)
|
||||
#define TARGET_NR_getresgid32 (211)
|
||||
#define TARGET_NR_chown32 (212)
|
||||
#define TARGET_NR_setuid32 (213)
|
||||
#define TARGET_NR_setgid32 (214)
|
||||
#define TARGET_NR_setfsuid32 (215)
|
||||
#define TARGET_NR_setfsgid32 (216)
|
||||
#define TARGET_NR_getdents64 (217)
|
||||
#define TARGET_NR_pivot_root (218)
|
||||
#define TARGET_NR_mincore (219)
|
||||
#define TARGET_NR_madvise (220)
|
||||
#define TARGET_NR_fcntl64 (221)
|
||||
/* 222 for tux */
|
||||
/* 223 is unused */
|
||||
#define TARGET_NR_gettid (224)
|
||||
#define TARGET_NR_readahead (225)
|
||||
#define TARGET_NR_setxattr (226)
|
||||
#define TARGET_NR_lsetxattr (227)
|
||||
#define TARGET_NR_fsetxattr (228)
|
||||
#define TARGET_NR_getxattr (229)
|
||||
#define TARGET_NR_lgetxattr (230)
|
||||
#define TARGET_NR_fgetxattr (231)
|
||||
#define TARGET_NR_listxattr (232)
|
||||
#define TARGET_NR_llistxattr (233)
|
||||
#define TARGET_NR_flistxattr (234)
|
||||
#define TARGET_NR_removexattr (235)
|
||||
#define TARGET_NR_lremovexattr (236)
|
||||
#define TARGET_NR_fremovexattr (237)
|
||||
#define TARGET_NR_tkill (238)
|
||||
#define TARGET_NR_sendfile64 (239)
|
||||
#define TARGET_NR_futex (240)
|
||||
#define TARGET_NR_sched_setaffinity (241)
|
||||
#define TARGET_NR_sched_getaffinity (242)
|
||||
#define TARGET_NR_io_setup (243)
|
||||
#define TARGET_NR_io_destroy (244)
|
||||
#define TARGET_NR_io_getevents (245)
|
||||
#define TARGET_NR_io_submit (246)
|
||||
#define TARGET_NR_io_cancel (247)
|
||||
#define TARGET_NR_exit_group (248)
|
||||
#define TARGET_NR_lookup_dcookie (249)
|
||||
#define TARGET_NR_epoll_create (250)
|
||||
#define TARGET_NR_epoll_ctl (251)
|
||||
#define TARGET_NR_epoll_wait (252)
|
||||
#define TARGET_NR_remap_file_pages (253)
|
||||
/* 254 for set_thread_area */
|
||||
/* 255 for get_thread_area */
|
||||
/* 256 for set_tid_address */
|
||||
@@ -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 */
|
||||
|
||||
+584
-214
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,221 @@
|
||||
/* default linux values for the selectors */
|
||||
#define __USER_CS (0x23)
|
||||
#define __USER_DS (0x2B)
|
||||
|
||||
struct target_pt_regs {
|
||||
long ebx;
|
||||
long ecx;
|
||||
long edx;
|
||||
long esi;
|
||||
long edi;
|
||||
long ebp;
|
||||
long eax;
|
||||
int xds;
|
||||
int xes;
|
||||
long orig_eax;
|
||||
long eip;
|
||||
int xcs;
|
||||
long eflags;
|
||||
long esp;
|
||||
int xss;
|
||||
};
|
||||
|
||||
/* ioctls */
|
||||
|
||||
#define TARGET_LDT_ENTRIES 8192
|
||||
#define TARGET_LDT_ENTRY_SIZE 8
|
||||
|
||||
#define TARGET_GDT_ENTRY_TLS_ENTRIES 3
|
||||
#define TARGET_GDT_ENTRY_TLS_MIN 6
|
||||
#define TARGET_GDT_ENTRY_TLS_MAX (TARGET_GDT_ENTRY_TLS_MIN + TARGET_GDT_ENTRY_TLS_ENTRIES - 1)
|
||||
|
||||
struct target_modify_ldt_ldt_s {
|
||||
unsigned int entry_number;
|
||||
target_ulong base_addr;
|
||||
unsigned int limit;
|
||||
unsigned int flags;
|
||||
};
|
||||
|
||||
/* vm86 defines */
|
||||
|
||||
#define TARGET_BIOSSEG 0x0f000
|
||||
|
||||
#define TARGET_CPU_086 0
|
||||
#define TARGET_CPU_186 1
|
||||
#define TARGET_CPU_286 2
|
||||
#define TARGET_CPU_386 3
|
||||
#define TARGET_CPU_486 4
|
||||
#define TARGET_CPU_586 5
|
||||
|
||||
#define TARGET_VM86_SIGNAL 0 /* return due to signal */
|
||||
#define TARGET_VM86_UNKNOWN 1 /* unhandled GP fault - IO-instruction or similar */
|
||||
#define TARGET_VM86_INTx 2 /* int3/int x instruction (ARG = x) */
|
||||
#define TARGET_VM86_STI 3 /* sti/popf/iret instruction enabled virtual interrupts */
|
||||
|
||||
/*
|
||||
* Additional return values when invoking new vm86()
|
||||
*/
|
||||
#define TARGET_VM86_PICRETURN 4 /* return due to pending PIC request */
|
||||
#define TARGET_VM86_TRAP 6 /* return due to DOS-debugger request */
|
||||
|
||||
/*
|
||||
* function codes when invoking new vm86()
|
||||
*/
|
||||
#define TARGET_VM86_PLUS_INSTALL_CHECK 0
|
||||
#define TARGET_VM86_ENTER 1
|
||||
#define TARGET_VM86_ENTER_NO_BYPASS 2
|
||||
#define TARGET_VM86_REQUEST_IRQ 3
|
||||
#define TARGET_VM86_FREE_IRQ 4
|
||||
#define TARGET_VM86_GET_IRQ_BITS 5
|
||||
#define TARGET_VM86_GET_AND_RESET_IRQ 6
|
||||
|
||||
/*
|
||||
* This is the stack-layout seen by the user space program when we have
|
||||
* done a translation of "SAVE_ALL" from vm86 mode. The real kernel layout
|
||||
* is 'kernel_vm86_regs' (see below).
|
||||
*/
|
||||
|
||||
struct target_vm86_regs {
|
||||
/*
|
||||
* normal regs, with special meaning for the segment descriptors..
|
||||
*/
|
||||
target_long ebx;
|
||||
target_long ecx;
|
||||
target_long edx;
|
||||
target_long esi;
|
||||
target_long edi;
|
||||
target_long ebp;
|
||||
target_long eax;
|
||||
target_long __null_ds;
|
||||
target_long __null_es;
|
||||
target_long __null_fs;
|
||||
target_long __null_gs;
|
||||
target_long orig_eax;
|
||||
target_long eip;
|
||||
unsigned short cs, __csh;
|
||||
target_long eflags;
|
||||
target_long esp;
|
||||
unsigned short ss, __ssh;
|
||||
/*
|
||||
* these are specific to v86 mode:
|
||||
*/
|
||||
unsigned short es, __esh;
|
||||
unsigned short ds, __dsh;
|
||||
unsigned short fs, __fsh;
|
||||
unsigned short gs, __gsh;
|
||||
};
|
||||
|
||||
struct target_revectored_struct {
|
||||
target_ulong __map[8]; /* 256 bits */
|
||||
};
|
||||
|
||||
struct target_vm86_struct {
|
||||
struct target_vm86_regs regs;
|
||||
target_ulong flags;
|
||||
target_ulong screen_bitmap;
|
||||
target_ulong cpu_type;
|
||||
struct target_revectored_struct int_revectored;
|
||||
struct target_revectored_struct int21_revectored;
|
||||
};
|
||||
|
||||
/*
|
||||
* flags masks
|
||||
*/
|
||||
#define TARGET_VM86_SCREEN_BITMAP 0x0001
|
||||
|
||||
struct target_vm86plus_info_struct {
|
||||
target_ulong flags;
|
||||
#define TARGET_force_return_for_pic (1 << 0)
|
||||
#define TARGET_vm86dbg_active (1 << 1) /* for debugger */
|
||||
#define TARGET_vm86dbg_TFpendig (1 << 2) /* for debugger */
|
||||
#define TARGET_is_vm86pus (1 << 31) /* for vm86 internal use */
|
||||
unsigned char vm86dbg_intxxtab[32]; /* for debugger */
|
||||
};
|
||||
|
||||
struct target_vm86plus_struct {
|
||||
struct target_vm86_regs regs;
|
||||
target_ulong flags;
|
||||
target_ulong screen_bitmap;
|
||||
target_ulong cpu_type;
|
||||
struct target_revectored_struct int_revectored;
|
||||
struct target_revectored_struct int21_revectored;
|
||||
struct target_vm86plus_info_struct vm86plus;
|
||||
};
|
||||
|
||||
/* ipcs */
|
||||
|
||||
#define TARGET_SEMOP 1
|
||||
#define TARGET_SEMGET 2
|
||||
#define TARGET_SEMCTL 3
|
||||
#define TARGET_MSGSND 11
|
||||
#define TARGET_MSGRCV 12
|
||||
#define TARGET_MSGGET 13
|
||||
#define TARGET_MSGCTL 14
|
||||
#define TARGET_SHMAT 21
|
||||
#define TARGET_SHMDT 22
|
||||
#define TARGET_SHMGET 23
|
||||
#define TARGET_SHMCTL 24
|
||||
|
||||
struct target_msgbuf {
|
||||
int mtype;
|
||||
char mtext[1];
|
||||
};
|
||||
|
||||
struct target_ipc_kludge {
|
||||
unsigned int msgp; /* Really (struct msgbuf *) */
|
||||
int msgtyp;
|
||||
};
|
||||
|
||||
struct target_ipc_perm {
|
||||
int key;
|
||||
unsigned short uid;
|
||||
unsigned short gid;
|
||||
unsigned short cuid;
|
||||
unsigned short cgid;
|
||||
unsigned short mode;
|
||||
unsigned short seq;
|
||||
};
|
||||
|
||||
struct target_msqid_ds {
|
||||
struct target_ipc_perm msg_perm;
|
||||
unsigned int msg_first; /* really struct target_msg* */
|
||||
unsigned int msg_last; /* really struct target_msg* */
|
||||
unsigned int msg_stime; /* really target_time_t */
|
||||
unsigned int msg_rtime; /* really target_time_t */
|
||||
unsigned int msg_ctime; /* really target_time_t */
|
||||
unsigned int wwait; /* really struct wait_queue* */
|
||||
unsigned int rwait; /* really struct wait_queue* */
|
||||
unsigned short msg_cbytes;
|
||||
unsigned short msg_qnum;
|
||||
unsigned short msg_qbytes;
|
||||
unsigned short msg_lspid;
|
||||
unsigned short msg_lrpid;
|
||||
};
|
||||
|
||||
struct target_shmid_ds {
|
||||
struct target_ipc_perm shm_perm;
|
||||
int shm_segsz;
|
||||
unsigned int shm_atime; /* really target_time_t */
|
||||
unsigned int shm_dtime; /* really target_time_t */
|
||||
unsigned int shm_ctime; /* really target_time_t */
|
||||
unsigned short shm_cpid;
|
||||
unsigned short shm_lpid;
|
||||
short shm_nattch;
|
||||
unsigned short shm_npages;
|
||||
unsigned long *shm_pages;
|
||||
void *attaches; /* really struct shm_desc * */
|
||||
};
|
||||
|
||||
#define TARGET_IPC_RMID 0
|
||||
#define TARGET_IPC_SET 1
|
||||
#define TARGET_IPC_STAT 2
|
||||
|
||||
union target_semun {
|
||||
int val;
|
||||
unsigned int buf; /* really struct semid_ds * */
|
||||
unsigned int array; /* really unsigned short * */
|
||||
unsigned int __buf; /* really struct seminfo * */
|
||||
unsigned int __pad; /* really void* */
|
||||
};
|
||||
|
||||
#define UNAME_MACHINE "i686"
|
||||
@@ -0,0 +1,273 @@
|
||||
/*
|
||||
* This file contains the system call numbers.
|
||||
*/
|
||||
|
||||
#define TARGET_NR_restart_syscall 0
|
||||
#define TARGET_NR_exit 1
|
||||
#define TARGET_NR_fork 2
|
||||
#define TARGET_NR_read 3
|
||||
#define TARGET_NR_write 4
|
||||
#define TARGET_NR_open 5
|
||||
#define TARGET_NR_close 6
|
||||
#define TARGET_NR_waitpid 7
|
||||
#define TARGET_NR_creat 8
|
||||
#define TARGET_NR_link 9
|
||||
#define TARGET_NR_unlink 10
|
||||
#define TARGET_NR_execve 11
|
||||
#define TARGET_NR_chdir 12
|
||||
#define TARGET_NR_time 13
|
||||
#define TARGET_NR_mknod 14
|
||||
#define TARGET_NR_chmod 15
|
||||
#define TARGET_NR_lchown 16
|
||||
#define TARGET_NR_break 17
|
||||
#define TARGET_NR_oldstat 18
|
||||
#define TARGET_NR_lseek 19
|
||||
#define TARGET_NR_getpid 20
|
||||
#define TARGET_NR_mount 21
|
||||
#define TARGET_NR_umount 22
|
||||
#define TARGET_NR_setuid 23
|
||||
#define TARGET_NR_getuid 24
|
||||
#define TARGET_NR_stime 25
|
||||
#define TARGET_NR_ptrace 26
|
||||
#define TARGET_NR_alarm 27
|
||||
#define TARGET_NR_oldfstat 28
|
||||
#define TARGET_NR_pause 29
|
||||
#define TARGET_NR_utime 30
|
||||
#define TARGET_NR_stty 31
|
||||
#define TARGET_NR_gtty 32
|
||||
#define TARGET_NR_access 33
|
||||
#define TARGET_NR_nice 34
|
||||
#define TARGET_NR_ftime 35
|
||||
#define TARGET_NR_sync 36
|
||||
#define TARGET_NR_kill 37
|
||||
#define TARGET_NR_rename 38
|
||||
#define TARGET_NR_mkdir 39
|
||||
#define TARGET_NR_rmdir 40
|
||||
#define TARGET_NR_dup 41
|
||||
#define TARGET_NR_pipe 42
|
||||
#define TARGET_NR_times 43
|
||||
#define TARGET_NR_prof 44
|
||||
#define TARGET_NR_brk 45
|
||||
#define TARGET_NR_setgid 46
|
||||
#define TARGET_NR_getgid 47
|
||||
#define TARGET_NR_signal 48
|
||||
#define TARGET_NR_geteuid 49
|
||||
#define TARGET_NR_getegid 50
|
||||
#define TARGET_NR_acct 51
|
||||
#define TARGET_NR_umount2 52
|
||||
#define TARGET_NR_lock 53
|
||||
#define TARGET_NR_ioctl 54
|
||||
#define TARGET_NR_fcntl 55
|
||||
#define TARGET_NR_mpx 56
|
||||
#define TARGET_NR_setpgid 57
|
||||
#define TARGET_NR_ulimit 58
|
||||
#define TARGET_NR_oldolduname 59
|
||||
#define TARGET_NR_umask 60
|
||||
#define TARGET_NR_chroot 61
|
||||
#define TARGET_NR_ustat 62
|
||||
#define TARGET_NR_dup2 63
|
||||
#define TARGET_NR_getppid 64
|
||||
#define TARGET_NR_getpgrp 65
|
||||
#define TARGET_NR_setsid 66
|
||||
#define TARGET_NR_sigaction 67
|
||||
#define TARGET_NR_sgetmask 68
|
||||
#define TARGET_NR_ssetmask 69
|
||||
#define TARGET_NR_setreuid 70
|
||||
#define TARGET_NR_setregid 71
|
||||
#define TARGET_NR_sigsuspend 72
|
||||
#define TARGET_NR_sigpending 73
|
||||
#define TARGET_NR_sethostname 74
|
||||
#define TARGET_NR_setrlimit 75
|
||||
#define TARGET_NR_getrlimit 76 /* Back compatible 2Gig limited rlimit */
|
||||
#define TARGET_NR_getrusage 77
|
||||
#define TARGET_NR_gettimeofday 78
|
||||
#define TARGET_NR_settimeofday 79
|
||||
#define TARGET_NR_getgroups 80
|
||||
#define TARGET_NR_setgroups 81
|
||||
#define TARGET_NR_select 82
|
||||
#define TARGET_NR_symlink 83
|
||||
#define TARGET_NR_oldlstat 84
|
||||
#define TARGET_NR_readlink 85
|
||||
#define TARGET_NR_uselib 86
|
||||
#define TARGET_NR_swapon 87
|
||||
#define TARGET_NR_reboot 88
|
||||
#define TARGET_NR_readdir 89
|
||||
#define TARGET_NR_mmap 90
|
||||
#define TARGET_NR_munmap 91
|
||||
#define TARGET_NR_truncate 92
|
||||
#define TARGET_NR_ftruncate 93
|
||||
#define TARGET_NR_fchmod 94
|
||||
#define TARGET_NR_fchown 95
|
||||
#define TARGET_NR_getpriority 96
|
||||
#define TARGET_NR_setpriority 97
|
||||
#define TARGET_NR_profil 98
|
||||
#define TARGET_NR_statfs 99
|
||||
#define TARGET_NR_fstatfs 100
|
||||
#define TARGET_NR_ioperm 101
|
||||
#define TARGET_NR_socketcall 102
|
||||
#define TARGET_NR_syslog 103
|
||||
#define TARGET_NR_setitimer 104
|
||||
#define TARGET_NR_getitimer 105
|
||||
#define TARGET_NR_stat 106
|
||||
#define TARGET_NR_lstat 107
|
||||
#define TARGET_NR_fstat 108
|
||||
#define TARGET_NR_olduname 109
|
||||
#define TARGET_NR_iopl 110
|
||||
#define TARGET_NR_vhangup 111
|
||||
#define TARGET_NR_idle 112
|
||||
#define TARGET_NR_vm86old 113
|
||||
#define TARGET_NR_wait4 114
|
||||
#define TARGET_NR_swapoff 115
|
||||
#define TARGET_NR_sysinfo 116
|
||||
#define TARGET_NR_ipc 117
|
||||
#define TARGET_NR_fsync 118
|
||||
#define TARGET_NR_sigreturn 119
|
||||
#define TARGET_NR_clone 120
|
||||
#define TARGET_NR_setdomainname 121
|
||||
#define TARGET_NR_uname 122
|
||||
#define TARGET_NR_modify_ldt 123
|
||||
#define TARGET_NR_adjtimex 124
|
||||
#define TARGET_NR_mprotect 125
|
||||
#define TARGET_NR_sigprocmask 126
|
||||
#define TARGET_NR_create_module 127
|
||||
#define TARGET_NR_init_module 128
|
||||
#define TARGET_NR_delete_module 129
|
||||
#define TARGET_NR_get_kernel_syms 130
|
||||
#define TARGET_NR_quotactl 131
|
||||
#define TARGET_NR_getpgid 132
|
||||
#define TARGET_NR_fchdir 133
|
||||
#define TARGET_NR_bdflush 134
|
||||
#define TARGET_NR_sysfs 135
|
||||
#define TARGET_NR_personality 136
|
||||
#define TARGET_NR_afs_syscall 137 /* Syscall for Andrew File System */
|
||||
#define TARGET_NR_setfsuid 138
|
||||
#define TARGET_NR_setfsgid 139
|
||||
#define TARGET_NR__llseek 140
|
||||
#define TARGET_NR_getdents 141
|
||||
#define TARGET_NR__newselect 142
|
||||
#define TARGET_NR_flock 143
|
||||
#define TARGET_NR_msync 144
|
||||
#define TARGET_NR_readv 145
|
||||
#define TARGET_NR_writev 146
|
||||
#define TARGET_NR_getsid 147
|
||||
#define TARGET_NR_fdatasync 148
|
||||
#define TARGET_NR__sysctl 149
|
||||
#define TARGET_NR_mlock 150
|
||||
#define TARGET_NR_munlock 151
|
||||
#define TARGET_NR_mlockall 152
|
||||
#define TARGET_NR_munlockall 153
|
||||
#define TARGET_NR_sched_setparam 154
|
||||
#define TARGET_NR_sched_getparam 155
|
||||
#define TARGET_NR_sched_setscheduler 156
|
||||
#define TARGET_NR_sched_getscheduler 157
|
||||
#define TARGET_NR_sched_yield 158
|
||||
#define TARGET_NR_sched_get_priority_max 159
|
||||
#define TARGET_NR_sched_get_priority_min 160
|
||||
#define TARGET_NR_sched_rr_get_interval 161
|
||||
#define TARGET_NR_nanosleep 162
|
||||
#define TARGET_NR_mremap 163
|
||||
#define TARGET_NR_setresuid 164
|
||||
#define TARGET_NR_getresuid 165
|
||||
#define TARGET_NR_vm86 166
|
||||
#define TARGET_NR_query_module 167
|
||||
#define TARGET_NR_poll 168
|
||||
#define TARGET_NR_nfsservctl 169
|
||||
#define TARGET_NR_setresgid 170
|
||||
#define TARGET_NR_getresgid 171
|
||||
#define TARGET_NR_prctl 172
|
||||
#define TARGET_NR_rt_sigreturn 173
|
||||
#define TARGET_NR_rt_sigaction 174
|
||||
#define TARGET_NR_rt_sigprocmask 175
|
||||
#define TARGET_NR_rt_sigpending 176
|
||||
#define TARGET_NR_rt_sigtimedwait 177
|
||||
#define TARGET_NR_rt_sigqueueinfo 178
|
||||
#define TARGET_NR_rt_sigsuspend 179
|
||||
#define TARGET_NR_pread 180
|
||||
#define TARGET_NR_pwrite 181
|
||||
#define TARGET_NR_chown 182
|
||||
#define TARGET_NR_getcwd 183
|
||||
#define TARGET_NR_capget 184
|
||||
#define TARGET_NR_capset 185
|
||||
#define TARGET_NR_sigaltstack 186
|
||||
#define TARGET_NR_sendfile 187
|
||||
#define TARGET_NR_getpmsg 188 /* some people actually want streams */
|
||||
#define TARGET_NR_putpmsg 189 /* some people actually want streams */
|
||||
#define TARGET_NR_vfork 190
|
||||
#define TARGET_NR_ugetrlimit 191 /* SuS compliant getrlimit */
|
||||
#define TARGET_NR_mmap2 192
|
||||
#define TARGET_NR_truncate64 193
|
||||
#define TARGET_NR_ftruncate64 194
|
||||
#define TARGET_NR_stat64 195
|
||||
#define TARGET_NR_lstat64 196
|
||||
#define TARGET_NR_fstat64 197
|
||||
#define TARGET_NR_lchown32 198
|
||||
#define TARGET_NR_getuid32 199
|
||||
#define TARGET_NR_getgid32 200
|
||||
#define TARGET_NR_geteuid32 201
|
||||
#define TARGET_NR_getegid32 202
|
||||
#define TARGET_NR_setreuid32 203
|
||||
#define TARGET_NR_setregid32 204
|
||||
#define TARGET_NR_getgroups32 205
|
||||
#define TARGET_NR_setgroups32 206
|
||||
#define TARGET_NR_fchown32 207
|
||||
#define TARGET_NR_setresuid32 208
|
||||
#define TARGET_NR_getresuid32 209
|
||||
#define TARGET_NR_setresgid32 210
|
||||
#define TARGET_NR_getresgid32 211
|
||||
#define TARGET_NR_chown32 212
|
||||
#define TARGET_NR_setuid32 213
|
||||
#define TARGET_NR_setgid32 214
|
||||
#define TARGET_NR_setfsuid32 215
|
||||
#define TARGET_NR_setfsgid32 216
|
||||
#define TARGET_NR_pivot_root 217
|
||||
#define TARGET_NR_mincore 218
|
||||
#define TARGET_NR_madvise 219
|
||||
#define TARGET_NR_madvise1 219 /* delete when C lib stub is removed */
|
||||
#define TARGET_NR_getdents64 220
|
||||
#define TARGET_NR_fcntl64 221
|
||||
/* 223 is unused */
|
||||
#define TARGET_NR_gettid 224
|
||||
#define TARGET_NR_readahead 225
|
||||
#define TARGET_NR_setxattr 226
|
||||
#define TARGET_NR_lsetxattr 227
|
||||
#define TARGET_NR_fsetxattr 228
|
||||
#define TARGET_NR_getxattr 229
|
||||
#define TARGET_NR_lgetxattr 230
|
||||
#define TARGET_NR_fgetxattr 231
|
||||
#define TARGET_NR_listxattr 232
|
||||
#define TARGET_NR_llistxattr 233
|
||||
#define TARGET_NR_flistxattr 234
|
||||
#define TARGET_NR_removexattr 235
|
||||
#define TARGET_NR_lremovexattr 236
|
||||
#define TARGET_NR_fremovexattr 237
|
||||
#define TARGET_NR_tkill 238
|
||||
#define TARGET_NR_sendfile64 239
|
||||
#define TARGET_NR_futex 240
|
||||
#define TARGET_NR_sched_setaffinity 241
|
||||
#define TARGET_NR_sched_getaffinity 242
|
||||
#define TARGET_NR_set_thread_area 243
|
||||
#define TARGET_NR_get_thread_area 244
|
||||
#define TARGET_NR_io_setup 245
|
||||
#define TARGET_NR_io_destroy 246
|
||||
#define TARGET_NR_io_getevents 247
|
||||
#define TARGET_NR_io_submit 248
|
||||
#define TARGET_NR_io_cancel 249
|
||||
#define TARGET_NR_fadvise64 250
|
||||
|
||||
#define TARGET_NR_exit_group 252
|
||||
#define TARGET_NR_lookup_dcookie 253
|
||||
#define TARGET_NR_epoll_create 254
|
||||
#define TARGET_NR_epoll_ctl 255
|
||||
#define TARGET_NR_epoll_wait 256
|
||||
#define TARGET_NR_remap_file_pages 257
|
||||
#define TARGET_NR_set_tid_address 258
|
||||
#define TARGET_NR_timer_create 259
|
||||
#define TARGET_NR_timer_settime (TARGET_NR_timer_create+1)
|
||||
#define TARGET_NR_timer_gettime (TARGET_NR_timer_create+2)
|
||||
#define TARGET_NR_timer_getoverrun (TARGET_NR_timer_create+3)
|
||||
#define TARGET_NR_timer_delete (TARGET_NR_timer_create+4)
|
||||
#define TARGET_NR_clock_settime (TARGET_NR_timer_create+5)
|
||||
#define TARGET_NR_clock_gettime (TARGET_NR_timer_create+6)
|
||||
#define TARGET_NR_clock_getres (TARGET_NR_timer_create+7)
|
||||
#define TARGET_NR_clock_nanosleep (TARGET_NR_timer_create+8)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user