Update virtio-drivers-and-devices
Update to release 0.2.0 which adds support for virtio devices.
Bug: 379677575
Test: build.py generic-arm64-virt-test-debug
Change-Id: Ia9a787825ca38deccf5ef12fbc5f64b725d60bb7
diff --git a/crates/virtio-drivers-and-devices/.android-checksum.json b/crates/virtio-drivers-and-devices/.android-checksum.json
index 4dd9574..e23e7b7 100644
--- a/crates/virtio-drivers-and-devices/.android-checksum.json
+++ b/crates/virtio-drivers-and-devices/.android-checksum.json
@@ -1 +1 @@
-{"package":null,"files":{".cargo-checksum.json":"f65ad9971708b5e9fe23aca299d7b5264a310a467419ff0e7794427927cdce7e","Android.bp":"67c91d4de91355d1b6ceeb9fcd8fdcc07640121f85af1f1fef2992f4c4a9966f","Cargo.toml":"96372b8482a6d0ae6d48aa672a10c5595fe15bf72f4b4195b5c81a82c895ce99","LICENSE":"ac7199d689b436833681f33b881e0b619be2053c06b122327caabb5a6bdb59f1","METADATA":"a956406ea68c03b46197e8f01aed29fd9da01937f1023d742d4bdbc40ce3b57e","MODULE_LICENSE_MIT":"0d6f8afa3940b7f06bebee651376d43bc8b0d5b437337be2696d30377451e93a","README.md":"219043a36ccfc84d1534a533c60b6a51ab3133a0a545ad910a7b264ffd715a04","cargo_embargo.json":"7b71cc90988f45f9b7d5c3796f6e14007422aa187fefaab637b1e48791e4dc06","patches/rules.mk.diff":"afdb592f46d323d0e04ec3c033fb272fe7f79c28c5ad544f462bdac4c01f661b","rules.mk":"eb16608f20e25294ea89d77e48acea58de2796369e49b8a33ce0cdeffcbdaec0","rust-toolchain.toml":"e29f2ad5748c6738b191d46ca6a4204014c51626eca5c106ab575225d8c915db","src/config.rs":"d3d20c66c228e04dae12242a6b28e04c7e5062a06c0ebd21ce34197c379d7ad6","src/device/blk.rs":"30754d708b893899c7b3ab3eaabb67f83d7884194c5fb0b435779aa1db99c613","src/device/common.rs":"090d853e88b893aebe01606fafcd9cab96d4601f3b7ce3cb6721975801616e0d","src/device/console.rs":"93fbca8aba93d1bd6796df431904d12145104dd7c7c55ab2804a4a2faa07b63f","src/device/console/embedded_io.rs":"5413e487a506ed2699c20e9dd1eaf0014128649f4e342bfb3de6f8f6d440ba6a","src/device/gpu.rs":"103d987c4d61ef92d551dd30ed66f749399722efade48c4546f780ac84517c7f","src/device/input.rs":"935616b220dfd81d8a76d64e0603cf4b30af1f9803aa47f3dfd25605108d6d1e","src/device/mod.rs":"84c2e13a08d50b7ba647b256a747acbe9cc5da5a15781f94084bf3e5e4be5a34","src/device/net/dev.rs":"9279bf99a856e20a58869403b82e463a05ab4c1e41591f06da6f9f1b9e6c6b99","src/device/net/dev_raw.rs":"ccc32379b2419766859f7e294f94a1a62039488c0f9ac78e2e147c480cde598f","src/device/net/mod.rs":"1835cba939ebc327391edb52bc9a61960bb9657c520d81699b223ec90cd62ff1","src/device/net/net_buf.rs":"e8244dc0306578148c6e557405363b0004ae43587c07be2a16dbb2d4a8d8512e","src/device/socket/connectionmanager.rs":"6a8475466cc7c8da82a7c38c32cd9e5ad3215468e1befc7fbb5271156ca20997","src/device/socket/error.rs":"74d56c73ce369aeff74fb2f001833be4efc77f14b1640d46a3ad73bada860db3","src/device/socket/mod.rs":"46ba478462b1c003acf42d449763f0a7457d853ee282f9b9349a6749caa19d2b","src/device/socket/protocol.rs":"8e990eb25c1b5e667801e97380053290bf4e03c62417f83d22d43ae3b0d9c169","src/device/socket/vsock.rs":"a04fc932fd3d8581e4660211a2dc95f5bdf658942286a4d0a21fee87a5d5092e","src/device/sound.rs":"fe4a4d439741c1f3a0af49e4a80bcc28e1a2799c478338147cfcf4af1f4717fe","src/device/sound/fake.rs":"c29ed8453863f6abe9dca76615da835b642497679d12b6a32ce601346e23b39c","src/embedded_io.rs":"fcf955e398d05037e37473a2efce9bc29198263962597193ff49e3c8588f4eac","src/hal.rs":"f2d413f8924bfe50dbd2705f3febffd111a1ae17f160cdb5d9f12159ca3dc803","src/hal/fake.rs":"060d24879ca1a381597cadeb22de59b7d9940c3cca01b6f729729359bbbba071","src/lib.rs":"d8d4e0605da550c8646b7b5c68be8444e41bd488fc8016af34546674a02a6e90","src/queue.rs":"29fc69f616a7fa4785f5b3d53a05f8ee451db1d45fb8fd6f1ee797d18353a0f7","src/queue/owning.rs":"91d6e94764f5919d3e75fc52dd38e88f727452aa9141d2cdaba4b1ee2936cd6a","src/transport/fake.rs":"5e50cc3b5b07c77332542adade2cfd44bd9c205fd06824a6549cf197f187f813","src/transport/mmio.rs":"d6e7dd13ff496d2844b01878f1f189ff7c33df714b23a621b68aee4f0f111b01","src/transport/mod.rs":"f321a2aede13defe52550742e380f98e3e4fe449dfce1e9f2918f9a610c46232","src/transport/pci.rs":"2fc9f2449b7a231214a96223e32874ea41edee8dd08666a98a71d1f29cfed7a2","src/transport/pci/bus.rs":"7cd31b57ab6d95e2a9b66b7fe4c0076fd3279d4efae5cfb152059ed5c5e0f4f9","src/transport/some.rs":"3a528e0d22069583940cd568ea1575cf3a2f5e1d71a5e3a4a5675089bc7c6347","src/transport/x86_64.rs":"2f7f814dea5726ac8092d9b187ef9b84852aa2036a42ff921942fa947124ce0d","src/transport/x86_64/cam.rs":"ad9945e9963383fe64f19af4828b345adaf779e74eff9d5db5a92a98599d0990","src/transport/x86_64/hypercalls.rs":"ecd307178a0d4f6385f279139cfbefed73acd8a1052510ba5f68d1c588bab1c0","src/volatile.rs":"be8d90f7f5339d0276466c026ea78093aa15d96e94226250ac13e21a5f5ba200"}}
\ No newline at end of file
+{"package":null,"files":{".cargo-checksum.json":"4a9d56d931bb647c0014d97c7f0ac04b0dfc30e7ad9908036600c1fa250f666b","Android.bp":"67c91d4de91355d1b6ceeb9fcd8fdcc07640121f85af1f1fef2992f4c4a9966f","Cargo.toml":"2f405ccfacf93644caa4694e4f55f14524189cf7df1f5e266e561d8f5277eb65","LICENSE":"ac7199d689b436833681f33b881e0b619be2053c06b122327caabb5a6bdb59f1","METADATA":"045f4f436850fe9c98e654209e93f5dc46e53587612ae6d61ed04b74dc2eb93b","MODULE_LICENSE_MIT":"0d6f8afa3940b7f06bebee651376d43bc8b0d5b437337be2696d30377451e93a","README.md":"219043a36ccfc84d1534a533c60b6a51ab3133a0a545ad910a7b264ffd715a04","cargo_embargo.json":"7b71cc90988f45f9b7d5c3796f6e14007422aa187fefaab637b1e48791e4dc06","patches/rules.mk.diff":"afdb592f46d323d0e04ec3c033fb272fe7f79c28c5ad544f462bdac4c01f661b","rules.mk":"eb16608f20e25294ea89d77e48acea58de2796369e49b8a33ce0cdeffcbdaec0","rust-toolchain.toml":"e29f2ad5748c6738b191d46ca6a4204014c51626eca5c106ab575225d8c915db","src/config.rs":"d3d20c66c228e04dae12242a6b28e04c7e5062a06c0ebd21ce34197c379d7ad6","src/device/blk.rs":"c43c71740f9fde0836be6c40fac37beb060865fa4b495782be9f588b5fb8fc1f","src/device/common.rs":"090d853e88b893aebe01606fafcd9cab96d4601f3b7ce3cb6721975801616e0d","src/device/console.rs":"97756229ef87c607bda05c837ffbfb4e79e60110f16bcb4c35a0eb0af9ac3b9f","src/device/console/embedded_io.rs":"5413e487a506ed2699c20e9dd1eaf0014128649f4e342bfb3de6f8f6d440ba6a","src/device/gpu.rs":"8273d450181c61e6941bc478d374393d4d1ecdbb112363f4b4de6a2afdcb2aa8","src/device/input.rs":"935616b220dfd81d8a76d64e0603cf4b30af1f9803aa47f3dfd25605108d6d1e","src/device/mod.rs":"84c2e13a08d50b7ba647b256a747acbe9cc5da5a15781f94084bf3e5e4be5a34","src/device/net/dev.rs":"9279bf99a856e20a58869403b82e463a05ab4c1e41591f06da6f9f1b9e6c6b99","src/device/net/dev_raw.rs":"ccc32379b2419766859f7e294f94a1a62039488c0f9ac78e2e147c480cde598f","src/device/net/mod.rs":"1835cba939ebc327391edb52bc9a61960bb9657c520d81699b223ec90cd62ff1","src/device/net/net_buf.rs":"e8244dc0306578148c6e557405363b0004ae43587c07be2a16dbb2d4a8d8512e","src/device/socket/connectionmanager.rs":"6f45962c1ac360b84dde5030f232109527cab734157bd11bd305f53539e1a1bf","src/device/socket/error.rs":"74d56c73ce369aeff74fb2f001833be4efc77f14b1640d46a3ad73bada860db3","src/device/socket/mod.rs":"c9b28c32ba41618415114f2480999650165e657ec7447f7cd9eedb8c36b37fe0","src/device/socket/protocol.rs":"8e990eb25c1b5e667801e97380053290bf4e03c62417f83d22d43ae3b0d9c169","src/device/socket/vsock.rs":"eda46d6e3de3214c141ebce3faeeece97c71fbe083dcaa8a23081515ca75b143","src/device/sound.rs":"fe4a4d439741c1f3a0af49e4a80bcc28e1a2799c478338147cfcf4af1f4717fe","src/device/sound/fake.rs":"c29ed8453863f6abe9dca76615da835b642497679d12b6a32ce601346e23b39c","src/embedded_io.rs":"fcf955e398d05037e37473a2efce9bc29198263962597193ff49e3c8588f4eac","src/hal.rs":"34909e1c5cd9fb5cfd2ea6871868608a0e6542cabc26f5bfab6161ee0351c3ac","src/hal/fake.rs":"060d24879ca1a381597cadeb22de59b7d9940c3cca01b6f729729359bbbba071","src/lib.rs":"d45128ded2eba2ef0a5eff64b19e93ff00ab168a749585dcf900177eed633bda","src/queue.rs":"5d8952719f3e19590b26c58860062464e48cb871eaf15df2b0910eb968751bae","src/queue/owning.rs":"91d6e94764f5919d3e75fc52dd38e88f727452aa9141d2cdaba4b1ee2936cd6a","src/transport/fake.rs":"5e50cc3b5b07c77332542adade2cfd44bd9c205fd06824a6549cf197f187f813","src/transport/mmio.rs":"d6e7dd13ff496d2844b01878f1f189ff7c33df714b23a621b68aee4f0f111b01","src/transport/mod.rs":"6b499861c60ce405fe1135e9068b6a0b3323153ab8d2d6b1fa2bf59943e4caa8","src/transport/pci.rs":"2fc9f2449b7a231214a96223e32874ea41edee8dd08666a98a71d1f29cfed7a2","src/transport/pci/bus.rs":"7cd31b57ab6d95e2a9b66b7fe4c0076fd3279d4efae5cfb152059ed5c5e0f4f9","src/transport/some.rs":"3a528e0d22069583940cd568ea1575cf3a2f5e1d71a5e3a4a5675089bc7c6347","src/transport/x86_64.rs":"2f7f814dea5726ac8092d9b187ef9b84852aa2036a42ff921942fa947124ce0d","src/transport/x86_64/cam.rs":"ad9945e9963383fe64f19af4828b345adaf779e74eff9d5db5a92a98599d0990","src/transport/x86_64/hypercalls.rs":"ecd307178a0d4f6385f279139cfbefed73acd8a1052510ba5f68d1c588bab1c0","src/volatile.rs":"55e67a2b1ee94f900402eb1a413ed4dc8ba1747675375fb1ec655b28b8b7963b"}}
\ No newline at end of file
diff --git a/crates/virtio-drivers-and-devices/.cargo-checksum.json b/crates/virtio-drivers-and-devices/.cargo-checksum.json
index b0b6c06..7d52b65 100644
--- a/crates/virtio-drivers-and-devices/.cargo-checksum.json
+++ b/crates/virtio-drivers-and-devices/.cargo-checksum.json
@@ -1 +1 @@
-{"files":{"Cargo.toml":"080fd9ce4d835684e3cb84b3730beec4d7772b44048ddcddb741550301ca9ab5","LICENSE":"bf2a1b2f68528d6cb47939394b181236858d3e9c6c5e43b3af0650976567f152","README.md":"a9fb3f382f4799dafe3893aa3d50c55db9a73f212b782a7f1d9e05ad6b56ddc2","rust-toolchain.toml":"3e18e70208ee460635e239a91c142cf67371feafb718b05617ff06f388bf96df","src/config.rs":"7ecf338624732427964901c0a99e5e799ed28b50ee57bcd9bea8cfc467840e1b","src/device/blk.rs":"8af2cc29f1b1c94e6a5dd3eafbe005f9a1af87995ec12534ad701020be922d8e","src/device/common.rs":"24277c9fba38a2c87fa6f12863e6e003d911cc2fedad2b6a053d869e26be0813","src/device/console.rs":"4bcb383910157e95e8779354482e504ee2676c6b7f1f382216914f39c402a46c","src/device/console/embedded_io.rs":"a6dc2d2b65e157e93f2821c544c4127c1cf8743066e292607995845ed68c1315","src/device/gpu.rs":"42bfc652b90e37c3c27fafc5b6f5274e3c59533c1e14082095e6367971e1327f","src/device/input.rs":"5eb0265a91912efddbd0ac993b44d40bbf707e303cf79e9891e9c62d2c53c4b8","src/device/mod.rs":"225fd5d8c894df988d90e30df91477eeff60fefe9c8f5a789a0ae6c10ff1ea8d","src/device/net/dev.rs":"1cd4d08e64fb112d2e24c9a6985d1914f9848ba61984c8fe6d9b4c1798554749","src/device/net/dev_raw.rs":"08a1aa40254ef7c63bbe7812ee9d6673263f2f04798e19fb95cc135c1d321d5c","src/device/net/mod.rs":"cea6029659ed436f03d9b83d4eb36843b4c5c15de93c80b534fda041d223ce95","src/device/net/net_buf.rs":"1885931a2c1d5d35eb22036268e4f0c1105d60d90be391a438013dddd28bc27e","src/device/socket/connectionmanager.rs":"54a963b2645a71977aeb381682493a300c9b70a25f67b637d3dbfb99019a1246","src/device/socket/error.rs":"49b7edd279587b2460487d74cdfbdb35e6167ed5771bdfd252cc4bcda4416bca","src/device/socket/mod.rs":"891945d2e88002653a9588bcf0586d6c62792af8fc133c5d1d11262abffb47c1","src/device/socket/protocol.rs":"1f25ea5f3b786fddaa39f0a851ffae2b0f38da0edb4329f7bcd08c52a162f469","src/device/socket/vsock.rs":"4673e0155921c7bb5e185994c3271bf5ba7a35f362ae7c4acf1383aaa3882685","src/device/sound.rs":"8c1ec761503b498b39c9f584969c7abff0cd3d38f97aa3aa87e71f7f1edb3073","src/device/sound/fake.rs":"23078ffb3557067f39e5ad43134fb6fe2c7dea718f7ba86e18d986dd060311c1","src/embedded_io.rs":"409dc7953ba2dc8f99e19ec3ff859b7e7ca6475ba62eb22dbc1c4a7bfd09fabb","src/hal.rs":"f6defc683d81b15cfbb825372f67702565c4424c9988f9b1abb7854c5b31a10c","src/hal/fake.rs":"3ffb615f79e4a631e254c2c0cbd44df771acb4d2b4c4cbfd110cef9594a8ff8b","src/lib.rs":"49389c75172989100f44d12fbe61afad0f9588882f59a547c031fbba42d6642a","src/queue.rs":"04147914be69f6b5509677d1db24a9d155d9fae1e405ab79e1d2659a6e72364e","src/queue/owning.rs":"fffd8d620bee37446db616fe619b19c77c55c21ae66bcb93d800ca4fd34a70c3","src/transport/fake.rs":"53c4f890676ab5b4eb5f96005438abc7519ba36c67b125ac5a392bd6403b3ce6","src/transport/mmio.rs":"f3276d8a64e4291a6deb47ac29f2311f471901fc0dae38b47c20a18e8812ad70","src/transport/mod.rs":"62170489de007b8f9f3dbbb120302dce66e7e2733dbff1d713621a658b3c39a2","src/transport/pci.rs":"19c0d997a2f960ff5e55678187a6a0c359407fc88877f05de9bff74947b5b11b","src/transport/pci/bus.rs":"68c6a6761288bdbbc9d475ff4098e4e600975e2761ef2b4f63e9e4f6f340a44d","src/transport/some.rs":"18cf079e2da3368a2eb16cb45bf3330f6c61f139b8c796ad642f554a44224675","src/transport/x86_64.rs":"f2252446f6d06a0530b876277f878d4598857331c9a2da752326078292819fe3","src/transport/x86_64/cam.rs":"001a4eb9c434582377a212de1aaa2bccd5b5d5eeb968099fa43b040070f2dfbb","src/transport/x86_64/hypercalls.rs":"83d9c47348fcf920afe48f8e4168e46bc6b2ae3f7130d374aa449bcc332439a7","src/volatile.rs":"ca7005e30d1585ef91d750e354dfe6fb0ea1a427c3ffeb3ea2cfcd73c2611595"},"package":"087f2286ad55b6c36ec93267bcd1cbb740d7f9784879a001f76eea329d488273"}
\ No newline at end of file
+{"files":{"Cargo.toml":"8b140197204b7f3590b5df587efe54fffb449a223500b028b858706cf2d32d45","LICENSE":"bf2a1b2f68528d6cb47939394b181236858d3e9c6c5e43b3af0650976567f152","README.md":"a9fb3f382f4799dafe3893aa3d50c55db9a73f212b782a7f1d9e05ad6b56ddc2","rust-toolchain.toml":"3e18e70208ee460635e239a91c142cf67371feafb718b05617ff06f388bf96df","src/config.rs":"7ecf338624732427964901c0a99e5e799ed28b50ee57bcd9bea8cfc467840e1b","src/device/blk.rs":"83255da3753e02f7abce1d3c8a504756031ca66b4500b5d9b8141598bfaa927b","src/device/common.rs":"24277c9fba38a2c87fa6f12863e6e003d911cc2fedad2b6a053d869e26be0813","src/device/console.rs":"c0fa8f976819f769538c7d004e1414eb088b1d03b1dcb9ddeded3168e63ee97d","src/device/console/embedded_io.rs":"a6dc2d2b65e157e93f2821c544c4127c1cf8743066e292607995845ed68c1315","src/device/gpu.rs":"3b4ed0d0c6b7976e67ee2b4f8623ebf1c3d3d0c9cdd7d43808656171453b8c5d","src/device/input.rs":"5eb0265a91912efddbd0ac993b44d40bbf707e303cf79e9891e9c62d2c53c4b8","src/device/mod.rs":"225fd5d8c894df988d90e30df91477eeff60fefe9c8f5a789a0ae6c10ff1ea8d","src/device/net/dev.rs":"1cd4d08e64fb112d2e24c9a6985d1914f9848ba61984c8fe6d9b4c1798554749","src/device/net/dev_raw.rs":"08a1aa40254ef7c63bbe7812ee9d6673263f2f04798e19fb95cc135c1d321d5c","src/device/net/mod.rs":"cea6029659ed436f03d9b83d4eb36843b4c5c15de93c80b534fda041d223ce95","src/device/net/net_buf.rs":"1885931a2c1d5d35eb22036268e4f0c1105d60d90be391a438013dddd28bc27e","src/device/socket/connectionmanager.rs":"c0f67ee7bc7ef2ede4fb642c63a46d7e751e58609645ec1aabfdee2bed551fad","src/device/socket/error.rs":"49b7edd279587b2460487d74cdfbdb35e6167ed5771bdfd252cc4bcda4416bca","src/device/socket/mod.rs":"cdd335c585279d6e7c3ecd2dcf97c7273bab331c89d262af721fb3daea79b4fa","src/device/socket/protocol.rs":"1f25ea5f3b786fddaa39f0a851ffae2b0f38da0edb4329f7bcd08c52a162f469","src/device/socket/vsock.rs":"f17e3b128e52b7375d391f9a120edfcd9fb975c5dd725f1fe0f58e9f5f005cc2","src/device/sound.rs":"8c1ec761503b498b39c9f584969c7abff0cd3d38f97aa3aa87e71f7f1edb3073","src/device/sound/fake.rs":"23078ffb3557067f39e5ad43134fb6fe2c7dea718f7ba86e18d986dd060311c1","src/embedded_io.rs":"409dc7953ba2dc8f99e19ec3ff859b7e7ca6475ba62eb22dbc1c4a7bfd09fabb","src/hal.rs":"bb03f8ac8012f07bff7ea07e5563fd2dea954193240c5e01a5908bb9f842644d","src/hal/fake.rs":"3ffb615f79e4a631e254c2c0cbd44df771acb4d2b4c4cbfd110cef9594a8ff8b","src/lib.rs":"674ef7233219864c67fa5e9c64746a0521142f990ca73dcb7bf7fda8b0d905ce","src/queue.rs":"dce3c291798dedb68032d8cb4d3283bb2bd86f1bbf2bfc77e38c0bdd125b0dc8","src/queue/owning.rs":"fffd8d620bee37446db616fe619b19c77c55c21ae66bcb93d800ca4fd34a70c3","src/transport/fake.rs":"53c4f890676ab5b4eb5f96005438abc7519ba36c67b125ac5a392bd6403b3ce6","src/transport/mmio.rs":"f3276d8a64e4291a6deb47ac29f2311f471901fc0dae38b47c20a18e8812ad70","src/transport/mod.rs":"f5d851a774cac16613895d469f7e742b259872cc117f580d399914a56052027e","src/transport/pci.rs":"19c0d997a2f960ff5e55678187a6a0c359407fc88877f05de9bff74947b5b11b","src/transport/pci/bus.rs":"68c6a6761288bdbbc9d475ff4098e4e600975e2761ef2b4f63e9e4f6f340a44d","src/transport/some.rs":"18cf079e2da3368a2eb16cb45bf3330f6c61f139b8c796ad642f554a44224675","src/transport/x86_64.rs":"f2252446f6d06a0530b876277f878d4598857331c9a2da752326078292819fe3","src/transport/x86_64/cam.rs":"001a4eb9c434582377a212de1aaa2bccd5b5d5eeb968099fa43b040070f2dfbb","src/transport/x86_64/hypercalls.rs":"83d9c47348fcf920afe48f8e4168e46bc6b2ae3f7130d374aa449bcc332439a7","src/volatile.rs":"4585123a86cb8a92d422a6e5f55b37b9e3eac75d07908b70321d63a73601a0d0"},"package":"603664485269cf027cbbf54a2987426e6333d8fda4d0da65def6de0bc8868f51"}
\ No newline at end of file
diff --git a/crates/virtio-drivers-and-devices/Cargo.toml b/crates/virtio-drivers-and-devices/Cargo.toml
index fb677af..55a5258 100644
--- a/crates/virtio-drivers-and-devices/Cargo.toml
+++ b/crates/virtio-drivers-and-devices/Cargo.toml
@@ -12,7 +12,7 @@
[package]
edition = "2021"
name = "virtio-drivers-and-devices"
-version = "0.1.0"
+version = "0.2.0"
authors = [
"Jiajie Chen <noc@jiegec.ac.cn>",
"Runji Wang <wangrunji0408@163.com>",
@@ -36,6 +36,14 @@
license = "MIT"
repository = "https://github.com/immunant/virtio-drivers-and-devices"
+[features]
+alloc = ["zerocopy/alloc"]
+default = [
+ "alloc",
+ "embedded-io",
+]
+embedded-io = ["dep:embedded-io"]
+
[lib]
name = "virtio_drivers_and_devices"
path = "src/lib.rs"
@@ -64,11 +72,3 @@
[dev-dependencies.zerocopy]
version = "0.8.14"
features = ["alloc"]
-
-[features]
-alloc = ["zerocopy/alloc"]
-default = [
- "alloc",
- "embedded-io",
-]
-embedded-io = ["dep:embedded-io"]
diff --git a/crates/virtio-drivers-and-devices/METADATA b/crates/virtio-drivers-and-devices/METADATA
index c39081e..853bd6f 100644
--- a/crates/virtio-drivers-and-devices/METADATA
+++ b/crates/virtio-drivers-and-devices/METADATA
@@ -1,17 +1,17 @@
name: "virtio-drivers-and-devices"
description: "VirtIO guest drivers and devices. Fork of rcore-os/virtio-drivers."
third_party {
- version: "0.1.0"
+ version: "0.2.0"
license_type: NOTICE
last_upgrade_date {
year: 2025
- month: 2
- day: 28
+ month: 3
+ day: 19
}
homepage: "https://crates.io/crates/virtio-drivers-and-devices"
identifier {
type: "Archive"
- value: "https://static.crates.io/crates/virtio-drivers-and-devices/virtio-drivers-and-devices-0.1.0.crate"
- version: "0.1.0"
+ value: "https://static.crates.io/crates/virtio-drivers-and-devices/virtio-drivers-and-devices-0.2.0.crate"
+ version: "0.2.0"
}
}
diff --git a/crates/virtio-drivers-and-devices/src/device/blk.rs b/crates/virtio-drivers-and-devices/src/device/blk.rs
index dc4a6c5..143e9f1 100644
--- a/crates/virtio-drivers-and-devices/src/device/blk.rs
+++ b/crates/virtio-drivers-and-devices/src/device/blk.rs
@@ -26,9 +26,9 @@
/// # Example
///
/// ```
-/// # use virtio_drivers::{Error, Hal};
-/// # use virtio_drivers::transport::Transport;
-/// use virtio_drivers::device::blk::{VirtIOBlk, SECTOR_SIZE};
+/// # use virtio_drivers_and_devices::{Error, Hal};
+/// # use virtio_drivers_and_devices::transport::Transport;
+/// use virtio_drivers_and_devices::device::blk::{VirtIOBlk, SECTOR_SIZE};
///
/// # fn example<HalImpl: Hal, T: Transport>(transport: T) -> Result<(), Error> {
/// let mut disk = VirtIOBlk::<HalImpl, _>::new(transport)?;
@@ -212,10 +212,10 @@
/// the same buffers before reading the response.
///
/// ```
- /// # use virtio_drivers::{Error, Hal};
- /// # use virtio_drivers::device::blk::VirtIOBlk;
- /// # use virtio_drivers::transport::Transport;
- /// use virtio_drivers::device::blk::{BlkReq, BlkResp, RespStatus};
+ /// # use virtio_drivers_and_devices::{Error, Hal};
+ /// # use virtio_drivers_and_devices::device::blk::VirtIOBlk;
+ /// # use virtio_drivers_and_devices::transport::Transport;
+ /// use virtio_drivers_and_devices::device::blk::{BlkReq, BlkResp, RespStatus};
///
/// # fn example<H: Hal, T: Transport>(blk: &mut VirtIOBlk<H, T>) -> Result<(), Error> {
/// let mut request = BlkReq::default();
diff --git a/crates/virtio-drivers-and-devices/src/device/console.rs b/crates/virtio-drivers-and-devices/src/device/console.rs
index c8c49d1..f02ae55 100644
--- a/crates/virtio-drivers-and-devices/src/device/console.rs
+++ b/crates/virtio-drivers-and-devices/src/device/console.rs
@@ -29,8 +29,8 @@
/// # Example
///
/// ```
-/// # use virtio_drivers::{Error, Hal, transport::Transport};
-/// use virtio_drivers::device::console::VirtIOConsole;
+/// # use virtio_drivers_and_devices::{Error, Hal, transport::Transport};
+/// use virtio_drivers_and_devices::device::console::VirtIOConsole;
/// # fn example<HalImpl: Hal, T: Transport>(transport: T) -> Result<(), Error> {
/// let mut console = VirtIOConsole::<HalImpl, _>::new(transport)?;
///
diff --git a/crates/virtio-drivers-and-devices/src/device/gpu.rs b/crates/virtio-drivers-and-devices/src/device/gpu.rs
index 75a5fef..22af9a8 100644
--- a/crates/virtio-drivers-and-devices/src/device/gpu.rs
+++ b/crates/virtio-drivers-and-devices/src/device/gpu.rs
@@ -1,7 +1,7 @@
//! Driver for VirtIO GPU devices.
use crate::config::{read_config, ReadOnly, WriteOnly};
-use crate::hal::{BufferDirection, Dma, Hal};
+use crate::hal::{BufferDirection, Dma, DmaMemory, Hal};
use crate::queue::VirtQueue;
use crate::transport::Transport;
use crate::{pages, Error, Result, PAGE_SIZE};
diff --git a/crates/virtio-drivers-and-devices/src/device/socket/connectionmanager.rs b/crates/virtio-drivers-and-devices/src/device/socket/connectionmanager.rs
index 8e823eb..5df3ec6 100644
--- a/crates/virtio-drivers-and-devices/src/device/socket/connectionmanager.rs
+++ b/crates/virtio-drivers-and-devices/src/device/socket/connectionmanager.rs
@@ -1,8 +1,11 @@
use super::{
protocol::VsockAddr, vsock::ConnectionInfo, DisconnectReason, SocketError, VirtIOSocket,
- VsockEvent, VsockEventType, DEFAULT_RX_BUFFER_SIZE,
+ VirtIOSocketDevice, VirtIOSocketManager, VsockEvent, VsockEventType, DEFAULT_RX_BUFFER_SIZE,
};
-use crate::{transport::Transport, Hal, Result};
+use crate::{
+ transport::{DeviceTransport, Transport},
+ DeviceHal, Hal, Result,
+};
use alloc::{boxed::Box, vec::Vec};
use core::cmp::min;
use core::convert::TryInto;
@@ -12,7 +15,7 @@
const DEFAULT_PER_CONNECTION_BUFFER_CAPACITY: u32 = 1024;
-/// A higher level interface for VirtIO socket (vsock) devices.
+/// A higher level interface for VirtIO socket (vsock) drivers.
///
/// This keeps track of multiple vsock connections.
///
@@ -22,9 +25,9 @@
/// # Example
///
/// ```
-/// # use virtio_drivers::{Error, Hal};
-/// # use virtio_drivers::transport::Transport;
-/// use virtio_drivers::device::socket::{VirtIOSocket, VsockAddr, VsockConnectionManager};
+/// # use virtio_drivers_and_devices::{Error, Hal};
+/// # use virtio_drivers_and_devices::transport::Transport;
+/// use virtio_drivers_and_devices::device::socket::{VirtIOSocket, VsockAddr, VsockConnectionManager};
///
/// # fn example<HalImpl: Hal, T: Transport>(transport: T) -> Result<(), Error> {
/// let mut socket = VsockConnectionManager::new(VirtIOSocket::<HalImpl, _>::new(transport)?);
@@ -47,8 +50,55 @@
H: Hal,
T: Transport,
const RX_BUFFER_SIZE: usize = DEFAULT_RX_BUFFER_SIZE,
-> {
- driver: VirtIOSocket<H, T, RX_BUFFER_SIZE>,
+>(VsockConnectionManagerCommon<VirtIOSocket<H, T, RX_BUFFER_SIZE>>);
+
+/// A high level interface for VirtIO socket (vsock) devices.
+pub struct VsockDeviceConnectionManager<H: DeviceHal, T: DeviceTransport>(
+ VsockConnectionManagerCommon<VirtIOSocketDevice<H, T>>,
+);
+
+/// A trait defining shared behavior for VirtIO socket devices and drivers.
+///
+/// All methods are implemented for VsockConnectionManager and VsockDeviceConnectionManager though
+/// the device side must not call the connect method. These are equivalent to the inherent methods
+/// which are kept for backwards compatibility.
+pub trait VsockManager {
+ /// Sends a request to connect to the given destination on the driver side.
+ ///
+ /// This returns as soon as the request is sent; you should wait until `poll` returns a
+ /// `VsockEventType::Connected` event indicating that the peer has accepted the connection
+ /// before sending data. This panics if called from the device side.
+ fn connect(&mut self, destination: VsockAddr, src_port: u32) -> Result;
+
+ /// Sends the buffer to the destination.
+ fn send(&mut self, dest: VsockAddr, src_port: u32, buffer: &[u8]) -> Result;
+
+ /// Sends a credit update to the given peer.
+ fn update_credit(&mut self, peer: VsockAddr, src_port: u32) -> Result;
+
+ /// Forcibly closes the connection without waiting for the peer.
+ fn force_close(&mut self, dest: VsockAddr, src_port: u32) -> Result;
+
+ /// Allows incoming connections on the given port number.
+ fn listen(&mut self, port: u32);
+
+ /// Polls the vsock device to receive data or other updates.
+ fn poll(&mut self) -> Result<Option<VsockEvent>>;
+
+ /// Requests to shut down the connection cleanly, telling the peer that we won't send or receive
+ /// any more data.
+ ///
+ /// This returns as soon as the request is sent; you should wait until `poll` returns a
+ /// `VsockEventType::Disconnected` event if you want to know that the peer has acknowledged the
+ /// shutdown.
+ fn shutdown(&mut self, dest: VsockAddr, src_port: u32) -> Result;
+
+ /// Reads data received from the given connection.
+ fn recv(&mut self, peer: VsockAddr, src_port: u32, buffer: &mut [u8]) -> Result<usize>;
+}
+
+struct VsockConnectionManagerCommon<M: VirtIOSocketManager> {
+ driver: M,
per_connection_buffer_capacity: u32,
connections: Vec<Connection>,
listening_ports: Vec<u32>,
@@ -89,19 +139,234 @@
driver: VirtIOSocket<H, T, RX_BUFFER_SIZE>,
per_connection_buffer_capacity: u32,
) -> Self {
- Self {
+ Self(VsockConnectionManagerCommon {
driver,
connections: Vec::new(),
listening_ports: Vec::new(),
per_connection_buffer_capacity,
- }
+ })
}
/// Returns the CID which has been assigned to this guest.
pub fn guest_cid(&self) -> u64 {
- self.driver.guest_cid()
+ self.0.driver.guest_cid()
}
+ /// Sends a request to connect to the given destination.
+ ///
+ /// This returns as soon as the request is sent; you should wait until `poll` returns a
+ /// `VsockEventType::Connected` event indicating that the peer has accepted the connection
+ /// before sending data.
+ pub fn connect(&mut self, destination: VsockAddr, src_port: u32) -> Result {
+ if self.0.connections.iter().any(|connection| {
+ connection.info.dst == destination && connection.info.src_port == src_port
+ }) {
+ return Err(SocketError::ConnectionExists.into());
+ }
+
+ let new_connection =
+ Connection::new(destination, src_port, self.0.per_connection_buffer_capacity);
+
+ self.0.driver.connect(&new_connection.info)?;
+ debug!("Connection requested: {:?}", new_connection.info);
+ self.0.connections.push(new_connection);
+ Ok(())
+ }
+ /// Allows incoming connections on the given port number.
+ pub fn listen(&mut self, port: u32) {
+ self.0.listen(port)
+ }
+
+ /// Stops allowing incoming connections on the given port number.
+ pub fn unlisten(&mut self, port: u32) {
+ self.0.unlisten(port)
+ }
+
+ /// Sends the buffer to the destination.
+ pub fn send(&mut self, destination: VsockAddr, src_port: u32, buffer: &[u8]) -> Result {
+ self.0.send(destination, src_port, buffer)
+ }
+
+ /// Polls the vsock device to receive data or other updates.
+ pub fn poll(&mut self) -> Result<Option<VsockEvent>> {
+ self.0.poll()
+ }
+
+ /// Reads data received from the given connection.
+ pub fn recv(&mut self, peer: VsockAddr, src_port: u32, buffer: &mut [u8]) -> Result<usize> {
+ self.0.recv(peer, src_port, buffer)
+ }
+
+ /// Returns the number of bytes in the receive buffer available to be read by `recv`.
+ ///
+ /// When the available bytes is 0, it indicates that the receive buffer is empty and does not
+ /// contain any data.
+ pub fn recv_buffer_available_bytes(&mut self, peer: VsockAddr, src_port: u32) -> Result<usize> {
+ self.0.recv_buffer_available_bytes(peer, src_port)
+ }
+
+ /// Sends a credit update to the given peer.
+ pub fn update_credit(&mut self, peer: VsockAddr, src_port: u32) -> Result {
+ self.0.update_credit(peer, src_port)
+ }
+
+ /// Blocks until we get some event from the vsock device.
+ pub fn wait_for_event(&mut self) -> Result<VsockEvent> {
+ self.0.wait_for_event()
+ }
+
+ /// Requests to shut down the connection cleanly, telling the peer that we won't send or receive
+ /// any more data.
+ ///
+ /// This returns as soon as the request is sent; you should wait until `poll` returns a
+ /// `VsockEventType::Disconnected` event if you want to know that the peer has acknowledged the
+ /// shutdown.
+ pub fn shutdown(&mut self, destination: VsockAddr, src_port: u32) -> Result {
+ self.0.shutdown(destination, src_port)
+ }
+
+ /// Forcibly closes the connection without waiting for the peer.
+ pub fn force_close(&mut self, destination: VsockAddr, src_port: u32) -> Result {
+ self.0.force_close(destination, src_port)
+ }
+}
+
+impl<H: DeviceHal, T: DeviceTransport> VsockDeviceConnectionManager<H, T> {
+ /// Construct a new connection manager wrapping the given low-level VirtIO socket driver.
+ pub fn new(driver: VirtIOSocketDevice<H, T>) -> Self {
+ Self::new_with_capacity(driver, DEFAULT_PER_CONNECTION_BUFFER_CAPACITY)
+ }
+
+ /// Construct a new connection manager wrapping the given low-level VirtIO socket driver, with
+ /// the given per-connection buffer capacity.
+ pub fn new_with_capacity(
+ driver: VirtIOSocketDevice<H, T>,
+ per_connection_buffer_capacity: u32,
+ ) -> Self {
+ Self(VsockConnectionManagerCommon {
+ driver,
+ connections: Vec::new(),
+ listening_ports: Vec::new(),
+ per_connection_buffer_capacity,
+ })
+ }
+
+ /// Allows incoming connections on the given port number.
+ pub fn listen(&mut self, port: u32) {
+ self.0.listen(port)
+ }
+
+ /// Stops allowing incoming connections on the given port number.
+ pub fn unlisten(&mut self, port: u32) {
+ self.0.unlisten(port)
+ }
+
+ /// Sends the buffer to the destination.
+ pub fn send(&mut self, destination: VsockAddr, src_port: u32, buffer: &[u8]) -> Result {
+ self.0.send(destination, src_port, buffer)
+ }
+
+ /// Polls the vsock device to receive data or other updates.
+ pub fn poll(&mut self) -> Result<Option<VsockEvent>> {
+ self.0.poll()
+ }
+
+ /// Reads data received from the given connection.
+ pub fn recv(&mut self, peer: VsockAddr, src_port: u32, buffer: &mut [u8]) -> Result<usize> {
+ self.0.recv(peer, src_port, buffer)
+ }
+
+ /// Returns the number of bytes in the receive buffer available to be read by `recv`.
+ ///
+ /// When the available bytes is 0, it indicates that the receive buffer is empty and does not
+ /// contain any data.
+ pub fn recv_buffer_available_bytes(&mut self, peer: VsockAddr, src_port: u32) -> Result<usize> {
+ self.0.recv_buffer_available_bytes(peer, src_port)
+ }
+
+ /// Sends a credit update to the given peer.
+ pub fn update_credit(&mut self, peer: VsockAddr, src_port: u32) -> Result {
+ self.0.update_credit(peer, src_port)
+ }
+
+ /// Blocks until we get some event from the vsock device.
+ pub fn wait_for_event(&mut self) -> Result<VsockEvent> {
+ self.0.wait_for_event()
+ }
+
+ /// Requests to shut down the connection cleanly, telling the peer that we won't send or receive
+ /// any more data.
+ ///
+ /// This returns as soon as the request is sent; you should wait until `poll` returns a
+ /// `VsockEventType::Disconnected` event if you want to know that the peer has acknowledged the
+ /// shutdown.
+ pub fn shutdown(&mut self, destination: VsockAddr, src_port: u32) -> Result {
+ self.0.shutdown(destination, src_port)
+ }
+
+ /// Forcibly closes the connection without waiting for the peer.
+ pub fn force_close(&mut self, destination: VsockAddr, src_port: u32) -> Result {
+ self.0.force_close(destination, src_port)
+ }
+}
+
+impl<H: Hal, T: Transport, const RX_BUFFER_SIZE: usize> VsockManager
+ for VsockConnectionManager<H, T, RX_BUFFER_SIZE>
+{
+ fn connect(&mut self, destination: VsockAddr, src_port: u32) -> Result {
+ Self::connect(self, destination, src_port)
+ }
+ fn send(&mut self, dest: VsockAddr, src_port: u32, buffer: &[u8]) -> Result {
+ Self::send(self, dest, src_port, buffer)
+ }
+ fn update_credit(&mut self, peer: VsockAddr, src_port: u32) -> Result {
+ Self::update_credit(self, peer, src_port)
+ }
+ fn force_close(&mut self, dest: VsockAddr, src_port: u32) -> Result {
+ Self::force_close(self, dest, src_port)
+ }
+ fn listen(&mut self, port: u32) {
+ Self::listen(self, port)
+ }
+ fn poll(&mut self) -> Result<Option<VsockEvent>> {
+ Self::poll(self)
+ }
+ fn shutdown(&mut self, dest: VsockAddr, src_port: u32) -> Result {
+ Self::shutdown(self, dest, src_port)
+ }
+ fn recv(&mut self, peer: VsockAddr, src_port: u32, buffer: &mut [u8]) -> Result<usize> {
+ Self::recv(self, peer, src_port, buffer)
+ }
+}
+
+impl<H: DeviceHal, T: DeviceTransport> VsockManager for VsockDeviceConnectionManager<H, T> {
+ fn connect(&mut self, _destination: VsockAddr, _src_port: u32) -> Result {
+ unreachable!("vsock devices should not make outgoing connections")
+ }
+ fn send(&mut self, dest: VsockAddr, src_port: u32, buffer: &[u8]) -> Result {
+ Self::send(self, dest, src_port, buffer)
+ }
+ fn update_credit(&mut self, peer: VsockAddr, src_port: u32) -> Result {
+ Self::update_credit(self, peer, src_port)
+ }
+ fn force_close(&mut self, dest: VsockAddr, src_port: u32) -> Result {
+ Self::force_close(self, dest, src_port)
+ }
+ fn listen(&mut self, port: u32) {
+ Self::listen(self, port)
+ }
+ fn poll(&mut self) -> Result<Option<VsockEvent>> {
+ Self::poll(self)
+ }
+ fn shutdown(&mut self, dest: VsockAddr, src_port: u32) -> Result {
+ Self::shutdown(self, dest, src_port)
+ }
+ fn recv(&mut self, peer: VsockAddr, src_port: u32, buffer: &mut [u8]) -> Result<usize> {
+ Self::recv(self, peer, src_port, buffer)
+ }
+}
+
+impl<M: VirtIOSocketManager> VsockConnectionManagerCommon<M> {
/// Allows incoming connections on the given port number.
pub fn listen(&mut self, port: u32) {
if !self.listening_ports.contains(&port) {
@@ -114,27 +379,6 @@
self.listening_ports.retain(|p| *p != port);
}
- /// Sends a request to connect to the given destination.
- ///
- /// This returns as soon as the request is sent; you should wait until `poll` returns a
- /// `VsockEventType::Connected` event indicating that the peer has accepted the connection
- /// before sending data.
- pub fn connect(&mut self, destination: VsockAddr, src_port: u32) -> Result {
- if self.connections.iter().any(|connection| {
- connection.info.dst == destination && connection.info.src_port == src_port
- }) {
- return Err(SocketError::ConnectionExists.into());
- }
-
- let new_connection =
- Connection::new(destination, src_port, self.per_connection_buffer_capacity);
-
- self.driver.connect(&new_connection.info)?;
- debug!("Connection requested: {:?}", new_connection.info);
- self.connections.push(new_connection);
- Ok(())
- }
-
/// Sends the buffer to the destination.
pub fn send(&mut self, destination: VsockAddr, src_port: u32, buffer: &[u8]) -> Result {
let (_, connection) = get_connection(&mut self.connections, destination, src_port)?;
@@ -144,12 +388,12 @@
/// Polls the vsock device to receive data or other updates.
pub fn poll(&mut self) -> Result<Option<VsockEvent>> {
- let guest_cid = self.driver.guest_cid();
+ let local_cid = self.driver.local_cid();
let connections = &mut self.connections;
let per_connection_buffer_capacity = self.per_connection_buffer_capacity;
let result = self.driver.poll(|event, body| {
- let connection = get_connection_for_event(connections, &event, guest_cid);
+ let connection = get_connection_for_event(connections, &event, local_cid);
// Skip events which don't match any connection we know about, unless they are a
// connection request.
@@ -157,7 +401,7 @@
connection
} else if let VsockEventType::ConnectionRequest = event.event_type {
// If the requested connection already exists or the CID isn't ours, ignore it.
- if connection.is_some() || event.destination.cid != guest_cid {
+ if connection.is_some() || event.destination.cid != local_cid {
return Ok(None);
}
// Add the new connection to our list, at least for now. It will be removed again
@@ -191,7 +435,7 @@
// The connection must exist because we found it above in the callback.
let (connection_index, connection) =
- get_connection_for_event(connections, &event, guest_cid).unwrap();
+ get_connection_for_event(connections, &event, local_cid).unwrap();
match event.event_type {
VsockEventType::ConnectionRequest => {
diff --git a/crates/virtio-drivers-and-devices/src/device/socket/mod.rs b/crates/virtio-drivers-and-devices/src/device/socket/mod.rs
index 607f739..c152dd0 100644
--- a/crates/virtio-drivers-and-devices/src/device/socket/mod.rs
+++ b/crates/virtio-drivers-and-devices/src/device/socket/mod.rs
@@ -15,11 +15,16 @@
mod vsock;
#[cfg(feature = "alloc")]
-pub use connectionmanager::VsockConnectionManager;
+pub use connectionmanager::{VsockConnectionManager, VsockDeviceConnectionManager, VsockManager};
pub use error::SocketError;
pub use protocol::{StreamShutdown, VsockAddr, VMADDR_CID_HOST};
#[cfg(feature = "alloc")]
-pub use vsock::{ConnectionInfo, DisconnectReason, VirtIOSocket, VsockEvent, VsockEventType};
+pub use vsock::{
+ ConnectionInfo, DisconnectReason, VirtIOSocket, VirtIOSocketDevice, VsockEvent, VsockEventType,
+};
+
+#[cfg(feature = "alloc")]
+pub(crate) use vsock::VirtIOSocketManager;
/// The size in bytes of each buffer used in the RX virtqueue. This must be bigger than
/// `size_of::<VirtioVsockHdr>()`.
diff --git a/crates/virtio-drivers-and-devices/src/device/socket/vsock.rs b/crates/virtio-drivers-and-devices/src/device/socket/vsock.rs
index 8a95ee4..1d4ea48 100644
--- a/crates/virtio-drivers-and-devices/src/device/socket/vsock.rs
+++ b/crates/virtio-drivers-and-devices/src/device/socket/vsock.rs
@@ -4,12 +4,13 @@
use super::error::SocketError;
use super::protocol::{
Feature, StreamShutdown, VirtioVsockConfig, VirtioVsockHdr, VirtioVsockOp, VsockAddr,
+ VMADDR_CID_HOST,
};
use super::DEFAULT_RX_BUFFER_SIZE;
use crate::config::read_config;
-use crate::hal::Hal;
-use crate::queue::{owning::OwningQueue, VirtQueue};
-use crate::transport::Transport;
+use crate::hal::{DeviceHal, Hal};
+use crate::queue::{owning::OwningQueue, DeviceVirtQueue, VirtQueue};
+use crate::transport::{DeviceTransport, Transport};
use crate::Result;
use core::mem::size_of;
use log::debug;
@@ -313,34 +314,182 @@
/// Accepts the given connection from a peer.
pub fn accept(&mut self, connection_info: &ConnectionInfo) -> Result {
+ <Self as VirtIOSocketManager>::accept(self, connection_info)
+ }
+
+ /// Requests the peer to send us a credit update for the given connection.
+ pub fn request_credit(&mut self, connection_info: &ConnectionInfo) -> Result {
+ <Self as VirtIOSocketManager>::request_credit(self, connection_info)
+ }
+
+ /// Sends the buffer to the destination.
+ pub fn send(&mut self, buffer: &[u8], connection_info: &mut ConnectionInfo) -> Result {
+ <Self as VirtIOSocketManager>::send(self, buffer, connection_info)
+ }
+
+ /// Tells the peer how much buffer space we have to receive data.
+ pub fn credit_update(&mut self, connection_info: &ConnectionInfo) -> Result {
+ <Self as VirtIOSocketManager>::credit_update(self, connection_info)
+ }
+
+ /// Polls the RX virtqueue for the next event, and calls the given handler function to handle
+ /// it.
+ pub fn poll(
+ &mut self,
+ handler: impl FnOnce(VsockEvent, &[u8]) -> Result<Option<VsockEvent>>,
+ ) -> Result<Option<VsockEvent>> {
+ <Self as VirtIOSocketManager>::poll(self, handler)
+ }
+
+ /// Requests to shut down the connection cleanly, sending hints about whether we will send or
+ /// receive more data.
+ ///
+ /// This returns as soon as the request is sent; you should wait until `poll` returns a
+ /// `VsockEventType::Disconnected` event if you want to know that the peer has acknowledged the
+ /// shutdown.
+ pub fn shutdown_with_hints(
+ &mut self,
+ connection_info: &ConnectionInfo,
+ hints: StreamShutdown,
+ ) -> Result {
+ <Self as VirtIOSocketManager>::shutdown_with_hints(self, connection_info, hints)
+ }
+
+ /// Requests to shut down the connection cleanly, telling the peer that we won't send or receive
+ /// any more data.
+ ///
+ /// This returns as soon as the request is sent; you should wait until `poll` returns a
+ /// `VsockEventType::Disconnected` event if you want to know that the peer has acknowledged the
+ /// shutdown.
+ pub fn shutdown(&mut self, connection_info: &ConnectionInfo) -> Result {
+ <Self as VirtIOSocketManager>::shutdown(self, connection_info)
+ }
+
+ /// Forcibly closes the connection without waiting for the peer.
+ pub fn force_close(&mut self, connection_info: &ConnectionInfo) -> Result {
+ <Self as VirtIOSocketManager>::force_close(self, connection_info)
+ }
+
+ fn send_packet_to_tx_queue(&mut self, header: &VirtioVsockHdr, buffer: &[u8]) -> Result {
+ let _len = if buffer.is_empty() {
+ self.tx
+ .add_notify_wait_pop(&[header.as_bytes()], &mut [], &mut self.transport)?
+ } else {
+ self.tx.add_notify_wait_pop(
+ &[header.as_bytes(), buffer],
+ &mut [],
+ &mut self.transport,
+ )?
+ };
+ Ok(())
+ }
+}
+
+impl<H: Hal, T: Transport, const RX_BUFFER_SIZE: usize> VirtIOSocketManager
+ for VirtIOSocket<H, T, RX_BUFFER_SIZE>
+{
+ fn local_cid(&self) -> u64 {
+ self.guest_cid()
+ }
+ fn send_packet_to_queue(&mut self, header: &VirtioVsockHdr, buffer: &[u8]) -> Result {
+ self.send_packet_to_tx_queue(header, buffer)
+ }
+ fn poll(
+ &mut self,
+ handler: impl FnOnce(VsockEvent, &[u8]) -> Result<Option<VsockEvent>>,
+ ) -> Result<Option<VsockEvent>> {
+ self.rx.poll(&mut self.transport, |buffer| {
+ let (header, body) = read_header_and_body(buffer)?;
+ VsockEvent::from_header(&header).and_then(|event| handler(event, body))
+ })
+ }
+}
+
+/// A low-level interface for a vsock device implementation
+pub struct VirtIOSocketDevice<H: DeviceHal, T: DeviceTransport> {
+ transport: T,
+ rx: DeviceVirtQueue<H, { QUEUE_SIZE }>,
+ tx: DeviceVirtQueue<H, { QUEUE_SIZE }>,
+ event: DeviceVirtQueue<H, { QUEUE_SIZE }>,
+}
+
+impl<H: DeviceHal, T: DeviceTransport> VirtIOSocketDevice<H, T> {
+ /// Create a new VirtIO Vsock device.
+ pub fn new(mut transport: T) -> Result<Self> {
+ let rx = DeviceVirtQueue::new(&mut transport, RX_QUEUE_IDX)?;
+ let tx = DeviceVirtQueue::new(&mut transport, TX_QUEUE_IDX)?;
+ let event = DeviceVirtQueue::new(&mut transport, EVENT_QUEUE_IDX)?;
+ Ok(Self {
+ transport,
+ rx,
+ tx,
+ event,
+ })
+ }
+}
+
+impl<H: DeviceHal, T: DeviceTransport> VirtIOSocketManager for VirtIOSocketDevice<H, T> {
+ fn local_cid(&self) -> u64 {
+ VMADDR_CID_HOST
+ }
+ fn send_packet_to_queue(&mut self, header: &VirtioVsockHdr, buffer: &[u8]) -> Result {
+ if buffer.is_empty() {
+ self.rx
+ .wait_pop_add_notify(&[header.as_bytes()], &mut self.transport)?
+ } else {
+ self.rx
+ .wait_pop_add_notify(&[header.as_bytes(), buffer], &mut self.transport)?
+ }
+ Ok(())
+ }
+ fn poll(
+ &mut self,
+ handler: impl FnOnce(VsockEvent, &[u8]) -> Result<Option<VsockEvent>>,
+ ) -> Result<Option<VsockEvent>> {
+ self.tx.poll(&mut self.transport, |buffer| {
+ let (header, body) = read_header_and_body(buffer)?;
+ VsockEvent::from_header(&header).and_then(|event| handler(event, body))
+ })
+ }
+}
+pub trait VirtIOSocketManager {
+ fn local_cid(&self) -> u64;
+ fn send_packet_to_queue(&mut self, header: &VirtioVsockHdr, buffer: &[u8]) -> Result;
+ fn poll(
+ &mut self,
+ handler: impl FnOnce(VsockEvent, &[u8]) -> Result<Option<VsockEvent>>,
+ ) -> Result<Option<VsockEvent>>;
+
+ /// Accepts the given connection from a peer.
+ fn accept(&mut self, connection_info: &ConnectionInfo) -> Result {
let header = VirtioVsockHdr {
op: VirtioVsockOp::Response.into(),
- ..connection_info.new_header(self.guest_cid)
+ ..connection_info.new_header(self.local_cid())
};
- self.send_packet_to_tx_queue(&header, &[])
+ self.send_packet_to_queue(&header, &[])
}
/// Requests the peer to send us a credit update for the given connection.
fn request_credit(&mut self, connection_info: &ConnectionInfo) -> Result {
let header = VirtioVsockHdr {
op: VirtioVsockOp::CreditRequest.into(),
- ..connection_info.new_header(self.guest_cid)
+ ..connection_info.new_header(self.local_cid())
};
- self.send_packet_to_tx_queue(&header, &[])
+ self.send_packet_to_queue(&header, &[])
}
/// Sends the buffer to the destination.
- pub fn send(&mut self, buffer: &[u8], connection_info: &mut ConnectionInfo) -> Result {
+ fn send(&mut self, buffer: &[u8], connection_info: &mut ConnectionInfo) -> Result {
self.check_peer_buffer_is_sufficient(connection_info, buffer.len())?;
let len = buffer.len() as u32;
let header = VirtioVsockHdr {
op: VirtioVsockOp::Rw.into(),
len: len.into(),
- ..connection_info.new_header(self.guest_cid)
+ ..connection_info.new_header(self.local_cid())
};
connection_info.tx_cnt += len;
- self.send_packet_to_tx_queue(&header, buffer)
+ self.send_packet_to_queue(&header, buffer)
}
fn check_peer_buffer_is_sufficient(
@@ -362,24 +511,12 @@
}
/// Tells the peer how much buffer space we have to receive data.
- pub fn credit_update(&mut self, connection_info: &ConnectionInfo) -> Result {
+ fn credit_update(&mut self, connection_info: &ConnectionInfo) -> Result {
let header = VirtioVsockHdr {
op: VirtioVsockOp::CreditUpdate.into(),
- ..connection_info.new_header(self.guest_cid)
+ ..connection_info.new_header(self.local_cid())
};
- self.send_packet_to_tx_queue(&header, &[])
- }
-
- /// Polls the RX virtqueue for the next event, and calls the given handler function to handle
- /// it.
- pub fn poll(
- &mut self,
- handler: impl FnOnce(VsockEvent, &[u8]) -> Result<Option<VsockEvent>>,
- ) -> Result<Option<VsockEvent>> {
- self.rx.poll(&mut self.transport, |buffer| {
- let (header, body) = read_header_and_body(buffer)?;
- VsockEvent::from_header(&header).and_then(|event| handler(event, body))
- })
+ self.send_packet_to_queue(&header, &[])
}
/// Requests to shut down the connection cleanly, sending hints about whether we will send or
@@ -388,7 +525,7 @@
/// This returns as soon as the request is sent; you should wait until `poll` returns a
/// `VsockEventType::Disconnected` event if you want to know that the peer has acknowledged the
/// shutdown.
- pub fn shutdown_with_hints(
+ fn shutdown_with_hints(
&mut self,
connection_info: &ConnectionInfo,
hints: StreamShutdown,
@@ -396,9 +533,9 @@
let header = VirtioVsockHdr {
op: VirtioVsockOp::Shutdown.into(),
flags: hints.into(),
- ..connection_info.new_header(self.guest_cid)
+ ..connection_info.new_header(self.local_cid())
};
- self.send_packet_to_tx_queue(&header, &[])
+ self.send_packet_to_queue(&header, &[])
}
/// Requests to shut down the connection cleanly, telling the peer that we won't send or receive
@@ -407,7 +544,7 @@
/// This returns as soon as the request is sent; you should wait until `poll` returns a
/// `VsockEventType::Disconnected` event if you want to know that the peer has acknowledged the
/// shutdown.
- pub fn shutdown(&mut self, connection_info: &ConnectionInfo) -> Result {
+ fn shutdown(&mut self, connection_info: &ConnectionInfo) -> Result {
self.shutdown_with_hints(
connection_info,
StreamShutdown::SEND | StreamShutdown::RECEIVE,
@@ -415,26 +552,12 @@
}
/// Forcibly closes the connection without waiting for the peer.
- pub fn force_close(&mut self, connection_info: &ConnectionInfo) -> Result {
+ fn force_close(&mut self, connection_info: &ConnectionInfo) -> Result {
let header = VirtioVsockHdr {
op: VirtioVsockOp::Rst.into(),
- ..connection_info.new_header(self.guest_cid)
+ ..connection_info.new_header(self.local_cid())
};
- self.send_packet_to_tx_queue(&header, &[])?;
- Ok(())
- }
-
- fn send_packet_to_tx_queue(&mut self, header: &VirtioVsockHdr, buffer: &[u8]) -> Result {
- let _len = if buffer.is_empty() {
- self.tx
- .add_notify_wait_pop(&[header.as_bytes()], &mut [], &mut self.transport)?
- } else {
- self.tx.add_notify_wait_pop(
- &[header.as_bytes(), buffer],
- &mut [],
- &mut self.transport,
- )?
- };
+ self.send_packet_to_queue(&header, &[])?;
Ok(())
}
}
diff --git a/crates/virtio-drivers-and-devices/src/hal.rs b/crates/virtio-drivers-and-devices/src/hal.rs
index 64e12e7..2026c92 100644
--- a/crates/virtio-drivers-and-devices/src/hal.rs
+++ b/crates/virtio-drivers-and-devices/src/hal.rs
@@ -7,6 +7,12 @@
/// A physical address as used for virtio.
pub type PhysAddr = usize;
+pub trait DmaMemory {
+ fn paddr(&self) -> usize;
+ fn vaddr(&self, offset: usize) -> NonNull<u8>;
+ fn raw_slice(&self) -> NonNull<[u8]>;
+}
+
/// A region of contiguous physical memory used for DMA.
#[derive(Debug)]
pub struct Dma<H: Hal> {
@@ -40,20 +46,22 @@
_hal: PhantomData,
})
}
+}
+impl<H: Hal> DmaMemory for Dma<H> {
/// Returns the physical address of the start of the DMA region, as seen by devices.
- pub fn paddr(&self) -> usize {
+ fn paddr(&self) -> usize {
self.paddr
}
/// Returns a pointer to the given offset within the DMA region.
- pub fn vaddr(&self, offset: usize) -> NonNull<u8> {
+ fn vaddr(&self, offset: usize) -> NonNull<u8> {
assert!(offset < self.pages * PAGE_SIZE);
NonNull::new((self.vaddr.as_ptr() as usize + offset) as _).unwrap()
}
/// Returns a pointer to the entire DMA region as a slice.
- pub fn raw_slice(&self) -> NonNull<[u8]> {
+ fn raw_slice(&self) -> NonNull<[u8]> {
let raw_slice =
core::ptr::slice_from_raw_parts_mut(self.vaddr(0).as_ptr(), self.pages * PAGE_SIZE);
NonNull::new(raw_slice).unwrap()
@@ -69,6 +77,71 @@
}
}
+#[derive(Debug)]
+pub struct DeviceDma<H: DeviceHal> {
+ paddr: usize,
+ vaddr: NonNull<u8>,
+ pages: usize,
+ _hal: PhantomData<H>,
+ client_id: u16,
+}
+
+// SAFETY: Device DMA memory can be accessed from any thread.
+unsafe impl<H: DeviceHal> Send for DeviceDma<H> {}
+
+// SAFETY: `&DeviceDma` only allows pointers and physical addresses to be returned. Any accesses to
+// the memory requires unsafe code, which is responsible for avoiding data races.
+unsafe impl<H: DeviceHal> Sync for DeviceDma<H> {}
+
+impl<H: DeviceHal> DeviceDma<H> {
+ // SAFETY: The caller must ensure that the memory described by paddr and pages can be mapped by
+ // the type implementing DeviceHal such as a virtqueue or a buffer described by a descriptor.
+ pub unsafe fn new(
+ paddr: PhysAddr,
+ pages: usize,
+ direction: BufferDirection,
+ client_id: u16,
+ ) -> Result<Self> {
+ let vaddr = H::dma_map(paddr, pages, direction, client_id)?;
+ Ok(Self {
+ paddr,
+ vaddr,
+ pages,
+ _hal: PhantomData,
+ client_id,
+ })
+ }
+}
+
+impl<H: DeviceHal> DmaMemory for DeviceDma<H> {
+ /// Returns the physical address of the start of the DMA region, as seen by devices.
+ fn paddr(&self) -> usize {
+ self.paddr
+ }
+
+ /// Returns a pointer to the given offset within the DMA region.
+ fn vaddr(&self, offset: usize) -> NonNull<u8> {
+ assert!(offset < self.pages * PAGE_SIZE);
+ NonNull::new((self.vaddr.as_ptr() as usize + offset) as _).unwrap()
+ }
+
+ /// Returns a pointer to the entire DMA region as a slice.
+ fn raw_slice(&self) -> NonNull<[u8]> {
+ let raw_slice =
+ core::ptr::slice_from_raw_parts_mut(self.vaddr(0).as_ptr(), self.pages * PAGE_SIZE);
+ NonNull::new(raw_slice).unwrap()
+ }
+}
+
+impl<H: DeviceHal> Drop for DeviceDma<H> {
+ fn drop(&mut self) {
+ // SAFETY: DeviceDma::new ensures that paddr, vaddr and pages were passed to
+ // DeviceHal::dma_map for this instance of DeviceDma
+ let err = unsafe { H::dma_unmap(self.paddr, self.vaddr, self.pages) };
+ assert_eq!(err, 0, "failed to unmap DMA");
+ }
+}
+
/// The interface which a particular hardware implementation must implement.
///
/// # Safety
@@ -140,6 +213,39 @@
unsafe fn unshare(paddr: PhysAddr, buffer: NonNull<[u8]>, direction: BufferDirection);
}
+/// Device-side abstraction layer for mapping and unmapping memory shared by the driver.
+///
+/// # Safety
+///
+/// Implementations of this trait must follow the "implementation safety" requirements documented
+/// for each method. Callers must follow the safety requirements documented for the unsafe methods.
+pub trait DeviceHal {
+ /// Maps in memory for a range of physical addresses shared by a VirtIO driver.
+ ///
+ /// Returns the virtual address which the device should use to access it.
+ /// # Implementation safety
+ ///
+ /// Implementations of this method must ensure that the `NonNull<u8>` returned is a
+ /// [_valid_](https://doc.rust-lang.org/std/ptr/index.html#safety) pointer, aligned to
+ /// [`PAGE_SIZE`], and won't alias any other allocations or references in the program until it
+ /// is freed by `dma_unmap`.
+ unsafe fn dma_map(
+ paddr: PhysAddr,
+ pages: usize,
+ direction: BufferDirection,
+ client_id: u16,
+ ) -> Result<NonNull<u8>>;
+
+ /// Unmaps memory previously shared by the driver.
+ ///
+ /// # Safety
+ ///
+ /// The memory must have been mapped in by `dma_map` on the same `DeviceHal` implementation, and
+ /// not yet unmapped. `pages` must be the same number passed to `dma_map` originally, and
+ /// both `paddr` and `vaddr` must be the values returned by `dma_map`.
+ unsafe fn dma_unmap(paddr: PhysAddr, vaddr: NonNull<u8>, pages: usize) -> i32;
+}
+
/// The direction in which a buffer is passed.
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum BufferDirection {
diff --git a/crates/virtio-drivers-and-devices/src/lib.rs b/crates/virtio-drivers-and-devices/src/lib.rs
index a1ff972..981dad0 100644
--- a/crates/virtio-drivers-and-devices/src/lib.rs
+++ b/crates/virtio-drivers-and-devices/src/lib.rs
@@ -12,7 +12,7 @@
//!
//! ```
//! use core::ptr::NonNull;
-//! use virtio_drivers::transport::mmio::{MmioTransport, VirtIOHeader};
+//! use virtio_drivers_and_devices::transport::mmio::{MmioTransport, VirtIOHeader};
//!
//! # fn example(mmio_device_address: usize, mmio_size: usize) {
//! let header = NonNull::new(mmio_device_address as *mut VirtIOHeader).unwrap();
@@ -23,9 +23,9 @@
//! You can then check what kind of VirtIO device it is and construct the appropriate driver:
//!
//! ```
-//! # use virtio_drivers::Hal;
+//! # use virtio_drivers_and_devices::Hal;
//! # #[cfg(feature = "alloc")]
-//! use virtio_drivers::{
+//! use virtio_drivers_and_devices::{
//! device::console::VirtIOConsole,
//! transport::{mmio::MmioTransport, DeviceType, Transport},
//! };
@@ -62,7 +62,7 @@
use device::socket::SocketError;
use thiserror::Error;
-pub use self::hal::{BufferDirection, Hal, PhysAddr};
+pub use self::hal::{BufferDirection, DeviceHal, Hal, PhysAddr};
/// The page size in bytes supported by the library (4 KiB).
pub const PAGE_SIZE: usize = 0x1000;
diff --git a/crates/virtio-drivers-and-devices/src/queue.rs b/crates/virtio-drivers-and-devices/src/queue.rs
index e363f0d..c3c03fa 100644
--- a/crates/virtio-drivers-and-devices/src/queue.rs
+++ b/crates/virtio-drivers-and-devices/src/queue.rs
@@ -3,11 +3,13 @@
#[cfg(feature = "alloc")]
pub mod owning;
-use crate::hal::{BufferDirection, Dma, Hal, PhysAddr};
-use crate::transport::Transport;
+use crate::hal::{BufferDirection, DeviceDma, DeviceHal, Dma, DmaMemory, Hal, PhysAddr};
+use crate::transport::{DeviceTransport, Transport};
use crate::{align_up, nonnull_slice_from_raw_parts, pages, Error, Result, PAGE_SIZE};
#[cfg(feature = "alloc")]
use alloc::boxed::Box;
+#[cfg(feature = "alloc")]
+use alloc::vec::Vec;
use bitflags::bitflags;
#[cfg(test)]
use core::cmp::min;
@@ -29,7 +31,7 @@
#[derive(Debug)]
pub struct VirtQueue<H: Hal, const SIZE: usize> {
/// DMA guard
- layout: VirtQueueLayout<H>,
+ layout: VirtQueueLayout<Dma<H>>,
/// Descriptor table
///
/// The device may be able to modify this, even though it's not supposed to, so we shouldn't
@@ -550,28 +552,290 @@
// data race.
unsafe impl<H: Hal, const SIZE: usize> Sync for VirtQueue<H, SIZE> {}
+#[derive(Debug)]
+pub struct MappedDescriptor<H: DeviceHal> {
+ desc_copy: Descriptor,
+ dma: DeviceDma<H>,
+}
+
+impl<H: DeviceHal> MappedDescriptor<H> {
+ // SAFETY: The caller must ensure that the entire chain of buffers described by desc_copy came
+ // from a device virtqueue descriptor.
+ unsafe fn map_buf(desc_copy: Descriptor, client_id: u16) -> Result<Self> {
+ let direction = if desc_copy.flags.contains(DescFlags::WRITE) {
+ BufferDirection::DeviceToDriver
+ } else {
+ BufferDirection::DriverToDevice
+ };
+ // SAFETY: The safety requirements on this function ensure that the memory region can be
+ // mapped in as DMA memory.
+ let dma = unsafe {
+ DeviceDma::new(
+ desc_copy.addr as PhysAddr,
+ pages(desc_copy.len as usize),
+ direction,
+ client_id,
+ )?
+ };
+ Ok(Self { desc_copy, dma })
+ }
+}
+
+#[derive(Debug)]
+pub struct DeviceVirtQueue<H: DeviceHal, const SIZE: usize> {
+ /// DMA guard
+ layout: VirtQueueLayout<DeviceDma<H>>,
+
+ desc: NonNull<[Descriptor]>,
+ avail: NonNull<AvailRing<SIZE>>,
+ used: NonNull<UsedRing<SIZE>>,
+
+ queue_idx: u16,
+
+ /// Our trusted copy of `avail.idx`.
+ avail_idx: u16,
+ last_used_idx: u16,
+ desc_mapped: [Option<MappedDescriptor<H>>; SIZE],
+ client_id: u16,
+}
+
+impl<H: DeviceHal, const SIZE: usize> DeviceVirtQueue<H, SIZE> {
+ const SIZE_OK: () = assert!(SIZE.is_power_of_two() && SIZE <= u16::MAX as usize);
+
+ pub fn new<T: DeviceTransport>(transport: &mut T, idx: u16) -> Result<Self> {
+ #[allow(clippy::let_unit_value)]
+ let _ = Self::SIZE_OK;
+
+ if transport.max_queue_size(idx) < SIZE as u32 {
+ return Err(Error::InvalidParam);
+ }
+ let client_id = transport.get_client_id();
+
+ let size = SIZE as u16;
+
+ let [paddr, _, used_paddr] = transport.queue_get(idx);
+
+ let layout = if transport.requires_legacy_layout() {
+ // SAFETY: paddr was the physical address returned by the DeviceTransport implementor
+ // for the start of the virtqueue (i.e. descriptor table)
+ unsafe { VirtQueueLayout::map_legacy(size, paddr, client_id)? }
+ } else {
+ // SAFETY: paddr was the physical address returned by the DeviceTransport implementor
+ // for the start of the virtqueue. used_paddr was the physical address returned for the
+ // used vring.
+ unsafe { VirtQueueLayout::map_flexible(size, paddr, used_paddr, client_id)? }
+ };
+ let desc =
+ nonnull_slice_from_raw_parts(layout.descriptors_vaddr().cast::<Descriptor>(), SIZE);
+ let avail = layout.avail_vaddr().cast();
+ let used = layout.used_vaddr().cast();
+ let desc_mapped = [const { None }; SIZE];
+ Ok(DeviceVirtQueue {
+ layout,
+ desc,
+ avail,
+ used,
+ queue_idx: idx,
+ avail_idx: 0,
+ last_used_idx: 0,
+ desc_mapped,
+ client_id,
+ })
+ }
+
+ pub fn wait_pop_add_notify(
+ &mut self,
+ inputs: &[&[u8]],
+ transport: &mut impl DeviceTransport,
+ ) -> Result<()> {
+ #[cfg(feature = "alloc")]
+ {
+ while !self.can_pop() {
+ spin_loop();
+ }
+ // SAFETY: inputs is copied into the first buffer then the they are returned to the used
+ // vring and not accessed again.
+ let (mut buffers, token) = unsafe { self.pop_avail()?.unwrap() };
+
+ let out_buf = &mut buffers[0];
+ let mut copied = 0;
+ for in_buf in inputs {
+ out_buf[copied..copied + in_buf.len()].copy_from_slice(in_buf);
+ copied += in_buf.len();
+ }
+
+ let head_len = copied;
+ self.add_used(token, head_len);
+
+ if self.should_notify() {
+ transport.notify(self.queue_idx);
+ }
+ Ok(())
+ }
+ #[cfg(not(feature = "alloc"))]
+ unreachable!("device virtqueue send loop requires alloc feature")
+ }
+
+ pub fn poll<T>(
+ &mut self,
+ transport: &mut impl DeviceTransport,
+ handler: impl FnOnce(&[u8]) -> Result<Option<T>>,
+ ) -> Result<Option<T>> {
+ #[cfg(feature = "alloc")]
+ {
+ // SAFETY: The buffers are copied to a single, temporary buffer. Then handler is called on
+ // that and the original buffers are returned to the used vring and not accessed again.
+ let Some((buffers, token)) = (unsafe { self.pop_avail()? }) else {
+ return Ok(None);
+ };
+
+ let mut tmp = Vec::new();
+ for in_buf in &buffers {
+ tmp.extend_from_slice(in_buf);
+ }
+ let result = handler(tmp.as_slice());
+
+ let head_len = buffers[0].len();
+ self.add_used(token, head_len);
+
+ if self.should_notify() {
+ transport.notify(self.queue_idx);
+ }
+ result
+ }
+ #[cfg(not(feature = "alloc"))]
+ unreachable!("device virtqueue polling requires alloc feature")
+ }
+
+ fn add_used(&mut self, head: u16, head_len: usize) {
+ let last_used_slot = self.last_used_idx & (SIZE as u16 - 1);
+ // SAFETY: self.used is properly aligned, dereferenceable and initialised instance of
+ // UsedRing
+ unsafe {
+ (*self.used.as_ptr()).ring[usize::from(last_used_slot)].id = u32::from(head);
+ (*self.used.as_ptr()).ring[usize::from(last_used_slot)].len = head_len as u32;
+ }
+
+ fence(Ordering::SeqCst);
+
+ self.last_used_idx = self.last_used_idx.wrapping_add(1);
+ // SAFETY: self.used is properly aligned, dereferenceable and initialised instance of
+ // UsedRing
+ unsafe {
+ (*self.used.as_ptr())
+ .idx
+ .store(self.last_used_idx, Ordering::Release);
+ }
+ }
+
+ fn read_desc(&mut self, index: u16) -> Result<Descriptor> {
+ let index = usize::from(index);
+ // SAFETY: self.desc is a properly aligned, dereferencable and initialised instance of
+ // Descriptor
+ let desc = unsafe { (*self.desc.as_ptr()).get(index) };
+ desc.ok_or(Error::WrongToken).cloned()
+ }
+
+ /// Pop a chain of buffers from the avail vring and return the index of the first buffer.
+ ///
+ /// # Safety
+ ///
+ /// The caller must ensure that the returned buffers are not accessed after the first buffer's
+ /// token has been written to the used vring and the `last_used` index has been updated.
+ #[cfg(feature = "alloc")]
+ unsafe fn pop_avail<'a>(&mut self) -> Result<Option<(Vec<&'a mut [u8]>, u16)>> {
+ let Some(head) = self.peek_avail() else {
+ return Ok(None);
+ };
+ let mut res = Vec::new();
+ let mut next_token = Some(head);
+ while let Some(token) = next_token {
+ let desc = self.read_desc(token)?;
+ assert!(!desc.flags.contains(DescFlags::INDIRECT));
+ next_token = if desc.flags.contains(DescFlags::NEXT) {
+ Some(desc.next)
+ } else {
+ None
+ };
+ let mapped_desc = self
+ .desc_mapped
+ .get_mut(usize::from(token))
+ .ok_or(Error::WrongToken)?;
+ let desc_changed = if let Some(prev_mapped_desc) = mapped_desc {
+ prev_mapped_desc.desc_copy != desc
+ } else {
+ true
+ };
+ if desc_changed {
+ // SAFETY: desc was read from the virtqueue descriptor table and is currently not in
+ // use since it was either obtained by getting the next available index from
+ // peek_avail and using that to index into the descriptor table or through a chain
+ // of buffers starting from the buffer obtained via peek_avail.
+ // Drop impl unmaps the old descriptor's buffer to avoid leaking that memory
+ *mapped_desc = Some(unsafe { MappedDescriptor::map_buf(desc, self.client_id)? });
+ }
+ let mut buffer = mapped_desc.as_ref().unwrap().dma.raw_slice();
+ // SAFETY: Safety delegated to safety requirements on this function.
+ let buffer = unsafe { buffer.as_mut() };
+ res.push(buffer);
+ }
+ self.avail_idx = self.avail_idx.wrapping_add(1);
+ Ok(Some((res, head)))
+ }
+
+ fn can_pop(&self) -> bool {
+ // SAFETY: self.avail points to a valid, aligned, initialised, dereferenceable, readable
+ // instance of AvailRing.
+ self.avail_idx != unsafe { (*self.avail.as_ptr()).idx.load(Ordering::Acquire) }
+ }
+
+ fn peek_avail(&self) -> Option<u16> {
+ if self.can_pop() {
+ let avail_slot = self.avail_idx & (SIZE as u16 - 1);
+ // SAFETY: self.avail points to a valid, aligned, initialised, dereferenceable,
+ // readable instance of AvailRing.
+ Some(unsafe { (*self.avail.as_ptr()).ring[avail_slot as usize] })
+ } else {
+ None
+ }
+ }
+
+ fn should_notify(&self) -> bool {
+ // SAFETY: self.avail points to a valid, aligned, initialised, dereferenceable, readable
+ // instance of AvailRing.
+ unsafe { (*self.avail.as_ptr()).flags.load(Ordering::Acquire) & 0x0001 == 0 }
+ }
+}
+
+// SAFETY: None of the virt queue resources are tied to a particular thread.
+unsafe impl<H: DeviceHal, const SIZE: usize> Send for DeviceVirtQueue<H, SIZE> {}
+
+// SAFETY: A `&DeviceVirtQueue` only allows reading from the various pointers it contains, so there is no
+// data race.
+unsafe impl<H: DeviceHal, const SIZE: usize> Sync for DeviceVirtQueue<H, SIZE> {}
+
/// The inner layout of a VirtQueue.
///
/// Ref: 2.6 Split Virtqueues
#[derive(Debug)]
-enum VirtQueueLayout<H: Hal> {
+enum VirtQueueLayout<D: DmaMemory> {
Legacy {
- dma: Dma<H>,
+ dma: D,
avail_offset: usize,
used_offset: usize,
},
Modern {
/// The region used for the descriptor area and driver area.
- driver_to_device_dma: Dma<H>,
+ driver_to_device_dma: D,
/// The region used for the device area.
- device_to_driver_dma: Dma<H>,
+ device_to_driver_dma: D,
/// The offset from the start of the `driver_to_device_dma` region to the driver area
/// (available ring).
avail_offset: usize,
},
}
-impl<H: Hal> VirtQueueLayout<H> {
+impl<H: Hal> VirtQueueLayout<Dma<H>> {
/// Allocates a single DMA region containing all parts of the virtqueue, following the layout
/// required by legacy interfaces.
///
@@ -603,7 +867,65 @@
avail_offset: desc,
})
}
+}
+impl<H: DeviceHal> VirtQueueLayout<DeviceDma<H>> {
+ // SAFETY: paddr must be memory shared by a virtio driver for a split virtqueue with the legacy
+ // layout and queue_size entries.
+ unsafe fn map_legacy(queue_size: u16, paddr: PhysAddr, client_id: u16) -> Result<Self> {
+ let (desc, avail, used) = queue_part_sizes(queue_size);
+ let size = align_up(desc + avail) + align_up(used);
+ // SAFETY: The safety requirements on this function ensure that this memory region can be
+ // mapped in as DMA memory.
+ let dma =
+ unsafe { DeviceDma::new(paddr, size / PAGE_SIZE, BufferDirection::Both, client_id)? };
+ Ok(Self::Legacy {
+ dma,
+ avail_offset: desc,
+ used_offset: align_up(desc + avail),
+ })
+ }
+
+ // SAFETY: desc_avail_paddr and used_paddr must be memory shared by a virtio driver for a split
+ // virtqueue where the device writeable and driver writeable portions are described by separate
+ // memory regions. Specifically desc_avail_paddr must point to the descriptor table and
+ // available vring and used_paddr must point to the used vring.
+ unsafe fn map_flexible(
+ queue_size: u16,
+ desc_avail_paddr: PhysAddr,
+ used_paddr: PhysAddr,
+ client_id: u16,
+ ) -> Result<Self> {
+ let (desc, avail, used) = queue_part_sizes(queue_size);
+ // SAFETY: The safety requirements on this function ensure that this memory region can be
+ // mapped in as DMA memory.
+ let driver_to_device_dma = unsafe {
+ DeviceDma::new(
+ desc_avail_paddr,
+ pages(desc + avail),
+ BufferDirection::DriverToDevice,
+ client_id,
+ )?
+ };
+ // SAFETY: The safety requirements on this function ensure that this memory region can be
+ // mapped in as DMA memory.
+ let device_to_driver_dma = unsafe {
+ DeviceDma::new(
+ used_paddr,
+ pages(used),
+ BufferDirection::DeviceToDriver,
+ client_id,
+ )?
+ };
+ Ok(Self::Modern {
+ driver_to_device_dma,
+ device_to_driver_dma,
+ avail_offset: desc,
+ })
+ }
+}
+
+impl<D: DmaMemory> VirtQueueLayout<D> {
/// Returns the physical address of the descriptor area.
fn descriptors_paddr(&self) -> PhysAddr {
match self {
@@ -698,7 +1020,7 @@
}
#[repr(C, align(16))]
-#[derive(Clone, Debug, FromBytes, Immutable, IntoBytes, KnownLayout)]
+#[derive(Clone, Debug, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
pub(crate) struct Descriptor {
addr: u64,
len: u32,
diff --git a/crates/virtio-drivers-and-devices/src/transport/mod.rs b/crates/virtio-drivers-and-devices/src/transport/mod.rs
index aed2267..6f339d4 100644
--- a/crates/virtio-drivers-and-devices/src/transport/mod.rs
+++ b/crates/virtio-drivers-and-devices/src/transport/mod.rs
@@ -15,6 +15,26 @@
pub use some::SomeTransport;
use zerocopy::{FromBytes, Immutable, IntoBytes};
+/// A VirtIO device-side transport layer.
+pub trait DeviceTransport {
+ /// Gets the client VM ID
+ fn get_client_id(&self) -> u16;
+
+ /// Gets the max size of the given queue.
+ fn max_queue_size(&mut self, queue: u16) -> u32;
+
+ /// Returns whether the transport requires queues to use the legacy layout.
+ ///
+ /// Ref: 2.6.2 Legacy Interfaces: A Note on Virtqueue Layout
+ fn requires_legacy_layout(&self) -> bool;
+
+ /// Gets the physical addresses for descriptors, driver area and device area for a given queue.
+ fn queue_get(&mut self, queue: u16) -> [PhysAddr; 3];
+
+ /// Notifies the given queue on the device.
+ fn notify(&mut self, queue: u16);
+}
+
/// A VirtIO transport layer.
pub trait Transport {
/// Gets the device type.
diff --git a/crates/virtio-drivers-and-devices/src/volatile.rs b/crates/virtio-drivers-and-devices/src/volatile.rs
index 16110cb..3aa6266 100644
--- a/crates/virtio-drivers-and-devices/src/volatile.rs
+++ b/crates/virtio-drivers-and-devices/src/volatile.rs
@@ -68,7 +68,7 @@
/// # Usage
/// ```compile_fail
/// # use core::ptr::NonNull;
-/// # use virtio_drivers::volatile::{ReadOnly, volread};
+/// # use virtio_drivers_and_devices::volatile::{ReadOnly, volread};
/// struct MmioDevice {
/// field: ReadOnly<u32>,
/// }
@@ -87,7 +87,7 @@
/// # Usage
/// ```compile_fail
/// # use core::ptr::NonNull;
-/// # use virtio_drivers::volatile::{WriteOnly, volread};
+/// # use virtio_drivers_and_devices::volatile::{WriteOnly, volread};
/// struct MmioDevice {
/// field: WriteOnly<u32>,
/// }
diff --git a/pseudo_crate/Cargo.lock b/pseudo_crate/Cargo.lock
index 52a2d57..b5f50da 100644
--- a/pseudo_crate/Cargo.lock
+++ b/pseudo_crate/Cargo.lock
@@ -6945,9 +6945,9 @@
[[package]]
name = "virtio-drivers-and-devices"
-version = "0.1.0"
+version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "087f2286ad55b6c36ec93267bcd1cbb740d7f9784879a001f76eea329d488273"
+checksum = "603664485269cf027cbbf54a2987426e6333d8fda4d0da65def6de0bc8868f51"
dependencies = [
"bitflags 2.9.0",
"embedded-io",
diff --git a/pseudo_crate/Cargo.toml b/pseudo_crate/Cargo.toml
index 0caca8e..4f89115 100644
--- a/pseudo_crate/Cargo.toml
+++ b/pseudo_crate/Cargo.toml
@@ -418,7 +418,7 @@
vhost-user-backend = "=0.17.0"
virtio-bindings = "=0.2.4"
virtio-drivers = "=0.9.0"
-virtio-drivers-and-devices = "=0.1.0"
+virtio-drivers-and-devices = "=0.2.0"
virtio-queue = "=0.14.0"
virtio-vsock = "=0.8.0"
vm-memory = "=0.16.1"