Compare commits
885 Commits
Author | SHA1 | Date |
---|---|---|
Sinipelto | 46a31b8efa | |
Bananymous | 85a5e81224 | |
Bananymous | 7d4cdcd1fd | |
Sinipelto | d72db1f81c | |
Sinipelto | 6cfa56dcec | |
Sinipelto | f97922a2b5 | |
Sinipelto | 566724d986 | |
Sinipelto | a7b1810aa2 | |
Sinipelto | a6a5c00763 | |
Bananymous | f2397b775c | |
Bananymous | 8b81406b81 | |
Bananymous | e2515c1109 | |
Bananymous | 5293ae070d | |
Bananymous | 6e2443ca72 | |
Bananymous | a312d75bb2 | |
Bananymous | a554bd0fd8 | |
Bananymous | f0d2a211ea | |
Bananymous | 065eec430e | |
Bananymous | 5f4d81a502 | |
Bananymous | 41065d2f9a | |
Bananymous | 3daf3d53a3 | |
Bananymous | ec56e9c6f1 | |
Bananymous | 07ae1bbf34 | |
Bananymous | 03b80ed113 | |
Bananymous | 407a7b80c5 | |
Bananymous | 8b4f169d0f | |
Bananymous | 6f9b3ab5de | |
Bananymous | aa7a8124ce | |
Bananymous | a9412aa741 | |
Bananymous | 8aab3a62cc | |
Bananymous | b0b39c56ba | |
Bananymous | 055b1a2a1a | |
Bananymous | d99ef11e48 | |
Bananymous | 732eb9da41 | |
Bananymous | 8faad47843 | |
Bananymous | aa4f3046ff | |
Bananymous | b4775fbe75 | |
Bananymous | 8a5753b0fe | |
Bananymous | 1a75262b04 | |
Bananymous | 39801e51da | |
Bananymous | 6e3f176457 | |
Bananymous | 447da99f0b | |
Bananymous | a3a287f5ca | |
Bananymous | c47f6a78bc | |
Bananymous | 430a006acf | |
Bananymous | 845ed66e5e | |
Bananymous | 2191ca46bb | |
Bananymous | cec04a2858 | |
Bananymous | b87351f6d5 | |
Bananymous | 464737fbe9 | |
Bananymous | 8b4f661acb | |
Bananymous | 27963febc0 | |
Bananymous | 6d4b684219 | |
Bananymous | 670c787af3 | |
Bananymous | a0fbf18d3b | |
Bananymous | 1acc0abf2e | |
Bananymous | c20f773c5d | |
Bananymous | a46b2f43d9 | |
Bananymous | a20f8607de | |
Bananymous | af330f7b8e | |
Bananymous | e33b3bcdff | |
Bananymous | 181d139c7d | |
Bananymous | 639fd8804c | |
Bananymous | cbb2c37e00 | |
Bananymous | ab4f033385 | |
Bananymous | 1ed08f62d3 | |
Bananymous | 8164c15b6c | |
Bananymous | f9bf47ab30 | |
Bananymous | e5ffadb109 | |
Bananymous | 061d10e635 | |
Bananymous | 6d899aa6ce | |
Bananymous | 120f7329b1 | |
Bananymous | 4f25c20c97 | |
Bananymous | 5e396851f4 | |
Bananymous | a44482639d | |
Bananymous | 3bac19e518 | |
Bananymous | 4dbe15aa0e | |
Bananymous | 1c5985148c | |
Bananymous | ce2461d0e8 | |
Bananymous | 4e785a133c | |
Bananymous | 26c7aee327 | |
Bananymous | 0405461742 | |
Bananymous | 8a10853ba7 | |
Bananymous | 5d34cebeca | |
Bananymous | 3d899d2e44 | |
Bananymous | f72fdeeb59 | |
Bananymous | 382f9d9bb3 | |
Bananymous | bc1d1bf919 | |
Bananymous | f05b9a6877 | |
Bananymous | ea5ed3001e | |
Bananymous | f312c3a4d7 | |
Bananymous | 1af3ca19ab | |
Bananymous | 09fcc613c7 | |
Bananymous | 3940f53231 | |
Bananymous | 0757834176 | |
Bananymous | 3bffbe330d | |
Bananymous | 8d583c8b67 | |
Bananymous | 99bde9aa49 | |
Bananymous | 98d702ac60 | |
Bananymous | 1ec341e2dd | |
Bananymous | d09310f388 | |
Bananymous | 126edea119 | |
Bananymous | 74bfb930f2 | |
Bananymous | 091c5b6a66 | |
Bananymous | fda4a4ad24 | |
Bananymous | 8bb47aee02 | |
Bananymous | 1f794e4ac0 | |
Bananymous | e85f9ac6a1 | |
Bananymous | 6ee5576dcc | |
Bananymous | b890e2fc14 | |
Bananymous | 4f4b8ada8c | |
Bananymous | 9e4adc1264 | |
Bananymous | 7a54a088b4 | |
Bananymous | 15bb1804ef | |
Bananymous | e8890062d6 | |
Bananymous | 1e2c2fb973 | |
Bananymous | 988a4e1cd8 | |
Bananymous | adbbdf73c4 | |
Bananymous | e8d20bc653 | |
Bananymous | 00ee86920a | |
Bananymous | 51ad27ea3c | |
Bananymous | df69612bb1 | |
Bananymous | 5bfeb9f3ca | |
Bananymous | db5c24b2a5 | |
Bananymous | 781c950af6 | |
Bananymous | e2e5c31d54 | |
Bananymous | be3efb0b92 | |
Bananymous | 792bb2df1c | |
Bananymous | e01928d186 | |
Bananymous | 48980b56ab | |
Bananymous | b767317a7a | |
Bananymous | 6f8fce94a0 | |
Bananymous | 31aa157201 | |
Bananymous | 5977341610 | |
Bananymous | 76f17bd569 | |
Bananymous | 6b1b3d333c | |
Bananymous | cb65be3e33 | |
Bananymous | dafc016293 | |
Bananymous | c7b6fc950a | |
Bananymous | 45a6783c3d | |
Bananymous | 6b180da4e8 | |
Bananymous | cf4f5f64a5 | |
Bananymous | 5630f64175 | |
Bananymous | 1d61bccfc3 | |
Bananymous | f842a9255f | |
Bananymous | 72f3c378dd | |
Bananymous | 39be6ab099 | |
Bananymous | 773dcdd3a2 | |
Bananymous | f0820e6f24 | |
Bananymous | a2b5e71654 | |
Bananymous | d3e5c8e0aa | |
Bananymous | f4b901a646 | |
Bananymous | 790064d248 | |
Bananymous | ab8b77406d | |
Bananymous | 1b9e14a53b | |
Bananymous | d2cfc843e4 | |
Bananymous | 521513bed2 | |
Bananymous | 400db176d1 | |
Bananymous | 211cad03ff | |
Bananymous | 8a9816d6e0 | |
Bananymous | 03d2bf4002 | |
Bananymous | f071240b33 | |
Bananymous | 27364f64a6 | |
Bananymous | bcf62c5f2e | |
Bananymous | 4d6322ff9c | |
Bananymous | 2eef581737 | |
Bananymous | 7ce8e2d57b | |
Bananymous | e780eaa45f | |
Bananymous | 44cb0af64f | |
Bananymous | bb0989fdef | |
Bananymous | f0b6844feb | |
Bananymous | b712c70c75 | |
Bananymous | 797ca65c66 | |
Bananymous | 762b7a4276 | |
Bananymous | a511441f7e | |
Bananymous | cd61d710df | |
Bananymous | f88ad7efcd | |
Bananymous | 38320018dc | |
Bananymous | d883d212b1 | |
Bananymous | dedb2a2399 | |
Bananymous | 8604c55de8 | |
Bananymous | e949e8550c | |
Bananymous | eb5c6cf736 | |
Bananymous | 94ce2c97be | |
Bananymous | 3f164c6b82 | |
Bananymous | f953f3d3ff | |
Bananymous | 9fc75fe445 | |
Bananymous | 7a5bb6a56b | |
Bananymous | d54c6b7f6b | |
Bananymous | db5d6a7f80 | |
Bananymous | 4a92f44cf6 | |
Bananymous | 376b9f7272 | |
Bananymous | 7e9e4c47ae | |
Bananymous | 603fc200e6 | |
Bananymous | c11e84b248 | |
Bananymous | be13120554 | |
Bananymous | 9943edad5a | |
Bananymous | f4049be975 | |
Bananymous | 6cf7e01fe9 | |
Bananymous | b51d2f5295 | |
Bananymous | 49d941ad65 | |
Bananymous | a66c3bdae5 | |
Bananymous | 547eabb403 | |
Bananymous | 79851394b3 | |
Bananymous | fcdc922343 | |
Bananymous | 0b11d76576 | |
Bananymous | f7097398ca | |
Bananymous | 85b1252b9e | |
Bananymous | 1cd12b5f16 | |
Bananymous | c84b66d078 | |
Bananymous | 27adb9486b | |
Bananymous | 8d5369fafe | |
Bananymous | feafc57b63 | |
Bananymous | f9b347f9d9 | |
Bananymous | 6e1825d6b4 | |
Bananymous | ec2baeb276 | |
Bananymous | 6cb8bda6e1 | |
Bananymous | 05e57801e7 | |
Bananymous | b924c85669 | |
Bananymous | 09c1aa44d8 | |
Bananymous | 1d470fb5ba | |
Bananymous | b4e4f7a6cc | |
Bananymous | 55d30a7cc3 | |
Bananymous | b62186441b | |
Bananymous | 8caba1e774 | |
Bananymous | 7bdb428938 | |
Bananymous | 3ea707c0e7 | |
Bananymous | 18d582c6ce | |
Bananymous | 8b2bb95b81 | |
Bananymous | 2ef496a24a | |
Bananymous | c0a89e8951 | |
Bananymous | fc953df281 | |
Bananymous | fe2dca16f0 | |
Bananymous | f662aa6da2 | |
Bananymous | fee3677fb9 | |
Bananymous | 4818c6e3dd | |
Bananymous | 971eb737c1 | |
Bananymous | 9a3286ad57 | |
Bananymous | c9e09b840e | |
Bananymous | 8136248a67 | |
Bananymous | 0d67e46041 | |
Bananymous | bc1087f5a7 | |
Bananymous | 3a9c6fc51a | |
Bananymous | 7774f56ab6 | |
Bananymous | 14a608effd | |
Bananymous | 5fae3cec2a | |
Bananymous | b0c22b61ec | |
Bananymous | 82b049204d | |
Bananymous | aa59142bfa | |
Bananymous | c55bb77ff5 | |
Bananymous | 9b4e2e1e21 | |
Bananymous | 202c38a65a | |
Bananymous | 720bc418a6 | |
Bananymous | d77f455065 | |
Bananymous | 7e08f0fb66 | |
Bananymous | 9e4a87021c | |
Bananymous | 5887f6bcaa | |
Bananymous | 5d67559e33 | |
Bananymous | e631eb7a7a | |
Bananymous | 64ff4c232a | |
Bananymous | 0ec4f970f7 | |
Bananymous | afe95be42f | |
Bananymous | 14ac1c9904 | |
Bananymous | 7c11ea3694 | |
Bananymous | c1fd341698 | |
Bananymous | 0deab1be51 | |
Bananymous | 5a623adaa6 | |
Bananymous | 4363118d9d | |
Bananymous | d613da4b6c | |
Bananymous | f46f5b2050 | |
Bananymous | d9c4114b5f | |
Bananymous | ddd36af0f1 | |
Bananymous | 35fd30ee29 | |
Bananymous | 4a0652684c | |
Bananymous | 33c81f00b7 | |
Bananymous | 55714b90cd | |
Bananymous | 9b47603a1d | |
Bananymous | 2e2a913412 | |
Bananymous | 42b85dc33b | |
Bananymous | a15ffcb071 | |
Bananymous | 692b77fb8e | |
Bananymous | 044378cfa3 | |
Bananymous | f1d4d5f995 | |
Bananymous | 19d0fb6fcd | |
Bananymous | 7933265095 | |
Bananymous | d810644018 | |
Bananymous | a7bfc1c2ec | |
Bananymous | 104b2740bc | |
Bananymous | 65501837b7 | |
Bananymous | 3ed0a54847 | |
Bananymous | cbd2519b9a | |
Bananymous | e8a73f9696 | |
Bananymous | 1a0d114861 | |
Bananymous | 5c3497681e | |
Bananymous | b05cf9ef09 | |
Bananymous | a74eb357a1 | |
Bananymous | 8eb71084f0 | |
Bananymous | ef1077fd7b | |
Bananymous | f1ba5c7e0f | |
Bananymous | 97ea4986af | |
Bananymous | 25c021c15b | |
Bananymous | 2bf12a52d1 | |
Bananymous | 6ada36d3cb | |
Bananymous | 42b90ae76c | |
Bananymous | ccc61cb10c | |
Bananymous | be5b81740e | |
Bananymous | e7458ca10a | |
Bananymous | b10168eb1c | |
Bananymous | 30463c9082 | |
Bananymous | dc7391dc89 | |
Bananymous | eb98d70a0b | |
Bananymous | dcd8374b89 | |
Bananymous | 8e4216215e | |
Bananymous | 5bd7099b96 | |
Bananymous | 9a63d3b2da | |
Bananymous | bf02330db9 | |
Bananymous | 5806a6484f | |
Bananymous | 0fa5401800 | |
Bananymous | b30f4cbfb5 | |
Bananymous | ba37183c9c | |
Bananymous | 2f298a1979 | |
Bananymous | 8c282a5d83 | |
Bananymous | d34c0a5abe | |
Bananymous | 8f3348cf2b | |
Bananymous | 38c0bc7bae | |
Bananymous | 313b00b11f | |
Bananymous | 165a379c73 | |
Bananymous | a7f37236bf | |
Bananymous | 51532336b0 | |
Bananymous | 03d4b47f63 | |
Bananymous | 8b57edde6b | |
Bananymous | 778778fede | |
Bananymous | f7449c4ab9 | |
Bananymous | fd2bcc9156 | |
Bananymous | a5b1555725 | |
Bananymous | e74fdbc55b | |
Bananymous | 008c777a9f | |
Bananymous | d8a9d4a24e | |
Bananymous | bc0e1fa898 | |
Bananymous | 17f1737c9a | |
Bananymous | 868444f043 | |
Bananymous | fdae253695 | |
Bananymous | d4adcff958 | |
Bananymous | 2c59c9a3cc | |
Bananymous | 3a59a64355 | |
Bananymous | 9363c1cdaf | |
Bananymous | 198e6d7cf6 | |
Bananymous | 07ee898f4f | |
Bananymous | 6feb8a99d2 | |
Bananymous | e57c1fc9fc | |
Bananymous | a11b5ae41f | |
Bananymous | c67a7cec5b | |
Bananymous | 91f04ce250 | |
Bananymous | 926df2b276 | |
Bananymous | 9fe878bbec | |
Bananymous | 217dbca7b7 | |
Bananymous | 13852e865c | |
Bananymous | 679d47131d | |
Bananymous | 8b1bccb79b | |
Bananymous | e86e755c51 | |
Bananymous | 8ec6d4c9fc | |
Bananymous | 08cdf88586 | |
Bananymous | 6f7d97cf94 | |
Bananymous | 5e434f5131 | |
Bananymous | a152d0aac5 | |
Bananymous | 879706e6e9 | |
Bananymous | 00f1f30a08 | |
Bananymous | a5813f9ba5 | |
Bananymous | 5652af3384 | |
Bananymous | 22cd9af8cc | |
Bananymous | a9cf9bceef | |
Bananymous | 6c0f864a6e | |
Bananymous | e4509d9482 | |
Bananymous | 0f23e1f0f4 | |
Bananymous | 642a6aa4ad | |
Bananymous | 432c296b7b | |
Bananymous | b576d373c4 | |
Bananymous | 522aa8e762 | |
Bananymous | 146802fa4c | |
Bananymous | cc8af25d73 | |
Bananymous | f5f4bf58ad | |
Bananymous | 3784da0d18 | |
Bananymous | 9eb72f4392 | |
Bananymous | f7bf6d5e62 | |
Bananymous | adb14ba373 | |
Bananymous | 7391d91317 | |
Bananymous | 2149cec29f | |
Bananymous | ad756c36fc | |
Bananymous | b56316e9da | |
Bananymous | a989c44211 | |
Bananymous | 217e5f81cc | |
Bananymous | 5f2549b198 | |
Bananymous | dcd4d0daeb | |
Bananymous | faf4220b38 | |
Bananymous | 193ddaa2f6 | |
Bananymous | 46eb27883a | |
Bananymous | 2db7cdb71e | |
Bananymous | 5411c5aa4a | |
Bananymous | f8a1a10897 | |
Bananymous | adbe13938e | |
Bananymous | 4d5b14753d | |
Bananymous | ba9fa00947 | |
Bananymous | 98cedf155c | |
Bananymous | 88e3998664 | |
Bananymous | c0c0bbc1bf | |
Bananymous | 650e1b4fc5 | |
Bananymous | 6c1ada8d0a | |
Bananymous | 7d00c2670f | |
Bananymous | bca7e9a1e8 | |
Bananymous | 3748f0304f | |
Bananymous | 2576bdbd14 | |
Bananymous | e341a36287 | |
Bananymous | bba09a3cd0 | |
Bananymous | 985df3532b | |
Bananymous | 72041a52e8 | |
Bananymous | 891144dac1 | |
Bananymous | 41e7b53903 | |
Bananymous | 6b0920e8c0 | |
Bananymous | 4285729d5c | |
Bananymous | a9c10d0751 | |
Bananymous | 74c79c7eff | |
Bananymous | 9174a89971 | |
Bananymous | 5c94a583bc | |
Bananymous | 6e1fc2766f | |
Bananymous | d3bb00cb55 | |
Bananymous | 5a5656b2d3 | |
Bananymous | 1a1e584cba | |
Bananymous | 65fa05f998 | |
Bananymous | 2276fc95b8 | |
Bananymous | 1e173c178d | |
Bananymous | 773747cf9c | |
Bananymous | 4972284dde | |
Bananymous | 45789fda08 | |
Bananymous | 3b5bc63d1b | |
Bananymous | f1089e2b8a | |
Bananymous | 6d93c1eb92 | |
Bananymous | 363c325c79 | |
Bananymous | 583504ebe0 | |
Bananymous | b354b77f8b | |
Bananymous | 74af46cb4a | |
Bananymous | 19dab08275 | |
Bananymous | 3840fbf957 | |
Bananymous | 78c091f7f8 | |
Bananymous | 274ecbba78 | |
Bananymous | 683c2a68cd | |
Bananymous | ad98181069 | |
Bananymous | a549336530 | |
Bananymous | 4eb95c963d | |
Bananymous | 22caacd2a9 | |
Bananymous | af30d537da | |
Bananymous | f1bd26fb92 | |
Bananymous | 5c6bbcb62f | |
Bananymous | 21bd87bb07 | |
Bananymous | 79450df04c | |
Bananymous | 7f8b7b811e | |
Bananymous | 3c068aa0ae | |
Bananymous | 86df258365 | |
Bananymous | d99e704728 | |
Bananymous | 0d620f3e0f | |
Bananymous | 4dce0f9074 | |
Bananymous | 54f89cba33 | |
Bananymous | de88f60d1a | |
Bananymous | f7060970e6 | |
Bananymous | e7a98ac6cc | |
Bananymous | 10544db52e | |
Bananymous | 5e123031aa | |
Bananymous | 388f530edd | |
Bananymous | d354cccd37 | |
Bananymous | 714305ef56 | |
Bananymous | f83ae1e9c6 | |
Bananymous | c38e8de6b5 | |
Bananymous | 97638f7ade | |
Bananymous | 326a30d1af | |
Bananymous | 32e1473c94 | |
Bananymous | bf617036c7 | |
Bananymous | ce55422a24 | |
Bananymous | 388cc7c3bb | |
Bananymous | 37f9404d93 | |
Bananymous | 38dff41e25 | |
Bananymous | d360340b9e | |
Bananymous | 0f63cfa43f | |
Bananymous | 537780ee1e | |
Bananymous | 4ca99fcb4e | |
Bananymous | eb7ee13f43 | |
Bananymous | b2de706693 | |
Bananymous | 6a8180470d | |
Bananymous | 12d56be5cc | |
Bananymous | bb4d81a4fa | |
Bananymous | b254ade69b | |
Bananymous | ef4ebaa969 | |
Bananymous | 99f8133b91 | |
Bananymous | 51eb44bf40 | |
Bananymous | a0be415e09 | |
Bananymous | 071da18fa3 | |
Bananymous | c62e820bcf | |
Bananymous | 46c34db6cb | |
Bananymous | 25a2a4879c | |
Bananymous | 8be28012ee | |
Bananymous | 5aed186827 | |
Bananymous | 91f812e17f | |
Bananymous | f0b22c48b2 | |
Bananymous | 52c4eebd77 | |
Bananymous | 24f0d26fce | |
Bananymous | 825ec221b7 | |
Bananymous | e31080bce3 | |
Bananymous | 7a5d5cabad | |
Bananymous | f7de310889 | |
Bananymous | e209ca7c82 | |
Bananymous | ee8de77a90 | |
Bananymous | db49cbd6e2 | |
Bananymous | e001eecb7b | |
Bananymous | 7f34d00c95 | |
Bananymous | 2c18adbddd | |
Bananymous | 97c7fc42d1 | |
Bananymous | 7da0627f8e | |
Bananymous | 27cef23823 | |
Bananymous | b7fc2dc3d0 | |
Bananymous | 8af390e0f6 | |
Bananymous | 96d6453ea8 | |
Bananymous | 2b9900e56e | |
Bananymous | 86f58f60cb | |
Bananymous | 064ce568c2 | |
Bananymous | 6aff459e1c | |
Bananymous | 0b1b4d8f7e | |
Bananymous | 3fc2c3529a | |
Bananymous | b0e9ab0519 | |
Bananymous | 668517a723 | |
Bananymous | 649f08ec78 | |
Bananymous | 2f2c298c68 | |
Bananymous | 90e48970e6 | |
Bananymous | 480842a203 | |
Bananymous | 5425394880 | |
Bananymous | a365813fa9 | |
Bananymous | 9d64dbd5c2 | |
Bananymous | 30bb61a775 | |
Bananymous | 1f36ed0cf9 | |
Bananymous | d54c76f88a | |
Bananymous | cbb9f47ee5 | |
Bananymous | b68d5a5833 | |
Bananymous | 94d2090777 | |
Bananymous | e97585daf9 | |
Bananymous | 924fc2118c | |
Bananymous | 51f4c0c750 | |
Bananymous | 37b93da650 | |
Bananymous | 35e739dcdd | |
Bananymous | 8352392b38 | |
Bananymous | 413f05bfca | |
Bananymous | dc1aff58ed | |
Bananymous | 9f75d9cfe5 | |
Bananymous | a42af7e973 | |
Bananymous | 2ce244d303 | |
Bananymous | a775a920d0 | |
Bananymous | 4f84faf392 | |
Bananymous | a4cb5d8360 | |
Bananymous | da7f09cf82 | |
Bananymous | 0166af472b | |
Bananymous | 884d986bd6 | |
Bananymous | 59b807189f | |
Bananymous | fb1c7015b1 | |
Bananymous | d4123f62b2 | |
Bananymous | a3f410d1a1 | |
Bananymous | 1d19a4bffe | |
Bananymous | 271dd91292 | |
Bananymous | 9bd4d68f9c | |
Bananymous | 3c3c7826ef | |
Bananymous | 2207357b93 | |
Bananymous | 3a69768eb0 | |
Bananymous | afb29ff3ec | |
Bananymous | e6f0f891a6 | |
Bananymous | 36e5aa4683 | |
Bananymous | 7738050105 | |
Bananymous | 4bf11ec349 | |
Bananymous | d821012eed | |
Bananymous | 35c6edd989 | |
Bananymous | 633cb4f282 | |
Bananymous | 4d4d0e26a9 | |
Bananymous | feea2d4024 | |
Bananymous | 0ffd2a5c1d | |
Bananymous | 232fdcb82c | |
Bananymous | 0ccc23d544 | |
Bananymous | 789ca3db1a | |
Bananymous | cb359a05dc | |
Bananymous | 14982c137a | |
Bananymous | 0acab11620 | |
Bananymous | 02f0239016 | |
Bananymous | ab61b49aca | |
Bananymous | 4da1d6fd27 | |
Bananymous | 909e847369 | |
Bananymous | eafa09fecf | |
Bananymous | 8175348284 | |
Bananymous | b2832cb47a | |
Bananymous | 9f499991c8 | |
Bananymous | 9a416e8ae8 | |
Bananymous | 911922c6a3 | |
Bananymous | 1f2fd59ad5 | |
Bananymous | 708d401d2c | |
Bananymous | ed0dcacab3 | |
Bananymous | e86050f343 | |
Bananymous | 57f7da6ce1 | |
Bananymous | 93e6455171 | |
Bananymous | 8f38780197 | |
Bananymous | 341f7e41e5 | |
Bananymous | 265fe9c62e | |
Bananymous | 3b9d60d7cb | |
Bananymous | 278b873e89 | |
Bananymous | e640344d7a | |
Bananymous | 7151bb86a8 | |
Bananymous | 2a34391b71 | |
Bananymous | 3d95cf02f3 | |
Bananymous | dd3f34cb2c | |
Bananymous | 0c316ebfb2 | |
Bananymous | 282bf24f65 | |
Bananymous | f964f6be8d | |
Bananymous | 0202ccec5f | |
Bananymous | 636c308993 | |
Bananymous | 6fdbe6f9c2 | |
Bananymous | c19f4c019a | |
Bananymous | 83eb3dc0cb | |
Bananymous | 481c8406f3 | |
Bananymous | 0129619d9a | |
Bananymous | e0479b291d | |
Bananymous | b847d7dfd5 | |
Bananymous | 245dff8027 | |
Bananymous | fed690a7f2 | |
Bananymous | 54d981120d | |
Bananymous | f79250c4d4 | |
Bananymous | 78b62776d2 | |
Bananymous | bda4614783 | |
Bananymous | 0ab3332ad3 | |
Bananymous | 9e0abbc2f0 | |
Bananymous | 496adb61a4 | |
Bananymous | 4a4a3bf184 | |
Bananymous | f33e78882e | |
Bananymous | 0ff067bdb7 | |
Bananymous | 31ac3260ed | |
Bananymous | d82c6c2337 | |
Bananymous | 632b699475 | |
Bananymous | 85039020d3 | |
Bananymous | 1a0fdc5a44 | |
Bananymous | fb1bab7c30 | |
Bananymous | 7eb43990ad | |
Bananymous | 53f4b5a9da | |
Bananymous | 1d4a6c3a42 | |
Bananymous | 40083e4aa1 | |
Bananymous | bd929bff07 | |
Bananymous | cd4a0530fa | |
Bananymous | 273fdd2235 | |
Bananymous | b20f2e8d31 | |
Bananymous | e756cde2b1 | |
Bananymous | de18d3e64d | |
Bananymous | 441999ba9f | |
Bananymous | dd046b1ace | |
Bananymous | 926aa238ab | |
Bananymous | 01fa521a03 | |
Bananymous | f31da19266 | |
Bananymous | 48edc38817 | |
Bananymous | ac12132ac0 | |
Bananymous | 13fabcc1f1 | |
Bananymous | 67005a80be | |
Bananymous | f43bfcb398 | |
Bananymous | d5ce4c9d2c | |
Bananymous | 1cf7ef3de6 | |
Bananymous | 5248a3fe48 | |
Bananymous | 812e61ca70 | |
Bananymous | 2d0a5a9e15 | |
Bananymous | f32d594879 | |
Bananymous | c2ad76fe4f | |
Bananymous | 10d9b72da1 | |
Bananymous | 2fe9af7165 | |
Bananymous | 0deda83d05 | |
Bananymous | ff5bcd4416 | |
Bananymous | b65cd1d09b | |
Bananymous | bc35a561d3 | |
Bananymous | 06bc807e34 | |
Bananymous | 6262e41de1 | |
Bananymous | 0cb53efa01 | |
Bananymous | 4e859bedbc | |
Bananymous | f139fc2229 | |
Bananymous | e48acbb03b | |
Bananymous | d1155c968e | |
Bananymous | 88a2c60065 | |
Bananymous | 5bfcf6783e | |
Bananymous | 94f8a657f1 | |
Bananymous | 7fac2a7526 | |
Bananymous | 46dcf98fc1 | |
Bananymous | 58ce907327 | |
Bananymous | 6ecc8cac0e | |
Bananymous | bd95f17426 | |
Bananymous | 0718bea5a1 | |
Bananymous | 175f07cd2f | |
Bananymous | 7b19d6e479 | |
Bananymous | 77c83e5552 | |
Bananymous | b15deb420f | |
Bananymous | b38989d594 | |
Bananymous | 79e6de325f | |
Bananymous | 163d2e4ba8 | |
Bananymous | 4f8f3ddc29 | |
Bananymous | 82a1a29260 | |
Bananymous | 8a5608df91 | |
Bananymous | 3f1c0ec91b | |
Bananymous | 1406a75a92 | |
Bananymous | 8001493df3 | |
Bananymous | 8c1f5bfe1e | |
Bananymous | ec8b9640e2 | |
Bananymous | 4ae1332a43 | |
Bananymous | 10c884bba4 | |
Bananymous | c15f031c3f | |
Bananymous | 1b4c744974 | |
Bananymous | d9068eebb5 | |
Bananymous | 3ad0d2328d | |
Bananymous | 3f2beb4547 | |
Bananymous | be14a6c239 | |
Bananymous | 3aa0eeb4a3 | |
Bananymous | b3eeb6412f | |
Bananymous | d38470c8e2 | |
Bananymous | a159c980ee | |
Bananymous | a993d997ad | |
Bananymous | 4475e3e184 | |
Bananymous | cf0320e47d | |
Bananymous | cd03a95128 | |
Bananymous | 51e299c7e3 | |
Bananymous | 6f65453fd4 | |
Bananymous | 67e0c21e0f | |
Bananymous | 702016a6e3 | |
Bananymous | d74ce4950c | |
Bananymous | 59a682c720 | |
Bananymous | 7bd4593748 | |
Bananymous | c5b006bf19 | |
Bananymous | 115c44630d | |
Bananymous | 1dc81abca4 | |
Bananymous | 5aaf2128a8 | |
Bananymous | 6aeac17072 | |
Bananymous | 6d425182a2 | |
Bananymous | 04ac23b67c | |
Bananymous | 5494e2c125 | |
Bananymous | aba82564f5 | |
Bananymous | 93abee9c7c | |
Bananymous | 4034bef42e | |
Bananymous | 821d065eba | |
Bananymous | 2614437ba0 | |
Bananymous | 1aac3a0425 | |
Bananymous | a4568f9263 | |
Bananymous | a180e72b6f | |
Bananymous | 2de64b592d | |
Bananymous | 9c0f3dd996 | |
Bananymous | 079df39ca8 | |
Bananymous | 60a99d1d23 | |
Bananymous | fe87c08a02 | |
Bananymous | 8637959289 | |
Bananymous | 6be53668b9 | |
Bananymous | d1b7249803 | |
Bananymous | ff7c50c627 | |
Bananymous | 12779cdef8 | |
Bananymous | f5e676b2b7 | |
Bananymous | 8e5e5f819f | |
Bananymous | 370a958379 | |
Bananymous | 0ee7da92a3 | |
Bananymous | a0bd3dc54f | |
Bananymous | 809eb2fe3e | |
Bananymous | 7010d8614f | |
Bananymous | 69f13f1896 | |
Bananymous | bdaf7cddcb | |
Bananymous | 8d6db168d6 | |
Bananymous | 2fabe1949c | |
Bananymous | c660df14ec | |
Bananymous | e704968f96 | |
Bananymous | 32359df939 | |
Bananymous | 641ed23380 | |
Bananymous | 9f977488fa | |
Bananymous | ac0b22f9b9 | |
Bananymous | 7752b02fb7 | |
Bananymous | 7610670287 | |
Bananymous | 31a1b23fb7 | |
Bananymous | 91c8f9a596 | |
Bananymous | f70cd3ea77 | |
Bananymous | 5db5ff069a | |
Bananymous | b8d852ddb7 | |
Bananymous | 46eedbd1a4 | |
Bananymous | e760bafeeb | |
Bananymous | 12351d5cb6 | |
Bananymous | e84f613c4d | |
Bananymous | 5db4e5b4d5 | |
Bananymous | b00dd8d68d | |
Bananymous | abbbf7ec15 | |
Bananymous | 22c72d8c70 | |
Bananymous | d0b1457f30 | |
Bananymous | a423cd8bb3 | |
Bananymous | db076058b9 | |
Bananymous | fe10ea85db | |
Bananymous | a1100624bf | |
Bananymous | 28e1497f88 | |
Bananymous | 8d6111641e | |
Bananymous | 3ee20d1a84 | |
Bananymous | 002c2d0aca | |
Bananymous | de9f109f2a | |
Bananymous | 461a5774f8 | |
Bananymous | 914f718767 | |
Bananymous | ebfd092075 | |
Bananymous | e322826347 | |
Bananymous | 3998c5f955 | |
Bananymous | 762d22ed28 | |
Bananymous | f2362b2b78 | |
Bananymous | 471ac80420 | |
Bananymous | 4a887fc706 | |
Bananymous | e49d3c7bfe | |
Bananymous | c5b83074ac | |
Bananymous | 79090c2648 | |
Bananymous | 7a6b1c8e47 | |
Bananymous | 8988ce2766 | |
Bananymous | dcde2ae6b4 | |
Bananymous | c62849a783 | |
Bananymous | f453e8e170 | |
Bananymous | 990887891e | |
Bananymous | 5da801d12b | |
Bananymous | 3a4557d417 | |
Bananymous | 26d9a3e253 | |
Bananymous | eef3631a5a | |
Bananymous | 88ee35165f | |
Bananymous | c8f05b4a7a | |
Bananymous | c32584cca0 | |
Bananymous | 2995a36942 | |
Bananymous | c1dbafc101 | |
Bananymous | 3e8ab8271d | |
Bananymous | 5b3a00c64f | |
Bananymous | 0ce9fd8597 | |
Bananymous | c9badb5a1c | |
Bananymous | a513bc5749 | |
Bananymous | 5d5487315f | |
Bananymous | 3508df67b1 | |
Bananymous | 06ce1f0667 | |
Bananymous | f9c3ae7090 | |
Bananymous | 1fb8c211f0 | |
Bananymous | 9c7670847e | |
Bananymous | a24c2d9be2 | |
Bananymous | f4db246658 | |
Bananymous | 7f90079ea7 | |
Bananymous | f4b4987d43 | |
Bananymous | 7f88ba70d4 | |
Bananymous | ac094a48d6 | |
Bananymous | 779912d8af | |
Bananymous | f205b8e883 | |
Bananymous | f9a0412e78 | |
Bananymous | 0ef318633c | |
Bananymous | 2f8c9746e3 | |
Bananymous | 6d6bef1b04 | |
Bananymous | 3dab392296 | |
Bananymous | f8a2c60c8d | |
Bananymous | 770f7716a0 | |
Bananymous | a011c0384f | |
Bananymous | 0d356c5bbc | |
Bananymous | d67de70126 | |
Bananymous | 6f334756c5 | |
Bananymous | 310713d203 | |
Bananymous | 7d2ab53baa | |
Bananymous | 2152b8b95f | |
Bananymous | 8ac1ae1574 | |
Bananymous | 4fd21bc303 | |
Bananymous | 15037bfc7a | |
Bananymous | 5831c72aad | |
Bananymous | a063d041c9 | |
Bananymous | 3572e9794a | |
Bananymous | cef6999dc7 | |
Bananymous | 6ed9651176 | |
Bananymous | 3efbe22a1b | |
Bananymous | 96579b88cf | |
Bananymous | 2ec18855f2 | |
Bananymous | b222581d18 | |
Bananymous | a8e3ee6f19 | |
Bananymous | a083e588ba | |
Bananymous | 9b500842a0 | |
Bananymous | b21348379f | |
Bananymous | 633055293e | |
Bananymous | ae9d618803 | |
Bananymous | 9c744dfc44 | |
Bananymous | faf1b661bb | |
Bananymous | 22e45278a2 | |
Bananymous | 43f4657566 | |
Bananymous | 70f2908056 | |
Bananymous | ef381d0600 | |
Bananymous | cfa87526a7 | |
Bananymous | 39b560fde3 | |
Bananymous | 0c582b4490 | |
Bananymous | 61caf566fc | |
Bananymous | 76d5364a55 | |
Bananymous | 5224df321e |
13
.clangd
13
.clangd
|
@ -1,13 +0,0 @@
|
||||||
Diagnostics:
|
|
||||||
Suppress: target_unsupported_type
|
|
||||||
|
|
||||||
CompileFlags:
|
|
||||||
Remove: [
|
|
||||||
-fstrict-volatile-bitfields,
|
|
||||||
-fno-tree-loop-distribute-patterns
|
|
||||||
]
|
|
||||||
Add: [
|
|
||||||
-D__banan_os__,
|
|
||||||
-D__arch__=x86_64,
|
|
||||||
-D__x86_64__
|
|
||||||
]
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
[submodule "kernel/lai"]
|
||||||
|
path = kernel/lai
|
||||||
|
url = https://github.com/managarm/lai.git
|
||||||
|
ignore = untracked
|
|
@ -1,8 +0,0 @@
|
||||||
# .pre-commit-config.yaml
|
|
||||||
exclude: '.patch$'
|
|
||||||
repos:
|
|
||||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
|
||||||
rev: v4.1.0 # this is optional, use `pre-commit autoupdate` to get the latest rev!
|
|
||||||
hooks:
|
|
||||||
- id: end-of-file-fixer
|
|
||||||
- id: trailing-whitespace
|
|
|
@ -1,38 +0,0 @@
|
||||||
{
|
|
||||||
"configurations": [
|
|
||||||
{
|
|
||||||
"name": "banan-os",
|
|
||||||
"includePath": [
|
|
||||||
"${workspaceFolder}/BAN/include",
|
|
||||||
"${workspaceFolder}/kernel/include",
|
|
||||||
"${workspaceFolder}/userspace/libraries/*/include"
|
|
||||||
],
|
|
||||||
"defines": [
|
|
||||||
"__arch=x86_64",
|
|
||||||
"__enable_sse=1"
|
|
||||||
],
|
|
||||||
"compilerPath": "${workspaceFolder}/toolchain/local/bin/x86_64-banan_os-gcc",
|
|
||||||
"cStandard": "c17",
|
|
||||||
"cppStandard": "gnu++20",
|
|
||||||
"intelliSenseMode": "linux-gcc-x64"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "banan-os-kernel",
|
|
||||||
"includePath": [
|
|
||||||
"${workspaceFolder}/BAN/include",
|
|
||||||
"${workspaceFolder}/kernel/include",
|
|
||||||
"${workspaceFolder}/userspace/libraries/*/include"
|
|
||||||
],
|
|
||||||
"defines": [
|
|
||||||
"__arch=x86_64",
|
|
||||||
"__is_kernel",
|
|
||||||
"__enable_sse=1"
|
|
||||||
],
|
|
||||||
"compilerPath": "${workspaceFolder}/toolchain/local/bin/x86_64-banan_os-gcc",
|
|
||||||
"cStandard": "c17",
|
|
||||||
"cppStandard": "gnu++20",
|
|
||||||
"intelliSenseMode": "linux-gcc-x64"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"version": 4
|
|
||||||
}
|
|
|
@ -1,10 +0,0 @@
|
||||||
{
|
|
||||||
"cmake.configureOnOpen": false,
|
|
||||||
"editor.tabSize": 4,
|
|
||||||
"editor.insertSpaces": false,
|
|
||||||
"editor.detectIndentation": false,
|
|
||||||
"clangd.arguments": [
|
|
||||||
"--compile-commands-dir=${workspaceFolder}/build",
|
|
||||||
"-header-insertion=never"
|
|
||||||
]
|
|
||||||
}
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
*.a
|
||||||
|
*.d
|
||||||
|
*.o
|
|
@ -1,22 +0,0 @@
|
||||||
#include <BAN/Assert.h>
|
|
||||||
|
|
||||||
#if __is_kernel
|
|
||||||
|
|
||||||
#include <kernel/Panic.h>
|
|
||||||
|
|
||||||
[[noreturn]] void __ban_assertion_failed(const char* location, const char* msg)
|
|
||||||
{
|
|
||||||
Kernel::panic_impl(location, msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
#include <BAN/Debug.h>
|
|
||||||
|
|
||||||
[[noreturn]] void __ban_assertion_failed(const char* location, const char* msg)
|
|
||||||
{
|
|
||||||
derrorln("{}: {}", location, msg);
|
|
||||||
__builtin_trap();
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -0,0 +1,269 @@
|
||||||
|
#include <BAN/String.h>
|
||||||
|
#include <BAN/New.h>
|
||||||
|
|
||||||
|
namespace BAN
|
||||||
|
{
|
||||||
|
|
||||||
|
String::String()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
String::String(const String& other)
|
||||||
|
{
|
||||||
|
*this = other;
|
||||||
|
}
|
||||||
|
|
||||||
|
String::String(String&& other)
|
||||||
|
{
|
||||||
|
*this = move(other);
|
||||||
|
}
|
||||||
|
|
||||||
|
String::String(StringView other)
|
||||||
|
{
|
||||||
|
*this = other;
|
||||||
|
}
|
||||||
|
|
||||||
|
String::~String()
|
||||||
|
{
|
||||||
|
clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
String& String::operator=(const String& other)
|
||||||
|
{
|
||||||
|
clear();
|
||||||
|
MUST(ensure_capacity(other.size()));
|
||||||
|
memcpy(data(), other.data(), other.size() + 1);
|
||||||
|
m_size = other.size();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
String& String::operator=(String&& other)
|
||||||
|
{
|
||||||
|
clear();
|
||||||
|
|
||||||
|
if (other.has_sso())
|
||||||
|
memcpy(data(), other.data(), other.size() + 1);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_storage.general_storage = other.m_storage.general_storage;
|
||||||
|
m_has_sso = false;
|
||||||
|
}
|
||||||
|
m_size = other.m_size;
|
||||||
|
|
||||||
|
other.m_size = 0;
|
||||||
|
other.m_storage.sso_storage = SSOStorage();
|
||||||
|
other.m_has_sso = true;
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
String& String::operator=(StringView other)
|
||||||
|
{
|
||||||
|
clear();
|
||||||
|
MUST(ensure_capacity(other.size()));
|
||||||
|
memcpy(data(), other.data(), other.size());
|
||||||
|
m_size = other.size();
|
||||||
|
data()[m_size] = '\0';
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
ErrorOr<void> String::push_back(char c)
|
||||||
|
{
|
||||||
|
TRY(ensure_capacity(m_size + 1));
|
||||||
|
data()[m_size] = c;
|
||||||
|
m_size++;
|
||||||
|
data()[m_size] = '\0';
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
ErrorOr<void> String::insert(char c, size_type index)
|
||||||
|
{
|
||||||
|
ASSERT(index <= m_size);
|
||||||
|
TRY(ensure_capacity(m_size + 1));
|
||||||
|
memmove(data() + index + 1, data() + index, m_size - index);
|
||||||
|
data()[index] = c;
|
||||||
|
m_size++;
|
||||||
|
data()[m_size] = '\0';
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
ErrorOr<void> String::insert(StringView str, size_type index)
|
||||||
|
{
|
||||||
|
ASSERT(index <= m_size);
|
||||||
|
TRY(ensure_capacity(m_size + str.size()));
|
||||||
|
memmove(data() + index + str.size(), data() + index, m_size - index);
|
||||||
|
memcpy(data() + index, str.data(), str.size());
|
||||||
|
m_size += str.size();
|
||||||
|
data()[m_size] = '\0';
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
ErrorOr<void> String::append(StringView str)
|
||||||
|
{
|
||||||
|
TRY(ensure_capacity(m_size + str.size()));
|
||||||
|
memcpy(data() + m_size, str.data(), str.size());
|
||||||
|
m_size += str.size();
|
||||||
|
data()[m_size] = '\0';
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
void String::pop_back()
|
||||||
|
{
|
||||||
|
ASSERT(m_size > 0);
|
||||||
|
m_size--;
|
||||||
|
data()[m_size] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
void String::remove(size_type index)
|
||||||
|
{
|
||||||
|
ASSERT(index < m_size);
|
||||||
|
memcpy(data() + index, data() + index + 1, m_size - index);
|
||||||
|
m_size--;
|
||||||
|
data()[m_size] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
void String::clear()
|
||||||
|
{
|
||||||
|
if (!has_sso())
|
||||||
|
{
|
||||||
|
deallocator(m_storage.general_storage.data);
|
||||||
|
m_storage.sso_storage = SSOStorage();
|
||||||
|
m_has_sso = true;
|
||||||
|
}
|
||||||
|
m_size = 0;
|
||||||
|
data()[m_size] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
bool String::operator==(StringView str) const
|
||||||
|
{
|
||||||
|
if (size() != str.size())
|
||||||
|
return false;
|
||||||
|
for (size_type i = 0; i < m_size; i++)
|
||||||
|
if (data()[i] != str.data()[i])
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool String::operator==(const char* cstr) const
|
||||||
|
{
|
||||||
|
for (size_type i = 0; i < m_size; i++)
|
||||||
|
if (data()[i] != cstr[i])
|
||||||
|
return false;
|
||||||
|
if (cstr[size()] != '\0')
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
ErrorOr<void> String::resize(size_type new_size, char init_c)
|
||||||
|
{
|
||||||
|
if (m_size == new_size)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
// expanding
|
||||||
|
if (m_size < new_size)
|
||||||
|
{
|
||||||
|
TRY(ensure_capacity(new_size));
|
||||||
|
memset(data() + m_size, init_c, new_size - m_size);
|
||||||
|
m_size = new_size;
|
||||||
|
data()[m_size] = '\0';
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
m_size = new_size;
|
||||||
|
data()[m_size] = '\0';
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
ErrorOr<void> String::reserve(size_type new_size)
|
||||||
|
{
|
||||||
|
TRY(ensure_capacity(new_size));
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
ErrorOr<void> String::shrink_to_fit()
|
||||||
|
{
|
||||||
|
if (has_sso())
|
||||||
|
return {};
|
||||||
|
|
||||||
|
if (fits_in_sso())
|
||||||
|
{
|
||||||
|
char* data = m_storage.general_storage.data;
|
||||||
|
m_storage.sso_storage = SSOStorage();
|
||||||
|
m_has_sso = true;
|
||||||
|
memcpy(this->data(), data, m_size + 1);
|
||||||
|
deallocator(data);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
GeneralStorage& storage = m_storage.general_storage;
|
||||||
|
if (storage.capacity == m_size)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
char* new_data = (char*)allocator(m_size + 1);
|
||||||
|
if (new_data == nullptr)
|
||||||
|
return Error::from_errno(ENOMEM);
|
||||||
|
|
||||||
|
memcpy(new_data, storage.data, m_size);
|
||||||
|
deallocator(storage.data);
|
||||||
|
|
||||||
|
storage.capacity = m_size;
|
||||||
|
storage.data = new_data;
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
String::size_type String::capacity() const
|
||||||
|
{
|
||||||
|
if (has_sso())
|
||||||
|
return sso_capacity;
|
||||||
|
return m_storage.general_storage.capacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* String::data()
|
||||||
|
{
|
||||||
|
if (has_sso())
|
||||||
|
return m_storage.sso_storage.data;
|
||||||
|
return m_storage.general_storage.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* String::data() const
|
||||||
|
{
|
||||||
|
if (has_sso())
|
||||||
|
return m_storage.sso_storage.data;
|
||||||
|
return m_storage.general_storage.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
ErrorOr<void> String::ensure_capacity(size_type new_size)
|
||||||
|
{
|
||||||
|
if (m_size >= new_size)
|
||||||
|
return {};
|
||||||
|
if (has_sso() && fits_in_sso(new_size))
|
||||||
|
return {};
|
||||||
|
|
||||||
|
char* new_data = (char*)allocator(new_size + 1);
|
||||||
|
if (new_data == nullptr)
|
||||||
|
return Error::from_errno(ENOMEM);
|
||||||
|
|
||||||
|
memcpy(new_data, data(), m_size + 1);
|
||||||
|
|
||||||
|
if (has_sso())
|
||||||
|
{
|
||||||
|
m_storage.general_storage = GeneralStorage();
|
||||||
|
m_has_sso = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
deallocator(m_storage.general_storage.data);
|
||||||
|
|
||||||
|
auto& storage = m_storage.general_storage;
|
||||||
|
storage.capacity = new_size;
|
||||||
|
storage.data = new_data;
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
bool String::has_sso() const
|
||||||
|
{
|
||||||
|
return m_has_sso;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,11 +1,180 @@
|
||||||
#include <BAN/String.h>
|
#include <BAN/String.h>
|
||||||
#include <BAN/StringView.h>
|
#include <BAN/StringView.h>
|
||||||
|
#include <BAN/Vector.h>
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
namespace BAN
|
namespace BAN
|
||||||
{
|
{
|
||||||
|
|
||||||
|
StringView::StringView()
|
||||||
|
{ }
|
||||||
|
|
||||||
StringView::StringView(const String& other)
|
StringView::StringView(const String& other)
|
||||||
: StringView(other.data(), other.size())
|
: StringView(other.data(), other.size())
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
}
|
StringView::StringView(const char* string, size_type len)
|
||||||
|
{
|
||||||
|
if (len == size_type(-1))
|
||||||
|
len = strlen(string);
|
||||||
|
m_data = string;
|
||||||
|
m_size = len;
|
||||||
|
}
|
||||||
|
|
||||||
|
char StringView::operator[](size_type index) const
|
||||||
|
{
|
||||||
|
ASSERT(index < m_size);
|
||||||
|
return m_data[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
bool StringView::operator==(const String& other) const
|
||||||
|
{
|
||||||
|
if (m_size != other.size())
|
||||||
|
return false;
|
||||||
|
return memcmp(m_data, other.data(), m_size) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool StringView::operator==(StringView other) const
|
||||||
|
{
|
||||||
|
if (m_size != other.m_size)
|
||||||
|
return false;
|
||||||
|
return memcmp(m_data, other.m_data, m_size) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool StringView::operator==(const char* other) const
|
||||||
|
{
|
||||||
|
if (memcmp(m_data, other, m_size))
|
||||||
|
return false;
|
||||||
|
return other[m_size] == '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
StringView StringView::substring(size_type index, size_type len) const
|
||||||
|
{
|
||||||
|
ASSERT(index <= m_size);
|
||||||
|
if (len == size_type(-1))
|
||||||
|
len = m_size - index;
|
||||||
|
ASSERT(len <= m_size - index); // weird order to avoid overflow
|
||||||
|
StringView result;
|
||||||
|
result.m_data = m_data + index;
|
||||||
|
result.m_size = len;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
ErrorOr<Vector<StringView>> StringView::split(char delim, bool allow_empties)
|
||||||
|
{
|
||||||
|
size_type count = 0;
|
||||||
|
{
|
||||||
|
size_type start = 0;
|
||||||
|
for (size_type i = 0; i < m_size; i++)
|
||||||
|
{
|
||||||
|
if (m_data[i] == delim)
|
||||||
|
{
|
||||||
|
if (allow_empties || start != i)
|
||||||
|
count++;
|
||||||
|
start = i + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (start != m_size)
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector<StringView> result;
|
||||||
|
TRY(result.reserve(count));
|
||||||
|
|
||||||
|
size_type start = 0;
|
||||||
|
for (size_type i = 0; i < m_size; i++)
|
||||||
|
{
|
||||||
|
if (m_data[i] == delim)
|
||||||
|
{
|
||||||
|
if (allow_empties || start != i)
|
||||||
|
TRY(result.push_back(this->substring(start, i - start)));
|
||||||
|
start = i + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (start != m_size)
|
||||||
|
TRY(result.push_back(this->substring(start)));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
ErrorOr<Vector<StringView>> StringView::split(bool(*comp)(char), bool allow_empties)
|
||||||
|
{
|
||||||
|
size_type count = 0;
|
||||||
|
{
|
||||||
|
size_type start = 0;
|
||||||
|
for (size_type i = 0; i < m_size; i++)
|
||||||
|
{
|
||||||
|
if (comp(m_data[i]))
|
||||||
|
{
|
||||||
|
if (allow_empties || start != i)
|
||||||
|
count++;
|
||||||
|
start = i + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (start != m_size)
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector<StringView> result;
|
||||||
|
TRY(result.reserve(count));
|
||||||
|
|
||||||
|
size_type start = 0;
|
||||||
|
for (size_type i = 0; i < m_size; i++)
|
||||||
|
{
|
||||||
|
if (comp(m_data[i]))
|
||||||
|
{
|
||||||
|
if (allow_empties || start != i)
|
||||||
|
TRY(result.push_back(this->substring(start, i - start)));
|
||||||
|
start = i + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (start != m_size)
|
||||||
|
TRY(result.push_back(this->substring(start)));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
char StringView::back() const
|
||||||
|
{
|
||||||
|
ASSERT(m_size > 0);
|
||||||
|
return m_data[m_size - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
char StringView::front() const
|
||||||
|
{
|
||||||
|
ASSERT(m_size > 0);
|
||||||
|
return m_data[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
bool StringView::contains(char ch) const
|
||||||
|
{
|
||||||
|
for (size_type i = 0; i < m_size; i++)
|
||||||
|
if (m_data[i] == ch)
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
StringView::size_type StringView::count(char ch) const
|
||||||
|
{
|
||||||
|
size_type result = 0;
|
||||||
|
for (size_type i = 0; i < m_size; i++)
|
||||||
|
if (m_data[i] == ch)
|
||||||
|
result++;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool StringView::empty() const
|
||||||
|
{
|
||||||
|
return m_size == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
StringView::size_type StringView::size() const
|
||||||
|
{
|
||||||
|
return m_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* StringView::data() const
|
||||||
|
{
|
||||||
|
return m_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -38,7 +38,7 @@ namespace BAN
|
||||||
}
|
}
|
||||||
|
|
||||||
BAN::Time from_unix_time(uint64_t unix_time)
|
BAN::Time from_unix_time(uint64_t unix_time)
|
||||||
{
|
{
|
||||||
BAN::Time time {};
|
BAN::Time time {};
|
||||||
|
|
||||||
time.second = unix_time % 60; unix_time /= 60;
|
time.second = unix_time % 60; unix_time /= 60;
|
||||||
|
@ -68,4 +68,4 @@ namespace BAN
|
||||||
return time;
|
return time;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -1,15 +1,24 @@
|
||||||
|
cmake_minimum_required(VERSION 3.26)
|
||||||
|
|
||||||
|
project(BAN CXX)
|
||||||
|
|
||||||
set(BAN_SOURCES
|
set(BAN_SOURCES
|
||||||
BAN/Assert.cpp
|
|
||||||
BAN/New.cpp
|
BAN/New.cpp
|
||||||
|
BAN/String.cpp
|
||||||
BAN/StringView.cpp
|
BAN/StringView.cpp
|
||||||
BAN/Time.cpp
|
BAN/Time.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
|
add_custom_target(ban-headers
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E copy_directory_if_different ${CMAKE_CURRENT_SOURCE_DIR}/include/ ${BANAN_INCLUDE}/
|
||||||
|
DEPENDS sysroot
|
||||||
|
)
|
||||||
|
|
||||||
add_library(ban ${BAN_SOURCES})
|
add_library(ban ${BAN_SOURCES})
|
||||||
target_link_options(ban PRIVATE -nolibc)
|
add_dependencies(ban headers libc-install)
|
||||||
banan_link_library(ban libc)
|
|
||||||
|
|
||||||
set_target_properties(ban PROPERTIES OUTPUT_NAME libban)
|
add_custom_target(ban-install
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_BINARY_DIR}/libban.a ${BANAN_LIB}/
|
||||||
banan_install_headers(ban)
|
DEPENDS ban
|
||||||
install(TARGETS ban OPTIONAL)
|
BYPRODUCTS ${BANAN_LIB}/libban.a
|
||||||
|
)
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <BAN/Errors.h>
|
||||||
#include <BAN/Iterators.h>
|
#include <BAN/Iterators.h>
|
||||||
#include <BAN/Span.h>
|
#include <BAN/Span.h>
|
||||||
|
|
||||||
|
@ -18,7 +19,7 @@ namespace BAN
|
||||||
using const_iterator = ConstIteratorSimple<T, Array>;
|
using const_iterator = ConstIteratorSimple<T, Array>;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Array() = default;
|
Array();
|
||||||
Array(const T&);
|
Array(const T&);
|
||||||
|
|
||||||
iterator begin() { return iterator(m_data); }
|
iterator begin() { return iterator(m_data); }
|
||||||
|
@ -38,14 +39,21 @@ namespace BAN
|
||||||
const Span<T> span() const { return Span(m_data, size()); }
|
const Span<T> span() const { return Span(m_data, size()); }
|
||||||
|
|
||||||
constexpr size_type size() const;
|
constexpr size_type size() const;
|
||||||
|
|
||||||
const T* data() const { return m_data; }
|
const T* data() const { return m_data; }
|
||||||
T* data() { return m_data; }
|
T* data() { return m_data; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
T m_data[S] {};
|
T m_data[S];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<typename T, size_t S>
|
||||||
|
Array<T, S>::Array()
|
||||||
|
{
|
||||||
|
for (size_type i = 0; i < S; i++)
|
||||||
|
m_data[i] = T();
|
||||||
|
}
|
||||||
|
|
||||||
template<typename T, size_t S>
|
template<typename T, size_t S>
|
||||||
Array<T, S>::Array(const T& value)
|
Array<T, S>::Array(const T& value)
|
||||||
{
|
{
|
||||||
|
@ -101,4 +109,4 @@ namespace BAN
|
||||||
return S;
|
return S;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -1,14 +1,33 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#define __ban_assert_stringify_helper(s) #s
|
#include <BAN/Traits.h>
|
||||||
#define __ban_assert_stringify(s) __ban_assert_stringify_helper(s)
|
|
||||||
|
|
||||||
#define ASSERT(cond) \
|
#if defined(__is_kernel)
|
||||||
(__builtin_expect(!(cond), 0) \
|
#include <kernel/Panic.h>
|
||||||
? __ban_assertion_failed(__FILE__ ":" __ban_assert_stringify(__LINE__), "ASSERT(" #cond ") failed") \
|
|
||||||
: (void)0)
|
|
||||||
|
|
||||||
#define ASSERT_NOT_REACHED() \
|
#define ASSERT(cond) \
|
||||||
__ban_assertion_failed(__FILE__ ":" __ban_assert_stringify(__LINE__), "ASSERT_NOT_REACHED() reached")
|
do { \
|
||||||
|
if (!(cond)) \
|
||||||
|
Kernel::panic("ASSERT(" #cond ") failed"); \
|
||||||
|
} while (false)
|
||||||
|
|
||||||
[[noreturn]] void __ban_assertion_failed(const char* location, const char* msg);
|
#define __ASSERT_BIN_OP(lhs, rhs, name, op) \
|
||||||
|
do { \
|
||||||
|
auto&& _lhs = lhs; \
|
||||||
|
auto&& _rhs = rhs; \
|
||||||
|
if (!(_lhs op _rhs)) \
|
||||||
|
Kernel::panic(name "(" #lhs ", " #rhs ") ({} " #op " {}) failed", _lhs, _rhs); \
|
||||||
|
} while (false)
|
||||||
|
|
||||||
|
#define ASSERT_LT(lhs, rhs) __ASSERT_BIN_OP(lhs, rhs, "ASSERT_LT", <)
|
||||||
|
#define ASSERT_LTE(lhs, rhs) __ASSERT_BIN_OP(lhs, rhs, "ASSERT_LTE", <=)
|
||||||
|
#define ASSERT_GT(lhs, rhs) __ASSERT_BIN_OP(lhs, rhs, "ASSERT_GT", >)
|
||||||
|
#define ASSERT_GTE(lhs, rhs) __ASSERT_BIN_OP(lhs, rhs, "ASSERT_GTE", >=)
|
||||||
|
#define ASSERT_EQ(lhs, rhs) __ASSERT_BIN_OP(lhs, rhs, "ASSERT_EQ", ==)
|
||||||
|
#define ASSERT_NEQ(lhs, rhs) __ASSERT_BIN_OP(lhs, rhs, "ASSERT_NEQ", !=)
|
||||||
|
#define ASSERT_NOT_REACHED() Kernel::panic("ASSERT_NOT_REACHED() failed")
|
||||||
|
#else
|
||||||
|
#include <assert.h>
|
||||||
|
#define ASSERT(cond) assert((cond) && "ASSERT("#cond") failed")
|
||||||
|
#define ASSERT_NOT_REACHED() do { assert(false && "ASSERT_NOT_REACHED() failed"); __builtin_unreachable(); } while (false)
|
||||||
|
#endif
|
||||||
|
|
|
@ -1,69 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
namespace BAN
|
|
||||||
{
|
|
||||||
|
|
||||||
enum MemoryOrder
|
|
||||||
{
|
|
||||||
memory_order_relaxed = __ATOMIC_RELAXED,
|
|
||||||
memory_order_consume = __ATOMIC_CONSUME,
|
|
||||||
memory_order_acquire = __ATOMIC_ACQUIRE,
|
|
||||||
memory_order_release = __ATOMIC_RELEASE,
|
|
||||||
memory_order_acq_rel = __ATOMIC_ACQ_REL,
|
|
||||||
memory_order_seq_cst = __ATOMIC_SEQ_CST,
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T, MemoryOrder MEM_ORDER = MemoryOrder::memory_order_seq_cst>
|
|
||||||
requires requires { __atomic_always_lock_free(sizeof(T), 0); }
|
|
||||||
class Atomic
|
|
||||||
{
|
|
||||||
Atomic(const Atomic&) = delete;
|
|
||||||
Atomic(Atomic&&) = delete;
|
|
||||||
Atomic& operator=(const Atomic&) volatile = delete;
|
|
||||||
Atomic& operator=(Atomic&&) volatile = delete;
|
|
||||||
|
|
||||||
public:
|
|
||||||
constexpr Atomic() : m_value(0) {}
|
|
||||||
constexpr Atomic(T val) : m_value(val) {}
|
|
||||||
|
|
||||||
inline T load(MemoryOrder mem_order = MEM_ORDER) const volatile { return __atomic_load_n(&m_value, mem_order); }
|
|
||||||
inline void store(T val, MemoryOrder mem_order = MEM_ORDER) volatile { __atomic_store_n(&m_value, val, mem_order); }
|
|
||||||
|
|
||||||
inline T operator=(T val) volatile { store(val); return val; }
|
|
||||||
|
|
||||||
inline operator T() const volatile { return load(); }
|
|
||||||
|
|
||||||
inline T operator+=(T val) volatile { return __atomic_add_fetch(&m_value, val, MEM_ORDER); }
|
|
||||||
inline T operator-=(T val) volatile { return __atomic_sub_fetch(&m_value, val, MEM_ORDER); }
|
|
||||||
inline T operator&=(T val) volatile { return __atomic_and_fetch(&m_value, val, MEM_ORDER); }
|
|
||||||
inline T operator^=(T val) volatile { return __atomic_xor_fetch(&m_value, val, MEM_ORDER); }
|
|
||||||
inline T operator|=(T val) volatile { return __atomic_or_fetch(&m_value, val, MEM_ORDER); }
|
|
||||||
|
|
||||||
inline T operator--() volatile { return __atomic_sub_fetch(&m_value, 1, MEM_ORDER); }
|
|
||||||
inline T operator++() volatile { return __atomic_add_fetch(&m_value, 1, MEM_ORDER); }
|
|
||||||
|
|
||||||
inline T operator--(int) volatile { return __atomic_fetch_sub(&m_value, 1, MEM_ORDER); }
|
|
||||||
inline T operator++(int) volatile { return __atomic_fetch_add(&m_value, 1, MEM_ORDER); }
|
|
||||||
|
|
||||||
inline bool compare_exchange(T& expected, T desired, MemoryOrder mem_order = MEM_ORDER) volatile { return __atomic_compare_exchange_n(&m_value, &expected, desired, false, mem_order, mem_order); }
|
|
||||||
inline T exchange(T desired, MemoryOrder mem_order = MEM_ORDER) volatile { return __atomic_exchange_n(&m_value, desired, mem_order); };
|
|
||||||
|
|
||||||
inline T add_fetch (T val, MemoryOrder mem_order = MEM_ORDER) volatile { return __atomic_add_fetch (&m_value, val, mem_order); }
|
|
||||||
inline T sub_fetch (T val, MemoryOrder mem_order = MEM_ORDER) volatile { return __atomic_sub_fetch (&m_value, val, mem_order); }
|
|
||||||
inline T and_fetch (T val, MemoryOrder mem_order = MEM_ORDER) volatile { return __atomic_and_fetch (&m_value, val, mem_order); }
|
|
||||||
inline T xor_fetch (T val, MemoryOrder mem_order = MEM_ORDER) volatile { return __atomic_xor_fetch (&m_value, val, mem_order); }
|
|
||||||
inline T or_fetch (T val, MemoryOrder mem_order = MEM_ORDER) volatile { return __atomic_or_fetch (&m_value, val, mem_order); }
|
|
||||||
inline T nand_fetch(T val, MemoryOrder mem_order = MEM_ORDER) volatile { return __atomic_nand_fetch(&m_value, val, mem_order); }
|
|
||||||
|
|
||||||
inline T fetch_add (T val, MemoryOrder mem_order = MEM_ORDER) volatile { return __atomic_fetch_add (&m_value, val, mem_order); }
|
|
||||||
inline T fetch_sub (T val, MemoryOrder mem_order = MEM_ORDER) volatile { return __atomic_fetch_sub (&m_value, val, mem_order); }
|
|
||||||
inline T fetch_and (T val, MemoryOrder mem_order = MEM_ORDER) volatile { return __atomic_fetch_and (&m_value, val, mem_order); }
|
|
||||||
inline T fetch_xor (T val, MemoryOrder mem_order = MEM_ORDER) volatile { return __atomic_fetch_xor (&m_value, val, mem_order); }
|
|
||||||
inline T fetch_or (T val, MemoryOrder mem_order = MEM_ORDER) volatile { return __atomic_fetch__or (&m_value, val, mem_order); }
|
|
||||||
inline T fetch_nand(T val, MemoryOrder mem_order = MEM_ORDER) volatile { return __atomic_nfetch_and(&m_value, val, mem_order); }
|
|
||||||
|
|
||||||
private:
|
|
||||||
T m_value;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,12 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
namespace BAN
|
|
||||||
{
|
|
||||||
|
|
||||||
template<typename To, typename From>
|
|
||||||
constexpr To bit_cast(const From& from)
|
|
||||||
{
|
|
||||||
return __builtin_bit_cast(To, from);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -2,8 +2,6 @@
|
||||||
|
|
||||||
#include <BAN/Span.h>
|
#include <BAN/Span.h>
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
namespace BAN
|
namespace BAN
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -21,56 +19,60 @@ namespace BAN
|
||||||
, m_size(size)
|
, m_size(size)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
template<bool SRC_CONST>
|
ByteSpanGeneral(ByteSpanGeneral& other)
|
||||||
ByteSpanGeneral(const ByteSpanGeneral<SRC_CONST>& other) requires(CONST || !SRC_CONST)
|
|
||||||
: m_data(other.data())
|
: m_data(other.data())
|
||||||
, m_size(other.size())
|
, m_size(other.size())
|
||||||
{ }
|
{ }
|
||||||
template<bool SRC_CONST>
|
template<bool C2>
|
||||||
ByteSpanGeneral(ByteSpanGeneral<SRC_CONST>&& other) requires(CONST || !SRC_CONST)
|
ByteSpanGeneral(const ByteSpanGeneral<C2>& other) requires(CONST)
|
||||||
: m_data(other.data())
|
|
||||||
, m_size(other.size())
|
|
||||||
{
|
|
||||||
other.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
ByteSpanGeneral(const Span<T>& other) requires(is_same_v<T, uint8_t> || (is_same_v<T, const uint8_t> && CONST))
|
|
||||||
: m_data(other.data())
|
: m_data(other.data())
|
||||||
, m_size(other.size())
|
, m_size(other.size())
|
||||||
{ }
|
{ }
|
||||||
template<typename T>
|
ByteSpanGeneral(Span<uint8_t> other)
|
||||||
ByteSpanGeneral(Span<T>&& other) requires(is_same_v<T, uint8_t> || (is_same_v<T, const uint8_t> && CONST))
|
|
||||||
: m_data(other.data())
|
: m_data(other.data())
|
||||||
, m_size(other.size())
|
, m_size(other.size())
|
||||||
{
|
{ }
|
||||||
other.clear();
|
ByteSpanGeneral(const Span<const uint8_t>& other) requires(CONST)
|
||||||
}
|
: m_data(other.data())
|
||||||
|
, m_size(other.size())
|
||||||
|
{ }
|
||||||
|
|
||||||
template<bool SRC_CONST>
|
ByteSpanGeneral& operator=(ByteSpanGeneral other)
|
||||||
ByteSpanGeneral& operator=(const ByteSpanGeneral<SRC_CONST>& other) requires(CONST || !SRC_CONST)
|
|
||||||
{
|
{
|
||||||
m_data = other.data();
|
m_data = other.data();
|
||||||
m_size = other.size();
|
m_size = other.size();
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
template<bool SRC_CONST>
|
template<bool C2>
|
||||||
ByteSpanGeneral& operator=(ByteSpanGeneral<SRC_CONST>&& other) requires(CONST || !SRC_CONST)
|
ByteSpanGeneral& operator=(const ByteSpanGeneral<C2>& other) requires(CONST)
|
||||||
|
{
|
||||||
|
m_data = other.data();
|
||||||
|
m_size = other.size();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
ByteSpanGeneral& operator=(Span<uint8_t> other)
|
||||||
|
{
|
||||||
|
m_data = other.data();
|
||||||
|
m_size = other.size();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
ByteSpanGeneral& operator=(const Span<const uint8_t>& other) requires(CONST)
|
||||||
{
|
{
|
||||||
m_data = other.data();
|
m_data = other.data();
|
||||||
m_size = other.size();
|
m_size = other.size();
|
||||||
other.clear();
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename S>
|
template<typename S>
|
||||||
static ByteSpanGeneral from(S& value) requires(CONST || !is_const_v<S>)
|
requires(CONST || !is_const_v<S>)
|
||||||
|
static ByteSpanGeneral from(S& value)
|
||||||
{
|
{
|
||||||
return ByteSpanGeneral(reinterpret_cast<value_type*>(&value), sizeof(S));
|
return ByteSpanGeneral(reinterpret_cast<value_type*>(&value), sizeof(S));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename S>
|
template<typename S>
|
||||||
S& as() const requires(!CONST || is_const_v<S>)
|
requires(!CONST && !is_const_v<S>)
|
||||||
|
S& as()
|
||||||
{
|
{
|
||||||
ASSERT(m_data);
|
ASSERT(m_data);
|
||||||
ASSERT(m_size >= sizeof(S));
|
ASSERT(m_size >= sizeof(S));
|
||||||
|
@ -78,13 +80,30 @@ namespace BAN
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename S>
|
template<typename S>
|
||||||
Span<S> as_span() const requires(!CONST || is_const_v<S>)
|
requires(is_const_v<S>)
|
||||||
|
S& as() const
|
||||||
|
{
|
||||||
|
ASSERT(m_data);
|
||||||
|
ASSERT(m_size >= sizeof(S));
|
||||||
|
return *reinterpret_cast<S*>(m_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename S>
|
||||||
|
requires(!CONST && !is_const_v<S>)
|
||||||
|
Span<S> as_span()
|
||||||
{
|
{
|
||||||
ASSERT(m_data);
|
ASSERT(m_data);
|
||||||
return Span<S>(reinterpret_cast<S*>(m_data), m_size / sizeof(S));
|
return Span<S>(reinterpret_cast<S*>(m_data), m_size / sizeof(S));
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] ByteSpanGeneral slice(size_type offset, size_type length = size_type(-1)) const
|
template<typename S>
|
||||||
|
const Span<S> as_span() const
|
||||||
|
{
|
||||||
|
ASSERT(m_data);
|
||||||
|
return Span<S>(reinterpret_cast<S*>(m_data), m_size / sizeof(S));
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteSpanGeneral slice(size_type offset, size_type length = size_type(-1))
|
||||||
{
|
{
|
||||||
ASSERT(m_data);
|
ASSERT(m_data);
|
||||||
ASSERT(m_size >= offset);
|
ASSERT(m_size >= offset);
|
||||||
|
@ -94,31 +113,28 @@ namespace BAN
|
||||||
return ByteSpanGeneral(m_data + offset, length);
|
return ByteSpanGeneral(m_data + offset, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
value_type& operator[](size_type offset) const
|
value_type& operator[](size_type offset)
|
||||||
|
{
|
||||||
|
ASSERT(offset < m_size);
|
||||||
|
return m_data[offset];
|
||||||
|
}
|
||||||
|
const value_type& operator[](size_type offset) const
|
||||||
{
|
{
|
||||||
ASSERT(offset < m_size);
|
ASSERT(offset < m_size);
|
||||||
return m_data[offset];
|
return m_data[offset];
|
||||||
}
|
}
|
||||||
|
|
||||||
value_type* data() const { return m_data; }
|
value_type* data() { return m_data; }
|
||||||
|
const value_type* data() const { return m_data; }
|
||||||
|
|
||||||
bool empty() const { return m_size == 0; }
|
|
||||||
size_type size() const { return m_size; }
|
size_type size() const { return m_size; }
|
||||||
|
|
||||||
void clear()
|
|
||||||
{
|
|
||||||
m_data = nullptr;
|
|
||||||
m_size = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
value_type* m_data { nullptr };
|
value_type* m_data { nullptr };
|
||||||
size_type m_size { 0 };
|
size_type m_size { 0 };
|
||||||
|
|
||||||
friend class ByteSpanGeneral<!CONST>;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
using ByteSpan = ByteSpanGeneral<false>;
|
using ByteSpan = ByteSpanGeneral<false>;
|
||||||
using ConstByteSpan = ByteSpanGeneral<true>;
|
using ConstByteSpan = ByteSpanGeneral<true>;
|
||||||
|
|
||||||
}
|
}
|
|
@ -1,8 +1,6 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <BAN/Assert.h>
|
#include <BAN/Assert.h>
|
||||||
#include <BAN/Move.h>
|
|
||||||
#include <BAN/PlacementNew.h>
|
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
@ -24,20 +22,17 @@ namespace BAN
|
||||||
void push(const T&);
|
void push(const T&);
|
||||||
void push(T&&);
|
void push(T&&);
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
void emplace(Args&&... args) requires is_constructible_v<T, Args...>;
|
void emplace(Args&&... args);
|
||||||
|
|
||||||
void pop();
|
void pop();
|
||||||
|
|
||||||
const T& front() const;
|
const T& front() const;
|
||||||
T& front();
|
T& front();
|
||||||
|
|
||||||
const T& back() const;
|
|
||||||
T& back();
|
|
||||||
|
|
||||||
size_type size() const { return m_size; }
|
size_type size() const { return m_size; }
|
||||||
bool empty() const { return size() == 0; }
|
bool empty() const { return size() == 0; }
|
||||||
bool full() const { return size() == capacity(); }
|
bool full() const { return size() == capacity(); }
|
||||||
|
|
||||||
static constexpr size_type capacity() { return S; }
|
static constexpr size_type capacity() { return S; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -71,7 +66,7 @@ namespace BAN
|
||||||
|
|
||||||
template<typename T, size_t S>
|
template<typename T, size_t S>
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
void CircularQueue<T, S>::emplace(Args&&... args) requires is_constructible_v<T, Args...>
|
void CircularQueue<T, S>::emplace(Args&&... args)
|
||||||
{
|
{
|
||||||
ASSERT(!full());
|
ASSERT(!full());
|
||||||
new (element_at(((m_first + m_size) % capacity()))) T(BAN::forward<Args>(args)...);
|
new (element_at(((m_first + m_size) % capacity()))) T(BAN::forward<Args>(args)...);
|
||||||
|
@ -101,20 +96,6 @@ namespace BAN
|
||||||
return *element_at(m_first);
|
return *element_at(m_first);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, size_t S>
|
|
||||||
const T& CircularQueue<T, S>::back() const
|
|
||||||
{
|
|
||||||
ASSERT(!empty());
|
|
||||||
return *element_at((m_first + m_size - 1) % capacity());
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T, size_t S>
|
|
||||||
T& CircularQueue<T, S>::back()
|
|
||||||
{
|
|
||||||
ASSERT(!empty());
|
|
||||||
return *element_at((m_first + m_size - 1) % capacity());
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T, size_t S>
|
template<typename T, size_t S>
|
||||||
const T* CircularQueue<T, S>::element_at(size_type index) const
|
const T* CircularQueue<T, S>::element_at(size_type index) const
|
||||||
{
|
{
|
||||||
|
@ -129,4 +110,4 @@ namespace BAN
|
||||||
return (T*)(m_storage + index * sizeof(T));
|
return (T*)(m_storage + index * sizeof(T));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -1,55 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#if __is_kernel
|
|
||||||
|
|
||||||
#include <kernel/Debug.h>
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
#include <BAN/Formatter.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
#define __debug_putchar [](int c) { putc(c, stddbg); }
|
|
||||||
|
|
||||||
#define dprintln(...) \
|
|
||||||
do { \
|
|
||||||
BAN::Formatter::print(__debug_putchar, __VA_ARGS__); \
|
|
||||||
BAN::Formatter::print(__debug_putchar,"\r\n"); \
|
|
||||||
fflush(stddbg); \
|
|
||||||
} while (false)
|
|
||||||
|
|
||||||
#define dwarnln(...) \
|
|
||||||
do { \
|
|
||||||
BAN::Formatter::print(__debug_putchar, "\e[33m"); \
|
|
||||||
BAN::Formatter::print(__debug_putchar, __VA_ARGS__); \
|
|
||||||
BAN::Formatter::print(__debug_putchar, "\e[m\r\n"); \
|
|
||||||
fflush(stddbg); \
|
|
||||||
} while(false)
|
|
||||||
|
|
||||||
#define derrorln(...) \
|
|
||||||
do { \
|
|
||||||
BAN::Formatter::print(__debug_putchar, "\e[31m"); \
|
|
||||||
BAN::Formatter::print(__debug_putchar, __VA_ARGS__); \
|
|
||||||
BAN::Formatter::print(__debug_putchar, "\e[m\r\n"); \
|
|
||||||
fflush(stddbg); \
|
|
||||||
} while(false)
|
|
||||||
|
|
||||||
#define dprintln_if(cond, ...) \
|
|
||||||
do { \
|
|
||||||
if constexpr(cond) \
|
|
||||||
dprintln(__VA_ARGS__); \
|
|
||||||
} while(false)
|
|
||||||
|
|
||||||
#define dwarnln_if(cond, ...) \
|
|
||||||
do { \
|
|
||||||
if constexpr(cond) \
|
|
||||||
dwarnln(__VA_ARGS__); \
|
|
||||||
} while(false)
|
|
||||||
|
|
||||||
#define derrorln_if(cond, ...) \
|
|
||||||
do { \
|
|
||||||
if constexpr(cond) \
|
|
||||||
derrorln(__VA_ARGS__); \
|
|
||||||
} while(false)
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -45,12 +45,6 @@ namespace BAN
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
template<integral T>
|
|
||||||
constexpr T little_endian_to_host(T value)
|
|
||||||
{
|
|
||||||
return host_to_little_endian(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<integral T>
|
template<integral T>
|
||||||
constexpr T host_to_big_endian(T value)
|
constexpr T host_to_big_endian(T value)
|
||||||
{
|
{
|
||||||
|
@ -61,28 +55,13 @@ namespace BAN
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
template<integral T>
|
|
||||||
constexpr T big_endian_to_host(T value)
|
|
||||||
{
|
|
||||||
return host_to_big_endian(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<integral T>
|
template<integral T>
|
||||||
struct LittleEndian
|
struct LittleEndian
|
||||||
{
|
{
|
||||||
constexpr LittleEndian()
|
|
||||||
: raw(0)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
constexpr LittleEndian(T value)
|
|
||||||
: raw(host_to_little_endian(value))
|
|
||||||
{ }
|
|
||||||
|
|
||||||
constexpr operator T() const
|
constexpr operator T() const
|
||||||
{
|
{
|
||||||
return host_to_little_endian(raw);
|
return host_to_little_endian(raw);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
T raw;
|
T raw;
|
||||||
};
|
};
|
||||||
|
@ -90,36 +69,12 @@ namespace BAN
|
||||||
template<integral T>
|
template<integral T>
|
||||||
struct BigEndian
|
struct BigEndian
|
||||||
{
|
{
|
||||||
constexpr BigEndian()
|
|
||||||
: raw(0)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
constexpr BigEndian(T value)
|
|
||||||
: raw(host_to_big_endian(value))
|
|
||||||
{ }
|
|
||||||
|
|
||||||
constexpr operator T() const
|
constexpr operator T() const
|
||||||
{
|
{
|
||||||
return host_to_big_endian(raw);
|
return host_to_big_endian(raw);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
T raw;
|
T raw;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<integral T>
|
}
|
||||||
using NetworkEndian = BigEndian<T>;
|
|
||||||
|
|
||||||
template<integral T>
|
|
||||||
constexpr T host_to_network_endian(T value)
|
|
||||||
{
|
|
||||||
return host_to_big_endian(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<integral T>
|
|
||||||
constexpr T network_endian_to_host(T value)
|
|
||||||
{
|
|
||||||
return big_endian_to_host(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,7 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <BAN/Formatter.h>
|
#include <BAN/Formatter.h>
|
||||||
#include <BAN/NoCopyMove.h>
|
#include <BAN/StringView.h>
|
||||||
#include <BAN/Variant.h>
|
#include <BAN/Variant.h>
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
@ -13,9 +13,9 @@
|
||||||
#define MUST(expr) ({ auto&& e = expr; if (e.is_error()) Kernel::panic("{}", e.error()); e.release_value(); })
|
#define MUST(expr) ({ auto&& e = expr; if (e.is_error()) Kernel::panic("{}", e.error()); e.release_value(); })
|
||||||
#define MUST_REF(expr) *({ auto&& e = expr; if (e.is_error()) Kernel::panic("{}", e.error()); &e.release_value(); })
|
#define MUST_REF(expr) *({ auto&& e = expr; if (e.is_error()) Kernel::panic("{}", e.error()); &e.release_value(); })
|
||||||
#else
|
#else
|
||||||
#include <BAN/Debug.h>
|
#include <assert.h>
|
||||||
#define MUST(expr) ({ auto&& e = expr; if (e.is_error()) { derrorln("MUST(" #expr "): {}", e.error()); __builtin_trap(); } e.release_value(); })
|
#define MUST(expr) ({ auto&& e = expr; assert(!e.is_error()); e.release_value(); })
|
||||||
#define MUST_REF(expr) *({ auto&& e = expr; if (e.is_error()) { derrorln("MUST(" #expr "): {}", e.error()); __builtin_trap(); } &e.release_value(); })
|
#define MUST_REF(expr) *({ auto&& e = expr; assert(!e.is_error()); &e.release_value(); })
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define TRY(expr) ({ auto&& e = expr; if (e.is_error()) return e.release_error(); e.release_value(); })
|
#define TRY(expr) ({ auto&& e = expr; if (e.is_error()) return e.release_error(); e.release_value(); })
|
||||||
|
@ -37,14 +37,7 @@ namespace BAN
|
||||||
{
|
{
|
||||||
return Error((uint64_t)error | kernel_error_mask);
|
return Error((uint64_t)error | kernel_error_mask);
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
template<size_t N>
|
|
||||||
consteval static Error from_literal(const char (&message)[N])
|
|
||||||
{
|
|
||||||
return Error(message);
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static Error from_errno(int error)
|
static Error from_errno(int error)
|
||||||
{
|
{
|
||||||
return Error(error);
|
return Error(error);
|
||||||
|
@ -62,43 +55,27 @@ namespace BAN
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
constexpr uint64_t get_error_code() const { return m_error_code; }
|
uint64_t get_error_code() const { return m_error_code; }
|
||||||
const char* get_message() const
|
BAN::StringView get_message() const
|
||||||
{
|
{
|
||||||
#ifdef __is_kernel
|
#ifdef __is_kernel
|
||||||
if (m_error_code & kernel_error_mask)
|
if (m_error_code & kernel_error_mask)
|
||||||
return Kernel::error_string(kernel_error());
|
return Kernel::error_string(kernel_error());
|
||||||
#else
|
|
||||||
if (m_message)
|
|
||||||
return m_message;
|
|
||||||
#endif
|
#endif
|
||||||
if (auto* desc = strerrordesc_np(m_error_code))
|
return strerror(m_error_code);
|
||||||
return desc;
|
|
||||||
return "Unknown error";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
constexpr Error(uint64_t error)
|
Error(uint64_t error)
|
||||||
: m_error_code(error)
|
: m_error_code(error)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
#ifndef __is_kernel
|
uint64_t m_error_code;
|
||||||
constexpr Error(const char* message)
|
|
||||||
: m_message(message)
|
|
||||||
{}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
uint64_t m_error_code { 0 };
|
|
||||||
|
|
||||||
#ifndef __is_kernel
|
|
||||||
const char* m_message { nullptr };
|
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
class [[nodiscard]] ErrorOr
|
class [[nodiscard]] ErrorOr
|
||||||
{
|
{
|
||||||
BAN_NON_COPYABLE(ErrorOr);
|
|
||||||
public:
|
public:
|
||||||
ErrorOr(const T& value)
|
ErrorOr(const T& value)
|
||||||
: m_data(value)
|
: m_data(value)
|
||||||
|
@ -112,14 +89,6 @@ namespace BAN
|
||||||
ErrorOr(Error&& error)
|
ErrorOr(Error&& error)
|
||||||
: m_data(move(error))
|
: m_data(move(error))
|
||||||
{}
|
{}
|
||||||
ErrorOr(ErrorOr&& other)
|
|
||||||
: m_data(move(other.m_data))
|
|
||||||
{}
|
|
||||||
ErrorOr& operator=(ErrorOr&& other)
|
|
||||||
{
|
|
||||||
m_data = move(other.m_data);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool is_error() const { return m_data.template has<Error>(); }
|
bool is_error() const { return m_data.template has<Error>(); }
|
||||||
const Error& error() const { return m_data.template get<Error>(); }
|
const Error& error() const { return m_data.template get<Error>(); }
|
||||||
|
|
|
@ -10,19 +10,22 @@ namespace BAN::Formatter
|
||||||
|
|
||||||
struct ValueFormat;
|
struct ValueFormat;
|
||||||
|
|
||||||
|
template<typename F>
|
||||||
|
static void print(F putc, const char* format);
|
||||||
|
|
||||||
|
template<typename F, typename Arg, typename... Args>
|
||||||
|
static void print(F putc, const char* format, Arg&& arg, Args&&... args);
|
||||||
|
|
||||||
template<typename F, typename... Args>
|
template<typename F, typename... Args>
|
||||||
concept PrintableArguments = requires(F putc, Args&&... args, const ValueFormat& format)
|
static void println(F putc, const char* format, Args&&... args);
|
||||||
{
|
|
||||||
(print_argument(putc, BAN::forward<Args>(args), format), ...);
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename F, typename T>
|
template<typename F, typename T>
|
||||||
inline void print_argument(F putc, T value, const ValueFormat& format);
|
static void print_argument(F putc, T value, const ValueFormat& format);
|
||||||
|
|
||||||
namespace detail
|
namespace detail
|
||||||
{
|
{
|
||||||
template<typename F, typename T>
|
template<typename F, typename T>
|
||||||
inline size_t parse_format_and_print_argument(F putc, const char* format, T&& arg);
|
static size_t parse_format_and_print_argument(F putc, const char* format, T&& arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -36,12 +39,11 @@ namespace BAN::Formatter
|
||||||
int base = 10;
|
int base = 10;
|
||||||
int percision = 3;
|
int percision = 3;
|
||||||
int fill = 0;
|
int fill = 0;
|
||||||
char fill_char = '0';
|
|
||||||
bool upper = false;
|
bool upper = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename F>
|
template<typename F>
|
||||||
inline void print(F putc, const char* format)
|
void print(F putc, const char* format)
|
||||||
{
|
{
|
||||||
while (*format)
|
while (*format)
|
||||||
{
|
{
|
||||||
|
@ -50,8 +52,8 @@ namespace BAN::Formatter
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename F, typename Arg, typename... Args> requires PrintableArguments<F, Arg, Args...>
|
template<typename F, typename Arg, typename... Args>
|
||||||
inline void print(F putc, const char* format, Arg&& arg, Args&&... args)
|
void print(F putc, const char* format, Arg&& arg, Args&&... args)
|
||||||
{
|
{
|
||||||
while (*format && *format != '{')
|
while (*format && *format != '{')
|
||||||
{
|
{
|
||||||
|
@ -69,7 +71,7 @@ namespace BAN::Formatter
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename F, typename... Args>
|
template<typename F, typename... Args>
|
||||||
inline void println(F putc, const char* format, Args&&... args)
|
void println(F putc, const char* format, Args&&... args)
|
||||||
{
|
{
|
||||||
print(putc, format, args...);
|
print(putc, format, args...);
|
||||||
putc('\n');
|
putc('\n');
|
||||||
|
@ -79,7 +81,7 @@ namespace BAN::Formatter
|
||||||
{
|
{
|
||||||
|
|
||||||
template<typename F, typename Arg>
|
template<typename F, typename Arg>
|
||||||
inline size_t parse_format_and_print_argument(F putc, const char* format, Arg&& argument)
|
size_t parse_format_and_print_argument(F putc, const char* format, Arg&& argument)
|
||||||
{
|
{
|
||||||
ValueFormat value_format;
|
ValueFormat value_format;
|
||||||
|
|
||||||
|
@ -92,12 +94,6 @@ namespace BAN::Formatter
|
||||||
if (!format[i] || format[i] == '}')
|
if (!format[i] || format[i] == '}')
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (format[i] == ' ')
|
|
||||||
{
|
|
||||||
value_format.fill_char = ' ';
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ('0' <= format[i] && format[i] <= '9')
|
if ('0' <= format[i] && format[i] <= '9')
|
||||||
{
|
{
|
||||||
int fill = 0;
|
int fill = 0;
|
||||||
|
@ -147,7 +143,7 @@ namespace BAN::Formatter
|
||||||
return i + 1;
|
return i + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline char value_to_base_char(uint8_t value, int base, bool upper)
|
static char value_to_base_char(uint8_t value, int base, bool upper)
|
||||||
{
|
{
|
||||||
if (base <= 10)
|
if (base <= 10)
|
||||||
return value + '0';
|
return value + '0';
|
||||||
|
@ -161,13 +157,12 @@ namespace BAN::Formatter
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename F, typename T>
|
template<typename F, typename T>
|
||||||
inline void print_integer(F putc, T value, const ValueFormat& format)
|
void print_integer(F putc, T value, const ValueFormat& format)
|
||||||
{
|
{
|
||||||
if (value == 0)
|
if (value == 0)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < format.fill - 1; i++)
|
for (int i = 0; i < format.fill || i < 1; i++)
|
||||||
putc(format.fill_char);
|
putc('0');
|
||||||
putc('0');
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -193,16 +188,16 @@ namespace BAN::Formatter
|
||||||
}
|
}
|
||||||
|
|
||||||
while (ptr >= buffer + sizeof(buffer) - format.fill)
|
while (ptr >= buffer + sizeof(buffer) - format.fill)
|
||||||
*(--ptr) = format.fill_char;
|
*(--ptr) = '0';
|
||||||
|
|
||||||
if (sign)
|
if (sign)
|
||||||
*(--ptr) = '-';
|
*(--ptr) = '-';
|
||||||
|
|
||||||
print(putc, ptr);
|
print(putc, ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename F, typename T>
|
template<typename F, typename T>
|
||||||
inline void print_floating(F putc, T value, const ValueFormat& format)
|
void print_floating(F putc, T value, const ValueFormat& format)
|
||||||
{
|
{
|
||||||
int64_t int_part = (int64_t)value;
|
int64_t int_part = (int64_t)value;
|
||||||
T frac_part = value - (T)int_part;
|
T frac_part = value - (T)int_part;
|
||||||
|
@ -210,10 +205,10 @@ namespace BAN::Formatter
|
||||||
frac_part = -frac_part;
|
frac_part = -frac_part;
|
||||||
|
|
||||||
print_integer(putc, int_part, format);
|
print_integer(putc, int_part, format);
|
||||||
|
|
||||||
if (format.percision > 0)
|
if (format.percision > 0)
|
||||||
putc('.');
|
putc('.');
|
||||||
|
|
||||||
for (int i = 0; i < format.percision; i++)
|
for (int i = 0; i < format.percision; i++)
|
||||||
{
|
{
|
||||||
frac_part *= format.base;
|
frac_part *= format.base;
|
||||||
|
@ -225,7 +220,7 @@ namespace BAN::Formatter
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename F>
|
template<typename F>
|
||||||
inline void print_pointer(F putc, void* ptr, const ValueFormat& format)
|
void print_pointer(F putc, void* ptr, const ValueFormat& format)
|
||||||
{
|
{
|
||||||
uintptr_t value = (uintptr_t)ptr;
|
uintptr_t value = (uintptr_t)ptr;
|
||||||
print(putc, "0x");
|
print(putc, "0x");
|
||||||
|
@ -241,13 +236,13 @@ namespace BAN::Formatter
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
template<typename F, integral T> inline void print_argument(F putc, T value, const ValueFormat& format) { detail::print_integer(putc, value, format); }
|
template<typename F, integral T> void print_argument(F putc, T value, const ValueFormat& format) { detail::print_integer(putc, value, format); }
|
||||||
template<typename F, floating_point T> inline void print_argument(F putc, T value, const ValueFormat& format) { detail::print_floating(putc, value, format); }
|
template<typename F, floating_point T> void print_argument(F putc, T value, const ValueFormat& format) { detail::print_floating(putc, value, format); }
|
||||||
template<typename F, pointer T> inline void print_argument(F putc, T value, const ValueFormat& format) { detail::print_pointer(putc, (void*)value, format); }
|
template<typename F, pointer T> void print_argument(F putc, T value, const ValueFormat& format) { detail::print_pointer(putc, (void*)value, format); }
|
||||||
|
|
||||||
template<typename F> inline void print_argument(F putc, char value, const ValueFormat&) { putc(value); }
|
template<typename F> void print_argument(F putc, char value, const ValueFormat&) { putc(value); }
|
||||||
template<typename F> inline void print_argument(F putc, bool value, const ValueFormat&) { print(putc, value ? "true" : "false"); }
|
template<typename F> void print_argument(F putc, bool value, const ValueFormat&) { print(putc, value ? "true" : "false"); }
|
||||||
template<typename F> inline void print_argument(F putc, const char* value, const ValueFormat&) { print(putc, value); }
|
template<typename F> void print_argument(F putc, const char* value, const ValueFormat&) { print(putc, value); }
|
||||||
template<typename F> inline void print_argument(F putc, char* value, const ValueFormat&) { print(putc, value); }
|
template<typename F> void print_argument(F putc, char* value, const ValueFormat&) { print(putc, value); }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
#include <BAN/Errors.h>
|
#include <BAN/Errors.h>
|
||||||
#include <BAN/Move.h>
|
#include <BAN/Move.h>
|
||||||
#include <BAN/PlacementNew.h>
|
#include <BAN/New.h>
|
||||||
|
|
||||||
namespace BAN
|
namespace BAN
|
||||||
{
|
{
|
||||||
|
@ -20,19 +20,19 @@ namespace BAN
|
||||||
new (m_storage) CallablePointer(function);
|
new (m_storage) CallablePointer(function);
|
||||||
}
|
}
|
||||||
template<typename Own>
|
template<typename Own>
|
||||||
Function(Ret(Own::*function)(Args...), Own& owner)
|
Function(Ret(Own::*function)(Args...), Own* owner)
|
||||||
{
|
{
|
||||||
static_assert(sizeof(CallableMember<Own>) <= m_size);
|
static_assert(sizeof(CallableMember<Own>) <= m_size);
|
||||||
new (m_storage) CallableMember<Own>(function, owner);
|
new (m_storage) CallableMember<Own>(function, owner);
|
||||||
}
|
}
|
||||||
template<typename Own>
|
template<typename Own>
|
||||||
Function(Ret(Own::*function)(Args...) const, const Own& owner)
|
Function(Ret(Own::*function)(Args...) const, const Own* owner)
|
||||||
{
|
{
|
||||||
static_assert(sizeof(CallableMemberConst<Own>) <= m_size);
|
static_assert(sizeof(CallableMemberConst<Own>) <= m_size);
|
||||||
new (m_storage) CallableMemberConst<Own>(function, owner);
|
new (m_storage) CallableMemberConst<Own>(function, owner);
|
||||||
}
|
}
|
||||||
template<typename Lambda>
|
template<typename Lambda>
|
||||||
Function(Lambda lambda) requires requires(Lambda lamda, Args&&... args) { { lambda(forward<Args>(args)...) } -> BAN::same_as<Ret>; }
|
Function(Lambda lambda)
|
||||||
{
|
{
|
||||||
static_assert(sizeof(CallableLambda<Lambda>) <= m_size);
|
static_assert(sizeof(CallableLambda<Lambda>) <= m_size);
|
||||||
new (m_storage) CallableLambda<Lambda>(lambda);
|
new (m_storage) CallableLambda<Lambda>(lambda);
|
||||||
|
@ -56,7 +56,7 @@ namespace BAN
|
||||||
return true;
|
return true;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void clear()
|
void clear()
|
||||||
{
|
{
|
||||||
if (*this)
|
if (*this)
|
||||||
|
@ -91,36 +91,36 @@ namespace BAN
|
||||||
template<typename Own>
|
template<typename Own>
|
||||||
struct CallableMember : public CallableBase
|
struct CallableMember : public CallableBase
|
||||||
{
|
{
|
||||||
CallableMember(Ret(Own::*function)(Args...), Own& owner)
|
CallableMember(Ret(Own::*function)(Args...), Own* owner)
|
||||||
: m_owner(owner)
|
: m_owner(owner)
|
||||||
, m_function(function)
|
, m_function(function)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
virtual Ret call(Args... args) const override
|
virtual Ret call(Args... args) const override
|
||||||
{
|
{
|
||||||
return (m_owner.*m_function)(forward<Args>(args)...);
|
return (m_owner->*m_function)(forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Own& m_owner;
|
Own* m_owner = nullptr;
|
||||||
Ret(Own::*m_function)(Args...) = nullptr;
|
Ret(Own::*m_function)(Args...) = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename Own>
|
template<typename Own>
|
||||||
struct CallableMemberConst : public CallableBase
|
struct CallableMemberConst : public CallableBase
|
||||||
{
|
{
|
||||||
CallableMemberConst(Ret(Own::*function)(Args...) const, const Own& owner)
|
CallableMemberConst(Ret(Own::*function)(Args...) const, const Own* owner)
|
||||||
: m_owner(owner)
|
: m_owner(owner)
|
||||||
, m_function(function)
|
, m_function(function)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
virtual Ret call(Args... args) const override
|
virtual Ret call(Args... args) const override
|
||||||
{
|
{
|
||||||
return (m_owner.*m_function)(forward<Args>(args)...);
|
return (m_owner->*m_function)(forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const Own& m_owner;
|
const Own* m_owner = nullptr;
|
||||||
Ret(Own::*m_function)(Args...) const = nullptr;
|
Ret(Own::*m_function)(Args...) const = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -141,8 +141,8 @@ namespace BAN
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static constexpr size_t m_size = sizeof(void*) * 8;
|
static constexpr size_t m_size = sizeof(void*) * 5;
|
||||||
alignas(CallableBase) uint8_t m_storage[m_size] { 0 };
|
alignas(CallableBase) uint8_t m_storage[m_size] { 0 };
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
|
@ -1,73 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <BAN/Optional.h>
|
|
||||||
#include <BAN/String.h>
|
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
namespace BAN
|
|
||||||
{
|
|
||||||
|
|
||||||
struct GUID
|
|
||||||
{
|
|
||||||
uint32_t component1 { 0 };
|
|
||||||
uint16_t component2 { 0 };
|
|
||||||
uint16_t component3 { 0 };
|
|
||||||
uint8_t component45[8] { };
|
|
||||||
|
|
||||||
bool operator==(const GUID& other) const
|
|
||||||
{
|
|
||||||
return memcmp(this, &other, sizeof(GUID)) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
BAN::ErrorOr<BAN::String> to_string() const
|
|
||||||
{
|
|
||||||
char buffer[37];
|
|
||||||
char* ptr = buffer;
|
|
||||||
|
|
||||||
const auto append_hex_nibble =
|
|
||||||
[&ptr](uint8_t nibble)
|
|
||||||
{
|
|
||||||
if (nibble < 10)
|
|
||||||
*ptr++ = '0' + nibble;
|
|
||||||
else
|
|
||||||
*ptr++ = 'A' + nibble - 10;
|
|
||||||
};
|
|
||||||
|
|
||||||
const auto append_hex_byte =
|
|
||||||
[&append_hex_nibble](uint8_t byte)
|
|
||||||
{
|
|
||||||
append_hex_nibble(byte >> 4);
|
|
||||||
append_hex_nibble(byte & 0xF);
|
|
||||||
};
|
|
||||||
|
|
||||||
append_hex_byte((component1 >> 24) & 0xFF);
|
|
||||||
append_hex_byte((component1 >> 16) & 0xFF);
|
|
||||||
append_hex_byte((component1 >> 8) & 0xFF);
|
|
||||||
append_hex_byte((component1 >> 0) & 0xFF);
|
|
||||||
*ptr++ = '-';
|
|
||||||
append_hex_byte((component2 >> 8) & 0xFF);
|
|
||||||
append_hex_byte((component2 >> 0) & 0xFF);
|
|
||||||
*ptr++ = '-';
|
|
||||||
append_hex_byte((component3 >> 8) & 0xFF);
|
|
||||||
append_hex_byte((component3 >> 0) & 0xFF);
|
|
||||||
*ptr++ = '-';
|
|
||||||
append_hex_byte(component45[0]);
|
|
||||||
append_hex_byte(component45[1]);
|
|
||||||
*ptr++ = '-';
|
|
||||||
append_hex_byte(component45[2]);
|
|
||||||
append_hex_byte(component45[3]);
|
|
||||||
append_hex_byte(component45[4]);
|
|
||||||
append_hex_byte(component45[5]);
|
|
||||||
append_hex_byte(component45[6]);
|
|
||||||
append_hex_byte(component45[7]);
|
|
||||||
*ptr = '\0';
|
|
||||||
|
|
||||||
BAN::String guid;
|
|
||||||
TRY(guid.append(buffer));
|
|
||||||
return BAN::move(guid);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
static_assert(sizeof(GUID) == 16);
|
|
||||||
|
|
||||||
}
|
|
|
@ -47,4 +47,4 @@ namespace BAN
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
|
@ -7,6 +7,9 @@
|
||||||
namespace BAN
|
namespace BAN
|
||||||
{
|
{
|
||||||
|
|
||||||
|
template<typename Container>
|
||||||
|
class HashMapIterator;
|
||||||
|
|
||||||
template<typename Key, typename T, typename HASH = BAN::hash<Key>>
|
template<typename Key, typename T, typename HASH = BAN::hash<Key>>
|
||||||
class HashMap
|
class HashMap
|
||||||
{
|
{
|
||||||
|
@ -14,17 +17,11 @@ namespace BAN
|
||||||
struct Entry
|
struct Entry
|
||||||
{
|
{
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
Entry(const Key& key, Args&&... args) requires is_constructible_v<T, Args...>
|
Entry(const Key& key, Args&&... args)
|
||||||
: key(key)
|
: key(key)
|
||||||
, value(forward<Args>(args)...)
|
, value(forward<Args>(args)...)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
template<typename... Args>
|
|
||||||
Entry(Key&& key, Args&&... args) requires is_constructible_v<T, Args...>
|
|
||||||
: key(BAN::move(key))
|
|
||||||
, value(forward<Args>(args)...)
|
|
||||||
{}
|
|
||||||
|
|
||||||
Key key;
|
Key key;
|
||||||
T value;
|
T value;
|
||||||
};
|
};
|
||||||
|
@ -45,27 +42,10 @@ namespace BAN
|
||||||
HashMap<Key, T, HASH>& operator=(const HashMap<Key, T, HASH>&);
|
HashMap<Key, T, HASH>& operator=(const HashMap<Key, T, HASH>&);
|
||||||
HashMap<Key, T, HASH>& operator=(HashMap<Key, T, HASH>&&);
|
HashMap<Key, T, HASH>& operator=(HashMap<Key, T, HASH>&&);
|
||||||
|
|
||||||
ErrorOr<iterator> insert(const Key& key, const T& value) { return emplace(key, value); }
|
ErrorOr<void> insert(const Key&, const T&);
|
||||||
ErrorOr<iterator> insert(const Key& key, T&& value) { return emplace(key, move(value)); }
|
ErrorOr<void> insert(const Key&, T&&);
|
||||||
ErrorOr<iterator> insert(Key&& key, const T& value) { return emplace(move(key), value); }
|
|
||||||
ErrorOr<iterator> insert(Key&& key, T&& value) { return emplace(move(key), move(value)); }
|
|
||||||
|
|
||||||
ErrorOr<iterator> insert_or_assign(const Key& key, const T& value) { return emplace_or_assign(key, value); }
|
|
||||||
ErrorOr<iterator> insert_or_assign(const Key& key, T&& value) { return emplace_or_assign(key, move(value)); }
|
|
||||||
ErrorOr<iterator> insert_or_assign(Key&& key, const T& value) { return emplace_or_assign(move(key), value); }
|
|
||||||
ErrorOr<iterator> insert_or_assign(Key&& key, T&& value) { return emplace_or_assign(move(key), move(value)); }
|
|
||||||
|
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
ErrorOr<iterator> emplace(const Key& key, Args&&... args) requires is_constructible_v<T, Args...>
|
ErrorOr<void> emplace(const Key&, Args&&...);
|
||||||
{ return emplace(Key(key), forward<Args>(args)...); }
|
|
||||||
template<typename... Args>
|
|
||||||
ErrorOr<iterator> emplace(Key&&, Args&&...) requires is_constructible_v<T, Args...>;
|
|
||||||
|
|
||||||
template<typename... Args>
|
|
||||||
ErrorOr<iterator> emplace_or_assign(const Key& key, Args&&... args) requires is_constructible_v<T, Args...>
|
|
||||||
{ return emplace_or_assign(Key(key), forward<Args>(args)...); }
|
|
||||||
template<typename... Args>
|
|
||||||
ErrorOr<iterator> emplace_or_assign(Key&&, Args&&...) requires is_constructible_v<T, Args...>;
|
|
||||||
|
|
||||||
iterator begin() { return iterator(m_buckets.end(), m_buckets.begin()); }
|
iterator begin() { return iterator(m_buckets.end(), m_buckets.begin()); }
|
||||||
iterator end() { return iterator(m_buckets.end(), m_buckets.end()); }
|
iterator end() { return iterator(m_buckets.end(), m_buckets.end()); }
|
||||||
|
@ -75,14 +55,11 @@ namespace BAN
|
||||||
ErrorOr<void> reserve(size_type);
|
ErrorOr<void> reserve(size_type);
|
||||||
|
|
||||||
void remove(const Key&);
|
void remove(const Key&);
|
||||||
void remove(iterator it);
|
|
||||||
void clear();
|
void clear();
|
||||||
|
|
||||||
T& operator[](const Key&);
|
T& operator[](const Key&);
|
||||||
const T& operator[](const Key&) const;
|
const T& operator[](const Key&) const;
|
||||||
|
|
||||||
iterator find(const Key& key);
|
|
||||||
const_iterator find(const Key& key) const;
|
|
||||||
bool contains(const Key&) const;
|
bool contains(const Key&) const;
|
||||||
|
|
||||||
bool empty() const;
|
bool empty() const;
|
||||||
|
@ -92,9 +69,7 @@ namespace BAN
|
||||||
ErrorOr<void> rebucket(size_type);
|
ErrorOr<void> rebucket(size_type);
|
||||||
LinkedList<Entry>& get_bucket(const Key&);
|
LinkedList<Entry>& get_bucket(const Key&);
|
||||||
const LinkedList<Entry>& get_bucket(const Key&) const;
|
const LinkedList<Entry>& get_bucket(const Key&) const;
|
||||||
Vector<LinkedList<Entry>>::iterator get_bucket_iterator(const Key&);
|
|
||||||
Vector<LinkedList<Entry>>::const_iterator get_bucket_iterator(const Key&) const;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Vector<LinkedList<Entry>> m_buckets;
|
Vector<LinkedList<Entry>> m_buckets;
|
||||||
size_type m_size = 0;
|
size_type m_size = 0;
|
||||||
|
@ -140,36 +115,29 @@ namespace BAN
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Key, typename T, typename HASH>
|
template<typename Key, typename T, typename HASH>
|
||||||
template<typename... Args>
|
ErrorOr<void> HashMap<Key, T, HASH>::insert(const Key& key, const T& value)
|
||||||
ErrorOr<typename HashMap<Key, T, HASH>::iterator> HashMap<Key, T, HASH>::emplace(Key&& key, Args&&... args) requires is_constructible_v<T, Args...>
|
|
||||||
{
|
{
|
||||||
ASSERT(!contains(key));
|
return insert(key, move(T(value)));
|
||||||
TRY(rebucket(m_size + 1));
|
}
|
||||||
|
|
||||||
auto bucket_it = get_bucket_iterator(key);
|
template<typename Key, typename T, typename HASH>
|
||||||
TRY(bucket_it->emplace_back(move(key), forward<Args>(args)...));
|
ErrorOr<void> HashMap<Key, T, HASH>::insert(const Key& key, T&& value)
|
||||||
m_size++;
|
{
|
||||||
|
return emplace(key, move(value));
|
||||||
return iterator(m_buckets.end(), bucket_it, prev(bucket_it->end(), 1));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Key, typename T, typename HASH>
|
template<typename Key, typename T, typename HASH>
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
ErrorOr<typename HashMap<Key, T, HASH>::iterator> HashMap<Key, T, HASH>::emplace_or_assign(Key&& key, Args&&... args) requires is_constructible_v<T, Args...>
|
ErrorOr<void> HashMap<Key, T, HASH>::emplace(const Key& key, Args&&... args)
|
||||||
{
|
{
|
||||||
if (empty())
|
ASSERT(!contains(key));
|
||||||
return emplace(move(key), forward<Args>(args)...);
|
TRY(rebucket(m_size + 1));
|
||||||
|
auto& bucket = get_bucket(key);
|
||||||
auto bucket_it = get_bucket_iterator(key);
|
auto result = bucket.emplace_back(key, forward<Args>(args)...);
|
||||||
for (auto entry_it = bucket_it->begin(); entry_it != bucket_it->end(); entry_it++)
|
if (result.is_error())
|
||||||
{
|
return Error::from_errno(ENOMEM);
|
||||||
if (entry_it->key != key)
|
m_size++;
|
||||||
continue;
|
return {};
|
||||||
entry_it->value = T(forward<Args>(args)...);
|
|
||||||
return iterator(m_buckets.end(), bucket_it, entry_it);
|
|
||||||
}
|
|
||||||
|
|
||||||
return emplace(move(key), forward<Args>(args)...);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Key, typename T, typename HASH>
|
template<typename Key, typename T, typename HASH>
|
||||||
|
@ -182,16 +150,17 @@ namespace BAN
|
||||||
template<typename Key, typename T, typename HASH>
|
template<typename Key, typename T, typename HASH>
|
||||||
void HashMap<Key, T, HASH>::remove(const Key& key)
|
void HashMap<Key, T, HASH>::remove(const Key& key)
|
||||||
{
|
{
|
||||||
auto it = find(key);
|
if (empty()) return;
|
||||||
if (it != end())
|
auto& bucket = get_bucket(key);
|
||||||
remove(it);
|
for (auto it = bucket.begin(); it != bucket.end(); it++)
|
||||||
}
|
{
|
||||||
|
if (it->key == key)
|
||||||
template<typename Key, typename T, typename HASH>
|
{
|
||||||
void HashMap<Key, T, HASH>::remove(iterator it)
|
bucket.remove(it);
|
||||||
{
|
m_size--;
|
||||||
it.outer_current()->remove(it.inner_current());
|
return;
|
||||||
m_size--;
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Key, typename T, typename HASH>
|
template<typename Key, typename T, typename HASH>
|
||||||
|
@ -209,7 +178,7 @@ namespace BAN
|
||||||
for (Entry& entry : bucket)
|
for (Entry& entry : bucket)
|
||||||
if (entry.key == key)
|
if (entry.key == key)
|
||||||
return entry.value;
|
return entry.value;
|
||||||
ASSERT_NOT_REACHED();
|
ASSERT(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Key, typename T, typename HASH>
|
template<typename Key, typename T, typename HASH>
|
||||||
|
@ -220,37 +189,18 @@ namespace BAN
|
||||||
for (const Entry& entry : bucket)
|
for (const Entry& entry : bucket)
|
||||||
if (entry.key == key)
|
if (entry.key == key)
|
||||||
return entry.value;
|
return entry.value;
|
||||||
ASSERT_NOT_REACHED();
|
ASSERT(false);
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Key, typename T, typename HASH>
|
|
||||||
typename HashMap<Key, T, HASH>::iterator HashMap<Key, T, HASH>::find(const Key& key)
|
|
||||||
{
|
|
||||||
if (empty())
|
|
||||||
return end();
|
|
||||||
auto bucket_it = get_bucket_iterator(key);
|
|
||||||
for (auto it = bucket_it->begin(); it != bucket_it->end(); it++)
|
|
||||||
if (it->key == key)
|
|
||||||
return iterator(m_buckets.end(), bucket_it, it);
|
|
||||||
return end();
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Key, typename T, typename HASH>
|
|
||||||
typename HashMap<Key, T, HASH>::const_iterator HashMap<Key, T, HASH>::find(const Key& key) const
|
|
||||||
{
|
|
||||||
if (empty())
|
|
||||||
return end();
|
|
||||||
auto bucket_it = get_bucket_iterator(key);
|
|
||||||
for (auto it = bucket_it->begin(); it != bucket_it->end(); it++)
|
|
||||||
if (it->key == key)
|
|
||||||
return const_iterator(m_buckets.end(), bucket_it, it);
|
|
||||||
return end();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Key, typename T, typename HASH>
|
template<typename Key, typename T, typename HASH>
|
||||||
bool HashMap<Key, T, HASH>::contains(const Key& key) const
|
bool HashMap<Key, T, HASH>::contains(const Key& key) const
|
||||||
{
|
{
|
||||||
return find(key) != end();
|
if (empty()) return false;
|
||||||
|
const auto& bucket = get_bucket(key);
|
||||||
|
for (const Entry& entry : bucket)
|
||||||
|
if (entry.key == key)
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Key, typename T, typename HASH>
|
template<typename Key, typename T, typename HASH>
|
||||||
|
@ -273,14 +223,18 @@ namespace BAN
|
||||||
|
|
||||||
size_type new_bucket_count = BAN::Math::max<size_type>(bucket_count, m_buckets.size() * 2);
|
size_type new_bucket_count = BAN::Math::max<size_type>(bucket_count, m_buckets.size() * 2);
|
||||||
Vector<LinkedList<Entry>> new_buckets;
|
Vector<LinkedList<Entry>> new_buckets;
|
||||||
TRY(new_buckets.resize(new_bucket_count));
|
if (new_buckets.resize(new_bucket_count).is_error())
|
||||||
|
return Error::from_errno(ENOMEM);
|
||||||
|
|
||||||
|
// NOTE: We have to copy the old entries to the new entries and not move
|
||||||
|
// since we might run out of memory half way through.
|
||||||
for (auto& bucket : m_buckets)
|
for (auto& bucket : m_buckets)
|
||||||
{
|
{
|
||||||
for (auto it = bucket.begin(); it != bucket.end();)
|
for (Entry& entry : bucket)
|
||||||
{
|
{
|
||||||
size_type new_bucket_index = HASH()(it->key) % new_buckets.size();
|
size_type bucket_index = HASH()(entry.key) % new_buckets.size();
|
||||||
it = bucket.move_element_to_other_linked_list(new_buckets[new_bucket_index], new_buckets[new_bucket_index].end(), it);
|
if (new_buckets[bucket_index].push_back(entry).is_error())
|
||||||
|
return Error::from_errno(ENOMEM);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -291,29 +245,17 @@ namespace BAN
|
||||||
template<typename Key, typename T, typename HASH>
|
template<typename Key, typename T, typename HASH>
|
||||||
LinkedList<typename HashMap<Key, T, HASH>::Entry>& HashMap<Key, T, HASH>::get_bucket(const Key& key)
|
LinkedList<typename HashMap<Key, T, HASH>::Entry>& HashMap<Key, T, HASH>::get_bucket(const Key& key)
|
||||||
{
|
{
|
||||||
return *get_bucket_iterator(key);
|
ASSERT(!m_buckets.empty());
|
||||||
|
auto index = HASH()(key) % m_buckets.size();
|
||||||
|
return m_buckets[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Key, typename T, typename HASH>
|
template<typename Key, typename T, typename HASH>
|
||||||
const LinkedList<typename HashMap<Key, T, HASH>::Entry>& HashMap<Key, T, HASH>::get_bucket(const Key& key) const
|
const LinkedList<typename HashMap<Key, T, HASH>::Entry>& HashMap<Key, T, HASH>::get_bucket(const Key& key) const
|
||||||
{
|
|
||||||
return *get_bucket_iterator(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Key, typename T, typename HASH>
|
|
||||||
Vector<LinkedList<typename HashMap<Key, T, HASH>::Entry>>::iterator HashMap<Key, T, HASH>::get_bucket_iterator(const Key& key)
|
|
||||||
{
|
{
|
||||||
ASSERT(!m_buckets.empty());
|
ASSERT(!m_buckets.empty());
|
||||||
auto index = HASH()(key) % m_buckets.size();
|
auto index = HASH()(key) % m_buckets.size();
|
||||||
return next(m_buckets.begin(), index);
|
return m_buckets[index];
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Key, typename T, typename HASH>
|
|
||||||
Vector<LinkedList<typename HashMap<Key, T, HASH>::Entry>>::const_iterator HashMap<Key, T, HASH>::get_bucket_iterator(const Key& key) const
|
|
||||||
{
|
|
||||||
ASSERT(!m_buckets.empty());
|
|
||||||
auto index = HASH()(key) % m_buckets.size();
|
|
||||||
return next(m_buckets.begin(), index);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,8 +2,6 @@
|
||||||
|
|
||||||
#include <BAN/Errors.h>
|
#include <BAN/Errors.h>
|
||||||
#include <BAN/Hash.h>
|
#include <BAN/Hash.h>
|
||||||
#include <BAN/Iterators.h>
|
|
||||||
#include <BAN/LinkedList.h>
|
|
||||||
#include <BAN/Math.h>
|
#include <BAN/Math.h>
|
||||||
#include <BAN/Move.h>
|
#include <BAN/Move.h>
|
||||||
#include <BAN/Vector.h>
|
#include <BAN/Vector.h>
|
||||||
|
@ -11,22 +9,24 @@
|
||||||
namespace BAN
|
namespace BAN
|
||||||
{
|
{
|
||||||
|
|
||||||
|
template<typename T, typename HASH>
|
||||||
|
class HashSetIterator;
|
||||||
|
|
||||||
template<typename T, typename HASH = hash<T>>
|
template<typename T, typename HASH = hash<T>>
|
||||||
class HashSet
|
class HashSet
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
using value_type = T;
|
using value_type = T;
|
||||||
using size_type = size_t;
|
using size_type = hash_t;
|
||||||
using iterator = IteratorDouble<T, Vector, LinkedList, HashSet>;
|
using const_iterator = HashSetIterator<T, HASH>;
|
||||||
using const_iterator = ConstIteratorDouble<T, Vector, LinkedList, HashSet>;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
HashSet() = default;
|
HashSet() = default;
|
||||||
HashSet(const HashSet&);
|
HashSet(const HashSet<T, HASH>&);
|
||||||
HashSet(HashSet&&);
|
HashSet(HashSet<T, HASH>&&);
|
||||||
|
|
||||||
HashSet& operator=(const HashSet&);
|
HashSet<T, HASH>& operator=(const HashSet<T, HASH>&);
|
||||||
HashSet& operator=(HashSet&&);
|
HashSet<T, HASH>& operator=(HashSet<T, HASH>&&);
|
||||||
|
|
||||||
ErrorOr<void> insert(const T&);
|
ErrorOr<void> insert(const T&);
|
||||||
ErrorOr<void> insert(T&&);
|
ErrorOr<void> insert(T&&);
|
||||||
|
@ -35,10 +35,8 @@ namespace BAN
|
||||||
|
|
||||||
ErrorOr<void> reserve(size_type);
|
ErrorOr<void> reserve(size_type);
|
||||||
|
|
||||||
iterator begin() { return iterator(m_buckets.end(), m_buckets.begin()); }
|
const_iterator begin() const { return const_iterator(this, m_buckets.begin()); }
|
||||||
iterator end() { return iterator(m_buckets.end(), m_buckets.end()); }
|
const_iterator end() const { return const_iterator(this, m_buckets.end()); }
|
||||||
const_iterator begin() const { return const_iterator(m_buckets.end(), m_buckets.begin()); }
|
|
||||||
const_iterator end() const { return const_iterator(m_buckets.end(), m_buckets.end()); }
|
|
||||||
|
|
||||||
bool contains(const T&) const;
|
bool contains(const T&) const;
|
||||||
|
|
||||||
|
@ -47,23 +45,55 @@ namespace BAN
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ErrorOr<void> rebucket(size_type);
|
ErrorOr<void> rebucket(size_type);
|
||||||
LinkedList<T>& get_bucket(const T&);
|
Vector<T>& get_bucket(const T&);
|
||||||
const LinkedList<T>& get_bucket(const T&) const;
|
const Vector<T>& get_bucket(const T&) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Vector<LinkedList<T>> m_buckets;
|
Vector<Vector<T>> m_buckets;
|
||||||
size_type m_size = 0;
|
size_type m_size = 0;
|
||||||
|
|
||||||
|
friend class HashSetIterator<T, HASH>;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T, typename HASH>
|
template<typename T, typename HASH>
|
||||||
HashSet<T, HASH>::HashSet(const HashSet& other)
|
class HashSetIterator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
HashSetIterator() = default;
|
||||||
|
HashSetIterator(const HashSetIterator<T, HASH>&);
|
||||||
|
|
||||||
|
HashSetIterator<T, HASH>& operator++();
|
||||||
|
HashSetIterator<T, HASH> operator++(int);
|
||||||
|
|
||||||
|
const T& operator*() const;
|
||||||
|
const T* operator->() const;
|
||||||
|
|
||||||
|
bool operator==(const HashSetIterator<T, HASH>&) const;
|
||||||
|
bool operator!=(const HashSetIterator<T, HASH>&) const;
|
||||||
|
|
||||||
|
operator bool() const { return m_owner && m_current_bucket; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
HashSetIterator(const HashSet<T, HASH>* owner, Vector<Vector<T>>::const_iterator bucket);
|
||||||
|
void find_next();
|
||||||
|
|
||||||
|
private:
|
||||||
|
const HashSet<T, HASH>* m_owner = nullptr;
|
||||||
|
Vector<Vector<T>>::const_iterator m_current_bucket;
|
||||||
|
Vector<T>::const_iterator m_current_key;
|
||||||
|
|
||||||
|
friend class HashSet<T, HASH>;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T, typename HASH>
|
||||||
|
HashSet<T, HASH>::HashSet(const HashSet<T, HASH>& other)
|
||||||
: m_buckets(other.m_buckets)
|
: m_buckets(other.m_buckets)
|
||||||
, m_size(other.m_size)
|
, m_size(other.m_size)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, typename HASH>
|
template<typename T, typename HASH>
|
||||||
HashSet<T, HASH>::HashSet(HashSet&& other)
|
HashSet<T, HASH>::HashSet(HashSet<T, HASH>&& other)
|
||||||
: m_buckets(move(other.m_buckets))
|
: m_buckets(move(other.m_buckets))
|
||||||
, m_size(other.m_size)
|
, m_size(other.m_size)
|
||||||
{
|
{
|
||||||
|
@ -71,7 +101,7 @@ namespace BAN
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, typename HASH>
|
template<typename T, typename HASH>
|
||||||
HashSet<T, HASH>& HashSet<T, HASH>::operator=(const HashSet& other)
|
HashSet<T, HASH>& HashSet<T, HASH>::operator=(const HashSet<T, HASH>& other)
|
||||||
{
|
{
|
||||||
clear();
|
clear();
|
||||||
m_buckets = other.m_buckets;
|
m_buckets = other.m_buckets;
|
||||||
|
@ -80,7 +110,7 @@ namespace BAN
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, typename HASH>
|
template<typename T, typename HASH>
|
||||||
HashSet<T, HASH>& HashSet<T, HASH>::operator=(HashSet&& other)
|
HashSet<T, HASH>& HashSet<T, HASH>::operator=(HashSet<T, HASH>&& other)
|
||||||
{
|
{
|
||||||
clear();
|
clear();
|
||||||
m_buckets = move(other.m_buckets);
|
m_buckets = move(other.m_buckets);
|
||||||
|
@ -111,15 +141,15 @@ namespace BAN
|
||||||
void HashSet<T, HASH>::remove(const T& key)
|
void HashSet<T, HASH>::remove(const T& key)
|
||||||
{
|
{
|
||||||
if (empty()) return;
|
if (empty()) return;
|
||||||
auto& bucket = get_bucket(key);
|
Vector<T>& bucket = get_bucket(key);
|
||||||
for (auto it = bucket.begin(); it != bucket.end(); it++)
|
for (size_type i = 0; i < bucket.size(); i++)
|
||||||
{
|
{
|
||||||
if (*it == key)
|
if (bucket[i] == key)
|
||||||
{
|
{
|
||||||
bucket.remove(it);
|
bucket.remove(i);
|
||||||
m_size--;
|
m_size--;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -162,17 +192,20 @@ namespace BAN
|
||||||
if (m_buckets.size() >= bucket_count)
|
if (m_buckets.size() >= bucket_count)
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
size_type new_bucket_count = Math::max<size_type>(bucket_count, m_buckets.size() * 2);
|
size_type new_bucket_count = BAN::Math::max<size_type>(bucket_count, m_buckets.size() * 2);
|
||||||
Vector<LinkedList<T>> new_buckets;
|
Vector<Vector<T>> new_buckets;
|
||||||
if (new_buckets.resize(new_bucket_count).is_error())
|
if (new_buckets.resize(new_bucket_count).is_error())
|
||||||
return Error::from_errno(ENOMEM);
|
return Error::from_errno(ENOMEM);
|
||||||
|
|
||||||
for (auto& bucket : m_buckets)
|
// NOTE: We have to copy the old keys to the new keys and not move
|
||||||
|
// since we might run out of memory half way through.
|
||||||
|
for (Vector<T>& bucket : m_buckets)
|
||||||
{
|
{
|
||||||
for (auto it = bucket.begin(); it != bucket.end();)
|
for (T& key : bucket)
|
||||||
{
|
{
|
||||||
size_type new_bucket_index = HASH()(*it) % new_buckets.size();
|
size_type bucket_index = HASH()(key) % new_buckets.size();
|
||||||
it = bucket.move_element_to_other_linked_list(new_buckets[new_bucket_index], new_buckets[new_bucket_index].end(), it);
|
if (new_buckets[bucket_index].push_back(key).is_error())
|
||||||
|
return Error::from_errno(ENOMEM);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -181,7 +214,7 @@ namespace BAN
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, typename HASH>
|
template<typename T, typename HASH>
|
||||||
LinkedList<T>& HashSet<T, HASH>::get_bucket(const T& key)
|
Vector<T>& HashSet<T, HASH>::get_bucket(const T& key)
|
||||||
{
|
{
|
||||||
ASSERT(!m_buckets.empty());
|
ASSERT(!m_buckets.empty());
|
||||||
size_type index = HASH()(key) % m_buckets.size();
|
size_type index = HASH()(key) % m_buckets.size();
|
||||||
|
@ -189,11 +222,83 @@ namespace BAN
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, typename HASH>
|
template<typename T, typename HASH>
|
||||||
const LinkedList<T>& HashSet<T, HASH>::get_bucket(const T& key) const
|
const Vector<T>& HashSet<T, HASH>::get_bucket(const T& key) const
|
||||||
{
|
{
|
||||||
ASSERT(!m_buckets.empty());
|
ASSERT(!m_buckets.empty());
|
||||||
size_type index = HASH()(key) % m_buckets.size();
|
size_type index = HASH()(key) % m_buckets.size();
|
||||||
return m_buckets[index];
|
return m_buckets[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
template<typename T, typename HASH>
|
||||||
|
HashSetIterator<T, HASH>& HashSetIterator<T, HASH>::operator++()
|
||||||
|
{
|
||||||
|
ASSERT(*this);
|
||||||
|
if (m_current_key == m_current_bucket->end())
|
||||||
|
m_current_bucket++;
|
||||||
|
else
|
||||||
|
m_current_key++;
|
||||||
|
find_next();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T, typename HASH>
|
||||||
|
HashSetIterator<T, HASH> HashSetIterator<T, HASH>::operator++(int)
|
||||||
|
{
|
||||||
|
auto temp = *this;
|
||||||
|
++(*this);
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T, typename HASH>
|
||||||
|
const T& HashSetIterator<T, HASH>::operator*() const
|
||||||
|
{
|
||||||
|
ASSERT(m_owner && m_current_bucket && m_current_key);
|
||||||
|
return *m_current_key;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T, typename HASH>
|
||||||
|
const T* HashSetIterator<T, HASH>::operator->() const
|
||||||
|
{
|
||||||
|
return &**this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T, typename HASH>
|
||||||
|
bool HashSetIterator<T, HASH>::operator==(const HashSetIterator<T, HASH>& other) const
|
||||||
|
{
|
||||||
|
if (!m_owner || m_owner != other.m_owner)
|
||||||
|
return false;
|
||||||
|
return m_current_bucket == other.m_current_bucket
|
||||||
|
&& m_current_key == other.m_current_key;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T, typename HASH>
|
||||||
|
bool HashSetIterator<T, HASH>::operator!=(const HashSetIterator<T, HASH>& other) const
|
||||||
|
{
|
||||||
|
return !(*this == other);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T, typename HASH>
|
||||||
|
HashSetIterator<T, HASH>::HashSetIterator(const HashSet<T, HASH>* owner, Vector<Vector<T>>::const_iterator bucket)
|
||||||
|
: m_owner(owner)
|
||||||
|
, m_current_bucket(bucket)
|
||||||
|
{
|
||||||
|
if (m_current_bucket != m_owner->m_buckets.end())
|
||||||
|
m_current_key = m_current_bucket->begin();
|
||||||
|
find_next();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T, typename HASH>
|
||||||
|
void HashSetIterator<T, HASH>::find_next()
|
||||||
|
{
|
||||||
|
ASSERT(m_owner && m_current_bucket);
|
||||||
|
while (m_current_bucket != m_owner->m_buckets.end())
|
||||||
|
{
|
||||||
|
if (m_current_key && m_current_key != m_current_bucket->end())
|
||||||
|
return;
|
||||||
|
m_current_bucket++;
|
||||||
|
m_current_key = m_current_bucket->begin();
|
||||||
|
}
|
||||||
|
m_current_key = typename Vector<T>::const_iterator();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,75 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <BAN/Endianness.h>
|
|
||||||
#include <BAN/Formatter.h>
|
|
||||||
#include <BAN/Hash.h>
|
|
||||||
|
|
||||||
namespace BAN
|
|
||||||
{
|
|
||||||
|
|
||||||
struct IPv4Address
|
|
||||||
{
|
|
||||||
constexpr IPv4Address(uint32_t u32_address)
|
|
||||||
{
|
|
||||||
raw = u32_address;
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr IPv4Address(uint8_t oct1, uint8_t oct2, uint8_t oct3, uint8_t oct4)
|
|
||||||
{
|
|
||||||
octets[0] = oct1;
|
|
||||||
octets[1] = oct2;
|
|
||||||
octets[2] = oct3;
|
|
||||||
octets[3] = oct4;
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr bool operator==(const IPv4Address& other) const
|
|
||||||
{
|
|
||||||
return raw == other.raw;
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr IPv4Address mask(const IPv4Address& other) const
|
|
||||||
{
|
|
||||||
return IPv4Address(raw & other.raw);
|
|
||||||
}
|
|
||||||
|
|
||||||
union
|
|
||||||
{
|
|
||||||
uint8_t octets[4];
|
|
||||||
uint32_t raw;
|
|
||||||
} __attribute__((packed));
|
|
||||||
};
|
|
||||||
static_assert(sizeof(IPv4Address) == 4);
|
|
||||||
|
|
||||||
template<>
|
|
||||||
struct hash<IPv4Address>
|
|
||||||
{
|
|
||||||
constexpr hash_t operator()(IPv4Address ipv4) const
|
|
||||||
{
|
|
||||||
return hash<uint32_t>()(ipv4.raw);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace BAN::Formatter
|
|
||||||
{
|
|
||||||
|
|
||||||
template<typename F>
|
|
||||||
void print_argument(F putc, const IPv4Address& ipv4, const ValueFormat&)
|
|
||||||
{
|
|
||||||
ValueFormat format {
|
|
||||||
.base = 10,
|
|
||||||
.percision = 0,
|
|
||||||
.fill = 0,
|
|
||||||
.upper = false,
|
|
||||||
};
|
|
||||||
|
|
||||||
print_argument(putc, ipv4.octets[0], format);
|
|
||||||
for (size_t i = 1; i < 4; i++)
|
|
||||||
{
|
|
||||||
putc('.');
|
|
||||||
print_argument(putc, ipv4.octets[i], format);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -9,4 +9,4 @@ namespace BAN
|
||||||
Break
|
Break
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
|
@ -1,180 +1,92 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <BAN/Assert.h>
|
#include <BAN/Assert.h>
|
||||||
#include <BAN/Traits.h>
|
|
||||||
|
|
||||||
#include <stddef.h>
|
|
||||||
|
|
||||||
namespace BAN
|
namespace BAN
|
||||||
{
|
{
|
||||||
|
|
||||||
template<typename It>
|
|
||||||
constexpr It next(It it, size_t count)
|
|
||||||
{
|
|
||||||
for (size_t i = 0; i < count; i++)
|
|
||||||
++it;
|
|
||||||
return it;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename It>
|
|
||||||
requires requires(It it, size_t n) { requires is_same_v<decltype(it + n), It>; }
|
|
||||||
constexpr It next(It it, size_t count)
|
|
||||||
{
|
|
||||||
return it + count;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename It>
|
|
||||||
constexpr It prev(It it, size_t count)
|
|
||||||
{
|
|
||||||
for (size_t i = 0; i < count; i++)
|
|
||||||
--it;
|
|
||||||
return it;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename It>
|
|
||||||
requires requires(It it, size_t n) { requires is_same_v<decltype(it - n), It>; }
|
|
||||||
constexpr It prev(It it, size_t count)
|
|
||||||
{
|
|
||||||
return it - count;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename It>
|
|
||||||
constexpr size_t distance(It it1, It it2)
|
|
||||||
{
|
|
||||||
size_t dist = 0;
|
|
||||||
while (it1 != it2)
|
|
||||||
{
|
|
||||||
++it1;
|
|
||||||
++dist;
|
|
||||||
}
|
|
||||||
return dist;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename It>
|
|
||||||
requires requires(It it1, It it2) { requires is_integral_v<decltype(it2 - it1)>; }
|
|
||||||
constexpr size_t distance(It it1, It it2)
|
|
||||||
{
|
|
||||||
return it2 - it1;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T, typename Container, bool CONST>
|
template<typename T, typename Container, bool CONST>
|
||||||
class IteratorSimpleGeneral
|
class IteratorSimpleGeneral
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
using value_type = T;
|
IteratorSimpleGeneral() = default;
|
||||||
|
|
||||||
public:
|
|
||||||
constexpr IteratorSimpleGeneral() = default;
|
|
||||||
template<bool CONST2, typename = enable_if_t<CONST2 == CONST || CONST>>
|
template<bool CONST2, typename = enable_if_t<CONST2 == CONST || CONST>>
|
||||||
constexpr IteratorSimpleGeneral(const IteratorSimpleGeneral<T, Container, CONST2>& other)
|
IteratorSimpleGeneral(const IteratorSimpleGeneral<T, Container, CONST2>& other)
|
||||||
: m_pointer(other.m_pointer)
|
: m_pointer(other.m_pointer)
|
||||||
, m_valid(other.m_valid)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr const T& operator*() const
|
const T& operator*() const
|
||||||
{
|
{
|
||||||
ASSERT(m_pointer);
|
ASSERT(m_pointer);
|
||||||
return *m_pointer;
|
return *m_pointer;
|
||||||
}
|
}
|
||||||
template<bool CONST2 = CONST>
|
template<bool CONST2 = CONST>
|
||||||
constexpr enable_if_t<!CONST2, T&> operator*()
|
enable_if_t<!CONST2, T&> operator*()
|
||||||
{
|
{
|
||||||
ASSERT(*this);
|
|
||||||
ASSERT(m_pointer);
|
ASSERT(m_pointer);
|
||||||
return *m_pointer;
|
return *m_pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr const T* operator->() const
|
const T* operator->() const
|
||||||
{
|
{
|
||||||
ASSERT(*this);
|
|
||||||
ASSERT(m_pointer);
|
ASSERT(m_pointer);
|
||||||
return m_pointer;
|
return m_pointer;
|
||||||
}
|
}
|
||||||
template<bool CONST2 = CONST>
|
template<bool CONST2 = CONST>
|
||||||
constexpr enable_if_t<!CONST2, T*> operator->()
|
enable_if_t<!CONST2, T*> operator->()
|
||||||
{
|
{
|
||||||
ASSERT(*this);
|
|
||||||
ASSERT(m_pointer);
|
ASSERT(m_pointer);
|
||||||
return m_pointer;
|
return m_pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr IteratorSimpleGeneral& operator++()
|
IteratorSimpleGeneral& operator++()
|
||||||
{
|
{
|
||||||
ASSERT(*this);
|
|
||||||
ASSERT(m_pointer);
|
ASSERT(m_pointer);
|
||||||
++m_pointer;
|
++m_pointer;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
constexpr IteratorSimpleGeneral operator++(int)
|
IteratorSimpleGeneral operator++(int)
|
||||||
{
|
{
|
||||||
auto temp = *this;
|
auto temp = *this;
|
||||||
++(*this);
|
++(*this);
|
||||||
return temp;
|
return temp;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr IteratorSimpleGeneral& operator--()
|
IteratorSimpleGeneral& operator--()
|
||||||
{
|
{
|
||||||
ASSERT(*this);
|
|
||||||
ASSERT(m_pointer);
|
ASSERT(m_pointer);
|
||||||
--m_pointer;
|
return --m_pointer;
|
||||||
return *this;
|
|
||||||
}
|
}
|
||||||
constexpr IteratorSimpleGeneral operator--(int)
|
IteratorSimpleGeneral operator--(int)
|
||||||
{
|
{
|
||||||
auto temp = *this;
|
auto temp = *this;
|
||||||
--(*this);
|
--(*this);
|
||||||
return temp;
|
return temp;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr size_t operator-(const IteratorSimpleGeneral& other) const
|
bool operator==(const IteratorSimpleGeneral& other) const
|
||||||
{
|
{
|
||||||
ASSERT(*this && other);
|
|
||||||
return m_pointer - other.m_pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr IteratorSimpleGeneral operator+(size_t offset) const
|
|
||||||
{
|
|
||||||
return IteratorSimpleGeneral(m_pointer + offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr IteratorSimpleGeneral operator-(size_t offset) const
|
|
||||||
{
|
|
||||||
return IteratorSimpleGeneral(m_pointer - offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr bool operator<(const IteratorSimpleGeneral& other) const
|
|
||||||
{
|
|
||||||
ASSERT(*this);
|
|
||||||
return m_pointer < other.m_pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr bool operator==(const IteratorSimpleGeneral& other) const
|
|
||||||
{
|
|
||||||
ASSERT(*this);
|
|
||||||
return m_pointer == other.m_pointer;
|
return m_pointer == other.m_pointer;
|
||||||
}
|
}
|
||||||
constexpr bool operator!=(const IteratorSimpleGeneral& other) const
|
bool operator!=(const IteratorSimpleGeneral& other) const
|
||||||
{
|
{
|
||||||
ASSERT(*this);
|
|
||||||
return !(*this == other);
|
return !(*this == other);
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr explicit operator bool() const
|
operator bool() const
|
||||||
{
|
{
|
||||||
return m_valid;
|
return m_pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
constexpr IteratorSimpleGeneral(maybe_const_t<CONST, T>* pointer)
|
IteratorSimpleGeneral(maybe_const_t<CONST, T>* pointer)
|
||||||
: m_pointer(pointer)
|
: m_pointer(pointer)
|
||||||
, m_valid(true)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
maybe_const_t<CONST, T>* m_pointer = nullptr;
|
maybe_const_t<CONST, T>* m_pointer = nullptr;
|
||||||
bool m_valid = false;
|
|
||||||
|
|
||||||
friend IteratorSimpleGeneral<T, Container, !CONST>;
|
friend IteratorSimpleGeneral<T, Container, !CONST>;
|
||||||
friend Container;
|
friend Container;
|
||||||
|
@ -190,19 +102,17 @@ namespace BAN
|
||||||
using InnerIterator = either_or_t<CONST, typename Inner::const_iterator, typename Inner::iterator>;
|
using InnerIterator = either_or_t<CONST, typename Inner::const_iterator, typename Inner::iterator>;
|
||||||
using OuterIterator = either_or_t<CONST, typename Outer::const_iterator, typename Outer::iterator>;
|
using OuterIterator = either_or_t<CONST, typename Outer::const_iterator, typename Outer::iterator>;
|
||||||
|
|
||||||
using value_type = T;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
constexpr IteratorDoubleGeneral() = default;
|
IteratorDoubleGeneral() = default;
|
||||||
template<bool CONST2, typename = enable_if_t<CONST2 == CONST || CONST>>
|
template<bool CONST2, typename = enable_if_t<CONST2 == CONST || CONST>>
|
||||||
constexpr IteratorDoubleGeneral(const IteratorDoubleGeneral<T, OuterContainer, InnerContainer, Container, CONST2>& other)
|
IteratorDoubleGeneral(const IteratorDoubleGeneral<T, OuterContainer, InnerContainer, Container, CONST2>& other)
|
||||||
: m_outer_end(other.m_outer_end)
|
: m_outer_end(other.m_outer_end)
|
||||||
, m_outer_current(other.m_outer_current)
|
, m_outer_current(other.m_outer_current)
|
||||||
, m_inner_current(other.m_inner_current)
|
, m_inner_current(other.m_inner_current)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr const T& operator*() const
|
const T& operator*() const
|
||||||
{
|
{
|
||||||
ASSERT(*this);
|
ASSERT(*this);
|
||||||
ASSERT(m_outer_current != m_outer_end);
|
ASSERT(m_outer_current != m_outer_end);
|
||||||
|
@ -210,7 +120,7 @@ namespace BAN
|
||||||
return m_inner_current.operator*();
|
return m_inner_current.operator*();
|
||||||
}
|
}
|
||||||
template<bool CONST2 = CONST>
|
template<bool CONST2 = CONST>
|
||||||
constexpr enable_if_t<!CONST2, T&> operator*()
|
enable_if_t<!CONST2, T&> operator*()
|
||||||
{
|
{
|
||||||
ASSERT(*this);
|
ASSERT(*this);
|
||||||
ASSERT(m_outer_current != m_outer_end);
|
ASSERT(m_outer_current != m_outer_end);
|
||||||
|
@ -218,7 +128,7 @@ namespace BAN
|
||||||
return m_inner_current.operator*();
|
return m_inner_current.operator*();
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr const T* operator->() const
|
const T* operator->() const
|
||||||
{
|
{
|
||||||
ASSERT(*this);
|
ASSERT(*this);
|
||||||
ASSERT(m_outer_current != m_outer_end);
|
ASSERT(m_outer_current != m_outer_end);
|
||||||
|
@ -226,7 +136,7 @@ namespace BAN
|
||||||
return m_inner_current.operator->();
|
return m_inner_current.operator->();
|
||||||
}
|
}
|
||||||
template<bool CONST2 = CONST>
|
template<bool CONST2 = CONST>
|
||||||
constexpr enable_if_t<!CONST2, T*> operator->()
|
enable_if_t<!CONST2, T*> operator->()
|
||||||
{
|
{
|
||||||
ASSERT(*this);
|
ASSERT(*this);
|
||||||
ASSERT(m_outer_current != m_outer_end);
|
ASSERT(m_outer_current != m_outer_end);
|
||||||
|
@ -234,7 +144,7 @@ namespace BAN
|
||||||
return m_inner_current.operator->();
|
return m_inner_current.operator->();
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr IteratorDoubleGeneral& operator++()
|
IteratorDoubleGeneral& operator++()
|
||||||
{
|
{
|
||||||
ASSERT(*this);
|
ASSERT(*this);
|
||||||
ASSERT(m_outer_current != m_outer_end);
|
ASSERT(m_outer_current != m_outer_end);
|
||||||
|
@ -243,37 +153,37 @@ namespace BAN
|
||||||
find_valid_or_end();
|
find_valid_or_end();
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
constexpr IteratorDoubleGeneral operator++(int)
|
IteratorDoubleGeneral operator++(int)
|
||||||
{
|
{
|
||||||
auto temp = *this;
|
auto temp = *this;
|
||||||
++(*this);
|
++(*this);
|
||||||
return temp;
|
return temp;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr bool operator==(const IteratorDoubleGeneral& other) const
|
bool operator==(const IteratorDoubleGeneral& other) const
|
||||||
{
|
{
|
||||||
ASSERT(*this && other);
|
if (!*this || !other)
|
||||||
|
return false;
|
||||||
if (m_outer_end != other.m_outer_end)
|
if (m_outer_end != other.m_outer_end)
|
||||||
return false;
|
return false;
|
||||||
if (m_outer_current != other.m_outer_current)
|
if (m_outer_current != other.m_outer_current)
|
||||||
return false;
|
return false;
|
||||||
if (m_outer_current == m_outer_end)
|
if (m_outer_current == m_outer_end)
|
||||||
return true;
|
return true;
|
||||||
ASSERT(m_inner_current && other.m_inner_current);
|
|
||||||
return m_inner_current == other.m_inner_current;
|
return m_inner_current == other.m_inner_current;
|
||||||
}
|
}
|
||||||
constexpr bool operator!=(const IteratorDoubleGeneral& other) const
|
bool operator!=(const IteratorDoubleGeneral& other) const
|
||||||
{
|
{
|
||||||
return !(*this == other);
|
return !(*this == other);
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr explicit operator bool() const
|
operator bool() const
|
||||||
{
|
{
|
||||||
return !!m_outer_current;
|
return m_outer_end && m_outer_current;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
constexpr IteratorDoubleGeneral(const OuterIterator& outer_end, const OuterIterator& outer_current)
|
IteratorDoubleGeneral(const OuterIterator& outer_end, const OuterIterator& outer_current)
|
||||||
: m_outer_end(outer_end)
|
: m_outer_end(outer_end)
|
||||||
, m_outer_current(outer_current)
|
, m_outer_current(outer_current)
|
||||||
{
|
{
|
||||||
|
@ -284,15 +194,7 @@ namespace BAN
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr IteratorDoubleGeneral(const OuterIterator& outer_end, const OuterIterator& outer_current, const InnerIterator& inner_current)
|
void find_valid_or_end()
|
||||||
: m_outer_end(outer_end)
|
|
||||||
, m_outer_current(outer_current)
|
|
||||||
, m_inner_current(inner_current)
|
|
||||||
{
|
|
||||||
find_valid_or_end();
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr void find_valid_or_end()
|
|
||||||
{
|
{
|
||||||
while (m_inner_current == m_outer_current->end())
|
while (m_inner_current == m_outer_current->end())
|
||||||
{
|
{
|
||||||
|
@ -303,9 +205,6 @@ namespace BAN
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr OuterIterator outer_current() { return m_outer_current; }
|
|
||||||
constexpr InnerIterator inner_current() { return m_inner_current; }
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
OuterIterator m_outer_end;
|
OuterIterator m_outer_end;
|
||||||
OuterIterator m_outer_current;
|
OuterIterator m_outer_current;
|
||||||
|
|
|
@ -1,156 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <BAN/Traits.h>
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
namespace BAN
|
|
||||||
{
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
class numeric_limits
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
numeric_limits() = delete;
|
|
||||||
|
|
||||||
static inline constexpr T max()
|
|
||||||
{
|
|
||||||
if constexpr(is_same_v<T, char>)
|
|
||||||
return __SCHAR_MAX__;
|
|
||||||
if constexpr(is_same_v<T, signed char>)
|
|
||||||
return __SCHAR_MAX__;
|
|
||||||
if constexpr(is_same_v<T, unsigned char>)
|
|
||||||
return (T)__SCHAR_MAX__ * 2 + 1;
|
|
||||||
|
|
||||||
if constexpr(is_same_v<T, short>)
|
|
||||||
return __SHRT_MAX__;
|
|
||||||
if constexpr(is_same_v<T, int>)
|
|
||||||
return __INT_MAX__;
|
|
||||||
if constexpr(is_same_v<T, long>)
|
|
||||||
return __LONG_MAX__;
|
|
||||||
if constexpr(is_same_v<T, long long>)
|
|
||||||
return __LONG_LONG_MAX__;
|
|
||||||
|
|
||||||
if constexpr(is_same_v<T, unsigned short>)
|
|
||||||
return (T)__SHRT_MAX__ * 2 + 1;
|
|
||||||
if constexpr(is_same_v<T, unsigned int>)
|
|
||||||
return (T)__INT_MAX__ * 2 + 1;
|
|
||||||
if constexpr(is_same_v<T, unsigned long>)
|
|
||||||
return (T)__LONG_MAX__ * 2 + 1;
|
|
||||||
if constexpr(is_same_v<T, unsigned long long>)
|
|
||||||
return (T)__LONG_LONG_MAX__ * 2 + 1;
|
|
||||||
|
|
||||||
if constexpr(is_same_v<T, float>)
|
|
||||||
return __FLT_MAX__;
|
|
||||||
if constexpr(is_same_v<T, double>)
|
|
||||||
return __DBL_MAX__;
|
|
||||||
if constexpr(is_same_v<T, long double>)
|
|
||||||
return __LDBL_MAX__;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline constexpr T min()
|
|
||||||
{
|
|
||||||
if constexpr(is_signed_v<T> && is_integral_v<T>)
|
|
||||||
return -max() - 1;
|
|
||||||
|
|
||||||
if constexpr(is_unsigned_v<T> && is_integral_v<T>)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if constexpr(is_same_v<T, float>)
|
|
||||||
return __FLT_MIN__;
|
|
||||||
if constexpr(is_same_v<T, double>)
|
|
||||||
return __DBL_MIN__;
|
|
||||||
if constexpr(is_same_v<T, long double>)
|
|
||||||
return __LDBL_MIN__;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline constexpr bool has_infinity()
|
|
||||||
{
|
|
||||||
if constexpr(is_same_v<T, float>)
|
|
||||||
return __FLT_HAS_INFINITY__;
|
|
||||||
if constexpr(is_same_v<T, double>)
|
|
||||||
return __DBL_HAS_INFINITY__;
|
|
||||||
if constexpr(is_same_v<T, long double>)
|
|
||||||
return __LDBL_HAS_INFINITY__;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline constexpr T infinity() requires(has_infinity())
|
|
||||||
{
|
|
||||||
if constexpr(is_same_v<T, float>)
|
|
||||||
return __builtin_inff();
|
|
||||||
if constexpr(is_same_v<T, double>)
|
|
||||||
return __builtin_inf();
|
|
||||||
if constexpr(is_same_v<T, long double>)
|
|
||||||
return __builtin_infl();
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline constexpr bool has_quiet_NaN()
|
|
||||||
{
|
|
||||||
if constexpr(is_same_v<T, float>)
|
|
||||||
return __FLT_HAS_QUIET_NAN__;
|
|
||||||
if constexpr(is_same_v<T, double>)
|
|
||||||
return __DBL_HAS_QUIET_NAN__;
|
|
||||||
if constexpr(is_same_v<T, long double>)
|
|
||||||
return __LDBL_HAS_QUIET_NAN__;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline constexpr T quiet_NaN() requires(has_quiet_NaN())
|
|
||||||
{
|
|
||||||
if constexpr(is_same_v<T, float>)
|
|
||||||
return __builtin_nanf("");
|
|
||||||
if constexpr(is_same_v<T, double>)
|
|
||||||
return __builtin_nan("");
|
|
||||||
if constexpr(is_same_v<T, long double>)
|
|
||||||
return __builtin_nanl("");
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline constexpr int max_exponent2()
|
|
||||||
{
|
|
||||||
static_assert(__FLT_RADIX__ == 2);
|
|
||||||
if constexpr(is_same_v<T, float>)
|
|
||||||
return __FLT_MAX_EXP__;
|
|
||||||
if constexpr(is_same_v<T, double>)
|
|
||||||
return __DBL_MAX_EXP__;
|
|
||||||
if constexpr(is_same_v<T, long double>)
|
|
||||||
return __LDBL_MAX_EXP__;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline constexpr int max_exponent10()
|
|
||||||
{
|
|
||||||
if constexpr(is_same_v<T, float>)
|
|
||||||
return __FLT_MAX_10_EXP__;
|
|
||||||
if constexpr(is_same_v<T, double>)
|
|
||||||
return __DBL_MAX_10_EXP__;
|
|
||||||
if constexpr(is_same_v<T, long double>)
|
|
||||||
return __LDBL_MAX_10_EXP__;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline constexpr int min_exponent2()
|
|
||||||
{
|
|
||||||
static_assert(__FLT_RADIX__ == 2);
|
|
||||||
if constexpr(is_same_v<T, float>)
|
|
||||||
return __FLT_MIN_EXP__;
|
|
||||||
if constexpr(is_same_v<T, double>)
|
|
||||||
return __DBL_MIN_EXP__;
|
|
||||||
if constexpr(is_same_v<T, long double>)
|
|
||||||
return __LDBL_MIN_EXP__;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline constexpr int min_exponent10()
|
|
||||||
{
|
|
||||||
if constexpr(is_same_v<T, float>)
|
|
||||||
return __FLT_MIN_10_EXP__;
|
|
||||||
if constexpr(is_same_v<T, double>)
|
|
||||||
return __DBL_MIN_10_EXP__;
|
|
||||||
if constexpr(is_same_v<T, long double>)
|
|
||||||
return __LDBL_MIN_10_EXP__;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
|
@ -3,7 +3,6 @@
|
||||||
#include <BAN/Errors.h>
|
#include <BAN/Errors.h>
|
||||||
#include <BAN/Move.h>
|
#include <BAN/Move.h>
|
||||||
#include <BAN/New.h>
|
#include <BAN/New.h>
|
||||||
#include <BAN/PlacementNew.h>
|
|
||||||
|
|
||||||
namespace BAN
|
namespace BAN
|
||||||
{
|
{
|
||||||
|
@ -22,11 +21,11 @@ namespace BAN
|
||||||
|
|
||||||
public:
|
public:
|
||||||
LinkedList() = default;
|
LinkedList() = default;
|
||||||
LinkedList(const LinkedList<T>& other) requires is_copy_constructible_v<T> { *this = other; }
|
LinkedList(const LinkedList<T>& other) { *this = other; }
|
||||||
LinkedList(LinkedList<T>&& other) { *this = move(other); }
|
LinkedList(LinkedList<T>&& other) { *this = move(other); }
|
||||||
~LinkedList() { clear(); }
|
~LinkedList() { clear(); }
|
||||||
|
|
||||||
LinkedList<T>& operator=(const LinkedList<T>&) requires is_copy_constructible_v<T>;
|
LinkedList<T>& operator=(const LinkedList<T>&);
|
||||||
LinkedList<T>& operator=(LinkedList<T>&&);
|
LinkedList<T>& operator=(LinkedList<T>&&);
|
||||||
|
|
||||||
ErrorOr<void> push_back(const T&);
|
ErrorOr<void> push_back(const T&);
|
||||||
|
@ -34,16 +33,14 @@ namespace BAN
|
||||||
ErrorOr<void> insert(iterator, const T&);
|
ErrorOr<void> insert(iterator, const T&);
|
||||||
ErrorOr<void> insert(iterator, T&&);
|
ErrorOr<void> insert(iterator, T&&);
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
ErrorOr<void> emplace_back(Args&&...) requires is_constructible_v<T, Args...>;
|
ErrorOr<void> emplace_back(Args&&...);
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
ErrorOr<void> emplace(iterator, Args&&...) requires is_constructible_v<T, Args...>;
|
ErrorOr<void> emplace(iterator, Args&&...);
|
||||||
|
|
||||||
void pop_back();
|
void pop_back();
|
||||||
iterator remove(iterator);
|
iterator remove(iterator);
|
||||||
void clear();
|
void clear();
|
||||||
|
|
||||||
iterator move_element_to_other_linked_list(LinkedList& dest_list, iterator dest_iter, iterator src_iter);
|
|
||||||
|
|
||||||
iterator begin() { return iterator(m_data, empty()); }
|
iterator begin() { return iterator(m_data, empty()); }
|
||||||
const_iterator begin() const { return const_iterator(m_data, empty()); }
|
const_iterator begin() const { return const_iterator(m_data, empty()); }
|
||||||
iterator end() { return iterator(m_last, true); }
|
iterator end() { return iterator(m_last, true); }
|
||||||
|
@ -67,11 +64,7 @@ namespace BAN
|
||||||
Node* prev;
|
Node* prev;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename... Args>
|
ErrorOr<Node*> allocate_node() const;
|
||||||
ErrorOr<Node*> allocate_node(Args&&...) const;
|
|
||||||
|
|
||||||
Node* remove_node(iterator);
|
|
||||||
void insert_node(iterator, Node*);
|
|
||||||
|
|
||||||
Node* m_data = nullptr;
|
Node* m_data = nullptr;
|
||||||
Node* m_last = nullptr;
|
Node* m_last = nullptr;
|
||||||
|
@ -122,7 +115,7 @@ namespace BAN
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
LinkedList<T>& LinkedList<T>::operator=(const LinkedList<T>& other) requires is_copy_constructible_v<T>
|
LinkedList<T>& LinkedList<T>::operator=(const LinkedList<T>& other)
|
||||||
{
|
{
|
||||||
clear();
|
clear();
|
||||||
for (const T& elem : other)
|
for (const T& elem : other)
|
||||||
|
@ -143,31 +136,6 @@ namespace BAN
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
LinkedList<T>::Node* LinkedList<T>::remove_node(iterator iter)
|
|
||||||
{
|
|
||||||
ASSERT(!empty() && iter);
|
|
||||||
Node* node = iter.m_current;
|
|
||||||
Node* prev = node->prev;
|
|
||||||
Node* next = node->next;
|
|
||||||
(prev ? prev->next : m_data) = next;
|
|
||||||
(next ? next->prev : m_last) = prev;
|
|
||||||
m_size--;
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
void LinkedList<T>::insert_node(iterator iter, Node* node)
|
|
||||||
{
|
|
||||||
Node* next = iter.m_past_end ? nullptr : iter.m_current;
|
|
||||||
Node* prev = next ? next->prev : m_last;
|
|
||||||
node->next = next;
|
|
||||||
node->prev = prev;
|
|
||||||
(prev ? prev->next : m_data) = node;
|
|
||||||
(next ? next->prev : m_last) = node;
|
|
||||||
m_size++;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
ErrorOr<void> LinkedList<T>::push_back(const T& value)
|
ErrorOr<void> LinkedList<T>::push_back(const T& value)
|
||||||
{
|
{
|
||||||
|
@ -189,31 +157,44 @@ namespace BAN
|
||||||
template<typename T>
|
template<typename T>
|
||||||
ErrorOr<void> LinkedList<T>::insert(iterator iter, T&& value)
|
ErrorOr<void> LinkedList<T>::insert(iterator iter, T&& value)
|
||||||
{
|
{
|
||||||
Node* new_node = TRY(allocate_node(move(value)));
|
Node* next = iter.m_past_end ? nullptr : iter.m_current;
|
||||||
insert_node(iter, new_node);
|
Node* prev = next ? next->prev : m_last;
|
||||||
|
Node* new_node = TRY(allocate_node());
|
||||||
|
new (&new_node->value) T(move(value));
|
||||||
|
new_node->next = next;
|
||||||
|
new_node->prev = prev;
|
||||||
|
(prev ? prev->next : m_data) = new_node;
|
||||||
|
(next ? next->prev : m_last) = new_node;
|
||||||
|
m_size++;
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
ErrorOr<void> LinkedList<T>::emplace_back(Args&&... args) requires is_constructible_v<T, Args...>
|
ErrorOr<void> LinkedList<T>::emplace_back(Args&&... args)
|
||||||
{
|
{
|
||||||
return emplace(end(), forward<Args>(args)...);
|
return emplace(end(), forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
ErrorOr<void> LinkedList<T>::emplace(iterator iter, Args&&... args) requires is_constructible_v<T, Args...>
|
ErrorOr<void> LinkedList<T>::emplace(iterator iter, Args&&... args)
|
||||||
{
|
{
|
||||||
Node* new_node = TRY(allocate_node(forward<Args>(args)...));
|
Node* next = iter.m_past_end ? nullptr : iter.m_current;
|
||||||
insert_node(iter, new_node);
|
Node* prev = next ? next->prev : m_last;
|
||||||
|
Node* new_node = TRY(allocate_node());
|
||||||
|
new (&new_node->value) T(forward<Args>(args)...);
|
||||||
|
new_node->next = next;
|
||||||
|
new_node->prev = prev;
|
||||||
|
(prev ? prev->next : m_data) = new_node;
|
||||||
|
(next ? next->prev : m_last) = new_node;
|
||||||
|
m_size++;
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
void LinkedList<T>::pop_back()
|
void LinkedList<T>::pop_back()
|
||||||
{
|
{
|
||||||
ASSERT(!empty());
|
|
||||||
remove(iterator(m_last, false));
|
remove(iterator(m_last, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -221,10 +202,14 @@ namespace BAN
|
||||||
LinkedList<T>::iterator LinkedList<T>::remove(iterator iter)
|
LinkedList<T>::iterator LinkedList<T>::remove(iterator iter)
|
||||||
{
|
{
|
||||||
ASSERT(!empty() && iter);
|
ASSERT(!empty() && iter);
|
||||||
Node* node = remove_node(iter);
|
Node* node = iter.m_current;
|
||||||
|
Node* prev = node->prev;
|
||||||
Node* next = node->next;
|
Node* next = node->next;
|
||||||
node->value.~T();
|
node->value.~T();
|
||||||
BAN::deallocator(node);
|
BAN::deallocator(node);
|
||||||
|
(prev ? prev->next : m_data) = next;
|
||||||
|
(next ? next->prev : m_last) = prev;
|
||||||
|
m_size--;
|
||||||
return next ? iterator(next, false) : iterator(m_last, true);
|
return next ? iterator(next, false) : iterator(m_last, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -244,16 +229,6 @@ namespace BAN
|
||||||
m_size = 0;
|
m_size = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
LinkedList<T>::iterator LinkedList<T>::move_element_to_other_linked_list(LinkedList& dest_list, iterator dest_iter, iterator src_iter)
|
|
||||||
{
|
|
||||||
ASSERT(!empty() && src_iter);
|
|
||||||
Node* node = remove_node(src_iter);
|
|
||||||
iterator ret = node->next ? iterator(node->next, false) : iterator(m_last, true);
|
|
||||||
dest_list.insert_node(dest_iter, node);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
const T& LinkedList<T>::back() const
|
const T& LinkedList<T>::back() const
|
||||||
{
|
{
|
||||||
|
@ -308,13 +283,11 @@ namespace BAN
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
template<typename... Args>
|
ErrorOr<typename LinkedList<T>::Node*> LinkedList<T>::allocate_node() const
|
||||||
ErrorOr<typename LinkedList<T>::Node*> LinkedList<T>::allocate_node(Args&&... args) const
|
|
||||||
{
|
{
|
||||||
Node* node = (Node*)BAN::allocator(sizeof(Node));
|
Node* node = (Node*)BAN::allocator(sizeof(Node));
|
||||||
if (node == nullptr)
|
if (node == nullptr)
|
||||||
return Error::from_errno(ENOMEM);
|
return Error::from_errno(ENOMEM);
|
||||||
new (&node->value) T(forward<Args>(args)...);
|
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -423,4 +396,4 @@ namespace BAN
|
||||||
return m_current;
|
return m_current;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -1,47 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <BAN/Formatter.h>
|
|
||||||
|
|
||||||
namespace BAN
|
|
||||||
{
|
|
||||||
|
|
||||||
struct MACAddress
|
|
||||||
{
|
|
||||||
uint8_t address[6];
|
|
||||||
|
|
||||||
constexpr bool operator==(const MACAddress& other) const
|
|
||||||
{
|
|
||||||
return
|
|
||||||
address[0] == other.address[0] &&
|
|
||||||
address[1] == other.address[1] &&
|
|
||||||
address[2] == other.address[2] &&
|
|
||||||
address[3] == other.address[3] &&
|
|
||||||
address[4] == other.address[4] &&
|
|
||||||
address[5] == other.address[5];
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace BAN::Formatter
|
|
||||||
{
|
|
||||||
|
|
||||||
template<typename F>
|
|
||||||
void print_argument(F putc, const MACAddress& mac, const ValueFormat&)
|
|
||||||
{
|
|
||||||
ValueFormat format {
|
|
||||||
.base = 16,
|
|
||||||
.percision = 0,
|
|
||||||
.fill = 2,
|
|
||||||
.upper = true,
|
|
||||||
};
|
|
||||||
|
|
||||||
print_argument(putc, mac.address[0], format);
|
|
||||||
for (size_t i = 1; i < 6; i++)
|
|
||||||
{
|
|
||||||
putc(':');
|
|
||||||
print_argument(putc, mac.address[i], format);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,20 +1,13 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <BAN/Limits.h>
|
|
||||||
#include <BAN/Numbers.h>
|
|
||||||
#include <BAN/Traits.h>
|
#include <BAN/Traits.h>
|
||||||
|
|
||||||
#include <float.h>
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
namespace BAN::Math
|
namespace BAN::Math
|
||||||
{
|
{
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
inline constexpr T abs(T x)
|
|
||||||
{
|
|
||||||
return x < 0 ? -x : x;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
inline constexpr T min(T a, T b)
|
inline constexpr T min(T a, T b)
|
||||||
{
|
{
|
||||||
|
@ -59,211 +52,41 @@ namespace BAN::Math
|
||||||
}
|
}
|
||||||
|
|
||||||
template<integral T>
|
template<integral T>
|
||||||
inline constexpr bool is_power_of_two(T x)
|
inline constexpr bool is_power_of_two(T value)
|
||||||
{
|
{
|
||||||
if (x == 0)
|
if (value == 0)
|
||||||
return false;
|
return false;
|
||||||
return (x & (x - 1)) == 0;
|
return (value & (value - 1)) == 0;
|
||||||
}
|
|
||||||
|
|
||||||
template<BAN::integral T>
|
|
||||||
static constexpr bool will_multiplication_overflow(T a, T b)
|
|
||||||
{
|
|
||||||
if (a == 0 || b == 0)
|
|
||||||
return false;
|
|
||||||
if ((a > 0) == (b > 0))
|
|
||||||
return a > BAN::numeric_limits<T>::max() / b;
|
|
||||||
else
|
|
||||||
return a < BAN::numeric_limits<T>::min() / b;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<BAN::integral T>
|
|
||||||
static constexpr bool will_addition_overflow(T a, T b)
|
|
||||||
{
|
|
||||||
if (a > 0 && b > 0)
|
|
||||||
return a > BAN::numeric_limits<T>::max() - b;
|
|
||||||
if (a < 0 && b < 0)
|
|
||||||
return a < BAN::numeric_limits<T>::min() - b;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
requires is_same_v<T, unsigned int> || is_same_v<T, unsigned long> || is_same_v<T, unsigned long long>
|
|
||||||
inline constexpr T ilog2(T x)
|
|
||||||
{
|
|
||||||
if constexpr(is_same_v<T, unsigned int>)
|
|
||||||
return sizeof(T) * 8 - __builtin_clz(x) - 1;
|
|
||||||
if constexpr(is_same_v<T, unsigned long>)
|
|
||||||
return sizeof(T) * 8 - __builtin_clzl(x) - 1;
|
|
||||||
return sizeof(T) * 8 - __builtin_clzll(x) - 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<floating_point T>
|
template<floating_point T>
|
||||||
inline constexpr T floor(T x)
|
inline constexpr T log2(T value)
|
||||||
{
|
{
|
||||||
if constexpr(is_same_v<T, float>)
|
T result;
|
||||||
return __builtin_floorf(x);
|
asm volatile("fyl2x" : "=t"(result) : "0"(value), "u"((T)1.0) : "st(1)");
|
||||||
if constexpr(is_same_v<T, double>)
|
return result;
|
||||||
return __builtin_floor(x);
|
|
||||||
if constexpr(is_same_v<T, long double>)
|
|
||||||
return __builtin_floorl(x);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<floating_point T>
|
template<floating_point T>
|
||||||
inline constexpr T ceil(T x)
|
inline constexpr T log10(T value)
|
||||||
{
|
{
|
||||||
if constexpr(is_same_v<T, float>)
|
constexpr T INV_LOG_2_10 = 0.3010299956639811952137388947244930267681898814621085413104274611;
|
||||||
return __builtin_ceilf(x);
|
T result;
|
||||||
if constexpr(is_same_v<T, double>)
|
asm volatile("fyl2x" : "=t"(result) : "0"(value), "u"(INV_LOG_2_10) : "st(1)");
|
||||||
return __builtin_ceil(x);
|
return result;
|
||||||
if constexpr(is_same_v<T, long double>)
|
|
||||||
return __builtin_ceill(x);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<floating_point T>
|
template<floating_point T>
|
||||||
inline constexpr T round(T x)
|
inline constexpr T log(T value, T base)
|
||||||
{
|
{
|
||||||
if (x == (T)0.0)
|
return log2(value) / log2(base);
|
||||||
return x;
|
|
||||||
if (x > (T)0.0)
|
|
||||||
return floor<T>(x + (T)0.5);
|
|
||||||
return ceil<T>(x - (T)0.5);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<floating_point T>
|
template<floating_point T>
|
||||||
inline constexpr T trunc(T x)
|
inline constexpr T pow(T base, T exp)
|
||||||
{
|
{
|
||||||
if constexpr(is_same_v<T, float>)
|
T result;
|
||||||
return __builtin_truncf(x);
|
asm volatile(
|
||||||
if constexpr(is_same_v<T, double>)
|
|
||||||
return __builtin_trunc(x);
|
|
||||||
if constexpr(is_same_v<T, long double>)
|
|
||||||
return __builtin_truncl(x);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<floating_point T>
|
|
||||||
inline constexpr T rint(T x)
|
|
||||||
{
|
|
||||||
asm("frndint" : "+t"(x));
|
|
||||||
return x;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<floating_point T>
|
|
||||||
inline constexpr T fmod(T a, T b)
|
|
||||||
{
|
|
||||||
asm(
|
|
||||||
"1:"
|
|
||||||
"fprem;"
|
|
||||||
"fnstsw %%ax;"
|
|
||||||
"testb $4, %%ah;"
|
|
||||||
"jne 1b;"
|
|
||||||
: "+t"(a)
|
|
||||||
: "u"(b)
|
|
||||||
: "ax"
|
|
||||||
);
|
|
||||||
return a;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<floating_point T>
|
|
||||||
static T modf(T x, T* iptr)
|
|
||||||
{
|
|
||||||
const T frac = BAN::Math::fmod<T>(x, 1);
|
|
||||||
*iptr = x - frac;
|
|
||||||
return frac;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<floating_point T>
|
|
||||||
inline constexpr T frexp(T num, int* exp)
|
|
||||||
{
|
|
||||||
if (num == 0.0)
|
|
||||||
{
|
|
||||||
*exp = 0;
|
|
||||||
return 0.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
T _exp;
|
|
||||||
asm("fxtract" : "+t"(num), "=u"(_exp));
|
|
||||||
*exp = (int)_exp + 1;
|
|
||||||
return num / (T)2.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<floating_point T>
|
|
||||||
inline constexpr T copysign(T x, T y)
|
|
||||||
{
|
|
||||||
if ((x < (T)0.0) != (y < (T)0.0))
|
|
||||||
x = -x;
|
|
||||||
return x;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace detail
|
|
||||||
{
|
|
||||||
|
|
||||||
template<floating_point T>
|
|
||||||
inline constexpr T fyl2x(T x, T y)
|
|
||||||
{
|
|
||||||
asm("fyl2x" : "+t"(x) : "u"(y) : "st(1)");
|
|
||||||
return x;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
template<floating_point T>
|
|
||||||
inline constexpr T log(T x)
|
|
||||||
{
|
|
||||||
return detail::fyl2x<T>(x, numbers::ln2_v<T>);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<floating_point T>
|
|
||||||
inline constexpr T log2(T x)
|
|
||||||
{
|
|
||||||
return detail::fyl2x<T>(x, 1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<floating_point T>
|
|
||||||
inline constexpr T log10(T x)
|
|
||||||
{
|
|
||||||
return detail::fyl2x<T>(x, numbers::lg2_v<T>);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<floating_point T>
|
|
||||||
inline constexpr T logb(T x)
|
|
||||||
{
|
|
||||||
static_assert(FLT_RADIX == 2);
|
|
||||||
return log2<T>(x);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<floating_point T>
|
|
||||||
inline constexpr T exp2(T x)
|
|
||||||
{
|
|
||||||
if (abs(x) <= (T)1.0)
|
|
||||||
{
|
|
||||||
asm("f2xm1" : "+t"(x));
|
|
||||||
return x + (T)1.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
asm(
|
|
||||||
"fld1;"
|
|
||||||
"fld %%st(1);"
|
|
||||||
"fprem;"
|
|
||||||
"f2xm1;"
|
|
||||||
"faddp;"
|
|
||||||
"fscale;"
|
|
||||||
"fstp %%st(1);"
|
|
||||||
: "+t"(x)
|
|
||||||
);
|
|
||||||
return x;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<floating_point T>
|
|
||||||
inline constexpr T exp(T x)
|
|
||||||
{
|
|
||||||
return exp2<T>(x * numbers::log2e_v<T>);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<floating_point T>
|
|
||||||
inline constexpr T pow(T x, T y)
|
|
||||||
{
|
|
||||||
asm(
|
|
||||||
"fyl2x;"
|
"fyl2x;"
|
||||||
"fld1;"
|
"fld1;"
|
||||||
"fld %%st(1);"
|
"fld %%st(1);"
|
||||||
|
@ -271,173 +94,12 @@ namespace BAN::Math
|
||||||
"f2xm1;"
|
"f2xm1;"
|
||||||
"faddp;"
|
"faddp;"
|
||||||
"fscale;"
|
"fscale;"
|
||||||
: "+t"(x), "+u"(y)
|
"fxch %%st(1);"
|
||||||
|
"fstp %%st;"
|
||||||
|
: "=t"(result)
|
||||||
|
: "0"(base), "u"(exp)
|
||||||
);
|
);
|
||||||
|
return result;
|
||||||
return x;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<floating_point T>
|
}
|
||||||
inline constexpr T scalbn(T x, int n)
|
|
||||||
{
|
|
||||||
asm("fscale" : "+t"(x) : "u"(static_cast<T>(n)));
|
|
||||||
return x;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<floating_point T>
|
|
||||||
inline constexpr T ldexp(T x, int y)
|
|
||||||
{
|
|
||||||
const bool exp_sign = y < 0;
|
|
||||||
if (exp_sign)
|
|
||||||
y = -y;
|
|
||||||
|
|
||||||
T exp = (T)1.0;
|
|
||||||
T mult = (T)2.0;
|
|
||||||
while (y)
|
|
||||||
{
|
|
||||||
if (y & 1)
|
|
||||||
exp *= mult;
|
|
||||||
mult *= mult;
|
|
||||||
y >>= 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (exp_sign)
|
|
||||||
exp = (T)1.0 / exp;
|
|
||||||
|
|
||||||
return x * exp;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<floating_point T>
|
|
||||||
inline constexpr T sqrt(T x)
|
|
||||||
{
|
|
||||||
asm("fsqrt" : "+t"(x));
|
|
||||||
return x;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<floating_point T>
|
|
||||||
inline constexpr T cbrt(T value)
|
|
||||||
{
|
|
||||||
if (value == 0.0)
|
|
||||||
return 0.0;
|
|
||||||
return pow<T>(value, 1.0 / 3.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<floating_point T>
|
|
||||||
inline constexpr T sin(T x)
|
|
||||||
{
|
|
||||||
asm("fsin" : "+t"(x));
|
|
||||||
return x;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<floating_point T>
|
|
||||||
inline constexpr T cos(T x)
|
|
||||||
{
|
|
||||||
asm("fcos" : "+t"(x));
|
|
||||||
return x;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<floating_point T>
|
|
||||||
inline constexpr void sincos(T x, T& sin, T& cos)
|
|
||||||
{
|
|
||||||
asm("fsincos" : "=t"(cos), "=u"(sin) : "0"(x));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<floating_point T>
|
|
||||||
inline constexpr T tan(T x)
|
|
||||||
{
|
|
||||||
T one, ret;
|
|
||||||
asm(
|
|
||||||
"fptan"
|
|
||||||
: "=t"(one), "=u"(ret)
|
|
||||||
: "0"(x)
|
|
||||||
);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<floating_point T>
|
|
||||||
inline constexpr T atan2(T y, T x)
|
|
||||||
{
|
|
||||||
asm(
|
|
||||||
"fpatan"
|
|
||||||
: "+t"(x)
|
|
||||||
: "u"(y)
|
|
||||||
: "st(1)"
|
|
||||||
);
|
|
||||||
return x;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<floating_point T>
|
|
||||||
inline constexpr T atan(T x)
|
|
||||||
{
|
|
||||||
return atan2<T>(x, 1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<floating_point T>
|
|
||||||
inline constexpr T asin(T x)
|
|
||||||
{
|
|
||||||
if (x == (T)0.0)
|
|
||||||
return (T)0.0;
|
|
||||||
if (x == (T)1.0)
|
|
||||||
return numbers::pi_v<T> / (T)2.0;
|
|
||||||
if (x == (T)-1.0)
|
|
||||||
return -numbers::pi_v<T> / (T)2.0;
|
|
||||||
return (T)2.0 * atan<T>(x / (T(1.0) + sqrt<T>((T)1.0 - x * x)));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<floating_point T>
|
|
||||||
inline constexpr T acos(T x)
|
|
||||||
{
|
|
||||||
if (x == (T)0.0)
|
|
||||||
return numbers::pi_v<T> / (T)2.0;
|
|
||||||
if (x == (T)1.0)
|
|
||||||
return (T)0.0;
|
|
||||||
if (x == (T)-1.0)
|
|
||||||
return numbers::pi_v<T>;
|
|
||||||
return (T)2.0 * atan<T>(sqrt<T>((T)1.0 - x * x) / ((T)1.0 + x));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<floating_point T>
|
|
||||||
inline constexpr T sinh(T x)
|
|
||||||
{
|
|
||||||
return (exp<T>(x) - exp<T>(-x)) / (T)2.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<floating_point T>
|
|
||||||
inline constexpr T cosh(T x)
|
|
||||||
{
|
|
||||||
return (exp<T>(x) + exp<T>(-x)) / (T)2.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<floating_point T>
|
|
||||||
inline constexpr T tanh(T x)
|
|
||||||
{
|
|
||||||
const T exp_px = exp<T>(x);
|
|
||||||
const T exp_nx = exp<T>(-x);
|
|
||||||
return (exp_px - exp_nx) / (exp_px + exp_nx);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<floating_point T>
|
|
||||||
inline constexpr T asinh(T x)
|
|
||||||
{
|
|
||||||
return log<T>(x + sqrt<T>(x * x + (T)1.0));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<floating_point T>
|
|
||||||
inline constexpr T acosh(T x)
|
|
||||||
{
|
|
||||||
return log<T>(x + sqrt<T>(x * x - (T)1.0));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<floating_point T>
|
|
||||||
inline constexpr T atanh(T x)
|
|
||||||
{
|
|
||||||
return (T)0.5 * log<T>(((T)1.0 + x) / ((T)1.0 - x));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<floating_point T>
|
|
||||||
inline constexpr T hypot(T x, T y)
|
|
||||||
{
|
|
||||||
return sqrt<T>(x * x + y * y);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -27,3 +27,6 @@ namespace BAN
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void* operator new(size_t, void* addr) { return addr; }
|
||||||
|
inline void* operator new[](size_t, void* addr) { return addr; }
|
|
@ -1,28 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <BAN/Traits.h>
|
|
||||||
|
|
||||||
namespace BAN::numbers
|
|
||||||
{
|
|
||||||
|
|
||||||
template<floating_point T> inline constexpr T e_v = 2.71828182845904523536;
|
|
||||||
template<floating_point T> inline constexpr T log2e_v = 1.44269504088896340736;
|
|
||||||
template<floating_point T> inline constexpr T lge_v = 0.43429448190325182765;
|
|
||||||
template<floating_point T> inline constexpr T lg2_v = 0.30102999566398119521;
|
|
||||||
template<floating_point T> inline constexpr T ln2_v = 0.69314718055994530942;
|
|
||||||
template<floating_point T> inline constexpr T ln10_v = 2.30258509299404568402;
|
|
||||||
template<floating_point T> inline constexpr T pi_v = 3.14159265358979323846;
|
|
||||||
template<floating_point T> inline constexpr T sqrt2_v = 1.41421356237309504880;
|
|
||||||
template<floating_point T> inline constexpr T sqrt3_v = 1.73205080756887729353;
|
|
||||||
|
|
||||||
inline constexpr double e = e_v<double>;
|
|
||||||
inline constexpr double log2e = log2e_v<double>;
|
|
||||||
inline constexpr double lge = lge_v<double>;
|
|
||||||
inline constexpr double lg2 = lge_v<double>;
|
|
||||||
inline constexpr double ln2 = ln2_v<double>;
|
|
||||||
inline constexpr double ln10 = ln10_v<double>;
|
|
||||||
inline constexpr double pi = pi_v<double>;
|
|
||||||
inline constexpr double sqrt2 = sqrt2_v<double>;
|
|
||||||
inline constexpr double sqrt3 = sqrt3_v<double>;
|
|
||||||
|
|
||||||
}
|
|
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
#include <BAN/Assert.h>
|
#include <BAN/Assert.h>
|
||||||
#include <BAN/Move.h>
|
#include <BAN/Move.h>
|
||||||
#include <BAN/PlacementNew.h>
|
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
@ -13,48 +12,48 @@ namespace BAN
|
||||||
class Optional
|
class Optional
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
constexpr Optional();
|
Optional();
|
||||||
constexpr Optional(Optional&&);
|
Optional(Optional&&);
|
||||||
constexpr Optional(const Optional&);
|
Optional(const Optional&);
|
||||||
constexpr Optional(const T&);
|
Optional(const T&);
|
||||||
constexpr Optional(T&&);
|
Optional(T&&);
|
||||||
|
template<typename... Args>
|
||||||
|
Optional(Args&&...);
|
||||||
|
|
||||||
~Optional();
|
~Optional();
|
||||||
|
|
||||||
constexpr Optional& operator=(Optional&&);
|
Optional& operator=(Optional&&);
|
||||||
constexpr Optional& operator=(const Optional&);
|
Optional& operator=(const Optional&);
|
||||||
|
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
constexpr Optional& emplace(Args&&...) requires is_constructible_v<T, Args...>;
|
Optional& emplace(Args&&...);
|
||||||
|
|
||||||
constexpr T* operator->();
|
T* operator->();
|
||||||
constexpr const T* operator->() const;
|
const T* operator->() const;
|
||||||
|
|
||||||
constexpr T& operator*();
|
T& operator*();
|
||||||
constexpr const T& operator*() const;
|
const T& operator*() const;
|
||||||
|
|
||||||
constexpr bool has_value() const;
|
bool has_value() const;
|
||||||
|
|
||||||
constexpr T release_value();
|
T release_value();
|
||||||
constexpr T& value();
|
T& value();
|
||||||
constexpr const T& value() const;
|
const T& value() const;
|
||||||
constexpr T& value_or(T&);
|
|
||||||
constexpr const T& value_or(const T&) const;
|
|
||||||
|
|
||||||
constexpr void clear();
|
void clear();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
alignas(T) uint8_t m_storage[sizeof(T)] {};
|
alignas(T) uint8_t m_storage[sizeof(T)];
|
||||||
bool m_has_value { false };
|
bool m_has_value { false };
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
constexpr Optional<T>::Optional()
|
Optional<T>::Optional()
|
||||||
: m_has_value(false)
|
: m_has_value(false)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
constexpr Optional<T>::Optional(Optional<T>&& other)
|
Optional<T>::Optional(Optional<T>&& other)
|
||||||
: m_has_value(other.has_value())
|
: m_has_value(other.has_value())
|
||||||
{
|
{
|
||||||
if (other.has_value())
|
if (other.has_value())
|
||||||
|
@ -62,7 +61,7 @@ namespace BAN
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
constexpr Optional<T>::Optional(const Optional<T>& other)
|
Optional<T>::Optional(const Optional<T>& other)
|
||||||
: m_has_value(other.has_value())
|
: m_has_value(other.has_value())
|
||||||
{
|
{
|
||||||
if (other.has_value())
|
if (other.has_value())
|
||||||
|
@ -70,19 +69,27 @@ namespace BAN
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
constexpr Optional<T>::Optional(const T& value)
|
Optional<T>::Optional(const T& value)
|
||||||
: m_has_value(true)
|
: m_has_value(true)
|
||||||
{
|
{
|
||||||
new (m_storage) T(value);
|
new (m_storage) T(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
constexpr Optional<T>::Optional(T&& value)
|
Optional<T>::Optional(T&& value)
|
||||||
: m_has_value(true)
|
: m_has_value(true)
|
||||||
{
|
{
|
||||||
new (m_storage) T(move(value));
|
new (m_storage) T(move(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
template<typename... Args>
|
||||||
|
Optional<T>::Optional(Args&&... args)
|
||||||
|
: m_has_value(true)
|
||||||
|
{
|
||||||
|
new (m_storage) T(forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
Optional<T>::~Optional()
|
Optional<T>::~Optional()
|
||||||
{
|
{
|
||||||
|
@ -90,7 +97,7 @@ namespace BAN
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
constexpr Optional<T>& Optional<T>::operator=(Optional&& other)
|
Optional<T>& Optional<T>::operator=(Optional&& other)
|
||||||
{
|
{
|
||||||
clear();
|
clear();
|
||||||
m_has_value = other.has_value();
|
m_has_value = other.has_value();
|
||||||
|
@ -100,18 +107,18 @@ namespace BAN
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
constexpr Optional<T>& Optional<T>::operator=(const Optional& other)
|
Optional<T>& Optional<T>::operator=(const Optional& other)
|
||||||
{
|
{
|
||||||
clear();
|
clear();
|
||||||
m_has_value = other.has_value();
|
m_has_value = other.has_value();
|
||||||
if (other.has_value())
|
if (other.has_value)
|
||||||
new (m_storage) T(other.value());
|
new (m_storage) T(other.value());
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
constexpr Optional<T>& Optional<T>::emplace(Args&&... args) requires is_constructible_v<T, Args...>
|
Optional<T>& Optional<T>::emplace(Args&&... args)
|
||||||
{
|
{
|
||||||
clear();
|
clear();
|
||||||
m_has_value = true;
|
m_has_value = true;
|
||||||
|
@ -120,41 +127,41 @@ namespace BAN
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
constexpr T* Optional<T>::operator->()
|
T* Optional<T>::operator->()
|
||||||
{
|
{
|
||||||
ASSERT(has_value());
|
ASSERT(has_value());
|
||||||
return &value();
|
return &value();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
constexpr const T* Optional<T>::operator->() const
|
const T* Optional<T>::operator->() const
|
||||||
{
|
{
|
||||||
ASSERT(has_value());
|
ASSERT(has_value());
|
||||||
return &value();
|
return &value();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
constexpr T& Optional<T>::operator*()
|
T& Optional<T>::operator*()
|
||||||
{
|
{
|
||||||
ASSERT(has_value());
|
ASSERT(has_value());
|
||||||
return value();
|
return value();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
constexpr const T& Optional<T>::operator*() const
|
const T& Optional<T>::operator*() const
|
||||||
{
|
{
|
||||||
ASSERT(has_value());
|
ASSERT(has_value());
|
||||||
return value();
|
return value();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
constexpr bool Optional<T>::has_value() const
|
bool Optional<T>::has_value() const
|
||||||
{
|
{
|
||||||
return m_has_value;
|
return m_has_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
constexpr T Optional<T>::release_value()
|
T Optional<T>::release_value()
|
||||||
{
|
{
|
||||||
ASSERT(has_value());
|
ASSERT(has_value());
|
||||||
T released_value = move(value());
|
T released_value = move(value());
|
||||||
|
@ -164,41 +171,25 @@ namespace BAN
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
constexpr T& Optional<T>::value()
|
T& Optional<T>::value()
|
||||||
{
|
{
|
||||||
ASSERT(has_value());
|
ASSERT(has_value());
|
||||||
return *reinterpret_cast<T*>(&m_storage);
|
return (T&)m_storage;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
constexpr const T& Optional<T>::value() const
|
const T& Optional<T>::value() const
|
||||||
{
|
{
|
||||||
ASSERT(has_value());
|
ASSERT(has_value());
|
||||||
return *reinterpret_cast<const T*>(&m_storage);
|
return (const T&)m_storage;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
constexpr T& Optional<T>::value_or(T& empty)
|
void Optional<T>::clear()
|
||||||
{
|
|
||||||
if (!has_value())
|
|
||||||
return empty;
|
|
||||||
return value();
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
constexpr const T& Optional<T>::value_or(const T& empty) const
|
|
||||||
{
|
|
||||||
if (!has_value())
|
|
||||||
return empty;
|
|
||||||
return value();
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
constexpr void Optional<T>::clear()
|
|
||||||
{
|
{
|
||||||
if (m_has_value)
|
if (m_has_value)
|
||||||
value().~T();
|
value().~T();
|
||||||
m_has_value = false;
|
m_has_value = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -1,10 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#if __has_include(<new>)
|
|
||||||
#include <new>
|
|
||||||
#else
|
|
||||||
#include <stddef.h>
|
|
||||||
|
|
||||||
inline void* operator new(size_t, void* addr) { return addr; }
|
|
||||||
inline void* operator new[](size_t, void* addr) { return addr; }
|
|
||||||
#endif
|
|
|
@ -5,7 +5,6 @@
|
||||||
#include <BAN/Math.h>
|
#include <BAN/Math.h>
|
||||||
#include <BAN/Move.h>
|
#include <BAN/Move.h>
|
||||||
#include <BAN/New.h>
|
#include <BAN/New.h>
|
||||||
#include <BAN/PlacementNew.h>
|
|
||||||
|
|
||||||
namespace BAN
|
namespace BAN
|
||||||
{
|
{
|
||||||
|
@ -31,7 +30,7 @@ namespace BAN
|
||||||
ErrorOr<void> push(T&&);
|
ErrorOr<void> push(T&&);
|
||||||
ErrorOr<void> push(const T&);
|
ErrorOr<void> push(const T&);
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
ErrorOr<void> emplace(Args&&...) requires is_constructible_v<T, Args...>;
|
ErrorOr<void> emplace(Args&&...);
|
||||||
|
|
||||||
ErrorOr<void> reserve(size_type);
|
ErrorOr<void> reserve(size_type);
|
||||||
ErrorOr<void> shrink_to_fit();
|
ErrorOr<void> shrink_to_fit();
|
||||||
|
@ -45,7 +44,6 @@ namespace BAN
|
||||||
void clear();
|
void clear();
|
||||||
|
|
||||||
bool empty() const;
|
bool empty() const;
|
||||||
size_type capacity() const;
|
|
||||||
size_type size() const;
|
size_type size() const;
|
||||||
|
|
||||||
const T& front() const;
|
const T& front() const;
|
||||||
|
@ -131,7 +129,7 @@ namespace BAN
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
ErrorOr<void> Queue<T>::emplace(Args&&... args) requires is_constructible_v<T, Args...>
|
ErrorOr<void> Queue<T>::emplace(Args&&... args)
|
||||||
{
|
{
|
||||||
TRY(ensure_capacity(m_size + 1));
|
TRY(ensure_capacity(m_size + 1));
|
||||||
new (m_data + m_size) T(forward<Args>(args)...);
|
new (m_data + m_size) T(forward<Args>(args)...);
|
||||||
|
@ -187,12 +185,6 @@ namespace BAN
|
||||||
return m_size == 0;
|
return m_size == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
typename Queue<T>::size_type Queue<T>::capacity() const
|
|
||||||
{
|
|
||||||
return m_capacity;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
typename Queue<T>::size_type Queue<T>::size() const
|
typename Queue<T>::size_type Queue<T>::size() const
|
||||||
{
|
{
|
||||||
|
@ -233,4 +225,4 @@ namespace BAN
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -1,6 +1,5 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <BAN/Atomic.h>
|
|
||||||
#include <BAN/Errors.h>
|
#include <BAN/Errors.h>
|
||||||
#include <BAN/Move.h>
|
#include <BAN/Move.h>
|
||||||
#include <BAN/NoCopyMove.h>
|
#include <BAN/NoCopyMove.h>
|
||||||
|
@ -23,36 +22,24 @@ namespace BAN
|
||||||
|
|
||||||
void ref() const
|
void ref() const
|
||||||
{
|
{
|
||||||
uint32_t old = m_ref_count.fetch_add(1, MemoryOrder::memory_order_relaxed);
|
ASSERT(m_ref_count > 0);
|
||||||
ASSERT(old > 0);
|
m_ref_count++;
|
||||||
}
|
|
||||||
|
|
||||||
bool try_ref() const
|
|
||||||
{
|
|
||||||
uint32_t expected = m_ref_count.load(MemoryOrder::memory_order_relaxed);
|
|
||||||
for (;;)
|
|
||||||
{
|
|
||||||
if (expected == 0)
|
|
||||||
return false;
|
|
||||||
if (m_ref_count.compare_exchange(expected, expected + 1, MemoryOrder::memory_order_acquire))
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void unref() const
|
void unref() const
|
||||||
{
|
{
|
||||||
uint32_t old = m_ref_count.fetch_sub(1);
|
ASSERT(m_ref_count > 0);
|
||||||
ASSERT(old > 0);
|
m_ref_count--;
|
||||||
if (old == 1)
|
if (m_ref_count == 0)
|
||||||
delete static_cast<const T*>(this);
|
delete (const T*)this;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
RefCounted() = default;
|
RefCounted() = default;
|
||||||
virtual ~RefCounted() { ASSERT(m_ref_count == 0); }
|
~RefCounted() { ASSERT(m_ref_count == 0); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
mutable Atomic<uint32_t> m_ref_count = 1;
|
mutable uint32_t m_ref_count = 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
|
@ -76,9 +63,8 @@ namespace BAN
|
||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: don't use is_constructible_v<T, Args...> as RefPtr<T> is allowed with friends
|
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
static ErrorOr<RefPtr> create(Args&&... args) requires requires(Args&&... args) { T(forward<Args>(args)...); }
|
static ErrorOr<RefPtr> create(Args&&... args)
|
||||||
{
|
{
|
||||||
T* pointer = new T(forward<Args>(args)...);
|
T* pointer = new T(forward<Args>(args)...);
|
||||||
if (pointer == nullptr)
|
if (pointer == nullptr)
|
||||||
|
@ -138,11 +124,8 @@ namespace BAN
|
||||||
T* operator->() { return ptr(); }
|
T* operator->() { return ptr(); }
|
||||||
const T* operator->() const { return ptr(); }
|
const T* operator->() const { return ptr(); }
|
||||||
|
|
||||||
bool operator==(RefPtr other) const { return m_pointer == other.m_pointer; }
|
|
||||||
bool operator!=(RefPtr other) const { return m_pointer != other.m_pointer; }
|
|
||||||
|
|
||||||
bool empty() const { return m_pointer == nullptr; }
|
bool empty() const { return m_pointer == nullptr; }
|
||||||
explicit operator bool() const { return m_pointer; }
|
operator bool() const { return m_pointer; }
|
||||||
|
|
||||||
void clear()
|
void clear()
|
||||||
{
|
{
|
||||||
|
|
|
@ -25,4 +25,4 @@ namespace BAN
|
||||||
bool m_enabled { true };
|
bool m_enabled { true };
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
|
@ -1,240 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <BAN/Math.h>
|
|
||||||
#include <BAN/Swap.h>
|
|
||||||
#include <BAN/Traits.h>
|
|
||||||
#include <BAN/Vector.h>
|
|
||||||
|
|
||||||
namespace BAN::sort
|
|
||||||
{
|
|
||||||
|
|
||||||
template<typename It, typename Comp = less<typename It::value_type>>
|
|
||||||
void exchange_sort(It begin, It end, Comp comp = {})
|
|
||||||
{
|
|
||||||
for (It lhs = begin; lhs != end; ++lhs)
|
|
||||||
for (It rhs = next(lhs, 1); rhs != end; ++rhs)
|
|
||||||
if (!comp(*lhs, *rhs))
|
|
||||||
swap(*lhs, *rhs);
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace detail
|
|
||||||
{
|
|
||||||
|
|
||||||
template<typename It, typename Comp>
|
|
||||||
It partition(It begin, It end, Comp comp)
|
|
||||||
{
|
|
||||||
It pivot = prev(end, 1);
|
|
||||||
|
|
||||||
It it1 = begin;
|
|
||||||
for (It it2 = begin; it2 != pivot; ++it2)
|
|
||||||
{
|
|
||||||
if (comp(*it2, *pivot))
|
|
||||||
{
|
|
||||||
swap(*it1, *it2);
|
|
||||||
++it1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
swap(*it1, *pivot);
|
|
||||||
|
|
||||||
return it1;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename It, typename Comp = less<typename It::value_type>>
|
|
||||||
void quick_sort(It begin, It end, Comp comp = {})
|
|
||||||
{
|
|
||||||
if (distance(begin, end) <= 1)
|
|
||||||
return;
|
|
||||||
It mid = detail::partition(begin, end, comp);
|
|
||||||
quick_sort(begin, mid, comp);
|
|
||||||
quick_sort(++mid, end, comp);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename It, typename Comp = less<typename It::value_type>>
|
|
||||||
void insertion_sort(It begin, It end, Comp comp = {})
|
|
||||||
{
|
|
||||||
if (distance(begin, end) <= 1)
|
|
||||||
return;
|
|
||||||
for (It it1 = next(begin, 1); it1 != end; ++it1)
|
|
||||||
{
|
|
||||||
typename It::value_type x = move(*it1);
|
|
||||||
It it2 = it1;
|
|
||||||
for (; it2 != begin && comp(x, *prev(it2, 1)); --it2)
|
|
||||||
*it2 = move(*prev(it2, 1));
|
|
||||||
*it2 = move(x);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace detail
|
|
||||||
{
|
|
||||||
|
|
||||||
template<typename It, typename Comp>
|
|
||||||
void push_heap(It begin, size_t hole_index, size_t top_index, typename It::value_type value, Comp comp)
|
|
||||||
{
|
|
||||||
size_t parent = (hole_index - 1) / 2;
|
|
||||||
while (hole_index > top_index && comp(*next(begin, parent), value))
|
|
||||||
{
|
|
||||||
*next(begin, hole_index) = move(*next(begin, parent));
|
|
||||||
hole_index = parent;
|
|
||||||
parent = (hole_index - 1) / 2;
|
|
||||||
}
|
|
||||||
*next(begin, hole_index) = move(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename It, typename Comp>
|
|
||||||
void adjust_heap(It begin, size_t hole_index, size_t len, typename It::value_type value, Comp comp)
|
|
||||||
{
|
|
||||||
const size_t top_index = hole_index;
|
|
||||||
size_t child = hole_index;
|
|
||||||
while (child < (len - 1) / 2)
|
|
||||||
{
|
|
||||||
child = 2 * (child + 1);
|
|
||||||
if (comp(*next(begin, child), *next(begin, child - 1)))
|
|
||||||
child--;
|
|
||||||
*next(begin, hole_index) = move(*next(begin, child));
|
|
||||||
hole_index = child;
|
|
||||||
}
|
|
||||||
if (len % 2 == 0 && child == (len - 2) / 2)
|
|
||||||
{
|
|
||||||
child = 2 * (child + 1);
|
|
||||||
*next(begin, hole_index) = move(*next(begin, child - 1));
|
|
||||||
hole_index = child - 1;
|
|
||||||
}
|
|
||||||
push_heap(begin, hole_index, top_index, move(value), comp);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename It, typename Comp = less<typename It::value_type>>
|
|
||||||
void make_heap(It begin, It end, Comp comp = {})
|
|
||||||
{
|
|
||||||
const size_t len = distance(begin, end);
|
|
||||||
if (len <= 1)
|
|
||||||
return;
|
|
||||||
|
|
||||||
size_t parent = (len - 2) / 2;
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
detail::adjust_heap(begin, parent, len, move(*next(begin, parent)), comp);
|
|
||||||
|
|
||||||
if (parent == 0)
|
|
||||||
break;
|
|
||||||
|
|
||||||
parent--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename It, typename Comp = less<typename It::value_type>>
|
|
||||||
void sort_heap(It begin, It end, Comp comp = {})
|
|
||||||
{
|
|
||||||
const size_t len = distance(begin, end);
|
|
||||||
if (len <= 1)
|
|
||||||
return;
|
|
||||||
|
|
||||||
size_t last = len;
|
|
||||||
while (last > 1)
|
|
||||||
{
|
|
||||||
last--;
|
|
||||||
typename It::value_type x = move(*next(begin, last));
|
|
||||||
*next(begin, last) = move(*begin);
|
|
||||||
detail::adjust_heap(begin, 0, last, move(x), comp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename It, typename Comp = less<typename It::value_type>>
|
|
||||||
void heap_sort(It begin, It end, Comp comp = {})
|
|
||||||
{
|
|
||||||
make_heap(begin, end, comp);
|
|
||||||
sort_heap(begin, end, comp);
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace detail
|
|
||||||
{
|
|
||||||
|
|
||||||
template<typename It, typename Comp>
|
|
||||||
void intro_sort_impl(It begin, It end, size_t max_depth, Comp comp)
|
|
||||||
{
|
|
||||||
if (distance(begin, end) <= 16)
|
|
||||||
return insertion_sort(begin, end, comp);
|
|
||||||
if (max_depth == 0)
|
|
||||||
return heap_sort(begin, end, comp);
|
|
||||||
It mid = detail::partition(begin, end, comp);
|
|
||||||
intro_sort_impl(begin, mid, max_depth - 1, comp);
|
|
||||||
intro_sort_impl(++mid, end, max_depth - 1, comp);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename It, typename Comp = less<typename It::value_type>>
|
|
||||||
void intro_sort(It begin, It end, Comp comp = {})
|
|
||||||
{
|
|
||||||
const size_t len = distance(begin, end);
|
|
||||||
if (len <= 1)
|
|
||||||
return;
|
|
||||||
detail::intro_sort_impl(begin, end, 2 * Math::ilog2(len), comp);
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace detail
|
|
||||||
{
|
|
||||||
|
|
||||||
template<unsigned_integral T>
|
|
||||||
consteval T lsb_index(T value)
|
|
||||||
{
|
|
||||||
for (T result = 0;; result++)
|
|
||||||
if (value & (1 << result))
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename It, size_t radix = 256>
|
|
||||||
requires is_unsigned_v<typename It::value_type> && (radix > 0 && (radix & (radix - 1)) == 0)
|
|
||||||
BAN::ErrorOr<void> radix_sort(It begin, It end)
|
|
||||||
{
|
|
||||||
using value_type = typename It::value_type;
|
|
||||||
|
|
||||||
const size_t len = distance(begin, end);
|
|
||||||
if (len <= 1)
|
|
||||||
return {};
|
|
||||||
|
|
||||||
Vector<value_type> temp;
|
|
||||||
TRY(temp.resize(len));
|
|
||||||
|
|
||||||
Vector<size_t> counts;
|
|
||||||
TRY(counts.resize(radix));
|
|
||||||
|
|
||||||
constexpr size_t mask = radix - 1;
|
|
||||||
constexpr size_t shift = detail::lsb_index(radix);
|
|
||||||
|
|
||||||
for (size_t s = 0; s < sizeof(value_type) * 8; s += shift)
|
|
||||||
{
|
|
||||||
for (auto& cnt : counts)
|
|
||||||
cnt = 0;
|
|
||||||
for (It it = begin; it != end; ++it)
|
|
||||||
counts[(*it >> s) & mask]++;
|
|
||||||
|
|
||||||
for (size_t i = 0; i < radix - 1; i++)
|
|
||||||
counts[i + 1] += counts[i];
|
|
||||||
|
|
||||||
for (It it = end; it != begin;)
|
|
||||||
{
|
|
||||||
--it;
|
|
||||||
temp[--counts[(*it >> s) & mask]] = *it;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t j = 0; j < temp.size(); j++)
|
|
||||||
*next(begin, j) = temp[j];
|
|
||||||
}
|
|
||||||
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename It, typename Comp = less<typename It::value_type>>
|
|
||||||
void sort(It begin, It end, Comp comp = {})
|
|
||||||
{
|
|
||||||
return intro_sort(begin, end, comp);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -14,91 +14,121 @@ namespace BAN
|
||||||
public:
|
public:
|
||||||
using value_type = T;
|
using value_type = T;
|
||||||
using size_type = size_t;
|
using size_type = size_t;
|
||||||
using iterator = IteratorSimple<value_type, Span>;
|
using iterator = IteratorSimple<T, Span>;
|
||||||
using const_iterator = ConstIteratorSimple<value_type, Span>;
|
using const_iterator = ConstIteratorSimple<T, Span>;
|
||||||
|
|
||||||
private:
|
|
||||||
template<typename S>
|
|
||||||
static inline constexpr bool can_init_from_v = is_same_v<value_type, const S> || is_same_v<value_type, S>;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Span() = default;
|
Span() = default;
|
||||||
Span(value_type* data, size_type size)
|
Span(T*, size_type);
|
||||||
: m_data(data)
|
Span(Span<T>&);
|
||||||
, m_size(size)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
template<typename S>
|
template<typename S>
|
||||||
Span(const Span<S>& other) requires can_init_from_v<S>
|
requires(is_same_v<T, const S>)
|
||||||
: m_data(other.m_data)
|
Span(const Span<S>&);
|
||||||
, m_size(other.m_size)
|
|
||||||
{ }
|
|
||||||
template<typename S>
|
|
||||||
Span(Span<S>&& other) requires can_init_from_v<S>
|
|
||||||
: m_data(other.m_data)
|
|
||||||
, m_size(other.m_size)
|
|
||||||
{
|
|
||||||
other.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename S>
|
|
||||||
Span& operator=(const Span<S>& other) requires can_init_from_v<S>
|
|
||||||
{
|
|
||||||
m_data = other.m_data;
|
|
||||||
m_size = other.m_size;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
template<typename S>
|
|
||||||
Span& operator=(Span<S>&& other) requires can_init_from_v<S>
|
|
||||||
{
|
|
||||||
m_data = other.m_data;
|
|
||||||
m_size = other.m_size;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
iterator begin() { return iterator(m_data); }
|
iterator begin() { return iterator(m_data); }
|
||||||
iterator end() { return iterator(m_data + m_size); }
|
iterator end() { return iterator(m_data + m_size); }
|
||||||
const_iterator begin() const { return const_iterator(m_data); }
|
const_iterator begin() const { return const_iterator(m_data); }
|
||||||
const_iterator end() const { return const_iterator(m_data + m_size); }
|
const_iterator end() const { return const_iterator(m_data + m_size); }
|
||||||
|
|
||||||
value_type& operator[](size_type index) const
|
T& operator[](size_type);
|
||||||
{
|
const T& operator[](size_type) const;
|
||||||
ASSERT(index < m_size);
|
|
||||||
return m_data[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
value_type* data() const
|
T* data();
|
||||||
{
|
const T* data() const;
|
||||||
ASSERT(m_data);
|
|
||||||
return m_data;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool empty() const { return m_size == 0; }
|
bool empty() const;
|
||||||
size_type size() const { return m_size; }
|
size_type size() const;
|
||||||
|
|
||||||
void clear()
|
void clear();
|
||||||
{
|
|
||||||
m_data = nullptr;
|
|
||||||
m_size = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
Span slice(size_type start, size_type length = ~size_type(0)) const
|
Span slice(size_type, size_type = ~size_type(0));
|
||||||
{
|
|
||||||
ASSERT(m_data);
|
|
||||||
ASSERT(start <= m_size);
|
|
||||||
if (length == ~size_type(0))
|
|
||||||
length = m_size - start;
|
|
||||||
ASSERT(m_size - start >= length);
|
|
||||||
return Span(m_data + start, length);
|
|
||||||
}
|
|
||||||
|
|
||||||
Span<const value_type> as_const() const { return *this; }
|
Span<const T> as_const() const { return Span<const T>(m_data, m_size); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
value_type* m_data = nullptr;
|
T* m_data = nullptr;
|
||||||
size_type m_size = 0;
|
size_type m_size = 0;
|
||||||
|
|
||||||
friend class Span<const value_type>;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
template<typename T>
|
||||||
|
Span<T>::Span(T* data, size_type size)
|
||||||
|
: m_data(data)
|
||||||
|
, m_size(size)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
Span<T>::Span(Span& other)
|
||||||
|
: m_data(other.data())
|
||||||
|
, m_size(other.size())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
template<typename S>
|
||||||
|
requires(is_same_v<T, const S>)
|
||||||
|
Span<T>::Span(const Span<S>& other)
|
||||||
|
: m_data(other.data())
|
||||||
|
, m_size(other.size())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
T& Span<T>::operator[](size_type index)
|
||||||
|
{
|
||||||
|
ASSERT(m_data);
|
||||||
|
ASSERT(index < m_size);
|
||||||
|
return m_data[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
const T& Span<T>::operator[](size_type index) const
|
||||||
|
{
|
||||||
|
ASSERT(m_data);
|
||||||
|
ASSERT(index < m_size);
|
||||||
|
return m_data[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
T* Span<T>::data()
|
||||||
|
{
|
||||||
|
return m_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
const T* Span<T>::data() const
|
||||||
|
{
|
||||||
|
return m_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
bool Span<T>::empty() const
|
||||||
|
{
|
||||||
|
return m_size == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
typename Span<T>::size_type Span<T>::size() const
|
||||||
|
{
|
||||||
|
return m_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void Span<T>::clear()
|
||||||
|
{
|
||||||
|
m_data = nullptr;
|
||||||
|
m_size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
Span<T> Span<T>::slice(size_type start, size_type length)
|
||||||
|
{
|
||||||
|
ASSERT(m_data);
|
||||||
|
ASSERT(start <= m_size);
|
||||||
|
if (length == ~size_type(0))
|
||||||
|
length = m_size - start;
|
||||||
|
ASSERT(m_size - start >= length);
|
||||||
|
return Span(m_data + start, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -2,10 +2,9 @@
|
||||||
|
|
||||||
#include <BAN/Errors.h>
|
#include <BAN/Errors.h>
|
||||||
#include <BAN/Formatter.h>
|
#include <BAN/Formatter.h>
|
||||||
|
#include <BAN/ForwardList.h>
|
||||||
#include <BAN/Hash.h>
|
#include <BAN/Hash.h>
|
||||||
#include <BAN/Iterators.h>
|
#include <BAN/Iterators.h>
|
||||||
#include <BAN/New.h>
|
|
||||||
#include <BAN/StringView.h>
|
|
||||||
|
|
||||||
namespace BAN
|
namespace BAN
|
||||||
{
|
{
|
||||||
|
@ -19,130 +18,28 @@ namespace BAN
|
||||||
static constexpr size_type sso_capacity = 15;
|
static constexpr size_type sso_capacity = 15;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
String() {}
|
String();
|
||||||
String(const String& other) { *this = other; }
|
String(const String&);
|
||||||
String(String&& other) { *this = move(other); }
|
String(String&&);
|
||||||
String(StringView other) { *this = other; }
|
String(StringView);
|
||||||
~String() { clear(); }
|
~String();
|
||||||
|
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
static BAN::ErrorOr<String> formatted(const char* format, Args&&... args)
|
static String formatted(const char* format, const Args&... args);
|
||||||
{
|
|
||||||
size_type length = 0;
|
|
||||||
BAN::Formatter::print([&](char) { length++; }, format, BAN::forward<Args>(args)...);
|
|
||||||
|
|
||||||
String result;
|
String& operator=(const String&);
|
||||||
TRY(result.reserve(length));
|
String& operator=(String&&);
|
||||||
BAN::Formatter::print([&](char c){ MUST(result.push_back(c)); }, format, BAN::forward<Args>(args)...);
|
String& operator=(StringView);
|
||||||
|
|
||||||
return result;
|
ErrorOr<void> push_back(char);
|
||||||
}
|
ErrorOr<void> insert(char, size_type);
|
||||||
|
ErrorOr<void> insert(StringView, size_type);
|
||||||
|
ErrorOr<void> append(StringView);
|
||||||
|
|
||||||
String& operator=(const String& other)
|
void pop_back();
|
||||||
{
|
void remove(size_type);
|
||||||
clear();
|
|
||||||
MUST(ensure_capacity(other.size()));
|
|
||||||
memcpy(data(), other.data(), other.size() + 1);
|
|
||||||
m_size = other.size();
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
String& operator=(String&& other)
|
void clear();
|
||||||
{
|
|
||||||
clear();
|
|
||||||
|
|
||||||
if (other.has_sso())
|
|
||||||
memcpy(data(), other.data(), other.size() + 1);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
m_storage.general_storage = other.m_storage.general_storage;
|
|
||||||
m_has_sso = false;
|
|
||||||
}
|
|
||||||
m_size = other.m_size;
|
|
||||||
|
|
||||||
other.m_size = 0;
|
|
||||||
other.m_storage.sso_storage = SSOStorage();
|
|
||||||
other.m_has_sso = true;
|
|
||||||
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
String& operator=(StringView other)
|
|
||||||
{
|
|
||||||
clear();
|
|
||||||
MUST(ensure_capacity(other.size()));
|
|
||||||
memcpy(data(), other.data(), other.size());
|
|
||||||
m_size = other.size();
|
|
||||||
data()[m_size] = '\0';
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
ErrorOr<void> push_back(char c)
|
|
||||||
{
|
|
||||||
TRY(ensure_capacity(m_size + 1));
|
|
||||||
data()[m_size] = c;
|
|
||||||
m_size++;
|
|
||||||
data()[m_size] = '\0';
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
ErrorOr<void> insert(char c, size_type index)
|
|
||||||
{
|
|
||||||
ASSERT(index <= m_size);
|
|
||||||
TRY(ensure_capacity(m_size + 1));
|
|
||||||
memmove(data() + index + 1, data() + index, m_size - index);
|
|
||||||
data()[index] = c;
|
|
||||||
m_size++;
|
|
||||||
data()[m_size] = '\0';
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
ErrorOr<void> insert(StringView str, size_type index)
|
|
||||||
{
|
|
||||||
ASSERT(index <= m_size);
|
|
||||||
TRY(ensure_capacity(m_size + str.size()));
|
|
||||||
memmove(data() + index + str.size(), data() + index, m_size - index);
|
|
||||||
memcpy(data() + index, str.data(), str.size());
|
|
||||||
m_size += str.size();
|
|
||||||
data()[m_size] = '\0';
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
ErrorOr<void> append(StringView str)
|
|
||||||
{
|
|
||||||
TRY(ensure_capacity(m_size + str.size()));
|
|
||||||
memcpy(data() + m_size, str.data(), str.size());
|
|
||||||
m_size += str.size();
|
|
||||||
data()[m_size] = '\0';
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
void pop_back()
|
|
||||||
{
|
|
||||||
ASSERT(m_size > 0);
|
|
||||||
m_size--;
|
|
||||||
data()[m_size] = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
void remove(size_type index)
|
|
||||||
{
|
|
||||||
ASSERT(index < m_size);
|
|
||||||
memmove(data() + index, data() + index + 1, m_size - index);
|
|
||||||
m_size--;
|
|
||||||
data()[m_size] = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
void clear()
|
|
||||||
{
|
|
||||||
if (!has_sso())
|
|
||||||
{
|
|
||||||
deallocator(m_storage.general_storage.data);
|
|
||||||
m_storage.sso_storage = SSOStorage();
|
|
||||||
m_has_sso = true;
|
|
||||||
}
|
|
||||||
m_size = 0;
|
|
||||||
data()[m_size] = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
const_iterator begin() const { return const_iterator(data()); }
|
const_iterator begin() const { return const_iterator(data()); }
|
||||||
iterator begin() { return iterator(data()); }
|
iterator begin() { return iterator(data()); }
|
||||||
|
@ -158,151 +55,26 @@ namespace BAN
|
||||||
char operator[](size_type index) const { ASSERT(index < m_size); return data()[index]; }
|
char operator[](size_type index) const { ASSERT(index < m_size); return data()[index]; }
|
||||||
char& operator[](size_type index) { ASSERT(index < m_size); return data()[index]; }
|
char& operator[](size_type index) { ASSERT(index < m_size); return data()[index]; }
|
||||||
|
|
||||||
bool operator==(const String& str) const
|
bool operator==(StringView) const;
|
||||||
{
|
bool operator==(const char*) const;
|
||||||
if (size() != str.size())
|
|
||||||
return false;
|
|
||||||
for (size_type i = 0; i < m_size; i++)
|
|
||||||
if (data()[i] != str.data()[i])
|
|
||||||
return false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator==(StringView str) const
|
ErrorOr<void> resize(size_type, char = '\0');
|
||||||
{
|
ErrorOr<void> reserve(size_type);
|
||||||
if (size() != str.size())
|
ErrorOr<void> shrink_to_fit();
|
||||||
return false;
|
|
||||||
for (size_type i = 0; i < m_size; i++)
|
|
||||||
if (data()[i] != str.data()[i])
|
|
||||||
return false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator==(const char* cstr) const
|
|
||||||
{
|
|
||||||
for (size_type i = 0; i < m_size; i++)
|
|
||||||
if (data()[i] != cstr[i])
|
|
||||||
return false;
|
|
||||||
if (cstr[size()] != '\0')
|
|
||||||
return false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
ErrorOr<void> resize(size_type new_size, char init_c = '\0')
|
|
||||||
{
|
|
||||||
if (m_size == new_size)
|
|
||||||
return {};
|
|
||||||
|
|
||||||
// expanding
|
|
||||||
if (m_size < new_size)
|
|
||||||
{
|
|
||||||
TRY(ensure_capacity(new_size));
|
|
||||||
memset(data() + m_size, init_c, new_size - m_size);
|
|
||||||
m_size = new_size;
|
|
||||||
data()[m_size] = '\0';
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
m_size = new_size;
|
|
||||||
data()[m_size] = '\0';
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
ErrorOr<void> reserve(size_type new_size)
|
|
||||||
{
|
|
||||||
TRY(ensure_capacity(new_size));
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
ErrorOr<void> shrink_to_fit()
|
|
||||||
{
|
|
||||||
if (has_sso())
|
|
||||||
return {};
|
|
||||||
|
|
||||||
if (fits_in_sso())
|
|
||||||
{
|
|
||||||
char* data = m_storage.general_storage.data;
|
|
||||||
m_storage.sso_storage = SSOStorage();
|
|
||||||
m_has_sso = true;
|
|
||||||
memcpy(this->data(), data, m_size + 1);
|
|
||||||
deallocator(data);
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
GeneralStorage& storage = m_storage.general_storage;
|
|
||||||
if (storage.capacity == m_size)
|
|
||||||
return {};
|
|
||||||
|
|
||||||
char* new_data = (char*)allocator(m_size + 1);
|
|
||||||
if (new_data == nullptr)
|
|
||||||
return Error::from_errno(ENOMEM);
|
|
||||||
|
|
||||||
memcpy(new_data, storage.data, m_size);
|
|
||||||
deallocator(storage.data);
|
|
||||||
|
|
||||||
storage.capacity = m_size;
|
|
||||||
storage.data = new_data;
|
|
||||||
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
StringView sv() const { return StringView(data(), size()); }
|
StringView sv() const { return StringView(data(), size()); }
|
||||||
|
|
||||||
bool empty() const { return m_size == 0; }
|
bool empty() const { return m_size == 0; }
|
||||||
size_type size() const { return m_size; }
|
size_type size() const { return m_size; }
|
||||||
|
size_type capacity() const;
|
||||||
|
|
||||||
size_type capacity() const
|
char* data();
|
||||||
{
|
const char* data() const;
|
||||||
if (has_sso())
|
|
||||||
return sso_capacity;
|
|
||||||
return m_storage.general_storage.capacity;
|
|
||||||
}
|
|
||||||
|
|
||||||
char* data()
|
|
||||||
{
|
|
||||||
if (has_sso())
|
|
||||||
return m_storage.sso_storage.data;
|
|
||||||
return m_storage.general_storage.data;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* data() const
|
|
||||||
{
|
|
||||||
if (has_sso())
|
|
||||||
return m_storage.sso_storage.data;
|
|
||||||
return m_storage.general_storage.data;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ErrorOr<void> ensure_capacity(size_type new_size)
|
ErrorOr<void> ensure_capacity(size_type);
|
||||||
{
|
|
||||||
if (m_size >= new_size)
|
|
||||||
return {};
|
|
||||||
if (has_sso() && fits_in_sso(new_size))
|
|
||||||
return {};
|
|
||||||
|
|
||||||
char* new_data = (char*)allocator(new_size + 1);
|
bool has_sso() const;
|
||||||
if (new_data == nullptr)
|
|
||||||
return Error::from_errno(ENOMEM);
|
|
||||||
|
|
||||||
if (m_size)
|
|
||||||
memcpy(new_data, data(), m_size + 1);
|
|
||||||
|
|
||||||
if (has_sso())
|
|
||||||
{
|
|
||||||
m_storage.general_storage = GeneralStorage();
|
|
||||||
m_has_sso = false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
deallocator(m_storage.general_storage.data);
|
|
||||||
|
|
||||||
auto& storage = m_storage.general_storage;
|
|
||||||
storage.capacity = new_size;
|
|
||||||
storage.data = new_data;
|
|
||||||
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
bool has_sso() const { return m_has_sso; }
|
|
||||||
|
|
||||||
bool fits_in_sso() const { return fits_in_sso(m_size); }
|
bool fits_in_sso() const { return fits_in_sso(m_size); }
|
||||||
static bool fits_in_sso(size_type size) { return size < sso_capacity; }
|
static bool fits_in_sso(size_type size) { return size < sso_capacity; }
|
||||||
|
@ -327,6 +99,14 @@ namespace BAN
|
||||||
size_type m_has_sso : 1 { true };
|
size_type m_has_sso : 1 { true };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<typename... Args>
|
||||||
|
String String::formatted(const char* format, const Args&... args)
|
||||||
|
{
|
||||||
|
String result;
|
||||||
|
BAN::Formatter::print([&](char c){ MUST(result.push_back(c)); }, format, args...);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
struct hash<String>
|
struct hash<String>
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,11 +1,8 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <BAN/Formatter.h>
|
|
||||||
#include <BAN/ForwardList.h>
|
#include <BAN/ForwardList.h>
|
||||||
#include <BAN/Hash.h>
|
#include <BAN/Formatter.h>
|
||||||
#include <BAN/Iterators.h>
|
#include <BAN/Iterators.h>
|
||||||
#include <BAN/Optional.h>
|
|
||||||
#include <BAN/Vector.h>
|
|
||||||
|
|
||||||
namespace BAN
|
namespace BAN
|
||||||
{
|
{
|
||||||
|
@ -17,229 +14,43 @@ namespace BAN
|
||||||
using const_iterator = ConstIteratorSimple<char, StringView>;
|
using const_iterator = ConstIteratorSimple<char, StringView>;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
constexpr StringView() {}
|
StringView();
|
||||||
constexpr StringView(const char* string, size_type len = -1)
|
|
||||||
{
|
|
||||||
if (len == size_type(-1))
|
|
||||||
len = strlen(string);
|
|
||||||
m_data = string;
|
|
||||||
m_size = len;
|
|
||||||
}
|
|
||||||
StringView(const String&);
|
StringView(const String&);
|
||||||
|
StringView(const char*, size_type = -1);
|
||||||
|
|
||||||
constexpr const_iterator begin() const { return const_iterator(m_data); }
|
const_iterator begin() const { return const_iterator(m_data); }
|
||||||
constexpr const_iterator end() const { return const_iterator(m_data + m_size); }
|
const_iterator end() const { return const_iterator(m_data + m_size); }
|
||||||
|
|
||||||
constexpr char operator[](size_type index) const
|
char operator[](size_type) const;
|
||||||
{
|
|
||||||
ASSERT(index < m_size);
|
|
||||||
return m_data[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr bool operator==(StringView other) const
|
bool operator==(const String&) const;
|
||||||
{
|
bool operator==(StringView) const;
|
||||||
if (m_size != other.m_size)
|
bool operator==(const char*) const;
|
||||||
return false;
|
|
||||||
for (size_type i = 0; i < m_size; i++)
|
|
||||||
if (m_data[i] != other.m_data[i])
|
|
||||||
return false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr bool operator==(const char* other) const
|
StringView substring(size_type, size_type = -1) const;
|
||||||
{
|
|
||||||
for (size_type i = 0; i < m_size; i++)
|
|
||||||
if (m_data[i] != other[i])
|
|
||||||
return false;
|
|
||||||
return other[m_size] == '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr StringView substring(size_type index, size_type len = -1) const
|
ErrorOr<Vector<StringView>> split(char, bool = false);
|
||||||
{
|
ErrorOr<Vector<StringView>> split(bool(*comp)(char), bool = false);
|
||||||
ASSERT(index <= m_size);
|
|
||||||
if (len == size_type(-1))
|
|
||||||
len = m_size - index;
|
|
||||||
ASSERT(len <= m_size - index); // weird order to avoid overflow
|
|
||||||
StringView result;
|
|
||||||
result.m_data = m_data + index;
|
|
||||||
result.m_size = len;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
ErrorOr<Vector<StringView>> split(char delim, bool allow_empties = false) const
|
char back() const;
|
||||||
{
|
char front() const;
|
||||||
size_type count = 0;
|
|
||||||
{
|
|
||||||
size_type start = 0;
|
|
||||||
for (size_type i = 0; i < m_size; i++)
|
|
||||||
{
|
|
||||||
if (m_data[i] == delim)
|
|
||||||
{
|
|
||||||
if (allow_empties || start != i)
|
|
||||||
count++;
|
|
||||||
start = i + 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (start != m_size)
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
|
|
||||||
Vector<StringView> result;
|
bool contains(char) const;
|
||||||
TRY(result.reserve(count));
|
size_type count(char) const;
|
||||||
|
|
||||||
size_type start = 0;
|
bool empty() const;
|
||||||
for (size_type i = 0; i < m_size; i++)
|
size_type size() const;
|
||||||
{
|
|
||||||
if (m_data[i] == delim)
|
const char* data() const;
|
||||||
{
|
|
||||||
if (allow_empties || start != i)
|
|
||||||
TRY(result.push_back(this->substring(start, i - start)));
|
|
||||||
start = i + 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (start < m_size || (start == m_size && allow_empties))
|
|
||||||
TRY(result.push_back(this->substring(start)));
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
ErrorOr<Vector<StringView>> split(bool(*comp)(char), bool allow_empties = false) const
|
|
||||||
{
|
|
||||||
size_type count = 0;
|
|
||||||
{
|
|
||||||
size_type start = 0;
|
|
||||||
for (size_type i = 0; i < m_size; i++)
|
|
||||||
{
|
|
||||||
if (comp(m_data[i]))
|
|
||||||
{
|
|
||||||
if (allow_empties || start != i)
|
|
||||||
count++;
|
|
||||||
start = i + 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (start != m_size)
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
|
|
||||||
Vector<StringView> result;
|
|
||||||
TRY(result.reserve(count));
|
|
||||||
|
|
||||||
size_type start = 0;
|
|
||||||
for (size_type i = 0; i < m_size; i++)
|
|
||||||
{
|
|
||||||
if (comp(m_data[i]))
|
|
||||||
{
|
|
||||||
if (allow_empties || start != i)
|
|
||||||
TRY(result.push_back(this->substring(start, i - start)));
|
|
||||||
start = i + 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (start < m_size || (start == m_size && allow_empties))
|
|
||||||
TRY(result.push_back(this->substring(start)));
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr char back() const
|
|
||||||
{
|
|
||||||
ASSERT(m_size > 0);
|
|
||||||
return m_data[m_size - 1];
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr char front() const
|
|
||||||
{
|
|
||||||
ASSERT(m_size > 0);
|
|
||||||
return m_data[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
BAN::Optional<size_type> find(char ch) const
|
|
||||||
{
|
|
||||||
for (size_type i = 0; i < m_size; i++)
|
|
||||||
if (m_data[i] == ch)
|
|
||||||
return i;
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
BAN::Optional<size_type> find(bool(*comp)(char)) const
|
|
||||||
{
|
|
||||||
for (size_type i = 0; i < m_size; i++)
|
|
||||||
if (comp(m_data[i]))
|
|
||||||
return i;
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
BAN::Optional<size_type> rfind(char ch) const
|
|
||||||
{
|
|
||||||
for (size_type i = m_size; i > 0; i--)
|
|
||||||
if (m_data[i - 1] == ch)
|
|
||||||
return i - 1;
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
BAN::Optional<size_type> rfind(bool(*comp)(char)) const
|
|
||||||
{
|
|
||||||
for (size_type i = m_size; i > 0; i--)
|
|
||||||
if (comp(m_data[i - 1]))
|
|
||||||
return i - 1;
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr bool starts_with(BAN::StringView target) const
|
|
||||||
{
|
|
||||||
if (target.size() > m_size)
|
|
||||||
return false;
|
|
||||||
for (size_type i = 0; i < target.size(); i++)
|
|
||||||
if (m_data[i] != target[i])
|
|
||||||
return false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr bool contains(char ch) const
|
|
||||||
{
|
|
||||||
for (size_type i = 0; i < m_size; i++)
|
|
||||||
if (m_data[i] == ch)
|
|
||||||
return true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr size_type count(char ch) const
|
|
||||||
{
|
|
||||||
size_type result = 0;
|
|
||||||
for (size_type i = 0; i < m_size; i++)
|
|
||||||
if (m_data[i] == ch)
|
|
||||||
result++;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr bool empty() const { return m_size == 0; }
|
|
||||||
constexpr size_type size() const { return m_size; }
|
|
||||||
constexpr const char* data() const { return m_data; }
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const char* m_data = nullptr;
|
const char* m_data = nullptr;
|
||||||
size_type m_size = 0;
|
size_type m_size = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<>
|
|
||||||
struct hash<StringView>
|
|
||||||
{
|
|
||||||
hash_t operator()(StringView string) const
|
|
||||||
{
|
|
||||||
constexpr hash_t FNV_offset_basis = 0x811c9dc5;
|
|
||||||
constexpr hash_t FNV_prime = 0x01000193;
|
|
||||||
|
|
||||||
hash_t hash = FNV_offset_basis;
|
|
||||||
for (StringView::size_type i = 0; i < string.size(); i++)
|
|
||||||
{
|
|
||||||
hash *= FNV_prime;
|
|
||||||
hash ^= (uint8_t)string[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
return hash;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline constexpr BAN::StringView operator""_sv(const char* str, BAN::StringView::size_type len) { return BAN::StringView(str, len); }
|
inline BAN::StringView operator""sv(const char* str, BAN::StringView::size_type len) { return BAN::StringView(str, len); }
|
||||||
|
|
||||||
namespace BAN::Formatter
|
namespace BAN::Formatter
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,16 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <BAN/Move.h>
|
|
||||||
|
|
||||||
namespace BAN
|
|
||||||
{
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
void swap(T& lhs, T& rhs)
|
|
||||||
{
|
|
||||||
T tmp = move(lhs);
|
|
||||||
lhs = move(rhs);
|
|
||||||
rhs = move(tmp);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -34,4 +34,4 @@ namespace BAN::Formatter
|
||||||
print(putc, "{} {} {} {2}:{2}:{2} GMT+0 {4}", week_days[time.week_day], months[time.month], time.day, time.hour, time.minute, time.second, time.year);
|
print(putc, "{} {} {} {2}:{2}:{2} GMT+0 {4}", week_days[time.week_day], months[time.month], time.day, time.hour, time.minute, time.second, time.year);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -3,10 +3,10 @@
|
||||||
namespace BAN
|
namespace BAN
|
||||||
{
|
{
|
||||||
|
|
||||||
template<typename T> struct remove_reference { using type = T; };
|
template<typename T> struct remove_refenrece { using type = T; };
|
||||||
template<typename T> struct remove_reference<T&> { using type = T; };
|
template<typename T> struct remove_refenrece<T&> { using type = T; };
|
||||||
template<typename T> struct remove_reference<T&&> { using type = T; };
|
template<typename T> struct remove_refenrece<T&&> { using type = T; };
|
||||||
template<typename T> using remove_reference_t = typename remove_reference<T>::type;
|
template<typename T> using remove_reference_t = typename remove_refenrece<T>::type;
|
||||||
|
|
||||||
template<typename T> struct remove_const { using type = T; };
|
template<typename T> struct remove_const { using type = T; };
|
||||||
template<typename T> struct remove_const<const T> { using type = T; };
|
template<typename T> struct remove_const<const T> { using type = T; };
|
||||||
|
@ -34,33 +34,18 @@ namespace BAN
|
||||||
template<typename T1, typename T2> struct either_or<true, T1, T2> { using type = T1; };
|
template<typename T1, typename T2> struct either_or<true, T1, T2> { using type = T1; };
|
||||||
template<bool B, typename T1, typename T2> using either_or_t = typename either_or<B, T1, T2>::type;
|
template<bool B, typename T1, typename T2> using either_or_t = typename either_or<B, T1, T2>::type;
|
||||||
|
|
||||||
template<typename T, T V> struct integral_constant { static constexpr T value = V; };
|
struct true_type { static constexpr bool value = true; };
|
||||||
template<typename T, T V > inline constexpr T integral_constant_v = integral_constant<T, V>::value;
|
struct false_type { static constexpr bool value = false; };
|
||||||
using true_type = integral_constant<bool, true>;
|
|
||||||
using false_type = integral_constant<bool, false>;
|
|
||||||
|
|
||||||
template<typename T, typename S> struct is_same : false_type {};
|
template<typename T, typename S> struct is_same : false_type {};
|
||||||
template<typename T> struct is_same<T, T> : true_type {};
|
template<typename T> struct is_same<T, T> : true_type {};
|
||||||
template<typename T, typename S> inline constexpr bool is_same_v = is_same<T, S>::value;
|
template<typename T, typename S> inline constexpr bool is_same_v = is_same<T, S>::value;
|
||||||
template<typename T, typename S> concept same_as = BAN::is_same_v<T, S>;
|
|
||||||
|
|
||||||
template<typename T> struct is_lvalue_reference : false_type {};
|
template<typename T> struct is_lvalue_reference : false_type {};
|
||||||
template<typename T> struct is_lvalue_reference<T&> : true_type {};
|
template<typename T> struct is_lvalue_reference<T&> : true_type {};
|
||||||
template<typename T> inline constexpr bool is_lvalue_reference_v = is_lvalue_reference<T>::value;
|
template<typename T> inline constexpr bool is_lvalue_reference_v = is_lvalue_reference<T>::value;
|
||||||
template<typename T> concept lvalue_reference = is_lvalue_reference_v<T>;
|
template<typename T> concept lvalue_reference = is_lvalue_reference_v<T>;
|
||||||
|
|
||||||
template<typename T, typename... Args> struct is_constructible { static constexpr bool value = __is_constructible(T, Args...); };
|
|
||||||
template<typename T, typename... Args> inline constexpr bool is_constructible_v = is_constructible<T, Args...>::value;
|
|
||||||
|
|
||||||
template<typename T> struct is_default_constructible { static constexpr bool value = is_constructible_v<T>; };
|
|
||||||
template<typename T> inline constexpr bool is_default_constructible_v = is_default_constructible<T>::value;
|
|
||||||
|
|
||||||
template<typename T> struct is_copy_constructible { static constexpr bool value = is_constructible_v<T, const T&>; };
|
|
||||||
template<typename T> inline constexpr bool is_copy_constructible_v = is_copy_constructible<T>::value;
|
|
||||||
|
|
||||||
template<typename T> struct is_move_constructible { static constexpr bool value = is_constructible_v<T, T&&>; };
|
|
||||||
template<typename T> inline constexpr bool is_move_constructible_v = is_move_constructible<T>::value;
|
|
||||||
|
|
||||||
template<typename T> struct is_integral { static constexpr bool value = requires (T t, T* p, void (*f)(T)) { reinterpret_cast<T>(t); f(0); p + t; }; };
|
template<typename T> struct is_integral { static constexpr bool value = requires (T t, T* p, void (*f)(T)) { reinterpret_cast<T>(t); f(0); p + t; }; };
|
||||||
template<typename T> inline constexpr bool is_integral_v = is_integral<T>::value;
|
template<typename T> inline constexpr bool is_integral_v = is_integral<T>::value;
|
||||||
template<typename T> concept integral = is_integral_v<T>;
|
template<typename T> concept integral = is_integral_v<T>;
|
||||||
|
@ -87,60 +72,16 @@ namespace BAN
|
||||||
template<typename T> struct is_arithmetic { static constexpr bool value = is_integral_v<T> || is_floating_point_v<T>; };
|
template<typename T> struct is_arithmetic { static constexpr bool value = is_integral_v<T> || is_floating_point_v<T>; };
|
||||||
template<typename T> inline constexpr bool is_arithmetic_v = is_arithmetic<T>::value;
|
template<typename T> inline constexpr bool is_arithmetic_v = is_arithmetic<T>::value;
|
||||||
|
|
||||||
template<typename Base, typename Derived> struct is_base_of { static constexpr bool value = __is_base_of(Base, Derived); };
|
|
||||||
template<typename Base, typename Derived> inline constexpr bool is_base_of_v = is_base_of<Base, Derived>::value;
|
|
||||||
|
|
||||||
template<typename T> struct is_pod { static constexpr bool value = __is_pod(T); };
|
|
||||||
template<typename T> inline constexpr bool is_pod_v = is_pod<T>::value;
|
|
||||||
|
|
||||||
namespace detail
|
namespace detail
|
||||||
{
|
{
|
||||||
template<typename T, bool = is_arithmetic_v<T>> struct is_signed { static constexpr bool value = T(-1) < T(0); };
|
template<typename T, bool = is_arithmetic_v<T>> struct is_signed { static constexpr bool value = T(-1) < T(0); };
|
||||||
template<typename T> struct is_signed<T, false> : false_type {};
|
template<typename T> struct is_signed<T, false> : false_type {};
|
||||||
|
|
||||||
template<typename T, bool = is_arithmetic_v<T>> struct is_unsigned { static constexpr bool value = T(0) < T(-1); };
|
|
||||||
template<typename T> struct is_unsigned<T, false> : false_type {};
|
|
||||||
}
|
}
|
||||||
template<typename T> struct is_signed : detail::is_signed<T> {};
|
template<typename T> struct is_signed : detail::is_signed<T> {};
|
||||||
template<typename T> inline constexpr bool is_signed_v = is_signed<T>::value;
|
template<typename T> inline constexpr bool is_signed_v = is_signed<T>::value;
|
||||||
template<typename T> concept signed_integral = is_signed_v<T> && is_integral_v<T>;
|
|
||||||
|
|
||||||
template<typename T> struct is_unsigned : detail::is_unsigned<T> {};
|
|
||||||
template<typename T> inline constexpr bool is_unsigned_v = is_unsigned<T>::value;
|
|
||||||
template<typename T> concept unsigned_integral = is_unsigned_v<T> && is_integral_v<T>;
|
|
||||||
|
|
||||||
#define __BAN_TRAITS_MAKE_UNSIGNED_CV(__type) \
|
|
||||||
template<> struct make_unsigned<__type> { using type = unsigned __type; }; \
|
|
||||||
template<> struct make_unsigned<const __type> { using type = unsigned const __type; }; \
|
|
||||||
template<> struct make_unsigned<volatile __type> { using type = unsigned volatile __type; }; \
|
|
||||||
template<> struct make_unsigned<const volatile __type> { using type = unsigned const volatile __type; };
|
|
||||||
|
|
||||||
template<typename T> requires is_arithmetic_v<T> struct make_unsigned { using type = T; };
|
|
||||||
__BAN_TRAITS_MAKE_UNSIGNED_CV(char)
|
|
||||||
__BAN_TRAITS_MAKE_UNSIGNED_CV(short)
|
|
||||||
__BAN_TRAITS_MAKE_UNSIGNED_CV(int)
|
|
||||||
__BAN_TRAITS_MAKE_UNSIGNED_CV(long)
|
|
||||||
__BAN_TRAITS_MAKE_UNSIGNED_CV(long long)
|
|
||||||
template<typename T> using make_unsigned_t = typename make_unsigned<T>::type;
|
|
||||||
#undef __BAN_TRAITS_MAKE_UNSIGNED_CV
|
|
||||||
|
|
||||||
#define __BAN_TRAITS_MAKE_SIGNED_CV(__type) \
|
|
||||||
template<> struct make_signed<unsigned __type> { using type = __type; }; \
|
|
||||||
template<> struct make_signed<unsigned const __type> { using type = const __type; }; \
|
|
||||||
template<> struct make_signed<unsigned volatile __type> { using type = volatile __type; }; \
|
|
||||||
template<> struct make_signed<unsigned const volatile __type> { using type = const volatile __type; };
|
|
||||||
|
|
||||||
template<typename T> requires is_arithmetic_v<T> struct make_signed { using type = T; };
|
|
||||||
__BAN_TRAITS_MAKE_SIGNED_CV(char)
|
|
||||||
__BAN_TRAITS_MAKE_SIGNED_CV(short)
|
|
||||||
__BAN_TRAITS_MAKE_SIGNED_CV(int)
|
|
||||||
__BAN_TRAITS_MAKE_SIGNED_CV(long)
|
|
||||||
__BAN_TRAITS_MAKE_SIGNED_CV(long long)
|
|
||||||
template<typename T> using make_signed_t = typename make_signed<T>::type;
|
|
||||||
#undef __BAN_TRAITS_MAKE_SIGNED_CV
|
|
||||||
|
|
||||||
template<typename T> struct less { constexpr bool operator()(const T& lhs, const T& rhs) const { return lhs < rhs; } };
|
template<typename T> struct less { constexpr bool operator()(const T& lhs, const T& rhs) const { return lhs < rhs; } };
|
||||||
template<typename T> struct equal { constexpr bool operator()(const T& lhs, const T& rhs) const { return lhs == rhs; } };
|
template<typename T> struct equal { constexpr bool operator()(const T& lhs, const T& rhs) const { return lhs == rhs; } };
|
||||||
template<typename T> struct greater { constexpr bool operator()(const T& lhs, const T& rhs) const { return lhs > rhs; } };
|
template<typename T> struct greater { constexpr bool operator()(const T& lhs, const T& rhs) const { return lhs > rhs; } };
|
||||||
|
|
||||||
}
|
}
|
|
@ -21,21 +21,20 @@ namespace BAN::UTF8
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T> requires (sizeof(T) == 1)
|
constexpr uint32_t to_codepoint(uint8_t* bytes)
|
||||||
constexpr uint32_t to_codepoint(const T* bytes)
|
|
||||||
{
|
{
|
||||||
uint32_t length = byte_length(bytes[0]);
|
uint32_t length = byte_length(bytes[0]);
|
||||||
|
|
||||||
for (uint32_t i = 1; i < length; i++)
|
for (uint32_t i = 1; i < length; i++)
|
||||||
if (((uint8_t)bytes[i] & 0xC0) != 0x80)
|
if ((bytes[i] & 0xC0) != 0x80)
|
||||||
return UTF8::invalid;
|
return UTF8::invalid;
|
||||||
|
|
||||||
switch (length)
|
switch (length)
|
||||||
{
|
{
|
||||||
case 1: return (((uint8_t)bytes[0] & 0x80) != 0x00) ? UTF8::invalid : (uint8_t)bytes[0];
|
case 1: return ((bytes[0] & 0x80) != 0x00) ? UTF8::invalid : bytes[0];
|
||||||
case 2: return (((uint8_t)bytes[0] & 0xE0) != 0xC0) ? UTF8::invalid : (((uint8_t)bytes[0] & 0x1F) << 6) | ((uint8_t)bytes[1] & 0x3F);
|
case 2: return ((bytes[0] & 0xE0) != 0xC0) ? UTF8::invalid : ((bytes[0] & 0x1F) << 6) | (bytes[1] & 0x3F);
|
||||||
case 3: return (((uint8_t)bytes[0] & 0xF0) != 0xE0) ? UTF8::invalid : (((uint8_t)bytes[0] & 0x0F) << 12) | (((uint8_t)bytes[1] & 0x3F) << 6) | ((uint8_t)bytes[2] & 0x3F);
|
case 3: return ((bytes[0] & 0xF0) != 0xE0) ? UTF8::invalid : ((bytes[0] & 0x0F) << 12) | ((bytes[1] & 0x3F) << 6) | (bytes[2] & 0x3F);
|
||||||
case 4: return (((uint8_t)bytes[0] & 0xF8) != 0xF0) ? UTF8::invalid : (((uint8_t)bytes[0] & 0x07) << 18) | (((uint8_t)bytes[1] & 0x3F) << 12) | (((uint8_t)bytes[2] & 0x3F) << 6) | ((uint8_t)bytes[3] & 0x3F);
|
case 4: return ((bytes[0] & 0xF8) != 0xF0) ? UTF8::invalid : ((bytes[0] & 0x07) << 18) | ((bytes[1] & 0x3F) << 12) | ((bytes[2] & 0x3F) << 6) | (bytes[3] & 0x3F);
|
||||||
}
|
}
|
||||||
|
|
||||||
return UTF8::invalid;
|
return UTF8::invalid;
|
||||||
|
@ -79,4 +78,4 @@ namespace BAN::UTF8
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -33,9 +33,8 @@ namespace BAN
|
||||||
return uniq;
|
return uniq;
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: don't use is_constructible_v<T, Args...> as UniqPtr<T> is allowed with friends
|
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
static BAN::ErrorOr<UniqPtr> create(Args&&... args) requires requires(Args&&... args) { T(forward<Args>(args)...); }
|
static BAN::ErrorOr<UniqPtr> create(Args&&... args)
|
||||||
{
|
{
|
||||||
UniqPtr uniq;
|
UniqPtr uniq;
|
||||||
uniq.m_pointer = new T(BAN::forward<Args>(args)...);
|
uniq.m_pointer = new T(BAN::forward<Args>(args)...);
|
||||||
|
@ -68,7 +67,7 @@ namespace BAN
|
||||||
T* operator->()
|
T* operator->()
|
||||||
{
|
{
|
||||||
ASSERT(m_pointer);
|
ASSERT(m_pointer);
|
||||||
return m_pointer;
|
return m_pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
const T* operator->() const
|
const T* operator->() const
|
||||||
|
@ -96,4 +95,4 @@ namespace BAN
|
||||||
friend class UniqPtr;
|
friend class UniqPtr;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
|
@ -3,7 +3,6 @@
|
||||||
#include <BAN/Assert.h>
|
#include <BAN/Assert.h>
|
||||||
#include <BAN/Math.h>
|
#include <BAN/Math.h>
|
||||||
#include <BAN/Move.h>
|
#include <BAN/Move.h>
|
||||||
#include <BAN/PlacementNew.h>
|
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
@ -43,10 +42,9 @@ namespace BAN
|
||||||
void destruct(size_t index, uint8_t* data)
|
void destruct(size_t index, uint8_t* data)
|
||||||
{
|
{
|
||||||
if (index == 0)
|
if (index == 0)
|
||||||
{
|
|
||||||
if constexpr(!is_lvalue_reference_v<T>)
|
if constexpr(!is_lvalue_reference_v<T>)
|
||||||
reinterpret_cast<T*>(data)->~T();
|
reinterpret_cast<T*>(data)->~T();
|
||||||
}
|
else;
|
||||||
else if constexpr(sizeof...(Ts) > 0)
|
else if constexpr(sizeof...(Ts) > 0)
|
||||||
destruct<Ts...>(index - 1, data);
|
destruct<Ts...>(index - 1, data);
|
||||||
else
|
else
|
||||||
|
@ -140,14 +138,14 @@ namespace BAN
|
||||||
Variant(T&& value) requires (can_have<T>() && !is_lvalue_reference_v<T>)
|
Variant(T&& value) requires (can_have<T>() && !is_lvalue_reference_v<T>)
|
||||||
: m_index(detail::index<T, Ts...>())
|
: m_index(detail::index<T, Ts...>())
|
||||||
{
|
{
|
||||||
new (m_storage) T(move(value));
|
new (m_storage) T(move(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
Variant(const T& value) requires (can_have<T>() && !is_lvalue_reference_v<T>)
|
Variant(const T& value) requires (can_have<T>() && !is_lvalue_reference_v<T>)
|
||||||
: m_index(detail::index<T, Ts...>())
|
: m_index(detail::index<T, Ts...>())
|
||||||
{
|
{
|
||||||
new (m_storage) T(value);
|
new (m_storage) T(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
~Variant()
|
~Variant()
|
||||||
|
@ -216,14 +214,6 @@ namespace BAN
|
||||||
return m_index == detail::index<T, Ts...>();
|
return m_index == detail::index<T, Ts...>();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, typename... Args>
|
|
||||||
void emplace(Args&&... args) requires (can_have<T>() && is_constructible_v<T, Args...>)
|
|
||||||
{
|
|
||||||
clear();
|
|
||||||
m_index = detail::index<T, Ts...>();
|
|
||||||
new (m_storage) T(BAN::forward<Args>(args)...);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
void set(T&& value) requires (can_have<T>() && !is_lvalue_reference_v<T>)
|
void set(T&& value) requires (can_have<T>() && !is_lvalue_reference_v<T>)
|
||||||
{
|
{
|
||||||
|
@ -286,16 +276,6 @@ namespace BAN
|
||||||
return **reinterpret_cast<const remove_reference_t<T>**>(m_storage);
|
return **reinterpret_cast<const remove_reference_t<T>**>(m_storage);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool has_value() const
|
|
||||||
{
|
|
||||||
return m_index != invalid_index();
|
|
||||||
}
|
|
||||||
|
|
||||||
explicit operator bool() const
|
|
||||||
{
|
|
||||||
return has_value();
|
|
||||||
}
|
|
||||||
|
|
||||||
void clear()
|
void clear()
|
||||||
{
|
{
|
||||||
if (m_index != invalid_index())
|
if (m_index != invalid_index())
|
||||||
|
@ -310,4 +290,4 @@ namespace BAN
|
||||||
size_t m_index { invalid_index() };
|
size_t m_index { invalid_index() };
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
|
@ -5,9 +5,7 @@
|
||||||
#include <BAN/Math.h>
|
#include <BAN/Math.h>
|
||||||
#include <BAN/Move.h>
|
#include <BAN/Move.h>
|
||||||
#include <BAN/New.h>
|
#include <BAN/New.h>
|
||||||
#include <BAN/PlacementNew.h>
|
|
||||||
#include <BAN/Span.h>
|
#include <BAN/Span.h>
|
||||||
#include <BAN/Swap.h>
|
|
||||||
|
|
||||||
namespace BAN
|
namespace BAN
|
||||||
{
|
{
|
||||||
|
@ -35,12 +33,12 @@ namespace BAN
|
||||||
ErrorOr<void> push_back(T&&);
|
ErrorOr<void> push_back(T&&);
|
||||||
ErrorOr<void> push_back(const T&);
|
ErrorOr<void> push_back(const T&);
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
ErrorOr<void> emplace_back(Args&&...) requires is_constructible_v<T, Args...>;
|
ErrorOr<void> emplace_back(Args&&...);
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
ErrorOr<void> emplace(size_type, Args&&...) requires is_constructible_v<T, Args...>;
|
ErrorOr<void> emplace(size_type, Args&&...);
|
||||||
ErrorOr<void> insert(size_type, T&&);
|
ErrorOr<void> insert(size_type, T&&);
|
||||||
ErrorOr<void> insert(size_type, const T&);
|
ErrorOr<void> insert(size_type, const T&);
|
||||||
|
|
||||||
iterator begin() { return iterator(m_data); }
|
iterator begin() { return iterator(m_data); }
|
||||||
iterator end() { return iterator(m_data + m_size); }
|
iterator end() { return iterator(m_data + m_size); }
|
||||||
const_iterator begin() const { return const_iterator(m_data); }
|
const_iterator begin() const { return const_iterator(m_data); }
|
||||||
|
@ -66,10 +64,7 @@ namespace BAN
|
||||||
const T& front() const;
|
const T& front() const;
|
||||||
T& front();
|
T& front();
|
||||||
|
|
||||||
void reverse();
|
ErrorOr<void> resize(size_type, const T& = T());
|
||||||
|
|
||||||
ErrorOr<void> resize(size_type) requires is_default_constructible_v<T>;
|
|
||||||
ErrorOr<void> resize(size_type, const T&) requires is_copy_constructible_v<T>;
|
|
||||||
ErrorOr<void> reserve(size_type);
|
ErrorOr<void> reserve(size_type);
|
||||||
ErrorOr<void> shrink_to_fit();
|
ErrorOr<void> shrink_to_fit();
|
||||||
|
|
||||||
|
@ -141,13 +136,10 @@ namespace BAN
|
||||||
template<typename T>
|
template<typename T>
|
||||||
Vector<T>& Vector<T>::operator=(const Vector<T>& other)
|
Vector<T>& Vector<T>::operator=(const Vector<T>& other)
|
||||||
{
|
{
|
||||||
|
clear();
|
||||||
MUST(ensure_capacity(other.size()));
|
MUST(ensure_capacity(other.size()));
|
||||||
for (size_type i = 0; i < BAN::Math::min(size(), other.size()); i++)
|
for (size_type i = 0; i < other.size(); i++)
|
||||||
m_data[i] = other.m_data[i];
|
|
||||||
for (size_type i = size(); i < other.size(); i++)
|
|
||||||
new (m_data + i) T(other[i]);
|
new (m_data + i) T(other[i]);
|
||||||
for (size_type i = other.size(); i < size(); i++)
|
|
||||||
m_data[i].~T();
|
|
||||||
m_size = other.m_size;
|
m_size = other.m_size;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
@ -169,7 +161,7 @@ namespace BAN
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
ErrorOr<void> Vector<T>::emplace_back(Args&&... args) requires is_constructible_v<T, Args...>
|
ErrorOr<void> Vector<T>::emplace_back(Args&&... args)
|
||||||
{
|
{
|
||||||
TRY(ensure_capacity(m_size + 1));
|
TRY(ensure_capacity(m_size + 1));
|
||||||
new (m_data + m_size) T(forward<Args>(args)...);
|
new (m_data + m_size) T(forward<Args>(args)...);
|
||||||
|
@ -179,7 +171,7 @@ namespace BAN
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
ErrorOr<void> Vector<T>::emplace(size_type index, Args&&... args) requires is_constructible_v<T, Args...>
|
ErrorOr<void> Vector<T>::emplace(size_type index, Args&&... args)
|
||||||
{
|
{
|
||||||
ASSERT(index <= m_size);
|
ASSERT(index <= m_size);
|
||||||
TRY(ensure_capacity(m_size + 1));
|
TRY(ensure_capacity(m_size + 1));
|
||||||
|
@ -305,28 +297,7 @@ namespace BAN
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
void Vector<T>::reverse()
|
ErrorOr<void> Vector<T>::resize(size_type size, const T& value)
|
||||||
{
|
|
||||||
for (size_type i = 0; i < m_size / 2; i++)
|
|
||||||
BAN::swap(m_data[i], m_data[m_size - i - 1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
ErrorOr<void> Vector<T>::resize(size_type size) requires is_default_constructible_v<T>
|
|
||||||
{
|
|
||||||
TRY(ensure_capacity(size));
|
|
||||||
if (size < m_size)
|
|
||||||
for (size_type i = size; i < m_size; i++)
|
|
||||||
m_data[i].~T();
|
|
||||||
if (size > m_size)
|
|
||||||
for (size_type i = m_size; i < size; i++)
|
|
||||||
new (m_data + i) T();
|
|
||||||
m_size = size;
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
ErrorOr<void> Vector<T>::resize(size_type size, const T& value) requires is_copy_constructible_v<T>
|
|
||||||
{
|
{
|
||||||
TRY(ensure_capacity(size));
|
TRY(ensure_capacity(size));
|
||||||
if (size < m_size)
|
if (size < m_size)
|
||||||
|
|
|
@ -2,10 +2,6 @@
|
||||||
|
|
||||||
#include <BAN/RefPtr.h>
|
#include <BAN/RefPtr.h>
|
||||||
|
|
||||||
#if __is_kernel
|
|
||||||
#include <kernel/Lock/SpinLock.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace BAN
|
namespace BAN
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -15,37 +11,22 @@ namespace BAN
|
||||||
template<typename T>
|
template<typename T>
|
||||||
class WeakPtr;
|
class WeakPtr;
|
||||||
|
|
||||||
// FIXME: Write this without using locks...
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
class WeakLink : public RefCounted<WeakLink<T>>
|
class WeakLink : public RefCounted<WeakLink<T>>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
RefPtr<T> try_lock()
|
RefPtr<T> lock() { ASSERT(m_ptr); return raw_ptr(); }
|
||||||
{
|
T* raw_ptr() { return m_ptr; }
|
||||||
#if __is_kernel
|
|
||||||
Kernel::SpinLockGuard _(m_weak_lock);
|
|
||||||
#endif
|
|
||||||
if (m_ptr && m_ptr->try_ref())
|
|
||||||
return RefPtr<T>::adopt(m_ptr);
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
bool valid() const { return m_ptr; }
|
bool valid() const { return m_ptr; }
|
||||||
void invalidate()
|
void invalidate() { m_ptr = nullptr; }
|
||||||
{
|
|
||||||
#if __is_kernel
|
|
||||||
Kernel::SpinLockGuard _(m_weak_lock);
|
|
||||||
#endif
|
|
||||||
m_ptr = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
WeakLink(T* ptr) : m_ptr(ptr) {}
|
WeakLink(T* ptr) : m_ptr(ptr) {}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
T* m_ptr;
|
T* m_ptr;
|
||||||
#if __is_kernel
|
|
||||||
Kernel::SpinLock m_weak_lock;
|
|
||||||
#endif
|
|
||||||
friend class RefPtr<WeakLink<T>>;
|
friend class RefPtr<WeakLink<T>>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -53,7 +34,7 @@ namespace BAN
|
||||||
class Weakable
|
class Weakable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual ~Weakable()
|
~Weakable()
|
||||||
{
|
{
|
||||||
if (m_link)
|
if (m_link)
|
||||||
m_link->invalidate();
|
m_link->invalidate();
|
||||||
|
@ -101,8 +82,8 @@ namespace BAN
|
||||||
|
|
||||||
RefPtr<T> lock()
|
RefPtr<T> lock()
|
||||||
{
|
{
|
||||||
if (m_link)
|
if (m_link->valid())
|
||||||
return m_link->try_lock();
|
return m_link->lock();
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -110,8 +91,6 @@ namespace BAN
|
||||||
|
|
||||||
bool valid() const { return m_link && m_link->valid(); }
|
bool valid() const { return m_link && m_link->valid(); }
|
||||||
|
|
||||||
explicit operator bool() const { return valid(); }
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
WeakPtr(const RefPtr<WeakLink<T>>& link)
|
WeakPtr(const RefPtr<WeakLink<T>>& link)
|
||||||
: m_link(link)
|
: m_link(link)
|
||||||
|
@ -125,4 +104,4 @@ namespace BAN
|
||||||
friend class Weakable<T>;
|
friend class Weakable<T>;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
|
@ -4,54 +4,41 @@ if (NOT ${CMAKE_SYSTEM_NAME} STREQUAL "banan-os")
|
||||||
message(FATAL_ERROR "CMAKE_SYSTEM_NAME is not banan-os")
|
message(FATAL_ERROR "CMAKE_SYSTEM_NAME is not banan-os")
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
|
add_compile_options(-mno-sse -mno-sse2)
|
||||||
|
add_compile_definitions(__enable_sse=0)
|
||||||
|
|
||||||
project(banan-os CXX C ASM)
|
project(banan-os CXX C ASM)
|
||||||
|
|
||||||
|
set(BANAN_BASE_SYSROOT ${CMAKE_SOURCE_DIR}/base-sysroot.tar.gz)
|
||||||
set(BANAN_INCLUDE ${BANAN_SYSROOT}/usr/include)
|
set(BANAN_INCLUDE ${BANAN_SYSROOT}/usr/include)
|
||||||
set(BANAN_LIB ${BANAN_SYSROOT}/usr/lib)
|
set(BANAN_LIB ${BANAN_SYSROOT}/usr/lib)
|
||||||
set(BANAN_BIN ${BANAN_SYSROOT}/usr/bin)
|
set(BANAN_BIN ${BANAN_SYSROOT}/usr/bin)
|
||||||
set(BANAN_ETC ${BANAN_SYSROOT}/usr/etc)
|
set(BANAN_BOOT ${BANAN_SYSROOT}/boot)
|
||||||
set(BANAN_SHARE ${BANAN_SYSROOT}/usr/share)
|
|
||||||
set(BANAN_BOOT ${BANAN_SYSROOT}/boot)
|
|
||||||
|
|
||||||
set(CMAKE_INSTALL_BINDIR ${BANAN_BIN})
|
|
||||||
set(CMAKE_INSTALL_SBINDIR ${BANAN_BIN})
|
|
||||||
set(CMAKE_INSTALL_LIBDIR ${BANAN_LIB})
|
|
||||||
set(CMAKE_INSTALL_INCLUDEDIR ${BANAN_INCLUDE})
|
|
||||||
set(CMAKE_INSTALL_SYSCONF ${BANAN_ETC})
|
|
||||||
set(CMAKE_INSTALL_MESSAGE NEVER)
|
|
||||||
set(CMAKE_SKIP_INSTALL_ALL_DEPENDENCY True)
|
|
||||||
|
|
||||||
set(CMAKE_STATIC_LIBRARY_PREFIX "")
|
|
||||||
set(CMAKE_SHARED_LIBRARY_PREFIX "")
|
|
||||||
set(BUILD_SHARED_LIBS True)
|
|
||||||
|
|
||||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
|
||||||
|
|
||||||
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}")
|
|
||||||
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}")
|
|
||||||
|
|
||||||
# include headers of ${library} to ${target}
|
|
||||||
function(banan_include_headers target library)
|
|
||||||
target_include_directories(${target} PRIVATE $<TARGET_PROPERTY:${library},SOURCE_DIR>/include)
|
|
||||||
endfunction()
|
|
||||||
|
|
||||||
# include headers and link ${library} to ${target}
|
|
||||||
function(banan_link_library target library)
|
|
||||||
target_link_libraries(${target} PRIVATE ${library})
|
|
||||||
banan_include_headers(${target} ${library})
|
|
||||||
endfunction()
|
|
||||||
|
|
||||||
# add install step for all header files of target
|
|
||||||
function(banan_install_headers target)
|
|
||||||
file(GLOB_RECURSE headers RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/include *.h)
|
|
||||||
foreach(header ${headers})
|
|
||||||
get_filename_component(subdirectory ${header} DIRECTORY)
|
|
||||||
install(FILES include/${header} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${subdirectory})
|
|
||||||
endforeach()
|
|
||||||
target_include_directories(${target} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include)
|
|
||||||
endfunction()
|
|
||||||
|
|
||||||
add_subdirectory(kernel)
|
add_subdirectory(kernel)
|
||||||
add_subdirectory(bootloader)
|
add_subdirectory(bootloader)
|
||||||
add_subdirectory(BAN)
|
add_subdirectory(BAN)
|
||||||
|
add_subdirectory(libc)
|
||||||
|
add_subdirectory(LibELF)
|
||||||
add_subdirectory(userspace)
|
add_subdirectory(userspace)
|
||||||
|
|
||||||
|
add_custom_target(sysroot
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E make_directory ${BANAN_SYSROOT}
|
||||||
|
COMMAND cd ${BANAN_SYSROOT} && tar xf ${BANAN_BASE_SYSROOT}
|
||||||
|
)
|
||||||
|
|
||||||
|
add_custom_target(headers
|
||||||
|
DEPENDS kernel-headers
|
||||||
|
DEPENDS ban-headers
|
||||||
|
DEPENDS libc-headers
|
||||||
|
DEPENDS libelf-headers
|
||||||
|
)
|
||||||
|
|
||||||
|
add_custom_target(install-sysroot
|
||||||
|
COMMAND cd ${BANAN_SYSROOT} && tar cf ${BANAN_SYSROOT_TAR} *
|
||||||
|
DEPENDS kernel-install
|
||||||
|
DEPENDS ban-install
|
||||||
|
DEPENDS libc-install
|
||||||
|
DEPENDS userspace-install
|
||||||
|
DEPENDS libelf-install
|
||||||
|
)
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
cmake_minimum_required(VERSION 3.26)
|
||||||
|
|
||||||
|
project(LibELF CXX)
|
||||||
|
|
||||||
|
add_custom_target(libelf-headers
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E copy_directory_if_different ${CMAKE_CURRENT_SOURCE_DIR}/include/ ${BANAN_INCLUDE}/
|
||||||
|
DEPENDS sysroot
|
||||||
|
)
|
||||||
|
|
||||||
|
add_custom_target(libelf-install
|
||||||
|
DEPENDS libelf-headers
|
||||||
|
)
|
|
@ -0,0 +1,406 @@
|
||||||
|
#include <BAN/ScopeGuard.h>
|
||||||
|
#include <LibELF/ELF.h>
|
||||||
|
#include <LibELF/Values.h>
|
||||||
|
|
||||||
|
#ifdef __is_kernel
|
||||||
|
#include <kernel/FS/VirtualFileSystem.h>
|
||||||
|
#include <kernel/Memory/PageTableScope.h>
|
||||||
|
#include <kernel/Process.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <fcntl.h>
|
||||||
|
|
||||||
|
#define ELF_PRINT_HEADERS 0
|
||||||
|
|
||||||
|
#ifdef __is_kernel
|
||||||
|
extern uint8_t g_kernel_end[];
|
||||||
|
using namespace Kernel;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace LibELF
|
||||||
|
{
|
||||||
|
|
||||||
|
#ifdef __is_kernel
|
||||||
|
BAN::ErrorOr<BAN::UniqPtr<ELF>> ELF::load_from_file(BAN::RefPtr<Inode> inode)
|
||||||
|
{
|
||||||
|
BAN::Vector<uint8_t> buffer;
|
||||||
|
TRY(buffer.resize(inode->size()));
|
||||||
|
|
||||||
|
TRY(inode->read(0, buffer.data(), inode->size()));
|
||||||
|
|
||||||
|
ELF* elf_ptr = new ELF(BAN::move(buffer));
|
||||||
|
if (elf_ptr == nullptr)
|
||||||
|
return BAN::Error::from_errno(ENOMEM);
|
||||||
|
|
||||||
|
auto elf = BAN::UniqPtr<ELF>::adopt(elf_ptr);
|
||||||
|
TRY(elf->load());
|
||||||
|
|
||||||
|
return BAN::move(elf);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
BAN::ErrorOr<ELF*> ELF::load_from_file(BAN::StringView file_path)
|
||||||
|
{
|
||||||
|
ELF* elf = nullptr;
|
||||||
|
|
||||||
|
{
|
||||||
|
BAN::Vector<uint8_t> data;
|
||||||
|
|
||||||
|
int fd = TRY(Kernel::Process::current().open(file_path, O_RDONLY));
|
||||||
|
BAN::ScopeGuard _([fd] { MUST(Kernel::Process::current().close(fd)); });
|
||||||
|
|
||||||
|
struct stat st;
|
||||||
|
TRY(Kernel::Process::current().fstat(fd, &st));
|
||||||
|
|
||||||
|
TRY(data.resize(st.st_size));
|
||||||
|
|
||||||
|
TRY(Kernel::Process::current().read(fd, data.data(), data.size()));
|
||||||
|
|
||||||
|
elf = new ELF(BAN::move(data));
|
||||||
|
ASSERT(elf);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (auto res = elf->load(); res.is_error())
|
||||||
|
{
|
||||||
|
delete elf;
|
||||||
|
return res.error();
|
||||||
|
}
|
||||||
|
|
||||||
|
return elf;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
BAN::ErrorOr<void> ELF::load()
|
||||||
|
{
|
||||||
|
if (m_data.size() < EI_NIDENT)
|
||||||
|
{
|
||||||
|
dprintln("Too small ELF file");
|
||||||
|
return BAN::Error::from_errno(EINVAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_data[EI_MAG0] != ELFMAG0 ||
|
||||||
|
m_data[EI_MAG1] != ELFMAG1 ||
|
||||||
|
m_data[EI_MAG2] != ELFMAG2 ||
|
||||||
|
m_data[EI_MAG3] != ELFMAG3)
|
||||||
|
{
|
||||||
|
dprintln("Invalid ELF header");
|
||||||
|
return BAN::Error::from_errno(EINVAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_data[EI_DATA] != ELFDATA2LSB)
|
||||||
|
{
|
||||||
|
dprintln("Only little-endian is supported");
|
||||||
|
return BAN::Error::from_errno(EINVAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_data[EI_VERSION] != EV_CURRENT)
|
||||||
|
{
|
||||||
|
dprintln("Invalid ELF version");
|
||||||
|
return BAN::Error::from_errno(EINVAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_data[EI_CLASS] == ELFCLASS64)
|
||||||
|
{
|
||||||
|
if (m_data.size() <= sizeof(Elf64FileHeader))
|
||||||
|
{
|
||||||
|
dprintln("Too small ELF file");
|
||||||
|
return BAN::Error::from_errno(EINVAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto& header = file_header64();
|
||||||
|
if (!parse_elf64_file_header(header))
|
||||||
|
return BAN::Error::from_errno(EINVAL);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < header.e_phnum; i++)
|
||||||
|
{
|
||||||
|
auto& program_header = program_header64(i);
|
||||||
|
if (!parse_elf64_program_header(program_header))
|
||||||
|
return BAN::Error::from_errno(EINVAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 1; i < header.e_shnum; i++)
|
||||||
|
{
|
||||||
|
auto& section_header = section_header64(i);
|
||||||
|
if (!parse_elf64_section_header(section_header))
|
||||||
|
return BAN::Error::from_errno(EINVAL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (m_data[EI_CLASS] == ELFCLASS32)
|
||||||
|
{
|
||||||
|
if (m_data.size() <= sizeof(Elf32FileHeader))
|
||||||
|
{
|
||||||
|
dprintln("Too small ELF file");
|
||||||
|
return BAN::Error::from_errno(EINVAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto& header = file_header32();
|
||||||
|
if (!parse_elf32_file_header(header))
|
||||||
|
return BAN::Error::from_errno(EINVAL);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < header.e_phnum; i++)
|
||||||
|
{
|
||||||
|
auto& program_header = program_header32(i);
|
||||||
|
if (!parse_elf32_program_header(program_header))
|
||||||
|
return BAN::Error::from_errno(EINVAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 1; i < header.e_shnum; i++)
|
||||||
|
{
|
||||||
|
auto& section_header = section_header32(i);
|
||||||
|
if (!parse_elf32_section_header(section_header))
|
||||||
|
return BAN::Error::from_errno(EINVAL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ELF::is_x86_32() const { return m_data[EI_CLASS] == ELFCLASS32; }
|
||||||
|
bool ELF::is_x86_64() const { return m_data[EI_CLASS] == ELFCLASS64; }
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
64 bit ELF
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
const char* ELF::lookup_section_name64(uint32_t offset) const
|
||||||
|
{
|
||||||
|
return lookup_string64(file_header64().e_shstrndx, offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* ELF::lookup_string64(size_t table_index, uint32_t offset) const
|
||||||
|
{
|
||||||
|
if (table_index == SHN_UNDEF)
|
||||||
|
return nullptr;
|
||||||
|
auto& section_header = section_header64(table_index);
|
||||||
|
return (const char*)m_data.data() + section_header.sh_offset + offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ELF::parse_elf64_file_header(const Elf64FileHeader& header)
|
||||||
|
{
|
||||||
|
if (header.e_type != ET_EXEC)
|
||||||
|
{
|
||||||
|
dprintln("Only executable files are supported");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (header.e_version != EV_CURRENT)
|
||||||
|
{
|
||||||
|
dprintln("Invalid ELF version");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ELF::parse_elf64_program_header(const Elf64ProgramHeader& header)
|
||||||
|
{
|
||||||
|
#if ELF_PRINT_HEADERS
|
||||||
|
dprintln("program header");
|
||||||
|
dprintln(" type {H}", header.p_type);
|
||||||
|
dprintln(" flags {H}", header.p_flags);
|
||||||
|
dprintln(" offset {H}", header.p_offset);
|
||||||
|
dprintln(" vaddr {H}", header.p_vaddr);
|
||||||
|
dprintln(" paddr {H}", header.p_paddr);
|
||||||
|
dprintln(" filesz {}", header.p_filesz);
|
||||||
|
dprintln(" memsz {}", header.p_memsz);
|
||||||
|
dprintln(" align {}", header.p_align);
|
||||||
|
#endif
|
||||||
|
(void)header;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ELF::parse_elf64_section_header(const Elf64SectionHeader& header)
|
||||||
|
{
|
||||||
|
#if ELF_PRINT_HEADERS
|
||||||
|
if (auto* name = lookup_section_name64(header.sh_name))
|
||||||
|
dprintln("{}", name);
|
||||||
|
|
||||||
|
switch (header.sh_type)
|
||||||
|
{
|
||||||
|
case SHT_NULL:
|
||||||
|
dprintln(" SHT_NULL");
|
||||||
|
break;
|
||||||
|
case SHT_PROGBITS:
|
||||||
|
dprintln(" SHT_PROGBITS");
|
||||||
|
break;
|
||||||
|
case SHT_SYMTAB:
|
||||||
|
for (size_t i = 1; i < header.sh_size / header.sh_entsize; i++)
|
||||||
|
{
|
||||||
|
auto& symbol = ((const Elf64Symbol*)(m_data.data() + header.sh_offset))[i];
|
||||||
|
if (auto* name = lookup_string64(header.sh_link, symbol.st_name))
|
||||||
|
dprintln(" {}", name);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SHT_STRTAB:
|
||||||
|
dprintln(" SHT_STRTAB");
|
||||||
|
break;
|
||||||
|
case SHT_RELA:
|
||||||
|
dprintln(" SHT_RELA");
|
||||||
|
break;
|
||||||
|
case SHT_NOBITS:
|
||||||
|
dprintln(" SHT_NOBITS");
|
||||||
|
break;
|
||||||
|
case SHT_REL:
|
||||||
|
dprintln(" SHT_REL");
|
||||||
|
break;
|
||||||
|
case SHT_SHLIB:
|
||||||
|
dprintln(" SHT_SHLIB");
|
||||||
|
break;
|
||||||
|
case SHT_DYNSYM:
|
||||||
|
dprintln(" SHT_DYNSYM");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ASSERT(false);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
(void)header;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Elf64FileHeader& ELF::file_header64() const
|
||||||
|
{
|
||||||
|
ASSERT(is_x86_64());
|
||||||
|
return *(const Elf64FileHeader*)m_data.data();
|
||||||
|
}
|
||||||
|
|
||||||
|
const Elf64ProgramHeader& ELF::program_header64(size_t index) const
|
||||||
|
{
|
||||||
|
ASSERT(is_x86_64());
|
||||||
|
const auto& file_header = file_header64();
|
||||||
|
ASSERT(index < file_header.e_phnum);
|
||||||
|
return *(const Elf64ProgramHeader*)(m_data.data() + file_header.e_phoff + file_header.e_phentsize * index);
|
||||||
|
}
|
||||||
|
|
||||||
|
const Elf64SectionHeader& ELF::section_header64(size_t index) const
|
||||||
|
{
|
||||||
|
ASSERT(is_x86_64());
|
||||||
|
const auto& file_header = file_header64();
|
||||||
|
ASSERT(index < file_header.e_shnum);
|
||||||
|
return *(const Elf64SectionHeader*)(m_data.data() + file_header.e_shoff + file_header.e_shentsize * index);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
32 bit ELF
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
const char* ELF::lookup_section_name32(uint32_t offset) const
|
||||||
|
{
|
||||||
|
return lookup_string32(file_header32().e_shstrndx, offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* ELF::lookup_string32(size_t table_index, uint32_t offset) const
|
||||||
|
{
|
||||||
|
if (table_index == SHN_UNDEF)
|
||||||
|
return nullptr;
|
||||||
|
auto& section_header = section_header32(table_index);
|
||||||
|
return (const char*)m_data.data() + section_header.sh_offset + offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ELF::parse_elf32_file_header(const Elf32FileHeader& header)
|
||||||
|
{
|
||||||
|
if (header.e_type != ET_EXEC)
|
||||||
|
{
|
||||||
|
dprintln("Only executable files are supported");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (header.e_version != EV_CURRENT)
|
||||||
|
{
|
||||||
|
dprintln("Invalid ELF version");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ELF::parse_elf32_program_header(const Elf32ProgramHeader& header)
|
||||||
|
{
|
||||||
|
#if ELF_PRINT_HEADERS
|
||||||
|
dprintln("program header");
|
||||||
|
dprintln(" type {H}", header.p_type);
|
||||||
|
dprintln(" flags {H}", header.p_flags);
|
||||||
|
dprintln(" offset {H}", header.p_offset);
|
||||||
|
dprintln(" vaddr {H}", header.p_vaddr);
|
||||||
|
dprintln(" paddr {H}", header.p_paddr);
|
||||||
|
dprintln(" filesz {}", header.p_filesz);
|
||||||
|
dprintln(" memsz {}", header.p_memsz);
|
||||||
|
dprintln(" align {}", header.p_align);
|
||||||
|
#endif
|
||||||
|
(void)header;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ELF::parse_elf32_section_header(const Elf32SectionHeader& header)
|
||||||
|
{
|
||||||
|
#if ELF_PRINT_HEADERS
|
||||||
|
if (auto* name = lookup_section_name32(header.sh_name))
|
||||||
|
dprintln("{}", name);
|
||||||
|
|
||||||
|
switch (header.sh_type)
|
||||||
|
{
|
||||||
|
case SHT_NULL:
|
||||||
|
dprintln(" SHT_NULL");
|
||||||
|
break;
|
||||||
|
case SHT_PROGBITS:
|
||||||
|
dprintln(" SHT_PROGBITS");
|
||||||
|
break;
|
||||||
|
case SHT_SYMTAB:
|
||||||
|
for (size_t i = 1; i < header.sh_size / header.sh_entsize; i++)
|
||||||
|
{
|
||||||
|
auto& symbol = ((const Elf32Symbol*)(m_data.data() + header.sh_offset))[i];
|
||||||
|
if (auto* name = lookup_string32(header.sh_link, symbol.st_name))
|
||||||
|
dprintln(" {}", name);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SHT_STRTAB:
|
||||||
|
dprintln(" SHT_STRTAB");
|
||||||
|
break;
|
||||||
|
case SHT_RELA:
|
||||||
|
dprintln(" SHT_RELA");
|
||||||
|
break;
|
||||||
|
case SHT_NOBITS:
|
||||||
|
dprintln(" SHT_NOBITS");
|
||||||
|
break;
|
||||||
|
case SHT_REL:
|
||||||
|
dprintln(" SHT_REL");
|
||||||
|
break;
|
||||||
|
case SHT_SHLIB:
|
||||||
|
dprintln(" SHT_SHLIB");
|
||||||
|
break;
|
||||||
|
case SHT_DYNSYM:
|
||||||
|
dprintln(" SHT_DYNSYM");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ASSERT(false);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
(void)header;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Elf32FileHeader& ELF::file_header32() const
|
||||||
|
{
|
||||||
|
ASSERT(is_x86_32());
|
||||||
|
return *(const Elf32FileHeader*)m_data.data();
|
||||||
|
}
|
||||||
|
|
||||||
|
const Elf32ProgramHeader& ELF::program_header32(size_t index) const
|
||||||
|
{
|
||||||
|
ASSERT(is_x86_32());
|
||||||
|
const auto& file_header = file_header32();
|
||||||
|
ASSERT(index < file_header.e_phnum);
|
||||||
|
return *(const Elf32ProgramHeader*)(m_data.data() + file_header.e_phoff + file_header.e_phentsize * index);
|
||||||
|
}
|
||||||
|
|
||||||
|
const Elf32SectionHeader& ELF::section_header32(size_t index) const
|
||||||
|
{
|
||||||
|
ASSERT(is_x86_32());
|
||||||
|
const auto& file_header = file_header32();
|
||||||
|
ASSERT(index < file_header.e_shnum);
|
||||||
|
return *(const Elf32SectionHeader*)(m_data.data() + file_header.e_shoff + file_header.e_shentsize * index);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,331 @@
|
||||||
|
#include <BAN/ScopeGuard.h>
|
||||||
|
#include <kernel/CriticalScope.h>
|
||||||
|
#include <kernel/Memory/Heap.h>
|
||||||
|
#include <kernel/LockGuard.h>
|
||||||
|
#include <LibELF/LoadableELF.h>
|
||||||
|
#include <LibELF/Values.h>
|
||||||
|
|
||||||
|
namespace LibELF
|
||||||
|
{
|
||||||
|
|
||||||
|
using namespace Kernel;
|
||||||
|
|
||||||
|
BAN::ErrorOr<BAN::UniqPtr<LoadableELF>> LoadableELF::load_from_inode(PageTable& page_table, BAN::RefPtr<Inode> inode)
|
||||||
|
{
|
||||||
|
auto* elf_ptr = new LoadableELF(page_table, inode);
|
||||||
|
if (elf_ptr == nullptr)
|
||||||
|
return BAN::Error::from_errno(ENOMEM);
|
||||||
|
auto elf = BAN::UniqPtr<LoadableELF>::adopt(elf_ptr);
|
||||||
|
TRY(elf->initialize());
|
||||||
|
return BAN::move(elf);
|
||||||
|
}
|
||||||
|
|
||||||
|
LoadableELF::LoadableELF(PageTable& page_table, BAN::RefPtr<Inode> inode)
|
||||||
|
: m_inode(inode)
|
||||||
|
, m_page_table(page_table)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
LoadableELF::~LoadableELF()
|
||||||
|
{
|
||||||
|
if (!m_loaded)
|
||||||
|
return;
|
||||||
|
for (const auto& program_header : m_program_headers)
|
||||||
|
{
|
||||||
|
switch (program_header.p_type)
|
||||||
|
{
|
||||||
|
case PT_NULL:
|
||||||
|
continue;
|
||||||
|
case PT_LOAD:
|
||||||
|
{
|
||||||
|
vaddr_t start = program_header.p_vaddr & PAGE_ADDR_MASK;
|
||||||
|
size_t pages = range_page_count(program_header.p_vaddr, program_header.p_memsz);
|
||||||
|
for (size_t i = 0; i < pages; i++)
|
||||||
|
{
|
||||||
|
paddr_t paddr = m_page_table.physical_address_of(start + i * PAGE_SIZE);
|
||||||
|
if (paddr != 0)
|
||||||
|
Heap::get().release_page(paddr);
|
||||||
|
}
|
||||||
|
m_page_table.unmap_range(start, pages * PAGE_SIZE);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
ASSERT_NOT_REACHED();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BAN::ErrorOr<void> LoadableELF::initialize()
|
||||||
|
{
|
||||||
|
if ((size_t)m_inode->size() < sizeof(ElfNativeFileHeader))
|
||||||
|
{
|
||||||
|
dprintln("Too small file");
|
||||||
|
return BAN::Error::from_errno(ENOEXEC);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t nread = TRY(m_inode->read(0, BAN::ByteSpan::from(m_file_header)));
|
||||||
|
ASSERT(nread == sizeof(m_file_header));
|
||||||
|
|
||||||
|
if (m_file_header.e_ident[EI_MAG0] != ELFMAG0 ||
|
||||||
|
m_file_header.e_ident[EI_MAG1] != ELFMAG1 ||
|
||||||
|
m_file_header.e_ident[EI_MAG2] != ELFMAG2 ||
|
||||||
|
m_file_header.e_ident[EI_MAG3] != ELFMAG3)
|
||||||
|
{
|
||||||
|
dprintln("Invalid magic in header");
|
||||||
|
return BAN::Error::from_errno(ENOEXEC);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_file_header.e_ident[EI_DATA] != ELFDATA2LSB)
|
||||||
|
{
|
||||||
|
dprintln("Only little-endian is supported");
|
||||||
|
return BAN::Error::from_errno(ENOEXEC);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_file_header.e_ident[EI_VERSION] != EV_CURRENT)
|
||||||
|
{
|
||||||
|
dprintln("Invalid version");
|
||||||
|
return BAN::Error::from_errno(ENOEXEC);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if ARCH(i386)
|
||||||
|
if (m_file_header.e_ident[EI_CLASS] != ELFCLASS32)
|
||||||
|
#elif ARCH(x86_64)
|
||||||
|
if (m_file_header.e_ident[EI_CLASS] != ELFCLASS64)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
dprintln("Not in native format");
|
||||||
|
return BAN::Error::from_errno(EINVAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_file_header.e_type != ET_EXEC)
|
||||||
|
{
|
||||||
|
dprintln("Only executable files are supported");
|
||||||
|
return BAN::Error::from_errno(EINVAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_file_header.e_version != EV_CURRENT)
|
||||||
|
{
|
||||||
|
dprintln("Unsupported version");
|
||||||
|
return BAN::Error::from_errno(EINVAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSERT(m_file_header.e_phentsize <= sizeof(ElfNativeProgramHeader));
|
||||||
|
|
||||||
|
TRY(m_program_headers.resize(m_file_header.e_phnum));
|
||||||
|
for (size_t i = 0; i < m_file_header.e_phnum; i++)
|
||||||
|
{
|
||||||
|
TRY(m_inode->read(m_file_header.e_phoff + m_file_header.e_phentsize * i, BAN::ByteSpan::from(m_program_headers[i])));
|
||||||
|
|
||||||
|
const auto& pheader = m_program_headers[i];
|
||||||
|
if (pheader.p_type != PT_NULL && pheader.p_type != PT_LOAD)
|
||||||
|
{
|
||||||
|
dprintln("Unsupported program header type {}", pheader.p_type);
|
||||||
|
return BAN::Error::from_errno(ENOTSUP);
|
||||||
|
}
|
||||||
|
if (pheader.p_memsz < pheader.p_filesz)
|
||||||
|
{
|
||||||
|
dprintln("Invalid program header");
|
||||||
|
return BAN::Error::from_errno(EINVAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_virtual_page_count += BAN::Math::div_round_up<size_t>((pheader.p_vaddr % PAGE_SIZE) + pheader.p_memsz, PAGE_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
vaddr_t LoadableELF::entry_point() const
|
||||||
|
{
|
||||||
|
return m_file_header.e_entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LoadableELF::contains(vaddr_t address) const
|
||||||
|
{
|
||||||
|
for (const auto& program_header : m_program_headers)
|
||||||
|
{
|
||||||
|
switch (program_header.p_type)
|
||||||
|
{
|
||||||
|
case PT_NULL:
|
||||||
|
continue;
|
||||||
|
case PT_LOAD:
|
||||||
|
if (program_header.p_vaddr <= address && address < program_header.p_vaddr + program_header.p_memsz)
|
||||||
|
return true;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ASSERT_NOT_REACHED();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LoadableELF::is_address_space_free() const
|
||||||
|
{
|
||||||
|
for (const auto& program_header : m_program_headers)
|
||||||
|
{
|
||||||
|
switch (program_header.p_type)
|
||||||
|
{
|
||||||
|
case PT_NULL:
|
||||||
|
break;
|
||||||
|
case PT_LOAD:
|
||||||
|
{
|
||||||
|
vaddr_t page_vaddr = program_header.p_vaddr & PAGE_ADDR_MASK;
|
||||||
|
size_t pages = range_page_count(program_header.p_vaddr, program_header.p_memsz);
|
||||||
|
if (!m_page_table.is_range_free(page_vaddr, pages * PAGE_SIZE))
|
||||||
|
return false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
ASSERT_NOT_REACHED();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LoadableELF::reserve_address_space()
|
||||||
|
{
|
||||||
|
for (const auto& program_header : m_program_headers)
|
||||||
|
{
|
||||||
|
switch (program_header.p_type)
|
||||||
|
{
|
||||||
|
case PT_NULL:
|
||||||
|
break;
|
||||||
|
case PT_LOAD:
|
||||||
|
{
|
||||||
|
vaddr_t page_vaddr = program_header.p_vaddr & PAGE_ADDR_MASK;
|
||||||
|
size_t pages = range_page_count(program_header.p_vaddr, program_header.p_memsz);
|
||||||
|
ASSERT(m_page_table.reserve_range(page_vaddr, pages * PAGE_SIZE));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
ASSERT_NOT_REACHED();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m_loaded = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
BAN::ErrorOr<void> LoadableELF::load_page_to_memory(vaddr_t address)
|
||||||
|
{
|
||||||
|
for (const auto& program_header : m_program_headers)
|
||||||
|
{
|
||||||
|
switch (program_header.p_type)
|
||||||
|
{
|
||||||
|
case PT_NULL:
|
||||||
|
break;
|
||||||
|
case PT_LOAD:
|
||||||
|
{
|
||||||
|
if (!(program_header.p_vaddr <= address && address < program_header.p_vaddr + program_header.p_memsz))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
PageTable::flags_t flags = PageTable::Flags::UserSupervisor | PageTable::Flags::Present;
|
||||||
|
if (program_header.p_flags & LibELF::PF_W)
|
||||||
|
flags |= PageTable::Flags::ReadWrite;
|
||||||
|
if (program_header.p_flags & LibELF::PF_X)
|
||||||
|
flags |= PageTable::Flags::Execute;
|
||||||
|
|
||||||
|
vaddr_t vaddr = address & PAGE_ADDR_MASK;
|
||||||
|
paddr_t paddr = Heap::get().take_free_page();
|
||||||
|
if (paddr == 0)
|
||||||
|
return BAN::Error::from_errno(ENOMEM);
|
||||||
|
|
||||||
|
// Temporarily map page as RW so kernel can write to it
|
||||||
|
m_page_table.map_page_at(paddr, vaddr, PageTable::Flags::ReadWrite | PageTable::Flags::Present);
|
||||||
|
m_physical_page_count++;
|
||||||
|
|
||||||
|
memset((void*)vaddr, 0x00, PAGE_SIZE);
|
||||||
|
|
||||||
|
if (vaddr / PAGE_SIZE < BAN::Math::div_round_up<size_t>(program_header.p_vaddr + program_header.p_filesz, PAGE_SIZE))
|
||||||
|
{
|
||||||
|
size_t vaddr_offset = 0;
|
||||||
|
if (vaddr < program_header.p_vaddr)
|
||||||
|
vaddr_offset = program_header.p_vaddr - vaddr;
|
||||||
|
|
||||||
|
size_t file_offset = 0;
|
||||||
|
if (vaddr > program_header.p_vaddr)
|
||||||
|
file_offset = vaddr - program_header.p_vaddr;
|
||||||
|
|
||||||
|
size_t bytes = BAN::Math::min<size_t>(PAGE_SIZE - vaddr_offset, program_header.p_filesz - file_offset);
|
||||||
|
TRY(m_inode->read(program_header.p_offset + file_offset, { (uint8_t*)vaddr + vaddr_offset, bytes }));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Map page with the correct flags
|
||||||
|
m_page_table.map_page_at(paddr, vaddr, flags);
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
ASSERT_NOT_REACHED();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ASSERT_NOT_REACHED();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BAN::ErrorOr<BAN::UniqPtr<LoadableELF>> LoadableELF::clone(Kernel::PageTable& new_page_table)
|
||||||
|
{
|
||||||
|
auto* elf_ptr = new LoadableELF(new_page_table, m_inode);
|
||||||
|
if (elf_ptr == nullptr)
|
||||||
|
return BAN::Error::from_errno(ENOMEM);
|
||||||
|
auto elf = BAN::UniqPtr<LoadableELF>::adopt(elf_ptr);
|
||||||
|
|
||||||
|
memcpy(&elf->m_file_header, &m_file_header, sizeof(ElfNativeFileHeader));
|
||||||
|
|
||||||
|
TRY(elf->m_program_headers.resize(m_program_headers.size()));
|
||||||
|
memcpy(elf->m_program_headers.data(), m_program_headers.data(), m_program_headers.size() * sizeof(ElfNativeProgramHeader));
|
||||||
|
|
||||||
|
elf->reserve_address_space();
|
||||||
|
|
||||||
|
ASSERT(&PageTable::current() == &m_page_table);
|
||||||
|
LockGuard _(m_page_table);
|
||||||
|
ASSERT(m_page_table.is_page_free(0));
|
||||||
|
|
||||||
|
for (const auto& program_header : m_program_headers)
|
||||||
|
{
|
||||||
|
switch (program_header.p_type)
|
||||||
|
{
|
||||||
|
case PT_NULL:
|
||||||
|
break;
|
||||||
|
case PT_LOAD:
|
||||||
|
{
|
||||||
|
if (!(program_header.p_flags & LibELF::PF_W))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
PageTable::flags_t flags = PageTable::Flags::UserSupervisor | PageTable::Flags::Present;
|
||||||
|
if (program_header.p_flags & LibELF::PF_W)
|
||||||
|
flags |= PageTable::Flags::ReadWrite;
|
||||||
|
if (program_header.p_flags & LibELF::PF_X)
|
||||||
|
flags |= PageTable::Flags::Execute;
|
||||||
|
|
||||||
|
vaddr_t start = program_header.p_vaddr & PAGE_ADDR_MASK;
|
||||||
|
size_t pages = range_page_count(program_header.p_vaddr, program_header.p_memsz);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < pages; i++)
|
||||||
|
{
|
||||||
|
if (m_page_table.physical_address_of(start + i * PAGE_SIZE) == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
paddr_t paddr = Heap::get().take_free_page();
|
||||||
|
if (paddr == 0)
|
||||||
|
return BAN::Error::from_errno(ENOMEM);
|
||||||
|
|
||||||
|
{
|
||||||
|
CriticalScope _;
|
||||||
|
PageTable::map_fast_page(paddr);
|
||||||
|
memcpy(PageTable::fast_page_as_ptr(), (void*)(start + i * PAGE_SIZE), PAGE_SIZE);
|
||||||
|
PageTable::unmap_fast_page();
|
||||||
|
}
|
||||||
|
|
||||||
|
new_page_table.map_page_at(paddr, start + i * PAGE_SIZE, flags);
|
||||||
|
elf->m_physical_page_count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
ASSERT_NOT_REACHED();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return elf;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,89 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifdef __is_kernel
|
||||||
|
#include <kernel/FS/Inode.h>
|
||||||
|
#include <kernel/Memory/VirtualRange.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <BAN/StringView.h>
|
||||||
|
#include <BAN/UniqPtr.h>
|
||||||
|
#include <BAN/Vector.h>
|
||||||
|
#include <kernel/Arch.h>
|
||||||
|
#include "Types.h"
|
||||||
|
|
||||||
|
namespace LibELF
|
||||||
|
{
|
||||||
|
|
||||||
|
class ELF
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
#ifdef __is_kernel
|
||||||
|
static BAN::ErrorOr<BAN::UniqPtr<ELF>> load_from_file(BAN::RefPtr<Kernel::Inode>);
|
||||||
|
#else
|
||||||
|
static BAN::ErrorOr<BAN::UniqPtr<ELF>> load_from_file(BAN::StringView);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
const Elf64FileHeader& file_header64() const;
|
||||||
|
const Elf64ProgramHeader& program_header64(size_t) const;
|
||||||
|
const Elf64SectionHeader& section_header64(size_t) const;
|
||||||
|
const char* lookup_section_name64(uint32_t) const;
|
||||||
|
const char* lookup_string64(size_t, uint32_t) const;
|
||||||
|
#if ARCH(x86_64)
|
||||||
|
const Elf64FileHeader& file_header_native() const { return file_header64(); }
|
||||||
|
const Elf64ProgramHeader& program_header_native(size_t index) const { return program_header64(index); }
|
||||||
|
const Elf64SectionHeader& section_header_native(size_t index) const { return section_header64(index); }
|
||||||
|
const char* lookup_section_name_native(uint32_t offset) const { return lookup_section_name64(offset); }
|
||||||
|
const char* lookup_string_native(size_t table_index, uint32_t offset) const { return lookup_string64(table_index, offset); }
|
||||||
|
bool is_native() const { return is_x86_64(); }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
const Elf32FileHeader& file_header32() const;
|
||||||
|
const Elf32ProgramHeader& program_header32(size_t) const;
|
||||||
|
const Elf32SectionHeader& section_header32(size_t) const;
|
||||||
|
const char* lookup_section_name32(uint32_t) const;
|
||||||
|
const char* lookup_string32(size_t, uint32_t) const;
|
||||||
|
#if ARCH(i386)
|
||||||
|
const Elf32FileHeader& file_header_native() const { return file_header32(); }
|
||||||
|
const Elf32ProgramHeader& program_header_native(size_t index) const { return program_header32(index); }
|
||||||
|
const Elf32SectionHeader& section_header_native(size_t index) const { return section_header32(index); }
|
||||||
|
const char* lookup_section_name_native(uint32_t offset) const { return lookup_section_name32(offset); }
|
||||||
|
const char* lookup_string_native(size_t table_index, uint32_t offset) const { return lookup_string32(table_index, offset); }
|
||||||
|
bool is_native() const { return is_x86_32(); }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
const uint8_t* data() const { return m_data.data(); }
|
||||||
|
|
||||||
|
bool is_x86_32() const;
|
||||||
|
bool is_x86_64() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
//#ifdef __is_kernel
|
||||||
|
// ELF(BAN::UniqPtr<Kernel::VirtualRange>&& storage, size_t size)
|
||||||
|
// : m_storage(BAN::move(storage))
|
||||||
|
// , m_data((const uint8_t*)m_storage->vaddr(), size)
|
||||||
|
// {}
|
||||||
|
//#else
|
||||||
|
ELF(BAN::Vector<uint8_t>&& data)
|
||||||
|
: m_data(BAN::move(data))
|
||||||
|
{}
|
||||||
|
//#endif
|
||||||
|
BAN::ErrorOr<void> load();
|
||||||
|
|
||||||
|
bool parse_elf64_file_header(const Elf64FileHeader&);
|
||||||
|
bool parse_elf64_program_header(const Elf64ProgramHeader&);
|
||||||
|
bool parse_elf64_section_header(const Elf64SectionHeader&);
|
||||||
|
|
||||||
|
bool parse_elf32_file_header(const Elf32FileHeader&);
|
||||||
|
bool parse_elf32_program_header(const Elf32ProgramHeader&);
|
||||||
|
bool parse_elf32_section_header(const Elf32SectionHeader&);
|
||||||
|
|
||||||
|
private:
|
||||||
|
//#ifdef __is_kernel
|
||||||
|
// BAN::UniqPtr<Kernel::VirtualRange> m_storage;
|
||||||
|
// BAN::Span<const uint8_t> m_data;
|
||||||
|
//#else
|
||||||
|
const BAN::Vector<uint8_t> m_data;
|
||||||
|
//#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,54 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifndef __is_kernel
|
||||||
|
#error "This is kernel only header"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <BAN/UniqPtr.h>
|
||||||
|
#include <BAN/Vector.h>
|
||||||
|
|
||||||
|
#include <kernel/FS/Inode.h>
|
||||||
|
#include <kernel/Memory/PageTable.h>
|
||||||
|
|
||||||
|
#include <LibELF/Types.h>
|
||||||
|
|
||||||
|
namespace LibELF
|
||||||
|
{
|
||||||
|
|
||||||
|
class LoadableELF
|
||||||
|
{
|
||||||
|
BAN_NON_COPYABLE(LoadableELF);
|
||||||
|
BAN_NON_MOVABLE(LoadableELF);
|
||||||
|
|
||||||
|
public:
|
||||||
|
static BAN::ErrorOr<BAN::UniqPtr<LoadableELF>> load_from_inode(Kernel::PageTable&, BAN::RefPtr<Kernel::Inode>);
|
||||||
|
~LoadableELF();
|
||||||
|
|
||||||
|
Kernel::vaddr_t entry_point() const;
|
||||||
|
|
||||||
|
bool contains(Kernel::vaddr_t address) const;
|
||||||
|
bool is_address_space_free() const;
|
||||||
|
void reserve_address_space();
|
||||||
|
|
||||||
|
BAN::ErrorOr<void> load_page_to_memory(Kernel::vaddr_t address);
|
||||||
|
|
||||||
|
BAN::ErrorOr<BAN::UniqPtr<LoadableELF>> clone(Kernel::PageTable&);
|
||||||
|
|
||||||
|
size_t virtual_page_count() const { return m_virtual_page_count; }
|
||||||
|
size_t physical_page_count() const { return m_physical_page_count; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
LoadableELF(Kernel::PageTable&, BAN::RefPtr<Kernel::Inode>);
|
||||||
|
BAN::ErrorOr<void> initialize();
|
||||||
|
|
||||||
|
private:
|
||||||
|
BAN::RefPtr<Kernel::Inode> m_inode;
|
||||||
|
Kernel::PageTable& m_page_table;
|
||||||
|
ElfNativeFileHeader m_file_header;
|
||||||
|
BAN::Vector<ElfNativeProgramHeader> m_program_headers;
|
||||||
|
size_t m_virtual_page_count = 0;
|
||||||
|
size_t m_physical_page_count = 0;
|
||||||
|
bool m_loaded { false };
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -80,16 +80,6 @@ namespace LibELF
|
||||||
Elf32Word p_align;
|
Elf32Word p_align;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Elf32Dynamic
|
|
||||||
{
|
|
||||||
Elf32Sword d_tag;
|
|
||||||
union
|
|
||||||
{
|
|
||||||
Elf32Word d_val;
|
|
||||||
Elf32Addr d_ptr;
|
|
||||||
} d_un;
|
|
||||||
};
|
|
||||||
|
|
||||||
using Elf64Addr = uint64_t;
|
using Elf64Addr = uint64_t;
|
||||||
using Elf64Off = uint64_t;
|
using Elf64Off = uint64_t;
|
||||||
using Elf64Half = uint16_t;
|
using Elf64Half = uint16_t;
|
||||||
|
@ -165,17 +155,7 @@ namespace LibELF
|
||||||
Elf64Xword p_align;
|
Elf64Xword p_align;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Elf64Dynamic
|
#if ARCH(i386)
|
||||||
{
|
|
||||||
Elf64Sxword d_tag;
|
|
||||||
union
|
|
||||||
{
|
|
||||||
Elf64Xword d_val;
|
|
||||||
Elf64Addr d_ptr;
|
|
||||||
} d_un;
|
|
||||||
};
|
|
||||||
|
|
||||||
#if ARCH(i686)
|
|
||||||
using ElfNativeAddr = Elf32Addr;
|
using ElfNativeAddr = Elf32Addr;
|
||||||
using ElfNativeOff = Elf32Off;
|
using ElfNativeOff = Elf32Off;
|
||||||
using ElfNativeHalf = Elf32Half;
|
using ElfNativeHalf = Elf32Half;
|
||||||
|
@ -187,7 +167,6 @@ namespace LibELF
|
||||||
using ElfNativeRelocation = Elf32Relocation;
|
using ElfNativeRelocation = Elf32Relocation;
|
||||||
using ElfNativeRelocationA = Elf32RelocationA;
|
using ElfNativeRelocationA = Elf32RelocationA;
|
||||||
using ElfNativeProgramHeader = Elf32ProgramHeader;
|
using ElfNativeProgramHeader = Elf32ProgramHeader;
|
||||||
using ElfNativeDynamic = Elf32Dynamic;
|
|
||||||
#elif ARCH(x86_64)
|
#elif ARCH(x86_64)
|
||||||
using ElfNativeAddr = Elf64Addr;
|
using ElfNativeAddr = Elf64Addr;
|
||||||
using ElfNativeOff = Elf64Off;
|
using ElfNativeOff = Elf64Off;
|
||||||
|
@ -202,7 +181,6 @@ namespace LibELF
|
||||||
using ElfNativeRelocation = Elf64Relocation;
|
using ElfNativeRelocation = Elf64Relocation;
|
||||||
using ElfNativeRelocationA = Elf64RelocationA;
|
using ElfNativeRelocationA = Elf64RelocationA;
|
||||||
using ElfNativeProgramHeader = Elf64ProgramHeader;
|
using ElfNativeProgramHeader = Elf64ProgramHeader;
|
||||||
using ElfNativeDynamic = Elf64Dynamic;
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
}
|
}
|
|
@ -0,0 +1,140 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace LibELF
|
||||||
|
{
|
||||||
|
|
||||||
|
enum ELF_Ident
|
||||||
|
{
|
||||||
|
ELFMAG0 = 0x7F,
|
||||||
|
ELFMAG1 = 'E',
|
||||||
|
ELFMAG2 = 'L',
|
||||||
|
ELFMAG3 = 'F',
|
||||||
|
|
||||||
|
ELFCLASSNONE = 0,
|
||||||
|
ELFCLASS32 = 1,
|
||||||
|
ELFCLASS64 = 2,
|
||||||
|
|
||||||
|
ELFDATANONE = 0,
|
||||||
|
ELFDATA2LSB = 1,
|
||||||
|
ELFDATA2MSB = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ELF_EI
|
||||||
|
{
|
||||||
|
EI_MAG0 = 0,
|
||||||
|
EI_MAG1 = 1,
|
||||||
|
EI_MAG2 = 2,
|
||||||
|
EI_MAG3 = 3,
|
||||||
|
EI_CLASS = 4,
|
||||||
|
EI_DATA = 5,
|
||||||
|
EI_VERSION = 6,
|
||||||
|
EI_OSABI = 7,
|
||||||
|
EI_ABIVERSION = 8,
|
||||||
|
EI_NIDENT = 16,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ELF_ET
|
||||||
|
{
|
||||||
|
ET_NONE = 0,
|
||||||
|
ET_REL = 1,
|
||||||
|
ET_EXEC = 2,
|
||||||
|
ET_DYN = 3,
|
||||||
|
ET_CORE = 4,
|
||||||
|
ET_LOOS = 0xfe00,
|
||||||
|
ET_HIOS = 0xfeff,
|
||||||
|
ET_LOPROC = 0xff00,
|
||||||
|
ET_HIPROC = 0xffff,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ELF_EV
|
||||||
|
{
|
||||||
|
EV_NONE = 0,
|
||||||
|
EV_CURRENT = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ELF_SHT
|
||||||
|
{
|
||||||
|
SHT_NULL = 0,
|
||||||
|
SHT_PROGBITS = 1,
|
||||||
|
SHT_SYMTAB = 2,
|
||||||
|
SHT_STRTAB = 3,
|
||||||
|
SHT_RELA = 4,
|
||||||
|
SHT_NOBITS = 8,
|
||||||
|
SHT_REL = 9,
|
||||||
|
SHT_SHLIB = 10,
|
||||||
|
SHT_DYNSYM = 11,
|
||||||
|
SHT_LOOS = 0x60000000,
|
||||||
|
SHT_HIOS = 0x6FFFFFFF,
|
||||||
|
SHT_LOPROC = 0x70000000,
|
||||||
|
SHT_HIPROC = 0x7FFFFFFF,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ELF_SHF
|
||||||
|
{
|
||||||
|
SHF_WRITE = 0x1,
|
||||||
|
SHF_ALLOC = 0x2,
|
||||||
|
SHF_EXECINSTR = 0x4,
|
||||||
|
SHF_MASKOS = 0x0F000000,
|
||||||
|
SHF_MASKPROC = 0xF0000000,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ELF_SHN
|
||||||
|
{
|
||||||
|
SHN_UNDEF = 0,
|
||||||
|
SHN_LOPROC = 0xFF00,
|
||||||
|
SHN_HIPROC = 0xFF1F,
|
||||||
|
SHN_LOOS = 0xFF20,
|
||||||
|
SHN_HIOS = 0xFF3F,
|
||||||
|
SHN_ABS = 0xFFF1,
|
||||||
|
SHN_COMMON = 0xFFF2,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ELF_STB
|
||||||
|
{
|
||||||
|
STB_LOCAL = 0,
|
||||||
|
STB_GLOBAL = 1,
|
||||||
|
STB_WEAK = 2,
|
||||||
|
STB_LOOS = 10,
|
||||||
|
STB_HIOS = 12,
|
||||||
|
STB_LOPROC = 13,
|
||||||
|
STB_HIPROC = 15,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ELF_STT
|
||||||
|
{
|
||||||
|
STT_NOTYPE = 0,
|
||||||
|
STT_OBJECT = 1,
|
||||||
|
STT_FUNC = 2,
|
||||||
|
STT_SECTION = 3,
|
||||||
|
STT_FILE = 4,
|
||||||
|
STT_LOOS = 10,
|
||||||
|
STT_HIOS = 12,
|
||||||
|
STT_LOPROC = 13,
|
||||||
|
STT_HIPROC = 15,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ELF_PT
|
||||||
|
{
|
||||||
|
PT_NULL = 0,
|
||||||
|
PT_LOAD = 1,
|
||||||
|
PT_DYNAMIC = 2,
|
||||||
|
PT_INTERP = 3,
|
||||||
|
PT_NOTE = 4,
|
||||||
|
PT_SHLIB = 5,
|
||||||
|
PT_PHDR = 6,
|
||||||
|
PT_LOOS = 0x60000000,
|
||||||
|
PT_HIOS = 0x6FFFFFFF,
|
||||||
|
PT_LOPROC = 0x70000000,
|
||||||
|
PT_HIPROC = 0x7FFFFFFF,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ELF_PF
|
||||||
|
{
|
||||||
|
PF_X = 0x1,
|
||||||
|
PF_W = 0x2,
|
||||||
|
PF_R = 0x4,
|
||||||
|
PF_MASKOS = 0x00FF0000,
|
||||||
|
PF_MASKPROC = 0xFF000000,
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
117
README.md
117
README.md
|
@ -1,73 +1,8 @@
|
||||||
[![](https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fbananymous.com%2Fbanan-os%2Ftokei.json&query=%24.lines&label=total%20lines)](https://git.bananymous.com/Bananymous/banan-os)
|
![license](https://img.shields.io/github/license/bananymous/banan-os)
|
||||||
[![](https://img.shields.io/github/commit-activity/m/Bananymous/banan-os)](https://git.bananymous.com/Bananymous/banan-os)
|
|
||||||
[![](https://img.shields.io/github/license/bananymous/banan-os)](https://git.bananymous.com/Bananymous/banan-os/src/branch/main/LICENSE)
|
|
||||||
[![](https://img.shields.io/discord/1242165176032297040?logo=discord&label=discord)](https://discord.gg/ehjGySwYdK)
|
|
||||||
|
|
||||||
# banan-os
|
# banan-os
|
||||||
|
|
||||||
This is my hobby operating system written in C++. Currently supports x86\_64 and i686 architectures.
|
This is my hobby operating system written in C++. Currently supports only x86\_64 architecture. We have a ext2 filesystem, basic ramfs, IDE disk drivers in ATA PIO mode, ATA AHCI drivers, userspace processes, executable loading from ELF format, linear VBE graphics and multithreaded processing on single core.
|
||||||
|
|
||||||
You can find a live demo [here](https://bananymous.com/banan-os)
|
|
||||||
|
|
||||||
If you want to try out DOOM, you should first enter the GUI environment using the `start-gui` command. Then you can run `doom` in the GUI terminal.
|
|
||||||
|
|
||||||
### Features
|
|
||||||
|
|
||||||
#### General
|
|
||||||
- [x] Ring3 userspace
|
|
||||||
- [x] SMP (multiprocessing)
|
|
||||||
- [x] Linear framebuffer (VESA and GOP)
|
|
||||||
- [x] Network stack
|
|
||||||
- [x] ELF executable loading
|
|
||||||
- [x] AML interpreter (partial)
|
|
||||||
- [x] Basic graphical environment
|
|
||||||
- [x] Terminal emulator
|
|
||||||
- [x] Status bar
|
|
||||||
- [ ] Program launcher
|
|
||||||
- [ ] Some nice apps
|
|
||||||
- [x] ELF dynamic linking
|
|
||||||
- [x] copy-on-write memory
|
|
||||||
- [x] file mappings
|
|
||||||
- [ ] anonymous mappings
|
|
||||||
|
|
||||||
#### Drivers
|
|
||||||
- [x] NVMe disks
|
|
||||||
- [x] ATA (IDE, SATA) disks
|
|
||||||
- [x] E1000 and E1000E NICs
|
|
||||||
- [x] RTL8111/8168/8211/8411 NICs
|
|
||||||
- [x] PS2 keyboard (all scancode sets)
|
|
||||||
- [x] PS2 mouse
|
|
||||||
- [x] USB
|
|
||||||
- [x] Keyboard
|
|
||||||
- [x] Mouse
|
|
||||||
- [x] Mass storage
|
|
||||||
- [ ] Hubs
|
|
||||||
- [ ] ...
|
|
||||||
- [ ] virtio devices (network, storage)
|
|
||||||
|
|
||||||
#### Network
|
|
||||||
- [x] ARP
|
|
||||||
- [x] ICMP
|
|
||||||
- [x] IPv4
|
|
||||||
- [x] UDP
|
|
||||||
- [x] TCP (partial and buggy)
|
|
||||||
- [x] Unix domain sockets
|
|
||||||
- [ ] SSL
|
|
||||||
|
|
||||||
#### Filesystems
|
|
||||||
- [x] Virtual filesystem
|
|
||||||
- [x] Ext2
|
|
||||||
- [x] FAT12/16/32
|
|
||||||
- [x] Dev
|
|
||||||
- [x] Ram
|
|
||||||
- [x] Proc
|
|
||||||
- [ ] Sys
|
|
||||||
- [ ] 9P
|
|
||||||
|
|
||||||
#### Bootloader support
|
|
||||||
- [x] GRUB
|
|
||||||
- [x] Custom BIOS bootloader
|
|
||||||
- [ ] Custom UEFI bootloader
|
|
||||||
|
|
||||||
![screenshot from qemu running banan-os](assets/banan-os.png)
|
![screenshot from qemu running banan-os](assets/banan-os.png)
|
||||||
|
|
||||||
|
@ -77,59 +12,37 @@ Each major component and library has its own subdirectory (kernel, userspace, li
|
||||||
|
|
||||||
## Building
|
## Building
|
||||||
|
|
||||||
### Needed packages
|
There does not exist a complete list of needed packages for building. From the top of my head I can say that *cmake*, *ninja*, *make*, *grub*, *rsync* and emulator (*qemu* or *bochs*) are needed.
|
||||||
|
|
||||||
#### apt (tested on ubuntu 22.04)
|
|
||||||
```# apt install build-essential git ninja-build texinfo bison flex libgmp-dev libmpfr-dev libmpc-dev parted qemu-system-x86 cpu-checker```
|
|
||||||
|
|
||||||
#### pacman
|
|
||||||
```# pacman -S --needed base-devel git wget cmake ninja parted qemu-system-x86```
|
|
||||||
|
|
||||||
|
|
||||||
### Compilation
|
|
||||||
|
|
||||||
To build the toolchain for this os. You can run the following command.
|
To build the toolchain for this os. You can run the following command.
|
||||||
> ***NOTE:*** The following step has to be done only once. This might take a long time since we are compiling binutils and gcc.
|
> ***NOTE:*** The following step has to be done only once. This might take a long time since we are compiling binutils and gcc.
|
||||||
```sh
|
```sh
|
||||||
./bos toolchain
|
./script/build.sh toolchain
|
||||||
```
|
```
|
||||||
|
|
||||||
To build the os itself you can run one of the following commands. You will need root access for disk image creation/modification.
|
To build the os itself you can run one of the following commands. You will need root access for disk image creation/modification.
|
||||||
```sh
|
```sh
|
||||||
./bos qemu
|
./script/build.sh qemu
|
||||||
./bos qemu-nographic
|
./script/build.sh qemu-nographic
|
||||||
./bos qemu-debug
|
./script/build.sh qemu-debug
|
||||||
./bos bochs
|
./script/build.sh bochs
|
||||||
```
|
```
|
||||||
|
|
||||||
You can also build the kernel or disk image without running it:
|
You can also build the kernel or disk image without running it:
|
||||||
```sh
|
```sh
|
||||||
./bos kernel
|
./script/build.sh kernel
|
||||||
./bos image
|
./script/build.sh image
|
||||||
```
|
```
|
||||||
|
|
||||||
To build for other architectures set environment variable BANAN\_ARCH=*arch* (e.g. BANAN\_ARCH=i686).
|
|
||||||
|
|
||||||
To change the bootloader you can set environment variable BANAN\_BOOTLOADER; supported values are BANAN (my custom bootloader) and GRUB.
|
|
||||||
|
|
||||||
To run with UEFI set environment variable BANAN\_UEFI\_BOOT=1. You will also have to set OVMF\_PATH to the correct OVMF (default */usr/share/ovmf/x64/OVMF.fd*).
|
|
||||||
|
|
||||||
If you have corrupted your disk image or want to create new one, you can either manually delete *build/banan-os.img* and build system will automatically create you a new one or you can run the following command.
|
If you have corrupted your disk image or want to create new one, you can either manually delete *build/banan-os.img* and build system will automatically create you a new one or you can run the following command.
|
||||||
```sh
|
```sh
|
||||||
./bos image-full
|
./script/build.sh image-full
|
||||||
```
|
```
|
||||||
|
|
||||||
|
If you feel like ```./script/build.sh``` is too verbose, there exists a symlink _bos_ in this projects root directory. All build commands can be used with ```./bos args...``` instead.
|
||||||
|
|
||||||
I have also created shell completion script for zsh. You can either copy the file in _script/shell-completion/zsh/\_bos_ to _/usr/share/zsh/site-functions/_ or add the _script/shell-completion/zsh_ to your fpath in _.zshrc_.
|
I have also created shell completion script for zsh. You can either copy the file in _script/shell-completion/zsh/\_bos_ to _/usr/share/zsh/site-functions/_ or add the _script/shell-completion/zsh_ to your fpath in _.zshrc_.
|
||||||
|
|
||||||
## Contributing
|
### Contributing
|
||||||
|
|
||||||
As the upstream is hosted on my server https://git.bananymous.com/Bananymous/banan-os, merging contributions is not as trivial as it would be on GitHub. You can still send PRs in GitHub in which case I should be able to download the diff and apply it manually. If you want, I can also provide you an account to my git server. In this case please contact me ([email](mailto:oskari.alaranta@bananymous.com), [discord](https://discord.gg/ehjGySwYdK)).
|
Currently I don't accept contributions to this repository unless explicitly told otherwise. This is a learning project for me and I want to do everything myself. Feel free to fork/clone this repo and tinker with it yourself.
|
||||||
|
|
||||||
As this is mostly a learning experience for me, I would appreciate if you first contacted me about adding new features (email, discord, issue, ...). If you send a PR about something I was planning on doing myself and you didn't ask me, I will probably just close it. Bug fixes are always welcome!
|
|
||||||
|
|
||||||
Commit message should be formatted followingly
|
|
||||||
|
|
||||||
1. First line is of the form "_Subject: Description_", where _Subject_ tells the area touched (Kernel, Shell, BuildSystem, ...) and _Description_ is brief description of the change done. First line should fit fully in 72 characters.
|
|
||||||
2. Body of the message should further describe the change and reasoning behind the change.
|
|
||||||
|
|
||||||
All commits should pass the pre-commit hook defined in _.pre-commit-config.yaml_. For instructions on how to setup pre-commit, please see https://pre-commit.com/#install.
|
|
||||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 384 KiB After Width: | Height: | Size: 11 KiB |
Binary file not shown.
|
@ -3,7 +3,6 @@ cmake_minimum_required(VERSION 3.26)
|
||||||
project(bootloader ASM)
|
project(bootloader ASM)
|
||||||
|
|
||||||
set(BOOTLOADER_SOURCES
|
set(BOOTLOADER_SOURCES
|
||||||
a20_line.S
|
|
||||||
boot.S
|
boot.S
|
||||||
command_line.S
|
command_line.S
|
||||||
disk.S
|
disk.S
|
||||||
|
@ -15,6 +14,5 @@ set(BOOTLOADER_SOURCES
|
||||||
)
|
)
|
||||||
|
|
||||||
add_executable(bootloader ${BOOTLOADER_SOURCES})
|
add_executable(bootloader ${BOOTLOADER_SOURCES})
|
||||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
|
|
||||||
target_link_options(bootloader PRIVATE LINKER:-T,${CMAKE_CURRENT_SOURCE_DIR}/linker.ld)
|
target_link_options(bootloader PRIVATE LINKER:-T,${CMAKE_CURRENT_SOURCE_DIR}/linker.ld)
|
||||||
target_link_options(bootloader PRIVATE -nostdlib)
|
target_link_options(bootloader PRIVATE -nostdlib)
|
||||||
|
|
|
@ -1,168 +0,0 @@
|
||||||
.code16
|
|
||||||
.section .stage2
|
|
||||||
|
|
||||||
# checks whether A20 line is enabled or disabled
|
|
||||||
# return
|
|
||||||
# ax: 1 if enabled, 0 otherwise
|
|
||||||
check_a20:
|
|
||||||
pushf
|
|
||||||
pushw %si
|
|
||||||
pushw %di
|
|
||||||
pushw %ds
|
|
||||||
pushw %es
|
|
||||||
|
|
||||||
cli
|
|
||||||
|
|
||||||
xorw %ax, %ax
|
|
||||||
movw %ax, %es
|
|
||||||
notw %ax
|
|
||||||
movw %ax, %ds
|
|
||||||
|
|
||||||
movw $0x0500, %di
|
|
||||||
movw $0x0510, %si
|
|
||||||
|
|
||||||
movb %es:(%di), %al
|
|
||||||
pushw %ax
|
|
||||||
|
|
||||||
movb %ds:(%si), %al
|
|
||||||
pushw %ax
|
|
||||||
|
|
||||||
movb $0x00, %es:(%di)
|
|
||||||
movb $0xFF, %ds:(%si)
|
|
||||||
|
|
||||||
cmpb $0xFF, %es:(%di)
|
|
||||||
|
|
||||||
pop %ax
|
|
||||||
movb %al, %ds:(%si)
|
|
||||||
|
|
||||||
pop %ax
|
|
||||||
movb %al, %es:(%di)
|
|
||||||
|
|
||||||
movw $0, %ax
|
|
||||||
je .check_a20_done
|
|
||||||
|
|
||||||
movw $1, %ax
|
|
||||||
|
|
||||||
.check_a20_done:
|
|
||||||
popw %es
|
|
||||||
popw %ds
|
|
||||||
popw %di
|
|
||||||
popw %si
|
|
||||||
popf
|
|
||||||
ret
|
|
||||||
|
|
||||||
|
|
||||||
# Try to enable A20 using PS2 controller
|
|
||||||
enable_a20_ps2:
|
|
||||||
pushf
|
|
||||||
pushw %ax
|
|
||||||
|
|
||||||
cli
|
|
||||||
|
|
||||||
# disable first port
|
|
||||||
call .enable_a20_ps2_wait1
|
|
||||||
movb $0xAD, %al
|
|
||||||
outb %al, $0x64
|
|
||||||
|
|
||||||
# read controller output
|
|
||||||
call .enable_a20_ps2_wait1
|
|
||||||
movb $0xD0, %al
|
|
||||||
outb %al, $0x64
|
|
||||||
|
|
||||||
call .enable_a20_ps2_wait2
|
|
||||||
inb $0x60, %al
|
|
||||||
pushw %ax
|
|
||||||
|
|
||||||
# write controller output
|
|
||||||
call .enable_a20_ps2_wait1
|
|
||||||
movb $0xD1, %al
|
|
||||||
outb %al, $0x64
|
|
||||||
|
|
||||||
call .enable_a20_ps2_wait1
|
|
||||||
popw %ax
|
|
||||||
orw $2, %ax
|
|
||||||
outb %al, $0x60
|
|
||||||
|
|
||||||
# enable first port
|
|
||||||
call .enable_a20_ps2_wait1
|
|
||||||
movb $0xAE, %al
|
|
||||||
outb %al, $0x64
|
|
||||||
|
|
||||||
call .enable_a20_ps2_wait1
|
|
||||||
|
|
||||||
popw %ax
|
|
||||||
popf
|
|
||||||
ret
|
|
||||||
|
|
||||||
.enable_a20_ps2_wait1:
|
|
||||||
inb $0x64, %al
|
|
||||||
test $2, %al
|
|
||||||
jnz .enable_a20_ps2_wait1
|
|
||||||
ret
|
|
||||||
|
|
||||||
.enable_a20_ps2_wait2:
|
|
||||||
inb $0x64, %al
|
|
||||||
test $1, %al
|
|
||||||
jnz .enable_a20_ps2_wait1
|
|
||||||
ret
|
|
||||||
|
|
||||||
|
|
||||||
# Check if A20 line is disabled. If it is, try to enable it
|
|
||||||
.global enable_a20
|
|
||||||
enable_a20:
|
|
||||||
pushw %ax
|
|
||||||
pushw %si
|
|
||||||
|
|
||||||
call check_a20
|
|
||||||
testw %ax, %ax
|
|
||||||
jnz .enable_a20_done
|
|
||||||
|
|
||||||
movw $a20_line_disabled_msg, %si
|
|
||||||
call puts; call print_newline
|
|
||||||
|
|
||||||
# Try to enable A20 line using bios interrupt
|
|
||||||
movw $0x2401, %ax
|
|
||||||
int $0x15
|
|
||||||
call check_a20
|
|
||||||
testw %ax, %ax
|
|
||||||
jnz .enable_a20_done
|
|
||||||
|
|
||||||
# Try to enable A20 line using ps2 controller
|
|
||||||
call enable_a20_ps2
|
|
||||||
call check_a20
|
|
||||||
testw %ax, %ax
|
|
||||||
jnz .enable_a20_done
|
|
||||||
|
|
||||||
# Try to enable A20 line using fast A20 gate
|
|
||||||
inb $0x92, %al
|
|
||||||
testb $2, %al
|
|
||||||
jnz .enable_a20_fast_done
|
|
||||||
orb $2, %al
|
|
||||||
outb %al, $0x92
|
|
||||||
.enable_a20_fast_done:
|
|
||||||
|
|
||||||
call check_a20
|
|
||||||
testw %ax, %ax
|
|
||||||
jnz .enable_a20_done
|
|
||||||
|
|
||||||
movw $a20_could_not_enable_msg, %si
|
|
||||||
call print_and_halt
|
|
||||||
|
|
||||||
.enable_a20_done:
|
|
||||||
movw $a20_line_enabled_msg, %si
|
|
||||||
call puts; call print_newline
|
|
||||||
|
|
||||||
popw %si
|
|
||||||
popw %ax
|
|
||||||
ret
|
|
||||||
|
|
||||||
.section .data
|
|
||||||
|
|
||||||
a20_line_disabled_msg:
|
|
||||||
.asciz "A20 line disabled. Trying to enable it"
|
|
||||||
|
|
||||||
a20_line_enabled_msg:
|
|
||||||
.asciz "A20 line enabled"
|
|
||||||
|
|
||||||
a20_could_not_enable_msg:
|
|
||||||
.asciz "Could not enable A20 line"
|
|
|
@ -1,5 +1,3 @@
|
||||||
.include "common.S"
|
|
||||||
|
|
||||||
.code16
|
.code16
|
||||||
|
|
||||||
#########################################
|
#########################################
|
||||||
|
@ -15,10 +13,12 @@
|
||||||
|
|
||||||
.global stage1_main
|
.global stage1_main
|
||||||
stage1_main:
|
stage1_main:
|
||||||
# setup segments and stack
|
# setup segments
|
||||||
xorw %ax, %ax
|
movw $0, %ax
|
||||||
movw %ax, %ds
|
movw %ax, %ds
|
||||||
movw %ax, %es
|
movw %ax, %es
|
||||||
|
|
||||||
|
# setup stack
|
||||||
movw %ax, %ss
|
movw %ax, %ss
|
||||||
movl $0x7C00, %esp
|
movl $0x7C00, %esp
|
||||||
|
|
||||||
|
@ -53,18 +53,14 @@ stage2_main:
|
||||||
movw $hello_msg, %si
|
movw $hello_msg, %si
|
||||||
call puts; call print_newline
|
call puts; call print_newline
|
||||||
|
|
||||||
lgdt gdtr
|
|
||||||
|
|
||||||
call enter_unreal_mode
|
call enter_unreal_mode
|
||||||
movw $unreal_enter_msg, %si
|
movw $unreal_enter_msg, %si
|
||||||
call puts; call print_newline
|
call puts; call print_newline
|
||||||
|
|
||||||
call enable_a20
|
|
||||||
|
|
||||||
call get_memory_map
|
call get_memory_map
|
||||||
|
|
||||||
call print_newline
|
|
||||||
call read_user_command_line
|
call read_user_command_line
|
||||||
|
|
||||||
|
call vesa_find_video_mode
|
||||||
|
|
||||||
call print_newline
|
call print_newline
|
||||||
|
|
||||||
|
@ -88,36 +84,36 @@ stage2_main:
|
||||||
|
|
||||||
call elf_read_kernel_to_memory
|
call elf_read_kernel_to_memory
|
||||||
|
|
||||||
call vesa_set_video_mode
|
call vesa_set_target_mode
|
||||||
|
|
||||||
cli
|
cli
|
||||||
|
|
||||||
# kernel entry point
|
|
||||||
movl %eax, %ecx
|
|
||||||
|
|
||||||
# setup kernel parameters
|
|
||||||
movl $0xD3C60CFF, %eax
|
|
||||||
movl $banan_boot_info, %ebx
|
|
||||||
|
|
||||||
# setup protected mode
|
# setup protected mode
|
||||||
movl %cr0, %edx
|
movl %cr0, %ebx
|
||||||
orb $1, %dl
|
orb $1, %bl
|
||||||
movl %edx, %cr0
|
movl %ebx, %cr0
|
||||||
|
|
||||||
|
# jump to kernel in protected mode
|
||||||
|
ljmpl $0x18, $protected_mode
|
||||||
|
|
||||||
# jump to protected mode
|
|
||||||
ljmpl $GDT_CODE32, $protected_mode
|
|
||||||
|
|
||||||
.code32
|
.code32
|
||||||
protected_mode:
|
protected_mode:
|
||||||
# setup protected mode segments
|
movw $0x10, %bx
|
||||||
movw $GDT_DATA32, %dx
|
movw %bx, %ds
|
||||||
movw %dx, %ds
|
movw %bx, %es
|
||||||
movw %dx, %es
|
movw %bx, %fs
|
||||||
movw %dx, %fs
|
movw %bx, %gs
|
||||||
movw %dx, %gs
|
movw %bx, %ss
|
||||||
movw %dx, %ss
|
|
||||||
|
movl %eax, %ecx
|
||||||
|
|
||||||
|
movl $0xD3C60CFF, %eax
|
||||||
|
movl $banan_boot_info, %ebx
|
||||||
|
xorl %edx, %edx
|
||||||
|
xorl %esi, %esi
|
||||||
|
xorl %edi, %edi
|
||||||
|
|
||||||
# jump to kernel entry
|
|
||||||
jmp *%ecx
|
jmp *%ecx
|
||||||
|
|
||||||
|
|
||||||
|
@ -126,18 +122,20 @@ enter_unreal_mode:
|
||||||
cli
|
cli
|
||||||
pushw %ds
|
pushw %ds
|
||||||
|
|
||||||
|
lgdt gdtr
|
||||||
|
|
||||||
movl %cr0, %eax
|
movl %cr0, %eax
|
||||||
orb $1, %al
|
orb $1, %al
|
||||||
movl %eax, %cr0
|
movl %eax, %cr0
|
||||||
ljmpl $GDT_CODE16, $.enter_unreal_mode_pmode
|
ljmpl $0x8, $.enter_unreal_mode_pmode
|
||||||
|
|
||||||
.enter_unreal_mode_pmode:
|
.enter_unreal_mode_pmode:
|
||||||
movw $GDT_DATA32, %bx
|
movw $0x10, %bx
|
||||||
movw %bx, %ds
|
movw %bx, %ds
|
||||||
|
|
||||||
andb $0xFE, %al
|
andb 0xFE, %al
|
||||||
movl %eax, %cr0
|
movl %eax, %cr0
|
||||||
ljmpl $0x00, $.enter_unreal_mode_unreal
|
ljmpl $0x0, $.enter_unreal_mode_unreal
|
||||||
|
|
||||||
.enter_unreal_mode_unreal:
|
.enter_unreal_mode_unreal:
|
||||||
popw %ds
|
popw %ds
|
||||||
|
@ -145,8 +143,6 @@ enter_unreal_mode:
|
||||||
|
|
||||||
ret
|
ret
|
||||||
|
|
||||||
.section .data
|
|
||||||
|
|
||||||
hello_msg:
|
hello_msg:
|
||||||
.asciz "This is banan-os bootloader"
|
.asciz "This is banan-os bootloader"
|
||||||
|
|
||||||
|
@ -158,12 +154,12 @@ start_kernel_load_msg:
|
||||||
|
|
||||||
gdt:
|
gdt:
|
||||||
.quad 0x0000000000000000
|
.quad 0x0000000000000000
|
||||||
.quad 0x008F9A000000FFFF # 16-bit code
|
.quad 0x00009A000000FFFF
|
||||||
.quad 0x00CF92000000FFFF # 32-bit data
|
.quad 0x00CF92000000FFFF
|
||||||
.quad 0x00CF9A000000FFFF # 32-bit code
|
.quad 0x00CF9A000000FFFF
|
||||||
gdtr:
|
gdtr:
|
||||||
.short . - gdt - 1
|
.short . - gdt - 1
|
||||||
.long gdt
|
.quad gdt
|
||||||
|
|
||||||
banan_boot_info:
|
banan_boot_info:
|
||||||
boot_command_line:
|
boot_command_line:
|
||||||
|
@ -172,5 +168,3 @@ banan_boot_info:
|
||||||
.long framebuffer
|
.long framebuffer
|
||||||
boot_memory_map:
|
boot_memory_map:
|
||||||
.long memory_map
|
.long memory_map
|
||||||
boot_kernel_paddr:
|
|
||||||
.long 0
|
|
||||||
|
|
|
@ -26,8 +26,6 @@ read_user_command_line:
|
||||||
|
|
||||||
cmpb $'\b', %al
|
cmpb $'\b', %al
|
||||||
je .read_user_command_line_backspace
|
je .read_user_command_line_backspace
|
||||||
cmpb $0x7F, %al
|
|
||||||
je .read_user_command_line_backspace
|
|
||||||
|
|
||||||
# Not sure if some BIOSes return '\n' as enter, but check it just in case
|
# Not sure if some BIOSes return '\n' as enter, but check it just in case
|
||||||
cmpb $'\r', %al
|
cmpb $'\r', %al
|
||||||
|
@ -74,8 +72,6 @@ read_user_command_line:
|
||||||
ret
|
ret
|
||||||
|
|
||||||
|
|
||||||
.section .data
|
|
||||||
|
|
||||||
command_line_enter_msg:
|
command_line_enter_msg:
|
||||||
.asciz "cmdline: "
|
.asciz "cmdline: "
|
||||||
|
|
||||||
|
@ -84,4 +80,4 @@ command_line:
|
||||||
# 100 character command line
|
# 100 character command line
|
||||||
command_line_buffer:
|
command_line_buffer:
|
||||||
.ascii "root=/dev/sda2"
|
.ascii "root=/dev/sda2"
|
||||||
.skip 100 - (. - command_line_buffer)
|
.skip 100 - 28
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
.set GDT_CODE16, 0x08
|
|
||||||
.set GDT_DATA32, 0x10
|
|
||||||
.set GDT_CODE32, 0x18
|
|
|
@ -41,7 +41,7 @@ read_from_disk:
|
||||||
call drive_has_int13_ext
|
call drive_has_int13_ext
|
||||||
|
|
||||||
# prepare disk read packet
|
# prepare disk read packet
|
||||||
movw $disk_address_packet, %si
|
mov $disk_address_packet, %si
|
||||||
movb $0x10, 0x00(%si) # packet size
|
movb $0x10, 0x00(%si) # packet size
|
||||||
movb $0x00, 0x01(%si) # always 0
|
movb $0x00, 0x01(%si) # always 0
|
||||||
movw %cx, 0x02(%si) # lba count
|
movw %cx, 0x02(%si) # lba count
|
||||||
|
@ -389,8 +389,10 @@ find_root_partition:
|
||||||
|
|
||||||
# increment 8 byte entry array lba
|
# increment 8 byte entry array lba
|
||||||
incl 0(%esp)
|
incl 0(%esp)
|
||||||
adcl $0, 4(%esp)
|
jnc .find_root_partition_no_overflow
|
||||||
|
incl 4(%esp)
|
||||||
|
|
||||||
|
.find_root_partition_no_overflow:
|
||||||
# loop to read next section if entries remaining
|
# loop to read next section if entries remaining
|
||||||
cmpl $0, 12(%esp)
|
cmpl $0, 12(%esp)
|
||||||
jnz .find_root_partition_read_entry_section
|
jnz .find_root_partition_read_entry_section
|
||||||
|
@ -414,11 +416,13 @@ find_root_partition:
|
||||||
|
|
||||||
# ebx:eax -= first lba - 1
|
# ebx:eax -= first lba - 1
|
||||||
subl (root_partition_entry + 36), %ebx
|
subl (root_partition_entry + 36), %ebx
|
||||||
movl (root_partition_entry + 32), %ecx
|
movl (root_partition_entry + 32), %ecx;
|
||||||
decl %ecx
|
decl %ecx
|
||||||
subl %ecx, %eax
|
subl %ecx, %eax
|
||||||
sbbl $0, %ebx
|
jnc .find_root_partition_count_sub_no_carry
|
||||||
|
decl %ebx
|
||||||
|
.find_root_partition_count_sub_no_carry:
|
||||||
|
|
||||||
# ecx: min(partition count, 0xFFFFFFFF)
|
# ecx: min(partition count, 0xFFFFFFFF)
|
||||||
movl $0xFFFFFFFF, %edx
|
movl $0xFFFFFFFF, %edx
|
||||||
movl %eax, %ecx
|
movl %eax, %ecx
|
||||||
|
@ -470,7 +474,6 @@ print_root_partition_info:
|
||||||
popw %ax
|
popw %ax
|
||||||
ret
|
ret
|
||||||
|
|
||||||
.section .data
|
|
||||||
|
|
||||||
# These will be patched during bootloader installation
|
# These will be patched during bootloader installation
|
||||||
root_disk_guid:
|
root_disk_guid:
|
||||||
|
|
|
@ -5,26 +5,15 @@
|
||||||
.set e_machine, 18
|
.set e_machine, 18
|
||||||
.set e_version, 20
|
.set e_version, 20
|
||||||
.set e_entry, 24
|
.set e_entry, 24
|
||||||
|
.set e_phoff, 32
|
||||||
.set e32_phoff, 28
|
.set e_shoff, 40
|
||||||
.set e32_shoff, 32
|
.set e_flags, 48
|
||||||
.set e32_flags, 36
|
.set e_ehsize, 52
|
||||||
.set e32_ehsize, 40
|
.set e_phentsize, 54
|
||||||
.set e32_phentsize, 42
|
.set e_phnum, 56
|
||||||
.set e32_phnum, 44
|
.set e_shentsize, 58
|
||||||
.set e32_shentsize, 46
|
.set e_shnum, 60
|
||||||
.set e32_shnum, 48
|
.set e_shstrndx, 62
|
||||||
.set e32_shstrndx, 50
|
|
||||||
|
|
||||||
.set e64_phoff, 32
|
|
||||||
.set e64_shoff, 40
|
|
||||||
.set e64_flags, 48
|
|
||||||
.set e64_ehsize, 52
|
|
||||||
.set e64_phentsize, 54
|
|
||||||
.set e64_phnum, 56
|
|
||||||
.set e64_shentsize, 58
|
|
||||||
.set e64_shnum, 60
|
|
||||||
.set e64_shstrndx, 62
|
|
||||||
|
|
||||||
# e_ident offsets
|
# e_ident offsets
|
||||||
.set EI_CLASS, 4
|
.set EI_CLASS, 4
|
||||||
|
@ -33,7 +22,6 @@
|
||||||
|
|
||||||
# e_ident constants
|
# e_ident constants
|
||||||
.set ELFMAGIC, 0x464C457F
|
.set ELFMAGIC, 0x464C457F
|
||||||
.set ELFCLASS32, 1
|
|
||||||
.set ELFCLASS64, 2
|
.set ELFCLASS64, 2
|
||||||
.set ELFDATA2LSB, 1
|
.set ELFDATA2LSB, 1
|
||||||
.set EV_CURRENT, 1
|
.set EV_CURRENT, 1
|
||||||
|
@ -43,30 +31,18 @@
|
||||||
|
|
||||||
# program header field offsets
|
# program header field offsets
|
||||||
.set p_type, 0
|
.set p_type, 0
|
||||||
|
.set p_flags, 4
|
||||||
.set p32_offset, 4
|
.set p_offset, 8
|
||||||
.set p32_vaddr, 8
|
.set p_vaddr, 16
|
||||||
.set p32_paddr, 12
|
.set p_paddr, 24
|
||||||
.set p32_filesz, 16
|
.set p_filesz, 32
|
||||||
.set p32_memsz, 20
|
.set p_memsz, 40
|
||||||
.set p32_flags, 24
|
.set p_align, 48
|
||||||
.set p32_align, 28
|
|
||||||
|
|
||||||
.set p64_flags, 4
|
|
||||||
.set p64_offset, 8
|
|
||||||
.set p64_vaddr, 16
|
|
||||||
.set p64_paddr, 24
|
|
||||||
.set p64_filesz, 32
|
|
||||||
.set p64_memsz, 40
|
|
||||||
.set p64_align, 48
|
|
||||||
|
|
||||||
# p_type constants
|
# p_type constants
|
||||||
.set PT_NULL, 0
|
.set PT_NULL, 0
|
||||||
.set PT_LOAD, 1
|
.set PT_LOAD, 1
|
||||||
|
|
||||||
# mask for entry point and segment loading
|
|
||||||
.set LOAD_MASK, 0x07FFFFFF
|
|
||||||
|
|
||||||
.code16
|
.code16
|
||||||
.section .stage2
|
.section .stage2
|
||||||
|
|
||||||
|
@ -76,12 +52,8 @@ elf_validate_file_header:
|
||||||
cmpl $ELFMAGIC, (elf_file_header)
|
cmpl $ELFMAGIC, (elf_file_header)
|
||||||
jne .elf_validate_file_header_invalid_magic
|
jne .elf_validate_file_header_invalid_magic
|
||||||
|
|
||||||
cmpb $ELFCLASS32, (elf_file_header + EI_CLASS)
|
|
||||||
je .elf_validate_file_header_class_valid
|
|
||||||
cmpb $ELFCLASS64, (elf_file_header + EI_CLASS)
|
cmpb $ELFCLASS64, (elf_file_header + EI_CLASS)
|
||||||
je .elf_validate_file_header_class_valid
|
jne .elf_validate_file_header_only_64bit_supported
|
||||||
jmp .elf_validate_file_header_invalid_class
|
|
||||||
.elf_validate_file_header_class_valid:
|
|
||||||
|
|
||||||
cmpb $ELFDATA2LSB, (elf_file_header + EI_DATA)
|
cmpb $ELFDATA2LSB, (elf_file_header + EI_DATA)
|
||||||
jne .elf_validate_file_header_only_little_endian_supported
|
jne .elf_validate_file_header_only_little_endian_supported
|
||||||
|
@ -100,8 +72,8 @@ elf_validate_file_header:
|
||||||
.elf_validate_file_header_invalid_magic:
|
.elf_validate_file_header_invalid_magic:
|
||||||
movw $elf_validate_file_header_invalid_magic_msg, %si
|
movw $elf_validate_file_header_invalid_magic_msg, %si
|
||||||
jmp print_and_halt
|
jmp print_and_halt
|
||||||
.elf_validate_file_header_invalid_class:
|
.elf_validate_file_header_only_64bit_supported:
|
||||||
movw $elf_validate_file_header_invalid_class_msg, %si
|
movw $elf_validate_file_header_only_64bit_supported_msg, %si
|
||||||
jmp print_and_halt
|
jmp print_and_halt
|
||||||
.elf_validate_file_header_only_little_endian_supported:
|
.elf_validate_file_header_only_little_endian_supported:
|
||||||
movw $elf_validate_file_header_only_little_endian_supported_msg, %si
|
movw $elf_validate_file_header_only_little_endian_supported_msg, %si
|
||||||
|
@ -113,59 +85,6 @@ elf_validate_file_header:
|
||||||
movw $elf_validate_file_header_not_executable_msg, %si
|
movw $elf_validate_file_header_not_executable_msg, %si
|
||||||
jmp print_and_halt
|
jmp print_and_halt
|
||||||
|
|
||||||
# reads memory specified by 32 bit elf_program_header to memory
|
|
||||||
elf_read_program_header32_to_memory:
|
|
||||||
pushal
|
|
||||||
pushl %ebp
|
|
||||||
movl %esp, %ebp
|
|
||||||
|
|
||||||
# memset p_filesz -> p_memsz to 0
|
|
||||||
movl (elf_program_header + p32_filesz), %ebx
|
|
||||||
movl (elf_program_header + p32_vaddr), %edi
|
|
||||||
andl $LOAD_MASK, %edi
|
|
||||||
addl %ebx, %edi
|
|
||||||
movl (elf_program_header + p32_memsz), %ecx
|
|
||||||
subl %ebx, %ecx
|
|
||||||
xorb %al, %al; call memset32
|
|
||||||
|
|
||||||
# read file specified in program header to memory
|
|
||||||
movl (elf_program_header + p32_offset), %eax
|
|
||||||
movl (elf_program_header + p32_vaddr), %edi
|
|
||||||
andl $LOAD_MASK, %edi
|
|
||||||
movl (elf_program_header + p32_filesz), %ecx
|
|
||||||
call *%esi
|
|
||||||
|
|
||||||
leavel
|
|
||||||
popal
|
|
||||||
ret
|
|
||||||
|
|
||||||
|
|
||||||
# reads memory specified by 64 bit elf_program_header to memory
|
|
||||||
elf_read_program_header64_to_memory:
|
|
||||||
pushal
|
|
||||||
pushl %ebp
|
|
||||||
movl %esp, %ebp
|
|
||||||
|
|
||||||
# memset p_filesz -> p_memsz to 0
|
|
||||||
movl (elf_program_header + p64_filesz), %ebx
|
|
||||||
movl (elf_program_header + p64_vaddr), %edi
|
|
||||||
andl $LOAD_MASK, %edi
|
|
||||||
addl %ebx, %edi
|
|
||||||
movl (elf_program_header + p64_memsz), %ecx
|
|
||||||
subl %ebx, %ecx
|
|
||||||
xorb %al, %al; call memset32
|
|
||||||
|
|
||||||
# read file specified in program header to memory
|
|
||||||
movl (elf_program_header + p64_offset), %eax
|
|
||||||
movl (elf_program_header + p64_vaddr), %edi
|
|
||||||
andl $LOAD_MASK, %edi
|
|
||||||
movl (elf_program_header + p64_filesz), %ecx
|
|
||||||
call *%esi
|
|
||||||
|
|
||||||
leavel
|
|
||||||
popal
|
|
||||||
ret
|
|
||||||
|
|
||||||
|
|
||||||
# read callback format
|
# read callback format
|
||||||
# eax: first byte
|
# eax: first byte
|
||||||
|
@ -185,72 +104,42 @@ elf_read_kernel_to_memory:
|
||||||
movl %esp, %ebp
|
movl %esp, %ebp
|
||||||
subl $2, %esp
|
subl $2, %esp
|
||||||
|
|
||||||
# read start of file header
|
# read file header
|
||||||
movl $0, %eax
|
movl $0, %eax
|
||||||
movl $24, %ecx
|
movl $64, %ecx
|
||||||
movl $elf_file_header, %edi
|
movl $elf_file_header, %edi
|
||||||
call *%esi
|
call *%esi
|
||||||
|
|
||||||
call elf_validate_file_header
|
call elf_validate_file_header
|
||||||
|
|
||||||
# determine file header size
|
cmpl $0, (elf_file_header + e_phoff + 4)
|
||||||
movl $52, %ecx
|
|
||||||
movl $64, %edx
|
|
||||||
cmpb $ELFCLASS64, (elf_file_header + EI_CLASS)
|
|
||||||
cmovel %edx, %ecx
|
|
||||||
|
|
||||||
# read full file header
|
|
||||||
movl $0, %eax
|
|
||||||
movl $elf_file_header, %edi
|
|
||||||
call *%esi
|
|
||||||
|
|
||||||
# verify that e_phoff fits in 32 bits
|
|
||||||
cmpb $ELFCLASS64, (elf_file_header + EI_CLASS)
|
|
||||||
jne .elf_read_kernel_to_memory_valid_offset
|
|
||||||
cmpl $0, (elf_file_header + e64_phoff + 4)
|
|
||||||
jnz .elf_read_kernel_to_memory_unsupported_offset
|
jnz .elf_read_kernel_to_memory_unsupported_offset
|
||||||
.elf_read_kernel_to_memory_valid_offset:
|
|
||||||
|
|
||||||
# read architecture phentsize and phnum to fixed locations
|
|
||||||
movw (elf_file_header + e32_phentsize), %ax
|
|
||||||
movw (elf_file_header + e32_phnum), %bx
|
|
||||||
movl (elf_file_header + e32_phoff), %ecx
|
|
||||||
cmpb $ELFCLASS64, (elf_file_header + EI_CLASS)
|
|
||||||
cmovew (elf_file_header + e64_phentsize), %ax
|
|
||||||
cmovew (elf_file_header + e64_phnum), %bx
|
|
||||||
cmovel (elf_file_header + e64_phoff), %ecx
|
|
||||||
movw %ax, (elf_file_header_phentsize)
|
|
||||||
movw %bx, (elf_file_header_phnum)
|
|
||||||
movl %ecx, (elf_file_header_phoff)
|
|
||||||
|
|
||||||
# current program header
|
# current program header
|
||||||
movw $0, -2(%ebp)
|
movw $0, -2(%ebp)
|
||||||
|
|
||||||
.elf_read_kernel_to_memory_loop_program_headers:
|
.elf_read_kernel_to_memory_loop_program_headers:
|
||||||
movw -2(%ebp), %cx
|
movw -2(%ebp), %cx
|
||||||
cmpw (elf_file_header_phnum), %cx
|
cmpw (elf_file_header + e_phnum), %cx
|
||||||
jae .elf_read_kernel_to_memory_done
|
jae .elf_read_kernel_to_memory_done
|
||||||
|
|
||||||
# eax := program_header_index * e_phentsize + e_phoff
|
# eax := program_header_index * e_phentsize + e_phoff
|
||||||
xorl %eax, %eax
|
xorl %eax, %eax
|
||||||
movw %cx, %ax
|
movw %cx, %ax
|
||||||
xorl %ebx, %ebx
|
xorl %ebx, %ebx
|
||||||
movw (elf_file_header_phentsize), %bx
|
movw (elf_file_header + e_phentsize), %bx
|
||||||
mull %ebx
|
mull %ebx
|
||||||
addl (elf_file_header_phoff), %eax
|
addl (elf_file_header + e_phoff), %eax
|
||||||
jc .elf_read_kernel_to_memory_unsupported_offset
|
jc .elf_read_kernel_to_memory_unsupported_offset
|
||||||
|
|
||||||
# determine program header size
|
# setup program header size and address
|
||||||
movl $32, %ecx
|
movl $56, %ecx
|
||||||
movl $56, %edx
|
|
||||||
cmpb $ELFCLASS64, (elf_file_header + EI_CLASS)
|
|
||||||
cmovel %edx, %ecx
|
|
||||||
|
|
||||||
# read program header
|
|
||||||
movl $elf_program_header, %edi
|
movl $elf_program_header, %edi
|
||||||
|
|
||||||
|
# read the program header
|
||||||
call *%esi
|
call *%esi
|
||||||
|
|
||||||
# test if program header is NULL header
|
# test if program header is empty
|
||||||
cmpl $PT_NULL, (elf_program_header + p_type)
|
cmpl $PT_NULL, (elf_program_header + p_type)
|
||||||
je .elf_read_kernel_to_memory_null_program_header
|
je .elf_read_kernel_to_memory_null_program_header
|
||||||
|
|
||||||
|
@ -258,12 +147,33 @@ elf_read_kernel_to_memory:
|
||||||
cmpl $PT_LOAD, (elf_program_header + p_type)
|
cmpl $PT_LOAD, (elf_program_header + p_type)
|
||||||
jne .elf_read_kernel_to_memory_not_loadable_header
|
jne .elf_read_kernel_to_memory_not_loadable_header
|
||||||
|
|
||||||
# read program header to memory
|
# memset p_filesz -> p_memsz to 0
|
||||||
movl $elf_read_program_header32_to_memory, %eax
|
movl (elf_program_header + p_filesz), %ebx
|
||||||
movl $elf_read_program_header64_to_memory, %ebx
|
|
||||||
cmpb $ELFCLASS64, (elf_file_header + EI_CLASS)
|
movl (elf_program_header + p_vaddr), %edi
|
||||||
cmovel %ebx, %eax
|
andl $0x7FFFFFFF, %edi
|
||||||
call *%eax
|
addl %ebx, %edi
|
||||||
|
|
||||||
|
movl (elf_program_header + p_memsz), %ecx
|
||||||
|
subl %ebx, %ecx
|
||||||
|
jz .elf_read_kernel_to_memory_memset_done
|
||||||
|
|
||||||
|
.elf_read_kernel_to_memory_memset:
|
||||||
|
movb $0, (%edi)
|
||||||
|
incl %edi
|
||||||
|
decl %ecx
|
||||||
|
jnz .elf_read_kernel_to_memory_memset
|
||||||
|
.elf_read_kernel_to_memory_memset_done:
|
||||||
|
|
||||||
|
# read file specified in program header to memory
|
||||||
|
movl (elf_program_header + p_offset), %eax
|
||||||
|
movl (elf_program_header + p_vaddr), %edi
|
||||||
|
andl $0x7FFFFFFF, %edi
|
||||||
|
movl (elf_program_header + p_filesz), %ecx
|
||||||
|
|
||||||
|
#call print_hex32; call print_newline
|
||||||
|
|
||||||
|
call *%esi
|
||||||
|
|
||||||
.elf_read_kernel_to_memory_null_program_header:
|
.elf_read_kernel_to_memory_null_program_header:
|
||||||
incw -2(%ebp)
|
incw -2(%ebp)
|
||||||
|
@ -275,7 +185,7 @@ elf_read_kernel_to_memory:
|
||||||
|
|
||||||
# set kernel entry address
|
# set kernel entry address
|
||||||
movl (elf_file_header + e_entry), %eax
|
movl (elf_file_header + e_entry), %eax
|
||||||
andl $LOAD_MASK, %eax
|
andl $0x7FFFFF, %eax
|
||||||
|
|
||||||
ret
|
ret
|
||||||
|
|
||||||
|
@ -286,12 +196,11 @@ elf_read_kernel_to_memory:
|
||||||
movw $elf_read_kernel_to_memory_not_loadable_header_msg, %si
|
movw $elf_read_kernel_to_memory_not_loadable_header_msg, %si
|
||||||
jmp print_and_halt
|
jmp print_and_halt
|
||||||
|
|
||||||
.section .data
|
|
||||||
|
|
||||||
elf_validate_file_header_invalid_magic_msg:
|
elf_validate_file_header_invalid_magic_msg:
|
||||||
.asciz "ELF: file has invalid ELF magic"
|
.asciz "ELF: file has invalid ELF magic"
|
||||||
elf_validate_file_header_invalid_class_msg:
|
elf_validate_file_header_only_64bit_supported_msg:
|
||||||
.asciz "ELF: file has invalid ELF class"
|
.asciz "ELF: file is not targettint 64 bit"
|
||||||
elf_validate_file_header_only_little_endian_supported_msg:
|
elf_validate_file_header_only_little_endian_supported_msg:
|
||||||
.asciz "ELF: file is not in little endian format"
|
.asciz "ELF: file is not in little endian format"
|
||||||
elf_validate_file_header_not_current_version_msg:
|
elf_validate_file_header_not_current_version_msg:
|
||||||
|
@ -309,12 +218,5 @@ elf_read_kernel_to_memory_not_loadable_header_msg:
|
||||||
elf_file_header:
|
elf_file_header:
|
||||||
.skip 64
|
.skip 64
|
||||||
|
|
||||||
elf_file_header_phentsize:
|
|
||||||
.skip 2
|
|
||||||
elf_file_header_phnum:
|
|
||||||
.skip 2
|
|
||||||
elf_file_header_phoff:
|
|
||||||
.skip 4 # NOTE: only 32 bit offsets are supported
|
|
||||||
|
|
||||||
elf_program_header:
|
elf_program_header:
|
||||||
.skip 56
|
.skip 56
|
||||||
|
|
|
@ -2,7 +2,9 @@
|
||||||
.set SECTOR_SHIFT, 9
|
.set SECTOR_SHIFT, 9
|
||||||
.set SECTOR_SIZE, 1 << SECTOR_SHIFT
|
.set SECTOR_SIZE, 1 << SECTOR_SHIFT
|
||||||
|
|
||||||
.set EXT2_MAX_BLOCK_SIZE, 4096
|
# FIXME: don't assume 1024 byte blocks
|
||||||
|
.set EXT2_BLOCK_SHIFT, 10
|
||||||
|
.set EXT2_BLOCK_SIZE, 1 << EXT2_BLOCK_SHIFT
|
||||||
.set EXT2_SUPERBLOCK_SIZE, 264
|
.set EXT2_SUPERBLOCK_SIZE, 264
|
||||||
.set EXT2_BGD_SHIFT, 5
|
.set EXT2_BGD_SHIFT, 5
|
||||||
.set EXT2_BGD_SIZE, 1 << EXT2_BGD_SHIFT
|
.set EXT2_BGD_SIZE, 1 << EXT2_BGD_SHIFT
|
||||||
|
@ -16,7 +18,6 @@
|
||||||
.set EXT2_S_IFREG, 0x8000
|
.set EXT2_S_IFREG, 0x8000
|
||||||
|
|
||||||
# superblock offsets
|
# superblock offsets
|
||||||
.set s_first_data_block, 20
|
|
||||||
.set s_log_block_size, 24
|
.set s_log_block_size, 24
|
||||||
.set s_inodes_per_group, 40
|
.set s_inodes_per_group, 40
|
||||||
.set s_magic, 56
|
.set s_magic, 56
|
||||||
|
@ -65,7 +66,9 @@ has_ext2_filesystem:
|
||||||
|
|
||||||
# from byte offset 1024
|
# from byte offset 1024
|
||||||
addl $(1024 / SECTOR_SIZE), %eax
|
addl $(1024 / SECTOR_SIZE), %eax
|
||||||
adcw $0, %bx
|
jnc .has_ext2_filesystem_no_overflow
|
||||||
|
incw %bx
|
||||||
|
.has_ext2_filesystem_no_overflow:
|
||||||
|
|
||||||
# into sector buffer
|
# into sector buffer
|
||||||
movw $ext2_block_buffer, %di
|
movw $ext2_block_buffer, %di
|
||||||
|
@ -87,16 +90,11 @@ has_ext2_filesystem:
|
||||||
movl (ext2_superblock_buffer + s_log_block_size), %ecx
|
movl (ext2_superblock_buffer + s_log_block_size), %ecx
|
||||||
testl $0xFFFFFF00, %ecx
|
testl $0xFFFFFF00, %ecx
|
||||||
jnz .has_ext2_filesystem_unsupported_block_size
|
jnz .has_ext2_filesystem_unsupported_block_size
|
||||||
# verify 1024 << s_log_block_size <= EXT2_MAX_BLOCK_SIZE
|
# verify 1024 << s_log_block_size == EXT2_BLOCK_SIZE
|
||||||
movl $1024, %eax
|
movl $1024, %eax
|
||||||
shll %cl, %eax
|
shll %cl, %eax
|
||||||
cmpl $EXT2_MAX_BLOCK_SIZE, %eax
|
cmpl $EXT2_BLOCK_SIZE, %eax
|
||||||
ja .has_ext2_filesystem_unsupported_block_size
|
jne .has_ext2_filesystem_unsupported_block_size
|
||||||
|
|
||||||
# fill block size and shift
|
|
||||||
movl %eax, (ext2_block_size)
|
|
||||||
addl $10, %ecx
|
|
||||||
movl %ecx, (ext2_block_shift)
|
|
||||||
|
|
||||||
# fill inode size
|
# fill inode size
|
||||||
movl $128, %eax
|
movl $128, %eax
|
||||||
|
@ -132,23 +130,38 @@ has_ext2_filesystem:
|
||||||
# reads block in to ext2_block_buffer
|
# reads block in to ext2_block_buffer
|
||||||
# eax: block number
|
# eax: block number
|
||||||
ext2_read_block:
|
ext2_read_block:
|
||||||
pushal
|
pushl %eax
|
||||||
|
pushl %ebx
|
||||||
|
pushw %cx
|
||||||
|
pushl %edx
|
||||||
|
pushw %di
|
||||||
|
|
||||||
# ecx := sectors_per_block := block_size / sector_size
|
# NOTE: this assumes 1024 block size
|
||||||
movl (ext2_block_size), %ecx
|
# eax := (block * block_size) / sector_size := (eax << EXT2_BLOCK_SHIFT) >> SECTOR_SHIFT
|
||||||
shrl $SECTOR_SHIFT, %ecx
|
xorl %edx, %edx
|
||||||
|
shll $EXT2_BLOCK_SHIFT, %eax
|
||||||
|
shrl $SECTOR_SHIFT, %eax
|
||||||
|
|
||||||
# ebx:eax := block * sectors_per_block + (ext2_partition_first_sector)
|
# ebx:eax := eax + (ext2_partition_first_sector)
|
||||||
xorl %ebx, %ebx
|
movl (ext2_partition_first_sector + 4), %ebx
|
||||||
mull %ecx
|
|
||||||
addl (ext2_partition_first_sector + 0), %eax
|
addl (ext2_partition_first_sector + 0), %eax
|
||||||
adcl (ext2_partition_first_sector + 4), %ebx
|
jnc .ext2_read_block_no_carry
|
||||||
|
incl %ebx
|
||||||
|
.ext2_read_block_no_carry:
|
||||||
|
|
||||||
|
# sectors per block
|
||||||
|
movw $(EXT2_BLOCK_SIZE / SECTOR_SIZE), %cx
|
||||||
|
|
||||||
movw $ext2_block_buffer, %di
|
movw $ext2_block_buffer, %di
|
||||||
|
|
||||||
movb (ext2_drive_number), %dl
|
movb (ext2_drive_number), %dl
|
||||||
call read_from_disk
|
call read_from_disk
|
||||||
|
|
||||||
popal
|
popw %di
|
||||||
|
popl %edx
|
||||||
|
popw %cx
|
||||||
|
popl %ebx
|
||||||
|
popl %eax
|
||||||
ret
|
ret
|
||||||
|
|
||||||
|
|
||||||
|
@ -157,23 +170,15 @@ ext2_read_block:
|
||||||
ext2_read_block_group_descriptor:
|
ext2_read_block_group_descriptor:
|
||||||
pushal
|
pushal
|
||||||
|
|
||||||
# ebx := bgd_block_byte_offset := (s_first_data_block + 1) * block_size
|
# eax := bgd_byte_offset := 2048 + EXT2_BGD_SIZE * eax := (eax << EXT2_BGD_SHIFT) + 2048
|
||||||
# := (s_first_data_block + 1) << ext2_block_shift
|
shll $EXT2_BGD_SHIFT, %eax
|
||||||
movl (ext2_superblock_buffer + s_first_data_block), %ebx
|
addl $2048, %eax
|
||||||
incl %ebx
|
|
||||||
movb (ext2_block_shift), %cl
|
|
||||||
shll %cl, %ebx
|
|
||||||
|
|
||||||
# eax := bgd_byte_offset := bgd_block_byte_offset + EXT2_BGD_SIZE * block_group;
|
# eax: bgd_block := bgd_byte_offset / EXT2_BLOCK_SIZE
|
||||||
# := bgd_block_byte_offset + (block_group << EXT2_BGD_SHIFT)
|
# ebx: bgd_offset := bgd_byte_offset % EXT2_BLOCK_SIZE
|
||||||
movb $EXT2_BGD_SHIFT, %cl
|
|
||||||
shll %cl, %eax
|
|
||||||
addl %ebx, %eax
|
|
||||||
|
|
||||||
# eax: bgd_block := bgd_byte_offset / block_size
|
|
||||||
# ebx: bgd_offset := bgd_byte_offset % block_size
|
|
||||||
xorl %edx, %edx
|
xorl %edx, %edx
|
||||||
divl (ext2_block_size)
|
movl $EXT2_BLOCK_SIZE, %ebx
|
||||||
|
divl %ebx
|
||||||
movl %edx, %ebx
|
movl %edx, %ebx
|
||||||
|
|
||||||
call ext2_read_block
|
call ext2_read_block
|
||||||
|
@ -199,19 +204,23 @@ ext2_read_inode:
|
||||||
# ebx := inode_index = (ino - 1) % s_inodes_per_group
|
# ebx := inode_index = (ino - 1) % s_inodes_per_group
|
||||||
xorl %edx, %edx
|
xorl %edx, %edx
|
||||||
decl %eax
|
decl %eax
|
||||||
divl (ext2_superblock_buffer + s_inodes_per_group)
|
movl (ext2_superblock_buffer + s_inodes_per_group), %ebx
|
||||||
|
divl %ebx
|
||||||
movl %edx, %ebx
|
movl %edx, %ebx
|
||||||
|
|
||||||
call ext2_read_block_group_descriptor
|
call ext2_read_block_group_descriptor
|
||||||
|
|
||||||
# eax := inode_table_block := (inode_index * inode_size) / block_size
|
# eax := inode_table_block := (inode_index * inode_size) / EXT2_BLOCK_SIZE
|
||||||
# ebx := inode_table_offset := (inode_index * inode_size) % block_size
|
# ebx := inode_table_offset := (inode_index * inode_size) % EXT2_BLOCK_SIZE
|
||||||
|
xorl %edx, %edx
|
||||||
movl %ebx, %eax
|
movl %ebx, %eax
|
||||||
mull (ext2_inode_size)
|
movl (ext2_inode_size), %ebx
|
||||||
divl (ext2_block_size)
|
mull %ebx
|
||||||
|
movl $EXT2_BLOCK_SIZE, %ebx
|
||||||
|
divl %ebx
|
||||||
movl %edx, %ebx
|
movl %edx, %ebx
|
||||||
|
|
||||||
# eax := filesystem_block := eax + bg_inode_table
|
# eax := file system block := eax + bg_inode_table
|
||||||
addl (ext2_block_group_descriptor_buffer + bg_inode_table), %eax
|
addl (ext2_block_group_descriptor_buffer + bg_inode_table), %eax
|
||||||
|
|
||||||
movb (ext2_drive_number), %dl
|
movb (ext2_drive_number), %dl
|
||||||
|
@ -227,10 +236,6 @@ ext2_read_inode:
|
||||||
movl (ext2_inode_size), %ecx
|
movl (ext2_inode_size), %ecx
|
||||||
rep movsb
|
rep movsb
|
||||||
|
|
||||||
# reset indirect cache to zero
|
|
||||||
movl $0, (ext2_inode_indirect_number)
|
|
||||||
|
|
||||||
.ext2_read_inode_done:
|
|
||||||
popal
|
popal
|
||||||
ret
|
ret
|
||||||
|
|
||||||
|
@ -244,19 +249,15 @@ ext2_data_block_index:
|
||||||
pushl %ecx
|
pushl %ecx
|
||||||
pushl %edx
|
pushl %edx
|
||||||
pushl %esi
|
pushl %esi
|
||||||
pushl %edi
|
|
||||||
|
|
||||||
# ebx := max_data_blocks := (file_size + block_size - 1) / block_size
|
# calculate max data blocks
|
||||||
# := (i_size + ext2_block_size - 1) >> ext2_block_shift
|
movl (ext2_inode_buffer + i_size), %ecx
|
||||||
# cl := ext2_block_shift
|
addl (ext2_inode_size), %ecx
|
||||||
movl (ext2_inode_buffer + i_size), %ebx
|
decl %ecx
|
||||||
addl (ext2_block_size), %ebx
|
shll $EXT2_BLOCK_SHIFT, %ecx
|
||||||
decl %ebx
|
|
||||||
movb (ext2_block_shift), %cl
|
|
||||||
shrl %cl, %ebx
|
|
||||||
|
|
||||||
# verify data block is within bounds
|
# verify data block is within bounds
|
||||||
cmpl %ebx, %eax
|
cmpl %ecx, %eax
|
||||||
jae .ext2_data_block_index_out_of_bounds
|
jae .ext2_data_block_index_out_of_bounds
|
||||||
|
|
||||||
# check if this is direct block access
|
# check if this is direct block access
|
||||||
|
@ -264,26 +265,18 @@ ext2_data_block_index:
|
||||||
jb .ext2_data_block_index_direct
|
jb .ext2_data_block_index_direct
|
||||||
subl $12, %eax
|
subl $12, %eax
|
||||||
|
|
||||||
# cl := indices_per_block_shift := ext2_block_shift - 2
|
|
||||||
# ebx := comp
|
|
||||||
subb $2, %cl
|
|
||||||
movl $1, %ebx
|
|
||||||
shll %cl, %ebx
|
|
||||||
|
|
||||||
# check if this is singly indirect block access
|
# check if this is singly indirect block access
|
||||||
cmpl %ebx, %eax
|
cmpl $(EXT2_BLOCK_SIZE / 4), %eax
|
||||||
jb .ext2_data_block_index_singly_indirect
|
jb .ext2_data_block_index_singly_indirect
|
||||||
subl %ebx, %eax
|
subl $(EXT2_BLOCK_SIZE / 4), %eax
|
||||||
shll %cl, %ebx
|
|
||||||
|
|
||||||
# check if this is doubly indirect block access
|
# check if this is doubly indirect block access
|
||||||
cmpl %ebx, %eax
|
cmpl $((EXT2_BLOCK_SIZE / 4) * (EXT2_BLOCK_SIZE / 4)), %eax
|
||||||
jb .ext2_data_block_index_doubly_indirect
|
jb .ext2_data_block_index_doubly_indirect
|
||||||
subl %ebx, %eax
|
subl $((EXT2_BLOCK_SIZE / 4) * (EXT2_BLOCK_SIZE / 4)), %eax
|
||||||
shll %cl, %ebx
|
|
||||||
|
|
||||||
# check if this is triply indirect block access
|
# check if this is triply indirect block access
|
||||||
cmpl %ebx, %eax
|
cmpl $((EXT2_BLOCK_SIZE / 4) * (EXT2_BLOCK_SIZE / 4) * (EXT2_BLOCK_SIZE / 4)), %eax
|
||||||
jb .ext2_data_block_index_triply_indirect
|
jb .ext2_data_block_index_triply_indirect
|
||||||
|
|
||||||
# otherwise this is invalid access
|
# otherwise this is invalid access
|
||||||
|
@ -316,28 +309,6 @@ ext2_data_block_index:
|
||||||
# ebx := index
|
# ebx := index
|
||||||
# cx := depth
|
# cx := depth
|
||||||
.ext2_data_block_index_indirect:
|
.ext2_data_block_index_indirect:
|
||||||
# edx := cache index := (index & ~(block_size / 4 - 1)) | depth
|
|
||||||
# := (index & -(block_size >> 2)) | depth
|
|
||||||
movl (ext2_block_size), %edx
|
|
||||||
shrl $2, %edx
|
|
||||||
negl %edx
|
|
||||||
andl %ebx, %edx
|
|
||||||
orw %cx, %dx
|
|
||||||
|
|
||||||
# check whether this block is already cached
|
|
||||||
cmpl $0, (ext2_inode_indirect_number)
|
|
||||||
je .ext2_data_block_index_indirect_no_cache
|
|
||||||
cmpl %edx, (ext2_inode_indirect_number)
|
|
||||||
je .ext2_data_block_index_indirect_cached
|
|
||||||
|
|
||||||
.ext2_data_block_index_indirect_no_cache:
|
|
||||||
# update cache block number, will be cached when found
|
|
||||||
movl %edx, (ext2_inode_indirect_number)
|
|
||||||
|
|
||||||
# eax := current block
|
|
||||||
# ebx := index
|
|
||||||
# cx := depth
|
|
||||||
.ext2_data_block_index_indirect_loop:
|
|
||||||
call ext2_read_block
|
call ext2_read_block
|
||||||
|
|
||||||
# store depth and index
|
# store depth and index
|
||||||
|
@ -348,21 +319,20 @@ ext2_data_block_index:
|
||||||
jbe .ext2_data_block_index_no_shift
|
jbe .ext2_data_block_index_no_shift
|
||||||
|
|
||||||
# cl := shift
|
# cl := shift
|
||||||
movb (ext2_block_shift), %al
|
movb $(EXT2_BLOCK_SHIFT - 2), %al
|
||||||
subb $2, %al
|
|
||||||
decb %cl
|
decb %cl
|
||||||
mulb %cl
|
mulb %cl
|
||||||
movb %al, %cl
|
movb %al, %cl
|
||||||
|
|
||||||
# ebx := ebx >> shift
|
# ebx := ebx >> cl
|
||||||
shrl %cl, %ebx
|
shrl %cl, %ebx
|
||||||
|
|
||||||
.ext2_data_block_index_no_shift:
|
.ext2_data_block_index_no_shift:
|
||||||
# edx := index of next block (ebx & (block_size / 4 - 1))
|
# edx := index of next block
|
||||||
movl (ext2_block_size), %edx
|
movl %ebx, %eax
|
||||||
shrl $2, %edx
|
xorl %edx, %edx
|
||||||
decl %edx
|
movl $(EXT2_BLOCK_SIZE / 4), %ebx
|
||||||
andl %ebx, %edx
|
divl %ebx
|
||||||
|
|
||||||
# eax := next block
|
# eax := next block
|
||||||
movl $ext2_block_buffer, %esi
|
movl $ext2_block_buffer, %esi
|
||||||
|
@ -372,13 +342,7 @@ ext2_data_block_index:
|
||||||
popl %ebx
|
popl %ebx
|
||||||
popw %cx
|
popw %cx
|
||||||
|
|
||||||
loop .ext2_data_block_index_indirect_loop
|
loop .ext2_data_block_index_indirect
|
||||||
|
|
||||||
# cache last read block
|
|
||||||
movw $ext2_block_buffer, %si
|
|
||||||
movw $ext2_inode_indirect_buffer, %di
|
|
||||||
movw (ext2_block_size), %cx
|
|
||||||
rep movsb
|
|
||||||
|
|
||||||
jmp .ext2_data_block_index_done
|
jmp .ext2_data_block_index_done
|
||||||
|
|
||||||
|
@ -394,16 +358,7 @@ ext2_data_block_index:
|
||||||
movl $0, %eax
|
movl $0, %eax
|
||||||
jmp .ext2_data_block_index_done
|
jmp .ext2_data_block_index_done
|
||||||
|
|
||||||
.ext2_data_block_index_indirect_cached:
|
|
||||||
movl $ext2_inode_indirect_buffer, %esi
|
|
||||||
movl (ext2_block_size), %edx
|
|
||||||
shrl $2, %edx
|
|
||||||
decl %edx
|
|
||||||
andl %edx, %ebx
|
|
||||||
movl (%esi, %ebx, 4), %eax
|
|
||||||
|
|
||||||
.ext2_data_block_index_done:
|
.ext2_data_block_index_done:
|
||||||
popl %edi
|
|
||||||
popl %esi
|
popl %esi
|
||||||
popl %edx
|
popl %edx
|
||||||
popl %ecx
|
popl %ecx
|
||||||
|
@ -419,7 +374,6 @@ ext2_data_block_index:
|
||||||
.global ext2_inode_read_bytes
|
.global ext2_inode_read_bytes
|
||||||
ext2_inode_read_bytes:
|
ext2_inode_read_bytes:
|
||||||
pushal
|
pushal
|
||||||
|
|
||||||
pushl %ebp
|
pushl %ebp
|
||||||
movl %esp, %ebp
|
movl %esp, %ebp
|
||||||
subl $8, %esp
|
subl $8, %esp
|
||||||
|
@ -428,11 +382,11 @@ ext2_inode_read_bytes:
|
||||||
movl %eax, 0(%esp)
|
movl %eax, 0(%esp)
|
||||||
movl %ecx, 4(%esp)
|
movl %ecx, 4(%esp)
|
||||||
|
|
||||||
# eax := first_byte / block_size
|
# check if eax % EXT2_BLOCK_SIZE != 0,
|
||||||
# edx := first_byte % block_size
|
# then we need to read a partial block starting from an offset
|
||||||
# when edx == 0, no partial read needed
|
|
||||||
xorl %edx, %edx
|
xorl %edx, %edx
|
||||||
divl (ext2_block_size)
|
movl $EXT2_BLOCK_SIZE, %ebx
|
||||||
|
divl %ebx
|
||||||
testl %edx, %edx
|
testl %edx, %edx
|
||||||
jz .ext2_inode_read_bytes_no_partial_start
|
jz .ext2_inode_read_bytes_no_partial_start
|
||||||
|
|
||||||
|
@ -441,7 +395,7 @@ ext2_inode_read_bytes:
|
||||||
call ext2_read_block
|
call ext2_read_block
|
||||||
|
|
||||||
# ecx := byte count (min(block_size - edx, remaining_bytes))
|
# ecx := byte count (min(block_size - edx, remaining_bytes))
|
||||||
movl (ext2_block_size), %ecx
|
movl $EXT2_BLOCK_SIZE, %ecx
|
||||||
subl %edx, %ecx
|
subl %edx, %ecx
|
||||||
cmpl %ecx, 4(%esp)
|
cmpl %ecx, 4(%esp)
|
||||||
cmovbl 4(%esp), %ecx
|
cmovbl 4(%esp), %ecx
|
||||||
|
@ -454,7 +408,15 @@ ext2_inode_read_bytes:
|
||||||
movl $ext2_block_buffer, %esi
|
movl $ext2_block_buffer, %esi
|
||||||
addl %edx, %esi
|
addl %edx, %esi
|
||||||
|
|
||||||
call memcpy32
|
# very dumb memcpy with 32 bit addresses
|
||||||
|
movl $0, %ebx
|
||||||
|
.ext2_inode_read_bytes_memcpy_partial:
|
||||||
|
movb (%esi, %ebx), %al
|
||||||
|
movb %al, (%edi, %ebx)
|
||||||
|
incl %ebx
|
||||||
|
decl %ecx
|
||||||
|
jnz .ext2_inode_read_bytes_memcpy_partial
|
||||||
|
addl %ebx, %edi
|
||||||
|
|
||||||
# check if all sectors are read
|
# check if all sectors are read
|
||||||
cmpl $0, 4(%esp)
|
cmpl $0, 4(%esp)
|
||||||
|
@ -463,15 +425,14 @@ ext2_inode_read_bytes:
|
||||||
.ext2_inode_read_bytes_no_partial_start:
|
.ext2_inode_read_bytes_no_partial_start:
|
||||||
# eax := data block index (byte_start / block_size)
|
# eax := data block index (byte_start / block_size)
|
||||||
movl 0(%esp), %eax
|
movl 0(%esp), %eax
|
||||||
movb (ext2_block_shift), %cl
|
shrl $(EXT2_BLOCK_SHIFT), %eax
|
||||||
shrl %cl, %eax
|
|
||||||
|
|
||||||
# get data block index and read block
|
# get data block index and read block
|
||||||
call ext2_data_block_index
|
call ext2_data_block_index
|
||||||
call ext2_read_block
|
call ext2_read_block
|
||||||
|
|
||||||
# calculate bytes to copy (min(block_size, remaining_bytes))
|
# calculate bytes to copy (min(block_size, remaining_bytes))
|
||||||
movl (ext2_block_size), %ecx
|
movl $EXT2_BLOCK_SIZE, %ecx
|
||||||
cmpl %ecx, 4(%esp)
|
cmpl %ecx, 4(%esp)
|
||||||
cmovbl 4(%esp), %ecx
|
cmovbl 4(%esp), %ecx
|
||||||
|
|
||||||
|
@ -479,8 +440,16 @@ ext2_inode_read_bytes:
|
||||||
addl %ecx, 0(%esp)
|
addl %ecx, 0(%esp)
|
||||||
subl %ecx, 4(%esp)
|
subl %ecx, 4(%esp)
|
||||||
|
|
||||||
|
# very dumb memcpy with 32 bit addresses
|
||||||
movl $ext2_block_buffer, %esi
|
movl $ext2_block_buffer, %esi
|
||||||
call memcpy32
|
movl $0, %ebx
|
||||||
|
.ext2_inode_read_bytes_memcpy:
|
||||||
|
movb (%esi, %ebx), %al
|
||||||
|
movb %al, (%edi, %ebx)
|
||||||
|
incl %ebx
|
||||||
|
decl %ecx
|
||||||
|
jnz .ext2_inode_read_bytes_memcpy
|
||||||
|
addl %ebx, %edi
|
||||||
|
|
||||||
# read next block if more sectors remaining
|
# read next block if more sectors remaining
|
||||||
cmpl $0, 4(%esp)
|
cmpl $0, 4(%esp)
|
||||||
|
@ -519,12 +488,11 @@ ext2_directory_find_inode:
|
||||||
cmpw $0xFF, %cx
|
cmpw $0xFF, %cx
|
||||||
ja .ext2_directory_find_inode_not_found
|
ja .ext2_directory_find_inode_not_found
|
||||||
|
|
||||||
# ebx := max data blocks: ceil(i_size / block_size)
|
# ebx := max data blocks: ceil(i_size / EXT2_BLOCK_SIZE)
|
||||||
movl (ext2_inode_buffer + i_size), %ebx
|
movl (ext2_inode_buffer + i_size), %ebx
|
||||||
addl (ext2_block_size), %ebx
|
addl $EXT2_BLOCK_SHIFT, %ebx
|
||||||
decl %ebx
|
decl %ebx
|
||||||
movb (ext2_block_shift), %cl
|
shrl $EXT2_BLOCK_SHIFT, %ebx
|
||||||
shrl %cl, %ebx
|
|
||||||
jz .ext2_directory_find_inode_not_found
|
jz .ext2_directory_find_inode_not_found
|
||||||
|
|
||||||
# 4(%esp) := current block
|
# 4(%esp) := current block
|
||||||
|
@ -571,9 +539,7 @@ ext2_directory_find_inode:
|
||||||
|
|
||||||
# go to next entry if this block contains one
|
# go to next entry if this block contains one
|
||||||
addw 4(%si), %si
|
addw 4(%si), %si
|
||||||
movw $ext2_block_buffer, %di
|
cmpw $(ext2_block_buffer + EXT2_BLOCK_SIZE), %si
|
||||||
addw (ext2_block_size), %di
|
|
||||||
cmpw %di, %si
|
|
||||||
jb .ext2_directory_find_inode_loop_entries
|
jb .ext2_directory_find_inode_loop_entries
|
||||||
|
|
||||||
.ext2_directory_find_inode_next_block:
|
.ext2_directory_find_inode_next_block:
|
||||||
|
@ -582,7 +548,7 @@ ext2_directory_find_inode:
|
||||||
jb .ext2_directory_find_inode_block_read_loop
|
jb .ext2_directory_find_inode_block_read_loop
|
||||||
|
|
||||||
.ext2_directory_find_inode_not_found:
|
.ext2_directory_find_inode_not_found:
|
||||||
xorb %al, %al
|
movb $0, %al
|
||||||
jmp .ext2_directory_find_inode_done
|
jmp .ext2_directory_find_inode_done
|
||||||
|
|
||||||
.ext2_directory_find_inode_found:
|
.ext2_directory_find_inode_found:
|
||||||
|
@ -676,7 +642,6 @@ ext2_find_kernel:
|
||||||
movw $ext2_kernel_not_reg_msg, %si
|
movw $ext2_kernel_not_reg_msg, %si
|
||||||
jmp print_and_halt
|
jmp print_and_halt
|
||||||
|
|
||||||
.section .data
|
|
||||||
|
|
||||||
kernel_path:
|
kernel_path:
|
||||||
.short kernel_path1
|
.short kernel_path1
|
||||||
|
@ -689,12 +654,13 @@ kernel_path2:
|
||||||
.short 15
|
.short 15
|
||||||
.asciz "banan-os.kernel"
|
.asciz "banan-os.kernel"
|
||||||
|
|
||||||
|
|
||||||
root_partition_does_not_fit_ext2_filesystem_msg:
|
root_partition_does_not_fit_ext2_filesystem_msg:
|
||||||
.asciz "Root partition is too small to contain ext2 filesystem"
|
.asciz "Root partition is too small to contain ext2 filesystem"
|
||||||
root_partition_has_invalid_ext2_magic_msg:
|
root_partition_has_invalid_ext2_magic_msg:
|
||||||
.asciz "Root partition doesn't contain ext2 magic number"
|
.asciz "Root partition doesn't contain ext2 magic number"
|
||||||
root_partition_has_unsupported_ext2_block_size_msg:
|
root_partition_has_unsupported_ext2_block_size_msg:
|
||||||
.asciz "Root partition has unsupported ext2 block size (1 KiB, 2 KiB and 4 KiB are supported)"
|
.asciz "Root partition has unsupported ext2 block size (only 1024 supported)"
|
||||||
|
|
||||||
ext2_part_not_dir_msg:
|
ext2_part_not_dir_msg:
|
||||||
.asciz "inode in root path is not directory"
|
.asciz "inode in root path is not directory"
|
||||||
|
@ -715,14 +681,8 @@ ext2_looking_for_msg:
|
||||||
|
|
||||||
.section .bss
|
.section .bss
|
||||||
|
|
||||||
.align SECTOR_SIZE
|
|
||||||
ext2_block_buffer:
|
ext2_block_buffer:
|
||||||
.skip EXT2_MAX_BLOCK_SIZE
|
.skip EXT2_BLOCK_SIZE
|
||||||
|
|
||||||
ext2_inode_indirect_buffer:
|
|
||||||
.skip EXT2_MAX_BLOCK_SIZE
|
|
||||||
ext2_inode_indirect_number:
|
|
||||||
.skip 4
|
|
||||||
|
|
||||||
ext2_partition_first_sector:
|
ext2_partition_first_sector:
|
||||||
.skip 8
|
.skip 8
|
||||||
|
@ -734,10 +694,6 @@ ext2_drive_number:
|
||||||
# NOTE: fits in 2 bytes
|
# NOTE: fits in 2 bytes
|
||||||
ext2_inode_size:
|
ext2_inode_size:
|
||||||
.skip 4
|
.skip 4
|
||||||
ext2_block_size:
|
|
||||||
.skip 4
|
|
||||||
ext2_block_shift:
|
|
||||||
.skip 4
|
|
||||||
|
|
||||||
ext2_superblock_buffer:
|
ext2_superblock_buffer:
|
||||||
.skip EXT2_SUPERBLOCK_SIZE
|
.skip EXT2_SUPERBLOCK_SIZE
|
||||||
|
|
|
@ -1,67 +1,19 @@
|
||||||
|
.set TARGET_WIDTH, 800
|
||||||
|
.set TARGET_HEIGHT, 600
|
||||||
|
.set TARGET_BPP, 32
|
||||||
|
|
||||||
.code16
|
.code16
|
||||||
.section .stage2
|
.section .stage2
|
||||||
|
|
||||||
# kernel framebuffer information format
|
# Find suitable video mode
|
||||||
# .align 8
|
|
||||||
# .long 0xBABAB007
|
|
||||||
# .long -(0xBABAB007 + width + height + bpp)
|
|
||||||
# .long width (2 bytes used, 4 bytes for ease of calculation)
|
|
||||||
# .long height (2 bytes used, 4 bytes for ease of calculation)
|
|
||||||
# .long bpp (1 bytes used, 4 bytes for ease of calculation)
|
|
||||||
|
|
||||||
# scan memory 0x100000 -> 0x200000 for framebuffer information
|
|
||||||
# return:
|
# return:
|
||||||
# ax: target width
|
# ax: video mode number if found, 0 otherwise
|
||||||
# bx: target height
|
.global vesa_find_video_mode
|
||||||
# cx: target bpp
|
|
||||||
vesa_scan_kernel_image:
|
|
||||||
pushl %edx
|
|
||||||
pushl %esi
|
|
||||||
|
|
||||||
movl $0x100000, %esi
|
|
||||||
|
|
||||||
.vesa_scan_kernel_image_loop:
|
|
||||||
# check magic
|
|
||||||
cmpl $0xBABAB007, (%esi)
|
|
||||||
jne .vesa_scan_kernel_image_next_addr
|
|
||||||
|
|
||||||
# check checksum
|
|
||||||
movl 0x00(%esi), %edx
|
|
||||||
addl 0x04(%esi), %edx
|
|
||||||
addl 0x08(%esi), %edx
|
|
||||||
addl 0x0C(%esi), %edx
|
|
||||||
addl 0x10(%esi), %edx
|
|
||||||
testl %edx, %edx
|
|
||||||
jnz .vesa_scan_kernel_image_next_addr
|
|
||||||
|
|
||||||
# set return registers
|
|
||||||
movw 0x08(%esi), %ax
|
|
||||||
movw 0x0C(%esi), %bx
|
|
||||||
movw 0x10(%esi), %cx
|
|
||||||
jmp .vesa_scan_kernel_image_done
|
|
||||||
|
|
||||||
.vesa_scan_kernel_image_next_addr:
|
|
||||||
addl $8, %esi
|
|
||||||
cmpl $0x200000, %esi
|
|
||||||
jb .vesa_scan_kernel_image_loop
|
|
||||||
|
|
||||||
# zero out return registers
|
|
||||||
xorw %ax, %ax
|
|
||||||
xorw %bx, %bx
|
|
||||||
xorw %cx, %cx
|
|
||||||
|
|
||||||
.vesa_scan_kernel_image_done:
|
|
||||||
popl %esi
|
|
||||||
popl %edx
|
|
||||||
ret
|
|
||||||
|
|
||||||
# Find suitable video mode and save it in (vesa_target_mode)
|
|
||||||
vesa_find_video_mode:
|
vesa_find_video_mode:
|
||||||
pushal
|
pushw %ax
|
||||||
|
pushw %cx
|
||||||
pushl %ebp
|
pushw %di
|
||||||
movl %esp, %ebp
|
pushl %esi
|
||||||
subl $6, %esp
|
|
||||||
|
|
||||||
# clear target mode and frame buffer
|
# clear target mode and frame buffer
|
||||||
movw $0, (vesa_target_mode)
|
movw $0, (vesa_target_mode)
|
||||||
|
@ -71,19 +23,10 @@ vesa_find_video_mode:
|
||||||
movl $0, (framebuffer + 12)
|
movl $0, (framebuffer + 12)
|
||||||
movw $0, (framebuffer + 16)
|
movw $0, (framebuffer + 16)
|
||||||
|
|
||||||
call vesa_scan_kernel_image
|
|
||||||
testw %ax, %ax
|
|
||||||
jz .vesa_find_video_mode_loop_modes_done
|
|
||||||
|
|
||||||
# save arguments in stack
|
|
||||||
movw %ax, -2(%ebp)
|
|
||||||
movw %bx, -4(%ebp)
|
|
||||||
movw %cx, -6(%ebp)
|
|
||||||
|
|
||||||
# get vesa information
|
# get vesa information
|
||||||
movw $0x4F00, %ax
|
movw $0x4F00, %ax
|
||||||
movw $vesa_info_buffer, %di
|
movw $vesa_info_buffer, %di
|
||||||
pushl %ebp; int $0x10; popl %ebp # BOCHS doesn't seem to reserve ebp
|
int $0x10
|
||||||
cmpb $0x4F, %al; jne .vesa_unsupported
|
cmpb $0x4F, %al; jne .vesa_unsupported
|
||||||
cmpb $0x00, %ah; jne .vesa_error
|
cmpb $0x00, %ah; jne .vesa_error
|
||||||
|
|
||||||
|
@ -95,7 +38,8 @@ vesa_find_video_mode:
|
||||||
cmpw $0x0200, (vesa_info_buffer + 0x04)
|
cmpw $0x0200, (vesa_info_buffer + 0x04)
|
||||||
jb .vesa_unsupported_version
|
jb .vesa_unsupported_version
|
||||||
|
|
||||||
movl (vesa_info_buffer + 0x0E), %esi
|
movl $(vesa_info_buffer + 0x0E), %esi
|
||||||
|
movl (%esi), %esi
|
||||||
.vesa_find_video_mode_loop_modes:
|
.vesa_find_video_mode_loop_modes:
|
||||||
cmpw $0xFFFF, (%esi)
|
cmpw $0xFFFF, (%esi)
|
||||||
je .vesa_find_video_mode_loop_modes_done
|
je .vesa_find_video_mode_loop_modes_done
|
||||||
|
@ -104,7 +48,7 @@ vesa_find_video_mode:
|
||||||
movw $0x4F01, %ax
|
movw $0x4F01, %ax
|
||||||
movw (%esi), %cx
|
movw (%esi), %cx
|
||||||
movw $vesa_mode_info_buffer, %di
|
movw $vesa_mode_info_buffer, %di
|
||||||
pushl %ebp; int $0x10; popl %ebp # BOCHS doesn't seem to reserve ebp
|
int $0x10
|
||||||
cmpb $0x4F, %al; jne .vesa_unsupported
|
cmpb $0x4F, %al; jne .vesa_unsupported
|
||||||
cmpb $0x00, %ah; jne .vesa_error
|
cmpb $0x00, %ah; jne .vesa_error
|
||||||
|
|
||||||
|
@ -113,24 +57,21 @@ vesa_find_video_mode:
|
||||||
jz .vesa_find_video_mode_next_mode
|
jz .vesa_find_video_mode_next_mode
|
||||||
|
|
||||||
# compare mode's dimensions
|
# compare mode's dimensions
|
||||||
movw -2(%ebp), %ax; cmpw %ax, (vesa_mode_info_buffer + 0x12)
|
cmpw $TARGET_WIDTH, (vesa_mode_info_buffer + 0x12)
|
||||||
jne .vesa_find_video_mode_next_mode
|
jne .vesa_find_video_mode_next_mode
|
||||||
movw -4(%ebp), %ax; cmpw %ax, (vesa_mode_info_buffer + 0x14)
|
cmpw $TARGET_HEIGHT, (vesa_mode_info_buffer + 0x14)
|
||||||
jne .vesa_find_video_mode_next_mode
|
jne .vesa_find_video_mode_next_mode
|
||||||
movb -6(%ebp), %al; cmpb %al, (vesa_mode_info_buffer + 0x19)
|
cmpb $TARGET_BPP, (vesa_mode_info_buffer + 0x19)
|
||||||
jne .vesa_find_video_mode_next_mode
|
jne .vesa_find_video_mode_next_mode
|
||||||
|
|
||||||
# set address, pitch, type
|
|
||||||
movl (vesa_mode_info_buffer + 0x28), %esi
|
movl (vesa_mode_info_buffer + 0x28), %esi
|
||||||
movl %esi, (framebuffer + 0)
|
movl %esi, (framebuffer + 0)
|
||||||
movw (vesa_mode_info_buffer + 0x10), %ax
|
movw (vesa_mode_info_buffer + 0x10), %ax
|
||||||
movw %ax, (framebuffer + 4)
|
movw %ax, (framebuffer + 4)
|
||||||
movb $1, (framebuffer + 17)
|
movl $TARGET_WIDTH, (framebuffer + 8)
|
||||||
|
movl $TARGET_HEIGHT, (framebuffer + 12)
|
||||||
# set width, height, bpp
|
movb $TARGET_BPP, (framebuffer + 16)
|
||||||
movw -2(%ebp), %ax; movw %ax, (framebuffer + 8)
|
movb $1, (framebuffer + 17)
|
||||||
movw -4(%ebp), %ax; movw %ax, (framebuffer + 12)
|
|
||||||
movw -6(%ebp), %ax; movb %al, (framebuffer + 16)
|
|
||||||
|
|
||||||
movw %cx, (vesa_target_mode)
|
movw %cx, (vesa_target_mode)
|
||||||
jmp .vesa_find_video_mode_loop_modes_done
|
jmp .vesa_find_video_mode_loop_modes_done
|
||||||
|
@ -140,8 +81,10 @@ vesa_find_video_mode:
|
||||||
jmp .vesa_find_video_mode_loop_modes
|
jmp .vesa_find_video_mode_loop_modes
|
||||||
|
|
||||||
.vesa_find_video_mode_loop_modes_done:
|
.vesa_find_video_mode_loop_modes_done:
|
||||||
leavel
|
popl %esi
|
||||||
popal
|
popw %di
|
||||||
|
popw %cx
|
||||||
|
popw %ax
|
||||||
ret
|
ret
|
||||||
|
|
||||||
.vesa_unsupported:
|
.vesa_unsupported:
|
||||||
|
@ -155,37 +98,33 @@ vesa_find_video_mode:
|
||||||
jmp print_and_halt
|
jmp print_and_halt
|
||||||
|
|
||||||
|
|
||||||
# scan for video mode in kernel memory and set the correct one.
|
# set mode found from vesa_find_video_mode. if no mode
|
||||||
# when video mode is not found or does not exists,
|
# was found, set it to 80x25 text mode to clear the screen.
|
||||||
# set it to 80x25 text mode to clear the screen.
|
.global vesa_set_target_mode
|
||||||
.global vesa_set_video_mode
|
vesa_set_target_mode:
|
||||||
vesa_set_video_mode:
|
|
||||||
pushw %ax
|
pushw %ax
|
||||||
pushw %bx
|
pushw %bx
|
||||||
|
|
||||||
call vesa_find_video_mode
|
|
||||||
|
|
||||||
movw (vesa_target_mode), %bx
|
movw (vesa_target_mode), %bx
|
||||||
testw %bx, %bx
|
testw %bx, %bx
|
||||||
jz .vesa_set_target_mode_generic
|
jz .vesa_set_target_mode_generic
|
||||||
|
|
||||||
movw $0x4F02, %ax
|
movw $0x4F02, %ax
|
||||||
orw $0x4000, %bx
|
orw $0x4000, %bx
|
||||||
pushl %ebp; int $0x10; popl %ebp # BOCHS doesn't seem to reserve ebp
|
int $0x10
|
||||||
|
|
||||||
jmp .set_video_done
|
jmp .set_video_done
|
||||||
|
|
||||||
.vesa_set_target_mode_generic:
|
.vesa_set_target_mode_generic:
|
||||||
movb $0x03, %al
|
movb $0x03, %al
|
||||||
movb $0x00, %ah
|
movb $0x00, %ah
|
||||||
pushl %ebp; int $0x10; popl %ebp # BOCHS doesn't seem to reserve ebp
|
int $0x10
|
||||||
|
|
||||||
.set_video_done:
|
.set_video_done:
|
||||||
popw %bx
|
popw %bx
|
||||||
popw %ax
|
popw %ax
|
||||||
ret
|
ret
|
||||||
|
|
||||||
.section .data
|
|
||||||
|
|
||||||
vesa_error_msg:
|
vesa_error_msg:
|
||||||
.asciz "VESA error"
|
.asciz "VESA error"
|
||||||
|
@ -208,7 +147,6 @@ vesa_target_mode:
|
||||||
.skip 2
|
.skip 2
|
||||||
|
|
||||||
.global framebuffer
|
.global framebuffer
|
||||||
.align 8
|
|
||||||
framebuffer:
|
framebuffer:
|
||||||
.skip 4 # address
|
.skip 4 # address
|
||||||
.skip 4 # pitch
|
.skip 4 # pitch
|
||||||
|
|
|
@ -8,10 +8,8 @@ SECTIONS
|
||||||
. = ALIGN(512);
|
. = ALIGN(512);
|
||||||
stage2_start = .;
|
stage2_start = .;
|
||||||
.stage2 : { *(.stage2) }
|
.stage2 : { *(.stage2) }
|
||||||
. = ALIGN(512);
|
|
||||||
.data : { *(.data) }
|
|
||||||
stage2_end = .;
|
stage2_end = .;
|
||||||
|
|
||||||
. = ALIGN(512);
|
. = ALIGN(512);
|
||||||
.bss : { *(.bss) }
|
.bss : { *(.bss) }
|
||||||
}
|
}
|
|
@ -114,7 +114,6 @@ print_memory_map:
|
||||||
|
|
||||||
ret
|
ret
|
||||||
|
|
||||||
.section .data
|
|
||||||
|
|
||||||
memory_map_msg:
|
memory_map_msg:
|
||||||
.asciz "memmap:"
|
.asciz "memmap:"
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
.include "common.S"
|
|
||||||
|
|
||||||
.set SCREEN_WIDTH, 80
|
.set SCREEN_WIDTH, 80
|
||||||
.set SCREEN_HEIGHT, 25
|
.set SCREEN_HEIGHT, 25
|
||||||
|
|
||||||
|
@ -275,127 +273,6 @@ isprint:
|
||||||
movb $0, %al
|
movb $0, %al
|
||||||
ret
|
ret
|
||||||
|
|
||||||
|
|
||||||
# memset with 32 bit registers
|
|
||||||
# edi: destination address
|
|
||||||
# ecx: bytes count
|
|
||||||
# al: value to set
|
|
||||||
# return:
|
|
||||||
# edi: destination address + bytes count
|
|
||||||
# ecx: 0
|
|
||||||
# other: preserved
|
|
||||||
.global memset32
|
|
||||||
memset32:
|
|
||||||
testl %ecx, %ecx
|
|
||||||
jz .memset32_done
|
|
||||||
|
|
||||||
pushf; cli
|
|
||||||
pushw %es
|
|
||||||
pushl %eax
|
|
||||||
pushl %ebx
|
|
||||||
pushl %edx
|
|
||||||
|
|
||||||
movl %cr0, %ebx
|
|
||||||
orb $1, %bl
|
|
||||||
movl %ebx, %cr0
|
|
||||||
|
|
||||||
ljmpl $GDT_CODE32, $.memset32_pmode32
|
|
||||||
|
|
||||||
.code32
|
|
||||||
.memset32_pmode32:
|
|
||||||
movw $GDT_DATA32, %dx
|
|
||||||
movw %dx, %es
|
|
||||||
|
|
||||||
movl %ecx, %edx
|
|
||||||
|
|
||||||
andl $3, %ecx
|
|
||||||
rep stosb %es:(%edi)
|
|
||||||
|
|
||||||
movl %edx, %ecx
|
|
||||||
shrl $2, %ecx
|
|
||||||
|
|
||||||
movb %al, %ah
|
|
||||||
movw %ax, %dx
|
|
||||||
shll $16, %eax
|
|
||||||
movw %dx, %ax
|
|
||||||
rep stosl %es:(%edi)
|
|
||||||
|
|
||||||
ljmpl $GDT_CODE16, $.memset32_pmode16
|
|
||||||
|
|
||||||
.code16
|
|
||||||
.memset32_pmode16:
|
|
||||||
andb $0xFE, %bl
|
|
||||||
movl %ebx, %cr0
|
|
||||||
ljmpl $0x00, $.memset32_rmode16
|
|
||||||
|
|
||||||
.memset32_rmode16:
|
|
||||||
popl %edx
|
|
||||||
popl %ebx
|
|
||||||
popl %eax
|
|
||||||
popw %es
|
|
||||||
popf
|
|
||||||
|
|
||||||
.memset32_done:
|
|
||||||
ret
|
|
||||||
|
|
||||||
# memcpy with 32 bit registers
|
|
||||||
# esi: source address
|
|
||||||
# edi: destination address
|
|
||||||
# ecx: bytes count
|
|
||||||
# return:
|
|
||||||
# esi: source address + bytes count
|
|
||||||
# edi: destination address + bytes count
|
|
||||||
# ecx: 0
|
|
||||||
# other: preserved
|
|
||||||
.global memcpy32
|
|
||||||
memcpy32:
|
|
||||||
testl %ecx, %ecx
|
|
||||||
jz .memcpy32_done
|
|
||||||
|
|
||||||
pushf; cli
|
|
||||||
pushw %ds
|
|
||||||
pushw %es
|
|
||||||
pushl %ebx
|
|
||||||
pushl %edx
|
|
||||||
|
|
||||||
movl %cr0, %ebx
|
|
||||||
orb $1, %bl
|
|
||||||
movl %ebx, %cr0
|
|
||||||
|
|
||||||
ljmpl $GDT_CODE32, $.memcpy32_pmode32
|
|
||||||
|
|
||||||
.code32
|
|
||||||
.memcpy32_pmode32:
|
|
||||||
movw $GDT_DATA32, %dx
|
|
||||||
movw %dx, %ds
|
|
||||||
movw %dx, %es
|
|
||||||
|
|
||||||
movl %ecx, %edx
|
|
||||||
andl $3, %ecx
|
|
||||||
rep movsb %ds:(%esi), %es:(%edi)
|
|
||||||
|
|
||||||
movl %edx, %ecx
|
|
||||||
shrl $2, %ecx
|
|
||||||
rep movsl %ds:(%esi), %es:(%edi)
|
|
||||||
|
|
||||||
ljmpl $GDT_CODE16, $.memcpy32_pmode16
|
|
||||||
|
|
||||||
.code16
|
|
||||||
.memcpy32_pmode16:
|
|
||||||
andb $0xFE, %bl
|
|
||||||
movl %ebx, %cr0
|
|
||||||
ljmpl $0x00, $.memcpy32_rmode16
|
|
||||||
|
|
||||||
.memcpy32_rmode16:
|
|
||||||
popl %edx
|
|
||||||
popl %ebx
|
|
||||||
popw %es
|
|
||||||
popw %ds
|
|
||||||
popf
|
|
||||||
|
|
||||||
.memcpy32_done:
|
|
||||||
ret
|
|
||||||
|
|
||||||
.section .bss
|
.section .bss
|
||||||
|
|
||||||
# enough for base 2 printing
|
# enough for base 2 printing
|
||||||
|
|
|
@ -1,11 +1,6 @@
|
||||||
cmake_minimum_required(VERSION 3.26)
|
cmake_minimum_required(VERSION 3.26)
|
||||||
|
|
||||||
if (NOT DEFINED ENV{BANAN_ARCH})
|
project(x86_64-banan_os-bootloader-installer CXX)
|
||||||
message(FATAL_ERROR "environment variable BANAN_ARCH not defined")
|
|
||||||
endif ()
|
|
||||||
set(BANAN_ARCH $ENV{BANAN_ARCH})
|
|
||||||
|
|
||||||
project(banan_os-bootloader-installer CXX)
|
|
||||||
|
|
||||||
set(SOURCES
|
set(SOURCES
|
||||||
crc32.cpp
|
crc32.cpp
|
||||||
|
@ -15,8 +10,8 @@ set(SOURCES
|
||||||
main.cpp
|
main.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
add_executable(banan_os-bootloader-installer ${SOURCES})
|
add_executable(x86_64-banan_os-bootloader-installer ${SOURCES})
|
||||||
target_compile_options(banan_os-bootloader-installer PRIVATE -O2 -std=c++20)
|
target_compile_options(x86_64-banan_os-bootloader-installer PRIVATE -O2 -std=c++20)
|
||||||
target_compile_definitions(banan_os-bootloader-installer PRIVATE __arch=${BANAN_ARCH})
|
target_compile_definitions(x86_64-banan_os-bootloader-installer PRIVATE __arch=x86_64)
|
||||||
target_include_directories(banan_os-bootloader-installer PRIVATE ${CMAKE_SOURCE_DIR}/../../userspace/libraries/LibELF/include)
|
target_include_directories(x86_64-banan_os-bootloader-installer PRIVATE ${CMAKE_SOURCE_DIR}/../../LibELF/include)
|
||||||
target_include_directories(banan_os-bootloader-installer PRIVATE ${CMAKE_SOURCE_DIR}/../../kernel/include)
|
target_include_directories(x86_64-banan_os-bootloader-installer PRIVATE ${CMAKE_SOURCE_DIR}/../../kernel/include)
|
||||||
|
|
|
@ -81,7 +81,7 @@ bool ELFFile::validate_elf_header() const
|
||||||
|
|
||||||
#if ARCH(x86_64)
|
#if ARCH(x86_64)
|
||||||
if (elf_header.e_ident[EI_CLASS] != ELFCLASS64)
|
if (elf_header.e_ident[EI_CLASS] != ELFCLASS64)
|
||||||
#elif ARCH(i686)
|
#elif ARCH(i386)
|
||||||
if (elf_header.e_ident[EI_CLASS] != ELFCLASS32)
|
if (elf_header.e_ident[EI_CLASS] != ELFCLASS32)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
|
|
|
@ -99,33 +99,33 @@ bool GPTFile::install_stage1(std::span<const uint8_t> stage1)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GPTFile::install_stage2(std::span<const uint8_t> stage2, std::span<const uint8_t> data, const GUID& root_partition_guid)
|
bool GPTFile::install_stage2(std::span<const uint8_t> stage2, const GUID& root_partition_guid)
|
||||||
{
|
{
|
||||||
if (data.size() < 16)
|
if (stage2.size() < 16)
|
||||||
{
|
{
|
||||||
std::cerr << m_path << ": contains invalid .data section, too small for patches" << std::endl;
|
std::cerr << m_path << ": contains invalid .stage2 section, too small for patches" << std::endl;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// find GUID patch offsets
|
// find GUID patch offsets
|
||||||
std::size_t disk_guid_offset(-1);
|
std::size_t disk_guid_offset(-1);
|
||||||
std::size_t part_guid_offset(-1);
|
std::size_t part_guid_offset(-1);
|
||||||
for (std::size_t i = 0; i < data.size() - 16; i++)
|
for (std::size_t i = 0; i < stage2.size() - 16; i++)
|
||||||
{
|
{
|
||||||
if (memcmp(data.data() + i, "root disk guid ", 16) == 0)
|
if (memcmp(stage2.data() + i, "root disk guid ", 16) == 0)
|
||||||
{
|
{
|
||||||
if (disk_guid_offset != std::size_t(-1))
|
if (disk_guid_offset != std::size_t(-1))
|
||||||
{
|
{
|
||||||
std::cerr << m_path << ": contains invalid .data section, multiple patchable disk guids" << std::endl;
|
std::cerr << m_path << ": contains invalid .stage2 section, multiple patchable disk guids" << std::endl;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
disk_guid_offset = i;
|
disk_guid_offset = i;
|
||||||
}
|
}
|
||||||
if (memcmp(data.data() + i, "root part guid ", 16) == 0)
|
if (memcmp(stage2.data() + i, "root part guid ", 16) == 0)
|
||||||
{
|
{
|
||||||
if (part_guid_offset != std::size_t(-1))
|
if (part_guid_offset != std::size_t(-1))
|
||||||
{
|
{
|
||||||
std::cerr << m_path << ": contains invalid .data section, multiple patchable partition guids" << std::endl;
|
std::cerr << m_path << ": contains invalid .stage2 section, multiple patchable partition guids" << std::endl;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
part_guid_offset = i;
|
part_guid_offset = i;
|
||||||
|
@ -133,14 +133,15 @@ bool GPTFile::install_stage2(std::span<const uint8_t> stage2, std::span<const ui
|
||||||
}
|
}
|
||||||
if (disk_guid_offset == std::size_t(-1))
|
if (disk_guid_offset == std::size_t(-1))
|
||||||
{
|
{
|
||||||
std::cerr << m_path << ": contains invalid .data section, no patchable disk guid" << std::endl;
|
std::cerr << m_path << ": contains invalid .stage2 section, no patchable disk guid" << std::endl;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (part_guid_offset == std::size_t(-1))
|
if (part_guid_offset == std::size_t(-1))
|
||||||
{
|
{
|
||||||
std::cerr << m_path << ": contains invalid .data section, no patchable partition guid" << std::endl;
|
std::cerr << m_path << ": contains invalid .stage2 section, no patchable partition guid" << std::endl;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
auto partition = find_partition_with_type(bios_boot_guid);
|
auto partition = find_partition_with_type(bios_boot_guid);
|
||||||
if (!partition.has_value())
|
if (!partition.has_value())
|
||||||
|
@ -151,28 +152,23 @@ bool GPTFile::install_stage2(std::span<const uint8_t> stage2, std::span<const ui
|
||||||
|
|
||||||
const std::size_t partition_size = (partition->ending_lba - partition->starting_lba + 1) * SECTOR_SIZE;
|
const std::size_t partition_size = (partition->ending_lba - partition->starting_lba + 1) * SECTOR_SIZE;
|
||||||
|
|
||||||
std::size_t data_offset = stage2.size();
|
if (stage2.size() > partition_size)
|
||||||
if (std::size_t rem = data_offset % 512)
|
|
||||||
data_offset += 512 - rem;
|
|
||||||
|
|
||||||
if (data_offset + data.size() > partition_size)
|
|
||||||
{
|
{
|
||||||
std::cerr << m_path << ": can't fit " << stage2.size() + data.size() << " bytes of data to partition of size " << partition_size << std::endl;
|
std::cerr << m_path << ": can't fit " << stage2.size() << " bytes of data to partition of size " << partition_size << std::endl;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t* partition_start = m_mmap + partition->starting_lba * SECTOR_SIZE;
|
uint8_t* partition_start = m_mmap + partition->starting_lba * SECTOR_SIZE;
|
||||||
memcpy(partition_start, stage2.data(), stage2.size());
|
memcpy(partition_start, stage2.data(), stage2.size());
|
||||||
memcpy(partition_start + data_offset, data.data(), data.size());
|
|
||||||
|
|
||||||
// patch GUIDs
|
// patch GUIDs
|
||||||
*reinterpret_cast<GUID*>(partition_start + data_offset + disk_guid_offset) = gpt_header().disk_guid;
|
*reinterpret_cast<GUID*>(partition_start + disk_guid_offset) = gpt_header().disk_guid;
|
||||||
*reinterpret_cast<GUID*>(partition_start + data_offset + part_guid_offset) = root_partition_guid;
|
*reinterpret_cast<GUID*>(partition_start + part_guid_offset) = root_partition_guid;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GPTFile::install_bootloader(std::span<const uint8_t> stage1, std::span<const uint8_t> stage2, std::span<const uint8_t> data, const GUID& root_partition_guid)
|
bool GPTFile::install_bootloader(std::span<const uint8_t> stage1, std::span<const uint8_t> stage2, const GUID& root_partition_guid)
|
||||||
{
|
{
|
||||||
if (!find_partition_with_guid(root_partition_guid).has_value())
|
if (!find_partition_with_guid(root_partition_guid).has_value())
|
||||||
{
|
{
|
||||||
|
@ -181,7 +177,7 @@ bool GPTFile::install_bootloader(std::span<const uint8_t> stage1, std::span<cons
|
||||||
}
|
}
|
||||||
if (!install_stage1(stage1))
|
if (!install_stage1(stage1))
|
||||||
return false;
|
return false;
|
||||||
if (!install_stage2(stage2, data, root_partition_guid))
|
if (!install_stage2(stage2, root_partition_guid))
|
||||||
return false;
|
return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -65,7 +65,7 @@ public:
|
||||||
GPTFile(std::string_view path);
|
GPTFile(std::string_view path);
|
||||||
~GPTFile();
|
~GPTFile();
|
||||||
|
|
||||||
bool install_bootloader(std::span<const uint8_t> stage1, std::span<const uint8_t> stage2, std::span<const uint8_t> data, const GUID& root_partition_guid);
|
bool install_bootloader(std::span<const uint8_t> stage1, std::span<const uint8_t> stage2, const GUID& root_partition_guid);
|
||||||
|
|
||||||
const GPTHeader& gpt_header() const;
|
const GPTHeader& gpt_header() const;
|
||||||
|
|
||||||
|
@ -80,7 +80,7 @@ private:
|
||||||
std::optional<GPTPartitionEntry> find_partition_with_type(const GUID& type_guid) const;
|
std::optional<GPTPartitionEntry> find_partition_with_type(const GUID& type_guid) const;
|
||||||
|
|
||||||
bool install_stage1(std::span<const uint8_t> stage1);
|
bool install_stage1(std::span<const uint8_t> stage1);
|
||||||
bool install_stage2(std::span<const uint8_t> stage2, std::span<const uint8_t> data, const GUID& root_partition_guid);
|
bool install_stage2(std::span<const uint8_t> stage2, const GUID& root_partition_guid);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const std::string m_path;
|
const std::string m_path;
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
g++ -O2 -std=c++20 main.cpp crc32.cpp ELF.cpp GPT.cpp GUID.cpp -o install-bootloader
|
|
@ -26,10 +26,9 @@ int main(int argc, char** argv)
|
||||||
|
|
||||||
auto stage1 = bootloader.find_section(".stage1"sv);
|
auto stage1 = bootloader.find_section(".stage1"sv);
|
||||||
auto stage2 = bootloader.find_section(".stage2"sv);
|
auto stage2 = bootloader.find_section(".stage2"sv);
|
||||||
auto data = bootloader.find_section(".data"sv);
|
if (!stage1.has_value() || !stage2.has_value())
|
||||||
if (!stage1.has_value() || !stage2.has_value() || !data.has_value())
|
|
||||||
{
|
{
|
||||||
std::cerr << bootloader.path() << " doesn't contain .stage1, .stage2 and .data sections" << std::endl;
|
std::cerr << bootloader.path() << " doesn't contain .stage1 and .stage2 sections" << std::endl;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,9 +36,9 @@ int main(int argc, char** argv)
|
||||||
if (!disk_image.success())
|
if (!disk_image.success())
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
if (!disk_image.install_bootloader(*stage1, *stage2, *data, *root_partition_guid))
|
if (!disk_image.install_bootloader(*stage1, *stage2, *root_partition_guid))
|
||||||
return 1;
|
return 1;
|
||||||
std::cout << "bootloader installed" << std::endl;
|
std::cout << "bootloader installed" << std::endl;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
|
@ -1,35 +1,28 @@
|
||||||
|
cmake_minimum_required(VERSION 3.26)
|
||||||
|
|
||||||
|
project(kernel CXX C ASM)
|
||||||
|
|
||||||
|
if("${BANAN_ARCH}" STREQUAL "x86_64")
|
||||||
|
set(ELF_FORMAT elf64-x86-64)
|
||||||
|
elseif("${BANAN_ARCH}" STREQUAL "i386")
|
||||||
|
set(ELF_FORMAT elf32-i386)
|
||||||
|
endif()
|
||||||
|
|
||||||
set(KERNEL_SOURCES
|
set(KERNEL_SOURCES
|
||||||
font/prefs.psf.o
|
font/prefs.psf.o
|
||||||
kernel/ACPI/ACPI.cpp
|
kernel/ACPI.cpp
|
||||||
kernel/ACPI/AML.cpp
|
|
||||||
kernel/ACPI/AML/Field.cpp
|
|
||||||
kernel/ACPI/AML/Integer.cpp
|
|
||||||
kernel/ACPI/AML/NamedObject.cpp
|
|
||||||
kernel/ACPI/AML/Namespace.cpp
|
|
||||||
kernel/ACPI/AML/Node.cpp
|
|
||||||
kernel/ACPI/AML/Package.cpp
|
|
||||||
kernel/ACPI/AML/Register.cpp
|
|
||||||
kernel/ACPI/AML/Scope.cpp
|
|
||||||
kernel/ACPI/AML/String.cpp
|
|
||||||
kernel/APIC.cpp
|
kernel/APIC.cpp
|
||||||
kernel/BootInfo.cpp
|
kernel/BootInfo.cpp
|
||||||
kernel/CPUID.cpp
|
kernel/CPUID.cpp
|
||||||
kernel/Credentials.cpp
|
|
||||||
kernel/Debug.cpp
|
kernel/Debug.cpp
|
||||||
kernel/Device/DebugDevice.cpp
|
|
||||||
kernel/Device/Device.cpp
|
kernel/Device/Device.cpp
|
||||||
kernel/Device/FramebufferDevice.cpp
|
|
||||||
kernel/Device/NullDevice.cpp
|
kernel/Device/NullDevice.cpp
|
||||||
kernel/Device/RandomDevice.cpp
|
|
||||||
kernel/Device/ZeroDevice.cpp
|
kernel/Device/ZeroDevice.cpp
|
||||||
kernel/ELF.cpp
|
|
||||||
kernel/Errors.cpp
|
kernel/Errors.cpp
|
||||||
|
kernel/Font.cpp
|
||||||
kernel/FS/DevFS/FileSystem.cpp
|
kernel/FS/DevFS/FileSystem.cpp
|
||||||
kernel/FS/Ext2/FileSystem.cpp
|
kernel/FS/Ext2/FileSystem.cpp
|
||||||
kernel/FS/Ext2/Inode.cpp
|
kernel/FS/Ext2/Inode.cpp
|
||||||
kernel/FS/FAT/FileSystem.cpp
|
|
||||||
kernel/FS/FAT/Inode.cpp
|
|
||||||
kernel/FS/FileSystem.cpp
|
|
||||||
kernel/FS/Inode.cpp
|
kernel/FS/Inode.cpp
|
||||||
kernel/FS/Pipe.cpp
|
kernel/FS/Pipe.cpp
|
||||||
kernel/FS/ProcFS/FileSystem.cpp
|
kernel/FS/ProcFS/FileSystem.cpp
|
||||||
|
@ -37,15 +30,9 @@ set(KERNEL_SOURCES
|
||||||
kernel/FS/TmpFS/FileSystem.cpp
|
kernel/FS/TmpFS/FileSystem.cpp
|
||||||
kernel/FS/TmpFS/Inode.cpp
|
kernel/FS/TmpFS/Inode.cpp
|
||||||
kernel/FS/VirtualFileSystem.cpp
|
kernel/FS/VirtualFileSystem.cpp
|
||||||
kernel/GDT.cpp
|
kernel/Input/PS2Controller.cpp
|
||||||
kernel/IDT.cpp
|
kernel/Input/PS2Keyboard.cpp
|
||||||
kernel/Input/InputDevice.cpp
|
kernel/Input/PS2Keymap.cpp
|
||||||
kernel/Input/PS2/Controller.cpp
|
|
||||||
kernel/Input/PS2/Device.cpp
|
|
||||||
kernel/Input/PS2/Keyboard.cpp
|
|
||||||
kernel/Input/PS2/Keymap.cpp
|
|
||||||
kernel/Input/PS2/Mouse.cpp
|
|
||||||
kernel/Interruptable.cpp
|
|
||||||
kernel/InterruptController.cpp
|
kernel/InterruptController.cpp
|
||||||
kernel/kernel.cpp
|
kernel/kernel.cpp
|
||||||
kernel/Memory/DMARegion.cpp
|
kernel/Memory/DMARegion.cpp
|
||||||
|
@ -55,29 +42,16 @@ set(KERNEL_SOURCES
|
||||||
kernel/Memory/MemoryBackedRegion.cpp
|
kernel/Memory/MemoryBackedRegion.cpp
|
||||||
kernel/Memory/MemoryRegion.cpp
|
kernel/Memory/MemoryRegion.cpp
|
||||||
kernel/Memory/PhysicalRange.cpp
|
kernel/Memory/PhysicalRange.cpp
|
||||||
kernel/Memory/SharedMemoryObject.cpp
|
|
||||||
kernel/Memory/VirtualRange.cpp
|
kernel/Memory/VirtualRange.cpp
|
||||||
kernel/Networking/ARPTable.cpp
|
kernel/Networking/E1000.cpp
|
||||||
kernel/Networking/E1000/E1000.cpp
|
|
||||||
kernel/Networking/E1000/E1000E.cpp
|
|
||||||
kernel/Networking/IPv4Layer.cpp
|
|
||||||
kernel/Networking/NetworkInterface.cpp
|
|
||||||
kernel/Networking/NetworkLayer.cpp
|
|
||||||
kernel/Networking/NetworkManager.cpp
|
|
||||||
kernel/Networking/NetworkSocket.cpp
|
|
||||||
kernel/Networking/RTL8169/RTL8169.cpp
|
|
||||||
kernel/Networking/TCPSocket.cpp
|
|
||||||
kernel/Networking/UDPSocket.cpp
|
|
||||||
kernel/Networking/UNIX/Socket.cpp
|
|
||||||
kernel/OpenFileDescriptorSet.cpp
|
kernel/OpenFileDescriptorSet.cpp
|
||||||
kernel/Panic.cpp
|
kernel/Panic.cpp
|
||||||
kernel/PCI.cpp
|
kernel/PCI.cpp
|
||||||
kernel/PIC.cpp
|
kernel/PIC.cpp
|
||||||
kernel/Process.cpp
|
kernel/Process.cpp
|
||||||
kernel/Processor.cpp
|
|
||||||
kernel/Random.cpp
|
|
||||||
kernel/Scheduler.cpp
|
kernel/Scheduler.cpp
|
||||||
kernel/ThreadBlocker.cpp
|
kernel/Semaphore.cpp
|
||||||
|
kernel/SpinLock.cpp
|
||||||
kernel/SSP.cpp
|
kernel/SSP.cpp
|
||||||
kernel/Storage/ATA/AHCI/Controller.cpp
|
kernel/Storage/ATA/AHCI/Controller.cpp
|
||||||
kernel/Storage/ATA/AHCI/Device.cpp
|
kernel/Storage/ATA/AHCI/Device.cpp
|
||||||
|
@ -85,36 +59,22 @@ set(KERNEL_SOURCES
|
||||||
kernel/Storage/ATA/ATAController.cpp
|
kernel/Storage/ATA/ATAController.cpp
|
||||||
kernel/Storage/ATA/ATADevice.cpp
|
kernel/Storage/ATA/ATADevice.cpp
|
||||||
kernel/Storage/DiskCache.cpp
|
kernel/Storage/DiskCache.cpp
|
||||||
kernel/Storage/NVMe/Controller.cpp
|
|
||||||
kernel/Storage/NVMe/Namespace.cpp
|
|
||||||
kernel/Storage/NVMe/Queue.cpp
|
|
||||||
kernel/Storage/Partition.cpp
|
|
||||||
kernel/Storage/SCSI.cpp
|
|
||||||
kernel/Storage/StorageDevice.cpp
|
kernel/Storage/StorageDevice.cpp
|
||||||
kernel/Syscall.cpp
|
kernel/Syscall.cpp
|
||||||
kernel/Terminal/FramebufferTerminal.cpp
|
kernel/Syscall.S
|
||||||
kernel/Terminal/PseudoTerminal.cpp
|
|
||||||
kernel/Terminal/Serial.cpp
|
kernel/Terminal/Serial.cpp
|
||||||
kernel/Terminal/TTY.cpp
|
kernel/Terminal/TTY.cpp
|
||||||
|
kernel/Terminal/VesaTerminalDriver.cpp
|
||||||
kernel/Terminal/VirtualTTY.cpp
|
kernel/Terminal/VirtualTTY.cpp
|
||||||
kernel/Thread.cpp
|
kernel/Thread.cpp
|
||||||
kernel/Timer/HPET.cpp
|
kernel/Timer/HPET.cpp
|
||||||
kernel/Timer/PIT.cpp
|
kernel/Timer/PIT.cpp
|
||||||
kernel/Timer/RTC.cpp
|
kernel/Timer/RTC.cpp
|
||||||
kernel/Timer/Timer.cpp
|
kernel/Timer/Timer.cpp
|
||||||
kernel/USB/Device.cpp
|
|
||||||
kernel/USB/HID/HIDDriver.cpp
|
|
||||||
kernel/USB/HID/Keyboard.cpp
|
|
||||||
kernel/USB/HID/Mouse.cpp
|
|
||||||
kernel/USB/MassStorage/MassStorageDriver.cpp
|
|
||||||
kernel/USB/MassStorage/SCSIDevice.cpp
|
|
||||||
kernel/USB/USBManager.cpp
|
|
||||||
kernel/USB/XHCI/Controller.cpp
|
|
||||||
kernel/USB/XHCI/Device.cpp
|
|
||||||
icxxabi.cpp
|
icxxabi.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
set(ENABLE_KERNEL_UBSAN False)
|
#set(ENABLE_KERNEL_UBSAN True)
|
||||||
|
|
||||||
if(ENABLE_KERNEL_UBSAN)
|
if(ENABLE_KERNEL_UBSAN)
|
||||||
set(KERNEL_SOURCES ${KERNEL_SOURCES} ubsan.cpp)
|
set(KERNEL_SOURCES ${KERNEL_SOURCES} ubsan.cpp)
|
||||||
|
@ -124,97 +84,100 @@ if("${BANAN_ARCH}" STREQUAL "x86_64")
|
||||||
set(KERNEL_SOURCES
|
set(KERNEL_SOURCES
|
||||||
${KERNEL_SOURCES}
|
${KERNEL_SOURCES}
|
||||||
arch/x86_64/boot.S
|
arch/x86_64/boot.S
|
||||||
|
arch/x86_64/GDT.cpp
|
||||||
|
arch/x86_64/IDT.cpp
|
||||||
arch/x86_64/interrupts.S
|
arch/x86_64/interrupts.S
|
||||||
arch/x86_64/PageTable.cpp
|
arch/x86_64/PageTable.cpp
|
||||||
arch/x86_64/Signal.S
|
arch/x86_64/Signal.S
|
||||||
arch/x86_64/Syscall.S
|
|
||||||
arch/x86_64/Thread.S
|
arch/x86_64/Thread.S
|
||||||
)
|
)
|
||||||
elseif("${BANAN_ARCH}" STREQUAL "i686")
|
elseif("${BANAN_ARCH}" STREQUAL "i386")
|
||||||
set(KERNEL_SOURCES
|
set(KERNEL_SOURCES
|
||||||
${KERNEL_SOURCES}
|
${KERNEL_SOURCES}
|
||||||
arch/i686/boot.S
|
arch/i386/boot.S
|
||||||
arch/i686/interrupts.S
|
arch/i386/GDT.cpp
|
||||||
arch/i686/PageTable.cpp
|
arch/i386/IDT.cpp
|
||||||
arch/i686/Signal.S
|
arch/i386/MMU.cpp
|
||||||
arch/i686/Syscall.S
|
arch/i386/SpinLock.S
|
||||||
arch/i686/Thread.S
|
arch/i386/Thread.S
|
||||||
)
|
)
|
||||||
else()
|
else()
|
||||||
message(FATAL_ERROR "unsupported architecure ${BANAN_ARCH}")
|
message(FATAL_ERROR "unsupported architecure ${BANAN_ARCH}")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
file(GLOB_RECURSE LAI_SOURCES
|
||||||
|
lai/*.c
|
||||||
|
)
|
||||||
|
set(LAI_SOURCES
|
||||||
|
${LAI_SOURCES}
|
||||||
|
kernel/lai_host.cpp
|
||||||
|
)
|
||||||
|
|
||||||
set(BAN_SOURCES
|
set(BAN_SOURCES
|
||||||
../BAN/BAN/Assert.cpp
|
|
||||||
../BAN/BAN/New.cpp
|
../BAN/BAN/New.cpp
|
||||||
|
../BAN/BAN/String.cpp
|
||||||
../BAN/BAN/StringView.cpp
|
../BAN/BAN/StringView.cpp
|
||||||
../BAN/BAN/Time.cpp
|
../BAN/BAN/Time.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
set(KLIBC_SOURCES
|
set(LIBC_SOURCES
|
||||||
klibc/ctype.cpp
|
../libc/ctype.cpp
|
||||||
klibc/string.cpp
|
../libc/string.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
set(LIBFONT_SOURCES
|
set(LIBELF_SOURCES
|
||||||
../userspace/libraries/LibFont/Font.cpp
|
../LibELF/LibELF/LoadableELF.cpp
|
||||||
../userspace/libraries/LibFont/PSF.cpp
|
|
||||||
)
|
|
||||||
|
|
||||||
set(LIBINPUT_SOURCE
|
|
||||||
../userspace/libraries/LibInput/KeyboardLayout.cpp
|
|
||||||
../userspace/libraries/LibInput/KeyEvent.cpp
|
|
||||||
)
|
)
|
||||||
|
|
||||||
set(KERNEL_SOURCES
|
set(KERNEL_SOURCES
|
||||||
${KERNEL_SOURCES}
|
${KERNEL_SOURCES}
|
||||||
|
${LAI_SOURCES}
|
||||||
${BAN_SOURCES}
|
${BAN_SOURCES}
|
||||||
${KLIBC_SOURCES}
|
${LIBC_SOURCES}
|
||||||
${LIBFONT_SOURCES}
|
${LIBELF_SOURCES}
|
||||||
${LIBINPUT_SOURCE}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
add_executable(kernel ${KERNEL_SOURCES})
|
add_executable(kernel ${KERNEL_SOURCES})
|
||||||
|
add_dependencies(kernel headers)
|
||||||
|
|
||||||
target_compile_definitions(kernel PRIVATE __is_kernel)
|
target_compile_definitions(kernel PUBLIC __is_kernel)
|
||||||
target_compile_definitions(kernel PRIVATE __arch=${BANAN_ARCH})
|
target_compile_definitions(kernel PUBLIC __arch=${BANAN_ARCH})
|
||||||
|
|
||||||
target_compile_options(kernel PRIVATE
|
target_compile_options(kernel PUBLIC -O2 -g)
|
||||||
-O2 -g
|
target_compile_options(kernel PUBLIC $<$<COMPILE_LANGUAGE:CXX>:-Wno-literal-suffix -fno-rtti -fno-exceptions>)
|
||||||
-fmacro-prefix-map=${CMAKE_CURRENT_SOURCE_DIR}=.
|
target_compile_options(kernel PUBLIC -fmacro-prefix-map=${CMAKE_CURRENT_SOURCE_DIR}=.)
|
||||||
-fstack-protector
|
target_compile_options(kernel PUBLIC -fstack-protector -ffreestanding -Wall -Werror=return-type -Wstack-usage=1024 -fno-omit-frame-pointer -mgeneral-regs-only)
|
||||||
-ffreestanding
|
|
||||||
-fno-omit-frame-pointer
|
|
||||||
-fstrict-volatile-bitfields
|
|
||||||
-mgeneral-regs-only
|
|
||||||
-Wall -Wextra -Werror -Wstack-usage=1024
|
|
||||||
)
|
|
||||||
|
|
||||||
# C++ specific
|
# This might not work with other toolchains
|
||||||
target_compile_options(kernel PRIVATE
|
target_compile_options(kernel PUBLIC $<$<COMPILE_LANGUAGE:CXX>:-Wno-invalid-offsetof>)
|
||||||
-Wno-literal-suffix
|
|
||||||
-Wno-invalid-offsetof
|
|
||||||
-fno-rtti
|
|
||||||
-fno-exceptions
|
|
||||||
)
|
|
||||||
|
|
||||||
if(ENABLE_KERNEL_UBSAN)
|
if(ENABLE_KERNEL_UBSAN)
|
||||||
target_compile_options(kernel PRIVATE -fsanitize=undefined)
|
target_compile_options(kernel PUBLIC -fsanitize=undefined)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if("${BANAN_ARCH}" STREQUAL "x86_64")
|
if("${BANAN_ARCH}" STREQUAL "x86_64")
|
||||||
target_compile_options(kernel PRIVATE -mcmodel=kernel -mno-red-zone)
|
target_compile_options(kernel PUBLIC -mcmodel=kernel -mno-red-zone -mno-mmx)
|
||||||
target_link_options(kernel PRIVATE LINKER:-z,max-page-size=4096)
|
target_link_options(kernel PUBLIC LINKER:-z,max-page-size=4096)
|
||||||
target_link_options(kernel PRIVATE LINKER:-T,${CMAKE_CURRENT_SOURCE_DIR}/arch/x86_64/linker.ld)
|
target_link_options(kernel PUBLIC LINKER:-T,${CMAKE_CURRENT_SOURCE_DIR}/arch/x86_64/linker.ld)
|
||||||
elseif("${BANAN_ARCH}" STREQUAL "i686")
|
elseif("${BANAN_ARCH}" STREQUAL "i386")
|
||||||
target_link_options(kernel PRIVATE LINKER:-T,${CMAKE_CURRENT_SOURCE_DIR}/arch/i686/linker.ld)
|
target_link_options(kernel PUBLIC LINKER:-T,${CMAKE_CURRENT_SOURCE_DIR}/arch/i386/linker.ld)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
target_link_options(kernel PRIVATE -ffreestanding -nostdlib -orphan-handling=error)
|
target_link_options(kernel PUBLIC -ffreestanding -nostdlib)
|
||||||
|
|
||||||
get_target_property(KERNEL_COMPILE_OPTIONS kernel COMPILE_OPTIONS)
|
add_custom_target(kernel-headers
|
||||||
execute_process(COMMAND ${CMAKE_CXX_COMPILER} ${KERNEL_COMPILE_OPTIONS} -print-file-name=crtbegin.o OUTPUT_VARIABLE CRTBEGIN OUTPUT_STRIP_TRAILING_WHITESPACE)
|
COMMAND ${CMAKE_COMMAND} -E copy_directory_if_different ${CMAKE_CURRENT_SOURCE_DIR}/include/ ${BANAN_INCLUDE}/
|
||||||
execute_process(COMMAND ${CMAKE_CXX_COMPILER} ${KERNEL_COMPILE_OPTIONS} -print-file-name=crtend.o OUTPUT_VARIABLE CRTEND OUTPUT_STRIP_TRAILING_WHITESPACE)
|
COMMAND ${CMAKE_COMMAND} -E copy_directory_if_different ${CMAKE_CURRENT_SOURCE_DIR}/lai/include/ ${BANAN_INCLUDE}/
|
||||||
|
DEPENDS sysroot
|
||||||
|
)
|
||||||
|
|
||||||
|
add_custom_target(kernel-install
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_BINARY_DIR}/kernel ${BANAN_BOOT}/banan-os.kernel
|
||||||
|
DEPENDS kernel
|
||||||
|
)
|
||||||
|
|
||||||
|
execute_process(COMMAND ${CMAKE_CXX_COMPILER} -print-file-name=crtbegin.o OUTPUT_VARIABLE CRTBEGIN OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||||
|
execute_process(COMMAND ${CMAKE_CXX_COMPILER} -print-file-name=crtend.o OUTPUT_VARIABLE CRTEND OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||||
|
|
||||||
add_custom_command(
|
add_custom_command(
|
||||||
TARGET kernel PRE_LINK
|
TARGET kernel PRE_LINK
|
||||||
|
@ -229,22 +192,6 @@ add_custom_command(
|
||||||
# COMMAND x86_64-banan_os-strip ${CMAKE_CURRENT_BINARY_DIR}/kernel
|
# COMMAND x86_64-banan_os-strip ${CMAKE_CURRENT_BINARY_DIR}/kernel
|
||||||
#)
|
#)
|
||||||
|
|
||||||
banan_include_headers(kernel ban)
|
|
||||||
banan_include_headers(kernel libc)
|
|
||||||
banan_include_headers(kernel libfont)
|
|
||||||
banan_include_headers(kernel libelf)
|
|
||||||
banan_include_headers(kernel libinput)
|
|
||||||
|
|
||||||
banan_install_headers(kernel)
|
|
||||||
set_target_properties(kernel PROPERTIES OUTPUT_NAME banan-os.kernel)
|
|
||||||
install(TARGETS kernel DESTINATION ${BANAN_BOOT} OPTIONAL)
|
|
||||||
|
|
||||||
if("${BANAN_ARCH}" STREQUAL "x86_64")
|
|
||||||
set(ELF_FORMAT elf64-x86-64)
|
|
||||||
elseif("${BANAN_ARCH}" STREQUAL "i686")
|
|
||||||
set(ELF_FORMAT elf32-i386)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
add_custom_command(
|
add_custom_command(
|
||||||
OUTPUT font/prefs.psf.o
|
OUTPUT font/prefs.psf.o
|
||||||
COMMAND cd ${CMAKE_CURRENT_SOURCE_DIR} && objcopy -O ${ELF_FORMAT} -B i386 -I binary font/prefs.psf ${CMAKE_CURRENT_BINARY_DIR}/font/prefs.psf.o
|
COMMAND cd ${CMAKE_CURRENT_SOURCE_DIR} && objcopy -O ${ELF_FORMAT} -B i386 -I binary font/prefs.psf ${CMAKE_CURRENT_BINARY_DIR}/font/prefs.psf.o
|
||||||
|
|
|
@ -0,0 +1,147 @@
|
||||||
|
#include <BAN/Assert.h>
|
||||||
|
#include <kernel/GDT.h>
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
extern "C" uintptr_t g_boot_stack_top[0];
|
||||||
|
|
||||||
|
namespace Kernel::GDT
|
||||||
|
{
|
||||||
|
|
||||||
|
struct TaskStateSegment
|
||||||
|
{
|
||||||
|
uint16_t link;
|
||||||
|
uint16_t reserved1;
|
||||||
|
uint32_t esp0;
|
||||||
|
uint16_t ss0;
|
||||||
|
uint16_t reserved2;
|
||||||
|
uint32_t esp1;
|
||||||
|
uint16_t ss1;
|
||||||
|
uint16_t reserved3;
|
||||||
|
uint32_t esp2;
|
||||||
|
uint16_t ss2;
|
||||||
|
uint16_t reserved4;
|
||||||
|
uint32_t cr3;
|
||||||
|
uint32_t eip;
|
||||||
|
uint32_t eflags;
|
||||||
|
uint32_t eax;
|
||||||
|
uint32_t ecx;
|
||||||
|
uint32_t edx;
|
||||||
|
uint32_t ebx;
|
||||||
|
uint32_t esp;
|
||||||
|
uint32_t ebp;
|
||||||
|
uint32_t esi;
|
||||||
|
uint32_t edi;
|
||||||
|
uint16_t es;
|
||||||
|
uint16_t reserved5;
|
||||||
|
uint16_t cs;
|
||||||
|
uint16_t reserved6;
|
||||||
|
uint16_t ss;
|
||||||
|
uint16_t reserved7;
|
||||||
|
uint16_t ds;
|
||||||
|
uint16_t reserved8;
|
||||||
|
uint16_t fs;
|
||||||
|
uint16_t reserved9;
|
||||||
|
uint16_t gs;
|
||||||
|
uint16_t reserved10;
|
||||||
|
uint16_t ldtr;
|
||||||
|
uint16_t reserved11;
|
||||||
|
uint16_t reserved12;
|
||||||
|
uint16_t iopb;
|
||||||
|
uint32_t ssp;
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
union SegmentDescriptor
|
||||||
|
{
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
uint16_t limit1;
|
||||||
|
uint16_t base1;
|
||||||
|
uint8_t base2;
|
||||||
|
uint8_t access;
|
||||||
|
uint8_t limit2 : 4;
|
||||||
|
uint8_t flags : 4;
|
||||||
|
uint8_t base3;
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
uint32_t low;
|
||||||
|
uint32_t high;
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
struct GDTR
|
||||||
|
{
|
||||||
|
uint16_t size;
|
||||||
|
uint32_t address;
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
static TaskStateSegment* s_tss = nullptr;
|
||||||
|
static SegmentDescriptor* s_gdt = nullptr;
|
||||||
|
static GDTR s_gdtr;
|
||||||
|
|
||||||
|
static void write_entry(uint8_t offset, uint32_t base, uint32_t limit, uint8_t access, uint8_t flags)
|
||||||
|
{
|
||||||
|
SegmentDescriptor& desc = *(SegmentDescriptor*)((uintptr_t)s_gdt + offset);
|
||||||
|
desc.base1 = base;
|
||||||
|
desc.base2 = base >> 16;
|
||||||
|
desc.base3 = base >> 24;
|
||||||
|
|
||||||
|
desc.limit1 = limit;
|
||||||
|
desc.limit2 = limit >> 16;
|
||||||
|
|
||||||
|
desc.access = access;
|
||||||
|
|
||||||
|
desc.flags = flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void write_tss(uint8_t offset)
|
||||||
|
{
|
||||||
|
s_tss = new TaskStateSegment();
|
||||||
|
ASSERT(s_tss);
|
||||||
|
|
||||||
|
memset(s_tss, 0x00, sizeof(TaskStateSegment));
|
||||||
|
s_tss->ss0 = 0x10;
|
||||||
|
s_tss->esp0 = (uintptr_t)g_boot_stack_top;
|
||||||
|
|
||||||
|
write_entry(offset, (uint32_t)s_tss, sizeof(TaskStateSegment), 0x89, 0x0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_tss_stack(uintptr_t esp)
|
||||||
|
{
|
||||||
|
s_tss->esp0 = esp;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void flush_gdt()
|
||||||
|
{
|
||||||
|
asm volatile("lgdt %0" :: "m"(s_gdtr));
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" void flush_tss(uint16_t offset)
|
||||||
|
{
|
||||||
|
asm volatile("ltr %0" :: "m"(offset));
|
||||||
|
}
|
||||||
|
|
||||||
|
void initialize()
|
||||||
|
{
|
||||||
|
constexpr uint32_t descriptor_count = 6;
|
||||||
|
s_gdt = new SegmentDescriptor[descriptor_count];
|
||||||
|
ASSERT(s_gdt);
|
||||||
|
|
||||||
|
s_gdtr.address = (uint64_t)s_gdt;
|
||||||
|
s_gdtr.size = descriptor_count * sizeof(SegmentDescriptor) - 1;
|
||||||
|
|
||||||
|
write_entry(0x00, 0x00000000, 0x00000, 0x00, 0x0); // null
|
||||||
|
write_entry(0x08, 0x00000000, 0xFFFFF, 0x9A, 0xC); // kernel code
|
||||||
|
write_entry(0x10, 0x00000000, 0xFFFFF, 0x92, 0xC); // kernel data
|
||||||
|
write_entry(0x18, 0x00000000, 0xFFFFF, 0xFA, 0xC); // user code
|
||||||
|
write_entry(0x20, 0x00000000, 0xFFFFF, 0xF2, 0xC); // user data
|
||||||
|
write_tss(0x28);
|
||||||
|
|
||||||
|
flush_gdt();
|
||||||
|
flush_tss(0x28);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,270 @@
|
||||||
|
#include <BAN/Errors.h>
|
||||||
|
#include <kernel/IDT.h>
|
||||||
|
#include <kernel/InterruptController.h>
|
||||||
|
#include <kernel/Memory/kmalloc.h>
|
||||||
|
#include <kernel/Panic.h>
|
||||||
|
#include <kernel/Scheduler.h>
|
||||||
|
|
||||||
|
#define INTERRUPT_HANDLER____(i, msg) \
|
||||||
|
static void interrupt ## i () \
|
||||||
|
{ \
|
||||||
|
uint32_t eax, ebx, ecx, edx; \
|
||||||
|
uint32_t esp, ebp; \
|
||||||
|
uint32_t cr0, cr2, cr3, cr4; \
|
||||||
|
asm volatile("":"=a"(eax),"=b"(ebx),"=c"(ecx),"=d"(edx)); \
|
||||||
|
asm volatile("movl %%esp, %%eax":"=a"(esp)); \
|
||||||
|
asm volatile("movl %%ebp, %%eax":"=a"(ebp)); \
|
||||||
|
asm volatile("movl %%cr0, %%eax":"=a"(cr0)); \
|
||||||
|
asm volatile("movl %%cr2, %%eax":"=a"(cr2)); \
|
||||||
|
asm volatile("movl %%cr3, %%eax":"=a"(cr3)); \
|
||||||
|
asm volatile("movl %%cr4, %%eax":"=a"(cr4)); \
|
||||||
|
Kernel::panic(msg "\r\nRegister dump\r\n" \
|
||||||
|
"eax=0x{8H}, ebx=0x{8H}, ecx=0x{8H}, edx=0x{8H}\r\n" \
|
||||||
|
"esp=0x{8H}, ebp=0x{8H}\r\n" \
|
||||||
|
"CR0=0x{8H}, CR2=0x{8H}, CR3=0x{8H}, CR4=0x{8H}\r\n", \
|
||||||
|
eax, ebx, ecx, edx, esp, ebp, cr0, cr2, cr3, cr4); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define INTERRUPT_HANDLER_ERR(i, msg) \
|
||||||
|
static void interrupt ## i () \
|
||||||
|
{ \
|
||||||
|
uint32_t eax, ebx, ecx, edx; \
|
||||||
|
uint32_t esp, ebp; \
|
||||||
|
uint32_t cr0, cr2, cr3, cr4; \
|
||||||
|
uint32_t error_code; \
|
||||||
|
asm volatile("":"=a"(eax),"=b"(ebx),"=c"(ecx),"=d"(edx)); \
|
||||||
|
asm volatile("movl %%esp, %%eax":"=a"(esp)); \
|
||||||
|
asm volatile("movl %%ebp, %%eax":"=a"(ebp)); \
|
||||||
|
asm volatile("movl %%cr0, %%eax":"=a"(cr0)); \
|
||||||
|
asm volatile("movl %%cr2, %%eax":"=a"(cr2)); \
|
||||||
|
asm volatile("movl %%cr3, %%eax":"=a"(cr3)); \
|
||||||
|
asm volatile("movl %%cr4, %%eax":"=a"(cr4)); \
|
||||||
|
asm volatile("popl %%eax":"=a"(error_code)); \
|
||||||
|
Kernel::panic(msg " (error code: 0x{8H})\r\n" \
|
||||||
|
"Register dump\r\n" \
|
||||||
|
"eax=0x{8H}, ebx=0x{8H}, ecx=0x{8H}, edx=0x{8H}\r\n" \
|
||||||
|
"esp=0x{8H}, ebp=0x{8H}\r\n" \
|
||||||
|
"CR0=0x{8H}, CR2=0x{8H}, CR3=0x{8H}, CR4=0x{8H}\r\n", \
|
||||||
|
eax, ebx, ecx, edx, esp, ebp, cr0, cr2, cr3, cr4, error_code); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define REGISTER_HANDLER(i) register_interrupt_handler(i, interrupt ## i)
|
||||||
|
|
||||||
|
namespace IDT
|
||||||
|
{
|
||||||
|
|
||||||
|
struct GateDescriptor
|
||||||
|
{
|
||||||
|
uint16_t offset1;
|
||||||
|
uint16_t selector;
|
||||||
|
uint8_t reserved : 5;
|
||||||
|
uint8_t zero1 : 3;
|
||||||
|
uint8_t type : 4;
|
||||||
|
uint8_t zero2 : 1;
|
||||||
|
uint8_t DPL : 2;
|
||||||
|
uint8_t present : 1;
|
||||||
|
uint16_t offset2;
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
struct IDTR
|
||||||
|
{
|
||||||
|
uint16_t size;
|
||||||
|
void* offset;
|
||||||
|
} __attribute((packed));
|
||||||
|
|
||||||
|
static IDTR s_idtr;
|
||||||
|
static GateDescriptor* s_idt = nullptr;
|
||||||
|
|
||||||
|
static void(*s_irq_handlers[16])() { nullptr };
|
||||||
|
|
||||||
|
INTERRUPT_HANDLER____(0x00, "Division Error")
|
||||||
|
INTERRUPT_HANDLER____(0x01, "Debug")
|
||||||
|
INTERRUPT_HANDLER____(0x02, "Non-maskable Interrupt")
|
||||||
|
INTERRUPT_HANDLER____(0x03, "Breakpoint")
|
||||||
|
INTERRUPT_HANDLER____(0x04, "Overflow")
|
||||||
|
INTERRUPT_HANDLER____(0x05, "Bound Range Exception")
|
||||||
|
INTERRUPT_HANDLER____(0x06, "Invalid Opcode")
|
||||||
|
INTERRUPT_HANDLER____(0x07, "Device Not Available")
|
||||||
|
INTERRUPT_HANDLER_ERR(0x08, "Double Fault")
|
||||||
|
INTERRUPT_HANDLER____(0x09, "Coprocessor Segment Overrun")
|
||||||
|
INTERRUPT_HANDLER_ERR(0x0A, "Invalid TSS")
|
||||||
|
INTERRUPT_HANDLER_ERR(0x0B, "Segment Not Present")
|
||||||
|
INTERRUPT_HANDLER_ERR(0x0C, "Stack-Segment Fault")
|
||||||
|
INTERRUPT_HANDLER_ERR(0x0D, "General Protection Fault")
|
||||||
|
INTERRUPT_HANDLER_ERR(0x0E, "Page Fault")
|
||||||
|
INTERRUPT_HANDLER____(0x0F, "Unknown Exception 0x0F")
|
||||||
|
INTERRUPT_HANDLER____(0x10, "x87 Floating-Point Exception")
|
||||||
|
INTERRUPT_HANDLER_ERR(0x11, "Alignment Check")
|
||||||
|
INTERRUPT_HANDLER____(0x12, "Machine Check")
|
||||||
|
INTERRUPT_HANDLER____(0x13, "SIMD Floating-Point Exception")
|
||||||
|
INTERRUPT_HANDLER____(0x14, "Virtualization Exception")
|
||||||
|
INTERRUPT_HANDLER_ERR(0x15, "Control Protection Exception")
|
||||||
|
INTERRUPT_HANDLER____(0x16, "Unknown Exception 0x16")
|
||||||
|
INTERRUPT_HANDLER____(0x17, "Unknown Exception 0x17")
|
||||||
|
INTERRUPT_HANDLER____(0x18, "Unknown Exception 0x18")
|
||||||
|
INTERRUPT_HANDLER____(0x19, "Unknown Exception 0x19")
|
||||||
|
INTERRUPT_HANDLER____(0x1A, "Unknown Exception 0x1A")
|
||||||
|
INTERRUPT_HANDLER____(0x1B, "Unknown Exception 0x1B")
|
||||||
|
INTERRUPT_HANDLER____(0x1C, "Hypervisor Injection Exception")
|
||||||
|
INTERRUPT_HANDLER_ERR(0x1D, "VMM Communication Exception")
|
||||||
|
INTERRUPT_HANDLER_ERR(0x1E, "Security Exception")
|
||||||
|
INTERRUPT_HANDLER____(0x1F, "Unkown Exception 0x1F")
|
||||||
|
|
||||||
|
extern "C" void handle_irq()
|
||||||
|
{
|
||||||
|
uint8_t irq;
|
||||||
|
for (uint32_t i = 0; i < 16; i++)
|
||||||
|
{
|
||||||
|
if (InterruptController::get().is_in_service(i))
|
||||||
|
{
|
||||||
|
irq = i;
|
||||||
|
goto found;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dprintln("Spurious irq");
|
||||||
|
return;
|
||||||
|
found:
|
||||||
|
if (s_irq_handlers[irq])
|
||||||
|
s_irq_handlers[irq]();
|
||||||
|
else
|
||||||
|
dprintln("no handler for irq 0x{2H}\n", irq);
|
||||||
|
|
||||||
|
// NOTE: Scheduler sends PIT eoi's
|
||||||
|
if (irq != PIT_IRQ)
|
||||||
|
InterruptController::get().eoi(irq);
|
||||||
|
|
||||||
|
Kernel::Scheduler::get().reschedule_if_idling();
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" void handle_irq_common();
|
||||||
|
asm(
|
||||||
|
".globl handle_irq_common;"
|
||||||
|
"handle_irq_common:"
|
||||||
|
"pusha;"
|
||||||
|
"pushw %ds;"
|
||||||
|
"pushw %es;"
|
||||||
|
"pushw %ss;"
|
||||||
|
"pushw %ss;"
|
||||||
|
"popw %ds;"
|
||||||
|
"popw %es;"
|
||||||
|
"call handle_irq;"
|
||||||
|
"popw %es;"
|
||||||
|
"popw %ds;"
|
||||||
|
"popa;"
|
||||||
|
"iret;"
|
||||||
|
);
|
||||||
|
|
||||||
|
extern "C" void syscall_asm();
|
||||||
|
asm(
|
||||||
|
".global syscall_asm;"
|
||||||
|
"syscall_asm:"
|
||||||
|
"pusha;"
|
||||||
|
"pushw %ds;"
|
||||||
|
"pushw %es;"
|
||||||
|
"pushw %ss;"
|
||||||
|
"pushw %ss;"
|
||||||
|
"popw %ds;"
|
||||||
|
"popw %es;"
|
||||||
|
"pushl %edx;"
|
||||||
|
"pushl %ecx;"
|
||||||
|
"pushl %ebx;"
|
||||||
|
"pushl %eax;"
|
||||||
|
"call cpp_syscall_handler;"
|
||||||
|
"addl $16, %esp;"
|
||||||
|
"popw %es;"
|
||||||
|
"popw %ds;"
|
||||||
|
|
||||||
|
// NOTE: following instructions are same as in 'popa', except we skip eax
|
||||||
|
// since it holds the return value of the syscall.
|
||||||
|
"popl %edi;"
|
||||||
|
"popl %esi;"
|
||||||
|
"popl %ebp;"
|
||||||
|
"addl $4, %esp;"
|
||||||
|
"popl %ebx;"
|
||||||
|
"popl %edx;"
|
||||||
|
"popl %ecx;"
|
||||||
|
"addl $4, %esp;"
|
||||||
|
|
||||||
|
"iret;"
|
||||||
|
);
|
||||||
|
|
||||||
|
static void flush_idt()
|
||||||
|
{
|
||||||
|
asm volatile("lidt %0"::"m"(s_idtr));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void register_interrupt_handler(uint8_t index, void(*f)())
|
||||||
|
{
|
||||||
|
GateDescriptor& descriptor = s_idt[index];
|
||||||
|
descriptor.offset1 = (uint32_t)f & 0xFFFF;
|
||||||
|
descriptor.selector = 0x08;
|
||||||
|
descriptor.type = 0xE;
|
||||||
|
descriptor.DPL = 0;
|
||||||
|
descriptor.present = 1;
|
||||||
|
descriptor.offset2 = (uint32_t)f >> 16;
|
||||||
|
}
|
||||||
|
|
||||||
|
void register_irq_handler(uint8_t irq, void(*f)())
|
||||||
|
{
|
||||||
|
s_irq_handlers[irq] = f;
|
||||||
|
register_interrupt_handler(IRQ_VECTOR_BASE + irq, handle_irq_common);
|
||||||
|
flush_idt();
|
||||||
|
}
|
||||||
|
|
||||||
|
void register_syscall_handler(uint8_t offset, void(*handler)())
|
||||||
|
{
|
||||||
|
register_interrupt_handler(offset, handler);
|
||||||
|
s_idt[offset].DPL = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
void initialize()
|
||||||
|
{
|
||||||
|
constexpr size_t idt_size = 0x100 * sizeof(GateDescriptor);
|
||||||
|
|
||||||
|
s_idt = (GateDescriptor*)kmalloc(idt_size);
|
||||||
|
ASSERT(s_idt);
|
||||||
|
memset(s_idt, 0x00, idt_size);
|
||||||
|
|
||||||
|
s_idtr.offset = s_idt;
|
||||||
|
s_idtr.size = idt_size - 1;
|
||||||
|
|
||||||
|
REGISTER_HANDLER(0x00);
|
||||||
|
REGISTER_HANDLER(0x01);
|
||||||
|
REGISTER_HANDLER(0x02);
|
||||||
|
REGISTER_HANDLER(0x03);
|
||||||
|
REGISTER_HANDLER(0x04);
|
||||||
|
REGISTER_HANDLER(0x05);
|
||||||
|
REGISTER_HANDLER(0x06);
|
||||||
|
REGISTER_HANDLER(0x07);
|
||||||
|
REGISTER_HANDLER(0x08);
|
||||||
|
REGISTER_HANDLER(0x09);
|
||||||
|
REGISTER_HANDLER(0x0A);
|
||||||
|
REGISTER_HANDLER(0x0B);
|
||||||
|
REGISTER_HANDLER(0x0C);
|
||||||
|
REGISTER_HANDLER(0x0D);
|
||||||
|
REGISTER_HANDLER(0x0E);
|
||||||
|
REGISTER_HANDLER(0x0F);
|
||||||
|
REGISTER_HANDLER(0x10);
|
||||||
|
REGISTER_HANDLER(0x11);
|
||||||
|
REGISTER_HANDLER(0x12);
|
||||||
|
REGISTER_HANDLER(0x13);
|
||||||
|
REGISTER_HANDLER(0x14);
|
||||||
|
REGISTER_HANDLER(0x15);
|
||||||
|
REGISTER_HANDLER(0x16);
|
||||||
|
REGISTER_HANDLER(0x17);
|
||||||
|
REGISTER_HANDLER(0x18);
|
||||||
|
REGISTER_HANDLER(0x19);
|
||||||
|
REGISTER_HANDLER(0x1A);
|
||||||
|
REGISTER_HANDLER(0x1B);
|
||||||
|
REGISTER_HANDLER(0x1C);
|
||||||
|
REGISTER_HANDLER(0x1D);
|
||||||
|
REGISTER_HANDLER(0x1E);
|
||||||
|
REGISTER_HANDLER(0x1F);
|
||||||
|
|
||||||
|
register_syscall_handler(0x80, syscall_asm);
|
||||||
|
|
||||||
|
flush_idt();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,227 @@
|
||||||
|
#include <BAN/Errors.h>
|
||||||
|
#include <kernel/Debug.h>
|
||||||
|
#include <kernel/Memory/MMU.h>
|
||||||
|
#include <kernel/Memory/kmalloc.h>
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#define MMU_DEBUG_PRINT 0
|
||||||
|
|
||||||
|
// bits 31-12 set
|
||||||
|
#define PAGE_MASK 0xfffff000
|
||||||
|
#define FLAGS_MASK 0x00000fff
|
||||||
|
|
||||||
|
namespace Kernel
|
||||||
|
{
|
||||||
|
|
||||||
|
static MMU* s_instance = nullptr;
|
||||||
|
|
||||||
|
void MMU::initialize()
|
||||||
|
{
|
||||||
|
ASSERT(s_instance == nullptr);
|
||||||
|
s_instance = new MMU();
|
||||||
|
ASSERT(s_instance);
|
||||||
|
s_instance->initialize_kernel();
|
||||||
|
s_instance->load();
|
||||||
|
}
|
||||||
|
|
||||||
|
MMU& MMU::get()
|
||||||
|
{
|
||||||
|
ASSERT(s_instance);
|
||||||
|
return *s_instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint64_t* allocate_page_aligned_page()
|
||||||
|
{
|
||||||
|
uint64_t* page = (uint64_t*)kmalloc(PAGE_SIZE, PAGE_SIZE);
|
||||||
|
ASSERT(page);
|
||||||
|
ASSERT(((uintptr_t)page % PAGE_SIZE) == 0);
|
||||||
|
memset(page, 0, PAGE_SIZE);
|
||||||
|
return page;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MMU::initialize_kernel()
|
||||||
|
{
|
||||||
|
m_highest_paging_struct = (uint64_t*)kmalloc(sizeof(uint64_t) * 4, 32);
|
||||||
|
ASSERT(m_highest_paging_struct);
|
||||||
|
ASSERT(((uintptr_t)m_highest_paging_struct % 32) == 0);
|
||||||
|
|
||||||
|
// allocate all page directories
|
||||||
|
for (int i = 0; i < 4; i++)
|
||||||
|
{
|
||||||
|
uint64_t* page_directory = allocate_page_aligned_page();
|
||||||
|
m_highest_paging_struct[i] = (uint64_t)page_directory | Flags::Present;
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: We should just identity map until g_kernel_end
|
||||||
|
|
||||||
|
// create and identity map first 6 MiB
|
||||||
|
uint64_t* page_directory1 = (uint64_t*)(m_highest_paging_struct[0] & PAGE_MASK);
|
||||||
|
for (uint64_t i = 0; i < 3; i++)
|
||||||
|
{
|
||||||
|
uint64_t* page_table = allocate_page_aligned_page();
|
||||||
|
for (uint64_t j = 0; j < 512; j++)
|
||||||
|
page_table[j] = (i << 21) | (j << 12) | Flags::ReadWrite | Flags::Present;
|
||||||
|
|
||||||
|
page_directory1[i] = (uint64_t)page_table | Flags::ReadWrite | Flags::Present;
|
||||||
|
}
|
||||||
|
|
||||||
|
// dont map first page (0 -> 4 KiB) so that nullptr dereference
|
||||||
|
// causes page fault :)
|
||||||
|
uint64_t* page_table1 = (uint64_t*)(page_directory1[0] & PAGE_MASK);
|
||||||
|
page_table1[0] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
MMU::MMU()
|
||||||
|
{
|
||||||
|
if (s_instance == nullptr)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Here we copy the s_instances paging structs since they are
|
||||||
|
// global for every process
|
||||||
|
|
||||||
|
uint64_t* global_pdpt = s_instance->m_highest_paging_struct;
|
||||||
|
|
||||||
|
uint64_t* pdpt = (uint64_t*)kmalloc(sizeof(uint64_t) * 4, 32);
|
||||||
|
ASSERT(pdpt);
|
||||||
|
|
||||||
|
for (uint32_t pdpte = 0; pdpte < 4; pdpte++)
|
||||||
|
{
|
||||||
|
if (!(global_pdpt[pdpte] & Flags::Present))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
uint64_t* global_pd = (uint64_t*)(global_pdpt[pdpte] & PAGE_MASK);
|
||||||
|
|
||||||
|
uint64_t* pd = allocate_page_aligned_page();
|
||||||
|
pdpt[pdpte] = (uint64_t)pd | (global_pdpt[pdpte] & ~PAGE_MASK);
|
||||||
|
|
||||||
|
for (uint32_t pde = 0; pde < 512; pde++)
|
||||||
|
{
|
||||||
|
if (!(global_pd[pde] & Flags::Present))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
uint64_t* global_pt = (uint64_t*)(global_pd[pde] & PAGE_MASK);
|
||||||
|
|
||||||
|
uint64_t* pt = allocate_page_aligned_page();
|
||||||
|
pd[pde] = (uint64_t)pt | (global_pd[pde] & ~PAGE_MASK);
|
||||||
|
|
||||||
|
memcpy(pt, global_pt, PAGE_SIZE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_highest_paging_struct = pdpt;
|
||||||
|
}
|
||||||
|
|
||||||
|
MMU::~MMU()
|
||||||
|
{
|
||||||
|
uint64_t* pdpt = m_highest_paging_struct;
|
||||||
|
for (uint32_t pdpte = 0; pdpte < 512; pdpte++)
|
||||||
|
{
|
||||||
|
if (!(pdpt[pdpte] & Flags::Present))
|
||||||
|
continue;
|
||||||
|
uint64_t* pd = (uint64_t*)(pdpt[pdpte] & PAGE_MASK);
|
||||||
|
for (uint32_t pde = 0; pde < 512; pde++)
|
||||||
|
{
|
||||||
|
if (!(pd[pde] & Flags::Present))
|
||||||
|
continue;
|
||||||
|
kfree((void*)(pd[pde] & PAGE_MASK));
|
||||||
|
}
|
||||||
|
kfree(pd);
|
||||||
|
}
|
||||||
|
kfree(pdpt);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MMU::load()
|
||||||
|
{
|
||||||
|
asm volatile("movl %0, %%cr3" :: "r"(m_highest_paging_struct));
|
||||||
|
}
|
||||||
|
|
||||||
|
void MMU::map_page_at(paddr_t paddr, vaddr_t vaddr, uint8_t flags)
|
||||||
|
{
|
||||||
|
#if MMU_DEBUG_PRINT
|
||||||
|
dprintln("AllocatePage(0x{8H})", address);
|
||||||
|
#endif
|
||||||
|
ASSERT(flags & Flags::Present);
|
||||||
|
|
||||||
|
ASSERT(!(paddr & ~PAGE_MASK));
|
||||||
|
ASSERT(!(vaddr & ~PAGE_MASK));
|
||||||
|
|
||||||
|
uint32_t pdpte = (vaddr & 0xC0000000) >> 30;
|
||||||
|
uint32_t pde = (vaddr & 0x3FE00000) >> 21;
|
||||||
|
uint32_t pte = (vaddr & 0x001FF000) >> 12;
|
||||||
|
|
||||||
|
uint64_t* page_directory = (uint64_t*)(m_highest_paging_struct[pdpte] & PAGE_MASK);
|
||||||
|
if (!(page_directory[pde] & Flags::Present))
|
||||||
|
{
|
||||||
|
uint64_t* page_table = allocate_page_aligned_page();
|
||||||
|
page_directory[pde] = (uint64_t)page_table;
|
||||||
|
}
|
||||||
|
page_directory[pde] |= flags;
|
||||||
|
|
||||||
|
uint64_t* page_table = (uint64_t*)(page_directory[pde] & PAGE_MASK);
|
||||||
|
page_table[pte] = paddr | flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MMU::identity_map_page(paddr_t address, uint8_t flags)
|
||||||
|
{
|
||||||
|
address &= PAGE_MASK;
|
||||||
|
map_page_at(address, address, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MMU::identity_map_range(paddr_t address, ptrdiff_t size, uint8_t flags)
|
||||||
|
{
|
||||||
|
paddr_t s_page = address & PAGE_MASK;
|
||||||
|
paddr_t e_page = (address + size - 1) & PAGE_MASK;
|
||||||
|
for (paddr_t page = s_page; page <= e_page; page += PAGE_SIZE)
|
||||||
|
identity_map_page(page, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MMU::unmap_page(vaddr_t address)
|
||||||
|
{
|
||||||
|
#if MMU_DEBUG_PRINT
|
||||||
|
dprintln("UnAllocatePage(0x{8H})", address & PAGE_MASK);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
uint32_t pdpte = (address & 0xC0000000) >> 30;
|
||||||
|
uint32_t pde = (address & 0x3FE00000) >> 21;
|
||||||
|
uint32_t pte = (address & 0x001FF000) >> 12;
|
||||||
|
|
||||||
|
uint64_t* page_directory = (uint64_t*)(m_highest_paging_struct[pdpte] & PAGE_MASK);
|
||||||
|
if (!(page_directory[pde] & Flags::Present))
|
||||||
|
return;
|
||||||
|
|
||||||
|
uint64_t* page_table = (uint64_t*)(page_directory[pde] & PAGE_MASK);
|
||||||
|
if (!(page_table[pte] & Flags::Present))
|
||||||
|
return;
|
||||||
|
|
||||||
|
page_table[pte] = 0;
|
||||||
|
|
||||||
|
// TODO: Unallocate the page table if this was the only allocated page
|
||||||
|
}
|
||||||
|
|
||||||
|
void MMU::unmap_range(vaddr_t address, ptrdiff_t size)
|
||||||
|
{
|
||||||
|
uintptr_t s_page = address & PAGE_MASK;
|
||||||
|
uintptr_t e_page = (address + size - 1) & PAGE_MASK;
|
||||||
|
for (uintptr_t page = s_page; page <= e_page; page += PAGE_SIZE)
|
||||||
|
unmap_page(page);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t MMU::get_page_flags(vaddr_t address) const
|
||||||
|
{
|
||||||
|
uint32_t pdpte = (address & 0xC0000000) >> 30;
|
||||||
|
uint32_t pde = (address & 0x3FE00000) >> 21;
|
||||||
|
uint32_t pte = (address & 0x001FF000) >> 12;
|
||||||
|
|
||||||
|
uint64_t* page_directory = (uint64_t*)(m_highest_paging_struct[pdpte] & PAGE_MASK);
|
||||||
|
if (!(page_directory[pde] & Flags::Present))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
uint64_t* page_table = (uint64_t*)(page_directory[pde] & PAGE_MASK);
|
||||||
|
if (!(page_table[pte] & Flags::Present))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return page_table[pte] & FLAGS_MASK;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
.global spinlock_lock_asm
|
||||||
|
spinlock_lock_asm:
|
||||||
|
movl 4(%esp), %eax
|
||||||
|
lock; btsl $0, (%eax)
|
||||||
|
jnc .done
|
||||||
|
.retry:
|
||||||
|
pause
|
||||||
|
testl $1, (%eax)
|
||||||
|
jne .retry
|
||||||
|
lock; btsl $0, (%eax)
|
||||||
|
jc .retry
|
||||||
|
.done:
|
||||||
|
ret
|
||||||
|
|
||||||
|
.global spinlock_unlock_asm
|
||||||
|
spinlock_unlock_asm:
|
||||||
|
movl 4(%esp), %eax
|
||||||
|
movl $0, (%eax)
|
||||||
|
ret
|
|
@ -0,0 +1,47 @@
|
||||||
|
# uint32_t read_rip()
|
||||||
|
.global read_rip
|
||||||
|
read_rip:
|
||||||
|
popl %eax
|
||||||
|
jmp *%eax
|
||||||
|
|
||||||
|
exit_thread_trampoline:
|
||||||
|
addl $4, %esp
|
||||||
|
pushl (%esp)
|
||||||
|
ret
|
||||||
|
|
||||||
|
# void start_thread(uint32_t esp, uint32_t eip)
|
||||||
|
.global start_thread
|
||||||
|
start_thread:
|
||||||
|
movl 8(%esp), %ecx
|
||||||
|
movl 4(%esp), %esp
|
||||||
|
movl $0, %ebp
|
||||||
|
pushl $exit_thread_trampoline
|
||||||
|
sti
|
||||||
|
jmp *%ecx
|
||||||
|
|
||||||
|
# void continue_thread(uint32_t rsp, uint32_t rip)
|
||||||
|
.global continue_thread
|
||||||
|
continue_thread:
|
||||||
|
movl 8(%esp), %ecx
|
||||||
|
movl 4(%esp), %esp
|
||||||
|
movl $0, %eax
|
||||||
|
jmp *%ecx
|
||||||
|
|
||||||
|
# void thread_jump_userspace(uint32_t rsp, uint32_t rip)
|
||||||
|
.global thread_jump_userspace
|
||||||
|
thread_jump_userspace:
|
||||||
|
movl $0x23, %eax
|
||||||
|
movw %ax, %ds
|
||||||
|
movw %ax, %es
|
||||||
|
movw %ax, %fs
|
||||||
|
movw %ax, %gs
|
||||||
|
|
||||||
|
movl 8(%esp), %ecx
|
||||||
|
movl 4(%esp), %esp
|
||||||
|
|
||||||
|
pushl $0x23
|
||||||
|
pushl %esp
|
||||||
|
pushfl
|
||||||
|
pushl $0x1B
|
||||||
|
pushl %ecx
|
||||||
|
iret
|
|
@ -0,0 +1,182 @@
|
||||||
|
# Declare constants for the multiboot header
|
||||||
|
.set ALIGN, 1<<0 # align loaded modules on page boundaries
|
||||||
|
.set MEMINFO, 1<<1 # provide memory map
|
||||||
|
.set VIDEOINFO, 1<<2 # provide video info
|
||||||
|
.set MB_FLAGS, ALIGN | MEMINFO | VIDEOINFO # this is the Multiboot 'flag' field
|
||||||
|
.set MB_MAGIC, 0x1BADB002 # 'magic number' lets bootloader find the header
|
||||||
|
.set MB_CHECKSUM, -(MB_MAGIC + MB_FLAGS) #checksum of above, to prove we are multiboot
|
||||||
|
|
||||||
|
# Multiboot header
|
||||||
|
.section .multiboot, "aw"
|
||||||
|
.align 4
|
||||||
|
.long MB_MAGIC
|
||||||
|
.long MB_FLAGS
|
||||||
|
.long MB_CHECKSUM
|
||||||
|
.skip 20
|
||||||
|
|
||||||
|
.long 0
|
||||||
|
.long 800
|
||||||
|
.long 600
|
||||||
|
.long 32
|
||||||
|
|
||||||
|
.section .bss, "aw", @nobits
|
||||||
|
# Create stack
|
||||||
|
.global g_boot_stack_bottom
|
||||||
|
g_boot_stack_bottom:
|
||||||
|
.skip 16384
|
||||||
|
.global g_boot_stack_top
|
||||||
|
g_boot_stack_top:
|
||||||
|
|
||||||
|
# 0 MiB -> 1 MiB: bootloader stuff
|
||||||
|
# 1 MiB -> : kernel
|
||||||
|
.align 32
|
||||||
|
boot_page_directory_pointer_table:
|
||||||
|
.skip 4 * 8
|
||||||
|
.align 4096
|
||||||
|
boot_page_directory1:
|
||||||
|
.skip 512 * 8
|
||||||
|
|
||||||
|
.global g_kernel_cmdline
|
||||||
|
g_kernel_cmdline:
|
||||||
|
.skip 4096
|
||||||
|
|
||||||
|
.global g_multiboot_info
|
||||||
|
g_multiboot_info:
|
||||||
|
.skip 4
|
||||||
|
.global g_multiboot_magic
|
||||||
|
g_multiboot_magic:
|
||||||
|
.skip 4
|
||||||
|
|
||||||
|
.section .text
|
||||||
|
|
||||||
|
boot_gdt:
|
||||||
|
.quad 0x0000000000000000 # null
|
||||||
|
.quad 0x00CF9A000000FFFF # kernel code
|
||||||
|
.quad 0x00CF92000000FFFF # kernel data
|
||||||
|
boot_gdtr:
|
||||||
|
.short . - boot_gdt - 1
|
||||||
|
.long boot_gdt
|
||||||
|
|
||||||
|
has_cpuid:
|
||||||
|
pushfl
|
||||||
|
pushfl
|
||||||
|
xorl $0x00200000, (%esp)
|
||||||
|
popfl
|
||||||
|
pushfl
|
||||||
|
popl %eax
|
||||||
|
xorl (%esp), %eax
|
||||||
|
popfl
|
||||||
|
testl $0x00200000, %eax
|
||||||
|
ret
|
||||||
|
|
||||||
|
has_pae:
|
||||||
|
movl $0, %eax
|
||||||
|
cpuid
|
||||||
|
testl $(1 << 6), %edx
|
||||||
|
ret
|
||||||
|
|
||||||
|
has_sse:
|
||||||
|
movl $1, %eax
|
||||||
|
cpuid
|
||||||
|
testl $(1 << 25), %edx
|
||||||
|
ret
|
||||||
|
|
||||||
|
check_requirements:
|
||||||
|
call has_cpuid
|
||||||
|
jz .exit
|
||||||
|
call has_pae
|
||||||
|
jz .exit
|
||||||
|
call has_sse
|
||||||
|
jz .exit
|
||||||
|
ret
|
||||||
|
.exit:
|
||||||
|
jmp system_halt
|
||||||
|
|
||||||
|
copy_kernel_commandline:
|
||||||
|
pushl %esi
|
||||||
|
pushl %edi
|
||||||
|
movl g_multiboot_info, %esi
|
||||||
|
addl $16, %esi
|
||||||
|
movl (%esi), %esi
|
||||||
|
movl $1024, %ecx
|
||||||
|
movl $g_kernel_cmdline, %edi
|
||||||
|
rep movsl
|
||||||
|
popl %edi
|
||||||
|
popl %esi
|
||||||
|
ret
|
||||||
|
|
||||||
|
enable_sse:
|
||||||
|
movl %cr0, %eax
|
||||||
|
andw $0xFFFB, %ax
|
||||||
|
orw $0x0002, %ax
|
||||||
|
movl %eax, %cr0
|
||||||
|
movl %cr4, %eax
|
||||||
|
orw $0x0600, %ax
|
||||||
|
movl %eax, %cr4
|
||||||
|
ret
|
||||||
|
|
||||||
|
initialize_paging:
|
||||||
|
# identity map first 6 MiB
|
||||||
|
movl $(0x00000000 + 0x83), boot_page_directory1 + 0
|
||||||
|
movl $(0x00200000 + 0x83), boot_page_directory1 + 8
|
||||||
|
movl $(0x00400000 + 0x83), boot_page_directory1 + 16
|
||||||
|
movl $(boot_page_directory1 + 0x01), boot_page_directory_pointer_table
|
||||||
|
|
||||||
|
# enable PAE
|
||||||
|
movl %cr4, %ecx
|
||||||
|
orl $0x20, %ecx
|
||||||
|
movl %ecx, %cr4
|
||||||
|
|
||||||
|
# set address of paging structures
|
||||||
|
movl $boot_page_directory_pointer_table, %ecx
|
||||||
|
movl %ecx, %cr3
|
||||||
|
|
||||||
|
# enable paging
|
||||||
|
movl %cr0, %ecx
|
||||||
|
orl $0x80000000, %ecx
|
||||||
|
movl %ecx, %cr0
|
||||||
|
|
||||||
|
ret
|
||||||
|
|
||||||
|
initialize_gdt:
|
||||||
|
lgdt boot_gdtr
|
||||||
|
|
||||||
|
# flush gdt
|
||||||
|
movw $0x10, %ax
|
||||||
|
movw %ax, %ds
|
||||||
|
movw %ax, %es
|
||||||
|
movw %ax, %fs
|
||||||
|
movw %ax, %gs
|
||||||
|
movw %ax, %ss
|
||||||
|
jmp $0x08, $flush
|
||||||
|
flush:
|
||||||
|
ret
|
||||||
|
|
||||||
|
.global _start
|
||||||
|
.type _start, @function
|
||||||
|
_start:
|
||||||
|
# Initialize stack and multiboot info
|
||||||
|
movl $g_boot_stack_top, %esp
|
||||||
|
movl %eax, g_multiboot_magic
|
||||||
|
movl %ebx, g_multiboot_info
|
||||||
|
|
||||||
|
call copy_kernel_commandline
|
||||||
|
call check_requirements
|
||||||
|
call enable_sse
|
||||||
|
|
||||||
|
call initialize_paging
|
||||||
|
call initialize_gdt
|
||||||
|
|
||||||
|
call _init
|
||||||
|
|
||||||
|
# call to the kernel itself (clear ebp for stacktrace)
|
||||||
|
xorl %ebp, %ebp
|
||||||
|
call kernel_main
|
||||||
|
|
||||||
|
call _fini
|
||||||
|
|
||||||
|
system_halt:
|
||||||
|
xchgw %bx, %bx
|
||||||
|
cli
|
||||||
|
1: hlt
|
||||||
|
jmp 1b
|
|
@ -0,0 +1,23 @@
|
||||||
|
.section .text
|
||||||
|
|
||||||
|
.global _start
|
||||||
|
_start:
|
||||||
|
# Set up end of the stack frame linked list.
|
||||||
|
movl $0, %ebp
|
||||||
|
pushl %ebp # rip=0
|
||||||
|
pushl %ebp # rbp=0
|
||||||
|
movl %esp, %ebp
|
||||||
|
|
||||||
|
# Prepare signals, memory allocation, stdio and such.
|
||||||
|
#call initialize_standard_library
|
||||||
|
|
||||||
|
# Run the global constructors.
|
||||||
|
call _init
|
||||||
|
|
||||||
|
# Run main
|
||||||
|
call main
|
||||||
|
|
||||||
|
# Terminate the process with the exit code.
|
||||||
|
movl %eax, %edi
|
||||||
|
call exit
|
||||||
|
.size _start, . - _start
|
|
@ -1,9 +1,9 @@
|
||||||
/* i686 crti.s */
|
/* x86 crti.s */
|
||||||
.section .init
|
.section .init
|
||||||
.global _init
|
.global _init
|
||||||
.type _init, @function
|
.type _init, @function
|
||||||
_init:
|
_init:
|
||||||
pushl %ebp
|
push %ebp
|
||||||
movl %esp, %ebp
|
movl %esp, %ebp
|
||||||
/* gcc will nicely put the contents of crtbegin.o's .init section here. */
|
/* gcc will nicely put the contents of crtbegin.o's .init section here. */
|
||||||
|
|
||||||
|
@ -11,6 +11,6 @@ _init:
|
||||||
.global _fini
|
.global _fini
|
||||||
.type _fini, @function
|
.type _fini, @function
|
||||||
_fini:
|
_fini:
|
||||||
pushl %ebp
|
push %ebp
|
||||||
movl %esp, %ebp
|
movl %esp, %ebp
|
||||||
/* gcc will nicely put the contents of crtbegin.o's .fini section here. */
|
/* gcc will nicely put the contents of crtbegin.o's .fini section here. */
|
|
@ -1,4 +1,4 @@
|
||||||
/* i686 crtn.s */
|
/* x86 crtn.s */
|
||||||
.section .init
|
.section .init
|
||||||
/* gcc will nicely put the contents of crtend.o's .init section here. */
|
/* gcc will nicely put the contents of crtend.o's .init section here. */
|
||||||
popl %ebp
|
popl %ebp
|
|
@ -0,0 +1,28 @@
|
||||||
|
ENTRY (_start)
|
||||||
|
|
||||||
|
SECTIONS
|
||||||
|
{
|
||||||
|
. = 0x00100000;
|
||||||
|
|
||||||
|
g_kernel_start = .;
|
||||||
|
.text BLOCK(4K) : ALIGN(4K)
|
||||||
|
{
|
||||||
|
*(.multiboot)
|
||||||
|
*(.text)
|
||||||
|
}
|
||||||
|
.rodata BLOCK(4K) : ALIGN(4K)
|
||||||
|
{
|
||||||
|
*(.rodata.*)
|
||||||
|
}
|
||||||
|
.data BLOCK(4K) : ALIGN(4K)
|
||||||
|
{
|
||||||
|
*(.data)
|
||||||
|
}
|
||||||
|
.bss BLOCK(4K) : ALIGN(4K)
|
||||||
|
{
|
||||||
|
*(COMMON)
|
||||||
|
*(.bss)
|
||||||
|
}
|
||||||
|
|
||||||
|
g_kernel_end = .;
|
||||||
|
}
|
|
@ -1,682 +0,0 @@
|
||||||
#include <kernel/BootInfo.h>
|
|
||||||
#include <kernel/CPUID.h>
|
|
||||||
#include <kernel/Lock/SpinLock.h>
|
|
||||||
#include <kernel/Memory/kmalloc.h>
|
|
||||||
#include <kernel/Memory/PageTable.h>
|
|
||||||
|
|
||||||
extern uint8_t g_kernel_start[];
|
|
||||||
extern uint8_t g_kernel_end[];
|
|
||||||
|
|
||||||
extern uint8_t g_kernel_execute_start[];
|
|
||||||
extern uint8_t g_kernel_execute_end[];
|
|
||||||
|
|
||||||
extern uint8_t g_kernel_writable_start[];
|
|
||||||
extern uint8_t g_kernel_writable_end[];
|
|
||||||
|
|
||||||
extern uint8_t g_userspace_start[];
|
|
||||||
extern uint8_t g_userspace_end[];
|
|
||||||
|
|
||||||
namespace Kernel
|
|
||||||
{
|
|
||||||
|
|
||||||
SpinLock PageTable::s_fast_page_lock;
|
|
||||||
|
|
||||||
static PageTable* s_kernel = nullptr;
|
|
||||||
static bool s_has_nxe = false;
|
|
||||||
static bool s_has_pge = false;
|
|
||||||
static bool s_has_pat = false;
|
|
||||||
|
|
||||||
static paddr_t s_global_pdpte = 0;
|
|
||||||
|
|
||||||
static inline PageTable::flags_t parse_flags(uint64_t entry)
|
|
||||||
{
|
|
||||||
using Flags = PageTable::Flags;
|
|
||||||
|
|
||||||
PageTable::flags_t result = 0;
|
|
||||||
if (s_has_nxe && !(entry & (1ull << 63)))
|
|
||||||
result |= Flags::Execute;
|
|
||||||
if (entry & Flags::Reserved)
|
|
||||||
result |= Flags::Reserved;
|
|
||||||
if (entry & Flags::UserSupervisor)
|
|
||||||
result |= Flags::UserSupervisor;
|
|
||||||
if (entry & Flags::ReadWrite)
|
|
||||||
result |= Flags::ReadWrite;
|
|
||||||
if (entry & Flags::Present)
|
|
||||||
result |= Flags::Present;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
void PageTable::initialize_pre_heap()
|
|
||||||
{
|
|
||||||
if (CPUID::has_nxe())
|
|
||||||
s_has_nxe = true;
|
|
||||||
|
|
||||||
if (CPUID::has_pge())
|
|
||||||
s_has_pge = true;
|
|
||||||
|
|
||||||
if (CPUID::has_pat())
|
|
||||||
s_has_pat = true;
|
|
||||||
|
|
||||||
ASSERT(s_kernel == nullptr);
|
|
||||||
s_kernel = new PageTable();
|
|
||||||
ASSERT(s_kernel);
|
|
||||||
|
|
||||||
s_kernel->initialize_kernel();
|
|
||||||
s_kernel->initial_load();
|
|
||||||
}
|
|
||||||
|
|
||||||
void PageTable::initialize_post_heap()
|
|
||||||
{
|
|
||||||
// NOTE: this is no-op as our 32 bit target does not use hhdm
|
|
||||||
}
|
|
||||||
|
|
||||||
void PageTable::initial_load()
|
|
||||||
{
|
|
||||||
if (s_has_nxe)
|
|
||||||
{
|
|
||||||
asm volatile(
|
|
||||||
"movl $0xC0000080, %%ecx;"
|
|
||||||
"rdmsr;"
|
|
||||||
"orl $0x800, %%eax;"
|
|
||||||
"wrmsr"
|
|
||||||
::: "eax", "ecx", "edx", "memory"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (s_has_pge)
|
|
||||||
{
|
|
||||||
asm volatile(
|
|
||||||
"movl %%cr4, %%eax;"
|
|
||||||
"orl $0x80, %%eax;"
|
|
||||||
"movl %%eax, %%cr4;"
|
|
||||||
::: "eax"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (s_has_pat)
|
|
||||||
{
|
|
||||||
asm volatile(
|
|
||||||
"movl $0x277, %%ecx;"
|
|
||||||
"rdmsr;"
|
|
||||||
"movw $0x0401, %%dx;"
|
|
||||||
"wrmsr;"
|
|
||||||
::: "eax", "ecx", "edx", "memory"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// enable write protect
|
|
||||||
asm volatile(
|
|
||||||
"movl %%cr0, %%eax;"
|
|
||||||
"orl $0x10000, %%eax;"
|
|
||||||
"movl %%eax, %%cr0;"
|
|
||||||
::: "rax"
|
|
||||||
);
|
|
||||||
|
|
||||||
load();
|
|
||||||
}
|
|
||||||
|
|
||||||
PageTable& PageTable::kernel()
|
|
||||||
{
|
|
||||||
ASSERT(s_kernel);
|
|
||||||
return *s_kernel;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool PageTable::is_valid_pointer(uintptr_t)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint64_t* allocate_zeroed_page_aligned_page()
|
|
||||||
{
|
|
||||||
void* page = kmalloc(PAGE_SIZE, PAGE_SIZE, true);
|
|
||||||
ASSERT(page);
|
|
||||||
memset(page, 0, PAGE_SIZE);
|
|
||||||
return (uint64_t*)page;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
static paddr_t V2P(const T vaddr)
|
|
||||||
{
|
|
||||||
return (vaddr_t)vaddr - KERNEL_OFFSET + g_boot_info.kernel_paddr;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
static vaddr_t P2V(const T paddr)
|
|
||||||
{
|
|
||||||
return (paddr_t)paddr - g_boot_info.kernel_paddr + KERNEL_OFFSET;
|
|
||||||
}
|
|
||||||
|
|
||||||
void PageTable::initialize_kernel()
|
|
||||||
{
|
|
||||||
ASSERT(s_global_pdpte == 0);
|
|
||||||
s_global_pdpte = V2P(allocate_zeroed_page_aligned_page());
|
|
||||||
|
|
||||||
map_kernel_memory();
|
|
||||||
|
|
||||||
prepare_fast_page();
|
|
||||||
|
|
||||||
// Map (phys_kernel_start -> phys_kernel_end) to (virt_kernel_start -> virt_kernel_end)
|
|
||||||
ASSERT((vaddr_t)g_kernel_start % PAGE_SIZE == 0);
|
|
||||||
map_range_at(
|
|
||||||
V2P(g_kernel_start),
|
|
||||||
(vaddr_t)g_kernel_start,
|
|
||||||
g_kernel_end - g_kernel_start,
|
|
||||||
Flags::Present
|
|
||||||
);
|
|
||||||
|
|
||||||
// Map executable kernel memory as executable
|
|
||||||
map_range_at(
|
|
||||||
V2P(g_kernel_execute_start),
|
|
||||||
(vaddr_t)g_kernel_execute_start,
|
|
||||||
g_kernel_execute_end - g_kernel_execute_start,
|
|
||||||
Flags::Execute | Flags::Present
|
|
||||||
);
|
|
||||||
|
|
||||||
// Map writable kernel memory as writable
|
|
||||||
map_range_at(
|
|
||||||
V2P(g_kernel_writable_start),
|
|
||||||
(vaddr_t)g_kernel_writable_start,
|
|
||||||
g_kernel_writable_end - g_kernel_writable_start,
|
|
||||||
Flags::ReadWrite | Flags::Present
|
|
||||||
);
|
|
||||||
|
|
||||||
// Map userspace memory
|
|
||||||
map_range_at(
|
|
||||||
V2P(g_userspace_start),
|
|
||||||
(vaddr_t)g_userspace_start,
|
|
||||||
g_userspace_end - g_userspace_start,
|
|
||||||
Flags::Execute | Flags::UserSupervisor | Flags::Present
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
void PageTable::prepare_fast_page()
|
|
||||||
{
|
|
||||||
constexpr uint64_t pdpte = (fast_page() >> 30) & 0x1FF;
|
|
||||||
constexpr uint64_t pde = (fast_page() >> 21) & 0x1FF;
|
|
||||||
|
|
||||||
uint64_t* pdpt = reinterpret_cast<uint64_t*>(P2V(m_highest_paging_struct));
|
|
||||||
ASSERT(pdpt[pdpte] & Flags::Present);
|
|
||||||
|
|
||||||
uint64_t* pd = reinterpret_cast<uint64_t*>(P2V(pdpt[pdpte]) & PAGE_ADDR_MASK);
|
|
||||||
ASSERT(!(pd[pde] & Flags::Present));
|
|
||||||
pd[pde] = V2P(allocate_zeroed_page_aligned_page()) | Flags::ReadWrite | Flags::Present;
|
|
||||||
}
|
|
||||||
|
|
||||||
void PageTable::map_fast_page(paddr_t paddr)
|
|
||||||
{
|
|
||||||
ASSERT(s_kernel);
|
|
||||||
ASSERT(paddr);
|
|
||||||
|
|
||||||
ASSERT(s_fast_page_lock.current_processor_has_lock());
|
|
||||||
|
|
||||||
constexpr uint64_t pdpte = (fast_page() >> 30) & 0x1FF;
|
|
||||||
constexpr uint64_t pde = (fast_page() >> 21) & 0x1FF;
|
|
||||||
constexpr uint64_t pte = (fast_page() >> 12) & 0x1FF;
|
|
||||||
|
|
||||||
uint64_t* pdpt = reinterpret_cast<uint64_t*>(P2V(s_kernel->m_highest_paging_struct));
|
|
||||||
uint64_t* pd = reinterpret_cast<uint64_t*>(P2V(pdpt[pdpte] & PAGE_ADDR_MASK));
|
|
||||||
uint64_t* pt = reinterpret_cast<uint64_t*>(P2V(pd[pde] & PAGE_ADDR_MASK));
|
|
||||||
|
|
||||||
ASSERT(!(pt[pte] & Flags::Present));
|
|
||||||
pt[pte] = paddr | Flags::ReadWrite | Flags::Present;
|
|
||||||
|
|
||||||
invalidate(fast_page(), false);
|
|
||||||
}
|
|
||||||
|
|
||||||
void PageTable::unmap_fast_page()
|
|
||||||
{
|
|
||||||
ASSERT(s_kernel);
|
|
||||||
|
|
||||||
ASSERT(s_fast_page_lock.current_processor_has_lock());
|
|
||||||
|
|
||||||
constexpr uint64_t pdpte = (fast_page() >> 30) & 0x1FF;
|
|
||||||
constexpr uint64_t pde = (fast_page() >> 21) & 0x1FF;
|
|
||||||
constexpr uint64_t pte = (fast_page() >> 12) & 0x1FF;
|
|
||||||
|
|
||||||
uint64_t* pdpt = reinterpret_cast<uint64_t*>(P2V(s_kernel->m_highest_paging_struct));
|
|
||||||
uint64_t* pd = reinterpret_cast<uint64_t*>(P2V(pdpt[pdpte] & PAGE_ADDR_MASK));
|
|
||||||
uint64_t* pt = reinterpret_cast<uint64_t*>(P2V(pd[pde] & PAGE_ADDR_MASK));
|
|
||||||
|
|
||||||
ASSERT(pt[pte] & Flags::Present);
|
|
||||||
pt[pte] = 0;
|
|
||||||
|
|
||||||
invalidate(fast_page(), false);
|
|
||||||
}
|
|
||||||
|
|
||||||
BAN::ErrorOr<PageTable*> PageTable::create_userspace()
|
|
||||||
{
|
|
||||||
SpinLockGuard _(s_kernel->m_lock);
|
|
||||||
PageTable* page_table = new PageTable;
|
|
||||||
if (page_table == nullptr)
|
|
||||||
return BAN::Error::from_errno(ENOMEM);
|
|
||||||
page_table->map_kernel_memory();
|
|
||||||
return page_table;
|
|
||||||
}
|
|
||||||
|
|
||||||
void PageTable::map_kernel_memory()
|
|
||||||
{
|
|
||||||
ASSERT(s_kernel);
|
|
||||||
ASSERT(s_global_pdpte);
|
|
||||||
|
|
||||||
ASSERT(m_highest_paging_struct == 0);
|
|
||||||
m_highest_paging_struct = V2P(kmalloc(32, 32, true));
|
|
||||||
ASSERT(m_highest_paging_struct);
|
|
||||||
|
|
||||||
uint64_t* pdpt = reinterpret_cast<uint64_t*>(P2V(m_highest_paging_struct));
|
|
||||||
pdpt[0] = 0;
|
|
||||||
pdpt[1] = 0;
|
|
||||||
pdpt[2] = 0;
|
|
||||||
pdpt[3] = s_global_pdpte | Flags::Present;
|
|
||||||
static_assert(KERNEL_OFFSET == 0xC0000000);
|
|
||||||
}
|
|
||||||
|
|
||||||
PageTable::~PageTable()
|
|
||||||
{
|
|
||||||
if (m_highest_paging_struct == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
uint64_t* pdpt = reinterpret_cast<uint64_t*>(P2V(m_highest_paging_struct));
|
|
||||||
|
|
||||||
for (uint32_t pdpte = 0; pdpte < 3; pdpte++)
|
|
||||||
{
|
|
||||||
if (!(pdpt[pdpte] & Flags::Present))
|
|
||||||
continue;
|
|
||||||
uint64_t* pd = reinterpret_cast<uint64_t*>(P2V(pdpt[pdpte] & PAGE_ADDR_MASK));
|
|
||||||
for (uint32_t pde = 0; pde < 512; pde++)
|
|
||||||
{
|
|
||||||
if (!(pd[pde] & Flags::Present))
|
|
||||||
continue;
|
|
||||||
kfree(reinterpret_cast<uint64_t*>(P2V(pd[pde] & PAGE_ADDR_MASK)));
|
|
||||||
}
|
|
||||||
kfree(pd);
|
|
||||||
}
|
|
||||||
kfree(pdpt);
|
|
||||||
}
|
|
||||||
|
|
||||||
void PageTable::load()
|
|
||||||
{
|
|
||||||
SpinLockGuard _(m_lock);
|
|
||||||
ASSERT(m_highest_paging_struct < 0x100000000);
|
|
||||||
const uint32_t pdpt_lo = m_highest_paging_struct;
|
|
||||||
asm volatile("movl %0, %%cr3" :: "r"(pdpt_lo));
|
|
||||||
Processor::set_current_page_table(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
void PageTable::invalidate(vaddr_t vaddr, bool send_smp_message)
|
|
||||||
{
|
|
||||||
ASSERT(vaddr % PAGE_SIZE == 0);
|
|
||||||
asm volatile("invlpg (%0)" :: "r"(vaddr) : "memory");
|
|
||||||
|
|
||||||
if (send_smp_message)
|
|
||||||
{
|
|
||||||
Processor::broadcast_smp_message({
|
|
||||||
.type = Processor::SMPMessage::Type::FlushTLB,
|
|
||||||
.flush_tlb = {
|
|
||||||
.vaddr = vaddr,
|
|
||||||
.page_count = 1
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void PageTable::unmap_page(vaddr_t vaddr, bool send_smp_message)
|
|
||||||
{
|
|
||||||
ASSERT(vaddr);
|
|
||||||
ASSERT(vaddr % PAGE_SIZE == 0);
|
|
||||||
ASSERT(vaddr != fast_page());
|
|
||||||
if (vaddr >= KERNEL_OFFSET)
|
|
||||||
ASSERT(vaddr >= (vaddr_t)g_kernel_start);
|
|
||||||
if ((vaddr >= KERNEL_OFFSET) != (this == s_kernel))
|
|
||||||
Kernel::panic("unmapping {8H}, kernel: {}", vaddr, this == s_kernel);
|
|
||||||
|
|
||||||
const uint64_t pdpte = (vaddr >> 30) & 0x1FF;
|
|
||||||
const uint64_t pde = (vaddr >> 21) & 0x1FF;
|
|
||||||
const uint64_t pte = (vaddr >> 12) & 0x1FF;
|
|
||||||
|
|
||||||
SpinLockGuard _(m_lock);
|
|
||||||
|
|
||||||
if (is_page_free(vaddr))
|
|
||||||
Kernel::panic("trying to unmap unmapped page 0x{H}", vaddr);
|
|
||||||
|
|
||||||
uint64_t* pdpt = reinterpret_cast<uint64_t*>(P2V(m_highest_paging_struct));
|
|
||||||
uint64_t* pd = reinterpret_cast<uint64_t*>(P2V(pdpt[pdpte] & PAGE_ADDR_MASK));
|
|
||||||
uint64_t* pt = reinterpret_cast<uint64_t*>(P2V(pd[pde] & PAGE_ADDR_MASK));
|
|
||||||
|
|
||||||
pt[pte] = 0;
|
|
||||||
invalidate(vaddr, send_smp_message);
|
|
||||||
}
|
|
||||||
|
|
||||||
void PageTable::unmap_range(vaddr_t vaddr, size_t size)
|
|
||||||
{
|
|
||||||
ASSERT(vaddr % PAGE_SIZE == 0);
|
|
||||||
|
|
||||||
size_t page_count = range_page_count(vaddr, size);
|
|
||||||
|
|
||||||
SpinLockGuard _(m_lock);
|
|
||||||
for (vaddr_t page = 0; page < page_count; page++)
|
|
||||||
unmap_page(vaddr + page * PAGE_SIZE, false);
|
|
||||||
|
|
||||||
Processor::broadcast_smp_message({
|
|
||||||
.type = Processor::SMPMessage::Type::FlushTLB,
|
|
||||||
.flush_tlb = {
|
|
||||||
.vaddr = vaddr,
|
|
||||||
.page_count = page_count
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void PageTable::map_page_at(paddr_t paddr, vaddr_t vaddr, flags_t flags, MemoryType memory_type, bool send_smp_message)
|
|
||||||
{
|
|
||||||
ASSERT(vaddr);
|
|
||||||
ASSERT(vaddr != fast_page());
|
|
||||||
if ((vaddr >= KERNEL_OFFSET) != (this == s_kernel))
|
|
||||||
Kernel::panic("mapping {8H} to {8H}, kernel: {}", paddr, vaddr, this == s_kernel);
|
|
||||||
|
|
||||||
ASSERT(paddr % PAGE_SIZE == 0);
|
|
||||||
ASSERT(vaddr % PAGE_SIZE == 0);
|
|
||||||
ASSERT(flags & Flags::Used);
|
|
||||||
|
|
||||||
const uint64_t pdpte = (vaddr >> 30) & 0x1FF;
|
|
||||||
const uint64_t pde = (vaddr >> 21) & 0x1FF;
|
|
||||||
const uint64_t pte = (vaddr >> 12) & 0x1FF;
|
|
||||||
|
|
||||||
uint64_t extra_flags = 0;
|
|
||||||
if (s_has_pge && vaddr >= KERNEL_OFFSET) // Map kernel memory as global
|
|
||||||
extra_flags |= 1ull << 8;
|
|
||||||
if (s_has_nxe && !(flags & Flags::Execute))
|
|
||||||
extra_flags |= 1ull << 63;
|
|
||||||
if (flags & Flags::Reserved)
|
|
||||||
extra_flags |= Flags::Reserved;
|
|
||||||
|
|
||||||
if (memory_type == MemoryType::Uncached)
|
|
||||||
extra_flags |= (1ull << 4);
|
|
||||||
if (s_has_pat && memory_type == MemoryType::WriteCombining)
|
|
||||||
extra_flags |= (1ull << 7);
|
|
||||||
if (s_has_pat && memory_type == MemoryType::WriteThrough)
|
|
||||||
extra_flags |= (1ull << 7) | (1ull << 3);
|
|
||||||
|
|
||||||
// NOTE: we add present here, since it has to be available in higher level structures
|
|
||||||
flags_t uwr_flags = (flags & (Flags::UserSupervisor | Flags::ReadWrite)) | Flags::Present;
|
|
||||||
|
|
||||||
SpinLockGuard _(m_lock);
|
|
||||||
|
|
||||||
uint64_t* pdpt = reinterpret_cast<uint64_t*>(P2V(m_highest_paging_struct));
|
|
||||||
if (!(pdpt[pdpte] & Flags::Present))
|
|
||||||
pdpt[pdpte] = V2P(allocate_zeroed_page_aligned_page()) | Flags::Present;
|
|
||||||
|
|
||||||
uint64_t* pd = reinterpret_cast<uint64_t*>(P2V(pdpt[pdpte] & PAGE_ADDR_MASK));
|
|
||||||
if ((pd[pde] & uwr_flags) != uwr_flags)
|
|
||||||
{
|
|
||||||
if (!(pd[pde] & Flags::Present))
|
|
||||||
pd[pde] = V2P(allocate_zeroed_page_aligned_page());
|
|
||||||
pd[pde] |= uwr_flags;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(flags & Flags::Present))
|
|
||||||
uwr_flags &= ~Flags::Present;
|
|
||||||
|
|
||||||
uint64_t* pt = reinterpret_cast<uint64_t*>(P2V(pd[pde] & PAGE_ADDR_MASK));
|
|
||||||
pt[pte] = paddr | uwr_flags | extra_flags;
|
|
||||||
|
|
||||||
invalidate(vaddr, send_smp_message);
|
|
||||||
}
|
|
||||||
|
|
||||||
void PageTable::map_range_at(paddr_t paddr, vaddr_t vaddr, size_t size, flags_t flags, MemoryType memory_type)
|
|
||||||
{
|
|
||||||
ASSERT(vaddr);
|
|
||||||
ASSERT(paddr % PAGE_SIZE == 0);
|
|
||||||
ASSERT(vaddr % PAGE_SIZE == 0);
|
|
||||||
|
|
||||||
size_t page_count = range_page_count(vaddr, size);
|
|
||||||
|
|
||||||
SpinLockGuard _(m_lock);
|
|
||||||
for (size_t page = 0; page < page_count; page++)
|
|
||||||
map_page_at(paddr + page * PAGE_SIZE, vaddr + page * PAGE_SIZE, flags, memory_type, false);
|
|
||||||
|
|
||||||
Processor::broadcast_smp_message({
|
|
||||||
.type = Processor::SMPMessage::Type::FlushTLB,
|
|
||||||
.flush_tlb = {
|
|
||||||
.vaddr = vaddr,
|
|
||||||
.page_count = page_count
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t PageTable::get_page_data(vaddr_t vaddr) const
|
|
||||||
{
|
|
||||||
ASSERT(vaddr % PAGE_SIZE == 0);
|
|
||||||
|
|
||||||
const uint64_t pdpte = (vaddr >> 30) & 0x1FF;
|
|
||||||
const uint64_t pde = (vaddr >> 21) & 0x1FF;
|
|
||||||
const uint64_t pte = (vaddr >> 12) & 0x1FF;
|
|
||||||
|
|
||||||
SpinLockGuard _(m_lock);
|
|
||||||
|
|
||||||
uint64_t* pdpt = (uint64_t*)P2V(m_highest_paging_struct);
|
|
||||||
if (!(pdpt[pdpte] & Flags::Present))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
uint64_t* pd = (uint64_t*)P2V(pdpt[pdpte] & PAGE_ADDR_MASK);
|
|
||||||
if (!(pd[pde] & Flags::Present))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
uint64_t* pt = (uint64_t*)P2V(pd[pde] & PAGE_ADDR_MASK);
|
|
||||||
if (!(pt[pte] & Flags::Used))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
return pt[pte];
|
|
||||||
}
|
|
||||||
|
|
||||||
PageTable::flags_t PageTable::get_page_flags(vaddr_t vaddr) const
|
|
||||||
{
|
|
||||||
return parse_flags(get_page_data(vaddr));
|
|
||||||
}
|
|
||||||
|
|
||||||
paddr_t PageTable::physical_address_of(vaddr_t vaddr) const
|
|
||||||
{
|
|
||||||
uint64_t page_data = get_page_data(vaddr);
|
|
||||||
return (page_data & PAGE_ADDR_MASK) & ~(1ull << 63);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool PageTable::is_page_free(vaddr_t vaddr) const
|
|
||||||
{
|
|
||||||
ASSERT(vaddr % PAGE_SIZE == 0);
|
|
||||||
return !(get_page_flags(vaddr) & Flags::Used);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool PageTable::is_range_free(vaddr_t vaddr, size_t size) const
|
|
||||||
{
|
|
||||||
vaddr_t s_page = vaddr / PAGE_SIZE;
|
|
||||||
vaddr_t e_page = BAN::Math::div_round_up<vaddr_t>(vaddr + size, PAGE_SIZE);
|
|
||||||
|
|
||||||
SpinLockGuard _(m_lock);
|
|
||||||
for (vaddr_t page = s_page; page < e_page; page++)
|
|
||||||
if (!is_page_free(page * PAGE_SIZE))
|
|
||||||
return false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool PageTable::reserve_page(vaddr_t vaddr, bool only_free)
|
|
||||||
{
|
|
||||||
SpinLockGuard _(m_lock);
|
|
||||||
ASSERT(vaddr % PAGE_SIZE == 0);
|
|
||||||
if (only_free && !is_page_free(vaddr))
|
|
||||||
return false;
|
|
||||||
map_page_at(0, vaddr, Flags::Reserved);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool PageTable::reserve_range(vaddr_t vaddr, size_t bytes, bool only_free)
|
|
||||||
{
|
|
||||||
if (size_t rem = bytes % PAGE_SIZE)
|
|
||||||
bytes += PAGE_SIZE - rem;
|
|
||||||
ASSERT(vaddr % PAGE_SIZE == 0);
|
|
||||||
|
|
||||||
SpinLockGuard _(m_lock);
|
|
||||||
if (only_free && !is_range_free(vaddr, bytes))
|
|
||||||
return false;
|
|
||||||
for (size_t offset = 0; offset < bytes; offset += PAGE_SIZE)
|
|
||||||
reserve_page(vaddr + offset);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
vaddr_t PageTable::reserve_free_page(vaddr_t first_address, vaddr_t last_address)
|
|
||||||
{
|
|
||||||
if (first_address >= KERNEL_OFFSET && first_address < (vaddr_t)g_kernel_end)
|
|
||||||
first_address = (vaddr_t)g_kernel_end;
|
|
||||||
if (size_t rem = first_address % PAGE_SIZE)
|
|
||||||
first_address += PAGE_SIZE - rem;
|
|
||||||
if (size_t rem = last_address % PAGE_SIZE)
|
|
||||||
last_address -= rem;
|
|
||||||
|
|
||||||
const uint32_t s_pdpte = (first_address >> 30) & 0x1FF;
|
|
||||||
const uint32_t s_pde = (first_address >> 21) & 0x1FF;
|
|
||||||
const uint32_t s_pte = (first_address >> 12) & 0x1FF;
|
|
||||||
|
|
||||||
const uint32_t e_pdpte = (last_address >> 30) & 0x1FF;
|
|
||||||
const uint32_t e_pde = (last_address >> 21) & 0x1FF;
|
|
||||||
const uint32_t e_pte = (last_address >> 12) & 0x1FF;
|
|
||||||
|
|
||||||
SpinLockGuard _(m_lock);
|
|
||||||
|
|
||||||
// Try to find free page that can be mapped without
|
|
||||||
// allocations (page table with unused entries)
|
|
||||||
uint64_t* pdpt = reinterpret_cast<uint64_t*>(P2V(m_highest_paging_struct));
|
|
||||||
for (uint32_t pdpte = s_pdpte; pdpte < 4; pdpte++)
|
|
||||||
{
|
|
||||||
if (pdpte > e_pdpte)
|
|
||||||
break;
|
|
||||||
if (!(pdpt[pdpte] & Flags::Present))
|
|
||||||
continue;
|
|
||||||
uint64_t* pd = reinterpret_cast<uint64_t*>(P2V(pdpt[pdpte] & PAGE_ADDR_MASK));
|
|
||||||
for (uint32_t pde = s_pde; pde < 512; pde++)
|
|
||||||
{
|
|
||||||
if (pdpte == e_pdpte && pde > e_pde)
|
|
||||||
break;
|
|
||||||
if (!(pd[pde] & Flags::Present))
|
|
||||||
continue;
|
|
||||||
uint64_t* pt = (uint64_t*)P2V(pd[pde] & PAGE_ADDR_MASK);
|
|
||||||
for (uint32_t pte = s_pte; pte < 512; pte++)
|
|
||||||
{
|
|
||||||
if (pdpte == e_pdpte && pde == e_pde && pte >= e_pte)
|
|
||||||
break;
|
|
||||||
if (!(pt[pte] & Flags::Used))
|
|
||||||
{
|
|
||||||
vaddr_t vaddr = 0;
|
|
||||||
vaddr |= (vaddr_t)pdpte << 30;
|
|
||||||
vaddr |= (vaddr_t)pde << 21;
|
|
||||||
vaddr |= (vaddr_t)pte << 12;
|
|
||||||
ASSERT(reserve_page(vaddr));
|
|
||||||
return vaddr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find any free page
|
|
||||||
for (vaddr_t vaddr = first_address; vaddr < last_address; vaddr += PAGE_SIZE)
|
|
||||||
{
|
|
||||||
if (is_page_free(vaddr))
|
|
||||||
{
|
|
||||||
ASSERT(reserve_page(vaddr));
|
|
||||||
return vaddr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ASSERT_NOT_REACHED();
|
|
||||||
}
|
|
||||||
|
|
||||||
vaddr_t PageTable::reserve_free_contiguous_pages(size_t page_count, vaddr_t first_address, vaddr_t last_address)
|
|
||||||
{
|
|
||||||
if (first_address >= KERNEL_OFFSET && first_address < (vaddr_t)g_kernel_start)
|
|
||||||
first_address = (vaddr_t)g_kernel_start;
|
|
||||||
if (size_t rem = first_address % PAGE_SIZE)
|
|
||||||
first_address += PAGE_SIZE - rem;
|
|
||||||
if (size_t rem = last_address % PAGE_SIZE)
|
|
||||||
last_address -= rem;
|
|
||||||
|
|
||||||
SpinLockGuard _(m_lock);
|
|
||||||
|
|
||||||
for (vaddr_t vaddr = first_address; vaddr < last_address;)
|
|
||||||
{
|
|
||||||
bool valid { true };
|
|
||||||
for (size_t page = 0; page < page_count; page++)
|
|
||||||
{
|
|
||||||
if (!is_page_free(vaddr + page * PAGE_SIZE))
|
|
||||||
{
|
|
||||||
vaddr += (page + 1) * PAGE_SIZE;
|
|
||||||
valid = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (valid)
|
|
||||||
{
|
|
||||||
ASSERT(reserve_range(vaddr, page_count * PAGE_SIZE));
|
|
||||||
return vaddr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ASSERT_NOT_REACHED();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void dump_range(vaddr_t start, vaddr_t end, PageTable::flags_t flags)
|
|
||||||
{
|
|
||||||
if (start == 0)
|
|
||||||
return;
|
|
||||||
dprintln("{}-{}: {}{}{}{}",
|
|
||||||
(void*)(start), (void*)(end - 1),
|
|
||||||
flags & PageTable::Flags::Execute ? 'x' : '-',
|
|
||||||
flags & PageTable::Flags::UserSupervisor ? 'u' : '-',
|
|
||||||
flags & PageTable::Flags::ReadWrite ? 'w' : '-',
|
|
||||||
flags & PageTable::Flags::Present ? 'r' : '-'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
void PageTable::debug_dump()
|
|
||||||
{
|
|
||||||
SpinLockGuard _(m_lock);
|
|
||||||
|
|
||||||
flags_t flags = 0;
|
|
||||||
vaddr_t start = 0;
|
|
||||||
|
|
||||||
uint64_t* pdpt = reinterpret_cast<uint64_t*>(P2V(m_highest_paging_struct));
|
|
||||||
for (uint32_t pdpte = 0; pdpte < 4; pdpte++)
|
|
||||||
{
|
|
||||||
if (!(pdpt[pdpte] & Flags::Present))
|
|
||||||
{
|
|
||||||
dump_range(start, (pdpte << 30), flags);
|
|
||||||
start = 0;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
uint64_t* pd = (uint64_t*)P2V(pdpt[pdpte] & PAGE_ADDR_MASK);
|
|
||||||
for (uint64_t pde = 0; pde < 512; pde++)
|
|
||||||
{
|
|
||||||
if (!(pd[pde] & Flags::Present))
|
|
||||||
{
|
|
||||||
dump_range(start, (pdpte << 30) | (pde << 21), flags);
|
|
||||||
start = 0;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
uint64_t* pt = (uint64_t*)P2V(pd[pde] & PAGE_ADDR_MASK);
|
|
||||||
for (uint64_t pte = 0; pte < 512; pte++)
|
|
||||||
{
|
|
||||||
if (parse_flags(pt[pte]) != flags)
|
|
||||||
{
|
|
||||||
dump_range(start, (pdpte << 30) | (pde << 21) | (pte << 12), flags);
|
|
||||||
start = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(pt[pte] & Flags::Used))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (start == 0)
|
|
||||||
{
|
|
||||||
flags = parse_flags(pt[pte]);
|
|
||||||
start = (pdpte << 30) | (pde << 21) | (pte << 12);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,35 +0,0 @@
|
||||||
.section .userspace, "ax"
|
|
||||||
|
|
||||||
// stack contains
|
|
||||||
// return address
|
|
||||||
// signal number
|
|
||||||
// signal handler
|
|
||||||
|
|
||||||
.global signal_trampoline
|
|
||||||
signal_trampoline:
|
|
||||||
pushl %ebp
|
|
||||||
movl %esp, %ebp
|
|
||||||
|
|
||||||
pusha
|
|
||||||
|
|
||||||
movl 40(%esp), %edi
|
|
||||||
movl 36(%esp), %eax
|
|
||||||
|
|
||||||
// align stack to 16 bytes
|
|
||||||
movl %esp, %ebx
|
|
||||||
andl $0x0F, %ebx
|
|
||||||
subl %ebx, %esp
|
|
||||||
|
|
||||||
subl $12, %esp
|
|
||||||
pushl %edi
|
|
||||||
call *%eax
|
|
||||||
addl $16, %esp
|
|
||||||
|
|
||||||
// restore stack
|
|
||||||
addl %ebx, %esp
|
|
||||||
popa
|
|
||||||
|
|
||||||
leave
|
|
||||||
addl $8, %esp
|
|
||||||
|
|
||||||
ret
|
|
|
@ -1,92 +0,0 @@
|
||||||
// arguments in EAX, EBX, ECX, EDX, ESI, EDI
|
|
||||||
.global asm_syscall_handler
|
|
||||||
asm_syscall_handler:
|
|
||||||
# save segment registers
|
|
||||||
pushw %ds
|
|
||||||
pushw %es
|
|
||||||
pushw %fs
|
|
||||||
pushw %gs
|
|
||||||
|
|
||||||
# save general purpose registers
|
|
||||||
pushl %ebx
|
|
||||||
pushl %ecx
|
|
||||||
pushl %edx
|
|
||||||
pushl %edi
|
|
||||||
pushl %esi
|
|
||||||
pushl %ebp
|
|
||||||
|
|
||||||
# align stack
|
|
||||||
movl %esp, %ebp
|
|
||||||
subl $15, %esp
|
|
||||||
andl $0xFFFFFFF0, %esp
|
|
||||||
|
|
||||||
# push arguments
|
|
||||||
subl $4, %esp
|
|
||||||
pushl %ebp
|
|
||||||
addl $32, (%esp)
|
|
||||||
pushl %edi
|
|
||||||
pushl %esi
|
|
||||||
pushl %edx
|
|
||||||
pushl %ecx
|
|
||||||
pushl %ebx
|
|
||||||
pushl %eax
|
|
||||||
|
|
||||||
# load kernel segments
|
|
||||||
movw $0x10, %ax
|
|
||||||
movw %ax, %ds
|
|
||||||
movw %ax, %es
|
|
||||||
movw %ax, %fs
|
|
||||||
movw $0x28, %ax
|
|
||||||
movw %ax, %gs
|
|
||||||
|
|
||||||
call cpp_syscall_handler
|
|
||||||
|
|
||||||
movl %ebp, %esp
|
|
||||||
|
|
||||||
# restore general purpose registers
|
|
||||||
popl %ebp
|
|
||||||
popl %esi
|
|
||||||
popl %edi
|
|
||||||
popl %edx
|
|
||||||
popl %ecx
|
|
||||||
popl %ebx
|
|
||||||
|
|
||||||
# restore segment registers
|
|
||||||
popw %gs
|
|
||||||
popw %fs
|
|
||||||
popw %es
|
|
||||||
popw %ds
|
|
||||||
|
|
||||||
iret
|
|
||||||
|
|
||||||
.global sys_fork_trampoline
|
|
||||||
sys_fork_trampoline:
|
|
||||||
pushl %ebp
|
|
||||||
pushl %ebx
|
|
||||||
pushl %esi
|
|
||||||
pushl %edi
|
|
||||||
|
|
||||||
call read_ip
|
|
||||||
testl %eax, %eax
|
|
||||||
jz .reload_stack
|
|
||||||
|
|
||||||
movl %esp, %ebx
|
|
||||||
|
|
||||||
subl $8, %esp
|
|
||||||
pushl %eax
|
|
||||||
pushl %ebx
|
|
||||||
call sys_fork
|
|
||||||
addl $16, %esp
|
|
||||||
|
|
||||||
.done:
|
|
||||||
popl %edi
|
|
||||||
popl %esi
|
|
||||||
popl %ebx
|
|
||||||
popl %ebp
|
|
||||||
ret
|
|
||||||
|
|
||||||
.reload_stack:
|
|
||||||
call get_thread_start_sp
|
|
||||||
movl %eax, %esp
|
|
||||||
xorl %eax, %eax
|
|
||||||
jmp .done
|
|
|
@ -1,69 +0,0 @@
|
||||||
# uint32_t read_ip()
|
|
||||||
.global read_ip
|
|
||||||
read_ip:
|
|
||||||
popl %eax
|
|
||||||
jmp *%eax
|
|
||||||
|
|
||||||
# void start_kernel_thread()
|
|
||||||
.global start_kernel_thread
|
|
||||||
start_kernel_thread:
|
|
||||||
call get_thread_start_sp
|
|
||||||
movl %eax, %esp
|
|
||||||
|
|
||||||
# STACK LAYOUT
|
|
||||||
# on_exit arg
|
|
||||||
# on_exit func
|
|
||||||
# entry arg
|
|
||||||
# entry func
|
|
||||||
|
|
||||||
movl 4(%esp), %edi
|
|
||||||
movl 0(%esp), %esi
|
|
||||||
|
|
||||||
subl $12, %esp
|
|
||||||
pushl %edi
|
|
||||||
sti
|
|
||||||
call *%esi
|
|
||||||
addl $16, %esp
|
|
||||||
|
|
||||||
movl 12(%esp), %edi
|
|
||||||
movl 8(%esp), %esi
|
|
||||||
|
|
||||||
subl $12, %esp
|
|
||||||
pushl %edi
|
|
||||||
call *%esi
|
|
||||||
addl $16, %esp
|
|
||||||
|
|
||||||
|
|
||||||
.global start_userspace_thread
|
|
||||||
start_userspace_thread:
|
|
||||||
call get_thread_start_sp
|
|
||||||
movl %eax, %esp
|
|
||||||
|
|
||||||
# STACK LAYOUT
|
|
||||||
# entry
|
|
||||||
# argc
|
|
||||||
# argv
|
|
||||||
# envp
|
|
||||||
# userspace stack
|
|
||||||
|
|
||||||
call get_userspace_thread_stack_top
|
|
||||||
|
|
||||||
movw $(0x20 | 3), %bx
|
|
||||||
movw %bx, %ds
|
|
||||||
movw %bx, %es
|
|
||||||
movw %bx, %fs
|
|
||||||
movw %bx, %gs
|
|
||||||
xorw %bx, %bx
|
|
||||||
|
|
||||||
popl %edi
|
|
||||||
popl %esi
|
|
||||||
popl %edx
|
|
||||||
popl %ecx
|
|
||||||
popl %ebx
|
|
||||||
|
|
||||||
pushl $(0x20 | 3)
|
|
||||||
pushl %eax
|
|
||||||
pushl $0x202
|
|
||||||
pushl $(0x18 | 3)
|
|
||||||
pushl %ebx
|
|
||||||
iret
|
|
|
@ -1,316 +0,0 @@
|
||||||
.set PG_PRESENT, 1<<0
|
|
||||||
.set PG_READ_WRITE, 1<<1
|
|
||||||
.set PG_PAGE_SIZE, 1<<7
|
|
||||||
|
|
||||||
.set FB_WIDTH, 800
|
|
||||||
.set FB_HEIGHT, 600
|
|
||||||
.set FB_BPP, 32
|
|
||||||
|
|
||||||
#define KERNEL_OFFSET 0xC0000000
|
|
||||||
#define V2P(vaddr) ((vaddr) - KERNEL_OFFSET)
|
|
||||||
|
|
||||||
.code32
|
|
||||||
|
|
||||||
# multiboot2 header
|
|
||||||
.section .multiboot, "aw"
|
|
||||||
.align 8
|
|
||||||
multiboot2_start:
|
|
||||||
.long 0xE85250D6
|
|
||||||
.long 0
|
|
||||||
.long multiboot2_end - multiboot2_start
|
|
||||||
.long -(0xE85250D6 + (multiboot2_end - multiboot2_start))
|
|
||||||
|
|
||||||
# framebuffer tag
|
|
||||||
.align 8
|
|
||||||
.short 5
|
|
||||||
.short 0
|
|
||||||
.long 20
|
|
||||||
.long FB_WIDTH
|
|
||||||
.long FB_HEIGHT
|
|
||||||
.long FB_BPP
|
|
||||||
|
|
||||||
# legacy start
|
|
||||||
.align 8
|
|
||||||
.short 3
|
|
||||||
.short 0
|
|
||||||
.long 12
|
|
||||||
.long V2P(_start)
|
|
||||||
|
|
||||||
.align 8
|
|
||||||
.short 0
|
|
||||||
.short 0
|
|
||||||
.long 8
|
|
||||||
multiboot2_end:
|
|
||||||
|
|
||||||
.section .bananboot, "aw"
|
|
||||||
.align 8
|
|
||||||
bananboot_start:
|
|
||||||
.long 0xBABAB007
|
|
||||||
.long -(0xBABAB007 + FB_WIDTH + FB_HEIGHT + FB_BPP)
|
|
||||||
.long FB_WIDTH
|
|
||||||
.long FB_HEIGHT
|
|
||||||
.long FB_BPP
|
|
||||||
bananboot_end:
|
|
||||||
|
|
||||||
.section .bss, "aw", @nobits
|
|
||||||
.align 4096
|
|
||||||
boot_stack_bottom:
|
|
||||||
.skip 4096 * 4
|
|
||||||
boot_stack_top:
|
|
||||||
|
|
||||||
.global g_kernel_cmdline
|
|
||||||
g_kernel_cmdline:
|
|
||||||
.skip 4096
|
|
||||||
|
|
||||||
bootloader_magic:
|
|
||||||
.skip 8
|
|
||||||
bootloader_info:
|
|
||||||
.skip 8
|
|
||||||
|
|
||||||
.section .data
|
|
||||||
|
|
||||||
# Map first GiB to 0x00000000 and 0xC0000000
|
|
||||||
.align 32
|
|
||||||
boot_pdpt:
|
|
||||||
.long V2P(boot_pd) + (PG_PRESENT)
|
|
||||||
.long 0
|
|
||||||
.quad 0
|
|
||||||
.quad 0
|
|
||||||
.long V2P(boot_pd) + (PG_PRESENT)
|
|
||||||
.long 0
|
|
||||||
.align 4096
|
|
||||||
boot_pd:
|
|
||||||
.set i, 0
|
|
||||||
.rept 512
|
|
||||||
.long V2P(boot_pts) + i + (PG_READ_WRITE | PG_PRESENT)
|
|
||||||
.long 0
|
|
||||||
.set i, i + 0x1000
|
|
||||||
.endr
|
|
||||||
boot_pts:
|
|
||||||
.set i, 0
|
|
||||||
.rept 512
|
|
||||||
.rept 512
|
|
||||||
.long i + (PG_READ_WRITE | PG_PRESENT)
|
|
||||||
.long 0
|
|
||||||
.set i, i + 0x1000
|
|
||||||
.endr
|
|
||||||
.endr
|
|
||||||
|
|
||||||
boot_gdt:
|
|
||||||
.quad 0x0000000000000000 # null descriptor
|
|
||||||
.quad 0x00CF9A000000FFFF # kernel code
|
|
||||||
.quad 0x00CF92000000FFFF # kernel data
|
|
||||||
boot_gdtr:
|
|
||||||
.short . - boot_gdt - 1
|
|
||||||
.long V2P(boot_gdt)
|
|
||||||
|
|
||||||
.global g_ap_startup_done
|
|
||||||
g_ap_startup_done:
|
|
||||||
.byte 0
|
|
||||||
.global g_ap_running_count
|
|
||||||
g_ap_running_count:
|
|
||||||
.byte 0
|
|
||||||
.global g_ap_stack_loaded
|
|
||||||
g_ap_stack_loaded:
|
|
||||||
.byte 0
|
|
||||||
|
|
||||||
.section .text
|
|
||||||
|
|
||||||
has_cpuid:
|
|
||||||
pushfl
|
|
||||||
pushfl
|
|
||||||
xorl $0x00200000, (%esp)
|
|
||||||
popfl
|
|
||||||
pushfl
|
|
||||||
popl %eax
|
|
||||||
xorl (%esp), %eax
|
|
||||||
popfl
|
|
||||||
testl $0x00200000, %eax
|
|
||||||
ret
|
|
||||||
|
|
||||||
has_pae:
|
|
||||||
movl $0, %eax
|
|
||||||
cpuid
|
|
||||||
testl $(1 << 6), %edx
|
|
||||||
ret
|
|
||||||
|
|
||||||
has_sse:
|
|
||||||
movl $1, %eax
|
|
||||||
cpuid
|
|
||||||
testl $(1 << 25), %edx
|
|
||||||
ret
|
|
||||||
|
|
||||||
check_requirements:
|
|
||||||
call has_cpuid
|
|
||||||
jz .exit
|
|
||||||
call has_pae
|
|
||||||
jz .exit
|
|
||||||
call has_sse
|
|
||||||
jz .exit
|
|
||||||
ret
|
|
||||||
.exit:
|
|
||||||
jmp system_halt
|
|
||||||
|
|
||||||
enable_sse:
|
|
||||||
movl %cr0, %eax
|
|
||||||
andw $0xFFFB, %ax
|
|
||||||
orw $0x0002, %ax
|
|
||||||
movl %eax, %cr0
|
|
||||||
movl %cr4, %eax
|
|
||||||
orw $0x0600, %ax
|
|
||||||
movl %eax, %cr4
|
|
||||||
ret
|
|
||||||
|
|
||||||
initialize_paging:
|
|
||||||
# enable PAE
|
|
||||||
movl %cr4, %ecx
|
|
||||||
orl $(1 << 5), %ecx
|
|
||||||
movl %ecx, %cr4
|
|
||||||
|
|
||||||
# load page tables
|
|
||||||
movl $V2P(boot_pdpt), %ecx
|
|
||||||
movl %ecx, %cr3
|
|
||||||
|
|
||||||
# enable paging
|
|
||||||
movl %cr0, %ecx
|
|
||||||
orl $(1 << 31), %ecx
|
|
||||||
movl %ecx, %cr0
|
|
||||||
|
|
||||||
ret
|
|
||||||
|
|
||||||
.global _start
|
|
||||||
.type _start, @function
|
|
||||||
_start:
|
|
||||||
cli; cld
|
|
||||||
|
|
||||||
# save bootloader magic and info
|
|
||||||
movl %eax, V2P(bootloader_magic)
|
|
||||||
movl %ebx, V2P(bootloader_info)
|
|
||||||
|
|
||||||
# load boot stack
|
|
||||||
movl $V2P(boot_stack_top), %esp
|
|
||||||
|
|
||||||
# load boot GDT
|
|
||||||
lgdt V2P(boot_gdtr)
|
|
||||||
ljmpl $0x08, $V2P(gdt_flush)
|
|
||||||
gdt_flush:
|
|
||||||
# set correct segment registers
|
|
||||||
movw $0x10, %ax
|
|
||||||
movw %ax, %ds
|
|
||||||
movw %ax, %ss
|
|
||||||
movw %ax, %es
|
|
||||||
|
|
||||||
# do processor initialization
|
|
||||||
call check_requirements
|
|
||||||
call enable_sse
|
|
||||||
call initialize_paging
|
|
||||||
|
|
||||||
# load higher half stack pointer
|
|
||||||
movl $boot_stack_top, %esp
|
|
||||||
|
|
||||||
# jump to higher half
|
|
||||||
leal higher_half, %ecx
|
|
||||||
jmp *%ecx
|
|
||||||
|
|
||||||
higher_half:
|
|
||||||
# call global constuctors
|
|
||||||
call _init
|
|
||||||
|
|
||||||
movl $g_init_array_start, %ebx
|
|
||||||
jmp 2f
|
|
||||||
1: call *(%ebx)
|
|
||||||
addl $4, %ebx
|
|
||||||
2: cmpl $g_init_array_end, %ebx
|
|
||||||
jne 1b
|
|
||||||
|
|
||||||
# call to the kernel itself (clear ebp for stacktrace)
|
|
||||||
xorl %ebp, %ebp
|
|
||||||
|
|
||||||
subl $8, %esp
|
|
||||||
pushl bootloader_info
|
|
||||||
pushl bootloader_magic
|
|
||||||
call kernel_main
|
|
||||||
addl $16, %esp
|
|
||||||
|
|
||||||
# call global destructors
|
|
||||||
call _fini
|
|
||||||
|
|
||||||
system_halt:
|
|
||||||
xchgw %bx, %bx
|
|
||||||
cli
|
|
||||||
1: hlt
|
|
||||||
jmp 1b
|
|
||||||
|
|
||||||
|
|
||||||
#define AP_V2P(vaddr) ((vaddr) - ap_trampoline + 0xF000)
|
|
||||||
|
|
||||||
.section .ap_init, "ax"
|
|
||||||
|
|
||||||
.code16
|
|
||||||
.global ap_trampoline
|
|
||||||
ap_trampoline:
|
|
||||||
jmp 1f
|
|
||||||
|
|
||||||
.align 8
|
|
||||||
ap_stack_ptr:
|
|
||||||
.skip 4
|
|
||||||
ap_stack_loaded:
|
|
||||||
.skip 1
|
|
||||||
|
|
||||||
1: cli; cld
|
|
||||||
ljmpl $0x00, $AP_V2P(ap_cs_clear)
|
|
||||||
|
|
||||||
ap_cs_clear:
|
|
||||||
# load ap gdt and enter protected mode
|
|
||||||
lgdt AP_V2P(ap_gdtr)
|
|
||||||
movl %cr0, %eax
|
|
||||||
orb $1, %al
|
|
||||||
movl %eax, %cr0
|
|
||||||
ljmpl $0x08, $AP_V2P(ap_protected_mode)
|
|
||||||
|
|
||||||
.code32
|
|
||||||
ap_protected_mode:
|
|
||||||
movw $0x10, %ax
|
|
||||||
movw %ax, %ds
|
|
||||||
movw %ax, %ss
|
|
||||||
movw %ax, %es
|
|
||||||
|
|
||||||
movl AP_V2P(ap_stack_ptr), %esp
|
|
||||||
movb $1, AP_V2P(ap_stack_loaded)
|
|
||||||
|
|
||||||
leal V2P(enable_sse), %ecx; call *%ecx
|
|
||||||
leal V2P(initialize_paging), %ecx; call *%ecx
|
|
||||||
|
|
||||||
# load boot gdt and enter long mode
|
|
||||||
lgdt V2P(boot_gdtr)
|
|
||||||
ljmpl $0x08, $AP_V2P(ap_flush_gdt)
|
|
||||||
|
|
||||||
ap_flush_gdt:
|
|
||||||
# move stack pointer to higher half
|
|
||||||
movl %esp, %esp
|
|
||||||
addl $KERNEL_OFFSET, %esp
|
|
||||||
|
|
||||||
# jump to higher half
|
|
||||||
leal ap_higher_half, %ecx
|
|
||||||
jmp *%ecx
|
|
||||||
|
|
||||||
ap_higher_half:
|
|
||||||
# clear rbp for stacktrace
|
|
||||||
xorl %ebp, %ebp
|
|
||||||
|
|
||||||
1: pause
|
|
||||||
cmpb $0, g_ap_startup_done
|
|
||||||
jz 1b
|
|
||||||
|
|
||||||
lock incb g_ap_running_count
|
|
||||||
|
|
||||||
call ap_main
|
|
||||||
jmp system_halt
|
|
||||||
|
|
||||||
ap_gdt:
|
|
||||||
.quad 0x0000000000000000 # null descriptor
|
|
||||||
.quad 0x00CF9A000000FFFF # 32 bit code
|
|
||||||
.quad 0x00CF92000000FFFF # 32 bit data
|
|
||||||
ap_gdtr:
|
|
||||||
.short . - ap_gdt - 1
|
|
||||||
.long ap_gdt
|
|
|
@ -1,396 +0,0 @@
|
||||||
.macro push_userspace
|
|
||||||
pushw %gs
|
|
||||||
pushw %fs
|
|
||||||
pushw %es
|
|
||||||
pushw %ds
|
|
||||||
pushal
|
|
||||||
.endm
|
|
||||||
|
|
||||||
.macro load_kernel_segments
|
|
||||||
movw $0x10, %ax
|
|
||||||
movw %ax, %ds
|
|
||||||
movw %ax, %es
|
|
||||||
movw %ax, %fs
|
|
||||||
|
|
||||||
movw $0x28, %ax
|
|
||||||
movw %ax, %gs
|
|
||||||
.endm
|
|
||||||
|
|
||||||
.macro pop_userspace
|
|
||||||
popal
|
|
||||||
popw %ds
|
|
||||||
popw %es
|
|
||||||
popw %fs
|
|
||||||
popw %gs
|
|
||||||
.endm
|
|
||||||
|
|
||||||
isr_stub:
|
|
||||||
push_userspace
|
|
||||||
load_kernel_segments
|
|
||||||
|
|
||||||
movl %cr0, %eax; pushl %eax
|
|
||||||
movl %cr2, %eax; pushl %eax
|
|
||||||
movl %cr3, %eax; pushl %eax
|
|
||||||
movl %cr4, %eax; pushl %eax
|
|
||||||
|
|
||||||
movl %esp, %eax // register ptr
|
|
||||||
leal 64(%esp), %ebx // interrupt stack ptr
|
|
||||||
movl 60(%esp), %ecx // error code
|
|
||||||
movl 56(%esp), %edx // isr number
|
|
||||||
|
|
||||||
movl %esp, %ebp
|
|
||||||
subl $15, %esp
|
|
||||||
andl $0xFFFFFFF0, %esp
|
|
||||||
|
|
||||||
pushl %eax
|
|
||||||
pushl %ebx
|
|
||||||
pushl %ecx
|
|
||||||
pushl %edx
|
|
||||||
call cpp_isr_handler
|
|
||||||
|
|
||||||
movl %ebp, %esp
|
|
||||||
addl $16, %esp
|
|
||||||
|
|
||||||
pop_userspace
|
|
||||||
addl $8, %esp
|
|
||||||
iret
|
|
||||||
|
|
||||||
irq_stub:
|
|
||||||
push_userspace
|
|
||||||
load_kernel_segments
|
|
||||||
|
|
||||||
movl 40(%esp), %eax # interrupt number
|
|
||||||
|
|
||||||
movl %esp, %ebp
|
|
||||||
subl $15, %esp
|
|
||||||
andl $0xFFFFFFF0, %esp
|
|
||||||
|
|
||||||
subl $12, %esp
|
|
||||||
pushl %eax
|
|
||||||
call cpp_irq_handler
|
|
||||||
|
|
||||||
movl %ebp, %esp
|
|
||||||
|
|
||||||
pop_userspace
|
|
||||||
addl $8, %esp
|
|
||||||
iret
|
|
||||||
|
|
||||||
.global asm_yield_handler
|
|
||||||
asm_yield_handler:
|
|
||||||
# This can only be called from kernel, so no segment saving is needed
|
|
||||||
pushal
|
|
||||||
|
|
||||||
movl %esp, %eax # interrupt registers ptr
|
|
||||||
leal 32(%esp), %ebx # interrupt stack ptr
|
|
||||||
|
|
||||||
movl %esp, %ebp
|
|
||||||
subl $15, %esp
|
|
||||||
andl $0xFFFFFFF0, %esp
|
|
||||||
|
|
||||||
subl $8, %esp
|
|
||||||
pushl %eax
|
|
||||||
pushl %ebx
|
|
||||||
call cpp_yield_handler
|
|
||||||
|
|
||||||
movl %ebp, %esp
|
|
||||||
|
|
||||||
popal
|
|
||||||
iret
|
|
||||||
|
|
||||||
.global asm_ipi_handler
|
|
||||||
asm_ipi_handler:
|
|
||||||
push_userspace
|
|
||||||
load_kernel_segments
|
|
||||||
|
|
||||||
movl %esp, %ebp
|
|
||||||
subl $15, %esp
|
|
||||||
andl $0xFFFFFFF0, %esp
|
|
||||||
|
|
||||||
call cpp_ipi_handler
|
|
||||||
|
|
||||||
movl %ebp, %esp
|
|
||||||
|
|
||||||
pop_userspace
|
|
||||||
iret
|
|
||||||
|
|
||||||
|
|
||||||
.global asm_timer_handler
|
|
||||||
asm_timer_handler:
|
|
||||||
push_userspace
|
|
||||||
load_kernel_segments
|
|
||||||
|
|
||||||
movl %esp, %ebp
|
|
||||||
subl $15, %esp
|
|
||||||
andl $0xFFFFFFF0, %esp
|
|
||||||
|
|
||||||
call cpp_timer_handler
|
|
||||||
|
|
||||||
movl %ebp, %esp
|
|
||||||
|
|
||||||
pop_userspace
|
|
||||||
iret
|
|
||||||
|
|
||||||
.macro isr n
|
|
||||||
.global isr\n
|
|
||||||
isr\n:
|
|
||||||
pushl $0
|
|
||||||
pushl $\n
|
|
||||||
jmp isr_stub
|
|
||||||
.endm
|
|
||||||
|
|
||||||
.macro isr_err n
|
|
||||||
.global isr\n
|
|
||||||
isr\n:
|
|
||||||
pushl $\n
|
|
||||||
jmp isr_stub
|
|
||||||
.endm
|
|
||||||
|
|
||||||
.macro irq n
|
|
||||||
.global irq\n
|
|
||||||
irq\n:
|
|
||||||
pushl $0
|
|
||||||
pushl $\n
|
|
||||||
jmp irq_stub
|
|
||||||
.endm
|
|
||||||
|
|
||||||
isr 0
|
|
||||||
isr 1
|
|
||||||
isr 2
|
|
||||||
isr 3
|
|
||||||
isr 4
|
|
||||||
isr 5
|
|
||||||
isr 6
|
|
||||||
isr 7
|
|
||||||
isr_err 8
|
|
||||||
isr 9
|
|
||||||
isr_err 10
|
|
||||||
isr_err 11
|
|
||||||
isr_err 12
|
|
||||||
isr_err 13
|
|
||||||
isr_err 14
|
|
||||||
isr 15
|
|
||||||
isr 16
|
|
||||||
isr_err 17
|
|
||||||
isr 18
|
|
||||||
isr 19
|
|
||||||
isr 20
|
|
||||||
isr 21
|
|
||||||
isr 22
|
|
||||||
isr 23
|
|
||||||
isr 24
|
|
||||||
isr 25
|
|
||||||
isr 26
|
|
||||||
isr 27
|
|
||||||
isr 28
|
|
||||||
isr 29
|
|
||||||
isr 30
|
|
||||||
isr 31
|
|
||||||
|
|
||||||
irq 0
|
|
||||||
irq 1
|
|
||||||
irq 2
|
|
||||||
irq 3
|
|
||||||
irq 4
|
|
||||||
irq 5
|
|
||||||
irq 6
|
|
||||||
irq 7
|
|
||||||
irq 8
|
|
||||||
irq 9
|
|
||||||
irq 10
|
|
||||||
irq 11
|
|
||||||
irq 12
|
|
||||||
irq 13
|
|
||||||
irq 14
|
|
||||||
irq 15
|
|
||||||
irq 16
|
|
||||||
irq 17
|
|
||||||
irq 18
|
|
||||||
irq 19
|
|
||||||
irq 20
|
|
||||||
irq 21
|
|
||||||
irq 22
|
|
||||||
irq 23
|
|
||||||
irq 24
|
|
||||||
irq 25
|
|
||||||
irq 26
|
|
||||||
irq 27
|
|
||||||
irq 28
|
|
||||||
irq 29
|
|
||||||
irq 30
|
|
||||||
irq 31
|
|
||||||
irq 32
|
|
||||||
irq 33
|
|
||||||
irq 34
|
|
||||||
irq 35
|
|
||||||
irq 36
|
|
||||||
irq 37
|
|
||||||
irq 38
|
|
||||||
irq 39
|
|
||||||
irq 40
|
|
||||||
irq 41
|
|
||||||
irq 42
|
|
||||||
irq 43
|
|
||||||
irq 44
|
|
||||||
irq 45
|
|
||||||
irq 46
|
|
||||||
irq 47
|
|
||||||
irq 48
|
|
||||||
irq 49
|
|
||||||
irq 50
|
|
||||||
irq 51
|
|
||||||
irq 52
|
|
||||||
irq 53
|
|
||||||
irq 54
|
|
||||||
irq 55
|
|
||||||
irq 56
|
|
||||||
irq 57
|
|
||||||
irq 58
|
|
||||||
irq 59
|
|
||||||
irq 60
|
|
||||||
irq 61
|
|
||||||
irq 62
|
|
||||||
irq 63
|
|
||||||
irq 64
|
|
||||||
irq 65
|
|
||||||
irq 66
|
|
||||||
irq 67
|
|
||||||
irq 68
|
|
||||||
irq 69
|
|
||||||
irq 70
|
|
||||||
irq 71
|
|
||||||
irq 72
|
|
||||||
irq 73
|
|
||||||
irq 74
|
|
||||||
irq 75
|
|
||||||
irq 76
|
|
||||||
irq 77
|
|
||||||
irq 78
|
|
||||||
irq 79
|
|
||||||
irq 80
|
|
||||||
irq 81
|
|
||||||
irq 82
|
|
||||||
irq 83
|
|
||||||
irq 84
|
|
||||||
irq 85
|
|
||||||
irq 86
|
|
||||||
irq 87
|
|
||||||
irq 88
|
|
||||||
irq 89
|
|
||||||
irq 90
|
|
||||||
irq 91
|
|
||||||
irq 92
|
|
||||||
irq 93
|
|
||||||
irq 94
|
|
||||||
irq 95
|
|
||||||
irq 96
|
|
||||||
irq 97
|
|
||||||
irq 98
|
|
||||||
irq 99
|
|
||||||
irq 100
|
|
||||||
irq 101
|
|
||||||
irq 102
|
|
||||||
irq 103
|
|
||||||
irq 104
|
|
||||||
irq 105
|
|
||||||
irq 106
|
|
||||||
irq 107
|
|
||||||
irq 108
|
|
||||||
irq 109
|
|
||||||
irq 110
|
|
||||||
irq 111
|
|
||||||
irq 112
|
|
||||||
irq 113
|
|
||||||
irq 114
|
|
||||||
irq 115
|
|
||||||
irq 116
|
|
||||||
irq 117
|
|
||||||
irq 118
|
|
||||||
irq 119
|
|
||||||
irq 120
|
|
||||||
irq 121
|
|
||||||
irq 122
|
|
||||||
irq 123
|
|
||||||
irq 124
|
|
||||||
irq 125
|
|
||||||
irq 126
|
|
||||||
irq 127
|
|
||||||
irq 128
|
|
||||||
irq 129
|
|
||||||
irq 130
|
|
||||||
irq 131
|
|
||||||
irq 132
|
|
||||||
irq 133
|
|
||||||
irq 134
|
|
||||||
irq 135
|
|
||||||
irq 136
|
|
||||||
irq 137
|
|
||||||
irq 138
|
|
||||||
irq 139
|
|
||||||
irq 140
|
|
||||||
irq 141
|
|
||||||
irq 142
|
|
||||||
irq 143
|
|
||||||
irq 144
|
|
||||||
irq 145
|
|
||||||
irq 146
|
|
||||||
irq 147
|
|
||||||
irq 148
|
|
||||||
irq 149
|
|
||||||
irq 150
|
|
||||||
irq 151
|
|
||||||
irq 152
|
|
||||||
irq 153
|
|
||||||
irq 154
|
|
||||||
irq 155
|
|
||||||
irq 156
|
|
||||||
irq 157
|
|
||||||
irq 158
|
|
||||||
irq 159
|
|
||||||
irq 160
|
|
||||||
irq 161
|
|
||||||
irq 162
|
|
||||||
irq 163
|
|
||||||
irq 164
|
|
||||||
irq 165
|
|
||||||
irq 166
|
|
||||||
irq 167
|
|
||||||
irq 168
|
|
||||||
irq 169
|
|
||||||
irq 170
|
|
||||||
irq 171
|
|
||||||
irq 172
|
|
||||||
irq 173
|
|
||||||
irq 174
|
|
||||||
irq 175
|
|
||||||
irq 176
|
|
||||||
irq 177
|
|
||||||
irq 178
|
|
||||||
irq 179
|
|
||||||
irq 180
|
|
||||||
irq 181
|
|
||||||
irq 182
|
|
||||||
irq 183
|
|
||||||
irq 184
|
|
||||||
irq 185
|
|
||||||
irq 186
|
|
||||||
irq 187
|
|
||||||
irq 188
|
|
||||||
irq 189
|
|
||||||
irq 190
|
|
||||||
irq 191
|
|
||||||
irq 192
|
|
||||||
irq 193
|
|
||||||
irq 194
|
|
||||||
irq 195
|
|
||||||
irq 196
|
|
||||||
irq 197
|
|
||||||
irq 198
|
|
||||||
irq 199
|
|
||||||
irq 200
|
|
||||||
irq 201
|
|
||||||
irq 202
|
|
||||||
irq 203
|
|
||||||
irq 204
|
|
||||||
irq 205
|
|
||||||
irq 206
|
|
||||||
irq 207
|
|
|
@ -1,51 +0,0 @@
|
||||||
ENTRY (_start)
|
|
||||||
|
|
||||||
KERNEL_OFFSET = 0xC0000000;
|
|
||||||
|
|
||||||
SECTIONS
|
|
||||||
{
|
|
||||||
. = 0x00100000 + KERNEL_OFFSET;
|
|
||||||
|
|
||||||
g_kernel_start = .;
|
|
||||||
.text ALIGN(4K) : AT(ADDR(.text) - KERNEL_OFFSET)
|
|
||||||
{
|
|
||||||
g_kernel_execute_start = .;
|
|
||||||
*(.multiboot)
|
|
||||||
*(.bananboot)
|
|
||||||
*(.text.*)
|
|
||||||
}
|
|
||||||
.userspace ALIGN(4K) : AT(ADDR(.userspace) - KERNEL_OFFSET)
|
|
||||||
{
|
|
||||||
g_userspace_start = .;
|
|
||||||
*(.userspace)
|
|
||||||
g_userspace_end = .;
|
|
||||||
g_kernel_execute_end = .;
|
|
||||||
}
|
|
||||||
.ap_init ALIGN(4K) : AT(ADDR(.ap_init) - KERNEL_OFFSET)
|
|
||||||
{
|
|
||||||
g_ap_init_addr = .;
|
|
||||||
*(.ap_init)
|
|
||||||
}
|
|
||||||
.rodata ALIGN(4K) : AT(ADDR(.rodata) - KERNEL_OFFSET)
|
|
||||||
{
|
|
||||||
*(.rodata.*)
|
|
||||||
}
|
|
||||||
.init_array ALIGN(4K) : AT(ADDR(.init_array) - KERNEL_OFFSET)
|
|
||||||
{
|
|
||||||
g_init_array_start = .;
|
|
||||||
*(.init_array)
|
|
||||||
g_init_array_end = .;
|
|
||||||
}
|
|
||||||
.data ALIGN(4K) : AT(ADDR(.data) - KERNEL_OFFSET)
|
|
||||||
{
|
|
||||||
g_kernel_writable_start = .;
|
|
||||||
*(.data)
|
|
||||||
}
|
|
||||||
.bss ALIGN(4K) : AT(ADDR(.bss) - KERNEL_OFFSET)
|
|
||||||
{
|
|
||||||
*(COMMON)
|
|
||||||
*(.bss)
|
|
||||||
g_kernel_writable_end = .;
|
|
||||||
}
|
|
||||||
g_kernel_end = .;
|
|
||||||
}
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue