Compare commits
815 Commits
main
...
6d899aa6ce
| Author | SHA1 | Date | |
|---|---|---|---|
| 6d899aa6ce | |||
| 120f7329b1 | |||
| 4f25c20c97 | |||
| 5e396851f4 | |||
| a44482639d | |||
| 3bac19e518 | |||
| 4dbe15aa0e | |||
| 1c5985148c | |||
| ce2461d0e8 | |||
| 4e785a133c | |||
| 26c7aee327 | |||
| 0405461742 | |||
| 8a10853ba7 | |||
| 5d34cebeca | |||
| 3d899d2e44 | |||
| f72fdeeb59 | |||
| 382f9d9bb3 | |||
| bc1d1bf919 | |||
| f05b9a6877 | |||
| ea5ed3001e | |||
| f312c3a4d7 | |||
| 1af3ca19ab | |||
| 09fcc613c7 | |||
| 3940f53231 | |||
| 0757834176 | |||
| 3bffbe330d | |||
| 8d583c8b67 | |||
| 99bde9aa49 | |||
| 98d702ac60 | |||
| 1ec341e2dd | |||
| d09310f388 | |||
| 126edea119 | |||
| 74bfb930f2 | |||
| 091c5b6a66 | |||
| fda4a4ad24 | |||
| 8bb47aee02 | |||
| 1f794e4ac0 | |||
| e85f9ac6a1 | |||
| 6ee5576dcc | |||
| b890e2fc14 | |||
| 4f4b8ada8c | |||
| 9e4adc1264 | |||
| 7a54a088b4 | |||
| 15bb1804ef | |||
| e8890062d6 | |||
| 1e2c2fb973 | |||
| 988a4e1cd8 | |||
| adbbdf73c4 | |||
| e8d20bc653 | |||
| 00ee86920a | |||
| 51ad27ea3c | |||
| df69612bb1 | |||
| 5bfeb9f3ca | |||
| db5c24b2a5 | |||
| 781c950af6 | |||
| e2e5c31d54 | |||
| be3efb0b92 | |||
| 792bb2df1c | |||
| e01928d186 | |||
| 48980b56ab | |||
| b767317a7a | |||
| 6f8fce94a0 | |||
| 31aa157201 | |||
| 5977341610 | |||
| 76f17bd569 | |||
| 6b1b3d333c | |||
| cb65be3e33 | |||
| dafc016293 | |||
| c7b6fc950a | |||
| 45a6783c3d | |||
| 6b180da4e8 | |||
| cf4f5f64a5 | |||
| 5630f64175 | |||
| 1d61bccfc3 | |||
| f842a9255f | |||
| 72f3c378dd | |||
| 39be6ab099 | |||
| 773dcdd3a2 | |||
| f0820e6f24 | |||
| a2b5e71654 | |||
| d3e5c8e0aa | |||
| f4b901a646 | |||
| 790064d248 | |||
| ab8b77406d | |||
| 1b9e14a53b | |||
| d2cfc843e4 | |||
| 521513bed2 | |||
| 400db176d1 | |||
| 211cad03ff | |||
| 8a9816d6e0 | |||
| 03d2bf4002 | |||
| f071240b33 | |||
| 27364f64a6 | |||
| bcf62c5f2e | |||
| 4d6322ff9c | |||
| 2eef581737 | |||
| 7ce8e2d57b | |||
| e780eaa45f | |||
| 44cb0af64f | |||
| bb0989fdef | |||
| f0b6844feb | |||
| b712c70c75 | |||
| 797ca65c66 | |||
| 762b7a4276 | |||
| a511441f7e | |||
| cd61d710df | |||
| f88ad7efcd | |||
| 38320018dc | |||
| d883d212b1 | |||
| dedb2a2399 | |||
| 8604c55de8 | |||
| e949e8550c | |||
| eb5c6cf736 | |||
| 94ce2c97be | |||
| 3f164c6b82 | |||
| f953f3d3ff | |||
| 9fc75fe445 | |||
| 7a5bb6a56b | |||
| d54c6b7f6b | |||
| db5d6a7f80 | |||
| 4a92f44cf6 | |||
| 376b9f7272 | |||
| 7e9e4c47ae | |||
| 603fc200e6 | |||
| c11e84b248 | |||
| be13120554 | |||
| 9943edad5a | |||
| f4049be975 | |||
| 6cf7e01fe9 | |||
| b51d2f5295 | |||
| 49d941ad65 | |||
| a66c3bdae5 | |||
| 547eabb403 | |||
| 79851394b3 | |||
| fcdc922343 | |||
| 0b11d76576 | |||
| f7097398ca | |||
| 85b1252b9e | |||
| 1cd12b5f16 | |||
| c84b66d078 | |||
| 27adb9486b | |||
| 8d5369fafe | |||
| feafc57b63 | |||
| f9b347f9d9 | |||
| 6e1825d6b4 | |||
| ec2baeb276 | |||
| 6cb8bda6e1 | |||
| 05e57801e7 | |||
| b924c85669 | |||
| 09c1aa44d8 | |||
| 1d470fb5ba | |||
| b4e4f7a6cc | |||
| 55d30a7cc3 | |||
| b62186441b | |||
| 8caba1e774 | |||
| 7bdb428938 | |||
| 3ea707c0e7 | |||
| 18d582c6ce | |||
| 8b2bb95b81 | |||
| 2ef496a24a | |||
| c0a89e8951 | |||
| fc953df281 | |||
| fe2dca16f0 | |||
| f662aa6da2 | |||
| fee3677fb9 | |||
| 4818c6e3dd | |||
| 971eb737c1 | |||
| 9a3286ad57 | |||
| c9e09b840e | |||
| 8136248a67 | |||
| 0d67e46041 | |||
| bc1087f5a7 | |||
| 3a9c6fc51a | |||
| 7774f56ab6 | |||
| 14a608effd | |||
| 5fae3cec2a | |||
| b0c22b61ec | |||
| 82b049204d | |||
| aa59142bfa | |||
| c55bb77ff5 | |||
| 9b4e2e1e21 | |||
| 202c38a65a | |||
| 720bc418a6 | |||
| d77f455065 | |||
| 7e08f0fb66 | |||
| 9e4a87021c | |||
| 5887f6bcaa | |||
| 5d67559e33 | |||
| e631eb7a7a | |||
| 64ff4c232a | |||
| 0ec4f970f7 | |||
| afe95be42f | |||
| 14ac1c9904 | |||
| 7c11ea3694 | |||
| c1fd341698 | |||
| 0deab1be51 | |||
| 5a623adaa6 | |||
| 4363118d9d | |||
| d613da4b6c | |||
| f46f5b2050 | |||
| d9c4114b5f | |||
| ddd36af0f1 | |||
| 35fd30ee29 | |||
| 4a0652684c | |||
| 33c81f00b7 | |||
| 55714b90cd | |||
| 9b47603a1d | |||
| 2e2a913412 | |||
| 42b85dc33b | |||
| a15ffcb071 | |||
| 692b77fb8e | |||
| 044378cfa3 | |||
| f1d4d5f995 | |||
| 19d0fb6fcd | |||
| 7933265095 | |||
| d810644018 | |||
| a7bfc1c2ec | |||
| 104b2740bc | |||
| 65501837b7 | |||
| 3ed0a54847 | |||
| cbd2519b9a | |||
| e8a73f9696 | |||
| 1a0d114861 | |||
| 5c3497681e | |||
| b05cf9ef09 | |||
| a74eb357a1 | |||
| 8eb71084f0 | |||
| ef1077fd7b | |||
| f1ba5c7e0f | |||
| 97ea4986af | |||
| 25c021c15b | |||
| 2bf12a52d1 | |||
| 6ada36d3cb | |||
| 42b90ae76c | |||
| ccc61cb10c | |||
| be5b81740e | |||
| e7458ca10a | |||
| b10168eb1c | |||
| 30463c9082 | |||
| dc7391dc89 | |||
| eb98d70a0b | |||
| dcd8374b89 | |||
| 8e4216215e | |||
| 5bd7099b96 | |||
| 9a63d3b2da | |||
| bf02330db9 | |||
| 5806a6484f | |||
| 0fa5401800 | |||
| b30f4cbfb5 | |||
| ba37183c9c | |||
| 2f298a1979 | |||
| 8c282a5d83 | |||
| d34c0a5abe | |||
| 8f3348cf2b | |||
| 38c0bc7bae | |||
| 313b00b11f | |||
| 165a379c73 | |||
| a7f37236bf | |||
| 51532336b0 | |||
| 03d4b47f63 | |||
| 8b57edde6b | |||
| 778778fede | |||
| f7449c4ab9 | |||
| fd2bcc9156 | |||
| a5b1555725 | |||
| e74fdbc55b | |||
| 008c777a9f | |||
| d8a9d4a24e | |||
| bc0e1fa898 | |||
| 17f1737c9a | |||
| 868444f043 | |||
| fdae253695 | |||
| d4adcff958 | |||
| 2c59c9a3cc | |||
| 3a59a64355 | |||
| 9363c1cdaf | |||
| 198e6d7cf6 | |||
| 07ee898f4f | |||
| 6feb8a99d2 | |||
| e57c1fc9fc | |||
| a11b5ae41f | |||
| c67a7cec5b | |||
| 91f04ce250 | |||
| 926df2b276 | |||
| 9fe878bbec | |||
| 217dbca7b7 | |||
| 13852e865c | |||
| 679d47131d | |||
| 8b1bccb79b | |||
| e86e755c51 | |||
| 8ec6d4c9fc | |||
| 08cdf88586 | |||
| 6f7d97cf94 | |||
| 5e434f5131 | |||
| a152d0aac5 | |||
| 879706e6e9 | |||
| 00f1f30a08 | |||
| a5813f9ba5 | |||
| 5652af3384 | |||
| 22cd9af8cc | |||
| a9cf9bceef | |||
| 6c0f864a6e | |||
| e4509d9482 | |||
| 0f23e1f0f4 | |||
| 642a6aa4ad | |||
| 432c296b7b | |||
| b576d373c4 | |||
| 522aa8e762 | |||
| 146802fa4c | |||
| cc8af25d73 | |||
| f5f4bf58ad | |||
| 3784da0d18 | |||
| 9eb72f4392 | |||
| f7bf6d5e62 | |||
| adb14ba373 | |||
| 7391d91317 | |||
| 2149cec29f | |||
| ad756c36fc | |||
| b56316e9da | |||
| a989c44211 | |||
| 217e5f81cc | |||
| 5f2549b198 | |||
| dcd4d0daeb | |||
| faf4220b38 | |||
| 193ddaa2f6 | |||
| 46eb27883a | |||
| 2db7cdb71e | |||
| 5411c5aa4a | |||
| f8a1a10897 | |||
| adbe13938e | |||
| 4d5b14753d | |||
| ba9fa00947 | |||
| 98cedf155c | |||
| 88e3998664 | |||
| c0c0bbc1bf | |||
| 650e1b4fc5 | |||
| 6c1ada8d0a | |||
| 7d00c2670f | |||
| bca7e9a1e8 | |||
| 3748f0304f | |||
| 2576bdbd14 | |||
| e341a36287 | |||
| bba09a3cd0 | |||
| 985df3532b | |||
| 72041a52e8 | |||
| 891144dac1 | |||
| 41e7b53903 | |||
| 6b0920e8c0 | |||
| 4285729d5c | |||
| a9c10d0751 | |||
| 74c79c7eff | |||
| 9174a89971 | |||
| 5c94a583bc | |||
| 6e1fc2766f | |||
| d3bb00cb55 | |||
| 5a5656b2d3 | |||
| 1a1e584cba | |||
| 65fa05f998 | |||
| 2276fc95b8 | |||
| 1e173c178d | |||
| 773747cf9c | |||
| 4972284dde | |||
| 45789fda08 | |||
| 3b5bc63d1b | |||
| f1089e2b8a | |||
| 6d93c1eb92 | |||
| 363c325c79 | |||
| 583504ebe0 | |||
| b354b77f8b | |||
| 74af46cb4a | |||
| 19dab08275 | |||
| 3840fbf957 | |||
| 78c091f7f8 | |||
| 274ecbba78 | |||
| 683c2a68cd | |||
| ad98181069 | |||
| a549336530 | |||
| 4eb95c963d | |||
| 22caacd2a9 | |||
| af30d537da | |||
| f1bd26fb92 | |||
| 5c6bbcb62f | |||
| 21bd87bb07 | |||
| 79450df04c | |||
| 7f8b7b811e | |||
| 3c068aa0ae | |||
| 86df258365 | |||
| d99e704728 | |||
| 0d620f3e0f | |||
| 4dce0f9074 | |||
| 54f89cba33 | |||
| de88f60d1a | |||
| f7060970e6 | |||
| e7a98ac6cc | |||
| 10544db52e | |||
| 5e123031aa | |||
| 388f530edd | |||
| d354cccd37 | |||
| 714305ef56 | |||
| f83ae1e9c6 | |||
| c38e8de6b5 | |||
| 97638f7ade | |||
| 326a30d1af | |||
| 32e1473c94 | |||
| bf617036c7 | |||
| ce55422a24 | |||
| 388cc7c3bb | |||
| 37f9404d93 | |||
| 38dff41e25 | |||
| d360340b9e | |||
| 0f63cfa43f | |||
| 537780ee1e | |||
| 4ca99fcb4e | |||
| eb7ee13f43 | |||
| b2de706693 | |||
| 6a8180470d | |||
| 12d56be5cc | |||
| bb4d81a4fa | |||
| b254ade69b | |||
| ef4ebaa969 | |||
| 99f8133b91 | |||
| 51eb44bf40 | |||
| a0be415e09 | |||
| 071da18fa3 | |||
| c62e820bcf | |||
| 46c34db6cb | |||
| 25a2a4879c | |||
| 8be28012ee | |||
| 5aed186827 | |||
| 91f812e17f | |||
| f0b22c48b2 | |||
| 52c4eebd77 | |||
| 24f0d26fce | |||
| 825ec221b7 | |||
| e31080bce3 | |||
| 7a5d5cabad | |||
| f7de310889 | |||
| e209ca7c82 | |||
| ee8de77a90 | |||
| db49cbd6e2 | |||
| e001eecb7b | |||
| 7f34d00c95 | |||
| 2c18adbddd | |||
| 97c7fc42d1 | |||
| 7da0627f8e | |||
| 27cef23823 | |||
| b7fc2dc3d0 | |||
| 8af390e0f6 | |||
| 96d6453ea8 | |||
| 2b9900e56e | |||
| 86f58f60cb | |||
| 064ce568c2 | |||
| 6aff459e1c | |||
| 0b1b4d8f7e | |||
| 3fc2c3529a | |||
| b0e9ab0519 | |||
| 668517a723 | |||
| 649f08ec78 | |||
| 2f2c298c68 | |||
| 90e48970e6 | |||
| 480842a203 | |||
| 5425394880 | |||
| a365813fa9 | |||
| 9d64dbd5c2 | |||
| 30bb61a775 | |||
| 1f36ed0cf9 | |||
| d54c76f88a | |||
| cbb9f47ee5 | |||
| b68d5a5833 | |||
| 94d2090777 | |||
| e97585daf9 | |||
| 924fc2118c | |||
| 51f4c0c750 | |||
| 37b93da650 | |||
| 35e739dcdd | |||
| 8352392b38 | |||
| 413f05bfca | |||
| dc1aff58ed | |||
| 9f75d9cfe5 | |||
| a42af7e973 | |||
| 2ce244d303 | |||
| a775a920d0 | |||
| 4f84faf392 | |||
| a4cb5d8360 | |||
| da7f09cf82 | |||
| 0166af472b | |||
| 884d986bd6 | |||
| 59b807189f | |||
| fb1c7015b1 | |||
| d4123f62b2 | |||
| a3f410d1a1 | |||
| 1d19a4bffe | |||
| 271dd91292 | |||
| 9bd4d68f9c | |||
| 3c3c7826ef | |||
| 2207357b93 | |||
| 3a69768eb0 | |||
| afb29ff3ec | |||
| e6f0f891a6 | |||
| 36e5aa4683 | |||
| 7738050105 | |||
| 4bf11ec349 | |||
| d821012eed | |||
| 35c6edd989 | |||
| 633cb4f282 | |||
| 4d4d0e26a9 | |||
| feea2d4024 | |||
| 0ffd2a5c1d | |||
| 232fdcb82c | |||
| 0ccc23d544 | |||
| 789ca3db1a | |||
| cb359a05dc | |||
| 14982c137a | |||
| 0acab11620 | |||
| 02f0239016 | |||
| ab61b49aca | |||
| 4da1d6fd27 | |||
| 909e847369 | |||
| eafa09fecf | |||
| 8175348284 | |||
| b2832cb47a | |||
| 9f499991c8 | |||
| 9a416e8ae8 | |||
| 911922c6a3 | |||
| 1f2fd59ad5 | |||
| 708d401d2c | |||
| ed0dcacab3 | |||
| e86050f343 | |||
| 57f7da6ce1 | |||
| 93e6455171 | |||
| 8f38780197 | |||
| 341f7e41e5 | |||
| 265fe9c62e | |||
| 3b9d60d7cb | |||
| 278b873e89 | |||
| e640344d7a | |||
| 7151bb86a8 | |||
| 2a34391b71 | |||
| 3d95cf02f3 | |||
| dd3f34cb2c | |||
| 0c316ebfb2 | |||
| 282bf24f65 | |||
| f964f6be8d | |||
| 0202ccec5f | |||
| 636c308993 | |||
| 6fdbe6f9c2 | |||
| c19f4c019a | |||
| 83eb3dc0cb | |||
| 481c8406f3 | |||
| 0129619d9a | |||
| e0479b291d | |||
| b847d7dfd5 | |||
| 245dff8027 | |||
| fed690a7f2 | |||
| 54d981120d | |||
| f79250c4d4 | |||
| 78b62776d2 | |||
| bda4614783 | |||
| 0ab3332ad3 | |||
| 9e0abbc2f0 | |||
| 496adb61a4 | |||
| 4a4a3bf184 | |||
| f33e78882e | |||
| 0ff067bdb7 | |||
| 31ac3260ed | |||
| d82c6c2337 | |||
| 632b699475 | |||
| 85039020d3 | |||
| 1a0fdc5a44 | |||
| fb1bab7c30 | |||
| 7eb43990ad | |||
| 53f4b5a9da | |||
| 1d4a6c3a42 | |||
| 40083e4aa1 | |||
| bd929bff07 | |||
| cd4a0530fa | |||
| 273fdd2235 | |||
| b20f2e8d31 | |||
| e756cde2b1 | |||
| de18d3e64d | |||
| 441999ba9f | |||
| dd046b1ace | |||
| 926aa238ab | |||
| 01fa521a03 | |||
| f31da19266 | |||
| 48edc38817 | |||
| ac12132ac0 | |||
| 13fabcc1f1 | |||
| 67005a80be | |||
| f43bfcb398 | |||
| d5ce4c9d2c | |||
| 1cf7ef3de6 | |||
| 5248a3fe48 | |||
| 812e61ca70 | |||
| 2d0a5a9e15 | |||
| f32d594879 | |||
| c2ad76fe4f | |||
| 10d9b72da1 | |||
| 2fe9af7165 | |||
| 0deda83d05 | |||
| ff5bcd4416 | |||
| b65cd1d09b | |||
| bc35a561d3 | |||
| 06bc807e34 | |||
| 6262e41de1 | |||
| 0cb53efa01 | |||
| 4e859bedbc | |||
| f139fc2229 | |||
| e48acbb03b | |||
| d1155c968e | |||
| 88a2c60065 | |||
| 5bfcf6783e | |||
| 94f8a657f1 | |||
| 7fac2a7526 | |||
| 46dcf98fc1 | |||
| 58ce907327 | |||
| 6ecc8cac0e | |||
| bd95f17426 | |||
| 0718bea5a1 | |||
| 175f07cd2f | |||
| 7b19d6e479 | |||
| 77c83e5552 | |||
| b15deb420f | |||
| b38989d594 | |||
| 79e6de325f | |||
| 163d2e4ba8 | |||
| 4f8f3ddc29 | |||
| 82a1a29260 | |||
| 8a5608df91 | |||
| 3f1c0ec91b | |||
| 1406a75a92 | |||
| 8001493df3 | |||
| 8c1f5bfe1e | |||
| ec8b9640e2 | |||
| 4ae1332a43 | |||
| 10c884bba4 | |||
| c15f031c3f | |||
| 1b4c744974 | |||
| d9068eebb5 | |||
| 3ad0d2328d | |||
| 3f2beb4547 | |||
| be14a6c239 | |||
| 3aa0eeb4a3 | |||
| b3eeb6412f | |||
| d38470c8e2 | |||
| a159c980ee | |||
| a993d997ad | |||
| 4475e3e184 | |||
| cf0320e47d | |||
| cd03a95128 | |||
| 51e299c7e3 | |||
| 6f65453fd4 | |||
|
|
67e0c21e0f | ||
| 702016a6e3 | |||
| d74ce4950c | |||
| 59a682c720 | |||
| 7bd4593748 | |||
| c5b006bf19 | |||
| 115c44630d | |||
| 1dc81abca4 | |||
| 5aaf2128a8 | |||
| 6aeac17072 | |||
| 6d425182a2 | |||
| 04ac23b67c | |||
| 5494e2c125 | |||
| aba82564f5 | |||
| 93abee9c7c | |||
| 4034bef42e | |||
| 821d065eba | |||
| 2614437ba0 | |||
| 1aac3a0425 | |||
| a4568f9263 | |||
| a180e72b6f | |||
| 2de64b592d | |||
| 9c0f3dd996 | |||
| 079df39ca8 | |||
|
|
60a99d1d23 | ||
| fe87c08a02 | |||
| 8637959289 | |||
| 6be53668b9 | |||
| d1b7249803 | |||
| ff7c50c627 | |||
| 12779cdef8 | |||
| f5e676b2b7 | |||
| 8e5e5f819f | |||
| 370a958379 | |||
| 0ee7da92a3 | |||
| a0bd3dc54f | |||
| 809eb2fe3e | |||
| 7010d8614f | |||
| 69f13f1896 | |||
| bdaf7cddcb | |||
| 8d6db168d6 | |||
| 2fabe1949c | |||
| c660df14ec | |||
| e704968f96 | |||
| 32359df939 | |||
| 641ed23380 | |||
| 9f977488fa | |||
| ac0b22f9b9 | |||
| 7752b02fb7 | |||
|
|
7610670287 | ||
| 31a1b23fb7 | |||
| 91c8f9a596 | |||
| f70cd3ea77 | |||
| 5db5ff069a | |||
| b8d852ddb7 | |||
| 46eedbd1a4 | |||
| e760bafeeb | |||
| 12351d5cb6 | |||
| e84f613c4d | |||
| 5db4e5b4d5 | |||
| b00dd8d68d | |||
| abbbf7ec15 | |||
| 22c72d8c70 | |||
| d0b1457f30 | |||
| a423cd8bb3 | |||
| db076058b9 | |||
| fe10ea85db | |||
| a1100624bf | |||
| 28e1497f88 | |||
| 8d6111641e | |||
| 3ee20d1a84 | |||
| 002c2d0aca | |||
| de9f109f2a | |||
| 461a5774f8 | |||
| 914f718767 | |||
| ebfd092075 | |||
| e322826347 | |||
| 3998c5f955 | |||
| 762d22ed28 | |||
| f2362b2b78 | |||
| 471ac80420 | |||
| 4a887fc706 | |||
| e49d3c7bfe | |||
| c5b83074ac | |||
| 79090c2648 | |||
| 7a6b1c8e47 | |||
| 8988ce2766 | |||
| dcde2ae6b4 | |||
| c62849a783 | |||
| f453e8e170 | |||
| 990887891e | |||
| 5da801d12b | |||
| 3a4557d417 | |||
| 26d9a3e253 | |||
| eef3631a5a | |||
| 88ee35165f | |||
| c8f05b4a7a | |||
| c32584cca0 | |||
| 2995a36942 | |||
| c1dbafc101 | |||
| 3e8ab8271d | |||
| 5b3a00c64f | |||
| 0ce9fd8597 | |||
| c9badb5a1c | |||
| a513bc5749 | |||
| 5d5487315f | |||
| 3508df67b1 | |||
| 06ce1f0667 | |||
| f9c3ae7090 | |||
| 1fb8c211f0 | |||
| 9c7670847e | |||
| a24c2d9be2 | |||
| f4db246658 | |||
| 7f90079ea7 | |||
| f4b4987d43 | |||
| 7f88ba70d4 | |||
| ac094a48d6 | |||
| 779912d8af | |||
| f205b8e883 | |||
| f9a0412e78 | |||
| 0ef318633c | |||
| 2f8c9746e3 | |||
| 6d6bef1b04 | |||
| 3dab392296 | |||
| f8a2c60c8d | |||
| 770f7716a0 | |||
| a011c0384f | |||
| 0d356c5bbc | |||
| d67de70126 | |||
| 6f334756c5 | |||
| 310713d203 | |||
| 7d2ab53baa | |||
| 2152b8b95f | |||
| 8ac1ae1574 | |||
| 4fd21bc303 | |||
| 15037bfc7a | |||
| 5831c72aad | |||
| a063d041c9 | |||
| 3572e9794a | |||
| cef6999dc7 | |||
| 6ed9651176 | |||
| 3efbe22a1b | |||
| 96579b88cf | |||
| 2ec18855f2 | |||
| b222581d18 | |||
| a8e3ee6f19 | |||
| a083e588ba | |||
| 9b500842a0 | |||
| b21348379f | |||
| 633055293e | |||
| ae9d618803 | |||
| 9c744dfc44 | |||
| faf1b661bb | |||
| 22e45278a2 | |||
| 43f4657566 | |||
| 70f2908056 | |||
| ef381d0600 | |||
| cfa87526a7 | |||
| 39b560fde3 | |||
| 0c582b4490 | |||
| 61caf566fc | |||
| 76d5364a55 | |||
|
|
5224df321e |
8
.gitignore
vendored
8
.gitignore
vendored
@@ -1,7 +1,5 @@
|
||||
*.img
|
||||
isodir
|
||||
sysroot
|
||||
.vscode/
|
||||
.idea/
|
||||
bochsrc
|
||||
bx_enh_dbg.ini
|
||||
build/
|
||||
base/
|
||||
script/fakeroot-context
|
||||
|
||||
4
.gitmodules
vendored
Normal file
4
.gitmodules
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
[submodule "kernel/lai"]
|
||||
path = kernel/lai
|
||||
url = https://github.com/managarm/lai.git
|
||||
ignore = untracked
|
||||
@@ -1,9 +0,0 @@
|
||||
#include <BAN/Memory.h>
|
||||
|
||||
void* operator new(size_t size) { return BAN::allocator(size); }
|
||||
void* operator new[](size_t size) { return BAN::allocator(size); }
|
||||
|
||||
void operator delete(void* addr) { BAN::deallocator(addr); }
|
||||
void operator delete[](void* addr) { BAN::deallocator(addr); }
|
||||
void operator delete(void* addr, size_t) { BAN::deallocator(addr); }
|
||||
void operator delete[](void* addr, size_t) { BAN::deallocator(addr); }
|
||||
9
BAN/BAN/New.cpp
Normal file
9
BAN/BAN/New.cpp
Normal file
@@ -0,0 +1,9 @@
|
||||
#include <BAN/New.h>
|
||||
|
||||
void* operator new(size_t size) { return BAN::allocator(size); }
|
||||
void* operator new[](size_t size) { return BAN::allocator(size); }
|
||||
|
||||
void operator delete(void* addr) { BAN::deallocator(addr); }
|
||||
void operator delete[](void* addr) { BAN::deallocator(addr); }
|
||||
void operator delete(void* addr, size_t) { BAN::deallocator(addr); }
|
||||
void operator delete[](void* addr, size_t) { BAN::deallocator(addr); }
|
||||
@@ -1,102 +1,109 @@
|
||||
#include <BAN/Errors.h>
|
||||
#include <BAN/Math.h>
|
||||
#include <BAN/Memory.h>
|
||||
#include <BAN/Move.h>
|
||||
#include <BAN/String.h>
|
||||
#include <BAN/StringView.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <BAN/New.h>
|
||||
|
||||
namespace BAN
|
||||
{
|
||||
|
||||
String::String()
|
||||
{
|
||||
MUST(copy_impl(""sv));
|
||||
}
|
||||
|
||||
String::String(const String& other)
|
||||
{
|
||||
MUST(copy_impl(other.sv()));
|
||||
*this = other;
|
||||
}
|
||||
|
||||
String::String(String&& other)
|
||||
{
|
||||
move_impl(move(other));
|
||||
*this = move(other);
|
||||
}
|
||||
|
||||
String::String(StringView other)
|
||||
{
|
||||
MUST(copy_impl(other));
|
||||
*this = other;
|
||||
}
|
||||
|
||||
String::~String()
|
||||
{
|
||||
BAN::deallocator(m_data);
|
||||
clear();
|
||||
}
|
||||
|
||||
String& String::operator=(const String& other)
|
||||
{
|
||||
MUST(copy_impl(other.sv()));
|
||||
clear();
|
||||
MUST(ensure_capacity(other.size()));
|
||||
memcpy(data(), other.data(), other.size() + 1);
|
||||
m_size = other.size();
|
||||
return *this;
|
||||
}
|
||||
|
||||
String& String::operator=(String&& other)
|
||||
{
|
||||
BAN::deallocator(m_data);
|
||||
move_impl(move(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)
|
||||
{
|
||||
MUST(copy_impl(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 ch)
|
||||
ErrorOr<void> String::push_back(char c)
|
||||
{
|
||||
TRY(ensure_capacity(m_size + 2));
|
||||
m_data[m_size] = ch;
|
||||
TRY(ensure_capacity(m_size + 1));
|
||||
data()[m_size] = c;
|
||||
m_size++;
|
||||
m_data[m_size] = '\0';
|
||||
data()[m_size] = '\0';
|
||||
return {};
|
||||
}
|
||||
|
||||
ErrorOr<void> String::insert(char ch, size_type index)
|
||||
ErrorOr<void> String::insert(char c, size_type index)
|
||||
{
|
||||
ASSERT(index <= m_size);
|
||||
TRY(ensure_capacity(m_size + 1 + 1));
|
||||
memmove(m_data + index + 1, m_data + index, m_size - index);
|
||||
m_data[index] = ch;
|
||||
m_size += 1;
|
||||
m_data[m_size] = '\0';
|
||||
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 other, size_type index)
|
||||
ErrorOr<void> String::insert(StringView str, size_type index)
|
||||
{
|
||||
ASSERT(index <= m_size);
|
||||
TRY(ensure_capacity(m_size + other.size() + 1));
|
||||
memmove(m_data + index + other.size(), m_data + index, m_size - index);
|
||||
memcpy(m_data + index, other.data(), other.size());
|
||||
m_size += other.size();
|
||||
m_data[m_size] = '\0';
|
||||
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 other)
|
||||
ErrorOr<void> String::append(StringView str)
|
||||
{
|
||||
TRY(ensure_capacity(m_size + other.size() + 1));
|
||||
memcpy(m_data + m_size, other.data(), other.size());
|
||||
m_size += other.size();
|
||||
m_data[m_size] = '\0';
|
||||
return {};
|
||||
}
|
||||
|
||||
ErrorOr<void> String::append(const String& string)
|
||||
{
|
||||
TRY(append(string.sv()));
|
||||
TRY(ensure_capacity(m_size + str.size()));
|
||||
memcpy(data() + m_size, str.data(), str.size());
|
||||
m_size += str.size();
|
||||
data()[m_size] = '\0';
|
||||
return {};
|
||||
}
|
||||
|
||||
@@ -104,159 +111,159 @@ namespace BAN
|
||||
{
|
||||
ASSERT(m_size > 0);
|
||||
m_size--;
|
||||
m_data[m_size] = '\0';
|
||||
data()[m_size] = '\0';
|
||||
}
|
||||
|
||||
void String::remove(size_type index)
|
||||
{
|
||||
erase(index, 1);
|
||||
ASSERT(index < m_size);
|
||||
memcpy(data() + index, data() + index + 1, m_size - index);
|
||||
m_size--;
|
||||
data()[m_size] = '\0';
|
||||
}
|
||||
|
||||
void String::erase(size_type index, size_type count)
|
||||
{
|
||||
ASSERT(index + count <= m_size);
|
||||
memmove(m_data + index, m_data + index + count, m_size - index - count);
|
||||
m_size -= count;
|
||||
m_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;
|
||||
m_data[0] = '\0';
|
||||
data()[m_size] = '\0';
|
||||
}
|
||||
|
||||
char String::operator[](size_type index) const
|
||||
bool String::operator==(StringView str) const
|
||||
{
|
||||
ASSERT(index < m_size);
|
||||
return m_data[index];
|
||||
}
|
||||
|
||||
char& String::operator[](size_type index)
|
||||
{
|
||||
ASSERT(index < m_size);
|
||||
return m_data[index];
|
||||
}
|
||||
|
||||
bool String::operator==(const String& other) const
|
||||
{
|
||||
if (m_size != other.m_size)
|
||||
if (size() != str.size())
|
||||
return false;
|
||||
return memcmp(m_data, other.m_data, m_size) == 0;
|
||||
}
|
||||
|
||||
bool String::operator==(StringView other) const
|
||||
{
|
||||
if (m_size != other.size())
|
||||
return false;
|
||||
return memcmp(m_data, other.data(), m_size) == 0;
|
||||
}
|
||||
|
||||
bool String::operator==(const char* other) const
|
||||
{
|
||||
for (size_type i = 0; i <= m_size; i++)
|
||||
if (m_data[i] != other[i])
|
||||
for (size_type i = 0; i < m_size; i++)
|
||||
if (data()[i] != str.data()[i])
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
ErrorOr<void> String::resize(size_type size, char ch)
|
||||
bool String::operator==(const char* cstr) const
|
||||
{
|
||||
if (size < m_size)
|
||||
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)
|
||||
{
|
||||
m_data[size] = '\0';
|
||||
m_size = 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 {};
|
||||
}
|
||||
else if (size > m_size)
|
||||
{
|
||||
TRY(ensure_capacity(size + 1));
|
||||
for (size_type i = m_size; i < size; i++)
|
||||
m_data[i] = ch;
|
||||
m_data[size] = '\0';
|
||||
m_size = size;
|
||||
}
|
||||
m_size = size;
|
||||
|
||||
m_size = new_size;
|
||||
data()[m_size] = '\0';
|
||||
return {};
|
||||
}
|
||||
|
||||
ErrorOr<void> String::reserve(size_type size)
|
||||
ErrorOr<void> String::reserve(size_type new_size)
|
||||
{
|
||||
TRY(ensure_capacity(size));
|
||||
TRY(ensure_capacity(new_size));
|
||||
return {};
|
||||
}
|
||||
|
||||
ErrorOr<void> String::shrink_to_fit()
|
||||
{
|
||||
size_type temp = m_capacity;
|
||||
m_capacity = 0;
|
||||
auto error_or = ensure_capacity(m_size);
|
||||
if (error_or.is_error())
|
||||
if (has_sso())
|
||||
return {};
|
||||
|
||||
if (fits_in_sso())
|
||||
{
|
||||
m_capacity = temp;
|
||||
return error_or;
|
||||
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 String::sv() const
|
||||
{
|
||||
return StringView(*this);
|
||||
}
|
||||
|
||||
bool String::empty() const
|
||||
{
|
||||
return m_size == 0;
|
||||
}
|
||||
|
||||
String::size_type String::size() const
|
||||
{
|
||||
return m_size;
|
||||
}
|
||||
|
||||
String::size_type String::capacity() const
|
||||
{
|
||||
return m_capacity;
|
||||
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
|
||||
{
|
||||
return m_data;
|
||||
if (has_sso())
|
||||
return m_storage.sso_storage.data;
|
||||
return m_storage.general_storage.data;
|
||||
}
|
||||
|
||||
ErrorOr<void> String::ensure_capacity(size_type size)
|
||||
ErrorOr<void> String::ensure_capacity(size_type new_size)
|
||||
{
|
||||
if (m_capacity >= size)
|
||||
if (m_size >= new_size)
|
||||
return {};
|
||||
size_type new_cap = BAN::Math::max<size_type>(size, m_capacity * 2);
|
||||
void* new_data = BAN::allocator(new_cap);
|
||||
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);
|
||||
if (m_data)
|
||||
memcpy(new_data, m_data, m_size + 1);
|
||||
BAN::deallocator(m_data);
|
||||
m_data = (char*)new_data;
|
||||
m_capacity = new_cap;
|
||||
|
||||
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 {};
|
||||
}
|
||||
|
||||
ErrorOr<void> String::copy_impl(StringView other)
|
||||
bool String::has_sso() const
|
||||
{
|
||||
TRY(ensure_capacity(other.size() + 1));
|
||||
memcpy(m_data, other.data(), other.size());
|
||||
m_size = other.size();
|
||||
m_data[m_size] = '\0';
|
||||
return {};
|
||||
}
|
||||
|
||||
void String::move_impl(String&& other)
|
||||
{
|
||||
m_data = other.m_data;
|
||||
m_size = other.m_size;
|
||||
m_capacity = other.m_capacity;
|
||||
|
||||
other.m_data = nullptr;
|
||||
other.m_size = 0;
|
||||
other.m_capacity = 0;
|
||||
return m_has_sso;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -63,9 +63,38 @@ namespace BAN
|
||||
|
||||
ErrorOr<Vector<StringView>> StringView::split(char delim, bool allow_empties)
|
||||
{
|
||||
// FIXME: Won't work while multithreading
|
||||
static char s_delim = delim;
|
||||
return split([](char c){ return c == s_delim; }, 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)
|
||||
@@ -116,6 +145,14 @@ namespace BAN
|
||||
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;
|
||||
@@ -134,7 +171,7 @@ namespace BAN
|
||||
{
|
||||
return m_size;
|
||||
}
|
||||
|
||||
|
||||
const char* StringView::data() const
|
||||
{
|
||||
return m_data;
|
||||
|
||||
71
BAN/BAN/Time.cpp
Normal file
71
BAN/BAN/Time.cpp
Normal file
@@ -0,0 +1,71 @@
|
||||
#include <BAN/Time.h>
|
||||
|
||||
namespace BAN
|
||||
{
|
||||
|
||||
static constexpr bool is_leap_year(uint64_t year)
|
||||
{
|
||||
if (year % 400 == 0)
|
||||
return true;
|
||||
if (year % 100 == 0)
|
||||
return false;
|
||||
if (year % 4 == 0)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
static constexpr uint64_t leap_days_since_epoch(const BAN::Time& time)
|
||||
{
|
||||
uint64_t leap_years = 0;
|
||||
for (uint32_t year = 1970; year < time.year; year++)
|
||||
if (is_leap_year(year))
|
||||
leap_years++;
|
||||
if (is_leap_year(time.year) && time.month >= 3)
|
||||
leap_years++;
|
||||
return leap_years;
|
||||
}
|
||||
|
||||
static constexpr uint64_t month_days[] { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
|
||||
|
||||
uint64_t to_unix_time(const BAN::Time& time)
|
||||
{
|
||||
uint64_t years = time.year - 1970;
|
||||
uint64_t days = years * 365 + month_days[time.month - 1] + leap_days_since_epoch(time) + (time.day - 1);
|
||||
uint64_t hours = days * 24 + time.hour;
|
||||
uint64_t minutes = hours * 60 + time.minute;
|
||||
uint64_t seconds = minutes * 60 + time.second;
|
||||
return seconds;
|
||||
}
|
||||
|
||||
BAN::Time from_unix_time(uint64_t unix_time)
|
||||
{
|
||||
BAN::Time time {};
|
||||
|
||||
time.second = unix_time % 60; unix_time /= 60;
|
||||
time.minute = unix_time % 60; unix_time /= 60;
|
||||
time.hour = unix_time % 24; unix_time /= 24;
|
||||
|
||||
uint64_t total_days = unix_time;
|
||||
|
||||
time.week_day = (total_days + 4) % 7 + 1;
|
||||
|
||||
time.year = 1970;
|
||||
while (total_days >= 365U + is_leap_year(time.year))
|
||||
{
|
||||
total_days -= 365U + is_leap_year(time.year);
|
||||
time.year++;
|
||||
}
|
||||
|
||||
bool is_leap_day = is_leap_year(time.year) && total_days == month_days[2];
|
||||
bool had_leap_day = is_leap_year(time.year) && total_days > month_days[2];
|
||||
|
||||
for (time.month = 1; time.month < 12; time.month++)
|
||||
if (total_days < month_days[time.month] + (is_leap_day || had_leap_day))
|
||||
break;
|
||||
|
||||
time.day = total_days - month_days[time.month - 1] + !had_leap_day;
|
||||
|
||||
return time;
|
||||
}
|
||||
|
||||
}
|
||||
24
BAN/CMakeLists.txt
Normal file
24
BAN/CMakeLists.txt
Normal file
@@ -0,0 +1,24 @@
|
||||
cmake_minimum_required(VERSION 3.26)
|
||||
|
||||
project(BAN CXX)
|
||||
|
||||
set(BAN_SOURCES
|
||||
BAN/New.cpp
|
||||
BAN/String.cpp
|
||||
BAN/StringView.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_dependencies(ban headers libc-install)
|
||||
|
||||
add_custom_target(ban-install
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_BINARY_DIR}/libban.a ${BANAN_LIB}/
|
||||
DEPENDS ban
|
||||
BYPRODUCTS ${BANAN_LIB}/libban.a
|
||||
)
|
||||
89
BAN/Makefile
89
BAN/Makefile
@@ -1,89 +0,0 @@
|
||||
DEFAULT_HOST!=../default-host.sh
|
||||
HOST?=DEFAULT_HOST
|
||||
HOSTARCH!=../target-triplet-to-arch.sh $(HOST)
|
||||
|
||||
CFLAGS?=-O2 -g
|
||||
CPPFLAGS?=
|
||||
LDFLAGS?=
|
||||
LIBS?=
|
||||
|
||||
DESTDIR?=
|
||||
PREFIX?=/usr/local
|
||||
EXEC_PREFIX?=$(PREFIX)
|
||||
INCLUDEDIR?=$(PREFIX)/include
|
||||
LIBDIR?=$(EXEC_PREFIX)/lib
|
||||
|
||||
CFLAGS:=$(CFLAGS) -Iinclude -ffreestanding -Wall -Wextra -Werror=return-type
|
||||
CPPFLAGS:=$(CPPFLAGS)
|
||||
LIBBANK_CFLAGS:=$(CFLAGS) -D__is_kernel -Iinclude -ffreestanding -Wall -Wextra
|
||||
LIBBANK_CPPFLAGS:=$(CPPFLAGS) -fno-rtti -fno-exceptions
|
||||
|
||||
ARCHDIR=arch/$(HOSTARCH)
|
||||
|
||||
include $(ARCHDIR)/make.config
|
||||
|
||||
CFLAGS:=$(CFLAGS) $(ARCH_CFLAGS)
|
||||
CPPFLAGS:=$(CPPFLAGS) $(ARCH_CPPFLAGS)
|
||||
LIBBANK_CFLAGS:=$(LIBBANK_CFLAGS) $(KERNEL_ARCH_CFLAGS)
|
||||
LIBBANK_CPPFLAGS:=$(LIBBANK_CPPFLAGS) $(KERNEL_ARCH_CPPFLAGS)
|
||||
|
||||
BUILDDIR=$(abspath build)
|
||||
|
||||
FREEOBJS= \
|
||||
$(ARCH_FREEOBJS) \
|
||||
BAN/Memory.o \
|
||||
BAN/String.o \
|
||||
BAN/StringView.o \
|
||||
|
||||
HOSTEDOBJS=\
|
||||
$(ARCH_HOSTEDOBJS) \
|
||||
|
||||
OBJS=\
|
||||
$(FREEOBJS) \
|
||||
$(HOSTEDOBJS) \
|
||||
|
||||
LIBBANK_OBJS=$(FREEOBJS:.o=.bank.o)
|
||||
|
||||
BINARIES=libbank.a
|
||||
|
||||
.PHONY: all always clean install install-headers install-libs
|
||||
.SUFFIXES: .o .bank.o .cpp .S
|
||||
|
||||
all: $(BINARIES)
|
||||
|
||||
libban.a: always $(OBJS)
|
||||
cd $(BUILDDIR) && $(AR) rcs $@ $(OBJS)
|
||||
|
||||
libbank.a: always $(LIBBANK_OBJS)
|
||||
cd $(BUILDDIR) && $(AR) rcs $@ $(LIBBANK_OBJS)
|
||||
|
||||
.cpp.o:
|
||||
$(CXX) -MD -c $< -o $(BUILDDIR)/$@ $(CFLAGS) $(CPPFLAGS)
|
||||
|
||||
.S.o:
|
||||
$(CXX) -MD -c $< -o $(BUILDDIR)/$@ $(CFLAGS) $(CPPFLAGS)
|
||||
|
||||
.cpp.bank.o:
|
||||
$(CXX) -MD -c $< -o $(BUILDDIR)/$@ $(LIBBANK_CFLAGS) $(LIBBANK_CPPFLAGS)
|
||||
|
||||
.S.bank.o:
|
||||
$(CXX) -MD -c $< -o $(BUILDDIR)/$@ $(LIBBANK_CFLAGS) $(LIBBANK_CPPFLAGS)
|
||||
|
||||
clean:
|
||||
rm -rf $(BUILDDIR)
|
||||
|
||||
always:
|
||||
mkdir -p $(BUILDDIR)/BAN
|
||||
|
||||
install: install-headers install-libs
|
||||
|
||||
install-headers:
|
||||
mkdir -p $(DESTDIR)$(INCLUDEDIR)
|
||||
cp -R --preserve=timestamps include/. $(DESTDIR)$(INCLUDEDIR)/.
|
||||
|
||||
install-libs: $(BINARIES)
|
||||
mkdir -p $(DESTDIR)$(LIBDIR)
|
||||
cp $(BUILDDIR)/$(BINARIES) $(DESTDIR)$(LIBDIR)
|
||||
|
||||
-include $(OBJS:.o=.d)
|
||||
-include $(LIBBANK_OBJS:.o=.d)
|
||||
@@ -1,8 +0,0 @@
|
||||
ARCH_CFLAGS=
|
||||
ARCH_CPPFLAGS=
|
||||
KERNEL_ARCH_CFLAGS=
|
||||
KERNEL_ARCH_CPPFLAGS=
|
||||
|
||||
ARCH_FREEOBJS=\
|
||||
|
||||
ARCH_HOSTEDOBJS=\
|
||||
@@ -1,8 +0,0 @@
|
||||
ARCH_CFLAGS=
|
||||
ARCH_CPPFLAGS=
|
||||
KERNEL_ARCH_CFLAGS=
|
||||
KERNEL_ARCH_CPPFLAGS=
|
||||
|
||||
ARCH_FREEOBJS=\
|
||||
|
||||
ARCH_HOSTEDOBJS=\
|
||||
@@ -1,6 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include <BAN/Errors.h>
|
||||
#include <BAN/Iterators.h>
|
||||
#include <BAN/Span.h>
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
@@ -13,11 +15,18 @@ namespace BAN
|
||||
public:
|
||||
using size_type = decltype(S);
|
||||
using value_type = T;
|
||||
using iterator = IteratorSimple<T, Array>;
|
||||
using const_iterator = ConstIteratorSimple<T, Array>;
|
||||
|
||||
public:
|
||||
Array();
|
||||
Array(const T&);
|
||||
|
||||
iterator begin() { return iterator(m_data); }
|
||||
iterator end() { return iterator(m_data + size()); }
|
||||
const_iterator begin() const { return const_iterator(m_data); }
|
||||
const_iterator end() const { return const_iterator(m_data + size()); }
|
||||
|
||||
const T& operator[](size_type) const;
|
||||
T& operator[](size_type);
|
||||
|
||||
@@ -26,7 +35,13 @@ namespace BAN
|
||||
const T& front() const;
|
||||
T& front();
|
||||
|
||||
Span<T> span() { return Span(m_data, size()); }
|
||||
const Span<T> span() const { return Span(m_data, size()); }
|
||||
|
||||
constexpr size_type size() const;
|
||||
|
||||
const T* data() const { return m_data; }
|
||||
T* data() { return m_data; }
|
||||
|
||||
private:
|
||||
T m_data[S];
|
||||
|
||||
@@ -1,11 +1,33 @@
|
||||
#pragma once
|
||||
|
||||
#include <BAN/Traits.h>
|
||||
|
||||
#if defined(__is_kernel)
|
||||
#include <kernel/Panic.h>
|
||||
#define ASSERT(cond) do { if (!(cond)) Kernel::panic("ASSERT("#cond") failed"); } while(false)
|
||||
|
||||
#define ASSERT(cond) \
|
||||
do { \
|
||||
if (!(cond)) \
|
||||
Kernel::panic("ASSERT(" #cond ") failed"); \
|
||||
} while (false)
|
||||
|
||||
#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() assert(false && "ASSERT_NOT_REACHED() failed")
|
||||
#endif
|
||||
#define ASSERT_NOT_REACHED() do { assert(false && "ASSERT_NOT_REACHED() failed"); __builtin_unreachable(); } while (false)
|
||||
#endif
|
||||
|
||||
141
BAN/include/BAN/ByteSpan.h
Normal file
141
BAN/include/BAN/ByteSpan.h
Normal file
@@ -0,0 +1,141 @@
|
||||
#pragma once
|
||||
|
||||
#include <BAN/Span.h>
|
||||
|
||||
namespace BAN
|
||||
{
|
||||
|
||||
template<bool CONST>
|
||||
class ByteSpanGeneral
|
||||
{
|
||||
public:
|
||||
using value_type = maybe_const_t<CONST, uint8_t>;
|
||||
using size_type = size_t;
|
||||
|
||||
public:
|
||||
ByteSpanGeneral() = default;
|
||||
ByteSpanGeneral(value_type* data, size_type size)
|
||||
: m_data(data)
|
||||
, m_size(size)
|
||||
{ }
|
||||
|
||||
ByteSpanGeneral(ByteSpanGeneral& other)
|
||||
: m_data(other.data())
|
||||
, m_size(other.size())
|
||||
{ }
|
||||
template<bool C2>
|
||||
ByteSpanGeneral(const ByteSpanGeneral<C2>& other) requires(CONST)
|
||||
: m_data(other.data())
|
||||
, m_size(other.size())
|
||||
{ }
|
||||
ByteSpanGeneral(Span<uint8_t> other)
|
||||
: m_data(other.data())
|
||||
, m_size(other.size())
|
||||
{ }
|
||||
ByteSpanGeneral(const Span<const uint8_t>& other) requires(CONST)
|
||||
: m_data(other.data())
|
||||
, m_size(other.size())
|
||||
{ }
|
||||
|
||||
ByteSpanGeneral& operator=(ByteSpanGeneral other)
|
||||
{
|
||||
m_data = other.data();
|
||||
m_size = other.size();
|
||||
return *this;
|
||||
}
|
||||
template<bool C2>
|
||||
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_size = other.size();
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename S>
|
||||
requires(CONST || !is_const_v<S>)
|
||||
static ByteSpanGeneral from(S& value)
|
||||
{
|
||||
return ByteSpanGeneral(reinterpret_cast<value_type*>(&value), sizeof(S));
|
||||
}
|
||||
|
||||
template<typename S>
|
||||
requires(!CONST && !is_const_v<S>)
|
||||
S& as()
|
||||
{
|
||||
ASSERT(m_data);
|
||||
ASSERT(m_size >= sizeof(S));
|
||||
return *reinterpret_cast<S*>(m_data);
|
||||
}
|
||||
|
||||
template<typename 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);
|
||||
return Span<S>(reinterpret_cast<S*>(m_data), m_size / sizeof(S));
|
||||
}
|
||||
|
||||
template<typename S>
|
||||
requires(is_const_v<S>)
|
||||
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_size >= offset);
|
||||
if (length == size_type(-1))
|
||||
length = m_size - offset;
|
||||
ASSERT(m_size >= offset + length);
|
||||
return ByteSpanGeneral(m_data + offset, length);
|
||||
}
|
||||
|
||||
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);
|
||||
return m_data[offset];
|
||||
}
|
||||
|
||||
value_type* data() { return m_data; }
|
||||
const value_type* data() const { return m_data; }
|
||||
|
||||
size_type size() const { return m_size; }
|
||||
|
||||
private:
|
||||
value_type* m_data { nullptr };
|
||||
size_type m_size { 0 };
|
||||
};
|
||||
|
||||
using ByteSpan = ByteSpanGeneral<false>;
|
||||
using ConstByteSpan = ByteSpanGeneral<true>;
|
||||
|
||||
}
|
||||
113
BAN/include/BAN/CircularQueue.h
Normal file
113
BAN/include/BAN/CircularQueue.h
Normal file
@@ -0,0 +1,113 @@
|
||||
#pragma once
|
||||
|
||||
#include <BAN/Assert.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
namespace BAN
|
||||
{
|
||||
|
||||
template<typename T, size_t S>
|
||||
class CircularQueue
|
||||
{
|
||||
public:
|
||||
using size_type = size_t;
|
||||
using value_type = T;
|
||||
|
||||
public:
|
||||
CircularQueue() = default;
|
||||
~CircularQueue();
|
||||
|
||||
void push(const T&);
|
||||
void push(T&&);
|
||||
template<typename... Args>
|
||||
void emplace(Args&&... args);
|
||||
|
||||
void pop();
|
||||
|
||||
const T& front() const;
|
||||
T& front();
|
||||
|
||||
size_type size() const { return m_size; }
|
||||
bool empty() const { return size() == 0; }
|
||||
bool full() const { return size() == capacity(); }
|
||||
|
||||
static constexpr size_type capacity() { return S; }
|
||||
|
||||
private:
|
||||
T* element_at(size_type);
|
||||
const T* element_at(size_type) const;
|
||||
|
||||
private:
|
||||
alignas(T) uint8_t m_storage[sizeof(T) * capacity()];
|
||||
size_type m_first { 0 };
|
||||
size_type m_size { 0 };
|
||||
};
|
||||
|
||||
template<typename T, size_t S>
|
||||
CircularQueue<T, S>::~CircularQueue()
|
||||
{
|
||||
for (size_type i = 0; i < m_size; i++)
|
||||
element_at((m_first + i) % capacity())->~T();
|
||||
}
|
||||
|
||||
template<typename T, size_t S>
|
||||
void CircularQueue<T, S>::push(const T& value)
|
||||
{
|
||||
emplace(BAN::move(T(value)));
|
||||
}
|
||||
|
||||
template<typename T, size_t S>
|
||||
void CircularQueue<T, S>::push(T&& value)
|
||||
{
|
||||
emplace(BAN::move(value));
|
||||
}
|
||||
|
||||
template<typename T, size_t S>
|
||||
template<typename... Args>
|
||||
void CircularQueue<T, S>::emplace(Args&&... args)
|
||||
{
|
||||
ASSERT(!full());
|
||||
new (element_at(((m_first + m_size) % capacity()))) T(BAN::forward<Args>(args)...);
|
||||
m_size++;
|
||||
}
|
||||
|
||||
template<typename T, size_t S>
|
||||
void CircularQueue<T, S>::pop()
|
||||
{
|
||||
ASSERT(!empty());
|
||||
element_at(m_first)->~T();
|
||||
m_first = (m_first + 1) % capacity();
|
||||
m_size--;
|
||||
}
|
||||
|
||||
template<typename T, size_t S>
|
||||
const T& CircularQueue<T, S>::front() const
|
||||
{
|
||||
ASSERT(!empty());
|
||||
return *element_at(m_first);
|
||||
}
|
||||
|
||||
template<typename T, size_t S>
|
||||
T& CircularQueue<T, S>::front()
|
||||
{
|
||||
ASSERT(!empty());
|
||||
return *element_at(m_first);
|
||||
}
|
||||
|
||||
template<typename T, size_t S>
|
||||
const T* CircularQueue<T, S>::element_at(size_type index) const
|
||||
{
|
||||
ASSERT(index < capacity());
|
||||
return (const T*)(m_storage + index * sizeof(T));
|
||||
}
|
||||
|
||||
template<typename T, size_t S>
|
||||
T* CircularQueue<T, S>::element_at(size_type index)
|
||||
{
|
||||
ASSERT(index < capacity());
|
||||
return (T*)(m_storage + index * sizeof(T));
|
||||
}
|
||||
|
||||
}
|
||||
80
BAN/include/BAN/Endianness.h
Normal file
80
BAN/include/BAN/Endianness.h
Normal file
@@ -0,0 +1,80 @@
|
||||
#pragma once
|
||||
|
||||
#include <BAN/Traits.h>
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
namespace BAN
|
||||
{
|
||||
|
||||
template<integral T>
|
||||
constexpr T swap_endianness(T value)
|
||||
{
|
||||
if constexpr(sizeof(T) == 1)
|
||||
return value;
|
||||
if constexpr(sizeof(T) == 2)
|
||||
return (((value >> 8) & 0xFF) << 0)
|
||||
| (((value >> 0) & 0xFF) << 8);
|
||||
if constexpr(sizeof(T) == 4)
|
||||
return (((value >> 24) & 0xFF) << 0)
|
||||
| (((value >> 16) & 0xFF) << 8)
|
||||
| (((value >> 8) & 0xFF) << 16)
|
||||
| (((value >> 0) & 0xFF) << 24);
|
||||
if constexpr(sizeof(T) == 8)
|
||||
return (((value >> 56) & 0xFF) << 0)
|
||||
| (((value >> 48) & 0xFF) << 8)
|
||||
| (((value >> 40) & 0xFF) << 16)
|
||||
| (((value >> 32) & 0xFF) << 24)
|
||||
| (((value >> 24) & 0xFF) << 32)
|
||||
| (((value >> 16) & 0xFF) << 40)
|
||||
| (((value >> 8) & 0xFF) << 48)
|
||||
| (((value >> 0) & 0xFF) << 56);
|
||||
T result { 0 };
|
||||
for (size_t i = 0; i < sizeof(T); i++)
|
||||
result |= ((value >> (i * 8)) & 0xFF) << ((sizeof(T) - i - 1) * 8);
|
||||
return result;
|
||||
}
|
||||
|
||||
template<integral T>
|
||||
constexpr T host_to_little_endian(T value)
|
||||
{
|
||||
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
||||
return value;
|
||||
#else
|
||||
return swap_endianness(value);
|
||||
#endif
|
||||
}
|
||||
|
||||
template<integral T>
|
||||
constexpr T host_to_big_endian(T value)
|
||||
{
|
||||
#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
|
||||
return value;
|
||||
#else
|
||||
return swap_endianness(value);
|
||||
#endif
|
||||
}
|
||||
|
||||
template<integral T>
|
||||
struct LittleEndian
|
||||
{
|
||||
constexpr operator T() const
|
||||
{
|
||||
return host_to_little_endian(raw);
|
||||
}
|
||||
private:
|
||||
T raw;
|
||||
};
|
||||
|
||||
template<integral T>
|
||||
struct BigEndian
|
||||
{
|
||||
constexpr operator T() const
|
||||
{
|
||||
return host_to_big_endian(raw);
|
||||
}
|
||||
private:
|
||||
T raw;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,62 +1,76 @@
|
||||
#pragma once
|
||||
|
||||
#include <BAN/Formatter.h>
|
||||
#include <BAN/StringView.h>
|
||||
#include <BAN/Variant.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#if defined(__is_kernel)
|
||||
#ifdef __is_kernel
|
||||
#include <kernel/Panic.h>
|
||||
#define MUST(expr) ({ auto e = expr; if (e.is_error()) Kernel::panic("{}", e.error()); e.release_value(); })
|
||||
#include <kernel/Errors.h>
|
||||
#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(); })
|
||||
#else
|
||||
#define MUST(expr) ({ auto e = expr; assert(!e.is_error()); e.release_value(); })
|
||||
#include <assert.h>
|
||||
#define MUST(expr) ({ auto&& e = expr; assert(!e.is_error()); e.release_value(); })
|
||||
#define MUST_REF(expr) *({ auto&& e = expr; assert(!e.is_error()); &e.release_value(); })
|
||||
#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(); })
|
||||
#define TRY_REF(expr) *({ auto&& e = expr; if (e.is_error()) return e.release_error(); &e.release_value(); })
|
||||
|
||||
namespace BAN
|
||||
{
|
||||
|
||||
class Error
|
||||
{
|
||||
#ifdef __is_kernel
|
||||
private:
|
||||
static constexpr uint64_t kernel_error_mask = uint64_t(1) << 63;
|
||||
#endif
|
||||
|
||||
public:
|
||||
static Error from_c_string(const char* message)
|
||||
#ifdef __is_kernel
|
||||
static Error from_error_code(Kernel::ErrorCode error)
|
||||
{
|
||||
Error result;
|
||||
strncpy(result.m_message, message, sizeof(Error::m_message));
|
||||
result.m_message[sizeof(Error::m_message) - 1] = '\0';
|
||||
result.m_error_code = 0xFF;
|
||||
return result;
|
||||
}
|
||||
template<typename... Args>
|
||||
static Error from_format(const char* format, Args&&... args)
|
||||
{
|
||||
char buffer[sizeof(Error::m_message)] {};
|
||||
size_t index = 0;
|
||||
auto putc = [&](char ch)
|
||||
{
|
||||
if (index < sizeof(buffer) - 1)
|
||||
buffer[index++] = ch;
|
||||
};
|
||||
Formatter::print(putc, format, forward<Args>(args)...);
|
||||
return from_c_string(buffer);
|
||||
return Error((uint64_t)error | kernel_error_mask);
|
||||
}
|
||||
#endif
|
||||
static Error from_errno(int error)
|
||||
{
|
||||
Error result;
|
||||
strncpy(result.m_message, strerror(error), sizeof(Error::m_message));
|
||||
result.m_message[sizeof(Error::m_message) - 1] = '\0';
|
||||
result.m_error_code = error;
|
||||
return result;
|
||||
return Error(error);
|
||||
}
|
||||
|
||||
uint8_t get_error_code() const { return m_error_code; }
|
||||
const char* get_message() const { return m_message; }
|
||||
#ifdef __is_kernel
|
||||
Kernel::ErrorCode kernel_error() const
|
||||
{
|
||||
return (Kernel::ErrorCode)(m_error_code & ~kernel_error_mask);
|
||||
}
|
||||
|
||||
bool is_kernel_error() const
|
||||
{
|
||||
return m_error_code & kernel_error_mask;
|
||||
}
|
||||
#endif
|
||||
|
||||
uint64_t get_error_code() const { return m_error_code; }
|
||||
BAN::StringView get_message() const
|
||||
{
|
||||
#ifdef __is_kernel
|
||||
if (m_error_code & kernel_error_mask)
|
||||
return Kernel::error_string(kernel_error());
|
||||
#endif
|
||||
return strerror(m_error_code);
|
||||
}
|
||||
|
||||
private:
|
||||
char m_message[128];
|
||||
uint8_t m_error_code;
|
||||
Error(uint64_t error)
|
||||
: m_error_code(error)
|
||||
{}
|
||||
|
||||
uint64_t m_error_code;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
@@ -76,19 +90,46 @@ namespace BAN
|
||||
: m_data(move(error))
|
||||
{}
|
||||
|
||||
bool is_error() const { return m_data.template is<Error>(); }
|
||||
bool is_error() const { return m_data.template has<Error>(); }
|
||||
const Error& error() const { return m_data.template get<Error>(); }
|
||||
Error& error() { return m_data.template get<Error>(); }
|
||||
const T& value() const { return m_data.template get<T>(); }
|
||||
T& value() { return m_data.template get<T>(); }
|
||||
|
||||
Error release_error() { return move(error()); m_data.clear(); }
|
||||
Error release_error() { return move(error()); m_data.clear(); }
|
||||
T release_value() { return move(value()); m_data.clear(); }
|
||||
|
||||
private:
|
||||
Variant<Error, T> m_data;
|
||||
};
|
||||
|
||||
template<lvalue_reference T>
|
||||
class [[nodiscard]] ErrorOr<T>
|
||||
{
|
||||
public:
|
||||
ErrorOr(T value)
|
||||
{
|
||||
m_data.template set<T>(value);
|
||||
}
|
||||
ErrorOr(Error&& error)
|
||||
: m_data(move(error))
|
||||
{ }
|
||||
ErrorOr(const Error& error)
|
||||
: m_data(error)
|
||||
{ }
|
||||
|
||||
bool is_error() const { return m_data.template has<Error>(); }
|
||||
Error& error() { return m_data.template get<Error>(); }
|
||||
const Error& error() const { return m_data.template get<Error>(); }
|
||||
T value() { return m_data.template get<T>(); }
|
||||
|
||||
Error release_error() { return move(error()); m_data.clear(); }
|
||||
T release_value() { return value(); m_data.clear(); }
|
||||
|
||||
private:
|
||||
Variant<Error, T> m_data;
|
||||
};
|
||||
|
||||
template<>
|
||||
class [[nodiscard]] ErrorOr<void>
|
||||
{
|
||||
@@ -102,12 +143,12 @@ namespace BAN
|
||||
const Error& error() const { return m_data; }
|
||||
void value() { }
|
||||
|
||||
Error release_error() { return move(m_data); m_data = Error(); }
|
||||
void release_value() { m_data = Error(); }
|
||||
Error release_error() { return move(m_data); }
|
||||
void release_value() { }
|
||||
|
||||
private:
|
||||
Error m_data;
|
||||
bool m_has_error = false;
|
||||
Error m_data { Error::from_errno(0) };
|
||||
bool m_has_error { false };
|
||||
};
|
||||
|
||||
}
|
||||
@@ -115,11 +156,8 @@ namespace BAN
|
||||
namespace BAN::Formatter
|
||||
{
|
||||
template<typename F>
|
||||
void print_argument(F putc, const Error& error, const ValueFormat&)
|
||||
void print_argument(F putc, const Error& error, const ValueFormat& format)
|
||||
{
|
||||
if (error.get_error_code() == 0xFF)
|
||||
print(putc, error.get_message());
|
||||
else
|
||||
print(putc, "{} ({})", error.get_message(), error.get_error_code());
|
||||
print_argument(putc, error.get_message(), format);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,9 +28,8 @@ namespace BAN::Formatter
|
||||
static size_t parse_format_and_print_argument(F putc, const char* format, T&& arg);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
|
||||
|
||||
IMPLEMENTATION
|
||||
|
||||
*/
|
||||
@@ -42,7 +41,7 @@ namespace BAN::Formatter
|
||||
int fill = 0;
|
||||
bool upper = false;
|
||||
};
|
||||
|
||||
|
||||
template<typename F>
|
||||
void print(F putc, const char* format)
|
||||
{
|
||||
@@ -232,7 +231,7 @@ namespace BAN::Formatter
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
|
||||
TEMPLATE SPECIALIZATIONS
|
||||
|
||||
*/
|
||||
@@ -243,10 +242,7 @@ namespace BAN::Formatter
|
||||
|
||||
template<typename F> void print_argument(F putc, char value, const ValueFormat&) { putc(value); }
|
||||
template<typename F> void print_argument(F putc, bool value, const ValueFormat&) { print(putc, value ? "true" : "false"); }
|
||||
template<typename F> void print_argument(F putc, const char* value, const ValueFormat&) { print(putc, value);}
|
||||
|
||||
//template<typename F> void print_argument(F putc, signed char value, const ValueFormat& format) { detail::print_integer(putc, value, format); }
|
||||
//template<typename F> void print_argument(F putc, unsigned char value, const ValueFormat& format) { detail::print_integer(putc, value, format); }
|
||||
//template<typename F, typename T> void print_argument(F putc, T* value, const ValueFormat& format) { detail::print_pointer(putc, (void*)value, format); }
|
||||
template<typename F> void print_argument(F putc, const char* value, const ValueFormat&) { print(putc, value); }
|
||||
template<typename F> void print_argument(F putc, char* value, const ValueFormat&) { print(putc, value); }
|
||||
|
||||
}
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#include <BAN/Traits.h>
|
||||
#include <stddef.h>
|
||||
|
||||
namespace BAN
|
||||
{
|
||||
|
||||
|
||||
|
||||
template<typename, size_t> class Array;
|
||||
template<typename> class ErrorOr;
|
||||
template<typename> class Function;
|
||||
@@ -14,5 +15,6 @@ namespace BAN
|
||||
class StringView;
|
||||
template<typename> class Vector;
|
||||
template<typename> class LinkedList;
|
||||
template<typename... Ts> requires (!is_const_v<Ts> && ...) class Variant;
|
||||
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
#include <BAN/Errors.h>
|
||||
#include <BAN/Move.h>
|
||||
#include <BAN/Memory.h>
|
||||
#include <BAN/New.h>
|
||||
|
||||
namespace BAN
|
||||
{
|
||||
@@ -43,10 +43,10 @@ namespace BAN
|
||||
clear();
|
||||
}
|
||||
|
||||
Ret operator()(Args... args)
|
||||
Ret operator()(Args... args) const
|
||||
{
|
||||
ASSERT(*this);
|
||||
return reinterpret_cast<CallableBase*>(m_storage)->call(forward<Args>(args)...);
|
||||
return reinterpret_cast<const CallableBase*>(m_storage)->call(forward<Args>(args)...);
|
||||
}
|
||||
|
||||
operator bool() const
|
||||
@@ -70,7 +70,7 @@ namespace BAN
|
||||
struct CallableBase
|
||||
{
|
||||
virtual ~CallableBase() {}
|
||||
virtual Ret call(Args...) = 0;
|
||||
virtual Ret call(Args...) const = 0;
|
||||
};
|
||||
|
||||
struct CallablePointer : public CallableBase
|
||||
@@ -79,7 +79,7 @@ namespace BAN
|
||||
: m_function(function)
|
||||
{ }
|
||||
|
||||
virtual Ret call(Args... args) override
|
||||
virtual Ret call(Args... args) const override
|
||||
{
|
||||
return m_function(forward<Args>(args)...);
|
||||
}
|
||||
@@ -96,7 +96,7 @@ namespace BAN
|
||||
, m_function(function)
|
||||
{ }
|
||||
|
||||
virtual Ret call(Args... args) override
|
||||
virtual Ret call(Args... args) const override
|
||||
{
|
||||
return (m_owner->*m_function)(forward<Args>(args)...);
|
||||
}
|
||||
@@ -114,7 +114,7 @@ namespace BAN
|
||||
, m_function(function)
|
||||
{ }
|
||||
|
||||
virtual Ret call(Args... args) override
|
||||
virtual Ret call(Args... args) const override
|
||||
{
|
||||
return (m_owner->*m_function)(forward<Args>(args)...);
|
||||
}
|
||||
@@ -131,7 +131,7 @@ namespace BAN
|
||||
: m_lambda(lambda)
|
||||
{ }
|
||||
|
||||
virtual Ret call(Args... args) override
|
||||
virtual Ret call(Args... args) const override
|
||||
{
|
||||
return m_lambda(forward<Args>(args)...);
|
||||
}
|
||||
@@ -141,7 +141,7 @@ namespace BAN
|
||||
};
|
||||
|
||||
private:
|
||||
static constexpr size_t m_size = sizeof(void*) * 4;
|
||||
static constexpr size_t m_size = sizeof(void*) * 5;
|
||||
alignas(CallableBase) uint8_t m_storage[m_size] { 0 };
|
||||
};
|
||||
|
||||
|
||||
@@ -7,13 +7,31 @@
|
||||
namespace BAN
|
||||
{
|
||||
|
||||
template<typename Container>
|
||||
class HashMapIterator;
|
||||
|
||||
template<typename Key, typename T, typename HASH = BAN::hash<Key>>
|
||||
class HashMap
|
||||
{
|
||||
public:
|
||||
struct Entry
|
||||
{
|
||||
template<typename... Args>
|
||||
Entry(const Key& key, Args&&... args)
|
||||
: key(key)
|
||||
, value(forward<Args>(args)...)
|
||||
{}
|
||||
|
||||
Key key;
|
||||
T value;
|
||||
};
|
||||
|
||||
public:
|
||||
using size_type = size_t;
|
||||
using key_type = Key;
|
||||
using value_type = T;
|
||||
using iterator = IteratorDouble<Entry, Vector, LinkedList, HashMap>;
|
||||
using const_iterator = ConstIteratorDouble<Entry, Vector, LinkedList, HashMap>;
|
||||
|
||||
public:
|
||||
HashMap() = default;
|
||||
@@ -29,6 +47,11 @@ namespace BAN
|
||||
template<typename... Args>
|
||||
ErrorOr<void> emplace(const Key&, Args&&...);
|
||||
|
||||
iterator begin() { return iterator(m_buckets.end(), m_buckets.begin()); }
|
||||
iterator end() { return iterator(m_buckets.end(), 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()); }
|
||||
|
||||
ErrorOr<void> reserve(size_type);
|
||||
|
||||
void remove(const Key&);
|
||||
@@ -42,19 +65,6 @@ namespace BAN
|
||||
bool empty() const;
|
||||
size_type size() const;
|
||||
|
||||
private:
|
||||
struct Entry
|
||||
{
|
||||
template<typename... Args>
|
||||
Entry(const Key& key, Args&&... args)
|
||||
: key(key)
|
||||
, value(forward<Args>(args)...)
|
||||
{}
|
||||
|
||||
Key key;
|
||||
T value;
|
||||
};
|
||||
|
||||
private:
|
||||
ErrorOr<void> rebucket(size_type);
|
||||
LinkedList<Entry>& get_bucket(const Key&);
|
||||
@@ -63,6 +73,8 @@ namespace BAN
|
||||
private:
|
||||
Vector<LinkedList<Entry>> m_buckets;
|
||||
size_type m_size = 0;
|
||||
|
||||
friend iterator;
|
||||
};
|
||||
|
||||
template<typename Key, typename T, typename HASH>
|
||||
@@ -246,4 +258,4 @@ namespace BAN
|
||||
return m_buckets[index];
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,8 +85,6 @@ namespace BAN
|
||||
friend class HashSet<T, HASH>;
|
||||
};
|
||||
|
||||
|
||||
|
||||
template<typename T, typename HASH>
|
||||
HashSet<T, HASH>::HashSet(const HashSet<T, HASH>& other)
|
||||
: m_buckets(other.m_buckets)
|
||||
@@ -231,8 +229,6 @@ namespace BAN
|
||||
return m_buckets[index];
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<typename T, typename HASH>
|
||||
HashSetIterator<T, HASH>& HashSetIterator<T, HASH>::operator++()
|
||||
{
|
||||
|
||||
12
BAN/include/BAN/Iteration.h
Normal file
12
BAN/include/BAN/Iteration.h
Normal file
@@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
namespace BAN
|
||||
{
|
||||
|
||||
enum class Iteration
|
||||
{
|
||||
Continue,
|
||||
Break
|
||||
};
|
||||
|
||||
}
|
||||
229
BAN/include/BAN/Iterators.h
Normal file
229
BAN/include/BAN/Iterators.h
Normal file
@@ -0,0 +1,229 @@
|
||||
#pragma once
|
||||
|
||||
#include <BAN/Assert.h>
|
||||
|
||||
namespace BAN
|
||||
{
|
||||
|
||||
template<typename T, typename Container, bool CONST>
|
||||
class IteratorSimpleGeneral
|
||||
{
|
||||
public:
|
||||
IteratorSimpleGeneral() = default;
|
||||
template<bool CONST2, typename = enable_if_t<CONST2 == CONST || CONST>>
|
||||
IteratorSimpleGeneral(const IteratorSimpleGeneral<T, Container, CONST2>& other)
|
||||
: m_pointer(other.m_pointer)
|
||||
{
|
||||
}
|
||||
|
||||
const T& operator*() const
|
||||
{
|
||||
ASSERT(m_pointer);
|
||||
return *m_pointer;
|
||||
}
|
||||
template<bool CONST2 = CONST>
|
||||
enable_if_t<!CONST2, T&> operator*()
|
||||
{
|
||||
ASSERT(m_pointer);
|
||||
return *m_pointer;
|
||||
}
|
||||
|
||||
const T* operator->() const
|
||||
{
|
||||
ASSERT(m_pointer);
|
||||
return m_pointer;
|
||||
}
|
||||
template<bool CONST2 = CONST>
|
||||
enable_if_t<!CONST2, T*> operator->()
|
||||
{
|
||||
ASSERT(m_pointer);
|
||||
return m_pointer;
|
||||
}
|
||||
|
||||
IteratorSimpleGeneral& operator++()
|
||||
{
|
||||
ASSERT(m_pointer);
|
||||
++m_pointer;
|
||||
return *this;
|
||||
}
|
||||
IteratorSimpleGeneral operator++(int)
|
||||
{
|
||||
auto temp = *this;
|
||||
++(*this);
|
||||
return temp;
|
||||
}
|
||||
|
||||
IteratorSimpleGeneral& operator--()
|
||||
{
|
||||
ASSERT(m_pointer);
|
||||
return --m_pointer;
|
||||
}
|
||||
IteratorSimpleGeneral operator--(int)
|
||||
{
|
||||
auto temp = *this;
|
||||
--(*this);
|
||||
return temp;
|
||||
}
|
||||
|
||||
bool operator==(const IteratorSimpleGeneral& other) const
|
||||
{
|
||||
return m_pointer == other.m_pointer;
|
||||
}
|
||||
bool operator!=(const IteratorSimpleGeneral& other) const
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
operator bool() const
|
||||
{
|
||||
return m_pointer;
|
||||
}
|
||||
|
||||
private:
|
||||
IteratorSimpleGeneral(maybe_const_t<CONST, T>* pointer)
|
||||
: m_pointer(pointer)
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
maybe_const_t<CONST, T>* m_pointer = nullptr;
|
||||
|
||||
friend IteratorSimpleGeneral<T, Container, !CONST>;
|
||||
friend Container;
|
||||
};
|
||||
|
||||
template<typename T, template<typename> typename OuterContainer, template<typename> typename InnerContainer, typename Container, bool CONST>
|
||||
class IteratorDoubleGeneral
|
||||
{
|
||||
public:
|
||||
using Inner = InnerContainer<T>;
|
||||
using Outer = OuterContainer<Inner>;
|
||||
|
||||
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>;
|
||||
|
||||
public:
|
||||
IteratorDoubleGeneral() = default;
|
||||
template<bool CONST2, typename = enable_if_t<CONST2 == CONST || CONST>>
|
||||
IteratorDoubleGeneral(const IteratorDoubleGeneral<T, OuterContainer, InnerContainer, Container, CONST2>& other)
|
||||
: m_outer_end(other.m_outer_end)
|
||||
, m_outer_current(other.m_outer_current)
|
||||
, m_inner_current(other.m_inner_current)
|
||||
{
|
||||
}
|
||||
|
||||
const T& operator*() const
|
||||
{
|
||||
ASSERT(*this);
|
||||
ASSERT(m_outer_current != m_outer_end);
|
||||
ASSERT(m_inner_current);
|
||||
return m_inner_current.operator*();
|
||||
}
|
||||
template<bool CONST2 = CONST>
|
||||
enable_if_t<!CONST2, T&> operator*()
|
||||
{
|
||||
ASSERT(*this);
|
||||
ASSERT(m_outer_current != m_outer_end);
|
||||
ASSERT(m_inner_current);
|
||||
return m_inner_current.operator*();
|
||||
}
|
||||
|
||||
const T* operator->() const
|
||||
{
|
||||
ASSERT(*this);
|
||||
ASSERT(m_outer_current != m_outer_end);
|
||||
ASSERT(m_inner_current);
|
||||
return m_inner_current.operator->();
|
||||
}
|
||||
template<bool CONST2 = CONST>
|
||||
enable_if_t<!CONST2, T*> operator->()
|
||||
{
|
||||
ASSERT(*this);
|
||||
ASSERT(m_outer_current != m_outer_end);
|
||||
ASSERT(m_inner_current);
|
||||
return m_inner_current.operator->();
|
||||
}
|
||||
|
||||
IteratorDoubleGeneral& operator++()
|
||||
{
|
||||
ASSERT(*this);
|
||||
ASSERT(m_outer_current != m_outer_end);
|
||||
ASSERT(m_inner_current);
|
||||
m_inner_current++;
|
||||
find_valid_or_end();
|
||||
return *this;
|
||||
}
|
||||
IteratorDoubleGeneral operator++(int)
|
||||
{
|
||||
auto temp = *this;
|
||||
++(*this);
|
||||
return temp;
|
||||
}
|
||||
|
||||
bool operator==(const IteratorDoubleGeneral& other) const
|
||||
{
|
||||
if (!*this || !other)
|
||||
return false;
|
||||
if (m_outer_end != other.m_outer_end)
|
||||
return false;
|
||||
if (m_outer_current != other.m_outer_current)
|
||||
return false;
|
||||
if (m_outer_current == m_outer_end)
|
||||
return true;
|
||||
return m_inner_current == other.m_inner_current;
|
||||
}
|
||||
bool operator!=(const IteratorDoubleGeneral& other) const
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
operator bool() const
|
||||
{
|
||||
return m_outer_end && m_outer_current;
|
||||
}
|
||||
|
||||
private:
|
||||
IteratorDoubleGeneral(const OuterIterator& outer_end, const OuterIterator& outer_current)
|
||||
: m_outer_end(outer_end)
|
||||
, m_outer_current(outer_current)
|
||||
{
|
||||
if (outer_current != outer_end)
|
||||
{
|
||||
m_inner_current = m_outer_current->begin();
|
||||
find_valid_or_end();
|
||||
}
|
||||
}
|
||||
|
||||
void find_valid_or_end()
|
||||
{
|
||||
while (m_inner_current == m_outer_current->end())
|
||||
{
|
||||
m_outer_current++;
|
||||
if (m_outer_current == m_outer_end)
|
||||
break;
|
||||
m_inner_current = m_outer_current->begin();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
OuterIterator m_outer_end;
|
||||
OuterIterator m_outer_current;
|
||||
InnerIterator m_inner_current;
|
||||
|
||||
friend class IteratorDoubleGeneral<T, OuterContainer, InnerContainer, Container, !CONST>;
|
||||
friend Container;
|
||||
};
|
||||
|
||||
template<typename T, typename Container>
|
||||
using IteratorSimple = IteratorSimpleGeneral<T, Container, false>;
|
||||
|
||||
template<typename T, typename Container>
|
||||
using ConstIteratorSimple = IteratorSimpleGeneral<T, Container, true>;
|
||||
|
||||
template<typename T, template<typename> typename OuterContainer, template<typename> typename InnerContainer, typename Container>
|
||||
using IteratorDouble = IteratorDoubleGeneral<T, OuterContainer, InnerContainer, Container, false>;
|
||||
|
||||
template<typename T, template<typename> typename OuterContainer, template<typename> typename InnerContainer, typename Container>
|
||||
using ConstIteratorDouble = IteratorDoubleGeneral<T, OuterContainer, InnerContainer, Container, true>;
|
||||
|
||||
}
|
||||
@@ -1,15 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include <BAN/Errors.h>
|
||||
#include <BAN/Memory.h>
|
||||
#include <BAN/Move.h>
|
||||
#include <BAN/New.h>
|
||||
|
||||
namespace BAN
|
||||
{
|
||||
|
||||
template<typename T, bool CONST>
|
||||
class LinkedListIterator;
|
||||
|
||||
|
||||
template<typename T>
|
||||
class LinkedList
|
||||
{
|
||||
@@ -38,7 +38,7 @@ namespace BAN
|
||||
ErrorOr<void> emplace(iterator, Args&&...);
|
||||
|
||||
void pop_back();
|
||||
void remove(iterator);
|
||||
iterator remove(iterator);
|
||||
void clear();
|
||||
|
||||
iterator begin() { return iterator(m_data, empty()); }
|
||||
@@ -114,8 +114,6 @@ namespace BAN
|
||||
friend class LinkedListIterator<T, !CONST>;
|
||||
};
|
||||
|
||||
|
||||
|
||||
template<typename T>
|
||||
LinkedList<T>& LinkedList<T>::operator=(const LinkedList<T>& other)
|
||||
{
|
||||
@@ -197,11 +195,11 @@ namespace BAN
|
||||
template<typename T>
|
||||
void LinkedList<T>::pop_back()
|
||||
{
|
||||
return remove(m_last);
|
||||
remove(iterator(m_last, false));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void LinkedList<T>::remove(iterator iter)
|
||||
LinkedList<T>::iterator LinkedList<T>::remove(iterator iter)
|
||||
{
|
||||
ASSERT(!empty() && iter);
|
||||
Node* node = iter.m_current;
|
||||
@@ -212,6 +210,7 @@ namespace BAN
|
||||
(prev ? prev->next : m_data) = next;
|
||||
(next ? next->prev : m_last) = prev;
|
||||
m_size--;
|
||||
return next ? iterator(next, false) : iterator(m_last, true);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
@@ -292,8 +291,6 @@ namespace BAN
|
||||
return node;
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<typename T, bool CONST>
|
||||
template<bool C>
|
||||
LinkedListIterator<T, CONST>::LinkedListIterator(const LinkedListIterator<T, C>& other, enable_if_t<C == CONST || !C>*)
|
||||
@@ -378,7 +375,7 @@ namespace BAN
|
||||
ASSERT(m_current);
|
||||
return &m_current->value;
|
||||
}
|
||||
|
||||
|
||||
template<typename T, bool CONST>
|
||||
bool LinkedListIterator<T, CONST>::operator==(const LinkedListIterator<T, CONST>& other) const
|
||||
{
|
||||
|
||||
@@ -52,20 +52,53 @@ namespace BAN::Math
|
||||
}
|
||||
|
||||
template<integral T>
|
||||
inline constexpr T little_endian_to_host(const uint8_t* bytes)
|
||||
inline constexpr bool is_power_of_two(T value)
|
||||
{
|
||||
T result = 0;
|
||||
for (size_t i = 0; i < sizeof(T); i++)
|
||||
result |= (T)bytes[i] << (i * 8);
|
||||
if (value == 0)
|
||||
return false;
|
||||
return (value & (value - 1)) == 0;
|
||||
}
|
||||
|
||||
template<floating_point T>
|
||||
inline constexpr T log2(T value)
|
||||
{
|
||||
T result;
|
||||
asm volatile("fyl2x" : "=t"(result) : "0"(value), "u"((T)1.0) : "st(1)");
|
||||
return result;
|
||||
}
|
||||
|
||||
template<integral T>
|
||||
inline constexpr T big_endian_to_host(const uint8_t* bytes)
|
||||
template<floating_point T>
|
||||
inline constexpr T log10(T value)
|
||||
{
|
||||
T result = 0;
|
||||
for (size_t i = 0; i < sizeof(T); i++)
|
||||
result |= (T)bytes[i] << (8 * (sizeof(T) - i - 1));
|
||||
constexpr T INV_LOG_2_10 = 0.3010299956639811952137388947244930267681898814621085413104274611;
|
||||
T result;
|
||||
asm volatile("fyl2x" : "=t"(result) : "0"(value), "u"(INV_LOG_2_10) : "st(1)");
|
||||
return result;
|
||||
}
|
||||
|
||||
template<floating_point T>
|
||||
inline constexpr T log(T value, T base)
|
||||
{
|
||||
return log2(value) / log2(base);
|
||||
}
|
||||
|
||||
template<floating_point T>
|
||||
inline constexpr T pow(T base, T exp)
|
||||
{
|
||||
T result;
|
||||
asm volatile(
|
||||
"fyl2x;"
|
||||
"fld1;"
|
||||
"fld %%st(1);"
|
||||
"fprem;"
|
||||
"f2xm1;"
|
||||
"faddp;"
|
||||
"fscale;"
|
||||
"fxch %%st(1);"
|
||||
"fstp %%st;"
|
||||
: "=t"(result)
|
||||
: "0"(base), "u"(exp)
|
||||
);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
#include <BAN/Traits.h>
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
namespace BAN
|
||||
{
|
||||
|
||||
@@ -24,4 +26,7 @@ namespace BAN
|
||||
return static_cast<T&&>(arg);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
inline void* operator new(size_t, void* addr) { return addr; }
|
||||
inline void* operator new[](size_t, void* addr) { return addr; }
|
||||
18
BAN/include/BAN/New.h
Normal file
18
BAN/include/BAN/New.h
Normal file
@@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
#if defined(__is_kernel)
|
||||
#include <kernel/Memory/kmalloc.h>
|
||||
#else
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
|
||||
namespace BAN
|
||||
{
|
||||
#if defined(__is_kernel)
|
||||
static constexpr void*(&allocator)(size_t) = kmalloc;
|
||||
static constexpr void(&deallocator)(void*) = kfree;
|
||||
#else
|
||||
static constexpr void*(&allocator)(size_t) = malloc;
|
||||
static constexpr void(&deallocator)(void*) = free;
|
||||
#endif
|
||||
}
|
||||
195
BAN/include/BAN/Optional.h
Normal file
195
BAN/include/BAN/Optional.h
Normal file
@@ -0,0 +1,195 @@
|
||||
#pragma once
|
||||
|
||||
#include <BAN/Assert.h>
|
||||
#include <BAN/Move.h>
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace BAN
|
||||
{
|
||||
|
||||
template<typename T>
|
||||
class Optional
|
||||
{
|
||||
public:
|
||||
Optional();
|
||||
Optional(Optional&&);
|
||||
Optional(const Optional&);
|
||||
Optional(const T&);
|
||||
Optional(T&&);
|
||||
template<typename... Args>
|
||||
Optional(Args&&...);
|
||||
|
||||
~Optional();
|
||||
|
||||
Optional& operator=(Optional&&);
|
||||
Optional& operator=(const Optional&);
|
||||
|
||||
template<typename... Args>
|
||||
Optional& emplace(Args&&...);
|
||||
|
||||
T* operator->();
|
||||
const T* operator->() const;
|
||||
|
||||
T& operator*();
|
||||
const T& operator*() const;
|
||||
|
||||
bool has_value() const;
|
||||
|
||||
T release_value();
|
||||
T& value();
|
||||
const T& value() const;
|
||||
|
||||
void clear();
|
||||
|
||||
private:
|
||||
alignas(T) uint8_t m_storage[sizeof(T)];
|
||||
bool m_has_value { false };
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
Optional<T>::Optional()
|
||||
: m_has_value(false)
|
||||
{}
|
||||
|
||||
template<typename T>
|
||||
Optional<T>::Optional(Optional<T>&& other)
|
||||
: m_has_value(other.has_value())
|
||||
{
|
||||
if (other.has_value())
|
||||
new (m_storage) T(move(other.release_value()));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Optional<T>::Optional(const Optional<T>& other)
|
||||
: m_has_value(other.has_value())
|
||||
{
|
||||
if (other.has_value())
|
||||
new (m_storage) T(other.value());
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Optional<T>::Optional(const T& value)
|
||||
: m_has_value(true)
|
||||
{
|
||||
new (m_storage) T(value);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Optional<T>::Optional(T&& value)
|
||||
: m_has_value(true)
|
||||
{
|
||||
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>
|
||||
Optional<T>::~Optional()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Optional<T>& Optional<T>::operator=(Optional&& other)
|
||||
{
|
||||
clear();
|
||||
m_has_value = other.has_value();
|
||||
if (other.has_value())
|
||||
new (m_storage) T(move(other.release_value()));
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Optional<T>& Optional<T>::operator=(const Optional& other)
|
||||
{
|
||||
clear();
|
||||
m_has_value = other.has_value();
|
||||
if (other.has_value)
|
||||
new (m_storage) T(other.value());
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
template<typename... Args>
|
||||
Optional<T>& Optional<T>::emplace(Args&&... args)
|
||||
{
|
||||
clear();
|
||||
m_has_value = true;
|
||||
new (m_storage) T(forward<Args>(args)...);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T* Optional<T>::operator->()
|
||||
{
|
||||
ASSERT(has_value());
|
||||
return &value();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
const T* Optional<T>::operator->() const
|
||||
{
|
||||
ASSERT(has_value());
|
||||
return &value();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T& Optional<T>::operator*()
|
||||
{
|
||||
ASSERT(has_value());
|
||||
return value();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
const T& Optional<T>::operator*() const
|
||||
{
|
||||
ASSERT(has_value());
|
||||
return value();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool Optional<T>::has_value() const
|
||||
{
|
||||
return m_has_value;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T Optional<T>::release_value()
|
||||
{
|
||||
ASSERT(has_value());
|
||||
T released_value = move(value());
|
||||
value().~T();
|
||||
m_has_value = false;
|
||||
return move(released_value);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T& Optional<T>::value()
|
||||
{
|
||||
ASSERT(has_value());
|
||||
return (T&)m_storage;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
const T& Optional<T>::value() const
|
||||
{
|
||||
ASSERT(has_value());
|
||||
return (const T&)m_storage;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void Optional<T>::clear()
|
||||
{
|
||||
if (m_has_value)
|
||||
value().~T();
|
||||
m_has_value = false;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,9 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include <BAN/Errors.h>
|
||||
#include <BAN/Iterators.h>
|
||||
#include <BAN/Math.h>
|
||||
#include <BAN/Memory.h>
|
||||
#include <BAN/Move.h>
|
||||
#include <BAN/New.h>
|
||||
|
||||
namespace BAN
|
||||
{
|
||||
@@ -14,6 +15,8 @@ namespace BAN
|
||||
public:
|
||||
using size_type = size_t;
|
||||
using value_type = T;
|
||||
using iterator = IteratorSimple<T, Queue>;
|
||||
using const_iterator = ConstIteratorSimple<T, Queue>;
|
||||
|
||||
public:
|
||||
Queue() = default;
|
||||
@@ -32,6 +35,11 @@ namespace BAN
|
||||
ErrorOr<void> reserve(size_type);
|
||||
ErrorOr<void> shrink_to_fit();
|
||||
|
||||
iterator begin() { return iterator(m_data); }
|
||||
iterator end() { return iterator(m_data + m_size); }
|
||||
const_iterator begin() const { return const_iterator(m_data); }
|
||||
const_iterator end() const { return const_iterator(m_data + m_size); }
|
||||
|
||||
void pop();
|
||||
void clear();
|
||||
|
||||
|
||||
@@ -1,27 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
|
||||
#include <BAN/Errors.h>
|
||||
#include <BAN/Move.h>
|
||||
#include <BAN/NoCopyMove.h>
|
||||
|
||||
#if defined(__is_kernel)
|
||||
#include <kernel/kmalloc.h>
|
||||
#else
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace BAN
|
||||
{
|
||||
#if defined(__is_kernel)
|
||||
static constexpr void*(&allocator)(size_t) = kmalloc;
|
||||
static constexpr void(&deallocator)(void*) = kfree;
|
||||
#else
|
||||
static constexpr void*(&allocator)(size_t) = malloc;
|
||||
static constexpr void(&deallocator)(void*) = free;
|
||||
#endif
|
||||
|
||||
template<typename T>
|
||||
class RefCounted
|
||||
@@ -68,7 +53,6 @@ namespace BAN
|
||||
if (m_pointer)
|
||||
m_pointer->ref();
|
||||
}
|
||||
|
||||
~RefPtr() { clear(); }
|
||||
|
||||
template<typename U>
|
||||
@@ -90,6 +74,10 @@ namespace BAN
|
||||
|
||||
RefPtr(const RefPtr& other) { *this = other; }
|
||||
RefPtr(RefPtr&& other) { *this = move(other); }
|
||||
template<typename U>
|
||||
RefPtr(const RefPtr<U>& other) { *this = other; }
|
||||
template<typename U>
|
||||
RefPtr(RefPtr<U>&& other) { *this = move(other); }
|
||||
|
||||
RefPtr& operator=(const RefPtr& other)
|
||||
{
|
||||
@@ -108,6 +96,25 @@ namespace BAN
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename U>
|
||||
RefPtr& operator=(const RefPtr<U>& other)
|
||||
{
|
||||
clear();
|
||||
m_pointer = other.m_pointer;
|
||||
if (m_pointer)
|
||||
m_pointer->ref();
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename U>
|
||||
RefPtr& operator=(RefPtr<U>&& other)
|
||||
{
|
||||
clear();
|
||||
m_pointer = other.m_pointer;
|
||||
other.m_pointer = nullptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
T* ptr() { ASSERT(!empty()); return m_pointer; }
|
||||
const T* ptr() const { ASSERT(!empty()); return m_pointer; }
|
||||
|
||||
@@ -129,9 +136,9 @@ namespace BAN
|
||||
|
||||
private:
|
||||
T* m_pointer = nullptr;
|
||||
|
||||
template<typename U>
|
||||
friend class RefPtr;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
inline void* operator new(size_t, void* addr) { return addr; }
|
||||
inline void* operator new[](size_t, void* addr) { return addr; }
|
||||
@@ -13,10 +13,16 @@ namespace BAN
|
||||
{ }
|
||||
~ScopeGuard()
|
||||
{
|
||||
m_func();
|
||||
if (m_enabled)
|
||||
m_func();
|
||||
}
|
||||
void disable()
|
||||
{
|
||||
m_enabled = false;
|
||||
}
|
||||
private:
|
||||
BAN::Function<void()> m_func;
|
||||
bool m_enabled { true };
|
||||
};
|
||||
|
||||
}
|
||||
134
BAN/include/BAN/Span.h
Normal file
134
BAN/include/BAN/Span.h
Normal file
@@ -0,0 +1,134 @@
|
||||
#pragma once
|
||||
|
||||
#include <BAN/Assert.h>
|
||||
#include <BAN/Iterators.h>
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
namespace BAN
|
||||
{
|
||||
|
||||
template<typename T>
|
||||
class Span
|
||||
{
|
||||
public:
|
||||
using value_type = T;
|
||||
using size_type = size_t;
|
||||
using iterator = IteratorSimple<T, Span>;
|
||||
using const_iterator = ConstIteratorSimple<T, Span>;
|
||||
|
||||
public:
|
||||
Span() = default;
|
||||
Span(T*, size_type);
|
||||
Span(Span<T>&);
|
||||
template<typename S>
|
||||
requires(is_same_v<T, const S>)
|
||||
Span(const Span<S>&);
|
||||
|
||||
iterator begin() { return iterator(m_data); }
|
||||
iterator end() { return iterator(m_data + m_size); }
|
||||
const_iterator begin() const { return const_iterator(m_data); }
|
||||
const_iterator end() const { return const_iterator(m_data + m_size); }
|
||||
|
||||
T& operator[](size_type);
|
||||
const T& operator[](size_type) const;
|
||||
|
||||
T* data();
|
||||
const T* data() const;
|
||||
|
||||
bool empty() const;
|
||||
size_type size() const;
|
||||
|
||||
void clear();
|
||||
|
||||
Span slice(size_type, size_type = ~size_type(0));
|
||||
|
||||
Span<const T> as_const() const { return Span<const T>(m_data, m_size); }
|
||||
|
||||
private:
|
||||
T* m_data = nullptr;
|
||||
size_type m_size = 0;
|
||||
};
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,8 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include <BAN/ForwardList.h>
|
||||
#include <BAN/Errors.h>
|
||||
#include <BAN/Formatter.h>
|
||||
#include <BAN/ForwardList.h>
|
||||
#include <BAN/Hash.h>
|
||||
#include <BAN/Iterators.h>
|
||||
|
||||
namespace BAN
|
||||
{
|
||||
@@ -11,6 +13,9 @@ namespace BAN
|
||||
{
|
||||
public:
|
||||
using size_type = size_t;
|
||||
using iterator = IteratorSimple<char, String>;
|
||||
using const_iterator = ConstIteratorSimple<char, String>;
|
||||
static constexpr size_type sso_capacity = 15;
|
||||
|
||||
public:
|
||||
String();
|
||||
@@ -30,18 +35,26 @@ namespace BAN
|
||||
ErrorOr<void> insert(char, size_type);
|
||||
ErrorOr<void> insert(StringView, size_type);
|
||||
ErrorOr<void> append(StringView);
|
||||
ErrorOr<void> append(const String&);
|
||||
|
||||
void pop_back();
|
||||
void remove(size_type);
|
||||
void erase(size_type, size_type);
|
||||
|
||||
void clear();
|
||||
|
||||
char operator[](size_type) const;
|
||||
char& operator[](size_type);
|
||||
const_iterator begin() const { return const_iterator(data()); }
|
||||
iterator begin() { return iterator(data()); }
|
||||
const_iterator end() const { return const_iterator(data() + size()); }
|
||||
iterator end() { return iterator(data() + size()); }
|
||||
|
||||
char front() const { ASSERT(m_size > 0); return data()[0]; }
|
||||
char& front() { ASSERT(m_size > 0); return data()[0]; }
|
||||
|
||||
char back() const { ASSERT(m_size > 0); return data()[m_size - 1]; }
|
||||
char& back() { ASSERT(m_size > 0); return data()[m_size - 1]; }
|
||||
|
||||
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]; }
|
||||
|
||||
bool operator==(const String&) const;
|
||||
bool operator==(StringView) const;
|
||||
bool operator==(const char*) const;
|
||||
|
||||
@@ -49,31 +62,48 @@ namespace BAN
|
||||
ErrorOr<void> reserve(size_type);
|
||||
ErrorOr<void> shrink_to_fit();
|
||||
|
||||
StringView sv() const;
|
||||
StringView sv() const { return StringView(data(), size()); }
|
||||
|
||||
bool empty() const;
|
||||
size_type size() const;
|
||||
bool empty() const { return m_size == 0; }
|
||||
size_type size() const { return m_size; }
|
||||
size_type capacity() const;
|
||||
|
||||
char* data();
|
||||
const char* data() const;
|
||||
|
||||
private:
|
||||
ErrorOr<void> ensure_capacity(size_type);
|
||||
|
||||
ErrorOr<void> copy_impl(StringView);
|
||||
void move_impl(String&&);
|
||||
bool has_sso() const;
|
||||
|
||||
bool fits_in_sso() const { return fits_in_sso(m_size); }
|
||||
static bool fits_in_sso(size_type size) { return size < sso_capacity; }
|
||||
|
||||
private:
|
||||
char* m_data = nullptr;
|
||||
size_type m_capacity = 0;
|
||||
size_type m_size = 0;
|
||||
struct SSOStorage
|
||||
{
|
||||
char data[sso_capacity + 1] {};
|
||||
};
|
||||
struct GeneralStorage
|
||||
{
|
||||
size_type capacity { 0 };
|
||||
char* data { nullptr };
|
||||
};
|
||||
|
||||
private:
|
||||
union {
|
||||
SSOStorage sso_storage;
|
||||
GeneralStorage general_storage;
|
||||
} m_storage { .sso_storage = SSOStorage() };
|
||||
size_type m_size : sizeof(size_type) * 8 - 1 { 0 };
|
||||
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){ result.push_back(c); }, format, args...);
|
||||
BAN::Formatter::print([&](char c){ MUST(result.push_back(c)); }, format, args...);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include <BAN/ForwardList.h>
|
||||
#include <BAN/Formatter.h>
|
||||
#include <BAN/Iterators.h>
|
||||
|
||||
namespace BAN
|
||||
{
|
||||
@@ -10,12 +11,16 @@ namespace BAN
|
||||
{
|
||||
public:
|
||||
using size_type = size_t;
|
||||
using const_iterator = ConstIteratorSimple<char, StringView>;
|
||||
|
||||
public:
|
||||
StringView();
|
||||
StringView(const String&);
|
||||
StringView(const char*, size_type = -1);
|
||||
|
||||
const_iterator begin() const { return const_iterator(m_data); }
|
||||
const_iterator end() const { return const_iterator(m_data + m_size); }
|
||||
|
||||
char operator[](size_type) const;
|
||||
|
||||
bool operator==(const String&) const;
|
||||
@@ -30,6 +35,7 @@ namespace BAN
|
||||
char back() const;
|
||||
char front() const;
|
||||
|
||||
bool contains(char) const;
|
||||
size_type count(char) const;
|
||||
|
||||
bool empty() const;
|
||||
|
||||
@@ -9,15 +9,18 @@ namespace BAN
|
||||
|
||||
struct Time
|
||||
{
|
||||
uint8_t second;
|
||||
uint8_t minute;
|
||||
uint8_t hour;
|
||||
uint8_t week_day;
|
||||
uint8_t day;
|
||||
uint32_t year;
|
||||
uint8_t month;
|
||||
int year;
|
||||
uint8_t day;
|
||||
uint8_t hour;
|
||||
uint8_t minute;
|
||||
uint8_t second;
|
||||
uint8_t week_day;
|
||||
};
|
||||
|
||||
uint64_t to_unix_time(const BAN::Time&);
|
||||
BAN::Time from_unix_time(uint64_t);
|
||||
|
||||
}
|
||||
|
||||
namespace BAN::Formatter
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace BAN
|
||||
{
|
||||
|
||||
|
||||
template<typename T> struct remove_refenrece { using type = T; };
|
||||
template<typename T> struct remove_refenrece<T&> { using type = T; };
|
||||
template<typename T> struct remove_refenrece<T&&> { using type = T; };
|
||||
@@ -30,6 +30,10 @@ namespace BAN
|
||||
template<typename T> struct maybe_const<true, T> { using type = const T; };
|
||||
template<bool B, typename T> using maybe_const_t = typename maybe_const<B, T>::type;
|
||||
|
||||
template<bool B, typename T1, typename T2> struct either_or { using type = T2; };
|
||||
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;
|
||||
|
||||
struct true_type { static constexpr bool value = true; };
|
||||
struct false_type { static constexpr bool value = false; };
|
||||
|
||||
@@ -40,6 +44,7 @@ namespace BAN
|
||||
template<typename T> struct is_lvalue_reference : false_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> concept lvalue_reference = is_lvalue_reference_v<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;
|
||||
@@ -60,6 +65,21 @@ namespace BAN
|
||||
template<typename T> inline constexpr bool is_pointer_v = is_pointer<T>::value;
|
||||
template<typename T> concept pointer = is_pointer_v<T>;
|
||||
|
||||
template<typename T> struct is_const : false_type {};
|
||||
template<typename T> struct is_const<const T> : true_type {};
|
||||
template<typename T> inline constexpr bool is_const_v = is_const<T>::value;
|
||||
|
||||
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;
|
||||
|
||||
namespace detail
|
||||
{
|
||||
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 : detail::is_signed<T> {};
|
||||
template<typename T> inline constexpr bool is_signed_v = is_signed<T>::value;
|
||||
|
||||
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 greater { constexpr bool operator()(const T& lhs, const T& rhs) const { return lhs > rhs; } };
|
||||
|
||||
@@ -3,26 +3,79 @@
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
namespace BAN
|
||||
namespace BAN::UTF8
|
||||
{
|
||||
|
||||
static constexpr uint16_t utf8_to_codepoint(uint8_t* bytes, size_t count)
|
||||
static constexpr uint32_t invalid = 0xFFFFFFFF;
|
||||
|
||||
constexpr uint32_t byte_length(uint8_t first_byte)
|
||||
{
|
||||
if (count > 3)
|
||||
return 0xFFFF;
|
||||
if ((first_byte & 0x80) == 0x00)
|
||||
return 1;
|
||||
if ((first_byte & 0xE0) == 0xC0)
|
||||
return 2;
|
||||
if ((first_byte & 0xF0) == 0xE0)
|
||||
return 3;
|
||||
if ((first_byte & 0xF8) == 0xF0)
|
||||
return 4;
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (size_t i = 1; i < count; i++)
|
||||
constexpr uint32_t to_codepoint(uint8_t* bytes)
|
||||
{
|
||||
uint32_t length = byte_length(bytes[0]);
|
||||
|
||||
for (uint32_t i = 1; i < length; i++)
|
||||
if ((bytes[i] & 0xC0) != 0x80)
|
||||
return 0xFFFF;
|
||||
|
||||
switch (count)
|
||||
return UTF8::invalid;
|
||||
|
||||
switch (length)
|
||||
{
|
||||
case 1: return bytes[0];
|
||||
case 2: return ((bytes[0] & 0x1F) << 6) | (bytes[1] & 0x3F);
|
||||
case 3: return ((bytes[0] & 0x1F) << 12) | ((bytes[1] & 0x3F) << 6) | (bytes[2] & 0x3F);
|
||||
case 1: return ((bytes[0] & 0x80) != 0x00) ? UTF8::invalid : bytes[0];
|
||||
case 2: return ((bytes[0] & 0xE0) != 0xC0) ? UTF8::invalid : ((bytes[0] & 0x1F) << 6) | (bytes[1] & 0x3F);
|
||||
case 3: return ((bytes[0] & 0xF0) != 0xE0) ? UTF8::invalid : ((bytes[0] & 0x0F) << 12) | ((bytes[1] & 0x3F) << 6) | (bytes[2] & 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 0xFFFF;
|
||||
return UTF8::invalid;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
constexpr bool from_codepoints(const T* codepoints, size_t count, char* out)
|
||||
{
|
||||
uint8_t* ptr = (uint8_t*)out;
|
||||
|
||||
for (size_t i = 0; i < count; i++)
|
||||
{
|
||||
if (codepoints[i] < 0x80)
|
||||
{
|
||||
*ptr++ = codepoints[i];
|
||||
}
|
||||
else if (codepoints[i] < 0x800)
|
||||
{
|
||||
*ptr++ = 0xC0 | ((codepoints[i] >> 6) & 0x1F);
|
||||
*ptr++ = 0x80 | ((codepoints[i] >> 0) & 0x3F);
|
||||
}
|
||||
else if (codepoints[i] < 0x10000)
|
||||
{
|
||||
*ptr++ = 0xE0 | ((codepoints[i] >> 12) & 0x0F);
|
||||
*ptr++ = 0x80 | ((codepoints[i] >> 6) & 0x3F);
|
||||
*ptr++ = 0x80 | ((codepoints[i] >> 0) & 0x3F);
|
||||
}
|
||||
else if (codepoints[i] < 0x110000)
|
||||
{
|
||||
*ptr++ = 0xF0 | ((codepoints[i] >> 18) & 0x07);
|
||||
*ptr++ = 0x80 | ((codepoints[i] >> 12) & 0x3F);
|
||||
*ptr++ = 0x80 | ((codepoints[i] >> 6) & 0x3F);
|
||||
*ptr++ = 0x80 | ((codepoints[i] >> 0) & 0x3F);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
98
BAN/include/BAN/UniqPtr.h
Normal file
98
BAN/include/BAN/UniqPtr.h
Normal file
@@ -0,0 +1,98 @@
|
||||
#pragma once
|
||||
|
||||
#include <BAN/Errors.h>
|
||||
#include <BAN/NoCopyMove.h>
|
||||
|
||||
namespace BAN
|
||||
{
|
||||
|
||||
template<typename T>
|
||||
class UniqPtr
|
||||
{
|
||||
BAN_NON_COPYABLE(UniqPtr);
|
||||
|
||||
public:
|
||||
UniqPtr() = default;
|
||||
|
||||
template<typename U>
|
||||
UniqPtr(UniqPtr<U>&& other)
|
||||
{
|
||||
m_pointer = other.m_pointer;
|
||||
other.m_pointer = nullptr;
|
||||
}
|
||||
|
||||
~UniqPtr()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
static UniqPtr adopt(T* pointer)
|
||||
{
|
||||
UniqPtr uniq;
|
||||
uniq.m_pointer = pointer;
|
||||
return uniq;
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
static BAN::ErrorOr<UniqPtr> create(Args&&... args)
|
||||
{
|
||||
UniqPtr uniq;
|
||||
uniq.m_pointer = new T(BAN::forward<Args>(args)...);
|
||||
if (uniq.m_pointer == nullptr)
|
||||
return BAN::Error::from_errno(ENOMEM);
|
||||
return uniq;
|
||||
}
|
||||
|
||||
template<typename U>
|
||||
UniqPtr& operator=(UniqPtr<U>&& other)
|
||||
{
|
||||
clear();
|
||||
m_pointer = other.m_pointer;
|
||||
other.m_pointer = nullptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
T& operator*()
|
||||
{
|
||||
ASSERT(m_pointer);
|
||||
return *m_pointer;
|
||||
}
|
||||
|
||||
const T& operator*() const
|
||||
{
|
||||
ASSERT(m_pointer);
|
||||
return *m_pointer;
|
||||
}
|
||||
|
||||
T* operator->()
|
||||
{
|
||||
ASSERT(m_pointer);
|
||||
return m_pointer;
|
||||
}
|
||||
|
||||
const T* operator->() const
|
||||
{
|
||||
ASSERT(m_pointer);
|
||||
return m_pointer;
|
||||
}
|
||||
|
||||
T* ptr() { return m_pointer; }
|
||||
const T* ptr() const { return m_pointer; }
|
||||
|
||||
void clear()
|
||||
{
|
||||
if (m_pointer)
|
||||
delete m_pointer;
|
||||
m_pointer = nullptr;
|
||||
}
|
||||
|
||||
operator bool() const { return m_pointer != nullptr; }
|
||||
|
||||
private:
|
||||
T* m_pointer = nullptr;
|
||||
|
||||
template<typename U>
|
||||
friend class UniqPtr;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -4,144 +4,290 @@
|
||||
#include <BAN/Math.h>
|
||||
#include <BAN/Move.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
namespace BAN
|
||||
{
|
||||
|
||||
template<typename T1, typename T2>
|
||||
namespace detail
|
||||
{
|
||||
|
||||
template<typename T>
|
||||
constexpr size_t size_ref_as_ptr() { return is_lvalue_reference_v<T> ? sizeof(remove_reference_t<T>*) : sizeof(T); }
|
||||
template<typename T>
|
||||
constexpr size_t align_ref_as_ptr() { return is_lvalue_reference_v<T> ? alignof(remove_reference_t<T>*) : alignof(T); }
|
||||
|
||||
template<typename T>
|
||||
constexpr size_t max_size_ref_as_ptr() { return size_ref_as_ptr<T>(); }
|
||||
template<typename T0, typename T1, typename... Ts>
|
||||
constexpr size_t max_size_ref_as_ptr() { return size_ref_as_ptr<T0>() > size_ref_as_ptr<T1>() ? max_size_ref_as_ptr<T0, Ts...>() : max_size_ref_as_ptr<T1, Ts...>(); }
|
||||
|
||||
template<typename T>
|
||||
constexpr size_t max_align_ref_as_ptr() { return align_ref_as_ptr<T>(); }
|
||||
template<typename T0, typename T1, typename... Ts>
|
||||
constexpr size_t max_align_ref_as_ptr() { return align_ref_as_ptr<T0>() > align_ref_as_ptr<T1>() ? max_align_ref_as_ptr<T0, Ts...>() : max_align_ref_as_ptr<T1, Ts...>(); }
|
||||
|
||||
template<typename T, typename T0, typename... Ts>
|
||||
constexpr size_t index()
|
||||
{
|
||||
if constexpr(is_same_v<T, T0>)
|
||||
return 0;
|
||||
else if constexpr(sizeof...(Ts) == 0)
|
||||
return 1;
|
||||
else
|
||||
return index<T, Ts...>() + 1;
|
||||
}
|
||||
|
||||
template<typename T, typename... Ts>
|
||||
void destruct(size_t index, uint8_t* data)
|
||||
{
|
||||
if (index == 0)
|
||||
if constexpr(!is_lvalue_reference_v<T>)
|
||||
reinterpret_cast<T*>(data)->~T();
|
||||
else;
|
||||
else if constexpr(sizeof...(Ts) > 0)
|
||||
destruct<Ts...>(index - 1, data);
|
||||
else
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
template<typename T, typename... Ts>
|
||||
void move_construct(size_t index, uint8_t* source, uint8_t* target)
|
||||
{
|
||||
if (index == 0)
|
||||
if constexpr(!is_lvalue_reference_v<T>)
|
||||
new (target) T(move(*reinterpret_cast<T*>(source)));
|
||||
else
|
||||
memcpy(target, source, sizeof(remove_reference_t<T>*));
|
||||
else if constexpr(sizeof...(Ts) > 0)
|
||||
move_construct<Ts...>(index - 1, source, target);
|
||||
else
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
template<typename T, typename... Ts>
|
||||
void copy_construct(size_t index, const uint8_t* source, uint8_t* target)
|
||||
{
|
||||
if (index == 0)
|
||||
if constexpr(!is_lvalue_reference_v<T>)
|
||||
new (target) T(*reinterpret_cast<const T*>(source));
|
||||
else
|
||||
memcpy(target, source, sizeof(remove_reference_t<T>*));
|
||||
else if constexpr(sizeof...(Ts) > 0)
|
||||
copy_construct<Ts...>(index - 1, source, target);
|
||||
else
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
template<typename T, typename... Ts>
|
||||
void move_assign(size_t index, uint8_t* source, uint8_t* target)
|
||||
{
|
||||
if (index == 0)
|
||||
if constexpr(!is_lvalue_reference_v<T>)
|
||||
*reinterpret_cast<T*>(target) = move(*reinterpret_cast<T*>(source));
|
||||
else
|
||||
memcpy(target, source, sizeof(remove_reference_t<T>*));
|
||||
else if constexpr(sizeof...(Ts) > 0)
|
||||
move_assign<Ts...>(index - 1, source, target);
|
||||
else
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
template<typename T, typename... Ts>
|
||||
void copy_assign(size_t index, const uint8_t* source, uint8_t* target)
|
||||
{
|
||||
if (index == 0)
|
||||
if constexpr(!is_lvalue_reference_v<T>)
|
||||
*reinterpret_cast<T*>(target) = *reinterpret_cast<const T*>(source);
|
||||
else
|
||||
memcpy(target, source, sizeof(remove_reference_t<T>*));
|
||||
else if constexpr(sizeof...(Ts) > 0)
|
||||
copy_assign<Ts...>(index - 1, source, target);
|
||||
else
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
template<typename... Ts>
|
||||
requires (!is_const_v<Ts> && ...)
|
||||
class Variant
|
||||
{
|
||||
public:
|
||||
static_assert(!is_same_v<T1, T2>);
|
||||
private:
|
||||
template<typename T>
|
||||
static constexpr bool can_have() { return detail::index<T, Ts...>() != invalid_index(); }
|
||||
static constexpr size_t invalid_index() { return sizeof...(Ts); }
|
||||
|
||||
public:
|
||||
Variant() = default;
|
||||
|
||||
Variant(const T1& value) { set(value); }
|
||||
Variant(T1&& value) { set(move(value)); }
|
||||
Variant(const T2& value) { set(value); }
|
||||
Variant(T2&& value) { set(move(value)); }
|
||||
Variant(Variant&& other)
|
||||
: m_index(other.m_index)
|
||||
{
|
||||
detail::move_construct<Ts...>(other.m_index, other.m_storage, m_storage);
|
||||
other.clear();
|
||||
}
|
||||
|
||||
Variant(const Variant<T1, T2>& other) { *this = other; }
|
||||
Variant(Variant<T1, T2>&& other) { *this = move(other); }
|
||||
Variant(const Variant& other)
|
||||
: m_index(other.m_index)
|
||||
{
|
||||
detail::copy_construct<Ts...>(other.m_index, other.m_storage, m_storage);
|
||||
}
|
||||
|
||||
~Variant() { clear(); }
|
||||
template<typename T>
|
||||
Variant(T&& value) requires (can_have<T>() && !is_lvalue_reference_v<T>)
|
||||
: m_index(detail::index<T, Ts...>())
|
||||
{
|
||||
new (m_storage) T(move(value));
|
||||
}
|
||||
|
||||
Variant<T1, T2>& operator=(const Variant<T1, T2>& other);
|
||||
Variant<T1, T2>& operator=(Variant<T1, T2>&& other);
|
||||
template<typename T>
|
||||
Variant(const T& value) requires (can_have<T>() && !is_lvalue_reference_v<T>)
|
||||
: m_index(detail::index<T, Ts...>())
|
||||
{
|
||||
new (m_storage) T(value);
|
||||
}
|
||||
|
||||
template<typename U>
|
||||
bool is() const;
|
||||
~Variant()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
template<typename U>
|
||||
void set(U&&);
|
||||
template<typename U>
|
||||
void set(const U& value) { set(move(U(value))); }
|
||||
Variant& operator=(Variant&& other)
|
||||
{
|
||||
if (m_index == other.m_index)
|
||||
detail::move_assign<Ts...>(m_index, other.m_storage, m_storage);
|
||||
else
|
||||
{
|
||||
clear();
|
||||
detail::move_construct<Ts...>(other.m_index, other.m_storage, m_storage);
|
||||
m_index = other.m_index;
|
||||
}
|
||||
other.clear();
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename U>
|
||||
const U& get() const;
|
||||
template<typename U>
|
||||
U& get();
|
||||
Variant& operator=(const Variant& other)
|
||||
{
|
||||
if (m_index == other.m_index)
|
||||
detail::copy_assign<Ts...>(m_index, other.m_storage, m_storage);
|
||||
else
|
||||
{
|
||||
clear();
|
||||
detail::copy_construct<Ts...>(other.m_index, other.m_storage, m_storage);
|
||||
m_index = other.m_index;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
void clear();
|
||||
template<typename T>
|
||||
Variant& operator=(T&& value) requires (can_have<T>() && !is_lvalue_reference_v<T>)
|
||||
{
|
||||
if (size_t index = detail::index<T, Ts...>(); index == m_index)
|
||||
get<T>() = move(value);
|
||||
else
|
||||
{
|
||||
clear();
|
||||
new (m_storage) T(move(value));
|
||||
m_index = index;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Variant& operator=(const T& value) requires (can_have<T>() && !is_lvalue_reference_v<T>)
|
||||
{
|
||||
if (size_t index = detail::index<T, Ts...>(); index == m_index)
|
||||
get<T>() = value;
|
||||
else
|
||||
{
|
||||
clear();
|
||||
new (m_storage) T(value);
|
||||
m_index = index;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool has() const requires (can_have<T>())
|
||||
{
|
||||
return m_index == detail::index<T, Ts...>();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void set(T&& value) requires (can_have<T>() && !is_lvalue_reference_v<T>)
|
||||
{
|
||||
if (has<T>())
|
||||
get<T>() = move(value);
|
||||
else
|
||||
{
|
||||
clear();
|
||||
m_index = detail::index<T, Ts...>();
|
||||
new (m_storage) T(move(value));
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void set(const T& value) requires (can_have<T>() && !is_lvalue_reference_v<T>)
|
||||
{
|
||||
if (has<T>())
|
||||
get<T>() = value;
|
||||
else
|
||||
{
|
||||
clear();
|
||||
m_index = detail::index<T, Ts...>();
|
||||
new (m_storage) T(value);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void set(T value) requires (can_have<T>() && is_lvalue_reference_v<T>)
|
||||
{
|
||||
clear();
|
||||
m_index = detail::index<T, Ts...>();
|
||||
*reinterpret_cast<remove_reference_t<T>**>(m_storage) = &value;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T& get() requires (can_have<T>() && !is_lvalue_reference_v<T>)
|
||||
{
|
||||
ASSERT(has<T>());
|
||||
return *reinterpret_cast<T*>(m_storage);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
const T& get() const requires (can_have<T>() && !is_lvalue_reference_v<T>)
|
||||
{
|
||||
ASSERT(has<T>());
|
||||
return *reinterpret_cast<const T*>(m_storage);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T get() requires (can_have<T>() && is_lvalue_reference_v<T>)
|
||||
{
|
||||
ASSERT(has<T>());
|
||||
return **reinterpret_cast<remove_reference_t<T>**>(m_storage);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
const T get() const requires (can_have<T>() && is_lvalue_reference_v<T>)
|
||||
{
|
||||
ASSERT(has<T>());
|
||||
return **reinterpret_cast<const remove_reference_t<T>**>(m_storage);
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
if (m_index != invalid_index())
|
||||
{
|
||||
detail::destruct<Ts...>(m_index, m_storage);
|
||||
m_index = invalid_index();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
static constexpr uint32_t m_size = Math::max(sizeof(T1), sizeof(T2));
|
||||
uint8_t m_storage[m_size] = {};
|
||||
uint32_t m_index = 0;
|
||||
alignas(detail::max_align_ref_as_ptr<Ts...>()) uint8_t m_storage[detail::max_size_ref_as_ptr<Ts...>()] {};
|
||||
size_t m_index { invalid_index() };
|
||||
};
|
||||
|
||||
template<typename T1, typename T2>
|
||||
Variant<T1, T2>& Variant<T1, T2>::operator=(const Variant<T1, T2>& other)
|
||||
{
|
||||
clear();
|
||||
if (other.is<T1>())
|
||||
set(other.get<T1>());
|
||||
if (other.is<T2>())
|
||||
set(other.get<T2>());
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename T1, typename T2>
|
||||
Variant<T1, T2>& Variant<T1, T2>::operator=(Variant<T1, T2>&& other)
|
||||
{
|
||||
clear();
|
||||
if (other.is<T1>())
|
||||
set(move(other.get<T1>()));
|
||||
if (other.is<T2>())
|
||||
set(move(other.get<T2>()));
|
||||
other.clear();
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename T1, typename T2>
|
||||
template<typename U>
|
||||
bool Variant<T1, T2>::is() const
|
||||
{
|
||||
if constexpr(is_same_v<T1, U>)
|
||||
return m_index == 1;
|
||||
if constexpr(is_same_v<T2, U>)
|
||||
return m_index == 2;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
template<typename T1, typename T2>
|
||||
template<typename U>
|
||||
void Variant<T1, T2>::set(U&& value)
|
||||
{
|
||||
static_assert(is_same_v<T1, U> || is_same_v<T2, U>);
|
||||
clear();
|
||||
if constexpr(is_same_v<T1, U>)
|
||||
{
|
||||
new (m_storage) T1(move(value));
|
||||
m_index = 1;
|
||||
}
|
||||
if constexpr(is_same_v<T2, U>)
|
||||
{
|
||||
new (m_storage) T2(move(value));
|
||||
m_index = 2;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T1, typename T2>
|
||||
template<typename U>
|
||||
const U& Variant<T1, T2>::get() const
|
||||
{
|
||||
static_assert(is_same_v<T1, U> || is_same_v<T2, U>);
|
||||
if constexpr(is_same_v<T1, U>)
|
||||
{
|
||||
ASSERT(m_index == 1);
|
||||
return *(T1*)m_storage;
|
||||
}
|
||||
if constexpr(is_same_v<T2, U>)
|
||||
{
|
||||
ASSERT(m_index == 2);
|
||||
return *(T2*)m_storage;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T1, typename T2>
|
||||
template<typename U>
|
||||
U& Variant<T1, T2>::get()
|
||||
{
|
||||
static_assert(is_same_v<T1, U> || is_same_v<T2, U>);
|
||||
if constexpr(is_same_v<T1, U>)
|
||||
{
|
||||
ASSERT(m_index == 1);
|
||||
return *(T1*)m_storage;
|
||||
}
|
||||
if constexpr(is_same_v<T2, U>)
|
||||
{
|
||||
ASSERT(m_index == 2);
|
||||
return *(T2*)m_storage;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T1, typename T2>
|
||||
void Variant<T1, T2>::clear()
|
||||
{
|
||||
if (is<T1>()) ((T1*)m_storage)->~T1();
|
||||
if (is<T2>()) ((T2*)m_storage)->~T2();
|
||||
m_index = 0;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,16 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include <BAN/Errors.h>
|
||||
#include <BAN/Iterators.h>
|
||||
#include <BAN/Math.h>
|
||||
#include <BAN/Memory.h>
|
||||
#include <BAN/Move.h>
|
||||
#include <BAN/New.h>
|
||||
#include <BAN/Span.h>
|
||||
|
||||
namespace BAN
|
||||
{
|
||||
|
||||
template<typename T, bool CONST>
|
||||
class VectorIterator;
|
||||
|
||||
// T must be move assignable, move constructable (and copy constructable for some functions)
|
||||
template<typename T>
|
||||
class Vector
|
||||
@@ -18,8 +17,8 @@ namespace BAN
|
||||
public:
|
||||
using size_type = size_t;
|
||||
using value_type = T;
|
||||
using iterator = VectorIterator<T, false>;
|
||||
using const_iterator = VectorIterator<T, true>;
|
||||
using iterator = IteratorSimple<T, Vector>;
|
||||
using const_iterator = ConstIteratorSimple<T, Vector>;
|
||||
|
||||
public:
|
||||
Vector() = default;
|
||||
@@ -40,10 +39,10 @@ namespace BAN
|
||||
ErrorOr<void> insert(size_type, T&&);
|
||||
ErrorOr<void> insert(size_type, const T&);
|
||||
|
||||
iterator begin() { return iterator (m_data); }
|
||||
const_iterator begin() const { return const_iterator(m_data); }
|
||||
iterator end() { return iterator (m_data + m_size); }
|
||||
const_iterator end() const { return const_iterator(m_data + m_size); }
|
||||
iterator begin() { return iterator(m_data); }
|
||||
iterator end() { return iterator(m_data + m_size); }
|
||||
const_iterator begin() const { return const_iterator(m_data); }
|
||||
const_iterator end() const { return const_iterator(m_data + m_size); }
|
||||
|
||||
void pop_back();
|
||||
void remove(size_type);
|
||||
@@ -54,6 +53,9 @@ namespace BAN
|
||||
|
||||
bool contains(const T&) const;
|
||||
|
||||
Span<T> span() { return Span(m_data, m_size); }
|
||||
const Span<T> span() const { return Span(m_data, m_size); }
|
||||
|
||||
const T& operator[](size_type) const;
|
||||
T& operator[](size_type);
|
||||
|
||||
@@ -62,7 +64,7 @@ namespace BAN
|
||||
const T& front() const;
|
||||
T& front();
|
||||
|
||||
ErrorOr<void> resize(size_type);
|
||||
ErrorOr<void> resize(size_type, const T& = T());
|
||||
ErrorOr<void> reserve(size_type);
|
||||
ErrorOr<void> shrink_to_fit();
|
||||
|
||||
@@ -76,54 +78,9 @@ namespace BAN
|
||||
private:
|
||||
T* m_data = nullptr;
|
||||
size_type m_capacity = 0;
|
||||
size_type m_size = 0;
|
||||
size_type m_size = 0;
|
||||
};
|
||||
|
||||
template<typename T, bool CONST>
|
||||
class VectorIterator
|
||||
{
|
||||
public:
|
||||
using value_type = T;
|
||||
using data_type = maybe_const_t<CONST, T>;
|
||||
|
||||
public:
|
||||
VectorIterator() = default;
|
||||
template<bool C>
|
||||
VectorIterator(const VectorIterator<T, C>& other, enable_if_t<C == CONST || !C>)
|
||||
: m_data(other.m_data)
|
||||
{
|
||||
}
|
||||
|
||||
VectorIterator<T, CONST>& operator++() { m_data++; return *this; }
|
||||
VectorIterator<T, CONST>& operator--() { m_data--; return *this; }
|
||||
VectorIterator<T, CONST> operator++(int) { auto temp = *this; ++(*this); return temp; }
|
||||
VectorIterator<T, CONST> operator--(int) { auto temp = *this; --(*this); return temp; }
|
||||
|
||||
template<bool ENABLE = !CONST>
|
||||
enable_if_t<ENABLE, T&> operator*() { ASSERT(m_data); return *m_data; }
|
||||
const T& operator*() const { ASSERT(m_data); return *m_data; }
|
||||
|
||||
template<bool ENABLE = !CONST>
|
||||
enable_if_t<ENABLE, T*> operator->() { ASSERT(m_data); return m_data; }
|
||||
const T* operator->() const { ASSERT(m_data); return m_data; }
|
||||
|
||||
bool operator==(const VectorIterator<T, CONST>& other) const { return m_data == other.m_data; }
|
||||
bool operator!=(const VectorIterator<T, CONST>& other) const { return !(*this == other); }
|
||||
|
||||
operator bool() const { return m_data; }
|
||||
|
||||
private:
|
||||
VectorIterator(data_type* data) : m_data(data) { }
|
||||
|
||||
private:
|
||||
data_type* m_data = nullptr;
|
||||
|
||||
friend class Vector<T>;
|
||||
friend class VectorIterator<T, !CONST>;
|
||||
};
|
||||
|
||||
|
||||
|
||||
template<typename T>
|
||||
Vector<T>::Vector(Vector<T>&& other)
|
||||
{
|
||||
@@ -256,7 +213,7 @@ namespace BAN
|
||||
template<typename T>
|
||||
ErrorOr<void> Vector<T>::insert(size_type index, const T& value)
|
||||
{
|
||||
return insert(move(T(value)), index);
|
||||
return insert(index, move(T(value)));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
@@ -296,7 +253,7 @@ namespace BAN
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
template<typename T>
|
||||
const T& Vector<T>::operator[](size_type index) const
|
||||
{
|
||||
@@ -340,7 +297,7 @@ namespace BAN
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
ErrorOr<void> Vector<T>::resize(size_type size)
|
||||
ErrorOr<void> Vector<T>::resize(size_type size, const T& value)
|
||||
{
|
||||
TRY(ensure_capacity(size));
|
||||
if (size < m_size)
|
||||
@@ -348,7 +305,7 @@ namespace BAN
|
||||
m_data[i].~T();
|
||||
if (size > m_size)
|
||||
for (size_type i = m_size; i < size; i++)
|
||||
new (m_data + i) T();
|
||||
new (m_data + i) T(value);
|
||||
m_size = size;
|
||||
return {};
|
||||
}
|
||||
|
||||
107
BAN/include/BAN/WeakPtr.h
Normal file
107
BAN/include/BAN/WeakPtr.h
Normal file
@@ -0,0 +1,107 @@
|
||||
#pragma once
|
||||
|
||||
#include <BAN/RefPtr.h>
|
||||
|
||||
namespace BAN
|
||||
{
|
||||
|
||||
template<typename T>
|
||||
class Weakable;
|
||||
|
||||
template<typename T>
|
||||
class WeakPtr;
|
||||
|
||||
template<typename T>
|
||||
class WeakLink : public RefCounted<WeakLink<T>>
|
||||
{
|
||||
public:
|
||||
RefPtr<T> lock() { ASSERT(m_ptr); return raw_ptr(); }
|
||||
T* raw_ptr() { return m_ptr; }
|
||||
|
||||
bool valid() const { return m_ptr; }
|
||||
void invalidate() { m_ptr = nullptr; }
|
||||
|
||||
private:
|
||||
WeakLink(T* ptr) : m_ptr(ptr) {}
|
||||
|
||||
private:
|
||||
T* m_ptr;
|
||||
|
||||
friend class RefPtr<WeakLink<T>>;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class Weakable
|
||||
{
|
||||
public:
|
||||
~Weakable()
|
||||
{
|
||||
if (m_link)
|
||||
m_link->invalidate();
|
||||
}
|
||||
|
||||
ErrorOr<WeakPtr<T>> get_weak_ptr() const
|
||||
{
|
||||
if (!m_link)
|
||||
m_link = TRY(RefPtr<WeakLink<T>>::create((T*)this));
|
||||
return WeakPtr<T>(m_link);
|
||||
}
|
||||
|
||||
private:
|
||||
mutable RefPtr<WeakLink<T>> m_link;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class WeakPtr
|
||||
{
|
||||
public:
|
||||
WeakPtr() = default;
|
||||
WeakPtr(WeakPtr&& other) { *this = move(other); }
|
||||
WeakPtr(const WeakPtr& other) { *this = other; }
|
||||
WeakPtr(const RefPtr<T>& other) { *this = other; }
|
||||
|
||||
WeakPtr& operator=(WeakPtr&& other)
|
||||
{
|
||||
clear();
|
||||
m_link = move(other.m_link);
|
||||
return *this;
|
||||
}
|
||||
WeakPtr& operator=(const WeakPtr& other)
|
||||
{
|
||||
clear();
|
||||
m_link = other.m_link;
|
||||
return *this;
|
||||
}
|
||||
WeakPtr& operator=(const RefPtr<T>& other)
|
||||
{
|
||||
clear();
|
||||
if (other)
|
||||
m_link = MUST(other->get_weak_ptr()).move_link();
|
||||
return *this;
|
||||
}
|
||||
|
||||
RefPtr<T> lock()
|
||||
{
|
||||
if (m_link->valid())
|
||||
return m_link->lock();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void clear() { m_link.clear(); }
|
||||
|
||||
bool valid() const { return m_link && m_link->valid(); }
|
||||
|
||||
private:
|
||||
WeakPtr(const RefPtr<WeakLink<T>>& link)
|
||||
: m_link(link)
|
||||
{ }
|
||||
|
||||
RefPtr<WeakLink<T>>&& move_link() { return move(m_link); }
|
||||
|
||||
private:
|
||||
RefPtr<WeakLink<T>> m_link;
|
||||
|
||||
friend class Weakable<T>;
|
||||
};
|
||||
|
||||
}
|
||||
43
CMakeLists.txt
Normal file
43
CMakeLists.txt
Normal file
@@ -0,0 +1,43 @@
|
||||
cmake_minimum_required(VERSION 3.26)
|
||||
|
||||
if (NOT ${CMAKE_SYSTEM_NAME} STREQUAL "banan-os")
|
||||
message(FATAL_ERROR "CMAKE_SYSTEM_NAME is not banan-os")
|
||||
endif ()
|
||||
|
||||
add_compile_options(-mno-sse -mno-sse2)
|
||||
add_compile_definitions(__enable_sse=0)
|
||||
|
||||
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_LIB ${BANAN_SYSROOT}/usr/lib)
|
||||
set(BANAN_BIN ${BANAN_SYSROOT}/usr/bin)
|
||||
set(BANAN_BOOT ${BANAN_SYSROOT}/boot)
|
||||
|
||||
add_subdirectory(kernel)
|
||||
add_subdirectory(BAN)
|
||||
add_subdirectory(libc)
|
||||
add_subdirectory(LibELF)
|
||||
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
|
||||
)
|
||||
24
LICENCE
Normal file
24
LICENCE
Normal file
@@ -0,0 +1,24 @@
|
||||
BSD 2-Clause License
|
||||
|
||||
Copyright (c) 2023, Oskari Alaranta
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
12
LibELF/CMakeLists.txt
Normal file
12
LibELF/CMakeLists.txt
Normal file
@@ -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
|
||||
)
|
||||
406
LibELF/LibELF/ELF.cpp
Normal file
406
LibELF/LibELF/ELF.cpp
Normal file
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
331
LibELF/LibELF/LoadableELF.cpp
Normal file
331
LibELF/LibELF/LoadableELF.cpp
Normal file
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
89
LibELF/include/LibELF/ELF.h
Normal file
89
LibELF/include/LibELF/ELF.h
Normal file
@@ -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
|
||||
};
|
||||
|
||||
}
|
||||
54
LibELF/include/LibELF/LoadableELF.h
Normal file
54
LibELF/include/LibELF/LoadableELF.h
Normal file
@@ -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 };
|
||||
};
|
||||
|
||||
}
|
||||
189
LibELF/include/LibELF/Types.h
Normal file
189
LibELF/include/LibELF/Types.h
Normal file
@@ -0,0 +1,189 @@
|
||||
#pragma once
|
||||
|
||||
#include <kernel/Arch.h>
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace LibELF
|
||||
{
|
||||
|
||||
using Elf32Addr = uint32_t;
|
||||
using Elf32Off = uint32_t;
|
||||
using Elf32Half = uint16_t;
|
||||
using Elf32Word = uint32_t;
|
||||
using Elf32Sword = int32_t;
|
||||
|
||||
struct Elf32FileHeader
|
||||
{
|
||||
unsigned char e_ident[16];
|
||||
Elf32Half e_type;
|
||||
Elf32Half e_machine;
|
||||
Elf32Word e_version;
|
||||
Elf32Addr e_entry;
|
||||
Elf32Off e_phoff;
|
||||
Elf32Off e_shoff;
|
||||
Elf32Word e_flags;
|
||||
Elf32Half e_ehsize;
|
||||
Elf32Half e_phentsize;
|
||||
Elf32Half e_phnum;
|
||||
Elf32Half e_shentsize;
|
||||
Elf32Half e_shnum;
|
||||
Elf32Half e_shstrndx;
|
||||
};
|
||||
|
||||
struct Elf32SectionHeader
|
||||
{
|
||||
Elf32Word sh_name;
|
||||
Elf32Word sh_type;
|
||||
Elf32Word sh_flags;
|
||||
Elf32Addr sh_addr;
|
||||
Elf32Off sh_offset;
|
||||
Elf32Word sh_size;
|
||||
Elf32Word sh_link;
|
||||
Elf32Word sh_info;
|
||||
Elf32Word sh_addralign;
|
||||
Elf32Word sh_entsize;
|
||||
};
|
||||
|
||||
struct Elf32Symbol
|
||||
{
|
||||
Elf32Word st_name;
|
||||
Elf32Addr st_value;
|
||||
Elf32Word st_size;
|
||||
unsigned char st_info;
|
||||
unsigned char st_other;
|
||||
Elf32Half st_shndx;
|
||||
};
|
||||
|
||||
struct Elf32Relocation
|
||||
{
|
||||
Elf32Addr r_offset;
|
||||
Elf32Word r_info;
|
||||
};
|
||||
|
||||
struct Elf32RelocationA
|
||||
{
|
||||
Elf32Addr r_offset;
|
||||
Elf32Word r_info;
|
||||
Elf32Sword r_addend;
|
||||
};
|
||||
|
||||
struct Elf32ProgramHeader
|
||||
{
|
||||
Elf32Word p_type;
|
||||
Elf32Off p_offset;
|
||||
Elf32Addr p_vaddr;
|
||||
Elf32Addr p_paddr;
|
||||
Elf32Word p_filesz;
|
||||
Elf32Word p_memsz;
|
||||
Elf32Word p_flags;
|
||||
Elf32Word p_align;
|
||||
};
|
||||
|
||||
using Elf64Addr = uint64_t;
|
||||
using Elf64Off = uint64_t;
|
||||
using Elf64Half = uint16_t;
|
||||
using Elf64Word = uint32_t;
|
||||
using Elf64Sword = int32_t;
|
||||
using Elf64Xword = uint64_t;
|
||||
using Elf64Sxword = int64_t;
|
||||
|
||||
struct Elf64FileHeader
|
||||
{
|
||||
unsigned char e_ident[16];
|
||||
Elf64Half e_type;
|
||||
Elf64Half e_machine;
|
||||
Elf64Word e_version;
|
||||
Elf64Addr e_entry;
|
||||
Elf64Off e_phoff;
|
||||
Elf64Off e_shoff;
|
||||
Elf64Word e_flags;
|
||||
Elf64Half e_ehsize;
|
||||
Elf64Half e_phentsize;
|
||||
Elf64Half e_phnum;
|
||||
Elf64Half e_shentsize;
|
||||
Elf64Half e_shnum;
|
||||
Elf64Half e_shstrndx;
|
||||
};
|
||||
|
||||
struct Elf64SectionHeader
|
||||
{
|
||||
Elf64Word sh_name;
|
||||
Elf64Word sh_type;
|
||||
Elf64Xword sh_flags;
|
||||
Elf64Addr sh_addr;
|
||||
Elf64Off sh_offset;
|
||||
Elf64Xword sh_size;
|
||||
Elf64Word sh_link;
|
||||
Elf64Word sh_info;
|
||||
Elf64Xword sh_addralign;
|
||||
Elf64Xword sh_entsize;
|
||||
};
|
||||
|
||||
struct Elf64Symbol
|
||||
{
|
||||
Elf64Word st_name;
|
||||
unsigned char st_info;
|
||||
unsigned char st_other;
|
||||
Elf64Half st_shndx;
|
||||
Elf64Addr st_value;
|
||||
Elf64Xword st_size;
|
||||
};
|
||||
|
||||
struct Elf64Relocation
|
||||
{
|
||||
Elf64Addr r_offset;
|
||||
Elf64Xword r_info;
|
||||
};
|
||||
|
||||
struct Elf64RelocationA
|
||||
{
|
||||
Elf64Addr r_offset;
|
||||
Elf64Xword r_info;
|
||||
Elf64Sxword r_addend;
|
||||
};
|
||||
|
||||
struct Elf64ProgramHeader
|
||||
{
|
||||
Elf64Word p_type;
|
||||
Elf64Word p_flags;
|
||||
Elf64Off p_offset;
|
||||
Elf64Addr p_vaddr;
|
||||
Elf64Addr p_paddr;
|
||||
Elf64Xword p_filesz;
|
||||
Elf64Xword p_memsz;
|
||||
Elf64Xword p_align;
|
||||
};
|
||||
|
||||
|
||||
#if ARCH(i386)
|
||||
using ElfNativeAddr = Elf32Addr;
|
||||
using ElfNativeOff = Elf32Off;
|
||||
using ElfNativeHalf = Elf32Half;
|
||||
using ElfNativeWord = Elf32Word;
|
||||
using ElfNativeSword = Elf32Sword;
|
||||
using ElfNativeXword = Elf32Xword;
|
||||
using ElfNativeSxword = Elf32Sxword;
|
||||
using ElfNativeFileHeader = Elf32FileHeader;
|
||||
using ElfNativeSectionHeader = Elf32SectionHeader;
|
||||
using ElfNativeSymbol = Elf32Symbol;
|
||||
using ElfNativeRelocation = Elf32Relocation;
|
||||
using ElfNativeRelocationA = Elf32RelocationA;
|
||||
using ElfNativeProgramHeader = Elf32ProgramHeader;
|
||||
#elif ARCH(x86_64)
|
||||
using ElfNativeAddr = Elf64Addr;
|
||||
using ElfNativeOff = Elf64Off;
|
||||
using ElfNativeHalf = Elf64Half;
|
||||
using ElfNativeWord = Elf64Word;
|
||||
using ElfNativeSword = Elf64Sword;
|
||||
using ElfNativeXword = Elf64Xword;
|
||||
using ElfNativeSxword = Elf64Sxword;
|
||||
using ElfNativeFileHeader = Elf64FileHeader;
|
||||
using ElfNativeSectionHeader = Elf64SectionHeader;
|
||||
using ElfNativeSymbol = Elf64Symbol;
|
||||
using ElfNativeRelocation = Elf64Relocation;
|
||||
using ElfNativeRelocationA = Elf64RelocationA;
|
||||
using ElfNativeProgramHeader = Elf64ProgramHeader;
|
||||
#endif
|
||||
|
||||
}
|
||||
140
LibELF/include/LibELF/Values.h
Normal file
140
LibELF/include/LibELF/Values.h
Normal file
@@ -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,
|
||||
};
|
||||
|
||||
}
|
||||
48
README.md
Normal file
48
README.md
Normal file
@@ -0,0 +1,48 @@
|
||||

|
||||
|
||||
# banan-os
|
||||
|
||||
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.
|
||||
|
||||

|
||||
|
||||
## Code structure
|
||||
|
||||
Each major component and library has its own subdirectory (kernel, userspace, libc, ...). Each directory contains directory *include*, which has **all** of the header files of the component. Every header is included by its absolute path.
|
||||
|
||||
## Building
|
||||
|
||||
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.
|
||||
|
||||
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.
|
||||
```sh
|
||||
./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.
|
||||
```sh
|
||||
./script/build.sh qemu
|
||||
./script/build.sh qemu-nographic
|
||||
./script/build.sh qemu-debug
|
||||
./script/build.sh bochs
|
||||
```
|
||||
|
||||
You can also build the kernel or disk image without running it:
|
||||
```sh
|
||||
./script/build.sh kernel
|
||||
./script/build.sh image
|
||||
```
|
||||
|
||||
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
|
||||
./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_.
|
||||
|
||||
### Contributing
|
||||
|
||||
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.
|
||||
BIN
assets/banan-os.png
Normal file
BIN
assets/banan-os.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 11 KiB |
BIN
base-sysroot.tar.gz
Normal file
BIN
base-sysroot.tar.gz
Normal file
Binary file not shown.
7
build.sh
7
build.sh
@@ -1,7 +0,0 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
. ./headers.sh
|
||||
|
||||
for PROJECT in $PROJECTS; do
|
||||
(cd $PROJECT && DESTDIR="$SYSROOT" $MAKE install)
|
||||
done
|
||||
11
clean.sh
11
clean.sh
@@ -1,11 +0,0 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
. ./config.sh
|
||||
|
||||
for PROJECT in $PROJECTS; do
|
||||
(cd $PROJECT && $MAKE clean)
|
||||
done
|
||||
|
||||
rm -rf sysroot
|
||||
rm -rf isodir
|
||||
rm -rf banan-os.img
|
||||
33
config.sh
33
config.sh
@@ -1,33 +0,0 @@
|
||||
SYSTEM_HEADER_PROJECTS="libc BAN kernel"
|
||||
PROJECTS="libc BAN kernel"
|
||||
|
||||
export MAKE=${MAKE:-make}
|
||||
export HOST=${HOST:-$(./default-host.sh)}
|
||||
|
||||
export AR=${HOST}-ar
|
||||
export AS=${HOST}-as
|
||||
export CC=${HOST}-gcc
|
||||
export CXX=${HOST}-g++
|
||||
|
||||
export PREFIX=/usr
|
||||
export EXEC_PREFIX=$PREFIX
|
||||
export BOOTDIR=/boot
|
||||
export LIBDIR=$EXEC_PREFIX/lib
|
||||
export INCLUDEDIR=$PREFIX/include
|
||||
|
||||
export CFLAGS='-O2 -g'
|
||||
export CPPFLAGS='--std=c++20 -Wno-literal-suffix'
|
||||
|
||||
export UBSAN=0
|
||||
|
||||
# Configure the cross-compiler to use the desired system root.
|
||||
export SYSROOT="$(pwd)/sysroot"
|
||||
export CC="$CC --sysroot=$SYSROOT"
|
||||
export CXX="$CXX --sysroot=$SYSROOT"
|
||||
|
||||
# Work around that the -elf gcc targets doesn't have a system include directory
|
||||
# because it was configured with --without-headers rather than --with-sysroot.
|
||||
if echo "$HOST" | grep -Eq -- '-elf($|-)'; then
|
||||
export CC="$CC -isystem=$INCLUDEDIR"
|
||||
export CXX="$CXX -isystem=$INCLUDEDIR"
|
||||
fi
|
||||
@@ -1,2 +0,0 @@
|
||||
#!/bin/sh
|
||||
echo x86_64-elf
|
||||
67
disk.sh
67
disk.sh
@@ -1,67 +0,0 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
. ./build.sh
|
||||
|
||||
DISK_NAME=banan-os.img
|
||||
DISK_SIZE=$[50 * 1024 * 1024]
|
||||
MOUNT_DIR=/mnt
|
||||
|
||||
dd if=/dev/zero of=$DISK_NAME bs=512 count=$[$DISK_SIZE / 512]
|
||||
|
||||
sed -e 's/\s*\([-\+[:alnum:]]*\).*/\1/' << EOF | fdisk $DISK_NAME
|
||||
g # gpt
|
||||
n # new partition
|
||||
1 # partition number 1
|
||||
# default (from the beginning of the disk)
|
||||
+1MiB # bios boot partiton size
|
||||
n # new partition
|
||||
2 # partition number 2
|
||||
# default (right after bios boot partition)
|
||||
# default (to the end of disk)
|
||||
t # set type
|
||||
1 # ... of partition 1
|
||||
4 # bios boot partition
|
||||
t # set type
|
||||
2 # ... of partition 2
|
||||
20 # Linux filesystem
|
||||
x # expert menu
|
||||
n # partition name
|
||||
2 # ... of partition 2
|
||||
banan-root
|
||||
r # back to main menu
|
||||
w # write changes
|
||||
EOF
|
||||
|
||||
LOOP_DEV=$(sudo losetup -f --show $DISK_NAME)
|
||||
sudo partprobe $LOOP_DEV
|
||||
|
||||
PARTITION1=${LOOP_DEV}p1
|
||||
PARTITION2=${LOOP_DEV}p2
|
||||
|
||||
sudo mkfs.ext2 $PARTITION2
|
||||
|
||||
sudo mount $PARTITION2 $MOUNT_DIR
|
||||
|
||||
sudo cp -r ${SYSROOT}/* ${MOUNT_DIR}/
|
||||
sudo mkdir -p ${MOUNT_DIR}/usr/share/
|
||||
sudo cp -r fonts ${MOUNT_DIR}/usr/share/
|
||||
|
||||
sudo grub-install --no-floppy --target=i386-pc --modules="normal ext2 multiboot" --boot-directory=${MOUNT_DIR}/boot $LOOP_DEV
|
||||
|
||||
echo -e '
|
||||
menuentry "banan-os" {
|
||||
multiboot /boot/banan-os.kernel
|
||||
}
|
||||
menuentry "banan-os (no serial)" {
|
||||
multiboot /boot/banan-os.kernel noserial
|
||||
}
|
||||
menuentry "banan-os (no apic)" {
|
||||
multiboot /boot/banan-os.kernel noapic
|
||||
}
|
||||
menuentry "banan-os (no apic, no serial)" {
|
||||
multiboot /boot/banan-os.kernel noapic noserial
|
||||
}
|
||||
' | sudo tee ${MOUNT_DIR}/boot/grub/grub.cfg
|
||||
|
||||
sudo umount $MOUNT_DIR
|
||||
sudo losetup -d $LOOP_DEV
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,9 +0,0 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
. ./config.sh
|
||||
|
||||
mkdir -p "$SYSROOT"
|
||||
|
||||
for PROJECT in $SYSTEM_HEADER_PROJECTS; do
|
||||
(cd $PROJECT && DESTDIR="$SYSROOT" $MAKE install-headers)
|
||||
done
|
||||
@@ -1,8 +0,0 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
. ./disk.sh
|
||||
|
||||
SIZE=$(stat -c '%s' banan-os.img | numfmt --to=iec)
|
||||
|
||||
echo Writing ${SIZE}iB
|
||||
sudo dd if=banan-os.img of=/dev/sda status=progress
|
||||
3
kernel/.gitignore
vendored
3
kernel/.gitignore
vendored
@@ -1,3 +0,0 @@
|
||||
*.d
|
||||
*.kernel
|
||||
*.o
|
||||
199
kernel/CMakeLists.txt
Normal file
199
kernel/CMakeLists.txt
Normal file
@@ -0,0 +1,199 @@
|
||||
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
|
||||
font/prefs.psf.o
|
||||
kernel/ACPI.cpp
|
||||
kernel/APIC.cpp
|
||||
kernel/CPUID.cpp
|
||||
kernel/Debug.cpp
|
||||
kernel/Device/Device.cpp
|
||||
kernel/Device/NullDevice.cpp
|
||||
kernel/Device/ZeroDevice.cpp
|
||||
kernel/Errors.cpp
|
||||
kernel/Font.cpp
|
||||
kernel/FS/DevFS/FileSystem.cpp
|
||||
kernel/FS/Ext2/FileSystem.cpp
|
||||
kernel/FS/Ext2/Inode.cpp
|
||||
kernel/FS/Inode.cpp
|
||||
kernel/FS/Pipe.cpp
|
||||
kernel/FS/ProcFS/FileSystem.cpp
|
||||
kernel/FS/ProcFS/Inode.cpp
|
||||
kernel/FS/RamFS/FileSystem.cpp
|
||||
kernel/FS/RamFS/Inode.cpp
|
||||
kernel/FS/VirtualFileSystem.cpp
|
||||
kernel/Input/PS2Controller.cpp
|
||||
kernel/Input/PS2Keyboard.cpp
|
||||
kernel/Input/PS2Keymap.cpp
|
||||
kernel/InterruptController.cpp
|
||||
kernel/kernel.cpp
|
||||
kernel/Memory/DMARegion.cpp
|
||||
kernel/Memory/FileBackedRegion.cpp
|
||||
kernel/Memory/Heap.cpp
|
||||
kernel/Memory/kmalloc.cpp
|
||||
kernel/Memory/MemoryBackedRegion.cpp
|
||||
kernel/Memory/MemoryRegion.cpp
|
||||
kernel/Memory/PhysicalRange.cpp
|
||||
kernel/Memory/VirtualRange.cpp
|
||||
kernel/Networking/E1000.cpp
|
||||
kernel/OpenFileDescriptorSet.cpp
|
||||
kernel/Panic.cpp
|
||||
kernel/PCI.cpp
|
||||
kernel/PIC.cpp
|
||||
kernel/Process.cpp
|
||||
kernel/Scheduler.cpp
|
||||
kernel/Semaphore.cpp
|
||||
kernel/SpinLock.cpp
|
||||
kernel/SSP.cpp
|
||||
kernel/Storage/ATA/AHCI/Controller.cpp
|
||||
kernel/Storage/ATA/AHCI/Device.cpp
|
||||
kernel/Storage/ATA/ATABus.cpp
|
||||
kernel/Storage/ATA/ATAController.cpp
|
||||
kernel/Storage/ATA/ATADevice.cpp
|
||||
kernel/Storage/DiskCache.cpp
|
||||
kernel/Storage/StorageDevice.cpp
|
||||
kernel/Syscall.cpp
|
||||
kernel/Syscall.S
|
||||
kernel/Terminal/Serial.cpp
|
||||
kernel/Terminal/TTY.cpp
|
||||
kernel/Terminal/VesaTerminalDriver.cpp
|
||||
kernel/Terminal/VirtualTTY.cpp
|
||||
kernel/Thread.cpp
|
||||
kernel/Timer/HPET.cpp
|
||||
kernel/Timer/PIT.cpp
|
||||
kernel/Timer/RTC.cpp
|
||||
kernel/Timer/Timer.cpp
|
||||
icxxabi.cpp
|
||||
)
|
||||
|
||||
#set(ENABLE_KERNEL_UBSAN True)
|
||||
|
||||
if(ENABLE_KERNEL_UBSAN)
|
||||
set(KERNEL_SOURCES ${KERNEL_SOURCES} ubsan.cpp)
|
||||
endif()
|
||||
|
||||
if("${BANAN_ARCH}" STREQUAL "x86_64")
|
||||
set(KERNEL_SOURCES
|
||||
${KERNEL_SOURCES}
|
||||
arch/x86_64/boot.S
|
||||
arch/x86_64/GDT.cpp
|
||||
arch/x86_64/IDT.cpp
|
||||
arch/x86_64/interrupts.S
|
||||
arch/x86_64/PageTable.cpp
|
||||
arch/x86_64/Signal.S
|
||||
arch/x86_64/Thread.S
|
||||
)
|
||||
elseif("${BANAN_ARCH}" STREQUAL "i386")
|
||||
set(KERNEL_SOURCES
|
||||
${KERNEL_SOURCES}
|
||||
arch/i386/boot.S
|
||||
arch/i386/GDT.cpp
|
||||
arch/i386/IDT.cpp
|
||||
arch/i386/MMU.cpp
|
||||
arch/i386/SpinLock.S
|
||||
arch/i386/Thread.S
|
||||
)
|
||||
else()
|
||||
message(FATAL_ERROR "unsupported architecure ${BANAN_ARCH}")
|
||||
endif()
|
||||
|
||||
file(GLOB_RECURSE LAI_SOURCES
|
||||
lai/*.c
|
||||
)
|
||||
set(LAI_SOURCES
|
||||
${LAI_SOURCES}
|
||||
kernel/lai_host.cpp
|
||||
)
|
||||
|
||||
set(BAN_SOURCES
|
||||
../BAN/BAN/New.cpp
|
||||
../BAN/BAN/String.cpp
|
||||
../BAN/BAN/StringView.cpp
|
||||
../BAN/BAN/Time.cpp
|
||||
)
|
||||
|
||||
set(LIBC_SOURCES
|
||||
../libc/ctype.cpp
|
||||
../libc/string.cpp
|
||||
)
|
||||
|
||||
set(LIBELF_SOURCES
|
||||
../LibELF/LibELF/LoadableELF.cpp
|
||||
)
|
||||
|
||||
set(KERNEL_SOURCES
|
||||
${KERNEL_SOURCES}
|
||||
${LAI_SOURCES}
|
||||
${BAN_SOURCES}
|
||||
${LIBC_SOURCES}
|
||||
${LIBELF_SOURCES}
|
||||
)
|
||||
|
||||
add_executable(kernel ${KERNEL_SOURCES})
|
||||
add_dependencies(kernel headers)
|
||||
|
||||
target_compile_definitions(kernel PUBLIC __is_kernel)
|
||||
target_compile_definitions(kernel PUBLIC __arch=${BANAN_ARCH})
|
||||
|
||||
target_compile_options(kernel PUBLIC -O2 -g)
|
||||
target_compile_options(kernel PUBLIC $<$<COMPILE_LANGUAGE:CXX>:-Wno-literal-suffix -fno-rtti -fno-exceptions>)
|
||||
target_compile_options(kernel PUBLIC -fmacro-prefix-map=${CMAKE_CURRENT_SOURCE_DIR}=.)
|
||||
target_compile_options(kernel PUBLIC -fstack-protector -ffreestanding -Wall -Werror=return-type -Wstack-usage=1024 -fno-omit-frame-pointer -mgeneral-regs-only)
|
||||
|
||||
# This might not work with other toolchains
|
||||
target_compile_options(kernel PUBLIC $<$<COMPILE_LANGUAGE:CXX>:-Wno-invalid-offsetof>)
|
||||
|
||||
if(ENABLE_KERNEL_UBSAN)
|
||||
target_compile_options(kernel PUBLIC -fsanitize=undefined)
|
||||
endif()
|
||||
|
||||
if("${BANAN_ARCH}" STREQUAL "x86_64")
|
||||
target_compile_options(kernel PUBLIC -mcmodel=kernel -mno-red-zone -mno-mmx)
|
||||
target_link_options(kernel PUBLIC LINKER:-z,max-page-size=4096)
|
||||
target_link_options(kernel PUBLIC LINKER:-T,${CMAKE_CURRENT_SOURCE_DIR}/arch/x86_64/linker.ld)
|
||||
elseif("${BANAN_ARCH}" STREQUAL "i386")
|
||||
target_link_options(kernel PUBLIC LINKER:-T,${CMAKE_CURRENT_SOURCE_DIR}/arch/i386/linker.ld)
|
||||
endif()
|
||||
|
||||
target_link_options(kernel PUBLIC -ffreestanding -nostdlib)
|
||||
|
||||
add_custom_target(kernel-headers
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_directory_if_different ${CMAKE_CURRENT_SOURCE_DIR}/include/ ${BANAN_INCLUDE}/
|
||||
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(
|
||||
TARGET kernel PRE_LINK
|
||||
COMMAND ${CMAKE_CXX_COMPILER} -MD -c ${CMAKE_CURRENT_SOURCE_DIR}/arch/${BANAN_ARCH}/crti.S ${COMPILE_OPTIONS}
|
||||
COMMAND ${CMAKE_CXX_COMPILER} -MD -c ${CMAKE_CURRENT_SOURCE_DIR}/arch/${BANAN_ARCH}/crtn.S ${COMPILE_OPTIONS}
|
||||
COMMAND ${CMAKE_COMMAND} -E copy ${CRTBEGIN} .
|
||||
COMMAND ${CMAKE_COMMAND} -E copy ${CRTEND} .
|
||||
)
|
||||
|
||||
#add_custom_command(
|
||||
# TARGET kernel POST_BUILD
|
||||
# COMMAND x86_64-banan_os-strip ${CMAKE_CURRENT_BINARY_DIR}/kernel
|
||||
#)
|
||||
|
||||
add_custom_command(
|
||||
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
|
||||
)
|
||||
|
||||
set(CMAKE_CXX_LINK_EXECUTABLE "${CMAKE_CXX_COMPILER} <CMAKE_CXX_LINK_FLAGS> <FLAGS> <LINK_FLAGS> -o <TARGET> ${CMAKE_CURRENT_BINARY_DIR}/crti.o ${CMAKE_CURRENT_BINARY_DIR}/crtbegin.o <OBJECTS> ${CMAKE_CURRENT_BINARY_DIR}/crtend.o ${CMAKE_CURRENT_BINARY_DIR}/crtn.o -lgcc ")
|
||||
131
kernel/Makefile
131
kernel/Makefile
@@ -1,131 +0,0 @@
|
||||
DEFAULT_HOST!=../default-host.sh
|
||||
HOST?=DEFAULT_HOST
|
||||
HOSTARCH!=../target-triplet-to-arch.sh $(HOST)
|
||||
|
||||
CFLAGS?=-O2 -g
|
||||
CPPFLAGS?=
|
||||
LDFLAGS?=
|
||||
LIBS?=
|
||||
|
||||
DESTDIR?=
|
||||
PREFIX?=/usr/local
|
||||
EXEC_PREFIX?=$(PREFIX)
|
||||
BOOTDIR?=$(EXEC_PREFIX)/boot
|
||||
INCLUDEDIR?=$(PREFIX)/include
|
||||
|
||||
CFLAGS:=$(CFLAGS) -D__is_kernel -D__arch=$(HOSTARCH) -Iinclude -fstack-protector -ffreestanding -Wall -Wextra -Werror=return-type -fno-omit-frame-pointer -mno-sse -mno-sse2
|
||||
CPPFLAGS:=$(CPPFLAGS) -fno-rtti -fno-exceptions
|
||||
LDFLAGS:=$(LDFLAGS)
|
||||
LIBS:=$(LIBS) -nostdlib -lk -lbank -lgcc
|
||||
|
||||
ARCHDIR=arch/$(HOSTARCH)
|
||||
|
||||
include $(ARCHDIR)/make.config
|
||||
|
||||
CFLAGS:=$(CFLAGS) $(KERNEL_ARCH_CFLAGS)
|
||||
CPPFLAGS:=$(CPPFLAGS) $(KERNEL_ARCH_CPPFLAGS)
|
||||
LDFLAGS:=$(LDFLAGS) $(KERNEL_ARCH_LDFLAGS)
|
||||
LIBS:=$(LIBS) $(KERNEL_ARCH_LIBS)
|
||||
|
||||
ifeq ($(UBSAN), 1)
|
||||
CFLAGS:=$(CFLAGS) -fsanitize=undefined
|
||||
endif
|
||||
|
||||
BUILDDIR=$(abspath build)
|
||||
|
||||
KERNEL_OBJS= \
|
||||
$(KERNEL_ARCH_OBJS) \
|
||||
font/prefs.o \
|
||||
kernel/APIC.o \
|
||||
kernel/build_libc.o \
|
||||
kernel/CPUID.o \
|
||||
kernel/Debug.o \
|
||||
kernel/Font.o \
|
||||
kernel/FS/Ext2.o \
|
||||
kernel/FS/VirtualFileSystem.o \
|
||||
kernel/Input.o \
|
||||
kernel/InterruptController.o \
|
||||
kernel/kernel.o \
|
||||
kernel/kmalloc.o \
|
||||
kernel/PCI.o \
|
||||
kernel/PIC.o \
|
||||
kernel/PIT.o \
|
||||
kernel/Process.o \
|
||||
kernel/RTC.o \
|
||||
kernel/Scheduler.o \
|
||||
kernel/Serial.o \
|
||||
kernel/Shell.o \
|
||||
kernel/SpinLock.o \
|
||||
kernel/SSP.o \
|
||||
kernel/Storage/ATAController.o \
|
||||
kernel/Storage/StorageDevice.o \
|
||||
kernel/Syscall.o \
|
||||
kernel/Thread.o \
|
||||
kernel/TTY.o \
|
||||
kernel/VesaTerminalDriver.o \
|
||||
userspace/userspace.o \
|
||||
icxxabi.o \
|
||||
ubsan.o \
|
||||
|
||||
OBJS= \
|
||||
$(ARCHDIR)/crti.o \
|
||||
$(ARCHDIR)/crtbegin.o \
|
||||
$(KERNEL_OBJS) \
|
||||
$(ARCHDIR)/crtend.o \
|
||||
$(ARCHDIR)/crtn.o \
|
||||
|
||||
LINK_LIST= \
|
||||
$(LDFLAGS) \
|
||||
$(ARCHDIR)/crti.o \
|
||||
$(ARCHDIR)/crtbegin.o \
|
||||
$(KERNEL_OBJS) \
|
||||
$(LIBS) \
|
||||
$(ARCHDIR)/crtend.o \
|
||||
$(ARCHDIR)/crtn.o \
|
||||
|
||||
.PHONY: all always clean install install-headers install-kernel
|
||||
.SUFFIXES: .o .c .cpp .S .psf
|
||||
|
||||
all: banan-os.kernel
|
||||
|
||||
banan-os.kernel: always $(OBJS) $(ARCHDIR)/linker.ld
|
||||
cd $(BUILDDIR) && $(CXX) -T ../$(ARCHDIR)/linker.ld -o banan-os.kernel $(CFLAGS) $(CPPFLAGS) $(LINK_LIST)
|
||||
cd $(BUILDDIR) && grub-file --is-x86-multiboot banan-os.kernel
|
||||
|
||||
$(ARCHDIR)/crtbegin.o $(ARCHDIR)/crtend.o:
|
||||
OBJ=`$(CC) $(CFLAGS) $(LDFLAGS) -print-file-name=$(@F)` && cp "$$OBJ" $(BUILDDIR)/$@
|
||||
|
||||
.c.o:
|
||||
$(CC) -MD -c $< -o $(BUILDDIR)/$@ $(CFLAGS)
|
||||
|
||||
.cpp.o:
|
||||
$(CXX) -MD -c $< -o $(BUILDDIR)/$@ $(CFLAGS) $(CPPFLAGS)
|
||||
|
||||
.S.o:
|
||||
$(CC) -MD -c $< -o $(BUILDDIR)/$@ $(CFLAGS)
|
||||
|
||||
.psf.o:
|
||||
objcopy -O $(ELF_FORMAT) -B i386 -I binary $< $(BUILDDIR)/$@
|
||||
|
||||
always:
|
||||
mkdir -p $(BUILDDIR)/$(ARCHDIR)
|
||||
mkdir -p $(BUILDDIR)/kernel
|
||||
mkdir -p $(BUILDDIR)/kernel/FS
|
||||
mkdir -p $(BUILDDIR)/kernel/Storage
|
||||
mkdir -p $(BUILDDIR)/userspace
|
||||
mkdir -p $(BUILDDIR)/font
|
||||
|
||||
clean:
|
||||
rm -rf $(BUILDDIR)
|
||||
|
||||
install: install-headers install-kernel
|
||||
|
||||
install-headers:
|
||||
mkdir -p $(DESTDIR)$(INCLUDEDIR)
|
||||
cp -R --preserve=timestamps include/. $(DESTDIR)$(INCLUDEDIR)/.
|
||||
|
||||
install-kernel: banan-os.kernel
|
||||
mkdir -p $(DESTDIR)$(BOOTDIR)
|
||||
cp $(BUILDDIR)/banan-os.kernel $(DESTDIR)$(BOOTDIR)
|
||||
|
||||
-include $(OBJS:.o=.d)
|
||||
@@ -109,6 +109,11 @@ namespace Kernel::GDT
|
||||
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));
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
#include <BAN/Errors.h>
|
||||
#include <kernel/IDT.h>
|
||||
#include <kernel/InterruptController.h>
|
||||
#include <kernel/kmalloc.h>
|
||||
#include <kernel/Memory/kmalloc.h>
|
||||
#include <kernel/Panic.h>
|
||||
#include <kernel/Scheduler.h>
|
||||
|
||||
#define INTERRUPT_HANDLER____(i, msg) \
|
||||
static void interrupt ## i () \
|
||||
@@ -132,6 +133,8 @@ found:
|
||||
// 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();
|
||||
@@ -151,7 +154,7 @@ found:
|
||||
"popa;"
|
||||
"iret;"
|
||||
);
|
||||
|
||||
|
||||
extern "C" void syscall_asm();
|
||||
asm(
|
||||
".global syscall_asm;"
|
||||
@@ -171,7 +174,18 @@ found:
|
||||
"addl $16, %esp;"
|
||||
"popw %es;"
|
||||
"popw %ds;"
|
||||
"popa;"
|
||||
|
||||
// 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;"
|
||||
);
|
||||
|
||||
|
||||
@@ -1,136 +1,227 @@
|
||||
#include <BAN/Errors.h>
|
||||
#include <kernel/Debug.h>
|
||||
#include <kernel/MMU.h>
|
||||
#include <kernel/kmalloc.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 PAGE_SIZE 0x00001000
|
||||
#define PAGE_MASK 0xfffff000
|
||||
#define FLAGS_MASK 0x00000fff
|
||||
|
||||
static MMU* s_instance = nullptr;
|
||||
|
||||
void MMU::intialize()
|
||||
namespace Kernel
|
||||
{
|
||||
ASSERT(s_instance == nullptr);
|
||||
s_instance = new MMU();
|
||||
}
|
||||
|
||||
MMU& MMU::get()
|
||||
{
|
||||
ASSERT(s_instance);
|
||||
return *s_instance;
|
||||
}
|
||||
static MMU* s_instance = nullptr;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
MMU::MMU()
|
||||
{
|
||||
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++)
|
||||
void MMU::initialize()
|
||||
{
|
||||
uint64_t* page_directory = allocate_page_aligned_page();
|
||||
m_highest_paging_struct[i] = (uint64_t)page_directory | Flags::Present;
|
||||
ASSERT(s_instance == nullptr);
|
||||
s_instance = new MMU();
|
||||
ASSERT(s_instance);
|
||||
s_instance->initialize_kernel();
|
||||
s_instance->load();
|
||||
}
|
||||
|
||||
// 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++)
|
||||
MMU& MMU::get()
|
||||
{
|
||||
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;
|
||||
ASSERT(s_instance);
|
||||
return *s_instance;
|
||||
}
|
||||
|
||||
// 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;
|
||||
|
||||
// reload this new pdpt
|
||||
asm volatile("movl %0, %%cr3" :: "r"(m_highest_paging_struct));
|
||||
}
|
||||
|
||||
void MMU::allocate_page(uintptr_t address, uint8_t flags)
|
||||
{
|
||||
#if MMU_DEBUG_PRINT
|
||||
dprintln("AllocatePage(0x{8H})", address);
|
||||
#endif
|
||||
ASSERT(flags & Flags::Present);
|
||||
|
||||
address &= PAGE_MASK;
|
||||
|
||||
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))
|
||||
static uint64_t* allocate_page_aligned_page()
|
||||
{
|
||||
uint64_t* page_table = allocate_page_aligned_page();
|
||||
page_directory[pde] = (uint64_t)page_table;
|
||||
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;
|
||||
}
|
||||
page_directory[pde] |= flags;
|
||||
|
||||
uint64_t* page_table = (uint64_t*)(page_directory[pde] & PAGE_MASK);
|
||||
page_table[pte] = address | flags;
|
||||
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;
|
||||
}
|
||||
|
||||
asm volatile("invlpg (%0)" :: "r"(address) : "memory");
|
||||
}
|
||||
|
||||
void MMU::allocate_range(uintptr_t address, ptrdiff_t size, uint8_t flags)
|
||||
{
|
||||
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)
|
||||
allocate_page(page, flags);
|
||||
}
|
||||
|
||||
void MMU::unallocate_page(uintptr_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
|
||||
|
||||
asm volatile("invlpg (%0)" :: "r"(address & PAGE_MASK) : "memory");
|
||||
}
|
||||
|
||||
void MMU::unallocate_range(uintptr_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)
|
||||
unallocate_page(page);
|
||||
}
|
||||
|
||||
@@ -25,4 +25,23 @@ continue_thread:
|
||||
movl 8(%esp), %ecx
|
||||
movl 4(%esp), %esp
|
||||
movl $0, %eax
|
||||
jmp *%ecx
|
||||
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
|
||||
|
||||
@@ -28,9 +28,7 @@ g_boot_stack_bottom:
|
||||
g_boot_stack_top:
|
||||
|
||||
# 0 MiB -> 1 MiB: bootloader stuff
|
||||
# 1 MiB -> 2 MiB: kernel
|
||||
# 2 MiB -> 3 MiB: kmalloc
|
||||
# 3 MiB -> 4 Mib: kmalloc_fixed
|
||||
# 1 MiB -> : kernel
|
||||
.align 32
|
||||
boot_page_directory_pointer_table:
|
||||
.skip 4 * 8
|
||||
|
||||
23
kernel/arch/i386/crt0.S
Normal file
23
kernel/arch/i386/crt0.S
Normal file
@@ -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
|
||||
@@ -4,6 +4,7 @@ SECTIONS
|
||||
{
|
||||
. = 0x00100000;
|
||||
|
||||
g_kernel_start = .;
|
||||
.text BLOCK(4K) : ALIGN(4K)
|
||||
{
|
||||
*(.multiboot)
|
||||
@@ -11,9 +12,7 @@ SECTIONS
|
||||
}
|
||||
.rodata BLOCK(4K) : ALIGN(4K)
|
||||
{
|
||||
g_rodata_start = .;
|
||||
*(.rodata.*)
|
||||
g_rodata_end = .;
|
||||
}
|
||||
.data BLOCK(4K) : ALIGN(4K)
|
||||
{
|
||||
@@ -26,13 +25,4 @@ SECTIONS
|
||||
}
|
||||
|
||||
g_kernel_end = .;
|
||||
|
||||
. = 0x00A00000;
|
||||
|
||||
g_userspace_start = .;
|
||||
.userspace BLOCK(4K) : ALIGN(4K)
|
||||
{
|
||||
*(.userspace)
|
||||
}
|
||||
g_userspace_end = .;
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
KERNEL_ARCH_CFLAGS=
|
||||
KERNEL_ARCH_CPPFLAGS=
|
||||
KERNEL_ARCH_LDFLAGS=
|
||||
KERNEL_ARCH_LIBS=
|
||||
|
||||
ELF_FORMAT=elf32-i386
|
||||
|
||||
KERNEL_ARCH_OBJS= \
|
||||
$(ARCHDIR)/boot.o \
|
||||
$(ARCHDIR)/GDT.o \
|
||||
$(ARCHDIR)/IDT.o \
|
||||
$(ARCHDIR)/MMU.o \
|
||||
$(ARCHDIR)/SpinLock.o \
|
||||
$(ARCHDIR)/Thread.o \
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include <BAN/Assert.h>
|
||||
#include <BAN/Array.h>
|
||||
#include <kernel/GDT.h>
|
||||
|
||||
#include <string.h>
|
||||
@@ -54,69 +54,72 @@ namespace Kernel::GDT
|
||||
uint64_t address;
|
||||
} __attribute__((packed));
|
||||
|
||||
static TaskStateSegment* s_tss = nullptr;
|
||||
static SegmentDescriptor* s_gdt = nullptr;
|
||||
static constexpr uint16_t s_tss_offset = 0x28;
|
||||
|
||||
static TaskStateSegment s_tss;
|
||||
static BAN::Array<SegmentDescriptor, 7> s_gdt; // null, kernel code, kernel data, user code, user data, tss low, tss high
|
||||
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;
|
||||
ASSERT(offset % sizeof(SegmentDescriptor) == 0);
|
||||
|
||||
desc.limit1 = limit;
|
||||
desc.limit2 = limit >> 16;
|
||||
SegmentDescriptor& desc = s_gdt[offset / sizeof(SegmentDescriptor)];
|
||||
desc.base1 = (base >> 0) & 0xFFFF;
|
||||
desc.base2 = (base >> 16) & 0xFF;
|
||||
desc.base3 = (base >> 24) & 0xFF;
|
||||
|
||||
desc.access = access;
|
||||
desc.limit1 = (limit >> 0) & 0xFFFF;
|
||||
desc.limit2 = (limit >> 16) & 0x0F;
|
||||
|
||||
desc.flags = flags;
|
||||
desc.access = access & 0xFF;
|
||||
|
||||
desc.flags = flags & 0x0F;
|
||||
}
|
||||
|
||||
static void write_tss(uint8_t offset)
|
||||
static void write_tss()
|
||||
{
|
||||
s_tss = new TaskStateSegment();
|
||||
ASSERT(s_tss);
|
||||
memset(&s_tss, 0x00, sizeof(TaskStateSegment));
|
||||
s_tss.iopb = sizeof(TaskStateSegment);
|
||||
|
||||
memset(s_tss, 0x00, sizeof(TaskStateSegment));
|
||||
s_tss->rsp0 = (uintptr_t)g_boot_stack_top;
|
||||
|
||||
uintptr_t base = (uintptr_t)s_tss;
|
||||
uint64_t base = (uint64_t)&s_tss;
|
||||
|
||||
write_entry(offset, (uint32_t)base, sizeof(TaskStateSegment), 0x89, 0x0);
|
||||
SegmentDescriptor& desc = *(SegmentDescriptor*)((uintptr_t)s_gdt + offset + 0x08);
|
||||
write_entry(s_tss_offset, (uint32_t)base, sizeof(TaskStateSegment), 0x89, 0x0);
|
||||
|
||||
SegmentDescriptor& desc = s_gdt[s_tss_offset / sizeof(SegmentDescriptor) + 1];
|
||||
desc.low = base >> 32;
|
||||
desc.high = 0;
|
||||
}
|
||||
|
||||
void set_tss_stack(uintptr_t rsp)
|
||||
{
|
||||
s_tss.rsp0 = rsp;
|
||||
}
|
||||
|
||||
static void flush_gdt()
|
||||
{
|
||||
asm volatile("lgdt %0" :: "m"(s_gdtr));
|
||||
}
|
||||
|
||||
extern "C" void flush_tss(uint16_t offset)
|
||||
static void flush_tss()
|
||||
{
|
||||
asm volatile("ltr %0" :: "m"(offset));
|
||||
asm volatile("ltr %0" :: "m"(s_tss_offset));
|
||||
}
|
||||
|
||||
void initialize()
|
||||
{
|
||||
constexpr uint32_t descriptor_count = 6 + 1; // tss takes 2
|
||||
s_gdt = new SegmentDescriptor[descriptor_count];
|
||||
ASSERT(s_gdt);
|
||||
|
||||
s_gdtr.address = (uint64_t)s_gdt;
|
||||
s_gdtr.size = descriptor_count * sizeof(SegmentDescriptor) - 1;
|
||||
s_gdtr.address = (uint64_t)&s_gdt;
|
||||
s_gdtr.size = s_gdt.size() * sizeof(SegmentDescriptor) - 1;
|
||||
|
||||
write_entry(0x00, 0x00000000, 0x00000, 0x00, 0x0); // null
|
||||
write_entry(0x08, 0x00000000, 0xFFFFF, 0x9A, 0xA); // kernel code
|
||||
write_entry(0x10, 0x00000000, 0xFFFFF, 0x92, 0xC); // kernel data
|
||||
write_entry(0x18, 0x00000000, 0xFFFFF, 0xFA, 0xA); // user code
|
||||
write_entry(0x20, 0x00000000, 0xFFFFF, 0xF2, 0xC); // user data
|
||||
write_tss(0x28);
|
||||
write_tss();
|
||||
|
||||
flush_gdt();
|
||||
flush_tss(0x28);
|
||||
flush_tss();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,13 +1,18 @@
|
||||
#include <BAN/Array.h>
|
||||
#include <BAN/Errors.h>
|
||||
#include <kernel/IDT.h>
|
||||
#include <kernel/InterruptController.h>
|
||||
#include <kernel/kmalloc.h>
|
||||
#include <kernel/InterruptStack.h>
|
||||
#include <kernel/Memory/kmalloc.h>
|
||||
#include <kernel/Panic.h>
|
||||
#include <kernel/Process.h>
|
||||
#include <kernel/Scheduler.h>
|
||||
#include <kernel/Timer/PIT.h>
|
||||
|
||||
#define REGISTER_ISR_HANDLER(i) register_interrupt_handler(i, isr ## i)
|
||||
#define REGISTER_IRQ_HANDLER(i) register_interrupt_handler(IRQ_VECTOR_BASE + i, irq ## i)
|
||||
#define ISR_LIST_X X(0) X(1) X(2) X(3) X(4) X(5) X(6) X(7) X(8) X(9) X(10) X(11) X(12) X(13) X(14) X(15) X(16) X(17) X(18) X(19) X(20) X(21) X(22) X(23) X(24) X(25) X(26) X(27) X(28) X(29) X(30) X(31)
|
||||
#define IRQ_LIST_X X(0) X(1) X(2) X(3) X(4) X(5) X(6) X(7) X(8) X(9) X(10) X(11) X(12) X(13) X(14) X(15) X(16) X(17) X(18) X(19) X(20) X(21) X(22) X(23) X(24) X(25) X(26) X(27) X(28) X(29) X(30) X(31)
|
||||
|
||||
namespace IDT
|
||||
namespace Kernel::IDT
|
||||
{
|
||||
|
||||
struct Registers
|
||||
@@ -57,7 +62,68 @@ namespace IDT
|
||||
static IDTR s_idtr;
|
||||
static GateDescriptor* s_idt = nullptr;
|
||||
|
||||
static void(*s_irq_handlers[0x10])() { nullptr };
|
||||
#define X(num) 1 +
|
||||
static BAN::Array<Interruptable*, IRQ_LIST_X 0> s_interruptables;
|
||||
#undef X
|
||||
|
||||
enum ISR
|
||||
{
|
||||
DivisionError,
|
||||
Debug,
|
||||
NonMaskableInterrupt,
|
||||
Breakpoint,
|
||||
Overflow,
|
||||
BoundRangeException,
|
||||
InvalidOpcode,
|
||||
DeviceNotAvailable,
|
||||
DoubleFault,
|
||||
CoprocessorSegmentOverrun,
|
||||
InvalidTSS,
|
||||
SegmentNotPresent,
|
||||
StackSegmentFault,
|
||||
GeneralProtectionFault,
|
||||
PageFault,
|
||||
UnknownException0x0F,
|
||||
x87FloatingPointException,
|
||||
AlignmentCheck,
|
||||
MachineCheck,
|
||||
SIMDFloatingPointException,
|
||||
VirtualizationException,
|
||||
ControlProtectionException,
|
||||
UnknownException0x16,
|
||||
UnknownException0x17,
|
||||
UnknownException0x18,
|
||||
UnknownException0x19,
|
||||
UnknownException0x1A,
|
||||
UnknownException0x1B,
|
||||
HypervisorInjectionException,
|
||||
VMMCommunicationException,
|
||||
SecurityException,
|
||||
UnkownException0x1F,
|
||||
};
|
||||
|
||||
struct PageFaultError
|
||||
{
|
||||
union
|
||||
{
|
||||
uint32_t raw;
|
||||
struct
|
||||
{
|
||||
uint32_t present : 1;
|
||||
uint32_t write : 1;
|
||||
uint32_t userspace : 1;
|
||||
uint32_t reserved_write : 1;
|
||||
uint32_t instruction : 1;
|
||||
uint32_t protection_key : 1;
|
||||
uint32_t shadow_stack : 1;
|
||||
uint32_t reserved1 : 8;
|
||||
uint32_t sgx_violation : 1;
|
||||
uint32_t reserved2 : 16;
|
||||
};
|
||||
};
|
||||
|
||||
};
|
||||
static_assert(sizeof(PageFaultError) == 4);
|
||||
|
||||
static const char* isr_exceptions[] =
|
||||
{
|
||||
@@ -95,40 +161,181 @@ namespace IDT
|
||||
"Unkown Exception 0x1F",
|
||||
};
|
||||
|
||||
extern "C" void cpp_isr_handler(uint64_t isr, uint64_t error, const Registers* regs)
|
||||
extern "C" void cpp_isr_handler(uint64_t isr, uint64_t error, InterruptStack& interrupt_stack, const Registers* regs)
|
||||
{
|
||||
Kernel::panic(
|
||||
"{} (error code: 0x{16H})\r\n"
|
||||
#if __enable_sse
|
||||
bool from_userspace = (interrupt_stack.cs & 0b11) == 0b11;
|
||||
if (from_userspace)
|
||||
Thread::current().save_sse();
|
||||
#endif
|
||||
|
||||
pid_t tid = Scheduler::current_tid();
|
||||
pid_t pid = tid ? Process::current().pid() : 0;
|
||||
|
||||
if (tid)
|
||||
{
|
||||
Thread::current().set_return_rsp(interrupt_stack.rsp);
|
||||
Thread::current().set_return_rip(interrupt_stack.rip);
|
||||
|
||||
if (isr == ISR::PageFault)
|
||||
{
|
||||
// Check if stack is OOB
|
||||
auto& stack = Thread::current().stack();
|
||||
auto& istack = Thread::current().interrupt_stack();
|
||||
if (stack.vaddr() < interrupt_stack.rsp && interrupt_stack.rsp <= stack.vaddr() + stack.size())
|
||||
; // using normal stack
|
||||
else if (istack.vaddr() < interrupt_stack.rsp && interrupt_stack.rsp <= istack.vaddr() + istack.size())
|
||||
; // using interrupt stack
|
||||
else
|
||||
{
|
||||
derrorln("Stack pointer out of bounds!");
|
||||
derrorln("rsp {H}, stack {H}->{H}, istack {H}->{H}",
|
||||
interrupt_stack.rsp,
|
||||
stack.vaddr(), stack.vaddr() + stack.size(),
|
||||
istack.vaddr(), istack.vaddr() + istack.size()
|
||||
);
|
||||
Thread::current().handle_signal(SIGKILL);
|
||||
goto done;
|
||||
}
|
||||
|
||||
// Try demand paging on non present pages
|
||||
PageFaultError page_fault_error;
|
||||
page_fault_error.raw = error;
|
||||
if (!page_fault_error.present)
|
||||
{
|
||||
asm volatile("sti");
|
||||
auto result = Process::current().allocate_page_for_demand_paging(regs->cr2);
|
||||
asm volatile("cli");
|
||||
|
||||
if (!result.is_error() && result.value())
|
||||
goto done;
|
||||
|
||||
if (result.is_error())
|
||||
{
|
||||
dwarnln("Demand paging: {}", result.error());
|
||||
Thread::current().handle_signal(SIGKILL);
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (PageTable::current().get_page_flags(interrupt_stack.rip & PAGE_ADDR_MASK) & PageTable::Flags::Present)
|
||||
{
|
||||
auto* machine_code = (const uint8_t*)interrupt_stack.rip;
|
||||
dwarnln("While executing: {2H}{2H}{2H}{2H}{2H}{2H}{2H}{2H}",
|
||||
machine_code[0],
|
||||
machine_code[1],
|
||||
machine_code[2],
|
||||
machine_code[3],
|
||||
machine_code[4],
|
||||
machine_code[5],
|
||||
machine_code[6],
|
||||
machine_code[7]
|
||||
);
|
||||
}
|
||||
|
||||
dwarnln(
|
||||
"{} (error code: 0x{16H}), pid {}, tid {}\r\n"
|
||||
"Register dump\r\n"
|
||||
"rax=0x{16H}, rbx=0x{16H}, rcx=0x{16H}, rdx=0x{16H}\r\n"
|
||||
"rsp=0x{16H}, rbp=0x{16H}, rdi=0x{16H}, rsi=0x{16H}\r\n"
|
||||
"rip=0x{16H}, rflags=0x{16H}\r\n"
|
||||
"cr0=0x{16H}, cr2=0x{16H}, cr3=0x{16H}, cr4=0x{16H}\r\n",
|
||||
isr_exceptions[isr], error,
|
||||
"cr0=0x{16H}, cr2=0x{16H}, cr3=0x{16H}, cr4=0x{16H}",
|
||||
isr_exceptions[isr], error, pid, tid,
|
||||
regs->rax, regs->rbx, regs->rcx, regs->rdx,
|
||||
regs->rsp, regs->rbp, regs->rdi, regs->rsi,
|
||||
regs->rip, regs->rflags,
|
||||
regs->cr0, regs->cr2, regs->cr3, regs->cr4
|
||||
);
|
||||
}
|
||||
if (isr == ISR::PageFault)
|
||||
PageTable::current().debug_dump();
|
||||
Debug::dump_stack_trace();
|
||||
|
||||
extern "C" void cpp_irq_handler(uint64_t irq)
|
||||
{
|
||||
if (s_irq_handlers[irq])
|
||||
s_irq_handlers[irq]();
|
||||
if (tid && Thread::current().is_userspace())
|
||||
{
|
||||
// TODO: Confirm and fix the exception to signal mappings
|
||||
|
||||
int signal = 0;
|
||||
switch (isr)
|
||||
{
|
||||
case ISR::DeviceNotAvailable:
|
||||
case ISR::DivisionError:
|
||||
case ISR::SIMDFloatingPointException:
|
||||
case ISR::x87FloatingPointException:
|
||||
signal = SIGFPE;
|
||||
break;
|
||||
case ISR::AlignmentCheck:
|
||||
signal = SIGBUS;
|
||||
break;
|
||||
case ISR::InvalidOpcode:
|
||||
signal = SIGILL;
|
||||
break;
|
||||
case ISR::PageFault:
|
||||
signal = SIGSEGV;
|
||||
break;
|
||||
default:
|
||||
dwarnln("Unhandled exception");
|
||||
signal = SIGABRT;
|
||||
break;
|
||||
}
|
||||
|
||||
Thread::current().handle_signal(signal);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!InterruptController::get().is_in_service(irq))
|
||||
{
|
||||
dprintln("spurious irq 0x{2H}", irq);
|
||||
return;
|
||||
}
|
||||
dprintln("no handler for irq 0x{2H}\n", irq);
|
||||
panic("Unhandled exception");
|
||||
}
|
||||
|
||||
// NOTE: Scheduler sends PIT eoi's
|
||||
if (irq != PIT_IRQ)
|
||||
ASSERT(Thread::current().state() != Thread::State::Terminated);
|
||||
|
||||
done:
|
||||
#if __enable_sse
|
||||
if (from_userspace)
|
||||
{
|
||||
ASSERT(Thread::current().state() == Thread::State::Executing);
|
||||
Thread::current().load_sse();
|
||||
}
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
extern "C" void cpp_irq_handler(uint64_t irq, InterruptStack& interrupt_stack)
|
||||
{
|
||||
#if __enable_sse
|
||||
bool from_userspace = (interrupt_stack.cs & 0b11) == 0b11;
|
||||
if (from_userspace)
|
||||
Thread::current().save_sse();
|
||||
#endif
|
||||
|
||||
if (Scheduler::current_tid())
|
||||
{
|
||||
Thread::current().set_return_rsp(interrupt_stack.rsp);
|
||||
Thread::current().set_return_rip(interrupt_stack.rip);
|
||||
}
|
||||
|
||||
if (!InterruptController::get().is_in_service(irq))
|
||||
dprintln("spurious irq 0x{2H}", irq);
|
||||
else
|
||||
{
|
||||
InterruptController::get().eoi(irq);
|
||||
if (s_interruptables[irq])
|
||||
s_interruptables[irq]->handle_irq();
|
||||
else
|
||||
dprintln("no handler for irq 0x{2H}\n", irq);
|
||||
}
|
||||
|
||||
Scheduler::get().reschedule_if_idling();
|
||||
|
||||
ASSERT(Thread::current().state() != Thread::State::Terminated);
|
||||
|
||||
#if __enable_sse
|
||||
if (from_userspace)
|
||||
{
|
||||
ASSERT(Thread::current().state() == Thread::State::Executing);
|
||||
Thread::current().load_sse();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void flush_idt()
|
||||
@@ -154,60 +361,20 @@ namespace IDT
|
||||
s_idt[index].flags = 0xEE;
|
||||
}
|
||||
|
||||
void register_irq_handler(uint8_t irq, void(*handler)())
|
||||
void register_irq_handler(uint8_t irq, Interruptable* interruptable)
|
||||
{
|
||||
s_irq_handlers[irq] = handler;
|
||||
if (irq > s_interruptables.size())
|
||||
Kernel::panic("Trying to assign handler for irq {} while only {} are supported", irq, s_interruptables.size());
|
||||
s_interruptables[irq] = interruptable;
|
||||
}
|
||||
|
||||
extern "C" void isr0();
|
||||
extern "C" void isr1();
|
||||
extern "C" void isr2();
|
||||
extern "C" void isr3();
|
||||
extern "C" void isr4();
|
||||
extern "C" void isr5();
|
||||
extern "C" void isr6();
|
||||
extern "C" void isr7();
|
||||
extern "C" void isr8();
|
||||
extern "C" void isr9();
|
||||
extern "C" void isr10();
|
||||
extern "C" void isr11();
|
||||
extern "C" void isr12();
|
||||
extern "C" void isr13();
|
||||
extern "C" void isr14();
|
||||
extern "C" void isr15();
|
||||
extern "C" void isr16();
|
||||
extern "C" void isr17();
|
||||
extern "C" void isr18();
|
||||
extern "C" void isr19();
|
||||
extern "C" void isr20();
|
||||
extern "C" void isr21();
|
||||
extern "C" void isr22();
|
||||
extern "C" void isr23();
|
||||
extern "C" void isr24();
|
||||
extern "C" void isr25();
|
||||
extern "C" void isr26();
|
||||
extern "C" void isr27();
|
||||
extern "C" void isr28();
|
||||
extern "C" void isr29();
|
||||
extern "C" void isr30();
|
||||
extern "C" void isr31();
|
||||
#define X(num) extern "C" void isr ## num();
|
||||
ISR_LIST_X
|
||||
#undef X
|
||||
|
||||
extern "C" void irq0();
|
||||
extern "C" void irq1();
|
||||
extern "C" void irq2();
|
||||
extern "C" void irq3();
|
||||
extern "C" void irq4();
|
||||
extern "C" void irq5();
|
||||
extern "C" void irq6();
|
||||
extern "C" void irq7();
|
||||
extern "C" void irq8();
|
||||
extern "C" void irq9();
|
||||
extern "C" void irq10();
|
||||
extern "C" void irq11();
|
||||
extern "C" void irq12();
|
||||
extern "C" void irq13();
|
||||
extern "C" void irq14();
|
||||
extern "C" void irq15();
|
||||
#define X(num) extern "C" void irq ## num();
|
||||
IRQ_LIST_X
|
||||
#undef X
|
||||
|
||||
extern "C" void syscall_asm();
|
||||
|
||||
@@ -220,59 +387,27 @@ namespace IDT
|
||||
s_idtr.offset = (uint64_t)s_idt;
|
||||
s_idtr.size = 0x100 * sizeof(GateDescriptor) - 1;
|
||||
|
||||
REGISTER_ISR_HANDLER(0);
|
||||
REGISTER_ISR_HANDLER(1);
|
||||
REGISTER_ISR_HANDLER(2);
|
||||
REGISTER_ISR_HANDLER(3);
|
||||
REGISTER_ISR_HANDLER(4);
|
||||
REGISTER_ISR_HANDLER(5);
|
||||
REGISTER_ISR_HANDLER(6);
|
||||
REGISTER_ISR_HANDLER(7);
|
||||
REGISTER_ISR_HANDLER(8);
|
||||
REGISTER_ISR_HANDLER(9);
|
||||
REGISTER_ISR_HANDLER(10);
|
||||
REGISTER_ISR_HANDLER(11);
|
||||
REGISTER_ISR_HANDLER(12);
|
||||
REGISTER_ISR_HANDLER(13);
|
||||
REGISTER_ISR_HANDLER(14);
|
||||
REGISTER_ISR_HANDLER(15);
|
||||
REGISTER_ISR_HANDLER(16);
|
||||
REGISTER_ISR_HANDLER(17);
|
||||
REGISTER_ISR_HANDLER(18);
|
||||
REGISTER_ISR_HANDLER(19);
|
||||
REGISTER_ISR_HANDLER(20);
|
||||
REGISTER_ISR_HANDLER(21);
|
||||
REGISTER_ISR_HANDLER(22);
|
||||
REGISTER_ISR_HANDLER(23);
|
||||
REGISTER_ISR_HANDLER(24);
|
||||
REGISTER_ISR_HANDLER(25);
|
||||
REGISTER_ISR_HANDLER(26);
|
||||
REGISTER_ISR_HANDLER(27);
|
||||
REGISTER_ISR_HANDLER(28);
|
||||
REGISTER_ISR_HANDLER(29);
|
||||
REGISTER_ISR_HANDLER(30);
|
||||
REGISTER_ISR_HANDLER(31);
|
||||
#define X(num) register_interrupt_handler(num, isr ## num);
|
||||
ISR_LIST_X
|
||||
#undef X
|
||||
|
||||
REGISTER_IRQ_HANDLER(0);
|
||||
REGISTER_IRQ_HANDLER(1);
|
||||
REGISTER_IRQ_HANDLER(2);
|
||||
REGISTER_IRQ_HANDLER(3);
|
||||
REGISTER_IRQ_HANDLER(4);
|
||||
REGISTER_IRQ_HANDLER(5);
|
||||
REGISTER_IRQ_HANDLER(6);
|
||||
REGISTER_IRQ_HANDLER(7);
|
||||
REGISTER_IRQ_HANDLER(8);
|
||||
REGISTER_IRQ_HANDLER(9);
|
||||
REGISTER_IRQ_HANDLER(10);
|
||||
REGISTER_IRQ_HANDLER(11);
|
||||
REGISTER_IRQ_HANDLER(12);
|
||||
REGISTER_IRQ_HANDLER(13);
|
||||
REGISTER_IRQ_HANDLER(14);
|
||||
REGISTER_IRQ_HANDLER(15);
|
||||
#define X(num) register_interrupt_handler(IRQ_VECTOR_BASE + num, irq ## num);
|
||||
IRQ_LIST_X
|
||||
#undef X
|
||||
|
||||
register_syscall_handler(0x80, syscall_asm);
|
||||
|
||||
flush_idt();
|
||||
}
|
||||
|
||||
}
|
||||
[[noreturn]] void force_triple_fault()
|
||||
{
|
||||
// load 0 sized IDT and trigger an interrupt to force triple fault
|
||||
asm volatile("cli");
|
||||
s_idtr.size = 0;
|
||||
flush_idt();
|
||||
asm volatile("int $0x00");
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,195 +0,0 @@
|
||||
#include <BAN/Errors.h>
|
||||
#include <kernel/kmalloc.h>
|
||||
#include <kernel/MMU.h>
|
||||
|
||||
#define PAGE_SIZE 0x1000
|
||||
#define PAGE_MASK ~(PAGE_SIZE - 1)
|
||||
|
||||
#define CLEANUP_STRUCTURE(s) \
|
||||
for (uint64_t i = 0; i < 512; i++) \
|
||||
if (s[i] & Flags::Present) \
|
||||
goto cleanup_done; \
|
||||
kfree(s)
|
||||
|
||||
static MMU* s_instance = nullptr;
|
||||
|
||||
void MMU::intialize()
|
||||
{
|
||||
ASSERT(s_instance == nullptr);
|
||||
s_instance = new MMU();
|
||||
}
|
||||
|
||||
MMU& MMU::get()
|
||||
{
|
||||
ASSERT(s_instance);
|
||||
return *s_instance;
|
||||
}
|
||||
|
||||
static uint64_t* allocate_page_aligned_page()
|
||||
{
|
||||
void* page = kmalloc(PAGE_SIZE, PAGE_SIZE);
|
||||
ASSERT(page);
|
||||
memset(page, 0, PAGE_SIZE);
|
||||
return (uint64_t*)page;
|
||||
}
|
||||
|
||||
MMU::MMU()
|
||||
{
|
||||
// Identity map from 4 KiB -> 6 MiB
|
||||
m_highest_paging_struct = allocate_page_aligned_page();
|
||||
|
||||
uint64_t* pdpt = allocate_page_aligned_page();
|
||||
m_highest_paging_struct[0] = (uint64_t)pdpt | Flags::ReadWrite | Flags::Present;
|
||||
|
||||
uint64_t* pd = allocate_page_aligned_page();
|
||||
pdpt[0] = (uint64_t)pd | Flags::ReadWrite | Flags::Present;
|
||||
|
||||
for (uint32_t i = 0; i < 3; i++)
|
||||
{
|
||||
uint64_t* pt = allocate_page_aligned_page();
|
||||
for (uint64_t j = 0; j < 512; j++)
|
||||
pt[j] = (i << 21) | (j << 12) | Flags::ReadWrite | Flags::Present;
|
||||
pd[i] = (uint64_t)pt | Flags::ReadWrite | Flags::Present;
|
||||
}
|
||||
|
||||
// Unmap 0 -> 4 KiB
|
||||
uint64_t* pt1 = (uint64_t*)(pd[0] & PAGE_MASK);
|
||||
pt1[0] = 0;
|
||||
|
||||
// Load the new pml4
|
||||
asm volatile("movq %0, %%cr3" :: "r"(m_highest_paging_struct));
|
||||
}
|
||||
|
||||
MMU::~MMU()
|
||||
{
|
||||
uint64_t* pml4 = m_highest_paging_struct;
|
||||
for (uint32_t pml4e = 0; pml4e < 512; pml4e++)
|
||||
{
|
||||
if (!(pml4[pml4e] & Flags::Present))
|
||||
continue;
|
||||
uint64_t* pdpt = (uint64_t*)(pml4[pml4e] & PAGE_MASK);
|
||||
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);
|
||||
}
|
||||
kfree(pml4);
|
||||
}
|
||||
|
||||
void MMU::allocate_page(uintptr_t address, uint8_t flags)
|
||||
{
|
||||
ASSERT((address >> 48) == 0);
|
||||
|
||||
ASSERT(flags & Flags::Present);
|
||||
bool should_invalidate = false;
|
||||
|
||||
address &= PAGE_MASK;
|
||||
|
||||
uint64_t pml4e = (address >> 39) & 0x1FF;
|
||||
uint64_t pdpte = (address >> 30) & 0x1FF;
|
||||
uint64_t pde = (address >> 21) & 0x1FF;
|
||||
uint64_t pte = (address >> 12) & 0x1FF;
|
||||
|
||||
uint64_t* pml4 = m_highest_paging_struct;
|
||||
if ((pml4[pml4e] & flags) != flags)
|
||||
{
|
||||
if (!(pml4[pml4e] & Flags::Present))
|
||||
pml4[pml4e] = (uint64_t)allocate_page_aligned_page();
|
||||
pml4[pml4e] = (pml4[pml4e] & PAGE_MASK) | flags;
|
||||
should_invalidate = true;
|
||||
}
|
||||
|
||||
uint64_t* pdpt = (uint64_t*)(pml4[pml4e] & PAGE_MASK);
|
||||
if ((pdpt[pdpte] & flags) != flags)
|
||||
{
|
||||
if (!(pdpt[pdpte] & Flags::Present))
|
||||
pdpt[pdpte] = (uint64_t)allocate_page_aligned_page();
|
||||
pdpt[pdpte] = (pdpt[pdpte] & PAGE_MASK) | flags;
|
||||
should_invalidate = true;
|
||||
}
|
||||
|
||||
uint64_t* pd = (uint64_t*)(pdpt[pdpte] & PAGE_MASK);
|
||||
if ((pd[pde] & flags) != flags)
|
||||
{
|
||||
if (!(pd[pde] & Flags::Present))
|
||||
pd[pde] = (uint64_t)allocate_page_aligned_page();
|
||||
pd[pde] = (pd[pde] & PAGE_MASK) | flags;
|
||||
should_invalidate = true;
|
||||
}
|
||||
|
||||
uint64_t* pt = (uint64_t*)(pd[pde] & PAGE_MASK);
|
||||
if ((pt[pte] & flags) != flags)
|
||||
{
|
||||
pt[pte] = address | flags;
|
||||
should_invalidate = true;
|
||||
}
|
||||
|
||||
if (should_invalidate)
|
||||
asm volatile("invlpg (%0)" :: "r"(address) : "memory");
|
||||
}
|
||||
|
||||
void MMU::allocate_range(uintptr_t address, ptrdiff_t size, uint8_t flags)
|
||||
{
|
||||
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)
|
||||
allocate_page(page, flags);
|
||||
}
|
||||
|
||||
void MMU::unallocate_page(uintptr_t address)
|
||||
{
|
||||
ASSERT((address >> 48) == 0);
|
||||
|
||||
address &= PAGE_MASK;
|
||||
|
||||
uint64_t pml4e = (address >> 39) & 0x1FF;
|
||||
uint64_t pdpte = (address >> 30) & 0x1FF;
|
||||
uint64_t pde = (address >> 21) & 0x1FF;
|
||||
uint64_t pte = (address >> 12) & 0x1FF;
|
||||
|
||||
uint64_t* pml4 = m_highest_paging_struct;
|
||||
if (!(pml4[pml4e] & Flags::Present))
|
||||
return;
|
||||
|
||||
uint64_t* pdpt = (uint64_t*)(pml4[pml4e] & PAGE_MASK);
|
||||
if (!(pdpt[pdpte] & Flags::Present))
|
||||
return;
|
||||
|
||||
uint64_t* pd = (uint64_t*)(pdpt[pdpte] & PAGE_MASK);
|
||||
if (!(pd[pde] & Flags::Present))
|
||||
return;
|
||||
|
||||
uint64_t* pt = (uint64_t*)(pd[pde] & PAGE_MASK);
|
||||
if (!(pt[pte] & Flags::Present))
|
||||
return;
|
||||
|
||||
pt[pte] = 0;
|
||||
|
||||
CLEANUP_STRUCTURE(pt);
|
||||
pd[pde] = 0;
|
||||
CLEANUP_STRUCTURE(pd);
|
||||
pdpt[pdpte] = 0;
|
||||
CLEANUP_STRUCTURE(pdpt);
|
||||
pml4[pml4e] = 0;
|
||||
cleanup_done:
|
||||
|
||||
asm volatile("invlpg (%0)" :: "r"(address) : "memory");
|
||||
}
|
||||
|
||||
void MMU::unallocate_range(uintptr_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)
|
||||
unallocate_page(page);
|
||||
}
|
||||
738
kernel/arch/x86_64/PageTable.cpp
Normal file
738
kernel/arch/x86_64/PageTable.cpp
Normal file
@@ -0,0 +1,738 @@
|
||||
#include <kernel/Arch.h>
|
||||
#include <kernel/CPUID.h>
|
||||
#include <kernel/InterruptController.h>
|
||||
#include <kernel/LockGuard.h>
|
||||
#include <kernel/Memory/kmalloc.h>
|
||||
#include <kernel/Memory/PageTable.h>
|
||||
#include <kernel/multiboot2.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_userspace_start[];
|
||||
extern uint8_t g_userspace_end[];
|
||||
|
||||
namespace Kernel
|
||||
{
|
||||
|
||||
static PageTable* s_kernel = nullptr;
|
||||
static PageTable* s_current = nullptr;
|
||||
static bool s_has_nxe = false;
|
||||
static bool s_has_pge = false;
|
||||
|
||||
// PML4 entry for kernel memory
|
||||
static paddr_t s_global_pml4e = 0;
|
||||
|
||||
static constexpr inline bool is_canonical(uintptr_t addr)
|
||||
{
|
||||
constexpr uintptr_t mask = 0xFFFF800000000000;
|
||||
addr &= mask;
|
||||
return addr == mask || addr == 0;
|
||||
}
|
||||
|
||||
static constexpr inline uintptr_t uncanonicalize(uintptr_t addr)
|
||||
{
|
||||
if (addr & 0x0000800000000000)
|
||||
return addr & ~0xFFFF000000000000;
|
||||
return addr;
|
||||
}
|
||||
|
||||
static constexpr inline uintptr_t canonicalize(uintptr_t addr)
|
||||
{
|
||||
if (addr & 0x0000800000000000)
|
||||
return addr | 0xFFFF000000000000;
|
||||
return addr;
|
||||
}
|
||||
|
||||
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::CacheDisable)
|
||||
result |= Flags::CacheDisable;
|
||||
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()
|
||||
{
|
||||
if (CPUID::has_nxe())
|
||||
{
|
||||
asm volatile(
|
||||
"movl $0xC0000080, %ecx;"
|
||||
"rdmsr;"
|
||||
"orl $0x800, %eax;"
|
||||
"wrmsr"
|
||||
);
|
||||
s_has_nxe = true;
|
||||
}
|
||||
|
||||
uint32_t ecx, edx;
|
||||
CPUID::get_features(ecx, edx);
|
||||
if (edx & CPUID::EDX_PGE)
|
||||
{
|
||||
asm volatile(
|
||||
"movq %cr4, %rax;"
|
||||
"orq $0x80, %rax;"
|
||||
"movq %rax, %cr4;"
|
||||
);
|
||||
s_has_pge = true;
|
||||
}
|
||||
|
||||
// enable write protect to kernel
|
||||
asm volatile(
|
||||
"movq %cr0, %rax;"
|
||||
"orq $0x10000, %rax;"
|
||||
"movq %rax, %cr0;"
|
||||
);
|
||||
|
||||
ASSERT(s_kernel == nullptr);
|
||||
s_kernel = new PageTable();
|
||||
ASSERT(s_kernel);
|
||||
s_kernel->initialize_kernel();
|
||||
s_kernel->load();
|
||||
}
|
||||
|
||||
PageTable& PageTable::kernel()
|
||||
{
|
||||
ASSERT(s_kernel);
|
||||
return *s_kernel;
|
||||
}
|
||||
|
||||
PageTable& PageTable::current()
|
||||
{
|
||||
ASSERT(s_current);
|
||||
return *s_current;
|
||||
}
|
||||
|
||||
bool PageTable::is_valid_pointer(uintptr_t pointer)
|
||||
{
|
||||
if (!is_canonical(pointer))
|
||||
return false;
|
||||
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;
|
||||
}
|
||||
|
||||
void PageTable::initialize_kernel()
|
||||
{
|
||||
ASSERT(s_global_pml4e == 0);
|
||||
s_global_pml4e = V2P(allocate_zeroed_page_aligned_page());
|
||||
|
||||
m_highest_paging_struct = V2P(allocate_zeroed_page_aligned_page());
|
||||
|
||||
uint64_t* pml4 = (uint64_t*)P2V(m_highest_paging_struct);
|
||||
pml4[511] = s_global_pml4e;
|
||||
|
||||
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::ReadWrite | 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 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
|
||||
);
|
||||
|
||||
// Map multiboot memory
|
||||
paddr_t multiboot2_data_start = (vaddr_t)g_multiboot2_info & PAGE_ADDR_MASK;
|
||||
paddr_t multiboot2_data_end = (vaddr_t)g_multiboot2_info + g_multiboot2_info->total_size;
|
||||
|
||||
size_t multiboot2_needed_pages = BAN::Math::div_round_up<size_t>(multiboot2_data_end - multiboot2_data_start, PAGE_SIZE);
|
||||
vaddr_t multiboot2_vaddr = reserve_free_contiguous_pages(multiboot2_needed_pages, KERNEL_OFFSET);
|
||||
|
||||
map_range_at(
|
||||
multiboot2_data_start,
|
||||
multiboot2_vaddr,
|
||||
multiboot2_needed_pages * PAGE_SIZE,
|
||||
Flags::ReadWrite | Flags::Present
|
||||
);
|
||||
|
||||
g_multiboot2_info = (multiboot2_info_t*)(multiboot2_vaddr + ((vaddr_t)g_multiboot2_info % PAGE_SIZE));
|
||||
}
|
||||
|
||||
void PageTable::prepare_fast_page()
|
||||
{
|
||||
constexpr vaddr_t uc_vaddr = uncanonicalize(fast_page());
|
||||
constexpr uint64_t pml4e = (uc_vaddr >> 39) & 0x1FF;
|
||||
constexpr uint64_t pdpte = (uc_vaddr >> 30) & 0x1FF;
|
||||
constexpr uint64_t pde = (uc_vaddr >> 21) & 0x1FF;
|
||||
constexpr uint64_t pte = (uc_vaddr >> 12) & 0x1FF;
|
||||
|
||||
uint64_t* pml4 = (uint64_t*)P2V(m_highest_paging_struct);
|
||||
ASSERT(!(pml4[pml4e] & Flags::Present));
|
||||
pml4[pml4e] = V2P(allocate_zeroed_page_aligned_page()) | Flags::ReadWrite | Flags::Present;
|
||||
|
||||
uint64_t* pdpt = (uint64_t*)P2V(pml4[pml4e] & PAGE_ADDR_MASK);
|
||||
ASSERT(!(pdpt[pdpte] & Flags::Present));
|
||||
pdpt[pdpte] = V2P(allocate_zeroed_page_aligned_page()) | Flags::ReadWrite | Flags::Present;
|
||||
|
||||
uint64_t* pd = (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;
|
||||
|
||||
uint64_t* pt = (uint64_t*)P2V(pd[pde] & PAGE_ADDR_MASK);
|
||||
ASSERT(!(pt[pte] & Flags::Present));
|
||||
pt[pte] = V2P(allocate_zeroed_page_aligned_page());
|
||||
}
|
||||
|
||||
void PageTable::map_fast_page(paddr_t paddr)
|
||||
{
|
||||
ASSERT(s_kernel);
|
||||
ASSERT_NEQ(paddr, 0);
|
||||
ASSERT(!interrupts_enabled());
|
||||
|
||||
constexpr vaddr_t uc_vaddr = uncanonicalize(fast_page());
|
||||
constexpr uint64_t pml4e = (uc_vaddr >> 39) & 0x1FF;
|
||||
constexpr uint64_t pdpte = (uc_vaddr >> 30) & 0x1FF;
|
||||
constexpr uint64_t pde = (uc_vaddr >> 21) & 0x1FF;
|
||||
constexpr uint64_t pte = (uc_vaddr >> 12) & 0x1FF;
|
||||
|
||||
uint64_t* pml4 = (uint64_t*)P2V(s_kernel->m_highest_paging_struct);
|
||||
uint64_t* pdpt = (uint64_t*)P2V(pml4[pml4e] & PAGE_ADDR_MASK);
|
||||
uint64_t* pd = (uint64_t*)P2V(pdpt[pdpte] & PAGE_ADDR_MASK);
|
||||
uint64_t* pt = (uint64_t*)P2V(pd[pde] & PAGE_ADDR_MASK);
|
||||
|
||||
ASSERT(!(pt[pte] & Flags::Present));
|
||||
pt[pte] = paddr | Flags::ReadWrite | Flags::Present;
|
||||
|
||||
invalidate(fast_page());
|
||||
}
|
||||
|
||||
void PageTable::unmap_fast_page()
|
||||
{
|
||||
ASSERT(s_kernel);
|
||||
ASSERT(!interrupts_enabled());
|
||||
|
||||
constexpr vaddr_t uc_vaddr = uncanonicalize(fast_page());
|
||||
constexpr uint64_t pml4e = (uc_vaddr >> 39) & 0x1FF;
|
||||
constexpr uint64_t pdpte = (uc_vaddr >> 30) & 0x1FF;
|
||||
constexpr uint64_t pde = (uc_vaddr >> 21) & 0x1FF;
|
||||
constexpr uint64_t pte = (uc_vaddr >> 12) & 0x1FF;
|
||||
|
||||
uint64_t* pml4 = (uint64_t*)P2V(s_kernel->m_highest_paging_struct);
|
||||
uint64_t* pdpt = (uint64_t*)P2V(pml4[pml4e] & PAGE_ADDR_MASK);
|
||||
uint64_t* pd = (uint64_t*)P2V(pdpt[pdpte] & PAGE_ADDR_MASK);
|
||||
uint64_t* pt = (uint64_t*)P2V(pd[pde] & PAGE_ADDR_MASK);
|
||||
|
||||
ASSERT(pt[pte] & Flags::Present);
|
||||
pt[pte] = 0;
|
||||
|
||||
invalidate(fast_page());
|
||||
}
|
||||
|
||||
BAN::ErrorOr<PageTable*> PageTable::create_userspace()
|
||||
{
|
||||
LockGuard _(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_pml4e);
|
||||
|
||||
ASSERT(m_highest_paging_struct == 0);
|
||||
m_highest_paging_struct = V2P(allocate_zeroed_page_aligned_page());
|
||||
|
||||
uint64_t* kernel_pml4 = (uint64_t*)P2V(s_kernel->m_highest_paging_struct);
|
||||
|
||||
uint64_t* pml4 = (uint64_t*)P2V(m_highest_paging_struct);
|
||||
pml4[511] = kernel_pml4[511];
|
||||
}
|
||||
|
||||
PageTable::~PageTable()
|
||||
{
|
||||
uint64_t* pml4 = (uint64_t*)P2V(m_highest_paging_struct);
|
||||
|
||||
// NOTE: we only loop until 511 since the last one is the kernel memory
|
||||
for (uint64_t pml4e = 0; pml4e < 511; pml4e++)
|
||||
{
|
||||
if (!(pml4[pml4e] & Flags::Present))
|
||||
continue;
|
||||
uint64_t* pdpt = (uint64_t*)P2V(pml4[pml4e] & PAGE_ADDR_MASK);
|
||||
for (uint64_t pdpte = 0; pdpte < 512; pdpte++)
|
||||
{
|
||||
if (!(pdpt[pdpte] & Flags::Present))
|
||||
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))
|
||||
continue;
|
||||
kfree((void*)P2V(pd[pde] & PAGE_ADDR_MASK));
|
||||
}
|
||||
kfree(pd);
|
||||
}
|
||||
kfree(pdpt);
|
||||
}
|
||||
kfree(pml4);
|
||||
}
|
||||
|
||||
void PageTable::load()
|
||||
{
|
||||
asm volatile("movq %0, %%cr3" :: "r"(m_highest_paging_struct));
|
||||
s_current = this;
|
||||
}
|
||||
|
||||
void PageTable::invalidate(vaddr_t vaddr)
|
||||
{
|
||||
ASSERT(vaddr % PAGE_SIZE == 0);
|
||||
asm volatile("invlpg (%0)" :: "r"(vaddr) : "memory");
|
||||
}
|
||||
|
||||
void PageTable::unmap_page(vaddr_t vaddr)
|
||||
{
|
||||
ASSERT(vaddr);
|
||||
ASSERT(vaddr != fast_page());
|
||||
if (vaddr >= KERNEL_OFFSET)
|
||||
ASSERT_GTE(vaddr, (vaddr_t)g_kernel_start);
|
||||
if ((vaddr >= KERNEL_OFFSET) != (this == s_kernel))
|
||||
Kernel::panic("unmapping {8H}, kernel: {}", vaddr, this == s_kernel);
|
||||
|
||||
ASSERT(is_canonical(vaddr));
|
||||
vaddr_t uc_vaddr = uncanonicalize(vaddr);
|
||||
|
||||
ASSERT(vaddr % PAGE_SIZE == 0);
|
||||
|
||||
uint64_t pml4e = (uc_vaddr >> 39) & 0x1FF;
|
||||
uint64_t pdpte = (uc_vaddr >> 30) & 0x1FF;
|
||||
uint64_t pde = (uc_vaddr >> 21) & 0x1FF;
|
||||
uint64_t pte = (uc_vaddr >> 12) & 0x1FF;
|
||||
|
||||
LockGuard _(m_lock);
|
||||
|
||||
if (is_page_free(vaddr))
|
||||
{
|
||||
dwarnln("unmapping unmapped page {8H}", vaddr);
|
||||
return;
|
||||
}
|
||||
|
||||
uint64_t* pml4 = (uint64_t*)P2V(m_highest_paging_struct);
|
||||
uint64_t* pdpt = (uint64_t*)P2V(pml4[pml4e] & PAGE_ADDR_MASK);
|
||||
uint64_t* pd = (uint64_t*)P2V(pdpt[pdpte] & PAGE_ADDR_MASK);
|
||||
uint64_t* pt = (uint64_t*)P2V(pd[pde] & PAGE_ADDR_MASK);
|
||||
|
||||
pt[pte] = 0;
|
||||
invalidate(vaddr);
|
||||
}
|
||||
|
||||
void PageTable::unmap_range(vaddr_t vaddr, size_t size)
|
||||
{
|
||||
vaddr_t s_page = vaddr / PAGE_SIZE;
|
||||
vaddr_t e_page = BAN::Math::div_round_up<vaddr_t>(vaddr + size, PAGE_SIZE);
|
||||
|
||||
LockGuard _(m_lock);
|
||||
for (vaddr_t page = s_page; page < e_page; page++)
|
||||
unmap_page(page * PAGE_SIZE);
|
||||
}
|
||||
|
||||
void PageTable::map_page_at(paddr_t paddr, vaddr_t vaddr, flags_t flags)
|
||||
{
|
||||
ASSERT(vaddr);
|
||||
ASSERT(vaddr != fast_page());
|
||||
if (vaddr >= KERNEL_OFFSET)
|
||||
ASSERT_GTE(vaddr, (vaddr_t)g_kernel_start);
|
||||
if ((vaddr >= KERNEL_OFFSET) != (this == s_kernel))
|
||||
Kernel::panic("mapping {8H} to {8H}, kernel: {}", paddr, vaddr, this == s_kernel);
|
||||
|
||||
ASSERT(is_canonical(vaddr));
|
||||
vaddr_t uc_vaddr = uncanonicalize(vaddr);
|
||||
|
||||
ASSERT(paddr % PAGE_SIZE == 0);
|
||||
ASSERT(vaddr % PAGE_SIZE == 0);
|
||||
ASSERT(flags & Flags::Used);
|
||||
|
||||
uint64_t pml4e = (uc_vaddr >> 39) & 0x1FF;
|
||||
uint64_t pdpte = (uc_vaddr >> 30) & 0x1FF;
|
||||
uint64_t pde = (uc_vaddr >> 21) & 0x1FF;
|
||||
uint64_t pte = (uc_vaddr >> 12) & 0x1FF;
|
||||
|
||||
uint64_t extra_flags = 0;
|
||||
if (s_has_pge && pml4e == 511) // 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 (flags & Flags::CacheDisable)
|
||||
extra_flags |= Flags::CacheDisable;
|
||||
|
||||
// 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;
|
||||
|
||||
LockGuard _(m_lock);
|
||||
|
||||
uint64_t* pml4 = (uint64_t*)P2V(m_highest_paging_struct);
|
||||
if ((pml4[pml4e] & uwr_flags) != uwr_flags)
|
||||
{
|
||||
if (!(pml4[pml4e] & Flags::Present))
|
||||
pml4[pml4e] = V2P(allocate_zeroed_page_aligned_page());
|
||||
pml4[pml4e] |= uwr_flags;
|
||||
}
|
||||
|
||||
uint64_t* pdpt = (uint64_t*)P2V(pml4[pml4e] & PAGE_ADDR_MASK);
|
||||
if ((pdpt[pdpte] & uwr_flags) != uwr_flags)
|
||||
{
|
||||
if (!(pdpt[pdpte] & Flags::Present))
|
||||
pdpt[pdpte] = V2P(allocate_zeroed_page_aligned_page());
|
||||
pdpt[pdpte] |= uwr_flags;
|
||||
}
|
||||
|
||||
uint64_t* pd = (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 = (uint64_t*)P2V(pd[pde] & PAGE_ADDR_MASK);
|
||||
pt[pte] = paddr | uwr_flags | extra_flags;
|
||||
|
||||
invalidate(vaddr);
|
||||
}
|
||||
|
||||
void PageTable::map_range_at(paddr_t paddr, vaddr_t vaddr, size_t size, flags_t flags)
|
||||
{
|
||||
ASSERT(is_canonical(vaddr));
|
||||
|
||||
ASSERT(vaddr);
|
||||
ASSERT(paddr % PAGE_SIZE == 0);
|
||||
ASSERT(vaddr % PAGE_SIZE == 0);
|
||||
|
||||
size_t page_count = range_page_count(vaddr, size);
|
||||
|
||||
LockGuard _(m_lock);
|
||||
for (size_t page = 0; page < page_count; page++)
|
||||
map_page_at(paddr + page * PAGE_SIZE, vaddr + page * PAGE_SIZE, flags);
|
||||
}
|
||||
|
||||
uint64_t PageTable::get_page_data(vaddr_t vaddr) const
|
||||
{
|
||||
ASSERT(is_canonical(vaddr));
|
||||
vaddr_t uc_vaddr = uncanonicalize(vaddr);
|
||||
|
||||
ASSERT(vaddr % PAGE_SIZE == 0);
|
||||
|
||||
uint64_t pml4e = (uc_vaddr >> 39) & 0x1FF;
|
||||
uint64_t pdpte = (uc_vaddr >> 30) & 0x1FF;
|
||||
uint64_t pde = (uc_vaddr >> 21) & 0x1FF;
|
||||
uint64_t pte = (uc_vaddr >> 12) & 0x1FF;
|
||||
|
||||
LockGuard _(m_lock);
|
||||
|
||||
uint64_t* pml4 = (uint64_t*)P2V(m_highest_paging_struct);
|
||||
if (!(pml4[pml4e] & Flags::Present))
|
||||
return 0;
|
||||
|
||||
uint64_t* pdpt = (uint64_t*)P2V(pml4[pml4e] & PAGE_ADDR_MASK);
|
||||
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 addr) const
|
||||
{
|
||||
return parse_flags(get_page_data(addr));
|
||||
}
|
||||
|
||||
paddr_t PageTable::physical_address_of(vaddr_t addr) const
|
||||
{
|
||||
uint64_t page_data = get_page_data(addr);
|
||||
return (page_data & PAGE_ADDR_MASK) & ~(1ull << 63);
|
||||
}
|
||||
|
||||
bool PageTable::reserve_page(vaddr_t vaddr, bool only_free)
|
||||
{
|
||||
LockGuard _(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);
|
||||
|
||||
LockGuard _(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;
|
||||
|
||||
ASSERT(is_canonical(first_address));
|
||||
ASSERT(is_canonical(last_address));
|
||||
const vaddr_t uc_vaddr_start = uncanonicalize(first_address);
|
||||
const vaddr_t uc_vaddr_end = uncanonicalize(last_address);
|
||||
|
||||
uint16_t pml4e = (uc_vaddr_start >> 39) & 0x1FF;
|
||||
uint16_t pdpte = (uc_vaddr_start >> 30) & 0x1FF;
|
||||
uint16_t pde = (uc_vaddr_start >> 21) & 0x1FF;
|
||||
uint16_t pte = (uc_vaddr_start >> 12) & 0x1FF;
|
||||
|
||||
const uint16_t e_pml4e = (uc_vaddr_end >> 39) & 0x1FF;
|
||||
const uint16_t e_pdpte = (uc_vaddr_end >> 30) & 0x1FF;
|
||||
const uint16_t e_pde = (uc_vaddr_end >> 21) & 0x1FF;
|
||||
const uint16_t e_pte = (uc_vaddr_end >> 12) & 0x1FF;
|
||||
|
||||
LockGuard _(m_lock);
|
||||
|
||||
// Try to find free page that can be mapped without
|
||||
// allocations (page table with unused entries)
|
||||
uint64_t* pml4 = (uint64_t*)P2V(m_highest_paging_struct);
|
||||
for (; pml4e < 512; pml4e++)
|
||||
{
|
||||
if (pml4e > e_pml4e)
|
||||
break;
|
||||
if (!(pml4[pml4e] & Flags::Present))
|
||||
continue;
|
||||
uint64_t* pdpt = (uint64_t*)P2V(pml4[pml4e] & PAGE_ADDR_MASK);
|
||||
for (; pdpte < 512; pdpte++)
|
||||
{
|
||||
if (pml4e == e_pml4e && pdpte > e_pdpte)
|
||||
break;
|
||||
if (!(pdpt[pdpte] & Flags::Present))
|
||||
continue;
|
||||
uint64_t* pd = (uint64_t*)P2V(pdpt[pdpte] & PAGE_ADDR_MASK);
|
||||
for (; pde < 512; pde++)
|
||||
{
|
||||
if (pml4e == e_pml4e && 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 (; pte < 512; pte++)
|
||||
{
|
||||
if (pml4e == e_pml4e && pdpte == e_pdpte && pde == e_pde && pte >= e_pte)
|
||||
break;
|
||||
if (!(pt[pte] & Flags::Used))
|
||||
{
|
||||
vaddr_t vaddr = 0;
|
||||
vaddr |= (uint64_t)pml4e << 39;
|
||||
vaddr |= (uint64_t)pdpte << 30;
|
||||
vaddr |= (uint64_t)pde << 21;
|
||||
vaddr |= (uint64_t)pte << 12;
|
||||
vaddr = canonicalize(vaddr);
|
||||
ASSERT(reserve_page(vaddr));
|
||||
return vaddr;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Find any free page
|
||||
vaddr_t uc_vaddr = uc_vaddr_start;
|
||||
while (uc_vaddr < uc_vaddr_end)
|
||||
{
|
||||
if (vaddr_t vaddr = canonicalize(uc_vaddr); is_page_free(vaddr))
|
||||
{
|
||||
ASSERT(reserve_page(vaddr));
|
||||
return vaddr;
|
||||
}
|
||||
uc_vaddr += PAGE_SIZE;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
ASSERT(is_canonical(first_address));
|
||||
ASSERT(is_canonical(last_address));
|
||||
|
||||
LockGuard _(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_canonical(vaddr + page * PAGE_SIZE))
|
||||
{
|
||||
vaddr = canonicalize(uncanonicalize(vaddr) + page * PAGE_SIZE);
|
||||
valid = false;
|
||||
break;
|
||||
}
|
||||
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();
|
||||
}
|
||||
|
||||
bool PageTable::is_page_free(vaddr_t page) const
|
||||
{
|
||||
ASSERT(page % PAGE_SIZE == 0);
|
||||
return !(get_page_flags(page) & 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);
|
||||
|
||||
LockGuard _(m_lock);
|
||||
for (vaddr_t page = s_page; page < e_page; page++)
|
||||
if (!is_page_free(page * PAGE_SIZE))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static void dump_range(vaddr_t start, vaddr_t end, PageTable::flags_t flags)
|
||||
{
|
||||
if (start == 0)
|
||||
return;
|
||||
dprintln("{}-{}: {}{}{}{}",
|
||||
(void*)canonicalize(start),
|
||||
(void*)canonicalize(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()
|
||||
{
|
||||
LockGuard _(m_lock);
|
||||
|
||||
flags_t flags = 0;
|
||||
vaddr_t start = 0;
|
||||
|
||||
uint64_t* pml4 = (uint64_t*)P2V(m_highest_paging_struct);
|
||||
for (uint64_t pml4e = 0; pml4e < 512; pml4e++)
|
||||
{
|
||||
if (!(pml4[pml4e] & Flags::Present))
|
||||
{
|
||||
dump_range(start, (pml4e << 39), flags);
|
||||
start = 0;
|
||||
continue;
|
||||
}
|
||||
uint64_t* pdpt = (uint64_t*)P2V(pml4[pml4e] & PAGE_ADDR_MASK);
|
||||
for (uint64_t pdpte = 0; pdpte < 512; pdpte++)
|
||||
{
|
||||
if (!(pdpt[pdpte] & Flags::Present))
|
||||
{
|
||||
dump_range(start, (pml4e << 39) | (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, (pml4e << 39) | (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, (pml4e << 39) | (pdpte << 30) | (pde << 21) | (pte << 12), flags);
|
||||
start = 0;
|
||||
}
|
||||
|
||||
if (!(pt[pte] & Flags::Used))
|
||||
continue;
|
||||
|
||||
if (start == 0)
|
||||
{
|
||||
flags = parse_flags(pt[pte]);
|
||||
start = (pml4e << 39) | (pdpte << 30) | (pde << 21) | (pte << 12);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
57
kernel/arch/x86_64/Signal.S
Normal file
57
kernel/arch/x86_64/Signal.S
Normal file
@@ -0,0 +1,57 @@
|
||||
.section .userspace, "aw"
|
||||
|
||||
#include <sys/syscall.h>
|
||||
|
||||
// stack contains
|
||||
// return address
|
||||
// signal number
|
||||
// signal handler
|
||||
|
||||
.global signal_trampoline
|
||||
signal_trampoline:
|
||||
pushq %rax
|
||||
pushq %rbx
|
||||
pushq %rcx
|
||||
pushq %rdx
|
||||
pushq %rbp
|
||||
pushq %rdi
|
||||
pushq %rsi
|
||||
pushq %r8
|
||||
pushq %r9
|
||||
pushq %r10
|
||||
pushq %r11
|
||||
pushq %r12
|
||||
pushq %r13
|
||||
pushq %r14
|
||||
pushq %r15
|
||||
|
||||
// This is 16 byte aligned
|
||||
|
||||
movq 128(%rsp), %rdi
|
||||
movq 120(%rsp), %rax
|
||||
call *%rax
|
||||
|
||||
movq $SYS_SIGNAL_DONE, %rax
|
||||
movq 128(%rsp), %rbx
|
||||
int $0x80
|
||||
|
||||
popq %r15
|
||||
popq %r14
|
||||
popq %r13
|
||||
popq %r12
|
||||
popq %r11
|
||||
popq %r10
|
||||
popq %r9
|
||||
popq %r8
|
||||
popq %rsi
|
||||
popq %rdi
|
||||
popq %rbp
|
||||
popq %rdx
|
||||
popq %rcx
|
||||
popq %rbx
|
||||
popq %rax
|
||||
|
||||
addq $16, %rsp
|
||||
|
||||
// return over red-zone
|
||||
ret $128
|
||||
@@ -1,17 +0,0 @@
|
||||
.global spinlock_lock_asm
|
||||
spinlock_lock_asm:
|
||||
lock; btsq $0, (%rdi)
|
||||
jnc .done
|
||||
.retry:
|
||||
pause
|
||||
testq $1, (%rdi)
|
||||
jne .retry
|
||||
lock; btsq $0, (%rdi)
|
||||
jc .retry
|
||||
.done:
|
||||
ret
|
||||
|
||||
.global spinlock_unlock_asm
|
||||
spinlock_unlock_asm:
|
||||
movl $0, (%rdi)
|
||||
ret
|
||||
@@ -23,4 +23,17 @@ start_thread:
|
||||
continue_thread:
|
||||
movq %rdi, %rsp
|
||||
movq $0, %rax
|
||||
jmp *%rsi
|
||||
jmp *%rsi
|
||||
|
||||
# void thread_userspace_trampoline(uint64_t rsp, uint64_t rip, int argc, char** argv, char** envp)
|
||||
.global thread_userspace_trampoline
|
||||
thread_userspace_trampoline:
|
||||
pushq $0x23
|
||||
pushq %rdi
|
||||
pushfq
|
||||
pushq $0x1B
|
||||
pushq %rsi
|
||||
movq %rdx, %rdi
|
||||
movq %rcx, %rsi
|
||||
movq %r8, %rdx
|
||||
iretq
|
||||
|
||||
@@ -1,30 +1,43 @@
|
||||
# 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
|
||||
|
||||
.set PG_PRESENT, 1<<0
|
||||
.set PG_READ_WRITE, 1<<1
|
||||
.set PG_PAGE_SIZE, 1<<7
|
||||
|
||||
#define KERNEL_OFFSET 0xFFFFFFFF80000000
|
||||
#define V2P(vaddr) ((vaddr) - KERNEL_OFFSET)
|
||||
|
||||
.code32
|
||||
|
||||
# Multiboot header
|
||||
# multiboot2 header
|
||||
.section .multiboot, "aw"
|
||||
.align 4
|
||||
.long MB_MAGIC
|
||||
.long MB_FLAGS
|
||||
.long MB_CHECKSUM
|
||||
.skip 20
|
||||
|
||||
multiboot2_start:
|
||||
.align 8
|
||||
.long 0xE85250D6
|
||||
.long 0
|
||||
.long 800
|
||||
.long 600
|
||||
.long multiboot2_end - multiboot2_start
|
||||
.long -(0xE85250D6 + (multiboot2_end - multiboot2_start))
|
||||
|
||||
# framebuffer tag
|
||||
.align 8
|
||||
.short 5
|
||||
.short 0
|
||||
.long 20
|
||||
.long 1920
|
||||
.long 1080
|
||||
.long 32
|
||||
|
||||
# legacy start
|
||||
.align 8
|
||||
.short 3
|
||||
.short 0
|
||||
.long 12
|
||||
.long V2P(_start)
|
||||
|
||||
.align 8
|
||||
.short 0
|
||||
.short 0
|
||||
.long 8
|
||||
multiboot2_end:
|
||||
|
||||
.section .bss, "aw", @nobits
|
||||
# Create stack
|
||||
.global g_boot_stack_bottom
|
||||
@@ -32,34 +45,45 @@
|
||||
.skip 16384
|
||||
.global g_boot_stack_top
|
||||
g_boot_stack_top:
|
||||
|
||||
|
||||
.global g_kernel_cmdline
|
||||
g_kernel_cmdline:
|
||||
.skip 4096
|
||||
|
||||
# Reserve memory for paging structures,
|
||||
# we will identity map first 4 MiB
|
||||
.global g_multiboot2_info
|
||||
g_multiboot2_info:
|
||||
.skip 8
|
||||
.global g_multiboot2_magic
|
||||
g_multiboot2_magic:
|
||||
.skip 8
|
||||
|
||||
# 0 MiB -> 1 MiB: bootloader stuff
|
||||
# 1 MiB -> 4 MiB: kernel
|
||||
# 4 MiB -> 5 MiB: kmalloc
|
||||
# 5 MiB -> 6 MiB: kmalloc_fixed
|
||||
.align 4096
|
||||
boot_pml4:
|
||||
.skip 512 * 8
|
||||
boot_pdpt1:
|
||||
.skip 512 * 8
|
||||
boot_pd1:
|
||||
.skip 512 * 8
|
||||
.section .data
|
||||
|
||||
.global g_multiboot_info
|
||||
g_multiboot_info:
|
||||
.skip 8
|
||||
.global g_multiboot_magic
|
||||
g_multiboot_magic:
|
||||
.skip 8
|
||||
|
||||
.section .text
|
||||
# Map first GiB to 0x00000000 and 0xFFFFFFFF80000000
|
||||
.align 4096
|
||||
boot_pml4:
|
||||
.quad V2P(boot_pdpt_lo) + (PG_READ_WRITE | PG_PRESENT)
|
||||
.rept 510
|
||||
.quad 0
|
||||
.endr
|
||||
.quad V2P(boot_pdpt_hi) + (PG_READ_WRITE | PG_PRESENT)
|
||||
boot_pdpt_lo:
|
||||
.quad V2P(boot_pd) + (PG_READ_WRITE | PG_PRESENT)
|
||||
.rept 511
|
||||
.quad 0
|
||||
.endr
|
||||
boot_pdpt_hi:
|
||||
.rept 510
|
||||
.quad 0
|
||||
.endr
|
||||
.quad V2P(boot_pd) + (PG_READ_WRITE | PG_PRESENT)
|
||||
.quad 0
|
||||
boot_pd:
|
||||
.set i, 0
|
||||
.rept 512
|
||||
.quad i + (PG_PAGE_SIZE | PG_READ_WRITE | PG_PRESENT)
|
||||
.set i, i + 0x200000
|
||||
.endr
|
||||
|
||||
boot_gdt:
|
||||
.quad 0x0000000000000000 # null descriptor
|
||||
@@ -67,7 +91,9 @@ boot_gdt:
|
||||
.quad 0x00AF92000000FFFF # kernel data
|
||||
boot_gdtr:
|
||||
.short . - boot_gdt - 1
|
||||
.quad boot_gdt
|
||||
.quad V2P(boot_gdt)
|
||||
|
||||
.section .text
|
||||
|
||||
has_cpuid:
|
||||
pushfl
|
||||
@@ -103,19 +129,6 @@ check_requirements:
|
||||
.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
|
||||
@@ -127,15 +140,6 @@ enable_sse:
|
||||
ret
|
||||
|
||||
initialize_paging:
|
||||
# identity map first 6 MiB
|
||||
movl $(0x00000000 + PG_PAGE_SIZE + PG_READ_WRITE + PG_PRESENT), boot_pd1 + 0
|
||||
movl $(0x00200000 + PG_PAGE_SIZE + PG_READ_WRITE + PG_PRESENT), boot_pd1 + 8
|
||||
movl $(0x00400000 + PG_PAGE_SIZE + PG_READ_WRITE + PG_PRESENT), boot_pd1 + 16
|
||||
|
||||
# set pdpte1 and pml4e1
|
||||
movl $(boot_pd1 + PG_READ_WRITE + PG_PRESENT), boot_pdpt1
|
||||
movl $(boot_pdpt1 + PG_READ_WRITE + PG_PRESENT), boot_pml4
|
||||
|
||||
# enable PAE
|
||||
movl %cr4, %ecx
|
||||
orl $0x20, %ecx
|
||||
@@ -148,7 +152,7 @@ initialize_paging:
|
||||
wrmsr
|
||||
|
||||
# set address of paging structures
|
||||
movl $boot_pml4, %ecx
|
||||
movl $V2P(boot_pml4), %ecx
|
||||
movl %ecx, %cr3
|
||||
|
||||
# enable paging
|
||||
@@ -162,19 +166,18 @@ initialize_paging:
|
||||
.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
|
||||
movl $V2P(g_boot_stack_top), %esp
|
||||
movl %eax, V2P(g_multiboot2_magic)
|
||||
movl %ebx, V2P(g_multiboot2_info)
|
||||
|
||||
call copy_kernel_commandline
|
||||
call check_requirements
|
||||
call enable_sse
|
||||
|
||||
call initialize_paging
|
||||
|
||||
# flush gdt and jump to 64 bit
|
||||
lgdt boot_gdtr
|
||||
ljmpl $0x08, $long_mode
|
||||
lgdt V2P(boot_gdtr)
|
||||
ljmpl $0x08, $V2P(long_mode)
|
||||
|
||||
.code64
|
||||
long_mode:
|
||||
@@ -188,6 +191,12 @@ long_mode:
|
||||
movw %ax, %fs
|
||||
movw %ax, %gs
|
||||
|
||||
# jump to higher half
|
||||
movq $g_boot_stack_top, %rsp
|
||||
movabsq $higher_half, %rcx
|
||||
jmp *%rcx
|
||||
|
||||
higher_half:
|
||||
# call global constuctors
|
||||
call _init
|
||||
|
||||
|
||||
@@ -64,7 +64,11 @@ isr_stub:
|
||||
|
||||
movq 176(%rsp), %rdi
|
||||
movq 184(%rsp), %rsi
|
||||
|
||||
movq %rsp, %rdx
|
||||
addq $192, %rdx
|
||||
|
||||
movq %rsp, %rcx
|
||||
|
||||
call cpp_isr_handler
|
||||
addq $56, %rsp
|
||||
@@ -75,6 +79,8 @@ isr_stub:
|
||||
irq_stub:
|
||||
pushaq
|
||||
movq 0x78(%rsp), %rdi # irq number
|
||||
movq %rsp, %rsi
|
||||
addq $136, %rsi
|
||||
call cpp_irq_handler
|
||||
popaq
|
||||
addq $16, %rsp
|
||||
@@ -83,7 +89,6 @@ irq_stub:
|
||||
.macro isr n
|
||||
.global isr\n
|
||||
isr\n:
|
||||
cli
|
||||
pushq $0
|
||||
pushq $\n
|
||||
jmp isr_stub
|
||||
@@ -92,7 +97,6 @@ irq_stub:
|
||||
.macro isr_err n
|
||||
.global isr\n
|
||||
isr\n:
|
||||
cli
|
||||
pushq $\n
|
||||
jmp isr_stub
|
||||
.endm
|
||||
@@ -100,7 +104,6 @@ irq_stub:
|
||||
.macro irq n
|
||||
.global irq\n
|
||||
irq\n:
|
||||
cli
|
||||
pushq $0
|
||||
pushq $\n
|
||||
jmp irq_stub
|
||||
@@ -155,15 +158,38 @@ 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
|
||||
|
||||
// arguments in RAX, RBX, RCX, RDX, RSI, RDI
|
||||
// System V ABI: RDI, RSI, RDX, RCX, R8, R9
|
||||
.global syscall_asm
|
||||
syscall_asm:
|
||||
cli
|
||||
pushaq
|
||||
movq %rsi, %r8
|
||||
movq %rdi, %r9
|
||||
movq %rax, %rdi
|
||||
movq %rbx, %rsi
|
||||
xchgq %rcx, %rdx
|
||||
movq %rsp, %rbx
|
||||
addq $120, %rbx
|
||||
pushq %rbx
|
||||
call cpp_syscall_handler
|
||||
addq $8, %rsp
|
||||
popaq_no_rax
|
||||
addq $8, %rsp
|
||||
iretq
|
||||
@@ -1,38 +1,37 @@
|
||||
ENTRY (_start)
|
||||
|
||||
KERNEL_OFFSET = 0xFFFFFFFF80000000;
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
. = 0x00100000;
|
||||
. = 0x00100000 + KERNEL_OFFSET;
|
||||
|
||||
.text BLOCK(4K) : ALIGN(4K)
|
||||
g_kernel_start = .;
|
||||
.text ALIGN(4K) : AT(ADDR(.text) - KERNEL_OFFSET)
|
||||
{
|
||||
g_kernel_execute_start = .;
|
||||
*(.multiboot)
|
||||
*(.text)
|
||||
*(.text.*)
|
||||
}
|
||||
.rodata BLOCK(4K) : ALIGN(4K)
|
||||
.userspace ALIGN(4K) : AT(ADDR(.userspace) - KERNEL_OFFSET)
|
||||
{
|
||||
g_rodata_start = .;
|
||||
*(.rodata.*)
|
||||
g_rodata_end = .;
|
||||
g_userspace_start = .;
|
||||
*(.userspace)
|
||||
g_userspace_end = .;
|
||||
}
|
||||
.data BLOCK(4K) : ALIGN(4K)
|
||||
.rodata ALIGN(4K) : AT(ADDR(.rodata) - KERNEL_OFFSET)
|
||||
{
|
||||
*(.rodata.*)
|
||||
g_kernel_execute_end = .;
|
||||
}
|
||||
.data ALIGN(4K) : AT(ADDR(.data) - KERNEL_OFFSET)
|
||||
{
|
||||
*(.data)
|
||||
}
|
||||
.bss BLOCK(4K) : ALIGN(4K)
|
||||
.bss ALIGN(4K) : AT(ADDR(.bss) - KERNEL_OFFSET)
|
||||
{
|
||||
*(COMMON)
|
||||
*(.bss)
|
||||
}
|
||||
g_kernel_end = .;
|
||||
|
||||
. = 0x00A00000;
|
||||
|
||||
g_userspace_start = .;
|
||||
.userspace BLOCK(4K) : ALIGN(4K)
|
||||
{
|
||||
*(.userspace)
|
||||
}
|
||||
g_userspace_end = .;
|
||||
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
KERNEL_ARCH_CFLAGS=-mcmodel=large -mno-red-zone -mno-mmx
|
||||
KERNEL_ARCH_CPPFLAGS=
|
||||
KERNEL_ARCH_LDFLAGS=-z max-page-size=4096
|
||||
KERNEL_ARCH_LIBS=
|
||||
|
||||
ELF_FORMAT=elf64-x86-64
|
||||
|
||||
KERNEL_ARCH_OBJS= \
|
||||
$(ARCHDIR)/boot.o \
|
||||
$(ARCHDIR)/GDT.o \
|
||||
$(ARCHDIR)/IDT.o \
|
||||
$(ARCHDIR)/interrupts.o \
|
||||
$(ARCHDIR)/MMU.o \
|
||||
$(ARCHDIR)/SpinLock.o \
|
||||
$(ARCHDIR)/Thread.o \
|
||||
|
||||
@@ -104,7 +104,7 @@ void __cxa_finalize(void *f)
|
||||
**/
|
||||
(*__atexit_funcs[i].destructor_func)(__atexit_funcs[i].obj_ptr);
|
||||
__atexit_funcs[i].destructor_func = 0;
|
||||
|
||||
|
||||
/*
|
||||
* Notice that we didn't decrement __atexit_func_count: this is because this algorithm
|
||||
* requires patching to deal with the FIXME outlined above.
|
||||
@@ -113,8 +113,6 @@ void __cxa_finalize(void *f)
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
|
||||
namespace __cxxabiv1
|
||||
{
|
||||
/* guard variables */
|
||||
@@ -122,19 +120,19 @@ namespace __cxxabiv1
|
||||
|
||||
/* The ABI requires a 64-bit type. */
|
||||
__extension__ typedef int __guard __attribute__((mode(__DI__)));
|
||||
|
||||
|
||||
int __cxa_guard_acquire (__guard* g)
|
||||
{
|
||||
Kernel::LockGuard lock_guard(s_spin_lock);
|
||||
return !*(int*)g;
|
||||
}
|
||||
|
||||
|
||||
void __cxa_guard_release (__guard* g)
|
||||
{
|
||||
Kernel::LockGuard lock_guard(s_spin_lock);
|
||||
*(int*)g = 1;
|
||||
}
|
||||
|
||||
|
||||
void __cxa_guard_abort (__guard*)
|
||||
{
|
||||
Kernel::panic("__cxa_guard_abort");
|
||||
|
||||
144
kernel/include/kernel/ACPI.h
Normal file
144
kernel/include/kernel/ACPI.h
Normal file
@@ -0,0 +1,144 @@
|
||||
#pragma once
|
||||
|
||||
#include <BAN/Vector.h>
|
||||
#include <kernel/Memory/Types.h>
|
||||
|
||||
namespace Kernel
|
||||
{
|
||||
|
||||
class ACPI
|
||||
{
|
||||
public:
|
||||
struct GAS
|
||||
{
|
||||
uint8_t address_space_id;
|
||||
uint8_t register_bit_width;
|
||||
uint8_t register_bit_offset;
|
||||
uint8_t access_size;
|
||||
uint64_t address;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct SDTHeader
|
||||
{
|
||||
uint8_t signature[4];
|
||||
uint32_t length;
|
||||
uint8_t revision;
|
||||
uint8_t checksum;
|
||||
uint8_t oemid[6];
|
||||
uint64_t oem_table_id;
|
||||
uint32_t oem_revision;
|
||||
uint32_t creator_id;
|
||||
uint32_t creator_revision;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct FADT : public SDTHeader
|
||||
{
|
||||
uint32_t firmware_ctrl;
|
||||
uint32_t dsdt;
|
||||
uint8_t __reserved;
|
||||
uint8_t preferred_pm_profile;
|
||||
uint16_t sci_int;
|
||||
uint32_t smi_cmd;
|
||||
uint8_t acpi_enable;
|
||||
uint8_t acpi_disable;
|
||||
uint8_t s4bios_req;
|
||||
uint8_t pstate_cnt;
|
||||
uint32_t pm1a_evt_blk;
|
||||
uint32_t pm1b_evt_blk;
|
||||
uint32_t pm1a_cnt_blk;
|
||||
uint32_t pm1b_cnt_blk;
|
||||
uint32_t pm2_cnt_blk;
|
||||
uint32_t pm_tmr_blk;
|
||||
uint32_t gpe0_blk;
|
||||
uint32_t gpe1_blk;
|
||||
uint8_t pm1_evt_len;
|
||||
uint8_t pm1_cnt_len;
|
||||
uint8_t pm2_cnt_len;
|
||||
uint8_t pm_tmr_len;
|
||||
uint8_t gpe0_blk_len;
|
||||
uint8_t gpe1_blk_len;
|
||||
uint8_t gpe1_base;
|
||||
uint8_t cst_cnt;
|
||||
uint16_t p_lvl2_lat;
|
||||
uint16_t p_lvl3_lat;
|
||||
uint16_t flush_size;
|
||||
uint16_t flush_stride;
|
||||
uint8_t duty_offset;
|
||||
uint8_t duty_width;
|
||||
uint8_t day_alrm;
|
||||
uint8_t mon_alrm;
|
||||
uint8_t century;
|
||||
uint16_t iapc_boot_arch;
|
||||
uint8_t __reserved2;
|
||||
uint32_t flags;
|
||||
uint8_t reset_reg[12];
|
||||
uint8_t reset_value;
|
||||
uint16_t arm_boot_arch;
|
||||
uint8_t fadt_minor_version;
|
||||
uint64_t x_firmware_version;
|
||||
uint64_t x_dsdt;
|
||||
uint8_t x_pm1a_evt_blk[12];
|
||||
uint8_t x_pm1b_evt_blk[12];
|
||||
uint8_t x_pm1a_cnt_blk[12];
|
||||
uint8_t x_pm1b_cnt_blk[12];
|
||||
uint8_t x_pm2_cnt_blk[12];
|
||||
uint8_t x_pm_tmr_blk[12];
|
||||
uint8_t x_gpe0_blk[12];
|
||||
uint8_t x_gpe1_blk[12];
|
||||
uint8_t sleep_control_reg[12];
|
||||
uint8_t sleep_status_reg[12];
|
||||
uint64_t hypervison_vendor_identity;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct HPET : public SDTHeader
|
||||
{
|
||||
uint8_t hardware_rev_id;
|
||||
uint8_t comparator_count : 5;
|
||||
uint8_t count_size_cap : 1;
|
||||
uint8_t reserved : 1;
|
||||
uint8_t legacy_replacement_irq_routing_cable : 1;
|
||||
uint16_t pci_vendor_id;
|
||||
GAS base_address;
|
||||
uint8_t hpet_number;
|
||||
uint16_t main_counter_minimum_clock_tick;
|
||||
uint8_t page_protection_and_oem_attribute;
|
||||
} __attribute__((packed));
|
||||
|
||||
public:
|
||||
static BAN::ErrorOr<void> initialize();
|
||||
static ACPI& get();
|
||||
|
||||
const SDTHeader* get_header(BAN::StringView signature, uint32_t index);
|
||||
|
||||
private:
|
||||
ACPI() = default;
|
||||
BAN::ErrorOr<void> initialize_impl();
|
||||
|
||||
private:
|
||||
paddr_t m_header_table_paddr = 0;
|
||||
vaddr_t m_header_table_vaddr = 0;
|
||||
uint32_t m_entry_size = 0;
|
||||
|
||||
struct MappedPage
|
||||
{
|
||||
Kernel::paddr_t paddr;
|
||||
Kernel::vaddr_t vaddr;
|
||||
|
||||
SDTHeader* as_header() { return (SDTHeader*)vaddr; }
|
||||
};
|
||||
BAN::Vector<MappedPage> m_mapped_headers;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
namespace BAN::Formatter
|
||||
{
|
||||
template<typename F>
|
||||
void print_argument(F putc, const Kernel::ACPI::SDTHeader& header, const ValueFormat& format)
|
||||
{
|
||||
putc(header.signature[0]);
|
||||
putc(header.signature[1]);
|
||||
putc(header.signature[2]);
|
||||
putc(header.signature[3]);
|
||||
}
|
||||
}
|
||||
21
kernel/include/kernel/API/DirectoryEntry.h
Normal file
21
kernel/include/kernel/API/DirectoryEntry.h
Normal file
@@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
#include <dirent.h>
|
||||
|
||||
namespace Kernel::API
|
||||
{
|
||||
|
||||
struct DirectoryEntry
|
||||
{
|
||||
size_t rec_len { 0 };
|
||||
struct dirent dirent;
|
||||
DirectoryEntry* next() const { return (DirectoryEntry*)((uintptr_t)this + rec_len); }
|
||||
};
|
||||
|
||||
struct DirectoryEntryList
|
||||
{
|
||||
size_t entry_count { 0 };
|
||||
DirectoryEntry array[];
|
||||
};
|
||||
|
||||
}
|
||||
@@ -2,49 +2,58 @@
|
||||
|
||||
#include <BAN/Vector.h>
|
||||
#include <kernel/InterruptController.h>
|
||||
#include <kernel/Memory/Types.h>
|
||||
|
||||
class APIC final : public InterruptController
|
||||
namespace Kernel
|
||||
{
|
||||
public:
|
||||
virtual void eoi(uint8_t) override;
|
||||
virtual void enable_irq(uint8_t) override;
|
||||
virtual bool is_in_service(uint8_t) override;
|
||||
|
||||
private:
|
||||
uint32_t read_from_local_apic(ptrdiff_t);
|
||||
void write_to_local_apic(ptrdiff_t, uint32_t);
|
||||
|
||||
private:
|
||||
static APIC* create();
|
||||
friend class InterruptController;
|
||||
|
||||
private:
|
||||
struct Processor
|
||||
class APIC final : public InterruptController
|
||||
{
|
||||
enum Flags : uint8_t
|
||||
public:
|
||||
virtual void eoi(uint8_t) override;
|
||||
virtual void enable_irq(uint8_t) override;
|
||||
virtual bool is_in_service(uint8_t) override;
|
||||
|
||||
private:
|
||||
uint32_t read_from_local_apic(ptrdiff_t);
|
||||
void write_to_local_apic(ptrdiff_t, uint32_t);
|
||||
|
||||
private:
|
||||
~APIC() { ASSERT_NOT_REACHED(); }
|
||||
static APIC* create();
|
||||
friend class InterruptController;
|
||||
|
||||
private:
|
||||
struct Processor
|
||||
{
|
||||
Enabled = 1,
|
||||
OnlineCapable = 2,
|
||||
enum Flags : uint8_t
|
||||
{
|
||||
Enabled = 1,
|
||||
OnlineCapable = 2,
|
||||
};
|
||||
uint8_t processor_id;
|
||||
uint8_t apic_id;
|
||||
uint8_t flags;
|
||||
};
|
||||
uint8_t processor_id;
|
||||
uint8_t apic_id;
|
||||
uint8_t flags;
|
||||
|
||||
struct IOAPIC
|
||||
{
|
||||
uint8_t id;
|
||||
Kernel::paddr_t paddr;
|
||||
Kernel::vaddr_t vaddr;
|
||||
uint32_t gsi_base;
|
||||
uint8_t max_redirs;
|
||||
|
||||
uint32_t read(uint8_t offset);
|
||||
void write(uint8_t offset, uint32_t data);
|
||||
};
|
||||
|
||||
private:
|
||||
BAN::Vector<Processor> m_processors;
|
||||
Kernel::paddr_t m_local_apic_paddr = 0;
|
||||
Kernel::vaddr_t m_local_apic_vaddr = 0;
|
||||
BAN::Vector<IOAPIC> m_io_apics;
|
||||
uint8_t m_irq_overrides[0x100] {};
|
||||
};
|
||||
|
||||
struct IOAPIC
|
||||
{
|
||||
uint8_t id;
|
||||
uintptr_t address;
|
||||
uint32_t gsi_base;
|
||||
uint8_t max_redirs;
|
||||
|
||||
uint32_t read(uint8_t offset);
|
||||
void write(uint8_t offset, uint32_t data);
|
||||
};
|
||||
|
||||
private:
|
||||
BAN::Vector<Processor> m_processors;
|
||||
uintptr_t m_local_apic = 0;
|
||||
BAN::Vector<IOAPIC> m_io_apics;
|
||||
uint8_t m_irq_overrides[0x100] {};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -17,4 +17,12 @@
|
||||
#define read_rsp(rsp) asm volatile("movl %%esp, %0" : "=r"(rsp))
|
||||
#define push_callee_saved() asm volatile("pushal")
|
||||
#define pop_callee_saved() asm volatile("popal")
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" uintptr_t read_rip();
|
||||
#else
|
||||
extern uintptr_t read_rip();
|
||||
#endif
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#pragma once
|
||||
|
||||
#define ALWAYS_INLINE inline __attribute__((always_inline))
|
||||
#define ALWAYS_INLINE inline __attribute__((always_inline))
|
||||
#define NEVER_INLINE __attribute__((noinline))
|
||||
|
||||
@@ -73,9 +73,10 @@ namespace CPUID
|
||||
|
||||
const char* feature_string_ecx(uint32_t feat);
|
||||
const char* feature_string_edx(uint32_t feat);
|
||||
|
||||
|
||||
const char* get_vendor();
|
||||
void get_features(uint32_t& ecx, uint32_t& edx);
|
||||
bool is_64_bit();
|
||||
bool has_nxe();
|
||||
|
||||
}
|
||||
50
kernel/include/kernel/Credentials.h
Normal file
50
kernel/include/kernel/Credentials.h
Normal file
@@ -0,0 +1,50 @@
|
||||
#pragma once
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
namespace Kernel
|
||||
{
|
||||
|
||||
class Credentials
|
||||
{
|
||||
public:
|
||||
Credentials(uid_t ruid, uid_t euid, gid_t rgid, gid_t egid)
|
||||
: m_ruid(ruid), m_euid(euid), m_suid(0)
|
||||
, m_rgid(rgid), m_egid(egid), m_sgid(0)
|
||||
{ }
|
||||
|
||||
uid_t ruid() const { return m_ruid; }
|
||||
uid_t euid() const { return m_euid; }
|
||||
uid_t suid() const { return m_suid; }
|
||||
|
||||
gid_t rgid() const { return m_rgid; }
|
||||
gid_t egid() const { return m_egid; }
|
||||
gid_t sgid() const { return m_sgid; }
|
||||
|
||||
void set_ruid(uid_t uid) { m_ruid = uid; }
|
||||
void set_euid(uid_t uid) { m_euid = uid; }
|
||||
void set_suid(uid_t uid) { m_suid = uid; }
|
||||
|
||||
void set_rgid(gid_t gid) { m_rgid = gid; }
|
||||
void set_egid(gid_t gid) { m_egid = gid; }
|
||||
void set_sgid(gid_t gid) { m_sgid = gid; }
|
||||
|
||||
bool is_superuser() const { return m_euid == 0; }
|
||||
|
||||
private:
|
||||
uid_t m_ruid, m_euid, m_suid;
|
||||
gid_t m_rgid, m_egid, m_sgid;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
namespace BAN::Formatter
|
||||
{
|
||||
|
||||
template<typename F>
|
||||
void print_argument(F putc, const Kernel::Credentials& credentials, const ValueFormat&)
|
||||
{
|
||||
print(putc, "(ruid {}, euid {})", credentials.ruid(), credentials.euid());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -11,7 +11,7 @@ namespace Kernel
|
||||
{
|
||||
BAN_NON_COPYABLE(CriticalScope);
|
||||
BAN_NON_MOVABLE(CriticalScope);
|
||||
|
||||
|
||||
public:
|
||||
CriticalScope()
|
||||
{
|
||||
|
||||
@@ -1,27 +1,50 @@
|
||||
#pragma once
|
||||
|
||||
#include <BAN/Formatter.h>
|
||||
#include <kernel/PIT.h>
|
||||
|
||||
#define dprintln(...) \
|
||||
do { \
|
||||
BAN::Formatter::print(Debug::putchar, "[{5}.{3}] {}:{}: ", PIT::ms_since_boot() / 1000, PIT::ms_since_boot() % 1000, __FILE__, __LINE__); \
|
||||
BAN::Formatter::print(Debug::putchar, __VA_ARGS__); \
|
||||
BAN::Formatter::print(Debug::putchar, "\r\n"); \
|
||||
#define dprintln(...) \
|
||||
do { \
|
||||
Debug::DebugLock::lock(); \
|
||||
Debug::print_prefix(__FILE__, __LINE__); \
|
||||
BAN::Formatter::print(Debug::putchar, __VA_ARGS__); \
|
||||
BAN::Formatter::print(Debug::putchar, "\r\n"); \
|
||||
Debug::DebugLock::unlock(); \
|
||||
} while(false)
|
||||
|
||||
#define dwarnln(...) \
|
||||
do { \
|
||||
#define dwarnln(...) \
|
||||
do { \
|
||||
Debug::DebugLock::lock(); \
|
||||
BAN::Formatter::print(Debug::putchar, "\e[33m"); \
|
||||
dprintln(__VA_ARGS__); \
|
||||
dprintln(__VA_ARGS__); \
|
||||
BAN::Formatter::print(Debug::putchar, "\e[m"); \
|
||||
Debug::DebugLock::unlock(); \
|
||||
} while(false)
|
||||
|
||||
#define derrorln(...) \
|
||||
do { \
|
||||
#define derrorln(...) \
|
||||
do { \
|
||||
Debug::DebugLock::lock(); \
|
||||
BAN::Formatter::print(Debug::putchar, "\e[31m"); \
|
||||
dprintln(__VA_ARGS__); \
|
||||
dprintln(__VA_ARGS__); \
|
||||
BAN::Formatter::print(Debug::putchar, "\e[m"); \
|
||||
Debug::DebugLock::unlock(); \
|
||||
} 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)
|
||||
|
||||
#define BOCHS_BREAK() asm volatile("xchgw %bx, %bx")
|
||||
@@ -30,4 +53,12 @@ namespace Debug
|
||||
{
|
||||
void dump_stack_trace();
|
||||
void putchar(char);
|
||||
void print_prefix(const char*, int);
|
||||
|
||||
class DebugLock
|
||||
{
|
||||
public:
|
||||
static void lock();
|
||||
static void unlock();
|
||||
};
|
||||
}
|
||||
46
kernel/include/kernel/Device/Device.h
Normal file
46
kernel/include/kernel/Device/Device.h
Normal file
@@ -0,0 +1,46 @@
|
||||
#pragma once
|
||||
|
||||
#include <kernel/FS/RamFS/Inode.h>
|
||||
|
||||
namespace Kernel
|
||||
{
|
||||
|
||||
class Device : public RamInode
|
||||
{
|
||||
public:
|
||||
virtual ~Device() = default;
|
||||
virtual void update() {}
|
||||
|
||||
virtual bool is_device() const override { return true; }
|
||||
virtual bool is_partition() const { return false; }
|
||||
virtual bool is_storage_device() const { return false; }
|
||||
|
||||
virtual dev_t rdev() const override = 0;
|
||||
|
||||
virtual BAN::StringView name() const = 0;
|
||||
|
||||
protected:
|
||||
Device(mode_t, uid_t, gid_t);
|
||||
};
|
||||
|
||||
class BlockDevice : public Device
|
||||
{
|
||||
protected:
|
||||
BlockDevice(mode_t mode, uid_t uid, gid_t gid)
|
||||
: Device(mode, uid, gid)
|
||||
{
|
||||
m_inode_info.mode |= Inode::Mode::IFBLK;
|
||||
}
|
||||
};
|
||||
|
||||
class CharacterDevice : public Device
|
||||
{
|
||||
protected:
|
||||
CharacterDevice(mode_t mode, uid_t uid, gid_t gid)
|
||||
: Device(mode, uid, gid)
|
||||
{
|
||||
m_inode_info.mode |= Inode::Mode::IFCHR;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
30
kernel/include/kernel/Device/NullDevice.h
Normal file
30
kernel/include/kernel/Device/NullDevice.h
Normal file
@@ -0,0 +1,30 @@
|
||||
#pragma once
|
||||
|
||||
#include <kernel/Device/Device.h>
|
||||
|
||||
namespace Kernel
|
||||
{
|
||||
|
||||
class NullDevice : public CharacterDevice
|
||||
{
|
||||
public:
|
||||
static BAN::ErrorOr<BAN::RefPtr<NullDevice>> create(mode_t, uid_t, gid_t);
|
||||
|
||||
virtual dev_t rdev() const override { return m_rdev; }
|
||||
|
||||
virtual BAN::StringView name() const override { return "null"sv; }
|
||||
|
||||
protected:
|
||||
NullDevice(mode_t mode, uid_t uid, gid_t gid, dev_t rdev)
|
||||
: CharacterDevice(mode, uid, gid)
|
||||
, m_rdev(rdev)
|
||||
{ }
|
||||
|
||||
virtual BAN::ErrorOr<size_t> read_impl(off_t, BAN::ByteSpan) override { return 0; }
|
||||
virtual BAN::ErrorOr<size_t> write_impl(off_t, BAN::ConstByteSpan buffer) override { return buffer.size(); };
|
||||
|
||||
private:
|
||||
const dev_t m_rdev;
|
||||
};
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user