Compare commits
1911 Commits
5050047cef
...
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 |
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 { \
|
||||||
|
flockfile(stddbg); \
|
||||||
BAN::Formatter::print(__debug_putchar, "\e[33m"); \
|
BAN::Formatter::print(__debug_putchar, "\e[33m"); \
|
||||||
dprintln(__VA_ARGS__); \
|
BAN::Formatter::print(__debug_putchar, __VA_ARGS__); \
|
||||||
BAN::Formatter::print(__debug_putchar, "\e[m"); \
|
BAN::Formatter::print(__debug_putchar, "\e[m\n"); \
|
||||||
|
fflush(stddbg); \
|
||||||
|
funlockfile(stddbg); \
|
||||||
} while(false)
|
} while(false)
|
||||||
|
|
||||||
#define derrorln(...) \
|
#define derrorln(...) \
|
||||||
do { \
|
do { \
|
||||||
|
flockfile(stddbg); \
|
||||||
BAN::Formatter::print(__debug_putchar, "\e[31m"); \
|
BAN::Formatter::print(__debug_putchar, "\e[31m"); \
|
||||||
|
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__); \
|
dprintln(__VA_ARGS__); \
|
||||||
BAN::Formatter::print(__debug_putchar, "\e[m"); \
|
} 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,11 +161,12 @@ 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(format.fill_char);
|
||||||
putc('0');
|
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,116 +14,75 @@ 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;
|
|
||||||
|
|
||||||
T* data();
|
|
||||||
const T* data() const;
|
|
||||||
|
|
||||||
bool empty() const;
|
|
||||||
size_type size() const;
|
|
||||||
|
|
||||||
void clear();
|
|
||||||
|
|
||||||
Span slice(size_type, size_type = ~size_type(0));
|
|
||||||
|
|
||||||
Span<const T> as_const() const { return Span<const T>(m_data, m_size); }
|
|
||||||
|
|
||||||
private:
|
|
||||||
T* m_data = nullptr;
|
|
||||||
size_type m_size = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
Span<T>::Span(T* data, size_type size)
|
|
||||||
: m_data(data)
|
|
||||||
, m_size(size)
|
|
||||||
{
|
{
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
Span<T>::Span(Span& other)
|
|
||||||
: m_data(other.data())
|
|
||||||
, m_size(other.size())
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
template<typename S>
|
|
||||||
requires(is_same_v<T, const S>)
|
|
||||||
Span<T>::Span(const Span<S>& other)
|
|
||||||
: m_data(other.data())
|
|
||||||
, m_size(other.size())
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
T& Span<T>::operator[](size_type index)
|
|
||||||
{
|
|
||||||
ASSERT(m_data);
|
|
||||||
ASSERT(index < m_size);
|
ASSERT(index < m_size);
|
||||||
return m_data[index];
|
return m_data[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
value_type* data() const
|
||||||
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;
|
return m_data;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
bool empty() const { return m_size == 0; }
|
||||||
const T* Span<T>::data() const
|
size_type size() const { return m_size; }
|
||||||
{
|
|
||||||
return m_data;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
void clear()
|
||||||
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_data = nullptr;
|
||||||
m_size = 0;
|
m_size = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
Span slice(size_type start, size_type length = ~size_type(0)) const
|
||||||
Span<T> Span<T>::slice(size_type start, size_type length)
|
|
||||||
{
|
{
|
||||||
ASSERT(m_data);
|
|
||||||
ASSERT(start <= m_size);
|
ASSERT(start <= m_size);
|
||||||
if (length == ~size_type(0))
|
if (length == ~size_type(0))
|
||||||
length = m_size - start;
|
length = m_size - start;
|
||||||
@@ -131,4 +90,13 @@ namespace BAN
|
|||||||
return Span(m_data + start, length);
|
return Span(m_data + start, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Span<const value_type> as_const() const { return *this; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
value_type* m_data = nullptr;
|
||||||
|
size_type m_size = 0;
|
||||||
|
|
||||||
|
friend class Span<const value_type>;
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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,6 +126,7 @@ namespace BAN
|
|||||||
Variant(Variant&& other)
|
Variant(Variant&& other)
|
||||||
: m_index(other.m_index)
|
: m_index(other.m_index)
|
||||||
{
|
{
|
||||||
|
if (other.has_value())
|
||||||
detail::move_construct<Ts...>(other.m_index, other.m_storage, m_storage);
|
detail::move_construct<Ts...>(other.m_index, other.m_storage, m_storage);
|
||||||
other.clear();
|
other.clear();
|
||||||
}
|
}
|
||||||
@@ -133,6 +134,7 @@ namespace BAN
|
|||||||
Variant(const Variant& other)
|
Variant(const Variant& other)
|
||||||
: m_index(other.m_index)
|
: m_index(other.m_index)
|
||||||
{
|
{
|
||||||
|
if (other.has_value())
|
||||||
detail::copy_construct<Ts...>(other.m_index, other.m_storage, m_storage);
|
detail::copy_construct<Ts...>(other.m_index, other.m_storage, m_storage);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -157,11 +159,12 @@ 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();
|
||||||
|
if (other.has_value())
|
||||||
detail::move_construct<Ts...>(other.m_index, other.m_storage, m_storage);
|
detail::move_construct<Ts...>(other.m_index, other.m_storage, m_storage);
|
||||||
m_index = other.m_index;
|
m_index = other.m_index;
|
||||||
}
|
}
|
||||||
@@ -171,11 +174,12 @@ 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();
|
||||||
|
if (other.has_value())
|
||||||
detail::copy_construct<Ts...>(other.m_index, other.m_storage, m_storage);
|
detail::copy_construct<Ts...>(other.m_index, other.m_storage, m_storage);
|
||||||
m_index = other.m_index;
|
m_index = other.m_index;
|
||||||
}
|
}
|
||||||
@@ -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,10 +381,35 @@ 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 constexpr (BAN::is_trivially_copyable_v<T>)
|
||||||
|
{
|
||||||
|
if constexpr (BAN::reallocator)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto* new_data = static_cast<T*>(BAN::allocator(new_cap * sizeof(T)));
|
||||||
if (new_data == nullptr)
|
if (new_data == nullptr)
|
||||||
return Error::from_errno(ENOMEM);
|
return Error::from_errno(ENOMEM);
|
||||||
for (size_type i = 0; i < m_size; i++)
|
for (size_type i = 0; i < m_size; i++)
|
||||||
@@ -381,6 +419,8 @@ namespace BAN
|
|||||||
}
|
}
|
||||||
BAN::deallocator(m_data);
|
BAN::deallocator(m_data);
|
||||||
m_data = new_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_ETC ${BANAN_SYSROOT}/usr/etc)
|
||||||
set(BANAN_SHARE ${BANAN_SYSROOT}/usr/share)
|
set(BANAN_SHARE ${BANAN_SYSROOT}/usr/share)
|
||||||
set(BANAN_BOOT ${BANAN_SYSROOT}/boot)
|
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
|
||||||
@@ -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,23 +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/GDT.cpp
|
kernel/GDT.cpp
|
||||||
kernel/IDT.cpp
|
kernel/IDT.cpp
|
||||||
kernel/Input/KeyboardLayout.cpp
|
kernel/Input/InputDevice.cpp
|
||||||
kernel/Input/KeyEvent.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
|
||||||
@@ -45,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
|
||||||
@@ -52,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
|
||||||
@@ -71,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
|
||||||
@@ -83,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)
|
||||||
@@ -112,13 +139,8 @@ if("${BANAN_ARCH}" STREQUAL "x86_64")
|
|||||||
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
|
||||||
@@ -129,6 +151,8 @@ elseif("${BANAN_ARCH}" STREQUAL "i686")
|
|||||||
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}")
|
||||||
@@ -137,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
|
||||||
)
|
)
|
||||||
@@ -145,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
|
||||||
@@ -216,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,3 +1,4 @@
|
|||||||
|
#include <kernel/BootInfo.h>
|
||||||
#include <kernel/CPUID.h>
|
#include <kernel/CPUID.h>
|
||||||
#include <kernel/Lock/SpinLock.h>
|
#include <kernel/Lock/SpinLock.h>
|
||||||
#include <kernel/Memory/kmalloc.h>
|
#include <kernel/Memory/kmalloc.h>
|
||||||
@@ -9,17 +10,26 @@ extern uint8_t g_kernel_end[];
|
|||||||
extern uint8_t g_kernel_execute_start[];
|
extern uint8_t g_kernel_execute_start[];
|
||||||
extern uint8_t g_kernel_execute_end[];
|
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_start[];
|
||||||
extern uint8_t g_userspace_end[];
|
extern uint8_t g_userspace_end[];
|
||||||
|
|
||||||
namespace Kernel
|
namespace Kernel
|
||||||
{
|
{
|
||||||
|
|
||||||
RecursiveSpinLock PageTable::s_fast_page_lock;
|
SpinLock PageTable::s_fast_page_lock;
|
||||||
|
|
||||||
|
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 PageTable* s_kernel = nullptr;
|
||||||
static bool s_has_nxe = false;
|
static bool s_has_nxe = false;
|
||||||
static bool s_has_pge = false;
|
static bool s_has_pge = false;
|
||||||
|
static bool s_has_pat = false;
|
||||||
|
|
||||||
static paddr_t s_global_pdpte = 0;
|
static paddr_t s_global_pdpte = 0;
|
||||||
|
|
||||||
@@ -32,8 +42,6 @@ namespace Kernel
|
|||||||
result |= Flags::Execute;
|
result |= Flags::Execute;
|
||||||
if (entry & Flags::Reserved)
|
if (entry & Flags::Reserved)
|
||||||
result |= Flags::Reserved;
|
result |= Flags::Reserved;
|
||||||
if (entry & Flags::CacheDisable)
|
|
||||||
result |= Flags::CacheDisable;
|
|
||||||
if (entry & Flags::UserSupervisor)
|
if (entry & Flags::UserSupervisor)
|
||||||
result |= Flags::UserSupervisor;
|
result |= Flags::UserSupervisor;
|
||||||
if (entry & Flags::ReadWrite)
|
if (entry & Flags::ReadWrite)
|
||||||
@@ -43,7 +51,7 @@ namespace Kernel
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PageTable::initialize()
|
void PageTable::initialize_pre_heap()
|
||||||
{
|
{
|
||||||
if (CPUID::has_nxe())
|
if (CPUID::has_nxe())
|
||||||
s_has_nxe = true;
|
s_has_nxe = true;
|
||||||
@@ -51,6 +59,9 @@ namespace Kernel
|
|||||||
if (CPUID::has_pge())
|
if (CPUID::has_pge())
|
||||||
s_has_pge = true;
|
s_has_pge = true;
|
||||||
|
|
||||||
|
if (CPUID::has_pat())
|
||||||
|
s_has_pat = true;
|
||||||
|
|
||||||
ASSERT(s_kernel == nullptr);
|
ASSERT(s_kernel == nullptr);
|
||||||
s_kernel = new PageTable();
|
s_kernel = new PageTable();
|
||||||
ASSERT(s_kernel);
|
ASSERT(s_kernel);
|
||||||
@@ -59,6 +70,11 @@ namespace Kernel
|
|||||||
s_kernel->initial_load();
|
s_kernel->initial_load();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PageTable::initialize_post_heap()
|
||||||
|
{
|
||||||
|
s_is_post_heap_done = true;
|
||||||
|
}
|
||||||
|
|
||||||
void PageTable::initial_load()
|
void PageTable::initial_load()
|
||||||
{
|
{
|
||||||
if (s_has_nxe)
|
if (s_has_nxe)
|
||||||
@@ -82,6 +98,17 @@ namespace Kernel
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (s_has_pat)
|
||||||
|
{
|
||||||
|
asm volatile(
|
||||||
|
"movl $0x277, %%ecx;"
|
||||||
|
"rdmsr;"
|
||||||
|
"movw $0x0401, %%dx;"
|
||||||
|
"wrmsr;"
|
||||||
|
::: "eax", "ecx", "edx", "memory"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// enable write protect
|
// enable write protect
|
||||||
asm volatile(
|
asm volatile(
|
||||||
"movl %%cr0, %%eax;"
|
"movl %%cr0, %%eax;"
|
||||||
@@ -112,39 +139,34 @@ namespace Kernel
|
|||||||
return (uint64_t*)page;
|
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(s_global_pdpte == 0);
|
ASSERT(s_global_pdpte == 0);
|
||||||
s_global_pdpte = V2P(allocate_zeroed_page_aligned_page());
|
s_global_pdpte = V2P(allocate_zeroed_page_aligned_page());
|
||||||
|
|
||||||
ASSERT(m_highest_paging_struct == 0);
|
map_kernel_memory();
|
||||||
m_highest_paging_struct = V2P(kmalloc(32, 32, true));
|
|
||||||
ASSERT(m_highest_paging_struct);
|
|
||||||
|
|
||||||
uint64_t* pdpt = reinterpret_cast<uint64_t*>(P2V(m_highest_paging_struct));
|
|
||||||
pdpt[0] = 0;
|
|
||||||
pdpt[1] = 0;
|
|
||||||
pdpt[2] = 0;
|
|
||||||
pdpt[3] = s_global_pdpte;
|
|
||||||
static_assert(KERNEL_OFFSET == 0xC0000000);
|
|
||||||
|
|
||||||
prepare_fast_page();
|
prepare_fast_page();
|
||||||
|
|
||||||
// Map main bios area below 1 MiB
|
|
||||||
map_range_at(
|
|
||||||
0x000E0000,
|
|
||||||
P2V(0x000E0000),
|
|
||||||
0x00100000 - 0x000E0000,
|
|
||||||
PageTable::Flags::Present
|
|
||||||
);
|
|
||||||
|
|
||||||
// Map (phys_kernel_start -> phys_kernel_end) to (virt_kernel_start -> virt_kernel_end)
|
// Map (phys_kernel_start -> phys_kernel_end) to (virt_kernel_start -> virt_kernel_end)
|
||||||
ASSERT((vaddr_t)g_kernel_start % PAGE_SIZE == 0);
|
ASSERT((vaddr_t)g_kernel_start % PAGE_SIZE == 0);
|
||||||
map_range_at(
|
map_range_at(
|
||||||
V2P(g_kernel_start),
|
V2P(g_kernel_start),
|
||||||
(vaddr_t)g_kernel_start,
|
(vaddr_t)g_kernel_start,
|
||||||
g_kernel_end - g_kernel_start,
|
g_kernel_end - g_kernel_start,
|
||||||
Flags::ReadWrite | Flags::Present
|
Flags::Present
|
||||||
);
|
);
|
||||||
|
|
||||||
// Map executable kernel memory as executable
|
// Map executable kernel memory as executable
|
||||||
@@ -155,6 +177,14 @@ namespace Kernel
|
|||||||
Flags::Execute | Flags::Present
|
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 userspace memory
|
||||||
map_range_at(
|
map_range_at(
|
||||||
V2P(g_userspace_start),
|
V2P(g_userspace_start),
|
||||||
@@ -170,58 +200,58 @@ namespace Kernel
|
|||||||
constexpr uint64_t pde = (fast_page() >> 21) & 0x1FF;
|
constexpr uint64_t pde = (fast_page() >> 21) & 0x1FF;
|
||||||
constexpr uint64_t pte = (fast_page() >> 12) & 0x1FF;
|
constexpr uint64_t pte = (fast_page() >> 12) & 0x1FF;
|
||||||
|
|
||||||
uint64_t* pdpt = reinterpret_cast<uint64_t*>(P2V(m_highest_paging_struct));
|
const uint64_t* pdpt = P2V(m_highest_paging_struct);
|
||||||
ASSERT(!(pdpt[pdpte] & Flags::Present));
|
ASSERT(pdpt[pdpte] & Flags::Present);
|
||||||
pdpt[pdpte] = V2P(allocate_zeroed_page_aligned_page()) | Flags::Present;
|
|
||||||
|
|
||||||
uint64_t* pd = reinterpret_cast<uint64_t*>(P2V(pdpt[pdpte]) & PAGE_ADDR_MASK);
|
uint64_t* pd = P2V(pdpt[pdpte] & s_page_addr_mask);
|
||||||
ASSERT(!(pd[pde] & Flags::Present));
|
ASSERT(!(pd[pde] & Flags::Present));
|
||||||
pd[pde] = V2P(allocate_zeroed_page_aligned_page()) | Flags::ReadWrite | Flags::Present;
|
pd[pde] = V2P(allocate_zeroed_page_aligned_page()) | Flags::ReadWrite | Flags::Present;
|
||||||
|
|
||||||
uint64_t* pt = reinterpret_cast<uint64_t*>(P2V(pd[pde]) & PAGE_ADDR_MASK);
|
uint64_t* pt = P2V(pd[pde] & s_page_addr_mask);
|
||||||
ASSERT(!(pt[pte] & Flags::Present));
|
ASSERT(pt[pte] == 0);
|
||||||
pt[pte] = V2P(allocate_zeroed_page_aligned_page());
|
pt[pte] = Flags::Reserved;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PageTable::map_fast_page(paddr_t paddr)
|
void PageTable::map_fast_page(paddr_t paddr)
|
||||||
{
|
{
|
||||||
ASSERT(s_kernel);
|
ASSERT(s_kernel);
|
||||||
ASSERT(paddr);
|
ASSERT(paddr);
|
||||||
|
ASSERT(paddr % PAGE_SIZE == 0);
|
||||||
|
|
||||||
SpinLockGuard _(s_fast_page_lock);
|
ASSERT(s_fast_page_lock.current_processor_has_lock());
|
||||||
|
|
||||||
constexpr uint64_t pdpte = (fast_page() >> 30) & 0x1FF;
|
constexpr uint64_t pdpte = (fast_page() >> 30) & 0x1FF;
|
||||||
constexpr uint64_t pde = (fast_page() >> 21) & 0x1FF;
|
constexpr uint64_t pde = (fast_page() >> 21) & 0x1FF;
|
||||||
constexpr uint64_t pte = (fast_page() >> 12) & 0x1FF;
|
constexpr uint64_t pte = (fast_page() >> 12) & 0x1FF;
|
||||||
|
|
||||||
uint64_t* pdpt = reinterpret_cast<uint64_t*>(P2V(s_kernel->m_highest_paging_struct));
|
uint64_t* pdpt = P2V(s_kernel->m_highest_paging_struct);
|
||||||
uint64_t* pd = reinterpret_cast<uint64_t*>(P2V(pdpt[pdpte] & PAGE_ADDR_MASK));
|
uint64_t* pd = P2V(pdpt[pdpte] & s_page_addr_mask);
|
||||||
uint64_t* pt = reinterpret_cast<uint64_t*>(P2V(pd[pde] & PAGE_ADDR_MASK));
|
uint64_t* pt = P2V(pd[pde] & s_page_addr_mask);
|
||||||
|
|
||||||
ASSERT(!(pt[pte] & Flags::Present));
|
ASSERT(!(pt[pte] & Flags::Present));
|
||||||
pt[pte] = paddr | Flags::ReadWrite | Flags::Present;
|
pt[pte] = paddr | Flags::ReadWrite | Flags::Present;
|
||||||
|
|
||||||
invalidate(fast_page());
|
asm volatile("invlpg (%0)" :: "r"(fast_page()) : "memory");
|
||||||
}
|
}
|
||||||
|
|
||||||
void PageTable::unmap_fast_page()
|
void PageTable::unmap_fast_page()
|
||||||
{
|
{
|
||||||
ASSERT(s_kernel);
|
ASSERT(s_kernel);
|
||||||
|
|
||||||
SpinLockGuard _(s_fast_page_lock);
|
ASSERT(s_fast_page_lock.current_processor_has_lock());
|
||||||
|
|
||||||
constexpr uint64_t pdpte = (fast_page() >> 30) & 0x1FF;
|
constexpr uint64_t pdpte = (fast_page() >> 30) & 0x1FF;
|
||||||
constexpr uint64_t pde = (fast_page() >> 21) & 0x1FF;
|
constexpr uint64_t pde = (fast_page() >> 21) & 0x1FF;
|
||||||
constexpr uint64_t pte = (fast_page() >> 12) & 0x1FF;
|
constexpr uint64_t pte = (fast_page() >> 12) & 0x1FF;
|
||||||
|
|
||||||
uint64_t* pdpt = reinterpret_cast<uint64_t*>(P2V(s_kernel->m_highest_paging_struct));
|
uint64_t* pdpt = P2V(s_kernel->m_highest_paging_struct);
|
||||||
uint64_t* pd = reinterpret_cast<uint64_t*>(P2V(pdpt[pdpte] & PAGE_ADDR_MASK));
|
uint64_t* pd = P2V(pdpt[pdpte] & s_page_addr_mask);
|
||||||
uint64_t* pt = reinterpret_cast<uint64_t*>(P2V(pd[pde] & PAGE_ADDR_MASK));
|
uint64_t* pt = P2V(pd[pde] & s_page_addr_mask);
|
||||||
|
|
||||||
ASSERT(pt[pte] & Flags::Present);
|
ASSERT(pt[pte] & Flags::Present);
|
||||||
pt[pte] = 0;
|
pt[pte] = Flags::Reserved;
|
||||||
|
|
||||||
invalidate(fast_page());
|
asm volatile("invlpg (%0)" :: "r"(fast_page()) : "memory");
|
||||||
}
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<PageTable*> PageTable::create_userspace()
|
BAN::ErrorOr<PageTable*> PageTable::create_userspace()
|
||||||
@@ -243,28 +273,30 @@ namespace Kernel
|
|||||||
m_highest_paging_struct = V2P(kmalloc(32, 32, true));
|
m_highest_paging_struct = V2P(kmalloc(32, 32, true));
|
||||||
ASSERT(m_highest_paging_struct);
|
ASSERT(m_highest_paging_struct);
|
||||||
|
|
||||||
uint64_t* pdpt = reinterpret_cast<uint64_t*>(P2V(m_highest_paging_struct));
|
uint64_t* pdpt = P2V(m_highest_paging_struct);
|
||||||
pdpt[0] = 0;
|
pdpt[0] = 0;
|
||||||
pdpt[1] = 0;
|
pdpt[1] = 0;
|
||||||
pdpt[2] = 0;
|
pdpt[2] = 0;
|
||||||
pdpt[3] = s_global_pdpte;
|
pdpt[3] = s_global_pdpte | Flags::Present;
|
||||||
static_assert(KERNEL_OFFSET == 0xC0000000);
|
static_assert(KERNEL_OFFSET == 0xC0000000);
|
||||||
}
|
}
|
||||||
|
|
||||||
PageTable::~PageTable()
|
PageTable::~PageTable()
|
||||||
{
|
{
|
||||||
uint64_t* pdpt = reinterpret_cast<uint64_t*>(P2V(m_highest_paging_struct));
|
if (m_highest_paging_struct == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
uint64_t* pdpt = P2V(m_highest_paging_struct);
|
||||||
for (uint32_t pdpte = 0; pdpte < 3; pdpte++)
|
for (uint32_t pdpte = 0; pdpte < 3; pdpte++)
|
||||||
{
|
{
|
||||||
if (!(pdpt[pdpte] & Flags::Present))
|
if (!(pdpt[pdpte] & Flags::Present))
|
||||||
continue;
|
continue;
|
||||||
uint64_t* pd = reinterpret_cast<uint64_t*>(P2V(pdpt[pdpte] & PAGE_ADDR_MASK));
|
uint64_t* pd = P2V(pdpt[pdpte] & s_page_addr_mask);
|
||||||
for (uint32_t pde = 0; pde < 512; pde++)
|
for (uint32_t pde = 0; pde < 512; pde++)
|
||||||
{
|
{
|
||||||
if (!(pd[pde] & Flags::Present))
|
if (!(pd[pde] & Flags::Present))
|
||||||
continue;
|
continue;
|
||||||
kfree(reinterpret_cast<uint64_t*>(P2V(pd[pde] & PAGE_ADDR_MASK)));
|
kfree(P2V(pd[pde] & s_page_addr_mask));
|
||||||
}
|
}
|
||||||
kfree(pd);
|
kfree(pd);
|
||||||
}
|
}
|
||||||
@@ -275,18 +307,58 @@ namespace Kernel
|
|||||||
{
|
{
|
||||||
SpinLockGuard _(m_lock);
|
SpinLockGuard _(m_lock);
|
||||||
ASSERT(m_highest_paging_struct < 0x100000000);
|
ASSERT(m_highest_paging_struct < 0x100000000);
|
||||||
const uint32_t pdpt_lo = m_highest_paging_struct;
|
asm volatile("movl %0, %%cr3" :: "r"(static_cast<uint32_t>(m_highest_paging_struct)));
|
||||||
asm volatile("movl %0, %%cr3" :: "r"(pdpt_lo));
|
|
||||||
Processor::set_current_page_table(this);
|
Processor::set_current_page_table(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PageTable::invalidate(vaddr_t vaddr)
|
void PageTable::invalidate_range(vaddr_t vaddr, size_t pages, bool send_smp_message)
|
||||||
{
|
{
|
||||||
ASSERT(vaddr % PAGE_SIZE == 0);
|
ASSERT(vaddr % PAGE_SIZE == 0);
|
||||||
asm volatile("invlpg (%0)" :: "r"(vaddr) : "memory");
|
|
||||||
|
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"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PageTable::unmap_page(vaddr_t vaddr)
|
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);
|
||||||
ASSERT(vaddr % PAGE_SIZE == 0);
|
ASSERT(vaddr % PAGE_SIZE == 0);
|
||||||
@@ -303,30 +375,33 @@ namespace Kernel
|
|||||||
SpinLockGuard _(m_lock);
|
SpinLockGuard _(m_lock);
|
||||||
|
|
||||||
if (is_page_free(vaddr))
|
if (is_page_free(vaddr))
|
||||||
{
|
Kernel::panic("trying to unmap unmapped page 0x{H}", vaddr);
|
||||||
dwarnln("unmapping unmapped page {8H}", vaddr);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t* pdpt = reinterpret_cast<uint64_t*>(P2V(m_highest_paging_struct));
|
uint64_t* pdpt = P2V(m_highest_paging_struct);
|
||||||
uint64_t* pd = reinterpret_cast<uint64_t*>(P2V(pdpt[pdpte] & PAGE_ADDR_MASK));
|
uint64_t* pd = P2V(pdpt[pdpte] & s_page_addr_mask);
|
||||||
uint64_t* pt = reinterpret_cast<uint64_t*>(P2V(pd[pde] & 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;
|
pt[pte] = 0;
|
||||||
invalidate(vaddr);
|
|
||||||
|
if (invalidate && old_paddr != 0)
|
||||||
|
invalidate_page(vaddr, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PageTable::unmap_range(vaddr_t vaddr, size_t size)
|
void PageTable::unmap_range(vaddr_t vaddr, size_t size)
|
||||||
{
|
{
|
||||||
vaddr_t s_page = vaddr / PAGE_SIZE;
|
ASSERT(vaddr % PAGE_SIZE == 0);
|
||||||
vaddr_t e_page = BAN::Math::div_round_up<vaddr_t>(vaddr + size, PAGE_SIZE);
|
|
||||||
|
size_t page_count = range_page_count(vaddr, size);
|
||||||
|
|
||||||
SpinLockGuard _(m_lock);
|
SpinLockGuard _(m_lock);
|
||||||
for (vaddr_t page = s_page; page < e_page; page++)
|
for (vaddr_t page = 0; page < page_count; page++)
|
||||||
unmap_page(page * PAGE_SIZE);
|
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)
|
void PageTable::map_page_at(paddr_t paddr, vaddr_t vaddr, flags_t flags, MemoryType memory_type, bool invalidate)
|
||||||
{
|
{
|
||||||
ASSERT(vaddr);
|
ASSERT(vaddr);
|
||||||
ASSERT(vaddr != fast_page());
|
ASSERT(vaddr != fast_page());
|
||||||
@@ -348,19 +423,24 @@ namespace Kernel
|
|||||||
extra_flags |= 1ull << 63;
|
extra_flags |= 1ull << 63;
|
||||||
if (flags & Flags::Reserved)
|
if (flags & Flags::Reserved)
|
||||||
extra_flags |= Flags::Reserved;
|
extra_flags |= Flags::Reserved;
|
||||||
if (flags & Flags::CacheDisable)
|
|
||||||
extra_flags |= Flags::CacheDisable;
|
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
|
// 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;
|
flags_t uwr_flags = (flags & (Flags::UserSupervisor | Flags::ReadWrite)) | Flags::Present;
|
||||||
|
|
||||||
SpinLockGuard _(m_lock);
|
SpinLockGuard _(m_lock);
|
||||||
|
|
||||||
uint64_t* pdpt = reinterpret_cast<uint64_t*>(P2V(m_highest_paging_struct));
|
uint64_t* pdpt = P2V(m_highest_paging_struct);
|
||||||
if (!(pdpt[pdpte] & Flags::Present))
|
if (!(pdpt[pdpte] & Flags::Present))
|
||||||
pdpt[pdpte] = V2P(allocate_zeroed_page_aligned_page()) | Flags::Present;
|
pdpt[pdpte] = V2P(allocate_zeroed_page_aligned_page()) | Flags::Present;
|
||||||
|
|
||||||
uint64_t* pd = reinterpret_cast<uint64_t*>(P2V(pdpt[pdpte] & PAGE_ADDR_MASK));
|
uint64_t* pd = P2V(pdpt[pdpte] & s_page_addr_mask);
|
||||||
if ((pd[pde] & uwr_flags) != uwr_flags)
|
if ((pd[pde] & uwr_flags) != uwr_flags)
|
||||||
{
|
{
|
||||||
if (!(pd[pde] & Flags::Present))
|
if (!(pd[pde] & Flags::Present))
|
||||||
@@ -371,13 +451,17 @@ namespace Kernel
|
|||||||
if (!(flags & Flags::Present))
|
if (!(flags & Flags::Present))
|
||||||
uwr_flags &= ~Flags::Present;
|
uwr_flags &= ~Flags::Present;
|
||||||
|
|
||||||
uint64_t* pt = reinterpret_cast<uint64_t*>(P2V(pd[pde] & 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] = paddr | uwr_flags | extra_flags;
|
pt[pte] = paddr | uwr_flags | extra_flags;
|
||||||
|
|
||||||
invalidate(vaddr);
|
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)
|
void PageTable::map_range_at(paddr_t paddr, vaddr_t vaddr, size_t size, flags_t flags, MemoryType memory_type)
|
||||||
{
|
{
|
||||||
ASSERT(vaddr);
|
ASSERT(vaddr);
|
||||||
ASSERT(paddr % PAGE_SIZE == 0);
|
ASSERT(paddr % PAGE_SIZE == 0);
|
||||||
@@ -387,7 +471,50 @@ namespace Kernel
|
|||||||
|
|
||||||
SpinLockGuard _(m_lock);
|
SpinLockGuard _(m_lock);
|
||||||
for (size_t page = 0; page < page_count; page++)
|
for (size_t page = 0; page < page_count; page++)
|
||||||
map_page_at(paddr + page * PAGE_SIZE, vaddr + page * PAGE_SIZE, flags);
|
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
|
uint64_t PageTable::get_page_data(vaddr_t vaddr) const
|
||||||
@@ -400,15 +527,15 @@ namespace Kernel
|
|||||||
|
|
||||||
SpinLockGuard _(m_lock);
|
SpinLockGuard _(m_lock);
|
||||||
|
|
||||||
uint64_t* pdpt = (uint64_t*)P2V(m_highest_paging_struct);
|
const uint64_t* pdpt = P2V(m_highest_paging_struct);
|
||||||
if (!(pdpt[pdpte] & Flags::Present))
|
if (!(pdpt[pdpte] & Flags::Present))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
uint64_t* pd = (uint64_t*)P2V(pdpt[pdpte] & PAGE_ADDR_MASK);
|
const uint64_t* pd = P2V(pdpt[pdpte] & s_page_addr_mask);
|
||||||
if (!(pd[pde] & Flags::Present))
|
if (!(pd[pde] & Flags::Present))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
uint64_t* pt = (uint64_t*)P2V(pd[pde] & PAGE_ADDR_MASK);
|
const uint64_t* pt = P2V(pd[pde] & s_page_addr_mask);
|
||||||
if (!(pt[pte] & Flags::Used))
|
if (!(pt[pte] & Flags::Used))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
@@ -422,8 +549,7 @@ namespace Kernel
|
|||||||
|
|
||||||
paddr_t PageTable::physical_address_of(vaddr_t vaddr) const
|
paddr_t PageTable::physical_address_of(vaddr_t vaddr) const
|
||||||
{
|
{
|
||||||
uint64_t page_data = get_page_data(vaddr);
|
return get_page_data(vaddr) & s_page_addr_mask;
|
||||||
return (page_data & PAGE_ADDR_MASK) & ~(1ull << 63);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PageTable::is_page_free(vaddr_t vaddr) const
|
bool PageTable::is_page_free(vaddr_t vaddr) const
|
||||||
@@ -444,13 +570,13 @@ namespace Kernel
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PageTable::reserve_page(vaddr_t vaddr, bool only_free)
|
bool PageTable::reserve_page(vaddr_t vaddr, bool only_free, bool send_smp_message)
|
||||||
{
|
{
|
||||||
SpinLockGuard _(m_lock);
|
SpinLockGuard _(m_lock);
|
||||||
ASSERT(vaddr % PAGE_SIZE == 0);
|
ASSERT(vaddr % PAGE_SIZE == 0);
|
||||||
if (only_free && !is_page_free(vaddr))
|
if (only_free && !is_page_free(vaddr))
|
||||||
return false;
|
return false;
|
||||||
map_page_at(0, vaddr, Flags::Reserved);
|
map_page_at(0, vaddr, Flags::Reserved, MemoryType::Normal, send_smp_message);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -464,7 +590,9 @@ namespace Kernel
|
|||||||
if (only_free && !is_range_free(vaddr, bytes))
|
if (only_free && !is_range_free(vaddr, bytes))
|
||||||
return false;
|
return false;
|
||||||
for (size_t offset = 0; offset < bytes; offset += PAGE_SIZE)
|
for (size_t offset = 0; offset < bytes; offset += PAGE_SIZE)
|
||||||
reserve_page(vaddr + offset);
|
reserve_page(vaddr + offset, true, false);
|
||||||
|
invalidate_range(vaddr, bytes / PAGE_SIZE, true);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -477,39 +605,37 @@ namespace Kernel
|
|||||||
if (size_t rem = last_address % PAGE_SIZE)
|
if (size_t rem = last_address % PAGE_SIZE)
|
||||||
last_address -= rem;
|
last_address -= rem;
|
||||||
|
|
||||||
const uint32_t s_pdpte = (first_address >> 30) & 0x1FF;
|
uint32_t pdpte = (first_address >> 30) & 0x1FF;
|
||||||
const uint32_t s_pde = (first_address >> 21) & 0x1FF;
|
uint32_t pde = (first_address >> 21) & 0x1FF;
|
||||||
const uint32_t s_pte = (first_address >> 12) & 0x1FF;
|
uint32_t pte = (first_address >> 12) & 0x1FF;
|
||||||
|
|
||||||
const uint32_t e_pdpte = (last_address >> 30) & 0x1FF;
|
const uint32_t e_pdpte = ((last_address - 1) >> 30) & 0x1FF;
|
||||||
const uint32_t e_pde = (last_address >> 21) & 0x1FF;
|
const uint32_t e_pde = ((last_address - 1) >> 21) & 0x1FF;
|
||||||
const uint32_t e_pte = (last_address >> 12) & 0x1FF;
|
const uint32_t e_pte = ((last_address - 1) >> 12) & 0x1FF;
|
||||||
|
|
||||||
SpinLockGuard _(m_lock);
|
SpinLockGuard _(m_lock);
|
||||||
|
|
||||||
// Try to find free page that can be mapped without
|
// Try to find free page that can be mapped without
|
||||||
// allocations (page table with unused entries)
|
// allocations (page table with unused entries)
|
||||||
uint64_t* pdpt = reinterpret_cast<uint64_t*>(P2V(m_highest_paging_struct));
|
const uint64_t* pdpt = P2V(m_highest_paging_struct);
|
||||||
for (uint32_t pdpte = s_pdpte; pdpte < 4; pdpte++)
|
for (; pdpte <= e_pdpte; pdpte++)
|
||||||
{
|
{
|
||||||
if (pdpte > e_pdpte)
|
|
||||||
break;
|
|
||||||
if (!(pdpt[pdpte] & Flags::Present))
|
if (!(pdpt[pdpte] & Flags::Present))
|
||||||
continue;
|
continue;
|
||||||
uint64_t* pd = reinterpret_cast<uint64_t*>(P2V(pdpt[pdpte] & PAGE_ADDR_MASK));
|
const uint64_t* pd = P2V(pdpt[pdpte] & s_page_addr_mask);
|
||||||
for (uint32_t pde = s_pde; pde < 512; pde++)
|
for (; pde < 512; pde++)
|
||||||
{
|
{
|
||||||
if (pdpte == e_pdpte && pde > e_pde)
|
if (pdpte == e_pdpte && pde > e_pde)
|
||||||
break;
|
break;
|
||||||
if (!(pd[pde] & Flags::Present))
|
if (!(pd[pde] & Flags::Present))
|
||||||
continue;
|
continue;
|
||||||
uint64_t* pt = (uint64_t*)P2V(pd[pde] & PAGE_ADDR_MASK);
|
const uint64_t* pt = P2V(pd[pde] & s_page_addr_mask);
|
||||||
for (uint32_t pte = s_pte; pte < 512; pte++)
|
for (; pte < 512; pte++)
|
||||||
{
|
{
|
||||||
if (pdpte == e_pdpte && pde == e_pde && pte >= e_pte)
|
if (pdpte == e_pdpte && pde == e_pde && pte > e_pte)
|
||||||
break;
|
break;
|
||||||
if (!(pt[pte] & Flags::Used))
|
if (pt[pte] & Flags::Used)
|
||||||
{
|
continue;
|
||||||
vaddr_t vaddr = 0;
|
vaddr_t vaddr = 0;
|
||||||
vaddr |= (vaddr_t)pdpte << 30;
|
vaddr |= (vaddr_t)pdpte << 30;
|
||||||
vaddr |= (vaddr_t)pde << 21;
|
vaddr |= (vaddr_t)pde << 21;
|
||||||
@@ -517,8 +643,9 @@ namespace Kernel
|
|||||||
ASSERT(reserve_page(vaddr));
|
ASSERT(reserve_page(vaddr));
|
||||||
return vaddr;
|
return vaddr;
|
||||||
}
|
}
|
||||||
|
pte = 0;
|
||||||
}
|
}
|
||||||
}
|
pde = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find any free page
|
// Find any free page
|
||||||
@@ -531,7 +658,7 @@ namespace Kernel
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ASSERT_NOT_REACHED();
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
vaddr_t PageTable::reserve_free_contiguous_pages(size_t page_count, vaddr_t first_address, vaddr_t last_address)
|
vaddr_t PageTable::reserve_free_contiguous_pages(size_t page_count, vaddr_t first_address, vaddr_t last_address)
|
||||||
@@ -564,7 +691,7 @@ namespace Kernel
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ASSERT_NOT_REACHED();
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dump_range(vaddr_t start, vaddr_t end, PageTable::flags_t flags)
|
static void dump_range(vaddr_t start, vaddr_t end, PageTable::flags_t flags)
|
||||||
@@ -587,7 +714,7 @@ namespace Kernel
|
|||||||
flags_t flags = 0;
|
flags_t flags = 0;
|
||||||
vaddr_t start = 0;
|
vaddr_t start = 0;
|
||||||
|
|
||||||
uint64_t* pdpt = reinterpret_cast<uint64_t*>(P2V(m_highest_paging_struct));
|
const uint64_t* pdpt = P2V(m_highest_paging_struct);
|
||||||
for (uint32_t pdpte = 0; pdpte < 4; pdpte++)
|
for (uint32_t pdpte = 0; pdpte < 4; pdpte++)
|
||||||
{
|
{
|
||||||
if (!(pdpt[pdpte] & Flags::Present))
|
if (!(pdpt[pdpte] & Flags::Present))
|
||||||
@@ -596,7 +723,7 @@ namespace Kernel
|
|||||||
start = 0;
|
start = 0;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
uint64_t* pd = (uint64_t*)P2V(pdpt[pdpte] & PAGE_ADDR_MASK);
|
const uint64_t* pd = P2V(pdpt[pdpte] & s_page_addr_mask);
|
||||||
for (uint64_t pde = 0; pde < 512; pde++)
|
for (uint64_t pde = 0; pde < 512; pde++)
|
||||||
{
|
{
|
||||||
if (!(pd[pde] & Flags::Present))
|
if (!(pd[pde] & Flags::Present))
|
||||||
@@ -605,7 +732,7 @@ namespace Kernel
|
|||||||
start = 0;
|
start = 0;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
uint64_t* pt = (uint64_t*)P2V(pd[pde] & PAGE_ADDR_MASK);
|
const uint64_t* pt = P2V(pd[pde] & s_page_addr_mask);
|
||||||
for (uint64_t pte = 0; pte < 512; pte++)
|
for (uint64_t pte = 0; pte < 512; pte++)
|
||||||
{
|
{
|
||||||
if (parse_flags(pt[pte]) != flags)
|
if (parse_flags(pt[pte]) != flags)
|
||||||
|
|||||||
@@ -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,40 +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:
|
||||||
movl 8(%esp), %edi # ip
|
|
||||||
movl 4(%esp), %esp # sp
|
|
||||||
|
|
||||||
# STACK LAYOUT
|
# STACK LAYOUT
|
||||||
# NULL
|
# on_exit arg
|
||||||
# thread ptr
|
# on_exit func
|
||||||
# &Thread::on_exit
|
# entry arg
|
||||||
# data
|
# entry func
|
||||||
|
|
||||||
xorl %ebp, %ebp
|
movl 4(%esp), %edi
|
||||||
|
movl 0(%esp), %esi
|
||||||
|
|
||||||
|
subl $12, %esp
|
||||||
|
pushl %edi
|
||||||
sti
|
sti
|
||||||
call *%edi
|
call *%esi
|
||||||
|
addl $16, %esp
|
||||||
|
|
||||||
movl 4(%esp), %edi # &Thread::on_exit
|
movl 12(%esp), %edi
|
||||||
|
movl 8(%esp), %esi
|
||||||
|
|
||||||
movl 8(%esp), %eax # thread ptr
|
subl $12, %esp
|
||||||
movl %eax, (%esp)
|
pushl %edi
|
||||||
|
call *%esi
|
||||||
|
|
||||||
call *%edi
|
.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
|
||||||
# void continue_thread(uint32_t sp, uint32_t ip)
|
|
||||||
.global continue_thread
|
|
||||||
continue_thread:
|
|
||||||
movl 8(%esp), %edi # ip
|
|
||||||
movl 4(%esp), %esp # sp
|
|
||||||
xorl %eax, %eax
|
|
||||||
jmp *%edi
|
|
||||||
|
|
||||||
# void thread_userspace_trampoline(uint32_t sp, uint32_t ip, int argc, char** argv, char** envp)
|
|
||||||
.global thread_userspace_trampoline
|
|
||||||
thread_userspace_trampoline:
|
|
||||||
ud2
|
|
||||||
|
|||||||
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,10 +77,10 @@ bananboot_start:
|
|||||||
bananboot_end:
|
bananboot_end:
|
||||||
|
|
||||||
.section .bss, "aw", @nobits
|
.section .bss, "aw", @nobits
|
||||||
.align 4096
|
.global g_boot_stack_top
|
||||||
boot_stack_bottom:
|
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:
|
||||||
@@ -82,9 +106,18 @@ boot_pdpt:
|
|||||||
boot_pd:
|
boot_pd:
|
||||||
.set i, 0
|
.set i, 0
|
||||||
.rept 512
|
.rept 512
|
||||||
.long i + (PG_PAGE_SIZE | PG_READ_WRITE | PG_PRESENT)
|
.long V2P(boot_pts) + i + (PG_READ_WRITE | PG_PRESENT)
|
||||||
.long 0
|
.long 0
|
||||||
.set i, i + 0x200000
|
.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
|
.endr
|
||||||
|
|
||||||
boot_gdt:
|
boot_gdt:
|
||||||
@@ -152,6 +185,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
|
||||||
@@ -179,7 +219,7 @@ _start:
|
|||||||
movl %ebx, V2P(bootloader_info)
|
movl %ebx, V2P(bootloader_info)
|
||||||
|
|
||||||
# load boot stack
|
# load boot stack
|
||||||
movl $V2P(boot_stack_top), %esp
|
movl $V2P(g_boot_stack_top), %esp
|
||||||
|
|
||||||
# load boot GDT
|
# load boot GDT
|
||||||
lgdt V2P(boot_gdtr)
|
lgdt V2P(boot_gdtr)
|
||||||
@@ -194,10 +234,11 @@ gdt_flush:
|
|||||||
# do processor initialization
|
# do processor initialization
|
||||||
call check_requirements
|
call check_requirements
|
||||||
call enable_sse
|
call enable_sse
|
||||||
|
call enable_tsc
|
||||||
call initialize_paging
|
call initialize_paging
|
||||||
|
|
||||||
# load higher half stack pointer
|
# load higher half stack pointer
|
||||||
movl $boot_stack_top, %esp
|
movl $g_boot_stack_top, %esp
|
||||||
|
|
||||||
# jump to higher half
|
# jump to higher half
|
||||||
leal higher_half, %ecx
|
leal higher_half, %ecx
|
||||||
@@ -207,6 +248,13 @@ 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
|
||||||
|
|
||||||
@@ -226,30 +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:
|
||||||
ud2
|
|
||||||
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:
|
||||||
@@ -258,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
|
||||||
|
|||||||
@@ -1,73 +1,107 @@
|
|||||||
isr_stub:
|
.macro intr_header, n
|
||||||
pusha
|
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 %cr0, %eax; pushl %eax
|
||||||
movl %cr2, %eax; pushl %eax
|
movl %cr2, %eax; pushl %eax
|
||||||
movl %cr3, %eax; pushl %eax
|
movl %cr3, %eax; pushl %eax
|
||||||
movl %cr4, %eax; pushl %eax
|
movl %cr4, %eax; pushl %eax
|
||||||
|
|
||||||
movl %esp, %eax // register ptr
|
movl 48(%esp), %edi // isr number
|
||||||
leal 56(%esp), %ebx // interrupt stack ptr
|
movl 52(%esp), %esi // error code
|
||||||
movl 52(%esp), %ecx // error code
|
leal 56(%esp), %edx // interrupt stack ptr
|
||||||
movl 48(%esp), %edx // isr number
|
movl %esp, %ecx // register ptr
|
||||||
|
|
||||||
|
# stack frame for stack trace
|
||||||
|
leal 56(%esp), %eax
|
||||||
|
pushl (%eax)
|
||||||
|
pushl %ebp
|
||||||
|
|
||||||
|
movl %esp, %ebp
|
||||||
|
andl $-16, %esp
|
||||||
|
|
||||||
subl $12, %esp
|
|
||||||
pushl %eax
|
|
||||||
pushl %ebx
|
|
||||||
pushl %ecx
|
pushl %ecx
|
||||||
pushl %edx
|
pushl %edx
|
||||||
|
pushl %esi
|
||||||
|
pushl %edi
|
||||||
call cpp_isr_handler
|
call cpp_isr_handler
|
||||||
addl $44, %esp
|
|
||||||
|
|
||||||
popa
|
movl %ebp, %esp
|
||||||
|
addl $24, %esp
|
||||||
|
|
||||||
|
intr_footer 12
|
||||||
addl $8, %esp
|
addl $8, %esp
|
||||||
iret
|
iret
|
||||||
|
|
||||||
irq_stub:
|
irq_stub:
|
||||||
pusha
|
intr_header 12
|
||||||
|
|
||||||
leal 40(%esp), %eax // interrupt stack ptr
|
movl 32(%esp), %edi # interrupt number
|
||||||
movl 32(%esp), %ebx // irq number
|
|
||||||
|
movl %esp, %ebp
|
||||||
|
andl $-16, %esp
|
||||||
|
|
||||||
subl $12, %esp
|
subl $12, %esp
|
||||||
pushl %eax
|
pushl %edi
|
||||||
pushl %ebx
|
|
||||||
call cpp_irq_handler
|
call cpp_irq_handler
|
||||||
addl $20, %esp
|
|
||||||
|
|
||||||
popa
|
movl %ebp, %esp
|
||||||
|
|
||||||
|
intr_footer 12
|
||||||
addl $8, %esp
|
addl $8, %esp
|
||||||
iret
|
iret
|
||||||
|
|
||||||
// arguments in EAX, EBX, ECX, EDX, ESI, EDI
|
.global asm_ipi_handler
|
||||||
.global syscall_asm
|
asm_ipi_handler:
|
||||||
syscall_asm:
|
intr_header 4
|
||||||
ud2
|
|
||||||
pusha
|
|
||||||
|
|
||||||
pushl %esp
|
movl %esp, %ebp
|
||||||
addl $36, (%esp)
|
andl $-16, %esp
|
||||||
|
|
||||||
pushl %edi
|
call cpp_ipi_handler
|
||||||
pushl %esi
|
|
||||||
pushl %edx
|
|
||||||
pushl %ecx
|
|
||||||
pushl %ebx
|
|
||||||
pushl %eax
|
|
||||||
|
|
||||||
call cpp_syscall_handler
|
movl %ebp, %esp
|
||||||
|
|
||||||
addl $60, %esp
|
intr_footer 4
|
||||||
|
iret
|
||||||
|
|
||||||
popl %edi
|
.global asm_timer_handler
|
||||||
popl %esi
|
asm_timer_handler:
|
||||||
popl %ebp
|
intr_header 4
|
||||||
addl $4, %esp
|
|
||||||
popl %ebx
|
|
||||||
popl %edx
|
|
||||||
popl %ecx
|
|
||||||
addl $4, %esp
|
|
||||||
|
|
||||||
|
movl %esp, %ebp
|
||||||
|
andl $-16, %esp
|
||||||
|
|
||||||
|
call cpp_timer_handler
|
||||||
|
|
||||||
|
movl %ebp, %esp
|
||||||
|
|
||||||
|
intr_footer 4
|
||||||
iret
|
iret
|
||||||
|
|
||||||
.macro isr n
|
.macro isr n
|
||||||
@@ -126,36 +160,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
|
|
||||||
|
|||||||
@@ -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 = .;
|
||||||
}
|
}
|
||||||
|
|||||||
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,7 +4,7 @@ read_ip:
|
|||||||
popq %rax
|
popq %rax
|
||||||
jmp *%rax
|
jmp *%rax
|
||||||
|
|
||||||
# void start_thread()
|
# void start_kernel_thread()
|
||||||
.global start_kernel_thread
|
.global start_kernel_thread
|
||||||
start_kernel_thread:
|
start_kernel_thread:
|
||||||
# STACK LAYOUT
|
# STACK LAYOUT
|
||||||
@@ -15,8 +15,14 @@ start_kernel_thread:
|
|||||||
|
|
||||||
movq 8(%rsp), %rdi
|
movq 8(%rsp), %rdi
|
||||||
movq 0(%rsp), %rsi
|
movq 0(%rsp), %rsi
|
||||||
|
sti
|
||||||
call *%rsi
|
call *%rsi
|
||||||
|
|
||||||
movq 24(%rsp), %rdi
|
movq 24(%rsp), %rdi
|
||||||
movq 16(%rsp), %rsi
|
movq 16(%rsp), %rsi
|
||||||
call *%rsi
|
call *%rsi
|
||||||
|
|
||||||
|
.global start_userspace_thread
|
||||||
|
start_userspace_thread:
|
||||||
|
swapgs
|
||||||
|
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,4 +1,4 @@
|
|||||||
.macro pushaq
|
.macro intr_header, n
|
||||||
pushq %rax
|
pushq %rax
|
||||||
pushq %rcx
|
pushq %rcx
|
||||||
pushq %rdx
|
pushq %rdx
|
||||||
@@ -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
|
||||||
@@ -34,26 +42,8 @@
|
|||||||
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 %rdi
|
|
||||||
popq %rsi
|
|
||||||
popq %rbp
|
|
||||||
popq %rbx
|
|
||||||
popq %rdx
|
|
||||||
popq %rcx
|
|
||||||
.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
|
||||||
@@ -66,18 +56,35 @@ isr_stub:
|
|||||||
call cpp_isr_handler
|
call cpp_isr_handler
|
||||||
addq $32, %rsp
|
addq $32, %rsp
|
||||||
|
|
||||||
popaq
|
intr_footer 24
|
||||||
addq $16, %rsp
|
addq $16, %rsp
|
||||||
iretq
|
iretq
|
||||||
|
|
||||||
irq_stub:
|
irq_stub:
|
||||||
pushaq
|
intr_header 24
|
||||||
|
xorq %rbp, %rbp
|
||||||
movq 120(%rsp), %rdi # irq number
|
movq 120(%rsp), %rdi # irq number
|
||||||
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:
|
||||||
@@ -134,63 +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
|
|
||||||
|
|
||||||
.global asm_reschedule_handler
|
|
||||||
asm_reschedule_handler:
|
|
||||||
pushaq
|
|
||||||
leaq 120(%rsp), %rdi # interrupt stack ptr
|
|
||||||
movq %rsp, %rsi # interrupt register ptr
|
|
||||||
call cpp_reschedule_handler
|
|
||||||
popaq
|
|
||||||
iretq
|
|
||||||
|
|
||||||
// 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]);
|
||||||
|
}
|
||||||
|
}
|
||||||
179
kernel/include/kernel/ACPI/Resource.h
Normal file
179
kernel/include/kernel/ACPI/Resource.h
Normal file
@@ -0,0 +1,179 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <BAN/ByteSpan.h>
|
||||||
|
#include <BAN/Debug.h>
|
||||||
|
#include <BAN/Optional.h>
|
||||||
|
|
||||||
|
namespace Kernel::ACPI
|
||||||
|
{
|
||||||
|
|
||||||
|
struct ResourceData
|
||||||
|
{
|
||||||
|
enum class Type
|
||||||
|
{
|
||||||
|
IRQ,
|
||||||
|
DMA,
|
||||||
|
IOPort,
|
||||||
|
FixedIOPort,
|
||||||
|
FixedDMA,
|
||||||
|
|
||||||
|
// TODO: large stuff the stuff :)
|
||||||
|
};
|
||||||
|
|
||||||
|
union {
|
||||||
|
struct {
|
||||||
|
uint16_t irq_mask;
|
||||||
|
union {
|
||||||
|
struct {
|
||||||
|
uint8_t edge_triggered : 1;
|
||||||
|
uint8_t : 2;
|
||||||
|
uint8_t active_low : 1;
|
||||||
|
uint8_t shared : 1;
|
||||||
|
uint8_t wake_capable : 1;
|
||||||
|
uint8_t : 2;
|
||||||
|
};
|
||||||
|
uint8_t raw;
|
||||||
|
};
|
||||||
|
} irq;
|
||||||
|
struct {
|
||||||
|
uint8_t channel_mask;
|
||||||
|
union {
|
||||||
|
struct {
|
||||||
|
uint8_t type : 2; // 0: 8 bit, 1: 8 and 16 bit, 2: 16 bit only
|
||||||
|
uint8_t bus_master : 1;
|
||||||
|
uint8_t : 2;
|
||||||
|
uint8_t channel_speed : 2; // 0: compatibility, 1: type A, 2: type B, 3: type F
|
||||||
|
uint8_t : 1;
|
||||||
|
};
|
||||||
|
uint8_t raw;
|
||||||
|
};
|
||||||
|
} dma;
|
||||||
|
struct {
|
||||||
|
uint16_t range_min_base;
|
||||||
|
uint16_t range_max_base;
|
||||||
|
uint8_t base_alignment;
|
||||||
|
uint8_t range_length;
|
||||||
|
} io_port;
|
||||||
|
struct {
|
||||||
|
uint16_t range_base;
|
||||||
|
uint8_t range_length;
|
||||||
|
} fixed_io_port;
|
||||||
|
struct {
|
||||||
|
uint16_t request_line;
|
||||||
|
uint16_t channel;
|
||||||
|
uint8_t transfer_width; // 0: 8 bit, 1: 16 bit, 2: 32 bit, 3: 64 bit, 4: 128 bit
|
||||||
|
} fixed_dma;
|
||||||
|
} as;
|
||||||
|
Type type;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ResourceParser
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ResourceParser(BAN::ConstByteSpan buffer)
|
||||||
|
: m_buffer(buffer)
|
||||||
|
{}
|
||||||
|
|
||||||
|
BAN::Optional<ResourceData> get_next()
|
||||||
|
{
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
if (m_buffer.empty())
|
||||||
|
return {};
|
||||||
|
|
||||||
|
if (m_buffer[0] & 0x80)
|
||||||
|
{
|
||||||
|
dprintln("Skipping large resource 0x{2H}", m_buffer[0] & 0x7F);
|
||||||
|
const uint16_t length = (m_buffer[2] << 8) | m_buffer[1];
|
||||||
|
if (m_buffer.size() < static_cast<size_t>(3 + length))
|
||||||
|
return {};
|
||||||
|
m_buffer = m_buffer.slice(3 + length);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint8_t length = m_buffer[0] & 0x07;
|
||||||
|
if (m_buffer.size() < static_cast<size_t>(1 + length))
|
||||||
|
return {};
|
||||||
|
|
||||||
|
BAN::Optional<ResourceData> result;
|
||||||
|
switch ((m_buffer[0] >> 3) & 0x0F)
|
||||||
|
{
|
||||||
|
case 0x04:
|
||||||
|
if (length < 2)
|
||||||
|
break;
|
||||||
|
result = ResourceData {
|
||||||
|
.as = { .irq = {
|
||||||
|
.irq_mask = static_cast<uint16_t>((m_buffer[2] << 8) | m_buffer[1]),
|
||||||
|
.raw = (length >= 3) ? m_buffer[3] : static_cast<uint8_t>(1),
|
||||||
|
}},
|
||||||
|
.type = ResourceData::Type::IRQ,
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
case 0x05:
|
||||||
|
if (length < 2)
|
||||||
|
break;
|
||||||
|
result = ResourceData {
|
||||||
|
.as = { .dma = {
|
||||||
|
.channel_mask = m_buffer[1],
|
||||||
|
.raw = m_buffer[2],
|
||||||
|
}},
|
||||||
|
.type = ResourceData::Type::DMA,
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
case 0x08:
|
||||||
|
if (length < 7)
|
||||||
|
break;
|
||||||
|
result = ResourceData {
|
||||||
|
.as = { .io_port = {
|
||||||
|
.range_min_base = static_cast<uint16_t>(((m_buffer[3] << 8) | m_buffer[2]) & ((m_buffer[1] & 1) ? 0xFFFF : 0x03FF)),
|
||||||
|
.range_max_base = static_cast<uint16_t>(((m_buffer[5] << 8) | m_buffer[4]) & ((m_buffer[1] & 1) ? 0xFFFF : 0x03FF)),
|
||||||
|
.base_alignment = m_buffer[6],
|
||||||
|
.range_length = m_buffer[7],
|
||||||
|
}},
|
||||||
|
.type = ResourceData::Type::IOPort,
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
case 0x09:
|
||||||
|
if (length < 3)
|
||||||
|
break;
|
||||||
|
result = ResourceData {
|
||||||
|
.as = { .fixed_io_port = {
|
||||||
|
.range_base = static_cast<uint16_t>(((m_buffer[2] << 8) | m_buffer[1]) & 0x03FF),
|
||||||
|
.range_length = m_buffer[3],
|
||||||
|
}},
|
||||||
|
.type = ResourceData::Type::FixedIOPort,
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
case 0x0A:
|
||||||
|
if (length < 5)
|
||||||
|
break;
|
||||||
|
result = ResourceData {
|
||||||
|
.as = { .fixed_dma = {
|
||||||
|
.request_line = static_cast<uint16_t>((m_buffer[2] << 8) | m_buffer[1]),
|
||||||
|
.channel = static_cast<uint16_t>((m_buffer[4] << 8) | m_buffer[3]),
|
||||||
|
.transfer_width = m_buffer[5],
|
||||||
|
}},
|
||||||
|
.type = ResourceData::Type::FixedDMA,
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
case 0x0F:
|
||||||
|
// End tag
|
||||||
|
return {};
|
||||||
|
case 0x06:
|
||||||
|
case 0x07:
|
||||||
|
case 0x0E:
|
||||||
|
dprintln("Skipping short resource 0x{2H}", (m_buffer[0] >> 3) & 0x0F);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_buffer = m_buffer.slice(1 + length);
|
||||||
|
if (result.has_value())
|
||||||
|
return result.release_value();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
BAN::ConstByteSpan m_buffer;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <dirent.h>
|
|
||||||
|
|
||||||
namespace Kernel::API
|
|
||||||
{
|
|
||||||
|
|
||||||
struct DirectoryEntry
|
|
||||||
{
|
|
||||||
size_t rec_len { 0 };
|
|
||||||
struct dirent dirent;
|
|
||||||
DirectoryEntry* next() const { return (DirectoryEntry*)((uintptr_t)this + rec_len); }
|
|
||||||
};
|
|
||||||
|
|
||||||
struct DirectoryEntryList
|
|
||||||
{
|
|
||||||
size_t entry_count { 0 };
|
|
||||||
DirectoryEntry array[];
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
37
kernel/include/kernel/API/SharedPage.h
Normal file
37
kernel/include/kernel/API/SharedPage.h
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
namespace Kernel::API
|
||||||
|
{
|
||||||
|
|
||||||
|
enum SharedPageFeature : uint32_t
|
||||||
|
{
|
||||||
|
SPF_GETTIME = 1 << 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SharedPage
|
||||||
|
{
|
||||||
|
uint8_t __sequence[0x100];
|
||||||
|
|
||||||
|
uint32_t features;
|
||||||
|
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
uint8_t shift;
|
||||||
|
uint64_t mult;
|
||||||
|
uint64_t realtime_seconds;
|
||||||
|
} gettime_shared;
|
||||||
|
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
uint32_t seq;
|
||||||
|
uint64_t last_ns;
|
||||||
|
uint64_t last_tsc;
|
||||||
|
} gettime_local;
|
||||||
|
} cpus[];
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
34
kernel/include/kernel/API/Syscall.h
Normal file
34
kernel/include/kernel/API/Syscall.h
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <BAN/MacroUtils.h>
|
||||||
|
|
||||||
|
#if defined(__x86_64__)
|
||||||
|
#define _kas_instruction "syscall"
|
||||||
|
#define _kas_result rax
|
||||||
|
#define _kas_arguments rdi, rsi, rdx, r10, r8, r9
|
||||||
|
#define _kas_globbers rcx, rdx, rdi, rsi, r8, r9, r10, r11
|
||||||
|
#elif defined(__i686__)
|
||||||
|
#define _kas_instruction "int $0xF0"
|
||||||
|
#define _kas_result eax
|
||||||
|
#define _kas_arguments eax, ebx, ecx, edx, esi, edi
|
||||||
|
#define _kas_globbers
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define _kas_argument_var(index, value) register long _kas_a##index asm(_ban_stringify(_ban_get(index, _kas_arguments))) = (long)value;
|
||||||
|
#define _kas_dummy_var(index, value) register long _kas_d##index asm(#value);
|
||||||
|
#define _kas_input(index, _) "r"(_kas_a##index)
|
||||||
|
#define _kas_output(index, _) , "=r"(_kas_d##index)
|
||||||
|
#define _kas_globber(_, value) #value
|
||||||
|
|
||||||
|
#define _kas_syscall(...) ({ \
|
||||||
|
register long _kas_ret asm(_ban_stringify(_kas_result)); \
|
||||||
|
_ban_for_each(_kas_argument_var, __VA_ARGS__) \
|
||||||
|
_ban_for_each(_kas_dummy_var, _kas_globbers) \
|
||||||
|
asm volatile( \
|
||||||
|
_kas_instruction \
|
||||||
|
: "=r"(_kas_ret) _ban_for_each(_kas_output, _kas_globbers) \
|
||||||
|
: _ban_for_each_comma(_kas_input, __VA_ARGS__) \
|
||||||
|
: "cc", "memory"); \
|
||||||
|
(void)_kas_a0; /* require 1 argument */ \
|
||||||
|
_kas_ret; \
|
||||||
|
})
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user