Compare commits
| 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 | ||
|
|
285dc330bd | ||
|
|
baf8ebf01a | ||
|
|
9d16dd550e | ||
|
|
78d6da976c | ||
|
|
dd6ee15c37 | ||
|
|
0db634747e | ||
|
|
6e59c1db89 | ||
|
|
61382a500a | ||
|
|
3a51dee658 | ||
|
|
cc38b844d7 | ||
|
|
c6105c0a04 | ||
|
|
93a40ea926 | ||
|
|
db8d746688 | ||
|
|
997344f303 | ||
|
|
16e9b7de41 | ||
|
|
3486513433 | ||
|
|
0806e3f66f | ||
|
|
39b4da28b3 | ||
|
|
5a67135a0b | ||
|
|
42f1e0e49b | ||
|
|
27c3f2cb9b | ||
|
|
a07cf92aed | ||
|
|
01e3b763a6 | ||
|
|
0ae04d7367 | ||
|
|
ebc054881f | ||
|
|
a20dd508aa | ||
|
|
6180a1818a | ||
|
|
d3eead2eec | ||
|
|
853d6f7a83 | ||
|
|
93ac68bca5 | ||
|
|
1e43adfc89 | ||
|
|
7a3f194486 | ||
|
|
2c0262afa7 | ||
|
|
196ad10903 | ||
|
|
b7dda06abf | ||
|
|
fcf8fcc8e5 | ||
|
|
dbc5594cb6 | ||
|
|
4cbb86e1c4 | ||
|
|
f513a41a3d | ||
|
|
c106152d26 | ||
|
|
facc68be25 | ||
|
|
3ff0631ed9 | ||
|
|
b1ba65744e | ||
|
|
b67d59594e | ||
|
|
2e255c6b9f | ||
|
|
3f33731662 | ||
|
|
d05e66d217 | ||
|
|
2d80ae8987 | ||
|
|
17383a2a2a | ||
|
|
9257a9e49c | ||
|
|
70a194b930 | ||
|
|
2573109866 | ||
|
|
9dfa5b421d | ||
|
|
9da8ba18e6 | ||
|
|
76bc683820 | ||
|
|
3b22c4707d | ||
|
|
96e6e05372 | ||
|
|
e2222c3924 | ||
|
|
31e8f3c894 | ||
|
|
9368caf64d | ||
|
|
38e584a072 | ||
|
|
313aa56710 | ||
|
|
4cbf74b6b8 | ||
|
|
33417e7025 | ||
|
|
4021dab059 | ||
|
|
626df76abb | ||
|
|
abcd5da72e | ||
|
|
97a847bc03 | ||
|
|
ab93bbe2ae | ||
|
|
0f0b726444 | ||
|
|
b92e5a22ec | ||
|
|
17b0018b42 | ||
|
|
39cf780327 | ||
|
|
e89f66eca9 | ||
|
|
b6d78bfa0d | ||
|
|
c33a346edf | ||
|
|
61a2ad53cb | ||
|
|
2c1794c42e | ||
|
|
8a4c1cc411 | ||
|
|
330d0414a5 | ||
|
|
3802ce26a1 | ||
|
|
4abe615b84 | ||
|
|
a412ac572f | ||
|
|
b2b5fb228f | ||
|
|
8f186479e2 | ||
|
|
4c3a88a284 | ||
|
|
d6b4936796 |
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,142 @@
|
||||
version 0.6.0:
|
||||
|
||||
- minimalist FPU exception support (NetBSD FPU probe fix)
|
||||
- cr0.ET fix (Win95 boot)
|
||||
- *BSD port (Markus Niemisto)
|
||||
- I/O access fix (signaled by Mark Jonckheere)
|
||||
- IDE drives serial number fix (Mike Nordell)
|
||||
- int13 CDROM BIOS fix (aka Solaris x86 install CD fix)
|
||||
- int15, ah=86 BIOS fix (aka Solaris x86 hardware probe hang up fix)
|
||||
- BSR/BSF "undefined behaviour" fix
|
||||
- vmdk2raw: convert VMware disk images to raw images
|
||||
- PCI support
|
||||
- NE2K PCI support
|
||||
- dummy VGA PCI support
|
||||
- VGA font selection fix (Daniel Serpell)
|
||||
- PIC reset fix (Hidemi KAWAI)
|
||||
- PIC spurious irq support (aka Solaris install bug)
|
||||
- added '-localtime' option
|
||||
- Cirrus CL-GD54xx VGA support (initial patch by Makoto Suzuki (suzu))
|
||||
- APM and system shutdown support
|
||||
- Fixed system reset
|
||||
- Support for other PC BIOSes
|
||||
- Initial PowerMac hardware emulation
|
||||
- PowerMac/PREP OpenFirmware compatible BIOS (Jocelyn Mayer)
|
||||
- initial IDE BMDMA support (needed for Darwin x86)
|
||||
- Set the default memory size for PC emulation to 128 MB
|
||||
|
||||
version 0.5.5:
|
||||
|
||||
- SDL full screen support (initial patch by malc)
|
||||
- VGA support on PowerPC PREP
|
||||
- VBE fixes (Matthew Mastracci)
|
||||
- PIT fixes (aka Win98 hardware probe and "VGA slowness" bug)
|
||||
- IDE master only fixes (aka Win98 CD-ROM probe bug)
|
||||
- ARM load/store half word fix (Ulrich Hecht)
|
||||
- FDC fixes for Win98
|
||||
|
||||
version 0.5.4:
|
||||
|
||||
- qemu-fast fixes
|
||||
- BIOS area protection fix (aka EMM386.EXE fix) (Mike Nordell)
|
||||
- keyboard/mouse fix (Mike Nordell)
|
||||
- IDE fixes (Linux did not recognized slave drivers)
|
||||
- VM86 EIP masking fix (aka NT5 install fix) (Mike Nordell)
|
||||
- QEMU can now boot a PowerPC Linux kernel (Jocelyn Mayer)
|
||||
- User mode network stack
|
||||
- imul imm8 fix + 0x82 opcode support (Hidemi KAWAI)
|
||||
- precise self modifying code (aka BeOS install bug)
|
||||
|
||||
version 0.5.3:
|
||||
|
||||
- added Bochs VESA VBE support
|
||||
- VGA memory map mode 3 access fix (OS/2 install fix)
|
||||
- IDE fixes (Jens Axboe)
|
||||
- CPU interrupt fixes
|
||||
- fixed various TLB invalidation cases (NT install)
|
||||
- fixed cr0.WP semantics (XP install)
|
||||
- direct chaining support for SPARC and PowerPC (faster)
|
||||
- ARM NWFPE support (initial patch by Ulrich Hecht)
|
||||
- added specific x86 to x86 translator (close to native performance
|
||||
in qemu-i386 and qemu-fast)
|
||||
- shm syscalls support (Paul McKerras)
|
||||
- added accurate CR0.MP/ME/TS emulation
|
||||
- fixed DMA memory write access (Win95 boot floppy fix)
|
||||
- graphical x86 linux loader
|
||||
- command line monitor
|
||||
- generic removable device support
|
||||
- support of CD-ROM change
|
||||
- multiple network interface support
|
||||
- initial x86-64 host support (Gwenole Beauchesne)
|
||||
- lret to outer priviledge fix (OS/2 install fix)
|
||||
- task switch fixes (SkyOS boot)
|
||||
- VM save/restore commands
|
||||
- new timer API
|
||||
- more precise RTC emulation (periodic timers + time updates)
|
||||
- Win32 port (initial patch by Kazu)
|
||||
|
||||
version 0.5.2:
|
||||
|
||||
- improved soft MMU speed (assembly functions and specializing)
|
||||
- improved multitasking speed by avoiding flushing TBs when
|
||||
switching tasks
|
||||
- improved qemu-fast speed
|
||||
- improved self modifying code handling (big performance gain in
|
||||
softmmu mode).
|
||||
- fixed IO checking
|
||||
- fixed CD-ROM detection (win98 install CD)
|
||||
- fixed addseg real mode bug (GRUB boot fix)
|
||||
- added ROM memory support (win98 boot)
|
||||
- fixed 'call Ev' in case of paging exception
|
||||
- updated the script 'qemu-binfmt-conf.sh' to use QEMU automagically
|
||||
when launching executables for the supported target CPUs.
|
||||
- PowerPC system emulation update (Jocelyn Mayer)
|
||||
- PC floppy emulation and DMA fixes (Jocelyn Mayer)
|
||||
- polled mode for PIC (Jocelyn Mayer)
|
||||
- fixed PTE dirty bit handling
|
||||
- fixed xadd same reg bug
|
||||
- fixed cmpxchg exception safeness
|
||||
- access to virtual memory in gdb stub
|
||||
- task gate and NT flag fixes
|
||||
- eflags optimisation fix for string operations
|
||||
|
||||
version 0.5.1:
|
||||
|
||||
- float access fixes when using soft mmu
|
||||
- PC emulation support on PowerPC
|
||||
- A20 support
|
||||
- IDE CD-ROM emulation
|
||||
- ARM fixes (Ulrich Hecht)
|
||||
- SB16 emulation (malc)
|
||||
- IRET and INT fixes in VM86 mode with IOPL=3
|
||||
- Port I/Os use TSS io map
|
||||
- Full task switching/task gate support
|
||||
- added verr, verw, arpl, fcmovxx
|
||||
- PowerPC target support (Jocelyn Mayer)
|
||||
- Major SPARC target fixes (dynamically linked programs begin to work)
|
||||
|
||||
version 0.5.0:
|
||||
|
||||
- full hardware level VGA emulation
|
||||
- graphical display with SDL
|
||||
- added PS/2 mouse and keyboard emulation
|
||||
- popw (%esp) fix
|
||||
- mov to/from segment data width fix
|
||||
- added real mode support
|
||||
- added Bochs BIOS and LGPL'ed VGA BIOS loader in qemu
|
||||
- m68k host port (Richard Zidlicky)
|
||||
- partial soft MMU support for memory mapped I/Os
|
||||
- multi-target build
|
||||
- fixed: no error code in hardware interrupts
|
||||
- fixed: pop ss, mov ss, x and sti disable hardware irqs for the next insn
|
||||
- correct single stepping thru string operations
|
||||
- preliminary SPARC target support (Thomas M. Ogrisegg)
|
||||
- tun-fd option (Rusty Russell)
|
||||
- automatic IDE geometry detection
|
||||
- renamed 'vl' to qemu[-fast] and user qemu to qemu-{cpu}.
|
||||
- added man page
|
||||
- added full soft mmu mode to launch unpatched OSes.
|
||||
|
||||
version 0.4.3:
|
||||
|
||||
- x86 exception fix in case of nop instruction.
|
||||
|
||||
@@ -1,255 +1,113 @@
|
||||
include config.mak
|
||||
include config-host.mak
|
||||
|
||||
CFLAGS=-Wall -O2 -g
|
||||
ifdef CONFIG_DARWIN
|
||||
CFLAGS+= -mdynamic-no-pic
|
||||
endif
|
||||
ifdef CONFIG_WIN32
|
||||
CFLAGS+=-fpack-struct
|
||||
endif
|
||||
LDFLAGS=-g
|
||||
LIBS=
|
||||
DEFINES=-DHAVE_BYTESWAP_H
|
||||
HELPER_CFLAGS=$(CFLAGS)
|
||||
PROGS=qemu
|
||||
|
||||
DEFINES+=-D_GNU_SOURCE
|
||||
ifndef CONFIG_WIN32
|
||||
TOOLS=qemu-mkcow vmdk2raw
|
||||
endif
|
||||
ifdef CONFIG_STATIC
|
||||
LDFLAGS+=-static
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH),i386)
|
||||
CFLAGS+=-fomit-frame-pointer
|
||||
OP_CFLAGS=$(CFLAGS) -mpreferred-stack-boundary=2
|
||||
ifeq ($(HAVE_GCC3_OPTIONS),yes)
|
||||
OP_CFLAGS+= -falign-functions=0
|
||||
else
|
||||
OP_CFLAGS+= -malign-functions=0
|
||||
endif
|
||||
ifdef TARGET_GPROF
|
||||
LDFLAGS+=-Wl,-T,i386.ld
|
||||
else
|
||||
# WARNING: this LDFLAGS is _very_ tricky : qemu is an ELF shared object
|
||||
# that the kernel ELF loader considers as an executable. I think this
|
||||
# is the simplest way to make it self virtualizable!
|
||||
LDFLAGS+=-Wl,-shared
|
||||
endif
|
||||
ifeq ($(TARGET_ARCH), i386)
|
||||
PROGS+=vl vlmkcow
|
||||
endif
|
||||
endif
|
||||
all: dyngen$(EXESUF) $(TOOLS) qemu-doc.html qemu-tech.html qemu.1
|
||||
for d in $(TARGET_DIRS); do \
|
||||
$(MAKE) -C $$d $@ || exit 1 ; \
|
||||
done
|
||||
|
||||
ifeq ($(ARCH),ppc)
|
||||
OP_CFLAGS=$(CFLAGS)
|
||||
LDFLAGS+=-Wl,-T,ppc.ld
|
||||
endif
|
||||
qemu-mkcow: qemu-mkcow.c
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) $(DEFINES) -o $@ $^ $(LIBS)
|
||||
|
||||
ifeq ($(ARCH),s390)
|
||||
OP_CFLAGS=$(CFLAGS)
|
||||
LDFLAGS+=-Wl,-T,s390.ld
|
||||
endif
|
||||
vmdk2raw: vmdk2raw.c
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) $(DEFINES) -o $@ $^ $(LIBS)
|
||||
|
||||
ifeq ($(ARCH),sparc)
|
||||
CFLAGS+=-m32 -ffixed-g1 -ffixed-g2 -ffixed-g3 -ffixed-g6
|
||||
LDFLAGS+=-m32
|
||||
OP_CFLAGS=$(CFLAGS) -fno-delayed-branch -ffixed-i0
|
||||
HELPER_CFLAGS=$(CFLAGS) -ffixed-i0 -mflat
|
||||
# -static is used to avoid g1/g3 usage by the dynamic linker
|
||||
LDFLAGS+=-Wl,-T,sparc.ld -static
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH),sparc64)
|
||||
CFLAGS+=-m64 -ffixed-g1 -ffixed-g2 -ffixed-g3 -ffixed-g6
|
||||
LDFLAGS+=-m64
|
||||
OP_CFLAGS=$(CFLAGS) -fno-delayed-branch -ffixed-i0
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH),alpha)
|
||||
# -msmall-data is not used because we want two-instruction relocations
|
||||
# for the constant constructions
|
||||
OP_CFLAGS=-Wall -O2 -g
|
||||
# Ensure there's only a single GP
|
||||
CFLAGS += -msmall-data
|
||||
LDFLAGS+=-Wl,-T,alpha.ld
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH),ia64)
|
||||
OP_CFLAGS=$(CFLAGS)
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH),arm)
|
||||
OP_CFLAGS=$(CFLAGS) -mno-sched-prolog
|
||||
LDFLAGS+=-Wl,-T,arm.ld
|
||||
endif
|
||||
|
||||
ifeq ($(HAVE_GCC3_OPTIONS),yes)
|
||||
# very important to generate a return at the end of every operation
|
||||
OP_CFLAGS+=-fno-reorder-blocks -fno-optimize-sibling-calls
|
||||
endif
|
||||
|
||||
#########################################################
|
||||
|
||||
DEFINES+=-D_GNU_SOURCE
|
||||
LIBS+=-lm
|
||||
|
||||
# profiling code
|
||||
ifdef TARGET_GPROF
|
||||
LDFLAGS+=-p
|
||||
main.o: CFLAGS+=-p
|
||||
endif
|
||||
|
||||
OBJS= elfload.o main.o syscall.o mmap.o signal.o path.o
|
||||
ifeq ($(TARGET_ARCH), i386)
|
||||
OBJS+= vm86.o
|
||||
endif
|
||||
SRCS:= $(OBJS:.o=.c)
|
||||
OBJS+= libqemu.a
|
||||
|
||||
# cpu emulator library
|
||||
LIBOBJS=thunk.o exec.o translate.o cpu-exec.o gdbstub.o
|
||||
|
||||
ifeq ($(TARGET_ARCH), i386)
|
||||
LIBOBJS+=translate-i386.o op-i386.o helper-i386.o
|
||||
endif
|
||||
ifeq ($(TARGET_ARCH), arm)
|
||||
LIBOBJS+=translate-arm.o op-arm.o
|
||||
endif
|
||||
|
||||
# NOTE: the disassembler code is only needed for debugging
|
||||
LIBOBJS+=disas.o
|
||||
ifeq ($(findstring i386, $(TARGET_ARCH) $(ARCH)),i386)
|
||||
LIBOBJS+=i386-dis.o
|
||||
endif
|
||||
ifeq ($(findstring alpha, $(TARGET_ARCH) $(ARCH)),alpha)
|
||||
LIBOBJS+=alpha-dis.o
|
||||
endif
|
||||
ifeq ($(findstring ppc, $(TARGET_ARCH) $(ARCH)),ppc)
|
||||
LIBOBJS+=ppc-dis.o
|
||||
endif
|
||||
ifeq ($(findstring sparc, $(TARGET_ARCH) $(ARCH)),sparc)
|
||||
LIBOBJS+=sparc-dis.o
|
||||
endif
|
||||
ifeq ($(findstring arm, $(TARGET_ARCH) $(ARCH)),arm)
|
||||
LIBOBJS+=arm-dis.o
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH),ia64)
|
||||
OBJS += ia64-syscall.o
|
||||
endif
|
||||
|
||||
all: $(PROGS) qemu-doc.html
|
||||
|
||||
qemu: $(OBJS)
|
||||
$(CC) $(LDFLAGS) -o $@ $^ $(LIBS)
|
||||
ifeq ($(ARCH),alpha)
|
||||
# Mark as 32 bit binary, i. e. it will be mapped into the low 31 bit of
|
||||
# the address space (31 bit so sign extending doesn't matter)
|
||||
echo -ne '\001\000\000\000' | dd of=qemu bs=1 seek=48 count=4 conv=notrunc
|
||||
endif
|
||||
|
||||
# must use static linking to avoid leaving stuff in virtual address space
|
||||
vl: vl.o block.o libqemu.a
|
||||
$(CC) -static -Wl,-T,i386-vl.ld -o $@ $^ $(LIBS)
|
||||
|
||||
vlmkcow: vlmkcow.o
|
||||
$(CC) -o $@ $^ $(LIBS)
|
||||
|
||||
depend: $(SRCS)
|
||||
$(CC) -MM $(CFLAGS) $^ 1>.depend
|
||||
|
||||
# libqemu
|
||||
|
||||
libqemu.a: $(LIBOBJS)
|
||||
rm -f $@
|
||||
$(AR) rcs $@ $(LIBOBJS)
|
||||
|
||||
dyngen: dyngen.c
|
||||
$(HOST_CC) -O2 -Wall -g $< -o $@
|
||||
|
||||
translate-$(TARGET_ARCH).o: translate-$(TARGET_ARCH).c gen-op-$(TARGET_ARCH).h opc-$(TARGET_ARCH).h cpu-$(TARGET_ARCH).h
|
||||
|
||||
translate.o: translate.c op-$(TARGET_ARCH).h opc-$(TARGET_ARCH).h cpu-$(TARGET_ARCH).h
|
||||
|
||||
op-$(TARGET_ARCH).h: op-$(TARGET_ARCH).o dyngen
|
||||
./dyngen -o $@ $<
|
||||
|
||||
opc-$(TARGET_ARCH).h: op-$(TARGET_ARCH).o dyngen
|
||||
./dyngen -c -o $@ $<
|
||||
|
||||
gen-op-$(TARGET_ARCH).h: op-$(TARGET_ARCH).o dyngen
|
||||
./dyngen -g -o $@ $<
|
||||
|
||||
op-$(TARGET_ARCH).o: op-$(TARGET_ARCH).c
|
||||
$(CC) $(OP_CFLAGS) $(DEFINES) -c -o $@ $<
|
||||
|
||||
helper-$(TARGET_ARCH).o: helper-$(TARGET_ARCH).c
|
||||
$(CC) $(HELPER_CFLAGS) $(DEFINES) -c -o $@ $<
|
||||
|
||||
op-i386.o: op-i386.c opreg_template.h ops_template.h ops_template_mem.h
|
||||
|
||||
op-arm.o: op-arm.c op-arm-template.h
|
||||
|
||||
%.o: %.c
|
||||
$(CC) $(CFLAGS) $(DEFINES) -c -o $@ $<
|
||||
dyngen$(EXESUF): dyngen.c
|
||||
$(HOST_CC) $(CFLAGS) $(DEFINES) -o $@ $^
|
||||
|
||||
clean:
|
||||
# avoid old build problems by removing potentially incorrect old files
|
||||
rm -f config.mak config.h op-i386.h opc-i386.h gen-op-i386.h op-arm.h opc-arm.h gen-op-arm.h
|
||||
rm -f *.o *.a $(TOOLS) dyngen$(EXESUF) TAGS qemu.pod
|
||||
$(MAKE) -C tests clean
|
||||
rm -f *.o *.a *~ qemu dyngen TAGS
|
||||
for d in $(TARGET_DIRS); do \
|
||||
$(MAKE) -C $$d $@ || exit 1 ; \
|
||||
done
|
||||
|
||||
distclean: clean
|
||||
rm -f config.mak config.h
|
||||
rm -f config-host.mak config-host.h
|
||||
for d in $(TARGET_DIRS); do \
|
||||
rm -rf $$d || exit 1 ; \
|
||||
done
|
||||
|
||||
install: $(PROGS)
|
||||
mkdir -p $(prefix)/bin
|
||||
install -m 755 -s $(PROGS) $(prefix)/bin
|
||||
install: all
|
||||
mkdir -p "$(bindir)"
|
||||
ifndef CONFIG_WIN32
|
||||
install -m 755 -s $(TOOLS) "$(bindir)"
|
||||
endif
|
||||
mkdir -p "$(datadir)"
|
||||
install -m 644 pc-bios/bios.bin pc-bios/vgabios.bin \
|
||||
pc-bios/vgabios-cirrus.bin \
|
||||
pc-bios/ppc_rom.bin \
|
||||
pc-bios/linux_boot.bin "$(datadir)"
|
||||
mkdir -p "$(docdir)"
|
||||
install -m 644 qemu-doc.html qemu-tech.html "$(docdir)"
|
||||
ifndef CONFIG_WIN32
|
||||
mkdir -p "$(mandir)/man1"
|
||||
install qemu.1 qemu-mkcow.1 "$(mandir)/man1"
|
||||
endif
|
||||
for d in $(TARGET_DIRS); do \
|
||||
$(MAKE) -C $$d $@ || exit 1 ; \
|
||||
done
|
||||
|
||||
# various test targets
|
||||
test speed: qemu
|
||||
make -C tests $@
|
||||
test speed test2: all
|
||||
$(MAKE) -C tests $@
|
||||
|
||||
TAGS:
|
||||
etags *.[ch] tests/*.[ch]
|
||||
|
||||
# documentation
|
||||
qemu-doc.html: qemu-doc.texi
|
||||
%.html: %.texi
|
||||
texi2html -monolithic -number $<
|
||||
|
||||
FILES= \
|
||||
README README.distrib COPYING COPYING.LIB TODO Changelog VERSION \
|
||||
configure \
|
||||
dyngen.c dyngen.h dyngen-exec.h ioctls.h syscall_types.h \
|
||||
Makefile elf.h elfload.c main.c signal.c qemu.h \
|
||||
syscall.c syscall_defs.h vm86.c path.c mmap.c \
|
||||
i386.ld ppc.ld alpha.ld s390.ld sparc.ld arm.ld\
|
||||
vl.c i386-vl.ld vl.h block.c vlmkcow.c\
|
||||
thunk.c cpu-exec.c translate.c cpu-all.h thunk.h exec.h\
|
||||
exec.c cpu-exec.c gdbstub.c\
|
||||
cpu-i386.h op-i386.c helper-i386.c syscall-i386.h translate-i386.c \
|
||||
exec-i386.h ops_template.h ops_template_mem.h op_string.h opreg_template.h \
|
||||
cpu-arm.h syscall-arm.h exec-arm.h op-arm.c translate-arm.c op-arm-template.h \
|
||||
dis-asm.h disas.c disas.h alpha-dis.c ppc-dis.c i386-dis.c sparc-dis.c \
|
||||
arm-dis.c \
|
||||
tests/Makefile \
|
||||
tests/test-i386.c tests/test-i386-shift.h tests/test-i386.h \
|
||||
tests/test-i386-muldiv.h tests/test-i386-code16.S tests/test-i386-vm86.S \
|
||||
tests/hello-i386.c tests/hello-i386 \
|
||||
tests/hello-arm.c tests/hello-arm \
|
||||
tests/sha1.c \
|
||||
tests/testsig.c tests/testclone.c tests/testthread.c \
|
||||
tests/runcom.c tests/pi_10.com \
|
||||
tests/test_path.c \
|
||||
qemu-doc.texi qemu-doc.html
|
||||
qemu.1: qemu-doc.texi
|
||||
./texi2pod.pl $< qemu.pod
|
||||
pod2man --section=1 --center=" " --release=" " qemu.pod > $@
|
||||
|
||||
FILE=qemu-$(VERSION)
|
||||
FILE=qemu-$(shell cat VERSION)
|
||||
|
||||
# tar release (use 'make -k tar' on a checkouted tree)
|
||||
tar:
|
||||
rm -rf /tmp/$(FILE)
|
||||
mkdir -p /tmp/$(FILE)
|
||||
cp -P $(FILES) /tmp/$(FILE)
|
||||
( cd /tmp ; tar zcvf ~/$(FILE).tar.gz $(FILE) )
|
||||
cp -r . /tmp/$(FILE)
|
||||
( cd /tmp ; tar zcvf ~/$(FILE).tar.gz $(FILE) --exclude CVS )
|
||||
rm -rf /tmp/$(FILE)
|
||||
|
||||
# generate a binary distribution including the test binary environnment
|
||||
BINPATH=/usr/local/qemu-i386
|
||||
|
||||
# generate a binary distribution
|
||||
tarbin:
|
||||
tar zcvf /tmp/qemu-$(VERSION)-i386-glibc21.tar.gz \
|
||||
$(BINPATH)/etc $(BINPATH)/lib $(BINPATH)/bin $(BINPATH)/usr
|
||||
tar zcvf /tmp/qemu-$(VERSION)-i386-wine.tar.gz \
|
||||
$(BINPATH)/wine
|
||||
( cd / ; tar zcvf ~/qemu-$(VERSION)-i386.tar.gz \
|
||||
$(bindir)/qemu $(bindir)/qemu-fast \
|
||||
$(bindir)/qemu-system-ppc \
|
||||
$(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),)
|
||||
include .depend
|
||||
|
||||
+348
@@ -0,0 +1,348 @@
|
||||
include config.mak
|
||||
|
||||
TARGET_PATH=$(SRC_PATH)/target-$(TARGET_ARCH)
|
||||
VPATH=$(SRC_PATH):$(TARGET_PATH):$(SRC_PATH)/hw
|
||||
DEFINES=-I. -I$(TARGET_PATH) -I$(SRC_PATH)
|
||||
ifdef CONFIG_USER_ONLY
|
||||
VPATH+=:$(SRC_PATH)/linux-user
|
||||
DEFINES+=-I$(SRC_PATH)/linux-user -I$(SRC_PATH)/linux-user/$(TARGET_ARCH)
|
||||
endif
|
||||
CFLAGS=-Wall -O2 -g -fno-strict-aliasing
|
||||
LDFLAGS=-g
|
||||
LIBS=
|
||||
HELPER_CFLAGS=$(CFLAGS)
|
||||
DYNGEN=../dyngen$(EXESUF)
|
||||
# user emulator name
|
||||
QEMU_USER=qemu-$(TARGET_ARCH)
|
||||
# system emulator name
|
||||
ifdef CONFIG_SOFTMMU
|
||||
ifeq ($(TARGET_ARCH), i386)
|
||||
QEMU_SYSTEM=qemu$(EXESUF)
|
||||
else
|
||||
QEMU_SYSTEM=qemu-system-$(TARGET_ARCH)$(EXESUF)
|
||||
endif
|
||||
else
|
||||
QEMU_SYSTEM=qemu-fast
|
||||
endif
|
||||
|
||||
ifdef CONFIG_USER_ONLY
|
||||
PROGS=$(QEMU_USER)
|
||||
else
|
||||
ifeq ($(TARGET_ARCH), i386)
|
||||
|
||||
ifeq ($(ARCH), i386)
|
||||
PROGS+=$(QEMU_SYSTEM)
|
||||
ifndef CONFIG_SOFTMMU
|
||||
CONFIG_STATIC=y
|
||||
endif
|
||||
else
|
||||
# the system emulator using soft mmu is portable
|
||||
ifdef CONFIG_SOFTMMU
|
||||
PROGS+=$(QEMU_SYSTEM)
|
||||
endif
|
||||
endif # ARCH != i386
|
||||
|
||||
endif # TARGET_ARCH = i386
|
||||
|
||||
ifeq ($(TARGET_ARCH), ppc)
|
||||
|
||||
ifeq ($(ARCH), ppc)
|
||||
PROGS+=$(QEMU_SYSTEM)
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH), i386)
|
||||
ifdef CONFIG_SOFTMMU
|
||||
PROGS+=$(QEMU_SYSTEM)
|
||||
endif
|
||||
endif # ARCH = i386
|
||||
|
||||
ifeq ($(ARCH), amd64)
|
||||
ifdef CONFIG_SOFTMMU
|
||||
PROGS+=$(QEMU_SYSTEM)
|
||||
endif
|
||||
endif # ARCH = amd64
|
||||
|
||||
endif # TARGET_ARCH = ppc
|
||||
endif # !CONFIG_USER_ONLY
|
||||
|
||||
ifdef CONFIG_STATIC
|
||||
LDFLAGS+=-static
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH),i386)
|
||||
CFLAGS+=-fomit-frame-pointer
|
||||
OP_CFLAGS=$(CFLAGS) -mpreferred-stack-boundary=2
|
||||
ifeq ($(HAVE_GCC3_OPTIONS),yes)
|
||||
OP_CFLAGS+= -falign-functions=0
|
||||
else
|
||||
OP_CFLAGS+= -malign-functions=0
|
||||
endif
|
||||
|
||||
ifdef TARGET_GPROF
|
||||
USE_I386_LD=y
|
||||
endif
|
||||
ifdef CONFIG_STATIC
|
||||
USE_I386_LD=y
|
||||
endif
|
||||
ifdef USE_I386_LD
|
||||
LDFLAGS+=-Wl,-T,$(SRC_PATH)/i386.ld
|
||||
else
|
||||
# WARNING: this LDFLAGS is _very_ tricky : qemu is an ELF shared object
|
||||
# that the kernel ELF loader considers as an executable. I think this
|
||||
# is the simplest way to make it self virtualizable!
|
||||
LDFLAGS+=-Wl,-shared
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH),amd64)
|
||||
OP_CFLAGS=$(CFLAGS) -falign-functions=0
|
||||
LDFLAGS+=-Wl,-T,$(SRC_PATH)/amd64.ld
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH),ppc)
|
||||
CFLAGS+= -D__powerpc__
|
||||
OP_CFLAGS=$(CFLAGS)
|
||||
LDFLAGS+=-Wl,-T,$(SRC_PATH)/ppc.ld
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH),s390)
|
||||
OP_CFLAGS=$(CFLAGS)
|
||||
LDFLAGS+=-Wl,-T,$(SRC_PATH)/s390.ld
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH),sparc)
|
||||
CFLAGS+=-m32 -ffixed-g1 -ffixed-g2 -ffixed-g3 -ffixed-g6
|
||||
LDFLAGS+=-m32
|
||||
OP_CFLAGS=$(CFLAGS) -fno-delayed-branch -ffixed-i0
|
||||
HELPER_CFLAGS=$(CFLAGS) -ffixed-i0 -mflat
|
||||
# -static is used to avoid g1/g3 usage by the dynamic linker
|
||||
LDFLAGS+=-Wl,-T,$(SRC_PATH)/sparc.ld -static
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH),sparc64)
|
||||
CFLAGS+=-m64 -ffixed-g1 -ffixed-g2 -ffixed-g3 -ffixed-g6
|
||||
LDFLAGS+=-m64
|
||||
OP_CFLAGS=$(CFLAGS) -fno-delayed-branch -ffixed-i0
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH),alpha)
|
||||
# -msmall-data is not used because we want two-instruction relocations
|
||||
# for the constant constructions
|
||||
OP_CFLAGS=-Wall -O2 -g
|
||||
# Ensure there's only a single GP
|
||||
CFLAGS += -msmall-data
|
||||
LDFLAGS+=-Wl,-T,$(SRC_PATH)/alpha.ld
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH),ia64)
|
||||
OP_CFLAGS=$(CFLAGS)
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH),arm)
|
||||
OP_CFLAGS=$(CFLAGS) -mno-sched-prolog
|
||||
LDFLAGS+=-Wl,-T,$(SRC_PATH)/arm.ld
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH),m68k)
|
||||
OP_CFLAGS=$(CFLAGS) -fomit-frame-pointer
|
||||
LDFLAGS+=-Wl,-T,m68k.ld
|
||||
endif
|
||||
|
||||
ifeq ($(HAVE_GCC3_OPTIONS),yes)
|
||||
# very important to generate a return at the end of every operation
|
||||
OP_CFLAGS+=-fno-reorder-blocks -fno-optimize-sibling-calls
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_DARWIN),yes)
|
||||
OP_CFLAGS+= -mdynamic-no-pic
|
||||
endif
|
||||
|
||||
#########################################################
|
||||
|
||||
DEFINES+=-D_GNU_SOURCE
|
||||
LIBS+=-lm
|
||||
ifdef CONFIG_WIN32
|
||||
LIBS+=-lwinmm
|
||||
endif
|
||||
|
||||
# profiling code
|
||||
ifdef TARGET_GPROF
|
||||
LDFLAGS+=-p
|
||||
main.o: CFLAGS+=-p
|
||||
endif
|
||||
|
||||
OBJS= elfload.o main.o syscall.o mmap.o signal.o path.o osdep.o thunk.o
|
||||
ifeq ($(TARGET_ARCH), i386)
|
||||
OBJS+= vm86.o
|
||||
endif
|
||||
ifeq ($(TARGET_ARCH), arm)
|
||||
OBJS+=nwfpe/softfloat.o nwfpe/fpa11.o nwfpe/fpa11_cpdo.o \
|
||||
nwfpe/fpa11_cpdt.o nwfpe/fpa11_cprt.o nwfpe/fpopcode.o nwfpe/single_cpdo.o \
|
||||
nwfpe/double_cpdo.o nwfpe/extended_cpdo.o
|
||||
endif
|
||||
SRCS:= $(OBJS:.o=.c)
|
||||
OBJS+= libqemu.a
|
||||
|
||||
# cpu emulator library
|
||||
LIBOBJS=exec.o translate-all.o cpu-exec.o\
|
||||
translate.o op.o
|
||||
|
||||
ifeq ($(TARGET_ARCH), i386)
|
||||
LIBOBJS+=helper.o helper2.o
|
||||
ifeq ($(ARCH), i386)
|
||||
LIBOBJS+=translate-copy.o
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(TARGET_ARCH), ppc)
|
||||
LIBOBJS+= op_helper.o helper.o
|
||||
endif
|
||||
|
||||
# NOTE: the disassembler code is only needed for debugging
|
||||
LIBOBJS+=disas.o
|
||||
ifeq ($(findstring i386, $(TARGET_ARCH) $(ARCH)),i386)
|
||||
USE_I386_DIS=y
|
||||
endif
|
||||
ifeq ($(findstring amd64, $(TARGET_ARCH) $(ARCH)),amd64)
|
||||
USE_I386_DIS=y
|
||||
endif
|
||||
ifdef USE_I386_DIS
|
||||
LIBOBJS+=i386-dis.o
|
||||
endif
|
||||
ifeq ($(findstring alpha, $(TARGET_ARCH) $(ARCH)),alpha)
|
||||
LIBOBJS+=alpha-dis.o
|
||||
endif
|
||||
ifeq ($(findstring ppc, $(TARGET_ARCH) $(ARCH)),ppc)
|
||||
LIBOBJS+=ppc-dis.o
|
||||
endif
|
||||
ifeq ($(findstring sparc, $(TARGET_ARCH) $(ARCH)),sparc)
|
||||
LIBOBJS+=sparc-dis.o
|
||||
endif
|
||||
ifeq ($(findstring arm, $(TARGET_ARCH) $(ARCH)),arm)
|
||||
LIBOBJS+=arm-dis.o
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH),ia64)
|
||||
OBJS += ia64-syscall.o
|
||||
endif
|
||||
|
||||
all: $(PROGS)
|
||||
|
||||
$(QEMU_USER): $(OBJS)
|
||||
$(CC) $(LDFLAGS) -o $@ $^ $(LIBS)
|
||||
ifeq ($(ARCH),alpha)
|
||||
# Mark as 32 bit binary, i. e. it will be mapped into the low 31 bit of
|
||||
# the address space (31 bit so sign extending doesn't matter)
|
||||
echo -ne '\001\000\000\000' | dd of=qemu bs=1 seek=48 count=4 conv=notrunc
|
||||
endif
|
||||
|
||||
# must use static linking to avoid leaving stuff in virtual address space
|
||||
VL_OBJS=vl.o osdep.o block.o 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
|
||||
VL_OBJS+=sdl.o
|
||||
endif
|
||||
ifdef CONFIG_SLIRP
|
||||
DEFINES+=-I$(SRC_PATH)/slirp
|
||||
SLIRP_OBJS=cksum.o if.o ip_icmp.o ip_input.o ip_output.o \
|
||||
slirp.o mbuf.o misc.o sbuf.o socket.o tcp_input.o tcp_output.o \
|
||||
tcp_subr.o tcp_timer.o udp.o bootp.o debug.o
|
||||
VL_OBJS+=$(addprefix slirp/, $(SLIRP_OBJS))
|
||||
endif
|
||||
|
||||
VL_LDFLAGS=
|
||||
# specific flags are needed for non soft mmu emulator
|
||||
ifdef CONFIG_STATIC
|
||||
VL_LDFLAGS+=-static
|
||||
endif
|
||||
ifndef CONFIG_SOFTMMU
|
||||
VL_LDFLAGS+=-Wl,-T,$(SRC_PATH)/i386-vl.ld
|
||||
endif
|
||||
ifndef CONFIG_DARWIN
|
||||
ifndef CONFIG_WIN32
|
||||
VL_LIBS=-lutil
|
||||
endif
|
||||
endif
|
||||
|
||||
$(QEMU_SYSTEM): $(VL_OBJS) libqemu.a
|
||||
$(CC) $(VL_LDFLAGS) -o $@ $^ $(LIBS) $(SDL_LIBS) $(VL_LIBS)
|
||||
|
||||
sdl.o: sdl.c
|
||||
$(CC) $(CFLAGS) $(DEFINES) $(SDL_CFLAGS) -c -o $@ $<
|
||||
|
||||
depend: $(SRCS)
|
||||
$(CC) -MM $(CFLAGS) $(DEFINES) $^ 1>.depend
|
||||
|
||||
# libqemu
|
||||
|
||||
libqemu.a: $(LIBOBJS)
|
||||
rm -f $@
|
||||
$(AR) rcs $@ $(LIBOBJS)
|
||||
|
||||
translate.o: translate.c gen-op.h opc.h cpu.h
|
||||
|
||||
translate-all.o: translate-all.c op.h opc.h cpu.h
|
||||
|
||||
op.h: op.o $(DYNGEN)
|
||||
$(DYNGEN) -o $@ $<
|
||||
|
||||
opc.h: op.o $(DYNGEN)
|
||||
$(DYNGEN) -c -o $@ $<
|
||||
|
||||
gen-op.h: op.o $(DYNGEN)
|
||||
$(DYNGEN) -g -o $@ $<
|
||||
|
||||
op.o: op.c
|
||||
$(CC) $(OP_CFLAGS) $(DEFINES) -c -o $@ $<
|
||||
|
||||
helper.o: helper.c
|
||||
$(CC) $(HELPER_CFLAGS) $(DEFINES) -c -o $@ $<
|
||||
|
||||
ifeq ($(TARGET_ARCH), i386)
|
||||
op.o: op.c opreg_template.h ops_template.h ops_template_mem.h ops_mem.h
|
||||
endif
|
||||
|
||||
ifeq ($(TARGET_ARCH), arm)
|
||||
op.o: op.c op_template.h
|
||||
endif
|
||||
|
||||
ifeq ($(TARGET_ARCH), sparc)
|
||||
op.o: op.c op_template.h
|
||||
endif
|
||||
|
||||
ifeq ($(TARGET_ARCH), ppc)
|
||||
op.o: op.c op_template.h op_mem.h
|
||||
op_helper.o: op_helper_mem.h
|
||||
endif
|
||||
|
||||
%.o: %.c
|
||||
$(CC) $(CFLAGS) $(DEFINES) -c -o $@ $<
|
||||
|
||||
%.o: %.S
|
||||
$(CC) $(DEFINES) -c -o $@ $<
|
||||
|
||||
clean:
|
||||
rm -f *.o *.a *~ $(PROGS) gen-op.h opc.h op.h nwfpe/*.o slirp/*.o
|
||||
|
||||
install: all
|
||||
ifneq ($(PROGS),)
|
||||
install -m 755 -s $(PROGS) "$(bindir)"
|
||||
endif
|
||||
|
||||
ifneq ($(wildcard .depend),)
|
||||
include .depend
|
||||
endif
|
||||
@@ -6,35 +6,17 @@ INSTALLATION
|
||||
|
||||
Type
|
||||
|
||||
./configure --interp-prefix=/usr/local/qemu-i386
|
||||
./configure
|
||||
make
|
||||
|
||||
to build qemu and libqemu.a.
|
||||
to build qemu, qemu-CPU and libqemu.a (CPU is the name of the various
|
||||
supported target CPUs).
|
||||
|
||||
Type
|
||||
|
||||
make install
|
||||
|
||||
to install QEMU in /usr/local/bin
|
||||
|
||||
* On x86 you should be able to launch any program by using the
|
||||
libraries installed on your PC. For example:
|
||||
|
||||
./qemu -L / /bin/ls
|
||||
|
||||
* On non x86 CPUs, you need first to download at least an x86 glibc
|
||||
(qemu-XXX-i386-glibc21.tar.gz on the qemu web page). Ensure that
|
||||
LD_LIBRARY_PATH is not set:
|
||||
|
||||
unset LD_LIBRARY_PATH
|
||||
|
||||
Then you can launch the precompiled 'ls' x86 executable:
|
||||
|
||||
./qemu /usr/local/qemu-i386/bin/ls-i386
|
||||
|
||||
You can look at /usr/local/qemu-i386/bin/qemu-conf.sh so that QEMU is
|
||||
automatically launched by the Linux kernel when you try to launch x86
|
||||
executables.
|
||||
to install QEMU in /usr/local
|
||||
|
||||
Tested tool versions
|
||||
--------------------
|
||||
@@ -52,7 +34,8 @@ x86 2.95.2 2.13.2 2.1.3 2.4.18
|
||||
2.96 2.11.93.0.2 2.2.5 2.4.18 Red Hat 7.3
|
||||
3.2.2 2.13.90.0.18 2.3.2 2.4.20 Red Hat 9
|
||||
|
||||
PowerPC 2.95.4 2.12.90.0.1 2.2.5 2.4.20-pre2 Debian 3.0
|
||||
PowerPC 3.3 [4] 2.13.90.0.18 2.3.1 2.4.20briq
|
||||
3.2
|
||||
|
||||
Alpha 3.3 [1] 2.14.90.0.4 2.2.5 2.2.20 [2] Debian 3.0
|
||||
|
||||
@@ -66,6 +49,9 @@ ARM 2.95.4 2.12.90.0.1 2.2.5 2.4.9 [3] Debian 3.0
|
||||
(untested).
|
||||
[3] 2.4.9-ac10-rmk2-np1-cerf2
|
||||
|
||||
[4] gcc 2.95.x generates invalid code when using too many register
|
||||
variables. You must use gcc 3.x on PowerPC.
|
||||
|
||||
Documentation
|
||||
-------------
|
||||
|
||||
|
||||
+2
-2
@@ -6,11 +6,11 @@ x86 binary distribution:
|
||||
|
||||
* wine-20020411 tarball
|
||||
|
||||
./configure --prefix=/usr/local/qemu-i386/wine
|
||||
./configure --prefix=/usr/local/wine-i386
|
||||
|
||||
All exe and libs were stripped. Some compile time tools and the
|
||||
includes were deleted.
|
||||
|
||||
* ldconfig was launched to build the library links:
|
||||
|
||||
./qemu /usr/local/qemu-i386/bin/ldconfig-i386 -C /usr/local/qemu-i386/etc/ld.so.cache
|
||||
qemu-i386 /usr/gnemul/qemu-i386/bin/ldconfig-i386 -C /usr/gnemul/qemu-i386/etc/ld.so.cache
|
||||
@@ -1,17 +1,35 @@
|
||||
- optimize FPU operations (evaluate x87 stack pointer statically) and
|
||||
fix cr0.TS emulation
|
||||
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
|
||||
- fix CCOP optimisation
|
||||
- fix all remaining thread lock issues (must put TBs in a specific invalid
|
||||
state, find a solution for tb_flush()).
|
||||
- cpu loop optimisation (optimise ret case as the cpu state does not change)
|
||||
- fix arm fpu rounding (at least for float->integer conversions)
|
||||
- add IPC syscalls
|
||||
- SMP support
|
||||
|
||||
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
|
||||
- SMP support
|
||||
- finish segment ops (call far, ret far, load_seg suppressed)
|
||||
- optimize FPU operations (evaluate x87 stack pointer statically)
|
||||
- add IPC syscalls
|
||||
- use -msoft-float on ARM
|
||||
- use kernel traps for unaligned accesses on ARM ?
|
||||
- handle rare page fault cases (in particular if page fault in 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
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <getopt.h>
|
||||
#include <inttypes.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/mman.h>
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
#include <malloc.h>
|
||||
#include <termios.h>
|
||||
#include <sys/poll.h>
|
||||
#include <errno.h>
|
||||
#include <sys/wait.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include "vl.h"
|
||||
|
||||
#define NO_THUNK_TYPE_SIZE
|
||||
#include "thunk.h"
|
||||
#ifndef _WIN32
|
||||
#include <sys/mman.h>
|
||||
#endif
|
||||
|
||||
#include "cow.h"
|
||||
|
||||
struct BlockDriverState {
|
||||
int fd; /* if -1, only COW mappings */
|
||||
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_addr; /* mmap address of cow_bitmap */
|
||||
int cow_bitmap_size;
|
||||
int cow_fd;
|
||||
int64_t cow_sectors_offset;
|
||||
int boot_sector_enabled;
|
||||
uint8_t boot_sector_data[512];
|
||||
|
||||
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)
|
||||
{
|
||||
BlockDriverState *bs;
|
||||
int fd, cow_fd;
|
||||
int64_t size;
|
||||
char template[] = "/tmp/vl.XXXXXX";
|
||||
struct cow_header_v2 cow_header;
|
||||
struct stat st;
|
||||
static BlockDriverState *bdrv_first;
|
||||
|
||||
bs = malloc(sizeof(BlockDriverState));
|
||||
/* create a new block device (by default it is empty) */
|
||||
BlockDriverState *bdrv_new(const char *device_name)
|
||||
{
|
||||
BlockDriverState **pbs, *bs;
|
||||
|
||||
bs = qemu_mallocz(sizeof(BlockDriverState));
|
||||
if(!bs)
|
||||
return NULL;
|
||||
pstrcpy(bs->device_name, sizeof(bs->device_name), device_name);
|
||||
/* 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->fd = -1;
|
||||
bs->cow_fd = -1;
|
||||
bs->cow_bitmap = NULL;
|
||||
strcpy(bs->filename, filename);
|
||||
pstrcpy(bs->filename, sizeof(bs->filename), filename);
|
||||
|
||||
/* open standard HD image */
|
||||
#ifdef _WIN32
|
||||
fd = open(filename, O_RDWR | O_BINARY);
|
||||
#else
|
||||
fd = open(filename, O_RDWR | O_LARGEFILE);
|
||||
#endif
|
||||
if (fd < 0) {
|
||||
/* read only image on disk */
|
||||
#ifdef _WIN32
|
||||
fd = open(filename, O_RDONLY | O_BINARY);
|
||||
#else
|
||||
fd = open(filename, O_RDONLY | O_LARGEFILE);
|
||||
#endif
|
||||
if (fd < 0) {
|
||||
perror(filename);
|
||||
goto fail;
|
||||
@@ -95,8 +121,9 @@ BlockDriverState *bdrv_open(const char *filename, int snapshot)
|
||||
fprintf(stderr, "%s: could not read header\n", filename);
|
||||
goto fail;
|
||||
}
|
||||
if (cow_header.magic == htonl(COW_MAGIC) &&
|
||||
cow_header.version == htonl(COW_VERSION)) {
|
||||
#ifndef _WIN32
|
||||
if (be32_to_cpu(cow_header.magic) == COW_MAGIC &&
|
||||
be32_to_cpu(cow_header.version) == COW_VERSION) {
|
||||
/* cow image found */
|
||||
size = cow_header.size;
|
||||
#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);
|
||||
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);
|
||||
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_sectors_offset = (bs->cow_bitmap_size + 511) & ~511;
|
||||
snapshot = 0;
|
||||
} else {
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
/* standard raw image */
|
||||
size = lseek64(fd, 0, SEEK_END);
|
||||
bs->total_sectors = size / 512;
|
||||
bs->fd = fd;
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
if (snapshot) {
|
||||
/* create a temporary COW file */
|
||||
cow_fd = mkstemp(template);
|
||||
cow_fd = mkstemp64(template);
|
||||
if (cow_fd < 0)
|
||||
goto fail;
|
||||
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_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:
|
||||
bdrv_close(bs);
|
||||
return NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
void bdrv_close(BlockDriverState *bs)
|
||||
{
|
||||
/* we unmap the mapping so that it is written to the COW file */
|
||||
if (bs->cow_bitmap_addr)
|
||||
munmap(bs->cow_bitmap_addr, bs->cow_bitmap_size);
|
||||
if (bs->cow_fd >= 0)
|
||||
close(bs->cow_fd);
|
||||
if (bs->fd >= 0)
|
||||
close(bs->fd);
|
||||
free(bs);
|
||||
if (bs->inserted) {
|
||||
#ifndef _WIN32
|
||||
/* we unmap the mapping so that it is written to the COW file */
|
||||
if (bs->cow_bitmap_addr)
|
||||
munmap(bs->cow_bitmap_addr, bs->cow_bitmap_size);
|
||||
#endif
|
||||
if (bs->cow_fd >= 0)
|
||||
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)
|
||||
@@ -216,6 +267,9 @@ int bdrv_commit(BlockDriverState *bs)
|
||||
int64_t i;
|
||||
uint8_t *cow_bitmap;
|
||||
|
||||
if (!bs->inserted)
|
||||
return -1;
|
||||
|
||||
if (!bs->cow_bitmap) {
|
||||
fprintf(stderr, "Already committed to %s\n", bs->filename);
|
||||
return 0;
|
||||
@@ -258,10 +312,17 @@ int bdrv_read(BlockDriverState *bs, int64_t sector_num,
|
||||
int ret, n, fd;
|
||||
int64_t offset;
|
||||
|
||||
if (!bs->inserted)
|
||||
return -1;
|
||||
|
||||
while (nb_sectors > 0) {
|
||||
if (is_changed(bs->cow_bitmap, sector_num, nb_sectors, &n)) {
|
||||
fd = bs->cow_fd;
|
||||
offset = bs->cow_sectors_offset;
|
||||
} else if (sector_num == 0 && bs->boot_sector_enabled) {
|
||||
memcpy(buf, bs->boot_sector_data, 512);
|
||||
n = 1;
|
||||
goto next;
|
||||
} else {
|
||||
fd = bs->fd;
|
||||
offset = 0;
|
||||
@@ -278,6 +339,7 @@ int bdrv_read(BlockDriverState *bs, int64_t sector_num,
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
next:
|
||||
nb_sectors -= n;
|
||||
sector_num += n;
|
||||
buf += n * 512;
|
||||
@@ -291,7 +353,9 @@ int bdrv_write(BlockDriverState *bs, int64_t sector_num,
|
||||
{
|
||||
int ret, fd, i;
|
||||
int64_t offset, retl;
|
||||
|
||||
|
||||
if (!bs->inserted)
|
||||
return -1;
|
||||
if (bs->read_only)
|
||||
return -1;
|
||||
|
||||
@@ -324,3 +388,116 @@ void bdrv_get_geometry(BlockDriverState *bs, int64_t *nb_sectors_ptr)
|
||||
{
|
||||
*nb_sectors_ptr = bs->total_sectors;
|
||||
}
|
||||
|
||||
/* force a given boot sector. */
|
||||
void bdrv_set_boot_sector(BlockDriverState *bs, const uint8_t *data, int size)
|
||||
{
|
||||
bs->boot_sector_enabled = 1;
|
||||
if (size > 512)
|
||||
size = 512;
|
||||
memcpy(bs->boot_sector_data, data, size);
|
||||
memset(bs->boot_sector_data + size, 0, 512 - size);
|
||||
}
|
||||
|
||||
void bdrv_set_geometry_hint(BlockDriverState *bs,
|
||||
int cyls, int heads, int secs)
|
||||
{
|
||||
bs->cyls = cyls;
|
||||
bs->heads = heads;
|
||||
bs->secs = secs;
|
||||
}
|
||||
|
||||
void bdrv_set_type_hint(BlockDriverState *bs, int type)
|
||||
{
|
||||
bs->type = type;
|
||||
bs->removable = ((type == BDRV_TYPE_CDROM ||
|
||||
type == BDRV_TYPE_FLOPPY));
|
||||
}
|
||||
|
||||
void bdrv_get_geometry_hint(BlockDriverState *bs,
|
||||
int *pcyls, int *pheads, int *psecs)
|
||||
{
|
||||
*pcyls = bs->cyls;
|
||||
*pheads = bs->heads;
|
||||
*psecs = bs->secs;
|
||||
}
|
||||
|
||||
int bdrv_get_type_hint(BlockDriverState *bs)
|
||||
{
|
||||
return bs->type;
|
||||
}
|
||||
|
||||
int bdrv_is_removable(BlockDriverState *bs)
|
||||
{
|
||||
return bs->removable;
|
||||
}
|
||||
|
||||
int bdrv_is_read_only(BlockDriverState *bs)
|
||||
{
|
||||
return bs->read_only;
|
||||
}
|
||||
|
||||
int bdrv_is_inserted(BlockDriverState *bs)
|
||||
{
|
||||
return bs->inserted;
|
||||
}
|
||||
|
||||
int bdrv_is_locked(BlockDriverState *bs)
|
||||
{
|
||||
return bs->locked;
|
||||
}
|
||||
|
||||
void bdrv_set_locked(BlockDriverState *bs, int locked)
|
||||
{
|
||||
bs->locked = locked;
|
||||
}
|
||||
|
||||
void bdrv_set_change_cb(BlockDriverState *bs,
|
||||
void (*change_cb)(void *opaque), void *opaque)
|
||||
{
|
||||
bs->change_cb = change_cb;
|
||||
bs->change_opaque = opaque;
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
#ifndef BSWAP_H
|
||||
#define BSWAP_H
|
||||
|
||||
#include "config-host.h"
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
#ifdef HAVE_BYTESWAP_H
|
||||
#include <byteswap.h>
|
||||
#else
|
||||
|
||||
#define bswap_16(x) \
|
||||
({ \
|
||||
uint16_t __x = (x); \
|
||||
((uint16_t)( \
|
||||
(((uint16_t)(__x) & (uint16_t)0x00ffU) << 8) | \
|
||||
(((uint16_t)(__x) & (uint16_t)0xff00U) >> 8) )); \
|
||||
})
|
||||
|
||||
#define bswap_32(x) \
|
||||
({ \
|
||||
uint32_t __x = (x); \
|
||||
((uint32_t)( \
|
||||
(((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
|
||||
(((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \
|
||||
(((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \
|
||||
(((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) )); \
|
||||
})
|
||||
|
||||
#define bswap_64(x) \
|
||||
({ \
|
||||
uint64_t __x = (x); \
|
||||
((uint64_t)( \
|
||||
(uint64_t)(((uint64_t)(__x) & (uint64_t)0x00000000000000ffULL) << 56) | \
|
||||
(uint64_t)(((uint64_t)(__x) & (uint64_t)0x000000000000ff00ULL) << 40) | \
|
||||
(uint64_t)(((uint64_t)(__x) & (uint64_t)0x0000000000ff0000ULL) << 24) | \
|
||||
(uint64_t)(((uint64_t)(__x) & (uint64_t)0x00000000ff000000ULL) << 8) | \
|
||||
(uint64_t)(((uint64_t)(__x) & (uint64_t)0x000000ff00000000ULL) >> 8) | \
|
||||
(uint64_t)(((uint64_t)(__x) & (uint64_t)0x0000ff0000000000ULL) >> 24) | \
|
||||
(uint64_t)(((uint64_t)(__x) & (uint64_t)0x00ff000000000000ULL) >> 40) | \
|
||||
(uint64_t)(((uint64_t)(__x) & (uint64_t)0xff00000000000000ULL) >> 56) )); \
|
||||
})
|
||||
|
||||
#endif /* !HAVE_BYTESWAP_H */
|
||||
|
||||
static inline uint16_t bswap16(uint16_t x)
|
||||
{
|
||||
return bswap_16(x);
|
||||
}
|
||||
|
||||
static inline uint32_t bswap32(uint32_t x)
|
||||
{
|
||||
return bswap_32(x);
|
||||
}
|
||||
|
||||
static inline uint64_t bswap64(uint64_t x)
|
||||
{
|
||||
return bswap_64(x);
|
||||
}
|
||||
|
||||
static inline void bswap16s(uint16_t *s)
|
||||
{
|
||||
*s = bswap16(*s);
|
||||
}
|
||||
|
||||
static inline void bswap32s(uint32_t *s)
|
||||
{
|
||||
*s = bswap32(*s);
|
||||
}
|
||||
|
||||
static inline void bswap64s(uint64_t *s)
|
||||
{
|
||||
*s = bswap64(*s);
|
||||
}
|
||||
|
||||
#endif /* BSWAP_H */
|
||||
@@ -15,11 +15,10 @@ TMPC="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}.c"
|
||||
TMPO="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}.o"
|
||||
TMPE="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}"
|
||||
TMPS="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}.S"
|
||||
TMPH="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}.h"
|
||||
|
||||
# default parameters
|
||||
prefix="/usr/local"
|
||||
interp_prefix="/usr/gnemul/qemu-i386"
|
||||
prefix=""
|
||||
interp_prefix="/usr/gnemul/qemu-%M"
|
||||
static="no"
|
||||
cross_prefix=""
|
||||
cc="gcc"
|
||||
@@ -27,12 +26,11 @@ host_cc="gcc"
|
||||
ar="ar"
|
||||
make="make"
|
||||
strip="strip"
|
||||
target_cpu="x86"
|
||||
target_bigendian="default"
|
||||
cpu=`uname -m`
|
||||
target_list="i386-user i386 i386-softmmu arm-user sparc-user ppc-user ppc-softmmu"
|
||||
case "$cpu" in
|
||||
i386|i486|i586|i686|i86pc|BePC)
|
||||
cpu="x86"
|
||||
cpu="i386"
|
||||
;;
|
||||
armv4l)
|
||||
cpu="armv4l"
|
||||
@@ -58,19 +56,52 @@ case "$cpu" in
|
||||
ia64)
|
||||
cpu="ia64"
|
||||
;;
|
||||
m68k)
|
||||
cpu="m68k"
|
||||
;;
|
||||
x86_64|amd64)
|
||||
cpu="amd64"
|
||||
;;
|
||||
*)
|
||||
cpu="unknown"
|
||||
;;
|
||||
esac
|
||||
gprof="no"
|
||||
bigendian="no"
|
||||
mingw32="no"
|
||||
EXESUF=""
|
||||
gdbstub="yes"
|
||||
slirp="yes"
|
||||
|
||||
# OS specific
|
||||
targetos=`uname -s`
|
||||
case $targetos in
|
||||
MINGW32*)
|
||||
mingw32="yes"
|
||||
;;
|
||||
FreeBSD)
|
||||
bsd="yes"
|
||||
;;
|
||||
NetBSD)
|
||||
bsd="yes"
|
||||
;;
|
||||
OpenBSD)
|
||||
bsd="yes"
|
||||
;;
|
||||
Darwin)
|
||||
bsd="yes"
|
||||
darwin="yes"
|
||||
;;
|
||||
*) ;;
|
||||
esac
|
||||
|
||||
if [ "$bsd" = "yes" ] ; then
|
||||
if [ ! "$darwin" = "yes" ] ; then
|
||||
make="gmake"
|
||||
fi
|
||||
target_list="i386-softmmu ppc-softmmu"
|
||||
fi
|
||||
|
||||
# find source path
|
||||
# XXX: we assume an absolute path is given when launching configure,
|
||||
# except in './configure' case.
|
||||
@@ -104,16 +135,18 @@ for opt do
|
||||
;;
|
||||
--cpu=*) cpu=`echo $opt | cut -d '=' -f 2`
|
||||
;;
|
||||
--target-cpu=*) target_cpu=`echo $opt | cut -d '=' -f 2`
|
||||
;;
|
||||
--target-big-endian) target_bigendian="yes"
|
||||
;;
|
||||
--target-little-endian) target_bigendian="no"
|
||||
--target-list=*) target_list=${opt#--target-list=}
|
||||
;;
|
||||
--enable-gprof) gprof="yes"
|
||||
;;
|
||||
--static) static="yes"
|
||||
;;
|
||||
--disable-sdl) sdl="no"
|
||||
;;
|
||||
--enable-mingw32) mingw32="yes" ; cross_prefix="i386-mingw32-"
|
||||
;;
|
||||
--disable-slirp) slirp="no"
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
@@ -126,6 +159,13 @@ cc="${cross_prefix}${cc}"
|
||||
ar="${cross_prefix}${ar}"
|
||||
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
|
||||
|
||||
# ---
|
||||
@@ -147,7 +187,7 @@ fi
|
||||
else
|
||||
|
||||
# if cross compiling, cannot launch a program, so make a static guess
|
||||
if test "$cpu" = "powerpc" -o "$cpu" = "mips" -o "$cpu" = "s390" -o "$cpu" = "sparc" -o "$cpu" = "sparc64"; then
|
||||
if test "$cpu" = "powerpc" -o "$cpu" = "mips" -o "$cpu" = "s390" -o "$cpu" = "sparc" -o "$cpu" = "sparc64" -o "$cpu" = "m68k"; then
|
||||
bigendian="yes"
|
||||
fi
|
||||
|
||||
@@ -164,16 +204,57 @@ if $cc -fno-reorder-blocks -fno-optimize-sibling-calls -o $TMPO $TMPC 2> /dev/nu
|
||||
have_gcc3_options="yes"
|
||||
fi
|
||||
|
||||
if test "$target_bigendian" = "default" ; then
|
||||
if test "$target_cpu" = "x86" ; then
|
||||
target_bigendian="no"
|
||||
elif test "$target_cpu" = "arm" ; then
|
||||
target_bigendian="no"
|
||||
else
|
||||
target_bigendian="no"
|
||||
fi
|
||||
##########################################
|
||||
# SDL probe
|
||||
|
||||
sdl_too_old=no
|
||||
|
||||
if test -z "$sdl" ; then
|
||||
|
||||
sdl_config="sdl-config"
|
||||
sdl=no
|
||||
sdl_static=no
|
||||
|
||||
if test "$mingw32" = "yes" -a ! -z "$cross_prefix" ; then
|
||||
# win32 cross compilation case
|
||||
sdl_config="i386-mingw32msvc-sdl-config"
|
||||
sdl=yes
|
||||
else
|
||||
# normal SDL probe
|
||||
cat > $TMPC << EOF
|
||||
#include <SDL.h>
|
||||
#undef main /* We don't want SDL to override our main() */
|
||||
int main( void ) { return SDL_Init (SDL_INIT_VIDEO); }
|
||||
EOF
|
||||
|
||||
if $cc -o $TMPE `$sdl_config --cflags 2> /dev/null` $TMPC `$sdl_config --libs 2> /dev/null` 2> /dev/null ; then
|
||||
_sdlversion=`$sdl_config --version | sed 's/[^0-9]//g'`
|
||||
if test "$_sdlversion" -lt 121 ; then
|
||||
sdl_too_old=yes
|
||||
else
|
||||
sdl=yes
|
||||
fi
|
||||
|
||||
# static link with sdl ?
|
||||
if test "$sdl" = "yes" ; then
|
||||
aa="no"
|
||||
`$sdl_config --static-libs | grep \\\-laa > /dev/null` && aa="yes"
|
||||
sdl_static_libs=`$sdl_config --static-libs`
|
||||
if [ "$aa" = "yes" ] ; then
|
||||
sdl_static_libs="$sdl_static_libs `aalib-config --static-libs`"
|
||||
fi
|
||||
|
||||
if $cc -o $TMPE `$sdl_config --cflags 2> /dev/null` $TMPC $sdl_static_libs 2> /dev/null; then
|
||||
sdl_static=yes
|
||||
fi
|
||||
|
||||
fi # static link
|
||||
|
||||
fi # sdl compile test
|
||||
|
||||
fi # cross compilation
|
||||
fi # -z $sdl
|
||||
|
||||
if test x"$1" = x"-h" -o x"$1" = x"--help" ; then
|
||||
cat << EOF
|
||||
|
||||
@@ -184,8 +265,9 @@ EOF
|
||||
echo "Standard options:"
|
||||
echo " --help print this message"
|
||||
echo " --prefix=PREFIX install in PREFIX [$prefix]"
|
||||
echo " --interp-prefix=PREFIX where to find shared libraries, etc. [$interp_prefix]"
|
||||
echo " --target_cpu=CPU set target cpu (x86 or arm) [$target_cpu]"
|
||||
echo " --interp-prefix=PREFIX where to find shared libraries, etc."
|
||||
echo " use %M for cpu name [$interp_prefix]"
|
||||
echo " --target-list=LIST set target list [$target_list]"
|
||||
echo ""
|
||||
echo "Advanced options (experts only):"
|
||||
echo " --source-path=PATH path of source code [$source_path]"
|
||||
@@ -193,106 +275,266 @@ echo " --cross-prefix=PREFIX use PREFIX for compile tools [$cross_prefix]"
|
||||
echo " --cc=CC use C compiler CC [$cc]"
|
||||
echo " --make=MAKE use specified make [$make]"
|
||||
echo " --static enable static build [$static]"
|
||||
echo " --enable-mingw32 enable Win32 cross compilation with mingw32"
|
||||
echo ""
|
||||
echo "NOTE: The object files are build at the place where configure is launched"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if test "$mingw32" = "yes" ; then
|
||||
if test -z "$prefix" ; then
|
||||
prefix="/c/Program Files/Qemu"
|
||||
fi
|
||||
mandir="$prefix"
|
||||
datadir="$prefix"
|
||||
docdir="$prefix"
|
||||
bindir="$prefix"
|
||||
else
|
||||
if test -z "$prefix" ; then
|
||||
prefix="/usr/local"
|
||||
fi
|
||||
mandir="$prefix/share/man"
|
||||
datadir="$prefix/share/qemu"
|
||||
docdir="$prefix/share/doc/qemu"
|
||||
bindir="$prefix/bin"
|
||||
fi
|
||||
|
||||
echo "Install prefix $prefix"
|
||||
echo "Source path $source_path"
|
||||
echo "BIOS directory $datadir"
|
||||
echo "binary directory $bindir"
|
||||
if test "$mingw32" = "no" ; then
|
||||
echo "Manual directory $mandir"
|
||||
echo "ELF interp prefix $interp_prefix"
|
||||
fi
|
||||
echo "Source path $source_path"
|
||||
echo "C compiler $cc"
|
||||
echo "make $make"
|
||||
echo "host CPU $cpu"
|
||||
echo "host big endian $bigendian"
|
||||
echo "target CPU $target_cpu"
|
||||
echo "target big endian $target_bigendian"
|
||||
echo "target list $target_list"
|
||||
echo "gprof enabled $gprof"
|
||||
echo "static build $static"
|
||||
echo "SDL support $sdl"
|
||||
echo "SDL static link $sdl_static"
|
||||
echo "mingw32 support $mingw32"
|
||||
|
||||
echo "Creating config.mak and config.h"
|
||||
|
||||
echo "# Automatically generated by configure - do not modify" > config.mak
|
||||
echo "/* Automatically generated by configure - do not modify */" > $TMPH
|
||||
|
||||
echo "prefix=$prefix" >> config.mak
|
||||
echo "#define CONFIG_QEMU_PREFIX \"$interp_prefix\"" >> $TMPH
|
||||
echo "MAKE=$make" >> config.mak
|
||||
echo "CC=$cc" >> config.mak
|
||||
if test "$have_gcc3_options" = "yes" ; then
|
||||
echo "HAVE_GCC3_OPTIONS=yes" >> config.mak
|
||||
if test $sdl_too_old = "yes"; then
|
||||
echo "-> Your SDL version is too old - please upgrade to have FFplay/SDL support"
|
||||
fi
|
||||
echo "HOST_CC=$host_cc" >> config.mak
|
||||
echo "AR=$ar" >> config.mak
|
||||
echo "STRIP=$strip -s -R .comment -R .note" >> config.mak
|
||||
echo "CFLAGS=$CFLAGS" >> config.mak
|
||||
echo "LDFLAGS=$LDFLAGS" >> config.mak
|
||||
if test "$cpu" = "x86" ; then
|
||||
echo "ARCH=i386" >> config.mak
|
||||
echo "#define HOST_I386 1" >> $TMPH
|
||||
if test "$sdl_static" = "no"; then
|
||||
echo "WARNING: cannot compile statically with SDL - qemu-fast won't have a graphical output"
|
||||
fi
|
||||
|
||||
config_mak="config-host.mak"
|
||||
config_h="config-host.h"
|
||||
|
||||
#echo "Creating $config_mak and $config_h"
|
||||
|
||||
echo "# Automatically generated by configure - do not modify" > $config_mak
|
||||
echo "/* Automatically generated by configure - do not modify */" > $config_h
|
||||
|
||||
echo "prefix=$prefix" >> $config_mak
|
||||
echo "bindir=$bindir" >> $config_mak
|
||||
echo "mandir=$mandir" >> $config_mak
|
||||
echo "datadir=$datadir" >> $config_mak
|
||||
echo "docdir=$docdir" >> $config_mak
|
||||
echo "#define CONFIG_QEMU_SHAREDIR \"$datadir\"" >> $config_h
|
||||
echo "MAKE=$make" >> $config_mak
|
||||
echo "CC=$cc" >> $config_mak
|
||||
if test "$have_gcc3_options" = "yes" ; then
|
||||
echo "HAVE_GCC3_OPTIONS=yes" >> $config_mak
|
||||
fi
|
||||
echo "HOST_CC=$host_cc" >> $config_mak
|
||||
echo "AR=$ar" >> $config_mak
|
||||
echo "STRIP=$strip -s -R .comment -R .note" >> $config_mak
|
||||
echo "CFLAGS=$CFLAGS" >> $config_mak
|
||||
echo "LDFLAGS=$LDFLAGS" >> $config_mak
|
||||
echo "EXESUF=$EXESUF" >> $config_mak
|
||||
if test "$cpu" = "i386" ; then
|
||||
echo "ARCH=i386" >> $config_mak
|
||||
echo "#define HOST_I386 1" >> $config_h
|
||||
elif test "$cpu" = "amd64" ; then
|
||||
echo "ARCH=amd64" >> $config_mak
|
||||
echo "#define HOST_AMD64 1" >> $config_h
|
||||
elif test "$cpu" = "armv4l" ; then
|
||||
echo "ARCH=arm" >> config.mak
|
||||
echo "#define HOST_ARM 1" >> $TMPH
|
||||
echo "ARCH=arm" >> $config_mak
|
||||
echo "#define HOST_ARM 1" >> $config_h
|
||||
elif test "$cpu" = "powerpc" ; then
|
||||
echo "ARCH=ppc" >> config.mak
|
||||
echo "#define HOST_PPC 1" >> $TMPH
|
||||
echo "ARCH=ppc" >> $config_mak
|
||||
echo "#define HOST_PPC 1" >> $config_h
|
||||
elif test "$cpu" = "mips" ; then
|
||||
echo "ARCH=mips" >> config.mak
|
||||
echo "#define HOST_MIPS 1" >> $TMPH
|
||||
echo "ARCH=mips" >> $config_mak
|
||||
echo "#define HOST_MIPS 1" >> $config_h
|
||||
elif test "$cpu" = "s390" ; then
|
||||
echo "ARCH=s390" >> config.mak
|
||||
echo "#define HOST_S390 1" >> $TMPH
|
||||
echo "ARCH=s390" >> $config_mak
|
||||
echo "#define HOST_S390 1" >> $config_h
|
||||
elif test "$cpu" = "alpha" ; then
|
||||
echo "ARCH=alpha" >> config.mak
|
||||
echo "#define HOST_ALPHA 1" >> $TMPH
|
||||
echo "ARCH=alpha" >> $config_mak
|
||||
echo "#define HOST_ALPHA 1" >> $config_h
|
||||
elif test "$cpu" = "sparc" ; then
|
||||
echo "ARCH=sparc" >> config.mak
|
||||
echo "#define HOST_SPARC 1" >> $TMPH
|
||||
echo "ARCH=sparc" >> $config_mak
|
||||
echo "#define HOST_SPARC 1" >> $config_h
|
||||
elif test "$cpu" = "sparc64" ; then
|
||||
echo "ARCH=sparc64" >> config.mak
|
||||
echo "#define HOST_SPARC64 1" >> $TMPH
|
||||
echo "ARCH=sparc64" >> $config_mak
|
||||
echo "#define HOST_SPARC64 1" >> $config_h
|
||||
elif test "$cpu" = "ia64" ; then
|
||||
echo "ARCH=ia64" >> config.mak
|
||||
echo "#define HOST_IA64 1" >> $TMPH
|
||||
echo "ARCH=ia64" >> $config_mak
|
||||
echo "#define HOST_IA64 1" >> $config_h
|
||||
elif test "$cpu" = "m68k" ; then
|
||||
echo "ARCH=m68k" >> $config_mak
|
||||
echo "#define HOST_M68K 1" >> $config_h
|
||||
else
|
||||
echo "Unsupported CPU"
|
||||
exit 1
|
||||
fi
|
||||
if test "$bigendian" = "yes" ; then
|
||||
echo "WORDS_BIGENDIAN=yes" >> config.mak
|
||||
echo "#define WORDS_BIGENDIAN 1" >> $TMPH
|
||||
echo "WORDS_BIGENDIAN=yes" >> $config_mak
|
||||
echo "#define WORDS_BIGENDIAN 1" >> $config_h
|
||||
fi
|
||||
if test "$mingw32" = "yes" ; then
|
||||
echo "CONFIG_WIN32=yes" >> $config_mak
|
||||
echo "#define CONFIG_WIN32 1" >> $config_h
|
||||
elif test -f "/usr/include/byteswap.h" ; then
|
||||
echo "#define HAVE_BYTESWAP_H 1" >> $config_h
|
||||
fi
|
||||
if test "$darwin" = "yes" ; then
|
||||
echo "CONFIG_DARWIN=yes" >> $config_mak
|
||||
echo "#define CONFIG_DARWIN 1" >> $config_h
|
||||
fi
|
||||
if test "$gdbstub" = "yes" ; then
|
||||
echo "CONFIG_GDBSTUB=yes" >> $config_mak
|
||||
echo "#define CONFIG_GDBSTUB 1" >> $config_h
|
||||
fi
|
||||
if test "$gprof" = "yes" ; then
|
||||
echo "TARGET_GPROF=yes" >> $config_mak
|
||||
echo "#define HAVE_GPROF 1" >> $config_h
|
||||
fi
|
||||
if test "$static" = "yes" ; then
|
||||
echo "CONFIG_STATIC=yes" >> $config_mak
|
||||
echo "#define CONFIG_STATIC 1" >> $config_h
|
||||
fi
|
||||
if test "$slirp" = "yes" ; then
|
||||
echo "CONFIG_SLIRP=yes" >> $config_mak
|
||||
echo "#define CONFIG_SLIRP 1" >> $config_h
|
||||
fi
|
||||
echo -n "VERSION=" >>$config_mak
|
||||
head $source_path/VERSION >>$config_mak
|
||||
echo "" >>$config_mak
|
||||
echo -n "#define QEMU_VERSION \"" >> $config_h
|
||||
head $source_path/VERSION >> $config_h
|
||||
echo "\"" >> $config_h
|
||||
|
||||
echo "SRC_PATH=$source_path" >> $config_mak
|
||||
echo "TARGET_DIRS=$target_list" >> $config_mak
|
||||
|
||||
# XXX: suppress that
|
||||
if [ "$bsd" = "yes" ] ; then
|
||||
echo "#define O_LARGEFILE 0" >> $config_h
|
||||
echo "#define 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
|
||||
|
||||
if test "$target_cpu" = "x86" ; then
|
||||
echo "TARGET_ARCH=i386" >> config.mak
|
||||
echo "#define TARGET_ARCH \"i386\"" >> $TMPH
|
||||
echo "#define TARGET_I386 1" >> $TMPH
|
||||
for target in $target_list; do
|
||||
|
||||
target_dir="$target"
|
||||
config_mak=$target_dir/config.mak
|
||||
config_h=$target_dir/config.h
|
||||
target_cpu=`echo $target | cut -d '-' -f 1`
|
||||
target_bigendian="no"
|
||||
[ "$target_cpu" = "sparc" ] && target_bigendian=yes
|
||||
[ "$target_cpu" = "ppc" ] && target_bigendian=yes
|
||||
target_softmmu="no"
|
||||
if expr $target : '.*-softmmu' > /dev/null ; then
|
||||
target_softmmu="yes"
|
||||
fi
|
||||
target_user_only="no"
|
||||
if expr $target : '.*-user' > /dev/null ; then
|
||||
target_user_only="yes"
|
||||
fi
|
||||
|
||||
#echo "Creating $config_mak, $config_h and $target_dir/Makefile"
|
||||
|
||||
mkdir -p $target_dir
|
||||
if test "$target" = "arm-user" ; then
|
||||
mkdir -p $target_dir/nwfpe
|
||||
fi
|
||||
if test "$target_user_only" = "no" ; then
|
||||
mkdir -p $target_dir/slirp
|
||||
fi
|
||||
|
||||
ln -sf $source_path/Makefile.target $target_dir/Makefile
|
||||
|
||||
echo "# Automatically generated by configure - do not modify" > $config_mak
|
||||
echo "/* Automatically generated by configure - do not modify */" > $config_h
|
||||
|
||||
|
||||
echo "include ../config-host.mak" >> $config_mak
|
||||
echo "#include \"../config-host.h\"" >> $config_h
|
||||
|
||||
interp_prefix1=`echo "$interp_prefix" | sed "s/%M/$target_cpu/g"`
|
||||
echo "#define CONFIG_QEMU_PREFIX \"$interp_prefix1\"" >> $config_h
|
||||
|
||||
if test "$target_cpu" = "i386" ; then
|
||||
echo "TARGET_ARCH=i386" >> $config_mak
|
||||
echo "#define TARGET_ARCH \"i386\"" >> $config_h
|
||||
echo "#define TARGET_I386 1" >> $config_h
|
||||
elif test "$target_cpu" = "arm" ; then
|
||||
echo "TARGET_ARCH=arm" >> config.mak
|
||||
echo "#define TARGET_ARCH \"arm\"" >> $TMPH
|
||||
echo "#define TARGET_ARM 1" >> $TMPH
|
||||
echo "TARGET_ARCH=arm" >> $config_mak
|
||||
echo "#define TARGET_ARCH \"arm\"" >> $config_h
|
||||
echo "#define TARGET_ARM 1" >> $config_h
|
||||
elif test "$target_cpu" = "sparc" ; then
|
||||
echo "TARGET_ARCH=sparc" >> $config_mak
|
||||
echo "#define TARGET_ARCH \"sparc\"" >> $config_h
|
||||
echo "#define TARGET_SPARC 1" >> $config_h
|
||||
elif test "$target_cpu" = "ppc" ; then
|
||||
echo "TARGET_ARCH=ppc" >> $config_mak
|
||||
echo "#define TARGET_ARCH \"ppc\"" >> $config_h
|
||||
echo "#define TARGET_PPC 1" >> $config_h
|
||||
else
|
||||
echo "Unsupported target CPU"
|
||||
exit 1
|
||||
fi
|
||||
if test "$target_bigendian" = "yes" ; then
|
||||
echo "TARGET_WORDS_BIGENDIAN=yes" >> config.mak
|
||||
echo "#define TARGET_WORDS_BIGENDIAN 1" >> $TMPH
|
||||
echo "TARGET_WORDS_BIGENDIAN=yes" >> $config_mak
|
||||
echo "#define TARGET_WORDS_BIGENDIAN 1" >> $config_h
|
||||
fi
|
||||
if test "$target_softmmu" = "yes" ; then
|
||||
echo "CONFIG_SOFTMMU=yes" >> $config_mak
|
||||
echo "#define CONFIG_SOFTMMU 1" >> $config_h
|
||||
fi
|
||||
if test "$target_user_only" = "yes" ; then
|
||||
echo "CONFIG_USER_ONLY=yes" >> $config_mak
|
||||
echo "#define CONFIG_USER_ONLY 1" >> $config_h
|
||||
fi
|
||||
|
||||
if test "$gprof" = "yes" ; then
|
||||
echo "TARGET_GPROF=yes" >> config.mak
|
||||
echo "#define HAVE_GPROF 1" >> $TMPH
|
||||
# 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
|
||||
if test "$static" = "yes" ; then
|
||||
echo "CONFIG_STATIC=yes" >> config.mak
|
||||
fi
|
||||
echo -n "VERSION=" >>config.mak
|
||||
head $source_path/VERSION >>config.mak
|
||||
echo "" >>config.mak
|
||||
echo -n "#define QEMU_VERSION \"" >> $TMPH
|
||||
head $source_path/VERSION >> $TMPH
|
||||
echo "\"" >> $TMPH
|
||||
|
||||
done # for target in $targets
|
||||
|
||||
# build tree in object directory if source path is different from current one
|
||||
if test "$source_path_used" = "yes" ; then
|
||||
@@ -305,13 +547,5 @@ if test "$source_path_used" = "yes" ; then
|
||||
ln -sf $source_path/$f $f
|
||||
done
|
||||
fi
|
||||
echo "SRC_PATH=$source_path" >> config.mak
|
||||
|
||||
diff $TMPH config.h >/dev/null 2>&1
|
||||
if test $? -ne 0 ; then
|
||||
mv -f $TMPH config.h
|
||||
else
|
||||
echo "config.h is unchanged"
|
||||
fi
|
||||
|
||||
rm -f $TMPO $TMPC $TMPE $TMPS $TMPH
|
||||
rm -f $TMPO $TMPC $TMPE $TMPS
|
||||
@@ -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,18 +20,163 @@
|
||||
#ifndef CPU_ALL_H
|
||||
#define CPU_ALL_H
|
||||
|
||||
/* all CPU memory access use these macros */
|
||||
static inline int ldub(void *ptr)
|
||||
#if defined(__arm__) || defined(__sparc__)
|
||||
#define WORDS_ALIGNED
|
||||
#endif
|
||||
|
||||
/* some important defines:
|
||||
*
|
||||
* WORDS_ALIGNED : if defined, the host cpu can only make word aligned
|
||||
* memory accesses.
|
||||
*
|
||||
* WORDS_BIGENDIAN : if defined, the host cpu is big endian and
|
||||
* otherwise little endian.
|
||||
*
|
||||
* (TARGET_WORDS_ALIGNED : same for target cpu (not supported yet))
|
||||
*
|
||||
* TARGET_WORDS_BIGENDIAN : same for target cpu
|
||||
*/
|
||||
|
||||
#include "bswap.h"
|
||||
|
||||
#if defined(WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
|
||||
#define BSWAP_NEEDED
|
||||
#endif
|
||||
|
||||
#ifdef BSWAP_NEEDED
|
||||
|
||||
static inline uint16_t tswap16(uint16_t s)
|
||||
{
|
||||
return bswap16(s);
|
||||
}
|
||||
|
||||
static inline uint32_t tswap32(uint32_t s)
|
||||
{
|
||||
return bswap32(s);
|
||||
}
|
||||
|
||||
static inline uint64_t tswap64(uint64_t s)
|
||||
{
|
||||
return bswap64(s);
|
||||
}
|
||||
|
||||
static inline void tswap16s(uint16_t *s)
|
||||
{
|
||||
*s = bswap16(*s);
|
||||
}
|
||||
|
||||
static inline void tswap32s(uint32_t *s)
|
||||
{
|
||||
*s = bswap32(*s);
|
||||
}
|
||||
|
||||
static inline void tswap64s(uint64_t *s)
|
||||
{
|
||||
*s = bswap64(*s);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static inline uint16_t tswap16(uint16_t s)
|
||||
{
|
||||
return s;
|
||||
}
|
||||
|
||||
static inline uint32_t tswap32(uint32_t s)
|
||||
{
|
||||
return s;
|
||||
}
|
||||
|
||||
static inline uint64_t tswap64(uint64_t s)
|
||||
{
|
||||
return s;
|
||||
}
|
||||
|
||||
static inline void tswap16s(uint16_t *s)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void tswap32s(uint32_t *s)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void tswap64s(uint64_t *s)
|
||||
{
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if TARGET_LONG_SIZE == 4
|
||||
#define tswapl(s) tswap32(s)
|
||||
#define tswapls(s) tswap32s((uint32_t *)(s))
|
||||
#else
|
||||
#define tswapl(s) tswap64(s)
|
||||
#define tswapls(s) tswap64s((uint64_t *)(s))
|
||||
#endif
|
||||
|
||||
/* NOTE: arm is horrible as double 32 bit words are stored in big endian ! */
|
||||
typedef union {
|
||||
double d;
|
||||
#if !defined(WORDS_BIGENDIAN) && !defined(__arm__)
|
||||
struct {
|
||||
uint32_t lower;
|
||||
uint32_t upper;
|
||||
} l;
|
||||
#else
|
||||
struct {
|
||||
uint32_t upper;
|
||||
uint32_t lower;
|
||||
} l;
|
||||
#endif
|
||||
uint64_t ll;
|
||||
} CPU_DoubleU;
|
||||
|
||||
/* CPU memory access without any memory or io remapping */
|
||||
|
||||
/*
|
||||
* the generic syntax for the memory accesses is:
|
||||
*
|
||||
* load: ld{type}{sign}{size}{endian}_{access_type}(ptr)
|
||||
*
|
||||
* store: st{type}{size}{endian}_{access_type}(ptr, val)
|
||||
*
|
||||
* type is:
|
||||
* (empty): integer access
|
||||
* f : float access
|
||||
*
|
||||
* sign is:
|
||||
* (empty): for floats or 32 bit size
|
||||
* u : unsigned
|
||||
* s : signed
|
||||
*
|
||||
* size is:
|
||||
* b: 8 bits
|
||||
* w: 16 bits
|
||||
* l: 32 bits
|
||||
* q: 64 bits
|
||||
*
|
||||
* endian is:
|
||||
* (empty): target cpu endianness or 8 bit access
|
||||
* r : reversed target cpu endianness (not implemented yet)
|
||||
* be : big endian (not implemented yet)
|
||||
* le : little endian (not implemented yet)
|
||||
*
|
||||
* access_type is:
|
||||
* raw : host memory access
|
||||
* user : user mode access using soft MMU
|
||||
* kernel : kernel mode access using soft MMU
|
||||
*/
|
||||
static inline int ldub_raw(void *ptr)
|
||||
{
|
||||
return *(uint8_t *)ptr;
|
||||
}
|
||||
|
||||
static inline int ldsb(void *ptr)
|
||||
static inline int ldsb_raw(void *ptr)
|
||||
{
|
||||
return *(int8_t *)ptr;
|
||||
}
|
||||
|
||||
static inline void stb(void *ptr, int v)
|
||||
static inline void stb_raw(void *ptr, int v)
|
||||
{
|
||||
*(uint8_t *)ptr = v;
|
||||
}
|
||||
@@ -39,10 +184,10 @@ static inline void stb(void *ptr, int v)
|
||||
/* NOTE: on arm, putting 2 in /proc/sys/debug/alignment so that the
|
||||
kernel handles unaligned load/stores may give better results, but
|
||||
it is a system wide setting : bad */
|
||||
#if defined(WORDS_BIGENDIAN) || defined(__arm__)
|
||||
#if !defined(TARGET_WORDS_BIGENDIAN) && (defined(WORDS_BIGENDIAN) || defined(WORDS_ALIGNED))
|
||||
|
||||
/* conservative code for little endian unaligned accesses */
|
||||
static inline int lduw(void *ptr)
|
||||
static inline int lduw_raw(void *ptr)
|
||||
{
|
||||
#ifdef __powerpc__
|
||||
int val;
|
||||
@@ -54,7 +199,7 @@ static inline int lduw(void *ptr)
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline int ldsw(void *ptr)
|
||||
static inline int ldsw_raw(void *ptr)
|
||||
{
|
||||
#ifdef __powerpc__
|
||||
int val;
|
||||
@@ -66,7 +211,7 @@ static inline int ldsw(void *ptr)
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline int ldl(void *ptr)
|
||||
static inline int ldl_raw(void *ptr)
|
||||
{
|
||||
#ifdef __powerpc__
|
||||
int val;
|
||||
@@ -78,16 +223,16 @@ static inline int ldl(void *ptr)
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline uint64_t ldq(void *ptr)
|
||||
static inline uint64_t ldq_raw(void *ptr)
|
||||
{
|
||||
uint8_t *p = ptr;
|
||||
uint32_t v1, v2;
|
||||
v1 = ldl(p);
|
||||
v2 = ldl(p + 4);
|
||||
v1 = ldl_raw(p);
|
||||
v2 = ldl_raw(p + 4);
|
||||
return v1 | ((uint64_t)v2 << 32);
|
||||
}
|
||||
|
||||
static inline void stw(void *ptr, int v)
|
||||
static inline void stw_raw(void *ptr, int v)
|
||||
{
|
||||
#ifdef __powerpc__
|
||||
__asm__ __volatile__ ("sthbrx %1,0,%2" : "=m" (*(uint16_t *)ptr) : "r" (v), "r" (ptr));
|
||||
@@ -98,7 +243,7 @@ static inline void stw(void *ptr, int v)
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void stl(void *ptr, int v)
|
||||
static inline void stl_raw(void *ptr, int v)
|
||||
{
|
||||
#ifdef __powerpc__
|
||||
__asm__ __volatile__ ("stwbrx %1,0,%2" : "=m" (*(uint32_t *)ptr) : "r" (v), "r" (ptr));
|
||||
@@ -111,154 +256,294 @@ static inline void stl(void *ptr, int v)
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void stq(void *ptr, uint64_t v)
|
||||
static inline void stq_raw(void *ptr, uint64_t v)
|
||||
{
|
||||
uint8_t *p = ptr;
|
||||
stl(p, (uint32_t)v);
|
||||
stl(p + 4, v >> 32);
|
||||
stl_raw(p, (uint32_t)v);
|
||||
stl_raw(p + 4, v >> 32);
|
||||
}
|
||||
|
||||
/* float access */
|
||||
|
||||
static inline float ldfl(void *ptr)
|
||||
static inline float ldfl_raw(void *ptr)
|
||||
{
|
||||
union {
|
||||
float f;
|
||||
uint32_t i;
|
||||
} u;
|
||||
u.i = ldl(ptr);
|
||||
u.i = ldl_raw(ptr);
|
||||
return u.f;
|
||||
}
|
||||
|
||||
static inline void stfl(void *ptr, float v)
|
||||
static inline void stfl_raw(void *ptr, float v)
|
||||
{
|
||||
union {
|
||||
float f;
|
||||
uint32_t i;
|
||||
} u;
|
||||
u.f = v;
|
||||
stl(ptr, u.i);
|
||||
stl_raw(ptr, u.i);
|
||||
}
|
||||
|
||||
#if defined(__arm__) && !defined(WORDS_BIGENDIAN)
|
||||
|
||||
/* NOTE: arm is horrible as double 32 bit words are stored in big endian ! */
|
||||
static inline double ldfq(void *ptr)
|
||||
static inline double ldfq_raw(void *ptr)
|
||||
{
|
||||
union {
|
||||
double d;
|
||||
uint32_t tab[2];
|
||||
} u;
|
||||
u.tab[1] = ldl(ptr);
|
||||
u.tab[0] = ldl(ptr + 4);
|
||||
CPU_DoubleU u;
|
||||
u.l.lower = ldl_raw(ptr);
|
||||
u.l.upper = ldl_raw(ptr + 4);
|
||||
return u.d;
|
||||
}
|
||||
|
||||
static inline void stfq(void *ptr, double v)
|
||||
static inline void stfq_raw(void *ptr, double v)
|
||||
{
|
||||
union {
|
||||
double d;
|
||||
uint32_t tab[2];
|
||||
} u;
|
||||
CPU_DoubleU u;
|
||||
u.d = v;
|
||||
stl(ptr, u.tab[1]);
|
||||
stl(ptr + 4, u.tab[0]);
|
||||
stl_raw(ptr, u.l.lower);
|
||||
stl_raw(ptr + 4, u.l.upper);
|
||||
}
|
||||
|
||||
#elif defined(TARGET_WORDS_BIGENDIAN) && (!defined(WORDS_BIGENDIAN) || defined(WORDS_ALIGNED))
|
||||
|
||||
static inline int lduw_raw(void *ptr)
|
||||
{
|
||||
#if defined(__i386__)
|
||||
int val;
|
||||
asm volatile ("movzwl %1, %0\n"
|
||||
"xchgb %b0, %h0\n"
|
||||
: "=q" (val)
|
||||
: "m" (*(uint16_t *)ptr));
|
||||
return val;
|
||||
#else
|
||||
static inline double ldfq(void *ptr)
|
||||
{
|
||||
union {
|
||||
double d;
|
||||
uint64_t i;
|
||||
} u;
|
||||
u.i = ldq(ptr);
|
||||
return u.d;
|
||||
}
|
||||
|
||||
static inline void stfq(void *ptr, double v)
|
||||
{
|
||||
union {
|
||||
double d;
|
||||
uint64_t i;
|
||||
} u;
|
||||
u.d = v;
|
||||
stq(ptr, u.i);
|
||||
}
|
||||
uint8_t *b = (uint8_t *) ptr;
|
||||
return ((b[0] << 8) | b[1]);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline int ldsw_raw(void *ptr)
|
||||
{
|
||||
#if defined(__i386__)
|
||||
int val;
|
||||
asm volatile ("movzwl %1, %0\n"
|
||||
"xchgb %b0, %h0\n"
|
||||
: "=q" (val)
|
||||
: "m" (*(uint16_t *)ptr));
|
||||
return (int16_t)val;
|
||||
#else
|
||||
uint8_t *b = (uint8_t *) ptr;
|
||||
return (int16_t)((b[0] << 8) | b[1]);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline int ldl_raw(void *ptr)
|
||||
{
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
int val;
|
||||
asm volatile ("movl %1, %0\n"
|
||||
"bswap %0\n"
|
||||
: "=r" (val)
|
||||
: "m" (*(uint32_t *)ptr));
|
||||
return val;
|
||||
#else
|
||||
uint8_t *b = (uint8_t *) ptr;
|
||||
return (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | b[3];
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline uint64_t ldq_raw(void *ptr)
|
||||
{
|
||||
uint32_t a,b;
|
||||
a = ldl_raw(ptr);
|
||||
b = ldl_raw(ptr+4);
|
||||
return (((uint64_t)a<<32)|b);
|
||||
}
|
||||
|
||||
static inline void stw_raw(void *ptr, int v)
|
||||
{
|
||||
#if defined(__i386__)
|
||||
asm volatile ("xchgb %b0, %h0\n"
|
||||
"movw %w0, %1\n"
|
||||
: "=q" (v)
|
||||
: "m" (*(uint16_t *)ptr), "0" (v));
|
||||
#else
|
||||
uint8_t *d = (uint8_t *) ptr;
|
||||
d[0] = v >> 8;
|
||||
d[1] = v;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void stl_raw(void *ptr, int v)
|
||||
{
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
asm volatile ("bswap %0\n"
|
||||
"movl %0, %1\n"
|
||||
: "=r" (v)
|
||||
: "m" (*(uint32_t *)ptr), "0" (v));
|
||||
#else
|
||||
uint8_t *d = (uint8_t *) ptr;
|
||||
d[0] = v >> 24;
|
||||
d[1] = v >> 16;
|
||||
d[2] = v >> 8;
|
||||
d[3] = v;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void stq_raw(void *ptr, uint64_t v)
|
||||
{
|
||||
stl_raw(ptr, v >> 32);
|
||||
stl_raw(ptr + 4, v);
|
||||
}
|
||||
|
||||
/* float access */
|
||||
|
||||
static inline float ldfl_raw(void *ptr)
|
||||
{
|
||||
union {
|
||||
float f;
|
||||
uint32_t i;
|
||||
} u;
|
||||
u.i = ldl_raw(ptr);
|
||||
return u.f;
|
||||
}
|
||||
|
||||
static inline void stfl_raw(void *ptr, float v)
|
||||
{
|
||||
union {
|
||||
float f;
|
||||
uint32_t i;
|
||||
} u;
|
||||
u.f = v;
|
||||
stl_raw(ptr, u.i);
|
||||
}
|
||||
|
||||
static inline double ldfq_raw(void *ptr)
|
||||
{
|
||||
CPU_DoubleU u;
|
||||
u.l.upper = ldl_raw(ptr);
|
||||
u.l.lower = ldl_raw(ptr + 4);
|
||||
return u.d;
|
||||
}
|
||||
|
||||
static inline void stfq_raw(void *ptr, double v)
|
||||
{
|
||||
CPU_DoubleU u;
|
||||
u.d = v;
|
||||
stl_raw(ptr, u.l.upper);
|
||||
stl_raw(ptr + 4, u.l.lower);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static inline int lduw(void *ptr)
|
||||
static inline int lduw_raw(void *ptr)
|
||||
{
|
||||
return *(uint16_t *)ptr;
|
||||
}
|
||||
|
||||
static inline int ldsw(void *ptr)
|
||||
static inline int ldsw_raw(void *ptr)
|
||||
{
|
||||
return *(int16_t *)ptr;
|
||||
}
|
||||
|
||||
static inline int ldl(void *ptr)
|
||||
static inline int ldl_raw(void *ptr)
|
||||
{
|
||||
return *(uint32_t *)ptr;
|
||||
}
|
||||
|
||||
static inline uint64_t ldq(void *ptr)
|
||||
static inline uint64_t ldq_raw(void *ptr)
|
||||
{
|
||||
return *(uint64_t *)ptr;
|
||||
}
|
||||
|
||||
static inline void stw(void *ptr, int v)
|
||||
static inline void stw_raw(void *ptr, int v)
|
||||
{
|
||||
*(uint16_t *)ptr = v;
|
||||
}
|
||||
|
||||
static inline void stl(void *ptr, int v)
|
||||
static inline void stl_raw(void *ptr, int v)
|
||||
{
|
||||
*(uint32_t *)ptr = v;
|
||||
}
|
||||
|
||||
static inline void stq(void *ptr, uint64_t v)
|
||||
static inline void stq_raw(void *ptr, uint64_t v)
|
||||
{
|
||||
*(uint64_t *)ptr = v;
|
||||
}
|
||||
|
||||
/* float access */
|
||||
|
||||
static inline float ldfl(void *ptr)
|
||||
static inline float ldfl_raw(void *ptr)
|
||||
{
|
||||
return *(float *)ptr;
|
||||
}
|
||||
|
||||
static inline double ldfq(void *ptr)
|
||||
static inline double ldfq_raw(void *ptr)
|
||||
{
|
||||
return *(double *)ptr;
|
||||
}
|
||||
|
||||
static inline void stfl(void *ptr, float v)
|
||||
static inline void stfl_raw(void *ptr, float v)
|
||||
{
|
||||
*(float *)ptr = v;
|
||||
}
|
||||
|
||||
static inline void stfq(void *ptr, double v)
|
||||
static inline void stfq_raw(void *ptr, double v)
|
||||
{
|
||||
*(double *)ptr = v;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* MMU memory access macros */
|
||||
|
||||
#if defined(CONFIG_USER_ONLY)
|
||||
|
||||
/* if user mode, no other memory access functions */
|
||||
#define ldub(p) ldub_raw(p)
|
||||
#define ldsb(p) ldsb_raw(p)
|
||||
#define lduw(p) lduw_raw(p)
|
||||
#define ldsw(p) ldsw_raw(p)
|
||||
#define ldl(p) ldl_raw(p)
|
||||
#define ldq(p) ldq_raw(p)
|
||||
#define ldfl(p) ldfl_raw(p)
|
||||
#define ldfq(p) ldfq_raw(p)
|
||||
#define stb(p, v) stb_raw(p, v)
|
||||
#define stw(p, v) stw_raw(p, v)
|
||||
#define stl(p, v) stl_raw(p, v)
|
||||
#define stq(p, v) stq_raw(p, v)
|
||||
#define stfl(p, v) stfl_raw(p, v)
|
||||
#define stfq(p, v) stfq_raw(p, v)
|
||||
|
||||
#define ldub_code(p) ldub_raw(p)
|
||||
#define ldsb_code(p) ldsb_raw(p)
|
||||
#define lduw_code(p) lduw_raw(p)
|
||||
#define ldsw_code(p) ldsw_raw(p)
|
||||
#define ldl_code(p) ldl_raw(p)
|
||||
|
||||
#define ldub_kernel(p) ldub_raw(p)
|
||||
#define ldsb_kernel(p) ldsb_raw(p)
|
||||
#define lduw_kernel(p) lduw_raw(p)
|
||||
#define ldsw_kernel(p) ldsw_raw(p)
|
||||
#define ldl_kernel(p) ldl_raw(p)
|
||||
#define ldfl_kernel(p) ldfl_raw(p)
|
||||
#define ldfq_kernel(p) ldfq_raw(p)
|
||||
#define stb_kernel(p, v) stb_raw(p, v)
|
||||
#define stw_kernel(p, v) stw_raw(p, v)
|
||||
#define stl_kernel(p, v) stl_raw(p, v)
|
||||
#define stq_kernel(p, v) stq_raw(p, v)
|
||||
#define stfl_kernel(p, v) stfl_raw(p, v)
|
||||
#define stfq_kernel(p, vt) stfq_raw(p, v)
|
||||
|
||||
#endif /* defined(CONFIG_USER_ONLY) */
|
||||
|
||||
/* page related stuff */
|
||||
|
||||
#define TARGET_PAGE_SIZE (1 << TARGET_PAGE_BITS)
|
||||
#define TARGET_PAGE_MASK ~(TARGET_PAGE_SIZE - 1)
|
||||
#define TARGET_PAGE_ALIGN(addr) (((addr) + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK)
|
||||
|
||||
extern unsigned long real_host_page_size;
|
||||
extern unsigned long host_page_bits;
|
||||
extern unsigned long host_page_size;
|
||||
extern unsigned long host_page_mask;
|
||||
extern unsigned long qemu_real_host_page_size;
|
||||
extern unsigned long qemu_host_page_bits;
|
||||
extern unsigned long qemu_host_page_size;
|
||||
extern unsigned long qemu_host_page_mask;
|
||||
|
||||
#define HOST_PAGE_ALIGN(addr) (((addr) + host_page_size - 1) & host_page_mask)
|
||||
#define HOST_PAGE_ALIGN(addr) (((addr) + qemu_host_page_size - 1) & qemu_host_page_mask)
|
||||
|
||||
/* same as PROT_xxx */
|
||||
#define PAGE_READ 0x0001
|
||||
@@ -284,8 +569,8 @@ void page_unprotect_range(uint8_t *data, unsigned long data_size);
|
||||
#define cpu_init cpu_x86_init
|
||||
#define cpu_exec cpu_x86_exec
|
||||
#define cpu_gen_code cpu_x86_gen_code
|
||||
#define cpu_interrupt cpu_x86_interrupt
|
||||
#define cpu_signal_handler cpu_x86_signal_handler
|
||||
#define cpu_dump_state cpu_x86_dump_state
|
||||
|
||||
#elif defined(TARGET_ARM)
|
||||
|
||||
@@ -293,8 +578,26 @@ void page_unprotect_range(uint8_t *data, unsigned long data_size);
|
||||
#define cpu_init cpu_arm_init
|
||||
#define cpu_exec cpu_arm_exec
|
||||
#define cpu_gen_code cpu_arm_gen_code
|
||||
#define cpu_interrupt cpu_arm_interrupt
|
||||
#define cpu_signal_handler cpu_arm_signal_handler
|
||||
#define cpu_dump_state cpu_arm_dump_state
|
||||
|
||||
#elif defined(TARGET_SPARC)
|
||||
|
||||
#define CPUState CPUSPARCState
|
||||
#define cpu_init cpu_sparc_init
|
||||
#define cpu_exec cpu_sparc_exec
|
||||
#define cpu_gen_code cpu_sparc_gen_code
|
||||
#define cpu_signal_handler cpu_sparc_signal_handler
|
||||
#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
|
||||
|
||||
@@ -304,18 +607,119 @@ void page_unprotect_range(uint8_t *data, unsigned long data_size);
|
||||
|
||||
#endif /* SINGLE_CPU_DEFINES */
|
||||
|
||||
#define DEFAULT_GDBSTUB_PORT 1234
|
||||
|
||||
void cpu_abort(CPUState *env, const char *fmt, ...);
|
||||
extern CPUState *cpu_single_env;
|
||||
extern int code_copy_enabled;
|
||||
|
||||
#define CPU_INTERRUPT_EXIT 0x01 /* wants exit from main loop */
|
||||
#define CPU_INTERRUPT_HARD 0x02 /* hardware interrupt pending */
|
||||
#define CPU_INTERRUPT_EXIT 0x01 /* wants exit from main loop */
|
||||
#define CPU_INTERRUPT_HARD 0x02 /* hardware interrupt pending */
|
||||
#define CPU_INTERRUPT_EXITTB 0x04 /* exit the current TB (use for x86 a20 case) */
|
||||
#define CPU_INTERRUPT_TIMER 0x08 /* internal timer exception pending */
|
||||
void cpu_interrupt(CPUState *s, int mask);
|
||||
void cpu_reset_interrupt(CPUState *env, int mask);
|
||||
|
||||
/* gdb stub API */
|
||||
extern int gdbstub_fd;
|
||||
CPUState *cpu_gdbstub_get_env(void *opaque);
|
||||
int cpu_gdbstub(void *opaque, void (*main_loop)(void *opaque), int port);
|
||||
int cpu_breakpoint_insert(CPUState *env, target_ulong pc);
|
||||
int cpu_breakpoint_remove(CPUState *env, target_ulong pc);
|
||||
void cpu_single_step(CPUState *env, int enabled);
|
||||
void cpu_reset(CPUState *s);
|
||||
|
||||
/* Return the physical page corresponding to a virtual one. Use it
|
||||
only for debugging because no protection checks are done. Return -1
|
||||
if no page found. */
|
||||
target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr);
|
||||
|
||||
#define CPU_LOG_TB_OUT_ASM (1 << 0)
|
||||
#define CPU_LOG_TB_IN_ASM (1 << 1)
|
||||
#define CPU_LOG_TB_OP (1 << 2)
|
||||
#define CPU_LOG_TB_OP_OPT (1 << 3)
|
||||
#define CPU_LOG_INT (1 << 4)
|
||||
#define CPU_LOG_EXEC (1 << 5)
|
||||
#define CPU_LOG_PCALL (1 << 6)
|
||||
#define CPU_LOG_IOPORT (1 << 7)
|
||||
#define CPU_LOG_TB_CPU (1 << 8)
|
||||
|
||||
/* define log items */
|
||||
typedef struct CPULogItem {
|
||||
int mask;
|
||||
const char *name;
|
||||
const char *help;
|
||||
} CPULogItem;
|
||||
|
||||
extern CPULogItem cpu_log_items[];
|
||||
|
||||
void cpu_set_log(int log_flags);
|
||||
void cpu_set_log_filename(const char *filename);
|
||||
int cpu_str_to_log_mask(const char *str);
|
||||
|
||||
/* IO ports API */
|
||||
|
||||
/* NOTE: as these functions may be even used when there is an isa
|
||||
brige on non x86 targets, we always defined them */
|
||||
#ifndef NO_CPU_IO_DEFS
|
||||
void cpu_outb(CPUState *env, int addr, int val);
|
||||
void cpu_outw(CPUState *env, int addr, int val);
|
||||
void cpu_outl(CPUState *env, int addr, int val);
|
||||
int cpu_inb(CPUState *env, int addr);
|
||||
int cpu_inw(CPUState *env, int addr);
|
||||
int cpu_inl(CPUState *env, int addr);
|
||||
#endif
|
||||
|
||||
/* memory API */
|
||||
|
||||
extern int phys_ram_size;
|
||||
extern int phys_ram_fd;
|
||||
extern uint8_t *phys_ram_base;
|
||||
extern uint8_t *phys_ram_dirty;
|
||||
|
||||
/* physical memory access */
|
||||
#define IO_MEM_NB_ENTRIES 256
|
||||
#define TLB_INVALID_MASK (1 << 3)
|
||||
#define IO_MEM_SHIFT 4
|
||||
|
||||
#define IO_MEM_RAM (0 << IO_MEM_SHIFT) /* hardcoded offset */
|
||||
#define IO_MEM_ROM (1 << IO_MEM_SHIFT) /* hardcoded offset */
|
||||
#define IO_MEM_UNASSIGNED (2 << IO_MEM_SHIFT)
|
||||
#define IO_MEM_CODE (3 << IO_MEM_SHIFT) /* used internally, never use directly */
|
||||
#define IO_MEM_NOTDIRTY (4 << IO_MEM_SHIFT) /* used internally, never use directly */
|
||||
|
||||
typedef void CPUWriteMemoryFunc(void *opaque, target_phys_addr_t addr, uint32_t value);
|
||||
typedef uint32_t CPUReadMemoryFunc(void *opaque, target_phys_addr_t addr);
|
||||
|
||||
void cpu_register_physical_memory(target_phys_addr_t start_addr,
|
||||
unsigned long size,
|
||||
unsigned long phys_offset);
|
||||
int cpu_register_io_memory(int io_index,
|
||||
CPUReadMemoryFunc **mem_read,
|
||||
CPUWriteMemoryFunc **mem_write,
|
||||
void *opaque);
|
||||
|
||||
void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
|
||||
int len, int is_write);
|
||||
static inline void cpu_physical_memory_read(target_phys_addr_t addr,
|
||||
uint8_t *buf, int len)
|
||||
{
|
||||
cpu_physical_memory_rw(addr, buf, len, 0);
|
||||
}
|
||||
static inline void cpu_physical_memory_write(target_phys_addr_t addr,
|
||||
const uint8_t *buf, int len)
|
||||
{
|
||||
cpu_physical_memory_rw(addr, (uint8_t *)buf, len, 1);
|
||||
}
|
||||
|
||||
int cpu_memory_rw_debug(CPUState *env, target_ulong addr,
|
||||
uint8_t *buf, int len, int is_write);
|
||||
|
||||
/* read dirty bit (return 0 or 1) */
|
||||
static inline int cpu_physical_memory_is_dirty(target_ulong addr)
|
||||
{
|
||||
return phys_ram_dirty[addr >> TARGET_PAGE_BITS];
|
||||
}
|
||||
|
||||
static inline void cpu_physical_memory_set_dirty(target_ulong addr)
|
||||
{
|
||||
phys_ram_dirty[addr >> TARGET_PAGE_BITS] = 1;
|
||||
}
|
||||
|
||||
void cpu_physical_memory_reset_dirty(target_ulong start, target_ulong end);
|
||||
|
||||
#endif /* CPU_ALL_H */
|
||||
+95
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* common defines for all CPUs
|
||||
*
|
||||
* Copyright (c) 2003 Fabrice Bellard
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#ifndef CPU_DEFS_H
|
||||
#define CPU_DEFS_H
|
||||
|
||||
#include "config.h"
|
||||
#include <setjmp.h>
|
||||
#include <inttypes.h>
|
||||
#include "osdep.h"
|
||||
|
||||
#ifndef TARGET_LONG_BITS
|
||||
#error TARGET_LONG_BITS must be defined before including this header
|
||||
#endif
|
||||
|
||||
#if defined(__alpha__) || defined (__ia64__) || defined(__x86_64__)
|
||||
#define HOST_LONG_BITS 64
|
||||
#else
|
||||
#define HOST_LONG_BITS 32
|
||||
#endif
|
||||
|
||||
#ifndef TARGET_PHYS_ADDR_BITS
|
||||
#if TARGET_LONG_BITS >= HOST_LONG_BITS
|
||||
#define TARGET_PHYS_ADDR_BITS TARGET_LONG_BITS
|
||||
#else
|
||||
#define TARGET_PHYS_ADDR_BITS HOST_LONG_BITS
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define TARGET_LONG_SIZE (TARGET_LONG_BITS / 8)
|
||||
|
||||
/* target_ulong is the type of a virtual address */
|
||||
#if TARGET_LONG_SIZE == 4
|
||||
typedef int32_t target_long;
|
||||
typedef uint32_t target_ulong;
|
||||
#elif TARGET_LONG_SIZE == 8
|
||||
typedef int64_t target_long;
|
||||
typedef uint64_t target_ulong;
|
||||
#else
|
||||
#error TARGET_LONG_SIZE undefined
|
||||
#endif
|
||||
|
||||
/* target_phys_addr_t is the type of a physical address (its size can
|
||||
be different from 'target_ulong'). We have sizeof(target_phys_addr)
|
||||
= max(sizeof(unsigned long),
|
||||
sizeof(size_of_target_physical_address)) because we must pass a
|
||||
host pointer to memory operations in some cases */
|
||||
|
||||
#if TARGET_PHYS_ADDR_BITS == 32
|
||||
typedef uint32_t target_phys_addr_t;
|
||||
#elif TARGET_PHYS_ADDR_BITS == 64
|
||||
typedef uint64_t target_phys_addr_t;
|
||||
#else
|
||||
#error TARGET_PHYS_ADDR_BITS undefined
|
||||
#endif
|
||||
|
||||
#define HOST_LONG_SIZE (HOST_LONG_BITS / 8)
|
||||
|
||||
#define EXCP_INTERRUPT 256 /* async interruption */
|
||||
#define EXCP_HLT 257 /* hlt instruction reached */
|
||||
#define EXCP_DEBUG 258 /* cpu stopped after a breakpoint or singlestep */
|
||||
|
||||
#define MAX_BREAKPOINTS 32
|
||||
|
||||
#define CPU_TLB_SIZE 256
|
||||
|
||||
typedef struct CPUTLBEntry {
|
||||
/* bit 31 to TARGET_PAGE_BITS : virtual address
|
||||
bit TARGET_PAGE_BITS-1..IO_MEM_SHIFT : if non zero, memory io
|
||||
zone number
|
||||
bit 3 : indicates that the entry is invalid
|
||||
bit 2..0 : zero
|
||||
*/
|
||||
target_ulong address;
|
||||
/* addend to virtual address to get physical address */
|
||||
target_phys_addr_t addend;
|
||||
} CPUTLBEntry;
|
||||
|
||||
#endif
|
||||
+488
-98
@@ -18,19 +18,29 @@
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#include "config.h"
|
||||
#ifdef TARGET_I386
|
||||
#include "exec-i386.h"
|
||||
#endif
|
||||
#ifdef TARGET_ARM
|
||||
#include "exec-arm.h"
|
||||
#include "exec.h"
|
||||
#include "disas.h"
|
||||
|
||||
#if !defined(CONFIG_SOFTMMU)
|
||||
#undef EAX
|
||||
#undef ECX
|
||||
#undef EDX
|
||||
#undef EBX
|
||||
#undef ESP
|
||||
#undef EBP
|
||||
#undef ESI
|
||||
#undef EDI
|
||||
#undef EIP
|
||||
#include <signal.h>
|
||||
#include <sys/ucontext.h>
|
||||
#endif
|
||||
|
||||
#include "disas.h"
|
||||
int tb_invalidated_flag;
|
||||
|
||||
//#define DEBUG_EXEC
|
||||
//#define DEBUG_SIGNAL
|
||||
|
||||
#if defined(TARGET_ARM)
|
||||
#if defined(TARGET_ARM) || defined(TARGET_SPARC)
|
||||
/* XXX: unify with i386 target */
|
||||
void cpu_loop_exit(void)
|
||||
{
|
||||
@@ -38,6 +48,28 @@ void cpu_loop_exit(void)
|
||||
}
|
||||
#endif
|
||||
|
||||
/* exit the current TB from a signal handler. The host registers are
|
||||
restored in a state compatible with the CPU emulator
|
||||
*/
|
||||
void cpu_resume_from_signal(CPUState *env1, void *puc)
|
||||
{
|
||||
#if !defined(CONFIG_SOFTMMU)
|
||||
struct ucontext *uc = puc;
|
||||
#endif
|
||||
|
||||
env = env1;
|
||||
|
||||
/* XXX: restore cpu registers saved in host registers */
|
||||
|
||||
#if !defined(CONFIG_SOFTMMU)
|
||||
if (puc) {
|
||||
/* XXX: use siglongjmp ? */
|
||||
sigprocmask(SIG_SETMASK, &uc->uc_sigmask, NULL);
|
||||
}
|
||||
#endif
|
||||
longjmp(env->jmp_env, 1);
|
||||
}
|
||||
|
||||
/* main execution loop */
|
||||
|
||||
int cpu_exec(CPUState *env1)
|
||||
@@ -136,6 +168,8 @@ int cpu_exec(CPUState *env1)
|
||||
env->VF = (psr << 3) & 0x80000000;
|
||||
env->cpsr = psr & ~0xf0000000;
|
||||
}
|
||||
#elif defined(TARGET_SPARC)
|
||||
#elif defined(TARGET_PPC)
|
||||
#else
|
||||
#error unsupported target CPU
|
||||
#endif
|
||||
@@ -144,6 +178,7 @@ int cpu_exec(CPUState *env1)
|
||||
/* prepare setjmp context for exception handling */
|
||||
for(;;) {
|
||||
if (setjmp(env->jmp_env) == 0) {
|
||||
env->current_tb = NULL;
|
||||
/* if an exception is pending, we execute it here */
|
||||
if (env->exception_index >= 0) {
|
||||
if (env->exception_index >= EXCP_INTERRUPT) {
|
||||
@@ -170,7 +205,9 @@ int cpu_exec(CPUState *env1)
|
||||
do_interrupt(env->exception_index,
|
||||
env->exception_is_int,
|
||||
env->error_code,
|
||||
env->exception_next_eip);
|
||||
env->exception_next_eip, 0);
|
||||
#elif defined(TARGET_PPC)
|
||||
do_interrupt(env);
|
||||
#endif
|
||||
}
|
||||
env->exception_index = -1;
|
||||
@@ -182,18 +219,19 @@ int cpu_exec(CPUState *env1)
|
||||
tmp_T0 = T0;
|
||||
#endif
|
||||
interrupt_request = env->interrupt_request;
|
||||
if (interrupt_request) {
|
||||
if (__builtin_expect(interrupt_request, 0)) {
|
||||
#if defined(TARGET_I386)
|
||||
/* if hardware interrupt pending, we execute it */
|
||||
if ((interrupt_request & CPU_INTERRUPT_HARD) &&
|
||||
(env->eflags & IF_MASK)) {
|
||||
(env->eflags & IF_MASK) &&
|
||||
!(env->hflags & HF_INHIBIT_IRQ_MASK)) {
|
||||
int intno;
|
||||
intno = cpu_x86_get_pic_interrupt(env);
|
||||
if (loglevel) {
|
||||
env->interrupt_request &= ~CPU_INTERRUPT_HARD;
|
||||
intno = cpu_get_pic_interrupt(env);
|
||||
if (loglevel & CPU_LOG_TB_IN_ASM) {
|
||||
fprintf(logfile, "Servicing hardware INT=0x%02x\n", intno);
|
||||
}
|
||||
do_interrupt(intno, 0, 0, 0);
|
||||
env->interrupt_request &= ~CPU_INTERRUPT_HARD;
|
||||
do_interrupt(intno, 0, 0, 0, 1);
|
||||
/* ensure that no TB jump will be modified as
|
||||
the program flow was changed */
|
||||
#ifdef __sparc__
|
||||
@@ -202,7 +240,38 @@ int cpu_exec(CPUState *env1)
|
||||
T0 = 0;
|
||||
#endif
|
||||
}
|
||||
#elif defined(TARGET_PPC)
|
||||
#if 0
|
||||
if ((interrupt_request & CPU_INTERRUPT_RESET)) {
|
||||
cpu_ppc_reset(env);
|
||||
}
|
||||
#endif
|
||||
if (msr_ee != 0) {
|
||||
if ((interrupt_request & CPU_INTERRUPT_HARD)) {
|
||||
/* Raise it */
|
||||
env->exception_index = EXCP_EXTERNAL;
|
||||
env->error_code = 0;
|
||||
do_interrupt(env);
|
||||
env->interrupt_request &= ~CPU_INTERRUPT_HARD;
|
||||
} else if ((interrupt_request & CPU_INTERRUPT_TIMER)) {
|
||||
/* Raise it */
|
||||
env->exception_index = EXCP_DECR;
|
||||
env->error_code = 0;
|
||||
do_interrupt(env);
|
||||
env->interrupt_request &= ~CPU_INTERRUPT_TIMER;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (interrupt_request & CPU_INTERRUPT_EXITTB) {
|
||||
env->interrupt_request &= ~CPU_INTERRUPT_EXITTB;
|
||||
/* ensure that no TB jump will be modified as
|
||||
the program flow was changed */
|
||||
#ifdef __sparc__
|
||||
tmp_T0 = 0;
|
||||
#else
|
||||
T0 = 0;
|
||||
#endif
|
||||
}
|
||||
if (interrupt_request & CPU_INTERRUPT_EXIT) {
|
||||
env->interrupt_request &= ~CPU_INTERRUPT_EXIT;
|
||||
env->exception_index = EXCP_INTERRUPT;
|
||||
@@ -210,7 +279,7 @@ int cpu_exec(CPUState *env1)
|
||||
}
|
||||
}
|
||||
#ifdef DEBUG_EXEC
|
||||
if (loglevel) {
|
||||
if (loglevel & CPU_LOG_EXEC) {
|
||||
#if defined(TARGET_I386)
|
||||
/* restore flags in standard format */
|
||||
env->regs[R_EAX] = EAX;
|
||||
@@ -228,48 +297,83 @@ int cpu_exec(CPUState *env1)
|
||||
env->cpsr = compute_cpsr();
|
||||
cpu_arm_dump_state(env, logfile, 0);
|
||||
env->cpsr &= ~0xf0000000;
|
||||
#elif defined(TARGET_SPARC)
|
||||
cpu_sparc_dump_state (env, logfile, 0);
|
||||
#elif defined(TARGET_PPC)
|
||||
cpu_ppc_dump_state(env, logfile, 0);
|
||||
#else
|
||||
#error unsupported target CPU
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
/* we compute the CPU state. We assume it will not
|
||||
change during the whole generated block. */
|
||||
/* we record a subset of the CPU state. It will
|
||||
always be the same before a given translated block
|
||||
is executed. */
|
||||
#if defined(TARGET_I386)
|
||||
flags = (env->segs[R_CS].flags & DESC_B_MASK)
|
||||
>> (DESC_B_SHIFT - GEN_FLAG_CODE32_SHIFT);
|
||||
flags |= (env->segs[R_SS].flags & DESC_B_MASK)
|
||||
>> (DESC_B_SHIFT - GEN_FLAG_SS32_SHIFT);
|
||||
flags |= (((unsigned long)env->segs[R_DS].base |
|
||||
(unsigned long)env->segs[R_ES].base |
|
||||
(unsigned long)env->segs[R_SS].base) != 0) <<
|
||||
GEN_FLAG_ADDSEG_SHIFT;
|
||||
if (!(env->eflags & VM_MASK)) {
|
||||
flags |= (env->segs[R_CS].selector & 3) << GEN_FLAG_CPL_SHIFT;
|
||||
} else {
|
||||
/* NOTE: a dummy CPL is kept */
|
||||
flags |= (1 << GEN_FLAG_VM_SHIFT);
|
||||
flags |= (3 << GEN_FLAG_CPL_SHIFT);
|
||||
}
|
||||
flags |= (env->eflags & (IOPL_MASK | TF_MASK));
|
||||
flags = env->hflags;
|
||||
flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK));
|
||||
cs_base = env->segs[R_CS].base;
|
||||
pc = cs_base + env->eip;
|
||||
#elif defined(TARGET_ARM)
|
||||
flags = 0;
|
||||
cs_base = 0;
|
||||
pc = (uint8_t *)env->regs[15];
|
||||
#elif defined(TARGET_SPARC)
|
||||
flags = 0;
|
||||
cs_base = (uint8_t *)env->npc;
|
||||
pc = (uint8_t *) env->pc;
|
||||
#elif defined(TARGET_PPC)
|
||||
flags = 0;
|
||||
cs_base = 0;
|
||||
pc = (uint8_t *)env->nip;
|
||||
#else
|
||||
#error unsupported CPU
|
||||
#endif
|
||||
tb = tb_find(&ptb, (unsigned long)pc, (unsigned long)cs_base,
|
||||
flags);
|
||||
if (!tb) {
|
||||
TranslationBlock **ptb1;
|
||||
unsigned int h;
|
||||
target_ulong phys_pc, phys_page1, phys_page2, virt_page2;
|
||||
|
||||
|
||||
spin_lock(&tb_lock);
|
||||
|
||||
tb_invalidated_flag = 0;
|
||||
|
||||
/* find translated block using physical mappings */
|
||||
phys_pc = get_phys_addr_code(env, (unsigned long)pc);
|
||||
phys_page1 = phys_pc & TARGET_PAGE_MASK;
|
||||
phys_page2 = -1;
|
||||
h = tb_phys_hash_func(phys_pc);
|
||||
ptb1 = &tb_phys_hash[h];
|
||||
for(;;) {
|
||||
tb = *ptb1;
|
||||
if (!tb)
|
||||
goto not_found;
|
||||
if (tb->pc == (unsigned long)pc &&
|
||||
tb->page_addr[0] == phys_page1 &&
|
||||
tb->cs_base == (unsigned long)cs_base &&
|
||||
tb->flags == flags) {
|
||||
/* check next page if needed */
|
||||
if (tb->page_addr[1] != -1) {
|
||||
virt_page2 = ((unsigned long)pc & TARGET_PAGE_MASK) +
|
||||
TARGET_PAGE_SIZE;
|
||||
phys_page2 = get_phys_addr_code(env, virt_page2);
|
||||
if (tb->page_addr[1] == phys_page2)
|
||||
goto found;
|
||||
} else {
|
||||
goto found;
|
||||
}
|
||||
}
|
||||
ptb1 = &tb->phys_hash_next;
|
||||
}
|
||||
not_found:
|
||||
/* if no translated code available, then translate it now */
|
||||
tb = tb_alloc((unsigned long)pc);
|
||||
if (!tb) {
|
||||
/* flush must be done */
|
||||
tb_flush();
|
||||
tb_flush(env);
|
||||
/* cannot fail at this point */
|
||||
tb = tb_alloc((unsigned long)pc);
|
||||
/* don't forget to invalidate previous TB info */
|
||||
@@ -280,25 +384,35 @@ int cpu_exec(CPUState *env1)
|
||||
tb->tc_ptr = tc_ptr;
|
||||
tb->cs_base = (unsigned long)cs_base;
|
||||
tb->flags = flags;
|
||||
ret = cpu_gen_code(tb, CODE_GEN_MAX_SIZE, &code_gen_size);
|
||||
#if defined(TARGET_I386)
|
||||
/* XXX: suppress that, this is incorrect */
|
||||
/* if invalid instruction, signal it */
|
||||
if (ret != 0) {
|
||||
/* NOTE: the tb is allocated but not linked, so we
|
||||
can leave it */
|
||||
spin_unlock(&tb_lock);
|
||||
raise_exception(EXCP06_ILLOP);
|
||||
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);
|
||||
}
|
||||
#endif
|
||||
tb_link_phys(tb, phys_pc, phys_page2);
|
||||
|
||||
found:
|
||||
if (tb_invalidated_flag) {
|
||||
/* as some TB could have been invalidated because
|
||||
of memory exceptions while generating the code, we
|
||||
must recompute the hash index here */
|
||||
ptb = &tb_hash[tb_hash_func((unsigned long)pc)];
|
||||
while (*ptb != NULL)
|
||||
ptb = &(*ptb)->hash_next;
|
||||
T0 = 0;
|
||||
}
|
||||
/* we add the TB in the virtual pc hash table */
|
||||
*ptb = tb;
|
||||
tb->hash_next = NULL;
|
||||
tb_link(tb);
|
||||
code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1));
|
||||
spin_unlock(&tb_lock);
|
||||
}
|
||||
#ifdef DEBUG_EXEC
|
||||
if (loglevel) {
|
||||
if (loglevel & CPU_LOG_EXEC) {
|
||||
fprintf(logfile, "Trace 0x%08lx [0x%08lx] %s\n",
|
||||
(long)tb->tc_ptr, (long)tb->pc,
|
||||
lookup_symbol((void *)tb->pc));
|
||||
@@ -307,14 +421,20 @@ int cpu_exec(CPUState *env1)
|
||||
#ifdef __sparc__
|
||||
T0 = tmp_T0;
|
||||
#endif
|
||||
/* see if we can patch the calling TB. XXX: remove TF test */
|
||||
/* see if we can patch the calling TB. */
|
||||
if (T0 != 0
|
||||
#if defined(TARGET_I386)
|
||||
&& !(env->eflags & TF_MASK)
|
||||
#if defined(TARGET_I386) && defined(USE_CODE_COPY)
|
||||
&& (tb->cflags & CF_CODE_COPY) ==
|
||||
(((TranslationBlock *)(T0 & ~3))->cflags & CF_CODE_COPY)
|
||||
#endif
|
||||
) {
|
||||
spin_lock(&tb_lock);
|
||||
tb_add_jump((TranslationBlock *)(T0 & ~3), T0 & 3, tb);
|
||||
#if defined(USE_CODE_COPY)
|
||||
/* propagates the FP use info */
|
||||
((TranslationBlock *)(T0 & ~3))->cflags |=
|
||||
(tb->cflags & CF_FP_USED);
|
||||
#endif
|
||||
spin_unlock(&tb_lock);
|
||||
}
|
||||
tc_ptr = tb->tc_ptr;
|
||||
@@ -334,10 +454,93 @@ int cpu_exec(CPUState *env1)
|
||||
: /* no outputs */
|
||||
: "r" (gen_func)
|
||||
: "r1", "r2", "r3", "r8", "r9", "r10", "r12", "r14");
|
||||
#elif defined(TARGET_I386) && defined(USE_CODE_COPY)
|
||||
{
|
||||
if (!(tb->cflags & CF_CODE_COPY)) {
|
||||
if ((tb->cflags & CF_FP_USED) && env->native_fp_regs) {
|
||||
save_native_fp_state(env);
|
||||
}
|
||||
gen_func();
|
||||
} else {
|
||||
if ((tb->cflags & CF_FP_USED) && !env->native_fp_regs) {
|
||||
restore_native_fp_state(env);
|
||||
}
|
||||
/* we work with native eflags */
|
||||
CC_SRC = cc_table[CC_OP].compute_all();
|
||||
CC_OP = CC_OP_EFLAGS;
|
||||
asm(".globl exec_loop\n"
|
||||
"\n"
|
||||
"debug1:\n"
|
||||
" pushl %%ebp\n"
|
||||
" fs movl %10, %9\n"
|
||||
" fs movl %11, %%eax\n"
|
||||
" andl $0x400, %%eax\n"
|
||||
" fs orl %8, %%eax\n"
|
||||
" pushl %%eax\n"
|
||||
" popf\n"
|
||||
" fs movl %%esp, %12\n"
|
||||
" fs movl %0, %%eax\n"
|
||||
" fs movl %1, %%ecx\n"
|
||||
" fs movl %2, %%edx\n"
|
||||
" fs movl %3, %%ebx\n"
|
||||
" fs movl %4, %%esp\n"
|
||||
" fs movl %5, %%ebp\n"
|
||||
" fs movl %6, %%esi\n"
|
||||
" fs movl %7, %%edi\n"
|
||||
" fs jmp *%9\n"
|
||||
"exec_loop:\n"
|
||||
" fs movl %%esp, %4\n"
|
||||
" fs movl %12, %%esp\n"
|
||||
" fs movl %%eax, %0\n"
|
||||
" fs movl %%ecx, %1\n"
|
||||
" fs movl %%edx, %2\n"
|
||||
" fs movl %%ebx, %3\n"
|
||||
" fs movl %%ebp, %5\n"
|
||||
" fs movl %%esi, %6\n"
|
||||
" fs movl %%edi, %7\n"
|
||||
" pushf\n"
|
||||
" popl %%eax\n"
|
||||
" movl %%eax, %%ecx\n"
|
||||
" andl $0x400, %%ecx\n"
|
||||
" shrl $9, %%ecx\n"
|
||||
" andl $0x8d5, %%eax\n"
|
||||
" fs movl %%eax, %8\n"
|
||||
" movl $1, %%eax\n"
|
||||
" subl %%ecx, %%eax\n"
|
||||
" fs movl %%eax, %11\n"
|
||||
" fs movl %9, %%ebx\n" /* get T0 value */
|
||||
" popl %%ebp\n"
|
||||
:
|
||||
: "m" (*(uint8_t *)offsetof(CPUState, regs[0])),
|
||||
"m" (*(uint8_t *)offsetof(CPUState, regs[1])),
|
||||
"m" (*(uint8_t *)offsetof(CPUState, regs[2])),
|
||||
"m" (*(uint8_t *)offsetof(CPUState, regs[3])),
|
||||
"m" (*(uint8_t *)offsetof(CPUState, regs[4])),
|
||||
"m" (*(uint8_t *)offsetof(CPUState, regs[5])),
|
||||
"m" (*(uint8_t *)offsetof(CPUState, regs[6])),
|
||||
"m" (*(uint8_t *)offsetof(CPUState, regs[7])),
|
||||
"m" (*(uint8_t *)offsetof(CPUState, cc_src)),
|
||||
"m" (*(uint8_t *)offsetof(CPUState, tmp0)),
|
||||
"a" (gen_func),
|
||||
"m" (*(uint8_t *)offsetof(CPUState, df)),
|
||||
"m" (*(uint8_t *)offsetof(CPUState, saved_esp))
|
||||
: "%ecx", "%edx"
|
||||
);
|
||||
}
|
||||
}
|
||||
#else
|
||||
gen_func();
|
||||
#endif
|
||||
env->current_tb = NULL;
|
||||
/* reset soft MMU for next block (it can currently
|
||||
only be set by a memory fault) */
|
||||
#if defined(TARGET_I386) && !defined(CONFIG_SOFTMMU)
|
||||
if (env->hflags & HF_SOFTMMU_MASK) {
|
||||
env->hflags &= ~HF_SOFTMMU_MASK;
|
||||
/* do not allow linking to another block */
|
||||
T0 = 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
} else {
|
||||
}
|
||||
@@ -345,6 +548,11 @@ int cpu_exec(CPUState *env1)
|
||||
|
||||
|
||||
#if defined(TARGET_I386)
|
||||
#if defined(USE_CODE_COPY)
|
||||
if (env->native_fp_regs) {
|
||||
save_native_fp_state(env);
|
||||
}
|
||||
#endif
|
||||
/* restore flags in standard format */
|
||||
env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
|
||||
|
||||
@@ -375,6 +583,8 @@ int cpu_exec(CPUState *env1)
|
||||
#endif
|
||||
#elif defined(TARGET_ARM)
|
||||
env->cpsr = compute_cpsr();
|
||||
#elif defined(TARGET_SPARC)
|
||||
#elif defined(TARGET_PPC)
|
||||
#else
|
||||
#error unsupported target CPU
|
||||
#endif
|
||||
@@ -388,7 +598,20 @@ int cpu_exec(CPUState *env1)
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if defined(TARGET_I386)
|
||||
/* must only be called from the generated code as an exception can be
|
||||
generated */
|
||||
void tb_invalidate_page_range(target_ulong start, target_ulong end)
|
||||
{
|
||||
/* XXX: cannot enable it yet because it yields to MMU exception
|
||||
where NIP != read address on PowerPC */
|
||||
#if 0
|
||||
target_ulong phys_addr;
|
||||
phys_addr = get_phys_addr_code(env, start);
|
||||
tb_invalidate_phys_page_range(phys_addr, phys_addr + end - start, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(TARGET_I386) && defined(CONFIG_USER_ONLY)
|
||||
|
||||
void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector)
|
||||
{
|
||||
@@ -396,18 +619,12 @@ void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector)
|
||||
|
||||
saved_env = env;
|
||||
env = s;
|
||||
if (env->eflags & VM_MASK) {
|
||||
SegmentCache *sc;
|
||||
if (!(env->cr[0] & CR0_PE_MASK) || (env->eflags & VM_MASK)) {
|
||||
selector &= 0xffff;
|
||||
sc = &env->segs[seg_reg];
|
||||
/* NOTE: in VM86 mode, limit and flags are never reloaded,
|
||||
so we must load them here */
|
||||
sc->base = (void *)(selector << 4);
|
||||
sc->limit = 0xffff;
|
||||
sc->flags = 0;
|
||||
sc->selector = selector;
|
||||
cpu_x86_load_seg_cache(env, seg_reg, selector,
|
||||
(uint8_t *)(selector << 4), 0xffff, 0);
|
||||
} else {
|
||||
load_seg(seg_reg, selector, 0);
|
||||
load_seg(seg_reg, selector);
|
||||
}
|
||||
env = saved_env;
|
||||
}
|
||||
@@ -438,17 +655,7 @@ void cpu_x86_frstor(CPUX86State *s, uint8_t *ptr, int data32)
|
||||
|
||||
#endif /* TARGET_I386 */
|
||||
|
||||
#undef EAX
|
||||
#undef ECX
|
||||
#undef EDX
|
||||
#undef EBX
|
||||
#undef ESP
|
||||
#undef EBP
|
||||
#undef ESI
|
||||
#undef EDI
|
||||
#undef EIP
|
||||
#include <signal.h>
|
||||
#include <sys/ucontext.h>
|
||||
#if !defined(CONFIG_SOFTMMU)
|
||||
|
||||
#if defined(TARGET_I386)
|
||||
|
||||
@@ -457,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
|
||||
signal set which should be restored */
|
||||
static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
|
||||
int is_write, sigset_t *old_set)
|
||||
int is_write, sigset_t *old_set,
|
||||
void *puc)
|
||||
{
|
||||
TranslationBlock *tb;
|
||||
int ret;
|
||||
@@ -465,15 +673,17 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
|
||||
if (cpu_single_env)
|
||||
env = cpu_single_env; /* XXX: find a correct solution for multithread */
|
||||
#if defined(DEBUG_SIGNAL)
|
||||
printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
|
||||
pc, address, is_write, *(unsigned long *)old_set);
|
||||
qemu_printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
|
||||
pc, address, is_write, *(unsigned long *)old_set);
|
||||
#endif
|
||||
/* XXX: locking issue */
|
||||
if (is_write && page_unprotect(address)) {
|
||||
if (is_write && page_unprotect(address, pc, puc)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* see if it is an MMU fault */
|
||||
ret = cpu_x86_handle_mmu_fault(env, address, is_write);
|
||||
ret = cpu_x86_handle_mmu_fault(env, address, is_write,
|
||||
((env->hflags & HF_CPL_MASK) == 3), 0);
|
||||
if (ret < 0)
|
||||
return 0; /* not an MMU fault */
|
||||
if (ret == 0)
|
||||
@@ -483,39 +693,129 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
|
||||
if (tb) {
|
||||
/* the PC is inside the translated code. It means that we have
|
||||
a virtual CPU fault */
|
||||
cpu_restore_state(tb, env, pc);
|
||||
cpu_restore_state(tb, env, pc, puc);
|
||||
}
|
||||
if (ret == 1) {
|
||||
#if 0
|
||||
printf("PF exception: EIP=0x%08x CR2=0x%08x error=0x%x\n",
|
||||
env->eip, env->cr[2], env->error_code);
|
||||
printf("PF exception: EIP=0x%08x CR2=0x%08x error=0x%x\n",
|
||||
env->eip, env->cr[2], env->error_code);
|
||||
#endif
|
||||
/* we restore the process signal mask as the sigreturn should
|
||||
do it (XXX: use sigsetjmp) */
|
||||
sigprocmask(SIG_SETMASK, old_set, NULL);
|
||||
raise_exception_err(EXCP0E_PAGE, env->error_code);
|
||||
/* we restore the process signal mask as the sigreturn should
|
||||
do it (XXX: use sigsetjmp) */
|
||||
sigprocmask(SIG_SETMASK, old_set, NULL);
|
||||
raise_exception_err(EXCP0E_PAGE, env->error_code);
|
||||
} else {
|
||||
/* activate soft MMU for this block */
|
||||
env->hflags |= HF_SOFTMMU_MASK;
|
||||
cpu_resume_from_signal(env, puc);
|
||||
}
|
||||
/* never comes here */
|
||||
return 1;
|
||||
}
|
||||
|
||||
#elif defined(TARGET_ARM)
|
||||
static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
|
||||
int is_write, sigset_t *old_set)
|
||||
int is_write, sigset_t *old_set,
|
||||
void *puc)
|
||||
{
|
||||
/* XXX: do more */
|
||||
return 0;
|
||||
}
|
||||
#elif defined(TARGET_SPARC)
|
||||
static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
|
||||
int is_write, sigset_t *old_set,
|
||||
void *puc)
|
||||
{
|
||||
/* XXX: locking issue */
|
||||
if (is_write && page_unprotect(address, pc, puc)) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#elif defined (TARGET_PPC)
|
||||
static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
|
||||
int is_write, sigset_t *old_set,
|
||||
void *puc)
|
||||
{
|
||||
TranslationBlock *tb;
|
||||
int ret;
|
||||
|
||||
#if 1
|
||||
if (cpu_single_env)
|
||||
env = cpu_single_env; /* XXX: find a correct solution for multithread */
|
||||
#endif
|
||||
#if defined(DEBUG_SIGNAL)
|
||||
printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
|
||||
pc, address, is_write, *(unsigned long *)old_set);
|
||||
#endif
|
||||
/* XXX: locking issue */
|
||||
if (is_write && page_unprotect(address, pc, puc)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* see if it is an MMU fault */
|
||||
ret = cpu_ppc_handle_mmu_fault(env, address, is_write, msr_pr, 0);
|
||||
if (ret < 0)
|
||||
return 0; /* not an MMU fault */
|
||||
if (ret == 0)
|
||||
return 1; /* the MMU fault was handled without causing real CPU fault */
|
||||
|
||||
/* now we have a real cpu fault */
|
||||
tb = tb_find_pc(pc);
|
||||
if (tb) {
|
||||
/* the PC is inside the translated code. It means that we have
|
||||
a virtual CPU fault */
|
||||
cpu_restore_state(tb, env, pc, puc);
|
||||
}
|
||||
if (ret == 1) {
|
||||
#if 0
|
||||
printf("PF exception: NIP=0x%08x error=0x%x %p\n",
|
||||
env->nip, env->error_code, tb);
|
||||
#endif
|
||||
/* we restore the process signal mask as the sigreturn should
|
||||
do it (XXX: use sigsetjmp) */
|
||||
sigprocmask(SIG_SETMASK, old_set, NULL);
|
||||
do_raise_exception_err(env->exception_index, env->error_code);
|
||||
} else {
|
||||
/* activate soft MMU for this block */
|
||||
cpu_resume_from_signal(env, puc);
|
||||
}
|
||||
/* never comes here */
|
||||
return 1;
|
||||
}
|
||||
#else
|
||||
#error unsupported target CPU
|
||||
#endif
|
||||
|
||||
#if defined(__i386__)
|
||||
|
||||
#if defined(USE_CODE_COPY)
|
||||
static void cpu_send_trap(unsigned long pc, int trap,
|
||||
struct ucontext *uc)
|
||||
{
|
||||
TranslationBlock *tb;
|
||||
|
||||
if (cpu_single_env)
|
||||
env = cpu_single_env; /* XXX: find a correct solution for multithread */
|
||||
/* now we have a real cpu fault */
|
||||
tb = tb_find_pc(pc);
|
||||
if (tb) {
|
||||
/* the PC is inside the translated code. It means that we have
|
||||
a virtual CPU fault */
|
||||
cpu_restore_state(tb, env, pc, uc);
|
||||
}
|
||||
sigprocmask(SIG_SETMASK, &uc->uc_sigmask, NULL);
|
||||
raise_exception_err(trap, env->error_code);
|
||||
}
|
||||
#endif
|
||||
|
||||
int cpu_signal_handler(int host_signum, struct siginfo *info,
|
||||
void *puc)
|
||||
{
|
||||
struct ucontext *uc = puc;
|
||||
unsigned long pc;
|
||||
|
||||
int trapno;
|
||||
|
||||
#ifndef REG_EIP
|
||||
/* for glibc 2.1 */
|
||||
#define REG_EIP EIP
|
||||
@@ -523,34 +823,105 @@ int cpu_signal_handler(int host_signum, struct siginfo *info,
|
||||
#define REG_TRAPNO TRAPNO
|
||||
#endif
|
||||
pc = uc->uc_mcontext.gregs[REG_EIP];
|
||||
return handle_cpu_signal(pc, (unsigned long)info->si_addr,
|
||||
uc->uc_mcontext.gregs[REG_TRAPNO] == 0xe ?
|
||||
(uc->uc_mcontext.gregs[REG_ERR] >> 1) & 1 : 0,
|
||||
&uc->uc_sigmask);
|
||||
trapno = uc->uc_mcontext.gregs[REG_TRAPNO];
|
||||
#if defined(TARGET_I386) && defined(USE_CODE_COPY)
|
||||
if (trapno == 0x00 || trapno == 0x05) {
|
||||
/* send division by zero or bound exception */
|
||||
cpu_send_trap(pc, trapno, uc);
|
||||
return 1;
|
||||
} else
|
||||
#endif
|
||||
return handle_cpu_signal(pc, (unsigned long)info->si_addr,
|
||||
trapno == 0xe ?
|
||||
(uc->uc_mcontext.gregs[REG_ERR] >> 1) & 1 : 0,
|
||||
&uc->uc_sigmask, puc);
|
||||
}
|
||||
|
||||
#elif defined(__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)
|
||||
{
|
||||
struct ucontext *uc = puc;
|
||||
struct pt_regs *regs = uc->uc_mcontext.regs;
|
||||
unsigned long pc;
|
||||
int is_write;
|
||||
|
||||
pc = regs->nip;
|
||||
pc = IAR_sig(uc);
|
||||
is_write = 0;
|
||||
#if 0
|
||||
/* ppc 4xx case */
|
||||
if (regs->dsisr & 0x00800000)
|
||||
if (DSISR_sig(uc) & 0x00800000)
|
||||
is_write = 1;
|
||||
#else
|
||||
if (regs->trap != 0x400 && (regs->dsisr & 0x02000000))
|
||||
if (TRAP_sig(uc) != 0x400 && (DSISR_sig(uc) & 0x02000000))
|
||||
is_write = 1;
|
||||
#endif
|
||||
return handle_cpu_signal(pc, (unsigned long)info->si_addr,
|
||||
is_write, &uc->uc_sigmask);
|
||||
is_write, &uc->uc_sigmask, puc);
|
||||
}
|
||||
|
||||
#elif defined(__alpha__)
|
||||
@@ -580,7 +951,7 @@ int cpu_signal_handler(int host_signum, struct siginfo *info,
|
||||
}
|
||||
|
||||
return handle_cpu_signal(pc, (unsigned long)info->si_addr,
|
||||
is_write, &uc->uc_sigmask);
|
||||
is_write, &uc->uc_sigmask, puc);
|
||||
}
|
||||
#elif defined(__sparc__)
|
||||
|
||||
@@ -612,7 +983,7 @@ int cpu_signal_handler(int host_signum, struct siginfo *info,
|
||||
}
|
||||
}
|
||||
return handle_cpu_signal(pc, (unsigned long)info->si_addr,
|
||||
is_write, sigmask);
|
||||
is_write, sigmask, NULL);
|
||||
}
|
||||
|
||||
#elif defined(__arm__)
|
||||
@@ -632,8 +1003,27 @@ int cpu_signal_handler(int host_signum, struct siginfo *info,
|
||||
&uc->uc_sigmask);
|
||||
}
|
||||
|
||||
#elif defined(__mc68000)
|
||||
|
||||
int cpu_signal_handler(int host_signum, struct siginfo *info,
|
||||
void *puc)
|
||||
{
|
||||
struct ucontext *uc = puc;
|
||||
unsigned long pc;
|
||||
int is_write;
|
||||
|
||||
pc = uc->uc_mcontext.gregs[16];
|
||||
/* XXX: compute is_write */
|
||||
is_write = 0;
|
||||
return handle_cpu_signal(pc, (unsigned long)info->si_addr,
|
||||
is_write,
|
||||
&uc->uc_sigmask, puc);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#error host CPU specific signal handler needed
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* !defined(CONFIG_SOFTMMU) */
|
||||
@@ -16,7 +16,9 @@
|
||||
#define PARAMS(x) x
|
||||
typedef void *PTR;
|
||||
typedef uint64_t bfd_vma;
|
||||
typedef int64_t bfd_signed_vma;
|
||||
typedef uint8_t bfd_byte;
|
||||
#define sprintf_vma(s,x) sprintf (s, "%0" PRIx64, x)
|
||||
|
||||
enum bfd_flavour {
|
||||
bfd_target_unknown_flavour,
|
||||
@@ -105,6 +107,9 @@ enum bfd_architecture
|
||||
bfd_arch_i386, /* Intel 386 */
|
||||
#define bfd_mach_i386_i386 0
|
||||
#define bfd_mach_i386_i8086 1
|
||||
#define bfd_mach_i386_i386_intel_syntax 2
|
||||
#define bfd_mach_x86_64 3
|
||||
#define bfd_mach_x86_64_intel_syntax 4
|
||||
bfd_arch_we32k, /* AT&T WE32xxx */
|
||||
bfd_arch_tahoe, /* CCI/Harris Tahoe */
|
||||
bfd_arch_i860, /* Intel 860 */
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
/* General "disassemble this chunk" code. Used for debugging. */
|
||||
#include "config.h"
|
||||
#include "dis-asm.h"
|
||||
#include "disas.h"
|
||||
#include "elf.h"
|
||||
#include <errno.h>
|
||||
|
||||
#include "cpu.h"
|
||||
#include "exec-all.h"
|
||||
#include "disas.h"
|
||||
|
||||
/* Filled in by elfload.c. Simplistic, but will do for now. */
|
||||
unsigned int disas_num_syms;
|
||||
void *disas_symtab;
|
||||
@@ -19,14 +22,32 @@ buffer_read_memory (memaddr, myaddr, length, info)
|
||||
int length;
|
||||
struct disassemble_info *info;
|
||||
{
|
||||
if (memaddr < info->buffer_vma
|
||||
|| memaddr + length > info->buffer_vma + info->buffer_length)
|
||||
/* Out of bounds. Use EIO because GDB uses it. */
|
||||
return EIO;
|
||||
memcpy (myaddr, info->buffer + (memaddr - info->buffer_vma), length);
|
||||
return 0;
|
||||
if (memaddr < info->buffer_vma
|
||||
|| memaddr + length > info->buffer_vma + info->buffer_length)
|
||||
/* Out of bounds. Use EIO because GDB uses it. */
|
||||
return EIO;
|
||||
memcpy (myaddr, info->buffer + (memaddr - info->buffer_vma), length);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
/* Get LENGTH bytes from info's buffer, at target address memaddr.
|
||||
Transfer them to myaddr. */
|
||||
static int
|
||||
target_read_memory (memaddr, myaddr, length, info)
|
||||
bfd_vma memaddr;
|
||||
bfd_byte *myaddr;
|
||||
int length;
|
||||
struct disassemble_info *info;
|
||||
{
|
||||
int i;
|
||||
for(i = 0; i < length; i++) {
|
||||
myaddr[i] = ldub_code((void *)((long)memaddr + i));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Print an error message. We can assume that this is in response to
|
||||
an error return from buffer_read_memory. */
|
||||
void
|
||||
@@ -103,6 +124,12 @@ void disas(FILE *out, void *code, unsigned long size, int is_host, int flags)
|
||||
|
||||
INIT_DISASSEMBLE_INFO(disasm_info, out, fprintf);
|
||||
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
if (!is_host) {
|
||||
disasm_info.read_memory_func = target_read_memory;
|
||||
}
|
||||
#endif
|
||||
|
||||
disasm_info.buffer = code;
|
||||
disasm_info.buffer_vma = (unsigned long)code;
|
||||
disasm_info.buffer_length = size;
|
||||
@@ -113,9 +140,12 @@ void disas(FILE *out, void *code, unsigned long size, int is_host, int flags)
|
||||
#else
|
||||
disasm_info.endian = BFD_ENDIAN_LITTLE;
|
||||
#endif
|
||||
#ifdef __i386__
|
||||
#if defined(__i386__)
|
||||
disasm_info.mach = bfd_mach_i386_i386;
|
||||
print_insn = print_insn_i386;
|
||||
#elif defined(__x86_64__)
|
||||
disasm_info.mach = bfd_mach_x86_64;
|
||||
print_insn = print_insn_i386;
|
||||
#elif defined(__powerpc__)
|
||||
print_insn = print_insn_ppc;
|
||||
#elif defined(__alpha__)
|
||||
@@ -142,6 +172,10 @@ void disas(FILE *out, void *code, unsigned long size, int is_host, int flags)
|
||||
print_insn = print_insn_i386;
|
||||
#elif defined(TARGET_ARM)
|
||||
print_insn = print_insn_arm;
|
||||
#elif defined(TARGET_SPARC)
|
||||
print_insn = print_insn_sparc;
|
||||
#elif defined(TARGET_PPC)
|
||||
print_insn = print_insn_ppc;
|
||||
#else
|
||||
fprintf(out, "Asm output not supported on this arch\n");
|
||||
return;
|
||||
@@ -185,3 +219,71 @@ const char *lookup_symbol(void *orig_addr)
|
||||
}
|
||||
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). */
|
||||
void disas(FILE *out, void *code, unsigned long size, int is_host, int flags);
|
||||
void monitor_disas(target_ulong pc, int nb_insn, int is_physical, int flags);
|
||||
|
||||
/* Look up symbol for debugging purpose. Returns "" if unknown. */
|
||||
const char *lookup_symbol(void *orig_addr);
|
||||
|
||||
+66
-10
@@ -17,31 +17,62 @@
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#if !defined(__DYNGEN_EXEC_H__)
|
||||
#define __DYNGEN_EXEC_H__
|
||||
|
||||
/* NOTE: standard headers should be used with special care at this
|
||||
point because host CPU registers are used as global variables. Some
|
||||
host headers do not allow that. */
|
||||
#include <stddef.h>
|
||||
|
||||
typedef unsigned char uint8_t;
|
||||
typedef unsigned short uint16_t;
|
||||
typedef unsigned int uint32_t;
|
||||
/* XXX may be done for all 64 bits targets ? */
|
||||
#if defined (__x86_64__)
|
||||
typedef unsigned long uint64_t;
|
||||
#else
|
||||
typedef unsigned long long uint64_t;
|
||||
#endif
|
||||
|
||||
typedef signed char int8_t;
|
||||
typedef signed short int16_t;
|
||||
typedef signed int int32_t;
|
||||
#if defined (__x86_64__)
|
||||
typedef signed long int64_t;
|
||||
#else
|
||||
typedef signed long long int64_t;
|
||||
#endif
|
||||
|
||||
#define bswap32(x) \
|
||||
({ \
|
||||
uint32_t __x = (x); \
|
||||
((uint32_t)( \
|
||||
(((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
|
||||
(((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \
|
||||
(((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \
|
||||
(((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) )); \
|
||||
})
|
||||
#define INT8_MIN (-128)
|
||||
#define INT16_MIN (-32767-1)
|
||||
#define INT32_MIN (-2147483647-1)
|
||||
#define INT64_MIN (-(int64_t)(9223372036854775807)-1)
|
||||
#define INT8_MAX (127)
|
||||
#define INT16_MAX (32767)
|
||||
#define INT32_MAX (2147483647)
|
||||
#define INT64_MAX ((int64_t)(9223372036854775807))
|
||||
#define UINT8_MAX (255)
|
||||
#define UINT16_MAX (65535)
|
||||
#define UINT32_MAX (4294967295U)
|
||||
#define UINT64_MAX ((uint64_t)(18446744073709551615))
|
||||
|
||||
typedef struct FILE FILE;
|
||||
extern int fprintf(FILE *, const char *, ...);
|
||||
extern int printf(const char *, ...);
|
||||
#undef NULL
|
||||
#define NULL 0
|
||||
#if defined(_BSD) && !defined(__APPLE__)
|
||||
#include <ieeefp.h>
|
||||
|
||||
#define FE_TONEAREST FP_RN
|
||||
#define FE_DOWNWARD FP_RM
|
||||
#define FE_UPWARD FP_RP
|
||||
#define FE_TOWARDZERO FP_RZ
|
||||
#define fesetround(x) fpsetround(x)
|
||||
#else
|
||||
#include <fenv.h>
|
||||
#endif
|
||||
|
||||
#ifdef __i386__
|
||||
#define AREG0 "ebp"
|
||||
@@ -49,11 +80,21 @@ extern int printf(const char *, ...);
|
||||
#define AREG2 "esi"
|
||||
#define AREG3 "edi"
|
||||
#endif
|
||||
#ifdef __x86_64__
|
||||
#define AREG0 "rbp"
|
||||
#define AREG1 "rbx"
|
||||
#define AREG2 "r12"
|
||||
#define AREG3 "r13"
|
||||
#define AREG4 "r14"
|
||||
#define AREG5 "r15"
|
||||
#endif
|
||||
#ifdef __powerpc__
|
||||
#define AREG0 "r27"
|
||||
#define AREG1 "r24"
|
||||
#define AREG2 "r25"
|
||||
#define AREG3 "r26"
|
||||
/* XXX: suppress this hack */
|
||||
#if defined(CONFIG_USER_ONLY)
|
||||
#define AREG4 "r16"
|
||||
#define AREG5 "r17"
|
||||
#define AREG6 "r18"
|
||||
@@ -62,6 +103,7 @@ extern int printf(const char *, ...);
|
||||
#define AREG9 "r21"
|
||||
#define AREG10 "r22"
|
||||
#define AREG11 "r23"
|
||||
#endif
|
||||
#define USE_INT_TO_FLOAT_HELPERS
|
||||
#define BUGGY_GCC_DIV64
|
||||
#endif
|
||||
@@ -109,6 +151,13 @@ extern int printf(const char *, ...);
|
||||
#define AREG5 "$13"
|
||||
#define AREG6 "$14"
|
||||
#endif
|
||||
#ifdef __mc68000
|
||||
#define AREG0 "%a5"
|
||||
#define AREG1 "%a4"
|
||||
#define AREG2 "%d7"
|
||||
#define AREG3 "%d6"
|
||||
#define AREG4 "%d5"
|
||||
#endif
|
||||
#ifdef __ia64__
|
||||
#define AREG0 "r27"
|
||||
#define AREG1 "r24"
|
||||
@@ -154,11 +203,14 @@ extern int __op_param1, __op_param2, __op_param3;
|
||||
#define PARAM3 ((long)(&__op_param3))
|
||||
#endif
|
||||
|
||||
extern int __op_jmp0, __op_jmp1;
|
||||
extern int __op_jmp0, __op_jmp1, __op_jmp2, __op_jmp3;
|
||||
|
||||
#ifdef __i386__
|
||||
#define EXIT_TB() asm volatile ("ret")
|
||||
#endif
|
||||
#ifdef __x86_64__
|
||||
#define EXIT_TB() asm volatile ("ret")
|
||||
#endif
|
||||
#ifdef __powerpc__
|
||||
#define EXIT_TB() asm volatile ("blr")
|
||||
#endif
|
||||
@@ -178,4 +230,8 @@ extern int __op_jmp0, __op_jmp1;
|
||||
#ifdef __arm__
|
||||
#define EXIT_TB() asm volatile ("b exec_loop")
|
||||
#endif
|
||||
#ifdef __mc68000
|
||||
#define EXIT_TB() asm volatile ("rts")
|
||||
#endif
|
||||
|
||||
#endif /* !defined(__DYNGEN_EXEC_H__) */
|
||||
@@ -19,7 +19,7 @@
|
||||
*/
|
||||
|
||||
int __op_param1, __op_param2, __op_param3;
|
||||
int __op_jmp0, __op_jmp1;
|
||||
int __op_jmp0, __op_jmp1, __op_jmp2, __op_jmp3;
|
||||
|
||||
#ifdef __i386__
|
||||
static inline void flush_icache_range(unsigned long start, unsigned long stop)
|
||||
@@ -27,6 +27,12 @@ static inline void flush_icache_range(unsigned long start, unsigned long stop)
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __x86_64__
|
||||
static inline void flush_icache_range(unsigned long start, unsigned long stop)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __s390__
|
||||
static inline void flush_icache_range(unsigned long start, unsigned long stop)
|
||||
{
|
||||
@@ -94,6 +100,14 @@ static inline void flush_icache_range(unsigned long start, unsigned long stop)
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __mc68000
|
||||
#include <asm/cachectl.h>
|
||||
static inline void flush_icache_range(unsigned long start, unsigned long stop)
|
||||
{
|
||||
cacheflush(start,FLUSH_SCOPE_LINE,FLUSH_CACHE_BOTH,stop-start+16);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __alpha__
|
||||
|
||||
register int gp asm("$29");
|
||||
|
||||
+603
@@ -0,0 +1,603 @@
|
||||
/*
|
||||
* internal execution defines for qemu
|
||||
*
|
||||
* Copyright (c) 2003 Fabrice Bellard
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/* allow to see translation results - the slowdown should be negligible, so we leave it */
|
||||
#define DEBUG_DISAS
|
||||
|
||||
#ifndef glue
|
||||
#define xglue(x, y) x ## y
|
||||
#define glue(x, y) xglue(x, y)
|
||||
#define stringify(s) tostring(s)
|
||||
#define tostring(s) #s
|
||||
#endif
|
||||
|
||||
#if GCC_MAJOR < 3
|
||||
#define __builtin_expect(x, n) (x)
|
||||
#endif
|
||||
|
||||
#ifdef __i386__
|
||||
#define REGPARM(n) __attribute((regparm(n)))
|
||||
#else
|
||||
#define REGPARM(n)
|
||||
#endif
|
||||
|
||||
/* is_jmp field values */
|
||||
#define DISAS_NEXT 0 /* next instruction can be analyzed */
|
||||
#define DISAS_JUMP 1 /* only pc was modified dynamically */
|
||||
#define DISAS_UPDATE 2 /* cpu state was modified dynamically */
|
||||
#define DISAS_TB_JUMP 3 /* only pc was modified statically */
|
||||
|
||||
struct TranslationBlock;
|
||||
|
||||
/* XXX: make safe guess about sizes */
|
||||
#define MAX_OP_PER_INSTR 32
|
||||
#define OPC_BUF_SIZE 512
|
||||
#define OPC_MAX_SIZE (OPC_BUF_SIZE - MAX_OP_PER_INSTR)
|
||||
|
||||
#define OPPARAM_BUF_SIZE (OPC_BUF_SIZE * 3)
|
||||
|
||||
extern uint16_t gen_opc_buf[OPC_BUF_SIZE];
|
||||
extern uint32_t gen_opparam_buf[OPPARAM_BUF_SIZE];
|
||||
extern uint32_t gen_opc_pc[OPC_BUF_SIZE];
|
||||
extern uint8_t gen_opc_cc_op[OPC_BUF_SIZE];
|
||||
extern uint8_t gen_opc_instr_start[OPC_BUF_SIZE];
|
||||
|
||||
typedef void (GenOpFunc)(void);
|
||||
typedef void (GenOpFunc1)(long);
|
||||
typedef void (GenOpFunc2)(long, long);
|
||||
typedef void (GenOpFunc3)(long, long, long);
|
||||
|
||||
#if defined(TARGET_I386)
|
||||
|
||||
void optimize_flags_init(void);
|
||||
|
||||
#endif
|
||||
|
||||
extern FILE *logfile;
|
||||
extern int loglevel;
|
||||
|
||||
int gen_intermediate_code(CPUState *env, struct TranslationBlock *tb);
|
||||
int gen_intermediate_code_pc(CPUState *env, struct TranslationBlock *tb);
|
||||
void dump_ops(const uint16_t *opc_buf, const uint32_t *opparam_buf);
|
||||
int cpu_gen_code(CPUState *env, struct TranslationBlock *tb,
|
||||
int max_code_size, int *gen_code_size_ptr);
|
||||
int cpu_restore_state(struct TranslationBlock *tb,
|
||||
CPUState *env, unsigned long searched_pc,
|
||||
void *puc);
|
||||
int cpu_gen_code_copy(CPUState *env, struct TranslationBlock *tb,
|
||||
int max_code_size, int *gen_code_size_ptr);
|
||||
int cpu_restore_state_copy(struct TranslationBlock *tb,
|
||||
CPUState *env, unsigned long searched_pc,
|
||||
void *puc);
|
||||
void cpu_resume_from_signal(CPUState *env1, void *puc);
|
||||
void cpu_exec_init(void);
|
||||
int page_unprotect(unsigned long address, unsigned long pc, void *puc);
|
||||
void tb_invalidate_phys_page_range(target_ulong start, target_ulong end,
|
||||
int is_cpu_write_access);
|
||||
void tb_invalidate_page_range(target_ulong start, target_ulong end);
|
||||
void tlb_flush_page(CPUState *env, target_ulong addr);
|
||||
void tlb_flush(CPUState *env, int flush_global);
|
||||
int tlb_set_page(CPUState *env, target_ulong vaddr,
|
||||
target_phys_addr_t paddr, int prot,
|
||||
int is_user, int is_softmmu);
|
||||
|
||||
#define CODE_GEN_MAX_SIZE 65536
|
||||
#define CODE_GEN_ALIGN 16 /* must be >= of the size of a icache line */
|
||||
|
||||
#define CODE_GEN_HASH_BITS 15
|
||||
#define CODE_GEN_HASH_SIZE (1 << CODE_GEN_HASH_BITS)
|
||||
|
||||
#define CODE_GEN_PHYS_HASH_BITS 15
|
||||
#define CODE_GEN_PHYS_HASH_SIZE (1 << CODE_GEN_PHYS_HASH_BITS)
|
||||
|
||||
/* maximum total translate dcode allocated */
|
||||
|
||||
/* NOTE: the translated code area cannot be too big because on some
|
||||
archs the range of "fast" function calls is limited. Here is a
|
||||
summary of the ranges:
|
||||
|
||||
i386 : signed 32 bits
|
||||
arm : signed 26 bits
|
||||
ppc : signed 24 bits
|
||||
sparc : signed 32 bits
|
||||
alpha : signed 23 bits
|
||||
*/
|
||||
|
||||
#if defined(__alpha__)
|
||||
#define CODE_GEN_BUFFER_SIZE (2 * 1024 * 1024)
|
||||
#elif defined(__powerpc__)
|
||||
#define CODE_GEN_BUFFER_SIZE (6 * 1024 * 1024)
|
||||
#else
|
||||
#define CODE_GEN_BUFFER_SIZE (8 * 1024 * 1024)
|
||||
#endif
|
||||
|
||||
//#define CODE_GEN_BUFFER_SIZE (128 * 1024)
|
||||
|
||||
/* estimated block size for TB allocation */
|
||||
/* XXX: use a per code average code fragment size and modulate it
|
||||
according to the host CPU */
|
||||
#if defined(CONFIG_SOFTMMU)
|
||||
#define CODE_GEN_AVG_BLOCK_SIZE 128
|
||||
#else
|
||||
#define CODE_GEN_AVG_BLOCK_SIZE 64
|
||||
#endif
|
||||
|
||||
#define CODE_GEN_MAX_BLOCKS (CODE_GEN_BUFFER_SIZE / CODE_GEN_AVG_BLOCK_SIZE)
|
||||
|
||||
#if defined(__powerpc__)
|
||||
#define USE_DIRECT_JUMP
|
||||
#endif
|
||||
#if defined(__i386__) && !defined(_WIN32)
|
||||
#define USE_DIRECT_JUMP
|
||||
#endif
|
||||
|
||||
typedef struct TranslationBlock {
|
||||
target_ulong pc; /* simulated PC corresponding to this block (EIP + CS base) */
|
||||
target_ulong cs_base; /* CS base for this block */
|
||||
unsigned int flags; /* flags defining in which context the code was generated */
|
||||
uint16_t size; /* size of target code for this block (1 <=
|
||||
size <= TARGET_PAGE_SIZE) */
|
||||
uint16_t cflags; /* compile flags */
|
||||
#define CF_CODE_COPY 0x0001 /* block was generated in code copy mode */
|
||||
#define CF_TB_FP_USED 0x0002 /* fp ops are used in the TB */
|
||||
#define CF_FP_USED 0x0004 /* fp ops are used in the TB or in a chained TB */
|
||||
#define CF_SINGLE_INSN 0x0008 /* compile only a single instruction */
|
||||
|
||||
uint8_t *tc_ptr; /* pointer to the translated code */
|
||||
struct TranslationBlock *hash_next; /* next matching tb for virtual address */
|
||||
/* next matching tb for physical address. */
|
||||
struct TranslationBlock *phys_hash_next;
|
||||
/* first and second physical page containing code. The lower bit
|
||||
of the pointer tells the index in page_next[] */
|
||||
struct TranslationBlock *page_next[2];
|
||||
target_ulong page_addr[2];
|
||||
|
||||
/* the following data are used to directly call another TB from
|
||||
the code of this one. */
|
||||
uint16_t tb_next_offset[2]; /* offset of original jump target */
|
||||
#ifdef USE_DIRECT_JUMP
|
||||
uint16_t tb_jmp_offset[4]; /* offset of jump instruction */
|
||||
#else
|
||||
uint32_t tb_next[2]; /* address of jump generated code */
|
||||
#endif
|
||||
/* list of TBs jumping to this one. This is a circular list using
|
||||
the two least significant bits of the pointers to tell what is
|
||||
the next pointer: 0 = jmp_next[0], 1 = jmp_next[1], 2 =
|
||||
jmp_first */
|
||||
struct TranslationBlock *jmp_next[2];
|
||||
struct TranslationBlock *jmp_first;
|
||||
} TranslationBlock;
|
||||
|
||||
static inline unsigned int tb_hash_func(unsigned long pc)
|
||||
{
|
||||
return pc & (CODE_GEN_HASH_SIZE - 1);
|
||||
}
|
||||
|
||||
static inline unsigned int tb_phys_hash_func(unsigned long pc)
|
||||
{
|
||||
return pc & (CODE_GEN_PHYS_HASH_SIZE - 1);
|
||||
}
|
||||
|
||||
TranslationBlock *tb_alloc(unsigned long pc);
|
||||
void tb_flush(CPUState *env);
|
||||
void tb_link(TranslationBlock *tb);
|
||||
void tb_link_phys(TranslationBlock *tb,
|
||||
target_ulong phys_pc, target_ulong phys_page2);
|
||||
|
||||
extern TranslationBlock *tb_hash[CODE_GEN_HASH_SIZE];
|
||||
extern TranslationBlock *tb_phys_hash[CODE_GEN_PHYS_HASH_SIZE];
|
||||
|
||||
extern uint8_t code_gen_buffer[CODE_GEN_BUFFER_SIZE];
|
||||
extern uint8_t *code_gen_ptr;
|
||||
|
||||
/* find a translation block in the translation cache. If not found,
|
||||
return NULL and the pointer to the last element of the list in pptb */
|
||||
static inline TranslationBlock *tb_find(TranslationBlock ***pptb,
|
||||
target_ulong pc,
|
||||
target_ulong cs_base,
|
||||
unsigned int flags)
|
||||
{
|
||||
TranslationBlock **ptb, *tb;
|
||||
unsigned int h;
|
||||
|
||||
h = tb_hash_func(pc);
|
||||
ptb = &tb_hash[h];
|
||||
for(;;) {
|
||||
tb = *ptb;
|
||||
if (!tb)
|
||||
break;
|
||||
if (tb->pc == pc && tb->cs_base == cs_base && tb->flags == flags)
|
||||
return tb;
|
||||
ptb = &tb->hash_next;
|
||||
}
|
||||
*pptb = ptb;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
#if defined(USE_DIRECT_JUMP)
|
||||
|
||||
#if defined(__powerpc__)
|
||||
static inline void tb_set_jmp_target1(unsigned long jmp_addr, unsigned long addr)
|
||||
{
|
||||
uint32_t val, *ptr;
|
||||
|
||||
/* patch the branch destination */
|
||||
ptr = (uint32_t *)jmp_addr;
|
||||
val = *ptr;
|
||||
val = (val & ~0x03fffffc) | ((addr - jmp_addr) & 0x03fffffc);
|
||||
*ptr = val;
|
||||
/* flush icache */
|
||||
asm volatile ("dcbst 0,%0" : : "r"(ptr) : "memory");
|
||||
asm volatile ("sync" : : : "memory");
|
||||
asm volatile ("icbi 0,%0" : : "r"(ptr) : "memory");
|
||||
asm volatile ("sync" : : : "memory");
|
||||
asm volatile ("isync" : : : "memory");
|
||||
}
|
||||
#elif defined(__i386__)
|
||||
static inline void tb_set_jmp_target1(unsigned long jmp_addr, unsigned long addr)
|
||||
{
|
||||
/* patch the branch destination */
|
||||
*(uint32_t *)jmp_addr = addr - (jmp_addr + 4);
|
||||
/* no need to flush icache explicitely */
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline void tb_set_jmp_target(TranslationBlock *tb,
|
||||
int n, unsigned long addr)
|
||||
{
|
||||
unsigned long offset;
|
||||
|
||||
offset = tb->tb_jmp_offset[n];
|
||||
tb_set_jmp_target1((unsigned long)(tb->tc_ptr + offset), addr);
|
||||
offset = tb->tb_jmp_offset[n + 2];
|
||||
if (offset != 0xffff)
|
||||
tb_set_jmp_target1((unsigned long)(tb->tc_ptr + offset), addr);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
/* set the jump target */
|
||||
static inline void tb_set_jmp_target(TranslationBlock *tb,
|
||||
int n, unsigned long addr)
|
||||
{
|
||||
tb->tb_next[n] = addr;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static inline void tb_add_jump(TranslationBlock *tb, int n,
|
||||
TranslationBlock *tb_next)
|
||||
{
|
||||
/* NOTE: this test is only needed for thread safety */
|
||||
if (!tb->jmp_next[n]) {
|
||||
/* patch the native jump address */
|
||||
tb_set_jmp_target(tb, n, (unsigned long)tb_next->tc_ptr);
|
||||
|
||||
/* add in TB jmp circular list */
|
||||
tb->jmp_next[n] = tb_next->jmp_first;
|
||||
tb_next->jmp_first = (TranslationBlock *)((long)(tb) | (n));
|
||||
}
|
||||
}
|
||||
|
||||
TranslationBlock *tb_find_pc(unsigned long pc_ptr);
|
||||
|
||||
#ifndef offsetof
|
||||
#define offsetof(type, field) ((size_t) &((type *)0)->field)
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32)
|
||||
#define ASM_DATA_SECTION ".section \".data\"\n"
|
||||
#define ASM_PREVIOUS_SECTION ".section .text\n"
|
||||
#elif defined(__APPLE__)
|
||||
#define ASM_DATA_SECTION ".data\n"
|
||||
#define ASM_PREVIOUS_SECTION ".text\n"
|
||||
#define ASM_NAME(x) "_" #x
|
||||
#else
|
||||
#define ASM_DATA_SECTION ".section \".data\"\n"
|
||||
#define ASM_PREVIOUS_SECTION ".previous\n"
|
||||
#define ASM_NAME(x) stringify(x)
|
||||
#endif
|
||||
|
||||
#if defined(__powerpc__)
|
||||
|
||||
/* we patch the jump instruction directly */
|
||||
#define JUMP_TB(opname, tbparam, n, eip)\
|
||||
do {\
|
||||
asm volatile (ASM_DATA_SECTION\
|
||||
ASM_NAME(__op_label) #n "." ASM_NAME(opname) ":\n"\
|
||||
".long 1f\n"\
|
||||
ASM_PREVIOUS_SECTION \
|
||||
"b " ASM_NAME(__op_jmp) #n "\n"\
|
||||
"1:\n");\
|
||||
T0 = (long)(tbparam) + (n);\
|
||||
EIP = eip;\
|
||||
EXIT_TB();\
|
||||
} while (0)
|
||||
|
||||
#define JUMP_TB2(opname, tbparam, n)\
|
||||
do {\
|
||||
asm volatile ("b " ASM_NAME(__op_jmp) #n "\n");\
|
||||
} while (0)
|
||||
|
||||
#elif defined(__i386__) && defined(USE_DIRECT_JUMP)
|
||||
|
||||
/* we patch the jump instruction directly */
|
||||
#define JUMP_TB(opname, tbparam, n, eip)\
|
||||
do {\
|
||||
asm volatile (".section .data\n"\
|
||||
ASM_NAME(__op_label) #n "." ASM_NAME(opname) ":\n"\
|
||||
".long 1f\n"\
|
||||
ASM_PREVIOUS_SECTION \
|
||||
"jmp " ASM_NAME(__op_jmp) #n "\n"\
|
||||
"1:\n");\
|
||||
T0 = (long)(tbparam) + (n);\
|
||||
EIP = eip;\
|
||||
EXIT_TB();\
|
||||
} while (0)
|
||||
|
||||
#define JUMP_TB2(opname, tbparam, n)\
|
||||
do {\
|
||||
asm volatile ("jmp " ASM_NAME(__op_jmp) #n "\n");\
|
||||
} while (0)
|
||||
|
||||
#else
|
||||
|
||||
/* jump to next block operations (more portable code, does not need
|
||||
cache flushing, but slower because of indirect jump) */
|
||||
#define JUMP_TB(opname, tbparam, n, eip)\
|
||||
do {\
|
||||
static void __attribute__((unused)) *__op_label ## n = &&label ## n;\
|
||||
static void __attribute__((unused)) *dummy ## n = &&dummy_label ## n;\
|
||||
goto *(void *)(((TranslationBlock *)tbparam)->tb_next[n]);\
|
||||
label ## n:\
|
||||
T0 = (long)(tbparam) + (n);\
|
||||
EIP = eip;\
|
||||
dummy_label ## n:\
|
||||
EXIT_TB();\
|
||||
} while (0)
|
||||
|
||||
/* second jump to same destination 'n' */
|
||||
#define JUMP_TB2(opname, tbparam, n)\
|
||||
do {\
|
||||
goto *(void *)(((TranslationBlock *)tbparam)->tb_next[n - 2]);\
|
||||
} while (0)
|
||||
|
||||
#endif
|
||||
|
||||
extern CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4];
|
||||
extern CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4];
|
||||
extern void *io_mem_opaque[IO_MEM_NB_ENTRIES];
|
||||
|
||||
#ifdef __powerpc__
|
||||
static inline int testandset (int *p)
|
||||
{
|
||||
int ret;
|
||||
__asm__ __volatile__ (
|
||||
"0: lwarx %0,0,%1\n"
|
||||
" xor. %0,%3,%0\n"
|
||||
" bne 1f\n"
|
||||
" stwcx. %2,0,%1\n"
|
||||
" bne- 0b\n"
|
||||
"1: "
|
||||
: "=&r" (ret)
|
||||
: "r" (p), "r" (1), "r" (0)
|
||||
: "cr0", "memory");
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __i386__
|
||||
static inline int testandset (int *p)
|
||||
{
|
||||
char ret;
|
||||
long int readval;
|
||||
|
||||
__asm__ __volatile__ ("lock; cmpxchgl %3, %1; sete %0"
|
||||
: "=q" (ret), "=m" (*p), "=a" (readval)
|
||||
: "r" (1), "m" (*p), "a" (0)
|
||||
: "memory");
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __x86_64__
|
||||
static inline int testandset (int *p)
|
||||
{
|
||||
char ret;
|
||||
int readval;
|
||||
|
||||
__asm__ __volatile__ ("lock; cmpxchgl %3, %1; sete %0"
|
||||
: "=q" (ret), "=m" (*p), "=a" (readval)
|
||||
: "r" (1), "m" (*p), "a" (0)
|
||||
: "memory");
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __s390__
|
||||
static inline int testandset (int *p)
|
||||
{
|
||||
int ret;
|
||||
|
||||
__asm__ __volatile__ ("0: cs %0,%1,0(%2)\n"
|
||||
" jl 0b"
|
||||
: "=&d" (ret)
|
||||
: "r" (1), "a" (p), "0" (*p)
|
||||
: "cc", "memory" );
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __alpha__
|
||||
static inline int testandset (int *p)
|
||||
{
|
||||
int ret;
|
||||
unsigned long one;
|
||||
|
||||
__asm__ __volatile__ ("0: mov 1,%2\n"
|
||||
" ldl_l %0,%1\n"
|
||||
" stl_c %2,%1\n"
|
||||
" beq %2,1f\n"
|
||||
".subsection 2\n"
|
||||
"1: br 0b\n"
|
||||
".previous"
|
||||
: "=r" (ret), "=m" (*p), "=r" (one)
|
||||
: "m" (*p));
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __sparc__
|
||||
static inline int testandset (int *p)
|
||||
{
|
||||
int ret;
|
||||
|
||||
__asm__ __volatile__("ldstub [%1], %0"
|
||||
: "=r" (ret)
|
||||
: "r" (p)
|
||||
: "memory");
|
||||
|
||||
return (ret ? 1 : 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __arm__
|
||||
static inline int testandset (int *spinlock)
|
||||
{
|
||||
register unsigned int ret;
|
||||
__asm__ __volatile__("swp %0, %1, [%2]"
|
||||
: "=r"(ret)
|
||||
: "0"(1), "r"(spinlock));
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __mc68000
|
||||
static inline int testandset (int *p)
|
||||
{
|
||||
char ret;
|
||||
__asm__ __volatile__("tas %1; sne %0"
|
||||
: "=r" (ret)
|
||||
: "m" (p)
|
||||
: "cc","memory");
|
||||
return ret == 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
typedef int spinlock_t;
|
||||
|
||||
#define SPIN_LOCK_UNLOCKED 0
|
||||
|
||||
#if defined(CONFIG_USER_ONLY)
|
||||
static inline void spin_lock(spinlock_t *lock)
|
||||
{
|
||||
while (testandset(lock));
|
||||
}
|
||||
|
||||
static inline void spin_unlock(spinlock_t *lock)
|
||||
{
|
||||
*lock = 0;
|
||||
}
|
||||
|
||||
static inline int spin_trylock(spinlock_t *lock)
|
||||
{
|
||||
return !testandset(lock);
|
||||
}
|
||||
#else
|
||||
static inline void spin_lock(spinlock_t *lock)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void spin_unlock(spinlock_t *lock)
|
||||
{
|
||||
}
|
||||
|
||||
static inline int spin_trylock(spinlock_t *lock)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
extern spinlock_t tb_lock;
|
||||
|
||||
extern int tb_invalidated_flag;
|
||||
|
||||
#if (defined(TARGET_I386) || defined(TARGET_PPC)) && \
|
||||
!defined(CONFIG_USER_ONLY)
|
||||
|
||||
void tlb_fill(unsigned long addr, int is_write, int is_user,
|
||||
void *retaddr);
|
||||
|
||||
#define ACCESS_TYPE 3
|
||||
#define MEMSUFFIX _code
|
||||
#define env cpu_single_env
|
||||
|
||||
#define DATA_SIZE 1
|
||||
#include "softmmu_header.h"
|
||||
|
||||
#define DATA_SIZE 2
|
||||
#include "softmmu_header.h"
|
||||
|
||||
#define DATA_SIZE 4
|
||||
#include "softmmu_header.h"
|
||||
|
||||
#undef ACCESS_TYPE
|
||||
#undef MEMSUFFIX
|
||||
#undef env
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_USER_ONLY)
|
||||
static inline target_ulong get_phys_addr_code(CPUState *env, target_ulong addr)
|
||||
{
|
||||
return addr;
|
||||
}
|
||||
#else
|
||||
/* NOTE: this function can trigger an exception */
|
||||
/* NOTE2: the returned address is not exactly the physical address: it
|
||||
is the offset relative to phys_ram_base */
|
||||
/* XXX: i386 target specific */
|
||||
static inline target_ulong get_phys_addr_code(CPUState *env, target_ulong addr)
|
||||
{
|
||||
int is_user, index;
|
||||
|
||||
index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
|
||||
#if defined(TARGET_I386)
|
||||
is_user = ((env->hflags & HF_CPL_MASK) == 3);
|
||||
#elif defined (TARGET_PPC)
|
||||
is_user = msr_pr;
|
||||
#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
|
||||
@@ -1,359 +0,0 @@
|
||||
/*
|
||||
* internal execution defines for qemu
|
||||
*
|
||||
* Copyright (c) 2003 Fabrice Bellard
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/* allow to see translation results - the slowdown should be negligible, so we leave it */
|
||||
#define DEBUG_DISAS
|
||||
|
||||
/* is_jmp field values */
|
||||
#define DISAS_NEXT 0 /* next instruction can be analyzed */
|
||||
#define DISAS_JUMP 1 /* only pc was modified dynamically */
|
||||
#define DISAS_UPDATE 2 /* cpu state was modified dynamically */
|
||||
#define DISAS_TB_JUMP 3 /* only pc was modified statically */
|
||||
|
||||
struct TranslationBlock;
|
||||
|
||||
/* XXX: make safe guess about sizes */
|
||||
#define MAX_OP_PER_INSTR 32
|
||||
#define OPC_BUF_SIZE 512
|
||||
#define OPC_MAX_SIZE (OPC_BUF_SIZE - MAX_OP_PER_INSTR)
|
||||
|
||||
#define OPPARAM_BUF_SIZE (OPC_BUF_SIZE * 3)
|
||||
|
||||
extern uint16_t gen_opc_buf[OPC_BUF_SIZE];
|
||||
extern uint32_t gen_opparam_buf[OPPARAM_BUF_SIZE];
|
||||
extern uint32_t gen_opc_pc[OPC_BUF_SIZE];
|
||||
extern uint8_t gen_opc_cc_op[OPC_BUF_SIZE];
|
||||
extern uint8_t gen_opc_instr_start[OPC_BUF_SIZE];
|
||||
|
||||
#if defined(TARGET_I386)
|
||||
|
||||
#define GEN_FLAG_CODE32_SHIFT 0
|
||||
#define GEN_FLAG_ADDSEG_SHIFT 1
|
||||
#define GEN_FLAG_SS32_SHIFT 2
|
||||
#define GEN_FLAG_VM_SHIFT 3
|
||||
#define GEN_FLAG_ST_SHIFT 4
|
||||
#define GEN_FLAG_TF_SHIFT 8 /* same position as eflags */
|
||||
#define GEN_FLAG_CPL_SHIFT 9
|
||||
#define GEN_FLAG_IOPL_SHIFT 12 /* same position as eflags */
|
||||
|
||||
#endif
|
||||
|
||||
extern FILE *logfile;
|
||||
extern int loglevel;
|
||||
|
||||
int gen_intermediate_code(struct TranslationBlock *tb);
|
||||
int gen_intermediate_code_pc(struct TranslationBlock *tb);
|
||||
void dump_ops(const uint16_t *opc_buf, const uint32_t *opparam_buf);
|
||||
int cpu_gen_code(struct TranslationBlock *tb,
|
||||
int max_code_size, int *gen_code_size_ptr);
|
||||
int cpu_restore_state(struct TranslationBlock *tb,
|
||||
CPUState *env, unsigned long searched_pc);
|
||||
void cpu_exec_init(void);
|
||||
int page_unprotect(unsigned long address);
|
||||
void page_unmap(void);
|
||||
|
||||
#define CODE_GEN_MAX_SIZE 65536
|
||||
#define CODE_GEN_ALIGN 16 /* must be >= of the size of a icache line */
|
||||
|
||||
#define CODE_GEN_HASH_BITS 15
|
||||
#define CODE_GEN_HASH_SIZE (1 << CODE_GEN_HASH_BITS)
|
||||
|
||||
/* maximum total translate dcode allocated */
|
||||
#define CODE_GEN_BUFFER_SIZE (2048 * 1024)
|
||||
//#define CODE_GEN_BUFFER_SIZE (128 * 1024)
|
||||
|
||||
#if defined(__powerpc__)
|
||||
#define USE_DIRECT_JUMP
|
||||
#endif
|
||||
|
||||
typedef struct TranslationBlock {
|
||||
unsigned long pc; /* simulated PC corresponding to this block (EIP + CS base) */
|
||||
unsigned long cs_base; /* CS base for this block */
|
||||
unsigned int flags; /* flags defining in which context the code was generated */
|
||||
uint16_t size; /* size of target code for this block (1 <=
|
||||
size <= TARGET_PAGE_SIZE) */
|
||||
uint8_t *tc_ptr; /* pointer to the translated code */
|
||||
struct TranslationBlock *hash_next; /* next matching block */
|
||||
struct TranslationBlock *page_next[2]; /* next blocks in even/odd page */
|
||||
/* the following data are used to directly call another TB from
|
||||
the code of this one. */
|
||||
uint16_t tb_next_offset[2]; /* offset of original jump target */
|
||||
#ifdef USE_DIRECT_JUMP
|
||||
uint16_t tb_jmp_offset[2]; /* offset of jump instruction */
|
||||
#else
|
||||
uint32_t tb_next[2]; /* address of jump generated code */
|
||||
#endif
|
||||
/* list of TBs jumping to this one. This is a circular list using
|
||||
the two least significant bits of the pointers to tell what is
|
||||
the next pointer: 0 = jmp_next[0], 1 = jmp_next[1], 2 =
|
||||
jmp_first */
|
||||
struct TranslationBlock *jmp_next[2];
|
||||
struct TranslationBlock *jmp_first;
|
||||
} TranslationBlock;
|
||||
|
||||
static inline unsigned int tb_hash_func(unsigned long pc)
|
||||
{
|
||||
return pc & (CODE_GEN_HASH_SIZE - 1);
|
||||
}
|
||||
|
||||
TranslationBlock *tb_alloc(unsigned long pc);
|
||||
void tb_flush(void);
|
||||
void tb_link(TranslationBlock *tb);
|
||||
|
||||
extern TranslationBlock *tb_hash[CODE_GEN_HASH_SIZE];
|
||||
|
||||
extern uint8_t code_gen_buffer[CODE_GEN_BUFFER_SIZE];
|
||||
extern uint8_t *code_gen_ptr;
|
||||
|
||||
/* find a translation block in the translation cache. If not found,
|
||||
return NULL and the pointer to the last element of the list in pptb */
|
||||
static inline TranslationBlock *tb_find(TranslationBlock ***pptb,
|
||||
unsigned long pc,
|
||||
unsigned long cs_base,
|
||||
unsigned int flags)
|
||||
{
|
||||
TranslationBlock **ptb, *tb;
|
||||
unsigned int h;
|
||||
|
||||
h = tb_hash_func(pc);
|
||||
ptb = &tb_hash[h];
|
||||
for(;;) {
|
||||
tb = *ptb;
|
||||
if (!tb)
|
||||
break;
|
||||
if (tb->pc == pc && tb->cs_base == cs_base && tb->flags == flags)
|
||||
return tb;
|
||||
ptb = &tb->hash_next;
|
||||
}
|
||||
*pptb = ptb;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#if defined(__powerpc__)
|
||||
|
||||
static inline void tb_set_jmp_target(TranslationBlock *tb,
|
||||
int n, unsigned long addr)
|
||||
{
|
||||
uint32_t val, *ptr;
|
||||
unsigned long offset;
|
||||
|
||||
offset = (unsigned long)(tb->tc_ptr + tb->tb_jmp_offset[n]);
|
||||
|
||||
/* patch the branch destination */
|
||||
ptr = (uint32_t *)offset;
|
||||
val = *ptr;
|
||||
val = (val & ~0x03fffffc) | ((addr - offset) & 0x03fffffc);
|
||||
*ptr = val;
|
||||
/* flush icache */
|
||||
asm volatile ("dcbst 0,%0" : : "r"(ptr) : "memory");
|
||||
asm volatile ("sync" : : : "memory");
|
||||
asm volatile ("icbi 0,%0" : : "r"(ptr) : "memory");
|
||||
asm volatile ("sync" : : : "memory");
|
||||
asm volatile ("isync" : : : "memory");
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
/* set the jump target */
|
||||
static inline void tb_set_jmp_target(TranslationBlock *tb,
|
||||
int n, unsigned long addr)
|
||||
{
|
||||
tb->tb_next[n] = addr;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static inline void tb_add_jump(TranslationBlock *tb, int n,
|
||||
TranslationBlock *tb_next)
|
||||
{
|
||||
/* NOTE: this test is only needed for thread safety */
|
||||
if (!tb->jmp_next[n]) {
|
||||
/* patch the native jump address */
|
||||
tb_set_jmp_target(tb, n, (unsigned long)tb_next->tc_ptr);
|
||||
|
||||
/* add in TB jmp circular list */
|
||||
tb->jmp_next[n] = tb_next->jmp_first;
|
||||
tb_next->jmp_first = (TranslationBlock *)((long)(tb) | (n));
|
||||
}
|
||||
}
|
||||
|
||||
TranslationBlock *tb_find_pc(unsigned long pc_ptr);
|
||||
|
||||
#ifndef offsetof
|
||||
#define offsetof(type, field) ((size_t) &((type *)0)->field)
|
||||
#endif
|
||||
|
||||
#if defined(__powerpc__)
|
||||
|
||||
/* on PowerPC we patch the jump instruction directly */
|
||||
#define JUMP_TB(tbparam, n, eip)\
|
||||
do {\
|
||||
static void __attribute__((unused)) *__op_label ## n = &&label ## n;\
|
||||
asm volatile ("b %0" : : "i" (&__op_jmp ## n));\
|
||||
label ## n:\
|
||||
T0 = (long)(tbparam) + (n);\
|
||||
EIP = eip;\
|
||||
} while (0)
|
||||
|
||||
#else
|
||||
|
||||
/* jump to next block operations (more portable code, does not need
|
||||
cache flushing, but slower because of indirect jump) */
|
||||
#define JUMP_TB(tbparam, n, eip)\
|
||||
do {\
|
||||
static void __attribute__((unused)) *__op_label ## n = &&label ## n;\
|
||||
static void __attribute__((unused)) *dummy ## n = &&dummy_label ## n;\
|
||||
goto *(void *)(((TranslationBlock *)tbparam)->tb_next[n]);\
|
||||
label ## n:\
|
||||
T0 = (long)(tbparam) + (n);\
|
||||
EIP = eip;\
|
||||
dummy_label ## n:\
|
||||
EXIT_TB();\
|
||||
} while (0)
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __powerpc__
|
||||
static inline int testandset (int *p)
|
||||
{
|
||||
int ret;
|
||||
__asm__ __volatile__ (
|
||||
"0: lwarx %0,0,%1 ;"
|
||||
" xor. %0,%3,%0;"
|
||||
" bne 1f;"
|
||||
" stwcx. %2,0,%1;"
|
||||
" bne- 0b;"
|
||||
"1: "
|
||||
: "=&r" (ret)
|
||||
: "r" (p), "r" (1), "r" (0)
|
||||
: "cr0", "memory");
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __i386__
|
||||
static inline int testandset (int *p)
|
||||
{
|
||||
char ret;
|
||||
long int readval;
|
||||
|
||||
__asm__ __volatile__ ("lock; cmpxchgl %3, %1; sete %0"
|
||||
: "=q" (ret), "=m" (*p), "=a" (readval)
|
||||
: "r" (1), "m" (*p), "a" (0)
|
||||
: "memory");
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __s390__
|
||||
static inline int testandset (int *p)
|
||||
{
|
||||
int ret;
|
||||
|
||||
__asm__ __volatile__ ("0: cs %0,%1,0(%2)\n"
|
||||
" jl 0b"
|
||||
: "=&d" (ret)
|
||||
: "r" (1), "a" (p), "0" (*p)
|
||||
: "cc", "memory" );
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __alpha__
|
||||
static inline int testandset (int *p)
|
||||
{
|
||||
int ret;
|
||||
unsigned long one;
|
||||
|
||||
__asm__ __volatile__ ("0: mov 1,%2\n"
|
||||
" ldl_l %0,%1\n"
|
||||
" stl_c %2,%1\n"
|
||||
" beq %2,1f\n"
|
||||
".subsection 2\n"
|
||||
"1: br 0b\n"
|
||||
".previous"
|
||||
: "=r" (ret), "=m" (*p), "=r" (one)
|
||||
: "m" (*p));
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __sparc__
|
||||
static inline int testandset (int *p)
|
||||
{
|
||||
int ret;
|
||||
|
||||
__asm__ __volatile__("ldstub [%1], %0"
|
||||
: "=r" (ret)
|
||||
: "r" (p)
|
||||
: "memory");
|
||||
|
||||
return (ret ? 1 : 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __arm__
|
||||
static inline int testandset (int *spinlock)
|
||||
{
|
||||
register unsigned int ret;
|
||||
__asm__ __volatile__("swp %0, %1, [%2]"
|
||||
: "=r"(ret)
|
||||
: "0"(1), "r"(spinlock));
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
typedef int spinlock_t;
|
||||
|
||||
#define SPIN_LOCK_UNLOCKED 0
|
||||
|
||||
#if 1
|
||||
static inline void spin_lock(spinlock_t *lock)
|
||||
{
|
||||
while (testandset(lock));
|
||||
}
|
||||
|
||||
static inline void spin_unlock(spinlock_t *lock)
|
||||
{
|
||||
*lock = 0;
|
||||
}
|
||||
|
||||
static inline int spin_trylock(spinlock_t *lock)
|
||||
{
|
||||
return !testandset(lock);
|
||||
}
|
||||
#else
|
||||
static inline void spin_lock(spinlock_t *lock)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void spin_unlock(spinlock_t *lock)
|
||||
{
|
||||
}
|
||||
|
||||
static inline int spin_trylock(spinlock_t *lock)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
extern spinlock_t tb_lock;
|
||||
|
||||
@@ -17,86 +17,39 @@
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include "vl.h"
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include "config.h"
|
||||
#ifdef TARGET_I386
|
||||
#include "cpu-i386.h"
|
||||
#endif
|
||||
#ifdef TARGET_ARM
|
||||
#include "cpu-arm.h"
|
||||
#endif
|
||||
#include "thunk.h"
|
||||
#include "exec.h"
|
||||
|
||||
//#define DEBUG_GDB
|
||||
|
||||
int gdbstub_fd = -1;
|
||||
enum RSState {
|
||||
RS_IDLE,
|
||||
RS_GETLINE,
|
||||
RS_CHKSUM1,
|
||||
RS_CHKSUM2,
|
||||
};
|
||||
|
||||
/* return 0 if OK */
|
||||
static int gdbstub_open(int port)
|
||||
{
|
||||
struct sockaddr_in sockaddr;
|
||||
socklen_t len;
|
||||
int fd, val, ret;
|
||||
static int gdbserver_fd;
|
||||
|
||||
fd = socket(PF_INET, SOCK_STREAM, 0);
|
||||
if (fd < 0) {
|
||||
perror("socket");
|
||||
return -1;
|
||||
}
|
||||
typedef struct GDBState {
|
||||
enum RSState state;
|
||||
int fd;
|
||||
char line_buf[4096];
|
||||
int line_buf_index;
|
||||
int line_csum;
|
||||
} GDBState;
|
||||
|
||||
/* allow fast reuse */
|
||||
val = 1;
|
||||
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
|
||||
|
||||
sockaddr.sin_family = AF_INET;
|
||||
sockaddr.sin_port = htons(port);
|
||||
sockaddr.sin_addr.s_addr = 0;
|
||||
ret = bind(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr));
|
||||
if (ret < 0) {
|
||||
perror("bind");
|
||||
return -1;
|
||||
}
|
||||
ret = listen(fd, 0);
|
||||
if (ret < 0) {
|
||||
perror("listen");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* now wait for one connection */
|
||||
for(;;) {
|
||||
len = sizeof(sockaddr);
|
||||
gdbstub_fd = accept(fd, (struct sockaddr *)&sockaddr, &len);
|
||||
if (gdbstub_fd < 0 && errno != EINTR) {
|
||||
perror("accept");
|
||||
return -1;
|
||||
} else if (gdbstub_fd >= 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* set short latency */
|
||||
val = 1;
|
||||
setsockopt(gdbstub_fd, SOL_TCP, TCP_NODELAY, &val, sizeof(val));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_char(void)
|
||||
static int get_char(GDBState *s)
|
||||
{
|
||||
uint8_t ch;
|
||||
int ret;
|
||||
|
||||
for(;;) {
|
||||
ret = read(gdbstub_fd, &ch, 1);
|
||||
ret = read(s->fd, &ch, 1);
|
||||
if (ret < 0) {
|
||||
if (errno != EINTR && errno != EAGAIN)
|
||||
return -1;
|
||||
@@ -109,12 +62,12 @@ static int get_char(void)
|
||||
return ch;
|
||||
}
|
||||
|
||||
static void put_buffer(const uint8_t *buf, int len)
|
||||
static void put_buffer(GDBState *s, const uint8_t *buf, int len)
|
||||
{
|
||||
int ret;
|
||||
|
||||
while (len > 0) {
|
||||
ret = write(gdbstub_fd, buf, len);
|
||||
ret = write(s->fd, buf, len);
|
||||
if (ret < 0) {
|
||||
if (errno != EINTR && errno != EAGAIN)
|
||||
return;
|
||||
@@ -168,59 +121,8 @@ static void hextomem(uint8_t *mem, const char *buf, int len)
|
||||
}
|
||||
}
|
||||
|
||||
/* return -1 if error or EOF */
|
||||
static int get_packet(char *buf, int buf_size)
|
||||
{
|
||||
int ch, len, csum, csum1;
|
||||
char reply[1];
|
||||
|
||||
for(;;) {
|
||||
for(;;) {
|
||||
ch = get_char();
|
||||
if (ch < 0)
|
||||
return -1;
|
||||
if (ch == '$')
|
||||
break;
|
||||
}
|
||||
len = 0;
|
||||
csum = 0;
|
||||
for(;;) {
|
||||
ch = get_char();
|
||||
if (ch < 0)
|
||||
return -1;
|
||||
if (ch == '#')
|
||||
break;
|
||||
if (len > buf_size - 1)
|
||||
return -1;
|
||||
buf[len++] = ch;
|
||||
csum += ch;
|
||||
}
|
||||
buf[len] = '\0';
|
||||
ch = get_char();
|
||||
if (ch < 0)
|
||||
return -1;
|
||||
csum1 = fromhex(ch) << 4;
|
||||
ch = get_char();
|
||||
if (ch < 0)
|
||||
return -1;
|
||||
csum1 |= fromhex(ch);
|
||||
if ((csum & 0xff) != csum1) {
|
||||
reply[0] = '-';
|
||||
put_buffer(reply, 1);
|
||||
} else {
|
||||
reply[0] = '+';
|
||||
put_buffer(reply, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
#ifdef DEBUG_GDB
|
||||
printf("command='%s'\n", buf);
|
||||
#endif
|
||||
return len;
|
||||
}
|
||||
|
||||
/* return -1 if error, 0 if OK */
|
||||
static int put_packet(char *buf)
|
||||
static int put_packet(GDBState *s, char *buf)
|
||||
{
|
||||
char buf1[3];
|
||||
int len, csum, ch, i;
|
||||
@@ -231,9 +133,9 @@ static int put_packet(char *buf)
|
||||
|
||||
for(;;) {
|
||||
buf1[0] = '$';
|
||||
put_buffer(buf1, 1);
|
||||
put_buffer(s, buf1, 1);
|
||||
len = strlen(buf);
|
||||
put_buffer(buf, len);
|
||||
put_buffer(s, buf, len);
|
||||
csum = 0;
|
||||
for(i = 0; i < len; i++) {
|
||||
csum += buf[i];
|
||||
@@ -242,9 +144,9 @@ static int put_packet(char *buf)
|
||||
buf1[1] = tohex((csum >> 4) & 0xf);
|
||||
buf1[2] = tohex((csum) & 0xf);
|
||||
|
||||
put_buffer(buf1, 3);
|
||||
put_buffer(s, buf1, 3);
|
||||
|
||||
ch = get_char();
|
||||
ch = get_char(s);
|
||||
if (ch < 0)
|
||||
return -1;
|
||||
if (ch == '+')
|
||||
@@ -253,97 +155,58 @@ static int put_packet(char *buf)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int memory_rw(uint8_t *buf, uint32_t addr, int len, int is_write)
|
||||
{
|
||||
int l, flags;
|
||||
uint32_t page;
|
||||
#if defined(TARGET_I386)
|
||||
|
||||
while (len > 0) {
|
||||
page = addr & TARGET_PAGE_MASK;
|
||||
l = (page + TARGET_PAGE_SIZE) - addr;
|
||||
if (l > len)
|
||||
l = len;
|
||||
flags = page_get_flags(page);
|
||||
if (!(flags & PAGE_VALID))
|
||||
return -1;
|
||||
if (is_write) {
|
||||
if (!(flags & PAGE_WRITE))
|
||||
return -1;
|
||||
memcpy((uint8_t *)addr, buf, l);
|
||||
} else {
|
||||
if (!(flags & PAGE_READ))
|
||||
return -1;
|
||||
memcpy(buf, (uint8_t *)addr, l);
|
||||
}
|
||||
len -= l;
|
||||
buf += l;
|
||||
addr += l;
|
||||
}
|
||||
return 0;
|
||||
static void to_le32(uint8_t *p, int v)
|
||||
{
|
||||
p[0] = v;
|
||||
p[1] = v >> 8;
|
||||
p[2] = v >> 16;
|
||||
p[3] = v >> 24;
|
||||
}
|
||||
|
||||
/* port = 0 means default port */
|
||||
int cpu_gdbstub(void *opaque, void (*main_loop)(void *opaque), int port)
|
||||
static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf)
|
||||
{
|
||||
CPUState *env;
|
||||
const char *p;
|
||||
int ret, ch, nb_regs, i;
|
||||
char buf[4096];
|
||||
uint8_t mem_buf[2000];
|
||||
uint32_t *registers;
|
||||
uint32_t addr, len;
|
||||
|
||||
printf("Waiting gdb connection on port %d\n", port);
|
||||
if (gdbstub_open(port) < 0)
|
||||
return -1;
|
||||
printf("Connected\n");
|
||||
for(;;) {
|
||||
ret = get_packet(buf, sizeof(buf));
|
||||
if (ret < 0)
|
||||
break;
|
||||
p = buf;
|
||||
ch = *p++;
|
||||
switch(ch) {
|
||||
case '?':
|
||||
snprintf(buf, sizeof(buf), "S%02x", SIGTRAP);
|
||||
put_packet(buf);
|
||||
break;
|
||||
case 'c':
|
||||
main_loop(opaque);
|
||||
snprintf(buf, sizeof(buf), "S%02x", 0);
|
||||
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];
|
||||
int i, fpus;
|
||||
|
||||
for(i = 0; i < 8; i++) {
|
||||
to_le32(mem_buf + i * 4, env->regs[i]);
|
||||
}
|
||||
to_le32(mem_buf + 8 * 4, env->eip);
|
||||
to_le32(mem_buf + 9 * 4, env->eflags);
|
||||
to_le32(mem_buf + 10 * 4, env->segs[R_CS].selector);
|
||||
to_le32(mem_buf + 11 * 4, env->segs[R_SS].selector);
|
||||
to_le32(mem_buf + 12 * 4, env->segs[R_DS].selector);
|
||||
to_le32(mem_buf + 13 * 4, env->segs[R_ES].selector);
|
||||
to_le32(mem_buf + 14 * 4, env->segs[R_FS].selector);
|
||||
to_le32(mem_buf + 15 * 4, env->segs[R_GS].selector);
|
||||
/* XXX: convert floats */
|
||||
for(i = 0; i < 8; i++) {
|
||||
memcpy(mem_buf + 16 * 4 + i * 10, &env->fpregs[i], 10);
|
||||
}
|
||||
to_le32(mem_buf + 36 * 4, env->fpuc);
|
||||
fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
|
||||
to_le32(mem_buf + 37 * 4, fpus);
|
||||
to_le32(mem_buf + 38 * 4, 0); /* XXX: convert tags */
|
||||
to_le32(mem_buf + 39 * 4, 0); /* fiseg */
|
||||
to_le32(mem_buf + 40 * 4, 0); /* fioff */
|
||||
to_le32(mem_buf + 41 * 4, 0); /* foseg */
|
||||
to_le32(mem_buf + 42 * 4, 0); /* fooff */
|
||||
to_le32(mem_buf + 43 * 4, 0); /* fop */
|
||||
return 44 * 4;
|
||||
}
|
||||
|
||||
static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size)
|
||||
{
|
||||
uint32_t *registers = (uint32_t *)mem_buf;
|
||||
int i;
|
||||
|
||||
for(i = 0; i < 8; i++) {
|
||||
env->regs[i] = tswapl(registers[i]);
|
||||
}
|
||||
env->eip = registers[8];
|
||||
env->eflags = registers[9];
|
||||
#if defined(CONFIG_USER_ONLY)
|
||||
#define LOAD_SEG(index, sreg)\
|
||||
if (tswapl(registers[index]) != env->segs[sreg].selector)\
|
||||
cpu_x86_load_seg(env, sreg, tswapl(registers[index]));
|
||||
@@ -354,37 +217,379 @@ int cpu_gdbstub(void *opaque, void (*main_loop)(void *opaque), int port)
|
||||
LOAD_SEG(14, R_FS);
|
||||
LOAD_SEG(15, R_GS);
|
||||
#endif
|
||||
put_packet("OK");
|
||||
break;
|
||||
case 'm':
|
||||
}
|
||||
|
||||
#elif defined (TARGET_PPC)
|
||||
static 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);
|
||||
if (*p == ',')
|
||||
p++;
|
||||
len = strtoul(p, NULL, 16);
|
||||
if (memory_rw(mem_buf, addr, len, 0) != 0)
|
||||
memset(mem_buf, 0, len);
|
||||
memtohex(buf, mem_buf, len);
|
||||
put_packet(buf);
|
||||
break;
|
||||
case 'M':
|
||||
#if defined(TARGET_I386)
|
||||
env->eip = addr;
|
||||
#elif defined (TARGET_PPC)
|
||||
env->nip = addr;
|
||||
#endif
|
||||
}
|
||||
vm_start();
|
||||
break;
|
||||
case 's':
|
||||
if (*p != '\0') {
|
||||
addr = strtoul(p, (char **)&p, 16);
|
||||
if (*p == ',')
|
||||
p++;
|
||||
len = strtoul(p, (char **)&p, 16);
|
||||
if (*p == ',')
|
||||
p++;
|
||||
hextomem(mem_buf, p, len);
|
||||
if (memory_rw(mem_buf, addr, len, 1) != 0)
|
||||
put_packet("ENN");
|
||||
else
|
||||
put_packet("OK");
|
||||
#if defined(TARGET_I386)
|
||||
env->eip = addr;
|
||||
#elif defined (TARGET_PPC)
|
||||
env->nip = addr;
|
||||
#endif
|
||||
}
|
||||
cpu_single_step(env, 1);
|
||||
vm_start();
|
||||
break;
|
||||
case 'g':
|
||||
reg_size = cpu_gdb_read_registers(env, mem_buf);
|
||||
memtohex(buf, mem_buf, reg_size);
|
||||
put_packet(s, buf);
|
||||
break;
|
||||
case 'G':
|
||||
registers = (void *)mem_buf;
|
||||
len = strlen(p) / 2;
|
||||
hextomem((uint8_t *)registers, p, len);
|
||||
cpu_gdb_write_registers(env, mem_buf, len);
|
||||
put_packet(s, "OK");
|
||||
break;
|
||||
case 'm':
|
||||
addr = strtoul(p, (char **)&p, 16);
|
||||
if (*p == ',')
|
||||
p++;
|
||||
len = strtoul(p, NULL, 16);
|
||||
if (cpu_memory_rw_debug(env, addr, mem_buf, len, 0) != 0)
|
||||
memset(mem_buf, 0, len);
|
||||
memtohex(buf, mem_buf, len);
|
||||
put_packet(s, buf);
|
||||
break;
|
||||
case 'M':
|
||||
addr = strtoul(p, (char **)&p, 16);
|
||||
if (*p == ',')
|
||||
p++;
|
||||
len = strtoul(p, (char **)&p, 16);
|
||||
if (*p == ',')
|
||||
p++;
|
||||
hextomem(mem_buf, p, len);
|
||||
if (cpu_memory_rw_debug(env, addr, mem_buf, len, 1) != 0)
|
||||
put_packet(s, "ENN");
|
||||
else
|
||||
put_packet(s, "OK");
|
||||
break;
|
||||
case 'Z':
|
||||
type = strtoul(p, (char **)&p, 16);
|
||||
if (*p == ',')
|
||||
p++;
|
||||
addr = strtoul(p, (char **)&p, 16);
|
||||
if (*p == ',')
|
||||
p++;
|
||||
len = strtoul(p, (char **)&p, 16);
|
||||
if (type == 0 || type == 1) {
|
||||
if (cpu_breakpoint_insert(env, addr) < 0)
|
||||
goto breakpoint_error;
|
||||
put_packet(s, "OK");
|
||||
} else {
|
||||
breakpoint_error:
|
||||
put_packet(s, "ENN");
|
||||
}
|
||||
break;
|
||||
case 'z':
|
||||
type = strtoul(p, (char **)&p, 16);
|
||||
if (*p == ',')
|
||||
p++;
|
||||
addr = strtoul(p, (char **)&p, 16);
|
||||
if (*p == ',')
|
||||
p++;
|
||||
len = strtoul(p, (char **)&p, 16);
|
||||
if (type == 0 || type == 1) {
|
||||
cpu_breakpoint_remove(env, addr);
|
||||
put_packet(s, "OK");
|
||||
} else {
|
||||
goto breakpoint_error;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// unknown_command:
|
||||
/* put empty packet */
|
||||
buf[0] = '\0';
|
||||
put_packet(s, buf);
|
||||
break;
|
||||
}
|
||||
return RS_IDLE;
|
||||
}
|
||||
|
||||
static void gdb_vm_stopped(void *opaque, int reason)
|
||||
{
|
||||
GDBState *s = opaque;
|
||||
char buf[256];
|
||||
int ret;
|
||||
|
||||
/* disable single step if it was enable */
|
||||
cpu_single_step(cpu_single_env, 0);
|
||||
|
||||
if (reason == EXCP_DEBUG)
|
||||
ret = SIGTRAP;
|
||||
else
|
||||
ret = 0;
|
||||
snprintf(buf, sizeof(buf), "S%02x", ret);
|
||||
put_packet(s, buf);
|
||||
}
|
||||
|
||||
static void gdb_read_byte(GDBState *s, int ch)
|
||||
{
|
||||
int i, csum;
|
||||
char reply[1];
|
||||
|
||||
if (vm_running) {
|
||||
/* when the CPU is running, we cannot do anything except stop
|
||||
it when receiving a char */
|
||||
vm_stop(EXCP_INTERRUPT);
|
||||
} else {
|
||||
switch(s->state) {
|
||||
case RS_IDLE:
|
||||
if (ch == '$') {
|
||||
s->line_buf_index = 0;
|
||||
s->state = RS_GETLINE;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
/* put empty packet */
|
||||
buf[0] = '\0';
|
||||
put_packet(buf);
|
||||
case RS_GETLINE:
|
||||
if (ch == '#') {
|
||||
s->state = RS_CHKSUM1;
|
||||
} else if (s->line_buf_index >= sizeof(s->line_buf) - 1) {
|
||||
s->state = RS_IDLE;
|
||||
} else {
|
||||
s->line_buf[s->line_buf_index++] = ch;
|
||||
}
|
||||
break;
|
||||
case RS_CHKSUM1:
|
||||
s->line_buf[s->line_buf_index] = '\0';
|
||||
s->line_csum = fromhex(ch) << 4;
|
||||
s->state = RS_CHKSUM2;
|
||||
break;
|
||||
case RS_CHKSUM2:
|
||||
s->line_csum |= fromhex(ch);
|
||||
csum = 0;
|
||||
for(i = 0; i < s->line_buf_index; i++) {
|
||||
csum += s->line_buf[i];
|
||||
}
|
||||
if (s->line_csum != (csum & 0xff)) {
|
||||
reply[0] = '-';
|
||||
put_buffer(s, reply, 1);
|
||||
s->state = RS_IDLE;
|
||||
} else {
|
||||
reply[0] = '+';
|
||||
put_buffer(s, reply, 1);
|
||||
s->state = gdb_handle_packet(s, s->line_buf);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int gdb_can_read(void *opaque)
|
||||
{
|
||||
return 256;
|
||||
}
|
||||
|
||||
static void gdb_read(void *opaque, const uint8_t *buf, int size)
|
||||
{
|
||||
GDBState *s = opaque;
|
||||
int i;
|
||||
if (size == 0) {
|
||||
/* end of connection */
|
||||
qemu_del_vm_stop_handler(gdb_vm_stopped, s);
|
||||
qemu_del_fd_read_handler(s->fd);
|
||||
qemu_free(s);
|
||||
vm_start();
|
||||
} else {
|
||||
for(i = 0; i < size; i++)
|
||||
gdb_read_byte(s, buf[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static void gdb_accept(void *opaque, const uint8_t *buf, int size)
|
||||
{
|
||||
GDBState *s;
|
||||
struct sockaddr_in sockaddr;
|
||||
socklen_t len;
|
||||
int val, fd;
|
||||
|
||||
for(;;) {
|
||||
len = sizeof(sockaddr);
|
||||
fd = accept(gdbserver_fd, (struct sockaddr *)&sockaddr, &len);
|
||||
if (fd < 0 && errno != EINTR) {
|
||||
perror("accept");
|
||||
return;
|
||||
} else if (fd >= 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* set short latency */
|
||||
val = 1;
|
||||
setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val));
|
||||
|
||||
s = qemu_mallocz(sizeof(GDBState));
|
||||
if (!s) {
|
||||
close(fd);
|
||||
return;
|
||||
}
|
||||
s->fd = fd;
|
||||
|
||||
fcntl(fd, F_SETFL, O_NONBLOCK);
|
||||
|
||||
/* stop the VM */
|
||||
vm_stop(EXCP_INTERRUPT);
|
||||
|
||||
/* start handling I/O */
|
||||
qemu_add_fd_read_handler(s->fd, gdb_can_read, gdb_read, s);
|
||||
/* when the VM is stopped, the following callback is called */
|
||||
qemu_add_vm_stop_handler(gdb_vm_stopped, s);
|
||||
}
|
||||
|
||||
static int gdbserver_open(int port)
|
||||
{
|
||||
struct sockaddr_in sockaddr;
|
||||
int fd, val, ret;
|
||||
|
||||
fd = socket(PF_INET, SOCK_STREAM, 0);
|
||||
if (fd < 0) {
|
||||
perror("socket");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* allow fast reuse */
|
||||
val = 1;
|
||||
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
|
||||
|
||||
sockaddr.sin_family = AF_INET;
|
||||
sockaddr.sin_port = htons(port);
|
||||
sockaddr.sin_addr.s_addr = 0;
|
||||
ret = bind(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr));
|
||||
if (ret < 0) {
|
||||
perror("bind");
|
||||
return -1;
|
||||
}
|
||||
ret = listen(fd, 0);
|
||||
if (ret < 0) {
|
||||
perror("listen");
|
||||
return -1;
|
||||
}
|
||||
fcntl(fd, F_SETFL, O_NONBLOCK);
|
||||
return fd;
|
||||
}
|
||||
|
||||
int gdbserver_start(int port)
|
||||
{
|
||||
gdbserver_fd = gdbserver_open(port);
|
||||
if (gdbserver_fd < 0)
|
||||
return -1;
|
||||
/* accept connections */
|
||||
qemu_add_fd_read_handler(gdbserver_fd, NULL, gdb_accept, NULL);
|
||||
return 0;
|
||||
}
|
||||
-1471
File diff suppressed because it is too large.
Load diff
@@ -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];
|
||||
@@ -0,0 +1,520 @@
|
||||
/*
|
||||
* QEMU VGA Emulator templates
|
||||
*
|
||||
* Copyright (c) 2003 Fabrice Bellard
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#if DEPTH == 8
|
||||
#define BPP 1
|
||||
#define PIXEL_TYPE uint8_t
|
||||
#elif DEPTH == 15 || DEPTH == 16
|
||||
#define BPP 2
|
||||
#define PIXEL_TYPE uint16_t
|
||||
#elif DEPTH == 32
|
||||
#define BPP 4
|
||||
#define PIXEL_TYPE uint32_t
|
||||
#else
|
||||
#error unsupport depth
|
||||
#endif
|
||||
|
||||
#if DEPTH != 15
|
||||
|
||||
static inline void glue(vga_draw_glyph_line_, DEPTH)(uint8_t *d,
|
||||
uint32_t font_data,
|
||||
uint32_t xorcol,
|
||||
uint32_t bgcol)
|
||||
{
|
||||
#if BPP == 1
|
||||
((uint32_t *)d)[0] = (dmask16[(font_data >> 4)] & xorcol) ^ bgcol;
|
||||
((uint32_t *)d)[3] = (dmask16[(font_data >> 0) & 0xf] & xorcol) ^ bgcol;
|
||||
#elif BPP == 2
|
||||
((uint32_t *)d)[0] = (dmask4[(font_data >> 6)] & xorcol) ^ bgcol;
|
||||
((uint32_t *)d)[1] = (dmask4[(font_data >> 4) & 3] & xorcol) ^ bgcol;
|
||||
((uint32_t *)d)[2] = (dmask4[(font_data >> 2) & 3] & xorcol) ^ bgcol;
|
||||
((uint32_t *)d)[3] = (dmask4[(font_data >> 0) & 3] & xorcol) ^ bgcol;
|
||||
#else
|
||||
((uint32_t *)d)[0] = (-((font_data >> 7)) & xorcol) ^ bgcol;
|
||||
((uint32_t *)d)[1] = (-((font_data >> 6) & 1) & xorcol) ^ bgcol;
|
||||
((uint32_t *)d)[2] = (-((font_data >> 5) & 1) & xorcol) ^ bgcol;
|
||||
((uint32_t *)d)[3] = (-((font_data >> 4) & 1) & xorcol) ^ bgcol;
|
||||
((uint32_t *)d)[4] = (-((font_data >> 3) & 1) & xorcol) ^ bgcol;
|
||||
((uint32_t *)d)[5] = (-((font_data >> 2) & 1) & xorcol) ^ bgcol;
|
||||
((uint32_t *)d)[6] = (-((font_data >> 1) & 1) & xorcol) ^ bgcol;
|
||||
((uint32_t *)d)[7] = (-((font_data >> 0) & 1) & xorcol) ^ bgcol;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void glue(vga_draw_glyph8_, DEPTH)(uint8_t *d, int linesize,
|
||||
const uint8_t *font_ptr, int h,
|
||||
uint32_t fgcol, uint32_t bgcol)
|
||||
{
|
||||
uint32_t font_data, xorcol;
|
||||
|
||||
xorcol = bgcol ^ fgcol;
|
||||
do {
|
||||
font_data = font_ptr[0];
|
||||
glue(vga_draw_glyph_line_, DEPTH)(d, font_data, xorcol, bgcol);
|
||||
font_ptr += 4;
|
||||
d += linesize;
|
||||
} while (--h);
|
||||
}
|
||||
|
||||
static void glue(vga_draw_glyph16_, DEPTH)(uint8_t *d, int linesize,
|
||||
const uint8_t *font_ptr, int h,
|
||||
uint32_t fgcol, uint32_t bgcol)
|
||||
{
|
||||
uint32_t font_data, xorcol;
|
||||
|
||||
xorcol = bgcol ^ fgcol;
|
||||
do {
|
||||
font_data = font_ptr[0];
|
||||
glue(vga_draw_glyph_line_, DEPTH)(d,
|
||||
expand4to8[font_data >> 4],
|
||||
xorcol, bgcol);
|
||||
glue(vga_draw_glyph_line_, DEPTH)(d + 8 * BPP,
|
||||
expand4to8[font_data & 0x0f],
|
||||
xorcol, bgcol);
|
||||
font_ptr += 4;
|
||||
d += linesize;
|
||||
} while (--h);
|
||||
}
|
||||
|
||||
static void glue(vga_draw_glyph9_, DEPTH)(uint8_t *d, int linesize,
|
||||
const uint8_t *font_ptr, int h,
|
||||
uint32_t fgcol, uint32_t bgcol, int dup9)
|
||||
{
|
||||
uint32_t font_data, xorcol, v;
|
||||
|
||||
xorcol = bgcol ^ fgcol;
|
||||
do {
|
||||
font_data = font_ptr[0];
|
||||
/* XXX: unaligned accesses are done */
|
||||
#if BPP == 1
|
||||
((uint32_t *)d)[0] = (dmask16[(font_data >> 4)] & xorcol) ^ bgcol;
|
||||
v = (dmask16[(font_data >> 0) & 0xf] & xorcol) ^ bgcol;
|
||||
((uint32_t *)d)[3] = v;
|
||||
if (dup9)
|
||||
((uint8_t *)d)[8] = v >> (24 * (1 - BIG));
|
||||
else
|
||||
((uint8_t *)d)[8] = bgcol;
|
||||
|
||||
#elif BPP == 2
|
||||
((uint32_t *)d)[0] = (dmask4[(font_data >> 6)] & xorcol) ^ bgcol;
|
||||
((uint32_t *)d)[1] = (dmask4[(font_data >> 4) & 3] & xorcol) ^ bgcol;
|
||||
((uint32_t *)d)[2] = (dmask4[(font_data >> 2) & 3] & xorcol) ^ bgcol;
|
||||
v = (dmask4[(font_data >> 0) & 3] & xorcol) ^ bgcol;
|
||||
((uint32_t *)d)[3] = v;
|
||||
if (dup9)
|
||||
((uint16_t *)d)[8] = v >> (16 * (1 - BIG));
|
||||
else
|
||||
((uint16_t *)d)[8] = bgcol;
|
||||
#else
|
||||
((uint32_t *)d)[0] = (-((font_data >> 7)) & xorcol) ^ bgcol;
|
||||
((uint32_t *)d)[1] = (-((font_data >> 6) & 1) & xorcol) ^ bgcol;
|
||||
((uint32_t *)d)[2] = (-((font_data >> 5) & 1) & xorcol) ^ bgcol;
|
||||
((uint32_t *)d)[3] = (-((font_data >> 4) & 1) & xorcol) ^ bgcol;
|
||||
((uint32_t *)d)[4] = (-((font_data >> 3) & 1) & xorcol) ^ bgcol;
|
||||
((uint32_t *)d)[5] = (-((font_data >> 2) & 1) & xorcol) ^ bgcol;
|
||||
((uint32_t *)d)[6] = (-((font_data >> 1) & 1) & xorcol) ^ bgcol;
|
||||
v = (-((font_data >> 0) & 1) & xorcol) ^ bgcol;
|
||||
((uint32_t *)d)[7] = v;
|
||||
if (dup9)
|
||||
((uint32_t *)d)[8] = v;
|
||||
else
|
||||
((uint32_t *)d)[8] = bgcol;
|
||||
#endif
|
||||
font_ptr += 4;
|
||||
d += linesize;
|
||||
} while (--h);
|
||||
}
|
||||
|
||||
/*
|
||||
* 4 color mode
|
||||
*/
|
||||
static void glue(vga_draw_line2_, DEPTH)(VGAState *s1, uint8_t *d,
|
||||
const uint8_t *s, int width)
|
||||
{
|
||||
uint32_t plane_mask, *palette, data, v;
|
||||
int x;
|
||||
|
||||
palette = s1->last_palette;
|
||||
plane_mask = mask16[s1->ar[0x12] & 0xf];
|
||||
width >>= 3;
|
||||
for(x = 0; x < width; x++) {
|
||||
data = ((uint32_t *)s)[0];
|
||||
data &= plane_mask;
|
||||
v = expand2[GET_PLANE(data, 0)];
|
||||
v |= expand2[GET_PLANE(data, 2)] << 2;
|
||||
((PIXEL_TYPE *)d)[0] = palette[v >> 12];
|
||||
((PIXEL_TYPE *)d)[1] = palette[(v >> 8) & 0xf];
|
||||
((PIXEL_TYPE *)d)[2] = palette[(v >> 4) & 0xf];
|
||||
((PIXEL_TYPE *)d)[3] = palette[(v >> 0) & 0xf];
|
||||
|
||||
v = expand2[GET_PLANE(data, 1)];
|
||||
v |= expand2[GET_PLANE(data, 3)] << 2;
|
||||
((PIXEL_TYPE *)d)[4] = palette[v >> 12];
|
||||
((PIXEL_TYPE *)d)[5] = palette[(v >> 8) & 0xf];
|
||||
((PIXEL_TYPE *)d)[6] = palette[(v >> 4) & 0xf];
|
||||
((PIXEL_TYPE *)d)[7] = palette[(v >> 0) & 0xf];
|
||||
d += BPP * 8;
|
||||
s += 4;
|
||||
}
|
||||
}
|
||||
|
||||
#if BPP == 1
|
||||
#define PUT_PIXEL2(d, n, v) ((uint16_t *)d)[(n)] = (v)
|
||||
#elif BPP == 2
|
||||
#define PUT_PIXEL2(d, n, v) ((uint32_t *)d)[(n)] = (v)
|
||||
#else
|
||||
#define PUT_PIXEL2(d, n, v) \
|
||||
((uint32_t *)d)[2*(n)] = ((uint32_t *)d)[2*(n)+1] = (v)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* 4 color mode, dup2 horizontal
|
||||
*/
|
||||
static void glue(vga_draw_line2d2_, DEPTH)(VGAState *s1, uint8_t *d,
|
||||
const uint8_t *s, int width)
|
||||
{
|
||||
uint32_t plane_mask, *palette, data, v;
|
||||
int x;
|
||||
|
||||
palette = s1->last_palette;
|
||||
plane_mask = mask16[s1->ar[0x12] & 0xf];
|
||||
width >>= 3;
|
||||
for(x = 0; x < width; x++) {
|
||||
data = ((uint32_t *)s)[0];
|
||||
data &= plane_mask;
|
||||
v = expand2[GET_PLANE(data, 0)];
|
||||
v |= expand2[GET_PLANE(data, 2)] << 2;
|
||||
PUT_PIXEL2(d, 0, palette[v >> 12]);
|
||||
PUT_PIXEL2(d, 1, palette[(v >> 8) & 0xf]);
|
||||
PUT_PIXEL2(d, 2, palette[(v >> 4) & 0xf]);
|
||||
PUT_PIXEL2(d, 3, palette[(v >> 0) & 0xf]);
|
||||
|
||||
v = expand2[GET_PLANE(data, 1)];
|
||||
v |= expand2[GET_PLANE(data, 3)] << 2;
|
||||
PUT_PIXEL2(d, 4, palette[v >> 12]);
|
||||
PUT_PIXEL2(d, 5, palette[(v >> 8) & 0xf]);
|
||||
PUT_PIXEL2(d, 6, palette[(v >> 4) & 0xf]);
|
||||
PUT_PIXEL2(d, 7, palette[(v >> 0) & 0xf]);
|
||||
d += BPP * 16;
|
||||
s += 4;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 16 color mode
|
||||
*/
|
||||
static void glue(vga_draw_line4_, DEPTH)(VGAState *s1, uint8_t *d,
|
||||
const uint8_t *s, int width)
|
||||
{
|
||||
uint32_t plane_mask, data, v, *palette;
|
||||
int x;
|
||||
|
||||
palette = s1->last_palette;
|
||||
plane_mask = mask16[s1->ar[0x12] & 0xf];
|
||||
width >>= 3;
|
||||
for(x = 0; x < width; x++) {
|
||||
data = ((uint32_t *)s)[0];
|
||||
data &= plane_mask;
|
||||
v = expand4[GET_PLANE(data, 0)];
|
||||
v |= expand4[GET_PLANE(data, 1)] << 1;
|
||||
v |= expand4[GET_PLANE(data, 2)] << 2;
|
||||
v |= expand4[GET_PLANE(data, 3)] << 3;
|
||||
((PIXEL_TYPE *)d)[0] = palette[v >> 28];
|
||||
((PIXEL_TYPE *)d)[1] = palette[(v >> 24) & 0xf];
|
||||
((PIXEL_TYPE *)d)[2] = palette[(v >> 20) & 0xf];
|
||||
((PIXEL_TYPE *)d)[3] = palette[(v >> 16) & 0xf];
|
||||
((PIXEL_TYPE *)d)[4] = palette[(v >> 12) & 0xf];
|
||||
((PIXEL_TYPE *)d)[5] = palette[(v >> 8) & 0xf];
|
||||
((PIXEL_TYPE *)d)[6] = palette[(v >> 4) & 0xf];
|
||||
((PIXEL_TYPE *)d)[7] = palette[(v >> 0) & 0xf];
|
||||
d += BPP * 8;
|
||||
s += 4;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 16 color mode, dup2 horizontal
|
||||
*/
|
||||
static void glue(vga_draw_line4d2_, DEPTH)(VGAState *s1, uint8_t *d,
|
||||
const uint8_t *s, int width)
|
||||
{
|
||||
uint32_t plane_mask, data, v, *palette;
|
||||
int x;
|
||||
|
||||
palette = s1->last_palette;
|
||||
plane_mask = mask16[s1->ar[0x12] & 0xf];
|
||||
width >>= 3;
|
||||
for(x = 0; x < width; x++) {
|
||||
data = ((uint32_t *)s)[0];
|
||||
data &= plane_mask;
|
||||
v = expand4[GET_PLANE(data, 0)];
|
||||
v |= expand4[GET_PLANE(data, 1)] << 1;
|
||||
v |= expand4[GET_PLANE(data, 2)] << 2;
|
||||
v |= expand4[GET_PLANE(data, 3)] << 3;
|
||||
PUT_PIXEL2(d, 0, palette[v >> 28]);
|
||||
PUT_PIXEL2(d, 1, palette[(v >> 24) & 0xf]);
|
||||
PUT_PIXEL2(d, 2, palette[(v >> 20) & 0xf]);
|
||||
PUT_PIXEL2(d, 3, palette[(v >> 16) & 0xf]);
|
||||
PUT_PIXEL2(d, 4, palette[(v >> 12) & 0xf]);
|
||||
PUT_PIXEL2(d, 5, palette[(v >> 8) & 0xf]);
|
||||
PUT_PIXEL2(d, 6, palette[(v >> 4) & 0xf]);
|
||||
PUT_PIXEL2(d, 7, palette[(v >> 0) & 0xf]);
|
||||
d += BPP * 16;
|
||||
s += 4;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 256 color mode, double pixels
|
||||
*
|
||||
* XXX: add plane_mask support (never used in standard VGA modes)
|
||||
*/
|
||||
static void glue(vga_draw_line8d2_, DEPTH)(VGAState *s1, uint8_t *d,
|
||||
const uint8_t *s, int width)
|
||||
{
|
||||
uint32_t *palette;
|
||||
int x;
|
||||
|
||||
palette = s1->last_palette;
|
||||
width >>= 3;
|
||||
for(x = 0; x < width; x++) {
|
||||
PUT_PIXEL2(d, 0, palette[s[0]]);
|
||||
PUT_PIXEL2(d, 1, palette[s[1]]);
|
||||
PUT_PIXEL2(d, 2, palette[s[2]]);
|
||||
PUT_PIXEL2(d, 3, palette[s[3]]);
|
||||
d += BPP * 8;
|
||||
s += 4;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* standard 256 color mode
|
||||
*
|
||||
* XXX: add plane_mask support (never used in standard VGA modes)
|
||||
*/
|
||||
static void glue(vga_draw_line8_, DEPTH)(VGAState *s1, uint8_t *d,
|
||||
const uint8_t *s, int width)
|
||||
{
|
||||
uint32_t *palette;
|
||||
int x;
|
||||
|
||||
palette = s1->last_palette;
|
||||
width >>= 3;
|
||||
for(x = 0; x < width; x++) {
|
||||
((PIXEL_TYPE *)d)[0] = palette[s[0]];
|
||||
((PIXEL_TYPE *)d)[1] = palette[s[1]];
|
||||
((PIXEL_TYPE *)d)[2] = palette[s[2]];
|
||||
((PIXEL_TYPE *)d)[3] = palette[s[3]];
|
||||
((PIXEL_TYPE *)d)[4] = palette[s[4]];
|
||||
((PIXEL_TYPE *)d)[5] = palette[s[5]];
|
||||
((PIXEL_TYPE *)d)[6] = palette[s[6]];
|
||||
((PIXEL_TYPE *)d)[7] = palette[s[7]];
|
||||
d += BPP * 8;
|
||||
s += 8;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* DEPTH != 15 */
|
||||
|
||||
|
||||
/* XXX: optimize */
|
||||
|
||||
/*
|
||||
* 15 bit color
|
||||
*/
|
||||
static void glue(vga_draw_line15_, DEPTH)(VGAState *s1, uint8_t *d,
|
||||
const uint8_t *s, int width)
|
||||
{
|
||||
#if DEPTH == 15 && defined(WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN)
|
||||
memcpy(d, s, width * 2);
|
||||
#else
|
||||
int w;
|
||||
uint32_t v, r, g, b;
|
||||
|
||||
w = width;
|
||||
do {
|
||||
v = lduw_raw((void *)s);
|
||||
r = (v >> 7) & 0xf8;
|
||||
g = (v >> 2) & 0xf8;
|
||||
b = (v << 3) & 0xf8;
|
||||
((PIXEL_TYPE *)d)[0] = glue(rgb_to_pixel, DEPTH)(r, g, b);
|
||||
s += 2;
|
||||
d += BPP;
|
||||
} while (--w != 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* 16 bit color
|
||||
*/
|
||||
static void glue(vga_draw_line16_, DEPTH)(VGAState *s1, uint8_t *d,
|
||||
const uint8_t *s, int width)
|
||||
{
|
||||
#if DEPTH == 16 && defined(WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN)
|
||||
memcpy(d, s, width * 2);
|
||||
#else
|
||||
int w;
|
||||
uint32_t v, r, g, b;
|
||||
|
||||
w = width;
|
||||
do {
|
||||
v = lduw_raw((void *)s);
|
||||
r = (v >> 8) & 0xf8;
|
||||
g = (v >> 3) & 0xfc;
|
||||
b = (v << 3) & 0xf8;
|
||||
((PIXEL_TYPE *)d)[0] = glue(rgb_to_pixel, DEPTH)(r, g, b);
|
||||
s += 2;
|
||||
d += BPP;
|
||||
} while (--w != 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* 24 bit color
|
||||
*/
|
||||
static void glue(vga_draw_line24_, DEPTH)(VGAState *s1, uint8_t *d,
|
||||
const uint8_t *s, int width)
|
||||
{
|
||||
int w;
|
||||
uint32_t r, g, b;
|
||||
|
||||
w = width;
|
||||
do {
|
||||
#if defined(TARGET_WORDS_BIGENDIAN)
|
||||
r = s[0];
|
||||
g = s[1];
|
||||
b = s[2];
|
||||
#else
|
||||
b = s[0];
|
||||
g = s[1];
|
||||
r = s[2];
|
||||
#endif
|
||||
((PIXEL_TYPE *)d)[0] = glue(rgb_to_pixel, DEPTH)(r, g, b);
|
||||
s += 3;
|
||||
d += BPP;
|
||||
} while (--w != 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* 32 bit color
|
||||
*/
|
||||
static void glue(vga_draw_line32_, DEPTH)(VGAState *s1, uint8_t *d,
|
||||
const uint8_t *s, int width)
|
||||
{
|
||||
#if DEPTH == 32 && defined(WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN)
|
||||
memcpy(d, s, width * 4);
|
||||
#else
|
||||
int w;
|
||||
uint32_t r, g, b;
|
||||
|
||||
w = width;
|
||||
do {
|
||||
#if defined(TARGET_WORDS_BIGENDIAN)
|
||||
r = s[1];
|
||||
g = s[2];
|
||||
b = s[3];
|
||||
#else
|
||||
b = s[0];
|
||||
g = s[1];
|
||||
r = s[2];
|
||||
#endif
|
||||
((PIXEL_TYPE *)d)[0] = glue(rgb_to_pixel, DEPTH)(r, g, b);
|
||||
s += 4;
|
||||
d += BPP;
|
||||
} while (--w != 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if DEPTH != 15
|
||||
void glue(vga_draw_cursor_line_, DEPTH)(uint8_t *d1,
|
||||
const uint8_t *src1,
|
||||
int poffset, int w,
|
||||
unsigned int color0,
|
||||
unsigned int color1,
|
||||
unsigned int color_xor)
|
||||
{
|
||||
const uint8_t *plane0, *plane1;
|
||||
int x, b0, b1;
|
||||
uint8_t *d;
|
||||
|
||||
d = d1;
|
||||
plane0 = src1;
|
||||
plane1 = src1 + poffset;
|
||||
for(x = 0; x < w; x++) {
|
||||
b0 = (plane0[x >> 3] >> (7 - (x & 7))) & 1;
|
||||
b1 = (plane1[x >> 3] >> (7 - (x & 7))) & 1;
|
||||
#if DEPTH == 8
|
||||
switch(b0 | (b1 << 1)) {
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
d[0] ^= color_xor;
|
||||
break;
|
||||
case 2:
|
||||
d[0] = color0;
|
||||
break;
|
||||
case 3:
|
||||
d[0] = color1;
|
||||
break;
|
||||
}
|
||||
#elif DEPTH == 16
|
||||
switch(b0 | (b1 << 1)) {
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
((uint16_t *)d)[0] ^= color_xor;
|
||||
break;
|
||||
case 2:
|
||||
((uint16_t *)d)[0] = color0;
|
||||
break;
|
||||
case 3:
|
||||
((uint16_t *)d)[0] = color1;
|
||||
break;
|
||||
}
|
||||
#elif DEPTH == 32
|
||||
switch(b0 | (b1 << 1)) {
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
((uint32_t *)d)[0] ^= color_xor;
|
||||
break;
|
||||
case 2:
|
||||
((uint32_t *)d)[0] = color0;
|
||||
break;
|
||||
case 3:
|
||||
((uint32_t *)d)[0] = color1;
|
||||
break;
|
||||
}
|
||||
#else
|
||||
#error unsupported depth
|
||||
#endif
|
||||
d += BPP;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#undef PUT_PIXEL2
|
||||
#undef DEPTH
|
||||
#undef BPP
|
||||
#undef PIXEL_TYPE
|
||||
+3159
-1316
File diff suppressed because it is too large.
Load diff
@@ -53,6 +53,16 @@ SECTIONS
|
||||
_etext = .;
|
||||
PROVIDE (etext = .);
|
||||
.fini : { *(.fini) } =0x47ff041f
|
||||
. = ALIGN(32 / 8);
|
||||
PROVIDE (__preinit_array_start = .);
|
||||
.preinit_array : { *(.preinit_array) }
|
||||
PROVIDE (__preinit_array_end = .);
|
||||
PROVIDE (__init_array_start = .);
|
||||
.init_array : { *(.init_array) }
|
||||
PROVIDE (__init_array_end = .);
|
||||
PROVIDE (__fini_array_start = .);
|
||||
.fini_array : { *(.fini_array) }
|
||||
PROVIDE (__fini_array_end = .);
|
||||
.rodata : { *(.rodata) *(.gnu.linkonce.r*) }
|
||||
.rodata1 : { *(.rodata1) }
|
||||
.reginfo : { *(.reginfo) }
|
||||
|
||||
@@ -0,0 +1,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_SYSCALL_BASE 0x900000
|
||||
|
||||
#define ARM_NR_cacheflush (ARM_SYSCALL_BASE + 0xf0000 + 2)
|
||||
@@ -0,0 +1,261 @@
|
||||
/*
|
||||
* This file contains the system call numbers.
|
||||
*/
|
||||
|
||||
#define TARGET_NR_restart_syscall ( 0)
|
||||
#define TARGET_NR_exit ( 1)
|
||||
#define TARGET_NR_fork ( 2)
|
||||
#define TARGET_NR_read ( 3)
|
||||
#define TARGET_NR_write ( 4)
|
||||
#define TARGET_NR_open ( 5)
|
||||
#define TARGET_NR_close ( 6)
|
||||
#define TARGET_NR_waitpid ( 7) /* removed */
|
||||
#define TARGET_NR_creat ( 8)
|
||||
#define TARGET_NR_link ( 9)
|
||||
#define TARGET_NR_unlink ( 10)
|
||||
#define TARGET_NR_execve ( 11)
|
||||
#define TARGET_NR_chdir ( 12)
|
||||
#define TARGET_NR_time ( 13)
|
||||
#define TARGET_NR_mknod ( 14)
|
||||
#define TARGET_NR_chmod ( 15)
|
||||
#define TARGET_NR_lchown ( 16)
|
||||
#define TARGET_NR_break ( 17) /* removed */
|
||||
/* 18 was sys_stat */
|
||||
#define TARGET_NR_lseek ( 19)
|
||||
#define TARGET_NR_getpid ( 20)
|
||||
#define TARGET_NR_mount ( 21)
|
||||
#define TARGET_NR_umount ( 22)
|
||||
#define TARGET_NR_setuid ( 23)
|
||||
#define TARGET_NR_getuid ( 24)
|
||||
#define TARGET_NR_stime ( 25)
|
||||
#define TARGET_NR_ptrace ( 26)
|
||||
#define TARGET_NR_alarm ( 27)
|
||||
|
||||
#define TARGET_NR_pause ( 29)
|
||||
#define TARGET_NR_utime ( 30)
|
||||
#define TARGET_NR_stty ( 31) /* removed */
|
||||
#define TARGET_NR_gtty ( 32) /* removed */
|
||||
#define TARGET_NR_access ( 33)
|
||||
#define TARGET_NR_nice ( 34)
|
||||
#define TARGET_NR_ftime ( 35) /* removed */
|
||||
#define TARGET_NR_sync ( 36)
|
||||
#define TARGET_NR_kill ( 37)
|
||||
#define TARGET_NR_rename ( 38)
|
||||
#define TARGET_NR_mkdir ( 39)
|
||||
#define TARGET_NR_rmdir ( 40)
|
||||
#define TARGET_NR_dup ( 41)
|
||||
#define TARGET_NR_pipe ( 42)
|
||||
#define TARGET_NR_times ( 43)
|
||||
#define TARGET_NR_prof ( 44) /* removed */
|
||||
#define TARGET_NR_brk ( 45)
|
||||
#define TARGET_NR_setgid ( 46)
|
||||
#define TARGET_NR_getgid ( 47)
|
||||
#define TARGET_NR_signal ( 48) /* removed */
|
||||
#define TARGET_NR_geteuid ( 49)
|
||||
#define TARGET_NR_getegid ( 50)
|
||||
#define TARGET_NR_acct ( 51)
|
||||
#define TARGET_NR_umount2 ( 52)
|
||||
#define TARGET_NR_lock ( 53) /* removed */
|
||||
#define TARGET_NR_ioctl ( 54)
|
||||
#define TARGET_NR_fcntl ( 55)
|
||||
#define TARGET_NR_mpx ( 56) /* removed */
|
||||
#define TARGET_NR_setpgid ( 57)
|
||||
#define TARGET_NR_ulimit ( 58) /* removed */
|
||||
/* 59 was sys_olduname */
|
||||
#define TARGET_NR_umask ( 60)
|
||||
#define TARGET_NR_chroot ( 61)
|
||||
#define TARGET_NR_ustat ( 62)
|
||||
#define TARGET_NR_dup2 ( 63)
|
||||
#define TARGET_NR_getppid ( 64)
|
||||
#define TARGET_NR_getpgrp ( 65)
|
||||
#define TARGET_NR_setsid ( 66)
|
||||
#define TARGET_NR_sigaction ( 67)
|
||||
#define TARGET_NR_sgetmask ( 68) /* removed */
|
||||
#define TARGET_NR_ssetmask ( 69) /* removed */
|
||||
#define TARGET_NR_setreuid ( 70)
|
||||
#define TARGET_NR_setregid ( 71)
|
||||
#define TARGET_NR_sigsuspend ( 72)
|
||||
#define TARGET_NR_sigpending ( 73)
|
||||
#define TARGET_NR_sethostname ( 74)
|
||||
#define TARGET_NR_setrlimit ( 75)
|
||||
#define TARGET_NR_getrlimit ( 76) /* Back compat 2GB limited rlimit */
|
||||
#define TARGET_NR_getrusage ( 77)
|
||||
#define TARGET_NR_gettimeofday ( 78)
|
||||
#define TARGET_NR_settimeofday ( 79)
|
||||
#define TARGET_NR_getgroups ( 80)
|
||||
#define TARGET_NR_setgroups ( 81)
|
||||
#define TARGET_NR_select ( 82)
|
||||
#define TARGET_NR_symlink ( 83)
|
||||
/* 84 was sys_lstat */
|
||||
#define TARGET_NR_readlink ( 85)
|
||||
#define TARGET_NR_uselib ( 86)
|
||||
#define TARGET_NR_swapon ( 87)
|
||||
#define TARGET_NR_reboot ( 88)
|
||||
#define TARGET_NR_readdir ( 89)
|
||||
#define TARGET_NR_mmap ( 90)
|
||||
#define TARGET_NR_munmap ( 91)
|
||||
#define TARGET_NR_truncate ( 92)
|
||||
#define TARGET_NR_ftruncate ( 93)
|
||||
#define TARGET_NR_fchmod ( 94)
|
||||
#define TARGET_NR_fchown ( 95)
|
||||
#define TARGET_NR_getpriority ( 96)
|
||||
#define TARGET_NR_setpriority ( 97)
|
||||
#define TARGET_NR_profil ( 98) /* removed */
|
||||
#define TARGET_NR_statfs ( 99)
|
||||
#define TARGET_NR_fstatfs (100)
|
||||
#define TARGET_NR_ioperm (101)
|
||||
#define TARGET_NR_socketcall (102)
|
||||
#define TARGET_NR_syslog (103)
|
||||
#define TARGET_NR_setitimer (104)
|
||||
#define TARGET_NR_getitimer (105)
|
||||
#define TARGET_NR_stat (106)
|
||||
#define TARGET_NR_lstat (107)
|
||||
#define TARGET_NR_fstat (108)
|
||||
/* 109 was sys_uname */
|
||||
/* 110 was sys_iopl */
|
||||
#define TARGET_NR_vhangup (111)
|
||||
#define TARGET_NR_idle (112)
|
||||
#define TARGET_NR_syscall (113) /* syscall to call a syscall! */
|
||||
#define TARGET_NR_wait4 (114)
|
||||
#define TARGET_NR_swapoff (115)
|
||||
#define TARGET_NR_sysinfo (116)
|
||||
#define TARGET_NR_ipc (117)
|
||||
#define TARGET_NR_fsync (118)
|
||||
#define TARGET_NR_sigreturn (119)
|
||||
#define TARGET_NR_clone (120)
|
||||
#define TARGET_NR_setdomainname (121)
|
||||
#define TARGET_NR_uname (122)
|
||||
#define TARGET_NR_modify_ldt (123)
|
||||
#define TARGET_NR_adjtimex (124)
|
||||
#define TARGET_NR_mprotect (125)
|
||||
#define TARGET_NR_sigprocmask (126)
|
||||
#define TARGET_NR_create_module (127) /* removed */
|
||||
#define TARGET_NR_init_module (128)
|
||||
#define TARGET_NR_delete_module (129)
|
||||
#define TARGET_NR_get_kernel_syms (130) /* removed */
|
||||
#define TARGET_NR_quotactl (131)
|
||||
#define TARGET_NR_getpgid (132)
|
||||
#define TARGET_NR_fchdir (133)
|
||||
#define TARGET_NR_bdflush (134)
|
||||
#define TARGET_NR_sysfs (135)
|
||||
#define TARGET_NR_personality (136)
|
||||
#define TARGET_NR_afs_syscall (137) /* Syscall for Andrew File System */
|
||||
#define TARGET_NR_setfsuid (138)
|
||||
#define TARGET_NR_setfsgid (139)
|
||||
#define TARGET_NR__llseek (140)
|
||||
#define TARGET_NR_getdents (141)
|
||||
#define TARGET_NR__newselect (142)
|
||||
#define TARGET_NR_flock (143)
|
||||
#define TARGET_NR_msync (144)
|
||||
#define TARGET_NR_readv (145)
|
||||
#define TARGET_NR_writev (146)
|
||||
#define TARGET_NR_getsid (147)
|
||||
#define TARGET_NR_fdatasync (148)
|
||||
#define TARGET_NR__sysctl (149)
|
||||
#define TARGET_NR_mlock (150)
|
||||
#define TARGET_NR_munlock (151)
|
||||
#define TARGET_NR_mlockall (152)
|
||||
#define TARGET_NR_munlockall (153)
|
||||
#define TARGET_NR_sched_setparam (154)
|
||||
#define TARGET_NR_sched_getparam (155)
|
||||
#define TARGET_NR_sched_setscheduler (156)
|
||||
#define TARGET_NR_sched_getscheduler (157)
|
||||
#define TARGET_NR_sched_yield (158)
|
||||
#define TARGET_NR_sched_get_priority_max (159)
|
||||
#define TARGET_NR_sched_get_priority_min (160)
|
||||
#define TARGET_NR_sched_rr_get_interval (161)
|
||||
#define TARGET_NR_nanosleep (162)
|
||||
#define TARGET_NR_mremap (163)
|
||||
#define TARGET_NR_setresuid (164)
|
||||
#define TARGET_NR_getresuid (165)
|
||||
#define TARGET_NR_vm86 (166) /* removed */
|
||||
#define TARGET_NR_query_module (167) /* removed */
|
||||
#define TARGET_NR_poll (168)
|
||||
#define TARGET_NR_nfsservctl (169)
|
||||
#define TARGET_NR_setresgid (170)
|
||||
#define TARGET_NR_getresgid (171)
|
||||
#define TARGET_NR_prctl (172)
|
||||
#define TARGET_NR_rt_sigreturn (173)
|
||||
#define TARGET_NR_rt_sigaction (174)
|
||||
#define TARGET_NR_rt_sigprocmask (175)
|
||||
#define TARGET_NR_rt_sigpending (176)
|
||||
#define TARGET_NR_rt_sigtimedwait (177)
|
||||
#define TARGET_NR_rt_sigqueueinfo (178)
|
||||
#define TARGET_NR_rt_sigsuspend (179)
|
||||
#define TARGET_NR_pread (180)
|
||||
#define TARGET_NR_pwrite (181)
|
||||
#define TARGET_NR_chown (182)
|
||||
#define TARGET_NR_getcwd (183)
|
||||
#define TARGET_NR_capget (184)
|
||||
#define TARGET_NR_capset (185)
|
||||
#define TARGET_NR_sigaltstack (186)
|
||||
#define TARGET_NR_sendfile (187)
|
||||
/* 188 reserved */
|
||||
/* 189 reserved */
|
||||
#define TARGET_NR_vfork (190)
|
||||
#define TARGET_NR_ugetrlimit (191) /* SuS compliant getrlimit */
|
||||
#define TARGET_NR_mmap2 (192)
|
||||
#define TARGET_NR_truncate64 (193)
|
||||
#define TARGET_NR_ftruncate64 (194)
|
||||
#define TARGET_NR_stat64 (195)
|
||||
#define TARGET_NR_lstat64 (196)
|
||||
#define TARGET_NR_fstat64 (197)
|
||||
#define TARGET_NR_lchown32 (198)
|
||||
#define TARGET_NR_getuid32 (199)
|
||||
#define TARGET_NR_getgid32 (200)
|
||||
#define TARGET_NR_geteuid32 (201)
|
||||
#define TARGET_NR_getegid32 (202)
|
||||
#define TARGET_NR_setreuid32 (203)
|
||||
#define TARGET_NR_setregid32 (204)
|
||||
#define TARGET_NR_getgroups32 (205)
|
||||
#define TARGET_NR_setgroups32 (206)
|
||||
#define TARGET_NR_fchown32 (207)
|
||||
#define TARGET_NR_setresuid32 (208)
|
||||
#define TARGET_NR_getresuid32 (209)
|
||||
#define TARGET_NR_setresgid32 (210)
|
||||
#define TARGET_NR_getresgid32 (211)
|
||||
#define TARGET_NR_chown32 (212)
|
||||
#define TARGET_NR_setuid32 (213)
|
||||
#define TARGET_NR_setgid32 (214)
|
||||
#define TARGET_NR_setfsuid32 (215)
|
||||
#define TARGET_NR_setfsgid32 (216)
|
||||
#define TARGET_NR_getdents64 (217)
|
||||
#define TARGET_NR_pivot_root (218)
|
||||
#define TARGET_NR_mincore (219)
|
||||
#define TARGET_NR_madvise (220)
|
||||
#define TARGET_NR_fcntl64 (221)
|
||||
/* 222 for tux */
|
||||
/* 223 is unused */
|
||||
#define TARGET_NR_gettid (224)
|
||||
#define TARGET_NR_readahead (225)
|
||||
#define TARGET_NR_setxattr (226)
|
||||
#define TARGET_NR_lsetxattr (227)
|
||||
#define TARGET_NR_fsetxattr (228)
|
||||
#define TARGET_NR_getxattr (229)
|
||||
#define TARGET_NR_lgetxattr (230)
|
||||
#define TARGET_NR_fgetxattr (231)
|
||||
#define TARGET_NR_listxattr (232)
|
||||
#define TARGET_NR_llistxattr (233)
|
||||
#define TARGET_NR_flistxattr (234)
|
||||
#define TARGET_NR_removexattr (235)
|
||||
#define TARGET_NR_lremovexattr (236)
|
||||
#define TARGET_NR_fremovexattr (237)
|
||||
#define TARGET_NR_tkill (238)
|
||||
#define TARGET_NR_sendfile64 (239)
|
||||
#define TARGET_NR_futex (240)
|
||||
#define TARGET_NR_sched_setaffinity (241)
|
||||
#define TARGET_NR_sched_getaffinity (242)
|
||||
#define TARGET_NR_io_setup (243)
|
||||
#define TARGET_NR_io_destroy (244)
|
||||
#define TARGET_NR_io_getevents (245)
|
||||
#define TARGET_NR_io_submit (246)
|
||||
#define TARGET_NR_io_cancel (247)
|
||||
#define TARGET_NR_exit_group (248)
|
||||
#define TARGET_NR_lookup_dcookie (249)
|
||||
#define TARGET_NR_epoll_create (250)
|
||||
#define TARGET_NR_epoll_ctl (251)
|
||||
#define TARGET_NR_epoll_wait (252)
|
||||
#define TARGET_NR_remap_file_pages (253)
|
||||
/* 254 for set_thread_area */
|
||||
/* 255 for get_thread_area */
|
||||
/* 256 for set_tid_address */
|
||||
@@ -0,0 +1,215 @@
|
||||
/* from asm/termbits.h */
|
||||
/* NOTE: exactly the same as i386 */
|
||||
|
||||
#define TARGET_NCCS 19
|
||||
|
||||
struct target_termios {
|
||||
unsigned int c_iflag; /* input mode flags */
|
||||
unsigned int c_oflag; /* output mode flags */
|
||||
unsigned int c_cflag; /* control mode flags */
|
||||
unsigned int c_lflag; /* local mode flags */
|
||||
unsigned char c_line; /* line discipline */
|
||||
unsigned char c_cc[TARGET_NCCS]; /* control characters */
|
||||
};
|
||||
|
||||
/* c_iflag bits */
|
||||
#define TARGET_IGNBRK 0000001
|
||||
#define TARGET_BRKINT 0000002
|
||||
#define TARGET_IGNPAR 0000004
|
||||
#define TARGET_PARMRK 0000010
|
||||
#define TARGET_INPCK 0000020
|
||||
#define TARGET_ISTRIP 0000040
|
||||
#define TARGET_INLCR 0000100
|
||||
#define TARGET_IGNCR 0000200
|
||||
#define TARGET_ICRNL 0000400
|
||||
#define TARGET_IUCLC 0001000
|
||||
#define TARGET_IXON 0002000
|
||||
#define TARGET_IXANY 0004000
|
||||
#define TARGET_IXOFF 0010000
|
||||
#define TARGET_IMAXBEL 0020000
|
||||
|
||||
/* c_oflag bits */
|
||||
#define TARGET_OPOST 0000001
|
||||
#define TARGET_OLCUC 0000002
|
||||
#define TARGET_ONLCR 0000004
|
||||
#define TARGET_OCRNL 0000010
|
||||
#define TARGET_ONOCR 0000020
|
||||
#define TARGET_ONLRET 0000040
|
||||
#define TARGET_OFILL 0000100
|
||||
#define TARGET_OFDEL 0000200
|
||||
#define TARGET_NLDLY 0000400
|
||||
#define TARGET_NL0 0000000
|
||||
#define TARGET_NL1 0000400
|
||||
#define TARGET_CRDLY 0003000
|
||||
#define TARGET_CR0 0000000
|
||||
#define TARGET_CR1 0001000
|
||||
#define TARGET_CR2 0002000
|
||||
#define TARGET_CR3 0003000
|
||||
#define TARGET_TABDLY 0014000
|
||||
#define TARGET_TAB0 0000000
|
||||
#define TARGET_TAB1 0004000
|
||||
#define TARGET_TAB2 0010000
|
||||
#define TARGET_TAB3 0014000
|
||||
#define TARGET_XTABS 0014000
|
||||
#define TARGET_BSDLY 0020000
|
||||
#define TARGET_BS0 0000000
|
||||
#define TARGET_BS1 0020000
|
||||
#define TARGET_VTDLY 0040000
|
||||
#define TARGET_VT0 0000000
|
||||
#define TARGET_VT1 0040000
|
||||
#define TARGET_FFDLY 0100000
|
||||
#define TARGET_FF0 0000000
|
||||
#define TARGET_FF1 0100000
|
||||
|
||||
/* c_cflag bit meaning */
|
||||
#define TARGET_CBAUD 0010017
|
||||
#define TARGET_B0 0000000 /* hang up */
|
||||
#define TARGET_B50 0000001
|
||||
#define TARGET_B75 0000002
|
||||
#define TARGET_B110 0000003
|
||||
#define TARGET_B134 0000004
|
||||
#define TARGET_B150 0000005
|
||||
#define TARGET_B200 0000006
|
||||
#define TARGET_B300 0000007
|
||||
#define TARGET_B600 0000010
|
||||
#define TARGET_B1200 0000011
|
||||
#define TARGET_B1800 0000012
|
||||
#define TARGET_B2400 0000013
|
||||
#define TARGET_B4800 0000014
|
||||
#define TARGET_B9600 0000015
|
||||
#define TARGET_B19200 0000016
|
||||
#define TARGET_B38400 0000017
|
||||
#define TARGET_EXTA B19200
|
||||
#define TARGET_EXTB B38400
|
||||
#define TARGET_CSIZE 0000060
|
||||
#define TARGET_CS5 0000000
|
||||
#define TARGET_CS6 0000020
|
||||
#define TARGET_CS7 0000040
|
||||
#define TARGET_CS8 0000060
|
||||
#define TARGET_CSTOPB 0000100
|
||||
#define TARGET_CREAD 0000200
|
||||
#define TARGET_PARENB 0000400
|
||||
#define TARGET_PARODD 0001000
|
||||
#define TARGET_HUPCL 0002000
|
||||
#define TARGET_CLOCAL 0004000
|
||||
#define TARGET_CBAUDEX 0010000
|
||||
#define TARGET_B57600 0010001
|
||||
#define TARGET_B115200 0010002
|
||||
#define TARGET_B230400 0010003
|
||||
#define TARGET_B460800 0010004
|
||||
#define TARGET_CIBAUD 002003600000 /* input baud rate (not used) */
|
||||
#define TARGET_CRTSCTS 020000000000 /* flow control */
|
||||
|
||||
/* c_lflag bits */
|
||||
#define TARGET_ISIG 0000001
|
||||
#define TARGET_ICANON 0000002
|
||||
#define TARGET_XCASE 0000004
|
||||
#define TARGET_ECHO 0000010
|
||||
#define TARGET_ECHOE 0000020
|
||||
#define TARGET_ECHOK 0000040
|
||||
#define TARGET_ECHONL 0000100
|
||||
#define TARGET_NOFLSH 0000200
|
||||
#define TARGET_TOSTOP 0000400
|
||||
#define TARGET_ECHOCTL 0001000
|
||||
#define TARGET_ECHOPRT 0002000
|
||||
#define TARGET_ECHOKE 0004000
|
||||
#define TARGET_FLUSHO 0010000
|
||||
#define TARGET_PENDIN 0040000
|
||||
#define TARGET_IEXTEN 0100000
|
||||
|
||||
/* c_cc character offsets */
|
||||
#define TARGET_VINTR 0
|
||||
#define TARGET_VQUIT 1
|
||||
#define TARGET_VERASE 2
|
||||
#define TARGET_VKILL 3
|
||||
#define TARGET_VEOF 4
|
||||
#define TARGET_VTIME 5
|
||||
#define TARGET_VMIN 6
|
||||
#define TARGET_VSWTC 7
|
||||
#define TARGET_VSTART 8
|
||||
#define TARGET_VSTOP 9
|
||||
#define TARGET_VSUSP 10
|
||||
#define TARGET_VEOL 11
|
||||
#define TARGET_VREPRINT 12
|
||||
#define TARGET_VDISCARD 13
|
||||
#define TARGET_VWERASE 14
|
||||
#define TARGET_VLNEXT 15
|
||||
#define TARGET_VEOL2 16
|
||||
|
||||
/* ioctls */
|
||||
|
||||
#define TARGET_TCGETS 0x5401
|
||||
#define TARGET_TCSETS 0x5402
|
||||
#define TARGET_TCSETSW 0x5403
|
||||
#define TARGET_TCSETSF 0x5404
|
||||
#define TARGET_TCGETA 0x5405
|
||||
#define TARGET_TCSETA 0x5406
|
||||
#define TARGET_TCSETAW 0x5407
|
||||
#define TARGET_TCSETAF 0x5408
|
||||
#define TARGET_TCSBRK 0x5409
|
||||
#define TARGET_TCXONC 0x540A
|
||||
#define TARGET_TCFLSH 0x540B
|
||||
|
||||
#define TARGET_TIOCEXCL 0x540C
|
||||
#define TARGET_TIOCNXCL 0x540D
|
||||
#define TARGET_TIOCSCTTY 0x540E
|
||||
#define TARGET_TIOCGPGRP 0x540F
|
||||
#define TARGET_TIOCSPGRP 0x5410
|
||||
#define TARGET_TIOCOUTQ 0x5411
|
||||
#define TARGET_TIOCSTI 0x5412
|
||||
#define TARGET_TIOCGWINSZ 0x5413
|
||||
#define TARGET_TIOCSWINSZ 0x5414
|
||||
#define TARGET_TIOCMGET 0x5415
|
||||
#define TARGET_TIOCMBIS 0x5416
|
||||
#define TARGET_TIOCMBIC 0x5417
|
||||
#define TARGET_TIOCMSET 0x5418
|
||||
#define TARGET_TIOCGSOFTCAR 0x5419
|
||||
#define TARGET_TIOCSSOFTCAR 0x541A
|
||||
#define TARGET_FIONREAD 0x541B
|
||||
#define TARGET_TIOCINQ TARGET_FIONREAD
|
||||
#define TARGET_TIOCLINUX 0x541C
|
||||
#define TARGET_TIOCCONS 0x541D
|
||||
#define TARGET_TIOCGSERIAL 0x541E
|
||||
#define TARGET_TIOCSSERIAL 0x541F
|
||||
#define TARGET_TIOCPKT 0x5420
|
||||
#define TARGET_FIONBIO 0x5421
|
||||
#define TARGET_TIOCNOTTY 0x5422
|
||||
#define TARGET_TIOCSETD 0x5423
|
||||
#define TARGET_TIOCGETD 0x5424
|
||||
#define TARGET_TCSBRKP 0x5425 /* Needed for POSIX tcsendbreak() */
|
||||
#define TARGET_TIOCTTYGSTRUCT 0x5426 /* For debugging only */
|
||||
#define TARGET_TIOCSBRK 0x5427 /* BSD compatibility */
|
||||
#define TARGET_TIOCCBRK 0x5428 /* BSD compatibility */
|
||||
#define TARGET_TIOCGSID 0x5429 /* Return the session ID of FD */
|
||||
#define TARGET_TIOCGPTN TARGET_IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */
|
||||
#define TARGET_TIOCSPTLCK TARGET_IOW('T',0x31, int) /* Lock/unlock Pty */
|
||||
|
||||
#define TARGET_FIONCLEX 0x5450 /* these numbers need to be adjusted. */
|
||||
#define TARGET_FIOCLEX 0x5451
|
||||
#define TARGET_FIOASYNC 0x5452
|
||||
#define TARGET_TIOCSERCONFIG 0x5453
|
||||
#define TARGET_TIOCSERGWILD 0x5454
|
||||
#define TARGET_TIOCSERSWILD 0x5455
|
||||
#define TARGET_TIOCGLCKTRMIOS 0x5456
|
||||
#define TARGET_TIOCSLCKTRMIOS 0x5457
|
||||
#define TARGET_TIOCSERGSTRUCT 0x5458 /* For debugging only */
|
||||
#define TARGET_TIOCSERGETLSR 0x5459 /* Get line status register */
|
||||
#define TARGET_TIOCSERGETMULTI 0x545A /* Get multiport config */
|
||||
#define TARGET_TIOCSERSETMULTI 0x545B /* Set multiport config */
|
||||
|
||||
#define TARGET_TIOCMIWAIT 0x545C /* wait for a change on serial input line(s) */
|
||||
#define TARGET_TIOCGICOUNT 0x545D /* read serial port inline interrupt counts */
|
||||
#define TARGET_TIOCGHAYESESP 0x545E /* Get Hayes ESP configuration */
|
||||
#define TARGET_TIOCSHAYESESP 0x545F /* Set Hayes ESP configuration */
|
||||
|
||||
/* Used for packet mode */
|
||||
#define TARGET_TIOCPKT_DATA 0
|
||||
#define TARGET_TIOCPKT_FLUSHREAD 1
|
||||
#define TARGET_TIOCPKT_FLUSHWRITE 2
|
||||
#define TARGET_TIOCPKT_STOP 4
|
||||
#define TARGET_TIOCPKT_START 8
|
||||
#define TARGET_TIOCPKT_NOSTOP 16
|
||||
#define TARGET_TIOCPKT_DOSTOP 32
|
||||
|
||||
#define TARGET_TIOCSER_TEMT 0x01 /* Transmitter physically empty */
|
||||
|
||||
+208
-72
@@ -13,6 +13,16 @@
|
||||
#include "qemu.h"
|
||||
#include "disas.h"
|
||||
|
||||
/* this flag is uneffective under linux too, should be deleted */
|
||||
#ifndef MAP_DENYWRITE
|
||||
#define MAP_DENYWRITE 0
|
||||
#endif
|
||||
|
||||
/* should probably go in elf.h */
|
||||
#ifndef ELIBBAD
|
||||
#define ELIBBAD 80
|
||||
#endif
|
||||
|
||||
#ifdef TARGET_I386
|
||||
|
||||
#define ELF_START_MMAP 0x80000000
|
||||
@@ -83,6 +93,103 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef TARGET_SPARC
|
||||
|
||||
#define ELF_START_MMAP 0x80000000
|
||||
|
||||
#define elf_check_arch(x) ( (x) == EM_SPARC )
|
||||
|
||||
#define ELF_CLASS ELFCLASS32
|
||||
#define ELF_DATA ELFDATA2MSB
|
||||
#define ELF_ARCH EM_SPARC
|
||||
|
||||
/*XXX*/
|
||||
#define ELF_PLAT_INIT(_r)
|
||||
|
||||
static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
|
||||
{
|
||||
regs->psr = 0;
|
||||
regs->pc = infop->entry;
|
||||
regs->npc = regs->pc + 4;
|
||||
regs->y = 0;
|
||||
regs->u_regs[14] = infop->start_stack - 16 * 4;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef TARGET_PPC
|
||||
|
||||
#define ELF_START_MMAP 0x80000000
|
||||
|
||||
#define elf_check_arch(x) ( (x) == EM_PPC )
|
||||
|
||||
#define ELF_CLASS ELFCLASS32
|
||||
#ifdef TARGET_WORDS_BIGENDIAN
|
||||
#define ELF_DATA ELFDATA2MSB
|
||||
#else
|
||||
#define ELF_DATA ELFDATA2LSB
|
||||
#endif
|
||||
#define ELF_ARCH EM_PPC
|
||||
|
||||
/* Note that isn't exactly what regular kernel does
|
||||
* but this is what the ABI wants and is needed to allow
|
||||
* execution of PPC BSD programs.
|
||||
*/
|
||||
#define ELF_PLAT_INIT(_r) \
|
||||
do { \
|
||||
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"
|
||||
|
||||
/*
|
||||
@@ -164,21 +271,13 @@ struct exec
|
||||
#define INTERPRETER_AOUT 1
|
||||
#define INTERPRETER_ELF 2
|
||||
|
||||
#define DLINFO_ITEMS 12
|
||||
|
||||
#define put_user(x,ptr) (void)(*(ptr) = (typeof(*ptr))(x))
|
||||
#define get_user(ptr) (typeof(*ptr))(*(ptr))
|
||||
#define DLINFO_ITEMS 11
|
||||
|
||||
static inline void memcpy_fromfs(void * to, const void * from, unsigned long n)
|
||||
{
|
||||
memcpy(to, from, n);
|
||||
}
|
||||
|
||||
static inline void memcpy_tofs(void * to, const void * from, unsigned long n)
|
||||
{
|
||||
memcpy(to, from, n);
|
||||
}
|
||||
|
||||
extern unsigned long x86_stack_size;
|
||||
|
||||
static int load_aout_interp(void * exptr, int interp_fd);
|
||||
@@ -243,7 +342,7 @@ static void * get_free_page(void)
|
||||
/* User-space version of kernel get_free_page. Returns a page-aligned
|
||||
* page-sized chunk of memory.
|
||||
*/
|
||||
retval = (void *)target_mmap(0, host_page_size, PROT_READ|PROT_WRITE,
|
||||
retval = (void *)target_mmap(0, qemu_host_page_size, PROT_READ|PROT_WRITE,
|
||||
MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
|
||||
|
||||
if((long)retval == -1) {
|
||||
@@ -257,7 +356,7 @@ static void * get_free_page(void)
|
||||
|
||||
static void free_page(void * pageaddr)
|
||||
{
|
||||
target_munmap((unsigned long)pageaddr, host_page_size);
|
||||
target_munmap((unsigned long)pageaddr, qemu_host_page_size);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -276,11 +375,13 @@ static unsigned long copy_strings(int argc,char ** argv,unsigned long *page,
|
||||
return 0; /* bullet-proofing */
|
||||
}
|
||||
while (argc-- > 0) {
|
||||
if (!(tmp1 = tmp = get_user(argv+argc))) {
|
||||
tmp = argv[argc];
|
||||
if (!tmp) {
|
||||
fprintf(stderr, "VFS: argc is wrong");
|
||||
exit(-1);
|
||||
}
|
||||
while (get_user(tmp++));
|
||||
tmp1 = tmp;
|
||||
while (*tmp++);
|
||||
len = tmp - tmp1;
|
||||
if (p < len) { /* this shouldn't happen - 128kB */
|
||||
return 0;
|
||||
@@ -289,14 +390,16 @@ static unsigned long copy_strings(int argc,char ** argv,unsigned long *page,
|
||||
--p; --tmp; --len;
|
||||
if (--offset < 0) {
|
||||
offset = p % TARGET_PAGE_SIZE;
|
||||
if (!(pag = (char *) page[p/TARGET_PAGE_SIZE]) &&
|
||||
!(pag = (char *) page[p/TARGET_PAGE_SIZE] =
|
||||
(unsigned long *) get_free_page())) {
|
||||
return 0;
|
||||
pag = (char *) page[p/TARGET_PAGE_SIZE];
|
||||
if (!pag) {
|
||||
pag = (char *)get_free_page();
|
||||
page[p/TARGET_PAGE_SIZE] = (unsigned long)pag;
|
||||
if (!pag)
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (len == 0 || offset == 0) {
|
||||
*(pag + offset) = get_user(tmp);
|
||||
*(pag + offset) = *tmp;
|
||||
}
|
||||
else {
|
||||
int bytes_to_copy = (len > offset) ? offset : len;
|
||||
@@ -409,7 +512,7 @@ unsigned long setup_arg_pages(unsigned long p, struct linux_binprm * bprm,
|
||||
if (size < MAX_ARG_PAGES*TARGET_PAGE_SIZE)
|
||||
size = MAX_ARG_PAGES*TARGET_PAGE_SIZE;
|
||||
error = target_mmap(0,
|
||||
size + host_page_size,
|
||||
size + qemu_host_page_size,
|
||||
PROT_READ | PROT_WRITE,
|
||||
MAP_PRIVATE | MAP_ANONYMOUS,
|
||||
-1, 0);
|
||||
@@ -418,7 +521,7 @@ unsigned long setup_arg_pages(unsigned long p, struct linux_binprm * bprm,
|
||||
exit(-1);
|
||||
}
|
||||
/* we reserve one extra page at the top of the stack as guard */
|
||||
target_mprotect(error + size, host_page_size, PROT_NONE);
|
||||
target_mprotect(error + size, qemu_host_page_size, PROT_NONE);
|
||||
|
||||
stack_base = error + size - MAX_ARG_PAGES*TARGET_PAGE_SIZE;
|
||||
p += stack_base;
|
||||
@@ -456,20 +559,34 @@ static void set_brk(unsigned long start, unsigned long end)
|
||||
}
|
||||
|
||||
|
||||
/* We need to explicitly zero any fractional pages
|
||||
after the data section (i.e. bss). This would
|
||||
contain the junk from the file that should not
|
||||
be in memory */
|
||||
|
||||
|
||||
/* We need to explicitly zero any fractional pages after the data
|
||||
section (i.e. bss). This would contain the junk from the file that
|
||||
should not be in memory. */
|
||||
static void padzero(unsigned long elf_bss)
|
||||
{
|
||||
unsigned long nbyte;
|
||||
char * fpnt;
|
||||
|
||||
nbyte = elf_bss & (host_page_size-1); /* was TARGET_PAGE_SIZE - JRP */
|
||||
/* XXX: this is really a hack : if the real host page size is
|
||||
smaller than the target page size, some pages after the end
|
||||
of the file may not be mapped. A better fix would be to
|
||||
patch target_mmap(), but it is more complicated as the file
|
||||
size must be known */
|
||||
if (qemu_real_host_page_size < qemu_host_page_size) {
|
||||
unsigned long end_addr, end_addr1;
|
||||
end_addr1 = (elf_bss + qemu_real_host_page_size - 1) &
|
||||
~(qemu_real_host_page_size - 1);
|
||||
end_addr = HOST_PAGE_ALIGN(elf_bss);
|
||||
if (end_addr1 < end_addr) {
|
||||
mmap((void *)end_addr1, end_addr - end_addr1,
|
||||
PROT_READ|PROT_WRITE|PROT_EXEC,
|
||||
MAP_FIXED|MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
|
||||
}
|
||||
}
|
||||
|
||||
nbyte = elf_bss & (qemu_host_page_size-1);
|
||||
if (nbyte) {
|
||||
nbyte = host_page_size - nbyte;
|
||||
nbyte = qemu_host_page_size - nbyte;
|
||||
fpnt = (char *) elf_bss;
|
||||
do {
|
||||
*fpnt++ = 0;
|
||||
@@ -484,53 +601,77 @@ static unsigned int * create_elf_tables(char *p, int argc, int envc,
|
||||
unsigned long interp_load_addr, int ibcs,
|
||||
struct image_info *info)
|
||||
{
|
||||
target_ulong *argv, *envp, *dlinfo;
|
||||
target_ulong *sp;
|
||||
target_ulong *argv, *envp;
|
||||
target_ulong *sp, *csp;
|
||||
int v;
|
||||
|
||||
/*
|
||||
* Force 16 byte alignment here for generality.
|
||||
*/
|
||||
/*
|
||||
* Force 16 byte _final_ alignment here for generality.
|
||||
*/
|
||||
sp = (unsigned int *) (~15UL & (unsigned long) p);
|
||||
sp -= DLINFO_ITEMS*2;
|
||||
dlinfo = sp;
|
||||
csp = sp;
|
||||
csp -= (DLINFO_ITEMS + 1) * 2;
|
||||
#ifdef DLINFO_ARCH_ITEMS
|
||||
csp -= DLINFO_ARCH_ITEMS*2;
|
||||
#endif
|
||||
csp -= envc+1;
|
||||
csp -= argc+1;
|
||||
csp -= (!ibcs ? 3 : 1); /* argc itself */
|
||||
if ((unsigned long)csp & 15UL)
|
||||
sp -= ((unsigned long)csp & 15UL) / sizeof(*sp);
|
||||
|
||||
#define NEW_AUX_ENT(nr, id, val) \
|
||||
put_user (id, sp + (nr * 2)); \
|
||||
put_user (val, sp + (nr * 2 + 1))
|
||||
sp -= 2;
|
||||
NEW_AUX_ENT (0, AT_NULL, 0);
|
||||
|
||||
sp -= DLINFO_ITEMS*2;
|
||||
NEW_AUX_ENT( 0, AT_PHDR, (target_ulong)(load_addr + exec->e_phoff));
|
||||
NEW_AUX_ENT( 1, AT_PHENT, (target_ulong)(sizeof (struct elf_phdr)));
|
||||
NEW_AUX_ENT( 2, AT_PHNUM, (target_ulong)(exec->e_phnum));
|
||||
NEW_AUX_ENT( 3, AT_PAGESZ, (target_ulong)(TARGET_PAGE_SIZE));
|
||||
NEW_AUX_ENT( 4, AT_BASE, (target_ulong)(interp_load_addr));
|
||||
NEW_AUX_ENT( 5, AT_FLAGS, (target_ulong)0);
|
||||
NEW_AUX_ENT( 6, AT_ENTRY, load_bias + exec->e_entry);
|
||||
NEW_AUX_ENT( 7, AT_UID, (target_ulong) getuid());
|
||||
NEW_AUX_ENT( 8, AT_EUID, (target_ulong) geteuid());
|
||||
NEW_AUX_ENT( 9, AT_GID, (target_ulong) getgid());
|
||||
NEW_AUX_ENT(11, AT_EGID, (target_ulong) getegid());
|
||||
#ifdef ARCH_DLINFO
|
||||
/*
|
||||
* ARCH_DLINFO must come last so platform specific code can enforce
|
||||
* special alignment requirements on the AUXV if necessary (eg. PPC).
|
||||
*/
|
||||
ARCH_DLINFO;
|
||||
#endif
|
||||
#undef NEW_AUX_ENT
|
||||
|
||||
sp -= envc+1;
|
||||
envp = sp;
|
||||
sp -= argc+1;
|
||||
argv = sp;
|
||||
if (!ibcs) {
|
||||
put_user(tswapl((target_ulong)envp),--sp);
|
||||
put_user(tswapl((target_ulong)argv),--sp);
|
||||
put_user((target_ulong)envp,--sp);
|
||||
put_user((target_ulong)argv,--sp);
|
||||
}
|
||||
|
||||
#define NEW_AUX_ENT(id, val) \
|
||||
put_user (tswapl(id), dlinfo++); \
|
||||
put_user (tswapl(val), dlinfo++)
|
||||
|
||||
NEW_AUX_ENT (AT_PHDR, (target_ulong)(load_addr + exec->e_phoff));
|
||||
NEW_AUX_ENT (AT_PHENT, (target_ulong)(sizeof (struct elf_phdr)));
|
||||
NEW_AUX_ENT (AT_PHNUM, (target_ulong)(exec->e_phnum));
|
||||
NEW_AUX_ENT (AT_PAGESZ, (target_ulong)(TARGET_PAGE_SIZE));
|
||||
NEW_AUX_ENT (AT_BASE, (target_ulong)(interp_load_addr));
|
||||
NEW_AUX_ENT (AT_FLAGS, (target_ulong)0);
|
||||
NEW_AUX_ENT (AT_ENTRY, load_bias + exec->e_entry);
|
||||
NEW_AUX_ENT (AT_UID, (target_ulong) getuid());
|
||||
NEW_AUX_ENT (AT_EUID, (target_ulong) geteuid());
|
||||
NEW_AUX_ENT (AT_GID, (target_ulong) getgid());
|
||||
NEW_AUX_ENT (AT_EGID, (target_ulong) getegid());
|
||||
NEW_AUX_ENT (AT_NULL, 0);
|
||||
#undef NEW_AUX_ENT
|
||||
|
||||
put_user(tswapl(argc),--sp);
|
||||
put_user(argc,--sp);
|
||||
info->arg_start = (unsigned int)((unsigned long)p & 0xffffffff);
|
||||
while (argc-->0) {
|
||||
put_user(tswapl((target_ulong)p),argv++);
|
||||
while (get_user(p++)) /* nothing */ ;
|
||||
put_user((target_ulong)p,argv++);
|
||||
do {
|
||||
get_user(v, p);
|
||||
p++;
|
||||
} while (v != 0);
|
||||
}
|
||||
put_user(0,argv);
|
||||
info->arg_end = info->env_start = (unsigned int)((unsigned long)p & 0xffffffff);
|
||||
while (envc-->0) {
|
||||
put_user(tswapl((target_ulong)p),envp++);
|
||||
while (get_user(p++)) /* nothing */ ;
|
||||
put_user((target_ulong)p,envp++);
|
||||
do {
|
||||
get_user(v, p);
|
||||
p++;
|
||||
} while (v != 0);
|
||||
}
|
||||
put_user(0,envp);
|
||||
info->env_end = (unsigned int)((unsigned long)p & 0xffffffff);
|
||||
@@ -680,7 +821,7 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex,
|
||||
* bss page.
|
||||
*/
|
||||
padzero(elf_bss);
|
||||
elf_bss = TARGET_ELF_PAGESTART(elf_bss + host_page_size - 1); /* What we have mapped so far */
|
||||
elf_bss = TARGET_ELF_PAGESTART(elf_bss + qemu_host_page_size - 1); /* What we have mapped so far */
|
||||
|
||||
/* Map the last of the bss segment */
|
||||
if (last_bss > elf_bss) {
|
||||
@@ -936,7 +1077,7 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r
|
||||
char * passed_p;
|
||||
|
||||
if (interpreter_type == INTERPRETER_AOUT) {
|
||||
sprintf(passed_fileno, "%d", bprm->fd);
|
||||
snprintf(passed_fileno, sizeof(passed_fileno), "%d", bprm->fd);
|
||||
passed_p = passed_fileno;
|
||||
|
||||
if (elf_interpreter) {
|
||||
@@ -1121,7 +1262,7 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r
|
||||
and some applications "depend" upon this behavior.
|
||||
Since we do not have the power to recompile these, we
|
||||
emulate the SVr4 behavior. Sigh. */
|
||||
mapped_addr = target_mmap(0, host_page_size, PROT_READ | PROT_EXEC,
|
||||
mapped_addr = target_mmap(0, qemu_host_page_size, PROT_READ | PROT_EXEC,
|
||||
MAP_FIXED | MAP_PRIVATE, -1, 0);
|
||||
}
|
||||
|
||||
@@ -1154,14 +1295,9 @@ int elf_exec(const char * filename, char ** argv, char ** envp,
|
||||
for (i=0 ; i<MAX_ARG_PAGES ; i++) /* clear page-table */
|
||||
bprm.page[i] = 0;
|
||||
retval = open(filename, O_RDONLY);
|
||||
if (retval == -1) {
|
||||
perror(filename);
|
||||
exit(-1);
|
||||
/* return retval; */
|
||||
}
|
||||
else {
|
||||
bprm.fd = retval;
|
||||
}
|
||||
if (retval < 0)
|
||||
return retval;
|
||||
bprm.fd = retval;
|
||||
bprm.filename = (char *)filename;
|
||||
bprm.sh_bang = 0;
|
||||
bprm.loader = 0;
|
||||
|
||||
File renamed without changes.
@@ -0,0 +1,273 @@
|
||||
/*
|
||||
* This file contains the system call numbers.
|
||||
*/
|
||||
|
||||
#define TARGET_NR_restart_syscall 0
|
||||
#define TARGET_NR_exit 1
|
||||
#define TARGET_NR_fork 2
|
||||
#define TARGET_NR_read 3
|
||||
#define TARGET_NR_write 4
|
||||
#define TARGET_NR_open 5
|
||||
#define TARGET_NR_close 6
|
||||
#define TARGET_NR_waitpid 7
|
||||
#define TARGET_NR_creat 8
|
||||
#define TARGET_NR_link 9
|
||||
#define TARGET_NR_unlink 10
|
||||
#define TARGET_NR_execve 11
|
||||
#define TARGET_NR_chdir 12
|
||||
#define TARGET_NR_time 13
|
||||
#define TARGET_NR_mknod 14
|
||||
#define TARGET_NR_chmod 15
|
||||
#define TARGET_NR_lchown 16
|
||||
#define TARGET_NR_break 17
|
||||
#define TARGET_NR_oldstat 18
|
||||
#define TARGET_NR_lseek 19
|
||||
#define TARGET_NR_getpid 20
|
||||
#define TARGET_NR_mount 21
|
||||
#define TARGET_NR_umount 22
|
||||
#define TARGET_NR_setuid 23
|
||||
#define TARGET_NR_getuid 24
|
||||
#define TARGET_NR_stime 25
|
||||
#define TARGET_NR_ptrace 26
|
||||
#define TARGET_NR_alarm 27
|
||||
#define TARGET_NR_oldfstat 28
|
||||
#define TARGET_NR_pause 29
|
||||
#define TARGET_NR_utime 30
|
||||
#define TARGET_NR_stty 31
|
||||
#define TARGET_NR_gtty 32
|
||||
#define TARGET_NR_access 33
|
||||
#define TARGET_NR_nice 34
|
||||
#define TARGET_NR_ftime 35
|
||||
#define TARGET_NR_sync 36
|
||||
#define TARGET_NR_kill 37
|
||||
#define TARGET_NR_rename 38
|
||||
#define TARGET_NR_mkdir 39
|
||||
#define TARGET_NR_rmdir 40
|
||||
#define TARGET_NR_dup 41
|
||||
#define TARGET_NR_pipe 42
|
||||
#define TARGET_NR_times 43
|
||||
#define TARGET_NR_prof 44
|
||||
#define TARGET_NR_brk 45
|
||||
#define TARGET_NR_setgid 46
|
||||
#define TARGET_NR_getgid 47
|
||||
#define TARGET_NR_signal 48
|
||||
#define TARGET_NR_geteuid 49
|
||||
#define TARGET_NR_getegid 50
|
||||
#define TARGET_NR_acct 51
|
||||
#define TARGET_NR_umount2 52
|
||||
#define TARGET_NR_lock 53
|
||||
#define TARGET_NR_ioctl 54
|
||||
#define TARGET_NR_fcntl 55
|
||||
#define TARGET_NR_mpx 56
|
||||
#define TARGET_NR_setpgid 57
|
||||
#define TARGET_NR_ulimit 58
|
||||
#define TARGET_NR_oldolduname 59
|
||||
#define TARGET_NR_umask 60
|
||||
#define TARGET_NR_chroot 61
|
||||
#define TARGET_NR_ustat 62
|
||||
#define TARGET_NR_dup2 63
|
||||
#define TARGET_NR_getppid 64
|
||||
#define TARGET_NR_getpgrp 65
|
||||
#define TARGET_NR_setsid 66
|
||||
#define TARGET_NR_sigaction 67
|
||||
#define TARGET_NR_sgetmask 68
|
||||
#define TARGET_NR_ssetmask 69
|
||||
#define TARGET_NR_setreuid 70
|
||||
#define TARGET_NR_setregid 71
|
||||
#define TARGET_NR_sigsuspend 72
|
||||
#define TARGET_NR_sigpending 73
|
||||
#define TARGET_NR_sethostname 74
|
||||
#define TARGET_NR_setrlimit 75
|
||||
#define TARGET_NR_getrlimit 76 /* Back compatible 2Gig limited rlimit */
|
||||
#define TARGET_NR_getrusage 77
|
||||
#define TARGET_NR_gettimeofday 78
|
||||
#define TARGET_NR_settimeofday 79
|
||||
#define TARGET_NR_getgroups 80
|
||||
#define TARGET_NR_setgroups 81
|
||||
#define TARGET_NR_select 82
|
||||
#define TARGET_NR_symlink 83
|
||||
#define TARGET_NR_oldlstat 84
|
||||
#define TARGET_NR_readlink 85
|
||||
#define TARGET_NR_uselib 86
|
||||
#define TARGET_NR_swapon 87
|
||||
#define TARGET_NR_reboot 88
|
||||
#define TARGET_NR_readdir 89
|
||||
#define TARGET_NR_mmap 90
|
||||
#define TARGET_NR_munmap 91
|
||||
#define TARGET_NR_truncate 92
|
||||
#define TARGET_NR_ftruncate 93
|
||||
#define TARGET_NR_fchmod 94
|
||||
#define TARGET_NR_fchown 95
|
||||
#define TARGET_NR_getpriority 96
|
||||
#define TARGET_NR_setpriority 97
|
||||
#define TARGET_NR_profil 98
|
||||
#define TARGET_NR_statfs 99
|
||||
#define TARGET_NR_fstatfs 100
|
||||
#define TARGET_NR_ioperm 101
|
||||
#define TARGET_NR_socketcall 102
|
||||
#define TARGET_NR_syslog 103
|
||||
#define TARGET_NR_setitimer 104
|
||||
#define TARGET_NR_getitimer 105
|
||||
#define TARGET_NR_stat 106
|
||||
#define TARGET_NR_lstat 107
|
||||
#define TARGET_NR_fstat 108
|
||||
#define TARGET_NR_olduname 109
|
||||
#define TARGET_NR_iopl 110
|
||||
#define TARGET_NR_vhangup 111
|
||||
#define TARGET_NR_idle 112
|
||||
#define TARGET_NR_vm86old 113
|
||||
#define TARGET_NR_wait4 114
|
||||
#define TARGET_NR_swapoff 115
|
||||
#define TARGET_NR_sysinfo 116
|
||||
#define TARGET_NR_ipc 117
|
||||
#define TARGET_NR_fsync 118
|
||||
#define TARGET_NR_sigreturn 119
|
||||
#define TARGET_NR_clone 120
|
||||
#define TARGET_NR_setdomainname 121
|
||||
#define TARGET_NR_uname 122
|
||||
#define TARGET_NR_modify_ldt 123
|
||||
#define TARGET_NR_adjtimex 124
|
||||
#define TARGET_NR_mprotect 125
|
||||
#define TARGET_NR_sigprocmask 126
|
||||
#define TARGET_NR_create_module 127
|
||||
#define TARGET_NR_init_module 128
|
||||
#define TARGET_NR_delete_module 129
|
||||
#define TARGET_NR_get_kernel_syms 130
|
||||
#define TARGET_NR_quotactl 131
|
||||
#define TARGET_NR_getpgid 132
|
||||
#define TARGET_NR_fchdir 133
|
||||
#define TARGET_NR_bdflush 134
|
||||
#define TARGET_NR_sysfs 135
|
||||
#define TARGET_NR_personality 136
|
||||
#define TARGET_NR_afs_syscall 137 /* Syscall for Andrew File System */
|
||||
#define TARGET_NR_setfsuid 138
|
||||
#define TARGET_NR_setfsgid 139
|
||||
#define TARGET_NR__llseek 140
|
||||
#define TARGET_NR_getdents 141
|
||||
#define TARGET_NR__newselect 142
|
||||
#define TARGET_NR_flock 143
|
||||
#define TARGET_NR_msync 144
|
||||
#define TARGET_NR_readv 145
|
||||
#define TARGET_NR_writev 146
|
||||
#define TARGET_NR_getsid 147
|
||||
#define TARGET_NR_fdatasync 148
|
||||
#define TARGET_NR__sysctl 149
|
||||
#define TARGET_NR_mlock 150
|
||||
#define TARGET_NR_munlock 151
|
||||
#define TARGET_NR_mlockall 152
|
||||
#define TARGET_NR_munlockall 153
|
||||
#define TARGET_NR_sched_setparam 154
|
||||
#define TARGET_NR_sched_getparam 155
|
||||
#define TARGET_NR_sched_setscheduler 156
|
||||
#define TARGET_NR_sched_getscheduler 157
|
||||
#define TARGET_NR_sched_yield 158
|
||||
#define TARGET_NR_sched_get_priority_max 159
|
||||
#define TARGET_NR_sched_get_priority_min 160
|
||||
#define TARGET_NR_sched_rr_get_interval 161
|
||||
#define TARGET_NR_nanosleep 162
|
||||
#define TARGET_NR_mremap 163
|
||||
#define TARGET_NR_setresuid 164
|
||||
#define TARGET_NR_getresuid 165
|
||||
#define TARGET_NR_vm86 166
|
||||
#define TARGET_NR_query_module 167
|
||||
#define TARGET_NR_poll 168
|
||||
#define TARGET_NR_nfsservctl 169
|
||||
#define TARGET_NR_setresgid 170
|
||||
#define TARGET_NR_getresgid 171
|
||||
#define TARGET_NR_prctl 172
|
||||
#define TARGET_NR_rt_sigreturn 173
|
||||
#define TARGET_NR_rt_sigaction 174
|
||||
#define TARGET_NR_rt_sigprocmask 175
|
||||
#define TARGET_NR_rt_sigpending 176
|
||||
#define TARGET_NR_rt_sigtimedwait 177
|
||||
#define TARGET_NR_rt_sigqueueinfo 178
|
||||
#define TARGET_NR_rt_sigsuspend 179
|
||||
#define TARGET_NR_pread 180
|
||||
#define TARGET_NR_pwrite 181
|
||||
#define TARGET_NR_chown 182
|
||||
#define TARGET_NR_getcwd 183
|
||||
#define TARGET_NR_capget 184
|
||||
#define TARGET_NR_capset 185
|
||||
#define TARGET_NR_sigaltstack 186
|
||||
#define TARGET_NR_sendfile 187
|
||||
#define TARGET_NR_getpmsg 188 /* some people actually want streams */
|
||||
#define TARGET_NR_putpmsg 189 /* some people actually want streams */
|
||||
#define TARGET_NR_vfork 190
|
||||
#define TARGET_NR_ugetrlimit 191 /* SuS compliant getrlimit */
|
||||
#define TARGET_NR_mmap2 192
|
||||
#define TARGET_NR_truncate64 193
|
||||
#define TARGET_NR_ftruncate64 194
|
||||
#define TARGET_NR_stat64 195
|
||||
#define TARGET_NR_lstat64 196
|
||||
#define TARGET_NR_fstat64 197
|
||||
#define TARGET_NR_lchown32 198
|
||||
#define TARGET_NR_getuid32 199
|
||||
#define TARGET_NR_getgid32 200
|
||||
#define TARGET_NR_geteuid32 201
|
||||
#define TARGET_NR_getegid32 202
|
||||
#define TARGET_NR_setreuid32 203
|
||||
#define TARGET_NR_setregid32 204
|
||||
#define TARGET_NR_getgroups32 205
|
||||
#define TARGET_NR_setgroups32 206
|
||||
#define TARGET_NR_fchown32 207
|
||||
#define TARGET_NR_setresuid32 208
|
||||
#define TARGET_NR_getresuid32 209
|
||||
#define TARGET_NR_setresgid32 210
|
||||
#define TARGET_NR_getresgid32 211
|
||||
#define TARGET_NR_chown32 212
|
||||
#define TARGET_NR_setuid32 213
|
||||
#define TARGET_NR_setgid32 214
|
||||
#define TARGET_NR_setfsuid32 215
|
||||
#define TARGET_NR_setfsgid32 216
|
||||
#define TARGET_NR_pivot_root 217
|
||||
#define TARGET_NR_mincore 218
|
||||
#define TARGET_NR_madvise 219
|
||||
#define TARGET_NR_madvise1 219 /* delete when C lib stub is removed */
|
||||
#define TARGET_NR_getdents64 220
|
||||
#define TARGET_NR_fcntl64 221
|
||||
/* 223 is unused */
|
||||
#define TARGET_NR_gettid 224
|
||||
#define TARGET_NR_readahead 225
|
||||
#define TARGET_NR_setxattr 226
|
||||
#define TARGET_NR_lsetxattr 227
|
||||
#define TARGET_NR_fsetxattr 228
|
||||
#define TARGET_NR_getxattr 229
|
||||
#define TARGET_NR_lgetxattr 230
|
||||
#define TARGET_NR_fgetxattr 231
|
||||
#define TARGET_NR_listxattr 232
|
||||
#define TARGET_NR_llistxattr 233
|
||||
#define TARGET_NR_flistxattr 234
|
||||
#define TARGET_NR_removexattr 235
|
||||
#define TARGET_NR_lremovexattr 236
|
||||
#define TARGET_NR_fremovexattr 237
|
||||
#define TARGET_NR_tkill 238
|
||||
#define TARGET_NR_sendfile64 239
|
||||
#define TARGET_NR_futex 240
|
||||
#define TARGET_NR_sched_setaffinity 241
|
||||
#define TARGET_NR_sched_getaffinity 242
|
||||
#define TARGET_NR_set_thread_area 243
|
||||
#define TARGET_NR_get_thread_area 244
|
||||
#define TARGET_NR_io_setup 245
|
||||
#define TARGET_NR_io_destroy 246
|
||||
#define TARGET_NR_io_getevents 247
|
||||
#define TARGET_NR_io_submit 248
|
||||
#define TARGET_NR_io_cancel 249
|
||||
#define TARGET_NR_fadvise64 250
|
||||
|
||||
#define TARGET_NR_exit_group 252
|
||||
#define TARGET_NR_lookup_dcookie 253
|
||||
#define TARGET_NR_epoll_create 254
|
||||
#define TARGET_NR_epoll_ctl 255
|
||||
#define TARGET_NR_epoll_wait 256
|
||||
#define TARGET_NR_remap_file_pages 257
|
||||
#define TARGET_NR_set_tid_address 258
|
||||
#define TARGET_NR_timer_create 259
|
||||
#define TARGET_NR_timer_settime (TARGET_NR_timer_create+1)
|
||||
#define TARGET_NR_timer_gettime (TARGET_NR_timer_create+2)
|
||||
#define TARGET_NR_timer_getoverrun (TARGET_NR_timer_create+3)
|
||||
#define TARGET_NR_timer_delete (TARGET_NR_timer_create+4)
|
||||
#define TARGET_NR_clock_settime (TARGET_NR_timer_create+5)
|
||||
#define TARGET_NR_clock_gettime (TARGET_NR_timer_create+6)
|
||||
#define TARGET_NR_clock_getres (TARGET_NR_timer_create+7)
|
||||
#define TARGET_NR_clock_nanosleep (TARGET_NR_timer_create+8)
|
||||
|
||||
@@ -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 */
|
||||
|
||||
+687
-44
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* qemu main
|
||||
* qemu user main
|
||||
*
|
||||
* Copyright (c) 2003 Fabrice Bellard
|
||||
*
|
||||
@@ -28,19 +28,24 @@
|
||||
|
||||
#define DEBUG_LOGFILE "/tmp/qemu.log"
|
||||
|
||||
FILE *logfile = NULL;
|
||||
int loglevel;
|
||||
#ifdef __APPLE__
|
||||
#include <crt_externs.h>
|
||||
# define environ (*_NSGetEnviron())
|
||||
#endif
|
||||
|
||||
static const char *interp_prefix = CONFIG_QEMU_PREFIX;
|
||||
|
||||
#ifdef __i386__
|
||||
#if defined(__i386__) && !defined(CONFIG_STATIC)
|
||||
/* Force usage of an ELF interpreter even if it is an ELF shared
|
||||
object ! */
|
||||
const char interp[] __attribute__((section(".interp"))) = "/lib/ld-linux.so.2";
|
||||
#endif
|
||||
|
||||
/* for recent libc, we add these dummies symbol which are not declared
|
||||
/* for recent libc, we add these dummy symbols which are not declared
|
||||
when generating a linked object (bug in ld ?) */
|
||||
#if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 3)
|
||||
#if (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 3)) && !defined(CONFIG_STATIC)
|
||||
long __preinit_array_start[0];
|
||||
long __preinit_array_end[0];
|
||||
long __init_array_start[0];
|
||||
long __init_array_end[0];
|
||||
long __fini_array_start[0];
|
||||
@@ -61,48 +66,88 @@ void gemu_log(const char *fmt, ...)
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
#ifdef TARGET_I386
|
||||
/***********************************************************/
|
||||
/* CPUX86 core interface */
|
||||
|
||||
void cpu_x86_outb(CPUX86State *env, int addr, int val)
|
||||
void cpu_outb(CPUState *env, int addr, int val)
|
||||
{
|
||||
fprintf(stderr, "outb: port=0x%04x, data=%02x\n", addr, val);
|
||||
}
|
||||
|
||||
void cpu_x86_outw(CPUX86State *env, int addr, int val)
|
||||
void cpu_outw(CPUState *env, int addr, int val)
|
||||
{
|
||||
fprintf(stderr, "outw: port=0x%04x, data=%04x\n", addr, val);
|
||||
}
|
||||
|
||||
void cpu_x86_outl(CPUX86State *env, int addr, int val)
|
||||
void cpu_outl(CPUState *env, int addr, int val)
|
||||
{
|
||||
fprintf(stderr, "outl: port=0x%04x, data=%08x\n", addr, val);
|
||||
}
|
||||
|
||||
int cpu_x86_inb(CPUX86State *env, int addr)
|
||||
int cpu_inb(CPUState *env, int addr)
|
||||
{
|
||||
fprintf(stderr, "inb: port=0x%04x\n", addr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cpu_x86_inw(CPUX86State *env, int addr)
|
||||
int cpu_inw(CPUState *env, int addr)
|
||||
{
|
||||
fprintf(stderr, "inw: port=0x%04x\n", addr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cpu_x86_inl(CPUX86State *env, int addr)
|
||||
int cpu_inl(CPUState *env, int addr)
|
||||
{
|
||||
fprintf(stderr, "inl: port=0x%04x\n", addr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cpu_x86_get_pic_interrupt(CPUX86State *env)
|
||||
int cpu_get_pic_interrupt(CPUState *env)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* timers for rdtsc */
|
||||
|
||||
#if defined(__i386__)
|
||||
|
||||
int64_t cpu_get_real_ticks(void)
|
||||
{
|
||||
int64_t val;
|
||||
asm volatile ("rdtsc" : "=A" (val));
|
||||
return val;
|
||||
}
|
||||
|
||||
#elif defined(__x86_64__)
|
||||
|
||||
int64_t cpu_get_real_ticks(void)
|
||||
{
|
||||
uint32_t low,high;
|
||||
int64_t val;
|
||||
asm volatile("rdtsc" : "=a" (low), "=d" (high));
|
||||
val = high;
|
||||
val <<= 32;
|
||||
val |= low;
|
||||
return val;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static uint64_t emu_time;
|
||||
|
||||
int64_t cpu_get_real_ticks(void)
|
||||
{
|
||||
return emu_time++;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef TARGET_I386
|
||||
/***********************************************************/
|
||||
/* CPUX86 core interface */
|
||||
|
||||
uint64_t cpu_get_tsc(CPUX86State *env)
|
||||
{
|
||||
return cpu_get_real_ticks();
|
||||
}
|
||||
|
||||
static void write_dt(void *ptr, unsigned long addr, unsigned long limit,
|
||||
int flags)
|
||||
{
|
||||
@@ -246,6 +291,27 @@ void cpu_loop(CPUX86State *env)
|
||||
|
||||
#ifdef TARGET_ARM
|
||||
|
||||
/* XXX: find a better solution */
|
||||
extern void tb_invalidate_page_range(target_ulong start, target_ulong end);
|
||||
|
||||
static void arm_cache_flush(target_ulong start, target_ulong last)
|
||||
{
|
||||
target_ulong addr, last1;
|
||||
|
||||
if (last < start)
|
||||
return;
|
||||
addr = start;
|
||||
for(;;) {
|
||||
last1 = ((addr + TARGET_PAGE_SIZE) & TARGET_PAGE_MASK) - 1;
|
||||
if (last1 > last)
|
||||
last1 = last;
|
||||
tb_invalidate_page_range(addr, last1 + 1);
|
||||
if (last1 == last)
|
||||
break;
|
||||
addr = last1 + 1;
|
||||
}
|
||||
}
|
||||
|
||||
void cpu_loop(CPUARMState *env)
|
||||
{
|
||||
int trapnr;
|
||||
@@ -256,18 +322,34 @@ void cpu_loop(CPUARMState *env)
|
||||
trapnr = cpu_arm_exec(env);
|
||||
switch(trapnr) {
|
||||
case EXCP_UDEF:
|
||||
info.si_signo = SIGILL;
|
||||
info.si_errno = 0;
|
||||
info.si_code = TARGET_ILL_ILLOPN;
|
||||
info._sifields._sigfault._addr = env->regs[15];
|
||||
queue_signal(info.si_signo, &info);
|
||||
{
|
||||
TaskState *ts = env->opaque;
|
||||
uint32_t opcode;
|
||||
|
||||
/* we handle the FPU emulation here, as Linux */
|
||||
/* we get the opcode */
|
||||
opcode = ldl_raw((uint8_t *)env->regs[15]);
|
||||
|
||||
if (EmulateAll(opcode, &ts->fpa, env->regs) == 0) {
|
||||
info.si_signo = SIGILL;
|
||||
info.si_errno = 0;
|
||||
info.si_code = TARGET_ILL_ILLOPN;
|
||||
info._sifields._sigfault._addr = env->regs[15];
|
||||
queue_signal(info.si_signo, &info);
|
||||
} else {
|
||||
/* increment PC */
|
||||
env->regs[15] += 4;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case EXCP_SWI:
|
||||
{
|
||||
/* system call */
|
||||
insn = ldl((void *)(env->regs[15] - 4));
|
||||
n = insn & 0xffffff;
|
||||
if (n >= ARM_SYSCALL_BASE) {
|
||||
if (n == ARM_NR_cacheflush) {
|
||||
arm_cache_flush(env->regs[0], env->regs[1]);
|
||||
} else if (n >= ARM_SYSCALL_BASE) {
|
||||
/* linux syscall */
|
||||
n -= ARM_SYSCALL_BASE;
|
||||
env->regs[0] = do_syscall(env,
|
||||
@@ -299,10 +381,524 @@ void cpu_loop(CPUARMState *env)
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef TARGET_SPARC
|
||||
|
||||
//#define DEBUG_WIN
|
||||
|
||||
/* WARNING: dealing with register windows _is_ complicated */
|
||||
static inline int get_reg_index(CPUSPARCState *env, int cwp, int index)
|
||||
{
|
||||
index = (index + cwp * 16) & (16 * NWINDOWS - 1);
|
||||
/* wrap handling : if cwp is on the last window, then we use the
|
||||
registers 'after' the end */
|
||||
if (index < 8 && env->cwp == (NWINDOWS - 1))
|
||||
index += (16 * NWINDOWS);
|
||||
return index;
|
||||
}
|
||||
|
||||
static inline void save_window_offset(CPUSPARCState *env, int offset)
|
||||
{
|
||||
unsigned int new_wim, i, cwp1;
|
||||
uint32_t *sp_ptr;
|
||||
|
||||
new_wim = ((env->wim >> 1) | (env->wim << (NWINDOWS - 1))) &
|
||||
((1LL << NWINDOWS) - 1);
|
||||
/* save the window */
|
||||
cwp1 = (env->cwp + offset) & (NWINDOWS - 1);
|
||||
sp_ptr = (uint32_t *)(env->regbase[get_reg_index(env, cwp1, 6)]);
|
||||
#if defined(DEBUG_WIN)
|
||||
printf("win_overflow: sp_ptr=0x%x save_cwp=%d\n",
|
||||
(int)sp_ptr, cwp1);
|
||||
#endif
|
||||
for(i = 0; i < 16; i++)
|
||||
stl_raw(sp_ptr + i, env->regbase[get_reg_index(env, cwp1, 8 + i)]);
|
||||
env->wim = new_wim;
|
||||
}
|
||||
|
||||
static void save_window(CPUSPARCState *env)
|
||||
{
|
||||
save_window_offset(env, 2);
|
||||
}
|
||||
|
||||
static void restore_window(CPUSPARCState *env)
|
||||
{
|
||||
unsigned int new_wim, i, cwp1;
|
||||
uint32_t *sp_ptr;
|
||||
|
||||
new_wim = ((env->wim << 1) | (env->wim >> (NWINDOWS - 1))) &
|
||||
((1LL << NWINDOWS) - 1);
|
||||
|
||||
/* restore the invalid window */
|
||||
cwp1 = (env->cwp + 1) & (NWINDOWS - 1);
|
||||
sp_ptr = (uint32_t *)(env->regbase[get_reg_index(env, cwp1, 6)]);
|
||||
#if defined(DEBUG_WIN)
|
||||
printf("win_underflow: sp_ptr=0x%x load_cwp=%d\n",
|
||||
(int)sp_ptr, cwp1);
|
||||
#endif
|
||||
for(i = 0; i < 16; i++)
|
||||
env->regbase[get_reg_index(env, cwp1, 8 + i)] = ldl_raw(sp_ptr + i);
|
||||
env->wim = new_wim;
|
||||
}
|
||||
|
||||
static void flush_windows(CPUSPARCState *env)
|
||||
{
|
||||
int offset, cwp1;
|
||||
#if defined(DEBUG_WIN)
|
||||
printf("flush_windows:\n");
|
||||
#endif
|
||||
offset = 2;
|
||||
for(;;) {
|
||||
/* if restore would invoke restore_window(), then we can stop */
|
||||
cwp1 = (env->cwp + 1) & (NWINDOWS - 1);
|
||||
if (env->wim & (1 << cwp1))
|
||||
break;
|
||||
#if defined(DEBUG_WIN)
|
||||
printf("offset=%d: ", offset);
|
||||
#endif
|
||||
save_window_offset(env, offset);
|
||||
offset++;
|
||||
}
|
||||
}
|
||||
|
||||
void cpu_loop (CPUSPARCState *env)
|
||||
{
|
||||
int trapnr, ret;
|
||||
|
||||
while (1) {
|
||||
trapnr = cpu_sparc_exec (env);
|
||||
|
||||
switch (trapnr) {
|
||||
case 0x88:
|
||||
case 0x90:
|
||||
ret = do_syscall (env, env->gregs[1],
|
||||
env->regwptr[0], env->regwptr[1],
|
||||
env->regwptr[2], env->regwptr[3],
|
||||
env->regwptr[4], env->regwptr[5]);
|
||||
if ((unsigned int)ret >= (unsigned int)(-515)) {
|
||||
env->psr |= PSR_CARRY;
|
||||
ret = -ret;
|
||||
} else {
|
||||
env->psr &= ~PSR_CARRY;
|
||||
}
|
||||
env->regwptr[0] = ret;
|
||||
/* next instruction */
|
||||
env->pc = env->npc;
|
||||
env->npc = env->npc + 4;
|
||||
break;
|
||||
case 0x83: /* flush windows */
|
||||
// flush_windows(env);
|
||||
/* next instruction */
|
||||
env->pc = env->npc;
|
||||
env->npc = env->npc + 4;
|
||||
break;
|
||||
case TT_WIN_OVF: /* window overflow */
|
||||
save_window(env);
|
||||
break;
|
||||
case TT_WIN_UNF: /* window underflow */
|
||||
restore_window(env);
|
||||
break;
|
||||
default:
|
||||
printf ("Unhandled trap: 0x%x\n", trapnr);
|
||||
cpu_sparc_dump_state(env, stderr, 0);
|
||||
exit (1);
|
||||
}
|
||||
process_pending_signals (env);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef TARGET_PPC
|
||||
|
||||
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)
|
||||
{
|
||||
printf("qemu version " QEMU_VERSION ", Copyright (c) 2003 Fabrice Bellard\n"
|
||||
"usage: qemu [-h] [-d] [-L path] [-s size] program [arguments...]\n"
|
||||
printf("qemu-" TARGET_ARCH " version " QEMU_VERSION ", Copyright (c) 2003-2004 Fabrice Bellard\n"
|
||||
"usage: qemu-" TARGET_ARCH " [-h] [-d opts] [-L path] [-s size] program [arguments...]\n"
|
||||
"Linux CPU emulator (compiled for %s emulation)\n"
|
||||
"\n"
|
||||
"-h print this help\n"
|
||||
@@ -310,7 +906,10 @@ void usage(void)
|
||||
"-s size set the stack size in bytes (default=%ld)\n"
|
||||
"\n"
|
||||
"debug options:\n"
|
||||
"-d activate log (logfile=%s)\n"
|
||||
#ifdef USE_CODE_COPY
|
||||
"-no-code-copy disable code copy acceleration\n"
|
||||
#endif
|
||||
"-d options activate log (logfile=%s)\n"
|
||||
"-p pagesize set the host page size to 'pagesize'\n",
|
||||
TARGET_ARCH,
|
||||
interp_prefix,
|
||||
@@ -340,7 +939,9 @@ int main(int argc, char **argv)
|
||||
if (argc <= 1)
|
||||
usage();
|
||||
|
||||
loglevel = 0;
|
||||
/* init debug */
|
||||
cpu_set_log_filename(DEBUG_LOGFILE);
|
||||
|
||||
optind = 1;
|
||||
for(;;) {
|
||||
if (optind >= argc)
|
||||
@@ -353,7 +954,22 @@ int main(int argc, char **argv)
|
||||
if (!strcmp(r, "-")) {
|
||||
break;
|
||||
} else if (!strcmp(r, "d")) {
|
||||
loglevel = 1;
|
||||
int mask;
|
||||
CPULogItem *item;
|
||||
|
||||
if (optind >= argc)
|
||||
break;
|
||||
|
||||
r = argv[optind++];
|
||||
mask = cpu_str_to_log_mask(r);
|
||||
if (!mask) {
|
||||
printf("Log items (comma separated):\n");
|
||||
for(item = cpu_log_items; item->mask != 0; item++) {
|
||||
printf("%-10s %s\n", item->name, item->help);
|
||||
}
|
||||
exit(1);
|
||||
}
|
||||
cpu_set_log(mask);
|
||||
} else if (!strcmp(r, "s")) {
|
||||
r = argv[optind++];
|
||||
x86_stack_size = strtol(r, (char **)&r, 0);
|
||||
@@ -366,13 +982,19 @@ int main(int argc, char **argv)
|
||||
} else if (!strcmp(r, "L")) {
|
||||
interp_prefix = argv[optind++];
|
||||
} else if (!strcmp(r, "p")) {
|
||||
host_page_size = atoi(argv[optind++]);
|
||||
if (host_page_size == 0 ||
|
||||
(host_page_size & (host_page_size - 1)) != 0) {
|
||||
qemu_host_page_size = atoi(argv[optind++]);
|
||||
if (qemu_host_page_size == 0 ||
|
||||
(qemu_host_page_size & (qemu_host_page_size - 1)) != 0) {
|
||||
fprintf(stderr, "page size must be a power of two\n");
|
||||
exit(1);
|
||||
}
|
||||
} else {
|
||||
} else
|
||||
#ifdef USE_CODE_COPY
|
||||
if (!strcmp(r, "no-code-copy")) {
|
||||
code_copy_enabled = 0;
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
usage();
|
||||
}
|
||||
}
|
||||
@@ -380,16 +1002,6 @@ int main(int argc, char **argv)
|
||||
usage();
|
||||
filename = argv[optind];
|
||||
|
||||
/* init debug */
|
||||
if (loglevel) {
|
||||
logfile = fopen(DEBUG_LOGFILE, "w");
|
||||
if (!logfile) {
|
||||
perror(DEBUG_LOGFILE);
|
||||
_exit(1);
|
||||
}
|
||||
setvbuf(logfile, NULL, _IOLBF, 0);
|
||||
}
|
||||
|
||||
/* Zero out regs */
|
||||
memset(regs, 0, sizeof(struct target_pt_regs));
|
||||
|
||||
@@ -399,8 +1011,8 @@ int main(int argc, char **argv)
|
||||
/* Scan interp_prefix dir for replacement files. */
|
||||
init_paths(interp_prefix);
|
||||
|
||||
/* NOTE: we need to init the CPU at this stage to get the
|
||||
host_page_size */
|
||||
/* NOTE: we need to init the CPU at this stage to get
|
||||
qemu_host_page_size */
|
||||
env = cpu_init();
|
||||
|
||||
if (elf_exec(filename, argv+optind, environ, regs, info) != 0) {
|
||||
@@ -433,6 +1045,14 @@ int main(int argc, char **argv)
|
||||
env->user_mode_only = 1;
|
||||
|
||||
#if defined(TARGET_I386)
|
||||
cpu_x86_set_cpl(env, 3);
|
||||
|
||||
env->cr[0] = CR0_PG_MASK | CR0_WP_MASK | CR0_PE_MASK;
|
||||
env->hflags |= HF_PE_MASK;
|
||||
|
||||
/* flags setup : we activate the IRQs by default as in user mode */
|
||||
env->eflags |= IF_MASK;
|
||||
|
||||
/* linux register setup */
|
||||
env->regs[R_EAX] = regs->eax;
|
||||
env->regs[R_EBX] = regs->ebx;
|
||||
@@ -493,6 +1113,29 @@ int main(int argc, char **argv)
|
||||
}
|
||||
env->cpsr = regs->uregs[16];
|
||||
}
|
||||
#elif defined(TARGET_SPARC)
|
||||
{
|
||||
int i;
|
||||
env->pc = regs->pc;
|
||||
env->npc = regs->npc;
|
||||
env->y = regs->y;
|
||||
for(i = 0; i < 8; i++)
|
||||
env->gregs[i] = regs->u_regs[i];
|
||||
for(i = 0; i < 8; i++)
|
||||
env->regwptr[i] = regs->u_regs[i + 8];
|
||||
}
|
||||
#elif defined(TARGET_PPC)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < 32; i++) {
|
||||
if (i != 12 && i != 6)
|
||||
env->msr[i] = (regs->msr >> i) & 1;
|
||||
}
|
||||
env->nip = regs->nip;
|
||||
for(i = 0; i < 32; i++) {
|
||||
env->gpr[i] = regs->gpr[i];
|
||||
}
|
||||
}
|
||||
#else
|
||||
#error unsupported target CPU
|
||||
#endif
|
||||
|
||||
+36
-31
@@ -53,7 +53,7 @@ int target_mprotect(unsigned long start, unsigned long len, int prot)
|
||||
if (len == 0)
|
||||
return 0;
|
||||
|
||||
host_start = start & host_page_mask;
|
||||
host_start = start & qemu_host_page_mask;
|
||||
host_end = HOST_PAGE_ALIGN(end);
|
||||
if (start > host_start) {
|
||||
/* handle host page containing start */
|
||||
@@ -61,27 +61,27 @@ int target_mprotect(unsigned long start, unsigned long len, int prot)
|
||||
for(addr = host_start; addr < start; addr += TARGET_PAGE_SIZE) {
|
||||
prot1 |= page_get_flags(addr);
|
||||
}
|
||||
if (host_end == host_start + host_page_size) {
|
||||
if (host_end == host_start + qemu_host_page_size) {
|
||||
for(addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) {
|
||||
prot1 |= page_get_flags(addr);
|
||||
}
|
||||
end = host_end;
|
||||
}
|
||||
ret = mprotect((void *)host_start, host_page_size, prot1 & PAGE_BITS);
|
||||
ret = mprotect((void *)host_start, qemu_host_page_size, prot1 & PAGE_BITS);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
host_start += host_page_size;
|
||||
host_start += qemu_host_page_size;
|
||||
}
|
||||
if (end < host_end) {
|
||||
prot1 = prot;
|
||||
for(addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) {
|
||||
prot1 |= page_get_flags(addr);
|
||||
}
|
||||
ret = mprotect((void *)(host_end - host_page_size), host_page_size,
|
||||
ret = mprotect((void *)(host_end - qemu_host_page_size), qemu_host_page_size,
|
||||
prot1 & PAGE_BITS);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
host_end -= host_page_size;
|
||||
host_end -= qemu_host_page_size;
|
||||
}
|
||||
|
||||
/* handle the pages in the middle */
|
||||
@@ -102,7 +102,7 @@ int mmap_frag(unsigned long host_start,
|
||||
unsigned long host_end, ret, addr;
|
||||
int prot1, prot_new;
|
||||
|
||||
host_end = host_start + host_page_size;
|
||||
host_end = host_start + qemu_host_page_size;
|
||||
|
||||
/* get the protection of the target pages outside the mapping */
|
||||
prot1 = 0;
|
||||
@@ -113,7 +113,7 @@ int mmap_frag(unsigned long host_start,
|
||||
|
||||
if (prot1 == 0) {
|
||||
/* no page was there, so we allocate one */
|
||||
ret = (long)mmap((void *)host_start, host_page_size, prot,
|
||||
ret = (long)mmap((void *)host_start, qemu_host_page_size, prot,
|
||||
flags | MAP_ANONYMOUS, -1, 0);
|
||||
if (ret == -1)
|
||||
return ret;
|
||||
@@ -130,18 +130,18 @@ int mmap_frag(unsigned long host_start,
|
||||
|
||||
/* adjust protection to be able to read */
|
||||
if (!(prot1 & PROT_WRITE))
|
||||
mprotect((void *)host_start, host_page_size, prot1 | PROT_WRITE);
|
||||
mprotect((void *)host_start, qemu_host_page_size, prot1 | PROT_WRITE);
|
||||
|
||||
/* read the corresponding file data */
|
||||
pread(fd, (void *)start, end - start, offset);
|
||||
|
||||
/* put final protection */
|
||||
if (prot_new != (prot1 | PROT_WRITE))
|
||||
mprotect((void *)host_start, host_page_size, prot_new);
|
||||
mprotect((void *)host_start, qemu_host_page_size, prot_new);
|
||||
} else {
|
||||
/* just update the protection */
|
||||
if (prot_new != prot1) {
|
||||
mprotect((void *)host_start, host_page_size, prot_new);
|
||||
mprotect((void *)host_start, qemu_host_page_size, prot_new);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
@@ -152,6 +152,9 @@ long target_mmap(unsigned long start, unsigned long len, int prot,
|
||||
int flags, int fd, unsigned long offset)
|
||||
{
|
||||
unsigned long ret, end, host_start, host_end, retaddr, host_offset, host_len;
|
||||
#if defined(__alpha__) || defined(__sparc__) || defined(__x86_64__)
|
||||
static unsigned long last_start = 0x40000000;
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG_MMAP
|
||||
{
|
||||
@@ -185,18 +188,20 @@ long target_mmap(unsigned long start, unsigned long len, int prot,
|
||||
len = TARGET_PAGE_ALIGN(len);
|
||||
if (len == 0)
|
||||
return start;
|
||||
host_start = start & host_page_mask;
|
||||
host_start = start & qemu_host_page_mask;
|
||||
|
||||
if (!(flags & MAP_FIXED)) {
|
||||
#if defined(__alpha__) || defined(__sparc__)
|
||||
#if defined(__alpha__) || defined(__sparc__) || defined(__x86_64__)
|
||||
/* tell the kenel to search at the same place as i386 */
|
||||
if (host_start == 0)
|
||||
host_start = 0x40000000;
|
||||
if (host_start == 0) {
|
||||
host_start = last_start;
|
||||
last_start += HOST_PAGE_ALIGN(len);
|
||||
}
|
||||
#endif
|
||||
if (host_page_size != real_host_page_size) {
|
||||
if (qemu_host_page_size != qemu_real_host_page_size) {
|
||||
/* NOTE: this code is only for debugging with '-p' option */
|
||||
/* reserve a memory area */
|
||||
host_len = HOST_PAGE_ALIGN(len) + host_page_size - TARGET_PAGE_SIZE;
|
||||
host_len = HOST_PAGE_ALIGN(len) + qemu_host_page_size - TARGET_PAGE_SIZE;
|
||||
host_start = (long)mmap((void *)host_start, host_len, PROT_NONE,
|
||||
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
if (host_start == -1)
|
||||
@@ -212,7 +217,7 @@ long target_mmap(unsigned long start, unsigned long len, int prot,
|
||||
flags |= MAP_FIXED;
|
||||
} else {
|
||||
/* if not fixed, no need to do anything */
|
||||
host_offset = offset & host_page_mask;
|
||||
host_offset = offset & qemu_host_page_mask;
|
||||
host_len = len + offset - host_offset;
|
||||
start = (long)mmap((void *)host_start, host_len,
|
||||
prot, flags, fd, host_offset);
|
||||
@@ -233,7 +238,7 @@ long target_mmap(unsigned long start, unsigned long len, int prot,
|
||||
/* worst case: we cannot map the file because the offset is not
|
||||
aligned, so we read it */
|
||||
if (!(flags & MAP_ANONYMOUS) &&
|
||||
(offset & ~host_page_mask) != (start & ~host_page_mask)) {
|
||||
(offset & ~qemu_host_page_mask) != (start & ~qemu_host_page_mask)) {
|
||||
/* msync() won't work here, so we return an error if write is
|
||||
possible while it is a shared mapping */
|
||||
if ((flags & MAP_TYPE) == MAP_SHARED &&
|
||||
@@ -255,7 +260,7 @@ long target_mmap(unsigned long start, unsigned long len, int prot,
|
||||
|
||||
/* handle the start of the mapping */
|
||||
if (start > host_start) {
|
||||
if (host_end == host_start + host_page_size) {
|
||||
if (host_end == host_start + qemu_host_page_size) {
|
||||
/* one single host page */
|
||||
ret = mmap_frag(host_start, start, end,
|
||||
prot, flags, fd, offset);
|
||||
@@ -263,21 +268,21 @@ long target_mmap(unsigned long start, unsigned long len, int prot,
|
||||
return ret;
|
||||
goto the_end1;
|
||||
}
|
||||
ret = mmap_frag(host_start, start, host_start + host_page_size,
|
||||
ret = mmap_frag(host_start, start, host_start + qemu_host_page_size,
|
||||
prot, flags, fd, offset);
|
||||
if (ret == -1)
|
||||
return ret;
|
||||
host_start += host_page_size;
|
||||
host_start += qemu_host_page_size;
|
||||
}
|
||||
/* handle the end of the mapping */
|
||||
if (end < host_end) {
|
||||
ret = mmap_frag(host_end - host_page_size,
|
||||
host_end - host_page_size, host_end,
|
||||
ret = mmap_frag(host_end - qemu_host_page_size,
|
||||
host_end - qemu_host_page_size, host_end,
|
||||
prot, flags, fd,
|
||||
offset + host_end - host_page_size - start);
|
||||
offset + host_end - qemu_host_page_size - start);
|
||||
if (ret == -1)
|
||||
return ret;
|
||||
host_end -= host_page_size;
|
||||
host_end -= qemu_host_page_size;
|
||||
}
|
||||
|
||||
/* map the middle (easier) */
|
||||
@@ -317,7 +322,7 @@ int target_munmap(unsigned long start, unsigned long len)
|
||||
if (len == 0)
|
||||
return -EINVAL;
|
||||
end = start + len;
|
||||
host_start = start & host_page_mask;
|
||||
host_start = start & qemu_host_page_mask;
|
||||
host_end = HOST_PAGE_ALIGN(end);
|
||||
|
||||
if (start > host_start) {
|
||||
@@ -326,14 +331,14 @@ int target_munmap(unsigned long start, unsigned long len)
|
||||
for(addr = host_start; addr < start; addr += TARGET_PAGE_SIZE) {
|
||||
prot |= page_get_flags(addr);
|
||||
}
|
||||
if (host_end == host_start + host_page_size) {
|
||||
if (host_end == host_start + qemu_host_page_size) {
|
||||
for(addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) {
|
||||
prot |= page_get_flags(addr);
|
||||
}
|
||||
end = host_end;
|
||||
}
|
||||
if (prot != 0)
|
||||
host_start += host_page_size;
|
||||
host_start += qemu_host_page_size;
|
||||
}
|
||||
if (end < host_end) {
|
||||
prot = 0;
|
||||
@@ -341,7 +346,7 @@ int target_munmap(unsigned long start, unsigned long len)
|
||||
prot |= page_get_flags(addr);
|
||||
}
|
||||
if (prot != 0)
|
||||
host_end -= host_page_size;
|
||||
host_end -= qemu_host_page_size;
|
||||
}
|
||||
|
||||
/* unmap what we can */
|
||||
@@ -386,7 +391,7 @@ int target_msync(unsigned long start, unsigned long len, int flags)
|
||||
if (end == start)
|
||||
return 0;
|
||||
|
||||
start &= host_page_mask;
|
||||
start &= qemu_host_page_mask;
|
||||
return msync((void *)start, end - start, flags);
|
||||
}
|
||||
|
||||
@@ -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 */
|
||||
|
||||
+131
-9
@@ -4,17 +4,11 @@
|
||||
#include "thunk.h"
|
||||
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
#include "syscall_defs.h"
|
||||
|
||||
#if defined(TARGET_I386)
|
||||
#include "cpu-i386.h"
|
||||
#include "syscall-i386.h"
|
||||
#elif defined(TARGET_ARM)
|
||||
#include "cpu-arm.h"
|
||||
#include "syscall-arm.h"
|
||||
#else
|
||||
#error unsupported target CPU
|
||||
#endif
|
||||
#include "cpu.h"
|
||||
#include "syscall.h"
|
||||
|
||||
/* This struct is used to hold certain information about the image.
|
||||
* Basically, it replicates in user space what would be certain
|
||||
@@ -55,10 +49,21 @@ struct vm86_saved_state {
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef TARGET_ARM
|
||||
/* FPU emulator */
|
||||
#include "nwfpe/fpa11.h"
|
||||
#undef put_user
|
||||
#undef get_user
|
||||
#endif
|
||||
|
||||
/* NOTE: we force a big alignment so that the stack stored after is
|
||||
aligned too */
|
||||
typedef struct TaskState {
|
||||
struct TaskState *next;
|
||||
#ifdef TARGET_ARM
|
||||
/* FPA state */
|
||||
FPA11 fpa;
|
||||
#endif
|
||||
#ifdef TARGET_I386
|
||||
struct target_vm86plus_struct *target_v86;
|
||||
struct vm86_saved_state vm86_saved_regs;
|
||||
@@ -116,4 +121,121 @@ long target_mremap(unsigned long old_addr, unsigned long old_size,
|
||||
unsigned long new_addr);
|
||||
int target_msync(unsigned long start, unsigned long len, int flags);
|
||||
|
||||
/* user access */
|
||||
|
||||
#define VERIFY_READ 0
|
||||
#define VERIFY_WRITE 1
|
||||
|
||||
#define access_ok(type,addr,size) (1)
|
||||
|
||||
#define __put_user(x,ptr)\
|
||||
({\
|
||||
int size = sizeof(*ptr);\
|
||||
switch(size) {\
|
||||
case 1:\
|
||||
stb(ptr, (typeof(*ptr))(x));\
|
||||
break;\
|
||||
case 2:\
|
||||
stw(ptr, (typeof(*ptr))(x));\
|
||||
break;\
|
||||
case 4:\
|
||||
stl(ptr, (typeof(*ptr))(x));\
|
||||
break;\
|
||||
case 8:\
|
||||
stq(ptr, (typeof(*ptr))(x));\
|
||||
break;\
|
||||
default:\
|
||||
abort();\
|
||||
}\
|
||||
0;\
|
||||
})
|
||||
|
||||
#define __get_user(x, ptr) \
|
||||
({\
|
||||
int size = sizeof(*ptr);\
|
||||
switch(size) {\
|
||||
case 1:\
|
||||
x = (typeof(*ptr))ldub((void *)ptr);\
|
||||
break;\
|
||||
case 2:\
|
||||
x = (typeof(*ptr))lduw((void *)ptr);\
|
||||
break;\
|
||||
case 4:\
|
||||
x = (typeof(*ptr))ldl((void *)ptr);\
|
||||
break;\
|
||||
case 8:\
|
||||
x = (typeof(*ptr))ldq((void *)ptr);\
|
||||
break;\
|
||||
default:\
|
||||
abort();\
|
||||
}\
|
||||
0;\
|
||||
})
|
||||
|
||||
static inline unsigned long __copy_to_user(void *dst, const void *src,
|
||||
unsigned long size)
|
||||
{
|
||||
memcpy(dst, src, size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline unsigned long __copy_from_user(void *dst, const void *src,
|
||||
unsigned long size)
|
||||
{
|
||||
memcpy(dst, src, size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline unsigned long __clear_user(void *dst, unsigned long size)
|
||||
{
|
||||
memset(dst, 0, size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define put_user(x,ptr)\
|
||||
({\
|
||||
int __ret;\
|
||||
if (access_ok(VERIFY_WRITE, ptr, sizeof(*ptr)))\
|
||||
__ret = __put_user(x, ptr);\
|
||||
else\
|
||||
__ret = -EFAULT;\
|
||||
__ret;\
|
||||
})
|
||||
|
||||
#define get_user(x,ptr)\
|
||||
({\
|
||||
int __ret;\
|
||||
if (access_ok(VERIFY_READ, ptr, sizeof(*ptr)))\
|
||||
__ret = __get_user(x, ptr);\
|
||||
else\
|
||||
__ret = -EFAULT;\
|
||||
__ret;\
|
||||
})
|
||||
|
||||
static inline unsigned long copy_to_user(void *dst, const void *src,
|
||||
unsigned long size)
|
||||
{
|
||||
if (access_ok(VERIFY_WRITE, dst, size))
|
||||
return __copy_to_user(dst, src, size);
|
||||
else
|
||||
return size;
|
||||
}
|
||||
|
||||
static inline unsigned long copy_from_user(void *dst, const void *src,
|
||||
unsigned long size)
|
||||
{
|
||||
if (access_ok(VERIFY_READ, src, size))
|
||||
return __copy_from_user(dst, src, size);
|
||||
else
|
||||
return size;
|
||||
}
|
||||
|
||||
static inline unsigned long clear_user(void *dst, unsigned long size)
|
||||
{
|
||||
if (access_ok(VERIFY_WRITE, dst, size))
|
||||
return __clear_user(dst, size);
|
||||
else
|
||||
return size;
|
||||
}
|
||||
|
||||
#endif
|
||||
+98
-147
@@ -67,7 +67,7 @@ static uint8_t host_to_target_signal_table[65] = {
|
||||
[SIGILL] = TARGET_SIGILL,
|
||||
[SIGTRAP] = TARGET_SIGTRAP,
|
||||
[SIGABRT] = TARGET_SIGABRT,
|
||||
[SIGIOT] = TARGET_SIGIOT,
|
||||
/* [SIGIOT] = TARGET_SIGIOT,*/
|
||||
[SIGBUS] = TARGET_SIGBUS,
|
||||
[SIGFPE] = TARGET_SIGFPE,
|
||||
[SIGKILL] = TARGET_SIGKILL,
|
||||
@@ -109,7 +109,8 @@ static inline int target_to_host_signal(int sig)
|
||||
return target_to_host_signal_table[sig];
|
||||
}
|
||||
|
||||
void host_to_target_sigset(target_sigset_t *d, const sigset_t *s)
|
||||
static void host_to_target_sigset_internal(target_sigset_t *d,
|
||||
const sigset_t *s)
|
||||
{
|
||||
int i;
|
||||
unsigned long sigmask;
|
||||
@@ -122,25 +123,35 @@ void host_to_target_sigset(target_sigset_t *d, const sigset_t *s)
|
||||
target_sigmask |= 1 << (host_to_target_signal(i + 1) - 1);
|
||||
}
|
||||
#if TARGET_LONG_BITS == 32 && HOST_LONG_BITS == 32
|
||||
d->sig[0] = tswapl(target_sigmask);
|
||||
d->sig[0] = target_sigmask;
|
||||
for(i = 1;i < TARGET_NSIG_WORDS; i++) {
|
||||
d->sig[i] = tswapl(((unsigned long *)s)[i]);
|
||||
d->sig[i] = ((unsigned long *)s)[i];
|
||||
}
|
||||
#elif TARGET_LONG_BITS == 32 && HOST_LONG_BITS == 64 && TARGET_NSIG_WORDS == 2
|
||||
d->sig[0] = tswapl(target_sigmask);
|
||||
d->sig[1] = tswapl(sigmask >> 32);
|
||||
d->sig[0] = target_sigmask;
|
||||
d->sig[1] = sigmask >> 32;
|
||||
#else
|
||||
#error host_to_target_sigset
|
||||
#endif
|
||||
}
|
||||
|
||||
void target_to_host_sigset(sigset_t *d, const target_sigset_t *s)
|
||||
void host_to_target_sigset(target_sigset_t *d, const sigset_t *s)
|
||||
{
|
||||
target_sigset_t d1;
|
||||
int i;
|
||||
|
||||
host_to_target_sigset_internal(&d1, s);
|
||||
for(i = 0;i < TARGET_NSIG_WORDS; i++)
|
||||
__put_user(d1.sig[i], &d->sig[i]);
|
||||
}
|
||||
|
||||
void target_to_host_sigset_internal(sigset_t *d, const target_sigset_t *s)
|
||||
{
|
||||
int i;
|
||||
unsigned long sigmask;
|
||||
target_ulong target_sigmask;
|
||||
|
||||
target_sigmask = tswapl(s->sig[0]);
|
||||
target_sigmask = s->sig[0];
|
||||
sigmask = 0;
|
||||
for(i = 0; i < 32; i++) {
|
||||
if (target_sigmask & (1 << i))
|
||||
@@ -149,15 +160,25 @@ void target_to_host_sigset(sigset_t *d, const target_sigset_t *s)
|
||||
#if TARGET_LONG_BITS == 32 && HOST_LONG_BITS == 32
|
||||
((unsigned long *)d)[0] = sigmask;
|
||||
for(i = 1;i < TARGET_NSIG_WORDS; i++) {
|
||||
((unsigned long *)d)[i] = tswapl(s->sig[i]);
|
||||
((unsigned long *)d)[i] = s->sig[i];
|
||||
}
|
||||
#elif TARGET_LONG_BITS == 32 && HOST_LONG_BITS == 64 && TARGET_NSIG_WORDS == 2
|
||||
((unsigned long *)d)[0] = sigmask | (tswapl(s->sig[1]) << 32);
|
||||
((unsigned long *)d)[0] = sigmask | ((unsigned long)(s->sig[1]) << 32);
|
||||
#else
|
||||
#error target_to_host_sigset
|
||||
#endif /* TARGET_LONG_BITS */
|
||||
}
|
||||
|
||||
void target_to_host_sigset(sigset_t *d, const target_sigset_t *s)
|
||||
{
|
||||
target_sigset_t s1;
|
||||
int i;
|
||||
|
||||
for(i = 0;i < TARGET_NSIG_WORDS; i++)
|
||||
__get_user(s1.sig[i], &s->sig[i]);
|
||||
target_to_host_sigset_internal(d, &s1);
|
||||
}
|
||||
|
||||
void host_to_target_old_sigset(target_ulong *old_sigset,
|
||||
const sigset_t *sigset)
|
||||
{
|
||||
@@ -370,33 +391,6 @@ int queue_signal(int sig, target_siginfo_t *info)
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(DEBUG_SIGNAL)
|
||||
#ifdef __i386__
|
||||
static void dump_regs(struct ucontext *uc)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n"
|
||||
"ESI=%08x EDI=%08x EBP=%08x ESP=%08x\n"
|
||||
"EFL=%08x EIP=%08x\n",
|
||||
uc->uc_mcontext.gregs[EAX],
|
||||
uc->uc_mcontext.gregs[EBX],
|
||||
uc->uc_mcontext.gregs[ECX],
|
||||
uc->uc_mcontext.gregs[EDX],
|
||||
uc->uc_mcontext.gregs[ESI],
|
||||
uc->uc_mcontext.gregs[EDI],
|
||||
uc->uc_mcontext.gregs[EBP],
|
||||
uc->uc_mcontext.gregs[ESP],
|
||||
uc->uc_mcontext.gregs[EFL],
|
||||
uc->uc_mcontext.gregs[EIP]);
|
||||
}
|
||||
#else
|
||||
static void dump_regs(struct ucontext *uc)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
static void host_signal_handler(int host_signum, siginfo_t *info,
|
||||
void *puc)
|
||||
{
|
||||
@@ -405,7 +399,11 @@ static void host_signal_handler(int host_signum, siginfo_t *info,
|
||||
|
||||
/* the CPU emulator uses some host signals to detect exceptions,
|
||||
we we forward to it some signals */
|
||||
if (host_signum == SIGSEGV || host_signum == SIGBUS) {
|
||||
if (host_signum == SIGSEGV || host_signum == SIGBUS
|
||||
#if defined(TARGET_I386) && defined(USE_CODE_COPY)
|
||||
|| host_signum == SIGFPE
|
||||
#endif
|
||||
) {
|
||||
if (cpu_signal_handler(host_signum, info, puc))
|
||||
return;
|
||||
}
|
||||
@@ -416,7 +414,6 @@ static void host_signal_handler(int host_signum, siginfo_t *info,
|
||||
return;
|
||||
#if defined(DEBUG_SIGNAL)
|
||||
fprintf(stderr, "qemu: got signal %d\n", sig);
|
||||
dump_regs(puc);
|
||||
#endif
|
||||
host_to_target_siginfo_noswap(&tinfo, info);
|
||||
if (queue_signal(sig, &tinfo) == 1) {
|
||||
@@ -429,11 +426,13 @@ int do_sigaction(int sig, const struct target_sigaction *act,
|
||||
struct target_sigaction *oact)
|
||||
{
|
||||
struct emulated_sigaction *k;
|
||||
struct sigaction act1;
|
||||
int host_sig;
|
||||
|
||||
if (sig < 1 || sig > TARGET_NSIG)
|
||||
return -EINVAL;
|
||||
k = &sigact_table[sig - 1];
|
||||
#if defined(DEBUG_SIGNAL) && 0
|
||||
#if defined(DEBUG_SIGNAL)
|
||||
fprintf(stderr, "sigaction sig=%d act=0x%08x, oact=0x%08x\n",
|
||||
sig, (int)act, (int)oact);
|
||||
#endif
|
||||
@@ -448,73 +447,30 @@ int do_sigaction(int sig, const struct target_sigaction *act,
|
||||
k->sa.sa_flags = tswapl(act->sa_flags);
|
||||
k->sa.sa_restorer = tswapl(act->sa_restorer);
|
||||
k->sa.sa_mask = act->sa_mask;
|
||||
|
||||
/* we update the host linux signal state */
|
||||
host_sig = target_to_host_signal(sig);
|
||||
if (host_sig != SIGSEGV && host_sig != SIGBUS) {
|
||||
sigfillset(&act1.sa_mask);
|
||||
act1.sa_flags = SA_SIGINFO;
|
||||
if (k->sa.sa_flags & TARGET_SA_RESTART)
|
||||
act1.sa_flags |= SA_RESTART;
|
||||
/* NOTE: it is important to update the host kernel signal
|
||||
ignore state to avoid getting unexpected interrupted
|
||||
syscalls */
|
||||
if (k->sa._sa_handler == TARGET_SIG_IGN) {
|
||||
act1.sa_sigaction = (void *)SIG_IGN;
|
||||
} else if (k->sa._sa_handler == TARGET_SIG_DFL) {
|
||||
act1.sa_sigaction = (void *)SIG_DFL;
|
||||
} else {
|
||||
act1.sa_sigaction = host_signal_handler;
|
||||
}
|
||||
sigaction(host_sig, &act1, NULL);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define __put_user(x,ptr)\
|
||||
({\
|
||||
int size = sizeof(*ptr);\
|
||||
switch(size) {\
|
||||
case 1:\
|
||||
stb(ptr, (typeof(*ptr))(x));\
|
||||
break;\
|
||||
case 2:\
|
||||
stw(ptr, (typeof(*ptr))(x));\
|
||||
break;\
|
||||
case 4:\
|
||||
stl(ptr, (typeof(*ptr))(x));\
|
||||
break;\
|
||||
case 8:\
|
||||
stq(ptr, (typeof(*ptr))(x));\
|
||||
break;\
|
||||
default:\
|
||||
abort();\
|
||||
}\
|
||||
0;\
|
||||
})
|
||||
|
||||
#define __get_user(x, ptr) \
|
||||
({\
|
||||
int size = sizeof(*ptr);\
|
||||
switch(size) {\
|
||||
case 1:\
|
||||
x = (typeof(*ptr))ldub(ptr);\
|
||||
break;\
|
||||
case 2:\
|
||||
x = (typeof(*ptr))lduw(ptr);\
|
||||
break;\
|
||||
case 4:\
|
||||
x = (typeof(*ptr))ldl(ptr);\
|
||||
break;\
|
||||
case 8:\
|
||||
x = (typeof(*ptr))ldq(ptr);\
|
||||
break;\
|
||||
default:\
|
||||
abort();\
|
||||
}\
|
||||
0;\
|
||||
})
|
||||
|
||||
|
||||
#define __copy_to_user(dst, src, size)\
|
||||
({\
|
||||
memcpy(dst, src, size);\
|
||||
0;\
|
||||
})
|
||||
|
||||
#define __copy_from_user(dst, src, size)\
|
||||
({\
|
||||
memcpy(dst, src, size);\
|
||||
0;\
|
||||
})
|
||||
|
||||
#define __clear_user(dst, size)\
|
||||
({\
|
||||
memset(dst, 0, size);\
|
||||
0;\
|
||||
})
|
||||
|
||||
#ifndef offsetof
|
||||
#define offsetof(type, field) ((size_t) &((type *)0)->field)
|
||||
#endif
|
||||
@@ -705,14 +661,12 @@ static void setup_frame(int sig, struct emulated_sigaction *ka,
|
||||
target_sigset_t *set, CPUX86State *env)
|
||||
{
|
||||
struct sigframe *frame;
|
||||
int err = 0;
|
||||
int i, err = 0;
|
||||
|
||||
frame = get_sigframe(ka, env, sizeof(*frame));
|
||||
|
||||
#if 0
|
||||
if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
|
||||
goto give_sigsegv;
|
||||
#endif
|
||||
err |= __put_user((/*current->exec_domain
|
||||
&& current->exec_domain->signal_invmap
|
||||
&& sig < 32
|
||||
@@ -726,12 +680,10 @@ static void setup_frame(int sig, struct emulated_sigaction *ka,
|
||||
if (err)
|
||||
goto give_sigsegv;
|
||||
|
||||
if (TARGET_NSIG_WORDS > 1) {
|
||||
err |= __copy_to_user(frame->extramask, &set->sig[1],
|
||||
sizeof(frame->extramask));
|
||||
}
|
||||
if (err)
|
||||
goto give_sigsegv;
|
||||
for(i = 1; i < TARGET_NSIG_WORDS; i++) {
|
||||
if (__put_user(set->sig[i], &frame->extramask[i - 1]))
|
||||
goto give_sigsegv;
|
||||
}
|
||||
|
||||
/* Set up to return from userspace. If provided, use a stub
|
||||
already in userspace. */
|
||||
@@ -771,14 +723,12 @@ static void setup_rt_frame(int sig, struct emulated_sigaction *ka,
|
||||
target_sigset_t *set, CPUX86State *env)
|
||||
{
|
||||
struct rt_sigframe *frame;
|
||||
int err = 0;
|
||||
int i, err = 0;
|
||||
|
||||
frame = get_sigframe(ka, env, sizeof(*frame));
|
||||
|
||||
#if 0
|
||||
if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
|
||||
goto give_sigsegv;
|
||||
#endif
|
||||
|
||||
err |= __put_user((/*current->exec_domain
|
||||
&& current->exec_domain->signal_invmap
|
||||
@@ -801,9 +751,10 @@ static void setup_rt_frame(int sig, struct emulated_sigaction *ka,
|
||||
err |= __put_user(/* current->sas_ss_size */ 0, &frame->uc.uc_stack.ss_size);
|
||||
err |= setup_sigcontext(&frame->uc.uc_mcontext, &frame->fpstate,
|
||||
env, set->sig[0]);
|
||||
err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
|
||||
if (err)
|
||||
goto give_sigsegv;
|
||||
for(i = 0; i < TARGET_NSIG_WORDS; i++) {
|
||||
if (__put_user(set->sig[i], &frame->uc.uc_sigmask.sig[i]))
|
||||
goto give_sigsegv;
|
||||
}
|
||||
|
||||
/* Set up to return from userspace. If provided, use a stub
|
||||
already in userspace. */
|
||||
@@ -898,11 +849,14 @@ long do_sigreturn(CPUX86State *env)
|
||||
fprintf(stderr, "do_sigreturn\n");
|
||||
#endif
|
||||
/* set blocked signals */
|
||||
target_set.sig[0] = frame->sc.oldmask;
|
||||
for(i = 1; i < TARGET_NSIG_WORDS; i++)
|
||||
target_set.sig[i] = frame->extramask[i - 1];
|
||||
if (__get_user(target_set.sig[0], &frame->sc.oldmask))
|
||||
goto badframe;
|
||||
for(i = 1; i < TARGET_NSIG_WORDS; i++) {
|
||||
if (__get_user(target_set.sig[i], &frame->extramask[i - 1]))
|
||||
goto badframe;
|
||||
}
|
||||
|
||||
target_to_host_sigset(&set, &target_set);
|
||||
target_to_host_sigset_internal(&set, &target_set);
|
||||
sigprocmask(SIG_SETMASK, &set, NULL);
|
||||
|
||||
/* restore registers */
|
||||
@@ -918,7 +872,6 @@ badframe:
|
||||
long do_rt_sigreturn(CPUX86State *env)
|
||||
{
|
||||
struct rt_sigframe *frame = (struct rt_sigframe *)(env->regs[R_ESP] - 4);
|
||||
target_sigset_t target_set;
|
||||
sigset_t set;
|
||||
// stack_t st;
|
||||
int eax;
|
||||
@@ -927,9 +880,7 @@ long do_rt_sigreturn(CPUX86State *env)
|
||||
if (verify_area(VERIFY_READ, frame, sizeof(*frame)))
|
||||
goto badframe;
|
||||
#endif
|
||||
memcpy(&target_set, &frame->uc.uc_sigmask, sizeof(target_sigset_t));
|
||||
|
||||
target_to_host_sigset(&set, &target_set);
|
||||
target_to_host_sigset(&set, &frame->uc.uc_sigmask);
|
||||
sigprocmask(SIG_SETMASK, &set, NULL);
|
||||
|
||||
if (restore_sigcontext(env, &frame->uc.uc_mcontext, &eax))
|
||||
@@ -1153,13 +1104,13 @@ static void setup_frame(int usig, struct emulated_sigaction *ka,
|
||||
target_sigset_t *set, CPUState *regs)
|
||||
{
|
||||
struct sigframe *frame = get_sigframe(ka, regs, sizeof(*frame));
|
||||
int err = 0;
|
||||
int i, err = 0;
|
||||
|
||||
err |= setup_sigcontext(&frame->sc, /*&frame->fpstate,*/ regs, set->sig[0]);
|
||||
|
||||
if (TARGET_NSIG_WORDS > 1) {
|
||||
err |= __copy_to_user(frame->extramask, &set->sig[1],
|
||||
sizeof(frame->extramask));
|
||||
for(i = 1; i < TARGET_NSIG_WORDS; i++) {
|
||||
if (__put_user(set->sig[i], &frame->extramask[i - 1]))
|
||||
return;
|
||||
}
|
||||
|
||||
if (err == 0)
|
||||
@@ -1172,12 +1123,11 @@ static void setup_rt_frame(int usig, struct emulated_sigaction *ka,
|
||||
target_sigset_t *set, CPUState *env)
|
||||
{
|
||||
struct rt_sigframe *frame = get_sigframe(ka, env, sizeof(*frame));
|
||||
int err = 0;
|
||||
int i, err = 0;
|
||||
|
||||
#if 0
|
||||
if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame)))
|
||||
return 1;
|
||||
#endif
|
||||
return /* 1 */;
|
||||
|
||||
__put_user_error(&frame->info, (target_ulong *)&frame->pinfo, err);
|
||||
__put_user_error(&frame->uc, (target_ulong *)&frame->puc, err);
|
||||
err |= copy_siginfo_to_user(&frame->info, info);
|
||||
@@ -1187,7 +1137,10 @@ static void setup_rt_frame(int usig, struct emulated_sigaction *ka,
|
||||
|
||||
err |= setup_sigcontext(&frame->uc.uc_mcontext, /*&frame->fpstate,*/
|
||||
env, set->sig[0]);
|
||||
err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
|
||||
for(i = 0; i < TARGET_NSIG_WORDS; i++) {
|
||||
if (__put_user(set->sig[i], &frame->uc.uc_sigmask.sig[i]))
|
||||
return;
|
||||
}
|
||||
|
||||
if (err == 0)
|
||||
err = setup_return(env, ka, &frame->retcode, frame, usig);
|
||||
@@ -1240,6 +1193,7 @@ long do_sigreturn(CPUState *env)
|
||||
struct sigframe *frame;
|
||||
target_sigset_t set;
|
||||
sigset_t host_set;
|
||||
int i;
|
||||
|
||||
/*
|
||||
* Since we stacked the signal on a 64-bit boundary,
|
||||
@@ -1255,13 +1209,14 @@ long do_sigreturn(CPUState *env)
|
||||
if (verify_area(VERIFY_READ, frame, sizeof (*frame)))
|
||||
goto badframe;
|
||||
#endif
|
||||
if (__get_user(set.sig[0], &frame->sc.oldmask)
|
||||
|| (TARGET_NSIG_WORDS > 1
|
||||
&& __copy_from_user(&set.sig[1], &frame->extramask,
|
||||
sizeof(frame->extramask))))
|
||||
goto badframe;
|
||||
if (__get_user(set.sig[0], &frame->sc.oldmask))
|
||||
goto badframe;
|
||||
for(i = 1; i < TARGET_NSIG_WORDS; i++) {
|
||||
if (__get_user(set.sig[i], &frame->extramask[i - 1]))
|
||||
goto badframe;
|
||||
}
|
||||
|
||||
target_to_host_sigset(&host_set, &set);
|
||||
target_to_host_sigset_internal(&host_set, &set);
|
||||
sigprocmask(SIG_SETMASK, &host_set, NULL);
|
||||
|
||||
if (restore_sigcontext(env, &frame->sc))
|
||||
@@ -1282,7 +1237,6 @@ badframe:
|
||||
long do_rt_sigreturn(CPUState *env)
|
||||
{
|
||||
struct rt_sigframe *frame;
|
||||
target_sigset_t set;
|
||||
sigset_t host_set;
|
||||
|
||||
/*
|
||||
@@ -1299,10 +1253,7 @@ long do_rt_sigreturn(CPUState *env)
|
||||
if (verify_area(VERIFY_READ, frame, sizeof (*frame)))
|
||||
goto badframe;
|
||||
#endif
|
||||
if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
|
||||
goto badframe;
|
||||
|
||||
target_to_host_sigset(&host_set, &set);
|
||||
target_to_host_sigset(&host_set, &frame->uc.uc_sigmask);
|
||||
sigprocmask(SIG_SETMASK, &host_set, NULL);
|
||||
|
||||
if (restore_sigcontext(env, &frame->uc.uc_mcontext))
|
||||
@@ -1405,7 +1356,7 @@ void process_pending_signals(void *cpu_env)
|
||||
sigprocmask(SIG_BLOCK, &set, &old_set);
|
||||
/* save the previous blocked signal state to restore it at the
|
||||
end of the signal execution (see do_sigreturn) */
|
||||
host_to_target_sigset(&target_old_set, &old_set);
|
||||
host_to_target_sigset_internal(&target_old_set, &old_set);
|
||||
|
||||
/* if the CPU is in VM86 mode, we restore the 32 bit values */
|
||||
#ifdef TARGET_I386
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
struct target_pt_regs {
|
||||
target_ulong psr;
|
||||
target_ulong pc;
|
||||
target_ulong npc;
|
||||
target_ulong y;
|
||||
target_ulong u_regs[16];
|
||||
};
|
||||
@@ -0,0 +1,220 @@
|
||||
#define TARGET_NR_exit 1 /* Common */
|
||||
#define TARGET_NR_fork 2 /* Common */
|
||||
#define TARGET_NR_read 3 /* Common */
|
||||
#define TARGET_NR_write 4 /* Common */
|
||||
#define TARGET_NR_open 5 /* Common */
|
||||
#define TARGET_NR_close 6 /* Common */
|
||||
#define TARGET_NR_wait4 7 /* Common */
|
||||
#define TARGET_NR_creat 8 /* Common */
|
||||
#define TARGET_NR_link 9 /* Common */
|
||||
#define TARGET_NR_unlink 10 /* Common */
|
||||
#define TARGET_NR_execv 11 /* SunOS Specific */
|
||||
#define TARGET_NR_chdir 12 /* Common */
|
||||
#define TARGET_NR_chown 13 /* Common */
|
||||
#define TARGET_NR_mknod 14 /* Common */
|
||||
#define TARGET_NR_chmod 15 /* Common */
|
||||
#define TARGET_NR_lchown 16 /* Common */
|
||||
#define TARGET_NR_brk 17 /* Common */
|
||||
#define TARGET_NR_perfctr 18 /* Performance counter operations */
|
||||
#define TARGET_NR_lseek 19 /* Common */
|
||||
#define TARGET_NR_getpid 20 /* Common */
|
||||
#define TARGET_NR_capget 21 /* Linux Specific */
|
||||
#define TARGET_NR_capset 22 /* Linux Specific */
|
||||
#define TARGET_NR_setuid 23 /* Implemented via setreuid in SunOS */
|
||||
#define TARGET_NR_getuid 24 /* Common */
|
||||
#define TARGET_NR_ptrace 26 /* Common */
|
||||
#define TARGET_NR_alarm 27 /* Implemented via setitimer in SunOS */
|
||||
#define TARGET_NR_sigaltstack 28 /* Common */
|
||||
#define TARGET_NR_pause 29 /* Is sigblock(0)->sigpause() in SunOS */
|
||||
#define TARGET_NR_utime 30 /* Implemented via utimes() under SunOS */
|
||||
#define TARGET_NR_lchown32 31 /* Linux sparc32 specific */
|
||||
#define TARGET_NR_fchown32 32 /* Linux sparc32 specific */
|
||||
#define TARGET_NR_access 33 /* Common */
|
||||
#define TARGET_NR_nice 34 /* Implemented via get/setpriority() in SunOS */
|
||||
#define TARGET_NR_chown32 35 /* Linux sparc32 specific */
|
||||
#define TARGET_NR_sync 36 /* Common */
|
||||
#define TARGET_NR_kill 37 /* Common */
|
||||
#define TARGET_NR_stat 38 /* Common */
|
||||
#define TARGET_NR_sendfile 39 /* Linux Specific */
|
||||
#define TARGET_NR_lstat 40 /* Common */
|
||||
#define TARGET_NR_dup 41 /* Common */
|
||||
#define TARGET_NR_pipe 42 /* Common */
|
||||
#define TARGET_NR_times 43 /* Implemented via getrusage() in SunOS */
|
||||
#define TARGET_NR_getuid32 44 /* Linux sparc32 specific */
|
||||
#define TARGET_NR_umount2 45 /* Linux Specific */
|
||||
#define TARGET_NR_setgid 46 /* Implemented via setregid() in SunOS */
|
||||
#define TARGET_NR_getgid 47 /* Common */
|
||||
#define TARGET_NR_signal 48 /* Implemented via sigvec() in SunOS */
|
||||
#define TARGET_NR_geteuid 49 /* SunOS calls getuid() */
|
||||
#define TARGET_NR_getegid 50 /* SunOS calls getgid() */
|
||||
#define TARGET_NR_acct 51 /* Common */
|
||||
#define TARGET_NR_getgid32 53 /* Linux sparc32 specific */
|
||||
#define TARGET_NR_ioctl 54 /* Common */
|
||||
#define TARGET_NR_reboot 55 /* Common */
|
||||
#define TARGET_NR_mmap2 56 /* Linux sparc32 Specific */
|
||||
#define TARGET_NR_symlink 57 /* Common */
|
||||
#define TARGET_NR_readlink 58 /* Common */
|
||||
#define TARGET_NR_execve 59 /* Common */
|
||||
#define TARGET_NR_umask 60 /* Common */
|
||||
#define TARGET_NR_chroot 61 /* Common */
|
||||
#define TARGET_NR_fstat 62 /* Common */
|
||||
#define TARGET_NR_fstat64 63 /* Linux sparc32 Specific */
|
||||
#define TARGET_NR_getpagesize 64 /* Common */
|
||||
#define TARGET_NR_msync 65 /* Common in newer 1.3.x revs... */
|
||||
#define TARGET_NR_vfork 66 /* Common */
|
||||
#define TARGET_NR_pread 67 /* Linux Specific */
|
||||
#define TARGET_NR_pwrite 68 /* Linux Specific */
|
||||
#define TARGET_NR_geteuid32 69 /* Linux sparc32, sbrk under SunOS */
|
||||
#define TARGET_NR_getegid32 70 /* Linux sparc32, sstk under SunOS */
|
||||
#define TARGET_NR_mmap 71 /* Common */
|
||||
#define TARGET_NR_setreuid32 72 /* Linux sparc32, vadvise under SunOS */
|
||||
#define TARGET_NR_munmap 73 /* Common */
|
||||
#define TARGET_NR_mprotect 74 /* Common */
|
||||
#define TARGET_NR_madvise 75 /* Common */
|
||||
#define TARGET_NR_vhangup 76 /* Common */
|
||||
#define TARGET_NR_truncate64 77 /* Linux sparc32 Specific */
|
||||
#define TARGET_NR_mincore 78 /* Common */
|
||||
#define TARGET_NR_getgroups 79 /* Common */
|
||||
#define TARGET_NR_setgroups 80 /* Common */
|
||||
#define TARGET_NR_getpgrp 81 /* Common */
|
||||
#define TARGET_NR_setgroups32 82 /* Linux sparc32, setpgrp under SunOS */
|
||||
#define TARGET_NR_setitimer 83 /* Common */
|
||||
#define TARGET_NR_ftruncate64 84 /* Linux sparc32 Specific */
|
||||
#define TARGET_NR_swapon 85 /* Common */
|
||||
#define TARGET_NR_getitimer 86 /* Common */
|
||||
#define TARGET_NR_setuid32 87 /* Linux sparc32, gethostname under SunOS */
|
||||
#define TARGET_NR_sethostname 88 /* Common */
|
||||
#define TARGET_NR_setgid32 89 /* Linux sparc32, getdtablesize under SunOS */
|
||||
#define TARGET_NR_dup2 90 /* Common */
|
||||
#define TARGET_NR_setfsuid32 91 /* Linux sparc32, getdopt under SunOS */
|
||||
#define TARGET_NR_fcntl 92 /* Common */
|
||||
#define TARGET_NR_select 93 /* Common */
|
||||
#define TARGET_NR_setfsgid32 94 /* Linux sparc32, setdopt under SunOS */
|
||||
#define TARGET_NR_fsync 95 /* Common */
|
||||
#define TARGET_NR_setpriority 96 /* Common */
|
||||
#define TARGET_NR_socket 97 /* Common */
|
||||
#define TARGET_NR_connect 98 /* Common */
|
||||
#define TARGET_NR_accept 99 /* Common */
|
||||
#define TARGET_NR_getpriority 100 /* Common */
|
||||
#define TARGET_NR_rt_sigreturn 101 /* Linux Specific */
|
||||
#define TARGET_NR_rt_sigaction 102 /* Linux Specific */
|
||||
#define TARGET_NR_rt_sigprocmask 103 /* Linux Specific */
|
||||
#define TARGET_NR_rt_sigpending 104 /* Linux Specific */
|
||||
#define TARGET_NR_rt_sigtimedwait 105 /* Linux Specific */
|
||||
#define TARGET_NR_rt_sigqueueinfo 106 /* Linux Specific */
|
||||
#define TARGET_NR_rt_sigsuspend 107 /* Linux Specific */
|
||||
#define TARGET_NR_setresuid32 108 /* Linux Specific, sigvec under SunOS */
|
||||
#define TARGET_NR_getresuid32 109 /* Linux Specific, sigblock under SunOS */
|
||||
#define TARGET_NR_setresgid32 110 /* Linux Specific, sigsetmask under SunOS */
|
||||
#define TARGET_NR_getresgid32 111 /* Linux Specific, sigpause under SunOS */
|
||||
#define TARGET_NR_setregid32 112 /* Linux sparc32, sigstack under SunOS */
|
||||
#define TARGET_NR_recvmsg 113 /* Common */
|
||||
#define TARGET_NR_sendmsg 114 /* Common */
|
||||
#define TARGET_NR_getgroups32 115 /* Linux sparc32, vtrace under SunOS */
|
||||
#define TARGET_NR_gettimeofday 116 /* Common */
|
||||
#define TARGET_NR_getrusage 117 /* Common */
|
||||
#define TARGET_NR_getsockopt 118 /* Common */
|
||||
#define TARGET_NR_getcwd 119 /* Linux Specific */
|
||||
#define TARGET_NR_readv 120 /* Common */
|
||||
#define TARGET_NR_writev 121 /* Common */
|
||||
#define TARGET_NR_settimeofday 122 /* Common */
|
||||
#define TARGET_NR_fchown 123 /* Common */
|
||||
#define TARGET_NR_fchmod 124 /* Common */
|
||||
#define TARGET_NR_recvfrom 125 /* Common */
|
||||
#define TARGET_NR_setreuid 126 /* Common */
|
||||
#define TARGET_NR_setregid 127 /* Common */
|
||||
#define TARGET_NR_rename 128 /* Common */
|
||||
#define TARGET_NR_truncate 129 /* Common */
|
||||
#define TARGET_NR_ftruncate 130 /* Common */
|
||||
#define TARGET_NR_flock 131 /* Common */
|
||||
#define TARGET_NR_lstat64 132 /* Linux sparc32 Specific */
|
||||
#define TARGET_NR_sendto 133 /* Common */
|
||||
#define TARGET_NR_shutdown 134 /* Common */
|
||||
#define TARGET_NR_socketpair 135 /* Common */
|
||||
#define TARGET_NR_mkdir 136 /* Common */
|
||||
#define TARGET_NR_rmdir 137 /* Common */
|
||||
#define TARGET_NR_utimes 138 /* SunOS Specific */
|
||||
#define TARGET_NR_stat64 139 /* Linux sparc32 Specific */
|
||||
#define TARGET_NR_getpeername 141 /* Common */
|
||||
#define TARGET_NR_gettid 143 /* ENOSYS under SunOS */
|
||||
#define TARGET_NR_getrlimit 144 /* Common */
|
||||
#define TARGET_NR_setrlimit 145 /* Common */
|
||||
#define TARGET_NR_pivot_root 146 /* Linux Specific, killpg under SunOS */
|
||||
#define TARGET_NR_prctl 147 /* ENOSYS under SunOS */
|
||||
#define TARGET_NR_pciconfig_read 148 /* ENOSYS under SunOS */
|
||||
#define TARGET_NR_pciconfig_write 149 /* ENOSYS under SunOS */
|
||||
#define TARGET_NR_getsockname 150 /* Common */
|
||||
#define TARGET_NR_poll 153 /* Common */
|
||||
#define TARGET_NR_getdents64 154 /* Linux specific */
|
||||
#define TARGET_NR_fcntl64 155 /* Linux sparc32 Specific */
|
||||
#define TARGET_NR_statfs 157 /* Common */
|
||||
#define TARGET_NR_fstatfs 158 /* Common */
|
||||
#define TARGET_NR_umount 159 /* Common */
|
||||
#define TARGET_NR_getdomainname 162 /* SunOS Specific */
|
||||
#define TARGET_NR_setdomainname 163 /* Common */
|
||||
#define TARGET_NR_quotactl 165 /* Common */
|
||||
#define TARGET_NR_mount 167 /* Common */
|
||||
#define TARGET_NR_ustat 168 /* Common */
|
||||
#define TARGET_NR_getdents 174 /* Common */
|
||||
#define TARGET_NR_setsid 175 /* Common */
|
||||
#define TARGET_NR_fchdir 176 /* Common */
|
||||
#define TARGET_NR_sigpending 183 /* Common */
|
||||
#define TARGET_NR_query_module 184 /* Linux Specific */
|
||||
#define TARGET_NR_setpgid 185 /* Common */
|
||||
#define TARGET_NR_tkill 187 /* SunOS: fpathconf */
|
||||
#define TARGET_NR_exit_group 188 /* Linux specific, sysconf undef SunOS */
|
||||
#define TARGET_NR_uname 189 /* Linux Specific */
|
||||
#define TARGET_NR_init_module 190 /* Linux Specific */
|
||||
#define TARGET_NR_personality 191 /* Linux Specific */
|
||||
#define TARGET_NR_getppid 197 /* Linux Specific */
|
||||
#define TARGET_NR_sigaction 198 /* Linux Specific */
|
||||
#define TARGET_NR_sgetmask 199 /* Linux Specific */
|
||||
#define TARGET_NR_ssetmask 200 /* Linux Specific */
|
||||
#define TARGET_NR_sigsuspend 201 /* Linux Specific */
|
||||
#define TARGET_NR_oldlstat 202 /* Linux Specific */
|
||||
#define TARGET_NR_uselib 203 /* Linux Specific */
|
||||
#define TARGET_NR_readdir 204 /* Linux Specific */
|
||||
#define TARGET_NR_readahead 205 /* Linux Specific */
|
||||
#define TARGET_NR_socketcall 206 /* Linux Specific */
|
||||
#define TARGET_NR_syslog 207 /* Linux Specific */
|
||||
#define TARGET_NR_waitpid 212 /* Linux Specific */
|
||||
#define TARGET_NR_swapoff 213 /* Linux Specific */
|
||||
#define TARGET_NR_sysinfo 214 /* Linux Specific */
|
||||
#define TARGET_NR_ipc 215 /* Linux Specific */
|
||||
#define TARGET_NR_sigreturn 216 /* Linux Specific */
|
||||
#define TARGET_NR_clone 217 /* Linux Specific */
|
||||
#define TARGET_NR_adjtimex 219 /* Linux Specific */
|
||||
#define TARGET_NR_sigprocmask 220 /* Linux Specific */
|
||||
#define TARGET_NR_create_module 221 /* Linux Specific */
|
||||
#define TARGET_NR_delete_module 222 /* Linux Specific */
|
||||
#define TARGET_NR_get_kernel_syms 223 /* Linux Specific */
|
||||
#define TARGET_NR_getpgid 224 /* Linux Specific */
|
||||
#define TARGET_NR_bdflush 225 /* Linux Specific */
|
||||
#define TARGET_NR_sysfs 226 /* Linux Specific */
|
||||
#define TARGET_NR_afs_syscall 227 /* Linux Specific */
|
||||
#define TARGET_NR_setfsuid 228 /* Linux Specific */
|
||||
#define TARGET_NR_setfsgid 229 /* Linux Specific */
|
||||
#define TARGET_NR__newselect 230 /* Linux Specific */
|
||||
#define TARGET_NR_time 231 /* Linux Specific */
|
||||
#define TARGET_NR_stime 233 /* Linux Specific */
|
||||
#define TARGET_NR__llseek 236 /* Linux Specific */
|
||||
#define TARGET_NR_mlock 237
|
||||
#define TARGET_NR_munlock 238
|
||||
#define TARGET_NR_mlockall 239
|
||||
#define TARGET_NR_munlockall 240
|
||||
#define TARGET_NR_sched_setparam 241
|
||||
#define TARGET_NR_sched_getparam 242
|
||||
#define TARGET_NR_sched_setscheduler 243
|
||||
#define TARGET_NR_sched_getscheduler 244
|
||||
#define TARGET_NR_sched_yield 245
|
||||
#define TARGET_NR_sched_get_priority_max 246
|
||||
#define TARGET_NR_sched_get_priority_min 247
|
||||
#define TARGET_NR_sched_rr_get_interval 248
|
||||
#define TARGET_NR_nanosleep 249
|
||||
#define TARGET_NR_mremap 250
|
||||
#define TARGET_NR__sysctl 251
|
||||
#define TARGET_NR_getsid 252
|
||||
#define TARGET_NR_fdatasync 253
|
||||
#define TARGET_NR_nfsservctl 254
|
||||
#define TARGET_NR_aplib 255
|
||||
#define TARGET_NR__exit TARGET_NR_exit
|
||||
@@ -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 */
|
||||
|
||||
+646
-178
File diff suppressed because it is too large.
Load diff
+229
-490
@@ -4,284 +4,7 @@
|
||||
most of them stay the same, so we handle it by puting ifdefs if
|
||||
necessary */
|
||||
|
||||
#define TARGET_NR_exit 1
|
||||
#define TARGET_NR_fork 2
|
||||
#define TARGET_NR_read 3
|
||||
#define TARGET_NR_write 4
|
||||
#define TARGET_NR_open 5
|
||||
#define TARGET_NR_close 6
|
||||
#define TARGET_NR_waitpid 7
|
||||
#define TARGET_NR_creat 8
|
||||
#define TARGET_NR_link 9
|
||||
#define TARGET_NR_unlink 10
|
||||
#define TARGET_NR_execve 11
|
||||
#define TARGET_NR_chdir 12
|
||||
#define TARGET_NR_time 13
|
||||
#define TARGET_NR_mknod 14
|
||||
#define TARGET_NR_chmod 15
|
||||
#define TARGET_NR_lchown 16
|
||||
#define TARGET_NR_break 17
|
||||
#define TARGET_NR_oldstat 18
|
||||
#define TARGET_NR_lseek 19
|
||||
#define TARGET_NR_getpid 20
|
||||
#define TARGET_NR_mount 21
|
||||
#define TARGET_NR_umount 22
|
||||
#define TARGET_NR_setuid 23
|
||||
#define TARGET_NR_getuid 24
|
||||
#define TARGET_NR_stime 25
|
||||
#define TARGET_NR_ptrace 26
|
||||
#define TARGET_NR_alarm 27
|
||||
#define TARGET_NR_oldfstat 28
|
||||
#define TARGET_NR_pause 29
|
||||
#define TARGET_NR_utime 30
|
||||
#define TARGET_NR_stty 31
|
||||
#define TARGET_NR_gtty 32
|
||||
#define TARGET_NR_access 33
|
||||
#define TARGET_NR_nice 34
|
||||
#define TARGET_NR_ftime 35
|
||||
#define TARGET_NR_sync 36
|
||||
#define TARGET_NR_kill 37
|
||||
#define TARGET_NR_rename 38
|
||||
#define TARGET_NR_mkdir 39
|
||||
#define TARGET_NR_rmdir 40
|
||||
#define TARGET_NR_dup 41
|
||||
#define TARGET_NR_pipe 42
|
||||
#define TARGET_NR_times 43
|
||||
#define TARGET_NR_prof 44
|
||||
#define TARGET_NR_brk 45
|
||||
#define TARGET_NR_setgid 46
|
||||
#define TARGET_NR_getgid 47
|
||||
#define TARGET_NR_signal 48
|
||||
#define TARGET_NR_geteuid 49
|
||||
#define TARGET_NR_getegid 50
|
||||
#define TARGET_NR_acct 51
|
||||
#define TARGET_NR_umount2 52
|
||||
#define TARGET_NR_lock 53
|
||||
#define TARGET_NR_ioctl 54
|
||||
#define TARGET_NR_fcntl 55
|
||||
#define TARGET_NR_mpx 56
|
||||
#define TARGET_NR_setpgid 57
|
||||
#define TARGET_NR_ulimit 58
|
||||
#define TARGET_NR_oldolduname 59
|
||||
#define TARGET_NR_umask 60
|
||||
#define TARGET_NR_chroot 61
|
||||
#define TARGET_NR_ustat 62
|
||||
#define TARGET_NR_dup2 63
|
||||
#define TARGET_NR_getppid 64
|
||||
#define TARGET_NR_getpgrp 65
|
||||
#define TARGET_NR_setsid 66
|
||||
#define TARGET_NR_sigaction 67
|
||||
#define TARGET_NR_sgetmask 68
|
||||
#define TARGET_NR_ssetmask 69
|
||||
#define TARGET_NR_setreuid 70
|
||||
#define TARGET_NR_setregid 71
|
||||
#define TARGET_NR_sigsuspend 72
|
||||
#define TARGET_NR_sigpending 73
|
||||
#define TARGET_NR_sethostname 74
|
||||
#define TARGET_NR_setrlimit 75
|
||||
#define TARGET_NR_getrlimit 76 /* Back compatible 2Gig limited rlimit */
|
||||
#define TARGET_NR_getrusage 77
|
||||
#define TARGET_NR_gettimeofday 78
|
||||
#define TARGET_NR_settimeofday 79
|
||||
#define TARGET_NR_getgroups 80
|
||||
#define TARGET_NR_setgroups 81
|
||||
#define TARGET_NR_select 82
|
||||
#define TARGET_NR_symlink 83
|
||||
#define TARGET_NR_oldlstat 84
|
||||
#define TARGET_NR_readlink 85
|
||||
#define TARGET_NR_uselib 86
|
||||
#define TARGET_NR_swapon 87
|
||||
#define TARGET_NR_reboot 88
|
||||
#define TARGET_NR_readdir 89
|
||||
#define TARGET_NR_mmap 90
|
||||
#define TARGET_NR_munmap 91
|
||||
#define TARGET_NR_truncate 92
|
||||
#define TARGET_NR_ftruncate 93
|
||||
#define TARGET_NR_fchmod 94
|
||||
#define TARGET_NR_fchown 95
|
||||
#define TARGET_NR_getpriority 96
|
||||
#define TARGET_NR_setpriority 97
|
||||
#define TARGET_NR_profil 98
|
||||
#define TARGET_NR_statfs 99
|
||||
#define TARGET_NR_fstatfs 100
|
||||
#define TARGET_NR_ioperm 101
|
||||
#define TARGET_NR_socketcall 102
|
||||
#define TARGET_NR_syslog 103
|
||||
#define TARGET_NR_setitimer 104
|
||||
#define TARGET_NR_getitimer 105
|
||||
#define TARGET_NR_stat 106
|
||||
#define TARGET_NR_lstat 107
|
||||
#define TARGET_NR_fstat 108
|
||||
#define TARGET_NR_olduname 109
|
||||
#define TARGET_NR_iopl 110
|
||||
#define TARGET_NR_vhangup 111
|
||||
#define TARGET_NR_idle 112
|
||||
#define TARGET_NR_vm86old 113
|
||||
#define TARGET_NR_wait4 114
|
||||
#define TARGET_NR_swapoff 115
|
||||
#define TARGET_NR_sysinfo 116
|
||||
#define TARGET_NR_ipc 117
|
||||
#define TARGET_NR_fsync 118
|
||||
#define TARGET_NR_sigreturn 119
|
||||
#define TARGET_NR_clone 120
|
||||
#define TARGET_NR_setdomainname 121
|
||||
#define TARGET_NR_uname 122
|
||||
#define TARGET_NR_modify_ldt 123
|
||||
#define TARGET_NR_adjtimex 124
|
||||
#define TARGET_NR_mprotect 125
|
||||
#define TARGET_NR_sigprocmask 126
|
||||
#define TARGET_NR_create_module 127
|
||||
#define TARGET_NR_init_module 128
|
||||
#define TARGET_NR_delete_module 129
|
||||
#define TARGET_NR_get_kernel_syms 130
|
||||
#define TARGET_NR_quotactl 131
|
||||
#define TARGET_NR_getpgid 132
|
||||
#define TARGET_NR_fchdir 133
|
||||
#define TARGET_NR_bdflush 134
|
||||
#define TARGET_NR_sysfs 135
|
||||
#define TARGET_NR_personality 136
|
||||
#define TARGET_NR_afs_syscall 137 /* Syscall for Andrew File System */
|
||||
#define TARGET_NR_setfsuid 138
|
||||
#define TARGET_NR_setfsgid 139
|
||||
#define TARGET_NR__llseek 140
|
||||
#define TARGET_NR_getdents 141
|
||||
#define TARGET_NR__newselect 142
|
||||
#define TARGET_NR_flock 143
|
||||
#define TARGET_NR_msync 144
|
||||
#define TARGET_NR_readv 145
|
||||
#define TARGET_NR_writev 146
|
||||
#define TARGET_NR_getsid 147
|
||||
#define TARGET_NR_fdatasync 148
|
||||
#define TARGET_NR__sysctl 149
|
||||
#define TARGET_NR_mlock 150
|
||||
#define TARGET_NR_munlock 151
|
||||
#define TARGET_NR_mlockall 152
|
||||
#define TARGET_NR_munlockall 153
|
||||
#define TARGET_NR_sched_setparam 154
|
||||
#define TARGET_NR_sched_getparam 155
|
||||
#define TARGET_NR_sched_setscheduler 156
|
||||
#define TARGET_NR_sched_getscheduler 157
|
||||
#define TARGET_NR_sched_yield 158
|
||||
#define TARGET_NR_sched_get_priority_max 159
|
||||
#define TARGET_NR_sched_get_priority_min 160
|
||||
#define TARGET_NR_sched_rr_get_interval 161
|
||||
#define TARGET_NR_nanosleep 162
|
||||
#define TARGET_NR_mremap 163
|
||||
#define TARGET_NR_setresuid 164
|
||||
#define TARGET_NR_getresuid 165
|
||||
#define TARGET_NR_vm86 166
|
||||
#define TARGET_NR_query_module 167
|
||||
#define TARGET_NR_poll 168
|
||||
#define TARGET_NR_nfsservctl 169
|
||||
#define TARGET_NR_setresgid 170
|
||||
#define TARGET_NR_getresgid 171
|
||||
#define TARGET_NR_prctl 172
|
||||
#define TARGET_NR_rt_sigreturn 173
|
||||
#define TARGET_NR_rt_sigaction 174
|
||||
#define TARGET_NR_rt_sigprocmask 175
|
||||
#define TARGET_NR_rt_sigpending 176
|
||||
#define TARGET_NR_rt_sigtimedwait 177
|
||||
#define TARGET_NR_rt_sigqueueinfo 178
|
||||
#define TARGET_NR_rt_sigsuspend 179
|
||||
#define TARGET_NR_pread 180
|
||||
#define TARGET_NR_pwrite 181
|
||||
#define TARGET_NR_chown 182
|
||||
#define TARGET_NR_getcwd 183
|
||||
#define TARGET_NR_capget 184
|
||||
#define TARGET_NR_capset 185
|
||||
#define TARGET_NR_sigaltstack 186
|
||||
#define TARGET_NR_sendfile 187
|
||||
#define TARGET_NR_getpmsg 188 /* some people actually want streams */
|
||||
#define TARGET_NR_putpmsg 189 /* some people actually want streams */
|
||||
#define TARGET_NR_vfork 190
|
||||
#define TARGET_NR_ugetrlimit 191 /* SuS compliant getrlimit */
|
||||
#define TARGET_NR_mmap2 192
|
||||
#define TARGET_NR_truncate64 193
|
||||
#define TARGET_NR_ftruncate64 194
|
||||
#define TARGET_NR_stat64 195
|
||||
#define TARGET_NR_lstat64 196
|
||||
#define TARGET_NR_fstat64 197
|
||||
#define TARGET_NR_lchown32 198
|
||||
#define TARGET_NR_getuid32 199
|
||||
#define TARGET_NR_getgid32 200
|
||||
#define TARGET_NR_geteuid32 201
|
||||
#define TARGET_NR_getegid32 202
|
||||
#define TARGET_NR_setreuid32 203
|
||||
#define TARGET_NR_setregid32 204
|
||||
#define TARGET_NR_getgroups32 205
|
||||
#define TARGET_NR_setgroups32 206
|
||||
#define TARGET_NR_fchown32 207
|
||||
#define TARGET_NR_setresuid32 208
|
||||
#define TARGET_NR_getresuid32 209
|
||||
#define TARGET_NR_setresgid32 210
|
||||
#define TARGET_NR_getresgid32 211
|
||||
#define TARGET_NR_chown32 212
|
||||
#define TARGET_NR_setuid32 213
|
||||
#define TARGET_NR_setgid32 214
|
||||
#define TARGET_NR_setfsuid32 215
|
||||
#define TARGET_NR_setfsgid32 216
|
||||
|
||||
#if defined(TARGET_I386)
|
||||
#define TARGET_NR_pivot_root 217
|
||||
#define TARGET_NR_mincore 218
|
||||
#define TARGET_NR_madvise 219
|
||||
#define TARGET_NR_madvise1 219 /* delete when C lib stub is removed */
|
||||
#define TARGET_NR_getdents64 220
|
||||
#endif
|
||||
|
||||
#if defined(TARGET_ARM)
|
||||
#define TARGET_NR_getdents64 217
|
||||
#define TARGET_NR_pivot_root 218
|
||||
#define TARGET_NR_mincore 219
|
||||
#define TARGET_NR_madvise 220
|
||||
#endif
|
||||
|
||||
#define TARGET_NR_fcntl64 221
|
||||
#define TARGET_NR_security 223 /* syscall for security modules */
|
||||
#define TARGET_NR_gettid 224
|
||||
#define TARGET_NR_readahead 225
|
||||
#define TARGET_NR_setxattr 226
|
||||
#define TARGET_NR_lsetxattr 227
|
||||
#define TARGET_NR_fsetxattr 228
|
||||
#define TARGET_NR_getxattr 229
|
||||
#define TARGET_NR_lgetxattr 230
|
||||
#define TARGET_NR_fgetxattr 231
|
||||
#define TARGET_NR_listxattr 232
|
||||
#define TARGET_NR_llistxattr 233
|
||||
#define TARGET_NR_flistxattr 234
|
||||
#define TARGET_NR_removexattr 235
|
||||
#define TARGET_NR_lremovexattr 236
|
||||
#define TARGET_NR_fremovexattr 237
|
||||
#define TARGET_NR_tkill 238
|
||||
#define TARGET_NR_sendfile64 239
|
||||
#define TARGET_NR_futex 240
|
||||
#define TARGET_NR_sched_setaffinity 241
|
||||
#define TARGET_NR_sched_getaffinity 242
|
||||
#define TARGET_NR_set_thread_area 243
|
||||
#define TARGET_NR_get_thread_area 244
|
||||
#define TARGET_NR_io_setup 245
|
||||
#define TARGET_NR_io_destroy 246
|
||||
#define TARGET_NR_io_getevents 247
|
||||
#define TARGET_NR_io_submit 248
|
||||
#define TARGET_NR_io_cancel 249
|
||||
#define TARGET_NR_fadvise64 250
|
||||
|
||||
#define TARGET_NR_exit_group 252
|
||||
#define TARGET_NR_lookup_dcookie 253
|
||||
#define TARGET_NR_epoll_create 254
|
||||
#define TARGET_NR_epoll_ctl 255
|
||||
#define TARGET_NR_epoll_wait 256
|
||||
#define TARGET_NR_remap_file_pages 257
|
||||
#define TARGET_NR_set_tid_address 258
|
||||
#define TARGET_NR_timer_create 259
|
||||
#define TARGET_NR_timer_settime (TARGET_NR_timer_create+1)
|
||||
#define TARGET_NR_timer_gettime (TARGET_NR_timer_create+2)
|
||||
#define TARGET_NR_timer_getoverrun (TARGET_NR_timer_create+3)
|
||||
#define TARGET_NR_timer_delete (TARGET_NR_timer_create+4)
|
||||
#define TARGET_NR_clock_settime (TARGET_NR_timer_create+5)
|
||||
#define TARGET_NR_clock_gettime (TARGET_NR_timer_create+6)
|
||||
#define TARGET_NR_clock_getres (TARGET_NR_timer_create+7)
|
||||
#define TARGET_NR_clock_nanosleep (TARGET_NR_timer_create+8)
|
||||
#include "syscall_nr.h"
|
||||
|
||||
#define SOCKOP_socket 1
|
||||
#define SOCKOP_bind 2
|
||||
@@ -301,6 +24,19 @@
|
||||
#define SOCKOP_sendmsg 16
|
||||
#define SOCKOP_recvmsg 17
|
||||
|
||||
#define IPCOP_semop 1
|
||||
#define IPCOP_semget 2
|
||||
#define IPCOP_semctl 3
|
||||
#define IPCOP_semtimedop 4
|
||||
#define IPCOP_msgsnd 11
|
||||
#define IPCOP_msgrcv 12
|
||||
#define IPCOP_msgget 13
|
||||
#define IPCOP_msgctl 14
|
||||
#define IPCOP_shmat 21
|
||||
#define IPCOP_shmdt 22
|
||||
#define IPCOP_shmget 23
|
||||
#define IPCOP_shmctl 24
|
||||
|
||||
/*
|
||||
* The following is for compatibility across the various Linux
|
||||
* platforms. The i386 ioctl numbering scheme doesn't really enforce
|
||||
@@ -321,7 +57,7 @@
|
||||
#define TARGET_IOC_WRITE 1U
|
||||
#define TARGET_IOC_READ 2U
|
||||
|
||||
#elif defined(TARGET_PPC) || defined(TARGET_ALPHA)
|
||||
#elif defined(TARGET_PPC) || defined(TARGET_ALPHA) || defined(TARGET_SPARC)
|
||||
|
||||
#define TARGET_IOC_SIZEBITS 13
|
||||
#define TARGET_IOC_DIRBITS 3
|
||||
@@ -392,6 +128,11 @@ struct target_tms {
|
||||
target_clock_t tms_cstime;
|
||||
};
|
||||
|
||||
struct target_utimbuf {
|
||||
target_long actime;
|
||||
target_long modtime;
|
||||
};
|
||||
|
||||
struct target_sel_arg_struct {
|
||||
target_long n;
|
||||
target_long inp, outp, exp;
|
||||
@@ -551,7 +292,7 @@ struct target_sigaction;
|
||||
int do_sigaction(int sig, const struct target_sigaction *act,
|
||||
struct target_sigaction *oact);
|
||||
|
||||
#if defined(TARGET_I386) || defined(TARGET_ARM)
|
||||
#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SPARC) || defined(TARGET_PPC)
|
||||
|
||||
#define TARGET_SA_NOCLDSTOP 0x00000001
|
||||
#define TARGET_SA_NOCLDWAIT 0x00000002 /* not supported yet */
|
||||
@@ -686,7 +427,14 @@ typedef struct target_siginfo {
|
||||
/*
|
||||
* SIGILL si_codes
|
||||
*/
|
||||
#define TARGET_ILL_ILLOPC (1) /* illegal opcode */
|
||||
#define TARGET_ILL_ILLOPN (2) /* illegal operand */
|
||||
#define TARGET_ILL_ILLADR (3) /* illegal addressing mode */
|
||||
#define TARGET_ILL_ILLTRP (4) /* illegal trap */
|
||||
#define TARGET_ILL_PRVOPC (5) /* privileged opcode */
|
||||
#define TARGET_ILL_PRVREG (6) /* privileged register */
|
||||
#define TARGET_ILL_COPROC (7) /* coprocessor error */
|
||||
#define TARGET_ILL_BADSTK (8) /* internal stack error */
|
||||
|
||||
/*
|
||||
* SIGFPE si_codes
|
||||
@@ -707,6 +455,13 @@ typedef struct target_siginfo {
|
||||
#define TARGET_SEGV_MAPERR (1) /* address not mapped to object */
|
||||
#define TARGET_SEGV_ACCERR (2) /* invalid permissions for mapped object */
|
||||
|
||||
/*
|
||||
* SIGBUS si_codes
|
||||
*/
|
||||
#define TARGET_BUS_ADRALN (1) /* invalid address alignment */
|
||||
#define TARGET_BUS_ADRERR (2) /* non-existant physical address */
|
||||
#define TARGET_BUS_OBJERR (3) /* object specific hardware error */
|
||||
|
||||
/*
|
||||
* SIGTRAP si_codes
|
||||
*/
|
||||
@@ -936,220 +691,26 @@ struct target_pollfd {
|
||||
#define TARGET_HDIO_SET_PIO_MODE 0x0327 /* reconfig interface to new speed */
|
||||
|
||||
|
||||
#if defined(TARGET_I386) || defined(TARGET_ARM)
|
||||
|
||||
/* 0x54 is just a magic number to make these relatively unique ('T') */
|
||||
|
||||
#define TARGET_TCGETS 0x5401
|
||||
#define TARGET_TCSETS 0x5402
|
||||
#define TARGET_TCSETSW 0x5403
|
||||
#define TARGET_TCSETSF 0x5404
|
||||
#define TARGET_TCGETA 0x5405
|
||||
#define TARGET_TCSETA 0x5406
|
||||
#define TARGET_TCSETAW 0x5407
|
||||
#define TARGET_TCSETAF 0x5408
|
||||
#define TARGET_TCSBRK 0x5409
|
||||
#define TARGET_TCXONC 0x540A
|
||||
#define TARGET_TCFLSH 0x540B
|
||||
#define TARGET_TIOCEXCL 0x540C
|
||||
#define TARGET_TIOCNXCL 0x540D
|
||||
#define TARGET_TIOCSCTTY 0x540E
|
||||
#define TARGET_TIOCGPGRP 0x540F
|
||||
#define TARGET_TIOCSPGRP 0x5410
|
||||
#define TARGET_TIOCOUTQ 0x5411
|
||||
#define TARGET_TIOCSTI 0x5412
|
||||
#define TARGET_TIOCGWINSZ 0x5413
|
||||
#define TARGET_TIOCSWINSZ 0x5414
|
||||
#define TARGET_TIOCMGET 0x5415
|
||||
#define TARGET_TIOCMBIS 0x5416
|
||||
#define TARGET_TIOCMBIC 0x5417
|
||||
#define TARGET_TIOCMSET 0x5418
|
||||
#define TARGET_TIOCGSOFTCAR 0x5419
|
||||
#define TARGET_TIOCSSOFTCAR 0x541A
|
||||
#define TARGET_FIONREAD 0x541B
|
||||
#define TARGET_TIOCINQ FIONREAD
|
||||
#define TARGET_TIOCLINUX 0x541C
|
||||
#define TARGET_TIOCCONS 0x541D
|
||||
#define TARGET_TIOCGSERIAL 0x541E
|
||||
#define TARGET_TIOCSSERIAL 0x541F
|
||||
#define TARGET_TIOCPKT 0x5420
|
||||
#define TARGET_FIONBIO 0x5421
|
||||
#define TARGET_TIOCNOTTY 0x5422
|
||||
#define TARGET_TIOCSETD 0x5423
|
||||
#define TARGET_TIOCGETD 0x5424
|
||||
#define TARGET_TCSBRKP 0x5425 /* Needed for POSIX tcsendbreak() */
|
||||
#define TARGET_TIOCTTYGSTRUCT 0x5426 /* For debugging only */
|
||||
#define TARGET_TIOCSBRK 0x5427 /* BSD compatibility */
|
||||
#define TARGET_TIOCCBRK 0x5428 /* BSD compatibility */
|
||||
#define TARGET_TIOCGSID 0x5429 /* Return the session ID of FD */
|
||||
#define TARGET_TIOCGPTN TARGET_IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */
|
||||
#define TARGET_TIOCSPTLCK TARGET_IOW('T',0x31, int) /* Lock/unlock Pty */
|
||||
|
||||
#define TARGET_FIONCLEX 0x5450 /* these numbers need to be adjusted. */
|
||||
#define TARGET_FIOCLEX 0x5451
|
||||
#define TARGET_FIOASYNC 0x5452
|
||||
#define TARGET_TIOCSERCONFIG 0x5453
|
||||
#define TARGET_TIOCSERGWILD 0x5454
|
||||
#define TARGET_TIOCSERSWILD 0x5455
|
||||
#define TARGET_TIOCGLCKTRMIOS 0x5456
|
||||
#define TARGET_TIOCSLCKTRMIOS 0x5457
|
||||
#define TARGET_TIOCSERGSTRUCT 0x5458 /* For debugging only */
|
||||
#define TARGET_TIOCSERGETLSR 0x5459 /* Get line status register */
|
||||
#define TARGET_TIOCSERGETMULTI 0x545A /* Get multiport config */
|
||||
#define TARGET_TIOCSERSETMULTI 0x545B /* Set multiport config */
|
||||
|
||||
#define TARGET_TIOCMIWAIT 0x545C /* wait for a change on serial input line(s) */
|
||||
#define TARGET_TIOCGICOUNT 0x545D /* read serial port inline interrupt counts */
|
||||
#define TARGET_TIOCGHAYESESP 0x545E /* Get Hayes ESP configuration */
|
||||
#define TARGET_TIOCSHAYESESP 0x545F /* Set Hayes ESP configuration */
|
||||
|
||||
/* Used for packet mode */
|
||||
#define TARGET_TIOCPKT_DATA 0
|
||||
#define TARGET_TIOCPKT_FLUSHREAD 1
|
||||
#define TARGET_TIOCPKT_FLUSHWRITE 2
|
||||
#define TARGET_TIOCPKT_STOP 4
|
||||
#define TARGET_TIOCPKT_START 8
|
||||
#define TARGET_TIOCPKT_NOSTOP 16
|
||||
#define TARGET_TIOCPKT_DOSTOP 32
|
||||
|
||||
#define TARGET_TIOCSER_TEMT 0x01 /* Transmitter physically empty */
|
||||
|
||||
/* from asm/termbits.h */
|
||||
|
||||
#define TARGET_NCCS 19
|
||||
|
||||
struct target_termios {
|
||||
unsigned int c_iflag; /* input mode flags */
|
||||
unsigned int c_oflag; /* output mode flags */
|
||||
unsigned int c_cflag; /* control mode flags */
|
||||
unsigned int c_lflag; /* local mode flags */
|
||||
unsigned char c_line; /* line discipline */
|
||||
unsigned char c_cc[TARGET_NCCS]; /* control characters */
|
||||
#define TARGET_NCC 8
|
||||
struct target_termio {
|
||||
unsigned short c_iflag; /* input mode flags */
|
||||
unsigned short c_oflag; /* output mode flags */
|
||||
unsigned short c_cflag; /* control mode flags */
|
||||
unsigned short c_lflag; /* local mode flags */
|
||||
unsigned char c_line; /* line discipline */
|
||||
unsigned char c_cc[TARGET_NCC]; /* control characters */
|
||||
};
|
||||
|
||||
/* c_iflag bits */
|
||||
#define TARGET_IGNBRK 0000001
|
||||
#define TARGET_BRKINT 0000002
|
||||
#define TARGET_IGNPAR 0000004
|
||||
#define TARGET_PARMRK 0000010
|
||||
#define TARGET_INPCK 0000020
|
||||
#define TARGET_ISTRIP 0000040
|
||||
#define TARGET_INLCR 0000100
|
||||
#define TARGET_IGNCR 0000200
|
||||
#define TARGET_ICRNL 0000400
|
||||
#define TARGET_IUCLC 0001000
|
||||
#define TARGET_IXON 0002000
|
||||
#define TARGET_IXANY 0004000
|
||||
#define TARGET_IXOFF 0010000
|
||||
#define TARGET_IMAXBEL 0020000
|
||||
struct target_winsize {
|
||||
unsigned short ws_row;
|
||||
unsigned short ws_col;
|
||||
unsigned short ws_xpixel;
|
||||
unsigned short ws_ypixel;
|
||||
};
|
||||
|
||||
/* c_oflag bits */
|
||||
#define TARGET_OPOST 0000001
|
||||
#define TARGET_OLCUC 0000002
|
||||
#define TARGET_ONLCR 0000004
|
||||
#define TARGET_OCRNL 0000010
|
||||
#define TARGET_ONOCR 0000020
|
||||
#define TARGET_ONLRET 0000040
|
||||
#define TARGET_OFILL 0000100
|
||||
#define TARGET_OFDEL 0000200
|
||||
#define TARGET_NLDLY 0000400
|
||||
#define TARGET_NL0 0000000
|
||||
#define TARGET_NL1 0000400
|
||||
#define TARGET_CRDLY 0003000
|
||||
#define TARGET_CR0 0000000
|
||||
#define TARGET_CR1 0001000
|
||||
#define TARGET_CR2 0002000
|
||||
#define TARGET_CR3 0003000
|
||||
#define TARGET_TABDLY 0014000
|
||||
#define TARGET_TAB0 0000000
|
||||
#define TARGET_TAB1 0004000
|
||||
#define TARGET_TAB2 0010000
|
||||
#define TARGET_TAB3 0014000
|
||||
#define TARGET_XTABS 0014000
|
||||
#define TARGET_BSDLY 0020000
|
||||
#define TARGET_BS0 0000000
|
||||
#define TARGET_BS1 0020000
|
||||
#define TARGET_VTDLY 0040000
|
||||
#define TARGET_VT0 0000000
|
||||
#define TARGET_VT1 0040000
|
||||
#define TARGET_FFDLY 0100000
|
||||
#define TARGET_FF0 0000000
|
||||
#define TARGET_FF1 0100000
|
||||
|
||||
/* c_cflag bit meaning */
|
||||
#define TARGET_CBAUD 0010017
|
||||
#define TARGET_B0 0000000 /* hang up */
|
||||
#define TARGET_B50 0000001
|
||||
#define TARGET_B75 0000002
|
||||
#define TARGET_B110 0000003
|
||||
#define TARGET_B134 0000004
|
||||
#define TARGET_B150 0000005
|
||||
#define TARGET_B200 0000006
|
||||
#define TARGET_B300 0000007
|
||||
#define TARGET_B600 0000010
|
||||
#define TARGET_B1200 0000011
|
||||
#define TARGET_B1800 0000012
|
||||
#define TARGET_B2400 0000013
|
||||
#define TARGET_B4800 0000014
|
||||
#define TARGET_B9600 0000015
|
||||
#define TARGET_B19200 0000016
|
||||
#define TARGET_B38400 0000017
|
||||
#define TARGET_EXTA B19200
|
||||
#define TARGET_EXTB B38400
|
||||
#define TARGET_CSIZE 0000060
|
||||
#define TARGET_CS5 0000000
|
||||
#define TARGET_CS6 0000020
|
||||
#define TARGET_CS7 0000040
|
||||
#define TARGET_CS8 0000060
|
||||
#define TARGET_CSTOPB 0000100
|
||||
#define TARGET_CREAD 0000200
|
||||
#define TARGET_PARENB 0000400
|
||||
#define TARGET_PARODD 0001000
|
||||
#define TARGET_HUPCL 0002000
|
||||
#define TARGET_CLOCAL 0004000
|
||||
#define TARGET_CBAUDEX 0010000
|
||||
#define TARGET_B57600 0010001
|
||||
#define TARGET_B115200 0010002
|
||||
#define TARGET_B230400 0010003
|
||||
#define TARGET_B460800 0010004
|
||||
#define TARGET_CIBAUD 002003600000 /* input baud rate (not used) */
|
||||
#define TARGET_CRTSCTS 020000000000 /* flow control */
|
||||
|
||||
/* c_lflag bits */
|
||||
#define TARGET_ISIG 0000001
|
||||
#define TARGET_ICANON 0000002
|
||||
#define TARGET_XCASE 0000004
|
||||
#define TARGET_ECHO 0000010
|
||||
#define TARGET_ECHOE 0000020
|
||||
#define TARGET_ECHOK 0000040
|
||||
#define TARGET_ECHONL 0000100
|
||||
#define TARGET_NOFLSH 0000200
|
||||
#define TARGET_TOSTOP 0000400
|
||||
#define TARGET_ECHOCTL 0001000
|
||||
#define TARGET_ECHOPRT 0002000
|
||||
#define TARGET_ECHOKE 0004000
|
||||
#define TARGET_FLUSHO 0010000
|
||||
#define TARGET_PENDIN 0040000
|
||||
#define TARGET_IEXTEN 0100000
|
||||
|
||||
/* c_cc character offsets */
|
||||
#define TARGET_VINTR 0
|
||||
#define TARGET_VQUIT 1
|
||||
#define TARGET_VERASE 2
|
||||
#define TARGET_VKILL 3
|
||||
#define TARGET_VEOF 4
|
||||
#define TARGET_VTIME 5
|
||||
#define TARGET_VMIN 6
|
||||
#define TARGET_VSWTC 7
|
||||
#define TARGET_VSTART 8
|
||||
#define TARGET_VSTOP 9
|
||||
#define TARGET_VSUSP 10
|
||||
#define TARGET_VEOL 11
|
||||
#define TARGET_VREPRINT 12
|
||||
#define TARGET_VDISCARD 13
|
||||
#define TARGET_VWERASE 14
|
||||
#define TARGET_VLNEXT 15
|
||||
#define TARGET_VEOL2 16
|
||||
#include "termbits.h"
|
||||
|
||||
#define TARGET_MAP_SHARED 0x01 /* Share changes */
|
||||
#define TARGET_MAP_PRIVATE 0x02 /* Changes are private */
|
||||
@@ -1163,6 +724,7 @@ struct target_termios {
|
||||
#define TARGET_MAP_LOCKED 0x2000 /* pages are locked */
|
||||
#define TARGET_MAP_NORESERVE 0x4000 /* don't check for reservations */
|
||||
|
||||
#if defined(TARGET_I386) || defined(TARGET_ARM)
|
||||
struct target_stat {
|
||||
unsigned short st_dev;
|
||||
unsigned short __pad1;
|
||||
@@ -1223,7 +785,111 @@ struct target_stat64 {
|
||||
unsigned long long st_ino;
|
||||
} __attribute__((packed));
|
||||
|
||||
#endif /* defined(TARGET_I386) || defined(TARGET_ARM) */
|
||||
#elif defined(TARGET_SPARC)
|
||||
|
||||
struct target_stat {
|
||||
unsigned short st_dev;
|
||||
target_ulong st_ino;
|
||||
unsigned short st_mode;
|
||||
short st_nlink;
|
||||
unsigned short st_uid;
|
||||
unsigned short st_gid;
|
||||
unsigned short st_rdev;
|
||||
target_long st_size;
|
||||
target_long target_st_atime;
|
||||
target_ulong __unused1;
|
||||
target_long target_st_mtime;
|
||||
target_ulong __unused2;
|
||||
target_long target_st_ctime;
|
||||
target_ulong __unused3;
|
||||
target_long st_blksize;
|
||||
target_long st_blocks;
|
||||
target_ulong __unused4[2];
|
||||
};
|
||||
|
||||
struct target_stat64 {
|
||||
unsigned char __pad0[6];
|
||||
unsigned short st_dev;
|
||||
|
||||
uint64_t st_ino;
|
||||
|
||||
unsigned int st_mode;
|
||||
unsigned int st_nlink;
|
||||
|
||||
unsigned int st_uid;
|
||||
unsigned int st_gid;
|
||||
|
||||
unsigned char __pad2[6];
|
||||
unsigned short st_rdev;
|
||||
|
||||
unsigned char __pad3[8];
|
||||
|
||||
int64_t st_size;
|
||||
unsigned int st_blksize;
|
||||
|
||||
unsigned char __pad4[8];
|
||||
unsigned int st_blocks;
|
||||
|
||||
unsigned int target_st_atime;
|
||||
unsigned int __unused1;
|
||||
|
||||
unsigned int target_st_mtime;
|
||||
unsigned int __unused2;
|
||||
|
||||
unsigned int target_st_ctime;
|
||||
unsigned int __unused3;
|
||||
|
||||
unsigned int __unused4;
|
||||
unsigned int __unused5;
|
||||
};
|
||||
|
||||
#elif defined(TARGET_PPC)
|
||||
|
||||
struct target_stat {
|
||||
unsigned short st_dev;
|
||||
target_ulong st_ino;
|
||||
unsigned int st_mode;
|
||||
unsigned short st_nlink;
|
||||
unsigned int st_uid;
|
||||
unsigned int st_gid;
|
||||
unsigned short st_rdev;
|
||||
target_ulong st_size;
|
||||
target_ulong st_blksize;
|
||||
target_ulong st_blocks;
|
||||
target_ulong target_st_atime;
|
||||
target_ulong __unused1;
|
||||
target_ulong target_st_mtime;
|
||||
target_ulong __unused2;
|
||||
target_ulong target_st_ctime;
|
||||
target_ulong __unused3;
|
||||
target_ulong __unused4;
|
||||
target_ulong __unused5;
|
||||
};
|
||||
|
||||
struct target_stat64 {
|
||||
unsigned long long st_dev;
|
||||
unsigned long long st_ino;
|
||||
unsigned int st_mode;
|
||||
unsigned int st_nlink;
|
||||
unsigned int st_uid;
|
||||
unsigned int st_gid;
|
||||
unsigned long long st_rdev;
|
||||
long long pad0;
|
||||
long long st_size;
|
||||
target_ulong st_blksize;
|
||||
target_ulong pad1;
|
||||
long long st_blocks; /* Number 512-byte blocks allocated. */
|
||||
target_ulong target_st_atime;
|
||||
target_ulong target_st_atime_nsec;
|
||||
target_ulong target_st_mtime;
|
||||
target_ulong target_st_mtime_nsec;
|
||||
target_ulong target_st_ctime;
|
||||
target_ulong target_st_ctime_nsec;
|
||||
target_ulong __unused4;
|
||||
target_ulong __unused5;
|
||||
};
|
||||
|
||||
#endif /* defined(TARGET_PPC) */
|
||||
|
||||
#define TARGET_F_DUPFD 0 /* dup */
|
||||
#define TARGET_F_GETFD 1 /* get close_on_exec */
|
||||
@@ -1252,6 +918,62 @@ struct target_stat64 {
|
||||
#define TARGET_F_SETLK64 13
|
||||
#define TARGET_F_SETLKW64 14
|
||||
|
||||
#if defined (TARGET_ARM)
|
||||
#define TARGET_O_ACCMODE 0003
|
||||
#define TARGET_O_RDONLY 00
|
||||
#define TARGET_O_WRONLY 01
|
||||
#define TARGET_O_RDWR 02
|
||||
#define TARGET_O_CREAT 0100 /* not fcntl */
|
||||
#define TARGET_O_EXCL 0200 /* not fcntl */
|
||||
#define TARGET_O_NOCTTY 0400 /* not fcntl */
|
||||
#define TARGET_O_TRUNC 01000 /* not fcntl */
|
||||
#define TARGET_O_APPEND 02000
|
||||
#define TARGET_O_NONBLOCK 04000
|
||||
#define TARGET_O_NDELAY O_NONBLOCK
|
||||
#define TARGET_O_SYNC 010000
|
||||
#define TARGET_FASYNC 020000 /* fcntl, for BSD compatibility */
|
||||
#define TARGET_O_DIRECTORY 040000 /* must be a directory */
|
||||
#define TARGET_O_NOFOLLOW 0100000 /* don't follow links */
|
||||
#define TARGET_O_DIRECT 0200000 /* direct disk access hint */
|
||||
#define TARGET_O_LARGEFILE 0400000
|
||||
#elif defined (TARGET_PPC)
|
||||
#define TARGET_O_ACCMODE 0003
|
||||
#define TARGET_O_RDONLY 00
|
||||
#define TARGET_O_WRONLY 01
|
||||
#define TARGET_O_RDWR 02
|
||||
#define TARGET_O_CREAT 0100 /* not fcntl */
|
||||
#define TARGET_O_EXCL 0200 /* not fcntl */
|
||||
#define TARGET_O_NOCTTY 0400 /* not fcntl */
|
||||
#define TARGET_O_TRUNC 01000 /* not fcntl */
|
||||
#define TARGET_O_APPEND 02000
|
||||
#define TARGET_O_NONBLOCK 04000
|
||||
#define TARGET_O_NDELAY O_NONBLOCK
|
||||
#define TARGET_O_SYNC 010000
|
||||
#define TARGET_FASYNC 020000 /* fcntl, for BSD compatibility */
|
||||
#define TARGET_O_DIRECTORY 040000 /* must be a directory */
|
||||
#define TARGET_O_NOFOLLOW 0100000 /* don't follow links */
|
||||
#define TARGET_O_LARGEFILE 0200000
|
||||
#define TARGET_O_DIRECT 0400000 /* direct disk access hint */
|
||||
#else
|
||||
#define TARGET_O_ACCMODE 0003
|
||||
#define TARGET_O_RDONLY 00
|
||||
#define TARGET_O_WRONLY 01
|
||||
#define TARGET_O_RDWR 02
|
||||
#define TARGET_O_CREAT 0100 /* not fcntl */
|
||||
#define TARGET_O_EXCL 0200 /* not fcntl */
|
||||
#define TARGET_O_NOCTTY 0400 /* not fcntl */
|
||||
#define TARGET_O_TRUNC 01000 /* not fcntl */
|
||||
#define TARGET_O_APPEND 02000
|
||||
#define TARGET_O_NONBLOCK 04000
|
||||
#define TARGET_O_NDELAY O_NONBLOCK
|
||||
#define TARGET_O_SYNC 010000
|
||||
#define TARGET_FASYNC 020000 /* fcntl, for BSD compatibility */
|
||||
#define TARGET_O_DIRECT 040000 /* direct disk access hint */
|
||||
#define TARGET_O_LARGEFILE 0100000
|
||||
#define TARGET_O_DIRECTORY 0200000 /* must be a directory */
|
||||
#define TARGET_O_NOFOLLOW 0400000 /* don't follow links */
|
||||
#endif
|
||||
|
||||
struct target_flock {
|
||||
short l_type;
|
||||
short l_whence;
|
||||
@@ -1411,3 +1133,20 @@ struct target_flock64 {
|
||||
/* vfat ioctls */
|
||||
#define TARGET_VFAT_IOCTL_READDIR_BOTH TARGET_IORU('r', 1)
|
||||
#define TARGET_VFAT_IOCTL_READDIR_SHORT TARGET_IORU('r', 2)
|
||||
|
||||
struct target_sysinfo {
|
||||
target_long uptime; /* Seconds since boot */
|
||||
target_ulong loads[3]; /* 1, 5, and 15 minute load averages */
|
||||
target_ulong totalram; /* Total usable main memory size */
|
||||
target_ulong freeram; /* Available memory size */
|
||||
target_ulong sharedram; /* Amount of shared memory */
|
||||
target_ulong bufferram; /* Memory used by buffers */
|
||||
target_ulong totalswap; /* Total swap space size */
|
||||
target_ulong freeswap; /* swap space still available */
|
||||
unsigned short procs; /* Number of current processes */
|
||||
unsigned short pad; /* explicit padding for m68k */
|
||||
target_ulong totalhigh; /* Total high memory size */
|
||||
target_ulong freehigh; /* Available high memory size */
|
||||
unsigned int mem_unit; /* Memory unit size in bytes */
|
||||
char _f[20-2*sizeof(target_long)-sizeof(int)]; /* Padding: libc5 uses this.. */
|
||||
};
|
||||
@@ -0,0 +1,177 @@
|
||||
/* Script for -z combreloc: combine and sort reloc sections */
|
||||
OUTPUT_FORMAT("elf32-m68k", "elf32-m68k",
|
||||
"elf32-m68k")
|
||||
OUTPUT_ARCH(m68k)
|
||||
ENTRY(_start)
|
||||
SEARCH_DIR("/usr/local/m68k-linux/lib");
|
||||
/* Do we need any of these for elf?
|
||||
__DYNAMIC = 0; */
|
||||
SECTIONS
|
||||
{
|
||||
/* Read-only sections, merged into text segment: */
|
||||
. = 0x60000000 + SIZEOF_HEADERS;
|
||||
.interp : { *(.interp) }
|
||||
.hash : { *(.hash) }
|
||||
.dynsym : { *(.dynsym) }
|
||||
.dynstr : { *(.dynstr) }
|
||||
.gnu.version : { *(.gnu.version) }
|
||||
.gnu.version_d : { *(.gnu.version_d) }
|
||||
.gnu.version_r : { *(.gnu.version_r) }
|
||||
.rel.dyn :
|
||||
{
|
||||
*(.rel.init)
|
||||
*(.rel.text .rel.text.* .rel.gnu.linkonce.t.*)
|
||||
*(.rel.fini)
|
||||
*(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*)
|
||||
*(.rel.data .rel.data.* .rel.gnu.linkonce.d.*)
|
||||
*(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*)
|
||||
*(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*)
|
||||
*(.rel.ctors)
|
||||
*(.rel.dtors)
|
||||
*(.rel.got)
|
||||
*(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*)
|
||||
}
|
||||
.rela.dyn :
|
||||
{
|
||||
*(.rela.init)
|
||||
*(.rela.text .rela.text.* .rela.gnu.linkonce.t.*)
|
||||
*(.rela.fini)
|
||||
*(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*)
|
||||
*(.rela.data .rela.data.* .rela.gnu.linkonce.d.*)
|
||||
*(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*)
|
||||
*(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*)
|
||||
*(.rela.ctors)
|
||||
*(.rela.dtors)
|
||||
*(.rela.got)
|
||||
*(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*)
|
||||
}
|
||||
.rel.plt : { *(.rel.plt) }
|
||||
.rela.plt : { *(.rela.plt) }
|
||||
.init :
|
||||
{
|
||||
KEEP (*(.init))
|
||||
} =0x4e754e75
|
||||
.plt : { *(.plt) }
|
||||
.text :
|
||||
{
|
||||
*(.text .stub .text.* .gnu.linkonce.t.*)
|
||||
/* .gnu.warning sections are handled specially by elf32.em. */
|
||||
*(.gnu.warning)
|
||||
} =0x4e754e75
|
||||
.fini :
|
||||
{
|
||||
KEEP (*(.fini))
|
||||
} =0x4e754e75
|
||||
PROVIDE (__etext = .);
|
||||
PROVIDE (_etext = .);
|
||||
PROVIDE (etext = .);
|
||||
.rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
|
||||
.rodata1 : { *(.rodata1) }
|
||||
.eh_frame_hdr : { *(.eh_frame_hdr) }
|
||||
/* Adjust the address for the data segment. We want to adjust up to
|
||||
the same address within the page on the next page up. */
|
||||
. = ALIGN(0x2000) + (. & (0x2000 - 1));
|
||||
/* Ensure the __preinit_array_start label is properly aligned. We
|
||||
could instead move the label definition inside the section, but
|
||||
the linker would then create the section even if it turns out to
|
||||
be empty, which isn't pretty. */
|
||||
. = ALIGN(32 / 8);
|
||||
PROVIDE (__preinit_array_start = .);
|
||||
.preinit_array : { *(.preinit_array) }
|
||||
PROVIDE (__preinit_array_end = .);
|
||||
PROVIDE (__init_array_start = .);
|
||||
.init_array : { *(.init_array) }
|
||||
PROVIDE (__init_array_end = .);
|
||||
PROVIDE (__fini_array_start = .);
|
||||
.fini_array : { *(.fini_array) }
|
||||
PROVIDE (__fini_array_end = .);
|
||||
.data :
|
||||
{
|
||||
*(.data .data.* .gnu.linkonce.d.*)
|
||||
SORT(CONSTRUCTORS)
|
||||
}
|
||||
.data1 : { *(.data1) }
|
||||
.tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) }
|
||||
.tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
|
||||
.eh_frame : { KEEP (*(.eh_frame)) }
|
||||
.gcc_except_table : { *(.gcc_except_table) }
|
||||
.dynamic : { *(.dynamic) }
|
||||
.ctors :
|
||||
{
|
||||
/* gcc uses crtbegin.o to find the start of
|
||||
the constructors, so we make sure it is
|
||||
first. Because this is a wildcard, it
|
||||
doesn't matter if the user does not
|
||||
actually link against crtbegin.o; the
|
||||
linker won't look for a file to match a
|
||||
wildcard. The wildcard also means that it
|
||||
doesn't matter which directory crtbegin.o
|
||||
is in. */
|
||||
KEEP (*crtbegin.o(.ctors))
|
||||
/* We don't want to include the .ctor section from
|
||||
from the crtend.o file until after the sorted ctors.
|
||||
The .ctor section from the crtend file contains the
|
||||
end of ctors marker and it must be last */
|
||||
KEEP (*(EXCLUDE_FILE (*crtend.o ) .ctors))
|
||||
KEEP (*(SORT(.ctors.*)))
|
||||
KEEP (*(.ctors))
|
||||
}
|
||||
.dtors :
|
||||
{
|
||||
KEEP (*crtbegin.o(.dtors))
|
||||
KEEP (*(EXCLUDE_FILE (*crtend.o ) .dtors))
|
||||
KEEP (*(SORT(.dtors.*)))
|
||||
KEEP (*(.dtors))
|
||||
}
|
||||
.jcr : { KEEP (*(.jcr)) }
|
||||
.got : { *(.got.plt) *(.got) }
|
||||
_edata = .;
|
||||
PROVIDE (edata = .);
|
||||
__bss_start = .;
|
||||
.bss :
|
||||
{
|
||||
*(.dynbss)
|
||||
*(.bss .bss.* .gnu.linkonce.b.*)
|
||||
*(COMMON)
|
||||
/* Align here to ensure that the .bss section occupies space up to
|
||||
_end. Align after .bss to ensure correct alignment even if the
|
||||
.bss section disappears because there are no input sections. */
|
||||
. = ALIGN(32 / 8);
|
||||
}
|
||||
. = ALIGN(32 / 8);
|
||||
_end = .;
|
||||
PROVIDE (end = .);
|
||||
/* Stabs debugging sections. */
|
||||
.stab 0 : { *(.stab) }
|
||||
.stabstr 0 : { *(.stabstr) }
|
||||
.stab.excl 0 : { *(.stab.excl) }
|
||||
.stab.exclstr 0 : { *(.stab.exclstr) }
|
||||
.stab.index 0 : { *(.stab.index) }
|
||||
.stab.indexstr 0 : { *(.stab.indexstr) }
|
||||
.comment 0 : { *(.comment) }
|
||||
/* DWARF debug sections.
|
||||
Symbols in the DWARF debugging sections are relative to the beginning
|
||||
of the section so we begin them at 0. */
|
||||
/* DWARF 1 */
|
||||
.debug 0 : { *(.debug) }
|
||||
.line 0 : { *(.line) }
|
||||
/* GNU DWARF 1 extensions */
|
||||
.debug_srcinfo 0 : { *(.debug_srcinfo) }
|
||||
.debug_sfnames 0 : { *(.debug_sfnames) }
|
||||
/* DWARF 1.1 and DWARF 2 */
|
||||
.debug_aranges 0 : { *(.debug_aranges) }
|
||||
.debug_pubnames 0 : { *(.debug_pubnames) }
|
||||
/* DWARF 2 */
|
||||
.debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
|
||||
.debug_abbrev 0 : { *(.debug_abbrev) }
|
||||
.debug_line 0 : { *(.debug_line) }
|
||||
.debug_frame 0 : { *(.debug_frame) }
|
||||
.debug_str 0 : { *(.debug_str) }
|
||||
.debug_loc 0 : { *(.debug_loc) }
|
||||
.debug_macinfo 0 : { *(.debug_macinfo) }
|
||||
/* SGI/MIPS DWARF 2 extensions */
|
||||
.debug_weaknames 0 : { *(.debug_weaknames) }
|
||||
.debug_funcnames 0 : { *(.debug_funcnames) }
|
||||
.debug_typenames 0 : { *(.debug_typenames) }
|
||||
.debug_varnames 0 : { *(.debug_varnames) }
|
||||
}
|
||||
-244
@@ -1,244 +0,0 @@
|
||||
|
||||
void OPPROTO glue(glue(op_movs, SUFFIX), STRING_SUFFIX)(void)
|
||||
{
|
||||
int v, inc;
|
||||
v = glue(ldu, SUFFIX)(SI_ADDR);
|
||||
glue(st, SUFFIX)(DI_ADDR, v);
|
||||
inc = (DF << SHIFT);
|
||||
INC_SI();
|
||||
INC_DI();
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_rep_movs, SUFFIX), STRING_SUFFIX)(void)
|
||||
{
|
||||
int v, inc;
|
||||
inc = (DF << SHIFT);
|
||||
while (CX != 0) {
|
||||
v = glue(ldu, SUFFIX)(SI_ADDR);
|
||||
glue(st, SUFFIX)(DI_ADDR, v);
|
||||
INC_SI();
|
||||
INC_DI();
|
||||
DEC_CX();
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_stos, SUFFIX), STRING_SUFFIX)(void)
|
||||
{
|
||||
int inc;
|
||||
glue(st, SUFFIX)(DI_ADDR, EAX);
|
||||
inc = (DF << SHIFT);
|
||||
INC_DI();
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_rep_stos, SUFFIX), STRING_SUFFIX)(void)
|
||||
{
|
||||
int inc;
|
||||
inc = (DF << SHIFT);
|
||||
while (CX != 0) {
|
||||
glue(st, SUFFIX)(DI_ADDR, EAX);
|
||||
INC_DI();
|
||||
DEC_CX();
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_lods, SUFFIX), STRING_SUFFIX)(void)
|
||||
{
|
||||
int v, inc;
|
||||
v = glue(ldu, SUFFIX)(SI_ADDR);
|
||||
#if SHIFT == 0
|
||||
EAX = (EAX & ~0xff) | v;
|
||||
#elif SHIFT == 1
|
||||
EAX = (EAX & ~0xffff) | v;
|
||||
#else
|
||||
EAX = v;
|
||||
#endif
|
||||
inc = (DF << SHIFT);
|
||||
INC_SI();
|
||||
}
|
||||
|
||||
/* don't know if it is used */
|
||||
void OPPROTO glue(glue(op_rep_lods, SUFFIX), STRING_SUFFIX)(void)
|
||||
{
|
||||
int v, inc;
|
||||
inc = (DF << SHIFT);
|
||||
while (CX != 0) {
|
||||
v = glue(ldu, SUFFIX)(SI_ADDR);
|
||||
#if SHIFT == 0
|
||||
EAX = (EAX & ~0xff) | v;
|
||||
#elif SHIFT == 1
|
||||
EAX = (EAX & ~0xffff) | v;
|
||||
#else
|
||||
EAX = v;
|
||||
#endif
|
||||
INC_SI();
|
||||
DEC_CX();
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_scas, SUFFIX), STRING_SUFFIX)(void)
|
||||
{
|
||||
int v, inc;
|
||||
|
||||
v = glue(ldu, SUFFIX)(DI_ADDR);
|
||||
inc = (DF << SHIFT);
|
||||
INC_DI();
|
||||
CC_SRC = v;
|
||||
CC_DST = EAX - v;
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_repz_scas, SUFFIX), STRING_SUFFIX)(void)
|
||||
{
|
||||
int v1, v2, inc;
|
||||
|
||||
if (CX != 0) {
|
||||
/* NOTE: the flags are not modified if CX == 0 */
|
||||
v1 = EAX & DATA_MASK;
|
||||
inc = (DF << SHIFT);
|
||||
do {
|
||||
v2 = glue(ldu, SUFFIX)(DI_ADDR);
|
||||
INC_DI();
|
||||
DEC_CX();
|
||||
if (v1 != v2)
|
||||
break;
|
||||
} while (CX != 0);
|
||||
CC_SRC = v2;
|
||||
CC_DST = v1 - v2;
|
||||
CC_OP = CC_OP_SUBB + SHIFT;
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_repnz_scas, SUFFIX), STRING_SUFFIX)(void)
|
||||
{
|
||||
int v1, v2, inc;
|
||||
|
||||
if (CX != 0) {
|
||||
/* NOTE: the flags are not modified if CX == 0 */
|
||||
v1 = EAX & DATA_MASK;
|
||||
inc = (DF << SHIFT);
|
||||
do {
|
||||
v2 = glue(ldu, SUFFIX)(DI_ADDR);
|
||||
INC_DI();
|
||||
DEC_CX();
|
||||
if (v1 == v2)
|
||||
break;
|
||||
} while (CX != 0);
|
||||
CC_SRC = v2;
|
||||
CC_DST = v1 - v2;
|
||||
CC_OP = CC_OP_SUBB + SHIFT;
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_cmps, SUFFIX), STRING_SUFFIX)(void)
|
||||
{
|
||||
int v1, v2, inc;
|
||||
v1 = glue(ldu, SUFFIX)(SI_ADDR);
|
||||
v2 = glue(ldu, SUFFIX)(DI_ADDR);
|
||||
inc = (DF << SHIFT);
|
||||
INC_SI();
|
||||
INC_DI();
|
||||
CC_SRC = v2;
|
||||
CC_DST = v1 - v2;
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_repz_cmps, SUFFIX), STRING_SUFFIX)(void)
|
||||
{
|
||||
int v1, v2, inc;
|
||||
if (CX != 0) {
|
||||
inc = (DF << SHIFT);
|
||||
do {
|
||||
v1 = glue(ldu, SUFFIX)(SI_ADDR);
|
||||
v2 = glue(ldu, SUFFIX)(DI_ADDR);
|
||||
INC_SI();
|
||||
INC_DI();
|
||||
DEC_CX();
|
||||
if (v1 != v2)
|
||||
break;
|
||||
} while (CX != 0);
|
||||
CC_SRC = v2;
|
||||
CC_DST = v1 - v2;
|
||||
CC_OP = CC_OP_SUBB + SHIFT;
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_repnz_cmps, SUFFIX), STRING_SUFFIX)(void)
|
||||
{
|
||||
int v1, v2, inc;
|
||||
if (CX != 0) {
|
||||
inc = (DF << SHIFT);
|
||||
do {
|
||||
v1 = glue(ldu, SUFFIX)(SI_ADDR);
|
||||
v2 = glue(ldu, SUFFIX)(DI_ADDR);
|
||||
INC_SI();
|
||||
INC_DI();
|
||||
DEC_CX();
|
||||
if (v1 == v2)
|
||||
break;
|
||||
} while (CX != 0);
|
||||
CC_SRC = v2;
|
||||
CC_DST = v1 - v2;
|
||||
CC_OP = CC_OP_SUBB + SHIFT;
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_outs, SUFFIX), STRING_SUFFIX)(void)
|
||||
{
|
||||
int v, dx, inc;
|
||||
dx = EDX & 0xffff;
|
||||
v = glue(ldu, SUFFIX)(SI_ADDR);
|
||||
glue(cpu_x86_out, SUFFIX)(env, dx, v);
|
||||
inc = (DF << SHIFT);
|
||||
INC_SI();
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_rep_outs, SUFFIX), STRING_SUFFIX)(void)
|
||||
{
|
||||
int v, dx, inc;
|
||||
inc = (DF << SHIFT);
|
||||
dx = EDX & 0xffff;
|
||||
while (CX != 0) {
|
||||
v = glue(ldu, SUFFIX)(SI_ADDR);
|
||||
glue(cpu_x86_out, SUFFIX)(env, dx, v);
|
||||
INC_SI();
|
||||
DEC_CX();
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_ins, SUFFIX), STRING_SUFFIX)(void)
|
||||
{
|
||||
int v, dx, inc;
|
||||
dx = EDX & 0xffff;
|
||||
v = glue(cpu_x86_in, SUFFIX)(env, dx);
|
||||
glue(st, SUFFIX)(DI_ADDR, v);
|
||||
inc = (DF << SHIFT);
|
||||
INC_DI();
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_rep_ins, SUFFIX), STRING_SUFFIX)(void)
|
||||
{
|
||||
int v, dx, inc;
|
||||
inc = (DF << SHIFT);
|
||||
dx = EDX & 0xffff;
|
||||
while (CX != 0) {
|
||||
v = glue(cpu_x86_in, SUFFIX)(env, dx);
|
||||
glue(st, SUFFIX)(DI_ADDR, v);
|
||||
INC_DI();
|
||||
DEC_CX();
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
#undef STRING_SUFFIX
|
||||
#undef SI_ADDR
|
||||
#undef DI_ADDR
|
||||
#undef INC_SI
|
||||
#undef INC_DI
|
||||
#undef CX
|
||||
#undef DEC_CX
|
||||
@@ -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 *~
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
- The PC BIOS comes from the Bochs project
|
||||
(http://bochs.sourceforge.net/). A patch from bios.diff was applied.
|
||||
|
||||
- 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
|
||||
operands are zeroes. */
|
||||
unsigned long opcode;
|
||||
uint32_t opcode;
|
||||
|
||||
/* The opcode mask. This is used by the disassembler. This is a
|
||||
mask containing ones indicating those bits which must match the
|
||||
opcode field, and zeroes indicating those bits which need not
|
||||
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
|
||||
specific processors support the instructions. The defined values
|
||||
are listed below. */
|
||||
unsigned long flags;
|
||||
uint32_t flags;
|
||||
|
||||
/* An array of operand codes. Each code is an index into the
|
||||
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
|
||||
operand value is legal, *ERRMSG will be unchanged (most operands
|
||||
can accept any value). */
|
||||
unsigned long (*insert)(unsigned long instruction, long op,
|
||||
unsigned long (*insert)(uint32_t instruction, int32_t op,
|
||||
const char **errmsg);
|
||||
|
||||
/* 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
|
||||
this operand (i.e., the instruction does not match). If the
|
||||
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. */
|
||||
unsigned long flags;
|
||||
uint32_t flags;
|
||||
};
|
||||
|
||||
/* 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
|
||||
specific processors support the instructions. The values are the
|
||||
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.
|
||||
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. */
|
||||
|
||||
static unsigned long insert_bat (unsigned long, long, const char **);
|
||||
static long extract_bat(unsigned long, int *);
|
||||
static unsigned long insert_bba(unsigned long, long, const char **);
|
||||
static long extract_bba(unsigned long, int *);
|
||||
static unsigned long insert_bd(unsigned long, long, const char **);
|
||||
static long extract_bd(unsigned long, int *);
|
||||
static unsigned long insert_bdm(unsigned long, long, const char **);
|
||||
static long extract_bdm(unsigned long, int *);
|
||||
static unsigned long insert_bdp(unsigned long, long, const char **);
|
||||
static long extract_bdp(unsigned long, int *);
|
||||
static unsigned long insert_bo(unsigned long, long, const char **);
|
||||
static long extract_bo(unsigned long, int *);
|
||||
static unsigned long insert_boe(unsigned long, long, const char **);
|
||||
static long extract_boe(unsigned long, int *);
|
||||
static unsigned long insert_ds(unsigned long, long, const char **);
|
||||
static long extract_ds(unsigned long, int *);
|
||||
static unsigned long insert_li(unsigned long, long, const char **);
|
||||
static long extract_li(unsigned long, int *);
|
||||
static unsigned long insert_mbe(unsigned long, long, const char **);
|
||||
static long extract_mbe(unsigned long, int *);
|
||||
static unsigned long insert_mb6(unsigned long, long, const char **);
|
||||
static long extract_mb6(unsigned long, int *);
|
||||
static unsigned long insert_nb(unsigned long, long, const char **);
|
||||
static long extract_nb(unsigned long, int *);
|
||||
static unsigned long insert_nsi(unsigned long, long, const char **);
|
||||
static long extract_nsi(unsigned long, int *);
|
||||
static unsigned long insert_ral(unsigned long, long, const char **);
|
||||
static unsigned long insert_ram(unsigned long, long, const char **);
|
||||
static unsigned long insert_ras(unsigned long, long, const char **);
|
||||
static unsigned long insert_rbs(unsigned long, long, const char **);
|
||||
static long extract_rbs(unsigned long, int *);
|
||||
static unsigned long insert_sh6(unsigned long, long, const char **);
|
||||
static long extract_sh6(unsigned long, int *);
|
||||
static unsigned long insert_spr(unsigned long, long, const char **);
|
||||
static long extract_spr(unsigned long, int *);
|
||||
static unsigned long insert_tbr(unsigned long, long, const char **);
|
||||
static long extract_tbr(unsigned long, int *);
|
||||
static unsigned long insert_bat (uint32_t, int32_t, const char **);
|
||||
static long extract_bat(uint32_t, int *);
|
||||
static unsigned long insert_bba(uint32_t, int32_t, const char **);
|
||||
static long extract_bba(uint32_t, int *);
|
||||
static unsigned long insert_bd(uint32_t, int32_t, const char **);
|
||||
static long extract_bd(uint32_t, int *);
|
||||
static unsigned long insert_bdm(uint32_t, int32_t, const char **);
|
||||
static long extract_bdm(uint32_t, int *);
|
||||
static unsigned long insert_bdp(uint32_t, int32_t, const char **);
|
||||
static long extract_bdp(uint32_t, int *);
|
||||
static unsigned long insert_bo(uint32_t, int32_t, const char **);
|
||||
static long extract_bo(uint32_t, int *);
|
||||
static unsigned long insert_boe(uint32_t, int32_t, const char **);
|
||||
static long extract_boe(uint32_t, int *);
|
||||
static unsigned long insert_ds(uint32_t, int32_t, const char **);
|
||||
static long extract_ds(uint32_t, int *);
|
||||
static unsigned long insert_li(uint32_t, int32_t, const char **);
|
||||
static long extract_li(uint32_t, int *);
|
||||
static unsigned long insert_mbe(uint32_t, int32_t, const char **);
|
||||
static long extract_mbe(uint32_t, int *);
|
||||
static unsigned long insert_mb6(uint32_t, int32_t, const char **);
|
||||
static long extract_mb6(uint32_t, int *);
|
||||
static unsigned long insert_nb(uint32_t, int32_t, const char **);
|
||||
static long extract_nb(uint32_t, int *);
|
||||
static unsigned long insert_nsi(uint32_t, int32_t, const char **);
|
||||
static long extract_nsi(uint32_t, int *);
|
||||
static unsigned long insert_ral(uint32_t, int32_t, const char **);
|
||||
static unsigned long insert_ram(uint32_t, int32_t, const char **);
|
||||
static unsigned long insert_ras(uint32_t, int32_t, const char **);
|
||||
static unsigned long insert_rbs(uint32_t, int32_t, const char **);
|
||||
static long extract_rbs(uint32_t, int *);
|
||||
static unsigned long insert_sh6(uint32_t, int32_t, const char **);
|
||||
static long extract_sh6(uint32_t, int *);
|
||||
static unsigned long insert_spr(uint32_t, int32_t, const char **);
|
||||
static long extract_spr(uint32_t, int *);
|
||||
static unsigned long insert_tbr(uint32_t, int32_t, const char **);
|
||||
static long extract_tbr(uint32_t, int *);
|
||||
|
||||
/* The operands table.
|
||||
|
||||
@@ -648,8 +648,8 @@ const struct powerpc_operand powerpc_operands[] =
|
||||
/*ARGSUSED*/
|
||||
static unsigned long
|
||||
insert_bat (insn, value, errmsg)
|
||||
unsigned long insn;
|
||||
long value;
|
||||
uint32_t insn;
|
||||
int32_t value;
|
||||
const char **errmsg;
|
||||
{
|
||||
return insn | (((insn >> 21) & 0x1f) << 16);
|
||||
@@ -657,7 +657,7 @@ insert_bat (insn, value, errmsg)
|
||||
|
||||
static long
|
||||
extract_bat (insn, invalid)
|
||||
unsigned long insn;
|
||||
uint32_t insn;
|
||||
int *invalid;
|
||||
{
|
||||
if (invalid != (int *) NULL
|
||||
@@ -675,8 +675,8 @@ extract_bat (insn, invalid)
|
||||
/*ARGSUSED*/
|
||||
static unsigned long
|
||||
insert_bba (insn, value, errmsg)
|
||||
unsigned long insn;
|
||||
long value;
|
||||
uint32_t insn;
|
||||
int32_t value;
|
||||
const char **errmsg;
|
||||
{
|
||||
return insn | (((insn >> 16) & 0x1f) << 11);
|
||||
@@ -684,7 +684,7 @@ insert_bba (insn, value, errmsg)
|
||||
|
||||
static long
|
||||
extract_bba (insn, invalid)
|
||||
unsigned long insn;
|
||||
uint32_t insn;
|
||||
int *invalid;
|
||||
{
|
||||
if (invalid != (int *) NULL
|
||||
@@ -699,8 +699,8 @@ extract_bba (insn, invalid)
|
||||
/*ARGSUSED*/
|
||||
static unsigned long
|
||||
insert_bd (insn, value, errmsg)
|
||||
unsigned long insn;
|
||||
long value;
|
||||
uint32_t insn;
|
||||
int32_t value;
|
||||
const char **errmsg;
|
||||
{
|
||||
return insn | (value & 0xfffc);
|
||||
@@ -709,7 +709,7 @@ insert_bd (insn, value, errmsg)
|
||||
/*ARGSUSED*/
|
||||
static long
|
||||
extract_bd (insn, invalid)
|
||||
unsigned long insn;
|
||||
uint32_t insn;
|
||||
int *invalid;
|
||||
{
|
||||
if ((insn & 0x8000) != 0)
|
||||
@@ -728,8 +728,8 @@ extract_bd (insn, invalid)
|
||||
/*ARGSUSED*/
|
||||
static unsigned long
|
||||
insert_bdm (insn, value, errmsg)
|
||||
unsigned long insn;
|
||||
long value;
|
||||
uint32_t insn;
|
||||
int32_t value;
|
||||
const char **errmsg;
|
||||
{
|
||||
if ((value & 0x8000) != 0)
|
||||
@@ -739,7 +739,7 @@ insert_bdm (insn, value, errmsg)
|
||||
|
||||
static long
|
||||
extract_bdm (insn, invalid)
|
||||
unsigned long insn;
|
||||
uint32_t insn;
|
||||
int *invalid;
|
||||
{
|
||||
if (invalid != (int *) NULL
|
||||
@@ -759,8 +759,8 @@ extract_bdm (insn, invalid)
|
||||
/*ARGSUSED*/
|
||||
static unsigned long
|
||||
insert_bdp (insn, value, errmsg)
|
||||
unsigned long insn;
|
||||
long value;
|
||||
uint32_t insn;
|
||||
int32_t value;
|
||||
const char **errmsg;
|
||||
{
|
||||
if ((value & 0x8000) == 0)
|
||||
@@ -770,7 +770,7 @@ insert_bdp (insn, value, errmsg)
|
||||
|
||||
static long
|
||||
extract_bdp (insn, invalid)
|
||||
unsigned long insn;
|
||||
uint32_t insn;
|
||||
int *invalid;
|
||||
{
|
||||
if (invalid != (int *) NULL
|
||||
@@ -786,7 +786,7 @@ extract_bdp (insn, invalid)
|
||||
/* Check for legal values of a BO field. */
|
||||
|
||||
static int
|
||||
valid_bo (long value)
|
||||
valid_bo (int32_t value)
|
||||
{
|
||||
/* Certain encodings have bits that are required to be zero. These
|
||||
are (z must be zero, y may be anything):
|
||||
@@ -815,8 +815,8 @@ valid_bo (long value)
|
||||
|
||||
static unsigned long
|
||||
insert_bo (insn, value, errmsg)
|
||||
unsigned long insn;
|
||||
long value;
|
||||
uint32_t insn;
|
||||
int32_t value;
|
||||
const char **errmsg;
|
||||
{
|
||||
if (errmsg != (const char **) NULL
|
||||
@@ -827,10 +827,10 @@ insert_bo (insn, value, errmsg)
|
||||
|
||||
static long
|
||||
extract_bo (insn, invalid)
|
||||
unsigned long insn;
|
||||
uint32_t insn;
|
||||
int *invalid;
|
||||
{
|
||||
long value;
|
||||
int32_t value;
|
||||
|
||||
value = (insn >> 21) & 0x1f;
|
||||
if (invalid != (int *) NULL
|
||||
@@ -845,8 +845,8 @@ extract_bo (insn, invalid)
|
||||
|
||||
static unsigned long
|
||||
insert_boe (insn, value, errmsg)
|
||||
unsigned long insn;
|
||||
long value;
|
||||
uint32_t insn;
|
||||
int32_t value;
|
||||
const char **errmsg;
|
||||
{
|
||||
if (errmsg != (const char **) NULL)
|
||||
@@ -861,10 +861,10 @@ insert_boe (insn, value, errmsg)
|
||||
|
||||
static long
|
||||
extract_boe (insn, invalid)
|
||||
unsigned long insn;
|
||||
uint32_t insn;
|
||||
int *invalid;
|
||||
{
|
||||
long value;
|
||||
int32_t value;
|
||||
|
||||
value = (insn >> 21) & 0x1f;
|
||||
if (invalid != (int *) NULL
|
||||
@@ -879,8 +879,8 @@ extract_boe (insn, invalid)
|
||||
/*ARGSUSED*/
|
||||
static unsigned long
|
||||
insert_ds (insn, value, errmsg)
|
||||
unsigned long insn;
|
||||
long value;
|
||||
uint32_t insn;
|
||||
int32_t value;
|
||||
const char **errmsg;
|
||||
{
|
||||
return insn | (value & 0xfffc);
|
||||
@@ -889,7 +889,7 @@ insert_ds (insn, value, errmsg)
|
||||
/*ARGSUSED*/
|
||||
static long
|
||||
extract_ds (insn, invalid)
|
||||
unsigned long insn;
|
||||
uint32_t insn;
|
||||
int *invalid;
|
||||
{
|
||||
if ((insn & 0x8000) != 0)
|
||||
@@ -904,8 +904,8 @@ extract_ds (insn, invalid)
|
||||
/*ARGSUSED*/
|
||||
static unsigned long
|
||||
insert_li (insn, value, errmsg)
|
||||
unsigned long insn;
|
||||
long value;
|
||||
uint32_t insn;
|
||||
int32_t value;
|
||||
const char **errmsg;
|
||||
{
|
||||
return insn | (value & 0x3fffffc);
|
||||
@@ -914,7 +914,7 @@ insert_li (insn, value, errmsg)
|
||||
/*ARGSUSED*/
|
||||
static long
|
||||
extract_li (insn, invalid)
|
||||
unsigned long insn;
|
||||
uint32_t insn;
|
||||
int *invalid;
|
||||
{
|
||||
if ((insn & 0x2000000) != 0)
|
||||
@@ -930,11 +930,11 @@ extract_li (insn, invalid)
|
||||
|
||||
static unsigned long
|
||||
insert_mbe (insn, value, errmsg)
|
||||
unsigned long insn;
|
||||
long value;
|
||||
uint32_t insn;
|
||||
int32_t value;
|
||||
const char **errmsg;
|
||||
{
|
||||
unsigned long uval;
|
||||
uint32_t uval;
|
||||
int mb, me;
|
||||
|
||||
uval = value;
|
||||
@@ -972,7 +972,7 @@ insert_mbe (insn, value, errmsg)
|
||||
|
||||
static long
|
||||
extract_mbe (insn, invalid)
|
||||
unsigned long insn;
|
||||
uint32_t insn;
|
||||
int *invalid;
|
||||
{
|
||||
long ret;
|
||||
@@ -996,8 +996,8 @@ extract_mbe (insn, invalid)
|
||||
/*ARGSUSED*/
|
||||
static unsigned long
|
||||
insert_mb6 (insn, value, errmsg)
|
||||
unsigned long insn;
|
||||
long value;
|
||||
uint32_t insn;
|
||||
int32_t value;
|
||||
const char **errmsg;
|
||||
{
|
||||
return insn | ((value & 0x1f) << 6) | (value & 0x20);
|
||||
@@ -1006,7 +1006,7 @@ insert_mb6 (insn, value, errmsg)
|
||||
/*ARGSUSED*/
|
||||
static long
|
||||
extract_mb6 (insn, invalid)
|
||||
unsigned long insn;
|
||||
uint32_t insn;
|
||||
int *invalid;
|
||||
{
|
||||
return ((insn >> 6) & 0x1f) | (insn & 0x20);
|
||||
@@ -1017,8 +1017,8 @@ extract_mb6 (insn, invalid)
|
||||
|
||||
static unsigned long
|
||||
insert_nb (insn, value, errmsg)
|
||||
unsigned long insn;
|
||||
long value;
|
||||
uint32_t insn;
|
||||
int32_t value;
|
||||
const char **errmsg;
|
||||
{
|
||||
if (value < 0 || value > 32)
|
||||
@@ -1031,7 +1031,7 @@ insert_nb (insn, value, errmsg)
|
||||
/*ARGSUSED*/
|
||||
static long
|
||||
extract_nb (insn, invalid)
|
||||
unsigned long insn;
|
||||
uint32_t insn;
|
||||
int *invalid;
|
||||
{
|
||||
long ret;
|
||||
@@ -1050,8 +1050,8 @@ extract_nb (insn, invalid)
|
||||
/*ARGSUSED*/
|
||||
static unsigned long
|
||||
insert_nsi (insn, value, errmsg)
|
||||
unsigned long insn;
|
||||
long value;
|
||||
uint32_t insn;
|
||||
int32_t value;
|
||||
const char **errmsg;
|
||||
{
|
||||
return insn | ((- value) & 0xffff);
|
||||
@@ -1059,7 +1059,7 @@ insert_nsi (insn, value, errmsg)
|
||||
|
||||
static long
|
||||
extract_nsi (insn, invalid)
|
||||
unsigned long insn;
|
||||
uint32_t insn;
|
||||
int *invalid;
|
||||
{
|
||||
if (invalid != (int *) NULL)
|
||||
@@ -1076,8 +1076,8 @@ extract_nsi (insn, invalid)
|
||||
|
||||
static unsigned long
|
||||
insert_ral (insn, value, errmsg)
|
||||
unsigned long insn;
|
||||
long value;
|
||||
uint32_t insn;
|
||||
int32_t value;
|
||||
const char **errmsg;
|
||||
{
|
||||
if (value == 0
|
||||
@@ -1091,8 +1091,8 @@ insert_ral (insn, value, errmsg)
|
||||
|
||||
static unsigned long
|
||||
insert_ram (insn, value, errmsg)
|
||||
unsigned long insn;
|
||||
long value;
|
||||
uint32_t insn;
|
||||
int32_t value;
|
||||
const char **errmsg;
|
||||
{
|
||||
if (value >= ((insn >> 21) & 0x1f))
|
||||
@@ -1106,8 +1106,8 @@ insert_ram (insn, value, errmsg)
|
||||
|
||||
static unsigned long
|
||||
insert_ras (insn, value, errmsg)
|
||||
unsigned long insn;
|
||||
long value;
|
||||
uint32_t insn;
|
||||
int32_t value;
|
||||
const char **errmsg;
|
||||
{
|
||||
if (value == 0)
|
||||
@@ -1124,8 +1124,8 @@ insert_ras (insn, value, errmsg)
|
||||
/*ARGSUSED*/
|
||||
static unsigned long
|
||||
insert_rbs (insn, value, errmsg)
|
||||
unsigned long insn;
|
||||
long value;
|
||||
uint32_t insn;
|
||||
int32_t value;
|
||||
const char **errmsg;
|
||||
{
|
||||
return insn | (((insn >> 21) & 0x1f) << 11);
|
||||
@@ -1133,7 +1133,7 @@ insert_rbs (insn, value, errmsg)
|
||||
|
||||
static long
|
||||
extract_rbs (insn, invalid)
|
||||
unsigned long insn;
|
||||
uint32_t insn;
|
||||
int *invalid;
|
||||
{
|
||||
if (invalid != (int *) NULL
|
||||
@@ -1147,8 +1147,8 @@ extract_rbs (insn, invalid)
|
||||
/*ARGSUSED*/
|
||||
static unsigned long
|
||||
insert_sh6 (insn, value, errmsg)
|
||||
unsigned long insn;
|
||||
long value;
|
||||
uint32_t insn;
|
||||
int32_t value;
|
||||
const char **errmsg;
|
||||
{
|
||||
return insn | ((value & 0x1f) << 11) | ((value & 0x20) >> 4);
|
||||
@@ -1157,7 +1157,7 @@ insert_sh6 (insn, value, errmsg)
|
||||
/*ARGSUSED*/
|
||||
static long
|
||||
extract_sh6 (insn, invalid)
|
||||
unsigned long insn;
|
||||
uint32_t insn;
|
||||
int *invalid;
|
||||
{
|
||||
return ((insn >> 11) & 0x1f) | ((insn << 4) & 0x20);
|
||||
@@ -1168,8 +1168,8 @@ extract_sh6 (insn, invalid)
|
||||
|
||||
static unsigned long
|
||||
insert_spr (insn, value, errmsg)
|
||||
unsigned long insn;
|
||||
long value;
|
||||
uint32_t insn;
|
||||
int32_t value;
|
||||
const char **errmsg;
|
||||
{
|
||||
return insn | ((value & 0x1f) << 16) | ((value & 0x3e0) << 6);
|
||||
@@ -1177,7 +1177,7 @@ insert_spr (insn, value, errmsg)
|
||||
|
||||
static long
|
||||
extract_spr (insn, invalid)
|
||||
unsigned long insn;
|
||||
uint32_t insn;
|
||||
int *invalid;
|
||||
{
|
||||
return ((insn >> 16) & 0x1f) | ((insn >> 6) & 0x3e0);
|
||||
@@ -1195,8 +1195,8 @@ extract_spr (insn, invalid)
|
||||
|
||||
static unsigned long
|
||||
insert_tbr (insn, value, errmsg)
|
||||
unsigned long insn;
|
||||
long value;
|
||||
uint32_t insn;
|
||||
int32_t value;
|
||||
const char **errmsg;
|
||||
{
|
||||
if (value == 0)
|
||||
@@ -1206,7 +1206,7 @@ insert_tbr (insn, value, errmsg)
|
||||
|
||||
static long
|
||||
extract_tbr (insn, invalid)
|
||||
unsigned long insn;
|
||||
uint32_t insn;
|
||||
int *invalid;
|
||||
{
|
||||
long ret;
|
||||
@@ -3067,27 +3067,30 @@ const struct powerpc_macro powerpc_macros[] = {
|
||||
const int powerpc_num_macros =
|
||||
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
|
||||
disassemble instructions supported by the Motorola PowerPC 601. */
|
||||
#include "cpu.h"
|
||||
|
||||
int print_insn_ppc (bfd_vma pc, disassemble_info *info)
|
||||
{
|
||||
return print_insn_powerpc (info->stream,
|
||||
(unsigned int)bfd_getb32((bfd_byte *)pc), pc,
|
||||
PPC_OPCODE_PPC | PPC_OPCODE_601);
|
||||
uint32_t opc;
|
||||
|
||||
(*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. */
|
||||
|
||||
static int
|
||||
print_insn_powerpc (FILE *out, unsigned long insn, unsigned memaddr,
|
||||
int
|
||||
print_insn_powerpc (FILE *out, uint32_t insn, unsigned memaddr,
|
||||
int dialect)
|
||||
{
|
||||
const struct powerpc_opcode *opcode;
|
||||
const struct powerpc_opcode *opcode_end;
|
||||
unsigned long op;
|
||||
uint32_t op;
|
||||
|
||||
/* Get the major opcode of the instruction. */
|
||||
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;
|
||||
for (opcode = powerpc_opcodes; opcode < opcode_end; opcode++)
|
||||
{
|
||||
unsigned long table_op;
|
||||
uint32_t table_op;
|
||||
const unsigned char *opindex;
|
||||
const struct powerpc_operand *operand;
|
||||
int invalid;
|
||||
@@ -3137,7 +3140,7 @@ print_insn_powerpc (FILE *out, unsigned long insn, unsigned memaddr,
|
||||
need_paren = 0;
|
||||
for (opindex = opcode->operands; *opindex != 0; opindex++)
|
||||
{
|
||||
long value;
|
||||
int32_t value;
|
||||
|
||||
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. */
|
||||
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)
|
||||
fprintf(out, "f%ld", value);
|
||||
fprintf(out, "f%d", value);
|
||||
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)
|
||||
fprintf(out, "%08lX", value & 0xffffffff);
|
||||
fprintf(out, "%08X", value & 0xffffffff);
|
||||
else if ((operand->flags & PPC_OPERAND_CR) == 0
|
||||
|| (dialect & PPC_OPCODE_PPC) == 0)
|
||||
fprintf(out, "%ld", value);
|
||||
fprintf(out, "%d", value);
|
||||
else
|
||||
{
|
||||
if (operand->bits == 3)
|
||||
fprintf(out, "cr%ld", value);
|
||||
fprintf(out, "cr%d", value);
|
||||
else
|
||||
{
|
||||
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. */
|
||||
fprintf(out, ".long 0x%lx", insn);
|
||||
fprintf(out, ".long 0x%x", insn);
|
||||
|
||||
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
|
||||
+903
-671
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
|
||||
+19
-16
@@ -28,22 +28,17 @@
|
||||
#include <getopt.h>
|
||||
#include <inttypes.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/mman.h>
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
#include <malloc.h>
|
||||
#include <termios.h>
|
||||
#include <sys/poll.h>
|
||||
#include <errno.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/stat.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include "vl.h"
|
||||
#include "cow.h"
|
||||
|
||||
#define NO_THUNK_TYPE_SIZE
|
||||
#include "thunk.h"
|
||||
#include "bswap.h"
|
||||
|
||||
int cow_create(int cow_fd, const char *image_filename,
|
||||
int64_t image_sectors)
|
||||
@@ -85,8 +80,8 @@ int cow_create(int cow_fd, const char *image_filename,
|
||||
|
||||
void help(void)
|
||||
{
|
||||
printf("vlmkcow version " QEMU_VERSION ", Copyright (c) 2003 Fabrice Bellard\n"
|
||||
"usage: vlmkcow [-h] [-f disk_image] cow_image [cow_size]\n"
|
||||
printf("qemu-mkcow version " QEMU_VERSION ", Copyright (c) 2003 Fabrice Bellard\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"
|
||||
"\n"
|
||||
"-f disk_image set the raw disk image name\n"
|
||||
@@ -101,13 +96,14 @@ void help(void)
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
const char *image_filename, *cow_filename;
|
||||
int cow_fd, c, nb_args;
|
||||
int cow_fd, c, nb_args, simple_image;
|
||||
int64_t image_size;
|
||||
|
||||
image_filename = NULL;
|
||||
image_size = 0;
|
||||
simple_image = 0;
|
||||
for(;;) {
|
||||
c = getopt(argc, argv, "hf:");
|
||||
c = getopt(argc, argv, "hf:s");
|
||||
if (c == -1)
|
||||
break;
|
||||
switch(c) {
|
||||
@@ -117,6 +113,9 @@ int main(int argc, char **argv)
|
||||
case 'f':
|
||||
image_filename = optarg;
|
||||
break;
|
||||
case 's':
|
||||
simple_image = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!image_filename)
|
||||
@@ -131,12 +130,16 @@ int main(int argc, char **argv)
|
||||
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)
|
||||
return -1;
|
||||
if (cow_create(cow_fd, image_filename, image_size) < 0) {
|
||||
fprintf(stderr, "%s: error while formating\n", cow_filename);
|
||||
exit(1);
|
||||
if (simple_image) {
|
||||
ftruncate64(cow_fd, image_size * 512);
|
||||
} 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);
|
||||
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.
|
||||
@@ -0,0 +1,515 @@
|
||||
/*
|
||||
* QEMU SDL display driver
|
||||
*
|
||||
* Copyright (c) 2003 Fabrice Bellard
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#include "vl.h"
|
||||
|
||||
#include <SDL.h>
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <signal.h>
|
||||
#endif
|
||||
|
||||
#if defined(__APPLE__)
|
||||
#define CONFIG_SDL_GENERIC_KBD
|
||||
#endif
|
||||
|
||||
static SDL_Surface *screen;
|
||||
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)
|
||||
{
|
||||
// printf("updating x=%d y=%d w=%d h=%d\n", x, y, w, h);
|
||||
SDL_UpdateRect(screen, x, y, w, h);
|
||||
}
|
||||
|
||||
static void sdl_resize(DisplayState *ds, int w, int h)
|
||||
{
|
||||
int flags;
|
||||
|
||||
// printf("resizing to %d %d\n", w, h);
|
||||
|
||||
flags = SDL_HWSURFACE|SDL_ASYNCBLIT|SDL_HWACCEL;
|
||||
flags |= SDL_RESIZABLE;
|
||||
if (gui_fullscreen)
|
||||
flags |= SDL_FULLSCREEN;
|
||||
screen = SDL_SetVideoMode(w, h, 0, flags);
|
||||
if (!screen) {
|
||||
fprintf(stderr, "Could not open SDL display\n");
|
||||
exit(1);
|
||||
}
|
||||
ds->data = screen->pixels;
|
||||
ds->linesize = screen->pitch;
|
||||
ds->depth = screen->format->BitsPerPixel;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SDL_GENERIC_KBD
|
||||
|
||||
/* XXX: use keymap tables defined in the VNC patch because the
|
||||
following code suppose you have a US keyboard. */
|
||||
|
||||
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 */
|
||||
0xcd, /* 102 Right */
|
||||
0xcf, /* 103 End */
|
||||
0xd0, /* 104 Down */
|
||||
0xd1, /* 105 PgDn */
|
||||
0xd2, /* 106 Ins */
|
||||
0xd3, /* 107 Del */
|
||||
0x9c, /* 108 Enter */
|
||||
0x9d, /* 109 Ctrl-R */
|
||||
0x0, /* 110 Pause */
|
||||
0xb7, /* 111 Print */
|
||||
0xb5, /* 112 Divide */
|
||||
0xb8, /* 113 Alt-R */
|
||||
0xc6, /* 114 Break */
|
||||
0x0, /* 115 */
|
||||
0x0, /* 116 */
|
||||
0x0, /* 117 */
|
||||
0x0, /* 118 */
|
||||
0x0, /* 119 */
|
||||
0x70, /* 120 Hiragana_Katakana */
|
||||
0x0, /* 121 */
|
||||
0x0, /* 122 */
|
||||
0x73, /* 123 backslash */
|
||||
0x0, /* 124 */
|
||||
0x0, /* 125 */
|
||||
0x0, /* 126 */
|
||||
0x0, /* 127 */
|
||||
0x0, /* 128 */
|
||||
0x79, /* 129 Henkan */
|
||||
0x0, /* 130 */
|
||||
0x7b, /* 131 Muhenkan */
|
||||
0x0, /* 132 */
|
||||
0x7d, /* 133 Yen */
|
||||
0x0, /* 134 */
|
||||
0x0, /* 135 */
|
||||
0x47, /* 136 KP_7 */
|
||||
0x48, /* 137 KP_8 */
|
||||
0x49, /* 138 KP_9 */
|
||||
0x4b, /* 139 KP_4 */
|
||||
0x4c, /* 140 KP_5 */
|
||||
0x4d, /* 141 KP_6 */
|
||||
0x4f, /* 142 KP_1 */
|
||||
0x50, /* 143 KP_2 */
|
||||
0x51, /* 144 KP_3 */
|
||||
0x52, /* 145 KP_0 */
|
||||
0x53, /* 146 KP_. */
|
||||
0x47, /* 147 KP_HOME */
|
||||
0x48, /* 148 KP_UP */
|
||||
0x49, /* 149 KP_PgUp */
|
||||
0x4b, /* 150 KP_Left */
|
||||
0x4c, /* 151 KP_ */
|
||||
0x4d, /* 152 KP_Right */
|
||||
0x4f, /* 153 KP_End */
|
||||
0x50, /* 154 KP_Down */
|
||||
0x51, /* 155 KP_PgDn */
|
||||
0x52, /* 156 KP_Ins */
|
||||
0x53, /* 157 KP_Del */
|
||||
};
|
||||
|
||||
static uint8_t sdl_keyevent_to_keycode(const SDL_KeyboardEvent *ev)
|
||||
{
|
||||
int keycode;
|
||||
|
||||
keycode = ev->keysym.scancode;
|
||||
|
||||
if (keycode < 9) {
|
||||
keycode = 0;
|
||||
} else if (keycode < 97) {
|
||||
keycode -= 8; /* just an offset */
|
||||
} else if (keycode < 158) {
|
||||
/* use conversion table */
|
||||
keycode = x_keycode_to_pc_keycode[keycode - 97];
|
||||
} else {
|
||||
keycode = 0;
|
||||
}
|
||||
return keycode;
|
||||
}
|
||||
|
||||
#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)
|
||||
v |= 0x80;
|
||||
kbd_put_keycode(0xe1);
|
||||
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)
|
||||
{
|
||||
SDL_ShowCursor(0);
|
||||
SDL_WM_GrabInput(SDL_GRAB_ON);
|
||||
/* dummy read to avoid moving the mouse */
|
||||
SDL_GetRelativeMouseState(NULL, NULL);
|
||||
gui_grab = 1;
|
||||
sdl_update_caption();
|
||||
}
|
||||
|
||||
static void sdl_grab_end(void)
|
||||
{
|
||||
SDL_WM_GrabInput(SDL_GRAB_OFF);
|
||||
SDL_ShowCursor(1);
|
||||
gui_grab = 0;
|
||||
sdl_update_caption();
|
||||
}
|
||||
|
||||
static void sdl_send_mouse_event(void)
|
||||
{
|
||||
int dx, dy, dz, state, buttons;
|
||||
state = SDL_GetRelativeMouseState(&dx, &dy);
|
||||
buttons = 0;
|
||||
if (state & SDL_BUTTON(SDL_BUTTON_LEFT))
|
||||
buttons |= MOUSE_EVENT_LBUTTON;
|
||||
if (state & SDL_BUTTON(SDL_BUTTON_RIGHT))
|
||||
buttons |= MOUSE_EVENT_RBUTTON;
|
||||
if (state & SDL_BUTTON(SDL_BUTTON_MIDDLE))
|
||||
buttons |= MOUSE_EVENT_MBUTTON;
|
||||
/* XXX: test wheel */
|
||||
dz = 0;
|
||||
#ifdef SDL_BUTTON_WHEELUP
|
||||
if (state & SDL_BUTTON(SDL_BUTTON_WHEELUP))
|
||||
dz--;
|
||||
if (state & SDL_BUTTON(SDL_BUTTON_WHEELDOWN))
|
||||
dz++;
|
||||
#endif
|
||||
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)
|
||||
{
|
||||
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();
|
||||
while (SDL_PollEvent(ev)) {
|
||||
switch (ev->type) {
|
||||
case SDL_VIDEOEXPOSE:
|
||||
sdl_update(ds, 0, 0, screen->w, screen->h);
|
||||
break;
|
||||
case SDL_KEYDOWN:
|
||||
case SDL_KEYUP:
|
||||
if (ev->type == SDL_KEYDOWN) {
|
||||
mod_state = (SDL_GetModState() & (KMOD_LSHIFT | KMOD_LCTRL)) ==
|
||||
(KMOD_LSHIFT | KMOD_LCTRL);
|
||||
gui_key_modifier_pressed = mod_state;
|
||||
if (gui_key_modifier_pressed &&
|
||||
ev->key.keysym.sym == SDLK_f) {
|
||||
gui_keysym = ev->key.keysym.sym;
|
||||
}
|
||||
} 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);
|
||||
break;
|
||||
case SDL_QUIT:
|
||||
qemu_system_shutdown_request();
|
||||
break;
|
||||
case SDL_MOUSEMOTION:
|
||||
if (gui_grab) {
|
||||
sdl_send_mouse_event();
|
||||
}
|
||||
break;
|
||||
case SDL_MOUSEBUTTONDOWN:
|
||||
case SDL_MOUSEBUTTONUP:
|
||||
{
|
||||
SDL_MouseButtonEvent *bev = &ev->button;
|
||||
if (!gui_grab) {
|
||||
if (ev->type == SDL_MOUSEBUTTONDOWN &&
|
||||
(bev->state & SDL_BUTTON_LMASK)) {
|
||||
/* start grabbing all events */
|
||||
sdl_grab_start();
|
||||
}
|
||||
} else {
|
||||
sdl_send_mouse_event();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SDL_ACTIVEEVENT:
|
||||
if (gui_grab && (ev->active.gain & SDL_ACTIVEEVENTMASK) == 0) {
|
||||
sdl_grab_end();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void sdl_cleanup(void)
|
||||
{
|
||||
SDL_Quit();
|
||||
}
|
||||
|
||||
void sdl_display_init(DisplayState *ds)
|
||||
{
|
||||
int flags;
|
||||
|
||||
flags = SDL_INIT_VIDEO | SDL_INIT_NOPARACHUTE;
|
||||
if (SDL_Init (flags)) {
|
||||
fprintf(stderr, "Could not initialize SDL - exiting\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
/* NOTE: we still want Ctrl-C to work, so we undo the SDL redirections */
|
||||
signal(SIGINT, SIG_DFL);
|
||||
signal(SIGQUIT, SIG_DFL);
|
||||
#endif
|
||||
|
||||
ds->dpy_update = sdl_update;
|
||||
ds->dpy_resize = sdl_resize;
|
||||
ds->dpy_refresh = sdl_refresh;
|
||||
|
||||
sdl_resize(ds, 640, 400);
|
||||
sdl_update_caption();
|
||||
SDL_EnableKeyRepeat(250, 50);
|
||||
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);
|
||||
}
|
||||
}
|
||||
Loaded 100 of 201 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user