diff --git a/Cargo.lock b/Cargo.lock index c3558ee39..f368dd39c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -20,10 +20,45 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234" [[package]] -name = "ahash" -version = "0.8.9" +name = "aead" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d713b3834d76b85304d4d525563c1276e2e30dc97cc67bfb4585a4a29fc2c89f" +checksum = "0b613b8e1e3cf911a086f53f03bf286f52fd7a7258e4fa606f0ef220d39d8877" +dependencies = [ + "generic-array", +] + +[[package]] +name = "aes" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e8b47f52ea9bae42228d07ec09eb676433d7c4ed1ebdf0f1d1c29ed446f1ab8" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", + "opaque-debug", +] + +[[package]] +name = "aes-gcm" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df5f85a83a7d8b0442b6aa7b504b8212c1733da07b98aae43d4bc21b2cb3cdf6" +dependencies = [ + "aead", + "aes", + "cipher", + "ctr", + "ghash", + "subtle", +] + +[[package]] +name = "ahash" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" dependencies = [ "cfg-if", "once_cell", @@ -37,9 +72,9 @@ version = "0.1.0" [[package]] name = "allocator-api2" -version = "0.2.16" +version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" [[package]] name = "aml" @@ -74,7 +109,7 @@ dependencies = [ "jhash", "ostd", "smoltcp", - "spin 0.9.8", + "spin", "static_assertions", "takeable", ] @@ -91,7 +126,7 @@ dependencies = [ "int-to-c-enum", "log", "ostd", - "spin 0.9.8", + "spin", "static_assertions", ] @@ -104,7 +139,7 @@ dependencies = [ "component", "log", "ostd", - "spin 0.9.8", + "spin", ] [[package]] @@ -116,7 +151,7 @@ dependencies = [ "font8x8", "log", "ostd", - "spin 0.9.8", + "spin", ] [[package]] @@ -131,7 +166,7 @@ dependencies = [ "int-to-c-enum", "log", "ostd", - "spin 0.9.8", + "spin", ] [[package]] @@ -145,7 +180,27 @@ dependencies = [ "log", "ostd", "owo-colors 3.5.0", - "spin 0.9.8", + "spin", +] + +[[package]] +name = "aster-mlsdisk" +version = "0.1.0" +dependencies = [ + "aes-gcm", + "aster-block", + "bittle", + "ctr", + "hashbrown 0.14.5", + "inherit-methods-macro", + "lending-iterator", + "log", + "lru", + "ostd", + "ostd-pod", + "postcard", + "serde", + "static_assertions", ] [[package]] @@ -162,7 +217,7 @@ dependencies = [ "int-to-c-enum", "log", "ostd", - "spin 0.9.8", + "spin", ] [[package]] @@ -177,6 +232,7 @@ dependencies = [ "aster-framebuffer", "aster-input", "aster-logger", + "aster-mlsdisk", "aster-network", "aster-rights", "aster-rights-proc", @@ -194,7 +250,7 @@ dependencies = [ "cpio-decoder", "fixed", "getset", - "hashbrown", + "hashbrown 0.14.5", "id-alloc", "inherit-methods-macro", "int-to-c-enum", @@ -208,7 +264,7 @@ dependencies = [ "paste", "rand", "riscv", - "spin 0.9.8", + "spin", "static_assertions", "takeable", "tdx-guest", @@ -246,7 +302,7 @@ dependencies = [ "component", "intrusive-collections", "ostd", - "spin 0.9.8", + "spin", ] [[package]] @@ -259,7 +315,7 @@ dependencies = [ "component", "log", "ostd", - "spin 0.9.8", + "spin", ] [[package]] @@ -293,7 +349,7 @@ dependencies = [ "int-to-c-enum", "log", "ostd", - "spin 0.9.8", + "spin", "typeflags-util", ] @@ -303,14 +359,23 @@ version = "0.1.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.91", +] + +[[package]] +name = "atomic-polyfill" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8cf2bce30dfe09ef0bfaef228b9d414faaf7e563035494d7fe092dba54b300f4" +dependencies = [ + "critical-section", ] [[package]] name = "autocfg" -version = "1.1.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "az" @@ -336,6 +401,12 @@ version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +[[package]] +name = "bittle" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4650bc513f4078b7ad8dfbbca0455a1ee6cc1325dc21b5995340a7ab3d80ac5b" + [[package]] name = "bitvec" version = "1.0.1" @@ -356,35 +427,35 @@ checksum = "a7913f22349ffcfc6ca0ca9a656ec26cfbba538ed49c31a273dff2c5d1ea83d9" [[package]] name = "bytemuck" -version = "1.17.0" +version = "1.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fd4c6dcc3b0aea2f5c0b4b82c2b15fe39ddbc76041a310848f4706edf76bb31" +checksum = "ef657dfab802224e671f5818e9a4935f9b1957ed18e58292690cc39e7a4092a3" dependencies = [ "bytemuck_derive", ] [[package]] name = "bytemuck_derive" -version = "1.7.1" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cc8b54b395f2fcfbb3d90c47b01c7f444d94d05bdeb775811dec868ac3bbc26" +checksum = "3fa76293b4f7bb636ab88fd78228235b5248b4d05cc589aed610f954af5d7c7a" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.91", ] [[package]] name = "byteorder" -version = "1.4.3" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.4.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" +checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b" [[package]] name = "cfg-if" @@ -394,13 +465,28 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" -version = "0.4.38" +version = "0.4.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" +checksum = "7e36cc9d416881d2e24f9a963be5fb1cd90966419ac844274161d10488b3e825" dependencies = [ "num-traits", ] +[[package]] +name = "cipher" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ee52072ec15386f770805afd189a01c8841be8696bed250fa2f13c4c0d6dfb7" +dependencies = [ + "generic-array", +] + +[[package]] +name = "cobs" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67ba02a97a2bd10f4b59b25c7973101c79642302776489e030cd13cdab09ed15" + [[package]] name = "component" version = "0.1.0" @@ -457,19 +543,28 @@ dependencies = [ ] [[package]] -name = "crc32fast" -version = "1.3.2" +name = "cpufeatures" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +checksum = "16b80225097f2e5ae4e7179dd2266824648f3e2f49d9134d584b76389d31c4c3" +dependencies = [ + "libc", +] + +[[package]] +name = "crc32fast" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" dependencies = [ "cfg-if", ] [[package]] name = "critical-section" -version = "1.1.3" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f64009896348fc5af4222e9cf7d7d82a95a256c634ebcf61c53e4ea461422242" +checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" [[package]] name = "crunchy" @@ -486,6 +581,15 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "ctr" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "049bb91fb4aaf0e3c7efa6cd5ef877dbbbd15b39dad06d9948de4ec8a75761ea" +dependencies = [ + "cipher", +] + [[package]] name = "darling" version = "0.13.4" @@ -523,15 +627,15 @@ dependencies = [ [[package]] name = "dary_heap" -version = "0.3.6" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7762d17f1241643615821a8455a0b2c3e803784b058693d990b11f2dce25a0ca" +checksum = "04d2cd9c18b9f454ed67da600630b021a8a80bf33f8c95896ab33aaf1c26b728" [[package]] name = "defmt" -version = "0.3.8" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a99dd22262668b887121d4672af5a64b238f026099f1a2a1b322066c9ecfe9e0" +checksum = "86f6162c53f659f65d00619fe31f14556a6e9f8752ccc4a41bd177ffcf3d6130" dependencies = [ "bitflags 1.3.2", "defmt-macros", @@ -539,31 +643,34 @@ dependencies = [ [[package]] name = "defmt-macros" -version = "0.3.6" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54f0216f6c5acb5ae1a47050a6645024e6edafc2ee32d421955eccfef12ef92e" +checksum = "9d135dd939bad62d7490b0002602d35b358dce5fd9233a709d3c1ef467d4bde6" dependencies = [ "defmt-parser", - "proc-macro-error", + "proc-macro-error2", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.91", ] [[package]] name = "defmt-parser" -version = "0.3.3" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "269924c02afd7f94bc4cecbfa5c379f6ffcf9766b3408fe63d22c728654eccd0" +checksum = "3983b127f13995e68c1e29071e5d115cd96f215ccb5e6812e3728cd6f92653b3" dependencies = [ "thiserror", ] [[package]] name = "deranged" -version = "0.3.7" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7684a49fb1af197853ef7b2ee694bc1f5b4179556f1e5710e1760c5db6f5e929" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +dependencies = [ + "powerfmt", +] [[package]] name = "derive_more" @@ -582,15 +689,15 @@ checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.91", "unicode-xid", ] [[package]] name = "either" -version = "1.9.0" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" [[package]] name = "embedded-hal" @@ -657,6 +764,12 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "foldhash" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0d2fde1f7b3d48b8395d5f2de76c18a528bd6a9cdde438df747bfcba3e05d6f" + [[package]] name = "font8x8" version = "0.2.7" @@ -670,10 +783,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" [[package]] -name = "getrandom" -version = "0.2.10" +name = "generic-array" +version = "0.14.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", "libc", @@ -682,32 +805,42 @@ dependencies = [ [[package]] name = "getset" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e45727250e75cc04ff2846a66397da8ef2b3db8e40e0cef4df67950a07621eb9" +checksum = "f636605b743120a8d32ed92fc27b6cde1a769f8f936c065151eb66f88ded513c" dependencies = [ - "proc-macro-error", + "proc-macro-error2", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.91", +] + +[[package]] +name = "ghash" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1583cc1656d7839fd3732b80cf4f38850336cdb9b8ded1cd399ca62958de3c99" +dependencies = [ + "opaque-debug", + "polyval", ] [[package]] name = "ghost" -version = "0.1.14" +version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba330b70a5341d3bc730b8e205aaee97ddab5d9c448c4f51a7c2d924266fa8f9" +checksum = "39b697dbd8bfcc35d0ee91698aaa379af096368ba8837d279cc097b276edda45" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.91", ] [[package]] name = "gimli" -version = "0.28.0" +version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0" +checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" [[package]] name = "gimli" @@ -725,6 +858,15 @@ dependencies = [ "crunchy", ] +[[package]] +name = "hash32" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0c35f58762feb77d74ebe43bdbc3210f09be9fe6742234d573bacc26ed92b67" +dependencies = [ + "byteorder", +] + [[package]] name = "hash32" version = "0.3.1" @@ -736,12 +878,38 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.14.3" +version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" dependencies = [ "ahash", "allocator-api2", + "serde", +] + +[[package]] +name = "hashbrown" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash", +] + +[[package]] +name = "heapless" +version = "0.7.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdc6457c0eb62c71aac4bc17216026d8410337c4126773b9c5daba343f17964f" +dependencies = [ + "atomic-polyfill", + "hash32 0.2.1", + "rustc_version", + "serde", + "spin", + "stable_deref_trait", ] [[package]] @@ -750,7 +918,7 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0bfb9eb618601c89945a70e254898da93b13be0388091d42117462b265bb3fad" dependencies = [ - "hash32", + "hash32 0.3.1", "stable_deref_trait", ] @@ -778,12 +946,12 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" [[package]] name = "indexmap" -version = "2.2.3" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "233cf39063f058ea2caae4091bf4a3ef70a653afbc026f5c4a4135d114e3c177" +checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f" dependencies = [ "equivalent", - "hashbrown", + "hashbrown 0.15.2", ] [[package]] @@ -810,14 +978,14 @@ version = "0.1.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.91", ] [[package]] name = "intrusive-collections" -version = "0.9.6" +version = "0.9.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b694dc9f70c3bda874626d2aed13b780f137aab435f4e9814121955cf706122e" +checksum = "189d0897e4cbe8c75efedf3502c18c887b05046e59d28404d4d8e46cbc4d1e86" dependencies = [ "memoffset", ] @@ -856,11 +1024,11 @@ version = "0.1.0" [[package]] name = "lazy_static" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" dependencies = [ - "spin 0.5.2", + "spin", ] [[package]] @@ -890,9 +1058,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.153" +version = "0.2.169" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" +checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" [[package]] name = "libflate" @@ -914,7 +1082,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6e0d73b369f386f1c44abd9c570d5318f55ccde816ff4b562fa452e5182863d" dependencies = [ "core2", - "hashbrown", + "hashbrown 0.14.5", "rle-decode-fast", ] @@ -953,9 +1121,9 @@ dependencies = [ [[package]] name = "lock_api" -version = "0.4.10" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" dependencies = [ "autocfg", "scopeguard", @@ -963,17 +1131,17 @@ dependencies = [ [[package]] name = "log" -version = "0.4.20" +version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" [[package]] name = "lru" -version = "0.12.3" +version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3262e75e648fce39813cb56ac41f3c3e3f65217ebf3844d818d1f9398cfb0dc" +checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38" dependencies = [ - "hashbrown", + "hashbrown 0.15.2", ] [[package]] @@ -1000,9 +1168,9 @@ checksum = "0ca88d725a0a943b096803bd34e73a4437208b6077654cc4ecb2947a5f91618d" [[package]] name = "memchr" -version = "2.7.1" +version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "memoffset" @@ -1015,9 +1183,9 @@ dependencies = [ [[package]] name = "multiboot2" -version = "0.23.0" +version = "0.23.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8bcd36c1256cbfbabbd8da34d487a64b45bea009a869185708735951792f0f3" +checksum = "43fcee184de68e344a888bc4f2b9d6b2f2f527cae8cedbb4d62a4df727d1ceae" dependencies = [ "bitflags 2.6.0", "derive_more", @@ -1029,9 +1197,9 @@ dependencies = [ [[package]] name = "multiboot2-common" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9f510cab65715c2b358a50d7d03c022e7c1499084ae6d420b0e594a9ca30853" +checksum = "fbabf8d9980d55576ba487924fa0b9a467fc0012b996b93d2319904f168ed8ab" dependencies = [ "derive_more", "ptr_meta", @@ -1086,6 +1254,12 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + [[package]] name = "num-derive" version = "0.4.2" @@ -1094,7 +1268,7 @@ checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.91", ] [[package]] @@ -1138,16 +1312,22 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.18.0" +version = "1.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" +checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" + +[[package]] +name = "opaque-debug" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" [[package]] name = "osdk-test-kernel" version = "0.11.1" dependencies = [ "ostd", - "owo-colors 4.0.0", + "owo-colors 4.1.0", ] [[package]] @@ -1164,7 +1344,7 @@ dependencies = [ "cfg-if", "const-assert", "fdt", - "gimli 0.28.0", + "gimli 0.28.1", "iced-x86", "id-alloc", "inherit-methods-macro", @@ -1182,7 +1362,7 @@ dependencies = [ "riscv", "sbi-rt", "smallvec", - "spin 0.9.8", + "spin", "static_assertions", "tdx-guest", "unwinding", @@ -1199,7 +1379,7 @@ dependencies = [ "proc-macro2", "quote", "rand", - "syn 2.0.79", + "syn 2.0.91", ] [[package]] @@ -1232,15 +1412,15 @@ checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f" [[package]] name = "owo-colors" -version = "4.0.0" +version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "caff54706df99d2a78a5a4e3455ff45448d81ef1bb63c22cd14052ca0e993a3f" +checksum = "fb37767f6569cd834a413442455e0f066d0d522de8630436e2a1761d9726ba56" [[package]] name = "paste" -version = "1.0.14" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" [[package]] name = "polonius-the-crab" @@ -1249,40 +1429,70 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2a69ee997a6282f8462abf1e0d8c38c965e968799e912b3bed8c9e8a28c2f9f" [[package]] -name = "ppv-lite86" -version = "0.2.17" +name = "polyval" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" - -[[package]] -name = "proc-macro-error" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +checksum = "8419d2b623c7c0896ff2d5d96e2cb4ede590fed28fcc34934f4c33c036e620a1" dependencies = [ - "proc-macro-error-attr", - "proc-macro2", - "quote", - "syn 1.0.109", - "version_check", + "cfg-if", + "cpufeatures", + "opaque-debug", + "universal-hash", ] [[package]] -name = "proc-macro-error-attr" -version = "1.0.4" +name = "postcard" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +checksum = "170a2601f67cc9dba8edd8c4870b15f71a6a2dc196daec8c83f72b59dff628a8" +dependencies = [ + "cobs", + "heapless 0.7.17", + "serde", +] + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "ppv-lite86" +version = "0.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "proc-macro-error-attr2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5" dependencies = [ "proc-macro2", "quote", - "version_check", +] + +[[package]] +name = "proc-macro-error2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802" +dependencies = [ + "proc-macro-error-attr2", + "proc-macro2", + "quote", + "syn 2.0.91", ] [[package]] name = "proc-macro2" -version = "1.0.86" +version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" dependencies = [ "unicode-ident", ] @@ -1315,9 +1525,9 @@ checksum = "8bb0fd6580eeed0103c054e3fba2c2618ff476943762f28a645b63b8692b21c9" [[package]] name = "quote" -version = "1.0.37" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" dependencies = [ "proc-macro2", ] @@ -1384,10 +1594,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3582f63211428f83597b51b2ddb88e2a91a9d52d12831f9d08f5e624e8977422" [[package]] -name = "rustversion" -version = "1.0.14" +name = "rustc_version" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + +[[package]] +name = "rustversion" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e819f2bc632f285be6d7cd36e25940d45b2391dd6d9b939e79de557f7014248" [[package]] name = "sbi-rt" @@ -1411,30 +1630,36 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] -name = "serde" -version = "1.0.196" +name = "semver" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "870026e60fa08c69f064aa766c10f10b1d62db9ccd4d0abb206472bee0ce3b32" +checksum = "3cb6eb87a131f756572d7fb904f6e7b68633f09cca868c5df1c4b8d1a694bbba" + +[[package]] +name = "serde" +version = "1.0.216" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b9781016e935a97e8beecf0c933758c97a5520d32930e460142b4cd80c6338e" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.196" +version = "1.0.216" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33c85360c95e7d137454dc81d9a4ed2b8efd8fbe19cee57357b32b9771fccb67" +checksum = "46f859dbbf73865c6627ed570e78961cd3ac92407a2d117204c49232485da55e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.91", ] [[package]] name = "serde_spanned" -version = "0.6.7" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb5b1b31579f3811bf615c144393417496f152e12ac8b7663bf664f4a815306d" +checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" dependencies = [ "serde", ] @@ -1454,17 +1679,11 @@ dependencies = [ "byteorder", "cfg-if", "defmt", - "heapless", + "heapless 0.8.0", "log", "managed", ] -[[package]] -name = "spin" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" - [[package]] name = "spin" version = "0.9.8" @@ -1501,6 +1720,12 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" +[[package]] +name = "subtle" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" + [[package]] name = "syn" version = "1.0.109" @@ -1514,9 +1739,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.79" +version = "2.0.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590" +checksum = "d53cbcb5a243bd33b7858b1d7f4aca2153490815872d86d955d6ea29f743c035" dependencies = [ "proc-macro2", "quote", @@ -1549,46 +1774,48 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.44" +version = "2.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "611040a08a0439f8248d1990b111c95baa9c704c805fa1f62104b39655fd7f90" +checksum = "f072643fd0190df67a8bab670c20ef5d8737177d6ac6b2e9a236cb096206b2cc" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.44" +version = "2.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "090198534930841fab3a5d1bb637cde49e339654e606195f8d9c76eeb081dc96" +checksum = "7b50fa271071aae2e6ee85f842e2e28ba8cd2c5fb67f11fcb1fd70b276f9e7d4" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.91", ] [[package]] name = "time" -version = "0.3.25" +version = "0.3.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0fdd63d58b18d663fbdf70e049f00a22c8e42be082203be7f26589213cd75ea" +checksum = "35e7868883861bd0e56d9ac6efcaaca0d6d5d82a2a7ec8209ff492c07cf37b21" dependencies = [ "deranged", + "num-conv", + "powerfmt", "serde", "time-core", ] [[package]] name = "time-core" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" [[package]] name = "toml" -version = "0.7.6" +version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c17e963a819c331dcacd7ab957d80bc2b9a9c1e71c804826d2f283dd65306542" +checksum = "dd79e69d3b627db300ff956027cc6c3798cef26d22526befdfcd12feeb6d2257" dependencies = [ "serde", "serde_spanned", @@ -1598,18 +1825,18 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.6.7" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8fb9f64314842840f1d940ac544da178732128f1c78c21772e876579e0da1db" +checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" dependencies = [ "serde", ] [[package]] name = "toml_edit" -version = "0.19.14" +version = "0.19.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8123f27e969974a3dfba720fdb560be359f57b44302d280ba72e76a74480e8a" +checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ "indexmap", "serde", @@ -1641,11 +1868,11 @@ checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] name = "uart_16550" -version = "0.3.0" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6dc00444796f6c71f47c85397a35e9c4dbf9901902ac02386940d178e2b78687" +checksum = "e492212ac378a5e00da953718dafb1340d9fbaf4f27d6f3c5cab03d931d1c049" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.6.0", "rustversion", "x86", ] @@ -1684,7 +1911,7 @@ checksum = "c19ee3a01d435eda42cb9931269b349d28a1762f91ddf01c68d276f74b957cc3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.91", ] [[package]] @@ -1700,21 +1927,31 @@ dependencies = [ [[package]] name = "uguid" -version = "2.1.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ef516f0806c5f61da6aa95125d0eb2d91cc95b2df426c06bde8be657282aee5" +checksum = "ab14ea9660d240e7865ce9d54ecdbd1cd9fa5802ae6f4512f093c7907e921533" [[package]] name = "unicode-ident" -version = "1.0.11" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" +checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" [[package]] name = "unicode-xid" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "229730647fbc343e3a80e463c1db7f78f3855d3f3739bee0dda773c9a037c90a" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + +[[package]] +name = "universal-hash" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f214e8f697e925001e66ec2c6e37a4ef93f0f78c2eed7814394e10c62025b05" +dependencies = [ + "generic-array", + "subtle", +] [[package]] name = "unwinding" @@ -1727,15 +1964,15 @@ dependencies = [ [[package]] name = "utf8parse" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "version_check" -version = "0.9.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "volatile" @@ -1756,9 +1993,9 @@ dependencies = [ [[package]] name = "vte_generate_state_changes" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d257817081c7dffcdbab24b9e62d2def62e2ff7d00b1c20062551e6cccc145ff" +checksum = "2e369bee1b05d510a7b4ed645f5faa90619e05437111783ea5848f28d97d3c2e" dependencies = [ "proc-macro2", "quote", @@ -1772,9 +2009,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "winnow" -version = "0.5.7" +version = "0.5.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19f495880723d0999eb3500a9064d8dbcf836460b24c17df80ea7b5794053aac" +checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" dependencies = [ "memchr", ] @@ -1857,20 +2094,21 @@ checksum = "2fe21bcc34ca7fe6dd56cc2cb1261ea59d6b93620215aefb5ea6032265527784" [[package]] name = "zerocopy" -version = "0.7.32" +version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" dependencies = [ + "byteorder", "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.7.32" +version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.91", ] diff --git a/Cargo.toml b/Cargo.toml index 9eda94ffc..d780f6c0c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,6 +18,7 @@ members = [ "kernel/comps/network", "kernel/comps/softirq", "kernel/comps/logger", + "kernel/comps/mlsdisk", "kernel/comps/time", "kernel/comps/virtio", "kernel/libs/cpio-decoder", diff --git a/Components.toml b/Components.toml index 866bd652b..0c84da501 100644 --- a/Components.toml +++ b/Components.toml @@ -10,6 +10,7 @@ logger = { name = "aster-logger" } time = { name = "aster-time" } framebuffer = { name = "aster-framebuffer" } network = { name = "aster-network" } +mlsdisk = { name = "aster-mlsdisk" } [whitelist] [whitelist.nix.main] diff --git a/Makefile b/Makefile index 1fd16a08b..6616579e1 100644 --- a/Makefile +++ b/Makefile @@ -149,6 +149,7 @@ OSDK_CRATES := \ kernel/comps/network \ kernel/comps/softirq \ kernel/comps/logger \ + kernel/comps/mlsdisk \ kernel/comps/time \ kernel/comps/virtio \ kernel/libs/aster-util \ diff --git a/kernel/Cargo.toml b/kernel/Cargo.toml index 5dabca618..c2ff90b1a 100644 --- a/kernel/Cargo.toml +++ b/kernel/Cargo.toml @@ -14,6 +14,7 @@ aster-console = { path = "comps/console" } aster-framebuffer = { path = "comps/framebuffer" } aster-softirq = { path = "comps/softirq" } aster-logger = { path = "comps/logger" } +aster-mlsdisk = { path = "comps/mlsdisk" } aster-time = { path = "comps/time" } aster-virtio = { path = "comps/virtio" } aster-rights = { path = "libs/aster-rights" } diff --git a/kernel/comps/mlsdisk/Cargo.toml b/kernel/comps/mlsdisk/Cargo.toml new file mode 100644 index 000000000..897f3d567 --- /dev/null +++ b/kernel/comps/mlsdisk/Cargo.toml @@ -0,0 +1,22 @@ +[package] +name = "aster-mlsdisk" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +inherit-methods-macro = {git = "https://github.com/asterinas/inherit-methods-macro", rev = "98f7e3e"} +ostd-pod = { git = "https://github.com/asterinas/ostd-pod", rev = "c4644be", version = "0.1.1" } +aster-block = { path = "../block" } +ostd = { path = "../../../ostd" } +aes-gcm = { version = "0.9.4", features = ["force-soft"] } +bittle = "0.5.6" +ctr = "0.8.0" +hashbrown = { version = "0.14.3", features = ["serde"] } +lending-iterator = "0.1.7" +log = "0.4" +lru = "0.12.3" +postcard = "1.0.6" +serde = { version = "1.0.192", default-features = false, features = ["alloc", "derive"] } +static_assertions = "1.1.0" diff --git a/kernel/comps/mlsdisk/src/error.rs b/kernel/comps/mlsdisk/src/error.rs new file mode 100644 index 000000000..c20dee943 --- /dev/null +++ b/kernel/comps/mlsdisk/src/error.rs @@ -0,0 +1,95 @@ +// SPDX-License-Identifier: MPL-2.0 + +use core::fmt; + +/// The error types used in this crate. +#[derive(Clone, Copy, PartialEq, Eq, Debug)] +pub enum Errno { + /// Transaction aborted. + TxAborted, + /// Not found. + NotFound, + /// Invalid arguments. + InvalidArgs, + /// Out of memory. + OutOfMemory, + /// Out of disk space. + OutOfDisk, + /// IO error. + IoFailed, + /// Permission denied. + PermissionDenied, + /// Unsupported. + Unsupported, + /// OS-specific unknown error. + OsSpecUnknown, + /// Encryption operation failed. + EncryptFailed, + /// Decryption operation failed. + DecryptFailed, + /// MAC (Message Authentication Code) mismatched. + MacMismatched, + /// Not aligned to `BLOCK_SIZE`. + NotBlockSizeAligned, + /// Try lock failed. + TryLockFailed, +} + +/// The error with an error type and an error message used in this crate. +#[derive(Clone, Debug)] +pub struct Error { + errno: Errno, + msg: Option<&'static str>, +} + +impl Error { + /// Creates a new error with the given error type and no error message. + pub const fn new(errno: Errno) -> Self { + Error { errno, msg: None } + } + + /// Creates a new error with the given error type and the error message. + pub const fn with_msg(errno: Errno, msg: &'static str) -> Self { + Error { + errno, + msg: Some(msg), + } + } + + /// Returns the error type. + pub fn errno(&self) -> Errno { + self.errno + } +} + +impl From for Error { + fn from(errno: Errno) -> Self { + Error::new(errno) + } +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{:?}", self) + } +} + +impl fmt::Display for Errno { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{:?}", self) + } +} + +#[macro_export] +macro_rules! return_errno { + ($errno: expr) => { + return core::result::Result::Err($crate::Error::new($errno)) + }; +} + +#[macro_export] +macro_rules! return_errno_with_msg { + ($errno: expr, $msg: expr) => { + return core::result::Result::Err($crate::Error::with_msg($errno, $msg)) + }; +} diff --git a/kernel/comps/mlsdisk/src/layers/0-bio/block_buf.rs b/kernel/comps/mlsdisk/src/layers/0-bio/block_buf.rs new file mode 100644 index 000000000..e60d69726 --- /dev/null +++ b/kernel/comps/mlsdisk/src/layers/0-bio/block_buf.rs @@ -0,0 +1,243 @@ +// SPDX-License-Identifier: MPL-2.0 + +//! This module provides API to represent buffers whose +//! sizes are block aligned. The advantage of using the +//! APIs provided this module over Rust std's counterparts +//! is to ensure the invariance of block-aligned length +//! at type level, eliminating the need for runtime check. +//! +//! There are three main types: +//! * `Buf`: A owned buffer backed by `Pages`, whose length is +//! a multiple of the block size. +//! * `BufRef`: An immutably-borrowed buffer whose length +//! is a multiple of the block size. +//! * `BufMut`: A mutably-borrowed buffer whose length is +//! a multiple of the block size. +//! +//! The basic usage is simple: replace the usage of `Box<[u8]>` +//! with `Buf`, `&[u8]` with `BufRef<[u8]>`, +//! and `&mut [u8]` with `BufMut<[u8]>`. + +use alloc::vec; +use core::convert::TryFrom; + +use lending_iterator::prelude::*; + +use super::BLOCK_SIZE; +use crate::prelude::*; + +/// A owned buffer whose length is a multiple of the block size. +pub struct Buf(Vec); + +impl Buf { + /// Allocate specific number of blocks as memory buffer. + pub fn alloc(num_blocks: usize) -> Result { + if num_blocks == 0 { + return_errno_with_msg!( + InvalidArgs, + "num_blocks must be greater than 0 for allocation" + ) + } + let buffer = vec![0; num_blocks * BLOCK_SIZE]; + Ok(Self(buffer)) + } + + /// Returns the number of blocks of owned buffer. + pub fn nblocks(&self) -> usize { + self.0.len() / BLOCK_SIZE + } + + /// Returns the immutable slice of owned buffer. + pub fn as_slice(&self) -> &[u8] { + self.0.as_slice() + } + + /// Returns the mutable slice of owned buffer. + pub fn as_mut_slice(&mut self) -> &mut [u8] { + self.0.as_mut_slice() + } + + /// Converts to immutably-borrowed buffer `BufRef`. + pub fn as_ref(&self) -> BufRef<'_> { + BufRef(self.as_slice()) + } + + /// Coverts to mutably-borrowed buffer `BufMut`. + pub fn as_mut(&mut self) -> BufMut<'_> { + BufMut(self.as_mut_slice()) + } +} + +/// An immutably-borrowed buffer whose length is a multiple of the block size. +#[derive(Clone, Copy)] +pub struct BufRef<'a>(&'a [u8]); + +impl BufRef<'_> { + /// Returns the immutable slice of borrowed buffer. + pub fn as_slice(&self) -> &[u8] { + self.0 + } + + /// Returns the number of blocks of borrowed buffer. + pub fn nblocks(&self) -> usize { + self.0.len() / BLOCK_SIZE + } + + /// Returns an iterator for immutable buffers of `BLOCK_SIZE`. + pub fn iter(&self) -> BufIter<'_> { + BufIter { + buf: BufRef(self.as_slice()), + offset: 0, + } + } +} + +impl<'a> TryFrom<&'a [u8]> for BufRef<'a> { + type Error = crate::error::Error; + + fn try_from(buf: &'a [u8]) -> Result { + if buf.is_empty() { + return_errno_with_msg!(InvalidArgs, "empty buf in `BufRef::try_from`"); + } + if buf.len() % BLOCK_SIZE != 0 { + return_errno_with_msg!( + NotBlockSizeAligned, + "buf not block size aligned `BufRef::try_from`" + ); + } + + let new_self = Self(buf); + Ok(new_self) + } +} + +/// A mutably-borrowed buffer whose length is a multiple of the block size. +pub struct BufMut<'a>(&'a mut [u8]); + +impl BufMut<'_> { + /// Returns the immutable slice of borrowed buffer. + pub fn as_slice(&self) -> &[u8] { + self.0 + } + + /// Returns the mutable slice of borrowed buffer. + pub fn as_mut_slice(&mut self) -> &mut [u8] { + self.0 + } + + /// Returns the number of blocks of borrowed buffer. + pub fn nblocks(&self) -> usize { + self.0.len() / BLOCK_SIZE + } + + /// Returns an iterator for immutable buffers of `BLOCK_SIZE`. + pub fn iter(&self) -> BufIter<'_> { + BufIter { + buf: BufRef(self.as_slice()), + offset: 0, + } + } + + /// Returns an iterator for mutable buffers of `BLOCK_SIZE`. + pub fn iter_mut(&mut self) -> BufIterMut<'_> { + BufIterMut { + buf: BufMut(self.as_mut_slice()), + offset: 0, + } + } +} + +impl<'a> TryFrom<&'a mut [u8]> for BufMut<'a> { + type Error = crate::error::Error; + + fn try_from(buf: &'a mut [u8]) -> Result { + if buf.is_empty() { + return_errno_with_msg!(InvalidArgs, "empty buf in `BufMut::try_from`"); + } + if buf.len() % BLOCK_SIZE != 0 { + return_errno_with_msg!( + NotBlockSizeAligned, + "buf not block size aligned `BufMut::try_from`" + ); + } + + let new_self = Self(buf); + Ok(new_self) + } +} + +/// Iterator for immutable buffers of `BLOCK_SIZE`. +pub struct BufIter<'a> { + buf: BufRef<'a>, + offset: usize, +} + +impl<'a> Iterator for BufIter<'a> { + type Item = BufRef<'a>; + + fn next(&mut self) -> Option { + if self.offset >= self.buf.0.len() { + return None; + } + + let offset = self.offset; + self.offset += BLOCK_SIZE; + BufRef::try_from(&self.buf.0[offset..offset + BLOCK_SIZE]).ok() + } +} + +/// Iterator for mutable buffers of `BLOCK_SIZE`. +pub struct BufIterMut<'a> { + buf: BufMut<'a>, + offset: usize, +} + +#[gat] +impl LendingIterator for BufIterMut<'_> { + type Item<'next> = BufMut<'next>; + + fn next(&mut self) -> Option> { + if self.offset >= self.buf.0.len() { + return None; + } + + let offset = self.offset; + self.offset += BLOCK_SIZE; + BufMut::try_from(&mut self.buf.0[offset..offset + BLOCK_SIZE]).ok() + } +} + +#[cfg(test)] +mod tests { + use lending_iterator::LendingIterator; + + use super::{Buf, BufMut, BufRef, BLOCK_SIZE}; + + fn iterate_buf_ref<'a>(buf: BufRef<'a>) { + for block in buf.iter() { + assert_eq!(block.as_slice().len(), BLOCK_SIZE); + assert_eq!(block.nblocks(), 1); + } + } + + fn iterate_buf_mut<'a>(mut buf: BufMut<'a>) { + let mut iter_mut = buf.iter_mut(); + while let Some(mut block) = iter_mut.next() { + assert_eq!(block.as_mut_slice().len(), BLOCK_SIZE); + assert_eq!(block.nblocks(), 1); + } + } + + #[test] + fn buf() { + let mut buf = Buf::alloc(10).unwrap(); + assert_eq!(buf.nblocks(), 10); + assert_eq!(buf.as_slice().len(), 10 * BLOCK_SIZE); + iterate_buf_ref(buf.as_ref()); + iterate_buf_mut(buf.as_mut()); + + let mut buf = [0u8; BLOCK_SIZE]; + iterate_buf_ref(BufRef::try_from(buf.as_slice()).unwrap()); + iterate_buf_mut(BufMut::try_from(buf.as_mut_slice()).unwrap()); + } +} diff --git a/kernel/comps/mlsdisk/src/layers/0-bio/block_log.rs b/kernel/comps/mlsdisk/src/layers/0-bio/block_log.rs new file mode 100644 index 000000000..59cb5f360 --- /dev/null +++ b/kernel/comps/mlsdisk/src/layers/0-bio/block_log.rs @@ -0,0 +1,133 @@ +// SPDX-License-Identifier: MPL-2.0 + +use core::sync::atomic::{AtomicUsize, Ordering}; + +use inherit_methods_macro::inherit_methods; + +use super::{Buf, BufMut, BufRef}; +use crate::{os::Mutex, prelude::*}; + +/// A log of data blocks that can support random reads and append-only +/// writes. +/// +/// # Thread safety +/// +/// `BlockLog` is a data structure of interior mutability. +/// It is ok to perform I/O on a `BlockLog` concurrently in multiple threads. +/// `BlockLog` promises the serialization of the append operations, i.e., +/// concurrent appends are carried out as if they are done one by one. +pub trait BlockLog: Sync + Send { + /// Read one or multiple blocks at a specified position. + fn read(&self, pos: BlockId, buf: BufMut) -> Result<()>; + + /// Append one or multiple blocks at the end, + /// returning the ID of the first newly-appended block. + fn append(&self, buf: BufRef) -> Result; + + /// Ensure that blocks are persisted to the disk. + fn flush(&self) -> Result<()>; + + /// Returns the number of blocks. + fn nblocks(&self) -> usize; +} + +macro_rules! impl_blocklog_for { + ($typ:ty,$from:tt) => { + #[inherit_methods(from = $from)] + impl BlockLog for $typ { + fn read(&self, pos: BlockId, buf: BufMut) -> Result<()>; + fn append(&self, buf: BufRef) -> Result; + fn flush(&self) -> Result<()>; + fn nblocks(&self) -> usize; + } + }; +} + +impl_blocklog_for!(&T, "(**self)"); +impl_blocklog_for!(&mut T, "(**self)"); +impl_blocklog_for!(Box, "(**self)"); +impl_blocklog_for!(Arc, "(**self)"); + +/// An in-memory log that impls `BlockLog`. +pub struct MemLog { + log: Mutex, + append_pos: AtomicUsize, +} + +impl BlockLog for MemLog { + fn read(&self, pos: BlockId, mut buf: BufMut) -> Result<()> { + let nblocks = buf.nblocks(); + if pos + nblocks > self.nblocks() { + return_errno_with_msg!(InvalidArgs, "read range out of bound"); + } + let log = self.log.lock(); + let read_buf = &log.as_slice()[Self::offset(pos)..Self::offset(pos) + nblocks * BLOCK_SIZE]; + buf.as_mut_slice().copy_from_slice(read_buf); + Ok(()) + } + + fn append(&self, buf: BufRef) -> Result { + let nblocks = buf.nblocks(); + let mut log = self.log.lock(); + let pos = self.append_pos.load(Ordering::Acquire); + if pos + nblocks > log.nblocks() { + return_errno_with_msg!(InvalidArgs, "append range out of bound"); + } + let write_buf = + &mut log.as_mut_slice()[Self::offset(pos)..Self::offset(pos) + nblocks * BLOCK_SIZE]; + write_buf.copy_from_slice(buf.as_slice()); + self.append_pos.fetch_add(nblocks, Ordering::Release); + Ok(pos) + } + + fn flush(&self) -> Result<()> { + Ok(()) + } + + fn nblocks(&self) -> usize { + self.append_pos.load(Ordering::Acquire) + } +} + +impl MemLog { + pub fn create(num_blocks: usize) -> Result { + Ok(Self { + log: Mutex::new(Buf::alloc(num_blocks)?), + append_pos: AtomicUsize::new(0), + }) + } + + fn offset(pos: BlockId) -> usize { + pos * BLOCK_SIZE + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn mem_log() -> Result<()> { + let total_blocks = 64; + let append_nblocks = 8; + let mem_log = MemLog::create(total_blocks)?; + assert_eq!(mem_log.nblocks(), 0); + + let mut append_buf = Buf::alloc(append_nblocks)?; + let content = 5_u8; + append_buf.as_mut_slice().fill(content); + let append_pos = mem_log.append(append_buf.as_ref())?; + assert_eq!(append_pos, 0); + assert_eq!(mem_log.nblocks(), append_nblocks); + + mem_log.flush()?; + let mut read_buf = Buf::alloc(1)?; + let read_pos = 7 as BlockId; + mem_log.read(read_pos, read_buf.as_mut())?; + assert_eq!( + read_buf.as_slice(), + &append_buf.as_slice()[read_pos * BLOCK_SIZE..(read_pos + 1) * BLOCK_SIZE] + ); + Ok(()) + } +} diff --git a/kernel/comps/mlsdisk/src/layers/0-bio/block_ring.rs b/kernel/comps/mlsdisk/src/layers/0-bio/block_ring.rs new file mode 100644 index 000000000..2d03c9efe --- /dev/null +++ b/kernel/comps/mlsdisk/src/layers/0-bio/block_ring.rs @@ -0,0 +1,114 @@ +// SPDX-License-Identifier: MPL-2.0 + +use super::{BlockLog, BlockSet, BufMut, BufRef}; +use crate::{os::Mutex, prelude::*}; + +/// `BlockRing` emulates a blocks log (`BlockLog`) with infinite +/// storage capacity by using a block set (`S: BlockSet`) of finite storage +/// capacity. +/// +/// `BlockRing` uses the entire storage space provided by the underlying +/// block set (`S`) for user data, maintaining no extra metadata. +/// Having no metadata, `BlockRing` has to put three responsibilities to +/// its user: +/// +/// 1. Tracking the valid block range for read. +/// `BlockRing` accepts reads at any position regardless of whether the +/// position refers to a valid block. It blindly redirects the read request to +/// the underlying block set after moduloing the target position by the +/// size of the block set. +/// +/// 2. Setting the cursor for appending new blocks. +/// `BlockRing` won't remember the progress of writing blocks after reboot. +/// Thus, after a `BlockRing` is instantiated, the user must specify the +/// append cursor (using the `set_cursor` method) before appending new blocks. +/// +/// 3. Avoiding overriding valid data blocks mistakenly. +/// As the underlying storage is used in a ring buffer style, old +/// blocks must be overridden to accommodate new blocks. The user must ensure +/// that the underlying storage is big enough to avoid overriding any useful +/// data. +pub struct BlockRing { + storage: S, + // The cursor for appending new blocks + cursor: Mutex>, +} + +impl BlockRing { + /// Creates a new instance. + pub fn new(storage: S) -> Self { + Self { + storage, + cursor: Mutex::new(None), + } + } + + /// Set the cursor for appending new blocks. + /// + /// # Panics + /// + /// Calling the `append` method without setting the append cursor first + /// via this method `set_cursor` causes panic. + pub fn set_cursor(&self, new_cursor: BlockId) { + *self.cursor.lock() = Some(new_cursor); + } + + // Return a reference to the underlying storage. + pub fn storage(&self) -> &S { + &self.storage + } +} + +impl BlockLog for BlockRing { + fn read(&self, pos: BlockId, buf: BufMut) -> Result<()> { + let pos = pos % self.storage.nblocks(); + self.storage.read(pos, buf) + } + + fn append(&self, buf: BufRef) -> Result { + let cursor = self + .cursor + .lock() + .expect("cursor must be set before appending new blocks"); + let pos = cursor % self.storage.nblocks(); + let new_cursor = cursor + buf.nblocks(); + self.storage.write(pos, buf)?; + self.set_cursor(new_cursor); + Ok(cursor) + } + + fn flush(&self) -> Result<()> { + self.storage.flush() + } + + fn nblocks(&self) -> usize { + self.cursor.lock().unwrap_or(0) + } +} + +#[cfg(test)] +mod tests { + use super::BlockRing; + use crate::layers::bio::{BlockLog, Buf, MemDisk}; + + #[test] + fn block_ring() { + let num_blocks = 16; + let disk = MemDisk::create(num_blocks).unwrap(); + let block_ring = BlockRing::new(disk); + block_ring.set_cursor(num_blocks); + assert_eq!(block_ring.nblocks(), num_blocks); + + let mut append_buf = Buf::alloc(1).unwrap(); + append_buf.as_mut_slice().fill(1); + let pos = block_ring.append(append_buf.as_ref()).unwrap(); + assert_eq!(pos, num_blocks); + assert_eq!(block_ring.nblocks(), num_blocks + 1); + + let mut read_buf = Buf::alloc(1).unwrap(); + block_ring + .read(pos % num_blocks, read_buf.as_mut()) + .unwrap(); + assert_eq!(read_buf.as_slice(), append_buf.as_slice()); + } +} diff --git a/kernel/comps/mlsdisk/src/layers/0-bio/block_set.rs b/kernel/comps/mlsdisk/src/layers/0-bio/block_set.rs new file mode 100644 index 000000000..ed0604d65 --- /dev/null +++ b/kernel/comps/mlsdisk/src/layers/0-bio/block_set.rs @@ -0,0 +1,227 @@ +// SPDX-License-Identifier: MPL-2.0 + +use core::ops::Range; + +use inherit_methods_macro::inherit_methods; + +use super::{Buf, BufMut, BufRef}; +use crate::{error::Errno, os::Mutex, prelude::*}; + +/// A fixed set of data blocks that can support random reads and writes. +/// +/// # Thread safety +/// +/// `BlockSet` is a data structure of interior mutability. +/// It is ok to perform I/O on a `BlockSet` concurrently in multiple threads. +/// `BlockSet` promises the atomicity of reading and writing individual blocks. +pub trait BlockSet: Sync + Send { + /// Read one or multiple blocks at a specified position. + fn read(&self, pos: BlockId, buf: BufMut) -> Result<()>; + + /// Read a slice of bytes at a specified byte offset. + fn read_slice(&self, offset: usize, buf: &mut [u8]) -> Result<()> { + let start_pos = offset / BLOCK_SIZE; + let end_pos = (offset + buf.len()).div_ceil(BLOCK_SIZE); + if end_pos > self.nblocks() { + return_errno_with_msg!(Errno::InvalidArgs, "read_slice position is out of range"); + } + + let nblocks = end_pos - start_pos; + let mut blocks = Buf::alloc(nblocks)?; + self.read(start_pos, blocks.as_mut())?; + + let offset = offset % BLOCK_SIZE; + buf.copy_from_slice(&blocks.as_slice()[offset..offset + buf.len()]); + Ok(()) + } + + /// Write one or multiple blocks at a specified position. + fn write(&self, pos: BlockId, buf: BufRef) -> Result<()>; + + /// Write a slice of bytes at a specified byte offset. + fn write_slice(&self, offset: usize, buf: &[u8]) -> Result<()> { + let start_pos = offset / BLOCK_SIZE; + let end_pos = (offset + buf.len()).div_ceil(BLOCK_SIZE); + if end_pos > self.nblocks() { + return_errno_with_msg!(Errno::InvalidArgs, "write_slice position is out of range"); + } + let nblocks = end_pos - start_pos; + let mut blocks = Buf::alloc(nblocks)?; + + // Maybe we should read the first block partially. + let start_offset = offset % BLOCK_SIZE; + if start_offset != 0 { + let mut start_block = Buf::alloc(1)?; + self.read(start_pos, start_block.as_mut())?; + blocks.as_mut_slice()[..start_offset] + .copy_from_slice(&start_block.as_slice()[..start_offset]); + } + + // Copy the input buffer to the write buffer. + let end_offset = start_offset + buf.len(); + blocks.as_mut_slice()[start_offset..end_offset].copy_from_slice(buf); + + // Maybe we should read the last block partially. + if end_offset % BLOCK_SIZE != 0 { + let mut end_block = Buf::alloc(1)?; + self.read(end_pos, end_block.as_mut())?; + blocks.as_mut_slice()[end_offset..] + .copy_from_slice(&end_block.as_slice()[end_offset % BLOCK_SIZE..]); + } + + // Write blocks. + self.write(start_pos, blocks.as_ref())?; + Ok(()) + } + + /// Get a subset of the blocks in the block set. + fn subset(&self, range: Range) -> Result + where + Self: Sized; + + /// Ensure that blocks are persisted to the disk. + fn flush(&self) -> Result<()>; + + /// Returns the number of blocks. + fn nblocks(&self) -> usize; +} + +macro_rules! impl_blockset_for { + ($typ:ty,$from:tt,$subset_fn:expr) => { + #[inherit_methods(from = $from)] + impl BlockSet for $typ { + fn read(&self, pos: BlockId, buf: BufMut) -> Result<()>; + fn read_slice(&self, offset: usize, buf: &mut [u8]) -> Result<()>; + fn write(&self, pos: BlockId, buf: BufRef) -> Result<()>; + fn write_slice(&self, offset: usize, buf: &[u8]) -> Result<()>; + fn flush(&self) -> Result<()>; + fn nblocks(&self) -> usize; + fn subset(&self, range: Range) -> Result { + let closure = $subset_fn; + closure(self, range) + } + } + }; +} + +impl_blockset_for!(&T, "(**self)", |_this, _range| { + return_errno_with_msg!(Errno::NotFound, "cannot return `Self` by `subset` of `&T`"); +}); + +impl_blockset_for!(&mut T, "(**self)", |_this, _range| { + return_errno_with_msg!( + Errno::NotFound, + "cannot return `Self` by `subset` of `&mut T`" + ); +}); + +impl_blockset_for!(Box, "(**self)", |this: &T, range| { + this.subset(range).map(|v| Box::new(v)) +}); + +impl_blockset_for!(Arc, "(**self)", |this: &Arc, range| { + (**this).subset(range).map(|v| Arc::new(v)) +}); + +/// A disk that impl `BlockSet`. +/// +/// The `region` is the accessible subset. +#[derive(Clone)] +pub struct MemDisk { + disk: Arc>, + region: Range, +} + +impl MemDisk { + /// Create a `MemDisk` with the number of blocks. + pub fn create(num_blocks: usize) -> Result { + let blocks = Buf::alloc(num_blocks)?; + Ok(Self { + disk: Arc::new(Mutex::new(blocks)), + region: Range { + start: 0, + end: num_blocks, + }, + }) + } +} + +impl BlockSet for MemDisk { + fn read(&self, pos: BlockId, mut buf: BufMut) -> Result<()> { + if pos + buf.nblocks() > self.region.end { + return_errno_with_msg!(Errno::InvalidArgs, "read position is out of range"); + } + let offset = (self.region.start + pos) * BLOCK_SIZE; + let buf_len = buf.as_slice().len(); + + let disk = self.disk.lock(); + buf.as_mut_slice() + .copy_from_slice(&disk.as_slice()[offset..offset + buf_len]); + Ok(()) + } + + fn write(&self, pos: BlockId, buf: BufRef) -> Result<()> { + if pos + buf.nblocks() > self.region.end { + return_errno_with_msg!(Errno::InvalidArgs, "write position is out of range"); + } + let offset = (self.region.start + pos) * BLOCK_SIZE; + let buf_len = buf.as_slice().len(); + + let mut disk = self.disk.lock(); + disk.as_mut_slice()[offset..offset + buf_len].copy_from_slice(buf.as_slice()); + Ok(()) + } + + fn subset(&self, range: Range) -> Result { + if self.region.start + range.end > self.region.end { + return_errno_with_msg!(Errno::InvalidArgs, "subset is out of range"); + } + + Ok(MemDisk { + disk: self.disk.clone(), + region: Range { + start: self.region.start + range.start, + end: self.region.start + range.end, + }, + }) + } + + fn flush(&self) -> Result<()> { + Ok(()) + } + + fn nblocks(&self) -> usize { + self.region.len() + } +} + +#[cfg(test)] +mod tests { + use core::ops::Range; + + use crate::layers::bio::{BlockSet, Buf, MemDisk}; + + #[test] + fn mem_disk() { + let num_blocks = 64; + let disk = MemDisk::create(num_blocks).unwrap(); + assert_eq!(disk.nblocks(), 64); + + let mut buf = Buf::alloc(1).unwrap(); + buf.as_mut_slice().fill(1); + disk.write(32, buf.as_ref()).unwrap(); + + let range = Range { start: 32, end: 64 }; + let subset = disk.subset(range).unwrap(); + assert_eq!(subset.nblocks(), 32); + + buf.as_mut_slice().fill(0); + subset.read(0, buf.as_mut()).unwrap(); + assert_eq!(buf.as_ref().as_slice(), [1u8; 4096]); + + subset.write_slice(4096 - 4, &[2u8; 8]).unwrap(); + let mut buf = [0u8; 16]; + subset.read_slice(4096 - 8, &mut buf).unwrap(); + assert_eq!(buf, [1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0]); + } +} diff --git a/kernel/comps/mlsdisk/src/layers/0-bio/mod.rs b/kernel/comps/mlsdisk/src/layers/0-bio/mod.rs new file mode 100644 index 000000000..9c6dbece3 --- /dev/null +++ b/kernel/comps/mlsdisk/src/layers/0-bio/mod.rs @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: MPL-2.0 + +//! The layer of untrusted block I/O. + +use static_assertions::assert_eq_size; + +mod block_buf; +mod block_log; +mod block_ring; +mod block_set; + +pub use self::{ + block_buf::{Buf, BufMut, BufRef}, + block_log::{BlockLog, MemLog}, + block_ring::BlockRing, + block_set::{BlockSet, MemDisk}, +}; + +pub type BlockId = usize; +pub const BLOCK_SIZE: usize = 0x1000; +pub const BID_SIZE: usize = core::mem::size_of::(); + +// This definition of BlockId assumes the target architecture is 64-bit +assert_eq_size!(usize, u64); diff --git a/kernel/comps/mlsdisk/src/layers/1-crypto/crypto_blob.rs b/kernel/comps/mlsdisk/src/layers/1-crypto/crypto_blob.rs new file mode 100644 index 000000000..c35bbe9e3 --- /dev/null +++ b/kernel/comps/mlsdisk/src/layers/1-crypto/crypto_blob.rs @@ -0,0 +1,358 @@ +// SPDX-License-Identifier: MPL-2.0 + +use ostd_pod::Pod; + +use super::{Iv, Key, Mac, VersionId}; +use crate::{ + layers::bio::{BlockSet, Buf, BLOCK_SIZE}, + os::{Aead, Mutex}, + prelude::*, +}; + +/// A cryptographically-protected blob of user data. +/// +/// `CryptoBlob` allows a variable-length of user data to be securely +/// written to and read from a fixed, pre-allocated block set +/// (represented by `B: BlockSet`) on disk. Obviously, the length of user data +/// must be smaller than that of the block set. +/// +/// # On-disk format +/// +/// The on-disk format of `CryptoBlob` is shown below. +/// +/// ``` +/// ┌─────────┬─────────┬─────────┬──────────────────────────────┐ +/// │VersionId│ MAC │ Length │ Encrypted Payload │ +/// │ (8B) │ (16B) │ (8B) │ (Length bytes) │ +/// └─────────┴─────────┴─────────┴──────────────────────────────┘ +/// ``` +/// +/// The version ID increments by one each time the `CryptoBlob` is updated. +/// The MAC protects the integrity of the length and the encrypted payload. +/// +/// # Security +/// +/// To ensure the confidentiality and integrity of user data, `CryptoBlob` +/// takes several measures: +/// +/// 1. Each instance of `CryptoBlob` is associated with a randomly-generated, +/// unique encryption key. +/// 2. Each instance of `CryptoBlob` maintains a version ID, which is +/// automatically incremented by one upon each write. +/// 3. The user data written to a `CryptoBlob` is protected with authenticated +/// encryption before being persisted to the disk. +/// The encryption takes the current version ID as the IV and generates a MAC +/// as the output. +/// 4. To read user data from a `CryptoBlob`, it first decrypts +/// the untrusted on-disk data with the encryption key associated with this object +/// and validating its integrity. Optimally, the user can check the version ID +/// of the decrypted user data and see if the version ID is up-to-date. +/// +pub struct CryptoBlob { + block_set: B, + key: Key, + header: Mutex>, +} + +#[repr(C)] +#[derive(Copy, Clone, Pod)] +struct Header { + version: VersionId, + mac: Mac, + payload_len: usize, +} + +impl CryptoBlob { + /// The size of the header of a crypto blob in bytes. + pub const HEADER_NBYTES: usize = core::mem::size_of::
(); + + /// Opens an existing `CryptoBlob`. + /// + /// The capacity of this `CryptoBlob` object is determined by the size + /// of `block_set: B`. + pub fn open(key: Key, block_set: B) -> Self { + Self { + block_set, + key, + header: Mutex::new(None), + } + } + + /// Creates a new `CryptoBlob`. + /// + /// The encryption key of a `CryptoBlob` is generated randomly so that + /// no two `CryptoBlob` instances shall ever use the same key. + pub fn create(block_set: B, init_data: &[u8]) -> Result { + let capacity = block_set.nblocks() * BLOCK_SIZE - Self::HEADER_NBYTES; + if init_data.len() > capacity { + return_errno_with_msg!(OutOfDisk, "init_data is too large"); + } + let nblocks = (Self::HEADER_NBYTES + init_data.len()).div_ceil(BLOCK_SIZE); + let mut block_buf = Buf::alloc(nblocks)?; + + // Encrypt init_data. + let aead = Aead::new(); + let key = Key::random(); + let version: VersionId = 0; + let mut iv = Iv::new_zeroed(); + iv.as_bytes_mut()[..version.as_bytes().len()].copy_from_slice(version.as_bytes()); + let output = &mut block_buf.as_mut_slice() + [Self::HEADER_NBYTES..Self::HEADER_NBYTES + init_data.len()]; + let mac = aead.encrypt(init_data, &key, &iv, &[], output)?; + + // Store header. + let header = Header { + version, + mac, + payload_len: init_data.len(), + }; + block_buf.as_mut_slice()[..Self::HEADER_NBYTES].copy_from_slice(header.as_bytes()); + + // Write to `BlockSet`. + block_set.write(0, block_buf.as_ref())?; + Ok(Self { + block_set, + key, + header: Mutex::new(Some(header)), + }) + } + + /// Write the buffer to the disk as the latest version of the content of + /// this `CryptoBlob`. + /// + /// The size of the buffer must not be greater than the capacity of this + /// `CryptoBlob`. + /// + /// Each successful write increments the version ID by one. If + /// there is no valid version ID, an `Error` will be returned. + /// User could get a version ID, either by a successful call to + /// `read`, or `recover_from` another valid `CryptoBlob`. + /// + /// # Security + /// + /// This content is guaranteed to be confidential as long as the key is not + /// known to an attacker. + pub fn write(&mut self, buf: &[u8]) -> Result { + if buf.len() > self.capacity() { + return_errno_with_msg!(OutOfDisk, "write data is too large"); + } + let nblocks = (Self::HEADER_NBYTES + buf.len()).div_ceil(BLOCK_SIZE); + let mut block_buf = Buf::alloc(nblocks)?; + + // Encrypt payload. + let aead = Aead::new(); + let version = match self.version_id() { + Some(version) => version + 1, + None => return_errno_with_msg!(NotFound, "write with no valid version ID"), + }; + let mut iv = Iv::new_zeroed(); + iv.as_bytes_mut()[..version.as_bytes().len()].copy_from_slice(version.as_bytes()); + let output = + &mut block_buf.as_mut_slice()[Self::HEADER_NBYTES..Self::HEADER_NBYTES + buf.len()]; + let mac = aead.encrypt(buf, &self.key, &iv, &[], output)?; + + // Store header. + let header = Header { + version, + mac, + payload_len: buf.len(), + }; + block_buf.as_mut_slice()[..Self::HEADER_NBYTES].copy_from_slice(header.as_bytes()); + + // Write to `BlockSet`. + self.block_set.write(0, block_buf.as_ref())?; + *self.header.lock() = Some(header); + Ok(version) + } + + /// Read the content of the `CryptoBlob` from the disk into the buffer. + /// + /// The given buffer must has a length that is no less than the size of + /// the plaintext content of this `CryptoBlob`. + /// + /// # Security + /// + /// This content, including its length, is guaranteed to be authentic. + pub fn read(&self, buf: &mut [u8]) -> Result { + let header = match *self.header.lock() { + Some(header) => header, + None => { + let mut header = Header::new_zeroed(); + self.block_set.read_slice(0, header.as_bytes_mut())?; + header + } + }; + if header.payload_len > self.capacity() { + return_errno_with_msg!(OutOfDisk, "payload_len is greater than the capacity"); + } + if header.payload_len > buf.len() { + return_errno_with_msg!(OutOfDisk, "read_buf is too small"); + } + let nblock = (Self::HEADER_NBYTES + header.payload_len).div_ceil(BLOCK_SIZE); + let mut block_buf = Buf::alloc(nblock)?; + self.block_set.read(0, block_buf.as_mut())?; + + // Decrypt payload. + let aead = Aead::new(); + let version = header.version; + let mut iv = Iv::new_zeroed(); + iv.as_bytes_mut()[..version.as_bytes().len()].copy_from_slice(version.as_bytes()); + let input = + &block_buf.as_slice()[Self::HEADER_NBYTES..Self::HEADER_NBYTES + header.payload_len]; + let output = &mut buf[..header.payload_len]; + aead.decrypt(input, &self.key, &iv, &[], &header.mac, output)?; + *self.header.lock() = Some(header); + Ok(header.payload_len) + } + + /// Returns the key associated with this `CryptoBlob`. + pub fn key(&self) -> &Key { + &self.key + } + + /// Returns the current version ID. + /// + /// # Security + /// + /// It is valid after a successful call to `create`, `read` or `write`. + /// User could also get a version ID from another valid `CryptoBlob`, + /// (usually a backup), through method `recover_from`. + pub fn version_id(&self) -> Option { + self.header.lock().map(|header| header.version) + } + + /// Recover from another `CryptoBlob`. + /// + /// If `CryptoBlob` doesn't have a valid version ID, e.g., payload decryption + /// failed when `read`, user could call this method to recover version ID and + /// payload from another `CryptoBlob` (usually a backup). + pub fn recover_from(&mut self, other: &CryptoBlob) -> Result<()> { + if self.capacity() != other.capacity() { + return_errno_with_msg!(InvalidArgs, "capacity not aligned, recover failed"); + } + if self.header.lock().is_some() { + return_errno_with_msg!(InvalidArgs, "no need to recover"); + } + let nblocks = self.block_set.nblocks(); + // Read version ID and payload from another `CryptoBlob`. + let mut read_buf = Buf::alloc(nblocks)?; + let payload_len = other.read(read_buf.as_mut_slice())?; + let version = other.version_id().unwrap(); + + // Encrypt payload. + let aead = Aead::new(); + let mut iv = Iv::new_zeroed(); + iv.as_bytes_mut()[..version.as_bytes().len()].copy_from_slice(version.as_bytes()); + let input = &read_buf.as_slice()[..payload_len]; + let mut write_buf = Buf::alloc(nblocks)?; + let output = + &mut write_buf.as_mut_slice()[Self::HEADER_NBYTES..Self::HEADER_NBYTES + payload_len]; + let mac = aead.encrypt(input, self.key(), &iv, &[], output)?; + + // Store header. + let header = Header { + version, + mac, + payload_len, + }; + write_buf.as_mut_slice()[..Self::HEADER_NBYTES].copy_from_slice(header.as_bytes()); + + // Write to `BlockSet`. + self.block_set.write(0, write_buf.as_ref())?; + *self.header.lock() = Some(header); + Ok(()) + } + + /// Returns the current MAC of encrypted payload. + /// + /// # Security + /// + /// It is valid after a successful call to `create`, `read` or `write`. + pub fn current_mac(&self) -> Option { + self.header.lock().map(|header| header.mac) + } + + /// Returns the capacity of this `CryptoBlob` in bytes. + pub fn capacity(&self) -> usize { + self.block_set.nblocks() * BLOCK_SIZE - Self::HEADER_NBYTES + } + + /// Returns the number of blocks occupied by the underlying `BlockSet`. + pub fn nblocks(&self) -> usize { + self.block_set.nblocks() + } +} + +#[cfg(test)] +mod tests { + use super::CryptoBlob; + use crate::layers::bio::{BlockSet, MemDisk, BLOCK_SIZE}; + + #[test] + fn create() { + let disk = MemDisk::create(2).unwrap(); + let init_data = [1u8; BLOCK_SIZE]; + let blob = CryptoBlob::create(disk, &init_data).unwrap(); + + println!("blob key: {:?}", blob.key()); + assert_eq!(blob.version_id(), Some(0)); + assert_eq!(blob.nblocks(), 2); + assert_eq!( + blob.capacity(), + 2 * BLOCK_SIZE - CryptoBlob::::HEADER_NBYTES + ); + } + + #[test] + fn open_and_read() { + let disk = MemDisk::create(4).unwrap(); + let key = { + let subset = disk.subset(0..2).unwrap(); + let init_data = [1u8; 1024]; + let blob = CryptoBlob::create(subset, &init_data).unwrap(); + blob.key + }; + + let subset = disk.subset(0..2).unwrap(); + let blob = CryptoBlob::open(key, subset); + assert_eq!(blob.version_id(), None); + assert_eq!(blob.nblocks(), 2); + let mut buf = [0u8; BLOCK_SIZE]; + let payload_len = blob.read(&mut buf).unwrap(); + assert_eq!(buf[..payload_len], [1u8; 1024]); + } + + #[test] + fn write() { + let disk = MemDisk::create(2).unwrap(); + let init_data = [0u8; BLOCK_SIZE]; + let mut blob = CryptoBlob::create(disk, &init_data).unwrap(); + + let write_buf = [1u8; 1024]; + blob.write(&write_buf).unwrap(); + let mut read_buf = [0u8; 1024]; + blob.read(&mut read_buf).unwrap(); + assert_eq!(read_buf, [1u8; 1024]); + assert_eq!(blob.version_id(), Some(1)); + } + + #[test] + fn recover_from() { + let disk = MemDisk::create(2).unwrap(); + let init_data = [1u8; 1024]; + let subset0 = disk.subset(0..1).unwrap(); + let mut blob0 = CryptoBlob::create(subset0, &init_data).unwrap(); + assert_eq!(blob0.version_id(), Some(0)); + blob0.write(&init_data).unwrap(); + assert_eq!(blob0.version_id(), Some(1)); + + let subset1 = disk.subset(1..2).unwrap(); + let mut blob1 = CryptoBlob::open(blob0.key, subset1); + assert_eq!(blob1.version_id(), None); + blob1.recover_from(&blob0).unwrap(); + let mut read_buf = [0u8; BLOCK_SIZE]; + let payload_len = blob1.read(&mut read_buf).unwrap(); + assert_eq!(read_buf[..payload_len], [1u8; 1024]); + assert_eq!(blob1.version_id(), Some(1)); + } +} diff --git a/kernel/comps/mlsdisk/src/layers/1-crypto/crypto_chain.rs b/kernel/comps/mlsdisk/src/layers/1-crypto/crypto_chain.rs new file mode 100644 index 000000000..eb3feb4df --- /dev/null +++ b/kernel/comps/mlsdisk/src/layers/1-crypto/crypto_chain.rs @@ -0,0 +1,401 @@ +// SPDX-License-Identifier: MPL-2.0 + +use core::ops::Range; + +use lending_iterator::prelude::*; +use ostd_pod::Pod; + +use super::{Iv, Key, Mac}; +use crate::{ + layers::bio::{BlockId, BlockLog, Buf, BLOCK_SIZE}, + os::Aead, + prelude::*, +}; + +/// A cryptographically-protected chain of blocks. +/// +/// `CryptoChain` allows writing and reading a sequence of +/// consecutive blocks securely to and from an untrusted storage of data log +/// `L: BlockLog`. +/// The target use case of `CryptoChain` is to implement secure journals, +/// where old data are scanned and new data are appended. +/// +/// # On-disk format +/// +/// The on-disk format of each block is shown below. +/// +/// ```text +/// ┌─────────────────────┬───────┬──────────┬──────────┬──────────┬─────────┐ +/// │ Encrypted payload │ Gap │ Length │ PreMac │ CurrMac │ IV │ +/// │(Length <= 4KB - 48B)│ │ (4B) │ (16B) │ (16B) │ (12B) │ +/// └─────────────────────┴───────┴──────────┴──────────┴──────────┴─────────┘ +/// +/// ◄─────────────────────────── Block size (4KB) ──────────────────────────► +/// ``` +/// +/// Each block begins with encrypted user payload. The size of payload +/// must be smaller than that of block size as each block ends with a footer +/// (in plaintext). +/// The footer consists of fours parts: the length of the payload (in bytes), +/// the MAC of the previous block, the MAC of the current block, the IV used +/// for encrypting the current block. +/// The MAC of a block protects the encrypted payload, its length, and the MAC +/// of the previous block. +/// +/// # Security +/// +/// Each `CryptoChain` is assigned a randomly-generated encryption key. +/// Each block is encrypted using this key and a randomly-generated IV. +/// This setup ensures the confidentiality of payload and even the same payloads +/// result in different ciphertexts. +/// +/// `CryptoChain` is called a "chain" of blocks because each block +/// not only stores its own MAC, but also the MAC of its previous block. +/// This effectively forms a "chain" (much like a blockchain), +/// ensuring the orderness and consecutiveness of the sequence of blocks. +/// +/// Due to this chain structure, the integrity of a `CryptoChain` can be ensured +/// by verifying the MAC of the last block. Once the integrity of the last block +/// is verified, the integrity of all previous blocks can also be verified. +pub struct CryptoChain { + block_log: L, + key: Key, + block_range: Range, + block_macs: Vec, +} + +#[repr(C)] +#[derive(Copy, Clone, Pod)] +struct Footer { + len: u32, + pre_mac: Mac, + this_mac: Mac, + this_iv: Iv, +} + +impl CryptoChain { + /// The available size in each chained block is smaller than that of + /// the block size. + pub const AVAIL_BLOCK_SIZE: usize = BLOCK_SIZE - core::mem::size_of::