Compare commits
1923 Commits
99e30a4d7d
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f527aca9d0 | ||
|
|
5fce3b64cc | ||
| c04ad65f7f | |||
| af17b29414 | |||
| 7badcf80cf | |||
| 7f122d9e89 | |||
| 984c7c0a89 | |||
| ce318c7930 | |||
| eff6c79e9e | |||
| aaade52146 | |||
| 1bf5e6a051 | |||
| 394719a909 | |||
| 3ebadc5c74 | |||
| d471bbf856 | |||
| c849293f3d | |||
| 0156d06cdc | |||
| ad12bf3e1d | |||
| 42964ad0b4 | |||
| 87979b1627 | |||
| fed9dbefdf | |||
| 2984927be5 | |||
| 2e654b53fa | |||
| ac6e6f3ec1 | |||
| 2b97587e9f | |||
| 4bde088b28 | |||
| 2a9dad2dd8 | |||
| d11160d2f7 | |||
| 7333008f40 | |||
| cd7d309fd1 | |||
| a4ba1da65a | |||
| 2f9b8b6fc9 | |||
| 279ac6b2b6 | |||
| 9084d9305c | |||
| 80c4213501 | |||
| e0af23a924 | |||
| 7e907b70f6 | |||
| 7fb27b16e8 | |||
| 3fb903d991 | |||
| 2a4a688c2d | |||
| 1487c86262 | |||
| 4d3751028b | |||
| e4c6539964 | |||
| 34b59f062b | |||
| ec4aa8d0b6 | |||
| 1eebe85071 | |||
| db0507e670 | |||
| 1e3ca7dc18 | |||
| 8ca3c5d778 | |||
| df257755f7 | |||
| d7e292a9f8 | |||
| 9fce114e8e | |||
| 9d83424346 | |||
| a29681a524 | |||
| 47d85eb281 | |||
| 85f676c30a | |||
| 8c5fa1c0b8 | |||
| c7690053ae | |||
| 3f55be638d | |||
| 664c824bc0 | |||
| e239d9ca55 | |||
| bf1d9662d7 | |||
| 675c215e6a | |||
| c09bca56f9 | |||
| 7d8f7753d5 | |||
| f77aa65dc5 | |||
| 9589b5984d | |||
| 32806a5af3 | |||
| 876fbe3d7c | |||
| c1b8f5e475 | |||
| cf31ea9cbe | |||
| 7e6b8c93b4 | |||
| dd2bbe4588 | |||
| e01e35713b | |||
| 82d5d9ba58 | |||
| d168492462 | |||
| 6f2e8320a9 | |||
| bf4831f468 | |||
| 5647cf24d2 | |||
| 85f61aded5 | |||
| 21639071c2 | |||
| 68506a789a | |||
| d9ca25b796 | |||
| e9c81477d7 | |||
| 5c20d5e291 | |||
| f89d690716 | |||
| c563efcd1c | |||
| dedeebbfbe | |||
| 35e2a70de0 | |||
| 81d5c86a7a | |||
| db6644bae9 | |||
| 14f1c1a358 | |||
| 5be9bc64a2 | |||
| 64d3a5c8b7 | |||
| ccb4d13a82 | |||
| cbe835a2c8 | |||
| 6a77754adf | |||
| 7d7d5ba734 | |||
| 684fa1c4b0 | |||
| a98d851fde | |||
| 9c3e2dab40 | |||
| eddb68f2fa | |||
| 791091174a | |||
| dd9280c6ea | |||
| a4d83f9fdb | |||
| f42c5c4a5b | |||
| 186fa4f1a1 | |||
| 09292bb87e | |||
| d18a0de879 | |||
| cdc45935b5 | |||
| 43e18148a6 | |||
| b0db645248 | |||
| 07712758a7 | |||
| c1a424a635 | |||
| a49588dbc7 | |||
| 1f22b9b982 | |||
| 1d07d8e08e | |||
| 05b2424fca | |||
| 07201c711e | |||
| 8fac88c9a6 | |||
| c9aafa78ec | |||
| e1c337a483 | |||
| acebe68dfa | |||
| eeef945c25 | |||
| a602753bda | |||
| 812ae77cd7 | |||
| 8b8af1a9d9 | |||
| 493b5cb9b1 | |||
| 1ecd7cc2fe | |||
| 5c38832456 | |||
| d16f07a547 | |||
| 54acb05131 | |||
| 9ddf19f605 | |||
| ff378e4538 | |||
| 2ea0a24795 | |||
| acf28d8170 | |||
| 666a7bb826 | |||
| 1ac20251cf | |||
| a318a19fe2 | |||
| f4a7aec167 | |||
| 9445332499 | |||
| 8edd63d115 | |||
| 304ace1172 | |||
| a5cdf0640f | |||
| 1fc2e43881 | |||
| 0964c9f928 | |||
| 8b1e820869 | |||
| 9edc6966db | |||
| 12207dcb77 | |||
| 2255e36810 | |||
| 5abddd448e | |||
| f022a1b08f | |||
| b3bbfaeff0 | |||
| 679a3d4209 | |||
| a0211d88e7 | |||
| e216fc7798 | |||
| c648ea12f2 | |||
| 2e59373a1e | |||
| a51a81b6cd | |||
| 9809f87010 | |||
| 8794122c2d | |||
| 8fb2270ecf | |||
| c304133224 | |||
| 7843d3de62 | |||
| aef536fff3 | |||
| d472e1ac0e | |||
| 120c08fb75 | |||
| ba6229b92d | |||
| 3d2362cb5f | |||
| a08b9b82a6 | |||
| 5d62fa3f10 | |||
| d3df00f0ba | |||
| 34e84f8b07 | |||
| 1143dc3cae | |||
| 0299d4d44e | |||
| 1d07151743 | |||
| a83fa6f4c6 | |||
| c30fc9d60f | |||
| 311a68160c | |||
| 343aef31c3 | |||
| 3ac8f7e14f | |||
| 0cef66d155 | |||
| 9ffbb9fbf0 | |||
| c9a8f5b456 | |||
| 4e3831e380 | |||
| cae2b3bd14 | |||
| 5637b8602b | |||
| 4af9699b22 | |||
| 35c97e2ff8 | |||
| 83e5cb81e8 | |||
| 7a49a0d986 | |||
| 78cd054d59 | |||
| d33a8eac9c | |||
| 9355ab1656 | |||
| 1f87bfbf2e | |||
| e06429da87 | |||
| 26058763df | |||
| 1f03d23dae | |||
| 2eea074473 | |||
| ed82a18e2a | |||
| 2961a49dc7 | |||
| 5c9151d3e9 | |||
| 90deb9fb43 | |||
| 12489a4c6b | |||
| 74f70ae4bd | |||
| a9ceab0415 | |||
| 94bd74d0bb | |||
| b2d8199480 | |||
| e60f3711f8 | |||
| 6ec9e4f7b8 | |||
| 9eb3834ae5 | |||
| ee57cf3e9a | |||
| fea5d1d82b | |||
| c84a30d4dd | |||
| 24d91eee90 | |||
| a5318448f5 | |||
| b7c40eeb57 | |||
| e7c9be1875 | |||
| 8f1b314802 | |||
| da6794c8ce | |||
| e926beba5a | |||
| 3ad053cf6d | |||
| bc11469a0b | |||
| a00695bdac | |||
| 89959b800c | |||
| 3e19c3b62e | |||
| d970debb4d | |||
| d0ba52073f | |||
| 943e3b6f51 | |||
| 25d43682aa | |||
| ad16de59f8 | |||
| 8634bbb792 | |||
| 60ec5d30fd | |||
| 7667fe6ca5 | |||
| 4b5a8196c3 | |||
| 706c0816dd | |||
| a8aa89362d | |||
| 7964698ae5 | |||
| 65664b0d65 | |||
| 08bfa0971e | |||
| 912c5ea0bf | |||
| 6cdf5a5a7f | |||
| 50ba743faf | |||
| e26aac3067 | |||
| 941e8aa5d5 | |||
| 33b6536e6b | |||
| 9fbd9288b2 | |||
| bef1a56007 | |||
| bc71ff5e81 | |||
| bd50444d06 | |||
| 2efd6f92b2 | |||
| 7fdfad4088 | |||
| 31a1968798 | |||
| b0bd4ad546 | |||
| dc454b9a6a | |||
| f06e5d33e7 | |||
| efdbd1576f | |||
| 0421fbdc25 | |||
| bd426199f8 | |||
| 8e00b3d110 | |||
| 6fbf1469aa | |||
| 280d3fd919 | |||
| 40ce95b87f | |||
| e7d644b874 | |||
| c64159d5c3 | |||
| e2ccc3026f | |||
| 2af6066ee3 | |||
| fc16b5331c | |||
| b2723a0c5f | |||
| 01042a24f0 | |||
| f9643b3881 | |||
| d2d18bea5d | |||
| 87e595b83e | |||
| 08031b1227 | |||
| 9a87c1f734 | |||
| edeb667ead | |||
| db2aa495b8 | |||
| ddfb591094 | |||
| e8f1ba3722 | |||
| 19c4f34ccb | |||
| 5d9e9c021a | |||
| 6a924db68c | |||
| 9d0990e5e8 | |||
| 3207f5d61f | |||
| c72b351bba | |||
| 1f9b296ae7 | |||
| e3e2e7b4df | |||
| 4ec8f4a4bf | |||
| 05d59a05df | |||
| 11ccbe6506 | |||
| 673711a246 | |||
| fff5139d80 | |||
| 812e70c626 | |||
| db7ffcf9d5 | |||
| 8f6cb9c057 | |||
| 291f298d19 | |||
| d60f12d3b8 | |||
| b8a2573bb4 | |||
| 7ce8e610f5 | |||
| 839b9c8f07 | |||
| db20801521 | |||
| 160a9278c9 | |||
| ee507de154 | |||
| dc0fa49de2 | |||
| b678541427 | |||
| 6c4cd0d8cb | |||
| c096d3cd42 | |||
| dcdab4df21 | |||
| 9803209ba1 | |||
| f166cb09ec | |||
| 2dd8b76289 | |||
| 2bf7c67767 | |||
| dd636ffcb2 | |||
| a44c45ff9e | |||
| dc2a455395 | |||
| c700d9f714 | |||
| 59cfc339b0 | |||
| e06c07ca89 | |||
| 6facd54a7e | |||
| 6f8d850726 | |||
| f3beee9874 | |||
| 35e063bdaf | |||
| 09175d1799 | |||
| 46f9a9053f | |||
| bb86520094 | |||
| c1e2c660bf | |||
| 89c0ff1a9d | |||
| 7a68ce7e94 | |||
| 9537922acc | |||
| a39aa73e21 | |||
| f1d12c330e | |||
| 82c8eeb4be | |||
| 3a951f4830 | |||
| 998ea25fb9 | |||
| 7b580b8f56 | |||
| 641ccfdd47 | |||
| 4288f70d04 | |||
| 95fda5dfb7 | |||
| 1903c5e0c6 | |||
| 362501a097 | |||
| 72982e3c2b | |||
| 04d24bce70 | |||
| 2f38306c6b | |||
| 4b36e5197d | |||
| b755cf3e42 | |||
| 3acad7c911 | |||
| f3319016c4 | |||
| 4e14f7d483 | |||
| 979059c804 | |||
| bdf4423512 | |||
| c6ef4b5840 | |||
| acd792d8b4 | |||
| fc730679ed | |||
| 00e5749e20 | |||
| 7b4d349574 | |||
| dc0cccfb6c | |||
| fdc1daefb6 | |||
| c9159b81c8 | |||
| 9233049356 | |||
| bd9015e474 | |||
| 3a79540d2d | |||
| 9e500dc387 | |||
| e05a735589 | |||
| 0be18c4a53 | |||
| e258fde25a | |||
| 7367672570 | |||
| b822d42889 | |||
| 10084ff1bb | |||
| c3c69ac727 | |||
| 0cfda6f6a7 | |||
| dc51ce9e92 | |||
| aa0de2b00e | |||
| 5f61581e1d | |||
| f519cb2cc0 | |||
| 37aef630d2 | |||
| d93fcff5db | |||
| 4952a82af5 | |||
| fecda6a034 | |||
| 9f0addbd8b | |||
| 7f8ea6b8e0 | |||
| 9d3ea6fed7 | |||
| 703b3eda56 | |||
| 84006e1e77 | |||
| 73fb085a41 | |||
| c89780178f | |||
| 2ac3976924 | |||
| ac9dbd24e4 | |||
| 3af9830a2e | |||
| da6b8eb2ab | |||
| da39e98adf | |||
| 791a541381 | |||
| 56684e753b | |||
| c7298edf65 | |||
| 30215963b2 | |||
| f15f88ebd6 | |||
| 391fc0c4c2 | |||
| 948ef2c820 | |||
| c1b6b6b76a | |||
| a8bb07052e | |||
| 6976a2dae7 | |||
| 51cd951b4c | |||
| 16a5a234c1 | |||
| f994210927 | |||
| aaa8760d09 | |||
| cea19ecc31 | |||
| 706cfeb443 | |||
| d9c91589f0 | |||
| 9854691265 | |||
| 32afa33a06 | |||
| c6946d0145 | |||
| abbe7b79d6 | |||
| e4abe75043 | |||
| b904503691 | |||
| 2db42dfb2e | |||
| 10bd24e585 | |||
| f926e599fa | |||
| e7b518ba67 | |||
| a4698f0bde | |||
| 9a6eae69ba | |||
| 0ff365c7f0 | |||
| 214e7a5672 | |||
| 24b69a6dea | |||
| 699235147c | |||
| 72ad413a61 | |||
| f11bb082e4 | |||
| 2f3fd6867d | |||
| 350ae90bb6 | |||
| fb61cab70d | |||
| 1d6c08478d | |||
| 0dfe0b7023 | |||
| def236b7cd | |||
| 247743ef9c | |||
| 49122cf729 | |||
| 84f579be81 | |||
| 3d5f23a1b2 | |||
| 8b26b6604d | |||
| f88e55ffa8 | |||
| 34bdcb12e5 | |||
| 95b353dae5 | |||
| 6560f229b1 | |||
| 8c9ab2d68c | |||
| 8496726ab1 | |||
| 32d7f429f8 | |||
| 0f52f49188 | |||
| b334259a07 | |||
| 74af4e9150 | |||
| 8b7790ded2 | |||
| 3e97a82af0 | |||
| 0066b20413 | |||
| 9d6656451a | |||
| 32f980e259 | |||
| ca9361abc1 | |||
| 36cb3d56fe | |||
| 0bece8a54c | |||
| 70bbdbd8f5 | |||
| df8365f0c7 | |||
| 974aae2ebe | |||
| ceca93c8b1 | |||
| b6793cc6f2 | |||
| 809d07546a | |||
| 804cbeb1a7 | |||
| c07188a60e | |||
| 3804d4332b | |||
| 064aaef6c3 | |||
| ce262a5d2d | |||
| d128f4d70b | |||
| 46d1ada708 | |||
| 2819e5f647 | |||
| c2017a5181 | |||
| 58ad839136 | |||
| 8ed5a71c45 | |||
| 57050a83ba | |||
| 6ed0e84421 | |||
| 9b09d2b47a | |||
| 1a6c5deb4b | |||
| 45a73b00de | |||
| 59fff26a5f | |||
| fde4d4662e | |||
| c9355ad94a | |||
| bad3b8b3e2 | |||
| 0b81bb9b10 | |||
| f61c78efd5 | |||
| 6b2307ab22 | |||
| 9ccb381c31 | |||
| 71133236f8 | |||
| e5786fe435 | |||
| ef6ee78fd1 | |||
| 695262624d | |||
| c96c264801 | |||
| af0bca74e4 | |||
| f41e254e35 | |||
| 7e472a9c1d | |||
| ee3f10313a | |||
| 5b587d199e | |||
| 009b073892 | |||
| 92e962430b | |||
| 3aa20a3a32 | |||
| de7c3d3d29 | |||
| 3f89df338e | |||
| c7f89c9b77 | |||
| a107e463e8 | |||
| 7a5cfe1728 | |||
| 7ad3f967db | |||
| d1c814cf9d | |||
| 72f85dce2b | |||
| f5bbcc017c | |||
| 2980173c8e | |||
| a84c348045 | |||
| d845ecc811 | |||
| 064d9009a2 | |||
| b6aa5bdfab | |||
| a3bdf0456e | |||
| e3ecf05866 | |||
| 6240374dd1 | |||
| e17ee831a7 | |||
| aef9bd6357 | |||
| 8857227a35 | |||
| 937250c681 | |||
| 66d3a1d025 | |||
| 647fedfa19 | |||
| c593d3ed75 | |||
| bd885a01e5 | |||
| 628825fdff | |||
| 46dd411273 | |||
| 2e2ee11452 | |||
| ce0df333b3 | |||
| 8bbda78272 | |||
| 945509fc93 | |||
| b586917930 | |||
| 45ad6082bc | |||
| f27823babe | |||
| 95cfac471a | |||
| f7c1084c3e | |||
| cf96bb6cc3 | |||
| f1369c8fd6 | |||
| eb7922ab88 | |||
| dfdfb7cdaf | |||
| 1cc0fb9c01 | |||
| a51b589bc9 | |||
| 5940e912b3 | |||
| 658a001d91 | |||
| 57c9f5a8a8 | |||
| fa7b58057c | |||
| 0e0f5295cf | |||
| 284c9e5f61 | |||
| 927fbda1e8 | |||
| d25a5034db | |||
| f197d39aaf | |||
| 4a95343936 | |||
| 4e705a91af | |||
| 82b351469b | |||
| ea91bdcce7 | |||
| 256c9daefd | |||
| af0a46e79c | |||
| 4519c48284 | |||
| 8ea32c7650 | |||
| 5972d40ced | |||
| f35a6b3922 | |||
| 21009c37b4 | |||
| 11a2d15003 | |||
| d8a695a88d | |||
| f82390424b | |||
| 08ed405a5b | |||
| 8c598a6902 | |||
| 8e9c40caa4 | |||
| 8c29036fbf | |||
| b46337d376 | |||
| 56d701492b | |||
| 07e4e764a0 | |||
| 66fe2f2e50 | |||
| fda0ced72e | |||
| 654e8bb7f6 | |||
| 80ffde5e1e | |||
| 52309e0754 | |||
| 31e411f8f1 | |||
| de45b760b5 | |||
| ff29e9c4d6 | |||
| cc04bd0f06 | |||
| e72e1e4e43 | |||
| 987cc3c237 | |||
| 935f69e011 | |||
| 9f0c2fb6e2 | |||
| 9b18bda9c8 | |||
| 7831c74e8c | |||
| c1978f9133 | |||
| 05affda20c | |||
| e2eb555ca0 | |||
| 418c3c9cfa | |||
| bc66e181a5 | |||
| 6971f76bd3 | |||
| 1e65f02ff7 | |||
| 4efaf65d3f | |||
| aa0249fadb | |||
| 2c65590134 | |||
| a0d1a9ad67 | |||
| 5df6270e32 | |||
| 7af6e1cd34 | |||
| cceb066284 | |||
| 7a054787ca | |||
| d27891c79f | |||
| 5874fd640e | |||
| 11ae220dbe | |||
| 22542a3a71 | |||
| e16fb6a8e9 | |||
| d941e6d70b | |||
| b65068dc7d | |||
| d5301508ec | |||
| 793cca423b | |||
| 3960687f9d | |||
| 3ec7aad432 | |||
| 84f1ad4f26 | |||
| 6b9dbf625d | |||
| 3aea2c007d | |||
| 85d195212a | |||
| 8a663cb94f | |||
| 674e194a91 | |||
| c57f0abb56 | |||
| 163fdcd582 | |||
| 3be17c6117 | |||
| 995dfa1455 | |||
| 544c8dbc13 | |||
| 8da4f80453 | |||
| 6084aae603 | |||
| e1319a06f2 | |||
| 51fd7a607d | |||
| 8aff315c7b | |||
| 8e0d79f301 | |||
| 8a0269d29e | |||
| 892e16dfb1 | |||
| 92e4078287 | |||
| 41e1819072 | |||
| fb7e9719a1 | |||
| c2d09b64ca | |||
| 1b2aa6c2da | |||
| a5b4cee298 | |||
| 17f1ac10e3 | |||
| c67198032f | |||
| 107b092982 | |||
| bac06e45a4 | |||
| 0e8a68831c | |||
| 5912abd541 | |||
| 13d33995cb | |||
| c8c05f62b4 | |||
| 944b045885 | |||
| 19897ffa26 | |||
| 42a10b21c7 | |||
| 5df0e25c1f | |||
| ebf2b16d09 | |||
| f2eaab6e43 | |||
| a847823411 | |||
| fe9a8b542a | |||
| cd101b6844 | |||
| 69229102c4 | |||
| 4bc3630d19 | |||
| ab00686ac9 | |||
| c3004a038f | |||
| 9cf9d8847b | |||
| 0a3c10566b | |||
| c94243e107 | |||
| 505388b9fa | |||
| 7314cf708c | |||
| 3e6a4f2b16 | |||
| c7c3dd7662 | |||
| e4f025edd6 | |||
| 96f3efbf86 | |||
| 2b2130ff42 | |||
| 463ce05da0 | |||
| fa4095ba95 | |||
| db571b4859 | |||
| e8491b34b8 | |||
| 521457eb92 | |||
| f26a445ce6 | |||
| f73bb242f3 | |||
| 9e895e5286 | |||
| 5b0e5512a8 | |||
| 850b3284ac | |||
| 05a727979a | |||
| d68c88c3f9 | |||
| 5f07d53034 | |||
| fe62ce4bae | |||
| fb09aa4d06 | |||
| 4d080b30ab | |||
| 2d314e72fe | |||
| cf07b747fe | |||
| 273e9bbc92 | |||
| 7dcf1797e9 | |||
| 7aa24b6157 | |||
| d73a667437 | |||
| 4695fa061d | |||
| 7bf7bfbe13 | |||
| 397219c22e | |||
| 83c0ef3514 | |||
| 4fa40de557 | |||
| bc06926702 | |||
| 9de27110e2 | |||
| 93e5d09a63 | |||
| 0cbc39698c | |||
| 83069e433f | |||
| bbb490b24f | |||
| 85f200bd86 | |||
| 0f2c02fb04 | |||
| 6d3d41abe2 | |||
| 6fa7fe26dc | |||
| fe804c123d | |||
| dba32fb95d | |||
| 7dc187fdb1 | |||
| ee5a627952 | |||
| 3b83561309 | |||
| 6fb0b5203a | |||
| 4677d7a1c6 | |||
| 3283359ac8 | |||
| fff16f6b8c | |||
| a347ceba74 | |||
| 05836fab4c | |||
| 15e84f28ed | |||
| 32c35a822b | |||
| 9c86e5e54d | |||
| 87f348b48e | |||
| ff289b25b6 | |||
| a9f58e96d2 | |||
| c61ded8a1e | |||
| 7651ca747d | |||
| 7ff7a4aa87 | |||
| cdcd226b1a | |||
| f9451915b9 | |||
| 5e4e174d61 | |||
| 4a00cb7d55 | |||
| b97c123764 | |||
| 69bdff6b7e | |||
| 8574fcf6e1 | |||
| f4f424bf04 | |||
| ac745bfa3d | |||
| aa691f236e | |||
| a0a9d49d81 | |||
| 125f8b591d | |||
| c97b60e7e5 | |||
| 8a73414e3e | |||
| ac22e006a4 | |||
| 30d5d85d1d | |||
| 6f74f3c386 | |||
| 515918329c | |||
| 8ea0a67280 | |||
| 5ad7d7edb1 | |||
| 00c6820825 | |||
| 6beaafcf11 | |||
| e92f039a17 | |||
| ef76ffa1c1 | |||
| 652eb2346c | |||
| 66726090ec | |||
| b668173cba | |||
| a7e20d6e85 | |||
| c6ded82406 | |||
| a76c6faffc | |||
| 81ff71a97f | |||
| 56db0efe58 | |||
| 5eefd98e1b | |||
| eecdad50a6 | |||
| 96d5ed9cc7 | |||
| 73090ecb37 | |||
| 8812704601 | |||
| 0f189d410e | |||
| cfeabc4580 | |||
| 49f203d61d | |||
| a912a4dc67 | |||
| f79db874bf | |||
| 8de19aff3c | |||
| bf41b448d6 | |||
| 448632cf11 | |||
| 11174bfa14 | |||
| 84b1f3990c | |||
| 943069b2a3 | |||
| e305698e6b | |||
| 4c0b7d44b4 | |||
| 775c77c0fa | |||
| fb466b5af7 | |||
| e473118ec8 | |||
| 755d41ca4e | |||
| bbff9f89b0 | |||
| fdcb38ac1f | |||
| fac742c038 | |||
| 5a6b43fc90 | |||
| 317f413746 | |||
| 895909b7fa | |||
| 2ee8b6c8b4 | |||
| 022bb69782 | |||
| be6da3e0db | |||
| 1f07e02298 | |||
| 7a645b8555 | |||
| c5b0d0235f | |||
| b7948551ff | |||
| e109b5cff6 | |||
| 9883fb7bf6 | |||
| e9f8471a28 | |||
| 4656b11256 | |||
| f2ccab2df7 | |||
| b2e3aefa72 | |||
| 2b48933f29 | |||
| 4ac6cbe70e | |||
| cc07c3df94 | |||
| 31bcad2535 | |||
| b75970958e | |||
| 91756c057e | |||
| df7f245cf8 | |||
| dbdefa0f4a | |||
| 56fdf6002c | |||
| c957f1ddca | |||
| 423386a052 | |||
| 1c882ea361 | |||
| b1065fa01d | |||
| 8ff9c030bf | |||
| 9b875fb930 | |||
| 857bac4b78 | |||
| 30074c290d | |||
| 60d1c26114 | |||
| 692ba43182 | |||
| 6542a037df | |||
| 9f4b451501 | |||
| 1bd454b8fd | |||
| 8392472bac | |||
| cd5b351ce4 | |||
| 50024fbf8b | |||
| 4d4fb3b6ec | |||
| 37dea8aee7 | |||
| 69c4940b27 | |||
| 7691b019e2 | |||
| f55d6b11c5 | |||
| f52877abb4 | |||
| ee7c9b6731 | |||
| 4721344518 | |||
| e0d986dcd7 | |||
| c7be3dcd5b | |||
| 89c9bfd052 | |||
| 12b93567f7 | |||
| 2f37776614 | |||
| f778bca3f2 | |||
| a945d19750 | |||
| 7f04b2c96c | |||
| 8aa4e4ff1e | |||
| 7eade002a7 | |||
| a8f8d27f4e | |||
| 356935bd4f | |||
| bce3dd045f | |||
| 79a2b84c81 | |||
| 44b762f916 | |||
| 5d80c880c8 | |||
| b907263f35 | |||
| 0f0accf82c | |||
| ddcf414107 | |||
| 6be3b1d7f2 | |||
| 0e0d7016b3 | |||
| 553c76ab0f | |||
| b90cfa8e5c | |||
| e7f0cd0c4b | |||
| 0661b339a0 | |||
| d1bb72f6fb | |||
| 1bcd1edbf5 | |||
| 143a00626b | |||
| 0eb981f51c | |||
| 6cc01349f7 | |||
| a7bd4acd46 | |||
| 8e0a56b49a | |||
| a8844ddd28 | |||
| c18fefd5f3 | |||
| 3040940e35 | |||
| df3d2d57c3 | |||
| 92d26f2216 | |||
| 0380c68f89 | |||
| 2a6dc6a7b7 | |||
| 40617f0d5c | |||
| 09745a7835 | |||
| 57f6f50939 | |||
| f959905adf | |||
| f78c7e7926 | |||
| 96496da0ab | |||
| 2dc4733ac1 | |||
| f14774d034 | |||
| c08c63f420 | |||
| eb79c6c47c | |||
| bf1cbb4cde | |||
| 592675022e | |||
| b2e10d7e6e | |||
| 0689954433 | |||
| 5c37f198cb | |||
| 3b02a9d4fe | |||
| c9057aa498 | |||
| 2b0d198b05 | |||
| 7798145c74 | |||
| fcfadd7c74 | |||
| c0181820a9 | |||
| 76d4e6bd18 | |||
| ccb81de85d | |||
| 82f4975f45 | |||
| d457e6ad6a | |||
| abf7c8e68a | |||
| 1a38d0c31e | |||
| 9ff9d679e9 | |||
| 9f3f8f950a | |||
| 006a196e4a | |||
| 418678466c | |||
| 9f4cb5c4dd | |||
| 73f9de6635 | |||
| 12b9c82086 | |||
| a8edb8870e | |||
| dabc3c6cc4 | |||
| cc7c1ad30d | |||
| 4d840a8d9a | |||
| 95a80bfe81 | |||
| 53e9eab0cd | |||
| 35b3c3c98c | |||
| 20e17a28cf | |||
| 28bf2d6374 | |||
| 8a00b53050 | |||
| 8834241417 | |||
| 96740d6be4 | |||
| b853d29992 | |||
| 33a0f562d3 | |||
| f8e3ae0525 | |||
| c790bad667 | |||
| d54489bbcb | |||
| 808c97020a | |||
| 34e680d792 | |||
| 32d543943b | |||
| 2632507980 | |||
| f467a9a309 | |||
| 5c9710c78b | |||
| 107b31a0b5 | |||
| 028c7a822f | |||
| 18f5f98e62 | |||
| 543bb3cc4b | |||
| 1c44d24b76 | |||
| 5305f962c0 | |||
| b774f147da | |||
| 2a5921b9c9 | |||
| 60cb392e97 | |||
| d012c538c3 | |||
| 1c88d0d7f7 | |||
| 773b8de8ba | |||
| 5d8dd090a9 | |||
| 2cbfe70a28 | |||
| 16dbfbb267 | |||
| 99fc7817c6 | |||
| 265b4c2b22 | |||
| db9db2cc40 | |||
| 3642eabac0 | |||
| 98e05fd179 | |||
| 1ccff9478f | |||
| 85f9b585f5 | |||
| 01626b4c9f | |||
| a85841ca76 | |||
| fe6c4cd0b5 | |||
| f1585d09e1 | |||
| 252784ff5b | |||
| 6f9dc2a9b8 | |||
| 7edfae8583 | |||
| 28275d86ea | |||
| 2d19b5074e | |||
| e62cc17797 | |||
| 407eed212a | |||
| 12d47858c1 | |||
| 3d34e6e6d9 | |||
| dc188e601a | |||
| 8a2df23260 | |||
| 46079a8612 | |||
| 201d752850 | |||
| 63b3d9875d | |||
| 8cd2d772b0 | |||
| 2ff3f88b4d | |||
| ab4dd6a268 | |||
| 0094efc7f4 | |||
| d73a270fb1 | |||
| d9647868cc | |||
| 85505b0482 | |||
| 703c1a485c | |||
| 9258c73484 | |||
| 6858546ce9 | |||
| 7c6966a9c4 | |||
| 40d1d20cd6 | |||
| c0942d78cb | |||
| cef8779bf7 | |||
| d6667844de | |||
| 4cdf218145 | |||
| 994713d04c | |||
| 554b13ac50 | |||
| 439fb57d88 | |||
| 4409d0f03f | |||
| ebd00b1eb2 | |||
| 3ca0ef1583 | |||
| 88abbd90dc | |||
| bdbde25784 | |||
| ee9e941a56 | |||
| ac90800c3c | |||
| 08f5833ca8 | |||
| 4bcd3ed86f | |||
| 254fd80088 | |||
| d7e6df1e44 | |||
| a933fabb86 | |||
| 36baf7b0af | |||
| e6026cb0b8 | |||
| cc2b4967ea | |||
| cf59f89bfb | |||
| 066ed7e4a1 | |||
| 4f49d60e4a | |||
| 3721dadd72 | |||
| 5539d5eed0 | |||
| 64002626b9 | |||
| 4b1c20fa36 | |||
| b418683337 | |||
| 00015285ab | |||
| 0f936fc163 | |||
| 15045cc486 | |||
| c9132d984b | |||
| a0123e7c2d | |||
| be786be67d | |||
| e85b18e206 | |||
| f32f62dfc1 | |||
| 28392050bf | |||
| b9cc6063ff | |||
| 9066e62a97 | |||
| 5549696c3a | |||
| 691c9fe8e0 | |||
| 04463675c0 | |||
| b9da6a4a5d | |||
| 9fb161c320 | |||
| 2ba25b4c28 | |||
| c1618e2b5d | |||
| 788f5429e1 | |||
| 36026d4ec6 | |||
| 96767f5ca8 | |||
| 76bad31dd5 | |||
| 2e3b917192 | |||
| 95f262b3e6 | |||
| aebacb6b6a | |||
| 27613da5ea | |||
| 28ac6c2267 | |||
| 1c1fc65c7c | |||
| ba74b352bd | |||
| 0474ac4262 | |||
| aba49cc93f | |||
| b3b5b40163 | |||
| 0e085b30cc | |||
| 35149b6960 | |||
| 3800d5420e | |||
| b145c1ab64 | |||
| b8a3439219 | |||
| 1a153b835c | |||
| 73c292c4e9 | |||
| d8bb0b53f8 | |||
| 83c66901f8 | |||
| 088f77a226 | |||
| 4dd6c85df2 | |||
| d0452a3510 | |||
| 11310e7615 | |||
| 22b32a0fe5 | |||
| ad143c184f | |||
| 803a4cd163 | |||
| 267fdf9fa1 | |||
| 26d2a4420e | |||
| c623ad7da0 | |||
| 7de689055c | |||
| 63b15a8855 | |||
| a2a7302964 | |||
| 6a5367dbe3 | |||
| 6768a18475 | |||
| 242ed4a3c2 | |||
| f9b70d1b5b | |||
| faa5252191 | |||
| 4212f48d7a | |||
| b30a79c7fe | |||
| 22374ac8f7 | |||
| 17014bb8de | |||
| d1c3d3d5aa | |||
| 7fedd94cc5 | |||
| 48eca3d031 | |||
| 21d3cf91a0 | |||
| 5938cc4086 | |||
| 7c57d736c6 | |||
| cbe3f2a4ac | |||
| 7a10e0e347 | |||
| efb577769e | |||
| 8c569ac7bf | |||
| a84fb57e32 | |||
| 7314d2b577 | |||
| ba83ede0d1 | |||
| 42500ce043 | |||
| caa8c1da90 | |||
| cbcb9f9044 | |||
| 60bffb5f49 | |||
| 2a16a67aed | |||
| c6cd185cb5 | |||
| 58cdcf754c | |||
| d969f5df7b | |||
| b6455e0661 | |||
| 15021b442c | |||
| ee078fc638 | |||
| 9893c90e74 | |||
| 82978da5e3 | |||
| 80ce9d546a | |||
| 34775633b2 | |||
| 03b5c8e76e | |||
| 766b8cd62e | |||
| 609067cefa | |||
| 9d497ad311 | |||
| 72059a9441 | |||
| ebecbb69ec | |||
| b129bab81a | |||
| 14c70c5cc8 | |||
| d62a67502e | |||
| 4b2c303873 | |||
| d189f00f38 | |||
| a5cf92b2ff | |||
| 8c45249c06 | |||
| 55c8a15983 | |||
| 3607e2e759 | |||
| d035068982 | |||
| af8156f310 | |||
| 47b995a2a3 | |||
| 6f8f99f42c | |||
| 69137cddab | |||
| 9caa3030ea | |||
| 3e9826acf5 | |||
| d7b4f54983 | |||
| 00b0dcd306 | |||
| 53c356a940 | |||
| a7f3351c0e | |||
| 3a6cdfff45 | |||
| c26e347e91 | |||
| 1b94957b07 | |||
| 2e39668605 | |||
| 0642c569b4 | |||
| 4e364bd2f6 | |||
| b9fe564d78 | |||
| 437fa45ca2 | |||
| 85e215650c | |||
| 7eb186dad4 | |||
| 2259614640 | |||
| a584e1a4ec | |||
| 869f4011a1 | |||
| 463bb72d24 | |||
| 8b312a47e6 | |||
| 46d4e32510 | |||
| 1815a913c3 | |||
| a7e06715ba | |||
| a89fd95864 | |||
| 9ba9469bb1 | |||
| 4dbf173ed4 | |||
| 8936cca9cf | |||
| 1c704680a8 | |||
| 3e36834751 | |||
| 581caff638 | |||
| 8b612ba547 | |||
| 90820f24a4 | |||
| 12a37500b0 | |||
| 3ae6ffdb01 | |||
| c4e76b391e | |||
| cf9ba737f0 | |||
| 2d0690ae2d | |||
| 71a2d0971f | |||
| 3bf57e0748 | |||
| fbc0319cb6 | |||
| e8bc3c2d80 | |||
| fe192e07fb | |||
| 51b6329c86 | |||
| 72d9e4c1e7 | |||
| cb7d5c9d09 | |||
| 097ab82529 | |||
| ccb603d77f | |||
| d7b02db832 | |||
| 56cc5da9fb | |||
| 1903079f96 | |||
| b6d0950ee9 | |||
| c1a32a4041 | |||
| 8fa443879c | |||
| 3a465cb94f | |||
| 49133dce48 | |||
| 3b7b6beca5 | |||
| 0dd81328ff | |||
| a668593e6b | |||
| 3a5a22511a | |||
| 86859267f0 | |||
| 88c9f6d233 | |||
| 176693dd5a | |||
| 62bee04fc0 | |||
| 0a5aacfd87 | |||
| 2dec3a6c95 | |||
| fcc2814199 | |||
| bc93d238dd | |||
| 79e2c5d48c | |||
| 0fab7ad63b | |||
| e6a2f55a59 | |||
| 67e9ca56ac | |||
| 713daf6cd3 | |||
| 12abe81c6d | |||
| fbcf10c86d | |||
| 415b20f884 | |||
| d58ca5f37a | |||
| 11b6ee423e | |||
| a10ca47657 | |||
| ad1f175a39 | |||
| fd3246113a | |||
| b8013c883c | |||
| ffcc4fd03a | |||
| 9d97964998 | |||
| f0e54cdd51 | |||
| 0360fd1efe | |||
| 4508e099ff | |||
| 6ed1435aeb | |||
| 6346e288ad | |||
| d2b503910f | |||
| 747c3b2a4b | |||
| cccb4e6d5e | |||
| f4c6afbdae | |||
| d1ef380e6b | |||
| c02de2580d | |||
| a231f8587e | |||
| 4149748766 | |||
| 783627c315 | |||
| 1ff6aa1748 | |||
| 6662dc4a8d | |||
| d6b170e274 | |||
| 11cac7a646 | |||
| 9c2fcd745c | |||
| 04f49a6819 | |||
| d465ea2a67 | |||
| 1f5073d0ac | |||
| 8dbbbc1a1a | |||
| f985673dc3 | |||
| a6fc3cf7a6 | |||
| 1941885cfd | |||
| 88a86a9927 | |||
| 48e030bca3 | |||
| 6f118c1be1 | |||
| 7316eb87b8 | |||
| 5376236ab6 | |||
| 0af80d48ee | |||
| 793c0368f2 | |||
| 076001462e | |||
| d2e1d8ec13 | |||
| 30ceaa6bef | |||
| 0247d47a3d | |||
| 480368c878 | |||
| c1d8790623 | |||
| fb1ffec5bb | |||
| 1bdabe693f | |||
| ce09f35275 | |||
| 40c13043b3 | |||
| e620068416 | |||
| 8e624ca85a | |||
| c7afd46016 | |||
| 3573656244 | |||
| 1de6de975a | |||
| 15c55b8c7d | |||
| 865061b492 | |||
| 39313e1737 | |||
| 70880636f4 | |||
| 96a5ba0ed3 | |||
| 8054f6c618 | |||
| 658ea68d04 | |||
| 5750f87396 | |||
| 1253e2a458 | |||
| 857b3e92f8 | |||
| 8bf14d542e | |||
| 31d2a39540 | |||
| 97718b4046 | |||
| c07fd265f0 | |||
| 1de50a2a94 | |||
| 627ca432cc | |||
| f8ef11b4d2 | |||
| 71563034a7 | |||
| aaff5a65e1 | |||
| 458a362f98 | |||
| 36d07065fb | |||
| f206e72447 | |||
| 58e45fb394 | |||
| 411f32c766 | |||
| e1b82e4e43 | |||
| df613775b6 | |||
| 5e8fdc997a | |||
| 51bfe4252d | |||
| c96aee5740 | |||
| 1c08849667 | |||
| 73349e5e75 | |||
| 74ae411b69 | |||
| d458592fb1 | |||
| 627c89a62d | |||
| 0228cd4f31 | |||
| a859558840 | |||
| 04eee2ea75 | |||
| bda2c663da | |||
| 5e041e6e5a | |||
| d19264eea8 | |||
| 64c52012df | |||
| 7542e55cb2 | |||
| 6bd51ac345 | |||
| cf21eb4b39 | |||
| da8170c5b6 | |||
| 12bc7480e0 | |||
| 92862fdf39 | |||
| 4417268ecc | |||
| 346853ee55 | |||
| a82f00cb70 | |||
| 1838ea5c30 | |||
| a356d90445 | |||
| a3f41fd4d9 | |||
| f4be37700f | |||
| ed19bb11fe | |||
| 07275ecb5f | |||
| 2464fccadd | |||
| 5fde2cf91a | |||
| d57e797147 | |||
| 988f7b0561 | |||
| e99a271465 | |||
| d266c7f93b | |||
| d7e5c56e94 | |||
| ddd3b4c093 | |||
| 3a6fc4c197 | |||
| 91381546d5 | |||
| 41e2b898ab | |||
| 6e981d1222 | |||
| 8317bb13ca | |||
| c40f244dff | |||
| a6aa048be0 | |||
| 8fd0162393 | |||
| f0b18da881 | |||
| 5f63ea8f8a | |||
| 2b43569927 | |||
| 4ba33175cf | |||
| 3edc1af560 | |||
| 55fbd09e45 | |||
| 6a46a25f48 | |||
| 88b8ca5b29 | |||
| fdddb556ae | |||
| d36b64e0c8 | |||
| 8adc97980a | |||
| dab6e5a60f | |||
| 0b05e9827b | |||
| 1c1a76d6d7 | |||
| df4f37d68d | |||
| 44629ba5dd | |||
| 2da6776451 | |||
| a68f411024 | |||
| 166550fbba | |||
| 3e68981b0b | |||
| 6fd76e8d1e | |||
| dfcd15e7c4 | |||
| 5fa359c28d | |||
| 5bcfc9dd50 | |||
| f67cad326a | |||
| 9775e83374 | |||
| 264d1798dc | |||
| 1824988b9a | |||
| c54d9b3f60 | |||
| f432d3fcf8 | |||
| 4f7828bab9 | |||
| ae073a336d | |||
| 6f90974896 | |||
| 4f3c05851c | |||
| 4b13055125 | |||
| d542cd811d | |||
| f75cebac7e | |||
| e302b6b635 | |||
| f709e88994 | |||
| ab9a6d583b | |||
| 26d6bf338e | |||
| b6e040dfc2 | |||
| f5802ca3e5 | |||
| 7223e581a2 | |||
| 2d11ce9669 | |||
| e4982a1a5c | |||
| cea6dedccc | |||
| e6ed5a388d | |||
| b89fc3fe87 | |||
| 57ae74f908 | |||
| 1a6804b4b4 | |||
| 82e6a3582d | |||
| 11a4e4faa2 | |||
| 50a3533322 | |||
| 4e9f39384a | |||
| 39802b56c1 | |||
| ebb87ccdde | |||
| f0e55938c1 | |||
| 348d04f7f5 | |||
| 1b0086217c | |||
| d395cf38b7 | |||
| 57aec2a733 | |||
| ae89237453 | |||
| 60d5257678 | |||
| d59463d11b | |||
| 1280528e4e | |||
| 23d6205659 | |||
| bc0acc6f44 | |||
| b8622f2b4b | |||
| 7f0c39fe91 | |||
| a489be0e05 | |||
| 8e08046519 | |||
| 999eb53364 | |||
| f7e549e412 | |||
| fbb99de728 | |||
| 0620ed3d4f | |||
| b779b3cf2d | |||
| a6b973003b | |||
| e431e90b20 | |||
| 4aa466b948 | |||
| 04ae53b6df | |||
| 3666525d24 | |||
| f1a4bbce53 | |||
| 708a720d9d | |||
| 7177da7d62 | |||
| 5e4aa75e03 | |||
| d88ee5c9ee | |||
| d4ea720239 | |||
| 97ee370ffe | |||
| a084f83f4c | |||
| 54732edff4 | |||
| 1a24d1839f | |||
| c3040a04a3 | |||
| 7feb4c4ebd | |||
| 2911d1f018 | |||
| d68ad893f0 | |||
| 4ca147699d | |||
| abed41b8fa | |||
| 2604a55f80 | |||
| 39667de662 | |||
| 8956835d95 | |||
| ea4ec2eafc | |||
| 3a352078de | |||
| 6060b39548 | |||
| dce2436b2c | |||
| 2b52ea4c6f | |||
| b41738b47b | |||
| 57e76a65a4 | |||
| 7f25ddc229 | |||
| 163961df4f | |||
| 97da386ed6 | |||
| c706829a91 | |||
| 6cd246a38e | |||
| 43e88c0ae0 | |||
| bf01b935bd | |||
| 98c011e6a6 | |||
| 86dcb5c471 | |||
| 467ac6c365 | |||
| c77ad5fb34 | |||
| 4006a04817 | |||
| 4189a1c729 | |||
| a07cbabcb3 | |||
| 64a3893f6f | |||
| eabe759ebf | |||
| a4838386e6 | |||
| c65613901f | |||
| 19d16620a6 | |||
| 4e15b9cdfa | |||
| de35cec2e1 | |||
| e8bcebfb8e | |||
| 2f241e1b61 | |||
| 6affef76b1 | |||
| 32ba4d07e2 | |||
| ddaaf89c87 | |||
| 9aed8dbe6b | |||
| aa7e92b275 | |||
| f30947336a | |||
| 0bb44d7b75 | |||
| 1138ec77ca | |||
| c4dadd27ac | |||
| 04c715d314 | |||
| 35743cc8e6 | |||
| 5f92807fdd | |||
| 700c3444f5 | |||
| ddf1babfe1 | |||
| 2ae2ede0b2 | |||
| ef5af384e7 | |||
| a134d16070 | |||
| 827eec6af0 | |||
| 8da2f12ba6 | |||
| 50ab391133 | |||
| 991647bc8f | |||
| 57300687ff | |||
| d559339f5f | |||
| 2bf65ef512 | |||
| d20752c318 | |||
| 5f66ef34dd | |||
| da0b4cd40e | |||
| 68f9dc1f8a | |||
| 5121d0d934 | |||
| 2c520391eb | |||
| 7c4b9218f2 | |||
| 72f8138ca1 | |||
| 991ae4383a | |||
| 2ce7205c80 | |||
| bec3e8654f | |||
| 14fdcb892d | |||
| d6d062841d | |||
| 06d0985bba | |||
| 9ea969be1f | |||
| 500f774b7f | |||
| ca8832c0e1 | |||
| 1cbba113fd | |||
| 45b4b33a3d | |||
| c453a8e2dc | |||
| e59772a58d | |||
| fb35f06cf5 | |||
| abc788c756 | |||
| 63b616dc2e | |||
| 72f3fe0b12 | |||
| cba12efeb1 | |||
| 37cd4ed504 | |||
| 869bba4dad | |||
| 23194d1f53 | |||
| 969563c06a | |||
| 066e8e1cc2 | |||
| 5cd7b40165 | |||
| c7b134ba4b | |||
| ff62c262fe | |||
| 42e2c15e0c | |||
| 40c6989374 | |||
| 71dc373610 | |||
| 0fa16cf982 | |||
| 8902032b42 | |||
| 368f5e9799 | |||
| 46b34817d2 | |||
| b1fe24bb57 | |||
| 490a28ee7a | |||
| 75884ca6b8 | |||
| d729d7f570 | |||
| 6408bb2efa | |||
| d8dabab4fb | |||
| 4dc107f77a | |||
| eaf06d239c | |||
| d9b3a4bf77 | |||
| cf970d5914 | |||
| 1cfe3dd4da | |||
| 51d1e47bfe | |||
| e0a447bfaf | |||
| 3f5ee6f414 | |||
| 44d5c8c4b4 | |||
| 17b7e9e772 | |||
| 8a2a444f33 | |||
| 957df08932 | |||
| fd018b32d0 | |||
| e000c7d818 | |||
| bb40069773 | |||
| 37d5b60f5c | |||
| 37e6cd6500 | |||
| feadea0e91 | |||
| f71a29b6c4 | |||
| ec4cfdee23 | |||
| dd79db6383 | |||
| 723e458bd7 | |||
| 25a47f0df3 | |||
| 39be57424c | |||
| 45ffa1b79c | |||
| f37e1c2229 | |||
| 1bd7b86e60 | |||
| 18e7cf2069 | |||
| 60b4d90608 | |||
| 5197000124 | |||
| 71d4060993 | |||
| 34c6ad7277 | |||
| 9e79ef2a91 | |||
| 4d1b32f770 | |||
| a5a097fa4a | |||
| ad645f31d0 | |||
| f08d429851 | |||
| bac3219a01 | |||
| 09a527fb12 | |||
| 58a3a480b9 | |||
| a12bfe4639 | |||
| 6cda639869 | |||
| 2797fe116f | |||
| e768cd53fb | |||
| 83e2ad40d6 | |||
| 7ebd0699e3 | |||
| 46b1d4d194 | |||
| f60e265397 | |||
| 2e642327ea | |||
| a87ce41030 | |||
| 0c8cae4cc3 | |||
| ed325b4a45 | |||
| 1c67b5e812 | |||
| b6c964c444 | |||
| 6fedf06150 | |||
| 91d513a672 | |||
| 44f0ec601f | |||
| 2a659a9d03 | |||
| 7e7c3a1bb3 | |||
| 3b23458ecc | |||
| 7afdfb150f | |||
| 2ca7886f88 | |||
| 5aca6c7c1f | |||
| fe94d6cf89 | |||
| 0a7c316ffb | |||
| e72424e01a | |||
| dbba9128a4 | |||
| 352c1ddc16 | |||
| 4d96ae56ac | |||
| adadb10b15 | |||
| a749b9806e | |||
| 615d9d4abe | |||
| aa03274093 | |||
| e7a06979ec | |||
| 3651306f57 | |||
| 5dce4e6aea | |||
| 1d9041f2aa | |||
| a578527012 | |||
| af78a2d080 | |||
| 840000d02b | |||
| 9ea4c777ad | |||
| a33b63d066 | |||
| da3b30cd94 | |||
| 4599e1dec5 | |||
| 6de350ce9d | |||
| 838d31fa41 | |||
| 401b460d75 | |||
| c440204fa5 | |||
| adf50dffd8 | |||
| 20d38ed28c | |||
| edc30cd71d | |||
| 10ce03a1e7 | |||
| 5fca5c774a | |||
| fc6c39e670 | |||
| 7c3b6307d9 | |||
| e52dac3b25 | |||
| 62db9a8ef3 | |||
| f0be4f86a6 | |||
| e5bb843059 | |||
| ca774dfeb5 | |||
| 681d8327f5 | |||
| 9bc02c81f8 | |||
| bb1738db8c | |||
| 9548c592a3 | |||
| cda0276d39 | |||
| 539afb329a | |||
| 3e0150f847 | |||
| f8261c60c0 | |||
| 9f90eeab05 | |||
| 1ee37cb671 | |||
| 8fe798de6d | |||
| e00efca170 | |||
| 86b6714777 | |||
| 77b5e6d44a | |||
| ffe73165f9 | |||
| 96c7e9e29d | |||
| 02051ed60f | |||
| f49689caac | |||
| 819c130366 | |||
| 974b9b992d | |||
| 3ab1214012 | |||
| 4b917390ac | |||
| 7a0fb9a57f | |||
| 58fcd2b2fe | |||
| bdcf058e52 | |||
| 61f0043cd8 | |||
| dd7bfba8d5 | |||
| 5b8fdbc82d | |||
| 6a1c677cbc | |||
| e30952efee | |||
| fd8dc03ae9 | |||
| 1337758660 | |||
| 339e8a7910 | |||
| a60b460701 | |||
| a5cb4057f9 | |||
| 9d7f97ccd5 | |||
| 0578d41500 | |||
| 42c3fa24f0 | |||
| 60b396fee5 | |||
| 4cd9252ff6 | |||
| 75875d3a8f | |||
| 86e9d92ecb | |||
| baa4e6475a | |||
| ac5c77ee2c | |||
| 1efc6a1385 | |||
| 442ea8a692 | |||
| 749be67df3 | |||
| a97a574718 | |||
| 110a45bee6 | |||
| f120da3aca | |||
| 240684bc1f | |||
| 62003d96f3 | |||
| e905634343 | |||
| 14dce1abac | |||
| 8ddab05ed3 | |||
| 5dc441c4af | |||
| 940fb0d1fd | |||
| f18c33563d | |||
| 10e8a54b2e | |||
| f792976d6d | |||
| 08cbd009ac | |||
| 3d4219bfee | |||
| d58a569660 | |||
| fd3cf5d2b1 | |||
| 1a844426c3 | |||
| 42237a3bc8 | |||
| 010c2c934b | |||
| 48a76426e7 | |||
| 0c645ba867 | |||
| f538dd5276 | |||
| 31568fc5a1 | |||
| 44c7fde2f7 | |||
| cb07142832 | |||
| 60a05412c9 | |||
| 0179f5ea09 | |||
| f671ed7e3f | |||
| 2fccff5a35 | |||
| cd41d5f6dd | |||
| 66905fcc08 | |||
| af4b138094 | |||
| 3c57e05a65 | |||
| 25099b4c98 | |||
| 1ac7629459 | |||
| 95681a7a05 | |||
| d7b8458a56 | |||
| 67dfe0bcf3 | |||
| b1869bced4 | |||
| 61aa1ea11f | |||
| 20aa7c79d1 | |||
| 22548a3f4a | |||
| 9e1b5cbaab | |||
| 1488ec5a03 | |||
| 4f0457a268 | |||
| 30fdc2198f | |||
| bce16cdd6e | |||
| d5daa46ab8 | |||
| ad6d95ba52 | |||
| 318ce5dec8 | |||
| 526d4369ce | |||
| c69919738b | |||
| 1b5a01a6c9 | |||
| f233715b70 | |||
| a58ac18fa0 | |||
| f1e366d36f | |||
| 301dcd78cc | |||
| 65c6d62a15 | |||
| aaf7a249c6 | |||
| 0bc8d49684 | |||
| 17ecbca204 | |||
| 78928b7eb4 | |||
| 5236e1ef0d | |||
| be7ed8e74a | |||
| 78bcb85679 | |||
| b98bb9eb27 | |||
| cad55a4da5 | |||
| 511fc870a1 | |||
| dafd2fecf7 | |||
| 9c5cca784e | |||
| 1138165308 | |||
| d7eb321d58 | |||
| 15f8c7014f | |||
| dd64e2060e | |||
| 14d4551476 | |||
| e6549b0fe8 | |||
| 157e05f57c | |||
| 96efd1e8b9 | |||
| 672ce40618 | |||
| 05e9d76c77 | |||
| ea7fc7f6c4 | |||
| 6b1d5d28be | |||
| a9b0bfa740 | |||
| cc6b80a55b | |||
| 6707989cd5 | |||
| 766439db6d | |||
| d4903caafa | |||
| caa0111c79 | |||
| ffacff67cf | |||
| f43a7fdfb4 | |||
| 7bb1a3906d | |||
| 530c259e71 | |||
| 843a6851c4 | |||
| 234051d6bc | |||
| 981c0eb8bc | |||
| 1066855532 | |||
| f2d6518311 | |||
| 765ccfa18c | |||
| 201aee3119 | |||
| 65f299038d | |||
| bd1290706a | |||
| 939cbf46e4 | |||
| aec5a09caf | |||
| 6346d1b6c7 | |||
| 05ee242b80 | |||
| 64be3f05a3 | |||
| cfdce9be61 | |||
| 446220494e | |||
| f12ffa92a0 | |||
| b2a4797d16 | |||
| 8bfacb0091 | |||
| 0501f3bd99 | |||
| ae3ae6fd0e | |||
| 011a5f57e1 | |||
| 84b3289a2a | |||
| b760892de2 | |||
| 6840a8983c | |||
| a1b3490764 | |||
| 076f1efecb | |||
| b23511edb1 | |||
| 53e572f072 | |||
| c2b6ba0d5a | |||
| d4d530e6c8 | |||
| 99270e96a9 | |||
| 4bf7a08c80 | |||
| 3823de6552 | |||
| 30592b27ce | |||
| 8bc6c2eb20 | |||
| 87d52e5ebe | |||
| 598a09c13d | |||
| 54db4ab215 | |||
| 5b5ccba247 | |||
| 18e2559b1e | |||
| f5987b68ff | |||
| a1ab44d39f | |||
| 8b1514e575 | |||
| 2d3810874d | |||
| a4c634e4bf | |||
| 2a4d986da5 | |||
| 3b18730af6 | |||
| df260fe0e8 | |||
| 2be4fe8404 | |||
| 7db7cfe20f | |||
| cc2cc2849e | |||
| 06f4b0b29a | |||
| e22821799b | |||
| 14dd9294aa | |||
| 83e3409bd8 | |||
| 7630170ed6 | |||
| 0af74fccda | |||
| e77de1804f | |||
| e00b92225d | |||
| ee8fca9439 | |||
| adc562feb8 | |||
| af8fa4014f | |||
| 08415b0e8f | |||
| 967f9a9174 | |||
| d255141bd4 | |||
| e7e1dd91c7 | |||
| 195c5e92a4 | |||
| 47dafe62b8 | |||
| 26922ebb51 | |||
| 7480e71801 | |||
| 9ac3f48fcb | |||
| 0e405755ad | |||
| 693f90449f | |||
| 0bf45069bd | |||
| 34b10f61ce | |||
| 1479b42112 | |||
| bb061d2a0a | |||
| 061012a268 | |||
| a698f91db4 | |||
| 30d12a76bc | |||
| 687fa44eff | |||
| aefb33efff | |||
| da0c45b7ee | |||
| 956335e844 | |||
| 701fc600cd | |||
| e38b2cff4f | |||
| b268293402 | |||
| 45b9dc8be9 | |||
| 0ad7025a17 | |||
| 49b7467840 | |||
| a40ef610a2 | |||
| f9943b60e4 | |||
| f97fb1b35d | |||
| b959181afd | |||
| cbc27a94ac | |||
| 6a4f999b88 | |||
| 7707e01352 | |||
| e667326df5 | |||
| f1b2d7530d | |||
| b6587b32b9 | |||
| b89bafa165 | |||
| 9fac5f94ba | |||
| 5affc73ee6 | |||
| 027016ddae | |||
| 8f2f98b7b4 | |||
| 6b43d12469 | |||
| 74940ed33c | |||
| 17871bb3ca | |||
| 89c4abc07a | |||
| 46b5a7697c | |||
| dd8060d64f | |||
| afb1d7ef0c | |||
| 93ddee5956 | |||
| 0184e5beb5 | |||
| 3f2e110eab | |||
| 0ff68b7d66 | |||
| cdbdc1a822 | |||
| 7a2be05c69 | |||
| 5be38d0702 | |||
| ff203d8d34 | |||
| 23fa39121c | |||
| b16e65168f | |||
| 090a294017 | |||
| 22bc4b4271 | |||
| e01c049401 | |||
| e7ef7a9e55 | |||
| e0011d22f2 | |||
| 7d34bd8f82 | |||
| bd69cf599b | |||
| 1ac7de9ee5 | |||
| 397043a9c0 | |||
| 43ff03e33b | |||
| fa900df5a7 | |||
| 414f0f6cd9 | |||
| 7ef751ba95 | |||
| f8c01418b1 | |||
| 731330c6b5 | |||
| d2df55b1ac | |||
| 0dd74e3c9d | |||
| 9e073e9fa0 | |||
| c95a271821 | |||
| fe386fa819 | |||
| 4d70322eab | |||
| d9b8391968 | |||
| 6ac3681604 | |||
| b35cad0c2e | |||
| 2106a9e373 | |||
| 5050047cef | |||
| 1b65f850ee | |||
| 7c2933aae1 | |||
| 96babec22a | |||
| c12d1e9bd9 | |||
| 4d1f0e77f2 | |||
| d7bf34ecd0 | |||
| 1943c3e7a1 | |||
| af050cc729 | |||
| 84ef2161a1 | |||
| ca23360d07 | |||
| 5dbe51a52e |
13
.clangd
Normal file
13
.clangd
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
Diagnostics:
|
||||||
|
Suppress: target_unsupported_type
|
||||||
|
|
||||||
|
CompileFlags:
|
||||||
|
Remove: [
|
||||||
|
-fstrict-volatile-bitfields,
|
||||||
|
-fno-tree-loop-distribute-patterns
|
||||||
|
]
|
||||||
|
Add: [
|
||||||
|
-D__banan_os__,
|
||||||
|
-D__arch__=x86_64,
|
||||||
|
-D__x86_64__
|
||||||
|
]
|
||||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -3,3 +3,4 @@
|
|||||||
build/
|
build/
|
||||||
base/
|
base/
|
||||||
script/fakeroot-context
|
script/fakeroot-context
|
||||||
|
tools/update-image-perms
|
||||||
|
|||||||
4
.gitmodules
vendored
4
.gitmodules
vendored
@@ -1,4 +0,0 @@
|
|||||||
[submodule "kernel/lai"]
|
|
||||||
path = kernel/lai
|
|
||||||
url = https://github.com/managarm/lai.git
|
|
||||||
ignore = untracked
|
|
||||||
|
|||||||
8
.pre-commit-config.yaml
Normal file
8
.pre-commit-config.yaml
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
# .pre-commit-config.yaml
|
||||||
|
exclude: '.patch$'
|
||||||
|
repos:
|
||||||
|
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||||
|
rev: v4.1.0 # this is optional, use `pre-commit autoupdate` to get the latest rev!
|
||||||
|
hooks:
|
||||||
|
- id: end-of-file-fixer
|
||||||
|
- id: trailing-whitespace
|
||||||
38
.vscode/c_cpp_properties.json
vendored
Normal file
38
.vscode/c_cpp_properties.json
vendored
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
{
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": "banan-os",
|
||||||
|
"includePath": [
|
||||||
|
"${workspaceFolder}/BAN/include",
|
||||||
|
"${workspaceFolder}/kernel/include",
|
||||||
|
"${workspaceFolder}/userspace/libraries/*/include"
|
||||||
|
],
|
||||||
|
"defines": [
|
||||||
|
"__arch=x86_64",
|
||||||
|
"__enable_sse=1"
|
||||||
|
],
|
||||||
|
"compilerPath": "${workspaceFolder}/toolchain/local/bin/x86_64-banan_os-gcc",
|
||||||
|
"cStandard": "c17",
|
||||||
|
"cppStandard": "gnu++20",
|
||||||
|
"intelliSenseMode": "linux-gcc-x64"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "banan-os-kernel",
|
||||||
|
"includePath": [
|
||||||
|
"${workspaceFolder}/BAN/include",
|
||||||
|
"${workspaceFolder}/kernel/include",
|
||||||
|
"${workspaceFolder}/userspace/libraries/*/include"
|
||||||
|
],
|
||||||
|
"defines": [
|
||||||
|
"__arch=x86_64",
|
||||||
|
"__is_kernel",
|
||||||
|
"__enable_sse=1"
|
||||||
|
],
|
||||||
|
"compilerPath": "${workspaceFolder}/toolchain/local/bin/x86_64-banan_os-gcc",
|
||||||
|
"cStandard": "c17",
|
||||||
|
"cppStandard": "gnu++20",
|
||||||
|
"intelliSenseMode": "linux-gcc-x64"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"version": 4
|
||||||
|
}
|
||||||
10
.vscode/settings.json
vendored
Normal file
10
.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"cmake.configureOnOpen": false,
|
||||||
|
"editor.tabSize": 4,
|
||||||
|
"editor.insertSpaces": false,
|
||||||
|
"editor.detectIndentation": false,
|
||||||
|
"clangd.arguments": [
|
||||||
|
"--compile-commands-dir=${workspaceFolder}/build",
|
||||||
|
"-header-insertion=never"
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -1,280 +0,0 @@
|
|||||||
#include <BAN/String.h>
|
|
||||||
#include <BAN/New.h>
|
|
||||||
|
|
||||||
namespace BAN
|
|
||||||
{
|
|
||||||
|
|
||||||
String::String()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
String::String(const String& other)
|
|
||||||
{
|
|
||||||
*this = other;
|
|
||||||
}
|
|
||||||
|
|
||||||
String::String(String&& other)
|
|
||||||
{
|
|
||||||
*this = move(other);
|
|
||||||
}
|
|
||||||
|
|
||||||
String::String(StringView other)
|
|
||||||
{
|
|
||||||
*this = other;
|
|
||||||
}
|
|
||||||
|
|
||||||
String::~String()
|
|
||||||
{
|
|
||||||
clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
String& String::operator=(const String& other)
|
|
||||||
{
|
|
||||||
clear();
|
|
||||||
MUST(ensure_capacity(other.size()));
|
|
||||||
memcpy(data(), other.data(), other.size() + 1);
|
|
||||||
m_size = other.size();
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
String& String::operator=(String&& other)
|
|
||||||
{
|
|
||||||
clear();
|
|
||||||
|
|
||||||
if (other.has_sso())
|
|
||||||
memcpy(data(), other.data(), other.size() + 1);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
m_storage.general_storage = other.m_storage.general_storage;
|
|
||||||
m_has_sso = false;
|
|
||||||
}
|
|
||||||
m_size = other.m_size;
|
|
||||||
|
|
||||||
other.m_size = 0;
|
|
||||||
other.m_storage.sso_storage = SSOStorage();
|
|
||||||
other.m_has_sso = true;
|
|
||||||
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
String& String::operator=(StringView other)
|
|
||||||
{
|
|
||||||
clear();
|
|
||||||
MUST(ensure_capacity(other.size()));
|
|
||||||
memcpy(data(), other.data(), other.size());
|
|
||||||
m_size = other.size();
|
|
||||||
data()[m_size] = '\0';
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
ErrorOr<void> String::push_back(char c)
|
|
||||||
{
|
|
||||||
TRY(ensure_capacity(m_size + 1));
|
|
||||||
data()[m_size] = c;
|
|
||||||
m_size++;
|
|
||||||
data()[m_size] = '\0';
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
ErrorOr<void> String::insert(char c, size_type index)
|
|
||||||
{
|
|
||||||
ASSERT(index <= m_size);
|
|
||||||
TRY(ensure_capacity(m_size + 1));
|
|
||||||
memmove(data() + index + 1, data() + index, m_size - index);
|
|
||||||
data()[index] = c;
|
|
||||||
m_size++;
|
|
||||||
data()[m_size] = '\0';
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
ErrorOr<void> String::insert(StringView str, size_type index)
|
|
||||||
{
|
|
||||||
ASSERT(index <= m_size);
|
|
||||||
TRY(ensure_capacity(m_size + str.size()));
|
|
||||||
memmove(data() + index + str.size(), data() + index, m_size - index);
|
|
||||||
memcpy(data() + index, str.data(), str.size());
|
|
||||||
m_size += str.size();
|
|
||||||
data()[m_size] = '\0';
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
ErrorOr<void> String::append(StringView str)
|
|
||||||
{
|
|
||||||
TRY(ensure_capacity(m_size + str.size()));
|
|
||||||
memcpy(data() + m_size, str.data(), str.size());
|
|
||||||
m_size += str.size();
|
|
||||||
data()[m_size] = '\0';
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
void String::pop_back()
|
|
||||||
{
|
|
||||||
ASSERT(m_size > 0);
|
|
||||||
m_size--;
|
|
||||||
data()[m_size] = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
void String::remove(size_type index)
|
|
||||||
{
|
|
||||||
ASSERT(index < m_size);
|
|
||||||
memcpy(data() + index, data() + index + 1, m_size - index);
|
|
||||||
m_size--;
|
|
||||||
data()[m_size] = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
void String::clear()
|
|
||||||
{
|
|
||||||
if (!has_sso())
|
|
||||||
{
|
|
||||||
deallocator(m_storage.general_storage.data);
|
|
||||||
m_storage.sso_storage = SSOStorage();
|
|
||||||
m_has_sso = true;
|
|
||||||
}
|
|
||||||
m_size = 0;
|
|
||||||
data()[m_size] = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
bool String::operator==(const String& str) const
|
|
||||||
{
|
|
||||||
if (size() != str.size())
|
|
||||||
return false;
|
|
||||||
for (size_type i = 0; i < m_size; i++)
|
|
||||||
if (data()[i] != str.data()[i])
|
|
||||||
return false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool String::operator==(StringView str) const
|
|
||||||
{
|
|
||||||
if (size() != str.size())
|
|
||||||
return false;
|
|
||||||
for (size_type i = 0; i < m_size; i++)
|
|
||||||
if (data()[i] != str.data()[i])
|
|
||||||
return false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool String::operator==(const char* cstr) const
|
|
||||||
{
|
|
||||||
for (size_type i = 0; i < m_size; i++)
|
|
||||||
if (data()[i] != cstr[i])
|
|
||||||
return false;
|
|
||||||
if (cstr[size()] != '\0')
|
|
||||||
return false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
ErrorOr<void> String::resize(size_type new_size, char init_c)
|
|
||||||
{
|
|
||||||
if (m_size == new_size)
|
|
||||||
return {};
|
|
||||||
|
|
||||||
// expanding
|
|
||||||
if (m_size < new_size)
|
|
||||||
{
|
|
||||||
TRY(ensure_capacity(new_size));
|
|
||||||
memset(data() + m_size, init_c, new_size - m_size);
|
|
||||||
m_size = new_size;
|
|
||||||
data()[m_size] = '\0';
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
m_size = new_size;
|
|
||||||
data()[m_size] = '\0';
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
ErrorOr<void> String::reserve(size_type new_size)
|
|
||||||
{
|
|
||||||
TRY(ensure_capacity(new_size));
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
ErrorOr<void> String::shrink_to_fit()
|
|
||||||
{
|
|
||||||
if (has_sso())
|
|
||||||
return {};
|
|
||||||
|
|
||||||
if (fits_in_sso())
|
|
||||||
{
|
|
||||||
char* data = m_storage.general_storage.data;
|
|
||||||
m_storage.sso_storage = SSOStorage();
|
|
||||||
m_has_sso = true;
|
|
||||||
memcpy(this->data(), data, m_size + 1);
|
|
||||||
deallocator(data);
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
GeneralStorage& storage = m_storage.general_storage;
|
|
||||||
if (storage.capacity == m_size)
|
|
||||||
return {};
|
|
||||||
|
|
||||||
char* new_data = (char*)allocator(m_size + 1);
|
|
||||||
if (new_data == nullptr)
|
|
||||||
return Error::from_errno(ENOMEM);
|
|
||||||
|
|
||||||
memcpy(new_data, storage.data, m_size);
|
|
||||||
deallocator(storage.data);
|
|
||||||
|
|
||||||
storage.capacity = m_size;
|
|
||||||
storage.data = new_data;
|
|
||||||
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
String::size_type String::capacity() const
|
|
||||||
{
|
|
||||||
if (has_sso())
|
|
||||||
return sso_capacity;
|
|
||||||
return m_storage.general_storage.capacity;
|
|
||||||
}
|
|
||||||
|
|
||||||
char* String::data()
|
|
||||||
{
|
|
||||||
if (has_sso())
|
|
||||||
return m_storage.sso_storage.data;
|
|
||||||
return m_storage.general_storage.data;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* String::data() const
|
|
||||||
{
|
|
||||||
if (has_sso())
|
|
||||||
return m_storage.sso_storage.data;
|
|
||||||
return m_storage.general_storage.data;
|
|
||||||
}
|
|
||||||
|
|
||||||
ErrorOr<void> String::ensure_capacity(size_type new_size)
|
|
||||||
{
|
|
||||||
if (m_size >= new_size)
|
|
||||||
return {};
|
|
||||||
if (has_sso() && fits_in_sso(new_size))
|
|
||||||
return {};
|
|
||||||
|
|
||||||
char* new_data = (char*)allocator(new_size + 1);
|
|
||||||
if (new_data == nullptr)
|
|
||||||
return Error::from_errno(ENOMEM);
|
|
||||||
|
|
||||||
if (m_size)
|
|
||||||
memcpy(new_data, data(), m_size + 1);
|
|
||||||
|
|
||||||
if (has_sso())
|
|
||||||
{
|
|
||||||
m_storage.general_storage = GeneralStorage();
|
|
||||||
m_has_sso = false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
deallocator(m_storage.general_storage.data);
|
|
||||||
|
|
||||||
auto& storage = m_storage.general_storage;
|
|
||||||
storage.capacity = new_size;
|
|
||||||
storage.data = new_data;
|
|
||||||
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
bool String::has_sso() const
|
|
||||||
{
|
|
||||||
return m_has_sso;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,196 +1,11 @@
|
|||||||
#include <BAN/String.h>
|
#include <BAN/String.h>
|
||||||
#include <BAN/StringView.h>
|
#include <BAN/StringView.h>
|
||||||
#include <BAN/Vector.h>
|
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
namespace BAN
|
namespace BAN
|
||||||
{
|
{
|
||||||
|
|
||||||
StringView::StringView()
|
|
||||||
{ }
|
|
||||||
|
|
||||||
StringView::StringView(const String& other)
|
StringView::StringView(const String& other)
|
||||||
: StringView(other.data(), other.size())
|
: StringView(other.data(), other.size())
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
StringView::StringView(const char* string, size_type len)
|
|
||||||
{
|
|
||||||
if (len == size_type(-1))
|
|
||||||
len = strlen(string);
|
|
||||||
m_data = string;
|
|
||||||
m_size = len;
|
|
||||||
}
|
|
||||||
|
|
||||||
char StringView::operator[](size_type index) const
|
|
||||||
{
|
|
||||||
ASSERT(index < m_size);
|
|
||||||
return m_data[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
bool StringView::operator==(const String& other) const
|
|
||||||
{
|
|
||||||
if (m_size != other.size())
|
|
||||||
return false;
|
|
||||||
return memcmp(m_data, other.data(), m_size) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool StringView::operator==(StringView other) const
|
|
||||||
{
|
|
||||||
if (m_size != other.m_size)
|
|
||||||
return false;
|
|
||||||
return memcmp(m_data, other.m_data, m_size) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool StringView::operator==(const char* other) const
|
|
||||||
{
|
|
||||||
if (memcmp(m_data, other, m_size))
|
|
||||||
return false;
|
|
||||||
return other[m_size] == '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
StringView StringView::substring(size_type index, size_type len) const
|
|
||||||
{
|
|
||||||
ASSERT(index <= m_size);
|
|
||||||
if (len == size_type(-1))
|
|
||||||
len = m_size - index;
|
|
||||||
ASSERT(len <= m_size - index); // weird order to avoid overflow
|
|
||||||
StringView result;
|
|
||||||
result.m_data = m_data + index;
|
|
||||||
result.m_size = len;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
ErrorOr<Vector<StringView>> StringView::split(char delim, bool allow_empties) const
|
|
||||||
{
|
|
||||||
size_type count = 0;
|
|
||||||
{
|
|
||||||
size_type start = 0;
|
|
||||||
for (size_type i = 0; i < m_size; i++)
|
|
||||||
{
|
|
||||||
if (m_data[i] == delim)
|
|
||||||
{
|
|
||||||
if (allow_empties || start != i)
|
|
||||||
count++;
|
|
||||||
start = i + 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (start != m_size)
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
|
|
||||||
Vector<StringView> result;
|
|
||||||
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 || (start == m_size && allow_empties))
|
|
||||||
TRY(result.push_back(this->substring(start)));
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
ErrorOr<Vector<StringView>> StringView::split(bool(*comp)(char), bool allow_empties) const
|
|
||||||
{
|
|
||||||
size_type count = 0;
|
|
||||||
{
|
|
||||||
size_type start = 0;
|
|
||||||
for (size_type i = 0; i < m_size; i++)
|
|
||||||
{
|
|
||||||
if (comp(m_data[i]))
|
|
||||||
{
|
|
||||||
if (allow_empties || start != i)
|
|
||||||
count++;
|
|
||||||
start = i + 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (start != m_size)
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
|
|
||||||
Vector<StringView> result;
|
|
||||||
TRY(result.reserve(count));
|
|
||||||
|
|
||||||
size_type start = 0;
|
|
||||||
for (size_type i = 0; i < m_size; i++)
|
|
||||||
{
|
|
||||||
if (comp(m_data[i]))
|
|
||||||
{
|
|
||||||
if (allow_empties || start != i)
|
|
||||||
TRY(result.push_back(this->substring(start, i - start)));
|
|
||||||
start = i + 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (start < m_size || (start == m_size && allow_empties))
|
|
||||||
TRY(result.push_back(this->substring(start)));
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
char StringView::back() const
|
|
||||||
{
|
|
||||||
ASSERT(m_size > 0);
|
|
||||||
return m_data[m_size - 1];
|
|
||||||
}
|
|
||||||
|
|
||||||
char StringView::front() const
|
|
||||||
{
|
|
||||||
ASSERT(m_size > 0);
|
|
||||||
return m_data[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
BAN::Optional<StringView::size_type> StringView::find(char ch) const
|
|
||||||
{
|
|
||||||
for (size_type i = 0; i < m_size; i++)
|
|
||||||
if (m_data[i] == ch)
|
|
||||||
return i;
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
BAN::Optional<StringView::size_type> StringView::find(bool(*comp)(char)) const
|
|
||||||
{
|
|
||||||
for (size_type i = 0; i < m_size; i++)
|
|
||||||
if (comp(m_data[i]))
|
|
||||||
return i;
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
bool StringView::contains(char ch) const
|
|
||||||
{
|
|
||||||
for (size_type i = 0; i < m_size; i++)
|
|
||||||
if (m_data[i] == ch)
|
|
||||||
return true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
StringView::size_type StringView::count(char ch) const
|
|
||||||
{
|
|
||||||
size_type result = 0;
|
|
||||||
for (size_type i = 0; i < m_size; i++)
|
|
||||||
if (m_data[i] == ch)
|
|
||||||
result++;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool StringView::empty() const
|
|
||||||
{
|
|
||||||
return m_size == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
StringView::size_type StringView::size() const
|
|
||||||
{
|
|
||||||
return m_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* StringView::data() const
|
|
||||||
{
|
|
||||||
return m_data;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,25 +1,18 @@
|
|||||||
cmake_minimum_required(VERSION 3.26)
|
|
||||||
|
|
||||||
project(BAN CXX)
|
|
||||||
|
|
||||||
set(BAN_SOURCES
|
set(BAN_SOURCES
|
||||||
BAN/Assert.cpp
|
BAN/Assert.cpp
|
||||||
BAN/New.cpp
|
BAN/New.cpp
|
||||||
BAN/String.cpp
|
|
||||||
BAN/StringView.cpp
|
BAN/StringView.cpp
|
||||||
BAN/Time.cpp
|
BAN/Time.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
add_custom_target(ban-headers
|
|
||||||
COMMAND ${CMAKE_COMMAND} -E copy_directory_if_different ${CMAKE_CURRENT_SOURCE_DIR}/include/ ${BANAN_INCLUDE}/
|
|
||||||
DEPENDS sysroot
|
|
||||||
)
|
|
||||||
|
|
||||||
add_library(ban ${BAN_SOURCES})
|
add_library(ban ${BAN_SOURCES})
|
||||||
add_dependencies(ban headers libc-install)
|
target_link_options(ban PRIVATE -nolibc)
|
||||||
|
banan_link_library(ban libc)
|
||||||
|
|
||||||
add_custom_target(ban-install
|
set_target_properties(ban PROPERTIES OUTPUT_NAME libban)
|
||||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_BINARY_DIR}/libban.a ${BANAN_LIB}/
|
|
||||||
DEPENDS ban
|
# set SONAME as cmake doesn't set it for some reason??
|
||||||
BYPRODUCTS ${BANAN_LIB}/libban.a
|
set_target_properties(ban PROPERTIES LINK_FLAGS "-Wl,-soname,libban.so")
|
||||||
)
|
|
||||||
|
banan_install_headers(ban)
|
||||||
|
install(TARGETS ban OPTIONAL)
|
||||||
|
|||||||
@@ -18,78 +18,78 @@ namespace BAN
|
|||||||
using const_iterator = ConstIteratorSimple<T, Array>;
|
using const_iterator = ConstIteratorSimple<T, Array>;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Array() = default;
|
constexpr Array() = default;
|
||||||
Array(const T&);
|
constexpr Array(const T&);
|
||||||
|
|
||||||
iterator begin() { return iterator(m_data); }
|
iterator begin() { return iterator(m_data); }
|
||||||
iterator end() { return iterator(m_data + size()); }
|
iterator end() { return iterator(m_data + size()); }
|
||||||
const_iterator begin() const { return const_iterator(m_data); }
|
const_iterator begin() const { return const_iterator(m_data); }
|
||||||
const_iterator end() const { return const_iterator(m_data + size()); }
|
const_iterator end() const { return const_iterator(m_data + size()); }
|
||||||
|
|
||||||
const T& operator[](size_type) const;
|
constexpr const T& operator[](size_type) const;
|
||||||
T& operator[](size_type);
|
constexpr T& operator[](size_type);
|
||||||
|
|
||||||
const T& back() const;
|
constexpr const T& back() const;
|
||||||
T& back();
|
constexpr T& back();
|
||||||
const T& front() const;
|
constexpr const T& front() const;
|
||||||
T& front();
|
constexpr T& front();
|
||||||
|
|
||||||
Span<T> span() { return Span(m_data, size()); }
|
Span<T> span() { return Span(m_data, size()); }
|
||||||
const Span<T> span() const { return Span(m_data, size()); }
|
Span<const T> span() const { return Span(m_data, size()); }
|
||||||
|
|
||||||
constexpr size_type size() const;
|
constexpr size_type size() const;
|
||||||
|
|
||||||
const T* data() const { return m_data; }
|
constexpr const T* data() const { return m_data; }
|
||||||
T* data() { return m_data; }
|
constexpr T* data() { return m_data; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
T m_data[S] {};
|
T m_data[S] {};
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T, size_t S>
|
template<typename T, size_t S>
|
||||||
Array<T, S>::Array(const T& value)
|
constexpr Array<T, S>::Array(const T& value)
|
||||||
{
|
{
|
||||||
for (size_type i = 0; i < S; i++)
|
for (size_type i = 0; i < S; i++)
|
||||||
m_data[i] = value;
|
m_data[i] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, size_t S>
|
template<typename T, size_t S>
|
||||||
const T& Array<T, S>::operator[](size_type index) const
|
constexpr const T& Array<T, S>::operator[](size_type index) const
|
||||||
{
|
{
|
||||||
ASSERT(index < S);
|
ASSERT(index < S);
|
||||||
return m_data[index];
|
return m_data[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, size_t S>
|
template<typename T, size_t S>
|
||||||
T& Array<T, S>::operator[](size_type index)
|
constexpr T& Array<T, S>::operator[](size_type index)
|
||||||
{
|
{
|
||||||
ASSERT(index < S);
|
ASSERT(index < S);
|
||||||
return m_data[index];
|
return m_data[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, size_t S>
|
template<typename T, size_t S>
|
||||||
const T& Array<T, S>::back() const
|
constexpr const T& Array<T, S>::back() const
|
||||||
{
|
{
|
||||||
ASSERT(S != 0);
|
ASSERT(S != 0);
|
||||||
return m_data[S - 1];
|
return m_data[S - 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, size_t S>
|
template<typename T, size_t S>
|
||||||
T& Array<T, S>::back()
|
constexpr T& Array<T, S>::back()
|
||||||
{
|
{
|
||||||
ASSERT(S != 0);
|
ASSERT(S != 0);
|
||||||
return m_data[S - 1];
|
return m_data[S - 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, size_t S>
|
template<typename T, size_t S>
|
||||||
const T& Array<T, S>::front() const
|
constexpr const T& Array<T, S>::front() const
|
||||||
{
|
{
|
||||||
ASSERT(S != 0);
|
ASSERT(S != 0);
|
||||||
return m_data[0];
|
return m_data[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, size_t S>
|
template<typename T, size_t S>
|
||||||
T& Array<T, S>::front()
|
constexpr T& Array<T, S>::front()
|
||||||
{
|
{
|
||||||
ASSERT(S != 0);
|
ASSERT(S != 0);
|
||||||
return m_data[0];
|
return m_data[0];
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <BAN/Traits.h>
|
||||||
|
|
||||||
namespace BAN
|
namespace BAN
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -13,8 +15,36 @@ namespace BAN
|
|||||||
memory_order_seq_cst = __ATOMIC_SEQ_CST,
|
memory_order_seq_cst = __ATOMIC_SEQ_CST,
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T, MemoryOrder MEM_ORDER = MemoryOrder::memory_order_seq_cst>
|
template<typename T> concept atomic_c = is_integral_v<T> || is_pointer_v<T>;
|
||||||
requires requires { __atomic_always_lock_free(sizeof(T), 0); }
|
template<typename T> concept atomic_lockfree_c = (is_integral_v<T> || is_pointer_v<T>) && __atomic_always_lock_free(sizeof(T), 0);
|
||||||
|
|
||||||
|
template<atomic_lockfree_c T, atomic_c U>
|
||||||
|
inline void atomic_store(T& obj, U value, MemoryOrder mem_order = MemoryOrder::memory_order_seq_cst) { __atomic_store_n(&obj, value, mem_order); }
|
||||||
|
template<atomic_lockfree_c T>
|
||||||
|
inline T atomic_load(T& obj, MemoryOrder mem_order = MemoryOrder::memory_order_seq_cst) { return __atomic_load_n(&obj, mem_order); }
|
||||||
|
|
||||||
|
template<atomic_lockfree_c T, atomic_c U>
|
||||||
|
inline T atomic_exchange(T& obj, U value, MemoryOrder mem_order = MemoryOrder::memory_order_seq_cst) { return __atomic_exchange_n(&obj, value, mem_order); }
|
||||||
|
template<atomic_lockfree_c T, atomic_lockfree_c U, atomic_c V>
|
||||||
|
inline bool atomic_compare_exchange(T& obj, U& expected, V value, MemoryOrder mem_order = MemoryOrder::memory_order_seq_cst) { return __atomic_compare_exchange_n(&obj, &expected, value, false, mem_order, mem_order); }
|
||||||
|
|
||||||
|
#define DECL_ATOMIC_INLINE template<atomic_lockfree_c T, atomic_c U> inline
|
||||||
|
DECL_ATOMIC_INLINE T atomic_add_fetch (T& obj, U value, MemoryOrder mem_order = MemoryOrder::memory_order_seq_cst) { return __atomic_add_fetch (&obj, value, mem_order); }
|
||||||
|
DECL_ATOMIC_INLINE T atomic_sub_fetch (T& obj, U value, MemoryOrder mem_order = MemoryOrder::memory_order_seq_cst) { return __atomic_sub_fetch (&obj, value, mem_order); }
|
||||||
|
DECL_ATOMIC_INLINE T atomic_and_fetch (T& obj, U value, MemoryOrder mem_order = MemoryOrder::memory_order_seq_cst) { return __atomic_and_fetch (&obj, value, mem_order); }
|
||||||
|
DECL_ATOMIC_INLINE T atomic_xor_fetch (T& obj, U value, MemoryOrder mem_order = MemoryOrder::memory_order_seq_cst) { return __atomic_xor_fetch (&obj, value, mem_order); }
|
||||||
|
DECL_ATOMIC_INLINE T atomic_or_fetch (T& obj, U value, MemoryOrder mem_order = MemoryOrder::memory_order_seq_cst) { return __atomic_or_fetch (&obj, value, mem_order); }
|
||||||
|
DECL_ATOMIC_INLINE T atomic_nand_fetch(T& obj, U value, MemoryOrder mem_order = MemoryOrder::memory_order_seq_cst) { return __atomic_nand_fetch(&obj, value, mem_order); }
|
||||||
|
|
||||||
|
DECL_ATOMIC_INLINE T atomic_fetch_add (T& obj, U value, MemoryOrder mem_order = MemoryOrder::memory_order_seq_cst) { return __atomic_fetch_add (&obj, value, mem_order); }
|
||||||
|
DECL_ATOMIC_INLINE T atomic_fetch_sub (T& obj, U value, MemoryOrder mem_order = MemoryOrder::memory_order_seq_cst) { return __atomic_fetch_sub (&obj, value, mem_order); }
|
||||||
|
DECL_ATOMIC_INLINE T atomic_fetch_and (T& obj, U value, MemoryOrder mem_order = MemoryOrder::memory_order_seq_cst) { return __atomic_fetch_and (&obj, value, mem_order); }
|
||||||
|
DECL_ATOMIC_INLINE T atomic_fetch_xor (T& obj, U value, MemoryOrder mem_order = MemoryOrder::memory_order_seq_cst) { return __atomic_fetch_xor (&obj, value, mem_order); }
|
||||||
|
DECL_ATOMIC_INLINE T atomic_fetch_or (T& obj, U value, MemoryOrder mem_order = MemoryOrder::memory_order_seq_cst) { return __atomic_fetch_or (&obj, value, mem_order); }
|
||||||
|
DECL_ATOMIC_INLINE T atomic_fetch_nand(T& obj, U value, MemoryOrder mem_order = MemoryOrder::memory_order_seq_cst) { return __atomic_fetch_nand(&obj, value, mem_order); }
|
||||||
|
#undef DECL_ATOMIC_INLINE
|
||||||
|
|
||||||
|
template<atomic_lockfree_c T, MemoryOrder MEM_ORDER = MemoryOrder::memory_order_seq_cst>
|
||||||
class Atomic
|
class Atomic
|
||||||
{
|
{
|
||||||
Atomic(const Atomic&) = delete;
|
Atomic(const Atomic&) = delete;
|
||||||
@@ -26,26 +56,41 @@ namespace BAN
|
|||||||
constexpr Atomic() : m_value(0) {}
|
constexpr Atomic() : m_value(0) {}
|
||||||
constexpr Atomic(T val) : m_value(val) {}
|
constexpr Atomic(T val) : m_value(val) {}
|
||||||
|
|
||||||
inline T load(MemoryOrder mem_order = MEM_ORDER) const volatile { return __atomic_load_n(&m_value, mem_order); }
|
inline T load(MemoryOrder mem_order = MEM_ORDER) const volatile { return atomic_load(m_value, mem_order); }
|
||||||
inline void store(T val, MemoryOrder mem_order = MEM_ORDER) volatile { __atomic_store_n(&m_value, val, mem_order); }
|
inline void store(T val, MemoryOrder mem_order = MEM_ORDER) volatile { atomic_store(m_value, val, mem_order); }
|
||||||
|
|
||||||
inline T operator=(T val) volatile { store(val); return val; }
|
inline T operator=(T val) volatile { store(val); return val; }
|
||||||
|
|
||||||
inline operator T() const volatile { return load(); }
|
inline operator T() const volatile { return load(); }
|
||||||
|
|
||||||
inline T operator+=(T val) volatile { return __atomic_add_fetch(&m_value, val, MEM_ORDER); }
|
inline T operator+=(T val) volatile { return atomic_add_fetch(m_value, val, MEM_ORDER); }
|
||||||
inline T operator-=(T val) volatile { return __atomic_sub_fetch(&m_value, val, MEM_ORDER); }
|
inline T operator-=(T val) volatile { return atomic_sub_fetch(m_value, val, MEM_ORDER); }
|
||||||
inline T operator&=(T val) volatile { return __atomic_and_fetch(&m_value, val, MEM_ORDER); }
|
inline T operator&=(T val) volatile { return atomic_and_fetch(m_value, val, MEM_ORDER); }
|
||||||
inline T operator^=(T val) volatile { return __atomic_xor_fetch(&m_value, val, MEM_ORDER); }
|
inline T operator^=(T val) volatile { return atomic_xor_fetch(m_value, val, MEM_ORDER); }
|
||||||
inline T operator|=(T val) volatile { return __atomic_or_fetch(&m_value, val, MEM_ORDER); }
|
inline T operator|=(T val) volatile { return atomic_or_fetch(m_value, val, MEM_ORDER); }
|
||||||
|
|
||||||
inline T operator--() volatile { return __atomic_sub_fetch(&m_value, 1, MEM_ORDER); }
|
inline T operator--() volatile { return atomic_sub_fetch(m_value, 1, MEM_ORDER); }
|
||||||
inline T operator++() volatile { return __atomic_add_fetch(&m_value, 1, MEM_ORDER); }
|
inline T operator++() volatile { return atomic_add_fetch(m_value, 1, MEM_ORDER); }
|
||||||
|
|
||||||
inline T operator--(int) volatile { return __atomic_fetch_sub(&m_value, 1, MEM_ORDER); }
|
inline T operator--(int) volatile { return atomic_fetch_sub(m_value, 1, MEM_ORDER); }
|
||||||
inline T operator++(int) volatile { return __atomic_fetch_add(&m_value, 1, MEM_ORDER); }
|
inline T operator++(int) volatile { return atomic_fetch_add(m_value, 1, MEM_ORDER); }
|
||||||
|
|
||||||
inline bool compare_exchange(T expected, T desired, MemoryOrder mem_order = MEM_ORDER) volatile { return __atomic_compare_exchange_n(&m_value, &expected, desired, false, mem_order, mem_order); }
|
inline bool compare_exchange(T& expected, T desired, MemoryOrder mem_order = MEM_ORDER) volatile { return atomic_compare_exchange(m_value, expected, desired, mem_order); }
|
||||||
|
inline T exchange(T desired, MemoryOrder mem_order = MEM_ORDER) volatile { return atomic_exchange(m_value, desired, mem_order); };
|
||||||
|
|
||||||
|
inline T add_fetch (T val, MemoryOrder mem_order = MEM_ORDER) volatile { return atomic_add_fetch (m_value, val, mem_order); }
|
||||||
|
inline T sub_fetch (T val, MemoryOrder mem_order = MEM_ORDER) volatile { return atomic_sub_fetch (m_value, val, mem_order); }
|
||||||
|
inline T and_fetch (T val, MemoryOrder mem_order = MEM_ORDER) volatile { return atomic_and_fetch (m_value, val, mem_order); }
|
||||||
|
inline T xor_fetch (T val, MemoryOrder mem_order = MEM_ORDER) volatile { return atomic_xor_fetch (m_value, val, mem_order); }
|
||||||
|
inline T or_fetch (T val, MemoryOrder mem_order = MEM_ORDER) volatile { return atomic_or_fetch (m_value, val, mem_order); }
|
||||||
|
inline T nand_fetch(T val, MemoryOrder mem_order = MEM_ORDER) volatile { return atomic_nand_fetch(m_value, val, mem_order); }
|
||||||
|
|
||||||
|
inline T fetch_add (T val, MemoryOrder mem_order = MEM_ORDER) volatile { return atomic_fetch_add (m_value, val, mem_order); }
|
||||||
|
inline T fetch_sub (T val, MemoryOrder mem_order = MEM_ORDER) volatile { return atomic_fetch_sub (m_value, val, mem_order); }
|
||||||
|
inline T fetch_and (T val, MemoryOrder mem_order = MEM_ORDER) volatile { return atomic_fetch_and (m_value, val, mem_order); }
|
||||||
|
inline T fetch_xor (T val, MemoryOrder mem_order = MEM_ORDER) volatile { return atomic_fetch_xor (m_value, val, mem_order); }
|
||||||
|
inline T fetch_or (T val, MemoryOrder mem_order = MEM_ORDER) volatile { return atomic_fetch_or (m_value, val, mem_order); }
|
||||||
|
inline T fetch_nand(T val, MemoryOrder mem_order = MEM_ORDER) volatile { return atomic_fetch_nand(m_value, val, mem_order); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
T m_value;
|
T m_value;
|
||||||
|
|||||||
@@ -21,60 +21,56 @@ namespace BAN
|
|||||||
, m_size(size)
|
, m_size(size)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
ByteSpanGeneral(ByteSpanGeneral& other)
|
template<bool SRC_CONST>
|
||||||
|
ByteSpanGeneral(const ByteSpanGeneral<SRC_CONST>& other) requires(CONST || !SRC_CONST)
|
||||||
: m_data(other.data())
|
: m_data(other.data())
|
||||||
, m_size(other.size())
|
, m_size(other.size())
|
||||||
{ }
|
{ }
|
||||||
template<bool C2>
|
template<bool SRC_CONST>
|
||||||
ByteSpanGeneral(const ByteSpanGeneral<C2>& other) requires(CONST)
|
ByteSpanGeneral(ByteSpanGeneral<SRC_CONST>&& other) requires(CONST || !SRC_CONST)
|
||||||
: m_data(other.data())
|
: m_data(other.data())
|
||||||
, m_size(other.size())
|
, m_size(other.size())
|
||||||
{ }
|
{
|
||||||
ByteSpanGeneral(Span<uint8_t> other)
|
other.clear();
|
||||||
: 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)
|
template<typename T>
|
||||||
|
ByteSpanGeneral(const Span<T>& other) requires(is_same_v<T, uint8_t> || (is_same_v<T, const uint8_t> && CONST))
|
||||||
|
: m_data(other.data())
|
||||||
|
, m_size(other.size())
|
||||||
|
{ }
|
||||||
|
template<typename T>
|
||||||
|
ByteSpanGeneral(Span<T>&& other) requires(is_same_v<T, uint8_t> || (is_same_v<T, const uint8_t> && CONST))
|
||||||
|
: m_data(other.data())
|
||||||
|
, m_size(other.size())
|
||||||
|
{
|
||||||
|
other.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<bool SRC_CONST>
|
||||||
|
ByteSpanGeneral& operator=(const ByteSpanGeneral<SRC_CONST>& other) requires(CONST || !SRC_CONST)
|
||||||
{
|
{
|
||||||
m_data = other.data();
|
m_data = other.data();
|
||||||
m_size = other.size();
|
m_size = other.size();
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
template<bool C2>
|
template<bool SRC_CONST>
|
||||||
ByteSpanGeneral& operator=(const ByteSpanGeneral<C2>& other) requires(CONST)
|
ByteSpanGeneral& operator=(ByteSpanGeneral<SRC_CONST>&& other) requires(CONST || !SRC_CONST)
|
||||||
{
|
|
||||||
m_data = other.data();
|
|
||||||
m_size = other.size();
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
ByteSpanGeneral& operator=(Span<uint8_t> other)
|
|
||||||
{
|
|
||||||
m_data = other.data();
|
|
||||||
m_size = other.size();
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
ByteSpanGeneral& operator=(const Span<const uint8_t>& other) requires(CONST)
|
|
||||||
{
|
{
|
||||||
m_data = other.data();
|
m_data = other.data();
|
||||||
m_size = other.size();
|
m_size = other.size();
|
||||||
|
other.clear();
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename S>
|
template<typename S>
|
||||||
requires(CONST || !is_const_v<S>)
|
static ByteSpanGeneral from(S& value) requires(CONST || !is_const_v<S>)
|
||||||
static ByteSpanGeneral from(S& value)
|
|
||||||
{
|
{
|
||||||
return ByteSpanGeneral(reinterpret_cast<value_type*>(&value), sizeof(S));
|
return ByteSpanGeneral(reinterpret_cast<value_type*>(&value), sizeof(S));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename S>
|
template<typename S>
|
||||||
requires(!CONST && !is_const_v<S>)
|
S& as() const requires(!CONST || is_const_v<S>)
|
||||||
S& as()
|
|
||||||
{
|
{
|
||||||
ASSERT(m_data);
|
ASSERT(m_data);
|
||||||
ASSERT(m_size >= sizeof(S));
|
ASSERT(m_size >= sizeof(S));
|
||||||
@@ -82,30 +78,13 @@ namespace BAN
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename S>
|
template<typename S>
|
||||||
requires(is_const_v<S>)
|
Span<S> as_span() const requires(!CONST || is_const_v<S>)
|
||||||
S& as() const
|
|
||||||
{
|
|
||||||
ASSERT(m_data);
|
|
||||||
ASSERT(m_size >= sizeof(S));
|
|
||||||
return *reinterpret_cast<S*>(m_data);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename S>
|
|
||||||
requires(!CONST && !is_const_v<S>)
|
|
||||||
Span<S> as_span()
|
|
||||||
{
|
{
|
||||||
ASSERT(m_data);
|
ASSERT(m_data);
|
||||||
return Span<S>(reinterpret_cast<S*>(m_data), m_size / sizeof(S));
|
return Span<S>(reinterpret_cast<S*>(m_data), m_size / sizeof(S));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename S>
|
[[nodiscard]] ByteSpanGeneral slice(size_type offset, size_type length = size_type(-1)) const
|
||||||
const Span<S> as_span() const
|
|
||||||
{
|
|
||||||
ASSERT(m_data);
|
|
||||||
return Span<S>(reinterpret_cast<S*>(m_data), m_size / sizeof(S));
|
|
||||||
}
|
|
||||||
|
|
||||||
ByteSpanGeneral slice(size_type offset, size_type length = size_type(-1))
|
|
||||||
{
|
{
|
||||||
ASSERT(m_data);
|
ASSERT(m_data);
|
||||||
ASSERT(m_size >= offset);
|
ASSERT(m_size >= offset);
|
||||||
@@ -115,25 +94,28 @@ namespace BAN
|
|||||||
return ByteSpanGeneral(m_data + offset, length);
|
return ByteSpanGeneral(m_data + offset, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
value_type& operator[](size_type offset)
|
value_type& operator[](size_type offset) const
|
||||||
{
|
|
||||||
ASSERT(offset < m_size);
|
|
||||||
return m_data[offset];
|
|
||||||
}
|
|
||||||
const value_type& operator[](size_type offset) const
|
|
||||||
{
|
{
|
||||||
ASSERT(offset < m_size);
|
ASSERT(offset < m_size);
|
||||||
return m_data[offset];
|
return m_data[offset];
|
||||||
}
|
}
|
||||||
|
|
||||||
value_type* data() { return m_data; }
|
value_type* data() const { return m_data; }
|
||||||
const value_type* data() const { return m_data; }
|
|
||||||
|
|
||||||
|
bool empty() const { return m_size == 0; }
|
||||||
size_type size() const { return m_size; }
|
size_type size() const { return m_size; }
|
||||||
|
|
||||||
|
void clear()
|
||||||
|
{
|
||||||
|
m_data = nullptr;
|
||||||
|
m_size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
value_type* m_data { nullptr };
|
value_type* m_data { nullptr };
|
||||||
size_type m_size { 0 };
|
size_type m_size { 0 };
|
||||||
|
|
||||||
|
friend class ByteSpanGeneral<!CONST>;
|
||||||
};
|
};
|
||||||
|
|
||||||
using ByteSpan = ByteSpanGeneral<false>;
|
using ByteSpan = ByteSpanGeneral<false>;
|
||||||
|
|||||||
@@ -24,13 +24,21 @@ namespace BAN
|
|||||||
void push(const T&);
|
void push(const T&);
|
||||||
void push(T&&);
|
void push(T&&);
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
void emplace(Args&&... args);
|
void emplace(Args&&... args) requires is_constructible_v<T, Args...>;
|
||||||
|
|
||||||
void pop();
|
void pop();
|
||||||
|
|
||||||
const T& front() const;
|
const T& front() const;
|
||||||
T& front();
|
T& front();
|
||||||
|
|
||||||
|
const T& back() const;
|
||||||
|
T& back();
|
||||||
|
|
||||||
|
const T& operator[](size_t index) const;
|
||||||
|
T& operator[](size_t index);
|
||||||
|
|
||||||
|
void clear();
|
||||||
|
|
||||||
size_type size() const { return m_size; }
|
size_type size() const { return m_size; }
|
||||||
bool empty() const { return size() == 0; }
|
bool empty() const { return size() == 0; }
|
||||||
bool full() const { return size() == capacity(); }
|
bool full() const { return size() == capacity(); }
|
||||||
@@ -50,8 +58,7 @@ namespace BAN
|
|||||||
template<typename T, size_t S>
|
template<typename T, size_t S>
|
||||||
CircularQueue<T, S>::~CircularQueue()
|
CircularQueue<T, S>::~CircularQueue()
|
||||||
{
|
{
|
||||||
for (size_type i = 0; i < m_size; i++)
|
clear();
|
||||||
element_at((m_first + i) % capacity())->~T();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, size_t S>
|
template<typename T, size_t S>
|
||||||
@@ -68,7 +75,7 @@ namespace BAN
|
|||||||
|
|
||||||
template<typename T, size_t S>
|
template<typename T, size_t S>
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
void CircularQueue<T, S>::emplace(Args&&... args)
|
void CircularQueue<T, S>::emplace(Args&&... args) requires is_constructible_v<T, Args...>
|
||||||
{
|
{
|
||||||
ASSERT(!full());
|
ASSERT(!full());
|
||||||
new (element_at(((m_first + m_size) % capacity()))) T(BAN::forward<Args>(args)...);
|
new (element_at(((m_first + m_size) % capacity()))) T(BAN::forward<Args>(args)...);
|
||||||
@@ -98,6 +105,42 @@ namespace BAN
|
|||||||
return *element_at(m_first);
|
return *element_at(m_first);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename T, size_t S>
|
||||||
|
const T& CircularQueue<T, S>::back() const
|
||||||
|
{
|
||||||
|
ASSERT(!empty());
|
||||||
|
return *element_at((m_first + m_size - 1) % capacity());
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T, size_t S>
|
||||||
|
T& CircularQueue<T, S>::back()
|
||||||
|
{
|
||||||
|
ASSERT(!empty());
|
||||||
|
return *element_at((m_first + m_size - 1) % capacity());
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T, size_t S>
|
||||||
|
const T& CircularQueue<T, S>::operator[](size_t index) const
|
||||||
|
{
|
||||||
|
ASSERT(index < m_size);
|
||||||
|
return *element_at((m_first + index) % capacity());
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T, size_t S>
|
||||||
|
T& CircularQueue<T, S>::operator[](size_t index)
|
||||||
|
{
|
||||||
|
ASSERT(index < m_size);
|
||||||
|
return *element_at((m_first + index) % capacity());
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T, size_t S>
|
||||||
|
void CircularQueue<T, S>::clear()
|
||||||
|
{
|
||||||
|
for (size_type i = 0; i < m_size; i++)
|
||||||
|
element_at((m_first + i) % capacity())->~T();
|
||||||
|
m_size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
template<typename T, size_t S>
|
template<typename T, size_t S>
|
||||||
const T* CircularQueue<T, S>::element_at(size_type index) const
|
const T* CircularQueue<T, S>::element_at(size_type index) const
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -9,27 +9,53 @@
|
|||||||
#include <BAN/Formatter.h>
|
#include <BAN/Formatter.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
#define __debug_putchar [](int c) { putc(c, stddbg); }
|
#define __debug_putchar [](int c) { putc_unlocked(c, stddbg); }
|
||||||
|
|
||||||
#define dprintln(...) \
|
#define dprintln(...) \
|
||||||
do { \
|
do { \
|
||||||
|
flockfile(stddbg); \
|
||||||
BAN::Formatter::print(__debug_putchar, __VA_ARGS__); \
|
BAN::Formatter::print(__debug_putchar, __VA_ARGS__); \
|
||||||
BAN::Formatter::print(__debug_putchar,"\r\n"); \
|
BAN::Formatter::print(__debug_putchar,"\n"); \
|
||||||
fflush(stddbg); \
|
fflush(stddbg); \
|
||||||
|
funlockfile(stddbg); \
|
||||||
} while (false)
|
} while (false)
|
||||||
|
|
||||||
#define dwarnln(...) \
|
#define dwarnln(...) \
|
||||||
do { \
|
do { \
|
||||||
BAN::Formatter::print(__debug_putchar, "\e[33m"); \
|
flockfile(stddbg); \
|
||||||
dprintln(__VA_ARGS__); \
|
BAN::Formatter::print(__debug_putchar, "\e[33m"); \
|
||||||
BAN::Formatter::print(__debug_putchar, "\e[m"); \
|
BAN::Formatter::print(__debug_putchar, __VA_ARGS__); \
|
||||||
|
BAN::Formatter::print(__debug_putchar, "\e[m\n"); \
|
||||||
|
fflush(stddbg); \
|
||||||
|
funlockfile(stddbg); \
|
||||||
} while(false)
|
} while(false)
|
||||||
|
|
||||||
#define derrorln(...) \
|
#define derrorln(...) \
|
||||||
do { \
|
do { \
|
||||||
BAN::Formatter::print(__debug_putchar, "\e[31m"); \
|
flockfile(stddbg); \
|
||||||
dprintln(__VA_ARGS__); \
|
BAN::Formatter::print(__debug_putchar, "\e[31m"); \
|
||||||
BAN::Formatter::print(__debug_putchar, "\e[m"); \
|
BAN::Formatter::print(__debug_putchar, __VA_ARGS__); \
|
||||||
|
BAN::Formatter::print(__debug_putchar, "\e[m\n"); \
|
||||||
|
fflush(stddbg); \
|
||||||
|
funlockfile(stddbg); \
|
||||||
|
} while(false)
|
||||||
|
|
||||||
|
#define dprintln_if(cond, ...) \
|
||||||
|
do { \
|
||||||
|
if constexpr(cond) \
|
||||||
|
dprintln(__VA_ARGS__); \
|
||||||
|
} while(false)
|
||||||
|
|
||||||
|
#define dwarnln_if(cond, ...) \
|
||||||
|
do { \
|
||||||
|
if constexpr(cond) \
|
||||||
|
dwarnln(__VA_ARGS__); \
|
||||||
|
} while(false)
|
||||||
|
|
||||||
|
#define derrorln_if(cond, ...) \
|
||||||
|
do { \
|
||||||
|
if constexpr(cond) \
|
||||||
|
derrorln(__VA_ARGS__); \
|
||||||
} while(false)
|
} while(false)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -45,6 +45,12 @@ namespace BAN
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<integral T>
|
||||||
|
constexpr T little_endian_to_host(T value)
|
||||||
|
{
|
||||||
|
return host_to_little_endian(value);
|
||||||
|
}
|
||||||
|
|
||||||
template<integral T>
|
template<integral T>
|
||||||
constexpr T host_to_big_endian(T value)
|
constexpr T host_to_big_endian(T value)
|
||||||
{
|
{
|
||||||
@@ -55,18 +61,28 @@ namespace BAN
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<integral T>
|
||||||
|
constexpr T big_endian_to_host(T value)
|
||||||
|
{
|
||||||
|
return host_to_big_endian(value);
|
||||||
|
}
|
||||||
|
|
||||||
template<integral T>
|
template<integral T>
|
||||||
struct LittleEndian
|
struct LittleEndian
|
||||||
{
|
{
|
||||||
|
constexpr LittleEndian()
|
||||||
|
: raw(0)
|
||||||
|
{ }
|
||||||
|
|
||||||
constexpr LittleEndian(T value)
|
constexpr LittleEndian(T value)
|
||||||
{
|
: raw(host_to_little_endian(value))
|
||||||
raw = host_to_little_endian(value);
|
{ }
|
||||||
}
|
|
||||||
|
|
||||||
constexpr operator T() const
|
constexpr operator T() const
|
||||||
{
|
{
|
||||||
return host_to_little_endian(raw);
|
return host_to_little_endian(raw);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
T raw;
|
T raw;
|
||||||
};
|
};
|
||||||
@@ -74,15 +90,19 @@ namespace BAN
|
|||||||
template<integral T>
|
template<integral T>
|
||||||
struct BigEndian
|
struct BigEndian
|
||||||
{
|
{
|
||||||
|
constexpr BigEndian()
|
||||||
|
: raw(0)
|
||||||
|
{ }
|
||||||
|
|
||||||
constexpr BigEndian(T value)
|
constexpr BigEndian(T value)
|
||||||
{
|
: raw(host_to_big_endian(value))
|
||||||
raw = host_to_big_endian(value);
|
{ }
|
||||||
}
|
|
||||||
|
|
||||||
constexpr operator T() const
|
constexpr operator T() const
|
||||||
{
|
{
|
||||||
return host_to_big_endian(raw);
|
return host_to_big_endian(raw);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
T raw;
|
T raw;
|
||||||
};
|
};
|
||||||
@@ -96,4 +116,10 @@ namespace BAN
|
|||||||
return host_to_big_endian(value);
|
return host_to_big_endian(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<integral T>
|
||||||
|
constexpr T network_endian_to_host(T value)
|
||||||
|
{
|
||||||
|
return big_endian_to_host(value);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <BAN/Formatter.h>
|
#include <BAN/Formatter.h>
|
||||||
#include <BAN/StringView.h>
|
#include <BAN/NoCopyMove.h>
|
||||||
#include <BAN/Variant.h>
|
#include <BAN/Variant.h>
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
@@ -10,16 +10,16 @@
|
|||||||
#ifdef __is_kernel
|
#ifdef __is_kernel
|
||||||
#include <kernel/Panic.h>
|
#include <kernel/Panic.h>
|
||||||
#include <kernel/Errors.h>
|
#include <kernel/Errors.h>
|
||||||
#define MUST(expr) ({ auto&& e = expr; if (e.is_error()) Kernel::panic("{}", e.error()); e.release_value(); })
|
#define MUST(...) ({ auto&& e = (__VA_ARGS__); if (e.is_error()) Kernel::panic("{}", e.error()); e.release_value(); })
|
||||||
#define MUST_REF(expr) *({ auto&& e = expr; if (e.is_error()) Kernel::panic("{}", e.error()); &e.release_value(); })
|
#define MUST_REF(...) *({ auto&& e = (__VA_ARGS__); if (e.is_error()) Kernel::panic("{}", e.error()); &e.release_value(); })
|
||||||
#else
|
#else
|
||||||
#include <assert.h>
|
#include <BAN/Debug.h>
|
||||||
#define MUST(expr) ({ auto&& e = expr; assert(!e.is_error()); e.release_value(); })
|
#define MUST(...) ({ auto&& e = (__VA_ARGS__); if (e.is_error()) { derrorln("MUST(" #__VA_ARGS__ "): {}", e.error()); __builtin_trap(); } e.release_value(); })
|
||||||
#define MUST_REF(expr) *({ auto&& e = expr; assert(!e.is_error()); &e.release_value(); })
|
#define MUST_REF(...) *({ auto&& e = (__VA_ARGS__); if (e.is_error()) { derrorln("MUST(" #__VA_ARGS__ "): {}", e.error()); __builtin_trap(); } &e.release_value(); })
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define TRY(expr) ({ auto&& e = expr; if (e.is_error()) return e.release_error(); e.release_value(); })
|
#define TRY(...) ({ auto&& e = (__VA_ARGS__); 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(); })
|
#define TRY_REF(...) *({ auto&& e = (__VA_ARGS__); if (e.is_error()) return e.release_error(); &e.release_value(); })
|
||||||
|
|
||||||
namespace BAN
|
namespace BAN
|
||||||
{
|
{
|
||||||
@@ -37,7 +37,14 @@ namespace BAN
|
|||||||
{
|
{
|
||||||
return Error((uint64_t)error | kernel_error_mask);
|
return Error((uint64_t)error | kernel_error_mask);
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
template<size_t N>
|
||||||
|
consteval static Error from_literal(const char (&message)[N])
|
||||||
|
{
|
||||||
|
return Error(message);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static Error from_errno(int error)
|
static Error from_errno(int error)
|
||||||
{
|
{
|
||||||
return Error(error);
|
return Error(error);
|
||||||
@@ -55,29 +62,43 @@ namespace BAN
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
uint64_t get_error_code() const { return m_error_code; }
|
constexpr uint64_t get_error_code() const { return m_error_code; }
|
||||||
BAN::StringView get_message() const
|
const char* get_message() const
|
||||||
{
|
{
|
||||||
#ifdef __is_kernel
|
#ifdef __is_kernel
|
||||||
if (m_error_code & kernel_error_mask)
|
if (m_error_code & kernel_error_mask)
|
||||||
return Kernel::error_string(kernel_error());
|
return Kernel::error_string(kernel_error());
|
||||||
|
#else
|
||||||
|
if (m_message)
|
||||||
|
return m_message;
|
||||||
#endif
|
#endif
|
||||||
if (auto* desc = strerrordesc_np(m_error_code))
|
if (auto* desc = strerrordesc_np(m_error_code))
|
||||||
return desc;
|
return desc;
|
||||||
return "Unknown error"sv;
|
return "Unknown error";
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Error(uint64_t error)
|
constexpr Error(uint64_t error)
|
||||||
: m_error_code(error)
|
: m_error_code(error)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
uint64_t m_error_code;
|
#ifndef __is_kernel
|
||||||
|
constexpr Error(const char* message)
|
||||||
|
: m_message(message)
|
||||||
|
{}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
uint64_t m_error_code { 0 };
|
||||||
|
|
||||||
|
#ifndef __is_kernel
|
||||||
|
const char* m_message { nullptr };
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
class [[nodiscard]] ErrorOr
|
class [[nodiscard]] ErrorOr
|
||||||
{
|
{
|
||||||
|
BAN_NON_COPYABLE(ErrorOr);
|
||||||
public:
|
public:
|
||||||
ErrorOr(const T& value)
|
ErrorOr(const T& value)
|
||||||
: m_data(value)
|
: m_data(value)
|
||||||
@@ -91,6 +112,14 @@ namespace BAN
|
|||||||
ErrorOr(Error&& error)
|
ErrorOr(Error&& error)
|
||||||
: m_data(move(error))
|
: m_data(move(error))
|
||||||
{}
|
{}
|
||||||
|
ErrorOr(ErrorOr&& other)
|
||||||
|
: m_data(move(other.m_data))
|
||||||
|
{}
|
||||||
|
ErrorOr& operator=(ErrorOr&& other)
|
||||||
|
{
|
||||||
|
m_data = move(other.m_data);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
bool is_error() const { return m_data.template has<Error>(); }
|
bool is_error() const { return m_data.template has<Error>(); }
|
||||||
const Error& error() const { return m_data.template get<Error>(); }
|
const Error& error() const { return m_data.template get<Error>(); }
|
||||||
|
|||||||
@@ -10,22 +10,19 @@ namespace BAN::Formatter
|
|||||||
|
|
||||||
struct ValueFormat;
|
struct ValueFormat;
|
||||||
|
|
||||||
template<typename F>
|
|
||||||
static void print(F putc, const char* format);
|
|
||||||
|
|
||||||
template<typename F, typename Arg, typename... Args>
|
|
||||||
static void print(F putc, const char* format, Arg&& arg, Args&&... args);
|
|
||||||
|
|
||||||
template<typename F, typename... Args>
|
template<typename F, typename... Args>
|
||||||
static void println(F putc, const char* format, Args&&... args);
|
concept PrintableArguments = requires(F putc, Args&&... args, const ValueFormat& format)
|
||||||
|
{
|
||||||
|
(print_argument(putc, BAN::forward<Args>(args), format), ...);
|
||||||
|
};
|
||||||
|
|
||||||
template<typename F, typename T>
|
template<typename F, typename T>
|
||||||
static void print_argument(F putc, T value, const ValueFormat& format);
|
inline void print_argument(F putc, T value, const ValueFormat& format);
|
||||||
|
|
||||||
namespace detail
|
namespace detail
|
||||||
{
|
{
|
||||||
template<typename F, typename T>
|
template<typename F, typename T>
|
||||||
static size_t parse_format_and_print_argument(F putc, const char* format, T&& arg);
|
inline size_t parse_format_and_print_argument(F putc, const char* format, T&& arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -39,11 +36,12 @@ namespace BAN::Formatter
|
|||||||
int base = 10;
|
int base = 10;
|
||||||
int percision = 3;
|
int percision = 3;
|
||||||
int fill = 0;
|
int fill = 0;
|
||||||
|
char fill_char = '0';
|
||||||
bool upper = false;
|
bool upper = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename F>
|
template<typename F>
|
||||||
void print(F putc, const char* format)
|
inline void print(F putc, const char* format)
|
||||||
{
|
{
|
||||||
while (*format)
|
while (*format)
|
||||||
{
|
{
|
||||||
@@ -52,8 +50,8 @@ namespace BAN::Formatter
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename F, typename Arg, typename... Args>
|
template<typename F, typename Arg, typename... Args> requires PrintableArguments<F, Arg, Args...>
|
||||||
void print(F putc, const char* format, Arg&& arg, Args&&... args)
|
inline void print(F putc, const char* format, Arg&& arg, Args&&... args)
|
||||||
{
|
{
|
||||||
while (*format && *format != '{')
|
while (*format && *format != '{')
|
||||||
{
|
{
|
||||||
@@ -71,7 +69,7 @@ namespace BAN::Formatter
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename F, typename... Args>
|
template<typename F, typename... Args>
|
||||||
void println(F putc, const char* format, Args&&... args)
|
inline void println(F putc, const char* format, Args&&... args)
|
||||||
{
|
{
|
||||||
print(putc, format, args...);
|
print(putc, format, args...);
|
||||||
putc('\n');
|
putc('\n');
|
||||||
@@ -81,7 +79,7 @@ namespace BAN::Formatter
|
|||||||
{
|
{
|
||||||
|
|
||||||
template<typename F, typename Arg>
|
template<typename F, typename Arg>
|
||||||
size_t parse_format_and_print_argument(F putc, const char* format, Arg&& argument)
|
inline size_t parse_format_and_print_argument(F putc, const char* format, Arg&& argument)
|
||||||
{
|
{
|
||||||
ValueFormat value_format;
|
ValueFormat value_format;
|
||||||
|
|
||||||
@@ -94,6 +92,12 @@ namespace BAN::Formatter
|
|||||||
if (!format[i] || format[i] == '}')
|
if (!format[i] || format[i] == '}')
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
if (format[i] == ' ')
|
||||||
|
{
|
||||||
|
value_format.fill_char = ' ';
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
if ('0' <= format[i] && format[i] <= '9')
|
if ('0' <= format[i] && format[i] <= '9')
|
||||||
{
|
{
|
||||||
int fill = 0;
|
int fill = 0;
|
||||||
@@ -143,7 +147,7 @@ namespace BAN::Formatter
|
|||||||
return i + 1;
|
return i + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char value_to_base_char(uint8_t value, int base, bool upper)
|
inline char value_to_base_char(uint8_t value, int base, bool upper)
|
||||||
{
|
{
|
||||||
if (base <= 10)
|
if (base <= 10)
|
||||||
return value + '0';
|
return value + '0';
|
||||||
@@ -157,12 +161,13 @@ namespace BAN::Formatter
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename F, typename T>
|
template<typename F, typename T>
|
||||||
void print_integer(F putc, T value, const ValueFormat& format)
|
inline void print_integer(F putc, T value, const ValueFormat& format)
|
||||||
{
|
{
|
||||||
if (value == 0)
|
if (value == 0)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < format.fill || i < 1; i++)
|
for (int i = 0; i < format.fill - 1; i++)
|
||||||
putc('0');
|
putc(format.fill_char);
|
||||||
|
putc('0');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -188,7 +193,7 @@ namespace BAN::Formatter
|
|||||||
}
|
}
|
||||||
|
|
||||||
while (ptr >= buffer + sizeof(buffer) - format.fill)
|
while (ptr >= buffer + sizeof(buffer) - format.fill)
|
||||||
*(--ptr) = '0';
|
*(--ptr) = format.fill_char;
|
||||||
|
|
||||||
if (sign)
|
if (sign)
|
||||||
*(--ptr) = '-';
|
*(--ptr) = '-';
|
||||||
@@ -197,12 +202,16 @@ namespace BAN::Formatter
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename F, typename T>
|
template<typename F, typename T>
|
||||||
void print_floating(F putc, T value, const ValueFormat& format)
|
inline void print_floating(F putc, T value, const ValueFormat& format)
|
||||||
{
|
{
|
||||||
|
if (value < 0)
|
||||||
|
{
|
||||||
|
putc('-');
|
||||||
|
return print_floating(putc, -value, format);
|
||||||
|
}
|
||||||
|
|
||||||
int64_t int_part = (int64_t)value;
|
int64_t int_part = (int64_t)value;
|
||||||
T frac_part = value - (T)int_part;
|
T frac_part = value - (T)int_part;
|
||||||
if (frac_part < 0)
|
|
||||||
frac_part = -frac_part;
|
|
||||||
|
|
||||||
print_integer(putc, int_part, format);
|
print_integer(putc, int_part, format);
|
||||||
|
|
||||||
@@ -220,7 +229,7 @@ namespace BAN::Formatter
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename F>
|
template<typename F>
|
||||||
void print_pointer(F putc, void* ptr, const ValueFormat& format)
|
inline void print_pointer(F putc, void* ptr, const ValueFormat& format)
|
||||||
{
|
{
|
||||||
uintptr_t value = (uintptr_t)ptr;
|
uintptr_t value = (uintptr_t)ptr;
|
||||||
print(putc, "0x");
|
print(putc, "0x");
|
||||||
@@ -236,13 +245,13 @@ namespace BAN::Formatter
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
template<typename F, integral T> void print_argument(F putc, T value, const ValueFormat& format) { detail::print_integer(putc, value, format); }
|
template<typename F, integral T> inline void print_argument(F putc, T value, const ValueFormat& format) { detail::print_integer(putc, value, format); }
|
||||||
template<typename F, floating_point T> void print_argument(F putc, T value, const ValueFormat& format) { detail::print_floating(putc, value, format); }
|
template<typename F, floating_point T> inline void print_argument(F putc, T value, const ValueFormat& format) { detail::print_floating(putc, value, format); }
|
||||||
template<typename F, pointer T> void print_argument(F putc, T value, const ValueFormat& format) { detail::print_pointer(putc, (void*)value, format); }
|
template<typename F, pointer T> inline void print_argument(F putc, T value, const ValueFormat& format) { detail::print_pointer(putc, (void*)value, format); }
|
||||||
|
|
||||||
template<typename F> void print_argument(F putc, char value, const ValueFormat&) { putc(value); }
|
template<typename F> inline 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> inline 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> inline 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); }
|
template<typename F> inline void print_argument(F putc, char* value, const ValueFormat&) { print(putc, value); }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,19 +20,19 @@ namespace BAN
|
|||||||
new (m_storage) CallablePointer(function);
|
new (m_storage) CallablePointer(function);
|
||||||
}
|
}
|
||||||
template<typename Own>
|
template<typename Own>
|
||||||
Function(Ret(Own::*function)(Args...), Own* owner)
|
Function(Ret(Own::*function)(Args...), Own& owner)
|
||||||
{
|
{
|
||||||
static_assert(sizeof(CallableMember<Own>) <= m_size);
|
static_assert(sizeof(CallableMember<Own>) <= m_size);
|
||||||
new (m_storage) CallableMember<Own>(function, owner);
|
new (m_storage) CallableMember<Own>(function, owner);
|
||||||
}
|
}
|
||||||
template<typename Own>
|
template<typename Own>
|
||||||
Function(Ret(Own::*function)(Args...) const, const Own* owner)
|
Function(Ret(Own::*function)(Args...) const, const Own& owner)
|
||||||
{
|
{
|
||||||
static_assert(sizeof(CallableMemberConst<Own>) <= m_size);
|
static_assert(sizeof(CallableMemberConst<Own>) <= m_size);
|
||||||
new (m_storage) CallableMemberConst<Own>(function, owner);
|
new (m_storage) CallableMemberConst<Own>(function, owner);
|
||||||
}
|
}
|
||||||
template<typename Lambda>
|
template<typename Lambda>
|
||||||
Function(Lambda lambda)
|
Function(Lambda lambda) requires requires(Lambda lamda, Args&&... args) { { lambda(forward<Args>(args)...) } -> BAN::same_as<Ret>; }
|
||||||
{
|
{
|
||||||
static_assert(sizeof(CallableLambda<Lambda>) <= m_size);
|
static_assert(sizeof(CallableLambda<Lambda>) <= m_size);
|
||||||
new (m_storage) CallableLambda<Lambda>(lambda);
|
new (m_storage) CallableLambda<Lambda>(lambda);
|
||||||
@@ -91,36 +91,36 @@ namespace BAN
|
|||||||
template<typename Own>
|
template<typename Own>
|
||||||
struct CallableMember : public CallableBase
|
struct CallableMember : public CallableBase
|
||||||
{
|
{
|
||||||
CallableMember(Ret(Own::*function)(Args...), Own* owner)
|
CallableMember(Ret(Own::*function)(Args...), Own& owner)
|
||||||
: m_owner(owner)
|
: m_owner(owner)
|
||||||
, m_function(function)
|
, m_function(function)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
virtual Ret call(Args... args) const override
|
virtual Ret call(Args... args) const override
|
||||||
{
|
{
|
||||||
return (m_owner->*m_function)(forward<Args>(args)...);
|
return (m_owner.*m_function)(forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Own* m_owner = nullptr;
|
Own& m_owner;
|
||||||
Ret(Own::*m_function)(Args...) = nullptr;
|
Ret(Own::*m_function)(Args...) = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename Own>
|
template<typename Own>
|
||||||
struct CallableMemberConst : public CallableBase
|
struct CallableMemberConst : public CallableBase
|
||||||
{
|
{
|
||||||
CallableMemberConst(Ret(Own::*function)(Args...) const, const Own* owner)
|
CallableMemberConst(Ret(Own::*function)(Args...) const, const Own& owner)
|
||||||
: m_owner(owner)
|
: m_owner(owner)
|
||||||
, m_function(function)
|
, m_function(function)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
virtual Ret call(Args... args) const override
|
virtual Ret call(Args... args) const override
|
||||||
{
|
{
|
||||||
return (m_owner->*m_function)(forward<Args>(args)...);
|
return (m_owner.*m_function)(forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const Own* m_owner = nullptr;
|
const Own& m_owner;
|
||||||
Ret(Own::*m_function)(Args...) const = nullptr;
|
Ret(Own::*m_function)(Args...) const = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -141,7 +141,7 @@ namespace BAN
|
|||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static constexpr size_t m_size = sizeof(void*) * 5;
|
static constexpr size_t m_size = sizeof(void*) * 8;
|
||||||
alignas(CallableBase) uint8_t m_storage[m_size] { 0 };
|
alignas(CallableBase) uint8_t m_storage[m_size] { 0 };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <BAN/Optional.h>
|
#include <BAN/Optional.h>
|
||||||
#include <BAN/StringView.h>
|
#include <BAN/String.h>
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
@@ -19,6 +19,54 @@ namespace BAN
|
|||||||
{
|
{
|
||||||
return memcmp(this, &other, sizeof(GUID)) == 0;
|
return memcmp(this, &other, sizeof(GUID)) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BAN::ErrorOr<BAN::String> to_string() const
|
||||||
|
{
|
||||||
|
char buffer[37];
|
||||||
|
char* ptr = buffer;
|
||||||
|
|
||||||
|
const auto append_hex_nibble =
|
||||||
|
[&ptr](uint8_t nibble)
|
||||||
|
{
|
||||||
|
if (nibble < 10)
|
||||||
|
*ptr++ = '0' + nibble;
|
||||||
|
else
|
||||||
|
*ptr++ = 'A' + nibble - 10;
|
||||||
|
};
|
||||||
|
|
||||||
|
const auto append_hex_byte =
|
||||||
|
[&append_hex_nibble](uint8_t byte)
|
||||||
|
{
|
||||||
|
append_hex_nibble(byte >> 4);
|
||||||
|
append_hex_nibble(byte & 0xF);
|
||||||
|
};
|
||||||
|
|
||||||
|
append_hex_byte((component1 >> 24) & 0xFF);
|
||||||
|
append_hex_byte((component1 >> 16) & 0xFF);
|
||||||
|
append_hex_byte((component1 >> 8) & 0xFF);
|
||||||
|
append_hex_byte((component1 >> 0) & 0xFF);
|
||||||
|
*ptr++ = '-';
|
||||||
|
append_hex_byte((component2 >> 8) & 0xFF);
|
||||||
|
append_hex_byte((component2 >> 0) & 0xFF);
|
||||||
|
*ptr++ = '-';
|
||||||
|
append_hex_byte((component3 >> 8) & 0xFF);
|
||||||
|
append_hex_byte((component3 >> 0) & 0xFF);
|
||||||
|
*ptr++ = '-';
|
||||||
|
append_hex_byte(component45[0]);
|
||||||
|
append_hex_byte(component45[1]);
|
||||||
|
*ptr++ = '-';
|
||||||
|
append_hex_byte(component45[2]);
|
||||||
|
append_hex_byte(component45[3]);
|
||||||
|
append_hex_byte(component45[4]);
|
||||||
|
append_hex_byte(component45[5]);
|
||||||
|
append_hex_byte(component45[6]);
|
||||||
|
append_hex_byte(component45[7]);
|
||||||
|
*ptr = '\0';
|
||||||
|
|
||||||
|
BAN::String guid;
|
||||||
|
TRY(guid.append(buffer));
|
||||||
|
return BAN::move(guid);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
static_assert(sizeof(GUID) == 16);
|
static_assert(sizeof(GUID) == 16);
|
||||||
|
|
||||||
|
|||||||
@@ -14,11 +14,17 @@ namespace BAN
|
|||||||
struct Entry
|
struct Entry
|
||||||
{
|
{
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
Entry(const Key& key, Args&&... args)
|
Entry(const Key& key, Args&&... args) requires is_constructible_v<T, Args...>
|
||||||
: key(key)
|
: key(key)
|
||||||
, value(forward<Args>(args)...)
|
, value(forward<Args>(args)...)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
template<typename... Args>
|
||||||
|
Entry(Key&& key, Args&&... args) requires is_constructible_v<T, Args...>
|
||||||
|
: key(BAN::move(key))
|
||||||
|
, value(forward<Args>(args)...)
|
||||||
|
{}
|
||||||
|
|
||||||
Key key;
|
Key key;
|
||||||
T value;
|
T value;
|
||||||
};
|
};
|
||||||
@@ -39,10 +45,27 @@ namespace BAN
|
|||||||
HashMap<Key, T, HASH>& operator=(const HashMap<Key, T, HASH>&);
|
HashMap<Key, T, HASH>& operator=(const HashMap<Key, T, HASH>&);
|
||||||
HashMap<Key, T, HASH>& operator=(HashMap<Key, T, HASH>&&);
|
HashMap<Key, T, HASH>& operator=(HashMap<Key, T, HASH>&&);
|
||||||
|
|
||||||
ErrorOr<void> insert(const Key&, const T&);
|
ErrorOr<iterator> insert(const Key& key, const T& value) { return emplace(key, value); }
|
||||||
ErrorOr<void> insert(const Key&, T&&);
|
ErrorOr<iterator> insert(const Key& key, T&& value) { return emplace(key, move(value)); }
|
||||||
|
ErrorOr<iterator> insert(Key&& key, const T& value) { return emplace(move(key), value); }
|
||||||
|
ErrorOr<iterator> insert(Key&& key, T&& value) { return emplace(move(key), move(value)); }
|
||||||
|
|
||||||
|
ErrorOr<iterator> insert_or_assign(const Key& key, const T& value) { return emplace_or_assign(key, value); }
|
||||||
|
ErrorOr<iterator> insert_or_assign(const Key& key, T&& value) { return emplace_or_assign(key, move(value)); }
|
||||||
|
ErrorOr<iterator> insert_or_assign(Key&& key, const T& value) { return emplace_or_assign(move(key), value); }
|
||||||
|
ErrorOr<iterator> insert_or_assign(Key&& key, T&& value) { return emplace_or_assign(move(key), move(value)); }
|
||||||
|
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
ErrorOr<void> emplace(const Key&, Args&&...);
|
ErrorOr<iterator> emplace(const Key& key, Args&&... args) requires is_constructible_v<T, Args...>
|
||||||
|
{ return emplace(Key(key), forward<Args>(args)...); }
|
||||||
|
template<typename... Args>
|
||||||
|
ErrorOr<iterator> emplace(Key&&, Args&&...) requires is_constructible_v<T, Args...>;
|
||||||
|
|
||||||
|
template<typename... Args>
|
||||||
|
ErrorOr<iterator> emplace_or_assign(const Key& key, Args&&... args) requires is_constructible_v<T, Args...>
|
||||||
|
{ return emplace_or_assign(Key(key), forward<Args>(args)...); }
|
||||||
|
template<typename... Args>
|
||||||
|
ErrorOr<iterator> emplace_or_assign(Key&&, Args&&...) requires is_constructible_v<T, Args...>;
|
||||||
|
|
||||||
iterator begin() { return iterator(m_buckets.end(), m_buckets.begin()); }
|
iterator begin() { return iterator(m_buckets.end(), m_buckets.begin()); }
|
||||||
iterator end() { return iterator(m_buckets.end(), m_buckets.end()); }
|
iterator end() { return iterator(m_buckets.end(), m_buckets.end()); }
|
||||||
@@ -117,27 +140,36 @@ namespace BAN
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename Key, typename T, typename HASH>
|
template<typename Key, typename T, typename HASH>
|
||||||
ErrorOr<void> HashMap<Key, T, HASH>::insert(const Key& key, const T& value)
|
template<typename... Args>
|
||||||
|
ErrorOr<typename HashMap<Key, T, HASH>::iterator> HashMap<Key, T, HASH>::emplace(Key&& key, Args&&... args) requires is_constructible_v<T, Args...>
|
||||||
{
|
{
|
||||||
return insert(key, move(T(value)));
|
ASSERT(!contains(key));
|
||||||
}
|
TRY(rebucket(m_size + 1));
|
||||||
|
|
||||||
template<typename Key, typename T, typename HASH>
|
auto bucket_it = get_bucket_iterator(key);
|
||||||
ErrorOr<void> HashMap<Key, T, HASH>::insert(const Key& key, T&& value)
|
TRY(bucket_it->emplace_back(move(key), forward<Args>(args)...));
|
||||||
{
|
m_size++;
|
||||||
return emplace(key, move(value));
|
|
||||||
|
return iterator(m_buckets.end(), bucket_it, prev(bucket_it->end(), 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Key, typename T, typename HASH>
|
template<typename Key, typename T, typename HASH>
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
ErrorOr<void> HashMap<Key, T, HASH>::emplace(const Key& key, Args&&... args)
|
ErrorOr<typename HashMap<Key, T, HASH>::iterator> HashMap<Key, T, HASH>::emplace_or_assign(Key&& key, Args&&... args) requires is_constructible_v<T, Args...>
|
||||||
{
|
{
|
||||||
ASSERT(!contains(key));
|
if (empty())
|
||||||
TRY(rebucket(m_size + 1));
|
return emplace(move(key), forward<Args>(args)...);
|
||||||
auto& bucket = get_bucket(key);
|
|
||||||
TRY(bucket.emplace_back(key, forward<Args>(args)...));
|
auto bucket_it = get_bucket_iterator(key);
|
||||||
m_size++;
|
for (auto entry_it = bucket_it->begin(); entry_it != bucket_it->end(); entry_it++)
|
||||||
return {};
|
{
|
||||||
|
if (entry_it->key != key)
|
||||||
|
continue;
|
||||||
|
entry_it->value = T(forward<Args>(args)...);
|
||||||
|
return iterator(m_buckets.end(), bucket_it, entry_it);
|
||||||
|
}
|
||||||
|
|
||||||
|
return emplace(move(key), forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Key, typename T, typename HASH>
|
template<typename Key, typename T, typename HASH>
|
||||||
@@ -177,7 +209,7 @@ namespace BAN
|
|||||||
for (Entry& entry : bucket)
|
for (Entry& entry : bucket)
|
||||||
if (entry.key == key)
|
if (entry.key == key)
|
||||||
return entry.value;
|
return entry.value;
|
||||||
ASSERT(false);
|
ASSERT_NOT_REACHED();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Key, typename T, typename HASH>
|
template<typename Key, typename T, typename HASH>
|
||||||
@@ -188,7 +220,7 @@ namespace BAN
|
|||||||
for (const Entry& entry : bucket)
|
for (const Entry& entry : bucket)
|
||||||
if (entry.key == key)
|
if (entry.key == key)
|
||||||
return entry.value;
|
return entry.value;
|
||||||
ASSERT(false);
|
ASSERT_NOT_REACHED();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Key, typename T, typename HASH>
|
template<typename Key, typename T, typename HASH>
|
||||||
|
|||||||
89
BAN/include/BAN/Heap.h
Normal file
89
BAN/include/BAN/Heap.h
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <BAN/Iterators.h>
|
||||||
|
#include <BAN/Swap.h>
|
||||||
|
#include <BAN/Traits.h>
|
||||||
|
|
||||||
|
namespace BAN
|
||||||
|
{
|
||||||
|
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
|
|
||||||
|
template<typename It, typename Comp>
|
||||||
|
void heapify_up(It begin, size_t index, Comp comp)
|
||||||
|
{
|
||||||
|
size_t parent = (index - 1) / 2;
|
||||||
|
while (parent < index)
|
||||||
|
{
|
||||||
|
if (comp(*(begin + index), *(begin + parent)))
|
||||||
|
break;
|
||||||
|
swap(*(begin + parent), *(begin + index));
|
||||||
|
index = parent;
|
||||||
|
parent = (index - 1) / 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename It, typename Comp>
|
||||||
|
void heapify_down(It begin, size_t index, size_t len, Comp comp)
|
||||||
|
{
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
const size_t lchild = 2 * index + 1;
|
||||||
|
const size_t rchild = 2 * index + 2;
|
||||||
|
|
||||||
|
size_t child = 0;
|
||||||
|
if (lchild < len && !comp(*(begin + lchild), *(begin + index)))
|
||||||
|
{
|
||||||
|
if (rchild < len && !comp(*(begin + rchild), *(begin + lchild)))
|
||||||
|
child = rchild;
|
||||||
|
else
|
||||||
|
child = lchild;
|
||||||
|
}
|
||||||
|
else if (rchild < len && !comp(*(begin + rchild), *(begin + index)))
|
||||||
|
child = rchild;
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
|
||||||
|
swap(*(begin + child), *(begin + index));
|
||||||
|
index = child;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename It, typename Comp = less<it_value_type_t<It>>>
|
||||||
|
void make_heap(It begin, It end, Comp comp = {})
|
||||||
|
{
|
||||||
|
const size_t len = distance(begin, end);
|
||||||
|
if (len <= 1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
size_t index = (len - 2) / 2;
|
||||||
|
while (index < len)
|
||||||
|
detail::heapify_down(begin, index--, len, comp);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename It, typename Comp = less<it_value_type_t<It>>>
|
||||||
|
void push_heap(It begin, It end, Comp comp = {})
|
||||||
|
{
|
||||||
|
const size_t len = distance(begin, end);
|
||||||
|
detail::heapify_up(begin, len - 1, comp);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename It, typename Comp = less<it_value_type_t<It>>>
|
||||||
|
void pop_heap(It begin, It end, Comp comp = {})
|
||||||
|
{
|
||||||
|
const size_t len = distance(begin, end);
|
||||||
|
swap(*begin, *(begin + len - 1));
|
||||||
|
detail::heapify_down(begin, 0, len - 1, comp);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename It, typename Comp = less<it_value_type_t<It>>>
|
||||||
|
void sort_heap(It begin, It end, Comp comp = {})
|
||||||
|
{
|
||||||
|
while (begin != end)
|
||||||
|
pop_heap(begin, end--, comp);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -9,6 +9,10 @@ namespace BAN
|
|||||||
|
|
||||||
struct IPv4Address
|
struct IPv4Address
|
||||||
{
|
{
|
||||||
|
constexpr IPv4Address()
|
||||||
|
: IPv4Address(0)
|
||||||
|
{ }
|
||||||
|
|
||||||
constexpr IPv4Address(uint32_t u32_address)
|
constexpr IPv4Address(uint32_t u32_address)
|
||||||
{
|
{
|
||||||
raw = u32_address;
|
raw = u32_address;
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ namespace BAN
|
|||||||
{
|
{
|
||||||
|
|
||||||
template<typename It>
|
template<typename It>
|
||||||
It next(It it, size_t count)
|
constexpr It next(It it, size_t count)
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i < count; i++)
|
for (size_t i = 0; i < count; i++)
|
||||||
++it;
|
++it;
|
||||||
@@ -18,13 +18,13 @@ namespace BAN
|
|||||||
|
|
||||||
template<typename It>
|
template<typename It>
|
||||||
requires requires(It it, size_t n) { requires is_same_v<decltype(it + n), It>; }
|
requires requires(It it, size_t n) { requires is_same_v<decltype(it + n), It>; }
|
||||||
It next(It it, size_t count)
|
constexpr It next(It it, size_t count)
|
||||||
{
|
{
|
||||||
return it + count;
|
return it + count;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename It>
|
template<typename It>
|
||||||
It prev(It it, size_t count)
|
constexpr It prev(It it, size_t count)
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i < count; i++)
|
for (size_t i = 0; i < count; i++)
|
||||||
--it;
|
--it;
|
||||||
@@ -33,13 +33,13 @@ namespace BAN
|
|||||||
|
|
||||||
template<typename It>
|
template<typename It>
|
||||||
requires requires(It it, size_t n) { requires is_same_v<decltype(it - n), It>; }
|
requires requires(It it, size_t n) { requires is_same_v<decltype(it - n), It>; }
|
||||||
It prev(It it, size_t count)
|
constexpr It prev(It it, size_t count)
|
||||||
{
|
{
|
||||||
return it - count;
|
return it - count;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename It>
|
template<typename It>
|
||||||
size_t distance(It it1, It it2)
|
constexpr size_t distance(It it1, It it2)
|
||||||
{
|
{
|
||||||
size_t dist = 0;
|
size_t dist = 0;
|
||||||
while (it1 != it2)
|
while (it1 != it2)
|
||||||
@@ -52,7 +52,7 @@ namespace BAN
|
|||||||
|
|
||||||
template<typename It>
|
template<typename It>
|
||||||
requires requires(It it1, It it2) { requires is_integral_v<decltype(it2 - it1)>; }
|
requires requires(It it1, It it2) { requires is_integral_v<decltype(it2 - it1)>; }
|
||||||
size_t distance(It it1, It it2)
|
constexpr size_t distance(It it1, It it2)
|
||||||
{
|
{
|
||||||
return it2 - it1;
|
return it2 - it1;
|
||||||
}
|
}
|
||||||
@@ -64,109 +64,109 @@ namespace BAN
|
|||||||
using value_type = T;
|
using value_type = T;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
IteratorSimpleGeneral() = default;
|
constexpr IteratorSimpleGeneral() = default;
|
||||||
template<bool CONST2, typename = enable_if_t<CONST2 == CONST || CONST>>
|
template<bool CONST2, typename = enable_if_t<CONST2 == CONST || CONST>>
|
||||||
IteratorSimpleGeneral(const IteratorSimpleGeneral<T, Container, CONST2>& other)
|
constexpr IteratorSimpleGeneral(const IteratorSimpleGeneral<T, Container, CONST2>& other)
|
||||||
: m_pointer(other.m_pointer)
|
: m_pointer(other.m_pointer)
|
||||||
, m_valid(other.m_valid)
|
, m_valid(other.m_valid)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
const T& operator*() const
|
constexpr const T& operator*() const
|
||||||
{
|
{
|
||||||
ASSERT(m_pointer);
|
ASSERT(m_pointer);
|
||||||
return *m_pointer;
|
return *m_pointer;
|
||||||
}
|
}
|
||||||
template<bool CONST2 = CONST>
|
template<bool CONST2 = CONST>
|
||||||
enable_if_t<!CONST2, T&> operator*()
|
constexpr enable_if_t<!CONST2, T&> operator*()
|
||||||
{
|
{
|
||||||
ASSERT(*this);
|
ASSERT(*this);
|
||||||
ASSERT(m_pointer);
|
ASSERT(m_pointer);
|
||||||
return *m_pointer;
|
return *m_pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
const T* operator->() const
|
constexpr const T* operator->() const
|
||||||
{
|
{
|
||||||
ASSERT(*this);
|
ASSERT(*this);
|
||||||
ASSERT(m_pointer);
|
ASSERT(m_pointer);
|
||||||
return m_pointer;
|
return m_pointer;
|
||||||
}
|
}
|
||||||
template<bool CONST2 = CONST>
|
template<bool CONST2 = CONST>
|
||||||
enable_if_t<!CONST2, T*> operator->()
|
constexpr enable_if_t<!CONST2, T*> operator->()
|
||||||
{
|
{
|
||||||
ASSERT(*this);
|
ASSERT(*this);
|
||||||
ASSERT(m_pointer);
|
ASSERT(m_pointer);
|
||||||
return m_pointer;
|
return m_pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
IteratorSimpleGeneral& operator++()
|
constexpr IteratorSimpleGeneral& operator++()
|
||||||
{
|
{
|
||||||
ASSERT(*this);
|
ASSERT(*this);
|
||||||
ASSERT(m_pointer);
|
ASSERT(m_pointer);
|
||||||
++m_pointer;
|
++m_pointer;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
IteratorSimpleGeneral operator++(int)
|
constexpr IteratorSimpleGeneral operator++(int)
|
||||||
{
|
{
|
||||||
auto temp = *this;
|
auto temp = *this;
|
||||||
++(*this);
|
++(*this);
|
||||||
return temp;
|
return temp;
|
||||||
}
|
}
|
||||||
|
|
||||||
IteratorSimpleGeneral& operator--()
|
constexpr IteratorSimpleGeneral& operator--()
|
||||||
{
|
{
|
||||||
ASSERT(*this);
|
ASSERT(*this);
|
||||||
ASSERT(m_pointer);
|
ASSERT(m_pointer);
|
||||||
--m_pointer;
|
--m_pointer;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
IteratorSimpleGeneral operator--(int)
|
constexpr IteratorSimpleGeneral operator--(int)
|
||||||
{
|
{
|
||||||
auto temp = *this;
|
auto temp = *this;
|
||||||
--(*this);
|
--(*this);
|
||||||
return temp;
|
return temp;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t operator-(const IteratorSimpleGeneral& other) const
|
constexpr size_t operator-(const IteratorSimpleGeneral& other) const
|
||||||
{
|
{
|
||||||
ASSERT(*this && other);
|
ASSERT(*this && other);
|
||||||
return m_pointer - other.m_pointer;
|
return m_pointer - other.m_pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
IteratorSimpleGeneral operator+(size_t offset) const
|
constexpr IteratorSimpleGeneral operator+(size_t offset) const
|
||||||
{
|
{
|
||||||
return IteratorSimpleGeneral(m_pointer + offset);
|
return IteratorSimpleGeneral(m_pointer + offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
IteratorSimpleGeneral operator-(size_t offset) const
|
constexpr IteratorSimpleGeneral operator-(size_t offset) const
|
||||||
{
|
{
|
||||||
return IteratorSimpleGeneral(m_pointer - offset);
|
return IteratorSimpleGeneral(m_pointer - offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator<(const IteratorSimpleGeneral& other) const
|
constexpr bool operator<(const IteratorSimpleGeneral& other) const
|
||||||
{
|
{
|
||||||
ASSERT(*this);
|
ASSERT(*this);
|
||||||
return m_pointer < other.m_pointer;
|
return m_pointer < other.m_pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator==(const IteratorSimpleGeneral& other) const
|
constexpr bool operator==(const IteratorSimpleGeneral& other) const
|
||||||
{
|
{
|
||||||
ASSERT(*this);
|
ASSERT(*this);
|
||||||
return m_pointer == other.m_pointer;
|
return m_pointer == other.m_pointer;
|
||||||
}
|
}
|
||||||
bool operator!=(const IteratorSimpleGeneral& other) const
|
constexpr bool operator!=(const IteratorSimpleGeneral& other) const
|
||||||
{
|
{
|
||||||
ASSERT(*this);
|
ASSERT(*this);
|
||||||
return !(*this == other);
|
return !(*this == other);
|
||||||
}
|
}
|
||||||
|
|
||||||
explicit operator bool() const
|
constexpr explicit operator bool() const
|
||||||
{
|
{
|
||||||
return m_valid;
|
return m_valid;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
IteratorSimpleGeneral(maybe_const_t<CONST, T>* pointer)
|
constexpr IteratorSimpleGeneral(maybe_const_t<CONST, T>* pointer)
|
||||||
: m_pointer(pointer)
|
: m_pointer(pointer)
|
||||||
, m_valid(true)
|
, m_valid(true)
|
||||||
{
|
{
|
||||||
@@ -193,16 +193,16 @@ namespace BAN
|
|||||||
using value_type = T;
|
using value_type = T;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
IteratorDoubleGeneral() = default;
|
constexpr IteratorDoubleGeneral() = default;
|
||||||
template<bool CONST2, typename = enable_if_t<CONST2 == CONST || CONST>>
|
template<bool CONST2, typename = enable_if_t<CONST2 == CONST || CONST>>
|
||||||
IteratorDoubleGeneral(const IteratorDoubleGeneral<T, OuterContainer, InnerContainer, Container, CONST2>& other)
|
constexpr IteratorDoubleGeneral(const IteratorDoubleGeneral<T, OuterContainer, InnerContainer, Container, CONST2>& other)
|
||||||
: m_outer_end(other.m_outer_end)
|
: m_outer_end(other.m_outer_end)
|
||||||
, m_outer_current(other.m_outer_current)
|
, m_outer_current(other.m_outer_current)
|
||||||
, m_inner_current(other.m_inner_current)
|
, m_inner_current(other.m_inner_current)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
const T& operator*() const
|
constexpr const T& operator*() const
|
||||||
{
|
{
|
||||||
ASSERT(*this);
|
ASSERT(*this);
|
||||||
ASSERT(m_outer_current != m_outer_end);
|
ASSERT(m_outer_current != m_outer_end);
|
||||||
@@ -210,7 +210,7 @@ namespace BAN
|
|||||||
return m_inner_current.operator*();
|
return m_inner_current.operator*();
|
||||||
}
|
}
|
||||||
template<bool CONST2 = CONST>
|
template<bool CONST2 = CONST>
|
||||||
enable_if_t<!CONST2, T&> operator*()
|
constexpr enable_if_t<!CONST2, T&> operator*()
|
||||||
{
|
{
|
||||||
ASSERT(*this);
|
ASSERT(*this);
|
||||||
ASSERT(m_outer_current != m_outer_end);
|
ASSERT(m_outer_current != m_outer_end);
|
||||||
@@ -218,7 +218,7 @@ namespace BAN
|
|||||||
return m_inner_current.operator*();
|
return m_inner_current.operator*();
|
||||||
}
|
}
|
||||||
|
|
||||||
const T* operator->() const
|
constexpr const T* operator->() const
|
||||||
{
|
{
|
||||||
ASSERT(*this);
|
ASSERT(*this);
|
||||||
ASSERT(m_outer_current != m_outer_end);
|
ASSERT(m_outer_current != m_outer_end);
|
||||||
@@ -226,7 +226,7 @@ namespace BAN
|
|||||||
return m_inner_current.operator->();
|
return m_inner_current.operator->();
|
||||||
}
|
}
|
||||||
template<bool CONST2 = CONST>
|
template<bool CONST2 = CONST>
|
||||||
enable_if_t<!CONST2, T*> operator->()
|
constexpr enable_if_t<!CONST2, T*> operator->()
|
||||||
{
|
{
|
||||||
ASSERT(*this);
|
ASSERT(*this);
|
||||||
ASSERT(m_outer_current != m_outer_end);
|
ASSERT(m_outer_current != m_outer_end);
|
||||||
@@ -234,7 +234,7 @@ namespace BAN
|
|||||||
return m_inner_current.operator->();
|
return m_inner_current.operator->();
|
||||||
}
|
}
|
||||||
|
|
||||||
IteratorDoubleGeneral& operator++()
|
constexpr IteratorDoubleGeneral& operator++()
|
||||||
{
|
{
|
||||||
ASSERT(*this);
|
ASSERT(*this);
|
||||||
ASSERT(m_outer_current != m_outer_end);
|
ASSERT(m_outer_current != m_outer_end);
|
||||||
@@ -243,14 +243,14 @@ namespace BAN
|
|||||||
find_valid_or_end();
|
find_valid_or_end();
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
IteratorDoubleGeneral operator++(int)
|
constexpr IteratorDoubleGeneral operator++(int)
|
||||||
{
|
{
|
||||||
auto temp = *this;
|
auto temp = *this;
|
||||||
++(*this);
|
++(*this);
|
||||||
return temp;
|
return temp;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator==(const IteratorDoubleGeneral& other) const
|
constexpr bool operator==(const IteratorDoubleGeneral& other) const
|
||||||
{
|
{
|
||||||
ASSERT(*this && other);
|
ASSERT(*this && other);
|
||||||
if (m_outer_end != other.m_outer_end)
|
if (m_outer_end != other.m_outer_end)
|
||||||
@@ -262,18 +262,18 @@ namespace BAN
|
|||||||
ASSERT(m_inner_current && other.m_inner_current);
|
ASSERT(m_inner_current && other.m_inner_current);
|
||||||
return m_inner_current == other.m_inner_current;
|
return m_inner_current == other.m_inner_current;
|
||||||
}
|
}
|
||||||
bool operator!=(const IteratorDoubleGeneral& other) const
|
constexpr bool operator!=(const IteratorDoubleGeneral& other) const
|
||||||
{
|
{
|
||||||
return !(*this == other);
|
return !(*this == other);
|
||||||
}
|
}
|
||||||
|
|
||||||
explicit operator bool() const
|
constexpr explicit operator bool() const
|
||||||
{
|
{
|
||||||
return !!m_outer_current;
|
return !!m_outer_current;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
IteratorDoubleGeneral(const OuterIterator& outer_end, const OuterIterator& outer_current)
|
constexpr IteratorDoubleGeneral(const OuterIterator& outer_end, const OuterIterator& outer_current)
|
||||||
: m_outer_end(outer_end)
|
: m_outer_end(outer_end)
|
||||||
, m_outer_current(outer_current)
|
, m_outer_current(outer_current)
|
||||||
{
|
{
|
||||||
@@ -284,7 +284,7 @@ namespace BAN
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
IteratorDoubleGeneral(const OuterIterator& outer_end, const OuterIterator& outer_current, const InnerIterator& inner_current)
|
constexpr IteratorDoubleGeneral(const OuterIterator& outer_end, const OuterIterator& outer_current, const InnerIterator& inner_current)
|
||||||
: m_outer_end(outer_end)
|
: m_outer_end(outer_end)
|
||||||
, m_outer_current(outer_current)
|
, m_outer_current(outer_current)
|
||||||
, m_inner_current(inner_current)
|
, m_inner_current(inner_current)
|
||||||
@@ -292,7 +292,7 @@ namespace BAN
|
|||||||
find_valid_or_end();
|
find_valid_or_end();
|
||||||
}
|
}
|
||||||
|
|
||||||
void find_valid_or_end()
|
constexpr void find_valid_or_end()
|
||||||
{
|
{
|
||||||
while (m_inner_current == m_outer_current->end())
|
while (m_inner_current == m_outer_current->end())
|
||||||
{
|
{
|
||||||
@@ -303,8 +303,8 @@ namespace BAN
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
OuterIterator outer_current() { return m_outer_current; }
|
constexpr OuterIterator outer_current() { return m_outer_current; }
|
||||||
InnerIterator inner_current() { return m_inner_current; }
|
constexpr InnerIterator inner_current() { return m_inner_current; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
OuterIterator m_outer_end;
|
OuterIterator m_outer_end;
|
||||||
|
|||||||
@@ -34,9 +34,9 @@ namespace BAN
|
|||||||
ErrorOr<void> insert(iterator, const T&);
|
ErrorOr<void> insert(iterator, const T&);
|
||||||
ErrorOr<void> insert(iterator, T&&);
|
ErrorOr<void> insert(iterator, T&&);
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
ErrorOr<void> emplace_back(Args&&...);
|
ErrorOr<void> emplace_back(Args&&...) requires is_constructible_v<T, Args...>;
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
ErrorOr<void> emplace(iterator, Args&&...);
|
ErrorOr<void> emplace(iterator, Args&&...) requires is_constructible_v<T, Args...>;
|
||||||
|
|
||||||
void pop_back();
|
void pop_back();
|
||||||
iterator remove(iterator);
|
iterator remove(iterator);
|
||||||
@@ -196,14 +196,14 @@ namespace BAN
|
|||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
ErrorOr<void> LinkedList<T>::emplace_back(Args&&... args)
|
ErrorOr<void> LinkedList<T>::emplace_back(Args&&... args) requires is_constructible_v<T, Args...>
|
||||||
{
|
{
|
||||||
return emplace(end(), forward<Args>(args)...);
|
return emplace(end(), forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
ErrorOr<void> LinkedList<T>::emplace(iterator iter, Args&&... args)
|
ErrorOr<void> LinkedList<T>::emplace(iterator iter, Args&&... args) requires is_constructible_v<T, Args...>
|
||||||
{
|
{
|
||||||
Node* new_node = TRY(allocate_node(forward<Args>(args)...));
|
Node* new_node = TRY(allocate_node(forward<Args>(args)...));
|
||||||
insert_node(iter, new_node);
|
insert_node(iter, new_node);
|
||||||
|
|||||||
46
BAN/include/BAN/MacroUtils.h
Normal file
46
BAN/include/BAN/MacroUtils.h
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#define _ban_count_args_impl(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, ...) _9
|
||||||
|
#define _ban_count_args(...) _ban_count_args_impl(__VA_ARGS__ __VA_OPT__(,) 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
|
||||||
|
|
||||||
|
#define _ban_concat_impl(a, b) a##b
|
||||||
|
#define _ban_concat(a, b) _ban_concat_impl(a, b)
|
||||||
|
|
||||||
|
#define _ban_stringify_impl(x) #x
|
||||||
|
#define _ban_stringify(x) _ban_stringify_impl(x)
|
||||||
|
|
||||||
|
#define _ban_fe_0(f)
|
||||||
|
#define _ban_fe_1(f, _0) f(0, _0)
|
||||||
|
#define _ban_fe_2(f, _0, _1) f(0, _0) f(1, _1)
|
||||||
|
#define _ban_fe_3(f, _0, _1, _2) f(0, _0) f(1, _1) f(2, _2)
|
||||||
|
#define _ban_fe_4(f, _0, _1, _2, _3) f(0, _0) f(1, _1) f(2, _2) f(3, _3)
|
||||||
|
#define _ban_fe_5(f, _0, _1, _2, _3, _4) f(0, _0) f(1, _1) f(2, _2) f(3, _3) f(4, _4)
|
||||||
|
#define _ban_fe_6(f, _0, _1, _2, _3, _4, _5) f(0, _0) f(1, _1) f(2, _2) f(3, _3) f(4, _4) f(5, _5)
|
||||||
|
#define _ban_fe_7(f, _0, _1, _2, _3, _4, _5, _6) f(0, _0) f(1, _1) f(2, _2) f(3, _3) f(4, _4) f(5, _5) f(6, _6)
|
||||||
|
#define _ban_fe_8(f, _0, _1, _2, _3, _4, _5, _6, _7) f(0, _0) f(1, _1) f(2, _2) f(3, _3) f(4, _4) f(5, _5) f(6, _6) f(7, _7)
|
||||||
|
#define _ban_fe_9(f, _0, _1, _2, _3, _4, _5, _6, _7, _8) f(0, _0) f(1, _1) f(2, _2) f(3, _3) f(4, _4) f(5, _5) f(6, _6) f(7, _7) f(8, _8)
|
||||||
|
#define _ban_for_each(f, ...) _ban_concat(_ban_fe_, _ban_count_args(__VA_ARGS__))(f __VA_OPT__(,) __VA_ARGS__)
|
||||||
|
|
||||||
|
#define _ban_fe_comma_0(f)
|
||||||
|
#define _ban_fe_comma_1(f, _0) f(0, _0)
|
||||||
|
#define _ban_fe_comma_2(f, _0, _1) f(0, _0), f(1, _1)
|
||||||
|
#define _ban_fe_comma_3(f, _0, _1, _2) f(0, _0), f(1, _1), f(2, _2)
|
||||||
|
#define _ban_fe_comma_4(f, _0, _1, _2, _3) f(0, _0), f(1, _1), f(2, _2), f(3, _3)
|
||||||
|
#define _ban_fe_comma_5(f, _0, _1, _2, _3, _4) f(0, _0), f(1, _1), f(2, _2), f(3, _3), f(4, _4)
|
||||||
|
#define _ban_fe_comma_6(f, _0, _1, _2, _3, _4, _5) f(0, _0), f(1, _1), f(2, _2), f(3, _3), f(4, _4), f(5, _5)
|
||||||
|
#define _ban_fe_comma_7(f, _0, _1, _2, _3, _4, _5, _6) f(0, _0), f(1, _1), f(2, _2), f(3, _3), f(4, _4), f(5, _5), f(6, _6)
|
||||||
|
#define _ban_fe_comma_8(f, _0, _1, _2, _3, _4, _5, _6, _7) f(0, _0), f(1, _1), f(2, _2), f(3, _3), f(4, _4), f(5, _5), f(6, _6), f(7, _7)
|
||||||
|
#define _ban_fe_comma_9(f, _0, _1, _2, _3, _4, _5, _6, _7, _8) f(0, _0), f(1, _1), f(2, _2), f(3, _3), f(4, _4), f(5, _5), f(6, _6), f(7, _7), f(8, _8)
|
||||||
|
#define _ban_for_each_comma(f, ...) _ban_concat(_ban_fe_comma_, _ban_count_args(__VA_ARGS__))(f __VA_OPT__(,) __VA_ARGS__)
|
||||||
|
|
||||||
|
#define _ban_get_0(a0, ...) a0
|
||||||
|
#define _ban_get_1(a0, a1, ...) a1
|
||||||
|
#define _ban_get_2(a0, a1, a2, ...) a2
|
||||||
|
#define _ban_get_3(a0, a1, a2, a3, ...) a3
|
||||||
|
#define _ban_get_4(a0, a1, a2, a3, a4, ...) a4
|
||||||
|
#define _ban_get_5(a0, a1, a2, a3, a4, a5, ...) a5
|
||||||
|
#define _ban_get_6(a0, a1, a2, a3, a4, a5, a6, ...) a6
|
||||||
|
#define _ban_get_7(a0, a1, a2, a3, a4, a5, a6, a7, ...) a7
|
||||||
|
#define _ban_get_8(a0, a1, a2, a3, a4, a5, a6, a7, a8, ...) a8
|
||||||
|
#define _ban_get_9(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, ...) a9
|
||||||
|
#define _ban_get(n, ...) _ban_concat(_ban_get_, n)(__VA_ARGS__)
|
||||||
@@ -1,17 +1,18 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <BAN/Limits.h>
|
||||||
|
#include <BAN/Numbers.h>
|
||||||
#include <BAN/Traits.h>
|
#include <BAN/Traits.h>
|
||||||
|
|
||||||
#include <stddef.h>
|
#include <float.h>
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
namespace BAN::Math
|
namespace BAN::Math
|
||||||
{
|
{
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
inline constexpr T abs(T val)
|
inline constexpr T abs(T x)
|
||||||
{
|
{
|
||||||
return val < 0 ? -val : val;
|
return x < 0 ? -x : x;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
@@ -35,12 +36,11 @@ namespace BAN::Math
|
|||||||
template<integral T>
|
template<integral T>
|
||||||
inline constexpr T gcd(T a, T b)
|
inline constexpr T gcd(T a, T b)
|
||||||
{
|
{
|
||||||
T t;
|
|
||||||
while (b)
|
while (b)
|
||||||
{
|
{
|
||||||
t = b;
|
T temp = b;
|
||||||
b = a % b;
|
b = a % b;
|
||||||
a = t;
|
a = temp;
|
||||||
}
|
}
|
||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
@@ -58,65 +58,408 @@ namespace BAN::Math
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<integral T>
|
template<integral T>
|
||||||
inline constexpr bool is_power_of_two(T value)
|
inline constexpr bool is_power_of_two(T x)
|
||||||
{
|
{
|
||||||
if (value == 0)
|
if (x == 0)
|
||||||
return false;
|
return false;
|
||||||
return (value & (value - 1)) == 0;
|
return (x & (x - 1)) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<integral T>
|
||||||
|
__attribute__((always_inline))
|
||||||
|
inline constexpr bool will_multiplication_overflow(T a, T b)
|
||||||
|
{
|
||||||
|
T dummy;
|
||||||
|
return __builtin_mul_overflow(a, b, &dummy);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<integral T>
|
||||||
|
__attribute__((always_inline))
|
||||||
|
inline constexpr bool will_addition_overflow(T a, T b)
|
||||||
|
{
|
||||||
|
T dummy;
|
||||||
|
return __builtin_add_overflow(a, b, &dummy);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
requires is_same_v<T, unsigned int> || is_same_v<T, unsigned long> || is_same_v<T, unsigned long long>
|
requires is_same_v<T, unsigned int> || is_same_v<T, unsigned long> || is_same_v<T, unsigned long long>
|
||||||
inline constexpr T ilog2(T value)
|
inline constexpr T ilog2(T x)
|
||||||
{
|
{
|
||||||
if constexpr(is_same_v<T, unsigned int>)
|
if constexpr(is_same_v<T, unsigned int>)
|
||||||
return sizeof(T) * 8 - __builtin_clz(value) - 1;
|
return sizeof(T) * 8 - __builtin_clz(x) - 1;
|
||||||
if constexpr(is_same_v<T, unsigned long>)
|
if constexpr(is_same_v<T, unsigned long>)
|
||||||
return sizeof(T) * 8 - __builtin_clzl(value) - 1;
|
return sizeof(T) * 8 - __builtin_clzl(x) - 1;
|
||||||
return sizeof(T) * 8 - __builtin_clzll(value) - 1;
|
return sizeof(T) * 8 - __builtin_clzll(x) - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is ugly but my clangd does not like including
|
||||||
|
// intrinsic headers at all
|
||||||
|
#if !defined(__SSE__) || !defined(__SSE2__)
|
||||||
|
#pragma GCC push_options
|
||||||
|
#ifndef __SSE__
|
||||||
|
#pragma GCC target("sse")
|
||||||
|
#endif
|
||||||
|
#ifndef __SSE2__
|
||||||
|
#pragma GCC target("sse2")
|
||||||
|
#endif
|
||||||
|
#define BAN_MATH_POP_OPTIONS
|
||||||
|
#endif
|
||||||
|
|
||||||
|
template<floating_point T>
|
||||||
|
inline constexpr T floor(T x)
|
||||||
|
{
|
||||||
|
if constexpr(is_same_v<T, float>)
|
||||||
|
return __builtin_floorf(x);
|
||||||
|
if constexpr(is_same_v<T, double>)
|
||||||
|
return __builtin_floor(x);
|
||||||
|
if constexpr(is_same_v<T, long double>)
|
||||||
|
return __builtin_floorl(x);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<floating_point T>
|
template<floating_point T>
|
||||||
inline constexpr T log2(T value)
|
inline constexpr T ceil(T x)
|
||||||
{
|
{
|
||||||
T result;
|
if constexpr(is_same_v<T, float>)
|
||||||
asm volatile("fyl2x" : "=t"(result) : "0"(value), "u"((T)1.0) : "st(1)");
|
return __builtin_ceilf(x);
|
||||||
return result;
|
if constexpr(is_same_v<T, double>)
|
||||||
|
return __builtin_ceil(x);
|
||||||
|
if constexpr(is_same_v<T, long double>)
|
||||||
|
return __builtin_ceill(x);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<floating_point T>
|
template<floating_point T>
|
||||||
inline constexpr T log10(T value)
|
inline constexpr T round(T x)
|
||||||
{
|
{
|
||||||
constexpr T INV_LOG_2_10 = 0.3010299956639811952137388947244930267681898814621085413104274611;
|
if (x == (T)0.0)
|
||||||
T result;
|
return x;
|
||||||
asm volatile("fyl2x" : "=t"(result) : "0"(value), "u"(INV_LOG_2_10) : "st(1)");
|
if (x > (T)0.0)
|
||||||
return result;
|
return floor<T>(x + (T)0.5);
|
||||||
|
return ceil<T>(x - (T)0.5);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<floating_point T>
|
template<floating_point T>
|
||||||
inline constexpr T log(T value, T base)
|
inline constexpr T trunc(T x)
|
||||||
{
|
{
|
||||||
return log2(value) / log2(base);
|
if constexpr(is_same_v<T, float>)
|
||||||
|
return __builtin_truncf(x);
|
||||||
|
if constexpr(is_same_v<T, double>)
|
||||||
|
return __builtin_trunc(x);
|
||||||
|
if constexpr(is_same_v<T, long double>)
|
||||||
|
return __builtin_truncl(x);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<floating_point T>
|
template<floating_point T>
|
||||||
inline constexpr T pow(T base, T exp)
|
inline constexpr T rint(T x)
|
||||||
{
|
{
|
||||||
T result;
|
asm("frndint" : "+t"(x));
|
||||||
asm volatile(
|
return x;
|
||||||
"fyl2x;"
|
}
|
||||||
|
|
||||||
|
template<floating_point T>
|
||||||
|
inline constexpr T fmod(T a, T b)
|
||||||
|
{
|
||||||
|
asm(
|
||||||
|
"1:"
|
||||||
|
"fprem;"
|
||||||
|
"fnstsw %%ax;"
|
||||||
|
"testb $4, %%ah;"
|
||||||
|
"jne 1b;"
|
||||||
|
: "+t"(a)
|
||||||
|
: "u"(b)
|
||||||
|
: "ax", "cc"
|
||||||
|
);
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<floating_point T>
|
||||||
|
inline constexpr T remainder(T a, T b)
|
||||||
|
{
|
||||||
|
asm(
|
||||||
|
"1:"
|
||||||
|
"fprem1;"
|
||||||
|
"fnstsw %%ax;"
|
||||||
|
"testb $4, %%ah;"
|
||||||
|
"jne 1b;"
|
||||||
|
: "+t"(a)
|
||||||
|
: "u"(b)
|
||||||
|
: "ax", "cc"
|
||||||
|
);
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<floating_point T>
|
||||||
|
static T modf(T x, T* iptr)
|
||||||
|
{
|
||||||
|
const T frac = BAN::Math::fmod<T>(x, (T)1.0);
|
||||||
|
*iptr = x - frac;
|
||||||
|
return frac;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<floating_point T>
|
||||||
|
inline constexpr T frexp(T num, int* exp)
|
||||||
|
{
|
||||||
|
if (num == (T)0.0)
|
||||||
|
{
|
||||||
|
*exp = 0;
|
||||||
|
return (T)0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
T e;
|
||||||
|
asm("fxtract" : "+t"(num), "=u"(e));
|
||||||
|
*exp = (int)e + 1;
|
||||||
|
return num / (T)2.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<floating_point T>
|
||||||
|
inline constexpr T copysign(T x, T y)
|
||||||
|
{
|
||||||
|
if ((x < (T)0.0) != (y < (T)0.0))
|
||||||
|
x = -x;
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
|
|
||||||
|
template<floating_point T>
|
||||||
|
inline constexpr T fyl2x(T x, T y)
|
||||||
|
{
|
||||||
|
asm("fyl2x" : "+t"(x) : "u"(y) : "st(1)");
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
template<floating_point T>
|
||||||
|
inline constexpr T log(T x)
|
||||||
|
{
|
||||||
|
return detail::fyl2x<T>(x, numbers::ln2_v<T>);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<floating_point T>
|
||||||
|
inline constexpr T log2(T x)
|
||||||
|
{
|
||||||
|
return detail::fyl2x<T>(x, 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<floating_point T>
|
||||||
|
inline constexpr T log10(T x)
|
||||||
|
{
|
||||||
|
return detail::fyl2x<T>(x, numbers::lg2_v<T>);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<floating_point T>
|
||||||
|
inline constexpr T logb(T x)
|
||||||
|
{
|
||||||
|
static_assert(FLT_RADIX == 2);
|
||||||
|
return log2<T>(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<floating_point T>
|
||||||
|
inline constexpr T exp2(T x)
|
||||||
|
{
|
||||||
|
if (abs(x) <= (T)1.0)
|
||||||
|
{
|
||||||
|
asm("f2xm1" : "+t"(x));
|
||||||
|
return x + (T)1.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
asm(
|
||||||
"fld1;"
|
"fld1;"
|
||||||
"fld %%st(1);"
|
"fld %%st(1);"
|
||||||
"fprem;"
|
"fprem;"
|
||||||
"f2xm1;"
|
"f2xm1;"
|
||||||
"faddp;"
|
"faddp;"
|
||||||
"fscale;"
|
"fscale;"
|
||||||
"fxch %%st(1);"
|
"fstp %%st(1);"
|
||||||
"fstp %%st;"
|
: "+t"(x)
|
||||||
: "=t"(result)
|
|
||||||
: "0"(base), "u"(exp)
|
|
||||||
);
|
);
|
||||||
return result;
|
|
||||||
|
return x;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<floating_point T>
|
||||||
|
inline constexpr T exp(T x)
|
||||||
|
{
|
||||||
|
return exp2<T>(x * numbers::log2e_v<T>);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<floating_point T>
|
||||||
|
inline constexpr T pow(T x, T y)
|
||||||
|
{
|
||||||
|
if (x == (T)0.0)
|
||||||
|
return (T)0.0;
|
||||||
|
return exp2<T>(y * log2<T>(x));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<floating_point T>
|
||||||
|
inline constexpr T scalbn(T x, int n)
|
||||||
|
{
|
||||||
|
asm("fscale" : "+t"(x) : "u"(static_cast<T>(n)));
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<floating_point T>
|
||||||
|
inline constexpr T ldexp(T x, int y)
|
||||||
|
{
|
||||||
|
const bool exp_sign = y < 0;
|
||||||
|
if (exp_sign)
|
||||||
|
y = -y;
|
||||||
|
|
||||||
|
T exp = (T)1.0;
|
||||||
|
T mult = (T)2.0;
|
||||||
|
while (y)
|
||||||
|
{
|
||||||
|
if (y & 1)
|
||||||
|
exp *= mult;
|
||||||
|
mult *= mult;
|
||||||
|
y >>= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (exp_sign)
|
||||||
|
exp = (T)1.0 / exp;
|
||||||
|
|
||||||
|
return x * exp;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<floating_point T>
|
||||||
|
inline constexpr T sqrt(T x)
|
||||||
|
{
|
||||||
|
if constexpr(BAN::is_same_v<T, float>)
|
||||||
|
{
|
||||||
|
using v4sf = float __attribute__((vector_size(16)));
|
||||||
|
return __builtin_ia32_sqrtss((v4sf) { x, 0.0f, 0.0f, 0.0f })[0];
|
||||||
|
}
|
||||||
|
else if constexpr(BAN::is_same_v<T, double>)
|
||||||
|
{
|
||||||
|
using v2df = double __attribute__((vector_size(16)));
|
||||||
|
return __builtin_ia32_sqrtsd((v2df) { x, 0.0 })[0];
|
||||||
|
}
|
||||||
|
else if constexpr(BAN::is_same_v<T, long double>)
|
||||||
|
{
|
||||||
|
asm("fsqrt" : "+t"(x));
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<floating_point T>
|
||||||
|
inline constexpr T cbrt(T value)
|
||||||
|
{
|
||||||
|
return pow<T>(value, (T)1.0 / (T)3.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<floating_point T>
|
||||||
|
inline constexpr T sin(T x)
|
||||||
|
{
|
||||||
|
asm("fsin" : "+t"(x));
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<floating_point T>
|
||||||
|
inline constexpr T cos(T x)
|
||||||
|
{
|
||||||
|
asm("fcos" : "+t"(x));
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<floating_point T>
|
||||||
|
inline constexpr void sincos(T x, T& sin, T& cos)
|
||||||
|
{
|
||||||
|
asm("fsincos" : "=t"(cos), "=u"(sin) : "0"(x));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<floating_point T>
|
||||||
|
inline constexpr T tan(T x)
|
||||||
|
{
|
||||||
|
T one, ret;
|
||||||
|
asm("fptan" : "=t"(one), "=u"(ret) : "0"(x));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<floating_point T>
|
||||||
|
inline constexpr T atan2(T y, T x)
|
||||||
|
{
|
||||||
|
asm("fpatan" : "+t"(x) : "u"(y) : "st(1)");
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<floating_point T>
|
||||||
|
inline constexpr T atan(T x)
|
||||||
|
{
|
||||||
|
return atan2<T>(x, (T)1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<floating_point T>
|
||||||
|
inline constexpr T asin(T x)
|
||||||
|
{
|
||||||
|
if (x == (T)0.0)
|
||||||
|
return (T)0.0;
|
||||||
|
if (x == (T)1.0)
|
||||||
|
return +numbers::pi_v<T> / (T)2.0;
|
||||||
|
if (x == (T)-1.0)
|
||||||
|
return -numbers::pi_v<T> / (T)2.0;
|
||||||
|
return (T)2.0 * atan<T>(x / ((T)1.0 + sqrt<T>((T)1.0 - x * x)));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<floating_point T>
|
||||||
|
inline constexpr T acos(T x)
|
||||||
|
{
|
||||||
|
if (x == (T)0.0)
|
||||||
|
return numbers::pi_v<T> / (T)2.0;
|
||||||
|
if (x == (T)1.0)
|
||||||
|
return (T)0.0;
|
||||||
|
if (x == (T)-1.0)
|
||||||
|
return numbers::pi_v<T>;
|
||||||
|
return (T)2.0 * atan<T>(sqrt<T>((T)1.0 - x * x) / ((T)1.0 + x));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<floating_point T>
|
||||||
|
inline constexpr T sinh(T x)
|
||||||
|
{
|
||||||
|
return (exp<T>(x) - exp<T>(-x)) / (T)2.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<floating_point T>
|
||||||
|
inline constexpr T cosh(T x)
|
||||||
|
{
|
||||||
|
return (exp<T>(x) + exp<T>(-x)) / (T)2.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<floating_point T>
|
||||||
|
inline constexpr T tanh(T x)
|
||||||
|
{
|
||||||
|
const T exp_px = exp<T>(+x);
|
||||||
|
const T exp_nx = exp<T>(-x);
|
||||||
|
return (exp_px - exp_nx) / (exp_px + exp_nx);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<floating_point T>
|
||||||
|
inline constexpr T asinh(T x)
|
||||||
|
{
|
||||||
|
return log<T>(x + sqrt<T>(x * x + (T)1.0));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<floating_point T>
|
||||||
|
inline constexpr T acosh(T x)
|
||||||
|
{
|
||||||
|
return log<T>(x + sqrt<T>(x * x - (T)1.0));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<floating_point T>
|
||||||
|
inline constexpr T atanh(T x)
|
||||||
|
{
|
||||||
|
return (T)0.5 * log<T>(((T)1.0 + x) / ((T)1.0 - x));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<floating_point T>
|
||||||
|
inline constexpr T hypot(T x, T y)
|
||||||
|
{
|
||||||
|
return sqrt<T>(x * x + y * y);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef BAN_MATH_POP_OPTIONS
|
||||||
|
#undef BAN_MATH_POP_OPTIONS
|
||||||
|
#pragma GCC pop_options
|
||||||
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,10 +9,12 @@
|
|||||||
namespace BAN
|
namespace BAN
|
||||||
{
|
{
|
||||||
#if defined(__is_kernel)
|
#if defined(__is_kernel)
|
||||||
static constexpr void*(&allocator)(size_t) = kmalloc;
|
static constexpr void*(*allocator)(size_t) = kmalloc;
|
||||||
static constexpr void(&deallocator)(void*) = kfree;
|
static constexpr void*(*reallocator)(void*, size_t) = nullptr;
|
||||||
|
static constexpr void(*deallocator)(void*) = kfree;
|
||||||
#else
|
#else
|
||||||
static constexpr void*(&allocator)(size_t) = malloc;
|
static constexpr void*(*allocator)(size_t) = malloc;
|
||||||
static constexpr void(&deallocator)(void*) = free;
|
static constexpr void*(*reallocator)(void*, size_t) = realloc;
|
||||||
|
static constexpr void(*deallocator)(void*) = free;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|||||||
28
BAN/include/BAN/Numbers.h
Normal file
28
BAN/include/BAN/Numbers.h
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <BAN/Traits.h>
|
||||||
|
|
||||||
|
namespace BAN::numbers
|
||||||
|
{
|
||||||
|
|
||||||
|
template<floating_point T> inline constexpr T e_v = 2.71828182845904523536;
|
||||||
|
template<floating_point T> inline constexpr T log2e_v = 1.44269504088896340736;
|
||||||
|
template<floating_point T> inline constexpr T lge_v = 0.43429448190325182765;
|
||||||
|
template<floating_point T> inline constexpr T lg2_v = 0.30102999566398119521;
|
||||||
|
template<floating_point T> inline constexpr T ln2_v = 0.69314718055994530942;
|
||||||
|
template<floating_point T> inline constexpr T ln10_v = 2.30258509299404568402;
|
||||||
|
template<floating_point T> inline constexpr T pi_v = 3.14159265358979323846;
|
||||||
|
template<floating_point T> inline constexpr T sqrt2_v = 1.41421356237309504880;
|
||||||
|
template<floating_point T> inline constexpr T sqrt3_v = 1.73205080756887729353;
|
||||||
|
|
||||||
|
inline constexpr double e = e_v<double>;
|
||||||
|
inline constexpr double log2e = log2e_v<double>;
|
||||||
|
inline constexpr double lge = lge_v<double>;
|
||||||
|
inline constexpr double lg2 = lge_v<double>;
|
||||||
|
inline constexpr double ln2 = ln2_v<double>;
|
||||||
|
inline constexpr double ln10 = ln10_v<double>;
|
||||||
|
inline constexpr double pi = pi_v<double>;
|
||||||
|
inline constexpr double sqrt2 = sqrt2_v<double>;
|
||||||
|
inline constexpr double sqrt3 = sqrt3_v<double>;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -13,48 +13,48 @@ namespace BAN
|
|||||||
class Optional
|
class Optional
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Optional();
|
constexpr Optional();
|
||||||
Optional(Optional&&);
|
constexpr Optional(Optional&&);
|
||||||
Optional(const Optional&);
|
constexpr Optional(const Optional&);
|
||||||
Optional(const T&);
|
constexpr Optional(const T&);
|
||||||
Optional(T&&);
|
constexpr Optional(T&&);
|
||||||
template<typename... Args>
|
|
||||||
Optional(Args&&...);
|
|
||||||
|
|
||||||
~Optional();
|
~Optional();
|
||||||
|
|
||||||
Optional& operator=(Optional&&);
|
constexpr Optional& operator=(Optional&&);
|
||||||
Optional& operator=(const Optional&);
|
constexpr Optional& operator=(const Optional&);
|
||||||
|
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
Optional& emplace(Args&&...);
|
constexpr Optional& emplace(Args&&...) requires is_constructible_v<T, Args...>;
|
||||||
|
|
||||||
T* operator->();
|
constexpr T* operator->();
|
||||||
const T* operator->() const;
|
constexpr const T* operator->() const;
|
||||||
|
|
||||||
T& operator*();
|
constexpr T& operator*();
|
||||||
const T& operator*() const;
|
constexpr const T& operator*() const;
|
||||||
|
|
||||||
bool has_value() const;
|
constexpr bool has_value() const;
|
||||||
|
|
||||||
T release_value();
|
constexpr T release_value();
|
||||||
T& value();
|
constexpr T& value();
|
||||||
const T& value() const;
|
constexpr const T& value() const;
|
||||||
|
constexpr T& value_or(T&);
|
||||||
|
constexpr const T& value_or(const T&) const;
|
||||||
|
|
||||||
void clear();
|
constexpr void clear();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
alignas(T) uint8_t m_storage[sizeof(T)];
|
alignas(T) uint8_t m_storage[sizeof(T)] {};
|
||||||
bool m_has_value { false };
|
bool m_has_value { false };
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
Optional<T>::Optional()
|
constexpr Optional<T>::Optional()
|
||||||
: m_has_value(false)
|
: m_has_value(false)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
Optional<T>::Optional(Optional<T>&& other)
|
constexpr Optional<T>::Optional(Optional<T>&& other)
|
||||||
: m_has_value(other.has_value())
|
: m_has_value(other.has_value())
|
||||||
{
|
{
|
||||||
if (other.has_value())
|
if (other.has_value())
|
||||||
@@ -62,7 +62,7 @@ namespace BAN
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
Optional<T>::Optional(const Optional<T>& other)
|
constexpr Optional<T>::Optional(const Optional<T>& other)
|
||||||
: m_has_value(other.has_value())
|
: m_has_value(other.has_value())
|
||||||
{
|
{
|
||||||
if (other.has_value())
|
if (other.has_value())
|
||||||
@@ -70,27 +70,19 @@ namespace BAN
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
Optional<T>::Optional(const T& value)
|
constexpr Optional<T>::Optional(const T& value)
|
||||||
: m_has_value(true)
|
: m_has_value(true)
|
||||||
{
|
{
|
||||||
new (m_storage) T(value);
|
new (m_storage) T(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
Optional<T>::Optional(T&& value)
|
constexpr Optional<T>::Optional(T&& value)
|
||||||
: m_has_value(true)
|
: m_has_value(true)
|
||||||
{
|
{
|
||||||
new (m_storage) T(move(value));
|
new (m_storage) T(move(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
template<typename... Args>
|
|
||||||
Optional<T>::Optional(Args&&... args)
|
|
||||||
: m_has_value(true)
|
|
||||||
{
|
|
||||||
new (m_storage) T(forward<Args>(args)...);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
Optional<T>::~Optional()
|
Optional<T>::~Optional()
|
||||||
{
|
{
|
||||||
@@ -98,7 +90,7 @@ namespace BAN
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
Optional<T>& Optional<T>::operator=(Optional&& other)
|
constexpr Optional<T>& Optional<T>::operator=(Optional&& other)
|
||||||
{
|
{
|
||||||
clear();
|
clear();
|
||||||
m_has_value = other.has_value();
|
m_has_value = other.has_value();
|
||||||
@@ -108,18 +100,18 @@ namespace BAN
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
Optional<T>& Optional<T>::operator=(const Optional& other)
|
constexpr Optional<T>& Optional<T>::operator=(const Optional& other)
|
||||||
{
|
{
|
||||||
clear();
|
clear();
|
||||||
m_has_value = other.has_value();
|
m_has_value = other.has_value();
|
||||||
if (other.has_value)
|
if (other.has_value())
|
||||||
new (m_storage) T(other.value());
|
new (m_storage) T(other.value());
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
Optional<T>& Optional<T>::emplace(Args&&... args)
|
constexpr Optional<T>& Optional<T>::emplace(Args&&... args) requires is_constructible_v<T, Args...>
|
||||||
{
|
{
|
||||||
clear();
|
clear();
|
||||||
m_has_value = true;
|
m_has_value = true;
|
||||||
@@ -128,41 +120,41 @@ namespace BAN
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
T* Optional<T>::operator->()
|
constexpr T* Optional<T>::operator->()
|
||||||
{
|
{
|
||||||
ASSERT(has_value());
|
ASSERT(has_value());
|
||||||
return &value();
|
return &value();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
const T* Optional<T>::operator->() const
|
constexpr const T* Optional<T>::operator->() const
|
||||||
{
|
{
|
||||||
ASSERT(has_value());
|
ASSERT(has_value());
|
||||||
return &value();
|
return &value();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
T& Optional<T>::operator*()
|
constexpr T& Optional<T>::operator*()
|
||||||
{
|
{
|
||||||
ASSERT(has_value());
|
ASSERT(has_value());
|
||||||
return value();
|
return value();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
const T& Optional<T>::operator*() const
|
constexpr const T& Optional<T>::operator*() const
|
||||||
{
|
{
|
||||||
ASSERT(has_value());
|
ASSERT(has_value());
|
||||||
return value();
|
return value();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
bool Optional<T>::has_value() const
|
constexpr bool Optional<T>::has_value() const
|
||||||
{
|
{
|
||||||
return m_has_value;
|
return m_has_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
T Optional<T>::release_value()
|
constexpr T Optional<T>::release_value()
|
||||||
{
|
{
|
||||||
ASSERT(has_value());
|
ASSERT(has_value());
|
||||||
T released_value = move(value());
|
T released_value = move(value());
|
||||||
@@ -172,21 +164,37 @@ namespace BAN
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
T& Optional<T>::value()
|
constexpr T& Optional<T>::value()
|
||||||
{
|
{
|
||||||
ASSERT(has_value());
|
ASSERT(has_value());
|
||||||
return (T&)m_storage;
|
return *reinterpret_cast<T*>(&m_storage);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
const T& Optional<T>::value() const
|
constexpr const T& Optional<T>::value() const
|
||||||
{
|
{
|
||||||
ASSERT(has_value());
|
ASSERT(has_value());
|
||||||
return (const T&)m_storage;
|
return *reinterpret_cast<const T*>(&m_storage);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
void Optional<T>::clear()
|
constexpr T& Optional<T>::value_or(T& empty)
|
||||||
|
{
|
||||||
|
if (!has_value())
|
||||||
|
return empty;
|
||||||
|
return value();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
constexpr const T& Optional<T>::value_or(const T& empty) const
|
||||||
|
{
|
||||||
|
if (!has_value())
|
||||||
|
return empty;
|
||||||
|
return value();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
constexpr void Optional<T>::clear()
|
||||||
{
|
{
|
||||||
if (m_has_value)
|
if (m_has_value)
|
||||||
value().~T();
|
value().~T();
|
||||||
|
|||||||
@@ -1,6 +1,10 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <stddef.h>
|
#if __has_include(<new>)
|
||||||
|
#include <new>
|
||||||
|
#else
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
inline void* operator new(size_t, void* addr) { return addr; }
|
inline void* operator new(size_t, void* addr) { return addr; }
|
||||||
inline void* operator new[](size_t, void* addr) { return addr; }
|
inline void* operator new[](size_t, void* addr) { return addr; }
|
||||||
|
#endif
|
||||||
|
|||||||
64
BAN/include/BAN/PriorityQueue.h
Normal file
64
BAN/include/BAN/PriorityQueue.h
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "BAN/Errors.h"
|
||||||
|
#include <BAN/Vector.h>
|
||||||
|
#include <BAN/Heap.h>
|
||||||
|
|
||||||
|
namespace BAN
|
||||||
|
{
|
||||||
|
|
||||||
|
template<typename T, typename Comp = less<T>>
|
||||||
|
class PriorityQueue
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
PriorityQueue() = default;
|
||||||
|
PriorityQueue(Comp comp)
|
||||||
|
: m_comp(comp)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
ErrorOr<void> push(const T& value)
|
||||||
|
{
|
||||||
|
TRY(m_data.push_back(value));
|
||||||
|
push_heap(m_data.begin(), m_data.end());
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
ErrorOr<void> push(T&& value)
|
||||||
|
{
|
||||||
|
TRY(m_data.push_back(move(value)));
|
||||||
|
push_heap(m_data.begin(), m_data.end());
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename... Args>
|
||||||
|
ErrorOr<void> emplace(Args&&... args) requires is_constructible_v<T, Args...>
|
||||||
|
{
|
||||||
|
TRY(m_data.emplace_back(forward<Args>(args)...));
|
||||||
|
push_heap(m_data.begin(), m_data.end());
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
void pop()
|
||||||
|
{
|
||||||
|
pop_heap(m_data.begin(), m_data.end());
|
||||||
|
m_data.pop_back();
|
||||||
|
}
|
||||||
|
|
||||||
|
BAN::ErrorOr<void> reserve(Vector<T>::size_type size)
|
||||||
|
{
|
||||||
|
return m_data.reserve(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
T& top() { return m_data.front(); }
|
||||||
|
const T& top() const { return m_data.front(); }
|
||||||
|
|
||||||
|
bool empty() const { return m_data.empty(); }
|
||||||
|
Vector<T>::size_type size() const { return m_data.size(); }
|
||||||
|
Vector<T>::size_type capacity() const { return m_data.capacity(); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
Comp m_comp;
|
||||||
|
Vector<T> m_data;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
@@ -31,7 +31,7 @@ namespace BAN
|
|||||||
ErrorOr<void> push(T&&);
|
ErrorOr<void> push(T&&);
|
||||||
ErrorOr<void> push(const T&);
|
ErrorOr<void> push(const T&);
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
ErrorOr<void> emplace(Args&&...);
|
ErrorOr<void> emplace(Args&&...) requires is_constructible_v<T, Args...>;
|
||||||
|
|
||||||
ErrorOr<void> reserve(size_type);
|
ErrorOr<void> reserve(size_type);
|
||||||
ErrorOr<void> shrink_to_fit();
|
ErrorOr<void> shrink_to_fit();
|
||||||
@@ -131,7 +131,7 @@ namespace BAN
|
|||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
ErrorOr<void> Queue<T>::emplace(Args&&... args)
|
ErrorOr<void> Queue<T>::emplace(Args&&... args) requires is_constructible_v<T, Args...>
|
||||||
{
|
{
|
||||||
TRY(ensure_capacity(m_size + 1));
|
TRY(ensure_capacity(m_size + 1));
|
||||||
new (m_data + m_size) T(forward<Args>(args)...);
|
new (m_data + m_size) T(forward<Args>(args)...);
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <BAN/Atomic.h>
|
||||||
#include <BAN/Errors.h>
|
#include <BAN/Errors.h>
|
||||||
#include <BAN/Move.h>
|
#include <BAN/Move.h>
|
||||||
#include <BAN/NoCopyMove.h>
|
#include <BAN/NoCopyMove.h>
|
||||||
@@ -22,24 +23,36 @@ namespace BAN
|
|||||||
|
|
||||||
void ref() const
|
void ref() const
|
||||||
{
|
{
|
||||||
ASSERT(m_ref_count > 0);
|
uint32_t old = m_ref_count.fetch_add(1, MemoryOrder::memory_order_relaxed);
|
||||||
m_ref_count++;
|
ASSERT(old > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool try_ref() const
|
||||||
|
{
|
||||||
|
uint32_t expected = m_ref_count.load(MemoryOrder::memory_order_relaxed);
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
if (expected == 0)
|
||||||
|
return false;
|
||||||
|
if (m_ref_count.compare_exchange(expected, expected + 1, MemoryOrder::memory_order_acquire))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void unref() const
|
void unref() const
|
||||||
{
|
{
|
||||||
ASSERT(m_ref_count > 0);
|
uint32_t old = m_ref_count.fetch_sub(1);
|
||||||
m_ref_count--;
|
ASSERT(old > 0);
|
||||||
if (m_ref_count == 0)
|
if (old == 1)
|
||||||
delete (const T*)this;
|
delete static_cast<const T*>(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
RefCounted() = default;
|
RefCounted() = default;
|
||||||
~RefCounted() { ASSERT(m_ref_count == 0); }
|
virtual ~RefCounted() { ASSERT(m_ref_count == 0); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
mutable uint32_t m_ref_count = 1;
|
mutable Atomic<uint32_t> m_ref_count = 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
@@ -63,8 +76,9 @@ namespace BAN
|
|||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NOTE: don't use is_constructible_v<T, Args...> as RefPtr<T> is allowed with friends
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
static ErrorOr<RefPtr> create(Args&&... args)
|
static ErrorOr<RefPtr> create(Args&&... args) requires requires(Args&&... args) { T(forward<Args>(args)...); }
|
||||||
{
|
{
|
||||||
T* pointer = new T(forward<Args>(args)...);
|
T* pointer = new T(forward<Args>(args)...);
|
||||||
if (pointer == nullptr)
|
if (pointer == nullptr)
|
||||||
@@ -124,8 +138,11 @@ namespace BAN
|
|||||||
T* operator->() { return ptr(); }
|
T* operator->() { return ptr(); }
|
||||||
const T* operator->() const { return ptr(); }
|
const T* operator->() const { return ptr(); }
|
||||||
|
|
||||||
|
bool operator==(RefPtr other) const { return m_pointer == other.m_pointer; }
|
||||||
|
bool operator!=(RefPtr other) const { return m_pointer != other.m_pointer; }
|
||||||
|
|
||||||
bool empty() const { return m_pointer == nullptr; }
|
bool empty() const { return m_pointer == nullptr; }
|
||||||
operator bool() const { return m_pointer; }
|
explicit operator bool() const { return m_pointer; }
|
||||||
|
|
||||||
void clear()
|
void clear()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <BAN/Heap.h>
|
||||||
#include <BAN/Math.h>
|
#include <BAN/Math.h>
|
||||||
#include <BAN/Swap.h>
|
#include <BAN/Swap.h>
|
||||||
#include <BAN/Traits.h>
|
#include <BAN/Traits.h>
|
||||||
@@ -8,7 +9,7 @@
|
|||||||
namespace BAN::sort
|
namespace BAN::sort
|
||||||
{
|
{
|
||||||
|
|
||||||
template<typename It, typename Comp = less<typename It::value_type>>
|
template<typename It, typename Comp = less<it_value_type_t<It>>>
|
||||||
void exchange_sort(It begin, It end, Comp comp = {})
|
void exchange_sort(It begin, It end, Comp comp = {})
|
||||||
{
|
{
|
||||||
for (It lhs = begin; lhs != end; ++lhs)
|
for (It lhs = begin; lhs != end; ++lhs)
|
||||||
@@ -42,7 +43,7 @@ namespace BAN::sort
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename It, typename Comp = less<typename It::value_type>>
|
template<typename It, typename Comp = less<it_value_type_t<It>>>
|
||||||
void quick_sort(It begin, It end, Comp comp = {})
|
void quick_sort(It begin, It end, Comp comp = {})
|
||||||
{
|
{
|
||||||
if (distance(begin, end) <= 1)
|
if (distance(begin, end) <= 1)
|
||||||
@@ -52,14 +53,14 @@ namespace BAN::sort
|
|||||||
quick_sort(++mid, end, comp);
|
quick_sort(++mid, end, comp);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename It, typename Comp = less<typename It::value_type>>
|
template<typename It, typename Comp = less<it_value_type_t<It>>>
|
||||||
void insertion_sort(It begin, It end, Comp comp = {})
|
void insertion_sort(It begin, It end, Comp comp = {})
|
||||||
{
|
{
|
||||||
if (distance(begin, end) <= 1)
|
if (distance(begin, end) <= 1)
|
||||||
return;
|
return;
|
||||||
for (It it1 = next(begin, 1); it1 != end; ++it1)
|
for (It it1 = next(begin, 1); it1 != end; ++it1)
|
||||||
{
|
{
|
||||||
typename It::value_type x = move(*it1);
|
auto x = move(*it1);
|
||||||
It it2 = it1;
|
It it2 = it1;
|
||||||
for (; it2 != begin && comp(x, *prev(it2, 1)); --it2)
|
for (; it2 != begin && comp(x, *prev(it2, 1)); --it2)
|
||||||
*it2 = move(*prev(it2, 1));
|
*it2 = move(*prev(it2, 1));
|
||||||
@@ -67,83 +68,7 @@ namespace BAN::sort
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace detail
|
template<typename It, typename Comp = less<it_value_type_t<It>>>
|
||||||
{
|
|
||||||
|
|
||||||
template<typename It, typename Comp>
|
|
||||||
void push_heap(It begin, size_t hole_index, size_t top_index, typename It::value_type value, Comp comp)
|
|
||||||
{
|
|
||||||
size_t parent = (hole_index - 1) / 2;
|
|
||||||
while (hole_index > top_index && comp(*next(begin, parent), value))
|
|
||||||
{
|
|
||||||
*next(begin, hole_index) = move(*next(begin, parent));
|
|
||||||
hole_index = parent;
|
|
||||||
parent = (hole_index - 1) / 2;
|
|
||||||
}
|
|
||||||
*next(begin, hole_index) = move(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename It, typename Comp>
|
|
||||||
void adjust_heap(It begin, size_t hole_index, size_t len, typename It::value_type value, Comp comp)
|
|
||||||
{
|
|
||||||
const size_t top_index = hole_index;
|
|
||||||
size_t child = hole_index;
|
|
||||||
while (child < (len - 1) / 2)
|
|
||||||
{
|
|
||||||
child = 2 * (child + 1);
|
|
||||||
if (comp(*next(begin, child), *next(begin, child - 1)))
|
|
||||||
child--;
|
|
||||||
*next(begin, hole_index) = move(*next(begin, child));
|
|
||||||
hole_index = child;
|
|
||||||
}
|
|
||||||
if (len % 2 == 0 && child == (len - 2) / 2)
|
|
||||||
{
|
|
||||||
child = 2 * (child + 1);
|
|
||||||
*next(begin, hole_index) = move(*next(begin, child - 1));
|
|
||||||
hole_index = child - 1;
|
|
||||||
}
|
|
||||||
push_heap(begin, hole_index, top_index, move(value), comp);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename It, typename Comp = less<typename It::value_type>>
|
|
||||||
void make_heap(It begin, It end, Comp comp = {})
|
|
||||||
{
|
|
||||||
const size_t len = distance(begin, end);
|
|
||||||
if (len <= 1)
|
|
||||||
return;
|
|
||||||
|
|
||||||
size_t parent = (len - 2) / 2;
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
detail::adjust_heap(begin, parent, len, move(*next(begin, parent)), comp);
|
|
||||||
|
|
||||||
if (parent == 0)
|
|
||||||
break;
|
|
||||||
|
|
||||||
parent--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename It, typename Comp = less<typename It::value_type>>
|
|
||||||
void sort_heap(It begin, It end, Comp comp = {})
|
|
||||||
{
|
|
||||||
const size_t len = distance(begin, end);
|
|
||||||
if (len <= 1)
|
|
||||||
return;
|
|
||||||
|
|
||||||
size_t last = len;
|
|
||||||
while (last > 1)
|
|
||||||
{
|
|
||||||
last--;
|
|
||||||
typename It::value_type x = move(*next(begin, last));
|
|
||||||
*next(begin, last) = move(*begin);
|
|
||||||
detail::adjust_heap(begin, 0, last, move(x), comp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename It, typename Comp = less<typename It::value_type>>
|
|
||||||
void heap_sort(It begin, It end, Comp comp = {})
|
void heap_sort(It begin, It end, Comp comp = {})
|
||||||
{
|
{
|
||||||
make_heap(begin, end, comp);
|
make_heap(begin, end, comp);
|
||||||
@@ -167,7 +92,7 @@ namespace BAN::sort
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename It, typename Comp = less<typename It::value_type>>
|
template<typename It, typename Comp = less<it_value_type_t<It>>>
|
||||||
void intro_sort(It begin, It end, Comp comp = {})
|
void intro_sort(It begin, It end, Comp comp = {})
|
||||||
{
|
{
|
||||||
const size_t len = distance(begin, end);
|
const size_t len = distance(begin, end);
|
||||||
@@ -190,10 +115,10 @@ namespace BAN::sort
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename It, size_t radix = 256>
|
template<typename It, size_t radix = 256>
|
||||||
requires is_unsigned_v<typename It::value_type> && (radix > 0 && (radix & (radix - 1)) == 0)
|
requires is_unsigned_v<it_value_type_t<It>> && (radix > 0 && (radix & (radix - 1)) == 0)
|
||||||
BAN::ErrorOr<void> radix_sort(It begin, It end)
|
BAN::ErrorOr<void> radix_sort(It begin, It end)
|
||||||
{
|
{
|
||||||
using value_type = typename It::value_type;
|
using value_type = it_value_type_t<It>;
|
||||||
|
|
||||||
const size_t len = distance(begin, end);
|
const size_t len = distance(begin, end);
|
||||||
if (len <= 1)
|
if (len <= 1)
|
||||||
@@ -231,7 +156,7 @@ namespace BAN::sort
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename It, typename Comp = less<typename It::value_type>>
|
template<typename It, typename Comp = less<it_value_type_t<It>>>
|
||||||
void sort(It begin, It end, Comp comp = {})
|
void sort(It begin, It end, Comp comp = {})
|
||||||
{
|
{
|
||||||
return intro_sort(begin, end, comp);
|
return intro_sort(begin, end, comp);
|
||||||
|
|||||||
@@ -14,121 +14,89 @@ namespace BAN
|
|||||||
public:
|
public:
|
||||||
using value_type = T;
|
using value_type = T;
|
||||||
using size_type = size_t;
|
using size_type = size_t;
|
||||||
using iterator = IteratorSimple<T, Span>;
|
using iterator = IteratorSimple<value_type, Span>;
|
||||||
using const_iterator = ConstIteratorSimple<T, Span>;
|
using const_iterator = ConstIteratorSimple<value_type, Span>;
|
||||||
|
|
||||||
|
private:
|
||||||
|
template<typename S>
|
||||||
|
static inline constexpr bool can_init_from_v = is_same_v<value_type, const S> || is_same_v<value_type, S>;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Span() = default;
|
Span() = default;
|
||||||
Span(T*, size_type);
|
Span(value_type* data, size_type size)
|
||||||
Span(Span<T>&);
|
: m_data(data)
|
||||||
|
, m_size(size)
|
||||||
|
{ }
|
||||||
|
|
||||||
template<typename S>
|
template<typename S>
|
||||||
requires(is_same_v<T, const S>)
|
Span(const Span<S>& other) requires can_init_from_v<S>
|
||||||
Span(const Span<S>&);
|
: m_data(other.m_data)
|
||||||
|
, m_size(other.m_size)
|
||||||
|
{ }
|
||||||
|
template<typename S>
|
||||||
|
Span(Span<S>&& other) requires can_init_from_v<S>
|
||||||
|
: m_data(other.m_data)
|
||||||
|
, m_size(other.m_size)
|
||||||
|
{
|
||||||
|
other.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename S>
|
||||||
|
Span& operator=(const Span<S>& other) requires can_init_from_v<S>
|
||||||
|
{
|
||||||
|
m_data = other.m_data;
|
||||||
|
m_size = other.m_size;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
template<typename S>
|
||||||
|
Span& operator=(Span<S>&& other) requires can_init_from_v<S>
|
||||||
|
{
|
||||||
|
m_data = other.m_data;
|
||||||
|
m_size = other.m_size;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
iterator begin() { return iterator(m_data); }
|
iterator begin() { return iterator(m_data); }
|
||||||
iterator end() { return iterator(m_data + m_size); }
|
iterator end() { return iterator(m_data + m_size); }
|
||||||
const_iterator begin() const { return const_iterator(m_data); }
|
const_iterator begin() const { return const_iterator(m_data); }
|
||||||
const_iterator end() const { return const_iterator(m_data + m_size); }
|
const_iterator end() const { return const_iterator(m_data + m_size); }
|
||||||
|
|
||||||
T& operator[](size_type);
|
value_type& operator[](size_type index) const
|
||||||
const T& operator[](size_type) const;
|
{
|
||||||
|
ASSERT(index < m_size);
|
||||||
|
return m_data[index];
|
||||||
|
}
|
||||||
|
|
||||||
T* data();
|
value_type* data() const
|
||||||
const T* data() const;
|
{
|
||||||
|
return m_data;
|
||||||
|
}
|
||||||
|
|
||||||
bool empty() const;
|
bool empty() const { return m_size == 0; }
|
||||||
size_type size() const;
|
size_type size() const { return m_size; }
|
||||||
|
|
||||||
void clear();
|
void clear()
|
||||||
|
{
|
||||||
|
m_data = nullptr;
|
||||||
|
m_size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
Span slice(size_type, size_type = ~size_type(0));
|
Span slice(size_type start, size_type length = ~size_type(0)) const
|
||||||
|
{
|
||||||
|
ASSERT(start <= m_size);
|
||||||
|
if (length == ~size_type(0))
|
||||||
|
length = m_size - start;
|
||||||
|
ASSERT(m_size - start >= length);
|
||||||
|
return Span(m_data + start, length);
|
||||||
|
}
|
||||||
|
|
||||||
Span<const T> as_const() const { return Span<const T>(m_data, m_size); }
|
Span<const value_type> as_const() const { return *this; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
T* m_data = nullptr;
|
value_type* m_data = nullptr;
|
||||||
size_type m_size = 0;
|
size_type m_size = 0;
|
||||||
|
|
||||||
|
friend class Span<const value_type>;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
Span<T>::Span(T* data, size_type size)
|
|
||||||
: m_data(data)
|
|
||||||
, m_size(size)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
Span<T>::Span(Span& other)
|
|
||||||
: m_data(other.data())
|
|
||||||
, m_size(other.size())
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
template<typename S>
|
|
||||||
requires(is_same_v<T, const S>)
|
|
||||||
Span<T>::Span(const Span<S>& other)
|
|
||||||
: m_data(other.data())
|
|
||||||
, m_size(other.size())
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
T& Span<T>::operator[](size_type index)
|
|
||||||
{
|
|
||||||
ASSERT(m_data);
|
|
||||||
ASSERT(index < m_size);
|
|
||||||
return m_data[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
const T& Span<T>::operator[](size_type index) const
|
|
||||||
{
|
|
||||||
ASSERT(m_data);
|
|
||||||
ASSERT(index < m_size);
|
|
||||||
return m_data[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
T* Span<T>::data()
|
|
||||||
{
|
|
||||||
return m_data;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
const T* Span<T>::data() const
|
|
||||||
{
|
|
||||||
return m_data;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
bool Span<T>::empty() const
|
|
||||||
{
|
|
||||||
return m_size == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
typename Span<T>::size_type Span<T>::size() const
|
|
||||||
{
|
|
||||||
return m_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
void Span<T>::clear()
|
|
||||||
{
|
|
||||||
m_data = nullptr;
|
|
||||||
m_size = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
Span<T> Span<T>::slice(size_type start, size_type length)
|
|
||||||
{
|
|
||||||
ASSERT(m_data);
|
|
||||||
ASSERT(start <= m_size);
|
|
||||||
if (length == ~size_type(0))
|
|
||||||
length = m_size - start;
|
|
||||||
ASSERT(m_size - start >= length);
|
|
||||||
return Span(m_data + start, length);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,9 +2,10 @@
|
|||||||
|
|
||||||
#include <BAN/Errors.h>
|
#include <BAN/Errors.h>
|
||||||
#include <BAN/Formatter.h>
|
#include <BAN/Formatter.h>
|
||||||
#include <BAN/ForwardList.h>
|
|
||||||
#include <BAN/Hash.h>
|
#include <BAN/Hash.h>
|
||||||
#include <BAN/Iterators.h>
|
#include <BAN/Iterators.h>
|
||||||
|
#include <BAN/New.h>
|
||||||
|
#include <BAN/StringView.h>
|
||||||
|
|
||||||
namespace BAN
|
namespace BAN
|
||||||
{
|
{
|
||||||
@@ -13,33 +14,136 @@ namespace BAN
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
using size_type = size_t;
|
using size_type = size_t;
|
||||||
|
using value_type = char;
|
||||||
using iterator = IteratorSimple<char, String>;
|
using iterator = IteratorSimple<char, String>;
|
||||||
using const_iterator = ConstIteratorSimple<char, String>;
|
using const_iterator = ConstIteratorSimple<char, String>;
|
||||||
static constexpr size_type sso_capacity = 15;
|
static constexpr size_type sso_capacity = 15;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
String();
|
String() {}
|
||||||
String(const String&);
|
String(const String& other) { *this = other; }
|
||||||
String(String&&);
|
String(String&& other) { *this = move(other); }
|
||||||
String(StringView);
|
String(StringView other) { *this = other; }
|
||||||
~String();
|
~String() { clear(); }
|
||||||
|
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
static String formatted(const char* format, const Args&... args);
|
static BAN::ErrorOr<String> formatted(const char* format, Args&&... args)
|
||||||
|
{
|
||||||
|
size_type length = 0;
|
||||||
|
BAN::Formatter::print([&](char) { length++; }, format, BAN::forward<Args>(args)...);
|
||||||
|
|
||||||
String& operator=(const String&);
|
String result;
|
||||||
String& operator=(String&&);
|
TRY(result.reserve(length));
|
||||||
String& operator=(StringView);
|
BAN::Formatter::print([&](char c){ MUST(result.push_back(c)); }, format, BAN::forward<Args>(args)...);
|
||||||
|
|
||||||
ErrorOr<void> push_back(char);
|
return result;
|
||||||
ErrorOr<void> insert(char, size_type);
|
}
|
||||||
ErrorOr<void> insert(StringView, size_type);
|
|
||||||
ErrorOr<void> append(StringView);
|
|
||||||
|
|
||||||
void pop_back();
|
String& operator=(const String& other)
|
||||||
void remove(size_type);
|
{
|
||||||
|
clear();
|
||||||
|
MUST(ensure_capacity(other.size()));
|
||||||
|
memcpy(data(), other.data(), other.size() + 1);
|
||||||
|
m_size = other.size();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
void clear();
|
String& operator=(String&& other)
|
||||||
|
{
|
||||||
|
clear();
|
||||||
|
|
||||||
|
if (other.has_sso())
|
||||||
|
memcpy(data(), other.data(), other.size() + 1);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_storage.general_storage = other.m_storage.general_storage;
|
||||||
|
m_has_sso = false;
|
||||||
|
}
|
||||||
|
m_size = other.m_size;
|
||||||
|
|
||||||
|
other.m_size = 0;
|
||||||
|
other.m_storage.sso_storage = SSOStorage();
|
||||||
|
other.m_has_sso = true;
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
String& operator=(StringView other)
|
||||||
|
{
|
||||||
|
clear();
|
||||||
|
MUST(ensure_capacity(other.size()));
|
||||||
|
memcpy(data(), other.data(), other.size());
|
||||||
|
m_size = other.size();
|
||||||
|
data()[m_size] = '\0';
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
ErrorOr<void> push_back(char c)
|
||||||
|
{
|
||||||
|
TRY(ensure_capacity(m_size + 1));
|
||||||
|
data()[m_size] = c;
|
||||||
|
m_size++;
|
||||||
|
data()[m_size] = '\0';
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
ErrorOr<void> insert(char c, size_type index)
|
||||||
|
{
|
||||||
|
ASSERT(index <= m_size);
|
||||||
|
TRY(ensure_capacity(m_size + 1));
|
||||||
|
memmove(data() + index + 1, data() + index, m_size - index);
|
||||||
|
data()[index] = c;
|
||||||
|
m_size++;
|
||||||
|
data()[m_size] = '\0';
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
ErrorOr<void> insert(StringView str, size_type index)
|
||||||
|
{
|
||||||
|
ASSERT(index <= m_size);
|
||||||
|
TRY(ensure_capacity(m_size + str.size()));
|
||||||
|
memmove(data() + index + str.size(), data() + index, m_size - index);
|
||||||
|
memcpy(data() + index, str.data(), str.size());
|
||||||
|
m_size += str.size();
|
||||||
|
data()[m_size] = '\0';
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
ErrorOr<void> append(StringView str)
|
||||||
|
{
|
||||||
|
TRY(ensure_capacity(m_size + str.size()));
|
||||||
|
memcpy(data() + m_size, str.data(), str.size());
|
||||||
|
m_size += str.size();
|
||||||
|
data()[m_size] = '\0';
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
void pop_back()
|
||||||
|
{
|
||||||
|
ASSERT(m_size > 0);
|
||||||
|
m_size--;
|
||||||
|
data()[m_size] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
void remove(size_type index)
|
||||||
|
{
|
||||||
|
ASSERT(index < m_size);
|
||||||
|
memmove(data() + index, data() + index + 1, m_size - index);
|
||||||
|
m_size--;
|
||||||
|
data()[m_size] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear()
|
||||||
|
{
|
||||||
|
if (!has_sso())
|
||||||
|
{
|
||||||
|
deallocator(m_storage.general_storage.data);
|
||||||
|
m_storage.sso_storage = SSOStorage();
|
||||||
|
m_has_sso = true;
|
||||||
|
}
|
||||||
|
m_size = 0;
|
||||||
|
data()[m_size] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
const_iterator begin() const { return const_iterator(data()); }
|
const_iterator begin() const { return const_iterator(data()); }
|
||||||
iterator begin() { return iterator(data()); }
|
iterator begin() { return iterator(data()); }
|
||||||
@@ -55,27 +159,151 @@ namespace BAN
|
|||||||
char operator[](size_type index) const { ASSERT(index < m_size); return data()[index]; }
|
char operator[](size_type index) const { ASSERT(index < m_size); return data()[index]; }
|
||||||
char& operator[](size_type index) { ASSERT(index < m_size); return data()[index]; }
|
char& operator[](size_type index) { ASSERT(index < m_size); return data()[index]; }
|
||||||
|
|
||||||
bool operator==(const String&) const;
|
bool operator==(const String& str) const
|
||||||
bool operator==(StringView) const;
|
{
|
||||||
bool operator==(const char*) const;
|
if (size() != str.size())
|
||||||
|
return false;
|
||||||
|
for (size_type i = 0; i < m_size; i++)
|
||||||
|
if (data()[i] != str.data()[i])
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
ErrorOr<void> resize(size_type, char = '\0');
|
bool operator==(StringView str) const
|
||||||
ErrorOr<void> reserve(size_type);
|
{
|
||||||
ErrorOr<void> shrink_to_fit();
|
if (size() != str.size())
|
||||||
|
return false;
|
||||||
|
for (size_type i = 0; i < m_size; i++)
|
||||||
|
if (data()[i] != str.data()[i])
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(const char* cstr) const
|
||||||
|
{
|
||||||
|
for (size_type i = 0; i < m_size; i++)
|
||||||
|
if (data()[i] != cstr[i])
|
||||||
|
return false;
|
||||||
|
if (cstr[size()] != '\0')
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
ErrorOr<void> resize(size_type new_size, char init_c = '\0')
|
||||||
|
{
|
||||||
|
if (m_size == new_size)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
// expanding
|
||||||
|
if (m_size < new_size)
|
||||||
|
{
|
||||||
|
TRY(ensure_capacity(new_size));
|
||||||
|
memset(data() + m_size, init_c, new_size - m_size);
|
||||||
|
m_size = new_size;
|
||||||
|
data()[m_size] = '\0';
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
m_size = new_size;
|
||||||
|
data()[m_size] = '\0';
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
ErrorOr<void> reserve(size_type new_size)
|
||||||
|
{
|
||||||
|
TRY(ensure_capacity(new_size));
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
ErrorOr<void> shrink_to_fit()
|
||||||
|
{
|
||||||
|
if (has_sso())
|
||||||
|
return {};
|
||||||
|
|
||||||
|
if (fits_in_sso())
|
||||||
|
{
|
||||||
|
char* data = m_storage.general_storage.data;
|
||||||
|
m_storage.sso_storage = SSOStorage();
|
||||||
|
m_has_sso = true;
|
||||||
|
memcpy(this->data(), data, m_size + 1);
|
||||||
|
deallocator(data);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
GeneralStorage& storage = m_storage.general_storage;
|
||||||
|
if (storage.capacity == m_size)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
char* new_data = (char*)allocator(m_size + 1);
|
||||||
|
if (new_data == nullptr)
|
||||||
|
return Error::from_errno(ENOMEM);
|
||||||
|
|
||||||
|
memcpy(new_data, storage.data, m_size);
|
||||||
|
deallocator(storage.data);
|
||||||
|
|
||||||
|
storage.capacity = m_size;
|
||||||
|
storage.data = new_data;
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
StringView sv() const { return StringView(data(), size()); }
|
StringView sv() const { return StringView(data(), size()); }
|
||||||
|
|
||||||
bool empty() const { return m_size == 0; }
|
bool empty() const { return m_size == 0; }
|
||||||
size_type size() const { return m_size; }
|
size_type size() const { return m_size; }
|
||||||
size_type capacity() const;
|
|
||||||
|
|
||||||
char* data();
|
size_type capacity() const
|
||||||
const char* data() const;
|
{
|
||||||
|
if (has_sso())
|
||||||
|
return sso_capacity;
|
||||||
|
return m_storage.general_storage.capacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* data()
|
||||||
|
{
|
||||||
|
if (has_sso())
|
||||||
|
return m_storage.sso_storage.data;
|
||||||
|
return m_storage.general_storage.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* data() const
|
||||||
|
{
|
||||||
|
if (has_sso())
|
||||||
|
return m_storage.sso_storage.data;
|
||||||
|
return m_storage.general_storage.data;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ErrorOr<void> ensure_capacity(size_type);
|
ErrorOr<void> ensure_capacity(size_type new_size)
|
||||||
|
{
|
||||||
|
if (m_size >= new_size)
|
||||||
|
return {};
|
||||||
|
if (has_sso() && fits_in_sso(new_size))
|
||||||
|
return {};
|
||||||
|
|
||||||
bool has_sso() const;
|
char* new_data = (char*)allocator(new_size + 1);
|
||||||
|
if (new_data == nullptr)
|
||||||
|
return Error::from_errno(ENOMEM);
|
||||||
|
|
||||||
|
if (m_size)
|
||||||
|
memcpy(new_data, data(), m_size + 1);
|
||||||
|
|
||||||
|
if (has_sso())
|
||||||
|
{
|
||||||
|
m_storage.general_storage = GeneralStorage();
|
||||||
|
m_has_sso = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
deallocator(m_storage.general_storage.data);
|
||||||
|
|
||||||
|
auto& storage = m_storage.general_storage;
|
||||||
|
storage.capacity = new_size;
|
||||||
|
storage.data = new_data;
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
bool has_sso() const { return m_has_sso; }
|
||||||
|
|
||||||
bool fits_in_sso() const { return fits_in_sso(m_size); }
|
bool fits_in_sso() const { return fits_in_sso(m_size); }
|
||||||
static bool fits_in_sso(size_type size) { return size < sso_capacity; }
|
static bool fits_in_sso(size_type size) { return size < sso_capacity; }
|
||||||
@@ -100,14 +328,6 @@ namespace BAN
|
|||||||
size_type m_has_sso : 1 { true };
|
size_type m_has_sso : 1 { true };
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename... Args>
|
|
||||||
String String::formatted(const char* format, const Args&... args)
|
|
||||||
{
|
|
||||||
String result;
|
|
||||||
BAN::Formatter::print([&](char c){ MUST(result.push_back(c)); }, format, args...);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
struct hash<String>
|
struct hash<String>
|
||||||
{
|
{
|
||||||
@@ -133,10 +353,9 @@ namespace BAN::Formatter
|
|||||||
{
|
{
|
||||||
|
|
||||||
template<typename F>
|
template<typename F>
|
||||||
void print_argument(F putc, const String& string, const ValueFormat&)
|
void print_argument(F putc, const String& string, const ValueFormat& format)
|
||||||
{
|
{
|
||||||
for (String::size_type i = 0; i < string.size(); i++)
|
print_argument(putc, string.sv(), format);
|
||||||
putc(string[i]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,8 +2,10 @@
|
|||||||
|
|
||||||
#include <BAN/Formatter.h>
|
#include <BAN/Formatter.h>
|
||||||
#include <BAN/ForwardList.h>
|
#include <BAN/ForwardList.h>
|
||||||
|
#include <BAN/Hash.h>
|
||||||
#include <BAN/Iterators.h>
|
#include <BAN/Iterators.h>
|
||||||
#include <BAN/Optional.h>
|
#include <BAN/Optional.h>
|
||||||
|
#include <BAN/Vector.h>
|
||||||
|
|
||||||
namespace BAN
|
namespace BAN
|
||||||
{
|
{
|
||||||
@@ -12,58 +14,245 @@ namespace BAN
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
using size_type = size_t;
|
using size_type = size_t;
|
||||||
|
using value_type = char;
|
||||||
using const_iterator = ConstIteratorSimple<char, StringView>;
|
using const_iterator = ConstIteratorSimple<char, StringView>;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
StringView();
|
constexpr StringView() {}
|
||||||
|
constexpr StringView(const char* string, size_type len = -1)
|
||||||
|
{
|
||||||
|
if (len == size_type(-1))
|
||||||
|
for (len = 0; string[len];)
|
||||||
|
len++;
|
||||||
|
m_data = string;
|
||||||
|
m_size = len;
|
||||||
|
}
|
||||||
StringView(const String&);
|
StringView(const String&);
|
||||||
StringView(const char*, size_type = -1);
|
|
||||||
|
|
||||||
const_iterator begin() const { return const_iterator(m_data); }
|
constexpr const_iterator begin() const { return const_iterator(m_data); }
|
||||||
const_iterator end() const { return const_iterator(m_data + m_size); }
|
constexpr const_iterator end() const { return const_iterator(m_data + m_size); }
|
||||||
|
|
||||||
char operator[](size_type) const;
|
constexpr char operator[](size_type index) const
|
||||||
|
{
|
||||||
|
ASSERT(index < m_size);
|
||||||
|
return m_data[index];
|
||||||
|
}
|
||||||
|
|
||||||
bool operator==(const String&) const;
|
constexpr bool operator==(StringView other) const
|
||||||
bool operator==(StringView) const;
|
{
|
||||||
bool operator==(const char*) const;
|
if (m_size != other.m_size)
|
||||||
|
return false;
|
||||||
|
for (size_type i = 0; i < m_size; i++)
|
||||||
|
if (m_data[i] != other.m_data[i])
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
StringView substring(size_type, size_type = -1) const;
|
constexpr bool operator==(const char* other) const
|
||||||
|
{
|
||||||
|
for (size_type i = 0; i < m_size; i++)
|
||||||
|
if (m_data[i] != other[i])
|
||||||
|
return false;
|
||||||
|
return other[m_size] == '\0';
|
||||||
|
}
|
||||||
|
|
||||||
ErrorOr<Vector<StringView>> split(char, bool = false) const;
|
constexpr StringView substring(size_type index, size_type len = -1) const
|
||||||
ErrorOr<Vector<StringView>> split(bool(*comp)(char), bool = false) const;
|
{
|
||||||
|
ASSERT(index <= m_size);
|
||||||
|
if (len == size_type(-1))
|
||||||
|
len = m_size - index;
|
||||||
|
ASSERT(len <= m_size - index); // weird order to avoid overflow
|
||||||
|
StringView result;
|
||||||
|
result.m_data = m_data + index;
|
||||||
|
result.m_size = len;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
char back() const;
|
ErrorOr<Vector<StringView>> split(char delim, bool allow_empties = false) const
|
||||||
char front() const;
|
{
|
||||||
|
size_type count = 0;
|
||||||
|
{
|
||||||
|
size_type start = 0;
|
||||||
|
for (size_type i = 0; i < m_size; i++)
|
||||||
|
{
|
||||||
|
if (m_data[i] == delim)
|
||||||
|
{
|
||||||
|
if (allow_empties || start != i)
|
||||||
|
count++;
|
||||||
|
start = i + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (start != m_size)
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
|
||||||
BAN::Optional<size_type> find(char) const;
|
Vector<StringView> result;
|
||||||
BAN::Optional<size_type> find(bool(*comp)(char)) const;
|
TRY(result.reserve(count));
|
||||||
|
|
||||||
bool contains(char) const;
|
size_type start = 0;
|
||||||
size_type count(char) const;
|
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 || (start == m_size && allow_empties))
|
||||||
|
TRY(result.push_back(this->substring(start)));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
bool empty() const;
|
ErrorOr<Vector<StringView>> split(bool(*comp)(char), bool allow_empties = false) const
|
||||||
size_type size() const;
|
{
|
||||||
|
size_type count = 0;
|
||||||
|
{
|
||||||
|
size_type start = 0;
|
||||||
|
for (size_type i = 0; i < m_size; i++)
|
||||||
|
{
|
||||||
|
if (comp(m_data[i]))
|
||||||
|
{
|
||||||
|
if (allow_empties || start != i)
|
||||||
|
count++;
|
||||||
|
start = i + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (start != m_size)
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
|
||||||
const char* data() const;
|
Vector<StringView> result;
|
||||||
|
TRY(result.reserve(count));
|
||||||
|
|
||||||
|
size_type start = 0;
|
||||||
|
for (size_type i = 0; i < m_size; i++)
|
||||||
|
{
|
||||||
|
if (comp(m_data[i]))
|
||||||
|
{
|
||||||
|
if (allow_empties || start != i)
|
||||||
|
TRY(result.push_back(this->substring(start, i - start)));
|
||||||
|
start = i + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (start < m_size || (start == m_size && allow_empties))
|
||||||
|
TRY(result.push_back(this->substring(start)));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr char back() const
|
||||||
|
{
|
||||||
|
ASSERT(m_size > 0);
|
||||||
|
return m_data[m_size - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr char front() const
|
||||||
|
{
|
||||||
|
ASSERT(m_size > 0);
|
||||||
|
return m_data[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
BAN::Optional<size_type> find(char ch) const
|
||||||
|
{
|
||||||
|
for (size_type i = 0; i < m_size; i++)
|
||||||
|
if (m_data[i] == ch)
|
||||||
|
return i;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
BAN::Optional<size_type> find(bool(*comp)(char)) const
|
||||||
|
{
|
||||||
|
for (size_type i = 0; i < m_size; i++)
|
||||||
|
if (comp(m_data[i]))
|
||||||
|
return i;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
BAN::Optional<size_type> rfind(char ch) const
|
||||||
|
{
|
||||||
|
for (size_type i = m_size; i > 0; i--)
|
||||||
|
if (m_data[i - 1] == ch)
|
||||||
|
return i - 1;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
BAN::Optional<size_type> rfind(bool(*comp)(char)) const
|
||||||
|
{
|
||||||
|
for (size_type i = m_size; i > 0; i--)
|
||||||
|
if (comp(m_data[i - 1]))
|
||||||
|
return i - 1;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr bool starts_with(BAN::StringView target) const
|
||||||
|
{
|
||||||
|
if (target.size() > m_size)
|
||||||
|
return false;
|
||||||
|
for (size_type i = 0; i < target.size(); i++)
|
||||||
|
if (m_data[i] != target[i])
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr bool contains(char ch) const
|
||||||
|
{
|
||||||
|
for (size_type i = 0; i < m_size; i++)
|
||||||
|
if (m_data[i] == ch)
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr size_type count(char ch) const
|
||||||
|
{
|
||||||
|
size_type result = 0;
|
||||||
|
for (size_type i = 0; i < m_size; i++)
|
||||||
|
if (m_data[i] == ch)
|
||||||
|
result++;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr bool empty() const { return m_size == 0; }
|
||||||
|
constexpr size_type size() const { return m_size; }
|
||||||
|
constexpr const char* data() const { return m_data; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const char* m_data = nullptr;
|
const char* m_data = nullptr;
|
||||||
size_type m_size = 0;
|
size_type m_size = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct hash<StringView>
|
||||||
|
{
|
||||||
|
hash_t operator()(StringView string) const
|
||||||
|
{
|
||||||
|
constexpr hash_t FNV_offset_basis = 0x811c9dc5;
|
||||||
|
constexpr hash_t FNV_prime = 0x01000193;
|
||||||
|
|
||||||
|
hash_t hash = FNV_offset_basis;
|
||||||
|
for (StringView::size_type i = 0; i < string.size(); i++)
|
||||||
|
{
|
||||||
|
hash *= FNV_prime;
|
||||||
|
hash ^= (uint8_t)string[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline BAN::StringView operator""sv(const char* str, BAN::StringView::size_type len) { return BAN::StringView(str, len); }
|
inline constexpr BAN::StringView operator""_sv(const char* str, BAN::StringView::size_type len) { return BAN::StringView(str, len); }
|
||||||
|
|
||||||
namespace BAN::Formatter
|
namespace BAN::Formatter
|
||||||
{
|
{
|
||||||
|
|
||||||
template<typename F>
|
template<typename F>
|
||||||
void print_argument(F putc, const StringView& sv, const ValueFormat&)
|
void print_argument(F putc, const StringView& sv, const ValueFormat& format)
|
||||||
{
|
{
|
||||||
for (StringView::size_type i = 0; i < sv.size(); i++)
|
for (StringView::size_type i = 0; i < sv.size(); i++)
|
||||||
putc(sv[i]);
|
putc(sv[i]);
|
||||||
|
for (int i = sv.size(); i < format.fill; i++)
|
||||||
|
putc(' ');
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,10 +3,10 @@
|
|||||||
namespace BAN
|
namespace BAN
|
||||||
{
|
{
|
||||||
|
|
||||||
template<typename T> struct remove_refenrece { using type = T; };
|
template<typename T> struct remove_reference { using type = T; };
|
||||||
template<typename T> struct remove_refenrece<T&> { using type = T; };
|
template<typename T> struct remove_reference<T&> { using type = T; };
|
||||||
template<typename T> struct remove_refenrece<T&&> { using type = T; };
|
template<typename T> struct remove_reference<T&&> { using type = T; };
|
||||||
template<typename T> using remove_reference_t = typename remove_refenrece<T>::type;
|
template<typename T> using remove_reference_t = typename remove_reference<T>::type;
|
||||||
|
|
||||||
template<typename T> struct remove_const { using type = T; };
|
template<typename T> struct remove_const { using type = T; };
|
||||||
template<typename T> struct remove_const<const T> { using type = T; };
|
template<typename T> struct remove_const<const T> { using type = T; };
|
||||||
@@ -34,12 +34,15 @@ namespace BAN
|
|||||||
template<typename T1, typename T2> struct either_or<true, T1, T2> { using type = T1; };
|
template<typename T1, typename T2> struct either_or<true, T1, T2> { using type = T1; };
|
||||||
template<bool B, typename T1, typename T2> using either_or_t = typename either_or<B, T1, T2>::type;
|
template<bool B, typename T1, typename T2> using either_or_t = typename either_or<B, T1, T2>::type;
|
||||||
|
|
||||||
struct true_type { static constexpr bool value = true; };
|
template<typename T, T V> struct integral_constant { static constexpr T value = V; };
|
||||||
struct false_type { static constexpr bool value = false; };
|
template<typename T, T V > inline constexpr T integral_constant_v = integral_constant<T, V>::value;
|
||||||
|
using true_type = integral_constant<bool, true>;
|
||||||
|
using false_type = integral_constant<bool, false>;
|
||||||
|
|
||||||
template<typename T, typename S> struct is_same : false_type {};
|
template<typename T, typename S> struct is_same : false_type {};
|
||||||
template<typename T> struct is_same<T, T> : true_type {};
|
template<typename T> struct is_same<T, T> : true_type {};
|
||||||
template<typename T, typename S> inline constexpr bool is_same_v = is_same<T, S>::value;
|
template<typename T, typename S> inline constexpr bool is_same_v = is_same<T, S>::value;
|
||||||
|
template<typename T, typename S> concept same_as = BAN::is_same_v<T, S>;
|
||||||
|
|
||||||
template<typename T> struct is_lvalue_reference : false_type {};
|
template<typename T> struct is_lvalue_reference : false_type {};
|
||||||
template<typename T> struct is_lvalue_reference<T&> : true_type {};
|
template<typename T> struct is_lvalue_reference<T&> : true_type {};
|
||||||
@@ -58,6 +61,9 @@ namespace BAN
|
|||||||
template<typename T> struct is_move_constructible { static constexpr bool value = is_constructible_v<T, T&&>; };
|
template<typename T> struct is_move_constructible { static constexpr bool value = is_constructible_v<T, T&&>; };
|
||||||
template<typename T> inline constexpr bool is_move_constructible_v = is_move_constructible<T>::value;
|
template<typename T> inline constexpr bool is_move_constructible_v = is_move_constructible<T>::value;
|
||||||
|
|
||||||
|
template<typename T> struct is_trivially_copyable { static constexpr bool value = __is_trivially_copyable(T); };
|
||||||
|
template<typename T> inline constexpr bool is_trivially_copyable_v = is_trivially_copyable<T>::value;
|
||||||
|
|
||||||
template<typename T> struct is_integral { static constexpr bool value = requires (T t, T* p, void (*f)(T)) { reinterpret_cast<T>(t); f(0); p + t; }; };
|
template<typename T> struct is_integral { static constexpr bool value = requires (T t, T* p, void (*f)(T)) { reinterpret_cast<T>(t); f(0); p + t; }; };
|
||||||
template<typename T> inline constexpr bool is_integral_v = is_integral<T>::value;
|
template<typename T> inline constexpr bool is_integral_v = is_integral<T>::value;
|
||||||
template<typename T> concept integral = is_integral_v<T>;
|
template<typename T> concept integral = is_integral_v<T>;
|
||||||
@@ -87,8 +93,8 @@ namespace BAN
|
|||||||
template<typename Base, typename Derived> struct is_base_of { static constexpr bool value = __is_base_of(Base, Derived); };
|
template<typename Base, typename Derived> struct is_base_of { static constexpr bool value = __is_base_of(Base, Derived); };
|
||||||
template<typename Base, typename Derived> inline constexpr bool is_base_of_v = is_base_of<Base, Derived>::value;
|
template<typename Base, typename Derived> inline constexpr bool is_base_of_v = is_base_of<Base, Derived>::value;
|
||||||
|
|
||||||
template<typename T, T V> struct integral_constant { static constexpr T value = V; };
|
template<typename T> struct is_pod { static constexpr bool value = __is_pod(T); };
|
||||||
template<typename T, T V > inline constexpr T integral_constant_v = integral_constant<T, V>::value;
|
template<typename T> inline constexpr bool is_pod_v = is_pod<T>::value;
|
||||||
|
|
||||||
namespace detail
|
namespace detail
|
||||||
{
|
{
|
||||||
@@ -136,6 +142,10 @@ namespace BAN
|
|||||||
template<typename T> using make_signed_t = typename make_signed<T>::type;
|
template<typename T> using make_signed_t = typename make_signed<T>::type;
|
||||||
#undef __BAN_TRAITS_MAKE_SIGNED_CV
|
#undef __BAN_TRAITS_MAKE_SIGNED_CV
|
||||||
|
|
||||||
|
template<typename T> struct it_value_type { using value_type = T::value_type; };
|
||||||
|
template<typename T> struct it_value_type<T*> { using value_type = T; };
|
||||||
|
template<typename T> using it_value_type_t = typename it_value_type<T>::value_type;
|
||||||
|
|
||||||
template<typename T> struct less { constexpr bool operator()(const T& lhs, const T& rhs) const { return lhs < rhs; } };
|
template<typename T> struct less { constexpr bool operator()(const T& lhs, const T& rhs) const { return lhs < rhs; } };
|
||||||
template<typename T> struct equal { constexpr bool operator()(const T& lhs, const T& rhs) const { return lhs == rhs; } };
|
template<typename T> struct equal { constexpr bool operator()(const T& lhs, const T& rhs) const { return lhs == rhs; } };
|
||||||
template<typename T> struct greater { constexpr bool operator()(const T& lhs, const T& rhs) const { return lhs > rhs; } };
|
template<typename T> struct greater { constexpr bool operator()(const T& lhs, const T& rhs) const { return lhs > rhs; } };
|
||||||
|
|||||||
@@ -18,23 +18,24 @@ namespace BAN::UTF8
|
|||||||
return 3;
|
return 3;
|
||||||
if ((first_byte & 0xF8) == 0xF0)
|
if ((first_byte & 0xF8) == 0xF0)
|
||||||
return 4;
|
return 4;
|
||||||
return 0;
|
return UTF8::invalid;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr uint32_t to_codepoint(uint8_t* bytes)
|
template<typename T> requires (sizeof(T) == 1)
|
||||||
|
constexpr uint32_t to_codepoint(const T* bytes)
|
||||||
{
|
{
|
||||||
uint32_t length = byte_length(bytes[0]);
|
uint32_t length = byte_length(bytes[0]);
|
||||||
|
|
||||||
for (uint32_t i = 1; i < length; i++)
|
for (uint32_t i = 1; i < length; i++)
|
||||||
if ((bytes[i] & 0xC0) != 0x80)
|
if (((uint8_t)bytes[i] & 0xC0) != 0x80)
|
||||||
return UTF8::invalid;
|
return UTF8::invalid;
|
||||||
|
|
||||||
switch (length)
|
switch (length)
|
||||||
{
|
{
|
||||||
case 1: return ((bytes[0] & 0x80) != 0x00) ? UTF8::invalid : bytes[0];
|
case 1: return (((uint8_t)bytes[0] & 0x80) != 0x00) ? UTF8::invalid : (uint8_t)bytes[0];
|
||||||
case 2: return ((bytes[0] & 0xE0) != 0xC0) ? UTF8::invalid : ((bytes[0] & 0x1F) << 6) | (bytes[1] & 0x3F);
|
case 2: return (((uint8_t)bytes[0] & 0xE0) != 0xC0) ? UTF8::invalid : (((uint8_t)bytes[0] & 0x1F) << 6) | ((uint8_t)bytes[1] & 0x3F);
|
||||||
case 3: return ((bytes[0] & 0xF0) != 0xE0) ? UTF8::invalid : ((bytes[0] & 0x0F) << 12) | ((bytes[1] & 0x3F) << 6) | (bytes[2] & 0x3F);
|
case 3: return (((uint8_t)bytes[0] & 0xF0) != 0xE0) ? UTF8::invalid : (((uint8_t)bytes[0] & 0x0F) << 12) | (((uint8_t)bytes[1] & 0x3F) << 6) | ((uint8_t)bytes[2] & 0x3F);
|
||||||
case 4: return ((bytes[0] & 0xF8) != 0xF0) ? UTF8::invalid : ((bytes[0] & 0x07) << 18) | ((bytes[1] & 0x3F) << 12) | ((bytes[2] & 0x3F) << 6) | (bytes[3] & 0x3F);
|
case 4: return (((uint8_t)bytes[0] & 0xF8) != 0xF0) ? UTF8::invalid : (((uint8_t)bytes[0] & 0x07) << 18) | (((uint8_t)bytes[1] & 0x3F) << 12) | (((uint8_t)bytes[2] & 0x3F) << 6) | ((uint8_t)bytes[3] & 0x3F);
|
||||||
}
|
}
|
||||||
|
|
||||||
return UTF8::invalid;
|
return UTF8::invalid;
|
||||||
@@ -75,6 +76,8 @@ namespace BAN::UTF8
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
*ptr = '\0';
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -33,8 +33,9 @@ namespace BAN
|
|||||||
return uniq;
|
return uniq;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NOTE: don't use is_constructible_v<T, Args...> as UniqPtr<T> is allowed with friends
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
static BAN::ErrorOr<UniqPtr> create(Args&&... args)
|
static BAN::ErrorOr<UniqPtr> create(Args&&... args) requires requires(Args&&... args) { T(forward<Args>(args)...); }
|
||||||
{
|
{
|
||||||
UniqPtr uniq;
|
UniqPtr uniq;
|
||||||
uniq.m_pointer = new T(BAN::forward<Args>(args)...);
|
uniq.m_pointer = new T(BAN::forward<Args>(args)...);
|
||||||
|
|||||||
@@ -126,14 +126,16 @@ namespace BAN
|
|||||||
Variant(Variant&& other)
|
Variant(Variant&& other)
|
||||||
: m_index(other.m_index)
|
: m_index(other.m_index)
|
||||||
{
|
{
|
||||||
detail::move_construct<Ts...>(other.m_index, other.m_storage, m_storage);
|
if (other.has_value())
|
||||||
|
detail::move_construct<Ts...>(other.m_index, other.m_storage, m_storage);
|
||||||
other.clear();
|
other.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
Variant(const Variant& other)
|
Variant(const Variant& other)
|
||||||
: m_index(other.m_index)
|
: m_index(other.m_index)
|
||||||
{
|
{
|
||||||
detail::copy_construct<Ts...>(other.m_index, other.m_storage, m_storage);
|
if (other.has_value())
|
||||||
|
detail::copy_construct<Ts...>(other.m_index, other.m_storage, m_storage);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
@@ -157,12 +159,13 @@ namespace BAN
|
|||||||
|
|
||||||
Variant& operator=(Variant&& other)
|
Variant& operator=(Variant&& other)
|
||||||
{
|
{
|
||||||
if (m_index == other.m_index)
|
if (m_index == other.m_index && m_index != invalid_index())
|
||||||
detail::move_assign<Ts...>(m_index, other.m_storage, m_storage);
|
detail::move_assign<Ts...>(m_index, other.m_storage, m_storage);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
clear();
|
clear();
|
||||||
detail::move_construct<Ts...>(other.m_index, other.m_storage, m_storage);
|
if (other.has_value())
|
||||||
|
detail::move_construct<Ts...>(other.m_index, other.m_storage, m_storage);
|
||||||
m_index = other.m_index;
|
m_index = other.m_index;
|
||||||
}
|
}
|
||||||
other.clear();
|
other.clear();
|
||||||
@@ -171,12 +174,13 @@ namespace BAN
|
|||||||
|
|
||||||
Variant& operator=(const Variant& other)
|
Variant& operator=(const Variant& other)
|
||||||
{
|
{
|
||||||
if (m_index == other.m_index)
|
if (m_index == other.m_index && m_index != invalid_index())
|
||||||
detail::copy_assign<Ts...>(m_index, other.m_storage, m_storage);
|
detail::copy_assign<Ts...>(m_index, other.m_storage, m_storage);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
clear();
|
clear();
|
||||||
detail::copy_construct<Ts...>(other.m_index, other.m_storage, m_storage);
|
if (other.has_value())
|
||||||
|
detail::copy_construct<Ts...>(other.m_index, other.m_storage, m_storage);
|
||||||
m_index = other.m_index;
|
m_index = other.m_index;
|
||||||
}
|
}
|
||||||
return *this;
|
return *this;
|
||||||
@@ -217,7 +221,7 @@ namespace BAN
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, typename... Args>
|
template<typename T, typename... Args>
|
||||||
void emplace(Args&&... args) requires (can_have<T>())
|
void emplace(Args&&... args) requires (can_have<T>() && is_constructible_v<T, Args...>)
|
||||||
{
|
{
|
||||||
clear();
|
clear();
|
||||||
m_index = detail::index<T, Ts...>();
|
m_index = detail::index<T, Ts...>();
|
||||||
@@ -286,6 +290,16 @@ namespace BAN
|
|||||||
return **reinterpret_cast<const remove_reference_t<T>**>(m_storage);
|
return **reinterpret_cast<const remove_reference_t<T>**>(m_storage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool has_value() const
|
||||||
|
{
|
||||||
|
return m_index != invalid_index();
|
||||||
|
}
|
||||||
|
|
||||||
|
explicit operator bool() const
|
||||||
|
{
|
||||||
|
return has_value();
|
||||||
|
}
|
||||||
|
|
||||||
void clear()
|
void clear()
|
||||||
{
|
{
|
||||||
if (m_index != invalid_index())
|
if (m_index != invalid_index())
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
#include <BAN/New.h>
|
#include <BAN/New.h>
|
||||||
#include <BAN/PlacementNew.h>
|
#include <BAN/PlacementNew.h>
|
||||||
#include <BAN/Span.h>
|
#include <BAN/Span.h>
|
||||||
|
#include <BAN/Swap.h>
|
||||||
|
|
||||||
namespace BAN
|
namespace BAN
|
||||||
{
|
{
|
||||||
@@ -34,9 +35,9 @@ namespace BAN
|
|||||||
ErrorOr<void> push_back(T&&);
|
ErrorOr<void> push_back(T&&);
|
||||||
ErrorOr<void> push_back(const T&);
|
ErrorOr<void> push_back(const T&);
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
ErrorOr<void> emplace_back(Args&&...);
|
ErrorOr<void> emplace_back(Args&&...) requires is_constructible_v<T, Args...>;
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
ErrorOr<void> emplace(size_type, Args&&...);
|
ErrorOr<void> emplace(size_type, Args&&...) requires is_constructible_v<T, Args...>;
|
||||||
ErrorOr<void> insert(size_type, T&&);
|
ErrorOr<void> insert(size_type, T&&);
|
||||||
ErrorOr<void> insert(size_type, const T&);
|
ErrorOr<void> insert(size_type, const T&);
|
||||||
|
|
||||||
@@ -55,7 +56,7 @@ namespace BAN
|
|||||||
bool contains(const T&) const;
|
bool contains(const T&) const;
|
||||||
|
|
||||||
Span<T> span() { return Span(m_data, m_size); }
|
Span<T> span() { return Span(m_data, m_size); }
|
||||||
const Span<T> span() const { return Span(m_data, m_size); }
|
Span<const T> span() const { return Span(m_data, m_size); }
|
||||||
|
|
||||||
const T& operator[](size_type) const;
|
const T& operator[](size_type) const;
|
||||||
T& operator[](size_type);
|
T& operator[](size_type);
|
||||||
@@ -65,6 +66,8 @@ namespace BAN
|
|||||||
const T& front() const;
|
const T& front() const;
|
||||||
T& front();
|
T& front();
|
||||||
|
|
||||||
|
void reverse();
|
||||||
|
|
||||||
ErrorOr<void> resize(size_type) requires is_default_constructible_v<T>;
|
ErrorOr<void> resize(size_type) requires is_default_constructible_v<T>;
|
||||||
ErrorOr<void> resize(size_type, const T&) requires is_copy_constructible_v<T>;
|
ErrorOr<void> resize(size_type, const T&) requires is_copy_constructible_v<T>;
|
||||||
ErrorOr<void> reserve(size_type);
|
ErrorOr<void> reserve(size_type);
|
||||||
@@ -138,10 +141,13 @@ namespace BAN
|
|||||||
template<typename T>
|
template<typename T>
|
||||||
Vector<T>& Vector<T>::operator=(const Vector<T>& other)
|
Vector<T>& Vector<T>::operator=(const Vector<T>& other)
|
||||||
{
|
{
|
||||||
clear();
|
|
||||||
MUST(ensure_capacity(other.size()));
|
MUST(ensure_capacity(other.size()));
|
||||||
for (size_type i = 0; i < other.size(); i++)
|
for (size_type i = 0; i < BAN::Math::min(size(), other.size()); i++)
|
||||||
|
m_data[i] = other.m_data[i];
|
||||||
|
for (size_type i = size(); i < other.size(); i++)
|
||||||
new (m_data + i) T(other[i]);
|
new (m_data + i) T(other[i]);
|
||||||
|
for (size_type i = other.size(); i < size(); i++)
|
||||||
|
m_data[i].~T();
|
||||||
m_size = other.m_size;
|
m_size = other.m_size;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
@@ -163,7 +169,7 @@ namespace BAN
|
|||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
ErrorOr<void> Vector<T>::emplace_back(Args&&... args)
|
ErrorOr<void> Vector<T>::emplace_back(Args&&... args) requires is_constructible_v<T, Args...>
|
||||||
{
|
{
|
||||||
TRY(ensure_capacity(m_size + 1));
|
TRY(ensure_capacity(m_size + 1));
|
||||||
new (m_data + m_size) T(forward<Args>(args)...);
|
new (m_data + m_size) T(forward<Args>(args)...);
|
||||||
@@ -173,7 +179,7 @@ namespace BAN
|
|||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
ErrorOr<void> Vector<T>::emplace(size_type index, Args&&... args)
|
ErrorOr<void> Vector<T>::emplace(size_type index, Args&&... args) requires is_constructible_v<T, Args...>
|
||||||
{
|
{
|
||||||
ASSERT(index <= m_size);
|
ASSERT(index <= m_size);
|
||||||
TRY(ensure_capacity(m_size + 1));
|
TRY(ensure_capacity(m_size + 1));
|
||||||
@@ -298,6 +304,13 @@ namespace BAN
|
|||||||
return m_data[0];
|
return m_data[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void Vector<T>::reverse()
|
||||||
|
{
|
||||||
|
for (size_type i = 0; i < m_size / 2; i++)
|
||||||
|
BAN::swap(m_data[i], m_data[m_size - i - 1]);
|
||||||
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
ErrorOr<void> Vector<T>::resize(size_type size) requires is_default_constructible_v<T>
|
ErrorOr<void> Vector<T>::resize(size_type size) requires is_default_constructible_v<T>
|
||||||
{
|
{
|
||||||
@@ -368,19 +381,46 @@ namespace BAN
|
|||||||
template<typename T>
|
template<typename T>
|
||||||
ErrorOr<void> Vector<T>::ensure_capacity(size_type size)
|
ErrorOr<void> Vector<T>::ensure_capacity(size_type size)
|
||||||
{
|
{
|
||||||
|
static_assert(alignof(T) <= alignof(max_align_t), "over aligned types not supported");
|
||||||
|
|
||||||
if (m_capacity >= size)
|
if (m_capacity >= size)
|
||||||
return {};
|
return {};
|
||||||
size_type new_cap = BAN::Math::max<size_type>(size, m_capacity * 2);
|
|
||||||
T* new_data = (T*)BAN::allocator(new_cap * sizeof(T));
|
const size_type new_cap = BAN::Math::max<size_type>(size, m_capacity * 2);
|
||||||
if (new_data == nullptr)
|
|
||||||
return Error::from_errno(ENOMEM);
|
if constexpr (BAN::is_trivially_copyable_v<T>)
|
||||||
for (size_type i = 0; i < m_size; i++)
|
|
||||||
{
|
{
|
||||||
new (new_data + i) T(move(m_data[i]));
|
if constexpr (BAN::reallocator)
|
||||||
m_data[i].~T();
|
{
|
||||||
|
auto* new_data = static_cast<T*>(BAN::reallocator(m_data, new_cap * sizeof(T)));
|
||||||
|
if (new_data == nullptr)
|
||||||
|
return Error::from_errno(ENOMEM);
|
||||||
|
m_data = new_data;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto* new_data = static_cast<T*>(BAN::allocator(new_cap * sizeof(T)));
|
||||||
|
if (new_data == nullptr)
|
||||||
|
return Error::from_errno(ENOMEM);
|
||||||
|
memcpy(new_data, m_data, m_size * sizeof(T));
|
||||||
|
BAN::deallocator(m_data);
|
||||||
|
m_data = new_data;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
BAN::deallocator(m_data);
|
else
|
||||||
m_data = new_data;
|
{
|
||||||
|
auto* new_data = static_cast<T*>(BAN::allocator(new_cap * sizeof(T)));
|
||||||
|
if (new_data == nullptr)
|
||||||
|
return Error::from_errno(ENOMEM);
|
||||||
|
for (size_type i = 0; i < m_size; i++)
|
||||||
|
{
|
||||||
|
new (new_data + i) T(move(m_data[i]));
|
||||||
|
m_data[i].~T();
|
||||||
|
}
|
||||||
|
BAN::deallocator(m_data);
|
||||||
|
m_data = new_data;
|
||||||
|
}
|
||||||
|
|
||||||
m_capacity = new_cap;
|
m_capacity = new_cap;
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,10 @@
|
|||||||
|
|
||||||
#include <BAN/RefPtr.h>
|
#include <BAN/RefPtr.h>
|
||||||
|
|
||||||
|
#if __is_kernel
|
||||||
|
#include <kernel/Lock/SpinLock.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace BAN
|
namespace BAN
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -11,22 +15,37 @@ namespace BAN
|
|||||||
template<typename T>
|
template<typename T>
|
||||||
class WeakPtr;
|
class WeakPtr;
|
||||||
|
|
||||||
|
// FIXME: Write this without using locks...
|
||||||
template<typename T>
|
template<typename T>
|
||||||
class WeakLink : public RefCounted<WeakLink<T>>
|
class WeakLink : public RefCounted<WeakLink<T>>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
RefPtr<T> lock() { ASSERT(m_ptr); return raw_ptr(); }
|
RefPtr<T> try_lock() const
|
||||||
T* raw_ptr() { return m_ptr; }
|
{
|
||||||
|
#if __is_kernel
|
||||||
|
Kernel::SpinLockGuard _(m_weak_lock);
|
||||||
|
#endif
|
||||||
|
if (m_ptr && m_ptr->try_ref())
|
||||||
|
return RefPtr<T>::adopt(m_ptr);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
bool valid() const { return m_ptr; }
|
bool valid() const { return m_ptr; }
|
||||||
void invalidate() { m_ptr = nullptr; }
|
void invalidate()
|
||||||
|
{
|
||||||
|
#if __is_kernel
|
||||||
|
Kernel::SpinLockGuard _(m_weak_lock);
|
||||||
|
#endif
|
||||||
|
m_ptr = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
WeakLink(T* ptr) : m_ptr(ptr) {}
|
WeakLink(T* ptr) : m_ptr(ptr) {}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
T* m_ptr;
|
T* m_ptr;
|
||||||
|
#if __is_kernel
|
||||||
|
mutable Kernel::SpinLock m_weak_lock;
|
||||||
|
#endif
|
||||||
friend class RefPtr<WeakLink<T>>;
|
friend class RefPtr<WeakLink<T>>;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -34,7 +53,7 @@ namespace BAN
|
|||||||
class Weakable
|
class Weakable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
~Weakable()
|
virtual ~Weakable()
|
||||||
{
|
{
|
||||||
if (m_link)
|
if (m_link)
|
||||||
m_link->invalidate();
|
m_link->invalidate();
|
||||||
@@ -80,10 +99,10 @@ namespace BAN
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
RefPtr<T> lock()
|
RefPtr<T> lock() const
|
||||||
{
|
{
|
||||||
if (m_link->valid())
|
if (m_link)
|
||||||
return m_link->lock();
|
return m_link->try_lock();
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -91,7 +110,7 @@ namespace BAN
|
|||||||
|
|
||||||
bool valid() const { return m_link && m_link->valid(); }
|
bool valid() const { return m_link && m_link->valid(); }
|
||||||
|
|
||||||
operator bool() const { return valid(); }
|
explicit operator bool() const { return valid(); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
WeakPtr(const RefPtr<WeakLink<T>>& link)
|
WeakPtr(const RefPtr<WeakLink<T>>& link)
|
||||||
|
|||||||
@@ -4,42 +4,51 @@ if (NOT ${CMAKE_SYSTEM_NAME} STREQUAL "banan-os")
|
|||||||
message(FATAL_ERROR "CMAKE_SYSTEM_NAME is not banan-os")
|
message(FATAL_ERROR "CMAKE_SYSTEM_NAME is not banan-os")
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
#add_compile_options(-mno-sse -mno-sse2)
|
|
||||||
add_compile_definitions(__enable_sse=1)
|
|
||||||
|
|
||||||
project(banan-os CXX C ASM)
|
project(banan-os CXX C ASM)
|
||||||
|
|
||||||
set(BANAN_BASE_SYSROOT ${CMAKE_SOURCE_DIR}/base-sysroot.tar.gz)
|
|
||||||
set(BANAN_INCLUDE ${BANAN_SYSROOT}/usr/include)
|
set(BANAN_INCLUDE ${BANAN_SYSROOT}/usr/include)
|
||||||
set(BANAN_LIB ${BANAN_SYSROOT}/usr/lib)
|
set(BANAN_LIB ${BANAN_SYSROOT}/usr/lib)
|
||||||
set(BANAN_BIN ${BANAN_SYSROOT}/usr/bin)
|
set(BANAN_BIN ${BANAN_SYSROOT}/usr/bin)
|
||||||
set(BANAN_SHARE ${BANAN_SYSROOT}/usr/share)
|
set(BANAN_ETC ${BANAN_SYSROOT}/usr/etc)
|
||||||
set(BANAN_BOOT ${BANAN_SYSROOT}/boot)
|
set(BANAN_SHARE ${BANAN_SYSROOT}/usr/share)
|
||||||
|
set(BANAN_BOOT ${BANAN_SYSROOT}/boot)
|
||||||
|
|
||||||
|
set(CMAKE_INSTALL_BINDIR ${BANAN_BIN})
|
||||||
|
set(CMAKE_INSTALL_SBINDIR ${BANAN_BIN})
|
||||||
|
set(CMAKE_INSTALL_LIBDIR ${BANAN_LIB})
|
||||||
|
set(CMAKE_INSTALL_INCLUDEDIR ${BANAN_INCLUDE})
|
||||||
|
set(CMAKE_INSTALL_SYSCONF ${BANAN_ETC})
|
||||||
|
set(CMAKE_INSTALL_MESSAGE NEVER)
|
||||||
|
set(CMAKE_SKIP_INSTALL_ALL_DEPENDENCY True)
|
||||||
|
|
||||||
|
set(CMAKE_STATIC_LIBRARY_PREFIX "")
|
||||||
|
set(CMAKE_SHARED_LIBRARY_PREFIX "")
|
||||||
|
set(BUILD_SHARED_LIBS True)
|
||||||
|
|
||||||
|
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||||
|
|
||||||
|
# include headers of ${library} to ${target}
|
||||||
|
function(banan_include_headers target library)
|
||||||
|
target_include_directories(${target} PUBLIC $<TARGET_PROPERTY:${library},SOURCE_DIR>/include)
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
# include headers and link ${library} to ${target}
|
||||||
|
function(banan_link_library target library)
|
||||||
|
target_link_libraries(${target} PUBLIC ${library})
|
||||||
|
banan_include_headers(${target} ${library})
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
# add install step for all header files of target
|
||||||
|
function(banan_install_headers target)
|
||||||
|
file(GLOB_RECURSE headers RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/include *.h)
|
||||||
|
foreach(header ${headers})
|
||||||
|
get_filename_component(subdirectory ${header} DIRECTORY)
|
||||||
|
install(FILES include/${header} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${subdirectory})
|
||||||
|
endforeach()
|
||||||
|
target_include_directories(${target} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include)
|
||||||
|
endfunction()
|
||||||
|
|
||||||
add_subdirectory(kernel)
|
add_subdirectory(kernel)
|
||||||
add_subdirectory(bootloader)
|
add_subdirectory(bootloader)
|
||||||
add_subdirectory(BAN)
|
add_subdirectory(BAN)
|
||||||
add_subdirectory(libc)
|
|
||||||
add_subdirectory(LibELF)
|
|
||||||
add_subdirectory(userspace)
|
add_subdirectory(userspace)
|
||||||
|
|
||||||
add_custom_target(sysroot
|
|
||||||
COMMAND ${CMAKE_COMMAND} -E make_directory ${BANAN_SYSROOT}
|
|
||||||
COMMAND cd ${BANAN_SYSROOT} && tar xf ${BANAN_BASE_SYSROOT}
|
|
||||||
)
|
|
||||||
|
|
||||||
add_custom_target(headers
|
|
||||||
DEPENDS kernel-headers
|
|
||||||
DEPENDS ban-headers
|
|
||||||
DEPENDS libc-headers
|
|
||||||
DEPENDS libelf-headers
|
|
||||||
)
|
|
||||||
|
|
||||||
add_custom_target(install-sysroot
|
|
||||||
COMMAND cd ${BANAN_SYSROOT} && tar cf ${BANAN_SYSROOT_TAR} *
|
|
||||||
DEPENDS kernel-install
|
|
||||||
DEPENDS ban-install
|
|
||||||
DEPENDS libc-install
|
|
||||||
DEPENDS userspace-install
|
|
||||||
DEPENDS libelf-install
|
|
||||||
)
|
|
||||||
|
|||||||
@@ -1,12 +0,0 @@
|
|||||||
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
|
|
||||||
)
|
|
||||||
@@ -1,405 +0,0 @@
|
|||||||
#include <BAN/ScopeGuard.h>
|
|
||||||
#include <LibELF/ELF.h>
|
|
||||||
#include <LibELF/Values.h>
|
|
||||||
|
|
||||||
#ifdef __is_kernel
|
|
||||||
#include <kernel/FS/VirtualFileSystem.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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,331 +0,0 @@
|
|||||||
#include <BAN/ScopeGuard.h>
|
|
||||||
#include <kernel/Memory/Heap.h>
|
|
||||||
#include <kernel/Lock/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(i686)
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
void LoadableELF::update_suid_sgid(Kernel::Credentials& credentials)
|
|
||||||
{
|
|
||||||
if (m_inode->mode().mode & +Inode::Mode::ISUID)
|
|
||||||
credentials.set_euid(m_inode->uid());
|
|
||||||
if (m_inode->mode().mode & +Inode::Mode::ISGID)
|
|
||||||
credentials.set_egid(m_inode->gid());
|
|
||||||
}
|
|
||||||
|
|
||||||
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();
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
PageTable::with_fast_page(paddr, [&] {
|
|
||||||
memcpy(PageTable::fast_page_as_ptr(), (void*)(start + i * PAGE_SIZE), PAGE_SIZE);
|
|
||||||
});
|
|
||||||
|
|
||||||
new_page_table.map_page_at(paddr, start + i * PAGE_SIZE, flags);
|
|
||||||
elf->m_physical_page_count++;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
ASSERT_NOT_REACHED();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return elf;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,89 +0,0 @@
|
|||||||
#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(i686)
|
|
||||||
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
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,57 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#ifndef __is_kernel
|
|
||||||
#error "This is kernel only header"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <BAN/UniqPtr.h>
|
|
||||||
#include <BAN/Vector.h>
|
|
||||||
|
|
||||||
#include <kernel/Credentials.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();
|
|
||||||
|
|
||||||
void update_suid_sgid(Kernel::Credentials&);
|
|
||||||
|
|
||||||
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 };
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,140 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
namespace LibELF
|
|
||||||
{
|
|
||||||
|
|
||||||
enum ELF_Ident
|
|
||||||
{
|
|
||||||
ELFMAG0 = 0x7F,
|
|
||||||
ELFMAG1 = 'E',
|
|
||||||
ELFMAG2 = 'L',
|
|
||||||
ELFMAG3 = 'F',
|
|
||||||
|
|
||||||
ELFCLASSNONE = 0,
|
|
||||||
ELFCLASS32 = 1,
|
|
||||||
ELFCLASS64 = 2,
|
|
||||||
|
|
||||||
ELFDATANONE = 0,
|
|
||||||
ELFDATA2LSB = 1,
|
|
||||||
ELFDATA2MSB = 2,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum ELF_EI
|
|
||||||
{
|
|
||||||
EI_MAG0 = 0,
|
|
||||||
EI_MAG1 = 1,
|
|
||||||
EI_MAG2 = 2,
|
|
||||||
EI_MAG3 = 3,
|
|
||||||
EI_CLASS = 4,
|
|
||||||
EI_DATA = 5,
|
|
||||||
EI_VERSION = 6,
|
|
||||||
EI_OSABI = 7,
|
|
||||||
EI_ABIVERSION = 8,
|
|
||||||
EI_NIDENT = 16,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum ELF_ET
|
|
||||||
{
|
|
||||||
ET_NONE = 0,
|
|
||||||
ET_REL = 1,
|
|
||||||
ET_EXEC = 2,
|
|
||||||
ET_DYN = 3,
|
|
||||||
ET_CORE = 4,
|
|
||||||
ET_LOOS = 0xfe00,
|
|
||||||
ET_HIOS = 0xfeff,
|
|
||||||
ET_LOPROC = 0xff00,
|
|
||||||
ET_HIPROC = 0xffff,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum ELF_EV
|
|
||||||
{
|
|
||||||
EV_NONE = 0,
|
|
||||||
EV_CURRENT = 1,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum ELF_SHT
|
|
||||||
{
|
|
||||||
SHT_NULL = 0,
|
|
||||||
SHT_PROGBITS = 1,
|
|
||||||
SHT_SYMTAB = 2,
|
|
||||||
SHT_STRTAB = 3,
|
|
||||||
SHT_RELA = 4,
|
|
||||||
SHT_NOBITS = 8,
|
|
||||||
SHT_REL = 9,
|
|
||||||
SHT_SHLIB = 10,
|
|
||||||
SHT_DYNSYM = 11,
|
|
||||||
SHT_LOOS = 0x60000000,
|
|
||||||
SHT_HIOS = 0x6FFFFFFF,
|
|
||||||
SHT_LOPROC = 0x70000000,
|
|
||||||
SHT_HIPROC = 0x7FFFFFFF,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum ELF_SHF
|
|
||||||
{
|
|
||||||
SHF_WRITE = 0x1,
|
|
||||||
SHF_ALLOC = 0x2,
|
|
||||||
SHF_EXECINSTR = 0x4,
|
|
||||||
SHF_MASKOS = 0x0F000000,
|
|
||||||
SHF_MASKPROC = 0xF0000000,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum ELF_SHN
|
|
||||||
{
|
|
||||||
SHN_UNDEF = 0,
|
|
||||||
SHN_LOPROC = 0xFF00,
|
|
||||||
SHN_HIPROC = 0xFF1F,
|
|
||||||
SHN_LOOS = 0xFF20,
|
|
||||||
SHN_HIOS = 0xFF3F,
|
|
||||||
SHN_ABS = 0xFFF1,
|
|
||||||
SHN_COMMON = 0xFFF2,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum ELF_STB
|
|
||||||
{
|
|
||||||
STB_LOCAL = 0,
|
|
||||||
STB_GLOBAL = 1,
|
|
||||||
STB_WEAK = 2,
|
|
||||||
STB_LOOS = 10,
|
|
||||||
STB_HIOS = 12,
|
|
||||||
STB_LOPROC = 13,
|
|
||||||
STB_HIPROC = 15,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum ELF_STT
|
|
||||||
{
|
|
||||||
STT_NOTYPE = 0,
|
|
||||||
STT_OBJECT = 1,
|
|
||||||
STT_FUNC = 2,
|
|
||||||
STT_SECTION = 3,
|
|
||||||
STT_FILE = 4,
|
|
||||||
STT_LOOS = 10,
|
|
||||||
STT_HIOS = 12,
|
|
||||||
STT_LOPROC = 13,
|
|
||||||
STT_HIPROC = 15,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum ELF_PT
|
|
||||||
{
|
|
||||||
PT_NULL = 0,
|
|
||||||
PT_LOAD = 1,
|
|
||||||
PT_DYNAMIC = 2,
|
|
||||||
PT_INTERP = 3,
|
|
||||||
PT_NOTE = 4,
|
|
||||||
PT_SHLIB = 5,
|
|
||||||
PT_PHDR = 6,
|
|
||||||
PT_LOOS = 0x60000000,
|
|
||||||
PT_HIOS = 0x6FFFFFFF,
|
|
||||||
PT_LOPROC = 0x70000000,
|
|
||||||
PT_HIPROC = 0x7FFFFFFF,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum ELF_PF
|
|
||||||
{
|
|
||||||
PF_X = 0x1,
|
|
||||||
PF_W = 0x2,
|
|
||||||
PF_R = 0x4,
|
|
||||||
PF_MASKOS = 0x00FF0000,
|
|
||||||
PF_MASKPROC = 0xFF000000,
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
117
README.md
117
README.md
@@ -1,8 +1,77 @@
|
|||||||

|
[](https://git.bananymous.com/Bananymous/banan-os)
|
||||||
|
[](https://git.bananymous.com/Bananymous/banan-os)
|
||||||
|
[](https://git.bananymous.com/Bananymous/banan-os/src/branch/main/LICENSE)
|
||||||
|
[](https://discord.gg/ehjGySwYdK)
|
||||||
|
|
||||||
# banan-os
|
# 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.
|
This is my hobby operating system written in C++. Currently supports x86\_64 and i686 architectures.
|
||||||
|
|
||||||
|
You can find a live demo [here](https://bananymous.com/banan-os)
|
||||||
|
|
||||||
|
If you want to try out DOOM, you should first enter the GUI environment using the `start-gui` command. Then you can run `doom` in the GUI terminal.
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
#### General
|
||||||
|
- [x] Ring3 userspace
|
||||||
|
- [x] SMP (multiprocessing)
|
||||||
|
- [x] Linear framebuffer (VESA and GOP)
|
||||||
|
- [x] Network stack
|
||||||
|
- [x] ELF executable loading
|
||||||
|
- [x] AML interpreter (partial)
|
||||||
|
- [x] Basic graphical environment
|
||||||
|
- [x] Terminal emulator
|
||||||
|
- [x] Status bar
|
||||||
|
- [x] Program launcher
|
||||||
|
- [ ] Some nice apps
|
||||||
|
- [x] ELF dynamic linking
|
||||||
|
- [x] copy-on-write memory
|
||||||
|
- [x] file mappings
|
||||||
|
- [ ] anonymous mappings
|
||||||
|
|
||||||
|
#### Drivers
|
||||||
|
- [x] NVMe disks
|
||||||
|
- [x] ATA (IDE, SATA) disks
|
||||||
|
- [x] E1000 and E1000E NICs
|
||||||
|
- [x] RTL8111/8168/8211/8411 NICs
|
||||||
|
- [x] PS2 keyboard (all scancode sets)
|
||||||
|
- [x] PS2 mouse
|
||||||
|
- [x] USB
|
||||||
|
- [x] xHCI
|
||||||
|
- [ ] EHCI
|
||||||
|
- [ ] OHCI
|
||||||
|
- [ ] UHCI
|
||||||
|
- [x] Keyboard
|
||||||
|
- [x] Mouse
|
||||||
|
- [x] Mass storage
|
||||||
|
- [x] Hubs
|
||||||
|
- [ ] ...
|
||||||
|
- [ ] virtio devices (network, storage)
|
||||||
|
|
||||||
|
#### Network
|
||||||
|
- [x] ARP
|
||||||
|
- [x] ICMP
|
||||||
|
- [x] IPv4
|
||||||
|
- [x] UDP
|
||||||
|
- [x] TCP (partial and buggy)
|
||||||
|
- [x] Unix domain sockets
|
||||||
|
- [ ] SSL
|
||||||
|
|
||||||
|
#### Filesystems
|
||||||
|
- [x] Virtual filesystem
|
||||||
|
- [x] Ext2
|
||||||
|
- [x] FAT12/16/32
|
||||||
|
- [x] Dev
|
||||||
|
- [x] Ram
|
||||||
|
- [x] Proc
|
||||||
|
- [ ] Sys
|
||||||
|
- [ ] 9P
|
||||||
|
|
||||||
|
#### Bootloader support
|
||||||
|
- [x] GRUB
|
||||||
|
- [x] Custom BIOS bootloader
|
||||||
|
- [ ] Custom UEFI bootloader
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
@@ -15,44 +84,58 @@ Each major component and library has its own subdirectory (kernel, userspace, li
|
|||||||
### Needed packages
|
### Needed packages
|
||||||
|
|
||||||
#### apt (tested on ubuntu 22.04)
|
#### apt (tested on ubuntu 22.04)
|
||||||
```# apt install build-essential git ninja-build texinfo bison flex libgmp-dev libmpfr-dev libmpc-dev parted qemu-system-x86```
|
```# apt install build-essential git ninja-build texinfo bison flex libgmp-dev libmpfr-dev libmpc-dev parted qemu-system-x86 cpu-checker```
|
||||||
|
|
||||||
#### pacman
|
#### pacman
|
||||||
```# pacman -S --needed base-devel git wget cmake ninja parted qemu-system-x86```
|
```# pacman -S --needed base-devel git wget cmake ninja parted qemu-system-x86```
|
||||||
|
|
||||||
> ***NOTE:*** You need cmake version of atleast 2.26. If you are using cmake that is not found from PATH, you can set the CMAKE\_COMMAND environment variable to point to the correct cmake binary. Or you can let build script download correct version of cmake if you don't have one.
|
|
||||||
|
|
||||||
When you clone this reposity, make sure to also clone submodules. This can be done by cloning with the command ```git clone --recurse-submodules https://git.bananymous.com/bananymous/banan-os.git``` or if you have already cloned this repo, run ```git submodule init && git submodule update```.
|
### Compilation
|
||||||
|
|
||||||
To build the toolchain for this os. You can run the following command.
|
To build the toolchain for this os. You can run the following command.
|
||||||
> ***NOTE:*** The following step has to be done only once. This might take a long time since we are compiling binutils and gcc.
|
> ***NOTE:*** The following step has to be done only once. This might take a long time since we are compiling binutils and gcc.
|
||||||
```sh
|
```sh
|
||||||
./script/build.sh toolchain
|
./bos toolchain
|
||||||
```
|
```
|
||||||
|
|
||||||
To build the os itself you can run one of the following commands. You will need root access for disk image creation/modification.
|
To build the os itself you can run one of the following commands. You will need root access for disk image creation/modification.
|
||||||
```sh
|
```sh
|
||||||
./script/build.sh qemu
|
./bos qemu
|
||||||
./script/build.sh qemu-nographic
|
./bos qemu-nographic
|
||||||
./script/build.sh qemu-debug
|
./bos qemu-debug
|
||||||
./script/build.sh bochs
|
./bos bochs
|
||||||
```
|
```
|
||||||
|
|
||||||
You can also build the kernel or disk image without running it:
|
You can also build the kernel or disk image without running it:
|
||||||
```sh
|
```sh
|
||||||
./script/build.sh kernel
|
./bos kernel
|
||||||
./script/build.sh image
|
./bos image
|
||||||
```
|
```
|
||||||
|
|
||||||
|
To build for other architectures set environment variable BANAN\_ARCH=*arch* (e.g. BANAN\_ARCH=i686).
|
||||||
|
|
||||||
|
To change the bootloader you can set environment variable BANAN\_BOOTLOADER; supported values are BANAN (my custom bootloader) and GRUB.
|
||||||
|
|
||||||
|
To run with UEFI set environment variable BANAN\_UEFI\_BOOT=1. You will also have to set OVMF\_PATH to the correct OVMF (default */usr/share/ovmf/x64/OVMF.fd*).
|
||||||
|
|
||||||
|
To build an image with no physical root filesystem, but an initrd set environment variable BANAN\_INITRD=1. This can be used when testing on hardware with unsupported USB controller.
|
||||||
|
|
||||||
If you have corrupted your disk image or want to create new one, you can either manually delete *build/banan-os.img* and build system will automatically create you a new one or you can run the following command.
|
If you have corrupted your disk image or want to create new one, you can either manually delete *build/banan-os.img* and build system will automatically create you a new one or you can run the following command.
|
||||||
```sh
|
```sh
|
||||||
./script/build.sh image-full
|
./bos image-full
|
||||||
```
|
```
|
||||||
|
|
||||||
If you feel like ```./script/build.sh``` is too verbose, there exists a symlink _bos_ in this projects root directory. All build commands can be used with ```./bos args...``` instead.
|
|
||||||
|
|
||||||
I have also created shell completion script for zsh. You can either copy the file in _script/shell-completion/zsh/\_bos_ to _/usr/share/zsh/site-functions/_ or add the _script/shell-completion/zsh_ to your fpath in _.zshrc_.
|
I have also created shell completion script for zsh. You can either copy the file in _script/shell-completion/zsh/\_bos_ to _/usr/share/zsh/site-functions/_ or add the _script/shell-completion/zsh_ to your fpath in _.zshrc_.
|
||||||
|
|
||||||
### Contributing
|
## Contributing
|
||||||
|
|
||||||
Currently I don't accept contributions to this repository unless explicitly told otherwise. This is a learning project for me and I want to do everything myself. Feel free to fork/clone this repo and tinker with it yourself.
|
As the upstream is hosted on my server https://git.bananymous.com/Bananymous/banan-os, merging contributions is not as trivial as it would be on GitHub. You can still send PRs in GitHub in which case I should be able to download the diff and apply it manually. If you want, I can also provide you an account to my git server. In this case please contact me ([email](mailto:oskari.alaranta@bananymous.com), [discord](https://discord.gg/ehjGySwYdK)).
|
||||||
|
|
||||||
|
As this is mostly a learning experience for me, I would appreciate if you first contacted me about adding new features (email, discord, issue, ...). If you send a PR about something I was planning on doing myself and you didn't ask me, I will probably just close it. Bug fixes are always welcome!
|
||||||
|
|
||||||
|
Commit message should be formatted followingly
|
||||||
|
|
||||||
|
1. First line is of the form "_Subject: Description_", where _Subject_ tells the area touched (Kernel, Shell, BuildSystem, ...) and _Description_ is brief description of the change done. First line should fit fully in 72 characters.
|
||||||
|
2. Body of the message should further describe the change and reasoning behind the change.
|
||||||
|
|
||||||
|
All commits should pass the pre-commit hook defined in _.pre-commit-config.yaml_. For instructions on how to setup pre-commit, please see https://pre-commit.com/#install.
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 384 KiB |
Binary file not shown.
@@ -15,5 +15,6 @@ set(BOOTLOADER_SOURCES
|
|||||||
)
|
)
|
||||||
|
|
||||||
add_executable(bootloader ${BOOTLOADER_SOURCES})
|
add_executable(bootloader ${BOOTLOADER_SOURCES})
|
||||||
|
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
target_link_options(bootloader PRIVATE LINKER:-T,${CMAKE_CURRENT_SOURCE_DIR}/linker.ld)
|
target_link_options(bootloader PRIVATE LINKER:-T,${CMAKE_CURRENT_SOURCE_DIR}/linker.ld)
|
||||||
target_link_options(bootloader PRIVATE -nostdlib)
|
target_link_options(bootloader PRIVATE -nostdlib)
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
.include "common.S"
|
||||||
|
|
||||||
.code16
|
.code16
|
||||||
|
|
||||||
#########################################
|
#########################################
|
||||||
@@ -103,12 +105,12 @@ stage2_main:
|
|||||||
movl %edx, %cr0
|
movl %edx, %cr0
|
||||||
|
|
||||||
# jump to protected mode
|
# jump to protected mode
|
||||||
ljmpl $0x18, $protected_mode
|
ljmpl $GDT_CODE32, $protected_mode
|
||||||
|
|
||||||
.code32
|
.code32
|
||||||
protected_mode:
|
protected_mode:
|
||||||
# setup protected mode segments
|
# setup protected mode segments
|
||||||
movw $0x10, %dx
|
movw $GDT_DATA32, %dx
|
||||||
movw %dx, %ds
|
movw %dx, %ds
|
||||||
movw %dx, %es
|
movw %dx, %es
|
||||||
movw %dx, %fs
|
movw %dx, %fs
|
||||||
@@ -127,15 +129,15 @@ enter_unreal_mode:
|
|||||||
movl %cr0, %eax
|
movl %cr0, %eax
|
||||||
orb $1, %al
|
orb $1, %al
|
||||||
movl %eax, %cr0
|
movl %eax, %cr0
|
||||||
ljmpl $0x8, $.enter_unreal_mode_pmode
|
ljmpl $GDT_CODE16, $.enter_unreal_mode_pmode
|
||||||
|
|
||||||
.enter_unreal_mode_pmode:
|
.enter_unreal_mode_pmode:
|
||||||
movw $0x10, %bx
|
movw $GDT_DATA32, %bx
|
||||||
movw %bx, %ds
|
movw %bx, %ds
|
||||||
|
|
||||||
andb $0xFE, %al
|
andb $0xFE, %al
|
||||||
movl %eax, %cr0
|
movl %eax, %cr0
|
||||||
ljmpl $0x0, $.enter_unreal_mode_unreal
|
ljmpl $0x00, $.enter_unreal_mode_unreal
|
||||||
|
|
||||||
.enter_unreal_mode_unreal:
|
.enter_unreal_mode_unreal:
|
||||||
popw %ds
|
popw %ds
|
||||||
@@ -161,7 +163,7 @@ gdt:
|
|||||||
.quad 0x00CF9A000000FFFF # 32-bit code
|
.quad 0x00CF9A000000FFFF # 32-bit code
|
||||||
gdtr:
|
gdtr:
|
||||||
.short . - gdt - 1
|
.short . - gdt - 1
|
||||||
.quad gdt
|
.long gdt
|
||||||
|
|
||||||
banan_boot_info:
|
banan_boot_info:
|
||||||
boot_command_line:
|
boot_command_line:
|
||||||
@@ -170,3 +172,5 @@ banan_boot_info:
|
|||||||
.long framebuffer
|
.long framebuffer
|
||||||
boot_memory_map:
|
boot_memory_map:
|
||||||
.long memory_map
|
.long memory_map
|
||||||
|
boot_kernel_paddr:
|
||||||
|
.long 0
|
||||||
|
|||||||
@@ -84,4 +84,4 @@ command_line:
|
|||||||
# 100 character command line
|
# 100 character command line
|
||||||
command_line_buffer:
|
command_line_buffer:
|
||||||
.ascii "root=/dev/sda2"
|
.ascii "root=/dev/sda2"
|
||||||
.skip 100 - 28
|
.skip 100 - (. - command_line_buffer)
|
||||||
|
|||||||
3
bootloader/bios/common.S
Normal file
3
bootloader/bios/common.S
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
.set GDT_CODE16, 0x08
|
||||||
|
.set GDT_DATA32, 0x10
|
||||||
|
.set GDT_CODE32, 0x18
|
||||||
@@ -5,15 +5,26 @@
|
|||||||
.set e_machine, 18
|
.set e_machine, 18
|
||||||
.set e_version, 20
|
.set e_version, 20
|
||||||
.set e_entry, 24
|
.set e_entry, 24
|
||||||
.set e_phoff, 32
|
|
||||||
.set e_shoff, 40
|
.set e32_phoff, 28
|
||||||
.set e_flags, 48
|
.set e32_shoff, 32
|
||||||
.set e_ehsize, 52
|
.set e32_flags, 36
|
||||||
.set e_phentsize, 54
|
.set e32_ehsize, 40
|
||||||
.set e_phnum, 56
|
.set e32_phentsize, 42
|
||||||
.set e_shentsize, 58
|
.set e32_phnum, 44
|
||||||
.set e_shnum, 60
|
.set e32_shentsize, 46
|
||||||
.set e_shstrndx, 62
|
.set e32_shnum, 48
|
||||||
|
.set e32_shstrndx, 50
|
||||||
|
|
||||||
|
.set e64_phoff, 32
|
||||||
|
.set e64_shoff, 40
|
||||||
|
.set e64_flags, 48
|
||||||
|
.set e64_ehsize, 52
|
||||||
|
.set e64_phentsize, 54
|
||||||
|
.set e64_phnum, 56
|
||||||
|
.set e64_shentsize, 58
|
||||||
|
.set e64_shnum, 60
|
||||||
|
.set e64_shstrndx, 62
|
||||||
|
|
||||||
# e_ident offsets
|
# e_ident offsets
|
||||||
.set EI_CLASS, 4
|
.set EI_CLASS, 4
|
||||||
@@ -22,6 +33,7 @@
|
|||||||
|
|
||||||
# e_ident constants
|
# e_ident constants
|
||||||
.set ELFMAGIC, 0x464C457F
|
.set ELFMAGIC, 0x464C457F
|
||||||
|
.set ELFCLASS32, 1
|
||||||
.set ELFCLASS64, 2
|
.set ELFCLASS64, 2
|
||||||
.set ELFDATA2LSB, 1
|
.set ELFDATA2LSB, 1
|
||||||
.set EV_CURRENT, 1
|
.set EV_CURRENT, 1
|
||||||
@@ -31,18 +43,30 @@
|
|||||||
|
|
||||||
# program header field offsets
|
# program header field offsets
|
||||||
.set p_type, 0
|
.set p_type, 0
|
||||||
.set p_flags, 4
|
|
||||||
.set p_offset, 8
|
.set p32_offset, 4
|
||||||
.set p_vaddr, 16
|
.set p32_vaddr, 8
|
||||||
.set p_paddr, 24
|
.set p32_paddr, 12
|
||||||
.set p_filesz, 32
|
.set p32_filesz, 16
|
||||||
.set p_memsz, 40
|
.set p32_memsz, 20
|
||||||
.set p_align, 48
|
.set p32_flags, 24
|
||||||
|
.set p32_align, 28
|
||||||
|
|
||||||
|
.set p64_flags, 4
|
||||||
|
.set p64_offset, 8
|
||||||
|
.set p64_vaddr, 16
|
||||||
|
.set p64_paddr, 24
|
||||||
|
.set p64_filesz, 32
|
||||||
|
.set p64_memsz, 40
|
||||||
|
.set p64_align, 48
|
||||||
|
|
||||||
# p_type constants
|
# p_type constants
|
||||||
.set PT_NULL, 0
|
.set PT_NULL, 0
|
||||||
.set PT_LOAD, 1
|
.set PT_LOAD, 1
|
||||||
|
|
||||||
|
# mask for entry point and segment loading
|
||||||
|
.set LOAD_MASK, 0x07FFFFFF
|
||||||
|
|
||||||
.code16
|
.code16
|
||||||
.section .stage2
|
.section .stage2
|
||||||
|
|
||||||
@@ -52,8 +76,12 @@ elf_validate_file_header:
|
|||||||
cmpl $ELFMAGIC, (elf_file_header)
|
cmpl $ELFMAGIC, (elf_file_header)
|
||||||
jne .elf_validate_file_header_invalid_magic
|
jne .elf_validate_file_header_invalid_magic
|
||||||
|
|
||||||
|
cmpb $ELFCLASS32, (elf_file_header + EI_CLASS)
|
||||||
|
je .elf_validate_file_header_class_valid
|
||||||
cmpb $ELFCLASS64, (elf_file_header + EI_CLASS)
|
cmpb $ELFCLASS64, (elf_file_header + EI_CLASS)
|
||||||
jne .elf_validate_file_header_only_64bit_supported
|
je .elf_validate_file_header_class_valid
|
||||||
|
jmp .elf_validate_file_header_invalid_class
|
||||||
|
.elf_validate_file_header_class_valid:
|
||||||
|
|
||||||
cmpb $ELFDATA2LSB, (elf_file_header + EI_DATA)
|
cmpb $ELFDATA2LSB, (elf_file_header + EI_DATA)
|
||||||
jne .elf_validate_file_header_only_little_endian_supported
|
jne .elf_validate_file_header_only_little_endian_supported
|
||||||
@@ -72,8 +100,8 @@ elf_validate_file_header:
|
|||||||
.elf_validate_file_header_invalid_magic:
|
.elf_validate_file_header_invalid_magic:
|
||||||
movw $elf_validate_file_header_invalid_magic_msg, %si
|
movw $elf_validate_file_header_invalid_magic_msg, %si
|
||||||
jmp print_and_halt
|
jmp print_and_halt
|
||||||
.elf_validate_file_header_only_64bit_supported:
|
.elf_validate_file_header_invalid_class:
|
||||||
movw $elf_validate_file_header_only_64bit_supported_msg, %si
|
movw $elf_validate_file_header_invalid_class_msg, %si
|
||||||
jmp print_and_halt
|
jmp print_and_halt
|
||||||
.elf_validate_file_header_only_little_endian_supported:
|
.elf_validate_file_header_only_little_endian_supported:
|
||||||
movw $elf_validate_file_header_only_little_endian_supported_msg, %si
|
movw $elf_validate_file_header_only_little_endian_supported_msg, %si
|
||||||
@@ -85,6 +113,59 @@ elf_validate_file_header:
|
|||||||
movw $elf_validate_file_header_not_executable_msg, %si
|
movw $elf_validate_file_header_not_executable_msg, %si
|
||||||
jmp print_and_halt
|
jmp print_and_halt
|
||||||
|
|
||||||
|
# reads memory specified by 32 bit elf_program_header to memory
|
||||||
|
elf_read_program_header32_to_memory:
|
||||||
|
pushal
|
||||||
|
pushl %ebp
|
||||||
|
movl %esp, %ebp
|
||||||
|
|
||||||
|
# memset p_filesz -> p_memsz to 0
|
||||||
|
movl (elf_program_header + p32_filesz), %ebx
|
||||||
|
movl (elf_program_header + p32_vaddr), %edi
|
||||||
|
andl $LOAD_MASK, %edi
|
||||||
|
addl %ebx, %edi
|
||||||
|
movl (elf_program_header + p32_memsz), %ecx
|
||||||
|
subl %ebx, %ecx
|
||||||
|
xorb %al, %al; call memset32
|
||||||
|
|
||||||
|
# read file specified in program header to memory
|
||||||
|
movl (elf_program_header + p32_offset), %eax
|
||||||
|
movl (elf_program_header + p32_vaddr), %edi
|
||||||
|
andl $LOAD_MASK, %edi
|
||||||
|
movl (elf_program_header + p32_filesz), %ecx
|
||||||
|
call *%esi
|
||||||
|
|
||||||
|
leavel
|
||||||
|
popal
|
||||||
|
ret
|
||||||
|
|
||||||
|
|
||||||
|
# reads memory specified by 64 bit elf_program_header to memory
|
||||||
|
elf_read_program_header64_to_memory:
|
||||||
|
pushal
|
||||||
|
pushl %ebp
|
||||||
|
movl %esp, %ebp
|
||||||
|
|
||||||
|
# memset p_filesz -> p_memsz to 0
|
||||||
|
movl (elf_program_header + p64_filesz), %ebx
|
||||||
|
movl (elf_program_header + p64_vaddr), %edi
|
||||||
|
andl $LOAD_MASK, %edi
|
||||||
|
addl %ebx, %edi
|
||||||
|
movl (elf_program_header + p64_memsz), %ecx
|
||||||
|
subl %ebx, %ecx
|
||||||
|
xorb %al, %al; call memset32
|
||||||
|
|
||||||
|
# read file specified in program header to memory
|
||||||
|
movl (elf_program_header + p64_offset), %eax
|
||||||
|
movl (elf_program_header + p64_vaddr), %edi
|
||||||
|
andl $LOAD_MASK, %edi
|
||||||
|
movl (elf_program_header + p64_filesz), %ecx
|
||||||
|
call *%esi
|
||||||
|
|
||||||
|
leavel
|
||||||
|
popal
|
||||||
|
ret
|
||||||
|
|
||||||
|
|
||||||
# read callback format
|
# read callback format
|
||||||
# eax: first byte
|
# eax: first byte
|
||||||
@@ -104,42 +185,72 @@ elf_read_kernel_to_memory:
|
|||||||
movl %esp, %ebp
|
movl %esp, %ebp
|
||||||
subl $2, %esp
|
subl $2, %esp
|
||||||
|
|
||||||
# read file header
|
# read start of file header
|
||||||
movl $0, %eax
|
movl $0, %eax
|
||||||
movl $64, %ecx
|
movl $24, %ecx
|
||||||
movl $elf_file_header, %edi
|
movl $elf_file_header, %edi
|
||||||
call *%esi
|
call *%esi
|
||||||
|
|
||||||
call elf_validate_file_header
|
call elf_validate_file_header
|
||||||
|
|
||||||
cmpl $0, (elf_file_header + e_phoff + 4)
|
# determine file header size
|
||||||
|
movl $52, %ecx
|
||||||
|
movl $64, %edx
|
||||||
|
cmpb $ELFCLASS64, (elf_file_header + EI_CLASS)
|
||||||
|
cmovel %edx, %ecx
|
||||||
|
|
||||||
|
# read full file header
|
||||||
|
movl $0, %eax
|
||||||
|
movl $elf_file_header, %edi
|
||||||
|
call *%esi
|
||||||
|
|
||||||
|
# verify that e_phoff fits in 32 bits
|
||||||
|
cmpb $ELFCLASS64, (elf_file_header + EI_CLASS)
|
||||||
|
jne .elf_read_kernel_to_memory_valid_offset
|
||||||
|
cmpl $0, (elf_file_header + e64_phoff + 4)
|
||||||
jnz .elf_read_kernel_to_memory_unsupported_offset
|
jnz .elf_read_kernel_to_memory_unsupported_offset
|
||||||
|
.elf_read_kernel_to_memory_valid_offset:
|
||||||
|
|
||||||
|
# read architecture phentsize and phnum to fixed locations
|
||||||
|
movw (elf_file_header + e32_phentsize), %ax
|
||||||
|
movw (elf_file_header + e32_phnum), %bx
|
||||||
|
movl (elf_file_header + e32_phoff), %ecx
|
||||||
|
cmpb $ELFCLASS64, (elf_file_header + EI_CLASS)
|
||||||
|
cmovew (elf_file_header + e64_phentsize), %ax
|
||||||
|
cmovew (elf_file_header + e64_phnum), %bx
|
||||||
|
cmovel (elf_file_header + e64_phoff), %ecx
|
||||||
|
movw %ax, (elf_file_header_phentsize)
|
||||||
|
movw %bx, (elf_file_header_phnum)
|
||||||
|
movl %ecx, (elf_file_header_phoff)
|
||||||
|
|
||||||
# current program header
|
# current program header
|
||||||
movw $0, -2(%ebp)
|
movw $0, -2(%ebp)
|
||||||
|
|
||||||
.elf_read_kernel_to_memory_loop_program_headers:
|
.elf_read_kernel_to_memory_loop_program_headers:
|
||||||
movw -2(%ebp), %cx
|
movw -2(%ebp), %cx
|
||||||
cmpw (elf_file_header + e_phnum), %cx
|
cmpw (elf_file_header_phnum), %cx
|
||||||
jae .elf_read_kernel_to_memory_done
|
jae .elf_read_kernel_to_memory_done
|
||||||
|
|
||||||
# eax := program_header_index * e_phentsize + e_phoff
|
# eax := program_header_index * e_phentsize + e_phoff
|
||||||
xorl %eax, %eax
|
xorl %eax, %eax
|
||||||
movw %cx, %ax
|
movw %cx, %ax
|
||||||
xorl %ebx, %ebx
|
xorl %ebx, %ebx
|
||||||
movw (elf_file_header + e_phentsize), %bx
|
movw (elf_file_header_phentsize), %bx
|
||||||
mull %ebx
|
mull %ebx
|
||||||
addl (elf_file_header + e_phoff), %eax
|
addl (elf_file_header_phoff), %eax
|
||||||
jc .elf_read_kernel_to_memory_unsupported_offset
|
jc .elf_read_kernel_to_memory_unsupported_offset
|
||||||
|
|
||||||
# setup program header size and address
|
# determine program header size
|
||||||
movl $56, %ecx
|
movl $32, %ecx
|
||||||
movl $elf_program_header, %edi
|
movl $56, %edx
|
||||||
|
cmpb $ELFCLASS64, (elf_file_header + EI_CLASS)
|
||||||
|
cmovel %edx, %ecx
|
||||||
|
|
||||||
# read the program header
|
# read program header
|
||||||
|
movl $elf_program_header, %edi
|
||||||
call *%esi
|
call *%esi
|
||||||
|
|
||||||
# test if program header is empty
|
# test if program header is NULL header
|
||||||
cmpl $PT_NULL, (elf_program_header + p_type)
|
cmpl $PT_NULL, (elf_program_header + p_type)
|
||||||
je .elf_read_kernel_to_memory_null_program_header
|
je .elf_read_kernel_to_memory_null_program_header
|
||||||
|
|
||||||
@@ -147,33 +258,12 @@ elf_read_kernel_to_memory:
|
|||||||
cmpl $PT_LOAD, (elf_program_header + p_type)
|
cmpl $PT_LOAD, (elf_program_header + p_type)
|
||||||
jne .elf_read_kernel_to_memory_not_loadable_header
|
jne .elf_read_kernel_to_memory_not_loadable_header
|
||||||
|
|
||||||
# memset p_filesz -> p_memsz to 0
|
# read program header to memory
|
||||||
movl (elf_program_header + p_filesz), %ebx
|
movl $elf_read_program_header32_to_memory, %eax
|
||||||
|
movl $elf_read_program_header64_to_memory, %ebx
|
||||||
movl (elf_program_header + p_vaddr), %edi
|
cmpb $ELFCLASS64, (elf_file_header + EI_CLASS)
|
||||||
andl $0x7FFFFFFF, %edi
|
cmovel %ebx, %eax
|
||||||
addl %ebx, %edi
|
call *%eax
|
||||||
|
|
||||||
movl (elf_program_header + p_memsz), %ecx
|
|
||||||
subl %ebx, %ecx
|
|
||||||
jz .elf_read_kernel_to_memory_memset_done
|
|
||||||
|
|
||||||
.elf_read_kernel_to_memory_memset:
|
|
||||||
movb $0, (%edi)
|
|
||||||
incl %edi
|
|
||||||
decl %ecx
|
|
||||||
jnz .elf_read_kernel_to_memory_memset
|
|
||||||
.elf_read_kernel_to_memory_memset_done:
|
|
||||||
|
|
||||||
# read file specified in program header to memory
|
|
||||||
movl (elf_program_header + p_offset), %eax
|
|
||||||
movl (elf_program_header + p_vaddr), %edi
|
|
||||||
andl $0x7FFFFFFF, %edi
|
|
||||||
movl (elf_program_header + p_filesz), %ecx
|
|
||||||
|
|
||||||
#call print_hex32; call print_newline
|
|
||||||
|
|
||||||
call *%esi
|
|
||||||
|
|
||||||
.elf_read_kernel_to_memory_null_program_header:
|
.elf_read_kernel_to_memory_null_program_header:
|
||||||
incw -2(%ebp)
|
incw -2(%ebp)
|
||||||
@@ -185,7 +275,7 @@ elf_read_kernel_to_memory:
|
|||||||
|
|
||||||
# set kernel entry address
|
# set kernel entry address
|
||||||
movl (elf_file_header + e_entry), %eax
|
movl (elf_file_header + e_entry), %eax
|
||||||
andl $0x7FFFFF, %eax
|
andl $LOAD_MASK, %eax
|
||||||
|
|
||||||
ret
|
ret
|
||||||
|
|
||||||
@@ -200,8 +290,8 @@ elf_read_kernel_to_memory:
|
|||||||
|
|
||||||
elf_validate_file_header_invalid_magic_msg:
|
elf_validate_file_header_invalid_magic_msg:
|
||||||
.asciz "ELF: file has invalid ELF magic"
|
.asciz "ELF: file has invalid ELF magic"
|
||||||
elf_validate_file_header_only_64bit_supported_msg:
|
elf_validate_file_header_invalid_class_msg:
|
||||||
.asciz "ELF: file is not targettint 64 bit"
|
.asciz "ELF: file has invalid ELF class"
|
||||||
elf_validate_file_header_only_little_endian_supported_msg:
|
elf_validate_file_header_only_little_endian_supported_msg:
|
||||||
.asciz "ELF: file is not in little endian format"
|
.asciz "ELF: file is not in little endian format"
|
||||||
elf_validate_file_header_not_current_version_msg:
|
elf_validate_file_header_not_current_version_msg:
|
||||||
@@ -219,5 +309,12 @@ elf_read_kernel_to_memory_not_loadable_header_msg:
|
|||||||
elf_file_header:
|
elf_file_header:
|
||||||
.skip 64
|
.skip 64
|
||||||
|
|
||||||
|
elf_file_header_phentsize:
|
||||||
|
.skip 2
|
||||||
|
elf_file_header_phnum:
|
||||||
|
.skip 2
|
||||||
|
elf_file_header_phoff:
|
||||||
|
.skip 4 # NOTE: only 32 bit offsets are supported
|
||||||
|
|
||||||
elf_program_header:
|
elf_program_header:
|
||||||
.skip 56
|
.skip 56
|
||||||
|
|||||||
@@ -454,15 +454,7 @@ ext2_inode_read_bytes:
|
|||||||
movl $ext2_block_buffer, %esi
|
movl $ext2_block_buffer, %esi
|
||||||
addl %edx, %esi
|
addl %edx, %esi
|
||||||
|
|
||||||
# very dumb memcpy with 32 bit addresses
|
call memcpy32
|
||||||
xorl %ebx, %ebx
|
|
||||||
.ext2_inode_read_bytes_memcpy_partial:
|
|
||||||
movb (%esi, %ebx), %al
|
|
||||||
movb %al, (%edi, %ebx)
|
|
||||||
incl %ebx
|
|
||||||
decl %ecx
|
|
||||||
jnz .ext2_inode_read_bytes_memcpy_partial
|
|
||||||
addl %ebx, %edi
|
|
||||||
|
|
||||||
# check if all sectors are read
|
# check if all sectors are read
|
||||||
cmpl $0, 4(%esp)
|
cmpl $0, 4(%esp)
|
||||||
@@ -487,16 +479,8 @@ ext2_inode_read_bytes:
|
|||||||
addl %ecx, 0(%esp)
|
addl %ecx, 0(%esp)
|
||||||
subl %ecx, 4(%esp)
|
subl %ecx, 4(%esp)
|
||||||
|
|
||||||
# very dumb memcpy with 32 bit addresses
|
|
||||||
movl $ext2_block_buffer, %esi
|
movl $ext2_block_buffer, %esi
|
||||||
movl $0, %ebx
|
call memcpy32
|
||||||
.ext2_inode_read_bytes_memcpy:
|
|
||||||
movb (%esi, %ebx), %al
|
|
||||||
movb %al, (%edi, %ebx)
|
|
||||||
incl %ebx
|
|
||||||
decl %ecx
|
|
||||||
jnz .ext2_inode_read_bytes_memcpy
|
|
||||||
addl %ebx, %edi
|
|
||||||
|
|
||||||
# read next block if more sectors remaining
|
# read next block if more sectors remaining
|
||||||
cmpl $0, 4(%esp)
|
cmpl $0, 4(%esp)
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
.include "common.S"
|
||||||
|
|
||||||
.set SCREEN_WIDTH, 80
|
.set SCREEN_WIDTH, 80
|
||||||
.set SCREEN_HEIGHT, 25
|
.set SCREEN_HEIGHT, 25
|
||||||
|
|
||||||
@@ -273,6 +275,109 @@ isprint:
|
|||||||
movb $0, %al
|
movb $0, %al
|
||||||
ret
|
ret
|
||||||
|
|
||||||
|
|
||||||
|
# memset with 32 bit registers
|
||||||
|
# edi: destination address
|
||||||
|
# ecx: bytes count
|
||||||
|
# al: value to set
|
||||||
|
# return:
|
||||||
|
# edi: destination address + bytes count
|
||||||
|
# ecx: 0
|
||||||
|
# other: preserved
|
||||||
|
.global memset32
|
||||||
|
memset32:
|
||||||
|
testl %ecx, %ecx
|
||||||
|
jz .memset32_done
|
||||||
|
|
||||||
|
pushf; cli
|
||||||
|
pushw %es
|
||||||
|
pushl %eax
|
||||||
|
pushl %ebx
|
||||||
|
pushl %edx
|
||||||
|
|
||||||
|
movl %cr0, %ebx
|
||||||
|
orb $1, %bl
|
||||||
|
movl %ebx, %cr0
|
||||||
|
|
||||||
|
ljmpl $GDT_CODE32, $.memset32_pmode32
|
||||||
|
|
||||||
|
.code32
|
||||||
|
.memset32_pmode32:
|
||||||
|
movw $GDT_DATA32, %dx
|
||||||
|
movw %dx, %es
|
||||||
|
|
||||||
|
rep stosb %es:(%edi)
|
||||||
|
|
||||||
|
ljmpl $GDT_CODE16, $.memset32_pmode16
|
||||||
|
|
||||||
|
.code16
|
||||||
|
.memset32_pmode16:
|
||||||
|
andb $0xFE, %bl
|
||||||
|
movl %ebx, %cr0
|
||||||
|
ljmpl $0x00, $.memset32_rmode16
|
||||||
|
|
||||||
|
.memset32_rmode16:
|
||||||
|
popl %edx
|
||||||
|
popl %ebx
|
||||||
|
popl %eax
|
||||||
|
popw %es
|
||||||
|
popf
|
||||||
|
|
||||||
|
.memset32_done:
|
||||||
|
ret
|
||||||
|
|
||||||
|
# memcpy with 32 bit registers
|
||||||
|
# esi: source address
|
||||||
|
# edi: destination address
|
||||||
|
# ecx: bytes count
|
||||||
|
# return:
|
||||||
|
# esi: source address + bytes count
|
||||||
|
# edi: destination address + bytes count
|
||||||
|
# ecx: 0
|
||||||
|
# other: preserved
|
||||||
|
.global memcpy32
|
||||||
|
memcpy32:
|
||||||
|
testl %ecx, %ecx
|
||||||
|
jz .memcpy32_done
|
||||||
|
|
||||||
|
pushf; cli
|
||||||
|
pushw %ds
|
||||||
|
pushw %es
|
||||||
|
pushl %ebx
|
||||||
|
pushl %edx
|
||||||
|
|
||||||
|
movl %cr0, %ebx
|
||||||
|
orb $1, %bl
|
||||||
|
movl %ebx, %cr0
|
||||||
|
|
||||||
|
ljmpl $GDT_CODE32, $.memcpy32_pmode32
|
||||||
|
|
||||||
|
.code32
|
||||||
|
.memcpy32_pmode32:
|
||||||
|
movw $GDT_DATA32, %dx
|
||||||
|
movw %dx, %ds
|
||||||
|
movw %dx, %es
|
||||||
|
|
||||||
|
rep movsb %ds:(%esi), %es:(%edi)
|
||||||
|
|
||||||
|
ljmpl $GDT_CODE16, $.memcpy32_pmode16
|
||||||
|
|
||||||
|
.code16
|
||||||
|
.memcpy32_pmode16:
|
||||||
|
andb $0xFE, %bl
|
||||||
|
movl %ebx, %cr0
|
||||||
|
ljmpl $0x00, $.memcpy32_rmode16
|
||||||
|
|
||||||
|
.memcpy32_rmode16:
|
||||||
|
popl %edx
|
||||||
|
popl %ebx
|
||||||
|
popw %es
|
||||||
|
popw %ds
|
||||||
|
popf
|
||||||
|
|
||||||
|
.memcpy32_done:
|
||||||
|
ret
|
||||||
|
|
||||||
.section .bss
|
.section .bss
|
||||||
|
|
||||||
# enough for base 2 printing
|
# enough for base 2 printing
|
||||||
|
|||||||
@@ -1,6 +1,11 @@
|
|||||||
cmake_minimum_required(VERSION 3.26)
|
cmake_minimum_required(VERSION 3.26)
|
||||||
|
|
||||||
project(x86_64-banan_os-bootloader-installer CXX)
|
if (NOT DEFINED ENV{BANAN_ARCH})
|
||||||
|
message(FATAL_ERROR "environment variable BANAN_ARCH not defined")
|
||||||
|
endif ()
|
||||||
|
set(BANAN_ARCH $ENV{BANAN_ARCH})
|
||||||
|
|
||||||
|
project(banan_os-bootloader-installer CXX)
|
||||||
|
|
||||||
set(SOURCES
|
set(SOURCES
|
||||||
crc32.cpp
|
crc32.cpp
|
||||||
@@ -10,8 +15,8 @@ set(SOURCES
|
|||||||
main.cpp
|
main.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
add_executable(x86_64-banan_os-bootloader-installer ${SOURCES})
|
add_executable(banan_os-bootloader-installer ${SOURCES})
|
||||||
target_compile_options(x86_64-banan_os-bootloader-installer PRIVATE -O2 -std=c++20)
|
target_compile_options(banan_os-bootloader-installer PRIVATE -O2 -std=c++20)
|
||||||
target_compile_definitions(x86_64-banan_os-bootloader-installer PRIVATE __arch=x86_64)
|
target_compile_definitions(banan_os-bootloader-installer PRIVATE __arch=${BANAN_ARCH})
|
||||||
target_include_directories(x86_64-banan_os-bootloader-installer PRIVATE ${CMAKE_SOURCE_DIR}/../../LibELF/include)
|
target_include_directories(banan_os-bootloader-installer PRIVATE ${CMAKE_SOURCE_DIR}/../../userspace/libraries/LibELF/include)
|
||||||
target_include_directories(x86_64-banan_os-bootloader-installer PRIVATE ${CMAKE_SOURCE_DIR}/../../kernel/include)
|
target_include_directories(banan_os-bootloader-installer PRIVATE ${CMAKE_SOURCE_DIR}/../../kernel/include)
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ bool ELFFile::validate_elf_header() const
|
|||||||
|
|
||||||
#if ARCH(x86_64)
|
#if ARCH(x86_64)
|
||||||
if (elf_header.e_ident[EI_CLASS] != ELFCLASS64)
|
if (elf_header.e_ident[EI_CLASS] != ELFCLASS64)
|
||||||
#elif ARCH(i386)
|
#elif ARCH(i686)
|
||||||
if (elf_header.e_ident[EI_CLASS] != ELFCLASS32)
|
if (elf_header.e_ident[EI_CLASS] != ELFCLASS32)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,17 +1,16 @@
|
|||||||
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 "i686")
|
|
||||||
set(ELF_FORMAT elf32-i386)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
set(KERNEL_SOURCES
|
set(KERNEL_SOURCES
|
||||||
font/prefs.psf.o
|
font/prefs.psf.o
|
||||||
kernel/ACPI.cpp
|
kernel/ACPI/ACPI.cpp
|
||||||
|
kernel/ACPI/AML/Namespace.cpp
|
||||||
|
kernel/ACPI/AML/Node.cpp
|
||||||
|
kernel/ACPI/AML/OpRegion.cpp
|
||||||
|
kernel/ACPI/BatterySystem.cpp
|
||||||
|
kernel/ACPI/EmbeddedController.cpp
|
||||||
kernel/APIC.cpp
|
kernel/APIC.cpp
|
||||||
|
kernel/Audio/AC97/Controller.cpp
|
||||||
|
kernel/Audio/Controller.cpp
|
||||||
|
kernel/Audio/HDAudio/AudioFunctionGroup.cpp
|
||||||
|
kernel/Audio/HDAudio/Controller.cpp
|
||||||
kernel/BootInfo.cpp
|
kernel/BootInfo.cpp
|
||||||
kernel/CPUID.cpp
|
kernel/CPUID.cpp
|
||||||
kernel/Credentials.cpp
|
kernel/Credentials.cpp
|
||||||
@@ -20,21 +19,29 @@ set(KERNEL_SOURCES
|
|||||||
kernel/Device/Device.cpp
|
kernel/Device/Device.cpp
|
||||||
kernel/Device/FramebufferDevice.cpp
|
kernel/Device/FramebufferDevice.cpp
|
||||||
kernel/Device/NullDevice.cpp
|
kernel/Device/NullDevice.cpp
|
||||||
|
kernel/Device/RandomDevice.cpp
|
||||||
kernel/Device/ZeroDevice.cpp
|
kernel/Device/ZeroDevice.cpp
|
||||||
|
kernel/ELF.cpp
|
||||||
|
kernel/Epoll.cpp
|
||||||
kernel/Errors.cpp
|
kernel/Errors.cpp
|
||||||
kernel/Font.cpp
|
|
||||||
kernel/FS/DevFS/FileSystem.cpp
|
kernel/FS/DevFS/FileSystem.cpp
|
||||||
|
kernel/FS/EventFD.cpp
|
||||||
kernel/FS/Ext2/FileSystem.cpp
|
kernel/FS/Ext2/FileSystem.cpp
|
||||||
kernel/FS/Ext2/Inode.cpp
|
kernel/FS/Ext2/Inode.cpp
|
||||||
|
kernel/FS/FAT/FileSystem.cpp
|
||||||
|
kernel/FS/FAT/Inode.cpp
|
||||||
|
kernel/FS/FileSystem.cpp
|
||||||
kernel/FS/Inode.cpp
|
kernel/FS/Inode.cpp
|
||||||
kernel/FS/Pipe.cpp
|
kernel/FS/Pipe.cpp
|
||||||
kernel/FS/ProcFS/FileSystem.cpp
|
kernel/FS/ProcFS/FileSystem.cpp
|
||||||
kernel/FS/ProcFS/Inode.cpp
|
kernel/FS/ProcFS/Inode.cpp
|
||||||
kernel/FS/TmpFS/FileSystem.cpp
|
kernel/FS/TmpFS/FileSystem.cpp
|
||||||
kernel/FS/TmpFS/Inode.cpp
|
kernel/FS/TmpFS/Inode.cpp
|
||||||
|
kernel/FS/USTARModule.cpp
|
||||||
kernel/FS/VirtualFileSystem.cpp
|
kernel/FS/VirtualFileSystem.cpp
|
||||||
kernel/Input/KeyboardLayout.cpp
|
kernel/GDT.cpp
|
||||||
kernel/Input/KeyEvent.cpp
|
kernel/IDT.cpp
|
||||||
|
kernel/Input/InputDevice.cpp
|
||||||
kernel/Input/PS2/Controller.cpp
|
kernel/Input/PS2/Controller.cpp
|
||||||
kernel/Input/PS2/Device.cpp
|
kernel/Input/PS2/Device.cpp
|
||||||
kernel/Input/PS2/Keyboard.cpp
|
kernel/Input/PS2/Keyboard.cpp
|
||||||
@@ -43,6 +50,8 @@ set(KERNEL_SOURCES
|
|||||||
kernel/Interruptable.cpp
|
kernel/Interruptable.cpp
|
||||||
kernel/InterruptController.cpp
|
kernel/InterruptController.cpp
|
||||||
kernel/kernel.cpp
|
kernel/kernel.cpp
|
||||||
|
kernel/Lock/SpinLock.cpp
|
||||||
|
kernel/Memory/ByteRingBuffer.cpp
|
||||||
kernel/Memory/DMARegion.cpp
|
kernel/Memory/DMARegion.cpp
|
||||||
kernel/Memory/FileBackedRegion.cpp
|
kernel/Memory/FileBackedRegion.cpp
|
||||||
kernel/Memory/Heap.cpp
|
kernel/Memory/Heap.cpp
|
||||||
@@ -50,14 +59,18 @@ set(KERNEL_SOURCES
|
|||||||
kernel/Memory/MemoryBackedRegion.cpp
|
kernel/Memory/MemoryBackedRegion.cpp
|
||||||
kernel/Memory/MemoryRegion.cpp
|
kernel/Memory/MemoryRegion.cpp
|
||||||
kernel/Memory/PhysicalRange.cpp
|
kernel/Memory/PhysicalRange.cpp
|
||||||
|
kernel/Memory/SharedMemoryObject.cpp
|
||||||
kernel/Memory/VirtualRange.cpp
|
kernel/Memory/VirtualRange.cpp
|
||||||
kernel/Networking/ARPTable.cpp
|
kernel/Networking/ARPTable.cpp
|
||||||
kernel/Networking/E1000/E1000.cpp
|
kernel/Networking/E1000/E1000.cpp
|
||||||
kernel/Networking/E1000/E1000E.cpp
|
kernel/Networking/E1000/E1000E.cpp
|
||||||
kernel/Networking/IPv4Layer.cpp
|
kernel/Networking/IPv4Layer.cpp
|
||||||
|
kernel/Networking/Loopback.cpp
|
||||||
kernel/Networking/NetworkInterface.cpp
|
kernel/Networking/NetworkInterface.cpp
|
||||||
|
kernel/Networking/NetworkLayer.cpp
|
||||||
kernel/Networking/NetworkManager.cpp
|
kernel/Networking/NetworkManager.cpp
|
||||||
kernel/Networking/NetworkSocket.cpp
|
kernel/Networking/NetworkSocket.cpp
|
||||||
|
kernel/Networking/RTL8169/RTL8169.cpp
|
||||||
kernel/Networking/TCPSocket.cpp
|
kernel/Networking/TCPSocket.cpp
|
||||||
kernel/Networking/UDPSocket.cpp
|
kernel/Networking/UDPSocket.cpp
|
||||||
kernel/Networking/UNIX/Socket.cpp
|
kernel/Networking/UNIX/Socket.cpp
|
||||||
@@ -69,7 +82,6 @@ set(KERNEL_SOURCES
|
|||||||
kernel/Processor.cpp
|
kernel/Processor.cpp
|
||||||
kernel/Random.cpp
|
kernel/Random.cpp
|
||||||
kernel/Scheduler.cpp
|
kernel/Scheduler.cpp
|
||||||
kernel/Semaphore.cpp
|
|
||||||
kernel/SSP.cpp
|
kernel/SSP.cpp
|
||||||
kernel/Storage/ATA/AHCI/Controller.cpp
|
kernel/Storage/ATA/AHCI/Controller.cpp
|
||||||
kernel/Storage/ATA/AHCI/Device.cpp
|
kernel/Storage/ATA/AHCI/Device.cpp
|
||||||
@@ -81,21 +93,38 @@ set(KERNEL_SOURCES
|
|||||||
kernel/Storage/NVMe/Namespace.cpp
|
kernel/Storage/NVMe/Namespace.cpp
|
||||||
kernel/Storage/NVMe/Queue.cpp
|
kernel/Storage/NVMe/Queue.cpp
|
||||||
kernel/Storage/Partition.cpp
|
kernel/Storage/Partition.cpp
|
||||||
|
kernel/Storage/SCSI.cpp
|
||||||
kernel/Storage/StorageDevice.cpp
|
kernel/Storage/StorageDevice.cpp
|
||||||
kernel/Syscall.cpp
|
kernel/Syscall.cpp
|
||||||
kernel/Terminal/FramebufferTerminal.cpp
|
kernel/Terminal/FramebufferTerminal.cpp
|
||||||
|
kernel/Terminal/PseudoTerminal.cpp
|
||||||
kernel/Terminal/Serial.cpp
|
kernel/Terminal/Serial.cpp
|
||||||
|
kernel/Terminal/TerminalDriver.cpp
|
||||||
|
kernel/Terminal/TextModeTerminal.cpp
|
||||||
kernel/Terminal/TTY.cpp
|
kernel/Terminal/TTY.cpp
|
||||||
kernel/Terminal/VirtualTTY.cpp
|
kernel/Terminal/VirtualTTY.cpp
|
||||||
kernel/Thread.cpp
|
kernel/Thread.cpp
|
||||||
|
kernel/ThreadBlocker.cpp
|
||||||
kernel/Timer/HPET.cpp
|
kernel/Timer/HPET.cpp
|
||||||
kernel/Timer/PIT.cpp
|
kernel/Timer/PIT.cpp
|
||||||
kernel/Timer/RTC.cpp
|
kernel/Timer/RTC.cpp
|
||||||
kernel/Timer/Timer.cpp
|
kernel/Timer/Timer.cpp
|
||||||
|
kernel/USB/Controller.cpp
|
||||||
|
kernel/USB/Device.cpp
|
||||||
|
kernel/USB/HID/HIDDriver.cpp
|
||||||
|
kernel/USB/HID/Joystick.cpp
|
||||||
|
kernel/USB/HID/Keyboard.cpp
|
||||||
|
kernel/USB/HID/Mouse.cpp
|
||||||
|
kernel/USB/Hub/HubDriver.cpp
|
||||||
|
kernel/USB/MassStorage/MassStorageDriver.cpp
|
||||||
|
kernel/USB/MassStorage/SCSIDevice.cpp
|
||||||
|
kernel/USB/USBManager.cpp
|
||||||
|
kernel/USB/XHCI/Controller.cpp
|
||||||
|
kernel/USB/XHCI/Device.cpp
|
||||||
icxxabi.cpp
|
icxxabi.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
#set(ENABLE_KERNEL_UBSAN True)
|
set(ENABLE_KERNEL_UBSAN False)
|
||||||
|
|
||||||
if(ENABLE_KERNEL_UBSAN)
|
if(ENABLE_KERNEL_UBSAN)
|
||||||
set(KERNEL_SOURCES ${KERNEL_SOURCES} ubsan.cpp)
|
set(KERNEL_SOURCES ${KERNEL_SOURCES} ubsan.cpp)
|
||||||
@@ -105,31 +134,25 @@ if("${BANAN_ARCH}" STREQUAL "x86_64")
|
|||||||
set(KERNEL_SOURCES
|
set(KERNEL_SOURCES
|
||||||
${KERNEL_SOURCES}
|
${KERNEL_SOURCES}
|
||||||
arch/x86_64/boot.S
|
arch/x86_64/boot.S
|
||||||
arch/x86_64/GDT.cpp
|
|
||||||
arch/x86_64/IDT.cpp
|
|
||||||
arch/x86_64/interrupts.S
|
arch/x86_64/interrupts.S
|
||||||
arch/x86_64/PageTable.cpp
|
arch/x86_64/PageTable.cpp
|
||||||
arch/x86_64/Signal.S
|
arch/x86_64/Signal.S
|
||||||
arch/x86_64/Syscall.S
|
arch/x86_64/Syscall.S
|
||||||
arch/x86_64/Thread.S
|
arch/x86_64/Thread.S
|
||||||
)
|
arch/x86_64/User.S
|
||||||
file(GLOB_RECURSE LAI_SOURCES
|
arch/x86_64/Yield.S
|
||||||
lai/*.c
|
|
||||||
)
|
|
||||||
set(LAI_SOURCES
|
|
||||||
${LAI_SOURCES}
|
|
||||||
kernel/lai_host.cpp
|
|
||||||
)
|
)
|
||||||
elseif("${BANAN_ARCH}" STREQUAL "i686")
|
elseif("${BANAN_ARCH}" STREQUAL "i686")
|
||||||
set(KERNEL_SOURCES
|
set(KERNEL_SOURCES
|
||||||
${KERNEL_SOURCES}
|
${KERNEL_SOURCES}
|
||||||
arch/i686/boot.S
|
arch/i686/boot.S
|
||||||
arch/i686/GDT.cpp
|
arch/i686/interrupts.S
|
||||||
arch/i686/IDT.cpp
|
|
||||||
arch/i686/PageTable.cpp
|
arch/i686/PageTable.cpp
|
||||||
arch/i686/Signal.S
|
arch/i686/Signal.S
|
||||||
arch/i686/Syscall.S
|
arch/i686/Syscall.S
|
||||||
arch/i686/Thread.S
|
arch/i686/Thread.S
|
||||||
|
arch/i686/User.S
|
||||||
|
arch/i686/Yield.S
|
||||||
)
|
)
|
||||||
else()
|
else()
|
||||||
message(FATAL_ERROR "unsupported architecure ${BANAN_ARCH}")
|
message(FATAL_ERROR "unsupported architecure ${BANAN_ARCH}")
|
||||||
@@ -138,7 +161,6 @@ endif()
|
|||||||
set(BAN_SOURCES
|
set(BAN_SOURCES
|
||||||
../BAN/BAN/Assert.cpp
|
../BAN/BAN/Assert.cpp
|
||||||
../BAN/BAN/New.cpp
|
../BAN/BAN/New.cpp
|
||||||
../BAN/BAN/String.cpp
|
|
||||||
../BAN/BAN/StringView.cpp
|
../BAN/BAN/StringView.cpp
|
||||||
../BAN/BAN/Time.cpp
|
../BAN/BAN/Time.cpp
|
||||||
)
|
)
|
||||||
@@ -146,63 +168,81 @@ set(BAN_SOURCES
|
|||||||
set(KLIBC_SOURCES
|
set(KLIBC_SOURCES
|
||||||
klibc/ctype.cpp
|
klibc/ctype.cpp
|
||||||
klibc/string.cpp
|
klibc/string.cpp
|
||||||
|
klibc/arch/${BANAN_ARCH}/string.S
|
||||||
)
|
)
|
||||||
|
|
||||||
set(LIBELF_SOURCES
|
set(LIBDEFLATE_SOURCE
|
||||||
../LibELF/LibELF/LoadableELF.cpp
|
../userspace/libraries/LibDEFLATE/Compressor.cpp
|
||||||
|
../userspace/libraries/LibDEFLATE/Decompressor.cpp
|
||||||
|
../userspace/libraries/LibDEFLATE/HuffmanTree.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
set(LIBFONT_SOURCES
|
||||||
|
../userspace/libraries/LibFont/Font.cpp
|
||||||
|
../userspace/libraries/LibFont/PSF.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
set(LIBINPUT_SOURCE
|
||||||
|
../userspace/libraries/LibInput/KeyboardLayout.cpp
|
||||||
|
../userspace/libraries/LibInput/KeyEvent.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
set(LIBQR_SOURCE
|
||||||
|
../userspace/libraries/LibQR/QRCode.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
set(KERNEL_SOURCES
|
set(KERNEL_SOURCES
|
||||||
${KERNEL_SOURCES}
|
${KERNEL_SOURCES}
|
||||||
${LAI_SOURCES}
|
|
||||||
${BAN_SOURCES}
|
${BAN_SOURCES}
|
||||||
${KLIBC_SOURCES}
|
${KLIBC_SOURCES}
|
||||||
${LIBELF_SOURCES}
|
${LIBDEFLATE_SOURCE}
|
||||||
|
${LIBFONT_SOURCES}
|
||||||
|
${LIBINPUT_SOURCE}
|
||||||
|
${LIBQR_SOURCE}
|
||||||
)
|
)
|
||||||
|
|
||||||
add_executable(kernel ${KERNEL_SOURCES})
|
add_executable(kernel ${KERNEL_SOURCES})
|
||||||
add_dependencies(kernel headers)
|
|
||||||
|
|
||||||
target_compile_definitions(kernel PUBLIC __is_kernel)
|
target_compile_definitions(kernel PRIVATE __is_kernel)
|
||||||
target_compile_definitions(kernel PUBLIC __arch=${BANAN_ARCH})
|
target_compile_definitions(kernel PRIVATE __arch=${BANAN_ARCH})
|
||||||
|
target_compile_definitions(kernel PRIVATE LIBDEFLATE_AVOID_STACK=1)
|
||||||
|
|
||||||
target_compile_options(kernel PUBLIC -O2 -g)
|
target_compile_options(kernel PRIVATE
|
||||||
target_compile_options(kernel PUBLIC $<$<COMPILE_LANGUAGE:CXX>:-Wno-literal-suffix -fno-rtti -fno-exceptions>)
|
-O2 -g
|
||||||
target_compile_options(kernel PUBLIC -fmacro-prefix-map=${CMAKE_CURRENT_SOURCE_DIR}=.)
|
-fmacro-prefix-map=${CMAKE_CURRENT_SOURCE_DIR}=.
|
||||||
target_compile_options(kernel PUBLIC -fstack-protector -ffreestanding -Wall -Wextra -Werror -Wstack-usage=1024 -fno-omit-frame-pointer -mgeneral-regs-only)
|
-fstack-protector
|
||||||
|
-ffreestanding
|
||||||
|
-fno-omit-frame-pointer
|
||||||
|
-fstrict-volatile-bitfields
|
||||||
|
-mgeneral-regs-only
|
||||||
|
-Wall -Wextra -Werror -Wstack-usage=1024
|
||||||
|
)
|
||||||
|
|
||||||
# This might not work with other toolchains
|
# C++ specific
|
||||||
target_compile_options(kernel PUBLIC $<$<COMPILE_LANGUAGE:CXX>:-Wno-invalid-offsetof>)
|
target_compile_options(kernel PRIVATE
|
||||||
|
-Wno-literal-suffix
|
||||||
|
-Wno-invalid-offsetof
|
||||||
|
-fno-rtti
|
||||||
|
-fno-exceptions
|
||||||
|
)
|
||||||
|
|
||||||
if(ENABLE_KERNEL_UBSAN)
|
if(ENABLE_KERNEL_UBSAN)
|
||||||
target_compile_options(kernel PUBLIC -fsanitize=undefined)
|
target_compile_options(kernel PRIVATE -fsanitize=undefined)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if("${BANAN_ARCH}" STREQUAL "x86_64")
|
if("${BANAN_ARCH}" STREQUAL "x86_64")
|
||||||
target_compile_options(kernel PUBLIC -mcmodel=kernel -mno-red-zone)
|
target_compile_options(kernel PRIVATE -mcmodel=kernel -mno-red-zone)
|
||||||
target_link_options(kernel PUBLIC LINKER:-z,max-page-size=4096)
|
target_link_options(kernel PRIVATE LINKER:-z,max-page-size=4096)
|
||||||
target_link_options(kernel PUBLIC LINKER:-T,${CMAKE_CURRENT_SOURCE_DIR}/arch/x86_64/linker.ld)
|
target_link_options(kernel PRIVATE LINKER:-T,${CMAKE_CURRENT_SOURCE_DIR}/arch/x86_64/linker.ld)
|
||||||
elseif("${BANAN_ARCH}" STREQUAL "i686")
|
elseif("${BANAN_ARCH}" STREQUAL "i686")
|
||||||
target_link_options(kernel PUBLIC LINKER:-T,${CMAKE_CURRENT_SOURCE_DIR}/arch/i686/linker.ld)
|
target_link_options(kernel PRIVATE LINKER:-T,${CMAKE_CURRENT_SOURCE_DIR}/arch/i686/linker.ld)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
target_link_options(kernel PUBLIC -ffreestanding -nostdlib)
|
target_link_options(kernel PRIVATE -ffreestanding -nostdlib -orphan-handling=error)
|
||||||
|
|
||||||
set_source_files_properties(${LAI_SOURCES} PROPERTIES COMPILE_FLAGS -Wno-stack-usage)
|
get_target_property(KERNEL_COMPILE_OPTIONS kernel COMPILE_OPTIONS)
|
||||||
|
execute_process(COMMAND ${CMAKE_CXX_COMPILER} ${KERNEL_COMPILE_OPTIONS} -print-file-name=crtbegin.o OUTPUT_VARIABLE CRTBEGIN OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||||
add_custom_target(kernel-headers
|
execute_process(COMMAND ${CMAKE_CXX_COMPILER} ${KERNEL_COMPILE_OPTIONS} -print-file-name=crtend.o OUTPUT_VARIABLE CRTEND OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||||
COMMAND ${CMAKE_COMMAND} -E copy_directory_if_different ${CMAKE_CURRENT_SOURCE_DIR}/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(
|
add_custom_command(
|
||||||
TARGET kernel PRE_LINK
|
TARGET kernel PRE_LINK
|
||||||
@@ -217,9 +257,27 @@ add_custom_command(
|
|||||||
# COMMAND x86_64-banan_os-strip ${CMAKE_CURRENT_BINARY_DIR}/kernel
|
# COMMAND x86_64-banan_os-strip ${CMAKE_CURRENT_BINARY_DIR}/kernel
|
||||||
#)
|
#)
|
||||||
|
|
||||||
|
banan_include_headers(kernel ban)
|
||||||
|
banan_include_headers(kernel libc)
|
||||||
|
banan_include_headers(kernel libdeflate)
|
||||||
|
banan_include_headers(kernel libelf)
|
||||||
|
banan_include_headers(kernel libfont)
|
||||||
|
banan_include_headers(kernel libinput)
|
||||||
|
banan_include_headers(kernel libqr)
|
||||||
|
|
||||||
|
banan_install_headers(kernel)
|
||||||
|
set_target_properties(kernel PROPERTIES OUTPUT_NAME banan-os.kernel)
|
||||||
|
install(TARGETS kernel DESTINATION ${BANAN_BOOT} OPTIONAL)
|
||||||
|
|
||||||
|
if("${BANAN_ARCH}" STREQUAL "x86_64")
|
||||||
|
set(ELF_FORMAT elf64-x86-64)
|
||||||
|
elseif("${BANAN_ARCH}" STREQUAL "i686")
|
||||||
|
set(ELF_FORMAT elf32-i386)
|
||||||
|
endif()
|
||||||
|
|
||||||
add_custom_command(
|
add_custom_command(
|
||||||
OUTPUT font/prefs.psf.o
|
OUTPUT font/prefs.psf.o
|
||||||
COMMAND cd ${CMAKE_CURRENT_SOURCE_DIR} && objcopy -O ${ELF_FORMAT} -B i386 -I binary font/prefs.psf ${CMAKE_CURRENT_BINARY_DIR}/font/prefs.psf.o
|
COMMAND cd ${CMAKE_CURRENT_SOURCE_DIR} && mkdir -p ${CMAKE_CURRENT_BINARY_DIR}/font && 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 ")
|
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 ")
|
||||||
|
|||||||
@@ -1,21 +0,0 @@
|
|||||||
#include <kernel/GDT.h>
|
|
||||||
|
|
||||||
namespace Kernel
|
|
||||||
{
|
|
||||||
|
|
||||||
GDT* GDT::create()
|
|
||||||
{
|
|
||||||
ASSERT_NOT_REACHED();
|
|
||||||
}
|
|
||||||
|
|
||||||
void GDT::write_entry(uint8_t, uint32_t, uint32_t, uint8_t, uint8_t)
|
|
||||||
{
|
|
||||||
ASSERT_NOT_REACHED();
|
|
||||||
}
|
|
||||||
|
|
||||||
void GDT::write_tss()
|
|
||||||
{
|
|
||||||
ASSERT_NOT_REACHED();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
#include <kernel/IDT.h>
|
|
||||||
|
|
||||||
namespace Kernel
|
|
||||||
{
|
|
||||||
|
|
||||||
IDT* IDT::create()
|
|
||||||
{
|
|
||||||
ASSERT_NOT_REACHED();
|
|
||||||
}
|
|
||||||
|
|
||||||
[[noreturn]] void IDT::force_triple_fault()
|
|
||||||
{
|
|
||||||
ASSERT_NOT_REACHED();
|
|
||||||
}
|
|
||||||
|
|
||||||
void IDT::register_irq_handler(uint8_t, Interruptable*)
|
|
||||||
{
|
|
||||||
ASSERT_NOT_REACHED();
|
|
||||||
}
|
|
||||||
|
|
||||||
void IDT::register_interrupt_handler(uint8_t, void (*)())
|
|
||||||
{
|
|
||||||
ASSERT_NOT_REACHED();
|
|
||||||
}
|
|
||||||
|
|
||||||
void IDT::register_syscall_handler(uint8_t, void (*)())
|
|
||||||
{
|
|
||||||
ASSERT_NOT_REACHED();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,144 +1,757 @@
|
|||||||
#include <kernel/Memory/PageTable.h>
|
#include <kernel/BootInfo.h>
|
||||||
|
#include <kernel/CPUID.h>
|
||||||
#include <kernel/Lock/SpinLock.h>
|
#include <kernel/Lock/SpinLock.h>
|
||||||
|
#include <kernel/Memory/kmalloc.h>
|
||||||
|
#include <kernel/Memory/PageTable.h>
|
||||||
|
|
||||||
|
extern uint8_t g_kernel_start[];
|
||||||
|
extern uint8_t g_kernel_end[];
|
||||||
|
|
||||||
|
extern uint8_t g_kernel_execute_start[];
|
||||||
|
extern uint8_t g_kernel_execute_end[];
|
||||||
|
|
||||||
|
extern uint8_t g_kernel_writable_start[];
|
||||||
|
extern uint8_t g_kernel_writable_end[];
|
||||||
|
|
||||||
|
extern uint8_t g_userspace_start[];
|
||||||
|
extern uint8_t g_userspace_end[];
|
||||||
|
|
||||||
namespace Kernel
|
namespace Kernel
|
||||||
{
|
{
|
||||||
|
|
||||||
RecursiveSpinLock PageTable::s_fast_page_lock;
|
SpinLock PageTable::s_fast_page_lock;
|
||||||
|
|
||||||
void PageTable::initialize()
|
constexpr uint64_t s_page_flag_mask = 0x8000000000000FFF;
|
||||||
|
constexpr uint64_t s_page_addr_mask = ~s_page_flag_mask;
|
||||||
|
|
||||||
|
static bool s_is_post_heap_done = false;
|
||||||
|
|
||||||
|
static PageTable* s_kernel = nullptr;
|
||||||
|
static bool s_has_nxe = false;
|
||||||
|
static bool s_has_pge = false;
|
||||||
|
static bool s_has_pat = false;
|
||||||
|
|
||||||
|
static paddr_t s_global_pdpte = 0;
|
||||||
|
|
||||||
|
static inline PageTable::flags_t parse_flags(uint64_t entry)
|
||||||
{
|
{
|
||||||
ASSERT_NOT_REACHED();
|
using Flags = PageTable::Flags;
|
||||||
|
|
||||||
|
PageTable::flags_t result = 0;
|
||||||
|
if (s_has_nxe && !(entry & (1ull << 63)))
|
||||||
|
result |= Flags::Execute;
|
||||||
|
if (entry & Flags::Reserved)
|
||||||
|
result |= Flags::Reserved;
|
||||||
|
if (entry & Flags::UserSupervisor)
|
||||||
|
result |= Flags::UserSupervisor;
|
||||||
|
if (entry & Flags::ReadWrite)
|
||||||
|
result |= Flags::ReadWrite;
|
||||||
|
if (entry & Flags::Present)
|
||||||
|
result |= Flags::Present;
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
PageTable& PageTable::kernel()
|
void PageTable::initialize_pre_heap()
|
||||||
{
|
{
|
||||||
ASSERT_NOT_REACHED();
|
if (CPUID::has_nxe())
|
||||||
|
s_has_nxe = true;
|
||||||
|
|
||||||
|
if (CPUID::has_pge())
|
||||||
|
s_has_pge = true;
|
||||||
|
|
||||||
|
if (CPUID::has_pat())
|
||||||
|
s_has_pat = true;
|
||||||
|
|
||||||
|
ASSERT(s_kernel == nullptr);
|
||||||
|
s_kernel = new PageTable();
|
||||||
|
ASSERT(s_kernel);
|
||||||
|
|
||||||
|
s_kernel->initialize_kernel();
|
||||||
|
s_kernel->initial_load();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PageTable::is_valid_pointer(uintptr_t)
|
void PageTable::initialize_post_heap()
|
||||||
{
|
{
|
||||||
ASSERT_NOT_REACHED();
|
s_is_post_heap_done = true;
|
||||||
}
|
|
||||||
|
|
||||||
BAN::ErrorOr<PageTable*> PageTable::create_userspace()
|
|
||||||
{
|
|
||||||
ASSERT_NOT_REACHED();
|
|
||||||
}
|
|
||||||
|
|
||||||
PageTable::~PageTable()
|
|
||||||
{
|
|
||||||
ASSERT_NOT_REACHED();
|
|
||||||
}
|
|
||||||
|
|
||||||
void PageTable::unmap_page(vaddr_t)
|
|
||||||
{
|
|
||||||
ASSERT_NOT_REACHED();
|
|
||||||
}
|
|
||||||
|
|
||||||
void PageTable::unmap_range(vaddr_t, size_t)
|
|
||||||
{
|
|
||||||
ASSERT_NOT_REACHED();
|
|
||||||
}
|
|
||||||
|
|
||||||
void PageTable::map_range_at(paddr_t, vaddr_t, size_t, flags_t)
|
|
||||||
{
|
|
||||||
ASSERT_NOT_REACHED();
|
|
||||||
}
|
|
||||||
|
|
||||||
void PageTable::map_page_at(paddr_t, vaddr_t, flags_t)
|
|
||||||
{
|
|
||||||
ASSERT_NOT_REACHED();
|
|
||||||
}
|
|
||||||
|
|
||||||
paddr_t PageTable::physical_address_of(vaddr_t) const
|
|
||||||
{
|
|
||||||
ASSERT_NOT_REACHED();
|
|
||||||
}
|
|
||||||
|
|
||||||
PageTable::flags_t PageTable::get_page_flags(vaddr_t) const
|
|
||||||
{
|
|
||||||
ASSERT_NOT_REACHED();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool PageTable::is_page_free(vaddr_t) const
|
|
||||||
{
|
|
||||||
ASSERT_NOT_REACHED();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool PageTable::is_range_free(vaddr_t, size_t) const
|
|
||||||
{
|
|
||||||
ASSERT_NOT_REACHED();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool PageTable::reserve_page(vaddr_t, bool)
|
|
||||||
{
|
|
||||||
ASSERT_NOT_REACHED();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool PageTable::reserve_range(vaddr_t, size_t, bool)
|
|
||||||
{
|
|
||||||
ASSERT_NOT_REACHED();
|
|
||||||
}
|
|
||||||
|
|
||||||
vaddr_t PageTable::reserve_free_page(vaddr_t, vaddr_t)
|
|
||||||
{
|
|
||||||
ASSERT_NOT_REACHED();
|
|
||||||
}
|
|
||||||
|
|
||||||
vaddr_t PageTable::reserve_free_contiguous_pages(size_t, vaddr_t, vaddr_t)
|
|
||||||
{
|
|
||||||
ASSERT_NOT_REACHED();
|
|
||||||
}
|
|
||||||
|
|
||||||
void PageTable::load()
|
|
||||||
{
|
|
||||||
ASSERT_NOT_REACHED();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PageTable::initial_load()
|
void PageTable::initial_load()
|
||||||
{
|
{
|
||||||
ASSERT_NOT_REACHED();
|
if (s_has_nxe)
|
||||||
|
{
|
||||||
|
asm volatile(
|
||||||
|
"movl $0xC0000080, %%ecx;"
|
||||||
|
"rdmsr;"
|
||||||
|
"orl $0x800, %%eax;"
|
||||||
|
"wrmsr"
|
||||||
|
::: "eax", "ecx", "edx", "memory"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s_has_pge)
|
||||||
|
{
|
||||||
|
asm volatile(
|
||||||
|
"movl %%cr4, %%eax;"
|
||||||
|
"orl $0x80, %%eax;"
|
||||||
|
"movl %%eax, %%cr4;"
|
||||||
|
::: "eax"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s_has_pat)
|
||||||
|
{
|
||||||
|
asm volatile(
|
||||||
|
"movl $0x277, %%ecx;"
|
||||||
|
"rdmsr;"
|
||||||
|
"movw $0x0401, %%dx;"
|
||||||
|
"wrmsr;"
|
||||||
|
::: "eax", "ecx", "edx", "memory"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// enable write protect
|
||||||
|
asm volatile(
|
||||||
|
"movl %%cr0, %%eax;"
|
||||||
|
"orl $0x10000, %%eax;"
|
||||||
|
"movl %%eax, %%cr0;"
|
||||||
|
::: "rax"
|
||||||
|
);
|
||||||
|
|
||||||
|
load();
|
||||||
}
|
}
|
||||||
|
|
||||||
void PageTable::debug_dump()
|
PageTable& PageTable::kernel()
|
||||||
{
|
{
|
||||||
ASSERT_NOT_REACHED();
|
ASSERT(s_kernel);
|
||||||
|
return *s_kernel;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t PageTable::get_page_data(vaddr_t) const
|
bool PageTable::is_valid_pointer(uintptr_t)
|
||||||
{
|
{
|
||||||
ASSERT_NOT_REACHED();
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint64_t* allocate_zeroed_page_aligned_page()
|
||||||
|
{
|
||||||
|
void* page = kmalloc(PAGE_SIZE, PAGE_SIZE, true);
|
||||||
|
ASSERT(page);
|
||||||
|
memset(page, 0, PAGE_SIZE);
|
||||||
|
return (uint64_t*)page;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
static paddr_t V2P(const T vaddr)
|
||||||
|
{
|
||||||
|
return (vaddr_t)vaddr - KERNEL_OFFSET + g_boot_info.kernel_paddr;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
static uint64_t* P2V(const T paddr)
|
||||||
|
{
|
||||||
|
return reinterpret_cast<uint64_t*>(reinterpret_cast<paddr_t>(paddr) - g_boot_info.kernel_paddr + KERNEL_OFFSET);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PageTable::initialize_kernel()
|
void PageTable::initialize_kernel()
|
||||||
{
|
{
|
||||||
ASSERT_NOT_REACHED();
|
ASSERT(s_global_pdpte == 0);
|
||||||
}
|
s_global_pdpte = V2P(allocate_zeroed_page_aligned_page());
|
||||||
|
|
||||||
void PageTable::map_kernel_memory()
|
map_kernel_memory();
|
||||||
{
|
|
||||||
ASSERT_NOT_REACHED();
|
prepare_fast_page();
|
||||||
|
|
||||||
|
// Map (phys_kernel_start -> phys_kernel_end) to (virt_kernel_start -> virt_kernel_end)
|
||||||
|
ASSERT((vaddr_t)g_kernel_start % PAGE_SIZE == 0);
|
||||||
|
map_range_at(
|
||||||
|
V2P(g_kernel_start),
|
||||||
|
(vaddr_t)g_kernel_start,
|
||||||
|
g_kernel_end - g_kernel_start,
|
||||||
|
Flags::Present
|
||||||
|
);
|
||||||
|
|
||||||
|
// Map executable kernel memory as executable
|
||||||
|
map_range_at(
|
||||||
|
V2P(g_kernel_execute_start),
|
||||||
|
(vaddr_t)g_kernel_execute_start,
|
||||||
|
g_kernel_execute_end - g_kernel_execute_start,
|
||||||
|
Flags::Execute | Flags::Present
|
||||||
|
);
|
||||||
|
|
||||||
|
// Map writable kernel memory as writable
|
||||||
|
map_range_at(
|
||||||
|
V2P(g_kernel_writable_start),
|
||||||
|
(vaddr_t)g_kernel_writable_start,
|
||||||
|
g_kernel_writable_end - g_kernel_writable_start,
|
||||||
|
Flags::ReadWrite | Flags::Present
|
||||||
|
);
|
||||||
|
|
||||||
|
// Map userspace memory
|
||||||
|
map_range_at(
|
||||||
|
V2P(g_userspace_start),
|
||||||
|
(vaddr_t)g_userspace_start,
|
||||||
|
g_userspace_end - g_userspace_start,
|
||||||
|
Flags::Execute | Flags::UserSupervisor | Flags::Present
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PageTable::prepare_fast_page()
|
void PageTable::prepare_fast_page()
|
||||||
{
|
{
|
||||||
ASSERT_NOT_REACHED();
|
constexpr uint64_t pdpte = (fast_page() >> 30) & 0x1FF;
|
||||||
|
constexpr uint64_t pde = (fast_page() >> 21) & 0x1FF;
|
||||||
|
constexpr uint64_t pte = (fast_page() >> 12) & 0x1FF;
|
||||||
|
|
||||||
|
const uint64_t* pdpt = P2V(m_highest_paging_struct);
|
||||||
|
ASSERT(pdpt[pdpte] & Flags::Present);
|
||||||
|
|
||||||
|
uint64_t* pd = P2V(pdpt[pdpte] & s_page_addr_mask);
|
||||||
|
ASSERT(!(pd[pde] & Flags::Present));
|
||||||
|
pd[pde] = V2P(allocate_zeroed_page_aligned_page()) | Flags::ReadWrite | Flags::Present;
|
||||||
|
|
||||||
|
uint64_t* pt = P2V(pd[pde] & s_page_addr_mask);
|
||||||
|
ASSERT(pt[pte] == 0);
|
||||||
|
pt[pte] = Flags::Reserved;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PageTable::invalidate(vaddr_t)
|
void PageTable::map_fast_page(paddr_t paddr)
|
||||||
{
|
{
|
||||||
ASSERT_NOT_REACHED();
|
ASSERT(s_kernel);
|
||||||
}
|
ASSERT(paddr);
|
||||||
|
ASSERT(paddr % PAGE_SIZE == 0);
|
||||||
|
|
||||||
void PageTable::map_fast_page(paddr_t)
|
ASSERT(s_fast_page_lock.current_processor_has_lock());
|
||||||
{
|
|
||||||
ASSERT_NOT_REACHED();
|
constexpr uint64_t pdpte = (fast_page() >> 30) & 0x1FF;
|
||||||
|
constexpr uint64_t pde = (fast_page() >> 21) & 0x1FF;
|
||||||
|
constexpr uint64_t pte = (fast_page() >> 12) & 0x1FF;
|
||||||
|
|
||||||
|
uint64_t* pdpt = P2V(s_kernel->m_highest_paging_struct);
|
||||||
|
uint64_t* pd = P2V(pdpt[pdpte] & s_page_addr_mask);
|
||||||
|
uint64_t* pt = P2V(pd[pde] & s_page_addr_mask);
|
||||||
|
|
||||||
|
ASSERT(!(pt[pte] & Flags::Present));
|
||||||
|
pt[pte] = paddr | Flags::ReadWrite | Flags::Present;
|
||||||
|
|
||||||
|
asm volatile("invlpg (%0)" :: "r"(fast_page()) : "memory");
|
||||||
}
|
}
|
||||||
|
|
||||||
void PageTable::unmap_fast_page()
|
void PageTable::unmap_fast_page()
|
||||||
{
|
{
|
||||||
ASSERT_NOT_REACHED();
|
ASSERT(s_kernel);
|
||||||
|
|
||||||
|
ASSERT(s_fast_page_lock.current_processor_has_lock());
|
||||||
|
|
||||||
|
constexpr uint64_t pdpte = (fast_page() >> 30) & 0x1FF;
|
||||||
|
constexpr uint64_t pde = (fast_page() >> 21) & 0x1FF;
|
||||||
|
constexpr uint64_t pte = (fast_page() >> 12) & 0x1FF;
|
||||||
|
|
||||||
|
uint64_t* pdpt = P2V(s_kernel->m_highest_paging_struct);
|
||||||
|
uint64_t* pd = P2V(pdpt[pdpte] & s_page_addr_mask);
|
||||||
|
uint64_t* pt = P2V(pd[pde] & s_page_addr_mask);
|
||||||
|
|
||||||
|
ASSERT(pt[pte] & Flags::Present);
|
||||||
|
pt[pte] = Flags::Reserved;
|
||||||
|
|
||||||
|
asm volatile("invlpg (%0)" :: "r"(fast_page()) : "memory");
|
||||||
|
}
|
||||||
|
|
||||||
|
BAN::ErrorOr<PageTable*> PageTable::create_userspace()
|
||||||
|
{
|
||||||
|
SpinLockGuard _(s_kernel->m_lock);
|
||||||
|
PageTable* page_table = new PageTable;
|
||||||
|
if (page_table == nullptr)
|
||||||
|
return BAN::Error::from_errno(ENOMEM);
|
||||||
|
page_table->map_kernel_memory();
|
||||||
|
return page_table;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PageTable::map_kernel_memory()
|
||||||
|
{
|
||||||
|
ASSERT(s_kernel);
|
||||||
|
ASSERT(s_global_pdpte);
|
||||||
|
|
||||||
|
ASSERT(m_highest_paging_struct == 0);
|
||||||
|
m_highest_paging_struct = V2P(kmalloc(32, 32, true));
|
||||||
|
ASSERT(m_highest_paging_struct);
|
||||||
|
|
||||||
|
uint64_t* pdpt = P2V(m_highest_paging_struct);
|
||||||
|
pdpt[0] = 0;
|
||||||
|
pdpt[1] = 0;
|
||||||
|
pdpt[2] = 0;
|
||||||
|
pdpt[3] = s_global_pdpte | Flags::Present;
|
||||||
|
static_assert(KERNEL_OFFSET == 0xC0000000);
|
||||||
|
}
|
||||||
|
|
||||||
|
PageTable::~PageTable()
|
||||||
|
{
|
||||||
|
if (m_highest_paging_struct == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
uint64_t* pdpt = P2V(m_highest_paging_struct);
|
||||||
|
for (uint32_t pdpte = 0; pdpte < 3; pdpte++)
|
||||||
|
{
|
||||||
|
if (!(pdpt[pdpte] & Flags::Present))
|
||||||
|
continue;
|
||||||
|
uint64_t* pd = P2V(pdpt[pdpte] & s_page_addr_mask);
|
||||||
|
for (uint32_t pde = 0; pde < 512; pde++)
|
||||||
|
{
|
||||||
|
if (!(pd[pde] & Flags::Present))
|
||||||
|
continue;
|
||||||
|
kfree(P2V(pd[pde] & s_page_addr_mask));
|
||||||
|
}
|
||||||
|
kfree(pd);
|
||||||
|
}
|
||||||
|
kfree(pdpt);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PageTable::load()
|
||||||
|
{
|
||||||
|
SpinLockGuard _(m_lock);
|
||||||
|
ASSERT(m_highest_paging_struct < 0x100000000);
|
||||||
|
asm volatile("movl %0, %%cr3" :: "r"(static_cast<uint32_t>(m_highest_paging_struct)));
|
||||||
|
Processor::set_current_page_table(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PageTable::invalidate_range(vaddr_t vaddr, size_t pages, bool send_smp_message)
|
||||||
|
{
|
||||||
|
ASSERT(vaddr % PAGE_SIZE == 0);
|
||||||
|
|
||||||
|
const bool is_userspace = (vaddr < KERNEL_OFFSET);
|
||||||
|
if (is_userspace && this != &PageTable::current())
|
||||||
|
;
|
||||||
|
else if (pages <= 32 || !s_is_post_heap_done)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < pages; i++, vaddr += PAGE_SIZE)
|
||||||
|
asm volatile("invlpg (%0)" :: "r"(vaddr));
|
||||||
|
}
|
||||||
|
else if (is_userspace || !s_has_pge)
|
||||||
|
{
|
||||||
|
asm volatile("movl %0, %%cr3" :: "r"(static_cast<uint32_t>(m_highest_paging_struct)));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
asm volatile(
|
||||||
|
"movl %%cr4, %%eax;"
|
||||||
|
|
||||||
|
"andl $~0x80, %%eax;"
|
||||||
|
"movl %%eax, %%cr4;"
|
||||||
|
|
||||||
|
"movl %0, %%cr3;"
|
||||||
|
|
||||||
|
"orl $0x80, %%eax;"
|
||||||
|
"movl %%eax, %%cr4;"
|
||||||
|
:
|
||||||
|
: "r"(static_cast<uint32_t>(m_highest_paging_struct))
|
||||||
|
: "eax"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (send_smp_message)
|
||||||
|
{
|
||||||
|
Processor::broadcast_smp_message({
|
||||||
|
.type = Processor::SMPMessage::Type::FlushTLB,
|
||||||
|
.flush_tlb = {
|
||||||
|
.vaddr = vaddr,
|
||||||
|
.page_count = pages,
|
||||||
|
.page_table = vaddr < KERNEL_OFFSET ? this : nullptr,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PageTable::unmap_page(vaddr_t vaddr, bool invalidate)
|
||||||
|
{
|
||||||
|
ASSERT(vaddr);
|
||||||
|
ASSERT(vaddr % PAGE_SIZE == 0);
|
||||||
|
ASSERT(vaddr != fast_page());
|
||||||
|
if (vaddr >= KERNEL_OFFSET)
|
||||||
|
ASSERT(vaddr >= (vaddr_t)g_kernel_start);
|
||||||
|
if ((vaddr >= KERNEL_OFFSET) != (this == s_kernel))
|
||||||
|
Kernel::panic("unmapping {8H}, kernel: {}", vaddr, this == s_kernel);
|
||||||
|
|
||||||
|
const uint64_t pdpte = (vaddr >> 30) & 0x1FF;
|
||||||
|
const uint64_t pde = (vaddr >> 21) & 0x1FF;
|
||||||
|
const uint64_t pte = (vaddr >> 12) & 0x1FF;
|
||||||
|
|
||||||
|
SpinLockGuard _(m_lock);
|
||||||
|
|
||||||
|
if (is_page_free(vaddr))
|
||||||
|
Kernel::panic("trying to unmap unmapped page 0x{H}", vaddr);
|
||||||
|
|
||||||
|
uint64_t* pdpt = P2V(m_highest_paging_struct);
|
||||||
|
uint64_t* pd = P2V(pdpt[pdpte] & s_page_addr_mask);
|
||||||
|
uint64_t* pt = P2V(pd[pde] & s_page_addr_mask);
|
||||||
|
|
||||||
|
const paddr_t old_paddr = pt[pte] & s_page_addr_mask;
|
||||||
|
|
||||||
|
pt[pte] = 0;
|
||||||
|
|
||||||
|
if (invalidate && old_paddr != 0)
|
||||||
|
invalidate_page(vaddr, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PageTable::unmap_range(vaddr_t vaddr, size_t size)
|
||||||
|
{
|
||||||
|
ASSERT(vaddr % PAGE_SIZE == 0);
|
||||||
|
|
||||||
|
size_t page_count = range_page_count(vaddr, size);
|
||||||
|
|
||||||
|
SpinLockGuard _(m_lock);
|
||||||
|
for (vaddr_t page = 0; page < page_count; page++)
|
||||||
|
unmap_page(vaddr + page * PAGE_SIZE, false);
|
||||||
|
invalidate_range(vaddr, page_count, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PageTable::map_page_at(paddr_t paddr, vaddr_t vaddr, flags_t flags, MemoryType memory_type, bool invalidate)
|
||||||
|
{
|
||||||
|
ASSERT(vaddr);
|
||||||
|
ASSERT(vaddr != fast_page());
|
||||||
|
if ((vaddr >= KERNEL_OFFSET) != (this == s_kernel))
|
||||||
|
Kernel::panic("mapping {8H} to {8H}, kernel: {}", paddr, vaddr, this == s_kernel);
|
||||||
|
|
||||||
|
ASSERT(paddr % PAGE_SIZE == 0);
|
||||||
|
ASSERT(vaddr % PAGE_SIZE == 0);
|
||||||
|
ASSERT(flags & Flags::Used);
|
||||||
|
|
||||||
|
const uint64_t pdpte = (vaddr >> 30) & 0x1FF;
|
||||||
|
const uint64_t pde = (vaddr >> 21) & 0x1FF;
|
||||||
|
const uint64_t pte = (vaddr >> 12) & 0x1FF;
|
||||||
|
|
||||||
|
uint64_t extra_flags = 0;
|
||||||
|
if (s_has_pge && vaddr >= KERNEL_OFFSET) // Map kernel memory as global
|
||||||
|
extra_flags |= 1ull << 8;
|
||||||
|
if (s_has_nxe && !(flags & Flags::Execute))
|
||||||
|
extra_flags |= 1ull << 63;
|
||||||
|
if (flags & Flags::Reserved)
|
||||||
|
extra_flags |= Flags::Reserved;
|
||||||
|
|
||||||
|
if (memory_type == MemoryType::Uncached)
|
||||||
|
extra_flags |= (1ull << 4);
|
||||||
|
if (s_has_pat && memory_type == MemoryType::WriteCombining)
|
||||||
|
extra_flags |= (1ull << 7);
|
||||||
|
if (s_has_pat && memory_type == MemoryType::WriteThrough)
|
||||||
|
extra_flags |= (1ull << 7) | (1ull << 3);
|
||||||
|
|
||||||
|
// NOTE: we add present here, since it has to be available in higher level structures
|
||||||
|
flags_t uwr_flags = (flags & (Flags::UserSupervisor | Flags::ReadWrite)) | Flags::Present;
|
||||||
|
|
||||||
|
SpinLockGuard _(m_lock);
|
||||||
|
|
||||||
|
uint64_t* pdpt = P2V(m_highest_paging_struct);
|
||||||
|
if (!(pdpt[pdpte] & Flags::Present))
|
||||||
|
pdpt[pdpte] = V2P(allocate_zeroed_page_aligned_page()) | Flags::Present;
|
||||||
|
|
||||||
|
uint64_t* pd = P2V(pdpt[pdpte] & s_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 = P2V(pd[pde] & s_page_addr_mask);
|
||||||
|
|
||||||
|
const paddr_t old_paddr = pt[pte] & s_page_addr_mask;
|
||||||
|
|
||||||
|
pt[pte] = paddr | uwr_flags | extra_flags;
|
||||||
|
|
||||||
|
if (invalidate && old_paddr != 0)
|
||||||
|
invalidate_page(vaddr, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PageTable::map_range_at(paddr_t paddr, vaddr_t vaddr, size_t size, flags_t flags, MemoryType memory_type)
|
||||||
|
{
|
||||||
|
ASSERT(vaddr);
|
||||||
|
ASSERT(paddr % PAGE_SIZE == 0);
|
||||||
|
ASSERT(vaddr % PAGE_SIZE == 0);
|
||||||
|
|
||||||
|
size_t page_count = range_page_count(vaddr, size);
|
||||||
|
|
||||||
|
SpinLockGuard _(m_lock);
|
||||||
|
for (size_t page = 0; page < page_count; page++)
|
||||||
|
map_page_at(paddr + page * PAGE_SIZE, vaddr + page * PAGE_SIZE, flags, memory_type, false);
|
||||||
|
invalidate_range(vaddr, page_count, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PageTable::remove_writable_from_range(vaddr_t vaddr, size_t size)
|
||||||
|
{
|
||||||
|
ASSERT(vaddr);
|
||||||
|
ASSERT(vaddr % PAGE_SIZE == 0);
|
||||||
|
|
||||||
|
uint32_t pdpte = (vaddr >> 30) & 0x1FF;
|
||||||
|
uint32_t pde = (vaddr >> 21) & 0x1FF;
|
||||||
|
uint32_t pte = (vaddr >> 12) & 0x1FF;
|
||||||
|
|
||||||
|
const uint32_t e_pdpte = ((vaddr + size - 1) >> 30) & 0x1FF;
|
||||||
|
const uint32_t e_pde = ((vaddr + size - 1) >> 21) & 0x1FF;
|
||||||
|
const uint32_t e_pte = ((vaddr + size - 1) >> 12) & 0x1FF;
|
||||||
|
|
||||||
|
SpinLockGuard _(m_lock);
|
||||||
|
|
||||||
|
const uint64_t* pdpt = P2V(m_highest_paging_struct);
|
||||||
|
for (; pdpte <= e_pdpte; pdpte++)
|
||||||
|
{
|
||||||
|
if (!(pdpt[pdpte] & Flags::Present))
|
||||||
|
continue;
|
||||||
|
const uint64_t* pd = P2V(pdpt[pdpte] & s_page_addr_mask);
|
||||||
|
for (; pde < 512; pde++)
|
||||||
|
{
|
||||||
|
if (pdpte == e_pdpte && pde > e_pde)
|
||||||
|
break;
|
||||||
|
if (!(pd[pde] & Flags::ReadWrite))
|
||||||
|
continue;
|
||||||
|
uint64_t* pt = P2V(pd[pde] & s_page_addr_mask);
|
||||||
|
for (; pte < 512; pte++)
|
||||||
|
{
|
||||||
|
if (pdpte == e_pdpte && pde == e_pde && pte > e_pte)
|
||||||
|
break;
|
||||||
|
pt[pte] &= ~static_cast<uint64_t>(Flags::ReadWrite);
|
||||||
|
}
|
||||||
|
pte = 0;
|
||||||
|
}
|
||||||
|
pde = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
invalidate_range(vaddr, size / PAGE_SIZE, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t PageTable::get_page_data(vaddr_t vaddr) const
|
||||||
|
{
|
||||||
|
ASSERT(vaddr % PAGE_SIZE == 0);
|
||||||
|
|
||||||
|
const uint64_t pdpte = (vaddr >> 30) & 0x1FF;
|
||||||
|
const uint64_t pde = (vaddr >> 21) & 0x1FF;
|
||||||
|
const uint64_t pte = (vaddr >> 12) & 0x1FF;
|
||||||
|
|
||||||
|
SpinLockGuard _(m_lock);
|
||||||
|
|
||||||
|
const uint64_t* pdpt = P2V(m_highest_paging_struct);
|
||||||
|
if (!(pdpt[pdpte] & Flags::Present))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
const uint64_t* pd = P2V(pdpt[pdpte] & s_page_addr_mask);
|
||||||
|
if (!(pd[pde] & Flags::Present))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
const uint64_t* pt = P2V(pd[pde] & s_page_addr_mask);
|
||||||
|
if (!(pt[pte] & Flags::Used))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return pt[pte];
|
||||||
|
}
|
||||||
|
|
||||||
|
PageTable::flags_t PageTable::get_page_flags(vaddr_t vaddr) const
|
||||||
|
{
|
||||||
|
return parse_flags(get_page_data(vaddr));
|
||||||
|
}
|
||||||
|
|
||||||
|
paddr_t PageTable::physical_address_of(vaddr_t vaddr) const
|
||||||
|
{
|
||||||
|
return get_page_data(vaddr) & s_page_addr_mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PageTable::is_page_free(vaddr_t vaddr) const
|
||||||
|
{
|
||||||
|
ASSERT(vaddr % PAGE_SIZE == 0);
|
||||||
|
return !(get_page_flags(vaddr) & Flags::Used);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PageTable::is_range_free(vaddr_t vaddr, size_t size) const
|
||||||
|
{
|
||||||
|
vaddr_t s_page = vaddr / PAGE_SIZE;
|
||||||
|
vaddr_t e_page = BAN::Math::div_round_up<vaddr_t>(vaddr + size, PAGE_SIZE);
|
||||||
|
|
||||||
|
SpinLockGuard _(m_lock);
|
||||||
|
for (vaddr_t page = s_page; page < e_page; page++)
|
||||||
|
if (!is_page_free(page * PAGE_SIZE))
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PageTable::reserve_page(vaddr_t vaddr, bool only_free, bool send_smp_message)
|
||||||
|
{
|
||||||
|
SpinLockGuard _(m_lock);
|
||||||
|
ASSERT(vaddr % PAGE_SIZE == 0);
|
||||||
|
if (only_free && !is_page_free(vaddr))
|
||||||
|
return false;
|
||||||
|
map_page_at(0, vaddr, Flags::Reserved, MemoryType::Normal, send_smp_message);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PageTable::reserve_range(vaddr_t vaddr, size_t bytes, bool only_free)
|
||||||
|
{
|
||||||
|
if (size_t rem = bytes % PAGE_SIZE)
|
||||||
|
bytes += PAGE_SIZE - rem;
|
||||||
|
ASSERT(vaddr % PAGE_SIZE == 0);
|
||||||
|
|
||||||
|
SpinLockGuard _(m_lock);
|
||||||
|
if (only_free && !is_range_free(vaddr, bytes))
|
||||||
|
return false;
|
||||||
|
for (size_t offset = 0; offset < bytes; offset += PAGE_SIZE)
|
||||||
|
reserve_page(vaddr + offset, true, false);
|
||||||
|
invalidate_range(vaddr, bytes / PAGE_SIZE, true);
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
uint32_t pdpte = (first_address >> 30) & 0x1FF;
|
||||||
|
uint32_t pde = (first_address >> 21) & 0x1FF;
|
||||||
|
uint32_t pte = (first_address >> 12) & 0x1FF;
|
||||||
|
|
||||||
|
const uint32_t e_pdpte = ((last_address - 1) >> 30) & 0x1FF;
|
||||||
|
const uint32_t e_pde = ((last_address - 1) >> 21) & 0x1FF;
|
||||||
|
const uint32_t e_pte = ((last_address - 1) >> 12) & 0x1FF;
|
||||||
|
|
||||||
|
SpinLockGuard _(m_lock);
|
||||||
|
|
||||||
|
// Try to find free page that can be mapped without
|
||||||
|
// allocations (page table with unused entries)
|
||||||
|
const uint64_t* pdpt = P2V(m_highest_paging_struct);
|
||||||
|
for (; pdpte <= e_pdpte; pdpte++)
|
||||||
|
{
|
||||||
|
if (!(pdpt[pdpte] & Flags::Present))
|
||||||
|
continue;
|
||||||
|
const uint64_t* pd = P2V(pdpt[pdpte] & s_page_addr_mask);
|
||||||
|
for (; pde < 512; pde++)
|
||||||
|
{
|
||||||
|
if (pdpte == e_pdpte && pde > e_pde)
|
||||||
|
break;
|
||||||
|
if (!(pd[pde] & Flags::Present))
|
||||||
|
continue;
|
||||||
|
const uint64_t* pt = P2V(pd[pde] & s_page_addr_mask);
|
||||||
|
for (; pte < 512; pte++)
|
||||||
|
{
|
||||||
|
if (pdpte == e_pdpte && pde == e_pde && pte > e_pte)
|
||||||
|
break;
|
||||||
|
if (pt[pte] & Flags::Used)
|
||||||
|
continue;
|
||||||
|
vaddr_t vaddr = 0;
|
||||||
|
vaddr |= (vaddr_t)pdpte << 30;
|
||||||
|
vaddr |= (vaddr_t)pde << 21;
|
||||||
|
vaddr |= (vaddr_t)pte << 12;
|
||||||
|
ASSERT(reserve_page(vaddr));
|
||||||
|
return vaddr;
|
||||||
|
}
|
||||||
|
pte = 0;
|
||||||
|
}
|
||||||
|
pde = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find any free page
|
||||||
|
for (vaddr_t vaddr = first_address; vaddr < last_address; vaddr += PAGE_SIZE)
|
||||||
|
{
|
||||||
|
if (is_page_free(vaddr))
|
||||||
|
{
|
||||||
|
ASSERT(reserve_page(vaddr));
|
||||||
|
return vaddr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
vaddr_t PageTable::reserve_free_contiguous_pages(size_t page_count, vaddr_t first_address, vaddr_t last_address)
|
||||||
|
{
|
||||||
|
if (first_address >= KERNEL_OFFSET && first_address < (vaddr_t)g_kernel_start)
|
||||||
|
first_address = (vaddr_t)g_kernel_start;
|
||||||
|
if (size_t rem = first_address % PAGE_SIZE)
|
||||||
|
first_address += PAGE_SIZE - rem;
|
||||||
|
if (size_t rem = last_address % PAGE_SIZE)
|
||||||
|
last_address -= rem;
|
||||||
|
|
||||||
|
SpinLockGuard _(m_lock);
|
||||||
|
|
||||||
|
for (vaddr_t vaddr = first_address; vaddr < last_address;)
|
||||||
|
{
|
||||||
|
bool valid { true };
|
||||||
|
for (size_t page = 0; page < page_count; page++)
|
||||||
|
{
|
||||||
|
if (!is_page_free(vaddr + page * PAGE_SIZE))
|
||||||
|
{
|
||||||
|
vaddr += (page + 1) * PAGE_SIZE;
|
||||||
|
valid = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (valid)
|
||||||
|
{
|
||||||
|
ASSERT(reserve_range(vaddr, page_count * PAGE_SIZE));
|
||||||
|
return vaddr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dump_range(vaddr_t start, vaddr_t end, PageTable::flags_t flags)
|
||||||
|
{
|
||||||
|
if (start == 0)
|
||||||
|
return;
|
||||||
|
dprintln("{}-{}: {}{}{}{}",
|
||||||
|
(void*)(start), (void*)(end - 1),
|
||||||
|
flags & PageTable::Flags::Execute ? 'x' : '-',
|
||||||
|
flags & PageTable::Flags::UserSupervisor ? 'u' : '-',
|
||||||
|
flags & PageTable::Flags::ReadWrite ? 'w' : '-',
|
||||||
|
flags & PageTable::Flags::Present ? 'r' : '-'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PageTable::debug_dump()
|
||||||
|
{
|
||||||
|
SpinLockGuard _(m_lock);
|
||||||
|
|
||||||
|
flags_t flags = 0;
|
||||||
|
vaddr_t start = 0;
|
||||||
|
|
||||||
|
const uint64_t* pdpt = P2V(m_highest_paging_struct);
|
||||||
|
for (uint32_t pdpte = 0; pdpte < 4; pdpte++)
|
||||||
|
{
|
||||||
|
if (!(pdpt[pdpte] & Flags::Present))
|
||||||
|
{
|
||||||
|
dump_range(start, (pdpte << 30), flags);
|
||||||
|
start = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const uint64_t* pd = P2V(pdpt[pdpte] & s_page_addr_mask);
|
||||||
|
for (uint64_t pde = 0; pde < 512; pde++)
|
||||||
|
{
|
||||||
|
if (!(pd[pde] & Flags::Present))
|
||||||
|
{
|
||||||
|
dump_range(start, (pdpte << 30) | (pde << 21), flags);
|
||||||
|
start = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const uint64_t* pt = P2V(pd[pde] & s_page_addr_mask);
|
||||||
|
for (uint64_t pte = 0; pte < 512; pte++)
|
||||||
|
{
|
||||||
|
if (parse_flags(pt[pte]) != flags)
|
||||||
|
{
|
||||||
|
dump_range(start, (pdpte << 30) | (pde << 21) | (pte << 12), flags);
|
||||||
|
start = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(pt[pte] & Flags::Used))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (start == 0)
|
||||||
|
{
|
||||||
|
flags = parse_flags(pt[pte]);
|
||||||
|
start = (pdpte << 30) | (pde << 21) | (pte << 12);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,31 +1,86 @@
|
|||||||
.section .userspace, "aw"
|
.section .userspace, "ax"
|
||||||
|
|
||||||
// stack contains
|
// stack contains
|
||||||
// return address
|
// (4 bytes) return address (on return stack)
|
||||||
// signal number
|
// (4 bytes) return stack
|
||||||
// signal handler
|
// (4 bytes) return rflags
|
||||||
|
// (8 bytes) restore sigmask
|
||||||
|
// (36 bytes) siginfo_t
|
||||||
|
// (4 bytes) signal number
|
||||||
|
// (4 bytes) signal handler
|
||||||
|
|
||||||
.global signal_trampoline
|
.global signal_trampoline
|
||||||
signal_trampoline:
|
signal_trampoline:
|
||||||
ud2
|
pushl %esi // gregs
|
||||||
|
pushl %edi
|
||||||
|
pushl %edx
|
||||||
|
pushl %ecx
|
||||||
|
pushl %ebx
|
||||||
|
pushl %eax
|
||||||
pushl %ebp
|
pushl %ebp
|
||||||
|
|
||||||
|
movl 80(%esp), %eax
|
||||||
|
pushl %eax; addl $4, (%esp)
|
||||||
|
pushl (%eax)
|
||||||
|
|
||||||
|
// FIXME: populate these
|
||||||
|
xorl %eax, %eax
|
||||||
|
pushl %eax // stack
|
||||||
|
pushl %eax
|
||||||
|
pushl %eax
|
||||||
|
pushl %eax // sigset
|
||||||
|
pushl %eax
|
||||||
|
pushl %eax // link
|
||||||
|
|
||||||
|
movl %esp, %edx // ucontext
|
||||||
|
leal 68(%esp), %esi // siginfo
|
||||||
|
movl 64(%esp), %edi // signal number
|
||||||
|
movl 60(%esp), %eax // handlers
|
||||||
|
|
||||||
|
// align stack to 16 bytes
|
||||||
movl %esp, %ebp
|
movl %esp, %ebp
|
||||||
subl $8, %esp
|
andl $-16, %esp
|
||||||
|
|
||||||
pusha
|
subl $512, %esp
|
||||||
|
fxsave (%esp)
|
||||||
|
|
||||||
movl 40(%esp), %edi
|
subl $4, %esp
|
||||||
movl 36(%esp), %eax
|
pushl %edx
|
||||||
|
pushl %esi
|
||||||
subl $12, %esp
|
|
||||||
pushl %edi
|
pushl %edi
|
||||||
call *%eax
|
call *%eax
|
||||||
addl $16, %esp
|
addl $16, %esp
|
||||||
|
|
||||||
popa
|
fxrstor (%esp)
|
||||||
|
addl $512, %esp
|
||||||
|
|
||||||
leave
|
// restore stack
|
||||||
|
movl %ebp, %esp
|
||||||
|
addl $24, %esp
|
||||||
|
|
||||||
|
// restore sigmask
|
||||||
|
movl $83, %eax // SYS_SIGPROCMASK
|
||||||
|
movl $3, %ebx // SIG_SETMASK
|
||||||
|
leal 72(%esp), %ecx // set
|
||||||
|
xorl %edx, %edx // oset
|
||||||
|
int $0xF0
|
||||||
|
|
||||||
|
// restore registers
|
||||||
addl $8, %esp
|
addl $8, %esp
|
||||||
|
popl %ebp
|
||||||
|
popl %eax
|
||||||
|
popl %ebx
|
||||||
|
popl %ecx
|
||||||
|
popl %edx
|
||||||
|
popl %edi
|
||||||
|
popl %esi
|
||||||
|
|
||||||
|
// skip handler, number, siginfo_t, sigmask
|
||||||
|
addl $52, %esp
|
||||||
|
|
||||||
|
// restore flags
|
||||||
|
popf
|
||||||
|
|
||||||
|
movl (%esp), %esp
|
||||||
|
|
||||||
ret
|
ret
|
||||||
|
|||||||
@@ -1,19 +1,81 @@
|
|||||||
|
// arguments in EAX, EBX, ECX, EDX, ESI, EDI
|
||||||
|
.global asm_syscall_handler
|
||||||
|
asm_syscall_handler:
|
||||||
|
# save general purpose registers
|
||||||
|
pushl %ebx
|
||||||
|
pushl %ecx
|
||||||
|
pushl %edx
|
||||||
|
pushl %edi
|
||||||
|
pushl %esi
|
||||||
|
pushl %ebp
|
||||||
|
cld
|
||||||
|
|
||||||
|
# align stack
|
||||||
|
movl %esp, %ebp
|
||||||
|
andl $-16, %esp
|
||||||
|
|
||||||
|
# push arguments
|
||||||
|
subl $8, %esp
|
||||||
|
pushl %edi
|
||||||
|
pushl %esi
|
||||||
|
pushl %edx
|
||||||
|
pushl %ecx
|
||||||
|
pushl %ebx
|
||||||
|
pushl %eax
|
||||||
|
|
||||||
|
# load kernel segments
|
||||||
|
movw $0x10, %ax
|
||||||
|
movw %ax, %ds
|
||||||
|
movw %ax, %es
|
||||||
|
movw %ax, %fs
|
||||||
|
movw $0x28, %ax
|
||||||
|
movw %ax, %gs
|
||||||
|
|
||||||
|
call cpp_syscall_handler
|
||||||
|
|
||||||
|
movl %ebp, %esp
|
||||||
|
|
||||||
|
# restore userspace segments
|
||||||
|
movw $(0x20 | 3), %bx
|
||||||
|
movw %bx, %ds
|
||||||
|
movw %bx, %es
|
||||||
|
movw $(0x30 | 3), %bx
|
||||||
|
movw %bx, %fs
|
||||||
|
movw $(0x38 | 3), %bx
|
||||||
|
movw %bx, %gs
|
||||||
|
|
||||||
|
# restore general purpose registers
|
||||||
|
popl %ebp
|
||||||
|
popl %esi
|
||||||
|
popl %edi
|
||||||
|
popl %edx
|
||||||
|
popl %ecx
|
||||||
|
popl %ebx
|
||||||
|
|
||||||
|
iret
|
||||||
|
|
||||||
.global sys_fork_trampoline
|
.global sys_fork_trampoline
|
||||||
sys_fork_trampoline:
|
sys_fork_trampoline:
|
||||||
ud2
|
|
||||||
subl $4, %esp
|
|
||||||
pushl %ebx
|
|
||||||
pushl %ebp
|
pushl %ebp
|
||||||
|
pushl %ebx
|
||||||
|
pushl %esi
|
||||||
|
pushl %edi
|
||||||
|
|
||||||
call read_ip
|
call read_ip
|
||||||
testl %eax, %eax
|
testl %eax, %eax
|
||||||
je .done
|
jz .done
|
||||||
|
|
||||||
|
movl %esp, %ebx
|
||||||
|
|
||||||
subl $8, %esp
|
subl $8, %esp
|
||||||
pushl %eax
|
pushl %eax
|
||||||
pushl %esp
|
pushl %ebx
|
||||||
call sys_fork
|
call sys_fork
|
||||||
addl $16, %esp
|
addl $16, %esp
|
||||||
.done:
|
|
||||||
popl %ebp
|
.done:
|
||||||
|
popl %edi
|
||||||
|
popl %esi
|
||||||
popl %ebx
|
popl %ebx
|
||||||
addl $4, %esp
|
popl %ebp
|
||||||
ret
|
ret
|
||||||
|
|||||||
@@ -4,17 +4,39 @@ read_ip:
|
|||||||
popl %eax
|
popl %eax
|
||||||
jmp *%eax
|
jmp *%eax
|
||||||
|
|
||||||
# void start_thread(uint32_t sp, uint32_t ip)
|
# void start_kernel_thread()
|
||||||
.global start_thread
|
.global start_kernel_thread
|
||||||
start_thread:
|
start_kernel_thread:
|
||||||
ud2
|
# STACK LAYOUT
|
||||||
|
# on_exit arg
|
||||||
|
# on_exit func
|
||||||
|
# entry arg
|
||||||
|
# entry func
|
||||||
|
|
||||||
# void continue_thread(uint32_t sp, uint32_t ip)
|
movl 4(%esp), %edi
|
||||||
.global continue_thread
|
movl 0(%esp), %esi
|
||||||
continue_thread:
|
|
||||||
ud2
|
|
||||||
|
|
||||||
# void thread_userspace_trampoline(uint32_t sp, uint32_t ip, int argc, char** argv, char** envp)
|
subl $12, %esp
|
||||||
.global thread_userspace_trampoline
|
pushl %edi
|
||||||
thread_userspace_trampoline:
|
sti
|
||||||
ud2
|
call *%esi
|
||||||
|
addl $16, %esp
|
||||||
|
|
||||||
|
movl 12(%esp), %edi
|
||||||
|
movl 8(%esp), %esi
|
||||||
|
|
||||||
|
subl $12, %esp
|
||||||
|
pushl %edi
|
||||||
|
call *%esi
|
||||||
|
|
||||||
|
.global start_userspace_thread
|
||||||
|
start_userspace_thread:
|
||||||
|
movw $(0x20 | 3), %bx
|
||||||
|
movw %bx, %ds
|
||||||
|
movw %bx, %es
|
||||||
|
movw $(0x30 | 3), %bx
|
||||||
|
movw %bx, %fs
|
||||||
|
movw $(0x38 | 3), %bx
|
||||||
|
movw %bx, %gs
|
||||||
|
|
||||||
|
iret
|
||||||
|
|||||||
54
kernel/arch/i686/User.S
Normal file
54
kernel/arch/i686/User.S
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
# bool safe_user_memcpy(void*, const void*, size_t)
|
||||||
|
.global safe_user_memcpy
|
||||||
|
.global safe_user_memcpy_end
|
||||||
|
.global safe_user_memcpy_fault
|
||||||
|
safe_user_memcpy:
|
||||||
|
xorl %eax, %eax
|
||||||
|
xchgl 4(%esp), %edi
|
||||||
|
xchgl 8(%esp), %esi
|
||||||
|
movl 12(%esp), %ecx
|
||||||
|
movl %edi, %edx
|
||||||
|
rep movsb
|
||||||
|
movl 4(%esp), %edi
|
||||||
|
movl 8(%esp), %esi
|
||||||
|
incl %eax
|
||||||
|
safe_user_memcpy_fault:
|
||||||
|
ret
|
||||||
|
safe_user_memcpy_end:
|
||||||
|
|
||||||
|
# bool safe_user_strncpy(void*, const void*, size_t)
|
||||||
|
.global safe_user_strncpy
|
||||||
|
.global safe_user_strncpy_end
|
||||||
|
.global safe_user_strncpy_fault
|
||||||
|
safe_user_strncpy:
|
||||||
|
xchgl 4(%esp), %edi
|
||||||
|
xchgl 8(%esp), %esi
|
||||||
|
movl 12(%esp), %ecx
|
||||||
|
|
||||||
|
testl %ecx, %ecx
|
||||||
|
jz safe_user_strncpy_fault
|
||||||
|
|
||||||
|
.safe_user_strncpy_loop:
|
||||||
|
movb (%esi), %al
|
||||||
|
movb %al, (%edi)
|
||||||
|
testb %al, %al
|
||||||
|
jz .safe_user_strncpy_done
|
||||||
|
|
||||||
|
incl %edi
|
||||||
|
incl %esi
|
||||||
|
decl %ecx
|
||||||
|
jnz .safe_user_strncpy_loop
|
||||||
|
|
||||||
|
safe_user_strncpy_fault:
|
||||||
|
xorl %eax, %eax
|
||||||
|
jmp .safe_user_strncpy_return
|
||||||
|
|
||||||
|
.safe_user_strncpy_done:
|
||||||
|
movl $1, %eax
|
||||||
|
|
||||||
|
.safe_user_strncpy_return:
|
||||||
|
movl 4(%esp), %edi
|
||||||
|
movl 8(%esp), %esi
|
||||||
|
ret
|
||||||
|
|
||||||
|
safe_user_strncpy_end:
|
||||||
25
kernel/arch/i686/Yield.S
Normal file
25
kernel/arch/i686/Yield.S
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
.global asm_yield_trampoline
|
||||||
|
asm_yield_trampoline:
|
||||||
|
leal 4(%esp), %ecx
|
||||||
|
movl 4(%esp), %esp
|
||||||
|
|
||||||
|
pushl -4(%ecx)
|
||||||
|
pushl %ecx
|
||||||
|
pushl %eax
|
||||||
|
pushl %ebx
|
||||||
|
pushl %esi
|
||||||
|
pushl %edi
|
||||||
|
pushl %ebp
|
||||||
|
|
||||||
|
pushl %esp
|
||||||
|
call scheduler_on_yield
|
||||||
|
addl $4, %esp
|
||||||
|
|
||||||
|
popl %ebp
|
||||||
|
popl %edi
|
||||||
|
popl %esi
|
||||||
|
popl %ebx
|
||||||
|
popl %eax
|
||||||
|
movl 4(%esp), %ecx
|
||||||
|
movl 0(%esp), %esp
|
||||||
|
jmp *%ecx
|
||||||
@@ -11,9 +11,28 @@
|
|||||||
|
|
||||||
.code32
|
.code32
|
||||||
|
|
||||||
# multiboot2 header
|
// video mode info, page align modules
|
||||||
|
.set multiboot_flags, (1 << 2) | (1 << 0)
|
||||||
|
|
||||||
.section .multiboot, "aw"
|
.section .multiboot, "aw"
|
||||||
.align 8
|
multiboot_start:
|
||||||
|
.long 0x1BADB002
|
||||||
|
.long multiboot_flags
|
||||||
|
.long -(0x1BADB002 + multiboot_flags)
|
||||||
|
|
||||||
|
.long 0
|
||||||
|
.long 0
|
||||||
|
.long 0
|
||||||
|
.long 0
|
||||||
|
.long 0
|
||||||
|
|
||||||
|
.long 0
|
||||||
|
.long FB_WIDTH
|
||||||
|
.long FB_HEIGHT
|
||||||
|
.long FB_BPP
|
||||||
|
multiboot_end:
|
||||||
|
|
||||||
|
.section .multiboot2, "aw"
|
||||||
multiboot2_start:
|
multiboot2_start:
|
||||||
.long 0xE85250D6
|
.long 0xE85250D6
|
||||||
.long 0
|
.long 0
|
||||||
@@ -36,6 +55,12 @@ multiboot2_start:
|
|||||||
.long 12
|
.long 12
|
||||||
.long V2P(_start)
|
.long V2P(_start)
|
||||||
|
|
||||||
|
# page align modules
|
||||||
|
.align 8
|
||||||
|
.short 6
|
||||||
|
.short 0
|
||||||
|
.long 8
|
||||||
|
|
||||||
.align 8
|
.align 8
|
||||||
.short 0
|
.short 0
|
||||||
.short 0
|
.short 0
|
||||||
@@ -43,7 +68,6 @@ multiboot2_start:
|
|||||||
multiboot2_end:
|
multiboot2_end:
|
||||||
|
|
||||||
.section .bananboot, "aw"
|
.section .bananboot, "aw"
|
||||||
.align 8
|
|
||||||
bananboot_start:
|
bananboot_start:
|
||||||
.long 0xBABAB007
|
.long 0xBABAB007
|
||||||
.long -(0xBABAB007 + FB_WIDTH + FB_HEIGHT + FB_BPP)
|
.long -(0xBABAB007 + FB_WIDTH + FB_HEIGHT + FB_BPP)
|
||||||
@@ -53,9 +77,10 @@ bananboot_start:
|
|||||||
bananboot_end:
|
bananboot_end:
|
||||||
|
|
||||||
.section .bss, "aw", @nobits
|
.section .bss, "aw", @nobits
|
||||||
boot_stack_bottom:
|
.global g_boot_stack_top
|
||||||
|
g_boot_stack_bottom:
|
||||||
.skip 4096 * 4
|
.skip 4096 * 4
|
||||||
boot_stack_top:
|
g_boot_stack_top:
|
||||||
|
|
||||||
.global g_kernel_cmdline
|
.global g_kernel_cmdline
|
||||||
g_kernel_cmdline:
|
g_kernel_cmdline:
|
||||||
@@ -68,11 +93,32 @@ bananboot_end:
|
|||||||
|
|
||||||
.section .data
|
.section .data
|
||||||
|
|
||||||
|
# Map first GiB to 0x00000000 and 0xC0000000
|
||||||
|
.align 32
|
||||||
|
boot_pdpt:
|
||||||
|
.long V2P(boot_pd) + (PG_PRESENT)
|
||||||
|
.long 0
|
||||||
|
.quad 0
|
||||||
|
.quad 0
|
||||||
|
.long V2P(boot_pd) + (PG_PRESENT)
|
||||||
|
.long 0
|
||||||
.align 4096
|
.align 4096
|
||||||
boot_pml4:
|
|
||||||
boot_pdpt_lo:
|
|
||||||
boot_pdpt_hi:
|
|
||||||
boot_pd:
|
boot_pd:
|
||||||
|
.set i, 0
|
||||||
|
.rept 512
|
||||||
|
.long V2P(boot_pts) + i + (PG_READ_WRITE | PG_PRESENT)
|
||||||
|
.long 0
|
||||||
|
.set i, i + 0x1000
|
||||||
|
.endr
|
||||||
|
boot_pts:
|
||||||
|
.set i, 0
|
||||||
|
.rept 512
|
||||||
|
.rept 512
|
||||||
|
.long i + (PG_READ_WRITE | PG_PRESENT)
|
||||||
|
.long 0
|
||||||
|
.set i, i + 0x1000
|
||||||
|
.endr
|
||||||
|
.endr
|
||||||
|
|
||||||
boot_gdt:
|
boot_gdt:
|
||||||
.quad 0x0000000000000000 # null descriptor
|
.quad 0x0000000000000000 # null descriptor
|
||||||
@@ -106,9 +152,25 @@ has_cpuid:
|
|||||||
testl $0x00200000, %eax
|
testl $0x00200000, %eax
|
||||||
ret
|
ret
|
||||||
|
|
||||||
|
has_pae:
|
||||||
|
movl $0, %eax
|
||||||
|
cpuid
|
||||||
|
testl $(1 << 6), %edx
|
||||||
|
ret
|
||||||
|
|
||||||
|
has_sse:
|
||||||
|
movl $1, %eax
|
||||||
|
cpuid
|
||||||
|
testl $(1 << 25), %edx
|
||||||
|
ret
|
||||||
|
|
||||||
check_requirements:
|
check_requirements:
|
||||||
call has_cpuid
|
call has_cpuid
|
||||||
jz .exit
|
jz .exit
|
||||||
|
call has_pae
|
||||||
|
jz .exit
|
||||||
|
call has_sse
|
||||||
|
jz .exit
|
||||||
ret
|
ret
|
||||||
.exit:
|
.exit:
|
||||||
jmp system_halt
|
jmp system_halt
|
||||||
@@ -123,19 +185,26 @@ enable_sse:
|
|||||||
movl %eax, %cr4
|
movl %eax, %cr4
|
||||||
ret
|
ret
|
||||||
|
|
||||||
|
enable_tsc:
|
||||||
|
# allow userspace to use RDTSC
|
||||||
|
movl %cr4, %ecx
|
||||||
|
andl $0xFFFFFFFB, %ecx
|
||||||
|
movl %ecx, %cr4
|
||||||
|
ret
|
||||||
|
|
||||||
initialize_paging:
|
initialize_paging:
|
||||||
# enable PAE
|
# enable PAE
|
||||||
movl %cr4, %ecx
|
movl %cr4, %ecx
|
||||||
orl $0x20, %ecx
|
orl $(1 << 5), %ecx
|
||||||
movl %ecx, %cr4
|
movl %ecx, %cr4
|
||||||
|
|
||||||
# set address of paging structures
|
# load page tables
|
||||||
movl $V2P(boot_pml4), %ecx
|
movl $V2P(boot_pdpt), %ecx
|
||||||
movl %ecx, %cr3
|
movl %ecx, %cr3
|
||||||
|
|
||||||
# enable paging
|
# enable paging
|
||||||
movl %cr0, %ecx
|
movl %cr0, %ecx
|
||||||
orl $0x80000000, %ecx
|
orl $(1 << 31), %ecx
|
||||||
movl %ecx, %cr0
|
movl %ecx, %cr0
|
||||||
|
|
||||||
ret
|
ret
|
||||||
@@ -145,30 +214,31 @@ initialize_paging:
|
|||||||
_start:
|
_start:
|
||||||
cli; cld
|
cli; cld
|
||||||
|
|
||||||
# Initialize stack and multiboot info
|
# save bootloader magic and info
|
||||||
movl %eax, V2P(bootloader_magic)
|
movl %eax, V2P(bootloader_magic)
|
||||||
movl %ebx, V2P(bootloader_info)
|
movl %ebx, V2P(bootloader_info)
|
||||||
|
|
||||||
movl $V2P(boot_stack_top), %esp
|
# load boot stack
|
||||||
|
movl $V2P(g_boot_stack_top), %esp
|
||||||
|
|
||||||
call check_requirements
|
# load boot GDT
|
||||||
call enable_sse
|
|
||||||
|
|
||||||
call initialize_paging
|
|
||||||
|
|
||||||
# flush gdt
|
|
||||||
lgdt V2P(boot_gdtr)
|
lgdt V2P(boot_gdtr)
|
||||||
ljmpl $0x08, $V2P(gdt_flush)
|
ljmpl $0x08, $V2P(gdt_flush)
|
||||||
|
|
||||||
gdt_flush:
|
gdt_flush:
|
||||||
|
# set correct segment registers
|
||||||
movw $0x10, %ax
|
movw $0x10, %ax
|
||||||
movw %ax, %ds
|
movw %ax, %ds
|
||||||
movw %ax, %ss
|
movw %ax, %ss
|
||||||
movw %ax, %es
|
movw %ax, %es
|
||||||
|
|
||||||
# move stack pointer to higher half
|
# do processor initialization
|
||||||
movl %esp, %esp
|
call check_requirements
|
||||||
addl $KERNEL_OFFSET, %esp
|
call enable_sse
|
||||||
|
call enable_tsc
|
||||||
|
call initialize_paging
|
||||||
|
|
||||||
|
# load higher half stack pointer
|
||||||
|
movl $g_boot_stack_top, %esp
|
||||||
|
|
||||||
# jump to higher half
|
# jump to higher half
|
||||||
leal higher_half, %ecx
|
leal higher_half, %ecx
|
||||||
@@ -178,12 +248,21 @@ higher_half:
|
|||||||
# call global constuctors
|
# call global constuctors
|
||||||
call _init
|
call _init
|
||||||
|
|
||||||
|
movl $g_init_array_start, %ebx
|
||||||
|
jmp 2f
|
||||||
|
1: call *(%ebx)
|
||||||
|
addl $4, %ebx
|
||||||
|
2: cmpl $g_init_array_end, %ebx
|
||||||
|
jne 1b
|
||||||
|
|
||||||
# call to the kernel itself (clear ebp for stacktrace)
|
# call to the kernel itself (clear ebp for stacktrace)
|
||||||
xorl %ebp, %ebp
|
xorl %ebp, %ebp
|
||||||
|
|
||||||
movl V2P(bootloader_magic), %edi
|
subl $8, %esp
|
||||||
movl V2P(bootloader_info), %esi
|
pushl bootloader_info
|
||||||
|
pushl bootloader_magic
|
||||||
call kernel_main
|
call kernel_main
|
||||||
|
addl $16, %esp
|
||||||
|
|
||||||
# call global destructors
|
# call global destructors
|
||||||
call _fini
|
call _fini
|
||||||
@@ -195,29 +274,31 @@ system_halt:
|
|||||||
jmp 1b
|
jmp 1b
|
||||||
|
|
||||||
|
|
||||||
|
#define AP_V2P(vaddr) ((vaddr) - ap_trampoline + 0xF000)
|
||||||
|
|
||||||
.section .ap_init, "ax"
|
.section .ap_init, "ax"
|
||||||
|
|
||||||
.code16
|
.code16
|
||||||
.global ap_trampoline
|
.global ap_trampoline
|
||||||
ap_trampoline:
|
ap_trampoline:
|
||||||
jmp 1f
|
jmp 1f
|
||||||
|
|
||||||
.align 8
|
.align 8
|
||||||
ap_stack_ptr:
|
ap_stack_ptr:
|
||||||
.skip 4
|
.skip 4
|
||||||
1:
|
ap_stack_loaded:
|
||||||
cli; cld
|
.skip 1
|
||||||
ljmpl $0x00, $ap_cs_clear
|
|
||||||
|
1: cli; cld
|
||||||
|
ljmpl $0x00, $AP_V2P(ap_cs_clear)
|
||||||
|
|
||||||
ap_cs_clear:
|
ap_cs_clear:
|
||||||
xorw %ax, %ax
|
|
||||||
movw %ax, %ds
|
|
||||||
|
|
||||||
# load ap gdt and enter protected mode
|
# load ap gdt and enter protected mode
|
||||||
lgdt ap_gdtr
|
lgdt AP_V2P(ap_gdtr)
|
||||||
movl %cr0, %eax
|
movl %cr0, %eax
|
||||||
orb $1, %al
|
orb $1, %al
|
||||||
movl %eax, %cr0
|
movl %eax, %cr0
|
||||||
ljmpl $0x08, $ap_protected_mode
|
ljmpl $0x08, $AP_V2P(ap_protected_mode)
|
||||||
|
|
||||||
.code32
|
.code32
|
||||||
ap_protected_mode:
|
ap_protected_mode:
|
||||||
@@ -226,16 +307,16 @@ ap_protected_mode:
|
|||||||
movw %ax, %ss
|
movw %ax, %ss
|
||||||
movw %ax, %es
|
movw %ax, %es
|
||||||
|
|
||||||
movl ap_stack_ptr, %esp
|
movl AP_V2P(ap_stack_ptr), %esp
|
||||||
movb $1, V2P(g_ap_stack_loaded)
|
movb $1, AP_V2P(ap_stack_loaded)
|
||||||
|
|
||||||
call V2P(enable_sse)
|
leal V2P(enable_sse), %ecx; call *%ecx
|
||||||
|
leal V2P(enable_tsc), %ecx; call *%ecx
|
||||||
call V2P(initialize_paging)
|
leal V2P(initialize_paging), %ecx; call *%ecx
|
||||||
|
|
||||||
# load boot gdt and enter long mode
|
# load boot gdt and enter long mode
|
||||||
lgdt V2P(boot_gdtr)
|
lgdt V2P(boot_gdtr)
|
||||||
ljmpl $0x08, $ap_flush_gdt
|
ljmpl $0x08, $AP_V2P(ap_flush_gdt)
|
||||||
|
|
||||||
ap_flush_gdt:
|
ap_flush_gdt:
|
||||||
# move stack pointer to higher half
|
# move stack pointer to higher half
|
||||||
|
|||||||
@@ -1,23 +0,0 @@
|
|||||||
.section .text
|
|
||||||
|
|
||||||
.global _start
|
|
||||||
_start:
|
|
||||||
# Set up end of the stack frame linked list.
|
|
||||||
movl $0, %ebp
|
|
||||||
pushl %ebp # rip=0
|
|
||||||
pushl %ebp # rbp=0
|
|
||||||
movl %esp, %ebp
|
|
||||||
|
|
||||||
# Prepare signals, memory allocation, stdio and such.
|
|
||||||
#call initialize_standard_library
|
|
||||||
|
|
||||||
# Run the global constructors.
|
|
||||||
call _init
|
|
||||||
|
|
||||||
# Run main
|
|
||||||
call main
|
|
||||||
|
|
||||||
# Terminate the process with the exit code.
|
|
||||||
movl %eax, %edi
|
|
||||||
call exit
|
|
||||||
.size _start, . - _start
|
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
/* x86 crti.s */
|
/* i686 crti.s */
|
||||||
.section .init
|
.section .init
|
||||||
.global _init
|
.global _init
|
||||||
.type _init, @function
|
.type _init, @function
|
||||||
_init:
|
_init:
|
||||||
push %ebp
|
pushl %ebp
|
||||||
movl %esp, %ebp
|
movl %esp, %ebp
|
||||||
/* gcc will nicely put the contents of crtbegin.o's .init section here. */
|
/* gcc will nicely put the contents of crtbegin.o's .init section here. */
|
||||||
|
|
||||||
@@ -11,6 +11,6 @@ _init:
|
|||||||
.global _fini
|
.global _fini
|
||||||
.type _fini, @function
|
.type _fini, @function
|
||||||
_fini:
|
_fini:
|
||||||
push %ebp
|
pushl %ebp
|
||||||
movl %esp, %ebp
|
movl %esp, %ebp
|
||||||
/* gcc will nicely put the contents of crtbegin.o's .fini section here. */
|
/* gcc will nicely put the contents of crtbegin.o's .fini section here. */
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
/* x86 crtn.s */
|
/* i686 crtn.s */
|
||||||
.section .init
|
.section .init
|
||||||
/* gcc will nicely put the contents of crtend.o's .init section here. */
|
/* gcc will nicely put the contents of crtend.o's .init section here. */
|
||||||
popl %ebp
|
popl %ebp
|
||||||
|
|||||||
185
kernel/arch/i686/interrupts.S
Normal file
185
kernel/arch/i686/interrupts.S
Normal file
@@ -0,0 +1,185 @@
|
|||||||
|
.macro intr_header, n
|
||||||
|
pushal
|
||||||
|
testb $3, \n+8*4(%esp)
|
||||||
|
jz 1f
|
||||||
|
movw $0x10, %ax
|
||||||
|
movw %ax, %ds
|
||||||
|
movw %ax, %es
|
||||||
|
movw %ax, %fs
|
||||||
|
movw $0x28, %ax
|
||||||
|
movw %ax, %gs
|
||||||
|
1: cld
|
||||||
|
.endm
|
||||||
|
|
||||||
|
.macro intr_footer, n
|
||||||
|
testb $3, \n+8*4(%esp)
|
||||||
|
jz 1f
|
||||||
|
call cpp_check_signal
|
||||||
|
movw $(0x20 | 3), %bx
|
||||||
|
movw %bx, %ds
|
||||||
|
movw %bx, %es
|
||||||
|
movw $(0x30 | 3), %bx
|
||||||
|
movw %bx, %fs
|
||||||
|
movw $(0x38 | 3), %bx
|
||||||
|
movw %bx, %gs
|
||||||
|
1: popal
|
||||||
|
.endm
|
||||||
|
|
||||||
|
isr_stub:
|
||||||
|
intr_header 12
|
||||||
|
movl %cr0, %eax; pushl %eax
|
||||||
|
movl %cr2, %eax; pushl %eax
|
||||||
|
movl %cr3, %eax; pushl %eax
|
||||||
|
movl %cr4, %eax; pushl %eax
|
||||||
|
|
||||||
|
movl 48(%esp), %edi // isr number
|
||||||
|
movl 52(%esp), %esi // error code
|
||||||
|
leal 56(%esp), %edx // interrupt stack ptr
|
||||||
|
movl %esp, %ecx // register ptr
|
||||||
|
|
||||||
|
# stack frame for stack trace
|
||||||
|
leal 56(%esp), %eax
|
||||||
|
pushl (%eax)
|
||||||
|
pushl %ebp
|
||||||
|
|
||||||
|
movl %esp, %ebp
|
||||||
|
andl $-16, %esp
|
||||||
|
|
||||||
|
pushl %ecx
|
||||||
|
pushl %edx
|
||||||
|
pushl %esi
|
||||||
|
pushl %edi
|
||||||
|
call cpp_isr_handler
|
||||||
|
|
||||||
|
movl %ebp, %esp
|
||||||
|
addl $24, %esp
|
||||||
|
|
||||||
|
intr_footer 12
|
||||||
|
addl $8, %esp
|
||||||
|
iret
|
||||||
|
|
||||||
|
irq_stub:
|
||||||
|
intr_header 12
|
||||||
|
|
||||||
|
movl 32(%esp), %edi # interrupt number
|
||||||
|
|
||||||
|
movl %esp, %ebp
|
||||||
|
andl $-16, %esp
|
||||||
|
|
||||||
|
subl $12, %esp
|
||||||
|
pushl %edi
|
||||||
|
call cpp_irq_handler
|
||||||
|
|
||||||
|
movl %ebp, %esp
|
||||||
|
|
||||||
|
intr_footer 12
|
||||||
|
addl $8, %esp
|
||||||
|
iret
|
||||||
|
|
||||||
|
.global asm_ipi_handler
|
||||||
|
asm_ipi_handler:
|
||||||
|
intr_header 4
|
||||||
|
|
||||||
|
movl %esp, %ebp
|
||||||
|
andl $-16, %esp
|
||||||
|
|
||||||
|
call cpp_ipi_handler
|
||||||
|
|
||||||
|
movl %ebp, %esp
|
||||||
|
|
||||||
|
intr_footer 4
|
||||||
|
iret
|
||||||
|
|
||||||
|
.global asm_timer_handler
|
||||||
|
asm_timer_handler:
|
||||||
|
intr_header 4
|
||||||
|
|
||||||
|
movl %esp, %ebp
|
||||||
|
andl $-16, %esp
|
||||||
|
|
||||||
|
call cpp_timer_handler
|
||||||
|
|
||||||
|
movl %ebp, %esp
|
||||||
|
|
||||||
|
intr_footer 4
|
||||||
|
iret
|
||||||
|
|
||||||
|
.macro isr n
|
||||||
|
.global isr\n
|
||||||
|
isr\n:
|
||||||
|
pushl $0
|
||||||
|
pushl $\n
|
||||||
|
jmp isr_stub
|
||||||
|
.endm
|
||||||
|
|
||||||
|
.macro isr_err n
|
||||||
|
.global isr\n
|
||||||
|
isr\n:
|
||||||
|
pushl $\n
|
||||||
|
jmp isr_stub
|
||||||
|
.endm
|
||||||
|
|
||||||
|
.macro irq n
|
||||||
|
.global irq\n
|
||||||
|
irq\n:
|
||||||
|
pushl $0
|
||||||
|
pushl $\n
|
||||||
|
jmp irq_stub
|
||||||
|
.endm
|
||||||
|
|
||||||
|
isr 0
|
||||||
|
isr 1
|
||||||
|
isr 2
|
||||||
|
isr 3
|
||||||
|
isr 4
|
||||||
|
isr 5
|
||||||
|
isr 6
|
||||||
|
isr 7
|
||||||
|
isr_err 8
|
||||||
|
isr 9
|
||||||
|
isr_err 10
|
||||||
|
isr_err 11
|
||||||
|
isr_err 12
|
||||||
|
isr_err 13
|
||||||
|
isr_err 14
|
||||||
|
isr 15
|
||||||
|
isr 16
|
||||||
|
isr_err 17
|
||||||
|
isr 18
|
||||||
|
isr 19
|
||||||
|
isr 20
|
||||||
|
isr 21
|
||||||
|
isr 22
|
||||||
|
isr 23
|
||||||
|
isr 24
|
||||||
|
isr 25
|
||||||
|
isr 26
|
||||||
|
isr 27
|
||||||
|
isr 28
|
||||||
|
isr 29
|
||||||
|
isr 30
|
||||||
|
isr 31
|
||||||
|
|
||||||
|
.irp i, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, \
|
||||||
|
10, 11, 12, 13, 14, 15, 16, 17, 18, 19, \
|
||||||
|
20, 21, 22, 23, 24, 25, 26, 27, 28, 29, \
|
||||||
|
30, 31, 32, 33, 34, 35, 36, 37, 38, 39, \
|
||||||
|
40, 41, 42, 43, 44, 45, 46, 47, 48, 49, \
|
||||||
|
50, 51, 52, 53, 54, 55, 56, 57, 58, 59, \
|
||||||
|
60, 61, 62, 63, 64, 65, 66, 67, 68, 69, \
|
||||||
|
70, 71, 72, 73, 74, 75, 76, 77, 78, 79, \
|
||||||
|
80, 81, 82, 83, 84, 85, 86, 87, 88, 89, \
|
||||||
|
90, 91, 92, 93, 94, 95, 96, 97, 98, 99, \
|
||||||
|
100,101,102,103,104,105,106,107,108,109, \
|
||||||
|
110,111,112,113,114,115,116,117,118,119, \
|
||||||
|
120,121,122,123,124,125,126,127,128,129, \
|
||||||
|
130,131,132,133,134,135,136,137,138,139, \
|
||||||
|
140,141,142,143,144,145,146,147,148,149, \
|
||||||
|
150,151,152,153,154,155,156,157,158,159, \
|
||||||
|
160,161,162,163,164,165,166,167,168,169, \
|
||||||
|
170,171,172,173,174,175,176,177,178,179, \
|
||||||
|
180,181,182,183,184,185,186,187,188,189, \
|
||||||
|
190,191,192,193,194,195,196,197,198,199, \
|
||||||
|
200,201,202,203,204,205,206,207
|
||||||
|
irq \i
|
||||||
|
.endr
|
||||||
@@ -4,13 +4,6 @@ KERNEL_OFFSET = 0xC0000000;
|
|||||||
|
|
||||||
SECTIONS
|
SECTIONS
|
||||||
{
|
{
|
||||||
. = 0xF000;
|
|
||||||
.ap_init ALIGN(4K) : AT(ADDR(.ap_init))
|
|
||||||
{
|
|
||||||
g_ap_init_addr = .;
|
|
||||||
*(.ap_init)
|
|
||||||
}
|
|
||||||
|
|
||||||
. = 0x00100000 + KERNEL_OFFSET;
|
. = 0x00100000 + KERNEL_OFFSET;
|
||||||
|
|
||||||
g_kernel_start = .;
|
g_kernel_start = .;
|
||||||
@@ -18,6 +11,7 @@ SECTIONS
|
|||||||
{
|
{
|
||||||
g_kernel_execute_start = .;
|
g_kernel_execute_start = .;
|
||||||
*(.multiboot)
|
*(.multiboot)
|
||||||
|
*(.multiboot2)
|
||||||
*(.bananboot)
|
*(.bananboot)
|
||||||
*(.text.*)
|
*(.text.*)
|
||||||
}
|
}
|
||||||
@@ -28,18 +22,31 @@ SECTIONS
|
|||||||
g_userspace_end = .;
|
g_userspace_end = .;
|
||||||
g_kernel_execute_end = .;
|
g_kernel_execute_end = .;
|
||||||
}
|
}
|
||||||
|
.ap_init ALIGN(4K) : AT(ADDR(.ap_init) - KERNEL_OFFSET)
|
||||||
|
{
|
||||||
|
g_ap_init_addr = .;
|
||||||
|
*(.ap_init)
|
||||||
|
}
|
||||||
.rodata ALIGN(4K) : AT(ADDR(.rodata) - KERNEL_OFFSET)
|
.rodata ALIGN(4K) : AT(ADDR(.rodata) - KERNEL_OFFSET)
|
||||||
{
|
{
|
||||||
*(.rodata.*)
|
*(.rodata.*)
|
||||||
}
|
}
|
||||||
|
.init_array ALIGN(4K) : AT(ADDR(.init_array) - KERNEL_OFFSET)
|
||||||
|
{
|
||||||
|
g_init_array_start = .;
|
||||||
|
*(.init_array)
|
||||||
|
g_init_array_end = .;
|
||||||
|
}
|
||||||
.data ALIGN(4K) : AT(ADDR(.data) - KERNEL_OFFSET)
|
.data ALIGN(4K) : AT(ADDR(.data) - KERNEL_OFFSET)
|
||||||
{
|
{
|
||||||
|
g_kernel_writable_start = .;
|
||||||
*(.data)
|
*(.data)
|
||||||
}
|
}
|
||||||
.bss ALIGN(4K) : AT(ADDR(.bss) - KERNEL_OFFSET)
|
.bss ALIGN(4K) : AT(ADDR(.bss) - KERNEL_OFFSET)
|
||||||
{
|
{
|
||||||
*(COMMON)
|
*(COMMON)
|
||||||
*(.bss)
|
*(.bss)
|
||||||
|
g_kernel_writable_end = .;
|
||||||
}
|
}
|
||||||
g_kernel_end = .;
|
g_kernel_end = .;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,56 +0,0 @@
|
|||||||
#include <kernel/GDT.h>
|
|
||||||
#include <kernel/Debug.h>
|
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
namespace Kernel
|
|
||||||
{
|
|
||||||
|
|
||||||
GDT* GDT::create()
|
|
||||||
{
|
|
||||||
auto* gdt = new GDT();
|
|
||||||
ASSERT(gdt);
|
|
||||||
|
|
||||||
gdt->write_entry(0x00, 0x00000000, 0x00000, 0x00, 0x0); // null
|
|
||||||
gdt->write_entry(0x08, 0x00000000, 0xFFFFF, 0x9A, 0xA); // kernel code
|
|
||||||
gdt->write_entry(0x10, 0x00000000, 0xFFFFF, 0x92, 0xC); // kernel data
|
|
||||||
gdt->write_entry(0x18, 0x00000000, 0xFFFFF, 0xFA, 0xA); // user code
|
|
||||||
gdt->write_entry(0x20, 0x00000000, 0xFFFFF, 0xF2, 0xC); // user data
|
|
||||||
gdt->write_tss();
|
|
||||||
|
|
||||||
return gdt;
|
|
||||||
}
|
|
||||||
|
|
||||||
void GDT::write_entry(uint8_t offset, uint32_t base, uint32_t limit, uint8_t access, uint8_t flags)
|
|
||||||
{
|
|
||||||
ASSERT(offset % sizeof(SegmentDescriptor) == 0);
|
|
||||||
uint8_t idx = offset / sizeof(SegmentDescriptor);
|
|
||||||
|
|
||||||
auto& desc = m_gdt[idx];
|
|
||||||
desc.base1 = (base >> 0) & 0xFFFF;
|
|
||||||
desc.base2 = (base >> 16) & 0xFF;
|
|
||||||
desc.base3 = (base >> 24) & 0xFF;
|
|
||||||
|
|
||||||
desc.limit1 = (limit >> 0) & 0xFFFF;
|
|
||||||
desc.limit2 = (limit >> 16) & 0x0F;
|
|
||||||
|
|
||||||
desc.access = access & 0xFF;
|
|
||||||
|
|
||||||
desc.flags = flags & 0x0F;
|
|
||||||
}
|
|
||||||
|
|
||||||
void GDT::write_tss()
|
|
||||||
{
|
|
||||||
memset(&m_tss, 0x00, sizeof(TaskStateSegment));
|
|
||||||
m_tss.iopb = sizeof(TaskStateSegment);
|
|
||||||
|
|
||||||
uint64_t base = reinterpret_cast<uint64_t>(&m_tss);
|
|
||||||
|
|
||||||
write_entry(0x28, (uint32_t)base, sizeof(TaskStateSegment), 0x89, 0x0);
|
|
||||||
|
|
||||||
auto& desc = m_gdt[0x30 / sizeof(SegmentDescriptor)];
|
|
||||||
desc.low = base >> 32;
|
|
||||||
desc.high = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,398 +0,0 @@
|
|||||||
#include <BAN/Array.h>
|
|
||||||
#include <BAN/Errors.h>
|
|
||||||
#include <kernel/IDT.h>
|
|
||||||
#include <kernel/InterruptController.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 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) X(32)
|
|
||||||
|
|
||||||
namespace Kernel
|
|
||||||
{
|
|
||||||
|
|
||||||
struct Registers
|
|
||||||
{
|
|
||||||
uint64_t rsp;
|
|
||||||
uint64_t rip;
|
|
||||||
uint64_t rflags;
|
|
||||||
uint64_t cr4;
|
|
||||||
uint64_t cr3;
|
|
||||||
uint64_t cr2;
|
|
||||||
uint64_t cr0;
|
|
||||||
|
|
||||||
uint64_t r15;
|
|
||||||
uint64_t r14;
|
|
||||||
uint64_t r13;
|
|
||||||
uint64_t r12;
|
|
||||||
uint64_t r11;
|
|
||||||
uint64_t r10;
|
|
||||||
uint64_t r9;
|
|
||||||
uint64_t r8;
|
|
||||||
uint64_t rsi;
|
|
||||||
uint64_t rdi;
|
|
||||||
uint64_t rbp;
|
|
||||||
uint64_t rdx;
|
|
||||||
uint64_t rcx;
|
|
||||||
uint64_t rbx;
|
|
||||||
uint64_t rax;
|
|
||||||
};
|
|
||||||
|
|
||||||
#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[] =
|
|
||||||
{
|
|
||||||
"Division Error",
|
|
||||||
"Debug",
|
|
||||||
"Non-maskable Interrupt",
|
|
||||||
"Breakpoint",
|
|
||||||
"Overflow",
|
|
||||||
"Bound Range Exception",
|
|
||||||
"Invalid Opcode",
|
|
||||||
"Device Not Available",
|
|
||||||
"Double Fault",
|
|
||||||
"Coprocessor Segment Overrun",
|
|
||||||
"Invalid TSS",
|
|
||||||
"Segment Not Present",
|
|
||||||
"Stack-Segment Fault",
|
|
||||||
"General Protection Fault",
|
|
||||||
"Page Fault",
|
|
||||||
"Unknown Exception 0x0F",
|
|
||||||
"x87 Floating-Point Exception",
|
|
||||||
"Alignment Check",
|
|
||||||
"Machine Check",
|
|
||||||
"SIMD Floating-Point Exception",
|
|
||||||
"Virtualization Exception",
|
|
||||||
"Control Protection Exception",
|
|
||||||
"Unknown Exception 0x16",
|
|
||||||
"Unknown Exception 0x17",
|
|
||||||
"Unknown Exception 0x18",
|
|
||||||
"Unknown Exception 0x19",
|
|
||||||
"Unknown Exception 0x1A",
|
|
||||||
"Unknown Exception 0x1B",
|
|
||||||
"Hypervisor Injection Exception",
|
|
||||||
"VMM Communication Exception",
|
|
||||||
"Security Exception",
|
|
||||||
"Unkown Exception 0x1F",
|
|
||||||
};
|
|
||||||
|
|
||||||
extern "C" void cpp_isr_handler(uint64_t isr, uint64_t error, InterruptStack& interrupt_stack, const Registers* regs)
|
|
||||||
{
|
|
||||||
if (g_paniced)
|
|
||||||
{
|
|
||||||
dprintln("Processor {} halted", Processor::current_id());
|
|
||||||
InterruptController::get().broadcast_ipi();
|
|
||||||
asm volatile("cli; 1: hlt; jmp 1b");
|
|
||||||
}
|
|
||||||
|
|
||||||
#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_sp(interrupt_stack.sp);
|
|
||||||
Thread::current().set_return_ip(interrupt_stack.ip);
|
|
||||||
|
|
||||||
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.sp && interrupt_stack.sp <= stack.vaddr() + stack.size())
|
|
||||||
; // using normal stack
|
|
||||||
else if (istack.vaddr() < interrupt_stack.sp && interrupt_stack.sp <= istack.vaddr() + istack.size())
|
|
||||||
; // using interrupt stack
|
|
||||||
else
|
|
||||||
{
|
|
||||||
derrorln("Stack pointer out of bounds!");
|
|
||||||
derrorln("rip {H}", interrupt_stack.ip);
|
|
||||||
derrorln("rsp {H}, stack {H}->{H}, istack {H}->{H}",
|
|
||||||
interrupt_stack.sp,
|
|
||||||
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 __enable_sse
|
|
||||||
else if (isr == ISR::DeviceNotAvailable)
|
|
||||||
{
|
|
||||||
asm volatile(
|
|
||||||
"movq %cr0, %rax;"
|
|
||||||
"andq $~(1 << 3), %rax;"
|
|
||||||
"movq %rax, %cr0;"
|
|
||||||
);
|
|
||||||
if (auto* current = &Thread::current(); current != Thread::sse_thread())
|
|
||||||
{
|
|
||||||
if (auto* sse = Thread::sse_thread())
|
|
||||||
sse->save_sse();
|
|
||||||
current->load_sse();
|
|
||||||
}
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
if (PageTable::current().get_page_flags(interrupt_stack.ip & PAGE_ADDR_MASK) & PageTable::Flags::Present)
|
|
||||||
{
|
|
||||||
auto* machine_code = (const uint8_t*)interrupt_stack.ip;
|
|
||||||
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}",
|
|
||||||
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();
|
|
||||||
|
|
||||||
if (tid && Thread::current().is_userspace())
|
|
||||||
{
|
|
||||||
// TODO: Confirm and fix the exception to signal mappings
|
|
||||||
|
|
||||||
int signal = 0;
|
|
||||||
switch (isr)
|
|
||||||
{
|
|
||||||
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
|
|
||||||
{
|
|
||||||
panic("Unhandled exception");
|
|
||||||
}
|
|
||||||
|
|
||||||
ASSERT(Thread::current().state() != Thread::State::Terminated);
|
|
||||||
|
|
||||||
done:
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "C" void cpp_irq_handler(uint64_t irq, InterruptStack& interrupt_stack)
|
|
||||||
{
|
|
||||||
if (g_paniced)
|
|
||||||
{
|
|
||||||
dprintln("Processor {} halted", Processor::current_id());
|
|
||||||
InterruptController::get().broadcast_ipi();
|
|
||||||
asm volatile("cli; 1: hlt; jmp 1b");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Scheduler::current_tid())
|
|
||||||
{
|
|
||||||
Thread::current().set_return_sp(interrupt_stack.sp);
|
|
||||||
Thread::current().set_return_ip(interrupt_stack.ip);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!InterruptController::get().is_in_service(irq))
|
|
||||||
dprintln("spurious irq 0x{2H}", irq);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
InterruptController::get().eoi(irq);
|
|
||||||
if (irq == IRQ_IPI)
|
|
||||||
Scheduler::get().reschedule();
|
|
||||||
else if (auto* handler = s_interruptables[irq])
|
|
||||||
handler->handle_irq();
|
|
||||||
else
|
|
||||||
dprintln("no handler for irq 0x{2H}", irq);
|
|
||||||
}
|
|
||||||
|
|
||||||
Scheduler::get().reschedule_if_idling();
|
|
||||||
|
|
||||||
ASSERT(Thread::current().state() != Thread::State::Terminated);
|
|
||||||
}
|
|
||||||
|
|
||||||
void IDT::register_interrupt_handler(uint8_t index, void (*handler)())
|
|
||||||
{
|
|
||||||
auto& descriptor = m_idt[index];
|
|
||||||
descriptor.offset1 = (uint16_t)((uint64_t)handler >> 0);
|
|
||||||
descriptor.offset2 = (uint16_t)((uint64_t)handler >> 16);
|
|
||||||
descriptor.offset3 = (uint32_t)((uint64_t)handler >> 32);
|
|
||||||
|
|
||||||
descriptor.selector = 0x08;
|
|
||||||
descriptor.IST = 0;
|
|
||||||
descriptor.flags = 0x8E;
|
|
||||||
}
|
|
||||||
|
|
||||||
void IDT::register_syscall_handler(uint8_t index, void (*handler)())
|
|
||||||
{
|
|
||||||
register_interrupt_handler(index, handler);
|
|
||||||
m_idt[index].flags = 0xEE;
|
|
||||||
}
|
|
||||||
|
|
||||||
void IDT::register_irq_handler(uint8_t irq, Interruptable* interruptable)
|
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define X(num) extern "C" void isr ## num();
|
|
||||||
ISR_LIST_X
|
|
||||||
#undef X
|
|
||||||
|
|
||||||
#define X(num) extern "C" void irq ## num();
|
|
||||||
IRQ_LIST_X
|
|
||||||
#undef X
|
|
||||||
|
|
||||||
extern "C" void syscall_asm();
|
|
||||||
|
|
||||||
IDT* IDT::create()
|
|
||||||
{
|
|
||||||
auto* idt = new IDT();
|
|
||||||
ASSERT(idt);
|
|
||||||
|
|
||||||
memset(idt->m_idt.data(), 0x00, 0x100 * sizeof(GateDescriptor));
|
|
||||||
|
|
||||||
#define X(num) idt->register_interrupt_handler(num, isr ## num);
|
|
||||||
ISR_LIST_X
|
|
||||||
#undef X
|
|
||||||
|
|
||||||
#define X(num) idt->register_interrupt_handler(IRQ_VECTOR_BASE + num, irq ## num);
|
|
||||||
IRQ_LIST_X
|
|
||||||
#undef X
|
|
||||||
|
|
||||||
idt->register_syscall_handler(0x80, syscall_asm);
|
|
||||||
|
|
||||||
return idt;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[noreturn]] void IDT::force_triple_fault()
|
|
||||||
{
|
|
||||||
// load 0 sized IDT and trigger an interrupt to force triple fault
|
|
||||||
Processor::set_interrupt_state(InterruptState::Disabled);
|
|
||||||
Processor::idt().m_idtr.size = 0;
|
|
||||||
Processor::idt().load();
|
|
||||||
asm volatile("int $0x00");
|
|
||||||
ASSERT_NOT_REACHED();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,51 +1,97 @@
|
|||||||
.section .userspace, "aw"
|
.section .userspace, "ax"
|
||||||
|
|
||||||
// stack contains
|
// stack contains
|
||||||
// return address
|
// (8 bytes) return address (on return stack)
|
||||||
// signal number
|
// (8 bytes) return stack
|
||||||
// signal handler
|
// (8 bytes) return rflags
|
||||||
|
// (8 bytes) restore sigmask
|
||||||
|
// (56 bytes) siginfo_t
|
||||||
|
// (8 bytes) signal number
|
||||||
|
// (8 bytes) signal handler
|
||||||
|
|
||||||
.global signal_trampoline
|
.global signal_trampoline
|
||||||
signal_trampoline:
|
signal_trampoline:
|
||||||
pushq %rax
|
pushq %r15 // gregs
|
||||||
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 %r14
|
||||||
pushq %r15
|
pushq %r13
|
||||||
|
pushq %r12
|
||||||
|
pushq %r11
|
||||||
|
pushq %r10
|
||||||
|
pushq %r9
|
||||||
|
pushq %r8
|
||||||
|
pushq %rsi
|
||||||
|
pushq %rdi
|
||||||
|
pushq %rdx
|
||||||
|
pushq %rcx
|
||||||
|
pushq %rbx
|
||||||
|
pushq %rax
|
||||||
|
pushq %rbp
|
||||||
|
|
||||||
// This is 16 byte aligned
|
movq 208(%rsp), %rax
|
||||||
|
pushq %rax; addq $(128 + 8), (%rsp)
|
||||||
|
pushq (%rax)
|
||||||
|
|
||||||
|
// FIXME: populate these
|
||||||
|
xorq %rax, %rax
|
||||||
|
pushq %rax // stack
|
||||||
|
pushq %rax
|
||||||
|
pushq %rax
|
||||||
|
pushq %rax // sigset
|
||||||
|
pushq %rax // link
|
||||||
|
|
||||||
|
movq %rsp, %rdx // ucontext
|
||||||
|
leaq 192(%rsp), %rsi // siginfo
|
||||||
|
movq 184(%rsp), %rdi // signal number
|
||||||
|
movq 176(%rsp), %rax // handler
|
||||||
|
|
||||||
|
// align stack to 16 bytes
|
||||||
|
movq %rsp, %rbp
|
||||||
|
andq $-16, %rsp
|
||||||
|
|
||||||
|
subq $512, %rsp
|
||||||
|
fxsave64 (%rsp)
|
||||||
|
|
||||||
movq 128(%rsp), %rdi
|
|
||||||
movq 120(%rsp), %rax
|
|
||||||
call *%rax
|
call *%rax
|
||||||
|
|
||||||
popq %r15
|
fxrstor64 (%rsp)
|
||||||
popq %r14
|
addq $512, %rsp
|
||||||
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
|
|
||||||
|
|
||||||
|
// restore stack
|
||||||
|
movq %rbp, %rsp
|
||||||
|
addq $40, %rsp
|
||||||
|
|
||||||
|
// restore sigmask
|
||||||
|
movq $83, %rdi // SYS_SIGPROCMASK
|
||||||
|
movq $3, %rsi // SIG_SETMASK
|
||||||
|
leaq 192(%rsp), %rdx // set
|
||||||
|
xorq %r10, %r10 // oset
|
||||||
|
syscall
|
||||||
|
|
||||||
|
// restore registers
|
||||||
addq $16, %rsp
|
addq $16, %rsp
|
||||||
|
popq %rbp
|
||||||
|
popq %rax
|
||||||
|
popq %rbx
|
||||||
|
popq %rcx
|
||||||
|
popq %rdx
|
||||||
|
popq %rdi
|
||||||
|
popq %rsi
|
||||||
|
popq %r8
|
||||||
|
popq %r9
|
||||||
|
popq %r10
|
||||||
|
popq %r11
|
||||||
|
popq %r12
|
||||||
|
popq %r13
|
||||||
|
popq %r14
|
||||||
|
popq %r15
|
||||||
|
|
||||||
|
// skip handler, number, siginfo_t, sigmask
|
||||||
|
addq $80, %rsp
|
||||||
|
|
||||||
|
// restore flags
|
||||||
|
popfq
|
||||||
|
|
||||||
|
movq (%rsp), %rsp
|
||||||
|
|
||||||
// return over red-zone
|
// return over red-zone
|
||||||
ret $128
|
ret $128
|
||||||
|
|||||||
@@ -1,3 +1,27 @@
|
|||||||
|
.global asm_syscall_handler
|
||||||
|
asm_syscall_handler:
|
||||||
|
swapgs
|
||||||
|
|
||||||
|
movq %rsp, %rax
|
||||||
|
movq %gs:8, %rsp
|
||||||
|
|
||||||
|
pushq $(0x20 | 3)
|
||||||
|
pushq %rax
|
||||||
|
pushq %r11
|
||||||
|
pushq $(0x28 | 3)
|
||||||
|
pushq %rcx
|
||||||
|
subq $8, %rsp
|
||||||
|
|
||||||
|
movq %r10, %rcx
|
||||||
|
call cpp_syscall_handler
|
||||||
|
|
||||||
|
movq 8(%rsp), %rcx
|
||||||
|
movq 24(%rsp), %r11
|
||||||
|
movq 32(%rsp), %rsp
|
||||||
|
|
||||||
|
swapgs
|
||||||
|
sysretq
|
||||||
|
|
||||||
.global sys_fork_trampoline
|
.global sys_fork_trampoline
|
||||||
sys_fork_trampoline:
|
sys_fork_trampoline:
|
||||||
pushq %rbx
|
pushq %rbx
|
||||||
@@ -6,13 +30,16 @@ sys_fork_trampoline:
|
|||||||
pushq %r13
|
pushq %r13
|
||||||
pushq %r14
|
pushq %r14
|
||||||
pushq %r15
|
pushq %r15
|
||||||
|
|
||||||
call read_ip
|
call read_ip
|
||||||
testq %rax, %rax
|
testq %rax, %rax
|
||||||
je .done
|
jz .done
|
||||||
|
|
||||||
movq %rax, %rsi
|
movq %rax, %rsi
|
||||||
movq %rsp, %rdi
|
movq %rsp, %rdi
|
||||||
call sys_fork
|
call sys_fork
|
||||||
.done:
|
|
||||||
|
.done:
|
||||||
popq %r15
|
popq %r15
|
||||||
popq %r14
|
popq %r14
|
||||||
popq %r13
|
popq %r13
|
||||||
|
|||||||
@@ -4,36 +4,25 @@ read_ip:
|
|||||||
popq %rax
|
popq %rax
|
||||||
jmp *%rax
|
jmp *%rax
|
||||||
|
|
||||||
exit_thread_trampoline:
|
# void start_kernel_thread()
|
||||||
|
.global start_kernel_thread
|
||||||
|
start_kernel_thread:
|
||||||
|
# STACK LAYOUT
|
||||||
|
# on_exit arg
|
||||||
|
# on_exit func
|
||||||
|
# entry arg
|
||||||
|
# entry func
|
||||||
|
|
||||||
movq 8(%rsp), %rdi
|
movq 8(%rsp), %rdi
|
||||||
ret
|
movq 0(%rsp), %rsi
|
||||||
|
|
||||||
# void start_thread(uint64_t sp, uint64_t ip)
|
|
||||||
.global start_thread
|
|
||||||
start_thread:
|
|
||||||
movq %rdi, %rsp
|
|
||||||
popq %rdi
|
|
||||||
movq $0, %rbp
|
|
||||||
pushq $exit_thread_trampoline
|
|
||||||
sti
|
sti
|
||||||
jmp *%rsi
|
call *%rsi
|
||||||
|
|
||||||
# void continue_thread(uint64_t sp, uint64_t ip)
|
movq 24(%rsp), %rdi
|
||||||
.global continue_thread
|
movq 16(%rsp), %rsi
|
||||||
continue_thread:
|
call *%rsi
|
||||||
movq %rdi, %rsp
|
|
||||||
movq $0, %rax
|
|
||||||
jmp *%rsi
|
|
||||||
|
|
||||||
# void thread_userspace_trampoline(uint64_t sp, uint64_t ip, int argc, char** argv, char** envp)
|
.global start_userspace_thread
|
||||||
.global thread_userspace_trampoline
|
start_userspace_thread:
|
||||||
thread_userspace_trampoline:
|
swapgs
|
||||||
pushq $0x23
|
|
||||||
pushq %rdi
|
|
||||||
pushfq
|
|
||||||
pushq $0x1B
|
|
||||||
pushq %rsi
|
|
||||||
movq %rdx, %rdi
|
|
||||||
movq %rcx, %rsi
|
|
||||||
movq %r8, %rdx
|
|
||||||
iretq
|
iretq
|
||||||
|
|||||||
87
kernel/arch/x86_64/User.S
Normal file
87
kernel/arch/x86_64/User.S
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
# bool safe_user_memcpy(void*, const void*, size_t)
|
||||||
|
.global safe_user_memcpy
|
||||||
|
.global safe_user_memcpy_end
|
||||||
|
.global safe_user_memcpy_fault
|
||||||
|
safe_user_memcpy:
|
||||||
|
xorq %rax, %rax
|
||||||
|
movq %rdx, %rcx
|
||||||
|
rep movsb
|
||||||
|
incq %rax
|
||||||
|
safe_user_memcpy_fault:
|
||||||
|
ret
|
||||||
|
safe_user_memcpy_end:
|
||||||
|
|
||||||
|
# bool safe_user_strncpy(void*, const void*, size_t)
|
||||||
|
.global safe_user_strncpy
|
||||||
|
.global safe_user_strncpy_end
|
||||||
|
.global safe_user_strncpy_fault
|
||||||
|
safe_user_strncpy:
|
||||||
|
movq %rdx, %rcx
|
||||||
|
testq %rcx, %rcx
|
||||||
|
jz safe_user_strncpy_fault
|
||||||
|
|
||||||
|
.safe_user_strncpy_align_loop:
|
||||||
|
testb $0x7, %sil
|
||||||
|
jz .safe_user_strncpy_align_done
|
||||||
|
|
||||||
|
movb (%rsi), %al
|
||||||
|
movb %al, (%rdi)
|
||||||
|
testb %al, %al
|
||||||
|
jz .safe_user_strncpy_done
|
||||||
|
|
||||||
|
incq %rdi
|
||||||
|
incq %rsi
|
||||||
|
decq %rcx
|
||||||
|
jnz .safe_user_strncpy_align_loop
|
||||||
|
jmp safe_user_strncpy_fault
|
||||||
|
|
||||||
|
.safe_user_strncpy_align_done:
|
||||||
|
movq $0x0101010101010101, %r8
|
||||||
|
movq $0x8080808080808080, %r9
|
||||||
|
|
||||||
|
.safe_user_strncpy_qword_loop:
|
||||||
|
cmpq $8, %rcx
|
||||||
|
jb .safe_user_strncpy_qword_done
|
||||||
|
|
||||||
|
movq (%rsi), %rax
|
||||||
|
movq %rax, %r10
|
||||||
|
movq %rax, %r11
|
||||||
|
|
||||||
|
# https://graphics.stanford.edu/~seander/bithacks.html#ZeroInWord
|
||||||
|
subq %r8, %r10
|
||||||
|
notq %r11
|
||||||
|
andq %r11, %r10
|
||||||
|
andq %r9, %r10
|
||||||
|
jnz .safe_user_strncpy_byte_loop
|
||||||
|
|
||||||
|
movq %rax, (%rdi)
|
||||||
|
|
||||||
|
addq $8, %rdi
|
||||||
|
addq $8, %rsi
|
||||||
|
subq $8, %rcx
|
||||||
|
jnz .safe_user_strncpy_qword_loop
|
||||||
|
jmp safe_user_strncpy_fault
|
||||||
|
|
||||||
|
.safe_user_strncpy_qword_done:
|
||||||
|
testq %rcx, %rcx
|
||||||
|
jz safe_user_strncpy_fault
|
||||||
|
|
||||||
|
.safe_user_strncpy_byte_loop:
|
||||||
|
movb (%rsi), %al
|
||||||
|
movb %al, (%rdi)
|
||||||
|
testb %al, %al
|
||||||
|
jz .safe_user_strncpy_done
|
||||||
|
|
||||||
|
incq %rdi
|
||||||
|
incq %rsi
|
||||||
|
decq %rcx
|
||||||
|
jnz .safe_user_strncpy_byte_loop
|
||||||
|
|
||||||
|
safe_user_strncpy_fault:
|
||||||
|
xorq %rax, %rax
|
||||||
|
ret
|
||||||
|
|
||||||
|
.safe_user_strncpy_done:
|
||||||
|
movb $1, %al
|
||||||
|
ret
|
||||||
|
safe_user_strncpy_end:
|
||||||
29
kernel/arch/x86_64/Yield.S
Normal file
29
kernel/arch/x86_64/Yield.S
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
.global asm_yield_trampoline
|
||||||
|
asm_yield_trampoline:
|
||||||
|
leaq 8(%rsp), %rcx
|
||||||
|
movq %rdi, %rsp
|
||||||
|
|
||||||
|
subq $8, %rsp
|
||||||
|
pushq -8(%rcx)
|
||||||
|
pushq %rcx
|
||||||
|
pushq %rax
|
||||||
|
pushq %rbx
|
||||||
|
pushq %rbp
|
||||||
|
pushq %r12
|
||||||
|
pushq %r13
|
||||||
|
pushq %r14
|
||||||
|
pushq %r15
|
||||||
|
|
||||||
|
movq %rsp, %rdi
|
||||||
|
call scheduler_on_yield
|
||||||
|
|
||||||
|
popq %r15
|
||||||
|
popq %r14
|
||||||
|
popq %r13
|
||||||
|
popq %r12
|
||||||
|
popq %rbp
|
||||||
|
popq %rbx
|
||||||
|
popq %rax
|
||||||
|
movq 8(%rsp), %rcx
|
||||||
|
movq 0(%rsp), %rsp
|
||||||
|
jmp *%rcx
|
||||||
@@ -11,9 +11,28 @@
|
|||||||
|
|
||||||
.code32
|
.code32
|
||||||
|
|
||||||
# multiboot2 header
|
// custom addresses, video mode info, page align modules
|
||||||
|
.set multiboot_flags, (1 << 16) | (1 << 2) | (1 << 0)
|
||||||
|
|
||||||
.section .multiboot, "aw"
|
.section .multiboot, "aw"
|
||||||
.align 8
|
multiboot_start:
|
||||||
|
.long 0x1BADB002
|
||||||
|
.long multiboot_flags
|
||||||
|
.long -(0x1BADB002 + multiboot_flags)
|
||||||
|
|
||||||
|
.long V2P(multiboot_start)
|
||||||
|
.long V2P(g_kernel_start)
|
||||||
|
.long V2P(g_kernel_bss_start)
|
||||||
|
.long V2P(g_kernel_end)
|
||||||
|
.long V2P(_start)
|
||||||
|
|
||||||
|
.long 0
|
||||||
|
.long FB_WIDTH
|
||||||
|
.long FB_HEIGHT
|
||||||
|
.long FB_BPP
|
||||||
|
multiboot_end:
|
||||||
|
|
||||||
|
.section .multiboot2, "aw"
|
||||||
multiboot2_start:
|
multiboot2_start:
|
||||||
.long 0xE85250D6
|
.long 0xE85250D6
|
||||||
.long 0
|
.long 0
|
||||||
@@ -36,6 +55,12 @@ multiboot2_start:
|
|||||||
.long 12
|
.long 12
|
||||||
.long V2P(_start)
|
.long V2P(_start)
|
||||||
|
|
||||||
|
# page align modules
|
||||||
|
.align 8
|
||||||
|
.short 6
|
||||||
|
.short 0
|
||||||
|
.long 8
|
||||||
|
|
||||||
.align 8
|
.align 8
|
||||||
.short 0
|
.short 0
|
||||||
.short 0
|
.short 0
|
||||||
@@ -43,7 +68,6 @@ multiboot2_start:
|
|||||||
multiboot2_end:
|
multiboot2_end:
|
||||||
|
|
||||||
.section .bananboot, "aw"
|
.section .bananboot, "aw"
|
||||||
.align 8
|
|
||||||
bananboot_start:
|
bananboot_start:
|
||||||
.long 0xBABAB007
|
.long 0xBABAB007
|
||||||
.long -(0xBABAB007 + FB_WIDTH + FB_HEIGHT + FB_BPP)
|
.long -(0xBABAB007 + FB_WIDTH + FB_HEIGHT + FB_BPP)
|
||||||
@@ -53,9 +77,10 @@ bananboot_start:
|
|||||||
bananboot_end:
|
bananboot_end:
|
||||||
|
|
||||||
.section .bss, "aw", @nobits
|
.section .bss, "aw", @nobits
|
||||||
boot_stack_bottom:
|
.global g_boot_stack_top
|
||||||
|
g_boot_stack_bottom:
|
||||||
.skip 4096 * 4
|
.skip 4096 * 4
|
||||||
boot_stack_top:
|
g_boot_stack_top:
|
||||||
|
|
||||||
.global g_kernel_cmdline
|
.global g_kernel_cmdline
|
||||||
g_kernel_cmdline:
|
g_kernel_cmdline:
|
||||||
@@ -108,9 +133,6 @@ g_ap_startup_done:
|
|||||||
.global g_ap_running_count
|
.global g_ap_running_count
|
||||||
g_ap_running_count:
|
g_ap_running_count:
|
||||||
.byte 0
|
.byte 0
|
||||||
.global g_ap_stack_loaded
|
|
||||||
g_ap_stack_loaded:
|
|
||||||
.byte 0
|
|
||||||
|
|
||||||
.section .text
|
.section .text
|
||||||
|
|
||||||
@@ -158,6 +180,13 @@ enable_sse:
|
|||||||
movl %eax, %cr4
|
movl %eax, %cr4
|
||||||
ret
|
ret
|
||||||
|
|
||||||
|
enable_tsc:
|
||||||
|
# allow userspace to use RDTSC
|
||||||
|
movl %cr4, %ecx
|
||||||
|
andl $0xFFFFFFFB, %ecx
|
||||||
|
movl %ecx, %cr4
|
||||||
|
ret
|
||||||
|
|
||||||
initialize_paging:
|
initialize_paging:
|
||||||
# enable PAE
|
# enable PAE
|
||||||
movl %cr4, %ecx
|
movl %cr4, %ecx
|
||||||
@@ -190,11 +219,11 @@ _start:
|
|||||||
movl %eax, V2P(bootloader_magic)
|
movl %eax, V2P(bootloader_magic)
|
||||||
movl %ebx, V2P(bootloader_info)
|
movl %ebx, V2P(bootloader_info)
|
||||||
|
|
||||||
movl $V2P(boot_stack_top), %esp
|
movl $V2P(g_boot_stack_top), %esp
|
||||||
|
|
||||||
call check_requirements
|
call check_requirements
|
||||||
call enable_sse
|
call enable_sse
|
||||||
|
call enable_tsc
|
||||||
call initialize_paging
|
call initialize_paging
|
||||||
|
|
||||||
# flush gdt and jump to 64 bit
|
# flush gdt and jump to 64 bit
|
||||||
@@ -220,6 +249,13 @@ higher_half:
|
|||||||
# call global constuctors
|
# call global constuctors
|
||||||
call _init
|
call _init
|
||||||
|
|
||||||
|
movq $g_init_array_start, %rbx
|
||||||
|
jmp 2f
|
||||||
|
1: call *(%rbx)
|
||||||
|
addq $8, %rbx
|
||||||
|
2: cmpq $g_init_array_end, %rbx
|
||||||
|
jne 1b
|
||||||
|
|
||||||
# call to the kernel itself (clear rbp for stacktrace)
|
# call to the kernel itself (clear rbp for stacktrace)
|
||||||
xorq %rbp, %rbp
|
xorq %rbp, %rbp
|
||||||
|
|
||||||
@@ -237,29 +273,31 @@ system_halt:
|
|||||||
jmp 1b
|
jmp 1b
|
||||||
|
|
||||||
|
|
||||||
|
#define AP_V2P(vaddr) ((vaddr) - ap_trampoline + 0xF000)
|
||||||
|
|
||||||
.section .ap_init, "ax"
|
.section .ap_init, "ax"
|
||||||
|
|
||||||
.code16
|
.code16
|
||||||
.global ap_trampoline
|
.global ap_trampoline
|
||||||
ap_trampoline:
|
ap_trampoline:
|
||||||
jmp 1f
|
jmp 1f
|
||||||
|
|
||||||
.align 8
|
.align 8
|
||||||
ap_stack_ptr:
|
ap_stack_ptr:
|
||||||
.skip 4
|
.skip 4
|
||||||
1:
|
ap_stack_loaded:
|
||||||
cli; cld
|
.skip 1
|
||||||
ljmpl $0x00, $ap_cs_clear
|
|
||||||
|
1: cli; cld
|
||||||
|
ljmpl $0x00, $AP_V2P(ap_cs_clear)
|
||||||
|
|
||||||
ap_cs_clear:
|
ap_cs_clear:
|
||||||
xorw %ax, %ax
|
|
||||||
movw %ax, %ds
|
|
||||||
|
|
||||||
# load ap gdt and enter protected mode
|
# load ap gdt and enter protected mode
|
||||||
lgdt ap_gdtr
|
lgdt AP_V2P(ap_gdtr)
|
||||||
movl %cr0, %eax
|
movl %cr0, %eax
|
||||||
orb $1, %al
|
orb $1, %al
|
||||||
movl %eax, %cr0
|
movl %eax, %cr0
|
||||||
ljmpl $0x08, $ap_protected_mode
|
ljmpl $0x08, $AP_V2P(ap_protected_mode)
|
||||||
|
|
||||||
.code32
|
.code32
|
||||||
ap_protected_mode:
|
ap_protected_mode:
|
||||||
@@ -268,16 +306,16 @@ ap_protected_mode:
|
|||||||
movw %ax, %ss
|
movw %ax, %ss
|
||||||
movw %ax, %es
|
movw %ax, %es
|
||||||
|
|
||||||
movl ap_stack_ptr, %esp
|
movl AP_V2P(ap_stack_ptr), %esp
|
||||||
movb $1, V2P(g_ap_stack_loaded)
|
movb $1, AP_V2P(ap_stack_loaded)
|
||||||
|
|
||||||
call V2P(enable_sse)
|
leal V2P(enable_sse), %ecx; call *%ecx
|
||||||
|
leal V2P(enable_tsc), %ecx; call *%ecx
|
||||||
call V2P(initialize_paging)
|
leal V2P(initialize_paging), %ecx; call *%ecx
|
||||||
|
|
||||||
# load boot gdt and enter long mode
|
# load boot gdt and enter long mode
|
||||||
lgdt V2P(boot_gdtr)
|
lgdt V2P(boot_gdtr)
|
||||||
ljmpl $0x08, $ap_long_mode
|
ljmpl $0x08, $AP_V2P(ap_long_mode)
|
||||||
|
|
||||||
.code64
|
.code64
|
||||||
ap_long_mode:
|
ap_long_mode:
|
||||||
@@ -285,22 +323,20 @@ ap_long_mode:
|
|||||||
movl %esp, %esp
|
movl %esp, %esp
|
||||||
addq $KERNEL_OFFSET, %rsp
|
addq $KERNEL_OFFSET, %rsp
|
||||||
|
|
||||||
# jump to higher half
|
|
||||||
movabsq $ap_higher_half, %rcx
|
|
||||||
jmp *%rcx
|
|
||||||
|
|
||||||
ap_higher_half:
|
|
||||||
# clear rbp for stacktrace
|
# clear rbp for stacktrace
|
||||||
xorq %rbp, %rbp
|
xorq %rbp, %rbp
|
||||||
|
|
||||||
|
xorb %al, %al
|
||||||
1: pause
|
1: pause
|
||||||
cmpb $0, g_ap_startup_done
|
cmpb %al, g_ap_startup_done
|
||||||
jz 1b
|
jz 1b
|
||||||
|
|
||||||
lock incb g_ap_running_count
|
lock incb g_ap_running_count
|
||||||
|
|
||||||
call ap_main
|
# jump to ap_main in higher half
|
||||||
jmp system_halt
|
movabsq $ap_main, %rcx
|
||||||
|
call *%rcx
|
||||||
|
jmp V2P(system_halt)
|
||||||
|
|
||||||
ap_gdt:
|
ap_gdt:
|
||||||
.quad 0x0000000000000000 # null descriptor
|
.quad 0x0000000000000000 # null descriptor
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
.macro pushaq
|
.macro intr_header, n
|
||||||
pushq %rax
|
pushq %rax
|
||||||
pushq %rbx
|
|
||||||
pushq %rcx
|
pushq %rcx
|
||||||
pushq %rdx
|
pushq %rdx
|
||||||
|
pushq %rbx
|
||||||
pushq %rbp
|
pushq %rbp
|
||||||
pushq %rdi
|
|
||||||
pushq %rsi
|
pushq %rsi
|
||||||
|
pushq %rdi
|
||||||
pushq %r8
|
pushq %r8
|
||||||
pushq %r9
|
pushq %r9
|
||||||
pushq %r10
|
pushq %r10
|
||||||
@@ -14,10 +14,18 @@
|
|||||||
pushq %r13
|
pushq %r13
|
||||||
pushq %r14
|
pushq %r14
|
||||||
pushq %r15
|
pushq %r15
|
||||||
|
testb $3, \n+15*8(%rsp)
|
||||||
|
jz 1f
|
||||||
|
swapgs
|
||||||
|
1: cld
|
||||||
.endm
|
.endm
|
||||||
|
|
||||||
.macro popaq
|
.macro intr_footer, n
|
||||||
popq %r15
|
testb $3, \n+15*8(%rsp)
|
||||||
|
jz 1f
|
||||||
|
call cpp_check_signal
|
||||||
|
swapgs
|
||||||
|
1: popq %r15
|
||||||
popq %r14
|
popq %r14
|
||||||
popq %r13
|
popq %r13
|
||||||
popq %r12
|
popq %r12
|
||||||
@@ -25,67 +33,58 @@
|
|||||||
popq %r10
|
popq %r10
|
||||||
popq %r9
|
popq %r9
|
||||||
popq %r8
|
popq %r8
|
||||||
popq %rsi
|
|
||||||
popq %rdi
|
popq %rdi
|
||||||
|
popq %rsi
|
||||||
popq %rbp
|
popq %rbp
|
||||||
|
popq %rbx
|
||||||
popq %rdx
|
popq %rdx
|
||||||
popq %rcx
|
popq %rcx
|
||||||
popq %rbx
|
|
||||||
popq %rax
|
popq %rax
|
||||||
.endm
|
.endm
|
||||||
|
|
||||||
.macro popaq_no_rax
|
|
||||||
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
|
|
||||||
.endm
|
|
||||||
|
|
||||||
isr_stub:
|
isr_stub:
|
||||||
pushaq
|
intr_header 24
|
||||||
|
movq %cr0, %rax; pushq %rax
|
||||||
movq %cr0, %rax; pushq %rax
|
movq %cr2, %rax; pushq %rax
|
||||||
movq %cr2, %rax; pushq %rax
|
movq %cr3, %rax; pushq %rax
|
||||||
movq %cr3, %rax; pushq %rax
|
movq %cr4, %rax; pushq %rax
|
||||||
movq %cr4, %rax; pushq %rax
|
|
||||||
movq 184(%rsp), %rax; pushq %rax
|
|
||||||
movq 176(%rsp), %rax; pushq %rax
|
|
||||||
movq 208(%rsp), %rax; pushq %rax
|
|
||||||
|
|
||||||
movq 176(%rsp), %rdi
|
|
||||||
movq 184(%rsp), %rsi
|
|
||||||
|
|
||||||
movq %rsp, %rdx
|
|
||||||
addq $192, %rdx
|
|
||||||
|
|
||||||
movq %rsp, %rcx
|
|
||||||
|
|
||||||
|
movq 152(%rsp), %rdi // isr number
|
||||||
|
movq 160(%rsp), %rsi // error code
|
||||||
|
leaq 168(%rsp), %rdx // interrupt stack ptr
|
||||||
|
movq %rsp, %rcx // register ptr
|
||||||
call cpp_isr_handler
|
call cpp_isr_handler
|
||||||
addq $56, %rsp
|
addq $32, %rsp
|
||||||
popaq
|
|
||||||
|
intr_footer 24
|
||||||
addq $16, %rsp
|
addq $16, %rsp
|
||||||
iretq
|
iretq
|
||||||
|
|
||||||
irq_stub:
|
irq_stub:
|
||||||
pushaq
|
intr_header 24
|
||||||
movq 0x78(%rsp), %rdi # irq number
|
xorq %rbp, %rbp
|
||||||
movq %rsp, %rsi
|
movq 120(%rsp), %rdi # irq number
|
||||||
addq $136, %rsi
|
|
||||||
call cpp_irq_handler
|
call cpp_irq_handler
|
||||||
popaq
|
intr_footer 24
|
||||||
addq $16, %rsp
|
addq $16, %rsp
|
||||||
iretq
|
iretq
|
||||||
|
|
||||||
|
.global asm_ipi_handler
|
||||||
|
asm_ipi_handler:
|
||||||
|
intr_header 8
|
||||||
|
xorq %rbp, %rbp
|
||||||
|
call cpp_ipi_handler
|
||||||
|
intr_footer 8
|
||||||
|
iretq
|
||||||
|
|
||||||
|
.global asm_timer_handler
|
||||||
|
asm_timer_handler:
|
||||||
|
intr_header 8
|
||||||
|
xorq %rbp, %rbp
|
||||||
|
call cpp_timer_handler
|
||||||
|
intr_footer 8
|
||||||
|
iretq
|
||||||
|
|
||||||
.macro isr n
|
.macro isr n
|
||||||
.global isr\n
|
.global isr\n
|
||||||
isr\n:
|
isr\n:
|
||||||
@@ -142,55 +141,26 @@ isr 29
|
|||||||
isr 30
|
isr 30
|
||||||
isr 31
|
isr 31
|
||||||
|
|
||||||
irq 0
|
.irp i, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, \
|
||||||
irq 1
|
10, 11, 12, 13, 14, 15, 16, 17, 18, 19, \
|
||||||
irq 2
|
20, 21, 22, 23, 24, 25, 26, 27, 28, 29, \
|
||||||
irq 3
|
30, 31, 32, 33, 34, 35, 36, 37, 38, 39, \
|
||||||
irq 4
|
40, 41, 42, 43, 44, 45, 46, 47, 48, 49, \
|
||||||
irq 5
|
50, 51, 52, 53, 54, 55, 56, 57, 58, 59, \
|
||||||
irq 6
|
60, 61, 62, 63, 64, 65, 66, 67, 68, 69, \
|
||||||
irq 7
|
70, 71, 72, 73, 74, 75, 76, 77, 78, 79, \
|
||||||
irq 8
|
80, 81, 82, 83, 84, 85, 86, 87, 88, 89, \
|
||||||
irq 9
|
90, 91, 92, 93, 94, 95, 96, 97, 98, 99, \
|
||||||
irq 10
|
100,101,102,103,104,105,106,107,108,109, \
|
||||||
irq 11
|
110,111,112,113,114,115,116,117,118,119, \
|
||||||
irq 12
|
120,121,122,123,124,125,126,127,128,129, \
|
||||||
irq 13
|
130,131,132,133,134,135,136,137,138,139, \
|
||||||
irq 14
|
140,141,142,143,144,145,146,147,148,149, \
|
||||||
irq 15
|
150,151,152,153,154,155,156,157,158,159, \
|
||||||
irq 16
|
160,161,162,163,164,165,166,167,168,169, \
|
||||||
irq 17
|
170,171,172,173,174,175,176,177,178,179, \
|
||||||
irq 18
|
180,181,182,183,184,185,186,187,188,189, \
|
||||||
irq 19
|
190,191,192,193,194,195,196,197,198,199, \
|
||||||
irq 20
|
200,201,202,203,204,205,206,207
|
||||||
irq 21
|
irq \i
|
||||||
irq 22
|
.endr
|
||||||
irq 23
|
|
||||||
irq 24
|
|
||||||
irq 25
|
|
||||||
irq 26
|
|
||||||
irq 27
|
|
||||||
irq 28
|
|
||||||
irq 29
|
|
||||||
irq 30
|
|
||||||
irq 31
|
|
||||||
irq 32
|
|
||||||
|
|
||||||
// arguments in RAX, RBX, RCX, RDX, RSI, RDI
|
|
||||||
// System V ABI: RDI, RSI, RDX, RCX, R8, R9
|
|
||||||
.global syscall_asm
|
|
||||||
syscall_asm:
|
|
||||||
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
|
|
||||||
|
|||||||
@@ -4,13 +4,6 @@ KERNEL_OFFSET = 0xFFFFFFFF80000000;
|
|||||||
|
|
||||||
SECTIONS
|
SECTIONS
|
||||||
{
|
{
|
||||||
. = 0xF000;
|
|
||||||
.ap_init ALIGN(4K) : AT(ADDR(.ap_init))
|
|
||||||
{
|
|
||||||
g_ap_init_addr = .;
|
|
||||||
*(.ap_init)
|
|
||||||
}
|
|
||||||
|
|
||||||
. = 0x00100000 + KERNEL_OFFSET;
|
. = 0x00100000 + KERNEL_OFFSET;
|
||||||
|
|
||||||
g_kernel_start = .;
|
g_kernel_start = .;
|
||||||
@@ -18,6 +11,7 @@ SECTIONS
|
|||||||
{
|
{
|
||||||
g_kernel_execute_start = .;
|
g_kernel_execute_start = .;
|
||||||
*(.multiboot)
|
*(.multiboot)
|
||||||
|
*(.multiboot2)
|
||||||
*(.bananboot)
|
*(.bananboot)
|
||||||
*(.text.*)
|
*(.text.*)
|
||||||
}
|
}
|
||||||
@@ -28,18 +22,32 @@ SECTIONS
|
|||||||
g_userspace_end = .;
|
g_userspace_end = .;
|
||||||
g_kernel_execute_end = .;
|
g_kernel_execute_end = .;
|
||||||
}
|
}
|
||||||
|
.ap_init ALIGN(4K) : AT(ADDR(.ap_init) - KERNEL_OFFSET)
|
||||||
|
{
|
||||||
|
g_ap_init_addr = .;
|
||||||
|
*(.ap_init)
|
||||||
|
}
|
||||||
.rodata ALIGN(4K) : AT(ADDR(.rodata) - KERNEL_OFFSET)
|
.rodata ALIGN(4K) : AT(ADDR(.rodata) - KERNEL_OFFSET)
|
||||||
{
|
{
|
||||||
*(.rodata.*)
|
*(.rodata.*)
|
||||||
}
|
}
|
||||||
|
.init_array ALIGN(4K) : AT(ADDR(.init_array) - KERNEL_OFFSET)
|
||||||
|
{
|
||||||
|
g_init_array_start = .;
|
||||||
|
*(.init_array)
|
||||||
|
g_init_array_end = .;
|
||||||
|
}
|
||||||
.data ALIGN(4K) : AT(ADDR(.data) - KERNEL_OFFSET)
|
.data ALIGN(4K) : AT(ADDR(.data) - KERNEL_OFFSET)
|
||||||
{
|
{
|
||||||
|
g_kernel_writable_start = .;
|
||||||
*(.data)
|
*(.data)
|
||||||
}
|
}
|
||||||
.bss ALIGN(4K) : AT(ADDR(.bss) - KERNEL_OFFSET)
|
.bss ALIGN(4K) : AT(ADDR(.bss) - KERNEL_OFFSET)
|
||||||
{
|
{
|
||||||
|
g_kernel_bss_start = .;
|
||||||
*(COMMON)
|
*(COMMON)
|
||||||
*(.bss)
|
*(.bss)
|
||||||
|
g_kernel_writable_end = .;
|
||||||
}
|
}
|
||||||
g_kernel_end = .;
|
g_kernel_end = .;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,20 +42,20 @@ namespace __cxxabiv1
|
|||||||
{
|
{
|
||||||
using __guard = uint64_t;
|
using __guard = uint64_t;
|
||||||
|
|
||||||
int __cxa_guard_acquire (__guard* g)
|
extern "C" int __cxa_guard_acquire (__guard* g)
|
||||||
{
|
{
|
||||||
uint8_t* byte = reinterpret_cast<uint8_t*>(g);
|
uint8_t* byte = reinterpret_cast<uint8_t*>(g);
|
||||||
uint8_t zero = 0;
|
uint8_t zero = 0;
|
||||||
return __atomic_compare_exchange_n(byte, &zero, 1, false, __ATOMIC_ACQUIRE, __ATOMIC_ACQUIRE);
|
return __atomic_compare_exchange_n(byte, &zero, 1, false, __ATOMIC_ACQUIRE, __ATOMIC_ACQUIRE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void __cxa_guard_release (__guard* g)
|
extern "C" void __cxa_guard_release (__guard* g)
|
||||||
{
|
{
|
||||||
uint8_t* byte = reinterpret_cast<uint8_t*>(g);
|
uint8_t* byte = reinterpret_cast<uint8_t*>(g);
|
||||||
__atomic_store_n(byte, 0, __ATOMIC_RELEASE);
|
__atomic_store_n(byte, 0, __ATOMIC_RELEASE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void __cxa_guard_abort (__guard*)
|
extern "C" void __cxa_guard_abort (__guard*)
|
||||||
{
|
{
|
||||||
Kernel::panic("__cxa_guard_abort");
|
Kernel::panic("__cxa_guard_abort");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,144 +0,0 @@
|
|||||||
#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]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
104
kernel/include/kernel/ACPI/ACPI.h
Normal file
104
kernel/include/kernel/ACPI/ACPI.h
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <BAN/Vector.h>
|
||||||
|
#include <kernel/ACPI/AML/Namespace.h>
|
||||||
|
#include <kernel/ACPI/EmbeddedController.h>
|
||||||
|
#include <kernel/ACPI/Headers.h>
|
||||||
|
#include <kernel/Memory/Types.h>
|
||||||
|
#include <kernel/ThreadBlocker.h>
|
||||||
|
|
||||||
|
namespace Kernel::ACPI
|
||||||
|
{
|
||||||
|
|
||||||
|
class ACPI : public Interruptable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static BAN::ErrorOr<void> initialize();
|
||||||
|
static ACPI& get();
|
||||||
|
|
||||||
|
static void acquire_global_lock();
|
||||||
|
static void release_global_lock();
|
||||||
|
|
||||||
|
bool hardware_reduced() const { return m_hardware_reduced; }
|
||||||
|
|
||||||
|
const SDTHeader* get_header(BAN::StringView signature, uint32_t index);
|
||||||
|
|
||||||
|
// mode
|
||||||
|
// 0: PIC
|
||||||
|
// 1: APIC
|
||||||
|
// 2: SAPIC
|
||||||
|
BAN::ErrorOr<void> enter_acpi_mode(uint8_t mode);
|
||||||
|
|
||||||
|
BAN::ErrorOr<void> initialize_acpi_devices();
|
||||||
|
|
||||||
|
AML::Namespace* acpi_namespace() { return m_namespace; }
|
||||||
|
|
||||||
|
BAN::ErrorOr<void> poweroff();
|
||||||
|
BAN::ErrorOr<void> reset();
|
||||||
|
|
||||||
|
BAN::ErrorOr<void> register_gpe_handler(uint8_t gpe, void (*callback)(void*), void* argument);
|
||||||
|
|
||||||
|
void handle_irq() override;
|
||||||
|
|
||||||
|
BAN::Span<BAN::UniqPtr<EmbeddedController>> embedded_controllers() { return m_embedded_controllers.span(); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
ACPI() = default;
|
||||||
|
BAN::ErrorOr<void> initialize_impl();
|
||||||
|
|
||||||
|
FADT& fadt() { return *m_fadt; }
|
||||||
|
|
||||||
|
BAN::ErrorOr<void> prepare_sleep(uint8_t sleep_state);
|
||||||
|
void acpi_event_task();
|
||||||
|
|
||||||
|
BAN::ErrorOr<void> load_aml_tables(BAN::StringView name, bool all);
|
||||||
|
|
||||||
|
BAN::ErrorOr<void> route_interrupt_link_device(const AML::Scope& device, uint64_t& routed_irq_mask);
|
||||||
|
|
||||||
|
BAN::ErrorOr<void> initialize_embedded_controller(const AML::Scope& embedded_controller);
|
||||||
|
BAN::ErrorOr<void> initialize_embedded_controllers();
|
||||||
|
|
||||||
|
BAN::Optional<GAS> find_gpe_block(size_t index);
|
||||||
|
bool enable_gpe(uint8_t gpe);
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
FADT* m_fadt { nullptr };
|
||||||
|
|
||||||
|
ThreadBlocker m_event_thread_blocker;
|
||||||
|
|
||||||
|
BAN::Vector<BAN::UniqPtr<EmbeddedController>> m_embedded_controllers;
|
||||||
|
|
||||||
|
struct GPEHandler
|
||||||
|
{
|
||||||
|
bool has_callback { false };
|
||||||
|
union {
|
||||||
|
AML::Reference* method;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
void (*callback)(void*);
|
||||||
|
void* argument;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
bool m_has_any_gpes { false };
|
||||||
|
AML::Scope m_gpe_scope;
|
||||||
|
BAN::Array<GPEHandler, 0xFF> m_gpe_methods;
|
||||||
|
|
||||||
|
bool m_hardware_reduced { false };
|
||||||
|
AML::Namespace* m_namespace { nullptr };
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
179
kernel/include/kernel/ACPI/AML/Bytes.h
Normal file
179
kernel/include/kernel/ACPI/AML/Bytes.h
Normal file
@@ -0,0 +1,179 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
namespace Kernel::ACPI::AML
|
||||||
|
{
|
||||||
|
|
||||||
|
enum class Byte
|
||||||
|
{
|
||||||
|
NullName = 0x00,
|
||||||
|
ZeroOp = 0x00,
|
||||||
|
OneOp = 0x01,
|
||||||
|
// 0x02 - 0x05
|
||||||
|
AliasOp = 0x06,
|
||||||
|
// 0x07
|
||||||
|
NameOp = 0x08,
|
||||||
|
// 0x09
|
||||||
|
BytePrefix = 0x0A,
|
||||||
|
WordPrefix = 0x0B,
|
||||||
|
DWordPrefix = 0x0C,
|
||||||
|
StringPrefix = 0x0D,
|
||||||
|
QWordPrefix = 0x0E,
|
||||||
|
// 0x0F
|
||||||
|
ScopeOp = 0x10,
|
||||||
|
BufferOp = 0x11,
|
||||||
|
PackageOp = 0x12,
|
||||||
|
VarPackageOp = 0x13,
|
||||||
|
MethodOp = 0x14,
|
||||||
|
ExternalOp = 0x15,
|
||||||
|
// 0x16 - 0x2D
|
||||||
|
DualNamePrefix = 0x2E,
|
||||||
|
MultiNamePrefix = 0x2F,
|
||||||
|
// 0x30 - 0x39 DigitChar
|
||||||
|
// 0x3A - 0x40
|
||||||
|
// 0x41 - 0x5A NameChar
|
||||||
|
ExtOpPrefix = 0x5B,
|
||||||
|
RootChar = 0x5C,
|
||||||
|
// 0x5D
|
||||||
|
ParentPrefixChar = 0x5E,
|
||||||
|
// 0x5F NameChar
|
||||||
|
Local0 = 0x60,
|
||||||
|
Local1 = 0x61,
|
||||||
|
Local2 = 0x62,
|
||||||
|
Local3 = 0x63,
|
||||||
|
Local4 = 0x64,
|
||||||
|
Local5 = 0x65,
|
||||||
|
Local6 = 0x66,
|
||||||
|
Local7 = 0x67,
|
||||||
|
Arg0 = 0x68,
|
||||||
|
Arg1 = 0x69,
|
||||||
|
Arg2 = 0x6A,
|
||||||
|
Arg3 = 0x6B,
|
||||||
|
Arg4 = 0x6C,
|
||||||
|
Arg5 = 0x6D,
|
||||||
|
Arg6 = 0x6E,
|
||||||
|
// 0x6F
|
||||||
|
StoreOp = 0x70,
|
||||||
|
RefOfOp = 0x71,
|
||||||
|
AddOp = 0x72,
|
||||||
|
ConcatOp = 0x73,
|
||||||
|
SubtractOp = 0x74,
|
||||||
|
IncrementOp = 0x75,
|
||||||
|
DecrementOp = 0x76,
|
||||||
|
MultiplyOp = 0x77,
|
||||||
|
DivideOp = 0x78,
|
||||||
|
ShiftLeftOp = 0x79,
|
||||||
|
ShiftRightOp = 0x7A,
|
||||||
|
AndOp = 0x7B,
|
||||||
|
NandOp = 0x7C,
|
||||||
|
OrOp = 0x7D,
|
||||||
|
NorOp = 0x7E,
|
||||||
|
XorOp = 0x7F,
|
||||||
|
NotOp = 0x80,
|
||||||
|
FindSetLeftBitOp = 0x81,
|
||||||
|
FindSetRightBitOp = 0x82,
|
||||||
|
DerefOfOp = 0x83,
|
||||||
|
ConcatResOp = 0x84,
|
||||||
|
ModOp = 0x85,
|
||||||
|
NotifyOp = 0x86,
|
||||||
|
SizeOfOp = 0x87,
|
||||||
|
IndexOp = 0x88,
|
||||||
|
MatchOp = 0x89,
|
||||||
|
CreateDWordFieldOp = 0x8A,
|
||||||
|
CreateWordFieldOp = 0x8B,
|
||||||
|
CreateByteFieldOp = 0x8C,
|
||||||
|
CreateBitFieldOp = 0x8D,
|
||||||
|
ObjectTypeOp = 0x8E,
|
||||||
|
CreateQWordFieldOp = 0x8F,
|
||||||
|
LAndOp = 0x90,
|
||||||
|
LOrOp = 0x91,
|
||||||
|
LNotOp = 0x92,
|
||||||
|
LEqualOp = 0x93,
|
||||||
|
LGreaterOp = 0x94,
|
||||||
|
LLessOp = 0x95,
|
||||||
|
ToBufferOp = 0x96,
|
||||||
|
ToDecimalStringOp = 0x97,
|
||||||
|
ToHexStringOp = 0x98,
|
||||||
|
ToIntegerOp = 0x99,
|
||||||
|
// 0x9A - 0x9B
|
||||||
|
ToStringOp = 0x9C,
|
||||||
|
CopyObjectOp = 0x9D,
|
||||||
|
MidOp = 0x9E,
|
||||||
|
ContinueOp = 0x9F,
|
||||||
|
IfOp = 0xA0,
|
||||||
|
ElseOp = 0xA1,
|
||||||
|
WhileOp = 0xA2,
|
||||||
|
NoopOp = 0xA3,
|
||||||
|
ReturnOp = 0xA4,
|
||||||
|
BreakOp = 0xA5,
|
||||||
|
// 0xA6 - 0xCB
|
||||||
|
BreakPointOp = 0xCC,
|
||||||
|
// 0xCD - 0xFE
|
||||||
|
OnesOp = 0xFF,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class ExtOp
|
||||||
|
{
|
||||||
|
MutexOp = 0x01,
|
||||||
|
EventOp = 0x02,
|
||||||
|
CondRefOfOp = 0x12,
|
||||||
|
CreateFieldOp = 0x13,
|
||||||
|
LoadTableOp = 0x1F,
|
||||||
|
LoadOp = 0x20,
|
||||||
|
StallOp = 0x21,
|
||||||
|
SleepOp = 0x22,
|
||||||
|
AcquireOp = 0x23,
|
||||||
|
SignalOp = 0x24,
|
||||||
|
WaitOp = 0x25,
|
||||||
|
ResetOp = 0x26,
|
||||||
|
ReleaseOp = 0x27,
|
||||||
|
FromBCDOp = 0x28,
|
||||||
|
ToBCDOp = 0x29,
|
||||||
|
RevisionOp = 0x30,
|
||||||
|
DebugOp = 0x31,
|
||||||
|
FatalOp = 0x32,
|
||||||
|
TimerOp = 0x33,
|
||||||
|
OpRegionOp = 0x80,
|
||||||
|
FieldOp = 0x81,
|
||||||
|
DeviceOp = 0x82,
|
||||||
|
ProcessorOp = 0x83,
|
||||||
|
PowerResOp = 0x84,
|
||||||
|
ThermalZoneOp = 0x85,
|
||||||
|
IndexFieldOp = 0x86,
|
||||||
|
BankFieldOp = 0x87,
|
||||||
|
DataRegionOp = 0x88,
|
||||||
|
};
|
||||||
|
|
||||||
|
inline constexpr bool is_digit_char(uint8_t ch)
|
||||||
|
{
|
||||||
|
return '0' <= ch && ch <= '9';
|
||||||
|
}
|
||||||
|
|
||||||
|
inline constexpr bool is_lead_name_char(uint8_t ch)
|
||||||
|
{
|
||||||
|
return ('A' <= ch && ch <= 'Z') || ch == '_';
|
||||||
|
}
|
||||||
|
|
||||||
|
inline constexpr bool is_name_char(uint8_t ch)
|
||||||
|
{
|
||||||
|
return is_lead_name_char(ch) || is_digit_char(ch);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline constexpr bool is_name_string_start(uint8_t ch)
|
||||||
|
{
|
||||||
|
if (is_lead_name_char(ch))
|
||||||
|
return true;
|
||||||
|
switch (static_cast<AML::Byte>(ch))
|
||||||
|
{
|
||||||
|
case AML::Byte::RootChar:
|
||||||
|
case AML::Byte::ParentPrefixChar:
|
||||||
|
case AML::Byte::MultiNamePrefix:
|
||||||
|
case AML::Byte::DualNamePrefix:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
74
kernel/include/kernel/ACPI/AML/Namespace.h
Normal file
74
kernel/include/kernel/ACPI/AML/Namespace.h
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <BAN/Bitcast.h>
|
||||||
|
#include <BAN/ByteSpan.h>
|
||||||
|
#include <BAN/Function.h>
|
||||||
|
#include <BAN/HashMap.h>
|
||||||
|
#include <BAN/HashSet.h>
|
||||||
|
#include <BAN/Iteration.h>
|
||||||
|
|
||||||
|
#include <kernel/ACPI/AML/Node.h>
|
||||||
|
|
||||||
|
namespace Kernel::ACPI::AML
|
||||||
|
{
|
||||||
|
|
||||||
|
struct Namespace
|
||||||
|
{
|
||||||
|
BAN_NON_COPYABLE(Namespace);
|
||||||
|
BAN_NON_MOVABLE(Namespace);
|
||||||
|
public:
|
||||||
|
Namespace() = default;
|
||||||
|
~Namespace();
|
||||||
|
|
||||||
|
static BAN::ErrorOr<void> prepare_root_namespace();
|
||||||
|
static Namespace& root_namespace();
|
||||||
|
|
||||||
|
BAN::ErrorOr<void> post_load_initialize();
|
||||||
|
|
||||||
|
BAN::ErrorOr<void> parse(BAN::ConstByteSpan);
|
||||||
|
|
||||||
|
BAN::ErrorOr<Node> evaluate(BAN::StringView path) { return evaluate(Scope {}, path); }
|
||||||
|
BAN::ErrorOr<Node> evaluate(const Scope& scope, BAN::StringView);
|
||||||
|
|
||||||
|
// returns empty scope if object already exited
|
||||||
|
BAN::ErrorOr<Scope> add_named_object(ParseContext& context, const NameString& name_string, Node&& node);
|
||||||
|
BAN::ErrorOr<Scope> add_alias(ParseContext& scope, const NameString& name_string, Reference* reference);
|
||||||
|
|
||||||
|
BAN::ErrorOr<void> remove_named_object(const Scope& absolute_path);
|
||||||
|
|
||||||
|
// node is nullptr if it is not found
|
||||||
|
struct FindResult
|
||||||
|
{
|
||||||
|
Scope path;
|
||||||
|
Reference* node { nullptr };
|
||||||
|
};
|
||||||
|
BAN::ErrorOr<FindResult> find_named_object(const Scope& scope, const NameString& name_string, bool force_absolute = false);
|
||||||
|
|
||||||
|
BAN::ErrorOr<Scope> find_reference_scope(const Reference* reference);
|
||||||
|
|
||||||
|
BAN::ErrorOr<void> for_each_child(const Scope&, const BAN::Function<BAN::Iteration(BAN::StringView, Reference*)>&);
|
||||||
|
BAN::ErrorOr<void> for_each_child(const Scope&, const BAN::Function<BAN::Iteration(const Scope&, Reference*)>&);
|
||||||
|
|
||||||
|
BAN::ErrorOr<BAN::Vector<Scope>> find_device_with_eisa_id(BAN::StringView eisa_id);
|
||||||
|
BAN::ErrorOr<BAN::Vector<Scope>> find_device_with_eisa_id(BAN::Span<BAN::StringView> eisa_ids);
|
||||||
|
|
||||||
|
private:
|
||||||
|
BAN::ErrorOr<Scope> resolve_path(const Scope& scope, const NameString& name_string);
|
||||||
|
|
||||||
|
BAN::ErrorOr<void> initialize_scope(const Scope& scope);
|
||||||
|
|
||||||
|
BAN::ErrorOr<void> opregion_call_reg(const Scope& scope, const Node& opregion);
|
||||||
|
|
||||||
|
BAN::ErrorOr<uint64_t> evaluate_sta(const Scope& scope);
|
||||||
|
BAN::ErrorOr<void> evaluate_ini(const Scope& scope);
|
||||||
|
|
||||||
|
BAN::ErrorOr<void> initialize_op_regions();
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool m_has_initialized_namespace { false };
|
||||||
|
BAN::HashMap<Scope, Reference*> m_named_objects;
|
||||||
|
BAN::HashMap<Scope, uint32_t> m_called_reg_bitmaps;
|
||||||
|
BAN::HashSet<Scope> m_aliases;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
449
kernel/include/kernel/ACPI/AML/Node.h
Normal file
449
kernel/include/kernel/ACPI/AML/Node.h
Normal file
@@ -0,0 +1,449 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <BAN/Array.h>
|
||||||
|
#include <BAN/ByteSpan.h>
|
||||||
|
#include <BAN/LinkedList.h>
|
||||||
|
#include <BAN/NoCopyMove.h>
|
||||||
|
#include <BAN/Optional.h>
|
||||||
|
#include <BAN/StringView.h>
|
||||||
|
#include <BAN/Vector.h>
|
||||||
|
|
||||||
|
#include <kernel/ACPI/AML/Scope.h>
|
||||||
|
#include <kernel/ACPI/Headers.h>
|
||||||
|
#include <kernel/Lock/Mutex.h>
|
||||||
|
|
||||||
|
#define AML_DUMP_FUNCTION_CALLS 0
|
||||||
|
#define AML_ENABLE_DEBUG 1
|
||||||
|
|
||||||
|
namespace Kernel::ACPI::AML
|
||||||
|
{
|
||||||
|
|
||||||
|
struct NameString
|
||||||
|
{
|
||||||
|
BAN_NON_COPYABLE(NameString);
|
||||||
|
public:
|
||||||
|
NameString() = default;
|
||||||
|
NameString(NameString&& other)
|
||||||
|
: base(other.base)
|
||||||
|
, parts(BAN::move(other.parts))
|
||||||
|
{}
|
||||||
|
NameString& operator=(NameString&& other)
|
||||||
|
{
|
||||||
|
base = other.base;
|
||||||
|
parts = BAN::move(other.parts);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
static BAN::ErrorOr<NameString> from_string(BAN::StringView name);
|
||||||
|
|
||||||
|
BAN::ErrorOr<NameString> copy() const
|
||||||
|
{
|
||||||
|
NameString result;
|
||||||
|
result.base = this->base;
|
||||||
|
|
||||||
|
TRY(result.parts.resize(parts.size()));
|
||||||
|
for (size_t i = 0; i < parts.size(); i++)
|
||||||
|
result.parts[i] = parts[i];
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr uint32_t base_root = -1;
|
||||||
|
uint32_t base { 0 };
|
||||||
|
BAN::Vector<uint32_t> parts;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T1, typename T2>
|
||||||
|
struct Pair
|
||||||
|
{
|
||||||
|
T1 elem1;
|
||||||
|
T2 elem2;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Node;
|
||||||
|
struct ParseContext;
|
||||||
|
struct Reference;
|
||||||
|
|
||||||
|
struct Mutex
|
||||||
|
{
|
||||||
|
Kernel::Mutex mutex;
|
||||||
|
uint8_t sync_level;
|
||||||
|
bool global_lock;
|
||||||
|
uint32_t ref_count;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Buffer
|
||||||
|
{
|
||||||
|
BAN::StringView as_sv() const
|
||||||
|
{
|
||||||
|
return BAN::StringView(reinterpret_cast<const char*>(bytes), size);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t size;
|
||||||
|
uint32_t ref_count;
|
||||||
|
uint8_t bytes[];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct OpRegion
|
||||||
|
{
|
||||||
|
GAS::AddressSpaceID address_space;
|
||||||
|
uint64_t offset;
|
||||||
|
uint64_t length;
|
||||||
|
alignas(Scope) uint8_t scope_storage[sizeof(Scope)];
|
||||||
|
Scope& scope() { return *reinterpret_cast<Scope*>(scope_storage); }
|
||||||
|
const Scope& scope() const { return *reinterpret_cast<const Scope*>(scope_storage); }
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FieldUnit
|
||||||
|
{
|
||||||
|
enum class Type {
|
||||||
|
Field,
|
||||||
|
IndexField,
|
||||||
|
BankField,
|
||||||
|
};
|
||||||
|
uint64_t offset;
|
||||||
|
uint64_t length;
|
||||||
|
uint8_t flags;
|
||||||
|
Type type;
|
||||||
|
|
||||||
|
union {
|
||||||
|
struct {
|
||||||
|
OpRegion opregion;
|
||||||
|
} field;
|
||||||
|
struct {
|
||||||
|
Reference* index;
|
||||||
|
Reference* data;
|
||||||
|
} index_field;
|
||||||
|
struct {
|
||||||
|
OpRegion opregion;
|
||||||
|
Reference* bank_selector;
|
||||||
|
uint64_t bank_value;
|
||||||
|
} bank_field;
|
||||||
|
} as;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Package
|
||||||
|
{
|
||||||
|
struct Element
|
||||||
|
{
|
||||||
|
struct Location {
|
||||||
|
NameString name;
|
||||||
|
Scope scope;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool resolved { true };
|
||||||
|
union {
|
||||||
|
Node* node { nullptr };
|
||||||
|
Location* location;
|
||||||
|
} value;
|
||||||
|
};
|
||||||
|
|
||||||
|
uint64_t num_elements;
|
||||||
|
uint32_t ref_count;
|
||||||
|
Element elements[];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Node
|
||||||
|
{
|
||||||
|
BAN_NON_COPYABLE(Node);
|
||||||
|
public:
|
||||||
|
Node() = default;
|
||||||
|
~Node() { clear(); }
|
||||||
|
|
||||||
|
Node(Node&& other) { *this = BAN::move(other); }
|
||||||
|
Node& operator=(Node&&);
|
||||||
|
|
||||||
|
static BAN::ErrorOr<Node> create_string(BAN::StringView string)
|
||||||
|
{
|
||||||
|
const auto* u8_data = reinterpret_cast<const uint8_t*>(string.data());
|
||||||
|
auto result = TRY(create_buffer({ u8_data, string.size() }));
|
||||||
|
result.type = Node::Type::String;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static BAN::ErrorOr<Node> create_buffer(BAN::ConstByteSpan buffer)
|
||||||
|
{
|
||||||
|
Node node;
|
||||||
|
node.type = Node::Type::Buffer;
|
||||||
|
node.as.str_buf = static_cast<Buffer*>(kmalloc(sizeof(Buffer) + buffer.size()));
|
||||||
|
if (node.as.str_buf == nullptr)
|
||||||
|
return BAN::Error::from_errno(ENOMEM);
|
||||||
|
node.as.str_buf->ref_count = 1;
|
||||||
|
node.as.str_buf->size = buffer.size();
|
||||||
|
memcpy(node.as.str_buf->bytes, buffer.data(), buffer.size());
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class Type
|
||||||
|
{
|
||||||
|
Uninitialized,
|
||||||
|
Debug,
|
||||||
|
Integer,
|
||||||
|
String,
|
||||||
|
Buffer,
|
||||||
|
Package,
|
||||||
|
BufferField,
|
||||||
|
OpRegion,
|
||||||
|
FieldUnit,
|
||||||
|
Event,
|
||||||
|
Device,
|
||||||
|
Processor,
|
||||||
|
PowerResource,
|
||||||
|
ThermalZone,
|
||||||
|
Method,
|
||||||
|
Mutex,
|
||||||
|
// FIXME: Index should not be its own type
|
||||||
|
// parsing index should return references
|
||||||
|
Index,
|
||||||
|
Reference,
|
||||||
|
PredefinedScope,
|
||||||
|
Count
|
||||||
|
} type { Type::Uninitialized };
|
||||||
|
|
||||||
|
inline bool is_scope() const
|
||||||
|
{
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case Type::Device:
|
||||||
|
case Type::Processor:
|
||||||
|
case Type::PowerResource:
|
||||||
|
case Type::ThermalZone:
|
||||||
|
case Type::PredefinedScope:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
ASSERT_NOT_REACHED();
|
||||||
|
}
|
||||||
|
|
||||||
|
union
|
||||||
|
{
|
||||||
|
struct {
|
||||||
|
uint64_t value;
|
||||||
|
} integer;
|
||||||
|
Package* package;
|
||||||
|
Buffer* str_buf;
|
||||||
|
struct {
|
||||||
|
Buffer* buffer;
|
||||||
|
uint64_t bit_offset;
|
||||||
|
uint64_t bit_count;
|
||||||
|
} buffer_field;
|
||||||
|
OpRegion opregion;
|
||||||
|
FieldUnit field_unit;
|
||||||
|
struct {
|
||||||
|
uint32_t signal_count;
|
||||||
|
} event;
|
||||||
|
struct {
|
||||||
|
uint8_t storage[sizeof(Kernel::Mutex)];
|
||||||
|
const uint8_t* start;
|
||||||
|
size_t length;
|
||||||
|
uint8_t arg_count;
|
||||||
|
BAN::ErrorOr<Node> (*override_func)(const BAN::Array<Reference*, 7>&);
|
||||||
|
bool serialized;
|
||||||
|
Mutex* mutex;
|
||||||
|
} method;
|
||||||
|
Mutex* mutex;
|
||||||
|
struct {
|
||||||
|
Node::Type type;
|
||||||
|
union {
|
||||||
|
Buffer* str_buf;
|
||||||
|
Package* package;
|
||||||
|
} as;
|
||||||
|
uint64_t index;
|
||||||
|
} index;
|
||||||
|
Reference* reference;
|
||||||
|
} as;
|
||||||
|
|
||||||
|
BAN::ErrorOr<Node> copy() const;
|
||||||
|
|
||||||
|
void clear();
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Reference
|
||||||
|
{
|
||||||
|
Node node {};
|
||||||
|
uint32_t ref_count { 1 };
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ParseContext
|
||||||
|
{
|
||||||
|
Scope scope;
|
||||||
|
BAN::ConstByteSpan aml_data;
|
||||||
|
|
||||||
|
uint32_t call_depth { 0 };
|
||||||
|
BAN::Array<Reference*, 8> locals;
|
||||||
|
BAN::Array<Reference*, 7> args;
|
||||||
|
|
||||||
|
BAN::LinkedList<Scope> created_nodes;
|
||||||
|
|
||||||
|
~ParseContext();
|
||||||
|
BAN::ErrorOr<void> allocate_locals();
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class ExecutionFlow
|
||||||
|
{
|
||||||
|
Normal,
|
||||||
|
Break,
|
||||||
|
Continue,
|
||||||
|
Return,
|
||||||
|
};
|
||||||
|
using ExecutionFlowResult = Pair<ExecutionFlow, BAN::Optional<Node>>;
|
||||||
|
|
||||||
|
enum Conversion : uint8_t
|
||||||
|
{
|
||||||
|
ConvInteger = 1,
|
||||||
|
ConvBuffer = 2,
|
||||||
|
ConvString = 4,
|
||||||
|
};
|
||||||
|
|
||||||
|
BAN::ErrorOr<Node> parse_node(ParseContext& context, bool return_ref = false);
|
||||||
|
BAN::ErrorOr<ExecutionFlowResult> parse_node_or_execution_flow(ParseContext& context);
|
||||||
|
|
||||||
|
BAN::ErrorOr<NameString> parse_name_string(BAN::ConstByteSpan& aml_data);
|
||||||
|
BAN::ErrorOr<BAN::ConstByteSpan> parse_pkg(BAN::ConstByteSpan& aml_data);
|
||||||
|
|
||||||
|
BAN::ErrorOr<Node> convert_node(Node&& source, uint8_t conversion, uint64_t max_length);
|
||||||
|
BAN::ErrorOr<Node> convert_node(Node&& source, const Node& target);
|
||||||
|
|
||||||
|
BAN::ErrorOr<Node> evaluate_node(const Scope& node_path, const Node& node);
|
||||||
|
|
||||||
|
// If method has no return, it will return <integer 0>
|
||||||
|
BAN::ErrorOr<Node> method_call(const Scope& scope, const Node& method, BAN::Array<Reference*, 7>&& args, uint32_t call_depth = 0);
|
||||||
|
BAN::ErrorOr<Node> method_call(const Scope& scope, const Node& method,
|
||||||
|
Node&& arg0 = {}, Node&& arg1 = {}, Node&& arg2 = {}, Node&& arg3 = {}, Node&& arg4 = {}, Node&& arg5 = {}, Node&& arg6 = {});
|
||||||
|
|
||||||
|
BAN::ErrorOr<void> resolve_package_element(Package::Element& element, bool error_if_not_exists);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace BAN::Formatter
|
||||||
|
{
|
||||||
|
|
||||||
|
template<typename F>
|
||||||
|
void print_argument(F putc, const Kernel::ACPI::AML::NameString& name_string, const ValueFormat&)
|
||||||
|
{
|
||||||
|
if (name_string.base == Kernel::ACPI::AML::NameString::base_root)
|
||||||
|
putc('\\');
|
||||||
|
else for (uint32_t i = 0; i < name_string.base; i++)
|
||||||
|
putc('^');
|
||||||
|
for (size_t i = 0; i < name_string.parts.size(); i++) {
|
||||||
|
if (i != 0)
|
||||||
|
putc('.');
|
||||||
|
const char* name_seg = reinterpret_cast<const char*>(&name_string.parts[i]);
|
||||||
|
putc(name_seg[0]); putc(name_seg[1]); putc(name_seg[2]); putc(name_seg[3]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename F>
|
||||||
|
void print_argument(F putc, const Kernel::ACPI::AML::Buffer& buffer, const ValueFormat&)
|
||||||
|
{
|
||||||
|
static constexpr size_t max_elements { 16 };
|
||||||
|
|
||||||
|
print(putc, "<buffer '");
|
||||||
|
if (buffer.size)
|
||||||
|
print(putc, "{2H}", buffer.bytes[0]);
|
||||||
|
for (size_t i = 1; i < buffer.size && i < max_elements; i++)
|
||||||
|
print(putc, " {2H}", buffer.bytes[i]);
|
||||||
|
if (buffer.size > max_elements)
|
||||||
|
print(putc, "...");
|
||||||
|
print(putc, "'>");
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename F>
|
||||||
|
void print_argument(F putc, const Kernel::ACPI::AML::Package& package, const ValueFormat&)
|
||||||
|
{
|
||||||
|
print(putc, "<package '{} elements'>", package.num_elements);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename F>
|
||||||
|
void print_argument(F putc, const Kernel::ACPI::AML::Node& node, const ValueFormat&)
|
||||||
|
{
|
||||||
|
switch (node.type)
|
||||||
|
{
|
||||||
|
case Kernel::ACPI::AML::Node::Type::Uninitialized:
|
||||||
|
print(putc, "<uninitialized>");
|
||||||
|
break;
|
||||||
|
case Kernel::ACPI::AML::Node::Type::Debug:
|
||||||
|
print(putc, "<debug>");
|
||||||
|
break;
|
||||||
|
case Kernel::ACPI::AML::Node::Type::Integer:
|
||||||
|
print(putc, "<integer 0x{H}>", node.as.integer.value);
|
||||||
|
break;
|
||||||
|
case Kernel::ACPI::AML::Node::Type::String:
|
||||||
|
print(putc, "<string '{}'>", node.as.str_buf->as_sv());
|
||||||
|
break;
|
||||||
|
case Kernel::ACPI::AML::Node::Type::Package:
|
||||||
|
print(putc, "{}", *node.as.package);
|
||||||
|
break;
|
||||||
|
case Kernel::ACPI::AML::Node::Type::Buffer:
|
||||||
|
print(putc, "{}", *node.as.str_buf);
|
||||||
|
break;
|
||||||
|
case Kernel::ACPI::AML::Node::Type::BufferField:
|
||||||
|
print(putc, "<buffer field '{} bytes, offset 0x{H}, bit count {}'>",
|
||||||
|
node.as.buffer_field.buffer->size,
|
||||||
|
node.as.buffer_field.bit_offset,
|
||||||
|
node.as.buffer_field.bit_count
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
case Kernel::ACPI::AML::Node::Type::OpRegion:
|
||||||
|
print(putc, "<opregion 'type {2H}, offset 0x{H}, length 0x{H}'>",
|
||||||
|
static_cast<uint8_t>(node.as.opregion.address_space),
|
||||||
|
node.as.opregion.offset,
|
||||||
|
node.as.opregion.length
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
case Kernel::ACPI::AML::Node::Type::FieldUnit:
|
||||||
|
print(putc, "<field unit ({}), 'offset 0x{H}, length 0x{H}'>",
|
||||||
|
static_cast<uint8_t>(node.as.field_unit.type),
|
||||||
|
node.as.field_unit.offset,
|
||||||
|
node.as.field_unit.length
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
case Kernel::ACPI::AML::Node::Type::Event:
|
||||||
|
print(putc, "<event '{} signals'>", node.as.event.signal_count);
|
||||||
|
break;
|
||||||
|
case Kernel::ACPI::AML::Node::Type::Device:
|
||||||
|
print(putc, "<device>");
|
||||||
|
break;
|
||||||
|
case Kernel::ACPI::AML::Node::Type::Processor:
|
||||||
|
print(putc, "<processor>");
|
||||||
|
break;
|
||||||
|
case Kernel::ACPI::AML::Node::Type::PowerResource:
|
||||||
|
print(putc, "<power resouce>");
|
||||||
|
break;
|
||||||
|
case Kernel::ACPI::AML::Node::Type::ThermalZone:
|
||||||
|
print(putc, "<thermal zone>");
|
||||||
|
break;
|
||||||
|
case Kernel::ACPI::AML::Node::Type::Method:
|
||||||
|
print(putc, "<method '{} bytes'>", node.as.method.length);
|
||||||
|
break;
|
||||||
|
case Kernel::ACPI::AML::Node::Type::Mutex:
|
||||||
|
print(putc, "<mutex>");
|
||||||
|
break;
|
||||||
|
case Kernel::ACPI::AML::Node::Type::Index:
|
||||||
|
switch (node.as.index.type)
|
||||||
|
{
|
||||||
|
case Kernel::ACPI::AML::Node::Type::String:
|
||||||
|
case Kernel::ACPI::AML::Node::Type::Buffer:
|
||||||
|
print(putc, "<index {}, {}>", *node.as.index.as.str_buf, node.as.index.index);
|
||||||
|
break;
|
||||||
|
case Kernel::ACPI::AML::Node::Type::Package:
|
||||||
|
print(putc, "<index {}, {}>", *node.as.index.as.package, node.as.index.index);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
print(putc, "<index {}??, {}>", (uint32_t)node.as.index.type, node.as.index.index);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Kernel::ACPI::AML::Node::Type::Reference:
|
||||||
|
print(putc, "<reference {}, {} refs>", node.as.reference->node, node.as.reference->ref_count);
|
||||||
|
break;
|
||||||
|
case Kernel::ACPI::AML::Node::Type::PredefinedScope:
|
||||||
|
print(putc, "<scope>");
|
||||||
|
break;
|
||||||
|
case Kernel::ACPI::AML::Node::Type::Count:
|
||||||
|
ASSERT_NOT_REACHED();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
16
kernel/include/kernel/ACPI/AML/OpRegion.h
Normal file
16
kernel/include/kernel/ACPI/AML/OpRegion.h
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <kernel/ACPI/AML/Node.h>
|
||||||
|
|
||||||
|
namespace Kernel::ACPI::AML
|
||||||
|
{
|
||||||
|
|
||||||
|
BAN::ErrorOr<void> parse_opregion_op(ParseContext& context);
|
||||||
|
BAN::ErrorOr<void> parse_field_op(ParseContext& context);
|
||||||
|
BAN::ErrorOr<void> parse_index_field_op(ParseContext& context);
|
||||||
|
BAN::ErrorOr<void> parse_bank_field_op(ParseContext& context);
|
||||||
|
|
||||||
|
BAN::ErrorOr<Node> convert_from_field_unit(const Node& node, uint8_t conversion, uint64_t max_length);
|
||||||
|
BAN::ErrorOr<void> store_to_field_unit(const Node& source, const Node& target);
|
||||||
|
|
||||||
|
}
|
||||||
74
kernel/include/kernel/ACPI/AML/Scope.h
Normal file
74
kernel/include/kernel/ACPI/AML/Scope.h
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <BAN/Hash.h>
|
||||||
|
#include <BAN/NoCopyMove.h>
|
||||||
|
#include <BAN/Vector.h>
|
||||||
|
|
||||||
|
namespace Kernel::ACPI::AML
|
||||||
|
{
|
||||||
|
|
||||||
|
struct Scope
|
||||||
|
{
|
||||||
|
BAN_NON_COPYABLE(Scope);
|
||||||
|
public:
|
||||||
|
Scope() = default;
|
||||||
|
Scope(Scope&& other) { *this = BAN::move(other); }
|
||||||
|
Scope& operator=(Scope&& other) { parts = BAN::move(other.parts); return *this; }
|
||||||
|
|
||||||
|
BAN::Vector<uint32_t> parts;
|
||||||
|
|
||||||
|
BAN::ErrorOr<Scope> copy() const
|
||||||
|
{
|
||||||
|
Scope result;
|
||||||
|
TRY(result.parts.reserve(parts.size()));
|
||||||
|
for (uint32_t part : parts)
|
||||||
|
TRY(result.parts.push_back(part));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(const Scope& other) const
|
||||||
|
{
|
||||||
|
if (parts.size() != other.parts.size())
|
||||||
|
return false;
|
||||||
|
for (size_t i = 0; i < parts.size(); i++)
|
||||||
|
if (parts[i] != other.parts[i])
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace BAN
|
||||||
|
{
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct hash<Kernel::ACPI::AML::Scope>
|
||||||
|
{
|
||||||
|
hash_t operator()(const Kernel::ACPI::AML::Scope& scope) const
|
||||||
|
{
|
||||||
|
hash_t hash { 0 };
|
||||||
|
for (uint32_t part : scope.parts)
|
||||||
|
hash ^= u32_hash(part);
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace BAN::Formatter
|
||||||
|
{
|
||||||
|
|
||||||
|
template<typename F>
|
||||||
|
void print_argument(F putc, const Kernel::ACPI::AML::Scope& scope, const ValueFormat&)
|
||||||
|
{
|
||||||
|
putc('\\');
|
||||||
|
for (size_t i = 0; i < scope.parts.size(); i++) {
|
||||||
|
if (i != 0)
|
||||||
|
putc('.');
|
||||||
|
const char* name_seg = reinterpret_cast<const char*>(&scope.parts[i]);
|
||||||
|
putc(name_seg[0]); putc(name_seg[1]); putc(name_seg[2]); putc(name_seg[3]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
26
kernel/include/kernel/ACPI/BatterySystem.h
Normal file
26
kernel/include/kernel/ACPI/BatterySystem.h
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <kernel/ACPI/AML/Namespace.h>
|
||||||
|
#include <kernel/FS/TmpFS/Inode.h>
|
||||||
|
|
||||||
|
namespace Kernel::ACPI
|
||||||
|
{
|
||||||
|
|
||||||
|
class BatterySystem
|
||||||
|
{
|
||||||
|
BAN_NON_COPYABLE(BatterySystem);
|
||||||
|
BAN_NON_MOVABLE(BatterySystem);
|
||||||
|
public:
|
||||||
|
static BAN::ErrorOr<void> initialize(AML::Namespace& acpi_namespace);
|
||||||
|
|
||||||
|
private:
|
||||||
|
BatterySystem(AML::Namespace&);
|
||||||
|
|
||||||
|
BAN::ErrorOr<void> initialize_impl();
|
||||||
|
|
||||||
|
private:
|
||||||
|
AML::Namespace& m_acpi_namespace;
|
||||||
|
BAN::RefPtr<TmpDirectoryInode> m_directory;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
69
kernel/include/kernel/ACPI/EmbeddedController.h
Normal file
69
kernel/include/kernel/ACPI/EmbeddedController.h
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <BAN/Atomic.h>
|
||||||
|
#include <BAN/UniqPtr.h>
|
||||||
|
|
||||||
|
#include <kernel/ACPI/AML/Scope.h>
|
||||||
|
#include <kernel/Lock/Mutex.h>
|
||||||
|
#include <kernel/Thread.h>
|
||||||
|
|
||||||
|
namespace Kernel::ACPI
|
||||||
|
{
|
||||||
|
|
||||||
|
class EmbeddedController
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static BAN::ErrorOr<BAN::UniqPtr<EmbeddedController>> create(AML::Scope&& scope, uint16_t command_port, uint16_t data_port, BAN::Optional<uint8_t> gpe);
|
||||||
|
~EmbeddedController();
|
||||||
|
|
||||||
|
BAN::ErrorOr<uint8_t> read_byte(uint8_t offset);
|
||||||
|
BAN::ErrorOr<void> write_byte(uint8_t offset, uint8_t value);
|
||||||
|
|
||||||
|
const AML::Scope& scope() const { return m_scope; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
EmbeddedController(AML::Scope&& scope, uint16_t command_port, uint16_t data_port, bool has_gpe)
|
||||||
|
: m_scope(BAN::move(scope))
|
||||||
|
, m_command_port(command_port)
|
||||||
|
, m_data_port(data_port)
|
||||||
|
, m_has_gpe(has_gpe)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
private:
|
||||||
|
void wait_status_bit(uint8_t bit, uint8_t value);
|
||||||
|
|
||||||
|
uint8_t read_one(uint16_t port);
|
||||||
|
void write_one(uint16_t port, uint8_t value);
|
||||||
|
|
||||||
|
static void handle_gpe_wrapper(void*);
|
||||||
|
void handle_gpe();
|
||||||
|
|
||||||
|
BAN::ErrorOr<void> call_query_method(uint8_t notification);
|
||||||
|
|
||||||
|
void thread_task();
|
||||||
|
|
||||||
|
struct Command
|
||||||
|
{
|
||||||
|
uint8_t command;
|
||||||
|
BAN::Optional<uint8_t> data1;
|
||||||
|
BAN::Optional<uint8_t> data2;
|
||||||
|
uint8_t* response;
|
||||||
|
BAN::Atomic<bool> done;
|
||||||
|
};
|
||||||
|
BAN::ErrorOr<void> send_command(Command& command);
|
||||||
|
|
||||||
|
private:
|
||||||
|
const AML::Scope m_scope;
|
||||||
|
const uint16_t m_command_port;
|
||||||
|
const uint16_t m_data_port;
|
||||||
|
const bool m_has_gpe;
|
||||||
|
|
||||||
|
Mutex m_mutex;
|
||||||
|
ThreadBlocker m_thread_blocker;
|
||||||
|
|
||||||
|
BAN::Optional<Command*> m_queued_command;
|
||||||
|
|
||||||
|
Thread* m_thread { nullptr };
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
151
kernel/include/kernel/ACPI/Headers.h
Normal file
151
kernel/include/kernel/ACPI/Headers.h
Normal file
@@ -0,0 +1,151 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <BAN/Errors.h>
|
||||||
|
#include <BAN/Optional.h>
|
||||||
|
|
||||||
|
namespace Kernel::ACPI
|
||||||
|
{
|
||||||
|
|
||||||
|
struct GAS
|
||||||
|
{
|
||||||
|
enum class AddressSpaceID : uint8_t
|
||||||
|
{
|
||||||
|
SystemMemory = 0x00,
|
||||||
|
SystemIO = 0x01,
|
||||||
|
PCIConfig = 0x02,
|
||||||
|
EmbeddedController = 0x03,
|
||||||
|
SMBus = 0x04,
|
||||||
|
SystemCMOS = 0x05,
|
||||||
|
PCIBarTarget = 0x06,
|
||||||
|
IPMI = 0x07,
|
||||||
|
GeneralPurposeIO = 0x08,
|
||||||
|
GenericSerialBus = 0x09,
|
||||||
|
PlatformCommunicationChannel = 0x0A,
|
||||||
|
};
|
||||||
|
|
||||||
|
BAN::ErrorOr<uint64_t> read();
|
||||||
|
BAN::ErrorOr<void> write(uint64_t value);
|
||||||
|
|
||||||
|
AddressSpaceID address_space_id;
|
||||||
|
uint8_t register_bit_width;
|
||||||
|
uint8_t register_bit_offset;
|
||||||
|
uint8_t access_size;
|
||||||
|
uint64_t address;
|
||||||
|
} __attribute__((packed));
|
||||||
|
static_assert(sizeof(GAS) == 12);
|
||||||
|
|
||||||
|
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;
|
||||||
|
GAS reset_reg;
|
||||||
|
uint8_t reset_value;
|
||||||
|
uint16_t arm_boot_arch;
|
||||||
|
uint8_t fadt_minor_version;
|
||||||
|
uint64_t x_firmware_ctrl;
|
||||||
|
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));
|
||||||
|
|
||||||
|
struct FACS
|
||||||
|
{
|
||||||
|
uint8_t signature[4];
|
||||||
|
uint32_t length;
|
||||||
|
uint32_t hardware_signature;
|
||||||
|
uint32_t firmware_waking_vector;
|
||||||
|
uint32_t global_lock;
|
||||||
|
uint32_t flags;
|
||||||
|
uint64_t x_firmware_waking_vector;
|
||||||
|
uint8_t version;
|
||||||
|
uint8_t reserved[3];
|
||||||
|
uint32_t ospm_flags;
|
||||||
|
uint8_t reserved2[24];
|
||||||
|
};
|
||||||
|
static_assert(sizeof(FACS) == 64);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace BAN::Formatter
|
||||||
|
{
|
||||||
|
template<typename F>
|
||||||
|
void print_argument(F putc, const Kernel::ACPI::SDTHeader& header, const struct ValueFormat&)
|
||||||
|
{
|
||||||
|
putc(header.signature[0]);
|
||||||
|
putc(header.signature[1]);
|
||||||
|
putc(header.signature[2]);
|
||||||
|
putc(header.signature[3]);
|
||||||
|
}
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user