Compare commits
2141 Commits
9213dd13bc
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b8dc199738 | ||
| 74127c0f45 | |||
| 28499b890c | |||
| 2f45349658 | |||
| fde085e04b | |||
| 77ca525552 | |||
| 3b83daef17 | |||
| f37d9dbdb1 | |||
| b7cedad891 | |||
| cdf0de34fb | |||
| 03fccdffe1 | |||
| 1602b195c5 | |||
| 1486ad7aa5 | |||
| ab8bcbec3e | |||
| 0e00b72df6 | |||
| a63818ec33 | |||
| cf2e8ffaff | |||
| b5647ff258 | |||
| bef53c726b | |||
| 6b43cadf3a | |||
| b74812d669 | |||
| eea0154f18 | |||
| ea4c34fc0b | |||
| 558ed8fd44 | |||
| 8665195350 | |||
| 72a24a0d38 | |||
| 0ee50032f3 | |||
| 40f3546aca | |||
| a8e496310b | |||
| fe613e4274 | |||
| 3264dcee44 | |||
| 71649ffe09 | |||
| 5b7b2d7ac3 | |||
| 8e543195b1 | |||
| a24ec0da2b | |||
| e6284c3cf3 | |||
|
|
f527aca9d0 | ||
|
|
5fce3b64cc | ||
| c04ad65f7f | |||
| af17b29414 | |||
| 7badcf80cf | |||
| 7f122d9e89 | |||
| 984c7c0a89 | |||
| ce318c7930 | |||
| eff6c79e9e | |||
| aaade52146 | |||
| 1bf5e6a051 | |||
| 394719a909 | |||
| 3ebadc5c74 | |||
| d471bbf856 | |||
| c849293f3d | |||
| 0156d06cdc | |||
| ad12bf3e1d | |||
| 42964ad0b4 | |||
| 87979b1627 | |||
| fed9dbefdf | |||
| 2984927be5 | |||
| 2e654b53fa | |||
| ac6e6f3ec1 | |||
| 2b97587e9f | |||
| 4bde088b28 | |||
| 2a9dad2dd8 | |||
| d11160d2f7 | |||
| 7333008f40 | |||
| cd7d309fd1 | |||
| a4ba1da65a | |||
| 2f9b8b6fc9 | |||
| 279ac6b2b6 | |||
| 9084d9305c | |||
| 80c4213501 | |||
| e0af23a924 | |||
| 7e907b70f6 | |||
| 7fb27b16e8 | |||
| 3fb903d991 | |||
| 2a4a688c2d | |||
| 1487c86262 | |||
| 4d3751028b | |||
| e4c6539964 | |||
| 34b59f062b | |||
| ec4aa8d0b6 | |||
| 1eebe85071 | |||
| db0507e670 | |||
| 1e3ca7dc18 | |||
| 8ca3c5d778 | |||
| df257755f7 | |||
| d7e292a9f8 | |||
| 9fce114e8e | |||
| 9d83424346 | |||
| a29681a524 | |||
| 47d85eb281 | |||
| 85f676c30a | |||
| 8c5fa1c0b8 | |||
| c7690053ae | |||
| 3f55be638d | |||
| 664c824bc0 | |||
| e239d9ca55 | |||
| bf1d9662d7 | |||
| 675c215e6a | |||
| c09bca56f9 | |||
| 7d8f7753d5 | |||
| f77aa65dc5 | |||
| 9589b5984d | |||
| 32806a5af3 | |||
| 876fbe3d7c | |||
| c1b8f5e475 | |||
| cf31ea9cbe | |||
| 7e6b8c93b4 | |||
| dd2bbe4588 | |||
| e01e35713b | |||
| 82d5d9ba58 | |||
| d168492462 | |||
| 6f2e8320a9 | |||
| bf4831f468 | |||
| 5647cf24d2 | |||
| 85f61aded5 | |||
| 21639071c2 | |||
| 68506a789a | |||
| d9ca25b796 | |||
| e9c81477d7 | |||
| 5c20d5e291 | |||
| f89d690716 | |||
| c563efcd1c | |||
| dedeebbfbe | |||
| 35e2a70de0 | |||
| 81d5c86a7a | |||
| db6644bae9 | |||
| 14f1c1a358 | |||
| 5be9bc64a2 | |||
| 64d3a5c8b7 | |||
| ccb4d13a82 | |||
| cbe835a2c8 | |||
| 6a77754adf | |||
| 7d7d5ba734 | |||
| 684fa1c4b0 | |||
| a98d851fde | |||
| 9c3e2dab40 | |||
| eddb68f2fa | |||
| 791091174a | |||
| dd9280c6ea | |||
| a4d83f9fdb | |||
| f42c5c4a5b | |||
| 186fa4f1a1 | |||
| 09292bb87e | |||
| d18a0de879 | |||
| cdc45935b5 | |||
| 43e18148a6 | |||
| b0db645248 | |||
| 07712758a7 | |||
| c1a424a635 | |||
| a49588dbc7 | |||
| 1f22b9b982 | |||
| 1d07d8e08e | |||
| 05b2424fca | |||
| 07201c711e | |||
| 8fac88c9a6 | |||
| c9aafa78ec | |||
| e1c337a483 | |||
| acebe68dfa | |||
| eeef945c25 | |||
| a602753bda | |||
| 812ae77cd7 | |||
| 8b8af1a9d9 | |||
| 493b5cb9b1 | |||
| 1ecd7cc2fe | |||
| 5c38832456 | |||
| d16f07a547 | |||
| 54acb05131 | |||
| 9ddf19f605 | |||
| ff378e4538 | |||
| 2ea0a24795 | |||
| acf28d8170 | |||
| 666a7bb826 | |||
| 1ac20251cf | |||
| a318a19fe2 | |||
| f4a7aec167 | |||
| 9445332499 | |||
| 8edd63d115 | |||
| 304ace1172 | |||
| a5cdf0640f | |||
| 1fc2e43881 | |||
| 0964c9f928 | |||
| 8b1e820869 | |||
| 9edc6966db | |||
| 12207dcb77 | |||
| 2255e36810 | |||
| 5abddd448e | |||
| f022a1b08f | |||
| b3bbfaeff0 | |||
| 679a3d4209 | |||
| a0211d88e7 | |||
| e216fc7798 | |||
| c648ea12f2 | |||
| 2e59373a1e | |||
| a51a81b6cd | |||
| 9809f87010 | |||
| 8794122c2d | |||
| 8fb2270ecf | |||
| c304133224 | |||
| 7843d3de62 | |||
| aef536fff3 | |||
| d472e1ac0e | |||
| 120c08fb75 | |||
| ba6229b92d | |||
| 3d2362cb5f | |||
| a08b9b82a6 | |||
| 5d62fa3f10 | |||
| d3df00f0ba | |||
| 34e84f8b07 | |||
| 1143dc3cae | |||
| 0299d4d44e | |||
| 1d07151743 | |||
| a83fa6f4c6 | |||
| c30fc9d60f | |||
| 311a68160c | |||
| 343aef31c3 | |||
| 3ac8f7e14f | |||
| 0cef66d155 | |||
| 9ffbb9fbf0 | |||
| c9a8f5b456 | |||
| 4e3831e380 | |||
| cae2b3bd14 | |||
| 5637b8602b | |||
| 4af9699b22 | |||
| 35c97e2ff8 | |||
| 83e5cb81e8 | |||
| 7a49a0d986 | |||
| 78cd054d59 | |||
| d33a8eac9c | |||
| 9355ab1656 | |||
| 1f87bfbf2e | |||
| e06429da87 | |||
| 26058763df | |||
| 1f03d23dae | |||
| 2eea074473 | |||
| ed82a18e2a | |||
| 2961a49dc7 | |||
| 5c9151d3e9 | |||
| 90deb9fb43 | |||
| 12489a4c6b | |||
| 74f70ae4bd | |||
| a9ceab0415 | |||
| 94bd74d0bb | |||
| b2d8199480 | |||
| e60f3711f8 | |||
| 6ec9e4f7b8 | |||
| 9eb3834ae5 | |||
| ee57cf3e9a | |||
| fea5d1d82b | |||
| c84a30d4dd | |||
| 24d91eee90 | |||
| a5318448f5 | |||
| b7c40eeb57 | |||
| e7c9be1875 | |||
| 8f1b314802 | |||
| da6794c8ce | |||
| e926beba5a | |||
| 3ad053cf6d | |||
| bc11469a0b | |||
| a00695bdac | |||
| 89959b800c | |||
| 3e19c3b62e | |||
| d970debb4d | |||
| d0ba52073f | |||
| 943e3b6f51 | |||
| 25d43682aa | |||
| ad16de59f8 | |||
| 8634bbb792 | |||
| 60ec5d30fd | |||
| 7667fe6ca5 | |||
| 4b5a8196c3 | |||
| 706c0816dd | |||
| a8aa89362d | |||
| 7964698ae5 | |||
| 65664b0d65 | |||
| 08bfa0971e | |||
| 912c5ea0bf | |||
| 6cdf5a5a7f | |||
| 50ba743faf | |||
| e26aac3067 | |||
| 941e8aa5d5 | |||
| 33b6536e6b | |||
| 9fbd9288b2 | |||
| bef1a56007 | |||
| bc71ff5e81 | |||
| bd50444d06 | |||
| 2efd6f92b2 | |||
| 7fdfad4088 | |||
| 31a1968798 | |||
| b0bd4ad546 | |||
| dc454b9a6a | |||
| f06e5d33e7 | |||
| efdbd1576f | |||
| 0421fbdc25 | |||
| bd426199f8 | |||
| 8e00b3d110 | |||
| 6fbf1469aa | |||
| 280d3fd919 | |||
| 40ce95b87f | |||
| e7d644b874 | |||
| c64159d5c3 | |||
| e2ccc3026f | |||
| 2af6066ee3 | |||
| fc16b5331c | |||
| b2723a0c5f | |||
| 01042a24f0 | |||
| f9643b3881 | |||
| d2d18bea5d | |||
| 87e595b83e | |||
| 08031b1227 | |||
| 9a87c1f734 | |||
| edeb667ead | |||
| db2aa495b8 | |||
| ddfb591094 | |||
| e8f1ba3722 | |||
| 19c4f34ccb | |||
| 5d9e9c021a | |||
| 6a924db68c | |||
| 9d0990e5e8 | |||
| 3207f5d61f | |||
| c72b351bba | |||
| 1f9b296ae7 | |||
| e3e2e7b4df | |||
| 4ec8f4a4bf | |||
| 05d59a05df | |||
| 11ccbe6506 | |||
| 673711a246 | |||
| fff5139d80 | |||
| 812e70c626 | |||
| db7ffcf9d5 | |||
| 8f6cb9c057 | |||
| 291f298d19 | |||
| d60f12d3b8 | |||
| b8a2573bb4 | |||
| 7ce8e610f5 | |||
| 839b9c8f07 | |||
| db20801521 | |||
| 160a9278c9 | |||
| ee507de154 | |||
| dc0fa49de2 | |||
| b678541427 | |||
| 6c4cd0d8cb | |||
| c096d3cd42 | |||
| dcdab4df21 | |||
| 9803209ba1 | |||
| f166cb09ec | |||
| 2dd8b76289 | |||
| 2bf7c67767 | |||
| dd636ffcb2 | |||
| a44c45ff9e | |||
| dc2a455395 | |||
| c700d9f714 | |||
| 59cfc339b0 | |||
| e06c07ca89 | |||
| 6facd54a7e | |||
| 6f8d850726 | |||
| f3beee9874 | |||
| 35e063bdaf | |||
| 09175d1799 | |||
| 46f9a9053f | |||
| bb86520094 | |||
| c1e2c660bf | |||
| 89c0ff1a9d | |||
| 7a68ce7e94 | |||
| 9537922acc | |||
| a39aa73e21 | |||
| f1d12c330e | |||
| 82c8eeb4be | |||
| 3a951f4830 | |||
| 998ea25fb9 | |||
| 7b580b8f56 | |||
| 641ccfdd47 | |||
| 4288f70d04 | |||
| 95fda5dfb7 | |||
| 1903c5e0c6 | |||
| 362501a097 | |||
| 72982e3c2b | |||
| 04d24bce70 | |||
| 2f38306c6b | |||
| 4b36e5197d | |||
| b755cf3e42 | |||
| 3acad7c911 | |||
| f3319016c4 | |||
| 4e14f7d483 | |||
| 979059c804 | |||
| bdf4423512 | |||
| c6ef4b5840 | |||
| acd792d8b4 | |||
| fc730679ed | |||
| 00e5749e20 | |||
| 7b4d349574 | |||
| dc0cccfb6c | |||
| fdc1daefb6 | |||
| c9159b81c8 | |||
| 9233049356 | |||
| bd9015e474 | |||
| 3a79540d2d | |||
| 9e500dc387 | |||
| e05a735589 | |||
| 0be18c4a53 | |||
| e258fde25a | |||
| 7367672570 | |||
| b822d42889 | |||
| 10084ff1bb | |||
| c3c69ac727 | |||
| 0cfda6f6a7 | |||
| dc51ce9e92 | |||
| aa0de2b00e | |||
| 5f61581e1d | |||
| f519cb2cc0 | |||
| 37aef630d2 | |||
| d93fcff5db | |||
| 4952a82af5 | |||
| fecda6a034 | |||
| 9f0addbd8b | |||
| 7f8ea6b8e0 | |||
| 9d3ea6fed7 | |||
| 703b3eda56 | |||
| 84006e1e77 | |||
| 73fb085a41 | |||
| c89780178f | |||
| 2ac3976924 | |||
| ac9dbd24e4 | |||
| 3af9830a2e | |||
| da6b8eb2ab | |||
| da39e98adf | |||
| 791a541381 | |||
| 56684e753b | |||
| c7298edf65 | |||
| 30215963b2 | |||
| f15f88ebd6 | |||
| 391fc0c4c2 | |||
| 948ef2c820 | |||
| c1b6b6b76a | |||
| a8bb07052e | |||
| 6976a2dae7 | |||
| 51cd951b4c | |||
| 16a5a234c1 | |||
| f994210927 | |||
| aaa8760d09 | |||
| cea19ecc31 | |||
| 706cfeb443 | |||
| d9c91589f0 | |||
| 9854691265 | |||
| 32afa33a06 | |||
| c6946d0145 | |||
| abbe7b79d6 | |||
| e4abe75043 | |||
| b904503691 | |||
| 2db42dfb2e | |||
| 10bd24e585 | |||
| f926e599fa | |||
| e7b518ba67 | |||
| a4698f0bde | |||
| 9a6eae69ba | |||
| 0ff365c7f0 | |||
| 214e7a5672 | |||
| 24b69a6dea | |||
| 699235147c | |||
| 72ad413a61 | |||
| f11bb082e4 | |||
| 2f3fd6867d | |||
| 350ae90bb6 | |||
| fb61cab70d | |||
| 1d6c08478d | |||
| 0dfe0b7023 | |||
| def236b7cd | |||
| 247743ef9c | |||
| 49122cf729 | |||
| 84f579be81 | |||
| 3d5f23a1b2 | |||
| 8b26b6604d | |||
| f88e55ffa8 | |||
| 34bdcb12e5 | |||
| 95b353dae5 | |||
| 6560f229b1 | |||
| 8c9ab2d68c | |||
| 8496726ab1 | |||
| 32d7f429f8 | |||
| 0f52f49188 | |||
| b334259a07 | |||
| 74af4e9150 | |||
| 8b7790ded2 | |||
| 3e97a82af0 | |||
| 0066b20413 | |||
| 9d6656451a | |||
| 32f980e259 | |||
| ca9361abc1 | |||
| 36cb3d56fe | |||
| 0bece8a54c | |||
| 70bbdbd8f5 | |||
| df8365f0c7 | |||
| 974aae2ebe | |||
| ceca93c8b1 | |||
| b6793cc6f2 | |||
| 809d07546a | |||
| 804cbeb1a7 | |||
| c07188a60e | |||
| 3804d4332b | |||
| 064aaef6c3 | |||
| ce262a5d2d | |||
| d128f4d70b | |||
| 46d1ada708 | |||
| 2819e5f647 | |||
| c2017a5181 | |||
| 58ad839136 | |||
| 8ed5a71c45 | |||
| 57050a83ba | |||
| 6ed0e84421 | |||
| 9b09d2b47a | |||
| 1a6c5deb4b | |||
| 45a73b00de | |||
| 59fff26a5f | |||
| fde4d4662e | |||
| c9355ad94a | |||
| bad3b8b3e2 | |||
| 0b81bb9b10 | |||
| f61c78efd5 | |||
| 6b2307ab22 | |||
| 9ccb381c31 | |||
| 71133236f8 | |||
| e5786fe435 | |||
| ef6ee78fd1 | |||
| 695262624d | |||
| c96c264801 | |||
| af0bca74e4 | |||
| f41e254e35 | |||
| 7e472a9c1d | |||
| ee3f10313a | |||
| 5b587d199e | |||
| 009b073892 | |||
| 92e962430b | |||
| 3aa20a3a32 | |||
| de7c3d3d29 | |||
| 3f89df338e | |||
| c7f89c9b77 | |||
| a107e463e8 | |||
| 7a5cfe1728 | |||
| 7ad3f967db | |||
| d1c814cf9d | |||
| 72f85dce2b | |||
| f5bbcc017c | |||
| 2980173c8e | |||
| a84c348045 | |||
| d845ecc811 | |||
| 064d9009a2 | |||
| b6aa5bdfab | |||
| a3bdf0456e | |||
| e3ecf05866 | |||
| 6240374dd1 | |||
| e17ee831a7 | |||
| aef9bd6357 | |||
| 8857227a35 | |||
| 937250c681 | |||
| 66d3a1d025 | |||
| 647fedfa19 | |||
| c593d3ed75 | |||
| bd885a01e5 | |||
| 628825fdff | |||
| 46dd411273 | |||
| 2e2ee11452 | |||
| ce0df333b3 | |||
| 8bbda78272 | |||
| 945509fc93 | |||
| b586917930 | |||
| 45ad6082bc | |||
| f27823babe | |||
| 95cfac471a | |||
| f7c1084c3e | |||
| cf96bb6cc3 | |||
| f1369c8fd6 | |||
| eb7922ab88 | |||
| dfdfb7cdaf | |||
| 1cc0fb9c01 | |||
| a51b589bc9 | |||
| 5940e912b3 | |||
| 658a001d91 | |||
| 57c9f5a8a8 | |||
| fa7b58057c | |||
| 0e0f5295cf | |||
| 284c9e5f61 | |||
| 927fbda1e8 | |||
| d25a5034db | |||
| f197d39aaf | |||
| 4a95343936 | |||
| 4e705a91af | |||
| 82b351469b | |||
| ea91bdcce7 | |||
| 256c9daefd | |||
| af0a46e79c | |||
| 4519c48284 | |||
| 8ea32c7650 | |||
| 5972d40ced | |||
| f35a6b3922 | |||
| 21009c37b4 | |||
| 11a2d15003 | |||
| d8a695a88d | |||
| f82390424b | |||
| 08ed405a5b | |||
| 8c598a6902 | |||
| 8e9c40caa4 | |||
| 8c29036fbf | |||
| b46337d376 | |||
| 56d701492b | |||
| 07e4e764a0 | |||
| 66fe2f2e50 | |||
| fda0ced72e | |||
| 654e8bb7f6 | |||
| 80ffde5e1e | |||
| 52309e0754 | |||
| 31e411f8f1 | |||
| de45b760b5 | |||
| ff29e9c4d6 | |||
| cc04bd0f06 | |||
| e72e1e4e43 | |||
| 987cc3c237 | |||
| 935f69e011 | |||
| 9f0c2fb6e2 | |||
| 9b18bda9c8 | |||
| 7831c74e8c | |||
| c1978f9133 | |||
| 05affda20c | |||
| e2eb555ca0 | |||
| 418c3c9cfa | |||
| bc66e181a5 | |||
| 6971f76bd3 | |||
| 1e65f02ff7 | |||
| 4efaf65d3f | |||
| aa0249fadb | |||
| 2c65590134 | |||
| a0d1a9ad67 | |||
| 5df6270e32 | |||
| 7af6e1cd34 | |||
| cceb066284 | |||
| 7a054787ca | |||
| d27891c79f | |||
| 5874fd640e | |||
| 11ae220dbe | |||
| 22542a3a71 | |||
| e16fb6a8e9 | |||
| d941e6d70b | |||
| b65068dc7d | |||
| d5301508ec | |||
| 793cca423b | |||
| 3960687f9d | |||
| 3ec7aad432 | |||
| 84f1ad4f26 | |||
| 6b9dbf625d | |||
| 3aea2c007d | |||
| 85d195212a | |||
| 8a663cb94f | |||
| 674e194a91 | |||
| c57f0abb56 | |||
| 163fdcd582 | |||
| 3be17c6117 | |||
| 995dfa1455 | |||
| 544c8dbc13 | |||
| 8da4f80453 | |||
| 6084aae603 | |||
| e1319a06f2 | |||
| 51fd7a607d | |||
| 8aff315c7b | |||
| 8e0d79f301 | |||
| 8a0269d29e | |||
| 892e16dfb1 | |||
| 92e4078287 | |||
| 41e1819072 | |||
| fb7e9719a1 | |||
| c2d09b64ca | |||
| 1b2aa6c2da | |||
| a5b4cee298 | |||
| 17f1ac10e3 | |||
| c67198032f | |||
| 107b092982 | |||
| bac06e45a4 | |||
| 0e8a68831c | |||
| 5912abd541 | |||
| 13d33995cb | |||
| c8c05f62b4 | |||
| 944b045885 | |||
| 19897ffa26 | |||
| 42a10b21c7 | |||
| 5df0e25c1f | |||
| ebf2b16d09 | |||
| f2eaab6e43 | |||
| a847823411 | |||
| fe9a8b542a | |||
| cd101b6844 | |||
| 69229102c4 | |||
| 4bc3630d19 | |||
| ab00686ac9 | |||
| c3004a038f | |||
| 9cf9d8847b | |||
| 0a3c10566b | |||
| c94243e107 | |||
| 505388b9fa | |||
| 7314cf708c | |||
| 3e6a4f2b16 | |||
| c7c3dd7662 | |||
| e4f025edd6 | |||
| 96f3efbf86 | |||
| 2b2130ff42 | |||
| 463ce05da0 | |||
| fa4095ba95 | |||
| db571b4859 | |||
| e8491b34b8 | |||
| 521457eb92 | |||
| f26a445ce6 | |||
| f73bb242f3 | |||
| 9e895e5286 | |||
| 5b0e5512a8 | |||
| 850b3284ac | |||
| 05a727979a | |||
| d68c88c3f9 | |||
| 5f07d53034 | |||
| fe62ce4bae | |||
| fb09aa4d06 | |||
| 4d080b30ab | |||
| 2d314e72fe | |||
| cf07b747fe | |||
| 273e9bbc92 | |||
| 7dcf1797e9 | |||
| 7aa24b6157 | |||
| d73a667437 | |||
| 4695fa061d | |||
| 7bf7bfbe13 | |||
| 397219c22e | |||
| 83c0ef3514 | |||
| 4fa40de557 | |||
| bc06926702 | |||
| 9de27110e2 | |||
| 93e5d09a63 | |||
| 0cbc39698c | |||
| 83069e433f | |||
| bbb490b24f | |||
| 85f200bd86 | |||
| 0f2c02fb04 | |||
| 6d3d41abe2 | |||
| 6fa7fe26dc | |||
| fe804c123d | |||
| dba32fb95d | |||
| 7dc187fdb1 | |||
| ee5a627952 | |||
| 3b83561309 | |||
| 6fb0b5203a | |||
| 4677d7a1c6 | |||
| 3283359ac8 | |||
| fff16f6b8c | |||
| a347ceba74 | |||
| 05836fab4c | |||
| 15e84f28ed | |||
| 32c35a822b | |||
| 9c86e5e54d | |||
| 87f348b48e | |||
| ff289b25b6 | |||
| a9f58e96d2 | |||
| c61ded8a1e | |||
| 7651ca747d | |||
| 7ff7a4aa87 | |||
| cdcd226b1a | |||
| f9451915b9 | |||
| 5e4e174d61 | |||
| 4a00cb7d55 | |||
| b97c123764 | |||
| 69bdff6b7e | |||
| 8574fcf6e1 | |||
| f4f424bf04 | |||
| ac745bfa3d | |||
| aa691f236e | |||
| a0a9d49d81 | |||
| 125f8b591d | |||
| c97b60e7e5 | |||
| 8a73414e3e | |||
| ac22e006a4 | |||
| 30d5d85d1d | |||
| 6f74f3c386 | |||
| 515918329c | |||
| 8ea0a67280 | |||
| 5ad7d7edb1 | |||
| 00c6820825 | |||
| 6beaafcf11 | |||
| e92f039a17 | |||
| ef76ffa1c1 | |||
| 652eb2346c | |||
| 66726090ec | |||
| b668173cba | |||
| a7e20d6e85 | |||
| c6ded82406 | |||
| a76c6faffc | |||
| 81ff71a97f | |||
| 56db0efe58 | |||
| 5eefd98e1b | |||
| eecdad50a6 | |||
| 96d5ed9cc7 | |||
| 73090ecb37 | |||
| 8812704601 | |||
| 0f189d410e | |||
| cfeabc4580 | |||
| 49f203d61d | |||
| a912a4dc67 | |||
| f79db874bf | |||
| 8de19aff3c | |||
| bf41b448d6 | |||
| 448632cf11 | |||
| 11174bfa14 | |||
| 84b1f3990c | |||
| 943069b2a3 | |||
| e305698e6b | |||
| 4c0b7d44b4 | |||
| 775c77c0fa | |||
| fb466b5af7 | |||
| e473118ec8 | |||
| 755d41ca4e | |||
| bbff9f89b0 | |||
| fdcb38ac1f | |||
| fac742c038 | |||
| 5a6b43fc90 | |||
| 317f413746 | |||
| 895909b7fa | |||
| 2ee8b6c8b4 | |||
| 022bb69782 | |||
| be6da3e0db | |||
| 1f07e02298 | |||
| 7a645b8555 | |||
| c5b0d0235f | |||
| b7948551ff | |||
| e109b5cff6 | |||
| 9883fb7bf6 | |||
| e9f8471a28 | |||
| 4656b11256 | |||
| f2ccab2df7 | |||
| b2e3aefa72 | |||
| 2b48933f29 | |||
| 4ac6cbe70e | |||
| cc07c3df94 | |||
| 31bcad2535 | |||
| b75970958e | |||
| 91756c057e | |||
| df7f245cf8 | |||
| dbdefa0f4a | |||
| 56fdf6002c | |||
| c957f1ddca | |||
| 423386a052 | |||
| 1c882ea361 | |||
| b1065fa01d | |||
| 8ff9c030bf | |||
| 9b875fb930 | |||
| 857bac4b78 | |||
| 30074c290d | |||
| 60d1c26114 | |||
| 692ba43182 | |||
| 6542a037df | |||
| 9f4b451501 | |||
| 1bd454b8fd | |||
| 8392472bac | |||
| cd5b351ce4 | |||
| 50024fbf8b | |||
| 4d4fb3b6ec | |||
| 37dea8aee7 | |||
| 69c4940b27 | |||
| 7691b019e2 | |||
| f55d6b11c5 | |||
| f52877abb4 | |||
| ee7c9b6731 | |||
| 4721344518 | |||
| e0d986dcd7 | |||
| c7be3dcd5b | |||
| 89c9bfd052 | |||
| 12b93567f7 | |||
| 2f37776614 | |||
| f778bca3f2 | |||
| a945d19750 | |||
| 7f04b2c96c | |||
| 8aa4e4ff1e | |||
| 7eade002a7 | |||
| a8f8d27f4e | |||
| 356935bd4f | |||
| bce3dd045f | |||
| 79a2b84c81 | |||
| 44b762f916 | |||
| 5d80c880c8 | |||
| b907263f35 | |||
| 0f0accf82c | |||
| ddcf414107 | |||
| 6be3b1d7f2 | |||
| 0e0d7016b3 | |||
| 553c76ab0f | |||
| b90cfa8e5c | |||
| e7f0cd0c4b | |||
| 0661b339a0 | |||
| d1bb72f6fb | |||
| 1bcd1edbf5 | |||
| 143a00626b | |||
| 0eb981f51c | |||
| 6cc01349f7 | |||
| a7bd4acd46 | |||
| 8e0a56b49a | |||
| a8844ddd28 | |||
| c18fefd5f3 | |||
| 3040940e35 | |||
| df3d2d57c3 | |||
| 92d26f2216 | |||
| 0380c68f89 | |||
| 2a6dc6a7b7 | |||
| 40617f0d5c | |||
| 09745a7835 | |||
| 57f6f50939 | |||
| f959905adf | |||
| f78c7e7926 | |||
| 96496da0ab | |||
| 2dc4733ac1 | |||
| f14774d034 | |||
| c08c63f420 | |||
| eb79c6c47c | |||
| bf1cbb4cde | |||
| 592675022e | |||
| b2e10d7e6e | |||
| 0689954433 | |||
| 5c37f198cb | |||
| 3b02a9d4fe | |||
| c9057aa498 | |||
| 2b0d198b05 | |||
| 7798145c74 | |||
| fcfadd7c74 | |||
| c0181820a9 | |||
| 76d4e6bd18 | |||
| ccb81de85d | |||
| 82f4975f45 | |||
| d457e6ad6a | |||
| abf7c8e68a | |||
| 1a38d0c31e | |||
| 9ff9d679e9 | |||
| 9f3f8f950a | |||
| 006a196e4a | |||
| 418678466c | |||
| 9f4cb5c4dd | |||
| 73f9de6635 | |||
| 12b9c82086 | |||
| a8edb8870e | |||
| dabc3c6cc4 | |||
| cc7c1ad30d | |||
| 4d840a8d9a | |||
| 95a80bfe81 | |||
| 53e9eab0cd | |||
| 35b3c3c98c | |||
| 20e17a28cf | |||
| 28bf2d6374 | |||
| 8a00b53050 | |||
| 8834241417 | |||
| 96740d6be4 | |||
| b853d29992 | |||
| 33a0f562d3 | |||
| f8e3ae0525 | |||
| c790bad667 | |||
| d54489bbcb | |||
| 808c97020a | |||
| 34e680d792 | |||
| 32d543943b | |||
| 2632507980 | |||
| f467a9a309 | |||
| 5c9710c78b | |||
| 107b31a0b5 | |||
| 028c7a822f | |||
| 18f5f98e62 | |||
| 543bb3cc4b | |||
| 1c44d24b76 | |||
| 5305f962c0 | |||
| b774f147da | |||
| 2a5921b9c9 | |||
| 60cb392e97 | |||
| d012c538c3 | |||
| 1c88d0d7f7 | |||
| 773b8de8ba | |||
| 5d8dd090a9 | |||
| 2cbfe70a28 | |||
| 16dbfbb267 | |||
| 99fc7817c6 | |||
| 265b4c2b22 | |||
| db9db2cc40 | |||
| 3642eabac0 | |||
| 98e05fd179 | |||
| 1ccff9478f | |||
| 85f9b585f5 | |||
| 01626b4c9f | |||
| a85841ca76 | |||
| fe6c4cd0b5 | |||
| f1585d09e1 | |||
| 252784ff5b | |||
| 6f9dc2a9b8 | |||
| 7edfae8583 | |||
| 28275d86ea | |||
| 2d19b5074e | |||
| e62cc17797 | |||
| 407eed212a | |||
| 12d47858c1 | |||
| 3d34e6e6d9 | |||
| dc188e601a | |||
| 8a2df23260 | |||
| 46079a8612 | |||
| 201d752850 | |||
| 63b3d9875d | |||
| 8cd2d772b0 | |||
| 2ff3f88b4d | |||
| ab4dd6a268 | |||
| 0094efc7f4 | |||
| d73a270fb1 | |||
| d9647868cc | |||
| 85505b0482 | |||
| 703c1a485c | |||
| 9258c73484 | |||
| 6858546ce9 | |||
| 7c6966a9c4 | |||
| 40d1d20cd6 | |||
| c0942d78cb | |||
| cef8779bf7 | |||
| d6667844de | |||
| 4cdf218145 | |||
| 994713d04c | |||
| 554b13ac50 | |||
| 439fb57d88 | |||
| 4409d0f03f | |||
| ebd00b1eb2 | |||
| 3ca0ef1583 | |||
| 88abbd90dc | |||
| bdbde25784 | |||
| ee9e941a56 | |||
| ac90800c3c | |||
| 08f5833ca8 | |||
| 4bcd3ed86f | |||
| 254fd80088 | |||
| d7e6df1e44 | |||
| a933fabb86 | |||
| 36baf7b0af | |||
| e6026cb0b8 | |||
| cc2b4967ea | |||
| cf59f89bfb | |||
| 066ed7e4a1 | |||
| 4f49d60e4a | |||
| 3721dadd72 | |||
| 5539d5eed0 | |||
| 64002626b9 | |||
| 4b1c20fa36 | |||
| b418683337 | |||
| 00015285ab | |||
| 0f936fc163 | |||
| 15045cc486 | |||
| c9132d984b | |||
| a0123e7c2d | |||
| be786be67d | |||
| e85b18e206 | |||
| f32f62dfc1 | |||
| 28392050bf | |||
| b9cc6063ff | |||
| 9066e62a97 | |||
| 5549696c3a | |||
| 691c9fe8e0 | |||
| 04463675c0 | |||
| b9da6a4a5d | |||
| 9fb161c320 | |||
| 2ba25b4c28 | |||
| c1618e2b5d | |||
| 788f5429e1 | |||
| 36026d4ec6 | |||
| 96767f5ca8 | |||
| 76bad31dd5 | |||
| 2e3b917192 | |||
| 95f262b3e6 | |||
| aebacb6b6a | |||
| 27613da5ea | |||
| 28ac6c2267 | |||
| 1c1fc65c7c | |||
| ba74b352bd | |||
| 0474ac4262 | |||
| aba49cc93f | |||
| b3b5b40163 | |||
| 0e085b30cc | |||
| 35149b6960 | |||
| 3800d5420e | |||
| b145c1ab64 | |||
| b8a3439219 | |||
| 1a153b835c | |||
| 73c292c4e9 | |||
| d8bb0b53f8 | |||
| 83c66901f8 | |||
| 088f77a226 | |||
| 4dd6c85df2 | |||
| d0452a3510 | |||
| 11310e7615 | |||
| 22b32a0fe5 | |||
| ad143c184f | |||
| 803a4cd163 | |||
| 267fdf9fa1 | |||
| 26d2a4420e | |||
| c623ad7da0 | |||
| 7de689055c | |||
| 63b15a8855 | |||
| a2a7302964 | |||
| 6a5367dbe3 | |||
| 6768a18475 | |||
| 242ed4a3c2 | |||
| f9b70d1b5b | |||
| faa5252191 | |||
| 4212f48d7a | |||
| b30a79c7fe | |||
| 22374ac8f7 | |||
| 17014bb8de | |||
| d1c3d3d5aa | |||
| 7fedd94cc5 | |||
| 48eca3d031 | |||
| 21d3cf91a0 | |||
| 5938cc4086 | |||
| 7c57d736c6 | |||
| cbe3f2a4ac | |||
| 7a10e0e347 | |||
| efb577769e | |||
| 8c569ac7bf | |||
| a84fb57e32 | |||
| 7314d2b577 | |||
| ba83ede0d1 | |||
| 42500ce043 | |||
| caa8c1da90 | |||
| cbcb9f9044 | |||
| 60bffb5f49 | |||
| 2a16a67aed | |||
| c6cd185cb5 | |||
| 58cdcf754c | |||
| d969f5df7b | |||
| b6455e0661 | |||
| 15021b442c | |||
| ee078fc638 | |||
| 9893c90e74 | |||
| 82978da5e3 | |||
| 80ce9d546a | |||
| 34775633b2 | |||
| 03b5c8e76e | |||
| 766b8cd62e | |||
| 609067cefa | |||
| 9d497ad311 | |||
| 72059a9441 | |||
| ebecbb69ec | |||
| b129bab81a | |||
| 14c70c5cc8 | |||
| d62a67502e | |||
| 4b2c303873 | |||
| d189f00f38 | |||
| a5cf92b2ff | |||
| 8c45249c06 | |||
| 55c8a15983 | |||
| 3607e2e759 | |||
| d035068982 | |||
| af8156f310 | |||
| 47b995a2a3 | |||
| 6f8f99f42c | |||
| 69137cddab | |||
| 9caa3030ea | |||
| 3e9826acf5 | |||
| d7b4f54983 | |||
| 00b0dcd306 | |||
| 53c356a940 | |||
| a7f3351c0e | |||
| 3a6cdfff45 | |||
| c26e347e91 | |||
| 1b94957b07 | |||
| 2e39668605 | |||
| 0642c569b4 | |||
| 4e364bd2f6 | |||
| b9fe564d78 | |||
| 437fa45ca2 | |||
| 85e215650c | |||
| 7eb186dad4 | |||
| 2259614640 | |||
| a584e1a4ec | |||
| 869f4011a1 | |||
| 463bb72d24 | |||
| 8b312a47e6 | |||
| 46d4e32510 | |||
| 1815a913c3 | |||
| a7e06715ba | |||
| a89fd95864 | |||
| 9ba9469bb1 | |||
| 4dbf173ed4 | |||
| 8936cca9cf | |||
| 1c704680a8 | |||
| 3e36834751 | |||
| 581caff638 | |||
| 8b612ba547 | |||
| 90820f24a4 | |||
| 12a37500b0 | |||
| 3ae6ffdb01 | |||
| c4e76b391e | |||
| cf9ba737f0 | |||
| 2d0690ae2d | |||
| 71a2d0971f | |||
| 3bf57e0748 | |||
| fbc0319cb6 | |||
| e8bc3c2d80 | |||
| fe192e07fb | |||
| 51b6329c86 | |||
| 72d9e4c1e7 | |||
| cb7d5c9d09 | |||
| 097ab82529 | |||
| ccb603d77f | |||
| d7b02db832 | |||
| 56cc5da9fb | |||
| 1903079f96 | |||
| b6d0950ee9 | |||
| c1a32a4041 | |||
| 8fa443879c | |||
| 3a465cb94f | |||
| 49133dce48 | |||
| 3b7b6beca5 | |||
| 0dd81328ff | |||
| a668593e6b | |||
| 3a5a22511a | |||
| 86859267f0 | |||
| 88c9f6d233 | |||
| 176693dd5a | |||
| 62bee04fc0 | |||
| 0a5aacfd87 | |||
| 2dec3a6c95 | |||
| fcc2814199 | |||
| bc93d238dd | |||
| 79e2c5d48c | |||
| 0fab7ad63b | |||
| e6a2f55a59 | |||
| 67e9ca56ac | |||
| 713daf6cd3 | |||
| 12abe81c6d | |||
| fbcf10c86d | |||
| 415b20f884 | |||
| d58ca5f37a | |||
| 11b6ee423e | |||
| a10ca47657 | |||
| ad1f175a39 | |||
| fd3246113a | |||
| b8013c883c | |||
| ffcc4fd03a | |||
| 9d97964998 | |||
| f0e54cdd51 | |||
| 0360fd1efe | |||
| 4508e099ff | |||
| 6ed1435aeb | |||
| 6346e288ad | |||
| d2b503910f | |||
| 747c3b2a4b | |||
| cccb4e6d5e | |||
| f4c6afbdae | |||
| d1ef380e6b | |||
| c02de2580d | |||
| a231f8587e | |||
| 4149748766 | |||
| 783627c315 | |||
| 1ff6aa1748 | |||
| 6662dc4a8d | |||
| d6b170e274 | |||
| 11cac7a646 | |||
| 9c2fcd745c | |||
| 04f49a6819 | |||
| d465ea2a67 | |||
| 1f5073d0ac | |||
| 8dbbbc1a1a | |||
| f985673dc3 | |||
| a6fc3cf7a6 | |||
| 1941885cfd | |||
| 88a86a9927 | |||
| 48e030bca3 | |||
| 6f118c1be1 | |||
| 7316eb87b8 | |||
| 5376236ab6 | |||
| 0af80d48ee | |||
| 793c0368f2 | |||
| 076001462e | |||
| d2e1d8ec13 | |||
| 30ceaa6bef | |||
| 0247d47a3d | |||
| 480368c878 | |||
| c1d8790623 | |||
| fb1ffec5bb | |||
| 1bdabe693f | |||
| ce09f35275 | |||
| 40c13043b3 | |||
| e620068416 | |||
| 8e624ca85a | |||
| c7afd46016 | |||
| 3573656244 | |||
| 1de6de975a | |||
| 15c55b8c7d | |||
| 865061b492 | |||
| 39313e1737 | |||
| 70880636f4 | |||
| 96a5ba0ed3 | |||
| 8054f6c618 | |||
| 658ea68d04 | |||
| 5750f87396 | |||
| 1253e2a458 | |||
| 857b3e92f8 | |||
| 8bf14d542e | |||
| 31d2a39540 | |||
| 97718b4046 | |||
| c07fd265f0 | |||
| 1de50a2a94 | |||
| 627ca432cc | |||
| f8ef11b4d2 | |||
| 71563034a7 | |||
| aaff5a65e1 | |||
| 458a362f98 | |||
| 36d07065fb | |||
| f206e72447 | |||
| 58e45fb394 | |||
| 411f32c766 | |||
| e1b82e4e43 | |||
| df613775b6 | |||
| 5e8fdc997a | |||
| 51bfe4252d | |||
| c96aee5740 | |||
| 1c08849667 | |||
| 73349e5e75 | |||
| 74ae411b69 | |||
| d458592fb1 | |||
| 627c89a62d | |||
| 0228cd4f31 | |||
| a859558840 | |||
| 04eee2ea75 | |||
| bda2c663da | |||
| 5e041e6e5a | |||
| d19264eea8 | |||
| 64c52012df | |||
| 7542e55cb2 | |||
| 6bd51ac345 | |||
| cf21eb4b39 | |||
| da8170c5b6 | |||
| 12bc7480e0 | |||
| 92862fdf39 | |||
| 4417268ecc | |||
| 346853ee55 | |||
| a82f00cb70 | |||
| 1838ea5c30 | |||
| a356d90445 | |||
| a3f41fd4d9 | |||
| f4be37700f | |||
| ed19bb11fe | |||
| 07275ecb5f | |||
| 2464fccadd | |||
| 5fde2cf91a | |||
| d57e797147 | |||
| 988f7b0561 | |||
| e99a271465 | |||
| d266c7f93b | |||
| d7e5c56e94 | |||
| ddd3b4c093 | |||
| 3a6fc4c197 | |||
| 91381546d5 | |||
| 41e2b898ab | |||
| 6e981d1222 | |||
| 8317bb13ca | |||
| c40f244dff | |||
| a6aa048be0 | |||
| 8fd0162393 | |||
| f0b18da881 | |||
| 5f63ea8f8a | |||
| 2b43569927 | |||
| 4ba33175cf | |||
| 3edc1af560 | |||
| 55fbd09e45 | |||
| 6a46a25f48 | |||
| 88b8ca5b29 | |||
| fdddb556ae | |||
| d36b64e0c8 | |||
| 8adc97980a | |||
| dab6e5a60f | |||
| 0b05e9827b | |||
| 1c1a76d6d7 | |||
| df4f37d68d | |||
| 44629ba5dd | |||
| 2da6776451 | |||
| a68f411024 | |||
| 166550fbba | |||
| 3e68981b0b | |||
| 6fd76e8d1e | |||
| dfcd15e7c4 | |||
| 5fa359c28d | |||
| 5bcfc9dd50 | |||
| f67cad326a | |||
| 9775e83374 | |||
| 264d1798dc | |||
| 1824988b9a | |||
| c54d9b3f60 | |||
| f432d3fcf8 | |||
| 4f7828bab9 | |||
| ae073a336d | |||
| 6f90974896 | |||
| 4f3c05851c | |||
| 4b13055125 | |||
| d542cd811d | |||
| f75cebac7e | |||
| e302b6b635 | |||
| f709e88994 | |||
| ab9a6d583b | |||
| 26d6bf338e | |||
| b6e040dfc2 | |||
| f5802ca3e5 | |||
| 7223e581a2 | |||
| 2d11ce9669 | |||
| e4982a1a5c | |||
| cea6dedccc | |||
| e6ed5a388d | |||
| b89fc3fe87 | |||
| 57ae74f908 | |||
| 1a6804b4b4 | |||
| 82e6a3582d | |||
| 11a4e4faa2 | |||
| 50a3533322 | |||
| 4e9f39384a | |||
| 39802b56c1 | |||
| ebb87ccdde | |||
| f0e55938c1 | |||
| 348d04f7f5 | |||
| 1b0086217c | |||
| d395cf38b7 | |||
| 57aec2a733 | |||
| ae89237453 | |||
| 60d5257678 | |||
| d59463d11b | |||
| 1280528e4e | |||
| 23d6205659 | |||
| bc0acc6f44 | |||
| b8622f2b4b | |||
| 7f0c39fe91 | |||
| a489be0e05 | |||
| 8e08046519 | |||
| 999eb53364 | |||
| f7e549e412 | |||
| fbb99de728 | |||
| 0620ed3d4f | |||
| b779b3cf2d | |||
| a6b973003b | |||
| e431e90b20 | |||
| 4aa466b948 | |||
| 04ae53b6df | |||
| 3666525d24 | |||
| f1a4bbce53 | |||
| 708a720d9d | |||
| 7177da7d62 | |||
| 5e4aa75e03 | |||
| d88ee5c9ee | |||
| d4ea720239 | |||
| 97ee370ffe | |||
| a084f83f4c | |||
| 54732edff4 | |||
| 1a24d1839f | |||
| c3040a04a3 | |||
| 7feb4c4ebd | |||
| 2911d1f018 | |||
| d68ad893f0 | |||
| 4ca147699d | |||
| abed41b8fa | |||
| 2604a55f80 | |||
| 39667de662 | |||
| 8956835d95 | |||
| ea4ec2eafc | |||
| 3a352078de | |||
| 6060b39548 | |||
| dce2436b2c | |||
| 2b52ea4c6f | |||
| b41738b47b | |||
| 57e76a65a4 | |||
| 7f25ddc229 | |||
| 163961df4f | |||
| 97da386ed6 | |||
| c706829a91 | |||
| 6cd246a38e | |||
| 43e88c0ae0 | |||
| bf01b935bd | |||
| 98c011e6a6 | |||
| 86dcb5c471 | |||
| 467ac6c365 | |||
| c77ad5fb34 | |||
| 4006a04817 | |||
| 4189a1c729 | |||
| a07cbabcb3 | |||
| 64a3893f6f | |||
| eabe759ebf | |||
| a4838386e6 | |||
| c65613901f | |||
| 19d16620a6 | |||
| 4e15b9cdfa | |||
| de35cec2e1 | |||
| e8bcebfb8e | |||
| 2f241e1b61 | |||
| 6affef76b1 | |||
| 32ba4d07e2 | |||
| ddaaf89c87 | |||
| 9aed8dbe6b | |||
| aa7e92b275 | |||
| f30947336a | |||
| 0bb44d7b75 | |||
| 1138ec77ca | |||
| c4dadd27ac | |||
| 04c715d314 | |||
| 35743cc8e6 | |||
| 5f92807fdd | |||
| 700c3444f5 | |||
| ddf1babfe1 | |||
| 2ae2ede0b2 | |||
| ef5af384e7 | |||
| a134d16070 | |||
| 827eec6af0 | |||
| 8da2f12ba6 | |||
| 50ab391133 | |||
| 991647bc8f | |||
| 57300687ff | |||
| d559339f5f | |||
| 2bf65ef512 | |||
| d20752c318 | |||
| 5f66ef34dd | |||
| da0b4cd40e | |||
| 68f9dc1f8a | |||
| 5121d0d934 | |||
| 2c520391eb | |||
| 7c4b9218f2 | |||
| 72f8138ca1 | |||
| 991ae4383a | |||
| 2ce7205c80 | |||
| bec3e8654f | |||
| 14fdcb892d | |||
| d6d062841d | |||
| 06d0985bba | |||
| 9ea969be1f | |||
| 500f774b7f | |||
| ca8832c0e1 | |||
| 1cbba113fd | |||
| 45b4b33a3d | |||
| c453a8e2dc | |||
| e59772a58d | |||
| fb35f06cf5 | |||
| abc788c756 | |||
| 63b616dc2e | |||
| 72f3fe0b12 | |||
| cba12efeb1 | |||
| 37cd4ed504 | |||
| 869bba4dad | |||
| 23194d1f53 | |||
| 969563c06a | |||
| 066e8e1cc2 | |||
| 5cd7b40165 | |||
| c7b134ba4b | |||
| ff62c262fe | |||
| 42e2c15e0c | |||
| 40c6989374 | |||
| 71dc373610 | |||
| 0fa16cf982 | |||
| 8902032b42 | |||
| 368f5e9799 | |||
| 46b34817d2 | |||
| b1fe24bb57 | |||
| 490a28ee7a | |||
| 75884ca6b8 | |||
| d729d7f570 | |||
| 6408bb2efa | |||
| d8dabab4fb | |||
| 4dc107f77a | |||
| eaf06d239c | |||
| d9b3a4bf77 | |||
| cf970d5914 | |||
| 1cfe3dd4da | |||
| 51d1e47bfe | |||
| e0a447bfaf | |||
| 3f5ee6f414 | |||
| 44d5c8c4b4 | |||
| 17b7e9e772 | |||
| 8a2a444f33 | |||
| 957df08932 | |||
| fd018b32d0 | |||
| e000c7d818 | |||
| bb40069773 | |||
| 37d5b60f5c | |||
| 37e6cd6500 | |||
| feadea0e91 | |||
| f71a29b6c4 | |||
| ec4cfdee23 | |||
| dd79db6383 | |||
| 723e458bd7 | |||
| 25a47f0df3 | |||
| 39be57424c | |||
| 45ffa1b79c | |||
| f37e1c2229 | |||
| 1bd7b86e60 | |||
| 18e7cf2069 | |||
| 60b4d90608 | |||
| 5197000124 | |||
| 71d4060993 | |||
| 34c6ad7277 | |||
| 9e79ef2a91 | |||
| 4d1b32f770 | |||
| a5a097fa4a | |||
| ad645f31d0 | |||
| f08d429851 | |||
| bac3219a01 | |||
| 09a527fb12 | |||
| 58a3a480b9 | |||
| a12bfe4639 | |||
| 6cda639869 | |||
| 2797fe116f | |||
| e768cd53fb | |||
| 83e2ad40d6 | |||
| 7ebd0699e3 | |||
| 46b1d4d194 | |||
| f60e265397 | |||
| 2e642327ea | |||
| a87ce41030 | |||
| 0c8cae4cc3 | |||
| ed325b4a45 | |||
| 1c67b5e812 | |||
| b6c964c444 | |||
| 6fedf06150 | |||
| 91d513a672 | |||
| 44f0ec601f | |||
| 2a659a9d03 | |||
| 7e7c3a1bb3 | |||
| 3b23458ecc | |||
| 7afdfb150f | |||
| 2ca7886f88 | |||
| 5aca6c7c1f | |||
| fe94d6cf89 | |||
| 0a7c316ffb | |||
| e72424e01a | |||
| dbba9128a4 | |||
| 352c1ddc16 | |||
| 4d96ae56ac | |||
| adadb10b15 | |||
| a749b9806e | |||
| 615d9d4abe | |||
| aa03274093 | |||
| e7a06979ec | |||
| 3651306f57 | |||
| 5dce4e6aea | |||
| 1d9041f2aa | |||
| a578527012 | |||
| af78a2d080 | |||
| 840000d02b | |||
| 9ea4c777ad | |||
| a33b63d066 | |||
| da3b30cd94 | |||
| 4599e1dec5 | |||
| 6de350ce9d | |||
| 838d31fa41 | |||
| 401b460d75 | |||
| c440204fa5 | |||
| adf50dffd8 | |||
| 20d38ed28c | |||
| edc30cd71d | |||
| 10ce03a1e7 | |||
| 5fca5c774a | |||
| fc6c39e670 | |||
| 7c3b6307d9 | |||
| e52dac3b25 | |||
| 62db9a8ef3 | |||
| f0be4f86a6 | |||
| e5bb843059 | |||
| ca774dfeb5 | |||
| 681d8327f5 | |||
| 9bc02c81f8 | |||
| bb1738db8c | |||
| 9548c592a3 | |||
| cda0276d39 | |||
| 539afb329a | |||
| 3e0150f847 | |||
| f8261c60c0 | |||
| 9f90eeab05 | |||
| 1ee37cb671 | |||
| 8fe798de6d | |||
| e00efca170 | |||
| 86b6714777 | |||
| 77b5e6d44a | |||
| ffe73165f9 | |||
| 96c7e9e29d | |||
| 02051ed60f | |||
| f49689caac | |||
| 819c130366 | |||
| 974b9b992d | |||
| 3ab1214012 | |||
| 4b917390ac | |||
| 7a0fb9a57f | |||
| 58fcd2b2fe | |||
| bdcf058e52 | |||
| 61f0043cd8 | |||
| dd7bfba8d5 | |||
| 5b8fdbc82d | |||
| 6a1c677cbc | |||
| e30952efee | |||
| fd8dc03ae9 | |||
| 1337758660 | |||
| 339e8a7910 | |||
| a60b460701 | |||
| a5cb4057f9 | |||
| 9d7f97ccd5 | |||
| 0578d41500 | |||
| 42c3fa24f0 | |||
| 60b396fee5 | |||
| 4cd9252ff6 | |||
| 75875d3a8f | |||
| 86e9d92ecb | |||
| baa4e6475a | |||
| ac5c77ee2c | |||
| 1efc6a1385 | |||
| 442ea8a692 | |||
| 749be67df3 | |||
| a97a574718 | |||
| 110a45bee6 | |||
| f120da3aca | |||
| 240684bc1f | |||
| 62003d96f3 | |||
| e905634343 | |||
| 14dce1abac | |||
| 8ddab05ed3 | |||
| 5dc441c4af | |||
| 940fb0d1fd | |||
| f18c33563d | |||
| 10e8a54b2e | |||
| f792976d6d | |||
| 08cbd009ac | |||
| 3d4219bfee | |||
| d58a569660 | |||
| fd3cf5d2b1 | |||
| 1a844426c3 | |||
| 42237a3bc8 | |||
| 010c2c934b | |||
| 48a76426e7 | |||
| 0c645ba867 | |||
| f538dd5276 | |||
| 31568fc5a1 | |||
| 44c7fde2f7 | |||
| cb07142832 | |||
| 60a05412c9 | |||
| 0179f5ea09 | |||
| f671ed7e3f | |||
| 2fccff5a35 | |||
| cd41d5f6dd | |||
| 66905fcc08 | |||
| af4b138094 | |||
| 3c57e05a65 | |||
| 25099b4c98 | |||
| 1ac7629459 | |||
| 95681a7a05 | |||
| d7b8458a56 | |||
| 67dfe0bcf3 | |||
| b1869bced4 | |||
| 61aa1ea11f | |||
| 20aa7c79d1 | |||
| 22548a3f4a | |||
| 9e1b5cbaab | |||
| 1488ec5a03 | |||
| 4f0457a268 | |||
| 30fdc2198f | |||
| bce16cdd6e | |||
| d5daa46ab8 | |||
| ad6d95ba52 | |||
| 318ce5dec8 | |||
| 526d4369ce | |||
| c69919738b | |||
| 1b5a01a6c9 | |||
| f233715b70 | |||
| a58ac18fa0 | |||
| f1e366d36f | |||
| 301dcd78cc | |||
| 65c6d62a15 | |||
| aaf7a249c6 | |||
| 0bc8d49684 | |||
| 17ecbca204 | |||
| 78928b7eb4 | |||
| 5236e1ef0d | |||
| be7ed8e74a | |||
| 78bcb85679 | |||
| b98bb9eb27 | |||
| cad55a4da5 | |||
| 511fc870a1 | |||
| dafd2fecf7 | |||
| 9c5cca784e | |||
| 1138165308 | |||
| d7eb321d58 | |||
| 15f8c7014f | |||
| dd64e2060e | |||
| 14d4551476 | |||
| e6549b0fe8 | |||
| 157e05f57c | |||
| 96efd1e8b9 | |||
| 672ce40618 | |||
| 05e9d76c77 | |||
| ea7fc7f6c4 | |||
| 6b1d5d28be | |||
| a9b0bfa740 | |||
| cc6b80a55b | |||
| 6707989cd5 | |||
| 766439db6d | |||
| d4903caafa | |||
| caa0111c79 | |||
| ffacff67cf | |||
| f43a7fdfb4 | |||
| 7bb1a3906d | |||
| 530c259e71 | |||
| 843a6851c4 | |||
| 234051d6bc | |||
| 981c0eb8bc | |||
| 1066855532 | |||
| f2d6518311 | |||
| 765ccfa18c | |||
| 201aee3119 | |||
| 65f299038d | |||
| bd1290706a | |||
| 939cbf46e4 | |||
| aec5a09caf | |||
| 6346d1b6c7 | |||
| 05ee242b80 | |||
| 64be3f05a3 | |||
| cfdce9be61 | |||
| 446220494e | |||
| f12ffa92a0 | |||
| b2a4797d16 | |||
| 8bfacb0091 | |||
| 0501f3bd99 | |||
| ae3ae6fd0e | |||
| 011a5f57e1 | |||
| 84b3289a2a | |||
| b760892de2 | |||
| 6840a8983c | |||
| a1b3490764 | |||
| 076f1efecb | |||
| b23511edb1 | |||
| 53e572f072 | |||
| c2b6ba0d5a | |||
| d4d530e6c8 | |||
| 99270e96a9 | |||
| 4bf7a08c80 | |||
| 3823de6552 | |||
| 30592b27ce | |||
| 8bc6c2eb20 | |||
| 87d52e5ebe | |||
| 598a09c13d | |||
| 54db4ab215 | |||
| 5b5ccba247 | |||
| 18e2559b1e | |||
| f5987b68ff | |||
| a1ab44d39f | |||
| 8b1514e575 | |||
| 2d3810874d | |||
| a4c634e4bf | |||
| 2a4d986da5 | |||
| 3b18730af6 | |||
| df260fe0e8 | |||
| 2be4fe8404 | |||
| 7db7cfe20f | |||
| cc2cc2849e | |||
| 06f4b0b29a | |||
| e22821799b | |||
| 14dd9294aa | |||
| 83e3409bd8 | |||
| 7630170ed6 | |||
| 0af74fccda | |||
| e77de1804f | |||
| e00b92225d | |||
| ee8fca9439 | |||
| adc562feb8 | |||
| af8fa4014f | |||
| 08415b0e8f | |||
| 967f9a9174 | |||
| d255141bd4 | |||
| e7e1dd91c7 | |||
| 195c5e92a4 | |||
| 47dafe62b8 | |||
| 26922ebb51 | |||
| 7480e71801 | |||
| 9ac3f48fcb | |||
| 0e405755ad | |||
| 693f90449f | |||
| 0bf45069bd | |||
| 34b10f61ce | |||
| 1479b42112 | |||
| bb061d2a0a | |||
| 061012a268 | |||
| a698f91db4 | |||
| 30d12a76bc | |||
| 687fa44eff | |||
| aefb33efff | |||
| da0c45b7ee | |||
| 956335e844 | |||
| 701fc600cd | |||
| e38b2cff4f | |||
| b268293402 | |||
| 45b9dc8be9 | |||
| 0ad7025a17 | |||
| 49b7467840 | |||
| a40ef610a2 | |||
| f9943b60e4 | |||
| f97fb1b35d | |||
| b959181afd | |||
| cbc27a94ac | |||
| 6a4f999b88 | |||
| 7707e01352 | |||
| e667326df5 | |||
| f1b2d7530d | |||
| b6587b32b9 | |||
| b89bafa165 | |||
| 9fac5f94ba | |||
| 5affc73ee6 | |||
| 027016ddae | |||
| 8f2f98b7b4 | |||
| 6b43d12469 | |||
| 74940ed33c | |||
| 17871bb3ca | |||
| 89c4abc07a | |||
| 46b5a7697c | |||
| dd8060d64f | |||
| afb1d7ef0c | |||
| 93ddee5956 | |||
| 0184e5beb5 | |||
| 3f2e110eab | |||
| 0ff68b7d66 | |||
| cdbdc1a822 | |||
| 7a2be05c69 | |||
| 5be38d0702 | |||
| ff203d8d34 | |||
| 23fa39121c | |||
| b16e65168f | |||
| 090a294017 | |||
| 22bc4b4271 | |||
| e01c049401 | |||
| e7ef7a9e55 | |||
| e0011d22f2 | |||
| 7d34bd8f82 | |||
| bd69cf599b | |||
| 1ac7de9ee5 | |||
| 397043a9c0 | |||
| 43ff03e33b | |||
| fa900df5a7 | |||
| 414f0f6cd9 | |||
| 7ef751ba95 | |||
| f8c01418b1 | |||
| 731330c6b5 | |||
| d2df55b1ac | |||
| 0dd74e3c9d | |||
| 9e073e9fa0 | |||
| c95a271821 | |||
| fe386fa819 | |||
| 4d70322eab | |||
| d9b8391968 | |||
| 6ac3681604 | |||
| b35cad0c2e | |||
| 2106a9e373 | |||
| 5050047cef | |||
| 1b65f850ee | |||
| 7c2933aae1 | |||
| 96babec22a | |||
| c12d1e9bd9 | |||
| 4d1f0e77f2 | |||
| d7bf34ecd0 | |||
| 1943c3e7a1 | |||
| af050cc729 | |||
| 84ef2161a1 | |||
| ca23360d07 | |||
| 5dbe51a52e | |||
| 99e30a4d7d | |||
| 93975fdc45 | |||
| fbef90f7cb | |||
| a9db4dd9a3 | |||
| fc7e96fa66 | |||
| 097d9a6479 | |||
| 2dd0bfdece | |||
| 26585bb1d9 | |||
| 0d92719433 | |||
| 1ab2722850 | |||
| fe17958b9f | |||
| 3e4d410646 | |||
| b5aae34d86 | |||
| 7f029b2713 | |||
| 0424082e7b | |||
| 2352c86048 | |||
| c0dff5e203 | |||
| d920785256 | |||
| 45cea14165 | |||
| 26ed689d30 | |||
| 7ce0370b6a | |||
| aa2e53c4f8 | |||
| 9ecd156622 | |||
| 3c62be3f5d | |||
| d1c8273826 | |||
| 7d1b7436d4 | |||
| 65750586b6 | |||
| 62f6128ba1 | |||
| 7f5c850744 | |||
| 9607b4205a | |||
| e447d5fccf | |||
| 090c3c9930 | |||
| 48ea9e1c1d | |||
| 42469b83fe | |||
| e65bc040af | |||
| 89ca4c8a8b | |||
| 2323a55517 | |||
| 45d6caa1d0 | |||
| 55d2a64f54 | |||
| 2420886c2c | |||
| e636dce919 | |||
| 1a1f9b1cf2 | |||
| 54d0cb47cd | |||
| 23a2f8b903 | |||
| 29fd682672 | |||
| efed67cbd0 | |||
| 6234a5bc0b | |||
| 54f64e7618 | |||
| f0105cb7fb | |||
| 76b0f80169 | |||
| f84df175ce | |||
| 58aca68726 | |||
| 8670364f44 | |||
| 418bc54f2b | |||
| 9c36d7c338 | |||
| 8141b9977d | |||
| c035d3c82c | |||
| 1de9daa40f | |||
| efd8203232 | |||
| a667d88f93 | |||
| 8d7dd577ab | |||
| 054b41383f | |||
| 02ad199138 | |||
| 65c4f9db5b | |||
| 51e38b7614 | |||
| 90878a7c2b | |||
| 7f028f70d5 | |||
| ec0cb5fd54 | |||
| 682de62c57 | |||
| 18253b6966 | |||
| 21f05eb118 | |||
| d94f6388b7 | |||
| 1971813336 | |||
| 3c88d2aad3 | |||
| 5c39903323 | |||
| 6d59a2b45d | |||
| 09c24088a2 | |||
| efdc4817bb | |||
| 0c97abb053 | |||
| 1759d247d9 | |||
| 21dc64dc21 | |||
| 264eff3ad0 | |||
| 05c7b21b0a | |||
| 40b626b0aa | |||
| 6ebfe05fce | |||
| 59abb5d344 | |||
| 9594ee8e47 | |||
| 7a4ec7f7a3 | |||
| 51db1706e9 | |||
| ac9e71d9c7 | |||
| f3f5ca1bd8 | |||
| b979023b9d | |||
| 915dea01c9 | |||
| 566bb73897 | |||
| fb0d8d746f | |||
| 1b24c4f279 | |||
| a5a041e637 | |||
| c469d9b3ff | |||
| 373d166076 | |||
| 3c54243ac7 | |||
| 1f467580ee | |||
| 1ba883719a | |||
| f73e954b28 | |||
| de629291b9 | |||
| 7eb5d220fd | |||
| 4cd9abdd15 | |||
| 198dde8365 | |||
| b165340662 | |||
| 5ad4340679 | |||
| b56fa4a29d | |||
| e946b392c9 | |||
| 81689b5f02 | |||
| c18d926174 | |||
| 00662bad46 | |||
| 420a7b60ca | |||
| 2ab3eb4109 | |||
| 9314528b9b | |||
| 78ef7e804f | |||
| 3fc1edede0 | |||
| f50b4be162 | |||
| ccde8148a7 | |||
| b9bbf42538 | |||
| 435636a655 | |||
| ba06269b14 | |||
| be01ccdb08 | |||
| b45d27593f | |||
| ff49d8b84f | |||
| 5d78cd3016 | |||
| ed0b1a86aa | |||
| 534b3e6a9a | |||
| d452cf4170 | |||
| f117027175 | |||
| acf79570ef | |||
| 5a939cf252 | |||
| 9bc7a72a25 | |||
| 065ee9004c | |||
| 6fb69a1dc2 | |||
| 49889858fa | |||
| 2424f38a62 | |||
| 218456d127 | |||
| e7dd03e551 | |||
| 0c8e9fe095 | |||
| 5b4acec4ca | |||
| e26f360d93 | |||
| 2cc9534570 | |||
| 572c4052f6 | |||
| 132286895f | |||
| 454bee3f02 | |||
| 41cad88d6e | |||
| 40e341b0ee | |||
| 5da59c9151 | |||
| f804e87f7d | |||
| dd3641f054 | |||
| b2291ce162 | |||
| c35ed6570b | |||
| d15cbb2d6a | |||
| b8cf6432ef | |||
| 89805fb092 | |||
| 692cec8458 | |||
| 79897e77dc | |||
| 649e9f4500 | |||
| 3a6d31d3fa | |||
| 2138eeb87f | |||
| 102aa50a41 | |||
| 5cfe249945 | |||
| a0138955cd | |||
| e1ffbb710b | |||
| c18f72ceb9 | |||
| bc1441a5eb | |||
| 0f154c3173 | |||
| 7b287a1d5b | |||
| 4b332b5d42 | |||
| ec2f21bb9f | |||
| acd6c86f98 | |||
| ab150b458a | |||
| cf28ecd5a6 | |||
| 99eed9c37a | |||
| f4e86028d0 | |||
| 7cb71ec6fb | |||
| d054e5b4b7 | |||
| c69efc040c | |||
| c4bf1641bd |
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"
|
||||||
|
]
|
||||||
|
}
|
||||||
3
BAN/.gitignore
vendored
3
BAN/.gitignore
vendored
@@ -1,3 +0,0 @@
|
|||||||
*.a
|
|
||||||
*.d
|
|
||||||
*.o
|
|
||||||
22
BAN/BAN/Assert.cpp
Normal file
22
BAN/BAN/Assert.cpp
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
#include <BAN/Assert.h>
|
||||||
|
|
||||||
|
#if __is_kernel
|
||||||
|
|
||||||
|
#include <kernel/Panic.h>
|
||||||
|
|
||||||
|
[[noreturn]] void __ban_assertion_failed(const char* location, const char* msg)
|
||||||
|
{
|
||||||
|
Kernel::panic_impl(location, msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#include <BAN/Debug.h>
|
||||||
|
|
||||||
|
[[noreturn]] void __ban_assertion_failed(const char* location, const char* msg)
|
||||||
|
{
|
||||||
|
derrorln("{}: {}", location, msg);
|
||||||
|
__builtin_trap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -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,24 +1,18 @@
|
|||||||
cmake_minimum_required(VERSION 3.26)
|
|
||||||
|
|
||||||
project(BAN CXX)
|
|
||||||
|
|
||||||
set(BAN_SOURCES
|
set(BAN_SOURCES
|
||||||
|
BAN/Assert.cpp
|
||||||
BAN/New.cpp
|
BAN/New.cpp
|
||||||
BAN/String.cpp
|
|
||||||
BAN/StringView.cpp
|
BAN/StringView.cpp
|
||||||
BAN/Time.cpp
|
BAN/Time.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
add_custom_target(ban-headers
|
|
||||||
COMMAND ${CMAKE_COMMAND} -E copy_directory_if_different ${CMAKE_CURRENT_SOURCE_DIR}/include/ ${BANAN_INCLUDE}/
|
|
||||||
DEPENDS sysroot
|
|
||||||
)
|
|
||||||
|
|
||||||
add_library(ban ${BAN_SOURCES})
|
add_library(ban ${BAN_SOURCES})
|
||||||
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)
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <BAN/Errors.h>
|
|
||||||
#include <BAN/Iterators.h>
|
#include <BAN/Iterators.h>
|
||||||
#include <BAN/Span.h>
|
#include <BAN/Span.h>
|
||||||
|
|
||||||
@@ -19,85 +18,78 @@ namespace BAN
|
|||||||
using const_iterator = ConstIteratorSimple<T, Array>;
|
using const_iterator = ConstIteratorSimple<T, Array>;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Array();
|
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()
|
constexpr Array<T, S>::Array(const T& value)
|
||||||
{
|
|
||||||
for (size_type i = 0; i < S; i++)
|
|
||||||
m_data[i] = T();
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T, size_t S>
|
|
||||||
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,33 +1,14 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <BAN/Traits.h>
|
#define __ban_assert_stringify_helper(s) #s
|
||||||
|
#define __ban_assert_stringify(s) __ban_assert_stringify_helper(s)
|
||||||
|
|
||||||
#if defined(__is_kernel)
|
#define ASSERT(cond) \
|
||||||
#include <kernel/Panic.h>
|
(__builtin_expect(!(cond), 0) \
|
||||||
|
? __ban_assertion_failed(__FILE__ ":" __ban_assert_stringify(__LINE__), "ASSERT(" #cond ") failed") \
|
||||||
|
: (void)0)
|
||||||
|
|
||||||
#define ASSERT(cond) \
|
#define ASSERT_NOT_REACHED() \
|
||||||
do { \
|
__ban_assertion_failed(__FILE__ ":" __ban_assert_stringify(__LINE__), "ASSERT_NOT_REACHED() reached")
|
||||||
if (!(cond)) \
|
|
||||||
Kernel::panic("ASSERT(" #cond ") failed"); \
|
|
||||||
} while (false)
|
|
||||||
|
|
||||||
#define __ASSERT_BIN_OP(lhs, rhs, name, op) \
|
[[noreturn]] void __ban_assertion_failed(const char* location, const char* msg);
|
||||||
do { \
|
|
||||||
auto&& _lhs = lhs; \
|
|
||||||
auto&& _rhs = rhs; \
|
|
||||||
if (!(_lhs op _rhs)) \
|
|
||||||
Kernel::panic(name "(" #lhs ", " #rhs ") ({} " #op " {}) failed", _lhs, _rhs); \
|
|
||||||
} while (false)
|
|
||||||
|
|
||||||
#define ASSERT_LT(lhs, rhs) __ASSERT_BIN_OP(lhs, rhs, "ASSERT_LT", <)
|
|
||||||
#define ASSERT_LTE(lhs, rhs) __ASSERT_BIN_OP(lhs, rhs, "ASSERT_LTE", <=)
|
|
||||||
#define ASSERT_GT(lhs, rhs) __ASSERT_BIN_OP(lhs, rhs, "ASSERT_GT", >)
|
|
||||||
#define ASSERT_GTE(lhs, rhs) __ASSERT_BIN_OP(lhs, rhs, "ASSERT_GTE", >=)
|
|
||||||
#define ASSERT_EQ(lhs, rhs) __ASSERT_BIN_OP(lhs, rhs, "ASSERT_EQ", ==)
|
|
||||||
#define ASSERT_NEQ(lhs, rhs) __ASSERT_BIN_OP(lhs, rhs, "ASSERT_NEQ", !=)
|
|
||||||
#define ASSERT_NOT_REACHED() Kernel::panic("ASSERT_NOT_REACHED() failed")
|
|
||||||
#else
|
|
||||||
#include <assert.h>
|
|
||||||
#define ASSERT(cond) assert((cond) && "ASSERT("#cond") failed")
|
|
||||||
#define ASSERT_NOT_REACHED() do { assert(false && "ASSERT_NOT_REACHED() failed"); __builtin_unreachable(); } while (false)
|
|
||||||
#endif
|
|
||||||
|
|||||||
@@ -1,10 +1,50 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <BAN/Traits.h>
|
||||||
|
|
||||||
namespace BAN
|
namespace BAN
|
||||||
{
|
{
|
||||||
|
|
||||||
template<typename T, int MEM_ORDER = __ATOMIC_SEQ_CST>
|
enum MemoryOrder
|
||||||
requires requires { __atomic_always_lock_free(sizeof(T), 0); }
|
{
|
||||||
|
memory_order_relaxed = __ATOMIC_RELAXED,
|
||||||
|
memory_order_consume = __ATOMIC_CONSUME,
|
||||||
|
memory_order_acquire = __ATOMIC_ACQUIRE,
|
||||||
|
memory_order_release = __ATOMIC_RELEASE,
|
||||||
|
memory_order_acq_rel = __ATOMIC_ACQ_REL,
|
||||||
|
memory_order_seq_cst = __ATOMIC_SEQ_CST,
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T> concept atomic_c = is_integral_v<T> || is_pointer_v<T>;
|
||||||
|
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;
|
||||||
@@ -16,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() 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) 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) 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;
|
||||||
|
|||||||
12
BAN/include/BAN/Bitcast.h
Normal file
12
BAN/include/BAN/Bitcast.h
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace BAN
|
||||||
|
{
|
||||||
|
|
||||||
|
template<typename To, typename From>
|
||||||
|
constexpr To bit_cast(const From& from)
|
||||||
|
{
|
||||||
|
return __builtin_bit_cast(To, from);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
#include <BAN/Span.h>
|
#include <BAN/Span.h>
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
namespace BAN
|
namespace BAN
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -19,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));
|
||||||
@@ -80,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);
|
||||||
@@ -113,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>;
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <BAN/Assert.h>
|
#include <BAN/Assert.h>
|
||||||
|
#include <BAN/Move.h>
|
||||||
#include <BAN/PlacementNew.h>
|
#include <BAN/PlacementNew.h>
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
@@ -23,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(); }
|
||||||
@@ -49,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>
|
||||||
@@ -67,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)...);
|
||||||
@@ -97,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
|
||||||
{
|
{
|
||||||
|
|||||||
61
BAN/include/BAN/Debug.h
Normal file
61
BAN/include/BAN/Debug.h
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#if __is_kernel
|
||||||
|
|
||||||
|
#include <kernel/Debug.h>
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#include <BAN/Formatter.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#define __debug_putchar [](int c) { putc_unlocked(c, stddbg); }
|
||||||
|
|
||||||
|
#define dprintln(...) \
|
||||||
|
do { \
|
||||||
|
flockfile(stddbg); \
|
||||||
|
BAN::Formatter::print(__debug_putchar, __VA_ARGS__); \
|
||||||
|
BAN::Formatter::print(__debug_putchar,"\n"); \
|
||||||
|
fflush(stddbg); \
|
||||||
|
funlockfile(stddbg); \
|
||||||
|
} while (false)
|
||||||
|
|
||||||
|
#define dwarnln(...) \
|
||||||
|
do { \
|
||||||
|
flockfile(stddbg); \
|
||||||
|
BAN::Formatter::print(__debug_putchar, "\e[33m"); \
|
||||||
|
BAN::Formatter::print(__debug_putchar, __VA_ARGS__); \
|
||||||
|
BAN::Formatter::print(__debug_putchar, "\e[m\n"); \
|
||||||
|
fflush(stddbg); \
|
||||||
|
funlockfile(stddbg); \
|
||||||
|
} while(false)
|
||||||
|
|
||||||
|
#define derrorln(...) \
|
||||||
|
do { \
|
||||||
|
flockfile(stddbg); \
|
||||||
|
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__); \
|
||||||
|
} while(false)
|
||||||
|
|
||||||
|
#define dwarnln_if(cond, ...) \
|
||||||
|
do { \
|
||||||
|
if constexpr(cond) \
|
||||||
|
dwarnln(__VA_ARGS__); \
|
||||||
|
} while(false)
|
||||||
|
|
||||||
|
#define derrorln_if(cond, ...) \
|
||||||
|
do { \
|
||||||
|
if constexpr(cond) \
|
||||||
|
derrorln(__VA_ARGS__); \
|
||||||
|
} while(false)
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -45,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,13 +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)
|
||||||
|
: 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;
|
||||||
};
|
};
|
||||||
@@ -69,12 +90,36 @@ namespace BAN
|
|||||||
template<integral T>
|
template<integral T>
|
||||||
struct BigEndian
|
struct BigEndian
|
||||||
{
|
{
|
||||||
|
constexpr BigEndian()
|
||||||
|
: raw(0)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
constexpr BigEndian(T value)
|
||||||
|
: raw(host_to_big_endian(value))
|
||||||
|
{ }
|
||||||
|
|
||||||
constexpr operator T() const
|
constexpr operator T() const
|
||||||
{
|
{
|
||||||
return host_to_big_endian(raw);
|
return host_to_big_endian(raw);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
T raw;
|
T raw;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<integral T>
|
||||||
|
using NetworkEndian = BigEndian<T>;
|
||||||
|
|
||||||
|
template<integral T>
|
||||||
|
constexpr T host_to_network_endian(T value)
|
||||||
|
{
|
||||||
|
return host_to_big_endian(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<integral T>
|
||||||
|
constexpr T network_endian_to_host(T value)
|
||||||
|
{
|
||||||
|
return big_endian_to_host(value);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <BAN/Formatter.h>
|
#include <BAN/Formatter.h>
|
||||||
#include <BAN/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,27 +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
|
||||||
return strerror(m_error_code);
|
if (auto* desc = strerrordesc_np(m_error_code))
|
||||||
|
return desc;
|
||||||
|
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)
|
||||||
@@ -89,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);
|
||||||
|
|
||||||
|
|||||||
@@ -1,262 +1,261 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <BAN/Hash.h>
|
#include <BAN/HashSet.h>
|
||||||
#include <BAN/LinkedList.h>
|
|
||||||
#include <BAN/Vector.h>
|
|
||||||
|
|
||||||
namespace BAN
|
namespace BAN
|
||||||
{
|
{
|
||||||
|
|
||||||
template<typename Key, typename T, typename HASH = BAN::hash<Key>, bool STABLE = true>
|
template<typename HashSetIt, typename HashMap, typename Entry>
|
||||||
|
class HashMapIterator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
HashMapIterator() = default;
|
||||||
|
|
||||||
|
Entry& operator*()
|
||||||
|
{
|
||||||
|
return const_cast<Entry&>(m_iterator.operator*());
|
||||||
|
}
|
||||||
|
const Entry& operator*() const
|
||||||
|
{
|
||||||
|
return m_iterator.operator*();
|
||||||
|
}
|
||||||
|
|
||||||
|
Entry* operator->()
|
||||||
|
{
|
||||||
|
return const_cast<Entry*>(m_iterator.operator->());
|
||||||
|
}
|
||||||
|
const Entry* operator->() const
|
||||||
|
{
|
||||||
|
return m_iterator.operator->();
|
||||||
|
}
|
||||||
|
|
||||||
|
HashMapIterator& operator++()
|
||||||
|
{
|
||||||
|
++m_iterator;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
HashMapIterator operator++(int)
|
||||||
|
{
|
||||||
|
auto temp = *this;
|
||||||
|
++(*this);
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(HashMapIterator other) const
|
||||||
|
{
|
||||||
|
return m_iterator == other.m_iterator;
|
||||||
|
}
|
||||||
|
bool operator!=(HashMapIterator other) const
|
||||||
|
{
|
||||||
|
return m_iterator != other.m_iterator;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
explicit HashMapIterator(HashSetIt it)
|
||||||
|
: m_iterator(it)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
private:
|
||||||
|
HashSetIt m_iterator;
|
||||||
|
friend HashMap;
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
|
template<typename T, typename Key, typename HASH, typename COMP>
|
||||||
|
concept HashMapFindable = requires(const Key& a, const T& b) { COMP()(a, b); HASH()(b); };
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Key, typename T, typename HASH = BAN::hash<Key>, typename COMP = BAN::equal<Key>>
|
||||||
class HashMap
|
class HashMap
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
struct Entry
|
struct Entry
|
||||||
{
|
{
|
||||||
template<typename... Args>
|
const Key key;
|
||||||
Entry(const Key& key, Args&&... args)
|
|
||||||
: key(key)
|
|
||||||
, value(forward<Args>(args)...)
|
|
||||||
{}
|
|
||||||
|
|
||||||
Key key;
|
|
||||||
T value;
|
T value;
|
||||||
|
|
||||||
|
Entry() = delete;
|
||||||
|
Entry& operator=(const Entry&) = delete;
|
||||||
|
Entry& operator=(Entry&&) = delete;
|
||||||
|
|
||||||
|
Entry(const Entry& other)
|
||||||
|
: key(other.key)
|
||||||
|
, value(other.value)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
Entry(Entry&& other)
|
||||||
|
: key(BAN::move(const_cast<Key&>(other.key)))
|
||||||
|
, value(BAN::move(other.value))
|
||||||
|
{ }
|
||||||
|
|
||||||
|
template<typename... Args>
|
||||||
|
Entry(Key&& key, Args&&... args)
|
||||||
|
: key(BAN::move(key))
|
||||||
|
, value(BAN::forward<Args>(args)...)
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
|
||||||
|
struct EntryHash
|
||||||
|
{
|
||||||
|
constexpr bool operator()(const Key& a)
|
||||||
|
{
|
||||||
|
return HASH()(a);
|
||||||
|
}
|
||||||
|
constexpr bool operator()(const Entry& a)
|
||||||
|
{
|
||||||
|
return HASH()(a.key);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct EntryComp
|
||||||
|
{
|
||||||
|
constexpr bool operator()(const Entry& a, const Key& b)
|
||||||
|
{
|
||||||
|
return COMP()(a.key, b);
|
||||||
|
}
|
||||||
|
constexpr bool operator()(const Entry& a, const Entry& b)
|
||||||
|
{
|
||||||
|
return COMP()(a.key, b.key);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
using size_type = size_t;
|
using size_type = size_t;
|
||||||
using key_type = Key;
|
using key_type = Key;
|
||||||
using value_type = T;
|
using value_type = T;
|
||||||
using iterator = IteratorDouble<Entry, Vector, LinkedList, HashMap>;
|
using iterator = HashMapIterator<typename HashSet<Entry, EntryHash, EntryComp>::iterator, HashMap, Entry>;
|
||||||
using const_iterator = ConstIteratorDouble<Entry, Vector, LinkedList, HashMap>;
|
using const_iterator = HashMapIterator<typename HashSet<Entry, EntryHash, EntryComp>::const_iterator, HashMap, const Entry>;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
HashMap() = default;
|
HashMap() = default;
|
||||||
HashMap(const HashMap<Key, T, HASH, STABLE>&);
|
~HashMap() { clear(); }
|
||||||
HashMap(HashMap<Key, T, HASH, STABLE>&&);
|
|
||||||
~HashMap();
|
|
||||||
|
|
||||||
HashMap<Key, T, HASH, STABLE>& operator=(const HashMap<Key, T, HASH, STABLE>&);
|
HashMap(const HashMap& other) { *this = other; }
|
||||||
HashMap<Key, T, HASH, STABLE>& operator=(HashMap<Key, T, HASH, STABLE>&&);
|
HashMap& operator=(const HashMap& other)
|
||||||
|
|
||||||
ErrorOr<void> insert(const Key&, const T&);
|
|
||||||
ErrorOr<void> insert(const Key&, T&&);
|
|
||||||
template<typename... Args>
|
|
||||||
ErrorOr<void> emplace(const Key&, Args&&...);
|
|
||||||
|
|
||||||
iterator begin() { return iterator(m_buckets.end(), m_buckets.begin()); }
|
|
||||||
iterator end() { return iterator(m_buckets.end(), m_buckets.end()); }
|
|
||||||
const_iterator begin() const { return const_iterator(m_buckets.end(), m_buckets.begin()); }
|
|
||||||
const_iterator end() const { return const_iterator(m_buckets.end(), m_buckets.end()); }
|
|
||||||
|
|
||||||
ErrorOr<void> reserve(size_type);
|
|
||||||
|
|
||||||
void remove(const Key&);
|
|
||||||
void clear();
|
|
||||||
|
|
||||||
T& operator[](const Key&);
|
|
||||||
const T& operator[](const Key&) const;
|
|
||||||
|
|
||||||
bool contains(const Key&) const;
|
|
||||||
|
|
||||||
bool empty() const;
|
|
||||||
size_type size() const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
ErrorOr<void> rebucket(size_type);
|
|
||||||
LinkedList<Entry>& get_bucket(const Key&);
|
|
||||||
const LinkedList<Entry>& get_bucket(const Key&) const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
Vector<LinkedList<Entry>> m_buckets;
|
|
||||||
size_type m_size = 0;
|
|
||||||
|
|
||||||
friend iterator;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename Key, typename T, typename HASH, bool STABLE>
|
|
||||||
HashMap<Key, T, HASH, STABLE>::HashMap(const HashMap<Key, T, HASH, STABLE>& other)
|
|
||||||
{
|
{
|
||||||
*this = other;
|
m_hash_set = other.m_hash_set;
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Key, typename T, typename HASH, bool STABLE>
|
|
||||||
HashMap<Key, T, HASH, STABLE>::HashMap(HashMap<Key, T, HASH, STABLE>&& other)
|
|
||||||
{
|
|
||||||
*this = move(other);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Key, typename T, typename HASH, bool STABLE>
|
|
||||||
HashMap<Key, T, HASH, STABLE>::~HashMap()
|
|
||||||
{
|
|
||||||
clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Key, typename T, typename HASH, bool STABLE>
|
|
||||||
HashMap<Key, T, HASH, STABLE>& HashMap<Key, T, HASH, STABLE>::operator=(const HashMap<Key, T, HASH, STABLE>& other)
|
|
||||||
{
|
|
||||||
clear();
|
|
||||||
m_buckets = other.m_buckets;
|
|
||||||
m_size = other.m_size;
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Key, typename T, typename HASH, bool STABLE>
|
HashMap(HashMap&& other) { *this = BAN::move(other); }
|
||||||
HashMap<Key, T, HASH, STABLE>& HashMap<Key, T, HASH, STABLE>::operator=(HashMap<Key, T, HASH, STABLE>&& other)
|
HashMap& operator=(HashMap&& other)
|
||||||
{
|
{
|
||||||
clear();
|
m_hash_set = BAN::move(other.m_hash_set);
|
||||||
m_buckets = move(other.m_buckets);
|
|
||||||
m_size = other.m_size;
|
|
||||||
other.m_size = 0;
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Key, typename T, typename HASH, bool STABLE>
|
iterator begin() { return iterator(m_hash_set.begin()); }
|
||||||
ErrorOr<void> HashMap<Key, T, HASH, STABLE>::insert(const Key& key, const T& value)
|
iterator end() { return iterator(m_hash_set.end()); }
|
||||||
{
|
const_iterator begin() const { return const_iterator(m_hash_set.begin()); }
|
||||||
return insert(key, move(T(value)));
|
const_iterator end() const { return const_iterator(m_hash_set.end()); }
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Key, typename T, typename HASH, bool STABLE>
|
ErrorOr<iterator> insert(const Key& key, const T& value) { return emplace(key, value); }
|
||||||
ErrorOr<void> HashMap<Key, T, HASH, STABLE>::insert(const Key& key, T&& value)
|
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); }
|
||||||
return emplace(key, move(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 Key, typename T, typename HASH, bool STABLE>
|
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
ErrorOr<void> HashMap<Key, T, HASH, STABLE>::emplace(const Key& key, Args&&... args)
|
ErrorOr<iterator> emplace(const Key& key, Args&&... args) requires is_constructible_v<T, Args...>
|
||||||
|
{ return emplace(Key(key), BAN::forward<Args>(args)...); }
|
||||||
|
template<typename... Args>
|
||||||
|
ErrorOr<iterator> emplace(Key&& key, Args&&... args) requires is_constructible_v<T, Args...>
|
||||||
{
|
{
|
||||||
ASSERT(!contains(key));
|
ASSERT(!contains(key));
|
||||||
TRY(rebucket(m_size + 1));
|
auto it = TRY(m_hash_set.insert(Entry { BAN::move(key), T(BAN::forward<Args>(args)...) }));
|
||||||
auto& bucket = get_bucket(key);
|
return iterator(it);
|
||||||
TRY(bucket.emplace_back(key, forward<Args>(args)...));
|
|
||||||
m_size++;
|
|
||||||
return {};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Key, typename T, typename HASH, bool STABLE>
|
template<typename... Args>
|
||||||
ErrorOr<void> HashMap<Key, T, HASH, STABLE>::reserve(size_type size)
|
ErrorOr<iterator> emplace_or_assign(const Key& key, Args&&... args) requires is_constructible_v<T, Args...>
|
||||||
|
{ return emplace_or_assign(Key(key), BAN::forward<Args>(args)...); }
|
||||||
|
template<typename... Args>
|
||||||
|
ErrorOr<iterator> emplace_or_assign(Key&& key, Args&&... args) requires is_constructible_v<T, Args...>
|
||||||
{
|
{
|
||||||
TRY(rebucket(size));
|
if (auto it = m_hash_set.find(key); it != m_hash_set.end())
|
||||||
return {};
|
{
|
||||||
|
const_cast<T&>(it->value) = T(BAN::forward<Args>(args)...);
|
||||||
|
return iterator(it);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Key, typename T, typename HASH, bool STABLE>
|
auto it = TRY(m_hash_set.insert(Entry { BAN::move(key), T(BAN::forward<Args>(args)...) }));
|
||||||
void HashMap<Key, T, HASH, STABLE>::remove(const Key& key)
|
return iterator(it);
|
||||||
{
|
|
||||||
if (empty()) return;
|
|
||||||
auto& bucket = get_bucket(key);
|
|
||||||
for (auto it = bucket.begin(); it != bucket.end(); it++)
|
|
||||||
{
|
|
||||||
if (it->key == key)
|
|
||||||
{
|
|
||||||
bucket.remove(it);
|
|
||||||
m_size--;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Key, typename T, typename HASH, bool STABLE>
|
template<detail::HashMapFindable<Key, HASH, COMP> U>
|
||||||
void HashMap<Key, T, HASH, STABLE>::clear()
|
void remove(const U& key)
|
||||||
{
|
{
|
||||||
m_buckets.clear();
|
if (auto it = find(key); it != end())
|
||||||
m_size = 0;
|
remove(it);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Key, typename T, typename HASH, bool STABLE>
|
iterator remove(iterator it)
|
||||||
T& HashMap<Key, T, HASH, STABLE>::operator[](const Key& key)
|
|
||||||
{
|
{
|
||||||
ASSERT(!empty());
|
return iterator(m_hash_set.remove(it.m_iterator));
|
||||||
auto& bucket = get_bucket(key);
|
|
||||||
for (Entry& entry : bucket)
|
|
||||||
if (entry.key == key)
|
|
||||||
return entry.value;
|
|
||||||
ASSERT(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Key, typename T, typename HASH, bool STABLE>
|
template<detail::HashMapFindable<Key, HASH, COMP> U>
|
||||||
const T& HashMap<Key, T, HASH, STABLE>::operator[](const Key& key) const
|
iterator find(const U& key)
|
||||||
{
|
{
|
||||||
ASSERT(!empty());
|
return iterator(m_hash_set.find(key));
|
||||||
const auto& bucket = get_bucket(key);
|
|
||||||
for (const Entry& entry : bucket)
|
|
||||||
if (entry.key == key)
|
|
||||||
return entry.value;
|
|
||||||
ASSERT(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Key, typename T, typename HASH, bool STABLE>
|
template<detail::HashMapFindable<Key, HASH, COMP> U>
|
||||||
bool HashMap<Key, T, HASH, STABLE>::contains(const Key& key) const
|
const_iterator find(const U& key) const
|
||||||
{
|
{
|
||||||
if (empty()) return false;
|
return const_iterator(m_hash_set.find(key));
|
||||||
const auto& bucket = get_bucket(key);
|
|
||||||
for (const Entry& entry : bucket)
|
|
||||||
if (entry.key == key)
|
|
||||||
return true;
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Key, typename T, typename HASH, bool STABLE>
|
void clear()
|
||||||
bool HashMap<Key, T, HASH, STABLE>::empty() const
|
|
||||||
{
|
{
|
||||||
return m_size == 0;
|
m_hash_set.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Key, typename T, typename HASH, bool STABLE>
|
ErrorOr<void> reserve(size_type size)
|
||||||
typename HashMap<Key, T, HASH, STABLE>::size_type HashMap<Key, T, HASH, STABLE>::size() const
|
|
||||||
{
|
{
|
||||||
return m_size;
|
return m_hash_set.reserve(size);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Key, typename T, typename HASH, bool STABLE>
|
template<detail::HashMapFindable<Key, HASH, COMP> U>
|
||||||
ErrorOr<void> HashMap<Key, T, HASH, STABLE>::rebucket(size_type bucket_count)
|
T& operator[](const U& key)
|
||||||
{
|
{
|
||||||
if (m_buckets.size() >= bucket_count)
|
return find(key)->value;
|
||||||
return {};
|
|
||||||
|
|
||||||
size_type new_bucket_count = BAN::Math::max<size_type>(bucket_count, m_buckets.size() * 2);
|
|
||||||
Vector<LinkedList<Entry>> new_buckets;
|
|
||||||
TRY(new_buckets.resize(new_bucket_count));
|
|
||||||
|
|
||||||
for (auto& bucket : m_buckets)
|
|
||||||
{
|
|
||||||
for (Entry& entry : bucket)
|
|
||||||
{
|
|
||||||
size_type bucket_index = HASH()(entry.key) % new_buckets.size();
|
|
||||||
if constexpr(STABLE)
|
|
||||||
TRY(new_buckets[bucket_index].push_back(entry));
|
|
||||||
else
|
|
||||||
TRY(new_buckets[bucket_index].push_back(move(entry)));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
m_buckets = move(new_buckets);
|
template<detail::HashMapFindable<Key, HASH, COMP> U>
|
||||||
return {};
|
const T& operator[](const U& key) const
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Key, typename T, typename HASH, bool STABLE>
|
|
||||||
LinkedList<typename HashMap<Key, T, HASH, STABLE>::Entry>& HashMap<Key, T, HASH, STABLE>::get_bucket(const Key& key)
|
|
||||||
{
|
{
|
||||||
ASSERT(!m_buckets.empty());
|
return find(key)->value;
|
||||||
auto index = HASH()(key) % m_buckets.size();
|
|
||||||
return m_buckets[index];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Key, typename T, typename HASH, bool STABLE>
|
template<detail::HashMapFindable<Key, HASH, COMP> U>
|
||||||
const LinkedList<typename HashMap<Key, T, HASH, STABLE>::Entry>& HashMap<Key, T, HASH, STABLE>::get_bucket(const Key& key) const
|
bool contains(const U& key) const
|
||||||
{
|
{
|
||||||
ASSERT(!m_buckets.empty());
|
return find(key) != end();
|
||||||
auto index = HASH()(key) % m_buckets.size();
|
|
||||||
return m_buckets[index];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unstable hash map moves values between container during rebucketing.
|
size_type capacity() const
|
||||||
// This means that if insertion to map fails, elements could be in invalid state
|
{
|
||||||
// and that container is no longer usable. This is better if either way you are
|
return m_hash_set.capacity();
|
||||||
// going to stop using the hash map after insertion fails.
|
}
|
||||||
template<typename Key, typename T, typename HASH = BAN::hash<Key>>
|
|
||||||
using HashMapUnstable = HashMap<Key, T, HASH, false>;
|
size_type size() const
|
||||||
|
{
|
||||||
|
return m_hash_set.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool empty() const
|
||||||
|
{
|
||||||
|
return m_hash_set.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
HashSet<Entry, EntryHash, EntryComp> m_hash_set;
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,208 +2,358 @@
|
|||||||
|
|
||||||
#include <BAN/Errors.h>
|
#include <BAN/Errors.h>
|
||||||
#include <BAN/Hash.h>
|
#include <BAN/Hash.h>
|
||||||
#include <BAN/Iterators.h>
|
|
||||||
#include <BAN/LinkedList.h>
|
|
||||||
#include <BAN/Math.h>
|
#include <BAN/Math.h>
|
||||||
#include <BAN/Move.h>
|
#include <BAN/Move.h>
|
||||||
#include <BAN/Vector.h>
|
#include <BAN/New.h>
|
||||||
|
|
||||||
namespace BAN
|
namespace BAN
|
||||||
{
|
{
|
||||||
|
|
||||||
template<typename T, typename HASH = hash<T>, bool STABLE = true>
|
template<typename HashSet, typename Bucket, typename T>
|
||||||
|
class HashSetIterator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
HashSetIterator() = default;
|
||||||
|
|
||||||
|
const T& operator*() const
|
||||||
|
{
|
||||||
|
ASSERT(m_bucket);
|
||||||
|
return *m_bucket->element();
|
||||||
|
}
|
||||||
|
|
||||||
|
const T* operator->() const
|
||||||
|
{
|
||||||
|
ASSERT(m_bucket);
|
||||||
|
return m_bucket->element();
|
||||||
|
}
|
||||||
|
|
||||||
|
HashSetIterator& operator++()
|
||||||
|
{
|
||||||
|
ASSERT(m_bucket);
|
||||||
|
m_bucket++;
|
||||||
|
skip_to_valid_bucket();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
HashSetIterator operator++(int)
|
||||||
|
{
|
||||||
|
auto temp = *this;
|
||||||
|
++(*this);
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(HashSetIterator other) const
|
||||||
|
{
|
||||||
|
return m_bucket == other.m_bucket;
|
||||||
|
}
|
||||||
|
bool operator!=(HashSetIterator other) const
|
||||||
|
{
|
||||||
|
return m_bucket != other.m_bucket;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
explicit HashSetIterator(Bucket* bucket)
|
||||||
|
: m_bucket(bucket)
|
||||||
|
{
|
||||||
|
if (m_bucket != nullptr)
|
||||||
|
skip_to_valid_bucket();
|
||||||
|
}
|
||||||
|
|
||||||
|
void skip_to_valid_bucket()
|
||||||
|
{
|
||||||
|
while (m_bucket->state != Bucket::USED && !m_bucket->end)
|
||||||
|
m_bucket++;
|
||||||
|
if (m_bucket->end)
|
||||||
|
m_bucket = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Bucket* m_bucket { nullptr };
|
||||||
|
friend HashSet;
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
|
template<typename T, typename U, typename HASH, typename COMP>
|
||||||
|
concept HashSetFindable = requires(const U& a, const T& b) { COMP()(a, b); HASH()(b); };
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T, typename HASH = BAN::hash<T>, typename COMP = BAN::equal<T>>
|
||||||
class HashSet
|
class HashSet
|
||||||
{
|
{
|
||||||
|
private:
|
||||||
|
struct Bucket
|
||||||
|
{
|
||||||
|
static constexpr uint8_t UNUSED = 0;
|
||||||
|
static constexpr uint8_t USED = 1;
|
||||||
|
static constexpr uint8_t REMOVED = 2;
|
||||||
|
|
||||||
|
alignas(T) uint8_t storage[sizeof(T)];
|
||||||
|
hash_t hash;
|
||||||
|
uint8_t state : 2;
|
||||||
|
uint8_t chain_start : 1;
|
||||||
|
uint8_t end : 1;
|
||||||
|
|
||||||
|
T* element() { return reinterpret_cast<T*>(storage); }
|
||||||
|
const T* element() const { return reinterpret_cast<const T*>(storage); }
|
||||||
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
using value_type = T;
|
using value_type = T;
|
||||||
using size_type = size_t;
|
using size_type = size_t;
|
||||||
using iterator = IteratorDouble<T, Vector, LinkedList, HashSet>;
|
using iterator = HashSetIterator<HashSet, Bucket, T>;
|
||||||
using const_iterator = ConstIteratorDouble<T, Vector, LinkedList, HashSet>;
|
using const_iterator = HashSetIterator<HashSet, const Bucket, const T>;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
HashSet() = default;
|
HashSet() = default;
|
||||||
HashSet(const HashSet&);
|
~HashSet() { clear(); }
|
||||||
HashSet(HashSet&&);
|
|
||||||
|
|
||||||
HashSet& operator=(const HashSet&);
|
HashSet(const HashSet& other) { *this = other; }
|
||||||
HashSet& operator=(HashSet&&);
|
HashSet& operator=(const HashSet& other)
|
||||||
|
|
||||||
ErrorOr<void> insert(const T&);
|
|
||||||
ErrorOr<void> insert(T&&);
|
|
||||||
void remove(const T&);
|
|
||||||
void clear();
|
|
||||||
|
|
||||||
ErrorOr<void> reserve(size_type);
|
|
||||||
|
|
||||||
iterator begin() { return iterator(m_buckets.end(), m_buckets.begin()); }
|
|
||||||
iterator end() { return iterator(m_buckets.end(), m_buckets.end()); }
|
|
||||||
const_iterator begin() const { return const_iterator(m_buckets.end(), m_buckets.begin()); }
|
|
||||||
const_iterator end() const { return const_iterator(m_buckets.end(), m_buckets.end()); }
|
|
||||||
|
|
||||||
bool contains(const T&) const;
|
|
||||||
|
|
||||||
size_type size() const;
|
|
||||||
bool empty() const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
ErrorOr<void> rebucket(size_type);
|
|
||||||
LinkedList<T>& get_bucket(const T&);
|
|
||||||
const LinkedList<T>& get_bucket(const T&) const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
Vector<LinkedList<T>> m_buckets;
|
|
||||||
size_type m_size = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T, typename HASH, bool STABLE>
|
|
||||||
HashSet<T, HASH, STABLE>::HashSet(const HashSet& other)
|
|
||||||
: m_buckets(other.m_buckets)
|
|
||||||
, m_size(other.m_size)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T, typename HASH, bool STABLE>
|
|
||||||
HashSet<T, HASH, STABLE>::HashSet(HashSet&& other)
|
|
||||||
: m_buckets(move(other.m_buckets))
|
|
||||||
, m_size(other.m_size)
|
|
||||||
{
|
|
||||||
other.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T, typename HASH, bool STABLE>
|
|
||||||
HashSet<T, HASH, STABLE>& HashSet<T, HASH, STABLE>::operator=(const HashSet& other)
|
|
||||||
{
|
{
|
||||||
clear();
|
clear();
|
||||||
|
|
||||||
|
MUST(reserve(other.size()));
|
||||||
|
for (auto& bucket : other)
|
||||||
|
MUST(insert(bucket));
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
HashSet(HashSet&& other) { *this = BAN::move(other); }
|
||||||
|
HashSet& operator=(HashSet&& other)
|
||||||
|
{
|
||||||
|
clear();
|
||||||
|
|
||||||
m_buckets = other.m_buckets;
|
m_buckets = other.m_buckets;
|
||||||
|
m_capacity = other.m_capacity;
|
||||||
m_size = other.m_size;
|
m_size = other.m_size;
|
||||||
|
m_removed = other.m_removed;
|
||||||
|
|
||||||
|
other.m_buckets = nullptr;
|
||||||
|
other.m_capacity = 0;
|
||||||
|
other.m_size = 0;
|
||||||
|
other.m_removed = 0;
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, typename HASH, bool STABLE>
|
iterator begin() { return iterator(m_buckets); }
|
||||||
HashSet<T, HASH, STABLE>& HashSet<T, HASH, STABLE>::operator=(HashSet&& other)
|
iterator end() { return iterator(nullptr); }
|
||||||
|
const_iterator begin() const { return const_iterator(m_buckets); }
|
||||||
|
const_iterator end() const { return const_iterator(nullptr); }
|
||||||
|
|
||||||
|
ErrorOr<iterator> insert(const T& value)
|
||||||
{
|
{
|
||||||
clear();
|
return insert(T(value));
|
||||||
m_buckets = move(other.m_buckets);
|
|
||||||
m_size = other.m_size;
|
|
||||||
other.clear();
|
|
||||||
return *this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, typename HASH, bool STABLE>
|
ErrorOr<iterator> insert(T&& value)
|
||||||
ErrorOr<void> HashSet<T, HASH, STABLE>::insert(const T& key)
|
|
||||||
{
|
{
|
||||||
return insert(move(T(key)));
|
if (should_rehash_with_size(m_size + 1))
|
||||||
|
TRY(rehash(m_size * 2));
|
||||||
|
return insert_impl(BAN::move(value), HASH()(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, typename HASH, bool STABLE>
|
template<detail::HashSetFindable<T, HASH, COMP> U>
|
||||||
ErrorOr<void> HashSet<T, HASH, STABLE>::insert(T&& key)
|
void remove(const U& value)
|
||||||
{
|
{
|
||||||
if (!empty() && get_bucket(key).contains(key))
|
if (auto it = find(value); it != end())
|
||||||
return {};
|
remove(it);
|
||||||
|
|
||||||
TRY(rebucket(m_size + 1));
|
|
||||||
TRY(get_bucket(key).push_back(move(key)));
|
|
||||||
m_size++;
|
|
||||||
return {};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, typename HASH, bool STABLE>
|
iterator remove(iterator it)
|
||||||
void HashSet<T, HASH, STABLE>::remove(const T& key)
|
|
||||||
{
|
{
|
||||||
if (empty()) return;
|
auto& bucket = *it.m_bucket;
|
||||||
auto& bucket = get_bucket(key);
|
bucket.element()->~T();
|
||||||
for (auto it = bucket.begin(); it != bucket.end(); it++)
|
bucket.state = Bucket::REMOVED;
|
||||||
{
|
|
||||||
if (*it == key)
|
|
||||||
{
|
|
||||||
bucket.remove(it);
|
|
||||||
m_size--;
|
m_size--;
|
||||||
break;
|
m_removed++;
|
||||||
}
|
return iterator(&bucket);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, typename HASH, bool STABLE>
|
template<detail::HashSetFindable<T, HASH, COMP> U>
|
||||||
void HashSet<T, HASH, STABLE>::clear()
|
iterator find(const U& value)
|
||||||
{
|
{
|
||||||
m_buckets.clear();
|
return iterator(const_cast<Bucket*>(find_impl(value).m_bucket));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<detail::HashSetFindable<T, HASH, COMP> U>
|
||||||
|
const_iterator find(const U& value) const
|
||||||
|
{
|
||||||
|
return find_impl(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear()
|
||||||
|
{
|
||||||
|
if (m_buckets == nullptr)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (size_type i = 0; i < m_capacity; i++)
|
||||||
|
if (m_buckets[i].state == Bucket::USED)
|
||||||
|
m_buckets[i].element()->~T();
|
||||||
|
|
||||||
|
BAN::deallocator(m_buckets);
|
||||||
|
m_buckets = nullptr;
|
||||||
|
m_capacity = 0;
|
||||||
m_size = 0;
|
m_size = 0;
|
||||||
|
m_removed = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, typename HASH, bool STABLE>
|
ErrorOr<void> reserve(size_type size)
|
||||||
ErrorOr<void> HashSet<T, HASH, STABLE>::reserve(size_type size)
|
|
||||||
{
|
{
|
||||||
TRY(rebucket(size));
|
if (should_rehash_with_size(size))
|
||||||
|
TRY(rehash(size * 2));
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, typename HASH, bool STABLE>
|
template<detail::HashSetFindable<T, HASH, COMP> U>
|
||||||
bool HashSet<T, HASH, STABLE>::contains(const T& key) const
|
bool contains(const U& value) const
|
||||||
{
|
{
|
||||||
if (empty()) return false;
|
return find(value) != end();
|
||||||
return get_bucket(key).contains(key);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, typename HASH, bool STABLE>
|
size_type capacity() const
|
||||||
typename HashSet<T, HASH, STABLE>::size_type HashSet<T, HASH, STABLE>::size() const
|
{
|
||||||
|
return m_capacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_type size() const
|
||||||
{
|
{
|
||||||
return m_size;
|
return m_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, typename HASH, bool STABLE>
|
bool empty() const
|
||||||
bool HashSet<T, HASH, STABLE>::empty() const
|
|
||||||
{
|
{
|
||||||
return m_size == 0;
|
return m_size == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, typename HASH, bool STABLE>
|
private:
|
||||||
ErrorOr<void> HashSet<T, HASH, STABLE>::rebucket(size_type bucket_count)
|
ErrorOr<void> rehash(size_type new_capacity)
|
||||||
{
|
{
|
||||||
if (m_buckets.size() >= bucket_count)
|
new_capacity = BAN::Math::max<size_t>(16, BAN::Math::max(new_capacity, m_size + 1));
|
||||||
return {};
|
new_capacity = BAN::Math::round_up_to_power_of_two(new_capacity);
|
||||||
|
|
||||||
size_type new_bucket_count = Math::max<size_type>(bucket_count, m_buckets.size() * 2);
|
void* new_buckets = BAN::allocator((new_capacity + 1) * sizeof(Bucket));
|
||||||
Vector<LinkedList<T>> new_buckets;
|
if (new_buckets == nullptr)
|
||||||
if (new_buckets.resize(new_bucket_count).is_error())
|
return BAN::Error::from_errno(ENOMEM);
|
||||||
return Error::from_errno(ENOMEM);
|
memset(new_buckets, 0, (new_capacity + 1) * sizeof(Bucket));
|
||||||
|
|
||||||
for (auto& bucket : m_buckets)
|
Bucket* old_buckets = m_buckets;
|
||||||
|
const size_type old_capacity = m_capacity;
|
||||||
|
|
||||||
|
m_buckets = static_cast<Bucket*>(new_buckets);
|
||||||
|
m_capacity = new_capacity;
|
||||||
|
m_size = 0;
|
||||||
|
m_removed = 0;
|
||||||
|
|
||||||
|
for (size_type i = 0; i < old_capacity; i++)
|
||||||
{
|
{
|
||||||
for (T& key : bucket)
|
auto& old_bucket = old_buckets[i];
|
||||||
{
|
if (old_bucket.state != Bucket::USED)
|
||||||
size_type bucket_index = HASH()(key) % new_buckets.size();
|
continue;
|
||||||
if constexpr(STABLE)
|
insert_impl(BAN::move(*old_bucket.element()), old_bucket.hash);
|
||||||
TRY(new_buckets[bucket_index].push_back(key));
|
old_bucket.element()->~T();
|
||||||
else
|
|
||||||
TRY(new_buckets[bucket_index].push_back(move(key)));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
m_buckets = move(new_buckets);
|
m_buckets[m_capacity].end = true;
|
||||||
|
|
||||||
|
BAN::deallocator(old_buckets);
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, typename HASH, bool STABLE>
|
template<detail::HashSetFindable<T, HASH, COMP> U>
|
||||||
LinkedList<T>& HashSet<T, HASH, STABLE>::get_bucket(const T& key)
|
const_iterator find_impl(const U& value) const
|
||||||
{
|
{
|
||||||
ASSERT(!m_buckets.empty());
|
if (m_capacity == 0)
|
||||||
size_type index = HASH()(key) % m_buckets.size();
|
return end();
|
||||||
return m_buckets[index];
|
|
||||||
|
bool first = true;
|
||||||
|
const hash_t orig_hash = HASH()(value);
|
||||||
|
for (auto hash = orig_hash;; hash = get_next_hash_in_chain(hash, orig_hash), first = false)
|
||||||
|
{
|
||||||
|
auto& bucket = m_buckets[hash & (m_capacity - 1)];
|
||||||
|
if (bucket.state == Bucket::USED && bucket.hash == orig_hash && COMP()(*bucket.element(), value))
|
||||||
|
return const_iterator(&bucket);
|
||||||
|
if (bucket.state == Bucket::UNUSED)
|
||||||
|
return end();
|
||||||
|
if (!first && bucket.chain_start)
|
||||||
|
return end();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, typename HASH, bool STABLE>
|
iterator insert_impl(T&& value, hash_t orig_hash)
|
||||||
const LinkedList<T>& HashSet<T, HASH, STABLE>::get_bucket(const T& key) const
|
|
||||||
{
|
{
|
||||||
ASSERT(!m_buckets.empty());
|
ASSERT(!should_rehash_with_size(m_size + 1));
|
||||||
size_type index = HASH()(key) % m_buckets.size();
|
|
||||||
return m_buckets[index];
|
Bucket* target = nullptr;
|
||||||
|
|
||||||
|
bool first = true;
|
||||||
|
for (auto hash = orig_hash;; hash = get_next_hash_in_chain(hash, orig_hash), first = false)
|
||||||
|
{
|
||||||
|
auto& bucket = m_buckets[hash & (m_capacity - 1)];
|
||||||
|
|
||||||
|
if (!first)
|
||||||
|
bucket.chain_start = false;
|
||||||
|
|
||||||
|
if (bucket.state == Bucket::USED)
|
||||||
|
{
|
||||||
|
if (bucket.hash != orig_hash || !COMP()(*bucket.element(), value))
|
||||||
|
continue;
|
||||||
|
target = &bucket;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unstable hash set moves values between container during rebucketing.
|
if (target == nullptr)
|
||||||
// This means that if insertion to set fails, elements could be in invalid state
|
target = &bucket;
|
||||||
// and that container is no longer usable. This is better if either way you are
|
|
||||||
// going to stop using the hash set after insertion fails.
|
if (bucket.state == Bucket::UNUSED)
|
||||||
template<typename T, typename HASH = hash<T>>
|
break;
|
||||||
using HashSetUnstable = HashSet<T, HASH, false>;
|
}
|
||||||
|
|
||||||
|
switch (target->state)
|
||||||
|
{
|
||||||
|
case Bucket::USED:
|
||||||
|
target->element()->~T();
|
||||||
|
break;
|
||||||
|
case Bucket::REMOVED:
|
||||||
|
m_removed--;
|
||||||
|
[[fallthrough]];
|
||||||
|
case Bucket::UNUSED:
|
||||||
|
m_size++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
target->chain_start = first && target->state == Bucket::UNUSED;
|
||||||
|
target->hash = orig_hash;
|
||||||
|
target->state = Bucket::USED;
|
||||||
|
|
||||||
|
new (target->element()) T(BAN::move(value));
|
||||||
|
|
||||||
|
return iterator(target);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool should_rehash_with_size(size_type size) const
|
||||||
|
{
|
||||||
|
if (m_capacity < 16)
|
||||||
|
return true;
|
||||||
|
if (size + m_removed > m_capacity / 4 * 3)
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
hash_t get_next_hash_in_chain(hash_t prev_hash, hash_t orig_hash) const
|
||||||
|
{
|
||||||
|
// TODO: does this even provide better performance than `return prev_hash + 1`
|
||||||
|
// when using "good" hash functions
|
||||||
|
return prev_hash * 1103515245 + (orig_hash | 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Bucket* m_buckets { nullptr };
|
||||||
|
size_type m_capacity { 0 };
|
||||||
|
size_type m_size { 0 };
|
||||||
|
size_type m_removed { 0 };
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
79
BAN/include/BAN/IPv4.h
Normal file
79
BAN/include/BAN/IPv4.h
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <BAN/Endianness.h>
|
||||||
|
#include <BAN/Formatter.h>
|
||||||
|
#include <BAN/Hash.h>
|
||||||
|
|
||||||
|
namespace BAN
|
||||||
|
{
|
||||||
|
|
||||||
|
struct IPv4Address
|
||||||
|
{
|
||||||
|
constexpr IPv4Address()
|
||||||
|
: IPv4Address(0)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
constexpr IPv4Address(uint32_t u32_address)
|
||||||
|
{
|
||||||
|
raw = u32_address;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr IPv4Address(uint8_t oct1, uint8_t oct2, uint8_t oct3, uint8_t oct4)
|
||||||
|
{
|
||||||
|
octets[0] = oct1;
|
||||||
|
octets[1] = oct2;
|
||||||
|
octets[2] = oct3;
|
||||||
|
octets[3] = oct4;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr bool operator==(const IPv4Address& other) const
|
||||||
|
{
|
||||||
|
return raw == other.raw;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr IPv4Address mask(const IPv4Address& other) const
|
||||||
|
{
|
||||||
|
return IPv4Address(raw & other.raw);
|
||||||
|
}
|
||||||
|
|
||||||
|
union
|
||||||
|
{
|
||||||
|
uint8_t octets[4];
|
||||||
|
uint32_t raw;
|
||||||
|
} __attribute__((packed));
|
||||||
|
};
|
||||||
|
static_assert(sizeof(IPv4Address) == 4);
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct hash<IPv4Address>
|
||||||
|
{
|
||||||
|
constexpr hash_t operator()(IPv4Address ipv4) const
|
||||||
|
{
|
||||||
|
return hash<uint32_t>()(ipv4.raw);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace BAN::Formatter
|
||||||
|
{
|
||||||
|
|
||||||
|
template<typename F>
|
||||||
|
void print_argument(F putc, const IPv4Address& ipv4, const ValueFormat&)
|
||||||
|
{
|
||||||
|
ValueFormat format {
|
||||||
|
.base = 10,
|
||||||
|
.percision = 0,
|
||||||
|
.fill = 0,
|
||||||
|
.upper = false,
|
||||||
|
};
|
||||||
|
|
||||||
|
print_argument(putc, ipv4.octets[0], format);
|
||||||
|
for (size_t i = 1; i < 4; i++)
|
||||||
|
{
|
||||||
|
putc('.');
|
||||||
|
print_argument(putc, ipv4.octets[i], format);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -3,11 +3,13 @@
|
|||||||
#include <BAN/Assert.h>
|
#include <BAN/Assert.h>
|
||||||
#include <BAN/Traits.h>
|
#include <BAN/Traits.h>
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
namespace BAN
|
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;
|
||||||
@@ -16,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;
|
||||||
@@ -31,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)
|
||||||
@@ -50,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;
|
||||||
}
|
}
|
||||||
@@ -62,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)
|
||||||
{
|
{
|
||||||
@@ -191,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);
|
||||||
@@ -208,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);
|
||||||
@@ -216,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);
|
||||||
@@ -224,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);
|
||||||
@@ -232,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);
|
||||||
@@ -241,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)
|
||||||
@@ -260,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)
|
||||||
{
|
{
|
||||||
@@ -282,7 +284,15 @@ namespace BAN
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void find_valid_or_end()
|
constexpr IteratorDoubleGeneral(const OuterIterator& outer_end, const OuterIterator& outer_current, const InnerIterator& inner_current)
|
||||||
|
: m_outer_end(outer_end)
|
||||||
|
, m_outer_current(outer_current)
|
||||||
|
, m_inner_current(inner_current)
|
||||||
|
{
|
||||||
|
find_valid_or_end();
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr void find_valid_or_end()
|
||||||
{
|
{
|
||||||
while (m_inner_current == m_outer_current->end())
|
while (m_inner_current == m_outer_current->end())
|
||||||
{
|
{
|
||||||
@@ -293,6 +303,9 @@ namespace BAN
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
constexpr OuterIterator outer_current() { return m_outer_current; }
|
||||||
|
constexpr InnerIterator inner_current() { return m_inner_current; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
OuterIterator m_outer_end;
|
OuterIterator m_outer_end;
|
||||||
OuterIterator m_outer_current;
|
OuterIterator m_outer_current;
|
||||||
|
|||||||
156
BAN/include/BAN/Limits.h
Normal file
156
BAN/include/BAN/Limits.h
Normal file
@@ -0,0 +1,156 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <BAN/Traits.h>
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
namespace BAN
|
||||||
|
{
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
class numeric_limits
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
numeric_limits() = delete;
|
||||||
|
|
||||||
|
static inline constexpr T max()
|
||||||
|
{
|
||||||
|
if constexpr(is_same_v<T, char>)
|
||||||
|
return __SCHAR_MAX__;
|
||||||
|
if constexpr(is_same_v<T, signed char>)
|
||||||
|
return __SCHAR_MAX__;
|
||||||
|
if constexpr(is_same_v<T, unsigned char>)
|
||||||
|
return (T)__SCHAR_MAX__ * 2 + 1;
|
||||||
|
|
||||||
|
if constexpr(is_same_v<T, short>)
|
||||||
|
return __SHRT_MAX__;
|
||||||
|
if constexpr(is_same_v<T, int>)
|
||||||
|
return __INT_MAX__;
|
||||||
|
if constexpr(is_same_v<T, long>)
|
||||||
|
return __LONG_MAX__;
|
||||||
|
if constexpr(is_same_v<T, long long>)
|
||||||
|
return __LONG_LONG_MAX__;
|
||||||
|
|
||||||
|
if constexpr(is_same_v<T, unsigned short>)
|
||||||
|
return (T)__SHRT_MAX__ * 2 + 1;
|
||||||
|
if constexpr(is_same_v<T, unsigned int>)
|
||||||
|
return (T)__INT_MAX__ * 2 + 1;
|
||||||
|
if constexpr(is_same_v<T, unsigned long>)
|
||||||
|
return (T)__LONG_MAX__ * 2 + 1;
|
||||||
|
if constexpr(is_same_v<T, unsigned long long>)
|
||||||
|
return (T)__LONG_LONG_MAX__ * 2 + 1;
|
||||||
|
|
||||||
|
if constexpr(is_same_v<T, float>)
|
||||||
|
return __FLT_MAX__;
|
||||||
|
if constexpr(is_same_v<T, double>)
|
||||||
|
return __DBL_MAX__;
|
||||||
|
if constexpr(is_same_v<T, long double>)
|
||||||
|
return __LDBL_MAX__;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline constexpr T min()
|
||||||
|
{
|
||||||
|
if constexpr(is_signed_v<T> && is_integral_v<T>)
|
||||||
|
return -max() - 1;
|
||||||
|
|
||||||
|
if constexpr(is_unsigned_v<T> && is_integral_v<T>)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if constexpr(is_same_v<T, float>)
|
||||||
|
return __FLT_MIN__;
|
||||||
|
if constexpr(is_same_v<T, double>)
|
||||||
|
return __DBL_MIN__;
|
||||||
|
if constexpr(is_same_v<T, long double>)
|
||||||
|
return __LDBL_MIN__;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline constexpr bool has_infinity()
|
||||||
|
{
|
||||||
|
if constexpr(is_same_v<T, float>)
|
||||||
|
return __FLT_HAS_INFINITY__;
|
||||||
|
if constexpr(is_same_v<T, double>)
|
||||||
|
return __DBL_HAS_INFINITY__;
|
||||||
|
if constexpr(is_same_v<T, long double>)
|
||||||
|
return __LDBL_HAS_INFINITY__;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline constexpr T infinity() requires(has_infinity())
|
||||||
|
{
|
||||||
|
if constexpr(is_same_v<T, float>)
|
||||||
|
return __builtin_inff();
|
||||||
|
if constexpr(is_same_v<T, double>)
|
||||||
|
return __builtin_inf();
|
||||||
|
if constexpr(is_same_v<T, long double>)
|
||||||
|
return __builtin_infl();
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline constexpr bool has_quiet_NaN()
|
||||||
|
{
|
||||||
|
if constexpr(is_same_v<T, float>)
|
||||||
|
return __FLT_HAS_QUIET_NAN__;
|
||||||
|
if constexpr(is_same_v<T, double>)
|
||||||
|
return __DBL_HAS_QUIET_NAN__;
|
||||||
|
if constexpr(is_same_v<T, long double>)
|
||||||
|
return __LDBL_HAS_QUIET_NAN__;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline constexpr T quiet_NaN() requires(has_quiet_NaN())
|
||||||
|
{
|
||||||
|
if constexpr(is_same_v<T, float>)
|
||||||
|
return __builtin_nanf("");
|
||||||
|
if constexpr(is_same_v<T, double>)
|
||||||
|
return __builtin_nan("");
|
||||||
|
if constexpr(is_same_v<T, long double>)
|
||||||
|
return __builtin_nanl("");
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline constexpr int max_exponent2()
|
||||||
|
{
|
||||||
|
static_assert(__FLT_RADIX__ == 2);
|
||||||
|
if constexpr(is_same_v<T, float>)
|
||||||
|
return __FLT_MAX_EXP__;
|
||||||
|
if constexpr(is_same_v<T, double>)
|
||||||
|
return __DBL_MAX_EXP__;
|
||||||
|
if constexpr(is_same_v<T, long double>)
|
||||||
|
return __LDBL_MAX_EXP__;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline constexpr int max_exponent10()
|
||||||
|
{
|
||||||
|
if constexpr(is_same_v<T, float>)
|
||||||
|
return __FLT_MAX_10_EXP__;
|
||||||
|
if constexpr(is_same_v<T, double>)
|
||||||
|
return __DBL_MAX_10_EXP__;
|
||||||
|
if constexpr(is_same_v<T, long double>)
|
||||||
|
return __LDBL_MAX_10_EXP__;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline constexpr int min_exponent2()
|
||||||
|
{
|
||||||
|
static_assert(__FLT_RADIX__ == 2);
|
||||||
|
if constexpr(is_same_v<T, float>)
|
||||||
|
return __FLT_MIN_EXP__;
|
||||||
|
if constexpr(is_same_v<T, double>)
|
||||||
|
return __DBL_MIN_EXP__;
|
||||||
|
if constexpr(is_same_v<T, long double>)
|
||||||
|
return __LDBL_MIN_EXP__;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline constexpr int min_exponent10()
|
||||||
|
{
|
||||||
|
if constexpr(is_same_v<T, float>)
|
||||||
|
return __FLT_MIN_10_EXP__;
|
||||||
|
if constexpr(is_same_v<T, double>)
|
||||||
|
return __DBL_MIN_10_EXP__;
|
||||||
|
if constexpr(is_same_v<T, long double>)
|
||||||
|
return __LDBL_MIN_10_EXP__;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
@@ -34,14 +34,16 @@ 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);
|
||||||
void clear();
|
void clear();
|
||||||
|
|
||||||
|
iterator move_element_to_other_linked_list(LinkedList& dest_list, iterator dest_iter, iterator src_iter);
|
||||||
|
|
||||||
iterator begin() { return iterator(m_data, empty()); }
|
iterator begin() { return iterator(m_data, empty()); }
|
||||||
const_iterator begin() const { return const_iterator(m_data, empty()); }
|
const_iterator begin() const { return const_iterator(m_data, empty()); }
|
||||||
iterator end() { return iterator(m_last, true); }
|
iterator end() { return iterator(m_last, true); }
|
||||||
@@ -65,7 +67,11 @@ namespace BAN
|
|||||||
Node* prev;
|
Node* prev;
|
||||||
};
|
};
|
||||||
|
|
||||||
ErrorOr<Node*> allocate_node() const;
|
template<typename... Args>
|
||||||
|
ErrorOr<Node*> allocate_node(Args&&...) const;
|
||||||
|
|
||||||
|
Node* remove_node(iterator);
|
||||||
|
void insert_node(iterator, Node*);
|
||||||
|
|
||||||
Node* m_data = nullptr;
|
Node* m_data = nullptr;
|
||||||
Node* m_last = nullptr;
|
Node* m_last = nullptr;
|
||||||
@@ -137,6 +143,31 @@ namespace BAN
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
LinkedList<T>::Node* LinkedList<T>::remove_node(iterator iter)
|
||||||
|
{
|
||||||
|
ASSERT(!empty() && iter);
|
||||||
|
Node* node = iter.m_current;
|
||||||
|
Node* prev = node->prev;
|
||||||
|
Node* next = node->next;
|
||||||
|
(prev ? prev->next : m_data) = next;
|
||||||
|
(next ? next->prev : m_last) = prev;
|
||||||
|
m_size--;
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void LinkedList<T>::insert_node(iterator iter, Node* node)
|
||||||
|
{
|
||||||
|
Node* next = iter.m_past_end ? nullptr : iter.m_current;
|
||||||
|
Node* prev = next ? next->prev : m_last;
|
||||||
|
node->next = next;
|
||||||
|
node->prev = prev;
|
||||||
|
(prev ? prev->next : m_data) = node;
|
||||||
|
(next ? next->prev : m_last) = node;
|
||||||
|
m_size++;
|
||||||
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
ErrorOr<void> LinkedList<T>::push_back(const T& value)
|
ErrorOr<void> LinkedList<T>::push_back(const T& value)
|
||||||
{
|
{
|
||||||
@@ -158,44 +189,31 @@ namespace BAN
|
|||||||
template<typename T>
|
template<typename T>
|
||||||
ErrorOr<void> LinkedList<T>::insert(iterator iter, T&& value)
|
ErrorOr<void> LinkedList<T>::insert(iterator iter, T&& value)
|
||||||
{
|
{
|
||||||
Node* next = iter.m_past_end ? nullptr : iter.m_current;
|
Node* new_node = TRY(allocate_node(move(value)));
|
||||||
Node* prev = next ? next->prev : m_last;
|
insert_node(iter, new_node);
|
||||||
Node* new_node = TRY(allocate_node());
|
|
||||||
new (&new_node->value) T(move(value));
|
|
||||||
new_node->next = next;
|
|
||||||
new_node->prev = prev;
|
|
||||||
(prev ? prev->next : m_data) = new_node;
|
|
||||||
(next ? next->prev : m_last) = new_node;
|
|
||||||
m_size++;
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
ErrorOr<void> LinkedList<T>::emplace_back(Args&&... args)
|
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* next = iter.m_past_end ? nullptr : iter.m_current;
|
Node* new_node = TRY(allocate_node(forward<Args>(args)...));
|
||||||
Node* prev = next ? next->prev : m_last;
|
insert_node(iter, new_node);
|
||||||
Node* new_node = TRY(allocate_node());
|
|
||||||
new (&new_node->value) T(forward<Args>(args)...);
|
|
||||||
new_node->next = next;
|
|
||||||
new_node->prev = prev;
|
|
||||||
(prev ? prev->next : m_data) = new_node;
|
|
||||||
(next ? next->prev : m_last) = new_node;
|
|
||||||
m_size++;
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
void LinkedList<T>::pop_back()
|
void LinkedList<T>::pop_back()
|
||||||
{
|
{
|
||||||
|
ASSERT(!empty());
|
||||||
remove(iterator(m_last, false));
|
remove(iterator(m_last, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -203,14 +221,10 @@ namespace BAN
|
|||||||
LinkedList<T>::iterator LinkedList<T>::remove(iterator iter)
|
LinkedList<T>::iterator LinkedList<T>::remove(iterator iter)
|
||||||
{
|
{
|
||||||
ASSERT(!empty() && iter);
|
ASSERT(!empty() && iter);
|
||||||
Node* node = iter.m_current;
|
Node* node = remove_node(iter);
|
||||||
Node* prev = node->prev;
|
|
||||||
Node* next = node->next;
|
Node* next = node->next;
|
||||||
node->value.~T();
|
node->value.~T();
|
||||||
BAN::deallocator(node);
|
BAN::deallocator(node);
|
||||||
(prev ? prev->next : m_data) = next;
|
|
||||||
(next ? next->prev : m_last) = prev;
|
|
||||||
m_size--;
|
|
||||||
return next ? iterator(next, false) : iterator(m_last, true);
|
return next ? iterator(next, false) : iterator(m_last, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -230,6 +244,16 @@ namespace BAN
|
|||||||
m_size = 0;
|
m_size = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
LinkedList<T>::iterator LinkedList<T>::move_element_to_other_linked_list(LinkedList& dest_list, iterator dest_iter, iterator src_iter)
|
||||||
|
{
|
||||||
|
ASSERT(!empty() && src_iter);
|
||||||
|
Node* node = remove_node(src_iter);
|
||||||
|
iterator ret = node->next ? iterator(node->next, false) : iterator(m_last, true);
|
||||||
|
dest_list.insert_node(dest_iter, node);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
const T& LinkedList<T>::back() const
|
const T& LinkedList<T>::back() const
|
||||||
{
|
{
|
||||||
@@ -284,11 +308,13 @@ namespace BAN
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
ErrorOr<typename LinkedList<T>::Node*> LinkedList<T>::allocate_node() const
|
template<typename... Args>
|
||||||
|
ErrorOr<typename LinkedList<T>::Node*> LinkedList<T>::allocate_node(Args&&... args) const
|
||||||
{
|
{
|
||||||
Node* node = (Node*)BAN::allocator(sizeof(Node));
|
Node* node = (Node*)BAN::allocator(sizeof(Node));
|
||||||
if (node == nullptr)
|
if (node == nullptr)
|
||||||
return Error::from_errno(ENOMEM);
|
return Error::from_errno(ENOMEM);
|
||||||
|
new (&node->value) T(forward<Args>(args)...);
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
47
BAN/include/BAN/MAC.h
Normal file
47
BAN/include/BAN/MAC.h
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <BAN/Formatter.h>
|
||||||
|
|
||||||
|
namespace BAN
|
||||||
|
{
|
||||||
|
|
||||||
|
struct MACAddress
|
||||||
|
{
|
||||||
|
uint8_t address[6];
|
||||||
|
|
||||||
|
constexpr bool operator==(const MACAddress& other) const
|
||||||
|
{
|
||||||
|
return
|
||||||
|
address[0] == other.address[0] &&
|
||||||
|
address[1] == other.address[1] &&
|
||||||
|
address[2] == other.address[2] &&
|
||||||
|
address[3] == other.address[3] &&
|
||||||
|
address[4] == other.address[4] &&
|
||||||
|
address[5] == other.address[5];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace BAN::Formatter
|
||||||
|
{
|
||||||
|
|
||||||
|
template<typename F>
|
||||||
|
void print_argument(F putc, const MACAddress& mac, const ValueFormat&)
|
||||||
|
{
|
||||||
|
ValueFormat format {
|
||||||
|
.base = 16,
|
||||||
|
.percision = 0,
|
||||||
|
.fill = 2,
|
||||||
|
.upper = true,
|
||||||
|
};
|
||||||
|
|
||||||
|
print_argument(putc, mac.address[0], format);
|
||||||
|
for (size_t i = 1; i < 6; i++)
|
||||||
|
{
|
||||||
|
putc(':');
|
||||||
|
print_argument(putc, mac.address[i], format);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
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,424 @@ 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> requires(sizeof(T) <= 8)
|
||||||
|
inline constexpr T round_up_to_power_of_two(T x)
|
||||||
|
{
|
||||||
|
x--;
|
||||||
|
x |= x >> 1;
|
||||||
|
x |= x >> 2;
|
||||||
|
x |= x >> 4;
|
||||||
|
if constexpr(sizeof(T) >= 2)
|
||||||
|
x |= x >> 8;
|
||||||
|
if constexpr(sizeof(T) >= 4)
|
||||||
|
x |= x >> 16;
|
||||||
|
if constexpr(sizeof(T) >= 8)
|
||||||
|
x |= x >> 32;
|
||||||
|
return x + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
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,4 +1,10 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
inline void* operator new(size_t, void* addr) { return addr; }
|
#if __has_include(<new>)
|
||||||
inline void* operator new[](size_t, void* addr) { return addr; }
|
#include <new>
|
||||||
|
#else
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
inline void* operator new(size_t, void* addr) { return addr; }
|
||||||
|
inline void* operator new[](size_t, void* addr) { return addr; }
|
||||||
|
#endif
|
||||||
|
|||||||
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();
|
||||||
@@ -45,6 +45,7 @@ namespace BAN
|
|||||||
void clear();
|
void clear();
|
||||||
|
|
||||||
bool empty() const;
|
bool empty() const;
|
||||||
|
size_type capacity() const;
|
||||||
size_type size() const;
|
size_type size() const;
|
||||||
|
|
||||||
const T& front() const;
|
const T& front() const;
|
||||||
@@ -130,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)...);
|
||||||
@@ -186,6 +187,12 @@ namespace BAN
|
|||||||
return m_size == 0;
|
return m_size == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
typename Queue<T>::size_type Queue<T>::capacity() const
|
||||||
|
{
|
||||||
|
return m_capacity;
|
||||||
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
typename Queue<T>::size_type Queue<T>::size() const
|
typename Queue<T>::size_type Queue<T>::size() const
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <BAN/Atomic.h>
|
||||||
#include <BAN/Errors.h>
|
#include <BAN/Errors.h>
|
||||||
|
#include <BAN/Hash.h>
|
||||||
#include <BAN/Move.h>
|
#include <BAN/Move.h>
|
||||||
#include <BAN/NoCopyMove.h>
|
#include <BAN/NoCopyMove.h>
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
namespace BAN
|
namespace BAN
|
||||||
{
|
{
|
||||||
@@ -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)
|
||||||
@@ -115,17 +129,15 @@ namespace BAN
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
T* ptr() { ASSERT(!empty()); return m_pointer; }
|
T* ptr() const { return m_pointer; }
|
||||||
const T* ptr() const { ASSERT(!empty()); return m_pointer; }
|
T& operator*() const { ASSERT(!empty()); return *ptr(); }
|
||||||
|
T* operator->() const { ASSERT(!empty()); return ptr(); }
|
||||||
|
|
||||||
T& operator*() { return *ptr(); }
|
bool operator==(RefPtr other) const { return m_pointer == other.m_pointer; }
|
||||||
const T& operator*() const { return *ptr(); }
|
bool operator!=(RefPtr other) const { return m_pointer != other.m_pointer; }
|
||||||
|
|
||||||
T* operator->() { return ptr(); }
|
|
||||||
const T* operator->() const { return ptr(); }
|
|
||||||
|
|
||||||
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()
|
||||||
{
|
{
|
||||||
@@ -141,4 +153,13 @@ namespace BAN
|
|||||||
friend class RefPtr;
|
friend class RefPtr;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct hash<RefPtr<T>>
|
||||||
|
{
|
||||||
|
constexpr hash_t operator()(const RefPtr<T>& ptr) const
|
||||||
|
{
|
||||||
|
return hash<T*>()(ptr.ptr());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,15 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <BAN/Heap.h>
|
||||||
|
#include <BAN/Math.h>
|
||||||
#include <BAN/Swap.h>
|
#include <BAN/Swap.h>
|
||||||
#include <BAN/Traits.h>
|
#include <BAN/Traits.h>
|
||||||
#include <BAN/Math.h>
|
#include <BAN/Vector.h>
|
||||||
|
|
||||||
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)
|
||||||
@@ -41,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)
|
||||||
@@ -51,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));
|
||||||
@@ -66,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);
|
||||||
@@ -166,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);
|
||||||
@@ -175,7 +101,62 @@ namespace BAN::sort
|
|||||||
detail::intro_sort_impl(begin, end, 2 * Math::ilog2(len), comp);
|
detail::intro_sort_impl(begin, end, 2 * Math::ilog2(len), comp);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename It, typename Comp = less<typename It::value_type>>
|
namespace detail
|
||||||
|
{
|
||||||
|
|
||||||
|
template<unsigned_integral T>
|
||||||
|
consteval T lsb_index(T value)
|
||||||
|
{
|
||||||
|
for (T result = 0;; result++)
|
||||||
|
if (value & (1 << result))
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename It, size_t radix = 256>
|
||||||
|
requires is_unsigned_v<it_value_type_t<It>> && (radix > 0 && (radix & (radix - 1)) == 0)
|
||||||
|
BAN::ErrorOr<void> radix_sort(It begin, It end)
|
||||||
|
{
|
||||||
|
using value_type = it_value_type_t<It>;
|
||||||
|
|
||||||
|
const size_t len = distance(begin, end);
|
||||||
|
if (len <= 1)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
Vector<value_type> temp;
|
||||||
|
TRY(temp.resize(len));
|
||||||
|
|
||||||
|
Vector<size_t> counts;
|
||||||
|
TRY(counts.resize(radix));
|
||||||
|
|
||||||
|
constexpr size_t mask = radix - 1;
|
||||||
|
constexpr size_t shift = detail::lsb_index(radix);
|
||||||
|
|
||||||
|
for (size_t s = 0; s < sizeof(value_type) * 8; s += shift)
|
||||||
|
{
|
||||||
|
for (auto& cnt : counts)
|
||||||
|
cnt = 0;
|
||||||
|
for (It it = begin; it != end; ++it)
|
||||||
|
counts[(*it >> s) & mask]++;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < radix - 1; i++)
|
||||||
|
counts[i + 1] += counts[i];
|
||||||
|
|
||||||
|
for (It it = end; it != begin;)
|
||||||
|
{
|
||||||
|
--it;
|
||||||
|
temp[--counts[(*it >> s) & mask]] = *it;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t j = 0; j < temp.size(); j++)
|
||||||
|
*next(begin, j) = temp[j];
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename It, typename Comp = less<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
|
||||||
{
|
{
|
||||||
@@ -106,6 +112,40 @@ namespace BAN
|
|||||||
template<typename T> inline constexpr bool is_unsigned_v = is_unsigned<T>::value;
|
template<typename T> inline constexpr bool is_unsigned_v = is_unsigned<T>::value;
|
||||||
template<typename T> concept unsigned_integral = is_unsigned_v<T> && is_integral_v<T>;
|
template<typename T> concept unsigned_integral = is_unsigned_v<T> && is_integral_v<T>;
|
||||||
|
|
||||||
|
#define __BAN_TRAITS_MAKE_UNSIGNED_CV(__type) \
|
||||||
|
template<> struct make_unsigned<__type> { using type = unsigned __type; }; \
|
||||||
|
template<> struct make_unsigned<const __type> { using type = unsigned const __type; }; \
|
||||||
|
template<> struct make_unsigned<volatile __type> { using type = unsigned volatile __type; }; \
|
||||||
|
template<> struct make_unsigned<const volatile __type> { using type = unsigned const volatile __type; };
|
||||||
|
|
||||||
|
template<typename T> requires is_arithmetic_v<T> struct make_unsigned { using type = T; };
|
||||||
|
__BAN_TRAITS_MAKE_UNSIGNED_CV(char)
|
||||||
|
__BAN_TRAITS_MAKE_UNSIGNED_CV(short)
|
||||||
|
__BAN_TRAITS_MAKE_UNSIGNED_CV(int)
|
||||||
|
__BAN_TRAITS_MAKE_UNSIGNED_CV(long)
|
||||||
|
__BAN_TRAITS_MAKE_UNSIGNED_CV(long long)
|
||||||
|
template<typename T> using make_unsigned_t = typename make_unsigned<T>::type;
|
||||||
|
#undef __BAN_TRAITS_MAKE_UNSIGNED_CV
|
||||||
|
|
||||||
|
#define __BAN_TRAITS_MAKE_SIGNED_CV(__type) \
|
||||||
|
template<> struct make_signed<unsigned __type> { using type = __type; }; \
|
||||||
|
template<> struct make_signed<unsigned const __type> { using type = const __type; }; \
|
||||||
|
template<> struct make_signed<unsigned volatile __type> { using type = volatile __type; }; \
|
||||||
|
template<> struct make_signed<unsigned const volatile __type> { using type = const volatile __type; };
|
||||||
|
|
||||||
|
template<typename T> requires is_arithmetic_v<T> struct make_signed { using type = T; };
|
||||||
|
__BAN_TRAITS_MAKE_SIGNED_CV(char)
|
||||||
|
__BAN_TRAITS_MAKE_SIGNED_CV(short)
|
||||||
|
__BAN_TRAITS_MAKE_SIGNED_CV(int)
|
||||||
|
__BAN_TRAITS_MAKE_SIGNED_CV(long)
|
||||||
|
__BAN_TRAITS_MAKE_SIGNED_CV(long long)
|
||||||
|
template<typename T> using make_signed_t = typename make_signed<T>::type;
|
||||||
|
#undef __BAN_TRAITS_MAKE_SIGNED_CV
|
||||||
|
|
||||||
|
template<typename T> struct 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <BAN/Errors.h>
|
#include <BAN/Errors.h>
|
||||||
|
#include <BAN/Hash.h>
|
||||||
#include <BAN/NoCopyMove.h>
|
#include <BAN/NoCopyMove.h>
|
||||||
|
|
||||||
namespace BAN
|
namespace BAN
|
||||||
@@ -33,8 +34,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)...);
|
||||||
@@ -52,32 +54,12 @@ namespace BAN
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
T& operator*()
|
T* ptr() const { return m_pointer; }
|
||||||
{
|
T& operator*() const { ASSERT(!empty()); return *ptr(); }
|
||||||
ASSERT(m_pointer);
|
T* operator->() const { ASSERT(!empty()); return ptr(); }
|
||||||
return *m_pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
const T& operator*() const
|
bool empty() const { return m_pointer == nullptr; }
|
||||||
{
|
explicit operator bool() const { return m_pointer; }
|
||||||
ASSERT(m_pointer);
|
|
||||||
return *m_pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
T* operator->()
|
|
||||||
{
|
|
||||||
ASSERT(m_pointer);
|
|
||||||
return m_pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
const T* operator->() const
|
|
||||||
{
|
|
||||||
ASSERT(m_pointer);
|
|
||||||
return m_pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
T* ptr() { return m_pointer; }
|
|
||||||
const T* ptr() const { return m_pointer; }
|
|
||||||
|
|
||||||
void clear()
|
void clear()
|
||||||
{
|
{
|
||||||
@@ -86,8 +68,6 @@ namespace BAN
|
|||||||
m_pointer = nullptr;
|
m_pointer = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
operator bool() const { return m_pointer != nullptr; }
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
T* m_pointer = nullptr;
|
T* m_pointer = nullptr;
|
||||||
|
|
||||||
@@ -95,4 +75,13 @@ namespace BAN
|
|||||||
friend class UniqPtr;
|
friend class UniqPtr;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct hash<UniqPtr<T>>
|
||||||
|
{
|
||||||
|
constexpr hash_t operator()(const UniqPtr<T>& ptr) const
|
||||||
|
{
|
||||||
|
return hash<T*>()(ptr.ptr());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
@@ -216,6 +220,14 @@ namespace BAN
|
|||||||
return m_index == detail::index<T, Ts...>();
|
return m_index == detail::index<T, Ts...>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename T, typename... Args>
|
||||||
|
void emplace(Args&&... args) requires (can_have<T>() && is_constructible_v<T, Args...>)
|
||||||
|
{
|
||||||
|
clear();
|
||||||
|
m_index = detail::index<T, Ts...>();
|
||||||
|
new (m_storage) T(BAN::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
void set(T&& value) requires (can_have<T>() && !is_lvalue_reference_v<T>)
|
void set(T&& value) requires (can_have<T>() && !is_lvalue_reference_v<T>)
|
||||||
{
|
{
|
||||||
@@ -278,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,6 +110,8 @@ namespace BAN
|
|||||||
|
|
||||||
bool valid() const { return m_link && m_link->valid(); }
|
bool valid() const { return m_link && m_link->valid(); }
|
||||||
|
|
||||||
|
explicit operator bool() const { return valid(); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
WeakPtr(const RefPtr<WeakLink<T>>& link)
|
WeakPtr(const RefPtr<WeakLink<T>>& link)
|
||||||
: m_link(link)
|
: m_link(link)
|
||||||
|
|||||||
@@ -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,406 +0,0 @@
|
|||||||
#include <BAN/ScopeGuard.h>
|
|
||||||
#include <LibELF/ELF.h>
|
|
||||||
#include <LibELF/Values.h>
|
|
||||||
|
|
||||||
#ifdef __is_kernel
|
|
||||||
#include <kernel/FS/VirtualFileSystem.h>
|
|
||||||
#include <kernel/Memory/PageTableScope.h>
|
|
||||||
#include <kernel/Process.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <fcntl.h>
|
|
||||||
|
|
||||||
#define ELF_PRINT_HEADERS 0
|
|
||||||
|
|
||||||
#ifdef __is_kernel
|
|
||||||
extern uint8_t g_kernel_end[];
|
|
||||||
using namespace Kernel;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace LibELF
|
|
||||||
{
|
|
||||||
|
|
||||||
#ifdef __is_kernel
|
|
||||||
BAN::ErrorOr<BAN::UniqPtr<ELF>> ELF::load_from_file(BAN::RefPtr<Inode> inode)
|
|
||||||
{
|
|
||||||
BAN::Vector<uint8_t> buffer;
|
|
||||||
TRY(buffer.resize(inode->size()));
|
|
||||||
|
|
||||||
TRY(inode->read(0, buffer.data(), inode->size()));
|
|
||||||
|
|
||||||
ELF* elf_ptr = new ELF(BAN::move(buffer));
|
|
||||||
if (elf_ptr == nullptr)
|
|
||||||
return BAN::Error::from_errno(ENOMEM);
|
|
||||||
|
|
||||||
auto elf = BAN::UniqPtr<ELF>::adopt(elf_ptr);
|
|
||||||
TRY(elf->load());
|
|
||||||
|
|
||||||
return BAN::move(elf);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
BAN::ErrorOr<ELF*> ELF::load_from_file(BAN::StringView file_path)
|
|
||||||
{
|
|
||||||
ELF* elf = nullptr;
|
|
||||||
|
|
||||||
{
|
|
||||||
BAN::Vector<uint8_t> data;
|
|
||||||
|
|
||||||
int fd = TRY(Kernel::Process::current().open(file_path, O_RDONLY));
|
|
||||||
BAN::ScopeGuard _([fd] { MUST(Kernel::Process::current().close(fd)); });
|
|
||||||
|
|
||||||
struct stat st;
|
|
||||||
TRY(Kernel::Process::current().fstat(fd, &st));
|
|
||||||
|
|
||||||
TRY(data.resize(st.st_size));
|
|
||||||
|
|
||||||
TRY(Kernel::Process::current().read(fd, data.data(), data.size()));
|
|
||||||
|
|
||||||
elf = new ELF(BAN::move(data));
|
|
||||||
ASSERT(elf);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (auto res = elf->load(); res.is_error())
|
|
||||||
{
|
|
||||||
delete elf;
|
|
||||||
return res.error();
|
|
||||||
}
|
|
||||||
|
|
||||||
return elf;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
BAN::ErrorOr<void> ELF::load()
|
|
||||||
{
|
|
||||||
if (m_data.size() < EI_NIDENT)
|
|
||||||
{
|
|
||||||
dprintln("Too small ELF file");
|
|
||||||
return BAN::Error::from_errno(EINVAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_data[EI_MAG0] != ELFMAG0 ||
|
|
||||||
m_data[EI_MAG1] != ELFMAG1 ||
|
|
||||||
m_data[EI_MAG2] != ELFMAG2 ||
|
|
||||||
m_data[EI_MAG3] != ELFMAG3)
|
|
||||||
{
|
|
||||||
dprintln("Invalid ELF header");
|
|
||||||
return BAN::Error::from_errno(EINVAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_data[EI_DATA] != ELFDATA2LSB)
|
|
||||||
{
|
|
||||||
dprintln("Only little-endian is supported");
|
|
||||||
return BAN::Error::from_errno(EINVAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_data[EI_VERSION] != EV_CURRENT)
|
|
||||||
{
|
|
||||||
dprintln("Invalid ELF version");
|
|
||||||
return BAN::Error::from_errno(EINVAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_data[EI_CLASS] == ELFCLASS64)
|
|
||||||
{
|
|
||||||
if (m_data.size() <= sizeof(Elf64FileHeader))
|
|
||||||
{
|
|
||||||
dprintln("Too small ELF file");
|
|
||||||
return BAN::Error::from_errno(EINVAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto& header = file_header64();
|
|
||||||
if (!parse_elf64_file_header(header))
|
|
||||||
return BAN::Error::from_errno(EINVAL);
|
|
||||||
|
|
||||||
for (size_t i = 0; i < header.e_phnum; i++)
|
|
||||||
{
|
|
||||||
auto& program_header = program_header64(i);
|
|
||||||
if (!parse_elf64_program_header(program_header))
|
|
||||||
return BAN::Error::from_errno(EINVAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t i = 1; i < header.e_shnum; i++)
|
|
||||||
{
|
|
||||||
auto& section_header = section_header64(i);
|
|
||||||
if (!parse_elf64_section_header(section_header))
|
|
||||||
return BAN::Error::from_errno(EINVAL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (m_data[EI_CLASS] == ELFCLASS32)
|
|
||||||
{
|
|
||||||
if (m_data.size() <= sizeof(Elf32FileHeader))
|
|
||||||
{
|
|
||||||
dprintln("Too small ELF file");
|
|
||||||
return BAN::Error::from_errno(EINVAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto& header = file_header32();
|
|
||||||
if (!parse_elf32_file_header(header))
|
|
||||||
return BAN::Error::from_errno(EINVAL);
|
|
||||||
|
|
||||||
for (size_t i = 0; i < header.e_phnum; i++)
|
|
||||||
{
|
|
||||||
auto& program_header = program_header32(i);
|
|
||||||
if (!parse_elf32_program_header(program_header))
|
|
||||||
return BAN::Error::from_errno(EINVAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t i = 1; i < header.e_shnum; i++)
|
|
||||||
{
|
|
||||||
auto& section_header = section_header32(i);
|
|
||||||
if (!parse_elf32_section_header(section_header))
|
|
||||||
return BAN::Error::from_errno(EINVAL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ELF::is_x86_32() const { return m_data[EI_CLASS] == ELFCLASS32; }
|
|
||||||
bool ELF::is_x86_64() const { return m_data[EI_CLASS] == ELFCLASS64; }
|
|
||||||
|
|
||||||
/*
|
|
||||||
|
|
||||||
64 bit ELF
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
const char* ELF::lookup_section_name64(uint32_t offset) const
|
|
||||||
{
|
|
||||||
return lookup_string64(file_header64().e_shstrndx, offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* ELF::lookup_string64(size_t table_index, uint32_t offset) const
|
|
||||||
{
|
|
||||||
if (table_index == SHN_UNDEF)
|
|
||||||
return nullptr;
|
|
||||||
auto& section_header = section_header64(table_index);
|
|
||||||
return (const char*)m_data.data() + section_header.sh_offset + offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ELF::parse_elf64_file_header(const Elf64FileHeader& header)
|
|
||||||
{
|
|
||||||
if (header.e_type != ET_EXEC)
|
|
||||||
{
|
|
||||||
dprintln("Only executable files are supported");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (header.e_version != EV_CURRENT)
|
|
||||||
{
|
|
||||||
dprintln("Invalid ELF version");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ELF::parse_elf64_program_header(const Elf64ProgramHeader& header)
|
|
||||||
{
|
|
||||||
#if ELF_PRINT_HEADERS
|
|
||||||
dprintln("program header");
|
|
||||||
dprintln(" type {H}", header.p_type);
|
|
||||||
dprintln(" flags {H}", header.p_flags);
|
|
||||||
dprintln(" offset {H}", header.p_offset);
|
|
||||||
dprintln(" vaddr {H}", header.p_vaddr);
|
|
||||||
dprintln(" paddr {H}", header.p_paddr);
|
|
||||||
dprintln(" filesz {}", header.p_filesz);
|
|
||||||
dprintln(" memsz {}", header.p_memsz);
|
|
||||||
dprintln(" align {}", header.p_align);
|
|
||||||
#endif
|
|
||||||
(void)header;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ELF::parse_elf64_section_header(const Elf64SectionHeader& header)
|
|
||||||
{
|
|
||||||
#if ELF_PRINT_HEADERS
|
|
||||||
if (auto* name = lookup_section_name64(header.sh_name))
|
|
||||||
dprintln("{}", name);
|
|
||||||
|
|
||||||
switch (header.sh_type)
|
|
||||||
{
|
|
||||||
case SHT_NULL:
|
|
||||||
dprintln(" SHT_NULL");
|
|
||||||
break;
|
|
||||||
case SHT_PROGBITS:
|
|
||||||
dprintln(" SHT_PROGBITS");
|
|
||||||
break;
|
|
||||||
case SHT_SYMTAB:
|
|
||||||
for (size_t i = 1; i < header.sh_size / header.sh_entsize; i++)
|
|
||||||
{
|
|
||||||
auto& symbol = ((const Elf64Symbol*)(m_data.data() + header.sh_offset))[i];
|
|
||||||
if (auto* name = lookup_string64(header.sh_link, symbol.st_name))
|
|
||||||
dprintln(" {}", name);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case SHT_STRTAB:
|
|
||||||
dprintln(" SHT_STRTAB");
|
|
||||||
break;
|
|
||||||
case SHT_RELA:
|
|
||||||
dprintln(" SHT_RELA");
|
|
||||||
break;
|
|
||||||
case SHT_NOBITS:
|
|
||||||
dprintln(" SHT_NOBITS");
|
|
||||||
break;
|
|
||||||
case SHT_REL:
|
|
||||||
dprintln(" SHT_REL");
|
|
||||||
break;
|
|
||||||
case SHT_SHLIB:
|
|
||||||
dprintln(" SHT_SHLIB");
|
|
||||||
break;
|
|
||||||
case SHT_DYNSYM:
|
|
||||||
dprintln(" SHT_DYNSYM");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
ASSERT(false);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
(void)header;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
const Elf64FileHeader& ELF::file_header64() const
|
|
||||||
{
|
|
||||||
ASSERT(is_x86_64());
|
|
||||||
return *(const Elf64FileHeader*)m_data.data();
|
|
||||||
}
|
|
||||||
|
|
||||||
const Elf64ProgramHeader& ELF::program_header64(size_t index) const
|
|
||||||
{
|
|
||||||
ASSERT(is_x86_64());
|
|
||||||
const auto& file_header = file_header64();
|
|
||||||
ASSERT(index < file_header.e_phnum);
|
|
||||||
return *(const Elf64ProgramHeader*)(m_data.data() + file_header.e_phoff + file_header.e_phentsize * index);
|
|
||||||
}
|
|
||||||
|
|
||||||
const Elf64SectionHeader& ELF::section_header64(size_t index) const
|
|
||||||
{
|
|
||||||
ASSERT(is_x86_64());
|
|
||||||
const auto& file_header = file_header64();
|
|
||||||
ASSERT(index < file_header.e_shnum);
|
|
||||||
return *(const Elf64SectionHeader*)(m_data.data() + file_header.e_shoff + file_header.e_shentsize * index);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
|
|
||||||
32 bit ELF
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
const char* ELF::lookup_section_name32(uint32_t offset) const
|
|
||||||
{
|
|
||||||
return lookup_string32(file_header32().e_shstrndx, offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* ELF::lookup_string32(size_t table_index, uint32_t offset) const
|
|
||||||
{
|
|
||||||
if (table_index == SHN_UNDEF)
|
|
||||||
return nullptr;
|
|
||||||
auto& section_header = section_header32(table_index);
|
|
||||||
return (const char*)m_data.data() + section_header.sh_offset + offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ELF::parse_elf32_file_header(const Elf32FileHeader& header)
|
|
||||||
{
|
|
||||||
if (header.e_type != ET_EXEC)
|
|
||||||
{
|
|
||||||
dprintln("Only executable files are supported");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (header.e_version != EV_CURRENT)
|
|
||||||
{
|
|
||||||
dprintln("Invalid ELF version");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ELF::parse_elf32_program_header(const Elf32ProgramHeader& header)
|
|
||||||
{
|
|
||||||
#if ELF_PRINT_HEADERS
|
|
||||||
dprintln("program header");
|
|
||||||
dprintln(" type {H}", header.p_type);
|
|
||||||
dprintln(" flags {H}", header.p_flags);
|
|
||||||
dprintln(" offset {H}", header.p_offset);
|
|
||||||
dprintln(" vaddr {H}", header.p_vaddr);
|
|
||||||
dprintln(" paddr {H}", header.p_paddr);
|
|
||||||
dprintln(" filesz {}", header.p_filesz);
|
|
||||||
dprintln(" memsz {}", header.p_memsz);
|
|
||||||
dprintln(" align {}", header.p_align);
|
|
||||||
#endif
|
|
||||||
(void)header;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ELF::parse_elf32_section_header(const Elf32SectionHeader& header)
|
|
||||||
{
|
|
||||||
#if ELF_PRINT_HEADERS
|
|
||||||
if (auto* name = lookup_section_name32(header.sh_name))
|
|
||||||
dprintln("{}", name);
|
|
||||||
|
|
||||||
switch (header.sh_type)
|
|
||||||
{
|
|
||||||
case SHT_NULL:
|
|
||||||
dprintln(" SHT_NULL");
|
|
||||||
break;
|
|
||||||
case SHT_PROGBITS:
|
|
||||||
dprintln(" SHT_PROGBITS");
|
|
||||||
break;
|
|
||||||
case SHT_SYMTAB:
|
|
||||||
for (size_t i = 1; i < header.sh_size / header.sh_entsize; i++)
|
|
||||||
{
|
|
||||||
auto& symbol = ((const Elf32Symbol*)(m_data.data() + header.sh_offset))[i];
|
|
||||||
if (auto* name = lookup_string32(header.sh_link, symbol.st_name))
|
|
||||||
dprintln(" {}", name);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case SHT_STRTAB:
|
|
||||||
dprintln(" SHT_STRTAB");
|
|
||||||
break;
|
|
||||||
case SHT_RELA:
|
|
||||||
dprintln(" SHT_RELA");
|
|
||||||
break;
|
|
||||||
case SHT_NOBITS:
|
|
||||||
dprintln(" SHT_NOBITS");
|
|
||||||
break;
|
|
||||||
case SHT_REL:
|
|
||||||
dprintln(" SHT_REL");
|
|
||||||
break;
|
|
||||||
case SHT_SHLIB:
|
|
||||||
dprintln(" SHT_SHLIB");
|
|
||||||
break;
|
|
||||||
case SHT_DYNSYM:
|
|
||||||
dprintln(" SHT_DYNSYM");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
ASSERT(false);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
(void)header;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
const Elf32FileHeader& ELF::file_header32() const
|
|
||||||
{
|
|
||||||
ASSERT(is_x86_32());
|
|
||||||
return *(const Elf32FileHeader*)m_data.data();
|
|
||||||
}
|
|
||||||
|
|
||||||
const Elf32ProgramHeader& ELF::program_header32(size_t index) const
|
|
||||||
{
|
|
||||||
ASSERT(is_x86_32());
|
|
||||||
const auto& file_header = file_header32();
|
|
||||||
ASSERT(index < file_header.e_phnum);
|
|
||||||
return *(const Elf32ProgramHeader*)(m_data.data() + file_header.e_phoff + file_header.e_phentsize * index);
|
|
||||||
}
|
|
||||||
|
|
||||||
const Elf32SectionHeader& ELF::section_header32(size_t index) const
|
|
||||||
{
|
|
||||||
ASSERT(is_x86_32());
|
|
||||||
const auto& file_header = file_header32();
|
|
||||||
ASSERT(index < file_header.e_shnum);
|
|
||||||
return *(const Elf32SectionHeader*)(m_data.data() + file_header.e_shoff + file_header.e_shentsize * index);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,339 +0,0 @@
|
|||||||
#include <BAN/ScopeGuard.h>
|
|
||||||
#include <kernel/CriticalScope.h>
|
|
||||||
#include <kernel/Memory/Heap.h>
|
|
||||||
#include <kernel/LockGuard.h>
|
|
||||||
#include <LibELF/LoadableELF.h>
|
|
||||||
#include <LibELF/Values.h>
|
|
||||||
|
|
||||||
namespace LibELF
|
|
||||||
{
|
|
||||||
|
|
||||||
using namespace Kernel;
|
|
||||||
|
|
||||||
BAN::ErrorOr<BAN::UniqPtr<LoadableELF>> LoadableELF::load_from_inode(PageTable& page_table, BAN::RefPtr<Inode> inode)
|
|
||||||
{
|
|
||||||
auto* elf_ptr = new LoadableELF(page_table, inode);
|
|
||||||
if (elf_ptr == nullptr)
|
|
||||||
return BAN::Error::from_errno(ENOMEM);
|
|
||||||
auto elf = BAN::UniqPtr<LoadableELF>::adopt(elf_ptr);
|
|
||||||
TRY(elf->initialize());
|
|
||||||
return BAN::move(elf);
|
|
||||||
}
|
|
||||||
|
|
||||||
LoadableELF::LoadableELF(PageTable& page_table, BAN::RefPtr<Inode> inode)
|
|
||||||
: m_inode(inode)
|
|
||||||
, m_page_table(page_table)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
LoadableELF::~LoadableELF()
|
|
||||||
{
|
|
||||||
if (!m_loaded)
|
|
||||||
return;
|
|
||||||
for (const auto& program_header : m_program_headers)
|
|
||||||
{
|
|
||||||
switch (program_header.p_type)
|
|
||||||
{
|
|
||||||
case PT_NULL:
|
|
||||||
continue;
|
|
||||||
case PT_LOAD:
|
|
||||||
{
|
|
||||||
vaddr_t start = program_header.p_vaddr & PAGE_ADDR_MASK;
|
|
||||||
size_t pages = range_page_count(program_header.p_vaddr, program_header.p_memsz);
|
|
||||||
for (size_t i = 0; i < pages; i++)
|
|
||||||
{
|
|
||||||
paddr_t paddr = m_page_table.physical_address_of(start + i * PAGE_SIZE);
|
|
||||||
if (paddr != 0)
|
|
||||||
Heap::get().release_page(paddr);
|
|
||||||
}
|
|
||||||
m_page_table.unmap_range(start, pages * PAGE_SIZE);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
ASSERT_NOT_REACHED();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
BAN::ErrorOr<void> LoadableELF::initialize()
|
|
||||||
{
|
|
||||||
if ((size_t)m_inode->size() < sizeof(ElfNativeFileHeader))
|
|
||||||
{
|
|
||||||
dprintln("Too small file");
|
|
||||||
return BAN::Error::from_errno(ENOEXEC);
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t nread = TRY(m_inode->read(0, BAN::ByteSpan::from(m_file_header)));
|
|
||||||
ASSERT(nread == sizeof(m_file_header));
|
|
||||||
|
|
||||||
if (m_file_header.e_ident[EI_MAG0] != ELFMAG0 ||
|
|
||||||
m_file_header.e_ident[EI_MAG1] != ELFMAG1 ||
|
|
||||||
m_file_header.e_ident[EI_MAG2] != ELFMAG2 ||
|
|
||||||
m_file_header.e_ident[EI_MAG3] != ELFMAG3)
|
|
||||||
{
|
|
||||||
dprintln("Invalid magic in header");
|
|
||||||
return BAN::Error::from_errno(ENOEXEC);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_file_header.e_ident[EI_DATA] != ELFDATA2LSB)
|
|
||||||
{
|
|
||||||
dprintln("Only little-endian is supported");
|
|
||||||
return BAN::Error::from_errno(ENOEXEC);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_file_header.e_ident[EI_VERSION] != EV_CURRENT)
|
|
||||||
{
|
|
||||||
dprintln("Invalid version");
|
|
||||||
return BAN::Error::from_errno(ENOEXEC);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if ARCH(i386)
|
|
||||||
if (m_file_header.e_ident[EI_CLASS] != ELFCLASS32)
|
|
||||||
#elif ARCH(x86_64)
|
|
||||||
if (m_file_header.e_ident[EI_CLASS] != ELFCLASS64)
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
dprintln("Not in native format");
|
|
||||||
return BAN::Error::from_errno(EINVAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_file_header.e_type != ET_EXEC)
|
|
||||||
{
|
|
||||||
dprintln("Only executable files are supported");
|
|
||||||
return BAN::Error::from_errno(EINVAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_file_header.e_version != EV_CURRENT)
|
|
||||||
{
|
|
||||||
dprintln("Unsupported version");
|
|
||||||
return BAN::Error::from_errno(EINVAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
ASSERT(m_file_header.e_phentsize <= sizeof(ElfNativeProgramHeader));
|
|
||||||
|
|
||||||
TRY(m_program_headers.resize(m_file_header.e_phnum));
|
|
||||||
for (size_t i = 0; i < m_file_header.e_phnum; i++)
|
|
||||||
{
|
|
||||||
TRY(m_inode->read(m_file_header.e_phoff + m_file_header.e_phentsize * i, BAN::ByteSpan::from(m_program_headers[i])));
|
|
||||||
|
|
||||||
const auto& pheader = m_program_headers[i];
|
|
||||||
if (pheader.p_type != PT_NULL && pheader.p_type != PT_LOAD)
|
|
||||||
{
|
|
||||||
dprintln("Unsupported program header type {}", pheader.p_type);
|
|
||||||
return BAN::Error::from_errno(ENOTSUP);
|
|
||||||
}
|
|
||||||
if (pheader.p_memsz < pheader.p_filesz)
|
|
||||||
{
|
|
||||||
dprintln("Invalid program header");
|
|
||||||
return BAN::Error::from_errno(EINVAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
m_virtual_page_count += BAN::Math::div_round_up<size_t>((pheader.p_vaddr % PAGE_SIZE) + pheader.p_memsz, PAGE_SIZE);
|
|
||||||
}
|
|
||||||
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
vaddr_t LoadableELF::entry_point() const
|
|
||||||
{
|
|
||||||
return m_file_header.e_entry;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool LoadableELF::contains(vaddr_t address) const
|
|
||||||
{
|
|
||||||
for (const auto& program_header : m_program_headers)
|
|
||||||
{
|
|
||||||
switch (program_header.p_type)
|
|
||||||
{
|
|
||||||
case PT_NULL:
|
|
||||||
continue;
|
|
||||||
case PT_LOAD:
|
|
||||||
if (program_header.p_vaddr <= address && address < program_header.p_vaddr + program_header.p_memsz)
|
|
||||||
return true;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
ASSERT_NOT_REACHED();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool LoadableELF::is_address_space_free() const
|
|
||||||
{
|
|
||||||
for (const auto& program_header : m_program_headers)
|
|
||||||
{
|
|
||||||
switch (program_header.p_type)
|
|
||||||
{
|
|
||||||
case PT_NULL:
|
|
||||||
break;
|
|
||||||
case PT_LOAD:
|
|
||||||
{
|
|
||||||
vaddr_t page_vaddr = program_header.p_vaddr & PAGE_ADDR_MASK;
|
|
||||||
size_t pages = range_page_count(program_header.p_vaddr, program_header.p_memsz);
|
|
||||||
if (!m_page_table.is_range_free(page_vaddr, pages * PAGE_SIZE))
|
|
||||||
return false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
ASSERT_NOT_REACHED();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void LoadableELF::reserve_address_space()
|
|
||||||
{
|
|
||||||
for (const auto& program_header : m_program_headers)
|
|
||||||
{
|
|
||||||
switch (program_header.p_type)
|
|
||||||
{
|
|
||||||
case PT_NULL:
|
|
||||||
break;
|
|
||||||
case PT_LOAD:
|
|
||||||
{
|
|
||||||
vaddr_t page_vaddr = program_header.p_vaddr & PAGE_ADDR_MASK;
|
|
||||||
size_t pages = range_page_count(program_header.p_vaddr, program_header.p_memsz);
|
|
||||||
ASSERT(m_page_table.reserve_range(page_vaddr, pages * PAGE_SIZE));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
ASSERT_NOT_REACHED();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
m_loaded = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
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();
|
|
||||||
|
|
||||||
ASSERT(&PageTable::current() == &m_page_table);
|
|
||||||
LockGuard _(m_page_table);
|
|
||||||
ASSERT(m_page_table.is_page_free(0));
|
|
||||||
|
|
||||||
for (const auto& program_header : m_program_headers)
|
|
||||||
{
|
|
||||||
switch (program_header.p_type)
|
|
||||||
{
|
|
||||||
case PT_NULL:
|
|
||||||
break;
|
|
||||||
case PT_LOAD:
|
|
||||||
{
|
|
||||||
if (!(program_header.p_flags & LibELF::PF_W))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
PageTable::flags_t flags = PageTable::Flags::UserSupervisor | PageTable::Flags::Present;
|
|
||||||
if (program_header.p_flags & LibELF::PF_W)
|
|
||||||
flags |= PageTable::Flags::ReadWrite;
|
|
||||||
if (program_header.p_flags & LibELF::PF_X)
|
|
||||||
flags |= PageTable::Flags::Execute;
|
|
||||||
|
|
||||||
vaddr_t start = program_header.p_vaddr & PAGE_ADDR_MASK;
|
|
||||||
size_t pages = range_page_count(program_header.p_vaddr, program_header.p_memsz);
|
|
||||||
|
|
||||||
for (size_t i = 0; i < pages; i++)
|
|
||||||
{
|
|
||||||
if (m_page_table.physical_address_of(start + i * PAGE_SIZE) == 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
paddr_t paddr = Heap::get().take_free_page();
|
|
||||||
if (paddr == 0)
|
|
||||||
return BAN::Error::from_errno(ENOMEM);
|
|
||||||
|
|
||||||
{
|
|
||||||
CriticalScope _;
|
|
||||||
PageTable::map_fast_page(paddr);
|
|
||||||
memcpy(PageTable::fast_page_as_ptr(), (void*)(start + i * PAGE_SIZE), PAGE_SIZE);
|
|
||||||
PageTable::unmap_fast_page();
|
|
||||||
}
|
|
||||||
|
|
||||||
new_page_table.map_page_at(paddr, start + i * PAGE_SIZE, flags);
|
|
||||||
elf->m_physical_page_count++;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
ASSERT_NOT_REACHED();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return elf;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -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(i386)
|
|
||||||
const Elf32FileHeader& file_header_native() const { return file_header32(); }
|
|
||||||
const Elf32ProgramHeader& program_header_native(size_t index) const { return program_header32(index); }
|
|
||||||
const Elf32SectionHeader& section_header_native(size_t index) const { return section_header32(index); }
|
|
||||||
const char* lookup_section_name_native(uint32_t offset) const { return lookup_section_name32(offset); }
|
|
||||||
const char* lookup_string_native(size_t table_index, uint32_t offset) const { return lookup_string32(table_index, offset); }
|
|
||||||
bool is_native() const { return is_x86_32(); }
|
|
||||||
#endif
|
|
||||||
|
|
||||||
const uint8_t* data() const { return m_data.data(); }
|
|
||||||
|
|
||||||
bool is_x86_32() const;
|
|
||||||
bool is_x86_64() const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
//#ifdef __is_kernel
|
|
||||||
// ELF(BAN::UniqPtr<Kernel::VirtualRange>&& storage, size_t size)
|
|
||||||
// : m_storage(BAN::move(storage))
|
|
||||||
// , m_data((const uint8_t*)m_storage->vaddr(), size)
|
|
||||||
// {}
|
|
||||||
//#else
|
|
||||||
ELF(BAN::Vector<uint8_t>&& data)
|
|
||||||
: m_data(BAN::move(data))
|
|
||||||
{}
|
|
||||||
//#endif
|
|
||||||
BAN::ErrorOr<void> load();
|
|
||||||
|
|
||||||
bool parse_elf64_file_header(const Elf64FileHeader&);
|
|
||||||
bool parse_elf64_program_header(const Elf64ProgramHeader&);
|
|
||||||
bool parse_elf64_section_header(const Elf64SectionHeader&);
|
|
||||||
|
|
||||||
bool parse_elf32_file_header(const Elf32FileHeader&);
|
|
||||||
bool parse_elf32_program_header(const Elf32ProgramHeader&);
|
|
||||||
bool parse_elf32_section_header(const Elf32SectionHeader&);
|
|
||||||
|
|
||||||
private:
|
|
||||||
//#ifdef __is_kernel
|
|
||||||
// BAN::UniqPtr<Kernel::VirtualRange> m_storage;
|
|
||||||
// BAN::Span<const uint8_t> m_data;
|
|
||||||
//#else
|
|
||||||
const BAN::Vector<uint8_t> m_data;
|
|
||||||
//#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,57 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#ifndef __is_kernel
|
|
||||||
#error "This is kernel only header"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <BAN/UniqPtr.h>
|
|
||||||
#include <BAN/Vector.h>
|
|
||||||
|
|
||||||
#include <kernel/Credentials.h>
|
|
||||||
#include <kernel/FS/Inode.h>
|
|
||||||
#include <kernel/Memory/PageTable.h>
|
|
||||||
|
|
||||||
#include <LibELF/Types.h>
|
|
||||||
|
|
||||||
namespace LibELF
|
|
||||||
{
|
|
||||||
|
|
||||||
class LoadableELF
|
|
||||||
{
|
|
||||||
BAN_NON_COPYABLE(LoadableELF);
|
|
||||||
BAN_NON_MOVABLE(LoadableELF);
|
|
||||||
|
|
||||||
public:
|
|
||||||
static BAN::ErrorOr<BAN::UniqPtr<LoadableELF>> load_from_inode(Kernel::PageTable&, BAN::RefPtr<Kernel::Inode>);
|
|
||||||
~LoadableELF();
|
|
||||||
|
|
||||||
Kernel::vaddr_t entry_point() const;
|
|
||||||
|
|
||||||
bool contains(Kernel::vaddr_t address) const;
|
|
||||||
bool is_address_space_free() const;
|
|
||||||
void reserve_address_space();
|
|
||||||
|
|
||||||
void update_suid_sgid(Kernel::Credentials&);
|
|
||||||
|
|
||||||
BAN::ErrorOr<void> load_page_to_memory(Kernel::vaddr_t address);
|
|
||||||
|
|
||||||
BAN::ErrorOr<BAN::UniqPtr<LoadableELF>> clone(Kernel::PageTable&);
|
|
||||||
|
|
||||||
size_t virtual_page_count() const { return m_virtual_page_count; }
|
|
||||||
size_t physical_page_count() const { return m_physical_page_count; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
LoadableELF(Kernel::PageTable&, BAN::RefPtr<Kernel::Inode>);
|
|
||||||
BAN::ErrorOr<void> initialize();
|
|
||||||
|
|
||||||
private:
|
|
||||||
BAN::RefPtr<Kernel::Inode> m_inode;
|
|
||||||
Kernel::PageTable& m_page_table;
|
|
||||||
ElfNativeFileHeader m_file_header;
|
|
||||||
BAN::Vector<ElfNativeProgramHeader> m_program_headers;
|
|
||||||
size_t m_virtual_page_count = 0;
|
|
||||||
size_t m_physical_page_count = 0;
|
|
||||||
bool m_loaded { false };
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,140 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
namespace LibELF
|
|
||||||
{
|
|
||||||
|
|
||||||
enum ELF_Ident
|
|
||||||
{
|
|
||||||
ELFMAG0 = 0x7F,
|
|
||||||
ELFMAG1 = 'E',
|
|
||||||
ELFMAG2 = 'L',
|
|
||||||
ELFMAG3 = 'F',
|
|
||||||
|
|
||||||
ELFCLASSNONE = 0,
|
|
||||||
ELFCLASS32 = 1,
|
|
||||||
ELFCLASS64 = 2,
|
|
||||||
|
|
||||||
ELFDATANONE = 0,
|
|
||||||
ELFDATA2LSB = 1,
|
|
||||||
ELFDATA2MSB = 2,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum ELF_EI
|
|
||||||
{
|
|
||||||
EI_MAG0 = 0,
|
|
||||||
EI_MAG1 = 1,
|
|
||||||
EI_MAG2 = 2,
|
|
||||||
EI_MAG3 = 3,
|
|
||||||
EI_CLASS = 4,
|
|
||||||
EI_DATA = 5,
|
|
||||||
EI_VERSION = 6,
|
|
||||||
EI_OSABI = 7,
|
|
||||||
EI_ABIVERSION = 8,
|
|
||||||
EI_NIDENT = 16,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum ELF_ET
|
|
||||||
{
|
|
||||||
ET_NONE = 0,
|
|
||||||
ET_REL = 1,
|
|
||||||
ET_EXEC = 2,
|
|
||||||
ET_DYN = 3,
|
|
||||||
ET_CORE = 4,
|
|
||||||
ET_LOOS = 0xfe00,
|
|
||||||
ET_HIOS = 0xfeff,
|
|
||||||
ET_LOPROC = 0xff00,
|
|
||||||
ET_HIPROC = 0xffff,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum ELF_EV
|
|
||||||
{
|
|
||||||
EV_NONE = 0,
|
|
||||||
EV_CURRENT = 1,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum ELF_SHT
|
|
||||||
{
|
|
||||||
SHT_NULL = 0,
|
|
||||||
SHT_PROGBITS = 1,
|
|
||||||
SHT_SYMTAB = 2,
|
|
||||||
SHT_STRTAB = 3,
|
|
||||||
SHT_RELA = 4,
|
|
||||||
SHT_NOBITS = 8,
|
|
||||||
SHT_REL = 9,
|
|
||||||
SHT_SHLIB = 10,
|
|
||||||
SHT_DYNSYM = 11,
|
|
||||||
SHT_LOOS = 0x60000000,
|
|
||||||
SHT_HIOS = 0x6FFFFFFF,
|
|
||||||
SHT_LOPROC = 0x70000000,
|
|
||||||
SHT_HIPROC = 0x7FFFFFFF,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum ELF_SHF
|
|
||||||
{
|
|
||||||
SHF_WRITE = 0x1,
|
|
||||||
SHF_ALLOC = 0x2,
|
|
||||||
SHF_EXECINSTR = 0x4,
|
|
||||||
SHF_MASKOS = 0x0F000000,
|
|
||||||
SHF_MASKPROC = 0xF0000000,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum ELF_SHN
|
|
||||||
{
|
|
||||||
SHN_UNDEF = 0,
|
|
||||||
SHN_LOPROC = 0xFF00,
|
|
||||||
SHN_HIPROC = 0xFF1F,
|
|
||||||
SHN_LOOS = 0xFF20,
|
|
||||||
SHN_HIOS = 0xFF3F,
|
|
||||||
SHN_ABS = 0xFFF1,
|
|
||||||
SHN_COMMON = 0xFFF2,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum ELF_STB
|
|
||||||
{
|
|
||||||
STB_LOCAL = 0,
|
|
||||||
STB_GLOBAL = 1,
|
|
||||||
STB_WEAK = 2,
|
|
||||||
STB_LOOS = 10,
|
|
||||||
STB_HIOS = 12,
|
|
||||||
STB_LOPROC = 13,
|
|
||||||
STB_HIPROC = 15,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum ELF_STT
|
|
||||||
{
|
|
||||||
STT_NOTYPE = 0,
|
|
||||||
STT_OBJECT = 1,
|
|
||||||
STT_FUNC = 2,
|
|
||||||
STT_SECTION = 3,
|
|
||||||
STT_FILE = 4,
|
|
||||||
STT_LOOS = 10,
|
|
||||||
STT_HIOS = 12,
|
|
||||||
STT_LOPROC = 13,
|
|
||||||
STT_HIPROC = 15,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum ELF_PT
|
|
||||||
{
|
|
||||||
PT_NULL = 0,
|
|
||||||
PT_LOAD = 1,
|
|
||||||
PT_DYNAMIC = 2,
|
|
||||||
PT_INTERP = 3,
|
|
||||||
PT_NOTE = 4,
|
|
||||||
PT_SHLIB = 5,
|
|
||||||
PT_PHDR = 6,
|
|
||||||
PT_LOOS = 0x60000000,
|
|
||||||
PT_HIOS = 0x6FFFFFFF,
|
|
||||||
PT_LOPROC = 0x70000000,
|
|
||||||
PT_HIPROC = 0x7FFFFFFF,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum ELF_PF
|
|
||||||
{
|
|
||||||
PF_X = 0x1,
|
|
||||||
PF_W = 0x2,
|
|
||||||
PF_R = 0x4,
|
|
||||||
PF_MASKOS = 0x00FF0000,
|
|
||||||
PF_MASKPROC = 0xFF000000,
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
117
README.md
117
README.md
@@ -1,8 +1,77 @@
|
|||||||

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

|

|
||||||
|
|
||||||
@@ -15,44 +84,58 @@ Each major component and library has its own subdirectory (kernel, userspace, li
|
|||||||
### Needed packages
|
### Needed packages
|
||||||
|
|
||||||
#### apt (tested on ubuntu 22.04)
|
#### apt (tested on ubuntu 22.04)
|
||||||
```# apt install build-essential git ninja-build texinfo bison flex libgmp-dev libmpfr-dev libmpc-dev parted qemu-system-x86```
|
```# apt install build-essential git ninja-build texinfo bison flex libgmp-dev libmpfr-dev libmpc-dev parted qemu-system-x86 cpu-checker```
|
||||||
|
|
||||||
#### pacman
|
#### pacman
|
||||||
```# pacman -S --needed base-devel git wget cmake ninja parted qemu-system-x86```
|
```# pacman -S --needed base-devel git wget cmake ninja parted qemu-system-x86```
|
||||||
|
|
||||||
> ***NOTE:*** You need cmake version of atleast 2.26. If you are using cmake that is not found from PATH, you can set the CMAKE\_COMMAND environment variable to point to the correct cmake binary. Or you can let build script download correct version of cmake if you don't have one.
|
|
||||||
|
|
||||||
When you clone this reposity, make sure to also clone submodules. This can be done by cloning with the command ```git clone --recurse-submodules https://git.bananymous.com/bananymous/banan-os.git``` or if you have already cloned this repo, run ```git submodule init && git submodule update```.
|
### Compilation
|
||||||
|
|
||||||
To build the toolchain for this os. You can run the following command.
|
To build the toolchain for this os. You can run the following command.
|
||||||
> ***NOTE:*** The following step has to be done only once. This might take a long time since we are compiling binutils and gcc.
|
> ***NOTE:*** The following step has to be done only once. This might take a long time since we are compiling binutils and gcc.
|
||||||
```sh
|
```sh
|
||||||
./script/build.sh toolchain
|
./bos toolchain
|
||||||
```
|
```
|
||||||
|
|
||||||
To build the os itself you can run one of the following commands. You will need root access for disk image creation/modification.
|
To build the os itself you can run one of the following commands. You will need root access for disk image creation/modification.
|
||||||
```sh
|
```sh
|
||||||
./script/build.sh qemu
|
./bos qemu
|
||||||
./script/build.sh qemu-nographic
|
./bos qemu-nographic
|
||||||
./script/build.sh qemu-debug
|
./bos qemu-debug
|
||||||
./script/build.sh bochs
|
./bos bochs
|
||||||
```
|
```
|
||||||
|
|
||||||
You can also build the kernel or disk image without running it:
|
You can also build the kernel or disk image without running it:
|
||||||
```sh
|
```sh
|
||||||
./script/build.sh kernel
|
./bos kernel
|
||||||
./script/build.sh image
|
./bos image
|
||||||
```
|
```
|
||||||
|
|
||||||
|
To build for other architectures set environment variable BANAN\_ARCH=*arch* (e.g. BANAN\_ARCH=i686).
|
||||||
|
|
||||||
|
To change the bootloader you can set environment variable BANAN\_BOOTLOADER; supported values are BANAN (my custom bootloader) and GRUB.
|
||||||
|
|
||||||
|
To run with UEFI set environment variable BANAN\_UEFI\_BOOT=1. You will also have to set OVMF\_PATH to the correct OVMF (default */usr/share/ovmf/x64/OVMF.fd*).
|
||||||
|
|
||||||
|
To build an image with no physical root filesystem, but an initrd set environment variable BANAN\_INITRD=1. This can be used when testing on hardware with unsupported USB controller.
|
||||||
|
|
||||||
If you have corrupted your disk image or want to create new one, you can either manually delete *build/banan-os.img* and build system will automatically create you a new one or you can run the following command.
|
If you have corrupted your disk image or want to create new one, you can either manually delete *build/banan-os.img* and build system will automatically create you a new one or you can run the following command.
|
||||||
```sh
|
```sh
|
||||||
./script/build.sh image-full
|
./bos image-full
|
||||||
```
|
```
|
||||||
|
|
||||||
If you feel like ```./script/build.sh``` is too verbose, there exists a symlink _bos_ in this projects root directory. All build commands can be used with ```./bos args...``` instead.
|
|
||||||
|
|
||||||
I have also created shell completion script for zsh. You can either copy the file in _script/shell-completion/zsh/\_bos_ to _/usr/share/zsh/site-functions/_ or add the _script/shell-completion/zsh_ to your fpath in _.zshrc_.
|
I have also created shell completion script for zsh. You can either copy the file in _script/shell-completion/zsh/\_bos_ to _/usr/share/zsh/site-functions/_ or add the _script/shell-completion/zsh_ to your fpath in _.zshrc_.
|
||||||
|
|
||||||
### Contributing
|
## Contributing
|
||||||
|
|
||||||
Currently I don't accept contributions to this repository unless explicitly told otherwise. This is a learning project for me and I want to do everything myself. Feel free to fork/clone this repo and tinker with it yourself.
|
As the upstream is hosted on my server https://git.bananymous.com/Bananymous/banan-os, merging contributions is not as trivial as it would be on GitHub. You can still send PRs in GitHub in which case I should be able to download the diff and apply it manually. If you want, I can also provide you an account to my git server. In this case please contact me ([email](mailto:oskari.alaranta@bananymous.com), [discord](https://discord.gg/ehjGySwYdK)).
|
||||||
|
|
||||||
|
As this is mostly a learning experience for me, I would appreciate if you first contacted me about adding new features (email, discord, issue, ...). If you send a PR about something I was planning on doing myself and you didn't ask me, I will probably just close it. Bug fixes are always welcome!
|
||||||
|
|
||||||
|
Commit message should be formatted followingly
|
||||||
|
|
||||||
|
1. First line is of the form "_Subject: Description_", where _Subject_ tells the area touched (Kernel, Shell, BuildSystem, ...) and _Description_ is brief description of the change done. First line should fit fully in 72 characters.
|
||||||
|
2. Body of the message should further describe the change and reasoning behind the change.
|
||||||
|
|
||||||
|
All commits should pass the pre-commit hook defined in _.pre-commit-config.yaml_. For instructions on how to setup pre-commit, please see https://pre-commit.com/#install.
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 384 KiB |
Binary file not shown.
@@ -15,5 +15,6 @@ set(BOOTLOADER_SOURCES
|
|||||||
)
|
)
|
||||||
|
|
||||||
add_executable(bootloader ${BOOTLOADER_SOURCES})
|
add_executable(bootloader ${BOOTLOADER_SOURCES})
|
||||||
|
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
target_link_options(bootloader PRIVATE LINKER:-T,${CMAKE_CURRENT_SOURCE_DIR}/linker.ld)
|
target_link_options(bootloader PRIVATE LINKER:-T,${CMAKE_CURRENT_SOURCE_DIR}/linker.ld)
|
||||||
target_link_options(bootloader PRIVATE -nostdlib)
|
target_link_options(bootloader PRIVATE -nostdlib)
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
.include "common.S"
|
||||||
|
|
||||||
.code16
|
.code16
|
||||||
|
|
||||||
#########################################
|
#########################################
|
||||||
@@ -103,12 +105,12 @@ stage2_main:
|
|||||||
movl %edx, %cr0
|
movl %edx, %cr0
|
||||||
|
|
||||||
# jump to protected mode
|
# jump to protected mode
|
||||||
ljmpl $0x18, $protected_mode
|
ljmpl $GDT_CODE32, $protected_mode
|
||||||
|
|
||||||
.code32
|
.code32
|
||||||
protected_mode:
|
protected_mode:
|
||||||
# setup protected mode segments
|
# setup protected mode segments
|
||||||
movw $0x10, %dx
|
movw $GDT_DATA32, %dx
|
||||||
movw %dx, %ds
|
movw %dx, %ds
|
||||||
movw %dx, %es
|
movw %dx, %es
|
||||||
movw %dx, %fs
|
movw %dx, %fs
|
||||||
@@ -127,15 +129,15 @@ enter_unreal_mode:
|
|||||||
movl %cr0, %eax
|
movl %cr0, %eax
|
||||||
orb $1, %al
|
orb $1, %al
|
||||||
movl %eax, %cr0
|
movl %eax, %cr0
|
||||||
ljmpl $0x8, $.enter_unreal_mode_pmode
|
ljmpl $GDT_CODE16, $.enter_unreal_mode_pmode
|
||||||
|
|
||||||
.enter_unreal_mode_pmode:
|
.enter_unreal_mode_pmode:
|
||||||
movw $0x10, %bx
|
movw $GDT_DATA32, %bx
|
||||||
movw %bx, %ds
|
movw %bx, %ds
|
||||||
|
|
||||||
andb $0xFE, %al
|
andb $0xFE, %al
|
||||||
movl %eax, %cr0
|
movl %eax, %cr0
|
||||||
ljmpl $0x0, $.enter_unreal_mode_unreal
|
ljmpl $0x00, $.enter_unreal_mode_unreal
|
||||||
|
|
||||||
.enter_unreal_mode_unreal:
|
.enter_unreal_mode_unreal:
|
||||||
popw %ds
|
popw %ds
|
||||||
@@ -161,7 +163,7 @@ gdt:
|
|||||||
.quad 0x00CF9A000000FFFF # 32-bit code
|
.quad 0x00CF9A000000FFFF # 32-bit code
|
||||||
gdtr:
|
gdtr:
|
||||||
.short . - gdt - 1
|
.short . - gdt - 1
|
||||||
.quad gdt
|
.long gdt
|
||||||
|
|
||||||
banan_boot_info:
|
banan_boot_info:
|
||||||
boot_command_line:
|
boot_command_line:
|
||||||
@@ -170,3 +172,5 @@ banan_boot_info:
|
|||||||
.long framebuffer
|
.long framebuffer
|
||||||
boot_memory_map:
|
boot_memory_map:
|
||||||
.long memory_map
|
.long memory_map
|
||||||
|
boot_kernel_paddr:
|
||||||
|
.long 0
|
||||||
|
|||||||
@@ -84,4 +84,4 @@ command_line:
|
|||||||
# 100 character command line
|
# 100 character command line
|
||||||
command_line_buffer:
|
command_line_buffer:
|
||||||
.ascii "root=/dev/sda2"
|
.ascii "root=/dev/sda2"
|
||||||
.skip 100 - 28
|
.skip 100 - (. - command_line_buffer)
|
||||||
|
|||||||
3
bootloader/bios/common.S
Normal file
3
bootloader/bios/common.S
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
.set GDT_CODE16, 0x08
|
||||||
|
.set GDT_DATA32, 0x10
|
||||||
|
.set GDT_CODE32, 0x18
|
||||||
@@ -5,15 +5,26 @@
|
|||||||
.set e_machine, 18
|
.set e_machine, 18
|
||||||
.set e_version, 20
|
.set e_version, 20
|
||||||
.set e_entry, 24
|
.set e_entry, 24
|
||||||
.set e_phoff, 32
|
|
||||||
.set e_shoff, 40
|
.set e32_phoff, 28
|
||||||
.set e_flags, 48
|
.set e32_shoff, 32
|
||||||
.set e_ehsize, 52
|
.set e32_flags, 36
|
||||||
.set e_phentsize, 54
|
.set e32_ehsize, 40
|
||||||
.set e_phnum, 56
|
.set e32_phentsize, 42
|
||||||
.set e_shentsize, 58
|
.set e32_phnum, 44
|
||||||
.set e_shnum, 60
|
.set e32_shentsize, 46
|
||||||
.set e_shstrndx, 62
|
.set e32_shnum, 48
|
||||||
|
.set e32_shstrndx, 50
|
||||||
|
|
||||||
|
.set e64_phoff, 32
|
||||||
|
.set e64_shoff, 40
|
||||||
|
.set e64_flags, 48
|
||||||
|
.set e64_ehsize, 52
|
||||||
|
.set e64_phentsize, 54
|
||||||
|
.set e64_phnum, 56
|
||||||
|
.set e64_shentsize, 58
|
||||||
|
.set e64_shnum, 60
|
||||||
|
.set e64_shstrndx, 62
|
||||||
|
|
||||||
# e_ident offsets
|
# e_ident offsets
|
||||||
.set EI_CLASS, 4
|
.set EI_CLASS, 4
|
||||||
@@ -22,6 +33,7 @@
|
|||||||
|
|
||||||
# e_ident constants
|
# e_ident constants
|
||||||
.set ELFMAGIC, 0x464C457F
|
.set ELFMAGIC, 0x464C457F
|
||||||
|
.set ELFCLASS32, 1
|
||||||
.set ELFCLASS64, 2
|
.set ELFCLASS64, 2
|
||||||
.set ELFDATA2LSB, 1
|
.set ELFDATA2LSB, 1
|
||||||
.set EV_CURRENT, 1
|
.set EV_CURRENT, 1
|
||||||
@@ -31,18 +43,30 @@
|
|||||||
|
|
||||||
# program header field offsets
|
# program header field offsets
|
||||||
.set p_type, 0
|
.set p_type, 0
|
||||||
.set p_flags, 4
|
|
||||||
.set p_offset, 8
|
.set p32_offset, 4
|
||||||
.set p_vaddr, 16
|
.set p32_vaddr, 8
|
||||||
.set p_paddr, 24
|
.set p32_paddr, 12
|
||||||
.set p_filesz, 32
|
.set p32_filesz, 16
|
||||||
.set p_memsz, 40
|
.set p32_memsz, 20
|
||||||
.set p_align, 48
|
.set p32_flags, 24
|
||||||
|
.set p32_align, 28
|
||||||
|
|
||||||
|
.set p64_flags, 4
|
||||||
|
.set p64_offset, 8
|
||||||
|
.set p64_vaddr, 16
|
||||||
|
.set p64_paddr, 24
|
||||||
|
.set p64_filesz, 32
|
||||||
|
.set p64_memsz, 40
|
||||||
|
.set p64_align, 48
|
||||||
|
|
||||||
# p_type constants
|
# p_type constants
|
||||||
.set PT_NULL, 0
|
.set PT_NULL, 0
|
||||||
.set PT_LOAD, 1
|
.set PT_LOAD, 1
|
||||||
|
|
||||||
|
# mask for entry point and segment loading
|
||||||
|
.set LOAD_MASK, 0x07FFFFFF
|
||||||
|
|
||||||
.code16
|
.code16
|
||||||
.section .stage2
|
.section .stage2
|
||||||
|
|
||||||
@@ -52,8 +76,12 @@ elf_validate_file_header:
|
|||||||
cmpl $ELFMAGIC, (elf_file_header)
|
cmpl $ELFMAGIC, (elf_file_header)
|
||||||
jne .elf_validate_file_header_invalid_magic
|
jne .elf_validate_file_header_invalid_magic
|
||||||
|
|
||||||
|
cmpb $ELFCLASS32, (elf_file_header + EI_CLASS)
|
||||||
|
je .elf_validate_file_header_class_valid
|
||||||
cmpb $ELFCLASS64, (elf_file_header + EI_CLASS)
|
cmpb $ELFCLASS64, (elf_file_header + EI_CLASS)
|
||||||
jne .elf_validate_file_header_only_64bit_supported
|
je .elf_validate_file_header_class_valid
|
||||||
|
jmp .elf_validate_file_header_invalid_class
|
||||||
|
.elf_validate_file_header_class_valid:
|
||||||
|
|
||||||
cmpb $ELFDATA2LSB, (elf_file_header + EI_DATA)
|
cmpb $ELFDATA2LSB, (elf_file_header + EI_DATA)
|
||||||
jne .elf_validate_file_header_only_little_endian_supported
|
jne .elf_validate_file_header_only_little_endian_supported
|
||||||
@@ -72,8 +100,8 @@ elf_validate_file_header:
|
|||||||
.elf_validate_file_header_invalid_magic:
|
.elf_validate_file_header_invalid_magic:
|
||||||
movw $elf_validate_file_header_invalid_magic_msg, %si
|
movw $elf_validate_file_header_invalid_magic_msg, %si
|
||||||
jmp print_and_halt
|
jmp print_and_halt
|
||||||
.elf_validate_file_header_only_64bit_supported:
|
.elf_validate_file_header_invalid_class:
|
||||||
movw $elf_validate_file_header_only_64bit_supported_msg, %si
|
movw $elf_validate_file_header_invalid_class_msg, %si
|
||||||
jmp print_and_halt
|
jmp print_and_halt
|
||||||
.elf_validate_file_header_only_little_endian_supported:
|
.elf_validate_file_header_only_little_endian_supported:
|
||||||
movw $elf_validate_file_header_only_little_endian_supported_msg, %si
|
movw $elf_validate_file_header_only_little_endian_supported_msg, %si
|
||||||
@@ -85,6 +113,59 @@ elf_validate_file_header:
|
|||||||
movw $elf_validate_file_header_not_executable_msg, %si
|
movw $elf_validate_file_header_not_executable_msg, %si
|
||||||
jmp print_and_halt
|
jmp print_and_halt
|
||||||
|
|
||||||
|
# reads memory specified by 32 bit elf_program_header to memory
|
||||||
|
elf_read_program_header32_to_memory:
|
||||||
|
pushal
|
||||||
|
pushl %ebp
|
||||||
|
movl %esp, %ebp
|
||||||
|
|
||||||
|
# memset p_filesz -> p_memsz to 0
|
||||||
|
movl (elf_program_header + p32_filesz), %ebx
|
||||||
|
movl (elf_program_header + p32_vaddr), %edi
|
||||||
|
andl $LOAD_MASK, %edi
|
||||||
|
addl %ebx, %edi
|
||||||
|
movl (elf_program_header + p32_memsz), %ecx
|
||||||
|
subl %ebx, %ecx
|
||||||
|
xorb %al, %al; call memset32
|
||||||
|
|
||||||
|
# read file specified in program header to memory
|
||||||
|
movl (elf_program_header + p32_offset), %eax
|
||||||
|
movl (elf_program_header + p32_vaddr), %edi
|
||||||
|
andl $LOAD_MASK, %edi
|
||||||
|
movl (elf_program_header + p32_filesz), %ecx
|
||||||
|
call *%esi
|
||||||
|
|
||||||
|
leavel
|
||||||
|
popal
|
||||||
|
ret
|
||||||
|
|
||||||
|
|
||||||
|
# reads memory specified by 64 bit elf_program_header to memory
|
||||||
|
elf_read_program_header64_to_memory:
|
||||||
|
pushal
|
||||||
|
pushl %ebp
|
||||||
|
movl %esp, %ebp
|
||||||
|
|
||||||
|
# memset p_filesz -> p_memsz to 0
|
||||||
|
movl (elf_program_header + p64_filesz), %ebx
|
||||||
|
movl (elf_program_header + p64_vaddr), %edi
|
||||||
|
andl $LOAD_MASK, %edi
|
||||||
|
addl %ebx, %edi
|
||||||
|
movl (elf_program_header + p64_memsz), %ecx
|
||||||
|
subl %ebx, %ecx
|
||||||
|
xorb %al, %al; call memset32
|
||||||
|
|
||||||
|
# read file specified in program header to memory
|
||||||
|
movl (elf_program_header + p64_offset), %eax
|
||||||
|
movl (elf_program_header + p64_vaddr), %edi
|
||||||
|
andl $LOAD_MASK, %edi
|
||||||
|
movl (elf_program_header + p64_filesz), %ecx
|
||||||
|
call *%esi
|
||||||
|
|
||||||
|
leavel
|
||||||
|
popal
|
||||||
|
ret
|
||||||
|
|
||||||
|
|
||||||
# read callback format
|
# read callback format
|
||||||
# eax: first byte
|
# eax: first byte
|
||||||
@@ -104,42 +185,72 @@ elf_read_kernel_to_memory:
|
|||||||
movl %esp, %ebp
|
movl %esp, %ebp
|
||||||
subl $2, %esp
|
subl $2, %esp
|
||||||
|
|
||||||
# read file header
|
# read start of file header
|
||||||
movl $0, %eax
|
movl $0, %eax
|
||||||
movl $64, %ecx
|
movl $24, %ecx
|
||||||
movl $elf_file_header, %edi
|
movl $elf_file_header, %edi
|
||||||
call *%esi
|
call *%esi
|
||||||
|
|
||||||
call elf_validate_file_header
|
call elf_validate_file_header
|
||||||
|
|
||||||
cmpl $0, (elf_file_header + e_phoff + 4)
|
# determine file header size
|
||||||
|
movl $52, %ecx
|
||||||
|
movl $64, %edx
|
||||||
|
cmpb $ELFCLASS64, (elf_file_header + EI_CLASS)
|
||||||
|
cmovel %edx, %ecx
|
||||||
|
|
||||||
|
# read full file header
|
||||||
|
movl $0, %eax
|
||||||
|
movl $elf_file_header, %edi
|
||||||
|
call *%esi
|
||||||
|
|
||||||
|
# verify that e_phoff fits in 32 bits
|
||||||
|
cmpb $ELFCLASS64, (elf_file_header + EI_CLASS)
|
||||||
|
jne .elf_read_kernel_to_memory_valid_offset
|
||||||
|
cmpl $0, (elf_file_header + e64_phoff + 4)
|
||||||
jnz .elf_read_kernel_to_memory_unsupported_offset
|
jnz .elf_read_kernel_to_memory_unsupported_offset
|
||||||
|
.elf_read_kernel_to_memory_valid_offset:
|
||||||
|
|
||||||
|
# read architecture phentsize and phnum to fixed locations
|
||||||
|
movw (elf_file_header + e32_phentsize), %ax
|
||||||
|
movw (elf_file_header + e32_phnum), %bx
|
||||||
|
movl (elf_file_header + e32_phoff), %ecx
|
||||||
|
cmpb $ELFCLASS64, (elf_file_header + EI_CLASS)
|
||||||
|
cmovew (elf_file_header + e64_phentsize), %ax
|
||||||
|
cmovew (elf_file_header + e64_phnum), %bx
|
||||||
|
cmovel (elf_file_header + e64_phoff), %ecx
|
||||||
|
movw %ax, (elf_file_header_phentsize)
|
||||||
|
movw %bx, (elf_file_header_phnum)
|
||||||
|
movl %ecx, (elf_file_header_phoff)
|
||||||
|
|
||||||
# current program header
|
# current program header
|
||||||
movw $0, -2(%ebp)
|
movw $0, -2(%ebp)
|
||||||
|
|
||||||
.elf_read_kernel_to_memory_loop_program_headers:
|
.elf_read_kernel_to_memory_loop_program_headers:
|
||||||
movw -2(%ebp), %cx
|
movw -2(%ebp), %cx
|
||||||
cmpw (elf_file_header + e_phnum), %cx
|
cmpw (elf_file_header_phnum), %cx
|
||||||
jae .elf_read_kernel_to_memory_done
|
jae .elf_read_kernel_to_memory_done
|
||||||
|
|
||||||
# eax := program_header_index * e_phentsize + e_phoff
|
# eax := program_header_index * e_phentsize + e_phoff
|
||||||
xorl %eax, %eax
|
xorl %eax, %eax
|
||||||
movw %cx, %ax
|
movw %cx, %ax
|
||||||
xorl %ebx, %ebx
|
xorl %ebx, %ebx
|
||||||
movw (elf_file_header + e_phentsize), %bx
|
movw (elf_file_header_phentsize), %bx
|
||||||
mull %ebx
|
mull %ebx
|
||||||
addl (elf_file_header + e_phoff), %eax
|
addl (elf_file_header_phoff), %eax
|
||||||
jc .elf_read_kernel_to_memory_unsupported_offset
|
jc .elf_read_kernel_to_memory_unsupported_offset
|
||||||
|
|
||||||
# setup program header size and address
|
# determine program header size
|
||||||
movl $56, %ecx
|
movl $32, %ecx
|
||||||
movl $elf_program_header, %edi
|
movl $56, %edx
|
||||||
|
cmpb $ELFCLASS64, (elf_file_header + EI_CLASS)
|
||||||
|
cmovel %edx, %ecx
|
||||||
|
|
||||||
# read the program header
|
# read program header
|
||||||
|
movl $elf_program_header, %edi
|
||||||
call *%esi
|
call *%esi
|
||||||
|
|
||||||
# test if program header is empty
|
# test if program header is NULL header
|
||||||
cmpl $PT_NULL, (elf_program_header + p_type)
|
cmpl $PT_NULL, (elf_program_header + p_type)
|
||||||
je .elf_read_kernel_to_memory_null_program_header
|
je .elf_read_kernel_to_memory_null_program_header
|
||||||
|
|
||||||
@@ -147,33 +258,12 @@ elf_read_kernel_to_memory:
|
|||||||
cmpl $PT_LOAD, (elf_program_header + p_type)
|
cmpl $PT_LOAD, (elf_program_header + p_type)
|
||||||
jne .elf_read_kernel_to_memory_not_loadable_header
|
jne .elf_read_kernel_to_memory_not_loadable_header
|
||||||
|
|
||||||
# memset p_filesz -> p_memsz to 0
|
# read program header to memory
|
||||||
movl (elf_program_header + p_filesz), %ebx
|
movl $elf_read_program_header32_to_memory, %eax
|
||||||
|
movl $elf_read_program_header64_to_memory, %ebx
|
||||||
movl (elf_program_header + p_vaddr), %edi
|
cmpb $ELFCLASS64, (elf_file_header + EI_CLASS)
|
||||||
andl $0x7FFFFFFF, %edi
|
cmovel %ebx, %eax
|
||||||
addl %ebx, %edi
|
call *%eax
|
||||||
|
|
||||||
movl (elf_program_header + p_memsz), %ecx
|
|
||||||
subl %ebx, %ecx
|
|
||||||
jz .elf_read_kernel_to_memory_memset_done
|
|
||||||
|
|
||||||
.elf_read_kernel_to_memory_memset:
|
|
||||||
movb $0, (%edi)
|
|
||||||
incl %edi
|
|
||||||
decl %ecx
|
|
||||||
jnz .elf_read_kernel_to_memory_memset
|
|
||||||
.elf_read_kernel_to_memory_memset_done:
|
|
||||||
|
|
||||||
# read file specified in program header to memory
|
|
||||||
movl (elf_program_header + p_offset), %eax
|
|
||||||
movl (elf_program_header + p_vaddr), %edi
|
|
||||||
andl $0x7FFFFFFF, %edi
|
|
||||||
movl (elf_program_header + p_filesz), %ecx
|
|
||||||
|
|
||||||
#call print_hex32; call print_newline
|
|
||||||
|
|
||||||
call *%esi
|
|
||||||
|
|
||||||
.elf_read_kernel_to_memory_null_program_header:
|
.elf_read_kernel_to_memory_null_program_header:
|
||||||
incw -2(%ebp)
|
incw -2(%ebp)
|
||||||
@@ -185,7 +275,7 @@ elf_read_kernel_to_memory:
|
|||||||
|
|
||||||
# set kernel entry address
|
# set kernel entry address
|
||||||
movl (elf_file_header + e_entry), %eax
|
movl (elf_file_header + e_entry), %eax
|
||||||
andl $0x7FFFFF, %eax
|
andl $LOAD_MASK, %eax
|
||||||
|
|
||||||
ret
|
ret
|
||||||
|
|
||||||
@@ -200,8 +290,8 @@ elf_read_kernel_to_memory:
|
|||||||
|
|
||||||
elf_validate_file_header_invalid_magic_msg:
|
elf_validate_file_header_invalid_magic_msg:
|
||||||
.asciz "ELF: file has invalid ELF magic"
|
.asciz "ELF: file has invalid ELF magic"
|
||||||
elf_validate_file_header_only_64bit_supported_msg:
|
elf_validate_file_header_invalid_class_msg:
|
||||||
.asciz "ELF: file is not targettint 64 bit"
|
.asciz "ELF: file has invalid ELF class"
|
||||||
elf_validate_file_header_only_little_endian_supported_msg:
|
elf_validate_file_header_only_little_endian_supported_msg:
|
||||||
.asciz "ELF: file is not in little endian format"
|
.asciz "ELF: file is not in little endian format"
|
||||||
elf_validate_file_header_not_current_version_msg:
|
elf_validate_file_header_not_current_version_msg:
|
||||||
@@ -219,5 +309,12 @@ elf_read_kernel_to_memory_not_loadable_header_msg:
|
|||||||
elf_file_header:
|
elf_file_header:
|
||||||
.skip 64
|
.skip 64
|
||||||
|
|
||||||
|
elf_file_header_phentsize:
|
||||||
|
.skip 2
|
||||||
|
elf_file_header_phnum:
|
||||||
|
.skip 2
|
||||||
|
elf_file_header_phoff:
|
||||||
|
.skip 4 # NOTE: only 32 bit offsets are supported
|
||||||
|
|
||||||
elf_program_header:
|
elf_program_header:
|
||||||
.skip 56
|
.skip 56
|
||||||
|
|||||||
@@ -454,15 +454,7 @@ ext2_inode_read_bytes:
|
|||||||
movl $ext2_block_buffer, %esi
|
movl $ext2_block_buffer, %esi
|
||||||
addl %edx, %esi
|
addl %edx, %esi
|
||||||
|
|
||||||
# very dumb memcpy with 32 bit addresses
|
call memcpy32
|
||||||
xorl %ebx, %ebx
|
|
||||||
.ext2_inode_read_bytes_memcpy_partial:
|
|
||||||
movb (%esi, %ebx), %al
|
|
||||||
movb %al, (%edi, %ebx)
|
|
||||||
incl %ebx
|
|
||||||
decl %ecx
|
|
||||||
jnz .ext2_inode_read_bytes_memcpy_partial
|
|
||||||
addl %ebx, %edi
|
|
||||||
|
|
||||||
# check if all sectors are read
|
# check if all sectors are read
|
||||||
cmpl $0, 4(%esp)
|
cmpl $0, 4(%esp)
|
||||||
@@ -487,16 +479,8 @@ ext2_inode_read_bytes:
|
|||||||
addl %ecx, 0(%esp)
|
addl %ecx, 0(%esp)
|
||||||
subl %ecx, 4(%esp)
|
subl %ecx, 4(%esp)
|
||||||
|
|
||||||
# very dumb memcpy with 32 bit addresses
|
|
||||||
movl $ext2_block_buffer, %esi
|
movl $ext2_block_buffer, %esi
|
||||||
movl $0, %ebx
|
call memcpy32
|
||||||
.ext2_inode_read_bytes_memcpy:
|
|
||||||
movb (%esi, %ebx), %al
|
|
||||||
movb %al, (%edi, %ebx)
|
|
||||||
incl %ebx
|
|
||||||
decl %ecx
|
|
||||||
jnz .ext2_inode_read_bytes_memcpy
|
|
||||||
addl %ebx, %edi
|
|
||||||
|
|
||||||
# read next block if more sectors remaining
|
# read next block if more sectors remaining
|
||||||
cmpl $0, 4(%esp)
|
cmpl $0, 4(%esp)
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
.include "common.S"
|
||||||
|
|
||||||
.set SCREEN_WIDTH, 80
|
.set SCREEN_WIDTH, 80
|
||||||
.set SCREEN_HEIGHT, 25
|
.set SCREEN_HEIGHT, 25
|
||||||
|
|
||||||
@@ -273,6 +275,109 @@ isprint:
|
|||||||
movb $0, %al
|
movb $0, %al
|
||||||
ret
|
ret
|
||||||
|
|
||||||
|
|
||||||
|
# memset with 32 bit registers
|
||||||
|
# edi: destination address
|
||||||
|
# ecx: bytes count
|
||||||
|
# al: value to set
|
||||||
|
# return:
|
||||||
|
# edi: destination address + bytes count
|
||||||
|
# ecx: 0
|
||||||
|
# other: preserved
|
||||||
|
.global memset32
|
||||||
|
memset32:
|
||||||
|
testl %ecx, %ecx
|
||||||
|
jz .memset32_done
|
||||||
|
|
||||||
|
pushf; cli
|
||||||
|
pushw %es
|
||||||
|
pushl %eax
|
||||||
|
pushl %ebx
|
||||||
|
pushl %edx
|
||||||
|
|
||||||
|
movl %cr0, %ebx
|
||||||
|
orb $1, %bl
|
||||||
|
movl %ebx, %cr0
|
||||||
|
|
||||||
|
ljmpl $GDT_CODE32, $.memset32_pmode32
|
||||||
|
|
||||||
|
.code32
|
||||||
|
.memset32_pmode32:
|
||||||
|
movw $GDT_DATA32, %dx
|
||||||
|
movw %dx, %es
|
||||||
|
|
||||||
|
rep stosb %es:(%edi)
|
||||||
|
|
||||||
|
ljmpl $GDT_CODE16, $.memset32_pmode16
|
||||||
|
|
||||||
|
.code16
|
||||||
|
.memset32_pmode16:
|
||||||
|
andb $0xFE, %bl
|
||||||
|
movl %ebx, %cr0
|
||||||
|
ljmpl $0x00, $.memset32_rmode16
|
||||||
|
|
||||||
|
.memset32_rmode16:
|
||||||
|
popl %edx
|
||||||
|
popl %ebx
|
||||||
|
popl %eax
|
||||||
|
popw %es
|
||||||
|
popf
|
||||||
|
|
||||||
|
.memset32_done:
|
||||||
|
ret
|
||||||
|
|
||||||
|
# memcpy with 32 bit registers
|
||||||
|
# esi: source address
|
||||||
|
# edi: destination address
|
||||||
|
# ecx: bytes count
|
||||||
|
# return:
|
||||||
|
# esi: source address + bytes count
|
||||||
|
# edi: destination address + bytes count
|
||||||
|
# ecx: 0
|
||||||
|
# other: preserved
|
||||||
|
.global memcpy32
|
||||||
|
memcpy32:
|
||||||
|
testl %ecx, %ecx
|
||||||
|
jz .memcpy32_done
|
||||||
|
|
||||||
|
pushf; cli
|
||||||
|
pushw %ds
|
||||||
|
pushw %es
|
||||||
|
pushl %ebx
|
||||||
|
pushl %edx
|
||||||
|
|
||||||
|
movl %cr0, %ebx
|
||||||
|
orb $1, %bl
|
||||||
|
movl %ebx, %cr0
|
||||||
|
|
||||||
|
ljmpl $GDT_CODE32, $.memcpy32_pmode32
|
||||||
|
|
||||||
|
.code32
|
||||||
|
.memcpy32_pmode32:
|
||||||
|
movw $GDT_DATA32, %dx
|
||||||
|
movw %dx, %ds
|
||||||
|
movw %dx, %es
|
||||||
|
|
||||||
|
rep movsb %ds:(%esi), %es:(%edi)
|
||||||
|
|
||||||
|
ljmpl $GDT_CODE16, $.memcpy32_pmode16
|
||||||
|
|
||||||
|
.code16
|
||||||
|
.memcpy32_pmode16:
|
||||||
|
andb $0xFE, %bl
|
||||||
|
movl %ebx, %cr0
|
||||||
|
ljmpl $0x00, $.memcpy32_rmode16
|
||||||
|
|
||||||
|
.memcpy32_rmode16:
|
||||||
|
popl %edx
|
||||||
|
popl %ebx
|
||||||
|
popw %es
|
||||||
|
popw %ds
|
||||||
|
popf
|
||||||
|
|
||||||
|
.memcpy32_done:
|
||||||
|
ret
|
||||||
|
|
||||||
.section .bss
|
.section .bss
|
||||||
|
|
||||||
# enough for base 2 printing
|
# enough for base 2 printing
|
||||||
|
|||||||
@@ -1,6 +1,11 @@
|
|||||||
cmake_minimum_required(VERSION 3.26)
|
cmake_minimum_required(VERSION 3.26)
|
||||||
|
|
||||||
project(x86_64-banan_os-bootloader-installer CXX)
|
if (NOT DEFINED ENV{BANAN_ARCH})
|
||||||
|
message(FATAL_ERROR "environment variable BANAN_ARCH not defined")
|
||||||
|
endif ()
|
||||||
|
set(BANAN_ARCH $ENV{BANAN_ARCH})
|
||||||
|
|
||||||
|
project(banan_os-bootloader-installer CXX)
|
||||||
|
|
||||||
set(SOURCES
|
set(SOURCES
|
||||||
crc32.cpp
|
crc32.cpp
|
||||||
@@ -10,8 +15,8 @@ set(SOURCES
|
|||||||
main.cpp
|
main.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
add_executable(x86_64-banan_os-bootloader-installer ${SOURCES})
|
add_executable(banan_os-bootloader-installer ${SOURCES})
|
||||||
target_compile_options(x86_64-banan_os-bootloader-installer PRIVATE -O2 -std=c++20)
|
target_compile_options(banan_os-bootloader-installer PRIVATE -O2 -std=c++20)
|
||||||
target_compile_definitions(x86_64-banan_os-bootloader-installer PRIVATE __arch=x86_64)
|
target_compile_definitions(banan_os-bootloader-installer PRIVATE __arch=${BANAN_ARCH})
|
||||||
target_include_directories(x86_64-banan_os-bootloader-installer PRIVATE ${CMAKE_SOURCE_DIR}/../../LibELF/include)
|
target_include_directories(banan_os-bootloader-installer PRIVATE ${CMAKE_SOURCE_DIR}/../../userspace/libraries/LibELF/include)
|
||||||
target_include_directories(x86_64-banan_os-bootloader-installer PRIVATE ${CMAKE_SOURCE_DIR}/../../kernel/include)
|
target_include_directories(banan_os-bootloader-installer PRIVATE ${CMAKE_SOURCE_DIR}/../../kernel/include)
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ bool ELFFile::validate_elf_header() const
|
|||||||
|
|
||||||
#if ARCH(x86_64)
|
#if ARCH(x86_64)
|
||||||
if (elf_header.e_ident[EI_CLASS] != ELFCLASS64)
|
if (elf_header.e_ident[EI_CLASS] != ELFCLASS64)
|
||||||
#elif ARCH(i386)
|
#elif ARCH(i686)
|
||||||
if (elf_header.e_ident[EI_CLASS] != ELFCLASS32)
|
if (elf_header.e_ident[EI_CLASS] != ELFCLASS32)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,46 +1,57 @@
|
|||||||
cmake_minimum_required(VERSION 3.26)
|
|
||||||
|
|
||||||
project(kernel CXX C ASM)
|
|
||||||
|
|
||||||
if("${BANAN_ARCH}" STREQUAL "x86_64")
|
|
||||||
set(ELF_FORMAT elf64-x86-64)
|
|
||||||
elseif("${BANAN_ARCH}" STREQUAL "i386")
|
|
||||||
set(ELF_FORMAT elf32-i386)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
set(KERNEL_SOURCES
|
set(KERNEL_SOURCES
|
||||||
font/prefs.psf.o
|
font/prefs.psf.o
|
||||||
kernel/ACPI.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
|
||||||
kernel/Debug.cpp
|
kernel/Debug.cpp
|
||||||
|
kernel/Device/DebugDevice.cpp
|
||||||
kernel/Device/Device.cpp
|
kernel/Device/Device.cpp
|
||||||
kernel/Device/FramebufferDevice.cpp
|
kernel/Device/FramebufferDevice.cpp
|
||||||
kernel/Device/NullDevice.cpp
|
kernel/Device/NullDevice.cpp
|
||||||
|
kernel/Device/RandomDevice.cpp
|
||||||
kernel/Device/ZeroDevice.cpp
|
kernel/Device/ZeroDevice.cpp
|
||||||
|
kernel/ELF.cpp
|
||||||
|
kernel/Epoll.cpp
|
||||||
kernel/Errors.cpp
|
kernel/Errors.cpp
|
||||||
kernel/Font.cpp
|
|
||||||
kernel/FS/DevFS/FileSystem.cpp
|
kernel/FS/DevFS/FileSystem.cpp
|
||||||
|
kernel/FS/EventFD.cpp
|
||||||
kernel/FS/Ext2/FileSystem.cpp
|
kernel/FS/Ext2/FileSystem.cpp
|
||||||
kernel/FS/Ext2/Inode.cpp
|
kernel/FS/Ext2/Inode.cpp
|
||||||
|
kernel/FS/FAT/FileSystem.cpp
|
||||||
|
kernel/FS/FAT/Inode.cpp
|
||||||
|
kernel/FS/FileSystem.cpp
|
||||||
kernel/FS/Inode.cpp
|
kernel/FS/Inode.cpp
|
||||||
kernel/FS/Pipe.cpp
|
kernel/FS/Pipe.cpp
|
||||||
kernel/FS/ProcFS/FileSystem.cpp
|
kernel/FS/ProcFS/FileSystem.cpp
|
||||||
kernel/FS/ProcFS/Inode.cpp
|
kernel/FS/ProcFS/Inode.cpp
|
||||||
kernel/FS/TmpFS/FileSystem.cpp
|
kernel/FS/TmpFS/FileSystem.cpp
|
||||||
kernel/FS/TmpFS/Inode.cpp
|
kernel/FS/TmpFS/Inode.cpp
|
||||||
|
kernel/FS/USTARModule.cpp
|
||||||
kernel/FS/VirtualFileSystem.cpp
|
kernel/FS/VirtualFileSystem.cpp
|
||||||
kernel/Input/KeyboardLayout.cpp
|
kernel/GDT.cpp
|
||||||
kernel/Input/KeyEvent.cpp
|
kernel/IDT.cpp
|
||||||
|
kernel/Input/InputDevice.cpp
|
||||||
kernel/Input/PS2/Controller.cpp
|
kernel/Input/PS2/Controller.cpp
|
||||||
kernel/Input/PS2/Device.cpp
|
kernel/Input/PS2/Device.cpp
|
||||||
kernel/Input/PS2/Keyboard.cpp
|
kernel/Input/PS2/Keyboard.cpp
|
||||||
kernel/Input/PS2/Keymap.cpp
|
kernel/Input/PS2/Keymap.cpp
|
||||||
kernel/Input/PS2/Mouse.cpp
|
kernel/Input/PS2/Mouse.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
|
||||||
@@ -48,16 +59,29 @@ 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/E1000.cpp
|
kernel/Networking/ARPTable.cpp
|
||||||
|
kernel/Networking/E1000/E1000.cpp
|
||||||
|
kernel/Networking/E1000/E1000E.cpp
|
||||||
|
kernel/Networking/IPv4Layer.cpp
|
||||||
|
kernel/Networking/Loopback.cpp
|
||||||
|
kernel/Networking/NetworkInterface.cpp
|
||||||
|
kernel/Networking/NetworkLayer.cpp
|
||||||
|
kernel/Networking/NetworkManager.cpp
|
||||||
|
kernel/Networking/NetworkSocket.cpp
|
||||||
|
kernel/Networking/RTL8169/RTL8169.cpp
|
||||||
|
kernel/Networking/TCPSocket.cpp
|
||||||
|
kernel/Networking/UDPSocket.cpp
|
||||||
|
kernel/Networking/UNIX/Socket.cpp
|
||||||
kernel/OpenFileDescriptorSet.cpp
|
kernel/OpenFileDescriptorSet.cpp
|
||||||
kernel/Panic.cpp
|
kernel/Panic.cpp
|
||||||
kernel/PCI.cpp
|
kernel/PCI.cpp
|
||||||
kernel/PIC.cpp
|
kernel/PIC.cpp
|
||||||
kernel/Process.cpp
|
kernel/Process.cpp
|
||||||
|
kernel/Processor.cpp
|
||||||
|
kernel/Random.cpp
|
||||||
kernel/Scheduler.cpp
|
kernel/Scheduler.cpp
|
||||||
kernel/Semaphore.cpp
|
|
||||||
kernel/SpinLock.cpp
|
|
||||||
kernel/SSP.cpp
|
kernel/SSP.cpp
|
||||||
kernel/Storage/ATA/AHCI/Controller.cpp
|
kernel/Storage/ATA/AHCI/Controller.cpp
|
||||||
kernel/Storage/ATA/AHCI/Device.cpp
|
kernel/Storage/ATA/AHCI/Device.cpp
|
||||||
@@ -69,22 +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/Syscall.S
|
|
||||||
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)
|
||||||
@@ -94,102 +134,115 @@ if("${BANAN_ARCH}" STREQUAL "x86_64")
|
|||||||
set(KERNEL_SOURCES
|
set(KERNEL_SOURCES
|
||||||
${KERNEL_SOURCES}
|
${KERNEL_SOURCES}
|
||||||
arch/x86_64/boot.S
|
arch/x86_64/boot.S
|
||||||
arch/x86_64/GDT.cpp
|
|
||||||
arch/x86_64/IDT.cpp
|
|
||||||
arch/x86_64/interrupts.S
|
arch/x86_64/interrupts.S
|
||||||
arch/x86_64/PageTable.cpp
|
arch/x86_64/PageTable.cpp
|
||||||
arch/x86_64/Signal.S
|
arch/x86_64/Signal.S
|
||||||
|
arch/x86_64/Syscall.S
|
||||||
arch/x86_64/Thread.S
|
arch/x86_64/Thread.S
|
||||||
|
arch/x86_64/User.S
|
||||||
|
arch/x86_64/Yield.S
|
||||||
)
|
)
|
||||||
elseif("${BANAN_ARCH}" STREQUAL "i386")
|
elseif("${BANAN_ARCH}" STREQUAL "i686")
|
||||||
set(KERNEL_SOURCES
|
set(KERNEL_SOURCES
|
||||||
${KERNEL_SOURCES}
|
${KERNEL_SOURCES}
|
||||||
arch/i386/boot.S
|
arch/i686/boot.S
|
||||||
arch/i386/GDT.cpp
|
arch/i686/interrupts.S
|
||||||
arch/i386/IDT.cpp
|
arch/i686/PageTable.cpp
|
||||||
arch/i386/MMU.cpp
|
arch/i686/Signal.S
|
||||||
arch/i386/SpinLock.S
|
arch/i686/Syscall.S
|
||||||
arch/i386/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}")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
file(GLOB_RECURSE LAI_SOURCES
|
|
||||||
lai/*.c
|
|
||||||
)
|
|
||||||
set(LAI_SOURCES
|
|
||||||
${LAI_SOURCES}
|
|
||||||
kernel/lai_host.cpp
|
|
||||||
)
|
|
||||||
|
|
||||||
set(BAN_SOURCES
|
set(BAN_SOURCES
|
||||||
|
../BAN/BAN/Assert.cpp
|
||||||
../BAN/BAN/New.cpp
|
../BAN/BAN/New.cpp
|
||||||
../BAN/BAN/String.cpp
|
|
||||||
../BAN/BAN/StringView.cpp
|
../BAN/BAN/StringView.cpp
|
||||||
../BAN/BAN/Time.cpp
|
../BAN/BAN/Time.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
set(LIBC_SOURCES
|
set(KLIBC_SOURCES
|
||||||
../libc/ctype.cpp
|
klibc/ctype.cpp
|
||||||
../libc/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}
|
||||||
${LIBC_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 -mno-mmx)
|
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 "i386")
|
elseif("${BANAN_ARCH}" STREQUAL "i686")
|
||||||
target_link_options(kernel PUBLIC LINKER:-T,${CMAKE_CURRENT_SOURCE_DIR}/arch/i386/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
|
||||||
@@ -204,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,147 +0,0 @@
|
|||||||
#include <BAN/Assert.h>
|
|
||||||
#include <kernel/GDT.h>
|
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
extern "C" uintptr_t g_boot_stack_top[0];
|
|
||||||
|
|
||||||
namespace Kernel::GDT
|
|
||||||
{
|
|
||||||
|
|
||||||
struct TaskStateSegment
|
|
||||||
{
|
|
||||||
uint16_t link;
|
|
||||||
uint16_t reserved1;
|
|
||||||
uint32_t esp0;
|
|
||||||
uint16_t ss0;
|
|
||||||
uint16_t reserved2;
|
|
||||||
uint32_t esp1;
|
|
||||||
uint16_t ss1;
|
|
||||||
uint16_t reserved3;
|
|
||||||
uint32_t esp2;
|
|
||||||
uint16_t ss2;
|
|
||||||
uint16_t reserved4;
|
|
||||||
uint32_t cr3;
|
|
||||||
uint32_t eip;
|
|
||||||
uint32_t eflags;
|
|
||||||
uint32_t eax;
|
|
||||||
uint32_t ecx;
|
|
||||||
uint32_t edx;
|
|
||||||
uint32_t ebx;
|
|
||||||
uint32_t esp;
|
|
||||||
uint32_t ebp;
|
|
||||||
uint32_t esi;
|
|
||||||
uint32_t edi;
|
|
||||||
uint16_t es;
|
|
||||||
uint16_t reserved5;
|
|
||||||
uint16_t cs;
|
|
||||||
uint16_t reserved6;
|
|
||||||
uint16_t ss;
|
|
||||||
uint16_t reserved7;
|
|
||||||
uint16_t ds;
|
|
||||||
uint16_t reserved8;
|
|
||||||
uint16_t fs;
|
|
||||||
uint16_t reserved9;
|
|
||||||
uint16_t gs;
|
|
||||||
uint16_t reserved10;
|
|
||||||
uint16_t ldtr;
|
|
||||||
uint16_t reserved11;
|
|
||||||
uint16_t reserved12;
|
|
||||||
uint16_t iopb;
|
|
||||||
uint32_t ssp;
|
|
||||||
} __attribute__((packed));
|
|
||||||
|
|
||||||
union SegmentDescriptor
|
|
||||||
{
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
uint16_t limit1;
|
|
||||||
uint16_t base1;
|
|
||||||
uint8_t base2;
|
|
||||||
uint8_t access;
|
|
||||||
uint8_t limit2 : 4;
|
|
||||||
uint8_t flags : 4;
|
|
||||||
uint8_t base3;
|
|
||||||
} __attribute__((packed));
|
|
||||||
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
uint32_t low;
|
|
||||||
uint32_t high;
|
|
||||||
} __attribute__((packed));
|
|
||||||
|
|
||||||
} __attribute__((packed));
|
|
||||||
|
|
||||||
struct GDTR
|
|
||||||
{
|
|
||||||
uint16_t size;
|
|
||||||
uint32_t address;
|
|
||||||
} __attribute__((packed));
|
|
||||||
|
|
||||||
static TaskStateSegment* s_tss = nullptr;
|
|
||||||
static SegmentDescriptor* s_gdt = nullptr;
|
|
||||||
static GDTR s_gdtr;
|
|
||||||
|
|
||||||
static void write_entry(uint8_t offset, uint32_t base, uint32_t limit, uint8_t access, uint8_t flags)
|
|
||||||
{
|
|
||||||
SegmentDescriptor& desc = *(SegmentDescriptor*)((uintptr_t)s_gdt + offset);
|
|
||||||
desc.base1 = base;
|
|
||||||
desc.base2 = base >> 16;
|
|
||||||
desc.base3 = base >> 24;
|
|
||||||
|
|
||||||
desc.limit1 = limit;
|
|
||||||
desc.limit2 = limit >> 16;
|
|
||||||
|
|
||||||
desc.access = access;
|
|
||||||
|
|
||||||
desc.flags = flags;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void write_tss(uint8_t offset)
|
|
||||||
{
|
|
||||||
s_tss = new TaskStateSegment();
|
|
||||||
ASSERT(s_tss);
|
|
||||||
|
|
||||||
memset(s_tss, 0x00, sizeof(TaskStateSegment));
|
|
||||||
s_tss->ss0 = 0x10;
|
|
||||||
s_tss->esp0 = (uintptr_t)g_boot_stack_top;
|
|
||||||
|
|
||||||
write_entry(offset, (uint32_t)s_tss, sizeof(TaskStateSegment), 0x89, 0x0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void set_tss_stack(uintptr_t esp)
|
|
||||||
{
|
|
||||||
s_tss->esp0 = esp;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void flush_gdt()
|
|
||||||
{
|
|
||||||
asm volatile("lgdt %0" :: "m"(s_gdtr));
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "C" void flush_tss(uint16_t offset)
|
|
||||||
{
|
|
||||||
asm volatile("ltr %0" :: "m"(offset));
|
|
||||||
}
|
|
||||||
|
|
||||||
void initialize()
|
|
||||||
{
|
|
||||||
constexpr uint32_t descriptor_count = 6;
|
|
||||||
s_gdt = new SegmentDescriptor[descriptor_count];
|
|
||||||
ASSERT(s_gdt);
|
|
||||||
|
|
||||||
s_gdtr.address = (uint64_t)s_gdt;
|
|
||||||
s_gdtr.size = descriptor_count * sizeof(SegmentDescriptor) - 1;
|
|
||||||
|
|
||||||
write_entry(0x00, 0x00000000, 0x00000, 0x00, 0x0); // null
|
|
||||||
write_entry(0x08, 0x00000000, 0xFFFFF, 0x9A, 0xC); // kernel code
|
|
||||||
write_entry(0x10, 0x00000000, 0xFFFFF, 0x92, 0xC); // kernel data
|
|
||||||
write_entry(0x18, 0x00000000, 0xFFFFF, 0xFA, 0xC); // user code
|
|
||||||
write_entry(0x20, 0x00000000, 0xFFFFF, 0xF2, 0xC); // user data
|
|
||||||
write_tss(0x28);
|
|
||||||
|
|
||||||
flush_gdt();
|
|
||||||
flush_tss(0x28);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,270 +0,0 @@
|
|||||||
#include <BAN/Errors.h>
|
|
||||||
#include <kernel/IDT.h>
|
|
||||||
#include <kernel/InterruptController.h>
|
|
||||||
#include <kernel/Memory/kmalloc.h>
|
|
||||||
#include <kernel/Panic.h>
|
|
||||||
#include <kernel/Scheduler.h>
|
|
||||||
|
|
||||||
#define INTERRUPT_HANDLER____(i, msg) \
|
|
||||||
static void interrupt ## i () \
|
|
||||||
{ \
|
|
||||||
uint32_t eax, ebx, ecx, edx; \
|
|
||||||
uint32_t esp, ebp; \
|
|
||||||
uint32_t cr0, cr2, cr3, cr4; \
|
|
||||||
asm volatile("":"=a"(eax),"=b"(ebx),"=c"(ecx),"=d"(edx)); \
|
|
||||||
asm volatile("movl %%esp, %%eax":"=a"(esp)); \
|
|
||||||
asm volatile("movl %%ebp, %%eax":"=a"(ebp)); \
|
|
||||||
asm volatile("movl %%cr0, %%eax":"=a"(cr0)); \
|
|
||||||
asm volatile("movl %%cr2, %%eax":"=a"(cr2)); \
|
|
||||||
asm volatile("movl %%cr3, %%eax":"=a"(cr3)); \
|
|
||||||
asm volatile("movl %%cr4, %%eax":"=a"(cr4)); \
|
|
||||||
Kernel::panic(msg "\r\nRegister dump\r\n" \
|
|
||||||
"eax=0x{8H}, ebx=0x{8H}, ecx=0x{8H}, edx=0x{8H}\r\n" \
|
|
||||||
"esp=0x{8H}, ebp=0x{8H}\r\n" \
|
|
||||||
"CR0=0x{8H}, CR2=0x{8H}, CR3=0x{8H}, CR4=0x{8H}\r\n", \
|
|
||||||
eax, ebx, ecx, edx, esp, ebp, cr0, cr2, cr3, cr4); \
|
|
||||||
}
|
|
||||||
|
|
||||||
#define INTERRUPT_HANDLER_ERR(i, msg) \
|
|
||||||
static void interrupt ## i () \
|
|
||||||
{ \
|
|
||||||
uint32_t eax, ebx, ecx, edx; \
|
|
||||||
uint32_t esp, ebp; \
|
|
||||||
uint32_t cr0, cr2, cr3, cr4; \
|
|
||||||
uint32_t error_code; \
|
|
||||||
asm volatile("":"=a"(eax),"=b"(ebx),"=c"(ecx),"=d"(edx)); \
|
|
||||||
asm volatile("movl %%esp, %%eax":"=a"(esp)); \
|
|
||||||
asm volatile("movl %%ebp, %%eax":"=a"(ebp)); \
|
|
||||||
asm volatile("movl %%cr0, %%eax":"=a"(cr0)); \
|
|
||||||
asm volatile("movl %%cr2, %%eax":"=a"(cr2)); \
|
|
||||||
asm volatile("movl %%cr3, %%eax":"=a"(cr3)); \
|
|
||||||
asm volatile("movl %%cr4, %%eax":"=a"(cr4)); \
|
|
||||||
asm volatile("popl %%eax":"=a"(error_code)); \
|
|
||||||
Kernel::panic(msg " (error code: 0x{8H})\r\n" \
|
|
||||||
"Register dump\r\n" \
|
|
||||||
"eax=0x{8H}, ebx=0x{8H}, ecx=0x{8H}, edx=0x{8H}\r\n" \
|
|
||||||
"esp=0x{8H}, ebp=0x{8H}\r\n" \
|
|
||||||
"CR0=0x{8H}, CR2=0x{8H}, CR3=0x{8H}, CR4=0x{8H}\r\n", \
|
|
||||||
eax, ebx, ecx, edx, esp, ebp, cr0, cr2, cr3, cr4, error_code); \
|
|
||||||
}
|
|
||||||
|
|
||||||
#define REGISTER_HANDLER(i) register_interrupt_handler(i, interrupt ## i)
|
|
||||||
|
|
||||||
namespace IDT
|
|
||||||
{
|
|
||||||
|
|
||||||
struct GateDescriptor
|
|
||||||
{
|
|
||||||
uint16_t offset1;
|
|
||||||
uint16_t selector;
|
|
||||||
uint8_t reserved : 5;
|
|
||||||
uint8_t zero1 : 3;
|
|
||||||
uint8_t type : 4;
|
|
||||||
uint8_t zero2 : 1;
|
|
||||||
uint8_t DPL : 2;
|
|
||||||
uint8_t present : 1;
|
|
||||||
uint16_t offset2;
|
|
||||||
} __attribute__((packed));
|
|
||||||
|
|
||||||
struct IDTR
|
|
||||||
{
|
|
||||||
uint16_t size;
|
|
||||||
void* offset;
|
|
||||||
} __attribute((packed));
|
|
||||||
|
|
||||||
static IDTR s_idtr;
|
|
||||||
static GateDescriptor* s_idt = nullptr;
|
|
||||||
|
|
||||||
static void(*s_irq_handlers[16])() { nullptr };
|
|
||||||
|
|
||||||
INTERRUPT_HANDLER____(0x00, "Division Error")
|
|
||||||
INTERRUPT_HANDLER____(0x01, "Debug")
|
|
||||||
INTERRUPT_HANDLER____(0x02, "Non-maskable Interrupt")
|
|
||||||
INTERRUPT_HANDLER____(0x03, "Breakpoint")
|
|
||||||
INTERRUPT_HANDLER____(0x04, "Overflow")
|
|
||||||
INTERRUPT_HANDLER____(0x05, "Bound Range Exception")
|
|
||||||
INTERRUPT_HANDLER____(0x06, "Invalid Opcode")
|
|
||||||
INTERRUPT_HANDLER____(0x07, "Device Not Available")
|
|
||||||
INTERRUPT_HANDLER_ERR(0x08, "Double Fault")
|
|
||||||
INTERRUPT_HANDLER____(0x09, "Coprocessor Segment Overrun")
|
|
||||||
INTERRUPT_HANDLER_ERR(0x0A, "Invalid TSS")
|
|
||||||
INTERRUPT_HANDLER_ERR(0x0B, "Segment Not Present")
|
|
||||||
INTERRUPT_HANDLER_ERR(0x0C, "Stack-Segment Fault")
|
|
||||||
INTERRUPT_HANDLER_ERR(0x0D, "General Protection Fault")
|
|
||||||
INTERRUPT_HANDLER_ERR(0x0E, "Page Fault")
|
|
||||||
INTERRUPT_HANDLER____(0x0F, "Unknown Exception 0x0F")
|
|
||||||
INTERRUPT_HANDLER____(0x10, "x87 Floating-Point Exception")
|
|
||||||
INTERRUPT_HANDLER_ERR(0x11, "Alignment Check")
|
|
||||||
INTERRUPT_HANDLER____(0x12, "Machine Check")
|
|
||||||
INTERRUPT_HANDLER____(0x13, "SIMD Floating-Point Exception")
|
|
||||||
INTERRUPT_HANDLER____(0x14, "Virtualization Exception")
|
|
||||||
INTERRUPT_HANDLER_ERR(0x15, "Control Protection Exception")
|
|
||||||
INTERRUPT_HANDLER____(0x16, "Unknown Exception 0x16")
|
|
||||||
INTERRUPT_HANDLER____(0x17, "Unknown Exception 0x17")
|
|
||||||
INTERRUPT_HANDLER____(0x18, "Unknown Exception 0x18")
|
|
||||||
INTERRUPT_HANDLER____(0x19, "Unknown Exception 0x19")
|
|
||||||
INTERRUPT_HANDLER____(0x1A, "Unknown Exception 0x1A")
|
|
||||||
INTERRUPT_HANDLER____(0x1B, "Unknown Exception 0x1B")
|
|
||||||
INTERRUPT_HANDLER____(0x1C, "Hypervisor Injection Exception")
|
|
||||||
INTERRUPT_HANDLER_ERR(0x1D, "VMM Communication Exception")
|
|
||||||
INTERRUPT_HANDLER_ERR(0x1E, "Security Exception")
|
|
||||||
INTERRUPT_HANDLER____(0x1F, "Unkown Exception 0x1F")
|
|
||||||
|
|
||||||
extern "C" void handle_irq()
|
|
||||||
{
|
|
||||||
uint8_t irq;
|
|
||||||
for (uint32_t i = 0; i < 16; i++)
|
|
||||||
{
|
|
||||||
if (InterruptController::get().is_in_service(i))
|
|
||||||
{
|
|
||||||
irq = i;
|
|
||||||
goto found;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dprintln("Spurious irq");
|
|
||||||
return;
|
|
||||||
found:
|
|
||||||
if (s_irq_handlers[irq])
|
|
||||||
s_irq_handlers[irq]();
|
|
||||||
else
|
|
||||||
dprintln("no handler for irq 0x{2H}\n", irq);
|
|
||||||
|
|
||||||
// NOTE: Scheduler sends PIT eoi's
|
|
||||||
if (irq != PIT_IRQ)
|
|
||||||
InterruptController::get().eoi(irq);
|
|
||||||
|
|
||||||
Kernel::Scheduler::get().reschedule_if_idling();
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "C" void handle_irq_common();
|
|
||||||
asm(
|
|
||||||
".globl handle_irq_common;"
|
|
||||||
"handle_irq_common:"
|
|
||||||
"pusha;"
|
|
||||||
"pushw %ds;"
|
|
||||||
"pushw %es;"
|
|
||||||
"pushw %ss;"
|
|
||||||
"pushw %ss;"
|
|
||||||
"popw %ds;"
|
|
||||||
"popw %es;"
|
|
||||||
"call handle_irq;"
|
|
||||||
"popw %es;"
|
|
||||||
"popw %ds;"
|
|
||||||
"popa;"
|
|
||||||
"iret;"
|
|
||||||
);
|
|
||||||
|
|
||||||
extern "C" void syscall_asm();
|
|
||||||
asm(
|
|
||||||
".global syscall_asm;"
|
|
||||||
"syscall_asm:"
|
|
||||||
"pusha;"
|
|
||||||
"pushw %ds;"
|
|
||||||
"pushw %es;"
|
|
||||||
"pushw %ss;"
|
|
||||||
"pushw %ss;"
|
|
||||||
"popw %ds;"
|
|
||||||
"popw %es;"
|
|
||||||
"pushl %edx;"
|
|
||||||
"pushl %ecx;"
|
|
||||||
"pushl %ebx;"
|
|
||||||
"pushl %eax;"
|
|
||||||
"call cpp_syscall_handler;"
|
|
||||||
"addl $16, %esp;"
|
|
||||||
"popw %es;"
|
|
||||||
"popw %ds;"
|
|
||||||
|
|
||||||
// NOTE: following instructions are same as in 'popa', except we skip eax
|
|
||||||
// since it holds the return value of the syscall.
|
|
||||||
"popl %edi;"
|
|
||||||
"popl %esi;"
|
|
||||||
"popl %ebp;"
|
|
||||||
"addl $4, %esp;"
|
|
||||||
"popl %ebx;"
|
|
||||||
"popl %edx;"
|
|
||||||
"popl %ecx;"
|
|
||||||
"addl $4, %esp;"
|
|
||||||
|
|
||||||
"iret;"
|
|
||||||
);
|
|
||||||
|
|
||||||
static void flush_idt()
|
|
||||||
{
|
|
||||||
asm volatile("lidt %0"::"m"(s_idtr));
|
|
||||||
}
|
|
||||||
|
|
||||||
static void register_interrupt_handler(uint8_t index, void(*f)())
|
|
||||||
{
|
|
||||||
GateDescriptor& descriptor = s_idt[index];
|
|
||||||
descriptor.offset1 = (uint32_t)f & 0xFFFF;
|
|
||||||
descriptor.selector = 0x08;
|
|
||||||
descriptor.type = 0xE;
|
|
||||||
descriptor.DPL = 0;
|
|
||||||
descriptor.present = 1;
|
|
||||||
descriptor.offset2 = (uint32_t)f >> 16;
|
|
||||||
}
|
|
||||||
|
|
||||||
void register_irq_handler(uint8_t irq, void(*f)())
|
|
||||||
{
|
|
||||||
s_irq_handlers[irq] = f;
|
|
||||||
register_interrupt_handler(IRQ_VECTOR_BASE + irq, handle_irq_common);
|
|
||||||
flush_idt();
|
|
||||||
}
|
|
||||||
|
|
||||||
void register_syscall_handler(uint8_t offset, void(*handler)())
|
|
||||||
{
|
|
||||||
register_interrupt_handler(offset, handler);
|
|
||||||
s_idt[offset].DPL = 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
void initialize()
|
|
||||||
{
|
|
||||||
constexpr size_t idt_size = 0x100 * sizeof(GateDescriptor);
|
|
||||||
|
|
||||||
s_idt = (GateDescriptor*)kmalloc(idt_size);
|
|
||||||
ASSERT(s_idt);
|
|
||||||
memset(s_idt, 0x00, idt_size);
|
|
||||||
|
|
||||||
s_idtr.offset = s_idt;
|
|
||||||
s_idtr.size = idt_size - 1;
|
|
||||||
|
|
||||||
REGISTER_HANDLER(0x00);
|
|
||||||
REGISTER_HANDLER(0x01);
|
|
||||||
REGISTER_HANDLER(0x02);
|
|
||||||
REGISTER_HANDLER(0x03);
|
|
||||||
REGISTER_HANDLER(0x04);
|
|
||||||
REGISTER_HANDLER(0x05);
|
|
||||||
REGISTER_HANDLER(0x06);
|
|
||||||
REGISTER_HANDLER(0x07);
|
|
||||||
REGISTER_HANDLER(0x08);
|
|
||||||
REGISTER_HANDLER(0x09);
|
|
||||||
REGISTER_HANDLER(0x0A);
|
|
||||||
REGISTER_HANDLER(0x0B);
|
|
||||||
REGISTER_HANDLER(0x0C);
|
|
||||||
REGISTER_HANDLER(0x0D);
|
|
||||||
REGISTER_HANDLER(0x0E);
|
|
||||||
REGISTER_HANDLER(0x0F);
|
|
||||||
REGISTER_HANDLER(0x10);
|
|
||||||
REGISTER_HANDLER(0x11);
|
|
||||||
REGISTER_HANDLER(0x12);
|
|
||||||
REGISTER_HANDLER(0x13);
|
|
||||||
REGISTER_HANDLER(0x14);
|
|
||||||
REGISTER_HANDLER(0x15);
|
|
||||||
REGISTER_HANDLER(0x16);
|
|
||||||
REGISTER_HANDLER(0x17);
|
|
||||||
REGISTER_HANDLER(0x18);
|
|
||||||
REGISTER_HANDLER(0x19);
|
|
||||||
REGISTER_HANDLER(0x1A);
|
|
||||||
REGISTER_HANDLER(0x1B);
|
|
||||||
REGISTER_HANDLER(0x1C);
|
|
||||||
REGISTER_HANDLER(0x1D);
|
|
||||||
REGISTER_HANDLER(0x1E);
|
|
||||||
REGISTER_HANDLER(0x1F);
|
|
||||||
|
|
||||||
register_syscall_handler(0x80, syscall_asm);
|
|
||||||
|
|
||||||
flush_idt();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,227 +0,0 @@
|
|||||||
#include <BAN/Errors.h>
|
|
||||||
#include <kernel/Debug.h>
|
|
||||||
#include <kernel/Memory/MMU.h>
|
|
||||||
#include <kernel/Memory/kmalloc.h>
|
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#define MMU_DEBUG_PRINT 0
|
|
||||||
|
|
||||||
// bits 31-12 set
|
|
||||||
#define PAGE_MASK 0xfffff000
|
|
||||||
#define FLAGS_MASK 0x00000fff
|
|
||||||
|
|
||||||
namespace Kernel
|
|
||||||
{
|
|
||||||
|
|
||||||
static MMU* s_instance = nullptr;
|
|
||||||
|
|
||||||
void MMU::initialize()
|
|
||||||
{
|
|
||||||
ASSERT(s_instance == nullptr);
|
|
||||||
s_instance = new MMU();
|
|
||||||
ASSERT(s_instance);
|
|
||||||
s_instance->initialize_kernel();
|
|
||||||
s_instance->load();
|
|
||||||
}
|
|
||||||
|
|
||||||
MMU& MMU::get()
|
|
||||||
{
|
|
||||||
ASSERT(s_instance);
|
|
||||||
return *s_instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint64_t* allocate_page_aligned_page()
|
|
||||||
{
|
|
||||||
uint64_t* page = (uint64_t*)kmalloc(PAGE_SIZE, PAGE_SIZE);
|
|
||||||
ASSERT(page);
|
|
||||||
ASSERT(((uintptr_t)page % PAGE_SIZE) == 0);
|
|
||||||
memset(page, 0, PAGE_SIZE);
|
|
||||||
return page;
|
|
||||||
}
|
|
||||||
|
|
||||||
void MMU::initialize_kernel()
|
|
||||||
{
|
|
||||||
m_highest_paging_struct = (uint64_t*)kmalloc(sizeof(uint64_t) * 4, 32);
|
|
||||||
ASSERT(m_highest_paging_struct);
|
|
||||||
ASSERT(((uintptr_t)m_highest_paging_struct % 32) == 0);
|
|
||||||
|
|
||||||
// allocate all page directories
|
|
||||||
for (int i = 0; i < 4; i++)
|
|
||||||
{
|
|
||||||
uint64_t* page_directory = allocate_page_aligned_page();
|
|
||||||
m_highest_paging_struct[i] = (uint64_t)page_directory | Flags::Present;
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME: We should just identity map until g_kernel_end
|
|
||||||
|
|
||||||
// create and identity map first 6 MiB
|
|
||||||
uint64_t* page_directory1 = (uint64_t*)(m_highest_paging_struct[0] & PAGE_MASK);
|
|
||||||
for (uint64_t i = 0; i < 3; i++)
|
|
||||||
{
|
|
||||||
uint64_t* page_table = allocate_page_aligned_page();
|
|
||||||
for (uint64_t j = 0; j < 512; j++)
|
|
||||||
page_table[j] = (i << 21) | (j << 12) | Flags::ReadWrite | Flags::Present;
|
|
||||||
|
|
||||||
page_directory1[i] = (uint64_t)page_table | Flags::ReadWrite | Flags::Present;
|
|
||||||
}
|
|
||||||
|
|
||||||
// dont map first page (0 -> 4 KiB) so that nullptr dereference
|
|
||||||
// causes page fault :)
|
|
||||||
uint64_t* page_table1 = (uint64_t*)(page_directory1[0] & PAGE_MASK);
|
|
||||||
page_table1[0] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
MMU::MMU()
|
|
||||||
{
|
|
||||||
if (s_instance == nullptr)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Here we copy the s_instances paging structs since they are
|
|
||||||
// global for every process
|
|
||||||
|
|
||||||
uint64_t* global_pdpt = s_instance->m_highest_paging_struct;
|
|
||||||
|
|
||||||
uint64_t* pdpt = (uint64_t*)kmalloc(sizeof(uint64_t) * 4, 32);
|
|
||||||
ASSERT(pdpt);
|
|
||||||
|
|
||||||
for (uint32_t pdpte = 0; pdpte < 4; pdpte++)
|
|
||||||
{
|
|
||||||
if (!(global_pdpt[pdpte] & Flags::Present))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
uint64_t* global_pd = (uint64_t*)(global_pdpt[pdpte] & PAGE_MASK);
|
|
||||||
|
|
||||||
uint64_t* pd = allocate_page_aligned_page();
|
|
||||||
pdpt[pdpte] = (uint64_t)pd | (global_pdpt[pdpte] & ~PAGE_MASK);
|
|
||||||
|
|
||||||
for (uint32_t pde = 0; pde < 512; pde++)
|
|
||||||
{
|
|
||||||
if (!(global_pd[pde] & Flags::Present))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
uint64_t* global_pt = (uint64_t*)(global_pd[pde] & PAGE_MASK);
|
|
||||||
|
|
||||||
uint64_t* pt = allocate_page_aligned_page();
|
|
||||||
pd[pde] = (uint64_t)pt | (global_pd[pde] & ~PAGE_MASK);
|
|
||||||
|
|
||||||
memcpy(pt, global_pt, PAGE_SIZE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
m_highest_paging_struct = pdpt;
|
|
||||||
}
|
|
||||||
|
|
||||||
MMU::~MMU()
|
|
||||||
{
|
|
||||||
uint64_t* pdpt = m_highest_paging_struct;
|
|
||||||
for (uint32_t pdpte = 0; pdpte < 512; pdpte++)
|
|
||||||
{
|
|
||||||
if (!(pdpt[pdpte] & Flags::Present))
|
|
||||||
continue;
|
|
||||||
uint64_t* pd = (uint64_t*)(pdpt[pdpte] & PAGE_MASK);
|
|
||||||
for (uint32_t pde = 0; pde < 512; pde++)
|
|
||||||
{
|
|
||||||
if (!(pd[pde] & Flags::Present))
|
|
||||||
continue;
|
|
||||||
kfree((void*)(pd[pde] & PAGE_MASK));
|
|
||||||
}
|
|
||||||
kfree(pd);
|
|
||||||
}
|
|
||||||
kfree(pdpt);
|
|
||||||
}
|
|
||||||
|
|
||||||
void MMU::load()
|
|
||||||
{
|
|
||||||
asm volatile("movl %0, %%cr3" :: "r"(m_highest_paging_struct));
|
|
||||||
}
|
|
||||||
|
|
||||||
void MMU::map_page_at(paddr_t paddr, vaddr_t vaddr, uint8_t flags)
|
|
||||||
{
|
|
||||||
#if MMU_DEBUG_PRINT
|
|
||||||
dprintln("AllocatePage(0x{8H})", address);
|
|
||||||
#endif
|
|
||||||
ASSERT(flags & Flags::Present);
|
|
||||||
|
|
||||||
ASSERT(!(paddr & ~PAGE_MASK));
|
|
||||||
ASSERT(!(vaddr & ~PAGE_MASK));
|
|
||||||
|
|
||||||
uint32_t pdpte = (vaddr & 0xC0000000) >> 30;
|
|
||||||
uint32_t pde = (vaddr & 0x3FE00000) >> 21;
|
|
||||||
uint32_t pte = (vaddr & 0x001FF000) >> 12;
|
|
||||||
|
|
||||||
uint64_t* page_directory = (uint64_t*)(m_highest_paging_struct[pdpte] & PAGE_MASK);
|
|
||||||
if (!(page_directory[pde] & Flags::Present))
|
|
||||||
{
|
|
||||||
uint64_t* page_table = allocate_page_aligned_page();
|
|
||||||
page_directory[pde] = (uint64_t)page_table;
|
|
||||||
}
|
|
||||||
page_directory[pde] |= flags;
|
|
||||||
|
|
||||||
uint64_t* page_table = (uint64_t*)(page_directory[pde] & PAGE_MASK);
|
|
||||||
page_table[pte] = paddr | flags;
|
|
||||||
}
|
|
||||||
|
|
||||||
void MMU::identity_map_page(paddr_t address, uint8_t flags)
|
|
||||||
{
|
|
||||||
address &= PAGE_MASK;
|
|
||||||
map_page_at(address, address, flags);
|
|
||||||
}
|
|
||||||
|
|
||||||
void MMU::identity_map_range(paddr_t address, ptrdiff_t size, uint8_t flags)
|
|
||||||
{
|
|
||||||
paddr_t s_page = address & PAGE_MASK;
|
|
||||||
paddr_t e_page = (address + size - 1) & PAGE_MASK;
|
|
||||||
for (paddr_t page = s_page; page <= e_page; page += PAGE_SIZE)
|
|
||||||
identity_map_page(page, flags);
|
|
||||||
}
|
|
||||||
|
|
||||||
void MMU::unmap_page(vaddr_t address)
|
|
||||||
{
|
|
||||||
#if MMU_DEBUG_PRINT
|
|
||||||
dprintln("UnAllocatePage(0x{8H})", address & PAGE_MASK);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
uint32_t pdpte = (address & 0xC0000000) >> 30;
|
|
||||||
uint32_t pde = (address & 0x3FE00000) >> 21;
|
|
||||||
uint32_t pte = (address & 0x001FF000) >> 12;
|
|
||||||
|
|
||||||
uint64_t* page_directory = (uint64_t*)(m_highest_paging_struct[pdpte] & PAGE_MASK);
|
|
||||||
if (!(page_directory[pde] & Flags::Present))
|
|
||||||
return;
|
|
||||||
|
|
||||||
uint64_t* page_table = (uint64_t*)(page_directory[pde] & PAGE_MASK);
|
|
||||||
if (!(page_table[pte] & Flags::Present))
|
|
||||||
return;
|
|
||||||
|
|
||||||
page_table[pte] = 0;
|
|
||||||
|
|
||||||
// TODO: Unallocate the page table if this was the only allocated page
|
|
||||||
}
|
|
||||||
|
|
||||||
void MMU::unmap_range(vaddr_t address, ptrdiff_t size)
|
|
||||||
{
|
|
||||||
uintptr_t s_page = address & PAGE_MASK;
|
|
||||||
uintptr_t e_page = (address + size - 1) & PAGE_MASK;
|
|
||||||
for (uintptr_t page = s_page; page <= e_page; page += PAGE_SIZE)
|
|
||||||
unmap_page(page);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t MMU::get_page_flags(vaddr_t address) const
|
|
||||||
{
|
|
||||||
uint32_t pdpte = (address & 0xC0000000) >> 30;
|
|
||||||
uint32_t pde = (address & 0x3FE00000) >> 21;
|
|
||||||
uint32_t pte = (address & 0x001FF000) >> 12;
|
|
||||||
|
|
||||||
uint64_t* page_directory = (uint64_t*)(m_highest_paging_struct[pdpte] & PAGE_MASK);
|
|
||||||
if (!(page_directory[pde] & Flags::Present))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
uint64_t* page_table = (uint64_t*)(page_directory[pde] & PAGE_MASK);
|
|
||||||
if (!(page_table[pte] & Flags::Present))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
return page_table[pte] & FLAGS_MASK;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
.global spinlock_lock_asm
|
|
||||||
spinlock_lock_asm:
|
|
||||||
movl 4(%esp), %eax
|
|
||||||
lock; btsl $0, (%eax)
|
|
||||||
jnc .done
|
|
||||||
.retry:
|
|
||||||
pause
|
|
||||||
testl $1, (%eax)
|
|
||||||
jne .retry
|
|
||||||
lock; btsl $0, (%eax)
|
|
||||||
jc .retry
|
|
||||||
.done:
|
|
||||||
ret
|
|
||||||
|
|
||||||
.global spinlock_unlock_asm
|
|
||||||
spinlock_unlock_asm:
|
|
||||||
movl 4(%esp), %eax
|
|
||||||
movl $0, (%eax)
|
|
||||||
ret
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
# uint32_t read_rip()
|
|
||||||
.global read_rip
|
|
||||||
read_rip:
|
|
||||||
popl %eax
|
|
||||||
jmp *%eax
|
|
||||||
|
|
||||||
exit_thread_trampoline:
|
|
||||||
addl $4, %esp
|
|
||||||
pushl (%esp)
|
|
||||||
ret
|
|
||||||
|
|
||||||
# void start_thread(uint32_t esp, uint32_t eip)
|
|
||||||
.global start_thread
|
|
||||||
start_thread:
|
|
||||||
movl 8(%esp), %ecx
|
|
||||||
movl 4(%esp), %esp
|
|
||||||
movl $0, %ebp
|
|
||||||
pushl $exit_thread_trampoline
|
|
||||||
sti
|
|
||||||
jmp *%ecx
|
|
||||||
|
|
||||||
# void continue_thread(uint32_t rsp, uint32_t rip)
|
|
||||||
.global continue_thread
|
|
||||||
continue_thread:
|
|
||||||
movl 8(%esp), %ecx
|
|
||||||
movl 4(%esp), %esp
|
|
||||||
movl $0, %eax
|
|
||||||
jmp *%ecx
|
|
||||||
|
|
||||||
# void thread_jump_userspace(uint32_t rsp, uint32_t rip)
|
|
||||||
.global thread_jump_userspace
|
|
||||||
thread_jump_userspace:
|
|
||||||
movl $0x23, %eax
|
|
||||||
movw %ax, %ds
|
|
||||||
movw %ax, %es
|
|
||||||
movw %ax, %fs
|
|
||||||
movw %ax, %gs
|
|
||||||
|
|
||||||
movl 8(%esp), %ecx
|
|
||||||
movl 4(%esp), %esp
|
|
||||||
|
|
||||||
pushl $0x23
|
|
||||||
pushl %esp
|
|
||||||
pushfl
|
|
||||||
pushl $0x1B
|
|
||||||
pushl %ecx
|
|
||||||
iret
|
|
||||||
@@ -1,182 +0,0 @@
|
|||||||
# Declare constants for the multiboot header
|
|
||||||
.set ALIGN, 1<<0 # align loaded modules on page boundaries
|
|
||||||
.set MEMINFO, 1<<1 # provide memory map
|
|
||||||
.set VIDEOINFO, 1<<2 # provide video info
|
|
||||||
.set MB_FLAGS, ALIGN | MEMINFO | VIDEOINFO # this is the Multiboot 'flag' field
|
|
||||||
.set MB_MAGIC, 0x1BADB002 # 'magic number' lets bootloader find the header
|
|
||||||
.set MB_CHECKSUM, -(MB_MAGIC + MB_FLAGS) #checksum of above, to prove we are multiboot
|
|
||||||
|
|
||||||
# Multiboot header
|
|
||||||
.section .multiboot, "aw"
|
|
||||||
.align 4
|
|
||||||
.long MB_MAGIC
|
|
||||||
.long MB_FLAGS
|
|
||||||
.long MB_CHECKSUM
|
|
||||||
.skip 20
|
|
||||||
|
|
||||||
.long 0
|
|
||||||
.long 800
|
|
||||||
.long 600
|
|
||||||
.long 32
|
|
||||||
|
|
||||||
.section .bss, "aw", @nobits
|
|
||||||
# Create stack
|
|
||||||
.global g_boot_stack_bottom
|
|
||||||
g_boot_stack_bottom:
|
|
||||||
.skip 16384
|
|
||||||
.global g_boot_stack_top
|
|
||||||
g_boot_stack_top:
|
|
||||||
|
|
||||||
# 0 MiB -> 1 MiB: bootloader stuff
|
|
||||||
# 1 MiB -> : kernel
|
|
||||||
.align 32
|
|
||||||
boot_page_directory_pointer_table:
|
|
||||||
.skip 4 * 8
|
|
||||||
.align 4096
|
|
||||||
boot_page_directory1:
|
|
||||||
.skip 512 * 8
|
|
||||||
|
|
||||||
.global g_kernel_cmdline
|
|
||||||
g_kernel_cmdline:
|
|
||||||
.skip 4096
|
|
||||||
|
|
||||||
.global g_multiboot_info
|
|
||||||
g_multiboot_info:
|
|
||||||
.skip 4
|
|
||||||
.global g_multiboot_magic
|
|
||||||
g_multiboot_magic:
|
|
||||||
.skip 4
|
|
||||||
|
|
||||||
.section .text
|
|
||||||
|
|
||||||
boot_gdt:
|
|
||||||
.quad 0x0000000000000000 # null
|
|
||||||
.quad 0x00CF9A000000FFFF # kernel code
|
|
||||||
.quad 0x00CF92000000FFFF # kernel data
|
|
||||||
boot_gdtr:
|
|
||||||
.short . - boot_gdt - 1
|
|
||||||
.long boot_gdt
|
|
||||||
|
|
||||||
has_cpuid:
|
|
||||||
pushfl
|
|
||||||
pushfl
|
|
||||||
xorl $0x00200000, (%esp)
|
|
||||||
popfl
|
|
||||||
pushfl
|
|
||||||
popl %eax
|
|
||||||
xorl (%esp), %eax
|
|
||||||
popfl
|
|
||||||
testl $0x00200000, %eax
|
|
||||||
ret
|
|
||||||
|
|
||||||
has_pae:
|
|
||||||
movl $0, %eax
|
|
||||||
cpuid
|
|
||||||
testl $(1 << 6), %edx
|
|
||||||
ret
|
|
||||||
|
|
||||||
has_sse:
|
|
||||||
movl $1, %eax
|
|
||||||
cpuid
|
|
||||||
testl $(1 << 25), %edx
|
|
||||||
ret
|
|
||||||
|
|
||||||
check_requirements:
|
|
||||||
call has_cpuid
|
|
||||||
jz .exit
|
|
||||||
call has_pae
|
|
||||||
jz .exit
|
|
||||||
call has_sse
|
|
||||||
jz .exit
|
|
||||||
ret
|
|
||||||
.exit:
|
|
||||||
jmp system_halt
|
|
||||||
|
|
||||||
copy_kernel_commandline:
|
|
||||||
pushl %esi
|
|
||||||
pushl %edi
|
|
||||||
movl g_multiboot_info, %esi
|
|
||||||
addl $16, %esi
|
|
||||||
movl (%esi), %esi
|
|
||||||
movl $1024, %ecx
|
|
||||||
movl $g_kernel_cmdline, %edi
|
|
||||||
rep movsl
|
|
||||||
popl %edi
|
|
||||||
popl %esi
|
|
||||||
ret
|
|
||||||
|
|
||||||
enable_sse:
|
|
||||||
movl %cr0, %eax
|
|
||||||
andw $0xFFFB, %ax
|
|
||||||
orw $0x0002, %ax
|
|
||||||
movl %eax, %cr0
|
|
||||||
movl %cr4, %eax
|
|
||||||
orw $0x0600, %ax
|
|
||||||
movl %eax, %cr4
|
|
||||||
ret
|
|
||||||
|
|
||||||
initialize_paging:
|
|
||||||
# identity map first 6 MiB
|
|
||||||
movl $(0x00000000 + 0x83), boot_page_directory1 + 0
|
|
||||||
movl $(0x00200000 + 0x83), boot_page_directory1 + 8
|
|
||||||
movl $(0x00400000 + 0x83), boot_page_directory1 + 16
|
|
||||||
movl $(boot_page_directory1 + 0x01), boot_page_directory_pointer_table
|
|
||||||
|
|
||||||
# enable PAE
|
|
||||||
movl %cr4, %ecx
|
|
||||||
orl $0x20, %ecx
|
|
||||||
movl %ecx, %cr4
|
|
||||||
|
|
||||||
# set address of paging structures
|
|
||||||
movl $boot_page_directory_pointer_table, %ecx
|
|
||||||
movl %ecx, %cr3
|
|
||||||
|
|
||||||
# enable paging
|
|
||||||
movl %cr0, %ecx
|
|
||||||
orl $0x80000000, %ecx
|
|
||||||
movl %ecx, %cr0
|
|
||||||
|
|
||||||
ret
|
|
||||||
|
|
||||||
initialize_gdt:
|
|
||||||
lgdt boot_gdtr
|
|
||||||
|
|
||||||
# flush gdt
|
|
||||||
movw $0x10, %ax
|
|
||||||
movw %ax, %ds
|
|
||||||
movw %ax, %es
|
|
||||||
movw %ax, %fs
|
|
||||||
movw %ax, %gs
|
|
||||||
movw %ax, %ss
|
|
||||||
jmp $0x08, $flush
|
|
||||||
flush:
|
|
||||||
ret
|
|
||||||
|
|
||||||
.global _start
|
|
||||||
.type _start, @function
|
|
||||||
_start:
|
|
||||||
# Initialize stack and multiboot info
|
|
||||||
movl $g_boot_stack_top, %esp
|
|
||||||
movl %eax, g_multiboot_magic
|
|
||||||
movl %ebx, g_multiboot_info
|
|
||||||
|
|
||||||
call copy_kernel_commandline
|
|
||||||
call check_requirements
|
|
||||||
call enable_sse
|
|
||||||
|
|
||||||
call initialize_paging
|
|
||||||
call initialize_gdt
|
|
||||||
|
|
||||||
call _init
|
|
||||||
|
|
||||||
# call to the kernel itself (clear ebp for stacktrace)
|
|
||||||
xorl %ebp, %ebp
|
|
||||||
call kernel_main
|
|
||||||
|
|
||||||
call _fini
|
|
||||||
|
|
||||||
system_halt:
|
|
||||||
xchgw %bx, %bx
|
|
||||||
cli
|
|
||||||
1: hlt
|
|
||||||
jmp 1b
|
|
||||||
@@ -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,28 +0,0 @@
|
|||||||
ENTRY (_start)
|
|
||||||
|
|
||||||
SECTIONS
|
|
||||||
{
|
|
||||||
. = 0x00100000;
|
|
||||||
|
|
||||||
g_kernel_start = .;
|
|
||||||
.text BLOCK(4K) : ALIGN(4K)
|
|
||||||
{
|
|
||||||
*(.multiboot)
|
|
||||||
*(.text)
|
|
||||||
}
|
|
||||||
.rodata BLOCK(4K) : ALIGN(4K)
|
|
||||||
{
|
|
||||||
*(.rodata.*)
|
|
||||||
}
|
|
||||||
.data BLOCK(4K) : ALIGN(4K)
|
|
||||||
{
|
|
||||||
*(.data)
|
|
||||||
}
|
|
||||||
.bss BLOCK(4K) : ALIGN(4K)
|
|
||||||
{
|
|
||||||
*(COMMON)
|
|
||||||
*(.bss)
|
|
||||||
}
|
|
||||||
|
|
||||||
g_kernel_end = .;
|
|
||||||
}
|
|
||||||
754
kernel/arch/i686/PageTable.cpp
Normal file
754
kernel/arch/i686/PageTable.cpp
Normal file
@@ -0,0 +1,754 @@
|
|||||||
|
#include <kernel/BootInfo.h>
|
||||||
|
#include <kernel/CPUID.h>
|
||||||
|
#include <kernel/Lock/SpinLock.h>
|
||||||
|
#include <kernel/Memory/kmalloc.h>
|
||||||
|
#include <kernel/Memory/PageTable.h>
|
||||||
|
|
||||||
|
extern uint8_t g_kernel_start[];
|
||||||
|
extern uint8_t g_kernel_end[];
|
||||||
|
|
||||||
|
extern uint8_t g_kernel_execute_start[];
|
||||||
|
extern uint8_t g_kernel_execute_end[];
|
||||||
|
|
||||||
|
extern uint8_t g_kernel_writable_start[];
|
||||||
|
extern uint8_t g_kernel_writable_end[];
|
||||||
|
|
||||||
|
extern uint8_t g_userspace_start[];
|
||||||
|
extern uint8_t g_userspace_end[];
|
||||||
|
|
||||||
|
extern uint64_t g_boot_fast_page_pt[];
|
||||||
|
|
||||||
|
namespace Kernel
|
||||||
|
{
|
||||||
|
|
||||||
|
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_initialized = false;
|
||||||
|
|
||||||
|
static PageTable* s_kernel = nullptr;
|
||||||
|
static bool s_has_nxe = false;
|
||||||
|
static bool s_has_pge = false;
|
||||||
|
static bool s_has_pat = false;
|
||||||
|
|
||||||
|
static paddr_t s_global_pdpte = 0;
|
||||||
|
|
||||||
|
static uint64_t* s_fast_page_pt { nullptr };
|
||||||
|
|
||||||
|
static uint64_t* allocate_zeroed_page_aligned_page()
|
||||||
|
{
|
||||||
|
void* page = kmalloc(PAGE_SIZE, PAGE_SIZE, true);
|
||||||
|
ASSERT(page);
|
||||||
|
memset(page, 0, PAGE_SIZE);
|
||||||
|
return (uint64_t*)page;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
static paddr_t V2P(const T vaddr)
|
||||||
|
{
|
||||||
|
return (vaddr_t)vaddr - KERNEL_OFFSET + g_boot_info.kernel_paddr;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
static uint64_t* P2V(const T paddr)
|
||||||
|
{
|
||||||
|
return reinterpret_cast<uint64_t*>(reinterpret_cast<paddr_t>(paddr) - g_boot_info.kernel_paddr + KERNEL_OFFSET);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline PageTable::flags_t parse_flags(uint64_t entry)
|
||||||
|
{
|
||||||
|
using Flags = PageTable::Flags;
|
||||||
|
|
||||||
|
PageTable::flags_t result = 0;
|
||||||
|
if (s_has_nxe && !(entry & (1ull << 63)))
|
||||||
|
result |= Flags::Execute;
|
||||||
|
if (entry & Flags::Reserved)
|
||||||
|
result |= Flags::Reserved;
|
||||||
|
if (entry & Flags::UserSupervisor)
|
||||||
|
result |= Flags::UserSupervisor;
|
||||||
|
if (entry & Flags::ReadWrite)
|
||||||
|
result |= Flags::ReadWrite;
|
||||||
|
if (entry & Flags::Present)
|
||||||
|
result |= Flags::Present;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PageTable::initialize_fast_page()
|
||||||
|
{
|
||||||
|
s_fast_page_pt = g_boot_fast_page_pt;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void detect_cpu_features()
|
||||||
|
{
|
||||||
|
if (CPUID::has_nxe())
|
||||||
|
s_has_nxe = true;
|
||||||
|
if (CPUID::has_pge())
|
||||||
|
s_has_pge = true;
|
||||||
|
if (CPUID::has_pat())
|
||||||
|
s_has_pat = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PageTable::enable_cpu_features()
|
||||||
|
{
|
||||||
|
if (s_has_nxe)
|
||||||
|
{
|
||||||
|
asm volatile(
|
||||||
|
"movl $0xC0000080, %%ecx;"
|
||||||
|
"rdmsr;"
|
||||||
|
"orl $0x800, %%eax;"
|
||||||
|
"wrmsr"
|
||||||
|
::: "eax", "ecx", "edx", "memory"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s_has_pge)
|
||||||
|
{
|
||||||
|
asm volatile(
|
||||||
|
"movl %%cr4, %%eax;"
|
||||||
|
"orl $0x80, %%eax;"
|
||||||
|
"movl %%eax, %%cr4;"
|
||||||
|
::: "eax"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s_has_pat)
|
||||||
|
{
|
||||||
|
asm volatile(
|
||||||
|
"movl $0x277, %%ecx;"
|
||||||
|
"rdmsr;"
|
||||||
|
"movw $0x0401, %%dx;"
|
||||||
|
"wrmsr;"
|
||||||
|
::: "eax", "ecx", "edx", "memory"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// enable write protect
|
||||||
|
asm volatile(
|
||||||
|
"movl %%cr0, %%eax;"
|
||||||
|
"orl $0x10000, %%eax;"
|
||||||
|
"movl %%eax, %%cr0;"
|
||||||
|
::: "rax"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PageTable::initialize_and_load()
|
||||||
|
{
|
||||||
|
detect_cpu_features();
|
||||||
|
enable_cpu_features();
|
||||||
|
|
||||||
|
ASSERT(s_kernel == nullptr);
|
||||||
|
s_kernel = new PageTable();
|
||||||
|
ASSERT(s_kernel);
|
||||||
|
|
||||||
|
auto* pdpt = allocate_zeroed_page_aligned_page();
|
||||||
|
ASSERT(pdpt);
|
||||||
|
|
||||||
|
s_kernel->m_highest_paging_struct = V2P(pdpt);
|
||||||
|
s_kernel->map_kernel_memory();
|
||||||
|
|
||||||
|
PageTable::with_fast_page(s_kernel->m_highest_paging_struct, [] {
|
||||||
|
s_global_pdpte = PageTable::fast_page_as_sized<paddr_t>(3);
|
||||||
|
});
|
||||||
|
|
||||||
|
// update fast page pt
|
||||||
|
{
|
||||||
|
constexpr vaddr_t vaddr = fast_page();
|
||||||
|
constexpr uint16_t pdpte = (vaddr >> 30) & 0x1FF;
|
||||||
|
constexpr uint16_t pde = (vaddr >> 21) & 0x1FF;
|
||||||
|
|
||||||
|
const auto get_or_allocate_entry =
|
||||||
|
[](paddr_t table_paddr, uint16_t entry, uint64_t flags)
|
||||||
|
{
|
||||||
|
uint64_t* table = P2V(table_paddr);
|
||||||
|
|
||||||
|
if (!(table[entry] & Flags::Present))
|
||||||
|
{
|
||||||
|
auto* vaddr = allocate_zeroed_page_aligned_page();
|
||||||
|
ASSERT(vaddr);
|
||||||
|
table[entry] = V2P(vaddr);
|
||||||
|
}
|
||||||
|
|
||||||
|
table[entry] |= flags;
|
||||||
|
|
||||||
|
return table[entry] & s_page_addr_mask;
|
||||||
|
};
|
||||||
|
|
||||||
|
const paddr_t pdpt = s_kernel->m_highest_paging_struct;
|
||||||
|
const paddr_t pd = get_or_allocate_entry(pdpt, pdpte, Flags::Present);
|
||||||
|
s_fast_page_pt = P2V(get_or_allocate_entry(pd, pde, Flags::ReadWrite | Flags::Present));
|
||||||
|
}
|
||||||
|
|
||||||
|
s_kernel->load();
|
||||||
|
}
|
||||||
|
|
||||||
|
PageTable& PageTable::kernel()
|
||||||
|
{
|
||||||
|
ASSERT(s_kernel);
|
||||||
|
return *s_kernel;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PageTable::is_valid_pointer(uintptr_t)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PageTable::map_kernel_memory()
|
||||||
|
{
|
||||||
|
// Map (phys_kernel_start -> phys_kernel_end) to (virt_kernel_start -> virt_kernel_end)
|
||||||
|
map_range_at(
|
||||||
|
V2P(g_kernel_start),
|
||||||
|
reinterpret_cast<vaddr_t>(g_kernel_start),
|
||||||
|
g_kernel_end - g_kernel_start,
|
||||||
|
Flags::Present
|
||||||
|
);
|
||||||
|
|
||||||
|
// Map executable kernel memory as executable
|
||||||
|
map_range_at(
|
||||||
|
V2P(g_kernel_execute_start),
|
||||||
|
reinterpret_cast<vaddr_t>(g_kernel_execute_start),
|
||||||
|
g_kernel_execute_end - g_kernel_execute_start,
|
||||||
|
Flags::Execute | Flags::Present
|
||||||
|
);
|
||||||
|
|
||||||
|
// Map writable kernel memory as writable
|
||||||
|
map_range_at(
|
||||||
|
V2P(g_kernel_writable_start),
|
||||||
|
reinterpret_cast<vaddr_t>(g_kernel_writable_start),
|
||||||
|
g_kernel_writable_end - g_kernel_writable_start,
|
||||||
|
Flags::ReadWrite | Flags::Present
|
||||||
|
);
|
||||||
|
|
||||||
|
// Map userspace memory
|
||||||
|
map_range_at(
|
||||||
|
V2P(g_userspace_start),
|
||||||
|
reinterpret_cast<vaddr_t>(g_userspace_start),
|
||||||
|
g_userspace_end - g_userspace_start,
|
||||||
|
Flags::Execute | Flags::UserSupervisor | Flags::Present
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PageTable::map_fast_page(paddr_t paddr)
|
||||||
|
{
|
||||||
|
ASSERT(paddr && paddr % PAGE_SIZE == 0);
|
||||||
|
|
||||||
|
ASSERT(s_fast_page_pt);
|
||||||
|
ASSERT(s_fast_page_lock.current_processor_has_lock());
|
||||||
|
|
||||||
|
ASSERT(!(*s_fast_page_pt & Flags::Present));
|
||||||
|
s_fast_page_pt[0] = paddr | Flags::ReadWrite | Flags::Present;
|
||||||
|
|
||||||
|
asm volatile("invlpg (%0)" :: "r"(fast_page()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void PageTable::unmap_fast_page()
|
||||||
|
{
|
||||||
|
ASSERT(s_fast_page_pt);
|
||||||
|
ASSERT(s_fast_page_lock.current_processor_has_lock());
|
||||||
|
|
||||||
|
ASSERT((*s_fast_page_pt & Flags::Present));
|
||||||
|
s_fast_page_pt[0] = 0;
|
||||||
|
|
||||||
|
asm volatile("invlpg (%0)" :: "r"(fast_page()));
|
||||||
|
}
|
||||||
|
|
||||||
|
BAN::ErrorOr<PageTable*> PageTable::create_userspace()
|
||||||
|
{
|
||||||
|
SpinLockGuard _(s_kernel->m_lock);
|
||||||
|
PageTable* page_table = new PageTable;
|
||||||
|
if (page_table == nullptr)
|
||||||
|
return BAN::Error::from_errno(ENOMEM);
|
||||||
|
|
||||||
|
uint64_t* pdpt = allocate_zeroed_page_aligned_page();
|
||||||
|
if (pdpt == nullptr)
|
||||||
|
{
|
||||||
|
delete page_table;
|
||||||
|
return BAN::Error::from_errno(ENOMEM);
|
||||||
|
}
|
||||||
|
|
||||||
|
page_table->m_highest_paging_struct = V2P(pdpt);
|
||||||
|
|
||||||
|
pdpt[0] = 0;
|
||||||
|
pdpt[1] = 0;
|
||||||
|
pdpt[2] = 0;
|
||||||
|
pdpt[3] = s_global_pdpte | Flags::Present;
|
||||||
|
static_assert(KERNEL_OFFSET == 0xC0000000);
|
||||||
|
|
||||||
|
return page_table;
|
||||||
|
}
|
||||||
|
|
||||||
|
PageTable::~PageTable()
|
||||||
|
{
|
||||||
|
if (m_highest_paging_struct == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
uint64_t* pdpt = P2V(m_highest_paging_struct);
|
||||||
|
for (uint32_t pdpte = 0; pdpte < 3; pdpte++)
|
||||||
|
{
|
||||||
|
if (!(pdpt[pdpte] & Flags::Present))
|
||||||
|
continue;
|
||||||
|
uint64_t* pd = P2V(pdpt[pdpte] & s_page_addr_mask);
|
||||||
|
for (uint32_t pde = 0; pde < 512; pde++)
|
||||||
|
{
|
||||||
|
if (!(pd[pde] & Flags::Present))
|
||||||
|
continue;
|
||||||
|
kfree(P2V(pd[pde] & s_page_addr_mask));
|
||||||
|
}
|
||||||
|
kfree(pd);
|
||||||
|
}
|
||||||
|
kfree(pdpt);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PageTable::load()
|
||||||
|
{
|
||||||
|
SpinLockGuard _(m_lock);
|
||||||
|
ASSERT(m_highest_paging_struct < 0x100000000);
|
||||||
|
asm volatile("movl %0, %%cr3" :: "r"(static_cast<uint32_t>(m_highest_paging_struct)));
|
||||||
|
Processor::set_current_page_table(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PageTable::invalidate_range(vaddr_t vaddr, size_t pages, bool send_smp_message)
|
||||||
|
{
|
||||||
|
ASSERT(vaddr % PAGE_SIZE == 0);
|
||||||
|
|
||||||
|
const bool is_userspace = (vaddr < KERNEL_OFFSET);
|
||||||
|
if (is_userspace && this != &PageTable::current())
|
||||||
|
;
|
||||||
|
else if (pages <= 32 || !s_is_initialized)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < pages; i++, vaddr += PAGE_SIZE)
|
||||||
|
asm volatile("invlpg (%0)" :: "r"(vaddr));
|
||||||
|
}
|
||||||
|
else if (is_userspace || !s_has_pge)
|
||||||
|
{
|
||||||
|
asm volatile("movl %0, %%cr3" :: "r"(static_cast<uint32_t>(m_highest_paging_struct)));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
asm volatile(
|
||||||
|
"movl %%cr4, %%eax;"
|
||||||
|
|
||||||
|
"andl $~0x80, %%eax;"
|
||||||
|
"movl %%eax, %%cr4;"
|
||||||
|
|
||||||
|
"movl %0, %%cr3;"
|
||||||
|
|
||||||
|
"orl $0x80, %%eax;"
|
||||||
|
"movl %%eax, %%cr4;"
|
||||||
|
:
|
||||||
|
: "r"(static_cast<uint32_t>(m_highest_paging_struct))
|
||||||
|
: "eax"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (send_smp_message)
|
||||||
|
{
|
||||||
|
Processor::broadcast_smp_message({
|
||||||
|
.type = Processor::SMPMessage::Type::FlushTLB,
|
||||||
|
.flush_tlb = {
|
||||||
|
.vaddr = vaddr,
|
||||||
|
.page_count = pages,
|
||||||
|
.page_table = vaddr < KERNEL_OFFSET ? this : nullptr,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PageTable::unmap_page(vaddr_t vaddr, bool invalidate)
|
||||||
|
{
|
||||||
|
ASSERT(vaddr);
|
||||||
|
ASSERT(vaddr % PAGE_SIZE == 0);
|
||||||
|
ASSERT(vaddr != fast_page());
|
||||||
|
if (vaddr >= KERNEL_OFFSET)
|
||||||
|
ASSERT(vaddr >= (vaddr_t)g_kernel_start);
|
||||||
|
if ((vaddr >= KERNEL_OFFSET) != (this == s_kernel))
|
||||||
|
Kernel::panic("unmapping {8H}, kernel: {}", vaddr, this == s_kernel);
|
||||||
|
|
||||||
|
const uint64_t pdpte = (vaddr >> 30) & 0x1FF;
|
||||||
|
const uint64_t pde = (vaddr >> 21) & 0x1FF;
|
||||||
|
const uint64_t pte = (vaddr >> 12) & 0x1FF;
|
||||||
|
|
||||||
|
SpinLockGuard _(m_lock);
|
||||||
|
|
||||||
|
if (is_page_free(vaddr))
|
||||||
|
Kernel::panic("trying to unmap unmapped page 0x{H}", vaddr);
|
||||||
|
|
||||||
|
uint64_t* pdpt = P2V(m_highest_paging_struct);
|
||||||
|
uint64_t* pd = P2V(pdpt[pdpte] & s_page_addr_mask);
|
||||||
|
uint64_t* pt = P2V(pd[pde] & s_page_addr_mask);
|
||||||
|
|
||||||
|
const paddr_t old_paddr = pt[pte] & s_page_addr_mask;
|
||||||
|
|
||||||
|
pt[pte] = 0;
|
||||||
|
|
||||||
|
if (invalidate && old_paddr != 0)
|
||||||
|
invalidate_page(vaddr, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PageTable::unmap_range(vaddr_t vaddr, size_t size)
|
||||||
|
{
|
||||||
|
ASSERT(vaddr % PAGE_SIZE == 0);
|
||||||
|
|
||||||
|
size_t page_count = range_page_count(vaddr, size);
|
||||||
|
|
||||||
|
SpinLockGuard _(m_lock);
|
||||||
|
for (vaddr_t page = 0; page < page_count; page++)
|
||||||
|
unmap_page(vaddr + page * PAGE_SIZE, false);
|
||||||
|
invalidate_range(vaddr, page_count, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PageTable::map_page_at(paddr_t paddr, vaddr_t vaddr, flags_t flags, MemoryType memory_type, bool invalidate)
|
||||||
|
{
|
||||||
|
ASSERT(vaddr);
|
||||||
|
ASSERT(vaddr != fast_page());
|
||||||
|
if ((vaddr >= KERNEL_OFFSET) != (this == s_kernel))
|
||||||
|
Kernel::panic("mapping {8H} to {8H}, kernel: {}", paddr, vaddr, this == s_kernel);
|
||||||
|
|
||||||
|
ASSERT(paddr % PAGE_SIZE == 0);
|
||||||
|
ASSERT(vaddr % PAGE_SIZE == 0);
|
||||||
|
ASSERT(flags & Flags::Used);
|
||||||
|
|
||||||
|
const uint64_t pdpte = (vaddr >> 30) & 0x1FF;
|
||||||
|
const uint64_t pde = (vaddr >> 21) & 0x1FF;
|
||||||
|
const uint64_t pte = (vaddr >> 12) & 0x1FF;
|
||||||
|
|
||||||
|
uint64_t extra_flags = 0;
|
||||||
|
if (s_has_pge && vaddr >= KERNEL_OFFSET) // Map kernel memory as global
|
||||||
|
extra_flags |= 1ull << 8;
|
||||||
|
if (s_has_nxe && !(flags & Flags::Execute))
|
||||||
|
extra_flags |= 1ull << 63;
|
||||||
|
if (flags & Flags::Reserved)
|
||||||
|
extra_flags |= Flags::Reserved;
|
||||||
|
|
||||||
|
if (memory_type == MemoryType::Uncached)
|
||||||
|
extra_flags |= (1ull << 4);
|
||||||
|
if (s_has_pat && memory_type == MemoryType::WriteCombining)
|
||||||
|
extra_flags |= (1ull << 7);
|
||||||
|
if (s_has_pat && memory_type == MemoryType::WriteThrough)
|
||||||
|
extra_flags |= (1ull << 7) | (1ull << 3);
|
||||||
|
|
||||||
|
// NOTE: we add present here, since it has to be available in higher level structures
|
||||||
|
flags_t uwr_flags = (flags & (Flags::UserSupervisor | Flags::ReadWrite)) | Flags::Present;
|
||||||
|
|
||||||
|
SpinLockGuard _(m_lock);
|
||||||
|
|
||||||
|
uint64_t* pdpt = P2V(m_highest_paging_struct);
|
||||||
|
if (!(pdpt[pdpte] & Flags::Present))
|
||||||
|
pdpt[pdpte] = V2P(allocate_zeroed_page_aligned_page()) | Flags::Present;
|
||||||
|
|
||||||
|
uint64_t* pd = P2V(pdpt[pdpte] & s_page_addr_mask);
|
||||||
|
if ((pd[pde] & uwr_flags) != uwr_flags)
|
||||||
|
{
|
||||||
|
if (!(pd[pde] & Flags::Present))
|
||||||
|
pd[pde] = V2P(allocate_zeroed_page_aligned_page());
|
||||||
|
pd[pde] |= uwr_flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(flags & Flags::Present))
|
||||||
|
uwr_flags &= ~Flags::Present;
|
||||||
|
|
||||||
|
uint64_t* pt = P2V(pd[pde] & s_page_addr_mask);
|
||||||
|
|
||||||
|
const paddr_t old_paddr = pt[pte] & s_page_addr_mask;
|
||||||
|
|
||||||
|
pt[pte] = paddr | uwr_flags | extra_flags;
|
||||||
|
|
||||||
|
if (invalidate && old_paddr != 0)
|
||||||
|
invalidate_page(vaddr, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PageTable::map_range_at(paddr_t paddr, vaddr_t vaddr, size_t size, flags_t flags, MemoryType memory_type)
|
||||||
|
{
|
||||||
|
ASSERT(vaddr);
|
||||||
|
ASSERT(paddr % PAGE_SIZE == 0);
|
||||||
|
ASSERT(vaddr % PAGE_SIZE == 0);
|
||||||
|
|
||||||
|
size_t page_count = range_page_count(vaddr, size);
|
||||||
|
|
||||||
|
SpinLockGuard _(m_lock);
|
||||||
|
for (size_t page = 0; page < page_count; page++)
|
||||||
|
map_page_at(paddr + page * PAGE_SIZE, vaddr + page * PAGE_SIZE, flags, memory_type, false);
|
||||||
|
invalidate_range(vaddr, page_count, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PageTable::remove_writable_from_range(vaddr_t vaddr, size_t size)
|
||||||
|
{
|
||||||
|
ASSERT(vaddr);
|
||||||
|
ASSERT(vaddr % PAGE_SIZE == 0);
|
||||||
|
|
||||||
|
uint32_t pdpte = (vaddr >> 30) & 0x1FF;
|
||||||
|
uint32_t pde = (vaddr >> 21) & 0x1FF;
|
||||||
|
uint32_t pte = (vaddr >> 12) & 0x1FF;
|
||||||
|
|
||||||
|
const uint32_t e_pdpte = ((vaddr + size - 1) >> 30) & 0x1FF;
|
||||||
|
const uint32_t e_pde = ((vaddr + size - 1) >> 21) & 0x1FF;
|
||||||
|
const uint32_t e_pte = ((vaddr + size - 1) >> 12) & 0x1FF;
|
||||||
|
|
||||||
|
SpinLockGuard _(m_lock);
|
||||||
|
|
||||||
|
const uint64_t* pdpt = P2V(m_highest_paging_struct);
|
||||||
|
for (; pdpte <= e_pdpte; pdpte++)
|
||||||
|
{
|
||||||
|
if (!(pdpt[pdpte] & Flags::Present))
|
||||||
|
continue;
|
||||||
|
const uint64_t* pd = P2V(pdpt[pdpte] & s_page_addr_mask);
|
||||||
|
for (; pde < 512; pde++)
|
||||||
|
{
|
||||||
|
if (pdpte == e_pdpte && pde > e_pde)
|
||||||
|
break;
|
||||||
|
if (!(pd[pde] & Flags::ReadWrite))
|
||||||
|
continue;
|
||||||
|
uint64_t* pt = P2V(pd[pde] & s_page_addr_mask);
|
||||||
|
for (; pte < 512; pte++)
|
||||||
|
{
|
||||||
|
if (pdpte == e_pdpte && pde == e_pde && pte > e_pte)
|
||||||
|
break;
|
||||||
|
pt[pte] &= ~static_cast<uint64_t>(Flags::ReadWrite);
|
||||||
|
}
|
||||||
|
pte = 0;
|
||||||
|
}
|
||||||
|
pde = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
invalidate_range(vaddr, size / PAGE_SIZE, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t PageTable::get_page_data(vaddr_t vaddr) const
|
||||||
|
{
|
||||||
|
ASSERT(vaddr % PAGE_SIZE == 0);
|
||||||
|
|
||||||
|
const uint64_t pdpte = (vaddr >> 30) & 0x1FF;
|
||||||
|
const uint64_t pde = (vaddr >> 21) & 0x1FF;
|
||||||
|
const uint64_t pte = (vaddr >> 12) & 0x1FF;
|
||||||
|
|
||||||
|
SpinLockGuard _(m_lock);
|
||||||
|
|
||||||
|
const uint64_t* pdpt = P2V(m_highest_paging_struct);
|
||||||
|
if (!(pdpt[pdpte] & Flags::Present))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
const uint64_t* pd = P2V(pdpt[pdpte] & s_page_addr_mask);
|
||||||
|
if (!(pd[pde] & Flags::Present))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
const uint64_t* pt = P2V(pd[pde] & s_page_addr_mask);
|
||||||
|
if (!(pt[pte] & Flags::Used))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return pt[pte];
|
||||||
|
}
|
||||||
|
|
||||||
|
PageTable::flags_t PageTable::get_page_flags(vaddr_t vaddr) const
|
||||||
|
{
|
||||||
|
return parse_flags(get_page_data(vaddr));
|
||||||
|
}
|
||||||
|
|
||||||
|
paddr_t PageTable::physical_address_of(vaddr_t vaddr) const
|
||||||
|
{
|
||||||
|
return get_page_data(vaddr) & s_page_addr_mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PageTable::is_page_free(vaddr_t vaddr) const
|
||||||
|
{
|
||||||
|
ASSERT(vaddr % PAGE_SIZE == 0);
|
||||||
|
return !(get_page_flags(vaddr) & Flags::Used);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PageTable::is_range_free(vaddr_t vaddr, size_t size) const
|
||||||
|
{
|
||||||
|
vaddr_t s_page = vaddr / PAGE_SIZE;
|
||||||
|
vaddr_t e_page = BAN::Math::div_round_up<vaddr_t>(vaddr + size, PAGE_SIZE);
|
||||||
|
|
||||||
|
SpinLockGuard _(m_lock);
|
||||||
|
for (vaddr_t page = s_page; page < e_page; page++)
|
||||||
|
if (!is_page_free(page * PAGE_SIZE))
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PageTable::reserve_page(vaddr_t vaddr, bool only_free, bool send_smp_message)
|
||||||
|
{
|
||||||
|
SpinLockGuard _(m_lock);
|
||||||
|
ASSERT(vaddr % PAGE_SIZE == 0);
|
||||||
|
if (only_free && !is_page_free(vaddr))
|
||||||
|
return false;
|
||||||
|
map_page_at(0, vaddr, Flags::Reserved, MemoryType::Normal, send_smp_message);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PageTable::reserve_range(vaddr_t vaddr, size_t bytes, bool only_free)
|
||||||
|
{
|
||||||
|
if (size_t rem = bytes % PAGE_SIZE)
|
||||||
|
bytes += PAGE_SIZE - rem;
|
||||||
|
ASSERT(vaddr % PAGE_SIZE == 0);
|
||||||
|
|
||||||
|
SpinLockGuard _(m_lock);
|
||||||
|
if (only_free && !is_range_free(vaddr, bytes))
|
||||||
|
return false;
|
||||||
|
for (size_t offset = 0; offset < bytes; offset += PAGE_SIZE)
|
||||||
|
reserve_page(vaddr + offset, true, false);
|
||||||
|
invalidate_range(vaddr, bytes / PAGE_SIZE, true);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
vaddr_t PageTable::reserve_free_page(vaddr_t first_address, vaddr_t last_address)
|
||||||
|
{
|
||||||
|
if (first_address >= KERNEL_OFFSET && first_address < (vaddr_t)g_kernel_end)
|
||||||
|
first_address = (vaddr_t)g_kernel_end;
|
||||||
|
if (size_t rem = first_address % PAGE_SIZE)
|
||||||
|
first_address += PAGE_SIZE - rem;
|
||||||
|
if (size_t rem = last_address % PAGE_SIZE)
|
||||||
|
last_address -= rem;
|
||||||
|
|
||||||
|
uint32_t pdpte = (first_address >> 30) & 0x1FF;
|
||||||
|
uint32_t pde = (first_address >> 21) & 0x1FF;
|
||||||
|
uint32_t pte = (first_address >> 12) & 0x1FF;
|
||||||
|
|
||||||
|
const uint32_t e_pdpte = ((last_address - 1) >> 30) & 0x1FF;
|
||||||
|
const uint32_t e_pde = ((last_address - 1) >> 21) & 0x1FF;
|
||||||
|
const uint32_t e_pte = ((last_address - 1) >> 12) & 0x1FF;
|
||||||
|
|
||||||
|
SpinLockGuard _(m_lock);
|
||||||
|
|
||||||
|
// Try to find free page that can be mapped without
|
||||||
|
// allocations (page table with unused entries)
|
||||||
|
const uint64_t* pdpt = P2V(m_highest_paging_struct);
|
||||||
|
for (; pdpte <= e_pdpte; pdpte++)
|
||||||
|
{
|
||||||
|
if (!(pdpt[pdpte] & Flags::Present))
|
||||||
|
continue;
|
||||||
|
const uint64_t* pd = P2V(pdpt[pdpte] & s_page_addr_mask);
|
||||||
|
for (; pde < 512; pde++)
|
||||||
|
{
|
||||||
|
if (pdpte == e_pdpte && pde > e_pde)
|
||||||
|
break;
|
||||||
|
if (!(pd[pde] & Flags::Present))
|
||||||
|
continue;
|
||||||
|
const uint64_t* pt = P2V(pd[pde] & s_page_addr_mask);
|
||||||
|
for (; pte < 512; pte++)
|
||||||
|
{
|
||||||
|
if (pdpte == e_pdpte && pde == e_pde && pte > e_pte)
|
||||||
|
break;
|
||||||
|
if (pt[pte] & Flags::Used)
|
||||||
|
continue;
|
||||||
|
vaddr_t vaddr = 0;
|
||||||
|
vaddr |= (vaddr_t)pdpte << 30;
|
||||||
|
vaddr |= (vaddr_t)pde << 21;
|
||||||
|
vaddr |= (vaddr_t)pte << 12;
|
||||||
|
ASSERT(reserve_page(vaddr));
|
||||||
|
return vaddr;
|
||||||
|
}
|
||||||
|
pte = 0;
|
||||||
|
}
|
||||||
|
pde = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find any free page
|
||||||
|
for (vaddr_t vaddr = first_address; vaddr < last_address; vaddr += PAGE_SIZE)
|
||||||
|
{
|
||||||
|
if (is_page_free(vaddr))
|
||||||
|
{
|
||||||
|
ASSERT(reserve_page(vaddr));
|
||||||
|
return vaddr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
vaddr_t PageTable::reserve_free_contiguous_pages(size_t page_count, vaddr_t first_address, vaddr_t last_address)
|
||||||
|
{
|
||||||
|
if (first_address >= KERNEL_OFFSET && first_address < (vaddr_t)g_kernel_start)
|
||||||
|
first_address = (vaddr_t)g_kernel_start;
|
||||||
|
if (size_t rem = first_address % PAGE_SIZE)
|
||||||
|
first_address += PAGE_SIZE - rem;
|
||||||
|
if (size_t rem = last_address % PAGE_SIZE)
|
||||||
|
last_address -= rem;
|
||||||
|
|
||||||
|
SpinLockGuard _(m_lock);
|
||||||
|
|
||||||
|
for (vaddr_t vaddr = first_address; vaddr < last_address;)
|
||||||
|
{
|
||||||
|
bool valid { true };
|
||||||
|
for (size_t page = 0; page < page_count; page++)
|
||||||
|
{
|
||||||
|
if (!is_page_free(vaddr + page * PAGE_SIZE))
|
||||||
|
{
|
||||||
|
vaddr += (page + 1) * PAGE_SIZE;
|
||||||
|
valid = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (valid)
|
||||||
|
{
|
||||||
|
ASSERT(reserve_range(vaddr, page_count * PAGE_SIZE));
|
||||||
|
return vaddr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dump_range(vaddr_t start, vaddr_t end, PageTable::flags_t flags)
|
||||||
|
{
|
||||||
|
if (start == 0)
|
||||||
|
return;
|
||||||
|
dprintln("{}-{}: {}{}{}{}",
|
||||||
|
(void*)(start), (void*)(end - 1),
|
||||||
|
flags & PageTable::Flags::Execute ? 'x' : '-',
|
||||||
|
flags & PageTable::Flags::UserSupervisor ? 'u' : '-',
|
||||||
|
flags & PageTable::Flags::ReadWrite ? 'w' : '-',
|
||||||
|
flags & PageTable::Flags::Present ? 'r' : '-'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PageTable::debug_dump()
|
||||||
|
{
|
||||||
|
SpinLockGuard _(m_lock);
|
||||||
|
|
||||||
|
flags_t flags = 0;
|
||||||
|
vaddr_t start = 0;
|
||||||
|
|
||||||
|
const uint64_t* pdpt = P2V(m_highest_paging_struct);
|
||||||
|
for (uint32_t pdpte = 0; pdpte < 4; pdpte++)
|
||||||
|
{
|
||||||
|
if (!(pdpt[pdpte] & Flags::Present))
|
||||||
|
{
|
||||||
|
dump_range(start, (pdpte << 30), flags);
|
||||||
|
start = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const uint64_t* pd = P2V(pdpt[pdpte] & s_page_addr_mask);
|
||||||
|
for (uint64_t pde = 0; pde < 512; pde++)
|
||||||
|
{
|
||||||
|
if (!(pd[pde] & Flags::Present))
|
||||||
|
{
|
||||||
|
dump_range(start, (pdpte << 30) | (pde << 21), flags);
|
||||||
|
start = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const uint64_t* pt = P2V(pd[pde] & s_page_addr_mask);
|
||||||
|
for (uint64_t pte = 0; pte < 512; pte++)
|
||||||
|
{
|
||||||
|
if (parse_flags(pt[pte]) != flags)
|
||||||
|
{
|
||||||
|
dump_range(start, (pdpte << 30) | (pde << 21) | (pte << 12), flags);
|
||||||
|
start = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(pt[pte] & Flags::Used))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (start == 0)
|
||||||
|
{
|
||||||
|
flags = parse_flags(pt[pte]);
|
||||||
|
start = (pdpte << 30) | (pde << 21) | (pte << 12);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
86
kernel/arch/i686/Signal.S
Normal file
86
kernel/arch/i686/Signal.S
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
.section .userspace, "ax"
|
||||||
|
|
||||||
|
// stack contains
|
||||||
|
// (4 bytes) return address (on return stack)
|
||||||
|
// (4 bytes) return stack
|
||||||
|
// (4 bytes) return rflags
|
||||||
|
// (8 bytes) restore sigmask
|
||||||
|
// (36 bytes) siginfo_t
|
||||||
|
// (4 bytes) signal number
|
||||||
|
// (4 bytes) signal handler
|
||||||
|
|
||||||
|
.global signal_trampoline
|
||||||
|
signal_trampoline:
|
||||||
|
pushl %esi // gregs
|
||||||
|
pushl %edi
|
||||||
|
pushl %edx
|
||||||
|
pushl %ecx
|
||||||
|
pushl %ebx
|
||||||
|
pushl %eax
|
||||||
|
pushl %ebp
|
||||||
|
|
||||||
|
movl 84(%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
|
||||||
|
andl $-16, %esp
|
||||||
|
|
||||||
|
subl $512, %esp
|
||||||
|
fxsave (%esp)
|
||||||
|
|
||||||
|
subl $4, %esp
|
||||||
|
pushl %edx
|
||||||
|
pushl %esi
|
||||||
|
pushl %edi
|
||||||
|
call *%eax
|
||||||
|
addl $16, %esp
|
||||||
|
|
||||||
|
fxrstor (%esp)
|
||||||
|
addl $512, %esp
|
||||||
|
|
||||||
|
// 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
|
||||||
|
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
|
||||||
81
kernel/arch/i686/Syscall.S
Normal file
81
kernel/arch/i686/Syscall.S
Normal file
@@ -0,0 +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
|
||||||
|
sys_fork_trampoline:
|
||||||
|
pushl %ebp
|
||||||
|
pushl %ebx
|
||||||
|
pushl %esi
|
||||||
|
pushl %edi
|
||||||
|
|
||||||
|
call read_ip
|
||||||
|
testl %eax, %eax
|
||||||
|
jz .done
|
||||||
|
|
||||||
|
movl %esp, %ebx
|
||||||
|
|
||||||
|
subl $8, %esp
|
||||||
|
pushl %eax
|
||||||
|
pushl %ebx
|
||||||
|
call sys_fork
|
||||||
|
addl $16, %esp
|
||||||
|
|
||||||
|
.done:
|
||||||
|
popl %edi
|
||||||
|
popl %esi
|
||||||
|
popl %ebx
|
||||||
|
popl %ebp
|
||||||
|
ret
|
||||||
42
kernel/arch/i686/Thread.S
Normal file
42
kernel/arch/i686/Thread.S
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
# uint32_t read_ip()
|
||||||
|
.global read_ip
|
||||||
|
read_ip:
|
||||||
|
popl %eax
|
||||||
|
jmp *%eax
|
||||||
|
|
||||||
|
# void start_kernel_thread()
|
||||||
|
.global start_kernel_thread
|
||||||
|
start_kernel_thread:
|
||||||
|
# STACK LAYOUT
|
||||||
|
# on_exit arg
|
||||||
|
# on_exit func
|
||||||
|
# entry arg
|
||||||
|
# entry func
|
||||||
|
|
||||||
|
movl 4(%esp), %edi
|
||||||
|
movl 0(%esp), %esi
|
||||||
|
|
||||||
|
subl $12, %esp
|
||||||
|
pushl %edi
|
||||||
|
sti
|
||||||
|
call *%esi
|
||||||
|
addl $16, %esp
|
||||||
|
|
||||||
|
movl 12(%esp), %edi
|
||||||
|
movl 8(%esp), %esi
|
||||||
|
|
||||||
|
subl $12, %esp
|
||||||
|
pushl %edi
|
||||||
|
call *%esi
|
||||||
|
|
||||||
|
.global start_userspace_thread
|
||||||
|
start_userspace_thread:
|
||||||
|
movw $(0x20 | 3), %bx
|
||||||
|
movw %bx, %ds
|
||||||
|
movw %bx, %es
|
||||||
|
movw $(0x30 | 3), %bx
|
||||||
|
movw %bx, %fs
|
||||||
|
movw $(0x38 | 3), %bx
|
||||||
|
movw %bx, %gs
|
||||||
|
|
||||||
|
iret
|
||||||
54
kernel/arch/i686/User.S
Normal file
54
kernel/arch/i686/User.S
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
# bool safe_user_memcpy(void*, const void*, size_t)
|
||||||
|
.global safe_user_memcpy
|
||||||
|
.global safe_user_memcpy_end
|
||||||
|
.global safe_user_memcpy_fault
|
||||||
|
safe_user_memcpy:
|
||||||
|
xorl %eax, %eax
|
||||||
|
xchgl 4(%esp), %edi
|
||||||
|
xchgl 8(%esp), %esi
|
||||||
|
movl 12(%esp), %ecx
|
||||||
|
movl %edi, %edx
|
||||||
|
rep movsb
|
||||||
|
movl 4(%esp), %edi
|
||||||
|
movl 8(%esp), %esi
|
||||||
|
incl %eax
|
||||||
|
safe_user_memcpy_fault:
|
||||||
|
ret
|
||||||
|
safe_user_memcpy_end:
|
||||||
|
|
||||||
|
# bool safe_user_strncpy(void*, const void*, size_t)
|
||||||
|
.global safe_user_strncpy
|
||||||
|
.global safe_user_strncpy_end
|
||||||
|
.global safe_user_strncpy_fault
|
||||||
|
safe_user_strncpy:
|
||||||
|
xchgl 4(%esp), %edi
|
||||||
|
xchgl 8(%esp), %esi
|
||||||
|
movl 12(%esp), %ecx
|
||||||
|
|
||||||
|
testl %ecx, %ecx
|
||||||
|
jz safe_user_strncpy_fault
|
||||||
|
|
||||||
|
.safe_user_strncpy_loop:
|
||||||
|
movb (%esi), %al
|
||||||
|
movb %al, (%edi)
|
||||||
|
testb %al, %al
|
||||||
|
jz .safe_user_strncpy_done
|
||||||
|
|
||||||
|
incl %edi
|
||||||
|
incl %esi
|
||||||
|
decl %ecx
|
||||||
|
jnz .safe_user_strncpy_loop
|
||||||
|
|
||||||
|
safe_user_strncpy_fault:
|
||||||
|
xorl %eax, %eax
|
||||||
|
jmp .safe_user_strncpy_return
|
||||||
|
|
||||||
|
.safe_user_strncpy_done:
|
||||||
|
movl $1, %eax
|
||||||
|
|
||||||
|
.safe_user_strncpy_return:
|
||||||
|
movl 4(%esp), %edi
|
||||||
|
movl 8(%esp), %esi
|
||||||
|
ret
|
||||||
|
|
||||||
|
safe_user_strncpy_end:
|
||||||
25
kernel/arch/i686/Yield.S
Normal file
25
kernel/arch/i686/Yield.S
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
.global asm_yield_trampoline
|
||||||
|
asm_yield_trampoline:
|
||||||
|
leal 4(%esp), %ecx
|
||||||
|
movl 4(%esp), %esp
|
||||||
|
|
||||||
|
pushl -4(%ecx)
|
||||||
|
pushl %ecx
|
||||||
|
pushl %eax
|
||||||
|
pushl %ebx
|
||||||
|
pushl %esi
|
||||||
|
pushl %edi
|
||||||
|
pushl %ebp
|
||||||
|
|
||||||
|
pushl %esp
|
||||||
|
call scheduler_on_yield
|
||||||
|
addl $4, %esp
|
||||||
|
|
||||||
|
popl %ebp
|
||||||
|
popl %edi
|
||||||
|
popl %esi
|
||||||
|
popl %ebx
|
||||||
|
popl %eax
|
||||||
|
movl 4(%esp), %ecx
|
||||||
|
movl 0(%esp), %esp
|
||||||
|
jmp *%ecx
|
||||||
360
kernel/arch/i686/boot.S
Normal file
360
kernel/arch/i686/boot.S
Normal file
@@ -0,0 +1,360 @@
|
|||||||
|
.set PG_PRESENT, 1<<0
|
||||||
|
.set PG_READ_WRITE, 1<<1
|
||||||
|
.set PG_PAGE_SIZE, 1<<7
|
||||||
|
|
||||||
|
.set FB_WIDTH, 800
|
||||||
|
.set FB_HEIGHT, 600
|
||||||
|
.set FB_BPP, 32
|
||||||
|
|
||||||
|
#define KERNEL_OFFSET 0xC0000000
|
||||||
|
#define V2P(vaddr) ((vaddr) - KERNEL_OFFSET)
|
||||||
|
|
||||||
|
.code32
|
||||||
|
|
||||||
|
// video mode info, page align modules
|
||||||
|
.set multiboot_flags, (1 << 2) | (1 << 0)
|
||||||
|
|
||||||
|
.section .multiboot, "aw"
|
||||||
|
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:
|
||||||
|
.long 0xE85250D6
|
||||||
|
.long 0
|
||||||
|
.long multiboot2_end - multiboot2_start
|
||||||
|
.long -(0xE85250D6 + (multiboot2_end - multiboot2_start))
|
||||||
|
|
||||||
|
# framebuffer tag
|
||||||
|
.align 8
|
||||||
|
.short 5
|
||||||
|
.short 0
|
||||||
|
.long 20
|
||||||
|
.long FB_WIDTH
|
||||||
|
.long FB_HEIGHT
|
||||||
|
.long FB_BPP
|
||||||
|
|
||||||
|
# legacy start
|
||||||
|
.align 8
|
||||||
|
.short 3
|
||||||
|
.short 0
|
||||||
|
.long 12
|
||||||
|
.long V2P(_start)
|
||||||
|
|
||||||
|
# page align modules
|
||||||
|
.align 8
|
||||||
|
.short 6
|
||||||
|
.short 0
|
||||||
|
.long 8
|
||||||
|
|
||||||
|
.align 8
|
||||||
|
.short 0
|
||||||
|
.short 0
|
||||||
|
.long 8
|
||||||
|
multiboot2_end:
|
||||||
|
|
||||||
|
.section .bananboot, "aw"
|
||||||
|
bananboot_start:
|
||||||
|
.long 0xBABAB007
|
||||||
|
.long -(0xBABAB007 + FB_WIDTH + FB_HEIGHT + FB_BPP)
|
||||||
|
.long FB_WIDTH
|
||||||
|
.long FB_HEIGHT
|
||||||
|
.long FB_BPP
|
||||||
|
bananboot_end:
|
||||||
|
|
||||||
|
.section .bss, "aw", @nobits
|
||||||
|
.global g_boot_stack_top
|
||||||
|
g_boot_stack_bottom:
|
||||||
|
.skip 4096 * 4
|
||||||
|
g_boot_stack_top:
|
||||||
|
|
||||||
|
.global g_kernel_cmdline
|
||||||
|
g_kernel_cmdline:
|
||||||
|
.skip 4096
|
||||||
|
|
||||||
|
bootloader_magic:
|
||||||
|
.skip 8
|
||||||
|
bootloader_info:
|
||||||
|
.skip 8
|
||||||
|
|
||||||
|
.section .data
|
||||||
|
|
||||||
|
# Map first GiB to 0x00000000 and 0xC0000000
|
||||||
|
.align 32
|
||||||
|
boot_pdpt:
|
||||||
|
.long V2P(boot_pd) + (PG_PRESENT)
|
||||||
|
.long 0
|
||||||
|
.skip 2 * 8
|
||||||
|
.long V2P(boot_pd) + (PG_PRESENT)
|
||||||
|
.long 0
|
||||||
|
.align 4096
|
||||||
|
boot_pd:
|
||||||
|
.set i, 0
|
||||||
|
.rept 512
|
||||||
|
.long V2P(boot_pts) + i + (PG_READ_WRITE | PG_PRESENT)
|
||||||
|
.long 0
|
||||||
|
.set i, i + 0x1000
|
||||||
|
.endr
|
||||||
|
boot_pts:
|
||||||
|
.set i, 0
|
||||||
|
.rept 511
|
||||||
|
.rept 512
|
||||||
|
.long i + (PG_READ_WRITE | PG_PRESENT)
|
||||||
|
.long 0
|
||||||
|
.set i, i + 0x1000
|
||||||
|
.endr
|
||||||
|
.endr
|
||||||
|
.global g_boot_fast_page_pt
|
||||||
|
g_boot_fast_page_pt:
|
||||||
|
.skip 512 * 8
|
||||||
|
|
||||||
|
boot_gdt:
|
||||||
|
.quad 0x0000000000000000 # null descriptor
|
||||||
|
.quad 0x00CF9A000000FFFF # kernel code
|
||||||
|
.quad 0x00CF92000000FFFF # kernel data
|
||||||
|
boot_gdtr:
|
||||||
|
.short . - boot_gdt - 1
|
||||||
|
.long V2P(boot_gdt)
|
||||||
|
|
||||||
|
.global g_ap_startup_done
|
||||||
|
g_ap_startup_done:
|
||||||
|
.byte 0
|
||||||
|
.global g_ap_running_count
|
||||||
|
g_ap_running_count:
|
||||||
|
.byte 0
|
||||||
|
.global g_ap_stack_loaded
|
||||||
|
g_ap_stack_loaded:
|
||||||
|
.byte 0
|
||||||
|
|
||||||
|
.section .text
|
||||||
|
|
||||||
|
has_cpuid:
|
||||||
|
pushfl
|
||||||
|
pushfl
|
||||||
|
xorl $0x00200000, (%esp)
|
||||||
|
popfl
|
||||||
|
pushfl
|
||||||
|
popl %eax
|
||||||
|
xorl (%esp), %eax
|
||||||
|
popfl
|
||||||
|
testl $0x00200000, %eax
|
||||||
|
ret
|
||||||
|
|
||||||
|
has_pae:
|
||||||
|
movl $0, %eax
|
||||||
|
cpuid
|
||||||
|
testl $(1 << 6), %edx
|
||||||
|
ret
|
||||||
|
|
||||||
|
has_sse:
|
||||||
|
movl $1, %eax
|
||||||
|
cpuid
|
||||||
|
testl $(1 << 25), %edx
|
||||||
|
ret
|
||||||
|
|
||||||
|
check_requirements:
|
||||||
|
call has_cpuid
|
||||||
|
jz .exit
|
||||||
|
call has_pae
|
||||||
|
jz .exit
|
||||||
|
call has_sse
|
||||||
|
jz .exit
|
||||||
|
ret
|
||||||
|
.exit:
|
||||||
|
jmp system_halt
|
||||||
|
|
||||||
|
enable_sse:
|
||||||
|
movl %cr0, %eax
|
||||||
|
andw $0xFFFB, %ax
|
||||||
|
orw $0x0002, %ax
|
||||||
|
movl %eax, %cr0
|
||||||
|
movl %cr4, %eax
|
||||||
|
orw $0x0600, %ax
|
||||||
|
movl %eax, %cr4
|
||||||
|
ret
|
||||||
|
|
||||||
|
enable_tsc:
|
||||||
|
# allow userspace to use RDTSC
|
||||||
|
movl %cr4, %ecx
|
||||||
|
andl $0xFFFFFFFB, %ecx
|
||||||
|
movl %ecx, %cr4
|
||||||
|
ret
|
||||||
|
|
||||||
|
initialize_paging:
|
||||||
|
# enable PAE
|
||||||
|
movl %cr4, %ecx
|
||||||
|
orl $(1 << 5), %ecx
|
||||||
|
movl %ecx, %cr4
|
||||||
|
|
||||||
|
# load page tables
|
||||||
|
movl $V2P(boot_pdpt), %ecx
|
||||||
|
movl %ecx, %cr3
|
||||||
|
|
||||||
|
# enable paging
|
||||||
|
movl %cr0, %ecx
|
||||||
|
orl $(1 << 31), %ecx
|
||||||
|
movl %ecx, %cr0
|
||||||
|
|
||||||
|
ret
|
||||||
|
|
||||||
|
.global _start
|
||||||
|
.type _start, @function
|
||||||
|
_start:
|
||||||
|
cli; cld
|
||||||
|
|
||||||
|
# save bootloader magic and info
|
||||||
|
movl %eax, V2P(bootloader_magic)
|
||||||
|
movl %ebx, V2P(bootloader_info)
|
||||||
|
|
||||||
|
# load boot stack
|
||||||
|
movl $V2P(g_boot_stack_top), %esp
|
||||||
|
|
||||||
|
# load boot GDT
|
||||||
|
lgdt V2P(boot_gdtr)
|
||||||
|
ljmpl $0x08, $V2P(gdt_flush)
|
||||||
|
gdt_flush:
|
||||||
|
# set correct segment registers
|
||||||
|
movw $0x10, %ax
|
||||||
|
movw %ax, %ds
|
||||||
|
movw %ax, %ss
|
||||||
|
movw %ax, %es
|
||||||
|
|
||||||
|
# do processor initialization
|
||||||
|
call check_requirements
|
||||||
|
call enable_sse
|
||||||
|
call enable_tsc
|
||||||
|
call initialize_paging
|
||||||
|
|
||||||
|
# load higher half stack pointer
|
||||||
|
movl $g_boot_stack_top, %esp
|
||||||
|
|
||||||
|
# jump to higher half
|
||||||
|
leal higher_half, %ecx
|
||||||
|
jmp *%ecx
|
||||||
|
|
||||||
|
higher_half:
|
||||||
|
# call global constuctors
|
||||||
|
call _init
|
||||||
|
|
||||||
|
movl $g_init_array_start, %ebx
|
||||||
|
jmp 2f
|
||||||
|
1: call *(%ebx)
|
||||||
|
addl $4, %ebx
|
||||||
|
2: cmpl $g_init_array_end, %ebx
|
||||||
|
jne 1b
|
||||||
|
|
||||||
|
# call to the kernel itself (clear ebp for stacktrace)
|
||||||
|
xorl %ebp, %ebp
|
||||||
|
|
||||||
|
subl $8, %esp
|
||||||
|
pushl bootloader_info
|
||||||
|
pushl bootloader_magic
|
||||||
|
call kernel_main
|
||||||
|
addl $16, %esp
|
||||||
|
|
||||||
|
# call global destructors
|
||||||
|
call _fini
|
||||||
|
|
||||||
|
system_halt:
|
||||||
|
xchgw %bx, %bx
|
||||||
|
cli
|
||||||
|
1: hlt
|
||||||
|
jmp 1b
|
||||||
|
|
||||||
|
|
||||||
|
#define AP_REL(vaddr) ((vaddr) - ap_trampoline + 0xF000)
|
||||||
|
|
||||||
|
.section .ap_init, "ax"
|
||||||
|
|
||||||
|
.code16
|
||||||
|
.global ap_trampoline
|
||||||
|
ap_trampoline:
|
||||||
|
jmp 1f
|
||||||
|
|
||||||
|
.align 8
|
||||||
|
ap_stack_paddr:
|
||||||
|
.skip 4
|
||||||
|
ap_stack_vaddr:
|
||||||
|
.skip 4
|
||||||
|
ap_prepare_paging:
|
||||||
|
.skip 4
|
||||||
|
ap_page_table:
|
||||||
|
.skip 4
|
||||||
|
ap_ready:
|
||||||
|
.skip 4
|
||||||
|
|
||||||
|
1: cli; cld
|
||||||
|
ljmpl $0x00, $AP_REL(ap_cs_clear)
|
||||||
|
|
||||||
|
ap_cs_clear:
|
||||||
|
# load ap gdt and enter protected mode
|
||||||
|
lgdt AP_REL(ap_gdtr)
|
||||||
|
movl %cr0, %eax
|
||||||
|
orb $1, %al
|
||||||
|
movl %eax, %cr0
|
||||||
|
ljmpl $0x08, $AP_REL(ap_protected_mode)
|
||||||
|
|
||||||
|
.code32
|
||||||
|
ap_protected_mode:
|
||||||
|
movw $0x10, %ax
|
||||||
|
movw %ax, %ds
|
||||||
|
movw %ax, %ss
|
||||||
|
movw %ax, %es
|
||||||
|
|
||||||
|
movl AP_REL(ap_stack_paddr), %esp
|
||||||
|
|
||||||
|
leal V2P(enable_sse), %ecx; call *%ecx
|
||||||
|
leal V2P(enable_tsc), %ecx; call *%ecx
|
||||||
|
leal V2P(initialize_paging), %ecx; call *%ecx
|
||||||
|
|
||||||
|
# load boot gdt and enter long mode
|
||||||
|
lgdt V2P(boot_gdtr)
|
||||||
|
ljmpl $0x08, $AP_REL(ap_flush_gdt)
|
||||||
|
|
||||||
|
ap_flush_gdt:
|
||||||
|
movl $ap_higher_half, %ecx
|
||||||
|
jmp *%ecx
|
||||||
|
|
||||||
|
ap_higher_half:
|
||||||
|
movl AP_REL(ap_prepare_paging), %eax
|
||||||
|
call *%eax
|
||||||
|
|
||||||
|
# load AP's initial values
|
||||||
|
movl AP_REL(ap_stack_vaddr), %esp
|
||||||
|
movl AP_REL(ap_page_table), %eax
|
||||||
|
movl $1, AP_REL(ap_ready)
|
||||||
|
movl %eax, %cr3
|
||||||
|
|
||||||
|
# clear rbp for stacktrace
|
||||||
|
xorl %ebp, %ebp
|
||||||
|
|
||||||
|
1: pause
|
||||||
|
cmpb $0, g_ap_startup_done
|
||||||
|
je 1b
|
||||||
|
|
||||||
|
lock incb g_ap_running_count
|
||||||
|
|
||||||
|
call ap_main
|
||||||
|
jmp system_halt
|
||||||
|
|
||||||
|
ap_gdt:
|
||||||
|
.quad 0x0000000000000000 # null descriptor
|
||||||
|
.quad 0x00CF9A000000FFFF # 32 bit code
|
||||||
|
.quad 0x00CF92000000FFFF # 32 bit data
|
||||||
|
ap_gdtr:
|
||||||
|
.short . - ap_gdt - 1
|
||||||
|
.long ap_gdt
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
/* x86 crti.s */
|
/* i686 crti.s */
|
||||||
.section .init
|
.section .init
|
||||||
.global _init
|
.global _init
|
||||||
.type _init, @function
|
.type _init, @function
|
||||||
_init:
|
_init:
|
||||||
push %ebp
|
pushl %ebp
|
||||||
movl %esp, %ebp
|
movl %esp, %ebp
|
||||||
/* gcc will nicely put the contents of crtbegin.o's .init section here. */
|
/* gcc will nicely put the contents of crtbegin.o's .init section here. */
|
||||||
|
|
||||||
@@ -11,6 +11,6 @@ _init:
|
|||||||
.global _fini
|
.global _fini
|
||||||
.type _fini, @function
|
.type _fini, @function
|
||||||
_fini:
|
_fini:
|
||||||
push %ebp
|
pushl %ebp
|
||||||
movl %esp, %ebp
|
movl %esp, %ebp
|
||||||
/* gcc will nicely put the contents of crtbegin.o's .fini section here. */
|
/* gcc will nicely put the contents of crtbegin.o's .fini section here. */
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
/* x86 crtn.s */
|
/* i686 crtn.s */
|
||||||
.section .init
|
.section .init
|
||||||
/* gcc will nicely put the contents of crtend.o's .init section here. */
|
/* gcc will nicely put the contents of crtend.o's .init section here. */
|
||||||
popl %ebp
|
popl %ebp
|
||||||
185
kernel/arch/i686/interrupts.S
Normal file
185
kernel/arch/i686/interrupts.S
Normal file
@@ -0,0 +1,185 @@
|
|||||||
|
.macro intr_header, n
|
||||||
|
pushal
|
||||||
|
testb $3, \n+8*4(%esp)
|
||||||
|
jz 1f
|
||||||
|
movw $0x10, %ax
|
||||||
|
movw %ax, %ds
|
||||||
|
movw %ax, %es
|
||||||
|
movw %ax, %fs
|
||||||
|
movw $0x28, %ax
|
||||||
|
movw %ax, %gs
|
||||||
|
1: cld
|
||||||
|
.endm
|
||||||
|
|
||||||
|
.macro intr_footer, n
|
||||||
|
testb $3, \n+8*4(%esp)
|
||||||
|
jz 1f
|
||||||
|
call cpp_check_signal
|
||||||
|
movw $(0x20 | 3), %bx
|
||||||
|
movw %bx, %ds
|
||||||
|
movw %bx, %es
|
||||||
|
movw $(0x30 | 3), %bx
|
||||||
|
movw %bx, %fs
|
||||||
|
movw $(0x38 | 3), %bx
|
||||||
|
movw %bx, %gs
|
||||||
|
1: popal
|
||||||
|
.endm
|
||||||
|
|
||||||
|
isr_stub:
|
||||||
|
intr_header 12
|
||||||
|
movl %cr0, %eax; pushl %eax
|
||||||
|
movl %cr2, %eax; pushl %eax
|
||||||
|
movl %cr3, %eax; pushl %eax
|
||||||
|
movl %cr4, %eax; pushl %eax
|
||||||
|
|
||||||
|
movl 48(%esp), %edi // isr number
|
||||||
|
movl 52(%esp), %esi // error code
|
||||||
|
leal 56(%esp), %edx // interrupt stack ptr
|
||||||
|
movl %esp, %ecx // register ptr
|
||||||
|
|
||||||
|
# stack frame for stack trace
|
||||||
|
leal 56(%esp), %eax
|
||||||
|
pushl (%eax)
|
||||||
|
pushl %ebp
|
||||||
|
|
||||||
|
movl %esp, %ebp
|
||||||
|
andl $-16, %esp
|
||||||
|
|
||||||
|
pushl %ecx
|
||||||
|
pushl %edx
|
||||||
|
pushl %esi
|
||||||
|
pushl %edi
|
||||||
|
call cpp_isr_handler
|
||||||
|
|
||||||
|
movl %ebp, %esp
|
||||||
|
addl $24, %esp
|
||||||
|
|
||||||
|
intr_footer 12
|
||||||
|
addl $8, %esp
|
||||||
|
iret
|
||||||
|
|
||||||
|
irq_stub:
|
||||||
|
intr_header 12
|
||||||
|
|
||||||
|
movl 32(%esp), %edi # interrupt number
|
||||||
|
|
||||||
|
movl %esp, %ebp
|
||||||
|
andl $-16, %esp
|
||||||
|
|
||||||
|
subl $12, %esp
|
||||||
|
pushl %edi
|
||||||
|
call cpp_irq_handler
|
||||||
|
|
||||||
|
movl %ebp, %esp
|
||||||
|
|
||||||
|
intr_footer 12
|
||||||
|
addl $8, %esp
|
||||||
|
iret
|
||||||
|
|
||||||
|
.global asm_ipi_handler
|
||||||
|
asm_ipi_handler:
|
||||||
|
intr_header 4
|
||||||
|
|
||||||
|
movl %esp, %ebp
|
||||||
|
andl $-16, %esp
|
||||||
|
|
||||||
|
call cpp_ipi_handler
|
||||||
|
|
||||||
|
movl %ebp, %esp
|
||||||
|
|
||||||
|
intr_footer 4
|
||||||
|
iret
|
||||||
|
|
||||||
|
.global asm_timer_handler
|
||||||
|
asm_timer_handler:
|
||||||
|
intr_header 4
|
||||||
|
|
||||||
|
movl %esp, %ebp
|
||||||
|
andl $-16, %esp
|
||||||
|
|
||||||
|
call cpp_timer_handler
|
||||||
|
|
||||||
|
movl %ebp, %esp
|
||||||
|
|
||||||
|
intr_footer 4
|
||||||
|
iret
|
||||||
|
|
||||||
|
.macro isr n
|
||||||
|
.global isr\n
|
||||||
|
isr\n:
|
||||||
|
pushl $0
|
||||||
|
pushl $\n
|
||||||
|
jmp isr_stub
|
||||||
|
.endm
|
||||||
|
|
||||||
|
.macro isr_err n
|
||||||
|
.global isr\n
|
||||||
|
isr\n:
|
||||||
|
pushl $\n
|
||||||
|
jmp isr_stub
|
||||||
|
.endm
|
||||||
|
|
||||||
|
.macro irq n
|
||||||
|
.global irq\n
|
||||||
|
irq\n:
|
||||||
|
pushl $0
|
||||||
|
pushl $\n
|
||||||
|
jmp irq_stub
|
||||||
|
.endm
|
||||||
|
|
||||||
|
isr 0
|
||||||
|
isr 1
|
||||||
|
isr 2
|
||||||
|
isr 3
|
||||||
|
isr 4
|
||||||
|
isr 5
|
||||||
|
isr 6
|
||||||
|
isr 7
|
||||||
|
isr_err 8
|
||||||
|
isr 9
|
||||||
|
isr_err 10
|
||||||
|
isr_err 11
|
||||||
|
isr_err 12
|
||||||
|
isr_err 13
|
||||||
|
isr_err 14
|
||||||
|
isr 15
|
||||||
|
isr 16
|
||||||
|
isr_err 17
|
||||||
|
isr 18
|
||||||
|
isr 19
|
||||||
|
isr 20
|
||||||
|
isr 21
|
||||||
|
isr 22
|
||||||
|
isr 23
|
||||||
|
isr 24
|
||||||
|
isr 25
|
||||||
|
isr 26
|
||||||
|
isr 27
|
||||||
|
isr 28
|
||||||
|
isr 29
|
||||||
|
isr 30
|
||||||
|
isr 31
|
||||||
|
|
||||||
|
.irp i, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, \
|
||||||
|
10, 11, 12, 13, 14, 15, 16, 17, 18, 19, \
|
||||||
|
20, 21, 22, 23, 24, 25, 26, 27, 28, 29, \
|
||||||
|
30, 31, 32, 33, 34, 35, 36, 37, 38, 39, \
|
||||||
|
40, 41, 42, 43, 44, 45, 46, 47, 48, 49, \
|
||||||
|
50, 51, 52, 53, 54, 55, 56, 57, 58, 59, \
|
||||||
|
60, 61, 62, 63, 64, 65, 66, 67, 68, 69, \
|
||||||
|
70, 71, 72, 73, 74, 75, 76, 77, 78, 79, \
|
||||||
|
80, 81, 82, 83, 84, 85, 86, 87, 88, 89, \
|
||||||
|
90, 91, 92, 93, 94, 95, 96, 97, 98, 99, \
|
||||||
|
100,101,102,103,104,105,106,107,108,109, \
|
||||||
|
110,111,112,113,114,115,116,117,118,119, \
|
||||||
|
120,121,122,123,124,125,126,127,128,129, \
|
||||||
|
130,131,132,133,134,135,136,137,138,139, \
|
||||||
|
140,141,142,143,144,145,146,147,148,149, \
|
||||||
|
150,151,152,153,154,155,156,157,158,159, \
|
||||||
|
160,161,162,163,164,165,166,167,168,169, \
|
||||||
|
170,171,172,173,174,175,176,177,178,179, \
|
||||||
|
180,181,182,183,184,185,186,187,188,189, \
|
||||||
|
190,191,192,193,194,195,196,197,198,199, \
|
||||||
|
200,201,202,203,204,205,206,207
|
||||||
|
irq \i
|
||||||
|
.endr
|
||||||
52
kernel/arch/i686/linker.ld
Normal file
52
kernel/arch/i686/linker.ld
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
ENTRY (_start)
|
||||||
|
|
||||||
|
KERNEL_OFFSET = 0xC0000000;
|
||||||
|
|
||||||
|
SECTIONS
|
||||||
|
{
|
||||||
|
. = 0x00100000 + KERNEL_OFFSET;
|
||||||
|
|
||||||
|
g_kernel_start = .;
|
||||||
|
.text ALIGN(4K) : AT(ADDR(.text) - KERNEL_OFFSET)
|
||||||
|
{
|
||||||
|
g_kernel_execute_start = .;
|
||||||
|
*(.multiboot)
|
||||||
|
*(.multiboot2)
|
||||||
|
*(.bananboot)
|
||||||
|
*(.text.*)
|
||||||
|
}
|
||||||
|
.ap_init ALIGN(4K) : AT(ADDR(.ap_init) - KERNEL_OFFSET)
|
||||||
|
{
|
||||||
|
g_ap_init_addr = .;
|
||||||
|
*(.ap_init)
|
||||||
|
g_kernel_execute_end = .;
|
||||||
|
}
|
||||||
|
.userspace ALIGN(4K) : AT(ADDR(.userspace) - KERNEL_OFFSET)
|
||||||
|
{
|
||||||
|
g_userspace_start = .;
|
||||||
|
*(.userspace)
|
||||||
|
g_userspace_end = .;
|
||||||
|
}
|
||||||
|
.rodata ALIGN(4K) : AT(ADDR(.rodata) - KERNEL_OFFSET)
|
||||||
|
{
|
||||||
|
*(.rodata.*)
|
||||||
|
}
|
||||||
|
.init_array ALIGN(4K) : AT(ADDR(.init_array) - KERNEL_OFFSET)
|
||||||
|
{
|
||||||
|
g_init_array_start = .;
|
||||||
|
*(.init_array)
|
||||||
|
g_init_array_end = .;
|
||||||
|
}
|
||||||
|
.data ALIGN(4K) : AT(ADDR(.data) - KERNEL_OFFSET)
|
||||||
|
{
|
||||||
|
g_kernel_writable_start = .;
|
||||||
|
*(.data)
|
||||||
|
}
|
||||||
|
.bss ALIGN(4K) : AT(ADDR(.bss) - KERNEL_OFFSET)
|
||||||
|
{
|
||||||
|
*(COMMON)
|
||||||
|
*(.bss)
|
||||||
|
g_kernel_writable_end = .;
|
||||||
|
}
|
||||||
|
g_kernel_end = .;
|
||||||
|
}
|
||||||
@@ -1,125 +0,0 @@
|
|||||||
#include <BAN/Array.h>
|
|
||||||
#include <kernel/GDT.h>
|
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
extern "C" uintptr_t g_boot_stack_top[0];
|
|
||||||
|
|
||||||
namespace Kernel::GDT
|
|
||||||
{
|
|
||||||
|
|
||||||
struct TaskStateSegment
|
|
||||||
{
|
|
||||||
uint32_t reserved1;
|
|
||||||
uint64_t rsp0;
|
|
||||||
uint64_t rsp1;
|
|
||||||
uint64_t rsp2;
|
|
||||||
uint64_t reserved2;
|
|
||||||
uint64_t ist1;
|
|
||||||
uint64_t ist2;
|
|
||||||
uint64_t ist3;
|
|
||||||
uint64_t ist4;
|
|
||||||
uint64_t ist5;
|
|
||||||
uint64_t ist6;
|
|
||||||
uint64_t ist7;
|
|
||||||
uint64_t reserved3;
|
|
||||||
uint16_t reserved4;
|
|
||||||
uint16_t iopb;
|
|
||||||
} __attribute__((packed));
|
|
||||||
|
|
||||||
union SegmentDescriptor
|
|
||||||
{
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
uint16_t limit1;
|
|
||||||
uint16_t base1;
|
|
||||||
uint8_t base2;
|
|
||||||
uint8_t access;
|
|
||||||
uint8_t limit2 : 4;
|
|
||||||
uint8_t flags : 4;
|
|
||||||
uint8_t base3;
|
|
||||||
} __attribute__((packed));
|
|
||||||
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
uint32_t low;
|
|
||||||
uint32_t high;
|
|
||||||
} __attribute__((packed));
|
|
||||||
|
|
||||||
} __attribute__((packed));
|
|
||||||
|
|
||||||
struct GDTR
|
|
||||||
{
|
|
||||||
uint16_t size;
|
|
||||||
uint64_t address;
|
|
||||||
} __attribute__((packed));
|
|
||||||
|
|
||||||
static constexpr uint16_t s_tss_offset = 0x28;
|
|
||||||
|
|
||||||
static TaskStateSegment s_tss;
|
|
||||||
static BAN::Array<SegmentDescriptor, 7> s_gdt; // null, kernel code, kernel data, user code, user data, tss low, tss high
|
|
||||||
static GDTR s_gdtr;
|
|
||||||
|
|
||||||
static void write_entry(uint8_t offset, uint32_t base, uint32_t limit, uint8_t access, uint8_t flags)
|
|
||||||
{
|
|
||||||
ASSERT(offset % sizeof(SegmentDescriptor) == 0);
|
|
||||||
|
|
||||||
SegmentDescriptor& desc = s_gdt[offset / sizeof(SegmentDescriptor)];
|
|
||||||
desc.base1 = (base >> 0) & 0xFFFF;
|
|
||||||
desc.base2 = (base >> 16) & 0xFF;
|
|
||||||
desc.base3 = (base >> 24) & 0xFF;
|
|
||||||
|
|
||||||
desc.limit1 = (limit >> 0) & 0xFFFF;
|
|
||||||
desc.limit2 = (limit >> 16) & 0x0F;
|
|
||||||
|
|
||||||
desc.access = access & 0xFF;
|
|
||||||
|
|
||||||
desc.flags = flags & 0x0F;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void write_tss()
|
|
||||||
{
|
|
||||||
memset(&s_tss, 0x00, sizeof(TaskStateSegment));
|
|
||||||
s_tss.iopb = sizeof(TaskStateSegment);
|
|
||||||
|
|
||||||
uint64_t base = (uint64_t)&s_tss;
|
|
||||||
|
|
||||||
write_entry(s_tss_offset, (uint32_t)base, sizeof(TaskStateSegment), 0x89, 0x0);
|
|
||||||
|
|
||||||
SegmentDescriptor& desc = s_gdt[s_tss_offset / sizeof(SegmentDescriptor) + 1];
|
|
||||||
desc.low = base >> 32;
|
|
||||||
desc.high = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void set_tss_stack(uintptr_t rsp)
|
|
||||||
{
|
|
||||||
s_tss.rsp0 = rsp;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void flush_gdt()
|
|
||||||
{
|
|
||||||
asm volatile("lgdt %0" :: "m"(s_gdtr));
|
|
||||||
}
|
|
||||||
|
|
||||||
static void flush_tss()
|
|
||||||
{
|
|
||||||
asm volatile("ltr %0" :: "m"(s_tss_offset));
|
|
||||||
}
|
|
||||||
|
|
||||||
void initialize()
|
|
||||||
{
|
|
||||||
s_gdtr.address = (uint64_t)&s_gdt;
|
|
||||||
s_gdtr.size = s_gdt.size() * sizeof(SegmentDescriptor) - 1;
|
|
||||||
|
|
||||||
write_entry(0x00, 0x00000000, 0x00000, 0x00, 0x0); // null
|
|
||||||
write_entry(0x08, 0x00000000, 0xFFFFF, 0x9A, 0xA); // kernel code
|
|
||||||
write_entry(0x10, 0x00000000, 0xFFFFF, 0x92, 0xC); // kernel data
|
|
||||||
write_entry(0x18, 0x00000000, 0xFFFFF, 0xFA, 0xA); // user code
|
|
||||||
write_entry(0x20, 0x00000000, 0xFFFFF, 0xF2, 0xC); // user data
|
|
||||||
write_tss();
|
|
||||||
|
|
||||||
flush_gdt();
|
|
||||||
flush_tss();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,409 +0,0 @@
|
|||||||
#include <BAN/Array.h>
|
|
||||||
#include <BAN/Errors.h>
|
|
||||||
#include <kernel/IDT.h>
|
|
||||||
#include <kernel/InterruptController.h>
|
|
||||||
#include <kernel/InterruptStack.h>
|
|
||||||
#include <kernel/Memory/kmalloc.h>
|
|
||||||
#include <kernel/Panic.h>
|
|
||||||
#include <kernel/Process.h>
|
|
||||||
#include <kernel/Scheduler.h>
|
|
||||||
#include <kernel/Timer/PIT.h>
|
|
||||||
|
|
||||||
#define ISR_LIST_X X(0) X(1) X(2) X(3) X(4) X(5) X(6) X(7) X(8) X(9) X(10) X(11) X(12) X(13) X(14) X(15) X(16) X(17) X(18) X(19) X(20) X(21) X(22) X(23) X(24) X(25) X(26) X(27) X(28) X(29) X(30) X(31)
|
|
||||||
#define IRQ_LIST_X X(0) X(1) X(2) X(3) X(4) X(5) X(6) X(7) X(8) X(9) X(10) X(11) X(12) X(13) X(14) X(15) X(16) X(17) X(18) X(19) X(20) X(21) X(22) X(23) X(24) X(25) X(26) X(27) X(28) X(29) X(30) X(31)
|
|
||||||
|
|
||||||
namespace Kernel::IDT
|
|
||||||
{
|
|
||||||
|
|
||||||
struct Registers
|
|
||||||
{
|
|
||||||
uint64_t rsp;
|
|
||||||
uint64_t rip;
|
|
||||||
uint64_t rflags;
|
|
||||||
uint64_t cr4;
|
|
||||||
uint64_t cr3;
|
|
||||||
uint64_t cr2;
|
|
||||||
uint64_t cr0;
|
|
||||||
|
|
||||||
uint64_t r15;
|
|
||||||
uint64_t r14;
|
|
||||||
uint64_t r13;
|
|
||||||
uint64_t r12;
|
|
||||||
uint64_t r11;
|
|
||||||
uint64_t r10;
|
|
||||||
uint64_t r9;
|
|
||||||
uint64_t r8;
|
|
||||||
uint64_t rsi;
|
|
||||||
uint64_t rdi;
|
|
||||||
uint64_t rbp;
|
|
||||||
uint64_t rdx;
|
|
||||||
uint64_t rcx;
|
|
||||||
uint64_t rbx;
|
|
||||||
uint64_t rax;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct GateDescriptor
|
|
||||||
{
|
|
||||||
uint16_t offset1;
|
|
||||||
uint16_t selector;
|
|
||||||
uint8_t IST;
|
|
||||||
uint8_t flags;
|
|
||||||
uint16_t offset2;
|
|
||||||
uint32_t offset3;
|
|
||||||
uint32_t reserved;
|
|
||||||
} __attribute__((packed));
|
|
||||||
|
|
||||||
struct IDTR
|
|
||||||
{
|
|
||||||
uint16_t size;
|
|
||||||
uint64_t offset;
|
|
||||||
} __attribute__((packed));
|
|
||||||
|
|
||||||
static IDTR s_idtr;
|
|
||||||
static GateDescriptor* s_idt = nullptr;
|
|
||||||
|
|
||||||
#define X(num) 1 +
|
|
||||||
static BAN::Array<Interruptable*, IRQ_LIST_X 0> s_interruptables;
|
|
||||||
#undef X
|
|
||||||
|
|
||||||
enum ISR
|
|
||||||
{
|
|
||||||
DivisionError,
|
|
||||||
Debug,
|
|
||||||
NonMaskableInterrupt,
|
|
||||||
Breakpoint,
|
|
||||||
Overflow,
|
|
||||||
BoundRangeException,
|
|
||||||
InvalidOpcode,
|
|
||||||
DeviceNotAvailable,
|
|
||||||
DoubleFault,
|
|
||||||
CoprocessorSegmentOverrun,
|
|
||||||
InvalidTSS,
|
|
||||||
SegmentNotPresent,
|
|
||||||
StackSegmentFault,
|
|
||||||
GeneralProtectionFault,
|
|
||||||
PageFault,
|
|
||||||
UnknownException0x0F,
|
|
||||||
x87FloatingPointException,
|
|
||||||
AlignmentCheck,
|
|
||||||
MachineCheck,
|
|
||||||
SIMDFloatingPointException,
|
|
||||||
VirtualizationException,
|
|
||||||
ControlProtectionException,
|
|
||||||
UnknownException0x16,
|
|
||||||
UnknownException0x17,
|
|
||||||
UnknownException0x18,
|
|
||||||
UnknownException0x19,
|
|
||||||
UnknownException0x1A,
|
|
||||||
UnknownException0x1B,
|
|
||||||
HypervisorInjectionException,
|
|
||||||
VMMCommunicationException,
|
|
||||||
SecurityException,
|
|
||||||
UnkownException0x1F,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct PageFaultError
|
|
||||||
{
|
|
||||||
union
|
|
||||||
{
|
|
||||||
uint32_t raw;
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
uint32_t present : 1;
|
|
||||||
uint32_t write : 1;
|
|
||||||
uint32_t userspace : 1;
|
|
||||||
uint32_t reserved_write : 1;
|
|
||||||
uint32_t instruction : 1;
|
|
||||||
uint32_t protection_key : 1;
|
|
||||||
uint32_t shadow_stack : 1;
|
|
||||||
uint32_t reserved1 : 8;
|
|
||||||
uint32_t sgx_violation : 1;
|
|
||||||
uint32_t reserved2 : 16;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
};
|
|
||||||
static_assert(sizeof(PageFaultError) == 4);
|
|
||||||
|
|
||||||
static const char* isr_exceptions[] =
|
|
||||||
{
|
|
||||||
"Division Error",
|
|
||||||
"Debug",
|
|
||||||
"Non-maskable Interrupt",
|
|
||||||
"Breakpoint",
|
|
||||||
"Overflow",
|
|
||||||
"Bound Range Exception",
|
|
||||||
"Invalid Opcode",
|
|
||||||
"Device Not Available",
|
|
||||||
"Double Fault",
|
|
||||||
"Coprocessor Segment Overrun",
|
|
||||||
"Invalid TSS",
|
|
||||||
"Segment Not Present",
|
|
||||||
"Stack-Segment Fault",
|
|
||||||
"General Protection Fault",
|
|
||||||
"Page Fault",
|
|
||||||
"Unknown Exception 0x0F",
|
|
||||||
"x87 Floating-Point Exception",
|
|
||||||
"Alignment Check",
|
|
||||||
"Machine Check",
|
|
||||||
"SIMD Floating-Point Exception",
|
|
||||||
"Virtualization Exception",
|
|
||||||
"Control Protection Exception",
|
|
||||||
"Unknown Exception 0x16",
|
|
||||||
"Unknown Exception 0x17",
|
|
||||||
"Unknown Exception 0x18",
|
|
||||||
"Unknown Exception 0x19",
|
|
||||||
"Unknown Exception 0x1A",
|
|
||||||
"Unknown Exception 0x1B",
|
|
||||||
"Hypervisor Injection Exception",
|
|
||||||
"VMM Communication Exception",
|
|
||||||
"Security Exception",
|
|
||||||
"Unkown Exception 0x1F",
|
|
||||||
};
|
|
||||||
|
|
||||||
extern "C" void cpp_isr_handler(uint64_t isr, uint64_t error, InterruptStack& interrupt_stack, const Registers* regs)
|
|
||||||
{
|
|
||||||
#if __enable_sse
|
|
||||||
bool from_userspace = (interrupt_stack.cs & 0b11) == 0b11;
|
|
||||||
if (from_userspace)
|
|
||||||
Thread::current().save_sse();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
pid_t tid = Scheduler::current_tid();
|
|
||||||
pid_t pid = tid ? Process::current().pid() : 0;
|
|
||||||
|
|
||||||
if (tid)
|
|
||||||
{
|
|
||||||
Thread::current().set_return_rsp(interrupt_stack.rsp);
|
|
||||||
Thread::current().set_return_rip(interrupt_stack.rip);
|
|
||||||
|
|
||||||
if (isr == ISR::PageFault)
|
|
||||||
{
|
|
||||||
// Check if stack is OOB
|
|
||||||
auto& stack = Thread::current().stack();
|
|
||||||
auto& istack = Thread::current().interrupt_stack();
|
|
||||||
if (stack.vaddr() < interrupt_stack.rsp && interrupt_stack.rsp <= stack.vaddr() + stack.size())
|
|
||||||
; // using normal stack
|
|
||||||
else if (istack.vaddr() < interrupt_stack.rsp && interrupt_stack.rsp <= istack.vaddr() + istack.size())
|
|
||||||
; // using interrupt stack
|
|
||||||
else
|
|
||||||
{
|
|
||||||
derrorln("Stack pointer out of bounds!");
|
|
||||||
derrorln("rip {H}", interrupt_stack.rip);
|
|
||||||
derrorln("rsp {H}, stack {H}->{H}, istack {H}->{H}",
|
|
||||||
interrupt_stack.rsp,
|
|
||||||
stack.vaddr(), stack.vaddr() + stack.size(),
|
|
||||||
istack.vaddr(), istack.vaddr() + istack.size()
|
|
||||||
);
|
|
||||||
Thread::current().handle_signal(SIGKILL);
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Try demand paging on non present pages
|
|
||||||
PageFaultError page_fault_error;
|
|
||||||
page_fault_error.raw = error;
|
|
||||||
if (!page_fault_error.present)
|
|
||||||
{
|
|
||||||
asm volatile("sti");
|
|
||||||
auto result = Process::current().allocate_page_for_demand_paging(regs->cr2);
|
|
||||||
asm volatile("cli");
|
|
||||||
|
|
||||||
if (!result.is_error() && result.value())
|
|
||||||
goto done;
|
|
||||||
|
|
||||||
if (result.is_error())
|
|
||||||
{
|
|
||||||
dwarnln("Demand paging: {}", result.error());
|
|
||||||
Thread::current().handle_signal(SIGKILL);
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#if __enable_sse
|
|
||||||
else if (isr == ISR::DeviceNotAvailable)
|
|
||||||
{
|
|
||||||
asm volatile(
|
|
||||||
"movq %cr0, %rax;"
|
|
||||||
"andq $~(1 << 3), %rax;"
|
|
||||||
"movq %rax, %cr0;"
|
|
||||||
);
|
|
||||||
if (auto* current = &Thread::current(); current != Thread::sse_thread())
|
|
||||||
{
|
|
||||||
if (auto* sse = Thread::sse_thread())
|
|
||||||
sse->save_sse();
|
|
||||||
current->load_sse();
|
|
||||||
}
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
if (PageTable::current().get_page_flags(interrupt_stack.rip & PAGE_ADDR_MASK) & PageTable::Flags::Present)
|
|
||||||
{
|
|
||||||
auto* machine_code = (const uint8_t*)interrupt_stack.rip;
|
|
||||||
dwarnln("While executing: {2H}{2H}{2H}{2H}{2H}{2H}{2H}{2H}",
|
|
||||||
machine_code[0],
|
|
||||||
machine_code[1],
|
|
||||||
machine_code[2],
|
|
||||||
machine_code[3],
|
|
||||||
machine_code[4],
|
|
||||||
machine_code[5],
|
|
||||||
machine_code[6],
|
|
||||||
machine_code[7]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
dwarnln(
|
|
||||||
"{} (error code: 0x{16H}), pid {}, tid {}\r\n"
|
|
||||||
"Register dump\r\n"
|
|
||||||
"rax=0x{16H}, rbx=0x{16H}, rcx=0x{16H}, rdx=0x{16H}\r\n"
|
|
||||||
"rsp=0x{16H}, rbp=0x{16H}, rdi=0x{16H}, rsi=0x{16H}\r\n"
|
|
||||||
"rip=0x{16H}, rflags=0x{16H}\r\n"
|
|
||||||
"cr0=0x{16H}, cr2=0x{16H}, cr3=0x{16H}, cr4=0x{16H}",
|
|
||||||
isr_exceptions[isr], error, pid, tid,
|
|
||||||
regs->rax, regs->rbx, regs->rcx, regs->rdx,
|
|
||||||
regs->rsp, regs->rbp, regs->rdi, regs->rsi,
|
|
||||||
regs->rip, regs->rflags,
|
|
||||||
regs->cr0, regs->cr2, regs->cr3, regs->cr4
|
|
||||||
);
|
|
||||||
if (isr == ISR::PageFault)
|
|
||||||
PageTable::current().debug_dump();
|
|
||||||
Debug::dump_stack_trace();
|
|
||||||
|
|
||||||
if (tid && Thread::current().is_userspace())
|
|
||||||
{
|
|
||||||
// TODO: Confirm and fix the exception to signal mappings
|
|
||||||
|
|
||||||
int signal = 0;
|
|
||||||
switch (isr)
|
|
||||||
{
|
|
||||||
case ISR::DivisionError:
|
|
||||||
case ISR::SIMDFloatingPointException:
|
|
||||||
case ISR::x87FloatingPointException:
|
|
||||||
signal = SIGFPE;
|
|
||||||
break;
|
|
||||||
case ISR::AlignmentCheck:
|
|
||||||
signal = SIGBUS;
|
|
||||||
break;
|
|
||||||
case ISR::InvalidOpcode:
|
|
||||||
signal = SIGILL;
|
|
||||||
break;
|
|
||||||
case ISR::PageFault:
|
|
||||||
signal = SIGSEGV;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
dwarnln("Unhandled exception");
|
|
||||||
signal = SIGABRT;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
Thread::current().handle_signal(signal);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
panic("Unhandled exception");
|
|
||||||
}
|
|
||||||
|
|
||||||
ASSERT(Thread::current().state() != Thread::State::Terminated);
|
|
||||||
|
|
||||||
done:
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "C" void cpp_irq_handler(uint64_t irq, InterruptStack& interrupt_stack)
|
|
||||||
{
|
|
||||||
if (Scheduler::current_tid())
|
|
||||||
{
|
|
||||||
Thread::current().set_return_rsp(interrupt_stack.rsp);
|
|
||||||
Thread::current().set_return_rip(interrupt_stack.rip);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!InterruptController::get().is_in_service(irq))
|
|
||||||
dprintln("spurious irq 0x{2H}", irq);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
InterruptController::get().eoi(irq);
|
|
||||||
if (s_interruptables[irq])
|
|
||||||
s_interruptables[irq]->handle_irq();
|
|
||||||
else
|
|
||||||
dprintln("no handler for irq 0x{2H}\n", irq);
|
|
||||||
}
|
|
||||||
|
|
||||||
Scheduler::get().reschedule_if_idling();
|
|
||||||
|
|
||||||
ASSERT(Thread::current().state() != Thread::State::Terminated);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void flush_idt()
|
|
||||||
{
|
|
||||||
asm volatile("lidt %0"::"m"(s_idtr));
|
|
||||||
}
|
|
||||||
|
|
||||||
static void register_interrupt_handler(uint8_t index, void(*handler)())
|
|
||||||
{
|
|
||||||
GateDescriptor& descriptor = s_idt[index];
|
|
||||||
descriptor.offset1 = (uint16_t)((uint64_t)handler >> 0);
|
|
||||||
descriptor.offset2 = (uint16_t)((uint64_t)handler >> 16);
|
|
||||||
descriptor.offset3 = (uint32_t)((uint64_t)handler >> 32);
|
|
||||||
|
|
||||||
descriptor.selector = 0x08;
|
|
||||||
descriptor.IST = 0;
|
|
||||||
descriptor.flags = 0x8E;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void register_syscall_handler(uint8_t index, void(*handler)())
|
|
||||||
{
|
|
||||||
register_interrupt_handler(index, handler);
|
|
||||||
s_idt[index].flags = 0xEE;
|
|
||||||
}
|
|
||||||
|
|
||||||
void register_irq_handler(uint8_t irq, Interruptable* interruptable)
|
|
||||||
{
|
|
||||||
if (irq > s_interruptables.size())
|
|
||||||
Kernel::panic("Trying to assign handler for irq {} while only {} are supported", irq, s_interruptables.size());
|
|
||||||
s_interruptables[irq] = interruptable;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define X(num) extern "C" void isr ## num();
|
|
||||||
ISR_LIST_X
|
|
||||||
#undef X
|
|
||||||
|
|
||||||
#define X(num) extern "C" void irq ## num();
|
|
||||||
IRQ_LIST_X
|
|
||||||
#undef X
|
|
||||||
|
|
||||||
extern "C" void syscall_asm();
|
|
||||||
|
|
||||||
void initialize()
|
|
||||||
{
|
|
||||||
s_idt = (GateDescriptor*)kmalloc(0x100 * sizeof(GateDescriptor));
|
|
||||||
ASSERT(s_idt);
|
|
||||||
memset(s_idt, 0x00, 0x100 * sizeof(GateDescriptor));
|
|
||||||
|
|
||||||
s_idtr.offset = (uint64_t)s_idt;
|
|
||||||
s_idtr.size = 0x100 * sizeof(GateDescriptor) - 1;
|
|
||||||
|
|
||||||
#define X(num) register_interrupt_handler(num, isr ## num);
|
|
||||||
ISR_LIST_X
|
|
||||||
#undef X
|
|
||||||
|
|
||||||
#define X(num) register_interrupt_handler(IRQ_VECTOR_BASE + num, irq ## num);
|
|
||||||
IRQ_LIST_X
|
|
||||||
#undef X
|
|
||||||
|
|
||||||
register_syscall_handler(0x80, syscall_asm);
|
|
||||||
|
|
||||||
flush_idt();
|
|
||||||
}
|
|
||||||
|
|
||||||
[[noreturn]] void force_triple_fault()
|
|
||||||
{
|
|
||||||
// load 0 sized IDT and trigger an interrupt to force triple fault
|
|
||||||
asm volatile("cli");
|
|
||||||
s_idtr.size = 0;
|
|
||||||
flush_idt();
|
|
||||||
asm volatile("int $0x00");
|
|
||||||
ASSERT_NOT_REACHED();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,53 +1,97 @@
|
|||||||
.section .userspace, "aw"
|
.section .userspace, "ax"
|
||||||
|
|
||||||
#include <sys/syscall.h>
|
|
||||||
|
|
||||||
// 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
|
||||||
|
|||||||
49
kernel/arch/x86_64/Syscall.S
Normal file
49
kernel/arch/x86_64/Syscall.S
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
.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
|
||||||
|
sys_fork_trampoline:
|
||||||
|
pushq %rbx
|
||||||
|
pushq %rbp
|
||||||
|
pushq %r12
|
||||||
|
pushq %r13
|
||||||
|
pushq %r14
|
||||||
|
pushq %r15
|
||||||
|
|
||||||
|
call read_ip
|
||||||
|
testq %rax, %rax
|
||||||
|
jz .done
|
||||||
|
|
||||||
|
movq %rax, %rsi
|
||||||
|
movq %rsp, %rdi
|
||||||
|
call sys_fork
|
||||||
|
|
||||||
|
.done:
|
||||||
|
popq %r15
|
||||||
|
popq %r14
|
||||||
|
popq %r13
|
||||||
|
popq %r12
|
||||||
|
popq %rbp
|
||||||
|
popq %rbx
|
||||||
|
ret
|
||||||
@@ -1,39 +1,28 @@
|
|||||||
# uint64_t read_rip()
|
# uint64_t read_ip()
|
||||||
.global read_rip
|
.global read_ip
|
||||||
read_rip:
|
read_ip:
|
||||||
popq %rax
|
popq %rax
|
||||||
jmp *%rax
|
jmp *%rax
|
||||||
|
|
||||||
exit_thread_trampoline:
|
# void start_kernel_thread()
|
||||||
|
.global start_kernel_thread
|
||||||
|
start_kernel_thread:
|
||||||
|
# STACK LAYOUT
|
||||||
|
# on_exit arg
|
||||||
|
# on_exit func
|
||||||
|
# entry arg
|
||||||
|
# entry func
|
||||||
|
|
||||||
movq 8(%rsp), %rdi
|
movq 8(%rsp), %rdi
|
||||||
ret
|
movq 0(%rsp), %rsi
|
||||||
|
|
||||||
# void start_thread(uint64_t rsp, uint64_t rip)
|
|
||||||
.global start_thread
|
|
||||||
start_thread:
|
|
||||||
movq %rdi, %rsp
|
|
||||||
popq %rdi
|
|
||||||
movq $0, %rbp
|
|
||||||
pushq $exit_thread_trampoline
|
|
||||||
sti
|
sti
|
||||||
jmp *%rsi
|
call *%rsi
|
||||||
|
|
||||||
# void continue_thread(uint64_t rsp, uint64_t rip)
|
movq 24(%rsp), %rdi
|
||||||
.global continue_thread
|
movq 16(%rsp), %rsi
|
||||||
continue_thread:
|
call *%rsi
|
||||||
movq %rdi, %rsp
|
|
||||||
movq $0, %rax
|
|
||||||
jmp *%rsi
|
|
||||||
|
|
||||||
# void thread_userspace_trampoline(uint64_t rsp, uint64_t rip, int argc, char** argv, char** envp)
|
.global start_userspace_thread
|
||||||
.global thread_userspace_trampoline
|
start_userspace_thread:
|
||||||
thread_userspace_trampoline:
|
swapgs
|
||||||
pushq $0x23
|
|
||||||
pushq %rdi
|
|
||||||
pushfq
|
|
||||||
pushq $0x1B
|
|
||||||
pushq %rsi
|
|
||||||
movq %rdx, %rdi
|
|
||||||
movq %rcx, %rsi
|
|
||||||
movq %r8, %rdx
|
|
||||||
iretq
|
iretq
|
||||||
|
|||||||
87
kernel/arch/x86_64/User.S
Normal file
87
kernel/arch/x86_64/User.S
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
# bool safe_user_memcpy(void*, const void*, size_t)
|
||||||
|
.global safe_user_memcpy
|
||||||
|
.global safe_user_memcpy_end
|
||||||
|
.global safe_user_memcpy_fault
|
||||||
|
safe_user_memcpy:
|
||||||
|
xorq %rax, %rax
|
||||||
|
movq %rdx, %rcx
|
||||||
|
rep movsb
|
||||||
|
incq %rax
|
||||||
|
safe_user_memcpy_fault:
|
||||||
|
ret
|
||||||
|
safe_user_memcpy_end:
|
||||||
|
|
||||||
|
# bool safe_user_strncpy(void*, const void*, size_t)
|
||||||
|
.global safe_user_strncpy
|
||||||
|
.global safe_user_strncpy_end
|
||||||
|
.global safe_user_strncpy_fault
|
||||||
|
safe_user_strncpy:
|
||||||
|
movq %rdx, %rcx
|
||||||
|
testq %rcx, %rcx
|
||||||
|
jz safe_user_strncpy_fault
|
||||||
|
|
||||||
|
.safe_user_strncpy_align_loop:
|
||||||
|
testb $0x7, %sil
|
||||||
|
jz .safe_user_strncpy_align_done
|
||||||
|
|
||||||
|
movb (%rsi), %al
|
||||||
|
movb %al, (%rdi)
|
||||||
|
testb %al, %al
|
||||||
|
jz .safe_user_strncpy_done
|
||||||
|
|
||||||
|
incq %rdi
|
||||||
|
incq %rsi
|
||||||
|
decq %rcx
|
||||||
|
jnz .safe_user_strncpy_align_loop
|
||||||
|
jmp safe_user_strncpy_fault
|
||||||
|
|
||||||
|
.safe_user_strncpy_align_done:
|
||||||
|
movq $0x0101010101010101, %r8
|
||||||
|
movq $0x8080808080808080, %r9
|
||||||
|
|
||||||
|
.safe_user_strncpy_qword_loop:
|
||||||
|
cmpq $8, %rcx
|
||||||
|
jb .safe_user_strncpy_qword_done
|
||||||
|
|
||||||
|
movq (%rsi), %rax
|
||||||
|
movq %rax, %r10
|
||||||
|
movq %rax, %r11
|
||||||
|
|
||||||
|
# https://graphics.stanford.edu/~seander/bithacks.html#ZeroInWord
|
||||||
|
subq %r8, %r10
|
||||||
|
notq %r11
|
||||||
|
andq %r11, %r10
|
||||||
|
andq %r9, %r10
|
||||||
|
jnz .safe_user_strncpy_byte_loop
|
||||||
|
|
||||||
|
movq %rax, (%rdi)
|
||||||
|
|
||||||
|
addq $8, %rdi
|
||||||
|
addq $8, %rsi
|
||||||
|
subq $8, %rcx
|
||||||
|
jnz .safe_user_strncpy_qword_loop
|
||||||
|
jmp safe_user_strncpy_fault
|
||||||
|
|
||||||
|
.safe_user_strncpy_qword_done:
|
||||||
|
testq %rcx, %rcx
|
||||||
|
jz safe_user_strncpy_fault
|
||||||
|
|
||||||
|
.safe_user_strncpy_byte_loop:
|
||||||
|
movb (%rsi), %al
|
||||||
|
movb %al, (%rdi)
|
||||||
|
testb %al, %al
|
||||||
|
jz .safe_user_strncpy_done
|
||||||
|
|
||||||
|
incq %rdi
|
||||||
|
incq %rsi
|
||||||
|
decq %rcx
|
||||||
|
jnz .safe_user_strncpy_byte_loop
|
||||||
|
|
||||||
|
safe_user_strncpy_fault:
|
||||||
|
xorq %rax, %rax
|
||||||
|
ret
|
||||||
|
|
||||||
|
.safe_user_strncpy_done:
|
||||||
|
movb $1, %al
|
||||||
|
ret
|
||||||
|
safe_user_strncpy_end:
|
||||||
29
kernel/arch/x86_64/Yield.S
Normal file
29
kernel/arch/x86_64/Yield.S
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
.global asm_yield_trampoline
|
||||||
|
asm_yield_trampoline:
|
||||||
|
leaq 8(%rsp), %rcx
|
||||||
|
movq %rdi, %rsp
|
||||||
|
|
||||||
|
subq $8, %rsp
|
||||||
|
pushq -8(%rcx)
|
||||||
|
pushq %rcx
|
||||||
|
pushq %rax
|
||||||
|
pushq %rbx
|
||||||
|
pushq %rbp
|
||||||
|
pushq %r12
|
||||||
|
pushq %r13
|
||||||
|
pushq %r14
|
||||||
|
pushq %r15
|
||||||
|
|
||||||
|
movq %rsp, %rdi
|
||||||
|
call scheduler_on_yield
|
||||||
|
|
||||||
|
popq %r15
|
||||||
|
popq %r14
|
||||||
|
popq %r13
|
||||||
|
popq %r12
|
||||||
|
popq %rbp
|
||||||
|
popq %rbx
|
||||||
|
popq %rax
|
||||||
|
movq 8(%rsp), %rcx
|
||||||
|
movq 0(%rsp), %rsp
|
||||||
|
jmp *%rcx
|
||||||
@@ -11,9 +11,28 @@
|
|||||||
|
|
||||||
.code32
|
.code32
|
||||||
|
|
||||||
# multiboot2 header
|
// custom addresses, video mode info, page align modules
|
||||||
|
.set multiboot_flags, (1 << 16) | (1 << 2) | (1 << 0)
|
||||||
|
|
||||||
.section .multiboot, "aw"
|
.section .multiboot, "aw"
|
||||||
.align 8
|
multiboot_start:
|
||||||
|
.long 0x1BADB002
|
||||||
|
.long multiboot_flags
|
||||||
|
.long -(0x1BADB002 + multiboot_flags)
|
||||||
|
|
||||||
|
.long V2P(multiboot_start)
|
||||||
|
.long V2P(g_kernel_start)
|
||||||
|
.long V2P(g_kernel_bss_start)
|
||||||
|
.long V2P(g_kernel_end)
|
||||||
|
.long V2P(_start)
|
||||||
|
|
||||||
|
.long 0
|
||||||
|
.long FB_WIDTH
|
||||||
|
.long FB_HEIGHT
|
||||||
|
.long FB_BPP
|
||||||
|
multiboot_end:
|
||||||
|
|
||||||
|
.section .multiboot2, "aw"
|
||||||
multiboot2_start:
|
multiboot2_start:
|
||||||
.long 0xE85250D6
|
.long 0xE85250D6
|
||||||
.long 0
|
.long 0
|
||||||
@@ -36,6 +55,12 @@ multiboot2_start:
|
|||||||
.long 12
|
.long 12
|
||||||
.long V2P(_start)
|
.long V2P(_start)
|
||||||
|
|
||||||
|
# page align modules
|
||||||
|
.align 8
|
||||||
|
.short 6
|
||||||
|
.short 0
|
||||||
|
.long 8
|
||||||
|
|
||||||
.align 8
|
.align 8
|
||||||
.short 0
|
.short 0
|
||||||
.short 0
|
.short 0
|
||||||
@@ -43,7 +68,6 @@ multiboot2_start:
|
|||||||
multiboot2_end:
|
multiboot2_end:
|
||||||
|
|
||||||
.section .bananboot, "aw"
|
.section .bananboot, "aw"
|
||||||
.align 8
|
|
||||||
bananboot_start:
|
bananboot_start:
|
||||||
.long 0xBABAB007
|
.long 0xBABAB007
|
||||||
.long -(0xBABAB007 + FB_WIDTH + FB_HEIGHT + FB_BPP)
|
.long -(0xBABAB007 + FB_WIDTH + FB_HEIGHT + FB_BPP)
|
||||||
@@ -53,11 +77,9 @@ bananboot_start:
|
|||||||
bananboot_end:
|
bananboot_end:
|
||||||
|
|
||||||
.section .bss, "aw", @nobits
|
.section .bss, "aw", @nobits
|
||||||
# Create stack
|
|
||||||
.global g_boot_stack_bottom
|
|
||||||
g_boot_stack_bottom:
|
|
||||||
.skip 16384
|
|
||||||
.global g_boot_stack_top
|
.global g_boot_stack_top
|
||||||
|
g_boot_stack_bottom:
|
||||||
|
.skip 4096 * 4
|
||||||
g_boot_stack_top:
|
g_boot_stack_top:
|
||||||
|
|
||||||
.global g_kernel_cmdline
|
.global g_kernel_cmdline
|
||||||
@@ -75,27 +97,25 @@ bananboot_end:
|
|||||||
.align 4096
|
.align 4096
|
||||||
boot_pml4:
|
boot_pml4:
|
||||||
.quad V2P(boot_pdpt_lo) + (PG_READ_WRITE | PG_PRESENT)
|
.quad V2P(boot_pdpt_lo) + (PG_READ_WRITE | PG_PRESENT)
|
||||||
.rept 510
|
.skip 510 * 8
|
||||||
.quad 0
|
|
||||||
.endr
|
|
||||||
.quad V2P(boot_pdpt_hi) + (PG_READ_WRITE | PG_PRESENT)
|
.quad V2P(boot_pdpt_hi) + (PG_READ_WRITE | PG_PRESENT)
|
||||||
boot_pdpt_lo:
|
boot_pdpt_lo:
|
||||||
.quad V2P(boot_pd) + (PG_READ_WRITE | PG_PRESENT)
|
.quad V2P(boot_pd) + (PG_READ_WRITE | PG_PRESENT)
|
||||||
.rept 511
|
.skip 511 * 8
|
||||||
.quad 0
|
|
||||||
.endr
|
|
||||||
boot_pdpt_hi:
|
boot_pdpt_hi:
|
||||||
.rept 510
|
.skip 510 * 8
|
||||||
.quad 0
|
|
||||||
.endr
|
|
||||||
.quad V2P(boot_pd) + (PG_READ_WRITE | PG_PRESENT)
|
.quad V2P(boot_pd) + (PG_READ_WRITE | PG_PRESENT)
|
||||||
.quad 0
|
.skip 8
|
||||||
boot_pd:
|
boot_pd:
|
||||||
.set i, 0
|
.set i, 0
|
||||||
.rept 512
|
.rept 511
|
||||||
.quad i + (PG_PAGE_SIZE | PG_READ_WRITE | PG_PRESENT)
|
.quad i + (PG_PAGE_SIZE | PG_READ_WRITE | PG_PRESENT)
|
||||||
.set i, i + 0x200000
|
.set i, i + 0x200000
|
||||||
.endr
|
.endr
|
||||||
|
.quad V2P(g_boot_fast_page_pt) + (PG_READ_WRITE | PG_PRESENT)
|
||||||
|
.global g_boot_fast_page_pt
|
||||||
|
g_boot_fast_page_pt:
|
||||||
|
.skip 512 * 8
|
||||||
|
|
||||||
boot_gdt:
|
boot_gdt:
|
||||||
.quad 0x0000000000000000 # null descriptor
|
.quad 0x0000000000000000 # null descriptor
|
||||||
@@ -105,6 +125,13 @@ boot_gdtr:
|
|||||||
.short . - boot_gdt - 1
|
.short . - boot_gdt - 1
|
||||||
.quad V2P(boot_gdt)
|
.quad V2P(boot_gdt)
|
||||||
|
|
||||||
|
.global g_ap_startup_done
|
||||||
|
g_ap_startup_done:
|
||||||
|
.byte 0
|
||||||
|
.global g_ap_running_count
|
||||||
|
g_ap_running_count:
|
||||||
|
.byte 0
|
||||||
|
|
||||||
.section .text
|
.section .text
|
||||||
|
|
||||||
has_cpuid:
|
has_cpuid:
|
||||||
@@ -151,6 +178,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
|
||||||
@@ -177,14 +211,17 @@ initialize_paging:
|
|||||||
.global _start
|
.global _start
|
||||||
.type _start, @function
|
.type _start, @function
|
||||||
_start:
|
_start:
|
||||||
|
cli; cld
|
||||||
|
|
||||||
# Initialize stack and multiboot info
|
# Initialize stack and multiboot info
|
||||||
movl $V2P(g_boot_stack_top), %esp
|
|
||||||
movl %eax, V2P(bootloader_magic)
|
movl %eax, V2P(bootloader_magic)
|
||||||
movl %ebx, V2P(bootloader_info)
|
movl %ebx, V2P(bootloader_info)
|
||||||
|
|
||||||
|
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
|
||||||
@@ -194,17 +231,15 @@ _start:
|
|||||||
.code64
|
.code64
|
||||||
long_mode:
|
long_mode:
|
||||||
movw $0x10, %ax
|
movw $0x10, %ax
|
||||||
movw %ax, %ss
|
|
||||||
|
|
||||||
# clear segment registers (unused in x86_64?)
|
|
||||||
movw $0x00, %ax
|
|
||||||
movw %ax, %ds
|
movw %ax, %ds
|
||||||
|
movw %ax, %ss
|
||||||
movw %ax, %es
|
movw %ax, %es
|
||||||
movw %ax, %fs
|
|
||||||
movw %ax, %gs
|
# move stack pointer to higher half
|
||||||
|
movl %esp, %esp
|
||||||
|
addq $KERNEL_OFFSET, %rsp
|
||||||
|
|
||||||
# jump to higher half
|
# jump to higher half
|
||||||
movq $g_boot_stack_top, %rsp
|
|
||||||
movabsq $higher_half, %rcx
|
movabsq $higher_half, %rcx
|
||||||
jmp *%rcx
|
jmp *%rcx
|
||||||
|
|
||||||
@@ -212,6 +247,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
|
||||||
|
|
||||||
@@ -227,3 +269,88 @@ system_halt:
|
|||||||
cli
|
cli
|
||||||
1: hlt
|
1: hlt
|
||||||
jmp 1b
|
jmp 1b
|
||||||
|
|
||||||
|
|
||||||
|
#define AP_REL(vaddr) ((vaddr) - ap_trampoline + 0xF000)
|
||||||
|
|
||||||
|
.section .ap_init, "ax"
|
||||||
|
|
||||||
|
.code16
|
||||||
|
.global ap_trampoline
|
||||||
|
ap_trampoline:
|
||||||
|
jmp 1f
|
||||||
|
|
||||||
|
.align 8
|
||||||
|
ap_stack_paddr:
|
||||||
|
.skip 8
|
||||||
|
ap_stack_vaddr:
|
||||||
|
.skip 8
|
||||||
|
ap_prepare_paging:
|
||||||
|
.skip 8
|
||||||
|
ap_page_table:
|
||||||
|
.skip 8
|
||||||
|
ap_ready:
|
||||||
|
.skip 8
|
||||||
|
|
||||||
|
1: cli; cld
|
||||||
|
ljmpl $0x00, $AP_REL(ap_cs_clear)
|
||||||
|
|
||||||
|
ap_cs_clear:
|
||||||
|
# load ap gdt and enter protected mode
|
||||||
|
lgdt AP_REL(ap_gdtr)
|
||||||
|
movl %cr0, %eax
|
||||||
|
orb $1, %al
|
||||||
|
movl %eax, %cr0
|
||||||
|
ljmpl $0x08, $AP_REL(ap_protected_mode)
|
||||||
|
|
||||||
|
.code32
|
||||||
|
ap_protected_mode:
|
||||||
|
movw $0x10, %ax
|
||||||
|
movw %ax, %ds
|
||||||
|
movw %ax, %ss
|
||||||
|
movw %ax, %es
|
||||||
|
|
||||||
|
movl AP_REL(ap_stack_paddr), %esp
|
||||||
|
|
||||||
|
leal V2P(enable_sse), %ecx; call *%ecx
|
||||||
|
leal V2P(enable_tsc), %ecx; call *%ecx
|
||||||
|
leal V2P(initialize_paging), %ecx; call *%ecx
|
||||||
|
|
||||||
|
# load boot gdt and enter long mode
|
||||||
|
lgdt V2P(boot_gdtr)
|
||||||
|
ljmpl $0x08, $AP_REL(ap_long_mode)
|
||||||
|
|
||||||
|
.code64
|
||||||
|
ap_long_mode:
|
||||||
|
movq $ap_higher_half, %rax
|
||||||
|
jmp *%rax
|
||||||
|
|
||||||
|
ap_higher_half:
|
||||||
|
movq AP_REL(ap_prepare_paging), %rax
|
||||||
|
call *%rax
|
||||||
|
|
||||||
|
# load AP's initial values
|
||||||
|
movq AP_REL(ap_stack_vaddr), %rsp
|
||||||
|
movq AP_REL(ap_page_table), %rax
|
||||||
|
movq $1, AP_REL(ap_ready)
|
||||||
|
movq %rax, %cr3
|
||||||
|
|
||||||
|
# clear rbp for stacktrace
|
||||||
|
xorq %rbp, %rbp
|
||||||
|
|
||||||
|
1: pause
|
||||||
|
cmpb $0, g_ap_startup_done
|
||||||
|
je 1b
|
||||||
|
|
||||||
|
lock incb g_ap_running_count
|
||||||
|
|
||||||
|
call ap_main
|
||||||
|
jmp system_halt
|
||||||
|
|
||||||
|
ap_gdt:
|
||||||
|
.quad 0x0000000000000000 # null descriptor
|
||||||
|
.quad 0x00CF9A000000FFFF # 32 bit code
|
||||||
|
.quad 0x00CF92000000FFFF # 32 bit data
|
||||||
|
ap_gdtr:
|
||||||
|
.short . - ap_gdt - 1
|
||||||
|
.quad ap_gdt
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
.macro pushaq
|
.macro intr_header, n
|
||||||
pushq %rax
|
pushq %rax
|
||||||
pushq %rbx
|
|
||||||
pushq %rcx
|
pushq %rcx
|
||||||
pushq %rdx
|
pushq %rdx
|
||||||
|
pushq %rbx
|
||||||
pushq %rbp
|
pushq %rbp
|
||||||
pushq %rdi
|
|
||||||
pushq %rsi
|
pushq %rsi
|
||||||
|
pushq %rdi
|
||||||
pushq %r8
|
pushq %r8
|
||||||
pushq %r9
|
pushq %r9
|
||||||
pushq %r10
|
pushq %r10
|
||||||
@@ -14,10 +14,18 @@
|
|||||||
pushq %r13
|
pushq %r13
|
||||||
pushq %r14
|
pushq %r14
|
||||||
pushq %r15
|
pushq %r15
|
||||||
|
testb $3, \n+15*8(%rsp)
|
||||||
|
jz 1f
|
||||||
|
swapgs
|
||||||
|
1: cld
|
||||||
.endm
|
.endm
|
||||||
|
|
||||||
.macro popaq
|
.macro intr_footer, n
|
||||||
popq %r15
|
testb $3, \n+15*8(%rsp)
|
||||||
|
jz 1f
|
||||||
|
call cpp_check_signal
|
||||||
|
swapgs
|
||||||
|
1: popq %r15
|
||||||
popq %r14
|
popq %r14
|
||||||
popq %r13
|
popq %r13
|
||||||
popq %r12
|
popq %r12
|
||||||
@@ -25,67 +33,58 @@
|
|||||||
popq %r10
|
popq %r10
|
||||||
popq %r9
|
popq %r9
|
||||||
popq %r8
|
popq %r8
|
||||||
popq %rsi
|
|
||||||
popq %rdi
|
popq %rdi
|
||||||
|
popq %rsi
|
||||||
popq %rbp
|
popq %rbp
|
||||||
|
popq %rbx
|
||||||
popq %rdx
|
popq %rdx
|
||||||
popq %rcx
|
popq %rcx
|
||||||
popq %rbx
|
|
||||||
popq %rax
|
popq %rax
|
||||||
.endm
|
.endm
|
||||||
|
|
||||||
.macro popaq_no_rax
|
|
||||||
popq %r15
|
|
||||||
popq %r14
|
|
||||||
popq %r13
|
|
||||||
popq %r12
|
|
||||||
popq %r11
|
|
||||||
popq %r10
|
|
||||||
popq %r9
|
|
||||||
popq %r8
|
|
||||||
popq %rsi
|
|
||||||
popq %rdi
|
|
||||||
popq %rbp
|
|
||||||
popq %rdx
|
|
||||||
popq %rcx
|
|
||||||
popq %rbx
|
|
||||||
.endm
|
|
||||||
|
|
||||||
isr_stub:
|
isr_stub:
|
||||||
pushaq
|
intr_header 24
|
||||||
|
|
||||||
movq %cr0, %rax; pushq %rax
|
movq %cr0, %rax; pushq %rax
|
||||||
movq %cr2, %rax; pushq %rax
|
movq %cr2, %rax; pushq %rax
|
||||||
movq %cr3, %rax; pushq %rax
|
movq %cr3, %rax; pushq %rax
|
||||||
movq %cr4, %rax; pushq %rax
|
movq %cr4, %rax; pushq %rax
|
||||||
movq 184(%rsp), %rax; pushq %rax
|
|
||||||
movq 176(%rsp), %rax; pushq %rax
|
|
||||||
movq 208(%rsp), %rax; pushq %rax
|
|
||||||
|
|
||||||
movq 176(%rsp), %rdi
|
|
||||||
movq 184(%rsp), %rsi
|
|
||||||
|
|
||||||
movq %rsp, %rdx
|
|
||||||
addq $192, %rdx
|
|
||||||
|
|
||||||
movq %rsp, %rcx
|
|
||||||
|
|
||||||
|
movq 152(%rsp), %rdi // isr number
|
||||||
|
movq 160(%rsp), %rsi // error code
|
||||||
|
leaq 168(%rsp), %rdx // interrupt stack ptr
|
||||||
|
movq %rsp, %rcx // register ptr
|
||||||
call cpp_isr_handler
|
call cpp_isr_handler
|
||||||
addq $56, %rsp
|
addq $32, %rsp
|
||||||
popaq
|
|
||||||
|
intr_footer 24
|
||||||
addq $16, %rsp
|
addq $16, %rsp
|
||||||
iretq
|
iretq
|
||||||
|
|
||||||
irq_stub:
|
irq_stub:
|
||||||
pushaq
|
intr_header 24
|
||||||
movq 0x78(%rsp), %rdi # irq number
|
xorq %rbp, %rbp
|
||||||
movq %rsp, %rsi
|
movq 120(%rsp), %rdi # irq number
|
||||||
addq $136, %rsi
|
|
||||||
call cpp_irq_handler
|
call cpp_irq_handler
|
||||||
popaq
|
intr_footer 24
|
||||||
addq $16, %rsp
|
addq $16, %rsp
|
||||||
iretq
|
iretq
|
||||||
|
|
||||||
|
.global asm_ipi_handler
|
||||||
|
asm_ipi_handler:
|
||||||
|
intr_header 8
|
||||||
|
xorq %rbp, %rbp
|
||||||
|
call cpp_ipi_handler
|
||||||
|
intr_footer 8
|
||||||
|
iretq
|
||||||
|
|
||||||
|
.global asm_timer_handler
|
||||||
|
asm_timer_handler:
|
||||||
|
intr_header 8
|
||||||
|
xorq %rbp, %rbp
|
||||||
|
call cpp_timer_handler
|
||||||
|
intr_footer 8
|
||||||
|
iretq
|
||||||
|
|
||||||
.macro isr n
|
.macro isr n
|
||||||
.global isr\n
|
.global isr\n
|
||||||
isr\n:
|
isr\n:
|
||||||
@@ -142,54 +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
|
|
||||||
|
|
||||||
// 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
|
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user