mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2026-08-05 02:19:16 +00:00
Compare commits
785 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d00eb4aa25 | ||
|
|
a1d8b63d86 | ||
|
|
0ce47c0538 | ||
|
|
828156db38 | ||
|
|
52df97e659 | ||
|
|
8e65d812cb | ||
|
|
610d694f1d | ||
|
|
25c6733feb | ||
|
|
39af0df279 | ||
|
|
5cc2876516 | ||
|
|
9009e785d9 | ||
|
|
a3231b1727 | ||
|
|
76a036e96d | ||
|
|
3e0bf235bb | ||
|
|
d0bafc72f8 | ||
|
|
2f3502eacc | ||
|
|
30cafccd23 | ||
|
|
88ebf565e0 | ||
|
|
0344805ed0 | ||
|
|
22873ae79e | ||
|
|
7dacfa3edc | ||
|
|
58d8206e2b | ||
|
|
1e1e61614c | ||
|
|
6a55768d94 | ||
|
|
5b177b205b | ||
|
|
f440976a7c | ||
|
|
0d573ae86c | ||
|
|
01420f5195 | ||
|
|
dfb1829f65 | ||
|
|
b5d11f72b3 | ||
|
|
00951f17d4 | ||
|
|
63c6c78c4e | ||
|
|
3fbdd7e16c | ||
|
|
455b0d5b62 | ||
|
|
bbefbe9273 | ||
|
|
84fc0e093d | ||
|
|
0eb78ab177 | ||
|
|
9aadbbe6d9 | ||
|
|
dc822be5e2 | ||
|
|
1a4747a20f | ||
|
|
83066cf58e | ||
|
|
495e444ca6 | ||
|
|
b99a3a7dc9 | ||
|
|
84a741a3fa | ||
|
|
db5d66747e | ||
|
|
dd6f07da23 | ||
|
|
8c135030d0 | ||
|
|
0468598fa3 | ||
|
|
7b7a3abfaa | ||
|
|
277ff84e55 | ||
|
|
a9f50dda08 | ||
|
|
73244aa6f2 | ||
|
|
6454c677d0 | ||
|
|
ca4857b5e6 | ||
|
|
1511cbda87 | ||
|
|
08021087ec | ||
|
|
90d79fa76b | ||
|
|
bebc5f957e | ||
|
|
5ac013df8b | ||
|
|
562a57012f | ||
|
|
93d19329f9 | ||
|
|
612dc544a8 | ||
|
|
59031531b6 | ||
|
|
2569621c4b | ||
|
|
1ea63f50a1 | ||
|
|
86f86c5348 | ||
|
|
0fb24ea3ae | ||
|
|
e390775bcb | ||
|
|
4450c44fbc | ||
|
|
a1caa6549a | ||
|
|
af3a59aa33 | ||
|
|
d7115ec656 | ||
|
|
7bbcc0f849 | ||
|
|
c4dc7a583d | ||
|
|
74485924b1 | ||
|
|
4889999277 | ||
|
|
eda0dc20d3 | ||
|
|
1e9c84af0f | ||
|
|
b50519651c | ||
|
|
08d859a7dd | ||
|
|
0dad7d9331 | ||
|
|
a496cecef1 | ||
|
|
a8f063db7c | ||
|
|
0066ddefe1 | ||
|
|
f9dd0aaf8a | ||
|
|
8b7880160e | ||
|
|
b7cb6257b5 | ||
|
|
6037c83585 | ||
|
|
b910a7922d | ||
|
|
ad6dfc5875 | ||
|
|
cb59976c68 | ||
|
|
520f54cb8d | ||
|
|
1a2d0e6dd8 | ||
|
|
7383087230 | ||
|
|
d72af85c42 | ||
|
|
d76d04e2f2 | ||
|
|
56c26b3d9c | ||
|
|
2280be825e | ||
|
|
73c822f64a | ||
|
|
43365ade2e | ||
|
|
e9d67dc405 | ||
|
|
fd4f32fa69 | ||
|
|
6fb88c3c5a | ||
|
|
d6c08d902b | ||
|
|
86afa38c64 | ||
|
|
ae68c802bd | ||
|
|
ccced2ebf4 | ||
|
|
d826b4fbdc | ||
|
|
0faa7afac2 | ||
|
|
da8eecc797 | ||
|
|
9dc9e224b9 | ||
|
|
b3fa56544c | ||
|
|
b30ddc0837 | ||
|
|
253c06d3ba | ||
|
|
46f6d9597d | ||
|
|
7b4f56e372 | ||
|
|
d6a2f48b32 | ||
|
|
c313bcbfd4 | ||
|
|
c741c01cc0 | ||
|
|
0aba41b3ee | ||
|
|
f67b3f79ea | ||
|
|
02173f42fc | ||
|
|
8ea0c542fd | ||
|
|
c1e896dddb | ||
|
|
a6040d7a30 | ||
|
|
a5d77cdee9 | ||
|
|
34f220edcd | ||
|
|
bcdac10149 | ||
|
|
ccda1a004e | ||
|
|
43f0dd6d25 | ||
|
|
a77160dca4 | ||
|
|
1d78812b63 | ||
|
|
8836715c2d | ||
|
|
330b5ea3be | ||
|
|
98bfd1e988 | ||
|
|
28382a1491 | ||
|
|
68e6a14deb | ||
|
|
f3778a7fc7 | ||
|
|
c6a110dd28 | ||
|
|
b0c7df2e59 | ||
|
|
1067059c4a | ||
|
|
8abe8c679b | ||
|
|
b6b686c71c | ||
|
|
171d12943d | ||
|
|
bdc44cd8bc | ||
|
|
33a55bac0f | ||
|
|
82ace6e327 | ||
|
|
2e56f0df77 | ||
|
|
a181b77bc8 | ||
|
|
9023412e31 | ||
|
|
977a893d86 | ||
|
|
2c4f8d2218 | ||
|
|
4f37a273d9 | ||
|
|
d64a77a5c6 | ||
|
|
e0d05683ab | ||
|
|
387753ae1d | ||
|
|
951ad3495e | ||
|
|
0dbb2683e3 | ||
|
|
579710d3e0 | ||
|
|
4d8a73735b | ||
|
|
687d646c60 | ||
|
|
54e523c302 | ||
|
|
4737679661 | ||
|
|
9c5b404415 | ||
|
|
6e9d3eccd6 | ||
|
|
10b954e954 | ||
|
|
e4abf2ce6c | ||
|
|
ad07a275c5 | ||
|
|
a20041ba68 | ||
|
|
eed0c927fd | ||
|
|
fb5cbd966e | ||
|
|
25798a97b3 | ||
|
|
2752b07762 | ||
|
|
a2e72774a9 | ||
|
|
584d5c5596 | ||
|
|
828dbd5227 | ||
|
|
b2e88967e4 | ||
|
|
ea396afdfa | ||
|
|
bfe0e90671 | ||
|
|
282484120d | ||
|
|
4d52a84ef7 | ||
|
|
1bf083bf00 | ||
|
|
c50051a686 | ||
|
|
e475b12cf7 | ||
|
|
64e217cf39 | ||
|
|
968902dfec | ||
|
|
df3b20f472 | ||
|
|
6c142e35f7 | ||
|
|
32da33eacd | ||
|
|
5d53648762 | ||
|
|
7549149bb5 | ||
|
|
c2144b5690 | ||
|
|
0d01eac1d4 | ||
|
|
46c60183cd | ||
|
|
7b80709595 | ||
|
|
a1a0bc8592 | ||
|
|
92a506fb06 | ||
|
|
72eb533f56 | ||
|
|
66f0b5b2b6 | ||
|
|
d92707afc5 | ||
|
|
9a634f07cb | ||
|
|
d475b953b8 | ||
|
|
c331d6b8cd | ||
|
|
4ef4a22e02 | ||
|
|
ae1ffeacec | ||
|
|
79486d1964 | ||
|
|
19ed8b329a | ||
|
|
b30a95f69a | ||
|
|
63637eba31 | ||
|
|
d74a219add | ||
|
|
4e5cbd27bb | ||
|
|
bc7ffdce95 | ||
|
|
22d7398139 | ||
|
|
a90260ffb6 | ||
|
|
f3793c08b5 | ||
|
|
8841e63e2d | ||
|
|
4d673de0fb | ||
|
|
e877718b29 | ||
|
|
744b5799a3 | ||
|
|
b0d8b50b36 | ||
|
|
2349b7e753 | ||
|
|
45d698ae72 | ||
|
|
f9098af4e4 | ||
|
|
47091bd02c | ||
|
|
8fae21c10c | ||
|
|
0bd0a65b3a | ||
|
|
b82bb55927 | ||
|
|
e89345c2c2 | ||
|
|
2b513ece00 | ||
|
|
e1f35628e2 | ||
|
|
001ee6794c | ||
|
|
f840335922 | ||
|
|
183605f9e1 | ||
|
|
e9a1b75ee6 | ||
|
|
e3487c0146 | ||
|
|
b075aada8c | ||
|
|
4d2a4e2805 | ||
|
|
6233f6f68e | ||
|
|
c913f7da2f | ||
|
|
760031103e | ||
|
|
25ed8722c7 | ||
|
|
8f6a5f979d | ||
|
|
b8b16c6eec | ||
|
|
a969d5016c | ||
|
|
c8df576933 | ||
|
|
f3035a0f7a | ||
|
|
6c00f5514f | ||
|
|
8f31688fa3 | ||
|
|
756dd236b9 | ||
|
|
780e606f12 | ||
|
|
db557916a5 | ||
|
|
722523f925 | ||
|
|
16f52914e0 | ||
|
|
b347e192d3 | ||
|
|
ddf5a848d8 | ||
|
|
d3170a926f | ||
|
|
2f2e870ad1 | ||
|
|
a37424c011 | ||
|
|
02aa95a098 | ||
|
|
2a470d9a30 | ||
|
|
e965007514 | ||
|
|
98fc38c465 | ||
|
|
1fa3a60b35 | ||
|
|
5db4dede28 | ||
|
|
452af9b17c | ||
|
|
fc24f39507 | ||
|
|
3778bf8a8e | ||
|
|
9aba1fdee6 | ||
|
|
864a5e4fe0 | ||
|
|
7d38a1848b | ||
|
|
2d2463ce04 | ||
|
|
08ac3405f5 | ||
|
|
c7f75f9d59 | ||
|
|
620aaf234e | ||
|
|
86b2c17135 | ||
|
|
ce52fc97b9 | ||
|
|
754ce37031 | ||
|
|
8f7ed5fed7 | ||
|
|
af3bdb452a | ||
|
|
9d35a10fd4 | ||
|
|
ea5a050341 | ||
|
|
0bad764462 | ||
|
|
e7893b9a97 | ||
|
|
d13eea3ba1 | ||
|
|
1240ef3261 | ||
|
|
ed53c74ca9 | ||
|
|
0b5c680d15 | ||
|
|
6f436f02dc | ||
|
|
53b2e19934 | ||
|
|
f99462add4 | ||
|
|
1d403ea5d6 | ||
|
|
c9cc97e9a0 | ||
|
|
bcae6c41e3 | ||
|
|
f3197c3833 | ||
|
|
5a0a4bc505 | ||
|
|
165364e08b | ||
|
|
20aa811de7 | ||
|
|
ba8d3f2c1c | ||
|
|
6d34ed03f7 | ||
|
|
4918c1ca7f | ||
|
|
d278e9f39b | ||
|
|
7e06d36dee | ||
|
|
4735cb8563 | ||
|
|
a636411522 | ||
|
|
71c7dff32b | ||
|
|
db444715fd | ||
|
|
c85aa6dfae | ||
|
|
5a83ebce64 | ||
|
|
f65538b08f | ||
|
|
152a3b98c9 | ||
|
|
a738808604 | ||
|
|
06729bb3ba | ||
|
|
2c54c30435 | ||
|
|
adae986233 | ||
|
|
1c3f8236e7 | ||
|
|
204be8611c | ||
|
|
5e74848ab4 | ||
|
|
7935430f6b | ||
|
|
d3b32b3d6d | ||
|
|
3efccd0fef | ||
|
|
b28063a7b4 | ||
|
|
9254b74c6d | ||
|
|
7fbec7113e | ||
|
|
2e236c53c8 | ||
|
|
77e147f333 | ||
|
|
980c1f7b19 | ||
|
|
db2159b563 | ||
|
|
5b0d4bb398 | ||
|
|
f7f2f25a57 | ||
|
|
b4f887ea80 | ||
|
|
91b05b6186 | ||
|
|
ed1b12f9d0 | ||
|
|
c6dd9918d5 | ||
|
|
db102a2547 | ||
|
|
27a285257e | ||
|
|
447c986916 | ||
|
|
7fb980f17b | ||
|
|
5c6139bbff | ||
|
|
0411064271 | ||
|
|
e9637d3733 | ||
|
|
9d88e0b417 | ||
|
|
b3f5630c27 | ||
|
|
61994cdb14 | ||
|
|
c1b962048c | ||
|
|
79425b6aa8 | ||
|
|
2a1e33ee35 | ||
|
|
b02df13af9 | ||
|
|
b2cc45e0a3 | ||
|
|
deb4ad5e23 | ||
|
|
3dff598fa2 | ||
|
|
cdfc177347 | ||
|
|
51ceae9131 | ||
|
|
1997152ee1 | ||
|
|
a5f4d79547 | ||
|
|
2ff193456d | ||
|
|
ecc8382ff0 | ||
|
|
521a11a110 | ||
|
|
60d054519e | ||
|
|
dc35dac306 | ||
|
|
ec1f7189da | ||
|
|
f5353c5b08 | ||
|
|
2a76a589c3 | ||
|
|
22275c3462 | ||
|
|
d27ea34a2d | ||
|
|
a0e48a87b8 | ||
|
|
349dbb9aac | ||
|
|
9e0f402e27 | ||
|
|
673c539f40 | ||
|
|
504ccc32a0 | ||
|
|
8fb53eb167 | ||
|
|
c7d3992bbc | ||
|
|
83c44a2411 | ||
|
|
c597655d06 | ||
|
|
902fe20d41 | ||
|
|
eabcbb5159 | ||
|
|
e51e410e04 | ||
|
|
8363a44b51 | ||
|
|
edc9f25efa | ||
|
|
62b8955245 | ||
|
|
461e6da1dc | ||
|
|
4993a1653b | ||
|
|
73eb1b1ba1 | ||
|
|
3baa0c3721 | ||
|
|
81895b9b40 | ||
|
|
6492496cc2 | ||
|
|
fdecba6958 | ||
|
|
4abcb0a33c | ||
|
|
ccafab6983 | ||
|
|
382b37f8d1 | ||
|
|
d4b8c8308c | ||
|
|
1da37c7bb4 | ||
|
|
12db6e5068 | ||
|
|
0852287fee | ||
|
|
dcc646f5b1 | ||
|
|
91bd4ee8cc | ||
|
|
6761868a69 | ||
|
|
9ccd23ebb0 | ||
|
|
b00a6a8519 | ||
|
|
e7c9954dc1 | ||
|
|
2723995cfa | ||
|
|
ca09638491 | ||
|
|
0835198ddd | ||
|
|
6d9c1eb638 | ||
|
|
b4c2772031 | ||
|
|
9106afae38 | ||
|
|
f063346de3 | ||
|
|
5e0d498582 | ||
|
|
a33280b8ad | ||
|
|
ec0a0adaab | ||
|
|
49c72beda5 | ||
|
|
bcd45efdd3 | ||
|
|
1b2e51d4d9 | ||
|
|
5bcbd5607e | ||
|
|
02f2ecee61 | ||
|
|
4c840f04e1 | ||
|
|
e6db599907 | ||
|
|
72092a9733 | ||
|
|
624af4f9af | ||
|
|
2b7b26374a | ||
|
|
48d1a31e08 | ||
|
|
2ecced376e | ||
|
|
da4cde70c3 | ||
|
|
9af2968a7d | ||
|
|
0ac4545c5b | ||
|
|
2aa43d3554 | ||
|
|
3e482c9c74 | ||
|
|
05f7651cf5 | ||
|
|
569be6e706 | ||
|
|
972e96ea68 | ||
|
|
d4316d0228 | ||
|
|
e481f97550 | ||
|
|
3937e03c02 | ||
|
|
d68c388cac | ||
|
|
e60078d939 | ||
|
|
39bc444db4 | ||
|
|
e8bafd8caa | ||
|
|
50e0869a17 | ||
|
|
867016757e | ||
|
|
1365388f0b | ||
|
|
73cc443213 | ||
|
|
4e759ab437 | ||
|
|
8c0f2ae87c | ||
|
|
2b1173acc3 | ||
|
|
26b46ec435 | ||
|
|
2100f97cbc | ||
|
|
607fd3a8e5 | ||
|
|
429928057d | ||
|
|
7f507dd77d | ||
|
|
ea0918e5e8 | ||
|
|
6b710209b1 | ||
|
|
3987026997 | ||
|
|
9aedabe11e | ||
|
|
4a3cec8c1f | ||
|
|
3229fcc900 | ||
|
|
910313cfde | ||
|
|
5b8eed0e8c | ||
|
|
6cd6bb2755 | ||
|
|
613f74ca1e | ||
|
|
5effa20a5b | ||
|
|
17c99ae00a | ||
|
|
9ec0c981f8 | ||
|
|
3d4e27fa0a | ||
|
|
c46441c937 | ||
|
|
5b6d424a77 | ||
|
|
76ac0f1555 | ||
|
|
74950d07dd | ||
|
|
894a46f30c | ||
|
|
8744162a0e | ||
|
|
4da3bdcd6e | ||
|
|
95ca4fb15e | ||
|
|
6dcf9f6588 | ||
|
|
4440671739 | ||
|
|
957d3deeea | ||
|
|
6e63df98ba | ||
|
|
1f2915bff0 | ||
|
|
63b8d2eb58 | ||
|
|
71bbaf556f | ||
|
|
8819bb0f21 | ||
|
|
215372fd78 | ||
|
|
97b3c9b7b6 | ||
|
|
43f1a32859 | ||
|
|
b45264af75 | ||
|
|
d9680c4c51 | ||
|
|
28b80ba42a | ||
|
|
f40e8ce6b7 | ||
|
|
d494d6b837 | ||
|
|
48326ce731 | ||
|
|
054c036e81 | ||
|
|
5e42e0f1f7 | ||
|
|
81ec47b283 | ||
|
|
c101b1f558 | ||
|
|
efb0e5a49f | ||
|
|
e214bb9eed | ||
|
|
5cd82cb2e2 | ||
|
|
cff190fa5f | ||
|
|
7ba3eeda98 | ||
|
|
239e39ddbc | ||
|
|
5768dcc320 | ||
|
|
1075209e2a | ||
|
|
54c552f90d | ||
|
|
d330d91e1a | ||
|
|
3613b4c096 | ||
|
|
45c4d1a06e | ||
|
|
d4d62fc9dc | ||
|
|
c4be0f4235 | ||
|
|
5825ab2dd4 | ||
|
|
585269ecb9 | ||
|
|
5432cbfaad | ||
|
|
4d25eaa24a | ||
|
|
58461ce250 | ||
|
|
57762d4328 | ||
|
|
652e30c97d | ||
|
|
49e061d15b | ||
|
|
28ad84c207 | ||
|
|
b546afd196 | ||
|
|
6974b378f3 | ||
|
|
4d36ecef9e | ||
|
|
8a02cb3378 | ||
|
|
15112ae1b6 | ||
|
|
c93b7037b4 | ||
|
|
56c3073da4 | ||
|
|
cee5508e9b | ||
|
|
b56e1217b6 | ||
|
|
fb2e8b6817 | ||
|
|
a94fa77621 | ||
|
|
f0af934891 | ||
|
|
dc15e44e2a | ||
|
|
a36ac96444 | ||
|
|
09c3ddd47d | ||
|
|
07f3075773 | ||
|
|
acc71c4eda | ||
|
|
4c22592c6f | ||
|
|
9708019312 | ||
|
|
14c0e8424b | ||
|
|
3c0f06c09c | ||
|
|
2c576ab312 | ||
|
|
3fed07419a | ||
|
|
aa27f0e743 | ||
|
|
a6fe4aa7e9 | ||
|
|
de7cfd61a0 | ||
|
|
1ff4d4e3ae | ||
|
|
744e9d06e5 | ||
|
|
428c637506 | ||
|
|
f67ae9b47e | ||
|
|
251708b908 | ||
|
|
40f73e4fa1 | ||
|
|
62e1721c52 | ||
|
|
57f70c0761 | ||
|
|
0699dc1000 | ||
|
|
2e3e64a4cf | ||
|
|
36d336841c | ||
|
|
bfd4aa2fed | ||
|
|
f060ecd705 | ||
|
|
5363cee847 | ||
|
|
31e4d80caf | ||
|
|
c7f69cc0df | ||
|
|
ee118152ff | ||
|
|
5ed8e01faf | ||
|
|
1a5c6631a5 | ||
|
|
acec7e34fc | ||
|
|
deca570544 | ||
|
|
7cfb2139d0 | ||
|
|
1a7a76511f | ||
|
|
8a22b2987f | ||
|
|
1eb8a4671f | ||
|
|
2fe3586eba | ||
|
|
805cb303d5 | ||
|
|
97307a7fc1 | ||
|
|
6ed1f83a87 | ||
|
|
04aff2e2f9 | ||
|
|
0268089ac6 | ||
|
|
5d5d338e10 | ||
|
|
8f1404eeef | ||
|
|
9dba097224 | ||
|
|
ce5c5833cb | ||
|
|
3cb2b72e92 | ||
|
|
88fda7c305 | ||
|
|
b8b5dccfd8 | ||
|
|
6880692a78 | ||
|
|
76911fbeb4 | ||
|
|
0eb245e177 | ||
|
|
c866ccb3a1 | ||
|
|
bb68e0bc3b | ||
|
|
f81f4490b0 | ||
|
|
c419d3286b | ||
|
|
d76743ed0b | ||
|
|
1e2aa769e5 | ||
|
|
8091c28dd5 | ||
|
|
eca1df4e2d | ||
|
|
3d8728488d | ||
|
|
650cbce017 | ||
|
|
058946772a | ||
|
|
b443900cc2 | ||
|
|
8fad60bada | ||
|
|
2e8a552c24 | ||
|
|
7c917c0e74 | ||
|
|
aee54fc8f3 | ||
|
|
e10e1f6eed | ||
|
|
0ccb597baf | ||
|
|
a3cbc1ff72 | ||
|
|
e7cf513064 | ||
|
|
3dc15a9259 | ||
|
|
bcee2fbd2d | ||
|
|
1b87f332b0 | ||
|
|
7839e121f6 | ||
|
|
2c4fa258a6 | ||
|
|
0e0159db0c | ||
|
|
b5bcdbaf48 | ||
|
|
c7b794a7c5 | ||
|
|
280bef834b | ||
|
|
df92495e31 | ||
|
|
e62aafdf58 | ||
|
|
a14c70019a | ||
|
|
48c8649891 | ||
|
|
b4eb015d86 | ||
|
|
3e00247a47 | ||
|
|
6bce7f7937 | ||
|
|
f3d3d8daed | ||
|
|
dcddfbff91 | ||
|
|
787426d4e6 | ||
|
|
c357adae44 | ||
|
|
9f5325fd52 | ||
|
|
7f3fa39d81 | ||
|
|
9a5f3fc2a7 | ||
|
|
7932cd22ca | ||
|
|
195eba188a | ||
|
|
9341cce8b3 | ||
|
|
2ac7232288 | ||
|
|
905135fe8c | ||
|
|
57f532a760 | ||
|
|
831dff8b4e | ||
|
|
4db7530f28 | ||
|
|
239e2adc68 | ||
|
|
1c60591eab | ||
|
|
5e53bbf405 | ||
|
|
fbaceea4c0 | ||
|
|
56ec5ca260 | ||
|
|
3ffd2cb9be | ||
|
|
cacec04df6 | ||
|
|
72ec98b8a8 | ||
|
|
a174ad011e | ||
|
|
e9cc23ea94 | ||
|
|
6c245f6cf1 | ||
|
|
dd92715ed2 | ||
|
|
b3d1278838 | ||
|
|
92c2101f7c | ||
|
|
ff46fb69d0 | ||
|
|
efc583c13e | ||
|
|
d882f8c928 | ||
|
|
213da7d862 | ||
|
|
9c5528490e | ||
|
|
7bfb51489b | ||
|
|
e1ef141112 | ||
|
|
5f27d649a6 | ||
|
|
cab103d172 | ||
|
|
084fdd9d10 | ||
|
|
74c064e477 | ||
|
|
14f27e4219 | ||
|
|
9a8ff68bc1 | ||
|
|
b461200211 | ||
|
|
aba2513322 | ||
|
|
cb8fc4dc9f | ||
|
|
47be87c7cc | ||
|
|
66d52199a7 | ||
|
|
f840327ffb | ||
|
|
719e36049b | ||
|
|
f583f993ee | ||
|
|
bcb1dfb86f | ||
|
|
d7a69f8aa1 | ||
|
|
f36b5f3e3c | ||
|
|
cdaa4d3ad7 | ||
|
|
8c73af048a | ||
|
|
e2121c5d75 | ||
|
|
9a7199a116 | ||
|
|
c549bbd72a | ||
|
|
c39d43dee1 | ||
|
|
b76e0b358f | ||
|
|
9bc309b416 | ||
|
|
65a39f43cb | ||
|
|
324c924ca4 | ||
|
|
75ad89670b | ||
|
|
d4f01bdb43 | ||
|
|
e1c9a956da | ||
|
|
c2137e33a0 | ||
|
|
c05010887f | ||
|
|
334aa8c941 | ||
|
|
5d2df70a79 | ||
|
|
af88ff1c49 | ||
|
|
40dc3e7c10 | ||
|
|
56b9149325 | ||
|
|
7ae631e0c1 | ||
|
|
84454f142d | ||
|
|
a335cbb8d5 | ||
|
|
0cf9218d3f | ||
|
|
2439625785 | ||
|
|
01e2826f26 | ||
|
|
01acea3102 | ||
|
|
5ae04349da | ||
|
|
aca6fdbd0e | ||
|
|
e4bb6409ae | ||
|
|
b282ff44d4 | ||
|
|
8160c2884b | ||
|
|
c91b16d2a1 | ||
|
|
65429cebae | ||
|
|
4449b0d3c2 | ||
|
|
589f93da92 | ||
|
|
5296bd10c1 | ||
|
|
d100c014bc | ||
|
|
2cf75116d9 | ||
|
|
a45f7ac1bc | ||
|
|
e75de542df | ||
|
|
252963190b | ||
|
|
93de4c67e5 | ||
|
|
23791a45c8 | ||
|
|
355e7468e4 | ||
|
|
496ceed1d0 | ||
|
|
1205bce0ef | ||
|
|
c03fe508c1 | ||
|
|
6895e634cc | ||
|
|
86015bef78 | ||
|
|
bd724fc304 | ||
|
|
6e6f66de2e | ||
|
|
daa935b5c9 | ||
|
|
6fa1ec4f3c | ||
|
|
363ca66c2d | ||
|
|
b8f5911c4e | ||
|
|
30b74e74cd | ||
|
|
c400702272 | ||
|
|
dce846fdfd | ||
|
|
bbda08717f | ||
|
|
2eeeaf5753 | ||
|
|
7299202d01 | ||
|
|
1f63350eba | ||
|
|
cb26ad511b | ||
|
|
139621778b | ||
|
|
ae4e01adc9 | ||
|
|
6d6cafafb2 | ||
|
|
0d3c5c966b | ||
|
|
18012d9ee8 | ||
|
|
a6da5f9e77 | ||
|
|
c418074360 | ||
|
|
f0b64547c2 | ||
|
|
1f94208090 | ||
|
|
5268bf5a8c | ||
|
|
a097e29292 | ||
|
|
9f07c7940f | ||
|
|
1adcf5225b | ||
|
|
c439324451 | ||
|
|
66b46a277e | ||
|
|
9adfc04f75 | ||
|
|
28f383bae9 | ||
|
|
b04e437cfd | ||
|
|
0a00df2e7e | ||
|
|
aa76c9db2e | ||
|
|
f56471566b | ||
|
|
14544d64e4 | ||
|
|
2646b24047 | ||
|
|
ac2469077f | ||
|
|
b2b577257f | ||
|
|
8f9ffe5417 | ||
|
|
a4a0751051 | ||
|
|
904aea76ab | ||
|
|
b5c6b04b36 | ||
|
|
656b9f97f9 | ||
|
|
db66cb6e9b | ||
|
|
7e0ccce225 | ||
|
|
2ad615cd32 | ||
|
|
151668b260 | ||
|
|
f237789753 | ||
|
|
0f7cae4130 | ||
|
|
b5be62a167 | ||
|
|
6eaf44ec61 | ||
|
|
8ee0377456 | ||
|
|
d42502fab9 | ||
|
|
b534619d37 | ||
|
|
2aec0a92a5 | ||
|
|
7c3b361fa6 | ||
|
|
da8136e49d | ||
|
|
1f4a34ffc8 | ||
|
|
3b18caf229 | ||
|
|
7ca4d40d49 | ||
|
|
d844f6113d | ||
|
|
8eb3aa56ca | ||
|
|
f446a0f97f | ||
|
|
e3efa9a5e2 |
18
.github/dependabot.yml
vendored
Normal file
18
.github/dependabot.yml
vendored
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
version: 2
|
||||||
|
updates:
|
||||||
|
- package-ecosystem: cargo
|
||||||
|
directory: "/"
|
||||||
|
schedule:
|
||||||
|
interval: daily
|
||||||
|
open-pull-requests-limit: 3
|
||||||
|
allow:
|
||||||
|
- dependency-type: direct
|
||||||
|
- dependency-type: indirect
|
||||||
|
- package-ecosystem: cargo
|
||||||
|
directory: "/fuzz"
|
||||||
|
schedule:
|
||||||
|
interval: daily
|
||||||
|
open-pull-requests-limit: 3
|
||||||
|
allow:
|
||||||
|
- dependency-type: direct
|
||||||
|
- dependency-type: indirect
|
||||||
11
.github/workflows/build.yaml
vendored
11
.github/workflows/build.yaml
vendored
@@ -31,7 +31,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Debug Check (default features)
|
- name: Debug Check (default features)
|
||||||
run: |
|
run: |
|
||||||
git rev-list origin/master..$GITHUB_SHA | xargs -t -I % sh -c 'git checkout %; cargo check --all --target=${{ matrix.target }}'
|
git rev-list origin/main..$GITHUB_SHA | xargs -t -I % sh -c 'git checkout %; cargo check --all --target=${{ matrix.target }}'
|
||||||
git checkout $GITHUB_SHA
|
git checkout $GITHUB_SHA
|
||||||
|
|
||||||
- name: Build (acpi,kvm)
|
- name: Build (acpi,kvm)
|
||||||
@@ -39,6 +39,15 @@ jobs:
|
|||||||
|
|
||||||
- name: Build (kvm)
|
- name: Build (kvm)
|
||||||
run: cargo rustc --bin cloud-hypervisor --no-default-features --features "kvm" -- -D warnings
|
run: cargo rustc --bin cloud-hypervisor --no-default-features --features "kvm" -- -D warnings
|
||||||
|
|
||||||
|
- name: Build (acpi,mshv)
|
||||||
|
run: cargo rustc --bin cloud-hypervisor --no-default-features --features "acpi,mshv" -- -D warnings
|
||||||
|
|
||||||
|
- name: Build (mshv)
|
||||||
|
run: cargo rustc --bin cloud-hypervisor --no-default-features --features "mshv" -- -D warnings
|
||||||
|
|
||||||
- name: Release Build (default features)
|
- name: Release Build (default features)
|
||||||
run: cargo build --all --release --target=${{ matrix.target }}
|
run: cargo build --all --release --target=${{ matrix.target }}
|
||||||
|
|
||||||
|
- name: Check build did not modify any files
|
||||||
|
run: test -z "$(git status --porcelain)"
|
||||||
|
|||||||
18
.github/workflows/dco.yaml
vendored
Normal file
18
.github/workflows/dco.yaml
vendored
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
name: DCO
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
jobs:
|
||||||
|
check:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- name: Set up Python 3.x
|
||||||
|
uses: actions/setup-python@v1
|
||||||
|
with:
|
||||||
|
python-version: '3.x'
|
||||||
|
- name: Check DCO
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
run: |
|
||||||
|
pip3 install -U dco-check
|
||||||
|
dco-check
|
||||||
2
.github/workflows/docker-image.yaml
vendored
2
.github/workflows/docker-image.yaml
vendored
@@ -2,7 +2,7 @@ name: Cloud-Hypervisor's Docker image update
|
|||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: master
|
branches: main
|
||||||
paths: resources/Dockerfile
|
paths: resources/Dockerfile
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
|
|||||||
4
.github/workflows/fuzz-build.yaml
vendored
4
.github/workflows/fuzz-build.yaml
vendored
@@ -22,6 +22,8 @@ jobs:
|
|||||||
target: ${{ matrix.target }}
|
target: ${{ matrix.target }}
|
||||||
override: true
|
override: true
|
||||||
- name: Install Cargo fuzz
|
- name: Install Cargo fuzz
|
||||||
run: cargo install -f cargo-fuzz
|
# Temporary fix for cargo-fuzz on latest nightly: https://github.com/rust-fuzz/cargo-fuzz/issues/276
|
||||||
|
#run: cargo install cargo-fuzz
|
||||||
|
run: cargo install --git https://github.com/rust-fuzz/cargo-fuzz --rev b4df3e58f767b5cad8d1aa6753961003f56f3609
|
||||||
- name: Cargo Fuzz Build
|
- name: Cargo Fuzz Build
|
||||||
run: cargo fuzz build
|
run: cargo fuzz build
|
||||||
|
|||||||
26
.github/workflows/quality-aarch64.yaml
vendored
26
.github/workflows/quality-aarch64.yaml
vendored
@@ -29,13 +29,33 @@ jobs:
|
|||||||
target: ${{ matrix.target }}
|
target: ${{ matrix.target }}
|
||||||
override: true
|
override: true
|
||||||
components: rustfmt, clippy
|
components: rustfmt, clippy
|
||||||
- name: Install arm64 libfdt
|
|
||||||
run: wget http://ftp.us.debian.org/debian/pool/main/d/device-tree-compiler/libfdt-dev_1.6.0-1_arm64.deb && dpkg-deb -xv libfdt-dev_1.6.0-1_arm64.deb ./tlibfdtdev && mkdir -p target/debug/deps && sudo cp ./tlibfdtdev/usr/lib/aarch64-linux-gnu/libfdt.a target/debug/deps/libfdt.a && echo "libfdt installed"
|
|
||||||
- name: Formatting (rustfmt)
|
- name: Formatting (rustfmt)
|
||||||
run: cargo fmt -- --check
|
run: cargo fmt -- --check
|
||||||
|
|
||||||
- name: Clippy (kvm)
|
- name: Clippy (kvm)
|
||||||
uses: actions-rs/cargo@v1
|
uses: actions-rs/cargo@v1
|
||||||
with:
|
with:
|
||||||
use-cross: true
|
use-cross: true
|
||||||
command: clippy
|
command: clippy
|
||||||
args: --target=${{ matrix.target }} --no-default-features --features "kvm" -- -D warnings
|
args: --target=${{ matrix.target }} --all --no-default-features --features "kvm" -- -D warnings
|
||||||
|
|
||||||
|
- name: Clippy (kvm,acpi)
|
||||||
|
uses: actions-rs/cargo@v1
|
||||||
|
with:
|
||||||
|
use-cross: true
|
||||||
|
command: clippy
|
||||||
|
args: --target=${{ matrix.target }} --all --no-default-features --features "kvm,acpi" -- -D warnings
|
||||||
|
|
||||||
|
- name: Clippy (all features,kvm)
|
||||||
|
uses: actions-rs/cargo@v1
|
||||||
|
with:
|
||||||
|
use-cross: true
|
||||||
|
command: clippy
|
||||||
|
args: --target=${{ matrix.target }} --all --no-default-features --features "common,kvm" -- -D warnings
|
||||||
|
|
||||||
|
- name: Clippy (default)
|
||||||
|
uses: actions-rs/cargo@v1
|
||||||
|
with:
|
||||||
|
use-cross: true
|
||||||
|
command: clippy
|
||||||
|
args: --target=${{ matrix.target }} --all -- -D warnings
|
||||||
|
|||||||
3
.github/workflows/quality.yaml
vendored
3
.github/workflows/quality.yaml
vendored
@@ -56,3 +56,6 @@ jobs:
|
|||||||
|
|
||||||
- name: Clippy (integration tests)
|
- name: Clippy (integration tests)
|
||||||
run: cargo clippy --all --all-targets --tests --features "integration_tests" -- -D warnings
|
run: cargo clippy --all --all-targets --tests --features "integration_tests" -- -D warnings
|
||||||
|
|
||||||
|
- name: Check build did not modify any files
|
||||||
|
run: test -z "$(git status --porcelain)"
|
||||||
|
|||||||
32
.github/workflows/release.yaml
vendored
32
.github/workflows/release.yaml
vendored
@@ -25,6 +25,18 @@ jobs:
|
|||||||
run: cargo build --all --release --target=x86_64-unknown-linux-musl
|
run: cargo build --all --release --target=x86_64-unknown-linux-musl
|
||||||
- name: Strip cloud-hypervisor binaries
|
- name: Strip cloud-hypervisor binaries
|
||||||
run: strip target/*/release/cloud-hypervisor
|
run: strip target/*/release/cloud-hypervisor
|
||||||
|
- name: Install Rust toolchain (aarch64-unknown-linux-musl)
|
||||||
|
uses: actions-rs/toolchain@v1
|
||||||
|
with:
|
||||||
|
toolchain: stable
|
||||||
|
target: aarch64-unknown-linux-musl
|
||||||
|
override: true
|
||||||
|
- name: Static Build (AArch64)
|
||||||
|
uses: actions-rs/cargo@v1
|
||||||
|
with:
|
||||||
|
use-cross: true
|
||||||
|
command: build
|
||||||
|
args: --all --release --target=aarch64-unknown-linux-musl
|
||||||
- name: Create Release
|
- name: Create Release
|
||||||
id: create_release
|
id: create_release
|
||||||
uses: actions/create-release@v1
|
uses: actions/create-release@v1
|
||||||
@@ -65,3 +77,23 @@ jobs:
|
|||||||
asset_path: target/x86_64-unknown-linux-gnu/release/ch-remote
|
asset_path: target/x86_64-unknown-linux-gnu/release/ch-remote
|
||||||
asset_name: ch-remote
|
asset_name: ch-remote
|
||||||
asset_content_type: application/octet-stream
|
asset_content_type: application/octet-stream
|
||||||
|
- name: Upload static AArch64 cloud-hypervisor
|
||||||
|
id: upload-release-static-aarch64-cloud-hypervisor
|
||||||
|
uses: actions/upload-release-asset@v1
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
with:
|
||||||
|
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||||
|
asset_path: target/aarch64-unknown-linux-musl/release/cloud-hypervisor
|
||||||
|
asset_name: cloud-hypervisor-static-aarch64
|
||||||
|
asset_content_type: application/octet-stream
|
||||||
|
- name: Upload static AArch64 ch-remote
|
||||||
|
id: upload-release-static-aarch64-ch-remote
|
||||||
|
uses: actions/upload-release-asset@v1
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
with:
|
||||||
|
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||||
|
asset_path: target/aarch64-unknown-linux-musl/release/ch-remote
|
||||||
|
asset_name: ch-remote-static-aarch64
|
||||||
|
asset_content_type: application/octet-stream
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ you want to merge your changes to `cloud-hypervisor`:
|
|||||||
into your github organization.
|
into your github organization.
|
||||||
2. Within your fork, create a branch for your contribution.
|
2. Within your fork, create a branch for your contribution.
|
||||||
3. [Create a pull request](https://help.github.com/articles/creating-a-pull-request-from-a-fork/)
|
3. [Create a pull request](https://help.github.com/articles/creating-a-pull-request-from-a-fork/)
|
||||||
against the master branch of the Cloud Hypervisor repository.
|
against the main branch of the Cloud Hypervisor repository.
|
||||||
4. Add reviewers to your pull request and then work with your reviewers to address
|
4. Add reviewers to your pull request and then work with your reviewers to address
|
||||||
any comments and obtain minimum of 2 [maintainers](MAINTAINERS.md) approvals.
|
any comments and obtain minimum of 2 [maintainers](MAINTAINERS.md) approvals.
|
||||||
To update your pull request amend existing commits whenever applicable and
|
To update your pull request amend existing commits whenever applicable and
|
||||||
|
|||||||
681
Cargo.lock
generated
681
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
30
Cargo.toml
30
Cargo.toml
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "cloud-hypervisor"
|
name = "cloud-hypervisor"
|
||||||
version = "15.0.0"
|
version = "19.0.0"
|
||||||
authors = ["The Cloud Hypervisor Authors"]
|
authors = ["The Cloud Hypervisor Authors"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
default-run = "cloud-hypervisor"
|
default-run = "cloud-hypervisor"
|
||||||
@@ -13,41 +13,42 @@ homepage = "https://github.com/cloud-hypervisor/cloud-hypervisor"
|
|||||||
lto = true
|
lto = true
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "1.0.40"
|
anyhow = "1.0.44"
|
||||||
api_client = { path = "api_client" }
|
api_client = { path = "api_client" }
|
||||||
clap = { version = "2.33.3", features = ["wrap_help"] }
|
clap = { version = "2.33.3", features = ["wrap_help"] }
|
||||||
epoll = "4.3.1"
|
epoll = "4.3.1"
|
||||||
event_monitor = { path = "event_monitor" }
|
event_monitor = { path = "event_monitor" }
|
||||||
hypervisor = { path = "hypervisor" }
|
hypervisor = { path = "hypervisor" }
|
||||||
libc = "0.2.94"
|
libc = "0.2.103"
|
||||||
log = { version = "0.4.14", features = ["std"] }
|
log = { version = "0.4.14", features = ["std"] }
|
||||||
option_parser = { path = "option_parser" }
|
option_parser = { path = "option_parser" }
|
||||||
seccomp = { git = "https://github.com/firecracker-microvm/firecracker", tag = "v0.24.2" }
|
seccompiler = "0.2.0"
|
||||||
serde_json = "1.0.64"
|
serde_json = "1.0.68"
|
||||||
signal-hook = "0.3.8"
|
signal-hook = "0.3.10"
|
||||||
thiserror = "1.0.24"
|
thiserror = "1.0.30"
|
||||||
vmm = { path = "vmm" }
|
vmm = { path = "vmm" }
|
||||||
vmm-sys-util = "0.8.0"
|
vmm-sys-util = "0.9.0"
|
||||||
vm-memory = "0.5.0"
|
vm-memory = "0.6.0"
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
clap = { version = "2.33.3", features = ["wrap_help"] }
|
clap = { version = "2.33.3", features = ["wrap_help"] }
|
||||||
|
|
||||||
# List of patched crates
|
# List of patched crates
|
||||||
[patch.crates-io]
|
[patch.crates-io]
|
||||||
kvm-bindings = { git = "https://github.com/cloud-hypervisor/kvm-bindings", branch = "ch-v0.4.0", features = ["with-serde", "fam-wrappers"] }
|
kvm-bindings = { git = "https://github.com/cloud-hypervisor/kvm-bindings", branch = "ch-v0.5.0", features = ["with-serde", "fam-wrappers"] }
|
||||||
|
versionize_derive = { git = "https://github.com/cloud-hypervisor/versionize_derive", branch = "ch" }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
credibility = "0.1.3"
|
credibility = "0.1.3"
|
||||||
dirs = "3.0.2"
|
dirs = "4.0.0"
|
||||||
lazy_static= "1.4.0"
|
lazy_static= "1.4.0"
|
||||||
net_util = { path = "net_util" }
|
net_util = { path = "net_util" }
|
||||||
serde_json = "1.0.64"
|
serde_json = "1.0.68"
|
||||||
test_infra = { path = "test_infra" }
|
test_infra = { path = "test_infra" }
|
||||||
wait-timeout = "0.2.0"
|
wait-timeout = "0.2.0"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["acpi", "cmos", "io_uring", "kvm"]
|
default = ["common", "kvm"]
|
||||||
# Common features for all hypervisors
|
# Common features for all hypervisors
|
||||||
common = ["acpi", "cmos", "fwdebug", "io_uring"]
|
common = ["acpi", "cmos", "fwdebug", "io_uring"]
|
||||||
acpi = ["vmm/acpi"]
|
acpi = ["vmm/acpi"]
|
||||||
@@ -66,7 +67,6 @@ members = [
|
|||||||
"acpi_tables",
|
"acpi_tables",
|
||||||
"api_client",
|
"api_client",
|
||||||
"arch",
|
"arch",
|
||||||
"arch_gen",
|
|
||||||
"block_util",
|
"block_util",
|
||||||
"devices",
|
"devices",
|
||||||
"event_monitor",
|
"event_monitor",
|
||||||
@@ -77,6 +77,8 @@ members = [
|
|||||||
"pci",
|
"pci",
|
||||||
"qcow",
|
"qcow",
|
||||||
"rate_limiter",
|
"rate_limiter",
|
||||||
|
"vfio_user",
|
||||||
|
"vhdx",
|
||||||
"vhost_user_backend",
|
"vhost_user_backend",
|
||||||
"vhost_user_block",
|
"vhost_user_block",
|
||||||
"vhost_user_net",
|
"vhost_user_net",
|
||||||
|
|||||||
75
Jenkinsfile
vendored
75
Jenkinsfile
vendored
@@ -2,7 +2,7 @@ pipeline{
|
|||||||
agent none
|
agent none
|
||||||
stages {
|
stages {
|
||||||
stage ('Early checks') {
|
stage ('Early checks') {
|
||||||
agent { node { label 'master' } }
|
agent { node { label 'built-in' } }
|
||||||
stages {
|
stages {
|
||||||
stage ('Check for RFC/WIP builds') {
|
stage ('Check for RFC/WIP builds') {
|
||||||
when {
|
when {
|
||||||
@@ -14,7 +14,7 @@ pipeline{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
stage ('Cancel older builds') {
|
stage ('Cancel older builds') {
|
||||||
when { not { branch 'master' } }
|
when { not { branch 'main' } }
|
||||||
steps {
|
steps {
|
||||||
cancelPreviousBuilds()
|
cancelPreviousBuilds()
|
||||||
}
|
}
|
||||||
@@ -24,7 +24,7 @@ pipeline{
|
|||||||
stage ('Build') {
|
stage ('Build') {
|
||||||
parallel {
|
parallel {
|
||||||
stage ('Worker build') {
|
stage ('Worker build') {
|
||||||
agent { node { label 'groovy' } }
|
agent { node { label 'hirsute' } }
|
||||||
stages {
|
stages {
|
||||||
stage ('Checkout') {
|
stage ('Checkout') {
|
||||||
steps {
|
steps {
|
||||||
@@ -46,6 +46,7 @@ pipeline{
|
|||||||
timeout(time: 1, unit: 'HOURS')
|
timeout(time: 1, unit: 'HOURS')
|
||||||
}
|
}
|
||||||
steps {
|
steps {
|
||||||
|
sh "sudo modprobe openvswitch"
|
||||||
sh "scripts/dev_cli.sh tests --integration"
|
sh "scripts/dev_cli.sh tests --integration"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -69,6 +70,7 @@ pipeline{
|
|||||||
timeout(time: 1, unit: 'HOURS')
|
timeout(time: 1, unit: 'HOURS')
|
||||||
}
|
}
|
||||||
steps {
|
steps {
|
||||||
|
sh "sudo modprobe openvswitch"
|
||||||
sh "scripts/dev_cli.sh tests --integration"
|
sh "scripts/dev_cli.sh tests --integration"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -81,7 +83,7 @@ pipeline{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
stage ('Worker build (musl)') {
|
stage ('Worker build (musl)') {
|
||||||
agent { node { label 'groovy' } }
|
agent { node { label 'hirsute' } }
|
||||||
stages {
|
stages {
|
||||||
stage ('Checkout') {
|
stage ('Checkout') {
|
||||||
steps {
|
steps {
|
||||||
@@ -98,6 +100,7 @@ pipeline{
|
|||||||
timeout(time: 1, unit: 'HOURS')
|
timeout(time: 1, unit: 'HOURS')
|
||||||
}
|
}
|
||||||
steps {
|
steps {
|
||||||
|
sh "sudo modprobe openvswitch"
|
||||||
sh "scripts/dev_cli.sh tests --integration --libc musl"
|
sh "scripts/dev_cli.sh tests --integration --libc musl"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -105,7 +108,10 @@ pipeline{
|
|||||||
}
|
}
|
||||||
stage ('Worker build SGX') {
|
stage ('Worker build SGX') {
|
||||||
agent { node { label 'bionic-sgx' } }
|
agent { node { label 'bionic-sgx' } }
|
||||||
when { branch 'master' }
|
when {
|
||||||
|
beforeAgent true
|
||||||
|
branch 'main'
|
||||||
|
}
|
||||||
stages {
|
stages {
|
||||||
stage ('Checkout') {
|
stage ('Checkout') {
|
||||||
steps {
|
steps {
|
||||||
@@ -138,7 +144,10 @@ pipeline{
|
|||||||
}
|
}
|
||||||
stage ('Worker build VFIO') {
|
stage ('Worker build VFIO') {
|
||||||
agent { node { label 'bionic-vfio' } }
|
agent { node { label 'bionic-vfio' } }
|
||||||
when { branch 'master' }
|
when {
|
||||||
|
beforeAgent true
|
||||||
|
branch 'main'
|
||||||
|
}
|
||||||
stages {
|
stages {
|
||||||
stage ('Checkout') {
|
stage ('Checkout') {
|
||||||
steps {
|
steps {
|
||||||
@@ -170,7 +179,10 @@ pipeline{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
stage ('Worker build - Windows guest') {
|
stage ('Worker build - Windows guest') {
|
||||||
agent { node { label 'groovy-win' } }
|
agent { node { label 'hirsute' } }
|
||||||
|
environment {
|
||||||
|
AZURE_CONNECTION_STRING = credentials('46b4e7d6-315f-4cc1-8333-b58780863b9b')
|
||||||
|
}
|
||||||
stages {
|
stages {
|
||||||
stage ('Checkout') {
|
stage ('Checkout') {
|
||||||
steps {
|
steps {
|
||||||
@@ -179,17 +191,10 @@ pipeline{
|
|||||||
}
|
}
|
||||||
stage ('Download assets') {
|
stage ('Download assets') {
|
||||||
steps {
|
steps {
|
||||||
|
sh "sudo apt install -y azure-cli"
|
||||||
sh "mkdir ${env.HOME}/workloads"
|
sh "mkdir ${env.HOME}/workloads"
|
||||||
azureDownload(storageCredentialId: 'ch-image-store',
|
sh 'az storage blob download --container-name private-images --file "$HOME/workloads/OVMF-4b47d0c6c8.fd" --name OVMF-4b47d0c6c8.fd --connection-string "$AZURE_CONNECTION_STRING"'
|
||||||
containerName: 'private-images',
|
sh 'az storage blob download --container-name private-images --file "$HOME/workloads/windows-server-2019.raw" --name windows-server-2019.raw --connection-string "$AZURE_CONNECTION_STRING"'
|
||||||
includeFilesPattern: 'OVMF-4b47d0c6c8.fd',
|
|
||||||
downloadType: 'container',
|
|
||||||
downloadDirLoc: "${env.HOME}/workloads")
|
|
||||||
azureDownload(storageCredentialId: 'ch-image-store',
|
|
||||||
containerName: 'private-images',
|
|
||||||
includeFilesPattern: 'windows-server-2019.raw',
|
|
||||||
downloadType: 'container',
|
|
||||||
downloadDirLoc: "${env.HOME}/workloads")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
stage ('Run Windows guest integration tests') {
|
stage ('Run Windows guest integration tests') {
|
||||||
@@ -210,21 +215,49 @@ pipeline{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
stage ('Worker build - Live Migration') {
|
||||||
|
agent { node { label 'hirsute-small' } }
|
||||||
|
stages {
|
||||||
|
stage ('Checkout') {
|
||||||
|
steps {
|
||||||
|
checkout scm
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stage ('Run live-migration integration tests') {
|
||||||
|
options {
|
||||||
|
timeout(time: 1, unit: 'HOURS')
|
||||||
|
}
|
||||||
|
steps {
|
||||||
|
sh "sudo modprobe openvswitch"
|
||||||
|
sh "scripts/dev_cli.sh tests --integration-live-migration"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stage ('Run live-migration integration tests for musl') {
|
||||||
|
options {
|
||||||
|
timeout(time: 1, unit: 'HOURS')
|
||||||
|
}
|
||||||
|
steps {
|
||||||
|
sh "sudo modprobe openvswitch"
|
||||||
|
sh "scripts/dev_cli.sh tests --integration-live-migration --libc musl"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
post {
|
post {
|
||||||
regression {
|
regression {
|
||||||
script {
|
script {
|
||||||
if (env.BRANCH_NAME == 'master') {
|
if (env.BRANCH_NAME == 'main') {
|
||||||
slackSend (color: '#ff0000', message: '"master" branch build is now failing')
|
slackSend (color: '#ff0000', message: '"main" branch build is now failing')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fixed {
|
fixed {
|
||||||
script {
|
script {
|
||||||
if (env.BRANCH_NAME == 'master') {
|
if (env.BRANCH_NAME == 'main') {
|
||||||
slackSend (color: '#00ff00', message: '"master" branch build is now fixed')
|
slackSend (color: '#00ff00', message: '"main" branch build is now fixed')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
# Maintainers
|
# Maintainers
|
||||||
|
|
||||||
- Sebastien Boeuf <sebastien.boeuf@intel.com> @sboeuf
|
- Sebastien Boeuf - @sboeuf
|
||||||
- Robert Bradford <robert.bradford@intel.com> @rbradford
|
- Robert Bradford - @rbradford
|
||||||
- Samuel Ortiz <sameo@linux.intel.com> @sameo
|
- Samuel Ortiz - @sameo
|
||||||
- Chao P Peng <chao.p.peng@linux.intel.com> @chao-p
|
- Wei Liu - @liuw
|
||||||
|
- Michael Zhao - @michael2012z
|
||||||
|
|||||||
10
README.md
10
README.md
@@ -1,11 +1,10 @@
|
|||||||
[](https://travis-ci.com/cloud-hypervisor/cloud-hypervisor)
|
|
||||||
|
|
||||||
- [1. What is Cloud Hypervisor?](#1-what-is-cloud-hypervisor)
|
- [1. What is Cloud Hypervisor?](#1-what-is-cloud-hypervisor)
|
||||||
- [Objectives](#objectives)
|
- [Objectives](#objectives)
|
||||||
- [High Level](#high-level)
|
- [High Level](#high-level)
|
||||||
- [Architectures](#architectures)
|
- [Architectures](#architectures)
|
||||||
- [Guest OS](#guest-os)
|
- [Guest OS](#guest-os)
|
||||||
- [2. Getting Started](#2-getting-started)
|
- [2. Getting Started](#2-getting-started)
|
||||||
|
- [Install prerequisites](#install-prerequisites)
|
||||||
- [Clone and build](#clone-and-build)
|
- [Clone and build](#clone-and-build)
|
||||||
- [Containerized builds and tests](#containerized-builds-and-tests)
|
- [Containerized builds and tests](#containerized-builds-and-tests)
|
||||||
- [Run](#run)
|
- [Run](#run)
|
||||||
@@ -23,6 +22,7 @@
|
|||||||
- [5. Community](#5-community)
|
- [5. Community](#5-community)
|
||||||
- [Contribute](#contribute)
|
- [Contribute](#contribute)
|
||||||
- [Join us](#join-us)
|
- [Join us](#join-us)
|
||||||
|
- [Security issues](#security-issues)
|
||||||
|
|
||||||
# 1. What is Cloud Hypervisor?
|
# 1. What is Cloud Hypervisor?
|
||||||
|
|
||||||
@@ -149,7 +149,7 @@ We need to get the latest `rust-hypervisor-firmware` release and also a working
|
|||||||
$ pushd $CLOUDH
|
$ pushd $CLOUDH
|
||||||
$ wget https://cloud-images.ubuntu.com/focal/current/focal-server-cloudimg-amd64.img
|
$ wget https://cloud-images.ubuntu.com/focal/current/focal-server-cloudimg-amd64.img
|
||||||
$ qemu-img convert -p -f qcow2 -O raw focal-server-cloudimg-amd64.img focal-server-cloudimg-amd64.raw
|
$ qemu-img convert -p -f qcow2 -O raw focal-server-cloudimg-amd64.img focal-server-cloudimg-amd64.raw
|
||||||
$ wget https://github.com/cloud-hypervisor/rust-hypervisor-firmware/releases/download/0.3.1/hypervisor-fw
|
$ wget https://github.com/cloud-hypervisor/rust-hypervisor-firmware/releases/download/0.3.2/hypervisor-fw
|
||||||
$ popd
|
$ popd
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -180,7 +180,7 @@ To build the kernel:
|
|||||||
|
|
||||||
# Clone the Cloud Hypervisor Linux branch
|
# Clone the Cloud Hypervisor Linux branch
|
||||||
$ pushd $CLOUDH
|
$ pushd $CLOUDH
|
||||||
$ git clone --depth 1 https://github.com/cloud-hypervisor/linux.git -b ch-5.12 linux-cloud-hypervisor
|
$ git clone --depth 1 https://github.com/cloud-hypervisor/linux.git -b ch-5.14 linux-cloud-hypervisor
|
||||||
$ pushd linux-cloud-hypervisor
|
$ pushd linux-cloud-hypervisor
|
||||||
|
|
||||||
# Use the cloud-hypervisor kernel config to build your kernel
|
# Use the cloud-hypervisor kernel config to build your kernel
|
||||||
@@ -205,7 +205,7 @@ $ popd
|
|||||||
#### Booting the guest VM
|
#### Booting the guest VM
|
||||||
|
|
||||||
Now we can directly boot into our custom kernel and make it use the Ubuntu root partition.
|
Now we can directly boot into our custom kernel and make it use the Ubuntu root partition.
|
||||||
If we want to have 4 vCPUs and 512 MBytes of memory:
|
If we want to have 4 vCPUs and 1024 MBytes of memory:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
$ pushd $CLOUDH
|
$ pushd $CLOUDH
|
||||||
|
|||||||
@@ -5,5 +5,4 @@ authors = ["The Cloud Hypervisor Authors"]
|
|||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
vm-memory = "0.5.0"
|
vm-memory = "0.6.0"
|
||||||
|
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ impl Rsdp {
|
|||||||
};
|
};
|
||||||
|
|
||||||
rsdp.checksum = super::generate_checksum(&rsdp.as_slice()[0..19]);
|
rsdp.checksum = super::generate_checksum(&rsdp.as_slice()[0..19]);
|
||||||
rsdp.extended_checksum = super::generate_checksum(&rsdp.as_slice());
|
rsdp.extended_checksum = super::generate_checksum(rsdp.as_slice());
|
||||||
rsdp
|
rsdp
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -22,6 +22,15 @@ impl GenericAddress {
|
|||||||
address: u64::from(address),
|
address: u64::from(address),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
pub fn mmio_address<T>(address: u64) -> Self {
|
||||||
|
GenericAddress {
|
||||||
|
address_space_id: 0,
|
||||||
|
register_bit_width: 8 * std::mem::size_of::<T>() as u8,
|
||||||
|
register_bit_offset: 0,
|
||||||
|
access_size: std::mem::size_of::<T>() as u8,
|
||||||
|
address,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Sdt {
|
pub struct Sdt {
|
||||||
@@ -66,7 +75,7 @@ impl Sdt {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn as_slice(&self) -> &[u8] {
|
pub fn as_slice(&self) -> &[u8] {
|
||||||
&self.data.as_slice()
|
self.data.as_slice()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn append<T>(&mut self, value: T) {
|
pub fn append<T>(&mut self, value: T) {
|
||||||
|
|||||||
@@ -3,3 +3,6 @@ name = "api_client"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
authors = ["The Cloud Hypervisor Authors"]
|
authors = ["The Cloud Hypervisor Authors"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
vmm-sys-util = "0.9.0"
|
||||||
|
|||||||
@@ -5,10 +5,13 @@
|
|||||||
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::io::{Read, Write};
|
use std::io::{Read, Write};
|
||||||
|
use std::os::unix::io::RawFd;
|
||||||
|
use vmm_sys_util::sock_ctrl_msg::ScmSocket;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
Socket(std::io::Error),
|
Socket(std::io::Error),
|
||||||
|
SocketSendFds(vmm_sys_util::errno::Error),
|
||||||
StatusCodeParsing(std::num::ParseIntError),
|
StatusCodeParsing(std::num::ParseIntError),
|
||||||
MissingProtocol,
|
MissingProtocol,
|
||||||
ContentLengthParsing(std::num::ParseIntError),
|
ContentLengthParsing(std::num::ParseIntError),
|
||||||
@@ -20,6 +23,7 @@ impl fmt::Display for Error {
|
|||||||
use Error::*;
|
use Error::*;
|
||||||
match self {
|
match self {
|
||||||
Socket(e) => write!(f, "Error writing to or reading from HTTP socket: {}", e),
|
Socket(e) => write!(f, "Error writing to or reading from HTTP socket: {}", e),
|
||||||
|
SocketSendFds(e) => write!(f, "Error writing to or reading from HTTP socket: {}", e),
|
||||||
StatusCodeParsing(e) => write!(f, "Error parsing HTTP status code: {}", e),
|
StatusCodeParsing(e) => write!(f, "Error parsing HTTP status code: {}", e),
|
||||||
MissingProtocol => write!(f, "HTTP output is missing protocol statement"),
|
MissingProtocol => write!(f, "HTTP output is missing protocol statement"),
|
||||||
ContentLengthParsing(e) => write!(f, "Error parsing HTTP Content-Length field: {}", e),
|
ContentLengthParsing(e) => write!(f, "Error parsing HTTP Content-Length field: {}", e),
|
||||||
@@ -133,21 +137,23 @@ fn parse_http_response(socket: &mut dyn Read) -> Result<Option<String>, Error> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn simple_api_command<T: Read + Write>(
|
pub fn simple_api_command_with_fds<T: Read + Write + ScmSocket>(
|
||||||
socket: &mut T,
|
socket: &mut T,
|
||||||
method: &str,
|
method: &str,
|
||||||
c: &str,
|
c: &str,
|
||||||
request_body: Option<&str>,
|
request_body: Option<&str>,
|
||||||
|
request_fds: Vec<RawFd>,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
socket
|
socket
|
||||||
.write_all(
|
.send_with_fds(
|
||||||
format!(
|
&[format!(
|
||||||
"{} /api/v1/vm.{} HTTP/1.1\r\nHost: localhost\r\nAccept: */*\r\n",
|
"{} /api/v1/vm.{} HTTP/1.1\r\nHost: localhost\r\nAccept: */*\r\n",
|
||||||
method, c
|
method, c
|
||||||
)
|
)
|
||||||
.as_bytes(),
|
.as_bytes()],
|
||||||
|
&request_fds,
|
||||||
)
|
)
|
||||||
.map_err(Error::Socket)?;
|
.map_err(Error::SocketSendFds)?;
|
||||||
|
|
||||||
if let Some(request_body) = request_body {
|
if let Some(request_body) = request_body {
|
||||||
socket
|
socket
|
||||||
@@ -170,3 +176,12 @@ pub fn simple_api_command<T: Read + Write>(
|
|||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn simple_api_command<T: Read + Write + ScmSocket>(
|
||||||
|
socket: &mut T,
|
||||||
|
method: &str,
|
||||||
|
c: &str,
|
||||||
|
request_body: Option<&str>,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
simple_api_command_with_fds(socket, method, c, request_body, Vec::new())
|
||||||
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
name = "arch"
|
name = "arch"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
authors = ["The Chromium OS Authors"]
|
authors = ["The Chromium OS Authors"]
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = []
|
default = []
|
||||||
@@ -10,17 +11,21 @@ tdx = []
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
acpi_tables = { path = "../acpi_tables", optional = true }
|
acpi_tables = { path = "../acpi_tables", optional = true }
|
||||||
anyhow = "1.0"
|
anyhow = "1.0.44"
|
||||||
arch_gen = { path = "../arch_gen" }
|
|
||||||
byteorder = "1.4.3"
|
byteorder = "1.4.3"
|
||||||
hypervisor = { path = "../hypervisor" }
|
hypervisor = { path = "../hypervisor" }
|
||||||
libc = "0.2.94"
|
libc = "0.2.103"
|
||||||
linux-loader = { version = "0.3.0", features = ["elf", "bzimage", "pe"] }
|
linux-loader = { version = "0.4.0", features = ["elf", "bzimage", "pe"] }
|
||||||
log = "0.4.14"
|
log = "0.4.14"
|
||||||
serde = {version = ">=1.0.27", features = ["rc"] }
|
serde = { version = "1.0.130", features = ["rc"] }
|
||||||
serde_derive = ">=1.0.27"
|
serde_derive = "1.0.130"
|
||||||
serde_json = ">=1.0.9"
|
thiserror = "1.0.30"
|
||||||
thiserror = "1.0"
|
versionize = "0.1.6"
|
||||||
vm-memory = { version = "0.5.0", features = ["backend-mmap"] }
|
versionize_derive = "0.1.4"
|
||||||
|
vm-memory = { version = "0.6.0", features = ["backend-mmap", "backend-bitmap"] }
|
||||||
vm-migration = { path = "../vm-migration" }
|
vm-migration = { path = "../vm-migration" }
|
||||||
|
vmm-sys-util = { version = "0.9.0", features = ["with-serde"] }
|
||||||
|
|
||||||
|
[target.'cfg(target_arch = "aarch64")'.dependencies]
|
||||||
|
fdt_parser = { version = "0.1.3", package = 'fdt'}
|
||||||
|
vm-fdt = { git = "https://github.com/rust-vmm/vm-fdt", branch = "main" }
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -152,7 +152,7 @@ pub fn set_dist_regs(gic: &Arc<dyn hypervisor::Device>, state: &[u32]) -> Result
|
|||||||
|
|
||||||
for dreg in VGIC_DIST_REGS {
|
for dreg in VGIC_DIST_REGS {
|
||||||
let mut base = dreg.base + REG_SIZE as u32 * dreg.bpi as u32;
|
let mut base = dreg.base + REG_SIZE as u32 * dreg.bpi as u32;
|
||||||
let end = compute_reg_len(gic, &dreg, base)?;
|
let end = compute_reg_len(gic, dreg, base)?;
|
||||||
|
|
||||||
while base < end {
|
while base < end {
|
||||||
let val = state[idx];
|
let val = state[idx];
|
||||||
@@ -169,7 +169,7 @@ pub fn get_dist_regs(gic: &Arc<dyn hypervisor::Device>) -> Result<Vec<u32>> {
|
|||||||
|
|
||||||
for dreg in VGIC_DIST_REGS {
|
for dreg in VGIC_DIST_REGS {
|
||||||
let mut base = dreg.base + REG_SIZE as u32 * dreg.bpi as u32;
|
let mut base = dreg.base + REG_SIZE as u32 * dreg.bpi as u32;
|
||||||
let end = compute_reg_len(gic, &dreg, base)?;
|
let end = compute_reg_len(gic, dreg, base)?;
|
||||||
|
|
||||||
while base < end {
|
while base < end {
|
||||||
let val: u32 = 0;
|
let val: u32 = 0;
|
||||||
|
|||||||
@@ -1,21 +1,30 @@
|
|||||||
|
// Copyright 2021 Arm Limited (or its affiliates). All rights reserved.
|
||||||
// Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
// Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
//
|
||||||
|
// This file implements the GicV3 device.
|
||||||
|
|
||||||
pub mod kvm {
|
pub mod kvm {
|
||||||
use crate::aarch64::gic::dist_regs::{get_dist_regs, read_ctlr, set_dist_regs, write_ctlr};
|
use crate::aarch64::gic::dist_regs::{get_dist_regs, read_ctlr, set_dist_regs, write_ctlr};
|
||||||
use crate::aarch64::gic::icc_regs::{get_icc_regs, set_icc_regs};
|
use crate::aarch64::gic::icc_regs::{get_icc_regs, set_icc_regs};
|
||||||
use crate::aarch64::gic::kvm::{save_pending_tables, KvmGicDevice};
|
use crate::aarch64::gic::kvm::{save_pending_tables, KvmGicDevice};
|
||||||
use crate::aarch64::gic::redist_regs::{get_redist_regs, set_redist_regs};
|
use crate::aarch64::gic::redist_regs::{
|
||||||
|
construct_gicr_typers, get_redist_regs, set_redist_regs,
|
||||||
|
};
|
||||||
use crate::aarch64::gic::GicDevice;
|
use crate::aarch64::gic::GicDevice;
|
||||||
use crate::layout;
|
use crate::layout;
|
||||||
use anyhow::anyhow;
|
use anyhow::anyhow;
|
||||||
use hypervisor::kvm::kvm_bindings;
|
use hypervisor::kvm::kvm_bindings;
|
||||||
|
use hypervisor::CpuState;
|
||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::{boxed::Box, result};
|
use std::{boxed::Box, result};
|
||||||
|
use versionize::{VersionMap, Versionize, VersionizeResult};
|
||||||
|
use versionize_derive::Versionize;
|
||||||
use vm_migration::{
|
use vm_migration::{
|
||||||
Migratable, MigratableError, Pausable, Snapshot, Snapshottable, Transportable,
|
Migratable, MigratableError, Pausable, Snapshot, Snapshottable, Transportable,
|
||||||
|
VersionMapped,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Errors thrown while saving/restoring the GICv3.
|
/// Errors thrown while saving/restoring the GICv3.
|
||||||
@@ -44,7 +53,7 @@ pub mod kvm {
|
|||||||
type Result<T> = result::Result<T, Error>;
|
type Result<T> = result::Result<T, Error>;
|
||||||
|
|
||||||
pub struct KvmGicV3 {
|
pub struct KvmGicV3 {
|
||||||
/// The hypervisor agnostic device
|
/// The hypervisor agnostic device for the GicV3
|
||||||
device: Arc<dyn hypervisor::Device>,
|
device: Arc<dyn hypervisor::Device>,
|
||||||
|
|
||||||
/// Vector holding values of GICR_TYPER for each vCPU
|
/// Vector holding values of GICR_TYPER for each vCPU
|
||||||
@@ -57,7 +66,7 @@ pub mod kvm {
|
|||||||
vcpu_count: u64,
|
vcpu_count: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Versionize)]
|
||||||
pub struct Gicv3State {
|
pub struct Gicv3State {
|
||||||
dist: Vec<u32>,
|
dist: Vec<u32>,
|
||||||
rdist: Vec<u32>,
|
rdist: Vec<u32>,
|
||||||
@@ -66,24 +75,20 @@ pub mod kvm {
|
|||||||
gicd_ctlr: u32,
|
gicd_ctlr: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl KvmGicV3 {
|
impl VersionMapped for Gicv3State {}
|
||||||
// Unfortunately bindgen omits defines that are based on other defines.
|
|
||||||
// See arch/arm64/include/uapi/asm/kvm.h file from the linux kernel.
|
|
||||||
pub const SZ_64K: u64 = 0x0001_0000;
|
|
||||||
const KVM_VGIC_V3_DIST_SIZE: u64 = KvmGicV3::SZ_64K;
|
|
||||||
const KVM_VGIC_V3_REDIST_SIZE: u64 = (2 * KvmGicV3::SZ_64K);
|
|
||||||
|
|
||||||
|
impl KvmGicV3 {
|
||||||
// Device trees specific constants
|
// Device trees specific constants
|
||||||
pub const ARCH_GIC_V3_MAINT_IRQ: u32 = 9;
|
pub const ARCH_GIC_V3_MAINT_IRQ: u32 = 9;
|
||||||
|
|
||||||
/// Get the address of the GIC distributor.
|
/// Get the address of the GIC distributor.
|
||||||
pub fn get_dist_addr() -> u64 {
|
pub fn get_dist_addr() -> u64 {
|
||||||
layout::MAPPED_IO_START - KvmGicV3::KVM_VGIC_V3_DIST_SIZE
|
layout::GIC_V3_DIST_START
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the size of the GIC distributor.
|
/// Get the size of the GIC distributor.
|
||||||
pub fn get_dist_size() -> u64 {
|
pub fn get_dist_size() -> u64 {
|
||||||
KvmGicV3::KVM_VGIC_V3_DIST_SIZE
|
layout::GIC_V3_DIST_SIZE
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the address of the GIC redistributors.
|
/// Get the address of the GIC redistributors.
|
||||||
@@ -93,25 +98,22 @@ pub mod kvm {
|
|||||||
|
|
||||||
/// Get the size of the GIC redistributors.
|
/// Get the size of the GIC redistributors.
|
||||||
pub fn get_redists_size(vcpu_count: u64) -> u64 {
|
pub fn get_redists_size(vcpu_count: u64) -> u64 {
|
||||||
vcpu_count * KvmGicV3::KVM_VGIC_V3_REDIST_SIZE
|
vcpu_count * layout::GIC_V3_REDIST_SIZE
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Save the state of GIC.
|
/// Save the state of GIC.
|
||||||
fn state(&self, gicr_typers: &[u64]) -> Result<Gicv3State> {
|
fn state(&self, gicr_typers: &[u64]) -> Result<Gicv3State> {
|
||||||
// Flush redistributors pending tables to guest RAM.
|
|
||||||
save_pending_tables(&self.device()).map_err(Error::SavePendingTables)?;
|
|
||||||
|
|
||||||
let gicd_ctlr =
|
let gicd_ctlr =
|
||||||
read_ctlr(&self.device()).map_err(Error::SaveDistributorCtrlRegisters)?;
|
read_ctlr(self.device()).map_err(Error::SaveDistributorCtrlRegisters)?;
|
||||||
|
|
||||||
let dist_state =
|
let dist_state =
|
||||||
get_dist_regs(&self.device()).map_err(Error::SaveDistributorRegisters)?;
|
get_dist_regs(self.device()).map_err(Error::SaveDistributorRegisters)?;
|
||||||
|
|
||||||
let rdist_state = get_redist_regs(&self.device(), &gicr_typers)
|
let rdist_state = get_redist_regs(self.device(), gicr_typers)
|
||||||
.map_err(Error::SaveRedistributorRegisters)?;
|
.map_err(Error::SaveRedistributorRegisters)?;
|
||||||
|
|
||||||
let icc_state =
|
let icc_state =
|
||||||
get_icc_regs(&self.device(), &gicr_typers).map_err(Error::SaveIccRegisters)?;
|
get_icc_regs(self.device(), gicr_typers).map_err(Error::SaveIccRegisters)?;
|
||||||
|
|
||||||
Ok(Gicv3State {
|
Ok(Gicv3State {
|
||||||
dist: dist_state,
|
dist: dist_state,
|
||||||
@@ -123,16 +125,16 @@ pub mod kvm {
|
|||||||
|
|
||||||
/// Restore the state of GIC.
|
/// Restore the state of GIC.
|
||||||
fn set_state(&mut self, gicr_typers: &[u64], state: &Gicv3State) -> Result<()> {
|
fn set_state(&mut self, gicr_typers: &[u64], state: &Gicv3State) -> Result<()> {
|
||||||
write_ctlr(&self.device(), state.gicd_ctlr)
|
write_ctlr(self.device(), state.gicd_ctlr)
|
||||||
.map_err(Error::RestoreDistributorCtrlRegisters)?;
|
.map_err(Error::RestoreDistributorCtrlRegisters)?;
|
||||||
|
|
||||||
set_dist_regs(&self.device(), &state.dist)
|
set_dist_regs(self.device(), &state.dist)
|
||||||
.map_err(Error::RestoreDistributorRegisters)?;
|
.map_err(Error::RestoreDistributorRegisters)?;
|
||||||
|
|
||||||
set_redist_regs(&self.device(), gicr_typers, &state.rdist)
|
set_redist_regs(self.device(), gicr_typers, &state.rdist)
|
||||||
.map_err(Error::RestoreRedistributorRegisters)?;
|
.map_err(Error::RestoreRedistributorRegisters)?;
|
||||||
|
|
||||||
set_icc_regs(&self.device(), &gicr_typers, &state.icc)
|
set_icc_regs(self.device(), gicr_typers, &state.icc)
|
||||||
.map_err(Error::RestoreIccRegisters)?;
|
.map_err(Error::RestoreIccRegisters)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -160,7 +162,10 @@ pub mod kvm {
|
|||||||
self.vcpu_count
|
self.vcpu_count
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_gicr_typers(&mut self, gicr_typers: Vec<u64>) {
|
fn set_its_device(&mut self, _its_device: Option<Arc<dyn hypervisor::Device>>) {}
|
||||||
|
|
||||||
|
fn set_gicr_typers(&mut self, vcpu_states: &[CpuState]) {
|
||||||
|
let gicr_typers = construct_gicr_typers(vcpu_states);
|
||||||
self.gicr_typers = gicr_typers;
|
self.gicr_typers = gicr_typers;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -193,7 +198,7 @@ pub mod kvm {
|
|||||||
|
|
||||||
fn init_device_attributes(
|
fn init_device_attributes(
|
||||||
_vm: &Arc<dyn hypervisor::Vm>,
|
_vm: &Arc<dyn hypervisor::Vm>,
|
||||||
gic_device: &dyn GicDevice,
|
gic_device: &mut dyn GicDevice,
|
||||||
) -> crate::aarch64::gic::Result<()> {
|
) -> crate::aarch64::gic::Result<()> {
|
||||||
/* Setting up the distributor attribute.
|
/* Setting up the distributor attribute.
|
||||||
We are placing the GIC below 1GB so we need to substract the size of the distributor.
|
We are placing the GIC below 1GB so we need to substract the size of the distributor.
|
||||||
@@ -229,19 +234,28 @@ pub mod kvm {
|
|||||||
|
|
||||||
fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> {
|
fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> {
|
||||||
let gicr_typers = self.gicr_typers.clone();
|
let gicr_typers = self.gicr_typers.clone();
|
||||||
Snapshot::new_from_state(&self.id(), &self.state(&gicr_typers).unwrap())
|
Snapshot::new_from_versioned_state(&self.id(), &self.state(&gicr_typers).unwrap())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn restore(&mut self, snapshot: Snapshot) -> std::result::Result<(), MigratableError> {
|
fn restore(&mut self, snapshot: Snapshot) -> std::result::Result<(), MigratableError> {
|
||||||
let gicr_typers = self.gicr_typers.clone();
|
let gicr_typers = self.gicr_typers.clone();
|
||||||
self.set_state(&gicr_typers, &snapshot.to_state(&self.id())?)
|
self.set_state(&gicr_typers, &snapshot.to_versioned_state(&self.id())?)
|
||||||
.map_err(|e| {
|
.map_err(|e| {
|
||||||
MigratableError::Restore(anyhow!("Could not restore GICv3 state {:?}", e))
|
MigratableError::Restore(anyhow!("Could not restore GICv3 state {:?}", e))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Pausable for KvmGicV3 {}
|
impl Pausable for KvmGicV3 {
|
||||||
|
fn pause(&mut self) -> std::result::Result<(), MigratableError> {
|
||||||
|
// Flush redistributors pending tables to guest RAM.
|
||||||
|
save_pending_tables(self.device()).map_err(|e| {
|
||||||
|
MigratableError::Pause(anyhow!("Could not save GICv3 GIC pending tables {:?}", e))
|
||||||
|
})?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
impl Transportable for KvmGicV3 {}
|
impl Transportable for KvmGicV3 {}
|
||||||
impl Migratable for KvmGicV3 {}
|
impl Migratable for KvmGicV3 {}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,20 +1,157 @@
|
|||||||
// Copyright 2020 ARM Limited
|
// Copyright 2021 Arm Limited (or its affiliates). All rights reserved.
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
//
|
||||||
|
// This file implements the GicV3 device with ITS (Virtual Interrupt Translation Service).
|
||||||
|
|
||||||
pub mod kvm {
|
pub mod kvm {
|
||||||
|
use crate::aarch64::gic::dist_regs::{get_dist_regs, read_ctlr, set_dist_regs, write_ctlr};
|
||||||
|
use crate::aarch64::gic::icc_regs::{get_icc_regs, set_icc_regs};
|
||||||
|
use crate::aarch64::gic::redist_regs::{
|
||||||
|
construct_gicr_typers, get_redist_regs, set_redist_regs,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::aarch64::gic::gicv3::kvm::KvmGicV3;
|
||||||
|
use crate::aarch64::gic::kvm::{save_pending_tables, KvmGicDevice};
|
||||||
|
use crate::aarch64::gic::GicDevice;
|
||||||
|
use crate::layout;
|
||||||
|
use anyhow::anyhow;
|
||||||
|
use hypervisor::kvm::kvm_bindings;
|
||||||
|
use hypervisor::CpuState;
|
||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
|
use std::convert::TryInto;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::{boxed::Box, result};
|
use std::{boxed::Box, result};
|
||||||
|
use versionize::{VersionMap, Versionize, VersionizeResult};
|
||||||
|
use versionize_derive::Versionize;
|
||||||
|
use vm_migration::{
|
||||||
|
Migratable, MigratableError, Pausable, Snapshot, Snapshottable, Transportable,
|
||||||
|
VersionMapped,
|
||||||
|
};
|
||||||
|
|
||||||
|
const GITS_CTLR: u32 = 0x0000;
|
||||||
|
const GITS_IIDR: u32 = 0x0004;
|
||||||
|
const GITS_CBASER: u32 = 0x0080;
|
||||||
|
const GITS_CWRITER: u32 = 0x0088;
|
||||||
|
const GITS_CREADR: u32 = 0x0090;
|
||||||
|
const GITS_BASER: u32 = 0x0100;
|
||||||
|
|
||||||
|
/// Errors thrown while saving/restoring the GICv3ITS.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum Error {
|
||||||
|
/// Error in saving RDIST pending tables into guest RAM.
|
||||||
|
SavePendingTables(crate::aarch64::gic::Error),
|
||||||
|
/// Error in saving GIC distributor registers.
|
||||||
|
SaveDistributorRegisters(crate::aarch64::gic::Error),
|
||||||
|
/// Error in restoring GIC distributor registers.
|
||||||
|
RestoreDistributorRegisters(crate::aarch64::gic::Error),
|
||||||
|
/// Error in saving GIC distributor control registers.
|
||||||
|
SaveDistributorCtrlRegisters(crate::aarch64::gic::Error),
|
||||||
|
/// Error in restoring GIC distributor control registers.
|
||||||
|
RestoreDistributorCtrlRegisters(crate::aarch64::gic::Error),
|
||||||
|
/// Error in saving GIC redistributor registers.
|
||||||
|
SaveRedistributorRegisters(crate::aarch64::gic::Error),
|
||||||
|
/// Error in restoring GIC redistributor registers.
|
||||||
|
RestoreRedistributorRegisters(crate::aarch64::gic::Error),
|
||||||
|
/// Error in saving GIC CPU interface registers.
|
||||||
|
SaveIccRegisters(crate::aarch64::gic::Error),
|
||||||
|
/// Error in restoring GIC CPU interface registers.
|
||||||
|
RestoreIccRegisters(crate::aarch64::gic::Error),
|
||||||
|
/// Error in saving GICv3ITS IIDR register.
|
||||||
|
SaveITSIIDR(crate::aarch64::gic::Error),
|
||||||
|
/// Error in restoring GICv3ITS IIDR register.
|
||||||
|
RestoreITSIIDR(crate::aarch64::gic::Error),
|
||||||
|
/// Error in saving GICv3ITS CBASER register.
|
||||||
|
SaveITSCBASER(crate::aarch64::gic::Error),
|
||||||
|
/// Error in restoring GICv3ITS CBASER register.
|
||||||
|
RestoreITSCBASER(crate::aarch64::gic::Error),
|
||||||
|
/// Error in saving GICv3ITS CREADR register.
|
||||||
|
SaveITSCREADR(crate::aarch64::gic::Error),
|
||||||
|
/// Error in restoring GICv3ITS CREADR register.
|
||||||
|
RestoreITSCREADR(crate::aarch64::gic::Error),
|
||||||
|
/// Error in saving GICv3ITS CWRITER register.
|
||||||
|
SaveITSCWRITER(crate::aarch64::gic::Error),
|
||||||
|
/// Error in restoring GICv3ITS CWRITER register.
|
||||||
|
RestoreITSCWRITER(crate::aarch64::gic::Error),
|
||||||
|
/// Error in saving GICv3ITS BASER register.
|
||||||
|
SaveITSBASER(crate::aarch64::gic::Error),
|
||||||
|
/// Error in restoring GICv3ITS BASER register.
|
||||||
|
RestoreITSBASER(crate::aarch64::gic::Error),
|
||||||
|
/// Error in saving GICv3ITS CTLR register.
|
||||||
|
SaveITSCTLR(crate::aarch64::gic::Error),
|
||||||
|
/// Error in restoring GICv3ITS CTLR register.
|
||||||
|
RestoreITSCTLR(crate::aarch64::gic::Error),
|
||||||
|
/// Error in saving GICv3ITS restore tables.
|
||||||
|
SaveITSTables(crate::aarch64::gic::Error),
|
||||||
|
/// Error in restoring GICv3ITS restore tables.
|
||||||
|
RestoreITSTables(crate::aarch64::gic::Error),
|
||||||
|
}
|
||||||
|
|
||||||
type Result<T> = result::Result<T, Error>;
|
type Result<T> = result::Result<T, Error>;
|
||||||
use crate::aarch64::gic::gicv3::kvm::KvmGicV3;
|
|
||||||
use crate::aarch64::gic::kvm::KvmGicDevice;
|
/// Access an ITS device attribute.
|
||||||
use crate::aarch64::gic::{Error, GicDevice};
|
///
|
||||||
use hypervisor::kvm::kvm_bindings;
|
/// This is a helper function to get/set the ITS device attribute depending
|
||||||
|
/// the bool parameter `set` provided.
|
||||||
|
pub fn gicv3_its_attr_access(
|
||||||
|
its_device: &Arc<dyn hypervisor::Device>,
|
||||||
|
group: u32,
|
||||||
|
attr: u32,
|
||||||
|
val: &u64,
|
||||||
|
set: bool,
|
||||||
|
) -> crate::aarch64::gic::Result<()> {
|
||||||
|
let mut gicv3_its_attr = kvm_bindings::kvm_device_attr {
|
||||||
|
group,
|
||||||
|
attr: attr as u64,
|
||||||
|
addr: val as *const u64 as u64,
|
||||||
|
flags: 0,
|
||||||
|
};
|
||||||
|
if set {
|
||||||
|
its_device
|
||||||
|
.set_device_attr(&gicv3_its_attr)
|
||||||
|
.map_err(crate::aarch64::gic::Error::SetDeviceAttribute)?;
|
||||||
|
} else {
|
||||||
|
its_device
|
||||||
|
.get_device_attr(&mut gicv3_its_attr)
|
||||||
|
.map_err(crate::aarch64::gic::Error::GetDeviceAttribute)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Function that saves/restores ITS tables into guest RAM.
|
||||||
|
///
|
||||||
|
/// The tables get flushed to guest RAM whenever the VM gets stopped.
|
||||||
|
pub fn gicv3_its_tables_access(
|
||||||
|
its_device: &Arc<dyn hypervisor::Device>,
|
||||||
|
save: bool,
|
||||||
|
) -> crate::aarch64::gic::Result<()> {
|
||||||
|
let attr: u64;
|
||||||
|
if save {
|
||||||
|
attr = u64::from(kvm_bindings::KVM_DEV_ARM_ITS_SAVE_TABLES);
|
||||||
|
} else {
|
||||||
|
attr = u64::from(kvm_bindings::KVM_DEV_ARM_ITS_RESTORE_TABLES);
|
||||||
|
}
|
||||||
|
|
||||||
|
let init_gic_attr = kvm_bindings::kvm_device_attr {
|
||||||
|
group: kvm_bindings::KVM_DEV_ARM_VGIC_GRP_CTRL,
|
||||||
|
attr,
|
||||||
|
addr: 0,
|
||||||
|
flags: 0,
|
||||||
|
};
|
||||||
|
its_device
|
||||||
|
.set_device_attr(&init_gic_attr)
|
||||||
|
.map_err(crate::aarch64::gic::Error::SetDeviceAttribute)
|
||||||
|
}
|
||||||
|
|
||||||
pub struct KvmGicV3Its {
|
pub struct KvmGicV3Its {
|
||||||
/// The hypervisor agnostic device
|
/// The hypervisor agnostic device for the GicV3
|
||||||
device: Arc<dyn hypervisor::Device>,
|
device: Arc<dyn hypervisor::Device>,
|
||||||
|
|
||||||
|
/// The hypervisor agnostic device for the Its device
|
||||||
|
its_device: Option<Arc<dyn hypervisor::Device>>,
|
||||||
|
|
||||||
|
/// Vector holding values of GICR_TYPER for each vCPU
|
||||||
|
gicr_typers: Vec<u64>,
|
||||||
|
|
||||||
/// GIC device properties, to be used for setting up the fdt entry
|
/// GIC device properties, to be used for setting up the fdt entry
|
||||||
gic_properties: [u64; 4],
|
gic_properties: [u64; 4],
|
||||||
|
|
||||||
@@ -25,16 +162,199 @@ pub mod kvm {
|
|||||||
vcpu_count: u64,
|
vcpu_count: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl KvmGicV3Its {
|
#[derive(Versionize)]
|
||||||
const KVM_VGIC_V3_ITS_SIZE: u64 = (2 * KvmGicV3::SZ_64K);
|
pub struct Gicv3ItsState {
|
||||||
|
dist: Vec<u32>,
|
||||||
|
rdist: Vec<u32>,
|
||||||
|
icc: Vec<u32>,
|
||||||
|
// special register that enables interrupts and affinity routing
|
||||||
|
gicd_ctlr: u32,
|
||||||
|
its_ctlr: u64,
|
||||||
|
its_iidr: u64,
|
||||||
|
its_cbaser: u64,
|
||||||
|
its_cwriter: u64,
|
||||||
|
its_creadr: u64,
|
||||||
|
its_baser: [u64; 8],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VersionMapped for Gicv3ItsState {}
|
||||||
|
|
||||||
|
impl KvmGicV3Its {
|
||||||
fn get_msi_size() -> u64 {
|
fn get_msi_size() -> u64 {
|
||||||
KvmGicV3Its::KVM_VGIC_V3_ITS_SIZE
|
layout::GIC_V3_ITS_SIZE
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_msi_addr(vcpu_count: u64) -> u64 {
|
fn get_msi_addr(vcpu_count: u64) -> u64 {
|
||||||
KvmGicV3::get_redists_addr(vcpu_count) - KvmGicV3Its::get_msi_size()
|
KvmGicV3::get_redists_addr(vcpu_count) - KvmGicV3Its::get_msi_size()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Save the state of GICv3ITS.
|
||||||
|
fn state(&self, gicr_typers: &[u64]) -> Result<Gicv3ItsState> {
|
||||||
|
let gicd_ctlr =
|
||||||
|
read_ctlr(self.device()).map_err(Error::SaveDistributorCtrlRegisters)?;
|
||||||
|
|
||||||
|
let dist_state =
|
||||||
|
get_dist_regs(self.device()).map_err(Error::SaveDistributorRegisters)?;
|
||||||
|
|
||||||
|
let rdist_state = get_redist_regs(self.device(), gicr_typers)
|
||||||
|
.map_err(Error::SaveRedistributorRegisters)?;
|
||||||
|
|
||||||
|
let icc_state =
|
||||||
|
get_icc_regs(self.device(), gicr_typers).map_err(Error::SaveIccRegisters)?;
|
||||||
|
|
||||||
|
let its_baser_state: [u64; 8] = [0; 8];
|
||||||
|
for i in 0..8 {
|
||||||
|
gicv3_its_attr_access(
|
||||||
|
self.its_device().unwrap(),
|
||||||
|
kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
|
||||||
|
GITS_BASER + i * 8,
|
||||||
|
&its_baser_state[i as usize],
|
||||||
|
false,
|
||||||
|
)
|
||||||
|
.map_err(Error::SaveITSBASER)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
let its_ctlr_state: u64 = 0;
|
||||||
|
gicv3_its_attr_access(
|
||||||
|
self.its_device().unwrap(),
|
||||||
|
kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
|
||||||
|
GITS_CTLR,
|
||||||
|
&its_ctlr_state,
|
||||||
|
false,
|
||||||
|
)
|
||||||
|
.map_err(Error::SaveITSCTLR)?;
|
||||||
|
|
||||||
|
let its_cbaser_state: u64 = 0;
|
||||||
|
gicv3_its_attr_access(
|
||||||
|
self.its_device().unwrap(),
|
||||||
|
kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
|
||||||
|
GITS_CBASER,
|
||||||
|
&its_cbaser_state,
|
||||||
|
false,
|
||||||
|
)
|
||||||
|
.map_err(Error::SaveITSCBASER)?;
|
||||||
|
|
||||||
|
let its_creadr_state: u64 = 0;
|
||||||
|
gicv3_its_attr_access(
|
||||||
|
self.its_device().unwrap(),
|
||||||
|
kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
|
||||||
|
GITS_CREADR,
|
||||||
|
&its_creadr_state,
|
||||||
|
false,
|
||||||
|
)
|
||||||
|
.map_err(Error::SaveITSCREADR)?;
|
||||||
|
|
||||||
|
let its_cwriter_state: u64 = 0;
|
||||||
|
gicv3_its_attr_access(
|
||||||
|
self.its_device().unwrap(),
|
||||||
|
kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
|
||||||
|
GITS_CWRITER,
|
||||||
|
&its_cwriter_state,
|
||||||
|
false,
|
||||||
|
)
|
||||||
|
.map_err(Error::SaveITSCWRITER)?;
|
||||||
|
|
||||||
|
let its_iidr_state: u64 = 0;
|
||||||
|
gicv3_its_attr_access(
|
||||||
|
self.its_device().unwrap(),
|
||||||
|
kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
|
||||||
|
GITS_IIDR,
|
||||||
|
&its_iidr_state,
|
||||||
|
false,
|
||||||
|
)
|
||||||
|
.map_err(Error::SaveITSIIDR)?;
|
||||||
|
|
||||||
|
Ok(Gicv3ItsState {
|
||||||
|
dist: dist_state,
|
||||||
|
rdist: rdist_state,
|
||||||
|
icc: icc_state,
|
||||||
|
gicd_ctlr,
|
||||||
|
its_ctlr: its_ctlr_state,
|
||||||
|
its_iidr: its_iidr_state,
|
||||||
|
its_cbaser: its_cbaser_state,
|
||||||
|
its_cwriter: its_cwriter_state,
|
||||||
|
its_creadr: its_creadr_state,
|
||||||
|
its_baser: its_baser_state,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Restore the state of GICv3ITS.
|
||||||
|
fn set_state(&mut self, gicr_typers: &[u64], state: &Gicv3ItsState) -> Result<()> {
|
||||||
|
write_ctlr(self.device(), state.gicd_ctlr)
|
||||||
|
.map_err(Error::RestoreDistributorCtrlRegisters)?;
|
||||||
|
|
||||||
|
set_dist_regs(self.device(), &state.dist)
|
||||||
|
.map_err(Error::RestoreDistributorRegisters)?;
|
||||||
|
|
||||||
|
set_redist_regs(self.device(), gicr_typers, &state.rdist)
|
||||||
|
.map_err(Error::RestoreRedistributorRegisters)?;
|
||||||
|
|
||||||
|
set_icc_regs(self.device(), gicr_typers, &state.icc)
|
||||||
|
.map_err(Error::RestoreIccRegisters)?;
|
||||||
|
|
||||||
|
//Restore GICv3ITS registers
|
||||||
|
gicv3_its_attr_access(
|
||||||
|
self.its_device().unwrap(),
|
||||||
|
kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
|
||||||
|
GITS_IIDR,
|
||||||
|
&state.its_iidr,
|
||||||
|
true,
|
||||||
|
)
|
||||||
|
.map_err(Error::RestoreITSIIDR)?;
|
||||||
|
|
||||||
|
gicv3_its_attr_access(
|
||||||
|
self.its_device().unwrap(),
|
||||||
|
kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
|
||||||
|
GITS_CBASER,
|
||||||
|
&state.its_cbaser,
|
||||||
|
true,
|
||||||
|
)
|
||||||
|
.map_err(Error::RestoreITSCBASER)?;
|
||||||
|
|
||||||
|
gicv3_its_attr_access(
|
||||||
|
self.its_device().unwrap(),
|
||||||
|
kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
|
||||||
|
GITS_CREADR,
|
||||||
|
&state.its_creadr,
|
||||||
|
true,
|
||||||
|
)
|
||||||
|
.map_err(Error::RestoreITSCREADR)?;
|
||||||
|
|
||||||
|
gicv3_its_attr_access(
|
||||||
|
self.its_device().unwrap(),
|
||||||
|
kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
|
||||||
|
GITS_CWRITER,
|
||||||
|
&state.its_cwriter,
|
||||||
|
true,
|
||||||
|
)
|
||||||
|
.map_err(Error::RestoreITSCWRITER)?;
|
||||||
|
|
||||||
|
for i in 0..8 {
|
||||||
|
gicv3_its_attr_access(
|
||||||
|
self.its_device().unwrap(),
|
||||||
|
kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
|
||||||
|
GITS_BASER + i * 8,
|
||||||
|
&state.its_baser[i as usize],
|
||||||
|
true,
|
||||||
|
)
|
||||||
|
.map_err(Error::RestoreITSBASER)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Restore ITS tables
|
||||||
|
gicv3_its_tables_access(self.its_device().unwrap(), false)
|
||||||
|
.map_err(Error::RestoreITSTables)?;
|
||||||
|
|
||||||
|
gicv3_its_attr_access(
|
||||||
|
self.its_device().unwrap(),
|
||||||
|
kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
|
||||||
|
GITS_CTLR,
|
||||||
|
&state.its_ctlr,
|
||||||
|
true,
|
||||||
|
)
|
||||||
|
.map_err(Error::RestoreITSCTLR)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GicDevice for KvmGicV3Its {
|
impl GicDevice for KvmGicV3Its {
|
||||||
@@ -42,6 +362,10 @@ pub mod kvm {
|
|||||||
&self.device
|
&self.device
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn its_device(&self) -> Option<&Arc<dyn hypervisor::Device>> {
|
||||||
|
self.its_device.as_ref()
|
||||||
|
}
|
||||||
|
|
||||||
fn fdt_compatibility(&self) -> &str {
|
fn fdt_compatibility(&self) -> &str {
|
||||||
"arm,gic-v3"
|
"arm,gic-v3"
|
||||||
}
|
}
|
||||||
@@ -70,7 +394,14 @@ pub mod kvm {
|
|||||||
self.vcpu_count
|
self.vcpu_count
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_gicr_typers(&mut self, _gicr_typers: Vec<u64>) {}
|
fn set_its_device(&mut self, its_device: Option<Arc<dyn hypervisor::Device>>) {
|
||||||
|
self.its_device = its_device;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_gicr_typers(&mut self, vcpu_states: &[CpuState]) {
|
||||||
|
let gicr_typers = construct_gicr_typers(vcpu_states);
|
||||||
|
self.gicr_typers = gicr_typers;
|
||||||
|
}
|
||||||
|
|
||||||
fn as_any_concrete_mut(&mut self) -> &mut dyn Any {
|
fn as_any_concrete_mut(&mut self) -> &mut dyn Any {
|
||||||
self
|
self
|
||||||
@@ -88,6 +419,8 @@ pub mod kvm {
|
|||||||
) -> Box<dyn GicDevice> {
|
) -> Box<dyn GicDevice> {
|
||||||
Box::new(KvmGicV3Its {
|
Box::new(KvmGicV3Its {
|
||||||
device,
|
device,
|
||||||
|
its_device: None,
|
||||||
|
gicr_typers: vec![0; vcpu_count.try_into().unwrap()],
|
||||||
gic_properties: [
|
gic_properties: [
|
||||||
KvmGicV3::get_dist_addr(),
|
KvmGicV3::get_dist_addr(),
|
||||||
KvmGicV3::get_dist_size(),
|
KvmGicV3::get_dist_size(),
|
||||||
@@ -104,8 +437,8 @@ pub mod kvm {
|
|||||||
|
|
||||||
fn init_device_attributes(
|
fn init_device_attributes(
|
||||||
vm: &Arc<dyn hypervisor::Vm>,
|
vm: &Arc<dyn hypervisor::Vm>,
|
||||||
gic_device: &dyn GicDevice,
|
gic_device: &mut dyn GicDevice,
|
||||||
) -> Result<()> {
|
) -> crate::aarch64::gic::Result<()> {
|
||||||
KvmGicV3::init_device_attributes(vm, gic_device)?;
|
KvmGicV3::init_device_attributes(vm, gic_device)?;
|
||||||
|
|
||||||
let mut its_device = kvm_bindings::kvm_create_device {
|
let mut its_device = kvm_bindings::kvm_create_device {
|
||||||
@@ -116,7 +449,7 @@ pub mod kvm {
|
|||||||
|
|
||||||
let its_fd = vm
|
let its_fd = vm
|
||||||
.create_device(&mut its_device)
|
.create_device(&mut its_device)
|
||||||
.map_err(Error::CreateGic)?;
|
.map_err(crate::aarch64::gic::Error::CreateGic)?;
|
||||||
|
|
||||||
Self::set_device_attribute(
|
Self::set_device_attribute(
|
||||||
&its_fd,
|
&its_fd,
|
||||||
@@ -134,7 +467,49 @@ pub mod kvm {
|
|||||||
0,
|
0,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
|
gic_device.set_its_device(Some(its_fd));
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub const GIC_V3_ITS_SNAPSHOT_ID: &str = "gic-v3-its";
|
||||||
|
impl Snapshottable for KvmGicV3Its {
|
||||||
|
fn id(&self) -> String {
|
||||||
|
GIC_V3_ITS_SNAPSHOT_ID.to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> {
|
||||||
|
let gicr_typers = self.gicr_typers.clone();
|
||||||
|
Snapshot::new_from_versioned_state(&self.id(), &self.state(&gicr_typers).unwrap())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn restore(&mut self, snapshot: Snapshot) -> std::result::Result<(), MigratableError> {
|
||||||
|
let gicr_typers = self.gicr_typers.clone();
|
||||||
|
self.set_state(&gicr_typers, &snapshot.to_versioned_state(&self.id())?)
|
||||||
|
.map_err(|e| {
|
||||||
|
MigratableError::Restore(anyhow!("Could not restore GICv3ITS state {:?}", e))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Pausable for KvmGicV3Its {
|
||||||
|
fn pause(&mut self) -> std::result::Result<(), MigratableError> {
|
||||||
|
// Flush redistributors pending tables to guest RAM.
|
||||||
|
save_pending_tables(self.device()).map_err(|e| {
|
||||||
|
MigratableError::Pause(anyhow!(
|
||||||
|
"Could not save GICv3ITS GIC pending tables {:?}",
|
||||||
|
e
|
||||||
|
))
|
||||||
|
})?;
|
||||||
|
// Flush ITS tables to guest RAM.
|
||||||
|
gicv3_its_tables_access(self.its_device().unwrap(), true).map_err(|e| {
|
||||||
|
MigratableError::Pause(anyhow!("Could not save GICv3ITS ITS tables {:?}", e))
|
||||||
|
})?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Transportable for KvmGicV3Its {}
|
||||||
|
impl Migratable for KvmGicV3Its {}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
// Copyright 2021 Arm Limited (or its affiliates). All rights reserved.
|
||||||
// Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
// Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
@@ -10,6 +11,7 @@ pub mod redist_regs;
|
|||||||
pub use self::dist_regs::{get_dist_regs, read_ctlr, set_dist_regs, write_ctlr};
|
pub use self::dist_regs::{get_dist_regs, read_ctlr, set_dist_regs, write_ctlr};
|
||||||
pub use self::icc_regs::{get_icc_regs, set_icc_regs};
|
pub use self::icc_regs::{get_icc_regs, set_icc_regs};
|
||||||
pub use self::redist_regs::{get_redist_regs, set_redist_regs};
|
pub use self::redist_regs::{get_redist_regs, set_redist_regs};
|
||||||
|
use hypervisor::CpuState;
|
||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
use std::result;
|
use std::result;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
@@ -30,6 +32,11 @@ pub trait GicDevice: Send {
|
|||||||
/// Returns the hypervisor agnostic Device of the GIC device
|
/// Returns the hypervisor agnostic Device of the GIC device
|
||||||
fn device(&self) -> &Arc<dyn hypervisor::Device>;
|
fn device(&self) -> &Arc<dyn hypervisor::Device>;
|
||||||
|
|
||||||
|
/// Returns the hypervisor agnostic Device of the ITS device
|
||||||
|
fn its_device(&self) -> Option<&Arc<dyn hypervisor::Device>> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns the fdt compatibility property of the device
|
/// Returns the fdt compatibility property of the device
|
||||||
fn fdt_compatibility(&self) -> &str;
|
fn fdt_compatibility(&self) -> &str;
|
||||||
|
|
||||||
@@ -57,8 +64,10 @@ pub trait GicDevice: Send {
|
|||||||
&[]
|
&[]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn set_its_device(&mut self, its_device: Option<Arc<dyn hypervisor::Device>>);
|
||||||
|
|
||||||
/// Get the values of GICR_TYPER for each vCPU.
|
/// Get the values of GICR_TYPER for each vCPU.
|
||||||
fn set_gicr_typers(&mut self, gicr_typers: Vec<u64>);
|
fn set_gicr_typers(&mut self, vcpu_states: &[CpuState]);
|
||||||
|
|
||||||
/// Downcast the trait object to its concrete type.
|
/// Downcast the trait object to its concrete type.
|
||||||
fn as_any_concrete_mut(&mut self) -> &mut dyn Any;
|
fn as_any_concrete_mut(&mut self) -> &mut dyn Any;
|
||||||
@@ -87,7 +96,7 @@ pub mod kvm {
|
|||||||
/// Setup the device-specific attributes
|
/// Setup the device-specific attributes
|
||||||
fn init_device_attributes(
|
fn init_device_attributes(
|
||||||
vm: &Arc<dyn hypervisor::Vm>,
|
vm: &Arc<dyn hypervisor::Vm>,
|
||||||
gic_device: &dyn GicDevice,
|
gic_device: &mut dyn GicDevice,
|
||||||
) -> Result<()>;
|
) -> Result<()>;
|
||||||
|
|
||||||
/// Initialize a GIC device
|
/// Initialize a GIC device
|
||||||
@@ -149,7 +158,7 @@ pub mod kvm {
|
|||||||
/* We need to tell the kernel how many irqs to support with this vgic.
|
/* We need to tell the kernel how many irqs to support with this vgic.
|
||||||
* See the `layout` module for details.
|
* See the `layout` module for details.
|
||||||
*/
|
*/
|
||||||
let nr_irqs: u32 = layout::IRQ_MAX - layout::IRQ_BASE + 1;
|
let nr_irqs: u32 = layout::IRQ_NUM;
|
||||||
let nr_irqs_ptr = &nr_irqs as *const u32;
|
let nr_irqs_ptr = &nr_irqs as *const u32;
|
||||||
Self::set_device_attribute(
|
Self::set_device_attribute(
|
||||||
gic_device.device(),
|
gic_device.device(),
|
||||||
@@ -178,9 +187,9 @@ pub mod kvm {
|
|||||||
fn new(vm: &Arc<dyn hypervisor::Vm>, vcpu_count: u64) -> Result<Box<dyn GicDevice>> {
|
fn new(vm: &Arc<dyn hypervisor::Vm>, vcpu_count: u64) -> Result<Box<dyn GicDevice>> {
|
||||||
let vgic_fd = Self::init_device(vm)?;
|
let vgic_fd = Self::init_device(vm)?;
|
||||||
|
|
||||||
let device = Self::create_device(vgic_fd, vcpu_count);
|
let mut device = Self::create_device(vgic_fd, vcpu_count);
|
||||||
|
|
||||||
Self::init_device_attributes(vm, &*device)?;
|
Self::init_device_attributes(vm, &mut *device)?;
|
||||||
|
|
||||||
Self::finalize_device(&*device)?;
|
Self::finalize_device(&*device)?;
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
use super::{Error, Result};
|
use super::{Error, Result};
|
||||||
use hypervisor::kvm::kvm_bindings::{kvm_device_attr, KVM_DEV_ARM_VGIC_GRP_REDIST_REGS};
|
use hypervisor::kvm::kvm_bindings::{kvm_device_attr, KVM_DEV_ARM_VGIC_GRP_REDIST_REGS};
|
||||||
|
use hypervisor::CpuState;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
// Relevant redistributor registers that we want to save/restore.
|
// Relevant redistributor registers that we want to save/restore.
|
||||||
@@ -61,11 +62,11 @@ macro_rules! VGIC_RDIST_REG {
|
|||||||
|
|
||||||
// List with relevant distributor registers that we will be restoring.
|
// List with relevant distributor registers that we will be restoring.
|
||||||
static VGIC_RDIST_REGS: &'static [RdistReg] = &[
|
static VGIC_RDIST_REGS: &'static [RdistReg] = &[
|
||||||
VGIC_RDIST_REG!(GICR_CTLR, 4),
|
|
||||||
VGIC_RDIST_REG!(GICR_STATUSR, 4),
|
VGIC_RDIST_REG!(GICR_STATUSR, 4),
|
||||||
VGIC_RDIST_REG!(GICR_WAKER, 4),
|
VGIC_RDIST_REG!(GICR_WAKER, 4),
|
||||||
VGIC_RDIST_REG!(GICR_PROPBASER, 8),
|
VGIC_RDIST_REG!(GICR_PROPBASER, 8),
|
||||||
VGIC_RDIST_REG!(GICR_PENDBASER, 8),
|
VGIC_RDIST_REG!(GICR_PENDBASER, 8),
|
||||||
|
VGIC_RDIST_REG!(GICR_CTLR, 4),
|
||||||
];
|
];
|
||||||
|
|
||||||
// List with relevant distributor registers that we will be restoring.
|
// List with relevant distributor registers that we will be restoring.
|
||||||
@@ -141,14 +142,14 @@ pub fn get_redist_regs(gic: &Arc<dyn hypervisor::Device>, gicr_typer: &[u64]) ->
|
|||||||
let mut idx: usize = 0;
|
let mut idx: usize = 0;
|
||||||
access_redists_aux(
|
access_redists_aux(
|
||||||
gic,
|
gic,
|
||||||
&gicr_typer,
|
gicr_typer,
|
||||||
&mut state,
|
&mut state,
|
||||||
VGIC_RDIST_REGS,
|
VGIC_RDIST_REGS,
|
||||||
&mut idx,
|
&mut idx,
|
||||||
false,
|
false,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
access_redists_aux(gic, &gicr_typer, &mut state, VGIC_SGI_REGS, &mut idx, false)?;
|
access_redists_aux(gic, gicr_typer, &mut state, VGIC_SGI_REGS, &mut idx, false)?;
|
||||||
Ok(state)
|
Ok(state)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -177,3 +178,34 @@ pub fn set_redist_regs(
|
|||||||
true,
|
true,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn construct_gicr_typers(vcpu_states: &[CpuState]) -> Vec<u64> {
|
||||||
|
/* Pre-construct the GICR_TYPER:
|
||||||
|
* For our implementation:
|
||||||
|
* Top 32 bits are the affinity value of the associated CPU
|
||||||
|
* CommonLPIAff == 01 (redistributors with same Aff3 share LPI table)
|
||||||
|
* Processor_Number == CPU index starting from 0
|
||||||
|
* DPGS == 0 (GICR_CTLR.DPG* not supported)
|
||||||
|
* Last == 1 if this is the last redistributor in a series of
|
||||||
|
* contiguous redistributor pages
|
||||||
|
* DirectLPI == 0 (direct injection of LPIs not supported)
|
||||||
|
* VLPIS == 0 (virtual LPIs not supported)
|
||||||
|
* PLPIS == 0 (physical LPIs not supported)
|
||||||
|
*/
|
||||||
|
let mut gicr_typers: Vec<u64> = Vec::new();
|
||||||
|
for (index, state) in vcpu_states.iter().enumerate() {
|
||||||
|
let last = {
|
||||||
|
if index == vcpu_states.len() - 1 {
|
||||||
|
1
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
};
|
||||||
|
//calculate affinity
|
||||||
|
let mut cpu_affid = state.mpidr & 1095233437695;
|
||||||
|
cpu_affid = ((cpu_affid & 0xFF00000000) >> 8) | (cpu_affid & 0xFFFFFF);
|
||||||
|
gicr_typers.push((cpu_affid << 32) | (1 << 24) | (index as u64) << 8 | (last << 4));
|
||||||
|
}
|
||||||
|
|
||||||
|
gicr_typers
|
||||||
|
}
|
||||||
|
|||||||
@@ -36,7 +36,7 @@
|
|||||||
// | |
|
// | |
|
||||||
// 144 M +---------------------------------------------------------------|
|
// 144 M +---------------------------------------------------------------|
|
||||||
// | Reserved (now GIC is here) |
|
// | Reserved (now GIC is here) |
|
||||||
// 128 M +---------------------------------------------------------------+
|
// 64 M +---------------------------------------------------------------+
|
||||||
// | |
|
// | |
|
||||||
// | UEFI space |
|
// | UEFI space |
|
||||||
// | |
|
// | |
|
||||||
@@ -46,26 +46,35 @@
|
|||||||
|
|
||||||
use vm_memory::GuestAddress;
|
use vm_memory::GuestAddress;
|
||||||
|
|
||||||
/// 0x0 ~ 0x800_0000 is reserved to uefi
|
/// 0x0 ~ 0x40_0000 (4 MiB) is reserved to UEFI
|
||||||
|
/// UEFI binary size is required less than 3 MiB, reserving 4 MiB is enough.
|
||||||
pub const UEFI_START: u64 = 0x0;
|
pub const UEFI_START: u64 = 0x0;
|
||||||
pub const MEM_UEFI_START: GuestAddress = GuestAddress(0);
|
pub const MEM_UEFI_START: GuestAddress = GuestAddress(0);
|
||||||
pub const UEFI_SIZE: u64 = 0x0800_0000;
|
pub const UEFI_SIZE: u64 = 0x040_0000;
|
||||||
|
|
||||||
/// Below this address will reside the GIC, above this address will reside the MMIO devices.
|
/// Below this address will reside the GIC, above this address will reside the MMIO devices.
|
||||||
pub const MAPPED_IO_START: u64 = 0x0900_0000;
|
pub const MAPPED_IO_START: u64 = 0x0900_0000;
|
||||||
|
|
||||||
/// Space 0x0900_0000 ~ 0x1000_0000 is reserved for legacy devices.
|
/// See kernel file arch/arm64/include/uapi/asm/kvm.h for the GIC related definitions.
|
||||||
|
/// 0x08ff_0000 ~ 0x0900_0000 is reserved for GICv3 Distributor
|
||||||
|
pub const GIC_V3_DIST_SIZE: u64 = 0x01_0000;
|
||||||
|
pub const GIC_V3_DIST_START: u64 = MAPPED_IO_START - GIC_V3_DIST_SIZE;
|
||||||
|
/// Below 0x08ff_0000 is reserved for GICv3 Redistributor.
|
||||||
|
/// The size defined here is for each vcpu.
|
||||||
|
/// The total size is 'number_of_vcpu * GIC_V3_REDIST_SIZE'
|
||||||
|
pub const GIC_V3_REDIST_SIZE: u64 = 0x02_0000;
|
||||||
|
/// Below Redistributor area is GICv3 ITS
|
||||||
|
pub const GIC_V3_ITS_SIZE: u64 = 0x02_0000;
|
||||||
|
|
||||||
|
/// Space 0x0900_0000 ~ 0x0905_0000 is reserved for legacy devices.
|
||||||
pub const LEGACY_SERIAL_MAPPED_IO_START: u64 = 0x0900_0000;
|
pub const LEGACY_SERIAL_MAPPED_IO_START: u64 = 0x0900_0000;
|
||||||
pub const LEGACY_RTC_MAPPED_IO_START: u64 = 0x0901_0000;
|
pub const LEGACY_RTC_MAPPED_IO_START: u64 = 0x0901_0000;
|
||||||
pub const LEGACY_GPIO_MAPPED_IO_START: u64 = 0x0902_0000;
|
pub const LEGACY_GPIO_MAPPED_IO_START: u64 = 0x0902_0000;
|
||||||
|
|
||||||
/// Space 0x0902_0000 ~ 0x903_0000 is reserved for pcie io address
|
/// Space 0x0905_0000 ~ 0x0906_0000 is reserved for pcie io address
|
||||||
pub const MEM_PCI_IO_START: GuestAddress = GuestAddress(0x0902_0000);
|
pub const MEM_PCI_IO_START: GuestAddress = GuestAddress(0x0905_0000);
|
||||||
pub const MEM_PCI_IO_SIZE: u64 = 0x10000;
|
pub const MEM_PCI_IO_SIZE: u64 = 0x10000;
|
||||||
|
|
||||||
/// Legacy space will be allocated at once whiling setting up legacy devices.
|
|
||||||
pub const LEGACY_DEVICES_MAPPED_IO_SIZE: u64 = 0x0700_0000;
|
|
||||||
|
|
||||||
/// Starting from 0x1000_0000 (256MiB) to 0x3000_0000 (768MiB) is used for PCIE MMIO
|
/// Starting from 0x1000_0000 (256MiB) to 0x3000_0000 (768MiB) is used for PCIE MMIO
|
||||||
pub const MEM_32BIT_DEVICES_START: GuestAddress = GuestAddress(0x1000_0000);
|
pub const MEM_32BIT_DEVICES_START: GuestAddress = GuestAddress(0x1000_0000);
|
||||||
pub const MEM_32BIT_DEVICES_SIZE: u64 = 0x2000_0000;
|
pub const MEM_32BIT_DEVICES_SIZE: u64 = 0x2000_0000;
|
||||||
@@ -81,21 +90,30 @@ pub const RAM_64BIT_START: u64 = 0x4000_0000;
|
|||||||
/// As per `arch/arm64/include/uapi/asm/setup.h`.
|
/// As per `arch/arm64/include/uapi/asm/setup.h`.
|
||||||
pub const CMDLINE_MAX_SIZE: usize = 2048;
|
pub const CMDLINE_MAX_SIZE: usize = 2048;
|
||||||
|
|
||||||
|
/// FDT is at the beginning of RAM.
|
||||||
/// Maximum size of the device tree blob as specified in https://www.kernel.org/doc/Documentation/arm64/booting.txt.
|
/// Maximum size of the device tree blob as specified in https://www.kernel.org/doc/Documentation/arm64/booting.txt.
|
||||||
|
pub const FDT_START: u64 = RAM_64BIT_START;
|
||||||
pub const FDT_MAX_SIZE: usize = 0x20_0000;
|
pub const FDT_MAX_SIZE: usize = 0x20_0000;
|
||||||
|
|
||||||
/// Put ACPI table above dtb
|
/// Put ACPI table above dtb
|
||||||
pub const ACPI_START: u64 = RAM_64BIT_START + FDT_MAX_SIZE as u64;
|
pub const ACPI_START: u64 = RAM_64BIT_START + FDT_MAX_SIZE as u64;
|
||||||
|
pub const ACPI_MAX_SIZE: usize = 0x20_0000;
|
||||||
pub const RSDP_POINTER: GuestAddress = GuestAddress(ACPI_START);
|
pub const RSDP_POINTER: GuestAddress = GuestAddress(ACPI_START);
|
||||||
|
|
||||||
|
/// Kernel start after FDT and ACPI
|
||||||
|
pub const KERNEL_START: u64 = ACPI_START + ACPI_MAX_SIZE as u64;
|
||||||
|
|
||||||
|
/// Pci high memory base
|
||||||
|
pub const PCI_HIGH_BASE: u64 = 0x80_0000_0000_u64;
|
||||||
|
|
||||||
// As per virt/kvm/arm/vgic/vgic-kvm-device.c we need
|
// As per virt/kvm/arm/vgic/vgic-kvm-device.c we need
|
||||||
// the number of interrupts our GIC will support to be:
|
// the number of interrupts our GIC will support to be:
|
||||||
// * bigger than 32
|
// * bigger than 32
|
||||||
// * less than 1023 and
|
// * less than 1023 and
|
||||||
// * a multiple of 32.
|
// * a multiple of 32.
|
||||||
// We are setting up our interrupt controller to support a maximum of 256 interrupts.
|
// We are setting up our interrupt controller to support a maximum of 256 interrupts.
|
||||||
/// First usable interrupt on aarch64.
|
/// First usable interrupt on aarch64
|
||||||
pub const IRQ_BASE: u32 = 0;
|
pub const IRQ_BASE: u32 = 32;
|
||||||
|
|
||||||
/// Last usable interrupt on aarch64.
|
/// Number of supported interrupts
|
||||||
pub const IRQ_MAX: u32 = 255;
|
pub const IRQ_NUM: u32 = 256;
|
||||||
|
|||||||
@@ -10,25 +10,29 @@ pub mod gic;
|
|||||||
pub mod layout;
|
pub mod layout;
|
||||||
/// Logic for configuring aarch64 registers.
|
/// Logic for configuring aarch64 registers.
|
||||||
pub mod regs;
|
pub mod regs;
|
||||||
|
/// Module for loading UEFI binary.
|
||||||
|
pub mod uefi;
|
||||||
|
|
||||||
pub use self::fdt::DeviceInfoForFdt;
|
pub use self::fdt::DeviceInfoForFdt;
|
||||||
use crate::DeviceType;
|
use crate::{DeviceType, GuestMemoryMmap, NumaNodes, RegionType};
|
||||||
use crate::RegionType;
|
use gic::GicDevice;
|
||||||
use aarch64::gic::GicDevice;
|
use log::{log_enabled, Level};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::ffi::CStr;
|
use std::convert::TryInto;
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use vm_memory::{
|
use vm_memory::{
|
||||||
Address, GuestAddress, GuestAddressSpace, GuestMemory, GuestMemoryAtomic, GuestMemoryMmap,
|
Address, GuestAddress, GuestAddressSpace, GuestMemory, GuestMemoryAtomic, GuestUsize,
|
||||||
GuestUsize,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Errors thrown while configuring aarch64 system.
|
/// Errors thrown while configuring aarch64 system.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
/// Failed to create a FDT.
|
/// Failed to create a FDT.
|
||||||
SetupFdt(fdt::Error),
|
SetupFdt,
|
||||||
|
|
||||||
|
/// Failed to write FDT to memory.
|
||||||
|
WriteFdtToMemory(fdt::Error),
|
||||||
|
|
||||||
/// Failed to create a GIC.
|
/// Failed to create a GIC.
|
||||||
SetupGic(gic::Error),
|
SetupGic(gic::Error),
|
||||||
@@ -79,64 +83,89 @@ pub fn configure_vcpu(
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn arch_memory_regions(size: GuestUsize) -> Vec<(GuestAddress, usize, RegionType)> {
|
pub fn arch_memory_regions(size: GuestUsize) -> Vec<(GuestAddress, usize, RegionType)> {
|
||||||
|
// Normally UEFI should be loaded to a flash area at the beginning of memory.
|
||||||
|
// But now flash memory type is not supported.
|
||||||
|
// As a workaround, we take 4 MiB memory from the main RAM for UEFI.
|
||||||
|
// As a result, the RAM that the guest can see is less than what has been
|
||||||
|
// assigned in command line, when ACPI and UEFI is enabled.
|
||||||
|
let ram_deduction = if cfg!(feature = "acpi") {
|
||||||
|
layout::UEFI_SIZE
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
};
|
||||||
|
|
||||||
vec![
|
vec![
|
||||||
// 0 ~ 256 MiB: Reserved
|
// 0 ~ 4 MiB: Reserved for UEFI space
|
||||||
|
#[cfg(feature = "acpi")]
|
||||||
|
(GuestAddress(0), layout::UEFI_SIZE as usize, RegionType::Ram),
|
||||||
|
#[cfg(not(feature = "acpi"))]
|
||||||
(
|
(
|
||||||
GuestAddress(0),
|
GuestAddress(0),
|
||||||
layout::MEM_32BIT_DEVICES_START.0 as usize,
|
layout::UEFI_SIZE as usize,
|
||||||
RegionType::Reserved,
|
RegionType::Reserved,
|
||||||
),
|
),
|
||||||
// 256 MiB ~ 1 G: MMIO space
|
// 4 MiB ~ 256 MiB: Gic and legacy devices
|
||||||
|
(
|
||||||
|
GuestAddress(layout::UEFI_SIZE),
|
||||||
|
(layout::MEM_32BIT_DEVICES_START.0 - layout::UEFI_SIZE) as usize,
|
||||||
|
RegionType::Reserved,
|
||||||
|
),
|
||||||
|
// 256 MiB ~ 768 MiB: MMIO space
|
||||||
(
|
(
|
||||||
layout::MEM_32BIT_DEVICES_START,
|
layout::MEM_32BIT_DEVICES_START,
|
||||||
layout::MEM_32BIT_DEVICES_SIZE as usize,
|
layout::MEM_32BIT_DEVICES_SIZE as usize,
|
||||||
RegionType::SubRegion,
|
RegionType::SubRegion,
|
||||||
),
|
),
|
||||||
// 1G ~ 2G: reserved. The leading 256M for PCIe MMCONFIG space
|
// 768 MiB ~ 1 GiB: reserved. The leading 256M for PCIe MMCONFIG space
|
||||||
(
|
(
|
||||||
layout::PCI_MMCONFIG_START,
|
layout::PCI_MMCONFIG_START,
|
||||||
(layout::RAM_64BIT_START - layout::PCI_MMCONFIG_START.0) as usize,
|
layout::PCI_MMCONFIG_SIZE as usize,
|
||||||
RegionType::Reserved,
|
RegionType::Reserved,
|
||||||
),
|
),
|
||||||
|
// 1 GiB ~ : Ram
|
||||||
(
|
(
|
||||||
GuestAddress(layout::RAM_64BIT_START),
|
GuestAddress(layout::RAM_64BIT_START),
|
||||||
size as usize,
|
(size - ram_deduction) as usize,
|
||||||
RegionType::Ram,
|
RegionType::Ram,
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Configures the system and should be called once per vm before starting vcpu threads.
|
/// Configures the system and should be called once per vm before starting vcpu threads.
|
||||||
///
|
|
||||||
/// # Arguments
|
|
||||||
///
|
|
||||||
/// * `guest_mem` - The memory to be used by the guest.
|
|
||||||
/// * `num_cpus` - Number of virtual CPUs the guest will have.
|
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
pub fn configure_system<T: DeviceInfoForFdt + Clone + Debug, S: ::std::hash::BuildHasher>(
|
pub fn configure_system<T: DeviceInfoForFdt + Clone + Debug, S: ::std::hash::BuildHasher>(
|
||||||
vm: &Arc<dyn hypervisor::Vm>,
|
|
||||||
guest_mem: &GuestMemoryMmap,
|
guest_mem: &GuestMemoryMmap,
|
||||||
cmdline_cstring: &CStr,
|
cmdline: &str,
|
||||||
vcpu_count: u64,
|
|
||||||
vcpu_mpidr: Vec<u64>,
|
vcpu_mpidr: Vec<u64>,
|
||||||
|
vcpu_topology: Option<(u8, u8, u8)>,
|
||||||
device_info: &HashMap<(DeviceType, String), T, S>,
|
device_info: &HashMap<(DeviceType, String), T, S>,
|
||||||
initrd: &Option<super::InitramfsConfig>,
|
initrd: &Option<super::InitramfsConfig>,
|
||||||
pci_space_address: &(u64, u64),
|
pci_space_address: &(u64, u64),
|
||||||
) -> super::Result<Box<dyn GicDevice>> {
|
virtio_iommu_bdf: Option<u32>,
|
||||||
let gic_device = gic::kvm::create_gic(vm, vcpu_count).map_err(Error::SetupGic)?;
|
gic_device: &dyn GicDevice,
|
||||||
|
numa_nodes: &NumaNodes,
|
||||||
fdt::create_fdt(
|
) -> super::Result<()> {
|
||||||
|
let fdt_final = fdt::create_fdt(
|
||||||
guest_mem,
|
guest_mem,
|
||||||
cmdline_cstring,
|
cmdline,
|
||||||
vcpu_mpidr,
|
vcpu_mpidr,
|
||||||
|
vcpu_topology,
|
||||||
device_info,
|
device_info,
|
||||||
&*gic_device,
|
gic_device,
|
||||||
initrd,
|
initrd,
|
||||||
pci_space_address,
|
pci_space_address,
|
||||||
|
numa_nodes,
|
||||||
|
virtio_iommu_bdf,
|
||||||
)
|
)
|
||||||
.map_err(Error::SetupFdt)?;
|
.map_err(|_| Error::SetupFdt)?;
|
||||||
|
|
||||||
Ok(gic_device)
|
if log_enabled!(Level::Debug) {
|
||||||
|
fdt::print_fdt(&fdt_final);
|
||||||
|
}
|
||||||
|
|
||||||
|
fdt::write_fdt_to_memory(fdt_final, guest_mem).map_err(Error::WriteFdtToMemory)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the memory address where the initramfs could be loaded.
|
/// Returns the memory address where the initramfs could be loaded.
|
||||||
@@ -145,8 +174,9 @@ pub fn initramfs_load_addr(
|
|||||||
initramfs_size: usize,
|
initramfs_size: usize,
|
||||||
) -> super::Result<u64> {
|
) -> super::Result<u64> {
|
||||||
let round_to_pagesize = |size| (size + (super::PAGE_SIZE - 1)) & !(super::PAGE_SIZE - 1);
|
let round_to_pagesize = |size| (size + (super::PAGE_SIZE - 1)) & !(super::PAGE_SIZE - 1);
|
||||||
match GuestAddress(get_fdt_addr(&guest_mem))
|
match guest_mem
|
||||||
.checked_sub(round_to_pagesize(initramfs_size) as u64)
|
.last_addr()
|
||||||
|
.checked_sub(round_to_pagesize(initramfs_size) as u64 - 1)
|
||||||
{
|
{
|
||||||
Some(offset) => {
|
Some(offset) => {
|
||||||
if guest_mem.address_in_range(offset) {
|
if guest_mem.address_in_range(offset) {
|
||||||
@@ -161,41 +191,31 @@ pub fn initramfs_load_addr(
|
|||||||
|
|
||||||
/// Returns the memory address where the kernel could be loaded.
|
/// Returns the memory address where the kernel could be loaded.
|
||||||
pub fn get_kernel_start() -> u64 {
|
pub fn get_kernel_start() -> u64 {
|
||||||
layout::RAM_64BIT_START
|
layout::KERNEL_START
|
||||||
|
}
|
||||||
|
|
||||||
|
///Return guest memory address where the uefi should be loaded.
|
||||||
|
pub fn get_uefi_start() -> u64 {
|
||||||
|
layout::UEFI_START
|
||||||
}
|
}
|
||||||
|
|
||||||
// Auxiliary function to get the address where the device tree blob is loaded.
|
// Auxiliary function to get the address where the device tree blob is loaded.
|
||||||
fn get_fdt_addr(mem: &GuestMemoryMmap) -> u64 {
|
fn get_fdt_addr() -> u64 {
|
||||||
// If the memory allocated is smaller than the size allocated for the FDT,
|
layout::FDT_START
|
||||||
// we return the start of the DRAM so that
|
|
||||||
// we allow the code to try and load the FDT.
|
|
||||||
|
|
||||||
if let Some(addr) = mem.last_addr().checked_sub(layout::FDT_MAX_SIZE as u64 - 1) {
|
|
||||||
if mem.address_in_range(addr) {
|
|
||||||
return addr.raw_value();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
layout::RAM_64BIT_START
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_host_cpu_phys_bits() -> u8 {
|
pub fn get_host_cpu_phys_bits() -> u8 {
|
||||||
// The value returned here is used to determine the physical address space size
|
// A dummy hypervisor created only for querying the host IPA size and will
|
||||||
// for a VM (IPA size).
|
// be freed after the query.
|
||||||
// In recent kernel versions, the maximum IPA size supported by the host can be
|
let hv = hypervisor::new().unwrap();
|
||||||
// known by querying cap KVM_CAP_ARM_VM_IPA_SIZE. And the IPA size for a
|
let host_cpu_phys_bits = hv.get_host_ipa_limit().try_into().unwrap();
|
||||||
// guest can be configured smaller.
|
if host_cpu_phys_bits == 0 {
|
||||||
// But in Cloud-Hypervisor we simply use the maximum value for the VM.
|
// Host kernel does not support `get_host_ipa_limit`,
|
||||||
// Reference https://lwn.net/Articles/766767/.
|
// we return the default value 40 here.
|
||||||
//
|
40
|
||||||
// The correct way to query KVM_CAP_ARM_VM_IPA_SIZE is via rust-vmm/kvm-ioctls,
|
} else {
|
||||||
// which wraps all IOCTL's and provides easy interface to user hypervisors.
|
host_cpu_phys_bits
|
||||||
// For now the cap hasn't been supported. A separate patch will be submitted to
|
}
|
||||||
// rust-vmm to add it.
|
|
||||||
// So a hardcoded value is used here as a temporary solution.
|
|
||||||
// It will be replace once rust-vmm/kvm-ioctls is ready.
|
|
||||||
//
|
|
||||||
40
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
@@ -205,38 +225,9 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_arch_memory_regions_dram() {
|
fn test_arch_memory_regions_dram() {
|
||||||
let regions = arch_memory_regions((1usize << 32) as u64); //4GB
|
let regions = arch_memory_regions((1usize << 32) as u64); //4GB
|
||||||
assert_eq!(4, regions.len());
|
assert_eq!(5, regions.len());
|
||||||
assert_eq!(GuestAddress(layout::RAM_64BIT_START), regions[3].0);
|
assert_eq!(GuestAddress(layout::RAM_64BIT_START), regions[4].0);
|
||||||
assert_eq!(1usize << 32, regions[3].1);
|
assert_eq!(1usize << 32, regions[4].1);
|
||||||
assert_eq!(RegionType::Ram, regions[3].2);
|
assert_eq!(RegionType::Ram, regions[4].2);
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_get_fdt_addr() {
|
|
||||||
let mut regions = Vec::new();
|
|
||||||
|
|
||||||
regions.push((
|
|
||||||
GuestAddress(layout::RAM_64BIT_START),
|
|
||||||
(layout::FDT_MAX_SIZE - 0x1000) as usize,
|
|
||||||
));
|
|
||||||
let mem = GuestMemoryMmap::from_ranges(®ions).expect("Cannot initialize memory");
|
|
||||||
assert_eq!(get_fdt_addr(&mem), layout::RAM_64BIT_START);
|
|
||||||
regions.clear();
|
|
||||||
|
|
||||||
regions.push((
|
|
||||||
GuestAddress(layout::RAM_64BIT_START),
|
|
||||||
(layout::FDT_MAX_SIZE) as usize,
|
|
||||||
));
|
|
||||||
let mem = GuestMemoryMmap::from_ranges(®ions).expect("Cannot initialize memory");
|
|
||||||
assert_eq!(get_fdt_addr(&mem), layout::RAM_64BIT_START);
|
|
||||||
regions.clear();
|
|
||||||
|
|
||||||
regions.push((
|
|
||||||
GuestAddress(layout::RAM_64BIT_START),
|
|
||||||
(layout::FDT_MAX_SIZE + 0x1000) as usize,
|
|
||||||
));
|
|
||||||
let mem = GuestMemoryMmap::from_ranges(®ions).expect("Cannot initialize memory");
|
|
||||||
assert_eq!(get_fdt_addr(&mem), 0x1000 + layout::RAM_64BIT_START);
|
|
||||||
regions.clear();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,13 +6,13 @@
|
|||||||
// found in the THIRD-PARTY file.
|
// found in the THIRD-PARTY file.
|
||||||
|
|
||||||
use super::get_fdt_addr;
|
use super::get_fdt_addr;
|
||||||
|
use crate::GuestMemoryMmap;
|
||||||
use hypervisor::kvm::kvm_bindings::{
|
use hypervisor::kvm::kvm_bindings::{
|
||||||
kvm_regs, user_pt_regs, KVM_REG_ARM64, KVM_REG_ARM_CORE, KVM_REG_SIZE_U64,
|
kvm_regs, user_pt_regs, KVM_REG_ARM64, KVM_REG_ARM_CORE, KVM_REG_SIZE_U64,
|
||||||
};
|
};
|
||||||
use hypervisor::{arm64_core_reg_id, offset__of};
|
use hypervisor::{arm64_core_reg_id, offset__of};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::{mem, result};
|
use std::{mem, result};
|
||||||
use vm_memory::GuestMemoryMmap;
|
|
||||||
|
|
||||||
/// Errors thrown while setting aarch64 registers.
|
/// Errors thrown while setting aarch64 registers.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@@ -47,7 +47,7 @@ pub fn setup_regs(
|
|||||||
vcpu: &Arc<dyn hypervisor::Vcpu>,
|
vcpu: &Arc<dyn hypervisor::Vcpu>,
|
||||||
cpu_id: u8,
|
cpu_id: u8,
|
||||||
boot_ip: u64,
|
boot_ip: u64,
|
||||||
mem: &GuestMemoryMmap,
|
_mem: &GuestMemoryMmap,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let kreg_off = offset__of!(kvm_regs, regs);
|
let kreg_off = offset__of!(kvm_regs, regs);
|
||||||
|
|
||||||
@@ -73,7 +73,7 @@ pub fn setup_regs(
|
|||||||
let regs0 = offset__of!(user_pt_regs, regs) + kreg_off;
|
let regs0 = offset__of!(user_pt_regs, regs) + kreg_off;
|
||||||
vcpu.set_reg(
|
vcpu.set_reg(
|
||||||
arm64_core_reg_id!(KVM_REG_SIZE_U64, regs0),
|
arm64_core_reg_id!(KVM_REG_SIZE_U64, regs0),
|
||||||
get_fdt_addr(mem) as u64,
|
get_fdt_addr() as u64,
|
||||||
)
|
)
|
||||||
.map_err(Error::SetCoreRegister)?;
|
.map_err(Error::SetCoreRegister)?;
|
||||||
}
|
}
|
||||||
|
|||||||
43
arch/src/aarch64/uefi.rs
Normal file
43
arch/src/aarch64/uefi.rs
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
// Copyright 2020 Arm Limited (or its affiliates). All rights reserved.
|
||||||
|
|
||||||
|
use std::io::{Read, Seek, SeekFrom};
|
||||||
|
use std::result;
|
||||||
|
use vm_memory::{Bytes, GuestAddress, GuestMemory};
|
||||||
|
|
||||||
|
/// Errors thrown while loading UEFI binary
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum Error {
|
||||||
|
/// Unable to seek to UEFI image start.
|
||||||
|
SeekUefiStart,
|
||||||
|
/// Unable to seek to UEFI image end.
|
||||||
|
SeekUefiEnd,
|
||||||
|
/// UEFI image too big.
|
||||||
|
UefiTooBig,
|
||||||
|
/// Unable to read UEFI image
|
||||||
|
ReadUefiImage,
|
||||||
|
}
|
||||||
|
type Result<T> = result::Result<T, Error>;
|
||||||
|
|
||||||
|
pub fn load_uefi<F, M: GuestMemory>(
|
||||||
|
guest_mem: &M,
|
||||||
|
guest_addr: GuestAddress,
|
||||||
|
uefi_image: &mut F,
|
||||||
|
) -> Result<()>
|
||||||
|
where
|
||||||
|
F: Read + Seek,
|
||||||
|
{
|
||||||
|
let uefi_size = uefi_image
|
||||||
|
.seek(SeekFrom::End(0))
|
||||||
|
.map_err(|_| Error::SeekUefiEnd)? as usize;
|
||||||
|
|
||||||
|
// edk2 image on virtual platform is smaller than 3M
|
||||||
|
if uefi_size > 0x300000 {
|
||||||
|
return Err(Error::UefiTooBig);
|
||||||
|
}
|
||||||
|
uefi_image
|
||||||
|
.seek(SeekFrom::Start(0))
|
||||||
|
.map_err(|_| Error::SeekUefiStart)?;
|
||||||
|
guest_mem
|
||||||
|
.read_exact_from(guest_addr, uefi_image, uefi_size)
|
||||||
|
.map_err(|_| Error::ReadUefiImage)
|
||||||
|
}
|
||||||
@@ -8,27 +8,23 @@
|
|||||||
//! Supported platforms: x86_64, aarch64.
|
//! Supported platforms: x86_64, aarch64.
|
||||||
#![allow(clippy::transmute_ptr_to_ptr, clippy::redundant_static_lifetimes)]
|
#![allow(clippy::transmute_ptr_to_ptr, clippy::redundant_static_lifetimes)]
|
||||||
|
|
||||||
extern crate anyhow;
|
|
||||||
extern crate byteorder;
|
|
||||||
extern crate hypervisor;
|
|
||||||
extern crate libc;
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate log;
|
extern crate log;
|
||||||
#[cfg(feature = "acpi")]
|
|
||||||
extern crate acpi_tables;
|
|
||||||
extern crate arch_gen;
|
|
||||||
extern crate linux_loader;
|
|
||||||
extern crate serde;
|
|
||||||
extern crate vm_memory;
|
|
||||||
extern crate vm_migration;
|
|
||||||
#[cfg(target_arch = "aarch64")]
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate serde_derive;
|
extern crate serde_derive;
|
||||||
extern crate serde_json;
|
|
||||||
extern crate thiserror;
|
|
||||||
|
|
||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
|
use crate::x86_64::SgxEpcSection;
|
||||||
|
use std::collections::BTreeMap;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::result;
|
use std::result;
|
||||||
|
use std::sync::Arc;
|
||||||
|
use versionize::{VersionMap, Versionize, VersionizeError, VersionizeResult};
|
||||||
|
use versionize_derive::Versionize;
|
||||||
|
use vm_migration::VersionMapped;
|
||||||
|
|
||||||
|
type GuestMemoryMmap = vm_memory::GuestMemoryMmap<vm_memory::bitmap::AtomicBitmap>;
|
||||||
|
type GuestRegionMmap = vm_memory::GuestRegionMmap<vm_memory::bitmap::AtomicBitmap>;
|
||||||
|
|
||||||
/// Type for returning error code.
|
/// Type for returning error code.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@@ -63,7 +59,7 @@ pub enum Error {
|
|||||||
pub type Result<T> = result::Result<T, Error>;
|
pub type Result<T> = result::Result<T, Error>;
|
||||||
|
|
||||||
/// Type for memory region types.
|
/// Type for memory region types.
|
||||||
#[derive(PartialEq, Debug)]
|
#[derive(Clone, Copy, PartialEq, Debug, Serialize, Deserialize, Versionize)]
|
||||||
pub enum RegionType {
|
pub enum RegionType {
|
||||||
/// RAM type
|
/// RAM type
|
||||||
Ram,
|
Ram,
|
||||||
@@ -81,6 +77,8 @@ pub enum RegionType {
|
|||||||
Reserved,
|
Reserved,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl VersionMapped for RegionType {}
|
||||||
|
|
||||||
/// Module for aarch64 related functionality.
|
/// Module for aarch64 related functionality.
|
||||||
#[cfg(target_arch = "aarch64")]
|
#[cfg(target_arch = "aarch64")]
|
||||||
pub mod aarch64;
|
pub mod aarch64;
|
||||||
@@ -88,8 +86,8 @@ pub mod aarch64;
|
|||||||
#[cfg(target_arch = "aarch64")]
|
#[cfg(target_arch = "aarch64")]
|
||||||
pub use aarch64::{
|
pub use aarch64::{
|
||||||
arch_memory_regions, configure_system, configure_vcpu, fdt::DeviceInfoForFdt,
|
arch_memory_regions, configure_system, configure_vcpu, fdt::DeviceInfoForFdt,
|
||||||
get_host_cpu_phys_bits, get_kernel_start, initramfs_load_addr, layout,
|
get_host_cpu_phys_bits, get_kernel_start, get_uefi_start, initramfs_load_addr, layout,
|
||||||
layout::CMDLINE_MAX_SIZE, layout::IRQ_BASE, layout::IRQ_MAX, EntryPoint,
|
layout::CMDLINE_MAX_SIZE, layout::IRQ_BASE, uefi, EntryPoint,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
@@ -97,9 +95,9 @@ pub mod x86_64;
|
|||||||
|
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
pub use x86_64::{
|
pub use x86_64::{
|
||||||
arch_memory_regions, configure_system, configure_vcpu, get_host_cpu_phys_bits,
|
arch_memory_regions, configure_system, configure_vcpu, generate_common_cpuid,
|
||||||
initramfs_load_addr, layout, layout::CMDLINE_MAX_SIZE, layout::CMDLINE_START, regs,
|
get_host_cpu_phys_bits, initramfs_load_addr, layout, layout::CMDLINE_MAX_SIZE,
|
||||||
BootProtocol, CpuidPatch, CpuidReg, EntryPoint,
|
layout::CMDLINE_START, regs, CpuidFeatureEntry, EntryPoint,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Safe wrapper for `sysconf(_SC_PAGESIZE)`.
|
/// Safe wrapper for `sysconf(_SC_PAGESIZE)`.
|
||||||
@@ -110,6 +108,19 @@ fn pagesize() -> usize {
|
|||||||
unsafe { libc::sysconf(libc::_SC_PAGESIZE) as usize }
|
unsafe { libc::sysconf(libc::_SC_PAGESIZE) as usize }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Default)]
|
||||||
|
pub struct NumaNode {
|
||||||
|
pub memory_regions: Vec<Arc<GuestRegionMmap>>,
|
||||||
|
pub hotplug_regions: Vec<Arc<GuestRegionMmap>>,
|
||||||
|
pub cpus: Vec<u8>,
|
||||||
|
pub distances: BTreeMap<u32, u8>,
|
||||||
|
pub memory_zones: Vec<String>,
|
||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
|
pub sgx_epc_sections: Vec<SgxEpcSection>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type NumaNodes = BTreeMap<u32, NumaNode>;
|
||||||
|
|
||||||
/// Type for passing information about the initramfs in the guest memory.
|
/// Type for passing information about the initramfs in the guest memory.
|
||||||
pub struct InitramfsConfig {
|
pub struct InitramfsConfig {
|
||||||
/// Load address of initramfs in guest memory
|
/// Load address of initramfs in guest memory
|
||||||
|
|||||||
@@ -12,12 +12,6 @@ use std::mem;
|
|||||||
use std::result;
|
use std::result;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum Error {
|
|
||||||
GetLapic(anyhow::Error),
|
|
||||||
SetLapic(anyhow::Error),
|
|
||||||
}
|
|
||||||
|
|
||||||
pub type Result<T> = result::Result<T, hypervisor::HypervisorCpuError>;
|
pub type Result<T> = result::Result<T, hypervisor::HypervisorCpuError>;
|
||||||
|
|
||||||
// Defines poached from apicdef.h kernel header.
|
// Defines poached from apicdef.h kernel header.
|
||||||
|
|||||||
@@ -9,39 +9,47 @@
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
pub mod interrupts;
|
pub mod interrupts;
|
||||||
pub mod layout;
|
pub mod layout;
|
||||||
|
mod mpspec;
|
||||||
mod mptable;
|
mod mptable;
|
||||||
pub mod regs;
|
pub mod regs;
|
||||||
|
use crate::GuestMemoryMmap;
|
||||||
use crate::InitramfsConfig;
|
use crate::InitramfsConfig;
|
||||||
use crate::RegionType;
|
use crate::RegionType;
|
||||||
use hypervisor::{CpuId, CpuIdEntry, CPUID_FLAG_VALID_INDEX};
|
use hypervisor::{CpuId, CpuIdEntry, HypervisorError, CPUID_FLAG_VALID_INDEX};
|
||||||
use linux_loader::loader::bootparam::{boot_params, setup_header};
|
use linux_loader::loader::bootparam::boot_params;
|
||||||
use linux_loader::loader::elf::start_info::{
|
use linux_loader::loader::elf::start_info::{
|
||||||
hvm_memmap_table_entry, hvm_modlist_entry, hvm_start_info,
|
hvm_memmap_table_entry, hvm_modlist_entry, hvm_start_info,
|
||||||
};
|
};
|
||||||
|
use std::collections::BTreeMap;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use vm_memory::{
|
use vm_memory::{
|
||||||
Address, ByteValued, Bytes, GuestAddress, GuestAddressSpace, GuestMemory, GuestMemoryAtomic,
|
Address, ByteValued, Bytes, GuestAddress, GuestAddressSpace, GuestMemory, GuestMemoryAtomic,
|
||||||
GuestMemoryMmap, GuestMemoryRegion, GuestUsize,
|
GuestMemoryRegion, GuestUsize,
|
||||||
};
|
};
|
||||||
mod smbios;
|
mod smbios;
|
||||||
use std::arch::x86_64;
|
use std::arch::x86_64;
|
||||||
#[cfg(feature = "tdx")]
|
#[cfg(feature = "tdx")]
|
||||||
pub mod tdx;
|
pub mod tdx;
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone)]
|
// CPUID feature bits
|
||||||
pub enum BootProtocol {
|
const TSC_DEADLINE_TIMER_ECX_BIT: u8 = 24; // tsc deadline timer ecx bit.
|
||||||
LinuxBoot,
|
const HYPERVISOR_ECX_BIT: u8 = 31; // Hypervisor ecx bit.
|
||||||
PvhBoot,
|
const MTRR_EDX_BIT: u8 = 12; // Hypervisor ecx bit.
|
||||||
}
|
|
||||||
|
|
||||||
impl ::std::fmt::Display for BootProtocol {
|
// KVM feature bits
|
||||||
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
const KVM_FEATURE_ASYNC_PF_INT_BIT: u8 = 14;
|
||||||
match self {
|
#[cfg(feature = "tdx")]
|
||||||
BootProtocol::LinuxBoot => write!(f, "Linux 64-bit boot protocol"),
|
const KVM_FEATURE_CLOCKSOURCE_BIT: u8 = 0;
|
||||||
BootProtocol::PvhBoot => write!(f, "PVH boot protocol"),
|
#[cfg(feature = "tdx")]
|
||||||
}
|
const KVM_FEATURE_CLOCKSOURCE2_BIT: u8 = 3;
|
||||||
}
|
#[cfg(feature = "tdx")]
|
||||||
}
|
const KVM_FEATURE_CLOCKSOURCE_STABLE_BIT: u8 = 24;
|
||||||
|
#[cfg(feature = "tdx")]
|
||||||
|
const KVM_FEATURE_ASYNC_PF_BIT: u8 = 4;
|
||||||
|
#[cfg(feature = "tdx")]
|
||||||
|
const KVM_FEATURE_ASYNC_PF_VMEXIT_BIT: u8 = 10;
|
||||||
|
#[cfg(feature = "tdx")]
|
||||||
|
const KVM_FEATURE_STEAL_TIME_BIT: u8 = 5;
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone)]
|
#[derive(Debug, Copy, Clone)]
|
||||||
/// Specifies the entry point address where the guest must start
|
/// Specifies the entry point address where the guest must start
|
||||||
@@ -50,10 +58,6 @@ impl ::std::fmt::Display for BootProtocol {
|
|||||||
pub struct EntryPoint {
|
pub struct EntryPoint {
|
||||||
/// Address in guest memory where the guest must start execution
|
/// Address in guest memory where the guest must start execution
|
||||||
pub entry_addr: GuestAddress,
|
pub entry_addr: GuestAddress,
|
||||||
/// Specifies which boot protocol to use
|
|
||||||
pub protocol: BootProtocol,
|
|
||||||
/// This field is used for bzImage to fill zero page
|
|
||||||
pub setup_header: Option<setup_header>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const E820_RAM: u32 = 1;
|
const E820_RAM: u32 = 1;
|
||||||
@@ -81,7 +85,7 @@ impl SgxEpcSection {
|
|||||||
pub struct SgxEpcRegion {
|
pub struct SgxEpcRegion {
|
||||||
start: GuestAddress,
|
start: GuestAddress,
|
||||||
size: GuestUsize,
|
size: GuestUsize,
|
||||||
epc_sections: Vec<SgxEpcSection>,
|
epc_sections: BTreeMap<String, SgxEpcSection>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SgxEpcRegion {
|
impl SgxEpcRegion {
|
||||||
@@ -89,7 +93,7 @@ impl SgxEpcRegion {
|
|||||||
SgxEpcRegion {
|
SgxEpcRegion {
|
||||||
start,
|
start,
|
||||||
size,
|
size,
|
||||||
epc_sections: Vec::new(),
|
epc_sections: BTreeMap::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn start(&self) -> GuestAddress {
|
pub fn start(&self) -> GuestAddress {
|
||||||
@@ -98,11 +102,11 @@ impl SgxEpcRegion {
|
|||||||
pub fn size(&self) -> GuestUsize {
|
pub fn size(&self) -> GuestUsize {
|
||||||
self.size
|
self.size
|
||||||
}
|
}
|
||||||
pub fn epc_sections(&self) -> &Vec<SgxEpcSection> {
|
pub fn epc_sections(&self) -> &BTreeMap<String, SgxEpcSection> {
|
||||||
&self.epc_sections
|
&self.epc_sections
|
||||||
}
|
}
|
||||||
pub fn push(&mut self, epc_section: SgxEpcSection) {
|
pub fn insert(&mut self, id: String, epc_section: SgxEpcSection) {
|
||||||
self.epc_sections.push(epc_section);
|
self.epc_sections.insert(id, epc_section);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -140,9 +144,6 @@ unsafe impl ByteValued for BootParamsWrapper {}
|
|||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
/// Invalid e820 setup params.
|
|
||||||
E820Configuration,
|
|
||||||
|
|
||||||
/// Error writing MP table to memory.
|
/// Error writing MP table to memory.
|
||||||
MpTableSetup(mptable::Error),
|
MpTableSetup(mptable::Error),
|
||||||
|
|
||||||
@@ -175,6 +176,18 @@ pub enum Error {
|
|||||||
|
|
||||||
/// Missing SGX_LC CPU feature
|
/// Missing SGX_LC CPU feature
|
||||||
MissingSgxLaunchControlFeature,
|
MissingSgxLaunchControlFeature,
|
||||||
|
|
||||||
|
/// Error getting supported CPUID through the hypervisor (kvm/mshv) API
|
||||||
|
CpuidGetSupported(HypervisorError),
|
||||||
|
|
||||||
|
/// Error populating CPUID with KVM HyperV emulation details
|
||||||
|
CpuidKvmHyperV(vmm_sys_util::fam::Error),
|
||||||
|
|
||||||
|
/// Error populating CPUID with CPU identification
|
||||||
|
CpuidIdentification(vmm_sys_util::fam::Error),
|
||||||
|
|
||||||
|
/// Error checking CPUID compatibility
|
||||||
|
CpuidCheckCompatibility,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Error> for super::Error {
|
impl From<Error> for super::Error {
|
||||||
@@ -184,7 +197,7 @@ impl From<Error> for super::Error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code, clippy::upper_case_acronyms)]
|
#[allow(dead_code, clippy::upper_case_acronyms)]
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
pub enum CpuidReg {
|
pub enum CpuidReg {
|
||||||
EAX,
|
EAX,
|
||||||
EBX,
|
EBX,
|
||||||
@@ -328,6 +341,386 @@ impl CpuidPatch {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
enum CpuidCompatibleCheck {
|
||||||
|
BitwiseSubset, // bitwise subset
|
||||||
|
Equal, // equal in value
|
||||||
|
NumNotGreater, // smaller or equal as a number
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct CpuidFeatureEntry {
|
||||||
|
function: u32,
|
||||||
|
index: u32,
|
||||||
|
feature_reg: CpuidReg,
|
||||||
|
compatible_check: CpuidCompatibleCheck,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CpuidFeatureEntry {
|
||||||
|
fn checked_feature_entry_list() -> Vec<CpuidFeatureEntry> {
|
||||||
|
vec![
|
||||||
|
// The following list includes all hardware features bits from
|
||||||
|
// the CPUID Wiki Page: https://en.wikipedia.org/wiki/CPUID
|
||||||
|
// Leaf 0x1, ECX/EDX, feature bits
|
||||||
|
CpuidFeatureEntry {
|
||||||
|
function: 1,
|
||||||
|
index: 0,
|
||||||
|
feature_reg: CpuidReg::ECX,
|
||||||
|
compatible_check: CpuidCompatibleCheck::BitwiseSubset,
|
||||||
|
},
|
||||||
|
CpuidFeatureEntry {
|
||||||
|
function: 1,
|
||||||
|
index: 0,
|
||||||
|
feature_reg: CpuidReg::EDX,
|
||||||
|
compatible_check: CpuidCompatibleCheck::BitwiseSubset,
|
||||||
|
},
|
||||||
|
// Leaf 0x7, EAX/EBX/ECX/EDX, extended features
|
||||||
|
CpuidFeatureEntry {
|
||||||
|
function: 7,
|
||||||
|
index: 0,
|
||||||
|
feature_reg: CpuidReg::EAX,
|
||||||
|
compatible_check: CpuidCompatibleCheck::NumNotGreater,
|
||||||
|
},
|
||||||
|
CpuidFeatureEntry {
|
||||||
|
function: 7,
|
||||||
|
index: 0,
|
||||||
|
feature_reg: CpuidReg::EBX,
|
||||||
|
compatible_check: CpuidCompatibleCheck::BitwiseSubset,
|
||||||
|
},
|
||||||
|
CpuidFeatureEntry {
|
||||||
|
function: 7,
|
||||||
|
index: 0,
|
||||||
|
feature_reg: CpuidReg::ECX,
|
||||||
|
compatible_check: CpuidCompatibleCheck::BitwiseSubset,
|
||||||
|
},
|
||||||
|
CpuidFeatureEntry {
|
||||||
|
function: 7,
|
||||||
|
index: 0,
|
||||||
|
feature_reg: CpuidReg::EDX,
|
||||||
|
compatible_check: CpuidCompatibleCheck::BitwiseSubset,
|
||||||
|
},
|
||||||
|
// Leaf 0x7 subleaf 0x1, EAX, extended features
|
||||||
|
CpuidFeatureEntry {
|
||||||
|
function: 7,
|
||||||
|
index: 1,
|
||||||
|
feature_reg: CpuidReg::EAX,
|
||||||
|
compatible_check: CpuidCompatibleCheck::BitwiseSubset,
|
||||||
|
},
|
||||||
|
// Leaf 0x8000_0001, ECX/EDX, CPUID features bits
|
||||||
|
CpuidFeatureEntry {
|
||||||
|
function: 0x8000_0001,
|
||||||
|
index: 0,
|
||||||
|
feature_reg: CpuidReg::ECX,
|
||||||
|
compatible_check: CpuidCompatibleCheck::BitwiseSubset,
|
||||||
|
},
|
||||||
|
CpuidFeatureEntry {
|
||||||
|
function: 0x8000_0001,
|
||||||
|
index: 0,
|
||||||
|
feature_reg: CpuidReg::EDX,
|
||||||
|
compatible_check: CpuidCompatibleCheck::BitwiseSubset,
|
||||||
|
},
|
||||||
|
// KVM CPUID bits: https://www.kernel.org/doc/html/latest/virt/kvm/cpuid.html
|
||||||
|
// Leaf 0x4000_0000, EAX/EBX/ECX/EDX, KVM CPUID SIGNATURE
|
||||||
|
CpuidFeatureEntry {
|
||||||
|
function: 0x4000_0000,
|
||||||
|
index: 0,
|
||||||
|
feature_reg: CpuidReg::EAX,
|
||||||
|
compatible_check: CpuidCompatibleCheck::NumNotGreater,
|
||||||
|
},
|
||||||
|
CpuidFeatureEntry {
|
||||||
|
function: 0x4000_0000,
|
||||||
|
index: 0,
|
||||||
|
feature_reg: CpuidReg::EBX,
|
||||||
|
compatible_check: CpuidCompatibleCheck::Equal,
|
||||||
|
},
|
||||||
|
CpuidFeatureEntry {
|
||||||
|
function: 0x4000_0000,
|
||||||
|
index: 0,
|
||||||
|
feature_reg: CpuidReg::ECX,
|
||||||
|
compatible_check: CpuidCompatibleCheck::Equal,
|
||||||
|
},
|
||||||
|
CpuidFeatureEntry {
|
||||||
|
function: 0x4000_0000,
|
||||||
|
index: 0,
|
||||||
|
feature_reg: CpuidReg::EDX,
|
||||||
|
compatible_check: CpuidCompatibleCheck::Equal,
|
||||||
|
},
|
||||||
|
// Leaf 0x4000_0001, EAX/EBX/ECX/EDX, KVM CPUID features
|
||||||
|
CpuidFeatureEntry {
|
||||||
|
function: 0x4000_0001,
|
||||||
|
index: 0,
|
||||||
|
feature_reg: CpuidReg::EAX,
|
||||||
|
compatible_check: CpuidCompatibleCheck::BitwiseSubset,
|
||||||
|
},
|
||||||
|
CpuidFeatureEntry {
|
||||||
|
function: 0x4000_0001,
|
||||||
|
index: 0,
|
||||||
|
feature_reg: CpuidReg::EBX,
|
||||||
|
compatible_check: CpuidCompatibleCheck::BitwiseSubset,
|
||||||
|
},
|
||||||
|
CpuidFeatureEntry {
|
||||||
|
function: 0x4000_0001,
|
||||||
|
index: 0,
|
||||||
|
feature_reg: CpuidReg::ECX,
|
||||||
|
compatible_check: CpuidCompatibleCheck::BitwiseSubset,
|
||||||
|
},
|
||||||
|
CpuidFeatureEntry {
|
||||||
|
function: 0x4000_0001,
|
||||||
|
index: 0,
|
||||||
|
feature_reg: CpuidReg::EDX,
|
||||||
|
compatible_check: CpuidCompatibleCheck::BitwiseSubset,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_features_from_cpuid(
|
||||||
|
cpuid: &CpuId,
|
||||||
|
feature_entry_list: &[CpuidFeatureEntry],
|
||||||
|
) -> Vec<u32> {
|
||||||
|
let mut features = vec![0; feature_entry_list.len()];
|
||||||
|
for (i, feature_entry) in feature_entry_list.iter().enumerate() {
|
||||||
|
for cpuid_entry in cpuid.as_slice().iter() {
|
||||||
|
if cpuid_entry.function == feature_entry.function
|
||||||
|
&& cpuid_entry.index == feature_entry.index
|
||||||
|
{
|
||||||
|
match feature_entry.feature_reg {
|
||||||
|
CpuidReg::EAX => {
|
||||||
|
features[i] = cpuid_entry.eax;
|
||||||
|
}
|
||||||
|
CpuidReg::EBX => {
|
||||||
|
features[i] = cpuid_entry.ebx;
|
||||||
|
}
|
||||||
|
CpuidReg::ECX => {
|
||||||
|
features[i] = cpuid_entry.ecx;
|
||||||
|
}
|
||||||
|
CpuidReg::EDX => {
|
||||||
|
features[i] = cpuid_entry.edx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
features
|
||||||
|
}
|
||||||
|
|
||||||
|
// The function returns `Error` (a.k.a. "incompatible"), when the CPUID features from `src_vm_cpuid`
|
||||||
|
// is not a subset of those of the `dest_vm_cpuid`.
|
||||||
|
pub fn check_cpuid_compatibility(
|
||||||
|
src_vm_cpuid: &CpuId,
|
||||||
|
dest_vm_cpuid: &CpuId,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
let feature_entry_list = &Self::checked_feature_entry_list();
|
||||||
|
let src_vm_features = Self::get_features_from_cpuid(src_vm_cpuid, feature_entry_list);
|
||||||
|
let dest_vm_features = Self::get_features_from_cpuid(dest_vm_cpuid, feature_entry_list);
|
||||||
|
|
||||||
|
// Loop on feature bit and check if the 'source vm' feature is a subset
|
||||||
|
// of those of the 'destination vm' feature
|
||||||
|
let mut compatible = true;
|
||||||
|
for (i, (src_vm_feature, dest_vm_feature)) in src_vm_features
|
||||||
|
.iter()
|
||||||
|
.zip(dest_vm_features.iter())
|
||||||
|
.enumerate()
|
||||||
|
{
|
||||||
|
let entry = &feature_entry_list[i];
|
||||||
|
let entry_compatible;
|
||||||
|
match entry.compatible_check {
|
||||||
|
CpuidCompatibleCheck::BitwiseSubset => {
|
||||||
|
let different_feature_bits = src_vm_feature ^ dest_vm_feature;
|
||||||
|
let src_vm_feature_bits_only = different_feature_bits & src_vm_feature;
|
||||||
|
entry_compatible = src_vm_feature_bits_only == 0;
|
||||||
|
}
|
||||||
|
CpuidCompatibleCheck::Equal => {
|
||||||
|
entry_compatible = src_vm_feature == dest_vm_feature;
|
||||||
|
}
|
||||||
|
CpuidCompatibleCheck::NumNotGreater => {
|
||||||
|
entry_compatible = src_vm_feature <= dest_vm_feature;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if !entry_compatible {
|
||||||
|
error!(
|
||||||
|
"Detected incompatible CPUID entry: leaf={:#02x} (subleaf={:#02x}), register='{:?}', \
|
||||||
|
compatilbe_check='{:?}', source VM feature='{:#04x}', destination VM feature'{:#04x}'.",
|
||||||
|
entry.function, entry.index, entry.feature_reg,
|
||||||
|
entry.compatible_check, src_vm_feature, dest_vm_feature
|
||||||
|
);
|
||||||
|
|
||||||
|
compatible = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if compatible {
|
||||||
|
info!("No CPU incompatibility detected.");
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(Error::CpuidCheckCompatibility)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn generate_common_cpuid(
|
||||||
|
hypervisor: Arc<dyn hypervisor::Hypervisor>,
|
||||||
|
topology: Option<(u8, u8, u8)>,
|
||||||
|
sgx_epc_sections: Option<Vec<SgxEpcSection>>,
|
||||||
|
phys_bits: u8,
|
||||||
|
kvm_hyperv: bool,
|
||||||
|
#[cfg(feature = "tdx")] tdx_enabled: bool,
|
||||||
|
) -> super::Result<CpuId> {
|
||||||
|
let cpuid_patches = vec![
|
||||||
|
// Patch tsc deadline timer bit
|
||||||
|
CpuidPatch {
|
||||||
|
function: 1,
|
||||||
|
index: 0,
|
||||||
|
flags_bit: None,
|
||||||
|
eax_bit: None,
|
||||||
|
ebx_bit: None,
|
||||||
|
ecx_bit: Some(TSC_DEADLINE_TIMER_ECX_BIT),
|
||||||
|
edx_bit: None,
|
||||||
|
},
|
||||||
|
// Patch hypervisor bit
|
||||||
|
CpuidPatch {
|
||||||
|
function: 1,
|
||||||
|
index: 0,
|
||||||
|
flags_bit: None,
|
||||||
|
eax_bit: None,
|
||||||
|
ebx_bit: None,
|
||||||
|
ecx_bit: Some(HYPERVISOR_ECX_BIT),
|
||||||
|
edx_bit: None,
|
||||||
|
},
|
||||||
|
// Enable MTRR feature
|
||||||
|
CpuidPatch {
|
||||||
|
function: 1,
|
||||||
|
index: 0,
|
||||||
|
flags_bit: None,
|
||||||
|
eax_bit: None,
|
||||||
|
ebx_bit: None,
|
||||||
|
ecx_bit: None,
|
||||||
|
edx_bit: Some(MTRR_EDX_BIT),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
// Supported CPUID
|
||||||
|
let mut cpuid = hypervisor.get_cpuid().map_err(Error::CpuidGetSupported)?;
|
||||||
|
|
||||||
|
CpuidPatch::patch_cpuid(&mut cpuid, cpuid_patches);
|
||||||
|
|
||||||
|
if let Some(t) = topology {
|
||||||
|
update_cpuid_topology(&mut cpuid, t.0, t.1, t.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(sgx_epc_sections) = sgx_epc_sections {
|
||||||
|
update_cpuid_sgx(&mut cpuid, sgx_epc_sections)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update some existing CPUID
|
||||||
|
for entry in cpuid.as_mut_slice().iter_mut() {
|
||||||
|
match entry.function {
|
||||||
|
// Set CPU physical bits
|
||||||
|
0x8000_0008 => {
|
||||||
|
entry.eax = (entry.eax & 0xffff_ff00) | (phys_bits as u32 & 0xff);
|
||||||
|
}
|
||||||
|
// Disable KVM_FEATURE_ASYNC_PF_INT
|
||||||
|
// This is required until we find out why the asynchronous page
|
||||||
|
// fault is generating unexpected behavior when using interrupt
|
||||||
|
// mechanism.
|
||||||
|
// TODO: Re-enable KVM_FEATURE_ASYNC_PF_INT (#2277)
|
||||||
|
0x4000_0001 => {
|
||||||
|
entry.eax &= !(1 << KVM_FEATURE_ASYNC_PF_INT_BIT);
|
||||||
|
|
||||||
|
// These features are not supported by TDX
|
||||||
|
#[cfg(feature = "tdx")]
|
||||||
|
if tdx_enabled {
|
||||||
|
entry.eax &= !(1 << KVM_FEATURE_CLOCKSOURCE_BIT
|
||||||
|
| 1 << KVM_FEATURE_CLOCKSOURCE2_BIT
|
||||||
|
| 1 << KVM_FEATURE_CLOCKSOURCE_STABLE_BIT
|
||||||
|
| 1 << KVM_FEATURE_ASYNC_PF_BIT
|
||||||
|
| 1 << KVM_FEATURE_ASYNC_PF_VMEXIT_BIT
|
||||||
|
| 1 << KVM_FEATURE_STEAL_TIME_BIT)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy CPU identification string
|
||||||
|
for i in 0x8000_0002..=0x8000_0004 {
|
||||||
|
cpuid.retain(|c| c.function != i);
|
||||||
|
let leaf = unsafe { std::arch::x86_64::__cpuid(i) };
|
||||||
|
cpuid
|
||||||
|
.push(CpuIdEntry {
|
||||||
|
function: i,
|
||||||
|
eax: leaf.eax,
|
||||||
|
ebx: leaf.ebx,
|
||||||
|
ecx: leaf.ecx,
|
||||||
|
edx: leaf.edx,
|
||||||
|
..Default::default()
|
||||||
|
})
|
||||||
|
.map_err(Error::CpuidIdentification)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if kvm_hyperv {
|
||||||
|
// Remove conflicting entries
|
||||||
|
cpuid.retain(|c| c.function != 0x4000_0000);
|
||||||
|
cpuid.retain(|c| c.function != 0x4000_0001);
|
||||||
|
// See "Hypervisor Top Level Functional Specification" for details
|
||||||
|
// Compliance with "Hv#1" requires leaves up to 0x4000_000a
|
||||||
|
cpuid
|
||||||
|
.push(CpuIdEntry {
|
||||||
|
function: 0x40000000,
|
||||||
|
eax: 0x4000000a, // Maximum cpuid leaf
|
||||||
|
ebx: 0x756e694c, // "Linu"
|
||||||
|
ecx: 0x564b2078, // "x KV"
|
||||||
|
edx: 0x7648204d, // "M Hv"
|
||||||
|
..Default::default()
|
||||||
|
})
|
||||||
|
.map_err(Error::CpuidKvmHyperV)?;
|
||||||
|
cpuid
|
||||||
|
.push(CpuIdEntry {
|
||||||
|
function: 0x40000001,
|
||||||
|
eax: 0x31237648, // "Hv#1"
|
||||||
|
..Default::default()
|
||||||
|
})
|
||||||
|
.map_err(Error::CpuidKvmHyperV)?;
|
||||||
|
cpuid
|
||||||
|
.push(CpuIdEntry {
|
||||||
|
function: 0x40000002,
|
||||||
|
eax: 0x3839, // "Build number"
|
||||||
|
ebx: 0xa0000, // "Version"
|
||||||
|
..Default::default()
|
||||||
|
})
|
||||||
|
.map_err(Error::CpuidKvmHyperV)?;
|
||||||
|
cpuid
|
||||||
|
.push(CpuIdEntry {
|
||||||
|
function: 0x4000_0003,
|
||||||
|
eax: 1 << 1 // AccessPartitionReferenceCounter
|
||||||
|
| 1 << 2 // AccessSynicRegs
|
||||||
|
| 1 << 3 // AccessSyntheticTimerRegs
|
||||||
|
| 1 << 9, // AccessPartitionReferenceTsc
|
||||||
|
edx: 1 << 3, // CPU dynamic partitioning
|
||||||
|
..Default::default()
|
||||||
|
})
|
||||||
|
.map_err(Error::CpuidKvmHyperV)?;
|
||||||
|
cpuid
|
||||||
|
.push(CpuIdEntry {
|
||||||
|
function: 0x4000_0004,
|
||||||
|
eax: 1 << 5, // Recommend relaxed timing
|
||||||
|
..Default::default()
|
||||||
|
})
|
||||||
|
.map_err(Error::CpuidKvmHyperV)?;
|
||||||
|
for i in 0x4000_0005..=0x4000_000a {
|
||||||
|
cpuid
|
||||||
|
.push(CpuIdEntry {
|
||||||
|
function: i,
|
||||||
|
..Default::default()
|
||||||
|
})
|
||||||
|
.map_err(Error::CpuidKvmHyperV)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(cpuid)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn configure_vcpu(
|
pub fn configure_vcpu(
|
||||||
fd: &Arc<dyn hypervisor::Vcpu>,
|
fd: &Arc<dyn hypervisor::Vcpu>,
|
||||||
id: u8,
|
id: u8,
|
||||||
@@ -336,7 +729,7 @@ pub fn configure_vcpu(
|
|||||||
cpuid: CpuId,
|
cpuid: CpuId,
|
||||||
kvm_hyperv: bool,
|
kvm_hyperv: bool,
|
||||||
) -> super::Result<()> {
|
) -> super::Result<()> {
|
||||||
// Per vCPU CPUID changes; common are handled via CpuManager::generate_common_cpuid()
|
// Per vCPU CPUID changes; common are handled via generate_common_cpuid()
|
||||||
let mut cpuid = cpuid;
|
let mut cpuid = cpuid;
|
||||||
CpuidPatch::set_cpuid_reg(&mut cpuid, 0xb, None, CpuidReg::EDX, u32::from(id));
|
CpuidPatch::set_cpuid_reg(&mut cpuid, 0xb, None, CpuidReg::EDX, u32::from(id));
|
||||||
CpuidPatch::set_cpuid_reg(&mut cpuid, 0x1f, None, CpuidReg::EDX, u32::from(id));
|
CpuidPatch::set_cpuid_reg(&mut cpuid, 0x1f, None, CpuidReg::EDX, u32::from(id));
|
||||||
@@ -351,17 +744,10 @@ pub fn configure_vcpu(
|
|||||||
regs::setup_msrs(fd).map_err(Error::MsrsConfiguration)?;
|
regs::setup_msrs(fd).map_err(Error::MsrsConfiguration)?;
|
||||||
if let Some(kernel_entry_point) = kernel_entry_point {
|
if let Some(kernel_entry_point) = kernel_entry_point {
|
||||||
// Safe to unwrap because this method is called after the VM is configured
|
// Safe to unwrap because this method is called after the VM is configured
|
||||||
regs::setup_regs(
|
regs::setup_regs(fd, kernel_entry_point.entry_addr.raw_value())
|
||||||
fd,
|
.map_err(Error::RegsConfiguration)?;
|
||||||
kernel_entry_point.entry_addr.raw_value(),
|
|
||||||
layout::BOOT_STACK_POINTER.raw_value(),
|
|
||||||
layout::ZERO_PAGE_START.raw_value(),
|
|
||||||
kernel_entry_point.protocol,
|
|
||||||
)
|
|
||||||
.map_err(Error::RegsConfiguration)?;
|
|
||||||
regs::setup_fpu(fd).map_err(Error::FpuConfiguration)?;
|
regs::setup_fpu(fd).map_err(Error::FpuConfiguration)?;
|
||||||
regs::setup_sregs(&vm_memory.memory(), fd, kernel_entry_point.protocol)
|
regs::setup_sregs(&vm_memory.memory(), fd).map_err(Error::SregsConfiguration)?;
|
||||||
.map_err(Error::SregsConfiguration)?;
|
|
||||||
}
|
}
|
||||||
interrupts::set_lint(fd).map_err(|e| Error::LocalIntConfiguration(e.into()))?;
|
interrupts::set_lint(fd).map_err(|e| Error::LocalIntConfiguration(e.into()))?;
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -426,12 +812,9 @@ pub fn arch_memory_regions(size: GuestUsize) -> Vec<(GuestAddress, usize, Region
|
|||||||
pub fn configure_system(
|
pub fn configure_system(
|
||||||
guest_mem: &GuestMemoryMmap,
|
guest_mem: &GuestMemoryMmap,
|
||||||
cmdline_addr: GuestAddress,
|
cmdline_addr: GuestAddress,
|
||||||
cmdline_size: usize,
|
|
||||||
initramfs: &Option<InitramfsConfig>,
|
initramfs: &Option<InitramfsConfig>,
|
||||||
_num_cpus: u8,
|
_num_cpus: u8,
|
||||||
setup_hdr: Option<setup_header>,
|
|
||||||
rsdp_addr: Option<GuestAddress>,
|
rsdp_addr: Option<GuestAddress>,
|
||||||
boot_prot: BootProtocol,
|
|
||||||
sgx_epc_region: Option<SgxEpcRegion>,
|
sgx_epc_region: Option<SgxEpcRegion>,
|
||||||
) -> super::Result<()> {
|
) -> super::Result<()> {
|
||||||
let size = smbios::setup_smbios(guest_mem).map_err(Error::SmbiosSetup)?;
|
let size = smbios::setup_smbios(guest_mem).map_err(Error::SmbiosSetup)?;
|
||||||
@@ -448,31 +831,13 @@ pub fn configure_system(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
match boot_prot {
|
configure_pvh(
|
||||||
BootProtocol::PvhBoot => {
|
guest_mem,
|
||||||
configure_pvh(
|
cmdline_addr,
|
||||||
guest_mem,
|
initramfs,
|
||||||
cmdline_addr,
|
rsdp_addr,
|
||||||
initramfs,
|
sgx_epc_region,
|
||||||
rsdp_addr,
|
)
|
||||||
sgx_epc_region,
|
|
||||||
)?;
|
|
||||||
}
|
|
||||||
BootProtocol::LinuxBoot => {
|
|
||||||
error!("Using deprecated LinuxBoot protocol: Please configure your kernel with CONFIG_PVH=y and supply the `vmlinux` file to `--kernel`");
|
|
||||||
configure_64bit_boot(
|
|
||||||
guest_mem,
|
|
||||||
cmdline_addr,
|
|
||||||
cmdline_size,
|
|
||||||
initramfs,
|
|
||||||
setup_hdr,
|
|
||||||
rsdp_addr,
|
|
||||||
sgx_epc_region,
|
|
||||||
)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn configure_pvh(
|
fn configure_pvh(
|
||||||
@@ -615,121 +980,6 @@ fn add_memmap_entry(memmap: &mut Vec<hvm_memmap_table_entry>, addr: u64, size: u
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn configure_64bit_boot(
|
|
||||||
guest_mem: &GuestMemoryMmap,
|
|
||||||
cmdline_addr: GuestAddress,
|
|
||||||
cmdline_size: usize,
|
|
||||||
initramfs: &Option<InitramfsConfig>,
|
|
||||||
setup_hdr: Option<setup_header>,
|
|
||||||
rsdp_addr: Option<GuestAddress>,
|
|
||||||
sgx_epc_region: Option<SgxEpcRegion>,
|
|
||||||
) -> super::Result<()> {
|
|
||||||
const KERNEL_BOOT_FLAG_MAGIC: u16 = 0xaa55;
|
|
||||||
const KERNEL_HDR_MAGIC: u32 = 0x53726448;
|
|
||||||
const KERNEL_LOADER_OTHER: u8 = 0xff;
|
|
||||||
const KERNEL_MIN_ALIGNMENT_BYTES: u32 = 0x1000000; // Must be non-zero.
|
|
||||||
|
|
||||||
let mut params: BootParamsWrapper = BootParamsWrapper(boot_params::default());
|
|
||||||
|
|
||||||
if let Some(hdr) = setup_hdr {
|
|
||||||
// We should use the header if the loader provides one (e.g. from a bzImage).
|
|
||||||
params.0.hdr = hdr;
|
|
||||||
} else {
|
|
||||||
params.0.hdr.boot_flag = KERNEL_BOOT_FLAG_MAGIC;
|
|
||||||
params.0.hdr.header = KERNEL_HDR_MAGIC;
|
|
||||||
params.0.hdr.kernel_alignment = KERNEL_MIN_ALIGNMENT_BYTES;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Common bootparams settings
|
|
||||||
if params.0.hdr.type_of_loader == 0 {
|
|
||||||
params.0.hdr.type_of_loader = KERNEL_LOADER_OTHER;
|
|
||||||
}
|
|
||||||
params.0.hdr.cmd_line_ptr = cmdline_addr.raw_value() as u32;
|
|
||||||
params.0.hdr.cmdline_size = cmdline_size as u32;
|
|
||||||
|
|
||||||
if let Some(initramfs_config) = initramfs {
|
|
||||||
params.0.hdr.ramdisk_image = initramfs_config.address.raw_value() as u32;
|
|
||||||
params.0.hdr.ramdisk_size = initramfs_config.size as u32;
|
|
||||||
}
|
|
||||||
|
|
||||||
add_e820_entry(&mut params.0, 0, layout::EBDA_START.raw_value(), E820_RAM)?;
|
|
||||||
|
|
||||||
let mem_end = guest_mem.last_addr();
|
|
||||||
if mem_end < layout::MEM_32BIT_RESERVED_START {
|
|
||||||
add_e820_entry(
|
|
||||||
&mut params.0,
|
|
||||||
layout::HIGH_RAM_START.raw_value(),
|
|
||||||
mem_end.unchecked_offset_from(layout::HIGH_RAM_START) + 1,
|
|
||||||
E820_RAM,
|
|
||||||
)?;
|
|
||||||
} else {
|
|
||||||
add_e820_entry(
|
|
||||||
&mut params.0,
|
|
||||||
layout::HIGH_RAM_START.raw_value(),
|
|
||||||
layout::MEM_32BIT_RESERVED_START.unchecked_offset_from(layout::HIGH_RAM_START),
|
|
||||||
E820_RAM,
|
|
||||||
)?;
|
|
||||||
if mem_end > layout::RAM_64BIT_START {
|
|
||||||
add_e820_entry(
|
|
||||||
&mut params.0,
|
|
||||||
layout::RAM_64BIT_START.raw_value(),
|
|
||||||
mem_end.unchecked_offset_from(layout::RAM_64BIT_START) + 1,
|
|
||||||
E820_RAM,
|
|
||||||
)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
add_e820_entry(
|
|
||||||
&mut params.0,
|
|
||||||
layout::PCI_MMCONFIG_START.0,
|
|
||||||
layout::PCI_MMCONFIG_SIZE,
|
|
||||||
E820_RESERVED,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
if let Some(sgx_epc_region) = sgx_epc_region {
|
|
||||||
add_e820_entry(
|
|
||||||
&mut params.0,
|
|
||||||
sgx_epc_region.start().raw_value(),
|
|
||||||
sgx_epc_region.size() as u64,
|
|
||||||
E820_RESERVED,
|
|
||||||
)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(rsdp_addr) = rsdp_addr {
|
|
||||||
params.0.acpi_rsdp_addr = rsdp_addr.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
let zero_page_addr = layout::ZERO_PAGE_START;
|
|
||||||
guest_mem
|
|
||||||
.checked_offset(zero_page_addr, mem::size_of::<boot_params>())
|
|
||||||
.ok_or(super::Error::ZeroPagePastRamEnd)?;
|
|
||||||
guest_mem
|
|
||||||
.write_obj(params, zero_page_addr)
|
|
||||||
.map_err(super::Error::ZeroPageSetup)?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Add an e820 region to the e820 map.
|
|
||||||
/// Returns Ok(()) if successful, or an error if there is no space left in the map.
|
|
||||||
fn add_e820_entry(
|
|
||||||
params: &mut boot_params,
|
|
||||||
addr: u64,
|
|
||||||
size: u64,
|
|
||||||
mem_type: u32,
|
|
||||||
) -> Result<(), Error> {
|
|
||||||
if params.e820_entries >= params.e820_table.len() as u8 {
|
|
||||||
return Err(Error::E820Configuration);
|
|
||||||
}
|
|
||||||
|
|
||||||
params.e820_table[params.e820_entries as usize].addr = addr;
|
|
||||||
params.e820_table[params.e820_entries as usize].size = size;
|
|
||||||
params.e820_table[params.e820_entries as usize].type_ = mem_type;
|
|
||||||
params.e820_entries += 1;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the memory address where the initramfs could be loaded.
|
/// Returns the memory address where the initramfs could be loaded.
|
||||||
pub fn initramfs_load_addr(
|
pub fn initramfs_load_addr(
|
||||||
guest_mem: &GuestMemoryMmap,
|
guest_mem: &GuestMemoryMmap,
|
||||||
@@ -776,7 +1026,7 @@ pub fn get_host_cpu_phys_bits() -> u8 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_cpuid_topology(
|
fn update_cpuid_topology(
|
||||||
cpuid: &mut CpuId,
|
cpuid: &mut CpuId,
|
||||||
threads_per_core: u8,
|
threads_per_core: u8,
|
||||||
cores_per_die: u8,
|
cores_per_die: u8,
|
||||||
@@ -841,7 +1091,7 @@ pub fn update_cpuid_topology(
|
|||||||
|
|
||||||
// The goal is to update the CPUID sub-leaves to reflect the number of EPC
|
// The goal is to update the CPUID sub-leaves to reflect the number of EPC
|
||||||
// sections exposed to the guest.
|
// sections exposed to the guest.
|
||||||
pub fn update_cpuid_sgx(cpuid: &mut CpuId, epc_sections: Vec<SgxEpcSection>) -> Result<(), Error> {
|
fn update_cpuid_sgx(cpuid: &mut CpuId, epc_sections: Vec<SgxEpcSection>) -> Result<(), Error> {
|
||||||
// Something's wrong if there's no EPC section.
|
// Something's wrong if there's no EPC section.
|
||||||
if epc_sections.is_empty() {
|
if epc_sections.is_empty() {
|
||||||
return Err(Error::NoSgxEpcSection);
|
return Err(Error::NoSgxEpcSection);
|
||||||
@@ -888,7 +1138,6 @@ pub fn update_cpuid_sgx(cpuid: &mut CpuId, epc_sections: Vec<SgxEpcSection>) ->
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use linux_loader::loader::bootparam::boot_e820_entry;
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn regions_lt_4gb() {
|
fn regions_lt_4gb() {
|
||||||
@@ -913,12 +1162,9 @@ mod tests {
|
|||||||
let config_err = configure_system(
|
let config_err = configure_system(
|
||||||
&gm,
|
&gm,
|
||||||
GuestAddress(0),
|
GuestAddress(0),
|
||||||
0,
|
|
||||||
&None,
|
&None,
|
||||||
1,
|
1,
|
||||||
None,
|
|
||||||
Some(layout::RSDP_POINTER),
|
Some(layout::RSDP_POINTER),
|
||||||
BootProtocol::LinuxBoot,
|
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
assert!(config_err.is_err());
|
assert!(config_err.is_err());
|
||||||
@@ -932,31 +1178,8 @@ mod tests {
|
|||||||
.map(|r| (r.0, r.1))
|
.map(|r| (r.0, r.1))
|
||||||
.collect();
|
.collect();
|
||||||
let gm = GuestMemoryMmap::from_ranges(&ram_regions).unwrap();
|
let gm = GuestMemoryMmap::from_ranges(&ram_regions).unwrap();
|
||||||
configure_system(
|
|
||||||
&gm,
|
|
||||||
GuestAddress(0),
|
|
||||||
0,
|
|
||||||
&None,
|
|
||||||
no_vcpus,
|
|
||||||
None,
|
|
||||||
None,
|
|
||||||
BootProtocol::LinuxBoot,
|
|
||||||
None,
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
configure_system(
|
configure_system(&gm, GuestAddress(0), &None, no_vcpus, None, None).unwrap();
|
||||||
&gm,
|
|
||||||
GuestAddress(0),
|
|
||||||
0,
|
|
||||||
&None,
|
|
||||||
no_vcpus,
|
|
||||||
None,
|
|
||||||
None,
|
|
||||||
BootProtocol::PvhBoot,
|
|
||||||
None,
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
// Now assigning some memory that is equal to the start of the 32bit memory hole.
|
// Now assigning some memory that is equal to the start of the 32bit memory hole.
|
||||||
let mem_size = 3328 << 20;
|
let mem_size = 3328 << 20;
|
||||||
@@ -967,31 +1190,9 @@ mod tests {
|
|||||||
.map(|r| (r.0, r.1))
|
.map(|r| (r.0, r.1))
|
||||||
.collect();
|
.collect();
|
||||||
let gm = GuestMemoryMmap::from_ranges(&ram_regions).unwrap();
|
let gm = GuestMemoryMmap::from_ranges(&ram_regions).unwrap();
|
||||||
configure_system(
|
configure_system(&gm, GuestAddress(0), &None, no_vcpus, None, None).unwrap();
|
||||||
&gm,
|
|
||||||
GuestAddress(0),
|
|
||||||
0,
|
|
||||||
&None,
|
|
||||||
no_vcpus,
|
|
||||||
None,
|
|
||||||
None,
|
|
||||||
BootProtocol::LinuxBoot,
|
|
||||||
None,
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
configure_system(
|
configure_system(&gm, GuestAddress(0), &None, no_vcpus, None, None).unwrap();
|
||||||
&gm,
|
|
||||||
GuestAddress(0),
|
|
||||||
0,
|
|
||||||
&None,
|
|
||||||
no_vcpus,
|
|
||||||
None,
|
|
||||||
None,
|
|
||||||
BootProtocol::PvhBoot,
|
|
||||||
None,
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
// Now assigning some memory that falls after the 32bit memory hole.
|
// Now assigning some memory that falls after the 32bit memory hole.
|
||||||
let mem_size = 3330 << 20;
|
let mem_size = 3330 << 20;
|
||||||
@@ -1002,71 +1203,9 @@ mod tests {
|
|||||||
.map(|r| (r.0, r.1))
|
.map(|r| (r.0, r.1))
|
||||||
.collect();
|
.collect();
|
||||||
let gm = GuestMemoryMmap::from_ranges(&ram_regions).unwrap();
|
let gm = GuestMemoryMmap::from_ranges(&ram_regions).unwrap();
|
||||||
configure_system(
|
configure_system(&gm, GuestAddress(0), &None, no_vcpus, None, None).unwrap();
|
||||||
&gm,
|
|
||||||
GuestAddress(0),
|
|
||||||
0,
|
|
||||||
&None,
|
|
||||||
no_vcpus,
|
|
||||||
None,
|
|
||||||
None,
|
|
||||||
BootProtocol::LinuxBoot,
|
|
||||||
None,
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
configure_system(
|
configure_system(&gm, GuestAddress(0), &None, no_vcpus, None, None).unwrap();
|
||||||
&gm,
|
|
||||||
GuestAddress(0),
|
|
||||||
0,
|
|
||||||
&None,
|
|
||||||
no_vcpus,
|
|
||||||
None,
|
|
||||||
None,
|
|
||||||
BootProtocol::PvhBoot,
|
|
||||||
None,
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_add_e820_entry() {
|
|
||||||
let e820_table = [(boot_e820_entry {
|
|
||||||
addr: 0x1,
|
|
||||||
size: 4,
|
|
||||||
type_: 1,
|
|
||||||
}); 128];
|
|
||||||
|
|
||||||
let expected_params = boot_params {
|
|
||||||
e820_table,
|
|
||||||
e820_entries: 1,
|
|
||||||
..Default::default()
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut params: boot_params = Default::default();
|
|
||||||
add_e820_entry(
|
|
||||||
&mut params,
|
|
||||||
e820_table[0].addr,
|
|
||||||
e820_table[0].size,
|
|
||||||
e820_table[0].type_,
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
assert_eq!(
|
|
||||||
format!("{:?}", params.e820_table[0]),
|
|
||||||
format!("{:?}", expected_params.e820_table[0])
|
|
||||||
);
|
|
||||||
assert_eq!(params.e820_entries, expected_params.e820_entries);
|
|
||||||
|
|
||||||
// Exercise the scenario where the field storing the length of the e820 entry table is
|
|
||||||
// is bigger than the allocated memory.
|
|
||||||
params.e820_entries = params.e820_table.len() as u8 + 1;
|
|
||||||
assert!(add_e820_entry(
|
|
||||||
&mut params,
|
|
||||||
e820_table[0].addr,
|
|
||||||
e820_table[0].size,
|
|
||||||
e820_table[0].type_
|
|
||||||
)
|
|
||||||
.is_err());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
112
arch/src/x86_64/mpspec.rs
Normal file
112
arch/src/x86_64/mpspec.rs
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
// Copyright 2017 The Chromium OS Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
|
// found in the LICENSE-BSD-3-Clause file.
|
||||||
|
|
||||||
|
pub const MP_PROCESSOR: ::std::os::raw::c_uint = 0;
|
||||||
|
pub const MP_BUS: ::std::os::raw::c_uint = 1;
|
||||||
|
pub const MP_IOAPIC: ::std::os::raw::c_uint = 2;
|
||||||
|
pub const MP_INTSRC: ::std::os::raw::c_uint = 3;
|
||||||
|
pub const MP_LINTSRC: ::std::os::raw::c_uint = 4;
|
||||||
|
pub const CPU_ENABLED: ::std::os::raw::c_uint = 1;
|
||||||
|
pub const CPU_BOOTPROCESSOR: ::std::os::raw::c_uint = 2;
|
||||||
|
pub const MPC_APIC_USABLE: ::std::os::raw::c_uint = 1;
|
||||||
|
pub const MP_IRQDIR_DEFAULT: ::std::os::raw::c_uint = 0;
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Debug, Default, Copy, Clone)]
|
||||||
|
pub struct mpf_intel {
|
||||||
|
pub signature: [::std::os::raw::c_char; 4usize],
|
||||||
|
pub physptr: ::std::os::raw::c_uint,
|
||||||
|
pub length: ::std::os::raw::c_uchar,
|
||||||
|
pub specification: ::std::os::raw::c_uchar,
|
||||||
|
pub checksum: ::std::os::raw::c_uchar,
|
||||||
|
pub feature1: ::std::os::raw::c_uchar,
|
||||||
|
pub feature2: ::std::os::raw::c_uchar,
|
||||||
|
pub feature3: ::std::os::raw::c_uchar,
|
||||||
|
pub feature4: ::std::os::raw::c_uchar,
|
||||||
|
pub feature5: ::std::os::raw::c_uchar,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Debug, Default, Copy, Clone)]
|
||||||
|
pub struct mpc_table {
|
||||||
|
pub signature: [::std::os::raw::c_char; 4usize],
|
||||||
|
pub length: ::std::os::raw::c_ushort,
|
||||||
|
pub spec: ::std::os::raw::c_char,
|
||||||
|
pub checksum: ::std::os::raw::c_char,
|
||||||
|
pub oem: [::std::os::raw::c_char; 8usize],
|
||||||
|
pub productid: [::std::os::raw::c_char; 12usize],
|
||||||
|
pub oemptr: ::std::os::raw::c_uint,
|
||||||
|
pub oemsize: ::std::os::raw::c_ushort,
|
||||||
|
pub oemcount: ::std::os::raw::c_ushort,
|
||||||
|
pub lapic: ::std::os::raw::c_uint,
|
||||||
|
pub reserved: ::std::os::raw::c_uint,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Debug, Default, Copy, Clone)]
|
||||||
|
pub struct mpc_cpu {
|
||||||
|
pub type_: ::std::os::raw::c_uchar,
|
||||||
|
pub apicid: ::std::os::raw::c_uchar,
|
||||||
|
pub apicver: ::std::os::raw::c_uchar,
|
||||||
|
pub cpuflag: ::std::os::raw::c_uchar,
|
||||||
|
pub cpufeature: ::std::os::raw::c_uint,
|
||||||
|
pub featureflag: ::std::os::raw::c_uint,
|
||||||
|
pub reserved: [::std::os::raw::c_uint; 2usize],
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Debug, Default, Copy, Clone)]
|
||||||
|
pub struct mpc_bus {
|
||||||
|
pub type_: ::std::os::raw::c_uchar,
|
||||||
|
pub busid: ::std::os::raw::c_uchar,
|
||||||
|
pub bustype: [::std::os::raw::c_uchar; 6usize],
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Debug, Default, Copy, Clone)]
|
||||||
|
pub struct mpc_ioapic {
|
||||||
|
pub type_: ::std::os::raw::c_uchar,
|
||||||
|
pub apicid: ::std::os::raw::c_uchar,
|
||||||
|
pub apicver: ::std::os::raw::c_uchar,
|
||||||
|
pub flags: ::std::os::raw::c_uchar,
|
||||||
|
pub apicaddr: ::std::os::raw::c_uint,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Debug, Default, Copy, Clone)]
|
||||||
|
pub struct mpc_intsrc {
|
||||||
|
pub type_: ::std::os::raw::c_uchar,
|
||||||
|
pub irqtype: ::std::os::raw::c_uchar,
|
||||||
|
pub irqflag: ::std::os::raw::c_ushort,
|
||||||
|
pub srcbus: ::std::os::raw::c_uchar,
|
||||||
|
pub srcbusirq: ::std::os::raw::c_uchar,
|
||||||
|
pub dstapic: ::std::os::raw::c_uchar,
|
||||||
|
pub dstirq: ::std::os::raw::c_uchar,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const MP_IRQ_SOURCE_TYPES_MP_INT: ::std::os::raw::c_uint = 0;
|
||||||
|
pub const MP_IRQ_SOURCE_TYPES_MP_NMI: ::std::os::raw::c_uint = 1;
|
||||||
|
pub const MP_IRQ_SOURCE_TYPES_MP_EXT_INT: ::std::os::raw::c_uint = 3;
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Debug, Default, Copy, Clone)]
|
||||||
|
pub struct mpc_lintsrc {
|
||||||
|
pub type_: ::std::os::raw::c_uchar,
|
||||||
|
pub irqtype: ::std::os::raw::c_uchar,
|
||||||
|
pub irqflag: ::std::os::raw::c_ushort,
|
||||||
|
pub srcbusid: ::std::os::raw::c_uchar,
|
||||||
|
pub srcbusirq: ::std::os::raw::c_uchar,
|
||||||
|
pub destapic: ::std::os::raw::c_uchar,
|
||||||
|
pub destapiclint: ::std::os::raw::c_uchar,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Debug, Default, Copy, Clone)]
|
||||||
|
pub struct mpc_oemtable {
|
||||||
|
pub signature: [::std::os::raw::c_char; 4usize],
|
||||||
|
pub length: ::std::os::raw::c_ushort,
|
||||||
|
pub rev: ::std::os::raw::c_char,
|
||||||
|
pub checksum: ::std::os::raw::c_char,
|
||||||
|
pub mpc: [::std::os::raw::c_char; 8usize],
|
||||||
|
}
|
||||||
@@ -5,18 +5,15 @@
|
|||||||
// Use of this source code is governed by a BSD-style license that can be
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
// found in the LICENSE-BSD-3-Clause file.
|
// found in the LICENSE-BSD-3-Clause file.
|
||||||
|
|
||||||
|
use crate::layout::{APIC_START, HIGH_RAM_START, IOAPIC_START};
|
||||||
|
use crate::x86_64::mpspec;
|
||||||
|
use crate::GuestMemoryMmap;
|
||||||
|
use libc::c_char;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::result;
|
use std::result;
|
||||||
use std::slice;
|
use std::slice;
|
||||||
|
use vm_memory::{Address, ByteValued, Bytes, GuestAddress, GuestMemory, GuestMemoryError};
|
||||||
use libc::c_char;
|
|
||||||
|
|
||||||
use arch_gen::x86::mpspec;
|
|
||||||
use layout::{APIC_START, HIGH_RAM_START, IOAPIC_START};
|
|
||||||
use vm_memory::{
|
|
||||||
Address, ByteValued, Bytes, GuestAddress, GuestMemory, GuestMemoryError, GuestMemoryMmap,
|
|
||||||
};
|
|
||||||
|
|
||||||
// This is a workaround to the Rust enforcement specifying that any implementation of a foreign
|
// This is a workaround to the Rust enforcement specifying that any implementation of a foreign
|
||||||
// trait (in this case `ByteValued`) where:
|
// trait (in this case `ByteValued`) where:
|
||||||
@@ -222,7 +219,7 @@ pub fn setup_mptable(offset: GuestAddress, mem: &GuestMemoryMmap, num_cpus: u8)
|
|||||||
let size = mem::size_of::<MpcIntsrcWrapper>();
|
let size = mem::size_of::<MpcIntsrcWrapper>();
|
||||||
let mut mpc_intsrc = MpcIntsrcWrapper(mpspec::mpc_intsrc::default());
|
let mut mpc_intsrc = MpcIntsrcWrapper(mpspec::mpc_intsrc::default());
|
||||||
mpc_intsrc.0.type_ = mpspec::MP_INTSRC as u8;
|
mpc_intsrc.0.type_ = mpspec::MP_INTSRC as u8;
|
||||||
mpc_intsrc.0.irqtype = mpspec::mp_irq_source_types_mp_INT as u8;
|
mpc_intsrc.0.irqtype = mpspec::MP_IRQ_SOURCE_TYPES_MP_INT as u8;
|
||||||
mpc_intsrc.0.irqflag = mpspec::MP_IRQDIR_DEFAULT as u16;
|
mpc_intsrc.0.irqflag = mpspec::MP_IRQDIR_DEFAULT as u16;
|
||||||
mpc_intsrc.0.srcbus = 0;
|
mpc_intsrc.0.srcbus = 0;
|
||||||
mpc_intsrc.0.srcbusirq = i;
|
mpc_intsrc.0.srcbusirq = i;
|
||||||
@@ -237,7 +234,7 @@ pub fn setup_mptable(offset: GuestAddress, mem: &GuestMemoryMmap, num_cpus: u8)
|
|||||||
let size = mem::size_of::<MpcLintsrcWrapper>();
|
let size = mem::size_of::<MpcLintsrcWrapper>();
|
||||||
let mut mpc_lintsrc = MpcLintsrcWrapper(mpspec::mpc_lintsrc::default());
|
let mut mpc_lintsrc = MpcLintsrcWrapper(mpspec::mpc_lintsrc::default());
|
||||||
mpc_lintsrc.0.type_ = mpspec::MP_LINTSRC as u8;
|
mpc_lintsrc.0.type_ = mpspec::MP_LINTSRC as u8;
|
||||||
mpc_lintsrc.0.irqtype = mpspec::mp_irq_source_types_mp_ExtINT as u8;
|
mpc_lintsrc.0.irqtype = mpspec::MP_IRQ_SOURCE_TYPES_MP_EXT_INT as u8;
|
||||||
mpc_lintsrc.0.irqflag = mpspec::MP_IRQDIR_DEFAULT as u16;
|
mpc_lintsrc.0.irqflag = mpspec::MP_IRQDIR_DEFAULT as u16;
|
||||||
mpc_lintsrc.0.srcbusid = 0;
|
mpc_lintsrc.0.srcbusid = 0;
|
||||||
mpc_lintsrc.0.srcbusirq = 0;
|
mpc_lintsrc.0.srcbusirq = 0;
|
||||||
@@ -252,7 +249,7 @@ pub fn setup_mptable(offset: GuestAddress, mem: &GuestMemoryMmap, num_cpus: u8)
|
|||||||
let size = mem::size_of::<MpcLintsrcWrapper>();
|
let size = mem::size_of::<MpcLintsrcWrapper>();
|
||||||
let mut mpc_lintsrc = MpcLintsrcWrapper(mpspec::mpc_lintsrc::default());
|
let mut mpc_lintsrc = MpcLintsrcWrapper(mpspec::mpc_lintsrc::default());
|
||||||
mpc_lintsrc.0.type_ = mpspec::MP_LINTSRC as u8;
|
mpc_lintsrc.0.type_ = mpspec::MP_LINTSRC as u8;
|
||||||
mpc_lintsrc.0.irqtype = mpspec::mp_irq_source_types_mp_NMI as u8;
|
mpc_lintsrc.0.irqtype = mpspec::MP_IRQ_SOURCE_TYPES_MP_NMI as u8;
|
||||||
mpc_lintsrc.0.irqflag = mpspec::MP_IRQDIR_DEFAULT as u16;
|
mpc_lintsrc.0.irqflag = mpspec::MP_IRQDIR_DEFAULT as u16;
|
||||||
mpc_lintsrc.0.srcbusid = 0;
|
mpc_lintsrc.0.srcbusid = 0;
|
||||||
mpc_lintsrc.0.srcbusirq = 0;
|
mpc_lintsrc.0.srcbusirq = 0;
|
||||||
@@ -287,7 +284,7 @@ pub fn setup_mptable(offset: GuestAddress, mem: &GuestMemoryMmap, num_cpus: u8)
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use layout::MPTABLE_START;
|
use crate::layout::MPTABLE_START;
|
||||||
use vm_memory::{GuestAddress, GuestUsize};
|
use vm_memory::{GuestAddress, GuestUsize};
|
||||||
|
|
||||||
fn table_entry_size(type_: u8) -> usize {
|
fn table_entry_size(type_: u8) -> usize {
|
||||||
|
|||||||
@@ -6,17 +6,14 @@
|
|||||||
// Portions Copyright 2017 The Chromium OS Authors. All rights reserved.
|
// Portions Copyright 2017 The Chromium OS Authors. All rights reserved.
|
||||||
// Use of this source code is governed by a BSD-style license that can be
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
// found in the LICENSE-BSD-3-Clause file.
|
// found in the LICENSE-BSD-3-Clause file.
|
||||||
use std::sync::Arc;
|
use crate::layout::{BOOT_GDT_START, BOOT_IDT_START, PVH_INFO_START};
|
||||||
use std::{mem, result};
|
use crate::GuestMemoryMmap;
|
||||||
|
|
||||||
use super::BootProtocol;
|
|
||||||
use hypervisor::arch::x86::gdt::{gdt_entry, segment_from_gdt};
|
use hypervisor::arch::x86::gdt::{gdt_entry, segment_from_gdt};
|
||||||
use hypervisor::arch::x86::regs::*;
|
use hypervisor::arch::x86::regs::*;
|
||||||
use hypervisor::x86_64::{FpuState, SpecialRegisters, StandardRegisters};
|
use hypervisor::x86_64::{FpuState, SpecialRegisters, StandardRegisters};
|
||||||
use layout::{
|
use std::sync::Arc;
|
||||||
BOOT_GDT_START, BOOT_IDT_START, PDE_START, PDPTE_START, PML4_START, PML5_START, PVH_INFO_START,
|
use std::{mem, result};
|
||||||
};
|
use vm_memory::{Address, Bytes, GuestMemory, GuestMemoryError};
|
||||||
use vm_memory::{Address, Bytes, GuestMemory, GuestMemoryError, GuestMemoryMmap};
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
@@ -81,32 +78,12 @@ pub fn setup_msrs(vcpu: &Arc<dyn hypervisor::Vcpu>) -> Result<()> {
|
|||||||
///
|
///
|
||||||
/// * `vcpu` - Structure for the VCPU that holds the VCPU's fd.
|
/// * `vcpu` - Structure for the VCPU that holds the VCPU's fd.
|
||||||
/// * `boot_ip` - Starting instruction pointer.
|
/// * `boot_ip` - Starting instruction pointer.
|
||||||
/// * `boot_sp` - Starting stack pointer.
|
pub fn setup_regs(vcpu: &Arc<dyn hypervisor::Vcpu>, boot_ip: u64) -> Result<()> {
|
||||||
/// * `boot_si` - Must point to zero page address per Linux ABI.
|
let regs = StandardRegisters {
|
||||||
pub fn setup_regs(
|
rflags: 0x0000000000000002u64,
|
||||||
vcpu: &Arc<dyn hypervisor::Vcpu>,
|
rbx: PVH_INFO_START.raw_value(),
|
||||||
boot_ip: u64,
|
rip: boot_ip,
|
||||||
boot_sp: u64,
|
..Default::default()
|
||||||
boot_si: u64,
|
|
||||||
boot_prot: BootProtocol,
|
|
||||||
) -> Result<()> {
|
|
||||||
let regs: StandardRegisters = match boot_prot {
|
|
||||||
// Configure regs as required by PVH boot protocol.
|
|
||||||
BootProtocol::PvhBoot => StandardRegisters {
|
|
||||||
rflags: 0x0000000000000002u64,
|
|
||||||
rbx: PVH_INFO_START.raw_value(),
|
|
||||||
rip: boot_ip,
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
// Configure regs as required by Linux 64-bit boot protocol.
|
|
||||||
BootProtocol::LinuxBoot => StandardRegisters {
|
|
||||||
rflags: 0x0000000000000002u64,
|
|
||||||
rip: boot_ip,
|
|
||||||
rsp: boot_sp,
|
|
||||||
rbp: boot_sp,
|
|
||||||
rsi: boot_si,
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
vcpu.set_regs(®s).map_err(Error::SetBaseRegisters)
|
vcpu.set_regs(®s).map_err(Error::SetBaseRegisters)
|
||||||
}
|
}
|
||||||
@@ -117,19 +94,9 @@ pub fn setup_regs(
|
|||||||
///
|
///
|
||||||
/// * `mem` - The memory that will be passed to the guest.
|
/// * `mem` - The memory that will be passed to the guest.
|
||||||
/// * `vcpu` - Structure for the VCPU that holds the VCPU's fd.
|
/// * `vcpu` - Structure for the VCPU that holds the VCPU's fd.
|
||||||
pub fn setup_sregs(
|
pub fn setup_sregs(mem: &GuestMemoryMmap, vcpu: &Arc<dyn hypervisor::Vcpu>) -> Result<()> {
|
||||||
mem: &GuestMemoryMmap,
|
|
||||||
vcpu: &Arc<dyn hypervisor::Vcpu>,
|
|
||||||
boot_prot: BootProtocol,
|
|
||||||
) -> Result<()> {
|
|
||||||
let mut sregs: SpecialRegisters = vcpu.get_sregs().map_err(Error::GetStatusRegisters)?;
|
let mut sregs: SpecialRegisters = vcpu.get_sregs().map_err(Error::GetStatusRegisters)?;
|
||||||
|
configure_segments_and_sregs(mem, &mut sregs)?;
|
||||||
configure_segments_and_sregs(mem, &mut sregs, boot_prot)?;
|
|
||||||
|
|
||||||
if let BootProtocol::LinuxBoot = boot_prot {
|
|
||||||
setup_page_tables(mem, &mut sregs)?; // TODO(dgreid) - Can this be done once per system instead?
|
|
||||||
}
|
|
||||||
|
|
||||||
vcpu.set_sregs(&sregs).map_err(Error::SetStatusRegisters)
|
vcpu.set_sregs(&sregs).map_err(Error::SetStatusRegisters)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -156,27 +123,15 @@ fn write_idt_value(val: u64, guest_mem: &GuestMemoryMmap) -> Result<()> {
|
|||||||
pub fn configure_segments_and_sregs(
|
pub fn configure_segments_and_sregs(
|
||||||
mem: &GuestMemoryMmap,
|
mem: &GuestMemoryMmap,
|
||||||
sregs: &mut SpecialRegisters,
|
sregs: &mut SpecialRegisters,
|
||||||
boot_prot: BootProtocol,
|
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let gdt_table: [u64; BOOT_GDT_MAX as usize] = match boot_prot {
|
let gdt_table: [u64; BOOT_GDT_MAX as usize] = {
|
||||||
BootProtocol::PvhBoot => {
|
// Configure GDT entries as specified by PVH boot protocol
|
||||||
// Configure GDT entries as specified by PVH boot protocol
|
[
|
||||||
[
|
gdt_entry(0, 0, 0), // NULL
|
||||||
gdt_entry(0, 0, 0), // NULL
|
gdt_entry(0xc09b, 0, 0xffffffff), // CODE
|
||||||
gdt_entry(0xc09b, 0, 0xffffffff), // CODE
|
gdt_entry(0xc093, 0, 0xffffffff), // DATA
|
||||||
gdt_entry(0xc093, 0, 0xffffffff), // DATA
|
gdt_entry(0x008b, 0, 0x67), // TSS
|
||||||
gdt_entry(0x008b, 0, 0x67), // TSS
|
]
|
||||||
]
|
|
||||||
}
|
|
||||||
BootProtocol::LinuxBoot => {
|
|
||||||
// Configure GDT entries as specified by Linux 64bit boot protocol
|
|
||||||
[
|
|
||||||
gdt_entry(0, 0, 0), // NULL
|
|
||||||
gdt_entry(0xa09b, 0, 0xfffff), // CODE
|
|
||||||
gdt_entry(0xc093, 0, 0xfffff), // DATA
|
|
||||||
gdt_entry(0x808b, 0, 0xfffff), // TSS
|
|
||||||
]
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let code_seg = segment_from_gdt(gdt_table[1], 1);
|
let code_seg = segment_from_gdt(gdt_table[1], 1);
|
||||||
@@ -200,61 +155,17 @@ pub fn configure_segments_and_sregs(
|
|||||||
sregs.ss = data_seg;
|
sregs.ss = data_seg;
|
||||||
sregs.tr = tss_seg;
|
sregs.tr = tss_seg;
|
||||||
|
|
||||||
match boot_prot {
|
sregs.cr0 = CR0_PE;
|
||||||
BootProtocol::PvhBoot => {
|
sregs.cr4 = 0;
|
||||||
sregs.cr0 = CR0_PE;
|
|
||||||
sregs.cr4 = 0;
|
|
||||||
}
|
|
||||||
BootProtocol::LinuxBoot => {
|
|
||||||
/* 64-bit protected mode */
|
|
||||||
sregs.cr0 |= CR0_PE;
|
|
||||||
sregs.efer |= EFER_LME | EFER_LMA;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn setup_page_tables(mem: &GuestMemoryMmap, sregs: &mut SpecialRegisters) -> Result<()> {
|
|
||||||
// Puts PML5 or PML4 right after zero page but aligned to 4k.
|
|
||||||
if unsafe { std::arch::x86_64::__cpuid(7).ecx } & (1 << 16) != 0 {
|
|
||||||
// Entry covering VA [0..256TB)
|
|
||||||
mem.write_obj(PML4_START.raw_value() | 0x03, PML5_START)
|
|
||||||
.map_err(Error::WritePml5Address)?;
|
|
||||||
|
|
||||||
sregs.cr3 = PML5_START.raw_value();
|
|
||||||
sregs.cr4 |= CR4_LA57;
|
|
||||||
} else {
|
|
||||||
sregs.cr3 = PML4_START.raw_value();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Entry covering VA [0..512GB)
|
|
||||||
mem.write_obj(PDPTE_START.raw_value() | 0x03, PML4_START)
|
|
||||||
.map_err(Error::WritePml4Address)?;
|
|
||||||
|
|
||||||
// Entry covering VA [0..1GB)
|
|
||||||
mem.write_obj(PDE_START.raw_value() | 0x03, PDPTE_START)
|
|
||||||
.map_err(Error::WritePdpteAddress)?;
|
|
||||||
|
|
||||||
// 512 2MB entries together covering VA [0..1GB). Note we are assuming
|
|
||||||
// CPU supports 2MB pages (/proc/cpuinfo has 'pse'). All modern CPUs do.
|
|
||||||
for i in 0..512 {
|
|
||||||
mem.write_obj((i << 21) + 0x83u64, PDE_START.unchecked_add(i * 8))
|
|
||||||
.map_err(Error::WritePdeAddress)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
sregs.cr4 |= CR4_PAE;
|
|
||||||
sregs.cr0 |= CR0_PG;
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
extern crate vm_memory;
|
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use vm_memory::{GuestAddress, GuestMemoryMmap};
|
use crate::GuestMemoryMmap;
|
||||||
|
use vm_memory::GuestAddress;
|
||||||
|
|
||||||
fn create_guest_mem() -> GuestMemoryMmap {
|
fn create_guest_mem() -> GuestMemoryMmap {
|
||||||
GuestMemoryMmap::from_ranges(&[(GuestAddress(0), 0x10000)]).unwrap()
|
GuestMemoryMmap::from_ranges(&[(GuestAddress(0), 0x10000)]).unwrap()
|
||||||
@@ -268,36 +179,7 @@ mod tests {
|
|||||||
fn segments_and_sregs() {
|
fn segments_and_sregs() {
|
||||||
let mut sregs: SpecialRegisters = Default::default();
|
let mut sregs: SpecialRegisters = Default::default();
|
||||||
let gm = create_guest_mem();
|
let gm = create_guest_mem();
|
||||||
configure_segments_and_sregs(&gm, &mut sregs, BootProtocol::LinuxBoot).unwrap();
|
configure_segments_and_sregs(&gm, &mut sregs).unwrap();
|
||||||
|
|
||||||
assert_eq!(0x0, read_u64(&gm, BOOT_GDT_START));
|
|
||||||
assert_eq!(
|
|
||||||
0xaf9b000000ffff,
|
|
||||||
read_u64(&gm, BOOT_GDT_START.unchecked_add(8))
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
0xcf93000000ffff,
|
|
||||||
read_u64(&gm, BOOT_GDT_START.unchecked_add(16))
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
0x8f8b000000ffff,
|
|
||||||
read_u64(&gm, BOOT_GDT_START.unchecked_add(24))
|
|
||||||
);
|
|
||||||
assert_eq!(0x0, read_u64(&gm, BOOT_IDT_START));
|
|
||||||
|
|
||||||
assert_eq!(0, sregs.cs.base);
|
|
||||||
assert_eq!(0xffffffff, sregs.ds.limit);
|
|
||||||
assert_eq!(0x10, sregs.es.selector);
|
|
||||||
assert_eq!(1, sregs.fs.present);
|
|
||||||
assert_eq!(1, sregs.gs.g);
|
|
||||||
assert_eq!(0, sregs.ss.avl);
|
|
||||||
assert_eq!(0, sregs.tr.base);
|
|
||||||
assert_eq!(0xffffffff, sregs.tr.limit);
|
|
||||||
assert_eq!(0, sregs.tr.avl);
|
|
||||||
assert_eq!(CR0_PE, sregs.cr0);
|
|
||||||
assert_eq!(EFER_LME | EFER_LMA, sregs.efer);
|
|
||||||
|
|
||||||
configure_segments_and_sregs(&gm, &mut sregs, BootProtocol::PvhBoot).unwrap();
|
|
||||||
assert_eq!(0x0, read_u64(&gm, BOOT_GDT_START));
|
assert_eq!(0x0, read_u64(&gm, BOOT_GDT_START));
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
0xcf9b000000ffff,
|
0xcf9b000000ffff,
|
||||||
@@ -327,31 +209,4 @@ mod tests {
|
|||||||
assert_eq!(CR0_PE, sregs.cr0);
|
assert_eq!(CR0_PE, sregs.cr0);
|
||||||
assert_eq!(0, sregs.cr4);
|
assert_eq!(0, sregs.cr4);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn page_tables() {
|
|
||||||
let mut sregs: SpecialRegisters = Default::default();
|
|
||||||
let gm = create_guest_mem();
|
|
||||||
setup_page_tables(&gm, &mut sregs).unwrap();
|
|
||||||
|
|
||||||
if unsafe { std::arch::x86_64::__cpuid(7).ecx } & (1 << 16) != 0 {
|
|
||||||
assert_eq!(0xa003, read_u64(&gm, PML5_START));
|
|
||||||
}
|
|
||||||
assert_eq!(0xb003, read_u64(&gm, PML4_START));
|
|
||||||
assert_eq!(0xc003, read_u64(&gm, PDPTE_START));
|
|
||||||
for i in 0..512 {
|
|
||||||
assert_eq!(
|
|
||||||
(i << 21) + 0x83u64,
|
|
||||||
read_u64(&gm, PDE_START.unchecked_add(i * 8))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if unsafe { std::arch::x86_64::__cpuid(7).ecx } & (1 << 16) != 0 {
|
|
||||||
assert_eq!(PML5_START.raw_value(), sregs.cr3);
|
|
||||||
} else {
|
|
||||||
assert_eq!(PML4_START.raw_value(), sregs.cr3);
|
|
||||||
}
|
|
||||||
assert_eq!(CR4_PAE, sregs.cr4);
|
|
||||||
assert_eq!(CR0_PG, sregs.cr0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,13 +6,14 @@
|
|||||||
//
|
//
|
||||||
// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
|
// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
|
||||||
|
|
||||||
use layout::SMBIOS_START;
|
use crate::layout::SMBIOS_START;
|
||||||
|
use crate::GuestMemoryMmap;
|
||||||
use std::fmt::{self, Display};
|
use std::fmt::{self, Display};
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::result;
|
use std::result;
|
||||||
use std::slice;
|
use std::slice;
|
||||||
use vm_memory::ByteValued;
|
use vm_memory::ByteValued;
|
||||||
use vm_memory::{Address, Bytes, GuestAddress, GuestMemoryMmap};
|
use vm_memory::{Address, Bytes, GuestAddress};
|
||||||
|
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
// Copyright © 2021 Intel Corporation
|
// Copyright © 2021 Intel Corporation
|
||||||
//
|
//
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
use crate::GuestMemoryMmap;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::{Read, Seek, SeekFrom};
|
use std::io::{Read, Seek, SeekFrom};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use vm_memory::{ByteValued, Bytes, GuestAddress, GuestMemoryError, GuestMemoryMmap};
|
use vm_memory::{ByteValued, Bytes, GuestAddress, GuestMemoryError};
|
||||||
|
|
||||||
#[derive(Error, Debug)]
|
#[derive(Error, Debug)]
|
||||||
pub enum TdvfError {
|
pub enum TdvfError {
|
||||||
@@ -59,6 +60,59 @@ impl Default for TdvfSectionType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Clone, Copy, Default, Debug)]
|
||||||
|
pub struct TdVmmDataRegion {
|
||||||
|
pub start_address: u64,
|
||||||
|
pub length: u64,
|
||||||
|
pub region_type: TdVmmDataRegionType,
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl ByteValued for TdVmmDataRegion {}
|
||||||
|
|
||||||
|
#[repr(u16)]
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
pub enum TdVmmDataRegionType {
|
||||||
|
Signature = 0x0000,
|
||||||
|
InterfaceVersion = 0x0001,
|
||||||
|
SystemUuid = 0x0002,
|
||||||
|
RamSize = 0x0003,
|
||||||
|
GraphicsEnabled = 0x0004,
|
||||||
|
SmpCpuCount = 0x0005,
|
||||||
|
MachineId = 0x0006,
|
||||||
|
KernelAddress = 0x0007,
|
||||||
|
KernelSize = 0x0008,
|
||||||
|
KernelCommandLine = 0x0009,
|
||||||
|
InitrdAddress = 0x000a,
|
||||||
|
InitrdSize = 0x000b,
|
||||||
|
BootDevice = 0x000c,
|
||||||
|
NumaData = 0x000d,
|
||||||
|
BootMenu = 0x000e,
|
||||||
|
MaximumCpuCount = 0x000f,
|
||||||
|
KernelEntry = 0x0010,
|
||||||
|
KernelData = 0x0011,
|
||||||
|
InitrdData = 0x0012,
|
||||||
|
CommandLineAddress = 0x0013,
|
||||||
|
CommandLineSize = 0x0014,
|
||||||
|
CommandLineData = 0x0015,
|
||||||
|
KernelSetupAddress = 0x0016,
|
||||||
|
KernelSetupSize = 0x0017,
|
||||||
|
KernelSetupData = 0x0018,
|
||||||
|
FileDir = 0x0019,
|
||||||
|
AcpiTables = 0x8000,
|
||||||
|
SmbiosTables = 0x8001,
|
||||||
|
Irq0Override = 0x8002,
|
||||||
|
E820Table = 0x8003,
|
||||||
|
HpetData = 0x8004,
|
||||||
|
Reserved = 0xffff,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for TdVmmDataRegionType {
|
||||||
|
fn default() -> Self {
|
||||||
|
TdVmmDataRegionType::Reserved
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn parse_tdvf_sections(file: &mut File) -> Result<Vec<TdvfSection>, TdvfError> {
|
pub fn parse_tdvf_sections(file: &mut File) -> Result<Vec<TdvfSection>, TdvfError> {
|
||||||
// The 32-bit offset to the TDVF metadata is located 32 bytes from
|
// The 32-bit offset to the TDVF metadata is located 32 bytes from
|
||||||
// the end of the file.
|
// the end of the file.
|
||||||
@@ -119,6 +173,7 @@ pub fn parse_tdvf_sections(file: &mut File) -> Result<Vec<TdvfSection>, TdvfErro
|
|||||||
enum HobType {
|
enum HobType {
|
||||||
Handoff = 0x1,
|
Handoff = 0x1,
|
||||||
ResourceDescriptor = 0x3,
|
ResourceDescriptor = 0x3,
|
||||||
|
GuidExtension = 0x4,
|
||||||
Unused = 0xfffe,
|
Unused = 0xfffe,
|
||||||
EndOfHobList = 0xffff,
|
EndOfHobList = 0xffff,
|
||||||
}
|
}
|
||||||
@@ -143,6 +198,7 @@ unsafe impl ByteValued for HobHeader {}
|
|||||||
struct HobHandoffInfoTable {
|
struct HobHandoffInfoTable {
|
||||||
header: HobHeader,
|
header: HobHeader,
|
||||||
version: u32,
|
version: u32,
|
||||||
|
boot_mode: u32,
|
||||||
efi_memory_top: u64,
|
efi_memory_top: u64,
|
||||||
efi_memory_bottom: u64,
|
efi_memory_bottom: u64,
|
||||||
efi_free_memory_top: u64,
|
efi_free_memory_top: u64,
|
||||||
@@ -172,6 +228,22 @@ struct HobResourceDescriptor {
|
|||||||
}
|
}
|
||||||
unsafe impl ByteValued for HobResourceDescriptor {}
|
unsafe impl ByteValued for HobResourceDescriptor {}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Copy, Clone, Default, Debug)]
|
||||||
|
struct HobGuidType {
|
||||||
|
header: HobHeader,
|
||||||
|
name: EfiGuid,
|
||||||
|
}
|
||||||
|
unsafe impl ByteValued for HobGuidType {}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Copy, Clone, Default, Debug)]
|
||||||
|
struct TdVmmData {
|
||||||
|
guid_type: HobGuidType,
|
||||||
|
region: TdVmmDataRegion,
|
||||||
|
}
|
||||||
|
unsafe impl ByteValued for TdVmmData {}
|
||||||
|
|
||||||
pub struct TdHob {
|
pub struct TdHob {
|
||||||
start_offset: u64,
|
start_offset: u64,
|
||||||
current_offset: u64,
|
current_offset: u64,
|
||||||
@@ -217,6 +289,7 @@ impl TdHob {
|
|||||||
reserved: 0,
|
reserved: 0,
|
||||||
},
|
},
|
||||||
version: 0x9,
|
version: 0x9,
|
||||||
|
boot_mode: 0,
|
||||||
efi_memory_top: 0,
|
efi_memory_top: 0,
|
||||||
efi_memory_bottom: 0,
|
efi_memory_bottom: 0,
|
||||||
efi_free_memory_top: 0,
|
efi_free_memory_top: 0,
|
||||||
@@ -276,10 +349,10 @@ impl TdHob {
|
|||||||
},
|
},
|
||||||
/* TODO:
|
/* TODO:
|
||||||
* QEMU currently fills it in like this:
|
* QEMU currently fills it in like this:
|
||||||
* EFI_RESOURCE_ATTRIBUTE_PRESENT | EFI_RESOURCE_ATTRIBUTE_INITIALIZED | EFI_RESOURCE_ATTRIBUTE_TESTED
|
* EFI_RESOURCE_ATTRIBUTE_PRESENT | EFI_RESOURCE_ATTRIBUTE_INITIALIZED | EFI_RESOURCE_ATTRIBUTE_ENCRYPTED | EFI_RESOURCE_ATTRIBUTE_TESTED
|
||||||
* which differs from the spec (due to TDVF implementation issue?)
|
* which differs from the spec (due to TDVF implementation issue?)
|
||||||
*/
|
*/
|
||||||
0x7,
|
0x04000007,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -300,6 +373,38 @@ impl TdHob {
|
|||||||
0x403,
|
0x403,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn add_td_vmm_data(
|
||||||
|
&mut self,
|
||||||
|
mem: &GuestMemoryMmap,
|
||||||
|
region: TdVmmDataRegion,
|
||||||
|
) -> Result<(), TdvfError> {
|
||||||
|
let td_vmm_data = TdVmmData {
|
||||||
|
guid_type: HobGuidType {
|
||||||
|
header: HobHeader {
|
||||||
|
r#type: HobType::GuidExtension,
|
||||||
|
length: std::mem::size_of::<TdVmmData>() as u16,
|
||||||
|
reserved: 0,
|
||||||
|
},
|
||||||
|
// TD_VMM_DATA_GUID CF2643E4-C0D3-46FF-0000-72EE623DDE38
|
||||||
|
name: EfiGuid {
|
||||||
|
data1: 0xcf26_43e4,
|
||||||
|
data2: 0xc0d3,
|
||||||
|
data3: 0x46ff,
|
||||||
|
data4: [0x00, 0x00, 0x72, 0xee, 0x62, 0x3d, 0xde, 0x38],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
region,
|
||||||
|
};
|
||||||
|
info!(
|
||||||
|
"Writing HOB TD_VMM_DATA {:x} {:x?}",
|
||||||
|
self.current_offset, td_vmm_data
|
||||||
|
);
|
||||||
|
mem.write_obj(td_vmm_data, GuestAddress(self.current_offset))
|
||||||
|
.map_err(TdvfError::GuestMemoryWriteHob)?;
|
||||||
|
self.update_offset::<TdVmmData>();
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|||||||
6
arch_gen/Cargo.lock
generated
6
arch_gen/Cargo.lock
generated
@@ -1,6 +0,0 @@
|
|||||||
# This file is automatically @generated by Cargo.
|
|
||||||
# It is not intended for manual editing.
|
|
||||||
[[package]]
|
|
||||||
name = "arch_gen"
|
|
||||||
version = "0.1.0"
|
|
||||||
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
[package]
|
|
||||||
name = "arch_gen"
|
|
||||||
version = "0.1.0"
|
|
||||||
authors = ["Amazon firecracker team <firecracker-devel@amazon.com>"]
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
|
||||||
|
|
||||||
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
|
||||||
pub mod x86;
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
|
||||||
//
|
|
||||||
// Portions Copyright 2017 The Chromium OS Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style license that can be
|
|
||||||
// found in the LICENSE-BSD-3-Clause file.
|
|
||||||
|
|
||||||
#[allow(non_upper_case_globals)]
|
|
||||||
#[allow(non_camel_case_types)]
|
|
||||||
#[allow(non_snake_case)]
|
|
||||||
#[allow(non_camel_case_types)]
|
|
||||||
#[allow(non_upper_case_globals)]
|
|
||||||
#[allow(clippy::unreadable_literal, clippy::redundant_static_lifetimes)]
|
|
||||||
pub mod mpspec;
|
|
||||||
@@ -1,832 +0,0 @@
|
|||||||
// Copyright 2017 The Chromium OS Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style license that can be
|
|
||||||
// found in the LICENSE-BSD-3-Clause file.
|
|
||||||
|
|
||||||
/* automatically generated by rust-bindgen */
|
|
||||||
|
|
||||||
pub const MPC_SIGNATURE: &'static [u8; 5usize] = b"PCMP\x00";
|
|
||||||
pub const MP_PROCESSOR: ::std::os::raw::c_uint = 0;
|
|
||||||
pub const MP_BUS: ::std::os::raw::c_uint = 1;
|
|
||||||
pub const MP_IOAPIC: ::std::os::raw::c_uint = 2;
|
|
||||||
pub const MP_INTSRC: ::std::os::raw::c_uint = 3;
|
|
||||||
pub const MP_LINTSRC: ::std::os::raw::c_uint = 4;
|
|
||||||
pub const MP_TRANSLATION: ::std::os::raw::c_uint = 192;
|
|
||||||
pub const CPU_ENABLED: ::std::os::raw::c_uint = 1;
|
|
||||||
pub const CPU_BOOTPROCESSOR: ::std::os::raw::c_uint = 2;
|
|
||||||
pub const CPU_STEPPING_MASK: ::std::os::raw::c_uint = 15;
|
|
||||||
pub const CPU_MODEL_MASK: ::std::os::raw::c_uint = 240;
|
|
||||||
pub const CPU_FAMILY_MASK: ::std::os::raw::c_uint = 3840;
|
|
||||||
pub const BUSTYPE_EISA: &'static [u8; 5usize] = b"EISA\x00";
|
|
||||||
pub const BUSTYPE_ISA: &'static [u8; 4usize] = b"ISA\x00";
|
|
||||||
pub const BUSTYPE_INTERN: &'static [u8; 7usize] = b"INTERN\x00";
|
|
||||||
pub const BUSTYPE_MCA: &'static [u8; 4usize] = b"MCA\x00";
|
|
||||||
pub const BUSTYPE_VL: &'static [u8; 3usize] = b"VL\x00";
|
|
||||||
pub const BUSTYPE_PCI: &'static [u8; 4usize] = b"PCI\x00";
|
|
||||||
pub const BUSTYPE_PCMCIA: &'static [u8; 7usize] = b"PCMCIA\x00";
|
|
||||||
pub const BUSTYPE_CBUS: &'static [u8; 5usize] = b"CBUS\x00";
|
|
||||||
pub const BUSTYPE_CBUSII: &'static [u8; 7usize] = b"CBUSII\x00";
|
|
||||||
pub const BUSTYPE_FUTURE: &'static [u8; 7usize] = b"FUTURE\x00";
|
|
||||||
pub const BUSTYPE_MBI: &'static [u8; 4usize] = b"MBI\x00";
|
|
||||||
pub const BUSTYPE_MBII: &'static [u8; 5usize] = b"MBII\x00";
|
|
||||||
pub const BUSTYPE_MPI: &'static [u8; 4usize] = b"MPI\x00";
|
|
||||||
pub const BUSTYPE_MPSA: &'static [u8; 5usize] = b"MPSA\x00";
|
|
||||||
pub const BUSTYPE_NUBUS: &'static [u8; 6usize] = b"NUBUS\x00";
|
|
||||||
pub const BUSTYPE_TC: &'static [u8; 3usize] = b"TC\x00";
|
|
||||||
pub const BUSTYPE_VME: &'static [u8; 4usize] = b"VME\x00";
|
|
||||||
pub const BUSTYPE_XPRESS: &'static [u8; 7usize] = b"XPRESS\x00";
|
|
||||||
pub const MPC_APIC_USABLE: ::std::os::raw::c_uint = 1;
|
|
||||||
pub const MP_IRQDIR_DEFAULT: ::std::os::raw::c_uint = 0;
|
|
||||||
pub const MP_IRQDIR_HIGH: ::std::os::raw::c_uint = 1;
|
|
||||||
pub const MP_IRQDIR_LOW: ::std::os::raw::c_uint = 3;
|
|
||||||
pub const MP_APIC_ALL: ::std::os::raw::c_uint = 255;
|
|
||||||
pub const MPC_OEM_SIGNATURE: &'static [u8; 5usize] = b"_OEM\x00";
|
|
||||||
#[repr(C)]
|
|
||||||
#[derive(Debug, Default, Copy)]
|
|
||||||
pub struct mpf_intel {
|
|
||||||
pub signature: [::std::os::raw::c_char; 4usize],
|
|
||||||
pub physptr: ::std::os::raw::c_uint,
|
|
||||||
pub length: ::std::os::raw::c_uchar,
|
|
||||||
pub specification: ::std::os::raw::c_uchar,
|
|
||||||
pub checksum: ::std::os::raw::c_uchar,
|
|
||||||
pub feature1: ::std::os::raw::c_uchar,
|
|
||||||
pub feature2: ::std::os::raw::c_uchar,
|
|
||||||
pub feature3: ::std::os::raw::c_uchar,
|
|
||||||
pub feature4: ::std::os::raw::c_uchar,
|
|
||||||
pub feature5: ::std::os::raw::c_uchar,
|
|
||||||
}
|
|
||||||
#[test]
|
|
||||||
fn bindgen_test_layout_mpf_intel() {
|
|
||||||
assert_eq!(
|
|
||||||
::std::mem::size_of::<mpf_intel>(),
|
|
||||||
16usize,
|
|
||||||
concat!("Size of: ", stringify!(mpf_intel))
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
::std::mem::align_of::<mpf_intel>(),
|
|
||||||
4usize,
|
|
||||||
concat!("Alignment of ", stringify!(mpf_intel))
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
unsafe { &(*std::ptr::null::<mpf_intel>()).signature as *const _ as usize },
|
|
||||||
0usize,
|
|
||||||
concat!(
|
|
||||||
"Alignment of field: ",
|
|
||||||
stringify!(mpf_intel),
|
|
||||||
"::",
|
|
||||||
stringify!(signature)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
unsafe { &(*std::ptr::null::<mpf_intel>()).physptr as *const _ as usize },
|
|
||||||
4usize,
|
|
||||||
concat!(
|
|
||||||
"Alignment of field: ",
|
|
||||||
stringify!(mpf_intel),
|
|
||||||
"::",
|
|
||||||
stringify!(physptr)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
unsafe { &(*std::ptr::null::<mpf_intel>()).length as *const _ as usize },
|
|
||||||
8usize,
|
|
||||||
concat!(
|
|
||||||
"Alignment of field: ",
|
|
||||||
stringify!(mpf_intel),
|
|
||||||
"::",
|
|
||||||
stringify!(length)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
unsafe { &(*std::ptr::null::<mpf_intel>()).specification as *const _ as usize },
|
|
||||||
9usize,
|
|
||||||
concat!(
|
|
||||||
"Alignment of field: ",
|
|
||||||
stringify!(mpf_intel),
|
|
||||||
"::",
|
|
||||||
stringify!(specification)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
unsafe { &(*std::ptr::null::<mpf_intel>()).checksum as *const _ as usize },
|
|
||||||
10usize,
|
|
||||||
concat!(
|
|
||||||
"Alignment of field: ",
|
|
||||||
stringify!(mpf_intel),
|
|
||||||
"::",
|
|
||||||
stringify!(checksum)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
unsafe { &(*std::ptr::null::<mpf_intel>()).feature1 as *const _ as usize },
|
|
||||||
11usize,
|
|
||||||
concat!(
|
|
||||||
"Alignment of field: ",
|
|
||||||
stringify!(mpf_intel),
|
|
||||||
"::",
|
|
||||||
stringify!(feature1)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
unsafe { &(*std::ptr::null::<mpf_intel>()).feature2 as *const _ as usize },
|
|
||||||
12usize,
|
|
||||||
concat!(
|
|
||||||
"Alignment of field: ",
|
|
||||||
stringify!(mpf_intel),
|
|
||||||
"::",
|
|
||||||
stringify!(feature2)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
unsafe { &(*std::ptr::null::<mpf_intel>()).feature3 as *const _ as usize },
|
|
||||||
13usize,
|
|
||||||
concat!(
|
|
||||||
"Alignment of field: ",
|
|
||||||
stringify!(mpf_intel),
|
|
||||||
"::",
|
|
||||||
stringify!(feature3)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
unsafe { &(*std::ptr::null::<mpf_intel>()).feature4 as *const _ as usize },
|
|
||||||
14usize,
|
|
||||||
concat!(
|
|
||||||
"Alignment of field: ",
|
|
||||||
stringify!(mpf_intel),
|
|
||||||
"::",
|
|
||||||
stringify!(feature4)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
unsafe { &(*std::ptr::null::<mpf_intel>()).feature5 as *const _ as usize },
|
|
||||||
15usize,
|
|
||||||
concat!(
|
|
||||||
"Alignment of field: ",
|
|
||||||
stringify!(mpf_intel),
|
|
||||||
"::",
|
|
||||||
stringify!(feature5)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
impl Clone for mpf_intel {
|
|
||||||
fn clone(&self) -> Self {
|
|
||||||
*self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#[repr(C)]
|
|
||||||
#[derive(Debug, Default, Copy)]
|
|
||||||
pub struct mpc_table {
|
|
||||||
pub signature: [::std::os::raw::c_char; 4usize],
|
|
||||||
pub length: ::std::os::raw::c_ushort,
|
|
||||||
pub spec: ::std::os::raw::c_char,
|
|
||||||
pub checksum: ::std::os::raw::c_char,
|
|
||||||
pub oem: [::std::os::raw::c_char; 8usize],
|
|
||||||
pub productid: [::std::os::raw::c_char; 12usize],
|
|
||||||
pub oemptr: ::std::os::raw::c_uint,
|
|
||||||
pub oemsize: ::std::os::raw::c_ushort,
|
|
||||||
pub oemcount: ::std::os::raw::c_ushort,
|
|
||||||
pub lapic: ::std::os::raw::c_uint,
|
|
||||||
pub reserved: ::std::os::raw::c_uint,
|
|
||||||
}
|
|
||||||
#[test]
|
|
||||||
fn bindgen_test_layout_mpc_table() {
|
|
||||||
assert_eq!(
|
|
||||||
::std::mem::size_of::<mpc_table>(),
|
|
||||||
44usize,
|
|
||||||
concat!("Size of: ", stringify!(mpc_table))
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
::std::mem::align_of::<mpc_table>(),
|
|
||||||
4usize,
|
|
||||||
concat!("Alignment of ", stringify!(mpc_table))
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
unsafe { &(*std::ptr::null::<mpc_table>()).signature as *const _ as usize },
|
|
||||||
0usize,
|
|
||||||
concat!(
|
|
||||||
"Alignment of field: ",
|
|
||||||
stringify!(mpc_table),
|
|
||||||
"::",
|
|
||||||
stringify!(signature)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
unsafe { &(*std::ptr::null::<mpc_table>()).length as *const _ as usize },
|
|
||||||
4usize,
|
|
||||||
concat!(
|
|
||||||
"Alignment of field: ",
|
|
||||||
stringify!(mpc_table),
|
|
||||||
"::",
|
|
||||||
stringify!(length)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
unsafe { &(*std::ptr::null::<mpc_table>()).spec as *const _ as usize },
|
|
||||||
6usize,
|
|
||||||
concat!(
|
|
||||||
"Alignment of field: ",
|
|
||||||
stringify!(mpc_table),
|
|
||||||
"::",
|
|
||||||
stringify!(spec)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
unsafe { &(*std::ptr::null::<mpc_table>()).checksum as *const _ as usize },
|
|
||||||
7usize,
|
|
||||||
concat!(
|
|
||||||
"Alignment of field: ",
|
|
||||||
stringify!(mpc_table),
|
|
||||||
"::",
|
|
||||||
stringify!(checksum)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
unsafe { &(*std::ptr::null::<mpc_table>()).oem as *const _ as usize },
|
|
||||||
8usize,
|
|
||||||
concat!(
|
|
||||||
"Alignment of field: ",
|
|
||||||
stringify!(mpc_table),
|
|
||||||
"::",
|
|
||||||
stringify!(oem)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
unsafe { &(*std::ptr::null::<mpc_table>()).productid as *const _ as usize },
|
|
||||||
16usize,
|
|
||||||
concat!(
|
|
||||||
"Alignment of field: ",
|
|
||||||
stringify!(mpc_table),
|
|
||||||
"::",
|
|
||||||
stringify!(productid)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
unsafe { &(*std::ptr::null::<mpc_table>()).oemptr as *const _ as usize },
|
|
||||||
28usize,
|
|
||||||
concat!(
|
|
||||||
"Alignment of field: ",
|
|
||||||
stringify!(mpc_table),
|
|
||||||
"::",
|
|
||||||
stringify!(oemptr)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
unsafe { &(*std::ptr::null::<mpc_table>()).oemsize as *const _ as usize },
|
|
||||||
32usize,
|
|
||||||
concat!(
|
|
||||||
"Alignment of field: ",
|
|
||||||
stringify!(mpc_table),
|
|
||||||
"::",
|
|
||||||
stringify!(oemsize)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
unsafe { &(*std::ptr::null::<mpc_table>()).oemcount as *const _ as usize },
|
|
||||||
34usize,
|
|
||||||
concat!(
|
|
||||||
"Alignment of field: ",
|
|
||||||
stringify!(mpc_table),
|
|
||||||
"::",
|
|
||||||
stringify!(oemcount)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
unsafe { &(*std::ptr::null::<mpc_table>()).lapic as *const _ as usize },
|
|
||||||
36usize,
|
|
||||||
concat!(
|
|
||||||
"Alignment of field: ",
|
|
||||||
stringify!(mpc_table),
|
|
||||||
"::",
|
|
||||||
stringify!(lapic)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
unsafe { &(*std::ptr::null::<mpc_table>()).reserved as *const _ as usize },
|
|
||||||
40usize,
|
|
||||||
concat!(
|
|
||||||
"Alignment of field: ",
|
|
||||||
stringify!(mpc_table),
|
|
||||||
"::",
|
|
||||||
stringify!(reserved)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
impl Clone for mpc_table {
|
|
||||||
fn clone(&self) -> Self {
|
|
||||||
*self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#[repr(C)]
|
|
||||||
#[derive(Debug, Default, Copy)]
|
|
||||||
pub struct mpc_cpu {
|
|
||||||
pub type_: ::std::os::raw::c_uchar,
|
|
||||||
pub apicid: ::std::os::raw::c_uchar,
|
|
||||||
pub apicver: ::std::os::raw::c_uchar,
|
|
||||||
pub cpuflag: ::std::os::raw::c_uchar,
|
|
||||||
pub cpufeature: ::std::os::raw::c_uint,
|
|
||||||
pub featureflag: ::std::os::raw::c_uint,
|
|
||||||
pub reserved: [::std::os::raw::c_uint; 2usize],
|
|
||||||
}
|
|
||||||
#[test]
|
|
||||||
fn bindgen_test_layout_mpc_cpu() {
|
|
||||||
assert_eq!(
|
|
||||||
::std::mem::size_of::<mpc_cpu>(),
|
|
||||||
20usize,
|
|
||||||
concat!("Size of: ", stringify!(mpc_cpu))
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
::std::mem::align_of::<mpc_cpu>(),
|
|
||||||
4usize,
|
|
||||||
concat!("Alignment of ", stringify!(mpc_cpu))
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
unsafe { &(*std::ptr::null::<mpc_cpu>()).type_ as *const _ as usize },
|
|
||||||
0usize,
|
|
||||||
concat!(
|
|
||||||
"Alignment of field: ",
|
|
||||||
stringify!(mpc_cpu),
|
|
||||||
"::",
|
|
||||||
stringify!(type_)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
unsafe { &(*std::ptr::null::<mpc_cpu>()).apicid as *const _ as usize },
|
|
||||||
1usize,
|
|
||||||
concat!(
|
|
||||||
"Alignment of field: ",
|
|
||||||
stringify!(mpc_cpu),
|
|
||||||
"::",
|
|
||||||
stringify!(apicid)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
unsafe { &(*std::ptr::null::<mpc_cpu>()).apicver as *const _ as usize },
|
|
||||||
2usize,
|
|
||||||
concat!(
|
|
||||||
"Alignment of field: ",
|
|
||||||
stringify!(mpc_cpu),
|
|
||||||
"::",
|
|
||||||
stringify!(apicver)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
unsafe { &(*std::ptr::null::<mpc_cpu>()).cpuflag as *const _ as usize },
|
|
||||||
3usize,
|
|
||||||
concat!(
|
|
||||||
"Alignment of field: ",
|
|
||||||
stringify!(mpc_cpu),
|
|
||||||
"::",
|
|
||||||
stringify!(cpuflag)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
unsafe { &(*std::ptr::null::<mpc_cpu>()).cpufeature as *const _ as usize },
|
|
||||||
4usize,
|
|
||||||
concat!(
|
|
||||||
"Alignment of field: ",
|
|
||||||
stringify!(mpc_cpu),
|
|
||||||
"::",
|
|
||||||
stringify!(cpufeature)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
unsafe { &(*std::ptr::null::<mpc_cpu>()).featureflag as *const _ as usize },
|
|
||||||
8usize,
|
|
||||||
concat!(
|
|
||||||
"Alignment of field: ",
|
|
||||||
stringify!(mpc_cpu),
|
|
||||||
"::",
|
|
||||||
stringify!(featureflag)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
unsafe { &(*std::ptr::null::<mpc_cpu>()).reserved as *const _ as usize },
|
|
||||||
12usize,
|
|
||||||
concat!(
|
|
||||||
"Alignment of field: ",
|
|
||||||
stringify!(mpc_cpu),
|
|
||||||
"::",
|
|
||||||
stringify!(reserved)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
impl Clone for mpc_cpu {
|
|
||||||
fn clone(&self) -> Self {
|
|
||||||
*self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#[repr(C)]
|
|
||||||
#[derive(Debug, Default, Copy)]
|
|
||||||
pub struct mpc_bus {
|
|
||||||
pub type_: ::std::os::raw::c_uchar,
|
|
||||||
pub busid: ::std::os::raw::c_uchar,
|
|
||||||
pub bustype: [::std::os::raw::c_uchar; 6usize],
|
|
||||||
}
|
|
||||||
#[test]
|
|
||||||
fn bindgen_test_layout_mpc_bus() {
|
|
||||||
assert_eq!(
|
|
||||||
::std::mem::size_of::<mpc_bus>(),
|
|
||||||
8usize,
|
|
||||||
concat!("Size of: ", stringify!(mpc_bus))
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
::std::mem::align_of::<mpc_bus>(),
|
|
||||||
1usize,
|
|
||||||
concat!("Alignment of ", stringify!(mpc_bus))
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
unsafe { &(*std::ptr::null::<mpc_bus>()).type_ as *const _ as usize },
|
|
||||||
0usize,
|
|
||||||
concat!(
|
|
||||||
"Alignment of field: ",
|
|
||||||
stringify!(mpc_bus),
|
|
||||||
"::",
|
|
||||||
stringify!(type_)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
unsafe { &(*std::ptr::null::<mpc_bus>()).busid as *const _ as usize },
|
|
||||||
1usize,
|
|
||||||
concat!(
|
|
||||||
"Alignment of field: ",
|
|
||||||
stringify!(mpc_bus),
|
|
||||||
"::",
|
|
||||||
stringify!(busid)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
unsafe { &(*std::ptr::null::<mpc_bus>()).bustype as *const _ as usize },
|
|
||||||
2usize,
|
|
||||||
concat!(
|
|
||||||
"Alignment of field: ",
|
|
||||||
stringify!(mpc_bus),
|
|
||||||
"::",
|
|
||||||
stringify!(bustype)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
impl Clone for mpc_bus {
|
|
||||||
fn clone(&self) -> Self {
|
|
||||||
*self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#[repr(C)]
|
|
||||||
#[derive(Debug, Default, Copy)]
|
|
||||||
pub struct mpc_ioapic {
|
|
||||||
pub type_: ::std::os::raw::c_uchar,
|
|
||||||
pub apicid: ::std::os::raw::c_uchar,
|
|
||||||
pub apicver: ::std::os::raw::c_uchar,
|
|
||||||
pub flags: ::std::os::raw::c_uchar,
|
|
||||||
pub apicaddr: ::std::os::raw::c_uint,
|
|
||||||
}
|
|
||||||
#[test]
|
|
||||||
fn bindgen_test_layout_mpc_ioapic() {
|
|
||||||
assert_eq!(
|
|
||||||
::std::mem::size_of::<mpc_ioapic>(),
|
|
||||||
8usize,
|
|
||||||
concat!("Size of: ", stringify!(mpc_ioapic))
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
::std::mem::align_of::<mpc_ioapic>(),
|
|
||||||
4usize,
|
|
||||||
concat!("Alignment of ", stringify!(mpc_ioapic))
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
unsafe { &(*std::ptr::null::<mpc_ioapic>()).type_ as *const _ as usize },
|
|
||||||
0usize,
|
|
||||||
concat!(
|
|
||||||
"Alignment of field: ",
|
|
||||||
stringify!(mpc_ioapic),
|
|
||||||
"::",
|
|
||||||
stringify!(type_)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
unsafe { &(*std::ptr::null::<mpc_ioapic>()).apicid as *const _ as usize },
|
|
||||||
1usize,
|
|
||||||
concat!(
|
|
||||||
"Alignment of field: ",
|
|
||||||
stringify!(mpc_ioapic),
|
|
||||||
"::",
|
|
||||||
stringify!(apicid)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
unsafe { &(*std::ptr::null::<mpc_ioapic>()).apicver as *const _ as usize },
|
|
||||||
2usize,
|
|
||||||
concat!(
|
|
||||||
"Alignment of field: ",
|
|
||||||
stringify!(mpc_ioapic),
|
|
||||||
"::",
|
|
||||||
stringify!(apicver)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
unsafe { &(*std::ptr::null::<mpc_ioapic>()).flags as *const _ as usize },
|
|
||||||
3usize,
|
|
||||||
concat!(
|
|
||||||
"Alignment of field: ",
|
|
||||||
stringify!(mpc_ioapic),
|
|
||||||
"::",
|
|
||||||
stringify!(flags)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
unsafe { &(*std::ptr::null::<mpc_ioapic>()).apicaddr as *const _ as usize },
|
|
||||||
4usize,
|
|
||||||
concat!(
|
|
||||||
"Alignment of field: ",
|
|
||||||
stringify!(mpc_ioapic),
|
|
||||||
"::",
|
|
||||||
stringify!(apicaddr)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
impl Clone for mpc_ioapic {
|
|
||||||
fn clone(&self) -> Self {
|
|
||||||
*self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#[repr(C)]
|
|
||||||
#[derive(Debug, Default, Copy)]
|
|
||||||
pub struct mpc_intsrc {
|
|
||||||
pub type_: ::std::os::raw::c_uchar,
|
|
||||||
pub irqtype: ::std::os::raw::c_uchar,
|
|
||||||
pub irqflag: ::std::os::raw::c_ushort,
|
|
||||||
pub srcbus: ::std::os::raw::c_uchar,
|
|
||||||
pub srcbusirq: ::std::os::raw::c_uchar,
|
|
||||||
pub dstapic: ::std::os::raw::c_uchar,
|
|
||||||
pub dstirq: ::std::os::raw::c_uchar,
|
|
||||||
}
|
|
||||||
#[test]
|
|
||||||
fn bindgen_test_layout_mpc_intsrc() {
|
|
||||||
assert_eq!(
|
|
||||||
::std::mem::size_of::<mpc_intsrc>(),
|
|
||||||
8usize,
|
|
||||||
concat!("Size of: ", stringify!(mpc_intsrc))
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
::std::mem::align_of::<mpc_intsrc>(),
|
|
||||||
2usize,
|
|
||||||
concat!("Alignment of ", stringify!(mpc_intsrc))
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
unsafe { &(*std::ptr::null::<mpc_intsrc>()).type_ as *const _ as usize },
|
|
||||||
0usize,
|
|
||||||
concat!(
|
|
||||||
"Alignment of field: ",
|
|
||||||
stringify!(mpc_intsrc),
|
|
||||||
"::",
|
|
||||||
stringify!(type_)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
unsafe { &(*std::ptr::null::<mpc_intsrc>()).irqtype as *const _ as usize },
|
|
||||||
1usize,
|
|
||||||
concat!(
|
|
||||||
"Alignment of field: ",
|
|
||||||
stringify!(mpc_intsrc),
|
|
||||||
"::",
|
|
||||||
stringify!(irqtype)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
unsafe { &(*std::ptr::null::<mpc_intsrc>()).irqflag as *const _ as usize },
|
|
||||||
2usize,
|
|
||||||
concat!(
|
|
||||||
"Alignment of field: ",
|
|
||||||
stringify!(mpc_intsrc),
|
|
||||||
"::",
|
|
||||||
stringify!(irqflag)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
unsafe { &(*std::ptr::null::<mpc_intsrc>()).srcbus as *const _ as usize },
|
|
||||||
4usize,
|
|
||||||
concat!(
|
|
||||||
"Alignment of field: ",
|
|
||||||
stringify!(mpc_intsrc),
|
|
||||||
"::",
|
|
||||||
stringify!(srcbus)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
unsafe { &(*std::ptr::null::<mpc_intsrc>()).srcbusirq as *const _ as usize },
|
|
||||||
5usize,
|
|
||||||
concat!(
|
|
||||||
"Alignment of field: ",
|
|
||||||
stringify!(mpc_intsrc),
|
|
||||||
"::",
|
|
||||||
stringify!(srcbusirq)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
unsafe { &(*std::ptr::null::<mpc_intsrc>()).dstapic as *const _ as usize },
|
|
||||||
6usize,
|
|
||||||
concat!(
|
|
||||||
"Alignment of field: ",
|
|
||||||
stringify!(mpc_intsrc),
|
|
||||||
"::",
|
|
||||||
stringify!(dstapic)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
unsafe { &(*std::ptr::null::<mpc_intsrc>()).dstirq as *const _ as usize },
|
|
||||||
7usize,
|
|
||||||
concat!(
|
|
||||||
"Alignment of field: ",
|
|
||||||
stringify!(mpc_intsrc),
|
|
||||||
"::",
|
|
||||||
stringify!(dstirq)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
impl Clone for mpc_intsrc {
|
|
||||||
fn clone(&self) -> Self {
|
|
||||||
*self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub const mp_irq_source_types_mp_INT: mp_irq_source_types = 0;
|
|
||||||
pub const mp_irq_source_types_mp_NMI: mp_irq_source_types = 1;
|
|
||||||
pub const mp_irq_source_types_mp_SMI: mp_irq_source_types = 2;
|
|
||||||
pub const mp_irq_source_types_mp_ExtINT: mp_irq_source_types = 3;
|
|
||||||
pub type mp_irq_source_types = ::std::os::raw::c_uint;
|
|
||||||
#[repr(C)]
|
|
||||||
#[derive(Debug, Default, Copy)]
|
|
||||||
pub struct mpc_lintsrc {
|
|
||||||
pub type_: ::std::os::raw::c_uchar,
|
|
||||||
pub irqtype: ::std::os::raw::c_uchar,
|
|
||||||
pub irqflag: ::std::os::raw::c_ushort,
|
|
||||||
pub srcbusid: ::std::os::raw::c_uchar,
|
|
||||||
pub srcbusirq: ::std::os::raw::c_uchar,
|
|
||||||
pub destapic: ::std::os::raw::c_uchar,
|
|
||||||
pub destapiclint: ::std::os::raw::c_uchar,
|
|
||||||
}
|
|
||||||
#[test]
|
|
||||||
fn bindgen_test_layout_mpc_lintsrc() {
|
|
||||||
assert_eq!(
|
|
||||||
::std::mem::size_of::<mpc_lintsrc>(),
|
|
||||||
8usize,
|
|
||||||
concat!("Size of: ", stringify!(mpc_lintsrc))
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
::std::mem::align_of::<mpc_lintsrc>(),
|
|
||||||
2usize,
|
|
||||||
concat!("Alignment of ", stringify!(mpc_lintsrc))
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
unsafe { &(*std::ptr::null::<mpc_lintsrc>()).type_ as *const _ as usize },
|
|
||||||
0usize,
|
|
||||||
concat!(
|
|
||||||
"Alignment of field: ",
|
|
||||||
stringify!(mpc_lintsrc),
|
|
||||||
"::",
|
|
||||||
stringify!(type_)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
unsafe { &(*std::ptr::null::<mpc_lintsrc>()).irqtype as *const _ as usize },
|
|
||||||
1usize,
|
|
||||||
concat!(
|
|
||||||
"Alignment of field: ",
|
|
||||||
stringify!(mpc_lintsrc),
|
|
||||||
"::",
|
|
||||||
stringify!(irqtype)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
unsafe { &(*std::ptr::null::<mpc_lintsrc>()).irqflag as *const _ as usize },
|
|
||||||
2usize,
|
|
||||||
concat!(
|
|
||||||
"Alignment of field: ",
|
|
||||||
stringify!(mpc_lintsrc),
|
|
||||||
"::",
|
|
||||||
stringify!(irqflag)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
unsafe { &(*std::ptr::null::<mpc_lintsrc>()).srcbusid as *const _ as usize },
|
|
||||||
4usize,
|
|
||||||
concat!(
|
|
||||||
"Alignment of field: ",
|
|
||||||
stringify!(mpc_lintsrc),
|
|
||||||
"::",
|
|
||||||
stringify!(srcbusid)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
unsafe { &(*std::ptr::null::<mpc_lintsrc>()).srcbusirq as *const _ as usize },
|
|
||||||
5usize,
|
|
||||||
concat!(
|
|
||||||
"Alignment of field: ",
|
|
||||||
stringify!(mpc_lintsrc),
|
|
||||||
"::",
|
|
||||||
stringify!(srcbusirq)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
unsafe { &(*std::ptr::null::<mpc_lintsrc>()).destapic as *const _ as usize },
|
|
||||||
6usize,
|
|
||||||
concat!(
|
|
||||||
"Alignment of field: ",
|
|
||||||
stringify!(mpc_lintsrc),
|
|
||||||
"::",
|
|
||||||
stringify!(destapic)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
unsafe { &(*std::ptr::null::<mpc_lintsrc>()).destapiclint as *const _ as usize },
|
|
||||||
7usize,
|
|
||||||
concat!(
|
|
||||||
"Alignment of field: ",
|
|
||||||
stringify!(mpc_lintsrc),
|
|
||||||
"::",
|
|
||||||
stringify!(destapiclint)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
impl Clone for mpc_lintsrc {
|
|
||||||
fn clone(&self) -> Self {
|
|
||||||
*self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#[repr(C)]
|
|
||||||
#[derive(Debug, Default, Copy)]
|
|
||||||
pub struct mpc_oemtable {
|
|
||||||
pub signature: [::std::os::raw::c_char; 4usize],
|
|
||||||
pub length: ::std::os::raw::c_ushort,
|
|
||||||
pub rev: ::std::os::raw::c_char,
|
|
||||||
pub checksum: ::std::os::raw::c_char,
|
|
||||||
pub mpc: [::std::os::raw::c_char; 8usize],
|
|
||||||
}
|
|
||||||
#[test]
|
|
||||||
fn bindgen_test_layout_mpc_oemtable() {
|
|
||||||
assert_eq!(
|
|
||||||
::std::mem::size_of::<mpc_oemtable>(),
|
|
||||||
16usize,
|
|
||||||
concat!("Size of: ", stringify!(mpc_oemtable))
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
::std::mem::align_of::<mpc_oemtable>(),
|
|
||||||
2usize,
|
|
||||||
concat!("Alignment of ", stringify!(mpc_oemtable))
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
unsafe { &(*std::ptr::null::<mpc_oemtable>()).signature as *const _ as usize },
|
|
||||||
0usize,
|
|
||||||
concat!(
|
|
||||||
"Alignment of field: ",
|
|
||||||
stringify!(mpc_oemtable),
|
|
||||||
"::",
|
|
||||||
stringify!(signature)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
unsafe { &(*std::ptr::null::<mpc_oemtable>()).length as *const _ as usize },
|
|
||||||
4usize,
|
|
||||||
concat!(
|
|
||||||
"Alignment of field: ",
|
|
||||||
stringify!(mpc_oemtable),
|
|
||||||
"::",
|
|
||||||
stringify!(length)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
unsafe { &(*std::ptr::null::<mpc_oemtable>()).rev as *const _ as usize },
|
|
||||||
6usize,
|
|
||||||
concat!(
|
|
||||||
"Alignment of field: ",
|
|
||||||
stringify!(mpc_oemtable),
|
|
||||||
"::",
|
|
||||||
stringify!(rev)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
unsafe { &(*std::ptr::null::<mpc_oemtable>()).checksum as *const _ as usize },
|
|
||||||
7usize,
|
|
||||||
concat!(
|
|
||||||
"Alignment of field: ",
|
|
||||||
stringify!(mpc_oemtable),
|
|
||||||
"::",
|
|
||||||
stringify!(checksum)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
unsafe { &(*std::ptr::null::<mpc_oemtable>()).mpc as *const _ as usize },
|
|
||||||
8usize,
|
|
||||||
concat!(
|
|
||||||
"Alignment of field: ",
|
|
||||||
stringify!(mpc_oemtable),
|
|
||||||
"::",
|
|
||||||
stringify!(mpc)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
impl Clone for mpc_oemtable {
|
|
||||||
fn clone(&self) -> Self {
|
|
||||||
*self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub const mp_bustype_MP_BUS_ISA: mp_bustype = 1;
|
|
||||||
pub const mp_bustype_MP_BUS_EISA: mp_bustype = 2;
|
|
||||||
pub const mp_bustype_MP_BUS_PCI: mp_bustype = 3;
|
|
||||||
pub type mp_bustype = ::std::os::raw::c_uint;
|
|
||||||
@@ -9,16 +9,16 @@ default = []
|
|||||||
io_uring = []
|
io_uring = []
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
io-uring = ">=0.4.0"
|
io-uring = "0.5.2"
|
||||||
libc = "0.2.94"
|
libc = "0.2.103"
|
||||||
log = "0.4.14"
|
log = "0.4.14"
|
||||||
qcow = { path = "../qcow" }
|
qcow = { path = "../qcow" }
|
||||||
serde = ">=1.0.27"
|
thiserror = "1.0.30"
|
||||||
serde_derive = ">=1.0.27"
|
versionize = "0.1.6"
|
||||||
serde_json = ">=1.0.9"
|
versionize_derive = "0.1.4"
|
||||||
thiserror = "1.0"
|
vhdx = { path = "../vhdx" }
|
||||||
virtio-bindings = { version = "0.1", features = ["virtio-v5_0_0"]}
|
virtio-bindings = { version = "0.1.0", features = ["virtio-v5_0_0"] }
|
||||||
vm-memory = { version = "0.5.0", features = ["backend-mmap", "backend-atomic"] }
|
vm-memory = { version = "0.6.0", features = ["backend-mmap", "backend-atomic", "backend-bitmap"] }
|
||||||
vm-virtio = { path = "../vm-virtio" }
|
vm-virtio = { path = "../vm-virtio" }
|
||||||
vmm-sys-util = ">=0.3.1"
|
vmm-sys-util = "0.9.0"
|
||||||
|
|
||||||
|
|||||||
@@ -10,8 +10,6 @@
|
|||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate log;
|
extern crate log;
|
||||||
#[macro_use]
|
|
||||||
extern crate serde_derive;
|
|
||||||
|
|
||||||
pub mod async_io;
|
pub mod async_io;
|
||||||
pub mod fixed_vhd_async;
|
pub mod fixed_vhd_async;
|
||||||
@@ -20,6 +18,7 @@ pub mod qcow_sync;
|
|||||||
pub mod raw_async;
|
pub mod raw_async;
|
||||||
pub mod raw_sync;
|
pub mod raw_sync;
|
||||||
pub mod vhd;
|
pub mod vhd;
|
||||||
|
pub mod vhdx_sync;
|
||||||
|
|
||||||
use crate::async_io::{AsyncIo, AsyncIoError, AsyncIoResult, DiskFileError, DiskFileResult};
|
use crate::async_io::{AsyncIo, AsyncIoError, AsyncIoResult, DiskFileError, DiskFileResult};
|
||||||
#[cfg(feature = "io_uring")]
|
#[cfg(feature = "io_uring")]
|
||||||
@@ -34,11 +33,18 @@ use std::os::unix::io::AsRawFd;
|
|||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::result;
|
use std::result;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
|
use versionize::{VersionMap, Versionize, VersionizeResult};
|
||||||
|
use versionize_derive::Versionize;
|
||||||
use virtio_bindings::bindings::virtio_blk::*;
|
use virtio_bindings::bindings::virtio_blk::*;
|
||||||
use vm_memory::{ByteValued, Bytes, GuestAddress, GuestMemory, GuestMemoryError, GuestMemoryMmap};
|
use vm_memory::{
|
||||||
|
bitmap::AtomicBitmap, bitmap::Bitmap, ByteValued, Bytes, GuestAddress, GuestMemory,
|
||||||
|
GuestMemoryError,
|
||||||
|
};
|
||||||
use vm_virtio::DescriptorChain;
|
use vm_virtio::DescriptorChain;
|
||||||
use vmm_sys_util::eventfd::EventFd;
|
use vmm_sys_util::eventfd::EventFd;
|
||||||
|
|
||||||
|
type GuestMemoryMmap = vm_memory::GuestMemoryMmap<AtomicBitmap>;
|
||||||
|
|
||||||
const SECTOR_SHIFT: u8 = 9;
|
const SECTOR_SHIFT: u8 = 9;
|
||||||
pub const SECTOR_SIZE: u64 = 0x01 << SECTOR_SHIFT;
|
pub const SECTOR_SIZE: u64 = 0x01 << SECTOR_SHIFT;
|
||||||
|
|
||||||
@@ -182,8 +188,8 @@ impl Request {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let mut req = Request {
|
let mut req = Request {
|
||||||
request_type: request_type(&mem, avail_desc.addr)?,
|
request_type: request_type(mem, avail_desc.addr)?,
|
||||||
sector: sector(&mem, avail_desc.addr)?,
|
sector: sector(mem, avail_desc.addr)?,
|
||||||
data_descriptors: Vec::new(),
|
data_descriptors: Vec::new(),
|
||||||
status_addr: GuestAddress(0),
|
status_addr: GuestAddress(0),
|
||||||
writeback: true,
|
writeback: true,
|
||||||
@@ -283,7 +289,7 @@ impl Request {
|
|||||||
if (*data_len as usize) < disk_id.len() {
|
if (*data_len as usize) < disk_id.len() {
|
||||||
return Err(ExecuteError::BadRequest(Error::InvalidOffset));
|
return Err(ExecuteError::BadRequest(Error::InvalidOffset));
|
||||||
}
|
}
|
||||||
mem.write_slice(&disk_id.as_slice(), *data_addr)
|
mem.write_slice(disk_id.as_slice(), *data_addr)
|
||||||
.map_err(ExecuteError::Write)?;
|
.map_err(ExecuteError::Write)?;
|
||||||
}
|
}
|
||||||
RequestType::Unsupported(t) => return Err(ExecuteError::Unsupported(t)),
|
RequestType::Unsupported(t) => return Err(ExecuteError::Unsupported(t)),
|
||||||
@@ -331,6 +337,12 @@ impl Request {
|
|||||||
// Queue operations expected to be submitted.
|
// Queue operations expected to be submitted.
|
||||||
match request_type {
|
match request_type {
|
||||||
RequestType::In => {
|
RequestType::In => {
|
||||||
|
for (data_addr, data_len) in &self.data_descriptors {
|
||||||
|
mem.get_slice(*data_addr, *data_len as usize)
|
||||||
|
.map_err(ExecuteError::GetHostAddress)?
|
||||||
|
.bitmap()
|
||||||
|
.mark_dirty(0, *data_len as usize);
|
||||||
|
}
|
||||||
disk_image
|
disk_image
|
||||||
.read_vectored(offset, iovecs, user_data)
|
.read_vectored(offset, iovecs, user_data)
|
||||||
.map_err(ExecuteError::AsyncRead)?;
|
.map_err(ExecuteError::AsyncRead)?;
|
||||||
@@ -369,7 +381,7 @@ impl Request {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, Default, Deserialize, Serialize)]
|
#[derive(Copy, Clone, Debug, Default, Versionize)]
|
||||||
#[repr(C, packed)]
|
#[repr(C, packed)]
|
||||||
pub struct VirtioBlockConfig {
|
pub struct VirtioBlockConfig {
|
||||||
pub capacity: u64,
|
pub capacity: u64,
|
||||||
@@ -394,7 +406,7 @@ pub struct VirtioBlockConfig {
|
|||||||
}
|
}
|
||||||
unsafe impl ByteValued for VirtioBlockConfig {}
|
unsafe impl ByteValued for VirtioBlockConfig {}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, Default, Serialize, Deserialize)]
|
#[derive(Copy, Clone, Debug, Default, Versionize)]
|
||||||
#[repr(C, packed)]
|
#[repr(C, packed)]
|
||||||
pub struct VirtioBlockGeometry {
|
pub struct VirtioBlockGeometry {
|
||||||
pub cylinders: u16,
|
pub cylinders: u16,
|
||||||
@@ -591,9 +603,11 @@ pub enum ImageType {
|
|||||||
FixedVhd,
|
FixedVhd,
|
||||||
Qcow2,
|
Qcow2,
|
||||||
Raw,
|
Raw,
|
||||||
|
Vhdx,
|
||||||
}
|
}
|
||||||
|
|
||||||
const QCOW_MAGIC: u32 = 0x5146_49fb;
|
const QCOW_MAGIC: u32 = 0x5146_49fb;
|
||||||
|
const VHDX_SIGN: u64 = 0x656C_6966_7864_6876;
|
||||||
|
|
||||||
/// Determine image type through file parsing.
|
/// Determine image type through file parsing.
|
||||||
pub fn detect_image_type(f: &mut File) -> std::io::Result<ImageType> {
|
pub fn detect_image_type(f: &mut File) -> std::io::Result<ImageType> {
|
||||||
@@ -612,6 +626,8 @@ pub fn detect_image_type(f: &mut File) -> std::io::Result<ImageType> {
|
|||||||
ImageType::Qcow2
|
ImageType::Qcow2
|
||||||
} else if vhd::is_fixed_vhd(f)? {
|
} else if vhd::is_fixed_vhd(f)? {
|
||||||
ImageType::FixedVhd
|
ImageType::FixedVhd
|
||||||
|
} else if u64::from_le_bytes(s.data[0..8].try_into().unwrap()) == VHDX_SIGN {
|
||||||
|
ImageType::Vhdx
|
||||||
} else {
|
} else {
|
||||||
ImageType::Raw
|
ImageType::Raw
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
use crate::async_io::{AsyncIo, AsyncIoResult, DiskFile, DiskFileResult};
|
use crate::async_io::{AsyncIo, AsyncIoResult, DiskFile, DiskFileResult};
|
||||||
use crate::{disk_size, fsync_sync, read_vectored_sync, write_vectored_sync};
|
use crate::{disk_size, fsync_sync, read_vectored_sync, write_vectored_sync};
|
||||||
use qcow::{QcowFile, RawFile};
|
use qcow::{QcowFile, RawFile, Result as QcowResult};
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
use vmm_sys_util::eventfd::EventFd;
|
use vmm_sys_util::eventfd::EventFd;
|
||||||
@@ -15,12 +15,11 @@ pub struct QcowDiskSync {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl QcowDiskSync {
|
impl QcowDiskSync {
|
||||||
pub fn new(file: File, direct_io: bool) -> Self {
|
pub fn new(file: File, direct_io: bool) -> QcowResult<Self> {
|
||||||
QcowDiskSync {
|
Ok(QcowDiskSync {
|
||||||
qcow_file: QcowFile::from(RawFile::new(file, direct_io))
|
qcow_file: QcowFile::from(RawFile::new(file, direct_io))?,
|
||||||
.expect("Failed creating QcowFile"),
|
|
||||||
semaphore: Arc::new(Mutex::new(())),
|
semaphore: Arc::new(Mutex::new(())),
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -175,7 +175,7 @@ mod tests {
|
|||||||
let mut disk_file: File = TempFile::new().unwrap().into_file();
|
let mut disk_file: File = TempFile::new().unwrap().into_file();
|
||||||
disk_file.set_len(0x1000_0200).unwrap();
|
disk_file.set_len(0x1000_0200).unwrap();
|
||||||
disk_file.seek(SeekFrom::Start(0x1000_0000)).unwrap();
|
disk_file.seek(SeekFrom::Start(0x1000_0000)).unwrap();
|
||||||
disk_file.write_all(&footer).unwrap();
|
disk_file.write_all(footer).unwrap();
|
||||||
|
|
||||||
testfn(disk_file); // File closed when the function exits.
|
testfn(disk_file); // File closed when the function exits.
|
||||||
}
|
}
|
||||||
|
|||||||
113
block_util/src/vhdx_sync.rs
Normal file
113
block_util/src/vhdx_sync.rs
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
// Copyright © 2021 Intel Corporation
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
use crate::async_io::{AsyncIo, AsyncIoResult, DiskFile, DiskFileError, DiskFileResult};
|
||||||
|
use crate::{fsync_sync, read_vectored_sync, write_vectored_sync};
|
||||||
|
use std::fs::File;
|
||||||
|
use std::ops::DerefMut;
|
||||||
|
use std::sync::{Arc, Mutex};
|
||||||
|
use vhdx::vhdx::{Result as VhdxResult, Vhdx};
|
||||||
|
use vmm_sys_util::eventfd::EventFd;
|
||||||
|
|
||||||
|
pub struct VhdxDiskSync {
|
||||||
|
vhdx_file: Arc<Mutex<Vhdx>>,
|
||||||
|
semaphore: Arc<Mutex<()>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VhdxDiskSync {
|
||||||
|
pub fn new(f: File) -> VhdxResult<Self> {
|
||||||
|
let vhdx = Vhdx::new(f)?;
|
||||||
|
let vhdx_file = Arc::new(Mutex::new(vhdx));
|
||||||
|
|
||||||
|
Ok(VhdxDiskSync {
|
||||||
|
vhdx_file,
|
||||||
|
semaphore: Arc::new(Mutex::new(())),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DiskFile for VhdxDiskSync {
|
||||||
|
fn size(&mut self) -> DiskFileResult<u64> {
|
||||||
|
Ok(self.vhdx_file.lock().unwrap().virtual_disk_size())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new_async_io(&self, _ring_depth: u32) -> DiskFileResult<Box<dyn AsyncIo>> {
|
||||||
|
Ok(Box::new(
|
||||||
|
VhdxSync::new(self.vhdx_file.clone(), self.semaphore.clone())
|
||||||
|
.map_err(DiskFileError::NewAsyncIo)?,
|
||||||
|
) as Box<dyn AsyncIo>)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct VhdxSync {
|
||||||
|
vhdx_file: Arc<Mutex<Vhdx>>,
|
||||||
|
eventfd: EventFd,
|
||||||
|
completion_list: Vec<(u64, i32)>,
|
||||||
|
semaphore: Arc<Mutex<()>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VhdxSync {
|
||||||
|
pub fn new(vhdx_file: Arc<Mutex<Vhdx>>, semaphore: Arc<Mutex<()>>) -> std::io::Result<Self> {
|
||||||
|
Ok(VhdxSync {
|
||||||
|
vhdx_file,
|
||||||
|
eventfd: EventFd::new(libc::EFD_NONBLOCK)?,
|
||||||
|
completion_list: Vec::new(),
|
||||||
|
semaphore,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsyncIo for VhdxSync {
|
||||||
|
fn notifier(&self) -> &EventFd {
|
||||||
|
&self.eventfd
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_vectored(
|
||||||
|
&mut self,
|
||||||
|
offset: libc::off_t,
|
||||||
|
iovecs: Vec<libc::iovec>,
|
||||||
|
user_data: u64,
|
||||||
|
) -> AsyncIoResult<()> {
|
||||||
|
read_vectored_sync(
|
||||||
|
offset,
|
||||||
|
iovecs,
|
||||||
|
user_data,
|
||||||
|
self.vhdx_file.lock().unwrap().deref_mut(),
|
||||||
|
&self.eventfd,
|
||||||
|
&mut self.completion_list,
|
||||||
|
&mut self.semaphore,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_vectored(
|
||||||
|
&mut self,
|
||||||
|
offset: libc::off_t,
|
||||||
|
iovecs: Vec<libc::iovec>,
|
||||||
|
user_data: u64,
|
||||||
|
) -> AsyncIoResult<()> {
|
||||||
|
write_vectored_sync(
|
||||||
|
offset,
|
||||||
|
iovecs,
|
||||||
|
user_data,
|
||||||
|
self.vhdx_file.lock().unwrap().deref_mut(),
|
||||||
|
&self.eventfd,
|
||||||
|
&mut self.completion_list,
|
||||||
|
&mut self.semaphore,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fsync(&mut self, user_data: Option<u64>) -> AsyncIoResult<()> {
|
||||||
|
fsync_sync(
|
||||||
|
user_data,
|
||||||
|
self.vhdx_file.lock().unwrap().deref_mut(),
|
||||||
|
&self.eventfd,
|
||||||
|
&mut self.completion_list,
|
||||||
|
&mut self.semaphore,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn complete(&mut self) -> Vec<(u64, i32)> {
|
||||||
|
self.completion_list.drain(..).collect()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,22 +2,23 @@
|
|||||||
name = "devices"
|
name = "devices"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
authors = ["The Chromium OS Authors"]
|
authors = ["The Chromium OS Authors"]
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "1.0"
|
|
||||||
bitflags = ">=1.2.1"
|
|
||||||
byteorder = "1.4.3"
|
|
||||||
epoll = ">=4.0.1"
|
|
||||||
libc = "0.2.94"
|
|
||||||
log = "0.4.14"
|
|
||||||
serde = {version = ">=1.0.27", features = ["rc"] }
|
|
||||||
serde_derive = ">=1.0.27"
|
|
||||||
serde_json = ">=1.0.9"
|
|
||||||
vm-device = { path = "../vm-device" }
|
|
||||||
acpi_tables = { path = "../acpi_tables", optional = true }
|
acpi_tables = { path = "../acpi_tables", optional = true }
|
||||||
vm-memory = "0.5.0"
|
anyhow = "1.0.44"
|
||||||
|
arch = { path = "../arch" }
|
||||||
|
bitflags = "1.3.2"
|
||||||
|
byteorder = "1.4.3"
|
||||||
|
epoll = "4.3.1"
|
||||||
|
libc = "0.2.103"
|
||||||
|
log = "0.4.14"
|
||||||
|
versionize = "0.1.6"
|
||||||
|
versionize_derive = "0.1.4"
|
||||||
|
vm-device = { path = "../vm-device" }
|
||||||
|
vm-memory = "0.6.0"
|
||||||
vm-migration = { path = "../vm-migration" }
|
vm-migration = { path = "../vm-migration" }
|
||||||
vmm-sys-util = ">=0.3.1"
|
vmm-sys-util = "0.9.0"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = []
|
default = []
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
//
|
//
|
||||||
|
|
||||||
|
use super::AcpiNotificationFlags;
|
||||||
use acpi_tables::{aml, aml::Aml};
|
use acpi_tables::{aml, aml::Aml};
|
||||||
use std::sync::{Arc, Barrier};
|
use std::sync::{Arc, Barrier};
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
@@ -10,7 +11,6 @@ use vm_device::interrupt::InterruptSourceGroup;
|
|||||||
use vm_device::BusDevice;
|
use vm_device::BusDevice;
|
||||||
use vm_memory::GuestAddress;
|
use vm_memory::GuestAddress;
|
||||||
use vmm_sys_util::eventfd::EventFd;
|
use vmm_sys_util::eventfd::EventFd;
|
||||||
use AcpiNotificationFlags;
|
|
||||||
|
|
||||||
pub const GED_DEVICE_ACPI_SIZE: usize = 0x1;
|
pub const GED_DEVICE_ACPI_SIZE: usize = 0x1;
|
||||||
|
|
||||||
@@ -34,14 +34,12 @@ impl AcpiShutdownDevice {
|
|||||||
impl BusDevice for AcpiShutdownDevice {
|
impl BusDevice for AcpiShutdownDevice {
|
||||||
// Spec has all fields as zero
|
// Spec has all fields as zero
|
||||||
fn read(&mut self, _base: u64, _offset: u64, data: &mut [u8]) {
|
fn read(&mut self, _base: u64, _offset: u64, data: &mut [u8]) {
|
||||||
for i in data.iter_mut() {
|
data.fill(0)
|
||||||
*i = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write(&mut self, _base: u64, _offset: u64, data: &[u8]) -> Option<Arc<Barrier>> {
|
fn write(&mut self, _base: u64, _offset: u64, data: &[u8]) -> Option<Arc<Barrier>> {
|
||||||
if data[0] == 1 {
|
if data[0] == 1 {
|
||||||
debug!("ACPI Reboot signalled");
|
info!("ACPI Reboot signalled");
|
||||||
if let Err(e) = self.reset_evt.write(1) {
|
if let Err(e) = self.reset_evt.write(1) {
|
||||||
error!("Error triggering ACPI reset event: {}", e);
|
error!("Error triggering ACPI reset event: {}", e);
|
||||||
}
|
}
|
||||||
@@ -51,8 +49,7 @@ impl BusDevice for AcpiShutdownDevice {
|
|||||||
const SLEEP_STATUS_EN_BIT: u8 = 5;
|
const SLEEP_STATUS_EN_BIT: u8 = 5;
|
||||||
const SLEEP_VALUE_BIT: u8 = 2;
|
const SLEEP_VALUE_BIT: u8 = 2;
|
||||||
if data[0] == (S5_SLEEP_VALUE << SLEEP_VALUE_BIT) | (1 << SLEEP_STATUS_EN_BIT) {
|
if data[0] == (S5_SLEEP_VALUE << SLEEP_VALUE_BIT) | (1 << SLEEP_STATUS_EN_BIT) {
|
||||||
debug!("ACPI Shutdown signalled");
|
info!("ACPI Shutdown signalled");
|
||||||
extern crate bitflags;
|
|
||||||
if let Err(e) = self.exit_evt.write(1) {
|
if let Err(e) = self.exit_evt.write(1) {
|
||||||
error!("Error triggering ACPI shutdown event: {}", e);
|
error!("Error triggering ACPI shutdown event: {}", e);
|
||||||
}
|
}
|
||||||
@@ -63,7 +60,7 @@ impl BusDevice for AcpiShutdownDevice {
|
|||||||
|
|
||||||
/// A device for handling ACPI GED event generation
|
/// A device for handling ACPI GED event generation
|
||||||
pub struct AcpiGedDevice {
|
pub struct AcpiGedDevice {
|
||||||
interrupt: Arc<Box<dyn InterruptSourceGroup>>,
|
interrupt: Arc<dyn InterruptSourceGroup>,
|
||||||
notification_type: AcpiNotificationFlags,
|
notification_type: AcpiNotificationFlags,
|
||||||
ged_irq: u32,
|
ged_irq: u32,
|
||||||
address: GuestAddress,
|
address: GuestAddress,
|
||||||
@@ -71,7 +68,7 @@ pub struct AcpiGedDevice {
|
|||||||
|
|
||||||
impl AcpiGedDevice {
|
impl AcpiGedDevice {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
interrupt: Arc<Box<dyn InterruptSourceGroup>>,
|
interrupt: Arc<dyn InterruptSourceGroup>,
|
||||||
ged_irq: u32,
|
ged_irq: u32,
|
||||||
address: GuestAddress,
|
address: GuestAddress,
|
||||||
) -> AcpiGedDevice {
|
) -> AcpiGedDevice {
|
||||||
@@ -192,6 +189,10 @@ impl Default for AcpiPmTimerDevice {
|
|||||||
|
|
||||||
impl BusDevice for AcpiPmTimerDevice {
|
impl BusDevice for AcpiPmTimerDevice {
|
||||||
fn read(&mut self, _base: u64, _offset: u64, data: &mut [u8]) {
|
fn read(&mut self, _base: u64, _offset: u64, data: &mut [u8]) {
|
||||||
|
if data.len() != std::mem::size_of::<u32>() {
|
||||||
|
warn!("Invalid sized read of PM timer: {}", data.len());
|
||||||
|
return;
|
||||||
|
}
|
||||||
let now = Instant::now();
|
let now = Instant::now();
|
||||||
let since = now.duration_since(self.start);
|
let since = now.duration_since(self.start);
|
||||||
let nanos = since.as_nanos();
|
let nanos = since.as_nanos();
|
||||||
|
|||||||
@@ -3,8 +3,10 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
|
// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
|
||||||
|
|
||||||
use super::interrupt_controller::{Error, InterruptController};
|
use super::interrupt_controller::{Error, InterruptController};
|
||||||
|
extern crate arch;
|
||||||
|
use arch::aarch64::gic::GicDevice;
|
||||||
use std::result;
|
use std::result;
|
||||||
use std::sync::Arc;
|
use std::sync::{Arc, Mutex};
|
||||||
use vm_device::interrupt::{
|
use vm_device::interrupt::{
|
||||||
InterruptIndex, InterruptManager, InterruptSourceConfig, InterruptSourceGroup,
|
InterruptIndex, InterruptManager, InterruptSourceConfig, InterruptSourceGroup,
|
||||||
LegacyIrqSourceConfig, MsiIrqGroupConfig,
|
LegacyIrqSourceConfig, MsiIrqGroupConfig,
|
||||||
@@ -14,7 +16,7 @@ use vmm_sys_util::eventfd::EventFd;
|
|||||||
type Result<T> = result::Result<T, Error>;
|
type Result<T> = result::Result<T, Error>;
|
||||||
|
|
||||||
// Reserve 32 IRQs for legacy device.
|
// Reserve 32 IRQs for legacy device.
|
||||||
pub const IRQ_LEGACY_BASE: usize = 0;
|
pub const IRQ_LEGACY_BASE: usize = arch::layout::IRQ_BASE as usize;
|
||||||
pub const IRQ_LEGACY_COUNT: usize = 32;
|
pub const IRQ_LEGACY_COUNT: usize = 32;
|
||||||
|
|
||||||
// This Gic struct implements InterruptController to provide interrupt delivery service.
|
// This Gic struct implements InterruptController to provide interrupt delivery service.
|
||||||
@@ -24,7 +26,8 @@ pub const IRQ_LEGACY_COUNT: usize = 32;
|
|||||||
// 1. Move Gic*.rs from arch/ folder here.
|
// 1. Move Gic*.rs from arch/ folder here.
|
||||||
// 2. Move this file and ioapic.rs to arch/, as they are architecture specific.
|
// 2. Move this file and ioapic.rs to arch/, as they are architecture specific.
|
||||||
pub struct Gic {
|
pub struct Gic {
|
||||||
interrupt_source_group: Arc<Box<dyn InterruptSourceGroup>>,
|
interrupt_source_group: Arc<dyn InterruptSourceGroup>,
|
||||||
|
gic_device: Option<Arc<Mutex<Box<dyn GicDevice>>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Gic {
|
impl Gic {
|
||||||
@@ -41,8 +44,17 @@ impl Gic {
|
|||||||
|
|
||||||
Ok(Gic {
|
Ok(Gic {
|
||||||
interrupt_source_group,
|
interrupt_source_group,
|
||||||
|
gic_device: None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_gic_device(&mut self, gic_device: Arc<Mutex<Box<dyn GicDevice>>>) {
|
||||||
|
self.gic_device = Some(gic_device);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_gic_device(&self) -> Option<&Arc<Mutex<Box<dyn GicDevice>>>> {
|
||||||
|
self.gic_device.as_ref()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl InterruptController for Gic {
|
impl InterruptController for Gic {
|
||||||
@@ -58,7 +70,7 @@ impl InterruptController for Gic {
|
|||||||
for i in IRQ_LEGACY_BASE..(IRQ_LEGACY_BASE + IRQ_LEGACY_COUNT) {
|
for i in IRQ_LEGACY_BASE..(IRQ_LEGACY_BASE + IRQ_LEGACY_COUNT) {
|
||||||
let config = LegacyIrqSourceConfig {
|
let config = LegacyIrqSourceConfig {
|
||||||
irqchip: 0,
|
irqchip: 0,
|
||||||
pin: i as u32,
|
pin: (i - IRQ_LEGACY_BASE) as u32,
|
||||||
};
|
};
|
||||||
self.interrupt_source_group
|
self.interrupt_source_group
|
||||||
.update(
|
.update(
|
||||||
|
|||||||
@@ -14,13 +14,17 @@ use anyhow::anyhow;
|
|||||||
use byteorder::{ByteOrder, LittleEndian};
|
use byteorder::{ByteOrder, LittleEndian};
|
||||||
use std::result;
|
use std::result;
|
||||||
use std::sync::{Arc, Barrier};
|
use std::sync::{Arc, Barrier};
|
||||||
|
use versionize::{VersionMap, Versionize, VersionizeResult};
|
||||||
|
use versionize_derive::Versionize;
|
||||||
use vm_device::interrupt::{
|
use vm_device::interrupt::{
|
||||||
InterruptIndex, InterruptManager, InterruptSourceConfig, InterruptSourceGroup,
|
InterruptIndex, InterruptManager, InterruptSourceConfig, InterruptSourceGroup,
|
||||||
MsiIrqGroupConfig, MsiIrqSourceConfig,
|
MsiIrqGroupConfig, MsiIrqSourceConfig,
|
||||||
};
|
};
|
||||||
use vm_device::BusDevice;
|
use vm_device::BusDevice;
|
||||||
use vm_memory::GuestAddress;
|
use vm_memory::GuestAddress;
|
||||||
use vm_migration::{Migratable, MigratableError, Pausable, Snapshot, Snapshottable, Transportable};
|
use vm_migration::{
|
||||||
|
Migratable, MigratableError, Pausable, Snapshot, Snapshottable, Transportable, VersionMapped,
|
||||||
|
};
|
||||||
use vmm_sys_util::eventfd::EventFd;
|
use vmm_sys_util::eventfd::EventFd;
|
||||||
|
|
||||||
type Result<T> = result::Result<T, Error>;
|
type Result<T> = result::Result<T, Error>;
|
||||||
@@ -130,10 +134,10 @@ pub struct Ioapic {
|
|||||||
reg_entries: [RedirectionTableEntry; NUM_IOAPIC_PINS],
|
reg_entries: [RedirectionTableEntry; NUM_IOAPIC_PINS],
|
||||||
used_entries: [bool; NUM_IOAPIC_PINS],
|
used_entries: [bool; NUM_IOAPIC_PINS],
|
||||||
apic_address: GuestAddress,
|
apic_address: GuestAddress,
|
||||||
interrupt_source_group: Arc<Box<dyn InterruptSourceGroup>>,
|
interrupt_source_group: Arc<dyn InterruptSourceGroup>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Versionize)]
|
||||||
pub struct IoapicState {
|
pub struct IoapicState {
|
||||||
id_reg: u32,
|
id_reg: u32,
|
||||||
reg_sel: u32,
|
reg_sel: u32,
|
||||||
@@ -141,10 +145,14 @@ pub struct IoapicState {
|
|||||||
used_entries: [bool; NUM_IOAPIC_PINS],
|
used_entries: [bool; NUM_IOAPIC_PINS],
|
||||||
apic_address: u64,
|
apic_address: u64,
|
||||||
}
|
}
|
||||||
|
impl VersionMapped for IoapicState {}
|
||||||
|
|
||||||
impl BusDevice for Ioapic {
|
impl BusDevice for Ioapic {
|
||||||
fn read(&mut self, _base: u64, offset: u64, data: &mut [u8]) {
|
fn read(&mut self, _base: u64, offset: u64, data: &mut [u8]) {
|
||||||
assert!(data.len() == 4);
|
if data.len() != std::mem::size_of::<u32>() {
|
||||||
|
warn!("Invalid read size on IOAPIC: {}", data.len());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
debug!("IOAPIC_R @ offset 0x{:x}", offset);
|
debug!("IOAPIC_R @ offset 0x{:x}", offset);
|
||||||
|
|
||||||
@@ -161,7 +169,10 @@ impl BusDevice for Ioapic {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn write(&mut self, _base: u64, offset: u64, data: &[u8]) -> Option<Arc<Barrier>> {
|
fn write(&mut self, _base: u64, offset: u64, data: &[u8]) -> Option<Arc<Barrier>> {
|
||||||
assert!(data.len() == 4);
|
if data.len() != std::mem::size_of::<u32>() {
|
||||||
|
warn!("Invalid write size on IOAPIC: {}", data.len());
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
debug!("IOAPIC_W @ offset 0x{:x}", offset);
|
debug!("IOAPIC_W @ offset 0x{:x}", offset);
|
||||||
|
|
||||||
@@ -221,6 +232,10 @@ impl Ioapic {
|
|||||||
IOAPIC_REG_ID => self.id_reg = (val >> 24) & 0xf,
|
IOAPIC_REG_ID => self.id_reg = (val >> 24) & 0xf,
|
||||||
IOWIN_OFF..=REG_MAX_OFFSET => {
|
IOWIN_OFF..=REG_MAX_OFFSET => {
|
||||||
let (index, is_high_bits) = decode_irq_from_selector(self.reg_sel as u8);
|
let (index, is_high_bits) = decode_irq_from_selector(self.reg_sel as u8);
|
||||||
|
if index > NUM_IOAPIC_PINS {
|
||||||
|
warn!("IOAPIC index out of range: {}", index);
|
||||||
|
return;
|
||||||
|
}
|
||||||
if is_high_bits {
|
if is_high_bits {
|
||||||
self.reg_entries[index] &= 0xffff_ffff;
|
self.reg_entries[index] &= 0xffff_ffff;
|
||||||
self.reg_entries[index] |= u64::from(val) << 32;
|
self.reg_entries[index] |= u64::from(val) << 32;
|
||||||
@@ -254,6 +269,10 @@ impl Ioapic {
|
|||||||
IOAPIC_REG_ID | IOAPIC_REG_ARBITRATION_ID => (self.id_reg & 0xf) << 24,
|
IOAPIC_REG_ID | IOAPIC_REG_ARBITRATION_ID => (self.id_reg & 0xf) << 24,
|
||||||
IOWIN_OFF..=REG_MAX_OFFSET => {
|
IOWIN_OFF..=REG_MAX_OFFSET => {
|
||||||
let (index, is_high_bits) = decode_irq_from_selector(self.reg_sel as u8);
|
let (index, is_high_bits) = decode_irq_from_selector(self.reg_sel as u8);
|
||||||
|
if index > NUM_IOAPIC_PINS {
|
||||||
|
warn!("IOAPIC index out of range: {}", index);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
if is_high_bits {
|
if is_high_bits {
|
||||||
(self.reg_entries[index] >> 32) as u32
|
(self.reg_entries[index] >> 32) as u32
|
||||||
} else {
|
} else {
|
||||||
@@ -410,13 +429,18 @@ impl Snapshottable for Ioapic {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> {
|
fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> {
|
||||||
Snapshot::new_from_state(&self.id, &self.state())
|
Snapshot::new_from_versioned_state(&self.id, &self.state())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn restore(&mut self, snapshot: Snapshot) -> std::result::Result<(), MigratableError> {
|
fn restore(&mut self, snapshot: Snapshot) -> std::result::Result<(), MigratableError> {
|
||||||
self.set_state(&snapshot.to_state(&self.id)?).map_err(|e| {
|
self.set_state(&snapshot.to_versioned_state(&self.id)?)
|
||||||
MigratableError::Restore(anyhow!("Could not restore state for {}: {:?}", self.id, e))
|
.map_err(|e| {
|
||||||
})
|
MigratableError::Restore(anyhow!(
|
||||||
|
"Could not restore state for {}: {:?}",
|
||||||
|
self.id,
|
||||||
|
e
|
||||||
|
))
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,12 +2,16 @@
|
|||||||
// Use of this source code is governed by a BSD-style license that can be
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
use libc::{clock_gettime, gmtime_r, time_t, timespec, tm, CLOCK_REALTIME};
|
use libc::{clock_gettime, gmtime_r, timespec, tm, CLOCK_REALTIME};
|
||||||
use std::cmp::min;
|
use std::cmp::min;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::sync::{Arc, Barrier};
|
use std::sync::{Arc, Barrier};
|
||||||
use vm_device::BusDevice;
|
use vm_device::BusDevice;
|
||||||
|
|
||||||
|
// https://github.com/rust-lang/libc/issues/1848
|
||||||
|
#[cfg_attr(target_env = "musl", allow(deprecated))]
|
||||||
|
use libc::time_t;
|
||||||
|
|
||||||
const INDEX_MASK: u8 = 0x7f;
|
const INDEX_MASK: u8 = 0x7f;
|
||||||
const INDEX_OFFSET: u64 = 0x0;
|
const INDEX_OFFSET: u64 = 0x0;
|
||||||
const DATA_OFFSET: u64 = 0x1;
|
const DATA_OFFSET: u64 = 0x1;
|
||||||
@@ -47,13 +51,14 @@ impl Cmos {
|
|||||||
impl BusDevice for Cmos {
|
impl BusDevice for Cmos {
|
||||||
fn write(&mut self, _base: u64, offset: u64, data: &[u8]) -> Option<Arc<Barrier>> {
|
fn write(&mut self, _base: u64, offset: u64, data: &[u8]) -> Option<Arc<Barrier>> {
|
||||||
if data.len() != 1 {
|
if data.len() != 1 {
|
||||||
|
warn!("Invalid write size on CMOS device: {}", data.len());
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
match offset {
|
match offset {
|
||||||
INDEX_OFFSET => self.index = data[0] & INDEX_MASK,
|
INDEX_OFFSET => self.index = data[0] & INDEX_MASK,
|
||||||
DATA_OFFSET => self.data[self.index as usize] = data[0],
|
DATA_OFFSET => self.data[self.index as usize] = data[0],
|
||||||
o => panic!("bad write offset on CMOS device: {}", o),
|
o => warn!("bad write offset on CMOS device: {}", o),
|
||||||
};
|
};
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
@@ -65,6 +70,7 @@ impl BusDevice for Cmos {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if data.len() != 1 {
|
if data.len() != 1 {
|
||||||
|
warn!("Invalid read size on CMOS device: {}", data.len());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -85,6 +91,8 @@ impl BusDevice for Cmos {
|
|||||||
let mut timespec: timespec = mem::zeroed();
|
let mut timespec: timespec = mem::zeroed();
|
||||||
clock_gettime(CLOCK_REALTIME, &mut timespec as *mut _);
|
clock_gettime(CLOCK_REALTIME, &mut timespec as *mut _);
|
||||||
|
|
||||||
|
// https://github.com/rust-lang/libc/issues/1848
|
||||||
|
#[cfg_attr(target_env = "musl", allow(deprecated))]
|
||||||
let now: time_t = timespec.tv_sec;
|
let now: time_t = timespec.tv_sec;
|
||||||
let mut tm: tm = mem::zeroed();
|
let mut tm: tm = mem::zeroed();
|
||||||
gmtime_r(&now, &mut tm as *mut _);
|
gmtime_r(&now, &mut tm as *mut _);
|
||||||
@@ -120,7 +128,10 @@ impl BusDevice for Cmos {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
o => panic!("bad read offset on CMOS device: {}", o),
|
o => {
|
||||||
|
warn!("bad read offset on CMOS device: {}", o);
|
||||||
|
0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,9 +11,13 @@ use crate::{read_le_u32, write_le_u32};
|
|||||||
use std::result;
|
use std::result;
|
||||||
use std::sync::{Arc, Barrier};
|
use std::sync::{Arc, Barrier};
|
||||||
use std::{fmt, io};
|
use std::{fmt, io};
|
||||||
|
use versionize::{VersionMap, Versionize, VersionizeResult};
|
||||||
|
use versionize_derive::Versionize;
|
||||||
use vm_device::interrupt::InterruptSourceGroup;
|
use vm_device::interrupt::InterruptSourceGroup;
|
||||||
use vm_device::BusDevice;
|
use vm_device::BusDevice;
|
||||||
use vm_migration::{Migratable, MigratableError, Pausable, Snapshot, Snapshottable, Transportable};
|
use vm_migration::{
|
||||||
|
Migratable, MigratableError, Pausable, Snapshot, Snapshottable, Transportable, VersionMapped,
|
||||||
|
};
|
||||||
|
|
||||||
const OFS_DATA: u64 = 0x400; // Data Register
|
const OFS_DATA: u64 = 0x400; // Data Register
|
||||||
const GPIODIR: u64 = 0x400; // Direction Register
|
const GPIODIR: u64 = 0x400; // Direction Register
|
||||||
@@ -82,10 +86,10 @@ pub struct Gpio {
|
|||||||
// Mode Control Select Register
|
// Mode Control Select Register
|
||||||
afsel: u32,
|
afsel: u32,
|
||||||
// GPIO irq_field
|
// GPIO irq_field
|
||||||
interrupt: Arc<Box<dyn InterruptSourceGroup>>,
|
interrupt: Arc<dyn InterruptSourceGroup>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Versionize)]
|
||||||
pub struct GpioState {
|
pub struct GpioState {
|
||||||
data: u32,
|
data: u32,
|
||||||
old_in_data: u32,
|
old_in_data: u32,
|
||||||
@@ -98,9 +102,11 @@ pub struct GpioState {
|
|||||||
afsel: u32,
|
afsel: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl VersionMapped for GpioState {}
|
||||||
|
|
||||||
impl Gpio {
|
impl Gpio {
|
||||||
/// Constructs an PL061 GPIO device.
|
/// Constructs an PL061 GPIO device.
|
||||||
pub fn new(id: String, interrupt: Arc<Box<dyn InterruptSourceGroup>>) -> Self {
|
pub fn new(id: String, interrupt: Arc<dyn InterruptSourceGroup>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
id,
|
id,
|
||||||
data: 0,
|
data: 0,
|
||||||
@@ -291,7 +297,7 @@ impl BusDevice for Gpio {
|
|||||||
|
|
||||||
fn write(&mut self, _base: u64, offset: u64, data: &[u8]) -> Option<Arc<Barrier>> {
|
fn write(&mut self, _base: u64, offset: u64, data: &[u8]) -> Option<Arc<Barrier>> {
|
||||||
if data.len() <= 4 {
|
if data.len() <= 4 {
|
||||||
let value = read_le_u32(&data);
|
let value = read_le_u32(data);
|
||||||
if let Err(e) = self.handle_write(offset, value) {
|
if let Err(e) = self.handle_write(offset, value) {
|
||||||
warn!("Failed to write to GPIO PL061 device: {}", e);
|
warn!("Failed to write to GPIO PL061 device: {}", e);
|
||||||
}
|
}
|
||||||
@@ -313,11 +319,11 @@ impl Snapshottable for Gpio {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> {
|
fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> {
|
||||||
Snapshot::new_from_state(&self.id, &self.state())
|
Snapshot::new_from_versioned_state(&self.id, &self.state())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn restore(&mut self, snapshot: Snapshot) -> std::result::Result<(), MigratableError> {
|
fn restore(&mut self, snapshot: Snapshot) -> std::result::Result<(), MigratableError> {
|
||||||
self.set_state(&snapshot.to_state(&self.id)?);
|
self.set_state(&snapshot.to_versioned_state(&self.id)?);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -370,14 +376,14 @@ mod tests {
|
|||||||
let intr_evt = EventFd::new(libc::EFD_NONBLOCK).unwrap();
|
let intr_evt = EventFd::new(libc::EFD_NONBLOCK).unwrap();
|
||||||
let mut gpio = Gpio::new(
|
let mut gpio = Gpio::new(
|
||||||
String::from(GPIO_NAME),
|
String::from(GPIO_NAME),
|
||||||
Arc::new(Box::new(TestInterrupt::new(intr_evt.try_clone().unwrap()))),
|
Arc::new(TestInterrupt::new(intr_evt.try_clone().unwrap())),
|
||||||
);
|
);
|
||||||
let mut data = [0; 4];
|
let mut data = [0; 4];
|
||||||
|
|
||||||
// Read and write to the GPIODIR register.
|
// Read and write to the GPIODIR register.
|
||||||
// Set pin 0 output pin.
|
// Set pin 0 output pin.
|
||||||
write_le_u32(&mut data, 1);
|
write_le_u32(&mut data, 1);
|
||||||
gpio.write(LEGACY_GPIO_MAPPED_IO_START, GPIODIR, &mut data);
|
gpio.write(LEGACY_GPIO_MAPPED_IO_START, GPIODIR, &data);
|
||||||
gpio.read(LEGACY_GPIO_MAPPED_IO_START, GPIODIR, &mut data);
|
gpio.read(LEGACY_GPIO_MAPPED_IO_START, GPIODIR, &mut data);
|
||||||
let v = read_le_u32(&data);
|
let v = read_le_u32(&data);
|
||||||
assert_eq!(v, 1);
|
assert_eq!(v, 1);
|
||||||
@@ -385,8 +391,8 @@ mod tests {
|
|||||||
// Read and write to the GPIODATA register.
|
// Read and write to the GPIODATA register.
|
||||||
write_le_u32(&mut data, 1);
|
write_le_u32(&mut data, 1);
|
||||||
// Set pin 0 high.
|
// Set pin 0 high.
|
||||||
let offset = 0x00000004 as u64;
|
let offset = 0x00000004_u64;
|
||||||
gpio.write(LEGACY_GPIO_MAPPED_IO_START, offset, &mut data);
|
gpio.write(LEGACY_GPIO_MAPPED_IO_START, offset, &data);
|
||||||
gpio.read(LEGACY_GPIO_MAPPED_IO_START, offset, &mut data);
|
gpio.read(LEGACY_GPIO_MAPPED_IO_START, offset, &mut data);
|
||||||
let v = read_le_u32(&data);
|
let v = read_le_u32(&data);
|
||||||
assert_eq!(v, 1);
|
assert_eq!(v, 1);
|
||||||
@@ -394,7 +400,7 @@ mod tests {
|
|||||||
// Read and write to the GPIOIS register.
|
// Read and write to the GPIOIS register.
|
||||||
// Configure pin 0 detecting level interrupt.
|
// Configure pin 0 detecting level interrupt.
|
||||||
write_le_u32(&mut data, 1);
|
write_le_u32(&mut data, 1);
|
||||||
gpio.write(LEGACY_GPIO_MAPPED_IO_START, GPIOIS, &mut data);
|
gpio.write(LEGACY_GPIO_MAPPED_IO_START, GPIOIS, &data);
|
||||||
gpio.read(LEGACY_GPIO_MAPPED_IO_START, GPIOIS, &mut data);
|
gpio.read(LEGACY_GPIO_MAPPED_IO_START, GPIOIS, &mut data);
|
||||||
let v = read_le_u32(&data);
|
let v = read_le_u32(&data);
|
||||||
assert_eq!(v, 1);
|
assert_eq!(v, 1);
|
||||||
@@ -402,7 +408,7 @@ mod tests {
|
|||||||
// Read and write to the GPIOIBE register.
|
// Read and write to the GPIOIBE register.
|
||||||
// Configure pin 1 detecting both falling and rising edges.
|
// Configure pin 1 detecting both falling and rising edges.
|
||||||
write_le_u32(&mut data, 2);
|
write_le_u32(&mut data, 2);
|
||||||
gpio.write(LEGACY_GPIO_MAPPED_IO_START, GPIOIBE, &mut data);
|
gpio.write(LEGACY_GPIO_MAPPED_IO_START, GPIOIBE, &data);
|
||||||
gpio.read(LEGACY_GPIO_MAPPED_IO_START, GPIOIBE, &mut data);
|
gpio.read(LEGACY_GPIO_MAPPED_IO_START, GPIOIBE, &mut data);
|
||||||
let v = read_le_u32(&data);
|
let v = read_le_u32(&data);
|
||||||
assert_eq!(v, 2);
|
assert_eq!(v, 2);
|
||||||
@@ -410,7 +416,7 @@ mod tests {
|
|||||||
// Read and write to the GPIOIEV register.
|
// Read and write to the GPIOIEV register.
|
||||||
// Configure pin 2 detecting both falling and rising edges.
|
// Configure pin 2 detecting both falling and rising edges.
|
||||||
write_le_u32(&mut data, 4);
|
write_le_u32(&mut data, 4);
|
||||||
gpio.write(LEGACY_GPIO_MAPPED_IO_START, GPIOIEV, &mut data);
|
gpio.write(LEGACY_GPIO_MAPPED_IO_START, GPIOIEV, &data);
|
||||||
gpio.read(LEGACY_GPIO_MAPPED_IO_START, GPIOIEV, &mut data);
|
gpio.read(LEGACY_GPIO_MAPPED_IO_START, GPIOIEV, &mut data);
|
||||||
let v = read_le_u32(&data);
|
let v = read_le_u32(&data);
|
||||||
assert_eq!(v, 4);
|
assert_eq!(v, 4);
|
||||||
@@ -419,12 +425,12 @@ mod tests {
|
|||||||
// Configure pin 0...2 capable of triggering their individual interrupts
|
// Configure pin 0...2 capable of triggering their individual interrupts
|
||||||
// and then the combined GPIOINTR line.
|
// and then the combined GPIOINTR line.
|
||||||
write_le_u32(&mut data, 7);
|
write_le_u32(&mut data, 7);
|
||||||
gpio.write(LEGACY_GPIO_MAPPED_IO_START, GPIOIE, &mut data);
|
gpio.write(LEGACY_GPIO_MAPPED_IO_START, GPIOIE, &data);
|
||||||
gpio.read(LEGACY_GPIO_MAPPED_IO_START, GPIOIE, &mut data);
|
gpio.read(LEGACY_GPIO_MAPPED_IO_START, GPIOIE, &mut data);
|
||||||
let v = read_le_u32(&data);
|
let v = read_le_u32(&data);
|
||||||
assert_eq!(v, 7);
|
assert_eq!(v, 7);
|
||||||
|
|
||||||
let mask = 0x00000002 as u32;
|
let mask = 0x00000002_u32;
|
||||||
// emulate an rising pulse in pin 1.
|
// emulate an rising pulse in pin 1.
|
||||||
gpio.data |= !(gpio.data & mask) & mask;
|
gpio.data |= !(gpio.data & mask) & mask;
|
||||||
gpio.pl061_internal_update();
|
gpio.pl061_internal_update();
|
||||||
@@ -437,14 +443,14 @@ mod tests {
|
|||||||
// Read and Write to the GPIOIC register.
|
// Read and Write to the GPIOIC register.
|
||||||
// clear interrupt in pin 1.
|
// clear interrupt in pin 1.
|
||||||
write_le_u32(&mut data, 2);
|
write_le_u32(&mut data, 2);
|
||||||
gpio.write(LEGACY_GPIO_MAPPED_IO_START, GPIOIC, &mut data);
|
gpio.write(LEGACY_GPIO_MAPPED_IO_START, GPIOIC, &data);
|
||||||
gpio.read(LEGACY_GPIO_MAPPED_IO_START, GPIOIC, &mut data);
|
gpio.read(LEGACY_GPIO_MAPPED_IO_START, GPIOIC, &mut data);
|
||||||
let v = read_le_u32(&data);
|
let v = read_le_u32(&data);
|
||||||
assert_eq!(v, 2);
|
assert_eq!(v, 2);
|
||||||
|
|
||||||
// Attempts to write beyond the writable space.
|
// Attempts to write beyond the writable space.
|
||||||
write_le_u32(&mut data, 0);
|
write_le_u32(&mut data, 0);
|
||||||
gpio.write(LEGACY_GPIO_MAPPED_IO_START, GPIO_ID_LOW, &mut data);
|
gpio.write(LEGACY_GPIO_MAPPED_IO_START, GPIO_ID_LOW, &data);
|
||||||
|
|
||||||
let mut data = [0; 4];
|
let mut data = [0; 4];
|
||||||
gpio.read(LEGACY_GPIO_MAPPED_IO_START, GPIO_ID_LOW, &mut data);
|
gpio.read(LEGACY_GPIO_MAPPED_IO_START, GPIO_ID_LOW, &mut data);
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ impl BusDevice for I8042Device {
|
|||||||
|
|
||||||
fn write(&mut self, _base: u64, offset: u64, data: &[u8]) -> Option<Arc<Barrier>> {
|
fn write(&mut self, _base: u64, offset: u64, data: &[u8]) -> Option<Arc<Barrier>> {
|
||||||
if data.len() == 1 && data[0] == 0xfe && offset == 3 {
|
if data.len() == 1 && data[0] == 0xfe && offset == 3 {
|
||||||
debug!("i8042 reset signalled");
|
info!("i8042 reset signalled");
|
||||||
if let Err(e) = self.reset_evt.write(1) {
|
if let Err(e) = self.reset_evt.write(1) {
|
||||||
error!("Error triggering i8042 reset event: {}", e);
|
error!("Error triggering i8042 reset event: {}", e);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -224,12 +224,12 @@ pub struct Rtc {
|
|||||||
load: u32,
|
load: u32,
|
||||||
imsc: u32,
|
imsc: u32,
|
||||||
ris: u32,
|
ris: u32,
|
||||||
interrupt: Arc<Box<dyn InterruptSourceGroup>>,
|
interrupt: Arc<dyn InterruptSourceGroup>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Rtc {
|
impl Rtc {
|
||||||
/// Constructs an AMBA PL031 RTC device.
|
/// Constructs an AMBA PL031 RTC device.
|
||||||
pub fn new(interrupt: Arc<Box<dyn InterruptSourceGroup>>) -> Self {
|
pub fn new(interrupt: Arc<dyn InterruptSourceGroup>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
// This is used only for duration measuring purposes.
|
// This is used only for duration measuring purposes.
|
||||||
previous_now: Instant::now(),
|
previous_now: Instant::now(),
|
||||||
@@ -328,7 +328,7 @@ impl BusDevice for Rtc {
|
|||||||
|
|
||||||
fn write(&mut self, _base: u64, offset: u64, data: &[u8]) -> Option<Arc<Barrier>> {
|
fn write(&mut self, _base: u64, offset: u64, data: &[u8]) -> Option<Arc<Barrier>> {
|
||||||
if data.len() <= 4 {
|
if data.len() <= 4 {
|
||||||
let v = read_le_u32(&data);
|
let v = read_le_u32(data);
|
||||||
if let Err(e) = self.handle_write(offset, v) {
|
if let Err(e) = self.handle_write(offset, v) {
|
||||||
warn!("Failed to write to RTC PL031 device: {}", e);
|
warn!("Failed to write to RTC PL031 device: {}", e);
|
||||||
}
|
}
|
||||||
@@ -450,14 +450,12 @@ mod tests {
|
|||||||
fn test_rtc_read_write_and_event() {
|
fn test_rtc_read_write_and_event() {
|
||||||
let intr_evt = EventFd::new(libc::EFD_NONBLOCK).unwrap();
|
let intr_evt = EventFd::new(libc::EFD_NONBLOCK).unwrap();
|
||||||
|
|
||||||
let mut rtc = Rtc::new(Arc::new(Box::new(TestInterrupt::new(
|
let mut rtc = Rtc::new(Arc::new(TestInterrupt::new(intr_evt.try_clone().unwrap())));
|
||||||
intr_evt.try_clone().unwrap(),
|
|
||||||
))));
|
|
||||||
let mut data = [0; 4];
|
let mut data = [0; 4];
|
||||||
|
|
||||||
// Read and write to the MR register.
|
// Read and write to the MR register.
|
||||||
write_le_u32(&mut data, 123);
|
write_le_u32(&mut data, 123);
|
||||||
rtc.write(LEGACY_RTC_MAPPED_IO_START, RTCMR, &mut data);
|
rtc.write(LEGACY_RTC_MAPPED_IO_START, RTCMR, &data);
|
||||||
rtc.read(LEGACY_RTC_MAPPED_IO_START, RTCMR, &mut data);
|
rtc.read(LEGACY_RTC_MAPPED_IO_START, RTCMR, &mut data);
|
||||||
let v = read_le_u32(&data);
|
let v = read_le_u32(&data);
|
||||||
assert_eq!(v, 123);
|
assert_eq!(v, 123);
|
||||||
@@ -466,7 +464,7 @@ mod tests {
|
|||||||
let v = get_time(ClockType::Real);
|
let v = get_time(ClockType::Real);
|
||||||
write_le_u32(&mut data, (v / NANOS_PER_SECOND) as u32);
|
write_le_u32(&mut data, (v / NANOS_PER_SECOND) as u32);
|
||||||
let previous_now_before = rtc.previous_now;
|
let previous_now_before = rtc.previous_now;
|
||||||
rtc.write(LEGACY_RTC_MAPPED_IO_START, RTCLR, &mut data);
|
rtc.write(LEGACY_RTC_MAPPED_IO_START, RTCLR, &data);
|
||||||
|
|
||||||
assert!(rtc.previous_now > previous_now_before);
|
assert!(rtc.previous_now > previous_now_before);
|
||||||
|
|
||||||
@@ -478,7 +476,7 @@ mod tests {
|
|||||||
// Test with non zero value.
|
// Test with non zero value.
|
||||||
let non_zero = 1;
|
let non_zero = 1;
|
||||||
write_le_u32(&mut data, non_zero);
|
write_le_u32(&mut data, non_zero);
|
||||||
rtc.write(LEGACY_RTC_MAPPED_IO_START, RTCIMSC, &mut data);
|
rtc.write(LEGACY_RTC_MAPPED_IO_START, RTCIMSC, &data);
|
||||||
// The interrupt line should be on.
|
// The interrupt line should be on.
|
||||||
assert!(rtc.interrupt.notifier(0).unwrap().read().unwrap() == 1);
|
assert!(rtc.interrupt.notifier(0).unwrap().read().unwrap() == 1);
|
||||||
rtc.read(LEGACY_RTC_MAPPED_IO_START, RTCIMSC, &mut data);
|
rtc.read(LEGACY_RTC_MAPPED_IO_START, RTCIMSC, &mut data);
|
||||||
@@ -487,14 +485,14 @@ mod tests {
|
|||||||
|
|
||||||
// Now test with 0.
|
// Now test with 0.
|
||||||
write_le_u32(&mut data, 0);
|
write_le_u32(&mut data, 0);
|
||||||
rtc.write(LEGACY_RTC_MAPPED_IO_START, RTCIMSC, &mut data);
|
rtc.write(LEGACY_RTC_MAPPED_IO_START, RTCIMSC, &data);
|
||||||
rtc.read(LEGACY_RTC_MAPPED_IO_START, RTCIMSC, &mut data);
|
rtc.read(LEGACY_RTC_MAPPED_IO_START, RTCIMSC, &mut data);
|
||||||
let v = read_le_u32(&data);
|
let v = read_le_u32(&data);
|
||||||
assert_eq!(0, v);
|
assert_eq!(0, v);
|
||||||
|
|
||||||
// Read and write to the ICR register.
|
// Read and write to the ICR register.
|
||||||
write_le_u32(&mut data, 1);
|
write_le_u32(&mut data, 1);
|
||||||
rtc.write(LEGACY_RTC_MAPPED_IO_START, RTCICR, &mut data);
|
rtc.write(LEGACY_RTC_MAPPED_IO_START, RTCICR, &data);
|
||||||
// The interrupt line should be on.
|
// The interrupt line should be on.
|
||||||
assert!(rtc.interrupt.notifier(0).unwrap().read().unwrap() > 1);
|
assert!(rtc.interrupt.notifier(0).unwrap().read().unwrap() > 1);
|
||||||
let v_before = read_le_u32(&data);
|
let v_before = read_le_u32(&data);
|
||||||
@@ -506,7 +504,7 @@ mod tests {
|
|||||||
|
|
||||||
// Attempts to turn off the RTC should not go through.
|
// Attempts to turn off the RTC should not go through.
|
||||||
write_le_u32(&mut data, 0);
|
write_le_u32(&mut data, 0);
|
||||||
rtc.write(LEGACY_RTC_MAPPED_IO_START, RTCCR, &mut data);
|
rtc.write(LEGACY_RTC_MAPPED_IO_START, RTCCR, &data);
|
||||||
rtc.read(LEGACY_RTC_MAPPED_IO_START, RTCCR, &mut data);
|
rtc.read(LEGACY_RTC_MAPPED_IO_START, RTCCR, &mut data);
|
||||||
let v = read_le_u32(&data);
|
let v = read_le_u32(&data);
|
||||||
assert_eq!(v, 1);
|
assert_eq!(v, 1);
|
||||||
@@ -514,7 +512,7 @@ mod tests {
|
|||||||
// Attempts to write beyond the writable space. Using here the space used to read
|
// Attempts to write beyond the writable space. Using here the space used to read
|
||||||
// the CID and PID from.
|
// the CID and PID from.
|
||||||
write_le_u32(&mut data, 0);
|
write_le_u32(&mut data, 0);
|
||||||
rtc.write(LEGACY_RTC_MAPPED_IO_START, AMBA_ID_LOW, &mut data);
|
rtc.write(LEGACY_RTC_MAPPED_IO_START, AMBA_ID_LOW, &data);
|
||||||
// However, reading from the AMBA_ID_LOW should succeed upon read.
|
// However, reading from the AMBA_ID_LOW should succeed upon read.
|
||||||
|
|
||||||
let mut data = [0; 4];
|
let mut data = [0; 4];
|
||||||
|
|||||||
@@ -8,9 +8,13 @@
|
|||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
use std::sync::{Arc, Barrier};
|
use std::sync::{Arc, Barrier};
|
||||||
use std::{io, result};
|
use std::{io, result};
|
||||||
|
use versionize::{VersionMap, Versionize, VersionizeResult};
|
||||||
|
use versionize_derive::Versionize;
|
||||||
use vm_device::interrupt::InterruptSourceGroup;
|
use vm_device::interrupt::InterruptSourceGroup;
|
||||||
use vm_device::BusDevice;
|
use vm_device::BusDevice;
|
||||||
use vm_migration::{Migratable, MigratableError, Pausable, Snapshot, Snapshottable, Transportable};
|
use vm_migration::{
|
||||||
|
Migratable, MigratableError, Pausable, Snapshot, Snapshottable, Transportable, VersionMapped,
|
||||||
|
};
|
||||||
use vmm_sys_util::errno::Result;
|
use vmm_sys_util::errno::Result;
|
||||||
|
|
||||||
const LOOP_SIZE: usize = 0x40;
|
const LOOP_SIZE: usize = 0x40;
|
||||||
@@ -59,7 +63,7 @@ pub struct Serial {
|
|||||||
id: String,
|
id: String,
|
||||||
interrupt_enable: u8,
|
interrupt_enable: u8,
|
||||||
interrupt_identification: u8,
|
interrupt_identification: u8,
|
||||||
interrupt: Arc<Box<dyn InterruptSourceGroup>>,
|
interrupt: Arc<dyn InterruptSourceGroup>,
|
||||||
line_control: u8,
|
line_control: u8,
|
||||||
line_status: u8,
|
line_status: u8,
|
||||||
modem_control: u8,
|
modem_control: u8,
|
||||||
@@ -70,7 +74,7 @@ pub struct Serial {
|
|||||||
out: Option<Box<dyn io::Write + Send>>,
|
out: Option<Box<dyn io::Write + Send>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Versionize)]
|
||||||
pub struct SerialState {
|
pub struct SerialState {
|
||||||
interrupt_enable: u8,
|
interrupt_enable: u8,
|
||||||
interrupt_identification: u8,
|
interrupt_identification: u8,
|
||||||
@@ -82,11 +86,12 @@ pub struct SerialState {
|
|||||||
baud_divisor: u16,
|
baud_divisor: u16,
|
||||||
in_buffer: Vec<u8>,
|
in_buffer: Vec<u8>,
|
||||||
}
|
}
|
||||||
|
impl VersionMapped for SerialState {}
|
||||||
|
|
||||||
impl Serial {
|
impl Serial {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
id: String,
|
id: String,
|
||||||
interrupt: Arc<Box<dyn InterruptSourceGroup>>,
|
interrupt: Arc<dyn InterruptSourceGroup>,
|
||||||
out: Option<Box<dyn io::Write + Send>>,
|
out: Option<Box<dyn io::Write + Send>>,
|
||||||
) -> Serial {
|
) -> Serial {
|
||||||
Serial {
|
Serial {
|
||||||
@@ -108,17 +113,21 @@ impl Serial {
|
|||||||
/// Constructs a Serial port ready for output.
|
/// Constructs a Serial port ready for output.
|
||||||
pub fn new_out(
|
pub fn new_out(
|
||||||
id: String,
|
id: String,
|
||||||
interrupt: Arc<Box<dyn InterruptSourceGroup>>,
|
interrupt: Arc<dyn InterruptSourceGroup>,
|
||||||
out: Box<dyn io::Write + Send>,
|
out: Box<dyn io::Write + Send>,
|
||||||
) -> Serial {
|
) -> Serial {
|
||||||
Self::new(id, interrupt, Some(out))
|
Self::new(id, interrupt, Some(out))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Constructs a Serial port with no connected output.
|
/// Constructs a Serial port with no connected output.
|
||||||
pub fn new_sink(id: String, interrupt: Arc<Box<dyn InterruptSourceGroup>>) -> Serial {
|
pub fn new_sink(id: String, interrupt: Arc<dyn InterruptSourceGroup>) -> Serial {
|
||||||
Self::new(id, interrupt, None)
|
Self::new(id, interrupt, None)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_out(&mut self, out: Box<dyn io::Write + Send>) {
|
||||||
|
self.out = Some(out);
|
||||||
|
}
|
||||||
|
|
||||||
/// Queues raw bytes for the guest to read and signals the interrupt if the line status would
|
/// Queues raw bytes for the guest to read and signals the interrupt if the line status would
|
||||||
/// change.
|
/// change.
|
||||||
pub fn queue_input_bytes(&mut self, c: &[u8]) -> Result<()> {
|
pub fn queue_input_bytes(&mut self, c: &[u8]) -> Result<()> {
|
||||||
@@ -129,6 +138,13 @@ impl Serial {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn flush_output(&mut self) -> result::Result<(), io::Error> {
|
||||||
|
if let Some(out) = self.out.as_mut() {
|
||||||
|
out.flush()?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn is_dlab_set(&self) -> bool {
|
fn is_dlab_set(&self) -> bool {
|
||||||
(self.line_control & LCR_DLAB_BIT) != 0
|
(self.line_control & LCR_DLAB_BIT) != 0
|
||||||
}
|
}
|
||||||
@@ -288,11 +304,11 @@ impl Snapshottable for Serial {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> {
|
fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> {
|
||||||
Snapshot::new_from_state(&self.id, &self.state())
|
Snapshot::new_from_versioned_state(&self.id, &self.state())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn restore(&mut self, snapshot: Snapshot) -> std::result::Result<(), MigratableError> {
|
fn restore(&mut self, snapshot: Snapshot) -> std::result::Result<(), MigratableError> {
|
||||||
self.set_state(&snapshot.to_state(&self.id)?);
|
self.set_state(&snapshot.to_versioned_state(&self.id)?);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -365,7 +381,7 @@ mod tests {
|
|||||||
let serial_out = SharedBuffer::new();
|
let serial_out = SharedBuffer::new();
|
||||||
let mut serial = Serial::new_out(
|
let mut serial = Serial::new_out(
|
||||||
String::from(SERIAL_NAME),
|
String::from(SERIAL_NAME),
|
||||||
Arc::new(Box::new(TestInterrupt::new(intr_evt.try_clone().unwrap()))),
|
Arc::new(TestInterrupt::new(intr_evt.try_clone().unwrap())),
|
||||||
Box::new(serial_out.clone()),
|
Box::new(serial_out.clone()),
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -385,7 +401,7 @@ mod tests {
|
|||||||
let serial_out = SharedBuffer::new();
|
let serial_out = SharedBuffer::new();
|
||||||
let mut serial = Serial::new_out(
|
let mut serial = Serial::new_out(
|
||||||
String::from(SERIAL_NAME),
|
String::from(SERIAL_NAME),
|
||||||
Arc::new(Box::new(TestInterrupt::new(intr_evt.try_clone().unwrap()))),
|
Arc::new(TestInterrupt::new(intr_evt.try_clone().unwrap())),
|
||||||
Box::new(serial_out),
|
Box::new(serial_out),
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -422,7 +438,7 @@ mod tests {
|
|||||||
let intr_evt = EventFd::new(0).unwrap();
|
let intr_evt = EventFd::new(0).unwrap();
|
||||||
let mut serial = Serial::new_sink(
|
let mut serial = Serial::new_sink(
|
||||||
String::from(SERIAL_NAME),
|
String::from(SERIAL_NAME),
|
||||||
Arc::new(Box::new(TestInterrupt::new(intr_evt.try_clone().unwrap()))),
|
Arc::new(TestInterrupt::new(intr_evt.try_clone().unwrap())),
|
||||||
);
|
);
|
||||||
|
|
||||||
// write 1 to the interrupt event fd, so that read doesn't block in case the event fd
|
// write 1 to the interrupt event fd, so that read doesn't block in case the event fd
|
||||||
@@ -444,7 +460,7 @@ mod tests {
|
|||||||
let intr_evt = EventFd::new(0).unwrap();
|
let intr_evt = EventFd::new(0).unwrap();
|
||||||
let mut serial = Serial::new_sink(
|
let mut serial = Serial::new_sink(
|
||||||
String::from(SERIAL_NAME),
|
String::from(SERIAL_NAME),
|
||||||
Arc::new(Box::new(TestInterrupt::new(intr_evt.try_clone().unwrap()))),
|
Arc::new(TestInterrupt::new(intr_evt.try_clone().unwrap())),
|
||||||
);
|
);
|
||||||
|
|
||||||
serial.write(0, LCR as u64, &[LCR_DLAB_BIT]);
|
serial.write(0, LCR as u64, &[LCR_DLAB_BIT]);
|
||||||
@@ -465,7 +481,7 @@ mod tests {
|
|||||||
let intr_evt = EventFd::new(0).unwrap();
|
let intr_evt = EventFd::new(0).unwrap();
|
||||||
let mut serial = Serial::new_sink(
|
let mut serial = Serial::new_sink(
|
||||||
String::from(SERIAL_NAME),
|
String::from(SERIAL_NAME),
|
||||||
Arc::new(Box::new(TestInterrupt::new(intr_evt.try_clone().unwrap()))),
|
Arc::new(TestInterrupt::new(intr_evt.try_clone().unwrap())),
|
||||||
);
|
);
|
||||||
|
|
||||||
serial.write(0, MCR as u64, &[MCR_LOOP_BIT]);
|
serial.write(0, MCR as u64, &[MCR_LOOP_BIT]);
|
||||||
@@ -491,7 +507,7 @@ mod tests {
|
|||||||
let intr_evt = EventFd::new(0).unwrap();
|
let intr_evt = EventFd::new(0).unwrap();
|
||||||
let mut serial = Serial::new_sink(
|
let mut serial = Serial::new_sink(
|
||||||
String::from(SERIAL_NAME),
|
String::from(SERIAL_NAME),
|
||||||
Arc::new(Box::new(TestInterrupt::new(intr_evt.try_clone().unwrap()))),
|
Arc::new(TestInterrupt::new(intr_evt.try_clone().unwrap())),
|
||||||
);
|
);
|
||||||
|
|
||||||
serial.write(0, SCR as u64, &[0x12]);
|
serial.write(0, SCR as u64, &[0x12]);
|
||||||
|
|||||||
@@ -11,9 +11,13 @@ use std::collections::VecDeque;
|
|||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::sync::{Arc, Barrier};
|
use std::sync::{Arc, Barrier};
|
||||||
use std::{io, result};
|
use std::{io, result};
|
||||||
|
use versionize::{VersionMap, Versionize, VersionizeResult};
|
||||||
|
use versionize_derive::Versionize;
|
||||||
use vm_device::interrupt::InterruptSourceGroup;
|
use vm_device::interrupt::InterruptSourceGroup;
|
||||||
use vm_device::BusDevice;
|
use vm_device::BusDevice;
|
||||||
use vm_migration::{Migratable, MigratableError, Pausable, Snapshot, Snapshottable, Transportable};
|
use vm_migration::{
|
||||||
|
Migratable, MigratableError, Pausable, Snapshot, Snapshottable, Transportable, VersionMapped,
|
||||||
|
};
|
||||||
|
|
||||||
/* Registers */
|
/* Registers */
|
||||||
const UARTDR: u64 = 0;
|
const UARTDR: u64 = 0;
|
||||||
@@ -82,11 +86,11 @@ pub struct Pl011 {
|
|||||||
ifl: u32,
|
ifl: u32,
|
||||||
read_count: u32,
|
read_count: u32,
|
||||||
read_trigger: u32,
|
read_trigger: u32,
|
||||||
irq: Arc<Box<dyn InterruptSourceGroup>>,
|
irq: Arc<dyn InterruptSourceGroup>,
|
||||||
out: Option<Box<dyn io::Write + Send>>,
|
out: Option<Box<dyn io::Write + Send>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Versionize)]
|
||||||
pub struct Pl011State {
|
pub struct Pl011State {
|
||||||
flags: u32,
|
flags: u32,
|
||||||
lcr: u32,
|
lcr: u32,
|
||||||
@@ -104,11 +108,13 @@ pub struct Pl011State {
|
|||||||
read_trigger: u32,
|
read_trigger: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl VersionMapped for Pl011State {}
|
||||||
|
|
||||||
impl Pl011 {
|
impl Pl011 {
|
||||||
/// Constructs an AMBA PL011 UART device.
|
/// Constructs an AMBA PL011 UART device.
|
||||||
pub fn new(
|
pub fn new(
|
||||||
id: String,
|
id: String,
|
||||||
irq: Arc<Box<dyn InterruptSourceGroup>>,
|
irq: Arc<dyn InterruptSourceGroup>,
|
||||||
out: Option<Box<dyn io::Write + Send>>,
|
out: Option<Box<dyn io::Write + Send>>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
@@ -132,6 +138,10 @@ impl Pl011 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_out(&mut self, out: Box<dyn io::Write + Send>) {
|
||||||
|
self.out = Some(out);
|
||||||
|
}
|
||||||
|
|
||||||
fn state(&self) -> Pl011State {
|
fn state(&self) -> Pl011State {
|
||||||
Pl011State {
|
Pl011State {
|
||||||
flags: self.flags,
|
flags: self.flags,
|
||||||
@@ -186,6 +196,13 @@ impl Pl011 {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn flush_output(&mut self) -> result::Result<(), io::Error> {
|
||||||
|
if let Some(out) = self.out.as_mut() {
|
||||||
|
out.flush()?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn pl011_get_baudrate(&self) -> u32 {
|
fn pl011_get_baudrate(&self) -> u32 {
|
||||||
if self.fbrd == 0 {
|
if self.fbrd == 0 {
|
||||||
return 0;
|
return 0;
|
||||||
@@ -335,7 +352,7 @@ impl BusDevice for Pl011 {
|
|||||||
|
|
||||||
fn write(&mut self, _base: u64, offset: u64, data: &[u8]) -> Option<Arc<Barrier>> {
|
fn write(&mut self, _base: u64, offset: u64, data: &[u8]) -> Option<Arc<Barrier>> {
|
||||||
if data.len() <= 4 {
|
if data.len() <= 4 {
|
||||||
let v = read_le_u32(&data);
|
let v = read_le_u32(data);
|
||||||
if let Err(e) = self.handle_write(offset, v) {
|
if let Err(e) = self.handle_write(offset, v) {
|
||||||
warn!("Failed to write to PL011 device: {}", e);
|
warn!("Failed to write to PL011 device: {}", e);
|
||||||
}
|
}
|
||||||
@@ -357,11 +374,11 @@ impl Snapshottable for Pl011 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> {
|
fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> {
|
||||||
Snapshot::new_from_state(&self.id, &self.state())
|
Snapshot::new_from_versioned_state(&self.id, &self.state())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn restore(&mut self, snapshot: Snapshot) -> std::result::Result<(), MigratableError> {
|
fn restore(&mut self, snapshot: Snapshot) -> std::result::Result<(), MigratableError> {
|
||||||
self.set_state(&snapshot.to_state(&self.id)?);
|
self.set_state(&snapshot.to_versioned_state(&self.id)?);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -434,7 +451,7 @@ mod tests {
|
|||||||
let pl011_out = SharedBuffer::new();
|
let pl011_out = SharedBuffer::new();
|
||||||
let mut pl011 = Pl011::new(
|
let mut pl011 = Pl011::new(
|
||||||
String::from(SERIAL_NAME),
|
String::from(SERIAL_NAME),
|
||||||
Arc::new(Box::new(TestInterrupt::new(intr_evt.try_clone().unwrap()))),
|
Arc::new(TestInterrupt::new(intr_evt.try_clone().unwrap())),
|
||||||
Some(Box::new(pl011_out.clone())),
|
Some(Box::new(pl011_out.clone())),
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -454,7 +471,7 @@ mod tests {
|
|||||||
let pl011_out = SharedBuffer::new();
|
let pl011_out = SharedBuffer::new();
|
||||||
let mut pl011 = Pl011::new(
|
let mut pl011 = Pl011::new(
|
||||||
String::from(SERIAL_NAME),
|
String::from(SERIAL_NAME),
|
||||||
Arc::new(Box::new(TestInterrupt::new(intr_evt.try_clone().unwrap()))),
|
Arc::new(TestInterrupt::new(intr_evt.try_clone().unwrap())),
|
||||||
Some(Box::new(pl011_out)),
|
Some(Box::new(pl011_out)),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -6,24 +6,11 @@
|
|||||||
// found in the LICENSE-BSD-3-Clause file.
|
// found in the LICENSE-BSD-3-Clause file.
|
||||||
|
|
||||||
//! Emulates virtual and hardware devices.
|
//! Emulates virtual and hardware devices.
|
||||||
extern crate anyhow;
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate bitflags;
|
extern crate bitflags;
|
||||||
extern crate byteorder;
|
|
||||||
extern crate epoll;
|
|
||||||
extern crate libc;
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate log;
|
extern crate log;
|
||||||
#[cfg(feature = "acpi")]
|
|
||||||
extern crate acpi_tables;
|
|
||||||
extern crate serde;
|
|
||||||
extern crate vm_device;
|
|
||||||
extern crate vm_memory;
|
|
||||||
extern crate vm_migration;
|
|
||||||
extern crate vmm_sys_util;
|
|
||||||
#[macro_use]
|
|
||||||
extern crate serde_derive;
|
|
||||||
extern crate serde_json;
|
|
||||||
|
|
||||||
#[cfg(feature = "acpi")]
|
#[cfg(feature = "acpi")]
|
||||||
pub mod acpi;
|
pub mod acpi;
|
||||||
|
|||||||
44
docs/api.md
44
docs/api.md
@@ -78,27 +78,29 @@ Shut the VMM down | `/vmm.shutdown` | N/A | N/A
|
|||||||
|
|
||||||
#### Virtual Machine (VM) Actions
|
#### Virtual Machine (VM) Actions
|
||||||
|
|
||||||
Action | Endpoint | Request Body | Response Body | Prerequisites
|
Action | Endpoint | Request Body | Response Body | Prerequisites
|
||||||
-----------------------------------|---------------------|---------------------------|--------------------------|---------------------------
|
-----------------------------------|----------------------|---------------------------|--------------------------|---------------------------
|
||||||
Create the VM | `/vm.create` | `/schemas/VmConfig` | N/A | The VM is not created yet
|
Create the VM | `/vm.create` | `/schemas/VmConfig` | N/A | The VM is not created yet
|
||||||
Delete the VM | `/vm.delete` | N/A | N/A | N/A
|
Delete the VM | `/vm.delete` | N/A | N/A | N/A
|
||||||
Boot the VM | `/vm.boot` | N/A | N/A | The VM is created but not booted
|
Boot the VM | `/vm.boot` | N/A | N/A | The VM is created but not booted
|
||||||
Shut the VM down | `/vm.shutdown` | N/A | N/A | The VM is booted
|
Shut the VM down | `/vm.shutdown` | N/A | N/A | The VM is booted
|
||||||
Reboot the VM | `/vm.reboot` | N/A | N/A | The VM is booted
|
Reboot the VM | `/vm.reboot` | N/A | N/A | The VM is booted
|
||||||
Pause the VM | `/vm.pause` | N/A | N/A | The VM is booted
|
Trigger power button of the VM | `/vm.power-button` | N/A | N/A | The VM is booted
|
||||||
Resume the VM | `/vm.resume` | N/A | N/A | The VM is paused
|
Pause the VM | `/vm.pause` | N/A | N/A | The VM is booted
|
||||||
Add/remove CPUs to/from the VM | `/vm.resize` | `/schemas/VmResize` | N/A | The VM is booted
|
Resume the VM | `/vm.resume` | N/A | N/A | The VM is paused
|
||||||
Add/remove memory from the VM | `/vm.resize` | `/schemas/VmResize` | N/A | The VM is booted
|
Add/remove CPUs to/from the VM | `/vm.resize` | `/schemas/VmResize` | N/A | The VM is booted
|
||||||
Add/remove memory from a zone | `/vm.resize-zone` | `/schemas/VmResizeZone` | N/A | The VM is booted
|
Add/remove memory from the VM | `/vm.resize` | `/schemas/VmResize` | N/A | The VM is booted
|
||||||
Dump the VM information | `/vm.info` | N/A | `/schemas/VmInfo` | The VM is created
|
Add/remove memory from a zone | `/vm.resize-zone` | `/schemas/VmResizeZone` | N/A | The VM is booted
|
||||||
Add VFIO PCI device to the VM | `/vm.add-device` | `/schemas/VmAddDevice` | `/schemas/PciDeviceInfo` | The VM is booted
|
Dump the VM information | `/vm.info` | N/A | `/schemas/VmInfo` | The VM is created
|
||||||
Add disk device to the VM | `/vm.add-disk` | `/schemas/DiskConfig` | `/schemas/PciDeviceInfo` | The VM is booted
|
Add VFIO PCI device to the VM | `/vm.add-device` | `/schemas/VmAddDevice` | `/schemas/PciDeviceInfo` | The VM is booted
|
||||||
Add fs device to the VM | `/vm.add-fs` | `/schemas/FsConfig` | `/schemas/PciDeviceInfo` | The VM is booted
|
Add disk device to the VM | `/vm.add-disk` | `/schemas/DiskConfig` | `/schemas/PciDeviceInfo` | The VM is booted
|
||||||
Add pmem device to the VM | `/vm.add-pmem` | `/schemas/PmemConfig` | `/schemas/PciDeviceInfo` | The VM is booted
|
Add fs device to the VM | `/vm.add-fs` | `/schemas/FsConfig` | `/schemas/PciDeviceInfo` | The VM is booted
|
||||||
Add network device to the VM | `/vm.add-net` | `/schemas/NetConfig` | `/schemas/PciDeviceInfo` | The VM is booted
|
Add pmem device to the VM | `/vm.add-pmem` | `/schemas/PmemConfig` | `/schemas/PciDeviceInfo` | The VM is booted
|
||||||
Add vsock device to the VM | `/vm.add-vsock` | `/schemas/VsockConfig` | `/schemas/PciDeviceInfo` | The VM is booted
|
Add network device to the VM | `/vm.add-net` | `/schemas/NetConfig` | `/schemas/PciDeviceInfo` | The VM is booted
|
||||||
Remove device from the VM | `/vm.remove-device` | `/schemas/VmRemoveDevice` | N/A | The VM is booted
|
Add userspace PCI device to the VM | `/vm.add-user-device`| `/schemas/VmAddUserDevice`| `/schemas/PciDeviceInfo` | The VM is booted
|
||||||
Dump the VM counters | `/vm.counters` | N/A | `/schemas/VmCounters` | The VM is booted
|
Add vsock device to the VM | `/vm.add-vsock` | `/schemas/VsockConfig` | `/schemas/PciDeviceInfo` | The VM is booted
|
||||||
|
Remove device from the VM | `/vm.remove-device` | `/schemas/VmRemoveDevice` | N/A | The VM is booted
|
||||||
|
Dump the VM counters | `/vm.counters` | N/A | `/schemas/VmCounters` | The VM is booted
|
||||||
|
|
||||||
### REST API Examples
|
### REST API Examples
|
||||||
|
|
||||||
|
|||||||
108
docs/arm64.md
108
docs/arm64.md
@@ -1,58 +1,116 @@
|
|||||||
# How to build and run Cloud-hypervisor on AArch64
|
# How to build and test Cloud Hypervisor on AArch64
|
||||||
|
|
||||||
Cloud-hypervisor is partially enabled on AArch64 architecture.
|
This document introduces how to build and test Cloud Hypervisor on AArch64 servers. Currently Cloud Hypervisor cannot be tested on Raspberry PI. Because on AArch64, Cloud Hypervisor requires GICv3-ITS device for PCIe MSI interrupt handling. But GICv3-ITS has not been equipped on any Raspberry PI product so far.
|
||||||
Although all features are not ready yet, you can begin to test Cloud-hypervisor on a AArch64 host by following this guide.
|
|
||||||
|
Now Cloud Hypervisor supports 2 ways of booting on AArch64: UEFI booting and direct-kernel booting. The document covers both of the ways.
|
||||||
|
|
||||||
|
All the steps are based on Ubuntu. We use the Ubuntu cloud image for guest VM disk.
|
||||||
|
|
||||||
|
## Getting started
|
||||||
|
|
||||||
|
We create a folder to build and run Cloud Hypervisor at `$HOME/cloud-hypervisor`
|
||||||
|
|
||||||
|
```shell
|
||||||
|
$ export CLOUDH=$HOME/cloud-hypervisor
|
||||||
|
$ mkdir $CLOUDH
|
||||||
|
```
|
||||||
|
|
||||||
## Prerequisites
|
## Prerequisites
|
||||||
|
|
||||||
On AArch64 machines, Cloud-hypervisor depends on an external library `libfdt-dev` for generating Flattened Device Tree (FDT).
|
You need to install some prerequisite packages to build and test Cloud Hypervisor.
|
||||||
|
|
||||||
The long-term plan is to replace `libfdt-dev` with some pure-Rust component to get rid of such dependency.
|
### Tools
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
sudo apt-get update
|
# Install rust tool chain
|
||||||
sudo apt-get install libfdt-dev
|
$ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
|
||||||
|
# Install the tools used for building guest kernel, EDK2 and converting guest disk
|
||||||
|
$ sudo apt-get update
|
||||||
|
$ sudo apt-get install git build-essential m4 bison flex uuid-dev qemu-utils
|
||||||
```
|
```
|
||||||
|
|
||||||
## Build
|
### Building Cloud Hypervisor
|
||||||
|
|
||||||
Using PCI devices requires GICv3-ITS for MSI messaging. GICv3-ITS is very common in modern servers.
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cargo build --no-default-features --features kvm
|
$ pushd $CLOUDH
|
||||||
|
$ git clone https://github.com/cloud-hypervisor/cloud-hypervisor.git
|
||||||
|
$ cd cloud-hypervisor
|
||||||
|
$ cargo build
|
||||||
|
$ popd
|
||||||
```
|
```
|
||||||
|
|
||||||
## Image
|
### Disk image
|
||||||
|
|
||||||
Download kernel binary and rootfs image from AWS.
|
Download the Ubuntu cloud image and convert the image type.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
wget https://s3.amazonaws.com/spec.ccfc.min/img/aarch64/ubuntu_with_ssh/fsfiles/xenial.rootfs.ext4 -O rootfs.ext4
|
$ pushd $CLOUDH
|
||||||
wget https://s3.amazonaws.com/spec.ccfc.min/img/aarch64/ubuntu_with_ssh/kernel/vmlinux.bin -O kernel.bin
|
$ wget https://cloud-images.ubuntu.com/focal/current/focal-server-cloudimg-arm64.img
|
||||||
|
$ qemu-img convert -p -f qcow2 -O raw focal-server-cloudimg-arm64.img focal-server-cloudimg-arm64.raw
|
||||||
|
$ popd
|
||||||
```
|
```
|
||||||
|
|
||||||
## Containerized build
|
## UEFI booting
|
||||||
|
|
||||||
If you want to build and test Cloud Hypervisor without having to install all the required dependencies, you can also turn to the development script: dev_cli.sh.
|
This part introduces how to build EDK2 firmware and boot Cloud Hypervisor with it.
|
||||||
|
|
||||||
To build the development container:
|
### Building EDK2
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
./scripts/dev_cli.sh build-container
|
$ pushd $CLOUDH
|
||||||
|
|
||||||
|
# Clone source code repos
|
||||||
|
$ git clone --depth 1 https://github.com/tianocore/edk2.git -b master
|
||||||
|
$ cd edk2
|
||||||
|
$ git submodule update --init
|
||||||
|
$ cd ..
|
||||||
|
$ git clone --depth 1 https://github.com/tianocore/edk2-platforms.git -b master
|
||||||
|
$ git clone --depth 1 https://github.com/acpica/acpica.git -b master
|
||||||
|
|
||||||
|
# Build tools
|
||||||
|
$ export PACKAGES_PATH="$PWD/edk2:$PWD/edk2-platforms"
|
||||||
|
$ export IASL_PREFIX="$PWD/acpica/generate/unix/bin/"
|
||||||
|
$ make -C acpica
|
||||||
|
$ cd edk2/
|
||||||
|
$ . edksetup.sh
|
||||||
|
$ cd ..
|
||||||
|
$ make -C edk2/BaseTools
|
||||||
|
|
||||||
|
# Build EDK2
|
||||||
|
$ build -a AARCH64 -t GCC5 -p ArmVirtPkg/ArmVirtCloudHv.dsc -b RELEASE
|
||||||
|
|
||||||
|
$ popd
|
||||||
```
|
```
|
||||||
|
|
||||||
To build Cloud-hypervisor in the container:
|
If the build goes well, the EDK2 binary is available at `edk2/Build/ArmVirtCloudHv-AARCH64/RELEASE_GCC5/FV/CLOUDHV_EFI.fd`.
|
||||||
|
|
||||||
|
### Booting the guest VM
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
./scripts/dev_cli.sh build
|
$ pushd $CLOUDH
|
||||||
|
$ sudo RUST_BACKTRACE=1 $CLOUDH/cloud-hypervisor/target/debug/cloud-hypervisor --api-socket /tmp/cloud-hypervisor.sock --kernel $CLOUDH/edk2/edk2/Build/ArmVirtCloudHv-AARCH64/RELEASE_GCC5/FV/CLOUDHV_EFI.fd --disk path=$CLOUDH/focal-server-cloudimg-arm64.raw --cpus boot=4 --memory size=4096M --serial tty --console off --log-file log.log -vvv --net tap=,mac=12:34:56:78:90:01,ip=192.168.1.1,mask=255.255.255.0
|
||||||
|
$ popd
|
||||||
```
|
```
|
||||||
|
|
||||||
## Run
|
## Direct-kernel booting
|
||||||
|
|
||||||
Assuming you have built Cloud-hypervisor with the development container, a VM can be started with command:
|
Alternativelly, you can build your own kernel for guest VM. This way, UEFI is not involved and ACPI cannot be enabled.
|
||||||
|
|
||||||
|
### Building kernel
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
sudo build/cargo_target/aarch64-unknown-linux-gnu/debug/cloud-hypervisor --kernel kernel.bin --disk path=rootfs.ext4 --cmdline "keep_bootcon console=hvc0 reboot=k panic=1 root=/dev/vda rw" --cpus boot=4 --memory size=512M --serial file=serial.log --log-file log.log -vvv
|
$ pushd $CLOUDH
|
||||||
|
$ git clone --depth 1 "https://github.com/cloud-hypervisor/linux.git" -b ch-5.12
|
||||||
|
$ cd linux
|
||||||
|
$ cp $CLOUDH/cloud-hypervisor/resources/linux-config-aarch64 .config
|
||||||
|
$ make -j `nproc`
|
||||||
|
$ popd
|
||||||
```
|
```
|
||||||
|
|
||||||
If the build was done out of the container, replace the binary path with `target/debug/cloud-hypervisor`.
|
### Booting the guest VM
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ pushd $CLOUDH
|
||||||
|
$ sudo $CLOUDH/cloud-hypervisor/target/debug/cloud-hypervisor --api-socket /tmp/cloud-hypervisor.sock --kernel $CLOUDH/linux/arch/arm64/boot/Image --disk path=focal-server-cloudimg-arm64.raw --cmdline "keep_bootcon console=ttyAMA0 reboot=k panic=1 root=/dev/vda1 rw" --cpus boot=4 --memory size=4096M --serial tty --console off --log-file log.log -vvv --net "tap=,mac=,ip=,mask="
|
||||||
|
$ popd
|
||||||
|
```
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ Ubuntu distributions.
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
apt update
|
apt update
|
||||||
apt install fio iperf iperf3 socat
|
apt install fio iperf iperf3 socat stress
|
||||||
```
|
```
|
||||||
|
|
||||||
### Remove counterproductive packages
|
### Remove counterproductive packages
|
||||||
|
|||||||
@@ -20,10 +20,10 @@ cargo install cargo-fuzz
|
|||||||
|
|
||||||
## Running the fuzzers
|
## Running the fuzzers
|
||||||
|
|
||||||
e.g. To run the `qcow` fuzzer using all available CPUs:
|
e.g. To run the `block` fuzzer using all available CPUs:
|
||||||
|
|
||||||
```
|
```
|
||||||
cargo fuzz run qcow -j `nproc`
|
cargo fuzz run block -j `nproc`
|
||||||
```
|
```
|
||||||
|
|
||||||
## Adding a new fuzzer
|
## Adding a new fuzzer
|
||||||
@@ -32,4 +32,4 @@ cargo fuzz run qcow -j `nproc`
|
|||||||
cargo fuzz add <new_fuzzer>
|
cargo fuzz add <new_fuzzer>
|
||||||
```
|
```
|
||||||
|
|
||||||
Inspiration for fuzzers can be found in [crosvm](https://chromium.googlesource.com/chromiumos/platform/crosvm/+/refs/heads/master/fuzz/)
|
Inspiration for fuzzers can be found in [crosvm](https://chromium.googlesource.com/chromiumos/platform/crosvm/+/refs/heads/master/fuzz/)
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ $ ./cloud-hypervisor/target/release/cloud-hypervisor \
|
|||||||
$ popd
|
$ popd
|
||||||
```
|
```
|
||||||
|
|
||||||
Notice the addition of `--api-socket=/tmp/ch-socket` and a `max` parameter on `--cpus boot=4.max=8`.
|
Notice the addition of `--api-socket=/tmp/ch-socket` and a `max` parameter on `--cpus boot=4,max=8`.
|
||||||
|
|
||||||
To ask the VMM to add additional vCPUs then use the resize API:
|
To ask the VMM to add additional vCPUs then use the resize API:
|
||||||
|
|
||||||
@@ -159,6 +159,8 @@ The same API can also be used to reduce the desired RAM for a VM. It is importan
|
|||||||
|
|
||||||
Extra PCI devices can be added and removed from a running Cloud Hypervisor instance. This is controlled by making a HTTP API request to the VMM to ask for the additional device to be added, or for the existing device to be removed.
|
Extra PCI devices can be added and removed from a running Cloud Hypervisor instance. This is controlled by making a HTTP API request to the VMM to ask for the additional device to be added, or for the existing device to be removed.
|
||||||
|
|
||||||
|
Note: On AArch64 platform, PCI device hotplug can only be achieved using ACPI. Please refer to the [documentation](arm64.md#uefi-booting) for more information.
|
||||||
|
|
||||||
To use PCI device hotplug start the VM with the HTTP server.
|
To use PCI device hotplug start the VM with the HTTP server.
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ following [instructions](https://github.com/intel/linux-sgx).
|
|||||||
|
|
||||||
## Cloud-Hypervisor support
|
## Cloud-Hypervisor support
|
||||||
|
|
||||||
Assuming the host exposes `/dev/sgx_virt_epc`, we can pass SGX enclaves through
|
Assuming the host exposes `/dev/sgx_vepc`, we can pass SGX enclaves through
|
||||||
the guest.
|
the guest.
|
||||||
|
|
||||||
In order to use SGX enclaves within a Cloud-Hypervisor VM, we must define one
|
In order to use SGX enclaves within a Cloud-Hypervisor VM, we must define one
|
||||||
@@ -34,7 +34,7 @@ memory, the second one being 32MiB with no pre-allocated memory.
|
|||||||
--disk path=focal-server-cloudimg-amd64.raw \
|
--disk path=focal-server-cloudimg-amd64.raw \
|
||||||
--kernel vmlinux \
|
--kernel vmlinux \
|
||||||
--cmdline "console=ttyS0 console=hvc0 root=/dev/vda1 rw" \
|
--cmdline "console=ttyS0 console=hvc0 root=/dev/vda1 rw" \
|
||||||
--sgx-epc size=64M,prefault=on size=32M,prefault=off
|
--sgx-epc id=epc0,size=64M,prefault=on id=epc1,size=32M,prefault=off
|
||||||
```
|
```
|
||||||
|
|
||||||
Once booted, and assuming your guest kernel contains the patches from the
|
Once booted, and assuming your guest kernel contains the patches from the
|
||||||
@@ -43,7 +43,7 @@ have been correctly created under `/dev/sgx`:
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
ls /dev/sgx*
|
ls /dev/sgx*
|
||||||
/dev/sgx_enclave /dev/sgx_provision /dev/sgx_virt_epc
|
/dev/sgx_enclave /dev/sgx_provision /dev/sgx_vepc
|
||||||
```
|
```
|
||||||
|
|
||||||
From this point, it is possible to run any SGX application from the guest, as
|
From this point, it is possible to run any SGX application from the guest, as
|
||||||
@@ -51,5 +51,5 @@ it will access `/dev/sgx_enclave` device to create dedicated SGX enclaves.
|
|||||||
|
|
||||||
Note: There is only one contiguous SGX EPC region, which contains all SGX EPC
|
Note: There is only one contiguous SGX EPC region, which contains all SGX EPC
|
||||||
sections. This region is exposed through ACPI and marked as reserved through
|
sections. This region is exposed through ACPI and marked as reserved through
|
||||||
the e820 table. It is treated yet as another device, which means it should
|
the e820 table. It is treated as yet another device, which means it should
|
||||||
appear at the end of the guest address space.
|
appear at the end of the guest address space.
|
||||||
|
|||||||
@@ -121,6 +121,29 @@ lspci
|
|||||||
00:04.0 Unassigned class [ffff]: Red Hat, Inc. Virtio RNG
|
00:04.0 Unassigned class [ffff]: Red Hat, Inc. Virtio RNG
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Work with FDT on AArch64
|
||||||
|
|
||||||
|
On AArch64 architecture, the virtual IOMMU can still be used even if ACPI is not
|
||||||
|
enabled. But the effect is different with what the aforementioned test showed.
|
||||||
|
|
||||||
|
When ACPI is disabled, virtual IOMMU is supported through Flattened Device Tree
|
||||||
|
(FDT). In this case, the guest kernel can not tell which device should be
|
||||||
|
IOMMU-attached and which should not. No matter how many devices you attached to
|
||||||
|
the virtual IOMMU by setting `iommu=on` option, all the devices on the PCI bus
|
||||||
|
will be attached to the virtual IOMMU (except the IOMMU itself). Each of the
|
||||||
|
devices will be added into a IOMMU group.
|
||||||
|
|
||||||
|
As a result, the directory content of `/sys/kernel/iommu_groups` would be:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ls /sys/kernel/iommu_groups/0/devices/
|
||||||
|
0000:00:02.0
|
||||||
|
ls /sys/kernel/iommu_groups/1/devices/
|
||||||
|
0000:00:03.0
|
||||||
|
ls /sys/kernel/iommu_groups/2/devices/
|
||||||
|
0000:00:04.0
|
||||||
|
```
|
||||||
|
|
||||||
## Faster mappings
|
## Faster mappings
|
||||||
|
|
||||||
By default, the guest memory is mapped with 4k pages and no huge pages, which
|
By default, the guest memory is mapped with 4k pages and no huge pages, which
|
||||||
|
|||||||
139
docs/live_migration.md
Normal file
139
docs/live_migration.md
Normal file
@@ -0,0 +1,139 @@
|
|||||||
|
# Live Migration
|
||||||
|
|
||||||
|
This document gives two examples of how to use the live migration
|
||||||
|
support in Cloud Hypervisor:
|
||||||
|
|
||||||
|
1. local migration - migrating between two VMs running on the same
|
||||||
|
machine;
|
||||||
|
1. nested-vm migration - migrating between two nested VMs whose host VMs
|
||||||
|
are running on the same machine.
|
||||||
|
|
||||||
|
## Local Migration
|
||||||
|
Launch the source VM (on the host machine):
|
||||||
|
```bash
|
||||||
|
$ target/release/cloud-hypervisor
|
||||||
|
--kernel ~/workloads/vmlinux \
|
||||||
|
--disk path=~/workloads/focal.raw \
|
||||||
|
--cpus boot=1 --memory size=1G \
|
||||||
|
--cmdline "root=/dev/vda1 console=ttyS0" \
|
||||||
|
--serial tty --console off --api-socket=/tmp/api1
|
||||||
|
```
|
||||||
|
|
||||||
|
Launch the destination VM from the same directory (on the host machine):
|
||||||
|
```bash
|
||||||
|
$ target/release/cloud-hypervisor --api-socket=/tmp/api2
|
||||||
|
```
|
||||||
|
|
||||||
|
Get ready for receiving migration for the destination VM (on the host machine):
|
||||||
|
```bash
|
||||||
|
$ target/release/ch-remote --api-socket=/tmp/api2 receive-migration unix:/tmp/sock
|
||||||
|
```
|
||||||
|
|
||||||
|
Start to send migration for the source VM (on the host machine):
|
||||||
|
```bash
|
||||||
|
$ target/release/ch-remote --api-socket=/tmp/api1 send-migration unix:/tmp/sock
|
||||||
|
```
|
||||||
|
|
||||||
|
When the above commands completed, the source VM should be successfully
|
||||||
|
migrated to the destination VM. Now the destination VM is running while
|
||||||
|
the source VM is terminated gracefully.
|
||||||
|
|
||||||
|
## Nested-VM Migration
|
||||||
|
|
||||||
|
Launch VM 1 (on the host machine) with an extra virtio-blk device for
|
||||||
|
exposing a guest image for the nested source VM:
|
||||||
|
> Note: the example below also attached an additional virtio-blk device
|
||||||
|
> with a dummy image for testing purpose (which is optional).
|
||||||
|
```bash
|
||||||
|
$ head -c 1M < /dev/urandom > tmp.img # create a dummy image for testing
|
||||||
|
$ sudo /target/release/cloud-hypervisor \
|
||||||
|
--serial tty --console off \
|
||||||
|
--cpus boot=1 --memory size=512M \
|
||||||
|
--kernel vmlinux \
|
||||||
|
--cmdline "root=/dev/vda1 console=ttyS0" \
|
||||||
|
--disk path=focal-1.raw path=focal-nested.raw path=tmp.img\
|
||||||
|
--net ip=192.168.101.1
|
||||||
|
```
|
||||||
|
|
||||||
|
Launch VM 2 (on the host machine) with an extra virtio-blk device for
|
||||||
|
exposing the same guest image for the nested destination VM:
|
||||||
|
```bash
|
||||||
|
$ sudo /target/release/cloud-hypervisor \
|
||||||
|
--serial tty --console off \
|
||||||
|
--cpus boot=1 --memory size=512M \
|
||||||
|
--kernel vmlinux \
|
||||||
|
--cmdline "root=/dev/vda1 console=ttyS0" \
|
||||||
|
--disk path=focal-2.raw path=focal-nested.raw path=tmp.img\
|
||||||
|
--net ip=192.168.102.1
|
||||||
|
```
|
||||||
|
|
||||||
|
Launch the nested source VM (inside the guest OS of the VM 1) :
|
||||||
|
```bash
|
||||||
|
vm-1:~$ sudo ./cloud-hypervisor \
|
||||||
|
--serial tty --console off \
|
||||||
|
--memory size=128M \
|
||||||
|
--kernel vmlinux \
|
||||||
|
--cmdline "console=ttyS0 root=/dev/vda1" \
|
||||||
|
--disk path=/dev/vdb path=/dev/vdc \
|
||||||
|
--api-socket=/tmp/api1 \
|
||||||
|
--net ip=192.168.100.1
|
||||||
|
vm-1:~$ # setup the guest network if needed
|
||||||
|
vm-1:~$ sudo ip addr add 192.168.101.2/24 dev ens4
|
||||||
|
vm-1:~$ sudo ip link set up dev ens4
|
||||||
|
vm-1:~$ sudo ip r add default via 192.168.101.1
|
||||||
|
```
|
||||||
|
Optional: Run the guest workload below (on the guest OS of the nested source VM),
|
||||||
|
which performs intensive virtio-blk operations. Now the console of the nested
|
||||||
|
source VM should repeatedly print `"equal"`, and our goal is migrating
|
||||||
|
this VM and the running workload without interruption.
|
||||||
|
```bash
|
||||||
|
#/bin/bash
|
||||||
|
|
||||||
|
# On the guest OS of the nested source VM
|
||||||
|
|
||||||
|
input="/dev/vdb"
|
||||||
|
result=$(md5sum $input)
|
||||||
|
tmp=$(md5sum $input)
|
||||||
|
|
||||||
|
while [[ "$result" == "$tmp" ]]
|
||||||
|
do
|
||||||
|
echo "equal"
|
||||||
|
tmp=$(md5sum $input)
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "not equal"
|
||||||
|
echo "result = $result"
|
||||||
|
echo "tmp = $tmp"
|
||||||
|
```
|
||||||
|
|
||||||
|
Launch the nested destination VM (inside the guest OS of the VM 2):
|
||||||
|
```bash
|
||||||
|
vm-2:~$ sudo ./cloud-hypervisor --api-socket=/tmp/api2
|
||||||
|
vm-2:~$ # setup the guest network with the following commands if needed
|
||||||
|
vm-2:~$ sudo ip addr add 192.168.102.2/24 dev ens4
|
||||||
|
vm-2:~$ sudo ip link set up dev ens4
|
||||||
|
vm-2:~$ sudo ip r add default via 192.168.102.1
|
||||||
|
vm-2:~$ ping 192.168.101.2 # This should succeed
|
||||||
|
```
|
||||||
|
> Note: If the above ping failed, please check the iptables rule on the
|
||||||
|
> host machine, e.g. whether the policy for the `FORWARD` chain is set
|
||||||
|
> to `DROP` (which is the default setting configured by Docker).
|
||||||
|
|
||||||
|
Get ready for receiving migration for the nested destination VM (inside
|
||||||
|
the guest OS of the VM 2):
|
||||||
|
```bash
|
||||||
|
vm-2:~$ sudo ./ch-remote --api-socket=/tmp/api2 receive-migration unix:/tmp/sock2
|
||||||
|
vm-2:~$ sudo socat TCP-LISTEN:6000,reuseaddr UNIX-CLIENT:/tmp/sock2
|
||||||
|
```
|
||||||
|
|
||||||
|
Start to send migration for the nested source VM (inside the guest OS of
|
||||||
|
the VM 1):
|
||||||
|
```bash
|
||||||
|
vm-1:~$ sudo socat UNIX-LISTEN:/tmp/sock1,reuseaddr TCP:192.168.102.2:6000
|
||||||
|
vm-1:~$ sudo ./ch-remote --api-socket=/tmp/api1 send-migration unix:/tmp/sock1
|
||||||
|
```
|
||||||
|
|
||||||
|
When the above commands completed, the source VM should be successfully
|
||||||
|
migrated to the destination VM without interrupting our testing guest
|
||||||
|
workload. Now the destination VM is running the testing guest workload
|
||||||
|
while the source VM is terminated gracefully.
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
# Using MACVTAP to Bridge onto Host Network
|
# Using MACVTAP to Bridge onto Host Network
|
||||||
|
|
||||||
Cloud Hypervisor supports using a MACVTAP device which is derived from a MACVLAN. Full details of configuring MACVLAN or MACVTAP is out of scope of this document. However the example below indicates how to bridge the guest directly onto the the network the host is on. Due to the lack of hairpin mode it not usually possible to reach the guest directly from the host.
|
Cloud Hypervisor supports using a MACVTAP device which is derived from a MACVLAN. Full details of configuring MACVLAN or MACVTAP is out of scope of this document. However the example below indicates how to bridge the guest directly onto the network the host is on. Due to the lack of hairpin mode it not usually possible to reach the guest directly from the host.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# The MAC address must be attached to the macvtap and be used inside the guest
|
# The MAC address must be attached to the macvtap and be used inside the guest
|
||||||
|
|||||||
204
docs/memory.md
204
docs/memory.md
@@ -13,18 +13,19 @@ easiest way to get started with Cloud-Hypervisor.
|
|||||||
struct MemoryConfig {
|
struct MemoryConfig {
|
||||||
size: u64,
|
size: u64,
|
||||||
mergeable: bool,
|
mergeable: bool,
|
||||||
shared: bool,
|
|
||||||
hugepages: bool,
|
|
||||||
hugepage_size: Option<u64>,
|
|
||||||
hotplug_method: HotplugMethod,
|
hotplug_method: HotplugMethod,
|
||||||
hotplug_size: Option<u64>,
|
hotplug_size: Option<u64>,
|
||||||
hotplugged_size: Option<u64>,
|
hotplugged_size: Option<u64>,
|
||||||
|
shared: bool,
|
||||||
|
hugepages: bool,
|
||||||
|
hugepage_size: Option<u64>,
|
||||||
|
prefault: bool,
|
||||||
zones: Option<Vec<MemoryZoneConfig>>,
|
zones: Option<Vec<MemoryZoneConfig>>,
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
```
|
```
|
||||||
--memory <memory> Memory parameters "size=<guest_memory_size>,mergeable=on|off,shared=on|off,hugepages=on|off,hotplug_method=acpi|virtio-mem,hotplug_size=<hotpluggable_memory_size>,hotplugged_size=<hotplugged_memory_size>"
|
--memory <memory> Memory parameters "size=<guest_memory_size>,mergeable=on|off,shared=on|off,hugepages=on|off,hugepage_size=<hugepage_size>,hotplug_method=acpi|virtio-mem,hotplug_size=<hotpluggable_memory_size>,hotplugged_size=<hotplugged_memory_size>,prefault=on|off" [default: size=512M]
|
||||||
```
|
```
|
||||||
|
|
||||||
### `size`
|
### `size`
|
||||||
@@ -59,44 +60,6 @@ _Example_
|
|||||||
--memory size=1G,mergeable=on
|
--memory size=1G,mergeable=on
|
||||||
```
|
```
|
||||||
|
|
||||||
### `shared`
|
|
||||||
|
|
||||||
Specifies if the memory must be `mmap(2)` with `MAP_SHARED` flag.
|
|
||||||
|
|
||||||
By sharing a memory mapping, one can share the guest RAM with other processes
|
|
||||||
running on the host. One can use this option when running vhost-user devices
|
|
||||||
as part of the VM device model, as they will be driven by standalone daemons
|
|
||||||
needing access to the guest RAM content.
|
|
||||||
|
|
||||||
By default this option is turned off, which results in performing `mmap(2)`
|
|
||||||
with `MAP_PRIVATE` flag.
|
|
||||||
|
|
||||||
_Example_
|
|
||||||
|
|
||||||
```
|
|
||||||
--memory size=1G,shared=on
|
|
||||||
```
|
|
||||||
|
|
||||||
### `hugepages` and `hugepage_size`
|
|
||||||
|
|
||||||
Specifies if the memory must be created and `mmap(2)` with `MAP_HUGETLB` and size
|
|
||||||
flags. This performs a memory mapping relying on the specified huge page size. If no huge page size is supplied the system's default huge page size is used.
|
|
||||||
|
|
||||||
By using hugepages, one can improve the overall performance of the VM, assuming
|
|
||||||
the guest will allocate hugepages as well. Another interesting use case is VFIO
|
|
||||||
as it speeds up the VM's boot time since the amount of IOMMU mappings are
|
|
||||||
reduced.
|
|
||||||
|
|
||||||
The user is responsible for ensuring there are sufficient huge pages of the specified size for the VMM to use. Failure to do so may result in strange VMM behaviour.
|
|
||||||
|
|
||||||
By default this option is turned off.
|
|
||||||
|
|
||||||
_Example_
|
|
||||||
|
|
||||||
```
|
|
||||||
--memory size=1G,hugepages=on,hugepage_size=2M
|
|
||||||
```
|
|
||||||
|
|
||||||
### `hotplug_method`
|
### `hotplug_method`
|
||||||
|
|
||||||
Selects the way of adding and/or removing memory to/from a booted VM.
|
Selects the way of adding and/or removing memory to/from a booted VM.
|
||||||
@@ -142,6 +105,72 @@ _Example_
|
|||||||
--memory size=1G,hotplug_method=virtio-mem,hotplug_size=1G,hotplugged_size=512M
|
--memory size=1G,hotplug_method=virtio-mem,hotplug_size=1G,hotplugged_size=512M
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### `shared`
|
||||||
|
|
||||||
|
Specifies if the memory must be `mmap(2)` with `MAP_SHARED` flag.
|
||||||
|
|
||||||
|
By sharing a memory mapping, one can share the guest RAM with other processes
|
||||||
|
running on the host. One can use this option when running vhost-user devices
|
||||||
|
as part of the VM device model, as they will be driven by standalone daemons
|
||||||
|
needing access to the guest RAM content.
|
||||||
|
|
||||||
|
By default this option is turned off, which results in performing `mmap(2)`
|
||||||
|
with `MAP_PRIVATE` flag.
|
||||||
|
|
||||||
|
_Example_
|
||||||
|
|
||||||
|
```
|
||||||
|
--memory size=1G,shared=on
|
||||||
|
```
|
||||||
|
|
||||||
|
### `hugepages` and `hugepage_size`
|
||||||
|
|
||||||
|
Specifies if the memory must be created and `mmap(2)` with `MAP_HUGETLB` and size
|
||||||
|
flags. This performs a memory mapping relying on the specified huge page size.
|
||||||
|
If no huge page size is supplied the system's default huge page size is used.
|
||||||
|
|
||||||
|
By using hugepages, one can improve the overall performance of the VM, assuming
|
||||||
|
the guest will allocate hugepages as well. Another interesting use case is VFIO
|
||||||
|
as it speeds up the VM's boot time since the amount of IOMMU mappings are
|
||||||
|
reduced.
|
||||||
|
|
||||||
|
The user is responsible for ensuring there are sufficient huge pages of the
|
||||||
|
specified size for the VMM to use. Failure to do so may result in strange VMM
|
||||||
|
behaviour, e.g. error with `ReadKernelImage` is common. If there is a strange
|
||||||
|
error with `hugepages` enabled, just disable it or check whether there are enough
|
||||||
|
huge pages.
|
||||||
|
|
||||||
|
By default this option is turned off.
|
||||||
|
|
||||||
|
_Example_
|
||||||
|
|
||||||
|
```
|
||||||
|
--memory size=1G,hugepages=on,hugepage_size=2M
|
||||||
|
```
|
||||||
|
|
||||||
|
### `prefault`
|
||||||
|
|
||||||
|
Specifies if the memory must be `mmap(2)` with `MAP_POPULATE` flag.
|
||||||
|
|
||||||
|
By triggering prefault, one can allocate all required physical memory and create
|
||||||
|
its page tables while calling `mmap`. With physical memory allocated, the number
|
||||||
|
of page faults will decrease during running, and performance will also improve.
|
||||||
|
|
||||||
|
Note that boot of VM will be slower with `prefault` enabled because of allocating
|
||||||
|
physical memory and creating page tables in advance, and physical memory of the
|
||||||
|
specified size will be consumed quickly.
|
||||||
|
|
||||||
|
This option only takes effect at boot of VM. There is also a `prefault` option in
|
||||||
|
restore and its choice will overwrite `prefault` in memory.
|
||||||
|
|
||||||
|
By default this option is turned off.
|
||||||
|
|
||||||
|
_Example_
|
||||||
|
|
||||||
|
```
|
||||||
|
--memory size=1G,prefault=on
|
||||||
|
```
|
||||||
|
|
||||||
## Advanced Parameters
|
## Advanced Parameters
|
||||||
|
|
||||||
`MemoryZoneConfig` or what is known as `--memory-zone` from the CLI perspective
|
`MemoryZoneConfig` or what is known as `--memory-zone` from the CLI perspective
|
||||||
@@ -155,14 +184,16 @@ struct MemoryZoneConfig {
|
|||||||
file: Option<PathBuf>,
|
file: Option<PathBuf>,
|
||||||
shared: bool,
|
shared: bool,
|
||||||
hugepages: bool,
|
hugepages: bool,
|
||||||
|
hugepage_size: Option<u64>,
|
||||||
host_numa_node: Option<u32>,
|
host_numa_node: Option<u32>,
|
||||||
hotplug_size: Option<u64>,
|
hotplug_size: Option<u64>,
|
||||||
hotplugged_size: Option<u64>,
|
hotplugged_size: Option<u64>,
|
||||||
|
prefault: bool,
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
```
|
```
|
||||||
--memory-zone <memory-zone> User defined memory zone parameters "size=<guest_memory_region_size>,file=<backing_file>,shared=on|off,hugepages=on|off,host_numa_node=<node_id>,id=<zone_identifier>,hotplug_size=<hotpluggable_memory_size>,hotplugged_size=<hotplugged_memory_size>"
|
--memory-zone <memory-zone> User defined memory zone parameters "size=<guest_memory_region_size>,file=<backing_file>,shared=on|off,hugepages=on|off,hugepage_size=<hugepage_size>,host_numa_node=<node_id>,id=<zone_identifier>,hotplug_size=<hotpluggable_memory_size>,hotplugged_size=<hotplugged_memory_size>,prefault=on|off"
|
||||||
```
|
```
|
||||||
|
|
||||||
This parameter expects one or more occurences, allowing for a list of memory
|
This parameter expects one or more occurences, allowing for a list of memory
|
||||||
@@ -250,24 +281,30 @@ _Example_
|
|||||||
--memory-zone id=mem0,size=1G,shared=on
|
--memory-zone id=mem0,size=1G,shared=on
|
||||||
```
|
```
|
||||||
|
|
||||||
### `hugepages`
|
### `hugepages` and `hugepage_size`
|
||||||
|
|
||||||
Specifies if the memory zone must be `mmap(2)` with `MAP_HUGETLB` and
|
Specifies if the memory must be created and `mmap(2)` with `MAP_HUGETLB` and size
|
||||||
`MAP_HUGE_2MB` flags. This performs a memory zone mapping relying on 2MiB
|
flags. This performs a memory mapping relying on the specified huge page size.
|
||||||
pages instead of the default 4kiB pages.
|
If no huge page size is supplied the system's default huge page size is used.
|
||||||
|
|
||||||
By using hugepages, one can improve the overall performance of the VM, assuming
|
By using hugepages, one can improve the overall performance of the VM, assuming
|
||||||
the guest will allocate hugepages as well. Another interesting use case is VFIO
|
the guest will allocate hugepages as well. Another interesting use case is VFIO
|
||||||
as it speeds up the VM's boot time since the amount of IOMMU mappings are
|
as it speeds up the VM's boot time since the amount of IOMMU mappings are
|
||||||
reduced.
|
reduced.
|
||||||
|
|
||||||
|
The user is responsible for ensuring there are sufficient huge pages of the
|
||||||
|
specified size for the VMM to use. Failure to do so may result in strange VMM
|
||||||
|
behaviour, e.g. error with `ReadKernelImage` is common. If there is a strange
|
||||||
|
error with `hugepages` enabled, just disable it or check whether there are enough
|
||||||
|
huge pages.
|
||||||
|
|
||||||
By default this option is turned off.
|
By default this option is turned off.
|
||||||
|
|
||||||
_Example_
|
_Example_
|
||||||
|
|
||||||
```
|
```
|
||||||
--memory size=0
|
--memory size=0
|
||||||
--memory-zone id=mem0,size=1G,hugepages=on
|
--memory-zone id=mem0,size=1G,hugepages=on,hugepage_size=2M
|
||||||
```
|
```
|
||||||
|
|
||||||
### `host_numa_node`
|
### `host_numa_node`
|
||||||
@@ -334,6 +371,30 @@ _Example_
|
|||||||
--memory-zone id=mem0,size=1G,hotplug_size=1G,hotplugged_size=512M
|
--memory-zone id=mem0,size=1G,hotplug_size=1G,hotplugged_size=512M
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### `prefault`
|
||||||
|
|
||||||
|
Specifies if the memory must be `mmap(2)` with `MAP_POPULATE` flag.
|
||||||
|
|
||||||
|
By triggering prefault, one can allocate all required physical memory and create
|
||||||
|
its page tables while calling `mmap`. With physical memory allocated, the number
|
||||||
|
of page faults will decrease during running, and performance will also improve.
|
||||||
|
|
||||||
|
Note that boot of VM will be slower with `prefault` enabled because of allocating
|
||||||
|
physical memory and creating page tables in advance, and physical memory of the
|
||||||
|
specified size will be consumed quickly.
|
||||||
|
|
||||||
|
This option only takes effect at boot of VM. There is also a `prefault` option in
|
||||||
|
restore and its choice will overwrite `prefault` in memory.
|
||||||
|
|
||||||
|
By default this option is turned off.
|
||||||
|
|
||||||
|
_Example_
|
||||||
|
|
||||||
|
```
|
||||||
|
--memory size=0
|
||||||
|
--memory-zone id=mem0,size=1G,prefault=on
|
||||||
|
```
|
||||||
|
|
||||||
## NUMA settings
|
## NUMA settings
|
||||||
|
|
||||||
`NumaConfig` or what is known as `--numa` from the CLI perspective has been
|
`NumaConfig` or what is known as `--numa` from the CLI perspective has been
|
||||||
@@ -343,15 +404,16 @@ it allows for specifying the distance between each NUMA node.
|
|||||||
|
|
||||||
```rust
|
```rust
|
||||||
struct NumaConfig {
|
struct NumaConfig {
|
||||||
id: u32,
|
guest_numa_id: u32,
|
||||||
cpus: Option<Vec<u8>>,
|
cpus: Option<Vec<u8>>,
|
||||||
distances: Option<Vec<NumaDistance>>,
|
distances: Option<Vec<NumaDistance>>,
|
||||||
memory_zones: Option<Vec<String>>,
|
memory_zones: Option<Vec<String>>,
|
||||||
|
sgx_epc_sections: Option<Vec<String>>,
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
```
|
```
|
||||||
--numa <numa> Settings related to a given NUMA node "id=<node_id>,cpus=<cpus_id>,distances=<list_of_distances_to_destination_nodes>,memory_zones=<list_of_memory_zones>"
|
--numa <numa> Settings related to a given NUMA node "guest_numa_id=<node_id>,cpus=<cpus_id>,distances=<list_of_distances_to_destination_nodes>,memory_zones=<list_of_memory_zones>,sgx_epc_sections=<list_of_sgx_epc_sections>"
|
||||||
```
|
```
|
||||||
|
|
||||||
### `guest_numa_id`
|
### `guest_numa_id`
|
||||||
@@ -394,8 +456,7 @@ _Example_
|
|||||||
|
|
||||||
```
|
```
|
||||||
--cpus boot=8
|
--cpus boot=8
|
||||||
--numa guest_numa_id=0,cpus=1-3:7
|
--numa guest_numa_id=0,cpus=1-3:7 guest_numa_id=1,cpus=0:4-6
|
||||||
--numa guest_numa_id=1,cpus=0:4-6
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### `distances`
|
### `distances`
|
||||||
@@ -420,9 +481,7 @@ different distances, it can be described with the following example.
|
|||||||
_Example_
|
_Example_
|
||||||
|
|
||||||
```
|
```
|
||||||
--numa guest_numa_id=0,distances=1@15:2@25
|
--numa guest_numa_id=0,distances=1@15:2@25 guest_numa_id=1,distances=0@15:2@20 guest_numa_id=2,distances=0@25:1@20
|
||||||
--numa guest_numa_id=1,distances=0@15:2@20
|
|
||||||
--numa guest_numa_id=2,distances=0@25:1@20
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### `memory_zones`
|
### `memory_zones`
|
||||||
@@ -441,13 +500,38 @@ Multiple values can be provided to define the list. Each value is a string
|
|||||||
referring to an existing memory zone identifier. Values are separated from
|
referring to an existing memory zone identifier. Values are separated from
|
||||||
each other with the `:` separator.
|
each other with the `:` separator.
|
||||||
|
|
||||||
|
Note that a memory zone must belong to a single NUMA node. The following
|
||||||
|
configuration is incorrect, therefore not allowed:
|
||||||
|
`--numa guest_numa_id=0,memory_zones=mem0 guest_numa_id=1,memory_zones=mem0`
|
||||||
|
|
||||||
_Example_
|
_Example_
|
||||||
|
|
||||||
```
|
```
|
||||||
--memory size=0
|
--memory size=0
|
||||||
--memory-zone id=mem0,size=1G
|
--memory-zone id=mem0,size=1G id=mem1,size=1G id=mem2,size=1G
|
||||||
--memory-zone id=mem1,size=1G
|
--numa guest_numa_id=0,memory_zones=mem0:mem2 guest_numa_id=1,memory_zones=mem1
|
||||||
--memory-zone id=mem2,size=1G
|
|
||||||
--numa guest_numa_id=0,memory_zones=mem0:mem2
|
|
||||||
--numa guest_numa_id=1,memory_zones=mem1
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### `sgx_epc_sections`
|
||||||
|
|
||||||
|
List of SGX EPC sections attached to the guest NUMA node identified by the
|
||||||
|
`guest_numa_id` option. This allows for describing a list of SGX EPC sections
|
||||||
|
which must be seen by the guest as belonging to the NUMA node `guest_numa_id`.
|
||||||
|
|
||||||
|
Multiple values can be provided to define the list. Each value is a string
|
||||||
|
referring to an existing SGX EPC section identifier. Values are separated from
|
||||||
|
each other with the `:` separator.
|
||||||
|
|
||||||
|
_Example_
|
||||||
|
|
||||||
|
```
|
||||||
|
--sgx-epc id=epc0,size=32M id=epc1,size=64M id=epc2,size=32M
|
||||||
|
--numa guest_numa_id=0,sgx_epc_sections=epc1 guest_numa_id=1,sgx_epc_sections=epc0:epc2
|
||||||
|
```
|
||||||
|
|
||||||
|
### PCI bus
|
||||||
|
|
||||||
|
Cloud Hypervisor supports only one PCI bus, which is why it has been tied to
|
||||||
|
the NUMA node 0 by default. It is the user responsibility to organize the NUMA
|
||||||
|
nodes correctly so that vCPUs and guest RAM which should be located on the same
|
||||||
|
NUMA node as the PCI bus end up on the NUMA node 0.
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# Profiling
|
# Profiling
|
||||||
|
|
||||||
`perf` can be used to profile the `cloud-hypervisor` binary but it is necessary to make some modifications to the the build in order to produce a binary that gives useful results.
|
`perf` can be used to profile the `cloud-hypervisor` binary but it is necessary to make some modifications to the build in order to produce a binary that gives useful results.
|
||||||
|
|
||||||
## Building a suitable binary
|
## Building a suitable binary
|
||||||
|
|
||||||
|
|||||||
@@ -41,19 +41,20 @@ CSM is a module that allows to boot legacy operating systems using the OVMF firm
|
|||||||
|
|
||||||
```shell
|
```shell
|
||||||
sudo apt-get update
|
sudo apt-get update
|
||||||
sudo apt-get install uuid-dev nasm iasl build-essential python3-distutils git
|
sudo apt-get install uuid-dev nasm iasl build-essential python3-distutils git libncurses-dev
|
||||||
|
|
||||||
git checkout https://github.com/cloud-hypervisor/seabios -b ch
|
git clone https://github.com/cloud-hypervisor/seabios -b ch
|
||||||
cd seabios
|
cd seabios
|
||||||
make menuconfig
|
make menuconfig
|
||||||
# Enable `CONFIG_CSM` and `CONFIG_QEMU_HARDWARE`
|
# Enable `CONFIG_CSM` and `CONFIG_QEMU_HARDWARE`
|
||||||
|
# Please make sure `python` is in your path
|
||||||
make CONFIG_CSM=y CONFIG_QEMU_HARDWARE=y
|
make CONFIG_CSM=y CONFIG_QEMU_HARDWARE=y
|
||||||
cd ..
|
cd ..
|
||||||
|
|
||||||
git clone https://github.com/cloud-hypervisor/edk2 -b ch
|
git clone https://github.com/cloud-hypervisor/edk2 -b ch
|
||||||
cd edk2
|
cd edk2
|
||||||
. edksetup.sh
|
. edksetup.sh
|
||||||
git submodule update --init
|
git submodule update --init --recursive
|
||||||
cp ../seabios/out/Csm16.bin OvmfPkg/Csm/Csm16/
|
cp ../seabios/out/Csm16.bin OvmfPkg/Csm/Csm16/
|
||||||
|
|
||||||
echo "ACTIVE_PLATFORM=OvmfPkg/OvmfCh.dsc" >> Conf/target.txt
|
echo "ACTIVE_PLATFORM=OvmfPkg/OvmfCh.dsc" >> Conf/target.txt
|
||||||
@@ -61,7 +62,7 @@ echo "TARGET_ARCH=X64" >> Conf/target.txt
|
|||||||
echo "TOOL_CHAIN_TAG=GCC5" >> Conf/target.txt
|
echo "TOOL_CHAIN_TAG=GCC5" >> Conf/target.txt
|
||||||
|
|
||||||
make -C ./BaseTools
|
make -C ./BaseTools
|
||||||
build
|
build -DCSM_ENABLE
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
77
docs/vfio-user.md
Normal file
77
docs/vfio-user.md
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
# Cloud Hypervisor VFIO-user HOWTO
|
||||||
|
|
||||||
|
VFIO-user is an *experimental* protocol for allowing devices to be implemented in another process and communicate over a socket; ie.e VFIO-user is to VFIO as virtio is to vhost-user.
|
||||||
|
|
||||||
|
The protocol is documented here: https://github.com/nutanix/libvfio-user/blob/master/docs/vfio-user.rst
|
||||||
|
|
||||||
|
The Cloud Hypervisor support for such devices is *experimental*. Not all Cloud Hypervisor functionality is supported in particular: virtio-mem and iommu are not supported.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
The `--user-device socket=<path>` parameter is used to create a vfio-user device when creating the VM specifying the socket to connect to. The device can also be hotplugged with `ch-remote add-user-device socket=<path>`.
|
||||||
|
|
||||||
|
## Example (GPIO device)
|
||||||
|
|
||||||
|
There is a simple GPIO device included in the libvfio-user repository: https://github.com/nutanix/libvfio-user#gpio
|
||||||
|
|
||||||
|
Run the example from the libvfio-user repository:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
rm /tmp/vfio-user.sock
|
||||||
|
./build/dbg/samples/gpio-pci-idio-16 -v /tmp/vfio-user.sock &
|
||||||
|
```
|
||||||
|
|
||||||
|
Start Cloud Hypervisor:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
target/debug/cloud-hypervisor \
|
||||||
|
--memory size=1G,shared=on \
|
||||||
|
--disk path=~/images/focal-server-cloudimg-amd64.raw \
|
||||||
|
--kernel ~/src/linux/vmlinux \
|
||||||
|
--cmdline "root=/dev/vda1 console=hvc0" \
|
||||||
|
--user-device socket=/tmp/vfio-user.sock
|
||||||
|
```
|
||||||
|
|
||||||
|
Inside the VM you can test the device with:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
cat /sys/class/gpio/gpiochip480/base > /sys/class/gpio/export
|
||||||
|
for ((i=0;i<12;i++)); do cat /sys/class/gpio/OUT0/value; done
|
||||||
|
```
|
||||||
|
|
||||||
|
## Example (NVMe device)
|
||||||
|
|
||||||
|
Use SPDK: https://github.com/spdk/spdk
|
||||||
|
|
||||||
|
Compile with `./configure --with-vfio-user`
|
||||||
|
|
||||||
|
Create an NVMe controller listening on a vfio-user socket with a simple block device:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
sudo scripts/setup.sh
|
||||||
|
rm ~/images/test-disk.raw
|
||||||
|
truncate ~/images/test-disk.raw -s 128M
|
||||||
|
mkfs.ext4 ~/images/test-disk.raw
|
||||||
|
sudo killall ./build/bin/nvmf_tgt
|
||||||
|
sudo ./build/bin/nvmf_tgt -i 0 -e 0xFFFF -m 0x1 &
|
||||||
|
sleep 2
|
||||||
|
sudo ./scripts/rpc.py nvmf_create_transport -t VFIOUSER
|
||||||
|
sudo rm -rf /tmp/nvme-vfio-user
|
||||||
|
sudo mkdir -p /tmp/nvme-vfio-user
|
||||||
|
sudo ./scripts/rpc.py bdev_aio_create ~/images/test-disk.raw test 512
|
||||||
|
sudo ./scripts/rpc.py nvmf_create_subsystem nqn.2019-07.io.spdk:cnode -a -s test
|
||||||
|
sudo ./scripts/rpc.py nvmf_subsystem_add_ns nqn.2019-07.io.spdk:cnode test
|
||||||
|
sudo ./scripts/rpc.py nvmf_subsystem_add_listener nqn.2019-07.io.spdk:cnode -t VFIOUSER -a /tmp/nvme-vfio-user -s 0
|
||||||
|
sudo chown $USER.$USER -R /tmp/nvme-vfio-user
|
||||||
|
```
|
||||||
|
|
||||||
|
Start Cloud Hypervisor:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
target/debug/cloud-hypervisor \
|
||||||
|
--memory size=1G,shared=on \
|
||||||
|
--disk path=~/images/focal-server-cloudimg-amd64.raw \
|
||||||
|
--kernel ~/src/linux/vmlinux \
|
||||||
|
--cmdline "root=/dev/vda1 console=hvc0" \
|
||||||
|
--user-device socket=/tmp/nvme-vfio-user/cntrl
|
||||||
|
```
|
||||||
@@ -11,7 +11,7 @@ by the VFIO kernel drivers. However, by default, a host device will be bound to
|
|||||||
its native driver, which is not the VFIO one.
|
its native driver, which is not the VFIO one.
|
||||||
|
|
||||||
As a consequence, a device must be unbound from its native driver before passing
|
As a consequence, a device must be unbound from its native driver before passing
|
||||||
it to `cloud-hypervisor` for assigning it to a guess.
|
it to `cloud-hypervisor` for assigning it to a guest.
|
||||||
|
|
||||||
### Example
|
### Example
|
||||||
|
|
||||||
|
|||||||
@@ -35,38 +35,52 @@ Here are some good references for detailing them.
|
|||||||
|
|
||||||
## Test environment
|
## Test environment
|
||||||
|
|
||||||
The below test environment is based on ubuntu release(16.04.1 LTS), as for other system, please check related document.
|
The below test environment is based on Ubuntu release (20.04.1 LTS), as for other system, please check related documents.
|
||||||
The test runs with multiple queue (MQ) support enabled, using 4 queues defined for both SPDK and the virtual machine.
|
This test runs with multiple queue (MQ) support enabled, using 4 queues defined for both SPDK and the virtual machine.
|
||||||
Here are the details on how the test can be run.
|
Here are the detailed instructions.
|
||||||
|
|
||||||
### The hugepages settings in host linux
|
### The hugepages settings on the host
|
||||||
Add "default_hugepagesz=1G hugepagesz=1G hugepages=2" into host linux cmdline.
|
Allocate enough persistent huge pages (e.g. 2GiB) on the host:
|
||||||
As for how to change Ubuntu linux cmdline in grub file, please ref below link:
|
|
||||||
https://www.ostechnix.com/configure-grub-2-boot-loader-settings-ubuntu-16-04/
|
```bash
|
||||||
reboot Ubuntu
|
# Assume the default hugepage size is 2MiB
|
||||||
sudo mount -t hugetlbfs -o pagesize=1G none /dev/hugepages
|
echo 1024 | sudo tee /proc/sys/vm/nr_hugepages
|
||||||
|
# Confirm the value of "Hugepagesize" and "HugePages_Total"
|
||||||
|
cat /proc/meminfo | grep -i huge
|
||||||
|
```
|
||||||
|
|
||||||
### Download the SPDK code
|
### Download the SPDK code
|
||||||
|
```bash
|
||||||
git clone https://github.com/spdk/spdk
|
git clone https://github.com/spdk/spdk
|
||||||
cd spdk
|
cd spdk
|
||||||
git submodule update --init
|
git submodule update --init
|
||||||
|
```
|
||||||
|
|
||||||
### Create the build dep
|
### Create the build dep
|
||||||
./scripts/pkgdep.sh
|
|
||||||
|
|
||||||
### Build spdk
|
```bash
|
||||||
|
./scripts/pkgdep.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
### Build SPDK
|
||||||
|
```bash
|
||||||
./configure
|
./configure
|
||||||
make
|
make
|
||||||
|
```
|
||||||
|
|
||||||
### Set the SPDk environment
|
### Set the SPDK environment
|
||||||
|
```bash
|
||||||
sudo HUGEMEM=2048 scripts/setup.sh
|
sudo HUGEMEM=2048 scripts/setup.sh
|
||||||
sudo ./app/vhost/vhost -S /var/tmp -s 1024 -m 0x3 &
|
sudo ./build/bin/vhost -S /var/tmp -s 1024 -m 0x3 &
|
||||||
|
```
|
||||||
|
|
||||||
### Create 512M block device
|
### Create 512M block device
|
||||||
|
```bash
|
||||||
sudo scripts/rpc.py bdev_malloc_create 512 512 -b Malloc0
|
sudo scripts/rpc.py bdev_malloc_create 512 512 -b Malloc0
|
||||||
sudo scripts/rpc.py vhost_create_blk_controller --cpumask 0x1 vhost.1 Malloc0
|
sudo scripts/rpc.py vhost_create_blk_controller --cpumask 0x1 vhost.1 Malloc0
|
||||||
|
```
|
||||||
|
|
||||||
_Launch the VM_
|
### Launch the VM
|
||||||
|
|
||||||
VMs run in client mode. They connect to the socket created by the `dpdkvhostuser` in the SPDK backend.
|
VMs run in client mode. They connect to the socket created by the `dpdkvhostuser` in the SPDK backend.
|
||||||
```bash
|
```bash
|
||||||
@@ -89,9 +103,9 @@ login in guest
|
|||||||
# Use lsblk command to find out vhost-user-blk device
|
# Use lsblk command to find out vhost-user-blk device
|
||||||
lsblk
|
lsblk
|
||||||
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
|
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
|
||||||
vda 252:0 0 2.2G 0 disk
|
vda 252:0 0 2.2G 0 disk
|
||||||
├─vda1 252:1 0 2.1G 0 part /
|
├─vda1 252:1 0 2.1G 0 part /
|
||||||
├─vda14 252:14 0 4M 0 part
|
├─vda14 252:14 0 4M 0 part
|
||||||
└─vda15 252:15 0 106M 0 part /boot/efi
|
└─vda15 252:15 0 106M 0 part /boot/efi
|
||||||
vdb 253:16 0 512M 0 disk
|
vdb 253:16 0 512M 0 disk
|
||||||
|
|
||||||
|
|||||||
@@ -1,27 +1,30 @@
|
|||||||
# How to test Vhost-user net with OpenVSwitch/DPDK
|
# How to test Vhost-user net with OpenVSwitch/DPDK
|
||||||
|
|
||||||
The purpose of this document is to illustrate how to test vhost-user-net in cloud-hypervisor with OVS/DPDK as the backend.
|
The purpose of this document is to illustrate how to test vhost-user-net
|
||||||
|
in cloud-hypervisor with OVS/DPDK as the backend. This document was
|
||||||
|
tested with Open vSwitch v2.13.1, DPDK v19.11.3, and Cloud Hypervisor
|
||||||
|
v15.0 on Ubuntu 20.04.1 (host kernel v5.4.0).
|
||||||
|
|
||||||
## Framework
|
## Framework
|
||||||
|
|
||||||
It's a simple test to validate the communication between two virtual machine, connecting them to vhost-user ports respectively provided by `OVS/DPDK`.
|
It's a simple test to validate the communication between two virtual machine, connecting them to vhost-user ports respectively provided by `OVS/DPDK`.
|
||||||
```
|
```
|
||||||
+----+----------+ +-------------+-----------+-------------+ +----------+----+
|
+----+----------+ +-------------+-----------+-------------+ +----------+----+
|
||||||
| | | | | | | | | |
|
| | | | | | | | | |
|
||||||
| |vhost-user|----------| vhost-user | ovs | vhost-user |----------|vhost-user| |
|
| |vhost-user|----------| vhost-user | ovs | vhost-user |----------|vhost-user| |
|
||||||
| |net device| | port 1 | | port 2 | |net device| |
|
| |net device| | port 1 | | port 2 | |net device| |
|
||||||
| | | | | | | | | |
|
| | | | | | | | | |
|
||||||
| +----------+ +-------------+-----------+-------------+ +----------+ |
|
| +----------+ +-------------+-----------+-------------+ +----------+ |
|
||||||
| | | | | |
|
| | | | | |
|
||||||
|vm1 | | dpdk | | vm2 |
|
|vm1 | | dpdk | | vm2 |
|
||||||
| | | | | |
|
| | | | | |
|
||||||
+--+---------------------------------------------------------------------------------------------+--+
|
+--+---------------------------------------------------------------------------------------------+--+
|
||||||
| | hugepages | |
|
| | hugepages | |
|
||||||
| +---------------------------------------------------------------------------------------------+ |
|
| +---------------------------------------------------------------------------------------------+ |
|
||||||
| |
|
| |
|
||||||
| host |
|
| host |
|
||||||
| |
|
| |
|
||||||
+---------------------------------------------------------------------------------------------------+
|
+---------------------------------------------------------------------------------------------------+
|
||||||
```
|
```
|
||||||
## Prerequisites
|
## Prerequisites
|
||||||
|
|
||||||
@@ -30,44 +33,54 @@ Prior to running the test, the following steps need to be performed.
|
|||||||
- Install DPDK
|
- Install DPDK
|
||||||
- Install OVS
|
- Install OVS
|
||||||
|
|
||||||
Here are some good references for detailing them.
|
Here is a good reference for setting up OVS with DPDK from scratch:
|
||||||
- Red Hat
|
https://docs.openvswitch.org/en/latest/intro/install/dpdk/.
|
||||||
* https://wiki.qemu.org/Documentation/vhost-user-ovs-dpdk
|
|
||||||
- Ubuntu server
|
|
||||||
* https://help.ubuntu.com/lts/serverguide/DPDK.html
|
|
||||||
* https://software.intel.com/en-us/articles/set-up-open-vswitch-with-dpdk-on-ubuntu-server
|
|
||||||
|
|
||||||
|
On Ubuntu systems (18.04 or newer), the OpenVswitch-DPDK package can be
|
||||||
|
easily installed with:
|
||||||
|
```bash
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install openvswitch-switch-dpdk
|
||||||
|
sudo update-alternatives --set ovs-vswitchd /usr/lib/openvswitch-switch-dpdk/ovs-vswitchd-dpdk
|
||||||
|
```
|
||||||
## Test
|
## Test
|
||||||
The test runs with multiple queue (MQ) support enabled, using 2 pairs of TX/RX queues defined for both OVS and the virtual machine. Here are the details on how the test can be run.
|
The test runs with multiple queue (MQ) support enabled, using 2 pairs of
|
||||||
|
TX/RX queues defined for both OVS and the virtual machine. Here are the
|
||||||
|
detailed instructions.
|
||||||
|
|
||||||
_Setup OVS_
|
_Setup OVS_
|
||||||
|
|
||||||
`ovs_test.sh` is created to setup and start OVS. OVS will provide the `dpdkvhostuser` backend running in server mode.
|
Here is an example how to configure a basic OpenVswitch using DPDK:
|
||||||
```bash
|
```bash
|
||||||
mkdir -p /var/run/openvswitch
|
# load the ovs kernel module
|
||||||
modprobe openvswitch
|
modprobe openvswitch
|
||||||
killall ovsdb-server ovs-vswitchd
|
sudo service openvswitch-switch start
|
||||||
rm -f /var/run/openvswitch/vhost-user*
|
ovs-vsctl init
|
||||||
rm -f /etc/openvswitch/conf.db
|
ovs-vsctl set Open_vSwitch . other_config:dpdk-init=true
|
||||||
export DB_SOCK=/var/run/openvswitch/db.sock
|
# run on core 0-3 only
|
||||||
ovsdb-tool create /etc/openvswitch/conf.db /usr/share/openvswitch/vswitch.ovsschema
|
ovs-vsctl set Open_vSwitch . other_config:dpdk-lcore-mask=0xf
|
||||||
ovsdb-server --remote=punix:$DB_SOCK --remote=db:Open_vSwitch,Open_vSwitch,manager_options --pidfile --detach
|
# allocate 2G huge pages (to NUMA 0 only)
|
||||||
ovs-vsctl --no-wait init
|
ovs-vsctl set Open_vSwitch . other_config:dpdk-socket-mem=1024
|
||||||
ovs-vsctl --no-wait set Open_vSwitch . other_config:dpdk-lcore-mask=0xf
|
# run PMD (Pull Mode Driver) threads on core 0-3 only
|
||||||
ovs-vsctl --no-wait set Open_vSwitch . other_config:dpdk-socket-mem=1024
|
ovs-vsctl set Open_vSwitch . other_config:pmd-cpu-mask=0xf
|
||||||
ovs-vsctl --no-wait set Open_vSwitch . other_config:dpdk-init=true
|
sudo service openvswitch-switch restart
|
||||||
ovs-vsctl --no-wait set Open_vSwitch . other_config:pmd-cpu-mask=0xf
|
# double check the configurations
|
||||||
ovs-vswitchd unix:$DB_SOCK --pidfile --detach --log-file=/var/log/openvswitch/ovs-vswitchd.log
|
ovs-vsctl list Open_vSwitch
|
||||||
|
```
|
||||||
|
|
||||||
|
Here is an example how to create a bridge and add two DPDK ports to it
|
||||||
|
(for later use via Cloud Hypervisor):
|
||||||
|
```bash
|
||||||
|
# create a bridge
|
||||||
ovs-vsctl add-br ovsbr0 -- set bridge ovsbr0 datapath_type=netdev
|
ovs-vsctl add-br ovsbr0 -- set bridge ovsbr0 datapath_type=netdev
|
||||||
|
# create two DPDK ports and add them to the bridge
|
||||||
ovs-vsctl add-port ovsbr0 vhost-user1 -- set Interface vhost-user1 type=dpdkvhostuser
|
ovs-vsctl add-port ovsbr0 vhost-user1 -- set Interface vhost-user1 type=dpdkvhostuser
|
||||||
ovs-vsctl add-port ovsbr0 vhost-user2 -- set Interface vhost-user2 type=dpdkvhostuser
|
ovs-vsctl add-port ovsbr0 vhost-user2 -- set Interface vhost-user2
|
||||||
|
type=dpdkvhostuser
|
||||||
|
# set the number of rx queues
|
||||||
ovs-vsctl set Interface vhost-user1 options:n_rxq=2
|
ovs-vsctl set Interface vhost-user1 options:n_rxq=2
|
||||||
ovs-vsctl set Interface vhost-user2 options:n_rxq=2
|
ovs-vsctl set Interface vhost-user2 options:n_rxq=2
|
||||||
```
|
```
|
||||||
_Run ovs_test.sh_
|
|
||||||
```bash
|
|
||||||
./ovs_test.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
_Launch the VMs_
|
_Launch the VMs_
|
||||||
|
|
||||||
@@ -89,19 +102,21 @@ VMs run in client mode. They connect to the socket created by the `dpdkvhostuser
|
|||||||
--kernel vmlinux \
|
--kernel vmlinux \
|
||||||
--cmdline "console=ttyS0 console=hvc0 root=/dev/vda1 rw" \
|
--cmdline "console=ttyS0 console=hvc0 root=/dev/vda1 rw" \
|
||||||
--disk path=focal-server-cloudimg-amd64.raw \
|
--disk path=focal-server-cloudimg-amd64.raw \
|
||||||
--net "mac=52:54:20:11:C5:02,vhost_user=true,socket=/var/run/openvswitch/vhost-user2,num_queues=4"
|
--net mac=52:54:20:11:C5:02,vhost_user=true,socket=/var/run/openvswitch/vhost-user2,num_queues=4
|
||||||
```
|
```
|
||||||
|
|
||||||
_Setup VM1_
|
_Setup VM1_
|
||||||
```bash
|
```bash
|
||||||
# From inside the guest
|
# From inside the guest
|
||||||
sudo ip addr add 172.100.0.1/24 dev enp0s3
|
sudo ip addr add 172.100.0.1/24 dev ens2
|
||||||
|
sudo ip link set up dev ens2
|
||||||
```
|
```
|
||||||
|
|
||||||
_Setup VM2_
|
_Setup VM2_
|
||||||
```bash
|
```bash
|
||||||
# From inside the guest
|
# From inside the guest
|
||||||
sudo ip addr add 172.100.0.2/24 dev enp0s3
|
sudo ip addr add 172.100.0.2/24 dev ens2
|
||||||
|
sudo ip link set up dev ens2
|
||||||
```
|
```
|
||||||
|
|
||||||
_Ping VM1 from VM2_
|
_Ping VM1 from VM2_
|
||||||
@@ -129,4 +144,3 @@ _Run VM2 as client_
|
|||||||
# From inside the guest
|
# From inside the guest
|
||||||
iperf3 -c 172.100.0.1 -t 30 -p 4444 &
|
iperf3 -c 172.100.0.1 -t 30 -p 4444 &
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -30,15 +30,15 @@ This step currently requires QEMU to install Windows onto the guest. QEMU is onl
|
|||||||
Preparing several command parts as these will be used in the follow up sections as well.
|
Preparing several command parts as these will be used in the follow up sections as well.
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
IMG_FILE=windows-disk.qcow
|
IMG_FILE=windows-disk.raw
|
||||||
WIN_ISO_FILE=en_windows_server_version_2004_updated_may_2020_x64_dvd_1e7f1cfa.iso
|
WIN_ISO_FILE=en_windows_server_version_2004_updated_may_2020_x64_dvd_1e7f1cfa.iso
|
||||||
VIRTIO_ISO_FILE=virtio-win-0.1.185.iso
|
VIRTIO_ISO_FILE=virtio-win-0.1.185.iso
|
||||||
OVMF_DIR=./FV
|
OVMF_DIR=./FV
|
||||||
```
|
```
|
||||||
|
|
||||||
Create an empty image file, `qcow` or `raw` is supported.
|
Create an empty image file, `raw` is supported.
|
||||||
```shell
|
```shell
|
||||||
qemu-img create -f qcow2 $IMG_FILE 30G
|
qemu-img create -f raw $IMG_FILE 30G
|
||||||
```
|
```
|
||||||
|
|
||||||
Begin the Windows installation process under QEMU
|
Begin the Windows installation process under QEMU
|
||||||
@@ -192,6 +192,8 @@ RAM hotplug is supported. Note, that while the `pnpmem.sys` driver in use suppor
|
|||||||
|
|
||||||
Network device hotplug and hot-remove are supported.
|
Network device hotplug and hot-remove are supported.
|
||||||
|
|
||||||
|
Disk hotplug and hot-remove are supported. After the device has been hotplugged, it will need to be onlined from within the guest. Among other tools, powershell applets `Get-Disk` and `Set-Disk` can be used for the disk configuration and activation.
|
||||||
|
|
||||||
## Debugging
|
## Debugging
|
||||||
|
|
||||||
The Windows guest debugging process relies heavily on QEMU and [socat](http://www.dest-unreach.org/socat/). The procedure requires two Windows VMs:
|
The Windows guest debugging process relies heavily on QEMU and [socat](http://www.dest-unreach.org/socat/). The procedure requires two Windows VMs:
|
||||||
@@ -219,7 +221,7 @@ qemu-system-x86_64 \
|
|||||||
-m 4G \
|
-m 4G \
|
||||||
-cdrom ./$WIN_ISO_FILE \
|
-cdrom ./$WIN_ISO_FILE \
|
||||||
-drive file=./$VIRTIO_ISO_FILE,index=0,media=cdrom
|
-drive file=./$VIRTIO_ISO_FILE,index=0,media=cdrom
|
||||||
-drive if=none,id=root,file=./windbg-disk.qcow \
|
-drive if=none,id=root,file=./windbg-disk.raw \
|
||||||
-device virtio-blk-pci,drive=root,disable-legacy=on \
|
-device virtio-blk-pci,drive=root,disable-legacy=on \
|
||||||
-device virtio-net-pci,netdev=mynet0,disable-legacy=on \
|
-device virtio-net-pci,netdev=mynet0,disable-legacy=on \
|
||||||
-netdev user,id=mynet0,net=192.168.178.0/24,host=192.168.178.1,dhcpstart=192.168.178.64,hostname=windbg-host \
|
-netdev user,id=mynet0,net=192.168.178.0/24,host=192.168.178.1,dhcpstart=192.168.178.64,hostname=windbg-host \
|
||||||
@@ -278,7 +280,7 @@ qemu-system-x86_64 \
|
|||||||
-cpu host \
|
-cpu host \
|
||||||
-smp 1 \
|
-smp 1 \
|
||||||
-m 4G \
|
-m 4G \
|
||||||
-drive if=none,id=root,file=./windbg-disk.qcow \
|
-drive if=none,id=root,file=./windbg-disk.raw \
|
||||||
-device virtio-blk-pci,drive=root,disable-legacy=on \
|
-device virtio-blk-pci,drive=root,disable-legacy=on \
|
||||||
-serial tcp::4445,server,nowait \
|
-serial tcp::4445,server,nowait \
|
||||||
-device virtio-net-pci,netdev=mynet0,disable-legacy=on \
|
-device virtio-net-pci,netdev=mynet0,disable-legacy=on \
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ authors = ["The Cloud Hypervisor Authors"]
|
|||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
libc = "0.2.94"
|
libc = "0.2.103"
|
||||||
serde = {version = ">=1.0.27", features = ["rc"] }
|
serde = { version = "1.0.130", features = ["rc"] }
|
||||||
serde_derive = ">=1.0.27"
|
serde_derive = "1.0.130"
|
||||||
serde_json = ">=1.0.9"
|
serde_json = "1.0.68"
|
||||||
|
|||||||
343
fuzz/Cargo.lock
generated
343
fuzz/Cargo.lock
generated
@@ -20,25 +20,28 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anyhow"
|
name = "anyhow"
|
||||||
version = "1.0.40"
|
version = "1.0.44"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "28b2cd92db5cbd74e8e5028f7e27dd7aa3090e89e4f2a197cc7c8dfb69c7063b"
|
checksum = "61604a8f862e1d5c3229fdd78f8b02c68dcf73a4c4b05fd636d12240aaa242c1"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "api_client"
|
name = "api_client"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"vmm-sys-util",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "arbitrary"
|
name = "arbitrary"
|
||||||
version = "1.0.0"
|
version = "1.0.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "698b65a961a9d730fb45b6b0327e20207810c9f61ee421b082b27ba003f49e2b"
|
checksum = "577b08a4acd7b99869f863c50011b01eb73424ccc798ecd996f2e24817adfca7"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "arc-swap"
|
name = "arc-swap"
|
||||||
version = "1.2.0"
|
version = "1.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d4d7d63395147b81a9e570bcc6243aaf71c017bd666d4909cfef0085bdda8d73"
|
checksum = "e6df5aef5c5830360ce5218cecb8f018af3438af5686ae945094affc86fdec63"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "arch"
|
name = "arch"
|
||||||
@@ -46,24 +49,23 @@ version = "0.1.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"acpi_tables",
|
"acpi_tables",
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"arch_gen",
|
|
||||||
"byteorder",
|
"byteorder",
|
||||||
|
"fdt",
|
||||||
"hypervisor",
|
"hypervisor",
|
||||||
"libc",
|
"libc",
|
||||||
"linux-loader",
|
"linux-loader",
|
||||||
"log",
|
"log",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
"serde_json",
|
|
||||||
"thiserror",
|
"thiserror",
|
||||||
|
"versionize",
|
||||||
|
"versionize_derive",
|
||||||
|
"vm-fdt",
|
||||||
"vm-memory",
|
"vm-memory",
|
||||||
"vm-migration",
|
"vm-migration",
|
||||||
|
"vmm-sys-util",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "arch_gen"
|
|
||||||
version = "0.1.0"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "atty"
|
name = "atty"
|
||||||
version = "0.2.14"
|
version = "0.2.14"
|
||||||
@@ -76,10 +78,19 @@ dependencies = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bitflags"
|
name = "bincode"
|
||||||
version = "1.2.1"
|
version = "1.3.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
|
checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bitflags"
|
||||||
|
version = "1.3.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "block_util"
|
name = "block_util"
|
||||||
@@ -89,10 +100,10 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
"log",
|
"log",
|
||||||
"qcow",
|
"qcow",
|
||||||
"serde",
|
|
||||||
"serde_derive",
|
|
||||||
"serde_json",
|
|
||||||
"thiserror",
|
"thiserror",
|
||||||
|
"versionize",
|
||||||
|
"versionize_derive",
|
||||||
|
"vhdx",
|
||||||
"virtio-bindings",
|
"virtio-bindings",
|
||||||
"vm-memory",
|
"vm-memory",
|
||||||
"vm-virtio",
|
"vm-virtio",
|
||||||
@@ -107,9 +118,9 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cc"
|
name = "cc"
|
||||||
version = "1.0.67"
|
version = "1.0.71"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e3c69b077ad434294d3ce9f1f6143a2a4b89a8a2d54ef813d85003a4fd1137fd"
|
checksum = "79c2681d6594606957bbb8631c4b90a7fcaaa72cdb714743a437b156d6a7eedd"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cfg-if"
|
name = "cfg-if"
|
||||||
@@ -135,7 +146,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cloud-hypervisor"
|
name = "cloud-hypervisor"
|
||||||
version = "0.14.0"
|
version = "18.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"api_client",
|
"api_client",
|
||||||
@@ -146,7 +157,7 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
"log",
|
"log",
|
||||||
"option_parser",
|
"option_parser",
|
||||||
"seccomp",
|
"seccompiler",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"signal-hook",
|
"signal-hook",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
@@ -164,27 +175,43 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
"libfuzzer-sys",
|
"libfuzzer-sys",
|
||||||
"qcow",
|
"qcow",
|
||||||
"seccomp",
|
"seccompiler",
|
||||||
|
"vhdx",
|
||||||
"virtio-devices",
|
"virtio-devices",
|
||||||
"vm-memory",
|
"vm-memory",
|
||||||
"vm-virtio",
|
"vm-virtio",
|
||||||
"vmm-sys-util",
|
"vmm-sys-util",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crc32c"
|
||||||
|
version = "0.6.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "210cdf933e6a81212bfabf90cd8762f471b5922e5f6b709547673ad8e04b9448"
|
||||||
|
dependencies = [
|
||||||
|
"rustc_version",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crc64"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "55626594feae15d266d52440b26ff77de0e22230cf0c113abe619084c1ddc910"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "devices"
|
name = "devices"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"acpi_tables",
|
"acpi_tables",
|
||||||
"anyhow",
|
"anyhow",
|
||||||
|
"arch",
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"byteorder",
|
"byteorder",
|
||||||
"epoll",
|
"epoll",
|
||||||
"libc",
|
"libc",
|
||||||
"log",
|
"log",
|
||||||
"serde",
|
"versionize",
|
||||||
"serde_derive",
|
"versionize_derive",
|
||||||
"serde_json",
|
|
||||||
"vm-device",
|
"vm-device",
|
||||||
"vm-memory",
|
"vm-memory",
|
||||||
"vm-migration",
|
"vm-migration",
|
||||||
@@ -212,10 +239,27 @@ dependencies = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hermit-abi"
|
name = "fdt"
|
||||||
version = "0.1.18"
|
version = "0.1.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "322f4de77956e22ed0e5032c359a0f1273f1f7f0d79bfa3b8ffbc730d7fbcc5c"
|
checksum = "b643857cf70949306b81d7e92cb9d47add673868edac9863c4a49c42feaf3f1e"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "getrandom"
|
||||||
|
version = "0.2.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"libc",
|
||||||
|
"wasi",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hermit-abi"
|
||||||
|
version = "0.1.19"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
@@ -241,9 +285,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "iced-x86"
|
name = "iced-x86"
|
||||||
version = "1.11.1"
|
version = "1.15.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "97b85a147f5dcb22ece887da5b99187954cc046939f22416e953dd7c336e85a1"
|
checksum = "46e977036f7f5139d580c7f19ad62df9cb8ebd8410bb569e73585226be80a86f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"static_assertions",
|
"static_assertions",
|
||||||
@@ -251,9 +295,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "io-uring"
|
name = "io-uring"
|
||||||
version = "0.5.1"
|
version = "0.5.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fb82832e05cc4ca298f198a8db108837b4f7b7b1248e3cba8e48f151aece80cf"
|
checksum = "8d75829ed9377bab6c90039fe47b9d84caceb4b5063266142e21bcce6550cda8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"libc",
|
"libc",
|
||||||
@@ -261,14 +305,14 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "itoa"
|
name = "itoa"
|
||||||
version = "0.4.7"
|
version = "0.4.8"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736"
|
checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "kvm-bindings"
|
name = "kvm-bindings"
|
||||||
version = "0.4.0"
|
version = "0.5.0"
|
||||||
source = "git+https://github.com/cloud-hypervisor/kvm-bindings?branch=ch-v0.4.0#1a68725639283e622f4bb64584885b30bfe8be44"
|
source = "git+https://github.com/cloud-hypervisor/kvm-bindings?branch=ch-v0.5.0#9c497710ba9968d8efe15dbae03991b16cf82e23"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
@@ -277,9 +321,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "kvm-ioctls"
|
name = "kvm-ioctls"
|
||||||
version = "0.8.0"
|
version = "0.10.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "74058b16912c6723db02d4ca3ec919b73cd41512ccd3b6202cf91ae8d6c9dce5"
|
checksum = "48dc14f9047df1873cf6942caccc7431d19c3d496ca7a0d162260c4cf0f64b76"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"kvm-bindings",
|
"kvm-bindings",
|
||||||
"libc",
|
"libc",
|
||||||
@@ -294,25 +338,26 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.94"
|
version = "0.2.103"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "18794a8ad5b29321f790b55d93dfba91e125cb1a9edbd4f8e3150acc771c1a5e"
|
checksum = "dd8f7255a17a627354f321ef0055d63b898c6fb27eff628af4d1b66b7331edf6"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libfuzzer-sys"
|
name = "libfuzzer-sys"
|
||||||
version = "0.4.0"
|
version = "0.4.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "86c975d637bc2a2f99440932b731491fc34c7f785d239e38af3addd3c2fd0e46"
|
checksum = "36a9a84a6e8b55dfefb04235e55edb2b9a2a18488fcae777a6bdaa6f06f1deb3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arbitrary",
|
"arbitrary",
|
||||||
"cc",
|
"cc",
|
||||||
|
"once_cell",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "linux-loader"
|
name = "linux-loader"
|
||||||
version = "0.3.0"
|
version = "0.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c819cc8275b0f2c1ed9feec455ca288b45d82932384a6a5f7a86812ee3427459"
|
checksum = "8a5e77493808403a6bd56a301a64ea6b9342e36ea845044bf0dfdf56fe52fa08"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"vm-memory",
|
"vm-memory",
|
||||||
]
|
]
|
||||||
@@ -329,7 +374,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "micro_http"
|
name = "micro_http"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/firecracker-microvm/micro-http?branch=main#9b605a8b61df602cda62076d30d9f70307ea336f"
|
source = "git+https://github.com/firecracker-microvm/micro-http?branch=main#9517a300370a158a7af0996b7eebf040d171e1a4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"vmm-sys-util",
|
"vmm-sys-util",
|
||||||
@@ -347,17 +392,26 @@ name = "net_util"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"epoll",
|
"epoll",
|
||||||
|
"getrandom",
|
||||||
"libc",
|
"libc",
|
||||||
"log",
|
"log",
|
||||||
"net_gen",
|
"net_gen",
|
||||||
"rate_limiter",
|
"rate_limiter",
|
||||||
"serde",
|
"serde",
|
||||||
|
"versionize",
|
||||||
|
"versionize_derive",
|
||||||
"virtio-bindings",
|
"virtio-bindings",
|
||||||
"vm-memory",
|
"vm-memory",
|
||||||
"vm-virtio",
|
"vm-virtio",
|
||||||
"vmm-sys-util",
|
"vmm-sys-util",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "once_cell"
|
||||||
|
version = "1.8.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "option_parser"
|
name = "option_parser"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
@@ -371,11 +425,12 @@ dependencies = [
|
|||||||
"hypervisor",
|
"hypervisor",
|
||||||
"libc",
|
"libc",
|
||||||
"log",
|
"log",
|
||||||
"serde",
|
"thiserror",
|
||||||
"serde_derive",
|
"versionize",
|
||||||
"serde_json",
|
"versionize_derive",
|
||||||
"vfio-bindings",
|
"vfio-bindings",
|
||||||
"vfio-ioctls",
|
"vfio-ioctls",
|
||||||
|
"vfio_user",
|
||||||
"vm-allocator",
|
"vm-allocator",
|
||||||
"vm-device",
|
"vm-device",
|
||||||
"vm-memory",
|
"vm-memory",
|
||||||
@@ -385,9 +440,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "1.0.26"
|
version = "1.0.30"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a152013215dca273577e18d2bf00fa862b89b24169fb78c4c95aeb07992c9cec"
|
checksum = "edc3358ebc67bc8b7fa0c007f945b0b18226f78437d61bec735a9eb96b61ee70"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"unicode-xid",
|
"unicode-xid",
|
||||||
]
|
]
|
||||||
@@ -405,9 +460,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "quote"
|
name = "quote"
|
||||||
version = "1.0.9"
|
version = "1.0.10"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7"
|
checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
]
|
]
|
||||||
@@ -432,6 +487,15 @@ dependencies = [
|
|||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustc_version"
|
||||||
|
version = "0.2.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
|
||||||
|
dependencies = [
|
||||||
|
"semver",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ryu"
|
name = "ryu"
|
||||||
version = "1.0.5"
|
version = "1.0.5"
|
||||||
@@ -439,24 +503,40 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e"
|
checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "seccomp"
|
name = "seccompiler"
|
||||||
version = "0.1.0"
|
version = "0.2.0"
|
||||||
source = "git+https://github.com/firecracker-microvm/firecracker?tag=v0.24.2#5ba819d7b7a684107f5434bcbd1617bc94565478"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e01d1292a1131b22ccea49f30bd106f1238b5ddeec1a98d39268dcc31d540e68"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde"
|
name = "semver"
|
||||||
version = "1.0.125"
|
version = "0.9.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "558dc50e1a5a5fa7112ca2ce4effcb321b0300c0d4ccf0776a9f60cd89031171"
|
checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
|
||||||
|
dependencies = [
|
||||||
|
"semver-parser",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "semver-parser"
|
||||||
|
version = "0.7.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde"
|
||||||
|
version = "1.0.130"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f12d06de37cf59146fbdecab66aa99f9fe4f78722e3607577a5375d66bd0c913"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_derive"
|
name = "serde_derive"
|
||||||
version = "1.0.125"
|
version = "1.0.130"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b093b7a2bb58203b5da3056c05b4ec1fed827dcfdb37347a8841695263b3d06d"
|
checksum = "d7bc1a1ab1961464eae040d96713baa5a724a8152c1222492465b54322ec508b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@@ -465,9 +545,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_json"
|
name = "serde_json"
|
||||||
version = "1.0.64"
|
version = "1.0.68"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "799e97dc9fdae36a5c8b8f2cae9ce2ee9fdce2058c57a93e6099d919fd982f79"
|
checksum = "0f690853975602e1bfe1ccbf50504d67174e3bcf340f23b5ea9992e0587a52d8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"itoa",
|
"itoa",
|
||||||
"ryu",
|
"ryu",
|
||||||
@@ -476,9 +556,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "signal-hook"
|
name = "signal-hook"
|
||||||
version = "0.3.8"
|
version = "0.3.10"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ef33d6d0cd06e0840fba9985aab098c147e67e05cee14d412d3345ed14ff30ac"
|
checksum = "9c98891d737e271a2954825ef19e46bd16bdb98e2746f2eec4f7a4ef7946efd1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"signal-hook-registry",
|
"signal-hook-registry",
|
||||||
@@ -486,9 +566,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "signal-hook-registry"
|
name = "signal-hook-registry"
|
||||||
version = "1.3.0"
|
version = "1.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "16f1d0fef1604ba8f7a073c7e701f213e056707210e9020af4528e0101ce11a6"
|
checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
@@ -507,9 +587,9 @@ checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "1.0.71"
|
version = "1.0.80"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ad184cc9470f9117b2ac6817bfe297307418819ba40552f9b3846f05c33d5373"
|
checksum = "d010a1623fbd906d51d650a9916aaefc05ffa0e4053ff7fe601167f3e715d194"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@@ -538,18 +618,18 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "thiserror"
|
name = "thiserror"
|
||||||
version = "1.0.24"
|
version = "1.0.30"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e0f4a65597094d4483ddaed134f409b2cb7c1beccf25201a9f73c719254fa98e"
|
checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"thiserror-impl",
|
"thiserror-impl",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "thiserror-impl"
|
name = "thiserror-impl"
|
||||||
version = "1.0.24"
|
version = "1.0.30"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7765189610d8241a44529806d6fd1f2e0a08734313a35d5b3a556f92b381f3c0"
|
checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@@ -558,15 +638,24 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-width"
|
name = "unicode-width"
|
||||||
version = "0.1.8"
|
version = "0.1.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3"
|
checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-xid"
|
name = "unicode-xid"
|
||||||
version = "0.2.1"
|
version = "0.2.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
|
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "uuid"
|
||||||
|
version = "0.8.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7"
|
||||||
|
dependencies = [
|
||||||
|
"getrandom",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "vec_map"
|
name = "vec_map"
|
||||||
@@ -574,6 +663,33 @@ version = "0.8.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
|
checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "versionize"
|
||||||
|
version = "0.1.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7429cf68de8f091b667d27323ed323afd39584a56d533995b12ddd748e5e6ca9"
|
||||||
|
dependencies = [
|
||||||
|
"bincode",
|
||||||
|
"crc64",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"serde",
|
||||||
|
"serde_derive",
|
||||||
|
"syn",
|
||||||
|
"versionize_derive",
|
||||||
|
"vmm-sys-util",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "versionize_derive"
|
||||||
|
version = "0.1.4"
|
||||||
|
source = "git+https://github.com/cloud-hypervisor/versionize_derive?branch=ch#ae35ef7a3ddabd3371ab8ac0193a383aff6e4b1b"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "vfio-bindings"
|
name = "vfio-bindings"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
@@ -586,7 +702,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "vfio-ioctls"
|
name = "vfio-ioctls"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/rust-vmm/vfio-ioctls?branch=master#a87b13bdec026e8144b91f30f35451a966d8c1ca"
|
source = "git+https://github.com/rust-vmm/vfio-ioctls?branch=main#d51c1fad37be30c20385c55a217e2d90972ea31d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"byteorder",
|
"byteorder",
|
||||||
"kvm-bindings",
|
"kvm-bindings",
|
||||||
@@ -598,12 +714,44 @@ dependencies = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "vhost"
|
name = "vfio_user"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/rust-vmm/vhost?branch=master#ee3e8722706c984b3dfe12d3a130e92101b78e8f"
|
dependencies = [
|
||||||
|
"anyhow",
|
||||||
|
"libc",
|
||||||
|
"log",
|
||||||
|
"serde",
|
||||||
|
"serde_derive",
|
||||||
|
"serde_json",
|
||||||
|
"thiserror",
|
||||||
|
"vfio-bindings",
|
||||||
|
"vm-memory",
|
||||||
|
"vmm-sys-util",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "vhdx"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"byteorder",
|
||||||
|
"crc32c",
|
||||||
|
"libc",
|
||||||
|
"log",
|
||||||
|
"remain",
|
||||||
|
"thiserror",
|
||||||
|
"uuid",
|
||||||
|
"vmm-sys-util",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "vhost"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2d23ddeb452fb4f837526c6298cc8a2f4948e5595b0328a3d61b5eebe51874d7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"libc",
|
"libc",
|
||||||
|
"vm-memory",
|
||||||
"vmm-sys-util",
|
"vmm-sys-util",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -630,10 +778,12 @@ dependencies = [
|
|||||||
"net_util",
|
"net_util",
|
||||||
"pci",
|
"pci",
|
||||||
"rate_limiter",
|
"rate_limiter",
|
||||||
"seccomp",
|
"seccompiler",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
|
"versionize",
|
||||||
|
"versionize_derive",
|
||||||
"vhost",
|
"vhost",
|
||||||
"virtio-bindings",
|
"virtio-bindings",
|
||||||
"vm-allocator",
|
"vm-allocator",
|
||||||
@@ -667,11 +817,16 @@ dependencies = [
|
|||||||
"vmm-sys-util",
|
"vmm-sys-util",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "vm-fdt"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "git+https://github.com/rust-vmm/vm-fdt?branch=main#720e48e435b791ec6cbe8d2b229448b71dcb1ab9"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "vm-memory"
|
name = "vm-memory"
|
||||||
version = "0.5.0"
|
version = "0.6.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "625f401b1b8b3ac3d43f53903cd138cfe840bd985f8581e553027b31d2bb8ae8"
|
checksum = "0a8ebcb86ca457f9d6e14cf97009f679952eba42f0113de5db596e514cd0e43b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arc-swap",
|
"arc-swap",
|
||||||
"libc",
|
"libc",
|
||||||
@@ -687,6 +842,8 @@ dependencies = [
|
|||||||
"serde_derive",
|
"serde_derive",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
|
"versionize",
|
||||||
|
"versionize_derive",
|
||||||
"vm-memory",
|
"vm-memory",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -695,9 +852,6 @@ name = "vm-virtio"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"log",
|
"log",
|
||||||
"serde",
|
|
||||||
"serde_derive",
|
|
||||||
"serde_json",
|
|
||||||
"virtio-bindings",
|
"virtio-bindings",
|
||||||
"vm-memory",
|
"vm-memory",
|
||||||
]
|
]
|
||||||
@@ -726,13 +880,18 @@ dependencies = [
|
|||||||
"option_parser",
|
"option_parser",
|
||||||
"pci",
|
"pci",
|
||||||
"qcow",
|
"qcow",
|
||||||
"seccomp",
|
"seccompiler",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"signal-hook",
|
"signal-hook",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
|
"uuid",
|
||||||
|
"versionize",
|
||||||
|
"versionize_derive",
|
||||||
"vfio-ioctls",
|
"vfio-ioctls",
|
||||||
|
"vfio_user",
|
||||||
|
"vhdx",
|
||||||
"virtio-devices",
|
"virtio-devices",
|
||||||
"vm-allocator",
|
"vm-allocator",
|
||||||
"vm-device",
|
"vm-device",
|
||||||
@@ -744,9 +903,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "vmm-sys-util"
|
name = "vmm-sys-util"
|
||||||
version = "0.8.0"
|
version = "0.9.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "01cf11afbc4ebc0d5c7a7748a77d19e2042677fc15faa2f4ccccb27c18a60605"
|
checksum = "733537bded03aaa93543f785ae997727b30d1d9f4a03b7861d23290474242e11"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"libc",
|
"libc",
|
||||||
@@ -754,6 +913,12 @@ dependencies = [
|
|||||||
"serde_derive",
|
"serde_derive",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasi"
|
||||||
|
version = "0.10.2+wasi-snapshot-preview1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winapi"
|
name = "winapi"
|
||||||
version = "0.3.9"
|
version = "0.3.9"
|
||||||
|
|||||||
@@ -10,21 +10,23 @@ cargo-fuzz = true
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
block_util = { path = "../block_util" }
|
block_util = { path = "../block_util" }
|
||||||
libc = "0.2.94"
|
libc = "0.2.103"
|
||||||
libfuzzer-sys = "0.4"
|
libfuzzer-sys = "0.4.2"
|
||||||
qcow = { path = "../qcow" }
|
qcow = { path = "../qcow" }
|
||||||
seccomp = { git = "https://github.com/firecracker-microvm/firecracker", tag = "v0.24.2" }
|
seccompiler = "0.2.0"
|
||||||
|
vhdx = { path = "../vhdx" }
|
||||||
virtio-devices = { path = "../virtio-devices" }
|
virtio-devices = { path = "../virtio-devices" }
|
||||||
vmm-sys-util = "0.8.0"
|
vmm-sys-util = "0.9.0"
|
||||||
vm-virtio = { path = "../vm-virtio" }
|
vm-virtio = { path = "../vm-virtio" }
|
||||||
vm-memory = "0.5.0"
|
vm-memory = "0.6.0"
|
||||||
|
|
||||||
[patch.crates-io]
|
|
||||||
kvm-bindings = { git = "https://github.com/cloud-hypervisor/kvm-bindings", branch = "ch-v0.4.0", features = ["with-serde", "fam-wrappers"] }
|
|
||||||
|
|
||||||
[dependencies.cloud-hypervisor]
|
[dependencies.cloud-hypervisor]
|
||||||
path = ".."
|
path = ".."
|
||||||
|
|
||||||
|
[patch.crates-io]
|
||||||
|
kvm-bindings = { git = "https://github.com/cloud-hypervisor/kvm-bindings", branch = "ch-v0.5.0", features = ["with-serde", "fam-wrappers"] }
|
||||||
|
versionize_derive = { git = "https://github.com/cloud-hypervisor/versionize_derive", branch = "ch" }
|
||||||
|
|
||||||
# Prevent this from interfering with workspaces
|
# Prevent this from interfering with workspaces
|
||||||
[workspace]
|
[workspace]
|
||||||
members = ["."]
|
members = ["."]
|
||||||
@@ -40,3 +42,9 @@ name = "block"
|
|||||||
path = "fuzz_targets/block.rs"
|
path = "fuzz_targets/block.rs"
|
||||||
test = false
|
test = false
|
||||||
doc = false
|
doc = false
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "vhdx"
|
||||||
|
path = "fuzz_targets/vhdx.rs"
|
||||||
|
test = false
|
||||||
|
doc = false
|
||||||
|
|||||||
@@ -4,9 +4,9 @@
|
|||||||
|
|
||||||
#![no_main]
|
#![no_main]
|
||||||
|
|
||||||
use block_util::{async_io::DiskFile, qcow_sync::QcowDiskSync};
|
use block_util::{async_io::DiskFile, raw_sync::RawFileDiskSync};
|
||||||
use libfuzzer_sys::fuzz_target;
|
use libfuzzer_sys::fuzz_target;
|
||||||
use seccomp::SeccompAction;
|
use seccompiler::SeccompAction;
|
||||||
use std::ffi;
|
use std::ffi;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::{self, Cursor, Read, Seek, SeekFrom};
|
use std::io::{self, Cursor, Read, Seek, SeekFrom};
|
||||||
@@ -17,7 +17,7 @@ use std::sync::Arc;
|
|||||||
use virtio_devices::{Block, VirtioDevice, VirtioInterrupt, VirtioInterruptType};
|
use virtio_devices::{Block, VirtioDevice, VirtioInterrupt, VirtioInterruptType};
|
||||||
use vm_memory::{Bytes, GuestAddress, GuestMemoryAtomic, GuestMemoryMmap};
|
use vm_memory::{Bytes, GuestAddress, GuestMemoryAtomic, GuestMemoryMmap};
|
||||||
use vm_virtio::Queue;
|
use vm_virtio::Queue;
|
||||||
use vmm_sys_util::eventfd::EventFd;
|
use vmm_sys_util::eventfd::{EventFd, EFD_NONBLOCK};
|
||||||
|
|
||||||
const MEM_SIZE: u64 = 256 * 1024 * 1024;
|
const MEM_SIZE: u64 = 256 * 1024 * 1024;
|
||||||
const DESC_SIZE: u64 = 16; // Bytes in one virtio descriptor.
|
const DESC_SIZE: u64 = 16; // Bytes in one virtio descriptor.
|
||||||
@@ -84,7 +84,7 @@ fuzz_target!(|bytes| {
|
|||||||
|
|
||||||
let shm = memfd_create(&ffi::CString::new("fuzz").unwrap(), 0).unwrap();
|
let shm = memfd_create(&ffi::CString::new("fuzz").unwrap(), 0).unwrap();
|
||||||
let disk_file: File = unsafe { File::from_raw_fd(shm) };
|
let disk_file: File = unsafe { File::from_raw_fd(shm) };
|
||||||
let qcow_disk = Box::new(QcowDiskSync::new(disk_file, false)) as Box<dyn DiskFile>;
|
let qcow_disk = Box::new(RawFileDiskSync::new(disk_file)) as Box<dyn DiskFile>;
|
||||||
|
|
||||||
let mut block = Block::new(
|
let mut block = Block::new(
|
||||||
"tmp".to_owned(),
|
"tmp".to_owned(),
|
||||||
@@ -96,6 +96,7 @@ fuzz_target!(|bytes| {
|
|||||||
256,
|
256,
|
||||||
SeccompAction::Allow,
|
SeccompAction::Allow,
|
||||||
None,
|
None,
|
||||||
|
EventFd::new(EFD_NONBLOCK).unwrap(),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
|||||||
53
fuzz/fuzz_targets/vhdx.rs
Normal file
53
fuzz/fuzz_targets/vhdx.rs
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
// Copyright © 2021 Intel Corporation
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
#![no_main]
|
||||||
|
use libfuzzer_sys::fuzz_target;
|
||||||
|
use std::ffi;
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::{self, Read, Seek, SeekFrom, Write};
|
||||||
|
use std::os::unix::io::{FromRawFd, RawFd};
|
||||||
|
use vhdx::vhdx::Vhdx;
|
||||||
|
|
||||||
|
// Populate the corpus directory with a test file:
|
||||||
|
// truncate -s 16M /tmp/source
|
||||||
|
// qemu-img convert -O vhdx /tmp/source fuzz/corpus/vhdx/test.vhdx
|
||||||
|
// Run with:
|
||||||
|
// cargo fuzz run vhdx -j 32 -- -max_len=16777216
|
||||||
|
fuzz_target!(|bytes| {
|
||||||
|
let shm = memfd_create(&ffi::CString::new("fuzz").unwrap(), 0).unwrap();
|
||||||
|
let mut disk_file: File = unsafe { File::from_raw_fd(shm) };
|
||||||
|
disk_file.write_all(&bytes[..]).unwrap();
|
||||||
|
disk_file.seek(SeekFrom::Start(0)).unwrap();
|
||||||
|
|
||||||
|
if let Ok(mut vhdx) = Vhdx::new(disk_file) {
|
||||||
|
if vhdx.seek(SeekFrom::Start(0)).is_ok() {
|
||||||
|
let mut offset = 0;
|
||||||
|
while offset < bytes.len() {
|
||||||
|
let mut data = vec![0; 8192];
|
||||||
|
vhdx.read_exact(&mut data).ok();
|
||||||
|
offset += data.len();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if vhdx.seek(SeekFrom::Start(0)).is_ok() {
|
||||||
|
let mut offset = 0;
|
||||||
|
while offset < bytes.len() {
|
||||||
|
let data = vec![0; 8192];
|
||||||
|
vhdx.write_all(&data).ok();
|
||||||
|
offset += data.len();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
fn memfd_create(name: &ffi::CStr, flags: u32) -> Result<RawFd, io::Error> {
|
||||||
|
let res = unsafe { libc::syscall(libc::SYS_memfd_create, name.as_ptr(), flags) };
|
||||||
|
|
||||||
|
if res < 0 {
|
||||||
|
Err(io::Error::last_os_error())
|
||||||
|
} else {
|
||||||
|
Ok(res as RawFd)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -11,25 +11,25 @@ mshv = ["mshv-ioctls", "mshv-bindings"]
|
|||||||
tdx = []
|
tdx = []
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "1.0"
|
anyhow = "1.0.44"
|
||||||
epoll = ">=4.0.1"
|
epoll = "4.3.1"
|
||||||
thiserror = "1.0"
|
thiserror = "1.0.30"
|
||||||
libc = "0.2.94"
|
libc = "0.2.103"
|
||||||
log = "0.4.14"
|
log = "0.4.14"
|
||||||
kvm-ioctls = { version = "0.8.0", optional = true }
|
kvm-ioctls = { version = "0.10.0", optional = true }
|
||||||
kvm-bindings = { git = "https://github.com/cloud-hypervisor/kvm-bindings", branch = "ch-v0.4.0", features = ["with-serde", "fam-wrappers"], optional = true }
|
kvm-bindings = { git = "https://github.com/cloud-hypervisor/kvm-bindings", branch = "ch-v0.5.0", features = ["with-serde", "fam-wrappers"], optional = true }
|
||||||
mshv-bindings = {git = "https://github.com/cloud-hypervisor/mshv", branch = "master", features = ["with-serde", "fam-wrappers"], optional = true }
|
mshv-bindings = {git = "https://github.com/rust-vmm/mshv", branch = "main", features = ["with-serde", "fam-wrappers"], optional = true }
|
||||||
mshv-ioctls = { git = "https://github.com/cloud-hypervisor/mshv", branch = "master", optional = true}
|
mshv-ioctls = { git = "https://github.com/rust-vmm/mshv", branch = "main", optional = true}
|
||||||
serde = {version = ">=1.0.27", features = ["rc"] }
|
serde = { version = "1.0.130", features = ["rc"] }
|
||||||
serde_derive = ">=1.0.27"
|
serde_derive = "1.0.130"
|
||||||
serde_json = ">=1.0.9"
|
serde_json = "1.0.68"
|
||||||
vm-memory = { version = "0.5.0", features = ["backend-mmap", "backend-atomic"] }
|
vm-memory = { version = "0.6.0", features = ["backend-mmap", "backend-atomic"] }
|
||||||
vmm-sys-util = { version = ">=0.5.0", features = ["with-serde"] }
|
vmm-sys-util = { version = "0.9.0", features = ["with-serde"] }
|
||||||
|
|
||||||
[target.'cfg(target_arch = "x86_64")'.dependencies.iced-x86]
|
[target.'cfg(target_arch = "x86_64")'.dependencies.iced-x86]
|
||||||
version = "1.11"
|
version = "1.15.0"
|
||||||
default-features = false
|
default-features = false
|
||||||
features = ["std", "decoder", "op_code_info", "instr_info", "fast_fmt"]
|
features = ["std", "decoder", "op_code_info", "instr_info", "fast_fmt"]
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
env_logger = "0.8.3"
|
env_logger = "0.9.0"
|
||||||
|
|||||||
@@ -4,8 +4,6 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
//
|
//
|
||||||
|
|
||||||
extern crate thiserror;
|
|
||||||
|
|
||||||
use core::fmt::Debug;
|
use core::fmt::Debug;
|
||||||
use std::fmt::{self, Display};
|
use std::fmt::{self, Display};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|||||||
@@ -10,8 +10,6 @@
|
|||||||
// CMP-Compare Two Operands
|
// CMP-Compare Two Operands
|
||||||
//
|
//
|
||||||
|
|
||||||
extern crate iced_x86;
|
|
||||||
|
|
||||||
use crate::arch::emulator::{EmulationError, PlatformEmulator};
|
use crate::arch::emulator::{EmulationError, PlatformEmulator};
|
||||||
use crate::arch::x86::emulator::instructions::*;
|
use crate::arch::x86::emulator::instructions::*;
|
||||||
use crate::arch::x86::regs::*;
|
use crate::arch::x86::regs::*;
|
||||||
|
|||||||
@@ -4,8 +4,6 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
//
|
//
|
||||||
|
|
||||||
extern crate iced_x86;
|
|
||||||
|
|
||||||
use crate::arch::emulator::{EmulationError, PlatformEmulator, PlatformError};
|
use crate::arch::emulator::{EmulationError, PlatformEmulator, PlatformError};
|
||||||
use crate::arch::x86::emulator::CpuStateManager;
|
use crate::arch::x86::emulator::CpuStateManager;
|
||||||
use crate::arch::x86::Exception;
|
use crate::arch::x86::Exception;
|
||||||
@@ -14,6 +12,7 @@ use iced_x86::*;
|
|||||||
pub mod cmp;
|
pub mod cmp;
|
||||||
pub mod mov;
|
pub mod mov;
|
||||||
pub mod movs;
|
pub mod movs;
|
||||||
|
pub mod or;
|
||||||
|
|
||||||
fn get_op<T: CpuStateManager>(
|
fn get_op<T: CpuStateManager>(
|
||||||
insn: &Instruction,
|
insn: &Instruction,
|
||||||
|
|||||||
@@ -12,8 +12,6 @@
|
|||||||
// Copies the second operand (source operand) to the first operand (destination operand).
|
// Copies the second operand (source operand) to the first operand (destination operand).
|
||||||
//
|
//
|
||||||
|
|
||||||
extern crate iced_x86;
|
|
||||||
|
|
||||||
use crate::arch::emulator::{EmulationError, PlatformEmulator};
|
use crate::arch::emulator::{EmulationError, PlatformEmulator};
|
||||||
use crate::arch::x86::emulator::instructions::*;
|
use crate::arch::x86::emulator::instructions::*;
|
||||||
use crate::arch::x86::Exception;
|
use crate::arch::x86::Exception;
|
||||||
|
|||||||
@@ -10,8 +10,6 @@
|
|||||||
// MOVS - Move Data from String to String
|
// MOVS - Move Data from String to String
|
||||||
//
|
//
|
||||||
|
|
||||||
extern crate iced_x86;
|
|
||||||
|
|
||||||
use crate::arch::emulator::{EmulationError, PlatformEmulator};
|
use crate::arch::emulator::{EmulationError, PlatformEmulator};
|
||||||
use crate::arch::x86::emulator::instructions::*;
|
use crate::arch::x86::emulator::instructions::*;
|
||||||
use crate::arch::x86::regs::DF;
|
use crate::arch::x86::regs::DF;
|
||||||
|
|||||||
83
hypervisor/src/arch/x86/emulator/instructions/or.rs
Normal file
83
hypervisor/src/arch/x86/emulator/instructions/or.rs
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
//
|
||||||
|
// Copyright © 2021 Microsoft
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
//
|
||||||
|
|
||||||
|
#![allow(non_camel_case_types)]
|
||||||
|
|
||||||
|
//
|
||||||
|
// OR - Logical inclusive OR
|
||||||
|
//
|
||||||
|
|
||||||
|
use crate::arch::emulator::{EmulationError, PlatformEmulator};
|
||||||
|
use crate::arch::x86::emulator::instructions::*;
|
||||||
|
use crate::arch::x86::Exception;
|
||||||
|
|
||||||
|
macro_rules! or_rm_r {
|
||||||
|
($bound:ty) => {
|
||||||
|
fn emulate(
|
||||||
|
&self,
|
||||||
|
insn: &Instruction,
|
||||||
|
state: &mut T,
|
||||||
|
platform: &mut dyn PlatformEmulator<CpuState = T>,
|
||||||
|
) -> Result<(), EmulationError<Exception>> {
|
||||||
|
let src_reg_value = get_op(&insn, 1, std::mem::size_of::<$bound>(), state, platform)
|
||||||
|
.map_err(EmulationError::PlatformEmulationError)?;
|
||||||
|
|
||||||
|
let dst_value = get_op(&insn, 0, std::mem::size_of::<$bound>(), state, platform)
|
||||||
|
.map_err(EmulationError::PlatformEmulationError)?;
|
||||||
|
|
||||||
|
let result = src_reg_value | dst_value;
|
||||||
|
|
||||||
|
set_op(
|
||||||
|
&insn,
|
||||||
|
0,
|
||||||
|
std::mem::size_of::<$bound>(),
|
||||||
|
state,
|
||||||
|
platform,
|
||||||
|
result,
|
||||||
|
)
|
||||||
|
.map_err(EmulationError::PlatformEmulationError)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Or_rm8_r8;
|
||||||
|
impl<T: CpuStateManager> InstructionHandler<T> for Or_rm8_r8 {
|
||||||
|
or_rm_r!(u8);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
#![allow(unused_mut)]
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
use crate::arch::x86::emulator::mock_vmm::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
// or byte ptr [rax+1h], sil
|
||||||
|
fn test_or_rm8_r8() {
|
||||||
|
let rax = 0;
|
||||||
|
let insn = [0x40, 0x08, 0x70, 0x1];
|
||||||
|
let cpu_id = 0;
|
||||||
|
let ip: u64 = 0x1000;
|
||||||
|
let sil = 0xaa;
|
||||||
|
let memory = [0x0, 0x55];
|
||||||
|
|
||||||
|
let mut vmm = MockVmm::new(
|
||||||
|
ip,
|
||||||
|
vec![(Register::SIL, sil), (Register::RAX, rax)],
|
||||||
|
Some((0, &memory)),
|
||||||
|
);
|
||||||
|
|
||||||
|
assert!(vmm.emulate_first_insn(cpu_id, &insn).is_ok());
|
||||||
|
|
||||||
|
let mut out: [u8; 1] = [0; 1];
|
||||||
|
|
||||||
|
vmm.read_memory(rax + 1, &mut out).unwrap();
|
||||||
|
assert_eq!(u8::from_le_bytes(out), 0xff);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,8 +4,6 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
//
|
//
|
||||||
|
|
||||||
extern crate iced_x86;
|
|
||||||
|
|
||||||
use crate::arch::emulator::{EmulationError, EmulationResult, PlatformEmulator, PlatformError};
|
use crate::arch::emulator::{EmulationError, EmulationResult, PlatformEmulator, PlatformError};
|
||||||
use crate::arch::x86::emulator::instructions::*;
|
use crate::arch::x86::emulator::instructions::*;
|
||||||
use crate::arch::x86::regs::*;
|
use crate::arch::x86::regs::*;
|
||||||
@@ -526,7 +524,9 @@ impl<'a, T: CpuStateManager> Emulator<'a, T> {
|
|||||||
(mov, Movzx_r32_rm16),
|
(mov, Movzx_r32_rm16),
|
||||||
(mov, Movzx_r64_rm16),
|
(mov, Movzx_r64_rm16),
|
||||||
// MOVS
|
// MOVS
|
||||||
(movs, Movsd_m32_m32)
|
(movs, Movsd_m32_m32),
|
||||||
|
// OR
|
||||||
|
(or, Or_rm8_r8)
|
||||||
);
|
);
|
||||||
|
|
||||||
handler
|
handler
|
||||||
@@ -640,8 +640,6 @@ impl<'a, T: CpuStateManager> Emulator<'a, T> {
|
|||||||
mod mock_vmm {
|
mod mock_vmm {
|
||||||
#![allow(unused_mut)]
|
#![allow(unused_mut)]
|
||||||
|
|
||||||
extern crate env_logger;
|
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::arch::emulator::{EmulationError, PlatformEmulator};
|
use crate::arch::emulator::{EmulationError, PlatformEmulator};
|
||||||
use crate::arch::x86::emulator::{Emulator, EmulatorCpuState as CpuState};
|
use crate::arch::x86::emulator::{Emulator, EmulatorCpuState as CpuState};
|
||||||
@@ -680,7 +678,7 @@ mod mock_vmm {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if let Some(mem) = memory {
|
if let Some(mem) = memory {
|
||||||
vmm.write_memory(mem.0, &mem.1).unwrap();
|
vmm.write_memory(mem.0, mem.1).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
vmm
|
vmm
|
||||||
@@ -695,7 +693,7 @@ mod mock_vmm {
|
|||||||
let ip = self.cpu_state(cpu_id).unwrap().ip();
|
let ip = self.cpu_state(cpu_id).unwrap().ip();
|
||||||
let mut emulator = Emulator::new(self);
|
let mut emulator = Emulator::new(self);
|
||||||
|
|
||||||
let new_state = emulator.emulate_insn_stream(cpu_id, &insn, num_insn)?;
|
let new_state = emulator.emulate_insn_stream(cpu_id, insn, num_insn)?;
|
||||||
if num_insn.is_none() {
|
if num_insn.is_none() {
|
||||||
assert_eq!(ip + insn.len() as u64, new_state.ip());
|
assert_eq!(ip + insn.len() as u64, new_state.ip());
|
||||||
}
|
}
|
||||||
@@ -718,7 +716,7 @@ mod mock_vmm {
|
|||||||
"Memory read {} bytes from [{:#x} -> {:#x}]",
|
"Memory read {} bytes from [{:#x} -> {:#x}]",
|
||||||
data.len(),
|
data.len(),
|
||||||
gva,
|
gva,
|
||||||
gva
|
gva + data.len() as u64 - 1
|
||||||
);
|
);
|
||||||
data.copy_from_slice(&self.memory[gva as usize..gva as usize + data.len()]);
|
data.copy_from_slice(&self.memory[gva as usize..gva as usize + data.len()]);
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -729,7 +727,7 @@ mod mock_vmm {
|
|||||||
"Memory write {} bytes at [{:#x} -> {:#x}]",
|
"Memory write {} bytes at [{:#x} -> {:#x}]",
|
||||||
data.len(),
|
data.len(),
|
||||||
gva,
|
gva,
|
||||||
gva
|
gva + data.len() as u64 - 1
|
||||||
);
|
);
|
||||||
self.memory[gva as usize..gva as usize + data.len()].copy_from_slice(data);
|
self.memory[gva as usize..gva as usize + data.len()].copy_from_slice(data);
|
||||||
|
|
||||||
|
|||||||
@@ -21,6 +21,8 @@ use crate::x86_64::{
|
|||||||
use crate::CpuState;
|
use crate::CpuState;
|
||||||
#[cfg(feature = "kvm")]
|
#[cfg(feature = "kvm")]
|
||||||
use crate::MpState;
|
use crate::MpState;
|
||||||
|
#[cfg(all(feature = "mshv", target_arch = "x86_64"))]
|
||||||
|
use crate::SuspendRegisters;
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
use crate::Xsave;
|
use crate::Xsave;
|
||||||
#[cfg(feature = "mshv")]
|
#[cfg(feature = "mshv")]
|
||||||
@@ -42,6 +44,11 @@ pub enum HypervisorCpuError {
|
|||||||
#[error("Failed to get standard registers: {0}")]
|
#[error("Failed to get standard registers: {0}")]
|
||||||
GetStandardRegs(#[source] anyhow::Error),
|
GetStandardRegs(#[source] anyhow::Error),
|
||||||
///
|
///
|
||||||
|
/// Getting suspend registers error
|
||||||
|
///
|
||||||
|
#[error("Failed to get suspend registers: {0}")]
|
||||||
|
GetSuspendRegs(#[source] anyhow::Error),
|
||||||
|
///
|
||||||
/// Setting special register error
|
/// Setting special register error
|
||||||
///
|
///
|
||||||
#[error("Failed to set special registers: {0}")]
|
#[error("Failed to set special registers: {0}")]
|
||||||
@@ -421,4 +428,9 @@ pub trait Vcpu: Send + Sync {
|
|||||||
///
|
///
|
||||||
#[cfg(feature = "tdx")]
|
#[cfg(feature = "tdx")]
|
||||||
fn tdx_init(&self, hob_address: u64) -> Result<()>;
|
fn tdx_init(&self, hob_address: u64) -> Result<()>;
|
||||||
|
#[cfg(all(feature = "mshv", target_arch = "x86_64"))]
|
||||||
|
///
|
||||||
|
/// Return suspend registers(explicit and intercept suspend registers)
|
||||||
|
///
|
||||||
|
fn get_suspend_regs(&self) -> Result<SuspendRegisters>;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,8 +12,6 @@ use crate::vm::Vm;
|
|||||||
use crate::x86_64::CpuId;
|
use crate::x86_64::CpuId;
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
use crate::x86_64::MsrList;
|
use crate::x86_64::MsrList;
|
||||||
#[cfg(all(feature = "kvm", target_arch = "x86_64"))]
|
|
||||||
use kvm_ioctls::Cap;
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
@@ -42,16 +40,6 @@ pub enum HypervisorError {
|
|||||||
#[error("Failed to get API Version: {0}")]
|
#[error("Failed to get API Version: {0}")]
|
||||||
GetApiVersion(#[source] anyhow::Error),
|
GetApiVersion(#[source] anyhow::Error),
|
||||||
///
|
///
|
||||||
/// Vcpu mmap error
|
|
||||||
///
|
|
||||||
#[error("Failed to get Vcpu Mmap: {0}")]
|
|
||||||
GetVcpuMmap(#[source] anyhow::Error),
|
|
||||||
///
|
|
||||||
/// Max Vcpu error
|
|
||||||
///
|
|
||||||
#[error("Failed to get number of max vcpus: {0}")]
|
|
||||||
GetMaxVcpu(#[source] anyhow::Error),
|
|
||||||
///
|
|
||||||
/// CpuId error
|
/// CpuId error
|
||||||
///
|
///
|
||||||
#[error("Failed to get cpuid: {0}")]
|
#[error("Failed to get cpuid: {0}")]
|
||||||
@@ -66,6 +54,11 @@ pub enum HypervisorError {
|
|||||||
///
|
///
|
||||||
#[error("Incompatible API version")]
|
#[error("Incompatible API version")]
|
||||||
IncompatibleApiVersion,
|
IncompatibleApiVersion,
|
||||||
|
///
|
||||||
|
/// Checking extensions failed
|
||||||
|
///
|
||||||
|
#[error("Checking extensions:{0}")]
|
||||||
|
CheckExtensions(#[source] anyhow::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
@@ -84,45 +77,32 @@ pub trait Hypervisor: Send + Sync {
|
|||||||
/// Return a hypervisor-agnostic Vm trait object
|
/// Return a hypervisor-agnostic Vm trait object
|
||||||
///
|
///
|
||||||
fn create_vm(&self) -> Result<Arc<dyn Vm>>;
|
fn create_vm(&self) -> Result<Arc<dyn Vm>>;
|
||||||
#[cfg(feature = "kvm")]
|
|
||||||
///
|
///
|
||||||
/// Create a Vm of a specific type using the underlying hypervisor
|
/// Create a Vm of a specific type using the underlying hypervisor
|
||||||
/// Return a hypervisor-agnostic Vm trait object
|
/// Return a hypervisor-agnostic Vm trait object
|
||||||
///
|
///
|
||||||
fn create_vm_with_type(&self, vm_type: u64) -> Result<Arc<dyn Vm>>;
|
fn create_vm_with_type(&self, _vm_type: u64) -> Result<Arc<dyn Vm>> {
|
||||||
#[cfg(feature = "kvm")]
|
unreachable!()
|
||||||
///
|
}
|
||||||
/// Returns the size of the memory mapping required to use the vcpu's structures
|
|
||||||
///
|
|
||||||
fn get_vcpu_mmap_size(&self) -> Result<usize>;
|
|
||||||
#[cfg(feature = "kvm")]
|
|
||||||
///
|
|
||||||
/// Gets the recommended maximum number of VCPUs per VM.
|
|
||||||
///
|
|
||||||
fn get_max_vcpus(&self) -> Result<usize>;
|
|
||||||
#[cfg(feature = "kvm")]
|
|
||||||
///
|
|
||||||
/// Gets the recommended number of VCPUs per VM.
|
|
||||||
///
|
|
||||||
fn get_nr_vcpus(&self) -> Result<usize>;
|
|
||||||
#[cfg(all(feature = "kvm", target_arch = "x86_64"))]
|
|
||||||
///
|
|
||||||
/// Checks if a particular `Cap` is available.
|
|
||||||
///
|
|
||||||
fn check_capability(&self, c: Cap) -> bool;
|
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
///
|
///
|
||||||
/// Get the supported CpuID
|
/// Get the supported CpuID
|
||||||
///
|
///
|
||||||
fn get_cpuid(&self) -> Result<CpuId>;
|
fn get_cpuid(&self) -> Result<CpuId>;
|
||||||
#[cfg(not(feature = "mshv"))]
|
|
||||||
///
|
///
|
||||||
/// Check particular extensions if any
|
/// Check particular extensions if any
|
||||||
///
|
///
|
||||||
fn check_required_extensions(&self) -> Result<()>;
|
fn check_required_extensions(&self) -> Result<()> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
///
|
///
|
||||||
/// Retrieve the list of MSRs supported by the hypervisor.
|
/// Retrieve the list of MSRs supported by the hypervisor.
|
||||||
///
|
///
|
||||||
fn get_msr_list(&self) -> Result<MsrList>;
|
fn get_msr_list(&self) -> Result<MsrList>;
|
||||||
|
#[cfg(target_arch = "aarch64")]
|
||||||
|
///
|
||||||
|
/// Retrieve AArch64 host maximum IPA size supported by KVM.
|
||||||
|
///
|
||||||
|
fn get_host_ipa_limit(&self) -> i32;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,19 +32,17 @@ pub use {kvm_ioctls::Cap, kvm_ioctls::Kvm};
|
|||||||
|
|
||||||
// This macro gets the offset of a structure (i.e `str`) member (i.e `field`) without having
|
// This macro gets the offset of a structure (i.e `str`) member (i.e `field`) without having
|
||||||
// an instance of that structure.
|
// an instance of that structure.
|
||||||
// It uses a null pointer to retrieve the offset to the field.
|
|
||||||
// Inspired by C solution: `#define offsetof(str, f) ((size_t)(&((str *)0)->f))`.
|
|
||||||
// Doing `offset__of!(user_pt_regs, pstate)` in our rust code will trigger the following:
|
|
||||||
// unsafe { &(*(0 as *const user_pt_regs)).pstate as *const _ as usize }
|
|
||||||
// The dereference expression produces an lvalue, but that lvalue is not actually read from,
|
|
||||||
// we're just doing pointer math on it, so in theory, it should safe.
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! offset__of {
|
macro_rules! offset__of {
|
||||||
($str:ty, $field:ident) => {
|
($str:ty, $($field:ident)+) => ({
|
||||||
unsafe { &(*std::ptr::null::<$str>()).$field as *const _ as usize }
|
let tmp: std::mem::MaybeUninit<$str> = std::mem::MaybeUninit::uninit();
|
||||||
};
|
let tmp = unsafe { tmp.assume_init() };
|
||||||
}
|
let base = &tmp as *const _ as usize;
|
||||||
|
let member = &tmp.$($field)* as *const _ as usize;
|
||||||
|
|
||||||
|
member - base
|
||||||
|
});
|
||||||
|
}
|
||||||
// Get the ID of a core register
|
// Get the ID of a core register
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! arm64_core_reg_id {
|
macro_rules! arm64_core_reg_id {
|
||||||
|
|||||||
@@ -22,11 +22,16 @@ use crate::vm::{self, VmmOps};
|
|||||||
use crate::{arm64_core_reg_id, offset__of};
|
use crate::{arm64_core_reg_id, offset__of};
|
||||||
use kvm_ioctls::{NoDatamatch, VcpuFd, VmFd};
|
use kvm_ioctls::{NoDatamatch, VcpuFd, VmFd};
|
||||||
use serde_derive::{Deserialize, Serialize};
|
use serde_derive::{Deserialize, Serialize};
|
||||||
|
use std::collections::HashMap;
|
||||||
|
#[cfg(target_arch = "aarch64")]
|
||||||
|
use std::convert::TryInto;
|
||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
|
use std::fs::File;
|
||||||
use std::os::unix::io::{AsRawFd, RawFd};
|
use std::os::unix::io::{AsRawFd, RawFd};
|
||||||
use std::result;
|
use std::result;
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
use std::sync::atomic::{AtomicBool, Ordering};
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
use std::sync::Arc;
|
use std::sync::{Arc, RwLock};
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
use vm_memory::Address;
|
use vm_memory::Address;
|
||||||
use vmm_sys_util::eventfd::EventFd;
|
use vmm_sys_util::eventfd::EventFd;
|
||||||
@@ -70,9 +75,9 @@ pub use kvm_ioctls;
|
|||||||
pub use kvm_ioctls::{Cap, Kvm};
|
pub use kvm_ioctls::{Cap, Kvm};
|
||||||
#[cfg(target_arch = "aarch64")]
|
#[cfg(target_arch = "aarch64")]
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
use thiserror::Error;
|
||||||
#[cfg(feature = "tdx")]
|
#[cfg(feature = "tdx")]
|
||||||
use vmm_sys_util::{ioctl::ioctl_with_val, ioctl_expr, ioctl_ioc_nr, ioctl_iowr_nr};
|
use vmm_sys_util::{ioctl::ioctl_with_val, ioctl_expr, ioctl_ioc_nr, ioctl_iowr_nr};
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Export generically-named wrappers of kvm-bindings for Unix-based platforms
|
/// Export generically-named wrappers of kvm-bindings for Unix-based platforms
|
||||||
///
|
///
|
||||||
@@ -85,6 +90,9 @@ pub use {
|
|||||||
kvm_ioctls::VcpuExit,
|
kvm_ioctls::VcpuExit,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
|
const KVM_CAP_SGX_ATTRIBUTE: u32 = 196;
|
||||||
|
|
||||||
#[cfg(feature = "tdx")]
|
#[cfg(feature = "tdx")]
|
||||||
ioctl_iowr_nr!(KVM_MEMORY_ENCRYPT_OP, KVMIO, 0xba, std::os::raw::c_ulong);
|
ioctl_iowr_nr!(KVM_MEMORY_ENCRYPT_OP, KVMIO, 0xba, std::os::raw::c_ulong);
|
||||||
|
|
||||||
@@ -103,12 +111,21 @@ enum TdxCommand {
|
|||||||
pub struct KvmVmState {}
|
pub struct KvmVmState {}
|
||||||
|
|
||||||
pub use KvmVmState as VmState;
|
pub use KvmVmState as VmState;
|
||||||
|
|
||||||
|
struct KvmDirtyLogSlot {
|
||||||
|
slot: u32,
|
||||||
|
guest_phys_addr: u64,
|
||||||
|
memory_size: u64,
|
||||||
|
userspace_addr: u64,
|
||||||
|
}
|
||||||
|
|
||||||
/// Wrapper over KVM VM ioctls.
|
/// Wrapper over KVM VM ioctls.
|
||||||
pub struct KvmVm {
|
pub struct KvmVm {
|
||||||
fd: Arc<VmFd>,
|
fd: Arc<VmFd>,
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
msrs: MsrEntries,
|
msrs: MsrEntries,
|
||||||
state: KvmVmState,
|
state: KvmVmState,
|
||||||
|
dirty_log_slots: Arc<RwLock<HashMap<u32, KvmDirtyLogSlot>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
@@ -161,7 +178,7 @@ impl vm::Vm for KvmVm {
|
|||||||
fn create_vcpu(
|
fn create_vcpu(
|
||||||
&self,
|
&self,
|
||||||
id: u8,
|
id: u8,
|
||||||
vmmops: Option<Arc<Box<dyn VmmOps>>>,
|
vmmops: Option<Arc<dyn VmmOps>>,
|
||||||
) -> vm::Result<Arc<dyn cpu::Vcpu>> {
|
) -> vm::Result<Arc<dyn cpu::Vcpu>> {
|
||||||
let vc = self
|
let vc = self
|
||||||
.fd
|
.fd
|
||||||
@@ -224,7 +241,7 @@ impl vm::Vm for KvmVm {
|
|||||||
unsafe {
|
unsafe {
|
||||||
let entries_slice: &mut [kvm_irq_routing_entry] =
|
let entries_slice: &mut [kvm_irq_routing_entry] =
|
||||||
irq_routing[0].entries.as_mut_slice(entries.len());
|
irq_routing[0].entries.as_mut_slice(entries.len());
|
||||||
entries_slice.copy_from_slice(&entries);
|
entries_slice.copy_from_slice(entries);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.fd
|
self.fd
|
||||||
@@ -232,7 +249,7 @@ impl vm::Vm for KvmVm {
|
|||||||
.map_err(|e| vm::HypervisorVmError::SetGsiRouting(e.into()))
|
.map_err(|e| vm::HypervisorVmError::SetGsiRouting(e.into()))
|
||||||
}
|
}
|
||||||
///
|
///
|
||||||
/// Creates a memory region structure that can be used with set_user_memory_region
|
/// Creates a memory region structure that can be used with {create/remove}_user_memory_region
|
||||||
///
|
///
|
||||||
fn make_user_memory_region(
|
fn make_user_memory_region(
|
||||||
&self,
|
&self,
|
||||||
@@ -257,14 +274,57 @@ impl vm::Vm for KvmVm {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
///
|
///
|
||||||
/// Creates/modifies a guest physical memory slot.
|
/// Creates a guest physical memory region.
|
||||||
///
|
///
|
||||||
fn set_user_memory_region(&self, user_memory_region: MemoryRegion) -> vm::Result<()> {
|
fn create_user_memory_region(&self, user_memory_region: MemoryRegion) -> vm::Result<()> {
|
||||||
|
let mut region = user_memory_region;
|
||||||
|
|
||||||
|
if (region.flags & KVM_MEM_LOG_DIRTY_PAGES) != 0 {
|
||||||
|
if (region.flags & KVM_MEM_READONLY) != 0 {
|
||||||
|
return Err(vm::HypervisorVmError::CreateUserMemory(anyhow!(
|
||||||
|
"Error creating regions with both 'dirty-pages-log' and 'read-only'."
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Keep track of the regions that need dirty pages log
|
||||||
|
self.dirty_log_slots.write().unwrap().insert(
|
||||||
|
region.slot,
|
||||||
|
KvmDirtyLogSlot {
|
||||||
|
slot: region.slot,
|
||||||
|
guest_phys_addr: region.guest_phys_addr,
|
||||||
|
memory_size: region.memory_size,
|
||||||
|
userspace_addr: region.userspace_addr,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
// Always create guest physical memory region without `KVM_MEM_LOG_DIRTY_PAGES`.
|
||||||
|
// For regions that need this flag, dirty pages log will be turned on in `start_dirty_log`.
|
||||||
|
region.flags = 0;
|
||||||
|
}
|
||||||
|
|
||||||
// Safe because guest regions are guaranteed not to overlap.
|
// Safe because guest regions are guaranteed not to overlap.
|
||||||
unsafe {
|
unsafe {
|
||||||
self.fd
|
self.fd
|
||||||
.set_user_memory_region(user_memory_region)
|
.set_user_memory_region(region)
|
||||||
.map_err(|e| vm::HypervisorVmError::SetUserMemory(e.into()))
|
.map_err(|e| vm::HypervisorVmError::CreateUserMemory(e.into()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
///
|
||||||
|
/// Removes a guest physical memory region.
|
||||||
|
///
|
||||||
|
fn remove_user_memory_region(&self, user_memory_region: MemoryRegion) -> vm::Result<()> {
|
||||||
|
let mut region = user_memory_region;
|
||||||
|
|
||||||
|
// Remove the corresponding entry from "self.dirty_log_slots" if needed
|
||||||
|
self.dirty_log_slots.write().unwrap().remove(®ion.slot);
|
||||||
|
|
||||||
|
// Setting the size to 0 means "remove"
|
||||||
|
region.memory_size = 0;
|
||||||
|
// Safe because guest regions are guaranteed not to overlap.
|
||||||
|
unsafe {
|
||||||
|
self.fd
|
||||||
|
.set_user_memory_region(region)
|
||||||
|
.map_err(|e| vm::HypervisorVmError::RemoveUserMemory(e.into()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
///
|
///
|
||||||
@@ -307,6 +367,18 @@ impl vm::Vm for KvmVm {
|
|||||||
.map_err(|e| vm::HypervisorVmError::EnableSplitIrq(e.into()))?;
|
.map_err(|e| vm::HypervisorVmError::EnableSplitIrq(e.into()))?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
|
fn enable_sgx_attribute(&self, file: File) -> vm::Result<()> {
|
||||||
|
let mut cap = kvm_enable_cap {
|
||||||
|
cap: KVM_CAP_SGX_ATTRIBUTE,
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
cap.args[0] = file.as_raw_fd() as u64;
|
||||||
|
self.fd
|
||||||
|
.enable_cap(&cap)
|
||||||
|
.map_err(|e| vm::HypervisorVmError::EnableSgxAttribute(e.into()))?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
/// Retrieve guest clock.
|
/// Retrieve guest clock.
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
fn get_clock(&self) -> vm::Result<ClockData> {
|
fn get_clock(&self) -> vm::Result<ClockData> {
|
||||||
@@ -349,10 +421,58 @@ impl vm::Vm for KvmVm {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Start logging dirty pages
|
||||||
|
///
|
||||||
|
fn start_dirty_log(&self) -> vm::Result<()> {
|
||||||
|
let dirty_log_slots = self.dirty_log_slots.read().unwrap();
|
||||||
|
for (_, s) in dirty_log_slots.iter() {
|
||||||
|
let region = MemoryRegion {
|
||||||
|
slot: s.slot,
|
||||||
|
guest_phys_addr: s.guest_phys_addr,
|
||||||
|
memory_size: s.memory_size,
|
||||||
|
userspace_addr: s.userspace_addr,
|
||||||
|
flags: KVM_MEM_LOG_DIRTY_PAGES,
|
||||||
|
};
|
||||||
|
// Safe because guest regions are guaranteed not to overlap.
|
||||||
|
unsafe {
|
||||||
|
self.fd
|
||||||
|
.set_user_memory_region(region)
|
||||||
|
.map_err(|e| vm::HypervisorVmError::StartDirtyLog(e.into()))?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Stop logging dirty pages
|
||||||
|
///
|
||||||
|
fn stop_dirty_log(&self) -> vm::Result<()> {
|
||||||
|
let dirty_log_slots = self.dirty_log_slots.read().unwrap();
|
||||||
|
for (_, s) in dirty_log_slots.iter() {
|
||||||
|
let region = MemoryRegion {
|
||||||
|
slot: s.slot,
|
||||||
|
guest_phys_addr: s.guest_phys_addr,
|
||||||
|
memory_size: s.memory_size,
|
||||||
|
userspace_addr: s.userspace_addr,
|
||||||
|
flags: 0,
|
||||||
|
};
|
||||||
|
// Safe because guest regions are guaranteed not to overlap.
|
||||||
|
unsafe {
|
||||||
|
self.fd
|
||||||
|
.set_user_memory_region(region)
|
||||||
|
.map_err(|e| vm::HypervisorVmError::StartDirtyLog(e.into()))?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Get dirty pages bitmap (one bit per page)
|
/// Get dirty pages bitmap (one bit per page)
|
||||||
///
|
///
|
||||||
fn get_dirty_log(&self, slot: u32, memory_size: u64) -> vm::Result<Vec<u64>> {
|
fn get_dirty_log(&self, slot: u32, _base_gpa: u64, memory_size: u64) -> vm::Result<Vec<u64>> {
|
||||||
self.fd
|
self.fd
|
||||||
.get_dirty_log(slot, memory_size as usize)
|
.get_dirty_log(slot, memory_size as usize)
|
||||||
.map_err(|e| vm::HypervisorVmError::GetDirtyLog(e.into()))
|
.map_err(|e| vm::HypervisorVmError::GetDirtyLog(e.into()))
|
||||||
@@ -366,15 +486,23 @@ impl vm::Vm for KvmVm {
|
|||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
struct TdxInitVm {
|
struct TdxInitVm {
|
||||||
max_vcpus: u32,
|
max_vcpus: u32,
|
||||||
reserved: u32,
|
tsc_khz: u32,
|
||||||
attributes: u64,
|
attributes: u64,
|
||||||
cpuid: u64,
|
cpuid: u64,
|
||||||
|
mrconfigid: [u64; 6],
|
||||||
|
mrowner: [u64; 6],
|
||||||
|
mrownerconfig: [u64; 6],
|
||||||
|
reserved: [u64; 43],
|
||||||
}
|
}
|
||||||
let data = TdxInitVm {
|
let data = TdxInitVm {
|
||||||
max_vcpus,
|
max_vcpus,
|
||||||
reserved: 0,
|
tsc_khz: 0,
|
||||||
attributes: 0,
|
attributes: 1, // TDX1_TD_ATTRIBUTE_DEBUG,
|
||||||
cpuid: cpuid.as_fam_struct_ptr() as u64,
|
cpuid: cpuid.as_fam_struct_ptr() as u64,
|
||||||
|
mrconfigid: [0; 6],
|
||||||
|
mrowner: [0; 6],
|
||||||
|
mrownerconfig: [0; 6],
|
||||||
|
reserved: [0; 43],
|
||||||
};
|
};
|
||||||
|
|
||||||
tdx_command(
|
tdx_command(
|
||||||
@@ -465,8 +593,9 @@ pub struct KvmHypervisor {
|
|||||||
kvm: Kvm,
|
kvm: Kvm,
|
||||||
}
|
}
|
||||||
/// Enum for KVM related error
|
/// Enum for KVM related error
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Error)]
|
||||||
pub enum KvmError {
|
pub enum KvmError {
|
||||||
|
#[error("Capability missing: {0:?}")]
|
||||||
CapabilityMissing(Cap),
|
CapabilityMissing(Cap),
|
||||||
}
|
}
|
||||||
pub type KvmResult<T> = result::Result<T, KvmError>;
|
pub type KvmResult<T> = result::Result<T, KvmError>;
|
||||||
@@ -536,6 +665,7 @@ impl hypervisor::Hypervisor for KvmHypervisor {
|
|||||||
fd: vm_fd,
|
fd: vm_fd,
|
||||||
msrs,
|
msrs,
|
||||||
state: VmState {},
|
state: VmState {},
|
||||||
|
dirty_log_slots: Arc::new(RwLock::new(HashMap::new())),
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -544,6 +674,7 @@ impl hypervisor::Hypervisor for KvmHypervisor {
|
|||||||
Ok(Arc::new(KvmVm {
|
Ok(Arc::new(KvmVm {
|
||||||
fd: vm_fd,
|
fd: vm_fd,
|
||||||
state: VmState {},
|
state: VmState {},
|
||||||
|
dirty_log_slots: Arc::new(RwLock::new(HashMap::new())),
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -557,41 +688,25 @@ impl hypervisor::Hypervisor for KvmHypervisor {
|
|||||||
/// let vm = hypervisor.create_vm().unwrap()
|
/// let vm = hypervisor.create_vm().unwrap()
|
||||||
///
|
///
|
||||||
fn create_vm(&self) -> hypervisor::Result<Arc<dyn vm::Vm>> {
|
fn create_vm(&self) -> hypervisor::Result<Arc<dyn vm::Vm>> {
|
||||||
self.create_vm_with_type(0) // Create with default platform type
|
#[allow(unused_mut)]
|
||||||
|
let mut vm_type: u64 = 0; // Create with default platform type
|
||||||
|
|
||||||
|
// When KVM supports Cap::ArmVmIPASize, it is better to get the IPA
|
||||||
|
// size from the host and use that when creating the VM, which may
|
||||||
|
// avoid unnecessary VM creation failures.
|
||||||
|
#[cfg(target_arch = "aarch64")]
|
||||||
|
if self.kvm.check_extension(Cap::ArmVmIPASize) {
|
||||||
|
vm_type = self.kvm.get_host_ipa_limit().try_into().unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
self.create_vm_with_type(vm_type)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_required_extensions(&self) -> hypervisor::Result<()> {
|
fn check_required_extensions(&self) -> hypervisor::Result<()> {
|
||||||
check_required_kvm_extensions(&self.kvm).expect("Missing KVM capabilities");
|
check_required_kvm_extensions(&self.kvm)
|
||||||
Ok(())
|
.map_err(|e| hypervisor::HypervisorError::CheckExtensions(e.into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
|
||||||
/// Returns the size of the memory mapping required to use the vcpu's `kvm_run` structure.
|
|
||||||
///
|
|
||||||
fn get_vcpu_mmap_size(&self) -> hypervisor::Result<usize> {
|
|
||||||
self.kvm
|
|
||||||
.get_vcpu_mmap_size()
|
|
||||||
.map_err(|e| hypervisor::HypervisorError::GetVcpuMmap(e.into()))
|
|
||||||
}
|
|
||||||
///
|
|
||||||
/// Gets the recommended maximum number of VCPUs per VM.
|
|
||||||
///
|
|
||||||
fn get_max_vcpus(&self) -> hypervisor::Result<usize> {
|
|
||||||
Ok(self.kvm.get_max_vcpus())
|
|
||||||
}
|
|
||||||
///
|
|
||||||
/// Gets the recommended number of VCPUs per VM.
|
|
||||||
///
|
|
||||||
fn get_nr_vcpus(&self) -> hypervisor::Result<usize> {
|
|
||||||
Ok(self.kvm.get_nr_vcpus())
|
|
||||||
}
|
|
||||||
#[cfg(target_arch = "x86_64")]
|
|
||||||
///
|
|
||||||
/// Checks if a particular `Cap` is available.
|
|
||||||
///
|
|
||||||
fn check_capability(&self, c: Cap) -> bool {
|
|
||||||
self.kvm.check_extension(c)
|
|
||||||
}
|
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
///
|
///
|
||||||
/// X86 specific call to get the system supported CPUID values.
|
/// X86 specific call to get the system supported CPUID values.
|
||||||
@@ -601,6 +716,7 @@ impl hypervisor::Hypervisor for KvmHypervisor {
|
|||||||
.get_supported_cpuid(kvm_bindings::KVM_MAX_CPUID_ENTRIES)
|
.get_supported_cpuid(kvm_bindings::KVM_MAX_CPUID_ENTRIES)
|
||||||
.map_err(|e| hypervisor::HypervisorError::GetCpuId(e.into()))
|
.map_err(|e| hypervisor::HypervisorError::GetCpuId(e.into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
///
|
///
|
||||||
/// Retrieve the list of MSRs supported by KVM.
|
/// Retrieve the list of MSRs supported by KVM.
|
||||||
@@ -610,13 +726,20 @@ impl hypervisor::Hypervisor for KvmHypervisor {
|
|||||||
.get_msr_index_list()
|
.get_msr_index_list()
|
||||||
.map_err(|e| hypervisor::HypervisorError::GetMsrList(e.into()))
|
.map_err(|e| hypervisor::HypervisorError::GetMsrList(e.into()))
|
||||||
}
|
}
|
||||||
|
#[cfg(target_arch = "aarch64")]
|
||||||
|
///
|
||||||
|
/// Retrieve AArch64 host maximum IPA size supported by KVM.
|
||||||
|
///
|
||||||
|
fn get_host_ipa_limit(&self) -> i32 {
|
||||||
|
self.kvm.get_host_ipa_limit()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
/// Vcpu struct for KVM
|
/// Vcpu struct for KVM
|
||||||
pub struct KvmVcpu {
|
pub struct KvmVcpu {
|
||||||
fd: VcpuFd,
|
fd: VcpuFd,
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
msrs: MsrEntries,
|
msrs: MsrEntries,
|
||||||
vmmops: Option<Arc<Box<dyn vm::VmmOps>>>,
|
vmmops: Option<Arc<dyn vm::VmmOps>>,
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
hyperv_synic: AtomicBool,
|
hyperv_synic: AtomicBool,
|
||||||
}
|
}
|
||||||
@@ -806,7 +929,7 @@ impl cpu::Vcpu for KvmVcpu {
|
|||||||
///
|
///
|
||||||
fn set_xcrs(&self, xcrs: &ExtendedControlRegisters) -> cpu::Result<()> {
|
fn set_xcrs(&self, xcrs: &ExtendedControlRegisters) -> cpu::Result<()> {
|
||||||
self.fd
|
self.fd
|
||||||
.set_xcrs(&xcrs)
|
.set_xcrs(xcrs)
|
||||||
.map_err(|e| cpu::HypervisorCpuError::SetXcsr(e.into()))
|
.map_err(|e| cpu::HypervisorCpuError::SetXcsr(e.into()))
|
||||||
}
|
}
|
||||||
///
|
///
|
||||||
@@ -1030,10 +1153,11 @@ impl cpu::Vcpu for KvmVcpu {
|
|||||||
// https://elixir.free-electrons.com/linux/v4.9.62/source/arch/arm64/include/uapi/asm/kvm.h#L53
|
// https://elixir.free-electrons.com/linux/v4.9.62/source/arch/arm64/include/uapi/asm/kvm.h#L53
|
||||||
let mut off = offset__of!(kvm_regs, fp_regs) + offset__of!(user_fpsimd_state, vregs);
|
let mut off = offset__of!(kvm_regs, fp_regs) + offset__of!(user_fpsimd_state, vregs);
|
||||||
for i in 0..32 {
|
for i in 0..32 {
|
||||||
state.fp_regs.vregs[i][0] = self
|
state.fp_regs.vregs[i] = self
|
||||||
.fd
|
.fd
|
||||||
.get_one_reg(arm64_core_reg_id!(KVM_REG_SIZE_U128, off))
|
.get_one_reg(arm64_core_reg_id!(KVM_REG_SIZE_U128, off))
|
||||||
.map_err(|e| cpu::HypervisorCpuError::GetCoreRegister(e.into()))?;
|
.map_err(|e| cpu::HypervisorCpuError::GetCoreRegister(e.into()))?
|
||||||
|
.into();
|
||||||
off += mem::size_of::<u128>();
|
off += mem::size_of::<u128>();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1110,7 +1234,7 @@ impl cpu::Vcpu for KvmVcpu {
|
|||||||
self.fd
|
self.fd
|
||||||
.set_one_reg(
|
.set_one_reg(
|
||||||
arm64_core_reg_id!(KVM_REG_SIZE_U128, off),
|
arm64_core_reg_id!(KVM_REG_SIZE_U128, off),
|
||||||
state.fp_regs.vregs[i][0],
|
state.fp_regs.vregs[i] as u64,
|
||||||
)
|
)
|
||||||
.map_err(|e| cpu::HypervisorCpuError::SetCoreRegister(e.into()))?;
|
.map_err(|e| cpu::HypervisorCpuError::SetCoreRegister(e.into()))?;
|
||||||
off += mem::size_of::<u128>();
|
off += mem::size_of::<u128>();
|
||||||
@@ -1150,19 +1274,12 @@ impl cpu::Vcpu for KvmVcpu {
|
|||||||
// call KVM_GET_ONE_REG on each id in order to save all of them. We carve out from the list
|
// call KVM_GET_ONE_REG on each id in order to save all of them. We carve out from the list
|
||||||
// the core registers which are represented in the kernel by kvm_regs structure and for which
|
// the core registers which are represented in the kernel by kvm_regs structure and for which
|
||||||
// we can calculate the id based on the offset in the structure.
|
// we can calculate the id based on the offset in the structure.
|
||||||
|
|
||||||
reg_list.retain(|regid| *regid != 0);
|
|
||||||
reg_list.as_slice().to_vec().sort_unstable();
|
|
||||||
|
|
||||||
reg_list.retain(|regid| is_system_register(*regid));
|
reg_list.retain(|regid| is_system_register(*regid));
|
||||||
|
|
||||||
// Now, for the rest of the registers left in the previously fetched register list, we are
|
// Now, for the rest of the registers left in the previously fetched register list, we are
|
||||||
// simply calling KVM_GET_ONE_REG.
|
// simply calling KVM_GET_ONE_REG.
|
||||||
let indices = reg_list.as_slice();
|
let indices = reg_list.as_slice();
|
||||||
for (_pos, index) in indices.iter().enumerate() {
|
for index in indices.iter() {
|
||||||
if _pos > 230 {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
state.push(kvm_bindings::kvm_one_reg {
|
state.push(kvm_bindings::kvm_one_reg {
|
||||||
id: *index,
|
id: *index,
|
||||||
addr: self
|
addr: self
|
||||||
@@ -1257,8 +1374,8 @@ impl cpu::Vcpu for KvmVcpu {
|
|||||||
0x40000020, 0x40000021, 0x40000080, 0x40000081, 0x40000082, 0x40000083, 0x40000084,
|
0x40000020, 0x40000021, 0x40000080, 0x40000081, 0x40000082, 0x40000083, 0x40000084,
|
||||||
0x40000090, 0x40000091, 0x40000092, 0x40000093, 0x40000094, 0x40000095, 0x40000096,
|
0x40000090, 0x40000091, 0x40000092, 0x40000093, 0x40000094, 0x40000095, 0x40000096,
|
||||||
0x40000097, 0x40000098, 0x40000099, 0x4000009a, 0x4000009b, 0x4000009c, 0x4000009d,
|
0x40000097, 0x40000098, 0x40000099, 0x4000009a, 0x4000009b, 0x4000009c, 0x4000009d,
|
||||||
0x4000009f, 0x400000b0, 0x400000b1, 0x400000b2, 0x400000b3, 0x400000b4, 0x400000b5,
|
0x4000009e, 0x4000009f, 0x400000b0, 0x400000b1, 0x400000b2, 0x400000b3, 0x400000b4,
|
||||||
0x400000b6, 0x400000b7,
|
0x400000b5, 0x400000b6, 0x400000b7,
|
||||||
];
|
];
|
||||||
for index in hyperv_synic_msrs {
|
for index in hyperv_synic_msrs {
|
||||||
let msr = kvm_msr_entry {
|
let msr = kvm_msr_entry {
|
||||||
|
|||||||
@@ -23,10 +23,6 @@ extern crate anyhow;
|
|||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate log;
|
extern crate log;
|
||||||
extern crate serde;
|
|
||||||
extern crate serde_derive;
|
|
||||||
extern crate serde_json;
|
|
||||||
extern crate thiserror;
|
|
||||||
|
|
||||||
/// Architecture specific definitions
|
/// Architecture specific definitions
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
|
|||||||
@@ -16,7 +16,8 @@ pub use mshv_bindings::*;
|
|||||||
pub use mshv_ioctls::IoEventAddress;
|
pub use mshv_ioctls::IoEventAddress;
|
||||||
use mshv_ioctls::{set_registers_64, Mshv, NoDatamatch, VcpuFd, VmFd};
|
use mshv_ioctls::{set_registers_64, Mshv, NoDatamatch, VcpuFd, VmFd};
|
||||||
use serde_derive::{Deserialize, Serialize};
|
use serde_derive::{Deserialize, Serialize};
|
||||||
use std::sync::Arc;
|
use std::collections::HashMap;
|
||||||
|
use std::sync::{Arc, RwLock};
|
||||||
use vm::DataMatch;
|
use vm::DataMatch;
|
||||||
// x86_64 dependencies
|
// x86_64 dependencies
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
@@ -28,8 +29,21 @@ pub use x86_64::VcpuMshvState as CpuState;
|
|||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
pub use x86_64::*;
|
pub use x86_64::*;
|
||||||
|
|
||||||
use std::os::unix::io::AsRawFd;
|
#[cfg(target_arch = "x86_64")]
|
||||||
use std::sync::RwLock;
|
use std::fs::File;
|
||||||
|
use std::os::unix::io::{AsRawFd, RawFd};
|
||||||
|
|
||||||
|
const DIRTY_BITMAP_CLEAR_DIRTY: u64 = 0x4;
|
||||||
|
const DIRTY_BITMAP_SET_DIRTY: u64 = 0x8;
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Export generically-named wrappers of mshv-bindings for Unix-based platforms
|
||||||
|
///
|
||||||
|
pub use {
|
||||||
|
mshv_bindings::mshv_create_device as CreateDevice,
|
||||||
|
mshv_bindings::mshv_device_attr as DeviceAttr,
|
||||||
|
mshv_bindings::mshv_msi_routing_entry as IrqRoutingEntry, mshv_ioctls::DeviceFd,
|
||||||
|
};
|
||||||
|
|
||||||
pub const PAGE_SHIFT: usize = 12;
|
pub const PAGE_SHIFT: usize = 12;
|
||||||
|
|
||||||
@@ -40,6 +54,11 @@ pub struct HvState {
|
|||||||
|
|
||||||
pub use HvState as VmState;
|
pub use HvState as VmState;
|
||||||
|
|
||||||
|
struct MshvDirtyLogSlot {
|
||||||
|
guest_pfn: u64,
|
||||||
|
memory_size: u64,
|
||||||
|
}
|
||||||
|
|
||||||
/// Wrapper over mshv system ioctls.
|
/// Wrapper over mshv system ioctls.
|
||||||
pub struct MshvHypervisor {
|
pub struct MshvHypervisor {
|
||||||
mshv: Mshv,
|
mshv: Mshv,
|
||||||
@@ -104,6 +123,7 @@ impl hypervisor::Hypervisor for MshvHypervisor {
|
|||||||
msrs,
|
msrs,
|
||||||
hv_state: hv_state_init(),
|
hv_state: hv_state_init(),
|
||||||
vmmops: None,
|
vmmops: None,
|
||||||
|
dirty_log_slots: Arc::new(RwLock::new(HashMap::new())),
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
///
|
///
|
||||||
@@ -131,7 +151,7 @@ pub struct MshvVcpu {
|
|||||||
cpuid: CpuId,
|
cpuid: CpuId,
|
||||||
msrs: MsrEntries,
|
msrs: MsrEntries,
|
||||||
hv_state: Arc<RwLock<HvState>>, // Mshv State
|
hv_state: Arc<RwLock<HvState>>, // Mshv State
|
||||||
vmmops: Option<Arc<Box<dyn vm::VmmOps>>>,
|
vmmops: Option<Arc<dyn vm::VmmOps>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Implementation of Vcpu trait for Microsoft Hypervisor
|
/// Implementation of Vcpu trait for Microsoft Hypervisor
|
||||||
@@ -235,7 +255,7 @@ impl cpu::Vcpu for MshvVcpu {
|
|||||||
///
|
///
|
||||||
fn set_xcrs(&self, xcrs: &ExtendedControlRegisters) -> cpu::Result<()> {
|
fn set_xcrs(&self, xcrs: &ExtendedControlRegisters) -> cpu::Result<()> {
|
||||||
self.fd
|
self.fd
|
||||||
.set_xcrs(&xcrs)
|
.set_xcrs(xcrs)
|
||||||
.map_err(|e| cpu::HypervisorCpuError::SetXcsr(e.into()))
|
.map_err(|e| cpu::HypervisorCpuError::SetXcsr(e.into()))
|
||||||
}
|
}
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
@@ -268,9 +288,7 @@ impl cpu::Vcpu for MshvVcpu {
|
|||||||
}
|
}
|
||||||
#[allow(non_upper_case_globals)]
|
#[allow(non_upper_case_globals)]
|
||||||
fn run(&self) -> std::result::Result<cpu::VmExit, cpu::HypervisorCpuError> {
|
fn run(&self) -> std::result::Result<cpu::VmExit, cpu::HypervisorCpuError> {
|
||||||
// Safe because this is just only done during initialization.
|
let hv_message: hv_message = hv_message::default();
|
||||||
// TODO don't zero it everytime we enter this function.
|
|
||||||
let hv_message: hv_message = unsafe { std::mem::zeroed() };
|
|
||||||
match self.fd.run(hv_message) {
|
match self.fd.run(hv_message) {
|
||||||
Ok(x) => match x.header.message_type {
|
Ok(x) => match x.header.message_type {
|
||||||
hv_message_type_HVMSG_X64_HALT => {
|
hv_message_type_HVMSG_X64_HALT => {
|
||||||
@@ -393,22 +411,22 @@ impl cpu::Vcpu for MshvVcpu {
|
|||||||
}
|
}
|
||||||
hv_message_type_HVMSG_X64_CPUID_INTERCEPT => {
|
hv_message_type_HVMSG_X64_CPUID_INTERCEPT => {
|
||||||
let info = x.to_cpuid_info().unwrap();
|
let info = x.to_cpuid_info().unwrap();
|
||||||
debug!("cpuid eax: {:x}", info.rax);
|
debug!("cpuid eax: {:x}", { info.rax });
|
||||||
Ok(cpu::VmExit::Ignore)
|
Ok(cpu::VmExit::Ignore)
|
||||||
}
|
}
|
||||||
hv_message_type_HVMSG_X64_MSR_INTERCEPT => {
|
hv_message_type_HVMSG_X64_MSR_INTERCEPT => {
|
||||||
let info = x.to_msr_info().unwrap();
|
let info = x.to_msr_info().unwrap();
|
||||||
if info.header.intercept_access_type == 0 {
|
if info.header.intercept_access_type == 0 {
|
||||||
debug!("msr read: {:x}", info.msr_number);
|
debug!("msr read: {:x}", { info.msr_number });
|
||||||
} else {
|
} else {
|
||||||
debug!("msr write: {:x}", info.msr_number);
|
debug!("msr write: {:x}", { info.msr_number });
|
||||||
}
|
}
|
||||||
Ok(cpu::VmExit::Ignore)
|
Ok(cpu::VmExit::Ignore)
|
||||||
}
|
}
|
||||||
hv_message_type_HVMSG_X64_EXCEPTION_INTERCEPT => {
|
hv_message_type_HVMSG_X64_EXCEPTION_INTERCEPT => {
|
||||||
//TODO: Handler for VMCALL here.
|
//TODO: Handler for VMCALL here.
|
||||||
let info = x.to_exception_info().unwrap();
|
let info = x.to_exception_info().unwrap();
|
||||||
debug!("Exception Info {:?}", info.exception_vector);
|
debug!("Exception Info {:?}", { info.exception_vector });
|
||||||
Ok(cpu::VmExit::Ignore)
|
Ok(cpu::VmExit::Ignore)
|
||||||
}
|
}
|
||||||
exit => Err(cpu::HypervisorCpuError::RunVcpu(anyhow!(
|
exit => Err(cpu::HypervisorCpuError::RunVcpu(anyhow!(
|
||||||
@@ -473,7 +491,7 @@ impl cpu::Vcpu for MshvVcpu {
|
|||||||
///
|
///
|
||||||
fn set_xsave(&self, xsave: &Xsave) -> cpu::Result<()> {
|
fn set_xsave(&self, xsave: &Xsave) -> cpu::Result<()> {
|
||||||
self.fd
|
self.fd
|
||||||
.set_xsave(*xsave)
|
.set_xsave(xsave)
|
||||||
.map_err(|e| cpu::HypervisorCpuError::SetXsaveState(e.into()))
|
.map_err(|e| cpu::HypervisorCpuError::SetXsaveState(e.into()))
|
||||||
}
|
}
|
||||||
///
|
///
|
||||||
@@ -534,6 +552,45 @@ impl cpu::Vcpu for MshvVcpu {
|
|||||||
|
|
||||||
Ok(r)
|
Ok(r)
|
||||||
}
|
}
|
||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
|
///
|
||||||
|
/// X86 specific call that returns the vcpu's current "suspend registers".
|
||||||
|
///
|
||||||
|
fn get_suspend_regs(&self) -> cpu::Result<SuspendRegisters> {
|
||||||
|
self.fd
|
||||||
|
.get_suspend_regs()
|
||||||
|
.map_err(|e| cpu::HypervisorCpuError::GetSuspendRegs(e.into()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Device struct for MSHV
|
||||||
|
pub struct MshvDevice {
|
||||||
|
fd: DeviceFd,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl device::Device for MshvDevice {
|
||||||
|
///
|
||||||
|
/// Set device attribute
|
||||||
|
///
|
||||||
|
fn set_device_attr(&self, attr: &DeviceAttr) -> device::Result<()> {
|
||||||
|
self.fd
|
||||||
|
.set_device_attr(attr)
|
||||||
|
.map_err(|e| device::HypervisorDeviceError::SetDeviceAttribute(e.into()))
|
||||||
|
}
|
||||||
|
///
|
||||||
|
/// Get device attribute
|
||||||
|
///
|
||||||
|
fn get_device_attr(&self, attr: &mut DeviceAttr) -> device::Result<()> {
|
||||||
|
self.fd
|
||||||
|
.get_device_attr(attr)
|
||||||
|
.map_err(|e| device::HypervisorDeviceError::GetDeviceAttribute(e.into()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsRawFd for MshvDevice {
|
||||||
|
fn as_raw_fd(&self) -> RawFd {
|
||||||
|
self.fd.as_raw_fd()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct MshvEmulatorContext<'a> {
|
struct MshvEmulatorContext<'a> {
|
||||||
@@ -559,7 +616,7 @@ impl<'a> MshvEmulatorContext<'a> {
|
|||||||
|
|
||||||
let result_code = unsafe { r.1.__bindgen_anon_1.result_code };
|
let result_code = unsafe { r.1.__bindgen_anon_1.result_code };
|
||||||
match result_code {
|
match result_code {
|
||||||
hv_translate_gva_result_code_HvTranslateGvaSuccess => Ok(r.0),
|
hv_translate_gva_result_code_HV_TRANSLATE_GVA_SUCCESS => Ok(r.0),
|
||||||
_ => Err(PlatformError::TranslateVirtualAddress(anyhow!(result_code))),
|
_ => Err(PlatformError::TranslateVirtualAddress(anyhow!(result_code))),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -669,7 +726,8 @@ pub struct MshvVm {
|
|||||||
msrs: MsrEntries,
|
msrs: MsrEntries,
|
||||||
// Hypervisor State
|
// Hypervisor State
|
||||||
hv_state: Arc<RwLock<HvState>>,
|
hv_state: Arc<RwLock<HvState>>,
|
||||||
vmmops: Option<Arc<Box<dyn vm::VmmOps>>>,
|
vmmops: Option<Arc<dyn vm::VmmOps>>,
|
||||||
|
dirty_log_slots: Arc<RwLock<HashMap<u64, MshvDirtyLogSlot>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn hv_state_init() -> Arc<RwLock<HvState>> {
|
fn hv_state_init() -> Arc<RwLock<HvState>> {
|
||||||
@@ -708,7 +766,7 @@ impl vm::Vm for MshvVm {
|
|||||||
debug!("register_irqfd fd {} gsi {}", fd.as_raw_fd(), gsi);
|
debug!("register_irqfd fd {} gsi {}", fd.as_raw_fd(), gsi);
|
||||||
|
|
||||||
self.fd
|
self.fd
|
||||||
.register_irqfd(&fd, gsi)
|
.register_irqfd(fd, gsi)
|
||||||
.map_err(|e| vm::HypervisorVmError::RegisterIrqFd(e.into()))?;
|
.map_err(|e| vm::HypervisorVmError::RegisterIrqFd(e.into()))?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -720,7 +778,7 @@ impl vm::Vm for MshvVm {
|
|||||||
debug!("unregister_irqfd fd {} gsi {}", fd.as_raw_fd(), gsi);
|
debug!("unregister_irqfd fd {} gsi {}", fd.as_raw_fd(), gsi);
|
||||||
|
|
||||||
self.fd
|
self.fd
|
||||||
.unregister_irqfd(&fd, gsi)
|
.unregister_irqfd(fd, gsi)
|
||||||
.map_err(|e| vm::HypervisorVmError::UnregisterIrqFd(e.into()))?;
|
.map_err(|e| vm::HypervisorVmError::UnregisterIrqFd(e.into()))?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -731,7 +789,7 @@ impl vm::Vm for MshvVm {
|
|||||||
fn create_vcpu(
|
fn create_vcpu(
|
||||||
&self,
|
&self,
|
||||||
id: u8,
|
id: u8,
|
||||||
vmmops: Option<Arc<Box<dyn VmmOps>>>,
|
vmmops: Option<Arc<dyn VmmOps>>,
|
||||||
) -> vm::Result<Arc<dyn cpu::Vcpu>> {
|
) -> vm::Result<Arc<dyn cpu::Vcpu>> {
|
||||||
let vcpu_fd = self
|
let vcpu_fd = self
|
||||||
.fd
|
.fd
|
||||||
@@ -751,6 +809,10 @@ impl vm::Vm for MshvVm {
|
|||||||
fn enable_split_irq(&self) -> vm::Result<()> {
|
fn enable_split_irq(&self) -> vm::Result<()> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
|
fn enable_sgx_attribute(&self, _file: File) -> vm::Result<()> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
fn register_ioevent(
|
fn register_ioevent(
|
||||||
&self,
|
&self,
|
||||||
fd: &EventFd,
|
fd: &EventFd,
|
||||||
@@ -789,11 +851,36 @@ impl vm::Vm for MshvVm {
|
|||||||
.map_err(|e| vm::HypervisorVmError::UnregisterIoEvent(e.into()))
|
.map_err(|e| vm::HypervisorVmError::UnregisterIoEvent(e.into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates/modifies a guest physical memory slot.
|
/// Creates a guest physical memory region.
|
||||||
fn set_user_memory_region(&self, user_memory_region: MemoryRegion) -> vm::Result<()> {
|
fn create_user_memory_region(&self, user_memory_region: MemoryRegion) -> vm::Result<()> {
|
||||||
|
// No matter read only or not we keep track the slots.
|
||||||
|
// For readonly hypervisor can enable the dirty bits,
|
||||||
|
// but a VM exit happens before setting the dirty bits
|
||||||
|
self.dirty_log_slots.write().unwrap().insert(
|
||||||
|
user_memory_region.guest_pfn,
|
||||||
|
MshvDirtyLogSlot {
|
||||||
|
guest_pfn: user_memory_region.guest_pfn,
|
||||||
|
memory_size: user_memory_region.size,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
self.fd
|
self.fd
|
||||||
.map_user_memory(user_memory_region)
|
.map_user_memory(user_memory_region)
|
||||||
.map_err(|e| vm::HypervisorVmError::SetUserMemory(e.into()))?;
|
.map_err(|e| vm::HypervisorVmError::CreateUserMemory(e.into()))?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Removes a guest physical memory region.
|
||||||
|
fn remove_user_memory_region(&self, user_memory_region: MemoryRegion) -> vm::Result<()> {
|
||||||
|
// Remove the corresponding entry from "self.dirty_log_slots" if needed
|
||||||
|
self.dirty_log_slots
|
||||||
|
.write()
|
||||||
|
.unwrap()
|
||||||
|
.remove(&user_memory_region.guest_pfn);
|
||||||
|
|
||||||
|
self.fd
|
||||||
|
.unmap_user_memory(user_memory_region)
|
||||||
|
.map_err(|e| vm::HypervisorVmError::RemoveUserMemory(e.into()))?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -819,10 +906,28 @@ impl vm::Vm for MshvVm {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Creates an in-kernel device.
|
||||||
|
///
|
||||||
|
/// See the documentation for `MSHV_CREATE_DEVICE`.
|
||||||
|
fn create_device(&self, device: &mut CreateDevice) -> vm::Result<Arc<dyn device::Device>> {
|
||||||
|
let fd = self
|
||||||
|
.fd
|
||||||
|
.create_device(device)
|
||||||
|
.map_err(|e| vm::HypervisorVmError::CreateDevice(e.into()))?;
|
||||||
|
let device = MshvDevice { fd };
|
||||||
|
Ok(Arc::new(device))
|
||||||
|
}
|
||||||
|
|
||||||
fn create_passthrough_device(&self) -> vm::Result<Arc<dyn device::Device>> {
|
fn create_passthrough_device(&self) -> vm::Result<Arc<dyn device::Device>> {
|
||||||
Err(vm::HypervisorVmError::CreatePassthroughDevice(anyhow!(
|
let mut vfio_dev = mshv_create_device {
|
||||||
"No passthrough support"
|
type_: mshv_device_type_MSHV_DEV_TYPE_VFIO,
|
||||||
)))
|
fd: 0,
|
||||||
|
flags: 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
self.create_device(&mut vfio_dev)
|
||||||
|
.map_err(|e| vm::HypervisorVmError::CreatePassthroughDevice(e.into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_gsi_routing(&self, entries: &[IrqRoutingEntry]) -> vm::Result<()> {
|
fn set_gsi_routing(&self, entries: &[IrqRoutingEntry]) -> vm::Result<()> {
|
||||||
@@ -833,7 +938,7 @@ impl vm::Vm for MshvVm {
|
|||||||
unsafe {
|
unsafe {
|
||||||
let entries_slice: &mut [mshv_msi_routing_entry] =
|
let entries_slice: &mut [mshv_msi_routing_entry] =
|
||||||
msi_routing[0].entries.as_mut_slice(entries.len());
|
msi_routing[0].entries.as_mut_slice(entries.len());
|
||||||
entries_slice.copy_from_slice(&entries);
|
entries_slice.copy_from_slice(entries);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.fd
|
self.fd
|
||||||
@@ -854,16 +959,44 @@ impl vm::Vm for MshvVm {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
///
|
///
|
||||||
|
/// Start logging dirty pages
|
||||||
|
///
|
||||||
|
fn start_dirty_log(&self) -> vm::Result<()> {
|
||||||
|
self.fd
|
||||||
|
.enable_dirty_page_tracking()
|
||||||
|
.map_err(|e| vm::HypervisorVmError::StartDirtyLog(e.into()))
|
||||||
|
}
|
||||||
|
///
|
||||||
|
/// Stop logging dirty pages
|
||||||
|
///
|
||||||
|
fn stop_dirty_log(&self) -> vm::Result<()> {
|
||||||
|
let dirty_log_slots = self.dirty_log_slots.read().unwrap();
|
||||||
|
// Before disabling the dirty page tracking we need
|
||||||
|
// to set the dirty bits in the Hypervisor
|
||||||
|
// This is a requirement from Microsoft Hypervisor
|
||||||
|
for (_, s) in dirty_log_slots.iter() {
|
||||||
|
self.fd
|
||||||
|
.get_dirty_log(s.guest_pfn, s.memory_size as usize, DIRTY_BITMAP_SET_DIRTY)
|
||||||
|
.map_err(|e| vm::HypervisorVmError::StartDirtyLog(e.into()))?;
|
||||||
|
}
|
||||||
|
self.fd
|
||||||
|
.disable_dirty_page_tracking()
|
||||||
|
.map_err(|e| vm::HypervisorVmError::StartDirtyLog(e.into()))?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
///
|
||||||
/// Get dirty pages bitmap (one bit per page)
|
/// Get dirty pages bitmap (one bit per page)
|
||||||
///
|
///
|
||||||
fn get_dirty_log(&self, _slot: u32, _memory_size: u64) -> vm::Result<Vec<u64>> {
|
fn get_dirty_log(&self, _slot: u32, base_gpa: u64, memory_size: u64) -> vm::Result<Vec<u64>> {
|
||||||
Err(vm::HypervisorVmError::GetDirtyLog(anyhow!(
|
self.fd
|
||||||
"get_dirty_log not implemented"
|
.get_dirty_log(
|
||||||
)))
|
base_gpa >> PAGE_SHIFT,
|
||||||
|
memory_size as usize,
|
||||||
|
DIRTY_BITMAP_CLEAR_DIRTY,
|
||||||
|
)
|
||||||
|
.map_err(|e| vm::HypervisorVmError::GetDirtyLog(e.into()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub use hv_cpuid_entry as CpuIdEntry;
|
pub use hv_cpuid_entry as CpuIdEntry;
|
||||||
|
|
||||||
pub type IrqRoutingEntry = mshv_msi_routing_entry;
|
|
||||||
|
|
||||||
pub const CPUID_FLAG_VALID_INDEX: u32 = 0;
|
pub const CPUID_FLAG_VALID_INDEX: u32 = 0;
|
||||||
|
|||||||
@@ -7,9 +7,10 @@
|
|||||||
// Copyright 2018-2019 CrowdStrike, Inc.
|
// Copyright 2018-2019 CrowdStrike, Inc.
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
|
use crate::arch::x86::{msr_index, SegmentRegisterOps, MTRR_ENABLE, MTRR_MEM_TYPE_WB};
|
||||||
use crate::arch::x86::{msr_index, SegmentRegisterOps};
|
|
||||||
use serde_derive::{Deserialize, Serialize};
|
use serde_derive::{Deserialize, Serialize};
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Export generically-named wrappers of mshv_bindings for Unix-based platforms
|
/// Export generically-named wrappers of mshv_bindings for Unix-based platforms
|
||||||
///
|
///
|
||||||
@@ -19,8 +20,8 @@ pub use {
|
|||||||
mshv_bindings::FloatingPointUnit as FpuState, mshv_bindings::LapicState,
|
mshv_bindings::FloatingPointUnit as FpuState, mshv_bindings::LapicState,
|
||||||
mshv_bindings::MsrList, mshv_bindings::Msrs as MsrEntries, mshv_bindings::Msrs,
|
mshv_bindings::MsrList, mshv_bindings::Msrs as MsrEntries, mshv_bindings::Msrs,
|
||||||
mshv_bindings::SegmentRegister, mshv_bindings::SpecialRegisters,
|
mshv_bindings::SegmentRegister, mshv_bindings::SpecialRegisters,
|
||||||
mshv_bindings::StandardRegisters, mshv_bindings::VcpuEvents, mshv_bindings::XSave as Xsave,
|
mshv_bindings::StandardRegisters, mshv_bindings::SuspendRegisters, mshv_bindings::VcpuEvents,
|
||||||
mshv_bindings::Xcrs as ExtendedControlRegisters,
|
mshv_bindings::XSave as Xsave, mshv_bindings::Xcrs as ExtendedControlRegisters,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Clone, Serialize, Deserialize)]
|
#[derive(Clone, Serialize, Deserialize)]
|
||||||
@@ -36,8 +37,30 @@ pub struct VcpuMshvState {
|
|||||||
pub xsave: Xsave,
|
pub xsave: Xsave,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct CreateDevice {}
|
impl fmt::Display for VcpuMshvState {
|
||||||
pub struct DeviceAttr {}
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
let expected_num_msrs = self.msrs.as_fam_struct_ref().nmsrs as usize;
|
||||||
|
let mut msr_entries = vec![vec![0; 2]; expected_num_msrs];
|
||||||
|
|
||||||
|
for (i, entry) in self.msrs.as_slice().iter().enumerate() {
|
||||||
|
msr_entries[i][1] = entry.data;
|
||||||
|
msr_entries[i][0] = entry.index as u64;
|
||||||
|
}
|
||||||
|
write!(f, "Number of MSRs: {}: MSRs: {:#010X?}, -- VCPU Events: {:?} -- Standard registers: {:?} Special Registers: {:?} ---- Floating Point Unit: {:?} --- Extended Control Register: {:?} --- Local APIC: {:?} --- DBG: {:?} --- Xsave: {:?}",
|
||||||
|
msr_entries.len(),
|
||||||
|
msr_entries,
|
||||||
|
self.vcpu_events,
|
||||||
|
self.regs,
|
||||||
|
self.sregs,
|
||||||
|
self.fpu,
|
||||||
|
self.xcrs,
|
||||||
|
self.lapic,
|
||||||
|
self.dbg,
|
||||||
|
self.xsave,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct IrqRouting {}
|
pub struct IrqRouting {}
|
||||||
pub enum VcpuExit {}
|
pub enum VcpuExit {}
|
||||||
pub struct MpState {}
|
pub struct MpState {}
|
||||||
@@ -118,6 +141,7 @@ pub fn boot_msr_entries() -> MsrEntries {
|
|||||||
msr!(msr_index::MSR_KERNEL_GS_BASE),
|
msr!(msr_index::MSR_KERNEL_GS_BASE),
|
||||||
msr!(msr_index::MSR_SYSCALL_MASK),
|
msr!(msr_index::MSR_SYSCALL_MASK),
|
||||||
msr!(msr_index::MSR_IA32_TSC),
|
msr!(msr_index::MSR_IA32_TSC),
|
||||||
|
msr_data!(msr_index::MSR_MTRRdefType, MTRR_ENABLE | MTRR_MEM_TYPE_WB),
|
||||||
])
|
])
|
||||||
.unwrap()
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ use crate::device::Device;
|
|||||||
use crate::x86_64::CpuId;
|
use crate::x86_64::CpuId;
|
||||||
#[cfg(all(feature = "kvm", target_arch = "x86_64"))]
|
#[cfg(all(feature = "kvm", target_arch = "x86_64"))]
|
||||||
use crate::ClockData;
|
use crate::ClockData;
|
||||||
#[cfg(feature = "kvm")]
|
|
||||||
use crate::CreateDevice;
|
use crate::CreateDevice;
|
||||||
#[cfg(feature = "mshv")]
|
#[cfg(feature = "mshv")]
|
||||||
use crate::HvState as VmState;
|
use crate::HvState as VmState;
|
||||||
@@ -25,6 +24,8 @@ use crate::KvmVmState as VmState;
|
|||||||
use crate::{IoEventAddress, IrqRoutingEntry, MemoryRegion};
|
use crate::{IoEventAddress, IrqRoutingEntry, MemoryRegion};
|
||||||
#[cfg(feature = "kvm")]
|
#[cfg(feature = "kvm")]
|
||||||
use kvm_ioctls::Cap;
|
use kvm_ioctls::Cap;
|
||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
|
use std::fs::File;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use vmm_sys_util::eventfd::EventFd;
|
use vmm_sys_util::eventfd::EventFd;
|
||||||
@@ -92,10 +93,15 @@ pub enum HypervisorVmError {
|
|||||||
#[error("Failed to set GSI routing: {0}")]
|
#[error("Failed to set GSI routing: {0}")]
|
||||||
SetGsiRouting(#[source] anyhow::Error),
|
SetGsiRouting(#[source] anyhow::Error),
|
||||||
///
|
///
|
||||||
/// Set user memory error
|
/// Create user memory error
|
||||||
///
|
///
|
||||||
#[error("Failed to set user memory: {0}")]
|
#[error("Failed to create user memory: {0}")]
|
||||||
SetUserMemory(#[source] anyhow::Error),
|
CreateUserMemory(#[source] anyhow::Error),
|
||||||
|
///
|
||||||
|
/// Remove user memory region error
|
||||||
|
///
|
||||||
|
#[error("Failed to remove user memory: {0}")]
|
||||||
|
RemoveUserMemory(#[source] anyhow::Error),
|
||||||
///
|
///
|
||||||
/// Create device error
|
/// Create device error
|
||||||
///
|
///
|
||||||
@@ -112,6 +118,11 @@ pub enum HypervisorVmError {
|
|||||||
#[error("Failed to enable split Irq: {0}")]
|
#[error("Failed to enable split Irq: {0}")]
|
||||||
EnableSplitIrq(#[source] anyhow::Error),
|
EnableSplitIrq(#[source] anyhow::Error),
|
||||||
///
|
///
|
||||||
|
/// Enable SGX attribute error
|
||||||
|
///
|
||||||
|
#[error("Failed to enable SGX attribute: {0}")]
|
||||||
|
EnableSgxAttribute(#[source] anyhow::Error),
|
||||||
|
///
|
||||||
/// Get clock error
|
/// Get clock error
|
||||||
///
|
///
|
||||||
#[error("Failed to get clock: {0}")]
|
#[error("Failed to get clock: {0}")]
|
||||||
@@ -156,6 +167,16 @@ pub enum HypervisorVmError {
|
|||||||
#[error("Failed to write to IO Bus: {0}")]
|
#[error("Failed to write to IO Bus: {0}")]
|
||||||
IoBusWrite(#[source] anyhow::Error),
|
IoBusWrite(#[source] anyhow::Error),
|
||||||
///
|
///
|
||||||
|
/// Start dirty log error
|
||||||
|
///
|
||||||
|
#[error("Failed to get dirty log: {0}")]
|
||||||
|
StartDirtyLog(#[source] anyhow::Error),
|
||||||
|
///
|
||||||
|
/// Stop dirty log error
|
||||||
|
///
|
||||||
|
#[error("Failed to get dirty log: {0}")]
|
||||||
|
StopDirtyLog(#[source] anyhow::Error),
|
||||||
|
///
|
||||||
/// Get dirty log error
|
/// Get dirty log error
|
||||||
///
|
///
|
||||||
#[error("Failed to get dirty log: {0}")]
|
#[error("Failed to get dirty log: {0}")]
|
||||||
@@ -206,7 +227,7 @@ pub trait Vm: Send + Sync {
|
|||||||
/// Unregister an event that will, when signaled, trigger the `gsi` IRQ.
|
/// Unregister an event that will, when signaled, trigger the `gsi` IRQ.
|
||||||
fn unregister_irqfd(&self, fd: &EventFd, gsi: u32) -> Result<()>;
|
fn unregister_irqfd(&self, fd: &EventFd, gsi: u32) -> Result<()>;
|
||||||
/// Creates a new KVM vCPU file descriptor and maps the memory corresponding
|
/// Creates a new KVM vCPU file descriptor and maps the memory corresponding
|
||||||
fn create_vcpu(&self, id: u8, vmmops: Option<Arc<Box<dyn VmmOps>>>) -> Result<Arc<dyn Vcpu>>;
|
fn create_vcpu(&self, id: u8, vmmops: Option<Arc<dyn VmmOps>>) -> Result<Arc<dyn Vcpu>>;
|
||||||
/// Registers an event to be signaled whenever a certain address is written to.
|
/// Registers an event to be signaled whenever a certain address is written to.
|
||||||
fn register_ioevent(
|
fn register_ioevent(
|
||||||
&self,
|
&self,
|
||||||
@@ -218,7 +239,7 @@ pub trait Vm: Send + Sync {
|
|||||||
fn unregister_ioevent(&self, fd: &EventFd, addr: &IoEventAddress) -> Result<()>;
|
fn unregister_ioevent(&self, fd: &EventFd, addr: &IoEventAddress) -> Result<()>;
|
||||||
/// Sets the GSI routing table entries, overwriting any previously set
|
/// Sets the GSI routing table entries, overwriting any previously set
|
||||||
fn set_gsi_routing(&self, entries: &[IrqRoutingEntry]) -> Result<()>;
|
fn set_gsi_routing(&self, entries: &[IrqRoutingEntry]) -> Result<()>;
|
||||||
/// Creates a memory region structure that can be used with set_user_memory_region
|
/// Creates a memory region structure that can be used with {create/remove}_user_memory_region
|
||||||
fn make_user_memory_region(
|
fn make_user_memory_region(
|
||||||
&self,
|
&self,
|
||||||
slot: u32,
|
slot: u32,
|
||||||
@@ -228,9 +249,10 @@ pub trait Vm: Send + Sync {
|
|||||||
readonly: bool,
|
readonly: bool,
|
||||||
log_dirty_pages: bool,
|
log_dirty_pages: bool,
|
||||||
) -> MemoryRegion;
|
) -> MemoryRegion;
|
||||||
/// Creates/modifies a guest physical memory slot.
|
/// Creates a guest physical memory slot.
|
||||||
fn set_user_memory_region(&self, user_memory_region: MemoryRegion) -> Result<()>;
|
fn create_user_memory_region(&self, user_memory_region: MemoryRegion) -> Result<()>;
|
||||||
#[cfg(feature = "kvm")]
|
/// Removes a guest physical memory slot.
|
||||||
|
fn remove_user_memory_region(&self, user_memory_region: MemoryRegion) -> Result<()>;
|
||||||
/// Creates an emulated device in the kernel.
|
/// Creates an emulated device in the kernel.
|
||||||
fn create_device(&self, device: &mut CreateDevice) -> Result<Arc<dyn Device>>;
|
fn create_device(&self, device: &mut CreateDevice) -> Result<Arc<dyn Device>>;
|
||||||
/// Returns the preferred CPU target type which can be emulated by KVM on underlying host.
|
/// Returns the preferred CPU target type which can be emulated by KVM on underlying host.
|
||||||
@@ -239,6 +261,8 @@ pub trait Vm: Send + Sync {
|
|||||||
/// Enable split Irq capability
|
/// Enable split Irq capability
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
fn enable_split_irq(&self) -> Result<()>;
|
fn enable_split_irq(&self) -> Result<()>;
|
||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
|
fn enable_sgx_attribute(&self, file: File) -> Result<()>;
|
||||||
/// Retrieve guest clock.
|
/// Retrieve guest clock.
|
||||||
#[cfg(all(feature = "kvm", target_arch = "x86_64"))]
|
#[cfg(all(feature = "kvm", target_arch = "x86_64"))]
|
||||||
fn get_clock(&self) -> Result<ClockData>;
|
fn get_clock(&self) -> Result<ClockData>;
|
||||||
@@ -254,8 +278,12 @@ pub trait Vm: Send + Sync {
|
|||||||
fn state(&self) -> Result<VmState>;
|
fn state(&self) -> Result<VmState>;
|
||||||
/// Set the VM state
|
/// Set the VM state
|
||||||
fn set_state(&self, state: VmState) -> Result<()>;
|
fn set_state(&self, state: VmState) -> Result<()>;
|
||||||
|
/// Start logging dirty pages
|
||||||
|
fn start_dirty_log(&self) -> Result<()>;
|
||||||
|
/// Stop logging dirty pages
|
||||||
|
fn stop_dirty_log(&self) -> Result<()>;
|
||||||
/// Get dirty pages bitmap
|
/// Get dirty pages bitmap
|
||||||
fn get_dirty_log(&self, slot: u32, memory_size: u64) -> Result<Vec<u64>>;
|
fn get_dirty_log(&self, slot: u32, base_gpa: u64, memory_size: u64) -> Result<Vec<u64>>;
|
||||||
#[cfg(feature = "tdx")]
|
#[cfg(feature = "tdx")]
|
||||||
/// Initalize TDX on this VM
|
/// Initalize TDX on this VM
|
||||||
fn tdx_init(&self, cpuid: &CpuId, max_vcpus: u32) -> Result<()>;
|
fn tdx_init(&self, cpuid: &CpuId, max_vcpus: u32) -> Result<()>;
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
name = "net_gen"
|
name = "net_gen"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
authors = ["The Chromium OS Authors"]
|
authors = ["The Chromium OS Authors"]
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
vmm-sys-util = ">=0.3.1"
|
vmm-sys-util = "0.9.0"
|
||||||
|
|||||||
@@ -1,24 +1,27 @@
|
|||||||
// Copyright 2017 The Chromium OS Authors. All rights reserved.
|
// Copyright © 2021 Intel Corporation
|
||||||
// Use of this source code is governed by a BSD-style license that can be
|
//
|
||||||
// found in the THIRD-PARTY file.
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
//
|
||||||
|
|
||||||
/* automatically generated by rust-bindgen */
|
// bindgen /usr/include/linux/if_tun.h --no-layout-tests
|
||||||
|
|
||||||
|
/* automatically generated by rust-bindgen 0.58.1 */
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct __IncompleteArrayField<T>(::std::marker::PhantomData<T>);
|
pub struct __IncompleteArrayField<T>(::std::marker::PhantomData<T>, [T; 0]);
|
||||||
impl<T> __IncompleteArrayField<T> {
|
impl<T> __IncompleteArrayField<T> {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn new() -> Self {
|
pub const fn new() -> Self {
|
||||||
__IncompleteArrayField(::std::marker::PhantomData)
|
__IncompleteArrayField(::std::marker::PhantomData, [])
|
||||||
}
|
}
|
||||||
#[inline]
|
#[inline]
|
||||||
pub unsafe fn as_ptr(&self) -> *const T {
|
pub fn as_ptr(&self) -> *const T {
|
||||||
::std::mem::transmute(self)
|
self as *const _ as *const T
|
||||||
}
|
}
|
||||||
#[inline]
|
#[inline]
|
||||||
pub unsafe fn as_mut_ptr(&mut self) -> *mut T {
|
pub fn as_mut_ptr(&mut self) -> *mut T {
|
||||||
::std::mem::transmute(self)
|
self as *mut _ as *mut T
|
||||||
}
|
}
|
||||||
#[inline]
|
#[inline]
|
||||||
pub unsafe fn as_slice(&self, len: usize) -> &[T] {
|
pub unsafe fn as_slice(&self, len: usize) -> &[T] {
|
||||||
@@ -30,191 +33,203 @@ impl<T> __IncompleteArrayField<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl<T> ::std::fmt::Debug for __IncompleteArrayField<T> {
|
impl<T> ::std::fmt::Debug for __IncompleteArrayField<T> {
|
||||||
fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
fn fmt(&self, fmt: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
|
||||||
fmt.write_str("__IncompleteArrayField")
|
fmt.write_str("__IncompleteArrayField")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl<T> ::std::clone::Clone for __IncompleteArrayField<T> {
|
pub const __BITS_PER_LONG: u32 = 64;
|
||||||
#[inline]
|
pub const __FD_SETSIZE: u32 = 1024;
|
||||||
fn clone(&self) -> Self {
|
pub const ETH_ALEN: u32 = 6;
|
||||||
Self::new()
|
pub const ETH_TLEN: u32 = 2;
|
||||||
}
|
pub const ETH_HLEN: u32 = 14;
|
||||||
}
|
pub const ETH_ZLEN: u32 = 60;
|
||||||
impl<T> ::std::marker::Copy for __IncompleteArrayField<T> {}
|
pub const ETH_DATA_LEN: u32 = 1500;
|
||||||
pub const __BITS_PER_LONG: ::std::os::raw::c_uint = 64;
|
pub const ETH_FRAME_LEN: u32 = 1514;
|
||||||
pub const __FD_SETSIZE: ::std::os::raw::c_uint = 1024;
|
pub const ETH_FCS_LEN: u32 = 4;
|
||||||
pub const ETH_ALEN: ::std::os::raw::c_uint = 6;
|
pub const ETH_MIN_MTU: u32 = 68;
|
||||||
pub const ETH_HLEN: ::std::os::raw::c_uint = 14;
|
pub const ETH_MAX_MTU: u32 = 65535;
|
||||||
pub const ETH_ZLEN: ::std::os::raw::c_uint = 60;
|
pub const ETH_P_LOOP: u32 = 96;
|
||||||
pub const ETH_DATA_LEN: ::std::os::raw::c_uint = 1500;
|
pub const ETH_P_PUP: u32 = 512;
|
||||||
pub const ETH_FRAME_LEN: ::std::os::raw::c_uint = 1514;
|
pub const ETH_P_PUPAT: u32 = 513;
|
||||||
pub const ETH_FCS_LEN: ::std::os::raw::c_uint = 4;
|
pub const ETH_P_TSN: u32 = 8944;
|
||||||
pub const ETH_P_LOOP: ::std::os::raw::c_uint = 96;
|
pub const ETH_P_ERSPAN2: u32 = 8939;
|
||||||
pub const ETH_P_PUP: ::std::os::raw::c_uint = 512;
|
pub const ETH_P_IP: u32 = 2048;
|
||||||
pub const ETH_P_PUPAT: ::std::os::raw::c_uint = 513;
|
pub const ETH_P_X25: u32 = 2053;
|
||||||
pub const ETH_P_TSN: ::std::os::raw::c_uint = 8944;
|
pub const ETH_P_ARP: u32 = 2054;
|
||||||
pub const ETH_P_IP: ::std::os::raw::c_uint = 2048;
|
pub const ETH_P_BPQ: u32 = 2303;
|
||||||
pub const ETH_P_X25: ::std::os::raw::c_uint = 2053;
|
pub const ETH_P_IEEEPUP: u32 = 2560;
|
||||||
pub const ETH_P_ARP: ::std::os::raw::c_uint = 2054;
|
pub const ETH_P_IEEEPUPAT: u32 = 2561;
|
||||||
pub const ETH_P_BPQ: ::std::os::raw::c_uint = 2303;
|
pub const ETH_P_BATMAN: u32 = 17157;
|
||||||
pub const ETH_P_IEEEPUP: ::std::os::raw::c_uint = 2560;
|
pub const ETH_P_DEC: u32 = 24576;
|
||||||
pub const ETH_P_IEEEPUPAT: ::std::os::raw::c_uint = 2561;
|
pub const ETH_P_DNA_DL: u32 = 24577;
|
||||||
pub const ETH_P_BATMAN: ::std::os::raw::c_uint = 17157;
|
pub const ETH_P_DNA_RC: u32 = 24578;
|
||||||
pub const ETH_P_DEC: ::std::os::raw::c_uint = 24576;
|
pub const ETH_P_DNA_RT: u32 = 24579;
|
||||||
pub const ETH_P_DNA_DL: ::std::os::raw::c_uint = 24577;
|
pub const ETH_P_LAT: u32 = 24580;
|
||||||
pub const ETH_P_DNA_RC: ::std::os::raw::c_uint = 24578;
|
pub const ETH_P_DIAG: u32 = 24581;
|
||||||
pub const ETH_P_DNA_RT: ::std::os::raw::c_uint = 24579;
|
pub const ETH_P_CUST: u32 = 24582;
|
||||||
pub const ETH_P_LAT: ::std::os::raw::c_uint = 24580;
|
pub const ETH_P_SCA: u32 = 24583;
|
||||||
pub const ETH_P_DIAG: ::std::os::raw::c_uint = 24581;
|
pub const ETH_P_TEB: u32 = 25944;
|
||||||
pub const ETH_P_CUST: ::std::os::raw::c_uint = 24582;
|
pub const ETH_P_RARP: u32 = 32821;
|
||||||
pub const ETH_P_SCA: ::std::os::raw::c_uint = 24583;
|
pub const ETH_P_ATALK: u32 = 32923;
|
||||||
pub const ETH_P_TEB: ::std::os::raw::c_uint = 25944;
|
pub const ETH_P_AARP: u32 = 33011;
|
||||||
pub const ETH_P_RARP: ::std::os::raw::c_uint = 32821;
|
pub const ETH_P_8021Q: u32 = 33024;
|
||||||
pub const ETH_P_ATALK: ::std::os::raw::c_uint = 32923;
|
pub const ETH_P_ERSPAN: u32 = 35006;
|
||||||
pub const ETH_P_AARP: ::std::os::raw::c_uint = 33011;
|
pub const ETH_P_IPX: u32 = 33079;
|
||||||
pub const ETH_P_8021Q: ::std::os::raw::c_uint = 33024;
|
pub const ETH_P_IPV6: u32 = 34525;
|
||||||
pub const ETH_P_IPX: ::std::os::raw::c_uint = 33079;
|
pub const ETH_P_PAUSE: u32 = 34824;
|
||||||
pub const ETH_P_IPV6: ::std::os::raw::c_uint = 34525;
|
pub const ETH_P_SLOW: u32 = 34825;
|
||||||
pub const ETH_P_PAUSE: ::std::os::raw::c_uint = 34824;
|
pub const ETH_P_WCCP: u32 = 34878;
|
||||||
pub const ETH_P_SLOW: ::std::os::raw::c_uint = 34825;
|
pub const ETH_P_MPLS_UC: u32 = 34887;
|
||||||
pub const ETH_P_WCCP: ::std::os::raw::c_uint = 34878;
|
pub const ETH_P_MPLS_MC: u32 = 34888;
|
||||||
pub const ETH_P_MPLS_UC: ::std::os::raw::c_uint = 34887;
|
pub const ETH_P_ATMMPOA: u32 = 34892;
|
||||||
pub const ETH_P_MPLS_MC: ::std::os::raw::c_uint = 34888;
|
pub const ETH_P_PPP_DISC: u32 = 34915;
|
||||||
pub const ETH_P_ATMMPOA: ::std::os::raw::c_uint = 34892;
|
pub const ETH_P_PPP_SES: u32 = 34916;
|
||||||
pub const ETH_P_PPP_DISC: ::std::os::raw::c_uint = 34915;
|
pub const ETH_P_LINK_CTL: u32 = 34924;
|
||||||
pub const ETH_P_PPP_SES: ::std::os::raw::c_uint = 34916;
|
pub const ETH_P_ATMFATE: u32 = 34948;
|
||||||
pub const ETH_P_LINK_CTL: ::std::os::raw::c_uint = 34924;
|
pub const ETH_P_PAE: u32 = 34958;
|
||||||
pub const ETH_P_ATMFATE: ::std::os::raw::c_uint = 34948;
|
pub const ETH_P_AOE: u32 = 34978;
|
||||||
pub const ETH_P_PAE: ::std::os::raw::c_uint = 34958;
|
pub const ETH_P_8021AD: u32 = 34984;
|
||||||
pub const ETH_P_AOE: ::std::os::raw::c_uint = 34978;
|
pub const ETH_P_802_EX1: u32 = 34997;
|
||||||
pub const ETH_P_8021AD: ::std::os::raw::c_uint = 34984;
|
pub const ETH_P_PREAUTH: u32 = 35015;
|
||||||
pub const ETH_P_802_EX1: ::std::os::raw::c_uint = 34997;
|
pub const ETH_P_TIPC: u32 = 35018;
|
||||||
pub const ETH_P_TIPC: ::std::os::raw::c_uint = 35018;
|
pub const ETH_P_LLDP: u32 = 35020;
|
||||||
pub const ETH_P_8021AH: ::std::os::raw::c_uint = 35047;
|
pub const ETH_P_MRP: u32 = 35043;
|
||||||
pub const ETH_P_MVRP: ::std::os::raw::c_uint = 35061;
|
pub const ETH_P_MACSEC: u32 = 35045;
|
||||||
pub const ETH_P_1588: ::std::os::raw::c_uint = 35063;
|
pub const ETH_P_8021AH: u32 = 35047;
|
||||||
pub const ETH_P_PRP: ::std::os::raw::c_uint = 35067;
|
pub const ETH_P_MVRP: u32 = 35061;
|
||||||
pub const ETH_P_FCOE: ::std::os::raw::c_uint = 35078;
|
pub const ETH_P_1588: u32 = 35063;
|
||||||
pub const ETH_P_TDLS: ::std::os::raw::c_uint = 35085;
|
pub const ETH_P_NCSI: u32 = 35064;
|
||||||
pub const ETH_P_FIP: ::std::os::raw::c_uint = 35092;
|
pub const ETH_P_PRP: u32 = 35067;
|
||||||
pub const ETH_P_80221: ::std::os::raw::c_uint = 35095;
|
pub const ETH_P_FCOE: u32 = 35078;
|
||||||
pub const ETH_P_LOOPBACK: ::std::os::raw::c_uint = 36864;
|
pub const ETH_P_IBOE: u32 = 35093;
|
||||||
pub const ETH_P_QINQ1: ::std::os::raw::c_uint = 37120;
|
pub const ETH_P_TDLS: u32 = 35085;
|
||||||
pub const ETH_P_QINQ2: ::std::os::raw::c_uint = 37376;
|
pub const ETH_P_FIP: u32 = 35092;
|
||||||
pub const ETH_P_QINQ3: ::std::os::raw::c_uint = 37632;
|
pub const ETH_P_80221: u32 = 35095;
|
||||||
pub const ETH_P_EDSA: ::std::os::raw::c_uint = 56026;
|
pub const ETH_P_HSR: u32 = 35119;
|
||||||
pub const ETH_P_AF_IUCV: ::std::os::raw::c_uint = 64507;
|
pub const ETH_P_NSH: u32 = 35151;
|
||||||
pub const ETH_P_802_3_MIN: ::std::os::raw::c_uint = 1536;
|
pub const ETH_P_LOOPBACK: u32 = 36864;
|
||||||
pub const ETH_P_802_3: ::std::os::raw::c_uint = 1;
|
pub const ETH_P_QINQ1: u32 = 37120;
|
||||||
pub const ETH_P_AX25: ::std::os::raw::c_uint = 2;
|
pub const ETH_P_QINQ2: u32 = 37376;
|
||||||
pub const ETH_P_ALL: ::std::os::raw::c_uint = 3;
|
pub const ETH_P_QINQ3: u32 = 37632;
|
||||||
pub const ETH_P_802_2: ::std::os::raw::c_uint = 4;
|
pub const ETH_P_EDSA: u32 = 56026;
|
||||||
pub const ETH_P_SNAP: ::std::os::raw::c_uint = 5;
|
pub const ETH_P_DSA_8021Q: u32 = 56027;
|
||||||
pub const ETH_P_DDCMP: ::std::os::raw::c_uint = 6;
|
pub const ETH_P_IFE: u32 = 60734;
|
||||||
pub const ETH_P_WAN_PPP: ::std::os::raw::c_uint = 7;
|
pub const ETH_P_AF_IUCV: u32 = 64507;
|
||||||
pub const ETH_P_PPP_MP: ::std::os::raw::c_uint = 8;
|
pub const ETH_P_802_3_MIN: u32 = 1536;
|
||||||
pub const ETH_P_LOCALTALK: ::std::os::raw::c_uint = 9;
|
pub const ETH_P_802_3: u32 = 1;
|
||||||
pub const ETH_P_CAN: ::std::os::raw::c_uint = 12;
|
pub const ETH_P_AX25: u32 = 2;
|
||||||
pub const ETH_P_CANFD: ::std::os::raw::c_uint = 13;
|
pub const ETH_P_ALL: u32 = 3;
|
||||||
pub const ETH_P_PPPTALK: ::std::os::raw::c_uint = 16;
|
pub const ETH_P_802_2: u32 = 4;
|
||||||
pub const ETH_P_TR_802_2: ::std::os::raw::c_uint = 17;
|
pub const ETH_P_SNAP: u32 = 5;
|
||||||
pub const ETH_P_MOBITEX: ::std::os::raw::c_uint = 21;
|
pub const ETH_P_DDCMP: u32 = 6;
|
||||||
pub const ETH_P_CONTROL: ::std::os::raw::c_uint = 22;
|
pub const ETH_P_WAN_PPP: u32 = 7;
|
||||||
pub const ETH_P_IRDA: ::std::os::raw::c_uint = 23;
|
pub const ETH_P_PPP_MP: u32 = 8;
|
||||||
pub const ETH_P_ECONET: ::std::os::raw::c_uint = 24;
|
pub const ETH_P_LOCALTALK: u32 = 9;
|
||||||
pub const ETH_P_HDLC: ::std::os::raw::c_uint = 25;
|
pub const ETH_P_CAN: u32 = 12;
|
||||||
pub const ETH_P_ARCNET: ::std::os::raw::c_uint = 26;
|
pub const ETH_P_CANFD: u32 = 13;
|
||||||
pub const ETH_P_DSA: ::std::os::raw::c_uint = 27;
|
pub const ETH_P_PPPTALK: u32 = 16;
|
||||||
pub const ETH_P_TRAILER: ::std::os::raw::c_uint = 28;
|
pub const ETH_P_TR_802_2: u32 = 17;
|
||||||
pub const ETH_P_PHONET: ::std::os::raw::c_uint = 245;
|
pub const ETH_P_MOBITEX: u32 = 21;
|
||||||
pub const ETH_P_IEEE802154: ::std::os::raw::c_uint = 246;
|
pub const ETH_P_CONTROL: u32 = 22;
|
||||||
pub const ETH_P_CAIF: ::std::os::raw::c_uint = 247;
|
pub const ETH_P_IRDA: u32 = 23;
|
||||||
pub const ETH_P_XDSA: ::std::os::raw::c_uint = 248;
|
pub const ETH_P_ECONET: u32 = 24;
|
||||||
pub const BPF_LD: ::std::os::raw::c_uint = 0;
|
pub const ETH_P_HDLC: u32 = 25;
|
||||||
pub const BPF_LDX: ::std::os::raw::c_uint = 1;
|
pub const ETH_P_ARCNET: u32 = 26;
|
||||||
pub const BPF_ST: ::std::os::raw::c_uint = 2;
|
pub const ETH_P_DSA: u32 = 27;
|
||||||
pub const BPF_STX: ::std::os::raw::c_uint = 3;
|
pub const ETH_P_TRAILER: u32 = 28;
|
||||||
pub const BPF_ALU: ::std::os::raw::c_uint = 4;
|
pub const ETH_P_PHONET: u32 = 245;
|
||||||
pub const BPF_JMP: ::std::os::raw::c_uint = 5;
|
pub const ETH_P_IEEE802154: u32 = 246;
|
||||||
pub const BPF_RET: ::std::os::raw::c_uint = 6;
|
pub const ETH_P_CAIF: u32 = 247;
|
||||||
pub const BPF_MISC: ::std::os::raw::c_uint = 7;
|
pub const ETH_P_XDSA: u32 = 248;
|
||||||
pub const BPF_W: ::std::os::raw::c_uint = 0;
|
pub const ETH_P_MAP: u32 = 249;
|
||||||
pub const BPF_H: ::std::os::raw::c_uint = 8;
|
pub const __UAPI_DEF_ETHHDR: u32 = 1;
|
||||||
pub const BPF_B: ::std::os::raw::c_uint = 16;
|
pub const BPF_LD: u32 = 0;
|
||||||
pub const BPF_IMM: ::std::os::raw::c_uint = 0;
|
pub const BPF_LDX: u32 = 1;
|
||||||
pub const BPF_ABS: ::std::os::raw::c_uint = 32;
|
pub const BPF_ST: u32 = 2;
|
||||||
pub const BPF_IND: ::std::os::raw::c_uint = 64;
|
pub const BPF_STX: u32 = 3;
|
||||||
pub const BPF_MEM: ::std::os::raw::c_uint = 96;
|
pub const BPF_ALU: u32 = 4;
|
||||||
pub const BPF_LEN: ::std::os::raw::c_uint = 128;
|
pub const BPF_JMP: u32 = 5;
|
||||||
pub const BPF_MSH: ::std::os::raw::c_uint = 160;
|
pub const BPF_RET: u32 = 6;
|
||||||
pub const BPF_ADD: ::std::os::raw::c_uint = 0;
|
pub const BPF_MISC: u32 = 7;
|
||||||
pub const BPF_SUB: ::std::os::raw::c_uint = 16;
|
pub const BPF_W: u32 = 0;
|
||||||
pub const BPF_MUL: ::std::os::raw::c_uint = 32;
|
pub const BPF_H: u32 = 8;
|
||||||
pub const BPF_DIV: ::std::os::raw::c_uint = 48;
|
pub const BPF_B: u32 = 16;
|
||||||
pub const BPF_OR: ::std::os::raw::c_uint = 64;
|
pub const BPF_IMM: u32 = 0;
|
||||||
pub const BPF_AND: ::std::os::raw::c_uint = 80;
|
pub const BPF_ABS: u32 = 32;
|
||||||
pub const BPF_LSH: ::std::os::raw::c_uint = 96;
|
pub const BPF_IND: u32 = 64;
|
||||||
pub const BPF_RSH: ::std::os::raw::c_uint = 112;
|
pub const BPF_MEM: u32 = 96;
|
||||||
pub const BPF_NEG: ::std::os::raw::c_uint = 128;
|
pub const BPF_LEN: u32 = 128;
|
||||||
pub const BPF_MOD: ::std::os::raw::c_uint = 144;
|
pub const BPF_MSH: u32 = 160;
|
||||||
pub const BPF_XOR: ::std::os::raw::c_uint = 160;
|
pub const BPF_ADD: u32 = 0;
|
||||||
pub const BPF_JA: ::std::os::raw::c_uint = 0;
|
pub const BPF_SUB: u32 = 16;
|
||||||
pub const BPF_JEQ: ::std::os::raw::c_uint = 16;
|
pub const BPF_MUL: u32 = 32;
|
||||||
pub const BPF_JGT: ::std::os::raw::c_uint = 32;
|
pub const BPF_DIV: u32 = 48;
|
||||||
pub const BPF_JGE: ::std::os::raw::c_uint = 48;
|
pub const BPF_OR: u32 = 64;
|
||||||
pub const BPF_JSET: ::std::os::raw::c_uint = 64;
|
pub const BPF_AND: u32 = 80;
|
||||||
pub const BPF_K: ::std::os::raw::c_uint = 0;
|
pub const BPF_LSH: u32 = 96;
|
||||||
pub const BPF_X: ::std::os::raw::c_uint = 8;
|
pub const BPF_RSH: u32 = 112;
|
||||||
pub const BPF_MAXINSNS: ::std::os::raw::c_uint = 4096;
|
pub const BPF_NEG: u32 = 128;
|
||||||
pub const BPF_MAJOR_VERSION: ::std::os::raw::c_uint = 1;
|
pub const BPF_MOD: u32 = 144;
|
||||||
pub const BPF_MINOR_VERSION: ::std::os::raw::c_uint = 1;
|
pub const BPF_XOR: u32 = 160;
|
||||||
pub const BPF_A: ::std::os::raw::c_uint = 16;
|
pub const BPF_JA: u32 = 0;
|
||||||
pub const BPF_TAX: ::std::os::raw::c_uint = 0;
|
pub const BPF_JEQ: u32 = 16;
|
||||||
pub const BPF_TXA: ::std::os::raw::c_uint = 128;
|
pub const BPF_JGT: u32 = 32;
|
||||||
pub const BPF_MEMWORDS: ::std::os::raw::c_uint = 16;
|
pub const BPF_JGE: u32 = 48;
|
||||||
pub const SKF_AD_OFF: ::std::os::raw::c_int = -4096;
|
pub const BPF_JSET: u32 = 64;
|
||||||
pub const SKF_AD_PROTOCOL: ::std::os::raw::c_uint = 0;
|
pub const BPF_K: u32 = 0;
|
||||||
pub const SKF_AD_PKTTYPE: ::std::os::raw::c_uint = 4;
|
pub const BPF_X: u32 = 8;
|
||||||
pub const SKF_AD_IFINDEX: ::std::os::raw::c_uint = 8;
|
pub const BPF_MAXINSNS: u32 = 4096;
|
||||||
pub const SKF_AD_NLATTR: ::std::os::raw::c_uint = 12;
|
pub const BPF_MAJOR_VERSION: u32 = 1;
|
||||||
pub const SKF_AD_NLATTR_NEST: ::std::os::raw::c_uint = 16;
|
pub const BPF_MINOR_VERSION: u32 = 1;
|
||||||
pub const SKF_AD_MARK: ::std::os::raw::c_uint = 20;
|
pub const BPF_A: u32 = 16;
|
||||||
pub const SKF_AD_QUEUE: ::std::os::raw::c_uint = 24;
|
pub const BPF_TAX: u32 = 0;
|
||||||
pub const SKF_AD_HATYPE: ::std::os::raw::c_uint = 28;
|
pub const BPF_TXA: u32 = 128;
|
||||||
pub const SKF_AD_RXHASH: ::std::os::raw::c_uint = 32;
|
pub const BPF_MEMWORDS: u32 = 16;
|
||||||
pub const SKF_AD_CPU: ::std::os::raw::c_uint = 36;
|
pub const SKF_AD_OFF: i32 = -4096;
|
||||||
pub const SKF_AD_ALU_XOR_X: ::std::os::raw::c_uint = 40;
|
pub const SKF_AD_PROTOCOL: u32 = 0;
|
||||||
pub const SKF_AD_VLAN_TAG: ::std::os::raw::c_uint = 44;
|
pub const SKF_AD_PKTTYPE: u32 = 4;
|
||||||
pub const SKF_AD_VLAN_TAG_PRESENT: ::std::os::raw::c_uint = 48;
|
pub const SKF_AD_IFINDEX: u32 = 8;
|
||||||
pub const SKF_AD_PAY_OFFSET: ::std::os::raw::c_uint = 52;
|
pub const SKF_AD_NLATTR: u32 = 12;
|
||||||
pub const SKF_AD_RANDOM: ::std::os::raw::c_uint = 56;
|
pub const SKF_AD_NLATTR_NEST: u32 = 16;
|
||||||
pub const SKF_AD_VLAN_TPID: ::std::os::raw::c_uint = 60;
|
pub const SKF_AD_MARK: u32 = 20;
|
||||||
pub const SKF_AD_MAX: ::std::os::raw::c_uint = 64;
|
pub const SKF_AD_QUEUE: u32 = 24;
|
||||||
pub const SKF_NET_OFF: ::std::os::raw::c_int = -1048576;
|
pub const SKF_AD_HATYPE: u32 = 28;
|
||||||
pub const SKF_LL_OFF: ::std::os::raw::c_int = -2097152;
|
pub const SKF_AD_RXHASH: u32 = 32;
|
||||||
pub const BPF_NET_OFF: ::std::os::raw::c_int = -1048576;
|
pub const SKF_AD_CPU: u32 = 36;
|
||||||
pub const BPF_LL_OFF: ::std::os::raw::c_int = -2097152;
|
pub const SKF_AD_ALU_XOR_X: u32 = 40;
|
||||||
pub const TUN_READQ_SIZE: ::std::os::raw::c_uint = 500;
|
pub const SKF_AD_VLAN_TAG: u32 = 44;
|
||||||
pub const TUN_TYPE_MASK: ::std::os::raw::c_uint = 15;
|
pub const SKF_AD_VLAN_TAG_PRESENT: u32 = 48;
|
||||||
pub const IFF_TUN: ::std::os::raw::c_uint = 1;
|
pub const SKF_AD_PAY_OFFSET: u32 = 52;
|
||||||
pub const IFF_TAP: ::std::os::raw::c_uint = 2;
|
pub const SKF_AD_RANDOM: u32 = 56;
|
||||||
pub const IFF_NO_PI: ::std::os::raw::c_uint = 4096;
|
pub const SKF_AD_VLAN_TPID: u32 = 60;
|
||||||
pub const IFF_ONE_QUEUE: ::std::os::raw::c_uint = 8192;
|
pub const SKF_AD_MAX: u32 = 64;
|
||||||
pub const IFF_VNET_HDR: ::std::os::raw::c_uint = 16384;
|
pub const SKF_NET_OFF: i32 = -1048576;
|
||||||
pub const IFF_TUN_EXCL: ::std::os::raw::c_uint = 32768;
|
pub const SKF_LL_OFF: i32 = -2097152;
|
||||||
pub const IFF_MULTI_QUEUE: ::std::os::raw::c_uint = 256;
|
pub const BPF_NET_OFF: i32 = -1048576;
|
||||||
pub const IFF_ATTACH_QUEUE: ::std::os::raw::c_uint = 512;
|
pub const BPF_LL_OFF: i32 = -2097152;
|
||||||
pub const IFF_DETACH_QUEUE: ::std::os::raw::c_uint = 1024;
|
pub const TUN_READQ_SIZE: u32 = 500;
|
||||||
pub const IFF_PERSIST: ::std::os::raw::c_uint = 2048;
|
pub const TUN_TYPE_MASK: u32 = 15;
|
||||||
pub const IFF_NOFILTER: ::std::os::raw::c_uint = 4096;
|
pub const IFF_TUN: u32 = 1;
|
||||||
pub const TUN_TX_TIMESTAMP: ::std::os::raw::c_uint = 1;
|
pub const IFF_TAP: u32 = 2;
|
||||||
pub const TUN_F_CSUM: ::std::os::raw::c_uint = 1;
|
pub const IFF_NAPI: u32 = 16;
|
||||||
pub const TUN_F_TSO4: ::std::os::raw::c_uint = 2;
|
pub const IFF_NAPI_FRAGS: u32 = 32;
|
||||||
pub const TUN_F_TSO6: ::std::os::raw::c_uint = 4;
|
pub const IFF_NO_PI: u32 = 4096;
|
||||||
pub const TUN_F_TSO_ECN: ::std::os::raw::c_uint = 8;
|
pub const IFF_ONE_QUEUE: u32 = 8192;
|
||||||
pub const TUN_F_UFO: ::std::os::raw::c_uint = 16;
|
pub const IFF_VNET_HDR: u32 = 16384;
|
||||||
pub const TUN_PKT_STRIP: ::std::os::raw::c_uint = 1;
|
pub const IFF_TUN_EXCL: u32 = 32768;
|
||||||
pub const TUN_FLT_ALLMULTI: ::std::os::raw::c_uint = 1;
|
pub const IFF_MULTI_QUEUE: u32 = 256;
|
||||||
|
pub const IFF_ATTACH_QUEUE: u32 = 512;
|
||||||
|
pub const IFF_DETACH_QUEUE: u32 = 1024;
|
||||||
|
pub const IFF_PERSIST: u32 = 2048;
|
||||||
|
pub const IFF_NOFILTER: u32 = 4096;
|
||||||
|
pub const TUN_TX_TIMESTAMP: u32 = 1;
|
||||||
|
pub const TUN_F_CSUM: u32 = 1;
|
||||||
|
pub const TUN_F_TSO4: u32 = 2;
|
||||||
|
pub const TUN_F_TSO6: u32 = 4;
|
||||||
|
pub const TUN_F_TSO_ECN: u32 = 8;
|
||||||
|
pub const TUN_F_UFO: u32 = 16;
|
||||||
|
pub const TUN_PKT_STRIP: u32 = 1;
|
||||||
|
pub const TUN_FLT_ALLMULTI: u32 = 1;
|
||||||
pub type __s8 = ::std::os::raw::c_schar;
|
pub type __s8 = ::std::os::raw::c_schar;
|
||||||
pub type __u8 = ::std::os::raw::c_uchar;
|
pub type __u8 = ::std::os::raw::c_uchar;
|
||||||
pub type __s16 = ::std::os::raw::c_short;
|
pub type __s16 = ::std::os::raw::c_short;
|
||||||
@@ -224,38 +239,10 @@ pub type __u32 = ::std::os::raw::c_uint;
|
|||||||
pub type __s64 = ::std::os::raw::c_longlong;
|
pub type __s64 = ::std::os::raw::c_longlong;
|
||||||
pub type __u64 = ::std::os::raw::c_ulonglong;
|
pub type __u64 = ::std::os::raw::c_ulonglong;
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Debug, Default, Copy)]
|
#[derive(Debug, Copy, Clone)]
|
||||||
pub struct __kernel_fd_set {
|
pub struct __kernel_fd_set {
|
||||||
pub fds_bits: [::std::os::raw::c_ulong; 16usize],
|
pub fds_bits: [::std::os::raw::c_ulong; 16usize],
|
||||||
}
|
}
|
||||||
#[test]
|
|
||||||
fn bindgen_test_layout___kernel_fd_set() {
|
|
||||||
assert_eq!(
|
|
||||||
::std::mem::size_of::<__kernel_fd_set>(),
|
|
||||||
128usize,
|
|
||||||
concat!("Size of: ", stringify!(__kernel_fd_set))
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
::std::mem::align_of::<__kernel_fd_set>(),
|
|
||||||
8usize,
|
|
||||||
concat!("Alignment of ", stringify!(__kernel_fd_set))
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
unsafe { &(*(0 as *const __kernel_fd_set)).fds_bits as *const _ as usize },
|
|
||||||
0usize,
|
|
||||||
concat!(
|
|
||||||
"Alignment of field: ",
|
|
||||||
stringify!(__kernel_fd_set),
|
|
||||||
"::",
|
|
||||||
stringify!(fds_bits)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
impl Clone for __kernel_fd_set {
|
|
||||||
fn clone(&self) -> Self {
|
|
||||||
*self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub type __kernel_sighandler_t =
|
pub type __kernel_sighandler_t =
|
||||||
::std::option::Option<unsafe extern "C" fn(arg1: ::std::os::raw::c_int)>;
|
::std::option::Option<unsafe extern "C" fn(arg1: ::std::os::raw::c_int)>;
|
||||||
pub type __kernel_key_t = ::std::os::raw::c_int;
|
pub type __kernel_key_t = ::std::os::raw::c_int;
|
||||||
@@ -279,41 +266,15 @@ pub type __kernel_size_t = __kernel_ulong_t;
|
|||||||
pub type __kernel_ssize_t = __kernel_long_t;
|
pub type __kernel_ssize_t = __kernel_long_t;
|
||||||
pub type __kernel_ptrdiff_t = __kernel_long_t;
|
pub type __kernel_ptrdiff_t = __kernel_long_t;
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Debug, Default, Copy)]
|
#[derive(Debug, Copy, Clone)]
|
||||||
pub struct __kernel_fsid_t {
|
pub struct __kernel_fsid_t {
|
||||||
pub val: [::std::os::raw::c_int; 2usize],
|
pub val: [::std::os::raw::c_int; 2usize],
|
||||||
}
|
}
|
||||||
#[test]
|
|
||||||
fn bindgen_test_layout___kernel_fsid_t() {
|
|
||||||
assert_eq!(
|
|
||||||
::std::mem::size_of::<__kernel_fsid_t>(),
|
|
||||||
8usize,
|
|
||||||
concat!("Size of: ", stringify!(__kernel_fsid_t))
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
::std::mem::align_of::<__kernel_fsid_t>(),
|
|
||||||
4usize,
|
|
||||||
concat!("Alignment of ", stringify!(__kernel_fsid_t))
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
unsafe { &(*(0 as *const __kernel_fsid_t)).val as *const _ as usize },
|
|
||||||
0usize,
|
|
||||||
concat!(
|
|
||||||
"Alignment of field: ",
|
|
||||||
stringify!(__kernel_fsid_t),
|
|
||||||
"::",
|
|
||||||
stringify!(val)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
impl Clone for __kernel_fsid_t {
|
|
||||||
fn clone(&self) -> Self {
|
|
||||||
*self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub type __kernel_off_t = __kernel_long_t;
|
pub type __kernel_off_t = __kernel_long_t;
|
||||||
pub type __kernel_loff_t = ::std::os::raw::c_longlong;
|
pub type __kernel_loff_t = ::std::os::raw::c_longlong;
|
||||||
|
pub type __kernel_old_time_t = __kernel_long_t;
|
||||||
pub type __kernel_time_t = __kernel_long_t;
|
pub type __kernel_time_t = __kernel_long_t;
|
||||||
|
pub type __kernel_time64_t = ::std::os::raw::c_longlong;
|
||||||
pub type __kernel_clock_t = __kernel_long_t;
|
pub type __kernel_clock_t = __kernel_long_t;
|
||||||
pub type __kernel_timer_t = ::std::os::raw::c_int;
|
pub type __kernel_timer_t = ::std::os::raw::c_int;
|
||||||
pub type __kernel_clockid_t = ::std::os::raw::c_int;
|
pub type __kernel_clockid_t = ::std::os::raw::c_int;
|
||||||
@@ -328,272 +289,38 @@ pub type __le64 = __u64;
|
|||||||
pub type __be64 = __u64;
|
pub type __be64 = __u64;
|
||||||
pub type __sum16 = __u16;
|
pub type __sum16 = __u16;
|
||||||
pub type __wsum = __u32;
|
pub type __wsum = __u32;
|
||||||
|
pub type __poll_t = ::std::os::raw::c_uint;
|
||||||
#[repr(C, packed)]
|
#[repr(C, packed)]
|
||||||
#[derive(Debug, Default, Copy)]
|
#[derive(Debug, Copy, Clone)]
|
||||||
pub struct ethhdr {
|
pub struct ethhdr {
|
||||||
pub h_dest: [::std::os::raw::c_uchar; 6usize],
|
pub h_dest: [::std::os::raw::c_uchar; 6usize],
|
||||||
pub h_source: [::std::os::raw::c_uchar; 6usize],
|
pub h_source: [::std::os::raw::c_uchar; 6usize],
|
||||||
pub h_proto: __be16,
|
pub h_proto: __be16,
|
||||||
}
|
}
|
||||||
#[test]
|
|
||||||
fn bindgen_test_layout_ethhdr() {
|
|
||||||
assert_eq!(
|
|
||||||
::std::mem::size_of::<ethhdr>(),
|
|
||||||
14usize,
|
|
||||||
concat!("Size of: ", stringify!(ethhdr))
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
::std::mem::align_of::<ethhdr>(),
|
|
||||||
1usize,
|
|
||||||
concat!("Alignment of ", stringify!(ethhdr))
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
unsafe { &(*(0 as *const ethhdr)).h_dest as *const _ as usize },
|
|
||||||
0usize,
|
|
||||||
concat!(
|
|
||||||
"Alignment of field: ",
|
|
||||||
stringify!(ethhdr),
|
|
||||||
"::",
|
|
||||||
stringify!(h_dest)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
unsafe { &(*(0 as *const ethhdr)).h_source as *const _ as usize },
|
|
||||||
6usize,
|
|
||||||
concat!(
|
|
||||||
"Alignment of field: ",
|
|
||||||
stringify!(ethhdr),
|
|
||||||
"::",
|
|
||||||
stringify!(h_source)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
unsafe { &(*(0 as *const ethhdr)).h_proto as *const _ as usize },
|
|
||||||
12usize,
|
|
||||||
concat!(
|
|
||||||
"Alignment of field: ",
|
|
||||||
stringify!(ethhdr),
|
|
||||||
"::",
|
|
||||||
stringify!(h_proto)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
impl Clone for ethhdr {
|
|
||||||
fn clone(&self) -> Self {
|
|
||||||
*self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Debug, Default, Copy)]
|
#[derive(Debug, Copy, Clone)]
|
||||||
pub struct sock_filter {
|
pub struct sock_filter {
|
||||||
pub code: __u16,
|
pub code: __u16,
|
||||||
pub jt: __u8,
|
pub jt: __u8,
|
||||||
pub jf: __u8,
|
pub jf: __u8,
|
||||||
pub k: __u32,
|
pub k: __u32,
|
||||||
}
|
}
|
||||||
#[test]
|
|
||||||
fn bindgen_test_layout_sock_filter() {
|
|
||||||
assert_eq!(
|
|
||||||
::std::mem::size_of::<sock_filter>(),
|
|
||||||
8usize,
|
|
||||||
concat!("Size of: ", stringify!(sock_filter))
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
::std::mem::align_of::<sock_filter>(),
|
|
||||||
4usize,
|
|
||||||
concat!("Alignment of ", stringify!(sock_filter))
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
unsafe { &(*(0 as *const sock_filter)).code as *const _ as usize },
|
|
||||||
0usize,
|
|
||||||
concat!(
|
|
||||||
"Alignment of field: ",
|
|
||||||
stringify!(sock_filter),
|
|
||||||
"::",
|
|
||||||
stringify!(code)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
unsafe { &(*(0 as *const sock_filter)).jt as *const _ as usize },
|
|
||||||
2usize,
|
|
||||||
concat!(
|
|
||||||
"Alignment of field: ",
|
|
||||||
stringify!(sock_filter),
|
|
||||||
"::",
|
|
||||||
stringify!(jt)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
unsafe { &(*(0 as *const sock_filter)).jf as *const _ as usize },
|
|
||||||
3usize,
|
|
||||||
concat!(
|
|
||||||
"Alignment of field: ",
|
|
||||||
stringify!(sock_filter),
|
|
||||||
"::",
|
|
||||||
stringify!(jf)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
unsafe { &(*(0 as *const sock_filter)).k as *const _ as usize },
|
|
||||||
4usize,
|
|
||||||
concat!(
|
|
||||||
"Alignment of field: ",
|
|
||||||
stringify!(sock_filter),
|
|
||||||
"::",
|
|
||||||
stringify!(k)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
impl Clone for sock_filter {
|
|
||||||
fn clone(&self) -> Self {
|
|
||||||
*self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Debug, Copy)]
|
#[derive(Debug, Copy, Clone)]
|
||||||
pub struct sock_fprog {
|
pub struct sock_fprog {
|
||||||
pub len: ::std::os::raw::c_ushort,
|
pub len: ::std::os::raw::c_ushort,
|
||||||
pub filter: *mut sock_filter,
|
pub filter: *mut sock_filter,
|
||||||
}
|
}
|
||||||
#[test]
|
|
||||||
fn bindgen_test_layout_sock_fprog() {
|
|
||||||
assert_eq!(
|
|
||||||
::std::mem::size_of::<sock_fprog>(),
|
|
||||||
16usize,
|
|
||||||
concat!("Size of: ", stringify!(sock_fprog))
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
::std::mem::align_of::<sock_fprog>(),
|
|
||||||
8usize,
|
|
||||||
concat!("Alignment of ", stringify!(sock_fprog))
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
unsafe { &(*(0 as *const sock_fprog)).len as *const _ as usize },
|
|
||||||
0usize,
|
|
||||||
concat!(
|
|
||||||
"Alignment of field: ",
|
|
||||||
stringify!(sock_fprog),
|
|
||||||
"::",
|
|
||||||
stringify!(len)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
unsafe { &(*(0 as *const sock_fprog)).filter as *const _ as usize },
|
|
||||||
8usize,
|
|
||||||
concat!(
|
|
||||||
"Alignment of field: ",
|
|
||||||
stringify!(sock_fprog),
|
|
||||||
"::",
|
|
||||||
stringify!(filter)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
impl Clone for sock_fprog {
|
|
||||||
fn clone(&self) -> Self {
|
|
||||||
*self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Default for sock_fprog {
|
|
||||||
fn default() -> Self {
|
|
||||||
unsafe { ::std::mem::zeroed() }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Debug, Default, Copy)]
|
#[derive(Debug, Copy, Clone)]
|
||||||
pub struct tun_pi {
|
pub struct tun_pi {
|
||||||
pub flags: __u16,
|
pub flags: __u16,
|
||||||
pub proto: __be16,
|
pub proto: __be16,
|
||||||
}
|
}
|
||||||
#[test]
|
|
||||||
fn bindgen_test_layout_tun_pi() {
|
|
||||||
assert_eq!(
|
|
||||||
::std::mem::size_of::<tun_pi>(),
|
|
||||||
4usize,
|
|
||||||
concat!("Size of: ", stringify!(tun_pi))
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
::std::mem::align_of::<tun_pi>(),
|
|
||||||
2usize,
|
|
||||||
concat!("Alignment of ", stringify!(tun_pi))
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
unsafe { &(*(0 as *const tun_pi)).flags as *const _ as usize },
|
|
||||||
0usize,
|
|
||||||
concat!(
|
|
||||||
"Alignment of field: ",
|
|
||||||
stringify!(tun_pi),
|
|
||||||
"::",
|
|
||||||
stringify!(flags)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
unsafe { &(*(0 as *const tun_pi)).proto as *const _ as usize },
|
|
||||||
2usize,
|
|
||||||
concat!(
|
|
||||||
"Alignment of field: ",
|
|
||||||
stringify!(tun_pi),
|
|
||||||
"::",
|
|
||||||
stringify!(proto)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
impl Clone for tun_pi {
|
|
||||||
fn clone(&self) -> Self {
|
|
||||||
*self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Debug, Default, Copy)]
|
#[derive(Debug)]
|
||||||
pub struct tun_filter {
|
pub struct tun_filter {
|
||||||
pub flags: __u16,
|
pub flags: __u16,
|
||||||
pub count: __u16,
|
pub count: __u16,
|
||||||
pub addr: __IncompleteArrayField<[__u8; 6usize]>,
|
pub addr: __IncompleteArrayField<[__u8; 6usize]>,
|
||||||
}
|
}
|
||||||
#[test]
|
|
||||||
fn bindgen_test_layout_tun_filter() {
|
|
||||||
assert_eq!(
|
|
||||||
::std::mem::size_of::<tun_filter>(),
|
|
||||||
4usize,
|
|
||||||
concat!("Size of: ", stringify!(tun_filter))
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
::std::mem::align_of::<tun_filter>(),
|
|
||||||
2usize,
|
|
||||||
concat!("Alignment of ", stringify!(tun_filter))
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
unsafe { &(*(0 as *const tun_filter)).flags as *const _ as usize },
|
|
||||||
0usize,
|
|
||||||
concat!(
|
|
||||||
"Alignment of field: ",
|
|
||||||
stringify!(tun_filter),
|
|
||||||
"::",
|
|
||||||
stringify!(flags)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
unsafe { &(*(0 as *const tun_filter)).count as *const _ as usize },
|
|
||||||
2usize,
|
|
||||||
concat!(
|
|
||||||
"Alignment of field: ",
|
|
||||||
stringify!(tun_filter),
|
|
||||||
"::",
|
|
||||||
stringify!(count)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
unsafe { &(*(0 as *const tun_filter)).addr as *const _ as usize },
|
|
||||||
4usize,
|
|
||||||
concat!(
|
|
||||||
"Alignment of field: ",
|
|
||||||
stringify!(tun_filter),
|
|
||||||
"::",
|
|
||||||
stringify!(addr)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
impl Clone for tun_filter {
|
|
||||||
fn clone(&self) -> Self {
|
|
||||||
*self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
3464
net_gen/src/iff.rs
3464
net_gen/src/iff.rs
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user