Compare commits
588
Commits
v0.5.0
...
release_0_6_0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ea4b3c0748 | ||
|
|
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 |
No files matched your search
+15
@@ -0,0 +1,15 @@
|
|||||||
|
arm-user
|
||||||
|
config-host.*
|
||||||
|
dyngen
|
||||||
|
i386
|
||||||
|
i386-softmmu
|
||||||
|
i386-user
|
||||||
|
ppc-softmmu
|
||||||
|
ppc-user
|
||||||
|
qemu-doc.html
|
||||||
|
qemu-mkcow
|
||||||
|
qemu-tech.html
|
||||||
|
qemu.1
|
||||||
|
qemu.pod
|
||||||
|
sparc-user
|
||||||
|
vmdk2raw
|
||||||
@@ -1,3 +1,120 @@
|
|||||||
|
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:
|
version 0.5.0:
|
||||||
|
|
||||||
- full hardware level VGA emulation
|
- full hardware level VGA emulation
|
||||||
@@ -18,7 +135,7 @@ version 0.5.0:
|
|||||||
- automatic IDE geometry detection
|
- automatic IDE geometry detection
|
||||||
- renamed 'vl' to qemu[-fast] and user qemu to qemu-{cpu}.
|
- renamed 'vl' to qemu[-fast] and user qemu to qemu-{cpu}.
|
||||||
- added man page
|
- added man page
|
||||||
- added full soft mmy mode to launch unpatched OSes.
|
- added full soft mmu mode to launch unpatched OSes.
|
||||||
|
|
||||||
version 0.4.3:
|
version 0.4.3:
|
||||||
|
|
||||||
|
|||||||
@@ -1,59 +1,80 @@
|
|||||||
include config-host.mak
|
include config-host.mak
|
||||||
|
|
||||||
CFLAGS=-Wall -O2 -g
|
CFLAGS=-Wall -O2 -g
|
||||||
|
ifdef CONFIG_DARWIN
|
||||||
|
CFLAGS+= -mdynamic-no-pic
|
||||||
|
endif
|
||||||
|
ifdef CONFIG_WIN32
|
||||||
|
CFLAGS+=-fpack-struct
|
||||||
|
endif
|
||||||
LDFLAGS=-g
|
LDFLAGS=-g
|
||||||
LIBS=
|
LIBS=
|
||||||
DEFINES+=-D_GNU_SOURCE
|
DEFINES+=-D_GNU_SOURCE
|
||||||
TOOLS=qemu-mkcow
|
ifndef CONFIG_WIN32
|
||||||
|
TOOLS=qemu-mkcow vmdk2raw
|
||||||
|
endif
|
||||||
|
ifdef CONFIG_STATIC
|
||||||
|
LDFLAGS+=-static
|
||||||
|
endif
|
||||||
|
|
||||||
all: dyngen $(TOOLS) qemu-doc.html qemu.1
|
all: dyngen$(EXESUF) $(TOOLS) qemu-doc.html qemu-tech.html qemu.1
|
||||||
for d in $(TARGET_DIRS); do \
|
for d in $(TARGET_DIRS); do \
|
||||||
make -C $$d $@ || exit 1 ; \
|
$(MAKE) -C $$d $@ || exit 1 ; \
|
||||||
done
|
done
|
||||||
|
|
||||||
qemu-mkcow: qemu-mkcow.o
|
qemu-mkcow: qemu-mkcow.c
|
||||||
$(HOST_CC) -o $@ $^ $(LIBS)
|
$(CC) $(CFLAGS) $(LDFLAGS) $(DEFINES) -o $@ $^ $(LIBS)
|
||||||
|
|
||||||
dyngen: dyngen.o
|
vmdk2raw: vmdk2raw.c
|
||||||
$(HOST_CC) -o $@ $^ $(LIBS)
|
$(CC) $(CFLAGS) $(LDFLAGS) $(DEFINES) -o $@ $^ $(LIBS)
|
||||||
|
|
||||||
%.o: %.c
|
dyngen$(EXESUF): dyngen.c
|
||||||
$(HOST_CC) $(CFLAGS) $(DEFINES) -c -o $@ $<
|
$(HOST_CC) $(CFLAGS) $(DEFINES) -o $@ $^
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
# avoid old build problems by removing potentially incorrect old files
|
# 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 config.mak config.h op-i386.h opc-i386.h gen-op-i386.h op-arm.h opc-arm.h gen-op-arm.h
|
||||||
rm -f *.o *.a $(TOOLS) dyngen TAGS qemu.pod
|
rm -f *.o *.a $(TOOLS) dyngen$(EXESUF) TAGS qemu.pod
|
||||||
|
$(MAKE) -C tests clean
|
||||||
for d in $(TARGET_DIRS); do \
|
for d in $(TARGET_DIRS); do \
|
||||||
make -C $$d $@ || exit 1 ; \
|
$(MAKE) -C $$d $@ || exit 1 ; \
|
||||||
done
|
done
|
||||||
|
|
||||||
distclean: clean
|
distclean: clean
|
||||||
rm -f config-host.mak config-host.h
|
rm -f config-host.mak config-host.h
|
||||||
for d in $(TARGET_DIRS); do \
|
for d in $(TARGET_DIRS); do \
|
||||||
rm -f $$d/config.h $$d/config.mak || exit 1 ; \
|
rm -rf $$d || exit 1 ; \
|
||||||
done
|
done
|
||||||
|
|
||||||
install: all
|
install: all
|
||||||
mkdir -p $(prefix)/bin
|
mkdir -p "$(bindir)"
|
||||||
install -m 755 -s $(TOOLS) $(prefix)/bin
|
ifndef CONFIG_WIN32
|
||||||
mkdir -p $(sharedir)
|
install -m 755 -s $(TOOLS) "$(bindir)"
|
||||||
install -m 644 pc-bios/bios.bin pc-bios/vgabios.bin $(sharedir)
|
endif
|
||||||
mkdir -p $(mandir)/man1
|
mkdir -p "$(datadir)"
|
||||||
install qemu.1 $(mandir)/man1
|
install -m 644 pc-bios/bios.bin pc-bios/vgabios.bin \
|
||||||
|
pc-bios/vgabios-cirrus.bin \
|
||||||
|
pc-bios/ppc_rom.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 \
|
for d in $(TARGET_DIRS); do \
|
||||||
make -C $$d $@ || exit 1 ; \
|
$(MAKE) -C $$d $@ || exit 1 ; \
|
||||||
done
|
done
|
||||||
|
|
||||||
# various test targets
|
# various test targets
|
||||||
test speed: all
|
test speed test2: all
|
||||||
make -C tests $@
|
$(MAKE) -C tests $@
|
||||||
|
|
||||||
TAGS:
|
TAGS:
|
||||||
etags *.[ch] tests/*.[ch]
|
etags *.[ch] tests/*.[ch]
|
||||||
|
|
||||||
# documentation
|
# documentation
|
||||||
qemu-doc.html: qemu-doc.texi
|
%.html: %.texi
|
||||||
texi2html -monolithic -number $<
|
texi2html -monolithic -number $<
|
||||||
|
|
||||||
qemu.1: qemu-doc.texi
|
qemu.1: qemu-doc.texi
|
||||||
@@ -66,17 +87,27 @@ FILE=qemu-$(shell cat VERSION)
|
|||||||
tar:
|
tar:
|
||||||
rm -rf /tmp/$(FILE)
|
rm -rf /tmp/$(FILE)
|
||||||
cp -r . /tmp/$(FILE)
|
cp -r . /tmp/$(FILE)
|
||||||
( cd /tmp ; tar zcvf ~/$(FILE).tar.gz $(FILE) )
|
( cd /tmp ; tar zcvf ~/$(FILE).tar.gz $(FILE) --exclude CVS )
|
||||||
rm -rf /tmp/$(FILE)
|
rm -rf /tmp/$(FILE)
|
||||||
|
|
||||||
# generate a binary distribution including the test binary environnment
|
# generate a binary distribution
|
||||||
BINPATH=/usr/local/qemu-i386
|
|
||||||
|
|
||||||
tarbin:
|
tarbin:
|
||||||
tar zcvf /tmp/qemu-$(VERSION)-i386-glibc21.tar.gz \
|
( cd / ; tar zcvf ~/qemu-$(VERSION)-i386.tar.gz \
|
||||||
$(BINPATH)/etc $(BINPATH)/lib $(BINPATH)/bin $(BINPATH)/usr
|
$(bindir)/qemu $(bindir)/qemu-fast \
|
||||||
tar zcvf /tmp/qemu-$(VERSION)-i386-wine.tar.gz \
|
$(bindir)/qemu-system-ppc \
|
||||||
$(BINPATH)/wine
|
$(bindir)/qemu-i386 \
|
||||||
|
$(bindir)/qemu-arm \
|
||||||
|
$(bindir)/qemu-sparc \
|
||||||
|
$(bindir)/qemu-ppc \
|
||||||
|
$(bindir)/qemu-mkcow $(bindir)/vmdk2raw \
|
||||||
|
$(datadir)/bios.bin \
|
||||||
|
$(datadir)/vgabios.bin \
|
||||||
|
$(datadir)/vgabios-cirrus.bin \
|
||||||
|
$(datadir)/ppc_rom.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),)
|
ifneq ($(wildcard .depend),)
|
||||||
include .depend
|
include .depend
|
||||||
|
|||||||
+134
-13
@@ -1,18 +1,26 @@
|
|||||||
include config.mak
|
include config.mak
|
||||||
|
|
||||||
TARGET_PATH=$(SRC_PATH)/target-$(TARGET_ARCH)
|
TARGET_PATH=$(SRC_PATH)/target-$(TARGET_ARCH)
|
||||||
VPATH=$(SRC_PATH):$(TARGET_PATH)
|
VPATH=$(SRC_PATH):$(TARGET_PATH):$(SRC_PATH)/hw
|
||||||
CFLAGS=-Wall -O2 -g
|
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
|
LDFLAGS=-g
|
||||||
LIBS=
|
LIBS=
|
||||||
DEFINES=-I. -I$(TARGET_PATH) -I$(SRC_PATH)
|
|
||||||
HELPER_CFLAGS=$(CFLAGS)
|
HELPER_CFLAGS=$(CFLAGS)
|
||||||
DYNGEN=../dyngen
|
DYNGEN=../dyngen$(EXESUF)
|
||||||
# user emulator name
|
# user emulator name
|
||||||
QEMU_USER=qemu-$(TARGET_ARCH)
|
QEMU_USER=qemu-$(TARGET_ARCH)
|
||||||
# system emulator name
|
# system emulator name
|
||||||
ifdef CONFIG_SOFTMMU
|
ifdef CONFIG_SOFTMMU
|
||||||
QEMU_SYSTEM=qemu
|
ifeq ($(TARGET_ARCH), i386)
|
||||||
|
QEMU_SYSTEM=qemu$(EXESUF)
|
||||||
|
else
|
||||||
|
QEMU_SYSTEM=qemu-system-$(TARGET_ARCH)$(EXESUF)
|
||||||
|
endif
|
||||||
else
|
else
|
||||||
QEMU_SYSTEM=qemu-fast
|
QEMU_SYSTEM=qemu-fast
|
||||||
endif
|
endif
|
||||||
@@ -20,12 +28,42 @@ endif
|
|||||||
ifdef CONFIG_USER_ONLY
|
ifdef CONFIG_USER_ONLY
|
||||||
PROGS=$(QEMU_USER)
|
PROGS=$(QEMU_USER)
|
||||||
else
|
else
|
||||||
ifeq ($(ARCH),i386)
|
|
||||||
ifeq ($(TARGET_ARCH), i386)
|
ifeq ($(TARGET_ARCH), i386)
|
||||||
|
|
||||||
|
ifeq ($(ARCH), i386)
|
||||||
|
PROGS+=$(QEMU_SYSTEM)
|
||||||
|
ifndef CONFIG_SOFTMMU
|
||||||
|
CONFIG_STATIC=y
|
||||||
|
endif
|
||||||
|
else
|
||||||
|
# the system emulator using soft mmu is portable
|
||||||
|
ifdef CONFIG_SOFTMMU
|
||||||
PROGS+=$(QEMU_SYSTEM)
|
PROGS+=$(QEMU_SYSTEM)
|
||||||
endif
|
endif
|
||||||
|
endif # ARCH != i386
|
||||||
|
|
||||||
|
endif # TARGET_ARCH = i386
|
||||||
|
|
||||||
|
ifeq ($(TARGET_ARCH), ppc)
|
||||||
|
|
||||||
|
ifeq ($(ARCH), ppc)
|
||||||
|
PROGS+=$(QEMU_SYSTEM)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifeq ($(ARCH), i386)
|
||||||
|
ifdef CONFIG_SOFTMMU
|
||||||
|
PROGS+=$(QEMU_SYSTEM)
|
||||||
endif
|
endif
|
||||||
|
endif # ARCH = i386
|
||||||
|
|
||||||
|
ifeq ($(ARCH), amd64)
|
||||||
|
ifdef CONFIG_SOFTMMU
|
||||||
|
PROGS+=$(QEMU_SYSTEM)
|
||||||
|
endif
|
||||||
|
endif # ARCH = amd64
|
||||||
|
|
||||||
|
endif # TARGET_ARCH = ppc
|
||||||
|
endif # !CONFIG_USER_ONLY
|
||||||
|
|
||||||
ifdef CONFIG_STATIC
|
ifdef CONFIG_STATIC
|
||||||
LDFLAGS+=-static
|
LDFLAGS+=-static
|
||||||
@@ -39,7 +77,14 @@ OP_CFLAGS+= -falign-functions=0
|
|||||||
else
|
else
|
||||||
OP_CFLAGS+= -malign-functions=0
|
OP_CFLAGS+= -malign-functions=0
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifdef TARGET_GPROF
|
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
|
LDFLAGS+=-Wl,-T,$(SRC_PATH)/i386.ld
|
||||||
else
|
else
|
||||||
# WARNING: this LDFLAGS is _very_ tricky : qemu is an ELF shared object
|
# WARNING: this LDFLAGS is _very_ tricky : qemu is an ELF shared object
|
||||||
@@ -49,7 +94,13 @@ LDFLAGS+=-Wl,-shared
|
|||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifeq ($(ARCH),amd64)
|
||||||
|
OP_CFLAGS=$(CFLAGS) -falign-functions=0
|
||||||
|
LDFLAGS+=-Wl,-T,$(SRC_PATH)/amd64.ld
|
||||||
|
endif
|
||||||
|
|
||||||
ifeq ($(ARCH),ppc)
|
ifeq ($(ARCH),ppc)
|
||||||
|
CFLAGS+= -D__powerpc__
|
||||||
OP_CFLAGS=$(CFLAGS)
|
OP_CFLAGS=$(CFLAGS)
|
||||||
LDFLAGS+=-Wl,-T,$(SRC_PATH)/ppc.ld
|
LDFLAGS+=-Wl,-T,$(SRC_PATH)/ppc.ld
|
||||||
endif
|
endif
|
||||||
@@ -102,10 +153,17 @@ ifeq ($(HAVE_GCC3_OPTIONS),yes)
|
|||||||
OP_CFLAGS+=-fno-reorder-blocks -fno-optimize-sibling-calls
|
OP_CFLAGS+=-fno-reorder-blocks -fno-optimize-sibling-calls
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifeq ($(CONFIG_DARWIN),yes)
|
||||||
|
OP_CFLAGS+= -mdynamic-no-pic
|
||||||
|
endif
|
||||||
|
|
||||||
#########################################################
|
#########################################################
|
||||||
|
|
||||||
DEFINES+=-D_GNU_SOURCE
|
DEFINES+=-D_GNU_SOURCE
|
||||||
LIBS+=-lm
|
LIBS+=-lm
|
||||||
|
ifdef CONFIG_WIN32
|
||||||
|
LIBS+=-lwinmm
|
||||||
|
endif
|
||||||
|
|
||||||
# profiling code
|
# profiling code
|
||||||
ifdef TARGET_GPROF
|
ifdef TARGET_GPROF
|
||||||
@@ -113,24 +171,42 @@ LDFLAGS+=-p
|
|||||||
main.o: CFLAGS+=-p
|
main.o: CFLAGS+=-p
|
||||||
endif
|
endif
|
||||||
|
|
||||||
OBJS= elfload.o main.o syscall.o mmap.o signal.o path.o
|
OBJS= elfload.o main.o syscall.o mmap.o signal.o path.o osdep.o thunk.o
|
||||||
ifeq ($(TARGET_ARCH), i386)
|
ifeq ($(TARGET_ARCH), i386)
|
||||||
OBJS+= vm86.o
|
OBJS+= vm86.o
|
||||||
endif
|
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)
|
SRCS:= $(OBJS:.o=.c)
|
||||||
OBJS+= libqemu.a
|
OBJS+= libqemu.a
|
||||||
|
|
||||||
# cpu emulator library
|
# cpu emulator library
|
||||||
LIBOBJS=thunk.o exec.o translate-all.o cpu-exec.o gdbstub.o \
|
LIBOBJS=exec.o translate-all.o cpu-exec.o\
|
||||||
translate.o op.o
|
translate.o op.o
|
||||||
|
|
||||||
ifeq ($(TARGET_ARCH), i386)
|
ifeq ($(TARGET_ARCH), i386)
|
||||||
LIBOBJS+=helper.o helper2.o
|
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
|
endif
|
||||||
|
|
||||||
# NOTE: the disassembler code is only needed for debugging
|
# NOTE: the disassembler code is only needed for debugging
|
||||||
LIBOBJS+=disas.o
|
LIBOBJS+=disas.o
|
||||||
ifeq ($(findstring i386, $(TARGET_ARCH) $(ARCH)),i386)
|
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
|
LIBOBJS+=i386-dis.o
|
||||||
endif
|
endif
|
||||||
ifeq ($(findstring alpha, $(TARGET_ARCH) $(ARCH)),alpha)
|
ifeq ($(findstring alpha, $(TARGET_ARCH) $(ARCH)),alpha)
|
||||||
@@ -161,14 +237,49 @@ ifeq ($(ARCH),alpha)
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
# must use static linking to avoid leaving stuff in virtual address space
|
# must use static linking to avoid leaving stuff in virtual address space
|
||||||
VL_OBJS=vl.o block.o vga.o
|
VL_OBJS=vl.o osdep.o block.o monitor.o pci.o
|
||||||
|
|
||||||
|
ifeq ($(TARGET_ARCH), i386)
|
||||||
|
# Hardware support
|
||||||
|
VL_OBJS+= ide.o ne2000.o pckbd.o vga.o sb16.o dma.o oss.o
|
||||||
|
VL_OBJS+= fdc.o mc146818rtc.o serial.o i8259.o i8254.o pc.o
|
||||||
|
VL_OBJS+= cirrus_vga.o
|
||||||
|
endif
|
||||||
|
ifeq ($(TARGET_ARCH), ppc)
|
||||||
|
VL_OBJS+= ppc.o ide.o ne2000.o pckbd.o vga.o sb16.o dma.o oss.o
|
||||||
|
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
|
||||||
|
endif
|
||||||
|
ifdef CONFIG_GDBSTUB
|
||||||
|
VL_OBJS+=gdbstub.o
|
||||||
|
endif
|
||||||
ifdef CONFIG_SDL
|
ifdef CONFIG_SDL
|
||||||
VL_OBJS+=sdl.o
|
VL_OBJS+=sdl.o
|
||||||
SDL_LIBS+=-L/usr/X11R6/lib -lX11 -lXext -lXv -ldl -lm
|
endif
|
||||||
|
ifdef CONFIG_SLIRP
|
||||||
|
DEFINES+=-I$(SRC_PATH)/slirp
|
||||||
|
SLIRP_OBJS=cksum.o if.o ip_icmp.o ip_input.o ip_output.o \
|
||||||
|
slirp.o mbuf.o misc.o sbuf.o socket.o tcp_input.o tcp_output.o \
|
||||||
|
tcp_subr.o tcp_timer.o udp.o bootp.o debug.o
|
||||||
|
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
|
endif
|
||||||
|
|
||||||
$(QEMU_SYSTEM): $(VL_OBJS) libqemu.a
|
$(QEMU_SYSTEM): $(VL_OBJS) libqemu.a
|
||||||
$(CC) -static -Wl,-T,$(SRC_PATH)/i386-vl.ld -o $@ $^ $(LIBS) $(SDL_LIBS)
|
$(CC) $(VL_LDFLAGS) -o $@ $^ $(LIBS) $(SDL_LIBS) $(VL_LIBS)
|
||||||
|
|
||||||
sdl.o: sdl.c
|
sdl.o: sdl.c
|
||||||
$(CC) $(CFLAGS) $(DEFINES) $(SDL_CFLAGS) -c -o $@ $<
|
$(CC) $(CFLAGS) $(DEFINES) $(SDL_CFLAGS) -c -o $@ $<
|
||||||
@@ -213,14 +324,24 @@ ifeq ($(TARGET_ARCH), sparc)
|
|||||||
op.o: op.c op_template.h
|
op.o: op.c op_template.h
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifeq ($(TARGET_ARCH), ppc)
|
||||||
|
op.o: op.c op_template.h op_mem.h
|
||||||
|
op_helper.o: op_helper_mem.h
|
||||||
|
endif
|
||||||
|
|
||||||
%.o: %.c
|
%.o: %.c
|
||||||
$(CC) $(CFLAGS) $(DEFINES) -c -o $@ $<
|
$(CC) $(CFLAGS) $(DEFINES) -c -o $@ $<
|
||||||
|
|
||||||
|
%.o: %.S
|
||||||
|
$(CC) $(DEFINES) -c -o $@ $<
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f *.o *.a *~ $(PROGS) gen-op.h opc.h op.h
|
rm -f *.o *.a *~ $(PROGS) gen-op.h opc.h op.h nwfpe/*.o slirp/*.o
|
||||||
|
|
||||||
install: all
|
install: all
|
||||||
install -m 755 -s $(PROGS) $(prefix)/bin
|
ifneq ($(PROGS),)
|
||||||
|
install -m 755 -s $(PROGS) "$(bindir)"
|
||||||
|
endif
|
||||||
|
|
||||||
ifneq ($(wildcard .depend),)
|
ifneq ($(wildcard .depend),)
|
||||||
include .depend
|
include .depend
|
||||||
|
|||||||
@@ -1,20 +1,35 @@
|
|||||||
|
short term:
|
||||||
|
----------
|
||||||
|
- 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
|
||||||
|
- handle fast timers + add explicit clocks
|
||||||
|
- cycle counter for all archs
|
||||||
|
- TLB code protection support for PPC
|
||||||
|
- add sysenter/sysexit and fxsr for L4 pistachio 686
|
||||||
|
- basic VGA optimizations
|
||||||
|
- 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
|
- tests for each target CPU
|
||||||
- ppc qemu test
|
|
||||||
- optimize FPU operations (evaluate x87 stack pointer statically) and
|
|
||||||
fix cr0.TS emulation
|
|
||||||
- fix some 16 bit sp push/pop overflow
|
|
||||||
- sysenter/sysexit emulation
|
|
||||||
- finish segment ops (call far, ret far, load_seg suppressed)
|
|
||||||
- fix CCOP optimisation
|
- fix CCOP optimisation
|
||||||
- fix all remaining thread lock issues (must put TBs in a specific invalid
|
- fix all remaining thread lock issues (must put TBs in a specific invalid
|
||||||
state, find a solution for tb_flush()).
|
state, find a solution for tb_flush()).
|
||||||
- cpu loop optimisation (optimise ret case as the cpu state does not change)
|
|
||||||
- fix arm fpu rounding (at least for float->integer conversions)
|
- fix arm fpu rounding (at least for float->integer conversions)
|
||||||
|
- SMP support
|
||||||
|
|
||||||
lower priority:
|
lower priority:
|
||||||
--------------
|
--------------
|
||||||
|
- 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
|
- add IPC syscalls
|
||||||
- SMP support
|
|
||||||
- use -msoft-float on ARM
|
- use -msoft-float on ARM
|
||||||
- use kernel traps for unaligned accesses on ARM ?
|
- use kernel traps for unaligned accesses on ARM ?
|
||||||
- handle rare page fault cases (in particular if page fault in heplers or
|
- handle rare page fault cases (in particular if page fault in heplers or
|
||||||
|
|||||||
@@ -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,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) }
|
||||||
|
}
|
||||||
@@ -21,66 +21,92 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <getopt.h>
|
|
||||||
#include <inttypes.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <sys/mman.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <signal.h>
|
|
||||||
#include <time.h>
|
|
||||||
#include <sys/time.h>
|
|
||||||
#include <malloc.h>
|
|
||||||
#include <termios.h>
|
|
||||||
#include <sys/poll.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <sys/wait.h>
|
|
||||||
#include <netinet/in.h>
|
|
||||||
|
|
||||||
#include "vl.h"
|
#include "vl.h"
|
||||||
|
|
||||||
#define NO_THUNK_TYPE_SIZE
|
#ifndef _WIN32
|
||||||
#include "thunk.h"
|
#include <sys/mman.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "cow.h"
|
||||||
|
|
||||||
struct BlockDriverState {
|
struct BlockDriverState {
|
||||||
int fd; /* if -1, only COW mappings */
|
int fd; /* if -1, only COW mappings */
|
||||||
int64_t total_sectors;
|
int64_t total_sectors;
|
||||||
int read_only;
|
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 */
|
||||||
|
/* event callback when inserting/removing */
|
||||||
|
void (*change_cb)(void *opaque);
|
||||||
|
void *change_opaque;
|
||||||
|
|
||||||
uint8_t *cow_bitmap; /* if non NULL, COW mappings are used first */
|
uint8_t *cow_bitmap; /* if non NULL, COW mappings are used first */
|
||||||
uint8_t *cow_bitmap_addr; /* mmap address of cow_bitmap */
|
uint8_t *cow_bitmap_addr; /* mmap address of cow_bitmap */
|
||||||
int cow_bitmap_size;
|
int cow_bitmap_size;
|
||||||
int cow_fd;
|
int cow_fd;
|
||||||
int64_t cow_sectors_offset;
|
int64_t cow_sectors_offset;
|
||||||
|
int boot_sector_enabled;
|
||||||
|
uint8_t boot_sector_data[512];
|
||||||
|
|
||||||
char filename[1024];
|
char filename[1024];
|
||||||
|
|
||||||
|
/* 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;
|
||||||
};
|
};
|
||||||
|
|
||||||
BlockDriverState *bdrv_open(const char *filename, int snapshot)
|
static BlockDriverState *bdrv_first;
|
||||||
{
|
|
||||||
BlockDriverState *bs;
|
|
||||||
int fd, cow_fd;
|
|
||||||
int64_t size;
|
|
||||||
char template[] = "/tmp/vl.XXXXXX";
|
|
||||||
struct cow_header_v2 cow_header;
|
|
||||||
struct stat st;
|
|
||||||
|
|
||||||
bs = malloc(sizeof(BlockDriverState));
|
/* 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)
|
if(!bs)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
pstrcpy(bs->device_name, sizeof(bs->device_name), device_name);
|
||||||
|
/* insert at the end */
|
||||||
|
pbs = &bdrv_first;
|
||||||
|
while (*pbs != NULL)
|
||||||
|
pbs = &(*pbs)->next;
|
||||||
|
*pbs = bs;
|
||||||
|
return bs;
|
||||||
|
}
|
||||||
|
|
||||||
|
int bdrv_open(BlockDriverState *bs, const char *filename, int snapshot)
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
int64_t size;
|
||||||
|
struct cow_header_v2 cow_header;
|
||||||
|
#ifndef _WIN32
|
||||||
|
char template[] = "/tmp/vl.XXXXXX";
|
||||||
|
int cow_fd;
|
||||||
|
struct stat st;
|
||||||
|
#endif
|
||||||
|
|
||||||
bs->read_only = 0;
|
bs->read_only = 0;
|
||||||
bs->fd = -1;
|
bs->fd = -1;
|
||||||
bs->cow_fd = -1;
|
bs->cow_fd = -1;
|
||||||
bs->cow_bitmap = NULL;
|
bs->cow_bitmap = NULL;
|
||||||
strcpy(bs->filename, filename);
|
pstrcpy(bs->filename, sizeof(bs->filename), filename);
|
||||||
|
|
||||||
/* open standard HD image */
|
/* open standard HD image */
|
||||||
|
#ifdef _WIN32
|
||||||
|
fd = open(filename, O_RDWR | O_BINARY);
|
||||||
|
#else
|
||||||
fd = open(filename, O_RDWR | O_LARGEFILE);
|
fd = open(filename, O_RDWR | O_LARGEFILE);
|
||||||
|
#endif
|
||||||
if (fd < 0) {
|
if (fd < 0) {
|
||||||
/* read only image on disk */
|
/* read only image on disk */
|
||||||
|
#ifdef _WIN32
|
||||||
|
fd = open(filename, O_RDONLY | O_BINARY);
|
||||||
|
#else
|
||||||
fd = open(filename, O_RDONLY | O_LARGEFILE);
|
fd = open(filename, O_RDONLY | O_LARGEFILE);
|
||||||
|
#endif
|
||||||
if (fd < 0) {
|
if (fd < 0) {
|
||||||
perror(filename);
|
perror(filename);
|
||||||
goto fail;
|
goto fail;
|
||||||
@@ -95,8 +121,9 @@ BlockDriverState *bdrv_open(const char *filename, int snapshot)
|
|||||||
fprintf(stderr, "%s: could not read header\n", filename);
|
fprintf(stderr, "%s: could not read header\n", filename);
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
if (cow_header.magic == htonl(COW_MAGIC) &&
|
#ifndef _WIN32
|
||||||
cow_header.version == htonl(COW_VERSION)) {
|
if (be32_to_cpu(cow_header.magic) == COW_MAGIC &&
|
||||||
|
be32_to_cpu(cow_header.version) == COW_VERSION) {
|
||||||
/* cow image found */
|
/* cow image found */
|
||||||
size = cow_header.size;
|
size = cow_header.size;
|
||||||
#ifndef WORDS_BIGENDIAN
|
#ifndef WORDS_BIGENDIAN
|
||||||
@@ -111,7 +138,7 @@ BlockDriverState *bdrv_open(const char *filename, int snapshot)
|
|||||||
fprintf(stderr, "%s: could not find original disk image '%s'\n", filename, cow_header.backing_file);
|
fprintf(stderr, "%s: could not find original disk image '%s'\n", filename, cow_header.backing_file);
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
if (st.st_mtime != htonl(cow_header.mtime)) {
|
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);
|
fprintf(stderr, "%s: original raw disk image '%s' does not match saved timestamp\n", filename, cow_header.backing_file);
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
@@ -131,16 +158,19 @@ BlockDriverState *bdrv_open(const char *filename, int snapshot)
|
|||||||
bs->cow_bitmap = bs->cow_bitmap_addr + sizeof(cow_header);
|
bs->cow_bitmap = bs->cow_bitmap_addr + sizeof(cow_header);
|
||||||
bs->cow_sectors_offset = (bs->cow_bitmap_size + 511) & ~511;
|
bs->cow_sectors_offset = (bs->cow_bitmap_size + 511) & ~511;
|
||||||
snapshot = 0;
|
snapshot = 0;
|
||||||
} else {
|
} else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
/* standard raw image */
|
/* standard raw image */
|
||||||
size = lseek64(fd, 0, SEEK_END);
|
size = lseek64(fd, 0, SEEK_END);
|
||||||
bs->total_sectors = size / 512;
|
bs->total_sectors = size / 512;
|
||||||
bs->fd = fd;
|
bs->fd = fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef _WIN32
|
||||||
if (snapshot) {
|
if (snapshot) {
|
||||||
/* create a temporary COW file */
|
/* create a temporary COW file */
|
||||||
cow_fd = mkstemp(template);
|
cow_fd = mkstemp64(template);
|
||||||
if (cow_fd < 0)
|
if (cow_fd < 0)
|
||||||
goto fail;
|
goto fail;
|
||||||
bs->cow_fd = cow_fd;
|
bs->cow_fd = cow_fd;
|
||||||
@@ -157,23 +187,44 @@ BlockDriverState *bdrv_open(const char *filename, int snapshot)
|
|||||||
bs->cow_bitmap = bs->cow_bitmap_addr;
|
bs->cow_bitmap = bs->cow_bitmap_addr;
|
||||||
bs->cow_sectors_offset = 0;
|
bs->cow_sectors_offset = 0;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
return bs;
|
bs->inserted = 1;
|
||||||
|
|
||||||
|
/* call the change callback */
|
||||||
|
if (bs->change_cb)
|
||||||
|
bs->change_cb(bs->change_opaque);
|
||||||
|
|
||||||
|
return 0;
|
||||||
fail:
|
fail:
|
||||||
bdrv_close(bs);
|
bdrv_close(bs);
|
||||||
return NULL;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void bdrv_close(BlockDriverState *bs)
|
void bdrv_close(BlockDriverState *bs)
|
||||||
{
|
{
|
||||||
/* we unmap the mapping so that it is written to the COW file */
|
if (bs->inserted) {
|
||||||
if (bs->cow_bitmap_addr)
|
#ifndef _WIN32
|
||||||
munmap(bs->cow_bitmap_addr, bs->cow_bitmap_size);
|
/* we unmap the mapping so that it is written to the COW file */
|
||||||
if (bs->cow_fd >= 0)
|
if (bs->cow_bitmap_addr)
|
||||||
close(bs->cow_fd);
|
munmap(bs->cow_bitmap_addr, bs->cow_bitmap_size);
|
||||||
if (bs->fd >= 0)
|
#endif
|
||||||
close(bs->fd);
|
if (bs->cow_fd >= 0)
|
||||||
free(bs);
|
close(bs->cow_fd);
|
||||||
|
if (bs->fd >= 0)
|
||||||
|
close(bs->fd);
|
||||||
|
bs->inserted = 0;
|
||||||
|
|
||||||
|
/* call the change callback */
|
||||||
|
if (bs->change_cb)
|
||||||
|
bs->change_cb(bs->change_opaque);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void bdrv_delete(BlockDriverState *bs)
|
||||||
|
{
|
||||||
|
bdrv_close(bs);
|
||||||
|
qemu_free(bs);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void set_bit(uint8_t *bitmap, int64_t bitnum)
|
static inline void set_bit(uint8_t *bitmap, int64_t bitnum)
|
||||||
@@ -216,6 +267,9 @@ int bdrv_commit(BlockDriverState *bs)
|
|||||||
int64_t i;
|
int64_t i;
|
||||||
uint8_t *cow_bitmap;
|
uint8_t *cow_bitmap;
|
||||||
|
|
||||||
|
if (!bs->inserted)
|
||||||
|
return -1;
|
||||||
|
|
||||||
if (!bs->cow_bitmap) {
|
if (!bs->cow_bitmap) {
|
||||||
fprintf(stderr, "Already committed to %s\n", bs->filename);
|
fprintf(stderr, "Already committed to %s\n", bs->filename);
|
||||||
return 0;
|
return 0;
|
||||||
@@ -258,10 +312,17 @@ int bdrv_read(BlockDriverState *bs, int64_t sector_num,
|
|||||||
int ret, n, fd;
|
int ret, n, fd;
|
||||||
int64_t offset;
|
int64_t offset;
|
||||||
|
|
||||||
|
if (!bs->inserted)
|
||||||
|
return -1;
|
||||||
|
|
||||||
while (nb_sectors > 0) {
|
while (nb_sectors > 0) {
|
||||||
if (is_changed(bs->cow_bitmap, sector_num, nb_sectors, &n)) {
|
if (is_changed(bs->cow_bitmap, sector_num, nb_sectors, &n)) {
|
||||||
fd = bs->cow_fd;
|
fd = bs->cow_fd;
|
||||||
offset = bs->cow_sectors_offset;
|
offset = bs->cow_sectors_offset;
|
||||||
|
} else if (sector_num == 0 && bs->boot_sector_enabled) {
|
||||||
|
memcpy(buf, bs->boot_sector_data, 512);
|
||||||
|
n = 1;
|
||||||
|
goto next;
|
||||||
} else {
|
} else {
|
||||||
fd = bs->fd;
|
fd = bs->fd;
|
||||||
offset = 0;
|
offset = 0;
|
||||||
@@ -278,6 +339,7 @@ int bdrv_read(BlockDriverState *bs, int64_t sector_num,
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
next:
|
||||||
nb_sectors -= n;
|
nb_sectors -= n;
|
||||||
sector_num += n;
|
sector_num += n;
|
||||||
buf += n * 512;
|
buf += n * 512;
|
||||||
@@ -291,7 +353,9 @@ int bdrv_write(BlockDriverState *bs, int64_t sector_num,
|
|||||||
{
|
{
|
||||||
int ret, fd, i;
|
int ret, fd, i;
|
||||||
int64_t offset, retl;
|
int64_t offset, retl;
|
||||||
|
|
||||||
|
if (!bs->inserted)
|
||||||
|
return -1;
|
||||||
if (bs->read_only)
|
if (bs->read_only)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
@@ -324,3 +388,116 @@ void bdrv_get_geometry(BlockDriverState *bs, int64_t *nb_sectors_ptr)
|
|||||||
{
|
{
|
||||||
*nb_sectors_ptr = bs->total_sectors;
|
*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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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_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);
|
||||||
|
term_printf(" ro=%d", bs->read_only);
|
||||||
|
} else {
|
||||||
|
term_printf(" [not inserted]");
|
||||||
|
}
|
||||||
|
term_printf("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -43,14 +43,6 @@
|
|||||||
|
|
||||||
#endif /* !HAVE_BYTESWAP_H */
|
#endif /* !HAVE_BYTESWAP_H */
|
||||||
|
|
||||||
#if defined(__alpha__) || defined (__ia64__)
|
|
||||||
#define HOST_LONG_BITS 64
|
|
||||||
#else
|
|
||||||
#define HOST_LONG_BITS 32
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define HOST_LONG_SIZE (HOST_LONG_BITS / 8)
|
|
||||||
|
|
||||||
static inline uint16_t bswap16(uint16_t x)
|
static inline uint16_t bswap16(uint16_t x)
|
||||||
{
|
{
|
||||||
return bswap_16(x);
|
return bswap_16(x);
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ TMPE="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}"
|
|||||||
TMPS="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}.S"
|
TMPS="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}.S"
|
||||||
|
|
||||||
# default parameters
|
# default parameters
|
||||||
prefix="/usr/local"
|
prefix=""
|
||||||
interp_prefix="/usr/gnemul/qemu-%M"
|
interp_prefix="/usr/gnemul/qemu-%M"
|
||||||
static="no"
|
static="no"
|
||||||
cross_prefix=""
|
cross_prefix=""
|
||||||
@@ -27,7 +27,7 @@ ar="ar"
|
|||||||
make="make"
|
make="make"
|
||||||
strip="strip"
|
strip="strip"
|
||||||
cpu=`uname -m`
|
cpu=`uname -m`
|
||||||
target_list="i386-user i386 i386-softmmu arm-user sparc-user"
|
target_list="i386-user i386 i386-softmmu arm-user sparc-user ppc-user ppc-softmmu"
|
||||||
case "$cpu" in
|
case "$cpu" in
|
||||||
i386|i486|i586|i686|i86pc|BePC)
|
i386|i486|i586|i686|i86pc|BePC)
|
||||||
cpu="i386"
|
cpu="i386"
|
||||||
@@ -59,37 +59,47 @@ case "$cpu" in
|
|||||||
m68k)
|
m68k)
|
||||||
cpu="m68k"
|
cpu="m68k"
|
||||||
;;
|
;;
|
||||||
|
x86_64|amd64)
|
||||||
|
cpu="amd64"
|
||||||
|
;;
|
||||||
*)
|
*)
|
||||||
cpu="unknown"
|
cpu="unknown"
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
gprof="no"
|
gprof="no"
|
||||||
bigendian="no"
|
bigendian="no"
|
||||||
|
mingw32="no"
|
||||||
|
EXESUF=""
|
||||||
|
gdbstub="yes"
|
||||||
|
slirp="yes"
|
||||||
|
|
||||||
# OS specific
|
# OS specific
|
||||||
targetos=`uname -s`
|
targetos=`uname -s`
|
||||||
case $targetos in
|
case $targetos in
|
||||||
|
MINGW32*)
|
||||||
|
mingw32="yes"
|
||||||
|
;;
|
||||||
|
FreeBSD)
|
||||||
|
bsd="yes"
|
||||||
|
;;
|
||||||
|
NetBSD)
|
||||||
|
bsd="yes"
|
||||||
|
;;
|
||||||
|
OpenBSD)
|
||||||
|
bsd="yes"
|
||||||
|
;;
|
||||||
|
Darwin)
|
||||||
|
bsd="yes"
|
||||||
|
darwin="yes"
|
||||||
|
;;
|
||||||
*) ;;
|
*) ;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
##########################################
|
if [ "$bsd" = "yes" ] ; then
|
||||||
# SDL probe
|
if [ ! "$darwin" = "yes" ] ; then
|
||||||
|
make="gmake"
|
||||||
cat > $TMPC << EOF
|
fi
|
||||||
#include <SDL.h>
|
target_list="i386-softmmu ppc-softmmu"
|
||||||
#undef main /* We don't want SDL to override our main() */
|
|
||||||
int main( void ) { return SDL_Init (SDL_INIT_VIDEO); }
|
|
||||||
EOF
|
|
||||||
|
|
||||||
sdl_too_old=no
|
|
||||||
sdl=no
|
|
||||||
if $cc -o $TMPE `sdl-config --cflags` $TMPC `sdl-config --libs` 2> /dev/null ; then
|
|
||||||
_sdlversion=`sdl-config --version | sed 's/[^0-9]//g'`
|
|
||||||
if test "$_sdlversion" -lt 121 ; then
|
|
||||||
sdl_too_old=yes
|
|
||||||
else
|
|
||||||
sdl=yes
|
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# find source path
|
# find source path
|
||||||
@@ -133,6 +143,10 @@ for opt do
|
|||||||
;;
|
;;
|
||||||
--disable-sdl) sdl="no"
|
--disable-sdl) sdl="no"
|
||||||
;;
|
;;
|
||||||
|
--enable-mingw32) mingw32="yes" ; cross_prefix="i386-mingw32-"
|
||||||
|
;;
|
||||||
|
--disable-slirp) slirp="no"
|
||||||
|
;;
|
||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
|
|
||||||
@@ -145,6 +159,13 @@ cc="${cross_prefix}${cc}"
|
|||||||
ar="${cross_prefix}${ar}"
|
ar="${cross_prefix}${ar}"
|
||||||
strip="${cross_prefix}${strip}"
|
strip="${cross_prefix}${strip}"
|
||||||
|
|
||||||
|
if test "$mingw32" = "yes" ; then
|
||||||
|
target_list="i386-softmmu ppc-softmmu"
|
||||||
|
EXESUF=".exe"
|
||||||
|
gdbstub="no"
|
||||||
|
slirp="no"
|
||||||
|
fi
|
||||||
|
|
||||||
if test -z "$cross_prefix" ; then
|
if test -z "$cross_prefix" ; then
|
||||||
|
|
||||||
# ---
|
# ---
|
||||||
@@ -183,6 +204,57 @@ if $cc -fno-reorder-blocks -fno-optimize-sibling-calls -o $TMPO $TMPC 2> /dev/nu
|
|||||||
have_gcc3_options="yes"
|
have_gcc3_options="yes"
|
||||||
fi
|
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
|
if test x"$1" = x"-h" -o x"$1" = x"--help" ; then
|
||||||
cat << EOF
|
cat << EOF
|
||||||
|
|
||||||
@@ -203,18 +275,37 @@ echo " --cross-prefix=PREFIX use PREFIX for compile tools [$cross_prefix]"
|
|||||||
echo " --cc=CC use C compiler CC [$cc]"
|
echo " --cc=CC use C compiler CC [$cc]"
|
||||||
echo " --make=MAKE use specified make [$make]"
|
echo " --make=MAKE use specified make [$make]"
|
||||||
echo " --static enable static build [$static]"
|
echo " --static enable static build [$static]"
|
||||||
|
echo " --enable-mingw32 enable Win32 cross compilation with mingw32"
|
||||||
echo ""
|
echo ""
|
||||||
echo "NOTE: The object files are build at the place where configure is launched"
|
echo "NOTE: The object files are build at the place where configure is launched"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
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"
|
mandir="$prefix/share/man"
|
||||||
sharedir="$prefix/share/qemu"
|
datadir="$prefix/share/qemu"
|
||||||
|
docdir="$prefix/share/doc/qemu"
|
||||||
|
bindir="$prefix/bin"
|
||||||
|
fi
|
||||||
|
|
||||||
echo "Install prefix $prefix"
|
echo "Install prefix $prefix"
|
||||||
|
echo "BIOS directory $datadir"
|
||||||
|
echo "binary directory $bindir"
|
||||||
|
if test "$mingw32" = "no" ; then
|
||||||
echo "Manual directory $mandir"
|
echo "Manual directory $mandir"
|
||||||
echo "BIOS directory $sharedir"
|
|
||||||
echo "ELF interp prefix $interp_prefix"
|
echo "ELF interp prefix $interp_prefix"
|
||||||
|
fi
|
||||||
echo "Source path $source_path"
|
echo "Source path $source_path"
|
||||||
echo "C compiler $cc"
|
echo "C compiler $cc"
|
||||||
echo "make $make"
|
echo "make $make"
|
||||||
@@ -224,22 +315,30 @@ echo "target list $target_list"
|
|||||||
echo "gprof enabled $gprof"
|
echo "gprof enabled $gprof"
|
||||||
echo "static build $static"
|
echo "static build $static"
|
||||||
echo "SDL support $sdl"
|
echo "SDL support $sdl"
|
||||||
|
echo "SDL static link $sdl_static"
|
||||||
|
echo "mingw32 support $mingw32"
|
||||||
|
|
||||||
if test $sdl_too_old = "yes"; then
|
if test $sdl_too_old = "yes"; then
|
||||||
echo "-> Your SDL version is too old - please upgrade to have FFplay/SDL support"
|
echo "-> Your SDL version is too old - please upgrade to have FFplay/SDL support"
|
||||||
fi
|
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_mak="config-host.mak"
|
||||||
config_h="config-host.h"
|
config_h="config-host.h"
|
||||||
|
|
||||||
echo "Creating $config_mak and $config_h"
|
#echo "Creating $config_mak and $config_h"
|
||||||
|
|
||||||
echo "# Automatically generated by configure - do not modify" > $config_mak
|
echo "# Automatically generated by configure - do not modify" > $config_mak
|
||||||
echo "/* Automatically generated by configure - do not modify */" > $config_h
|
echo "/* Automatically generated by configure - do not modify */" > $config_h
|
||||||
|
|
||||||
echo "prefix=$prefix" >> $config_mak
|
echo "prefix=$prefix" >> $config_mak
|
||||||
|
echo "bindir=$bindir" >> $config_mak
|
||||||
echo "mandir=$mandir" >> $config_mak
|
echo "mandir=$mandir" >> $config_mak
|
||||||
echo "sharedir=$sharedir" >> $config_mak
|
echo "datadir=$datadir" >> $config_mak
|
||||||
echo "#define CONFIG_QEMU_SHAREDIR \"$sharedir\"" >> $config_h
|
echo "docdir=$docdir" >> $config_mak
|
||||||
|
echo "#define CONFIG_QEMU_SHAREDIR \"$datadir\"" >> $config_h
|
||||||
echo "MAKE=$make" >> $config_mak
|
echo "MAKE=$make" >> $config_mak
|
||||||
echo "CC=$cc" >> $config_mak
|
echo "CC=$cc" >> $config_mak
|
||||||
if test "$have_gcc3_options" = "yes" ; then
|
if test "$have_gcc3_options" = "yes" ; then
|
||||||
@@ -250,9 +349,13 @@ echo "AR=$ar" >> $config_mak
|
|||||||
echo "STRIP=$strip -s -R .comment -R .note" >> $config_mak
|
echo "STRIP=$strip -s -R .comment -R .note" >> $config_mak
|
||||||
echo "CFLAGS=$CFLAGS" >> $config_mak
|
echo "CFLAGS=$CFLAGS" >> $config_mak
|
||||||
echo "LDFLAGS=$LDFLAGS" >> $config_mak
|
echo "LDFLAGS=$LDFLAGS" >> $config_mak
|
||||||
|
echo "EXESUF=$EXESUF" >> $config_mak
|
||||||
if test "$cpu" = "i386" ; then
|
if test "$cpu" = "i386" ; then
|
||||||
echo "ARCH=i386" >> $config_mak
|
echo "ARCH=i386" >> $config_mak
|
||||||
echo "#define HOST_I386 1" >> $config_h
|
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
|
elif test "$cpu" = "armv4l" ; then
|
||||||
echo "ARCH=arm" >> $config_mak
|
echo "ARCH=arm" >> $config_mak
|
||||||
echo "#define HOST_ARM 1" >> $config_h
|
echo "#define HOST_ARM 1" >> $config_h
|
||||||
@@ -278,8 +381,8 @@ elif test "$cpu" = "ia64" ; then
|
|||||||
echo "ARCH=ia64" >> $config_mak
|
echo "ARCH=ia64" >> $config_mak
|
||||||
echo "#define HOST_IA64 1" >> $config_h
|
echo "#define HOST_IA64 1" >> $config_h
|
||||||
elif test "$cpu" = "m68k" ; then
|
elif test "$cpu" = "m68k" ; then
|
||||||
echo "ARCH=m68k" >> config.mak
|
echo "ARCH=m68k" >> $config_mak
|
||||||
echo "#define HOST_M68K 1" >> $TMPH
|
echo "#define HOST_M68K 1" >> $config_h
|
||||||
else
|
else
|
||||||
echo "Unsupported CPU"
|
echo "Unsupported CPU"
|
||||||
exit 1
|
exit 1
|
||||||
@@ -288,19 +391,31 @@ if test "$bigendian" = "yes" ; then
|
|||||||
echo "WORDS_BIGENDIAN=yes" >> $config_mak
|
echo "WORDS_BIGENDIAN=yes" >> $config_mak
|
||||||
echo "#define WORDS_BIGENDIAN 1" >> $config_h
|
echo "#define WORDS_BIGENDIAN 1" >> $config_h
|
||||||
fi
|
fi
|
||||||
echo "#define HAVE_BYTESWAP_H 1" >> $config_h
|
if test "$mingw32" = "yes" ; then
|
||||||
|
echo "CONFIG_WIN32=yes" >> $config_mak
|
||||||
|
echo "#define CONFIG_WIN32 1" >> $config_h
|
||||||
|
elif test -f "/usr/include/byteswap.h" ; then
|
||||||
|
echo "#define HAVE_BYTESWAP_H 1" >> $config_h
|
||||||
|
fi
|
||||||
|
if test "$darwin" = "yes" ; then
|
||||||
|
echo "CONFIG_DARWIN=yes" >> $config_mak
|
||||||
|
echo "#define CONFIG_DARWIN 1" >> $config_h
|
||||||
|
fi
|
||||||
|
if test "$gdbstub" = "yes" ; then
|
||||||
|
echo "CONFIG_GDBSTUB=yes" >> $config_mak
|
||||||
|
echo "#define CONFIG_GDBSTUB 1" >> $config_h
|
||||||
|
fi
|
||||||
if test "$gprof" = "yes" ; then
|
if test "$gprof" = "yes" ; then
|
||||||
echo "TARGET_GPROF=yes" >> $config_mak
|
echo "TARGET_GPROF=yes" >> $config_mak
|
||||||
echo "#define HAVE_GPROF 1" >> $config_h
|
echo "#define HAVE_GPROF 1" >> $config_h
|
||||||
fi
|
fi
|
||||||
if test "$static" = "yes" ; then
|
if test "$static" = "yes" ; then
|
||||||
echo "CONFIG_STATIC=yes" >> $config_mak
|
echo "CONFIG_STATIC=yes" >> $config_mak
|
||||||
|
echo "#define CONFIG_STATIC 1" >> $config_h
|
||||||
fi
|
fi
|
||||||
if test "$sdl" = "yes" ; then
|
if test "$slirp" = "yes" ; then
|
||||||
echo "CONFIG_SDL=yes" >> $config_mak
|
echo "CONFIG_SLIRP=yes" >> $config_mak
|
||||||
echo "#define CONFIG_SDL 1" >> $config_h
|
echo "#define CONFIG_SLIRP 1" >> $config_h
|
||||||
echo "SDL_LIBS=`sdl-config --libs`" >> $config_mak
|
|
||||||
echo "SDL_CFLAGS=`sdl-config --cflags`" >> $config_mak
|
|
||||||
fi
|
fi
|
||||||
echo -n "VERSION=" >>$config_mak
|
echo -n "VERSION=" >>$config_mak
|
||||||
head $source_path/VERSION >>$config_mak
|
head $source_path/VERSION >>$config_mak
|
||||||
@@ -312,6 +427,17 @@ echo "\"" >> $config_h
|
|||||||
echo "SRC_PATH=$source_path" >> $config_mak
|
echo "SRC_PATH=$source_path" >> $config_mak
|
||||||
echo "TARGET_DIRS=$target_list" >> $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 lseek64 lseek" >> $config_h
|
||||||
|
echo "#define mkstemp64 mkstemp" >> $config_h
|
||||||
|
echo "#define ftruncate64 ftruncate" >> $config_h
|
||||||
|
echo "#define off64_t off_t" >> $config_h
|
||||||
|
echo "#define MAP_ANONYMOUS MAP_ANON" >> $config_h
|
||||||
|
echo "#define _BSD 1" >> $config_h
|
||||||
|
fi
|
||||||
|
|
||||||
for target in $target_list; do
|
for target in $target_list; do
|
||||||
|
|
||||||
target_dir="$target"
|
target_dir="$target"
|
||||||
@@ -320,6 +446,7 @@ config_h=$target_dir/config.h
|
|||||||
target_cpu=`echo $target | cut -d '-' -f 1`
|
target_cpu=`echo $target | cut -d '-' -f 1`
|
||||||
target_bigendian="no"
|
target_bigendian="no"
|
||||||
[ "$target_cpu" = "sparc" ] && target_bigendian=yes
|
[ "$target_cpu" = "sparc" ] && target_bigendian=yes
|
||||||
|
[ "$target_cpu" = "ppc" ] && target_bigendian=yes
|
||||||
target_softmmu="no"
|
target_softmmu="no"
|
||||||
if expr $target : '.*-softmmu' > /dev/null ; then
|
if expr $target : '.*-softmmu' > /dev/null ; then
|
||||||
target_softmmu="yes"
|
target_softmmu="yes"
|
||||||
@@ -329,9 +456,16 @@ if expr $target : '.*-user' > /dev/null ; then
|
|||||||
target_user_only="yes"
|
target_user_only="yes"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "Creating $config_mak, $config_h and $target_dir/Makefile"
|
#echo "Creating $config_mak, $config_h and $target_dir/Makefile"
|
||||||
|
|
||||||
mkdir -p $target_dir
|
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
|
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_mak
|
||||||
@@ -356,6 +490,10 @@ elif test "$target_cpu" = "sparc" ; then
|
|||||||
echo "TARGET_ARCH=sparc" >> $config_mak
|
echo "TARGET_ARCH=sparc" >> $config_mak
|
||||||
echo "#define TARGET_ARCH \"sparc\"" >> $config_h
|
echo "#define TARGET_ARCH \"sparc\"" >> $config_h
|
||||||
echo "#define TARGET_SPARC 1" >> $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
|
else
|
||||||
echo "Unsupported target CPU"
|
echo "Unsupported target CPU"
|
||||||
exit 1
|
exit 1
|
||||||
@@ -373,6 +511,29 @@ if test "$target_user_only" = "yes" ; then
|
|||||||
echo "#define CONFIG_USER_ONLY 1" >> $config_h
|
echo "#define CONFIG_USER_ONLY 1" >> $config_h
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# sdl defines
|
||||||
|
|
||||||
|
if test "$target_user_only" = "no"; then
|
||||||
|
if test "$target_softmmu" = "no" -o "$static" = "yes"; then
|
||||||
|
if test "$sdl_static" = "yes" ; then
|
||||||
|
echo "#define CONFIG_SDL 1" >> $config_h
|
||||||
|
echo "CONFIG_SDL=yes" >> $config_mak
|
||||||
|
echo "SDL_LIBS=$sdl_static_libs" >> $config_mak
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
if test "$sdl" = "yes" ; then
|
||||||
|
echo "#define CONFIG_SDL 1" >> $config_h
|
||||||
|
echo "CONFIG_SDL=yes" >> $config_mak
|
||||||
|
echo "SDL_LIBS=`$sdl_config --libs`" >> $config_mak
|
||||||
|
fi
|
||||||
|
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
|
||||||
|
|
||||||
done # for target in $targets
|
done # for target in $targets
|
||||||
|
|
||||||
# build tree in object directory if source path is different from current one
|
# build tree in object directory if source path is different from current one
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
/* 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;
|
||||||
|
};
|
||||||
|
|
||||||
@@ -20,8 +20,152 @@
|
|||||||
#ifndef CPU_ALL_H
|
#ifndef CPU_ALL_H
|
||||||
#define 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 */
|
/* 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)
|
static inline int ldub_raw(void *ptr)
|
||||||
{
|
{
|
||||||
return *(uint8_t *)ptr;
|
return *(uint8_t *)ptr;
|
||||||
@@ -40,7 +184,7 @@ static inline void stb_raw(void *ptr, int v)
|
|||||||
/* NOTE: on arm, putting 2 in /proc/sys/debug/alignment so that the
|
/* NOTE: on arm, putting 2 in /proc/sys/debug/alignment so that the
|
||||||
kernel handles unaligned load/stores may give better results, but
|
kernel handles unaligned load/stores may give better results, but
|
||||||
it is a system wide setting : bad */
|
it is a system wide setting : bad */
|
||||||
#if defined(WORDS_BIGENDIAN) || defined(__arm__)
|
#if !defined(TARGET_WORDS_BIGENDIAN) && (defined(WORDS_BIGENDIAN) || defined(WORDS_ALIGNED))
|
||||||
|
|
||||||
/* conservative code for little endian unaligned accesses */
|
/* conservative code for little endian unaligned accesses */
|
||||||
static inline int lduw_raw(void *ptr)
|
static inline int lduw_raw(void *ptr)
|
||||||
@@ -141,102 +285,149 @@ static inline void stfl_raw(void *ptr, float v)
|
|||||||
stl_raw(ptr, u.i);
|
stl_raw(ptr, u.i);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#if defined(__arm__) && !defined(WORDS_BIGENDIAN)
|
|
||||||
|
|
||||||
/* NOTE: arm is horrible as double 32 bit words are stored in big endian ! */
|
|
||||||
static inline double ldfq_raw(void *ptr)
|
static inline double ldfq_raw(void *ptr)
|
||||||
{
|
{
|
||||||
union {
|
CPU_DoubleU u;
|
||||||
double d;
|
u.l.lower = ldl_raw(ptr);
|
||||||
uint32_t tab[2];
|
u.l.upper = ldl_raw(ptr + 4);
|
||||||
} u;
|
|
||||||
u.tab[1] = ldl_raw(ptr);
|
|
||||||
u.tab[0] = ldl_raw(ptr + 4);
|
|
||||||
return u.d;
|
return u.d;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void stfq_raw(void *ptr, double v)
|
static inline void stfq_raw(void *ptr, double v)
|
||||||
{
|
{
|
||||||
union {
|
CPU_DoubleU u;
|
||||||
double d;
|
|
||||||
uint32_t tab[2];
|
|
||||||
} u;
|
|
||||||
u.d = v;
|
u.d = v;
|
||||||
stl_raw(ptr, u.tab[1]);
|
stl_raw(ptr, u.l.lower);
|
||||||
stl_raw(ptr + 4, u.tab[0]);
|
stl_raw(ptr + 4, u.l.upper);
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
#elif defined(TARGET_WORDS_BIGENDIAN) && (!defined(WORDS_BIGENDIAN) || defined(WORDS_ALIGNED))
|
||||||
static inline double ldfq_raw(void *ptr)
|
|
||||||
{
|
|
||||||
union {
|
|
||||||
double d;
|
|
||||||
uint64_t i;
|
|
||||||
} u;
|
|
||||||
u.i = ldq_raw(ptr);
|
|
||||||
return u.d;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void stfq_raw(void *ptr, double v)
|
|
||||||
{
|
|
||||||
union {
|
|
||||||
double d;
|
|
||||||
uint64_t i;
|
|
||||||
} u;
|
|
||||||
u.d = v;
|
|
||||||
stq_raw(ptr, u.i);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#elif defined(TARGET_WORDS_BIGENDIAN) && !defined(WORDS_BIGENDIAN)
|
|
||||||
|
|
||||||
static inline int lduw_raw(void *ptr)
|
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;
|
uint8_t *b = (uint8_t *) ptr;
|
||||||
return (b[0]<<8|b[1]);
|
return ((b[0] << 8) | b[1]);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int ldsw_raw(void *ptr)
|
static inline int ldsw_raw(void *ptr)
|
||||||
{
|
{
|
||||||
int8_t *b = (int8_t *) ptr;
|
#if defined(__i386__)
|
||||||
return (b[0]<<8|b[1]);
|
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)
|
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;
|
uint8_t *b = (uint8_t *) ptr;
|
||||||
return (b[0]<<24|b[1]<<16|b[2]<<8|b[3]);
|
return (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | b[3];
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline uint64_t ldq_raw(void *ptr)
|
static inline uint64_t ldq_raw(void *ptr)
|
||||||
{
|
{
|
||||||
uint32_t a,b;
|
uint32_t a,b;
|
||||||
a = ldl (ptr);
|
a = ldl_raw(ptr);
|
||||||
b = ldl (ptr+4);
|
b = ldl_raw(ptr+4);
|
||||||
return (((uint64_t)a<<32)|b);
|
return (((uint64_t)a<<32)|b);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void stw_raw(void *ptr, int v)
|
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;
|
uint8_t *d = (uint8_t *) ptr;
|
||||||
d[0] = v >> 8;
|
d[0] = v >> 8;
|
||||||
d[1] = v;
|
d[1] = v;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void stl_raw(void *ptr, int v)
|
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;
|
uint8_t *d = (uint8_t *) ptr;
|
||||||
d[0] = v >> 24;
|
d[0] = v >> 24;
|
||||||
d[1] = v >> 16;
|
d[1] = v >> 16;
|
||||||
d[2] = v >> 8;
|
d[2] = v >> 8;
|
||||||
d[3] = v;
|
d[3] = v;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void stq_raw(void *ptr, uint64_t v)
|
static inline void stq_raw(void *ptr, uint64_t v)
|
||||||
{
|
{
|
||||||
stl (ptr, v);
|
stl_raw(ptr, v >> 32);
|
||||||
stl (ptr+4, 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
|
#else
|
||||||
@@ -330,10 +521,14 @@ static inline void stfq_raw(void *ptr, double v)
|
|||||||
#define lduw_kernel(p) lduw_raw(p)
|
#define lduw_kernel(p) lduw_raw(p)
|
||||||
#define ldsw_kernel(p) ldsw_raw(p)
|
#define ldsw_kernel(p) ldsw_raw(p)
|
||||||
#define ldl_kernel(p) ldl_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 stb_kernel(p, v) stb_raw(p, v)
|
||||||
#define stw_kernel(p, v) stw_raw(p, v)
|
#define stw_kernel(p, v) stw_raw(p, v)
|
||||||
#define stl_kernel(p, v) stl_raw(p, v)
|
#define stl_kernel(p, v) stl_raw(p, v)
|
||||||
#define stq_kernel(p, v) stq_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) */
|
#endif /* defined(CONFIG_USER_ONLY) */
|
||||||
|
|
||||||
@@ -343,12 +538,12 @@ static inline void stfq_raw(void *ptr, double v)
|
|||||||
#define TARGET_PAGE_MASK ~(TARGET_PAGE_SIZE - 1)
|
#define TARGET_PAGE_MASK ~(TARGET_PAGE_SIZE - 1)
|
||||||
#define TARGET_PAGE_ALIGN(addr) (((addr) + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK)
|
#define TARGET_PAGE_ALIGN(addr) (((addr) + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK)
|
||||||
|
|
||||||
extern unsigned long real_host_page_size;
|
extern unsigned long qemu_real_host_page_size;
|
||||||
extern unsigned long host_page_bits;
|
extern unsigned long qemu_host_page_bits;
|
||||||
extern unsigned long host_page_size;
|
extern unsigned long qemu_host_page_size;
|
||||||
extern unsigned long host_page_mask;
|
extern unsigned long qemu_host_page_mask;
|
||||||
|
|
||||||
#define HOST_PAGE_ALIGN(addr) (((addr) + host_page_size - 1) & host_page_mask)
|
#define HOST_PAGE_ALIGN(addr) (((addr) + qemu_host_page_size - 1) & qemu_host_page_mask)
|
||||||
|
|
||||||
/* same as PROT_xxx */
|
/* same as PROT_xxx */
|
||||||
#define PAGE_READ 0x0001
|
#define PAGE_READ 0x0001
|
||||||
@@ -374,8 +569,8 @@ void page_unprotect_range(uint8_t *data, unsigned long data_size);
|
|||||||
#define cpu_init cpu_x86_init
|
#define cpu_init cpu_x86_init
|
||||||
#define cpu_exec cpu_x86_exec
|
#define cpu_exec cpu_x86_exec
|
||||||
#define cpu_gen_code cpu_x86_gen_code
|
#define cpu_gen_code cpu_x86_gen_code
|
||||||
#define cpu_interrupt cpu_x86_interrupt
|
|
||||||
#define cpu_signal_handler cpu_x86_signal_handler
|
#define cpu_signal_handler cpu_x86_signal_handler
|
||||||
|
#define cpu_dump_state cpu_x86_dump_state
|
||||||
|
|
||||||
#elif defined(TARGET_ARM)
|
#elif defined(TARGET_ARM)
|
||||||
|
|
||||||
@@ -383,8 +578,8 @@ void page_unprotect_range(uint8_t *data, unsigned long data_size);
|
|||||||
#define cpu_init cpu_arm_init
|
#define cpu_init cpu_arm_init
|
||||||
#define cpu_exec cpu_arm_exec
|
#define cpu_exec cpu_arm_exec
|
||||||
#define cpu_gen_code cpu_arm_gen_code
|
#define cpu_gen_code cpu_arm_gen_code
|
||||||
#define cpu_interrupt cpu_arm_interrupt
|
|
||||||
#define cpu_signal_handler cpu_arm_signal_handler
|
#define cpu_signal_handler cpu_arm_signal_handler
|
||||||
|
#define cpu_dump_state cpu_arm_dump_state
|
||||||
|
|
||||||
#elif defined(TARGET_SPARC)
|
#elif defined(TARGET_SPARC)
|
||||||
|
|
||||||
@@ -392,8 +587,17 @@ void page_unprotect_range(uint8_t *data, unsigned long data_size);
|
|||||||
#define cpu_init cpu_sparc_init
|
#define cpu_init cpu_sparc_init
|
||||||
#define cpu_exec cpu_sparc_exec
|
#define cpu_exec cpu_sparc_exec
|
||||||
#define cpu_gen_code cpu_sparc_gen_code
|
#define cpu_gen_code cpu_sparc_gen_code
|
||||||
#define cpu_interrupt cpu_sparc_interrupt
|
|
||||||
#define cpu_signal_handler cpu_sparc_signal_handler
|
#define cpu_signal_handler cpu_sparc_signal_handler
|
||||||
|
#define cpu_dump_state cpu_sparc_dump_state
|
||||||
|
|
||||||
|
#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
|
||||||
|
#define cpu_dump_state cpu_ppc_dump_state
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
@@ -403,37 +607,119 @@ void page_unprotect_range(uint8_t *data, unsigned long data_size);
|
|||||||
|
|
||||||
#endif /* SINGLE_CPU_DEFINES */
|
#endif /* SINGLE_CPU_DEFINES */
|
||||||
|
|
||||||
#define DEFAULT_GDBSTUB_PORT 1234
|
|
||||||
|
|
||||||
void cpu_abort(CPUState *env, const char *fmt, ...);
|
void cpu_abort(CPUState *env, const char *fmt, ...);
|
||||||
extern CPUState *cpu_single_env;
|
extern CPUState *cpu_single_env;
|
||||||
|
extern int code_copy_enabled;
|
||||||
|
|
||||||
#define CPU_INTERRUPT_EXIT 0x01 /* wants exit from main loop */
|
#define CPU_INTERRUPT_EXIT 0x01 /* wants exit from main loop */
|
||||||
#define CPU_INTERRUPT_HARD 0x02 /* hardware interrupt pending */
|
#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_interrupt(CPUState *s, int mask);
|
||||||
|
void cpu_reset_interrupt(CPUState *env, int mask);
|
||||||
|
|
||||||
int cpu_breakpoint_insert(CPUState *env, uint32_t pc);
|
int cpu_breakpoint_insert(CPUState *env, target_ulong pc);
|
||||||
int cpu_breakpoint_remove(CPUState *env, uint32_t pc);
|
int cpu_breakpoint_remove(CPUState *env, target_ulong pc);
|
||||||
void cpu_single_step(CPUState *env, int enabled);
|
void cpu_single_step(CPUState *env, int enabled);
|
||||||
|
void cpu_reset(CPUState *s);
|
||||||
|
|
||||||
|
/* Return the physical page corresponding to a virtual one. Use it
|
||||||
|
only for debugging because no protection checks are done. Return -1
|
||||||
|
if no page found. */
|
||||||
|
target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr);
|
||||||
|
|
||||||
|
#define CPU_LOG_TB_OUT_ASM (1 << 0)
|
||||||
|
#define CPU_LOG_TB_IN_ASM (1 << 1)
|
||||||
|
#define CPU_LOG_TB_OP (1 << 2)
|
||||||
|
#define CPU_LOG_TB_OP_OPT (1 << 3)
|
||||||
|
#define CPU_LOG_INT (1 << 4)
|
||||||
|
#define CPU_LOG_EXEC (1 << 5)
|
||||||
|
#define CPU_LOG_PCALL (1 << 6)
|
||||||
|
#define CPU_LOG_IOPORT (1 << 7)
|
||||||
|
#define CPU_LOG_TB_CPU (1 << 8)
|
||||||
|
|
||||||
|
/* define log items */
|
||||||
|
typedef struct CPULogItem {
|
||||||
|
int mask;
|
||||||
|
const char *name;
|
||||||
|
const char *help;
|
||||||
|
} CPULogItem;
|
||||||
|
|
||||||
|
extern CPULogItem cpu_log_items[];
|
||||||
|
|
||||||
#define CPU_LOG_ALL 1
|
|
||||||
void cpu_set_log(int log_flags);
|
void cpu_set_log(int log_flags);
|
||||||
void cpu_set_log_filename(const char *filename);
|
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 */
|
/* memory API */
|
||||||
|
|
||||||
typedef void CPUWriteMemoryFunc(uint32_t addr, uint32_t value);
|
extern int phys_ram_size;
|
||||||
typedef uint32_t CPUReadMemoryFunc(uint32_t addr);
|
extern int phys_ram_fd;
|
||||||
|
extern uint8_t *phys_ram_base;
|
||||||
|
extern uint8_t *phys_ram_dirty;
|
||||||
|
|
||||||
void cpu_register_physical_memory(unsigned long start_addr, unsigned long size,
|
/* physical memory access */
|
||||||
long phys_offset);
|
#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,
|
int cpu_register_io_memory(int io_index,
|
||||||
CPUReadMemoryFunc **mem_read,
|
CPUReadMemoryFunc **mem_read,
|
||||||
CPUWriteMemoryFunc **mem_write);
|
CPUWriteMemoryFunc **mem_write,
|
||||||
|
void *opaque);
|
||||||
|
|
||||||
/* gdb stub API */
|
void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
|
||||||
extern int gdbstub_fd;
|
int len, int is_write);
|
||||||
CPUState *cpu_gdbstub_get_env(void *opaque);
|
static inline void cpu_physical_memory_read(target_phys_addr_t addr,
|
||||||
int cpu_gdbstub(void *opaque, int (*main_loop)(void *opaque), int port);
|
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 */
|
#endif /* CPU_ALL_H */
|
||||||
+51
-2
@@ -22,6 +22,55 @@
|
|||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include <setjmp.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_INTERRUPT 256 /* async interruption */
|
||||||
#define EXCP_HLT 257 /* hlt instruction reached */
|
#define EXCP_HLT 257 /* hlt instruction reached */
|
||||||
@@ -38,9 +87,9 @@ typedef struct CPUTLBEntry {
|
|||||||
bit 3 : indicates that the entry is invalid
|
bit 3 : indicates that the entry is invalid
|
||||||
bit 2..0 : zero
|
bit 2..0 : zero
|
||||||
*/
|
*/
|
||||||
uint32_t address;
|
target_ulong address;
|
||||||
/* addend to virtual address to get physical address */
|
/* addend to virtual address to get physical address */
|
||||||
uint32_t addend;
|
target_phys_addr_t addend;
|
||||||
} CPUTLBEntry;
|
} CPUTLBEntry;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
+429
-54
@@ -21,6 +21,22 @@
|
|||||||
#include "exec.h"
|
#include "exec.h"
|
||||||
#include "disas.h"
|
#include "disas.h"
|
||||||
|
|
||||||
|
#if !defined(CONFIG_SOFTMMU)
|
||||||
|
#undef EAX
|
||||||
|
#undef ECX
|
||||||
|
#undef EDX
|
||||||
|
#undef EBX
|
||||||
|
#undef ESP
|
||||||
|
#undef EBP
|
||||||
|
#undef ESI
|
||||||
|
#undef EDI
|
||||||
|
#undef EIP
|
||||||
|
#include <signal.h>
|
||||||
|
#include <sys/ucontext.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int tb_invalidated_flag;
|
||||||
|
|
||||||
//#define DEBUG_EXEC
|
//#define DEBUG_EXEC
|
||||||
//#define DEBUG_SIGNAL
|
//#define DEBUG_SIGNAL
|
||||||
|
|
||||||
@@ -32,6 +48,28 @@ void cpu_loop_exit(void)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* exit the current TB from a signal handler. The host registers are
|
||||||
|
restored in a state compatible with the CPU emulator
|
||||||
|
*/
|
||||||
|
void cpu_resume_from_signal(CPUState *env1, void *puc)
|
||||||
|
{
|
||||||
|
#if !defined(CONFIG_SOFTMMU)
|
||||||
|
struct ucontext *uc = puc;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
env = env1;
|
||||||
|
|
||||||
|
/* XXX: restore cpu registers saved in host registers */
|
||||||
|
|
||||||
|
#if !defined(CONFIG_SOFTMMU)
|
||||||
|
if (puc) {
|
||||||
|
/* XXX: use siglongjmp ? */
|
||||||
|
sigprocmask(SIG_SETMASK, &uc->uc_sigmask, NULL);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
longjmp(env->jmp_env, 1);
|
||||||
|
}
|
||||||
|
|
||||||
/* main execution loop */
|
/* main execution loop */
|
||||||
|
|
||||||
int cpu_exec(CPUState *env1)
|
int cpu_exec(CPUState *env1)
|
||||||
@@ -131,6 +169,7 @@ int cpu_exec(CPUState *env1)
|
|||||||
env->cpsr = psr & ~0xf0000000;
|
env->cpsr = psr & ~0xf0000000;
|
||||||
}
|
}
|
||||||
#elif defined(TARGET_SPARC)
|
#elif defined(TARGET_SPARC)
|
||||||
|
#elif defined(TARGET_PPC)
|
||||||
#else
|
#else
|
||||||
#error unsupported target CPU
|
#error unsupported target CPU
|
||||||
#endif
|
#endif
|
||||||
@@ -139,6 +178,7 @@ int cpu_exec(CPUState *env1)
|
|||||||
/* prepare setjmp context for exception handling */
|
/* prepare setjmp context for exception handling */
|
||||||
for(;;) {
|
for(;;) {
|
||||||
if (setjmp(env->jmp_env) == 0) {
|
if (setjmp(env->jmp_env) == 0) {
|
||||||
|
env->current_tb = NULL;
|
||||||
/* if an exception is pending, we execute it here */
|
/* if an exception is pending, we execute it here */
|
||||||
if (env->exception_index >= 0) {
|
if (env->exception_index >= 0) {
|
||||||
if (env->exception_index >= EXCP_INTERRUPT) {
|
if (env->exception_index >= EXCP_INTERRUPT) {
|
||||||
@@ -166,6 +206,8 @@ int cpu_exec(CPUState *env1)
|
|||||||
env->exception_is_int,
|
env->exception_is_int,
|
||||||
env->error_code,
|
env->error_code,
|
||||||
env->exception_next_eip, 0);
|
env->exception_next_eip, 0);
|
||||||
|
#elif defined(TARGET_PPC)
|
||||||
|
do_interrupt(env);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
env->exception_index = -1;
|
env->exception_index = -1;
|
||||||
@@ -184,12 +226,12 @@ int cpu_exec(CPUState *env1)
|
|||||||
(env->eflags & IF_MASK) &&
|
(env->eflags & IF_MASK) &&
|
||||||
!(env->hflags & HF_INHIBIT_IRQ_MASK)) {
|
!(env->hflags & HF_INHIBIT_IRQ_MASK)) {
|
||||||
int intno;
|
int intno;
|
||||||
intno = cpu_x86_get_pic_interrupt(env);
|
env->interrupt_request &= ~CPU_INTERRUPT_HARD;
|
||||||
if (loglevel) {
|
intno = cpu_get_pic_interrupt(env);
|
||||||
|
if (loglevel & CPU_LOG_TB_IN_ASM) {
|
||||||
fprintf(logfile, "Servicing hardware INT=0x%02x\n", intno);
|
fprintf(logfile, "Servicing hardware INT=0x%02x\n", intno);
|
||||||
}
|
}
|
||||||
do_interrupt(intno, 0, 0, 0, 1);
|
do_interrupt(intno, 0, 0, 0, 1);
|
||||||
env->interrupt_request &= ~CPU_INTERRUPT_HARD;
|
|
||||||
/* ensure that no TB jump will be modified as
|
/* ensure that no TB jump will be modified as
|
||||||
the program flow was changed */
|
the program flow was changed */
|
||||||
#ifdef __sparc__
|
#ifdef __sparc__
|
||||||
@@ -198,7 +240,38 @@ int cpu_exec(CPUState *env1)
|
|||||||
T0 = 0;
|
T0 = 0;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
#elif defined(TARGET_PPC)
|
||||||
|
#if 0
|
||||||
|
if ((interrupt_request & CPU_INTERRUPT_RESET)) {
|
||||||
|
cpu_ppc_reset(env);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
if (msr_ee != 0) {
|
||||||
|
if ((interrupt_request & CPU_INTERRUPT_HARD)) {
|
||||||
|
/* Raise it */
|
||||||
|
env->exception_index = EXCP_EXTERNAL;
|
||||||
|
env->error_code = 0;
|
||||||
|
do_interrupt(env);
|
||||||
|
env->interrupt_request &= ~CPU_INTERRUPT_HARD;
|
||||||
|
} else if ((interrupt_request & CPU_INTERRUPT_TIMER)) {
|
||||||
|
/* Raise it */
|
||||||
|
env->exception_index = EXCP_DECR;
|
||||||
|
env->error_code = 0;
|
||||||
|
do_interrupt(env);
|
||||||
|
env->interrupt_request &= ~CPU_INTERRUPT_TIMER;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (interrupt_request & CPU_INTERRUPT_EXITTB) {
|
||||||
|
env->interrupt_request &= ~CPU_INTERRUPT_EXITTB;
|
||||||
|
/* ensure that no TB jump will be modified as
|
||||||
|
the program flow was changed */
|
||||||
|
#ifdef __sparc__
|
||||||
|
tmp_T0 = 0;
|
||||||
|
#else
|
||||||
|
T0 = 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
if (interrupt_request & CPU_INTERRUPT_EXIT) {
|
if (interrupt_request & CPU_INTERRUPT_EXIT) {
|
||||||
env->interrupt_request &= ~CPU_INTERRUPT_EXIT;
|
env->interrupt_request &= ~CPU_INTERRUPT_EXIT;
|
||||||
env->exception_index = EXCP_INTERRUPT;
|
env->exception_index = EXCP_INTERRUPT;
|
||||||
@@ -206,7 +279,7 @@ int cpu_exec(CPUState *env1)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#ifdef DEBUG_EXEC
|
#ifdef DEBUG_EXEC
|
||||||
if (loglevel) {
|
if (loglevel & CPU_LOG_EXEC) {
|
||||||
#if defined(TARGET_I386)
|
#if defined(TARGET_I386)
|
||||||
/* restore flags in standard format */
|
/* restore flags in standard format */
|
||||||
env->regs[R_EAX] = EAX;
|
env->regs[R_EAX] = EAX;
|
||||||
@@ -226,6 +299,8 @@ int cpu_exec(CPUState *env1)
|
|||||||
env->cpsr &= ~0xf0000000;
|
env->cpsr &= ~0xf0000000;
|
||||||
#elif defined(TARGET_SPARC)
|
#elif defined(TARGET_SPARC)
|
||||||
cpu_sparc_dump_state (env, logfile, 0);
|
cpu_sparc_dump_state (env, logfile, 0);
|
||||||
|
#elif defined(TARGET_PPC)
|
||||||
|
cpu_ppc_dump_state(env, logfile, 0);
|
||||||
#else
|
#else
|
||||||
#error unsupported target CPU
|
#error unsupported target CPU
|
||||||
#endif
|
#endif
|
||||||
@@ -244,25 +319,61 @@ int cpu_exec(CPUState *env1)
|
|||||||
cs_base = 0;
|
cs_base = 0;
|
||||||
pc = (uint8_t *)env->regs[15];
|
pc = (uint8_t *)env->regs[15];
|
||||||
#elif defined(TARGET_SPARC)
|
#elif defined(TARGET_SPARC)
|
||||||
flags = 0;
|
flags = 0;
|
||||||
cs_base = 0;
|
cs_base = (uint8_t *)env->npc;
|
||||||
if (env->npc) {
|
pc = (uint8_t *) env->pc;
|
||||||
env->pc = env->npc;
|
#elif defined(TARGET_PPC)
|
||||||
env->npc = 0;
|
flags = 0;
|
||||||
}
|
cs_base = 0;
|
||||||
pc = (uint8_t *) env->pc;
|
pc = (uint8_t *)env->nip;
|
||||||
#else
|
#else
|
||||||
#error unsupported CPU
|
#error unsupported CPU
|
||||||
#endif
|
#endif
|
||||||
tb = tb_find(&ptb, (unsigned long)pc, (unsigned long)cs_base,
|
tb = tb_find(&ptb, (unsigned long)pc, (unsigned long)cs_base,
|
||||||
flags);
|
flags);
|
||||||
if (!tb) {
|
if (!tb) {
|
||||||
|
TranslationBlock **ptb1;
|
||||||
|
unsigned int h;
|
||||||
|
target_ulong phys_pc, phys_page1, phys_page2, virt_page2;
|
||||||
|
|
||||||
|
|
||||||
spin_lock(&tb_lock);
|
spin_lock(&tb_lock);
|
||||||
|
|
||||||
|
tb_invalidated_flag = 0;
|
||||||
|
|
||||||
|
/* find translated block using physical mappings */
|
||||||
|
phys_pc = get_phys_addr_code(env, (unsigned long)pc);
|
||||||
|
phys_page1 = phys_pc & TARGET_PAGE_MASK;
|
||||||
|
phys_page2 = -1;
|
||||||
|
h = tb_phys_hash_func(phys_pc);
|
||||||
|
ptb1 = &tb_phys_hash[h];
|
||||||
|
for(;;) {
|
||||||
|
tb = *ptb1;
|
||||||
|
if (!tb)
|
||||||
|
goto not_found;
|
||||||
|
if (tb->pc == (unsigned long)pc &&
|
||||||
|
tb->page_addr[0] == phys_page1 &&
|
||||||
|
tb->cs_base == (unsigned long)cs_base &&
|
||||||
|
tb->flags == flags) {
|
||||||
|
/* check next page if needed */
|
||||||
|
if (tb->page_addr[1] != -1) {
|
||||||
|
virt_page2 = ((unsigned long)pc & TARGET_PAGE_MASK) +
|
||||||
|
TARGET_PAGE_SIZE;
|
||||||
|
phys_page2 = get_phys_addr_code(env, virt_page2);
|
||||||
|
if (tb->page_addr[1] == phys_page2)
|
||||||
|
goto found;
|
||||||
|
} else {
|
||||||
|
goto found;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ptb1 = &tb->phys_hash_next;
|
||||||
|
}
|
||||||
|
not_found:
|
||||||
/* if no translated code available, then translate it now */
|
/* if no translated code available, then translate it now */
|
||||||
tb = tb_alloc((unsigned long)pc);
|
tb = tb_alloc((unsigned long)pc);
|
||||||
if (!tb) {
|
if (!tb) {
|
||||||
/* flush must be done */
|
/* flush must be done */
|
||||||
tb_flush();
|
tb_flush(env);
|
||||||
/* cannot fail at this point */
|
/* cannot fail at this point */
|
||||||
tb = tb_alloc((unsigned long)pc);
|
tb = tb_alloc((unsigned long)pc);
|
||||||
/* don't forget to invalidate previous TB info */
|
/* don't forget to invalidate previous TB info */
|
||||||
@@ -273,16 +384,35 @@ int cpu_exec(CPUState *env1)
|
|||||||
tb->tc_ptr = tc_ptr;
|
tb->tc_ptr = tc_ptr;
|
||||||
tb->cs_base = (unsigned long)cs_base;
|
tb->cs_base = (unsigned long)cs_base;
|
||||||
tb->flags = flags;
|
tb->flags = flags;
|
||||||
/* XXX: an MMU exception can occur here */
|
|
||||||
cpu_gen_code(env, tb, CODE_GEN_MAX_SIZE, &code_gen_size);
|
cpu_gen_code(env, tb, CODE_GEN_MAX_SIZE, &code_gen_size);
|
||||||
|
code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1));
|
||||||
|
|
||||||
|
/* check next page if needed */
|
||||||
|
virt_page2 = ((unsigned long)pc + tb->size - 1) & TARGET_PAGE_MASK;
|
||||||
|
phys_page2 = -1;
|
||||||
|
if (((unsigned long)pc & TARGET_PAGE_MASK) != virt_page2) {
|
||||||
|
phys_page2 = get_phys_addr_code(env, virt_page2);
|
||||||
|
}
|
||||||
|
tb_link_phys(tb, phys_pc, phys_page2);
|
||||||
|
|
||||||
|
found:
|
||||||
|
if (tb_invalidated_flag) {
|
||||||
|
/* as some TB could have been invalidated because
|
||||||
|
of memory exceptions while generating the code, we
|
||||||
|
must recompute the hash index here */
|
||||||
|
ptb = &tb_hash[tb_hash_func((unsigned long)pc)];
|
||||||
|
while (*ptb != NULL)
|
||||||
|
ptb = &(*ptb)->hash_next;
|
||||||
|
T0 = 0;
|
||||||
|
}
|
||||||
|
/* we add the TB in the virtual pc hash table */
|
||||||
*ptb = tb;
|
*ptb = tb;
|
||||||
tb->hash_next = NULL;
|
tb->hash_next = NULL;
|
||||||
tb_link(tb);
|
tb_link(tb);
|
||||||
code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1));
|
|
||||||
spin_unlock(&tb_lock);
|
spin_unlock(&tb_lock);
|
||||||
}
|
}
|
||||||
#ifdef DEBUG_EXEC
|
#ifdef DEBUG_EXEC
|
||||||
if (loglevel) {
|
if (loglevel & CPU_LOG_EXEC) {
|
||||||
fprintf(logfile, "Trace 0x%08lx [0x%08lx] %s\n",
|
fprintf(logfile, "Trace 0x%08lx [0x%08lx] %s\n",
|
||||||
(long)tb->tc_ptr, (long)tb->pc,
|
(long)tb->tc_ptr, (long)tb->pc,
|
||||||
lookup_symbol((void *)tb->pc));
|
lookup_symbol((void *)tb->pc));
|
||||||
@@ -292,9 +422,19 @@ int cpu_exec(CPUState *env1)
|
|||||||
T0 = tmp_T0;
|
T0 = tmp_T0;
|
||||||
#endif
|
#endif
|
||||||
/* see if we can patch the calling TB. */
|
/* see if we can patch the calling TB. */
|
||||||
if (T0 != 0) {
|
if (T0 != 0
|
||||||
|
#if defined(TARGET_I386) && defined(USE_CODE_COPY)
|
||||||
|
&& (tb->cflags & CF_CODE_COPY) ==
|
||||||
|
(((TranslationBlock *)(T0 & ~3))->cflags & CF_CODE_COPY)
|
||||||
|
#endif
|
||||||
|
) {
|
||||||
spin_lock(&tb_lock);
|
spin_lock(&tb_lock);
|
||||||
tb_add_jump((TranslationBlock *)(T0 & ~3), T0 & 3, tb);
|
tb_add_jump((TranslationBlock *)(T0 & ~3), T0 & 3, tb);
|
||||||
|
#if defined(USE_CODE_COPY)
|
||||||
|
/* propagates the FP use info */
|
||||||
|
((TranslationBlock *)(T0 & ~3))->cflags |=
|
||||||
|
(tb->cflags & CF_FP_USED);
|
||||||
|
#endif
|
||||||
spin_unlock(&tb_lock);
|
spin_unlock(&tb_lock);
|
||||||
}
|
}
|
||||||
tc_ptr = tb->tc_ptr;
|
tc_ptr = tb->tc_ptr;
|
||||||
@@ -314,6 +454,80 @@ int cpu_exec(CPUState *env1)
|
|||||||
: /* no outputs */
|
: /* no outputs */
|
||||||
: "r" (gen_func)
|
: "r" (gen_func)
|
||||||
: "r1", "r2", "r3", "r8", "r9", "r10", "r12", "r14");
|
: "r1", "r2", "r3", "r8", "r9", "r10", "r12", "r14");
|
||||||
|
#elif defined(TARGET_I386) && defined(USE_CODE_COPY)
|
||||||
|
{
|
||||||
|
if (!(tb->cflags & CF_CODE_COPY)) {
|
||||||
|
if ((tb->cflags & CF_FP_USED) && env->native_fp_regs) {
|
||||||
|
save_native_fp_state(env);
|
||||||
|
}
|
||||||
|
gen_func();
|
||||||
|
} else {
|
||||||
|
if ((tb->cflags & CF_FP_USED) && !env->native_fp_regs) {
|
||||||
|
restore_native_fp_state(env);
|
||||||
|
}
|
||||||
|
/* we work with native eflags */
|
||||||
|
CC_SRC = cc_table[CC_OP].compute_all();
|
||||||
|
CC_OP = CC_OP_EFLAGS;
|
||||||
|
asm(".globl exec_loop\n"
|
||||||
|
"\n"
|
||||||
|
"debug1:\n"
|
||||||
|
" pushl %%ebp\n"
|
||||||
|
" fs movl %10, %9\n"
|
||||||
|
" fs movl %11, %%eax\n"
|
||||||
|
" andl $0x400, %%eax\n"
|
||||||
|
" fs orl %8, %%eax\n"
|
||||||
|
" pushl %%eax\n"
|
||||||
|
" popf\n"
|
||||||
|
" fs movl %%esp, %12\n"
|
||||||
|
" fs movl %0, %%eax\n"
|
||||||
|
" fs movl %1, %%ecx\n"
|
||||||
|
" fs movl %2, %%edx\n"
|
||||||
|
" fs movl %3, %%ebx\n"
|
||||||
|
" fs movl %4, %%esp\n"
|
||||||
|
" fs movl %5, %%ebp\n"
|
||||||
|
" fs movl %6, %%esi\n"
|
||||||
|
" fs movl %7, %%edi\n"
|
||||||
|
" fs jmp *%9\n"
|
||||||
|
"exec_loop:\n"
|
||||||
|
" fs movl %%esp, %4\n"
|
||||||
|
" fs movl %12, %%esp\n"
|
||||||
|
" fs movl %%eax, %0\n"
|
||||||
|
" fs movl %%ecx, %1\n"
|
||||||
|
" fs movl %%edx, %2\n"
|
||||||
|
" fs movl %%ebx, %3\n"
|
||||||
|
" fs movl %%ebp, %5\n"
|
||||||
|
" fs movl %%esi, %6\n"
|
||||||
|
" fs movl %%edi, %7\n"
|
||||||
|
" pushf\n"
|
||||||
|
" popl %%eax\n"
|
||||||
|
" movl %%eax, %%ecx\n"
|
||||||
|
" andl $0x400, %%ecx\n"
|
||||||
|
" shrl $9, %%ecx\n"
|
||||||
|
" andl $0x8d5, %%eax\n"
|
||||||
|
" fs movl %%eax, %8\n"
|
||||||
|
" movl $1, %%eax\n"
|
||||||
|
" subl %%ecx, %%eax\n"
|
||||||
|
" fs movl %%eax, %11\n"
|
||||||
|
" fs movl %9, %%ebx\n" /* get T0 value */
|
||||||
|
" popl %%ebp\n"
|
||||||
|
:
|
||||||
|
: "m" (*(uint8_t *)offsetof(CPUState, regs[0])),
|
||||||
|
"m" (*(uint8_t *)offsetof(CPUState, regs[1])),
|
||||||
|
"m" (*(uint8_t *)offsetof(CPUState, regs[2])),
|
||||||
|
"m" (*(uint8_t *)offsetof(CPUState, regs[3])),
|
||||||
|
"m" (*(uint8_t *)offsetof(CPUState, regs[4])),
|
||||||
|
"m" (*(uint8_t *)offsetof(CPUState, regs[5])),
|
||||||
|
"m" (*(uint8_t *)offsetof(CPUState, regs[6])),
|
||||||
|
"m" (*(uint8_t *)offsetof(CPUState, regs[7])),
|
||||||
|
"m" (*(uint8_t *)offsetof(CPUState, cc_src)),
|
||||||
|
"m" (*(uint8_t *)offsetof(CPUState, tmp0)),
|
||||||
|
"a" (gen_func),
|
||||||
|
"m" (*(uint8_t *)offsetof(CPUState, df)),
|
||||||
|
"m" (*(uint8_t *)offsetof(CPUState, saved_esp))
|
||||||
|
: "%ecx", "%edx"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
gen_func();
|
gen_func();
|
||||||
#endif
|
#endif
|
||||||
@@ -334,6 +548,11 @@ int cpu_exec(CPUState *env1)
|
|||||||
|
|
||||||
|
|
||||||
#if defined(TARGET_I386)
|
#if defined(TARGET_I386)
|
||||||
|
#if defined(USE_CODE_COPY)
|
||||||
|
if (env->native_fp_regs) {
|
||||||
|
save_native_fp_state(env);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
/* restore flags in standard format */
|
/* restore flags in standard format */
|
||||||
env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
|
env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
|
||||||
|
|
||||||
@@ -365,6 +584,7 @@ int cpu_exec(CPUState *env1)
|
|||||||
#elif defined(TARGET_ARM)
|
#elif defined(TARGET_ARM)
|
||||||
env->cpsr = compute_cpsr();
|
env->cpsr = compute_cpsr();
|
||||||
#elif defined(TARGET_SPARC)
|
#elif defined(TARGET_SPARC)
|
||||||
|
#elif defined(TARGET_PPC)
|
||||||
#else
|
#else
|
||||||
#error unsupported target CPU
|
#error unsupported target CPU
|
||||||
#endif
|
#endif
|
||||||
@@ -378,7 +598,20 @@ int cpu_exec(CPUState *env1)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(TARGET_I386)
|
/* must only be called from the generated code as an exception can be
|
||||||
|
generated */
|
||||||
|
void tb_invalidate_page_range(target_ulong start, target_ulong end)
|
||||||
|
{
|
||||||
|
/* XXX: cannot enable it yet because it yields to MMU exception
|
||||||
|
where NIP != read address on PowerPC */
|
||||||
|
#if 0
|
||||||
|
target_ulong phys_addr;
|
||||||
|
phys_addr = get_phys_addr_code(env, start);
|
||||||
|
tb_invalidate_phys_page_range(phys_addr, phys_addr + end - start, 0);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(TARGET_I386) && defined(CONFIG_USER_ONLY)
|
||||||
|
|
||||||
void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector)
|
void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector)
|
||||||
{
|
{
|
||||||
@@ -391,7 +624,7 @@ void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector)
|
|||||||
cpu_x86_load_seg_cache(env, seg_reg, selector,
|
cpu_x86_load_seg_cache(env, seg_reg, selector,
|
||||||
(uint8_t *)(selector << 4), 0xffff, 0);
|
(uint8_t *)(selector << 4), 0xffff, 0);
|
||||||
} else {
|
} else {
|
||||||
load_seg(seg_reg, selector, 0);
|
load_seg(seg_reg, selector);
|
||||||
}
|
}
|
||||||
env = saved_env;
|
env = saved_env;
|
||||||
}
|
}
|
||||||
@@ -422,17 +655,7 @@ void cpu_x86_frstor(CPUX86State *s, uint8_t *ptr, int data32)
|
|||||||
|
|
||||||
#endif /* TARGET_I386 */
|
#endif /* TARGET_I386 */
|
||||||
|
|
||||||
#undef EAX
|
#if !defined(CONFIG_SOFTMMU)
|
||||||
#undef ECX
|
|
||||||
#undef EDX
|
|
||||||
#undef EBX
|
|
||||||
#undef ESP
|
|
||||||
#undef EBP
|
|
||||||
#undef ESI
|
|
||||||
#undef EDI
|
|
||||||
#undef EIP
|
|
||||||
#include <signal.h>
|
|
||||||
#include <sys/ucontext.h>
|
|
||||||
|
|
||||||
#if defined(TARGET_I386)
|
#if defined(TARGET_I386)
|
||||||
|
|
||||||
@@ -441,7 +664,8 @@ void cpu_x86_frstor(CPUX86State *s, uint8_t *ptr, int data32)
|
|||||||
write caused the exception and otherwise 0'. 'old_set' is the
|
write caused the exception and otherwise 0'. 'old_set' is the
|
||||||
signal set which should be restored */
|
signal set which should be restored */
|
||||||
static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
|
static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
|
||||||
int is_write, sigset_t *old_set)
|
int is_write, sigset_t *old_set,
|
||||||
|
void *puc)
|
||||||
{
|
{
|
||||||
TranslationBlock *tb;
|
TranslationBlock *tb;
|
||||||
int ret;
|
int ret;
|
||||||
@@ -449,13 +673,14 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
|
|||||||
if (cpu_single_env)
|
if (cpu_single_env)
|
||||||
env = cpu_single_env; /* XXX: find a correct solution for multithread */
|
env = cpu_single_env; /* XXX: find a correct solution for multithread */
|
||||||
#if defined(DEBUG_SIGNAL)
|
#if defined(DEBUG_SIGNAL)
|
||||||
printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
|
qemu_printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
|
||||||
pc, address, is_write, *(unsigned long *)old_set);
|
pc, address, is_write, *(unsigned long *)old_set);
|
||||||
#endif
|
#endif
|
||||||
/* XXX: locking issue */
|
/* XXX: locking issue */
|
||||||
if (is_write && page_unprotect(address)) {
|
if (is_write && page_unprotect(address, pc, puc)) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* see if it is an MMU fault */
|
/* see if it is an MMU fault */
|
||||||
ret = cpu_x86_handle_mmu_fault(env, address, is_write,
|
ret = cpu_x86_handle_mmu_fault(env, address, is_write,
|
||||||
((env->hflags & HF_CPL_MASK) == 3), 0);
|
((env->hflags & HF_CPL_MASK) == 3), 0);
|
||||||
@@ -468,7 +693,7 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
|
|||||||
if (tb) {
|
if (tb) {
|
||||||
/* the PC is inside the translated code. It means that we have
|
/* the PC is inside the translated code. It means that we have
|
||||||
a virtual CPU fault */
|
a virtual CPU fault */
|
||||||
cpu_restore_state(tb, env, pc);
|
cpu_restore_state(tb, env, pc, puc);
|
||||||
}
|
}
|
||||||
if (ret == 1) {
|
if (ret == 1) {
|
||||||
#if 0
|
#if 0
|
||||||
@@ -482,8 +707,7 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
|
|||||||
} else {
|
} else {
|
||||||
/* activate soft MMU for this block */
|
/* activate soft MMU for this block */
|
||||||
env->hflags |= HF_SOFTMMU_MASK;
|
env->hflags |= HF_SOFTMMU_MASK;
|
||||||
sigprocmask(SIG_SETMASK, old_set, NULL);
|
cpu_resume_from_signal(env, puc);
|
||||||
cpu_loop_exit();
|
|
||||||
}
|
}
|
||||||
/* never comes here */
|
/* never comes here */
|
||||||
return 1;
|
return 1;
|
||||||
@@ -491,16 +715,73 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
|
|||||||
|
|
||||||
#elif defined(TARGET_ARM)
|
#elif defined(TARGET_ARM)
|
||||||
static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
|
static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
|
||||||
int is_write, sigset_t *old_set)
|
int is_write, sigset_t *old_set,
|
||||||
|
void *puc)
|
||||||
{
|
{
|
||||||
/* XXX: do more */
|
/* XXX: do more */
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#elif defined(TARGET_SPARC)
|
#elif defined(TARGET_SPARC)
|
||||||
static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
|
static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
|
||||||
int is_write, sigset_t *old_set)
|
int is_write, sigset_t *old_set,
|
||||||
|
void *puc)
|
||||||
{
|
{
|
||||||
return 0;
|
/* XXX: locking issue */
|
||||||
|
if (is_write && page_unprotect(address, pc, puc)) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#elif defined (TARGET_PPC)
|
||||||
|
static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
|
||||||
|
int is_write, sigset_t *old_set,
|
||||||
|
void *puc)
|
||||||
|
{
|
||||||
|
TranslationBlock *tb;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
#if 1
|
||||||
|
if (cpu_single_env)
|
||||||
|
env = cpu_single_env; /* XXX: find a correct solution for multithread */
|
||||||
|
#endif
|
||||||
|
#if defined(DEBUG_SIGNAL)
|
||||||
|
printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
|
||||||
|
pc, address, is_write, *(unsigned long *)old_set);
|
||||||
|
#endif
|
||||||
|
/* XXX: locking issue */
|
||||||
|
if (is_write && page_unprotect(address, pc, puc)) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* see if it is an MMU fault */
|
||||||
|
ret = cpu_ppc_handle_mmu_fault(env, address, is_write, msr_pr, 0);
|
||||||
|
if (ret < 0)
|
||||||
|
return 0; /* not an MMU fault */
|
||||||
|
if (ret == 0)
|
||||||
|
return 1; /* the MMU fault was handled without causing real CPU fault */
|
||||||
|
|
||||||
|
/* now we have a real cpu fault */
|
||||||
|
tb = tb_find_pc(pc);
|
||||||
|
if (tb) {
|
||||||
|
/* the PC is inside the translated code. It means that we have
|
||||||
|
a virtual CPU fault */
|
||||||
|
cpu_restore_state(tb, env, pc, puc);
|
||||||
|
}
|
||||||
|
if (ret == 1) {
|
||||||
|
#if 0
|
||||||
|
printf("PF exception: NIP=0x%08x error=0x%x %p\n",
|
||||||
|
env->nip, env->error_code, tb);
|
||||||
|
#endif
|
||||||
|
/* we restore the process signal mask as the sigreturn should
|
||||||
|
do it (XXX: use sigsetjmp) */
|
||||||
|
sigprocmask(SIG_SETMASK, old_set, NULL);
|
||||||
|
do_raise_exception_err(env->exception_index, env->error_code);
|
||||||
|
} else {
|
||||||
|
/* activate soft MMU for this block */
|
||||||
|
cpu_resume_from_signal(env, puc);
|
||||||
|
}
|
||||||
|
/* never comes here */
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
#error unsupported target CPU
|
#error unsupported target CPU
|
||||||
@@ -508,12 +789,33 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
|
|||||||
|
|
||||||
#if defined(__i386__)
|
#if defined(__i386__)
|
||||||
|
|
||||||
|
#if defined(USE_CODE_COPY)
|
||||||
|
static void cpu_send_trap(unsigned long pc, int trap,
|
||||||
|
struct ucontext *uc)
|
||||||
|
{
|
||||||
|
TranslationBlock *tb;
|
||||||
|
|
||||||
|
if (cpu_single_env)
|
||||||
|
env = cpu_single_env; /* XXX: find a correct solution for multithread */
|
||||||
|
/* now we have a real cpu fault */
|
||||||
|
tb = tb_find_pc(pc);
|
||||||
|
if (tb) {
|
||||||
|
/* the PC is inside the translated code. It means that we have
|
||||||
|
a virtual CPU fault */
|
||||||
|
cpu_restore_state(tb, env, pc, uc);
|
||||||
|
}
|
||||||
|
sigprocmask(SIG_SETMASK, &uc->uc_sigmask, NULL);
|
||||||
|
raise_exception_err(trap, env->error_code);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
int cpu_signal_handler(int host_signum, struct siginfo *info,
|
int cpu_signal_handler(int host_signum, struct siginfo *info,
|
||||||
void *puc)
|
void *puc)
|
||||||
{
|
{
|
||||||
struct ucontext *uc = puc;
|
struct ucontext *uc = puc;
|
||||||
unsigned long pc;
|
unsigned long pc;
|
||||||
|
int trapno;
|
||||||
|
|
||||||
#ifndef REG_EIP
|
#ifndef REG_EIP
|
||||||
/* for glibc 2.1 */
|
/* for glibc 2.1 */
|
||||||
#define REG_EIP EIP
|
#define REG_EIP EIP
|
||||||
@@ -521,34 +823,105 @@ int cpu_signal_handler(int host_signum, struct siginfo *info,
|
|||||||
#define REG_TRAPNO TRAPNO
|
#define REG_TRAPNO TRAPNO
|
||||||
#endif
|
#endif
|
||||||
pc = uc->uc_mcontext.gregs[REG_EIP];
|
pc = uc->uc_mcontext.gregs[REG_EIP];
|
||||||
return handle_cpu_signal(pc, (unsigned long)info->si_addr,
|
trapno = uc->uc_mcontext.gregs[REG_TRAPNO];
|
||||||
uc->uc_mcontext.gregs[REG_TRAPNO] == 0xe ?
|
#if defined(TARGET_I386) && defined(USE_CODE_COPY)
|
||||||
(uc->uc_mcontext.gregs[REG_ERR] >> 1) & 1 : 0,
|
if (trapno == 0x00 || trapno == 0x05) {
|
||||||
&uc->uc_sigmask);
|
/* send division by zero or bound exception */
|
||||||
|
cpu_send_trap(pc, trapno, uc);
|
||||||
|
return 1;
|
||||||
|
} else
|
||||||
|
#endif
|
||||||
|
return handle_cpu_signal(pc, (unsigned long)info->si_addr,
|
||||||
|
trapno == 0xe ?
|
||||||
|
(uc->uc_mcontext.gregs[REG_ERR] >> 1) & 1 : 0,
|
||||||
|
&uc->uc_sigmask, puc);
|
||||||
}
|
}
|
||||||
|
|
||||||
#elif defined(__powerpc)
|
#elif defined(__x86_64__)
|
||||||
|
|
||||||
int cpu_signal_handler(int host_signum, struct siginfo *info,
|
int cpu_signal_handler(int host_signum, struct siginfo *info,
|
||||||
|
void *puc)
|
||||||
|
{
|
||||||
|
struct ucontext *uc = puc;
|
||||||
|
unsigned long pc;
|
||||||
|
|
||||||
|
pc = uc->uc_mcontext.gregs[REG_RIP];
|
||||||
|
return handle_cpu_signal(pc, (unsigned long)info->si_addr,
|
||||||
|
uc->uc_mcontext.gregs[REG_TRAPNO] == 0xe ?
|
||||||
|
(uc->uc_mcontext.gregs[REG_ERR] >> 1) & 1 : 0,
|
||||||
|
&uc->uc_sigmask, puc);
|
||||||
|
}
|
||||||
|
|
||||||
|
#elif defined(__powerpc__)
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
* signal context platform-specific definitions
|
||||||
|
* From Wine
|
||||||
|
*/
|
||||||
|
#ifdef linux
|
||||||
|
/* All Registers access - only for local access */
|
||||||
|
# define REG_sig(reg_name, context) ((context)->uc_mcontext.regs->reg_name)
|
||||||
|
/* Gpr Registers access */
|
||||||
|
# define GPR_sig(reg_num, context) REG_sig(gpr[reg_num], context)
|
||||||
|
# define IAR_sig(context) REG_sig(nip, context) /* Program counter */
|
||||||
|
# define MSR_sig(context) REG_sig(msr, context) /* Machine State Register (Supervisor) */
|
||||||
|
# define CTR_sig(context) REG_sig(ctr, context) /* Count register */
|
||||||
|
# define XER_sig(context) REG_sig(xer, context) /* User's integer exception register */
|
||||||
|
# define LR_sig(context) REG_sig(link, context) /* Link register */
|
||||||
|
# define CR_sig(context) REG_sig(ccr, context) /* Condition register */
|
||||||
|
/* Float Registers access */
|
||||||
|
# define FLOAT_sig(reg_num, context) (((double*)((char*)((context)->uc_mcontext.regs+48*4)))[reg_num])
|
||||||
|
# define FPSCR_sig(context) (*(int*)((char*)((context)->uc_mcontext.regs+(48+32*2)*4)))
|
||||||
|
/* Exception Registers access */
|
||||||
|
# define DAR_sig(context) REG_sig(dar, context)
|
||||||
|
# define DSISR_sig(context) REG_sig(dsisr, context)
|
||||||
|
# define TRAP_sig(context) REG_sig(trap, context)
|
||||||
|
#endif /* linux */
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
# include <sys/ucontext.h>
|
||||||
|
typedef struct ucontext SIGCONTEXT;
|
||||||
|
/* All Registers access - only for local access */
|
||||||
|
# define REG_sig(reg_name, context) ((context)->uc_mcontext->ss.reg_name)
|
||||||
|
# define FLOATREG_sig(reg_name, context) ((context)->uc_mcontext->fs.reg_name)
|
||||||
|
# define EXCEPREG_sig(reg_name, context) ((context)->uc_mcontext->es.reg_name)
|
||||||
|
# define VECREG_sig(reg_name, context) ((context)->uc_mcontext->vs.reg_name)
|
||||||
|
/* Gpr Registers access */
|
||||||
|
# define GPR_sig(reg_num, context) REG_sig(r##reg_num, context)
|
||||||
|
# define IAR_sig(context) REG_sig(srr0, context) /* Program counter */
|
||||||
|
# define MSR_sig(context) REG_sig(srr1, context) /* Machine State Register (Supervisor) */
|
||||||
|
# define CTR_sig(context) REG_sig(ctr, context)
|
||||||
|
# define XER_sig(context) REG_sig(xer, context) /* Link register */
|
||||||
|
# define LR_sig(context) REG_sig(lr, context) /* User's integer exception register */
|
||||||
|
# define CR_sig(context) REG_sig(cr, context) /* Condition register */
|
||||||
|
/* Float Registers access */
|
||||||
|
# define FLOAT_sig(reg_num, context) FLOATREG_sig(fpregs[reg_num], context)
|
||||||
|
# define FPSCR_sig(context) ((double)FLOATREG_sig(fpscr, context))
|
||||||
|
/* Exception Registers access */
|
||||||
|
# define DAR_sig(context) EXCEPREG_sig(dar, context) /* Fault registers for coredump */
|
||||||
|
# define DSISR_sig(context) EXCEPREG_sig(dsisr, context)
|
||||||
|
# define TRAP_sig(context) EXCEPREG_sig(exception, context) /* number of powerpc exception taken */
|
||||||
|
#endif /* __APPLE__ */
|
||||||
|
|
||||||
|
int cpu_signal_handler(int host_signum, siginfo *info,
|
||||||
void *puc)
|
void *puc)
|
||||||
{
|
{
|
||||||
struct ucontext *uc = puc;
|
struct ucontext *uc = puc;
|
||||||
struct pt_regs *regs = uc->uc_mcontext.regs;
|
|
||||||
unsigned long pc;
|
unsigned long pc;
|
||||||
int is_write;
|
int is_write;
|
||||||
|
|
||||||
pc = regs->nip;
|
pc = IAR_sig(uc);
|
||||||
is_write = 0;
|
is_write = 0;
|
||||||
#if 0
|
#if 0
|
||||||
/* ppc 4xx case */
|
/* ppc 4xx case */
|
||||||
if (regs->dsisr & 0x00800000)
|
if (DSISR_sig(uc) & 0x00800000)
|
||||||
is_write = 1;
|
is_write = 1;
|
||||||
#else
|
#else
|
||||||
if (regs->trap != 0x400 && (regs->dsisr & 0x02000000))
|
if (TRAP_sig(uc) != 0x400 && (DSISR_sig(uc) & 0x02000000))
|
||||||
is_write = 1;
|
is_write = 1;
|
||||||
#endif
|
#endif
|
||||||
return handle_cpu_signal(pc, (unsigned long)info->si_addr,
|
return handle_cpu_signal(pc, (unsigned long)info->si_addr,
|
||||||
is_write, &uc->uc_sigmask);
|
is_write, &uc->uc_sigmask, puc);
|
||||||
}
|
}
|
||||||
|
|
||||||
#elif defined(__alpha__)
|
#elif defined(__alpha__)
|
||||||
@@ -578,7 +951,7 @@ int cpu_signal_handler(int host_signum, struct siginfo *info,
|
|||||||
}
|
}
|
||||||
|
|
||||||
return handle_cpu_signal(pc, (unsigned long)info->si_addr,
|
return handle_cpu_signal(pc, (unsigned long)info->si_addr,
|
||||||
is_write, &uc->uc_sigmask);
|
is_write, &uc->uc_sigmask, puc);
|
||||||
}
|
}
|
||||||
#elif defined(__sparc__)
|
#elif defined(__sparc__)
|
||||||
|
|
||||||
@@ -610,7 +983,7 @@ int cpu_signal_handler(int host_signum, struct siginfo *info,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return handle_cpu_signal(pc, (unsigned long)info->si_addr,
|
return handle_cpu_signal(pc, (unsigned long)info->si_addr,
|
||||||
is_write, sigmask);
|
is_write, sigmask, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
#elif defined(__arm__)
|
#elif defined(__arm__)
|
||||||
@@ -644,7 +1017,7 @@ int cpu_signal_handler(int host_signum, struct siginfo *info,
|
|||||||
is_write = 0;
|
is_write = 0;
|
||||||
return handle_cpu_signal(pc, (unsigned long)info->si_addr,
|
return handle_cpu_signal(pc, (unsigned long)info->si_addr,
|
||||||
is_write,
|
is_write,
|
||||||
&uc->uc_sigmask);
|
&uc->uc_sigmask, puc);
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
@@ -652,3 +1025,5 @@ int cpu_signal_handler(int host_signum, struct siginfo *info,
|
|||||||
#error host CPU specific signal handler needed
|
#error host CPU specific signal handler needed
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#endif /* !defined(CONFIG_SOFTMMU) */
|
||||||
@@ -16,7 +16,9 @@
|
|||||||
#define PARAMS(x) x
|
#define PARAMS(x) x
|
||||||
typedef void *PTR;
|
typedef void *PTR;
|
||||||
typedef uint64_t bfd_vma;
|
typedef uint64_t bfd_vma;
|
||||||
|
typedef int64_t bfd_signed_vma;
|
||||||
typedef uint8_t bfd_byte;
|
typedef uint8_t bfd_byte;
|
||||||
|
#define sprintf_vma(s,x) sprintf (s, "%0" PRIx64, x)
|
||||||
|
|
||||||
enum bfd_flavour {
|
enum bfd_flavour {
|
||||||
bfd_target_unknown_flavour,
|
bfd_target_unknown_flavour,
|
||||||
@@ -105,6 +107,9 @@ enum bfd_architecture
|
|||||||
bfd_arch_i386, /* Intel 386 */
|
bfd_arch_i386, /* Intel 386 */
|
||||||
#define bfd_mach_i386_i386 0
|
#define bfd_mach_i386_i386 0
|
||||||
#define bfd_mach_i386_i8086 1
|
#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_we32k, /* AT&T WE32xxx */
|
||||||
bfd_arch_tahoe, /* CCI/Harris Tahoe */
|
bfd_arch_tahoe, /* CCI/Harris Tahoe */
|
||||||
bfd_arch_i860, /* Intel 860 */
|
bfd_arch_i860, /* Intel 860 */
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
/* General "disassemble this chunk" code. Used for debugging. */
|
/* General "disassemble this chunk" code. Used for debugging. */
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "dis-asm.h"
|
#include "dis-asm.h"
|
||||||
#include "disas.h"
|
|
||||||
#include "elf.h"
|
#include "elf.h"
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|
||||||
#include "cpu.h"
|
#include "cpu.h"
|
||||||
#include "exec-all.h"
|
#include "exec-all.h"
|
||||||
|
#include "disas.h"
|
||||||
|
|
||||||
/* Filled in by elfload.c. Simplistic, but will do for now. */
|
/* Filled in by elfload.c. Simplistic, but will do for now. */
|
||||||
unsigned int disas_num_syms;
|
unsigned int disas_num_syms;
|
||||||
@@ -140,9 +140,12 @@ void disas(FILE *out, void *code, unsigned long size, int is_host, int flags)
|
|||||||
#else
|
#else
|
||||||
disasm_info.endian = BFD_ENDIAN_LITTLE;
|
disasm_info.endian = BFD_ENDIAN_LITTLE;
|
||||||
#endif
|
#endif
|
||||||
#ifdef __i386__
|
#if defined(__i386__)
|
||||||
disasm_info.mach = bfd_mach_i386_i386;
|
disasm_info.mach = bfd_mach_i386_i386;
|
||||||
print_insn = print_insn_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__)
|
#elif defined(__powerpc__)
|
||||||
print_insn = print_insn_ppc;
|
print_insn = print_insn_ppc;
|
||||||
#elif defined(__alpha__)
|
#elif defined(__alpha__)
|
||||||
@@ -171,6 +174,8 @@ void disas(FILE *out, void *code, unsigned long size, int is_host, int flags)
|
|||||||
print_insn = print_insn_arm;
|
print_insn = print_insn_arm;
|
||||||
#elif defined(TARGET_SPARC)
|
#elif defined(TARGET_SPARC)
|
||||||
print_insn = print_insn_sparc;
|
print_insn = print_insn_sparc;
|
||||||
|
#elif defined(TARGET_PPC)
|
||||||
|
print_insn = print_insn_ppc;
|
||||||
#else
|
#else
|
||||||
fprintf(out, "Asm output not supported on this arch\n");
|
fprintf(out, "Asm output not supported on this arch\n");
|
||||||
return;
|
return;
|
||||||
@@ -214,3 +219,71 @@ const char *lookup_symbol(void *orig_addr)
|
|||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if !defined(CONFIG_USER_ONLY)
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
void monitor_disas(target_ulong pc, int nb_insn, int is_physical, int flags)
|
||||||
|
{
|
||||||
|
FILE *out;
|
||||||
|
int count, i;
|
||||||
|
struct disassemble_info disasm_info;
|
||||||
|
int (*print_insn)(bfd_vma pc, disassemble_info *info);
|
||||||
|
|
||||||
|
out = stdout;
|
||||||
|
|
||||||
|
INIT_DISASSEMBLE_INFO(disasm_info, out, 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
|
||||||
|
fprintf(out, "Asm output not supported on this arch\n");
|
||||||
|
return;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
for(i = 0; i < nb_insn; i++) {
|
||||||
|
fprintf(out, "0x%08lx: ", (unsigned long)pc);
|
||||||
|
count = print_insn(pc, &disasm_info);
|
||||||
|
fprintf(out, "\n");
|
||||||
|
if (count < 0)
|
||||||
|
break;
|
||||||
|
pc += count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
/* Disassemble this for me please... (debugging). */
|
/* Disassemble this for me please... (debugging). */
|
||||||
void disas(FILE *out, void *code, unsigned long size, int is_host, int flags);
|
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. */
|
/* Look up symbol for debugging purpose. Returns "" if unknown. */
|
||||||
const char *lookup_symbol(void *orig_addr);
|
const char *lookup_symbol(void *orig_addr);
|
||||||
|
|||||||
+56
-9
@@ -17,31 +17,62 @@
|
|||||||
* License along with this library; if not, write to the Free Software
|
* License along with this library; if not, write to the Free Software
|
||||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
* 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 char uint8_t;
|
||||||
typedef unsigned short uint16_t;
|
typedef unsigned short uint16_t;
|
||||||
typedef unsigned int uint32_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;
|
typedef unsigned long long uint64_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
typedef signed char int8_t;
|
typedef signed char int8_t;
|
||||||
typedef signed short int16_t;
|
typedef signed short int16_t;
|
||||||
typedef signed int int32_t;
|
typedef signed int int32_t;
|
||||||
|
#if defined (__x86_64__)
|
||||||
|
typedef signed long int64_t;
|
||||||
|
#else
|
||||||
typedef signed long long int64_t;
|
typedef signed long long int64_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
#define bswap32(x) \
|
#define INT8_MIN (-128)
|
||||||
({ \
|
#define INT16_MIN (-32767-1)
|
||||||
uint32_t __x = (x); \
|
#define INT32_MIN (-2147483647-1)
|
||||||
((uint32_t)( \
|
#define INT64_MIN (-(int64_t)(9223372036854775807)-1)
|
||||||
(((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
|
#define INT8_MAX (127)
|
||||||
(((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \
|
#define INT16_MAX (32767)
|
||||||
(((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \
|
#define INT32_MAX (2147483647)
|
||||||
(((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) )); \
|
#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;
|
typedef struct FILE FILE;
|
||||||
extern int fprintf(FILE *, const char *, ...);
|
extern int fprintf(FILE *, const char *, ...);
|
||||||
extern int printf(const char *, ...);
|
extern int printf(const char *, ...);
|
||||||
|
#undef NULL
|
||||||
#define NULL 0
|
#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>
|
#include <fenv.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef __i386__
|
#ifdef __i386__
|
||||||
#define AREG0 "ebp"
|
#define AREG0 "ebp"
|
||||||
@@ -49,11 +80,21 @@ extern int printf(const char *, ...);
|
|||||||
#define AREG2 "esi"
|
#define AREG2 "esi"
|
||||||
#define AREG3 "edi"
|
#define AREG3 "edi"
|
||||||
#endif
|
#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__
|
#ifdef __powerpc__
|
||||||
#define AREG0 "r27"
|
#define AREG0 "r27"
|
||||||
#define AREG1 "r24"
|
#define AREG1 "r24"
|
||||||
#define AREG2 "r25"
|
#define AREG2 "r25"
|
||||||
#define AREG3 "r26"
|
#define AREG3 "r26"
|
||||||
|
/* XXX: suppress this hack */
|
||||||
|
#if defined(CONFIG_USER_ONLY)
|
||||||
#define AREG4 "r16"
|
#define AREG4 "r16"
|
||||||
#define AREG5 "r17"
|
#define AREG5 "r17"
|
||||||
#define AREG6 "r18"
|
#define AREG6 "r18"
|
||||||
@@ -62,6 +103,7 @@ extern int printf(const char *, ...);
|
|||||||
#define AREG9 "r21"
|
#define AREG9 "r21"
|
||||||
#define AREG10 "r22"
|
#define AREG10 "r22"
|
||||||
#define AREG11 "r23"
|
#define AREG11 "r23"
|
||||||
|
#endif
|
||||||
#define USE_INT_TO_FLOAT_HELPERS
|
#define USE_INT_TO_FLOAT_HELPERS
|
||||||
#define BUGGY_GCC_DIV64
|
#define BUGGY_GCC_DIV64
|
||||||
#endif
|
#endif
|
||||||
@@ -166,6 +208,9 @@ extern int __op_jmp0, __op_jmp1, __op_jmp2, __op_jmp3;
|
|||||||
#ifdef __i386__
|
#ifdef __i386__
|
||||||
#define EXIT_TB() asm volatile ("ret")
|
#define EXIT_TB() asm volatile ("ret")
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef __x86_64__
|
||||||
|
#define EXIT_TB() asm volatile ("ret")
|
||||||
|
#endif
|
||||||
#ifdef __powerpc__
|
#ifdef __powerpc__
|
||||||
#define EXIT_TB() asm volatile ("blr")
|
#define EXIT_TB() asm volatile ("blr")
|
||||||
#endif
|
#endif
|
||||||
@@ -188,3 +233,5 @@ extern int __op_jmp0, __op_jmp1, __op_jmp2, __op_jmp3;
|
|||||||
#ifdef __mc68000
|
#ifdef __mc68000
|
||||||
#define EXIT_TB() asm volatile ("rts")
|
#define EXIT_TB() asm volatile ("rts")
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#endif /* !defined(__DYNGEN_EXEC_H__) */
|
||||||
@@ -27,6 +27,12 @@ static inline void flush_icache_range(unsigned long start, unsigned long stop)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef __x86_64__
|
||||||
|
static inline void flush_icache_range(unsigned long start, unsigned long stop)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef __s390__
|
#ifdef __s390__
|
||||||
static inline void flush_icache_range(unsigned long start, unsigned long stop)
|
static inline void flush_icache_range(unsigned long start, unsigned long stop)
|
||||||
{
|
{
|
||||||
|
|||||||
+199
-38
@@ -59,6 +59,11 @@ extern uint32_t gen_opc_pc[OPC_BUF_SIZE];
|
|||||||
extern uint8_t gen_opc_cc_op[OPC_BUF_SIZE];
|
extern uint8_t gen_opc_cc_op[OPC_BUF_SIZE];
|
||||||
extern uint8_t gen_opc_instr_start[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)
|
#if defined(TARGET_I386)
|
||||||
|
|
||||||
void optimize_flags_init(void);
|
void optimize_flags_init(void);
|
||||||
@@ -74,13 +79,24 @@ void dump_ops(const uint16_t *opc_buf, const uint32_t *opparam_buf);
|
|||||||
int cpu_gen_code(CPUState *env, struct TranslationBlock *tb,
|
int cpu_gen_code(CPUState *env, struct TranslationBlock *tb,
|
||||||
int max_code_size, int *gen_code_size_ptr);
|
int max_code_size, int *gen_code_size_ptr);
|
||||||
int cpu_restore_state(struct TranslationBlock *tb,
|
int cpu_restore_state(struct TranslationBlock *tb,
|
||||||
CPUState *env, unsigned long searched_pc);
|
CPUState *env, unsigned long searched_pc,
|
||||||
|
void *puc);
|
||||||
|
int cpu_gen_code_copy(CPUState *env, struct TranslationBlock *tb,
|
||||||
|
int max_code_size, int *gen_code_size_ptr);
|
||||||
|
int cpu_restore_state_copy(struct TranslationBlock *tb,
|
||||||
|
CPUState *env, unsigned long searched_pc,
|
||||||
|
void *puc);
|
||||||
|
void cpu_resume_from_signal(CPUState *env1, void *puc);
|
||||||
void cpu_exec_init(void);
|
void cpu_exec_init(void);
|
||||||
int page_unprotect(unsigned long address);
|
int page_unprotect(unsigned long address, unsigned long pc, void *puc);
|
||||||
void page_unmap(void);
|
void tb_invalidate_phys_page_range(target_ulong start, target_ulong end,
|
||||||
void tlb_flush_page(CPUState *env, uint32_t addr);
|
int is_cpu_write_access);
|
||||||
void tlb_flush_page_write(CPUState *env, uint32_t addr);
|
void tb_invalidate_page_range(target_ulong start, target_ulong end);
|
||||||
void tlb_flush(CPUState *env);
|
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_MAX_SIZE 65536
|
||||||
#define CODE_GEN_ALIGN 16 /* must be >= of the size of a icache line */
|
#define CODE_GEN_ALIGN 16 /* must be >= of the size of a icache line */
|
||||||
@@ -88,23 +104,71 @@ void tlb_flush(CPUState *env);
|
|||||||
#define CODE_GEN_HASH_BITS 15
|
#define CODE_GEN_HASH_BITS 15
|
||||||
#define CODE_GEN_HASH_SIZE (1 << CODE_GEN_HASH_BITS)
|
#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 */
|
/* maximum total translate dcode allocated */
|
||||||
#define CODE_GEN_BUFFER_SIZE (2048 * 1024)
|
|
||||||
|
/* NOTE: the translated code area cannot be too big because on some
|
||||||
|
archs the range of "fast" function calls is limited. Here is a
|
||||||
|
summary of the ranges:
|
||||||
|
|
||||||
|
i386 : signed 32 bits
|
||||||
|
arm : signed 26 bits
|
||||||
|
ppc : signed 24 bits
|
||||||
|
sparc : signed 32 bits
|
||||||
|
alpha : signed 23 bits
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if defined(__alpha__)
|
||||||
|
#define CODE_GEN_BUFFER_SIZE (2 * 1024 * 1024)
|
||||||
|
#elif defined(__powerpc__)
|
||||||
|
#define CODE_GEN_BUFFER_SIZE (6 * 1024 * 1024)
|
||||||
|
#else
|
||||||
|
#define CODE_GEN_BUFFER_SIZE (8 * 1024 * 1024)
|
||||||
|
#endif
|
||||||
|
|
||||||
//#define CODE_GEN_BUFFER_SIZE (128 * 1024)
|
//#define CODE_GEN_BUFFER_SIZE (128 * 1024)
|
||||||
|
|
||||||
#if defined(__powerpc__)
|
/* estimated block size for TB allocation */
|
||||||
|
/* XXX: use a per code average code fragment size and modulate it
|
||||||
|
according to the host CPU */
|
||||||
|
#if defined(CONFIG_SOFTMMU)
|
||||||
|
#define CODE_GEN_AVG_BLOCK_SIZE 128
|
||||||
|
#else
|
||||||
|
#define CODE_GEN_AVG_BLOCK_SIZE 64
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define CODE_GEN_MAX_BLOCKS (CODE_GEN_BUFFER_SIZE / CODE_GEN_AVG_BLOCK_SIZE)
|
||||||
|
|
||||||
|
#if defined(__powerpc__)
|
||||||
|
#define USE_DIRECT_JUMP
|
||||||
|
#endif
|
||||||
|
#if defined(__i386__) && !defined(_WIN32)
|
||||||
#define USE_DIRECT_JUMP
|
#define USE_DIRECT_JUMP
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef struct TranslationBlock {
|
typedef struct TranslationBlock {
|
||||||
unsigned long pc; /* simulated PC corresponding to this block (EIP + CS base) */
|
target_ulong pc; /* simulated PC corresponding to this block (EIP + CS base) */
|
||||||
unsigned long cs_base; /* CS base for this block */
|
target_ulong cs_base; /* CS base for this block */
|
||||||
unsigned int flags; /* flags defining in which context the code was generated */
|
unsigned int flags; /* flags defining in which context the code was generated */
|
||||||
uint16_t size; /* size of target code for this block (1 <=
|
uint16_t size; /* size of target code for this block (1 <=
|
||||||
size <= TARGET_PAGE_SIZE) */
|
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 */
|
uint8_t *tc_ptr; /* pointer to the translated code */
|
||||||
struct TranslationBlock *hash_next; /* next matching block */
|
struct TranslationBlock *hash_next; /* next matching tb for virtual address */
|
||||||
struct TranslationBlock *page_next[2]; /* next blocks in even/odd page */
|
/* 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 following data are used to directly call another TB from
|
||||||
the code of this one. */
|
the code of this one. */
|
||||||
uint16_t tb_next_offset[2]; /* offset of original jump target */
|
uint16_t tb_next_offset[2]; /* offset of original jump target */
|
||||||
@@ -126,11 +190,19 @@ static inline unsigned int tb_hash_func(unsigned long pc)
|
|||||||
return pc & (CODE_GEN_HASH_SIZE - 1);
|
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);
|
TranslationBlock *tb_alloc(unsigned long pc);
|
||||||
void tb_flush(void);
|
void tb_flush(CPUState *env);
|
||||||
void tb_link(TranslationBlock *tb);
|
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_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_buffer[CODE_GEN_BUFFER_SIZE];
|
||||||
extern uint8_t *code_gen_ptr;
|
extern uint8_t *code_gen_ptr;
|
||||||
@@ -138,8 +210,8 @@ extern uint8_t *code_gen_ptr;
|
|||||||
/* find a translation block in the translation cache. If not found,
|
/* 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 */
|
return NULL and the pointer to the last element of the list in pptb */
|
||||||
static inline TranslationBlock *tb_find(TranslationBlock ***pptb,
|
static inline TranslationBlock *tb_find(TranslationBlock ***pptb,
|
||||||
unsigned long pc,
|
target_ulong pc,
|
||||||
unsigned long cs_base,
|
target_ulong cs_base,
|
||||||
unsigned int flags)
|
unsigned int flags)
|
||||||
{
|
{
|
||||||
TranslationBlock **ptb, *tb;
|
TranslationBlock **ptb, *tb;
|
||||||
@@ -159,8 +231,10 @@ static inline TranslationBlock *tb_find(TranslationBlock ***pptb,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(__powerpc__)
|
|
||||||
|
|
||||||
|
#if defined(USE_DIRECT_JUMP)
|
||||||
|
|
||||||
|
#if defined(__powerpc__)
|
||||||
static inline void tb_set_jmp_target1(unsigned long jmp_addr, unsigned long addr)
|
static inline void tb_set_jmp_target1(unsigned long jmp_addr, unsigned long addr)
|
||||||
{
|
{
|
||||||
uint32_t val, *ptr;
|
uint32_t val, *ptr;
|
||||||
@@ -177,6 +251,14 @@ static inline void tb_set_jmp_target1(unsigned long jmp_addr, unsigned long addr
|
|||||||
asm volatile ("sync" : : : "memory");
|
asm volatile ("sync" : : : "memory");
|
||||||
asm volatile ("isync" : : : "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,
|
static inline void tb_set_jmp_target(TranslationBlock *tb,
|
||||||
int n, unsigned long addr)
|
int n, unsigned long addr)
|
||||||
@@ -221,16 +303,29 @@ TranslationBlock *tb_find_pc(unsigned long pc_ptr);
|
|||||||
#define offsetof(type, field) ((size_t) &((type *)0)->field)
|
#define offsetof(type, field) ((size_t) &((type *)0)->field)
|
||||||
#endif
|
#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__)
|
#if defined(__powerpc__)
|
||||||
|
|
||||||
/* on PowerPC we patch the jump instruction directly */
|
/* we patch the jump instruction directly */
|
||||||
#define JUMP_TB(opname, tbparam, n, eip)\
|
#define JUMP_TB(opname, tbparam, n, eip)\
|
||||||
do {\
|
do {\
|
||||||
asm volatile (".section \".data\"\n"\
|
asm volatile (ASM_DATA_SECTION\
|
||||||
"__op_label" #n "." stringify(opname) ":\n"\
|
ASM_NAME(__op_label) #n "." ASM_NAME(opname) ":\n"\
|
||||||
".long 1f\n"\
|
".long 1f\n"\
|
||||||
".previous\n"\
|
ASM_PREVIOUS_SECTION \
|
||||||
"b __op_jmp" #n "\n"\
|
"b " ASM_NAME(__op_jmp) #n "\n"\
|
||||||
"1:\n");\
|
"1:\n");\
|
||||||
T0 = (long)(tbparam) + (n);\
|
T0 = (long)(tbparam) + (n);\
|
||||||
EIP = eip;\
|
EIP = eip;\
|
||||||
@@ -239,7 +334,28 @@ do {\
|
|||||||
|
|
||||||
#define JUMP_TB2(opname, tbparam, n)\
|
#define JUMP_TB2(opname, tbparam, n)\
|
||||||
do {\
|
do {\
|
||||||
asm volatile ("b __op_jmp%0\n" : : "i" (n + 2));\
|
asm volatile ("b " ASM_NAME(__op_jmp) #n "\n");\
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#elif defined(__i386__) && defined(USE_DIRECT_JUMP)
|
||||||
|
|
||||||
|
/* we patch the jump instruction directly */
|
||||||
|
#define JUMP_TB(opname, tbparam, n, eip)\
|
||||||
|
do {\
|
||||||
|
asm volatile (".section .data\n"\
|
||||||
|
ASM_NAME(__op_label) #n "." ASM_NAME(opname) ":\n"\
|
||||||
|
".long 1f\n"\
|
||||||
|
ASM_PREVIOUS_SECTION \
|
||||||
|
"jmp " ASM_NAME(__op_jmp) #n "\n"\
|
||||||
|
"1:\n");\
|
||||||
|
T0 = (long)(tbparam) + (n);\
|
||||||
|
EIP = eip;\
|
||||||
|
EXIT_TB();\
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define JUMP_TB2(opname, tbparam, n)\
|
||||||
|
do {\
|
||||||
|
asm volatile ("jmp " ASM_NAME(__op_jmp) #n "\n");\
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#else
|
#else
|
||||||
@@ -261,32 +377,25 @@ dummy_label ## n:\
|
|||||||
/* second jump to same destination 'n' */
|
/* second jump to same destination 'n' */
|
||||||
#define JUMP_TB2(opname, tbparam, n)\
|
#define JUMP_TB2(opname, tbparam, n)\
|
||||||
do {\
|
do {\
|
||||||
goto *(void *)(((TranslationBlock *)tbparam)->tb_next[n]);\
|
goto *(void *)(((TranslationBlock *)tbparam)->tb_next[n - 2]);\
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* physical memory access */
|
|
||||||
#define IO_MEM_NB_ENTRIES 256
|
|
||||||
#define TLB_INVALID_MASK (1 << 3)
|
|
||||||
#define IO_MEM_SHIFT 4
|
|
||||||
#define IO_MEM_UNASSIGNED (1 << IO_MEM_SHIFT)
|
|
||||||
|
|
||||||
unsigned long physpage_find(unsigned long page);
|
|
||||||
|
|
||||||
extern CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4];
|
extern CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4];
|
||||||
extern CPUReadMemoryFunc *io_mem_read[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__
|
#ifdef __powerpc__
|
||||||
static inline int testandset (int *p)
|
static inline int testandset (int *p)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
__asm__ __volatile__ (
|
__asm__ __volatile__ (
|
||||||
"0: lwarx %0,0,%1 ;"
|
"0: lwarx %0,0,%1\n"
|
||||||
" xor. %0,%3,%0;"
|
" xor. %0,%3,%0\n"
|
||||||
" bne 1f;"
|
" bne 1f\n"
|
||||||
" stwcx. %2,0,%1;"
|
" stwcx. %2,0,%1\n"
|
||||||
" bne- 0b;"
|
" bne- 0b\n"
|
||||||
"1: "
|
"1: "
|
||||||
: "=&r" (ret)
|
: "=&r" (ret)
|
||||||
: "r" (p), "r" (1), "r" (0)
|
: "r" (p), "r" (1), "r" (0)
|
||||||
@@ -309,6 +418,20 @@ static inline int testandset (int *p)
|
|||||||
}
|
}
|
||||||
#endif
|
#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__
|
#ifdef __s390__
|
||||||
static inline int testandset (int *p)
|
static inline int testandset (int *p)
|
||||||
{
|
{
|
||||||
@@ -384,7 +507,7 @@ typedef int spinlock_t;
|
|||||||
|
|
||||||
#define SPIN_LOCK_UNLOCKED 0
|
#define SPIN_LOCK_UNLOCKED 0
|
||||||
|
|
||||||
#if 1
|
#if defined(CONFIG_USER_ONLY)
|
||||||
static inline void spin_lock(spinlock_t *lock)
|
static inline void spin_lock(spinlock_t *lock)
|
||||||
{
|
{
|
||||||
while (testandset(lock));
|
while (testandset(lock));
|
||||||
@@ -416,8 +539,10 @@ static inline int spin_trylock(spinlock_t *lock)
|
|||||||
|
|
||||||
extern spinlock_t tb_lock;
|
extern spinlock_t tb_lock;
|
||||||
|
|
||||||
|
extern int tb_invalidated_flag;
|
||||||
|
|
||||||
#if defined(TARGET_I386) && !defined(CONFIG_USER_ONLY)
|
#if (defined(TARGET_I386) || defined(TARGET_PPC)) && \
|
||||||
|
!defined(CONFIG_USER_ONLY)
|
||||||
|
|
||||||
void tlb_fill(unsigned long addr, int is_write, int is_user,
|
void tlb_fill(unsigned long addr, int is_write, int is_user,
|
||||||
void *retaddr);
|
void *retaddr);
|
||||||
@@ -440,3 +565,39 @@ void tlb_fill(unsigned long addr, int is_write, int is_user,
|
|||||||
#undef env
|
#undef env
|
||||||
|
|
||||||
#endif
|
#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;
|
||||||
|
#else
|
||||||
|
#error "Unimplemented !"
|
||||||
|
#endif
|
||||||
|
if (__builtin_expect(env->tlb_read[is_user][index].address !=
|
||||||
|
(addr & TARGET_PAGE_MASK), 0)) {
|
||||||
|
#if defined (TARGET_PPC)
|
||||||
|
env->access_type = ACCESS_CODE;
|
||||||
|
ldub_code((void *)addr);
|
||||||
|
env->access_type = ACCESS_INT;
|
||||||
|
#else
|
||||||
|
ldub_code((void *)addr);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
return addr + env->tlb_read[is_user][index].addend - (unsigned long)phys_ram_base;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
@@ -17,81 +17,39 @@
|
|||||||
* License along with this library; if not, write to the Free Software
|
* License along with this library; if not, write to the Free Software
|
||||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
#include <stdlib.h>
|
#include "vl.h"
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
#include <netinet/tcp.h>
|
#include <netinet/tcp.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
#include "cpu.h"
|
|
||||||
#include "thunk.h"
|
|
||||||
#include "exec-all.h"
|
|
||||||
|
|
||||||
//#define DEBUG_GDB
|
//#define DEBUG_GDB
|
||||||
|
|
||||||
int gdbstub_fd = -1;
|
enum RSState {
|
||||||
|
RS_IDLE,
|
||||||
|
RS_GETLINE,
|
||||||
|
RS_CHKSUM1,
|
||||||
|
RS_CHKSUM2,
|
||||||
|
};
|
||||||
|
|
||||||
/* return 0 if OK */
|
static int gdbserver_fd;
|
||||||
static int gdbstub_open(int port)
|
|
||||||
{
|
|
||||||
struct sockaddr_in sockaddr;
|
|
||||||
socklen_t len;
|
|
||||||
int fd, val, ret;
|
|
||||||
|
|
||||||
fd = socket(PF_INET, SOCK_STREAM, 0);
|
typedef struct GDBState {
|
||||||
if (fd < 0) {
|
enum RSState state;
|
||||||
perror("socket");
|
int fd;
|
||||||
return -1;
|
char line_buf[4096];
|
||||||
}
|
int line_buf_index;
|
||||||
|
int line_csum;
|
||||||
|
} GDBState;
|
||||||
|
|
||||||
/* allow fast reuse */
|
static int get_char(GDBState *s)
|
||||||
val = 1;
|
|
||||||
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
|
|
||||||
|
|
||||||
sockaddr.sin_family = AF_INET;
|
|
||||||
sockaddr.sin_port = htons(port);
|
|
||||||
sockaddr.sin_addr.s_addr = 0;
|
|
||||||
ret = bind(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr));
|
|
||||||
if (ret < 0) {
|
|
||||||
perror("bind");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
ret = listen(fd, 0);
|
|
||||||
if (ret < 0) {
|
|
||||||
perror("listen");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* now wait for one connection */
|
|
||||||
for(;;) {
|
|
||||||
len = sizeof(sockaddr);
|
|
||||||
gdbstub_fd = accept(fd, (struct sockaddr *)&sockaddr, &len);
|
|
||||||
if (gdbstub_fd < 0 && errno != EINTR) {
|
|
||||||
perror("accept");
|
|
||||||
return -1;
|
|
||||||
} else if (gdbstub_fd >= 0) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* set short latency */
|
|
||||||
val = 1;
|
|
||||||
setsockopt(gdbstub_fd, SOL_TCP, TCP_NODELAY, &val, sizeof(val));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int get_char(void)
|
|
||||||
{
|
{
|
||||||
uint8_t ch;
|
uint8_t ch;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
for(;;) {
|
for(;;) {
|
||||||
ret = read(gdbstub_fd, &ch, 1);
|
ret = read(s->fd, &ch, 1);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
if (errno != EINTR && errno != EAGAIN)
|
if (errno != EINTR && errno != EAGAIN)
|
||||||
return -1;
|
return -1;
|
||||||
@@ -104,12 +62,12 @@ static int get_char(void)
|
|||||||
return ch;
|
return ch;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void put_buffer(const uint8_t *buf, int len)
|
static void put_buffer(GDBState *s, const uint8_t *buf, int len)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
while (len > 0) {
|
while (len > 0) {
|
||||||
ret = write(gdbstub_fd, buf, len);
|
ret = write(s->fd, buf, len);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
if (errno != EINTR && errno != EAGAIN)
|
if (errno != EINTR && errno != EAGAIN)
|
||||||
return;
|
return;
|
||||||
@@ -163,59 +121,8 @@ static void hextomem(uint8_t *mem, const char *buf, int len)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* return -1 if error or EOF */
|
|
||||||
static int get_packet(char *buf, int buf_size)
|
|
||||||
{
|
|
||||||
int ch, len, csum, csum1;
|
|
||||||
char reply[1];
|
|
||||||
|
|
||||||
for(;;) {
|
|
||||||
for(;;) {
|
|
||||||
ch = get_char();
|
|
||||||
if (ch < 0)
|
|
||||||
return -1;
|
|
||||||
if (ch == '$')
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
len = 0;
|
|
||||||
csum = 0;
|
|
||||||
for(;;) {
|
|
||||||
ch = get_char();
|
|
||||||
if (ch < 0)
|
|
||||||
return -1;
|
|
||||||
if (ch == '#')
|
|
||||||
break;
|
|
||||||
if (len > buf_size - 1)
|
|
||||||
return -1;
|
|
||||||
buf[len++] = ch;
|
|
||||||
csum += ch;
|
|
||||||
}
|
|
||||||
buf[len] = '\0';
|
|
||||||
ch = get_char();
|
|
||||||
if (ch < 0)
|
|
||||||
return -1;
|
|
||||||
csum1 = fromhex(ch) << 4;
|
|
||||||
ch = get_char();
|
|
||||||
if (ch < 0)
|
|
||||||
return -1;
|
|
||||||
csum1 |= fromhex(ch);
|
|
||||||
if ((csum & 0xff) != csum1) {
|
|
||||||
reply[0] = '-';
|
|
||||||
put_buffer(reply, 1);
|
|
||||||
} else {
|
|
||||||
reply[0] = '+';
|
|
||||||
put_buffer(reply, 1);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#ifdef DEBUG_GDB
|
|
||||||
printf("command='%s'\n", buf);
|
|
||||||
#endif
|
|
||||||
return len;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* return -1 if error, 0 if OK */
|
/* return -1 if error, 0 if OK */
|
||||||
static int put_packet(char *buf)
|
static int put_packet(GDBState *s, char *buf)
|
||||||
{
|
{
|
||||||
char buf1[3];
|
char buf1[3];
|
||||||
int len, csum, ch, i;
|
int len, csum, ch, i;
|
||||||
@@ -226,9 +133,9 @@ static int put_packet(char *buf)
|
|||||||
|
|
||||||
for(;;) {
|
for(;;) {
|
||||||
buf1[0] = '$';
|
buf1[0] = '$';
|
||||||
put_buffer(buf1, 1);
|
put_buffer(s, buf1, 1);
|
||||||
len = strlen(buf);
|
len = strlen(buf);
|
||||||
put_buffer(buf, len);
|
put_buffer(s, buf, len);
|
||||||
csum = 0;
|
csum = 0;
|
||||||
for(i = 0; i < len; i++) {
|
for(i = 0; i < len; i++) {
|
||||||
csum += buf[i];
|
csum += buf[i];
|
||||||
@@ -237,9 +144,9 @@ static int put_packet(char *buf)
|
|||||||
buf1[1] = tohex((csum >> 4) & 0xf);
|
buf1[1] = tohex((csum >> 4) & 0xf);
|
||||||
buf1[2] = tohex((csum) & 0xf);
|
buf1[2] = tohex((csum) & 0xf);
|
||||||
|
|
||||||
put_buffer(buf1, 3);
|
put_buffer(s, buf1, 3);
|
||||||
|
|
||||||
ch = get_char();
|
ch = get_char(s);
|
||||||
if (ch < 0)
|
if (ch < 0)
|
||||||
return -1;
|
return -1;
|
||||||
if (ch == '+')
|
if (ch == '+')
|
||||||
@@ -248,126 +155,58 @@ static int put_packet(char *buf)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int memory_rw(uint8_t *buf, uint32_t addr, int len, int is_write)
|
#if defined(TARGET_I386)
|
||||||
{
|
|
||||||
int l, flags;
|
|
||||||
uint32_t page;
|
|
||||||
|
|
||||||
while (len > 0) {
|
static void to_le32(uint8_t *p, int v)
|
||||||
page = addr & TARGET_PAGE_MASK;
|
{
|
||||||
l = (page + TARGET_PAGE_SIZE) - addr;
|
p[0] = v;
|
||||||
if (l > len)
|
p[1] = v >> 8;
|
||||||
l = len;
|
p[2] = v >> 16;
|
||||||
flags = page_get_flags(page);
|
p[3] = v >> 24;
|
||||||
if (!(flags & PAGE_VALID))
|
|
||||||
return -1;
|
|
||||||
if (is_write) {
|
|
||||||
if (!(flags & PAGE_WRITE))
|
|
||||||
return -1;
|
|
||||||
memcpy((uint8_t *)addr, buf, l);
|
|
||||||
} else {
|
|
||||||
if (!(flags & PAGE_READ))
|
|
||||||
return -1;
|
|
||||||
memcpy(buf, (uint8_t *)addr, l);
|
|
||||||
}
|
|
||||||
len -= l;
|
|
||||||
buf += l;
|
|
||||||
addr += l;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* port = 0 means default port */
|
static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf)
|
||||||
int cpu_gdbstub(void *opaque, int (*main_loop)(void *opaque), int port)
|
|
||||||
{
|
{
|
||||||
CPUState *env;
|
int i, fpus;
|
||||||
const char *p;
|
|
||||||
int ret, ch, nb_regs, i, type;
|
for(i = 0; i < 8; i++) {
|
||||||
char buf[4096];
|
to_le32(mem_buf + i * 4, env->regs[i]);
|
||||||
uint8_t mem_buf[2000];
|
}
|
||||||
uint32_t *registers;
|
to_le32(mem_buf + 8 * 4, env->eip);
|
||||||
uint32_t addr, len;
|
to_le32(mem_buf + 9 * 4, env->eflags);
|
||||||
|
to_le32(mem_buf + 10 * 4, env->segs[R_CS].selector);
|
||||||
printf("Waiting gdb connection on port %d\n", port);
|
to_le32(mem_buf + 11 * 4, env->segs[R_SS].selector);
|
||||||
if (gdbstub_open(port) < 0)
|
to_le32(mem_buf + 12 * 4, env->segs[R_DS].selector);
|
||||||
return -1;
|
to_le32(mem_buf + 13 * 4, env->segs[R_ES].selector);
|
||||||
printf("Connected\n");
|
to_le32(mem_buf + 14 * 4, env->segs[R_FS].selector);
|
||||||
for(;;) {
|
to_le32(mem_buf + 15 * 4, env->segs[R_GS].selector);
|
||||||
ret = get_packet(buf, sizeof(buf));
|
/* XXX: convert floats */
|
||||||
if (ret < 0)
|
for(i = 0; i < 8; i++) {
|
||||||
break;
|
memcpy(mem_buf + 16 * 4 + i * 10, &env->fpregs[i], 10);
|
||||||
p = buf;
|
}
|
||||||
ch = *p++;
|
to_le32(mem_buf + 36 * 4, env->fpuc);
|
||||||
switch(ch) {
|
fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
|
||||||
case '?':
|
to_le32(mem_buf + 37 * 4, fpus);
|
||||||
snprintf(buf, sizeof(buf), "S%02x", SIGTRAP);
|
to_le32(mem_buf + 38 * 4, 0); /* XXX: convert tags */
|
||||||
put_packet(buf);
|
to_le32(mem_buf + 39 * 4, 0); /* fiseg */
|
||||||
break;
|
to_le32(mem_buf + 40 * 4, 0); /* fioff */
|
||||||
case 'c':
|
to_le32(mem_buf + 41 * 4, 0); /* foseg */
|
||||||
if (*p != '\0') {
|
to_le32(mem_buf + 42 * 4, 0); /* fooff */
|
||||||
addr = strtoul(p, (char **)&p, 16);
|
to_le32(mem_buf + 43 * 4, 0); /* fop */
|
||||||
env = cpu_gdbstub_get_env(opaque);
|
return 44 * 4;
|
||||||
#if defined(TARGET_I386)
|
}
|
||||||
env->eip = addr;
|
|
||||||
#endif
|
static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size)
|
||||||
}
|
{
|
||||||
ret = main_loop(opaque);
|
uint32_t *registers = (uint32_t *)mem_buf;
|
||||||
if (ret == EXCP_DEBUG)
|
int i;
|
||||||
ret = SIGTRAP;
|
|
||||||
else
|
for(i = 0; i < 8; i++) {
|
||||||
ret = 0;
|
env->regs[i] = tswapl(registers[i]);
|
||||||
snprintf(buf, sizeof(buf), "S%02x", ret);
|
}
|
||||||
put_packet(buf);
|
env->eip = registers[8];
|
||||||
break;
|
env->eflags = registers[9];
|
||||||
case 's':
|
#if defined(CONFIG_USER_ONLY)
|
||||||
env = cpu_gdbstub_get_env(opaque);
|
|
||||||
if (*p != '\0') {
|
|
||||||
addr = strtoul(p, (char **)&p, 16);
|
|
||||||
#if defined(TARGET_I386)
|
|
||||||
env->eip = addr;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
cpu_single_step(env, 1);
|
|
||||||
ret = main_loop(opaque);
|
|
||||||
cpu_single_step(env, 0);
|
|
||||||
if (ret == EXCP_DEBUG)
|
|
||||||
ret = SIGTRAP;
|
|
||||||
else
|
|
||||||
ret = 0;
|
|
||||||
snprintf(buf, sizeof(buf), "S%02x", ret);
|
|
||||||
put_packet(buf);
|
|
||||||
break;
|
|
||||||
case 'g':
|
|
||||||
env = cpu_gdbstub_get_env(opaque);
|
|
||||||
registers = (void *)mem_buf;
|
|
||||||
#if defined(TARGET_I386)
|
|
||||||
for(i = 0; i < 8; i++) {
|
|
||||||
registers[i] = tswapl(env->regs[i]);
|
|
||||||
}
|
|
||||||
registers[8] = env->eip;
|
|
||||||
registers[9] = env->eflags;
|
|
||||||
registers[10] = env->segs[R_CS].selector;
|
|
||||||
registers[11] = env->segs[R_SS].selector;
|
|
||||||
registers[12] = env->segs[R_DS].selector;
|
|
||||||
registers[13] = env->segs[R_ES].selector;
|
|
||||||
registers[14] = env->segs[R_FS].selector;
|
|
||||||
registers[15] = env->segs[R_GS].selector;
|
|
||||||
nb_regs = 16;
|
|
||||||
#endif
|
|
||||||
memtohex(buf, (const uint8_t *)registers,
|
|
||||||
sizeof(registers[0]) * nb_regs);
|
|
||||||
put_packet(buf);
|
|
||||||
break;
|
|
||||||
case 'G':
|
|
||||||
env = cpu_gdbstub_get_env(opaque);
|
|
||||||
registers = (void *)mem_buf;
|
|
||||||
#if defined(TARGET_I386)
|
|
||||||
hextomem((uint8_t *)registers, p, 16 * 4);
|
|
||||||
for(i = 0; i < 8; i++) {
|
|
||||||
env->regs[i] = tswapl(registers[i]);
|
|
||||||
}
|
|
||||||
env->eip = registers[8];
|
|
||||||
env->eflags = registers[9];
|
|
||||||
#define LOAD_SEG(index, sreg)\
|
#define LOAD_SEG(index, sreg)\
|
||||||
if (tswapl(registers[index]) != env->segs[sreg].selector)\
|
if (tswapl(registers[index]) != env->segs[sreg].selector)\
|
||||||
cpu_x86_load_seg(env, sreg, tswapl(registers[index]));
|
cpu_x86_load_seg(env, sreg, tswapl(registers[index]));
|
||||||
@@ -378,88 +217,379 @@ int cpu_gdbstub(void *opaque, int (*main_loop)(void *opaque), int port)
|
|||||||
LOAD_SEG(14, R_FS);
|
LOAD_SEG(14, R_FS);
|
||||||
LOAD_SEG(15, R_GS);
|
LOAD_SEG(15, R_GS);
|
||||||
#endif
|
#endif
|
||||||
put_packet("OK");
|
}
|
||||||
break;
|
|
||||||
case 'm':
|
#elif defined (TARGET_PPC)
|
||||||
|
static void to_le32(uint32_t *buf, uint32_t v)
|
||||||
|
{
|
||||||
|
uint8_t *p = (uint8_t *)buf;
|
||||||
|
p[3] = v;
|
||||||
|
p[2] = v >> 8;
|
||||||
|
p[1] = v >> 16;
|
||||||
|
p[0] = v >> 24;
|
||||||
|
}
|
||||||
|
|
||||||
|
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++) {
|
||||||
|
to_le32(®isters[i], env->gpr[i]);
|
||||||
|
}
|
||||||
|
/* fill in fprs */
|
||||||
|
for (i = 0; i < 32; i++) {
|
||||||
|
to_le32(®isters[(i * 2) + 32], *((uint32_t *)&env->fpr[i]));
|
||||||
|
to_le32(®isters[(i * 2) + 33], *((uint32_t *)&env->fpr[i] + 1));
|
||||||
|
}
|
||||||
|
/* nip, msr, ccr, lnk, ctr, xer, mq */
|
||||||
|
to_le32(®isters[96], (uint32_t)env->nip/* - 4*/);
|
||||||
|
to_le32(®isters[97], _load_msr(env));
|
||||||
|
tmp = 0;
|
||||||
|
for (i = 0; i < 8; i++)
|
||||||
|
tmp |= env->crf[i] << (32 - ((i + 1) * 4));
|
||||||
|
to_le32(®isters[98], tmp);
|
||||||
|
to_le32(®isters[99], env->lr);
|
||||||
|
to_le32(®isters[100], env->ctr);
|
||||||
|
to_le32(®isters[101], _load_xer(env));
|
||||||
|
to_le32(®isters[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] = from_le32(®isters[i]);
|
||||||
|
}
|
||||||
|
/* fill in fprs */
|
||||||
|
for (i = 0; i < 32; i++) {
|
||||||
|
*((uint32_t *)&env->fpr[i]) = from_le32(®isters[(i * 2) + 32]);
|
||||||
|
*((uint32_t *)&env->fpr[i] + 1) = from_le32(®isters[(i * 2) + 33]);
|
||||||
|
}
|
||||||
|
/* nip, msr, ccr, lnk, ctr, xer, mq */
|
||||||
|
env->nip = from_le32(®isters[96]);
|
||||||
|
_store_msr(env, from_le32(®isters[97]));
|
||||||
|
registers[98] = from_le32(®isters[98]);
|
||||||
|
for (i = 0; i < 8; i++)
|
||||||
|
env->crf[i] = (registers[98] >> (32 - ((i + 1) * 4))) & 0xF;
|
||||||
|
env->lr = from_le32(®isters[99]);
|
||||||
|
env->ctr = from_le32(®isters[100]);
|
||||||
|
_store_xer(env, from_le32(®isters[101]));
|
||||||
|
}
|
||||||
|
#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);
|
addr = strtoul(p, (char **)&p, 16);
|
||||||
if (*p == ',')
|
#if defined(TARGET_I386)
|
||||||
p++;
|
env->eip = addr;
|
||||||
len = strtoul(p, NULL, 16);
|
#elif defined (TARGET_PPC)
|
||||||
if (memory_rw(mem_buf, addr, len, 0) != 0)
|
env->nip = addr;
|
||||||
memset(mem_buf, 0, len);
|
#endif
|
||||||
memtohex(buf, mem_buf, len);
|
}
|
||||||
put_packet(buf);
|
vm_start();
|
||||||
break;
|
break;
|
||||||
case 'M':
|
case 's':
|
||||||
|
if (*p != '\0') {
|
||||||
addr = strtoul(p, (char **)&p, 16);
|
addr = strtoul(p, (char **)&p, 16);
|
||||||
if (*p == ',')
|
#if defined(TARGET_I386)
|
||||||
p++;
|
env->eip = addr;
|
||||||
len = strtoul(p, (char **)&p, 16);
|
#elif defined (TARGET_PPC)
|
||||||
if (*p == ',')
|
env->nip = addr;
|
||||||
p++;
|
#endif
|
||||||
hextomem(mem_buf, p, len);
|
}
|
||||||
if (memory_rw(mem_buf, addr, len, 1) != 0)
|
cpu_single_step(env, 1);
|
||||||
put_packet("ENN");
|
vm_start();
|
||||||
else
|
break;
|
||||||
put_packet("OK");
|
case 'g':
|
||||||
break;
|
reg_size = cpu_gdb_read_registers(env, mem_buf);
|
||||||
case 'Z':
|
memtohex(buf, mem_buf, reg_size);
|
||||||
type = strtoul(p, (char **)&p, 16);
|
put_packet(s, buf);
|
||||||
if (*p == ',')
|
break;
|
||||||
p++;
|
case 'G':
|
||||||
addr = strtoul(p, (char **)&p, 16);
|
registers = (void *)mem_buf;
|
||||||
if (*p == ',')
|
len = strlen(p) / 2;
|
||||||
p++;
|
hextomem((uint8_t *)registers, p, len);
|
||||||
len = strtoul(p, (char **)&p, 16);
|
cpu_gdb_write_registers(env, mem_buf, len);
|
||||||
if (type == 0 || type == 1) {
|
put_packet(s, "OK");
|
||||||
env = cpu_gdbstub_get_env(opaque);
|
break;
|
||||||
if (cpu_breakpoint_insert(env, addr) < 0)
|
case 'm':
|
||||||
goto breakpoint_error;
|
addr = strtoul(p, (char **)&p, 16);
|
||||||
put_packet("OK");
|
if (*p == ',')
|
||||||
} else {
|
p++;
|
||||||
breakpoint_error:
|
len = strtoul(p, NULL, 16);
|
||||||
put_packet("ENN");
|
if (cpu_memory_rw_debug(env, addr, mem_buf, len, 0) != 0)
|
||||||
}
|
memset(mem_buf, 0, len);
|
||||||
break;
|
memtohex(buf, mem_buf, len);
|
||||||
case 'z':
|
put_packet(s, buf);
|
||||||
type = strtoul(p, (char **)&p, 16);
|
break;
|
||||||
if (*p == ',')
|
case 'M':
|
||||||
p++;
|
addr = strtoul(p, (char **)&p, 16);
|
||||||
addr = strtoul(p, (char **)&p, 16);
|
if (*p == ',')
|
||||||
if (*p == ',')
|
p++;
|
||||||
p++;
|
len = strtoul(p, (char **)&p, 16);
|
||||||
len = strtoul(p, (char **)&p, 16);
|
if (*p == ',')
|
||||||
if (type == 0 || type == 1) {
|
p++;
|
||||||
env = cpu_gdbstub_get_env(opaque);
|
hextomem(mem_buf, p, len);
|
||||||
cpu_breakpoint_remove(env, addr);
|
if (cpu_memory_rw_debug(env, addr, mem_buf, len, 1) != 0)
|
||||||
put_packet("OK");
|
put_packet(s, "ENN");
|
||||||
} else {
|
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;
|
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;
|
break;
|
||||||
case 'Q':
|
case RS_GETLINE:
|
||||||
if (!strncmp(p, "Tinit", 5)) {
|
if (ch == '#') {
|
||||||
/* init traces */
|
s->state = RS_CHKSUM1;
|
||||||
put_packet("OK");
|
} else if (s->line_buf_index >= sizeof(s->line_buf) - 1) {
|
||||||
} else if (!strncmp(p, "TStart", 6)) {
|
s->state = RS_IDLE;
|
||||||
/* start log (gdb 'tstart' command) */
|
|
||||||
cpu_set_log(CPU_LOG_ALL);
|
|
||||||
put_packet("OK");
|
|
||||||
} else if (!strncmp(p, "TStop", 5)) {
|
|
||||||
/* stop log (gdb 'tstop' command) */
|
|
||||||
cpu_set_log(0);
|
|
||||||
put_packet("OK");
|
|
||||||
} else {
|
} else {
|
||||||
goto unknown_command;
|
s->line_buf[s->line_buf_index++] = ch;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
case RS_CHKSUM1:
|
||||||
unknown_command:
|
s->line_buf[s->line_buf_index] = '\0';
|
||||||
/* put empty packet */
|
s->line_csum = fromhex(ch) << 4;
|
||||||
buf[0] = '\0';
|
s->state = RS_CHKSUM2;
|
||||||
put_packet(buf);
|
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;
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,362 @@
|
|||||||
|
/*
|
||||||
|
* 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
|
||||||
|
|
||||||
|
int adb_request(ADBBusState *s, uint8_t *obuf, const uint8_t *buf, int len)
|
||||||
|
{
|
||||||
|
ADBDevice *d;
|
||||||
|
int devaddr, cmd, i;
|
||||||
|
|
||||||
|
cmd = buf[0] & 0xf;
|
||||||
|
devaddr = buf[0] >> 4;
|
||||||
|
if (buf[1] == ADB_BUSRESET) {
|
||||||
|
obuf[0] = 0x00;
|
||||||
|
obuf[1] = 0x00;
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
if (cmd == ADB_FLUSH) {
|
||||||
|
obuf[0] = 0x00;
|
||||||
|
obuf[1] = 0x00;
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(i = 0; i < s->nb_devices; i++) {
|
||||||
|
d = &s->devices[i];
|
||||||
|
if (d->devaddr == devaddr) {
|
||||||
|
return d->devreq(d, obuf, buf, len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int adb_poll(ADBBusState *s, uint8_t *obuf)
|
||||||
|
{
|
||||||
|
ADBDevice *d;
|
||||||
|
int olen, i;
|
||||||
|
|
||||||
|
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];
|
||||||
|
olen = d->devreq(d, obuf, NULL, 0);
|
||||||
|
s->poll_index++;
|
||||||
|
if (olen)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return olen;
|
||||||
|
}
|
||||||
|
|
||||||
|
ADBDevice *adb_register_device(ADBBusState *s, int devaddr,
|
||||||
|
ADBDeviceRequest *devreq,
|
||||||
|
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->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] = (d->devaddr << 4) | 0x0c;
|
||||||
|
obuf[1] = adb_keycode | (keycode & 0x80);
|
||||||
|
obuf[2] = 0xff;
|
||||||
|
olen = 3;
|
||||||
|
ext_keycode = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return olen;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int adb_kbd_request(ADBDevice *d, uint8_t *obuf,
|
||||||
|
const uint8_t *buf, int len)
|
||||||
|
{
|
||||||
|
int cmd, reg, olen;
|
||||||
|
|
||||||
|
if (!buf) {
|
||||||
|
return adb_kbd_poll(d, obuf);
|
||||||
|
}
|
||||||
|
|
||||||
|
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 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, 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] = (d->devaddr << 4) | 0x0c;
|
||||||
|
obuf[1] = dy;
|
||||||
|
obuf[2] = dx;
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int adb_mouse_request(ADBDevice *d, uint8_t *obuf,
|
||||||
|
const uint8_t *buf, int len)
|
||||||
|
{
|
||||||
|
int cmd, reg, olen;
|
||||||
|
|
||||||
|
if (!buf) {
|
||||||
|
return adb_mouse_poll(d, obuf);
|
||||||
|
}
|
||||||
|
|
||||||
|
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 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, s);
|
||||||
|
d->handler = 2;
|
||||||
|
qemu_add_mouse_event_handler(adb_mouse_event, d);
|
||||||
|
}
|
||||||
+3045
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,613 @@
|
|||||||
|
/*
|
||||||
|
* 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 {
|
||||||
|
/* empty reply */
|
||||||
|
obuf[0] = ADB_PACKET;
|
||||||
|
obuf[1] = 0x02;
|
||||||
|
}
|
||||||
|
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,430 @@
|
|||||||
|
/*
|
||||||
|
* QEMU DMA emulation
|
||||||
|
*
|
||||||
|
* Copyright (c) 2003 Vassili Karpov (malc)
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#include "vl.h"
|
||||||
|
|
||||||
|
//#define DEBUG_DMA
|
||||||
|
|
||||||
|
#define log(...) fprintf (stderr, "dma: " __VA_ARGS__)
|
||||||
|
#ifdef DEBUG_DMA
|
||||||
|
#define lwarn(...) fprintf (stderr, "dma: " __VA_ARGS__)
|
||||||
|
#define linfo(...) fprintf (stderr, "dma: " __VA_ARGS__)
|
||||||
|
#define ldebug(...) fprintf (stderr, "dma: " __VA_ARGS__)
|
||||||
|
#else
|
||||||
|
#define lwarn(...)
|
||||||
|
#define linfo(...)
|
||||||
|
#define ldebug(...)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define 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) {
|
||||||
|
log ("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) {
|
||||||
|
log ("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) {
|
||||||
|
log ("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) {
|
||||||
|
log ("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[0] << 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;
|
||||||
|
struct dma_regs *r;
|
||||||
|
|
||||||
|
iport = (nport >> d->dshift) & 0x0f;
|
||||||
|
ichan = iport >> 1;
|
||||||
|
nreg = iport & 1;
|
||||||
|
r = d->regs + ichan;
|
||||||
|
|
||||||
|
ff = getff (d);
|
||||||
|
if (nreg)
|
||||||
|
val = (r->base[COUNT] << d->dshift) - r->now[COUNT];
|
||||||
|
else
|
||||||
|
val = r->now[ADDR] + r->now[COUNT];
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
iport = (nport >> d->dshift) & 0x0f;
|
||||||
|
switch (iport) {
|
||||||
|
case 8: /* command */
|
||||||
|
if ((data != 0) && (data & CMD_NOT_SUPPORTED)) {
|
||||||
|
log ("command %#x not supported\n", data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
d->command = data;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 9:
|
||||||
|
ichan = data & 3;
|
||||||
|
if (data & 4) {
|
||||||
|
d->status |= 1 << (ichan + 4);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
d->status &= ~(1 << (ichan + 4));
|
||||||
|
}
|
||||||
|
d->status &= ~(1 << ichan);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xa: /* single mask */
|
||||||
|
if (data & 4)
|
||||||
|
d->mask |= 1 << (data & 3);
|
||||||
|
else
|
||||||
|
d->mask &= ~(1 << (data & 3));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xb: /* mode */
|
||||||
|
{
|
||||||
|
ichan = data & 3;
|
||||||
|
#ifdef DEBUG_DMA
|
||||||
|
int op;
|
||||||
|
int ai;
|
||||||
|
int dir;
|
||||||
|
int 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 0xc: /* clear flip flop */
|
||||||
|
d->flip_flop = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xd: /* reset */
|
||||||
|
d->flip_flop = 0;
|
||||||
|
d->mask = ~0;
|
||||||
|
d->status = 0;
|
||||||
|
d->command = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xe: /* clear mask for all channels */
|
||||||
|
d->mask = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xf: /* write mask for all channels */
|
||||||
|
d->mask = data;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
log ("dma: unknown iport %#x\n", iport);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef DEBUG_DMA
|
||||||
|
if (0xc != iport) {
|
||||||
|
linfo ("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;
|
||||||
|
}
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
struct dma_regs *r;
|
||||||
|
int n;
|
||||||
|
target_ulong addr;
|
||||||
|
/* int ai, dir; */
|
||||||
|
|
||||||
|
r = dma_controllers[ncont].regs + ichan;
|
||||||
|
/* ai = r->mode & 16; */
|
||||||
|
/* dir = r->mode & 32 ? -1 : 1; */
|
||||||
|
|
||||||
|
/* NOTE: pageh is only used by PPC PREP */
|
||||||
|
addr = ((r->pageh & 0x7f) << 24) | (r->page << 16) | r->now[ADDR];
|
||||||
|
n = r->transfer_handler (r->opaque, addr,
|
||||||
|
(r->base[COUNT] << ncont) + (1 << ncont));
|
||||||
|
r->now[COUNT] = n;
|
||||||
|
|
||||||
|
ldebug ("dma_pos %d size %d\n",
|
||||||
|
n, (r->base[1] << ncont) + (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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
+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;
|
||||||
|
}
|
||||||
+510
@@ -0,0 +1,510 @@
|
|||||||
|
/*
|
||||||
|
* 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);
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
+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__) */
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
+623
@@ -0,0 +1,623 @@
|
|||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/***********************************************************/
|
||||||
|
/* 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((PCIDevice *)d, 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);
|
||||||
|
}
|
||||||
+1023
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,516 @@
|
|||||||
|
/*
|
||||||
|
* 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(int ram_size, int boot_device)
|
||||||
|
{
|
||||||
|
RTCState *s = rtc_state;
|
||||||
|
int val;
|
||||||
|
int fd0, fd1, nb;
|
||||||
|
time_t ti;
|
||||||
|
struct tm *tm;
|
||||||
|
|
||||||
|
/* 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);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
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 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 };
|
||||||
|
|
||||||
|
/* 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, fd;
|
||||||
|
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);
|
||||||
|
|
||||||
|
fd = serial_open_device();
|
||||||
|
serial_init(0x3f8, 4, fd);
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
#ifndef _WIN32
|
||||||
|
if (audio_enabled) {
|
||||||
|
/* no audio supported yet for win32 */
|
||||||
|
AUD_init();
|
||||||
|
SB16_init();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
floppy_controller = fdctrl_init(6, 2, 0, 0x3f0, fd_table);
|
||||||
|
|
||||||
|
cmos_init(ram_size, boot_device);
|
||||||
|
|
||||||
|
/* 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);
|
||||||
|
}
|
||||||
+234
@@ -0,0 +1,234 @@
|
|||||||
|
/*
|
||||||
|
* 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, fd;
|
||||||
|
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 */
|
||||||
|
fd = serial_open_device();
|
||||||
|
serial_init(0x3f8, 4, fd);
|
||||||
|
|
||||||
|
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 */
|
||||||
|
}
|
||||||
+549
@@ -0,0 +1,549 @@
|
|||||||
|
/*
|
||||||
|
* 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, fd;
|
||||||
|
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);
|
||||||
|
|
||||||
|
fd = serial_open_device();
|
||||||
|
serial_init(0x3f8, 4, fd);
|
||||||
|
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);
|
||||||
|
}
|
||||||
@@ -0,0 +1,762 @@
|
|||||||
|
/*
|
||||||
|
* QEMU Soundblaster 16 emulation
|
||||||
|
*
|
||||||
|
* Copyright (c) 2003 Vassili Karpov (malc)
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#include "vl.h"
|
||||||
|
|
||||||
|
#define MIN(a, b) ((a)>(b)?(b):(a))
|
||||||
|
#define LENOFA(a) ((int) (sizeof(a)/sizeof(a[0])))
|
||||||
|
|
||||||
|
#define log(...) do { \
|
||||||
|
fprintf (stderr, "sb16: " __VA_ARGS__); \
|
||||||
|
fputc ('\n', stderr); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
/* #define DEBUG_SB16 */
|
||||||
|
#ifdef DEBUG_SB16
|
||||||
|
#define lwarn(...) fprintf (stderr, "sb16: " __VA_ARGS__)
|
||||||
|
#define linfo(...) fprintf (stderr, "sb16: " __VA_ARGS__)
|
||||||
|
#define ldebug(...) fprintf (stderr, "sb16: " __VA_ARGS__)
|
||||||
|
#else
|
||||||
|
#define lwarn(...)
|
||||||
|
#define linfo(...)
|
||||||
|
#define ldebug(...)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define IO_READ_PROTO(name) \
|
||||||
|
uint32_t name (void *opaque, uint32_t nport)
|
||||||
|
#define IO_WRITE_PROTO(name) \
|
||||||
|
void name (void *opaque, uint32_t nport, uint32_t val)
|
||||||
|
|
||||||
|
static const char e3[] = "COPYRIGHT (C) CREATIVE TECHNOLOGY LTD, 1992.";
|
||||||
|
|
||||||
|
static struct {
|
||||||
|
int ver_lo;
|
||||||
|
int ver_hi;
|
||||||
|
int irq;
|
||||||
|
int dma;
|
||||||
|
int hdma;
|
||||||
|
int port;
|
||||||
|
int mix_block;
|
||||||
|
} sb = {5, 4, 5, 1, 5, 0x220, -1};
|
||||||
|
|
||||||
|
static int mix_block, noirq;
|
||||||
|
|
||||||
|
typedef struct SB16State {
|
||||||
|
int in_index;
|
||||||
|
int out_data_len;
|
||||||
|
int fmt_stereo;
|
||||||
|
int fmt_signed;
|
||||||
|
int fmt_bits;
|
||||||
|
int dma_auto;
|
||||||
|
int dma_buffer_size;
|
||||||
|
int fifo;
|
||||||
|
int freq;
|
||||||
|
int time_const;
|
||||||
|
int speaker;
|
||||||
|
int needed_bytes;
|
||||||
|
int cmd;
|
||||||
|
int dma_pos;
|
||||||
|
int use_hdma;
|
||||||
|
|
||||||
|
int v2x6;
|
||||||
|
|
||||||
|
uint8_t in_data[10];
|
||||||
|
uint8_t out_data[50];
|
||||||
|
|
||||||
|
int left_till_irq;
|
||||||
|
|
||||||
|
/* mixer state */
|
||||||
|
int mixer_nreg;
|
||||||
|
uint8_t mixer_regs[256];
|
||||||
|
} SB16State;
|
||||||
|
|
||||||
|
/* XXX: suppress that and use a context */
|
||||||
|
static struct SB16State dsp;
|
||||||
|
|
||||||
|
static void log_dsp (SB16State *dsp)
|
||||||
|
{
|
||||||
|
linfo ("%c:%c:%d:%c:dmabuf=%d:pos=%d:freq=%d:timeconst=%d:speaker=%d\n",
|
||||||
|
dsp->fmt_stereo ? 'S' : 'M',
|
||||||
|
dsp->fmt_signed ? 'S' : 'U',
|
||||||
|
dsp->fmt_bits,
|
||||||
|
dsp->dma_auto ? 'a' : 's',
|
||||||
|
dsp->dma_buffer_size,
|
||||||
|
dsp->dma_pos,
|
||||||
|
dsp->freq,
|
||||||
|
dsp->time_const,
|
||||||
|
dsp->speaker);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void control (int hold)
|
||||||
|
{
|
||||||
|
linfo ("%d high %d\n", hold, dsp.use_hdma);
|
||||||
|
if (hold) {
|
||||||
|
if (dsp.use_hdma)
|
||||||
|
DMA_hold_DREQ (sb.hdma);
|
||||||
|
else
|
||||||
|
DMA_hold_DREQ (sb.dma);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (dsp.use_hdma)
|
||||||
|
DMA_release_DREQ (sb.hdma);
|
||||||
|
else
|
||||||
|
DMA_release_DREQ (sb.dma);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dma_cmd (uint8_t cmd, uint8_t d0, int dma_len)
|
||||||
|
{
|
||||||
|
int bps;
|
||||||
|
audfmt_e fmt;
|
||||||
|
|
||||||
|
dsp.use_hdma = cmd < 0xc0;
|
||||||
|
dsp.fifo = (cmd >> 1) & 1;
|
||||||
|
dsp.dma_auto = (cmd >> 2) & 1;
|
||||||
|
|
||||||
|
switch (cmd >> 4) {
|
||||||
|
case 11:
|
||||||
|
dsp.fmt_bits = 16;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 12:
|
||||||
|
dsp.fmt_bits = 8;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
dsp.fmt_signed = (d0 >> 4) & 1;
|
||||||
|
dsp.fmt_stereo = (d0 >> 5) & 1;
|
||||||
|
|
||||||
|
if (-1 != dsp.time_const) {
|
||||||
|
int tmp;
|
||||||
|
|
||||||
|
tmp = 256 - dsp.time_const;
|
||||||
|
dsp.freq = (1000000 + (tmp / 2)) / tmp;
|
||||||
|
}
|
||||||
|
bps = 1 << (16 == dsp.fmt_bits);
|
||||||
|
|
||||||
|
if (-1 != dma_len)
|
||||||
|
dsp.dma_buffer_size = (dma_len + 1) * bps;
|
||||||
|
|
||||||
|
linfo ("frequency %d, stereo %d, signed %d, bits %d, size %d, auto %d\n",
|
||||||
|
dsp.freq, dsp.fmt_stereo, dsp.fmt_signed, dsp.fmt_bits,
|
||||||
|
dsp.dma_buffer_size, dsp.dma_auto);
|
||||||
|
|
||||||
|
if (16 == dsp.fmt_bits) {
|
||||||
|
if (dsp.fmt_signed) {
|
||||||
|
fmt = AUD_FMT_S16;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fmt = AUD_FMT_U16;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (dsp.fmt_signed) {
|
||||||
|
fmt = AUD_FMT_S8;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fmt = AUD_FMT_U8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dsp.dma_pos = 0;
|
||||||
|
dsp.left_till_irq = dsp.dma_buffer_size;
|
||||||
|
|
||||||
|
if (sb.mix_block) {
|
||||||
|
mix_block = sb.mix_block;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
int align;
|
||||||
|
|
||||||
|
align = bps << dsp.fmt_stereo;
|
||||||
|
mix_block = ((dsp.freq * align) / 100) & ~(align - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
AUD_reset (dsp.freq, 1 << dsp.fmt_stereo, fmt);
|
||||||
|
control (1);
|
||||||
|
dsp.speaker = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void dsp_out_data(SB16State *dsp, int val)
|
||||||
|
{
|
||||||
|
if (dsp->out_data_len < sizeof(dsp->out_data))
|
||||||
|
dsp->out_data[dsp->out_data_len++] = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void command (SB16State *dsp, uint8_t cmd)
|
||||||
|
{
|
||||||
|
linfo ("%#x\n", cmd);
|
||||||
|
|
||||||
|
if (cmd > 0xaf && cmd < 0xd0) {
|
||||||
|
if (cmd & 8)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
switch (cmd >> 4) {
|
||||||
|
case 11:
|
||||||
|
case 12:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
log("%#x wrong bits", cmd);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
dsp->needed_bytes = 3;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
switch (cmd) {
|
||||||
|
case 0x00:
|
||||||
|
case 0x03:
|
||||||
|
case 0xe7:
|
||||||
|
/* IMS uses those when probing for sound devices */
|
||||||
|
return;
|
||||||
|
|
||||||
|
case 0x04:
|
||||||
|
dsp->needed_bytes = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x05:
|
||||||
|
case 0x0e:
|
||||||
|
dsp->needed_bytes = 2;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x0f:
|
||||||
|
dsp->needed_bytes = 1;
|
||||||
|
dsp_out_data (dsp, 0);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x10:
|
||||||
|
dsp->needed_bytes = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x14:
|
||||||
|
dsp->needed_bytes = 2;
|
||||||
|
dsp->dma_buffer_size = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x20:
|
||||||
|
dsp_out_data(dsp, 0xff);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x35:
|
||||||
|
lwarn ("MIDI commands not implemented\n");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x40:
|
||||||
|
dsp->freq = -1;
|
||||||
|
dsp->time_const = -1;
|
||||||
|
dsp->needed_bytes = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x41:
|
||||||
|
case 0x42:
|
||||||
|
dsp->freq = -1;
|
||||||
|
dsp->time_const = -1;
|
||||||
|
dsp->needed_bytes = 2;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x47: /* Continue Auto-Initialize DMA 16bit */
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x48:
|
||||||
|
dsp->needed_bytes = 2;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x27: /* ????????? */
|
||||||
|
case 0x4e:
|
||||||
|
return;
|
||||||
|
|
||||||
|
case 0x80:
|
||||||
|
cmd = -1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x90:
|
||||||
|
case 0x91:
|
||||||
|
{
|
||||||
|
uint8_t d0;
|
||||||
|
|
||||||
|
d0 = 4;
|
||||||
|
/* if (dsp->fmt_signed) d0 |= 16; */
|
||||||
|
/* if (dsp->fmt_stereo) d0 |= 32; */
|
||||||
|
dma_cmd (cmd == 0x90 ? 0xc4 : 0xc0, d0, -1);
|
||||||
|
cmd = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 0xd0: /* XXX */
|
||||||
|
control (0);
|
||||||
|
return;
|
||||||
|
|
||||||
|
case 0xd1:
|
||||||
|
dsp->speaker = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xd3:
|
||||||
|
dsp->speaker = 0;
|
||||||
|
return;
|
||||||
|
|
||||||
|
case 0xd4:
|
||||||
|
control (1);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xd5:
|
||||||
|
control (0);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xd6:
|
||||||
|
control (1);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xd9:
|
||||||
|
control (0);
|
||||||
|
dsp->dma_auto = 0;
|
||||||
|
return;
|
||||||
|
|
||||||
|
case 0xda:
|
||||||
|
control (0);
|
||||||
|
dsp->dma_auto = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xe0:
|
||||||
|
dsp->needed_bytes = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xe1:
|
||||||
|
dsp_out_data(dsp, sb.ver_lo);
|
||||||
|
dsp_out_data(dsp, sb.ver_hi);
|
||||||
|
return;
|
||||||
|
|
||||||
|
case 0xe3:
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = sizeof (e3) - 1; i >= 0; --i)
|
||||||
|
dsp_out_data (dsp, e3[i]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 0xf2:
|
||||||
|
dsp_out_data(dsp, 0xaa);
|
||||||
|
dsp->mixer_regs[0x82] |= dsp->mixer_regs[0x80];
|
||||||
|
pic_set_irq (sb.irq, 1);
|
||||||
|
return;
|
||||||
|
|
||||||
|
default:
|
||||||
|
log("%#x is unknown", cmd);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dsp->cmd = cmd;
|
||||||
|
return;
|
||||||
|
|
||||||
|
error:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void complete (SB16State *dsp)
|
||||||
|
{
|
||||||
|
linfo ("complete command %#x, in_index %d, needed_bytes %d\n",
|
||||||
|
dsp->cmd, dsp->in_index, dsp->needed_bytes);
|
||||||
|
|
||||||
|
if (dsp->cmd > 0xaf && dsp->cmd < 0xd0) {
|
||||||
|
int d0, d1, d2;
|
||||||
|
|
||||||
|
d0 = dsp->in_data[0];
|
||||||
|
d1 = dsp->in_data[1];
|
||||||
|
d2 = dsp->in_data[2];
|
||||||
|
|
||||||
|
ldebug ("d0 = %d, d1 = %d, d2 = %d\n",
|
||||||
|
d0, d1, d2);
|
||||||
|
dma_cmd (dsp->cmd, d0, d1 + (d2 << 8));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
switch (dsp->cmd) {
|
||||||
|
case 0x05:
|
||||||
|
case 0x04:
|
||||||
|
case 0x0e:
|
||||||
|
case 0x0f:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x10:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x14:
|
||||||
|
{
|
||||||
|
int d0, d1;
|
||||||
|
int save_left;
|
||||||
|
int save_pos;
|
||||||
|
|
||||||
|
d0 = dsp->in_data[0];
|
||||||
|
d1 = dsp->in_data[1];
|
||||||
|
|
||||||
|
save_left = dsp->left_till_irq;
|
||||||
|
save_pos = dsp->dma_pos;
|
||||||
|
dma_cmd (0xc0, 0, d0 + (d1 << 8));
|
||||||
|
dsp->left_till_irq = save_left;
|
||||||
|
dsp->dma_pos = save_pos;
|
||||||
|
|
||||||
|
linfo ("set buffer size data[%d, %d] %d pos %d\n",
|
||||||
|
d0, d1, dsp->dma_buffer_size, dsp->dma_pos);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 0x40:
|
||||||
|
dsp->time_const = dsp->in_data[0];
|
||||||
|
linfo ("set time const %d\n", dsp->time_const);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x41:
|
||||||
|
case 0x42:
|
||||||
|
dsp->freq = dsp->in_data[1] + (dsp->in_data[0] << 8);
|
||||||
|
linfo ("set freq %#x, %#x = %d\n",
|
||||||
|
dsp->in_data[1], dsp->in_data[0], dsp->freq);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x48:
|
||||||
|
dsp->dma_buffer_size = dsp->in_data[1] + (dsp->in_data[0] << 8);
|
||||||
|
linfo ("set dma len %#x, %#x = %d\n",
|
||||||
|
dsp->in_data[1], dsp->in_data[0], dsp->dma_buffer_size);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xe0:
|
||||||
|
dsp->out_data_len = 0;
|
||||||
|
linfo ("data = %#x\n", dsp->in_data[0]);
|
||||||
|
dsp_out_data(dsp, dsp->in_data[0] ^ 0xff);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
log ("unrecognized command %#x", dsp->cmd);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dsp->cmd = -1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static IO_WRITE_PROTO (dsp_write)
|
||||||
|
{
|
||||||
|
SB16State *dsp = opaque;
|
||||||
|
int iport;
|
||||||
|
|
||||||
|
iport = nport - sb.port;
|
||||||
|
|
||||||
|
ldebug ("write %#x %#x\n", nport, iport);
|
||||||
|
switch (iport) {
|
||||||
|
case 0x6:
|
||||||
|
control (0);
|
||||||
|
if (0 == val)
|
||||||
|
dsp->v2x6 = 0;
|
||||||
|
else if ((1 == val) && (0 == dsp->v2x6)) {
|
||||||
|
dsp->v2x6 = 1;
|
||||||
|
dsp_out_data(dsp, 0xaa);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
dsp->v2x6 = ~0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xc: /* write data or command | write status */
|
||||||
|
if (0 == dsp->needed_bytes) {
|
||||||
|
command (dsp, val);
|
||||||
|
if (0 == dsp->needed_bytes) {
|
||||||
|
log_dsp (dsp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
dsp->in_data[dsp->in_index++] = val;
|
||||||
|
if (dsp->in_index == dsp->needed_bytes) {
|
||||||
|
dsp->needed_bytes = 0;
|
||||||
|
dsp->in_index = 0;
|
||||||
|
complete (dsp);
|
||||||
|
log_dsp (dsp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
log ("(nport=%#x, val=%#x)", nport, val);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static IO_READ_PROTO (dsp_read)
|
||||||
|
{
|
||||||
|
SB16State *dsp = opaque;
|
||||||
|
int iport, retval;
|
||||||
|
|
||||||
|
iport = nport - sb.port;
|
||||||
|
|
||||||
|
switch (iport) {
|
||||||
|
|
||||||
|
case 0x6: /* reset */
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
case 0xa: /* read data */
|
||||||
|
if (dsp->out_data_len) {
|
||||||
|
retval = dsp->out_data[--dsp->out_data_len];
|
||||||
|
} else {
|
||||||
|
log("empty output buffer");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xc: /* 0 can write */
|
||||||
|
retval = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xd: /* timer interrupt clear */
|
||||||
|
log("timer interrupt clear");
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
case 0xe: /* data available status | irq 8 ack */
|
||||||
|
/* XXX drop pic irq line here? */
|
||||||
|
ldebug ("8 ack\n");
|
||||||
|
retval = (0 == dsp->out_data_len) ? 0 : 0x80;
|
||||||
|
dsp->mixer_regs[0x82] &= ~dsp->mixer_regs[0x80];
|
||||||
|
pic_set_irq (sb.irq, 0);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xf: /* irq 16 ack */
|
||||||
|
/* XXX drop pic irq line here? */
|
||||||
|
ldebug ("16 ack\n");
|
||||||
|
retval = 0xff;
|
||||||
|
dsp->mixer_regs[0x82] &= ~dsp->mixer_regs[0x80];
|
||||||
|
pic_set_irq (sb.irq, 0);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((0xc != iport) && (0xe != iport)) {
|
||||||
|
ldebug ("nport=%#x iport %#x = %#x\n",
|
||||||
|
nport, iport, retval);
|
||||||
|
}
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
error:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static IO_WRITE_PROTO(mixer_write_indexb)
|
||||||
|
{
|
||||||
|
SB16State *dsp = opaque;
|
||||||
|
dsp->mixer_nreg = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
static IO_WRITE_PROTO(mixer_write_datab)
|
||||||
|
{
|
||||||
|
SB16State *dsp = opaque;
|
||||||
|
|
||||||
|
if (dsp->mixer_nreg > 0x83)
|
||||||
|
return;
|
||||||
|
dsp->mixer_regs[dsp->mixer_nreg] = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
static IO_WRITE_PROTO(mixer_write_indexw)
|
||||||
|
{
|
||||||
|
mixer_write_indexb (opaque, nport, val & 0xff);
|
||||||
|
mixer_write_datab (opaque, nport, (val >> 8) & 0xff);
|
||||||
|
}
|
||||||
|
|
||||||
|
static IO_READ_PROTO(mixer_read)
|
||||||
|
{
|
||||||
|
SB16State *dsp = opaque;
|
||||||
|
return dsp->mixer_regs[dsp->mixer_nreg];
|
||||||
|
}
|
||||||
|
|
||||||
|
void SB16_run (void)
|
||||||
|
{
|
||||||
|
if (0 == dsp.speaker)
|
||||||
|
return;
|
||||||
|
|
||||||
|
AUD_run ();
|
||||||
|
}
|
||||||
|
|
||||||
|
static int write_audio (uint32_t addr, int len, int size)
|
||||||
|
{
|
||||||
|
int temp, net;
|
||||||
|
uint8_t tmpbuf[4096];
|
||||||
|
|
||||||
|
temp = size;
|
||||||
|
|
||||||
|
net = 0;
|
||||||
|
|
||||||
|
while (temp) {
|
||||||
|
int left_till_end;
|
||||||
|
int to_copy;
|
||||||
|
int copied;
|
||||||
|
|
||||||
|
left_till_end = len - dsp.dma_pos;
|
||||||
|
|
||||||
|
to_copy = MIN (temp, left_till_end);
|
||||||
|
if (to_copy > sizeof(tmpbuf))
|
||||||
|
to_copy = sizeof(tmpbuf);
|
||||||
|
cpu_physical_memory_read(addr + dsp.dma_pos, tmpbuf, to_copy);
|
||||||
|
copied = AUD_write (tmpbuf, to_copy);
|
||||||
|
|
||||||
|
temp -= copied;
|
||||||
|
dsp.dma_pos += copied;
|
||||||
|
|
||||||
|
if (dsp.dma_pos == len) {
|
||||||
|
dsp.dma_pos = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
net += copied;
|
||||||
|
|
||||||
|
if (copied != to_copy)
|
||||||
|
return net;
|
||||||
|
}
|
||||||
|
|
||||||
|
return net;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int SB_read_DMA (void *opaque, target_ulong addr, int size)
|
||||||
|
{
|
||||||
|
SB16State *dsp = opaque;
|
||||||
|
int free, till, copy, written;
|
||||||
|
|
||||||
|
if (0 == dsp->speaker)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (dsp->left_till_irq < 0) {
|
||||||
|
dsp->left_till_irq += dsp->dma_buffer_size;
|
||||||
|
return dsp->dma_pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
free = AUD_get_free ();
|
||||||
|
|
||||||
|
if ((free <= 0) || (0 == size)) {
|
||||||
|
return dsp->dma_pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mix_block > 0) {
|
||||||
|
copy = MIN (free, mix_block);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
copy = free;
|
||||||
|
}
|
||||||
|
|
||||||
|
till = dsp->left_till_irq;
|
||||||
|
|
||||||
|
ldebug ("addr:%#010x free:%d till:%d size:%d\n",
|
||||||
|
addr, free, till, size);
|
||||||
|
if (till <= copy) {
|
||||||
|
if (0 == dsp->dma_auto) {
|
||||||
|
copy = till;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
written = write_audio (addr, size, copy);
|
||||||
|
dsp->left_till_irq -= written;
|
||||||
|
AUD_adjust_estimate (free - written);
|
||||||
|
|
||||||
|
if (dsp->left_till_irq <= 0) {
|
||||||
|
dsp->mixer_regs[0x82] |= dsp->mixer_regs[0x80];
|
||||||
|
if (0 == noirq) {
|
||||||
|
ldebug ("request irq\n");
|
||||||
|
pic_set_irq(sb.irq, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (0 == dsp->dma_auto) {
|
||||||
|
control (0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ldebug ("pos %5d free %5d size %5d till % 5d copy %5d dma size %5d\n",
|
||||||
|
dsp->dma_pos, free, size, dsp->left_till_irq, copy,
|
||||||
|
dsp->dma_buffer_size);
|
||||||
|
|
||||||
|
if (dsp->left_till_irq <= 0) {
|
||||||
|
dsp->left_till_irq += dsp->dma_buffer_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
return dsp->dma_pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int magic_of_irq (int irq)
|
||||||
|
{
|
||||||
|
switch (irq) {
|
||||||
|
case 2:
|
||||||
|
return 1;
|
||||||
|
case 5:
|
||||||
|
return 2;
|
||||||
|
case 7:
|
||||||
|
return 4;
|
||||||
|
case 10:
|
||||||
|
return 8;
|
||||||
|
default:
|
||||||
|
log ("bad irq %d", irq);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
static int irq_of_magic (int magic)
|
||||||
|
{
|
||||||
|
switch (magic) {
|
||||||
|
case 1:
|
||||||
|
return 2;
|
||||||
|
case 2:
|
||||||
|
return 5;
|
||||||
|
case 4:
|
||||||
|
return 7;
|
||||||
|
case 8:
|
||||||
|
return 10;
|
||||||
|
default:
|
||||||
|
log ("bad irq magic %d", magic);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void SB16_init (void)
|
||||||
|
{
|
||||||
|
SB16State *s = &dsp;
|
||||||
|
int i;
|
||||||
|
static const uint8_t dsp_write_ports[] = {0x6, 0xc};
|
||||||
|
static const uint8_t dsp_read_ports[] = {0x6, 0xa, 0xc, 0xd, 0xe, 0xf};
|
||||||
|
|
||||||
|
memset(s->mixer_regs, 0xff, sizeof(s->mixer_regs));
|
||||||
|
|
||||||
|
s->mixer_regs[0x0e] = ~0;
|
||||||
|
s->mixer_regs[0x80] = magic_of_irq (sb.irq);
|
||||||
|
s->mixer_regs[0x81] = 0x20 | (sb.dma << 1);
|
||||||
|
|
||||||
|
for (i = 0x30; i < 0x48; i++) {
|
||||||
|
s->mixer_regs[i] = 0x20;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < LENOFA (dsp_write_ports); i++) {
|
||||||
|
register_ioport_write (sb.port + dsp_write_ports[i], 1, 1, dsp_write, s);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < LENOFA (dsp_read_ports); i++) {
|
||||||
|
register_ioport_read (sb.port + dsp_read_ports[i], 1, 1, dsp_read, s);
|
||||||
|
}
|
||||||
|
|
||||||
|
register_ioport_write (sb.port + 0x4, 1, 1, mixer_write_indexb, s);
|
||||||
|
register_ioport_write (sb.port + 0x4, 1, 2, mixer_write_indexw, s);
|
||||||
|
register_ioport_read (sb.port + 0x5, 1, 1, mixer_read, s);
|
||||||
|
register_ioport_write (sb.port + 0x5, 1, 1, mixer_write_datab, s);
|
||||||
|
|
||||||
|
DMA_register_channel (sb.hdma, SB_read_DMA, s);
|
||||||
|
DMA_register_channel (sb.dma, SB_read_DMA, s);
|
||||||
|
}
|
||||||
+283
@@ -0,0 +1,283 @@
|
|||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
int out_fd;
|
||||||
|
};
|
||||||
|
|
||||||
|
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;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
if (s->out_fd >= 0) {
|
||||||
|
ch = val;
|
||||||
|
do {
|
||||||
|
ret = write(s->out_fd, &ch, 1);
|
||||||
|
} while (ret != 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;
|
||||||
|
serial_update_irq(s);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
s->lcr = val;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
s->mcr = val;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
int serial_can_receive(SerialState *s)
|
||||||
|
{
|
||||||
|
return !(s->lsr & UART_LSR_DR);
|
||||||
|
}
|
||||||
|
|
||||||
|
void serial_receive_byte(SerialState *s, int ch)
|
||||||
|
{
|
||||||
|
s->rbr = ch;
|
||||||
|
s->lsr |= UART_LSR_DR;
|
||||||
|
serial_update_irq(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
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]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If fd is zero, it means that the serial device uses the console */
|
||||||
|
SerialState *serial_init(int base, int irq, int fd)
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
|
||||||
|
if (fd < 0) {
|
||||||
|
/* no associated device */
|
||||||
|
s->out_fd = -1;
|
||||||
|
} else if (fd != 0) {
|
||||||
|
qemu_add_fd_read_handler(fd, serial_can_receive1, serial_receive1, s);
|
||||||
|
s->out_fd = fd;
|
||||||
|
} else {
|
||||||
|
serial_console = s;
|
||||||
|
s->out_fd = 1;
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
}
|
||||||
+167
@@ -0,0 +1,167 @@
|
|||||||
|
/*
|
||||||
|
* 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; \
|
||||||
|
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];
|
||||||
+111
-11
@@ -127,14 +127,14 @@ static void glue(vga_draw_glyph9_, DEPTH)(uint8_t *d, int linesize,
|
|||||||
else
|
else
|
||||||
((uint16_t *)d)[8] = bgcol;
|
((uint16_t *)d)[8] = bgcol;
|
||||||
#else
|
#else
|
||||||
((uint32_t *)d)[0] = ((-(font_data >> 7)) & xorcol) ^ bgcol;
|
((uint32_t *)d)[0] = (-((font_data >> 7)) & xorcol) ^ bgcol;
|
||||||
((uint32_t *)d)[1] = ((-(font_data >> 6) & 1) & 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)[2] = (-((font_data >> 5) & 1) & xorcol) ^ bgcol;
|
||||||
((uint32_t *)d)[3] = ((-(font_data >> 4) & 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)[4] = (-((font_data >> 3) & 1) & xorcol) ^ bgcol;
|
||||||
((uint32_t *)d)[5] = ((-(font_data >> 2) & 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)[6] = (-((font_data >> 1) & 1) & xorcol) ^ bgcol;
|
||||||
v = ((-(font_data >> 0) & 1) & xorcol) ^ bgcol;
|
v = (-((font_data >> 0) & 1) & xorcol) ^ bgcol;
|
||||||
((uint32_t *)d)[7] = v;
|
((uint32_t *)d)[7] = v;
|
||||||
if (dup9)
|
if (dup9)
|
||||||
((uint32_t *)d)[8] = v;
|
((uint32_t *)d)[8] = v;
|
||||||
@@ -346,7 +346,7 @@ static void glue(vga_draw_line8_, DEPTH)(VGAState *s1, uint8_t *d,
|
|||||||
static void glue(vga_draw_line15_, DEPTH)(VGAState *s1, uint8_t *d,
|
static void glue(vga_draw_line15_, DEPTH)(VGAState *s1, uint8_t *d,
|
||||||
const uint8_t *s, int width)
|
const uint8_t *s, int width)
|
||||||
{
|
{
|
||||||
#if DEPTH == 15 && !defined(WORDS_BIGENDIAN)
|
#if DEPTH == 15 && defined(WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN)
|
||||||
memcpy(d, s, width * 2);
|
memcpy(d, s, width * 2);
|
||||||
#else
|
#else
|
||||||
int w;
|
int w;
|
||||||
@@ -371,7 +371,7 @@ static void glue(vga_draw_line15_, DEPTH)(VGAState *s1, uint8_t *d,
|
|||||||
static void glue(vga_draw_line16_, DEPTH)(VGAState *s1, uint8_t *d,
|
static void glue(vga_draw_line16_, DEPTH)(VGAState *s1, uint8_t *d,
|
||||||
const uint8_t *s, int width)
|
const uint8_t *s, int width)
|
||||||
{
|
{
|
||||||
#if DEPTH == 16 && !defined(WORDS_BIGENDIAN)
|
#if DEPTH == 16 && defined(WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN)
|
||||||
memcpy(d, s, width * 2);
|
memcpy(d, s, width * 2);
|
||||||
#else
|
#else
|
||||||
int w;
|
int w;
|
||||||
@@ -390,13 +390,39 @@ static void glue(vga_draw_line16_, DEPTH)(VGAState *s1, uint8_t *d,
|
|||||||
#endif
|
#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
|
* 32 bit color
|
||||||
*/
|
*/
|
||||||
static void glue(vga_draw_line32_, DEPTH)(VGAState *s1, uint8_t *d,
|
static void glue(vga_draw_line32_, DEPTH)(VGAState *s1, uint8_t *d,
|
||||||
const uint8_t *s, int width)
|
const uint8_t *s, int width)
|
||||||
{
|
{
|
||||||
#if DEPTH == 32 && !defined(WORDS_BIGENDIAN)
|
#if DEPTH == 32 && defined(WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN)
|
||||||
memcpy(d, s, width * 4);
|
memcpy(d, s, width * 4);
|
||||||
#else
|
#else
|
||||||
int w;
|
int w;
|
||||||
@@ -404,9 +430,15 @@ static void glue(vga_draw_line32_, DEPTH)(VGAState *s1, uint8_t *d,
|
|||||||
|
|
||||||
w = width;
|
w = width;
|
||||||
do {
|
do {
|
||||||
|
#if defined(TARGET_WORDS_BIGENDIAN)
|
||||||
|
r = s[1];
|
||||||
|
g = s[2];
|
||||||
|
b = s[3];
|
||||||
|
#else
|
||||||
b = s[0];
|
b = s[0];
|
||||||
g = s[1];
|
g = s[1];
|
||||||
r = s[2];
|
r = s[2];
|
||||||
|
#endif
|
||||||
((PIXEL_TYPE *)d)[0] = glue(rgb_to_pixel, DEPTH)(r, g, b);
|
((PIXEL_TYPE *)d)[0] = glue(rgb_to_pixel, DEPTH)(r, g, b);
|
||||||
s += 4;
|
s += 4;
|
||||||
d += BPP;
|
d += BPP;
|
||||||
@@ -414,6 +446,74 @@ static void glue(vga_draw_line32_, DEPTH)(VGAState *s1, uint8_t *d,
|
|||||||
#endif
|
#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 PUT_PIXEL2
|
||||||
#undef DEPTH
|
#undef DEPTH
|
||||||
#undef BPP
|
#undef BPP
|
||||||
|
|||||||
+3159
-1316
File diff suppressed because it is too large.
Load diff
@@ -53,6 +53,16 @@ SECTIONS
|
|||||||
_etext = .;
|
_etext = .;
|
||||||
PROVIDE (etext = .);
|
PROVIDE (etext = .);
|
||||||
.fini : { *(.fini) } =0x47ff041f
|
.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*) }
|
.rodata : { *(.rodata) *(.gnu.linkonce.r*) }
|
||||||
.rodata1 : { *(.rodata1) }
|
.rodata1 : { *(.rodata1) }
|
||||||
.reginfo : { *(.reginfo) }
|
.reginfo : { *(.reginfo) }
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -26,3 +26,5 @@ struct target_pt_regs {
|
|||||||
#define ARM_ORIG_r0 uregs[17]
|
#define ARM_ORIG_r0 uregs[17]
|
||||||
|
|
||||||
#define ARM_SYSCALL_BASE 0x900000
|
#define ARM_SYSCALL_BASE 0x900000
|
||||||
|
|
||||||
|
#define ARM_NR_cacheflush (ARM_SYSCALL_BASE + 0xf0000 + 2)
|
||||||
@@ -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 */
|
||||||
|
|
||||||
+172
-71
@@ -13,6 +13,16 @@
|
|||||||
#include "qemu.h"
|
#include "qemu.h"
|
||||||
#include "disas.h"
|
#include "disas.h"
|
||||||
|
|
||||||
|
/* this flag is uneffective under linux too, should be deleted */
|
||||||
|
#ifndef MAP_DENYWRITE
|
||||||
|
#define MAP_DENYWRITE 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* should probably go in elf.h */
|
||||||
|
#ifndef ELIBBAD
|
||||||
|
#define ELIBBAD 80
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef TARGET_I386
|
#ifdef TARGET_I386
|
||||||
|
|
||||||
#define ELF_START_MMAP 0x80000000
|
#define ELF_START_MMAP 0x80000000
|
||||||
@@ -98,12 +108,88 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i
|
|||||||
|
|
||||||
static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
|
static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
|
||||||
{
|
{
|
||||||
regs->u_regs[0] = infop->entry;
|
regs->psr = 0;
|
||||||
regs->u_regs[1] = infop->start_stack;
|
regs->pc = infop->entry;
|
||||||
|
regs->npc = regs->pc + 4;
|
||||||
|
regs->y = 0;
|
||||||
|
regs->u_regs[14] = infop->start_stack - 16 * 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef TARGET_PPC
|
||||||
|
|
||||||
|
#define ELF_START_MMAP 0x80000000
|
||||||
|
|
||||||
|
#define elf_check_arch(x) ( (x) == EM_PPC )
|
||||||
|
|
||||||
|
#define ELF_CLASS ELFCLASS32
|
||||||
|
#ifdef TARGET_WORDS_BIGENDIAN
|
||||||
|
#define ELF_DATA ELFDATA2MSB
|
||||||
|
#else
|
||||||
|
#define ELF_DATA ELFDATA2LSB
|
||||||
|
#endif
|
||||||
|
#define ELF_ARCH EM_PPC
|
||||||
|
|
||||||
|
/* Note that isn't exactly what regular kernel does
|
||||||
|
* but this is what the ABI wants and is needed to allow
|
||||||
|
* execution of PPC BSD programs.
|
||||||
|
*/
|
||||||
|
#define ELF_PLAT_INIT(_r) \
|
||||||
|
do { \
|
||||||
|
target_ulong *pos = (target_ulong *)bprm->p, tmp = 1; \
|
||||||
|
_r->gpr[3] = bprm->argc; \
|
||||||
|
_r->gpr[4] = (unsigned long)++pos; \
|
||||||
|
for (; tmp != 0; pos++) \
|
||||||
|
tmp = *pos; \
|
||||||
|
_r->gpr[5] = (unsigned long)pos; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We need to put in some extra aux table entries to tell glibc what
|
||||||
|
* the cache block size is, so it can use the dcbz instruction safely.
|
||||||
|
*/
|
||||||
|
#define AT_DCACHEBSIZE 19
|
||||||
|
#define AT_ICACHEBSIZE 20
|
||||||
|
#define AT_UCACHEBSIZE 21
|
||||||
|
/* A special ignored type value for PPC, for glibc compatibility. */
|
||||||
|
#define AT_IGNOREPPC 22
|
||||||
|
/*
|
||||||
|
* The requirements here are:
|
||||||
|
* - keep the final alignment of sp (sp & 0xf)
|
||||||
|
* - make sure the 32-bit value at the first 16 byte aligned position of
|
||||||
|
* AUXV is greater than 16 for glibc compatibility.
|
||||||
|
* AT_IGNOREPPC is used for that.
|
||||||
|
* - for compatibility with glibc ARCH_DLINFO must always be defined on PPC,
|
||||||
|
* even if DLINFO_ARCH_ITEMS goes to zero or is undefined.
|
||||||
|
*/
|
||||||
|
#define DLINFO_ARCH_ITEMS 3
|
||||||
|
#define ARCH_DLINFO \
|
||||||
|
do { \
|
||||||
|
sp -= DLINFO_ARCH_ITEMS * 2; \
|
||||||
|
NEW_AUX_ENT(0, AT_DCACHEBSIZE, 0x20); \
|
||||||
|
NEW_AUX_ENT(1, AT_ICACHEBSIZE, 0x20); \
|
||||||
|
NEW_AUX_ENT(2, AT_UCACHEBSIZE, 0); \
|
||||||
|
/* \
|
||||||
|
* Now handle glibc compatibility. \
|
||||||
|
*/ \
|
||||||
|
sp -= 2*2; \
|
||||||
|
NEW_AUX_ENT(0, AT_IGNOREPPC, AT_IGNOREPPC); \
|
||||||
|
NEW_AUX_ENT(1, AT_IGNOREPPC, AT_IGNOREPPC); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
static inline void init_thread(struct target_pt_regs *_regs, struct image_info *infop)
|
||||||
|
{
|
||||||
|
_regs->msr = 1 << MSR_PR; /* Set user mode */
|
||||||
|
_regs->gpr[1] = infop->start_stack;
|
||||||
|
_regs->nip = infop->entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define USE_ELF_CORE_DUMP
|
||||||
|
#define ELF_EXEC_PAGESIZE 4096
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "elf.h"
|
#include "elf.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -185,21 +271,13 @@ struct exec
|
|||||||
#define INTERPRETER_AOUT 1
|
#define INTERPRETER_AOUT 1
|
||||||
#define INTERPRETER_ELF 2
|
#define INTERPRETER_ELF 2
|
||||||
|
|
||||||
#define DLINFO_ITEMS 12
|
#define DLINFO_ITEMS 11
|
||||||
|
|
||||||
#define put_user(x,ptr) (void)(*(ptr) = (typeof(*ptr))(x))
|
|
||||||
#define get_user(ptr) (typeof(*ptr))(*(ptr))
|
|
||||||
|
|
||||||
static inline void memcpy_fromfs(void * to, const void * from, unsigned long n)
|
static inline void memcpy_fromfs(void * to, const void * from, unsigned long n)
|
||||||
{
|
{
|
||||||
memcpy(to, from, n);
|
memcpy(to, from, n);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void memcpy_tofs(void * to, const void * from, unsigned long n)
|
|
||||||
{
|
|
||||||
memcpy(to, from, n);
|
|
||||||
}
|
|
||||||
|
|
||||||
extern unsigned long x86_stack_size;
|
extern unsigned long x86_stack_size;
|
||||||
|
|
||||||
static int load_aout_interp(void * exptr, int interp_fd);
|
static int load_aout_interp(void * exptr, int interp_fd);
|
||||||
@@ -264,7 +342,7 @@ static void * get_free_page(void)
|
|||||||
/* User-space version of kernel get_free_page. Returns a page-aligned
|
/* User-space version of kernel get_free_page. Returns a page-aligned
|
||||||
* page-sized chunk of memory.
|
* page-sized chunk of memory.
|
||||||
*/
|
*/
|
||||||
retval = (void *)target_mmap(0, host_page_size, PROT_READ|PROT_WRITE,
|
retval = (void *)target_mmap(0, qemu_host_page_size, PROT_READ|PROT_WRITE,
|
||||||
MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
|
MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
|
||||||
|
|
||||||
if((long)retval == -1) {
|
if((long)retval == -1) {
|
||||||
@@ -278,7 +356,7 @@ static void * get_free_page(void)
|
|||||||
|
|
||||||
static void free_page(void * pageaddr)
|
static void free_page(void * pageaddr)
|
||||||
{
|
{
|
||||||
target_munmap((unsigned long)pageaddr, host_page_size);
|
target_munmap((unsigned long)pageaddr, qemu_host_page_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -297,11 +375,13 @@ static unsigned long copy_strings(int argc,char ** argv,unsigned long *page,
|
|||||||
return 0; /* bullet-proofing */
|
return 0; /* bullet-proofing */
|
||||||
}
|
}
|
||||||
while (argc-- > 0) {
|
while (argc-- > 0) {
|
||||||
if (!(tmp1 = tmp = get_user(argv+argc))) {
|
tmp = argv[argc];
|
||||||
|
if (!tmp) {
|
||||||
fprintf(stderr, "VFS: argc is wrong");
|
fprintf(stderr, "VFS: argc is wrong");
|
||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
while (get_user(tmp++));
|
tmp1 = tmp;
|
||||||
|
while (*tmp++);
|
||||||
len = tmp - tmp1;
|
len = tmp - tmp1;
|
||||||
if (p < len) { /* this shouldn't happen - 128kB */
|
if (p < len) { /* this shouldn't happen - 128kB */
|
||||||
return 0;
|
return 0;
|
||||||
@@ -310,14 +390,16 @@ static unsigned long copy_strings(int argc,char ** argv,unsigned long *page,
|
|||||||
--p; --tmp; --len;
|
--p; --tmp; --len;
|
||||||
if (--offset < 0) {
|
if (--offset < 0) {
|
||||||
offset = p % TARGET_PAGE_SIZE;
|
offset = p % TARGET_PAGE_SIZE;
|
||||||
if (!(pag = (char *) page[p/TARGET_PAGE_SIZE]) &&
|
pag = (char *) page[p/TARGET_PAGE_SIZE];
|
||||||
!(pag = (char *) page[p/TARGET_PAGE_SIZE] =
|
if (!pag) {
|
||||||
(unsigned long *) get_free_page())) {
|
pag = (char *)get_free_page();
|
||||||
return 0;
|
page[p/TARGET_PAGE_SIZE] = (unsigned long)pag;
|
||||||
|
if (!pag)
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (len == 0 || offset == 0) {
|
if (len == 0 || offset == 0) {
|
||||||
*(pag + offset) = get_user(tmp);
|
*(pag + offset) = *tmp;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
int bytes_to_copy = (len > offset) ? offset : len;
|
int bytes_to_copy = (len > offset) ? offset : len;
|
||||||
@@ -430,7 +512,7 @@ unsigned long setup_arg_pages(unsigned long p, struct linux_binprm * bprm,
|
|||||||
if (size < MAX_ARG_PAGES*TARGET_PAGE_SIZE)
|
if (size < MAX_ARG_PAGES*TARGET_PAGE_SIZE)
|
||||||
size = MAX_ARG_PAGES*TARGET_PAGE_SIZE;
|
size = MAX_ARG_PAGES*TARGET_PAGE_SIZE;
|
||||||
error = target_mmap(0,
|
error = target_mmap(0,
|
||||||
size + host_page_size,
|
size + qemu_host_page_size,
|
||||||
PROT_READ | PROT_WRITE,
|
PROT_READ | PROT_WRITE,
|
||||||
MAP_PRIVATE | MAP_ANONYMOUS,
|
MAP_PRIVATE | MAP_ANONYMOUS,
|
||||||
-1, 0);
|
-1, 0);
|
||||||
@@ -439,7 +521,7 @@ unsigned long setup_arg_pages(unsigned long p, struct linux_binprm * bprm,
|
|||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
/* we reserve one extra page at the top of the stack as guard */
|
/* we reserve one extra page at the top of the stack as guard */
|
||||||
target_mprotect(error + size, host_page_size, PROT_NONE);
|
target_mprotect(error + size, qemu_host_page_size, PROT_NONE);
|
||||||
|
|
||||||
stack_base = error + size - MAX_ARG_PAGES*TARGET_PAGE_SIZE;
|
stack_base = error + size - MAX_ARG_PAGES*TARGET_PAGE_SIZE;
|
||||||
p += stack_base;
|
p += stack_base;
|
||||||
@@ -490,10 +572,10 @@ static void padzero(unsigned long elf_bss)
|
|||||||
of the file may not be mapped. A better fix would be to
|
of the file may not be mapped. A better fix would be to
|
||||||
patch target_mmap(), but it is more complicated as the file
|
patch target_mmap(), but it is more complicated as the file
|
||||||
size must be known */
|
size must be known */
|
||||||
if (real_host_page_size < host_page_size) {
|
if (qemu_real_host_page_size < qemu_host_page_size) {
|
||||||
unsigned long end_addr, end_addr1;
|
unsigned long end_addr, end_addr1;
|
||||||
end_addr1 = (elf_bss + real_host_page_size - 1) &
|
end_addr1 = (elf_bss + qemu_real_host_page_size - 1) &
|
||||||
~(real_host_page_size - 1);
|
~(qemu_real_host_page_size - 1);
|
||||||
end_addr = HOST_PAGE_ALIGN(elf_bss);
|
end_addr = HOST_PAGE_ALIGN(elf_bss);
|
||||||
if (end_addr1 < end_addr) {
|
if (end_addr1 < end_addr) {
|
||||||
mmap((void *)end_addr1, end_addr - end_addr1,
|
mmap((void *)end_addr1, end_addr - end_addr1,
|
||||||
@@ -502,9 +584,9 @@ static void padzero(unsigned long elf_bss)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
nbyte = elf_bss & (host_page_size-1);
|
nbyte = elf_bss & (qemu_host_page_size-1);
|
||||||
if (nbyte) {
|
if (nbyte) {
|
||||||
nbyte = host_page_size - nbyte;
|
nbyte = qemu_host_page_size - nbyte;
|
||||||
fpnt = (char *) elf_bss;
|
fpnt = (char *) elf_bss;
|
||||||
do {
|
do {
|
||||||
*fpnt++ = 0;
|
*fpnt++ = 0;
|
||||||
@@ -519,53 +601,77 @@ static unsigned int * create_elf_tables(char *p, int argc, int envc,
|
|||||||
unsigned long interp_load_addr, int ibcs,
|
unsigned long interp_load_addr, int ibcs,
|
||||||
struct image_info *info)
|
struct image_info *info)
|
||||||
{
|
{
|
||||||
target_ulong *argv, *envp, *dlinfo;
|
target_ulong *argv, *envp;
|
||||||
target_ulong *sp;
|
target_ulong *sp, *csp;
|
||||||
|
int v;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Force 16 byte alignment here for generality.
|
* Force 16 byte _final_ alignment here for generality.
|
||||||
*/
|
*/
|
||||||
sp = (unsigned int *) (~15UL & (unsigned long) p);
|
sp = (unsigned int *) (~15UL & (unsigned long) p);
|
||||||
sp -= DLINFO_ITEMS*2;
|
csp = sp;
|
||||||
dlinfo = sp;
|
csp -= (DLINFO_ITEMS + 1) * 2;
|
||||||
|
#ifdef DLINFO_ARCH_ITEMS
|
||||||
|
csp -= DLINFO_ARCH_ITEMS*2;
|
||||||
|
#endif
|
||||||
|
csp -= envc+1;
|
||||||
|
csp -= argc+1;
|
||||||
|
csp -= (!ibcs ? 3 : 1); /* argc itself */
|
||||||
|
if ((unsigned long)csp & 15UL)
|
||||||
|
sp -= ((unsigned long)csp & 15UL) / sizeof(*sp);
|
||||||
|
|
||||||
|
#define NEW_AUX_ENT(nr, id, val) \
|
||||||
|
put_user (id, sp + (nr * 2)); \
|
||||||
|
put_user (val, sp + (nr * 2 + 1))
|
||||||
|
sp -= 2;
|
||||||
|
NEW_AUX_ENT (0, AT_NULL, 0);
|
||||||
|
|
||||||
|
sp -= DLINFO_ITEMS*2;
|
||||||
|
NEW_AUX_ENT( 0, AT_PHDR, (target_ulong)(load_addr + exec->e_phoff));
|
||||||
|
NEW_AUX_ENT( 1, AT_PHENT, (target_ulong)(sizeof (struct elf_phdr)));
|
||||||
|
NEW_AUX_ENT( 2, AT_PHNUM, (target_ulong)(exec->e_phnum));
|
||||||
|
NEW_AUX_ENT( 3, AT_PAGESZ, (target_ulong)(TARGET_PAGE_SIZE));
|
||||||
|
NEW_AUX_ENT( 4, AT_BASE, (target_ulong)(interp_load_addr));
|
||||||
|
NEW_AUX_ENT( 5, AT_FLAGS, (target_ulong)0);
|
||||||
|
NEW_AUX_ENT( 6, AT_ENTRY, load_bias + exec->e_entry);
|
||||||
|
NEW_AUX_ENT( 7, AT_UID, (target_ulong) getuid());
|
||||||
|
NEW_AUX_ENT( 8, AT_EUID, (target_ulong) geteuid());
|
||||||
|
NEW_AUX_ENT( 9, AT_GID, (target_ulong) getgid());
|
||||||
|
NEW_AUX_ENT(11, AT_EGID, (target_ulong) getegid());
|
||||||
|
#ifdef ARCH_DLINFO
|
||||||
|
/*
|
||||||
|
* ARCH_DLINFO must come last so platform specific code can enforce
|
||||||
|
* special alignment requirements on the AUXV if necessary (eg. PPC).
|
||||||
|
*/
|
||||||
|
ARCH_DLINFO;
|
||||||
|
#endif
|
||||||
|
#undef NEW_AUX_ENT
|
||||||
|
|
||||||
sp -= envc+1;
|
sp -= envc+1;
|
||||||
envp = sp;
|
envp = sp;
|
||||||
sp -= argc+1;
|
sp -= argc+1;
|
||||||
argv = sp;
|
argv = sp;
|
||||||
if (!ibcs) {
|
if (!ibcs) {
|
||||||
put_user(tswapl((target_ulong)envp),--sp);
|
put_user((target_ulong)envp,--sp);
|
||||||
put_user(tswapl((target_ulong)argv),--sp);
|
put_user((target_ulong)argv,--sp);
|
||||||
}
|
}
|
||||||
|
put_user(argc,--sp);
|
||||||
#define NEW_AUX_ENT(id, val) \
|
|
||||||
put_user (tswapl(id), dlinfo++); \
|
|
||||||
put_user (tswapl(val), dlinfo++)
|
|
||||||
|
|
||||||
NEW_AUX_ENT (AT_PHDR, (target_ulong)(load_addr + exec->e_phoff));
|
|
||||||
NEW_AUX_ENT (AT_PHENT, (target_ulong)(sizeof (struct elf_phdr)));
|
|
||||||
NEW_AUX_ENT (AT_PHNUM, (target_ulong)(exec->e_phnum));
|
|
||||||
NEW_AUX_ENT (AT_PAGESZ, (target_ulong)(TARGET_PAGE_SIZE));
|
|
||||||
NEW_AUX_ENT (AT_BASE, (target_ulong)(interp_load_addr));
|
|
||||||
NEW_AUX_ENT (AT_FLAGS, (target_ulong)0);
|
|
||||||
NEW_AUX_ENT (AT_ENTRY, load_bias + exec->e_entry);
|
|
||||||
NEW_AUX_ENT (AT_UID, (target_ulong) getuid());
|
|
||||||
NEW_AUX_ENT (AT_EUID, (target_ulong) geteuid());
|
|
||||||
NEW_AUX_ENT (AT_GID, (target_ulong) getgid());
|
|
||||||
NEW_AUX_ENT (AT_EGID, (target_ulong) getegid());
|
|
||||||
NEW_AUX_ENT (AT_NULL, 0);
|
|
||||||
#undef NEW_AUX_ENT
|
|
||||||
|
|
||||||
put_user(tswapl(argc),--sp);
|
|
||||||
info->arg_start = (unsigned int)((unsigned long)p & 0xffffffff);
|
info->arg_start = (unsigned int)((unsigned long)p & 0xffffffff);
|
||||||
while (argc-->0) {
|
while (argc-->0) {
|
||||||
put_user(tswapl((target_ulong)p),argv++);
|
put_user((target_ulong)p,argv++);
|
||||||
while (get_user(p++)) /* nothing */ ;
|
do {
|
||||||
|
get_user(v, p);
|
||||||
|
p++;
|
||||||
|
} while (v != 0);
|
||||||
}
|
}
|
||||||
put_user(0,argv);
|
put_user(0,argv);
|
||||||
info->arg_end = info->env_start = (unsigned int)((unsigned long)p & 0xffffffff);
|
info->arg_end = info->env_start = (unsigned int)((unsigned long)p & 0xffffffff);
|
||||||
while (envc-->0) {
|
while (envc-->0) {
|
||||||
put_user(tswapl((target_ulong)p),envp++);
|
put_user((target_ulong)p,envp++);
|
||||||
while (get_user(p++)) /* nothing */ ;
|
do {
|
||||||
|
get_user(v, p);
|
||||||
|
p++;
|
||||||
|
} while (v != 0);
|
||||||
}
|
}
|
||||||
put_user(0,envp);
|
put_user(0,envp);
|
||||||
info->env_end = (unsigned int)((unsigned long)p & 0xffffffff);
|
info->env_end = (unsigned int)((unsigned long)p & 0xffffffff);
|
||||||
@@ -715,7 +821,7 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex,
|
|||||||
* bss page.
|
* bss page.
|
||||||
*/
|
*/
|
||||||
padzero(elf_bss);
|
padzero(elf_bss);
|
||||||
elf_bss = TARGET_ELF_PAGESTART(elf_bss + host_page_size - 1); /* What we have mapped so far */
|
elf_bss = TARGET_ELF_PAGESTART(elf_bss + qemu_host_page_size - 1); /* What we have mapped so far */
|
||||||
|
|
||||||
/* Map the last of the bss segment */
|
/* Map the last of the bss segment */
|
||||||
if (last_bss > elf_bss) {
|
if (last_bss > elf_bss) {
|
||||||
@@ -971,7 +1077,7 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r
|
|||||||
char * passed_p;
|
char * passed_p;
|
||||||
|
|
||||||
if (interpreter_type == INTERPRETER_AOUT) {
|
if (interpreter_type == INTERPRETER_AOUT) {
|
||||||
sprintf(passed_fileno, "%d", bprm->fd);
|
snprintf(passed_fileno, sizeof(passed_fileno), "%d", bprm->fd);
|
||||||
passed_p = passed_fileno;
|
passed_p = passed_fileno;
|
||||||
|
|
||||||
if (elf_interpreter) {
|
if (elf_interpreter) {
|
||||||
@@ -1156,7 +1262,7 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r
|
|||||||
and some applications "depend" upon this behavior.
|
and some applications "depend" upon this behavior.
|
||||||
Since we do not have the power to recompile these, we
|
Since we do not have the power to recompile these, we
|
||||||
emulate the SVr4 behavior. Sigh. */
|
emulate the SVr4 behavior. Sigh. */
|
||||||
mapped_addr = target_mmap(0, host_page_size, PROT_READ | PROT_EXEC,
|
mapped_addr = target_mmap(0, qemu_host_page_size, PROT_READ | PROT_EXEC,
|
||||||
MAP_FIXED | MAP_PRIVATE, -1, 0);
|
MAP_FIXED | MAP_PRIVATE, -1, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1189,14 +1295,9 @@ int elf_exec(const char * filename, char ** argv, char ** envp,
|
|||||||
for (i=0 ; i<MAX_ARG_PAGES ; i++) /* clear page-table */
|
for (i=0 ; i<MAX_ARG_PAGES ; i++) /* clear page-table */
|
||||||
bprm.page[i] = 0;
|
bprm.page[i] = 0;
|
||||||
retval = open(filename, O_RDONLY);
|
retval = open(filename, O_RDONLY);
|
||||||
if (retval == -1) {
|
if (retval < 0)
|
||||||
perror(filename);
|
return retval;
|
||||||
exit(-1);
|
bprm.fd = retval;
|
||||||
/* return retval; */
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
bprm.fd = retval;
|
|
||||||
}
|
|
||||||
bprm.filename = (char *)filename;
|
bprm.filename = (char *)filename;
|
||||||
bprm.sh_bang = 0;
|
bprm.sh_bang = 0;
|
||||||
bprm.loader = 0;
|
bprm.loader = 0;
|
||||||
|
|||||||
@@ -0,0 +1,214 @@
|
|||||||
|
/* from asm/termbits.h */
|
||||||
|
|
||||||
|
#define TARGET_NCCS 19
|
||||||
|
|
||||||
|
struct target_termios {
|
||||||
|
unsigned int c_iflag; /* input mode flags */
|
||||||
|
unsigned int c_oflag; /* output mode flags */
|
||||||
|
unsigned int c_cflag; /* control mode flags */
|
||||||
|
unsigned int c_lflag; /* local mode flags */
|
||||||
|
unsigned char c_line; /* line discipline */
|
||||||
|
unsigned char c_cc[TARGET_NCCS]; /* control characters */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* c_iflag bits */
|
||||||
|
#define TARGET_IGNBRK 0000001
|
||||||
|
#define TARGET_BRKINT 0000002
|
||||||
|
#define TARGET_IGNPAR 0000004
|
||||||
|
#define TARGET_PARMRK 0000010
|
||||||
|
#define TARGET_INPCK 0000020
|
||||||
|
#define TARGET_ISTRIP 0000040
|
||||||
|
#define TARGET_INLCR 0000100
|
||||||
|
#define TARGET_IGNCR 0000200
|
||||||
|
#define TARGET_ICRNL 0000400
|
||||||
|
#define TARGET_IUCLC 0001000
|
||||||
|
#define TARGET_IXON 0002000
|
||||||
|
#define TARGET_IXANY 0004000
|
||||||
|
#define TARGET_IXOFF 0010000
|
||||||
|
#define TARGET_IMAXBEL 0020000
|
||||||
|
|
||||||
|
/* c_oflag bits */
|
||||||
|
#define TARGET_OPOST 0000001
|
||||||
|
#define TARGET_OLCUC 0000002
|
||||||
|
#define TARGET_ONLCR 0000004
|
||||||
|
#define TARGET_OCRNL 0000010
|
||||||
|
#define TARGET_ONOCR 0000020
|
||||||
|
#define TARGET_ONLRET 0000040
|
||||||
|
#define TARGET_OFILL 0000100
|
||||||
|
#define TARGET_OFDEL 0000200
|
||||||
|
#define TARGET_NLDLY 0000400
|
||||||
|
#define TARGET_NL0 0000000
|
||||||
|
#define TARGET_NL1 0000400
|
||||||
|
#define TARGET_CRDLY 0003000
|
||||||
|
#define TARGET_CR0 0000000
|
||||||
|
#define TARGET_CR1 0001000
|
||||||
|
#define TARGET_CR2 0002000
|
||||||
|
#define TARGET_CR3 0003000
|
||||||
|
#define TARGET_TABDLY 0014000
|
||||||
|
#define TARGET_TAB0 0000000
|
||||||
|
#define TARGET_TAB1 0004000
|
||||||
|
#define TARGET_TAB2 0010000
|
||||||
|
#define TARGET_TAB3 0014000
|
||||||
|
#define TARGET_XTABS 0014000
|
||||||
|
#define TARGET_BSDLY 0020000
|
||||||
|
#define TARGET_BS0 0000000
|
||||||
|
#define TARGET_BS1 0020000
|
||||||
|
#define TARGET_VTDLY 0040000
|
||||||
|
#define TARGET_VT0 0000000
|
||||||
|
#define TARGET_VT1 0040000
|
||||||
|
#define TARGET_FFDLY 0100000
|
||||||
|
#define TARGET_FF0 0000000
|
||||||
|
#define TARGET_FF1 0100000
|
||||||
|
|
||||||
|
/* c_cflag bit meaning */
|
||||||
|
#define TARGET_CBAUD 0010017
|
||||||
|
#define TARGET_B0 0000000 /* hang up */
|
||||||
|
#define TARGET_B50 0000001
|
||||||
|
#define TARGET_B75 0000002
|
||||||
|
#define TARGET_B110 0000003
|
||||||
|
#define TARGET_B134 0000004
|
||||||
|
#define TARGET_B150 0000005
|
||||||
|
#define TARGET_B200 0000006
|
||||||
|
#define TARGET_B300 0000007
|
||||||
|
#define TARGET_B600 0000010
|
||||||
|
#define TARGET_B1200 0000011
|
||||||
|
#define TARGET_B1800 0000012
|
||||||
|
#define TARGET_B2400 0000013
|
||||||
|
#define TARGET_B4800 0000014
|
||||||
|
#define TARGET_B9600 0000015
|
||||||
|
#define TARGET_B19200 0000016
|
||||||
|
#define TARGET_B38400 0000017
|
||||||
|
#define TARGET_EXTA B19200
|
||||||
|
#define TARGET_EXTB B38400
|
||||||
|
#define TARGET_CSIZE 0000060
|
||||||
|
#define TARGET_CS5 0000000
|
||||||
|
#define TARGET_CS6 0000020
|
||||||
|
#define TARGET_CS7 0000040
|
||||||
|
#define TARGET_CS8 0000060
|
||||||
|
#define TARGET_CSTOPB 0000100
|
||||||
|
#define TARGET_CREAD 0000200
|
||||||
|
#define TARGET_PARENB 0000400
|
||||||
|
#define TARGET_PARODD 0001000
|
||||||
|
#define TARGET_HUPCL 0002000
|
||||||
|
#define TARGET_CLOCAL 0004000
|
||||||
|
#define TARGET_CBAUDEX 0010000
|
||||||
|
#define TARGET_B57600 0010001
|
||||||
|
#define TARGET_B115200 0010002
|
||||||
|
#define TARGET_B230400 0010003
|
||||||
|
#define TARGET_B460800 0010004
|
||||||
|
#define TARGET_CIBAUD 002003600000 /* input baud rate (not used) */
|
||||||
|
#define TARGET_CRTSCTS 020000000000 /* flow control */
|
||||||
|
|
||||||
|
/* c_lflag bits */
|
||||||
|
#define TARGET_ISIG 0000001
|
||||||
|
#define TARGET_ICANON 0000002
|
||||||
|
#define TARGET_XCASE 0000004
|
||||||
|
#define TARGET_ECHO 0000010
|
||||||
|
#define TARGET_ECHOE 0000020
|
||||||
|
#define TARGET_ECHOK 0000040
|
||||||
|
#define TARGET_ECHONL 0000100
|
||||||
|
#define TARGET_NOFLSH 0000200
|
||||||
|
#define TARGET_TOSTOP 0000400
|
||||||
|
#define TARGET_ECHOCTL 0001000
|
||||||
|
#define TARGET_ECHOPRT 0002000
|
||||||
|
#define TARGET_ECHOKE 0004000
|
||||||
|
#define TARGET_FLUSHO 0010000
|
||||||
|
#define TARGET_PENDIN 0040000
|
||||||
|
#define TARGET_IEXTEN 0100000
|
||||||
|
|
||||||
|
/* c_cc character offsets */
|
||||||
|
#define TARGET_VINTR 0
|
||||||
|
#define TARGET_VQUIT 1
|
||||||
|
#define TARGET_VERASE 2
|
||||||
|
#define TARGET_VKILL 3
|
||||||
|
#define TARGET_VEOF 4
|
||||||
|
#define TARGET_VTIME 5
|
||||||
|
#define TARGET_VMIN 6
|
||||||
|
#define TARGET_VSWTC 7
|
||||||
|
#define TARGET_VSTART 8
|
||||||
|
#define TARGET_VSTOP 9
|
||||||
|
#define TARGET_VSUSP 10
|
||||||
|
#define TARGET_VEOL 11
|
||||||
|
#define TARGET_VREPRINT 12
|
||||||
|
#define TARGET_VDISCARD 13
|
||||||
|
#define TARGET_VWERASE 14
|
||||||
|
#define TARGET_VLNEXT 15
|
||||||
|
#define TARGET_VEOL2 16
|
||||||
|
|
||||||
|
/* ioctls */
|
||||||
|
|
||||||
|
#define TARGET_TCGETS 0x5401
|
||||||
|
#define TARGET_TCSETS 0x5402
|
||||||
|
#define TARGET_TCSETSW 0x5403
|
||||||
|
#define TARGET_TCSETSF 0x5404
|
||||||
|
#define TARGET_TCGETA 0x5405
|
||||||
|
#define TARGET_TCSETA 0x5406
|
||||||
|
#define TARGET_TCSETAW 0x5407
|
||||||
|
#define TARGET_TCSETAF 0x5408
|
||||||
|
#define TARGET_TCSBRK 0x5409
|
||||||
|
#define TARGET_TCXONC 0x540A
|
||||||
|
#define TARGET_TCFLSH 0x540B
|
||||||
|
|
||||||
|
#define TARGET_TIOCEXCL 0x540C
|
||||||
|
#define TARGET_TIOCNXCL 0x540D
|
||||||
|
#define TARGET_TIOCSCTTY 0x540E
|
||||||
|
#define TARGET_TIOCGPGRP 0x540F
|
||||||
|
#define TARGET_TIOCSPGRP 0x5410
|
||||||
|
#define TARGET_TIOCOUTQ 0x5411
|
||||||
|
#define TARGET_TIOCSTI 0x5412
|
||||||
|
#define TARGET_TIOCGWINSZ 0x5413
|
||||||
|
#define TARGET_TIOCSWINSZ 0x5414
|
||||||
|
#define TARGET_TIOCMGET 0x5415
|
||||||
|
#define TARGET_TIOCMBIS 0x5416
|
||||||
|
#define TARGET_TIOCMBIC 0x5417
|
||||||
|
#define TARGET_TIOCMSET 0x5418
|
||||||
|
#define TARGET_TIOCGSOFTCAR 0x5419
|
||||||
|
#define TARGET_TIOCSSOFTCAR 0x541A
|
||||||
|
#define TARGET_FIONREAD 0x541B
|
||||||
|
#define TARGET_TIOCINQ TARGET_FIONREAD
|
||||||
|
#define TARGET_TIOCLINUX 0x541C
|
||||||
|
#define TARGET_TIOCCONS 0x541D
|
||||||
|
#define TARGET_TIOCGSERIAL 0x541E
|
||||||
|
#define TARGET_TIOCSSERIAL 0x541F
|
||||||
|
#define TARGET_TIOCPKT 0x5420
|
||||||
|
#define TARGET_FIONBIO 0x5421
|
||||||
|
#define TARGET_TIOCNOTTY 0x5422
|
||||||
|
#define TARGET_TIOCSETD 0x5423
|
||||||
|
#define TARGET_TIOCGETD 0x5424
|
||||||
|
#define TARGET_TCSBRKP 0x5425 /* Needed for POSIX tcsendbreak() */
|
||||||
|
#define TARGET_TIOCTTYGSTRUCT 0x5426 /* For debugging only */
|
||||||
|
#define TARGET_TIOCSBRK 0x5427 /* BSD compatibility */
|
||||||
|
#define TARGET_TIOCCBRK 0x5428 /* BSD compatibility */
|
||||||
|
#define TARGET_TIOCGSID 0x5429 /* Return the session ID of FD */
|
||||||
|
#define TARGET_TIOCGPTN TARGET_IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */
|
||||||
|
#define TARGET_TIOCSPTLCK TARGET_IOW('T',0x31, int) /* Lock/unlock Pty */
|
||||||
|
|
||||||
|
#define TARGET_FIONCLEX 0x5450 /* these numbers need to be adjusted. */
|
||||||
|
#define TARGET_FIOCLEX 0x5451
|
||||||
|
#define TARGET_FIOASYNC 0x5452
|
||||||
|
#define TARGET_TIOCSERCONFIG 0x5453
|
||||||
|
#define TARGET_TIOCSERGWILD 0x5454
|
||||||
|
#define TARGET_TIOCSERSWILD 0x5455
|
||||||
|
#define TARGET_TIOCGLCKTRMIOS 0x5456
|
||||||
|
#define TARGET_TIOCSLCKTRMIOS 0x5457
|
||||||
|
#define TARGET_TIOCSERGSTRUCT 0x5458 /* For debugging only */
|
||||||
|
#define TARGET_TIOCSERGETLSR 0x5459 /* Get line status register */
|
||||||
|
#define TARGET_TIOCSERGETMULTI 0x545A /* Get multiport config */
|
||||||
|
#define TARGET_TIOCSERSETMULTI 0x545B /* Set multiport config */
|
||||||
|
|
||||||
|
#define TARGET_TIOCMIWAIT 0x545C /* wait for a change on serial input line(s) */
|
||||||
|
#define TARGET_TIOCGICOUNT 0x545D /* read serial port inline interrupt counts */
|
||||||
|
#define TARGET_TIOCGHAYESESP 0x545E /* Get Hayes ESP configuration */
|
||||||
|
#define TARGET_TIOCSHAYESESP 0x545F /* Set Hayes ESP configuration */
|
||||||
|
|
||||||
|
/* Used for packet mode */
|
||||||
|
#define TARGET_TIOCPKT_DATA 0
|
||||||
|
#define TARGET_TIOCPKT_FLUSHREAD 1
|
||||||
|
#define TARGET_TIOCPKT_FLUSHWRITE 2
|
||||||
|
#define TARGET_TIOCPKT_STOP 4
|
||||||
|
#define TARGET_TIOCPKT_START 8
|
||||||
|
#define TARGET_TIOCPKT_NOSTOP 16
|
||||||
|
#define TARGET_TIOCPKT_DOSTOP 32
|
||||||
|
|
||||||
|
#define TARGET_TIOCSER_TEMT 0x01 /* Transmitter physically empty */
|
||||||
|
|
||||||
+669
-50
@@ -28,9 +28,14 @@
|
|||||||
|
|
||||||
#define DEBUG_LOGFILE "/tmp/qemu.log"
|
#define DEBUG_LOGFILE "/tmp/qemu.log"
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
#include <crt_externs.h>
|
||||||
|
# define environ (*_NSGetEnviron())
|
||||||
|
#endif
|
||||||
|
|
||||||
static const char *interp_prefix = CONFIG_QEMU_PREFIX;
|
static const char *interp_prefix = CONFIG_QEMU_PREFIX;
|
||||||
|
|
||||||
#ifdef __i386__
|
#if defined(__i386__) && !defined(CONFIG_STATIC)
|
||||||
/* Force usage of an ELF interpreter even if it is an ELF shared
|
/* Force usage of an ELF interpreter even if it is an ELF shared
|
||||||
object ! */
|
object ! */
|
||||||
const char interp[] __attribute__((section(".interp"))) = "/lib/ld-linux.so.2";
|
const char interp[] __attribute__((section(".interp"))) = "/lib/ld-linux.so.2";
|
||||||
@@ -38,7 +43,9 @@ const char interp[] __attribute__((section(".interp"))) = "/lib/ld-linux.so.2";
|
|||||||
|
|
||||||
/* for recent libc, we add these dummy symbols which are not declared
|
/* for recent libc, we add these dummy symbols which are not declared
|
||||||
when generating a linked object (bug in ld ?) */
|
when generating a linked object (bug in ld ?) */
|
||||||
#if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 3)
|
#if (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 3)) && !defined(CONFIG_STATIC)
|
||||||
|
long __preinit_array_start[0];
|
||||||
|
long __preinit_array_end[0];
|
||||||
long __init_array_start[0];
|
long __init_array_start[0];
|
||||||
long __init_array_end[0];
|
long __init_array_end[0];
|
||||||
long __fini_array_start[0];
|
long __fini_array_start[0];
|
||||||
@@ -59,48 +66,88 @@ void gemu_log(const char *fmt, ...)
|
|||||||
va_end(ap);
|
va_end(ap);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef TARGET_I386
|
void cpu_outb(CPUState *env, int addr, int val)
|
||||||
/***********************************************************/
|
|
||||||
/* CPUX86 core interface */
|
|
||||||
|
|
||||||
void cpu_x86_outb(CPUX86State *env, int addr, int val)
|
|
||||||
{
|
{
|
||||||
fprintf(stderr, "outb: port=0x%04x, data=%02x\n", addr, val);
|
fprintf(stderr, "outb: port=0x%04x, data=%02x\n", addr, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
void cpu_x86_outw(CPUX86State *env, int addr, int val)
|
void cpu_outw(CPUState *env, int addr, int val)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "outw: port=0x%04x, data=%04x\n", addr, val);
|
fprintf(stderr, "outw: port=0x%04x, data=%04x\n", addr, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
void cpu_x86_outl(CPUX86State *env, int addr, int val)
|
void cpu_outl(CPUState *env, int addr, int val)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "outl: port=0x%04x, data=%08x\n", addr, val);
|
fprintf(stderr, "outl: port=0x%04x, data=%08x\n", addr, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
int cpu_x86_inb(CPUX86State *env, int addr)
|
int cpu_inb(CPUState *env, int addr)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "inb: port=0x%04x\n", addr);
|
fprintf(stderr, "inb: port=0x%04x\n", addr);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int cpu_x86_inw(CPUX86State *env, int addr)
|
int cpu_inw(CPUState *env, int addr)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "inw: port=0x%04x\n", addr);
|
fprintf(stderr, "inw: port=0x%04x\n", addr);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int cpu_x86_inl(CPUX86State *env, int addr)
|
int cpu_inl(CPUState *env, int addr)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "inl: port=0x%04x\n", addr);
|
fprintf(stderr, "inl: port=0x%04x\n", addr);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int cpu_x86_get_pic_interrupt(CPUX86State *env)
|
int cpu_get_pic_interrupt(CPUState *env)
|
||||||
{
|
{
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* timers for rdtsc */
|
||||||
|
|
||||||
|
#if defined(__i386__)
|
||||||
|
|
||||||
|
int64_t cpu_get_real_ticks(void)
|
||||||
|
{
|
||||||
|
int64_t val;
|
||||||
|
asm volatile ("rdtsc" : "=A" (val));
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
#elif defined(__x86_64__)
|
||||||
|
|
||||||
|
int64_t cpu_get_real_ticks(void)
|
||||||
|
{
|
||||||
|
uint32_t low,high;
|
||||||
|
int64_t val;
|
||||||
|
asm volatile("rdtsc" : "=a" (low), "=d" (high));
|
||||||
|
val = high;
|
||||||
|
val <<= 32;
|
||||||
|
val |= low;
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
static uint64_t emu_time;
|
||||||
|
|
||||||
|
int64_t cpu_get_real_ticks(void)
|
||||||
|
{
|
||||||
|
return emu_time++;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef TARGET_I386
|
||||||
|
/***********************************************************/
|
||||||
|
/* CPUX86 core interface */
|
||||||
|
|
||||||
|
uint64_t cpu_get_tsc(CPUX86State *env)
|
||||||
|
{
|
||||||
|
return cpu_get_real_ticks();
|
||||||
|
}
|
||||||
|
|
||||||
static void write_dt(void *ptr, unsigned long addr, unsigned long limit,
|
static void write_dt(void *ptr, unsigned long addr, unsigned long limit,
|
||||||
int flags)
|
int flags)
|
||||||
{
|
{
|
||||||
@@ -244,6 +291,27 @@ void cpu_loop(CPUX86State *env)
|
|||||||
|
|
||||||
#ifdef TARGET_ARM
|
#ifdef TARGET_ARM
|
||||||
|
|
||||||
|
/* XXX: find a better solution */
|
||||||
|
extern void tb_invalidate_page_range(target_ulong start, target_ulong end);
|
||||||
|
|
||||||
|
static void arm_cache_flush(target_ulong start, target_ulong last)
|
||||||
|
{
|
||||||
|
target_ulong addr, last1;
|
||||||
|
|
||||||
|
if (last < start)
|
||||||
|
return;
|
||||||
|
addr = start;
|
||||||
|
for(;;) {
|
||||||
|
last1 = ((addr + TARGET_PAGE_SIZE) & TARGET_PAGE_MASK) - 1;
|
||||||
|
if (last1 > last)
|
||||||
|
last1 = last;
|
||||||
|
tb_invalidate_page_range(addr, last1 + 1);
|
||||||
|
if (last1 == last)
|
||||||
|
break;
|
||||||
|
addr = last1 + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void cpu_loop(CPUARMState *env)
|
void cpu_loop(CPUARMState *env)
|
||||||
{
|
{
|
||||||
int trapnr;
|
int trapnr;
|
||||||
@@ -254,18 +322,34 @@ void cpu_loop(CPUARMState *env)
|
|||||||
trapnr = cpu_arm_exec(env);
|
trapnr = cpu_arm_exec(env);
|
||||||
switch(trapnr) {
|
switch(trapnr) {
|
||||||
case EXCP_UDEF:
|
case EXCP_UDEF:
|
||||||
info.si_signo = SIGILL;
|
{
|
||||||
info.si_errno = 0;
|
TaskState *ts = env->opaque;
|
||||||
info.si_code = TARGET_ILL_ILLOPN;
|
uint32_t opcode;
|
||||||
info._sifields._sigfault._addr = env->regs[15];
|
|
||||||
queue_signal(info.si_signo, &info);
|
/* we handle the FPU emulation here, as Linux */
|
||||||
|
/* we get the opcode */
|
||||||
|
opcode = ldl_raw((uint8_t *)env->regs[15]);
|
||||||
|
|
||||||
|
if (EmulateAll(opcode, &ts->fpa, env->regs) == 0) {
|
||||||
|
info.si_signo = SIGILL;
|
||||||
|
info.si_errno = 0;
|
||||||
|
info.si_code = TARGET_ILL_ILLOPN;
|
||||||
|
info._sifields._sigfault._addr = env->regs[15];
|
||||||
|
queue_signal(info.si_signo, &info);
|
||||||
|
} else {
|
||||||
|
/* increment PC */
|
||||||
|
env->regs[15] += 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case EXCP_SWI:
|
case EXCP_SWI:
|
||||||
{
|
{
|
||||||
/* system call */
|
/* system call */
|
||||||
insn = ldl((void *)(env->regs[15] - 4));
|
insn = ldl((void *)(env->regs[15] - 4));
|
||||||
n = insn & 0xffffff;
|
n = insn & 0xffffff;
|
||||||
if (n >= ARM_SYSCALL_BASE) {
|
if (n == ARM_NR_cacheflush) {
|
||||||
|
arm_cache_flush(env->regs[0], env->regs[1]);
|
||||||
|
} else if (n >= ARM_SYSCALL_BASE) {
|
||||||
/* linux syscall */
|
/* linux syscall */
|
||||||
n -= ARM_SYSCALL_BASE;
|
n -= ARM_SYSCALL_BASE;
|
||||||
env->regs[0] = do_syscall(env,
|
env->regs[0] = do_syscall(env,
|
||||||
@@ -299,35 +383,522 @@ void cpu_loop(CPUARMState *env)
|
|||||||
|
|
||||||
#ifdef TARGET_SPARC
|
#ifdef TARGET_SPARC
|
||||||
|
|
||||||
|
//#define DEBUG_WIN
|
||||||
|
|
||||||
|
/* WARNING: dealing with register windows _is_ complicated */
|
||||||
|
static inline int get_reg_index(CPUSPARCState *env, int cwp, int index)
|
||||||
|
{
|
||||||
|
index = (index + cwp * 16) & (16 * NWINDOWS - 1);
|
||||||
|
/* wrap handling : if cwp is on the last window, then we use the
|
||||||
|
registers 'after' the end */
|
||||||
|
if (index < 8 && env->cwp == (NWINDOWS - 1))
|
||||||
|
index += (16 * NWINDOWS);
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void save_window_offset(CPUSPARCState *env, int offset)
|
||||||
|
{
|
||||||
|
unsigned int new_wim, i, cwp1;
|
||||||
|
uint32_t *sp_ptr;
|
||||||
|
|
||||||
|
new_wim = ((env->wim >> 1) | (env->wim << (NWINDOWS - 1))) &
|
||||||
|
((1LL << NWINDOWS) - 1);
|
||||||
|
/* save the window */
|
||||||
|
cwp1 = (env->cwp + offset) & (NWINDOWS - 1);
|
||||||
|
sp_ptr = (uint32_t *)(env->regbase[get_reg_index(env, cwp1, 6)]);
|
||||||
|
#if defined(DEBUG_WIN)
|
||||||
|
printf("win_overflow: sp_ptr=0x%x save_cwp=%d\n",
|
||||||
|
(int)sp_ptr, cwp1);
|
||||||
|
#endif
|
||||||
|
for(i = 0; i < 16; i++)
|
||||||
|
stl_raw(sp_ptr + i, env->regbase[get_reg_index(env, cwp1, 8 + i)]);
|
||||||
|
env->wim = new_wim;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void save_window(CPUSPARCState *env)
|
||||||
|
{
|
||||||
|
save_window_offset(env, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void restore_window(CPUSPARCState *env)
|
||||||
|
{
|
||||||
|
unsigned int new_wim, i, cwp1;
|
||||||
|
uint32_t *sp_ptr;
|
||||||
|
|
||||||
|
new_wim = ((env->wim << 1) | (env->wim >> (NWINDOWS - 1))) &
|
||||||
|
((1LL << NWINDOWS) - 1);
|
||||||
|
|
||||||
|
/* restore the invalid window */
|
||||||
|
cwp1 = (env->cwp + 1) & (NWINDOWS - 1);
|
||||||
|
sp_ptr = (uint32_t *)(env->regbase[get_reg_index(env, cwp1, 6)]);
|
||||||
|
#if defined(DEBUG_WIN)
|
||||||
|
printf("win_underflow: sp_ptr=0x%x load_cwp=%d\n",
|
||||||
|
(int)sp_ptr, cwp1);
|
||||||
|
#endif
|
||||||
|
for(i = 0; i < 16; i++)
|
||||||
|
env->regbase[get_reg_index(env, cwp1, 8 + i)] = ldl_raw(sp_ptr + i);
|
||||||
|
env->wim = new_wim;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void flush_windows(CPUSPARCState *env)
|
||||||
|
{
|
||||||
|
int offset, cwp1;
|
||||||
|
#if defined(DEBUG_WIN)
|
||||||
|
printf("flush_windows:\n");
|
||||||
|
#endif
|
||||||
|
offset = 2;
|
||||||
|
for(;;) {
|
||||||
|
/* if restore would invoke restore_window(), then we can stop */
|
||||||
|
cwp1 = (env->cwp + 1) & (NWINDOWS - 1);
|
||||||
|
if (env->wim & (1 << cwp1))
|
||||||
|
break;
|
||||||
|
#if defined(DEBUG_WIN)
|
||||||
|
printf("offset=%d: ", offset);
|
||||||
|
#endif
|
||||||
|
save_window_offset(env, offset);
|
||||||
|
offset++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void cpu_loop (CPUSPARCState *env)
|
void cpu_loop (CPUSPARCState *env)
|
||||||
{
|
{
|
||||||
int trapnr;
|
int trapnr, ret;
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
trapnr = cpu_sparc_exec (env);
|
trapnr = cpu_sparc_exec (env);
|
||||||
|
|
||||||
switch (trapnr) {
|
switch (trapnr) {
|
||||||
case 0x8: case 0x10:
|
case 0x88:
|
||||||
env->regwptr[0] = do_syscall (env, env->gregs[1],
|
case 0x90:
|
||||||
env->regwptr[0], env->regwptr[1], env->regwptr[2],
|
ret = do_syscall (env, env->gregs[1],
|
||||||
env->regwptr[3], env->regwptr[4], env->regwptr[13]);
|
env->regwptr[0], env->regwptr[1],
|
||||||
if (env->regwptr[0] >= 0xffffffe0)
|
env->regwptr[2], env->regwptr[3],
|
||||||
env->psr |= PSR_CARRY;
|
env->regwptr[4], env->regwptr[5]);
|
||||||
break;
|
if ((unsigned int)ret >= (unsigned int)(-515)) {
|
||||||
default:
|
env->psr |= PSR_CARRY;
|
||||||
printf ("Invalid trap: %d\n", trapnr);
|
ret = -ret;
|
||||||
exit (1);
|
} else {
|
||||||
}
|
env->psr &= ~PSR_CARRY;
|
||||||
process_pending_signals (env);
|
}
|
||||||
}
|
env->regwptr[0] = ret;
|
||||||
|
/* next instruction */
|
||||||
|
env->pc = env->npc;
|
||||||
|
env->npc = env->npc + 4;
|
||||||
|
break;
|
||||||
|
case 0x83: /* flush windows */
|
||||||
|
// flush_windows(env);
|
||||||
|
/* next instruction */
|
||||||
|
env->pc = env->npc;
|
||||||
|
env->npc = env->npc + 4;
|
||||||
|
break;
|
||||||
|
case TT_WIN_OVF: /* window overflow */
|
||||||
|
save_window(env);
|
||||||
|
break;
|
||||||
|
case TT_WIN_UNF: /* window underflow */
|
||||||
|
restore_window(env);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
printf ("Unhandled trap: 0x%x\n", trapnr);
|
||||||
|
cpu_sparc_dump_state(env, stderr, 0);
|
||||||
|
exit (1);
|
||||||
|
}
|
||||||
|
process_pending_signals (env);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef TARGET_PPC
|
||||||
|
|
||||||
|
static inline uint64_t cpu_ppc_get_tb (CPUState *env)
|
||||||
|
{
|
||||||
|
/* TO FIX */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t cpu_ppc_load_tbl (CPUState *env)
|
||||||
|
{
|
||||||
|
return cpu_ppc_get_tb(env) & 0xFFFFFFFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t cpu_ppc_load_tbu (CPUState *env)
|
||||||
|
{
|
||||||
|
return cpu_ppc_get_tb(env) >> 32;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cpu_ppc_store_tb (CPUState *env, uint64_t value)
|
||||||
|
{
|
||||||
|
/* TO FIX */
|
||||||
|
}
|
||||||
|
|
||||||
|
void cpu_ppc_store_tbu (CPUState *env, uint32_t value)
|
||||||
|
{
|
||||||
|
cpu_ppc_store_tb(env, ((uint64_t)value << 32) | cpu_ppc_load_tbl(env));
|
||||||
|
}
|
||||||
|
|
||||||
|
void cpu_ppc_store_tbl (CPUState *env, uint32_t value)
|
||||||
|
{
|
||||||
|
cpu_ppc_store_tb(env, ((uint64_t)cpu_ppc_load_tbl(env) << 32) | value);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t cpu_ppc_load_decr (CPUState *env)
|
||||||
|
{
|
||||||
|
/* TO FIX */
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cpu_ppc_store_decr (CPUState *env, uint32_t value)
|
||||||
|
{
|
||||||
|
/* TO FIX */
|
||||||
|
}
|
||||||
|
|
||||||
|
void cpu_loop(CPUPPCState *env)
|
||||||
|
{
|
||||||
|
target_siginfo_t info;
|
||||||
|
int trapnr;
|
||||||
|
uint32_t ret;
|
||||||
|
|
||||||
|
for(;;) {
|
||||||
|
trapnr = cpu_ppc_exec(env);
|
||||||
|
if (trapnr != EXCP_SYSCALL_USER && trapnr != EXCP_BRANCH &&
|
||||||
|
trapnr != EXCP_TRACE) {
|
||||||
|
if (loglevel > 0) {
|
||||||
|
cpu_ppc_dump_state(env, logfile, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
switch(trapnr) {
|
||||||
|
case EXCP_NONE:
|
||||||
|
break;
|
||||||
|
case EXCP_SYSCALL_USER:
|
||||||
|
/* system call */
|
||||||
|
/* WARNING:
|
||||||
|
* PPC ABI uses overflow flag in cr0 to signal an error
|
||||||
|
* in syscalls.
|
||||||
|
*/
|
||||||
|
#if 0
|
||||||
|
printf("syscall %d 0x%08x 0x%08x 0x%08x 0x%08x\n", env->gpr[0],
|
||||||
|
env->gpr[3], env->gpr[4], env->gpr[5], env->gpr[6]);
|
||||||
|
#endif
|
||||||
|
env->crf[0] &= ~0x1;
|
||||||
|
ret = do_syscall(env, env->gpr[0], env->gpr[3], env->gpr[4],
|
||||||
|
env->gpr[5], env->gpr[6], env->gpr[7],
|
||||||
|
env->gpr[8]);
|
||||||
|
if (ret > (uint32_t)(-515)) {
|
||||||
|
env->crf[0] |= 0x1;
|
||||||
|
ret = -ret;
|
||||||
|
}
|
||||||
|
env->gpr[3] = ret;
|
||||||
|
#if 0
|
||||||
|
printf("syscall returned 0x%08x (%d)\n", ret, ret);
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
case EXCP_RESET:
|
||||||
|
/* Should not happen ! */
|
||||||
|
fprintf(stderr, "RESET asked... Stop emulation\n");
|
||||||
|
if (loglevel)
|
||||||
|
fprintf(logfile, "RESET asked... Stop emulation\n");
|
||||||
|
abort();
|
||||||
|
case EXCP_MACHINE_CHECK:
|
||||||
|
fprintf(stderr, "Machine check exeption... Stop emulation\n");
|
||||||
|
if (loglevel)
|
||||||
|
fprintf(logfile, "RESET asked... Stop emulation\n");
|
||||||
|
info.si_signo = TARGET_SIGBUS;
|
||||||
|
info.si_errno = 0;
|
||||||
|
info.si_code = TARGET_BUS_OBJERR;
|
||||||
|
info._sifields._sigfault._addr = env->nip - 4;
|
||||||
|
queue_signal(info.si_signo, &info);
|
||||||
|
case EXCP_DSI:
|
||||||
|
fprintf(stderr, "Invalid data memory access: 0x%08x\n", env->spr[DAR]);
|
||||||
|
if (loglevel) {
|
||||||
|
fprintf(logfile, "Invalid data memory access: 0x%08x\n",
|
||||||
|
env->spr[DAR]);
|
||||||
|
}
|
||||||
|
switch (env->error_code & 0xF) {
|
||||||
|
case EXCP_DSI_TRANSLATE:
|
||||||
|
info.si_signo = TARGET_SIGSEGV;
|
||||||
|
info.si_errno = 0;
|
||||||
|
info.si_code = TARGET_SEGV_MAPERR;
|
||||||
|
break;
|
||||||
|
case EXCP_DSI_NOTSUP:
|
||||||
|
case EXCP_DSI_EXTERNAL:
|
||||||
|
info.si_signo = TARGET_SIGILL;
|
||||||
|
info.si_errno = 0;
|
||||||
|
info.si_code = TARGET_ILL_ILLADR;
|
||||||
|
break;
|
||||||
|
case EXCP_DSI_PROT:
|
||||||
|
info.si_signo = TARGET_SIGSEGV;
|
||||||
|
info.si_errno = 0;
|
||||||
|
info.si_code = TARGET_SEGV_ACCERR;
|
||||||
|
break;
|
||||||
|
case EXCP_DSI_DABR:
|
||||||
|
info.si_signo = TARGET_SIGTRAP;
|
||||||
|
info.si_errno = 0;
|
||||||
|
info.si_code = TARGET_TRAP_BRKPT;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
/* Let's send a regular segfault... */
|
||||||
|
fprintf(stderr, "Invalid segfault errno (%02x)\n",
|
||||||
|
env->error_code);
|
||||||
|
if (loglevel) {
|
||||||
|
fprintf(logfile, "Invalid segfault errno (%02x)\n",
|
||||||
|
env->error_code);
|
||||||
|
}
|
||||||
|
info.si_signo = TARGET_SIGSEGV;
|
||||||
|
info.si_errno = 0;
|
||||||
|
info.si_code = TARGET_SEGV_MAPERR;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
info._sifields._sigfault._addr = env->nip;
|
||||||
|
queue_signal(info.si_signo, &info);
|
||||||
|
break;
|
||||||
|
case EXCP_ISI:
|
||||||
|
fprintf(stderr, "Invalid instruction fetch\n");
|
||||||
|
if (loglevel)
|
||||||
|
fprintf(logfile, "Invalid instruction fetch\n");
|
||||||
|
switch (env->error_code) {
|
||||||
|
case EXCP_ISI_TRANSLATE:
|
||||||
|
info.si_signo = TARGET_SIGSEGV;
|
||||||
|
info.si_errno = 0;
|
||||||
|
info.si_code = TARGET_SEGV_MAPERR;
|
||||||
|
break;
|
||||||
|
case EXCP_ISI_GUARD:
|
||||||
|
info.si_signo = TARGET_SIGILL;
|
||||||
|
info.si_errno = 0;
|
||||||
|
info.si_code = TARGET_ILL_ILLADR;
|
||||||
|
break;
|
||||||
|
case EXCP_ISI_NOEXEC:
|
||||||
|
case EXCP_ISI_PROT:
|
||||||
|
info.si_signo = TARGET_SIGSEGV;
|
||||||
|
info.si_errno = 0;
|
||||||
|
info.si_code = TARGET_SEGV_ACCERR;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
/* Let's send a regular segfault... */
|
||||||
|
fprintf(stderr, "Invalid segfault errno (%02x)\n",
|
||||||
|
env->error_code);
|
||||||
|
if (loglevel) {
|
||||||
|
fprintf(logfile, "Invalid segfault errno (%02x)\n",
|
||||||
|
env->error_code);
|
||||||
|
}
|
||||||
|
info.si_signo = TARGET_SIGSEGV;
|
||||||
|
info.si_errno = 0;
|
||||||
|
info.si_code = TARGET_SEGV_MAPERR;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
info._sifields._sigfault._addr = env->nip - 4;
|
||||||
|
queue_signal(info.si_signo, &info);
|
||||||
|
break;
|
||||||
|
case EXCP_EXTERNAL:
|
||||||
|
/* Should not happen ! */
|
||||||
|
fprintf(stderr, "External interruption... Stop emulation\n");
|
||||||
|
if (loglevel)
|
||||||
|
fprintf(logfile, "External interruption... Stop emulation\n");
|
||||||
|
abort();
|
||||||
|
case EXCP_ALIGN:
|
||||||
|
fprintf(stderr, "Invalid unaligned memory access\n");
|
||||||
|
if (loglevel)
|
||||||
|
fprintf(logfile, "Invalid unaligned memory access\n");
|
||||||
|
info.si_signo = TARGET_SIGBUS;
|
||||||
|
info.si_errno = 0;
|
||||||
|
info.si_code = TARGET_BUS_ADRALN;
|
||||||
|
info._sifields._sigfault._addr = env->nip - 4;
|
||||||
|
queue_signal(info.si_signo, &info);
|
||||||
|
break;
|
||||||
|
case EXCP_PROGRAM:
|
||||||
|
switch (env->error_code & ~0xF) {
|
||||||
|
case EXCP_FP:
|
||||||
|
fprintf(stderr, "Program exception\n");
|
||||||
|
if (loglevel)
|
||||||
|
fprintf(logfile, "Program exception\n");
|
||||||
|
/* Set FX */
|
||||||
|
env->fpscr[7] |= 0x8;
|
||||||
|
/* Finally, update FEX */
|
||||||
|
if ((((env->fpscr[7] & 0x3) << 3) | (env->fpscr[6] >> 1)) &
|
||||||
|
((env->fpscr[1] << 1) | (env->fpscr[0] >> 3)))
|
||||||
|
env->fpscr[7] |= 0x4;
|
||||||
|
info.si_signo = TARGET_SIGFPE;
|
||||||
|
info.si_errno = 0;
|
||||||
|
switch (env->error_code & 0xF) {
|
||||||
|
case EXCP_FP_OX:
|
||||||
|
info.si_code = TARGET_FPE_FLTOVF;
|
||||||
|
break;
|
||||||
|
case EXCP_FP_UX:
|
||||||
|
info.si_code = TARGET_FPE_FLTUND;
|
||||||
|
break;
|
||||||
|
case EXCP_FP_ZX:
|
||||||
|
case EXCP_FP_VXZDZ:
|
||||||
|
info.si_code = TARGET_FPE_FLTDIV;
|
||||||
|
break;
|
||||||
|
case EXCP_FP_XX:
|
||||||
|
info.si_code = TARGET_FPE_FLTRES;
|
||||||
|
break;
|
||||||
|
case EXCP_FP_VXSOFT:
|
||||||
|
info.si_code = TARGET_FPE_FLTINV;
|
||||||
|
break;
|
||||||
|
case EXCP_FP_VXNAN:
|
||||||
|
case EXCP_FP_VXISI:
|
||||||
|
case EXCP_FP_VXIDI:
|
||||||
|
case EXCP_FP_VXIMZ:
|
||||||
|
case EXCP_FP_VXVC:
|
||||||
|
case EXCP_FP_VXSQRT:
|
||||||
|
case EXCP_FP_VXCVI:
|
||||||
|
info.si_code = TARGET_FPE_FLTSUB;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
fprintf(stderr, "Unknown floating point exception "
|
||||||
|
"(%02x)\n", env->error_code);
|
||||||
|
if (loglevel) {
|
||||||
|
fprintf(logfile, "Unknown floating point exception "
|
||||||
|
"(%02x)\n", env->error_code & 0xF);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case EXCP_INVAL:
|
||||||
|
fprintf(stderr, "Invalid instruction\n");
|
||||||
|
if (loglevel)
|
||||||
|
fprintf(logfile, "Invalid instruction\n");
|
||||||
|
info.si_signo = TARGET_SIGILL;
|
||||||
|
info.si_errno = 0;
|
||||||
|
switch (env->error_code & 0xF) {
|
||||||
|
case EXCP_INVAL_INVAL:
|
||||||
|
info.si_code = TARGET_ILL_ILLOPC;
|
||||||
|
break;
|
||||||
|
case EXCP_INVAL_LSWX:
|
||||||
|
info.si_code = TARGET_ILL_ILLOPN;
|
||||||
|
break;
|
||||||
|
case EXCP_INVAL_SPR:
|
||||||
|
info.si_code = TARGET_ILL_PRVREG;
|
||||||
|
break;
|
||||||
|
case EXCP_INVAL_FP:
|
||||||
|
info.si_code = TARGET_ILL_COPROC;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
fprintf(stderr, "Unknown invalid operation (%02x)\n",
|
||||||
|
env->error_code & 0xF);
|
||||||
|
if (loglevel) {
|
||||||
|
fprintf(logfile, "Unknown invalid operation (%02x)\n",
|
||||||
|
env->error_code & 0xF);
|
||||||
|
}
|
||||||
|
info.si_code = TARGET_ILL_ILLADR;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case EXCP_PRIV:
|
||||||
|
fprintf(stderr, "Privilege violation\n");
|
||||||
|
if (loglevel)
|
||||||
|
fprintf(logfile, "Privilege violation\n");
|
||||||
|
info.si_signo = TARGET_SIGILL;
|
||||||
|
info.si_errno = 0;
|
||||||
|
switch (env->error_code & 0xF) {
|
||||||
|
case EXCP_PRIV_OPC:
|
||||||
|
info.si_code = TARGET_ILL_PRVOPC;
|
||||||
|
break;
|
||||||
|
case EXCP_PRIV_REG:
|
||||||
|
info.si_code = TARGET_ILL_PRVREG;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
fprintf(stderr, "Unknown privilege violation (%02x)\n",
|
||||||
|
env->error_code & 0xF);
|
||||||
|
info.si_code = TARGET_ILL_PRVOPC;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case EXCP_TRAP:
|
||||||
|
fprintf(stderr, "Tried to call a TRAP\n");
|
||||||
|
if (loglevel)
|
||||||
|
fprintf(logfile, "Tried to call a TRAP\n");
|
||||||
|
abort();
|
||||||
|
default:
|
||||||
|
/* Should not happen ! */
|
||||||
|
fprintf(stderr, "Unknown program exception (%02x)\n",
|
||||||
|
env->error_code);
|
||||||
|
if (loglevel) {
|
||||||
|
fprintf(logfile, "Unknwon program exception (%02x)\n",
|
||||||
|
env->error_code);
|
||||||
|
}
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
info._sifields._sigfault._addr = env->nip - 4;
|
||||||
|
queue_signal(info.si_signo, &info);
|
||||||
|
break;
|
||||||
|
case EXCP_NO_FP:
|
||||||
|
fprintf(stderr, "No floating point allowed\n");
|
||||||
|
if (loglevel)
|
||||||
|
fprintf(logfile, "No floating point allowed\n");
|
||||||
|
info.si_signo = TARGET_SIGILL;
|
||||||
|
info.si_errno = 0;
|
||||||
|
info.si_code = TARGET_ILL_COPROC;
|
||||||
|
info._sifields._sigfault._addr = env->nip - 4;
|
||||||
|
queue_signal(info.si_signo, &info);
|
||||||
|
break;
|
||||||
|
case EXCP_DECR:
|
||||||
|
/* Should not happen ! */
|
||||||
|
fprintf(stderr, "Decrementer exception\n");
|
||||||
|
if (loglevel)
|
||||||
|
fprintf(logfile, "Decrementer exception\n");
|
||||||
|
abort();
|
||||||
|
case EXCP_RESA: /* Implementation specific */
|
||||||
|
/* Should not happen ! */
|
||||||
|
fprintf(stderr, "RESA exception should never happen !\n");
|
||||||
|
if (loglevel)
|
||||||
|
fprintf(logfile, "RESA exception should never happen !\n");
|
||||||
|
abort();
|
||||||
|
case EXCP_RESB: /* Implementation specific */
|
||||||
|
/* Should not happen ! */
|
||||||
|
fprintf(stderr, "RESB exception should never happen !\n");
|
||||||
|
if (loglevel)
|
||||||
|
fprintf(logfile, "RESB exception should never happen !\n");
|
||||||
|
abort();
|
||||||
|
case EXCP_TRACE:
|
||||||
|
/* Do nothing: we use this to trace execution */
|
||||||
|
break;
|
||||||
|
case EXCP_FP_ASSIST:
|
||||||
|
/* Should not happen ! */
|
||||||
|
fprintf(stderr, "Floating point assist exception\n");
|
||||||
|
if (loglevel)
|
||||||
|
fprintf(logfile, "Floating point assist exception\n");
|
||||||
|
abort();
|
||||||
|
case EXCP_MTMSR:
|
||||||
|
/* We reloaded the msr, just go on */
|
||||||
|
if (msr_pr == 0) {
|
||||||
|
fprintf(stderr, "Tried to go into supervisor mode !\n");
|
||||||
|
if (loglevel)
|
||||||
|
fprintf(logfile, "Tried to go into supervisor mode !\n");
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case EXCP_BRANCH:
|
||||||
|
/* We stopped because of a jump... */
|
||||||
|
break;
|
||||||
|
case EXCP_RFI:
|
||||||
|
/* Should not occur: we always are in user mode */
|
||||||
|
fprintf(stderr, "Return from interrupt ?\n");
|
||||||
|
if (loglevel)
|
||||||
|
fprintf(logfile, "Return from interrupt ?\n");
|
||||||
|
abort();
|
||||||
|
case EXCP_INTERRUPT:
|
||||||
|
/* Don't know why this should ever happen... */
|
||||||
|
break;
|
||||||
|
case EXCP_DEBUG:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n",
|
||||||
|
trapnr);
|
||||||
|
if (loglevel) {
|
||||||
|
fprintf(logfile, "qemu: unhandled CPU exception 0x%02x - "
|
||||||
|
"0x%02x - aborting\n", trapnr, env->error_code);
|
||||||
|
}
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
process_pending_signals(env);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void usage(void)
|
void usage(void)
|
||||||
{
|
{
|
||||||
printf("qemu-" TARGET_ARCH " version " QEMU_VERSION ", Copyright (c) 2003 Fabrice Bellard\n"
|
printf("qemu-" TARGET_ARCH " version " QEMU_VERSION ", Copyright (c) 2003-2004 Fabrice Bellard\n"
|
||||||
"usage: qemu-" TARGET_ARCH " [-h] [-d] [-L path] [-s size] program [arguments...]\n"
|
"usage: qemu-" TARGET_ARCH " [-h] [-d opts] [-L path] [-s size] program [arguments...]\n"
|
||||||
"Linux CPU emulator (compiled for %s emulation)\n"
|
"Linux CPU emulator (compiled for %s emulation)\n"
|
||||||
"\n"
|
"\n"
|
||||||
"-h print this help\n"
|
"-h print this help\n"
|
||||||
@@ -335,7 +906,10 @@ void usage(void)
|
|||||||
"-s size set the stack size in bytes (default=%ld)\n"
|
"-s size set the stack size in bytes (default=%ld)\n"
|
||||||
"\n"
|
"\n"
|
||||||
"debug options:\n"
|
"debug options:\n"
|
||||||
"-d activate log (logfile=%s)\n"
|
#ifdef USE_CODE_COPY
|
||||||
|
"-no-code-copy disable code copy acceleration\n"
|
||||||
|
#endif
|
||||||
|
"-d options activate log (logfile=%s)\n"
|
||||||
"-p pagesize set the host page size to 'pagesize'\n",
|
"-p pagesize set the host page size to 'pagesize'\n",
|
||||||
TARGET_ARCH,
|
TARGET_ARCH,
|
||||||
interp_prefix,
|
interp_prefix,
|
||||||
@@ -380,7 +954,22 @@ int main(int argc, char **argv)
|
|||||||
if (!strcmp(r, "-")) {
|
if (!strcmp(r, "-")) {
|
||||||
break;
|
break;
|
||||||
} else if (!strcmp(r, "d")) {
|
} else if (!strcmp(r, "d")) {
|
||||||
cpu_set_log(CPU_LOG_ALL);
|
int mask;
|
||||||
|
CPULogItem *item;
|
||||||
|
|
||||||
|
if (optind >= argc)
|
||||||
|
break;
|
||||||
|
|
||||||
|
r = argv[optind++];
|
||||||
|
mask = cpu_str_to_log_mask(r);
|
||||||
|
if (!mask) {
|
||||||
|
printf("Log items (comma separated):\n");
|
||||||
|
for(item = cpu_log_items; item->mask != 0; item++) {
|
||||||
|
printf("%-10s %s\n", item->name, item->help);
|
||||||
|
}
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
cpu_set_log(mask);
|
||||||
} else if (!strcmp(r, "s")) {
|
} else if (!strcmp(r, "s")) {
|
||||||
r = argv[optind++];
|
r = argv[optind++];
|
||||||
x86_stack_size = strtol(r, (char **)&r, 0);
|
x86_stack_size = strtol(r, (char **)&r, 0);
|
||||||
@@ -393,13 +982,19 @@ int main(int argc, char **argv)
|
|||||||
} else if (!strcmp(r, "L")) {
|
} else if (!strcmp(r, "L")) {
|
||||||
interp_prefix = argv[optind++];
|
interp_prefix = argv[optind++];
|
||||||
} else if (!strcmp(r, "p")) {
|
} else if (!strcmp(r, "p")) {
|
||||||
host_page_size = atoi(argv[optind++]);
|
qemu_host_page_size = atoi(argv[optind++]);
|
||||||
if (host_page_size == 0 ||
|
if (qemu_host_page_size == 0 ||
|
||||||
(host_page_size & (host_page_size - 1)) != 0) {
|
(qemu_host_page_size & (qemu_host_page_size - 1)) != 0) {
|
||||||
fprintf(stderr, "page size must be a power of two\n");
|
fprintf(stderr, "page size must be a power of two\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
} else {
|
} else
|
||||||
|
#ifdef USE_CODE_COPY
|
||||||
|
if (!strcmp(r, "no-code-copy")) {
|
||||||
|
code_copy_enabled = 0;
|
||||||
|
} else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
usage();
|
usage();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -416,8 +1011,8 @@ int main(int argc, char **argv)
|
|||||||
/* Scan interp_prefix dir for replacement files. */
|
/* Scan interp_prefix dir for replacement files. */
|
||||||
init_paths(interp_prefix);
|
init_paths(interp_prefix);
|
||||||
|
|
||||||
/* NOTE: we need to init the CPU at this stage to get the
|
/* NOTE: we need to init the CPU at this stage to get
|
||||||
host_page_size */
|
qemu_host_page_size */
|
||||||
env = cpu_init();
|
env = cpu_init();
|
||||||
|
|
||||||
if (elf_exec(filename, argv+optind, environ, regs, info) != 0) {
|
if (elf_exec(filename, argv+optind, environ, regs, info) != 0) {
|
||||||
@@ -453,7 +1048,11 @@ int main(int argc, char **argv)
|
|||||||
cpu_x86_set_cpl(env, 3);
|
cpu_x86_set_cpl(env, 3);
|
||||||
|
|
||||||
env->cr[0] = CR0_PG_MASK | CR0_WP_MASK | CR0_PE_MASK;
|
env->cr[0] = CR0_PG_MASK | CR0_WP_MASK | CR0_PE_MASK;
|
||||||
|
env->hflags |= HF_PE_MASK;
|
||||||
|
|
||||||
|
/* flags setup : we activate the IRQs by default as in user mode */
|
||||||
|
env->eflags |= IF_MASK;
|
||||||
|
|
||||||
/* linux register setup */
|
/* linux register setup */
|
||||||
env->regs[R_EAX] = regs->eax;
|
env->regs[R_EAX] = regs->eax;
|
||||||
env->regs[R_EBX] = regs->ebx;
|
env->regs[R_EBX] = regs->ebx;
|
||||||
@@ -515,8 +1114,28 @@ int main(int argc, char **argv)
|
|||||||
env->cpsr = regs->uregs[16];
|
env->cpsr = regs->uregs[16];
|
||||||
}
|
}
|
||||||
#elif defined(TARGET_SPARC)
|
#elif defined(TARGET_SPARC)
|
||||||
env->pc = regs->u_regs[0];
|
{
|
||||||
env->regwptr[6] = regs->u_regs[1]-0x40;
|
int i;
|
||||||
|
env->pc = regs->pc;
|
||||||
|
env->npc = regs->npc;
|
||||||
|
env->y = regs->y;
|
||||||
|
for(i = 0; i < 8; i++)
|
||||||
|
env->gregs[i] = regs->u_regs[i];
|
||||||
|
for(i = 0; i < 8; i++)
|
||||||
|
env->regwptr[i] = regs->u_regs[i + 8];
|
||||||
|
}
|
||||||
|
#elif defined(TARGET_PPC)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < 32; i++) {
|
||||||
|
if (i != 12 && i != 6)
|
||||||
|
env->msr[i] = (regs->msr >> i) & 1;
|
||||||
|
}
|
||||||
|
env->nip = regs->nip;
|
||||||
|
for(i = 0; i < 32; i++) {
|
||||||
|
env->gpr[i] = regs->gpr[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
#error unsupported target CPU
|
#error unsupported target CPU
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
+36
-31
@@ -53,7 +53,7 @@ int target_mprotect(unsigned long start, unsigned long len, int prot)
|
|||||||
if (len == 0)
|
if (len == 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
host_start = start & host_page_mask;
|
host_start = start & qemu_host_page_mask;
|
||||||
host_end = HOST_PAGE_ALIGN(end);
|
host_end = HOST_PAGE_ALIGN(end);
|
||||||
if (start > host_start) {
|
if (start > host_start) {
|
||||||
/* handle host page containing start */
|
/* handle host page containing start */
|
||||||
@@ -61,27 +61,27 @@ int target_mprotect(unsigned long start, unsigned long len, int prot)
|
|||||||
for(addr = host_start; addr < start; addr += TARGET_PAGE_SIZE) {
|
for(addr = host_start; addr < start; addr += TARGET_PAGE_SIZE) {
|
||||||
prot1 |= page_get_flags(addr);
|
prot1 |= page_get_flags(addr);
|
||||||
}
|
}
|
||||||
if (host_end == host_start + host_page_size) {
|
if (host_end == host_start + qemu_host_page_size) {
|
||||||
for(addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) {
|
for(addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) {
|
||||||
prot1 |= page_get_flags(addr);
|
prot1 |= page_get_flags(addr);
|
||||||
}
|
}
|
||||||
end = host_end;
|
end = host_end;
|
||||||
}
|
}
|
||||||
ret = mprotect((void *)host_start, host_page_size, prot1 & PAGE_BITS);
|
ret = mprotect((void *)host_start, qemu_host_page_size, prot1 & PAGE_BITS);
|
||||||
if (ret != 0)
|
if (ret != 0)
|
||||||
return ret;
|
return ret;
|
||||||
host_start += host_page_size;
|
host_start += qemu_host_page_size;
|
||||||
}
|
}
|
||||||
if (end < host_end) {
|
if (end < host_end) {
|
||||||
prot1 = prot;
|
prot1 = prot;
|
||||||
for(addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) {
|
for(addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) {
|
||||||
prot1 |= page_get_flags(addr);
|
prot1 |= page_get_flags(addr);
|
||||||
}
|
}
|
||||||
ret = mprotect((void *)(host_end - host_page_size), host_page_size,
|
ret = mprotect((void *)(host_end - qemu_host_page_size), qemu_host_page_size,
|
||||||
prot1 & PAGE_BITS);
|
prot1 & PAGE_BITS);
|
||||||
if (ret != 0)
|
if (ret != 0)
|
||||||
return ret;
|
return ret;
|
||||||
host_end -= host_page_size;
|
host_end -= qemu_host_page_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* handle the pages in the middle */
|
/* handle the pages in the middle */
|
||||||
@@ -102,7 +102,7 @@ int mmap_frag(unsigned long host_start,
|
|||||||
unsigned long host_end, ret, addr;
|
unsigned long host_end, ret, addr;
|
||||||
int prot1, prot_new;
|
int prot1, prot_new;
|
||||||
|
|
||||||
host_end = host_start + host_page_size;
|
host_end = host_start + qemu_host_page_size;
|
||||||
|
|
||||||
/* get the protection of the target pages outside the mapping */
|
/* get the protection of the target pages outside the mapping */
|
||||||
prot1 = 0;
|
prot1 = 0;
|
||||||
@@ -113,7 +113,7 @@ int mmap_frag(unsigned long host_start,
|
|||||||
|
|
||||||
if (prot1 == 0) {
|
if (prot1 == 0) {
|
||||||
/* no page was there, so we allocate one */
|
/* no page was there, so we allocate one */
|
||||||
ret = (long)mmap((void *)host_start, host_page_size, prot,
|
ret = (long)mmap((void *)host_start, qemu_host_page_size, prot,
|
||||||
flags | MAP_ANONYMOUS, -1, 0);
|
flags | MAP_ANONYMOUS, -1, 0);
|
||||||
if (ret == -1)
|
if (ret == -1)
|
||||||
return ret;
|
return ret;
|
||||||
@@ -130,18 +130,18 @@ int mmap_frag(unsigned long host_start,
|
|||||||
|
|
||||||
/* adjust protection to be able to read */
|
/* adjust protection to be able to read */
|
||||||
if (!(prot1 & PROT_WRITE))
|
if (!(prot1 & PROT_WRITE))
|
||||||
mprotect((void *)host_start, host_page_size, prot1 | PROT_WRITE);
|
mprotect((void *)host_start, qemu_host_page_size, prot1 | PROT_WRITE);
|
||||||
|
|
||||||
/* read the corresponding file data */
|
/* read the corresponding file data */
|
||||||
pread(fd, (void *)start, end - start, offset);
|
pread(fd, (void *)start, end - start, offset);
|
||||||
|
|
||||||
/* put final protection */
|
/* put final protection */
|
||||||
if (prot_new != (prot1 | PROT_WRITE))
|
if (prot_new != (prot1 | PROT_WRITE))
|
||||||
mprotect((void *)host_start, host_page_size, prot_new);
|
mprotect((void *)host_start, qemu_host_page_size, prot_new);
|
||||||
} else {
|
} else {
|
||||||
/* just update the protection */
|
/* just update the protection */
|
||||||
if (prot_new != prot1) {
|
if (prot_new != prot1) {
|
||||||
mprotect((void *)host_start, host_page_size, prot_new);
|
mprotect((void *)host_start, qemu_host_page_size, prot_new);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
@@ -152,6 +152,9 @@ long target_mmap(unsigned long start, unsigned long len, int prot,
|
|||||||
int flags, int fd, unsigned long offset)
|
int flags, int fd, unsigned long offset)
|
||||||
{
|
{
|
||||||
unsigned long ret, end, host_start, host_end, retaddr, host_offset, host_len;
|
unsigned long ret, end, host_start, host_end, retaddr, host_offset, host_len;
|
||||||
|
#if defined(__alpha__) || defined(__sparc__) || defined(__x86_64__)
|
||||||
|
static unsigned long last_start = 0x40000000;
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef DEBUG_MMAP
|
#ifdef DEBUG_MMAP
|
||||||
{
|
{
|
||||||
@@ -185,18 +188,20 @@ long target_mmap(unsigned long start, unsigned long len, int prot,
|
|||||||
len = TARGET_PAGE_ALIGN(len);
|
len = TARGET_PAGE_ALIGN(len);
|
||||||
if (len == 0)
|
if (len == 0)
|
||||||
return start;
|
return start;
|
||||||
host_start = start & host_page_mask;
|
host_start = start & qemu_host_page_mask;
|
||||||
|
|
||||||
if (!(flags & MAP_FIXED)) {
|
if (!(flags & MAP_FIXED)) {
|
||||||
#if defined(__alpha__) || defined(__sparc__)
|
#if defined(__alpha__) || defined(__sparc__) || defined(__x86_64__)
|
||||||
/* tell the kenel to search at the same place as i386 */
|
/* tell the kenel to search at the same place as i386 */
|
||||||
if (host_start == 0)
|
if (host_start == 0) {
|
||||||
host_start = 0x40000000;
|
host_start = last_start;
|
||||||
|
last_start += HOST_PAGE_ALIGN(len);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
if (host_page_size != real_host_page_size) {
|
if (qemu_host_page_size != qemu_real_host_page_size) {
|
||||||
/* NOTE: this code is only for debugging with '-p' option */
|
/* NOTE: this code is only for debugging with '-p' option */
|
||||||
/* reserve a memory area */
|
/* reserve a memory area */
|
||||||
host_len = HOST_PAGE_ALIGN(len) + host_page_size - TARGET_PAGE_SIZE;
|
host_len = HOST_PAGE_ALIGN(len) + qemu_host_page_size - TARGET_PAGE_SIZE;
|
||||||
host_start = (long)mmap((void *)host_start, host_len, PROT_NONE,
|
host_start = (long)mmap((void *)host_start, host_len, PROT_NONE,
|
||||||
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||||
if (host_start == -1)
|
if (host_start == -1)
|
||||||
@@ -212,7 +217,7 @@ long target_mmap(unsigned long start, unsigned long len, int prot,
|
|||||||
flags |= MAP_FIXED;
|
flags |= MAP_FIXED;
|
||||||
} else {
|
} else {
|
||||||
/* if not fixed, no need to do anything */
|
/* if not fixed, no need to do anything */
|
||||||
host_offset = offset & host_page_mask;
|
host_offset = offset & qemu_host_page_mask;
|
||||||
host_len = len + offset - host_offset;
|
host_len = len + offset - host_offset;
|
||||||
start = (long)mmap((void *)host_start, host_len,
|
start = (long)mmap((void *)host_start, host_len,
|
||||||
prot, flags, fd, host_offset);
|
prot, flags, fd, host_offset);
|
||||||
@@ -233,7 +238,7 @@ long target_mmap(unsigned long start, unsigned long len, int prot,
|
|||||||
/* worst case: we cannot map the file because the offset is not
|
/* worst case: we cannot map the file because the offset is not
|
||||||
aligned, so we read it */
|
aligned, so we read it */
|
||||||
if (!(flags & MAP_ANONYMOUS) &&
|
if (!(flags & MAP_ANONYMOUS) &&
|
||||||
(offset & ~host_page_mask) != (start & ~host_page_mask)) {
|
(offset & ~qemu_host_page_mask) != (start & ~qemu_host_page_mask)) {
|
||||||
/* msync() won't work here, so we return an error if write is
|
/* msync() won't work here, so we return an error if write is
|
||||||
possible while it is a shared mapping */
|
possible while it is a shared mapping */
|
||||||
if ((flags & MAP_TYPE) == MAP_SHARED &&
|
if ((flags & MAP_TYPE) == MAP_SHARED &&
|
||||||
@@ -255,7 +260,7 @@ long target_mmap(unsigned long start, unsigned long len, int prot,
|
|||||||
|
|
||||||
/* handle the start of the mapping */
|
/* handle the start of the mapping */
|
||||||
if (start > host_start) {
|
if (start > host_start) {
|
||||||
if (host_end == host_start + host_page_size) {
|
if (host_end == host_start + qemu_host_page_size) {
|
||||||
/* one single host page */
|
/* one single host page */
|
||||||
ret = mmap_frag(host_start, start, end,
|
ret = mmap_frag(host_start, start, end,
|
||||||
prot, flags, fd, offset);
|
prot, flags, fd, offset);
|
||||||
@@ -263,21 +268,21 @@ long target_mmap(unsigned long start, unsigned long len, int prot,
|
|||||||
return ret;
|
return ret;
|
||||||
goto the_end1;
|
goto the_end1;
|
||||||
}
|
}
|
||||||
ret = mmap_frag(host_start, start, host_start + host_page_size,
|
ret = mmap_frag(host_start, start, host_start + qemu_host_page_size,
|
||||||
prot, flags, fd, offset);
|
prot, flags, fd, offset);
|
||||||
if (ret == -1)
|
if (ret == -1)
|
||||||
return ret;
|
return ret;
|
||||||
host_start += host_page_size;
|
host_start += qemu_host_page_size;
|
||||||
}
|
}
|
||||||
/* handle the end of the mapping */
|
/* handle the end of the mapping */
|
||||||
if (end < host_end) {
|
if (end < host_end) {
|
||||||
ret = mmap_frag(host_end - host_page_size,
|
ret = mmap_frag(host_end - qemu_host_page_size,
|
||||||
host_end - host_page_size, host_end,
|
host_end - qemu_host_page_size, host_end,
|
||||||
prot, flags, fd,
|
prot, flags, fd,
|
||||||
offset + host_end - host_page_size - start);
|
offset + host_end - qemu_host_page_size - start);
|
||||||
if (ret == -1)
|
if (ret == -1)
|
||||||
return ret;
|
return ret;
|
||||||
host_end -= host_page_size;
|
host_end -= qemu_host_page_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* map the middle (easier) */
|
/* map the middle (easier) */
|
||||||
@@ -317,7 +322,7 @@ int target_munmap(unsigned long start, unsigned long len)
|
|||||||
if (len == 0)
|
if (len == 0)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
end = start + len;
|
end = start + len;
|
||||||
host_start = start & host_page_mask;
|
host_start = start & qemu_host_page_mask;
|
||||||
host_end = HOST_PAGE_ALIGN(end);
|
host_end = HOST_PAGE_ALIGN(end);
|
||||||
|
|
||||||
if (start > host_start) {
|
if (start > host_start) {
|
||||||
@@ -326,14 +331,14 @@ int target_munmap(unsigned long start, unsigned long len)
|
|||||||
for(addr = host_start; addr < start; addr += TARGET_PAGE_SIZE) {
|
for(addr = host_start; addr < start; addr += TARGET_PAGE_SIZE) {
|
||||||
prot |= page_get_flags(addr);
|
prot |= page_get_flags(addr);
|
||||||
}
|
}
|
||||||
if (host_end == host_start + host_page_size) {
|
if (host_end == host_start + qemu_host_page_size) {
|
||||||
for(addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) {
|
for(addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) {
|
||||||
prot |= page_get_flags(addr);
|
prot |= page_get_flags(addr);
|
||||||
}
|
}
|
||||||
end = host_end;
|
end = host_end;
|
||||||
}
|
}
|
||||||
if (prot != 0)
|
if (prot != 0)
|
||||||
host_start += host_page_size;
|
host_start += qemu_host_page_size;
|
||||||
}
|
}
|
||||||
if (end < host_end) {
|
if (end < host_end) {
|
||||||
prot = 0;
|
prot = 0;
|
||||||
@@ -341,7 +346,7 @@ int target_munmap(unsigned long start, unsigned long len)
|
|||||||
prot |= page_get_flags(addr);
|
prot |= page_get_flags(addr);
|
||||||
}
|
}
|
||||||
if (prot != 0)
|
if (prot != 0)
|
||||||
host_end -= host_page_size;
|
host_end -= qemu_host_page_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* unmap what we can */
|
/* unmap what we can */
|
||||||
@@ -386,7 +391,7 @@ int target_msync(unsigned long start, unsigned long len, int flags)
|
|||||||
if (end == start)
|
if (end == start)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
start &= host_page_mask;
|
start &= qemu_host_page_mask;
|
||||||
return msync((void *)start, end - start, flags);
|
return msync((void *)start, end - start, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,129 @@
|
|||||||
|
/*
|
||||||
|
* PPC emulation for qemu: syscall definitions.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2003 Jocelyn Mayer
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* XXX: ABSOLUTELY BUGGY:
|
||||||
|
* for now, this is quite just a cut-and-paste from i386 target...
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* default linux values for the selectors */
|
||||||
|
#define __USER_DS (1)
|
||||||
|
|
||||||
|
struct target_pt_regs {
|
||||||
|
unsigned long gpr[32];
|
||||||
|
unsigned long nip;
|
||||||
|
unsigned long msr;
|
||||||
|
unsigned long orig_gpr3; /* Used for restarting system calls */
|
||||||
|
unsigned long ctr;
|
||||||
|
unsigned long link;
|
||||||
|
unsigned long xer;
|
||||||
|
unsigned long ccr;
|
||||||
|
unsigned long mq; /* 601 only (not used at present) */
|
||||||
|
/* Used on APUS to hold IPL value. */
|
||||||
|
unsigned long trap; /* Reason for being here */
|
||||||
|
unsigned long dar; /* Fault registers */
|
||||||
|
unsigned long dsisr;
|
||||||
|
unsigned long result; /* Result of a system call */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* ioctls */
|
||||||
|
struct target_revectored_struct {
|
||||||
|
target_ulong __map[8]; /* 256 bits */
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* flags masks
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* ipcs */
|
||||||
|
|
||||||
|
#define TARGET_SEMOP 1
|
||||||
|
#define TARGET_SEMGET 2
|
||||||
|
#define TARGET_SEMCTL 3
|
||||||
|
#define TARGET_MSGSND 11
|
||||||
|
#define TARGET_MSGRCV 12
|
||||||
|
#define TARGET_MSGGET 13
|
||||||
|
#define TARGET_MSGCTL 14
|
||||||
|
#define TARGET_SHMAT 21
|
||||||
|
#define TARGET_SHMDT 22
|
||||||
|
#define TARGET_SHMGET 23
|
||||||
|
#define TARGET_SHMCTL 24
|
||||||
|
|
||||||
|
struct target_msgbuf {
|
||||||
|
int mtype;
|
||||||
|
char mtext[1];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct target_ipc_kludge {
|
||||||
|
unsigned int msgp; /* Really (struct msgbuf *) */
|
||||||
|
int msgtyp;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct target_ipc_perm {
|
||||||
|
int key;
|
||||||
|
unsigned short uid;
|
||||||
|
unsigned short gid;
|
||||||
|
unsigned short cuid;
|
||||||
|
unsigned short cgid;
|
||||||
|
unsigned short mode;
|
||||||
|
unsigned short seq;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct target_msqid_ds {
|
||||||
|
struct target_ipc_perm msg_perm;
|
||||||
|
unsigned int msg_first; /* really struct target_msg* */
|
||||||
|
unsigned int msg_last; /* really struct target_msg* */
|
||||||
|
unsigned int msg_stime; /* really target_time_t */
|
||||||
|
unsigned int msg_rtime; /* really target_time_t */
|
||||||
|
unsigned int msg_ctime; /* really target_time_t */
|
||||||
|
unsigned int wwait; /* really struct wait_queue* */
|
||||||
|
unsigned int rwait; /* really struct wait_queue* */
|
||||||
|
unsigned short msg_cbytes;
|
||||||
|
unsigned short msg_qnum;
|
||||||
|
unsigned short msg_qbytes;
|
||||||
|
unsigned short msg_lspid;
|
||||||
|
unsigned short msg_lrpid;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct target_shmid_ds {
|
||||||
|
struct target_ipc_perm shm_perm;
|
||||||
|
int shm_segsz;
|
||||||
|
unsigned int shm_atime; /* really target_time_t */
|
||||||
|
unsigned int shm_dtime; /* really target_time_t */
|
||||||
|
unsigned int shm_ctime; /* really target_time_t */
|
||||||
|
unsigned short shm_cpid;
|
||||||
|
unsigned short shm_lpid;
|
||||||
|
short shm_nattch;
|
||||||
|
unsigned short shm_npages;
|
||||||
|
unsigned long *shm_pages;
|
||||||
|
void *attaches; /* really struct shm_desc * */
|
||||||
|
};
|
||||||
|
|
||||||
|
#define TARGET_IPC_RMID 0
|
||||||
|
#define TARGET_IPC_SET 1
|
||||||
|
#define TARGET_IPC_STAT 2
|
||||||
|
|
||||||
|
union target_semun {
|
||||||
|
int val;
|
||||||
|
unsigned int buf; /* really struct semid_ds * */
|
||||||
|
unsigned int array; /* really unsigned short * */
|
||||||
|
unsigned int __buf; /* really struct seminfo * */
|
||||||
|
unsigned int __pad; /* really void* */
|
||||||
|
};
|
||||||
|
|
||||||
@@ -0,0 +1,258 @@
|
|||||||
|
/*
|
||||||
|
* This file contains the system call numbers.
|
||||||
|
*/
|
||||||
|
#define TARGET_NR_restart_syscall 0
|
||||||
|
#define TARGET_NR_exit 1
|
||||||
|
#define TARGET_NR_fork 2
|
||||||
|
#define TARGET_NR_read 3
|
||||||
|
#define TARGET_NR_write 4
|
||||||
|
#define TARGET_NR_open 5
|
||||||
|
#define TARGET_NR_close 6
|
||||||
|
#define TARGET_NR_waitpid 7
|
||||||
|
#define TARGET_NR_creat 8
|
||||||
|
#define TARGET_NR_link 9
|
||||||
|
#define TARGET_NR_unlink 10
|
||||||
|
#define TARGET_NR_execve 11
|
||||||
|
#define TARGET_NR_chdir 12
|
||||||
|
#define TARGET_NR_time 13
|
||||||
|
#define TARGET_NR_mknod 14
|
||||||
|
#define TARGET_NR_chmod 15
|
||||||
|
#define TARGET_NR_lchown32 16
|
||||||
|
#define TARGET_NR_break 17
|
||||||
|
#define TARGET_NR_oldstat 18
|
||||||
|
#define TARGET_NR_lseek 19
|
||||||
|
#define TARGET_NR_getpid 20
|
||||||
|
#define TARGET_NR_mount 21
|
||||||
|
#define TARGET_NR_umount 22
|
||||||
|
#define TARGET_NR_setuid32 23
|
||||||
|
#define TARGET_NR_getuid32 24
|
||||||
|
#define TARGET_NR_stime 25
|
||||||
|
#define TARGET_NR_ptrace 26
|
||||||
|
#define TARGET_NR_alarm 27
|
||||||
|
#define TARGET_NR_oldfstat 28
|
||||||
|
#define TARGET_NR_pause 29
|
||||||
|
#define TARGET_NR_utime 30
|
||||||
|
#define TARGET_NR_stty 31
|
||||||
|
#define TARGET_NR_gtty 32
|
||||||
|
#define TARGET_NR_access 33
|
||||||
|
#define TARGET_NR_nice 34
|
||||||
|
#define TARGET_NR_ftime 35
|
||||||
|
#define TARGET_NR_sync 36
|
||||||
|
#define TARGET_NR_kill 37
|
||||||
|
#define TARGET_NR_rename 38
|
||||||
|
#define TARGET_NR_mkdir 39
|
||||||
|
#define TARGET_NR_rmdir 40
|
||||||
|
#define TARGET_NR_dup 41
|
||||||
|
#define TARGET_NR_pipe 42
|
||||||
|
#define TARGET_NR_times 43
|
||||||
|
#define TARGET_NR_prof 44
|
||||||
|
#define TARGET_NR_brk 45
|
||||||
|
#define TARGET_NR_setgid32 46
|
||||||
|
#define TARGET_NR_getgid32 47
|
||||||
|
#define TARGET_NR_signal 48
|
||||||
|
#define TARGET_NR_geteuid32 49
|
||||||
|
#define TARGET_NR_getegid32 50
|
||||||
|
#define TARGET_NR_acct 51
|
||||||
|
#define TARGET_NR_umount2 52
|
||||||
|
#define TARGET_NR_lock 53
|
||||||
|
#define TARGET_NR_ioctl 54
|
||||||
|
#define TARGET_NR_fcntl 55
|
||||||
|
#define TARGET_NR_mpx 56
|
||||||
|
#define TARGET_NR_setpgid 57
|
||||||
|
#define TARGET_NR_ulimit 58
|
||||||
|
#define TARGET_NR_oldolduname 59
|
||||||
|
#define TARGET_NR_umask 60
|
||||||
|
#define TARGET_NR_chroot 61
|
||||||
|
#define TARGET_NR_ustat 62
|
||||||
|
#define TARGET_NR_dup2 63
|
||||||
|
#define TARGET_NR_getppid 64
|
||||||
|
#define TARGET_NR_getpgrp 65
|
||||||
|
#define TARGET_NR_setsid 66
|
||||||
|
#define TARGET_NR_sigaction 67
|
||||||
|
#define TARGET_NR_sgetmask 68
|
||||||
|
#define TARGET_NR_ssetmask 69
|
||||||
|
#define TARGET_NR_setreuid32 70
|
||||||
|
#define TARGET_NR_setregid32 71
|
||||||
|
#define TARGET_NR_sigsuspend 72
|
||||||
|
#define TARGET_NR_sigpending 73
|
||||||
|
#define TARGET_NR_sethostname 74
|
||||||
|
#define TARGET_NR_setrlimit 75
|
||||||
|
#define TARGET_NR_getrlimit 76
|
||||||
|
#define TARGET_NR_getrusage 77
|
||||||
|
#define TARGET_NR_gettimeofday 78
|
||||||
|
#define TARGET_NR_settimeofday 79
|
||||||
|
#define TARGET_NR_getgroups32 80
|
||||||
|
#define TARGET_NR_setgroups32 81
|
||||||
|
#define TARGET_NR_select 82
|
||||||
|
#define TARGET_NR_symlink 83
|
||||||
|
#define TARGET_NR_oldlstat 84
|
||||||
|
#define TARGET_NR_readlink 85
|
||||||
|
#define TARGET_NR_uselib 86
|
||||||
|
#define TARGET_NR_swapon 87
|
||||||
|
#define TARGET_NR_reboot 88
|
||||||
|
#define TARGET_NR_readdir 89
|
||||||
|
#define TARGET_NR_mmap 90
|
||||||
|
#define TARGET_NR_munmap 91
|
||||||
|
#define TARGET_NR_truncate 92
|
||||||
|
#define TARGET_NR_ftruncate 93
|
||||||
|
#define TARGET_NR_fchmod 94
|
||||||
|
#define TARGET_NR_fchown32 95
|
||||||
|
#define TARGET_NR_getpriority 96
|
||||||
|
#define TARGET_NR_setpriority 97
|
||||||
|
#define TARGET_NR_profil 98
|
||||||
|
#define TARGET_NR_statfs 99
|
||||||
|
#define TARGET_NR_fstatfs 100
|
||||||
|
#define TARGET_NR_ioperm 101
|
||||||
|
#define TARGET_NR_socketcall 102
|
||||||
|
#define TARGET_NR_syslog 103
|
||||||
|
#define TARGET_NR_setitimer 104
|
||||||
|
#define TARGET_NR_getitimer 105
|
||||||
|
#define TARGET_NR_stat 106
|
||||||
|
#define TARGET_NR_lstat 107
|
||||||
|
#define TARGET_NR_fstat 108
|
||||||
|
#define TARGET_NR_olduname 109
|
||||||
|
#define TARGET_NR_iopl 110
|
||||||
|
#define TARGET_NR_vhangup 111
|
||||||
|
#define TARGET_NR_idle 112
|
||||||
|
#define TARGET_NR_vm86 113
|
||||||
|
#define TARGET_NR_wait4 114
|
||||||
|
#define TARGET_NR_swapoff 115
|
||||||
|
#define TARGET_NR_sysinfo 116
|
||||||
|
#define TARGET_NR_ipc 117
|
||||||
|
#define TARGET_NR_fsync 118
|
||||||
|
#define TARGET_NR_sigreturn 119
|
||||||
|
#define TARGET_NR_clone 120
|
||||||
|
#define TARGET_NR_setdomainname 121
|
||||||
|
#define TARGET_NR_uname 122
|
||||||
|
#define TARGET_NR_modify_ldt 123
|
||||||
|
#define TARGET_NR_adjtimex 124
|
||||||
|
#define TARGET_NR_mprotect 125
|
||||||
|
#define TARGET_NR_sigprocmask 126
|
||||||
|
#define TARGET_NR_create_module 127
|
||||||
|
#define TARGET_NR_init_module 128
|
||||||
|
#define TARGET_NR_delete_module 129
|
||||||
|
#define TARGET_NR_get_kernel_syms 130
|
||||||
|
#define TARGET_NR_quotactl 131
|
||||||
|
#define TARGET_NR_getpgid 132
|
||||||
|
#define TARGET_NR_fchdir 133
|
||||||
|
#define TARGET_NR_bdflush 134
|
||||||
|
#define TARGET_NR_sysfs 135
|
||||||
|
#define TARGET_NR_personality 136
|
||||||
|
#define TARGET_NR_afs_syscall 137 /* Syscall for Andrew File System */
|
||||||
|
#define TARGET_NR_setfsuid32 138
|
||||||
|
#define TARGET_NR_setfsgid32 139
|
||||||
|
#define TARGET_NR__llseek 140
|
||||||
|
#define TARGET_NR_getdents 141
|
||||||
|
#define TARGET_NR__newselect 142
|
||||||
|
#define TARGET_NR_flock 143
|
||||||
|
#define TARGET_NR_msync 144
|
||||||
|
#define TARGET_NR_readv 145
|
||||||
|
#define TARGET_NR_writev 146
|
||||||
|
#define TARGET_NR_getsid 147
|
||||||
|
#define TARGET_NR_fdatasync 148
|
||||||
|
#define TARGET_NR__sysctl 149
|
||||||
|
#define TARGET_NR_mlock 150
|
||||||
|
#define TARGET_NR_munlock 151
|
||||||
|
#define TARGET_NR_mlockall 152
|
||||||
|
#define TARGET_NR_munlockall 153
|
||||||
|
#define TARGET_NR_sched_setparam 154
|
||||||
|
#define TARGET_NR_sched_getparam 155
|
||||||
|
#define TARGET_NR_sched_setscheduler 156
|
||||||
|
#define TARGET_NR_sched_getscheduler 157
|
||||||
|
#define TARGET_NR_sched_yield 158
|
||||||
|
#define TARGET_NR_sched_get_priority_max 159
|
||||||
|
#define TARGET_NR_sched_get_priority_min 160
|
||||||
|
#define TARGET_NR_sched_rr_get_interval 161
|
||||||
|
#define TARGET_NR_nanosleep 162
|
||||||
|
#define TARGET_NR_mremap 163
|
||||||
|
#define TARGET_NR_setresuid32 164
|
||||||
|
#define TARGET_NR_getresuid32 165
|
||||||
|
#define TARGET_NR_query_module 166
|
||||||
|
#define TARGET_NR_poll 167
|
||||||
|
#define TARGET_NR_nfsservctl 168
|
||||||
|
#define TARGET_NR_setresgid32 169
|
||||||
|
#define TARGET_NR_getresgid32 170
|
||||||
|
#define TARGET_NR_prctl 171
|
||||||
|
#define TARGET_NR_rt_sigreturn 172
|
||||||
|
#define TARGET_NR_rt_sigaction 173
|
||||||
|
#define TARGET_NR_rt_sigprocmask 174
|
||||||
|
#define TARGET_NR_rt_sigpending 175
|
||||||
|
#define TARGET_NR_rt_sigtimedwait 176
|
||||||
|
#define TARGET_NR_rt_sigqueueinfo 177
|
||||||
|
#define TARGET_NR_rt_sigsuspend 178
|
||||||
|
#define TARGET_NR_pread64 179
|
||||||
|
#define TARGET_NR_pwrite64 180
|
||||||
|
#define TARGET_NR_chown32 181
|
||||||
|
#define TARGET_NR_getcwd 182
|
||||||
|
#define TARGET_NR_capget 183
|
||||||
|
#define TARGET_NR_capset 184
|
||||||
|
#define TARGET_NR_sigaltstack 185
|
||||||
|
#define TARGET_NR_sendfile 186
|
||||||
|
#define TARGET_NR_getpmsg 187 /* some people actually want streams */
|
||||||
|
#define TARGET_NR_putpmsg 188 /* some people actually want streams */
|
||||||
|
#define TARGET_NR_vfork 189
|
||||||
|
#define TARGET_NR_ugetrlimit 190 /* SuS compliant getrlimit */
|
||||||
|
#define TARGET_NR_readahead 191
|
||||||
|
#define TARGET_NR_mmap2 192
|
||||||
|
#define TARGET_NR_truncate64 193
|
||||||
|
#define TARGET_NR_ftruncate64 194
|
||||||
|
#define TARGET_NR_stat64 195
|
||||||
|
#define TARGET_NR_lstat64 196
|
||||||
|
#define TARGET_NR_fstat64 197
|
||||||
|
#define TARGET_NR_pciconfig_read 198
|
||||||
|
#define TARGET_NR_pciconfig_write 199
|
||||||
|
#define TARGET_NR_pciconfig_iobase 200
|
||||||
|
#define TARGET_NR_multiplexer 201
|
||||||
|
#define TARGET_NR_getdents64 202
|
||||||
|
#define TARGET_NR_pivot_root 203
|
||||||
|
#define TARGET_NR_fcntl64 204
|
||||||
|
#define TARGET_NR_madvise 205
|
||||||
|
#define TARGET_NR_mincore 206
|
||||||
|
#define TARGET_NR_gettid 207
|
||||||
|
#define TARGET_NR_tkill 208
|
||||||
|
#define TARGET_NR_setxattr 209
|
||||||
|
#define TARGET_NR_lsetxattr 210
|
||||||
|
#define TARGET_NR_fsetxattr 211
|
||||||
|
#define TARGET_NR_getxattr 212
|
||||||
|
#define TARGET_NR_lgetxattr 213
|
||||||
|
#define TARGET_NR_fgetxattr 214
|
||||||
|
#define TARGET_NR_listxattr 215
|
||||||
|
#define TARGET_NR_llistxattr 216
|
||||||
|
#define TARGET_NR_flistxattr 217
|
||||||
|
#define TARGET_NR_removexattr 218
|
||||||
|
#define TARGET_NR_lremovexattr 219
|
||||||
|
#define TARGET_NR_fremovexattr 220
|
||||||
|
#define TARGET_NR_futex 221
|
||||||
|
#define TARGET_NR_sched_setaffinity 222
|
||||||
|
#define TARGET_NR_sched_getaffinity 223
|
||||||
|
/* 224 currently unused */
|
||||||
|
#define TARGET_NR_tuxcall 225
|
||||||
|
#define TARGET_NR_sendfile64 226
|
||||||
|
#define TARGET_NR_io_setup 227
|
||||||
|
#define TARGET_NR_io_destroy 228
|
||||||
|
#define TARGET_NR_io_getevents 229
|
||||||
|
#define TARGET_NR_io_submit 230
|
||||||
|
#define TARGET_NR_io_cancel 231
|
||||||
|
#define TARGET_NR_set_tid_address 232
|
||||||
|
#define TARGET_NR_fadvise64 233
|
||||||
|
#define TARGET_NR_exit_group 234
|
||||||
|
#define TARGET_NR_lookup_dcookie 235
|
||||||
|
#define TARGET_NR_epoll_create 236
|
||||||
|
#define TARGET_NR_epoll_ctl 237
|
||||||
|
#define TARGET_NR_epoll_wait 238
|
||||||
|
#define TARGET_NR_remap_file_pages 239
|
||||||
|
#define TARGET_NR_timer_create 240
|
||||||
|
#define TARGET_NR_timer_settime 241
|
||||||
|
#define TARGET_NR_timer_gettime 242
|
||||||
|
#define TARGET_NR_timer_getoverrun 243
|
||||||
|
#define TARGET_NR_timer_delete 244
|
||||||
|
#define TARGET_NR_clock_settime 245
|
||||||
|
#define TARGET_NR_clock_gettime 246
|
||||||
|
#define TARGET_NR_clock_getres 247
|
||||||
|
#define TARGET_NR_clock_nanosleep 248
|
||||||
|
#define TARGET_NR_swapcontext 249
|
||||||
|
#define TARGET_NR_tgkill 250
|
||||||
|
#define TARGET_NR_utimes 251
|
||||||
|
#define TARGET_NR_statfs64 252
|
||||||
|
#define TARGET_NR_fstatfs64 253
|
||||||
|
#define TARGET_NR_fadvise64_64 254
|
||||||
@@ -0,0 +1,235 @@
|
|||||||
|
/* from asm/termbits.h */
|
||||||
|
|
||||||
|
#define TARGET_NCCS 19
|
||||||
|
|
||||||
|
struct target_termios {
|
||||||
|
unsigned int c_iflag; /* input mode flags */
|
||||||
|
unsigned int c_oflag; /* output mode flags */
|
||||||
|
unsigned int c_cflag; /* control mode flags */
|
||||||
|
unsigned int c_lflag; /* local mode flags */
|
||||||
|
unsigned char c_line; /* line discipline */
|
||||||
|
unsigned char c_cc[TARGET_NCCS]; /* control characters */
|
||||||
|
unsigned int c_ispeed; /* input speed */
|
||||||
|
unsigned int c_ospeed; /* output speed */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* c_cc character offsets */
|
||||||
|
#define TARGET_VINTR 0
|
||||||
|
#define TARGET_VQUIT 1
|
||||||
|
#define TARGET_VERASE 2
|
||||||
|
#define TARGET_VKILL 3
|
||||||
|
#define TARGET_VEOF 4
|
||||||
|
#define TARGET_VMIN 5
|
||||||
|
#define TARGET_VEOL 6
|
||||||
|
#define TARGET_VTIME 7
|
||||||
|
#define TARGET_VEOL2 8
|
||||||
|
#define TARGET_VSWTC 9
|
||||||
|
|
||||||
|
#define TARGET_VWERASE 10
|
||||||
|
#define TARGET_VREPRINT 11
|
||||||
|
#define TARGET_VSUSP 12
|
||||||
|
#define TARGET_VSTART 13
|
||||||
|
#define TARGET_VSTOP 14
|
||||||
|
#define TARGET_VLNEXT 15
|
||||||
|
#define TARGET_VDISCARD 16
|
||||||
|
|
||||||
|
#define TARGET_IGNBRK 0000001
|
||||||
|
#define TARGET_BRKINT 0000002
|
||||||
|
#define TARGET_IGNPAR 0000004
|
||||||
|
#define TARGET_PARMRK 0000010
|
||||||
|
#define TARGET_INPCK 0000020
|
||||||
|
#define TARGET_ISTRIP 0000040
|
||||||
|
#define TARGET_INLCR 0000100
|
||||||
|
#define TARGET_IGNCR 0000200
|
||||||
|
#define TARGET_ICRNL 0000400
|
||||||
|
#define TARGET_IXON 0001000
|
||||||
|
#define TARGET_IXOFF 0002000
|
||||||
|
#define TARGET_IXANY 0004000
|
||||||
|
#define TARGET_IUCLC 0010000
|
||||||
|
#define TARGET_IMAXBEL 0020000
|
||||||
|
|
||||||
|
/* c_oflag bits */
|
||||||
|
#define TARGET_OPOST 0000001
|
||||||
|
#define TARGET_ONLCR 0000002
|
||||||
|
#define TARGET_OLCUC 0000004
|
||||||
|
|
||||||
|
#define TARGET_OCRNL 0000010
|
||||||
|
#define TARGET_ONOCR 0000020
|
||||||
|
#define TARGET_ONLRET 0000040
|
||||||
|
|
||||||
|
#define TARGET_OFILL 00000100
|
||||||
|
#define TARGET_OFDEL 00000200
|
||||||
|
#define TARGET_NLDLY 00001400
|
||||||
|
#define TARGET_NL0 00000000
|
||||||
|
#define TARGET_NL1 00000400
|
||||||
|
#define TARGET_NL2 00001000
|
||||||
|
#define TARGET_NL3 00001400
|
||||||
|
#define TARGET_TABDLY 00006000
|
||||||
|
#define TARGET_TAB0 00000000
|
||||||
|
#define TARGET_TAB1 00002000
|
||||||
|
#define TARGET_TAB2 00004000
|
||||||
|
#define TARGET_TAB3 00006000
|
||||||
|
#define TARGET_CRDLY 00030000
|
||||||
|
#define TARGET_CR0 00000000
|
||||||
|
#define TARGET_CR1 00010000
|
||||||
|
#define TARGET_CR2 00020000
|
||||||
|
#define TARGET_CR3 00030000
|
||||||
|
#define TARGET_FFDLY 00040000
|
||||||
|
#define TARGET_FF0 00000000
|
||||||
|
#define TARGET_FF1 00040000
|
||||||
|
#define TARGET_BSDLY 00100000
|
||||||
|
#define TARGET_BS0 00000000
|
||||||
|
#define TARGET_BS1 00100000
|
||||||
|
#define TARGET_VTDLY 00200000
|
||||||
|
#define TARGET_VT0 00000000
|
||||||
|
#define TARGET_VT1 00200000
|
||||||
|
#define TARGET_XTABS 01000000 /* Hmm.. Linux/i386 considers this part of TABDLY.. */
|
||||||
|
|
||||||
|
/* c_cflag bit meaning */
|
||||||
|
#define TARGET_CBAUD 0000377
|
||||||
|
#define TARGET_B0 0000000 /* hang up */
|
||||||
|
#define TARGET_B50 0000001
|
||||||
|
#define TARGET_B75 0000002
|
||||||
|
#define TARGET_B110 0000003
|
||||||
|
#define TARGET_B134 0000004
|
||||||
|
#define TARGET_B150 0000005
|
||||||
|
#define TARGET_B200 0000006
|
||||||
|
#define TARGET_B300 0000007
|
||||||
|
#define TARGET_B600 0000010
|
||||||
|
#define TARGET_B1200 0000011
|
||||||
|
#define TARGET_B1800 0000012
|
||||||
|
#define TARGET_B2400 0000013
|
||||||
|
#define TARGET_B4800 0000014
|
||||||
|
#define TARGET_B9600 0000015
|
||||||
|
#define TARGET_B19200 0000016
|
||||||
|
#define TARGET_B38400 0000017
|
||||||
|
#define TARGET_EXTA B19200
|
||||||
|
#define TARGET_EXTB B38400
|
||||||
|
#define TARGET_CBAUDEX 0000000
|
||||||
|
#define TARGET_B57600 00020
|
||||||
|
#define TARGET_B115200 00021
|
||||||
|
#define TARGET_B230400 00022
|
||||||
|
#define TARGET_B460800 00023
|
||||||
|
#define TARGET_B500000 00024
|
||||||
|
#define TARGET_B576000 00025
|
||||||
|
#define TARGET_B921600 00026
|
||||||
|
#define TARGET_B1000000 00027
|
||||||
|
#define TARGET_B1152000 00030
|
||||||
|
#define TARGET_B1500000 00031
|
||||||
|
#define TARGET_B2000000 00032
|
||||||
|
#define TARGET_B2500000 00033
|
||||||
|
#define TARGET_B3000000 00034
|
||||||
|
#define TARGET_B3500000 00035
|
||||||
|
#define TARGET_B4000000 00036
|
||||||
|
|
||||||
|
#define TARGET_CSIZE 00001400
|
||||||
|
#define TARGET_CS5 00000000
|
||||||
|
#define TARGET_CS6 00000400
|
||||||
|
#define TARGET_CS7 00001000
|
||||||
|
#define TARGET_CS8 00001400
|
||||||
|
|
||||||
|
#define TARGET_CSTOPB 00002000
|
||||||
|
#define TARGET_CREAD 00004000
|
||||||
|
#define TARGET_PARENB 00010000
|
||||||
|
#define TARGET_PARODD 00020000
|
||||||
|
#define TARGET_HUPCL 00040000
|
||||||
|
|
||||||
|
#define TARGET_CLOCAL 00100000
|
||||||
|
#define TARGET_CRTSCTS 020000000000 /* flow control */
|
||||||
|
|
||||||
|
/* c_lflag bits */
|
||||||
|
#define TARGET_ISIG 0x00000080
|
||||||
|
#define TARGET_ICANON 0x00000100
|
||||||
|
#define TARGET_XCASE 0x00004000
|
||||||
|
#define TARGET_ECHO 0x00000008
|
||||||
|
#define TARGET_ECHOE 0x00000002
|
||||||
|
#define TARGET_ECHOK 0x00000004
|
||||||
|
#define TARGET_ECHONL 0x00000010
|
||||||
|
#define TARGET_NOFLSH 0x80000000
|
||||||
|
#define TARGET_TOSTOP 0x00400000
|
||||||
|
#define TARGET_ECHOCTL 0x00000040
|
||||||
|
#define TARGET_ECHOPRT 0x00000020
|
||||||
|
#define TARGET_ECHOKE 0x00000001
|
||||||
|
#define TARGET_FLUSHO 0x00800000
|
||||||
|
#define TARGET_PENDIN 0x20000000
|
||||||
|
#define TARGET_IEXTEN 0x00000400
|
||||||
|
|
||||||
|
/* ioctls */
|
||||||
|
|
||||||
|
#define TARGET_FIOCLEX TARGET_IO('f', 1)
|
||||||
|
#define TARGET_FIONCLEX TARGET_IO('f', 2)
|
||||||
|
#define TARGET_FIOASYNC TARGET_IOW('f', 125, int)
|
||||||
|
#define TARGET_FIONBIO TARGET_IOW('f', 126, int)
|
||||||
|
#define TARGET_FIONREAD TARGET_IOR('f', 127, int)
|
||||||
|
#define TARGET_TIOCINQ TARGET_FIONREAD
|
||||||
|
//#define TARGET_FIOQSIZE TARGET_IOR('f', 128, loff_t)
|
||||||
|
|
||||||
|
#define TARGET_TCGETS TARGET_IOR('t', 19, struct target_termios)
|
||||||
|
#define TARGET_TCSETS TARGET_IOW('t', 20, struct target_termios)
|
||||||
|
#define TARGET_TCSETSW TARGET_IOW('t', 21, struct target_termios)
|
||||||
|
#define TARGET_TCSETSF TARGET_IOW('t', 22, struct target_termios)
|
||||||
|
|
||||||
|
#define TARGET_TCGETA TARGET_IOR('t', 23, struct target_termio)
|
||||||
|
#define TARGET_TCSETA TARGET_IOW('t', 24, struct target_termio)
|
||||||
|
#define TARGET_TCSETAW TARGET_IOW('t', 25, struct target_termio)
|
||||||
|
#define TARGET_TCSETAF TARGET_IOW('t', 28, struct target_termio)
|
||||||
|
|
||||||
|
#define TARGET_TCSBRK TARGET_IO('t', 29)
|
||||||
|
#define TARGET_TCXONC TARGET_IO('t', 30)
|
||||||
|
#define TARGET_TCFLSH TARGET_IO('t', 31)
|
||||||
|
|
||||||
|
#define TARGET_TIOCSWINSZ TARGET_IOW('t', 103, struct target_winsize)
|
||||||
|
#define TARGET_TIOCGWINSZ TARGET_IOR('t', 104, struct target_winsize)
|
||||||
|
#define TARGET_TIOCSTART TARGET_IO('t', 110) /* start output, like ^Q */
|
||||||
|
#define TARGET_TIOCSTOP TARGET_IO('t', 111) /* stop output, like ^S */
|
||||||
|
#define TARGET_TIOCOUTQ TARGET_IOR('t', 115, int) /* output queue size */
|
||||||
|
|
||||||
|
#define TARGET_TIOCGLTC TARGET_IOR('t', 116, struct target_ltchars)
|
||||||
|
#define TARGET_TIOCSLTC TARGET_IOW('t', 117, struct target_ltchars)
|
||||||
|
#define TARGET_TIOCSPGRP TARGET_IOW('t', 118, int)
|
||||||
|
#define TARGET_TIOCGPGRP TARGET_IOR('t', 119, int)
|
||||||
|
|
||||||
|
#define TARGET_TIOCEXCL 0x540C
|
||||||
|
#define TARGET_TIOCNXCL 0x540D
|
||||||
|
#define TARGET_TIOCSCTTY 0x540E
|
||||||
|
|
||||||
|
#define TARGET_TIOCSTI 0x5412
|
||||||
|
#define TARGET_TIOCMGET 0x5415
|
||||||
|
#define TARGET_TIOCMBIS 0x5416
|
||||||
|
#define TARGET_TIOCMBIC 0x5417
|
||||||
|
#define TARGET_TIOCMSET 0x5418
|
||||||
|
|
||||||
|
#define TARGET_TIOCGSOFTCAR 0x5419
|
||||||
|
#define TARGET_TIOCSSOFTCAR 0x541A
|
||||||
|
#define TARGET_TIOCLINUX 0x541C
|
||||||
|
#define TARGET_TIOCCONS 0x541D
|
||||||
|
#define TARGET_TIOCGSERIAL 0x541E
|
||||||
|
#define TARGET_TIOCSSERIAL 0x541F
|
||||||
|
#define TARGET_TIOCPKT 0x5420
|
||||||
|
|
||||||
|
#define TARGET_TIOCNOTTY 0x5422
|
||||||
|
#define TARGET_TIOCSETD 0x5423
|
||||||
|
#define TARGET_TIOCGETD 0x5424
|
||||||
|
#define TARGET_TCSBRKP 0x5425 /* Needed for POSIX tcsendbreak() */
|
||||||
|
#define TARGET_TIOCTTYGSTRUCT 0x5426 /* For debugging only */
|
||||||
|
#define TARGET_TIOCSBRK 0x5427 /* BSD compatibility */
|
||||||
|
#define TARGET_TIOCCBRK 0x5428 /* BSD compatibility */
|
||||||
|
#define TARGET_TIOCGSID 0x5429 /* Return the session ID of FD */
|
||||||
|
#define TARGET_TIOCGPTN TARGET_IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */
|
||||||
|
#define TARGET_TIOCSPTLCK TARGET_IOW('T',0x31, int) /* Lock/unlock Pty */
|
||||||
|
|
||||||
|
#define TARGET_TIOCSERCONFIG 0x5453
|
||||||
|
#define TARGET_TIOCSERGWILD 0x5454
|
||||||
|
#define TARGET_TIOCSERSWILD 0x5455
|
||||||
|
#define TARGET_TIOCGLCKTRMIOS 0x5456
|
||||||
|
#define TARGET_TIOCSLCKTRMIOS 0x5457
|
||||||
|
#define TARGET_TIOCSERGSTRUCT 0x5458 /* For debugging only */
|
||||||
|
#define TARGET_TIOCSERGETLSR 0x5459 /* Get line status register */
|
||||||
|
/* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */
|
||||||
|
# define TARGET_TIOCSER_TEMT 0x01 /* Transmitter physically empty */
|
||||||
|
#define TARGET_TIOCSERGETMULTI 0x545A /* Get multiport config */
|
||||||
|
#define TARGET_TIOCSERSETMULTI 0x545B /* Set multiport config */
|
||||||
|
|
||||||
|
#define TARGET_TIOCMIWAIT 0x545C /* wait for a change on serial input line(s) */
|
||||||
|
#define TARGET_TIOCGICOUNT 0x545D /* read serial port inline interrupt counts */
|
||||||
|
|
||||||
@@ -4,6 +4,7 @@
|
|||||||
#include "thunk.h"
|
#include "thunk.h"
|
||||||
|
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
#include <string.h>
|
||||||
#include "syscall_defs.h"
|
#include "syscall_defs.h"
|
||||||
|
|
||||||
#include "cpu.h"
|
#include "cpu.h"
|
||||||
@@ -48,10 +49,21 @@ struct vm86_saved_state {
|
|||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef TARGET_ARM
|
||||||
|
/* FPU emulator */
|
||||||
|
#include "nwfpe/fpa11.h"
|
||||||
|
#undef put_user
|
||||||
|
#undef get_user
|
||||||
|
#endif
|
||||||
|
|
||||||
/* NOTE: we force a big alignment so that the stack stored after is
|
/* NOTE: we force a big alignment so that the stack stored after is
|
||||||
aligned too */
|
aligned too */
|
||||||
typedef struct TaskState {
|
typedef struct TaskState {
|
||||||
struct TaskState *next;
|
struct TaskState *next;
|
||||||
|
#ifdef TARGET_ARM
|
||||||
|
/* FPA state */
|
||||||
|
FPA11 fpa;
|
||||||
|
#endif
|
||||||
#ifdef TARGET_I386
|
#ifdef TARGET_I386
|
||||||
struct target_vm86plus_struct *target_v86;
|
struct target_vm86plus_struct *target_v86;
|
||||||
struct vm86_saved_state vm86_saved_regs;
|
struct vm86_saved_state vm86_saved_regs;
|
||||||
@@ -109,4 +121,121 @@ long target_mremap(unsigned long old_addr, unsigned long old_size,
|
|||||||
unsigned long new_addr);
|
unsigned long new_addr);
|
||||||
int target_msync(unsigned long start, unsigned long len, int flags);
|
int target_msync(unsigned long start, unsigned long len, int flags);
|
||||||
|
|
||||||
|
/* user access */
|
||||||
|
|
||||||
|
#define VERIFY_READ 0
|
||||||
|
#define VERIFY_WRITE 1
|
||||||
|
|
||||||
|
#define access_ok(type,addr,size) (1)
|
||||||
|
|
||||||
|
#define __put_user(x,ptr)\
|
||||||
|
({\
|
||||||
|
int size = sizeof(*ptr);\
|
||||||
|
switch(size) {\
|
||||||
|
case 1:\
|
||||||
|
stb(ptr, (typeof(*ptr))(x));\
|
||||||
|
break;\
|
||||||
|
case 2:\
|
||||||
|
stw(ptr, (typeof(*ptr))(x));\
|
||||||
|
break;\
|
||||||
|
case 4:\
|
||||||
|
stl(ptr, (typeof(*ptr))(x));\
|
||||||
|
break;\
|
||||||
|
case 8:\
|
||||||
|
stq(ptr, (typeof(*ptr))(x));\
|
||||||
|
break;\
|
||||||
|
default:\
|
||||||
|
abort();\
|
||||||
|
}\
|
||||||
|
0;\
|
||||||
|
})
|
||||||
|
|
||||||
|
#define __get_user(x, ptr) \
|
||||||
|
({\
|
||||||
|
int size = sizeof(*ptr);\
|
||||||
|
switch(size) {\
|
||||||
|
case 1:\
|
||||||
|
x = (typeof(*ptr))ldub((void *)ptr);\
|
||||||
|
break;\
|
||||||
|
case 2:\
|
||||||
|
x = (typeof(*ptr))lduw((void *)ptr);\
|
||||||
|
break;\
|
||||||
|
case 4:\
|
||||||
|
x = (typeof(*ptr))ldl((void *)ptr);\
|
||||||
|
break;\
|
||||||
|
case 8:\
|
||||||
|
x = (typeof(*ptr))ldq((void *)ptr);\
|
||||||
|
break;\
|
||||||
|
default:\
|
||||||
|
abort();\
|
||||||
|
}\
|
||||||
|
0;\
|
||||||
|
})
|
||||||
|
|
||||||
|
static inline unsigned long __copy_to_user(void *dst, const void *src,
|
||||||
|
unsigned long size)
|
||||||
|
{
|
||||||
|
memcpy(dst, src, size);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline unsigned long __copy_from_user(void *dst, const void *src,
|
||||||
|
unsigned long size)
|
||||||
|
{
|
||||||
|
memcpy(dst, src, size);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline unsigned long __clear_user(void *dst, unsigned long size)
|
||||||
|
{
|
||||||
|
memset(dst, 0, size);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define put_user(x,ptr)\
|
||||||
|
({\
|
||||||
|
int __ret;\
|
||||||
|
if (access_ok(VERIFY_WRITE, ptr, sizeof(*ptr)))\
|
||||||
|
__ret = __put_user(x, ptr);\
|
||||||
|
else\
|
||||||
|
__ret = -EFAULT;\
|
||||||
|
__ret;\
|
||||||
|
})
|
||||||
|
|
||||||
|
#define get_user(x,ptr)\
|
||||||
|
({\
|
||||||
|
int __ret;\
|
||||||
|
if (access_ok(VERIFY_READ, ptr, sizeof(*ptr)))\
|
||||||
|
__ret = __get_user(x, ptr);\
|
||||||
|
else\
|
||||||
|
__ret = -EFAULT;\
|
||||||
|
__ret;\
|
||||||
|
})
|
||||||
|
|
||||||
|
static inline unsigned long copy_to_user(void *dst, const void *src,
|
||||||
|
unsigned long size)
|
||||||
|
{
|
||||||
|
if (access_ok(VERIFY_WRITE, dst, size))
|
||||||
|
return __copy_to_user(dst, src, size);
|
||||||
|
else
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline unsigned long copy_from_user(void *dst, const void *src,
|
||||||
|
unsigned long size)
|
||||||
|
{
|
||||||
|
if (access_ok(VERIFY_READ, src, size))
|
||||||
|
return __copy_from_user(dst, src, size);
|
||||||
|
else
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline unsigned long clear_user(void *dst, unsigned long size)
|
||||||
|
{
|
||||||
|
if (access_ok(VERIFY_WRITE, dst, size))
|
||||||
|
return __clear_user(dst, size);
|
||||||
|
else
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
+97
-146
@@ -109,7 +109,8 @@ static inline int target_to_host_signal(int sig)
|
|||||||
return target_to_host_signal_table[sig];
|
return target_to_host_signal_table[sig];
|
||||||
}
|
}
|
||||||
|
|
||||||
void host_to_target_sigset(target_sigset_t *d, const sigset_t *s)
|
static void host_to_target_sigset_internal(target_sigset_t *d,
|
||||||
|
const sigset_t *s)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
unsigned long sigmask;
|
unsigned long sigmask;
|
||||||
@@ -122,25 +123,35 @@ void host_to_target_sigset(target_sigset_t *d, const sigset_t *s)
|
|||||||
target_sigmask |= 1 << (host_to_target_signal(i + 1) - 1);
|
target_sigmask |= 1 << (host_to_target_signal(i + 1) - 1);
|
||||||
}
|
}
|
||||||
#if TARGET_LONG_BITS == 32 && HOST_LONG_BITS == 32
|
#if TARGET_LONG_BITS == 32 && HOST_LONG_BITS == 32
|
||||||
d->sig[0] = tswapl(target_sigmask);
|
d->sig[0] = target_sigmask;
|
||||||
for(i = 1;i < TARGET_NSIG_WORDS; i++) {
|
for(i = 1;i < TARGET_NSIG_WORDS; i++) {
|
||||||
d->sig[i] = tswapl(((unsigned long *)s)[i]);
|
d->sig[i] = ((unsigned long *)s)[i];
|
||||||
}
|
}
|
||||||
#elif TARGET_LONG_BITS == 32 && HOST_LONG_BITS == 64 && TARGET_NSIG_WORDS == 2
|
#elif TARGET_LONG_BITS == 32 && HOST_LONG_BITS == 64 && TARGET_NSIG_WORDS == 2
|
||||||
d->sig[0] = tswapl(target_sigmask);
|
d->sig[0] = target_sigmask;
|
||||||
d->sig[1] = tswapl(sigmask >> 32);
|
d->sig[1] = sigmask >> 32;
|
||||||
#else
|
#else
|
||||||
#error host_to_target_sigset
|
#error host_to_target_sigset
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void target_to_host_sigset(sigset_t *d, const target_sigset_t *s)
|
void host_to_target_sigset(target_sigset_t *d, const sigset_t *s)
|
||||||
|
{
|
||||||
|
target_sigset_t d1;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
host_to_target_sigset_internal(&d1, s);
|
||||||
|
for(i = 0;i < TARGET_NSIG_WORDS; i++)
|
||||||
|
__put_user(d1.sig[i], &d->sig[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void target_to_host_sigset_internal(sigset_t *d, const target_sigset_t *s)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
unsigned long sigmask;
|
unsigned long sigmask;
|
||||||
target_ulong target_sigmask;
|
target_ulong target_sigmask;
|
||||||
|
|
||||||
target_sigmask = tswapl(s->sig[0]);
|
target_sigmask = s->sig[0];
|
||||||
sigmask = 0;
|
sigmask = 0;
|
||||||
for(i = 0; i < 32; i++) {
|
for(i = 0; i < 32; i++) {
|
||||||
if (target_sigmask & (1 << i))
|
if (target_sigmask & (1 << i))
|
||||||
@@ -149,15 +160,25 @@ void target_to_host_sigset(sigset_t *d, const target_sigset_t *s)
|
|||||||
#if TARGET_LONG_BITS == 32 && HOST_LONG_BITS == 32
|
#if TARGET_LONG_BITS == 32 && HOST_LONG_BITS == 32
|
||||||
((unsigned long *)d)[0] = sigmask;
|
((unsigned long *)d)[0] = sigmask;
|
||||||
for(i = 1;i < TARGET_NSIG_WORDS; i++) {
|
for(i = 1;i < TARGET_NSIG_WORDS; i++) {
|
||||||
((unsigned long *)d)[i] = tswapl(s->sig[i]);
|
((unsigned long *)d)[i] = s->sig[i];
|
||||||
}
|
}
|
||||||
#elif TARGET_LONG_BITS == 32 && HOST_LONG_BITS == 64 && TARGET_NSIG_WORDS == 2
|
#elif TARGET_LONG_BITS == 32 && HOST_LONG_BITS == 64 && TARGET_NSIG_WORDS == 2
|
||||||
((unsigned long *)d)[0] = sigmask | ((unsigned long)tswapl(s->sig[1]) << 32);
|
((unsigned long *)d)[0] = sigmask | ((unsigned long)(s->sig[1]) << 32);
|
||||||
#else
|
#else
|
||||||
#error target_to_host_sigset
|
#error target_to_host_sigset
|
||||||
#endif /* TARGET_LONG_BITS */
|
#endif /* TARGET_LONG_BITS */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void target_to_host_sigset(sigset_t *d, const target_sigset_t *s)
|
||||||
|
{
|
||||||
|
target_sigset_t s1;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for(i = 0;i < TARGET_NSIG_WORDS; i++)
|
||||||
|
__get_user(s1.sig[i], &s->sig[i]);
|
||||||
|
target_to_host_sigset_internal(d, &s1);
|
||||||
|
}
|
||||||
|
|
||||||
void host_to_target_old_sigset(target_ulong *old_sigset,
|
void host_to_target_old_sigset(target_ulong *old_sigset,
|
||||||
const sigset_t *sigset)
|
const sigset_t *sigset)
|
||||||
{
|
{
|
||||||
@@ -370,33 +391,6 @@ int queue_signal(int sig, target_siginfo_t *info)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(DEBUG_SIGNAL)
|
|
||||||
#ifdef __i386__
|
|
||||||
static void dump_regs(struct ucontext *uc)
|
|
||||||
{
|
|
||||||
fprintf(stderr,
|
|
||||||
"EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n"
|
|
||||||
"ESI=%08x EDI=%08x EBP=%08x ESP=%08x\n"
|
|
||||||
"EFL=%08x EIP=%08x\n",
|
|
||||||
uc->uc_mcontext.gregs[EAX],
|
|
||||||
uc->uc_mcontext.gregs[EBX],
|
|
||||||
uc->uc_mcontext.gregs[ECX],
|
|
||||||
uc->uc_mcontext.gregs[EDX],
|
|
||||||
uc->uc_mcontext.gregs[ESI],
|
|
||||||
uc->uc_mcontext.gregs[EDI],
|
|
||||||
uc->uc_mcontext.gregs[EBP],
|
|
||||||
uc->uc_mcontext.gregs[ESP],
|
|
||||||
uc->uc_mcontext.gregs[EFL],
|
|
||||||
uc->uc_mcontext.gregs[EIP]);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
static void dump_regs(struct ucontext *uc)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static void host_signal_handler(int host_signum, siginfo_t *info,
|
static void host_signal_handler(int host_signum, siginfo_t *info,
|
||||||
void *puc)
|
void *puc)
|
||||||
{
|
{
|
||||||
@@ -405,7 +399,11 @@ static void host_signal_handler(int host_signum, siginfo_t *info,
|
|||||||
|
|
||||||
/* the CPU emulator uses some host signals to detect exceptions,
|
/* the CPU emulator uses some host signals to detect exceptions,
|
||||||
we we forward to it some signals */
|
we we forward to it some signals */
|
||||||
if (host_signum == SIGSEGV || host_signum == SIGBUS) {
|
if (host_signum == SIGSEGV || host_signum == SIGBUS
|
||||||
|
#if defined(TARGET_I386) && defined(USE_CODE_COPY)
|
||||||
|
|| host_signum == SIGFPE
|
||||||
|
#endif
|
||||||
|
) {
|
||||||
if (cpu_signal_handler(host_signum, info, puc))
|
if (cpu_signal_handler(host_signum, info, puc))
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -416,7 +414,6 @@ static void host_signal_handler(int host_signum, siginfo_t *info,
|
|||||||
return;
|
return;
|
||||||
#if defined(DEBUG_SIGNAL)
|
#if defined(DEBUG_SIGNAL)
|
||||||
fprintf(stderr, "qemu: got signal %d\n", sig);
|
fprintf(stderr, "qemu: got signal %d\n", sig);
|
||||||
dump_regs(puc);
|
|
||||||
#endif
|
#endif
|
||||||
host_to_target_siginfo_noswap(&tinfo, info);
|
host_to_target_siginfo_noswap(&tinfo, info);
|
||||||
if (queue_signal(sig, &tinfo) == 1) {
|
if (queue_signal(sig, &tinfo) == 1) {
|
||||||
@@ -429,11 +426,13 @@ int do_sigaction(int sig, const struct target_sigaction *act,
|
|||||||
struct target_sigaction *oact)
|
struct target_sigaction *oact)
|
||||||
{
|
{
|
||||||
struct emulated_sigaction *k;
|
struct emulated_sigaction *k;
|
||||||
|
struct sigaction act1;
|
||||||
|
int host_sig;
|
||||||
|
|
||||||
if (sig < 1 || sig > TARGET_NSIG)
|
if (sig < 1 || sig > TARGET_NSIG)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
k = &sigact_table[sig - 1];
|
k = &sigact_table[sig - 1];
|
||||||
#if defined(DEBUG_SIGNAL) && 0
|
#if defined(DEBUG_SIGNAL)
|
||||||
fprintf(stderr, "sigaction sig=%d act=0x%08x, oact=0x%08x\n",
|
fprintf(stderr, "sigaction sig=%d act=0x%08x, oact=0x%08x\n",
|
||||||
sig, (int)act, (int)oact);
|
sig, (int)act, (int)oact);
|
||||||
#endif
|
#endif
|
||||||
@@ -448,73 +447,30 @@ int do_sigaction(int sig, const struct target_sigaction *act,
|
|||||||
k->sa.sa_flags = tswapl(act->sa_flags);
|
k->sa.sa_flags = tswapl(act->sa_flags);
|
||||||
k->sa.sa_restorer = tswapl(act->sa_restorer);
|
k->sa.sa_restorer = tswapl(act->sa_restorer);
|
||||||
k->sa.sa_mask = act->sa_mask;
|
k->sa.sa_mask = act->sa_mask;
|
||||||
|
|
||||||
|
/* we update the host linux signal state */
|
||||||
|
host_sig = target_to_host_signal(sig);
|
||||||
|
if (host_sig != SIGSEGV && host_sig != SIGBUS) {
|
||||||
|
sigfillset(&act1.sa_mask);
|
||||||
|
act1.sa_flags = SA_SIGINFO;
|
||||||
|
if (k->sa.sa_flags & TARGET_SA_RESTART)
|
||||||
|
act1.sa_flags |= SA_RESTART;
|
||||||
|
/* NOTE: it is important to update the host kernel signal
|
||||||
|
ignore state to avoid getting unexpected interrupted
|
||||||
|
syscalls */
|
||||||
|
if (k->sa._sa_handler == TARGET_SIG_IGN) {
|
||||||
|
act1.sa_sigaction = (void *)SIG_IGN;
|
||||||
|
} else if (k->sa._sa_handler == TARGET_SIG_DFL) {
|
||||||
|
act1.sa_sigaction = (void *)SIG_DFL;
|
||||||
|
} else {
|
||||||
|
act1.sa_sigaction = host_signal_handler;
|
||||||
|
}
|
||||||
|
sigaction(host_sig, &act1, NULL);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define __put_user(x,ptr)\
|
|
||||||
({\
|
|
||||||
int size = sizeof(*ptr);\
|
|
||||||
switch(size) {\
|
|
||||||
case 1:\
|
|
||||||
stb(ptr, (typeof(*ptr))(x));\
|
|
||||||
break;\
|
|
||||||
case 2:\
|
|
||||||
stw(ptr, (typeof(*ptr))(x));\
|
|
||||||
break;\
|
|
||||||
case 4:\
|
|
||||||
stl(ptr, (typeof(*ptr))(x));\
|
|
||||||
break;\
|
|
||||||
case 8:\
|
|
||||||
stq(ptr, (typeof(*ptr))(x));\
|
|
||||||
break;\
|
|
||||||
default:\
|
|
||||||
abort();\
|
|
||||||
}\
|
|
||||||
0;\
|
|
||||||
})
|
|
||||||
|
|
||||||
#define __get_user(x, ptr) \
|
|
||||||
({\
|
|
||||||
int size = sizeof(*ptr);\
|
|
||||||
switch(size) {\
|
|
||||||
case 1:\
|
|
||||||
x = (typeof(*ptr))ldub(ptr);\
|
|
||||||
break;\
|
|
||||||
case 2:\
|
|
||||||
x = (typeof(*ptr))lduw(ptr);\
|
|
||||||
break;\
|
|
||||||
case 4:\
|
|
||||||
x = (typeof(*ptr))ldl(ptr);\
|
|
||||||
break;\
|
|
||||||
case 8:\
|
|
||||||
x = (typeof(*ptr))ldq(ptr);\
|
|
||||||
break;\
|
|
||||||
default:\
|
|
||||||
abort();\
|
|
||||||
}\
|
|
||||||
0;\
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
#define __copy_to_user(dst, src, size)\
|
|
||||||
({\
|
|
||||||
memcpy(dst, src, size);\
|
|
||||||
0;\
|
|
||||||
})
|
|
||||||
|
|
||||||
#define __copy_from_user(dst, src, size)\
|
|
||||||
({\
|
|
||||||
memcpy(dst, src, size);\
|
|
||||||
0;\
|
|
||||||
})
|
|
||||||
|
|
||||||
#define __clear_user(dst, size)\
|
|
||||||
({\
|
|
||||||
memset(dst, 0, size);\
|
|
||||||
0;\
|
|
||||||
})
|
|
||||||
|
|
||||||
#ifndef offsetof
|
#ifndef offsetof
|
||||||
#define offsetof(type, field) ((size_t) &((type *)0)->field)
|
#define offsetof(type, field) ((size_t) &((type *)0)->field)
|
||||||
#endif
|
#endif
|
||||||
@@ -705,14 +661,12 @@ static void setup_frame(int sig, struct emulated_sigaction *ka,
|
|||||||
target_sigset_t *set, CPUX86State *env)
|
target_sigset_t *set, CPUX86State *env)
|
||||||
{
|
{
|
||||||
struct sigframe *frame;
|
struct sigframe *frame;
|
||||||
int err = 0;
|
int i, err = 0;
|
||||||
|
|
||||||
frame = get_sigframe(ka, env, sizeof(*frame));
|
frame = get_sigframe(ka, env, sizeof(*frame));
|
||||||
|
|
||||||
#if 0
|
|
||||||
if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
|
if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
|
||||||
goto give_sigsegv;
|
goto give_sigsegv;
|
||||||
#endif
|
|
||||||
err |= __put_user((/*current->exec_domain
|
err |= __put_user((/*current->exec_domain
|
||||||
&& current->exec_domain->signal_invmap
|
&& current->exec_domain->signal_invmap
|
||||||
&& sig < 32
|
&& sig < 32
|
||||||
@@ -726,12 +680,10 @@ static void setup_frame(int sig, struct emulated_sigaction *ka,
|
|||||||
if (err)
|
if (err)
|
||||||
goto give_sigsegv;
|
goto give_sigsegv;
|
||||||
|
|
||||||
if (TARGET_NSIG_WORDS > 1) {
|
for(i = 1; i < TARGET_NSIG_WORDS; i++) {
|
||||||
err |= __copy_to_user(frame->extramask, &set->sig[1],
|
if (__put_user(set->sig[i], &frame->extramask[i - 1]))
|
||||||
sizeof(frame->extramask));
|
goto give_sigsegv;
|
||||||
}
|
}
|
||||||
if (err)
|
|
||||||
goto give_sigsegv;
|
|
||||||
|
|
||||||
/* Set up to return from userspace. If provided, use a stub
|
/* Set up to return from userspace. If provided, use a stub
|
||||||
already in userspace. */
|
already in userspace. */
|
||||||
@@ -771,14 +723,12 @@ static void setup_rt_frame(int sig, struct emulated_sigaction *ka,
|
|||||||
target_sigset_t *set, CPUX86State *env)
|
target_sigset_t *set, CPUX86State *env)
|
||||||
{
|
{
|
||||||
struct rt_sigframe *frame;
|
struct rt_sigframe *frame;
|
||||||
int err = 0;
|
int i, err = 0;
|
||||||
|
|
||||||
frame = get_sigframe(ka, env, sizeof(*frame));
|
frame = get_sigframe(ka, env, sizeof(*frame));
|
||||||
|
|
||||||
#if 0
|
|
||||||
if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
|
if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
|
||||||
goto give_sigsegv;
|
goto give_sigsegv;
|
||||||
#endif
|
|
||||||
|
|
||||||
err |= __put_user((/*current->exec_domain
|
err |= __put_user((/*current->exec_domain
|
||||||
&& current->exec_domain->signal_invmap
|
&& current->exec_domain->signal_invmap
|
||||||
@@ -801,9 +751,10 @@ static void setup_rt_frame(int sig, struct emulated_sigaction *ka,
|
|||||||
err |= __put_user(/* current->sas_ss_size */ 0, &frame->uc.uc_stack.ss_size);
|
err |= __put_user(/* current->sas_ss_size */ 0, &frame->uc.uc_stack.ss_size);
|
||||||
err |= setup_sigcontext(&frame->uc.uc_mcontext, &frame->fpstate,
|
err |= setup_sigcontext(&frame->uc.uc_mcontext, &frame->fpstate,
|
||||||
env, set->sig[0]);
|
env, set->sig[0]);
|
||||||
err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
|
for(i = 0; i < TARGET_NSIG_WORDS; i++) {
|
||||||
if (err)
|
if (__put_user(set->sig[i], &frame->uc.uc_sigmask.sig[i]))
|
||||||
goto give_sigsegv;
|
goto give_sigsegv;
|
||||||
|
}
|
||||||
|
|
||||||
/* Set up to return from userspace. If provided, use a stub
|
/* Set up to return from userspace. If provided, use a stub
|
||||||
already in userspace. */
|
already in userspace. */
|
||||||
@@ -898,11 +849,14 @@ long do_sigreturn(CPUX86State *env)
|
|||||||
fprintf(stderr, "do_sigreturn\n");
|
fprintf(stderr, "do_sigreturn\n");
|
||||||
#endif
|
#endif
|
||||||
/* set blocked signals */
|
/* set blocked signals */
|
||||||
target_set.sig[0] = frame->sc.oldmask;
|
if (__get_user(target_set.sig[0], &frame->sc.oldmask))
|
||||||
for(i = 1; i < TARGET_NSIG_WORDS; i++)
|
goto badframe;
|
||||||
target_set.sig[i] = frame->extramask[i - 1];
|
for(i = 1; i < TARGET_NSIG_WORDS; i++) {
|
||||||
|
if (__get_user(target_set.sig[i], &frame->extramask[i - 1]))
|
||||||
|
goto badframe;
|
||||||
|
}
|
||||||
|
|
||||||
target_to_host_sigset(&set, &target_set);
|
target_to_host_sigset_internal(&set, &target_set);
|
||||||
sigprocmask(SIG_SETMASK, &set, NULL);
|
sigprocmask(SIG_SETMASK, &set, NULL);
|
||||||
|
|
||||||
/* restore registers */
|
/* restore registers */
|
||||||
@@ -918,7 +872,6 @@ badframe:
|
|||||||
long do_rt_sigreturn(CPUX86State *env)
|
long do_rt_sigreturn(CPUX86State *env)
|
||||||
{
|
{
|
||||||
struct rt_sigframe *frame = (struct rt_sigframe *)(env->regs[R_ESP] - 4);
|
struct rt_sigframe *frame = (struct rt_sigframe *)(env->regs[R_ESP] - 4);
|
||||||
target_sigset_t target_set;
|
|
||||||
sigset_t set;
|
sigset_t set;
|
||||||
// stack_t st;
|
// stack_t st;
|
||||||
int eax;
|
int eax;
|
||||||
@@ -927,9 +880,7 @@ long do_rt_sigreturn(CPUX86State *env)
|
|||||||
if (verify_area(VERIFY_READ, frame, sizeof(*frame)))
|
if (verify_area(VERIFY_READ, frame, sizeof(*frame)))
|
||||||
goto badframe;
|
goto badframe;
|
||||||
#endif
|
#endif
|
||||||
memcpy(&target_set, &frame->uc.uc_sigmask, sizeof(target_sigset_t));
|
target_to_host_sigset(&set, &frame->uc.uc_sigmask);
|
||||||
|
|
||||||
target_to_host_sigset(&set, &target_set);
|
|
||||||
sigprocmask(SIG_SETMASK, &set, NULL);
|
sigprocmask(SIG_SETMASK, &set, NULL);
|
||||||
|
|
||||||
if (restore_sigcontext(env, &frame->uc.uc_mcontext, &eax))
|
if (restore_sigcontext(env, &frame->uc.uc_mcontext, &eax))
|
||||||
@@ -1153,13 +1104,13 @@ static void setup_frame(int usig, struct emulated_sigaction *ka,
|
|||||||
target_sigset_t *set, CPUState *regs)
|
target_sigset_t *set, CPUState *regs)
|
||||||
{
|
{
|
||||||
struct sigframe *frame = get_sigframe(ka, regs, sizeof(*frame));
|
struct sigframe *frame = get_sigframe(ka, regs, sizeof(*frame));
|
||||||
int err = 0;
|
int i, err = 0;
|
||||||
|
|
||||||
err |= setup_sigcontext(&frame->sc, /*&frame->fpstate,*/ regs, set->sig[0]);
|
err |= setup_sigcontext(&frame->sc, /*&frame->fpstate,*/ regs, set->sig[0]);
|
||||||
|
|
||||||
if (TARGET_NSIG_WORDS > 1) {
|
for(i = 1; i < TARGET_NSIG_WORDS; i++) {
|
||||||
err |= __copy_to_user(frame->extramask, &set->sig[1],
|
if (__put_user(set->sig[i], &frame->extramask[i - 1]))
|
||||||
sizeof(frame->extramask));
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (err == 0)
|
if (err == 0)
|
||||||
@@ -1172,12 +1123,11 @@ static void setup_rt_frame(int usig, struct emulated_sigaction *ka,
|
|||||||
target_sigset_t *set, CPUState *env)
|
target_sigset_t *set, CPUState *env)
|
||||||
{
|
{
|
||||||
struct rt_sigframe *frame = get_sigframe(ka, env, sizeof(*frame));
|
struct rt_sigframe *frame = get_sigframe(ka, env, sizeof(*frame));
|
||||||
int err = 0;
|
int i, err = 0;
|
||||||
|
|
||||||
#if 0
|
|
||||||
if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame)))
|
if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame)))
|
||||||
return 1;
|
return /* 1 */;
|
||||||
#endif
|
|
||||||
__put_user_error(&frame->info, (target_ulong *)&frame->pinfo, err);
|
__put_user_error(&frame->info, (target_ulong *)&frame->pinfo, err);
|
||||||
__put_user_error(&frame->uc, (target_ulong *)&frame->puc, err);
|
__put_user_error(&frame->uc, (target_ulong *)&frame->puc, err);
|
||||||
err |= copy_siginfo_to_user(&frame->info, info);
|
err |= copy_siginfo_to_user(&frame->info, info);
|
||||||
@@ -1187,7 +1137,10 @@ static void setup_rt_frame(int usig, struct emulated_sigaction *ka,
|
|||||||
|
|
||||||
err |= setup_sigcontext(&frame->uc.uc_mcontext, /*&frame->fpstate,*/
|
err |= setup_sigcontext(&frame->uc.uc_mcontext, /*&frame->fpstate,*/
|
||||||
env, set->sig[0]);
|
env, set->sig[0]);
|
||||||
err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
|
for(i = 0; i < TARGET_NSIG_WORDS; i++) {
|
||||||
|
if (__put_user(set->sig[i], &frame->uc.uc_sigmask.sig[i]))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (err == 0)
|
if (err == 0)
|
||||||
err = setup_return(env, ka, &frame->retcode, frame, usig);
|
err = setup_return(env, ka, &frame->retcode, frame, usig);
|
||||||
@@ -1240,6 +1193,7 @@ long do_sigreturn(CPUState *env)
|
|||||||
struct sigframe *frame;
|
struct sigframe *frame;
|
||||||
target_sigset_t set;
|
target_sigset_t set;
|
||||||
sigset_t host_set;
|
sigset_t host_set;
|
||||||
|
int i;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Since we stacked the signal on a 64-bit boundary,
|
* Since we stacked the signal on a 64-bit boundary,
|
||||||
@@ -1255,13 +1209,14 @@ long do_sigreturn(CPUState *env)
|
|||||||
if (verify_area(VERIFY_READ, frame, sizeof (*frame)))
|
if (verify_area(VERIFY_READ, frame, sizeof (*frame)))
|
||||||
goto badframe;
|
goto badframe;
|
||||||
#endif
|
#endif
|
||||||
if (__get_user(set.sig[0], &frame->sc.oldmask)
|
if (__get_user(set.sig[0], &frame->sc.oldmask))
|
||||||
|| (TARGET_NSIG_WORDS > 1
|
goto badframe;
|
||||||
&& __copy_from_user(&set.sig[1], &frame->extramask,
|
for(i = 1; i < TARGET_NSIG_WORDS; i++) {
|
||||||
sizeof(frame->extramask))))
|
if (__get_user(set.sig[i], &frame->extramask[i - 1]))
|
||||||
goto badframe;
|
goto badframe;
|
||||||
|
}
|
||||||
|
|
||||||
target_to_host_sigset(&host_set, &set);
|
target_to_host_sigset_internal(&host_set, &set);
|
||||||
sigprocmask(SIG_SETMASK, &host_set, NULL);
|
sigprocmask(SIG_SETMASK, &host_set, NULL);
|
||||||
|
|
||||||
if (restore_sigcontext(env, &frame->sc))
|
if (restore_sigcontext(env, &frame->sc))
|
||||||
@@ -1282,7 +1237,6 @@ badframe:
|
|||||||
long do_rt_sigreturn(CPUState *env)
|
long do_rt_sigreturn(CPUState *env)
|
||||||
{
|
{
|
||||||
struct rt_sigframe *frame;
|
struct rt_sigframe *frame;
|
||||||
target_sigset_t set;
|
|
||||||
sigset_t host_set;
|
sigset_t host_set;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1299,10 +1253,7 @@ long do_rt_sigreturn(CPUState *env)
|
|||||||
if (verify_area(VERIFY_READ, frame, sizeof (*frame)))
|
if (verify_area(VERIFY_READ, frame, sizeof (*frame)))
|
||||||
goto badframe;
|
goto badframe;
|
||||||
#endif
|
#endif
|
||||||
if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
|
target_to_host_sigset(&host_set, &frame->uc.uc_sigmask);
|
||||||
goto badframe;
|
|
||||||
|
|
||||||
target_to_host_sigset(&host_set, &set);
|
|
||||||
sigprocmask(SIG_SETMASK, &host_set, NULL);
|
sigprocmask(SIG_SETMASK, &host_set, NULL);
|
||||||
|
|
||||||
if (restore_sigcontext(env, &frame->uc.uc_mcontext))
|
if (restore_sigcontext(env, &frame->uc.uc_mcontext))
|
||||||
@@ -1405,7 +1356,7 @@ void process_pending_signals(void *cpu_env)
|
|||||||
sigprocmask(SIG_BLOCK, &set, &old_set);
|
sigprocmask(SIG_BLOCK, &set, &old_set);
|
||||||
/* save the previous blocked signal state to restore it at the
|
/* save the previous blocked signal state to restore it at the
|
||||||
end of the signal execution (see do_sigreturn) */
|
end of the signal execution (see do_sigreturn) */
|
||||||
host_to_target_sigset(&target_old_set, &old_set);
|
host_to_target_sigset_internal(&target_old_set, &old_set);
|
||||||
|
|
||||||
/* if the CPU is in VM86 mode, we restore the 32 bit values */
|
/* if the CPU is in VM86 mode, we restore the 32 bit values */
|
||||||
#ifdef TARGET_I386
|
#ifdef TARGET_I386
|
||||||
|
|||||||
@@ -0,0 +1,279 @@
|
|||||||
|
/* from asm/termbits.h */
|
||||||
|
|
||||||
|
#define TARGET_NCCS 19
|
||||||
|
|
||||||
|
struct target_termios {
|
||||||
|
unsigned int c_iflag; /* input mode flags */
|
||||||
|
unsigned int c_oflag; /* output mode flags */
|
||||||
|
unsigned int c_cflag; /* control mode flags */
|
||||||
|
unsigned int c_lflag; /* local mode flags */
|
||||||
|
unsigned char c_line; /* line discipline */
|
||||||
|
unsigned char c_cc[TARGET_NCCS]; /* control characters */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* c_cc characters */
|
||||||
|
#define TARGET_VINTR 0
|
||||||
|
#define TARGET_VQUIT 1
|
||||||
|
#define TARGET_VERASE 2
|
||||||
|
#define TARGET_VKILL 3
|
||||||
|
#define TARGET_VEOF 4
|
||||||
|
#define TARGET_VEOL 5
|
||||||
|
#define TARGET_VEOL2 6
|
||||||
|
#define TARGET_VSWTC 7
|
||||||
|
#define TARGET_VSTART 8
|
||||||
|
#define TARGET_VSTOP 9
|
||||||
|
|
||||||
|
#define TARGET_VSUSP 10
|
||||||
|
#define TARGET_VDSUSP 11 /* SunOS POSIX nicety I do believe... */
|
||||||
|
#define TARGET_VREPRINT 12
|
||||||
|
#define TARGET_VDISCARD 13
|
||||||
|
#define TARGET_VWERASE 14
|
||||||
|
#define TARGET_VLNEXT 15
|
||||||
|
|
||||||
|
/* Kernel keeps vmin/vtime separated, user apps assume vmin/vtime is
|
||||||
|
* shared with eof/eol
|
||||||
|
*/
|
||||||
|
#define TARGET_VMIN TARGET_VEOF
|
||||||
|
#define TARGET_VTIME TARGET_VEOL
|
||||||
|
|
||||||
|
/* c_iflag bits */
|
||||||
|
#define TARGET_IGNBRK 0x00000001
|
||||||
|
#define TARGET_BRKINT 0x00000002
|
||||||
|
#define TARGET_IGNPAR 0x00000004
|
||||||
|
#define TARGET_PARMRK 0x00000008
|
||||||
|
#define TARGET_INPCK 0x00000010
|
||||||
|
#define TARGET_ISTRIP 0x00000020
|
||||||
|
#define TARGET_INLCR 0x00000040
|
||||||
|
#define TARGET_IGNCR 0x00000080
|
||||||
|
#define TARGET_ICRNL 0x00000100
|
||||||
|
#define TARGET_IUCLC 0x00000200
|
||||||
|
#define TARGET_IXON 0x00000400
|
||||||
|
#define TARGET_IXANY 0x00000800
|
||||||
|
#define TARGET_IXOFF 0x00001000
|
||||||
|
#define TARGET_IMAXBEL 0x00002000
|
||||||
|
|
||||||
|
/* c_oflag bits */
|
||||||
|
#define TARGET_OPOST 0x00000001
|
||||||
|
#define TARGET_OLCUC 0x00000002
|
||||||
|
#define TARGET_ONLCR 0x00000004
|
||||||
|
#define TARGET_OCRNL 0x00000008
|
||||||
|
#define TARGET_ONOCR 0x00000010
|
||||||
|
#define TARGET_ONLRET 0x00000020
|
||||||
|
#define TARGET_OFILL 0x00000040
|
||||||
|
#define TARGET_OFDEL 0x00000080
|
||||||
|
#define TARGET_NLDLY 0x00000100
|
||||||
|
#define TARGET_NL0 0x00000000
|
||||||
|
#define TARGET_NL1 0x00000100
|
||||||
|
#define TARGET_CRDLY 0x00000600
|
||||||
|
#define TARGET_CR0 0x00000000
|
||||||
|
#define TARGET_CR1 0x00000200
|
||||||
|
#define TARGET_CR2 0x00000400
|
||||||
|
#define TARGET_CR3 0x00000600
|
||||||
|
#define TARGET_TABDLY 0x00001800
|
||||||
|
#define TARGET_TAB0 0x00000000
|
||||||
|
#define TARGET_TAB1 0x00000800
|
||||||
|
#define TARGET_TAB2 0x00001000
|
||||||
|
#define TARGET_TAB3 0x00001800
|
||||||
|
#define TARGET_XTABS 0x00001800
|
||||||
|
#define TARGET_BSDLY 0x00002000
|
||||||
|
#define TARGET_BS0 0x00000000
|
||||||
|
#define TARGET_BS1 0x00002000
|
||||||
|
#define TARGET_VTDLY 0x00004000
|
||||||
|
#define TARGET_VT0 0x00000000
|
||||||
|
#define TARGET_VT1 0x00004000
|
||||||
|
#define TARGET_FFDLY 0x00008000
|
||||||
|
#define TARGET_FF0 0x00000000
|
||||||
|
#define TARGET_FF1 0x00008000
|
||||||
|
#define TARGET_PAGEOUT 0x00010000 /* SUNOS specific */
|
||||||
|
#define TARGET_WRAP 0x00020000 /* SUNOS specific */
|
||||||
|
|
||||||
|
/* c_cflag bit meaning */
|
||||||
|
#define TARGET_CBAUD 0x0000100f
|
||||||
|
#define TARGET_B0 0x00000000 /* hang up */
|
||||||
|
#define TARGET_B50 0x00000001
|
||||||
|
#define TARGET_B75 0x00000002
|
||||||
|
#define TARGET_B110 0x00000003
|
||||||
|
#define TARGET_B134 0x00000004
|
||||||
|
#define TARGET_B150 0x00000005
|
||||||
|
#define TARGET_B200 0x00000006
|
||||||
|
#define TARGET_B300 0x00000007
|
||||||
|
#define TARGET_B600 0x00000008
|
||||||
|
#define TARGET_B1200 0x00000009
|
||||||
|
#define TARGET_B1800 0x0000000a
|
||||||
|
#define TARGET_B2400 0x0000000b
|
||||||
|
#define TARGET_B4800 0x0000000c
|
||||||
|
#define TARGET_B9600 0x0000000d
|
||||||
|
#define TARGET_B19200 0x0000000e
|
||||||
|
#define TARGET_B38400 0x0000000f
|
||||||
|
#define TARGET_EXTA B19200
|
||||||
|
#define TARGET_EXTB B38400
|
||||||
|
#define TARGET_CSIZE 0x00000030
|
||||||
|
#define TARGET_CS5 0x00000000
|
||||||
|
#define TARGET_CS6 0x00000010
|
||||||
|
#define TARGET_CS7 0x00000020
|
||||||
|
#define TARGET_CS8 0x00000030
|
||||||
|
#define TARGET_CSTOPB 0x00000040
|
||||||
|
#define TARGET_CREAD 0x00000080
|
||||||
|
#define TARGET_PARENB 0x00000100
|
||||||
|
#define TARGET_PARODD 0x00000200
|
||||||
|
#define TARGET_HUPCL 0x00000400
|
||||||
|
#define TARGET_CLOCAL 0x00000800
|
||||||
|
#define TARGET_CBAUDEX 0x00001000
|
||||||
|
/* We'll never see these speeds with the Zilogs, but for completeness... */
|
||||||
|
#define TARGET_B57600 0x00001001
|
||||||
|
#define TARGET_B115200 0x00001002
|
||||||
|
#define TARGET_B230400 0x00001003
|
||||||
|
#define TARGET_B460800 0x00001004
|
||||||
|
/* This is what we can do with the Zilogs. */
|
||||||
|
#define TARGET_B76800 0x00001005
|
||||||
|
/* This is what we can do with the SAB82532. */
|
||||||
|
#define TARGET_B153600 0x00001006
|
||||||
|
#define TARGET_B307200 0x00001007
|
||||||
|
#define TARGET_B614400 0x00001008
|
||||||
|
#define TARGET_B921600 0x00001009
|
||||||
|
/* And these are the rest... */
|
||||||
|
#define TARGET_B500000 0x0000100a
|
||||||
|
#define TARGET_B576000 0x0000100b
|
||||||
|
#define TARGET_B1000000 0x0000100c
|
||||||
|
#define TARGET_B1152000 0x0000100d
|
||||||
|
#define TARGET_B1500000 0x0000100e
|
||||||
|
#define TARGET_B2000000 0x0000100f
|
||||||
|
/* These have totally bogus values and nobody uses them
|
||||||
|
so far. Later on we'd have to use say 0x10000x and
|
||||||
|
adjust CBAUD constant and drivers accordingly.
|
||||||
|
#define B2500000 0x00001010
|
||||||
|
#define B3000000 0x00001011
|
||||||
|
#define B3500000 0x00001012
|
||||||
|
#define B4000000 0x00001013 */
|
||||||
|
#define TARGET_CIBAUD 0x100f0000 /* input baud rate (not used) */
|
||||||
|
#define TARGET_CMSPAR 0x40000000 /* mark or space (stick) parity */
|
||||||
|
#define TARGET_CRTSCTS 0x80000000 /* flow control */
|
||||||
|
|
||||||
|
/* c_lflag bits */
|
||||||
|
#define TARGET_ISIG 0x00000001
|
||||||
|
#define TARGET_ICANON 0x00000002
|
||||||
|
#define TARGET_XCASE 0x00000004
|
||||||
|
#define TARGET_ECHO 0x00000008
|
||||||
|
#define TARGET_ECHOE 0x00000010
|
||||||
|
#define TARGET_ECHOK 0x00000020
|
||||||
|
#define TARGET_ECHONL 0x00000040
|
||||||
|
#define TARGET_NOFLSH 0x00000080
|
||||||
|
#define TARGET_TOSTOP 0x00000100
|
||||||
|
#define TARGET_ECHOCTL 0x00000200
|
||||||
|
#define TARGET_ECHOPRT 0x00000400
|
||||||
|
#define TARGET_ECHOKE 0x00000800
|
||||||
|
#define TARGET_DEFECHO 0x00001000 /* SUNOS thing, what is it? */
|
||||||
|
#define TARGET_FLUSHO 0x00002000
|
||||||
|
#define TARGET_PENDIN 0x00004000
|
||||||
|
#define TARGET_IEXTEN 0x00008000
|
||||||
|
|
||||||
|
/* ioctls */
|
||||||
|
|
||||||
|
/* Big T */
|
||||||
|
#define TARGET_TCGETA TARGET_IOR('T', 1, struct target_termio)
|
||||||
|
#define TARGET_TCSETA TARGET_IOW('T', 2, struct target_termio)
|
||||||
|
#define TARGET_TCSETAW TARGET_IOW('T', 3, struct target_termio)
|
||||||
|
#define TARGET_TCSETAF TARGET_IOW('T', 4, struct target_termio)
|
||||||
|
#define TARGET_TCSBRK TARGET_IO('T', 5)
|
||||||
|
#define TARGET_TCXONC TARGET_IO('T', 6)
|
||||||
|
#define TARGET_TCFLSH TARGET_IO('T', 7)
|
||||||
|
#define TARGET_TCGETS TARGET_IOR('T', 8, struct target_termios)
|
||||||
|
#define TARGET_TCSETS TARGET_IOW('T', 9, struct target_termios)
|
||||||
|
#define TARGET_TCSETSW TARGET_IOW('T', 10, struct target_termios)
|
||||||
|
#define TARGET_TCSETSF TARGET_IOW('T', 11, struct target_termios)
|
||||||
|
|
||||||
|
/* Note that all the ioctls that are not available in Linux have a
|
||||||
|
* double underscore on the front to: a) avoid some programs to
|
||||||
|
* thing we support some ioctls under Linux (autoconfiguration stuff)
|
||||||
|
*/
|
||||||
|
/* Little t */
|
||||||
|
#define TARGET_TIOCGETD TARGET_IOR('t', 0, int)
|
||||||
|
#define TARGET_TIOCSETD TARGET_IOW('t', 1, int)
|
||||||
|
//#define __TIOCHPCL _IO('t', 2) /* SunOS Specific */
|
||||||
|
//#define __TIOCMODG _IOR('t', 3, int) /* SunOS Specific */
|
||||||
|
//#define __TIOCMODS _IOW('t', 4, int) /* SunOS Specific */
|
||||||
|
//#define __TIOCGETP _IOR('t', 8, struct sgttyb) /* SunOS Specific */
|
||||||
|
//#define __TIOCSETP _IOW('t', 9, struct sgttyb) /* SunOS Specific */
|
||||||
|
//#define __TIOCSETN _IOW('t', 10, struct sgttyb) /* SunOS Specific */
|
||||||
|
#define TARGET_TIOCEXCL TARGET_IO('t', 13)
|
||||||
|
#define TARGET_TIOCNXCL TARGET_IO('t', 14)
|
||||||
|
//#define __TIOCFLUSH _IOW('t', 16, int) /* SunOS Specific */
|
||||||
|
//#define __TIOCSETC _IOW('t', 17, struct tchars) /* SunOS Specific */
|
||||||
|
//#define __TIOCGETC _IOR('t', 18, struct tchars) /* SunOS Specific */
|
||||||
|
//#define __TIOCTCNTL _IOW('t', 32, int) /* SunOS Specific */
|
||||||
|
//#define __TIOCSIGNAL _IOW('t', 33, int) /* SunOS Specific */
|
||||||
|
//#define __TIOCSETX _IOW('t', 34, int) /* SunOS Specific */
|
||||||
|
//#define __TIOCGETX _IOR('t', 35, int) /* SunOS Specific */
|
||||||
|
#define TARGET_TIOCCONS TARGET_IO('t', 36)
|
||||||
|
//#define __TIOCSSIZE _IOW('t', 37, struct sunos_ttysize) /* SunOS Specific */
|
||||||
|
//#define __TIOCGSIZE _IOR('t', 38, struct sunos_ttysize) /* SunOS Specific */
|
||||||
|
#define TARGET_TIOCGSOFTCAR TARGET_IOR('t', 100, int)
|
||||||
|
#define TARGET_TIOCSSOFTCAR TARGET_IOW('t', 101, int)
|
||||||
|
//#define __TIOCUCNTL _IOW('t', 102, int) /* SunOS Specific */
|
||||||
|
#define TARGET_TIOCSWINSZ TARGET_IOW('t', 103, struct winsize)
|
||||||
|
#define TARGET_TIOCGWINSZ TARGET_IOR('t', 104, struct winsize)
|
||||||
|
//#define __TIOCREMOTE _IOW('t', 105, int) /* SunOS Specific */
|
||||||
|
#define TARGET_TIOCMGET TARGET_IOR('t', 106, int)
|
||||||
|
#define TARGET_TIOCMBIC TARGET_IOW('t', 107, int)
|
||||||
|
#define TARGET_TIOCMBIS TARGET_IOW('t', 108, int)
|
||||||
|
#define TARGET_TIOCMSET TARGET_IOW('t', 109, int)
|
||||||
|
#define TARGET_TIOCSTART TARGET_IO('t', 110)
|
||||||
|
#define TARGET_TIOCSTOP TARGET_IO('t', 111)
|
||||||
|
#define TARGET_TIOCPKT TARGET_IOW('t', 112, int)
|
||||||
|
#define TARGET_TIOCNOTTY TARGET_IO('t', 113)
|
||||||
|
#define TARGET_TIOCSTI TARGET_IOW('t', 114, char)
|
||||||
|
#define TARGET_TIOCOUTQ TARGET_IOR('t', 115, int)
|
||||||
|
//#define __TIOCGLTC _IOR('t', 116, struct ltchars) /* SunOS Specific */
|
||||||
|
//#define __TIOCSLTC _IOW('t', 117, struct ltchars) /* SunOS Specific */
|
||||||
|
/* 118 is the non-posix setpgrp tty ioctl */
|
||||||
|
/* 119 is the non-posix getpgrp tty ioctl */
|
||||||
|
//#define __TIOCCDTR TARGET_IO('t', 120) /* SunOS Specific */
|
||||||
|
//#define __TIOCSDTR TARGET_IO('t', 121) /* SunOS Specific */
|
||||||
|
#define TARGET_TIOCCBRK TARGET_IO('t', 122)
|
||||||
|
#define TARGET_TIOCSBRK TARGET_IO('t', 123)
|
||||||
|
//#define __TIOCLGET TARGET_IOW('t', 124, int) /* SunOS Specific */
|
||||||
|
//#define __TIOCLSET TARGET_IOW('t', 125, int) /* SunOS Specific */
|
||||||
|
//#define __TIOCLBIC TARGET_IOW('t', 126, int) /* SunOS Specific */
|
||||||
|
//#define __TIOCLBIS TARGET_IOW('t', 127, int) /* SunOS Specific */
|
||||||
|
//#define __TIOCISPACE TARGET_IOR('t', 128, int) /* SunOS Specific */
|
||||||
|
//#define __TIOCISIZE TARGET_IOR('t', 129, int) /* SunOS Specific */
|
||||||
|
#define TARGET_TIOCSPGRP TARGET_IOW('t', 130, int)
|
||||||
|
#define TARGET_TIOCGPGRP TARGET_IOR('t', 131, int)
|
||||||
|
#define TARGET_TIOCSCTTY TARGET_IO('t', 132)
|
||||||
|
#define TARGET_TIOCGSID TARGET_IOR('t', 133, int)
|
||||||
|
/* Get minor device of a pty master's FD -- Solaris equiv is ISPTM */
|
||||||
|
#define TARGET_TIOCGPTN TARGET_IOR('t', 134, unsigned int) /* Get Pty Number */
|
||||||
|
#define TARGET_TIOCSPTLCK TARGET_IOW('t', 135, int) /* Lock/unlock PTY */
|
||||||
|
|
||||||
|
/* Little f */
|
||||||
|
#define TARGET_FIOCLEX TARGET_IO('f', 1)
|
||||||
|
#define TARGET_FIONCLEX TARGET_IO('f', 2)
|
||||||
|
#define TARGET_FIOASYNC TARGET_IOW('f', 125, int)
|
||||||
|
#define TARGET_FIONBIO TARGET_IOW('f', 126, int)
|
||||||
|
#define TARGET_FIONREAD TARGET_IOR('f', 127, int)
|
||||||
|
#define TARGET_TIOCINQ TARGET_FIONREAD
|
||||||
|
|
||||||
|
/* SCARY Rutgers local SunOS kernel hackery, perhaps I will support it
|
||||||
|
* someday. This is completely bogus, I know...
|
||||||
|
*/
|
||||||
|
//#define __TCGETSTAT TARGET_IO('T', 200) /* Rutgers specific */
|
||||||
|
//#define __TCSETSTAT TARGET_IO('T', 201) /* Rutgers specific */
|
||||||
|
|
||||||
|
/* Linux specific, no SunOS equivalent. */
|
||||||
|
#define TARGET_TIOCLINUX 0x541C
|
||||||
|
#define TARGET_TIOCGSERIAL 0x541E
|
||||||
|
#define TARGET_TIOCSSERIAL 0x541F
|
||||||
|
#define TARGET_TCSBRKP 0x5425
|
||||||
|
#define TARGET_TIOCTTYGSTRUCT 0x5426
|
||||||
|
#define TARGET_TIOCSERCONFIG 0x5453
|
||||||
|
#define TARGET_TIOCSERGWILD 0x5454
|
||||||
|
#define TARGET_TIOCSERSWILD 0x5455
|
||||||
|
#define TARGET_TIOCGLCKTRMIOS 0x5456
|
||||||
|
#define TARGET_TIOCSLCKTRMIOS 0x5457
|
||||||
|
#define TARGET_TIOCSERGSTRUCT 0x5458 /* For debugging only */
|
||||||
|
#define TARGET_TIOCSERGETLSR 0x5459 /* Get line status register */
|
||||||
|
#define TARGET_TIOCSERGETMULTI 0x545A /* Get multiport config */
|
||||||
|
#define TARGET_TIOCSERSETMULTI 0x545B /* Set multiport config */
|
||||||
|
#define TARGET_TIOCMIWAIT 0x545C /* Wait input */
|
||||||
|
#define TARGET_TIOCGICOUNT 0x545D /* Read serial port inline interrupt counts */
|
||||||
|
|
||||||
+470
-189
@@ -41,8 +41,11 @@
|
|||||||
#include <sys/uio.h>
|
#include <sys/uio.h>
|
||||||
#include <sys/poll.h>
|
#include <sys/poll.h>
|
||||||
#include <sys/times.h>
|
#include <sys/times.h>
|
||||||
|
#include <sys/shm.h>
|
||||||
#include <utime.h>
|
#include <utime.h>
|
||||||
|
#include <sys/sysinfo.h>
|
||||||
//#include <sys/user.h>
|
//#include <sys/user.h>
|
||||||
|
#include <netinet/ip.h>
|
||||||
#include <netinet/tcp.h>
|
#include <netinet/tcp.h>
|
||||||
|
|
||||||
#define termios host_termios
|
#define termios host_termios
|
||||||
@@ -65,6 +68,11 @@
|
|||||||
|
|
||||||
//#define DEBUG
|
//#define DEBUG
|
||||||
|
|
||||||
|
#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SPARC)
|
||||||
|
/* 16 bit uid wrappers emulation */
|
||||||
|
#define USE_UID16
|
||||||
|
#endif
|
||||||
|
|
||||||
//#include <linux/msdos_fs.h>
|
//#include <linux/msdos_fs.h>
|
||||||
#define VFAT_IOCTL_READDIR_BOTH _IOR('r', 1, struct dirent [2])
|
#define VFAT_IOCTL_READDIR_BOTH _IOR('r', 1, struct dirent [2])
|
||||||
#define VFAT_IOCTL_READDIR_SHORT _IOR('r', 2, struct dirent [2])
|
#define VFAT_IOCTL_READDIR_SHORT _IOR('r', 2, struct dirent [2])
|
||||||
@@ -200,7 +208,7 @@ type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5) \
|
|||||||
#define __NR_sys_getdents64 __NR_getdents64
|
#define __NR_sys_getdents64 __NR_getdents64
|
||||||
#define __NR_sys_rt_sigqueueinfo __NR_rt_sigqueueinfo
|
#define __NR_sys_rt_sigqueueinfo __NR_rt_sigqueueinfo
|
||||||
|
|
||||||
#if defined(__alpha__) || defined (__ia64__)
|
#if defined(__alpha__) || defined (__ia64__) || defined(__x86_64__)
|
||||||
#define __NR__llseek __NR_lseek
|
#define __NR__llseek __NR_lseek
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -320,7 +328,7 @@ static inline void host_to_target_fds(target_long *target_fds,
|
|||||||
target_long v;
|
target_long v;
|
||||||
|
|
||||||
if (target_fds) {
|
if (target_fds) {
|
||||||
nw = n / TARGET_LONG_BITS;
|
nw = (n + TARGET_LONG_BITS - 1) / TARGET_LONG_BITS;
|
||||||
k = 0;
|
k = 0;
|
||||||
for(i = 0;i < nw; i++) {
|
for(i = 0;i < nw; i++) {
|
||||||
v = 0;
|
v = 0;
|
||||||
@@ -525,61 +533,116 @@ static inline void host_to_target_cmsg(struct target_msghdr *target_msgh,
|
|||||||
static long do_setsockopt(int sockfd, int level, int optname,
|
static long do_setsockopt(int sockfd, int level, int optname,
|
||||||
void *optval, socklen_t optlen)
|
void *optval, socklen_t optlen)
|
||||||
{
|
{
|
||||||
if (level == SOL_TCP) {
|
int val, ret;
|
||||||
|
|
||||||
|
switch(level) {
|
||||||
|
case SOL_TCP:
|
||||||
/* TCP options all take an 'int' value. */
|
/* TCP options all take an 'int' value. */
|
||||||
int val;
|
|
||||||
|
|
||||||
if (optlen < sizeof(uint32_t))
|
if (optlen < sizeof(uint32_t))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
val = tswap32(*(uint32_t *)optval);
|
if (get_user(val, (uint32_t *)optval))
|
||||||
return get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
|
return -EFAULT;
|
||||||
}
|
ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
|
||||||
|
break;
|
||||||
else if (level != SOL_SOCKET) {
|
case SOL_IP:
|
||||||
gemu_log("Unsupported setsockopt level: %d\n", level);
|
switch(optname) {
|
||||||
return -ENOSYS;
|
case IP_HDRINCL:
|
||||||
}
|
val = 0;
|
||||||
|
if (optlen >= sizeof(uint32_t)) {
|
||||||
switch (optname) {
|
if (get_user(val, (uint32_t *)optval))
|
||||||
/* Options with 'int' argument. */
|
return -EFAULT;
|
||||||
case SO_DEBUG:
|
} else if (optlen >= 1) {
|
||||||
case SO_REUSEADDR:
|
if (get_user(val, (uint8_t *)optval))
|
||||||
case SO_TYPE:
|
return -EFAULT;
|
||||||
case SO_ERROR:
|
}
|
||||||
case SO_DONTROUTE:
|
ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
|
||||||
case SO_BROADCAST:
|
break;
|
||||||
case SO_SNDBUF:
|
default:
|
||||||
case SO_RCVBUF:
|
goto unimplemented;
|
||||||
case SO_KEEPALIVE:
|
}
|
||||||
case SO_OOBINLINE:
|
break;
|
||||||
case SO_NO_CHECK:
|
case SOL_SOCKET:
|
||||||
case SO_PRIORITY:
|
switch (optname) {
|
||||||
case SO_BSDCOMPAT:
|
/* Options with 'int' argument. */
|
||||||
case SO_PASSCRED:
|
case SO_DEBUG:
|
||||||
case SO_TIMESTAMP:
|
case SO_REUSEADDR:
|
||||||
case SO_RCVLOWAT:
|
case SO_TYPE:
|
||||||
case SO_RCVTIMEO:
|
case SO_ERROR:
|
||||||
case SO_SNDTIMEO:
|
case SO_DONTROUTE:
|
||||||
{
|
case SO_BROADCAST:
|
||||||
int val;
|
case SO_SNDBUF:
|
||||||
if (optlen < sizeof(uint32_t))
|
case SO_RCVBUF:
|
||||||
return -EINVAL;
|
case SO_KEEPALIVE:
|
||||||
val = tswap32(*(uint32_t *)optval);
|
case SO_OOBINLINE:
|
||||||
return get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
|
case SO_NO_CHECK:
|
||||||
}
|
case SO_PRIORITY:
|
||||||
|
case SO_BSDCOMPAT:
|
||||||
|
case SO_PASSCRED:
|
||||||
|
case SO_TIMESTAMP:
|
||||||
|
case SO_RCVLOWAT:
|
||||||
|
case SO_RCVTIMEO:
|
||||||
|
case SO_SNDTIMEO:
|
||||||
|
if (optlen < sizeof(uint32_t))
|
||||||
|
return -EINVAL;
|
||||||
|
if (get_user(val, (uint32_t *)optval))
|
||||||
|
return -EFAULT;
|
||||||
|
ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
goto unimplemented;
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
gemu_log("Unsupported setsockopt SOL_SOCKET option: %d\n", optname);
|
unimplemented:
|
||||||
return -ENOSYS;
|
gemu_log("Unsupported setsockopt level=%d optname=%d \n", level, optname);
|
||||||
|
ret = -ENOSYS;
|
||||||
}
|
}
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static long do_getsockopt(int sockfd, int level, int optname,
|
static long do_getsockopt(int sockfd, int level, int optname,
|
||||||
void *optval, socklen_t *optlen)
|
void *optval, socklen_t *optlen)
|
||||||
{
|
{
|
||||||
gemu_log("getsockopt not yet supported\n");
|
int len, lv, val, ret;
|
||||||
return -ENOSYS;
|
|
||||||
|
switch(level) {
|
||||||
|
case SOL_SOCKET:
|
||||||
|
switch (optname) {
|
||||||
|
case SO_LINGER:
|
||||||
|
case SO_RCVTIMEO:
|
||||||
|
case SO_SNDTIMEO:
|
||||||
|
case SO_PEERCRED:
|
||||||
|
case SO_PEERNAME:
|
||||||
|
/* These don't just return a single integer */
|
||||||
|
goto unimplemented;
|
||||||
|
default:
|
||||||
|
if (get_user(len, optlen))
|
||||||
|
return -EFAULT;
|
||||||
|
if (len < 0)
|
||||||
|
return -EINVAL;
|
||||||
|
lv = sizeof(int);
|
||||||
|
ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
val = tswap32(val);
|
||||||
|
if (len > lv)
|
||||||
|
len = lv;
|
||||||
|
if (copy_to_user(optval, &val, len))
|
||||||
|
return -EFAULT;
|
||||||
|
if (put_user(len, optlen))
|
||||||
|
return -EFAULT;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
unimplemented:
|
||||||
|
gemu_log("getsockopt level=%d optname=%d not yet supported\n",
|
||||||
|
level, optname);
|
||||||
|
ret = -ENOSYS;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static long do_socketcall(int num, int32_t *vptr)
|
static long do_socketcall(int num, int32_t *vptr)
|
||||||
@@ -802,12 +865,9 @@ static long do_socketcall(int num, int32_t *vptr)
|
|||||||
int level = tswap32(vptr[1]);
|
int level = tswap32(vptr[1]);
|
||||||
int optname = tswap32(vptr[2]);
|
int optname = tswap32(vptr[2]);
|
||||||
void *optval = (void *)tswap32(vptr[3]);
|
void *optval = (void *)tswap32(vptr[3]);
|
||||||
uint32_t *target_len = (void *)tswap32(vptr[4]);
|
uint32_t *poptlen = (void *)tswap32(vptr[4]);
|
||||||
socklen_t optlen = tswap32(*target_len);
|
|
||||||
|
|
||||||
ret = do_getsockopt(sockfd, level, optname, optval, &optlen);
|
ret = do_getsockopt(sockfd, level, optname, optval, poptlen);
|
||||||
if (!is_error(ret))
|
|
||||||
*target_len = tswap32(optlen);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@@ -818,6 +878,92 @@ static long do_socketcall(int num, int32_t *vptr)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#define N_SHM_REGIONS 32
|
||||||
|
|
||||||
|
static struct shm_region {
|
||||||
|
uint32_t start;
|
||||||
|
uint32_t size;
|
||||||
|
} shm_regions[N_SHM_REGIONS];
|
||||||
|
|
||||||
|
static long do_ipc(long call, long first, long second, long third,
|
||||||
|
long ptr, long fifth)
|
||||||
|
{
|
||||||
|
int version;
|
||||||
|
long ret = 0;
|
||||||
|
unsigned long raddr;
|
||||||
|
struct shmid_ds shm_info;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
version = call >> 16;
|
||||||
|
call &= 0xffff;
|
||||||
|
|
||||||
|
switch (call) {
|
||||||
|
case IPCOP_shmat:
|
||||||
|
/* SHM_* flags are the same on all linux platforms */
|
||||||
|
ret = get_errno((long) shmat(first, (void *) ptr, second));
|
||||||
|
if (is_error(ret))
|
||||||
|
break;
|
||||||
|
raddr = ret;
|
||||||
|
/* find out the length of the shared memory segment */
|
||||||
|
|
||||||
|
ret = get_errno(shmctl(first, IPC_STAT, &shm_info));
|
||||||
|
if (is_error(ret)) {
|
||||||
|
/* can't get length, bail out */
|
||||||
|
shmdt((void *) raddr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
page_set_flags(raddr, raddr + shm_info.shm_segsz,
|
||||||
|
PAGE_VALID | PAGE_READ |
|
||||||
|
((second & SHM_RDONLY)? 0: PAGE_WRITE));
|
||||||
|
for (i = 0; i < N_SHM_REGIONS; ++i) {
|
||||||
|
if (shm_regions[i].start == 0) {
|
||||||
|
shm_regions[i].start = raddr;
|
||||||
|
shm_regions[i].size = shm_info.shm_segsz;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (put_user(raddr, (uint32_t *)third))
|
||||||
|
return -EFAULT;
|
||||||
|
ret = 0;
|
||||||
|
break;
|
||||||
|
case IPCOP_shmdt:
|
||||||
|
for (i = 0; i < N_SHM_REGIONS; ++i) {
|
||||||
|
if (shm_regions[i].start == ptr) {
|
||||||
|
shm_regions[i].start = 0;
|
||||||
|
page_set_flags(ptr, shm_regions[i].size, 0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ret = get_errno(shmdt((void *) ptr));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case IPCOP_shmget:
|
||||||
|
/* IPC_* flag values are the same on all linux platforms */
|
||||||
|
ret = get_errno(shmget(first, second, third));
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* IPC_* and SHM_* command values are the same on all linux platforms */
|
||||||
|
case IPCOP_shmctl:
|
||||||
|
switch(second) {
|
||||||
|
case IPC_RMID:
|
||||||
|
case SHM_LOCK:
|
||||||
|
case SHM_UNLOCK:
|
||||||
|
ret = get_errno(shmctl(first, second, NULL));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
goto unimplemented;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
unimplemented:
|
||||||
|
gemu_log("Unsupported ipc call: %ld (version %d)\n", call, version);
|
||||||
|
ret = -ENOSYS;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/* kernel structure types definitions */
|
/* kernel structure types definitions */
|
||||||
#define IFNAMSIZ 16
|
#define IFNAMSIZ 16
|
||||||
|
|
||||||
@@ -1104,6 +1250,26 @@ static bitmask_transtbl mmap_flags_tbl[] = {
|
|||||||
{ 0, 0, 0, 0 }
|
{ 0, 0, 0, 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static bitmask_transtbl fcntl_flags_tbl[] = {
|
||||||
|
{ TARGET_O_ACCMODE, TARGET_O_WRONLY, O_ACCMODE, O_WRONLY, },
|
||||||
|
{ TARGET_O_ACCMODE, TARGET_O_RDWR, O_ACCMODE, O_RDWR, },
|
||||||
|
{ TARGET_O_CREAT, TARGET_O_CREAT, O_CREAT, O_CREAT, },
|
||||||
|
{ TARGET_O_EXCL, TARGET_O_EXCL, O_EXCL, O_EXCL, },
|
||||||
|
{ TARGET_O_NOCTTY, TARGET_O_NOCTTY, O_NOCTTY, O_NOCTTY, },
|
||||||
|
{ TARGET_O_TRUNC, TARGET_O_TRUNC, O_TRUNC, O_TRUNC, },
|
||||||
|
{ TARGET_O_APPEND, TARGET_O_APPEND, O_APPEND, O_APPEND, },
|
||||||
|
{ TARGET_O_NONBLOCK, TARGET_O_NONBLOCK, O_NONBLOCK, O_NONBLOCK, },
|
||||||
|
{ TARGET_O_SYNC, TARGET_O_SYNC, O_SYNC, O_SYNC, },
|
||||||
|
{ TARGET_FASYNC, TARGET_FASYNC, FASYNC, FASYNC, },
|
||||||
|
{ TARGET_O_DIRECTORY, TARGET_O_DIRECTORY, O_DIRECTORY, O_DIRECTORY, },
|
||||||
|
{ TARGET_O_NOFOLLOW, TARGET_O_NOFOLLOW, O_NOFOLLOW, O_NOFOLLOW, },
|
||||||
|
{ TARGET_O_LARGEFILE, TARGET_O_LARGEFILE, O_LARGEFILE, O_LARGEFILE, },
|
||||||
|
#if defined(O_DIRECT)
|
||||||
|
{ TARGET_O_DIRECT, TARGET_O_DIRECT, O_DIRECT, O_DIRECT, },
|
||||||
|
#endif
|
||||||
|
{ 0, 0, 0, 0 }
|
||||||
|
};
|
||||||
|
|
||||||
#if defined(TARGET_I386)
|
#if defined(TARGET_I386)
|
||||||
|
|
||||||
/* NOTE: there is really one LDT for all the threads */
|
/* NOTE: there is really one LDT for all the threads */
|
||||||
@@ -1264,7 +1430,16 @@ int do_fork(CPUState *env, unsigned int flags, unsigned long newsp)
|
|||||||
new_env->regs[13] = newsp;
|
new_env->regs[13] = newsp;
|
||||||
new_env->regs[0] = 0;
|
new_env->regs[0] = 0;
|
||||||
#elif defined(TARGET_SPARC)
|
#elif defined(TARGET_SPARC)
|
||||||
printf ("HELPME: %s:%d\n", __FILE__, __LINE__);
|
printf ("HELPME: %s:%d\n", __FILE__, __LINE__);
|
||||||
|
#elif defined(TARGET_PPC)
|
||||||
|
if (!newsp)
|
||||||
|
newsp = env->gpr[1];
|
||||||
|
new_env->gpr[1] = newsp;
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = 7; i < 32; i++)
|
||||||
|
new_env->gpr[i] = 0;
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
#error unsupported target CPU
|
#error unsupported target CPU
|
||||||
#endif
|
#endif
|
||||||
@@ -1318,6 +1493,15 @@ static long do_fcntl(int fd, int cmd, unsigned long arg)
|
|||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case F_GETFL:
|
||||||
|
ret = fcntl(fd, cmd, arg);
|
||||||
|
ret = host_to_target_bitmask(ret, fcntl_flags_tbl);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case F_SETFL:
|
||||||
|
ret = fcntl(fd, cmd, target_to_host_bitmask(arg, fcntl_flags_tbl));
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
ret = fcntl(fd, cmd, arg);
|
ret = fcntl(fd, cmd, arg);
|
||||||
break;
|
break;
|
||||||
@@ -1325,11 +1509,41 @@ static long do_fcntl(int fd, int cmd, unsigned long arg)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef USE_UID16
|
||||||
|
|
||||||
#define high2lowuid(x) (x)
|
static inline int high2lowuid(int uid)
|
||||||
#define high2lowgid(x) (x)
|
{
|
||||||
#define low2highuid(x) (x)
|
if (uid > 65535)
|
||||||
#define low2highgid(x) (x)
|
return 65534;
|
||||||
|
else
|
||||||
|
return uid;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int high2lowgid(int gid)
|
||||||
|
{
|
||||||
|
if (gid > 65535)
|
||||||
|
return 65534;
|
||||||
|
else
|
||||||
|
return gid;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int low2highuid(int uid)
|
||||||
|
{
|
||||||
|
if ((int16_t)uid == -1)
|
||||||
|
return -1;
|
||||||
|
else
|
||||||
|
return uid;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int low2highgid(int gid)
|
||||||
|
{
|
||||||
|
if ((int16_t)gid == -1)
|
||||||
|
return -1;
|
||||||
|
else
|
||||||
|
return gid;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* USE_UID16 */
|
||||||
|
|
||||||
void syscall_init(void)
|
void syscall_init(void)
|
||||||
{
|
{
|
||||||
@@ -1371,7 +1585,7 @@ void syscall_init(void)
|
|||||||
ie++;
|
ie++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
||||||
long arg4, long arg5, long arg6)
|
long arg4, long arg5, long arg6)
|
||||||
{
|
{
|
||||||
@@ -1380,7 +1594,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
|||||||
struct kernel_statfs *stfs;
|
struct kernel_statfs *stfs;
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
gemu_log("syscall %d\n", num);
|
gemu_log("syscall %d", num);
|
||||||
#endif
|
#endif
|
||||||
switch(num) {
|
switch(num) {
|
||||||
case TARGET_NR_exit:
|
case TARGET_NR_exit:
|
||||||
@@ -1399,7 +1613,9 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
|||||||
ret = get_errno(write(arg1, (void *)arg2, arg3));
|
ret = get_errno(write(arg1, (void *)arg2, arg3));
|
||||||
break;
|
break;
|
||||||
case TARGET_NR_open:
|
case TARGET_NR_open:
|
||||||
ret = get_errno(open(path((const char *)arg1), arg2, arg3));
|
ret = get_errno(open(path((const char *)arg1),
|
||||||
|
target_to_host_bitmask(arg2, fcntl_flags_tbl),
|
||||||
|
arg3));
|
||||||
break;
|
break;
|
||||||
case TARGET_NR_close:
|
case TARGET_NR_close:
|
||||||
ret = get_errno(close(arg1));
|
ret = get_errno(close(arg1));
|
||||||
@@ -1472,9 +1688,6 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
|||||||
case TARGET_NR_chmod:
|
case TARGET_NR_chmod:
|
||||||
ret = get_errno(chmod((const char *)arg1, arg2));
|
ret = get_errno(chmod((const char *)arg1, arg2));
|
||||||
break;
|
break;
|
||||||
case TARGET_NR_lchown:
|
|
||||||
ret = get_errno(chown((const char *)arg1, arg2, arg3));
|
|
||||||
break;
|
|
||||||
#ifdef TARGET_NR_break
|
#ifdef TARGET_NR_break
|
||||||
case TARGET_NR_break:
|
case TARGET_NR_break:
|
||||||
goto unimplemented;
|
goto unimplemented;
|
||||||
@@ -1495,12 +1708,6 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
|||||||
case TARGET_NR_umount:
|
case TARGET_NR_umount:
|
||||||
ret = get_errno(umount((const char *)arg1));
|
ret = get_errno(umount((const char *)arg1));
|
||||||
break;
|
break;
|
||||||
case TARGET_NR_setuid:
|
|
||||||
ret = get_errno(setuid(low2highuid(arg1)));
|
|
||||||
break;
|
|
||||||
case TARGET_NR_getuid:
|
|
||||||
ret = get_errno(getuid());
|
|
||||||
break;
|
|
||||||
case TARGET_NR_stime:
|
case TARGET_NR_stime:
|
||||||
{
|
{
|
||||||
int *time_ptr = (int *)arg1;
|
int *time_ptr = (int *)arg1;
|
||||||
@@ -1523,11 +1730,16 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
|||||||
break;
|
break;
|
||||||
case TARGET_NR_utime:
|
case TARGET_NR_utime:
|
||||||
{
|
{
|
||||||
struct utimbuf tbuf;
|
struct utimbuf tbuf, *tbuf1;
|
||||||
struct target_utimbuf *target_tbuf = (void *)arg2;
|
struct target_utimbuf *target_tbuf = (void *)arg2;
|
||||||
tbuf.actime = tswapl(target_tbuf->actime);
|
if (target_tbuf) {
|
||||||
tbuf.modtime = tswapl(target_tbuf->modtime);
|
get_user(tbuf.actime, &target_tbuf->actime);
|
||||||
ret = get_errno(utime((const char *)arg1, &tbuf));
|
get_user(tbuf.modtime, &target_tbuf->modtime);
|
||||||
|
tbuf1 = &tbuf;
|
||||||
|
} else {
|
||||||
|
tbuf1 = NULL;
|
||||||
|
}
|
||||||
|
ret = get_errno(utime((const char *)arg1, tbuf1));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
#ifdef TARGET_NR_stty
|
#ifdef TARGET_NR_stty
|
||||||
@@ -1596,20 +1808,9 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
|||||||
case TARGET_NR_prof:
|
case TARGET_NR_prof:
|
||||||
goto unimplemented;
|
goto unimplemented;
|
||||||
#endif
|
#endif
|
||||||
case TARGET_NR_setgid:
|
|
||||||
ret = get_errno(setgid(low2highgid(arg1)));
|
|
||||||
break;
|
|
||||||
case TARGET_NR_getgid:
|
|
||||||
ret = get_errno(getgid());
|
|
||||||
break;
|
|
||||||
case TARGET_NR_signal:
|
case TARGET_NR_signal:
|
||||||
goto unimplemented;
|
goto unimplemented;
|
||||||
case TARGET_NR_geteuid:
|
|
||||||
ret = get_errno(geteuid());
|
|
||||||
break;
|
|
||||||
case TARGET_NR_getegid:
|
|
||||||
ret = get_errno(getegid());
|
|
||||||
break;
|
|
||||||
case TARGET_NR_acct:
|
case TARGET_NR_acct:
|
||||||
goto unimplemented;
|
goto unimplemented;
|
||||||
case TARGET_NR_umount2:
|
case TARGET_NR_umount2:
|
||||||
@@ -1844,12 +2045,6 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
|||||||
/* NOTE: ret is eax, so not transcoding must be done */
|
/* NOTE: ret is eax, so not transcoding must be done */
|
||||||
ret = do_rt_sigreturn(cpu_env);
|
ret = do_rt_sigreturn(cpu_env);
|
||||||
break;
|
break;
|
||||||
case TARGET_NR_setreuid:
|
|
||||||
ret = get_errno(setreuid(arg1, arg2));
|
|
||||||
break;
|
|
||||||
case TARGET_NR_setregid:
|
|
||||||
ret = get_errno(setregid(arg1, arg2));
|
|
||||||
break;
|
|
||||||
case TARGET_NR_sethostname:
|
case TARGET_NR_sethostname:
|
||||||
ret = get_errno(sethostname((const char *)arg1, arg2));
|
ret = get_errno(sethostname((const char *)arg1, arg2));
|
||||||
break;
|
break;
|
||||||
@@ -1906,34 +2101,6 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
|||||||
ret = get_errno(settimeofday(&tv, NULL));
|
ret = get_errno(settimeofday(&tv, NULL));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case TARGET_NR_getgroups:
|
|
||||||
{
|
|
||||||
int gidsetsize = arg1;
|
|
||||||
uint16_t *target_grouplist = (void *)arg2;
|
|
||||||
gid_t *grouplist;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
grouplist = alloca(gidsetsize * sizeof(gid_t));
|
|
||||||
ret = get_errno(getgroups(gidsetsize, grouplist));
|
|
||||||
if (!is_error(ret)) {
|
|
||||||
for(i = 0;i < gidsetsize; i++)
|
|
||||||
target_grouplist[i] = tswap16(grouplist[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case TARGET_NR_setgroups:
|
|
||||||
{
|
|
||||||
int gidsetsize = arg1;
|
|
||||||
uint16_t *target_grouplist = (void *)arg2;
|
|
||||||
gid_t *grouplist;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
grouplist = alloca(gidsetsize * sizeof(gid_t));
|
|
||||||
for(i = 0;i < gidsetsize; i++)
|
|
||||||
grouplist[i] = tswap16(target_grouplist[i]);
|
|
||||||
ret = get_errno(setgroups(gidsetsize, grouplist));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case TARGET_NR_select:
|
case TARGET_NR_select:
|
||||||
{
|
{
|
||||||
struct target_sel_arg_struct *sel = (void *)arg1;
|
struct target_sel_arg_struct *sel = (void *)arg1;
|
||||||
@@ -1988,10 +2155,15 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
|||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
case TARGET_NR_mmap2:
|
case TARGET_NR_mmap2:
|
||||||
|
#if defined(TARGET_SPARC)
|
||||||
|
#define MMAP_SHIFT 12
|
||||||
|
#else
|
||||||
|
#define MMAP_SHIFT TARGET_PAGE_BITS
|
||||||
|
#endif
|
||||||
ret = get_errno(target_mmap(arg1, arg2, arg3,
|
ret = get_errno(target_mmap(arg1, arg2, arg3,
|
||||||
target_to_host_bitmask(arg4, mmap_flags_tbl),
|
target_to_host_bitmask(arg4, mmap_flags_tbl),
|
||||||
arg5,
|
arg5,
|
||||||
arg6 << TARGET_PAGE_BITS));
|
arg6 << MMAP_SHIFT));
|
||||||
break;
|
break;
|
||||||
case TARGET_NR_munmap:
|
case TARGET_NR_munmap:
|
||||||
ret = get_errno(target_munmap(arg1, arg2));
|
ret = get_errno(target_munmap(arg1, arg2));
|
||||||
@@ -2026,9 +2198,6 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
|||||||
case TARGET_NR_fchmod:
|
case TARGET_NR_fchmod:
|
||||||
ret = get_errno(fchmod(arg1, arg2));
|
ret = get_errno(fchmod(arg1, arg2));
|
||||||
break;
|
break;
|
||||||
case TARGET_NR_fchown:
|
|
||||||
ret = get_errno(fchown(arg1, arg2, arg3));
|
|
||||||
break;
|
|
||||||
case TARGET_NR_getpriority:
|
case TARGET_NR_getpriority:
|
||||||
ret = get_errno(getpriority(arg1, arg2));
|
ret = get_errno(getpriority(arg1, arg2));
|
||||||
break;
|
break;
|
||||||
@@ -2121,10 +2290,16 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
|||||||
struct target_stat *target_st = (void *)arg2;
|
struct target_stat *target_st = (void *)arg2;
|
||||||
target_st->st_dev = tswap16(st.st_dev);
|
target_st->st_dev = tswap16(st.st_dev);
|
||||||
target_st->st_ino = tswapl(st.st_ino);
|
target_st->st_ino = tswapl(st.st_ino);
|
||||||
|
#if defined(TARGET_PPC)
|
||||||
|
target_st->st_mode = tswapl(st.st_mode); /* XXX: check this */
|
||||||
|
target_st->st_uid = tswap32(st.st_uid);
|
||||||
|
target_st->st_gid = tswap32(st.st_gid);
|
||||||
|
#else
|
||||||
target_st->st_mode = tswap16(st.st_mode);
|
target_st->st_mode = tswap16(st.st_mode);
|
||||||
target_st->st_nlink = tswap16(st.st_nlink);
|
|
||||||
target_st->st_uid = tswap16(st.st_uid);
|
target_st->st_uid = tswap16(st.st_uid);
|
||||||
target_st->st_gid = tswap16(st.st_gid);
|
target_st->st_gid = tswap16(st.st_gid);
|
||||||
|
#endif
|
||||||
|
target_st->st_nlink = tswap16(st.st_nlink);
|
||||||
target_st->st_rdev = tswap16(st.st_rdev);
|
target_st->st_rdev = tswap16(st.st_rdev);
|
||||||
target_st->st_size = tswapl(st.st_size);
|
target_st->st_size = tswapl(st.st_size);
|
||||||
target_st->st_blksize = tswapl(st.st_blksize);
|
target_st->st_blksize = tswapl(st.st_blksize);
|
||||||
@@ -2174,9 +2349,32 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
|||||||
ret = get_errno(swapoff((const char *)arg1));
|
ret = get_errno(swapoff((const char *)arg1));
|
||||||
break;
|
break;
|
||||||
case TARGET_NR_sysinfo:
|
case TARGET_NR_sysinfo:
|
||||||
goto unimplemented;
|
{
|
||||||
|
struct target_sysinfo *target_value = (void *)arg1;
|
||||||
|
struct sysinfo value;
|
||||||
|
ret = get_errno(sysinfo(&value));
|
||||||
|
if (!is_error(ret) && target_value)
|
||||||
|
{
|
||||||
|
__put_user(value.uptime, &target_value->uptime);
|
||||||
|
__put_user(value.loads[0], &target_value->loads[0]);
|
||||||
|
__put_user(value.loads[1], &target_value->loads[1]);
|
||||||
|
__put_user(value.loads[2], &target_value->loads[2]);
|
||||||
|
__put_user(value.totalram, &target_value->totalram);
|
||||||
|
__put_user(value.freeram, &target_value->freeram);
|
||||||
|
__put_user(value.sharedram, &target_value->sharedram);
|
||||||
|
__put_user(value.bufferram, &target_value->bufferram);
|
||||||
|
__put_user(value.totalswap, &target_value->totalswap);
|
||||||
|
__put_user(value.freeswap, &target_value->freeswap);
|
||||||
|
__put_user(value.procs, &target_value->procs);
|
||||||
|
__put_user(value.totalhigh, &target_value->totalhigh);
|
||||||
|
__put_user(value.freehigh, &target_value->freehigh);
|
||||||
|
__put_user(value.mem_unit, &target_value->mem_unit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
case TARGET_NR_ipc:
|
case TARGET_NR_ipc:
|
||||||
goto unimplemented;
|
ret = do_ipc(arg1, arg2, arg3, arg4, arg5, arg6);
|
||||||
|
break;
|
||||||
case TARGET_NR_fsync:
|
case TARGET_NR_fsync:
|
||||||
ret = get_errno(fsync(arg1));
|
ret = get_errno(fsync(arg1));
|
||||||
break;
|
break;
|
||||||
@@ -2230,17 +2428,16 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
|||||||
break;
|
break;
|
||||||
case TARGET_NR_afs_syscall:
|
case TARGET_NR_afs_syscall:
|
||||||
goto unimplemented;
|
goto unimplemented;
|
||||||
case TARGET_NR_setfsuid:
|
|
||||||
ret = get_errno(setfsuid(arg1));
|
|
||||||
break;
|
|
||||||
case TARGET_NR_setfsgid:
|
|
||||||
ret = get_errno(setfsgid(arg1));
|
|
||||||
break;
|
|
||||||
case TARGET_NR__llseek:
|
case TARGET_NR__llseek:
|
||||||
{
|
{
|
||||||
|
#if defined (__x86_64__)
|
||||||
|
ret = get_errno(lseek(arg1, ((uint64_t )arg2 << 32) | arg3, arg5));
|
||||||
|
*(int64_t *)arg4 = ret;
|
||||||
|
#else
|
||||||
int64_t res;
|
int64_t res;
|
||||||
ret = get_errno(_llseek(arg1, arg2, arg3, &res, arg5));
|
ret = get_errno(_llseek(arg1, arg2, arg3, &res, arg5));
|
||||||
*(int64_t *)arg4 = tswap64(res);
|
*(int64_t *)arg4 = tswap64(res);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case TARGET_NR_getdents:
|
case TARGET_NR_getdents:
|
||||||
@@ -2311,6 +2508,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
|
#ifdef TARGET_NR_getdents64
|
||||||
case TARGET_NR_getdents64:
|
case TARGET_NR_getdents64:
|
||||||
{
|
{
|
||||||
struct dirent64 *dirp = (void *)arg2;
|
struct dirent64 *dirp = (void *)arg2;
|
||||||
@@ -2334,6 +2532,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
#endif /* TARGET_NR_getdents64 */
|
||||||
case TARGET_NR__newselect:
|
case TARGET_NR__newselect:
|
||||||
ret = do_select(arg1, (void *)arg2, (void *)arg3, (void *)arg4,
|
ret = do_select(arg1, (void *)arg2, (void *)arg3, (void *)arg4,
|
||||||
(void *)arg5);
|
(void *)arg5);
|
||||||
@@ -2465,52 +2664,13 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
#ifdef TARGET_NR_setresuid
|
|
||||||
case TARGET_NR_setresuid:
|
|
||||||
ret = get_errno(setresuid(low2highuid(arg1),
|
|
||||||
low2highuid(arg2),
|
|
||||||
low2highuid(arg3)));
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
#ifdef TARGET_NR_getresuid
|
|
||||||
case TARGET_NR_getresuid:
|
|
||||||
{
|
|
||||||
int ruid, euid, suid;
|
|
||||||
ret = get_errno(getresuid(&ruid, &euid, &suid));
|
|
||||||
if (!is_error(ret)) {
|
|
||||||
*(uint16_t *)arg1 = tswap16(high2lowuid(ruid));
|
|
||||||
*(uint16_t *)arg2 = tswap16(high2lowuid(euid));
|
|
||||||
*(uint16_t *)arg3 = tswap16(high2lowuid(suid));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
#ifdef TARGET_NR_getresgid
|
|
||||||
case TARGET_NR_setresgid:
|
|
||||||
ret = get_errno(setresgid(low2highgid(arg1),
|
|
||||||
low2highgid(arg2),
|
|
||||||
low2highgid(arg3)));
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
#ifdef TARGET_NR_getresgid
|
|
||||||
case TARGET_NR_getresgid:
|
|
||||||
{
|
|
||||||
int rgid, egid, sgid;
|
|
||||||
ret = get_errno(getresgid(&rgid, &egid, &sgid));
|
|
||||||
if (!is_error(ret)) {
|
|
||||||
*(uint16_t *)arg1 = high2lowgid(tswap16(rgid));
|
|
||||||
*(uint16_t *)arg2 = high2lowgid(tswap16(egid));
|
|
||||||
*(uint16_t *)arg3 = high2lowgid(tswap16(sgid));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
case TARGET_NR_query_module:
|
case TARGET_NR_query_module:
|
||||||
goto unimplemented;
|
goto unimplemented;
|
||||||
case TARGET_NR_nfsservctl:
|
case TARGET_NR_nfsservctl:
|
||||||
goto unimplemented;
|
goto unimplemented;
|
||||||
case TARGET_NR_prctl:
|
case TARGET_NR_prctl:
|
||||||
goto unimplemented;
|
goto unimplemented;
|
||||||
|
#ifdef TARGET_NR_pread
|
||||||
case TARGET_NR_pread:
|
case TARGET_NR_pread:
|
||||||
page_unprotect_range((void *)arg2, arg3);
|
page_unprotect_range((void *)arg2, arg3);
|
||||||
ret = get_errno(pread(arg1, (void *)arg2, arg3, arg4));
|
ret = get_errno(pread(arg1, (void *)arg2, arg3, arg4));
|
||||||
@@ -2518,9 +2678,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
|||||||
case TARGET_NR_pwrite:
|
case TARGET_NR_pwrite:
|
||||||
ret = get_errno(pwrite(arg1, (void *)arg2, arg3, arg4));
|
ret = get_errno(pwrite(arg1, (void *)arg2, arg3, arg4));
|
||||||
break;
|
break;
|
||||||
case TARGET_NR_chown:
|
#endif
|
||||||
ret = get_errno(chown((const char *)arg1, arg2, arg3));
|
|
||||||
break;
|
|
||||||
case TARGET_NR_getcwd:
|
case TARGET_NR_getcwd:
|
||||||
ret = get_errno(sys_getcwd1((char *)arg1, arg2));
|
ret = get_errno(sys_getcwd1((char *)arg1, arg2));
|
||||||
break;
|
break;
|
||||||
@@ -2573,27 +2731,137 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
|||||||
if (!is_error(ret)) {
|
if (!is_error(ret)) {
|
||||||
struct target_stat64 *target_st = (void *)arg2;
|
struct target_stat64 *target_st = (void *)arg2;
|
||||||
memset(target_st, 0, sizeof(struct target_stat64));
|
memset(target_st, 0, sizeof(struct target_stat64));
|
||||||
target_st->st_dev = tswap16(st.st_dev);
|
put_user(st.st_dev, &target_st->st_dev);
|
||||||
target_st->st_ino = tswap64(st.st_ino);
|
put_user(st.st_ino, &target_st->st_ino);
|
||||||
#ifdef TARGET_STAT64_HAS_BROKEN_ST_INO
|
#ifdef TARGET_STAT64_HAS_BROKEN_ST_INO
|
||||||
target_st->__st_ino = tswapl(st.st_ino);
|
put_user(st.st_ino, &target_st->__st_ino);
|
||||||
#endif
|
#endif
|
||||||
target_st->st_mode = tswap32(st.st_mode);
|
put_user(st.st_mode, &target_st->st_mode);
|
||||||
target_st->st_nlink = tswap32(st.st_nlink);
|
put_user(st.st_nlink, &target_st->st_nlink);
|
||||||
target_st->st_uid = tswapl(st.st_uid);
|
put_user(st.st_uid, &target_st->st_uid);
|
||||||
target_st->st_gid = tswapl(st.st_gid);
|
put_user(st.st_gid, &target_st->st_gid);
|
||||||
target_st->st_rdev = tswap16(st.st_rdev);
|
put_user(st.st_rdev, &target_st->st_rdev);
|
||||||
/* XXX: better use of kernel struct */
|
/* XXX: better use of kernel struct */
|
||||||
target_st->st_size = tswap64(st.st_size);
|
put_user(st.st_size, &target_st->st_size);
|
||||||
target_st->st_blksize = tswapl(st.st_blksize);
|
put_user(st.st_blksize, &target_st->st_blksize);
|
||||||
target_st->st_blocks = tswapl(st.st_blocks);
|
put_user(st.st_blocks, &target_st->st_blocks);
|
||||||
target_st->target_st_atime = tswapl(st.st_atime);
|
put_user(st.st_atime, &target_st->target_st_atime);
|
||||||
target_st->target_st_mtime = tswapl(st.st_mtime);
|
put_user(st.st_mtime, &target_st->target_st_mtime);
|
||||||
target_st->target_st_ctime = tswapl(st.st_ctime);
|
put_user(st.st_ctime, &target_st->target_st_ctime);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
#ifdef USE_UID16
|
||||||
|
case TARGET_NR_lchown:
|
||||||
|
ret = get_errno(lchown((const char *)arg1, low2highuid(arg2), low2highgid(arg3)));
|
||||||
|
break;
|
||||||
|
case TARGET_NR_getuid:
|
||||||
|
ret = get_errno(high2lowuid(getuid()));
|
||||||
|
break;
|
||||||
|
case TARGET_NR_getgid:
|
||||||
|
ret = get_errno(high2lowgid(getgid()));
|
||||||
|
break;
|
||||||
|
case TARGET_NR_geteuid:
|
||||||
|
ret = get_errno(high2lowuid(geteuid()));
|
||||||
|
break;
|
||||||
|
case TARGET_NR_getegid:
|
||||||
|
ret = get_errno(high2lowgid(getegid()));
|
||||||
|
break;
|
||||||
|
case TARGET_NR_setreuid:
|
||||||
|
ret = get_errno(setreuid(low2highuid(arg1), low2highuid(arg2)));
|
||||||
|
break;
|
||||||
|
case TARGET_NR_setregid:
|
||||||
|
ret = get_errno(setregid(low2highgid(arg1), low2highgid(arg2)));
|
||||||
|
break;
|
||||||
|
case TARGET_NR_getgroups:
|
||||||
|
{
|
||||||
|
int gidsetsize = arg1;
|
||||||
|
uint16_t *target_grouplist = (void *)arg2;
|
||||||
|
gid_t *grouplist;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
grouplist = alloca(gidsetsize * sizeof(gid_t));
|
||||||
|
ret = get_errno(getgroups(gidsetsize, grouplist));
|
||||||
|
if (!is_error(ret)) {
|
||||||
|
for(i = 0;i < gidsetsize; i++)
|
||||||
|
target_grouplist[i] = tswap16(grouplist[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case TARGET_NR_setgroups:
|
||||||
|
{
|
||||||
|
int gidsetsize = arg1;
|
||||||
|
uint16_t *target_grouplist = (void *)arg2;
|
||||||
|
gid_t *grouplist;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
grouplist = alloca(gidsetsize * sizeof(gid_t));
|
||||||
|
for(i = 0;i < gidsetsize; i++)
|
||||||
|
grouplist[i] = tswap16(target_grouplist[i]);
|
||||||
|
ret = get_errno(setgroups(gidsetsize, grouplist));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case TARGET_NR_fchown:
|
||||||
|
ret = get_errno(fchown(arg1, low2highuid(arg2), low2highgid(arg3)));
|
||||||
|
break;
|
||||||
|
#ifdef TARGET_NR_setresuid
|
||||||
|
case TARGET_NR_setresuid:
|
||||||
|
ret = get_errno(setresuid(low2highuid(arg1),
|
||||||
|
low2highuid(arg2),
|
||||||
|
low2highuid(arg3)));
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
#ifdef TARGET_NR_getresuid
|
||||||
|
case TARGET_NR_getresuid:
|
||||||
|
{
|
||||||
|
int ruid, euid, suid;
|
||||||
|
ret = get_errno(getresuid(&ruid, &euid, &suid));
|
||||||
|
if (!is_error(ret)) {
|
||||||
|
*(uint16_t *)arg1 = tswap16(high2lowuid(ruid));
|
||||||
|
*(uint16_t *)arg2 = tswap16(high2lowuid(euid));
|
||||||
|
*(uint16_t *)arg3 = tswap16(high2lowuid(suid));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
#ifdef TARGET_NR_getresgid
|
||||||
|
case TARGET_NR_setresgid:
|
||||||
|
ret = get_errno(setresgid(low2highgid(arg1),
|
||||||
|
low2highgid(arg2),
|
||||||
|
low2highgid(arg3)));
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
#ifdef TARGET_NR_getresgid
|
||||||
|
case TARGET_NR_getresgid:
|
||||||
|
{
|
||||||
|
int rgid, egid, sgid;
|
||||||
|
ret = get_errno(getresgid(&rgid, &egid, &sgid));
|
||||||
|
if (!is_error(ret)) {
|
||||||
|
*(uint16_t *)arg1 = tswap16(high2lowgid(rgid));
|
||||||
|
*(uint16_t *)arg2 = tswap16(high2lowgid(egid));
|
||||||
|
*(uint16_t *)arg3 = tswap16(high2lowgid(sgid));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
case TARGET_NR_chown:
|
||||||
|
ret = get_errno(chown((const char *)arg1, low2highuid(arg2), low2highgid(arg3)));
|
||||||
|
break;
|
||||||
|
case TARGET_NR_setuid:
|
||||||
|
ret = get_errno(setuid(low2highuid(arg1)));
|
||||||
|
break;
|
||||||
|
case TARGET_NR_setgid:
|
||||||
|
ret = get_errno(setgid(low2highgid(arg1)));
|
||||||
|
break;
|
||||||
|
case TARGET_NR_setfsuid:
|
||||||
|
ret = get_errno(setfsuid(arg1));
|
||||||
|
break;
|
||||||
|
case TARGET_NR_setfsgid:
|
||||||
|
ret = get_errno(setfsgid(arg1));
|
||||||
|
break;
|
||||||
|
#endif /* USE_UID16 */
|
||||||
|
|
||||||
case TARGET_NR_lchown32:
|
case TARGET_NR_lchown32:
|
||||||
ret = get_errno(lchown((const char *)arg1, arg2, arg3));
|
ret = get_errno(lchown((const char *)arg1, arg2, arg3));
|
||||||
break;
|
break;
|
||||||
@@ -2665,12 +2933,17 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
|||||||
case TARGET_NR_setfsgid32:
|
case TARGET_NR_setfsgid32:
|
||||||
ret = get_errno(setfsgid(arg1));
|
ret = get_errno(setfsgid(arg1));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TARGET_NR_pivot_root:
|
case TARGET_NR_pivot_root:
|
||||||
goto unimplemented;
|
goto unimplemented;
|
||||||
|
#ifdef TARGET_NR_mincore
|
||||||
case TARGET_NR_mincore:
|
case TARGET_NR_mincore:
|
||||||
goto unimplemented;
|
goto unimplemented;
|
||||||
|
#endif
|
||||||
|
#ifdef TARGET_NR_madvise
|
||||||
case TARGET_NR_madvise:
|
case TARGET_NR_madvise:
|
||||||
goto unimplemented;
|
goto unimplemented;
|
||||||
|
#endif
|
||||||
#if TARGET_LONG_BITS == 32
|
#if TARGET_LONG_BITS == 32
|
||||||
case TARGET_NR_fcntl64:
|
case TARGET_NR_fcntl64:
|
||||||
{
|
{
|
||||||
@@ -2708,6 +2981,11 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
|||||||
#ifdef TARGET_NR_security
|
#ifdef TARGET_NR_security
|
||||||
case TARGET_NR_security:
|
case TARGET_NR_security:
|
||||||
goto unimplemented;
|
goto unimplemented;
|
||||||
|
#endif
|
||||||
|
#ifdef TARGET_NR_getpagesize
|
||||||
|
case TARGET_NR_getpagesize:
|
||||||
|
ret = TARGET_PAGE_SIZE;
|
||||||
|
break;
|
||||||
#endif
|
#endif
|
||||||
case TARGET_NR_gettid:
|
case TARGET_NR_gettid:
|
||||||
ret = get_errno(gettid());
|
ret = get_errno(gettid());
|
||||||
@@ -2742,6 +3020,9 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
fail:
|
fail:
|
||||||
|
#ifdef DEBUG
|
||||||
|
gemu_log(" = %ld\n", ret);
|
||||||
|
#endif
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
+222
-211
@@ -24,6 +24,19 @@
|
|||||||
#define SOCKOP_sendmsg 16
|
#define SOCKOP_sendmsg 16
|
||||||
#define SOCKOP_recvmsg 17
|
#define SOCKOP_recvmsg 17
|
||||||
|
|
||||||
|
#define IPCOP_semop 1
|
||||||
|
#define IPCOP_semget 2
|
||||||
|
#define IPCOP_semctl 3
|
||||||
|
#define IPCOP_semtimedop 4
|
||||||
|
#define IPCOP_msgsnd 11
|
||||||
|
#define IPCOP_msgrcv 12
|
||||||
|
#define IPCOP_msgget 13
|
||||||
|
#define IPCOP_msgctl 14
|
||||||
|
#define IPCOP_shmat 21
|
||||||
|
#define IPCOP_shmdt 22
|
||||||
|
#define IPCOP_shmget 23
|
||||||
|
#define IPCOP_shmctl 24
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The following is for compatibility across the various Linux
|
* The following is for compatibility across the various Linux
|
||||||
* platforms. The i386 ioctl numbering scheme doesn't really enforce
|
* platforms. The i386 ioctl numbering scheme doesn't really enforce
|
||||||
@@ -279,7 +292,7 @@ struct target_sigaction;
|
|||||||
int do_sigaction(int sig, const struct target_sigaction *act,
|
int do_sigaction(int sig, const struct target_sigaction *act,
|
||||||
struct target_sigaction *oact);
|
struct target_sigaction *oact);
|
||||||
|
|
||||||
#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SPARC)
|
#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SPARC) || defined(TARGET_PPC)
|
||||||
|
|
||||||
#define TARGET_SA_NOCLDSTOP 0x00000001
|
#define TARGET_SA_NOCLDSTOP 0x00000001
|
||||||
#define TARGET_SA_NOCLDWAIT 0x00000002 /* not supported yet */
|
#define TARGET_SA_NOCLDWAIT 0x00000002 /* not supported yet */
|
||||||
@@ -414,7 +427,14 @@ typedef struct target_siginfo {
|
|||||||
/*
|
/*
|
||||||
* SIGILL si_codes
|
* SIGILL si_codes
|
||||||
*/
|
*/
|
||||||
|
#define TARGET_ILL_ILLOPC (1) /* illegal opcode */
|
||||||
#define TARGET_ILL_ILLOPN (2) /* illegal operand */
|
#define TARGET_ILL_ILLOPN (2) /* illegal operand */
|
||||||
|
#define TARGET_ILL_ILLADR (3) /* illegal addressing mode */
|
||||||
|
#define TARGET_ILL_ILLTRP (4) /* illegal trap */
|
||||||
|
#define TARGET_ILL_PRVOPC (5) /* privileged opcode */
|
||||||
|
#define TARGET_ILL_PRVREG (6) /* privileged register */
|
||||||
|
#define TARGET_ILL_COPROC (7) /* coprocessor error */
|
||||||
|
#define TARGET_ILL_BADSTK (8) /* internal stack error */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* SIGFPE si_codes
|
* SIGFPE si_codes
|
||||||
@@ -435,6 +455,13 @@ typedef struct target_siginfo {
|
|||||||
#define TARGET_SEGV_MAPERR (1) /* address not mapped to object */
|
#define TARGET_SEGV_MAPERR (1) /* address not mapped to object */
|
||||||
#define TARGET_SEGV_ACCERR (2) /* invalid permissions for mapped object */
|
#define TARGET_SEGV_ACCERR (2) /* invalid permissions for mapped object */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* SIGBUS si_codes
|
||||||
|
*/
|
||||||
|
#define TARGET_BUS_ADRALN (1) /* invalid address alignment */
|
||||||
|
#define TARGET_BUS_ADRERR (2) /* non-existant physical address */
|
||||||
|
#define TARGET_BUS_OBJERR (3) /* object specific hardware error */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* SIGTRAP si_codes
|
* SIGTRAP si_codes
|
||||||
*/
|
*/
|
||||||
@@ -664,220 +691,26 @@ struct target_pollfd {
|
|||||||
#define TARGET_HDIO_SET_PIO_MODE 0x0327 /* reconfig interface to new speed */
|
#define TARGET_HDIO_SET_PIO_MODE 0x0327 /* reconfig interface to new speed */
|
||||||
|
|
||||||
|
|
||||||
#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SPARC)
|
|
||||||
|
|
||||||
/* 0x54 is just a magic number to make these relatively unique ('T') */
|
|
||||||
|
|
||||||
#define TARGET_TCGETS 0x5401
|
|
||||||
#define TARGET_TCSETS 0x5402
|
|
||||||
#define TARGET_TCSETSW 0x5403
|
|
||||||
#define TARGET_TCSETSF 0x5404
|
|
||||||
#define TARGET_TCGETA 0x5405
|
|
||||||
#define TARGET_TCSETA 0x5406
|
|
||||||
#define TARGET_TCSETAW 0x5407
|
|
||||||
#define TARGET_TCSETAF 0x5408
|
|
||||||
#define TARGET_TCSBRK 0x5409
|
|
||||||
#define TARGET_TCXONC 0x540A
|
|
||||||
#define TARGET_TCFLSH 0x540B
|
|
||||||
#define TARGET_TIOCEXCL 0x540C
|
|
||||||
#define TARGET_TIOCNXCL 0x540D
|
|
||||||
#define TARGET_TIOCSCTTY 0x540E
|
|
||||||
#define TARGET_TIOCGPGRP 0x540F
|
|
||||||
#define TARGET_TIOCSPGRP 0x5410
|
|
||||||
#define TARGET_TIOCOUTQ 0x5411
|
|
||||||
#define TARGET_TIOCSTI 0x5412
|
|
||||||
#define TARGET_TIOCGWINSZ 0x5413
|
|
||||||
#define TARGET_TIOCSWINSZ 0x5414
|
|
||||||
#define TARGET_TIOCMGET 0x5415
|
|
||||||
#define TARGET_TIOCMBIS 0x5416
|
|
||||||
#define TARGET_TIOCMBIC 0x5417
|
|
||||||
#define TARGET_TIOCMSET 0x5418
|
|
||||||
#define TARGET_TIOCGSOFTCAR 0x5419
|
|
||||||
#define TARGET_TIOCSSOFTCAR 0x541A
|
|
||||||
#define TARGET_FIONREAD 0x541B
|
|
||||||
#define TARGET_TIOCINQ FIONREAD
|
|
||||||
#define TARGET_TIOCLINUX 0x541C
|
|
||||||
#define TARGET_TIOCCONS 0x541D
|
|
||||||
#define TARGET_TIOCGSERIAL 0x541E
|
|
||||||
#define TARGET_TIOCSSERIAL 0x541F
|
|
||||||
#define TARGET_TIOCPKT 0x5420
|
|
||||||
#define TARGET_FIONBIO 0x5421
|
|
||||||
#define TARGET_TIOCNOTTY 0x5422
|
|
||||||
#define TARGET_TIOCSETD 0x5423
|
|
||||||
#define TARGET_TIOCGETD 0x5424
|
|
||||||
#define TARGET_TCSBRKP 0x5425 /* Needed for POSIX tcsendbreak() */
|
|
||||||
#define TARGET_TIOCTTYGSTRUCT 0x5426 /* For debugging only */
|
|
||||||
#define TARGET_TIOCSBRK 0x5427 /* BSD compatibility */
|
|
||||||
#define TARGET_TIOCCBRK 0x5428 /* BSD compatibility */
|
|
||||||
#define TARGET_TIOCGSID 0x5429 /* Return the session ID of FD */
|
|
||||||
#define TARGET_TIOCGPTN TARGET_IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */
|
|
||||||
#define TARGET_TIOCSPTLCK TARGET_IOW('T',0x31, int) /* Lock/unlock Pty */
|
|
||||||
|
|
||||||
#define TARGET_FIONCLEX 0x5450 /* these numbers need to be adjusted. */
|
|
||||||
#define TARGET_FIOCLEX 0x5451
|
|
||||||
#define TARGET_FIOASYNC 0x5452
|
|
||||||
#define TARGET_TIOCSERCONFIG 0x5453
|
|
||||||
#define TARGET_TIOCSERGWILD 0x5454
|
|
||||||
#define TARGET_TIOCSERSWILD 0x5455
|
|
||||||
#define TARGET_TIOCGLCKTRMIOS 0x5456
|
|
||||||
#define TARGET_TIOCSLCKTRMIOS 0x5457
|
|
||||||
#define TARGET_TIOCSERGSTRUCT 0x5458 /* For debugging only */
|
|
||||||
#define TARGET_TIOCSERGETLSR 0x5459 /* Get line status register */
|
|
||||||
#define TARGET_TIOCSERGETMULTI 0x545A /* Get multiport config */
|
|
||||||
#define TARGET_TIOCSERSETMULTI 0x545B /* Set multiport config */
|
|
||||||
|
|
||||||
#define TARGET_TIOCMIWAIT 0x545C /* wait for a change on serial input line(s) */
|
|
||||||
#define TARGET_TIOCGICOUNT 0x545D /* read serial port inline interrupt counts */
|
|
||||||
#define TARGET_TIOCGHAYESESP 0x545E /* Get Hayes ESP configuration */
|
|
||||||
#define TARGET_TIOCSHAYESESP 0x545F /* Set Hayes ESP configuration */
|
|
||||||
|
|
||||||
/* Used for packet mode */
|
|
||||||
#define TARGET_TIOCPKT_DATA 0
|
|
||||||
#define TARGET_TIOCPKT_FLUSHREAD 1
|
|
||||||
#define TARGET_TIOCPKT_FLUSHWRITE 2
|
|
||||||
#define TARGET_TIOCPKT_STOP 4
|
|
||||||
#define TARGET_TIOCPKT_START 8
|
|
||||||
#define TARGET_TIOCPKT_NOSTOP 16
|
|
||||||
#define TARGET_TIOCPKT_DOSTOP 32
|
|
||||||
|
|
||||||
#define TARGET_TIOCSER_TEMT 0x01 /* Transmitter physically empty */
|
|
||||||
|
|
||||||
/* from asm/termbits.h */
|
/* from asm/termbits.h */
|
||||||
|
|
||||||
#define TARGET_NCCS 19
|
#define TARGET_NCC 8
|
||||||
|
struct target_termio {
|
||||||
struct target_termios {
|
unsigned short c_iflag; /* input mode flags */
|
||||||
unsigned int c_iflag; /* input mode flags */
|
unsigned short c_oflag; /* output mode flags */
|
||||||
unsigned int c_oflag; /* output mode flags */
|
unsigned short c_cflag; /* control mode flags */
|
||||||
unsigned int c_cflag; /* control mode flags */
|
unsigned short c_lflag; /* local mode flags */
|
||||||
unsigned int c_lflag; /* local mode flags */
|
unsigned char c_line; /* line discipline */
|
||||||
unsigned char c_line; /* line discipline */
|
unsigned char c_cc[TARGET_NCC]; /* control characters */
|
||||||
unsigned char c_cc[TARGET_NCCS]; /* control characters */
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* c_iflag bits */
|
struct target_winsize {
|
||||||
#define TARGET_IGNBRK 0000001
|
unsigned short ws_row;
|
||||||
#define TARGET_BRKINT 0000002
|
unsigned short ws_col;
|
||||||
#define TARGET_IGNPAR 0000004
|
unsigned short ws_xpixel;
|
||||||
#define TARGET_PARMRK 0000010
|
unsigned short ws_ypixel;
|
||||||
#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 */
|
#include "termbits.h"
|
||||||
#define TARGET_OPOST 0000001
|
|
||||||
#define TARGET_OLCUC 0000002
|
|
||||||
#define TARGET_ONLCR 0000004
|
|
||||||
#define TARGET_OCRNL 0000010
|
|
||||||
#define TARGET_ONOCR 0000020
|
|
||||||
#define TARGET_ONLRET 0000040
|
|
||||||
#define TARGET_OFILL 0000100
|
|
||||||
#define TARGET_OFDEL 0000200
|
|
||||||
#define TARGET_NLDLY 0000400
|
|
||||||
#define TARGET_NL0 0000000
|
|
||||||
#define TARGET_NL1 0000400
|
|
||||||
#define TARGET_CRDLY 0003000
|
|
||||||
#define TARGET_CR0 0000000
|
|
||||||
#define TARGET_CR1 0001000
|
|
||||||
#define TARGET_CR2 0002000
|
|
||||||
#define TARGET_CR3 0003000
|
|
||||||
#define TARGET_TABDLY 0014000
|
|
||||||
#define TARGET_TAB0 0000000
|
|
||||||
#define TARGET_TAB1 0004000
|
|
||||||
#define TARGET_TAB2 0010000
|
|
||||||
#define TARGET_TAB3 0014000
|
|
||||||
#define TARGET_XTABS 0014000
|
|
||||||
#define TARGET_BSDLY 0020000
|
|
||||||
#define TARGET_BS0 0000000
|
|
||||||
#define TARGET_BS1 0020000
|
|
||||||
#define TARGET_VTDLY 0040000
|
|
||||||
#define TARGET_VT0 0000000
|
|
||||||
#define TARGET_VT1 0040000
|
|
||||||
#define TARGET_FFDLY 0100000
|
|
||||||
#define TARGET_FF0 0000000
|
|
||||||
#define TARGET_FF1 0100000
|
|
||||||
|
|
||||||
/* c_cflag bit meaning */
|
|
||||||
#define TARGET_CBAUD 0010017
|
|
||||||
#define TARGET_B0 0000000 /* hang up */
|
|
||||||
#define TARGET_B50 0000001
|
|
||||||
#define TARGET_B75 0000002
|
|
||||||
#define TARGET_B110 0000003
|
|
||||||
#define TARGET_B134 0000004
|
|
||||||
#define TARGET_B150 0000005
|
|
||||||
#define TARGET_B200 0000006
|
|
||||||
#define TARGET_B300 0000007
|
|
||||||
#define TARGET_B600 0000010
|
|
||||||
#define TARGET_B1200 0000011
|
|
||||||
#define TARGET_B1800 0000012
|
|
||||||
#define TARGET_B2400 0000013
|
|
||||||
#define TARGET_B4800 0000014
|
|
||||||
#define TARGET_B9600 0000015
|
|
||||||
#define TARGET_B19200 0000016
|
|
||||||
#define TARGET_B38400 0000017
|
|
||||||
#define TARGET_EXTA B19200
|
|
||||||
#define TARGET_EXTB B38400
|
|
||||||
#define TARGET_CSIZE 0000060
|
|
||||||
#define TARGET_CS5 0000000
|
|
||||||
#define TARGET_CS6 0000020
|
|
||||||
#define TARGET_CS7 0000040
|
|
||||||
#define TARGET_CS8 0000060
|
|
||||||
#define TARGET_CSTOPB 0000100
|
|
||||||
#define TARGET_CREAD 0000200
|
|
||||||
#define TARGET_PARENB 0000400
|
|
||||||
#define TARGET_PARODD 0001000
|
|
||||||
#define TARGET_HUPCL 0002000
|
|
||||||
#define TARGET_CLOCAL 0004000
|
|
||||||
#define TARGET_CBAUDEX 0010000
|
|
||||||
#define TARGET_B57600 0010001
|
|
||||||
#define TARGET_B115200 0010002
|
|
||||||
#define TARGET_B230400 0010003
|
|
||||||
#define TARGET_B460800 0010004
|
|
||||||
#define TARGET_CIBAUD 002003600000 /* input baud rate (not used) */
|
|
||||||
#define TARGET_CRTSCTS 020000000000 /* flow control */
|
|
||||||
|
|
||||||
/* c_lflag bits */
|
|
||||||
#define TARGET_ISIG 0000001
|
|
||||||
#define TARGET_ICANON 0000002
|
|
||||||
#define TARGET_XCASE 0000004
|
|
||||||
#define TARGET_ECHO 0000010
|
|
||||||
#define TARGET_ECHOE 0000020
|
|
||||||
#define TARGET_ECHOK 0000040
|
|
||||||
#define TARGET_ECHONL 0000100
|
|
||||||
#define TARGET_NOFLSH 0000200
|
|
||||||
#define TARGET_TOSTOP 0000400
|
|
||||||
#define TARGET_ECHOCTL 0001000
|
|
||||||
#define TARGET_ECHOPRT 0002000
|
|
||||||
#define TARGET_ECHOKE 0004000
|
|
||||||
#define TARGET_FLUSHO 0010000
|
|
||||||
#define TARGET_PENDIN 0040000
|
|
||||||
#define TARGET_IEXTEN 0100000
|
|
||||||
|
|
||||||
/* c_cc character offsets */
|
|
||||||
#define TARGET_VINTR 0
|
|
||||||
#define TARGET_VQUIT 1
|
|
||||||
#define TARGET_VERASE 2
|
|
||||||
#define TARGET_VKILL 3
|
|
||||||
#define TARGET_VEOF 4
|
|
||||||
#define TARGET_VTIME 5
|
|
||||||
#define TARGET_VMIN 6
|
|
||||||
#define TARGET_VSWTC 7
|
|
||||||
#define TARGET_VSTART 8
|
|
||||||
#define TARGET_VSTOP 9
|
|
||||||
#define TARGET_VSUSP 10
|
|
||||||
#define TARGET_VEOL 11
|
|
||||||
#define TARGET_VREPRINT 12
|
|
||||||
#define TARGET_VDISCARD 13
|
|
||||||
#define TARGET_VWERASE 14
|
|
||||||
#define TARGET_VLNEXT 15
|
|
||||||
#define TARGET_VEOL2 16
|
|
||||||
|
|
||||||
#define TARGET_MAP_SHARED 0x01 /* Share changes */
|
#define TARGET_MAP_SHARED 0x01 /* Share changes */
|
||||||
#define TARGET_MAP_PRIVATE 0x02 /* Changes are private */
|
#define TARGET_MAP_PRIVATE 0x02 /* Changes are private */
|
||||||
@@ -891,6 +724,7 @@ struct target_termios {
|
|||||||
#define TARGET_MAP_LOCKED 0x2000 /* pages are locked */
|
#define TARGET_MAP_LOCKED 0x2000 /* pages are locked */
|
||||||
#define TARGET_MAP_NORESERVE 0x4000 /* don't check for reservations */
|
#define TARGET_MAP_NORESERVE 0x4000 /* don't check for reservations */
|
||||||
|
|
||||||
|
#if defined(TARGET_I386) || defined(TARGET_ARM)
|
||||||
struct target_stat {
|
struct target_stat {
|
||||||
unsigned short st_dev;
|
unsigned short st_dev;
|
||||||
unsigned short __pad1;
|
unsigned short __pad1;
|
||||||
@@ -951,7 +785,111 @@ struct target_stat64 {
|
|||||||
unsigned long long st_ino;
|
unsigned long long st_ino;
|
||||||
} __attribute__((packed));
|
} __attribute__((packed));
|
||||||
|
|
||||||
#endif /* defined(TARGET_I386) || defined(TARGET_ARM) */
|
#elif defined(TARGET_SPARC)
|
||||||
|
|
||||||
|
struct target_stat {
|
||||||
|
unsigned short st_dev;
|
||||||
|
target_ulong st_ino;
|
||||||
|
unsigned short st_mode;
|
||||||
|
short st_nlink;
|
||||||
|
unsigned short st_uid;
|
||||||
|
unsigned short st_gid;
|
||||||
|
unsigned short st_rdev;
|
||||||
|
target_long st_size;
|
||||||
|
target_long target_st_atime;
|
||||||
|
target_ulong __unused1;
|
||||||
|
target_long target_st_mtime;
|
||||||
|
target_ulong __unused2;
|
||||||
|
target_long target_st_ctime;
|
||||||
|
target_ulong __unused3;
|
||||||
|
target_long st_blksize;
|
||||||
|
target_long st_blocks;
|
||||||
|
target_ulong __unused4[2];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct target_stat64 {
|
||||||
|
unsigned char __pad0[6];
|
||||||
|
unsigned short st_dev;
|
||||||
|
|
||||||
|
uint64_t st_ino;
|
||||||
|
|
||||||
|
unsigned int st_mode;
|
||||||
|
unsigned int st_nlink;
|
||||||
|
|
||||||
|
unsigned int st_uid;
|
||||||
|
unsigned int st_gid;
|
||||||
|
|
||||||
|
unsigned char __pad2[6];
|
||||||
|
unsigned short st_rdev;
|
||||||
|
|
||||||
|
unsigned char __pad3[8];
|
||||||
|
|
||||||
|
int64_t st_size;
|
||||||
|
unsigned int st_blksize;
|
||||||
|
|
||||||
|
unsigned char __pad4[8];
|
||||||
|
unsigned int st_blocks;
|
||||||
|
|
||||||
|
unsigned int target_st_atime;
|
||||||
|
unsigned int __unused1;
|
||||||
|
|
||||||
|
unsigned int target_st_mtime;
|
||||||
|
unsigned int __unused2;
|
||||||
|
|
||||||
|
unsigned int target_st_ctime;
|
||||||
|
unsigned int __unused3;
|
||||||
|
|
||||||
|
unsigned int __unused4;
|
||||||
|
unsigned int __unused5;
|
||||||
|
};
|
||||||
|
|
||||||
|
#elif defined(TARGET_PPC)
|
||||||
|
|
||||||
|
struct target_stat {
|
||||||
|
unsigned short st_dev;
|
||||||
|
target_ulong st_ino;
|
||||||
|
unsigned int st_mode;
|
||||||
|
unsigned short st_nlink;
|
||||||
|
unsigned int st_uid;
|
||||||
|
unsigned int st_gid;
|
||||||
|
unsigned short st_rdev;
|
||||||
|
target_ulong st_size;
|
||||||
|
target_ulong st_blksize;
|
||||||
|
target_ulong st_blocks;
|
||||||
|
target_ulong target_st_atime;
|
||||||
|
target_ulong __unused1;
|
||||||
|
target_ulong target_st_mtime;
|
||||||
|
target_ulong __unused2;
|
||||||
|
target_ulong target_st_ctime;
|
||||||
|
target_ulong __unused3;
|
||||||
|
target_ulong __unused4;
|
||||||
|
target_ulong __unused5;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct target_stat64 {
|
||||||
|
unsigned long long st_dev;
|
||||||
|
unsigned long long st_ino;
|
||||||
|
unsigned int st_mode;
|
||||||
|
unsigned int st_nlink;
|
||||||
|
unsigned int st_uid;
|
||||||
|
unsigned int st_gid;
|
||||||
|
unsigned long long st_rdev;
|
||||||
|
long long pad0;
|
||||||
|
long long st_size;
|
||||||
|
target_ulong st_blksize;
|
||||||
|
target_ulong pad1;
|
||||||
|
long long st_blocks; /* Number 512-byte blocks allocated. */
|
||||||
|
target_ulong target_st_atime;
|
||||||
|
target_ulong target_st_atime_nsec;
|
||||||
|
target_ulong target_st_mtime;
|
||||||
|
target_ulong target_st_mtime_nsec;
|
||||||
|
target_ulong target_st_ctime;
|
||||||
|
target_ulong target_st_ctime_nsec;
|
||||||
|
target_ulong __unused4;
|
||||||
|
target_ulong __unused5;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* defined(TARGET_PPC) */
|
||||||
|
|
||||||
#define TARGET_F_DUPFD 0 /* dup */
|
#define TARGET_F_DUPFD 0 /* dup */
|
||||||
#define TARGET_F_GETFD 1 /* get close_on_exec */
|
#define TARGET_F_GETFD 1 /* get close_on_exec */
|
||||||
@@ -980,6 +918,62 @@ struct target_stat64 {
|
|||||||
#define TARGET_F_SETLK64 13
|
#define TARGET_F_SETLK64 13
|
||||||
#define TARGET_F_SETLKW64 14
|
#define TARGET_F_SETLKW64 14
|
||||||
|
|
||||||
|
#if defined (TARGET_ARM)
|
||||||
|
#define TARGET_O_ACCMODE 0003
|
||||||
|
#define TARGET_O_RDONLY 00
|
||||||
|
#define TARGET_O_WRONLY 01
|
||||||
|
#define TARGET_O_RDWR 02
|
||||||
|
#define TARGET_O_CREAT 0100 /* not fcntl */
|
||||||
|
#define TARGET_O_EXCL 0200 /* not fcntl */
|
||||||
|
#define TARGET_O_NOCTTY 0400 /* not fcntl */
|
||||||
|
#define TARGET_O_TRUNC 01000 /* not fcntl */
|
||||||
|
#define TARGET_O_APPEND 02000
|
||||||
|
#define TARGET_O_NONBLOCK 04000
|
||||||
|
#define TARGET_O_NDELAY O_NONBLOCK
|
||||||
|
#define TARGET_O_SYNC 010000
|
||||||
|
#define TARGET_FASYNC 020000 /* fcntl, for BSD compatibility */
|
||||||
|
#define TARGET_O_DIRECTORY 040000 /* must be a directory */
|
||||||
|
#define TARGET_O_NOFOLLOW 0100000 /* don't follow links */
|
||||||
|
#define TARGET_O_DIRECT 0200000 /* direct disk access hint */
|
||||||
|
#define TARGET_O_LARGEFILE 0400000
|
||||||
|
#elif defined (TARGET_PPC)
|
||||||
|
#define TARGET_O_ACCMODE 0003
|
||||||
|
#define TARGET_O_RDONLY 00
|
||||||
|
#define TARGET_O_WRONLY 01
|
||||||
|
#define TARGET_O_RDWR 02
|
||||||
|
#define TARGET_O_CREAT 0100 /* not fcntl */
|
||||||
|
#define TARGET_O_EXCL 0200 /* not fcntl */
|
||||||
|
#define TARGET_O_NOCTTY 0400 /* not fcntl */
|
||||||
|
#define TARGET_O_TRUNC 01000 /* not fcntl */
|
||||||
|
#define TARGET_O_APPEND 02000
|
||||||
|
#define TARGET_O_NONBLOCK 04000
|
||||||
|
#define TARGET_O_NDELAY O_NONBLOCK
|
||||||
|
#define TARGET_O_SYNC 010000
|
||||||
|
#define TARGET_FASYNC 020000 /* fcntl, for BSD compatibility */
|
||||||
|
#define TARGET_O_DIRECTORY 040000 /* must be a directory */
|
||||||
|
#define TARGET_O_NOFOLLOW 0100000 /* don't follow links */
|
||||||
|
#define TARGET_O_LARGEFILE 0200000
|
||||||
|
#define TARGET_O_DIRECT 0400000 /* direct disk access hint */
|
||||||
|
#else
|
||||||
|
#define TARGET_O_ACCMODE 0003
|
||||||
|
#define TARGET_O_RDONLY 00
|
||||||
|
#define TARGET_O_WRONLY 01
|
||||||
|
#define TARGET_O_RDWR 02
|
||||||
|
#define TARGET_O_CREAT 0100 /* not fcntl */
|
||||||
|
#define TARGET_O_EXCL 0200 /* not fcntl */
|
||||||
|
#define TARGET_O_NOCTTY 0400 /* not fcntl */
|
||||||
|
#define TARGET_O_TRUNC 01000 /* not fcntl */
|
||||||
|
#define TARGET_O_APPEND 02000
|
||||||
|
#define TARGET_O_NONBLOCK 04000
|
||||||
|
#define TARGET_O_NDELAY O_NONBLOCK
|
||||||
|
#define TARGET_O_SYNC 010000
|
||||||
|
#define TARGET_FASYNC 020000 /* fcntl, for BSD compatibility */
|
||||||
|
#define TARGET_O_DIRECT 040000 /* direct disk access hint */
|
||||||
|
#define TARGET_O_LARGEFILE 0100000
|
||||||
|
#define TARGET_O_DIRECTORY 0200000 /* must be a directory */
|
||||||
|
#define TARGET_O_NOFOLLOW 0400000 /* don't follow links */
|
||||||
|
#endif
|
||||||
|
|
||||||
struct target_flock {
|
struct target_flock {
|
||||||
short l_type;
|
short l_type;
|
||||||
short l_whence;
|
short l_whence;
|
||||||
@@ -1139,3 +1133,20 @@ struct target_flock64 {
|
|||||||
/* vfat ioctls */
|
/* vfat ioctls */
|
||||||
#define TARGET_VFAT_IOCTL_READDIR_BOTH TARGET_IORU('r', 1)
|
#define TARGET_VFAT_IOCTL_READDIR_BOTH TARGET_IORU('r', 1)
|
||||||
#define TARGET_VFAT_IOCTL_READDIR_SHORT TARGET_IORU('r', 2)
|
#define TARGET_VFAT_IOCTL_READDIR_SHORT TARGET_IORU('r', 2)
|
||||||
|
|
||||||
|
struct target_sysinfo {
|
||||||
|
target_long uptime; /* Seconds since boot */
|
||||||
|
target_ulong loads[3]; /* 1, 5, and 15 minute load averages */
|
||||||
|
target_ulong totalram; /* Total usable main memory size */
|
||||||
|
target_ulong freeram; /* Available memory size */
|
||||||
|
target_ulong sharedram; /* Amount of shared memory */
|
||||||
|
target_ulong bufferram; /* Memory used by buffers */
|
||||||
|
target_ulong totalswap; /* Total swap space size */
|
||||||
|
target_ulong freeswap; /* swap space still available */
|
||||||
|
unsigned short procs; /* Number of current processes */
|
||||||
|
unsigned short pad; /* explicit padding for m68k */
|
||||||
|
target_ulong totalhigh; /* Total high memory size */
|
||||||
|
target_ulong freehigh; /* Available high memory size */
|
||||||
|
unsigned int mem_unit; /* Memory unit size in bytes */
|
||||||
|
char _f[20-2*sizeof(target_long)-sizeof(int)]; /* Padding: libc5 uses this.. */
|
||||||
|
};
|
||||||
@@ -0,0 +1,473 @@
|
|||||||
|
/*
|
||||||
|
* QEMU low level functions
|
||||||
|
*
|
||||||
|
* Copyright (c) 2003 Fabrice Bellard
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "cpu.h"
|
||||||
|
|
||||||
|
#if defined(__i386__) && !defined(CONFIG_SOFTMMU) && !defined(CONFIG_USER_ONLY)
|
||||||
|
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <sys/ipc.h>
|
||||||
|
|
||||||
|
/* When not using soft mmu, libc independant functions are needed for
|
||||||
|
the CPU core because it needs to use alternates stacks and
|
||||||
|
libc/thread incompatibles settings */
|
||||||
|
|
||||||
|
#include <linux/unistd.h>
|
||||||
|
|
||||||
|
#define QEMU_SYSCALL0(name) \
|
||||||
|
{ \
|
||||||
|
long __res; \
|
||||||
|
__asm__ volatile ("int $0x80" \
|
||||||
|
: "=a" (__res) \
|
||||||
|
: "0" (__NR_##name)); \
|
||||||
|
return __res; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define QEMU_SYSCALL1(name,arg1) \
|
||||||
|
{ \
|
||||||
|
long __res; \
|
||||||
|
__asm__ volatile ("int $0x80" \
|
||||||
|
: "=a" (__res) \
|
||||||
|
: "0" (__NR_##name),"b" ((long)(arg1))); \
|
||||||
|
return __res; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define QEMU_SYSCALL2(name,arg1,arg2) \
|
||||||
|
{ \
|
||||||
|
long __res; \
|
||||||
|
__asm__ volatile ("int $0x80" \
|
||||||
|
: "=a" (__res) \
|
||||||
|
: "0" (__NR_##name),"b" ((long)(arg1)),"c" ((long)(arg2))); \
|
||||||
|
return __res; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define QEMU_SYSCALL3(name,arg1,arg2,arg3) \
|
||||||
|
{ \
|
||||||
|
long __res; \
|
||||||
|
__asm__ volatile ("int $0x80" \
|
||||||
|
: "=a" (__res) \
|
||||||
|
: "0" (__NR_##name),"b" ((long)(arg1)),"c" ((long)(arg2)), \
|
||||||
|
"d" ((long)(arg3))); \
|
||||||
|
return __res; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define QEMU_SYSCALL4(name,arg1,arg2,arg3,arg4) \
|
||||||
|
{ \
|
||||||
|
long __res; \
|
||||||
|
__asm__ volatile ("int $0x80" \
|
||||||
|
: "=a" (__res) \
|
||||||
|
: "0" (__NR_##name),"b" ((long)(arg1)),"c" ((long)(arg2)), \
|
||||||
|
"d" ((long)(arg3)),"S" ((long)(arg4))); \
|
||||||
|
return __res; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define QEMU_SYSCALL5(name,arg1,arg2,arg3,arg4,arg5) \
|
||||||
|
{ \
|
||||||
|
long __res; \
|
||||||
|
__asm__ volatile ("int $0x80" \
|
||||||
|
: "=a" (__res) \
|
||||||
|
: "0" (__NR_##name),"b" ((long)(arg1)),"c" ((long)(arg2)), \
|
||||||
|
"d" ((long)(arg3)),"S" ((long)(arg4)),"D" ((long)(arg5))); \
|
||||||
|
return __res; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define QEMU_SYSCALL6(name,arg1,arg2,arg3,arg4,arg5,arg6) \
|
||||||
|
{ \
|
||||||
|
long __res; \
|
||||||
|
__asm__ volatile ("push %%ebp ; movl %%eax,%%ebp ; movl %1,%%eax ; int $0x80 ; pop %%ebp" \
|
||||||
|
: "=a" (__res) \
|
||||||
|
: "i" (__NR_##name),"b" ((long)(arg1)),"c" ((long)(arg2)), \
|
||||||
|
"d" ((long)(arg3)),"S" ((long)(arg4)),"D" ((long)(arg5)), \
|
||||||
|
"0" ((long)(arg6))); \
|
||||||
|
return __res; \
|
||||||
|
}
|
||||||
|
|
||||||
|
int qemu_write(int fd, const void *buf, size_t n)
|
||||||
|
{
|
||||||
|
QEMU_SYSCALL3(write, fd, buf, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/****************************************************************/
|
||||||
|
/* shmat replacement */
|
||||||
|
|
||||||
|
int qemu_ipc(int call, unsigned long first,
|
||||||
|
unsigned long second, unsigned long third,
|
||||||
|
void *ptr, unsigned long fifth)
|
||||||
|
{
|
||||||
|
QEMU_SYSCALL6(ipc, call, first, second, third, ptr, fifth);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define SHMAT 21
|
||||||
|
|
||||||
|
/* we must define shmat so that a specific address will be used when
|
||||||
|
mapping the X11 ximage */
|
||||||
|
void *shmat(int shmid, const void *shmaddr, int shmflg)
|
||||||
|
{
|
||||||
|
void *ptr;
|
||||||
|
int ret;
|
||||||
|
/* we give an address in the right memory area */
|
||||||
|
if (!shmaddr)
|
||||||
|
shmaddr = get_mmap_addr(8192 * 1024);
|
||||||
|
ret = qemu_ipc(SHMAT, shmid, shmflg, (unsigned long)&ptr, (void *)shmaddr, 0);
|
||||||
|
if (ret < 0)
|
||||||
|
return NULL;
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************/
|
||||||
|
/* memory allocation */
|
||||||
|
|
||||||
|
//#define DEBUG_MALLOC
|
||||||
|
|
||||||
|
#define MALLOC_BASE 0xab000000
|
||||||
|
#define PHYS_RAM_BASE 0xac000000
|
||||||
|
|
||||||
|
#define MALLOC_ALIGN 16
|
||||||
|
#define BLOCK_HEADER_SIZE 16
|
||||||
|
|
||||||
|
typedef struct MemoryBlock {
|
||||||
|
struct MemoryBlock *next;
|
||||||
|
unsigned long size; /* size of block, including header */
|
||||||
|
} MemoryBlock;
|
||||||
|
|
||||||
|
static MemoryBlock *first_free_block;
|
||||||
|
static unsigned long malloc_addr = MALLOC_BASE;
|
||||||
|
|
||||||
|
static void *malloc_get_space(size_t size)
|
||||||
|
{
|
||||||
|
void *ptr;
|
||||||
|
size = TARGET_PAGE_ALIGN(size);
|
||||||
|
ptr = mmap((void *)malloc_addr, size,
|
||||||
|
PROT_WRITE | PROT_READ,
|
||||||
|
MAP_PRIVATE | MAP_FIXED | MAP_ANON, -1, 0);
|
||||||
|
if (ptr == MAP_FAILED)
|
||||||
|
return NULL;
|
||||||
|
malloc_addr += size;
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *qemu_malloc(size_t size)
|
||||||
|
{
|
||||||
|
MemoryBlock *mb, *mb1, **pmb;
|
||||||
|
void *ptr;
|
||||||
|
size_t size1, area_size;
|
||||||
|
|
||||||
|
if (size == 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
size = (size + BLOCK_HEADER_SIZE + MALLOC_ALIGN - 1) & ~(MALLOC_ALIGN - 1);
|
||||||
|
pmb = &first_free_block;
|
||||||
|
for(;;) {
|
||||||
|
mb = *pmb;
|
||||||
|
if (mb == NULL)
|
||||||
|
break;
|
||||||
|
if (size <= mb->size)
|
||||||
|
goto found;
|
||||||
|
pmb = &mb->next;
|
||||||
|
}
|
||||||
|
/* no big enough blocks found: get new space */
|
||||||
|
area_size = TARGET_PAGE_ALIGN(size);
|
||||||
|
mb = malloc_get_space(area_size);
|
||||||
|
if (!mb)
|
||||||
|
return NULL;
|
||||||
|
size1 = area_size - size;
|
||||||
|
if (size1 > 0) {
|
||||||
|
/* create a new free block */
|
||||||
|
mb1 = (MemoryBlock *)((uint8_t *)mb + size);
|
||||||
|
mb1->next = NULL;
|
||||||
|
mb1->size = size1;
|
||||||
|
*pmb = mb1;
|
||||||
|
}
|
||||||
|
goto the_end;
|
||||||
|
found:
|
||||||
|
/* a free block was found: use it */
|
||||||
|
size1 = mb->size - size;
|
||||||
|
if (size1 > 0) {
|
||||||
|
/* create a new free block */
|
||||||
|
mb1 = (MemoryBlock *)((uint8_t *)mb + size);
|
||||||
|
mb1->next = mb->next;
|
||||||
|
mb1->size = size1;
|
||||||
|
*pmb = mb1;
|
||||||
|
} else {
|
||||||
|
/* suppress the first block */
|
||||||
|
*pmb = mb->next;
|
||||||
|
}
|
||||||
|
the_end:
|
||||||
|
mb->size = size;
|
||||||
|
mb->next = NULL;
|
||||||
|
ptr = ((uint8_t *)mb + BLOCK_HEADER_SIZE);
|
||||||
|
#ifdef DEBUG_MALLOC
|
||||||
|
qemu_printf("malloc: size=0x%x ptr=0x%lx\n", size, (unsigned long)ptr);
|
||||||
|
#endif
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void qemu_free(void *ptr)
|
||||||
|
{
|
||||||
|
MemoryBlock *mb;
|
||||||
|
|
||||||
|
if (!ptr)
|
||||||
|
return;
|
||||||
|
mb = (MemoryBlock *)((uint8_t *)ptr - BLOCK_HEADER_SIZE);
|
||||||
|
mb->next = first_free_block;
|
||||||
|
first_free_block = mb;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************/
|
||||||
|
/* virtual memory allocation */
|
||||||
|
|
||||||
|
unsigned long mmap_addr = PHYS_RAM_BASE;
|
||||||
|
|
||||||
|
void *get_mmap_addr(unsigned long size)
|
||||||
|
{
|
||||||
|
unsigned long addr;
|
||||||
|
addr = mmap_addr;
|
||||||
|
mmap_addr += ((size + 4095) & ~4095) + 4096;
|
||||||
|
return (void *)addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
int qemu_write(int fd, const void *buf, size_t n)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
ret = write(fd, buf, n);
|
||||||
|
if (ret < 0)
|
||||||
|
return -errno;
|
||||||
|
else
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *get_mmap_addr(unsigned long size)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void qemu_free(void *ptr)
|
||||||
|
{
|
||||||
|
free(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void *qemu_malloc(size_t size)
|
||||||
|
{
|
||||||
|
return malloc(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void *qemu_mallocz(size_t size)
|
||||||
|
{
|
||||||
|
void *ptr;
|
||||||
|
ptr = qemu_malloc(size);
|
||||||
|
if (!ptr)
|
||||||
|
return NULL;
|
||||||
|
memset(ptr, 0, size);
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************/
|
||||||
|
/* printf support */
|
||||||
|
|
||||||
|
static inline int qemu_isdigit(int c)
|
||||||
|
{
|
||||||
|
return c >= '0' && c <= '9';
|
||||||
|
}
|
||||||
|
|
||||||
|
#define OUTCHAR(c) (buflen > 0? (--buflen, *buf++ = (c)): 0)
|
||||||
|
|
||||||
|
/* from BSD ppp sources */
|
||||||
|
int qemu_vsnprintf(char *buf, int buflen, const char *fmt, va_list args)
|
||||||
|
{
|
||||||
|
int c, i, n;
|
||||||
|
int width, prec, fillch;
|
||||||
|
int base, len, neg;
|
||||||
|
unsigned long val = 0;
|
||||||
|
const char *f;
|
||||||
|
char *str, *buf0;
|
||||||
|
char num[32];
|
||||||
|
static const char hexchars[] = "0123456789abcdef";
|
||||||
|
|
||||||
|
buf0 = buf;
|
||||||
|
--buflen;
|
||||||
|
while (buflen > 0) {
|
||||||
|
for (f = fmt; *f != '%' && *f != 0; ++f)
|
||||||
|
;
|
||||||
|
if (f > fmt) {
|
||||||
|
len = f - fmt;
|
||||||
|
if (len > buflen)
|
||||||
|
len = buflen;
|
||||||
|
memcpy(buf, fmt, len);
|
||||||
|
buf += len;
|
||||||
|
buflen -= len;
|
||||||
|
fmt = f;
|
||||||
|
}
|
||||||
|
if (*fmt == 0)
|
||||||
|
break;
|
||||||
|
c = *++fmt;
|
||||||
|
width = prec = 0;
|
||||||
|
fillch = ' ';
|
||||||
|
if (c == '0') {
|
||||||
|
fillch = '0';
|
||||||
|
c = *++fmt;
|
||||||
|
}
|
||||||
|
if (c == '*') {
|
||||||
|
width = va_arg(args, int);
|
||||||
|
c = *++fmt;
|
||||||
|
} else {
|
||||||
|
while (qemu_isdigit(c)) {
|
||||||
|
width = width * 10 + c - '0';
|
||||||
|
c = *++fmt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (c == '.') {
|
||||||
|
c = *++fmt;
|
||||||
|
if (c == '*') {
|
||||||
|
prec = va_arg(args, int);
|
||||||
|
c = *++fmt;
|
||||||
|
} else {
|
||||||
|
while (qemu_isdigit(c)) {
|
||||||
|
prec = prec * 10 + c - '0';
|
||||||
|
c = *++fmt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* modifiers */
|
||||||
|
switch(c) {
|
||||||
|
case 'l':
|
||||||
|
c = *++fmt;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
str = 0;
|
||||||
|
base = 0;
|
||||||
|
neg = 0;
|
||||||
|
++fmt;
|
||||||
|
switch (c) {
|
||||||
|
case 'd':
|
||||||
|
i = va_arg(args, int);
|
||||||
|
if (i < 0) {
|
||||||
|
neg = 1;
|
||||||
|
val = -i;
|
||||||
|
} else
|
||||||
|
val = i;
|
||||||
|
base = 10;
|
||||||
|
break;
|
||||||
|
case 'o':
|
||||||
|
val = va_arg(args, unsigned int);
|
||||||
|
base = 8;
|
||||||
|
break;
|
||||||
|
case 'x':
|
||||||
|
case 'X':
|
||||||
|
val = va_arg(args, unsigned int);
|
||||||
|
base = 16;
|
||||||
|
break;
|
||||||
|
case 'p':
|
||||||
|
val = (unsigned long) va_arg(args, void *);
|
||||||
|
base = 16;
|
||||||
|
neg = 2;
|
||||||
|
break;
|
||||||
|
case 's':
|
||||||
|
str = va_arg(args, char *);
|
||||||
|
break;
|
||||||
|
case 'c':
|
||||||
|
num[0] = va_arg(args, int);
|
||||||
|
num[1] = 0;
|
||||||
|
str = num;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
*buf++ = '%';
|
||||||
|
if (c != '%')
|
||||||
|
--fmt; /* so %z outputs %z etc. */
|
||||||
|
--buflen;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (base != 0) {
|
||||||
|
str = num + sizeof(num);
|
||||||
|
*--str = 0;
|
||||||
|
while (str > num + neg) {
|
||||||
|
*--str = hexchars[val % base];
|
||||||
|
val = val / base;
|
||||||
|
if (--prec <= 0 && val == 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
switch (neg) {
|
||||||
|
case 1:
|
||||||
|
*--str = '-';
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
*--str = 'x';
|
||||||
|
*--str = '0';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
len = num + sizeof(num) - 1 - str;
|
||||||
|
} else {
|
||||||
|
len = strlen(str);
|
||||||
|
if (prec > 0 && len > prec)
|
||||||
|
len = prec;
|
||||||
|
}
|
||||||
|
if (width > 0) {
|
||||||
|
if (width > buflen)
|
||||||
|
width = buflen;
|
||||||
|
if ((n = width - len) > 0) {
|
||||||
|
buflen -= n;
|
||||||
|
for (; n > 0; --n)
|
||||||
|
*buf++ = fillch;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (len > buflen)
|
||||||
|
len = buflen;
|
||||||
|
memcpy(buf, str, len);
|
||||||
|
buf += len;
|
||||||
|
buflen -= len;
|
||||||
|
}
|
||||||
|
*buf = 0;
|
||||||
|
return buf - buf0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void qemu_vprintf(const char *fmt, va_list ap)
|
||||||
|
{
|
||||||
|
char buf[1024];
|
||||||
|
int len;
|
||||||
|
|
||||||
|
len = qemu_vsnprintf(buf, sizeof(buf), fmt, ap);
|
||||||
|
qemu_write(1, buf, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
void qemu_printf(const char *fmt, ...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
va_start(ap, fmt);
|
||||||
|
qemu_vprintf(fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
#ifndef QEMU_OSDEP_H
|
||||||
|
#define QEMU_OSDEP_H
|
||||||
|
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
int qemu_vsnprintf(char *buf, int buflen, const char *fmt, va_list args);
|
||||||
|
void qemu_vprintf(const char *fmt, va_list ap);
|
||||||
|
void qemu_printf(const char *fmt, ...);
|
||||||
|
|
||||||
|
void *qemu_malloc(size_t size);
|
||||||
|
void *qemu_mallocz(size_t size);
|
||||||
|
void qemu_free(void *ptr);
|
||||||
|
|
||||||
|
void *get_mmap_addr(unsigned long size);
|
||||||
|
|
||||||
|
/* specific kludges for OS compatibility (should be moved elsewhere) */
|
||||||
|
#if defined(__i386__) && !defined(CONFIG_SOFTMMU) && !defined(CONFIG_USER_ONLY)
|
||||||
|
|
||||||
|
/* disabled pthread version of longjmp which prevent us from using an
|
||||||
|
alternative signal stack */
|
||||||
|
extern void __longjmp(jmp_buf env, int val);
|
||||||
|
#define longjmp __longjmp
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,597 @@
|
|||||||
|
/*
|
||||||
|
* QEMU OSS Audio output driver
|
||||||
|
*
|
||||||
|
* Copyright (c) 2003 Vassili Karpov (malc)
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#include "vl.h"
|
||||||
|
|
||||||
|
#if !defined(_WIN32) && !defined(__APPLE__)
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <sys/soundcard.h>
|
||||||
|
|
||||||
|
|
||||||
|
/* http://www.df.lth.se/~john_e/gems/gem002d.html */
|
||||||
|
/* http://www.multi-platforms.com/Tips/PopCount.htm */
|
||||||
|
static inline uint32_t popcount (uint32_t u)
|
||||||
|
{
|
||||||
|
u = ((u&0x55555555) + ((u>>1)&0x55555555));
|
||||||
|
u = ((u&0x33333333) + ((u>>2)&0x33333333));
|
||||||
|
u = ((u&0x0f0f0f0f) + ((u>>4)&0x0f0f0f0f));
|
||||||
|
u = ((u&0x00ff00ff) + ((u>>8)&0x00ff00ff));
|
||||||
|
u = ( u&0x0000ffff) + (u>>16);
|
||||||
|
return u;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint32_t lsbindex (uint32_t u)
|
||||||
|
{
|
||||||
|
return popcount ((u&-u)-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define MIN(a, b) ((a)>(b)?(b):(a))
|
||||||
|
#define MAX(a, b) ((a)<(b)?(b):(a))
|
||||||
|
|
||||||
|
#define DEREF(x) (void)x
|
||||||
|
#define log(...) fprintf (stderr, "oss: " __VA_ARGS__)
|
||||||
|
#define ERRFail(...) do { \
|
||||||
|
int _errno = errno; \
|
||||||
|
fprintf (stderr, "oss: " __VA_ARGS__); \
|
||||||
|
fprintf (stderr, "system error: %s\n", strerror (_errno)); \
|
||||||
|
abort (); \
|
||||||
|
} while (0)
|
||||||
|
#define Fail(...) do { \
|
||||||
|
fprintf (stderr, "oss: " __VA_ARGS__); \
|
||||||
|
fprintf (stderr, "\n"); \
|
||||||
|
abort (); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#ifdef DEBUG_OSS
|
||||||
|
#define lwarn(...) fprintf (stderr, "oss: " __VA_ARGS__)
|
||||||
|
#define linfo(...) fprintf (stderr, "oss: " __VA_ARGS__)
|
||||||
|
#define ldebug(...) fprintf (stderr, "oss: " __VA_ARGS__)
|
||||||
|
#else
|
||||||
|
#define lwarn(...)
|
||||||
|
#define linfo(...)
|
||||||
|
#define ldebug(...)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#define IOCTL(args) do { \
|
||||||
|
int ret = ioctl args; \
|
||||||
|
if (-1 == ret) { \
|
||||||
|
ERRFail (#args); \
|
||||||
|
} \
|
||||||
|
ldebug ("ioctl " #args " = %d\n", ret); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
static struct {
|
||||||
|
int fd;
|
||||||
|
int freq;
|
||||||
|
int bits16;
|
||||||
|
int nchannels;
|
||||||
|
int rpos;
|
||||||
|
int wpos;
|
||||||
|
int live;
|
||||||
|
int oss_fmt;
|
||||||
|
int bytes_per_second;
|
||||||
|
int is_mapped;
|
||||||
|
void *buf;
|
||||||
|
int bufsize;
|
||||||
|
int nfrags;
|
||||||
|
int fragsize;
|
||||||
|
int old_optr;
|
||||||
|
int leftover;
|
||||||
|
uint64_t old_ticks;
|
||||||
|
void (*copy_fn)(void *, void *, int);
|
||||||
|
} oss = { .fd = -1 };
|
||||||
|
|
||||||
|
static struct {
|
||||||
|
int try_mmap;
|
||||||
|
int nfrags;
|
||||||
|
int fragsize;
|
||||||
|
} conf = {
|
||||||
|
.try_mmap = 0,
|
||||||
|
.nfrags = 4,
|
||||||
|
.fragsize = 4096
|
||||||
|
};
|
||||||
|
|
||||||
|
static enum {DONT, DSP, TID} est = DONT;
|
||||||
|
|
||||||
|
static void copy_no_conversion (void *dst, void *src, int size)
|
||||||
|
{
|
||||||
|
memcpy (dst, src, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void copy_u16_to_s16 (void *dst, void *src, int size)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
uint16_t *out, *in;
|
||||||
|
|
||||||
|
out = dst;
|
||||||
|
in = src;
|
||||||
|
|
||||||
|
for (i = 0; i < size / 2; i++) {
|
||||||
|
out[i] = in[i] + 0x8000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pab (struct audio_buf_info *abinfo)
|
||||||
|
{
|
||||||
|
DEREF (abinfo);
|
||||||
|
|
||||||
|
ldebug ("fragments %d, fragstotal %d, fragsize %d, bytes %d\n"
|
||||||
|
"rpos %d, wpos %d, live %d\n",
|
||||||
|
abinfo->fragments,
|
||||||
|
abinfo->fragstotal,
|
||||||
|
abinfo->fragsize,
|
||||||
|
abinfo->bytes,
|
||||||
|
rpos, wpos, live);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void do_open ()
|
||||||
|
{
|
||||||
|
int mmmmssss;
|
||||||
|
audio_buf_info abinfo;
|
||||||
|
int fmt, freq, nchannels;
|
||||||
|
|
||||||
|
if (oss.buf) {
|
||||||
|
if (-1 == munmap (oss.buf, oss.bufsize)) {
|
||||||
|
ERRFail ("failed to unmap audio buffer %p %d",
|
||||||
|
oss.buf, oss.bufsize);
|
||||||
|
}
|
||||||
|
oss.buf = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (-1 != oss.fd)
|
||||||
|
close (oss.fd);
|
||||||
|
|
||||||
|
oss.fd = open ("/dev/dsp", O_RDWR | O_NONBLOCK);
|
||||||
|
if (-1 == oss.fd) {
|
||||||
|
ERRFail ("can not open /dev/dsp");
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt = oss.oss_fmt;
|
||||||
|
freq = oss.freq;
|
||||||
|
nchannels = oss.nchannels;
|
||||||
|
|
||||||
|
IOCTL ((oss.fd, SNDCTL_DSP_RESET, 1));
|
||||||
|
IOCTL ((oss.fd, SNDCTL_DSP_SAMPLESIZE, &fmt));
|
||||||
|
IOCTL ((oss.fd, SNDCTL_DSP_CHANNELS, &nchannels));
|
||||||
|
IOCTL ((oss.fd, SNDCTL_DSP_SPEED, &freq));
|
||||||
|
IOCTL ((oss.fd, SNDCTL_DSP_NONBLOCK));
|
||||||
|
|
||||||
|
mmmmssss = (conf.nfrags << 16) | conf.fragsize;
|
||||||
|
IOCTL ((oss.fd, SNDCTL_DSP_SETFRAGMENT, &mmmmssss));
|
||||||
|
|
||||||
|
if ((oss.oss_fmt != fmt)
|
||||||
|
|| (oss.nchannels != nchannels)
|
||||||
|
|| (oss.freq != freq)) {
|
||||||
|
Fail ("failed to set audio parameters\n"
|
||||||
|
"parameter | requested value | obtained value\n"
|
||||||
|
"format | %10d | %10d\n"
|
||||||
|
"channels | %10d | %10d\n"
|
||||||
|
"frequency | %10d | %10d\n",
|
||||||
|
oss.oss_fmt, fmt,
|
||||||
|
oss.nchannels, nchannels,
|
||||||
|
oss.freq, freq);
|
||||||
|
}
|
||||||
|
|
||||||
|
IOCTL ((oss.fd, SNDCTL_DSP_GETOSPACE, &abinfo));
|
||||||
|
|
||||||
|
oss.nfrags = abinfo.fragstotal;
|
||||||
|
oss.fragsize = abinfo.fragsize;
|
||||||
|
oss.bufsize = oss.nfrags * oss.fragsize;
|
||||||
|
oss.old_optr = 0;
|
||||||
|
|
||||||
|
oss.bytes_per_second = (freq << (nchannels >> 1)) << oss.bits16;
|
||||||
|
|
||||||
|
linfo ("bytes per second %d\n", oss.bytes_per_second);
|
||||||
|
|
||||||
|
linfo ("fragments %d, fragstotal %d, fragsize %d, bytes %d, bufsize %d\n",
|
||||||
|
abinfo.fragments,
|
||||||
|
abinfo.fragstotal,
|
||||||
|
abinfo.fragsize,
|
||||||
|
abinfo.bytes,
|
||||||
|
oss.bufsize);
|
||||||
|
|
||||||
|
oss.buf = MAP_FAILED;
|
||||||
|
oss.is_mapped = 0;
|
||||||
|
|
||||||
|
if (conf.try_mmap) {
|
||||||
|
oss.buf = mmap (NULL, oss.bufsize, PROT_WRITE, MAP_SHARED, oss.fd, 0);
|
||||||
|
if (MAP_FAILED == oss.buf) {
|
||||||
|
int err;
|
||||||
|
|
||||||
|
err = errno;
|
||||||
|
log ("failed to mmap audio, size %d, fd %d\n"
|
||||||
|
"syserr: %s\n",
|
||||||
|
oss.bufsize, oss.fd, strerror (err));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
est = TID;
|
||||||
|
oss.is_mapped = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (MAP_FAILED == oss.buf) {
|
||||||
|
est = TID;
|
||||||
|
oss.buf = mmap (NULL, oss.bufsize, PROT_READ | PROT_WRITE,
|
||||||
|
MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
|
||||||
|
if (MAP_FAILED == oss.buf) {
|
||||||
|
ERRFail ("mmap audio buf, size %d", oss.bufsize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
oss.rpos = 0;
|
||||||
|
oss.wpos = 0;
|
||||||
|
oss.live = 0;
|
||||||
|
|
||||||
|
if (oss.is_mapped) {
|
||||||
|
int trig;
|
||||||
|
|
||||||
|
trig = 0;
|
||||||
|
IOCTL ((oss.fd, SNDCTL_DSP_SETTRIGGER, &trig));
|
||||||
|
trig = PCM_ENABLE_OUTPUT;
|
||||||
|
IOCTL ((oss.fd, SNDCTL_DSP_SETTRIGGER, &trig));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void maybe_open (int req_freq, int req_nchannels,
|
||||||
|
audfmt_e req_fmt, int force_open)
|
||||||
|
{
|
||||||
|
int oss_fmt, bits16;
|
||||||
|
|
||||||
|
switch (req_fmt) {
|
||||||
|
case AUD_FMT_U8:
|
||||||
|
bits16 = 0;
|
||||||
|
oss_fmt = AFMT_U8;
|
||||||
|
oss.copy_fn = copy_no_conversion;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AUD_FMT_S8:
|
||||||
|
Fail ("can not play 8bit signed");
|
||||||
|
|
||||||
|
case AUD_FMT_S16:
|
||||||
|
bits16 = 1;
|
||||||
|
oss_fmt = AFMT_S16_LE;
|
||||||
|
oss.copy_fn = copy_no_conversion;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AUD_FMT_U16:
|
||||||
|
bits16 = 1;
|
||||||
|
oss_fmt = AFMT_S16_LE;
|
||||||
|
oss.copy_fn = copy_u16_to_s16;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
abort ();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (force_open
|
||||||
|
|| (-1 == oss.fd)
|
||||||
|
|| (oss_fmt != oss.oss_fmt)
|
||||||
|
|| (req_nchannels != oss.nchannels)
|
||||||
|
|| (req_freq != oss.freq)
|
||||||
|
|| (bits16 != oss.bits16)) {
|
||||||
|
oss.oss_fmt = oss_fmt;
|
||||||
|
oss.nchannels = req_nchannels;
|
||||||
|
oss.freq = req_freq;
|
||||||
|
oss.bits16 = bits16;
|
||||||
|
do_open ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AUD_reset (int req_freq, int req_nchannels, audfmt_e req_fmt)
|
||||||
|
{
|
||||||
|
maybe_open (req_freq, req_nchannels, req_fmt, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AUD_open (int req_freq, int req_nchannels, audfmt_e req_fmt)
|
||||||
|
{
|
||||||
|
maybe_open (req_freq, req_nchannels, req_fmt, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int AUD_write (void *in_buf, int size)
|
||||||
|
{
|
||||||
|
int to_copy, temp;
|
||||||
|
uint8_t *in, *out;
|
||||||
|
|
||||||
|
to_copy = MIN (oss.bufsize - oss.live, size);
|
||||||
|
|
||||||
|
temp = to_copy;
|
||||||
|
|
||||||
|
in = in_buf;
|
||||||
|
out = oss.buf;
|
||||||
|
|
||||||
|
while (temp) {
|
||||||
|
int copy;
|
||||||
|
|
||||||
|
copy = MIN (temp, oss.bufsize - oss.wpos);
|
||||||
|
oss.copy_fn (out + oss.wpos, in, copy);
|
||||||
|
|
||||||
|
oss.wpos += copy;
|
||||||
|
if (oss.wpos == oss.bufsize) {
|
||||||
|
oss.wpos = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
temp -= copy;
|
||||||
|
in += copy;
|
||||||
|
oss.live += copy;
|
||||||
|
}
|
||||||
|
|
||||||
|
return to_copy;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AUD_run (void)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
int bytes;
|
||||||
|
struct audio_buf_info abinfo;
|
||||||
|
|
||||||
|
if (0 == oss.live)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (oss.is_mapped) {
|
||||||
|
count_info info;
|
||||||
|
|
||||||
|
res = ioctl (oss.fd, SNDCTL_DSP_GETOPTR, &info);
|
||||||
|
if (-1 == res) {
|
||||||
|
int err;
|
||||||
|
|
||||||
|
err = errno;
|
||||||
|
lwarn ("SNDCTL_DSP_GETOPTR failed with %s\n", strerror (err));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (info.ptr > oss.old_optr) {
|
||||||
|
bytes = info.ptr - oss.old_optr;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
bytes = oss.bufsize + info.ptr - oss.old_optr;
|
||||||
|
}
|
||||||
|
|
||||||
|
oss.old_optr = info.ptr;
|
||||||
|
oss.live -= bytes;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = ioctl (oss.fd, SNDCTL_DSP_GETOSPACE, &abinfo);
|
||||||
|
|
||||||
|
if (-1 == res) {
|
||||||
|
int err;
|
||||||
|
|
||||||
|
err = errno;
|
||||||
|
lwarn ("SNDCTL_DSP_GETOSPACE failed with %s\n", strerror (err));
|
||||||
|
}
|
||||||
|
|
||||||
|
bytes = abinfo.bytes;
|
||||||
|
bytes = MIN (oss.live, bytes);
|
||||||
|
#if 0
|
||||||
|
bytes = (bytes / fragsize) * fragsize;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
while (bytes) {
|
||||||
|
int left, play, written;
|
||||||
|
|
||||||
|
left = oss.bufsize - oss.rpos;
|
||||||
|
play = MIN (left, bytes);
|
||||||
|
written = write (oss.fd, (void *) ((uint32_t) oss.buf + oss.rpos), play);
|
||||||
|
|
||||||
|
if (-1 == written) {
|
||||||
|
if (EAGAIN == errno || EINTR == errno) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ERRFail ("write audio");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
play = written;
|
||||||
|
oss.live -= play;
|
||||||
|
oss.rpos += play;
|
||||||
|
bytes -= play;
|
||||||
|
|
||||||
|
if (oss.rpos == oss.bufsize) {
|
||||||
|
oss.rpos = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int get_dsp_bytes (void)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
struct count_info info;
|
||||||
|
|
||||||
|
res = ioctl (oss.fd, SNDCTL_DSP_GETOPTR, &info);
|
||||||
|
if (-1 == res) {
|
||||||
|
int err;
|
||||||
|
|
||||||
|
err = errno;
|
||||||
|
lwarn ("SNDCTL_DSP_GETOPTR failed with %s\n", strerror (err));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ldebug ("bytes %d\n", info.bytes);
|
||||||
|
return info.bytes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AUD_adjust_estimate (int leftover)
|
||||||
|
{
|
||||||
|
oss.leftover = leftover;
|
||||||
|
}
|
||||||
|
|
||||||
|
int AUD_get_free (void)
|
||||||
|
{
|
||||||
|
int free, elapsed;
|
||||||
|
|
||||||
|
free = oss.bufsize - oss.live;
|
||||||
|
|
||||||
|
if (0 == free)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
elapsed = free;
|
||||||
|
switch (est) {
|
||||||
|
case DONT:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DSP:
|
||||||
|
{
|
||||||
|
static int old_bytes;
|
||||||
|
int bytes;
|
||||||
|
|
||||||
|
bytes = get_dsp_bytes ();
|
||||||
|
if (bytes <= 0)
|
||||||
|
return free;
|
||||||
|
|
||||||
|
elapsed = bytes - old_bytes;
|
||||||
|
old_bytes = bytes;
|
||||||
|
ldebug ("dsp elapsed %d bytes\n", elapsed);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case TID:
|
||||||
|
{
|
||||||
|
uint64_t ticks, delta;
|
||||||
|
uint64_t ua_elapsed;
|
||||||
|
uint64_t al_elapsed;
|
||||||
|
|
||||||
|
ticks = qemu_get_clock(rt_clock);
|
||||||
|
delta = ticks - oss.old_ticks;
|
||||||
|
oss.old_ticks = ticks;
|
||||||
|
|
||||||
|
ua_elapsed = (delta * oss.bytes_per_second) / 1000;
|
||||||
|
al_elapsed = ua_elapsed & ~3ULL;
|
||||||
|
|
||||||
|
ldebug ("tid elapsed %llu bytes\n", ua_elapsed);
|
||||||
|
|
||||||
|
if (al_elapsed > (uint64_t) INT_MAX)
|
||||||
|
elapsed = INT_MAX;
|
||||||
|
else
|
||||||
|
elapsed = al_elapsed;
|
||||||
|
|
||||||
|
elapsed += oss.leftover;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (elapsed > free) {
|
||||||
|
lwarn ("audio can not keep up elapsed %d free %d\n", elapsed, free);
|
||||||
|
return free;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return elapsed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int AUD_get_live (void)
|
||||||
|
{
|
||||||
|
return oss.live;
|
||||||
|
}
|
||||||
|
|
||||||
|
int AUD_get_buffer_size (void)
|
||||||
|
{
|
||||||
|
return oss.bufsize;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define QC_OSS_FRAGSIZE "QEMU_OSS_FRAGSIZE"
|
||||||
|
#define QC_OSS_NFRAGS "QEMU_OSS_NFRAGS"
|
||||||
|
#define QC_OSS_MMAP "QEMU_OSS_MMAP"
|
||||||
|
|
||||||
|
static int get_conf_val (const char *key, int defval)
|
||||||
|
{
|
||||||
|
int val = defval;
|
||||||
|
char *strval;
|
||||||
|
|
||||||
|
strval = getenv (key);
|
||||||
|
if (strval) {
|
||||||
|
val = atoi (strval);
|
||||||
|
}
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AUD_init (void)
|
||||||
|
{
|
||||||
|
int fsp;
|
||||||
|
|
||||||
|
DEREF (pab);
|
||||||
|
|
||||||
|
conf.fragsize = get_conf_val (QC_OSS_FRAGSIZE, conf.fragsize);
|
||||||
|
conf.nfrags = get_conf_val (QC_OSS_NFRAGS, conf.nfrags);
|
||||||
|
conf.try_mmap = get_conf_val (QC_OSS_MMAP, conf.try_mmap);
|
||||||
|
|
||||||
|
fsp = conf.fragsize;
|
||||||
|
if (0 != (fsp & (fsp - 1))) {
|
||||||
|
Fail ("fragment size %d is not power of 2", fsp);
|
||||||
|
}
|
||||||
|
|
||||||
|
conf.fragsize = lsbindex (fsp);
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
void AUD_run (void)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
int AUD_write (void *in_buf, int size)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AUD_reset (int rfreq, int rnchannels, audfmt_e rfmt)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void AUD_adjust_estimate (int _leftover)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
int AUD_get_free (void)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int AUD_get_live (void)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int AUD_get_buffer_size (void)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AUD_init (void)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
#
|
||||||
|
# NOTE: only compilable with x86 cross compile tools
|
||||||
|
#
|
||||||
|
include ../config-host.mak
|
||||||
|
|
||||||
|
DEFINES=
|
||||||
|
|
||||||
|
TARGETS=
|
||||||
|
ifeq ($(ARCH),i386)
|
||||||
|
TARGETS+=linux_boot.bin
|
||||||
|
endif
|
||||||
|
|
||||||
|
all: $(TARGETS)
|
||||||
|
|
||||||
|
linux_boot.bin: linux_boot.o
|
||||||
|
ld --oformat binary -Ttext 0 -o $@ $<
|
||||||
|
chmod a-x $@
|
||||||
|
|
||||||
|
%.o: %.S
|
||||||
|
$(CC) $(DEFINES) -c -o $@ $<
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f $(TARGETS) *.o *~
|
||||||
|
|
||||||
+7
-3
@@ -1,4 +1,8 @@
|
|||||||
- The PC BIOS comes from the Bochs project
|
- The PC BIOS comes from the Bochs project
|
||||||
(http://bochs.sourceforge.net/).
|
(http://bochs.sourceforge.net/). A patch from bios.diff was applied.
|
||||||
- The VGA BIOS comes from the LGPL VGA bios project
|
|
||||||
(http://www.nongnu.org/vgabios/).
|
- The VGA BIOS and the Cirrus VGA BIOS come from the LGPL VGA bios
|
||||||
|
project (http://www.nongnu.org/vgabios/).
|
||||||
|
|
||||||
|
- The PowerPC Open Hack'Ware Open Firmware Compatible BIOS is
|
||||||
|
available at http://site.voila.fr/jmayer/OpenHackWare/index.htm.
|
||||||
Binary file not shown.
@@ -0,0 +1,104 @@
|
|||||||
|
Index: rombios.c
|
||||||
|
===================================================================
|
||||||
|
RCS file: /cvsroot/bochs/bochs/bios/rombios.c,v
|
||||||
|
retrieving revision 1.110
|
||||||
|
diff -u -w -r1.110 rombios.c
|
||||||
|
--- rombios.c 31 May 2004 13:11:27 -0000 1.110
|
||||||
|
+++ rombios.c 20 Jun 2004 13:10:07 -0000
|
||||||
|
@@ -137,6 +137,7 @@
|
||||||
|
#define DEBUG_INT16 0
|
||||||
|
#define DEBUG_INT1A 0
|
||||||
|
#define DEBUG_INT74 0
|
||||||
|
+#define DEBUG_APM 0
|
||||||
|
|
||||||
|
#define BX_CPU 3
|
||||||
|
#define BX_USE_PS2_MOUSE 1
|
||||||
|
@@ -145,6 +146,7 @@
|
||||||
|
#define BX_SUPPORT_FLOPPY 1
|
||||||
|
#define BX_FLOPPY_ON_CNT 37 // 2 seconds
|
||||||
|
#define BX_PCIBIOS 1
|
||||||
|
+#define BX_APM 1
|
||||||
|
|
||||||
|
#define BX_USE_ATADRV 1
|
||||||
|
#define BX_ELTORITO_BOOT 1
|
||||||
|
@@ -230,17 +232,6 @@
|
||||||
|
out dx,ax
|
||||||
|
MEND
|
||||||
|
|
||||||
|
-MACRO HALT2
|
||||||
|
- ;; the HALT macro is called with the line number of the HALT call.
|
||||||
|
- ;; The line number is then sent to the PANIC_PORT, causing Bochs/Plex
|
||||||
|
- ;; to print a BX_PANIC message. This will normally halt the simulation
|
||||||
|
- ;; with a message such as "BIOS panic at rombios.c, line 4091".
|
||||||
|
- ;; However, users can choose to make panics non-fatal and continue.
|
||||||
|
- mov dx,#PANIC_PORT2
|
||||||
|
- mov ax,#?1
|
||||||
|
- out dx,ax
|
||||||
|
-MEND
|
||||||
|
-
|
||||||
|
MACRO JMP_AP
|
||||||
|
db 0xea
|
||||||
|
dw ?2
|
||||||
|
@@ -1543,15 +1534,12 @@
|
||||||
|
}
|
||||||
|
|
||||||
|
if (action & BIOS_PRINTF_HALT) {
|
||||||
|
- // freeze in a busy loop. If I do a HLT instruction, then in versions
|
||||||
|
- // 1.3.pre1 and earlier, it will panic without ever updating the VGA
|
||||||
|
- // display, so the panic message will not be visible. By waiting
|
||||||
|
- // forever, you are certain to see the panic message on screen.
|
||||||
|
- // After a few more versions have passed, we can turn this back into
|
||||||
|
- // a halt or something.
|
||||||
|
- // do {} while (1);
|
||||||
|
+ // freeze in a busy loop.
|
||||||
|
ASM_START
|
||||||
|
- HALT2(__LINE__)
|
||||||
|
+ cli
|
||||||
|
+ halt2_loop:
|
||||||
|
+ hlt
|
||||||
|
+ jmp halt2_loop
|
||||||
|
ASM_END
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@@ -8344,6 +8332,19 @@
|
||||||
|
pop ax
|
||||||
|
iret
|
||||||
|
|
||||||
|
+
|
||||||
|
+;--------------------
|
||||||
|
+#if BX_APM
|
||||||
|
+use32 386
|
||||||
|
+#define APM_PROT32
|
||||||
|
+#include "apmbios.S"
|
||||||
|
+use16 386
|
||||||
|
+
|
||||||
|
+#define APM_REAL
|
||||||
|
+#include "apmbios.S"
|
||||||
|
+
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
;--------------------
|
||||||
|
#if BX_PCIBIOS
|
||||||
|
use32 386
|
||||||
|
@@ -9560,6 +9561,10 @@
|
||||||
|
.org 0xf859 ; INT 15h System Services Entry Point
|
||||||
|
int15_handler:
|
||||||
|
pushf
|
||||||
|
+#if BX_APM
|
||||||
|
+ cmp ah, #0x53
|
||||||
|
+ je apm_call
|
||||||
|
+#endif
|
||||||
|
push ds
|
||||||
|
push es
|
||||||
|
pushad
|
||||||
|
@@ -9570,6 +9575,10 @@
|
||||||
|
popf
|
||||||
|
//JMPL(iret_modify_cf)
|
||||||
|
jmp iret_modify_cf
|
||||||
|
+#if BX_APM
|
||||||
|
+apm_call:
|
||||||
|
+ jmp _apmreal_entry
|
||||||
|
+#endif
|
||||||
|
|
||||||
|
;; Protected mode IDT descriptor
|
||||||
|
;;
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
/*
|
||||||
|
* QEMU Boot sector to launch a preloaded Linux kernel
|
||||||
|
* Copyright (c) 2004 Fabrice Bellard
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define LOAD_SEG 0x9000
|
||||||
|
|
||||||
|
.code16
|
||||||
|
.text
|
||||||
|
.globl _start
|
||||||
|
|
||||||
|
_start:
|
||||||
|
cli
|
||||||
|
cld
|
||||||
|
mov $LOAD_SEG, %ax
|
||||||
|
mov %ax, %ds
|
||||||
|
mov %ax, %es
|
||||||
|
mov %ax, %fs
|
||||||
|
mov %ax, %gs
|
||||||
|
mov %ax, %ss
|
||||||
|
mov $0x8ffe, %sp
|
||||||
|
ljmp $LOAD_SEG + 0x20, $0
|
||||||
|
|
||||||
|
1:
|
||||||
|
.fill 510 - (1b - _start), 1, 0
|
||||||
|
|
||||||
|
/* boot sector signature */
|
||||||
|
.byte 0x55
|
||||||
|
.byte 0xaa
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -48,18 +48,18 @@ struct powerpc_opcode
|
|||||||
|
|
||||||
/* The opcode itself. Those bits which will be filled in with
|
/* The opcode itself. Those bits which will be filled in with
|
||||||
operands are zeroes. */
|
operands are zeroes. */
|
||||||
unsigned long opcode;
|
uint32_t opcode;
|
||||||
|
|
||||||
/* The opcode mask. This is used by the disassembler. This is a
|
/* The opcode mask. This is used by the disassembler. This is a
|
||||||
mask containing ones indicating those bits which must match the
|
mask containing ones indicating those bits which must match the
|
||||||
opcode field, and zeroes indicating those bits which need not
|
opcode field, and zeroes indicating those bits which need not
|
||||||
match (and are presumably filled in by operands). */
|
match (and are presumably filled in by operands). */
|
||||||
unsigned long mask;
|
uint32_t mask;
|
||||||
|
|
||||||
/* One bit flags for the opcode. These are used to indicate which
|
/* One bit flags for the opcode. These are used to indicate which
|
||||||
specific processors support the instructions. The defined values
|
specific processors support the instructions. The defined values
|
||||||
are listed below. */
|
are listed below. */
|
||||||
unsigned long flags;
|
uint32_t flags;
|
||||||
|
|
||||||
/* An array of operand codes. Each code is an index into the
|
/* An array of operand codes. Each code is an index into the
|
||||||
operand table. They appear in the order which the operands must
|
operand table. They appear in the order which the operands must
|
||||||
@@ -124,7 +124,7 @@ struct powerpc_operand
|
|||||||
string (the operand will be inserted in any case). If the
|
string (the operand will be inserted in any case). If the
|
||||||
operand value is legal, *ERRMSG will be unchanged (most operands
|
operand value is legal, *ERRMSG will be unchanged (most operands
|
||||||
can accept any value). */
|
can accept any value). */
|
||||||
unsigned long (*insert)(unsigned long instruction, long op,
|
unsigned long (*insert)(uint32_t instruction, int32_t op,
|
||||||
const char **errmsg);
|
const char **errmsg);
|
||||||
|
|
||||||
/* Extraction function. This is used by the disassembler. To
|
/* Extraction function. This is used by the disassembler. To
|
||||||
@@ -144,10 +144,10 @@ struct powerpc_operand
|
|||||||
non-zero if this operand type can not actually be extracted from
|
non-zero if this operand type can not actually be extracted from
|
||||||
this operand (i.e., the instruction does not match). If the
|
this operand (i.e., the instruction does not match). If the
|
||||||
operand is valid, *INVALID will not be changed. */
|
operand is valid, *INVALID will not be changed. */
|
||||||
long (*extract) (unsigned long instruction, int *invalid);
|
long (*extract) (uint32_t instruction, int *invalid);
|
||||||
|
|
||||||
/* One bit syntax flags. */
|
/* One bit syntax flags. */
|
||||||
unsigned long flags;
|
uint32_t flags;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Elements in the table are retrieved by indexing with values from
|
/* Elements in the table are retrieved by indexing with values from
|
||||||
@@ -244,7 +244,7 @@ struct powerpc_macro
|
|||||||
/* One bit flags for the opcode. These are used to indicate which
|
/* One bit flags for the opcode. These are used to indicate which
|
||||||
specific processors support the instructions. The values are the
|
specific processors support the instructions. The values are the
|
||||||
same as those for the struct powerpc_opcode flags field. */
|
same as those for the struct powerpc_opcode flags field. */
|
||||||
unsigned long flags;
|
uint32_t flags;
|
||||||
|
|
||||||
/* A format string to turn the macro into a normal instruction.
|
/* A format string to turn the macro into a normal instruction.
|
||||||
Each %N in the string is replaced with operand number N (zero
|
Each %N in the string is replaced with operand number N (zero
|
||||||
@@ -288,43 +288,43 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
|||||||
|
|
||||||
/* Local insertion and extraction functions. */
|
/* Local insertion and extraction functions. */
|
||||||
|
|
||||||
static unsigned long insert_bat (unsigned long, long, const char **);
|
static unsigned long insert_bat (uint32_t, int32_t, const char **);
|
||||||
static long extract_bat(unsigned long, int *);
|
static long extract_bat(uint32_t, int *);
|
||||||
static unsigned long insert_bba(unsigned long, long, const char **);
|
static unsigned long insert_bba(uint32_t, int32_t, const char **);
|
||||||
static long extract_bba(unsigned long, int *);
|
static long extract_bba(uint32_t, int *);
|
||||||
static unsigned long insert_bd(unsigned long, long, const char **);
|
static unsigned long insert_bd(uint32_t, int32_t, const char **);
|
||||||
static long extract_bd(unsigned long, int *);
|
static long extract_bd(uint32_t, int *);
|
||||||
static unsigned long insert_bdm(unsigned long, long, const char **);
|
static unsigned long insert_bdm(uint32_t, int32_t, const char **);
|
||||||
static long extract_bdm(unsigned long, int *);
|
static long extract_bdm(uint32_t, int *);
|
||||||
static unsigned long insert_bdp(unsigned long, long, const char **);
|
static unsigned long insert_bdp(uint32_t, int32_t, const char **);
|
||||||
static long extract_bdp(unsigned long, int *);
|
static long extract_bdp(uint32_t, int *);
|
||||||
static unsigned long insert_bo(unsigned long, long, const char **);
|
static unsigned long insert_bo(uint32_t, int32_t, const char **);
|
||||||
static long extract_bo(unsigned long, int *);
|
static long extract_bo(uint32_t, int *);
|
||||||
static unsigned long insert_boe(unsigned long, long, const char **);
|
static unsigned long insert_boe(uint32_t, int32_t, const char **);
|
||||||
static long extract_boe(unsigned long, int *);
|
static long extract_boe(uint32_t, int *);
|
||||||
static unsigned long insert_ds(unsigned long, long, const char **);
|
static unsigned long insert_ds(uint32_t, int32_t, const char **);
|
||||||
static long extract_ds(unsigned long, int *);
|
static long extract_ds(uint32_t, int *);
|
||||||
static unsigned long insert_li(unsigned long, long, const char **);
|
static unsigned long insert_li(uint32_t, int32_t, const char **);
|
||||||
static long extract_li(unsigned long, int *);
|
static long extract_li(uint32_t, int *);
|
||||||
static unsigned long insert_mbe(unsigned long, long, const char **);
|
static unsigned long insert_mbe(uint32_t, int32_t, const char **);
|
||||||
static long extract_mbe(unsigned long, int *);
|
static long extract_mbe(uint32_t, int *);
|
||||||
static unsigned long insert_mb6(unsigned long, long, const char **);
|
static unsigned long insert_mb6(uint32_t, int32_t, const char **);
|
||||||
static long extract_mb6(unsigned long, int *);
|
static long extract_mb6(uint32_t, int *);
|
||||||
static unsigned long insert_nb(unsigned long, long, const char **);
|
static unsigned long insert_nb(uint32_t, int32_t, const char **);
|
||||||
static long extract_nb(unsigned long, int *);
|
static long extract_nb(uint32_t, int *);
|
||||||
static unsigned long insert_nsi(unsigned long, long, const char **);
|
static unsigned long insert_nsi(uint32_t, int32_t, const char **);
|
||||||
static long extract_nsi(unsigned long, int *);
|
static long extract_nsi(uint32_t, int *);
|
||||||
static unsigned long insert_ral(unsigned long, long, const char **);
|
static unsigned long insert_ral(uint32_t, int32_t, const char **);
|
||||||
static unsigned long insert_ram(unsigned long, long, const char **);
|
static unsigned long insert_ram(uint32_t, int32_t, const char **);
|
||||||
static unsigned long insert_ras(unsigned long, long, const char **);
|
static unsigned long insert_ras(uint32_t, int32_t, const char **);
|
||||||
static unsigned long insert_rbs(unsigned long, long, const char **);
|
static unsigned long insert_rbs(uint32_t, int32_t, const char **);
|
||||||
static long extract_rbs(unsigned long, int *);
|
static long extract_rbs(uint32_t, int *);
|
||||||
static unsigned long insert_sh6(unsigned long, long, const char **);
|
static unsigned long insert_sh6(uint32_t, int32_t, const char **);
|
||||||
static long extract_sh6(unsigned long, int *);
|
static long extract_sh6(uint32_t, int *);
|
||||||
static unsigned long insert_spr(unsigned long, long, const char **);
|
static unsigned long insert_spr(uint32_t, int32_t, const char **);
|
||||||
static long extract_spr(unsigned long, int *);
|
static long extract_spr(uint32_t, int *);
|
||||||
static unsigned long insert_tbr(unsigned long, long, const char **);
|
static unsigned long insert_tbr(uint32_t, int32_t, const char **);
|
||||||
static long extract_tbr(unsigned long, int *);
|
static long extract_tbr(uint32_t, int *);
|
||||||
|
|
||||||
/* The operands table.
|
/* The operands table.
|
||||||
|
|
||||||
@@ -648,8 +648,8 @@ const struct powerpc_operand powerpc_operands[] =
|
|||||||
/*ARGSUSED*/
|
/*ARGSUSED*/
|
||||||
static unsigned long
|
static unsigned long
|
||||||
insert_bat (insn, value, errmsg)
|
insert_bat (insn, value, errmsg)
|
||||||
unsigned long insn;
|
uint32_t insn;
|
||||||
long value;
|
int32_t value;
|
||||||
const char **errmsg;
|
const char **errmsg;
|
||||||
{
|
{
|
||||||
return insn | (((insn >> 21) & 0x1f) << 16);
|
return insn | (((insn >> 21) & 0x1f) << 16);
|
||||||
@@ -657,7 +657,7 @@ insert_bat (insn, value, errmsg)
|
|||||||
|
|
||||||
static long
|
static long
|
||||||
extract_bat (insn, invalid)
|
extract_bat (insn, invalid)
|
||||||
unsigned long insn;
|
uint32_t insn;
|
||||||
int *invalid;
|
int *invalid;
|
||||||
{
|
{
|
||||||
if (invalid != (int *) NULL
|
if (invalid != (int *) NULL
|
||||||
@@ -675,8 +675,8 @@ extract_bat (insn, invalid)
|
|||||||
/*ARGSUSED*/
|
/*ARGSUSED*/
|
||||||
static unsigned long
|
static unsigned long
|
||||||
insert_bba (insn, value, errmsg)
|
insert_bba (insn, value, errmsg)
|
||||||
unsigned long insn;
|
uint32_t insn;
|
||||||
long value;
|
int32_t value;
|
||||||
const char **errmsg;
|
const char **errmsg;
|
||||||
{
|
{
|
||||||
return insn | (((insn >> 16) & 0x1f) << 11);
|
return insn | (((insn >> 16) & 0x1f) << 11);
|
||||||
@@ -684,7 +684,7 @@ insert_bba (insn, value, errmsg)
|
|||||||
|
|
||||||
static long
|
static long
|
||||||
extract_bba (insn, invalid)
|
extract_bba (insn, invalid)
|
||||||
unsigned long insn;
|
uint32_t insn;
|
||||||
int *invalid;
|
int *invalid;
|
||||||
{
|
{
|
||||||
if (invalid != (int *) NULL
|
if (invalid != (int *) NULL
|
||||||
@@ -699,8 +699,8 @@ extract_bba (insn, invalid)
|
|||||||
/*ARGSUSED*/
|
/*ARGSUSED*/
|
||||||
static unsigned long
|
static unsigned long
|
||||||
insert_bd (insn, value, errmsg)
|
insert_bd (insn, value, errmsg)
|
||||||
unsigned long insn;
|
uint32_t insn;
|
||||||
long value;
|
int32_t value;
|
||||||
const char **errmsg;
|
const char **errmsg;
|
||||||
{
|
{
|
||||||
return insn | (value & 0xfffc);
|
return insn | (value & 0xfffc);
|
||||||
@@ -709,7 +709,7 @@ insert_bd (insn, value, errmsg)
|
|||||||
/*ARGSUSED*/
|
/*ARGSUSED*/
|
||||||
static long
|
static long
|
||||||
extract_bd (insn, invalid)
|
extract_bd (insn, invalid)
|
||||||
unsigned long insn;
|
uint32_t insn;
|
||||||
int *invalid;
|
int *invalid;
|
||||||
{
|
{
|
||||||
if ((insn & 0x8000) != 0)
|
if ((insn & 0x8000) != 0)
|
||||||
@@ -728,8 +728,8 @@ extract_bd (insn, invalid)
|
|||||||
/*ARGSUSED*/
|
/*ARGSUSED*/
|
||||||
static unsigned long
|
static unsigned long
|
||||||
insert_bdm (insn, value, errmsg)
|
insert_bdm (insn, value, errmsg)
|
||||||
unsigned long insn;
|
uint32_t insn;
|
||||||
long value;
|
int32_t value;
|
||||||
const char **errmsg;
|
const char **errmsg;
|
||||||
{
|
{
|
||||||
if ((value & 0x8000) != 0)
|
if ((value & 0x8000) != 0)
|
||||||
@@ -739,7 +739,7 @@ insert_bdm (insn, value, errmsg)
|
|||||||
|
|
||||||
static long
|
static long
|
||||||
extract_bdm (insn, invalid)
|
extract_bdm (insn, invalid)
|
||||||
unsigned long insn;
|
uint32_t insn;
|
||||||
int *invalid;
|
int *invalid;
|
||||||
{
|
{
|
||||||
if (invalid != (int *) NULL
|
if (invalid != (int *) NULL
|
||||||
@@ -759,8 +759,8 @@ extract_bdm (insn, invalid)
|
|||||||
/*ARGSUSED*/
|
/*ARGSUSED*/
|
||||||
static unsigned long
|
static unsigned long
|
||||||
insert_bdp (insn, value, errmsg)
|
insert_bdp (insn, value, errmsg)
|
||||||
unsigned long insn;
|
uint32_t insn;
|
||||||
long value;
|
int32_t value;
|
||||||
const char **errmsg;
|
const char **errmsg;
|
||||||
{
|
{
|
||||||
if ((value & 0x8000) == 0)
|
if ((value & 0x8000) == 0)
|
||||||
@@ -770,7 +770,7 @@ insert_bdp (insn, value, errmsg)
|
|||||||
|
|
||||||
static long
|
static long
|
||||||
extract_bdp (insn, invalid)
|
extract_bdp (insn, invalid)
|
||||||
unsigned long insn;
|
uint32_t insn;
|
||||||
int *invalid;
|
int *invalid;
|
||||||
{
|
{
|
||||||
if (invalid != (int *) NULL
|
if (invalid != (int *) NULL
|
||||||
@@ -786,7 +786,7 @@ extract_bdp (insn, invalid)
|
|||||||
/* Check for legal values of a BO field. */
|
/* Check for legal values of a BO field. */
|
||||||
|
|
||||||
static int
|
static int
|
||||||
valid_bo (long value)
|
valid_bo (int32_t value)
|
||||||
{
|
{
|
||||||
/* Certain encodings have bits that are required to be zero. These
|
/* Certain encodings have bits that are required to be zero. These
|
||||||
are (z must be zero, y may be anything):
|
are (z must be zero, y may be anything):
|
||||||
@@ -815,8 +815,8 @@ valid_bo (long value)
|
|||||||
|
|
||||||
static unsigned long
|
static unsigned long
|
||||||
insert_bo (insn, value, errmsg)
|
insert_bo (insn, value, errmsg)
|
||||||
unsigned long insn;
|
uint32_t insn;
|
||||||
long value;
|
int32_t value;
|
||||||
const char **errmsg;
|
const char **errmsg;
|
||||||
{
|
{
|
||||||
if (errmsg != (const char **) NULL
|
if (errmsg != (const char **) NULL
|
||||||
@@ -827,10 +827,10 @@ insert_bo (insn, value, errmsg)
|
|||||||
|
|
||||||
static long
|
static long
|
||||||
extract_bo (insn, invalid)
|
extract_bo (insn, invalid)
|
||||||
unsigned long insn;
|
uint32_t insn;
|
||||||
int *invalid;
|
int *invalid;
|
||||||
{
|
{
|
||||||
long value;
|
int32_t value;
|
||||||
|
|
||||||
value = (insn >> 21) & 0x1f;
|
value = (insn >> 21) & 0x1f;
|
||||||
if (invalid != (int *) NULL
|
if (invalid != (int *) NULL
|
||||||
@@ -845,8 +845,8 @@ extract_bo (insn, invalid)
|
|||||||
|
|
||||||
static unsigned long
|
static unsigned long
|
||||||
insert_boe (insn, value, errmsg)
|
insert_boe (insn, value, errmsg)
|
||||||
unsigned long insn;
|
uint32_t insn;
|
||||||
long value;
|
int32_t value;
|
||||||
const char **errmsg;
|
const char **errmsg;
|
||||||
{
|
{
|
||||||
if (errmsg != (const char **) NULL)
|
if (errmsg != (const char **) NULL)
|
||||||
@@ -861,10 +861,10 @@ insert_boe (insn, value, errmsg)
|
|||||||
|
|
||||||
static long
|
static long
|
||||||
extract_boe (insn, invalid)
|
extract_boe (insn, invalid)
|
||||||
unsigned long insn;
|
uint32_t insn;
|
||||||
int *invalid;
|
int *invalid;
|
||||||
{
|
{
|
||||||
long value;
|
int32_t value;
|
||||||
|
|
||||||
value = (insn >> 21) & 0x1f;
|
value = (insn >> 21) & 0x1f;
|
||||||
if (invalid != (int *) NULL
|
if (invalid != (int *) NULL
|
||||||
@@ -879,8 +879,8 @@ extract_boe (insn, invalid)
|
|||||||
/*ARGSUSED*/
|
/*ARGSUSED*/
|
||||||
static unsigned long
|
static unsigned long
|
||||||
insert_ds (insn, value, errmsg)
|
insert_ds (insn, value, errmsg)
|
||||||
unsigned long insn;
|
uint32_t insn;
|
||||||
long value;
|
int32_t value;
|
||||||
const char **errmsg;
|
const char **errmsg;
|
||||||
{
|
{
|
||||||
return insn | (value & 0xfffc);
|
return insn | (value & 0xfffc);
|
||||||
@@ -889,7 +889,7 @@ insert_ds (insn, value, errmsg)
|
|||||||
/*ARGSUSED*/
|
/*ARGSUSED*/
|
||||||
static long
|
static long
|
||||||
extract_ds (insn, invalid)
|
extract_ds (insn, invalid)
|
||||||
unsigned long insn;
|
uint32_t insn;
|
||||||
int *invalid;
|
int *invalid;
|
||||||
{
|
{
|
||||||
if ((insn & 0x8000) != 0)
|
if ((insn & 0x8000) != 0)
|
||||||
@@ -904,8 +904,8 @@ extract_ds (insn, invalid)
|
|||||||
/*ARGSUSED*/
|
/*ARGSUSED*/
|
||||||
static unsigned long
|
static unsigned long
|
||||||
insert_li (insn, value, errmsg)
|
insert_li (insn, value, errmsg)
|
||||||
unsigned long insn;
|
uint32_t insn;
|
||||||
long value;
|
int32_t value;
|
||||||
const char **errmsg;
|
const char **errmsg;
|
||||||
{
|
{
|
||||||
return insn | (value & 0x3fffffc);
|
return insn | (value & 0x3fffffc);
|
||||||
@@ -914,7 +914,7 @@ insert_li (insn, value, errmsg)
|
|||||||
/*ARGSUSED*/
|
/*ARGSUSED*/
|
||||||
static long
|
static long
|
||||||
extract_li (insn, invalid)
|
extract_li (insn, invalid)
|
||||||
unsigned long insn;
|
uint32_t insn;
|
||||||
int *invalid;
|
int *invalid;
|
||||||
{
|
{
|
||||||
if ((insn & 0x2000000) != 0)
|
if ((insn & 0x2000000) != 0)
|
||||||
@@ -930,11 +930,11 @@ extract_li (insn, invalid)
|
|||||||
|
|
||||||
static unsigned long
|
static unsigned long
|
||||||
insert_mbe (insn, value, errmsg)
|
insert_mbe (insn, value, errmsg)
|
||||||
unsigned long insn;
|
uint32_t insn;
|
||||||
long value;
|
int32_t value;
|
||||||
const char **errmsg;
|
const char **errmsg;
|
||||||
{
|
{
|
||||||
unsigned long uval;
|
uint32_t uval;
|
||||||
int mb, me;
|
int mb, me;
|
||||||
|
|
||||||
uval = value;
|
uval = value;
|
||||||
@@ -972,7 +972,7 @@ insert_mbe (insn, value, errmsg)
|
|||||||
|
|
||||||
static long
|
static long
|
||||||
extract_mbe (insn, invalid)
|
extract_mbe (insn, invalid)
|
||||||
unsigned long insn;
|
uint32_t insn;
|
||||||
int *invalid;
|
int *invalid;
|
||||||
{
|
{
|
||||||
long ret;
|
long ret;
|
||||||
@@ -996,8 +996,8 @@ extract_mbe (insn, invalid)
|
|||||||
/*ARGSUSED*/
|
/*ARGSUSED*/
|
||||||
static unsigned long
|
static unsigned long
|
||||||
insert_mb6 (insn, value, errmsg)
|
insert_mb6 (insn, value, errmsg)
|
||||||
unsigned long insn;
|
uint32_t insn;
|
||||||
long value;
|
int32_t value;
|
||||||
const char **errmsg;
|
const char **errmsg;
|
||||||
{
|
{
|
||||||
return insn | ((value & 0x1f) << 6) | (value & 0x20);
|
return insn | ((value & 0x1f) << 6) | (value & 0x20);
|
||||||
@@ -1006,7 +1006,7 @@ insert_mb6 (insn, value, errmsg)
|
|||||||
/*ARGSUSED*/
|
/*ARGSUSED*/
|
||||||
static long
|
static long
|
||||||
extract_mb6 (insn, invalid)
|
extract_mb6 (insn, invalid)
|
||||||
unsigned long insn;
|
uint32_t insn;
|
||||||
int *invalid;
|
int *invalid;
|
||||||
{
|
{
|
||||||
return ((insn >> 6) & 0x1f) | (insn & 0x20);
|
return ((insn >> 6) & 0x1f) | (insn & 0x20);
|
||||||
@@ -1017,8 +1017,8 @@ extract_mb6 (insn, invalid)
|
|||||||
|
|
||||||
static unsigned long
|
static unsigned long
|
||||||
insert_nb (insn, value, errmsg)
|
insert_nb (insn, value, errmsg)
|
||||||
unsigned long insn;
|
uint32_t insn;
|
||||||
long value;
|
int32_t value;
|
||||||
const char **errmsg;
|
const char **errmsg;
|
||||||
{
|
{
|
||||||
if (value < 0 || value > 32)
|
if (value < 0 || value > 32)
|
||||||
@@ -1031,7 +1031,7 @@ insert_nb (insn, value, errmsg)
|
|||||||
/*ARGSUSED*/
|
/*ARGSUSED*/
|
||||||
static long
|
static long
|
||||||
extract_nb (insn, invalid)
|
extract_nb (insn, invalid)
|
||||||
unsigned long insn;
|
uint32_t insn;
|
||||||
int *invalid;
|
int *invalid;
|
||||||
{
|
{
|
||||||
long ret;
|
long ret;
|
||||||
@@ -1050,8 +1050,8 @@ extract_nb (insn, invalid)
|
|||||||
/*ARGSUSED*/
|
/*ARGSUSED*/
|
||||||
static unsigned long
|
static unsigned long
|
||||||
insert_nsi (insn, value, errmsg)
|
insert_nsi (insn, value, errmsg)
|
||||||
unsigned long insn;
|
uint32_t insn;
|
||||||
long value;
|
int32_t value;
|
||||||
const char **errmsg;
|
const char **errmsg;
|
||||||
{
|
{
|
||||||
return insn | ((- value) & 0xffff);
|
return insn | ((- value) & 0xffff);
|
||||||
@@ -1059,7 +1059,7 @@ insert_nsi (insn, value, errmsg)
|
|||||||
|
|
||||||
static long
|
static long
|
||||||
extract_nsi (insn, invalid)
|
extract_nsi (insn, invalid)
|
||||||
unsigned long insn;
|
uint32_t insn;
|
||||||
int *invalid;
|
int *invalid;
|
||||||
{
|
{
|
||||||
if (invalid != (int *) NULL)
|
if (invalid != (int *) NULL)
|
||||||
@@ -1076,8 +1076,8 @@ extract_nsi (insn, invalid)
|
|||||||
|
|
||||||
static unsigned long
|
static unsigned long
|
||||||
insert_ral (insn, value, errmsg)
|
insert_ral (insn, value, errmsg)
|
||||||
unsigned long insn;
|
uint32_t insn;
|
||||||
long value;
|
int32_t value;
|
||||||
const char **errmsg;
|
const char **errmsg;
|
||||||
{
|
{
|
||||||
if (value == 0
|
if (value == 0
|
||||||
@@ -1091,8 +1091,8 @@ insert_ral (insn, value, errmsg)
|
|||||||
|
|
||||||
static unsigned long
|
static unsigned long
|
||||||
insert_ram (insn, value, errmsg)
|
insert_ram (insn, value, errmsg)
|
||||||
unsigned long insn;
|
uint32_t insn;
|
||||||
long value;
|
int32_t value;
|
||||||
const char **errmsg;
|
const char **errmsg;
|
||||||
{
|
{
|
||||||
if (value >= ((insn >> 21) & 0x1f))
|
if (value >= ((insn >> 21) & 0x1f))
|
||||||
@@ -1106,8 +1106,8 @@ insert_ram (insn, value, errmsg)
|
|||||||
|
|
||||||
static unsigned long
|
static unsigned long
|
||||||
insert_ras (insn, value, errmsg)
|
insert_ras (insn, value, errmsg)
|
||||||
unsigned long insn;
|
uint32_t insn;
|
||||||
long value;
|
int32_t value;
|
||||||
const char **errmsg;
|
const char **errmsg;
|
||||||
{
|
{
|
||||||
if (value == 0)
|
if (value == 0)
|
||||||
@@ -1124,8 +1124,8 @@ insert_ras (insn, value, errmsg)
|
|||||||
/*ARGSUSED*/
|
/*ARGSUSED*/
|
||||||
static unsigned long
|
static unsigned long
|
||||||
insert_rbs (insn, value, errmsg)
|
insert_rbs (insn, value, errmsg)
|
||||||
unsigned long insn;
|
uint32_t insn;
|
||||||
long value;
|
int32_t value;
|
||||||
const char **errmsg;
|
const char **errmsg;
|
||||||
{
|
{
|
||||||
return insn | (((insn >> 21) & 0x1f) << 11);
|
return insn | (((insn >> 21) & 0x1f) << 11);
|
||||||
@@ -1133,7 +1133,7 @@ insert_rbs (insn, value, errmsg)
|
|||||||
|
|
||||||
static long
|
static long
|
||||||
extract_rbs (insn, invalid)
|
extract_rbs (insn, invalid)
|
||||||
unsigned long insn;
|
uint32_t insn;
|
||||||
int *invalid;
|
int *invalid;
|
||||||
{
|
{
|
||||||
if (invalid != (int *) NULL
|
if (invalid != (int *) NULL
|
||||||
@@ -1147,8 +1147,8 @@ extract_rbs (insn, invalid)
|
|||||||
/*ARGSUSED*/
|
/*ARGSUSED*/
|
||||||
static unsigned long
|
static unsigned long
|
||||||
insert_sh6 (insn, value, errmsg)
|
insert_sh6 (insn, value, errmsg)
|
||||||
unsigned long insn;
|
uint32_t insn;
|
||||||
long value;
|
int32_t value;
|
||||||
const char **errmsg;
|
const char **errmsg;
|
||||||
{
|
{
|
||||||
return insn | ((value & 0x1f) << 11) | ((value & 0x20) >> 4);
|
return insn | ((value & 0x1f) << 11) | ((value & 0x20) >> 4);
|
||||||
@@ -1157,7 +1157,7 @@ insert_sh6 (insn, value, errmsg)
|
|||||||
/*ARGSUSED*/
|
/*ARGSUSED*/
|
||||||
static long
|
static long
|
||||||
extract_sh6 (insn, invalid)
|
extract_sh6 (insn, invalid)
|
||||||
unsigned long insn;
|
uint32_t insn;
|
||||||
int *invalid;
|
int *invalid;
|
||||||
{
|
{
|
||||||
return ((insn >> 11) & 0x1f) | ((insn << 4) & 0x20);
|
return ((insn >> 11) & 0x1f) | ((insn << 4) & 0x20);
|
||||||
@@ -1168,8 +1168,8 @@ extract_sh6 (insn, invalid)
|
|||||||
|
|
||||||
static unsigned long
|
static unsigned long
|
||||||
insert_spr (insn, value, errmsg)
|
insert_spr (insn, value, errmsg)
|
||||||
unsigned long insn;
|
uint32_t insn;
|
||||||
long value;
|
int32_t value;
|
||||||
const char **errmsg;
|
const char **errmsg;
|
||||||
{
|
{
|
||||||
return insn | ((value & 0x1f) << 16) | ((value & 0x3e0) << 6);
|
return insn | ((value & 0x1f) << 16) | ((value & 0x3e0) << 6);
|
||||||
@@ -1177,7 +1177,7 @@ insert_spr (insn, value, errmsg)
|
|||||||
|
|
||||||
static long
|
static long
|
||||||
extract_spr (insn, invalid)
|
extract_spr (insn, invalid)
|
||||||
unsigned long insn;
|
uint32_t insn;
|
||||||
int *invalid;
|
int *invalid;
|
||||||
{
|
{
|
||||||
return ((insn >> 16) & 0x1f) | ((insn >> 6) & 0x3e0);
|
return ((insn >> 16) & 0x1f) | ((insn >> 6) & 0x3e0);
|
||||||
@@ -1195,8 +1195,8 @@ extract_spr (insn, invalid)
|
|||||||
|
|
||||||
static unsigned long
|
static unsigned long
|
||||||
insert_tbr (insn, value, errmsg)
|
insert_tbr (insn, value, errmsg)
|
||||||
unsigned long insn;
|
uint32_t insn;
|
||||||
long value;
|
int32_t value;
|
||||||
const char **errmsg;
|
const char **errmsg;
|
||||||
{
|
{
|
||||||
if (value == 0)
|
if (value == 0)
|
||||||
@@ -1206,7 +1206,7 @@ insert_tbr (insn, value, errmsg)
|
|||||||
|
|
||||||
static long
|
static long
|
||||||
extract_tbr (insn, invalid)
|
extract_tbr (insn, invalid)
|
||||||
unsigned long insn;
|
uint32_t insn;
|
||||||
int *invalid;
|
int *invalid;
|
||||||
{
|
{
|
||||||
long ret;
|
long ret;
|
||||||
@@ -3067,27 +3067,30 @@ const struct powerpc_macro powerpc_macros[] = {
|
|||||||
const int powerpc_num_macros =
|
const int powerpc_num_macros =
|
||||||
sizeof (powerpc_macros) / sizeof (powerpc_macros[0]);
|
sizeof (powerpc_macros) / sizeof (powerpc_macros[0]);
|
||||||
|
|
||||||
static int print_insn_powerpc(FILE *, unsigned long insn, unsigned memaddr, int dialect);
|
static int print_insn_powerpc(FILE *, uint32_t insn, unsigned memaddr, int dialect);
|
||||||
|
|
||||||
/* Print a big endian PowerPC instruction. For convenience, also
|
/* Print a big endian PowerPC instruction. For convenience, also
|
||||||
disassemble instructions supported by the Motorola PowerPC 601. */
|
disassemble instructions supported by the Motorola PowerPC 601. */
|
||||||
|
#include "cpu.h"
|
||||||
|
|
||||||
int print_insn_ppc (bfd_vma pc, disassemble_info *info)
|
int print_insn_ppc (bfd_vma pc, disassemble_info *info)
|
||||||
{
|
{
|
||||||
return print_insn_powerpc (info->stream,
|
uint32_t opc;
|
||||||
(unsigned int)bfd_getb32((bfd_byte *)pc), pc,
|
|
||||||
PPC_OPCODE_PPC | PPC_OPCODE_601);
|
(*info->read_memory_func)(pc, (bfd_byte *)(&opc), 4, info);
|
||||||
|
return print_insn_powerpc (info->stream, tswap32(opc), pc,
|
||||||
|
PPC | B32 | M601);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Print a PowerPC or POWER instruction. */
|
/* Print a PowerPC or POWER instruction. */
|
||||||
|
|
||||||
static int
|
int
|
||||||
print_insn_powerpc (FILE *out, unsigned long insn, unsigned memaddr,
|
print_insn_powerpc (FILE *out, uint32_t insn, unsigned memaddr,
|
||||||
int dialect)
|
int dialect)
|
||||||
{
|
{
|
||||||
const struct powerpc_opcode *opcode;
|
const struct powerpc_opcode *opcode;
|
||||||
const struct powerpc_opcode *opcode_end;
|
const struct powerpc_opcode *opcode_end;
|
||||||
unsigned long op;
|
uint32_t op;
|
||||||
|
|
||||||
/* Get the major opcode of the instruction. */
|
/* Get the major opcode of the instruction. */
|
||||||
op = PPC_OP (insn);
|
op = PPC_OP (insn);
|
||||||
@@ -3097,7 +3100,7 @@ print_insn_powerpc (FILE *out, unsigned long insn, unsigned memaddr,
|
|||||||
opcode_end = powerpc_opcodes + powerpc_num_opcodes;
|
opcode_end = powerpc_opcodes + powerpc_num_opcodes;
|
||||||
for (opcode = powerpc_opcodes; opcode < opcode_end; opcode++)
|
for (opcode = powerpc_opcodes; opcode < opcode_end; opcode++)
|
||||||
{
|
{
|
||||||
unsigned long table_op;
|
uint32_t table_op;
|
||||||
const unsigned char *opindex;
|
const unsigned char *opindex;
|
||||||
const struct powerpc_operand *operand;
|
const struct powerpc_operand *operand;
|
||||||
int invalid;
|
int invalid;
|
||||||
@@ -3137,7 +3140,7 @@ print_insn_powerpc (FILE *out, unsigned long insn, unsigned memaddr,
|
|||||||
need_paren = 0;
|
need_paren = 0;
|
||||||
for (opindex = opcode->operands; *opindex != 0; opindex++)
|
for (opindex = opcode->operands; *opindex != 0; opindex++)
|
||||||
{
|
{
|
||||||
long value;
|
int32_t value;
|
||||||
|
|
||||||
operand = powerpc_operands + *opindex;
|
operand = powerpc_operands + *opindex;
|
||||||
|
|
||||||
@@ -3173,20 +3176,20 @@ print_insn_powerpc (FILE *out, unsigned long insn, unsigned memaddr,
|
|||||||
|
|
||||||
/* Print the operand as directed by the flags. */
|
/* Print the operand as directed by the flags. */
|
||||||
if ((operand->flags & PPC_OPERAND_GPR) != 0)
|
if ((operand->flags & PPC_OPERAND_GPR) != 0)
|
||||||
fprintf(out, "r%ld", value);
|
fprintf(out, "r%d", value);
|
||||||
else if ((operand->flags & PPC_OPERAND_FPR) != 0)
|
else if ((operand->flags & PPC_OPERAND_FPR) != 0)
|
||||||
fprintf(out, "f%ld", value);
|
fprintf(out, "f%d", value);
|
||||||
else if ((operand->flags & PPC_OPERAND_RELATIVE) != 0)
|
else if ((operand->flags & PPC_OPERAND_RELATIVE) != 0)
|
||||||
fprintf(out, "%08lX", memaddr + value);
|
fprintf(out, "%08X", memaddr + value);
|
||||||
else if ((operand->flags & PPC_OPERAND_ABSOLUTE) != 0)
|
else if ((operand->flags & PPC_OPERAND_ABSOLUTE) != 0)
|
||||||
fprintf(out, "%08lX", value & 0xffffffff);
|
fprintf(out, "%08X", value & 0xffffffff);
|
||||||
else if ((operand->flags & PPC_OPERAND_CR) == 0
|
else if ((operand->flags & PPC_OPERAND_CR) == 0
|
||||||
|| (dialect & PPC_OPCODE_PPC) == 0)
|
|| (dialect & PPC_OPCODE_PPC) == 0)
|
||||||
fprintf(out, "%ld", value);
|
fprintf(out, "%d", value);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (operand->bits == 3)
|
if (operand->bits == 3)
|
||||||
fprintf(out, "cr%ld", value);
|
fprintf(out, "cr%d", value);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
static const char *cbnames[4] = { "lt", "gt", "eq", "so" };
|
static const char *cbnames[4] = { "lt", "gt", "eq", "so" };
|
||||||
@@ -3226,7 +3229,7 @@ print_insn_powerpc (FILE *out, unsigned long insn, unsigned memaddr,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* We could not find a match. */
|
/* We could not find a match. */
|
||||||
fprintf(out, ".long 0x%lx", insn);
|
fprintf(out, ".long 0x%x", insn);
|
||||||
|
|
||||||
return 4;
|
return 4;
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# enable automatic i386/ARM/SPARC/PPC program execution by the kernel
|
||||||
|
|
||||||
|
# load the binfmt_misc module
|
||||||
|
/sbin/modprobe binfmt_misc
|
||||||
|
|
||||||
|
# probe cpu type
|
||||||
|
cpu=`uname -m`
|
||||||
|
case "$cpu" in
|
||||||
|
i386|i486|i586|i686|i86pc|BePC)
|
||||||
|
cpu="i386"
|
||||||
|
;;
|
||||||
|
"Power Macintosh"|ppc|ppc64)
|
||||||
|
cpu="ppc"
|
||||||
|
;;
|
||||||
|
armv4l)
|
||||||
|
cpu="arm"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# register the interpreter for each cpu except for the native one
|
||||||
|
if [ $cpu != "i386" ] ; then
|
||||||
|
echo ':i386:M::\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x03\x00:\xff\xff\xff\xff\xff\xfe\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfb\xff\xff\xff:/usr/local/bin/qemu-i386:' > /proc/sys/fs/binfmt_misc/register
|
||||||
|
echo ':i486:M::\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x06\x00:\xff\xff\xff\xff\xff\xfe\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfb\xff\xff\xff:/usr/local/bin/qemu-i386:' > /proc/sys/fs/binfmt_misc/register
|
||||||
|
fi
|
||||||
|
if [ $cpu != "arm" ] ; then
|
||||||
|
echo ':arm:M::\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x28\x00:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfb\xff\xff\xff:/usr/local/bin/qemu-arm:' > /proc/sys/fs/binfmt_misc/register
|
||||||
|
fi
|
||||||
|
if [ $cpu != "sparc" ] ; then
|
||||||
|
echo ':sparc:M::\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x02:\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfb\xff\xff\xff:/usr/local/bin/qemu-sparc:' > /proc/sys/fs/binfmt_misc/register
|
||||||
|
fi
|
||||||
|
if [ $cpu != "ppc" ] ; then
|
||||||
|
echo ':ppc:M::\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x14:\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfb\xff\xff\xff:/usr/local/bin/qemu-ppc:' > /proc/sys/fs/binfmt_misc/register
|
||||||
|
fi
|
||||||
+1012
-891
File diff suppressed because it is too large.
Load diff
+105
@@ -0,0 +1,105 @@
|
|||||||
|
.\" $Header: /home/paul/qemu/svnmerge/qemu-cvs/qemu/qemu-mkcow.1,v 1.1 2004-03-26 22:42:54 bellard Exp $
|
||||||
|
.\"
|
||||||
|
.\" transcript compatibility for postscript use.
|
||||||
|
.\"
|
||||||
|
.\" synopsis: .P! <file.ps>
|
||||||
|
.\"
|
||||||
|
.de P!
|
||||||
|
.fl
|
||||||
|
\!!1 setgray
|
||||||
|
.fl
|
||||||
|
\\&.\"
|
||||||
|
.fl
|
||||||
|
\!!0 setgray
|
||||||
|
.fl \" force out current output buffer
|
||||||
|
\!!save /psv exch def currentpoint translate 0 0 moveto
|
||||||
|
\!!/showpage{}def
|
||||||
|
.fl \" prolog
|
||||||
|
.sy sed -e 's/^/!/' \\$1\" bring in postscript file
|
||||||
|
\!!psv restore
|
||||||
|
.
|
||||||
|
.de pF
|
||||||
|
.ie \\*(f1 .ds f1 \\n(.f
|
||||||
|
.el .ie \\*(f2 .ds f2 \\n(.f
|
||||||
|
.el .ie \\*(f3 .ds f3 \\n(.f
|
||||||
|
.el .ie \\*(f4 .ds f4 \\n(.f
|
||||||
|
.el .tm ? font overflow
|
||||||
|
.ft \\$1
|
||||||
|
..
|
||||||
|
.de fP
|
||||||
|
.ie !\\*(f4 \{\
|
||||||
|
. ft \\*(f4
|
||||||
|
. ds f4\"
|
||||||
|
' br \}
|
||||||
|
.el .ie !\\*(f3 \{\
|
||||||
|
. ft \\*(f3
|
||||||
|
. ds f3\"
|
||||||
|
' br \}
|
||||||
|
.el .ie !\\*(f2 \{\
|
||||||
|
. ft \\*(f2
|
||||||
|
. ds f2\"
|
||||||
|
' br \}
|
||||||
|
.el .ie !\\*(f1 \{\
|
||||||
|
. ft \\*(f1
|
||||||
|
. ds f1\"
|
||||||
|
' br \}
|
||||||
|
.el .tm ? font underflow
|
||||||
|
..
|
||||||
|
.ds f1\"
|
||||||
|
.ds f2\"
|
||||||
|
.ds f3\"
|
||||||
|
.ds f4\"
|
||||||
|
'\" t
|
||||||
|
.ta 8n 16n 24n 32n 40n 48n 56n 64n 72n
|
||||||
|
.TH "QEMU" "8"
|
||||||
|
.SH "NAME"
|
||||||
|
qemu-mkcow \(em create a copy-on-write file for qemu
|
||||||
|
.SH "SYNOPSIS"
|
||||||
|
.PP
|
||||||
|
\fBqemu-mkcow\fR [\fB-h\fP] [\fB-f \fImaster_disk_image\fR\fP] [\fIcow_image\fR] [\fB\fIcow_size\fR\fP]
|
||||||
|
.SH "DESCRIPTION"
|
||||||
|
.PP
|
||||||
|
The \fBqemu-mkcow\fR command creates a
|
||||||
|
persistent copy-on-write file for \fBqemu\fR.
|
||||||
|
|
||||||
|
.PP
|
||||||
|
\fBqemu\fR can be used in a "copy-on-write" mode,
|
||||||
|
where changes made by \fBqemu\fR do not actually
|
||||||
|
change the disk image file. One way is to invoke
|
||||||
|
\fBqemu\fR with -snapshot: these changes
|
||||||
|
are stored in a temporary file, which is discarded when
|
||||||
|
\fBqemu\fR exits.
|
||||||
|
|
||||||
|
.PP
|
||||||
|
\fBqemu-mkcow\fR creates an explicit copy-on-write
|
||||||
|
file where changes are to be stored: this way, changes made
|
||||||
|
inside \fBqemu\fR will still be there next time you
|
||||||
|
run it, although the master disk image isn't ever changed.
|
||||||
|
|
||||||
|
.PP
|
||||||
|
The usual method is to create the master image, then create a
|
||||||
|
copy-on-write file using \fBqemu-mkcow\fR with
|
||||||
|
\fB-f\fP. The filename of the master image is stored
|
||||||
|
inside the generated copy-on-write file: it must not be modified
|
||||||
|
after this is run!
|
||||||
|
|
||||||
|
.PP
|
||||||
|
If no master file is specified, the effect is that of a
|
||||||
|
blank master of size \fIcow_size\fR.
|
||||||
|
|
||||||
|
.SH "SEE ALSO"
|
||||||
|
.PP
|
||||||
|
qemu(1), qemu-fast(1).
|
||||||
|
.SH "AUTHOR"
|
||||||
|
.PP
|
||||||
|
This manual page was written by Paul Russell prussell@debian.org for
|
||||||
|
the \fBDebian\fP system (but may be used by others). Permission is
|
||||||
|
granted to copy, distribute and/or modify this document under
|
||||||
|
the terms of the GNU General Public License, Version 2 any
|
||||||
|
later version published by the Free Software Foundation.
|
||||||
|
|
||||||
|
.PP
|
||||||
|
On Debian systems, the complete text of the GNU General Public
|
||||||
|
License can be found in /usr/share/common-licenses/GPL.
|
||||||
|
|
||||||
|
.\" created by instant / docbook-to-man, Fri 12 Mar 2004, 05:58
|
||||||
+17
-14
@@ -28,20 +28,15 @@
|
|||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <sys/mman.h>
|
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
#include <malloc.h>
|
|
||||||
#include <termios.h>
|
|
||||||
#include <sys/poll.h>
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <sys/wait.h>
|
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
|
|
||||||
#include "vl.h"
|
#include "cow.h"
|
||||||
|
|
||||||
#include "bswap.h"
|
#include "bswap.h"
|
||||||
|
|
||||||
@@ -85,8 +80,8 @@ int cow_create(int cow_fd, const char *image_filename,
|
|||||||
|
|
||||||
void help(void)
|
void help(void)
|
||||||
{
|
{
|
||||||
printf("vlmkcow version " QEMU_VERSION ", Copyright (c) 2003 Fabrice Bellard\n"
|
printf("qemu-mkcow version " QEMU_VERSION ", Copyright (c) 2003 Fabrice Bellard\n"
|
||||||
"usage: vlmkcow [-h] [-f disk_image] cow_image [cow_size]\n"
|
"usage: qemu-mkcow [-h] [-f disk_image] cow_image [cow_size]\n"
|
||||||
"Create a Copy On Write disk image from an optional raw disk image\n"
|
"Create a Copy On Write disk image from an optional raw disk image\n"
|
||||||
"\n"
|
"\n"
|
||||||
"-f disk_image set the raw disk image name\n"
|
"-f disk_image set the raw disk image name\n"
|
||||||
@@ -101,13 +96,14 @@ void help(void)
|
|||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
const char *image_filename, *cow_filename;
|
const char *image_filename, *cow_filename;
|
||||||
int cow_fd, c, nb_args;
|
int cow_fd, c, nb_args, simple_image;
|
||||||
int64_t image_size;
|
int64_t image_size;
|
||||||
|
|
||||||
image_filename = NULL;
|
image_filename = NULL;
|
||||||
image_size = 0;
|
image_size = 0;
|
||||||
|
simple_image = 0;
|
||||||
for(;;) {
|
for(;;) {
|
||||||
c = getopt(argc, argv, "hf:");
|
c = getopt(argc, argv, "hf:s");
|
||||||
if (c == -1)
|
if (c == -1)
|
||||||
break;
|
break;
|
||||||
switch(c) {
|
switch(c) {
|
||||||
@@ -117,6 +113,9 @@ int main(int argc, char **argv)
|
|||||||
case 'f':
|
case 'f':
|
||||||
image_filename = optarg;
|
image_filename = optarg;
|
||||||
break;
|
break;
|
||||||
|
case 's':
|
||||||
|
simple_image = 1;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!image_filename)
|
if (!image_filename)
|
||||||
@@ -131,12 +130,16 @@ int main(int argc, char **argv)
|
|||||||
image_size = (int64_t)atoi(argv[optind + 1]) * 2 * 1024;
|
image_size = (int64_t)atoi(argv[optind + 1]) * 2 * 1024;
|
||||||
}
|
}
|
||||||
|
|
||||||
cow_fd = open(cow_filename, O_RDWR | O_CREAT | O_TRUNC, 0644);
|
cow_fd = open(cow_filename, O_RDWR | O_CREAT | O_TRUNC | O_LARGEFILE, 0644);
|
||||||
if (!cow_fd < 0)
|
if (!cow_fd < 0)
|
||||||
return -1;
|
return -1;
|
||||||
if (cow_create(cow_fd, image_filename, image_size) < 0) {
|
if (simple_image) {
|
||||||
fprintf(stderr, "%s: error while formating\n", cow_filename);
|
ftruncate64(cow_fd, image_size * 512);
|
||||||
exit(1);
|
} else {
|
||||||
|
if (cow_create(cow_fd, image_filename, image_size) < 0) {
|
||||||
|
fprintf(stderr, "%s: error while formating\n", cow_filename);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
close(cow_fd);
|
close(cow_fd);
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
+494
@@ -0,0 +1,494 @@
|
|||||||
|
\input texinfo @c -*- texinfo -*-
|
||||||
|
|
||||||
|
@iftex
|
||||||
|
@settitle QEMU Internals
|
||||||
|
@titlepage
|
||||||
|
@sp 7
|
||||||
|
@center @titlefont{QEMU Internals}
|
||||||
|
@sp 3
|
||||||
|
@end titlepage
|
||||||
|
@end iftex
|
||||||
|
|
||||||
|
@chapter Introduction
|
||||||
|
|
||||||
|
@section Features
|
||||||
|
|
||||||
|
QEMU is a FAST! processor emulator using a portable dynamic
|
||||||
|
translator.
|
||||||
|
|
||||||
|
QEMU has two operating modes:
|
||||||
|
|
||||||
|
@itemize @minus
|
||||||
|
|
||||||
|
@item
|
||||||
|
Full system emulation. In this mode, QEMU emulates a full system
|
||||||
|
(usually a PC), including a processor and various peripherials. It can
|
||||||
|
be used to launch an different Operating System without rebooting the
|
||||||
|
PC or to debug system code.
|
||||||
|
|
||||||
|
@item
|
||||||
|
User mode emulation (Linux host only). In this mode, QEMU can launch
|
||||||
|
Linux processes compiled for one CPU on another CPU. It can be used to
|
||||||
|
launch the Wine Windows API emulator (@url{http://www.winehq.org}) or
|
||||||
|
to ease cross-compilation and cross-debugging.
|
||||||
|
|
||||||
|
@end itemize
|
||||||
|
|
||||||
|
As QEMU requires no host kernel driver to run, it is very safe and
|
||||||
|
easy to use.
|
||||||
|
|
||||||
|
QEMU generic features:
|
||||||
|
|
||||||
|
@itemize
|
||||||
|
|
||||||
|
@item User space only or full system emulation.
|
||||||
|
|
||||||
|
@item Using dynamic translation to native code for reasonnable speed.
|
||||||
|
|
||||||
|
@item Working on x86 and PowerPC hosts. Being tested on ARM, Sparc32, Alpha and S390.
|
||||||
|
|
||||||
|
@item Self-modifying code support.
|
||||||
|
|
||||||
|
@item Precise exceptions support.
|
||||||
|
|
||||||
|
@item The virtual CPU is a library (@code{libqemu}) which can be used
|
||||||
|
in other projects (look at @file{qemu/tests/qruncom.c} to have an
|
||||||
|
example of user mode @code{libqemu} usage).
|
||||||
|
|
||||||
|
@end itemize
|
||||||
|
|
||||||
|
QEMU user mode emulation features:
|
||||||
|
@itemize
|
||||||
|
@item Generic Linux system call converter, including most ioctls.
|
||||||
|
|
||||||
|
@item clone() emulation using native CPU clone() to use Linux scheduler for threads.
|
||||||
|
|
||||||
|
@item Accurate signal handling by remapping host signals to target signals.
|
||||||
|
@end itemize
|
||||||
|
@end itemize
|
||||||
|
|
||||||
|
QEMU full system emulation features:
|
||||||
|
@itemize
|
||||||
|
@item QEMU can either use a full software MMU for maximum portability or use the host system call mmap() to simulate the target MMU.
|
||||||
|
@end itemize
|
||||||
|
|
||||||
|
@section x86 emulation
|
||||||
|
|
||||||
|
QEMU x86 target features:
|
||||||
|
|
||||||
|
@itemize
|
||||||
|
|
||||||
|
@item The virtual x86 CPU supports 16 bit and 32 bit addressing with segmentation.
|
||||||
|
LDT/GDT and IDT are emulated. VM86 mode is also supported to run DOSEMU.
|
||||||
|
|
||||||
|
@item Support of host page sizes bigger than 4KB in user mode emulation.
|
||||||
|
|
||||||
|
@item QEMU can emulate itself on x86.
|
||||||
|
|
||||||
|
@item An extensive Linux x86 CPU test program is included @file{tests/test-i386}.
|
||||||
|
It can be used to test other x86 virtual CPUs.
|
||||||
|
|
||||||
|
@end itemize
|
||||||
|
|
||||||
|
Current QEMU limitations:
|
||||||
|
|
||||||
|
@itemize
|
||||||
|
|
||||||
|
@item No SSE/MMX support (yet).
|
||||||
|
|
||||||
|
@item No x86-64 support.
|
||||||
|
|
||||||
|
@item IPC syscalls are missing.
|
||||||
|
|
||||||
|
@item The x86 segment limits and access rights are not tested at every
|
||||||
|
memory access (yet). Hopefully, very few OSes seem to rely on that for
|
||||||
|
normal use.
|
||||||
|
|
||||||
|
@item On non x86 host CPUs, @code{double}s are used instead of the non standard
|
||||||
|
10 byte @code{long double}s of x86 for floating point emulation to get
|
||||||
|
maximum performances.
|
||||||
|
|
||||||
|
@end itemize
|
||||||
|
|
||||||
|
@section ARM emulation
|
||||||
|
|
||||||
|
@itemize
|
||||||
|
|
||||||
|
@item Full ARM 7 user emulation.
|
||||||
|
|
||||||
|
@item NWFPE FPU support included in user Linux emulation.
|
||||||
|
|
||||||
|
@item Can run most ARM Linux binaries.
|
||||||
|
|
||||||
|
@end itemize
|
||||||
|
|
||||||
|
@section PowerPC emulation
|
||||||
|
|
||||||
|
@itemize
|
||||||
|
|
||||||
|
@item Full PowerPC 32 bit emulation, including priviledged instructions,
|
||||||
|
FPU and MMU.
|
||||||
|
|
||||||
|
@item Can run most PowerPC Linux binaries.
|
||||||
|
|
||||||
|
@end itemize
|
||||||
|
|
||||||
|
@section SPARC emulation
|
||||||
|
|
||||||
|
@itemize
|
||||||
|
|
||||||
|
@item SPARC V8 user support, except FPU instructions.
|
||||||
|
|
||||||
|
@item Can run some SPARC Linux binaries.
|
||||||
|
|
||||||
|
@end itemize
|
||||||
|
|
||||||
|
@chapter QEMU Internals
|
||||||
|
|
||||||
|
@section QEMU compared to other emulators
|
||||||
|
|
||||||
|
Like bochs [3], QEMU emulates an x86 CPU. But QEMU is much faster than
|
||||||
|
bochs as it uses dynamic compilation. Bochs is closely tied to x86 PC
|
||||||
|
emulation while QEMU can emulate several processors.
|
||||||
|
|
||||||
|
Like Valgrind [2], QEMU does user space emulation and dynamic
|
||||||
|
translation. Valgrind is mainly a memory debugger while QEMU has no
|
||||||
|
support for it (QEMU could be used to detect out of bound memory
|
||||||
|
accesses as Valgrind, but it has no support to track uninitialised data
|
||||||
|
as Valgrind does). The Valgrind dynamic translator generates better code
|
||||||
|
than QEMU (in particular it does register allocation) but it is closely
|
||||||
|
tied to an x86 host and target and has no support for precise exceptions
|
||||||
|
and system emulation.
|
||||||
|
|
||||||
|
EM86 [4] is the closest project to user space QEMU (and QEMU still uses
|
||||||
|
some of its code, in particular the ELF file loader). EM86 was limited
|
||||||
|
to an alpha host and used a proprietary and slow interpreter (the
|
||||||
|
interpreter part of the FX!32 Digital Win32 code translator [5]).
|
||||||
|
|
||||||
|
TWIN [6] is a Windows API emulator like Wine. It is less accurate than
|
||||||
|
Wine but includes a protected mode x86 interpreter to launch x86 Windows
|
||||||
|
executables. Such an approach as greater potential because most of the
|
||||||
|
Windows API is executed natively but it is far more difficult to develop
|
||||||
|
because all the data structures and function parameters exchanged
|
||||||
|
between the API and the x86 code must be converted.
|
||||||
|
|
||||||
|
User mode Linux [7] was the only solution before QEMU to launch a
|
||||||
|
Linux kernel as a process while not needing any host kernel
|
||||||
|
patches. However, user mode Linux requires heavy kernel patches while
|
||||||
|
QEMU accepts unpatched Linux kernels. The price to pay is that QEMU is
|
||||||
|
slower.
|
||||||
|
|
||||||
|
The new Plex86 [8] PC virtualizer is done in the same spirit as the
|
||||||
|
qemu-fast system emulator. It requires a patched Linux kernel to work
|
||||||
|
(you cannot launch the same kernel on your PC), but the patches are
|
||||||
|
really small. As it is a PC virtualizer (no emulation is done except
|
||||||
|
for some priveledged instructions), it has the potential of being
|
||||||
|
faster than QEMU. The downside is that a complicated (and potentially
|
||||||
|
unsafe) host kernel patch is needed.
|
||||||
|
|
||||||
|
The commercial PC Virtualizers (VMWare [9], VirtualPC [10], TwoOStwo
|
||||||
|
[11]) are faster than QEMU, but they all need specific, proprietary
|
||||||
|
and potentially unsafe host drivers. Moreover, they are unable to
|
||||||
|
provide cycle exact simulation as an emulator can.
|
||||||
|
|
||||||
|
@section Portable dynamic translation
|
||||||
|
|
||||||
|
QEMU is a dynamic translator. When it first encounters a piece of code,
|
||||||
|
it converts it to the host instruction set. Usually dynamic translators
|
||||||
|
are very complicated and highly CPU dependent. QEMU uses some tricks
|
||||||
|
which make it relatively easily portable and simple while achieving good
|
||||||
|
performances.
|
||||||
|
|
||||||
|
The basic idea is to split every x86 instruction into fewer simpler
|
||||||
|
instructions. Each simple instruction is implemented by a piece of C
|
||||||
|
code (see @file{target-i386/op.c}). Then a compile time tool
|
||||||
|
(@file{dyngen}) takes the corresponding object file (@file{op.o})
|
||||||
|
to generate a dynamic code generator which concatenates the simple
|
||||||
|
instructions to build a function (see @file{op.h:dyngen_code()}).
|
||||||
|
|
||||||
|
In essence, the process is similar to [1], but more work is done at
|
||||||
|
compile time.
|
||||||
|
|
||||||
|
A key idea to get optimal performances is that constant parameters can
|
||||||
|
be passed to the simple operations. For that purpose, dummy ELF
|
||||||
|
relocations are generated with gcc for each constant parameter. Then,
|
||||||
|
the tool (@file{dyngen}) can locate the relocations and generate the
|
||||||
|
appriopriate C code to resolve them when building the dynamic code.
|
||||||
|
|
||||||
|
That way, QEMU is no more difficult to port than a dynamic linker.
|
||||||
|
|
||||||
|
To go even faster, GCC static register variables are used to keep the
|
||||||
|
state of the virtual CPU.
|
||||||
|
|
||||||
|
@section Register allocation
|
||||||
|
|
||||||
|
Since QEMU uses fixed simple instructions, no efficient register
|
||||||
|
allocation can be done. However, because RISC CPUs have a lot of
|
||||||
|
register, most of the virtual CPU state can be put in registers without
|
||||||
|
doing complicated register allocation.
|
||||||
|
|
||||||
|
@section Condition code optimisations
|
||||||
|
|
||||||
|
Good CPU condition codes emulation (@code{EFLAGS} register on x86) is a
|
||||||
|
critical point to get good performances. QEMU uses lazy condition code
|
||||||
|
evaluation: instead of computing the condition codes after each x86
|
||||||
|
instruction, it just stores one operand (called @code{CC_SRC}), the
|
||||||
|
result (called @code{CC_DST}) and the type of operation (called
|
||||||
|
@code{CC_OP}).
|
||||||
|
|
||||||
|
@code{CC_OP} is almost never explicitely set in the generated code
|
||||||
|
because it is known at translation time.
|
||||||
|
|
||||||
|
In order to increase performances, a backward pass is performed on the
|
||||||
|
generated simple instructions (see
|
||||||
|
@code{target-i386/translate.c:optimize_flags()}). When it can be proved that
|
||||||
|
the condition codes are not needed by the next instructions, no
|
||||||
|
condition codes are computed at all.
|
||||||
|
|
||||||
|
@section CPU state optimisations
|
||||||
|
|
||||||
|
The x86 CPU has many internal states which change the way it evaluates
|
||||||
|
instructions. In order to achieve a good speed, the translation phase
|
||||||
|
considers that some state information of the virtual x86 CPU cannot
|
||||||
|
change in it. For example, if the SS, DS and ES segments have a zero
|
||||||
|
base, then the translator does not even generate an addition for the
|
||||||
|
segment base.
|
||||||
|
|
||||||
|
[The FPU stack pointer register is not handled that way yet].
|
||||||
|
|
||||||
|
@section Translation cache
|
||||||
|
|
||||||
|
A 16 MByte cache holds the most recently used translations. For
|
||||||
|
simplicity, it is completely flushed when it is full. A translation unit
|
||||||
|
contains just a single basic block (a block of x86 instructions
|
||||||
|
terminated by a jump or by a virtual CPU state change which the
|
||||||
|
translator cannot deduce statically).
|
||||||
|
|
||||||
|
@section Direct block chaining
|
||||||
|
|
||||||
|
After each translated basic block is executed, QEMU uses the simulated
|
||||||
|
Program Counter (PC) and other cpu state informations (such as the CS
|
||||||
|
segment base value) to find the next basic block.
|
||||||
|
|
||||||
|
In order to accelerate the most common cases where the new simulated PC
|
||||||
|
is known, QEMU can patch a basic block so that it jumps directly to the
|
||||||
|
next one.
|
||||||
|
|
||||||
|
The most portable code uses an indirect jump. An indirect jump makes
|
||||||
|
it easier to make the jump target modification atomic. On some host
|
||||||
|
architectures (such as x86 or PowerPC), the @code{JUMP} opcode is
|
||||||
|
directly patched so that the block chaining has no overhead.
|
||||||
|
|
||||||
|
@section Self-modifying code and translated code invalidation
|
||||||
|
|
||||||
|
Self-modifying code is a special challenge in x86 emulation because no
|
||||||
|
instruction cache invalidation is signaled by the application when code
|
||||||
|
is modified.
|
||||||
|
|
||||||
|
When translated code is generated for a basic block, the corresponding
|
||||||
|
host page is write protected if it is not already read-only (with the
|
||||||
|
system call @code{mprotect()}). Then, if a write access is done to the
|
||||||
|
page, Linux raises a SEGV signal. QEMU then invalidates all the
|
||||||
|
translated code in the page and enables write accesses to the page.
|
||||||
|
|
||||||
|
Correct translated code invalidation is done efficiently by maintaining
|
||||||
|
a linked list of every translated block contained in a given page. Other
|
||||||
|
linked lists are also maintained to undo direct block chaining.
|
||||||
|
|
||||||
|
Although the overhead of doing @code{mprotect()} calls is important,
|
||||||
|
most MSDOS programs can be emulated at reasonnable speed with QEMU and
|
||||||
|
DOSEMU.
|
||||||
|
|
||||||
|
Note that QEMU also invalidates pages of translated code when it detects
|
||||||
|
that memory mappings are modified with @code{mmap()} or @code{munmap()}.
|
||||||
|
|
||||||
|
When using a software MMU, the code invalidation is more efficient: if
|
||||||
|
a given code page is invalidated too often because of write accesses,
|
||||||
|
then a bitmap representing all the code inside the page is
|
||||||
|
built. Every store into that page checks the bitmap to see if the code
|
||||||
|
really needs to be invalidated. It avoids invalidating the code when
|
||||||
|
only data is modified in the page.
|
||||||
|
|
||||||
|
@section Exception support
|
||||||
|
|
||||||
|
longjmp() is used when an exception such as division by zero is
|
||||||
|
encountered.
|
||||||
|
|
||||||
|
The host SIGSEGV and SIGBUS signal handlers are used to get invalid
|
||||||
|
memory accesses. The exact CPU state can be retrieved because all the
|
||||||
|
x86 registers are stored in fixed host registers. The simulated program
|
||||||
|
counter is found by retranslating the corresponding basic block and by
|
||||||
|
looking where the host program counter was at the exception point.
|
||||||
|
|
||||||
|
The virtual CPU cannot retrieve the exact @code{EFLAGS} register because
|
||||||
|
in some cases it is not computed because of condition code
|
||||||
|
optimisations. It is not a big concern because the emulated code can
|
||||||
|
still be restarted in any cases.
|
||||||
|
|
||||||
|
@section MMU emulation
|
||||||
|
|
||||||
|
For system emulation, QEMU uses the mmap() system call to emulate the
|
||||||
|
target CPU MMU. It works as long the emulated OS does not use an area
|
||||||
|
reserved by the host OS (such as the area above 0xc0000000 on x86
|
||||||
|
Linux).
|
||||||
|
|
||||||
|
In order to be able to launch any OS, QEMU also supports a soft
|
||||||
|
MMU. In that mode, the MMU virtual to physical address translation is
|
||||||
|
done at every memory access. QEMU uses an address translation cache to
|
||||||
|
speed up the translation.
|
||||||
|
|
||||||
|
In order to avoid flushing the translated code each time the MMU
|
||||||
|
mappings change, QEMU uses a physically indexed translation cache. It
|
||||||
|
means that each basic block is indexed with its physical address.
|
||||||
|
|
||||||
|
When MMU mappings change, only the chaining of the basic blocks is
|
||||||
|
reset (i.e. a basic block can no longer jump directly to another one).
|
||||||
|
|
||||||
|
@section Hardware interrupts
|
||||||
|
|
||||||
|
In order to be faster, QEMU does not check at every basic block if an
|
||||||
|
hardware interrupt is pending. Instead, the user must asynchrously
|
||||||
|
call a specific function to tell that an interrupt is pending. This
|
||||||
|
function resets the chaining of the currently executing basic
|
||||||
|
block. It ensures that the execution will return soon in the main loop
|
||||||
|
of the CPU emulator. Then the main loop can test if the interrupt is
|
||||||
|
pending and handle it.
|
||||||
|
|
||||||
|
@section User emulation specific details
|
||||||
|
|
||||||
|
@subsection Linux system call translation
|
||||||
|
|
||||||
|
QEMU includes a generic system call translator for Linux. It means that
|
||||||
|
the parameters of the system calls can be converted to fix the
|
||||||
|
endianness and 32/64 bit issues. The IOCTLs are converted with a generic
|
||||||
|
type description system (see @file{ioctls.h} and @file{thunk.c}).
|
||||||
|
|
||||||
|
QEMU supports host CPUs which have pages bigger than 4KB. It records all
|
||||||
|
the mappings the process does and try to emulated the @code{mmap()}
|
||||||
|
system calls in cases where the host @code{mmap()} call would fail
|
||||||
|
because of bad page alignment.
|
||||||
|
|
||||||
|
@subsection Linux signals
|
||||||
|
|
||||||
|
Normal and real-time signals are queued along with their information
|
||||||
|
(@code{siginfo_t}) as it is done in the Linux kernel. Then an interrupt
|
||||||
|
request is done to the virtual CPU. When it is interrupted, one queued
|
||||||
|
signal is handled by generating a stack frame in the virtual CPU as the
|
||||||
|
Linux kernel does. The @code{sigreturn()} system call is emulated to return
|
||||||
|
from the virtual signal handler.
|
||||||
|
|
||||||
|
Some signals (such as SIGALRM) directly come from the host. Other
|
||||||
|
signals are synthetized from the virtual CPU exceptions such as SIGFPE
|
||||||
|
when a division by zero is done (see @code{main.c:cpu_loop()}).
|
||||||
|
|
||||||
|
The blocked signal mask is still handled by the host Linux kernel so
|
||||||
|
that most signal system calls can be redirected directly to the host
|
||||||
|
Linux kernel. Only the @code{sigaction()} and @code{sigreturn()} system
|
||||||
|
calls need to be fully emulated (see @file{signal.c}).
|
||||||
|
|
||||||
|
@subsection clone() system call and threads
|
||||||
|
|
||||||
|
The Linux clone() system call is usually used to create a thread. QEMU
|
||||||
|
uses the host clone() system call so that real host threads are created
|
||||||
|
for each emulated thread. One virtual CPU instance is created for each
|
||||||
|
thread.
|
||||||
|
|
||||||
|
The virtual x86 CPU atomic operations are emulated with a global lock so
|
||||||
|
that their semantic is preserved.
|
||||||
|
|
||||||
|
Note that currently there are still some locking issues in QEMU. In
|
||||||
|
particular, the translated cache flush is not protected yet against
|
||||||
|
reentrancy.
|
||||||
|
|
||||||
|
@subsection Self-virtualization
|
||||||
|
|
||||||
|
QEMU was conceived so that ultimately it can emulate itself. Although
|
||||||
|
it is not very useful, it is an important test to show the power of the
|
||||||
|
emulator.
|
||||||
|
|
||||||
|
Achieving self-virtualization is not easy because there may be address
|
||||||
|
space conflicts. QEMU solves this problem by being an executable ELF
|
||||||
|
shared object as the ld-linux.so ELF interpreter. That way, it can be
|
||||||
|
relocated at load time.
|
||||||
|
|
||||||
|
@section Bibliography
|
||||||
|
|
||||||
|
@table @asis
|
||||||
|
|
||||||
|
@item [1]
|
||||||
|
@url{http://citeseer.nj.nec.com/piumarta98optimizing.html}, Optimizing
|
||||||
|
direct threaded code by selective inlining (1998) by Ian Piumarta, Fabio
|
||||||
|
Riccardi.
|
||||||
|
|
||||||
|
@item [2]
|
||||||
|
@url{http://developer.kde.org/~sewardj/}, Valgrind, an open-source
|
||||||
|
memory debugger for x86-GNU/Linux, by Julian Seward.
|
||||||
|
|
||||||
|
@item [3]
|
||||||
|
@url{http://bochs.sourceforge.net/}, the Bochs IA-32 Emulator Project,
|
||||||
|
by Kevin Lawton et al.
|
||||||
|
|
||||||
|
@item [4]
|
||||||
|
@url{http://www.cs.rose-hulman.edu/~donaldlf/em86/index.html}, the EM86
|
||||||
|
x86 emulator on Alpha-Linux.
|
||||||
|
|
||||||
|
@item [5]
|
||||||
|
@url{http://www.usenix.org/publications/library/proceedings/usenix-nt97/full_papers/chernoff/chernoff.pdf},
|
||||||
|
DIGITAL FX!32: Running 32-Bit x86 Applications on Alpha NT, by Anton
|
||||||
|
Chernoff and Ray Hookway.
|
||||||
|
|
||||||
|
@item [6]
|
||||||
|
@url{http://www.willows.com/}, Windows API library emulation from
|
||||||
|
Willows Software.
|
||||||
|
|
||||||
|
@item [7]
|
||||||
|
@url{http://user-mode-linux.sourceforge.net/},
|
||||||
|
The User-mode Linux Kernel.
|
||||||
|
|
||||||
|
@item [8]
|
||||||
|
@url{http://www.plex86.org/},
|
||||||
|
The new Plex86 project.
|
||||||
|
|
||||||
|
@item [9]
|
||||||
|
@url{http://www.vmware.com/},
|
||||||
|
The VMWare PC virtualizer.
|
||||||
|
|
||||||
|
@item [10]
|
||||||
|
@url{http://www.microsoft.com/windowsxp/virtualpc/},
|
||||||
|
The VirtualPC PC virtualizer.
|
||||||
|
|
||||||
|
@item [11]
|
||||||
|
@url{http://www.twoostwo.org/},
|
||||||
|
The TwoOStwo PC virtualizer.
|
||||||
|
|
||||||
|
@end table
|
||||||
|
|
||||||
|
@chapter Regression Tests
|
||||||
|
|
||||||
|
In the directory @file{tests/}, various interesting testing programs
|
||||||
|
are available. There are used for regression testing.
|
||||||
|
|
||||||
|
@section @file{test-i386}
|
||||||
|
|
||||||
|
This program executes most of the 16 bit and 32 bit x86 instructions and
|
||||||
|
generates a text output. It can be compared with the output obtained with
|
||||||
|
a real CPU or another emulator. The target @code{make test} runs this
|
||||||
|
program and a @code{diff} on the generated output.
|
||||||
|
|
||||||
|
The Linux system call @code{modify_ldt()} is used to create x86 selectors
|
||||||
|
to test some 16 bit addressing and 32 bit with segmentation cases.
|
||||||
|
|
||||||
|
The Linux system call @code{vm86()} is used to test vm86 emulation.
|
||||||
|
|
||||||
|
Various exceptions are raised to test most of the x86 user space
|
||||||
|
exception reporting.
|
||||||
|
|
||||||
|
@section @file{linux-test}
|
||||||
|
|
||||||
|
This program tests various Linux system calls. It is used to verify
|
||||||
|
that the system call parameters are correctly converted between target
|
||||||
|
and host CPUs.
|
||||||
|
|
||||||
|
@section @file{qruncom.c}
|
||||||
|
|
||||||
|
Example of usage of @code{libqemu} to emulate a user mode i386 CPU.
|
||||||
@@ -21,37 +21,29 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
#include <stdlib.h>
|
#include "vl.h"
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <getopt.h>
|
|
||||||
#include <inttypes.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <sys/mman.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <signal.h>
|
|
||||||
#include <time.h>
|
|
||||||
#include <sys/time.h>
|
|
||||||
#include <malloc.h>
|
|
||||||
#include <termios.h>
|
|
||||||
#include <sys/poll.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <sys/wait.h>
|
|
||||||
#include <netinet/in.h>
|
|
||||||
|
|
||||||
#include <SDL.h>
|
#include <SDL.h>
|
||||||
|
|
||||||
#include "cpu.h"
|
#ifndef _WIN32
|
||||||
#include "exec-all.h"
|
#include <signal.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "vl.h"
|
#if defined(__APPLE__)
|
||||||
|
#define CONFIG_SDL_GENERIC_KBD
|
||||||
|
#endif
|
||||||
|
|
||||||
static SDL_Surface *screen;
|
static SDL_Surface *screen;
|
||||||
static int gui_grab; /* if true, all keyboard/mouse events are grabbed */
|
static int gui_grab; /* if true, all keyboard/mouse events are grabbed */
|
||||||
|
static int last_vm_running;
|
||||||
|
static int gui_saved_grab;
|
||||||
|
static int gui_fullscreen;
|
||||||
|
static int gui_key_modifier_pressed;
|
||||||
|
static int gui_keysym;
|
||||||
|
|
||||||
static void sdl_update(DisplayState *ds, int x, int y, int w, int h)
|
static void sdl_update(DisplayState *ds, int x, int y, int w, int h)
|
||||||
{
|
{
|
||||||
|
// printf("updating x=%d y=%d w=%d h=%d\n", x, y, w, h);
|
||||||
SDL_UpdateRect(screen, x, y, w, h);
|
SDL_UpdateRect(screen, x, y, w, h);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -63,6 +55,8 @@ static void sdl_resize(DisplayState *ds, int w, int h)
|
|||||||
|
|
||||||
flags = SDL_HWSURFACE|SDL_ASYNCBLIT|SDL_HWACCEL;
|
flags = SDL_HWSURFACE|SDL_ASYNCBLIT|SDL_HWACCEL;
|
||||||
flags |= SDL_RESIZABLE;
|
flags |= SDL_RESIZABLE;
|
||||||
|
if (gui_fullscreen)
|
||||||
|
flags |= SDL_FULLSCREEN;
|
||||||
screen = SDL_SetVideoMode(w, h, 0, flags);
|
screen = SDL_SetVideoMode(w, h, 0, flags);
|
||||||
if (!screen) {
|
if (!screen) {
|
||||||
fprintf(stderr, "Could not open SDL display\n");
|
fprintf(stderr, "Could not open SDL display\n");
|
||||||
@@ -73,44 +67,164 @@ static void sdl_resize(DisplayState *ds, int w, int h)
|
|||||||
ds->depth = screen->format->BitsPerPixel;
|
ds->depth = screen->format->BitsPerPixel;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const uint32_t x_keycode_to_pc_keycode[61] = {
|
#ifdef CONFIG_SDL_GENERIC_KBD
|
||||||
0x47e0, /* 97 Home */
|
|
||||||
0x48e0, /* 98 Up */
|
/* XXX: use keymap tables defined in the VNC patch because the
|
||||||
0x49e0, /* 99 PgUp */
|
following code suppose you have a US keyboard. */
|
||||||
0x4be0, /* 100 Left */
|
|
||||||
|
static const uint8_t scancodes[SDLK_LAST] = {
|
||||||
|
[SDLK_ESCAPE] = 0x01,
|
||||||
|
[SDLK_1] = 0x02,
|
||||||
|
[SDLK_2] = 0x03,
|
||||||
|
[SDLK_3] = 0x04,
|
||||||
|
[SDLK_4] = 0x05,
|
||||||
|
[SDLK_5] = 0x06,
|
||||||
|
[SDLK_6] = 0x07,
|
||||||
|
[SDLK_7] = 0x08,
|
||||||
|
[SDLK_8] = 0x09,
|
||||||
|
[SDLK_9] = 0x0a,
|
||||||
|
[SDLK_0] = 0x0b,
|
||||||
|
[SDLK_MINUS] = 0x0c,
|
||||||
|
[SDLK_EQUALS] = 0x0d,
|
||||||
|
[SDLK_BACKSPACE] = 0x0e,
|
||||||
|
[SDLK_TAB] = 0x0f,
|
||||||
|
[SDLK_q] = 0x10,
|
||||||
|
[SDLK_w] = 0x11,
|
||||||
|
[SDLK_e] = 0x12,
|
||||||
|
[SDLK_r] = 0x13,
|
||||||
|
[SDLK_t] = 0x14,
|
||||||
|
[SDLK_y] = 0x15,
|
||||||
|
[SDLK_u] = 0x16,
|
||||||
|
[SDLK_i] = 0x17,
|
||||||
|
[SDLK_o] = 0x18,
|
||||||
|
[SDLK_p] = 0x19,
|
||||||
|
[SDLK_LEFTBRACKET] = 0x1a,
|
||||||
|
[SDLK_RIGHTBRACKET] = 0x1b,
|
||||||
|
[SDLK_RETURN] = 0x1c,
|
||||||
|
[SDLK_LCTRL] = 0x1d,
|
||||||
|
[SDLK_a] = 0x1e,
|
||||||
|
[SDLK_s] = 0x1f,
|
||||||
|
[SDLK_d] = 0x20,
|
||||||
|
[SDLK_f] = 0x21,
|
||||||
|
[SDLK_g] = 0x22,
|
||||||
|
[SDLK_h] = 0x23,
|
||||||
|
[SDLK_j] = 0x24,
|
||||||
|
[SDLK_k] = 0x25,
|
||||||
|
[SDLK_l] = 0x26,
|
||||||
|
[SDLK_SEMICOLON] = 0x27,
|
||||||
|
[SDLK_QUOTE] = 0x28,
|
||||||
|
[SDLK_BACKQUOTE] = 0x29,
|
||||||
|
[SDLK_LSHIFT] = 0x2a,
|
||||||
|
[SDLK_BACKSLASH] = 0x2b,
|
||||||
|
[SDLK_z] = 0x2c,
|
||||||
|
[SDLK_x] = 0x2d,
|
||||||
|
[SDLK_c] = 0x2e,
|
||||||
|
[SDLK_v] = 0x2f,
|
||||||
|
[SDLK_b] = 0x30,
|
||||||
|
[SDLK_n] = 0x31,
|
||||||
|
[SDLK_m] = 0x32,
|
||||||
|
[SDLK_COMMA] = 0x33,
|
||||||
|
[SDLK_PERIOD] = 0x34,
|
||||||
|
[SDLK_SLASH] = 0x35,
|
||||||
|
[SDLK_KP_MULTIPLY] = 0x37,
|
||||||
|
[SDLK_LALT] = 0x38,
|
||||||
|
[SDLK_SPACE] = 0x39,
|
||||||
|
[SDLK_CAPSLOCK] = 0x3a,
|
||||||
|
[SDLK_F1] = 0x3b,
|
||||||
|
[SDLK_F2] = 0x3c,
|
||||||
|
[SDLK_F3] = 0x3d,
|
||||||
|
[SDLK_F4] = 0x3e,
|
||||||
|
[SDLK_F5] = 0x3f,
|
||||||
|
[SDLK_F6] = 0x40,
|
||||||
|
[SDLK_F7] = 0x41,
|
||||||
|
[SDLK_F8] = 0x42,
|
||||||
|
[SDLK_F9] = 0x43,
|
||||||
|
[SDLK_F10] = 0x44,
|
||||||
|
[SDLK_NUMLOCK] = 0x45,
|
||||||
|
[SDLK_SCROLLOCK] = 0x46,
|
||||||
|
[SDLK_KP7] = 0x47,
|
||||||
|
[SDLK_KP8] = 0x48,
|
||||||
|
[SDLK_KP9] = 0x49,
|
||||||
|
[SDLK_KP_MINUS] = 0x4a,
|
||||||
|
[SDLK_KP4] = 0x4b,
|
||||||
|
[SDLK_KP5] = 0x4c,
|
||||||
|
[SDLK_KP6] = 0x4d,
|
||||||
|
[SDLK_KP_PLUS] = 0x4e,
|
||||||
|
[SDLK_KP1] = 0x4f,
|
||||||
|
[SDLK_KP2] = 0x50,
|
||||||
|
[SDLK_KP3] = 0x51,
|
||||||
|
[SDLK_KP0] = 0x52,
|
||||||
|
[SDLK_KP_PERIOD] = 0x53,
|
||||||
|
[SDLK_PRINT] = 0x54,
|
||||||
|
[SDLK_LMETA] = 0x56,
|
||||||
|
|
||||||
|
[SDLK_KP_ENTER] = 0x9c,
|
||||||
|
[SDLK_KP_DIVIDE] = 0xb5,
|
||||||
|
|
||||||
|
[SDLK_UP] = 0xc8,
|
||||||
|
[SDLK_DOWN] = 0xd0,
|
||||||
|
[SDLK_RIGHT] = 0xcd,
|
||||||
|
[SDLK_LEFT] = 0xcb,
|
||||||
|
[SDLK_INSERT] = 0xd2,
|
||||||
|
[SDLK_HOME] = 0xc7,
|
||||||
|
[SDLK_END] = 0xcf,
|
||||||
|
[SDLK_PAGEUP] = 0xc9,
|
||||||
|
[SDLK_PAGEDOWN] = 0xd1,
|
||||||
|
[SDLK_DELETE] = 0xd3,
|
||||||
|
};
|
||||||
|
|
||||||
|
static uint8_t sdl_keyevent_to_keycode(const SDL_KeyboardEvent *ev)
|
||||||
|
{
|
||||||
|
return scancodes[ev->keysym.sym];
|
||||||
|
}
|
||||||
|
|
||||||
|
#elif defined(_WIN32)
|
||||||
|
|
||||||
|
static uint8_t sdl_keyevent_to_keycode(const SDL_KeyboardEvent *ev)
|
||||||
|
{
|
||||||
|
return ev->keysym.scancode;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
static const uint8_t x_keycode_to_pc_keycode[61] = {
|
||||||
|
0xc7, /* 97 Home */
|
||||||
|
0xc8, /* 98 Up */
|
||||||
|
0xc9, /* 99 PgUp */
|
||||||
|
0xcb, /* 100 Left */
|
||||||
0x4c, /* 101 KP-5 */
|
0x4c, /* 101 KP-5 */
|
||||||
0x4de0, /* 102 Right */
|
0xcd, /* 102 Right */
|
||||||
0x4fe0, /* 103 End */
|
0xcf, /* 103 End */
|
||||||
0x50e0, /* 104 Down */
|
0xd0, /* 104 Down */
|
||||||
0x51e0, /* 105 PgDn */
|
0xd1, /* 105 PgDn */
|
||||||
0x52e0, /* 106 Ins */
|
0xd2, /* 106 Ins */
|
||||||
0x53e0, /* 107 Del */
|
0xd3, /* 107 Del */
|
||||||
0x1ce0, /* 108 Enter */
|
0x9c, /* 108 Enter */
|
||||||
0x1de0, /* 109 Ctrl-R */
|
0x9d, /* 109 Ctrl-R */
|
||||||
0x451de1, /* 110 Pause */
|
0x0, /* 110 Pause */
|
||||||
0x37e0, /* 111 Print */
|
0xb7, /* 111 Print */
|
||||||
0x35e0, /* 112 Divide */
|
0xb5, /* 112 Divide */
|
||||||
0x38e0, /* 113 Alt-R */
|
0xb8, /* 113 Alt-R */
|
||||||
0x46e0, /* 114 Break */
|
0xc6, /* 114 Break */
|
||||||
0x0, /* 115 */
|
0x0, /* 115 */
|
||||||
0x0, /* 116 */
|
0x0, /* 116 */
|
||||||
0x0, /* 117 */
|
0x0, /* 117 */
|
||||||
0x0, /* 118 */
|
0x0, /* 118 */
|
||||||
0x0, /* 119 */
|
0x0, /* 119 */
|
||||||
0x0, /* 120 */
|
0x70, /* 120 Hiragana_Katakana */
|
||||||
0x0, /* 121 */
|
0x0, /* 121 */
|
||||||
0x0, /* 122 */
|
0x0, /* 122 */
|
||||||
0x0, /* 123 */
|
0x73, /* 123 backslash */
|
||||||
0x0, /* 124 */
|
0x0, /* 124 */
|
||||||
0x0, /* 125 */
|
0x0, /* 125 */
|
||||||
0x0, /* 126 */
|
0x0, /* 126 */
|
||||||
0x0, /* 127 */
|
0x0, /* 127 */
|
||||||
0x0, /* 128 */
|
0x0, /* 128 */
|
||||||
0x0, /* 129 */
|
0x79, /* 129 Henkan */
|
||||||
0x0, /* 130 */
|
0x0, /* 130 */
|
||||||
0x0, /* 131 */
|
0x7b, /* 131 Muhenkan */
|
||||||
0x0, /* 132 */
|
0x0, /* 132 */
|
||||||
0x0, /* 133 */
|
0x7d, /* 133 Yen */
|
||||||
0x0, /* 134 */
|
0x0, /* 134 */
|
||||||
0x0, /* 135 */
|
0x0, /* 135 */
|
||||||
0x47, /* 136 KP_7 */
|
0x47, /* 136 KP_7 */
|
||||||
@@ -137,12 +251,12 @@ static const uint32_t x_keycode_to_pc_keycode[61] = {
|
|||||||
0x53, /* 157 KP_Del */
|
0x53, /* 157 KP_Del */
|
||||||
};
|
};
|
||||||
|
|
||||||
static void sdl_process_key(SDL_KeyboardEvent *ev)
|
static uint8_t sdl_keyevent_to_keycode(const SDL_KeyboardEvent *ev)
|
||||||
{
|
{
|
||||||
int keycode, v;
|
int keycode;
|
||||||
|
|
||||||
/* XXX: not portable, but avoids complicated mappings */
|
|
||||||
keycode = ev->keysym.scancode;
|
keycode = ev->keysym.scancode;
|
||||||
|
|
||||||
if (keycode < 9) {
|
if (keycode < 9) {
|
||||||
keycode = 0;
|
keycode = 0;
|
||||||
} else if (keycode < 97) {
|
} else if (keycode < 97) {
|
||||||
@@ -153,33 +267,98 @@ static void sdl_process_key(SDL_KeyboardEvent *ev)
|
|||||||
} else {
|
} else {
|
||||||
keycode = 0;
|
keycode = 0;
|
||||||
}
|
}
|
||||||
|
return keycode;
|
||||||
/* now send the key code */
|
}
|
||||||
while (keycode != 0) {
|
|
||||||
v = keycode & 0xff;
|
#endif
|
||||||
|
|
||||||
|
static void sdl_process_key(SDL_KeyboardEvent *ev)
|
||||||
|
{
|
||||||
|
int keycode, v, i;
|
||||||
|
static uint8_t modifiers_state[256];
|
||||||
|
|
||||||
|
if (ev->keysym.sym == SDLK_PAUSE) {
|
||||||
|
/* specific case */
|
||||||
|
v = 0;
|
||||||
if (ev->type == SDL_KEYUP)
|
if (ev->type == SDL_KEYUP)
|
||||||
v |= 0x80;
|
v |= 0x80;
|
||||||
kbd_put_keycode(v);
|
kbd_put_keycode(0xe1);
|
||||||
keycode >>= 8;
|
kbd_put_keycode(0x1d | v);
|
||||||
|
kbd_put_keycode(0x45 | v);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* XXX: not portable, but avoids complicated mappings */
|
||||||
|
keycode = sdl_keyevent_to_keycode(ev);
|
||||||
|
|
||||||
|
switch(keycode) {
|
||||||
|
case 0x00:
|
||||||
|
/* sent when leaving window: reset the modifiers state */
|
||||||
|
for(i = 0; i < 256; i++) {
|
||||||
|
if (modifiers_state[i]) {
|
||||||
|
if (i & 0x80)
|
||||||
|
kbd_put_keycode(0xe0);
|
||||||
|
kbd_put_keycode(i | 0x80);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
case 0x2a: /* Left Shift */
|
||||||
|
case 0x36: /* Right Shift */
|
||||||
|
case 0x1d: /* Left CTRL */
|
||||||
|
case 0x9d: /* Right CTRL */
|
||||||
|
case 0x38: /* Left ALT */
|
||||||
|
case 0xb8: /* Right ALT */
|
||||||
|
if (ev->type == SDL_KEYUP)
|
||||||
|
modifiers_state[keycode] = 0;
|
||||||
|
else
|
||||||
|
modifiers_state[keycode] = 1;
|
||||||
|
break;
|
||||||
|
case 0x45: /* num lock */
|
||||||
|
case 0x3a: /* caps lock */
|
||||||
|
/* SDL does not send the key up event, so we generate it */
|
||||||
|
kbd_put_keycode(keycode);
|
||||||
|
kbd_put_keycode(keycode | 0x80);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* now send the key code */
|
||||||
|
if (keycode & 0x80)
|
||||||
|
kbd_put_keycode(0xe0);
|
||||||
|
if (ev->type == SDL_KEYUP)
|
||||||
|
kbd_put_keycode(keycode | 0x80);
|
||||||
|
else
|
||||||
|
kbd_put_keycode(keycode & 0x7f);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sdl_update_caption(void)
|
||||||
|
{
|
||||||
|
char buf[1024];
|
||||||
|
strcpy(buf, "QEMU");
|
||||||
|
if (!vm_running) {
|
||||||
|
strcat(buf, " [Stopped]");
|
||||||
|
}
|
||||||
|
if (gui_grab) {
|
||||||
|
strcat(buf, " - Press Ctrl-Shift to exit grab");
|
||||||
|
}
|
||||||
|
SDL_WM_SetCaption(buf, "QEMU");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sdl_grab_start(void)
|
static void sdl_grab_start(void)
|
||||||
{
|
{
|
||||||
SDL_WM_SetCaption("QEMU - Press Ctrl-Shift to exit grab", "QEMU");
|
|
||||||
SDL_ShowCursor(0);
|
SDL_ShowCursor(0);
|
||||||
SDL_WM_GrabInput(SDL_GRAB_ON);
|
SDL_WM_GrabInput(SDL_GRAB_ON);
|
||||||
/* dummy read to avoid moving the mouse */
|
/* dummy read to avoid moving the mouse */
|
||||||
SDL_GetRelativeMouseState(NULL, NULL);
|
SDL_GetRelativeMouseState(NULL, NULL);
|
||||||
gui_grab = 1;
|
gui_grab = 1;
|
||||||
|
sdl_update_caption();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sdl_grab_end(void)
|
static void sdl_grab_end(void)
|
||||||
{
|
{
|
||||||
SDL_WM_SetCaption("QEMU", "QEMU");
|
|
||||||
SDL_WM_GrabInput(SDL_GRAB_OFF);
|
SDL_WM_GrabInput(SDL_GRAB_OFF);
|
||||||
SDL_ShowCursor(1);
|
SDL_ShowCursor(1);
|
||||||
gui_grab = 0;
|
gui_grab = 0;
|
||||||
|
sdl_update_caption();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sdl_send_mouse_event(void)
|
static void sdl_send_mouse_event(void)
|
||||||
@@ -195,16 +374,39 @@ static void sdl_send_mouse_event(void)
|
|||||||
buttons |= MOUSE_EVENT_MBUTTON;
|
buttons |= MOUSE_EVENT_MBUTTON;
|
||||||
/* XXX: test wheel */
|
/* XXX: test wheel */
|
||||||
dz = 0;
|
dz = 0;
|
||||||
|
#ifdef SDL_BUTTON_WHEELUP
|
||||||
if (state & SDL_BUTTON(SDL_BUTTON_WHEELUP))
|
if (state & SDL_BUTTON(SDL_BUTTON_WHEELUP))
|
||||||
dz--;
|
dz--;
|
||||||
if (state & SDL_BUTTON(SDL_BUTTON_WHEELDOWN))
|
if (state & SDL_BUTTON(SDL_BUTTON_WHEELDOWN))
|
||||||
dz++;
|
dz++;
|
||||||
|
#endif
|
||||||
kbd_mouse_event(dx, dy, dz, buttons);
|
kbd_mouse_event(dx, dy, dz, buttons);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void toggle_full_screen(DisplayState *ds)
|
||||||
|
{
|
||||||
|
gui_fullscreen = !gui_fullscreen;
|
||||||
|
sdl_resize(ds, screen->w, screen->h);
|
||||||
|
if (gui_fullscreen) {
|
||||||
|
gui_saved_grab = gui_grab;
|
||||||
|
sdl_grab_start();
|
||||||
|
} else {
|
||||||
|
if (!gui_saved_grab)
|
||||||
|
sdl_grab_end();
|
||||||
|
}
|
||||||
|
vga_invalidate_display();
|
||||||
|
vga_update_display();
|
||||||
|
}
|
||||||
|
|
||||||
static void sdl_refresh(DisplayState *ds)
|
static void sdl_refresh(DisplayState *ds)
|
||||||
{
|
{
|
||||||
SDL_Event ev1, *ev = &ev1;
|
SDL_Event ev1, *ev = &ev1;
|
||||||
|
int mod_state;
|
||||||
|
|
||||||
|
if (last_vm_running != vm_running) {
|
||||||
|
last_vm_running = vm_running;
|
||||||
|
sdl_update_caption();
|
||||||
|
}
|
||||||
|
|
||||||
vga_update_display();
|
vga_update_display();
|
||||||
while (SDL_PollEvent(ev)) {
|
while (SDL_PollEvent(ev)) {
|
||||||
@@ -215,19 +417,38 @@ static void sdl_refresh(DisplayState *ds)
|
|||||||
case SDL_KEYDOWN:
|
case SDL_KEYDOWN:
|
||||||
case SDL_KEYUP:
|
case SDL_KEYUP:
|
||||||
if (ev->type == SDL_KEYDOWN) {
|
if (ev->type == SDL_KEYDOWN) {
|
||||||
if ((SDL_GetModState() & (KMOD_LSHIFT | KMOD_LCTRL)) ==
|
mod_state = (SDL_GetModState() & (KMOD_LSHIFT | KMOD_LCTRL)) ==
|
||||||
(KMOD_LSHIFT | KMOD_LCTRL)) {
|
(KMOD_LSHIFT | KMOD_LCTRL);
|
||||||
/* exit/enter grab if pressing Ctrl-Shift */
|
gui_key_modifier_pressed = mod_state;
|
||||||
if (!gui_grab)
|
if (gui_key_modifier_pressed &&
|
||||||
sdl_grab_start();
|
ev->key.keysym.sym == SDLK_f) {
|
||||||
else
|
gui_keysym = ev->key.keysym.sym;
|
||||||
sdl_grab_end();
|
}
|
||||||
|
} else if (ev->type == SDL_KEYUP) {
|
||||||
|
mod_state = (SDL_GetModState() & (KMOD_LSHIFT | KMOD_LCTRL));
|
||||||
|
if (!mod_state) {
|
||||||
|
if (gui_key_modifier_pressed) {
|
||||||
|
switch(gui_keysym) {
|
||||||
|
case SDLK_f:
|
||||||
|
toggle_full_screen(ds);
|
||||||
|
break;
|
||||||
|
case 0:
|
||||||
|
/* exit/enter grab if pressing Ctrl-Shift */
|
||||||
|
if (!gui_grab)
|
||||||
|
sdl_grab_start();
|
||||||
|
else
|
||||||
|
sdl_grab_end();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
gui_key_modifier_pressed = 0;
|
||||||
|
gui_keysym = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sdl_process_key(&ev->key);
|
sdl_process_key(&ev->key);
|
||||||
break;
|
break;
|
||||||
case SDL_QUIT:
|
case SDL_QUIT:
|
||||||
reset_requested = 1;
|
qemu_system_shutdown_request();
|
||||||
break;
|
break;
|
||||||
case SDL_MOUSEMOTION:
|
case SDL_MOUSEMOTION:
|
||||||
if (gui_grab) {
|
if (gui_grab) {
|
||||||
@@ -249,12 +470,22 @@ static void sdl_refresh(DisplayState *ds)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case SDL_ACTIVEEVENT:
|
||||||
|
if (gui_grab && (ev->active.gain & SDL_ACTIVEEVENTMASK) == 0) {
|
||||||
|
sdl_grab_end();
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void sdl_cleanup(void)
|
||||||
|
{
|
||||||
|
SDL_Quit();
|
||||||
|
}
|
||||||
|
|
||||||
void sdl_display_init(DisplayState *ds)
|
void sdl_display_init(DisplayState *ds)
|
||||||
{
|
{
|
||||||
int flags;
|
int flags;
|
||||||
@@ -264,16 +495,21 @@ void sdl_display_init(DisplayState *ds)
|
|||||||
fprintf(stderr, "Could not initialize SDL - exiting\n");
|
fprintf(stderr, "Could not initialize SDL - exiting\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef _WIN32
|
||||||
/* NOTE: we still want Ctrl-C to work, so we undo the SDL redirections */
|
/* NOTE: we still want Ctrl-C to work, so we undo the SDL redirections */
|
||||||
signal(SIGINT, SIG_DFL);
|
signal(SIGINT, SIG_DFL);
|
||||||
signal(SIGQUIT, SIG_DFL);
|
signal(SIGQUIT, SIG_DFL);
|
||||||
|
#endif
|
||||||
|
|
||||||
ds->dpy_update = sdl_update;
|
ds->dpy_update = sdl_update;
|
||||||
ds->dpy_resize = sdl_resize;
|
ds->dpy_resize = sdl_resize;
|
||||||
ds->dpy_refresh = sdl_refresh;
|
ds->dpy_refresh = sdl_refresh;
|
||||||
|
|
||||||
sdl_resize(ds, 640, 400);
|
sdl_resize(ds, 640, 400);
|
||||||
SDL_WM_SetCaption("QEMU", "QEMU");
|
sdl_update_caption();
|
||||||
SDL_EnableKeyRepeat(250, 50);
|
SDL_EnableKeyRepeat(250, 50);
|
||||||
gui_grab = 0;
|
gui_grab = 0;
|
||||||
|
|
||||||
|
atexit(sdl_cleanup);
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
Slirp was written by Danny Gasparovski.
|
||||||
|
Copyright (c), 1995,1996 All Rights Reserved.
|
||||||
|
|
||||||
|
Slirp is maintained by Kelly Price <tygris+slirp@erols.com>
|
||||||
|
|
||||||
|
Slirp is free software; "free" as in you don't have to pay for it, and you
|
||||||
|
are free to do whatever you want with it. I do not accept any donations,
|
||||||
|
monetary or otherwise, for Slirp. Instead, I would ask you to pass this
|
||||||
|
potential donation to your favorite charity. In fact, I encourage
|
||||||
|
*everyone* who finds Slirp useful to make a small donation to their
|
||||||
|
favorite charity (for example, GreenPeace). This is not a requirement, but
|
||||||
|
a suggestion from someone who highly values the service they provide.
|
||||||
|
|
||||||
|
The copyright terms and conditions:
|
||||||
|
|
||||||
|
---BEGIN---
|
||||||
|
|
||||||
|
Copyright (c) 1995,1996 Danny Gasparovski. All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
1. Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
3. All advertising materials mentioning features or use of this software
|
||||||
|
must display the following acknowledgment:
|
||||||
|
This product includes software developed by Danny Gasparovski.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||||
|
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||||
|
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||||
|
DANNY GASPAROVSKI OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
---END---
|
||||||
|
|
||||||
|
This basically means you can do anything you want with the software, except
|
||||||
|
1) call it your own, and 2) claim warranty on it. There is no warranty for
|
||||||
|
this software. None. Nada. If you lose a million dollars while using
|
||||||
|
Slirp, that's your loss not mine. So, ***USE AT YOUR OWN RISK!***.
|
||||||
|
|
||||||
|
If these conditions cannot be met due to legal restrictions (E.g. where it
|
||||||
|
is against the law to give out Software without warranty), you must cease
|
||||||
|
using the software and delete all copies you have.
|
||||||
|
|
||||||
|
Slirp uses code that is copyrighted by the following people/organizations:
|
||||||
|
|
||||||
|
Juha Pirkola.
|
||||||
|
Gregory M. Christy.
|
||||||
|
The Regents of the University of California.
|
||||||
|
Carnegie Mellon University.
|
||||||
|
The Australian National University.
|
||||||
|
RSA Data Security, Inc.
|
||||||
|
|
||||||
|
Please read the top of each source file for the details on the various
|
||||||
|
copyrights.
|
||||||
+240
@@ -0,0 +1,240 @@
|
|||||||
|
/*
|
||||||
|
* QEMU BOOTP/DHCP server
|
||||||
|
*
|
||||||
|
* 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 <slirp.h>
|
||||||
|
|
||||||
|
/* XXX: only DHCP is supported */
|
||||||
|
|
||||||
|
#define NB_ADDR 16
|
||||||
|
|
||||||
|
#define START_ADDR 15
|
||||||
|
|
||||||
|
#define LEASE_TIME (24 * 3600)
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t allocated;
|
||||||
|
uint8_t macaddr[6];
|
||||||
|
} BOOTPClient;
|
||||||
|
|
||||||
|
BOOTPClient bootp_clients[NB_ADDR];
|
||||||
|
|
||||||
|
static const uint8_t rfc1533_cookie[] = { RFC1533_COOKIE };
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
#define dprintf(fmt, args...) \
|
||||||
|
if (slirp_debug & DBG_CALL) { fprintf(dfd, fmt, ## args); fflush(dfd); }
|
||||||
|
#else
|
||||||
|
#define dprintf(fmt, args...)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static BOOTPClient *get_new_addr(struct in_addr *paddr)
|
||||||
|
{
|
||||||
|
BOOTPClient *bc;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for(i = 0; i < NB_ADDR; i++) {
|
||||||
|
if (!bootp_clients[i].allocated)
|
||||||
|
goto found;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
found:
|
||||||
|
bc = &bootp_clients[i];
|
||||||
|
bc->allocated = 1;
|
||||||
|
paddr->s_addr = htonl(ntohl(special_addr.s_addr) | (i + START_ADDR));
|
||||||
|
return bc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static BOOTPClient *find_addr(struct in_addr *paddr, const uint8_t *macaddr)
|
||||||
|
{
|
||||||
|
BOOTPClient *bc;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for(i = 0; i < NB_ADDR; i++) {
|
||||||
|
if (!memcmp(macaddr, bootp_clients[i].macaddr, 6))
|
||||||
|
goto found;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
found:
|
||||||
|
bc = &bootp_clients[i];
|
||||||
|
bc->allocated = 1;
|
||||||
|
paddr->s_addr = htonl(ntohl(special_addr.s_addr) | (i + START_ADDR));
|
||||||
|
return bc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dhcp_decode(const uint8_t *buf, int size,
|
||||||
|
int *pmsg_type)
|
||||||
|
{
|
||||||
|
const uint8_t *p, *p_end;
|
||||||
|
int len, tag;
|
||||||
|
|
||||||
|
*pmsg_type = 0;
|
||||||
|
|
||||||
|
p = buf;
|
||||||
|
p_end = buf + size;
|
||||||
|
if (size < 5)
|
||||||
|
return;
|
||||||
|
if (memcmp(p, rfc1533_cookie, 4) != 0)
|
||||||
|
return;
|
||||||
|
p += 4;
|
||||||
|
while (p < p_end) {
|
||||||
|
tag = p[0];
|
||||||
|
if (tag == RFC1533_PAD) {
|
||||||
|
p++;
|
||||||
|
} else if (tag == RFC1533_END) {
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
p++;
|
||||||
|
if (p >= p_end)
|
||||||
|
break;
|
||||||
|
len = *p++;
|
||||||
|
dprintf("dhcp: tag=0x%02x len=%d\n", tag, len);
|
||||||
|
|
||||||
|
switch(tag) {
|
||||||
|
case RFC2132_MSG_TYPE:
|
||||||
|
if (len >= 1)
|
||||||
|
*pmsg_type = p[0];
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
p += len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void bootp_reply(struct bootp_t *bp)
|
||||||
|
{
|
||||||
|
BOOTPClient *bc;
|
||||||
|
struct mbuf *m;
|
||||||
|
struct bootp_t *rbp;
|
||||||
|
struct sockaddr_in saddr, daddr;
|
||||||
|
struct in_addr dns_addr;
|
||||||
|
int dhcp_msg_type, val;
|
||||||
|
uint8_t *q;
|
||||||
|
|
||||||
|
/* extract exact DHCP msg type */
|
||||||
|
dhcp_decode(bp->bp_vend, DHCP_OPT_LEN, &dhcp_msg_type);
|
||||||
|
dprintf("bootp packet op=%d msgtype=%d\n", bp->bp_op, dhcp_msg_type);
|
||||||
|
|
||||||
|
if (dhcp_msg_type != DHCPDISCOVER &&
|
||||||
|
dhcp_msg_type != DHCPREQUEST)
|
||||||
|
return;
|
||||||
|
/* XXX: this is a hack to get the client mac address */
|
||||||
|
memcpy(client_ethaddr, bp->bp_hwaddr, 6);
|
||||||
|
|
||||||
|
if ((m = m_get()) == NULL)
|
||||||
|
return;
|
||||||
|
m->m_data += if_maxlinkhdr;
|
||||||
|
rbp = (struct bootp_t *)m->m_data;
|
||||||
|
m->m_data += sizeof(struct udpiphdr);
|
||||||
|
memset(rbp, 0, sizeof(struct bootp_t));
|
||||||
|
|
||||||
|
if (dhcp_msg_type == DHCPDISCOVER) {
|
||||||
|
bc = get_new_addr(&daddr.sin_addr);
|
||||||
|
if (!bc) {
|
||||||
|
dprintf("no address left\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
memcpy(bc->macaddr, client_ethaddr, 6);
|
||||||
|
} else {
|
||||||
|
bc = find_addr(&daddr.sin_addr, bp->bp_hwaddr);
|
||||||
|
if (!bc) {
|
||||||
|
dprintf("no address assigned\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dprintf("offered addr=%08x\n", ntohl(daddr.sin_addr.s_addr));
|
||||||
|
|
||||||
|
saddr.sin_addr.s_addr = htonl(ntohl(special_addr.s_addr) | CTL_ALIAS);
|
||||||
|
saddr.sin_port = htons(BOOTP_SERVER);
|
||||||
|
|
||||||
|
daddr.sin_port = htons(BOOTP_CLIENT);
|
||||||
|
|
||||||
|
rbp->bp_op = BOOTP_REPLY;
|
||||||
|
rbp->bp_xid = bp->bp_xid;
|
||||||
|
rbp->bp_htype = 1;
|
||||||
|
rbp->bp_hlen = 6;
|
||||||
|
memcpy(rbp->bp_hwaddr, bp->bp_hwaddr, 6);
|
||||||
|
|
||||||
|
rbp->bp_yiaddr = daddr.sin_addr; /* IP address */
|
||||||
|
|
||||||
|
q = rbp->bp_vend;
|
||||||
|
memcpy(q, rfc1533_cookie, 4);
|
||||||
|
q += 4;
|
||||||
|
|
||||||
|
if (dhcp_msg_type == DHCPDISCOVER) {
|
||||||
|
*q++ = RFC2132_MSG_TYPE;
|
||||||
|
*q++ = 1;
|
||||||
|
*q++ = DHCPOFFER;
|
||||||
|
} else if (dhcp_msg_type == DHCPREQUEST) {
|
||||||
|
*q++ = RFC2132_MSG_TYPE;
|
||||||
|
*q++ = 1;
|
||||||
|
*q++ = DHCPACK;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dhcp_msg_type == DHCPDISCOVER ||
|
||||||
|
dhcp_msg_type == DHCPREQUEST) {
|
||||||
|
*q++ = RFC2132_SRV_ID;
|
||||||
|
*q++ = 4;
|
||||||
|
memcpy(q, &saddr.sin_addr, 4);
|
||||||
|
q += 4;
|
||||||
|
|
||||||
|
*q++ = RFC1533_NETMASK;
|
||||||
|
*q++ = 4;
|
||||||
|
*q++ = 0xff;
|
||||||
|
*q++ = 0xff;
|
||||||
|
*q++ = 0xff;
|
||||||
|
*q++ = 0x00;
|
||||||
|
|
||||||
|
*q++ = RFC1533_GATEWAY;
|
||||||
|
*q++ = 4;
|
||||||
|
memcpy(q, &saddr.sin_addr, 4);
|
||||||
|
q += 4;
|
||||||
|
|
||||||
|
*q++ = RFC1533_DNS;
|
||||||
|
*q++ = 4;
|
||||||
|
dns_addr.s_addr = htonl(ntohl(special_addr.s_addr) | CTL_DNS);
|
||||||
|
memcpy(q, &dns_addr, 4);
|
||||||
|
q += 4;
|
||||||
|
|
||||||
|
*q++ = RFC2132_LEASE_TIME;
|
||||||
|
*q++ = 4;
|
||||||
|
val = htonl(LEASE_TIME);
|
||||||
|
memcpy(q, &val, 4);
|
||||||
|
q += 4;
|
||||||
|
}
|
||||||
|
*q++ = RFC1533_END;
|
||||||
|
|
||||||
|
m->m_len = sizeof(struct bootp_t) -
|
||||||
|
sizeof(struct ip) - sizeof(struct udphdr);
|
||||||
|
udp_output2(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY);
|
||||||
|
}
|
||||||
|
|
||||||
|
void bootp_input(struct mbuf *m)
|
||||||
|
{
|
||||||
|
struct bootp_t *bp = (struct bootp_t *)m->m_data;
|
||||||
|
|
||||||
|
if (bp->bp_op == BOOTP_REQUEST) {
|
||||||
|
bootp_reply(bp);
|
||||||
|
}
|
||||||
|
}
|
||||||
+113
@@ -0,0 +1,113 @@
|
|||||||
|
/* bootp/dhcp defines */
|
||||||
|
|
||||||
|
#define BOOTP_SERVER 67
|
||||||
|
#define BOOTP_CLIENT 68
|
||||||
|
|
||||||
|
#define BOOTP_REQUEST 1
|
||||||
|
#define BOOTP_REPLY 2
|
||||||
|
|
||||||
|
#define RFC1533_COOKIE 99, 130, 83, 99
|
||||||
|
#define RFC1533_PAD 0
|
||||||
|
#define RFC1533_NETMASK 1
|
||||||
|
#define RFC1533_TIMEOFFSET 2
|
||||||
|
#define RFC1533_GATEWAY 3
|
||||||
|
#define RFC1533_TIMESERVER 4
|
||||||
|
#define RFC1533_IEN116NS 5
|
||||||
|
#define RFC1533_DNS 6
|
||||||
|
#define RFC1533_LOGSERVER 7
|
||||||
|
#define RFC1533_COOKIESERVER 8
|
||||||
|
#define RFC1533_LPRSERVER 9
|
||||||
|
#define RFC1533_IMPRESSSERVER 10
|
||||||
|
#define RFC1533_RESOURCESERVER 11
|
||||||
|
#define RFC1533_HOSTNAME 12
|
||||||
|
#define RFC1533_BOOTFILESIZE 13
|
||||||
|
#define RFC1533_MERITDUMPFILE 14
|
||||||
|
#define RFC1533_DOMAINNAME 15
|
||||||
|
#define RFC1533_SWAPSERVER 16
|
||||||
|
#define RFC1533_ROOTPATH 17
|
||||||
|
#define RFC1533_EXTENSIONPATH 18
|
||||||
|
#define RFC1533_IPFORWARDING 19
|
||||||
|
#define RFC1533_IPSOURCEROUTING 20
|
||||||
|
#define RFC1533_IPPOLICYFILTER 21
|
||||||
|
#define RFC1533_IPMAXREASSEMBLY 22
|
||||||
|
#define RFC1533_IPTTL 23
|
||||||
|
#define RFC1533_IPMTU 24
|
||||||
|
#define RFC1533_IPMTUPLATEAU 25
|
||||||
|
#define RFC1533_INTMTU 26
|
||||||
|
#define RFC1533_INTLOCALSUBNETS 27
|
||||||
|
#define RFC1533_INTBROADCAST 28
|
||||||
|
#define RFC1533_INTICMPDISCOVER 29
|
||||||
|
#define RFC1533_INTICMPRESPOND 30
|
||||||
|
#define RFC1533_INTROUTEDISCOVER 31
|
||||||
|
#define RFC1533_INTROUTESOLICIT 32
|
||||||
|
#define RFC1533_INTSTATICROUTES 33
|
||||||
|
#define RFC1533_LLTRAILERENCAP 34
|
||||||
|
#define RFC1533_LLARPCACHETMO 35
|
||||||
|
#define RFC1533_LLETHERNETENCAP 36
|
||||||
|
#define RFC1533_TCPTTL 37
|
||||||
|
#define RFC1533_TCPKEEPALIVETMO 38
|
||||||
|
#define RFC1533_TCPKEEPALIVEGB 39
|
||||||
|
#define RFC1533_NISDOMAIN 40
|
||||||
|
#define RFC1533_NISSERVER 41
|
||||||
|
#define RFC1533_NTPSERVER 42
|
||||||
|
#define RFC1533_VENDOR 43
|
||||||
|
#define RFC1533_NBNS 44
|
||||||
|
#define RFC1533_NBDD 45
|
||||||
|
#define RFC1533_NBNT 46
|
||||||
|
#define RFC1533_NBSCOPE 47
|
||||||
|
#define RFC1533_XFS 48
|
||||||
|
#define RFC1533_XDM 49
|
||||||
|
|
||||||
|
#define RFC2132_REQ_ADDR 50
|
||||||
|
#define RFC2132_LEASE_TIME 51
|
||||||
|
#define RFC2132_MSG_TYPE 53
|
||||||
|
#define RFC2132_SRV_ID 54
|
||||||
|
#define RFC2132_PARAM_LIST 55
|
||||||
|
#define RFC2132_MAX_SIZE 57
|
||||||
|
#define RFC2132_RENEWAL_TIME 58
|
||||||
|
#define RFC2132_REBIND_TIME 59
|
||||||
|
|
||||||
|
#define DHCPDISCOVER 1
|
||||||
|
#define DHCPOFFER 2
|
||||||
|
#define DHCPREQUEST 3
|
||||||
|
#define DHCPACK 5
|
||||||
|
|
||||||
|
#define RFC1533_VENDOR_MAJOR 0
|
||||||
|
#define RFC1533_VENDOR_MINOR 0
|
||||||
|
|
||||||
|
#define RFC1533_VENDOR_MAGIC 128
|
||||||
|
#define RFC1533_VENDOR_ADDPARM 129
|
||||||
|
#define RFC1533_VENDOR_ETHDEV 130
|
||||||
|
#define RFC1533_VENDOR_HOWTO 132
|
||||||
|
#define RFC1533_VENDOR_MNUOPTS 160
|
||||||
|
#define RFC1533_VENDOR_SELECTION 176
|
||||||
|
#define RFC1533_VENDOR_MOTD 184
|
||||||
|
#define RFC1533_VENDOR_NUMOFMOTD 8
|
||||||
|
#define RFC1533_VENDOR_IMG 192
|
||||||
|
#define RFC1533_VENDOR_NUMOFIMG 16
|
||||||
|
|
||||||
|
#define RFC1533_END 255
|
||||||
|
#define BOOTP_VENDOR_LEN 64
|
||||||
|
#define DHCP_OPT_LEN 312
|
||||||
|
|
||||||
|
struct bootp_t {
|
||||||
|
struct ip ip;
|
||||||
|
struct udphdr udp;
|
||||||
|
uint8_t bp_op;
|
||||||
|
uint8_t bp_htype;
|
||||||
|
uint8_t bp_hlen;
|
||||||
|
uint8_t bp_hops;
|
||||||
|
unsigned long bp_xid;
|
||||||
|
unsigned short bp_secs;
|
||||||
|
unsigned short unused;
|
||||||
|
struct in_addr bp_ciaddr;
|
||||||
|
struct in_addr bp_yiaddr;
|
||||||
|
struct in_addr bp_siaddr;
|
||||||
|
struct in_addr bp_giaddr;
|
||||||
|
uint8_t bp_hwaddr[16];
|
||||||
|
uint8_t bp_sname[64];
|
||||||
|
uint8_t bp_file[128];
|
||||||
|
uint8_t bp_vend[DHCP_OPT_LEN];
|
||||||
|
};
|
||||||
|
|
||||||
|
void bootp_input(struct mbuf *m);
|
||||||
+141
@@ -0,0 +1,141 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 1988, 1992, 1993
|
||||||
|
* The Regents of the University of California. All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. All advertising materials mentioning features or use of this software
|
||||||
|
* must display the following acknowledgement:
|
||||||
|
* This product includes software developed by the University of
|
||||||
|
* California, Berkeley and its contributors.
|
||||||
|
* 4. Neither the name of the University nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* @(#)in_cksum.c 8.1 (Berkeley) 6/10/93
|
||||||
|
* in_cksum.c,v 1.2 1994/08/02 07:48:16 davidg Exp
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <slirp.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Checksum routine for Internet Protocol family headers (Portable Version).
|
||||||
|
*
|
||||||
|
* This routine is very heavily used in the network
|
||||||
|
* code and should be modified for each CPU to be as fast as possible.
|
||||||
|
*
|
||||||
|
* XXX Since we will never span more than 1 mbuf, we can optimise this
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define ADDCARRY(x) (x > 65535 ? x -= 65535 : x)
|
||||||
|
#define REDUCE {l_util.l = sum; sum = l_util.s[0] + l_util.s[1]; ADDCARRY(sum);}
|
||||||
|
|
||||||
|
int cksum(struct mbuf *m, int len)
|
||||||
|
{
|
||||||
|
register u_int16_t *w;
|
||||||
|
register int sum = 0;
|
||||||
|
register int mlen = 0;
|
||||||
|
int byte_swapped = 0;
|
||||||
|
|
||||||
|
union {
|
||||||
|
u_int8_t c[2];
|
||||||
|
u_int16_t s;
|
||||||
|
} s_util;
|
||||||
|
union {
|
||||||
|
u_int16_t s[2];
|
||||||
|
u_int32_t l;
|
||||||
|
} l_util;
|
||||||
|
|
||||||
|
if (m->m_len == 0)
|
||||||
|
goto cont;
|
||||||
|
w = mtod(m, u_int16_t *);
|
||||||
|
|
||||||
|
mlen = m->m_len;
|
||||||
|
|
||||||
|
if (len < mlen)
|
||||||
|
mlen = len;
|
||||||
|
len -= mlen;
|
||||||
|
/*
|
||||||
|
* Force to even boundary.
|
||||||
|
*/
|
||||||
|
if ((1 & (long) w) && (mlen > 0)) {
|
||||||
|
REDUCE;
|
||||||
|
sum <<= 8;
|
||||||
|
s_util.c[0] = *(u_int8_t *)w;
|
||||||
|
w = (u_int16_t *)((int8_t *)w + 1);
|
||||||
|
mlen--;
|
||||||
|
byte_swapped = 1;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Unroll the loop to make overhead from
|
||||||
|
* branches &c small.
|
||||||
|
*/
|
||||||
|
while ((mlen -= 32) >= 0) {
|
||||||
|
sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3];
|
||||||
|
sum += w[4]; sum += w[5]; sum += w[6]; sum += w[7];
|
||||||
|
sum += w[8]; sum += w[9]; sum += w[10]; sum += w[11];
|
||||||
|
sum += w[12]; sum += w[13]; sum += w[14]; sum += w[15];
|
||||||
|
w += 16;
|
||||||
|
}
|
||||||
|
mlen += 32;
|
||||||
|
while ((mlen -= 8) >= 0) {
|
||||||
|
sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3];
|
||||||
|
w += 4;
|
||||||
|
}
|
||||||
|
mlen += 8;
|
||||||
|
if (mlen == 0 && byte_swapped == 0)
|
||||||
|
goto cont;
|
||||||
|
REDUCE;
|
||||||
|
while ((mlen -= 2) >= 0) {
|
||||||
|
sum += *w++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (byte_swapped) {
|
||||||
|
REDUCE;
|
||||||
|
sum <<= 8;
|
||||||
|
byte_swapped = 0;
|
||||||
|
if (mlen == -1) {
|
||||||
|
s_util.c[1] = *(u_int8_t *)w;
|
||||||
|
sum += s_util.s;
|
||||||
|
mlen = 0;
|
||||||
|
} else
|
||||||
|
|
||||||
|
mlen = -1;
|
||||||
|
} else if (mlen == -1)
|
||||||
|
s_util.c[0] = *(u_int8_t *)w;
|
||||||
|
|
||||||
|
cont:
|
||||||
|
#ifdef DEBUG
|
||||||
|
if (len) {
|
||||||
|
DEBUG_ERROR((dfd, "cksum: out of data\n"));
|
||||||
|
DEBUG_ERROR((dfd, " len = %d\n", len));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (mlen == -1) {
|
||||||
|
/* The last mbuf has odd # of bytes. Follow the
|
||||||
|
standard (the odd byte may be shifted left by 8 bits
|
||||||
|
or not as determined by endian-ness of the machine) */
|
||||||
|
s_util.c[1] = 0;
|
||||||
|
sum += s_util.s;
|
||||||
|
}
|
||||||
|
REDUCE;
|
||||||
|
return (~sum & 0xffff);
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
#define CTL_CMD 0
|
||||||
|
#define CTL_EXEC 1
|
||||||
|
#define CTL_ALIAS 2
|
||||||
|
#define CTL_DNS 3
|
||||||
|
|
||||||
|
#define CTL_SPECIAL "10.0.2.0"
|
||||||
|
#define CTL_LOCAL "10.0.2.15"
|
||||||
+376
@@ -0,0 +1,376 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 1995 Danny Gasparovski.
|
||||||
|
* Portions copyright (c) 2000 Kelly Price.
|
||||||
|
*
|
||||||
|
* Please read the file COPYRIGHT for the
|
||||||
|
* terms and conditions of the copyright.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <slirp.h>
|
||||||
|
|
||||||
|
FILE *dfd = NULL;
|
||||||
|
#ifdef DEBUG
|
||||||
|
int dostats = 1;
|
||||||
|
#else
|
||||||
|
int dostats = 0;
|
||||||
|
#endif
|
||||||
|
int slirp_debug = 0;
|
||||||
|
|
||||||
|
extern char *strerror _P((int));
|
||||||
|
|
||||||
|
/* Carry over one item from main.c so that the tty's restored.
|
||||||
|
* Only done when the tty being used is /dev/tty --RedWolf */
|
||||||
|
extern struct termios slirp_tty_settings;
|
||||||
|
extern int slirp_tty_restore;
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
debug_init(file, dbg)
|
||||||
|
char *file;
|
||||||
|
int dbg;
|
||||||
|
{
|
||||||
|
/* Close the old debugging file */
|
||||||
|
if (dfd)
|
||||||
|
fclose(dfd);
|
||||||
|
|
||||||
|
dfd = fopen(file,"w");
|
||||||
|
if (dfd != NULL) {
|
||||||
|
#if 0
|
||||||
|
fprintf(dfd,"Slirp %s - Debugging Started.\n", SLIRP_VERSION);
|
||||||
|
#endif
|
||||||
|
fprintf(dfd,"Debugging Started level %i.\r\n",dbg);
|
||||||
|
fflush(dfd);
|
||||||
|
slirp_debug = dbg;
|
||||||
|
} else {
|
||||||
|
lprint("Error: Debugging file \"%s\" could not be opened: %s\r\n",
|
||||||
|
file, strerror(errno));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Dump a packet in the same format as tcpdump -x
|
||||||
|
*/
|
||||||
|
#ifdef DEBUG
|
||||||
|
void
|
||||||
|
dump_packet(dat, n)
|
||||||
|
void *dat;
|
||||||
|
int n;
|
||||||
|
{
|
||||||
|
u_char *pptr = (u_char *)dat;
|
||||||
|
int j,k;
|
||||||
|
|
||||||
|
n /= 16;
|
||||||
|
n++;
|
||||||
|
DEBUG_MISC((dfd, "PACKET DUMPED: \n"));
|
||||||
|
for(j = 0; j < n; j++) {
|
||||||
|
for(k = 0; k < 6; k++)
|
||||||
|
DEBUG_MISC((dfd, "%02x ", *pptr++));
|
||||||
|
DEBUG_MISC((dfd, "\n"));
|
||||||
|
fflush(dfd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
/*
|
||||||
|
* Statistic routines
|
||||||
|
*
|
||||||
|
* These will print statistics to the screen, the debug file (dfd), or
|
||||||
|
* a buffer, depending on "type", so that the stats can be sent over
|
||||||
|
* the link as well.
|
||||||
|
*/
|
||||||
|
|
||||||
|
void
|
||||||
|
ttystats(ttyp)
|
||||||
|
struct ttys *ttyp;
|
||||||
|
{
|
||||||
|
struct slirp_ifstats *is = &ttyp->ifstats;
|
||||||
|
char buff[512];
|
||||||
|
|
||||||
|
lprint(" \r\n");
|
||||||
|
|
||||||
|
if (if_comp & IF_COMPRESS)
|
||||||
|
strcpy(buff, "on");
|
||||||
|
else if (if_comp & IF_NOCOMPRESS)
|
||||||
|
strcpy(buff, "off");
|
||||||
|
else
|
||||||
|
strcpy(buff, "off (for now)");
|
||||||
|
lprint("Unit %d:\r\n", ttyp->unit);
|
||||||
|
lprint(" using %s encapsulation (VJ compression is %s)\r\n", (
|
||||||
|
#ifdef USE_PPP
|
||||||
|
ttyp->proto==PROTO_PPP?"PPP":
|
||||||
|
#endif
|
||||||
|
"SLIP"), buff);
|
||||||
|
lprint(" %d baudrate\r\n", ttyp->baud);
|
||||||
|
lprint(" interface is %s\r\n", ttyp->up?"up":"down");
|
||||||
|
lprint(" using fd %d, guardian pid is %d\r\n", ttyp->fd, ttyp->pid);
|
||||||
|
#ifndef FULL_BOLT
|
||||||
|
lprint(" towrite is %d bytes\r\n", ttyp->towrite);
|
||||||
|
#endif
|
||||||
|
if (ttyp->zeros)
|
||||||
|
lprint(" %d zeros have been typed\r\n", ttyp->zeros);
|
||||||
|
else if (ttyp->ones)
|
||||||
|
lprint(" %d ones have been typed\r\n", ttyp->ones);
|
||||||
|
lprint("Interface stats:\r\n");
|
||||||
|
lprint(" %6d output packets sent (%d bytes)\r\n", is->out_pkts, is->out_bytes);
|
||||||
|
lprint(" %6d output packets dropped (%d bytes)\r\n", is->out_errpkts, is->out_errbytes);
|
||||||
|
lprint(" %6d input packets received (%d bytes)\r\n", is->in_pkts, is->in_bytes);
|
||||||
|
lprint(" %6d input packets dropped (%d bytes)\r\n", is->in_errpkts, is->in_errbytes);
|
||||||
|
lprint(" %6d bad input packets\r\n", is->in_mbad);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
allttystats()
|
||||||
|
{
|
||||||
|
struct ttys *ttyp;
|
||||||
|
|
||||||
|
for (ttyp = ttys; ttyp; ttyp = ttyp->next)
|
||||||
|
ttystats(ttyp);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void
|
||||||
|
ipstats()
|
||||||
|
{
|
||||||
|
lprint(" \r\n");
|
||||||
|
|
||||||
|
lprint("IP stats:\r\n");
|
||||||
|
lprint(" %6d total packets received (%d were unaligned)\r\n",
|
||||||
|
ipstat.ips_total, ipstat.ips_unaligned);
|
||||||
|
lprint(" %6d with incorrect version\r\n", ipstat.ips_badvers);
|
||||||
|
lprint(" %6d with bad header checksum\r\n", ipstat.ips_badsum);
|
||||||
|
lprint(" %6d with length too short (len < sizeof(iphdr))\r\n", ipstat.ips_tooshort);
|
||||||
|
lprint(" %6d with length too small (len < ip->len)\r\n", ipstat.ips_toosmall);
|
||||||
|
lprint(" %6d with bad header length\r\n", ipstat.ips_badhlen);
|
||||||
|
lprint(" %6d with bad packet length\r\n", ipstat.ips_badlen);
|
||||||
|
lprint(" %6d fragments received\r\n", ipstat.ips_fragments);
|
||||||
|
lprint(" %6d fragments dropped\r\n", ipstat.ips_fragdropped);
|
||||||
|
lprint(" %6d fragments timed out\r\n", ipstat.ips_fragtimeout);
|
||||||
|
lprint(" %6d packets reassembled ok\r\n", ipstat.ips_reassembled);
|
||||||
|
lprint(" %6d outgoing packets fragmented\r\n", ipstat.ips_fragmented);
|
||||||
|
lprint(" %6d total outgoing fragments\r\n", ipstat.ips_ofragments);
|
||||||
|
lprint(" %6d with bad protocol field\r\n", ipstat.ips_noproto);
|
||||||
|
lprint(" %6d total packets delivered\r\n", ipstat.ips_delivered);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
void
|
||||||
|
vjstats()
|
||||||
|
{
|
||||||
|
lprint(" \r\n");
|
||||||
|
|
||||||
|
lprint("VJ compression stats:\r\n");
|
||||||
|
|
||||||
|
lprint(" %6d outbound packets (%d compressed)\r\n",
|
||||||
|
comp_s.sls_packets, comp_s.sls_compressed);
|
||||||
|
lprint(" %6d searches for connection stats (%d misses)\r\n",
|
||||||
|
comp_s.sls_searches, comp_s.sls_misses);
|
||||||
|
lprint(" %6d inbound uncompressed packets\r\n", comp_s.sls_uncompressedin);
|
||||||
|
lprint(" %6d inbound compressed packets\r\n", comp_s.sls_compressedin);
|
||||||
|
lprint(" %6d inbound unknown type packets\r\n", comp_s.sls_errorin);
|
||||||
|
lprint(" %6d inbound packets tossed due to error\r\n", comp_s.sls_tossed);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void
|
||||||
|
tcpstats()
|
||||||
|
{
|
||||||
|
lprint(" \r\n");
|
||||||
|
|
||||||
|
lprint("TCP stats:\r\n");
|
||||||
|
|
||||||
|
lprint(" %6d packets sent\r\n", tcpstat.tcps_sndtotal);
|
||||||
|
lprint(" %6d data packets (%d bytes)\r\n",
|
||||||
|
tcpstat.tcps_sndpack, tcpstat.tcps_sndbyte);
|
||||||
|
lprint(" %6d data packets retransmitted (%d bytes)\r\n",
|
||||||
|
tcpstat.tcps_sndrexmitpack, tcpstat.tcps_sndrexmitbyte);
|
||||||
|
lprint(" %6d ack-only packets (%d delayed)\r\n",
|
||||||
|
tcpstat.tcps_sndacks, tcpstat.tcps_delack);
|
||||||
|
lprint(" %6d URG only packets\r\n", tcpstat.tcps_sndurg);
|
||||||
|
lprint(" %6d window probe packets\r\n", tcpstat.tcps_sndprobe);
|
||||||
|
lprint(" %6d window update packets\r\n", tcpstat.tcps_sndwinup);
|
||||||
|
lprint(" %6d control (SYN/FIN/RST) packets\r\n", tcpstat.tcps_sndctrl);
|
||||||
|
lprint(" %6d times tcp_output did nothing\r\n", tcpstat.tcps_didnuttin);
|
||||||
|
|
||||||
|
lprint(" %6d packets received\r\n", tcpstat.tcps_rcvtotal);
|
||||||
|
lprint(" %6d acks (for %d bytes)\r\n",
|
||||||
|
tcpstat.tcps_rcvackpack, tcpstat.tcps_rcvackbyte);
|
||||||
|
lprint(" %6d duplicate acks\r\n", tcpstat.tcps_rcvdupack);
|
||||||
|
lprint(" %6d acks for unsent data\r\n", tcpstat.tcps_rcvacktoomuch);
|
||||||
|
lprint(" %6d packets received in sequence (%d bytes)\r\n",
|
||||||
|
tcpstat.tcps_rcvpack, tcpstat.tcps_rcvbyte);
|
||||||
|
lprint(" %6d completely duplicate packets (%d bytes)\r\n",
|
||||||
|
tcpstat.tcps_rcvduppack, tcpstat.tcps_rcvdupbyte);
|
||||||
|
|
||||||
|
lprint(" %6d packets with some duplicate data (%d bytes duped)\r\n",
|
||||||
|
tcpstat.tcps_rcvpartduppack, tcpstat.tcps_rcvpartdupbyte);
|
||||||
|
lprint(" %6d out-of-order packets (%d bytes)\r\n",
|
||||||
|
tcpstat.tcps_rcvoopack, tcpstat.tcps_rcvoobyte);
|
||||||
|
lprint(" %6d packets of data after window (%d bytes)\r\n",
|
||||||
|
tcpstat.tcps_rcvpackafterwin, tcpstat.tcps_rcvbyteafterwin);
|
||||||
|
lprint(" %6d window probes\r\n", tcpstat.tcps_rcvwinprobe);
|
||||||
|
lprint(" %6d window update packets\r\n", tcpstat.tcps_rcvwinupd);
|
||||||
|
lprint(" %6d packets received after close\r\n", tcpstat.tcps_rcvafterclose);
|
||||||
|
lprint(" %6d discarded for bad checksums\r\n", tcpstat.tcps_rcvbadsum);
|
||||||
|
lprint(" %6d discarded for bad header offset fields\r\n",
|
||||||
|
tcpstat.tcps_rcvbadoff);
|
||||||
|
|
||||||
|
lprint(" %6d connection requests\r\n", tcpstat.tcps_connattempt);
|
||||||
|
lprint(" %6d connection accepts\r\n", tcpstat.tcps_accepts);
|
||||||
|
lprint(" %6d connections established (including accepts)\r\n", tcpstat.tcps_connects);
|
||||||
|
lprint(" %6d connections closed (including %d drop)\r\n",
|
||||||
|
tcpstat.tcps_closed, tcpstat.tcps_drops);
|
||||||
|
lprint(" %6d embryonic connections dropped\r\n", tcpstat.tcps_conndrops);
|
||||||
|
lprint(" %6d segments we tried to get rtt (%d succeeded)\r\n",
|
||||||
|
tcpstat.tcps_segstimed, tcpstat.tcps_rttupdated);
|
||||||
|
lprint(" %6d retransmit timeouts\r\n", tcpstat.tcps_rexmttimeo);
|
||||||
|
lprint(" %6d connections dropped by rxmt timeout\r\n",
|
||||||
|
tcpstat.tcps_timeoutdrop);
|
||||||
|
lprint(" %6d persist timeouts\r\n", tcpstat.tcps_persisttimeo);
|
||||||
|
lprint(" %6d keepalive timeouts\r\n", tcpstat.tcps_keeptimeo);
|
||||||
|
lprint(" %6d keepalive probes sent\r\n", tcpstat.tcps_keepprobe);
|
||||||
|
lprint(" %6d connections dropped by keepalive\r\n", tcpstat.tcps_keepdrops);
|
||||||
|
lprint(" %6d correct ACK header predictions\r\n", tcpstat.tcps_predack);
|
||||||
|
lprint(" %6d correct data packet header predictions\n", tcpstat.tcps_preddat);
|
||||||
|
lprint(" %6d TCP cache misses\r\n", tcpstat.tcps_socachemiss);
|
||||||
|
|
||||||
|
|
||||||
|
/* lprint(" Packets received too short: %d\r\n", tcpstat.tcps_rcvshort); */
|
||||||
|
/* lprint(" Segments dropped due to PAWS: %d\r\n", tcpstat.tcps_pawsdrop); */
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
udpstats()
|
||||||
|
{
|
||||||
|
lprint(" \r\n");
|
||||||
|
|
||||||
|
lprint("UDP stats:\r\n");
|
||||||
|
lprint(" %6d datagrams received\r\n", udpstat.udps_ipackets);
|
||||||
|
lprint(" %6d with packets shorter than header\r\n", udpstat.udps_hdrops);
|
||||||
|
lprint(" %6d with bad checksums\r\n", udpstat.udps_badsum);
|
||||||
|
lprint(" %6d with data length larger than packet\r\n", udpstat.udps_badlen);
|
||||||
|
lprint(" %6d UDP socket cache misses\r\n", udpstat.udpps_pcbcachemiss);
|
||||||
|
lprint(" %6d datagrams sent\r\n", udpstat.udps_opackets);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
icmpstats()
|
||||||
|
{
|
||||||
|
lprint(" \r\n");
|
||||||
|
lprint("ICMP stats:\r\n");
|
||||||
|
lprint(" %6d ICMP packets received\r\n", icmpstat.icps_received);
|
||||||
|
lprint(" %6d were too short\r\n", icmpstat.icps_tooshort);
|
||||||
|
lprint(" %6d with bad checksums\r\n", icmpstat.icps_checksum);
|
||||||
|
lprint(" %6d with type not supported\r\n", icmpstat.icps_notsupp);
|
||||||
|
lprint(" %6d with bad type feilds\r\n", icmpstat.icps_badtype);
|
||||||
|
lprint(" %6d ICMP packets sent in reply\r\n", icmpstat.icps_reflect);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
mbufstats()
|
||||||
|
{
|
||||||
|
struct mbuf *m;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
lprint(" \r\n");
|
||||||
|
|
||||||
|
lprint("Mbuf stats:\r\n");
|
||||||
|
|
||||||
|
lprint(" %6d mbufs allocated (%d max)\r\n", mbuf_alloced, mbuf_max);
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
for (m = m_freelist.m_next; m != &m_freelist; m = m->m_next)
|
||||||
|
i++;
|
||||||
|
lprint(" %6d mbufs on free list\r\n", i);
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
for (m = m_usedlist.m_next; m != &m_usedlist; m = m->m_next)
|
||||||
|
i++;
|
||||||
|
lprint(" %6d mbufs on used list\r\n", i);
|
||||||
|
lprint(" %6d mbufs queued as packets\r\n\r\n", if_queued);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
sockstats()
|
||||||
|
{
|
||||||
|
char buff[256];
|
||||||
|
int n;
|
||||||
|
struct socket *so;
|
||||||
|
|
||||||
|
lprint(" \r\n");
|
||||||
|
|
||||||
|
lprint(
|
||||||
|
"Proto[state] Sock Local Address, Port Remote Address, Port RecvQ SendQ\r\n");
|
||||||
|
|
||||||
|
for (so = tcb.so_next; so != &tcb; so = so->so_next) {
|
||||||
|
|
||||||
|
n = sprintf(buff, "tcp[%s]", so->so_tcpcb?tcpstates[so->so_tcpcb->t_state]:"NONE");
|
||||||
|
while (n < 17)
|
||||||
|
buff[n++] = ' ';
|
||||||
|
buff[17] = 0;
|
||||||
|
lprint("%s %3d %15s %5d ",
|
||||||
|
buff, so->s,
|
||||||
|
inet_ntoa(so->so_laddr), ntohs(so->so_lport));
|
||||||
|
lprint("%15s %5d %5d %5d\r\n",
|
||||||
|
inet_ntoa(so->so_faddr), ntohs(so->so_fport),
|
||||||
|
so->so_rcv.sb_cc, so->so_snd.sb_cc);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (so = udb.so_next; so != &udb; so = so->so_next) {
|
||||||
|
|
||||||
|
n = sprintf(buff, "udp[%d sec]", (so->so_expire - curtime) / 1000);
|
||||||
|
while (n < 17)
|
||||||
|
buff[n++] = ' ';
|
||||||
|
buff[17] = 0;
|
||||||
|
lprint("%s %3d %15s %5d ",
|
||||||
|
buff, so->s,
|
||||||
|
inet_ntoa(so->so_laddr), ntohs(so->so_lport));
|
||||||
|
lprint("%15s %5d %5d %5d\r\n",
|
||||||
|
inet_ntoa(so->so_faddr), ntohs(so->so_fport),
|
||||||
|
so->so_rcv.sb_cc, so->so_snd.sb_cc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
void
|
||||||
|
slirp_exit(exit_status)
|
||||||
|
int exit_status;
|
||||||
|
{
|
||||||
|
struct ttys *ttyp;
|
||||||
|
|
||||||
|
DEBUG_CALL("slirp_exit");
|
||||||
|
DEBUG_ARG("exit_status = %d", exit_status);
|
||||||
|
|
||||||
|
if (dostats) {
|
||||||
|
lprint_print = (int (*) _P((void *, const char *, va_list)))vfprintf;
|
||||||
|
if (!dfd)
|
||||||
|
debug_init("slirp_stats", 0xf);
|
||||||
|
lprint_arg = (char **)&dfd;
|
||||||
|
|
||||||
|
ipstats();
|
||||||
|
tcpstats();
|
||||||
|
udpstats();
|
||||||
|
icmpstats();
|
||||||
|
mbufstats();
|
||||||
|
sockstats();
|
||||||
|
allttystats();
|
||||||
|
vjstats();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (ttyp = ttys; ttyp; ttyp = ttyp->next)
|
||||||
|
tty_detached(ttyp, 1);
|
||||||
|
|
||||||
|
if (slirp_forked) {
|
||||||
|
/* Menendez time */
|
||||||
|
if (kill(getppid(), SIGQUIT) < 0)
|
||||||
|
lprint("Couldn't kill parent process %ld!\n",
|
||||||
|
(long) getppid());
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Restore the terminal if we gotta */
|
||||||
|
if(slirp_tty_restore)
|
||||||
|
tcsetattr(0,TCSANOW, &slirp_tty_settings); /* NOW DAMMIT! */
|
||||||
|
exit(exit_status);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 1995 Danny Gasparovski.
|
||||||
|
*
|
||||||
|
* Please read the file COPYRIGHT for the
|
||||||
|
* terms and conditions of the copyright.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define PRN_STDERR 1
|
||||||
|
#define PRN_SPRINTF 2
|
||||||
|
|
||||||
|
extern FILE *dfd;
|
||||||
|
extern FILE *lfd;
|
||||||
|
extern int dostats;
|
||||||
|
extern int slirp_debug;
|
||||||
|
|
||||||
|
#define DBG_CALL 0x1
|
||||||
|
#define DBG_MISC 0x2
|
||||||
|
#define DBG_ERROR 0x4
|
||||||
|
#define DEBUG_DEFAULT DBG_CALL|DBG_MISC|DBG_ERROR
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
#define DEBUG_CALL(x) if (slirp_debug & DBG_CALL) { fprintf(dfd, "%s...\n", x); fflush(dfd); }
|
||||||
|
#define DEBUG_ARG(x, y) if (slirp_debug & DBG_CALL) { fputc(' ', dfd); fprintf(dfd, x, y); fputc('\n', dfd); fflush(dfd); }
|
||||||
|
#define DEBUG_ARGS(x) if (slirp_debug & DBG_CALL) { fprintf x ; fflush(dfd); }
|
||||||
|
#define DEBUG_MISC(x) if (slirp_debug & DBG_MISC) { fprintf x ; fflush(dfd); }
|
||||||
|
#define DEBUG_ERROR(x) if (slirp_debug & DBG_ERROR) {fprintf x ; fflush(dfd); }
|
||||||
|
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#define DEBUG_CALL(x)
|
||||||
|
#define DEBUG_ARG(x, y)
|
||||||
|
#define DEBUG_ARGS(x)
|
||||||
|
#define DEBUG_MISC(x)
|
||||||
|
#define DEBUG_ERROR(x)
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void debug_init _P((char *, int));
|
||||||
|
//void ttystats _P((struct ttys *));
|
||||||
|
void allttystats _P((void));
|
||||||
|
void ipstats _P((void));
|
||||||
|
void vjstats _P((void));
|
||||||
|
void tcpstats _P((void));
|
||||||
|
void udpstats _P((void));
|
||||||
|
void icmpstats _P((void));
|
||||||
|
void mbufstats _P((void));
|
||||||
|
void sockstats _P((void));
|
||||||
|
void slirp_exit _P((int));
|
||||||
|
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 1982, 1986, 1993
|
||||||
|
* The Regents of the University of California. All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. All advertising materials mentioning features or use of this software
|
||||||
|
* must display the following acknowledgement:
|
||||||
|
* This product includes software developed by the University of
|
||||||
|
* California, Berkeley and its contributors.
|
||||||
|
* 4. Neither the name of the University nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* @(#)icmp_var.h 8.1 (Berkeley) 6/10/93
|
||||||
|
* icmp_var.h,v 1.4 1995/02/16 00:27:40 wollman Exp
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _NETINET_ICMP_VAR_H_
|
||||||
|
#define _NETINET_ICMP_VAR_H_
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Variables related to this implementation
|
||||||
|
* of the internet control message protocol.
|
||||||
|
*/
|
||||||
|
struct icmpstat {
|
||||||
|
/* statistics related to input messages processed */
|
||||||
|
u_long icps_received; /* #ICMP packets received */
|
||||||
|
u_long icps_tooshort; /* packet < ICMP_MINLEN */
|
||||||
|
u_long icps_checksum; /* bad checksum */
|
||||||
|
u_long icps_notsupp; /* #ICMP packets not supported */
|
||||||
|
u_long icps_badtype; /* #with bad type feild */
|
||||||
|
u_long icps_reflect; /* number of responses */
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Names for ICMP sysctl objects
|
||||||
|
*/
|
||||||
|
#define ICMPCTL_MASKREPL 1 /* allow replies to netmask requests */
|
||||||
|
#define ICMPCTL_STATS 2 /* statistics (read-only) */
|
||||||
|
#define ICMPCTL_MAXID 3
|
||||||
|
|
||||||
|
#define ICMPCTL_NAMES { \
|
||||||
|
{ 0, 0 }, \
|
||||||
|
{ "maskrepl", CTLTYPE_INT }, \
|
||||||
|
{ "stats", CTLTYPE_STRUCT }, \
|
||||||
|
}
|
||||||
|
|
||||||
|
extern struct icmpstat icmpstat;
|
||||||
|
|
||||||
|
#endif
|
||||||
+320
@@ -0,0 +1,320 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 1995 Danny Gasparovski.
|
||||||
|
*
|
||||||
|
* Please read the file COPYRIGHT for the
|
||||||
|
* terms and conditions of the copyright.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <slirp.h>
|
||||||
|
|
||||||
|
int if_mtu, if_mru;
|
||||||
|
int if_comp;
|
||||||
|
int if_maxlinkhdr;
|
||||||
|
int if_queued = 0; /* Number of packets queued so far */
|
||||||
|
int if_thresh = 10; /* Number of packets queued before we start sending
|
||||||
|
* (to prevent allocing too many mbufs) */
|
||||||
|
|
||||||
|
struct mbuf if_fastq; /* fast queue (for interactive data) */
|
||||||
|
struct mbuf if_batchq; /* queue for non-interactive data */
|
||||||
|
struct mbuf *next_m; /* Pointer to next mbuf to output */
|
||||||
|
|
||||||
|
#define ifs_init(ifm) ((ifm)->ifs_next = (ifm)->ifs_prev = (ifm))
|
||||||
|
|
||||||
|
void
|
||||||
|
ifs_insque(ifm, ifmhead)
|
||||||
|
struct mbuf *ifm, *ifmhead;
|
||||||
|
{
|
||||||
|
ifm->ifs_next = ifmhead->ifs_next;
|
||||||
|
ifmhead->ifs_next = ifm;
|
||||||
|
ifm->ifs_prev = ifmhead;
|
||||||
|
ifm->ifs_next->ifs_prev = ifm;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ifs_remque(ifm)
|
||||||
|
struct mbuf *ifm;
|
||||||
|
{
|
||||||
|
ifm->ifs_prev->ifs_next = ifm->ifs_next;
|
||||||
|
ifm->ifs_next->ifs_prev = ifm->ifs_prev;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
if_init()
|
||||||
|
{
|
||||||
|
#if 0
|
||||||
|
/*
|
||||||
|
* Set if_maxlinkhdr to 48 because it's 40 bytes for TCP/IP,
|
||||||
|
* and 8 bytes for PPP, but need to have it on an 8byte boundary
|
||||||
|
*/
|
||||||
|
#ifdef USE_PPP
|
||||||
|
if_maxlinkhdr = 48;
|
||||||
|
#else
|
||||||
|
if_maxlinkhdr = 40;
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
/* 14 for ethernet + 40 */
|
||||||
|
if_maxlinkhdr = 14 + 40;
|
||||||
|
#endif
|
||||||
|
if_mtu = 1500;
|
||||||
|
if_mru = 1500;
|
||||||
|
if_comp = IF_AUTOCOMP;
|
||||||
|
if_fastq.ifq_next = if_fastq.ifq_prev = &if_fastq;
|
||||||
|
if_batchq.ifq_next = if_batchq.ifq_prev = &if_batchq;
|
||||||
|
// sl_compress_init(&comp_s);
|
||||||
|
next_m = &if_batchq;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
/*
|
||||||
|
* This shouldn't be needed since the modem is blocking and
|
||||||
|
* we don't expect any signals, but what the hell..
|
||||||
|
*/
|
||||||
|
inline int
|
||||||
|
writen(fd, bptr, n)
|
||||||
|
int fd;
|
||||||
|
char *bptr;
|
||||||
|
int n;
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
int total;
|
||||||
|
|
||||||
|
/* This should succeed most of the time */
|
||||||
|
ret = write(fd, bptr, n);
|
||||||
|
if (ret == n || ret <= 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
/* Didn't write everything, go into the loop */
|
||||||
|
total = ret;
|
||||||
|
while (n > total) {
|
||||||
|
ret = write(fd, bptr+total, n-total);
|
||||||
|
if (ret <= 0)
|
||||||
|
return ret;
|
||||||
|
total += ret;
|
||||||
|
}
|
||||||
|
return total;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* if_input - read() the tty, do "top level" processing (ie: check for any escapes),
|
||||||
|
* and pass onto (*ttyp->if_input)
|
||||||
|
*
|
||||||
|
* XXXXX Any zeros arriving by themselves are NOT placed into the arriving packet.
|
||||||
|
*/
|
||||||
|
#define INBUFF_SIZE 2048 /* XXX */
|
||||||
|
void
|
||||||
|
if_input(ttyp)
|
||||||
|
struct ttys *ttyp;
|
||||||
|
{
|
||||||
|
u_char if_inbuff[INBUFF_SIZE];
|
||||||
|
int if_n;
|
||||||
|
|
||||||
|
DEBUG_CALL("if_input");
|
||||||
|
DEBUG_ARG("ttyp = %lx", (long)ttyp);
|
||||||
|
|
||||||
|
if_n = read(ttyp->fd, (char *)if_inbuff, INBUFF_SIZE);
|
||||||
|
|
||||||
|
DEBUG_MISC((dfd, " read %d bytes\n", if_n));
|
||||||
|
|
||||||
|
if (if_n <= 0) {
|
||||||
|
if (if_n == 0 || (errno != EINTR && errno != EAGAIN)) {
|
||||||
|
if (ttyp->up)
|
||||||
|
link_up--;
|
||||||
|
tty_detached(ttyp, 0);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (if_n == 1) {
|
||||||
|
if (*if_inbuff == '0') {
|
||||||
|
ttyp->ones = 0;
|
||||||
|
if (++ttyp->zeros >= 5)
|
||||||
|
slirp_exit(0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (*if_inbuff == '1') {
|
||||||
|
ttyp->zeros = 0;
|
||||||
|
if (++ttyp->ones >= 5)
|
||||||
|
tty_detached(ttyp, 0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ttyp->ones = ttyp->zeros = 0;
|
||||||
|
|
||||||
|
(*ttyp->if_input)(ttyp, if_inbuff, if_n);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* if_output: Queue packet into an output queue.
|
||||||
|
* There are 2 output queue's, if_fastq and if_batchq.
|
||||||
|
* Each output queue is a doubly linked list of double linked lists
|
||||||
|
* of mbufs, each list belonging to one "session" (socket). This
|
||||||
|
* way, we can output packets fairly by sending one packet from each
|
||||||
|
* session, instead of all the packets from one session, then all packets
|
||||||
|
* from the next session, etc. Packets on the if_fastq get absolute
|
||||||
|
* priority, but if one session hogs the link, it gets "downgraded"
|
||||||
|
* to the batchq until it runs out of packets, then it'll return
|
||||||
|
* to the fastq (eg. if the user does an ls -alR in a telnet session,
|
||||||
|
* it'll temporarily get downgraded to the batchq)
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
if_output(so, ifm)
|
||||||
|
struct socket *so;
|
||||||
|
struct mbuf *ifm;
|
||||||
|
{
|
||||||
|
struct mbuf *ifq;
|
||||||
|
int on_fastq = 1;
|
||||||
|
|
||||||
|
DEBUG_CALL("if_output");
|
||||||
|
DEBUG_ARG("so = %lx", (long)so);
|
||||||
|
DEBUG_ARG("ifm = %lx", (long)ifm);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* First remove the mbuf from m_usedlist,
|
||||||
|
* since we're gonna use m_next and m_prev ourselves
|
||||||
|
* XXX Shouldn't need this, gotta change dtom() etc.
|
||||||
|
*/
|
||||||
|
if (ifm->m_flags & M_USEDLIST) {
|
||||||
|
remque(ifm);
|
||||||
|
ifm->m_flags &= ~M_USEDLIST;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* See if there's already a batchq list for this session.
|
||||||
|
* This can include an interactive session, which should go on fastq,
|
||||||
|
* but gets too greedy... hence it'll be downgraded from fastq to batchq.
|
||||||
|
* We mustn't put this packet back on the fastq (or we'll send it out of order)
|
||||||
|
* XXX add cache here?
|
||||||
|
*/
|
||||||
|
for (ifq = if_batchq.ifq_prev; ifq != &if_batchq; ifq = ifq->ifq_prev) {
|
||||||
|
if (so == ifq->ifq_so) {
|
||||||
|
/* A match! */
|
||||||
|
ifm->ifq_so = so;
|
||||||
|
ifs_insque(ifm, ifq->ifs_prev);
|
||||||
|
goto diddit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* No match, check which queue to put it on */
|
||||||
|
if (so && (so->so_iptos & IPTOS_LOWDELAY)) {
|
||||||
|
ifq = if_fastq.ifq_prev;
|
||||||
|
on_fastq = 1;
|
||||||
|
/*
|
||||||
|
* Check if this packet is a part of the last
|
||||||
|
* packet's session
|
||||||
|
*/
|
||||||
|
if (ifq->ifq_so == so) {
|
||||||
|
ifm->ifq_so = so;
|
||||||
|
ifs_insque(ifm, ifq->ifs_prev);
|
||||||
|
goto diddit;
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
ifq = if_batchq.ifq_prev;
|
||||||
|
|
||||||
|
/* Create a new doubly linked list for this session */
|
||||||
|
ifm->ifq_so = so;
|
||||||
|
ifs_init(ifm);
|
||||||
|
insque(ifm, ifq);
|
||||||
|
|
||||||
|
diddit:
|
||||||
|
++if_queued;
|
||||||
|
|
||||||
|
if (so) {
|
||||||
|
/* Update *_queued */
|
||||||
|
so->so_queued++;
|
||||||
|
so->so_nqueued++;
|
||||||
|
/*
|
||||||
|
* Check if the interactive session should be downgraded to
|
||||||
|
* the batchq. A session is downgraded if it has queued 6
|
||||||
|
* packets without pausing, and at least 3 of those packets
|
||||||
|
* have been sent over the link
|
||||||
|
* (XXX These are arbitrary numbers, probably not optimal..)
|
||||||
|
*/
|
||||||
|
if (on_fastq && ((so->so_nqueued >= 6) &&
|
||||||
|
(so->so_nqueued - so->so_queued) >= 3)) {
|
||||||
|
|
||||||
|
/* Remove from current queue... */
|
||||||
|
remque(ifm->ifs_next);
|
||||||
|
|
||||||
|
/* ...And insert in the new. That'll teach ya! */
|
||||||
|
insque(ifm->ifs_next, &if_batchq);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef FULL_BOLT
|
||||||
|
/*
|
||||||
|
* This prevents us from malloc()ing too many mbufs
|
||||||
|
*/
|
||||||
|
if (link_up) {
|
||||||
|
/* if_start will check towrite */
|
||||||
|
if_start();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Send a packet
|
||||||
|
* We choose a packet based on it's position in the output queues;
|
||||||
|
* If there are packets on the fastq, they are sent FIFO, before
|
||||||
|
* everything else. Otherwise we choose the first packet from the
|
||||||
|
* batchq and send it. the next packet chosen will be from the session
|
||||||
|
* after this one, then the session after that one, and so on.. So,
|
||||||
|
* for example, if there are 3 ftp session's fighting for bandwidth,
|
||||||
|
* one packet will be sent from the first session, then one packet
|
||||||
|
* from the second session, then one packet from the third, then back
|
||||||
|
* to the first, etc. etc.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
if_start(void)
|
||||||
|
{
|
||||||
|
struct mbuf *ifm, *ifqt;
|
||||||
|
|
||||||
|
DEBUG_CALL("if_start");
|
||||||
|
|
||||||
|
if (if_queued == 0)
|
||||||
|
return; /* Nothing to do */
|
||||||
|
|
||||||
|
again:
|
||||||
|
/* check if we can really output */
|
||||||
|
if (!slirp_can_output())
|
||||||
|
return;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* See which queue to get next packet from
|
||||||
|
* If there's something in the fastq, select it immediately
|
||||||
|
*/
|
||||||
|
if (if_fastq.ifq_next != &if_fastq) {
|
||||||
|
ifm = if_fastq.ifq_next;
|
||||||
|
} else {
|
||||||
|
/* Nothing on fastq, see if next_m is valid */
|
||||||
|
if (next_m != &if_batchq)
|
||||||
|
ifm = next_m;
|
||||||
|
else
|
||||||
|
ifm = if_batchq.ifq_next;
|
||||||
|
|
||||||
|
/* Set which packet to send on next iteration */
|
||||||
|
next_m = ifm->ifq_next;
|
||||||
|
}
|
||||||
|
/* Remove it from the queue */
|
||||||
|
ifqt = ifm->ifq_prev;
|
||||||
|
remque(ifm);
|
||||||
|
--if_queued;
|
||||||
|
|
||||||
|
/* If there are more packets for this session, re-queue them */
|
||||||
|
if (ifm->ifs_next != /* ifm->ifs_prev != */ ifm) {
|
||||||
|
insque(ifm->ifs_next, ifqt);
|
||||||
|
ifs_remque(ifm);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Update so_queued */
|
||||||
|
if (ifm->ifq_so) {
|
||||||
|
if (--ifm->ifq_so->so_queued == 0)
|
||||||
|
/* If there's no more queued, reset nqueued */
|
||||||
|
ifm->ifq_so->so_nqueued = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Encapsulate the packet for sending */
|
||||||
|
if_encap(ifm->m_data, ifm->m_len);
|
||||||
|
|
||||||
|
if (if_queued)
|
||||||
|
goto again;
|
||||||
|
}
|
||||||
+50
@@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 1995 Danny Gasparovski.
|
||||||
|
*
|
||||||
|
* Please read the file COPYRIGHT for the
|
||||||
|
* terms and conditions of the copyright.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _IF_H_
|
||||||
|
#define _IF_H_
|
||||||
|
|
||||||
|
#define IF_COMPRESS 0x01 /* We want compression */
|
||||||
|
#define IF_NOCOMPRESS 0x02 /* Do not do compression */
|
||||||
|
#define IF_AUTOCOMP 0x04 /* Autodetect (default) */
|
||||||
|
#define IF_NOCIDCOMP 0x08 /* CID compression */
|
||||||
|
|
||||||
|
/* Needed for FreeBSD */
|
||||||
|
#undef if_mtu
|
||||||
|
extern int if_mtu;
|
||||||
|
extern int if_mru; /* MTU and MRU */
|
||||||
|
extern int if_comp; /* Flags for compression */
|
||||||
|
extern int if_maxlinkhdr;
|
||||||
|
extern int if_queued; /* Number of packets queued so far */
|
||||||
|
extern int if_thresh; /* Number of packets queued before we start sending
|
||||||
|
* (to prevent allocing too many mbufs) */
|
||||||
|
|
||||||
|
extern struct mbuf if_fastq; /* fast queue (for interactive data) */
|
||||||
|
extern struct mbuf if_batchq; /* queue for non-interactive data */
|
||||||
|
extern struct mbuf *next_m;
|
||||||
|
|
||||||
|
#define ifs_init(ifm) ((ifm)->ifs_next = (ifm)->ifs_prev = (ifm))
|
||||||
|
|
||||||
|
/* Interface statistics */
|
||||||
|
struct slirp_ifstats {
|
||||||
|
u_int out_pkts; /* Output packets */
|
||||||
|
u_int out_bytes; /* Output bytes */
|
||||||
|
u_int out_errpkts; /* Output Error Packets */
|
||||||
|
u_int out_errbytes; /* Output Error Bytes */
|
||||||
|
u_int in_pkts; /* Input packets */
|
||||||
|
u_int in_bytes; /* Input bytes */
|
||||||
|
u_int in_errpkts; /* Input Error Packets */
|
||||||
|
u_int in_errbytes; /* Input Error Bytes */
|
||||||
|
|
||||||
|
u_int bytes_saved; /* Number of bytes that compression "saved" */
|
||||||
|
/* ie: number of bytes that didn't need to be sent over the link
|
||||||
|
* because of compression */
|
||||||
|
|
||||||
|
u_int in_mbad; /* Bad incoming packets */
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
+317
@@ -0,0 +1,317 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 1982, 1986, 1993
|
||||||
|
* The Regents of the University of California. All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. All advertising materials mentioning features or use of this software
|
||||||
|
* must display the following acknowledgement:
|
||||||
|
* This product includes software developed by the University of
|
||||||
|
* California, Berkeley and its contributors.
|
||||||
|
* 4. Neither the name of the University nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* @(#)ip.h 8.1 (Berkeley) 6/10/93
|
||||||
|
* ip.h,v 1.3 1994/08/21 05:27:30 paul Exp
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _IP_H_
|
||||||
|
#define _IP_H_
|
||||||
|
|
||||||
|
#ifdef WORDS_BIGENDIAN
|
||||||
|
# ifndef NTOHL
|
||||||
|
# define NTOHL(d)
|
||||||
|
# endif
|
||||||
|
# ifndef NTOHS
|
||||||
|
# define NTOHS(d)
|
||||||
|
# endif
|
||||||
|
# ifndef HTONL
|
||||||
|
# define HTONL(d)
|
||||||
|
# endif
|
||||||
|
# ifndef HTONS
|
||||||
|
# define HTONS(d)
|
||||||
|
# endif
|
||||||
|
#else
|
||||||
|
# ifndef NTOHL
|
||||||
|
# define NTOHL(d) ((d) = ntohl((d)))
|
||||||
|
# endif
|
||||||
|
# ifndef NTOHS
|
||||||
|
# define NTOHS(d) ((d) = ntohs((u_int16_t)(d)))
|
||||||
|
# endif
|
||||||
|
# ifndef HTONL
|
||||||
|
# define HTONL(d) ((d) = htonl((d)))
|
||||||
|
# endif
|
||||||
|
# ifndef HTONS
|
||||||
|
# define HTONS(d) ((d) = htons((u_int16_t)(d)))
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef u_int32_t n_long; /* long as received from the net */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Definitions for internet protocol version 4.
|
||||||
|
* Per RFC 791, September 1981.
|
||||||
|
*/
|
||||||
|
#define IPVERSION 4
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Structure of an internet header, naked of options.
|
||||||
|
*
|
||||||
|
* We declare ip_len and ip_off to be short, rather than u_short
|
||||||
|
* pragmatically since otherwise unsigned comparisons can result
|
||||||
|
* against negative integers quite easily, and fail in subtle ways.
|
||||||
|
*/
|
||||||
|
struct ip {
|
||||||
|
#ifdef WORDS_BIGENDIAN
|
||||||
|
u_int ip_v:4, /* version */
|
||||||
|
ip_hl:4; /* header length */
|
||||||
|
#else
|
||||||
|
u_int ip_hl:4, /* header length */
|
||||||
|
ip_v:4; /* version */
|
||||||
|
#endif
|
||||||
|
u_int8_t ip_tos; /* type of service */
|
||||||
|
int16_t ip_len; /* total length */
|
||||||
|
u_int16_t ip_id; /* identification */
|
||||||
|
int16_t ip_off; /* fragment offset field */
|
||||||
|
#define IP_DF 0x4000 /* don't fragment flag */
|
||||||
|
#define IP_MF 0x2000 /* more fragments flag */
|
||||||
|
#define IP_OFFMASK 0x1fff /* mask for fragmenting bits */
|
||||||
|
u_int8_t ip_ttl; /* time to live */
|
||||||
|
u_int8_t ip_p; /* protocol */
|
||||||
|
u_int16_t ip_sum; /* checksum */
|
||||||
|
struct in_addr ip_src,ip_dst; /* source and dest address */
|
||||||
|
};
|
||||||
|
|
||||||
|
#define IP_MAXPACKET 65535 /* maximum packet size */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Definitions for IP type of service (ip_tos)
|
||||||
|
*/
|
||||||
|
#define IPTOS_LOWDELAY 0x10
|
||||||
|
#define IPTOS_THROUGHPUT 0x08
|
||||||
|
#define IPTOS_RELIABILITY 0x04
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Definitions for options.
|
||||||
|
*/
|
||||||
|
#define IPOPT_COPIED(o) ((o)&0x80)
|
||||||
|
#define IPOPT_CLASS(o) ((o)&0x60)
|
||||||
|
#define IPOPT_NUMBER(o) ((o)&0x1f)
|
||||||
|
|
||||||
|
#define IPOPT_CONTROL 0x00
|
||||||
|
#define IPOPT_RESERVED1 0x20
|
||||||
|
#define IPOPT_DEBMEAS 0x40
|
||||||
|
#define IPOPT_RESERVED2 0x60
|
||||||
|
|
||||||
|
#define IPOPT_EOL 0 /* end of option list */
|
||||||
|
#define IPOPT_NOP 1 /* no operation */
|
||||||
|
|
||||||
|
#define IPOPT_RR 7 /* record packet route */
|
||||||
|
#define IPOPT_TS 68 /* timestamp */
|
||||||
|
#define IPOPT_SECURITY 130 /* provide s,c,h,tcc */
|
||||||
|
#define IPOPT_LSRR 131 /* loose source route */
|
||||||
|
#define IPOPT_SATID 136 /* satnet id */
|
||||||
|
#define IPOPT_SSRR 137 /* strict source route */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Offsets to fields in options other than EOL and NOP.
|
||||||
|
*/
|
||||||
|
#define IPOPT_OPTVAL 0 /* option ID */
|
||||||
|
#define IPOPT_OLEN 1 /* option length */
|
||||||
|
#define IPOPT_OFFSET 2 /* offset within option */
|
||||||
|
#define IPOPT_MINOFF 4 /* min value of above */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Time stamp option structure.
|
||||||
|
*/
|
||||||
|
struct ip_timestamp {
|
||||||
|
u_int8_t ipt_code; /* IPOPT_TS */
|
||||||
|
u_int8_t ipt_len; /* size of structure (variable) */
|
||||||
|
u_int8_t ipt_ptr; /* index of current entry */
|
||||||
|
#ifdef WORDS_BIGENDIAN
|
||||||
|
u_int ipt_oflw:4, /* overflow counter */
|
||||||
|
ipt_flg:4; /* flags, see below */
|
||||||
|
#else
|
||||||
|
u_int ipt_flg:4, /* flags, see below */
|
||||||
|
ipt_oflw:4; /* overflow counter */
|
||||||
|
#endif
|
||||||
|
union ipt_timestamp {
|
||||||
|
n_long ipt_time[1];
|
||||||
|
struct ipt_ta {
|
||||||
|
struct in_addr ipt_addr;
|
||||||
|
n_long ipt_time;
|
||||||
|
} ipt_ta[1];
|
||||||
|
} ipt_timestamp;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* flag bits for ipt_flg */
|
||||||
|
#define IPOPT_TS_TSONLY 0 /* timestamps only */
|
||||||
|
#define IPOPT_TS_TSANDADDR 1 /* timestamps and addresses */
|
||||||
|
#define IPOPT_TS_PRESPEC 3 /* specified modules only */
|
||||||
|
|
||||||
|
/* bits for security (not byte swapped) */
|
||||||
|
#define IPOPT_SECUR_UNCLASS 0x0000
|
||||||
|
#define IPOPT_SECUR_CONFID 0xf135
|
||||||
|
#define IPOPT_SECUR_EFTO 0x789a
|
||||||
|
#define IPOPT_SECUR_MMMM 0xbc4d
|
||||||
|
#define IPOPT_SECUR_RESTR 0xaf13
|
||||||
|
#define IPOPT_SECUR_SECRET 0xd788
|
||||||
|
#define IPOPT_SECUR_TOPSECRET 0x6bc5
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Internet implementation parameters.
|
||||||
|
*/
|
||||||
|
#define MAXTTL 255 /* maximum time to live (seconds) */
|
||||||
|
#define IPDEFTTL 64 /* default ttl, from RFC 1340 */
|
||||||
|
#define IPFRAGTTL 60 /* time to live for frags, slowhz */
|
||||||
|
#define IPTTLDEC 1 /* subtracted when forwarding */
|
||||||
|
|
||||||
|
#define IP_MSS 576 /* default maximum segment size */
|
||||||
|
|
||||||
|
#ifdef HAVE_SYS_TYPES32_H /* Overcome some Solaris 2.x junk */
|
||||||
|
#include <sys/types32.h>
|
||||||
|
#else
|
||||||
|
#if SIZEOF_CHAR_P == 4
|
||||||
|
typedef caddr_t caddr32_t;
|
||||||
|
#else
|
||||||
|
typedef u_int32_t caddr32_t;
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if SIZEOF_CHAR_P == 4
|
||||||
|
typedef struct ipq *ipqp_32;
|
||||||
|
typedef struct ipasfrag *ipasfragp_32;
|
||||||
|
#else
|
||||||
|
typedef caddr32_t ipqp_32;
|
||||||
|
typedef caddr32_t ipasfragp_32;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Overlay for ip header used by other protocols (tcp, udp).
|
||||||
|
*/
|
||||||
|
struct ipovly {
|
||||||
|
caddr32_t ih_next, ih_prev; /* for protocol sequence q's */
|
||||||
|
u_int8_t ih_x1; /* (unused) */
|
||||||
|
u_int8_t ih_pr; /* protocol */
|
||||||
|
int16_t ih_len; /* protocol length */
|
||||||
|
struct in_addr ih_src; /* source internet address */
|
||||||
|
struct in_addr ih_dst; /* destination internet address */
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Ip reassembly queue structure. Each fragment
|
||||||
|
* being reassembled is attached to one of these structures.
|
||||||
|
* They are timed out after ipq_ttl drops to 0, and may also
|
||||||
|
* be reclaimed if memory becomes tight.
|
||||||
|
* size 28 bytes
|
||||||
|
*/
|
||||||
|
struct ipq {
|
||||||
|
ipqp_32 next,prev; /* to other reass headers */
|
||||||
|
u_int8_t ipq_ttl; /* time for reass q to live */
|
||||||
|
u_int8_t ipq_p; /* protocol of this fragment */
|
||||||
|
u_int16_t ipq_id; /* sequence id for reassembly */
|
||||||
|
ipasfragp_32 ipq_next,ipq_prev;
|
||||||
|
/* to ip headers of fragments */
|
||||||
|
struct in_addr ipq_src,ipq_dst;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Ip header, when holding a fragment.
|
||||||
|
*
|
||||||
|
* Note: ipf_next must be at same offset as ipq_next above
|
||||||
|
*/
|
||||||
|
struct ipasfrag {
|
||||||
|
#ifdef WORDS_BIGENDIAN
|
||||||
|
u_int ip_v:4,
|
||||||
|
ip_hl:4;
|
||||||
|
#else
|
||||||
|
u_int ip_hl:4,
|
||||||
|
ip_v:4;
|
||||||
|
#endif
|
||||||
|
/* BUG : u_int changed to u_int8_t.
|
||||||
|
* sizeof(u_int)==4 on linux 2.0
|
||||||
|
*/
|
||||||
|
u_int8_t ipf_mff; /* XXX overlays ip_tos: use low bit
|
||||||
|
* to avoid destroying tos (PPPDTRuu);
|
||||||
|
* copied from (ip_off&IP_MF) */
|
||||||
|
int16_t ip_len;
|
||||||
|
u_int16_t ip_id;
|
||||||
|
int16_t ip_off;
|
||||||
|
u_int8_t ip_ttl;
|
||||||
|
u_int8_t ip_p;
|
||||||
|
u_int16_t ip_sum;
|
||||||
|
ipasfragp_32 ipf_next; /* next fragment */
|
||||||
|
ipasfragp_32 ipf_prev; /* previous fragment */
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Structure stored in mbuf in inpcb.ip_options
|
||||||
|
* and passed to ip_output when ip options are in use.
|
||||||
|
* The actual length of the options (including ipopt_dst)
|
||||||
|
* is in m_len.
|
||||||
|
*/
|
||||||
|
#define MAX_IPOPTLEN 40
|
||||||
|
|
||||||
|
struct ipoption {
|
||||||
|
struct in_addr ipopt_dst; /* first-hop dst if source routed */
|
||||||
|
int8_t ipopt_list[MAX_IPOPTLEN]; /* options proper */
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Structure attached to inpcb.ip_moptions and
|
||||||
|
* passed to ip_output when IP multicast options are in use.
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct ipstat {
|
||||||
|
u_long ips_total; /* total packets received */
|
||||||
|
u_long ips_badsum; /* checksum bad */
|
||||||
|
u_long ips_tooshort; /* packet too short */
|
||||||
|
u_long ips_toosmall; /* not enough data */
|
||||||
|
u_long ips_badhlen; /* ip header length < data size */
|
||||||
|
u_long ips_badlen; /* ip length < ip header length */
|
||||||
|
u_long ips_fragments; /* fragments received */
|
||||||
|
u_long ips_fragdropped; /* frags dropped (dups, out of space) */
|
||||||
|
u_long ips_fragtimeout; /* fragments timed out */
|
||||||
|
u_long ips_forward; /* packets forwarded */
|
||||||
|
u_long ips_cantforward; /* packets rcvd for unreachable dest */
|
||||||
|
u_long ips_redirectsent; /* packets forwarded on same net */
|
||||||
|
u_long ips_noproto; /* unknown or unsupported protocol */
|
||||||
|
u_long ips_delivered; /* datagrams delivered to upper level*/
|
||||||
|
u_long ips_localout; /* total ip packets generated here */
|
||||||
|
u_long ips_odropped; /* lost packets due to nobufs, etc. */
|
||||||
|
u_long ips_reassembled; /* total packets reassembled ok */
|
||||||
|
u_long ips_fragmented; /* datagrams successfully fragmented */
|
||||||
|
u_long ips_ofragments; /* output fragments created */
|
||||||
|
u_long ips_cantfrag; /* don't fragment flag was set, etc. */
|
||||||
|
u_long ips_badoptions; /* error in option processing */
|
||||||
|
u_long ips_noroute; /* packets discarded due to no route */
|
||||||
|
u_long ips_badvers; /* ip version != 4 */
|
||||||
|
u_long ips_rawout; /* total raw ip packets generated */
|
||||||
|
u_long ips_unaligned; /* times the ip packet was not aligned */
|
||||||
|
};
|
||||||
|
|
||||||
|
extern struct ipstat ipstat;
|
||||||
|
extern struct ipq ipq; /* ip reass. queue */
|
||||||
|
extern u_int16_t ip_id; /* ip packet ctr, for ids */
|
||||||
|
extern int ip_defttl; /* default IP ttl */
|
||||||
|
|
||||||
|
#endif
|
||||||
+376
@@ -0,0 +1,376 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 1982, 1986, 1988, 1993
|
||||||
|
* The Regents of the University of California. All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. All advertising materials mentioning features or use of this software
|
||||||
|
* must display the following acknowledgement:
|
||||||
|
* This product includes software developed by the University of
|
||||||
|
* California, Berkeley and its contributors.
|
||||||
|
* 4. Neither the name of the University nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* @(#)ip_icmp.c 8.2 (Berkeley) 1/4/94
|
||||||
|
* ip_icmp.c,v 1.7 1995/05/30 08:09:42 rgrimes Exp
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "slirp.h"
|
||||||
|
#include "ip_icmp.h"
|
||||||
|
|
||||||
|
struct icmpstat icmpstat;
|
||||||
|
|
||||||
|
/* The message sent when emulating PING */
|
||||||
|
/* Be nice and tell them it's just a psuedo-ping packet */
|
||||||
|
char icmp_ping_msg[] = "This is a psuedo-PING packet used by Slirp to emulate ICMP ECHO-REQUEST packets.\n";
|
||||||
|
|
||||||
|
/* list of actions for icmp_error() on RX of an icmp message */
|
||||||
|
static int icmp_flush[19] = {
|
||||||
|
/* ECHO REPLY (0) */ 0,
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
/* DEST UNREACH (3) */ 1,
|
||||||
|
/* SOURCE QUENCH (4)*/ 1,
|
||||||
|
/* REDIRECT (5) */ 1,
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
/* ECHO (8) */ 0,
|
||||||
|
/* ROUTERADVERT (9) */ 1,
|
||||||
|
/* ROUTERSOLICIT (10) */ 1,
|
||||||
|
/* TIME EXCEEDED (11) */ 1,
|
||||||
|
/* PARAMETER PROBLEM (12) */ 1,
|
||||||
|
/* TIMESTAMP (13) */ 0,
|
||||||
|
/* TIMESTAMP REPLY (14) */ 0,
|
||||||
|
/* INFO (15) */ 0,
|
||||||
|
/* INFO REPLY (16) */ 0,
|
||||||
|
/* ADDR MASK (17) */ 0,
|
||||||
|
/* ADDR MASK REPLY (18) */ 0
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Process a received ICMP message.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
icmp_input(m, hlen)
|
||||||
|
struct mbuf *m;
|
||||||
|
int hlen;
|
||||||
|
{
|
||||||
|
register struct icmp *icp;
|
||||||
|
register struct ip *ip=mtod(m, struct ip *);
|
||||||
|
int icmplen=ip->ip_len;
|
||||||
|
/* int code; */
|
||||||
|
|
||||||
|
DEBUG_CALL("icmp_input");
|
||||||
|
DEBUG_ARG("m = %lx", (long )m);
|
||||||
|
DEBUG_ARG("m_len = %d", m->m_len);
|
||||||
|
|
||||||
|
icmpstat.icps_received++;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Locate icmp structure in mbuf, and check
|
||||||
|
* that its not corrupted and of at least minimum length.
|
||||||
|
*/
|
||||||
|
if (icmplen < ICMP_MINLEN) { /* min 8 bytes payload */
|
||||||
|
icmpstat.icps_tooshort++;
|
||||||
|
freeit:
|
||||||
|
m_freem(m);
|
||||||
|
goto end_error;
|
||||||
|
}
|
||||||
|
|
||||||
|
m->m_len -= hlen;
|
||||||
|
m->m_data += hlen;
|
||||||
|
icp = mtod(m, struct icmp *);
|
||||||
|
if (cksum(m, icmplen)) {
|
||||||
|
icmpstat.icps_checksum++;
|
||||||
|
goto freeit;
|
||||||
|
}
|
||||||
|
m->m_len += hlen;
|
||||||
|
m->m_data -= hlen;
|
||||||
|
|
||||||
|
/* icmpstat.icps_inhist[icp->icmp_type]++; */
|
||||||
|
/* code = icp->icmp_code; */
|
||||||
|
|
||||||
|
DEBUG_ARG("icmp_type = %d", icp->icmp_type);
|
||||||
|
switch (icp->icmp_type) {
|
||||||
|
case ICMP_ECHO:
|
||||||
|
icp->icmp_type = ICMP_ECHOREPLY;
|
||||||
|
ip->ip_len += hlen; /* since ip_input subtracts this */
|
||||||
|
if (ip->ip_dst.s_addr == our_addr.s_addr ||
|
||||||
|
(ip->ip_dst.s_addr == (special_addr.s_addr|htonl(CTL_ALIAS))) ) {
|
||||||
|
icmp_reflect(m);
|
||||||
|
} else {
|
||||||
|
struct socket *so;
|
||||||
|
struct sockaddr_in addr;
|
||||||
|
if ((so = socreate()) == NULL) goto freeit;
|
||||||
|
if(udp_attach(so) == -1) {
|
||||||
|
DEBUG_MISC((dfd,"icmp_input udp_attach errno = %d-%s\n",
|
||||||
|
errno,strerror(errno)));
|
||||||
|
sofree(so);
|
||||||
|
m_free(m);
|
||||||
|
goto end_error;
|
||||||
|
}
|
||||||
|
so->so_m = m;
|
||||||
|
so->so_faddr = ip->ip_dst;
|
||||||
|
so->so_fport = htons(7);
|
||||||
|
so->so_laddr = ip->ip_src;
|
||||||
|
so->so_lport = htons(9);
|
||||||
|
so->so_iptos = ip->ip_tos;
|
||||||
|
so->so_type = IPPROTO_ICMP;
|
||||||
|
so->so_state = SS_ISFCONNECTED;
|
||||||
|
|
||||||
|
/* Send the packet */
|
||||||
|
addr.sin_family = AF_INET;
|
||||||
|
if ((so->so_faddr.s_addr & htonl(0xffffff00)) == special_addr.s_addr) {
|
||||||
|
/* It's an alias */
|
||||||
|
switch(ntohl(so->so_faddr.s_addr) & 0xff) {
|
||||||
|
case CTL_DNS:
|
||||||
|
addr.sin_addr = dns_addr;
|
||||||
|
break;
|
||||||
|
case CTL_ALIAS:
|
||||||
|
default:
|
||||||
|
addr.sin_addr = loopback_addr;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
addr.sin_addr = so->so_faddr;
|
||||||
|
}
|
||||||
|
addr.sin_port = so->so_fport;
|
||||||
|
if(sendto(so->s, icmp_ping_msg, strlen(icmp_ping_msg), 0,
|
||||||
|
(struct sockaddr *)&addr, sizeof(addr)) == -1) {
|
||||||
|
DEBUG_MISC((dfd,"icmp_input udp sendto tx errno = %d-%s\n",
|
||||||
|
errno,strerror(errno)));
|
||||||
|
icmp_error(m, ICMP_UNREACH,ICMP_UNREACH_NET, 0,strerror(errno));
|
||||||
|
udp_detach(so);
|
||||||
|
}
|
||||||
|
} /* if ip->ip_dst.s_addr == our_addr.s_addr */
|
||||||
|
break;
|
||||||
|
case ICMP_UNREACH:
|
||||||
|
/* XXX? report error? close socket? */
|
||||||
|
case ICMP_TIMXCEED:
|
||||||
|
case ICMP_PARAMPROB:
|
||||||
|
case ICMP_SOURCEQUENCH:
|
||||||
|
case ICMP_TSTAMP:
|
||||||
|
case ICMP_MASKREQ:
|
||||||
|
case ICMP_REDIRECT:
|
||||||
|
icmpstat.icps_notsupp++;
|
||||||
|
m_freem(m);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
icmpstat.icps_badtype++;
|
||||||
|
m_freem(m);
|
||||||
|
} /* swith */
|
||||||
|
|
||||||
|
end_error:
|
||||||
|
/* m is m_free()'d xor put in a socket xor or given to ip_send */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Send an ICMP message in response to a situation
|
||||||
|
*
|
||||||
|
* RFC 1122: 3.2.2 MUST send at least the IP header and 8 bytes of header. MAY send more (we do).
|
||||||
|
* MUST NOT change this header information.
|
||||||
|
* MUST NOT reply to a multicast/broadcast IP address.
|
||||||
|
* MUST NOT reply to a multicast/broadcast MAC address.
|
||||||
|
* MUST reply to only the first fragment.
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
* Send ICMP_UNREACH back to the source regarding msrc.
|
||||||
|
* mbuf *msrc is used as a template, but is NOT m_free()'d.
|
||||||
|
* It is reported as the bad ip packet. The header should
|
||||||
|
* be fully correct and in host byte order.
|
||||||
|
* ICMP fragmentation is illegal. All machines must accept 576 bytes in one
|
||||||
|
* packet. The maximum payload is 576-20(ip hdr)-8(icmp hdr)=548
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define ICMP_MAXDATALEN (IP_MSS-28)
|
||||||
|
void
|
||||||
|
icmp_error(msrc, type, code, minsize, message)
|
||||||
|
struct mbuf *msrc;
|
||||||
|
u_char type;
|
||||||
|
u_char code;
|
||||||
|
int minsize;
|
||||||
|
char *message;
|
||||||
|
{
|
||||||
|
unsigned hlen, shlen, s_ip_len;
|
||||||
|
register struct ip *ip;
|
||||||
|
register struct icmp *icp;
|
||||||
|
register struct mbuf *m;
|
||||||
|
|
||||||
|
DEBUG_CALL("icmp_error");
|
||||||
|
DEBUG_ARG("msrc = %lx", (long )msrc);
|
||||||
|
DEBUG_ARG("msrc_len = %d", msrc->m_len);
|
||||||
|
|
||||||
|
if(type!=ICMP_UNREACH && type!=ICMP_TIMXCEED) goto end_error;
|
||||||
|
|
||||||
|
/* check msrc */
|
||||||
|
if(!msrc) goto end_error;
|
||||||
|
ip = mtod(msrc, struct ip *);
|
||||||
|
#if DEBUG
|
||||||
|
{ char bufa[20], bufb[20];
|
||||||
|
strcpy(bufa, inet_ntoa(ip->ip_src));
|
||||||
|
strcpy(bufb, inet_ntoa(ip->ip_dst));
|
||||||
|
DEBUG_MISC((dfd, " %.16s to %.16s\n", bufa, bufb));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if(ip->ip_off & IP_OFFMASK) goto end_error; /* Only reply to fragment 0 */
|
||||||
|
|
||||||
|
shlen=ip->ip_hl << 2;
|
||||||
|
s_ip_len=ip->ip_len;
|
||||||
|
if(ip->ip_p == IPPROTO_ICMP) {
|
||||||
|
icp = (struct icmp *)((char *)ip + shlen);
|
||||||
|
/*
|
||||||
|
* Assume any unknown ICMP type is an error. This isn't
|
||||||
|
* specified by the RFC, but think about it..
|
||||||
|
*/
|
||||||
|
if(icp->icmp_type>18 || icmp_flush[icp->icmp_type]) goto end_error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* make a copy */
|
||||||
|
if(!(m=m_get())) goto end_error; /* get mbuf */
|
||||||
|
{ int new_m_size;
|
||||||
|
new_m_size=sizeof(struct ip )+ICMP_MINLEN+msrc->m_len+ICMP_MAXDATALEN;
|
||||||
|
if(new_m_size>m->m_size) m_inc(m, new_m_size);
|
||||||
|
}
|
||||||
|
memcpy(m->m_data, msrc->m_data, msrc->m_len);
|
||||||
|
m->m_len = msrc->m_len; /* copy msrc to m */
|
||||||
|
|
||||||
|
/* make the header of the reply packet */
|
||||||
|
ip = mtod(m, struct ip *);
|
||||||
|
hlen= sizeof(struct ip ); /* no options in reply */
|
||||||
|
|
||||||
|
/* fill in icmp */
|
||||||
|
m->m_data += hlen;
|
||||||
|
m->m_len -= hlen;
|
||||||
|
|
||||||
|
icp = mtod(m, struct icmp *);
|
||||||
|
|
||||||
|
if(minsize) s_ip_len=shlen+ICMP_MINLEN; /* return header+8b only */
|
||||||
|
else if(s_ip_len>ICMP_MAXDATALEN) /* maximum size */
|
||||||
|
s_ip_len=ICMP_MAXDATALEN;
|
||||||
|
|
||||||
|
m->m_len=ICMP_MINLEN+s_ip_len; /* 8 bytes ICMP header */
|
||||||
|
|
||||||
|
/* min. size = 8+sizeof(struct ip)+8 */
|
||||||
|
|
||||||
|
icp->icmp_type = type;
|
||||||
|
icp->icmp_code = code;
|
||||||
|
icp->icmp_id = 0;
|
||||||
|
icp->icmp_seq = 0;
|
||||||
|
|
||||||
|
memcpy(&icp->icmp_ip, msrc->m_data, s_ip_len); /* report the ip packet */
|
||||||
|
HTONS(icp->icmp_ip.ip_len);
|
||||||
|
HTONS(icp->icmp_ip.ip_id);
|
||||||
|
HTONS(icp->icmp_ip.ip_off);
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
if(message) { /* DEBUG : append message to ICMP packet */
|
||||||
|
int message_len;
|
||||||
|
char *cpnt;
|
||||||
|
message_len=strlen(message);
|
||||||
|
if(message_len>ICMP_MAXDATALEN) message_len=ICMP_MAXDATALEN;
|
||||||
|
cpnt=(char *)m->m_data+m->m_len;
|
||||||
|
memcpy(cpnt, message, message_len);
|
||||||
|
m->m_len+=message_len;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
icp->icmp_cksum = 0;
|
||||||
|
icp->icmp_cksum = cksum(m, m->m_len);
|
||||||
|
|
||||||
|
m->m_data -= hlen;
|
||||||
|
m->m_len += hlen;
|
||||||
|
|
||||||
|
/* fill in ip */
|
||||||
|
ip->ip_hl = hlen >> 2;
|
||||||
|
ip->ip_len = m->m_len;
|
||||||
|
|
||||||
|
ip->ip_tos=((ip->ip_tos & 0x1E) | 0xC0); /* high priority for errors */
|
||||||
|
|
||||||
|
ip->ip_ttl = MAXTTL;
|
||||||
|
ip->ip_p = IPPROTO_ICMP;
|
||||||
|
ip->ip_dst = ip->ip_src; /* ip adresses */
|
||||||
|
ip->ip_src = our_addr;
|
||||||
|
|
||||||
|
(void ) ip_output((struct socket *)NULL, m);
|
||||||
|
|
||||||
|
icmpstat.icps_reflect++;
|
||||||
|
|
||||||
|
end_error:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#undef ICMP_MAXDATALEN
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Reflect the ip packet back to the source
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
icmp_reflect(m)
|
||||||
|
struct mbuf *m;
|
||||||
|
{
|
||||||
|
register struct ip *ip = mtod(m, struct ip *);
|
||||||
|
int hlen = ip->ip_hl << 2;
|
||||||
|
int optlen = hlen - sizeof(struct ip );
|
||||||
|
register struct icmp *icp;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Send an icmp packet back to the ip level,
|
||||||
|
* after supplying a checksum.
|
||||||
|
*/
|
||||||
|
m->m_data += hlen;
|
||||||
|
m->m_len -= hlen;
|
||||||
|
icp = mtod(m, struct icmp *);
|
||||||
|
|
||||||
|
icp->icmp_cksum = 0;
|
||||||
|
icp->icmp_cksum = cksum(m, ip->ip_len - hlen);
|
||||||
|
|
||||||
|
m->m_data -= hlen;
|
||||||
|
m->m_len += hlen;
|
||||||
|
|
||||||
|
/* fill in ip */
|
||||||
|
if (optlen > 0) {
|
||||||
|
/*
|
||||||
|
* Strip out original options by copying rest of first
|
||||||
|
* mbuf's data back, and adjust the IP length.
|
||||||
|
*/
|
||||||
|
memmove((caddr_t)(ip + 1), (caddr_t)ip + hlen,
|
||||||
|
(unsigned )(m->m_len - hlen));
|
||||||
|
hlen -= optlen;
|
||||||
|
ip->ip_hl = hlen >> 2;
|
||||||
|
ip->ip_len -= optlen;
|
||||||
|
m->m_len -= optlen;
|
||||||
|
}
|
||||||
|
|
||||||
|
ip->ip_ttl = MAXTTL;
|
||||||
|
{ /* swap */
|
||||||
|
struct in_addr icmp_dst;
|
||||||
|
icmp_dst = ip->ip_dst;
|
||||||
|
ip->ip_dst = ip->ip_src;
|
||||||
|
ip->ip_src = icmp_dst;
|
||||||
|
}
|
||||||
|
|
||||||
|
(void ) ip_output((struct socket *)NULL, m);
|
||||||
|
|
||||||
|
icmpstat.icps_reflect++;
|
||||||
|
}
|
||||||
+164
@@ -0,0 +1,164 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 1982, 1986, 1993
|
||||||
|
* The Regents of the University of California. All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. All advertising materials mentioning features or use of this software
|
||||||
|
* must display the following acknowledgement:
|
||||||
|
* This product includes software developed by the University of
|
||||||
|
* California, Berkeley and its contributors.
|
||||||
|
* 4. Neither the name of the University nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* @(#)ip_icmp.h 8.1 (Berkeley) 6/10/93
|
||||||
|
* ip_icmp.h,v 1.4 1995/05/30 08:09:43 rgrimes Exp
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _NETINET_IP_ICMP_H_
|
||||||
|
#define _NETINET_IP_ICMP_H_
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Interface Control Message Protocol Definitions.
|
||||||
|
* Per RFC 792, September 1981.
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef u_int32_t n_time;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Structure of an icmp header.
|
||||||
|
*/
|
||||||
|
struct icmp {
|
||||||
|
u_char icmp_type; /* type of message, see below */
|
||||||
|
u_char icmp_code; /* type sub code */
|
||||||
|
u_short icmp_cksum; /* ones complement cksum of struct */
|
||||||
|
union {
|
||||||
|
u_char ih_pptr; /* ICMP_PARAMPROB */
|
||||||
|
struct in_addr ih_gwaddr; /* ICMP_REDIRECT */
|
||||||
|
struct ih_idseq {
|
||||||
|
u_short icd_id;
|
||||||
|
u_short icd_seq;
|
||||||
|
} ih_idseq;
|
||||||
|
int ih_void;
|
||||||
|
|
||||||
|
/* ICMP_UNREACH_NEEDFRAG -- Path MTU Discovery (RFC1191) */
|
||||||
|
struct ih_pmtu {
|
||||||
|
u_short ipm_void;
|
||||||
|
u_short ipm_nextmtu;
|
||||||
|
} ih_pmtu;
|
||||||
|
} icmp_hun;
|
||||||
|
#define icmp_pptr icmp_hun.ih_pptr
|
||||||
|
#define icmp_gwaddr icmp_hun.ih_gwaddr
|
||||||
|
#define icmp_id icmp_hun.ih_idseq.icd_id
|
||||||
|
#define icmp_seq icmp_hun.ih_idseq.icd_seq
|
||||||
|
#define icmp_void icmp_hun.ih_void
|
||||||
|
#define icmp_pmvoid icmp_hun.ih_pmtu.ipm_void
|
||||||
|
#define icmp_nextmtu icmp_hun.ih_pmtu.ipm_nextmtu
|
||||||
|
union {
|
||||||
|
struct id_ts {
|
||||||
|
n_time its_otime;
|
||||||
|
n_time its_rtime;
|
||||||
|
n_time its_ttime;
|
||||||
|
} id_ts;
|
||||||
|
struct id_ip {
|
||||||
|
struct ip idi_ip;
|
||||||
|
/* options and then 64 bits of data */
|
||||||
|
} id_ip;
|
||||||
|
u_long id_mask;
|
||||||
|
char id_data[1];
|
||||||
|
} icmp_dun;
|
||||||
|
#define icmp_otime icmp_dun.id_ts.its_otime
|
||||||
|
#define icmp_rtime icmp_dun.id_ts.its_rtime
|
||||||
|
#define icmp_ttime icmp_dun.id_ts.its_ttime
|
||||||
|
#define icmp_ip icmp_dun.id_ip.idi_ip
|
||||||
|
#define icmp_mask icmp_dun.id_mask
|
||||||
|
#define icmp_data icmp_dun.id_data
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Lower bounds on packet lengths for various types.
|
||||||
|
* For the error advice packets must first insure that the
|
||||||
|
* packet is large enought to contain the returned ip header.
|
||||||
|
* Only then can we do the check to see if 64 bits of packet
|
||||||
|
* data have been returned, since we need to check the returned
|
||||||
|
* ip header length.
|
||||||
|
*/
|
||||||
|
#define ICMP_MINLEN 8 /* abs minimum */
|
||||||
|
#define ICMP_TSLEN (8 + 3 * sizeof (n_time)) /* timestamp */
|
||||||
|
#define ICMP_MASKLEN 12 /* address mask */
|
||||||
|
#define ICMP_ADVLENMIN (8 + sizeof (struct ip) + 8) /* min */
|
||||||
|
#define ICMP_ADVLEN(p) (8 + ((p)->icmp_ip.ip_hl << 2) + 8)
|
||||||
|
/* N.B.: must separately check that ip_hl >= 5 */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Definition of type and code field values.
|
||||||
|
*/
|
||||||
|
#define ICMP_ECHOREPLY 0 /* echo reply */
|
||||||
|
#define ICMP_UNREACH 3 /* dest unreachable, codes: */
|
||||||
|
#define ICMP_UNREACH_NET 0 /* bad net */
|
||||||
|
#define ICMP_UNREACH_HOST 1 /* bad host */
|
||||||
|
#define ICMP_UNREACH_PROTOCOL 2 /* bad protocol */
|
||||||
|
#define ICMP_UNREACH_PORT 3 /* bad port */
|
||||||
|
#define ICMP_UNREACH_NEEDFRAG 4 /* IP_DF caused drop */
|
||||||
|
#define ICMP_UNREACH_SRCFAIL 5 /* src route failed */
|
||||||
|
#define ICMP_UNREACH_NET_UNKNOWN 6 /* unknown net */
|
||||||
|
#define ICMP_UNREACH_HOST_UNKNOWN 7 /* unknown host */
|
||||||
|
#define ICMP_UNREACH_ISOLATED 8 /* src host isolated */
|
||||||
|
#define ICMP_UNREACH_NET_PROHIB 9 /* prohibited access */
|
||||||
|
#define ICMP_UNREACH_HOST_PROHIB 10 /* ditto */
|
||||||
|
#define ICMP_UNREACH_TOSNET 11 /* bad tos for net */
|
||||||
|
#define ICMP_UNREACH_TOSHOST 12 /* bad tos for host */
|
||||||
|
#define ICMP_SOURCEQUENCH 4 /* packet lost, slow down */
|
||||||
|
#define ICMP_REDIRECT 5 /* shorter route, codes: */
|
||||||
|
#define ICMP_REDIRECT_NET 0 /* for network */
|
||||||
|
#define ICMP_REDIRECT_HOST 1 /* for host */
|
||||||
|
#define ICMP_REDIRECT_TOSNET 2 /* for tos and net */
|
||||||
|
#define ICMP_REDIRECT_TOSHOST 3 /* for tos and host */
|
||||||
|
#define ICMP_ECHO 8 /* echo service */
|
||||||
|
#define ICMP_ROUTERADVERT 9 /* router advertisement */
|
||||||
|
#define ICMP_ROUTERSOLICIT 10 /* router solicitation */
|
||||||
|
#define ICMP_TIMXCEED 11 /* time exceeded, code: */
|
||||||
|
#define ICMP_TIMXCEED_INTRANS 0 /* ttl==0 in transit */
|
||||||
|
#define ICMP_TIMXCEED_REASS 1 /* ttl==0 in reass */
|
||||||
|
#define ICMP_PARAMPROB 12 /* ip header bad */
|
||||||
|
#define ICMP_PARAMPROB_OPTABSENT 1 /* req. opt. absent */
|
||||||
|
#define ICMP_TSTAMP 13 /* timestamp request */
|
||||||
|
#define ICMP_TSTAMPREPLY 14 /* timestamp reply */
|
||||||
|
#define ICMP_IREQ 15 /* information request */
|
||||||
|
#define ICMP_IREQREPLY 16 /* information reply */
|
||||||
|
#define ICMP_MASKREQ 17 /* address mask request */
|
||||||
|
#define ICMP_MASKREPLY 18 /* address mask reply */
|
||||||
|
|
||||||
|
#define ICMP_MAXTYPE 18
|
||||||
|
|
||||||
|
#define ICMP_INFOTYPE(type) \
|
||||||
|
((type) == ICMP_ECHOREPLY || (type) == ICMP_ECHO || \
|
||||||
|
(type) == ICMP_ROUTERADVERT || (type) == ICMP_ROUTERSOLICIT || \
|
||||||
|
(type) == ICMP_TSTAMP || (type) == ICMP_TSTAMPREPLY || \
|
||||||
|
(type) == ICMP_IREQ || (type) == ICMP_IREQREPLY || \
|
||||||
|
(type) == ICMP_MASKREQ || (type) == ICMP_MASKREPLY)
|
||||||
|
|
||||||
|
void icmp_input _P((struct mbuf *, int));
|
||||||
|
void icmp_error _P((struct mbuf *, u_char, u_char, int, char *));
|
||||||
|
void icmp_reflect _P((struct mbuf *));
|
||||||
|
|
||||||
|
#endif
|
||||||
Loaded 100 of 184 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user