Compare commits
1250 Commits
91381546d5
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 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 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -3,3 +3,4 @@
|
||||
build/
|
||||
base/
|
||||
script/fakeroot-context
|
||||
tools/update-image-perms
|
||||
|
||||
@@ -11,5 +11,8 @@ banan_link_library(ban libc)
|
||||
|
||||
set_target_properties(ban PROPERTIES OUTPUT_NAME libban)
|
||||
|
||||
# set SONAME as cmake doesn't set it for some reason??
|
||||
set_target_properties(ban PROPERTIES LINK_FLAGS "-Wl,-soname,libban.so")
|
||||
|
||||
banan_install_headers(ban)
|
||||
install(TARGETS ban OPTIONAL)
|
||||
|
||||
@@ -18,78 +18,78 @@ namespace BAN
|
||||
using const_iterator = ConstIteratorSimple<T, Array>;
|
||||
|
||||
public:
|
||||
Array() = default;
|
||||
Array(const T&);
|
||||
constexpr Array() = default;
|
||||
constexpr Array(const T&);
|
||||
|
||||
iterator begin() { return iterator(m_data); }
|
||||
iterator end() { return iterator(m_data + size()); }
|
||||
const_iterator begin() const { return const_iterator(m_data); }
|
||||
const_iterator end() const { return const_iterator(m_data + size()); }
|
||||
|
||||
const T& operator[](size_type) const;
|
||||
T& operator[](size_type);
|
||||
constexpr const T& operator[](size_type) const;
|
||||
constexpr T& operator[](size_type);
|
||||
|
||||
const T& back() const;
|
||||
T& back();
|
||||
const T& front() const;
|
||||
T& front();
|
||||
constexpr const T& back() const;
|
||||
constexpr T& back();
|
||||
constexpr const T& front() const;
|
||||
constexpr T& front();
|
||||
|
||||
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;
|
||||
|
||||
const T* data() const { return m_data; }
|
||||
T* data() { return m_data; }
|
||||
constexpr const T* data() const { return m_data; }
|
||||
constexpr T* data() { return m_data; }
|
||||
|
||||
private:
|
||||
T m_data[S] {};
|
||||
};
|
||||
|
||||
template<typename T, size_t S>
|
||||
Array<T, S>::Array(const T& value)
|
||||
constexpr Array<T, S>::Array(const T& value)
|
||||
{
|
||||
for (size_type i = 0; i < S; i++)
|
||||
m_data[i] = value;
|
||||
}
|
||||
|
||||
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);
|
||||
return m_data[index];
|
||||
}
|
||||
|
||||
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);
|
||||
return m_data[index];
|
||||
}
|
||||
|
||||
template<typename T, size_t S>
|
||||
const T& Array<T, S>::back() const
|
||||
constexpr const T& Array<T, S>::back() const
|
||||
{
|
||||
ASSERT(S != 0);
|
||||
return m_data[S - 1];
|
||||
}
|
||||
|
||||
template<typename T, size_t S>
|
||||
T& Array<T, S>::back()
|
||||
constexpr T& Array<T, S>::back()
|
||||
{
|
||||
ASSERT(S != 0);
|
||||
return m_data[S - 1];
|
||||
}
|
||||
|
||||
template<typename T, size_t S>
|
||||
const T& Array<T, S>::front() const
|
||||
constexpr const T& Array<T, S>::front() const
|
||||
{
|
||||
ASSERT(S != 0);
|
||||
return m_data[0];
|
||||
}
|
||||
|
||||
template<typename T, size_t S>
|
||||
T& Array<T, S>::front()
|
||||
constexpr T& Array<T, S>::front()
|
||||
{
|
||||
ASSERT(S != 0);
|
||||
return m_data[0];
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <BAN/Traits.h>
|
||||
|
||||
namespace BAN
|
||||
{
|
||||
|
||||
@@ -13,8 +15,36 @@ namespace BAN
|
||||
memory_order_seq_cst = __ATOMIC_SEQ_CST,
|
||||
};
|
||||
|
||||
template<typename T, MemoryOrder MEM_ORDER = MemoryOrder::memory_order_seq_cst>
|
||||
requires requires { __atomic_always_lock_free(sizeof(T), 0); }
|
||||
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
|
||||
{
|
||||
Atomic(const Atomic&) = delete;
|
||||
@@ -26,41 +56,41 @@ namespace BAN
|
||||
constexpr Atomic() : m_value(0) {}
|
||||
constexpr Atomic(T val) : m_value(val) {}
|
||||
|
||||
inline T load(MemoryOrder mem_order = MEM_ORDER) const volatile { return __atomic_load_n(&m_value, mem_order); }
|
||||
inline void store(T val, MemoryOrder mem_order = MEM_ORDER) volatile { __atomic_store_n(&m_value, val, mem_order); }
|
||||
inline T load(MemoryOrder mem_order = MEM_ORDER) const volatile { return atomic_load(m_value, mem_order); }
|
||||
inline void store(T val, MemoryOrder mem_order = MEM_ORDER) volatile { atomic_store(m_value, val, mem_order); }
|
||||
|
||||
inline T operator=(T val) volatile { store(val); return val; }
|
||||
|
||||
inline operator T() const volatile { return load(); }
|
||||
|
||||
inline T operator+=(T val) volatile { return __atomic_add_fetch(&m_value, val, MEM_ORDER); }
|
||||
inline T operator-=(T val) volatile { return __atomic_sub_fetch(&m_value, val, MEM_ORDER); }
|
||||
inline T operator&=(T val) volatile { return __atomic_and_fetch(&m_value, val, MEM_ORDER); }
|
||||
inline T operator^=(T val) volatile { return __atomic_xor_fetch(&m_value, val, MEM_ORDER); }
|
||||
inline T operator|=(T val) volatile { return __atomic_or_fetch(&m_value, val, MEM_ORDER); }
|
||||
inline T operator+=(T val) volatile { return atomic_add_fetch(m_value, val, MEM_ORDER); }
|
||||
inline T operator-=(T val) volatile { return atomic_sub_fetch(m_value, val, MEM_ORDER); }
|
||||
inline T operator&=(T val) volatile { return atomic_and_fetch(m_value, val, MEM_ORDER); }
|
||||
inline T operator^=(T val) volatile { return atomic_xor_fetch(m_value, val, MEM_ORDER); }
|
||||
inline T operator|=(T val) volatile { return atomic_or_fetch(m_value, val, MEM_ORDER); }
|
||||
|
||||
inline T operator--() volatile { return __atomic_sub_fetch(&m_value, 1, MEM_ORDER); }
|
||||
inline T operator++() volatile { return __atomic_add_fetch(&m_value, 1, MEM_ORDER); }
|
||||
inline T operator--() volatile { return atomic_sub_fetch(m_value, 1, MEM_ORDER); }
|
||||
inline T operator++() volatile { return atomic_add_fetch(m_value, 1, MEM_ORDER); }
|
||||
|
||||
inline T operator--(int) volatile { return __atomic_fetch_sub(&m_value, 1, MEM_ORDER); }
|
||||
inline T operator++(int) volatile { return __atomic_fetch_add(&m_value, 1, MEM_ORDER); }
|
||||
inline T operator--(int) volatile { return atomic_fetch_sub(m_value, 1, MEM_ORDER); }
|
||||
inline T operator++(int) volatile { return atomic_fetch_add(m_value, 1, MEM_ORDER); }
|
||||
|
||||
inline bool compare_exchange(T& expected, T desired, MemoryOrder mem_order = MEM_ORDER) volatile { return __atomic_compare_exchange_n(&m_value, &expected, desired, false, mem_order, mem_order); }
|
||||
inline T exchange(T desired, MemoryOrder mem_order = MEM_ORDER) volatile { return __atomic_exchange_n(&m_value, desired, mem_order); };
|
||||
inline 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 add_fetch (T val, MemoryOrder mem_order = MEM_ORDER) volatile { return atomic_add_fetch (m_value, val, mem_order); }
|
||||
inline T sub_fetch (T val, MemoryOrder mem_order = MEM_ORDER) volatile { return atomic_sub_fetch (m_value, val, mem_order); }
|
||||
inline T and_fetch (T val, MemoryOrder mem_order = MEM_ORDER) volatile { return atomic_and_fetch (m_value, val, mem_order); }
|
||||
inline T xor_fetch (T val, MemoryOrder mem_order = MEM_ORDER) volatile { return atomic_xor_fetch (m_value, val, mem_order); }
|
||||
inline T or_fetch (T val, MemoryOrder mem_order = MEM_ORDER) volatile { return atomic_or_fetch (m_value, val, mem_order); }
|
||||
inline T nand_fetch(T val, MemoryOrder mem_order = MEM_ORDER) volatile { return atomic_nand_fetch(m_value, val, mem_order); }
|
||||
|
||||
inline T fetch_add (T val, MemoryOrder mem_order = MEM_ORDER) volatile { return __atomic_fetch_add (&m_value, val, mem_order); }
|
||||
inline T fetch_sub (T val, MemoryOrder mem_order = MEM_ORDER) volatile { return __atomic_fetch_sub (&m_value, val, mem_order); }
|
||||
inline T fetch_and (T val, MemoryOrder mem_order = MEM_ORDER) volatile { return __atomic_fetch_and (&m_value, val, mem_order); }
|
||||
inline T fetch_xor (T val, MemoryOrder mem_order = MEM_ORDER) volatile { return __atomic_fetch_xor (&m_value, val, mem_order); }
|
||||
inline T fetch_or (T val, MemoryOrder mem_order = MEM_ORDER) volatile { return __atomic_fetch__or (&m_value, val, mem_order); }
|
||||
inline T fetch_nand(T val, MemoryOrder mem_order = MEM_ORDER) volatile { return __atomic_nfetch_and(&m_value, val, mem_order); }
|
||||
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:
|
||||
T m_value;
|
||||
|
||||
@@ -84,7 +84,7 @@ namespace BAN
|
||||
return Span<S>(reinterpret_cast<S*>(m_data), m_size / sizeof(S));
|
||||
}
|
||||
|
||||
ByteSpanGeneral slice(size_type offset, size_type length = size_type(-1)) const
|
||||
[[nodiscard]] ByteSpanGeneral slice(size_type offset, size_type length = size_type(-1)) const
|
||||
{
|
||||
ASSERT(m_data);
|
||||
ASSERT(m_size >= offset);
|
||||
|
||||
@@ -34,6 +34,11 @@ namespace BAN
|
||||
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; }
|
||||
bool empty() const { return size() == 0; }
|
||||
bool full() const { return size() == capacity(); }
|
||||
@@ -53,8 +58,7 @@ namespace BAN
|
||||
template<typename T, size_t S>
|
||||
CircularQueue<T, S>::~CircularQueue()
|
||||
{
|
||||
for (size_type i = 0; i < m_size; i++)
|
||||
element_at((m_first + i) % capacity())->~T();
|
||||
clear();
|
||||
}
|
||||
|
||||
template<typename T, size_t S>
|
||||
@@ -115,6 +119,28 @@ namespace BAN
|
||||
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>
|
||||
const T* CircularQueue<T, S>::element_at(size_type index) const
|
||||
{
|
||||
|
||||
@@ -9,29 +9,35 @@
|
||||
#include <BAN/Formatter.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define __debug_putchar [](int c) { putc(c, stddbg); }
|
||||
#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,"\r\n"); \
|
||||
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\r\n"); \
|
||||
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\r\n"); \
|
||||
BAN::Formatter::print(__debug_putchar, "\e[m\n"); \
|
||||
fflush(stddbg); \
|
||||
funlockfile(stddbg); \
|
||||
} while(false)
|
||||
|
||||
#define dprintln_if(cond, ...) \
|
||||
|
||||
@@ -70,15 +70,19 @@ namespace BAN
|
||||
template<integral T>
|
||||
struct LittleEndian
|
||||
{
|
||||
constexpr LittleEndian()
|
||||
: raw(0)
|
||||
{ }
|
||||
|
||||
constexpr LittleEndian(T value)
|
||||
{
|
||||
raw = host_to_little_endian(value);
|
||||
}
|
||||
: raw(host_to_little_endian(value))
|
||||
{ }
|
||||
|
||||
constexpr operator T() const
|
||||
{
|
||||
return host_to_little_endian(raw);
|
||||
}
|
||||
|
||||
private:
|
||||
T raw;
|
||||
};
|
||||
@@ -86,15 +90,19 @@ namespace BAN
|
||||
template<integral T>
|
||||
struct BigEndian
|
||||
{
|
||||
constexpr BigEndian()
|
||||
: raw(0)
|
||||
{ }
|
||||
|
||||
constexpr BigEndian(T value)
|
||||
{
|
||||
raw = host_to_big_endian(value);
|
||||
}
|
||||
: raw(host_to_big_endian(value))
|
||||
{ }
|
||||
|
||||
constexpr operator T() const
|
||||
{
|
||||
return host_to_big_endian(raw);
|
||||
}
|
||||
|
||||
private:
|
||||
T raw;
|
||||
};
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <BAN/Formatter.h>
|
||||
#include <BAN/NoCopyMove.h>
|
||||
#include <BAN/Variant.h>
|
||||
|
||||
#include <errno.h>
|
||||
@@ -9,16 +10,16 @@
|
||||
#ifdef __is_kernel
|
||||
#include <kernel/Panic.h>
|
||||
#include <kernel/Errors.h>
|
||||
#define MUST(expr) ({ auto&& e = expr; if (e.is_error()) Kernel::panic("{}", e.error()); e.release_value(); })
|
||||
#define MUST_REF(expr) *({ auto&& e = expr; if (e.is_error()) Kernel::panic("{}", e.error()); &e.release_value(); })
|
||||
#define MUST(...) ({ auto&& e = (__VA_ARGS__); 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
|
||||
#include <assert.h>
|
||||
#define MUST(expr) ({ auto&& e = expr; assert(!e.is_error()); e.release_value(); })
|
||||
#define MUST_REF(expr) *({ auto&& e = expr; assert(!e.is_error()); &e.release_value(); })
|
||||
#include <BAN/Debug.h>
|
||||
#define MUST(...) ({ auto&& e = (__VA_ARGS__); if (e.is_error()) { derrorln("MUST(" #__VA_ARGS__ "): {}", e.error()); __builtin_trap(); } 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
|
||||
|
||||
#define TRY(expr) ({ auto&& e = expr; if (e.is_error()) return e.release_error(); e.release_value(); })
|
||||
#define TRY_REF(expr) *({ auto&& e = expr; if (e.is_error()) return e.release_error(); &e.release_value(); })
|
||||
#define TRY(...) ({ auto&& e = (__VA_ARGS__); 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
|
||||
{
|
||||
@@ -97,6 +98,7 @@ namespace BAN
|
||||
template<typename T>
|
||||
class [[nodiscard]] ErrorOr
|
||||
{
|
||||
BAN_NON_COPYABLE(ErrorOr);
|
||||
public:
|
||||
ErrorOr(const T& value)
|
||||
: m_data(value)
|
||||
@@ -110,6 +112,14 @@ namespace BAN
|
||||
ErrorOr(Error&& 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>(); }
|
||||
const Error& error() const { return m_data.template get<Error>(); }
|
||||
|
||||
@@ -10,14 +10,11 @@ namespace BAN::Formatter
|
||||
|
||||
struct ValueFormat;
|
||||
|
||||
template<typename F>
|
||||
inline void print(F putc, const char* format);
|
||||
|
||||
template<typename F, typename Arg, typename... Args>
|
||||
inline void print(F putc, const char* format, Arg&& arg, Args&&... args);
|
||||
|
||||
template<typename F, typename... Args>
|
||||
inline 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>
|
||||
inline void print_argument(F putc, T value, const ValueFormat& format);
|
||||
@@ -53,7 +50,7 @@ namespace BAN::Formatter
|
||||
}
|
||||
}
|
||||
|
||||
template<typename F, typename Arg, typename... Args>
|
||||
template<typename F, typename Arg, typename... Args> requires PrintableArguments<F, Arg, Args...>
|
||||
inline void print(F putc, const char* format, Arg&& arg, Args&&... args)
|
||||
{
|
||||
while (*format && *format != '{')
|
||||
@@ -207,10 +204,14 @@ namespace BAN::Formatter
|
||||
template<typename F, typename T>
|
||||
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;
|
||||
T frac_part = value - (T)int_part;
|
||||
if (frac_part < 0)
|
||||
frac_part = -frac_part;
|
||||
|
||||
print_integer(putc, int_part, format);
|
||||
|
||||
|
||||
@@ -19,6 +19,12 @@ namespace BAN
|
||||
, value(forward<Args>(args)...)
|
||||
{}
|
||||
|
||||
template<typename... Args>
|
||||
Entry(Key&& key, Args&&... args) requires is_constructible_v<T, Args...>
|
||||
: key(BAN::move(key))
|
||||
, value(forward<Args>(args)...)
|
||||
{}
|
||||
|
||||
Key key;
|
||||
T value;
|
||||
};
|
||||
@@ -39,27 +45,27 @@ namespace BAN
|
||||
HashMap<Key, T, HASH>& operator=(const HashMap<Key, T, HASH>&);
|
||||
HashMap<Key, T, HASH>& operator=(HashMap<Key, T, HASH>&&);
|
||||
|
||||
ErrorOr<void> insert(const Key& key, const T& value) { return emplace(key, value); }
|
||||
ErrorOr<void> insert(const Key& key, T&& value) { return emplace(key, move(value)); }
|
||||
ErrorOr<void> insert(Key&& key, const T& value) { return emplace(move(key), value); }
|
||||
ErrorOr<void> insert(Key&& key, T&& value) { return emplace(move(key), move(value)); }
|
||||
ErrorOr<iterator> insert(const Key& key, const T& value) { return emplace(key, 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); }
|
||||
ErrorOr<iterator> insert(Key&& key, T&& value) { return emplace(move(key), move(value)); }
|
||||
|
||||
ErrorOr<void> insert_or_assign(const Key& key, const T& value) { return emplace_or_assign(key, value); }
|
||||
ErrorOr<void> insert_or_assign(const Key& key, T&& value) { return emplace_or_assign(key, move(value)); }
|
||||
ErrorOr<void> insert_or_assign(Key&& key, const T& value) { return emplace_or_assign(move(key), value); }
|
||||
ErrorOr<void> insert_or_assign(Key&& key, T&& value) { return emplace_or_assign(move(key), move(value)); }
|
||||
ErrorOr<iterator> insert_or_assign(const Key& key, const T& value) { return emplace_or_assign(key, value); }
|
||||
ErrorOr<iterator> insert_or_assign(const Key& key, T&& value) { return emplace_or_assign(key, move(value)); }
|
||||
ErrorOr<iterator> insert_or_assign(Key&& key, const T& value) { return emplace_or_assign(move(key), value); }
|
||||
ErrorOr<iterator> insert_or_assign(Key&& key, T&& value) { return emplace_or_assign(move(key), move(value)); }
|
||||
|
||||
template<typename... Args>
|
||||
ErrorOr<void> emplace(const Key& key, Args&&... args) requires is_constructible_v<T, Args...>
|
||||
ErrorOr<iterator> emplace(const Key& key, Args&&... args) requires is_constructible_v<T, Args...>
|
||||
{ return emplace(Key(key), forward<Args>(args)...); }
|
||||
template<typename... Args>
|
||||
ErrorOr<void> emplace(Key&&, Args&&...) requires is_constructible_v<T, Args...>;
|
||||
ErrorOr<iterator> emplace(Key&&, Args&&...) requires is_constructible_v<T, Args...>;
|
||||
|
||||
template<typename... Args>
|
||||
ErrorOr<void> emplace_or_assign(const Key& key, Args&&... args) requires is_constructible_v<T, Args...>
|
||||
ErrorOr<iterator> emplace_or_assign(const Key& key, Args&&... args) requires is_constructible_v<T, Args...>
|
||||
{ return emplace_or_assign(Key(key), forward<Args>(args)...); }
|
||||
template<typename... Args>
|
||||
ErrorOr<void> emplace_or_assign(Key&&, Args&&...) requires is_constructible_v<T, Args...>;
|
||||
ErrorOr<iterator> emplace_or_assign(Key&&, Args&&...) requires is_constructible_v<T, Args...>;
|
||||
|
||||
iterator begin() { return iterator(m_buckets.end(), m_buckets.begin()); }
|
||||
iterator end() { return iterator(m_buckets.end(), m_buckets.end()); }
|
||||
@@ -135,29 +141,35 @@ namespace BAN
|
||||
|
||||
template<typename Key, typename T, typename HASH>
|
||||
template<typename... Args>
|
||||
ErrorOr<void> HashMap<Key, T, HASH>::emplace(Key&& key, Args&&... args) requires is_constructible_v<T, Args...>
|
||||
ErrorOr<typename HashMap<Key, T, HASH>::iterator> HashMap<Key, T, HASH>::emplace(Key&& key, Args&&... args) requires is_constructible_v<T, Args...>
|
||||
{
|
||||
ASSERT(!contains(key));
|
||||
TRY(rebucket(m_size + 1));
|
||||
auto& bucket = get_bucket(key);
|
||||
TRY(bucket.emplace_back(move(key), forward<Args>(args)...));
|
||||
|
||||
auto bucket_it = get_bucket_iterator(key);
|
||||
TRY(bucket_it->emplace_back(move(key), forward<Args>(args)...));
|
||||
m_size++;
|
||||
return {};
|
||||
|
||||
return iterator(m_buckets.end(), bucket_it, prev(bucket_it->end(), 1));
|
||||
}
|
||||
|
||||
template<typename Key, typename T, typename HASH>
|
||||
template<typename... Args>
|
||||
ErrorOr<void> HashMap<Key, T, HASH>::emplace_or_assign(Key&& key, Args&&... args) requires is_constructible_v<T, Args...>
|
||||
ErrorOr<typename HashMap<Key, T, HASH>::iterator> HashMap<Key, T, HASH>::emplace_or_assign(Key&& key, Args&&... args) requires is_constructible_v<T, Args...>
|
||||
{
|
||||
if (empty())
|
||||
return emplace(move(key), forward<Args>(args)...);
|
||||
auto& bucket = get_bucket(key);
|
||||
for (Entry& entry : bucket)
|
||||
if (entry.key == key)
|
||||
return {};
|
||||
TRY(bucket.emplace_back(move(key), forward<Args>(args)...));
|
||||
m_size++;
|
||||
return {};
|
||||
|
||||
auto bucket_it = get_bucket_iterator(key);
|
||||
for (auto entry_it = bucket_it->begin(); entry_it != bucket_it->end(); entry_it++)
|
||||
{
|
||||
if (entry_it->key != key)
|
||||
continue;
|
||||
entry_it->value = T(forward<Args>(args)...);
|
||||
return iterator(m_buckets.end(), bucket_it, entry_it);
|
||||
}
|
||||
|
||||
return emplace(move(key), forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template<typename Key, typename T, typename HASH>
|
||||
@@ -197,7 +209,7 @@ namespace BAN
|
||||
for (Entry& entry : bucket)
|
||||
if (entry.key == key)
|
||||
return entry.value;
|
||||
ASSERT(false);
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
template<typename Key, typename T, typename HASH>
|
||||
@@ -208,7 +220,7 @@ namespace BAN
|
||||
for (const Entry& entry : bucket)
|
||||
if (entry.key == key)
|
||||
return entry.value;
|
||||
ASSERT(false);
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
template<typename Key, typename T, typename HASH>
|
||||
|
||||
89
BAN/include/BAN/Heap.h
Normal file
89
BAN/include/BAN/Heap.h
Normal file
@@ -0,0 +1,89 @@
|
||||
#pragma once
|
||||
|
||||
#include <BAN/Iterators.h>
|
||||
#include <BAN/Swap.h>
|
||||
#include <BAN/Traits.h>
|
||||
|
||||
namespace BAN
|
||||
{
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
template<typename It, typename Comp>
|
||||
void heapify_up(It begin, size_t index, Comp comp)
|
||||
{
|
||||
size_t parent = (index - 1) / 2;
|
||||
while (parent < index)
|
||||
{
|
||||
if (comp(*(begin + index), *(begin + parent)))
|
||||
break;
|
||||
swap(*(begin + parent), *(begin + index));
|
||||
index = parent;
|
||||
parent = (index - 1) / 2;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename It, typename Comp>
|
||||
void heapify_down(It begin, size_t index, size_t len, Comp comp)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
const size_t lchild = 2 * index + 1;
|
||||
const size_t rchild = 2 * index + 2;
|
||||
|
||||
size_t child = 0;
|
||||
if (lchild < len && !comp(*(begin + lchild), *(begin + index)))
|
||||
{
|
||||
if (rchild < len && !comp(*(begin + rchild), *(begin + lchild)))
|
||||
child = rchild;
|
||||
else
|
||||
child = lchild;
|
||||
}
|
||||
else if (rchild < len && !comp(*(begin + rchild), *(begin + index)))
|
||||
child = rchild;
|
||||
else
|
||||
break;
|
||||
|
||||
swap(*(begin + child), *(begin + index));
|
||||
index = child;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
template<typename It, typename Comp = less<it_value_type_t<It>>>
|
||||
void make_heap(It begin, It end, Comp comp = {})
|
||||
{
|
||||
const size_t len = distance(begin, end);
|
||||
if (len <= 1)
|
||||
return;
|
||||
|
||||
size_t index = (len - 2) / 2;
|
||||
while (index < len)
|
||||
detail::heapify_down(begin, index--, len, comp);
|
||||
}
|
||||
|
||||
template<typename It, typename Comp = less<it_value_type_t<It>>>
|
||||
void push_heap(It begin, It end, Comp comp = {})
|
||||
{
|
||||
const size_t len = distance(begin, end);
|
||||
detail::heapify_up(begin, len - 1, comp);
|
||||
}
|
||||
|
||||
template<typename It, typename Comp = less<it_value_type_t<It>>>
|
||||
void pop_heap(It begin, It end, Comp comp = {})
|
||||
{
|
||||
const size_t len = distance(begin, end);
|
||||
swap(*begin, *(begin + len - 1));
|
||||
detail::heapify_down(begin, 0, len - 1, comp);
|
||||
}
|
||||
|
||||
template<typename It, typename Comp = less<it_value_type_t<It>>>
|
||||
void sort_heap(It begin, It end, Comp comp = {})
|
||||
{
|
||||
while (begin != end)
|
||||
pop_heap(begin, end--, comp);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -9,6 +9,10 @@ namespace BAN
|
||||
|
||||
struct IPv4Address
|
||||
{
|
||||
constexpr IPv4Address()
|
||||
: IPv4Address(0)
|
||||
{ }
|
||||
|
||||
constexpr IPv4Address(uint32_t u32_address)
|
||||
{
|
||||
raw = u32_address;
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
#include <BAN/Limits.h>
|
||||
#include <BAN/Numbers.h>
|
||||
#include <BAN/Traits.h>
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <float.h>
|
||||
|
||||
namespace BAN::Math
|
||||
{
|
||||
|
||||
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>
|
||||
@@ -36,12 +36,11 @@ namespace BAN::Math
|
||||
template<integral T>
|
||||
inline constexpr T gcd(T a, T b)
|
||||
{
|
||||
T t;
|
||||
while (b)
|
||||
{
|
||||
t = b;
|
||||
T temp = b;
|
||||
b = a % b;
|
||||
a = t;
|
||||
a = temp;
|
||||
}
|
||||
return a;
|
||||
}
|
||||
@@ -59,86 +58,408 @@ namespace BAN::Math
|
||||
}
|
||||
|
||||
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 (value & (value - 1)) == 0;
|
||||
return (x & (x - 1)) == 0;
|
||||
}
|
||||
|
||||
template<BAN::integral T>
|
||||
static constexpr bool will_multiplication_overflow(T a, T b)
|
||||
template<integral T>
|
||||
__attribute__((always_inline))
|
||||
inline constexpr bool will_multiplication_overflow(T a, T b)
|
||||
{
|
||||
if (a == 0 || b == 0)
|
||||
return false;
|
||||
if ((a > 0) == (b > 0))
|
||||
return a > BAN::numeric_limits<T>::max() / b;
|
||||
else
|
||||
return a < BAN::numeric_limits<T>::min() / b;
|
||||
T dummy;
|
||||
return __builtin_mul_overflow(a, b, &dummy);
|
||||
}
|
||||
|
||||
template<BAN::integral T>
|
||||
static constexpr bool will_addition_overflow(T a, T b)
|
||||
template<integral T>
|
||||
__attribute__((always_inline))
|
||||
inline constexpr bool will_addition_overflow(T a, T b)
|
||||
{
|
||||
if (a > 0 && b > 0)
|
||||
return a > BAN::numeric_limits<T>::max() - b;
|
||||
if (a < 0 && b < 0)
|
||||
return a < BAN::numeric_limits<T>::min() - b;
|
||||
return false;
|
||||
T dummy;
|
||||
return __builtin_add_overflow(a, b, &dummy);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
requires is_same_v<T, unsigned int> || is_same_v<T, unsigned long> || is_same_v<T, unsigned long long>
|
||||
inline constexpr T ilog2(T value)
|
||||
inline constexpr T ilog2(T x)
|
||||
{
|
||||
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>)
|
||||
return sizeof(T) * 8 - __builtin_clzl(value) - 1;
|
||||
return sizeof(T) * 8 - __builtin_clzll(value) - 1;
|
||||
return sizeof(T) * 8 - __builtin_clzl(x) - 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>
|
||||
inline constexpr T log2(T value)
|
||||
inline constexpr T ceil(T x)
|
||||
{
|
||||
T result;
|
||||
asm volatile("fyl2x" : "=t"(result) : "0"(value), "u"((T)1.0) : "st(1)");
|
||||
return result;
|
||||
if constexpr(is_same_v<T, float>)
|
||||
return __builtin_ceilf(x);
|
||||
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>
|
||||
inline constexpr T log10(T value)
|
||||
inline constexpr T round(T x)
|
||||
{
|
||||
constexpr T INV_LOG_2_10 = 0.3010299956639811952137388947244930267681898814621085413104274611;
|
||||
T result;
|
||||
asm volatile("fyl2x" : "=t"(result) : "0"(value), "u"(INV_LOG_2_10) : "st(1)");
|
||||
return result;
|
||||
if (x == (T)0.0)
|
||||
return x;
|
||||
if (x > (T)0.0)
|
||||
return floor<T>(x + (T)0.5);
|
||||
return ceil<T>(x - (T)0.5);
|
||||
}
|
||||
|
||||
template<floating_point T>
|
||||
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>
|
||||
inline constexpr T pow(T base, T exp)
|
||||
inline constexpr T rint(T x)
|
||||
{
|
||||
T result;
|
||||
asm volatile(
|
||||
"fyl2x;"
|
||||
asm("frndint" : "+t"(x));
|
||||
return x;
|
||||
}
|
||||
|
||||
template<floating_point T>
|
||||
inline constexpr T fmod(T a, T b)
|
||||
{
|
||||
asm(
|
||||
"1:"
|
||||
"fprem;"
|
||||
"fnstsw %%ax;"
|
||||
"testb $4, %%ah;"
|
||||
"jne 1b;"
|
||||
: "+t"(a)
|
||||
: "u"(b)
|
||||
: "ax", "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;"
|
||||
"fld %%st(1);"
|
||||
"fprem;"
|
||||
"f2xm1;"
|
||||
"faddp;"
|
||||
"fscale;"
|
||||
"fxch %%st(1);"
|
||||
"fstp %%st;"
|
||||
: "=t"(result)
|
||||
: "0"(base), "u"(exp)
|
||||
"fstp %%st(1);"
|
||||
: "+t"(x)
|
||||
);
|
||||
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
|
||||
{
|
||||
#if defined(__is_kernel)
|
||||
static constexpr void*(&allocator)(size_t) = kmalloc;
|
||||
static constexpr void(&deallocator)(void*) = kfree;
|
||||
static constexpr void*(*allocator)(size_t) = kmalloc;
|
||||
static constexpr void*(*reallocator)(void*, size_t) = nullptr;
|
||||
static constexpr void(*deallocator)(void*) = kfree;
|
||||
#else
|
||||
static constexpr void*(&allocator)(size_t) = malloc;
|
||||
static constexpr void(&deallocator)(void*) = free;
|
||||
static constexpr void*(*allocator)(size_t) = malloc;
|
||||
static constexpr void*(*reallocator)(void*, size_t) = realloc;
|
||||
static constexpr void(*deallocator)(void*) = free;
|
||||
#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>;
|
||||
|
||||
}
|
||||
@@ -1,10 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#if __has_include(<new>)
|
||||
#include <new>
|
||||
#else
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef __banan_os__
|
||||
inline void* operator new(size_t, void* addr) { return addr; }
|
||||
inline void* operator new[](size_t, void* addr) { return addr; }
|
||||
#else
|
||||
#include <new>
|
||||
#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;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <BAN/Heap.h>
|
||||
#include <BAN/Math.h>
|
||||
#include <BAN/Swap.h>
|
||||
#include <BAN/Traits.h>
|
||||
@@ -8,7 +9,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 exchange_sort(It begin, It end, Comp comp = {})
|
||||
{
|
||||
for (It lhs = begin; lhs != end; ++lhs)
|
||||
@@ -42,7 +43,7 @@ namespace BAN::sort
|
||||
|
||||
}
|
||||
|
||||
template<typename It, typename Comp = less<typename It::value_type>>
|
||||
template<typename It, typename Comp = less<it_value_type_t<It>>>
|
||||
void quick_sort(It begin, It end, Comp comp = {})
|
||||
{
|
||||
if (distance(begin, end) <= 1)
|
||||
@@ -52,14 +53,14 @@ namespace BAN::sort
|
||||
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 = {})
|
||||
{
|
||||
if (distance(begin, end) <= 1)
|
||||
return;
|
||||
for (It it1 = next(begin, 1); it1 != end; ++it1)
|
||||
{
|
||||
typename It::value_type x = move(*it1);
|
||||
auto x = move(*it1);
|
||||
It it2 = it1;
|
||||
for (; it2 != begin && comp(x, *prev(it2, 1)); --it2)
|
||||
*it2 = move(*prev(it2, 1));
|
||||
@@ -67,83 +68,7 @@ namespace BAN::sort
|
||||
}
|
||||
}
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
template<typename It, typename Comp>
|
||||
void push_heap(It begin, size_t hole_index, size_t top_index, typename It::value_type value, Comp comp)
|
||||
{
|
||||
size_t parent = (hole_index - 1) / 2;
|
||||
while (hole_index > top_index && comp(*next(begin, parent), value))
|
||||
{
|
||||
*next(begin, hole_index) = move(*next(begin, parent));
|
||||
hole_index = parent;
|
||||
parent = (hole_index - 1) / 2;
|
||||
}
|
||||
*next(begin, hole_index) = move(value);
|
||||
}
|
||||
|
||||
template<typename It, typename Comp>
|
||||
void adjust_heap(It begin, size_t hole_index, size_t len, typename It::value_type value, Comp comp)
|
||||
{
|
||||
const size_t top_index = hole_index;
|
||||
size_t child = hole_index;
|
||||
while (child < (len - 1) / 2)
|
||||
{
|
||||
child = 2 * (child + 1);
|
||||
if (comp(*next(begin, child), *next(begin, child - 1)))
|
||||
child--;
|
||||
*next(begin, hole_index) = move(*next(begin, child));
|
||||
hole_index = child;
|
||||
}
|
||||
if (len % 2 == 0 && child == (len - 2) / 2)
|
||||
{
|
||||
child = 2 * (child + 1);
|
||||
*next(begin, hole_index) = move(*next(begin, child - 1));
|
||||
hole_index = child - 1;
|
||||
}
|
||||
push_heap(begin, hole_index, top_index, move(value), comp);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
template<typename It, typename Comp = less<typename It::value_type>>
|
||||
void make_heap(It begin, It end, Comp comp = {})
|
||||
{
|
||||
const size_t len = distance(begin, end);
|
||||
if (len <= 1)
|
||||
return;
|
||||
|
||||
size_t parent = (len - 2) / 2;
|
||||
while (true)
|
||||
{
|
||||
detail::adjust_heap(begin, parent, len, move(*next(begin, parent)), comp);
|
||||
|
||||
if (parent == 0)
|
||||
break;
|
||||
|
||||
parent--;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename It, typename Comp = less<typename It::value_type>>
|
||||
void sort_heap(It begin, It end, Comp comp = {})
|
||||
{
|
||||
const size_t len = distance(begin, end);
|
||||
if (len <= 1)
|
||||
return;
|
||||
|
||||
size_t last = len;
|
||||
while (last > 1)
|
||||
{
|
||||
last--;
|
||||
typename It::value_type x = move(*next(begin, last));
|
||||
*next(begin, last) = move(*begin);
|
||||
detail::adjust_heap(begin, 0, last, move(x), comp);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename It, typename Comp = less<typename It::value_type>>
|
||||
template<typename It, typename Comp = less<it_value_type_t<It>>>
|
||||
void heap_sort(It begin, It end, Comp comp = {})
|
||||
{
|
||||
make_heap(begin, end, comp);
|
||||
@@ -167,7 +92,7 @@ namespace BAN::sort
|
||||
|
||||
}
|
||||
|
||||
template<typename It, typename Comp = less<typename It::value_type>>
|
||||
template<typename It, typename Comp = less<it_value_type_t<It>>>
|
||||
void intro_sort(It begin, It end, Comp comp = {})
|
||||
{
|
||||
const size_t len = distance(begin, end);
|
||||
@@ -190,10 +115,10 @@ namespace BAN::sort
|
||||
}
|
||||
|
||||
template<typename It, size_t radix = 256>
|
||||
requires is_unsigned_v<typename It::value_type> && (radix > 0 && (radix & (radix - 1)) == 0)
|
||||
requires is_unsigned_v<it_value_type_t<It>> && (radix > 0 && (radix & (radix - 1)) == 0)
|
||||
BAN::ErrorOr<void> radix_sort(It begin, It end)
|
||||
{
|
||||
using value_type = typename It::value_type;
|
||||
using value_type = it_value_type_t<It>;
|
||||
|
||||
const size_t len = distance(begin, end);
|
||||
if (len <= 1)
|
||||
@@ -231,7 +156,7 @@ namespace BAN::sort
|
||||
return {};
|
||||
}
|
||||
|
||||
template<typename It, typename Comp = less<typename It::value_type>>
|
||||
template<typename It, typename Comp = less<it_value_type_t<It>>>
|
||||
void sort(It begin, It end, Comp comp = {})
|
||||
{
|
||||
return intro_sort(begin, end, comp);
|
||||
|
||||
@@ -69,7 +69,6 @@ namespace BAN
|
||||
|
||||
value_type* data() const
|
||||
{
|
||||
ASSERT(m_data);
|
||||
return m_data;
|
||||
}
|
||||
|
||||
@@ -84,7 +83,6 @@ namespace BAN
|
||||
|
||||
Span slice(size_type start, size_type length = ~size_type(0)) const
|
||||
{
|
||||
ASSERT(m_data);
|
||||
ASSERT(start <= m_size);
|
||||
if (length == ~size_type(0))
|
||||
length = m_size - start;
|
||||
|
||||
@@ -14,6 +14,7 @@ namespace BAN
|
||||
{
|
||||
public:
|
||||
using size_type = size_t;
|
||||
using value_type = char;
|
||||
using iterator = IteratorSimple<char, String>;
|
||||
using const_iterator = ConstIteratorSimple<char, String>;
|
||||
static constexpr size_type sso_capacity = 15;
|
||||
@@ -352,10 +353,9 @@ namespace BAN::Formatter
|
||||
{
|
||||
|
||||
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++)
|
||||
putc(string[i]);
|
||||
print_argument(putc, string.sv(), format);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ namespace BAN
|
||||
{
|
||||
public:
|
||||
using size_type = size_t;
|
||||
using value_type = char;
|
||||
using const_iterator = ConstIteratorSimple<char, StringView>;
|
||||
|
||||
public:
|
||||
@@ -21,7 +22,8 @@ namespace BAN
|
||||
constexpr StringView(const char* string, size_type len = -1)
|
||||
{
|
||||
if (len == size_type(-1))
|
||||
len = strlen(string);
|
||||
for (len = 0; string[len];)
|
||||
len++;
|
||||
m_data = string;
|
||||
m_size = len;
|
||||
}
|
||||
@@ -245,10 +247,12 @@ namespace BAN::Formatter
|
||||
{
|
||||
|
||||
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++)
|
||||
putc(sv[i]);
|
||||
for (int i = sv.size(); i < format.fill; i++)
|
||||
putc(' ');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -61,6 +61,9 @@ namespace BAN
|
||||
template<typename T> struct is_move_constructible { static constexpr bool value = is_constructible_v<T, T&&>; };
|
||||
template<typename T> inline constexpr bool is_move_constructible_v = is_move_constructible<T>::value;
|
||||
|
||||
template<typename T> struct is_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> inline constexpr bool is_integral_v = is_integral<T>::value;
|
||||
template<typename T> concept integral = is_integral_v<T>;
|
||||
@@ -90,6 +93,9 @@ 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> inline constexpr bool is_base_of_v = is_base_of<Base, Derived>::value;
|
||||
|
||||
template<typename T> struct is_pod { static constexpr bool value = __is_pod(T); };
|
||||
template<typename T> inline constexpr bool is_pod_v = is_pod<T>::value;
|
||||
|
||||
namespace detail
|
||||
{
|
||||
template<typename T, bool = is_arithmetic_v<T>> struct is_signed { static constexpr bool value = T(-1) < T(0); };
|
||||
@@ -136,6 +142,10 @@ namespace BAN
|
||||
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 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; } };
|
||||
|
||||
@@ -18,7 +18,7 @@ namespace BAN::UTF8
|
||||
return 3;
|
||||
if ((first_byte & 0xF8) == 0xF0)
|
||||
return 4;
|
||||
return 0;
|
||||
return UTF8::invalid;
|
||||
}
|
||||
|
||||
template<typename T> requires (sizeof(T) == 1)
|
||||
@@ -76,6 +76,8 @@ namespace BAN::UTF8
|
||||
}
|
||||
}
|
||||
|
||||
*ptr = '\0';
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -126,6 +126,7 @@ namespace BAN
|
||||
Variant(Variant&& other)
|
||||
: m_index(other.m_index)
|
||||
{
|
||||
if (other.has_value())
|
||||
detail::move_construct<Ts...>(other.m_index, other.m_storage, m_storage);
|
||||
other.clear();
|
||||
}
|
||||
@@ -133,6 +134,7 @@ namespace BAN
|
||||
Variant(const Variant& other)
|
||||
: m_index(other.m_index)
|
||||
{
|
||||
if (other.has_value())
|
||||
detail::copy_construct<Ts...>(other.m_index, other.m_storage, m_storage);
|
||||
}
|
||||
|
||||
@@ -157,11 +159,12 @@ namespace BAN
|
||||
|
||||
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);
|
||||
else
|
||||
{
|
||||
clear();
|
||||
if (other.has_value())
|
||||
detail::move_construct<Ts...>(other.m_index, other.m_storage, m_storage);
|
||||
m_index = other.m_index;
|
||||
}
|
||||
@@ -171,11 +174,12 @@ namespace BAN
|
||||
|
||||
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);
|
||||
else
|
||||
{
|
||||
clear();
|
||||
if (other.has_value())
|
||||
detail::copy_construct<Ts...>(other.m_index, other.m_storage, m_storage);
|
||||
m_index = other.m_index;
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@ namespace BAN
|
||||
bool contains(const T&) const;
|
||||
|
||||
Span<T> span() { return Span(m_data, m_size); }
|
||||
const Span<T> span() const { return Span(m_data, m_size); }
|
||||
Span<const T> span() const { return Span(m_data, m_size); }
|
||||
|
||||
const T& operator[](size_type) const;
|
||||
T& operator[](size_type);
|
||||
@@ -381,10 +381,35 @@ namespace BAN
|
||||
template<typename T>
|
||||
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)
|
||||
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)
|
||||
return Error::from_errno(ENOMEM);
|
||||
for (size_type i = 0; i < m_size; i++)
|
||||
@@ -394,6 +419,8 @@ namespace BAN
|
||||
}
|
||||
BAN::deallocator(m_data);
|
||||
m_data = new_data;
|
||||
}
|
||||
|
||||
m_capacity = new_cap;
|
||||
return {};
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace BAN
|
||||
class WeakLink : public RefCounted<WeakLink<T>>
|
||||
{
|
||||
public:
|
||||
RefPtr<T> try_lock()
|
||||
RefPtr<T> try_lock() const
|
||||
{
|
||||
#if __is_kernel
|
||||
Kernel::SpinLockGuard _(m_weak_lock);
|
||||
@@ -44,7 +44,7 @@ namespace BAN
|
||||
private:
|
||||
T* m_ptr;
|
||||
#if __is_kernel
|
||||
Kernel::SpinLock m_weak_lock;
|
||||
mutable Kernel::SpinLock m_weak_lock;
|
||||
#endif
|
||||
friend class RefPtr<WeakLink<T>>;
|
||||
};
|
||||
@@ -99,7 +99,7 @@ namespace BAN
|
||||
return *this;
|
||||
}
|
||||
|
||||
RefPtr<T> lock()
|
||||
RefPtr<T> lock() const
|
||||
{
|
||||
if (m_link)
|
||||
return m_link->try_lock();
|
||||
|
||||
@@ -4,12 +4,8 @@ if (NOT ${CMAKE_SYSTEM_NAME} STREQUAL "banan-os")
|
||||
message(FATAL_ERROR "CMAKE_SYSTEM_NAME is not banan-os")
|
||||
endif ()
|
||||
|
||||
set(BANAN_ENABLE_SSE 1)
|
||||
|
||||
project(banan-os CXX C ASM)
|
||||
|
||||
set(BANAN_BASE_SYSROOT ${CMAKE_SOURCE_DIR}/base-sysroot.tar.gz)
|
||||
|
||||
set(BANAN_INCLUDE ${BANAN_SYSROOT}/usr/include)
|
||||
set(BANAN_LIB ${BANAN_SYSROOT}/usr/lib)
|
||||
set(BANAN_BIN ${BANAN_SYSROOT}/usr/bin)
|
||||
@@ -31,17 +27,14 @@ set(BUILD_SHARED_LIBS True)
|
||||
|
||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||
|
||||
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}")
|
||||
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}")
|
||||
|
||||
# include headers of ${library} to ${target}
|
||||
function(banan_include_headers target library)
|
||||
target_include_directories(${target} PRIVATE $<TARGET_PROPERTY:${library},SOURCE_DIR>/include)
|
||||
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} PRIVATE ${library})
|
||||
target_link_libraries(${target} PUBLIC ${library})
|
||||
banan_include_headers(${target} ${library})
|
||||
endfunction()
|
||||
|
||||
@@ -59,8 +52,3 @@ add_subdirectory(kernel)
|
||||
add_subdirectory(bootloader)
|
||||
add_subdirectory(BAN)
|
||||
add_subdirectory(userspace)
|
||||
|
||||
add_custom_target(sysroot
|
||||
COMMAND ${CMAKE_COMMAND} -E make_directory ${BANAN_SYSROOT}
|
||||
COMMAND cd ${BANAN_SYSROOT} && tar xf ${BANAN_BASE_SYSROOT}
|
||||
)
|
||||
|
||||
17
README.md
17
README.md
@@ -9,6 +9,8 @@ This is my hobby operating system written in C++. Currently supports x86\_64 and
|
||||
|
||||
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
|
||||
@@ -20,8 +22,8 @@ You can find a live demo [here](https://bananymous.com/banan-os)
|
||||
- [x] AML interpreter (partial)
|
||||
- [x] Basic graphical environment
|
||||
- [x] Terminal emulator
|
||||
- [ ] Task bar
|
||||
- [ ] Program launcher
|
||||
- [x] Status bar
|
||||
- [x] Program launcher
|
||||
- [ ] Some nice apps
|
||||
- [x] ELF dynamic linking
|
||||
- [x] copy-on-write memory
|
||||
@@ -32,13 +34,18 @@ You can find a live demo [here](https://bananymous.com/banan-os)
|
||||
- [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
|
||||
- [ ] Hubs
|
||||
- [ ] Mass storage
|
||||
- [x] Mass storage
|
||||
- [x] Hubs
|
||||
- [ ] ...
|
||||
- [ ] virtio devices (network, storage)
|
||||
|
||||
@@ -111,6 +118,8 @@ To change the bootloader you can set environment variable BANAN\_BOOTLOADER; sup
|
||||
|
||||
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.
|
||||
```sh
|
||||
./bos image-full
|
||||
|
||||
Binary file not shown.
@@ -84,4 +84,4 @@ command_line:
|
||||
# 100 character command line
|
||||
command_line_buffer:
|
||||
.ascii "root=/dev/sda2"
|
||||
.skip 100 - 28
|
||||
.skip 100 - (. - command_line_buffer)
|
||||
|
||||
@@ -306,20 +306,8 @@ memset32:
|
||||
movw $GDT_DATA32, %dx
|
||||
movw %dx, %es
|
||||
|
||||
movl %ecx, %edx
|
||||
|
||||
andl $3, %ecx
|
||||
rep stosb %es:(%edi)
|
||||
|
||||
movl %edx, %ecx
|
||||
shrl $2, %ecx
|
||||
|
||||
movb %al, %ah
|
||||
movw %ax, %dx
|
||||
shll $16, %eax
|
||||
movw %dx, %ax
|
||||
rep stosl %es:(%edi)
|
||||
|
||||
ljmpl $GDT_CODE16, $.memset32_pmode16
|
||||
|
||||
.code16
|
||||
@@ -370,14 +358,8 @@ memcpy32:
|
||||
movw %dx, %ds
|
||||
movw %dx, %es
|
||||
|
||||
movl %ecx, %edx
|
||||
andl $3, %ecx
|
||||
rep movsb %ds:(%esi), %es:(%edi)
|
||||
|
||||
movl %edx, %ecx
|
||||
shrl $2, %ecx
|
||||
rep movsl %ds:(%esi), %es:(%edi)
|
||||
|
||||
ljmpl $GDT_CODE16, $.memcpy32_pmode16
|
||||
|
||||
.code16
|
||||
|
||||
@@ -1,17 +1,16 @@
|
||||
set(KERNEL_SOURCES
|
||||
font/prefs.psf.o
|
||||
kernel/ACPI/ACPI.cpp
|
||||
kernel/ACPI/AML.cpp
|
||||
kernel/ACPI/AML/Field.cpp
|
||||
kernel/ACPI/AML/Integer.cpp
|
||||
kernel/ACPI/AML/NamedObject.cpp
|
||||
kernel/ACPI/AML/Namespace.cpp
|
||||
kernel/ACPI/AML/Node.cpp
|
||||
kernel/ACPI/AML/Package.cpp
|
||||
kernel/ACPI/AML/Register.cpp
|
||||
kernel/ACPI/AML/Scope.cpp
|
||||
kernel/ACPI/AML/String.cpp
|
||||
kernel/ACPI/AML/OpRegion.cpp
|
||||
kernel/ACPI/BatterySystem.cpp
|
||||
kernel/ACPI/EmbeddedController.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/CPUID.cpp
|
||||
kernel/Credentials.cpp
|
||||
@@ -23,8 +22,10 @@ set(KERNEL_SOURCES
|
||||
kernel/Device/RandomDevice.cpp
|
||||
kernel/Device/ZeroDevice.cpp
|
||||
kernel/ELF.cpp
|
||||
kernel/Epoll.cpp
|
||||
kernel/Errors.cpp
|
||||
kernel/FS/DevFS/FileSystem.cpp
|
||||
kernel/FS/EventFD.cpp
|
||||
kernel/FS/Ext2/FileSystem.cpp
|
||||
kernel/FS/Ext2/Inode.cpp
|
||||
kernel/FS/FAT/FileSystem.cpp
|
||||
@@ -36,6 +37,7 @@ set(KERNEL_SOURCES
|
||||
kernel/FS/ProcFS/Inode.cpp
|
||||
kernel/FS/TmpFS/FileSystem.cpp
|
||||
kernel/FS/TmpFS/Inode.cpp
|
||||
kernel/FS/USTARModule.cpp
|
||||
kernel/FS/VirtualFileSystem.cpp
|
||||
kernel/GDT.cpp
|
||||
kernel/IDT.cpp
|
||||
@@ -48,6 +50,8 @@ set(KERNEL_SOURCES
|
||||
kernel/Interruptable.cpp
|
||||
kernel/InterruptController.cpp
|
||||
kernel/kernel.cpp
|
||||
kernel/Lock/SpinLock.cpp
|
||||
kernel/Memory/ByteRingBuffer.cpp
|
||||
kernel/Memory/DMARegion.cpp
|
||||
kernel/Memory/FileBackedRegion.cpp
|
||||
kernel/Memory/Heap.cpp
|
||||
@@ -61,6 +65,7 @@ set(KERNEL_SOURCES
|
||||
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
|
||||
@@ -77,7 +82,6 @@ set(KERNEL_SOURCES
|
||||
kernel/Processor.cpp
|
||||
kernel/Random.cpp
|
||||
kernel/Scheduler.cpp
|
||||
kernel/ThreadBlocker.cpp
|
||||
kernel/SSP.cpp
|
||||
kernel/Storage/ATA/AHCI/Controller.cpp
|
||||
kernel/Storage/ATA/AHCI/Device.cpp
|
||||
@@ -89,22 +93,31 @@ set(KERNEL_SOURCES
|
||||
kernel/Storage/NVMe/Namespace.cpp
|
||||
kernel/Storage/NVMe/Queue.cpp
|
||||
kernel/Storage/Partition.cpp
|
||||
kernel/Storage/SCSI.cpp
|
||||
kernel/Storage/StorageDevice.cpp
|
||||
kernel/Syscall.cpp
|
||||
kernel/Terminal/FramebufferTerminal.cpp
|
||||
kernel/Terminal/PseudoTerminal.cpp
|
||||
kernel/Terminal/Serial.cpp
|
||||
kernel/Terminal/TerminalDriver.cpp
|
||||
kernel/Terminal/TextModeTerminal.cpp
|
||||
kernel/Terminal/TTY.cpp
|
||||
kernel/Terminal/VirtualTTY.cpp
|
||||
kernel/Thread.cpp
|
||||
kernel/ThreadBlocker.cpp
|
||||
kernel/Timer/HPET.cpp
|
||||
kernel/Timer/PIT.cpp
|
||||
kernel/Timer/RTC.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
|
||||
@@ -126,6 +139,8 @@ if("${BANAN_ARCH}" STREQUAL "x86_64")
|
||||
arch/x86_64/Signal.S
|
||||
arch/x86_64/Syscall.S
|
||||
arch/x86_64/Thread.S
|
||||
arch/x86_64/User.S
|
||||
arch/x86_64/Yield.S
|
||||
)
|
||||
elseif("${BANAN_ARCH}" STREQUAL "i686")
|
||||
set(KERNEL_SOURCES
|
||||
@@ -136,6 +151,8 @@ elseif("${BANAN_ARCH}" STREQUAL "i686")
|
||||
arch/i686/Signal.S
|
||||
arch/i686/Syscall.S
|
||||
arch/i686/Thread.S
|
||||
arch/i686/User.S
|
||||
arch/i686/Yield.S
|
||||
)
|
||||
else()
|
||||
message(FATAL_ERROR "unsupported architecure ${BANAN_ARCH}")
|
||||
@@ -151,6 +168,16 @@ set(BAN_SOURCES
|
||||
set(KLIBC_SOURCES
|
||||
klibc/ctype.cpp
|
||||
klibc/string.cpp
|
||||
|
||||
# Ehhh don't do this but for now libc uses the same stuff kernel can use
|
||||
# This won't work after libc starts using sse implemetations tho
|
||||
../userspace/libraries/LibC/arch/${BANAN_ARCH}/string.S
|
||||
)
|
||||
|
||||
set(LIBDEFLATE_SOURCE
|
||||
../userspace/libraries/LibDEFLATE/Compressor.cpp
|
||||
../userspace/libraries/LibDEFLATE/Decompressor.cpp
|
||||
../userspace/libraries/LibDEFLATE/HuffmanTree.cpp
|
||||
)
|
||||
|
||||
set(LIBFONT_SOURCES
|
||||
@@ -163,19 +190,25 @@ set(LIBINPUT_SOURCE
|
||||
../userspace/libraries/LibInput/KeyEvent.cpp
|
||||
)
|
||||
|
||||
set(LIBQR_SOURCE
|
||||
../userspace/libraries/LibQR/QRCode.cpp
|
||||
)
|
||||
|
||||
set(KERNEL_SOURCES
|
||||
${KERNEL_SOURCES}
|
||||
${BAN_SOURCES}
|
||||
${KLIBC_SOURCES}
|
||||
${LIBDEFLATE_SOURCE}
|
||||
${LIBFONT_SOURCES}
|
||||
${LIBINPUT_SOURCE}
|
||||
${LIBQR_SOURCE}
|
||||
)
|
||||
|
||||
add_executable(kernel ${KERNEL_SOURCES})
|
||||
|
||||
target_compile_definitions(kernel PRIVATE __is_kernel)
|
||||
target_compile_definitions(kernel PRIVATE __arch=${BANAN_ARCH})
|
||||
target_compile_definitions(kernel PRIVATE __enable_sse=${BANAN_ENABLE_SSE})
|
||||
target_compile_definitions(kernel PRIVATE LIBDEFLATE_AVOID_STACK=1)
|
||||
|
||||
target_compile_options(kernel PRIVATE
|
||||
-O2 -g
|
||||
@@ -229,9 +262,11 @@ add_custom_command(
|
||||
|
||||
banan_include_headers(kernel ban)
|
||||
banan_include_headers(kernel libc)
|
||||
banan_include_headers(kernel libfont)
|
||||
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)
|
||||
@@ -245,7 +280,7 @@ endif()
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT font/prefs.psf.o
|
||||
COMMAND cd ${CMAKE_CURRENT_SOURCE_DIR} && objcopy -O ${ELF_FORMAT} -B i386 -I binary font/prefs.psf ${CMAKE_CURRENT_BINARY_DIR}/font/prefs.psf.o
|
||||
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 ")
|
||||
|
||||
@@ -206,6 +206,7 @@ namespace Kernel
|
||||
{
|
||||
ASSERT(s_kernel);
|
||||
ASSERT(paddr);
|
||||
ASSERT(paddr % PAGE_SIZE == 0);
|
||||
|
||||
ASSERT(s_fast_page_lock.current_processor_has_lock());
|
||||
|
||||
@@ -220,7 +221,7 @@ namespace Kernel
|
||||
ASSERT(!(pt[pte] & Flags::Present));
|
||||
pt[pte] = paddr | Flags::ReadWrite | Flags::Present;
|
||||
|
||||
invalidate(fast_page(), false);
|
||||
asm volatile("invlpg (%0)" :: "r"(fast_page()) : "memory");
|
||||
}
|
||||
|
||||
void PageTable::unmap_fast_page()
|
||||
@@ -240,7 +241,7 @@ namespace Kernel
|
||||
ASSERT(pt[pte] & Flags::Present);
|
||||
pt[pte] = 0;
|
||||
|
||||
invalidate(fast_page(), false);
|
||||
asm volatile("invlpg (%0)" :: "r"(fast_page()) : "memory");
|
||||
}
|
||||
|
||||
BAN::ErrorOr<PageTable*> PageTable::create_userspace()
|
||||
@@ -272,6 +273,9 @@ namespace Kernel
|
||||
|
||||
PageTable::~PageTable()
|
||||
{
|
||||
if (m_highest_paging_struct == 0)
|
||||
return;
|
||||
|
||||
uint64_t* pdpt = reinterpret_cast<uint64_t*>(P2V(m_highest_paging_struct));
|
||||
|
||||
for (uint32_t pdpte = 0; pdpte < 3; pdpte++)
|
||||
@@ -310,7 +314,8 @@ namespace Kernel
|
||||
.type = Processor::SMPMessage::Type::FlushTLB,
|
||||
.flush_tlb = {
|
||||
.vaddr = vaddr,
|
||||
.page_count = 1
|
||||
.page_count = 1,
|
||||
.page_table = vaddr < KERNEL_OFFSET ? this : nullptr,
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -339,7 +344,11 @@ namespace Kernel
|
||||
uint64_t* pd = reinterpret_cast<uint64_t*>(P2V(pdpt[pdpte] & PAGE_ADDR_MASK));
|
||||
uint64_t* pt = reinterpret_cast<uint64_t*>(P2V(pd[pde] & PAGE_ADDR_MASK));
|
||||
|
||||
const paddr_t old_paddr = pt[pte] & PAGE_ADDR_MASK;
|
||||
|
||||
pt[pte] = 0;
|
||||
|
||||
if (old_paddr != 0)
|
||||
invalidate(vaddr, send_smp_message);
|
||||
}
|
||||
|
||||
@@ -357,7 +366,8 @@ namespace Kernel
|
||||
.type = Processor::SMPMessage::Type::FlushTLB,
|
||||
.flush_tlb = {
|
||||
.vaddr = vaddr,
|
||||
.page_count = page_count
|
||||
.page_count = page_count,
|
||||
.page_table = vaddr < KERNEL_OFFSET ? this : nullptr,
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -413,8 +423,12 @@ namespace Kernel
|
||||
uwr_flags &= ~Flags::Present;
|
||||
|
||||
uint64_t* pt = reinterpret_cast<uint64_t*>(P2V(pd[pde] & PAGE_ADDR_MASK));
|
||||
|
||||
const paddr_t old_paddr = pt[pte] & PAGE_ADDR_MASK;
|
||||
|
||||
pt[pte] = paddr | uwr_flags | extra_flags;
|
||||
|
||||
if (old_paddr != 0)
|
||||
invalidate(vaddr, send_smp_message);
|
||||
}
|
||||
|
||||
@@ -434,7 +448,8 @@ namespace Kernel
|
||||
.type = Processor::SMPMessage::Type::FlushTLB,
|
||||
.flush_tlb = {
|
||||
.vaddr = vaddr,
|
||||
.page_count = page_count
|
||||
.page_count = page_count,
|
||||
.page_table = vaddr < KERNEL_OFFSET ? this : nullptr,
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -493,13 +508,13 @@ namespace Kernel
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PageTable::reserve_page(vaddr_t vaddr, bool only_free)
|
||||
bool PageTable::reserve_page(vaddr_t vaddr, bool only_free, bool send_smp_message)
|
||||
{
|
||||
SpinLockGuard _(m_lock);
|
||||
ASSERT(vaddr % PAGE_SIZE == 0);
|
||||
if (only_free && !is_page_free(vaddr))
|
||||
return false;
|
||||
map_page_at(0, vaddr, Flags::Reserved);
|
||||
map_page_at(0, vaddr, Flags::Reserved, MemoryType::Normal, send_smp_message);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -513,7 +528,15 @@ namespace Kernel
|
||||
if (only_free && !is_range_free(vaddr, bytes))
|
||||
return false;
|
||||
for (size_t offset = 0; offset < bytes; offset += PAGE_SIZE)
|
||||
reserve_page(vaddr + offset);
|
||||
reserve_page(vaddr + offset, true, false);
|
||||
Processor::broadcast_smp_message({
|
||||
.type = Processor::SMPMessage::Type::FlushTLB,
|
||||
.flush_tlb = {
|
||||
.vaddr = vaddr,
|
||||
.page_count = bytes / PAGE_SIZE,
|
||||
.page_table = vaddr < KERNEL_OFFSET ? this : nullptr,
|
||||
}
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,34 +2,72 @@
|
||||
|
||||
// stack contains
|
||||
// return address
|
||||
// return stack
|
||||
// return rflags
|
||||
// siginfo_t
|
||||
// signal number
|
||||
// signal handler
|
||||
|
||||
.global signal_trampoline
|
||||
signal_trampoline:
|
||||
pushl %esi // gregs
|
||||
pushl %edi
|
||||
pushl %edx
|
||||
pushl %ecx
|
||||
pushl %ebx
|
||||
pushl %eax
|
||||
pushl %ebp
|
||||
movl %esp, %ebp
|
||||
|
||||
pusha
|
||||
// FIXME: populate these
|
||||
xorl %eax, %eax
|
||||
pushl %eax // stack
|
||||
pushl %eax
|
||||
pushl %eax
|
||||
pushl %eax // sigset
|
||||
pushl %eax
|
||||
pushl %eax // link
|
||||
|
||||
movl 40(%esp), %edi
|
||||
movl 36(%esp), %eax
|
||||
movl %esp, %edx // ucontext
|
||||
leal 60(%esp), %esi // siginfo
|
||||
movl 56(%esp), %edi // signal number
|
||||
movl 52(%esp), %eax // handlers
|
||||
|
||||
// align stack to 16 bytes
|
||||
movl %esp, %ebx
|
||||
andl $0x0F, %ebx
|
||||
subl %ebx, %esp
|
||||
movl %esp, %ebp
|
||||
andl $-16, %esp
|
||||
|
||||
subl $12, %esp
|
||||
subl $512, %esp
|
||||
fxsave (%esp)
|
||||
|
||||
subl $4, %esp
|
||||
pushl %edx
|
||||
pushl %esi
|
||||
pushl %edi
|
||||
call *%eax
|
||||
addl $16, %esp
|
||||
|
||||
// restore stack
|
||||
addl %ebx, %esp
|
||||
popa
|
||||
fxrstor (%esp)
|
||||
addl $512, %esp
|
||||
|
||||
leave
|
||||
addl $8, %esp
|
||||
// restore stack
|
||||
movl %ebp, %esp
|
||||
addl $24, %esp
|
||||
|
||||
// restore registers
|
||||
popl %ebp
|
||||
popl %eax
|
||||
popl %ebx
|
||||
popl %ecx
|
||||
popl %edx
|
||||
popl %edi
|
||||
popl %esi
|
||||
|
||||
// skip handler, number, siginfo_t
|
||||
addl $44, %esp
|
||||
|
||||
// restore flags
|
||||
popf
|
||||
|
||||
movl (%esp), %esp
|
||||
|
||||
ret
|
||||
|
||||
@@ -1,12 +1,6 @@
|
||||
// arguments in EAX, EBX, ECX, EDX, ESI, EDI
|
||||
.global asm_syscall_handler
|
||||
asm_syscall_handler:
|
||||
# save segment registers
|
||||
pushw %ds
|
||||
pushw %es
|
||||
pushw %fs
|
||||
pushw %gs
|
||||
|
||||
# save general purpose registers
|
||||
pushl %ebx
|
||||
pushl %ecx
|
||||
@@ -14,16 +8,14 @@ asm_syscall_handler:
|
||||
pushl %edi
|
||||
pushl %esi
|
||||
pushl %ebp
|
||||
cld
|
||||
|
||||
# align stack
|
||||
movl %esp, %ebp
|
||||
subl $15, %esp
|
||||
andl $0xFFFFFFF0, %esp
|
||||
andl $-16, %esp
|
||||
|
||||
# push arguments
|
||||
subl $4, %esp
|
||||
pushl %ebp
|
||||
addl $32, (%esp)
|
||||
subl $8, %esp
|
||||
pushl %edi
|
||||
pushl %esi
|
||||
pushl %edx
|
||||
@@ -43,6 +35,15 @@ asm_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
|
||||
@@ -51,12 +52,6 @@ asm_syscall_handler:
|
||||
popl %ecx
|
||||
popl %ebx
|
||||
|
||||
# restore segment registers
|
||||
popw %gs
|
||||
popw %fs
|
||||
popw %es
|
||||
popw %ds
|
||||
|
||||
iret
|
||||
|
||||
.global sys_fork_trampoline
|
||||
|
||||
@@ -31,39 +31,18 @@ start_kernel_thread:
|
||||
subl $12, %esp
|
||||
pushl %edi
|
||||
call *%esi
|
||||
addl $16, %esp
|
||||
|
||||
|
||||
.global start_userspace_thread
|
||||
start_userspace_thread:
|
||||
call get_thread_start_sp
|
||||
movl %eax, %esp
|
||||
|
||||
# STACK LAYOUT
|
||||
# entry
|
||||
# argc
|
||||
# argv
|
||||
# envp
|
||||
# userspace stack
|
||||
|
||||
call get_userspace_thread_stack_top
|
||||
|
||||
movw $(0x20 | 3), %bx
|
||||
movw %bx, %ds
|
||||
movw %bx, %es
|
||||
movw $(0x30 | 3), %bx
|
||||
movw %bx, %fs
|
||||
movw $(0x38 | 3), %bx
|
||||
movw %bx, %gs
|
||||
xorw %bx, %bx
|
||||
|
||||
popl %edi
|
||||
popl %esi
|
||||
popl %edx
|
||||
popl %ecx
|
||||
popl %ebx
|
||||
|
||||
pushl $(0x20 | 3)
|
||||
pushl %eax
|
||||
pushl $0x202
|
||||
pushl $(0x18 | 3)
|
||||
pushl %ebx
|
||||
iret
|
||||
|
||||
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
|
||||
@@ -14,6 +14,23 @@
|
||||
# multiboot2 header
|
||||
.section .multiboot, "aw"
|
||||
.align 8
|
||||
multiboot_start:
|
||||
.long 0x1BADB002
|
||||
.long (1 << 2) # page align modules
|
||||
.long -(0x1BADB002 + (1 << 2))
|
||||
|
||||
.long 0
|
||||
.long 0
|
||||
.long 0
|
||||
.long 0
|
||||
.long 0
|
||||
|
||||
.long 0
|
||||
.long FB_WIDTH
|
||||
.long FB_HEIGHT
|
||||
.long FB_BPP
|
||||
multiboot_end:
|
||||
.align 8
|
||||
multiboot2_start:
|
||||
.long 0xE85250D6
|
||||
.long 0
|
||||
@@ -36,6 +53,12 @@ multiboot2_start:
|
||||
.long 12
|
||||
.long V2P(_start)
|
||||
|
||||
# page align modules
|
||||
.align 8
|
||||
.short 6
|
||||
.short 0
|
||||
.long 8
|
||||
|
||||
.align 8
|
||||
.short 0
|
||||
.short 0
|
||||
@@ -53,10 +76,10 @@ bananboot_start:
|
||||
bananboot_end:
|
||||
|
||||
.section .bss, "aw", @nobits
|
||||
.align 4096
|
||||
boot_stack_bottom:
|
||||
.global g_boot_stack_top
|
||||
g_boot_stack_bottom:
|
||||
.skip 4096 * 4
|
||||
boot_stack_top:
|
||||
g_boot_stack_top:
|
||||
|
||||
.global g_kernel_cmdline
|
||||
g_kernel_cmdline:
|
||||
@@ -161,6 +184,13 @@ enable_sse:
|
||||
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
|
||||
@@ -188,7 +218,7 @@ _start:
|
||||
movl %ebx, V2P(bootloader_info)
|
||||
|
||||
# load boot stack
|
||||
movl $V2P(boot_stack_top), %esp
|
||||
movl $V2P(g_boot_stack_top), %esp
|
||||
|
||||
# load boot GDT
|
||||
lgdt V2P(boot_gdtr)
|
||||
@@ -203,10 +233,11 @@ gdt_flush:
|
||||
# do processor initialization
|
||||
call check_requirements
|
||||
call enable_sse
|
||||
call enable_tsc
|
||||
call initialize_paging
|
||||
|
||||
# load higher half stack pointer
|
||||
movl $boot_stack_top, %esp
|
||||
movl $g_boot_stack_top, %esp
|
||||
|
||||
# jump to higher half
|
||||
leal higher_half, %ecx
|
||||
@@ -279,6 +310,7 @@ ap_protected_mode:
|
||||
movb $1, AP_V2P(ap_stack_loaded)
|
||||
|
||||
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
|
||||
|
||||
@@ -1,133 +1,120 @@
|
||||
.macro push_userspace
|
||||
pushw %gs
|
||||
pushw %fs
|
||||
pushw %es
|
||||
pushw %ds
|
||||
pushal
|
||||
.endm
|
||||
.macro maybe_load_kernel_segments, n
|
||||
testb $3, \n(%esp)
|
||||
jz 1f; jnp 1f
|
||||
|
||||
.macro load_kernel_segments
|
||||
movw $0x10, %ax
|
||||
movw %ax, %ds
|
||||
movw %ax, %es
|
||||
movw %ax, %fs
|
||||
|
||||
movw $0x28, %ax
|
||||
movw %ax, %gs
|
||||
1:
|
||||
.endm
|
||||
|
||||
.macro pop_userspace
|
||||
popal
|
||||
popw %ds
|
||||
popw %es
|
||||
popw %fs
|
||||
popw %gs
|
||||
.macro maybe_load_userspace_segments, n
|
||||
testb $3, \n(%esp)
|
||||
jz 1f; jnp 1f
|
||||
|
||||
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:
|
||||
.endm
|
||||
|
||||
isr_stub:
|
||||
push_userspace
|
||||
load_kernel_segments
|
||||
pushal
|
||||
maybe_load_kernel_segments 44
|
||||
cld
|
||||
|
||||
movl %cr0, %eax; pushl %eax
|
||||
movl %cr2, %eax; pushl %eax
|
||||
movl %cr3, %eax; pushl %eax
|
||||
movl %cr4, %eax; pushl %eax
|
||||
|
||||
movl %esp, %eax // register ptr
|
||||
leal 64(%esp), %ebx // interrupt stack ptr
|
||||
movl 60(%esp), %ecx // error code
|
||||
movl 56(%esp), %edx // isr number
|
||||
movl 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
|
||||
subl $15, %esp
|
||||
andl $0xFFFFFFF0, %esp
|
||||
andl $-16, %esp
|
||||
|
||||
pushl %eax
|
||||
pushl %ebx
|
||||
pushl %ecx
|
||||
pushl %edx
|
||||
pushl %esi
|
||||
pushl %edi
|
||||
call cpp_isr_handler
|
||||
|
||||
movl %ebp, %esp
|
||||
addl $16, %esp
|
||||
addl $24, %esp
|
||||
|
||||
pop_userspace
|
||||
maybe_load_userspace_segments 44
|
||||
popal
|
||||
addl $8, %esp
|
||||
iret
|
||||
|
||||
irq_stub:
|
||||
push_userspace
|
||||
load_kernel_segments
|
||||
pushal
|
||||
maybe_load_kernel_segments 44
|
||||
cld
|
||||
|
||||
movl 40(%esp), %eax # interrupt number
|
||||
movl 32(%esp), %edi # interrupt number
|
||||
|
||||
movl %esp, %ebp
|
||||
subl $15, %esp
|
||||
andl $0xFFFFFFF0, %esp
|
||||
andl $-16, %esp
|
||||
|
||||
subl $12, %esp
|
||||
pushl %eax
|
||||
pushl %edi
|
||||
call cpp_irq_handler
|
||||
|
||||
movl %ebp, %esp
|
||||
|
||||
pop_userspace
|
||||
addl $8, %esp
|
||||
iret
|
||||
|
||||
.global asm_yield_handler
|
||||
asm_yield_handler:
|
||||
# This can only be called from kernel, so no segment saving is needed
|
||||
pushal
|
||||
|
||||
movl %esp, %eax # interrupt registers ptr
|
||||
leal 32(%esp), %ebx # interrupt stack ptr
|
||||
|
||||
movl %esp, %ebp
|
||||
subl $15, %esp
|
||||
andl $0xFFFFFFF0, %esp
|
||||
|
||||
subl $8, %esp
|
||||
pushl %eax
|
||||
pushl %ebx
|
||||
call cpp_yield_handler
|
||||
|
||||
movl %ebp, %esp
|
||||
|
||||
maybe_load_userspace_segments 44
|
||||
popal
|
||||
addl $8, %esp
|
||||
iret
|
||||
|
||||
.global asm_ipi_handler
|
||||
asm_ipi_handler:
|
||||
push_userspace
|
||||
load_kernel_segments
|
||||
pushal
|
||||
maybe_load_kernel_segments 36
|
||||
cld
|
||||
|
||||
movl %esp, %ebp
|
||||
subl $15, %esp
|
||||
andl $0xFFFFFFF0, %esp
|
||||
andl $-16, %esp
|
||||
|
||||
call cpp_ipi_handler
|
||||
|
||||
movl %ebp, %esp
|
||||
|
||||
pop_userspace
|
||||
maybe_load_userspace_segments 36
|
||||
popal
|
||||
iret
|
||||
|
||||
|
||||
.global asm_timer_handler
|
||||
asm_timer_handler:
|
||||
push_userspace
|
||||
load_kernel_segments
|
||||
pushal
|
||||
maybe_load_kernel_segments 36
|
||||
cld
|
||||
|
||||
movl %esp, %ebp
|
||||
subl $15, %esp
|
||||
andl $0xFFFFFFF0, %esp
|
||||
andl $-16, %esp
|
||||
|
||||
call cpp_timer_handler
|
||||
|
||||
movl %ebp, %esp
|
||||
|
||||
pop_userspace
|
||||
maybe_load_userspace_segments 36
|
||||
popal
|
||||
iret
|
||||
|
||||
.macro isr n
|
||||
@@ -186,211 +173,26 @@ isr 29
|
||||
isr 30
|
||||
isr 31
|
||||
|
||||
irq 0
|
||||
irq 1
|
||||
irq 2
|
||||
irq 3
|
||||
irq 4
|
||||
irq 5
|
||||
irq 6
|
||||
irq 7
|
||||
irq 8
|
||||
irq 9
|
||||
irq 10
|
||||
irq 11
|
||||
irq 12
|
||||
irq 13
|
||||
irq 14
|
||||
irq 15
|
||||
irq 16
|
||||
irq 17
|
||||
irq 18
|
||||
irq 19
|
||||
irq 20
|
||||
irq 21
|
||||
irq 22
|
||||
irq 23
|
||||
irq 24
|
||||
irq 25
|
||||
irq 26
|
||||
irq 27
|
||||
irq 28
|
||||
irq 29
|
||||
irq 30
|
||||
irq 31
|
||||
irq 32
|
||||
irq 33
|
||||
irq 34
|
||||
irq 35
|
||||
irq 36
|
||||
irq 37
|
||||
irq 38
|
||||
irq 39
|
||||
irq 40
|
||||
irq 41
|
||||
irq 42
|
||||
irq 43
|
||||
irq 44
|
||||
irq 45
|
||||
irq 46
|
||||
irq 47
|
||||
irq 48
|
||||
irq 49
|
||||
irq 50
|
||||
irq 51
|
||||
irq 52
|
||||
irq 53
|
||||
irq 54
|
||||
irq 55
|
||||
irq 56
|
||||
irq 57
|
||||
irq 58
|
||||
irq 59
|
||||
irq 60
|
||||
irq 61
|
||||
irq 62
|
||||
irq 63
|
||||
irq 64
|
||||
irq 65
|
||||
irq 66
|
||||
irq 67
|
||||
irq 68
|
||||
irq 69
|
||||
irq 70
|
||||
irq 71
|
||||
irq 72
|
||||
irq 73
|
||||
irq 74
|
||||
irq 75
|
||||
irq 76
|
||||
irq 77
|
||||
irq 78
|
||||
irq 79
|
||||
irq 80
|
||||
irq 81
|
||||
irq 82
|
||||
irq 83
|
||||
irq 84
|
||||
irq 85
|
||||
irq 86
|
||||
irq 87
|
||||
irq 88
|
||||
irq 89
|
||||
irq 90
|
||||
irq 91
|
||||
irq 92
|
||||
irq 93
|
||||
irq 94
|
||||
irq 95
|
||||
irq 96
|
||||
irq 97
|
||||
irq 98
|
||||
irq 99
|
||||
irq 100
|
||||
irq 101
|
||||
irq 102
|
||||
irq 103
|
||||
irq 104
|
||||
irq 105
|
||||
irq 106
|
||||
irq 107
|
||||
irq 108
|
||||
irq 109
|
||||
irq 110
|
||||
irq 111
|
||||
irq 112
|
||||
irq 113
|
||||
irq 114
|
||||
irq 115
|
||||
irq 116
|
||||
irq 117
|
||||
irq 118
|
||||
irq 119
|
||||
irq 120
|
||||
irq 121
|
||||
irq 122
|
||||
irq 123
|
||||
irq 124
|
||||
irq 125
|
||||
irq 126
|
||||
irq 127
|
||||
irq 128
|
||||
irq 129
|
||||
irq 130
|
||||
irq 131
|
||||
irq 132
|
||||
irq 133
|
||||
irq 134
|
||||
irq 135
|
||||
irq 136
|
||||
irq 137
|
||||
irq 138
|
||||
irq 139
|
||||
irq 140
|
||||
irq 141
|
||||
irq 142
|
||||
irq 143
|
||||
irq 144
|
||||
irq 145
|
||||
irq 146
|
||||
irq 147
|
||||
irq 148
|
||||
irq 149
|
||||
irq 150
|
||||
irq 151
|
||||
irq 152
|
||||
irq 153
|
||||
irq 154
|
||||
irq 155
|
||||
irq 156
|
||||
irq 157
|
||||
irq 158
|
||||
irq 159
|
||||
irq 160
|
||||
irq 161
|
||||
irq 162
|
||||
irq 163
|
||||
irq 164
|
||||
irq 165
|
||||
irq 166
|
||||
irq 167
|
||||
irq 168
|
||||
irq 169
|
||||
irq 170
|
||||
irq 171
|
||||
irq 172
|
||||
irq 173
|
||||
irq 174
|
||||
irq 175
|
||||
irq 176
|
||||
irq 177
|
||||
irq 178
|
||||
irq 179
|
||||
irq 180
|
||||
irq 181
|
||||
irq 182
|
||||
irq 183
|
||||
irq 184
|
||||
irq 185
|
||||
irq 186
|
||||
irq 187
|
||||
irq 188
|
||||
irq 189
|
||||
irq 190
|
||||
irq 191
|
||||
irq 192
|
||||
irq 193
|
||||
irq 194
|
||||
irq 195
|
||||
irq 196
|
||||
irq 197
|
||||
irq 198
|
||||
irq 199
|
||||
irq 200
|
||||
irq 201
|
||||
irq 202
|
||||
irq 203
|
||||
irq 204
|
||||
irq 205
|
||||
irq 206
|
||||
irq 207
|
||||
.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
|
||||
|
||||
@@ -503,6 +503,7 @@ namespace Kernel
|
||||
{
|
||||
ASSERT(s_kernel);
|
||||
ASSERT(paddr);
|
||||
ASSERT(paddr % PAGE_SIZE == 0);
|
||||
|
||||
ASSERT(s_fast_page_lock.current_processor_has_lock());
|
||||
|
||||
@@ -520,7 +521,7 @@ namespace Kernel
|
||||
ASSERT(!(pt[pte] & Flags::Present));
|
||||
pt[pte] = paddr | Flags::ReadWrite | Flags::Present;
|
||||
|
||||
invalidate(fast_page(), false);
|
||||
asm volatile("invlpg (%0)" :: "r"(fast_page()) : "memory");
|
||||
}
|
||||
|
||||
void PageTable::unmap_fast_page()
|
||||
@@ -543,7 +544,7 @@ namespace Kernel
|
||||
ASSERT(pt[pte] & Flags::Present);
|
||||
pt[pte] = 0;
|
||||
|
||||
invalidate(fast_page(), false);
|
||||
asm volatile("invlpg (%0)" :: "r"(fast_page()) : "memory");
|
||||
}
|
||||
|
||||
BAN::ErrorOr<PageTable*> PageTable::create_userspace()
|
||||
@@ -576,6 +577,9 @@ namespace Kernel
|
||||
|
||||
PageTable::~PageTable()
|
||||
{
|
||||
if (m_highest_paging_struct == 0)
|
||||
return;
|
||||
|
||||
// NOTE: we only loop until 256 since after that is hhdm
|
||||
const uint64_t* pml4 = P2V(m_highest_paging_struct);
|
||||
for (uint64_t pml4e = 0; pml4e < 256; pml4e++)
|
||||
@@ -619,7 +623,8 @@ namespace Kernel
|
||||
.type = Processor::SMPMessage::Type::FlushTLB,
|
||||
.flush_tlb = {
|
||||
.vaddr = vaddr,
|
||||
.page_count = 1
|
||||
.page_count = 1,
|
||||
.page_table = vaddr < KERNEL_OFFSET ? this : nullptr,
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -654,7 +659,11 @@ namespace Kernel
|
||||
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] & PAGE_ADDR_MASK;
|
||||
|
||||
pt[pte] = 0;
|
||||
|
||||
if (old_paddr != 0)
|
||||
invalidate(vaddr, send_smp_message);
|
||||
}
|
||||
|
||||
@@ -672,7 +681,8 @@ namespace Kernel
|
||||
.type = Processor::SMPMessage::Type::FlushTLB,
|
||||
.flush_tlb = {
|
||||
.vaddr = vaddr,
|
||||
.page_count = page_count
|
||||
.page_count = page_count,
|
||||
.page_table = vaddr < KERNEL_OFFSET ? this : nullptr,
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -738,8 +748,11 @@ namespace Kernel
|
||||
if (!(flags & Flags::Present))
|
||||
uwr_flags &= ~Flags::Present;
|
||||
|
||||
const paddr_t old_paddr = pt[pte] & PAGE_ADDR_MASK;
|
||||
|
||||
pt[pte] = paddr | uwr_flags | extra_flags;
|
||||
|
||||
if (old_paddr != 0)
|
||||
invalidate(vaddr, send_smp_message);
|
||||
}
|
||||
|
||||
@@ -761,7 +774,8 @@ namespace Kernel
|
||||
.type = Processor::SMPMessage::Type::FlushTLB,
|
||||
.flush_tlb = {
|
||||
.vaddr = vaddr,
|
||||
.page_count = page_count
|
||||
.page_count = page_count,
|
||||
.page_table = vaddr < KERNEL_OFFSET ? this : nullptr,
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -810,13 +824,13 @@ namespace Kernel
|
||||
return page_data & s_page_addr_mask;
|
||||
}
|
||||
|
||||
bool PageTable::reserve_page(vaddr_t vaddr, bool only_free)
|
||||
bool PageTable::reserve_page(vaddr_t vaddr, bool only_free, bool send_smp_message)
|
||||
{
|
||||
SpinLockGuard _(m_lock);
|
||||
ASSERT(vaddr % PAGE_SIZE == 0);
|
||||
if (only_free && !is_page_free(vaddr))
|
||||
return false;
|
||||
map_page_at(0, vaddr, Flags::Reserved);
|
||||
map_page_at(0, vaddr, Flags::Reserved, MemoryType::Normal, send_smp_message);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -830,7 +844,15 @@ namespace Kernel
|
||||
if (only_free && !is_range_free(vaddr, bytes))
|
||||
return false;
|
||||
for (size_t offset = 0; offset < bytes; offset += PAGE_SIZE)
|
||||
reserve_page(vaddr + offset);
|
||||
reserve_page(vaddr + offset, true, false);
|
||||
Processor::broadcast_smp_message({
|
||||
.type = Processor::SMPMessage::Type::FlushTLB,
|
||||
.flush_tlb = {
|
||||
.vaddr = vaddr,
|
||||
.page_count = bytes / PAGE_SIZE,
|
||||
.page_table = vaddr < KERNEL_OFFSET ? this : nullptr,
|
||||
}
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -844,7 +866,7 @@ namespace Kernel
|
||||
last_address -= rem;
|
||||
|
||||
ASSERT(is_canonical(first_address));
|
||||
ASSERT(is_canonical(last_address));
|
||||
ASSERT(is_canonical(last_address - 1));
|
||||
const vaddr_t uc_vaddr_start = uncanonicalize(first_address);
|
||||
const vaddr_t uc_vaddr_end = uncanonicalize(last_address);
|
||||
|
||||
@@ -926,7 +948,7 @@ namespace Kernel
|
||||
last_address -= rem;
|
||||
|
||||
ASSERT(is_canonical(first_address));
|
||||
ASSERT(is_canonical(last_address));
|
||||
ASSERT(is_canonical(last_address - 1));
|
||||
|
||||
SpinLockGuard _(m_lock);
|
||||
|
||||
|
||||
@@ -2,56 +2,83 @@
|
||||
|
||||
// stack contains
|
||||
// return address
|
||||
// return stack
|
||||
// return rflags
|
||||
// siginfo_t
|
||||
// signal number
|
||||
// signal handler
|
||||
|
||||
.global signal_trampoline
|
||||
signal_trampoline:
|
||||
pushq %rax
|
||||
pushq %rbx
|
||||
pushq %rcx
|
||||
pushq %rdx
|
||||
pushq %rbp
|
||||
pushq %rdi
|
||||
pushq %rsi
|
||||
pushq %r8
|
||||
pushq %r9
|
||||
pushq %r10
|
||||
pushq %r11
|
||||
pushq %r12
|
||||
pushq %r13
|
||||
pushq %r15 // gregs
|
||||
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
|
||||
|
||||
movq 128(%rsp), %rdi
|
||||
movq 120(%rsp), %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 176(%rsp), %rsi // siginfo
|
||||
movq 168(%rsp), %rdi // signal number
|
||||
movq 160(%rsp), %rax // handler
|
||||
|
||||
// align stack to 16 bytes
|
||||
movq %rsp, %rbx
|
||||
andq $0x0F, %rbx
|
||||
subq %rbx, %rsp
|
||||
movq %rsp, %rbp
|
||||
andq $-16, %rsp
|
||||
|
||||
subq $512, %rsp
|
||||
fxsave64 (%rsp)
|
||||
|
||||
call *%rax
|
||||
|
||||
fxrstor64 (%rsp)
|
||||
addq $512, %rsp
|
||||
|
||||
// restore stack
|
||||
addq %rbx, %rsp
|
||||
popq %r15
|
||||
popq %r14
|
||||
popq %r13
|
||||
popq %r12
|
||||
popq %r11
|
||||
popq %r10
|
||||
popq %r9
|
||||
popq %r8
|
||||
popq %rsi
|
||||
popq %rdi
|
||||
movq %rbp, %rsp
|
||||
addq $40, %rsp
|
||||
|
||||
// restore registers
|
||||
popq %rbp
|
||||
popq %rdx
|
||||
popq %rcx
|
||||
popq %rbx
|
||||
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
|
||||
|
||||
addq $16, %rsp
|
||||
// skip handler, number, siginfo_t
|
||||
addq $72, %rsp
|
||||
|
||||
// return over red-zone
|
||||
// restore flags
|
||||
popfq
|
||||
|
||||
movq (%rsp), %rsp
|
||||
|
||||
// return over red-zone and siginfo_t
|
||||
ret $128
|
||||
|
||||
@@ -1,48 +1,26 @@
|
||||
// arguments in RAX, RBX, RCX, RDX, RSI, RDI
|
||||
// System V ABI: RDI, RSI, RDX, RCX, R8, R9
|
||||
.global asm_syscall_handler
|
||||
asm_syscall_handler:
|
||||
pushq %rbx
|
||||
pushq %rcx
|
||||
pushq %rdx
|
||||
pushq %rdi
|
||||
pushq %rsi
|
||||
pushq %rbp
|
||||
pushq %r8
|
||||
pushq %r9
|
||||
pushq %r10
|
||||
swapgs
|
||||
|
||||
movq %rsp, %rax
|
||||
movq %gs:8, %rsp
|
||||
|
||||
pushq $(0x20 | 3)
|
||||
pushq %rax
|
||||
pushq %r11
|
||||
pushq %r12
|
||||
pushq %r13
|
||||
pushq %r14
|
||||
pushq %r15
|
||||
pushq $(0x28 | 3)
|
||||
pushq %rcx
|
||||
subq $8, %rsp
|
||||
|
||||
movq %rsi, %r8
|
||||
movq %rdi, %r9
|
||||
movq %rax, %rdi
|
||||
movq %rbx, %rsi
|
||||
xchgq %rcx, %rdx
|
||||
leaq 112(%rsp), %rbx
|
||||
pushq %rbx
|
||||
movq %r10, %rcx
|
||||
call cpp_syscall_handler
|
||||
addq $8, %rsp
|
||||
|
||||
popq %r15
|
||||
popq %r14
|
||||
popq %r13
|
||||
popq %r12
|
||||
popq %r11
|
||||
popq %r10
|
||||
popq %r9
|
||||
popq %r8
|
||||
popq %rbp
|
||||
popq %rsi
|
||||
popq %rdi
|
||||
popq %rdx
|
||||
popq %rcx
|
||||
popq %rbx
|
||||
iretq
|
||||
movq 8(%rsp), %rcx
|
||||
movq 24(%rsp), %r11
|
||||
movq 32(%rsp), %rsp
|
||||
|
||||
swapgs
|
||||
sysretq
|
||||
|
||||
.global sys_fork_trampoline
|
||||
sys_fork_trampoline:
|
||||
@@ -55,7 +33,7 @@ sys_fork_trampoline:
|
||||
|
||||
call read_ip
|
||||
testq %rax, %rax
|
||||
je .reload_stack
|
||||
je .done
|
||||
|
||||
movq %rax, %rsi
|
||||
movq %rsp, %rdi
|
||||
@@ -69,9 +47,3 @@ sys_fork_trampoline:
|
||||
popq %rbp
|
||||
popq %rbx
|
||||
ret
|
||||
|
||||
.reload_stack:
|
||||
call get_thread_start_sp
|
||||
movq %rax, %rsp
|
||||
xorq %rax, %rax
|
||||
jmp .done
|
||||
|
||||
@@ -30,24 +30,6 @@ start_userspace_thread:
|
||||
call get_thread_start_sp
|
||||
movq %rax, %rsp
|
||||
|
||||
# STACK LAYOUT
|
||||
# entry
|
||||
# argc
|
||||
# argv
|
||||
# envp
|
||||
# userspace stack
|
||||
swapgs
|
||||
|
||||
call get_userspace_thread_stack_top
|
||||
|
||||
popq %rdi
|
||||
popq %rsi
|
||||
popq %rdx
|
||||
popq %rcx
|
||||
popq %rbx
|
||||
|
||||
pushq $(0x20 | 3)
|
||||
pushq %rax
|
||||
pushq $0x202
|
||||
pushq $(0x18 | 3)
|
||||
pushq %rbx
|
||||
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
|
||||
@@ -14,6 +14,23 @@
|
||||
# multiboot2 header
|
||||
.section .multiboot, "aw"
|
||||
.align 8
|
||||
multiboot_start:
|
||||
.long 0x1BADB002
|
||||
.long (1 << 2) # page align modules
|
||||
.long -(0x1BADB002 + (1 << 2))
|
||||
|
||||
.long 0
|
||||
.long 0
|
||||
.long 0
|
||||
.long 0
|
||||
.long 0
|
||||
|
||||
.long 0
|
||||
.long FB_WIDTH
|
||||
.long FB_HEIGHT
|
||||
.long FB_BPP
|
||||
multiboot_end:
|
||||
.align 8
|
||||
multiboot2_start:
|
||||
.long 0xE85250D6
|
||||
.long 0
|
||||
@@ -36,6 +53,12 @@ multiboot2_start:
|
||||
.long 12
|
||||
.long V2P(_start)
|
||||
|
||||
# page align modules
|
||||
.align 8
|
||||
.short 6
|
||||
.short 0
|
||||
.long 8
|
||||
|
||||
.align 8
|
||||
.short 0
|
||||
.short 0
|
||||
@@ -53,9 +76,10 @@ bananboot_start:
|
||||
bananboot_end:
|
||||
|
||||
.section .bss, "aw", @nobits
|
||||
boot_stack_bottom:
|
||||
.skip 4096 * 64
|
||||
boot_stack_top:
|
||||
.global g_boot_stack_top
|
||||
g_boot_stack_bottom:
|
||||
.skip 4096 * 4
|
||||
g_boot_stack_top:
|
||||
|
||||
.global g_kernel_cmdline
|
||||
g_kernel_cmdline:
|
||||
@@ -155,6 +179,13 @@ enable_sse:
|
||||
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
|
||||
@@ -187,10 +218,11 @@ _start:
|
||||
movl %eax, V2P(bootloader_magic)
|
||||
movl %ebx, V2P(bootloader_info)
|
||||
|
||||
movl $V2P(boot_stack_top), %esp
|
||||
movl $V2P(g_boot_stack_top), %esp
|
||||
|
||||
call check_requirements
|
||||
call enable_sse
|
||||
call enable_tsc
|
||||
call initialize_paging
|
||||
|
||||
# flush gdt and jump to 64 bit
|
||||
@@ -277,6 +309,7 @@ ap_protected_mode:
|
||||
movb $1, AP_V2P(ap_stack_loaded)
|
||||
|
||||
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
|
||||
|
||||
@@ -1,4 +1,12 @@
|
||||
.macro pushaq
|
||||
.macro swapgs_if_necessary, n
|
||||
testb $3, \n(%rsp)
|
||||
jz 1f; jnp 1f
|
||||
swapgs
|
||||
1:
|
||||
.endm
|
||||
|
||||
.macro pushaq, n
|
||||
swapgs_if_necessary \n
|
||||
pushq %rax
|
||||
pushq %rcx
|
||||
pushq %rdx
|
||||
@@ -16,7 +24,7 @@
|
||||
pushq %r15
|
||||
.endm
|
||||
|
||||
.macro popaq
|
||||
.macro popaq, n
|
||||
popq %r15
|
||||
popq %r14
|
||||
popq %r13
|
||||
@@ -32,11 +40,12 @@
|
||||
popq %rdx
|
||||
popq %rcx
|
||||
popq %rax
|
||||
swapgs_if_necessary \n
|
||||
.endm
|
||||
|
||||
isr_stub:
|
||||
pushaq
|
||||
|
||||
pushaq 24
|
||||
cld
|
||||
movq %cr0, %rax; pushq %rax
|
||||
movq %cr2, %rax; pushq %rax
|
||||
movq %cr3, %rax; pushq %rax
|
||||
@@ -49,39 +58,33 @@ isr_stub:
|
||||
call cpp_isr_handler
|
||||
addq $32, %rsp
|
||||
|
||||
popaq
|
||||
popaq 24
|
||||
addq $16, %rsp
|
||||
iretq
|
||||
|
||||
irq_stub:
|
||||
pushaq
|
||||
pushaq 24
|
||||
cld
|
||||
movq 120(%rsp), %rdi # irq number
|
||||
call cpp_irq_handler
|
||||
popaq
|
||||
popaq 24
|
||||
addq $16, %rsp
|
||||
iretq
|
||||
|
||||
.global asm_yield_handler
|
||||
asm_yield_handler:
|
||||
pushaq
|
||||
leaq 120(%rsp), %rdi # interrupt stack ptr
|
||||
movq %rsp, %rsi # interrupt register ptr
|
||||
call cpp_yield_handler
|
||||
popaq
|
||||
iretq
|
||||
|
||||
.global asm_ipi_handler
|
||||
asm_ipi_handler:
|
||||
pushaq
|
||||
pushaq 8
|
||||
cld
|
||||
call cpp_ipi_handler
|
||||
popaq
|
||||
popaq 8
|
||||
iretq
|
||||
|
||||
.global asm_timer_handler
|
||||
asm_timer_handler:
|
||||
pushaq
|
||||
pushaq 8
|
||||
cld
|
||||
call cpp_timer_handler
|
||||
popaq
|
||||
popaq 8
|
||||
iretq
|
||||
|
||||
.macro isr n
|
||||
@@ -140,211 +143,26 @@ isr 29
|
||||
isr 30
|
||||
isr 31
|
||||
|
||||
irq 0
|
||||
irq 1
|
||||
irq 2
|
||||
irq 3
|
||||
irq 4
|
||||
irq 5
|
||||
irq 6
|
||||
irq 7
|
||||
irq 8
|
||||
irq 9
|
||||
irq 10
|
||||
irq 11
|
||||
irq 12
|
||||
irq 13
|
||||
irq 14
|
||||
irq 15
|
||||
irq 16
|
||||
irq 17
|
||||
irq 18
|
||||
irq 19
|
||||
irq 20
|
||||
irq 21
|
||||
irq 22
|
||||
irq 23
|
||||
irq 24
|
||||
irq 25
|
||||
irq 26
|
||||
irq 27
|
||||
irq 28
|
||||
irq 29
|
||||
irq 30
|
||||
irq 31
|
||||
irq 32
|
||||
irq 33
|
||||
irq 34
|
||||
irq 35
|
||||
irq 36
|
||||
irq 37
|
||||
irq 38
|
||||
irq 39
|
||||
irq 40
|
||||
irq 41
|
||||
irq 42
|
||||
irq 43
|
||||
irq 44
|
||||
irq 45
|
||||
irq 46
|
||||
irq 47
|
||||
irq 48
|
||||
irq 49
|
||||
irq 50
|
||||
irq 51
|
||||
irq 52
|
||||
irq 53
|
||||
irq 54
|
||||
irq 55
|
||||
irq 56
|
||||
irq 57
|
||||
irq 58
|
||||
irq 59
|
||||
irq 60
|
||||
irq 61
|
||||
irq 62
|
||||
irq 63
|
||||
irq 64
|
||||
irq 65
|
||||
irq 66
|
||||
irq 67
|
||||
irq 68
|
||||
irq 69
|
||||
irq 70
|
||||
irq 71
|
||||
irq 72
|
||||
irq 73
|
||||
irq 74
|
||||
irq 75
|
||||
irq 76
|
||||
irq 77
|
||||
irq 78
|
||||
irq 79
|
||||
irq 80
|
||||
irq 81
|
||||
irq 82
|
||||
irq 83
|
||||
irq 84
|
||||
irq 85
|
||||
irq 86
|
||||
irq 87
|
||||
irq 88
|
||||
irq 89
|
||||
irq 90
|
||||
irq 91
|
||||
irq 92
|
||||
irq 93
|
||||
irq 94
|
||||
irq 95
|
||||
irq 96
|
||||
irq 97
|
||||
irq 98
|
||||
irq 99
|
||||
irq 100
|
||||
irq 101
|
||||
irq 102
|
||||
irq 103
|
||||
irq 104
|
||||
irq 105
|
||||
irq 106
|
||||
irq 107
|
||||
irq 108
|
||||
irq 109
|
||||
irq 110
|
||||
irq 111
|
||||
irq 112
|
||||
irq 113
|
||||
irq 114
|
||||
irq 115
|
||||
irq 116
|
||||
irq 117
|
||||
irq 118
|
||||
irq 119
|
||||
irq 120
|
||||
irq 121
|
||||
irq 122
|
||||
irq 123
|
||||
irq 124
|
||||
irq 125
|
||||
irq 126
|
||||
irq 127
|
||||
irq 128
|
||||
irq 129
|
||||
irq 130
|
||||
irq 131
|
||||
irq 132
|
||||
irq 133
|
||||
irq 134
|
||||
irq 135
|
||||
irq 136
|
||||
irq 137
|
||||
irq 138
|
||||
irq 139
|
||||
irq 140
|
||||
irq 141
|
||||
irq 142
|
||||
irq 143
|
||||
irq 144
|
||||
irq 145
|
||||
irq 146
|
||||
irq 147
|
||||
irq 148
|
||||
irq 149
|
||||
irq 150
|
||||
irq 151
|
||||
irq 152
|
||||
irq 153
|
||||
irq 154
|
||||
irq 155
|
||||
irq 156
|
||||
irq 157
|
||||
irq 158
|
||||
irq 159
|
||||
irq 160
|
||||
irq 161
|
||||
irq 162
|
||||
irq 163
|
||||
irq 164
|
||||
irq 165
|
||||
irq 166
|
||||
irq 167
|
||||
irq 168
|
||||
irq 169
|
||||
irq 170
|
||||
irq 171
|
||||
irq 172
|
||||
irq 173
|
||||
irq 174
|
||||
irq 175
|
||||
irq 176
|
||||
irq 177
|
||||
irq 178
|
||||
irq 179
|
||||
irq 180
|
||||
irq 181
|
||||
irq 182
|
||||
irq 183
|
||||
irq 184
|
||||
irq 185
|
||||
irq 186
|
||||
irq 187
|
||||
irq 188
|
||||
irq 189
|
||||
irq 190
|
||||
irq 191
|
||||
irq 192
|
||||
irq 193
|
||||
irq 194
|
||||
irq 195
|
||||
irq 196
|
||||
irq 197
|
||||
irq 198
|
||||
irq 199
|
||||
irq 200
|
||||
irq 201
|
||||
irq 202
|
||||
irq 203
|
||||
irq 204
|
||||
irq 205
|
||||
irq 206
|
||||
irq 207
|
||||
.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
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include <BAN/Vector.h>
|
||||
#include <kernel/ACPI/AML/Method.h>
|
||||
#include <kernel/ACPI/AML/Namespace.h>
|
||||
#include <kernel/ACPI/EmbeddedController.h>
|
||||
#include <kernel/ACPI/Headers.h>
|
||||
#include <kernel/Memory/Types.h>
|
||||
#include <kernel/ThreadBlocker.h>
|
||||
@@ -29,25 +29,38 @@ namespace Kernel::ACPI
|
||||
// 2: SAPIC
|
||||
BAN::ErrorOr<void> enter_acpi_mode(uint8_t mode);
|
||||
|
||||
// This function will power off the system
|
||||
// This function will return only if there was an error
|
||||
void poweroff();
|
||||
BAN::ErrorOr<void> initialize_acpi_devices();
|
||||
|
||||
// This function will reset the system
|
||||
// This function will return only if there was an error
|
||||
void reset();
|
||||
AML::Namespace* acpi_namespace() { return m_namespace; }
|
||||
|
||||
BAN::ErrorOr<void> poweroff();
|
||||
BAN::ErrorOr<void> reset();
|
||||
|
||||
BAN::ErrorOr<void> register_gpe_handler(uint8_t gpe, void (*callback)(void*), void* argument);
|
||||
|
||||
void handle_irq() override;
|
||||
|
||||
BAN::Span<BAN::UniqPtr<EmbeddedController>> embedded_controllers() { return m_embedded_controllers.span(); }
|
||||
|
||||
private:
|
||||
ACPI() = default;
|
||||
BAN::ErrorOr<void> initialize_impl();
|
||||
|
||||
FADT& fadt() { return *m_fadt; }
|
||||
|
||||
bool prepare_sleep(uint8_t sleep_state);
|
||||
BAN::ErrorOr<void> prepare_sleep(uint8_t sleep_state);
|
||||
void acpi_event_task();
|
||||
|
||||
BAN::ErrorOr<void> load_aml_tables(BAN::StringView name, bool all);
|
||||
|
||||
BAN::ErrorOr<void> route_interrupt_link_device(const AML::Scope& device, uint64_t& routed_irq_mask);
|
||||
|
||||
BAN::ErrorOr<void> initialize_embedded_controller(const AML::Scope& embedded_controller);
|
||||
BAN::ErrorOr<void> initialize_embedded_controllers();
|
||||
|
||||
BAN::Optional<GAS> find_gpe_block(size_t index);
|
||||
bool enable_gpe(uint8_t gpe);
|
||||
|
||||
private:
|
||||
paddr_t m_header_table_paddr = 0;
|
||||
vaddr_t m_header_table_vaddr = 0;
|
||||
@@ -65,10 +78,27 @@ namespace Kernel::ACPI
|
||||
FADT* m_fadt { nullptr };
|
||||
|
||||
ThreadBlocker m_event_thread_blocker;
|
||||
BAN::Array<BAN::RefPtr<AML::Method>, 0xFF> m_gpe_methods;
|
||||
|
||||
BAN::Vector<BAN::UniqPtr<EmbeddedController>> m_embedded_controllers;
|
||||
|
||||
struct GPEHandler
|
||||
{
|
||||
bool has_callback { false };
|
||||
union {
|
||||
AML::Reference* method;
|
||||
struct
|
||||
{
|
||||
void (*callback)(void*);
|
||||
void* argument;
|
||||
};
|
||||
};
|
||||
};
|
||||
bool m_has_any_gpes { false };
|
||||
AML::Scope m_gpe_scope;
|
||||
BAN::Array<GPEHandler, 0xFF> m_gpe_methods;
|
||||
|
||||
bool m_hardware_reduced { false };
|
||||
BAN::RefPtr<AML::Namespace> m_namespace;
|
||||
AML::Namespace* m_namespace { nullptr };
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <kernel/ACPI/Headers.h>
|
||||
#include <kernel/ACPI/AML/Namespace.h>
|
||||
|
||||
namespace Kernel::ACPI::AML
|
||||
{
|
||||
|
||||
BAN::RefPtr<AML::Namespace> initialize_namespace();
|
||||
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <kernel/ACPI/AML/NamedObject.h>
|
||||
#include <kernel/ACPI/AML/Names.h>
|
||||
#include <kernel/ACPI/AML/ParseContext.h>
|
||||
|
||||
namespace Kernel::ACPI::AML
|
||||
{
|
||||
|
||||
struct Alias
|
||||
{
|
||||
static ParseResult parse(ParseContext& context)
|
||||
{
|
||||
ASSERT(context.aml_data.size() >= 1);
|
||||
ASSERT(static_cast<Byte>(context.aml_data[0]) == Byte::AliasOp);
|
||||
context.aml_data = context.aml_data.slice(1);
|
||||
|
||||
auto source_string = AML::NameString::parse(context.aml_data);
|
||||
if (!source_string.has_value())
|
||||
return ParseResult::Failure;
|
||||
|
||||
auto source_object = AML::Namespace::root_namespace()->find_object(context.scope, source_string.value(), AML::Namespace::FindMode::Normal);
|
||||
auto alias_string = AML::NameString::parse(context.aml_data);
|
||||
if (!alias_string.has_value())
|
||||
return ParseResult::Failure;
|
||||
|
||||
if (!source_object)
|
||||
{
|
||||
AML_PRINT("Alias target could not be found");
|
||||
return ParseResult::Success;
|
||||
}
|
||||
|
||||
if (!Namespace::root_namespace()->add_named_object(context, alias_string.value(), source_object))
|
||||
return ParseResult::Success;
|
||||
|
||||
#if AML_DEBUG_LEVEL >= 2
|
||||
AML_DEBUG_PRINT("Alias \"");
|
||||
alias_string->debug_print();
|
||||
AML_DEBUG_PRINT("\" => ");
|
||||
source_object->debug_print(0);
|
||||
AML_DEBUG_PRINTLN("");
|
||||
#endif
|
||||
|
||||
return ParseResult::Success;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,312 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <kernel/ACPI/AML/Bytes.h>
|
||||
#include <kernel/ACPI/AML/Integer.h>
|
||||
#include <kernel/ACPI/AML/Node.h>
|
||||
#include <kernel/ACPI/AML/ParseContext.h>
|
||||
#include <kernel/ACPI/AML/Pkg.h>
|
||||
#include <kernel/ACPI/AML/String.h>
|
||||
|
||||
namespace Kernel::ACPI::AML
|
||||
{
|
||||
|
||||
struct Buffer final : public AML::Node
|
||||
{
|
||||
BAN::Vector<uint8_t> buffer;
|
||||
|
||||
Buffer()
|
||||
: AML::Node(Node::Type::Buffer)
|
||||
{}
|
||||
|
||||
BAN::Optional<bool> logical_compare(BAN::RefPtr<AML::Node> node, AML::Byte binaryop)
|
||||
{
|
||||
auto rhs_node = node ? node->convert(AML::Node::ConvBuffer) : BAN::RefPtr<AML::Node>();
|
||||
if (!rhs_node)
|
||||
{
|
||||
AML_ERROR("Buffer logical compare RHS cannot be converted to buffer");
|
||||
return {};
|
||||
}
|
||||
|
||||
(void)binaryop;
|
||||
AML_TODO("Logical compare buffer");
|
||||
return {};
|
||||
}
|
||||
|
||||
BAN::RefPtr<AML::Node> convert(uint8_t mask) override
|
||||
{
|
||||
if (mask & AML::Node::ConvBuffer)
|
||||
return this;
|
||||
if (mask & AML::Node::ConvInteger)
|
||||
return as_integer();
|
||||
if (mask & AML::Node::ConvString)
|
||||
{
|
||||
AML_TODO("Convert BufferField to String");
|
||||
return {};
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
BAN::RefPtr<AML::Node> store(BAN::RefPtr<AML::Node> node) override
|
||||
{
|
||||
ASSERT(node);
|
||||
auto conv_node = node->convert(AML::Node::ConvBuffer);
|
||||
if (!conv_node)
|
||||
{
|
||||
AML_ERROR("Buffer store could not convert to buffer");
|
||||
return {};
|
||||
}
|
||||
|
||||
auto& conv_buffer = static_cast<AML::Buffer*>(conv_node.ptr())->buffer;
|
||||
MUST(buffer.resize(conv_buffer.size()));
|
||||
for (size_t i = 0; i < buffer.size(); i++)
|
||||
buffer[i] = conv_buffer[i];
|
||||
return this;
|
||||
}
|
||||
|
||||
static ParseResult parse(AML::ParseContext& context)
|
||||
{
|
||||
ASSERT(context.aml_data.size() >= 1);
|
||||
ASSERT(static_cast<Byte>(context.aml_data[0]) == Byte::BufferOp);
|
||||
context.aml_data = context.aml_data.slice(1);
|
||||
|
||||
auto buffer_pkg = AML::parse_pkg(context.aml_data);
|
||||
if (!buffer_pkg.has_value())
|
||||
return ParseResult::Failure;
|
||||
|
||||
auto buffer_context = context;
|
||||
buffer_context.aml_data = buffer_pkg.value();
|
||||
|
||||
auto buffer_size_result = AML::parse_object(buffer_context);
|
||||
if (!buffer_size_result.success())
|
||||
return ParseResult::Failure;
|
||||
|
||||
auto buffer_size_node = buffer_size_result.node() ? buffer_size_result.node()->convert(AML::Node::ConvInteger) : BAN::RefPtr<AML::Node>();
|
||||
if (!buffer_size_node)
|
||||
{
|
||||
AML_ERROR("Buffer size is not an integer");
|
||||
return ParseResult::Failure;
|
||||
}
|
||||
|
||||
const uint32_t actual_buffer_size = BAN::Math::max<uint32_t>(
|
||||
static_cast<AML::Integer*>(buffer_size_node.ptr())->value,
|
||||
buffer_context.aml_data.size()
|
||||
);
|
||||
|
||||
auto buffer = MUST(BAN::RefPtr<Buffer>::create());
|
||||
MUST(buffer->buffer.resize(actual_buffer_size, 0));
|
||||
for (uint32_t i = 0; i < buffer_context.aml_data.size(); i++)
|
||||
buffer->buffer[i] = buffer_context.aml_data[i];
|
||||
|
||||
#if AML_DEBUG_LEVEL >= 2
|
||||
buffer->debug_print(0);
|
||||
AML_DEBUG_PRINTLN("");
|
||||
#endif
|
||||
|
||||
return ParseResult(buffer);
|
||||
}
|
||||
|
||||
virtual void debug_print(int indent) const override
|
||||
{
|
||||
AML_DEBUG_PRINT_INDENT(indent);
|
||||
AML_DEBUG_PRINT("Buffer ({} bytes)", buffer.size());
|
||||
}
|
||||
|
||||
private:
|
||||
BAN::RefPtr<AML::Integer> as_integer()
|
||||
{
|
||||
uint64_t value = 0;
|
||||
for (size_t i = 0; i < BAN::Math::min<size_t>(buffer.size(), 8); i++)
|
||||
value |= static_cast<uint64_t>(buffer[i]) << (8 * i);
|
||||
return MUST(BAN::RefPtr<Integer>::create(value));
|
||||
}
|
||||
};
|
||||
|
||||
struct BufferField final : AML::NamedObject
|
||||
{
|
||||
BAN::RefPtr<AML::Node> buffer;
|
||||
size_t field_bit_offset;
|
||||
size_t field_bit_size;
|
||||
|
||||
template<typename T> requires BAN::is_same_v<T, AML::Buffer> || BAN::is_same_v<T, AML::String>
|
||||
BufferField(AML::NameSeg name, BAN::RefPtr<T> buffer, size_t field_bit_offset, size_t field_bit_size)
|
||||
: AML::NamedObject(Node::Type::BufferField, name)
|
||||
, buffer(buffer)
|
||||
, field_bit_offset(field_bit_offset)
|
||||
, field_bit_size(field_bit_size)
|
||||
{}
|
||||
|
||||
BAN::RefPtr<AML::Node> convert(uint8_t mask) override
|
||||
{
|
||||
if (mask & AML::Node::ConvBufferField)
|
||||
return this;
|
||||
if (mask & AML::Node::ConvInteger)
|
||||
return as_integer();
|
||||
if (mask & AML::Node::ConvBuffer)
|
||||
{
|
||||
AML_TODO("Convert BufferField to Buffer");
|
||||
return {};
|
||||
}
|
||||
if (mask & AML::Node::ConvString)
|
||||
{
|
||||
AML_TODO("Convert BufferField to String");
|
||||
return {};
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
BAN::RefPtr<AML::Node> store(BAN::RefPtr<AML::Node> node) override
|
||||
{
|
||||
ASSERT(buffer);
|
||||
ASSERT(buffer->type == AML::Node::Type::Buffer || buffer->type == AML::Node::Type::String);
|
||||
auto& buffer = (this->buffer->type == AML::Node::Type::Buffer)
|
||||
? static_cast<AML::Buffer*>(this->buffer.ptr())->buffer
|
||||
: static_cast<AML::String*>(this->buffer.ptr())->string;
|
||||
ASSERT(field_bit_offset + field_bit_size <= buffer.size() * 8);
|
||||
|
||||
auto value_node = node ? node->convert(AML::Node::ConvInteger) : BAN::RefPtr<AML::Node>();
|
||||
if (!value_node)
|
||||
return {};
|
||||
const auto value = static_cast<AML::Integer*>(value_node.ptr())->value;
|
||||
|
||||
// TODO: optimize for whole byte accesses
|
||||
for (size_t i = 0; i < field_bit_size; i++)
|
||||
{
|
||||
const size_t bit = field_bit_offset + i;
|
||||
buffer[bit / 8] &= ~(1 << (bit % 8));
|
||||
buffer[bit / 8] |= ((value >> i) & 1) << (bit % 8);
|
||||
}
|
||||
|
||||
return value_node;
|
||||
}
|
||||
|
||||
static ParseResult parse(AML::ParseContext& context)
|
||||
{
|
||||
ASSERT(context.aml_data.size() >= 1);
|
||||
|
||||
bool offset_in_bytes;
|
||||
size_t field_bit_size;
|
||||
switch (static_cast<AML::Byte>(context.aml_data[0]))
|
||||
{
|
||||
case AML::Byte::CreateBitFieldOp:
|
||||
field_bit_size = 1;
|
||||
offset_in_bytes = false;
|
||||
break;
|
||||
case AML::Byte::CreateByteFieldOp:
|
||||
field_bit_size = 8;
|
||||
offset_in_bytes = true;
|
||||
break;
|
||||
case AML::Byte::CreateWordFieldOp:
|
||||
field_bit_size = 16;
|
||||
offset_in_bytes = true;
|
||||
break;
|
||||
case AML::Byte::CreateDWordFieldOp:
|
||||
field_bit_size = 32;
|
||||
offset_in_bytes = true;
|
||||
break;
|
||||
case AML::Byte::CreateQWordFieldOp:
|
||||
field_bit_size = 64;
|
||||
offset_in_bytes = true;
|
||||
break;
|
||||
case AML::Byte::ExtOpPrefix:
|
||||
ASSERT(context.aml_data.size() >= 2);
|
||||
ASSERT(static_cast<AML::ExtOp>(context.aml_data[1]) == AML::ExtOp::CreateFieldOp);
|
||||
field_bit_size = 0;
|
||||
offset_in_bytes = false;
|
||||
break;
|
||||
default:
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
context.aml_data = context.aml_data.slice(1 + (static_cast<AML::Byte>(context.aml_data[0]) == AML::Byte::ExtOpPrefix));
|
||||
|
||||
auto buffer_result = AML::parse_object(context);
|
||||
if (!buffer_result.success())
|
||||
return ParseResult::Failure;
|
||||
auto buffer_node = buffer_result.node() ? buffer_result.node()->convert(AML::Node::ConvBuffer) : BAN::RefPtr<AML::Node>();
|
||||
if (!buffer_node || buffer_node->type != Node::Type::Buffer)
|
||||
{
|
||||
AML_ERROR("Buffer source does not evaluate to a Buffer");
|
||||
return ParseResult::Failure;
|
||||
}
|
||||
auto buffer = BAN::RefPtr<AML::Buffer>(static_cast<AML::Buffer*>(buffer_node.ptr()));
|
||||
|
||||
auto index_result = AML::parse_object(context);
|
||||
if (!index_result.success())
|
||||
return ParseResult::Failure;
|
||||
auto index_node = index_result.node() ? index_result.node()->convert(AML::Node::ConvInteger) : BAN::RefPtr<AML::Node>();
|
||||
if (!index_node)
|
||||
{
|
||||
AML_ERROR("Failed to parse index for BufferField");
|
||||
return ParseResult::Failure;
|
||||
}
|
||||
|
||||
if (field_bit_size == 0)
|
||||
{
|
||||
auto bit_count_result = AML::parse_object(context);
|
||||
if (!bit_count_result.success())
|
||||
return ParseResult::Failure;
|
||||
auto bit_count_node = bit_count_result.node() ? bit_count_result.node()->convert(AML::Node::ConvInteger) : BAN::RefPtr<AML::Node>();
|
||||
if (!bit_count_node)
|
||||
{
|
||||
AML_ERROR("Failed to parse bit count for BufferField");
|
||||
return ParseResult::Failure;
|
||||
}
|
||||
field_bit_size = static_cast<AML::Integer*>(bit_count_node.ptr())->value;
|
||||
}
|
||||
|
||||
auto field_name = AML::NameString::parse(context.aml_data);
|
||||
if (!field_name.has_value())
|
||||
return ParseResult::Failure;
|
||||
if (field_name->path.empty())
|
||||
{
|
||||
AML_ERROR("Empty field name for BufferField");
|
||||
return ParseResult::Failure;
|
||||
}
|
||||
|
||||
size_t field_bit_offset = static_cast<AML::Integer*>(index_node.ptr())->value;
|
||||
if (offset_in_bytes)
|
||||
field_bit_offset *= 8;
|
||||
|
||||
auto field = MUST(BAN::RefPtr<BufferField>::create(field_name->path.back(), buffer, field_bit_offset, field_bit_size));
|
||||
if (!Namespace::root_namespace()->add_named_object(context, field_name.value(), field))
|
||||
return ParseResult::Success;
|
||||
|
||||
#if AML_DEBUG_LEVEL >= 2
|
||||
field->debug_print(0);
|
||||
AML_DEBUG_PRINTLN("");
|
||||
#endif
|
||||
|
||||
return ParseResult::Success;
|
||||
}
|
||||
|
||||
virtual void debug_print(int indent) const override
|
||||
{
|
||||
AML_DEBUG_PRINT_INDENT(indent);
|
||||
AML_DEBUG_PRINT("BufferField {} at bit offset {} ({} bits) to { ", name, field_bit_offset, field_bit_size);
|
||||
buffer->debug_print(0);
|
||||
AML_DEBUG_PRINT(" }");
|
||||
}
|
||||
|
||||
private:
|
||||
BAN::RefPtr<AML::Integer> as_integer()
|
||||
{
|
||||
ASSERT(buffer);
|
||||
ASSERT(buffer->type == AML::Node::Type::Buffer || buffer->type == AML::Node::Type::String);
|
||||
|
||||
const auto& buffer = (this->buffer->type == AML::Node::Type::Buffer)
|
||||
? static_cast<AML::Buffer*>(this->buffer.ptr())->buffer
|
||||
: static_cast<AML::String*>(this->buffer.ptr())->string;
|
||||
|
||||
uint64_t value = 0;
|
||||
|
||||
// TODO: optimize for whole byte accesses
|
||||
for (size_t i = 0; i < BAN::Math::min<size_t>(field_bit_size, 64); i++)
|
||||
{
|
||||
const size_t bit = field_bit_offset + i;
|
||||
value |= static_cast<uint64_t>((buffer[bit / 8] >> (bit % 8)) & 1) << i;
|
||||
}
|
||||
|
||||
return MUST(BAN::RefPtr<Integer>::create(value));
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@@ -145,19 +145,35 @@ namespace Kernel::ACPI::AML
|
||||
DataRegionOp = 0x88,
|
||||
};
|
||||
|
||||
static constexpr bool is_digit_char(uint8_t ch)
|
||||
inline constexpr bool is_digit_char(uint8_t ch)
|
||||
{
|
||||
return '0' <= ch && ch <= '9';
|
||||
}
|
||||
|
||||
static constexpr bool is_lead_name_char(uint8_t ch)
|
||||
inline constexpr bool is_lead_name_char(uint8_t ch)
|
||||
{
|
||||
return ('A' <= ch && ch <= 'Z') || ch == '_';
|
||||
}
|
||||
|
||||
static constexpr bool is_name_char(uint8_t ch)
|
||||
inline constexpr bool is_name_char(uint8_t ch)
|
||||
{
|
||||
return is_lead_name_char(ch) || is_digit_char(ch);
|
||||
}
|
||||
|
||||
inline constexpr bool is_name_string_start(uint8_t ch)
|
||||
{
|
||||
if (is_lead_name_char(ch))
|
||||
return true;
|
||||
switch (static_cast<AML::Byte>(ch))
|
||||
{
|
||||
case AML::Byte::RootChar:
|
||||
case AML::Byte::ParentPrefixChar:
|
||||
case AML::Byte::MultiNamePrefix:
|
||||
case AML::Byte::DualNamePrefix:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,92 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <kernel/ACPI/AML/Buffer.h>
|
||||
#include <kernel/ACPI/AML/Integer.h>
|
||||
#include <kernel/ACPI/AML/ParseContext.h>
|
||||
#include <kernel/ACPI/AML/String.h>
|
||||
|
||||
namespace Kernel::ACPI::AML
|
||||
{
|
||||
|
||||
struct Conversion
|
||||
{
|
||||
static ParseResult parse(AML::ParseContext& context)
|
||||
{
|
||||
const auto opcode = static_cast<AML::Byte>(context.aml_data[0]);
|
||||
context.aml_data = context.aml_data.slice(1);
|
||||
|
||||
switch (opcode)
|
||||
{
|
||||
case AML::Byte::ToIntegerOp:
|
||||
case AML::Byte::ToBufferOp:
|
||||
case AML::Byte::ToStringOp:
|
||||
break;
|
||||
default:
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
auto data_result = AML::parse_object(context);
|
||||
if (!data_result.success())
|
||||
return ParseResult::Failure;
|
||||
auto data_node = data_result.node();
|
||||
if (!data_node)
|
||||
{
|
||||
AML_ERROR("Conversion {2H} data could not be evaluated", static_cast<uint8_t>(opcode));
|
||||
return ParseResult::Failure;
|
||||
}
|
||||
|
||||
if (context.aml_data.size() < 1)
|
||||
{
|
||||
AML_ERROR("Conversion {2H} missing target", static_cast<uint8_t>(opcode));
|
||||
return ParseResult::Failure;
|
||||
}
|
||||
|
||||
BAN::RefPtr<AML::Node> target_node;
|
||||
if (context.aml_data[0] == 0x00)
|
||||
context.aml_data = context.aml_data.slice(1);
|
||||
else
|
||||
{
|
||||
auto target_result = AML::parse_object(context);
|
||||
if (!target_result.success())
|
||||
return ParseResult::Failure;
|
||||
target_node = target_result.node();
|
||||
if (!target_node)
|
||||
{
|
||||
AML_ERROR("Conversion {2H} target invalid", static_cast<uint8_t>(opcode));
|
||||
return ParseResult::Failure;
|
||||
}
|
||||
}
|
||||
|
||||
BAN::RefPtr<AML::Node> converted;
|
||||
switch (opcode)
|
||||
{
|
||||
case AML::Byte::ToBufferOp:
|
||||
converted = data_node->convert(AML::Node::ConvBuffer);
|
||||
break;
|
||||
case AML::Byte::ToIntegerOp:
|
||||
converted = data_node->convert(AML::Node::ConvInteger);
|
||||
break;
|
||||
case AML::Byte::ToStringOp:
|
||||
converted = data_node->convert(AML::Node::ConvString);
|
||||
break;
|
||||
default:
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
if (!converted)
|
||||
{
|
||||
AML_ERROR("Conversion {2H} could not convert from node type {}", static_cast<uint8_t>(opcode), static_cast<uint8_t>(data_node->type));
|
||||
return ParseResult::Failure;
|
||||
}
|
||||
|
||||
if (target_node && !target_node->store(converted))
|
||||
{
|
||||
AML_ERROR("Conversion {2H} failed to store converted value", static_cast<uint8_t>(opcode));
|
||||
return ParseResult::Failure;
|
||||
}
|
||||
|
||||
return ParseResult(converted);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <kernel/ACPI/AML/Alias.h>
|
||||
#include <kernel/ACPI/AML/NamedObject.h>
|
||||
#include <kernel/ACPI/AML/ParseContext.h>
|
||||
#include <kernel/ACPI/AML/Register.h>
|
||||
|
||||
namespace Kernel::ACPI::AML
|
||||
{
|
||||
|
||||
struct CopyObject
|
||||
{
|
||||
static ParseResult parse(ParseContext& context)
|
||||
{
|
||||
ASSERT(context.aml_data.size() >= 1);
|
||||
ASSERT(static_cast<Byte>(context.aml_data[0]) == Byte::CopyObjectOp);
|
||||
context.aml_data = context.aml_data.slice(1);
|
||||
|
||||
auto source_result = AML::parse_object(context);
|
||||
if (!source_result.success())
|
||||
return ParseResult::Failure;
|
||||
auto source = source_result.node()
|
||||
? source_result.node()->to_underlying()
|
||||
: BAN::RefPtr<AML::Node>();
|
||||
if (!source)
|
||||
{
|
||||
AML_ERROR("CopyObject source is null");
|
||||
return ParseResult::Failure;
|
||||
}
|
||||
|
||||
auto destination_result = AML::parse_object(context);
|
||||
if (!destination_result.success())
|
||||
return ParseResult::Failure;
|
||||
auto destination = destination_result.node();
|
||||
if (!destination)
|
||||
{
|
||||
AML_ERROR("CopyObject destination is null");
|
||||
return ParseResult::Failure;
|
||||
}
|
||||
|
||||
#if AML_DEBUG_LEVEL >= 2
|
||||
AML_DEBUG_PRINTLN("CopyObject {");
|
||||
source->debug_print(1);
|
||||
AML_DEBUG_PRINTLN("");
|
||||
AML_DEBUG_PRINTLN("} to {");
|
||||
destination->debug_print(1);
|
||||
AML_DEBUG_PRINTLN("");
|
||||
AML_DEBUG_PRINTLN("}");
|
||||
#endif
|
||||
|
||||
switch (destination->type)
|
||||
{
|
||||
case AML::Node::Type::Name:
|
||||
static_cast<AML::Name*>(destination.ptr())->object = source->copy();
|
||||
return source;
|
||||
case AML::Node::Type::Register:
|
||||
static_cast<AML::Register*>(destination.ptr())->value = source->copy();
|
||||
return source;
|
||||
default:
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <kernel/ACPI/AML/Method.h>
|
||||
#include <kernel/ACPI/AML/ParseContext.h>
|
||||
#include <kernel/ACPI/AML/Pkg.h>
|
||||
#include <kernel/ACPI/AML/Scope.h>
|
||||
|
||||
namespace Kernel::ACPI::AML
|
||||
{
|
||||
|
||||
struct Device final : public AML::Scope
|
||||
{
|
||||
Device(NameSeg name)
|
||||
: Scope(Node::Type::Device, name)
|
||||
{}
|
||||
|
||||
BAN::RefPtr<AML::Node> convert(uint8_t) override { return {}; }
|
||||
|
||||
static ParseResult parse(ParseContext& context)
|
||||
{
|
||||
ASSERT(context.aml_data.size() >= 2);
|
||||
ASSERT(static_cast<AML::Byte>(context.aml_data[0]) == AML::Byte::ExtOpPrefix);
|
||||
ASSERT(static_cast<AML::ExtOp>(context.aml_data[1]) == AML::ExtOp::DeviceOp);
|
||||
context.aml_data = context.aml_data.slice(2);
|
||||
|
||||
auto device_pkg = AML::parse_pkg(context.aml_data);
|
||||
if (!device_pkg.has_value())
|
||||
return ParseResult::Failure;
|
||||
|
||||
auto name_string = AML::NameString::parse(device_pkg.value());
|
||||
if (!name_string.has_value())
|
||||
return ParseResult::Failure;
|
||||
|
||||
auto device = MUST(BAN::RefPtr<Device>::create(name_string->path.back()));
|
||||
if (!Namespace::root_namespace()->add_named_object(context, name_string.value(), device))
|
||||
return ParseResult::Success;
|
||||
|
||||
return device->enter_context_and_parse_term_list(context, name_string.value(), device_pkg.value());
|
||||
}
|
||||
|
||||
virtual void debug_print(int indent) const override
|
||||
{
|
||||
AML_DEBUG_PRINT_INDENT(indent);
|
||||
AML_DEBUG_PRINT("Device ");
|
||||
name.debug_print();
|
||||
AML_DEBUG_PRINTLN(" {");
|
||||
Namespace::root_namespace()->for_each_child(scope,
|
||||
[&](const auto&, const auto& child)
|
||||
{
|
||||
child->debug_print(indent + 1);
|
||||
AML_DEBUG_PRINTLN("");
|
||||
}
|
||||
);
|
||||
AML_DEBUG_PRINT_INDENT(indent);
|
||||
AML_DEBUG_PRINT("}");
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,148 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <kernel/ACPI/AML/Bytes.h>
|
||||
#include <kernel/ACPI/AML/Integer.h>
|
||||
#include <kernel/ACPI/AML/NamedObject.h>
|
||||
#include <kernel/ACPI/AML/ParseContext.h>
|
||||
#include <kernel/ThreadBlocker.h>
|
||||
#include <kernel/Timer/Timer.h>
|
||||
|
||||
namespace Kernel::ACPI::AML
|
||||
{
|
||||
|
||||
struct Event final : public AML::NamedObject
|
||||
{
|
||||
BAN::Atomic<uint32_t> signal_count { 0 };
|
||||
ThreadBlocker thread_blocker;
|
||||
|
||||
Event(NameSeg name)
|
||||
: NamedObject(Node::Type::Event, name)
|
||||
{}
|
||||
|
||||
BAN::RefPtr<AML::Node> convert(uint8_t) override { return {}; }
|
||||
|
||||
static ParseResult parse(ParseContext& context)
|
||||
{
|
||||
ASSERT(context.aml_data.size() >= 2);
|
||||
ASSERT(static_cast<AML::Byte>(context.aml_data[0]) == AML::Byte::ExtOpPrefix);
|
||||
|
||||
const auto ext_op = static_cast<AML::ExtOp>(context.aml_data[1]);
|
||||
switch (ext_op)
|
||||
{
|
||||
case AML::ExtOp::EventOp:
|
||||
return parse_event(context);
|
||||
case AML::ExtOp::ResetOp:
|
||||
case AML::ExtOp::SignalOp:
|
||||
case AML::ExtOp::WaitOp:
|
||||
break;
|
||||
default:
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
context.aml_data = context.aml_data.slice(2);
|
||||
|
||||
auto event_result = parse_object(context);
|
||||
if (!event_result.success())
|
||||
return ParseResult::Failure;
|
||||
|
||||
auto general_node = event_result.node();
|
||||
if (!general_node || general_node->type != Node::Type::Event)
|
||||
{
|
||||
AML_ERROR("Release, Wait or Signal does not name an event");
|
||||
return ParseResult::Failure;
|
||||
}
|
||||
|
||||
auto* event_node = static_cast<AML::Event*>(general_node.ptr());
|
||||
|
||||
if (ext_op == AML::ExtOp::WaitOp)
|
||||
{
|
||||
auto timeout_result = parse_object(context);
|
||||
if (!timeout_result.success())
|
||||
return ParseResult::Failure;
|
||||
|
||||
auto timeout_node = timeout_result.node()
|
||||
? timeout_result.node()->convert(AML::Node::ConvInteger)
|
||||
: BAN::RefPtr<AML::Node>();
|
||||
if (!timeout_node)
|
||||
{
|
||||
AML_ERROR("Wait timeout does not evaluate to integer");
|
||||
return ParseResult::Failure;
|
||||
}
|
||||
const auto timeout_value = static_cast<AML::Integer*>(timeout_node.ptr())->value;
|
||||
|
||||
const uint64_t start_ms = SystemTimer::get().ms_since_boot();
|
||||
while (true)
|
||||
{
|
||||
auto expected = event_node->signal_count.load();
|
||||
while (true)
|
||||
{
|
||||
if (expected == 0)
|
||||
break;
|
||||
if (event_node->signal_count.compare_exchange(expected, expected - 1))
|
||||
return ParseResult(Integer::Constants::Zero);
|
||||
}
|
||||
|
||||
if (timeout_value >= 0xFFFF)
|
||||
event_node->thread_blocker.block_indefinite();
|
||||
else
|
||||
{
|
||||
const uint64_t current_ms = SystemTimer::get().ms_since_boot();
|
||||
if (current_ms >= start_ms + timeout_value)
|
||||
return ParseResult(Integer::Constants::Ones);
|
||||
event_node->thread_blocker.block_with_timeout_ms(start_ms + timeout_value - current_ms);
|
||||
}
|
||||
}
|
||||
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
switch (ext_op)
|
||||
{
|
||||
case AML::ExtOp::ResetOp:
|
||||
event_node->signal_count = 0;
|
||||
break;
|
||||
case AML::ExtOp::SignalOp:
|
||||
event_node->signal_count++;
|
||||
event_node->thread_blocker.unblock();
|
||||
break;
|
||||
default:
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
return ParseResult::Success;
|
||||
}
|
||||
|
||||
virtual void debug_print(int indent) const override
|
||||
{
|
||||
AML_DEBUG_PRINT_INDENT(indent);
|
||||
AML_DEBUG_PRINT("Event ");
|
||||
name.debug_print();
|
||||
AML_DEBUG_PRINT(" (Signals: {})", signal_count.load());
|
||||
}
|
||||
|
||||
private:
|
||||
static ParseResult parse_event(ParseContext& context)
|
||||
{
|
||||
ASSERT(context.aml_data.size() >= 2);
|
||||
ASSERT(static_cast<AML::Byte>(context.aml_data[0]) == AML::Byte::ExtOpPrefix);
|
||||
ASSERT(static_cast<AML::ExtOp>(context.aml_data[1]) == AML::ExtOp::EventOp);
|
||||
context.aml_data = context.aml_data.slice(2);
|
||||
|
||||
auto name_string = NameString::parse(context.aml_data);
|
||||
if (!name_string.has_value())
|
||||
return ParseResult::Failure;
|
||||
|
||||
auto event = MUST(BAN::RefPtr<Event>::create(name_string->path.back()));
|
||||
if (!Namespace::root_namespace()->add_named_object(context, name_string.value(), event))
|
||||
return ParseResult::Success;
|
||||
|
||||
#if AML_DEBUG_LEVEL >= 2
|
||||
event->debug_print(0);
|
||||
AML_DEBUG_PRINTLN("");
|
||||
#endif
|
||||
|
||||
return ParseResult::Success;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,243 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <kernel/ACPI/AML/Buffer.h>
|
||||
#include <kernel/ACPI/AML/Bytes.h>
|
||||
#include <kernel/ACPI/AML/Integer.h>
|
||||
#include <kernel/ACPI/AML/ParseContext.h>
|
||||
#include <kernel/ACPI/AML/String.h>
|
||||
|
||||
namespace Kernel::ACPI::AML
|
||||
{
|
||||
|
||||
struct Expression
|
||||
{
|
||||
static ParseResult parse(ParseContext& context)
|
||||
{
|
||||
ASSERT(context.aml_data.size() >= 1);
|
||||
switch (static_cast<Byte>(context.aml_data[0]))
|
||||
{
|
||||
// unary
|
||||
case AML::Byte::IncrementOp:
|
||||
case AML::Byte::DecrementOp:
|
||||
{
|
||||
auto opcode = (static_cast<AML::Byte>(context.aml_data[0]) == AML::Byte::IncrementOp) ? AML::Byte::AddOp : AML::Byte::SubtractOp;
|
||||
context.aml_data = context.aml_data.slice(1);
|
||||
|
||||
auto source_result = AML::parse_object(context);
|
||||
if (!source_result.success())
|
||||
return ParseResult::Failure;
|
||||
auto conv_node = source_result.node() ? source_result.node()->convert(AML::Node::ConvInteger) : BAN::RefPtr<AML::Node>();
|
||||
if (!conv_node)
|
||||
{
|
||||
AML_ERROR("UnaryOp source not integer, type {}", static_cast<uint8_t>(source_result.node()->type));
|
||||
return ParseResult::Failure;
|
||||
}
|
||||
|
||||
auto source_node = static_cast<AML::Integer*>(conv_node.ptr());
|
||||
if (source_node->constant)
|
||||
{
|
||||
AML_ERROR("UnaryOp source is constant");
|
||||
return ParseResult::Failure;
|
||||
}
|
||||
|
||||
source_node->value += (opcode == AML::Byte::AddOp) ? 1 : -1;
|
||||
return ParseResult(source_node);
|
||||
}
|
||||
case AML::Byte::NotOp:
|
||||
AML_TODO("NotOp", context.aml_data[0]);
|
||||
return ParseResult::Failure;
|
||||
case AML::Byte::LNotOp:
|
||||
{
|
||||
context.aml_data = context.aml_data.slice(1);
|
||||
|
||||
auto source_result = AML::parse_object(context);
|
||||
if (!source_result.success())
|
||||
return ParseResult::Failure;
|
||||
auto conv_node = source_result.node() ? source_result.node()->convert(AML::Node::ConvInteger) : BAN::RefPtr<AML::Node>();
|
||||
if (!conv_node)
|
||||
{
|
||||
AML_ERROR("UnaryOp source not integer, type {}", static_cast<uint8_t>(source_result.node()->type));
|
||||
return ParseResult::Failure;
|
||||
}
|
||||
auto source_node = static_cast<AML::Integer*>(conv_node.ptr());
|
||||
if (!source_node)
|
||||
{
|
||||
AML_ERROR("Logical NotOp source is not integer");
|
||||
return ParseResult::Failure;
|
||||
}
|
||||
|
||||
auto result = source_node->value ? Integer::Constants::Zero : Integer::Constants::Ones;
|
||||
return ParseResult(result);
|
||||
}
|
||||
case AML::Byte::AddOp:
|
||||
case AML::Byte::AndOp:
|
||||
case AML::Byte::ModOp:
|
||||
case AML::Byte::MultiplyOp:
|
||||
case AML::Byte::NandOp:
|
||||
case AML::Byte::NorOp:
|
||||
case AML::Byte::OrOp:
|
||||
case AML::Byte::ShiftLeftOp:
|
||||
case AML::Byte::ShiftRightOp:
|
||||
case AML::Byte::SubtractOp:
|
||||
case AML::Byte::XorOp:
|
||||
return parse_binary_op(context);
|
||||
case AML::Byte::LAndOp:
|
||||
case AML::Byte::LEqualOp:
|
||||
case AML::Byte::LGreaterOp:
|
||||
case AML::Byte::LLessOp:
|
||||
case AML::Byte::LOrOp:
|
||||
return parse_logical_binary_op(context);
|
||||
case AML::Byte::DivideOp:
|
||||
AML_TODO("DivideOp");
|
||||
return ParseResult::Failure;
|
||||
default:
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
static ParseResult parse_binary_op(ParseContext& context)
|
||||
{
|
||||
auto opcode = static_cast<AML::Byte>(context.aml_data[0]);
|
||||
context.aml_data = context.aml_data.slice(1);
|
||||
|
||||
auto lhs_result = AML::parse_object(context);
|
||||
if (!lhs_result.success())
|
||||
return ParseResult::Failure;
|
||||
auto lhs_conv = lhs_result.node() ? lhs_result.node()->convert(AML::Node::ConvInteger) : BAN::RefPtr<AML::Node>();
|
||||
if (!lhs_conv)
|
||||
{
|
||||
AML_ERROR("BinaryOP {2H} LHS not an integer, type {}",
|
||||
static_cast<uint8_t>(opcode),
|
||||
static_cast<uint8_t>(lhs_result.node()->type)
|
||||
);
|
||||
if (lhs_result.node())
|
||||
lhs_result.node()->debug_print(1);
|
||||
AML_DEBUG_PRINTLN("");
|
||||
return ParseResult::Failure;
|
||||
}
|
||||
const auto lhs_value = static_cast<AML::Integer*>(lhs_conv.ptr())->value;
|
||||
|
||||
auto rhs_result = AML::parse_object(context);
|
||||
if (!rhs_result.success())
|
||||
return ParseResult::Failure;
|
||||
auto rhs_conv = rhs_result.node() ? rhs_result.node()->convert(AML::Node::ConvInteger) : BAN::RefPtr<AML::Node>();
|
||||
if (!rhs_conv)
|
||||
{
|
||||
AML_ERROR("BinaryOP {2H} RHS not an integer", static_cast<uint8_t>(opcode));
|
||||
if (rhs_result.node())
|
||||
rhs_result.node()->debug_print(1);
|
||||
AML_DEBUG_PRINTLN("");
|
||||
return ParseResult::Failure;
|
||||
}
|
||||
const auto rhs_value = static_cast<AML::Integer*>(rhs_conv.ptr())->value;
|
||||
|
||||
if (context.aml_data.size() < 1)
|
||||
{
|
||||
AML_ERROR("BinaryOP {2H} missing target", static_cast<uint8_t>(opcode));
|
||||
return ParseResult::Failure;
|
||||
}
|
||||
|
||||
BAN::RefPtr<AML::Node> target_node;
|
||||
if (context.aml_data[0] == 0x00)
|
||||
context.aml_data = context.aml_data.slice(1);
|
||||
else
|
||||
{
|
||||
auto target_result = AML::parse_object(context);
|
||||
if (!target_result.success())
|
||||
return ParseResult::Failure;
|
||||
target_node = target_result.node();
|
||||
if (!target_node)
|
||||
{
|
||||
AML_ERROR("BinaryOP {2H} target invalid", static_cast<uint8_t>(opcode));
|
||||
return ParseResult::Failure;
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t (*func)(uint64_t, uint64_t) = nullptr;
|
||||
switch (opcode)
|
||||
{
|
||||
case AML::Byte::AddOp: func = [](uint64_t a, uint64_t b) { return a + b; }; break;
|
||||
case AML::Byte::AndOp: func = [](uint64_t a, uint64_t b) { return a & b; }; break;
|
||||
case AML::Byte::ModOp: func = [](uint64_t a, uint64_t b) { return a % b; }; break;
|
||||
case AML::Byte::MultiplyOp: func = [](uint64_t a, uint64_t b) { return a * b; }; break;
|
||||
case AML::Byte::NandOp: func = [](uint64_t a, uint64_t b) { return ~(a & b); }; break;
|
||||
case AML::Byte::NorOp: func = [](uint64_t a, uint64_t b) { return ~(a | b); }; break;
|
||||
case AML::Byte::OrOp: func = [](uint64_t a, uint64_t b) { return a | b; }; break;
|
||||
case AML::Byte::ShiftLeftOp: func = [](uint64_t a, uint64_t b) { return a << b; }; break;
|
||||
case AML::Byte::ShiftRightOp: func = [](uint64_t a, uint64_t b) { return a >> b; }; break;
|
||||
case AML::Byte::SubtractOp: func = [](uint64_t a, uint64_t b) { return a - b; }; break;
|
||||
case AML::Byte::XorOp: func = [](uint64_t a, uint64_t b) { return a ^ b; }; break;
|
||||
default:
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
auto result_node = MUST(BAN::RefPtr<AML::Integer>::create(func(lhs_value, rhs_value)));
|
||||
if (target_node && !target_node->store(result_node))
|
||||
{
|
||||
AML_ERROR("BinaryOp {2H} failed to store result", static_cast<uint8_t>(opcode));
|
||||
return ParseResult::Failure;
|
||||
}
|
||||
|
||||
return ParseResult(result_node);
|
||||
}
|
||||
|
||||
static ParseResult parse_logical_binary_op(ParseContext& context)
|
||||
{
|
||||
auto opcode = static_cast<AML::Byte>(context.aml_data[0]);
|
||||
context.aml_data = context.aml_data.slice(1);
|
||||
|
||||
uint8_t mask;
|
||||
switch (opcode)
|
||||
{
|
||||
case AML::Byte::LAndOp:
|
||||
case AML::Byte::LOrOp:
|
||||
mask = AML::Node::ConvInteger;
|
||||
break;
|
||||
case AML::Byte::LEqualOp:
|
||||
case AML::Byte::LGreaterOp:
|
||||
case AML::Byte::LLessOp:
|
||||
mask = AML::Node::ConvInteger | AML::Node::ConvString | AML::Node::ConvBuffer;
|
||||
break;
|
||||
default:
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
auto lhs_result = AML::parse_object(context);
|
||||
if (!lhs_result.success())
|
||||
return ParseResult::Failure;
|
||||
auto lhs_node = lhs_result.node() ? lhs_result.node()->convert(mask) : BAN::RefPtr<AML::Node>();
|
||||
if (!lhs_node)
|
||||
{
|
||||
AML_TODO("Logical BinaryOP {2H} LHS evaluated to nothing", static_cast<uint8_t>(opcode));
|
||||
return ParseResult::Failure;
|
||||
}
|
||||
|
||||
auto rhs_result = AML::parse_object(context);
|
||||
if (!rhs_result.success())
|
||||
return ParseResult::Failure;
|
||||
|
||||
BAN::Optional<bool> result = false;
|
||||
switch (lhs_node->type)
|
||||
{
|
||||
case AML::Node::Type::Integer:
|
||||
result = static_cast<AML::Integer*>(lhs_node.ptr())->logical_compare(rhs_result.node(), opcode);
|
||||
break;
|
||||
case AML::Node::Type::Buffer:
|
||||
result = static_cast<AML::Buffer*>(lhs_node.ptr())->logical_compare(rhs_result.node(), opcode);
|
||||
break;
|
||||
case AML::Node::Type::String:
|
||||
result = static_cast<AML::String*>(lhs_node.ptr())->logical_compare(rhs_result.node(), opcode);
|
||||
break;
|
||||
default:
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
if (!result.has_value())
|
||||
return ParseResult::Failure;
|
||||
|
||||
return ParseResult(result.value() ? AML::Integer::Constants::Ones : AML::Integer::Constants::Zero);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,199 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <kernel/ACPI/AML/NamedObject.h>
|
||||
#include <kernel/ACPI/AML/ParseContext.h>
|
||||
#include <kernel/ACPI/AML/Pkg.h>
|
||||
#include <kernel/ACPI/AML/Region.h>
|
||||
|
||||
namespace Kernel::ACPI::AML
|
||||
{
|
||||
|
||||
struct FieldRules
|
||||
{
|
||||
enum class AccessType
|
||||
{
|
||||
Any = 0,
|
||||
Byte = 1,
|
||||
Word = 2,
|
||||
DWord = 3,
|
||||
QWord = 4,
|
||||
Buffer = 5,
|
||||
};
|
||||
AccessType access_type;
|
||||
|
||||
enum class LockRule
|
||||
{
|
||||
NoLock = 0,
|
||||
Lock = 1,
|
||||
};
|
||||
LockRule lock_rule;
|
||||
|
||||
enum class UpdateRule
|
||||
{
|
||||
Preserve = 0,
|
||||
WriteAsOnes = 1,
|
||||
WriteAsZeros = 2,
|
||||
};
|
||||
UpdateRule update_rule;
|
||||
|
||||
enum class AccessAttrib
|
||||
{
|
||||
Normal = 0,
|
||||
Bytes = 1,
|
||||
RawBytes = 2,
|
||||
RawProcessBytes = 3,
|
||||
};
|
||||
AccessAttrib access_attrib = AccessAttrib::Normal;
|
||||
uint8_t access_length = 0;
|
||||
};
|
||||
|
||||
struct FieldElement final : public AML::NamedObject
|
||||
{
|
||||
uint64_t bit_offset;
|
||||
uint64_t bit_count;
|
||||
|
||||
FieldRules access_rules;
|
||||
|
||||
BAN::RefPtr<OpRegion> op_region;
|
||||
|
||||
FieldElement(NameSeg name, uint64_t bit_offset, uint64_t bit_count, FieldRules access_rules)
|
||||
: NamedObject(Node::Type::FieldElement, name)
|
||||
, bit_offset(bit_offset)
|
||||
, bit_count(bit_count)
|
||||
, access_rules(access_rules)
|
||||
{}
|
||||
|
||||
BAN::RefPtr<AML::Node> convert(uint8_t mask) override
|
||||
{
|
||||
if (mask & AML::Node::ConvInteger)
|
||||
return as_integer();
|
||||
if (mask & AML::Node::ConvBuffer)
|
||||
{
|
||||
AML_TODO("Convert BankFieldElement to Buffer");
|
||||
return {};
|
||||
}
|
||||
if (mask & AML::Node::ConvString)
|
||||
{
|
||||
AML_TODO("Convert BankFieldElement to String");
|
||||
return {};
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
BAN::RefPtr<AML::Node> store(BAN::RefPtr<Node> source) override;
|
||||
|
||||
void debug_print(int indent) const override;
|
||||
|
||||
private:
|
||||
BAN::RefPtr<AML::Integer> as_integer();
|
||||
|
||||
BAN::Optional<uint64_t> evaluate_internal();
|
||||
bool store_internal(uint64_t value);
|
||||
|
||||
friend struct IndexFieldElement;
|
||||
friend struct BankFieldElement;
|
||||
};
|
||||
|
||||
struct Field
|
||||
{
|
||||
static ParseResult parse(ParseContext& context);
|
||||
};
|
||||
|
||||
struct IndexFieldElement final : public AML::NamedObject
|
||||
{
|
||||
uint64_t bit_offset;
|
||||
uint64_t bit_count;
|
||||
|
||||
FieldRules access_rules;
|
||||
|
||||
BAN::RefPtr<FieldElement> index_element;
|
||||
BAN::RefPtr<FieldElement> data_element;
|
||||
|
||||
IndexFieldElement(NameSeg name, uint64_t bit_offset, uint64_t bit_count, FieldRules access_rules)
|
||||
: NamedObject(Node::Type::IndexFieldElement, name)
|
||||
, bit_offset(bit_offset)
|
||||
, bit_count(bit_count)
|
||||
, access_rules(access_rules)
|
||||
{}
|
||||
|
||||
BAN::RefPtr<AML::Node> convert(uint8_t mask) override
|
||||
{
|
||||
if (mask & AML::Node::ConvInteger)
|
||||
if (auto node = as_integer())
|
||||
return node;
|
||||
if (mask & AML::Node::ConvBuffer)
|
||||
{
|
||||
AML_TODO("convert BankFieldElement to Buffer");
|
||||
return {};
|
||||
}
|
||||
if (mask & AML::Node::ConvString)
|
||||
{
|
||||
AML_TODO("convert BankFieldElement to String");
|
||||
return {};
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
BAN::RefPtr<AML::Node> store(BAN::RefPtr<Node> source) override;
|
||||
|
||||
void debug_print(int indent) const override;
|
||||
|
||||
private:
|
||||
BAN::RefPtr<AML::Integer> as_integer();
|
||||
};
|
||||
|
||||
struct IndexField
|
||||
{
|
||||
static ParseResult parse(ParseContext& context);
|
||||
};
|
||||
|
||||
struct BankFieldElement final : public AML::NamedObject
|
||||
{
|
||||
uint64_t bit_offset;
|
||||
uint64_t bit_count;
|
||||
|
||||
FieldRules access_rules;
|
||||
|
||||
BAN::RefPtr<OpRegion> op_region;
|
||||
BAN::RefPtr<FieldElement> bank_selector;
|
||||
uint64_t bank_value;
|
||||
|
||||
BankFieldElement(NameSeg name, uint64_t bit_offset, uint64_t bit_count, FieldRules access_rules)
|
||||
: NamedObject(Node::Type::BankFieldElement, name)
|
||||
, bit_offset(bit_offset)
|
||||
, bit_count(bit_count)
|
||||
, access_rules(access_rules)
|
||||
{}
|
||||
|
||||
BAN::RefPtr<AML::Node> convert(uint8_t mask) override
|
||||
{
|
||||
if (mask & AML::Node::ConvInteger)
|
||||
if (auto node = as_integer())
|
||||
return node;
|
||||
if (mask & AML::Node::ConvBuffer)
|
||||
{
|
||||
AML_TODO("convert BankFieldElement to Buffer");
|
||||
return {};
|
||||
}
|
||||
if (mask & AML::Node::ConvString)
|
||||
{
|
||||
AML_TODO("convert BankFieldElement to String");
|
||||
return {};
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
BAN::RefPtr<AML::Node> store(BAN::RefPtr<Node> source) override;
|
||||
|
||||
void debug_print(int indent) const override;
|
||||
|
||||
private:
|
||||
BAN::RefPtr<AML::Integer> as_integer();
|
||||
};
|
||||
|
||||
struct BankField
|
||||
{
|
||||
static ParseResult parse(ParseContext& context);
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <BAN/HashMap.h>
|
||||
#include <kernel/ACPI/AML/Node.h>
|
||||
#include <kernel/ACPI/AML/ParseContext.h>
|
||||
#include <kernel/ACPI/AML/Pkg.h>
|
||||
|
||||
namespace Kernel::ACPI::AML
|
||||
{
|
||||
|
||||
struct IfElse
|
||||
{
|
||||
static ParseResult parse(ParseContext& context)
|
||||
{
|
||||
ASSERT(context.aml_data.size() >= 1);
|
||||
ASSERT(static_cast<Byte>(context.aml_data[0]) == Byte::IfOp);
|
||||
context.aml_data = context.aml_data.slice(1);
|
||||
|
||||
auto if_pkg = AML::parse_pkg(context.aml_data);
|
||||
if (!if_pkg.has_value())
|
||||
return ParseResult::Failure;
|
||||
|
||||
auto outer_aml_data = context.aml_data;
|
||||
context.aml_data = if_pkg.value();
|
||||
|
||||
auto predicate_result = AML::parse_object(context);
|
||||
if (!predicate_result.success())
|
||||
return ParseResult::Failure;
|
||||
auto predicate_node = predicate_result.node() ? predicate_result.node()->convert(AML::Node::ConvInteger) : BAN::RefPtr<AML::Node>();
|
||||
if (!predicate_node)
|
||||
{
|
||||
AML_ERROR("If predicate is not an integer");
|
||||
return ParseResult::Failure;
|
||||
}
|
||||
const auto predicate_value = static_cast<AML::Integer*>(predicate_node.ptr())->value;
|
||||
|
||||
// Else
|
||||
BAN::ConstByteSpan else_pkg;
|
||||
if (outer_aml_data.size() >= 1 && static_cast<AML::Byte>(outer_aml_data[0]) == Byte::ElseOp)
|
||||
{
|
||||
outer_aml_data = outer_aml_data.slice(1);
|
||||
auto else_pkg_result = AML::parse_pkg(outer_aml_data);
|
||||
if (!else_pkg_result.has_value())
|
||||
return ParseResult::Failure;
|
||||
else_pkg = else_pkg_result.value();
|
||||
}
|
||||
if (predicate_value == 0)
|
||||
context.aml_data = else_pkg;
|
||||
|
||||
while (context.aml_data.size() > 0)
|
||||
{
|
||||
auto object_result = AML::parse_object(context);
|
||||
if (object_result.returned() || object_result.breaked() || object_result.continued())
|
||||
return object_result;
|
||||
if (!object_result.success())
|
||||
return ParseResult::Failure;
|
||||
}
|
||||
|
||||
context.aml_data = outer_aml_data;
|
||||
|
||||
return ParseResult::Success;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,126 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <kernel/ACPI/AML/Buffer.h>
|
||||
#include <kernel/ACPI/AML/Node.h>
|
||||
#include <kernel/ACPI/AML/Package.h>
|
||||
#include <kernel/ACPI/AML/ParseContext.h>
|
||||
#include <kernel/ACPI/AML/Reference.h>
|
||||
#include <kernel/ACPI/AML/Register.h>
|
||||
|
||||
namespace Kernel::ACPI::AML
|
||||
{
|
||||
|
||||
struct Index
|
||||
{
|
||||
static ParseResult parse(ParseContext& context)
|
||||
{
|
||||
ASSERT(context.aml_data.size() >= 1);
|
||||
ASSERT(static_cast<Byte>(context.aml_data[0]) == Byte::IndexOp);
|
||||
context.aml_data = context.aml_data.slice(1);
|
||||
|
||||
auto source_result = AML::parse_object(context);
|
||||
if (!source_result.success())
|
||||
return ParseResult::Failure;
|
||||
auto source = source_result.node() ? source_result.node()->to_underlying() : BAN::RefPtr<AML::Node>();
|
||||
if (source && source->type != AML::Node::Type::Package)
|
||||
source = source->convert(AML::Node::ConvBuffer | AML::Node::ConvInteger | AML::Node::ConvString);
|
||||
if (!source)
|
||||
{
|
||||
AML_ERROR("IndexOp source could not be converted");
|
||||
return ParseResult::Failure;
|
||||
}
|
||||
|
||||
auto index_result = AML::parse_object(context);
|
||||
if (!index_result.success())
|
||||
return ParseResult::Failure;
|
||||
auto index_node = index_result.node()
|
||||
? index_result.node()->convert(AML::Node::ConvInteger)
|
||||
: BAN::RefPtr<AML::Node>();
|
||||
if (!index_node)
|
||||
{
|
||||
AML_ERROR("IndexOp index is not an integer");
|
||||
return ParseResult::Failure;
|
||||
}
|
||||
const auto index = static_cast<AML::Integer*>(index_node.ptr())->value;
|
||||
|
||||
BAN::RefPtr<AML::Reference> result;
|
||||
switch (source->type)
|
||||
{
|
||||
case AML::Node::Type::Buffer:
|
||||
{
|
||||
auto buffer = BAN::RefPtr<AML::Buffer>(static_cast<AML::Buffer*>(source.ptr()));
|
||||
if (index >= buffer->buffer.size())
|
||||
{
|
||||
AML_ERROR("IndexOp index is out of buffer bounds");
|
||||
return ParseResult::Failure;
|
||||
}
|
||||
auto buffer_field = MUST(BAN::RefPtr<BufferField>::create(NameSeg(""_sv), buffer, index * 8, 8));
|
||||
result = MUST(BAN::RefPtr<AML::Reference>::create(buffer_field));
|
||||
break;
|
||||
}
|
||||
case AML::Node::Type::Package:
|
||||
{
|
||||
auto package = static_cast<AML::Package*>(source.ptr());
|
||||
if (index >= package->elements.size())
|
||||
{
|
||||
AML_ERROR("IndexOp index is out of package bounds");
|
||||
return ParseResult::Failure;
|
||||
}
|
||||
auto package_element = package->elements[index];
|
||||
if (!package_element)
|
||||
{
|
||||
AML_ERROR("IndexOp target is null package element");
|
||||
return ParseResult::Failure;
|
||||
}
|
||||
result = MUST(BAN::RefPtr<AML::Reference>::create(package_element));
|
||||
break;
|
||||
}
|
||||
case AML::Node::Type::String:
|
||||
{
|
||||
auto string = BAN::RefPtr<AML::String>(static_cast<AML::String*>(source.ptr()));
|
||||
if (index >= string->string.size())
|
||||
{
|
||||
AML_ERROR("IndexOp index is out of string bounds");
|
||||
return ParseResult::Failure;
|
||||
}
|
||||
auto buffer_field = MUST(BAN::RefPtr<BufferField>::create(NameSeg(""_sv), string, index * 8, 8));
|
||||
result = MUST(BAN::RefPtr<AML::Reference>::create(buffer_field));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
AML_ERROR("IndexOp source is not a Buffer, Package, or String");
|
||||
return ParseResult::Failure;
|
||||
}
|
||||
|
||||
#if AML_DEBUG_LEVEL >= 2
|
||||
AML_DEBUG_PRINT("Index {}, ", index);
|
||||
source->debug_print(0);
|
||||
AML_DEBUG_PRINTLN("");
|
||||
#endif
|
||||
|
||||
if (context.aml_data.size() < 1)
|
||||
return ParseResult::Failure;
|
||||
|
||||
if (context.aml_data[0] == 0x00)
|
||||
context.aml_data = context.aml_data.slice(1);
|
||||
else
|
||||
{
|
||||
auto destination_result = AML::parse_object(context);
|
||||
if (!destination_result.success())
|
||||
return ParseResult::Failure;
|
||||
auto destination = destination_result.node();
|
||||
if (!destination)
|
||||
{
|
||||
AML_ERROR("IndexOp failed to resolve destination");
|
||||
return ParseResult::Failure;
|
||||
}
|
||||
|
||||
if (!destination->store(result))
|
||||
return ParseResult::Failure;
|
||||
}
|
||||
|
||||
return ParseResult(result);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <BAN/Optional.h>
|
||||
#include <BAN/String.h>
|
||||
#include <BAN/Vector.h>
|
||||
#include <kernel/ACPI/AML/Bytes.h>
|
||||
#include <kernel/ACPI/AML/Node.h>
|
||||
#include <kernel/ACPI/AML/Utils.h>
|
||||
|
||||
namespace Kernel::ACPI::AML
|
||||
{
|
||||
|
||||
struct Integer final : public AML::Node
|
||||
{
|
||||
struct Constants
|
||||
{
|
||||
// Initialized in Namespace::create_root_namespace
|
||||
static BAN::RefPtr<Integer> Zero;
|
||||
static BAN::RefPtr<Integer> One;
|
||||
static BAN::RefPtr<Integer> Ones;
|
||||
};
|
||||
|
||||
uint64_t value;
|
||||
const bool constant;
|
||||
|
||||
Integer(uint64_t value, bool constant = false);
|
||||
|
||||
BAN::Optional<bool> logical_compare(BAN::RefPtr<AML::Node> node, AML::Byte binaryop);
|
||||
|
||||
BAN::RefPtr<AML::Node> convert(uint8_t mask) override;
|
||||
BAN::RefPtr<Node> copy() override;
|
||||
BAN::RefPtr<AML::Node> store(BAN::RefPtr<AML::Node> store_node) override;
|
||||
|
||||
static ParseResult parse(BAN::ConstByteSpan& aml_data);
|
||||
|
||||
void debug_print(int indent) const override;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,182 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <BAN/Function.h>
|
||||
#include <kernel/ACPI/AML/Bytes.h>
|
||||
#include <kernel/ACPI/AML/Namespace.h>
|
||||
#include <kernel/ACPI/AML/Namespace.h>
|
||||
#include <kernel/ACPI/AML/ParseContext.h>
|
||||
#include <kernel/ACPI/AML/Pkg.h>
|
||||
#include <kernel/ACPI/AML/Register.h>
|
||||
#include <kernel/ACPI/AML/Scope.h>
|
||||
|
||||
namespace Kernel::ACPI::AML
|
||||
{
|
||||
|
||||
struct Method final : public AML::Scope
|
||||
{
|
||||
Kernel::Mutex mutex;
|
||||
uint8_t arg_count;
|
||||
bool serialized;
|
||||
uint8_t sync_level;
|
||||
|
||||
BAN::Function<BAN::RefPtr<AML::Node>(ParseContext&)> override_function;
|
||||
BAN::ConstByteSpan term_list;
|
||||
|
||||
Method(AML::NameSeg name, uint8_t arg_count, bool serialized, uint8_t sync_level)
|
||||
: AML::Scope(Node::Type::Method, name)
|
||||
, arg_count(arg_count)
|
||||
, serialized(serialized)
|
||||
, sync_level(sync_level)
|
||||
{}
|
||||
|
||||
BAN::RefPtr<AML::Node> convert(uint8_t) override { return {}; }
|
||||
|
||||
static ParseResult parse(AML::ParseContext& context)
|
||||
{
|
||||
ASSERT(context.aml_data.size() >= 1);
|
||||
ASSERT(static_cast<Byte>(context.aml_data[0]) == Byte::MethodOp);
|
||||
context.aml_data = context.aml_data.slice(1);
|
||||
|
||||
auto method_pkg = AML::parse_pkg(context.aml_data);
|
||||
if (!method_pkg.has_value())
|
||||
return ParseResult::Failure;
|
||||
|
||||
auto name_string = AML::NameString::parse(method_pkg.value());
|
||||
if (!name_string.has_value())
|
||||
return ParseResult::Failure;
|
||||
|
||||
if (method_pkg->size() < 1)
|
||||
return ParseResult::Failure;
|
||||
auto method_flags = method_pkg.value()[0];
|
||||
method_pkg = method_pkg.value().slice(1);
|
||||
|
||||
auto method = MUST(BAN::RefPtr<Method>::create(
|
||||
name_string.value().path.back(),
|
||||
method_flags & 0x07,
|
||||
(method_flags >> 3) & 0x01,
|
||||
method_flags >> 4
|
||||
));
|
||||
if (!Namespace::root_namespace()->add_named_object(context, name_string.value(), method))
|
||||
return ParseResult::Success;
|
||||
method->term_list = method_pkg.value();
|
||||
|
||||
#if AML_DEBUG_LEVEL >= 2
|
||||
method->debug_print(0);
|
||||
AML_DEBUG_PRINTLN("");
|
||||
#endif
|
||||
|
||||
return ParseResult::Success;
|
||||
}
|
||||
|
||||
BAN::Optional<BAN::RefPtr<AML::Node>> invoke(
|
||||
BAN::RefPtr<AML::Node> arg0 = {},
|
||||
BAN::RefPtr<AML::Node> arg1 = {},
|
||||
BAN::RefPtr<AML::Node> arg2 = {},
|
||||
BAN::RefPtr<AML::Node> arg3 = {},
|
||||
BAN::RefPtr<AML::Node> arg4 = {},
|
||||
BAN::RefPtr<AML::Node> arg5 = {},
|
||||
BAN::RefPtr<AML::Node> arg6 = {}
|
||||
)
|
||||
{
|
||||
BAN::Vector<uint8_t> sync_stack;
|
||||
return invoke_with_sync_stack(sync_stack, arg0, arg1, arg2, arg3, arg4, arg5, arg6);
|
||||
}
|
||||
|
||||
BAN::Optional<BAN::RefPtr<AML::Node>> invoke_with_sync_stack(
|
||||
BAN::Vector<uint8_t>& current_sync_stack,
|
||||
BAN::RefPtr<AML::Node> arg0 = {},
|
||||
BAN::RefPtr<AML::Node> arg1 = {},
|
||||
BAN::RefPtr<AML::Node> arg2 = {},
|
||||
BAN::RefPtr<AML::Node> arg3 = {},
|
||||
BAN::RefPtr<AML::Node> arg4 = {},
|
||||
BAN::RefPtr<AML::Node> arg5 = {},
|
||||
BAN::RefPtr<AML::Node> arg6 = {}
|
||||
)
|
||||
{
|
||||
if (serialized && !current_sync_stack.empty() && sync_level < current_sync_stack.back())
|
||||
{
|
||||
AML_ERROR("Trying to evaluate method {} with lower sync level than current sync level", scope);
|
||||
return {};
|
||||
}
|
||||
|
||||
ParseContext context;
|
||||
context.aml_data = term_list;
|
||||
context.scope = scope;
|
||||
context.method_args[0] = MUST(BAN::RefPtr<AML::Register>::create(arg0));
|
||||
context.method_args[1] = MUST(BAN::RefPtr<AML::Register>::create(arg1));
|
||||
context.method_args[2] = MUST(BAN::RefPtr<AML::Register>::create(arg2));
|
||||
context.method_args[3] = MUST(BAN::RefPtr<AML::Register>::create(arg3));
|
||||
context.method_args[4] = MUST(BAN::RefPtr<AML::Register>::create(arg4));
|
||||
context.method_args[5] = MUST(BAN::RefPtr<AML::Register>::create(arg5));
|
||||
context.method_args[6] = MUST(BAN::RefPtr<AML::Register>::create(arg6));
|
||||
context.sync_stack = BAN::move(current_sync_stack);
|
||||
for (auto& local : context.method_locals)
|
||||
local = MUST(BAN::RefPtr<AML::Register>::create());
|
||||
|
||||
if (serialized)
|
||||
{
|
||||
mutex.lock();
|
||||
MUST(context.sync_stack.push_back(sync_level));
|
||||
}
|
||||
|
||||
#if AML_DEBUG_LEVEL >= 2
|
||||
AML_DEBUG_PRINTLN("Evaluating {}", scope);
|
||||
#endif
|
||||
|
||||
BAN::Optional<BAN::RefPtr<AML::Node>> return_value = BAN::RefPtr<AML::Node>();
|
||||
|
||||
if (override_function)
|
||||
return_value = override_function(context);
|
||||
else
|
||||
{
|
||||
while (context.aml_data.size() > 0)
|
||||
{
|
||||
auto parse_result = AML::parse_object(context);
|
||||
if (parse_result.returned())
|
||||
{
|
||||
return_value = parse_result.node();
|
||||
break;
|
||||
}
|
||||
if (!parse_result.success())
|
||||
{
|
||||
AML_ERROR("Method {} evaluate failed", scope);
|
||||
return_value = {};
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (return_value.has_value() && return_value.value() && return_value.value()->type == AML::Node::Type::Register)
|
||||
return_value.value() = static_cast<AML::Register*>(return_value.value().ptr())->value;
|
||||
|
||||
while (!context.created_objects.empty())
|
||||
{
|
||||
Namespace::root_namespace()->remove_named_object(context.created_objects.back());
|
||||
context.created_objects.pop_back();
|
||||
}
|
||||
|
||||
if (serialized)
|
||||
{
|
||||
context.sync_stack.pop_back();
|
||||
mutex.unlock();
|
||||
}
|
||||
|
||||
current_sync_stack = BAN::move(context.sync_stack);
|
||||
|
||||
return return_value;
|
||||
}
|
||||
|
||||
virtual void debug_print(int indent) const override
|
||||
{
|
||||
AML_DEBUG_PRINT_INDENT(indent);
|
||||
AML_DEBUG_PRINT("Method ");
|
||||
name.debug_print();
|
||||
AML_DEBUG_PRINTLN("({} args, {}Serialized, 0x{H}) {", arg_count, serialized ? "" : "Not", sync_level);
|
||||
AML_DEBUG_PRINT_INDENT(indent + 1);
|
||||
AML_DEBUG_PRINTLN("TermList: {} bytes", term_list.size());
|
||||
AML_DEBUG_PRINT_INDENT(indent);
|
||||
AML_DEBUG_PRINT("}");
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,170 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <kernel/ACPI/AML/Bytes.h>
|
||||
#include <kernel/ACPI/AML/Integer.h>
|
||||
#include <kernel/ACPI/AML/NamedObject.h>
|
||||
#include <kernel/ACPI/AML/ParseContext.h>
|
||||
#include <kernel/Lock/Mutex.h>
|
||||
#include <kernel/Timer/Timer.h>
|
||||
|
||||
namespace Kernel::ACPI::AML
|
||||
{
|
||||
|
||||
struct Mutex final : public AML::NamedObject
|
||||
{
|
||||
Kernel::Mutex mutex;
|
||||
uint8_t sync_level;
|
||||
bool global;
|
||||
|
||||
Mutex(NameSeg name, uint8_t sync_level, bool global = false)
|
||||
: NamedObject(Node::Type::Mutex, name)
|
||||
, sync_level(sync_level)
|
||||
, global(global)
|
||||
{}
|
||||
|
||||
BAN::RefPtr<AML::Node> convert(uint8_t) override { return {}; }
|
||||
|
||||
static ParseResult parse(ParseContext& context)
|
||||
{
|
||||
ASSERT(context.aml_data.size() >= 2);
|
||||
ASSERT(static_cast<AML::Byte>(context.aml_data[0]) == AML::Byte::ExtOpPrefix);
|
||||
|
||||
switch (static_cast<AML::ExtOp>(context.aml_data[1]))
|
||||
{
|
||||
case AML::ExtOp::MutexOp:
|
||||
return parse_mutex(context);
|
||||
case AML::ExtOp::AcquireOp:
|
||||
return parse_acquire(context);
|
||||
case AML::ExtOp::ReleaseOp:
|
||||
return parse_release(context);
|
||||
default:
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
}
|
||||
|
||||
virtual void debug_print(int indent) const override
|
||||
{
|
||||
AML_DEBUG_PRINT_INDENT(indent);
|
||||
AML_DEBUG_PRINT("Mutex ");
|
||||
name.debug_print();
|
||||
AML_DEBUG_PRINT(" (SyncLevel: {})", sync_level);
|
||||
}
|
||||
|
||||
private:
|
||||
static ParseResult parse_mutex(ParseContext& context)
|
||||
{
|
||||
ASSERT(context.aml_data.size() >= 2);
|
||||
ASSERT(static_cast<AML::Byte>(context.aml_data[0]) == AML::Byte::ExtOpPrefix);
|
||||
ASSERT(static_cast<AML::ExtOp>(context.aml_data[1]) == AML::ExtOp::MutexOp);
|
||||
context.aml_data = context.aml_data.slice(2);
|
||||
|
||||
auto name = NameString::parse(context.aml_data);
|
||||
if (!name.has_value())
|
||||
return ParseResult::Failure;
|
||||
|
||||
if (context.aml_data.size() < 1)
|
||||
return ParseResult::Failure;
|
||||
auto sync_level = context.aml_data[0];
|
||||
context.aml_data = context.aml_data.slice(1);
|
||||
|
||||
if (sync_level & 0xF0)
|
||||
{
|
||||
AML_ERROR("Invalid sync level {}", sync_level);
|
||||
return ParseResult::Failure;
|
||||
}
|
||||
|
||||
auto mutex = MUST(BAN::RefPtr<Mutex>::create(name->path.back(), sync_level));
|
||||
if (!Namespace::root_namespace()->add_named_object(context, name.value(), mutex))
|
||||
return ParseResult::Success;
|
||||
|
||||
#if AML_DEBUG_LEVEL >= 2
|
||||
mutex->debug_print(0);
|
||||
AML_DEBUG_PRINTLN("");
|
||||
#endif
|
||||
|
||||
return ParseResult::Success;
|
||||
}
|
||||
|
||||
static ParseResult parse_acquire(ParseContext& context)
|
||||
{
|
||||
ASSERT(context.aml_data.size() >= 2);
|
||||
ASSERT(static_cast<AML::Byte>(context.aml_data[0]) == AML::Byte::ExtOpPrefix);
|
||||
ASSERT(static_cast<AML::ExtOp>(context.aml_data[1]) == AML::ExtOp::AcquireOp);
|
||||
context.aml_data = context.aml_data.slice(2);
|
||||
|
||||
auto mutex_result = AML::parse_object(context);
|
||||
if (!mutex_result.success() || !mutex_result.node() || mutex_result.node()->type != AML::Node::Type::Mutex)
|
||||
{
|
||||
AML_ERROR("Acquire does not name a valid mutex");
|
||||
return ParseResult::Failure;
|
||||
}
|
||||
|
||||
auto* mutex = static_cast<AML::Mutex*>(mutex_result.node().ptr());
|
||||
if (mutex->sync_level < context.sync_level())
|
||||
{
|
||||
AML_ERROR("Trying to acquire mutex with lower sync level than current sync level");
|
||||
return ParseResult::Failure;
|
||||
}
|
||||
|
||||
if (context.aml_data.size() < 2)
|
||||
{
|
||||
AML_ERROR("Missing timeout value");
|
||||
return ParseResult::Failure;
|
||||
}
|
||||
uint16_t timeout = context.aml_data[0] | (context.aml_data[1] << 8);
|
||||
context.aml_data = context.aml_data.slice(2);
|
||||
|
||||
if (timeout >= 0xFFFF)
|
||||
mutex->mutex.lock();
|
||||
else
|
||||
{
|
||||
// FIXME: This is a very inefficient way to wait for a mutex
|
||||
uint64_t wake_time = SystemTimer::get().ms_since_boot() + timeout;
|
||||
while (!mutex->mutex.try_lock())
|
||||
{
|
||||
if (SystemTimer::get().ms_since_boot() >= wake_time)
|
||||
return ParseResult(Integer::Constants::Ones);
|
||||
Processor::yield();
|
||||
}
|
||||
}
|
||||
|
||||
MUST(context.sync_stack.push_back(mutex->sync_level));
|
||||
return ParseResult(Integer::Constants::Zero);
|
||||
}
|
||||
|
||||
static ParseResult parse_release(ParseContext& context)
|
||||
{
|
||||
ASSERT(context.aml_data.size() >= 2);
|
||||
ASSERT(static_cast<AML::Byte>(context.aml_data[0]) == AML::Byte::ExtOpPrefix);
|
||||
ASSERT(static_cast<AML::ExtOp>(context.aml_data[1]) == AML::ExtOp::ReleaseOp);
|
||||
context.aml_data = context.aml_data.slice(2);
|
||||
|
||||
auto mutex_result = AML::parse_object(context);
|
||||
if (!mutex_result.success() || !mutex_result.node() || mutex_result.node()->type != AML::Node::Type::Mutex)
|
||||
{
|
||||
AML_ERROR("Release does not name a valid mutex");
|
||||
return ParseResult::Failure;
|
||||
}
|
||||
|
||||
if (context.sync_stack.empty())
|
||||
{
|
||||
AML_ERROR("Trying to release mutex without having acquired it");
|
||||
return ParseResult::Failure;
|
||||
}
|
||||
|
||||
auto* mutex = static_cast<AML::Mutex*>(mutex_result.node().ptr());
|
||||
if (mutex->sync_level != context.sync_level())
|
||||
{
|
||||
AML_ERROR("Trying to release mutex with different sync level than current sync level");
|
||||
return ParseResult::Failure;
|
||||
}
|
||||
|
||||
mutex->mutex.unlock();
|
||||
context.sync_stack.pop_back();
|
||||
|
||||
return ParseResult::Success;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <BAN/HashMap.h>
|
||||
#include <kernel/ACPI/AML/Names.h>
|
||||
|
||||
namespace Kernel::ACPI::AML
|
||||
{
|
||||
|
||||
struct NamedObject : public AML::Node
|
||||
{
|
||||
BAN::RefPtr<NamedObject> parent;
|
||||
NameSeg name;
|
||||
|
||||
NamedObject(Node::Type type, NameSeg name) : Node(type), name(name) {}
|
||||
};
|
||||
|
||||
struct Name final : public AML::NamedObject
|
||||
{
|
||||
BAN::RefPtr<AML::Node> object;
|
||||
|
||||
Name(NameSeg name, BAN::RefPtr<AML::Node> object)
|
||||
: NamedObject(Node::Type::Name, name), object(BAN::move(object))
|
||||
{}
|
||||
|
||||
BAN::RefPtr<AML::Node> to_underlying() override { return object; }
|
||||
|
||||
BAN::RefPtr<AML::Node> convert(uint8_t mask) override
|
||||
{
|
||||
ASSERT(object);
|
||||
return object->convert(mask);
|
||||
}
|
||||
|
||||
BAN::RefPtr<AML::Node> store(BAN::RefPtr<AML::Node> node) override
|
||||
{
|
||||
ASSERT(object);
|
||||
ASSERT(object->type != AML::Node::Type::Reference);
|
||||
return object->store(node);
|
||||
}
|
||||
|
||||
static ParseResult parse(ParseContext& context);
|
||||
virtual void debug_print(int indent) const override;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,244 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <BAN/Optional.h>
|
||||
#include <BAN/String.h>
|
||||
#include <BAN/Vector.h>
|
||||
#include <kernel/ACPI/AML/Bytes.h>
|
||||
#include <kernel/ACPI/AML/Node.h>
|
||||
#include <kernel/ACPI/AML/Utils.h>
|
||||
|
||||
namespace Kernel::ACPI::AML
|
||||
{
|
||||
|
||||
struct NameSeg
|
||||
{
|
||||
union {
|
||||
char chars[4];
|
||||
uint32_t u32;
|
||||
};
|
||||
|
||||
NameSeg() = default;
|
||||
|
||||
NameSeg(BAN::StringView name)
|
||||
{
|
||||
ASSERT(name.size() <= 4);
|
||||
for (size_t i = 0; i < name.size(); i++)
|
||||
chars[i] = static_cast<char>(name[i]);
|
||||
for (size_t i = name.size(); i < 4; i++)
|
||||
chars[i] = '_';
|
||||
}
|
||||
|
||||
NameSeg(BAN::ConstByteSpan& aml_data)
|
||||
{
|
||||
ASSERT(aml_data.size() >= 4);
|
||||
for (size_t i = 0; i < 4; i++)
|
||||
chars[i] = static_cast<char>(aml_data[i]);
|
||||
aml_data = aml_data.slice(4);
|
||||
}
|
||||
|
||||
BAN::StringView sv() const
|
||||
{
|
||||
size_t len = 4;
|
||||
while (len > 0 && chars[len - 1] == '_')
|
||||
len--;
|
||||
return BAN::StringView(chars, len);
|
||||
}
|
||||
|
||||
static BAN::Optional<NameSeg> parse(BAN::ConstByteSpan& aml_data)
|
||||
{
|
||||
if (aml_data.size() < 4)
|
||||
return {};
|
||||
|
||||
if (!is_lead_name_char(aml_data[0])
|
||||
|| !is_name_char(aml_data[1])
|
||||
|| !is_name_char(aml_data[2])
|
||||
|| !is_name_char(aml_data[3]))
|
||||
return {};
|
||||
|
||||
return NameSeg(aml_data);
|
||||
}
|
||||
|
||||
constexpr bool operator==(const NameSeg& other) const
|
||||
{
|
||||
return u32 == other.u32;
|
||||
}
|
||||
|
||||
void debug_print() const
|
||||
{
|
||||
size_t len = 4;
|
||||
while (len > 0 && chars[len - 1] == '_')
|
||||
len--;
|
||||
for (size_t i = 0; i < len; i++)
|
||||
AML_DEBUG_PUTC(chars[i]);
|
||||
}
|
||||
};
|
||||
|
||||
struct NameString
|
||||
{
|
||||
BAN::String prefix;
|
||||
BAN::Vector<NameSeg> path;
|
||||
|
||||
NameString() = default;
|
||||
NameString(BAN::StringView str)
|
||||
{
|
||||
if (!str.empty() && str.front() == '\\')
|
||||
{
|
||||
MUST(prefix.push_back('\\'));
|
||||
str = str.substring(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
while (str.size() > 0 && str.front() == '^')
|
||||
{
|
||||
MUST(prefix.push_back('^'));
|
||||
str = str.substring(1);
|
||||
}
|
||||
}
|
||||
|
||||
while (!str.empty())
|
||||
{
|
||||
ASSERT(str[0] != '.');
|
||||
size_t len = 1;
|
||||
while (len < str.size() && str[len] != '.')
|
||||
len++;
|
||||
ASSERT(len <= 4);
|
||||
|
||||
MUST(path.push_back(NameSeg(str.substring(0, len))));
|
||||
str = str.substring(len);
|
||||
|
||||
if (!str.empty())
|
||||
{
|
||||
ASSERT(str[0] == '.');
|
||||
str = str.substring(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool can_parse(BAN::ConstByteSpan aml_data)
|
||||
{
|
||||
if (aml_data.size() == 0)
|
||||
return false;
|
||||
switch (static_cast<AML::Byte>(aml_data[0]))
|
||||
{
|
||||
case AML::Byte::RootChar:
|
||||
case AML::Byte::ParentPrefixChar:
|
||||
case AML::Byte::NullName:
|
||||
case AML::Byte::DualNamePrefix:
|
||||
case AML::Byte::MultiNamePrefix:
|
||||
return true;
|
||||
default:
|
||||
return is_lead_name_char(aml_data[0]);
|
||||
}
|
||||
}
|
||||
|
||||
static BAN::Optional<NameString> parse(BAN::ConstByteSpan& aml_data)
|
||||
{
|
||||
if (aml_data.size() == 0)
|
||||
return {};
|
||||
|
||||
NameString result;
|
||||
|
||||
if (static_cast<AML::Byte>(aml_data[0]) == AML::Byte::RootChar)
|
||||
{
|
||||
MUST(result.prefix.push_back('\\'));
|
||||
aml_data = aml_data.slice(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
while (aml_data.size() > 0 && static_cast<AML::Byte>(aml_data[0]) == AML::Byte::ParentPrefixChar)
|
||||
{
|
||||
MUST(result.prefix.push_back(aml_data[0]));
|
||||
aml_data = aml_data.slice(1);
|
||||
}
|
||||
}
|
||||
|
||||
if (aml_data.size() == 0)
|
||||
return {};
|
||||
|
||||
size_t name_count = 1;
|
||||
switch (static_cast<AML::Byte>(aml_data[0]))
|
||||
{
|
||||
case AML::Byte::NullName:
|
||||
name_count = 0;
|
||||
aml_data = aml_data.slice(1);
|
||||
break;
|
||||
case AML::Byte::DualNamePrefix:
|
||||
name_count = 2;
|
||||
aml_data = aml_data.slice(1);
|
||||
break;
|
||||
case AML::Byte::MultiNamePrefix:
|
||||
if (aml_data.size() < 2)
|
||||
return {};
|
||||
name_count = aml_data[1];
|
||||
aml_data = aml_data.slice(2);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < name_count; i++)
|
||||
{
|
||||
auto name_seg = NameSeg::parse(aml_data);
|
||||
if (!name_seg.has_value())
|
||||
return {};
|
||||
MUST(result.path.push_back(name_seg.release_value()));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void debug_print() const
|
||||
{
|
||||
for (size_t i = 0; i < prefix.size(); i++)
|
||||
AML_DEBUG_PUTC(prefix[i]);
|
||||
if (!path.empty())
|
||||
path.front().debug_print();
|
||||
for (size_t i = 1; i < path.size(); i++)
|
||||
{
|
||||
AML_DEBUG_PUTC('.');
|
||||
path[i].debug_print();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
namespace BAN
|
||||
{
|
||||
|
||||
template<>
|
||||
struct hash<Kernel::ACPI::AML::NameSeg>
|
||||
{
|
||||
constexpr hash_t operator()(Kernel::ACPI::AML::NameSeg name) const
|
||||
{
|
||||
return hash<uint32_t>()(name.u32);
|
||||
}
|
||||
};
|
||||
|
||||
namespace Formatter
|
||||
{
|
||||
template<typename F>
|
||||
void print_argument(F putc, const Kernel::ACPI::AML::NameSeg& name_seg, const ValueFormat&)
|
||||
{
|
||||
size_t len = 4;
|
||||
while (len > 0 && name_seg.chars[len - 1] == '_')
|
||||
len--;
|
||||
for (size_t i = 0; i < len; i++)
|
||||
putc(name_seg.chars[i]);
|
||||
}
|
||||
|
||||
template<typename F>
|
||||
void print_argument(F putc, const Kernel::ACPI::AML::NameString& name_string, const ValueFormat&)
|
||||
{
|
||||
print_argument(putc, name_string.prefix, {});
|
||||
if (!name_string.path.empty())
|
||||
print_argument(putc, name_string.path.front(), {});
|
||||
for (size_t i = 1; i < name_string.path.size(); i++)
|
||||
{
|
||||
putc('.');
|
||||
print_argument(putc, name_string.path[i], {});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,66 +1,74 @@
|
||||
#pragma once
|
||||
|
||||
#include <BAN/Bitcast.h>
|
||||
#include <BAN/ByteSpan.h>
|
||||
#include <BAN/Function.h>
|
||||
#include <BAN/HashMap.h>
|
||||
#include <kernel/ACPI/AML/Scope.h>
|
||||
#include <kernel/ACPI/Headers.h>
|
||||
#include <kernel/Lock/Mutex.h>
|
||||
#include <BAN/HashSet.h>
|
||||
#include <BAN/Iteration.h>
|
||||
|
||||
#include <kernel/ACPI/AML/Node.h>
|
||||
|
||||
namespace Kernel::ACPI::AML
|
||||
{
|
||||
|
||||
struct Namespace final : public AML::Scope
|
||||
struct Namespace
|
||||
{
|
||||
static BAN::RefPtr<AML::Namespace> create_root_namespace();
|
||||
static BAN::RefPtr<AML::Namespace> root_namespace();
|
||||
static BAN::RefPtr<AML::Node> debug_node;
|
||||
BAN_NON_COPYABLE(Namespace);
|
||||
BAN_NON_MOVABLE(Namespace);
|
||||
public:
|
||||
Namespace() = default;
|
||||
~Namespace();
|
||||
|
||||
template<typename F>
|
||||
static void for_each_child(const AML::NameString& scope, const F& callback)
|
||||
static BAN::ErrorOr<void> prepare_root_namespace();
|
||||
static Namespace& root_namespace();
|
||||
|
||||
BAN::ErrorOr<void> post_load_initialize();
|
||||
|
||||
BAN::ErrorOr<void> parse(BAN::ConstByteSpan);
|
||||
|
||||
BAN::ErrorOr<Node> evaluate(BAN::StringView path) { return evaluate(Scope {}, path); }
|
||||
BAN::ErrorOr<Node> evaluate(const Scope& scope, BAN::StringView);
|
||||
|
||||
// returns empty scope if object already exited
|
||||
BAN::ErrorOr<Scope> add_named_object(ParseContext& context, const NameString& name_string, Node&& node);
|
||||
BAN::ErrorOr<Scope> add_alias(ParseContext& scope, const NameString& name_string, Reference* reference);
|
||||
|
||||
BAN::ErrorOr<void> remove_named_object(const Scope& absolute_path);
|
||||
|
||||
// node is nullptr if it is not found
|
||||
struct FindResult
|
||||
{
|
||||
auto canonical_path = root_namespace()->resolve_path(scope, {}, FindMode::ForceAbsolute);
|
||||
ASSERT(canonical_path.has_value());
|
||||
|
||||
for (auto& [path, child] : root_namespace()->m_objects)
|
||||
{
|
||||
if (path.size() < canonical_path->size() + 1)
|
||||
continue;
|
||||
if (canonical_path->size() != 1 && path[canonical_path->size()] != '.')
|
||||
continue;
|
||||
if (path.sv().substring(0, canonical_path->size()) != canonical_path->sv())
|
||||
continue;
|
||||
if (path.sv().substring(canonical_path->size() + 1).contains('.'))
|
||||
continue;
|
||||
callback(path, child);
|
||||
}
|
||||
}
|
||||
|
||||
Namespace(NameSeg name) : AML::Scope(Node::Type::Namespace, name) {}
|
||||
|
||||
BAN::RefPtr<AML::Node> convert(uint8_t) override { return {}; }
|
||||
|
||||
bool parse(const SDTHeader& header);
|
||||
|
||||
void debug_print(int indent) const override;
|
||||
|
||||
enum class FindMode
|
||||
{
|
||||
Normal,
|
||||
ForceAbsolute,
|
||||
Scope path;
|
||||
Reference* node { nullptr };
|
||||
};
|
||||
BAN::Optional<BAN::String> resolve_path(const AML::NameString& relative_base, const AML::NameString& relative_path, FindMode mode, bool check_existence = true) const;
|
||||
BAN::ErrorOr<FindResult> find_named_object(const Scope& scope, const NameString& name_string, bool force_absolute = false);
|
||||
|
||||
// Find an object in the namespace. Returns nullptr if the object is not found.
|
||||
BAN::RefPtr<NamedObject> find_object(const AML::NameString& relative_base, const AML::NameString& relative_path, FindMode mode);
|
||||
BAN::ErrorOr<Scope> find_reference_scope(const Reference* reference);
|
||||
|
||||
// Add an object to the namespace. Returns false if the parent object could not be added.
|
||||
bool add_named_object(ParseContext&, const AML::NameString& object_path, BAN::RefPtr<NamedObject> object);
|
||||
BAN::ErrorOr<void> for_each_child(const Scope&, const BAN::Function<BAN::Iteration(BAN::StringView, Reference*)>&);
|
||||
BAN::ErrorOr<void> for_each_child(const Scope&, const BAN::Function<BAN::Iteration(const Scope&, Reference*)>&);
|
||||
|
||||
// Remove an object from the namespace. Returns false if the object could not be removed.
|
||||
bool remove_named_object(const AML::NameString& absolute_path);
|
||||
BAN::ErrorOr<BAN::Vector<Scope>> find_device_with_eisa_id(BAN::StringView eisa_id);
|
||||
BAN::ErrorOr<BAN::Vector<Scope>> find_device_with_eisa_id(BAN::Span<BAN::StringView> eisa_ids);
|
||||
|
||||
private:
|
||||
BAN::HashMap<BAN::String, BAN::RefPtr<NamedObject>> m_objects;
|
||||
mutable Mutex m_object_mutex;
|
||||
BAN::ErrorOr<Scope> resolve_path(const Scope& scope, const NameString& name_string);
|
||||
|
||||
BAN::ErrorOr<void> initialize_scope(const Scope& scope);
|
||||
|
||||
BAN::ErrorOr<void> opregion_call_reg(const Scope& scope, const Node& opregion);
|
||||
|
||||
BAN::ErrorOr<uint64_t> evaluate_sta(const Scope& scope);
|
||||
BAN::ErrorOr<void> evaluate_ini(const Scope& scope);
|
||||
|
||||
BAN::ErrorOr<void> initialize_op_regions();
|
||||
|
||||
private:
|
||||
bool m_has_initialized_namespace { false };
|
||||
BAN::HashMap<Scope, Reference*> m_named_objects;
|
||||
BAN::HashMap<Scope, uint32_t> m_called_reg_bitmaps;
|
||||
BAN::HashSet<Scope> m_aliases;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -1,115 +1,449 @@
|
||||
#pragma once
|
||||
|
||||
#include <BAN/Array.h>
|
||||
#include <BAN/ByteSpan.h>
|
||||
#include <BAN/LinkedList.h>
|
||||
#include <BAN/NoCopyMove.h>
|
||||
#include <BAN/Optional.h>
|
||||
#include <BAN/RefPtr.h>
|
||||
#include <BAN/StringView.h>
|
||||
#include <BAN/Vector.h>
|
||||
#include <kernel/ACPI/AML/Utils.h>
|
||||
|
||||
#include <kernel/ACPI/AML/Scope.h>
|
||||
#include <kernel/ACPI/Headers.h>
|
||||
#include <kernel/Lock/Mutex.h>
|
||||
|
||||
#define AML_DUMP_FUNCTION_CALLS 0
|
||||
#define AML_ENABLE_DEBUG 1
|
||||
|
||||
namespace Kernel::ACPI::AML
|
||||
{
|
||||
|
||||
struct Buffer;
|
||||
struct Integer;
|
||||
struct String;
|
||||
|
||||
struct Node : public BAN::RefCounted<Node>
|
||||
struct NameString
|
||||
{
|
||||
static uint64_t total_node_count;
|
||||
BAN_NON_COPYABLE(NameString);
|
||||
public:
|
||||
NameString() = default;
|
||||
NameString(NameString&& other)
|
||||
: base(other.base)
|
||||
, parts(BAN::move(other.parts))
|
||||
{}
|
||||
NameString& operator=(NameString&& other)
|
||||
{
|
||||
base = other.base;
|
||||
parts = BAN::move(other.parts);
|
||||
return *this;
|
||||
}
|
||||
|
||||
static BAN::ErrorOr<NameString> from_string(BAN::StringView name);
|
||||
|
||||
BAN::ErrorOr<NameString> copy() const
|
||||
{
|
||||
NameString result;
|
||||
result.base = this->base;
|
||||
|
||||
TRY(result.parts.resize(parts.size()));
|
||||
for (size_t i = 0; i < parts.size(); i++)
|
||||
result.parts[i] = parts[i];
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static constexpr uint32_t base_root = -1;
|
||||
uint32_t base { 0 };
|
||||
BAN::Vector<uint32_t> parts;
|
||||
};
|
||||
|
||||
template<typename T1, typename T2>
|
||||
struct Pair
|
||||
{
|
||||
T1 elem1;
|
||||
T2 elem2;
|
||||
};
|
||||
|
||||
struct Node;
|
||||
struct ParseContext;
|
||||
struct Reference;
|
||||
|
||||
struct Mutex
|
||||
{
|
||||
Kernel::Mutex mutex;
|
||||
uint8_t sync_level;
|
||||
bool global_lock;
|
||||
uint32_t ref_count;
|
||||
};
|
||||
|
||||
struct Buffer
|
||||
{
|
||||
BAN::StringView as_sv() const
|
||||
{
|
||||
return BAN::StringView(reinterpret_cast<const char*>(bytes), size);
|
||||
}
|
||||
|
||||
uint64_t size;
|
||||
uint32_t ref_count;
|
||||
uint8_t bytes[];
|
||||
};
|
||||
|
||||
struct OpRegion
|
||||
{
|
||||
GAS::AddressSpaceID address_space;
|
||||
uint64_t offset;
|
||||
uint64_t length;
|
||||
alignas(Scope) uint8_t scope_storage[sizeof(Scope)];
|
||||
Scope& scope() { return *reinterpret_cast<Scope*>(scope_storage); }
|
||||
const Scope& scope() const { return *reinterpret_cast<const Scope*>(scope_storage); }
|
||||
};
|
||||
|
||||
struct FieldUnit
|
||||
{
|
||||
enum class Type {
|
||||
Field,
|
||||
IndexField,
|
||||
BankField,
|
||||
};
|
||||
uint64_t offset;
|
||||
uint64_t length;
|
||||
uint8_t flags;
|
||||
Type type;
|
||||
|
||||
union {
|
||||
struct {
|
||||
OpRegion opregion;
|
||||
} field;
|
||||
struct {
|
||||
Reference* index;
|
||||
Reference* data;
|
||||
} index_field;
|
||||
struct {
|
||||
OpRegion opregion;
|
||||
Reference* bank_selector;
|
||||
uint64_t bank_value;
|
||||
} bank_field;
|
||||
} as;
|
||||
};
|
||||
|
||||
struct Package
|
||||
{
|
||||
struct Element
|
||||
{
|
||||
struct Location {
|
||||
NameString name;
|
||||
Scope scope;
|
||||
};
|
||||
|
||||
bool resolved { true };
|
||||
union {
|
||||
Node* node { nullptr };
|
||||
Location* location;
|
||||
} value;
|
||||
};
|
||||
|
||||
uint64_t num_elements;
|
||||
uint32_t ref_count;
|
||||
Element elements[];
|
||||
};
|
||||
|
||||
struct Node
|
||||
{
|
||||
BAN_NON_COPYABLE(Node);
|
||||
public:
|
||||
Node() = default;
|
||||
~Node() { clear(); }
|
||||
|
||||
Node(Node&& other) { *this = BAN::move(other); }
|
||||
Node& operator=(Node&&);
|
||||
|
||||
static BAN::ErrorOr<Node> create_string(BAN::StringView string)
|
||||
{
|
||||
const auto* u8_data = reinterpret_cast<const uint8_t*>(string.data());
|
||||
auto result = TRY(create_buffer({ u8_data, string.size() }));
|
||||
result.type = Node::Type::String;
|
||||
return result;
|
||||
}
|
||||
|
||||
static BAN::ErrorOr<Node> create_buffer(BAN::ConstByteSpan buffer)
|
||||
{
|
||||
Node node;
|
||||
node.type = Node::Type::Buffer;
|
||||
node.as.str_buf = static_cast<Buffer*>(kmalloc(sizeof(Buffer) + buffer.size()));
|
||||
if (node.as.str_buf == nullptr)
|
||||
return BAN::Error::from_errno(ENOMEM);
|
||||
node.as.str_buf->ref_count = 1;
|
||||
node.as.str_buf->size = buffer.size();
|
||||
memcpy(node.as.str_buf->bytes, buffer.data(), buffer.size());
|
||||
return node;
|
||||
}
|
||||
|
||||
enum class Type
|
||||
{
|
||||
Uninitialized,
|
||||
Debug,
|
||||
Integer,
|
||||
String,
|
||||
Buffer,
|
||||
Package,
|
||||
BufferField,
|
||||
OpRegion,
|
||||
FieldUnit,
|
||||
Event,
|
||||
Device,
|
||||
Processor,
|
||||
PowerResource,
|
||||
ThermalZone,
|
||||
Method,
|
||||
Mutex,
|
||||
// FIXME: Index should not be its own type
|
||||
// parsing index should return references
|
||||
Index,
|
||||
Reference,
|
||||
PredefinedScope,
|
||||
Count
|
||||
} type { Type::Uninitialized };
|
||||
|
||||
inline bool is_scope() const
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case Type::Device:
|
||||
case Type::Processor:
|
||||
case Type::PowerResource:
|
||||
case Type::ThermalZone:
|
||||
case Type::PredefinedScope:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
union
|
||||
{
|
||||
struct {
|
||||
uint64_t value;
|
||||
} integer;
|
||||
Package* package;
|
||||
Buffer* str_buf;
|
||||
struct {
|
||||
Buffer* buffer;
|
||||
uint64_t bit_offset;
|
||||
uint64_t bit_count;
|
||||
} buffer_field;
|
||||
OpRegion opregion;
|
||||
FieldUnit field_unit;
|
||||
struct {
|
||||
uint32_t signal_count;
|
||||
} event;
|
||||
struct {
|
||||
uint8_t storage[sizeof(Kernel::Mutex)];
|
||||
const uint8_t* start;
|
||||
size_t length;
|
||||
uint8_t arg_count;
|
||||
BAN::ErrorOr<Node> (*override_func)(const BAN::Array<Reference*, 7>&);
|
||||
bool serialized;
|
||||
Mutex* mutex;
|
||||
} method;
|
||||
Mutex* mutex;
|
||||
struct {
|
||||
Node::Type type;
|
||||
union {
|
||||
Buffer* str_buf;
|
||||
Package* package;
|
||||
} as;
|
||||
uint64_t index;
|
||||
} index;
|
||||
Reference* reference;
|
||||
} as;
|
||||
|
||||
BAN::ErrorOr<Node> copy() const;
|
||||
|
||||
void clear();
|
||||
};
|
||||
|
||||
struct Reference
|
||||
{
|
||||
Node node {};
|
||||
uint32_t ref_count { 1 };
|
||||
};
|
||||
|
||||
struct ParseContext
|
||||
{
|
||||
Scope scope;
|
||||
BAN::ConstByteSpan aml_data;
|
||||
|
||||
uint32_t call_depth { 0 };
|
||||
BAN::Array<Reference*, 8> locals;
|
||||
BAN::Array<Reference*, 7> args;
|
||||
|
||||
BAN::LinkedList<Scope> created_nodes;
|
||||
|
||||
~ParseContext();
|
||||
BAN::ErrorOr<void> allocate_locals();
|
||||
};
|
||||
|
||||
enum class ExecutionFlow
|
||||
{
|
||||
Normal,
|
||||
Break,
|
||||
Continue,
|
||||
Return,
|
||||
};
|
||||
using ExecutionFlowResult = Pair<ExecutionFlow, BAN::Optional<Node>>;
|
||||
|
||||
enum Conversion : uint8_t
|
||||
{
|
||||
ConvBuffer = 1 << 0,
|
||||
ConvBufferField = 1 << 1,
|
||||
ConvFieldUnit = 1 << 2,
|
||||
ConvInteger = 1 << 3,
|
||||
ConvString = 1 << 4,
|
||||
ConvInteger = 1,
|
||||
ConvBuffer = 2,
|
||||
ConvString = 4,
|
||||
};
|
||||
|
||||
enum class Type : uint8_t
|
||||
{
|
||||
None,
|
||||
BankFieldElement,
|
||||
Buffer,
|
||||
BufferField,
|
||||
Debug,
|
||||
Device,
|
||||
Event,
|
||||
FieldElement,
|
||||
IndexFieldElement,
|
||||
Integer,
|
||||
Method,
|
||||
Mutex,
|
||||
Name,
|
||||
Namespace,
|
||||
OpRegion,
|
||||
Package,
|
||||
PackageElement,
|
||||
PowerResource,
|
||||
Processor,
|
||||
Reference,
|
||||
Register,
|
||||
String,
|
||||
ThermalZone,
|
||||
};
|
||||
const Type type;
|
||||
BAN::ErrorOr<Node> parse_node(ParseContext& context, bool return_ref = false);
|
||||
BAN::ErrorOr<ExecutionFlowResult> parse_node_or_execution_flow(ParseContext& context);
|
||||
|
||||
Node(Type type) : type(type) { total_node_count++; }
|
||||
virtual ~Node() { total_node_count--; }
|
||||
BAN::ErrorOr<NameString> parse_name_string(BAN::ConstByteSpan& aml_data);
|
||||
BAN::ErrorOr<BAN::ConstByteSpan> parse_pkg(BAN::ConstByteSpan& aml_data);
|
||||
|
||||
virtual bool is_scope() const { return false; }
|
||||
BAN::ErrorOr<Node> convert_node(Node&& source, uint8_t conversion, uint64_t max_length);
|
||||
BAN::ErrorOr<Node> convert_node(Node&& source, const Node& target);
|
||||
|
||||
[[nodiscard]] virtual BAN::RefPtr<AML::Node> to_underlying() { return this; }
|
||||
[[nodiscard]] virtual BAN::RefPtr<AML::Node> convert(uint8_t mask) = 0;
|
||||
[[nodiscard]] virtual BAN::RefPtr<Node> copy() { return this; }
|
||||
[[nodiscard]] virtual BAN::RefPtr<AML::Node> store(BAN::RefPtr<AML::Node>) { AML_TODO("store, type {}", static_cast<uint8_t>(type)); return {}; }
|
||||
BAN::ErrorOr<Node> evaluate_node(const Scope& node_path, const Node& node);
|
||||
|
||||
virtual void debug_print(int indent) const = 0;
|
||||
};
|
||||
// If method has no return, it will return <integer 0>
|
||||
BAN::ErrorOr<Node> method_call(const Scope& scope, const Node& method, BAN::Array<Reference*, 7>&& args, uint32_t call_depth = 0);
|
||||
BAN::ErrorOr<Node> method_call(const Scope& scope, const Node& method,
|
||||
Node&& arg0 = {}, Node&& arg1 = {}, Node&& arg2 = {}, Node&& arg3 = {}, Node&& arg4 = {}, Node&& arg5 = {}, Node&& arg6 = {});
|
||||
|
||||
struct ParseContext;
|
||||
struct ParseResult
|
||||
{
|
||||
static ParseResult Failure;
|
||||
static ParseResult Success;
|
||||
BAN::ErrorOr<void> resolve_package_element(Package::Element& element, bool error_if_not_exists);
|
||||
|
||||
enum class Result
|
||||
{
|
||||
Success,
|
||||
Failure,
|
||||
Returned,
|
||||
Breaked,
|
||||
Continued,
|
||||
};
|
||||
|
||||
ParseResult(Result success)
|
||||
: m_result(success)
|
||||
{}
|
||||
ParseResult(Result success, BAN::RefPtr<Node> node)
|
||||
: m_result(success)
|
||||
, m_node(BAN::move(node))
|
||||
{}
|
||||
ParseResult(BAN::RefPtr<Node> node)
|
||||
: m_result(Result::Success)
|
||||
, m_node(BAN::move(node))
|
||||
{
|
||||
ASSERT(m_node);
|
||||
}
|
||||
|
||||
bool success() const { return m_result == Result::Success; }
|
||||
bool returned() const { return m_result == Result::Returned; }
|
||||
bool breaked() const { return m_result == Result::Breaked; }
|
||||
bool continued() const { return m_result == Result::Continued; }
|
||||
|
||||
BAN::RefPtr<Node> node()
|
||||
namespace BAN::Formatter
|
||||
{
|
||||
return m_node;
|
||||
|
||||
template<typename F>
|
||||
void print_argument(F putc, const Kernel::ACPI::AML::NameString& name_string, const ValueFormat&)
|
||||
{
|
||||
if (name_string.base == Kernel::ACPI::AML::NameString::base_root)
|
||||
putc('\\');
|
||||
else for (uint32_t i = 0; i < name_string.base; i++)
|
||||
putc('^');
|
||||
for (size_t i = 0; i < name_string.parts.size(); i++) {
|
||||
if (i != 0)
|
||||
putc('.');
|
||||
const char* name_seg = reinterpret_cast<const char*>(&name_string.parts[i]);
|
||||
putc(name_seg[0]); putc(name_seg[1]); putc(name_seg[2]); putc(name_seg[3]);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
Result m_result = Result::Failure;
|
||||
BAN::RefPtr<Node> m_node;
|
||||
};
|
||||
ParseResult parse_object(ParseContext& context);
|
||||
template<typename F>
|
||||
void print_argument(F putc, const Kernel::ACPI::AML::Buffer& buffer, const ValueFormat&)
|
||||
{
|
||||
static constexpr size_t max_elements { 16 };
|
||||
|
||||
print(putc, "<buffer '");
|
||||
if (buffer.size)
|
||||
print(putc, "{2H}", buffer.bytes[0]);
|
||||
for (size_t i = 1; i < buffer.size && i < max_elements; i++)
|
||||
print(putc, " {2H}", buffer.bytes[i]);
|
||||
if (buffer.size > max_elements)
|
||||
print(putc, "...");
|
||||
print(putc, "'>");
|
||||
}
|
||||
|
||||
template<typename F>
|
||||
void print_argument(F putc, const Kernel::ACPI::AML::Package& package, const ValueFormat&)
|
||||
{
|
||||
print(putc, "<package '{} elements'>", package.num_elements);
|
||||
}
|
||||
|
||||
template<typename F>
|
||||
void print_argument(F putc, const Kernel::ACPI::AML::Node& node, const ValueFormat&)
|
||||
{
|
||||
switch (node.type)
|
||||
{
|
||||
case Kernel::ACPI::AML::Node::Type::Uninitialized:
|
||||
print(putc, "<uninitialized>");
|
||||
break;
|
||||
case Kernel::ACPI::AML::Node::Type::Debug:
|
||||
print(putc, "<debug>");
|
||||
break;
|
||||
case Kernel::ACPI::AML::Node::Type::Integer:
|
||||
print(putc, "<integer 0x{H}>", node.as.integer.value);
|
||||
break;
|
||||
case Kernel::ACPI::AML::Node::Type::String:
|
||||
print(putc, "<string '{}'>", node.as.str_buf->as_sv());
|
||||
break;
|
||||
case Kernel::ACPI::AML::Node::Type::Package:
|
||||
print(putc, "{}", *node.as.package);
|
||||
break;
|
||||
case Kernel::ACPI::AML::Node::Type::Buffer:
|
||||
print(putc, "{}", *node.as.str_buf);
|
||||
break;
|
||||
case Kernel::ACPI::AML::Node::Type::BufferField:
|
||||
print(putc, "<buffer field '{} bytes, offset 0x{H}, bit count {}'>",
|
||||
node.as.buffer_field.buffer->size,
|
||||
node.as.buffer_field.bit_offset,
|
||||
node.as.buffer_field.bit_count
|
||||
);
|
||||
break;
|
||||
case Kernel::ACPI::AML::Node::Type::OpRegion:
|
||||
print(putc, "<opregion 'type {2H}, offset 0x{H}, length 0x{H}'>",
|
||||
static_cast<uint8_t>(node.as.opregion.address_space),
|
||||
node.as.opregion.offset,
|
||||
node.as.opregion.length
|
||||
);
|
||||
break;
|
||||
case Kernel::ACPI::AML::Node::Type::FieldUnit:
|
||||
print(putc, "<field unit ({}), 'offset 0x{H}, length 0x{H}'>",
|
||||
static_cast<uint8_t>(node.as.field_unit.type),
|
||||
node.as.field_unit.offset,
|
||||
node.as.field_unit.length
|
||||
);
|
||||
break;
|
||||
case Kernel::ACPI::AML::Node::Type::Event:
|
||||
print(putc, "<event '{} signals'>", node.as.event.signal_count);
|
||||
break;
|
||||
case Kernel::ACPI::AML::Node::Type::Device:
|
||||
print(putc, "<device>");
|
||||
break;
|
||||
case Kernel::ACPI::AML::Node::Type::Processor:
|
||||
print(putc, "<processor>");
|
||||
break;
|
||||
case Kernel::ACPI::AML::Node::Type::PowerResource:
|
||||
print(putc, "<power resouce>");
|
||||
break;
|
||||
case Kernel::ACPI::AML::Node::Type::ThermalZone:
|
||||
print(putc, "<thermal zone>");
|
||||
break;
|
||||
case Kernel::ACPI::AML::Node::Type::Method:
|
||||
print(putc, "<method '{} bytes'>", node.as.method.length);
|
||||
break;
|
||||
case Kernel::ACPI::AML::Node::Type::Mutex:
|
||||
print(putc, "<mutex>");
|
||||
break;
|
||||
case Kernel::ACPI::AML::Node::Type::Index:
|
||||
switch (node.as.index.type)
|
||||
{
|
||||
case Kernel::ACPI::AML::Node::Type::String:
|
||||
case Kernel::ACPI::AML::Node::Type::Buffer:
|
||||
print(putc, "<index {}, {}>", *node.as.index.as.str_buf, node.as.index.index);
|
||||
break;
|
||||
case Kernel::ACPI::AML::Node::Type::Package:
|
||||
print(putc, "<index {}, {}>", *node.as.index.as.package, node.as.index.index);
|
||||
break;
|
||||
default:
|
||||
print(putc, "<index {}??, {}>", (uint32_t)node.as.index.type, node.as.index.index);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case Kernel::ACPI::AML::Node::Type::Reference:
|
||||
print(putc, "<reference {}, {} refs>", node.as.reference->node, node.as.reference->ref_count);
|
||||
break;
|
||||
case Kernel::ACPI::AML::Node::Type::PredefinedScope:
|
||||
print(putc, "<scope>");
|
||||
break;
|
||||
case Kernel::ACPI::AML::Node::Type::Count:
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,67 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <kernel/ACPI/AML/Device.h>
|
||||
#include <kernel/ACPI/AML/ParseContext.h>
|
||||
#include <kernel/ACPI/AML/Processor.h>
|
||||
#include <kernel/ACPI/AML/ThermalZone.h>
|
||||
|
||||
namespace Kernel::ACPI::AML
|
||||
{
|
||||
|
||||
struct Notify
|
||||
{
|
||||
static ParseResult parse(ParseContext& context)
|
||||
{
|
||||
ASSERT(context.aml_data.size() >= 1);
|
||||
ASSERT(static_cast<Byte>(context.aml_data[0]) == Byte::NotifyOp);
|
||||
context.aml_data = context.aml_data.slice(1);
|
||||
|
||||
auto object_result = AML::parse_object(context);
|
||||
if (!object_result.success())
|
||||
return ParseResult::Failure;
|
||||
auto object = object_result.node();
|
||||
if (!object)
|
||||
{
|
||||
AML_ERROR("Notify object is null");
|
||||
return ParseResult::Failure;
|
||||
}
|
||||
|
||||
auto value_result = AML::parse_object(context);
|
||||
if (!value_result.success())
|
||||
return ParseResult::Failure;
|
||||
auto value_node = value_result.node() ? value_result.node()->convert(AML::Node::ConvInteger) : BAN::RefPtr<AML::Node>();
|
||||
if (!value_node)
|
||||
{
|
||||
AML_ERROR("Notify value is not an integer");
|
||||
return ParseResult::Failure;
|
||||
}
|
||||
const auto value = static_cast<AML::Integer*>(value_node.ptr())->value;
|
||||
|
||||
BAN::StringView object_type_sv;
|
||||
BAN::StringView object_name_sv;
|
||||
switch (object->type)
|
||||
{
|
||||
case AML::Node::Type::Device:
|
||||
object_type_sv = "Device"_sv;
|
||||
object_name_sv = static_cast<AML::Device*>(object.ptr())->name.sv();
|
||||
break;
|
||||
case AML::Node::Type::Processor:
|
||||
object_type_sv = "Processor"_sv;
|
||||
object_name_sv = static_cast<AML::Processor*>(object.ptr())->name.sv();
|
||||
break;
|
||||
case AML::Node::Type::ThermalZone:
|
||||
object_type_sv = "ThermalZone"_sv;
|
||||
object_name_sv = static_cast<AML::ThermalZone*>(object.ptr())->name.sv();
|
||||
break;
|
||||
default:
|
||||
object_type_sv = "Unknown"_sv;
|
||||
object_name_sv = "????"_sv;
|
||||
break;
|
||||
}
|
||||
|
||||
AML_TODO("Notify: {} {}: {2H}", object_type_sv, object_name_sv, value);
|
||||
return ParseResult::Success;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,107 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <kernel/ACPI/AML/Integer.h>
|
||||
#include <kernel/ACPI/AML/ParseContext.h>
|
||||
#include <kernel/ACPI/AML/Reference.h>
|
||||
|
||||
namespace Kernel::ACPI::AML
|
||||
{
|
||||
|
||||
struct ObjectType
|
||||
{
|
||||
static ParseResult parse(ParseContext& context)
|
||||
{
|
||||
ASSERT(context.aml_data.size() >= 1);
|
||||
ASSERT(static_cast<Byte>(context.aml_data[0]) == Byte::ObjectTypeOp);
|
||||
context.aml_data = context.aml_data.slice(1);
|
||||
|
||||
auto object_result = AML::parse_object(context);
|
||||
if (!object_result.success())
|
||||
return ParseResult::Failure;
|
||||
auto object = object_result.node()
|
||||
? object_result.node()->to_underlying()
|
||||
: BAN::RefPtr<AML::Node>();
|
||||
|
||||
if (object && object->type == AML::Node::Type::Reference)
|
||||
object = static_cast<AML::Reference*>(object.ptr())->node->to_underlying();
|
||||
|
||||
uint64_t value = 0;
|
||||
if (object)
|
||||
{
|
||||
switch (object->type)
|
||||
{
|
||||
case AML::Node::Type::None:
|
||||
case AML::Node::Type::Name:
|
||||
case AML::Node::Type::PackageElement:
|
||||
case AML::Node::Type::Reference:
|
||||
case AML::Node::Type::Register:
|
||||
ASSERT_NOT_REACHED();
|
||||
case AML::Node::Type::Namespace:
|
||||
value = 0;
|
||||
break;
|
||||
case AML::Node::Type::Integer:
|
||||
value = 1;
|
||||
break;
|
||||
case AML::Node::Type::String:
|
||||
value = 2;
|
||||
break;
|
||||
case AML::Node::Type::Buffer:
|
||||
value = 3;
|
||||
break;
|
||||
case AML::Node::Type::Package:
|
||||
value = 4;
|
||||
break;
|
||||
case AML::Node::Type::FieldElement:
|
||||
case AML::Node::Type::BankFieldElement:
|
||||
case AML::Node::Type::IndexFieldElement:
|
||||
value = 5;
|
||||
break;
|
||||
case AML::Node::Type::Device:
|
||||
value = 6;
|
||||
break;
|
||||
case AML::Node::Type::Event:
|
||||
value = 7;
|
||||
break;
|
||||
case AML::Node::Type::Method:
|
||||
value = 8;
|
||||
break;
|
||||
case AML::Node::Type::Mutex:
|
||||
value = 9;
|
||||
break;
|
||||
case AML::Node::Type::OpRegion:
|
||||
value = 10;
|
||||
break;
|
||||
case AML::Node::Type::PowerResource:
|
||||
value = 11;
|
||||
break;
|
||||
case AML::Node::Type::Processor:
|
||||
value = 12;
|
||||
break;
|
||||
case AML::Node::Type::ThermalZone:
|
||||
value = 13;
|
||||
break;
|
||||
case AML::Node::Type::BufferField:
|
||||
value = 14;
|
||||
break;
|
||||
case AML::Node::Type::Debug:
|
||||
value = 16;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#if AML_DEBUG_LEVEL >= 2
|
||||
if (!object)
|
||||
AML_DEBUG_PRINTLN("ObjectType { null }");
|
||||
else
|
||||
{
|
||||
AML_DEBUG_PRINTLN("ObjectType {");
|
||||
object->debug_print(1);
|
||||
AML_DEBUG_PRINTLN("");
|
||||
}
|
||||
#endif
|
||||
|
||||
return ParseResult(MUST(BAN::RefPtr<AML::Integer>::create(value)));
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
16
kernel/include/kernel/ACPI/AML/OpRegion.h
Normal file
16
kernel/include/kernel/ACPI/AML/OpRegion.h
Normal file
@@ -0,0 +1,16 @@
|
||||
#pragma once
|
||||
|
||||
#include <kernel/ACPI/AML/Node.h>
|
||||
|
||||
namespace Kernel::ACPI::AML
|
||||
{
|
||||
|
||||
BAN::ErrorOr<void> parse_opregion_op(ParseContext& context);
|
||||
BAN::ErrorOr<void> parse_field_op(ParseContext& context);
|
||||
BAN::ErrorOr<void> parse_index_field_op(ParseContext& context);
|
||||
BAN::ErrorOr<void> parse_bank_field_op(ParseContext& context);
|
||||
|
||||
BAN::ErrorOr<Node> convert_from_field_unit(const Node& node, uint8_t conversion, uint64_t max_length);
|
||||
BAN::ErrorOr<void> store_to_field_unit(const Node& source, const Node& target);
|
||||
|
||||
}
|
||||
@@ -1,168 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <kernel/ACPI/AML/Bytes.h>
|
||||
#include <kernel/ACPI/AML/Integer.h>
|
||||
#include <kernel/ACPI/AML/Node.h>
|
||||
#include <kernel/ACPI/AML/ParseContext.h>
|
||||
#include <kernel/ACPI/AML/Pkg.h>
|
||||
#include <kernel/ACPI/AML/Reference.h>
|
||||
|
||||
namespace Kernel::ACPI::AML
|
||||
{
|
||||
|
||||
struct PackageElement;
|
||||
|
||||
struct Package final : public AML::Node
|
||||
{
|
||||
BAN::Vector<BAN::RefPtr<PackageElement>> elements;
|
||||
AML::NameString scope;
|
||||
|
||||
Package(AML::NameString scope)
|
||||
: Node(Node::Type::Package)
|
||||
, elements(BAN::move(elements))
|
||||
, scope(scope)
|
||||
{}
|
||||
|
||||
BAN::RefPtr<AML::Node> convert(uint8_t) override { return {}; }
|
||||
|
||||
static ParseResult parse(AML::ParseContext& context);
|
||||
virtual void debug_print(int indent) const override;
|
||||
};
|
||||
|
||||
struct PackageElement final : public AML::Node
|
||||
{
|
||||
BAN::RefPtr<AML::Package> parent;
|
||||
BAN::RefPtr<AML::Node> element;
|
||||
AML::NameString unresolved_name;
|
||||
bool resolved = false;
|
||||
bool initialized = false;
|
||||
|
||||
PackageElement(BAN::RefPtr<AML::Package> parent, BAN::RefPtr<AML::Node> element)
|
||||
: Node(Node::Type::PackageElement)
|
||||
, parent(parent)
|
||||
, element(element)
|
||||
{
|
||||
ASSERT(element);
|
||||
resolved = true;
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
PackageElement(BAN::RefPtr<AML::Package> parent, AML::NameString unresolved_name)
|
||||
: Node(Node::Type::PackageElement)
|
||||
, parent(parent)
|
||||
, unresolved_name(unresolved_name)
|
||||
{
|
||||
resolved = false;
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
PackageElement(BAN::RefPtr<AML::Package> parent)
|
||||
: Node(Node::Type::PackageElement)
|
||||
, parent(parent)
|
||||
{
|
||||
resolved = false;
|
||||
initialized = false;
|
||||
}
|
||||
|
||||
bool resolve()
|
||||
{
|
||||
ASSERT(!resolved);
|
||||
|
||||
auto object = Namespace::root_namespace()->find_object(parent->scope, unresolved_name, Namespace::FindMode::Normal);
|
||||
if (!object)
|
||||
{
|
||||
AML_ERROR("Failed to resolve reference {} in package {}", unresolved_name, parent->scope);
|
||||
return false;
|
||||
}
|
||||
element = object;
|
||||
resolved = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
BAN::RefPtr<AML::Node> convert(uint8_t mask) override
|
||||
{
|
||||
if (!initialized)
|
||||
{
|
||||
AML_ERROR("Trying to convert uninitialized PackageElement");
|
||||
return {};
|
||||
}
|
||||
if (!resolved && !resolve())
|
||||
return {};
|
||||
return element->convert(mask);
|
||||
}
|
||||
|
||||
BAN::RefPtr<AML::Node> to_underlying() override
|
||||
{
|
||||
if (!initialized)
|
||||
{
|
||||
AML_ERROR("Trying to read uninitialized PackageElement");
|
||||
return {};
|
||||
}
|
||||
if (!resolved && !resolve())
|
||||
return {};
|
||||
return element;
|
||||
}
|
||||
|
||||
BAN::RefPtr<AML::Node> store(BAN::RefPtr<AML::Node> node) override
|
||||
{
|
||||
if (!initialized)
|
||||
{
|
||||
initialized = true;
|
||||
resolved = true;
|
||||
}
|
||||
if (!resolved && !resolve())
|
||||
return {};
|
||||
ASSERT(!element || element->type != AML::Node::Type::Reference);
|
||||
if (node->type == AML::Node::Type::Reference)
|
||||
element = static_cast<AML::Reference*>(node.ptr())->node;
|
||||
else
|
||||
element = node->copy();
|
||||
return node;
|
||||
}
|
||||
|
||||
static ParseResult parse(AML::ParseContext& context, BAN::RefPtr<AML::Package> package)
|
||||
{
|
||||
BAN::RefPtr<AML::PackageElement> element;
|
||||
if (context.aml_data[0] != 0x00 && AML::NameString::can_parse(context.aml_data))
|
||||
{
|
||||
auto name = AML::NameString::parse(context.aml_data);
|
||||
if (!name.has_value())
|
||||
return ParseResult::Failure;
|
||||
element = MUST(BAN::RefPtr<PackageElement>::create(package, name.value()));
|
||||
}
|
||||
else
|
||||
{
|
||||
auto element_result = AML::parse_object(context);
|
||||
if (!element_result.success())
|
||||
return ParseResult::Failure;
|
||||
element = MUST(BAN::RefPtr<PackageElement>::create(package, element_result.node()));
|
||||
}
|
||||
return ParseResult(element);
|
||||
}
|
||||
|
||||
virtual void debug_print(int indent) const override
|
||||
{
|
||||
AML_DEBUG_PRINT_INDENT(indent);
|
||||
AML_DEBUG_PRINTLN("PackageElement {");
|
||||
if (!initialized)
|
||||
{
|
||||
AML_DEBUG_PRINT_INDENT(indent + 1);
|
||||
AML_DEBUG_PRINT("Uninitialized");
|
||||
}
|
||||
else if (!resolved)
|
||||
{
|
||||
AML_DEBUG_PRINT_INDENT(indent + 1);
|
||||
AML_DEBUG_PRINT("Unresolved {}", unresolved_name);
|
||||
}
|
||||
else
|
||||
{
|
||||
element->debug_print(indent + 1);
|
||||
}
|
||||
AML_DEBUG_PRINTLN("");
|
||||
AML_DEBUG_PRINT_INDENT(indent);
|
||||
AML_DEBUG_PRINT("}");
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <BAN/Array.h>
|
||||
#include <BAN/ByteSpan.h>
|
||||
#include <BAN/LinkedList.h>
|
||||
#include <kernel/ACPI/AML/NamedObject.h>
|
||||
#include <kernel/ACPI/AML/Namespace.h>
|
||||
#include <kernel/ACPI/AML/Register.h>
|
||||
|
||||
namespace Kernel::ACPI::AML
|
||||
{
|
||||
|
||||
struct ParseContext
|
||||
{
|
||||
BAN::ConstByteSpan aml_data;
|
||||
AML::NameString scope;
|
||||
|
||||
// Used for cleaning up on method exit
|
||||
// NOTE: This uses linked list instead of vector because
|
||||
// we don't really need large contiguous memory
|
||||
BAN::LinkedList<AML::NameString> created_objects;
|
||||
|
||||
uint8_t sync_level() const { return !sync_stack.empty() ? sync_stack.back() : 0; }
|
||||
BAN::Vector<uint8_t> sync_stack;
|
||||
|
||||
BAN::Array<BAN::RefPtr<Register>, 7> method_args;
|
||||
BAN::Array<BAN::RefPtr<Register>, 8> method_locals;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <BAN/ByteSpan.h>
|
||||
#include <BAN/Optional.h>
|
||||
|
||||
namespace Kernel::ACPI::AML
|
||||
{
|
||||
|
||||
static BAN::Optional<uint32_t> parse_pkg_length(BAN::ConstByteSpan aml_data)
|
||||
{
|
||||
if (aml_data.size() < 1)
|
||||
return {};
|
||||
|
||||
uint8_t lead_byte = aml_data[0];
|
||||
if ((lead_byte & 0xC0) && (lead_byte & 0x30))
|
||||
return {};
|
||||
|
||||
uint32_t pkg_length = lead_byte & 0x3F;
|
||||
uint8_t byte_count = (lead_byte >> 6) + 1;
|
||||
|
||||
if (aml_data.size() < byte_count)
|
||||
return {};
|
||||
|
||||
for (uint8_t i = 1; i < byte_count; i++)
|
||||
pkg_length |= aml_data[i] << (i * 8 - 4);
|
||||
|
||||
return pkg_length;
|
||||
}
|
||||
|
||||
static void trim_pkg_length(BAN::ConstByteSpan& aml_data)
|
||||
{
|
||||
ASSERT(aml_data.size() >= 1);
|
||||
uint8_t byte_count = (aml_data[0] >> 6) + 1;
|
||||
aml_data = aml_data.slice(byte_count);
|
||||
}
|
||||
|
||||
static BAN::Optional<BAN::ConstByteSpan> parse_pkg(BAN::ConstByteSpan& aml_data)
|
||||
{
|
||||
auto pkg_length = parse_pkg_length(aml_data);
|
||||
if (!pkg_length.has_value())
|
||||
return {};
|
||||
|
||||
auto result = aml_data.slice(0, pkg_length.value());
|
||||
trim_pkg_length(result);
|
||||
|
||||
aml_data = aml_data.slice(pkg_length.value());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,70 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <BAN/Endianness.h>
|
||||
#include <kernel/ACPI/AML/Bytes.h>
|
||||
#include <kernel/ACPI/AML/ParseContext.h>
|
||||
#include <kernel/ACPI/AML/Pkg.h>
|
||||
#include <kernel/ACPI/AML/Scope.h>
|
||||
|
||||
namespace Kernel::ACPI::AML
|
||||
{
|
||||
|
||||
struct PowerResource final : public AML::Scope
|
||||
{
|
||||
uint8_t system_level;
|
||||
uint16_t resource_order;
|
||||
|
||||
PowerResource(NameSeg name, uint8_t system_level, uint16_t resource_order)
|
||||
: Scope(Node::Type::PowerResource, name)
|
||||
, system_level(system_level)
|
||||
, resource_order(resource_order)
|
||||
{}
|
||||
|
||||
BAN::RefPtr<AML::Node> convert(uint8_t) override { return {}; }
|
||||
|
||||
static ParseResult parse(ParseContext& context)
|
||||
{
|
||||
ASSERT(context.aml_data.size() >= 2);
|
||||
ASSERT(static_cast<AML::Byte>(context.aml_data[0]) == AML::Byte::ExtOpPrefix);
|
||||
ASSERT(static_cast<AML::ExtOp>(context.aml_data[1]) == AML::ExtOp::PowerResOp);
|
||||
context.aml_data = context.aml_data.slice(2);
|
||||
|
||||
auto opt_power_res_pkg = AML::parse_pkg(context.aml_data);
|
||||
if (!opt_power_res_pkg.has_value())
|
||||
return ParseResult::Failure;
|
||||
auto power_res_pkg = opt_power_res_pkg.value();
|
||||
|
||||
auto name = NameString::parse(power_res_pkg);
|
||||
if (!name.has_value())
|
||||
return ParseResult::Failure;
|
||||
|
||||
if (power_res_pkg.size() < 1)
|
||||
return ParseResult::Failure;
|
||||
uint8_t system_level = power_res_pkg[0];
|
||||
power_res_pkg = power_res_pkg.slice(1);
|
||||
|
||||
if (power_res_pkg.size() < 2)
|
||||
return ParseResult::Failure;
|
||||
uint16_t resource_order = BAN::little_endian_to_host<uint16_t>(*reinterpret_cast<const uint16_t*>(power_res_pkg.data()));
|
||||
power_res_pkg = power_res_pkg.slice(2);
|
||||
|
||||
auto power_res = MUST(BAN::RefPtr<PowerResource>::create(name->path.back(), system_level, resource_order));
|
||||
if (!Namespace::root_namespace()->add_named_object(context, name.value(), power_res))
|
||||
return ParseResult::Failure;
|
||||
|
||||
#if AML_DEBUG_LEVEL >= 2
|
||||
power_res->debug_print(0);
|
||||
AML_DEBUG_PRINTLN("");
|
||||
#endif
|
||||
|
||||
return power_res->enter_context_and_parse_term_list(context, name.value(), power_res_pkg);
|
||||
}
|
||||
|
||||
virtual void debug_print(int indent) const override
|
||||
{
|
||||
AML_DEBUG_PRINT_INDENT(indent);
|
||||
AML_DEBUG_PRINT("PowerResource {} (SystemLevel {}, ResourceOrder {})", name, system_level, resource_order);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,86 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <BAN/Endianness.h>
|
||||
#include <kernel/ACPI/AML/Bytes.h>
|
||||
#include <kernel/ACPI/AML/ParseContext.h>
|
||||
#include <kernel/ACPI/AML/Pkg.h>
|
||||
#include <kernel/ACPI/AML/Scope.h>
|
||||
|
||||
namespace Kernel::ACPI::AML
|
||||
{
|
||||
|
||||
struct Processor final : public AML::Scope
|
||||
{
|
||||
uint8_t id;
|
||||
uint32_t pblk_addr;
|
||||
uint8_t pblk_len;
|
||||
|
||||
Processor(NameSeg name, uint8_t id, uint32_t pblk_addr, uint8_t pblk_len)
|
||||
: Scope(Node::Type::Processor, name)
|
||||
, id(id)
|
||||
, pblk_addr(pblk_addr)
|
||||
, pblk_len(pblk_len)
|
||||
{}
|
||||
|
||||
BAN::RefPtr<AML::Node> convert(uint8_t) override { return {}; }
|
||||
|
||||
static ParseResult parse(ParseContext& context)
|
||||
{
|
||||
ASSERT(context.aml_data.size() >= 2);
|
||||
ASSERT(static_cast<AML::Byte>(context.aml_data[0]) == AML::Byte::ExtOpPrefix);
|
||||
ASSERT(static_cast<AML::ExtOp>(context.aml_data[1]) == AML::ExtOp::ProcessorOp);
|
||||
context.aml_data = context.aml_data.slice(2);
|
||||
|
||||
auto opt_processor_pkg = AML::parse_pkg(context.aml_data);
|
||||
if (!opt_processor_pkg.has_value())
|
||||
return ParseResult::Failure;
|
||||
auto processor_pkg = opt_processor_pkg.value();
|
||||
|
||||
auto name = NameString::parse(processor_pkg);
|
||||
if (!name.has_value())
|
||||
return ParseResult::Failure;
|
||||
|
||||
if (processor_pkg.size() < 1)
|
||||
return ParseResult::Failure;
|
||||
uint8_t id = processor_pkg[0];
|
||||
processor_pkg = processor_pkg.slice(1);
|
||||
|
||||
if (processor_pkg.size() < 4)
|
||||
return ParseResult::Failure;
|
||||
uint32_t pblk_addr = BAN::little_endian_to_host<uint32_t>(*reinterpret_cast<const uint32_t*>(processor_pkg.data()));
|
||||
processor_pkg = processor_pkg.slice(4);
|
||||
|
||||
if (processor_pkg.size() < 1)
|
||||
return ParseResult::Failure;
|
||||
uint8_t pblk_len = processor_pkg[0];
|
||||
processor_pkg = processor_pkg.slice(1);
|
||||
|
||||
auto processor = MUST(BAN::RefPtr<Processor>::create(name->path.back(), id, pblk_addr, pblk_len));
|
||||
if (!Namespace::root_namespace()->add_named_object(context, name.value(), processor))
|
||||
return ParseResult::Success;
|
||||
|
||||
#if AML_DEBUG_LEVEL >= 2
|
||||
processor->debug_print(0);
|
||||
AML_DEBUG_PRINTLN("");
|
||||
#endif
|
||||
|
||||
return processor->enter_context_and_parse_term_list(context, name.value(), processor_pkg);
|
||||
}
|
||||
|
||||
virtual void debug_print(int indent) const override
|
||||
{
|
||||
AML_DEBUG_PRINT_INDENT(indent);
|
||||
AML_DEBUG_PRINTLN("Processor {} (ID: {}, PBlkAddr: 0x{H}, PBlkLen: {}) {", name, id, pblk_addr, pblk_len);
|
||||
Namespace::root_namespace()->for_each_child(scope,
|
||||
[&](const auto&, const auto& child)
|
||||
{
|
||||
child->debug_print(indent + 1);
|
||||
AML_DEBUG_PRINTLN("");
|
||||
}
|
||||
);
|
||||
AML_DEBUG_PRINT_INDENT(indent);
|
||||
AML_DEBUG_PRINT("}");
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,186 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <kernel/ACPI/AML/Bytes.h>
|
||||
#include <kernel/ACPI/AML/Integer.h>
|
||||
#include <kernel/ACPI/AML/Node.h>
|
||||
#include <kernel/ACPI/AML/Names.h>
|
||||
#include <kernel/ACPI/AML/String.h>
|
||||
#include <kernel/ACPI/AML/ParseContext.h>
|
||||
|
||||
namespace Kernel::ACPI::AML
|
||||
{
|
||||
|
||||
struct Reference final : public AML::Node
|
||||
{
|
||||
BAN::RefPtr<AML::Node> node;
|
||||
|
||||
Reference(BAN::RefPtr<AML::Node> node)
|
||||
: Node(AML::Node::Type::Reference)
|
||||
, node(node)
|
||||
{
|
||||
ASSERT(node);
|
||||
}
|
||||
|
||||
BAN::RefPtr<AML::Node> convert(uint8_t mask) override
|
||||
{
|
||||
ASSERT(node);
|
||||
return node->convert(mask);
|
||||
}
|
||||
|
||||
BAN::RefPtr<AML::Node> store(BAN::RefPtr<AML::Node> value) override
|
||||
{
|
||||
ASSERT(node);
|
||||
return node->store(value);
|
||||
}
|
||||
|
||||
static ParseResult parse(ParseContext& context)
|
||||
{
|
||||
ASSERT(context.aml_data.size() >= 1);
|
||||
|
||||
bool conditional = false;
|
||||
switch (static_cast<AML::Byte>(context.aml_data[0]))
|
||||
{
|
||||
case AML::Byte::DerefOfOp:
|
||||
return parse_dereference(context);
|
||||
case AML::Byte::RefOfOp:
|
||||
context.aml_data = context.aml_data.slice(1);
|
||||
conditional = false;
|
||||
break;
|
||||
case AML::Byte::ExtOpPrefix:
|
||||
ASSERT(static_cast<AML::ExtOp>(context.aml_data[1]) == AML::ExtOp::CondRefOfOp);
|
||||
context.aml_data = context.aml_data.slice(2);
|
||||
conditional = true;
|
||||
break;
|
||||
default:
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
BAN::RefPtr<AML::Node> object;
|
||||
if (NameString::can_parse(context.aml_data))
|
||||
{
|
||||
auto name = NameString::parse(context.aml_data);
|
||||
if (!name.has_value())
|
||||
return ParseResult::Failure;
|
||||
object = Namespace::root_namespace()->find_object(context.scope, name.value(), Namespace::FindMode::Normal);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto parse_result = AML::parse_object(context);
|
||||
if (!parse_result.success())
|
||||
return ParseResult::Failure;
|
||||
object = parse_result.node();
|
||||
}
|
||||
|
||||
if (object && object->type == AML::Node::Type::Reference)
|
||||
object = static_cast<AML::Reference*>(object.ptr())->node;
|
||||
if (object && object->type == AML::Node::Type::Register)
|
||||
object = static_cast<AML::Register*>(object.ptr())->value;
|
||||
|
||||
if (!conditional)
|
||||
{
|
||||
if (!object)
|
||||
{
|
||||
AML_ERROR("RefOf failed to resolve reference");
|
||||
return ParseResult::Failure;
|
||||
}
|
||||
auto reference = MUST(BAN::RefPtr<Reference>::create(object));
|
||||
#if AML_DEBUG_LEVEL >= 2
|
||||
reference->debug_print(0);
|
||||
AML_DEBUG_PRINTLN("");
|
||||
#endif
|
||||
return ParseResult(reference);
|
||||
}
|
||||
|
||||
if (context.aml_data.size() < 1)
|
||||
{
|
||||
AML_ERROR("CondRefOf missing target");
|
||||
return ParseResult::Failure;
|
||||
}
|
||||
|
||||
BAN::RefPtr<AML::Node> target_node;
|
||||
if (context.aml_data[0] == 0x00)
|
||||
context.aml_data = context.aml_data.slice(1);
|
||||
else
|
||||
{
|
||||
auto target_result = AML::parse_object(context);
|
||||
if (!target_result.success())
|
||||
return ParseResult::Failure;
|
||||
target_node = target_result.node();
|
||||
if (!target_node)
|
||||
{
|
||||
AML_ERROR("CondRefOf failed to resolve target");
|
||||
return ParseResult::Failure;
|
||||
}
|
||||
}
|
||||
|
||||
#if AML_DEBUG_LEVEL >= 2
|
||||
AML_DEBUG_PRINT("CondRefOf ");
|
||||
if (object)
|
||||
object->debug_print(0);
|
||||
else
|
||||
AML_DEBUG_PRINT("null");
|
||||
AML_DEBUG_PRINTLN("");
|
||||
#endif
|
||||
|
||||
if (!object)
|
||||
return AML::ParseResult(Integer::Constants::Zero);
|
||||
|
||||
if (target_node && !target_node->store(object))
|
||||
{
|
||||
AML_ERROR("CondRefOf failed to store into target");
|
||||
return ParseResult::Failure;
|
||||
}
|
||||
|
||||
return AML::ParseResult(Integer::Constants::Ones);
|
||||
}
|
||||
|
||||
static ParseResult parse_dereference(ParseContext& context)
|
||||
{
|
||||
ASSERT(context.aml_data.size() >= 1);
|
||||
ASSERT(static_cast<Byte>(context.aml_data[0]) == Byte::DerefOfOp);
|
||||
context.aml_data = context.aml_data.slice(1);
|
||||
|
||||
if (context.aml_data.size() >= 1 && static_cast<AML::Byte>(context.aml_data[0]) == AML::Byte::StringPrefix)
|
||||
{
|
||||
auto string_result = AML::String::parse(context);
|
||||
if (!string_result.success())
|
||||
return ParseResult::Failure;
|
||||
ASSERT(string_result.node());
|
||||
auto string = static_cast<AML::String*>(string_result.node().ptr());
|
||||
AML_TODO("DerefOf String ({})", string->string);
|
||||
return ParseResult::Failure;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto parse_result = AML::parse_object(context);
|
||||
if (!parse_result.success())
|
||||
return ParseResult::Failure;
|
||||
auto node = parse_result.node();
|
||||
if (node && node->type == AML::Node::Type::Register)
|
||||
node = static_cast<AML::Register*>(node.ptr())->value;
|
||||
if (!node || node->type != AML::Node::Type::Reference)
|
||||
{
|
||||
AML_TODO("DerefOf source is not a Reference, but a {}", node ? static_cast<uint8_t>(node->type) : 999);
|
||||
return ParseResult::Failure;
|
||||
}
|
||||
#if AML_DEBUG_LEVEL >= 2
|
||||
AML_DEBUG_PRINT("DerefOf ");
|
||||
node->debug_print(0);
|
||||
AML_DEBUG_PRINTLN("");
|
||||
#endif
|
||||
return ParseResult(static_cast<Reference*>(node.ptr())->node);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void debug_print(int indent) const override
|
||||
{
|
||||
AML_DEBUG_PRINT_INDENT(indent);
|
||||
AML_DEBUG_PRINTLN("Reference {");
|
||||
node->debug_print(indent + 1);
|
||||
AML_DEBUG_PRINTLN("");
|
||||
AML_DEBUG_PRINT_INDENT(indent);
|
||||
AML_DEBUG_PRINT("}");
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,116 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <kernel/ACPI/AML/Integer.h>
|
||||
#include <kernel/ACPI/AML/NamedObject.h>
|
||||
#include <kernel/ACPI/AML/Namespace.h>
|
||||
#include <kernel/ACPI/AML/ParseContext.h>
|
||||
|
||||
namespace Kernel::ACPI::AML
|
||||
{
|
||||
|
||||
struct OpRegion final : public AML::NamedObject
|
||||
{
|
||||
using RegionSpace = GAS::AddressSpaceID;
|
||||
RegionSpace region_space;
|
||||
uint64_t region_offset;
|
||||
uint64_t region_length;
|
||||
|
||||
Kernel::Mutex mutex;
|
||||
|
||||
OpRegion(NameSeg name, RegionSpace region_space, uint64_t region_offset, uint64_t region_length)
|
||||
: NamedObject(Node::Type::OpRegion, name)
|
||||
, region_space(region_space)
|
||||
, region_offset(region_offset)
|
||||
, region_length(region_length)
|
||||
{}
|
||||
|
||||
BAN::RefPtr<AML::Node> convert(uint8_t) override { return {}; }
|
||||
|
||||
static ParseResult parse(AML::ParseContext& context)
|
||||
{
|
||||
ASSERT(context.aml_data.size() > 2);
|
||||
ASSERT(static_cast<Byte>(context.aml_data[0]) == Byte::ExtOpPrefix);
|
||||
ASSERT(static_cast<ExtOp>(context.aml_data[1]) == ExtOp::OpRegionOp);
|
||||
context.aml_data = context.aml_data.slice(2);
|
||||
|
||||
auto name = NameString::parse(context.aml_data);
|
||||
if (!name.has_value())
|
||||
return ParseResult::Failure;
|
||||
|
||||
if (context.aml_data.size() < 1)
|
||||
return ParseResult::Failure;
|
||||
auto region_space = static_cast<RegionSpace>(context.aml_data[0]);
|
||||
context.aml_data = context.aml_data.slice(1);
|
||||
|
||||
auto offset_result = AML::parse_object(context);
|
||||
if (!offset_result.success())
|
||||
return ParseResult::Failure;
|
||||
auto offset_node = offset_result.node()
|
||||
? offset_result.node()->convert(AML::Node::ConvInteger)
|
||||
: BAN::RefPtr<AML::Node>();
|
||||
if (!offset_node)
|
||||
{
|
||||
AML_ERROR("OpRegion offset must be an integer");
|
||||
return ParseResult::Failure;
|
||||
}
|
||||
|
||||
auto length_result = AML::parse_object(context);
|
||||
if (!length_result.success())
|
||||
return ParseResult::Failure;
|
||||
auto length_node = length_result.node()
|
||||
? length_result.node()->convert(AML::Node::ConvInteger)
|
||||
: BAN::RefPtr<AML::Node>();
|
||||
if (!length_node)
|
||||
{
|
||||
AML_ERROR("OpRegion length must be an integer");
|
||||
return ParseResult::Failure;
|
||||
}
|
||||
|
||||
const auto offset = static_cast<AML::Integer*>(offset_node.ptr())->value;
|
||||
const auto length = static_cast<AML::Integer*>(length_node.ptr())->value;
|
||||
|
||||
auto op_region = MUST(BAN::RefPtr<OpRegion>::create(
|
||||
name->path.back(),
|
||||
region_space,
|
||||
offset,
|
||||
length
|
||||
));
|
||||
|
||||
if (!Namespace::root_namespace()->add_named_object(context, name.value(), op_region))
|
||||
return ParseResult::Success;
|
||||
|
||||
#if AML_DEBUG_LEVEL >= 2
|
||||
op_region->debug_print(0);
|
||||
AML_DEBUG_PRINTLN("");
|
||||
#endif
|
||||
|
||||
return ParseResult::Success;
|
||||
}
|
||||
|
||||
virtual void debug_print(int indent) const override
|
||||
{
|
||||
BAN::StringView region_space_name;
|
||||
switch (region_space)
|
||||
{
|
||||
case RegionSpace::SystemMemory: region_space_name = "SystemMemory"_sv; break;
|
||||
case RegionSpace::SystemIO: region_space_name = "SystemIO"_sv; break;
|
||||
case RegionSpace::PCIConfig: region_space_name = "PCIConfig"_sv; break;
|
||||
case RegionSpace::EmbeddedController: region_space_name = "EmbeddedController"_sv; break;
|
||||
case RegionSpace::SMBus: region_space_name = "SMBus"_sv; break;
|
||||
case RegionSpace::SystemCMOS: region_space_name = "SystemCMOS"_sv; break;
|
||||
case RegionSpace::PCIBarTarget: region_space_name = "PCIBarTarget"_sv; break;
|
||||
case RegionSpace::IPMI: region_space_name = "IPMI"_sv; break;
|
||||
case RegionSpace::GeneralPurposeIO: region_space_name = "GeneralPurposeIO"_sv; break;
|
||||
case RegionSpace::GenericSerialBus: region_space_name = "GenericSerialBus"_sv; break;
|
||||
case RegionSpace::PlatformCommunicationChannel: region_space_name = "PlatformCommunicationChannel"_sv; break;
|
||||
default: region_space_name = "Unknown"_sv; break;
|
||||
}
|
||||
AML_DEBUG_PRINT_INDENT(indent);
|
||||
AML_DEBUG_PRINT("OperationRegion(");
|
||||
name.debug_print();
|
||||
AML_DEBUG_PRINT(", {}, 0x{H}, 0x{H})", region_space_name, region_offset, region_length);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <kernel/ACPI/AML/Node.h>
|
||||
|
||||
namespace Kernel::ACPI::AML
|
||||
{
|
||||
|
||||
struct Register final : public AML::Node
|
||||
{
|
||||
BAN::RefPtr<AML::Node> value;
|
||||
|
||||
Register();
|
||||
Register(BAN::RefPtr<AML::Node> node);
|
||||
|
||||
BAN::RefPtr<AML::Node> to_underlying() override { return value->to_underlying(); }
|
||||
|
||||
BAN::RefPtr<AML::Node> convert(uint8_t mask) override;
|
||||
BAN::RefPtr<AML::Node> store(BAN::RefPtr<AML::Node> source) override;
|
||||
|
||||
void debug_print(int indent) const override;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,27 +1,74 @@
|
||||
#pragma once
|
||||
|
||||
#include <kernel/ACPI/AML/NamedObject.h>
|
||||
#include <kernel/ACPI/AML/Names.h>
|
||||
#include <BAN/Hash.h>
|
||||
#include <BAN/NoCopyMove.h>
|
||||
#include <BAN/Vector.h>
|
||||
|
||||
namespace Kernel::ACPI::AML
|
||||
{
|
||||
|
||||
struct Scope : public AML::NamedObject
|
||||
struct Scope
|
||||
{
|
||||
AML::NameString scope;
|
||||
BAN_NON_COPYABLE(Scope);
|
||||
public:
|
||||
Scope() = default;
|
||||
Scope(Scope&& other) { *this = BAN::move(other); }
|
||||
Scope& operator=(Scope&& other) { parts = BAN::move(other.parts); return *this; }
|
||||
|
||||
Scope(Node::Type type, NameSeg name)
|
||||
: NamedObject(type, name)
|
||||
{}
|
||||
BAN::Vector<uint32_t> parts;
|
||||
|
||||
virtual bool is_scope() const override { return true; }
|
||||
BAN::ErrorOr<Scope> copy() const
|
||||
{
|
||||
Scope result;
|
||||
TRY(result.parts.reserve(parts.size()));
|
||||
for (uint32_t part : parts)
|
||||
TRY(result.parts.push_back(part));
|
||||
return result;
|
||||
}
|
||||
|
||||
static ParseResult parse(ParseContext& context);
|
||||
|
||||
protected:
|
||||
ParseResult enter_context_and_parse_term_list(ParseContext& outer_context, const AML::NameString& name, BAN::ConstByteSpan aml_data);
|
||||
bool operator==(const Scope& other) const
|
||||
{
|
||||
if (parts.size() != other.parts.size())
|
||||
return false;
|
||||
for (size_t i = 0; i < parts.size(); i++)
|
||||
if (parts[i] != other.parts[i])
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
bool initialize_scope(BAN::RefPtr<Scope> scope);
|
||||
}
|
||||
|
||||
namespace BAN
|
||||
{
|
||||
|
||||
template<>
|
||||
struct hash<Kernel::ACPI::AML::Scope>
|
||||
{
|
||||
hash_t operator()(const Kernel::ACPI::AML::Scope& scope) const
|
||||
{
|
||||
hash_t hash { 0 };
|
||||
for (uint32_t part : scope.parts)
|
||||
hash ^= u32_hash(part);
|
||||
return hash;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
namespace BAN::Formatter
|
||||
{
|
||||
|
||||
template<typename F>
|
||||
void print_argument(F putc, const Kernel::ACPI::AML::Scope& scope, const ValueFormat&)
|
||||
{
|
||||
putc('\\');
|
||||
for (size_t i = 0; i < scope.parts.size(); i++) {
|
||||
if (i != 0)
|
||||
putc('.');
|
||||
const char* name_seg = reinterpret_cast<const char*>(&scope.parts[i]);
|
||||
putc(name_seg[0]); putc(name_seg[1]); putc(name_seg[2]); putc(name_seg[3]);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,60 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
|
||||
#include <kernel/ACPI/AML/Buffer.h>
|
||||
#include <kernel/ACPI/AML/Names.h>
|
||||
#include <kernel/ACPI/AML/Package.h>
|
||||
#include <kernel/ACPI/AML/ParseContext.h>
|
||||
#include <kernel/ACPI/AML/Reference.h>
|
||||
|
||||
namespace Kernel::ACPI::AML
|
||||
{
|
||||
|
||||
struct SizeOf
|
||||
{
|
||||
static ParseResult parse(ParseContext& context)
|
||||
{
|
||||
ASSERT(context.aml_data.size() >= 1);
|
||||
ASSERT(static_cast<Byte>(context.aml_data[0]) == Byte::SizeOfOp);
|
||||
context.aml_data = context.aml_data.slice(1);
|
||||
|
||||
auto object_result = AML::parse_object(context);
|
||||
if (!object_result.success())
|
||||
return ParseResult::Failure;
|
||||
auto object_node = object_result.node();
|
||||
if (object_node)
|
||||
object_node = object_node->to_underlying();
|
||||
if (!object_node)
|
||||
{
|
||||
AML_ERROR("SizeOf object is null");
|
||||
return ParseResult::Failure;
|
||||
}
|
||||
if (object_node->type != AML::Node::Type::Package)
|
||||
object_node = object_node->convert(AML::Node::ConvBuffer | AML::Node::ConvString);
|
||||
if (!object_node)
|
||||
{
|
||||
AML_ERROR("SizeOf object is not Buffer, String or Package");
|
||||
return ParseResult::Failure;
|
||||
}
|
||||
|
||||
uint64_t size = 0;
|
||||
switch (object_node->type)
|
||||
{
|
||||
case AML::Node::Type::Buffer:
|
||||
size = static_cast<AML::Buffer*>(object_node.ptr())->buffer.size();
|
||||
break;
|
||||
case AML::Node::Type::String:
|
||||
size = static_cast<AML::String*>(object_node.ptr())->string.size();
|
||||
break;
|
||||
case AML::Node::Type::Package:
|
||||
size = static_cast<AML::Package*>(object_node.ptr())->elements.size();
|
||||
break;
|
||||
default:
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
return ParseResult(MUST(BAN::RefPtr<Integer>::create(size)));
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <kernel/ACPI/AML/Bytes.h>
|
||||
#include <kernel/ACPI/AML/ParseContext.h>
|
||||
#include <kernel/Timer/Timer.h>
|
||||
|
||||
namespace Kernel::ACPI::AML
|
||||
{
|
||||
|
||||
struct Sleep
|
||||
{
|
||||
static ParseResult parse(ParseContext& context)
|
||||
{
|
||||
ASSERT(context.aml_data.size() >= 2);
|
||||
ASSERT(static_cast<AML::Byte>(context.aml_data[0]) == AML::Byte::ExtOpPrefix);
|
||||
ASSERT(static_cast<AML::ExtOp>(context.aml_data[1]) == AML::ExtOp::SleepOp);
|
||||
context.aml_data = context.aml_data.slice(2);
|
||||
|
||||
auto sleep_time_result = AML::parse_object(context);
|
||||
if (!sleep_time_result.success())
|
||||
return ParseResult::Failure;
|
||||
auto sleep_time_node = sleep_time_result.node()
|
||||
? sleep_time_result.node()->convert(AML::Node::ConvInteger)
|
||||
: BAN::RefPtr<AML::Node>();
|
||||
if (!sleep_time_node)
|
||||
{
|
||||
AML_ERROR("Sleep time cannot be evaluated to an integer");
|
||||
return ParseResult::Failure;
|
||||
}
|
||||
|
||||
const auto sleep_time_value = static_cast<AML::Integer*>(sleep_time_node.ptr())->value;
|
||||
|
||||
#if AML_DEBUG_LEVEL >= 2
|
||||
AML_DEBUG_PRINTLN("Sleeping for {} ms", sleep_time_value);
|
||||
#endif
|
||||
|
||||
SystemTimer::get().sleep_ms(sleep_time_value);
|
||||
return ParseResult::Success;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <kernel/ACPI/AML/Bytes.h>
|
||||
#include <kernel/ACPI/AML/ParseContext.h>
|
||||
|
||||
namespace Kernel::ACPI::AML
|
||||
{
|
||||
|
||||
struct Store
|
||||
{
|
||||
static ParseResult parse(ParseContext& context)
|
||||
{
|
||||
ASSERT(context.aml_data.size() >= 1);
|
||||
ASSERT(static_cast<Byte>(context.aml_data[0]) == Byte::StoreOp);
|
||||
context.aml_data = context.aml_data.slice(1);
|
||||
|
||||
auto source_result = AML::parse_object(context);
|
||||
if (!source_result.success())
|
||||
return ParseResult::Failure;
|
||||
auto source = source_result.node();
|
||||
if (!source)
|
||||
{
|
||||
AML_ERROR("Store source is null");
|
||||
return ParseResult::Failure;
|
||||
}
|
||||
|
||||
auto destination_result = AML::parse_object(context);
|
||||
if (!destination_result.success())
|
||||
return ParseResult::Failure;
|
||||
auto destination = destination_result.node();
|
||||
if (!destination)
|
||||
{
|
||||
AML_ERROR("Store destination is null");
|
||||
return ParseResult::Failure;
|
||||
}
|
||||
|
||||
#if AML_DEBUG_LEVEL >= 2
|
||||
AML_DEBUG_PRINTLN("Storing {");
|
||||
source->debug_print(1);
|
||||
AML_DEBUG_PRINTLN("");
|
||||
AML_DEBUG_PRINTLN("} to {");
|
||||
destination->debug_print(1);
|
||||
AML_DEBUG_PRINTLN("");
|
||||
AML_DEBUG_PRINTLN("}");
|
||||
#endif
|
||||
|
||||
if (auto stored = destination->store(source))
|
||||
return ParseResult(stored);
|
||||
return ParseResult::Failure;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <kernel/ACPI/AML/Bytes.h>
|
||||
#include <kernel/ACPI/AML/Node.h>
|
||||
#include <kernel/ACPI/AML/ParseContext.h>
|
||||
|
||||
namespace Kernel::ACPI::AML
|
||||
{
|
||||
|
||||
struct String final : public AML::Node
|
||||
{
|
||||
BAN::Vector<uint8_t> string;
|
||||
|
||||
String() : Node(Node::Type::String) {}
|
||||
String(BAN::StringView string)
|
||||
: Node(Node::Type::String)
|
||||
{
|
||||
MUST(this->string.resize(string.size()));
|
||||
for (size_t i = 0; i < string.size(); i++)
|
||||
this->string[i] = string[i];
|
||||
}
|
||||
|
||||
BAN::Optional<bool> logical_compare(BAN::RefPtr<AML::Node> node, AML::Byte binaryop);
|
||||
|
||||
BAN::RefPtr<AML::Node> convert(uint8_t mask) override;
|
||||
|
||||
BAN::RefPtr<AML::Node> copy() override
|
||||
{
|
||||
auto new_string = MUST(BAN::RefPtr<AML::String>::create());
|
||||
MUST(new_string->string.resize(this->string.size()));
|
||||
for (size_t i = 0; i < this->string.size(); i++)
|
||||
new_string->string[i] = this->string[i];
|
||||
return new_string;
|
||||
}
|
||||
|
||||
BAN::RefPtr<AML::Node> store(BAN::RefPtr<AML::Node> node) override
|
||||
{
|
||||
ASSERT(node);
|
||||
auto conv_node = node->convert(AML::Node::ConvString);
|
||||
if (!conv_node)
|
||||
{
|
||||
AML_ERROR("Could not convert to String");
|
||||
return {};
|
||||
}
|
||||
auto* string_node = static_cast<AML::String*>(conv_node.ptr());
|
||||
MUST(string.resize(string_node->string.size()));
|
||||
for (size_t i = 0; i < string.size(); i++)
|
||||
string[i] = string_node->string[i];
|
||||
return string_node->copy();
|
||||
}
|
||||
|
||||
BAN::StringView string_view() const
|
||||
{
|
||||
return BAN::StringView(reinterpret_cast<const char*>(string.data()), string.size());
|
||||
}
|
||||
|
||||
static ParseResult parse(ParseContext& context);
|
||||
|
||||
virtual void debug_print(int indent) const override
|
||||
{
|
||||
AML_DEBUG_PRINT_INDENT(indent);
|
||||
AML_DEBUG_PRINT("String \"{}\"", string_view());
|
||||
}
|
||||
|
||||
private:
|
||||
BAN::RefPtr<AML::Buffer> as_buffer();
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <BAN/Endianness.h>
|
||||
#include <kernel/ACPI/AML/Bytes.h>
|
||||
#include <kernel/ACPI/AML/ParseContext.h>
|
||||
#include <kernel/ACPI/AML/Pkg.h>
|
||||
#include <kernel/ACPI/AML/Scope.h>
|
||||
|
||||
namespace Kernel::ACPI::AML
|
||||
{
|
||||
|
||||
struct ThermalZone final : public AML::Scope
|
||||
{
|
||||
ThermalZone(NameSeg name)
|
||||
: Scope(Node::Type::ThermalZone, name)
|
||||
{}
|
||||
|
||||
BAN::RefPtr<AML::Node> convert(uint8_t) override { return {}; }
|
||||
|
||||
static ParseResult parse(ParseContext& context)
|
||||
{
|
||||
ASSERT(context.aml_data.size() >= 2);
|
||||
ASSERT(static_cast<AML::Byte>(context.aml_data[0]) == AML::Byte::ExtOpPrefix);
|
||||
ASSERT(static_cast<AML::ExtOp>(context.aml_data[1]) == AML::ExtOp::ThermalZoneOp);
|
||||
context.aml_data = context.aml_data.slice(2);
|
||||
|
||||
auto opt_thermal_zone_pkg = AML::parse_pkg(context.aml_data);
|
||||
if (!opt_thermal_zone_pkg.has_value())
|
||||
return ParseResult::Failure;
|
||||
auto thermal_zone_pkg = opt_thermal_zone_pkg.value();
|
||||
|
||||
auto name = NameString::parse(thermal_zone_pkg);
|
||||
if (!name.has_value())
|
||||
return ParseResult::Failure;
|
||||
|
||||
auto thermal_zone = MUST(BAN::RefPtr<ThermalZone>::create(name->path.back()));
|
||||
if (!Namespace::root_namespace()->add_named_object(context, name.value(), thermal_zone))
|
||||
return ParseResult::Success;
|
||||
|
||||
#if AML_DEBUG_LEVEL >= 2
|
||||
thermal_zone->debug_print(0);
|
||||
AML_DEBUG_PRINTLN("");
|
||||
#endif
|
||||
|
||||
return thermal_zone->enter_context_and_parse_term_list(context, name.value(), thermal_zone_pkg);
|
||||
}
|
||||
|
||||
virtual void debug_print(int indent) const override
|
||||
{
|
||||
AML_DEBUG_PRINT_INDENT(indent);
|
||||
AML_DEBUG_PRINT("ThermalZone {} {", name);
|
||||
Namespace::root_namespace()->for_each_child(scope,
|
||||
[&](const auto&, const auto& child)
|
||||
{
|
||||
child->debug_print(indent + 1);
|
||||
AML_DEBUG_PRINTLN("");
|
||||
}
|
||||
);
|
||||
AML_DEBUG_PRINT_INDENT(indent);
|
||||
AML_DEBUG_PRINT("}");
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <BAN/Formatter.h>
|
||||
#include <kernel/Debug.h>
|
||||
|
||||
// AML_DEBUG_LEVEL:
|
||||
// 0: No debug output
|
||||
// 1: Dump AML after parsing
|
||||
// 2: Dump AML while parsing
|
||||
#define AML_DEBUG_LEVEL 0
|
||||
|
||||
#define AML_TODO(...) \
|
||||
do { \
|
||||
BAN::Formatter::print(Debug::putchar, "\e[33mTODO: "); \
|
||||
BAN::Formatter::print(Debug::putchar, __VA_ARGS__); \
|
||||
BAN::Formatter::println(Debug::putchar, "\e[m"); \
|
||||
} while (0)
|
||||
|
||||
#define AML_ERROR(...) \
|
||||
do { \
|
||||
BAN::Formatter::print(Debug::putchar, "\e[31mERROR: "); \
|
||||
BAN::Formatter::print(Debug::putchar, __VA_ARGS__); \
|
||||
BAN::Formatter::println(Debug::putchar, "\e[m"); \
|
||||
} while (0)
|
||||
|
||||
#define AML_PRINT(...) BAN::Formatter::println(Debug::putchar, __VA_ARGS__)
|
||||
|
||||
#define AML_DEBUG_PRINT_INDENT(indent) \
|
||||
do { \
|
||||
for (int i = 0; i < (indent) * 2; i++) \
|
||||
AML_DEBUG_PUTC(' '); \
|
||||
} while (0)
|
||||
|
||||
#define AML_DEBUG_PUTC(c) Debug::putchar(c)
|
||||
#define AML_DEBUG_PRINT(...) BAN::Formatter::print(Debug::putchar, __VA_ARGS__)
|
||||
#define AML_DEBUG_PRINTLN(...) BAN::Formatter::println(Debug::putchar, __VA_ARGS__)
|
||||
@@ -1,77 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <kernel/ACPI/AML/Node.h>
|
||||
#include <kernel/ACPI/AML/ParseContext.h>
|
||||
#include <kernel/ACPI/AML/Pkg.h>
|
||||
|
||||
namespace Kernel::ACPI::AML
|
||||
{
|
||||
|
||||
struct While
|
||||
{
|
||||
static ParseResult parse(ParseContext& context)
|
||||
{
|
||||
ASSERT(context.aml_data.size() >= 1);
|
||||
|
||||
AML::Byte opcode = static_cast<Byte>(context.aml_data[0]);
|
||||
context.aml_data = context.aml_data.slice(1);
|
||||
|
||||
switch (opcode)
|
||||
{
|
||||
case AML::Byte::BreakOp:
|
||||
return ParseResult(ParseResult::Result::Breaked);
|
||||
case AML::Byte::ContinueOp:
|
||||
return ParseResult(ParseResult::Result::Continued);
|
||||
case AML::Byte::WhileOp:
|
||||
break;
|
||||
default:
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
auto while_pkg = AML::parse_pkg(context.aml_data);
|
||||
if (!while_pkg.has_value())
|
||||
return ParseResult::Failure;
|
||||
|
||||
auto outer_aml_data = context.aml_data;
|
||||
|
||||
bool breaked = false;
|
||||
while (!breaked)
|
||||
{
|
||||
context.aml_data = while_pkg.value();
|
||||
|
||||
auto predicate_result = AML::parse_object(context);
|
||||
if (!predicate_result.success())
|
||||
return ParseResult::Failure;
|
||||
auto predicate_node = predicate_result.node()
|
||||
? predicate_result.node()->convert(AML::Node::ConvInteger)
|
||||
: BAN::RefPtr<AML::Node>();
|
||||
if (!predicate_node)
|
||||
{
|
||||
AML_ERROR("While predicate is not an integer");
|
||||
return ParseResult::Failure;
|
||||
}
|
||||
|
||||
if (!static_cast<AML::Integer*>(predicate_node.ptr())->value)
|
||||
break;
|
||||
|
||||
while (context.aml_data.size() > 0)
|
||||
{
|
||||
auto object_result = AML::parse_object(context);
|
||||
if (object_result.returned())
|
||||
return ParseResult(ParseResult::Result::Returned, object_result.node());
|
||||
if (object_result.breaked())
|
||||
breaked = true;
|
||||
if (object_result.breaked() || object_result.continued())
|
||||
break;
|
||||
if (!object_result.success())
|
||||
return ParseResult::Failure;
|
||||
}
|
||||
}
|
||||
|
||||
context.aml_data = outer_aml_data;
|
||||
|
||||
return ParseResult::Success;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
26
kernel/include/kernel/ACPI/BatterySystem.h
Normal file
26
kernel/include/kernel/ACPI/BatterySystem.h
Normal file
@@ -0,0 +1,26 @@
|
||||
#pragma once
|
||||
|
||||
#include <kernel/ACPI/AML/Namespace.h>
|
||||
#include <kernel/FS/TmpFS/Inode.h>
|
||||
|
||||
namespace Kernel::ACPI
|
||||
{
|
||||
|
||||
class BatterySystem
|
||||
{
|
||||
BAN_NON_COPYABLE(BatterySystem);
|
||||
BAN_NON_MOVABLE(BatterySystem);
|
||||
public:
|
||||
static BAN::ErrorOr<void> initialize(AML::Namespace& acpi_namespace);
|
||||
|
||||
private:
|
||||
BatterySystem(AML::Namespace&);
|
||||
|
||||
BAN::ErrorOr<void> initialize_impl();
|
||||
|
||||
private:
|
||||
AML::Namespace& m_acpi_namespace;
|
||||
BAN::RefPtr<TmpDirectoryInode> m_directory;
|
||||
};
|
||||
|
||||
}
|
||||
69
kernel/include/kernel/ACPI/EmbeddedController.h
Normal file
69
kernel/include/kernel/ACPI/EmbeddedController.h
Normal file
@@ -0,0 +1,69 @@
|
||||
#pragma once
|
||||
|
||||
#include <BAN/Atomic.h>
|
||||
#include <BAN/UniqPtr.h>
|
||||
|
||||
#include <kernel/ACPI/AML/Scope.h>
|
||||
#include <kernel/Lock/Mutex.h>
|
||||
#include <kernel/Thread.h>
|
||||
|
||||
namespace Kernel::ACPI
|
||||
{
|
||||
|
||||
class EmbeddedController
|
||||
{
|
||||
public:
|
||||
static BAN::ErrorOr<BAN::UniqPtr<EmbeddedController>> create(AML::Scope&& scope, uint16_t command_port, uint16_t data_port, BAN::Optional<uint8_t> gpe);
|
||||
~EmbeddedController();
|
||||
|
||||
BAN::ErrorOr<uint8_t> read_byte(uint8_t offset);
|
||||
BAN::ErrorOr<void> write_byte(uint8_t offset, uint8_t value);
|
||||
|
||||
const AML::Scope& scope() const { return m_scope; }
|
||||
|
||||
private:
|
||||
EmbeddedController(AML::Scope&& scope, uint16_t command_port, uint16_t data_port, bool has_gpe)
|
||||
: m_scope(BAN::move(scope))
|
||||
, m_command_port(command_port)
|
||||
, m_data_port(data_port)
|
||||
, m_has_gpe(has_gpe)
|
||||
{ }
|
||||
|
||||
private:
|
||||
void wait_status_bit(uint8_t bit, uint8_t value);
|
||||
|
||||
uint8_t read_one(uint16_t port);
|
||||
void write_one(uint16_t port, uint8_t value);
|
||||
|
||||
static void handle_gpe_wrapper(void*);
|
||||
void handle_gpe();
|
||||
|
||||
BAN::ErrorOr<void> call_query_method(uint8_t notification);
|
||||
|
||||
void thread_task();
|
||||
|
||||
struct Command
|
||||
{
|
||||
uint8_t command;
|
||||
BAN::Optional<uint8_t> data1;
|
||||
BAN::Optional<uint8_t> data2;
|
||||
uint8_t* response;
|
||||
BAN::Atomic<bool> done;
|
||||
};
|
||||
BAN::ErrorOr<void> send_command(Command& command);
|
||||
|
||||
private:
|
||||
const AML::Scope m_scope;
|
||||
const uint16_t m_command_port;
|
||||
const uint16_t m_data_port;
|
||||
const bool m_has_gpe;
|
||||
|
||||
Mutex m_mutex;
|
||||
ThreadBlocker m_thread_blocker;
|
||||
|
||||
BAN::Optional<Command*> m_queued_command;
|
||||
|
||||
Thread* m_thread { nullptr };
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <BAN/Errors.h>
|
||||
#include <BAN/Optional.h>
|
||||
|
||||
namespace Kernel::ACPI
|
||||
{
|
||||
@@ -22,8 +23,8 @@ namespace Kernel::ACPI
|
||||
PlatformCommunicationChannel = 0x0A,
|
||||
};
|
||||
|
||||
BAN::Optional<uint64_t> read();
|
||||
bool write(uint64_t value);
|
||||
BAN::ErrorOr<uint64_t> read();
|
||||
BAN::ErrorOr<void> write(uint64_t value);
|
||||
|
||||
AddressSpaceID address_space_id;
|
||||
uint8_t register_bit_width;
|
||||
|
||||
179
kernel/include/kernel/ACPI/Resource.h
Normal file
179
kernel/include/kernel/ACPI/Resource.h
Normal file
@@ -0,0 +1,179 @@
|
||||
#pragma once
|
||||
|
||||
#include <BAN/ByteSpan.h>
|
||||
#include <BAN/Debug.h>
|
||||
#include <BAN/Optional.h>
|
||||
|
||||
namespace Kernel::ACPI
|
||||
{
|
||||
|
||||
struct ResourceData
|
||||
{
|
||||
enum class Type
|
||||
{
|
||||
IRQ,
|
||||
DMA,
|
||||
IOPort,
|
||||
FixedIOPort,
|
||||
FixedDMA,
|
||||
|
||||
// TODO: large stuff the stuff :)
|
||||
};
|
||||
|
||||
union {
|
||||
struct {
|
||||
uint16_t irq_mask;
|
||||
union {
|
||||
struct {
|
||||
uint8_t edge_triggered : 1;
|
||||
uint8_t : 2;
|
||||
uint8_t active_low : 1;
|
||||
uint8_t shared : 1;
|
||||
uint8_t wake_capable : 1;
|
||||
uint8_t : 2;
|
||||
};
|
||||
uint8_t raw;
|
||||
};
|
||||
} irq;
|
||||
struct {
|
||||
uint8_t channel_mask;
|
||||
union {
|
||||
struct {
|
||||
uint8_t type : 2; // 0: 8 bit, 1: 8 and 16 bit, 2: 16 bit only
|
||||
uint8_t bus_master : 1;
|
||||
uint8_t : 2;
|
||||
uint8_t channel_speed : 2; // 0: compatibility, 1: type A, 2: type B, 3: type F
|
||||
uint8_t : 1;
|
||||
};
|
||||
uint8_t raw;
|
||||
};
|
||||
} dma;
|
||||
struct {
|
||||
uint16_t range_min_base;
|
||||
uint16_t range_max_base;
|
||||
uint8_t base_alignment;
|
||||
uint8_t range_length;
|
||||
} io_port;
|
||||
struct {
|
||||
uint16_t range_base;
|
||||
uint8_t range_length;
|
||||
} fixed_io_port;
|
||||
struct {
|
||||
uint16_t request_line;
|
||||
uint16_t channel;
|
||||
uint8_t transfer_width; // 0: 8 bit, 1: 16 bit, 2: 32 bit, 3: 64 bit, 4: 128 bit
|
||||
} fixed_dma;
|
||||
} as;
|
||||
Type type;
|
||||
};
|
||||
|
||||
class ResourceParser
|
||||
{
|
||||
public:
|
||||
ResourceParser(BAN::ConstByteSpan buffer)
|
||||
: m_buffer(buffer)
|
||||
{}
|
||||
|
||||
BAN::Optional<ResourceData> get_next()
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
if (m_buffer.empty())
|
||||
return {};
|
||||
|
||||
if (m_buffer[0] & 0x80)
|
||||
{
|
||||
dprintln("Skipping large resource 0x{2H}", m_buffer[0] & 0x7F);
|
||||
const uint16_t length = (m_buffer[2] << 8) | m_buffer[1];
|
||||
if (m_buffer.size() < static_cast<size_t>(3 + length))
|
||||
return {};
|
||||
m_buffer = m_buffer.slice(3 + length);
|
||||
continue;
|
||||
}
|
||||
|
||||
const uint8_t length = m_buffer[0] & 0x07;
|
||||
if (m_buffer.size() < static_cast<size_t>(1 + length))
|
||||
return {};
|
||||
|
||||
BAN::Optional<ResourceData> result;
|
||||
switch ((m_buffer[0] >> 3) & 0x0F)
|
||||
{
|
||||
case 0x04:
|
||||
if (length < 2)
|
||||
break;
|
||||
result = ResourceData {
|
||||
.as = { .irq = {
|
||||
.irq_mask = static_cast<uint16_t>((m_buffer[2] << 8) | m_buffer[1]),
|
||||
.raw = (length >= 3) ? m_buffer[3] : static_cast<uint8_t>(1),
|
||||
}},
|
||||
.type = ResourceData::Type::IRQ,
|
||||
};
|
||||
break;
|
||||
case 0x05:
|
||||
if (length < 2)
|
||||
break;
|
||||
result = ResourceData {
|
||||
.as = { .dma = {
|
||||
.channel_mask = m_buffer[1],
|
||||
.raw = m_buffer[2],
|
||||
}},
|
||||
.type = ResourceData::Type::DMA,
|
||||
};
|
||||
break;
|
||||
case 0x08:
|
||||
if (length < 7)
|
||||
break;
|
||||
result = ResourceData {
|
||||
.as = { .io_port = {
|
||||
.range_min_base = static_cast<uint16_t>(((m_buffer[3] << 8) | m_buffer[2]) & ((m_buffer[1] & 1) ? 0xFFFF : 0x03FF)),
|
||||
.range_max_base = static_cast<uint16_t>(((m_buffer[5] << 8) | m_buffer[4]) & ((m_buffer[1] & 1) ? 0xFFFF : 0x03FF)),
|
||||
.base_alignment = m_buffer[6],
|
||||
.range_length = m_buffer[7],
|
||||
}},
|
||||
.type = ResourceData::Type::IOPort,
|
||||
};
|
||||
break;
|
||||
case 0x09:
|
||||
if (length < 3)
|
||||
break;
|
||||
result = ResourceData {
|
||||
.as = { .fixed_io_port = {
|
||||
.range_base = static_cast<uint16_t>(((m_buffer[2] << 8) | m_buffer[1]) & 0x03FF),
|
||||
.range_length = m_buffer[3],
|
||||
}},
|
||||
.type = ResourceData::Type::FixedIOPort,
|
||||
};
|
||||
break;
|
||||
case 0x0A:
|
||||
if (length < 5)
|
||||
break;
|
||||
result = ResourceData {
|
||||
.as = { .fixed_dma = {
|
||||
.request_line = static_cast<uint16_t>((m_buffer[2] << 8) | m_buffer[1]),
|
||||
.channel = static_cast<uint16_t>((m_buffer[4] << 8) | m_buffer[3]),
|
||||
.transfer_width = m_buffer[5],
|
||||
}},
|
||||
.type = ResourceData::Type::FixedDMA,
|
||||
};
|
||||
break;
|
||||
case 0x0F:
|
||||
// End tag
|
||||
return {};
|
||||
case 0x06:
|
||||
case 0x07:
|
||||
case 0x0E:
|
||||
dprintln("Skipping short resource 0x{2H}", (m_buffer[0] >> 3) & 0x0F);
|
||||
break;
|
||||
}
|
||||
|
||||
m_buffer = m_buffer.slice(1 + length);
|
||||
if (result.has_value())
|
||||
return result.release_value();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
BAN::ConstByteSpan m_buffer;
|
||||
};
|
||||
|
||||
}
|
||||
37
kernel/include/kernel/API/SharedPage.h
Normal file
37
kernel/include/kernel/API/SharedPage.h
Normal file
@@ -0,0 +1,37 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace Kernel::API
|
||||
{
|
||||
|
||||
enum SharedPageFeature : uint32_t
|
||||
{
|
||||
SPF_GETTIME = 1 << 0,
|
||||
};
|
||||
|
||||
struct SharedPage
|
||||
{
|
||||
uint8_t __sequence[0x100];
|
||||
|
||||
uint32_t features;
|
||||
|
||||
struct
|
||||
{
|
||||
uint8_t shift;
|
||||
uint64_t mult;
|
||||
uint64_t realtime_seconds;
|
||||
} gettime_shared;
|
||||
|
||||
struct
|
||||
{
|
||||
struct
|
||||
{
|
||||
uint32_t seq;
|
||||
uint64_t last_ns;
|
||||
uint64_t last_tsc;
|
||||
} gettime_local;
|
||||
} cpus[];
|
||||
};
|
||||
|
||||
}
|
||||
44
kernel/include/kernel/API/Syscall.h
Normal file
44
kernel/include/kernel/API/Syscall.h
Normal file
@@ -0,0 +1,44 @@
|
||||
#pragma once
|
||||
|
||||
#include <kernel/Attributes.h>
|
||||
#include <kernel/IDT.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/syscall.h>
|
||||
|
||||
namespace Kernel
|
||||
{
|
||||
|
||||
ALWAYS_INLINE long syscall(int syscall, uintptr_t arg1 = 0, uintptr_t arg2 = 0, uintptr_t arg3 = 0, uintptr_t arg4 = 0, uintptr_t arg5 = 0)
|
||||
{
|
||||
long ret;
|
||||
#if ARCH(x86_64)
|
||||
register uintptr_t r10 asm("r10") = arg3;
|
||||
register uintptr_t r8 asm( "r8") = arg4;
|
||||
register uintptr_t r9 asm( "r9") = arg5;
|
||||
asm volatile(
|
||||
"syscall"
|
||||
: "=a"(ret)
|
||||
, "+D"(syscall)
|
||||
, "+S"(arg1)
|
||||
, "+d"(arg2)
|
||||
, "+r"(r10)
|
||||
, "+r"(r8)
|
||||
, "+r"(r9)
|
||||
:: "rcx", "r11", "memory");
|
||||
#elif ARCH(i686)
|
||||
asm volatile(
|
||||
"int %[irq]"
|
||||
: "=a"(ret)
|
||||
: [irq]"i"(static_cast<int>(IRQ_SYSCALL)) // WTF GCC 15
|
||||
, "a"(syscall)
|
||||
, "b"(arg1)
|
||||
, "c"(arg2)
|
||||
, "d"(arg3)
|
||||
, "S"(arg4)
|
||||
, "D"(arg5)
|
||||
: "memory");
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -23,6 +23,8 @@ namespace Kernel
|
||||
virtual void broadcast_ipi() override;
|
||||
virtual void enable() override;
|
||||
|
||||
BAN::ErrorOr<uint8_t> reserve_gsi(uint32_t gsi);
|
||||
|
||||
void initialize_timer();
|
||||
|
||||
private:
|
||||
|
||||
59
kernel/include/kernel/Audio/AC97/Controller.h
Normal file
59
kernel/include/kernel/Audio/AC97/Controller.h
Normal file
@@ -0,0 +1,59 @@
|
||||
#pragma once
|
||||
|
||||
#include <kernel/Audio/Controller.h>
|
||||
#include <kernel/Memory/DMARegion.h>
|
||||
|
||||
namespace Kernel
|
||||
{
|
||||
|
||||
class AC97AudioController final : public AudioController, public Interruptable
|
||||
{
|
||||
public:
|
||||
static BAN::ErrorOr<void> create(PCI::Device& pci_device);
|
||||
|
||||
void handle_irq() override;
|
||||
|
||||
protected:
|
||||
void handle_new_data() override;
|
||||
|
||||
uint32_t get_channels() const override { return 2; }
|
||||
uint32_t get_sample_rate() const override { return 48000; }
|
||||
|
||||
uint32_t get_total_pins() const override { return 1; }
|
||||
uint32_t get_current_pin() const override { return 0; }
|
||||
BAN::ErrorOr<void> set_current_pin(uint32_t pin) override { if (pin != 0) return BAN::Error::from_errno(EINVAL); return {}; }
|
||||
|
||||
BAN::ErrorOr<void> set_volume_mdB(int32_t) override;
|
||||
|
||||
private:
|
||||
AC97AudioController(PCI::Device& pci_device)
|
||||
: m_pci_device(pci_device)
|
||||
{ }
|
||||
|
||||
uint32_t get_volume_data() const;
|
||||
|
||||
BAN::ErrorOr<void> initialize();
|
||||
BAN::ErrorOr<void> initialize_bld();
|
||||
BAN::ErrorOr<void> initialize_interrupts();
|
||||
|
||||
bool queue_samples_to_bld();
|
||||
|
||||
private:
|
||||
static constexpr size_t m_bdl_entries = 32;
|
||||
static constexpr size_t m_samples_per_entry = 0x1000;
|
||||
|
||||
// We only store samples in 2 BDL entries at a time to reduce the amount of samples queued.
|
||||
// This is to reduce latency as you cannot remove data already passed to the BDLs
|
||||
static constexpr size_t m_used_bdl_entries = 2;
|
||||
|
||||
PCI::Device& m_pci_device;
|
||||
BAN::UniqPtr<PCI::BarRegion> m_mixer;
|
||||
BAN::UniqPtr<PCI::BarRegion> m_bus_master;
|
||||
|
||||
BAN::UniqPtr<DMARegion> m_bdl_region;
|
||||
|
||||
uint32_t m_bdl_tail { 0 };
|
||||
uint32_t m_bdl_head { 0 };
|
||||
};
|
||||
|
||||
}
|
||||
15
kernel/include/kernel/Audio/AC97/Definitions.h
Normal file
15
kernel/include/kernel/Audio/AC97/Definitions.h
Normal file
@@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace Kernel::AC97
|
||||
{
|
||||
|
||||
struct BufferDescriptorListEntry
|
||||
{
|
||||
uint32_t address;
|
||||
uint16_t samples;
|
||||
uint16_t flags; // bit 14: last entry, bit 15: IOC
|
||||
};
|
||||
|
||||
}
|
||||
58
kernel/include/kernel/Audio/Controller.h
Normal file
58
kernel/include/kernel/Audio/Controller.h
Normal file
@@ -0,0 +1,58 @@
|
||||
#pragma once
|
||||
|
||||
#include <kernel/Device/Device.h>
|
||||
#include <kernel/Memory/ByteRingBuffer.h>
|
||||
#include <kernel/PCI.h>
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
namespace Kernel
|
||||
{
|
||||
|
||||
class AudioController : public CharacterDevice
|
||||
{
|
||||
public:
|
||||
static BAN::ErrorOr<void> create(PCI::Device& pci_device);
|
||||
|
||||
dev_t rdev() const override { return m_rdev; }
|
||||
BAN::StringView name() const override { return m_name; }
|
||||
|
||||
protected:
|
||||
AudioController();
|
||||
BAN::ErrorOr<void> initialize();
|
||||
|
||||
virtual void handle_new_data() = 0;
|
||||
|
||||
virtual uint32_t get_channels() const = 0;
|
||||
virtual uint32_t get_sample_rate() const = 0;
|
||||
|
||||
virtual uint32_t get_total_pins() const = 0;
|
||||
virtual uint32_t get_current_pin() const = 0;
|
||||
virtual BAN::ErrorOr<void> set_current_pin(uint32_t) = 0;
|
||||
|
||||
virtual BAN::ErrorOr<void> set_volume_mdB(int32_t) = 0;
|
||||
|
||||
bool can_read_impl() const override { return false; }
|
||||
bool can_write_impl() const override { SpinLockGuard _(m_spinlock); return !m_sample_data->full(); }
|
||||
bool has_error_impl() const override { return false; }
|
||||
bool has_hungup_impl() const override { return false; }
|
||||
|
||||
BAN::ErrorOr<size_t> write_impl(off_t, BAN::ConstByteSpan) override;
|
||||
|
||||
BAN::ErrorOr<long> ioctl_impl(int cmd, void* arg) override;
|
||||
|
||||
protected:
|
||||
ThreadBlocker m_sample_data_blocker;
|
||||
mutable SpinLock m_spinlock;
|
||||
|
||||
static constexpr size_t m_sample_data_capacity = 1 << 20;
|
||||
BAN::UniqPtr<ByteRingBuffer> m_sample_data;
|
||||
|
||||
snd_volume_info m_volume_info {};
|
||||
|
||||
private:
|
||||
const dev_t m_rdev;
|
||||
char m_name[10] {};
|
||||
};
|
||||
|
||||
}
|
||||
80
kernel/include/kernel/Audio/HDAudio/AudioFunctionGroup.h
Normal file
80
kernel/include/kernel/Audio/HDAudio/AudioFunctionGroup.h
Normal file
@@ -0,0 +1,80 @@
|
||||
#pragma once
|
||||
|
||||
#include <kernel/Audio/Controller.h>
|
||||
#include <kernel/Audio/HDAudio/Controller.h>
|
||||
|
||||
namespace Kernel
|
||||
{
|
||||
|
||||
class HDAudioController;
|
||||
|
||||
class HDAudioFunctionGroup final : public AudioController
|
||||
{
|
||||
public:
|
||||
static BAN::ErrorOr<BAN::RefPtr<HDAudioFunctionGroup>> create(BAN::RefPtr<HDAudioController>, uint8_t cid, HDAudio::AFGNode&&);
|
||||
|
||||
void on_stream_interrupt(uint8_t stream_index);
|
||||
|
||||
protected:
|
||||
// FIXME: allow setting these :D
|
||||
uint32_t get_channels() const override { return 2; }
|
||||
uint32_t get_sample_rate() const override { return 48000; }
|
||||
|
||||
uint32_t get_total_pins() const override;
|
||||
uint32_t get_current_pin() const override;
|
||||
BAN::ErrorOr<void> set_current_pin(uint32_t) override;
|
||||
|
||||
BAN::ErrorOr<void> set_volume_mdB(int32_t) override;
|
||||
|
||||
void handle_new_data() override;
|
||||
|
||||
private:
|
||||
HDAudioFunctionGroup(BAN::RefPtr<HDAudioController> controller, uint8_t cid, HDAudio::AFGNode&& afg_node)
|
||||
: m_controller(controller)
|
||||
, m_afg_node(BAN::move(afg_node))
|
||||
, m_cid(cid)
|
||||
{ }
|
||||
~HDAudioFunctionGroup();
|
||||
|
||||
BAN::ErrorOr<void> initialize();
|
||||
BAN::ErrorOr<void> initialize_stream();
|
||||
BAN::ErrorOr<void> initialize_output();
|
||||
|
||||
BAN::ErrorOr<void> enable_output_path(uint8_t index);
|
||||
BAN::ErrorOr<void> disable_output_path(uint8_t index);
|
||||
|
||||
void reset_stream();
|
||||
|
||||
BAN::ErrorOr<void> recurse_output_paths(const HDAudio::AFGWidget& widget, BAN::Vector<const HDAudio::AFGWidget*>& path);
|
||||
|
||||
uint16_t get_format_data() const;
|
||||
|
||||
size_t bdl_offset() const;
|
||||
|
||||
void queue_bdl_data();
|
||||
|
||||
private:
|
||||
// use 6 512 sample BDL entries
|
||||
// each entry is ~10.7 ms at 48 kHz
|
||||
// -> total buffered audio is 64 ms
|
||||
static constexpr size_t m_bdl_entry_sample_frames = 512;
|
||||
static constexpr size_t m_bdl_entry_count = 6;
|
||||
|
||||
BAN::RefPtr<HDAudioController> m_controller;
|
||||
const HDAudio::AFGNode m_afg_node;
|
||||
const uint8_t m_cid;
|
||||
|
||||
BAN::Vector<BAN::Vector<const HDAudio::AFGWidget*>> m_output_paths;
|
||||
BAN::Vector<const HDAudio::AFGWidget*> m_output_pins;
|
||||
size_t m_output_path_index { SIZE_MAX };
|
||||
|
||||
uint8_t m_stream_id { 0xFF };
|
||||
uint8_t m_stream_index { 0xFF };
|
||||
BAN::UniqPtr<DMARegion> m_bdl_region;
|
||||
|
||||
size_t m_bdl_head { 0 };
|
||||
size_t m_bdl_tail { 0 };
|
||||
bool m_stream_running { false };
|
||||
};
|
||||
|
||||
}
|
||||
77
kernel/include/kernel/Audio/HDAudio/Controller.h
Normal file
77
kernel/include/kernel/Audio/HDAudio/Controller.h
Normal file
@@ -0,0 +1,77 @@
|
||||
#pragma once
|
||||
|
||||
#include <kernel/Audio/Controller.h>
|
||||
#include <kernel/Audio/HDAudio/Definitions.h>
|
||||
#include <kernel/Memory/DMARegion.h>
|
||||
|
||||
namespace Kernel
|
||||
{
|
||||
|
||||
class HDAudioController : public Interruptable, public BAN::RefCounted<HDAudioController>
|
||||
{
|
||||
public:
|
||||
static BAN::ErrorOr<void> create(PCI::Device& pci_device);
|
||||
|
||||
BAN::ErrorOr<uint32_t> send_command(HDAudio::CORBEntry);
|
||||
|
||||
uint8_t get_stream_index(HDAudio::StreamType type, uint8_t index) const;
|
||||
|
||||
BAN::ErrorOr<uint8_t> allocate_stream_id();
|
||||
void deallocate_stream_id(uint8_t id);
|
||||
|
||||
BAN::ErrorOr<uint8_t> allocate_stream(HDAudio::StreamType type, void* afg);
|
||||
void deallocate_stream(uint8_t index);
|
||||
|
||||
PCI::BarRegion& bar0() { return *m_bar0; }
|
||||
|
||||
bool is_64bit() const { return m_is64bit; }
|
||||
|
||||
void handle_irq() override;
|
||||
|
||||
private:
|
||||
HDAudioController(PCI::Device& pci_device)
|
||||
: m_pci_device(pci_device)
|
||||
{ }
|
||||
|
||||
BAN::ErrorOr<void> initialize();
|
||||
BAN::ErrorOr<void> initialize_ring_buffers();
|
||||
|
||||
BAN::ErrorOr<void> reset_controller();
|
||||
|
||||
BAN::ErrorOr<HDAudio::Codec> initialize_codec(uint8_t codec);
|
||||
BAN::ErrorOr<HDAudio::AFGNode> initialize_node(uint8_t codec, uint8_t node);
|
||||
BAN::ErrorOr<HDAudio::AFGWidget> initialize_widget(uint8_t codec, uint8_t node);
|
||||
|
||||
private:
|
||||
struct RingBuffer
|
||||
{
|
||||
vaddr_t vaddr;
|
||||
uint32_t index;
|
||||
uint32_t size;
|
||||
};
|
||||
|
||||
private:
|
||||
PCI::Device& m_pci_device;
|
||||
BAN::UniqPtr<PCI::BarRegion> m_bar0;
|
||||
bool m_is64bit { false };
|
||||
|
||||
bool m_use_immediate_command { false };
|
||||
|
||||
uint8_t m_output_streams { 0 };
|
||||
uint8_t m_input_streams { 0 };
|
||||
uint8_t m_bidir_streams { 0 };
|
||||
void* m_allocated_streams[30] {};
|
||||
|
||||
// NOTE: stream ids are from 1 to 15
|
||||
uint16_t m_allocated_stream_ids { 0 };
|
||||
|
||||
Mutex m_command_mutex;
|
||||
SpinLock m_rb_lock;
|
||||
ThreadBlocker m_rb_blocker;
|
||||
|
||||
RingBuffer m_corb;
|
||||
RingBuffer m_rirb;
|
||||
BAN::UniqPtr<DMARegion> m_ring_buffer_region;
|
||||
};
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user