Compare commits
695 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 2b8eb8deb6 | |||
| 7262f3d0b7 | |||
| 6f80fd0063 | |||
| 7a51b7a019 | |||
| d9eb31000d | |||
| f8589de476 | |||
| f1c61067bc | |||
| 8a5620592b | |||
| 5227e65808 | |||
| c4c6dc19a5 | |||
| 7fc26b1fab | |||
| c0e121abef | |||
| 7db13fdeff | |||
| e68027b464 | |||
| 220b69058c | |||
| 9c3e55787e | |||
| c952e99f3e | |||
| 35322b5d14 | |||
| 6b96807112 | |||
| 57621d1c4e | |||
| e04b2eebc3 | |||
| 02b684b810 | |||
| 76b1acf99d | |||
| 18c120ab9f | |||
| f87dd91b52 | |||
| 4a8a161a43 | |||
| e3dec420a2 | |||
| 1e32311a65 | |||
| 92e5bb88e8 | |||
| 66581d115b | |||
| 4399324955 | |||
| 733f31f90e | |||
| bef2c50b03 | |||
| a96b4412d3 | |||
| bee76fc8d1 | |||
| d9cb1a6319 | |||
| 567d23d856 | |||
| c94a98e15a | |||
| 72e6e87d82 | |||
| 0055d84bd6 | |||
| d17d22139e | |||
| 87b6284275 | |||
| 2c6b974f24 | |||
| 020acc8235 | |||
| a8e0d261b7 | |||
| 6357b9a04f | |||
| 43a58df8a0 | |||
| b7bf316c1a | |||
| 41ee792f95 | |||
| 6c1b6c1704 | |||
| acadaeed3a | |||
| 96bde3df81 | |||
| 5cb70ddbd5 | |||
| b9b9a0465f | |||
| bd269bccaf | |||
| 5f618814f6 | |||
| 43c87e99b0 | |||
| 74a09a6338 | |||
| 2b9c407dc3 | |||
| 59ed222205 | |||
| 2c06043617 | |||
| ef884642e4 | |||
| e449111c33 | |||
| 066e53da55 | |||
| c74b2cb085 | |||
| eec11bfba9 | |||
| d254a5736b | |||
| b655e4aa47 | |||
| 1adec3d8e5 | |||
| db9b7db531 | |||
| 05099e2ae1 | |||
| 77352a2a86 | |||
| ae633292c0 | |||
| d6042cf891 | |||
| 534c63bf57 | |||
| fb29933d3d | |||
| 360c4d1554 | |||
| 4cfa9b11f3 | |||
| 908465b274 | |||
| a7f10d142e | |||
| e855673802 | |||
| 112ac7bd13 | |||
| ec7963df3d | |||
| 343d006ae2 | |||
| ed8e5498d1 | |||
| 3cfead4ca6 | |||
| c8947eee6a | |||
| 6c1ca7d797 | |||
| 2172974db9 | |||
| ba03df8511 | |||
| fb47d1f788 | |||
| 3c86e14ea4 | |||
| c16fb61bea | |||
| 2acead357b | |||
| 235db57f0e | |||
| cfbde005fb | |||
| 0a865bd9dc | |||
| 6b3f722ff0 | |||
| 3dbecada4e | |||
| d21f87af5d | |||
| 0bfec59af8 | |||
| 035a76f26d | |||
| 42f4e831a2 | |||
| d3686dbb75 | |||
| fb1c790350 | |||
| 0ef5743261 | |||
| e82bef425f | |||
| 24c246a9f6 | |||
| e39348ad96 | |||
| ca5f0444bf | |||
| 4a883ba6ea | |||
| bfe1a8673a | |||
| 0445ef393f | |||
| 7eb16e13bb | |||
| 03ad5c6830 | |||
| ab23e5ca0e | |||
| 35ecd00559 | |||
| e5603fec1e | |||
| e321765c54 | |||
| 62fdcf50ea | |||
| 09d293592e | |||
| f83c2f0b6b | |||
| d775c8dc73 | |||
| 8e07b19bc7 | |||
| cb8ef46ec7 | |||
| ee814cfd0c | |||
| a6a5292cd7 | |||
| b59f142d4e | |||
| 666a18f5e5 | |||
| dff4392c10 | |||
| b09b7c1184 | |||
| 6e05dcadb6 | |||
| bc7acf9f7a | |||
| cb19316a17 | |||
| 33c3977036 | |||
| 7a015b6fc0 | |||
| aa3aef4beb | |||
| 12a48fc6d1 | |||
| 72284b4530 | |||
| 65c04e4ddd | |||
| b382d3b3e9 | |||
| 61b882b2a6 | |||
| 36c8654fb8 | |||
| d25c401aec | |||
| aac874a842 | |||
| 5d934c8759 | |||
| e055d16b2c | |||
| 38745e5782 | |||
| d0c271e534 | |||
| 33635c5723 | |||
| f8d2830ac7 | |||
| a7e5c255b4 | |||
| 062c605eb1 | |||
| 2602be426f | |||
| 51dcb4a79d | |||
| 24e4e329ed | |||
| eb66302907 | |||
| b16cc618b5 | |||
| 77aa9e58f2 | |||
| 3a0b3a85a5 | |||
| 15a12afe25 | |||
| 427cf91447 | |||
| af8c661a64 | |||
| 7b694ebeb4 | |||
| d1e7837422 | |||
| 8efc22bd45 | |||
| 983439076b | |||
| 019f566239 | |||
| 332410d20b | |||
| c2a85bde08 | |||
| 13a0b88755 | |||
| 32f39fec1c | |||
| cad3a6c547 | |||
| 2aa5c437e8 | |||
| 67f48ce21c | |||
| 845a7d9968 | |||
| 924774d3ef | |||
| e0635cf65c | |||
| 3b8e3a9714 | |||
| 2bee096246 | |||
| 872655369a | |||
| 0892758994 | |||
| 22a24446c1 | |||
| b5d498ffda | |||
| bd90e3e37f | |||
| 8b6d615aa6 | |||
| 9e352da052 | |||
| ca9898e838 | |||
| 95b8467a76 | |||
| 2b674d4d8c | |||
| 487b572aa6 | |||
| 600c0ea5ba | |||
| 00e64920c8 | |||
| 9efedbe76a | |||
| d8e9382573 | |||
| ab248e170c | |||
| 27097cbcfe | |||
| 43952e18e2 | |||
| 5076da8f77 | |||
| 8228a4adcd | |||
| 721883f64e | |||
| b55c759f71 | |||
| 3f028fbb83 | |||
| f0cba1371c | |||
| 14fa96fdef | |||
| b954a41f2a | |||
| f1c65dcefc | |||
| d4c17ecda5 | |||
| a4458e2c8c | |||
| 16cc88dd0e | |||
| 280f5f0b54 | |||
| e38eaa7cd7 | |||
| a27bd2275c | |||
| 7d00c69a4f | |||
| a2c189b45a | |||
| 41320688b7 | |||
| f85c8584b0 | |||
| 6cf50f8f6c | |||
| d70ab11477 | |||
| cab4c78b7b | |||
| 14358d5e84 | |||
| 7553429130 | |||
| 3ddfa288cf | |||
| e89a568765 | |||
| 71f1021648 | |||
| 60cff6f3d4 | |||
| 5f010c2f4c | |||
| c0f3d1f06d | |||
| 6c18e00977 | |||
| 72ac1aa537 | |||
| 5bcaa25c02 | |||
| 85880ffded | |||
| 5b207c3b95 | |||
| 3087f15dd8 | |||
| 36f1193497 | |||
| 292af1e4cd | |||
| d4d5dc99f3 | |||
| 3e1344e4e4 | |||
| 6d37bc62a5 | |||
| e9f7c100a0 | |||
| 190676c982 | |||
| 28cbba5a7d | |||
| 0e7a705254 | |||
| 68931b4c43 | |||
| a4e28df9cf | |||
| 65c81c5e83 | |||
| ccd0d2046d | |||
| 0fec99e75b | |||
| f8d1f070f5 | |||
| 3dd48a24ce | |||
| 984e97cbdc | |||
| 50ea1a12c9 | |||
| 992a372fc7 | |||
| d789250976 | |||
| d7e1cf7dd2 | |||
| ea5f5aea5f | |||
| eaf0bbc108 | |||
| b1710bb712 | |||
| dfae7bd073 | |||
| 333fe9a561 | |||
| badb3dc2dd | |||
| 3ac819ee70 | |||
| 00f877e812 | |||
| 1e269751bf | |||
| 5b69eda39a | |||
| 71ca413067 | |||
| 0c7f9458c0 | |||
| ab365fe494 | |||
| e48f160a29 | |||
| cfda4d0ade | |||
| debfae06a8 | |||
| e6f2f8ad0d | |||
| 67785a918c | |||
| 50d80c64fa | |||
| 1378645413 | |||
| 3888b0429c | |||
| 70761a4ef0 | |||
| e37df998e9 | |||
| c30cdfb3a7 | |||
| 350b704cd7 | |||
| ad013d59f4 | |||
| d391133524 | |||
| 4b823469f7 | |||
| 7cd1e767be | |||
| 829a697c39 | |||
| fefab50e06 | |||
| 6e27ab60ca | |||
| 74274f6d77 | |||
| 908b2703f3 | |||
| c047ab6147 | |||
| 52fa69d93d | |||
| a83df01bfd | |||
| b32d989a10 | |||
| d1ee7c651f | |||
| dcbe8ef5f4 | |||
| bd5253047b | |||
| cdaa8cb5c4 | |||
| 083397a555 | |||
| e98eb4659e | |||
| d1988d384c | |||
| bc61835d97 | |||
| 8a50880613 | |||
| b05d12df0e | |||
| 733b46d51a | |||
| 8bc9868c1f | |||
| 3507cd0a37 | |||
| 21ec32b465 | |||
| 1c99a2e7fb | |||
| b68bdafadc | |||
| bacfa9be19 | |||
| 5265eb81e0 | |||
| 516da4ecdd | |||
| 6fcc68699a | |||
| 3cb5fd8ebc | |||
| fd7ea82965 | |||
| 0bd989b118 | |||
| bd0b292b39 | |||
| 31f0a0c064 | |||
| 3e445eff8e | |||
| 6dcd482dd0 | |||
| a28ab0a408 | |||
| a3eb5c2d63 | |||
| e2303f3378 | |||
| acb17b0298 | |||
| fde7cf1fab | |||
| c2cb7e1004 | |||
| 4075f5c497 | |||
| debd44fa9b | |||
| 0a5742587a | |||
| ad4df2d946 | |||
| bfe9580551 | |||
| 1e45437498 | |||
| f9c8f78000 | |||
| 4554eedd19 | |||
| 557f0c5a8a | |||
| 9fb8d449fe | |||
| 1bb7c74c93 | |||
| cc07e5306e | |||
| 34fa010601 | |||
| 7d56069243 | |||
| fc77fb9b4c | |||
| ebdf93e5dc | |||
| 5248240e10 | |||
| b66628baca | |||
| ba5ed5f380 | |||
| 8d5e119582 | |||
| d022e7cd27 | |||
| 5d7acda80e | |||
| 9b595c68a5 | |||
| 2d38d8a639 | |||
| dea8aa675a | |||
| 027eba2b59 | |||
| 91b8e7504e | |||
| 088931525d | |||
| ef9638e094 | |||
| 09a9d08466 | |||
| 1b8bf081b5 | |||
| 06ecc2ae68 | |||
| 46d3066c62 | |||
| 8d12816001 | |||
| fe03b55046 | |||
| ca57f25f26 | |||
| 3c639ff8e1 | |||
| 78c986b5dd | |||
| a42663b09b | |||
| 36149fd986 | |||
| c2c559f8d9 | |||
| 5e8419af0d | |||
| 86fc842c89 | |||
| 80530e8aef | |||
| ba26e16411 | |||
| 2cee26c3e7 | |||
| 5d55e509ec | |||
| 4984e87776 | |||
| c65b7d0aea | |||
| 54fd224fd8 | |||
| 5ca2b1200d | |||
| b5014d56ab | |||
| c4e89f8bb4 | |||
| 7dd85b207f | |||
| cb0431d960 | |||
| 58adb6a1aa | |||
| 13c564f2af | |||
| 95aeebe4b5 | |||
| 605d57c541 | |||
| f972fa26a4 | |||
| 150e18539c | |||
| f03d4cf8fd | |||
| 3419d15878 | |||
| 0da24f21d6 | |||
| e794109a67 | |||
| 006c783aba | |||
| 4378a09867 | |||
| fb24b06a5d | |||
| 425fce5070 | |||
| d5667a859a | |||
| 95dbcf2fd7 | |||
| 8ce0819b42 | |||
| 688a456642 | |||
| 59b3a3d26b | |||
| ea1cdbfdd8 | |||
| 3641926333 | |||
| 280958ee74 | |||
| f4070731a8 | |||
| e791678dfc | |||
| 6f5bbf550a | |||
| ff550b5c3c | |||
| d6daa0d05b | |||
| 86785dffa4 | |||
| c491b73f3a | |||
| c50233cc92 | |||
| 13de773486 | |||
| 4966f6de73 | |||
| 6806e3d5c7 | |||
| 0a121e9d26 | |||
| 15e8cba398 | |||
| b32eecb5a7 | |||
| 8ce0eaa9d0 | |||
| 8307f82f86 | |||
| 2b6a56c21c | |||
| f1e66085cd | |||
| d344701fd5 | |||
| 130a0ef20e | |||
| 18ca3ed449 | |||
| af6fcb19a8 | |||
| eec2dfad7b | |||
| 0fcf767ee9 | |||
| 1e7bf218e0 | |||
| 4ea7628204 | |||
| 7db77a5580 | |||
| 97ae5ab561 | |||
| 89d9813a45 | |||
| 2b52b4a749 | |||
| c479d431a4 | |||
| 8628fc441d | |||
| d48d67767a | |||
| 10caa2981f | |||
| 49610f52f5 | |||
| 27643cb715 | |||
| fe3c7926f7 | |||
| 552d8e6aec | |||
| 0bb3609cad | |||
| b56bc7e087 | |||
| abcf265bc7 | |||
| 6d3c421823 | |||
| e70f430b5a | |||
| 8c927d3cc8 | |||
| b998852385 | |||
| 59d9e7ce98 | |||
| 306593a0c5 | |||
| 3b8bce1bed | |||
| f0fd7e2e19 | |||
| 4384ae15b4 | |||
| dc8252bb9f | |||
| 182a998cb6 | |||
| ea8e435b32 | |||
| 72d1ac22aa | |||
| 8ce5392390 | |||
| 311682b341 | |||
| 44c90c060a | |||
| a5eb11d79f | |||
| 120849c734 | |||
| adf50b7c4b | |||
| f5c575961f | |||
| a90801e2aa | |||
| 402e8b12a6 | |||
| 701f7f39d6 | |||
| 6590366f8e | |||
| fa0b02ed30 | |||
| 15efb73aae | |||
| d0057c92e4 | |||
| 4078f43984 | |||
| 3d980a9f66 | |||
| a0d95a823e | |||
| 9e14d240a8 | |||
| 1393bb2caf | |||
| e9914f3004 | |||
| 073772a801 | |||
| 2babe4c236 | |||
| bbda618beb | |||
| 344c813eb1 | |||
| abaa8f855f | |||
| ea1171f624 | |||
| 1e83d2a4e9 | |||
| 443c2b920d | |||
| 953663e00b | |||
| 5185ddb8b5 | |||
| 583ed61712 | |||
| 492ed27495 | |||
| facde63460 | |||
| 494953997e | |||
| 1b89ad00e7 | |||
| 40558e7ac1 | |||
| 3bddba0c7a | |||
| 97cd641da9 | |||
| 91db4b724c | |||
| dcff8c2637 | |||
| 7a76fb1469 | |||
| 17f805ae64 | |||
| 1606f97177 | |||
| dc39a9b84f | |||
| 4ff23a9943 | |||
| a806be8bc4 | |||
| b57a9c31f0 | |||
| 95c1443e30 | |||
| 5bd5a382c0 | |||
| 1885e4345c | |||
| 2f329cf7b5 | |||
| f2d2a6b605 | |||
| 3c935f7834 | |||
| 2c8b3f05ac | |||
| e8e3a3b2a2 | |||
| ec7d243ee9 | |||
| b74c5e04f5 | |||
| 050c3e1d6b | |||
| 6d83c9cc0e | |||
| 346a1d4433 | |||
| d962bb018d | |||
| bca3a3f4ed | |||
| ffea52dc36 | |||
| 865464f607 | |||
| 73f96f48ee | |||
| 89f1248140 | |||
| 59be63167f | |||
| c628147521 | |||
| a5cff8b186 | |||
| 983547af7e | |||
| d5f7e7b179 | |||
| 2a258dc21e | |||
| ec1244bb82 | |||
| ac6e042223 | |||
| a0b387e0a9 | |||
| 4cafd5a31c | |||
| 888b520b31 | |||
| 493e57837b | |||
| bddfa76b2e | |||
| ee00fdb61b | |||
| 9b22661c19 | |||
| 0ac3dbfec9 | |||
| 56cebd99c2 | |||
| 04c3d8d1bb | |||
| 7fdf3dd760 | |||
| 1f28bee86a | |||
| aed560b630 | |||
| 871b15f6e1 | |||
| ef0faf03fd | |||
| 5226076676 | |||
| 046923d9f7 | |||
| 531eb04fd7 | |||
| f4ca6f02a1 | |||
| 3f7eba19c8 | |||
| 04ff7913b4 | |||
| 09cddc84be | |||
| 9baef8c705 | |||
| a14a358b73 | |||
| 259844f4f3 | |||
| 264df11132 | |||
| 53c8ed6a63 | |||
| f22348a9f9 | |||
| 83d71519e0 | |||
| 8ad36e2526 | |||
| 0f67c68993 | |||
| b79d236bfa | |||
| 92efaf0bba | |||
| 3b11f22062 | |||
| 6164b3d2e2 | |||
| c806da51f8 | |||
| 183aa31319 | |||
| 7b3c0a69f3 | |||
| 6b11d82dd0 | |||
| d0f1b29b39 | |||
| b8fa6fb4c4 | |||
| 22269ca0d7 | |||
| 9ea478008c | |||
| 20f1eb865b | |||
| 53212ba7a9 | |||
| 3372409590 | |||
| 4fe2951509 | |||
| ff8a94714f | |||
| b45d6fee2d | |||
| f44e696edf | |||
| 5a049322ed | |||
| 04deb97f94 | |||
| 0c3c34179e | |||
| e938ddda2c | |||
| 97e26f9d6c | |||
| bfa78870cb | |||
| ad37259ccc | |||
| 418968d974 | |||
| 89905bc1c4 | |||
| 3a96d99187 | |||
| a50ea09053 | |||
| d012abd924 | |||
| 7ed82c0791 | |||
| cf61198fe3 | |||
| 5d50602397 | |||
| 34eff440eb | |||
| 0b42cf06f8 | |||
| 4c4be331f5 | |||
| 511e9920c2 | |||
| 75c3fdcb6f | |||
| 9031c5a6e0 | |||
| 5ac6f090fc | |||
| 0d183a24be | |||
| a21790b992 | |||
| 762ceaf87e | |||
| 2620a51cc9 | |||
| f1e8739608 | |||
| b31a0115b2 | |||
| ed032dc985 | |||
| c436ef0c6f | |||
| 9db97278f3 | |||
| d3898fda57 | |||
| 36ac68b436 | |||
| cdc3ee6c1c | |||
| 6540393df5 | |||
| 3f534b33ec | |||
| 9a6aac1662 | |||
| 4c70864588 | |||
| 17c8b34088 | |||
| 7900780cea | |||
| 0eb739756e | |||
| 05364908f3 | |||
| 92d65ff3c2 | |||
| a52a16807f | |||
| 8df1d74395 | |||
| f84697ad5c | |||
| a2da187615 | |||
| d0ffbbfc4d | |||
| 460a933267 | |||
| fe9c61fe73 | |||
| 3206378ae6 | |||
| 7ce790f369 | |||
| 5db1427923 | |||
| 81eceb1728 | |||
| 639650c65a | |||
| 9d034ea4a2 | |||
| 9ff0b460a2 | |||
| 4f0125a0e9 | |||
| 54493747a8 | |||
| b48c036636 | |||
| d489b02fc1 | |||
| 595fdb2f57 | |||
| 8d56dd1969 | |||
| 44371dedd9 | |||
| fb62c297fa | |||
| 676fed7cfc | |||
| d9d354c981 | |||
| 8c8048f037 | |||
| da6760ed98 | |||
| 1d04f14a53 | |||
| 570eee3202 | |||
| ca07605835 | |||
| 46e8b4f561 | |||
| 1e4655aef6 | |||
| 3e1b76258e | |||
| a845a0395a | |||
| f0053bfc1a | |||
| 22dc2947b3 | |||
| 43fce92aa9 | |||
| 6380e67af9 | |||
| dc465df3bc | |||
| 2e88924cb9 | |||
| fee96ec92d | |||
| c39ad1ee12 | |||
| 5669c7497d | |||
| 60f8fc293d | |||
| 9134388f94 | |||
| 10820fa135 | |||
| 2f3e0044f1 | |||
| 5060c779da | |||
| 6d2cb94e3e | |||
| 85e5b077f7 | |||
| 85dd1b4ea9 | |||
| 220e86bbd1 | |||
| abc715bc5c | |||
| e1adb18491 | |||
| 2688081656 | |||
| e4abd3dc5a | |||
| c7a185d4e7 | |||
| baf96b3eb6 | |||
| 8e2b07ba9e | |||
| 0b023d4e28 | |||
| 4ffc58a8ce | |||
| c5c9ea1b21 | |||
| 3c43d8fe05 | |||
| 21f06e1074 | |||
| 875e252db3 | |||
| 610e71b71b | |||
| 73d23eb6e6 | |||
| ddfa077c3e | |||
| 006f546e7c | |||
| 1dac01498c | |||
| ae0e454fc2 | |||
| ca3ee019cc |
+9
-15
@@ -1,25 +1,18 @@
|
||||
#!/bin/sh -ex
|
||||
|
||||
ccache -s # debug
|
||||
|
||||
# Pull all the submodules except llvm
|
||||
# Note: Tried to use git submodule status, but it takes over 20 seconds
|
||||
# shellcheck disable=SC2046
|
||||
git submodule -q update --init $(awk '/path/ && !/llvm/ { print $3 }' .gitmodules)
|
||||
git submodule -q update --init --depth 1 $(awk '/path/ && !/llvm/ { print $3 }' .gitmodules)
|
||||
|
||||
# XXX Drop after Travis upgrades FreeBSD to 12.2 (see also .ci/install-freebsd.sh)
|
||||
case $(${CXX:-c++} --version) in
|
||||
*version\ 8.0.*)
|
||||
fetch https://github.com/llvm/llvm-project/releases/download/llvmorg-10.0.0/libcxx-10.0.0.src.tar.xz
|
||||
tar xf libcxx-10.0.0.src.tar.xz
|
||||
export CC=clang10 CXX=clang++10
|
||||
export CXXFLAGS="$CXXFLAGS -nostdinc++ -isystem $PWD/libcxx-10.0.0.src/include"
|
||||
;;
|
||||
esac
|
||||
# Prefer newer Clang than in base system (see also .ci/install-freebsd.sh)
|
||||
# libc++ isn't in llvm* packages, so download manually
|
||||
fetch https://github.com/llvm/llvm-project/releases/download/llvmorg-11.0.0/libcxx-11.0.0.src.tar.xz
|
||||
tar xf libcxx-11.0.0.src.tar.xz
|
||||
export CC=clang11 CXX=clang++11
|
||||
export CXXFLAGS="$CXXFLAGS -nostdinc++ -isystem $PWD/libcxx-11.0.0.src/include"
|
||||
|
||||
CONFIGURE_ARGS="
|
||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache
|
||||
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache
|
||||
-DWITH_LLVM=OFF
|
||||
-DUSE_PRECOMPILED_HEADERS=OFF
|
||||
-DUSE_NATIVE_INSTRUCTIONS=OFF
|
||||
@@ -32,4 +25,5 @@ CONFIGURE_ARGS="
|
||||
cmake -B build -G Ninja $CONFIGURE_ARGS
|
||||
cmake --build build
|
||||
|
||||
ccache -s # debug
|
||||
ccache --show-stats
|
||||
ccache --zero-stats
|
||||
|
||||
+4
-5
@@ -48,17 +48,16 @@ cmake .. \
|
||||
-DCMAKE_CXX_FLAGS="$CFLAGS" \
|
||||
-DCMAKE_AR="$AR" \
|
||||
-DCMAKE_RANLIB="$RANLIB" \
|
||||
-DUSE_SYSTEM_CURL=ON \
|
||||
-G Ninja
|
||||
|
||||
ninja; build_status=$?;
|
||||
|
||||
cd ..
|
||||
|
||||
# If it compiled succesfully let's deploy depending on the build pipeline (Travis, Azure Pipelines).
|
||||
# Travis only deploys on master, and it publishes to GitHub releases. Azure publishes PRs as artifacts
|
||||
# only.
|
||||
{ [ "$IS_AZURE" = "true" ] ||
|
||||
{ [ "$TRAVIS_BRANCH" = "master" ] && [ "$TRAVIS_PULL_REQUEST" = "false" ]; };
|
||||
# If it compiled succesfully let's deploy depending on the build pipeline (Azure Pipelines).
|
||||
# Azure publishes PRs as artifacts only.
|
||||
{ [ "$IS_AZURE" = "true" ];
|
||||
} && SHOULD_DEPLOY="true" || SHOULD_DEPLOY="false"
|
||||
|
||||
if [ "$build_status" -eq 0 ] && [ "$SHOULD_DEPLOY" = "true" ]; then
|
||||
|
||||
+3
-11
@@ -41,7 +41,6 @@ if [ "$DEPLOY_APPIMAGE" = "true" ]; then
|
||||
COMM_HASH="$(git rev-parse --short=8 HEAD)"
|
||||
RPCS3_APPIMAGE="rpcs3-v${COMM_TAG}-${COMM_COUNT}-${COMM_HASH}_linux64.AppImage"
|
||||
|
||||
curl -sLO https://github.com/hcorion/uploadtool/raw/master/upload.sh
|
||||
mv ./RPCS3*.AppImage "$RPCS3_APPIMAGE"
|
||||
|
||||
# If we're building using Azure Pipelines, let's copy over the AppImage artifact
|
||||
@@ -50,16 +49,9 @@ if [ "$DEPLOY_APPIMAGE" = "true" ]; then
|
||||
fi
|
||||
|
||||
FILESIZE=$(stat -c %s ./rpcs3*.AppImage)
|
||||
SHA256SUM=$(sha256sum ./rpcs3*.AppImage)
|
||||
if [ -n "$GITHUB_TOKEN" ]; then
|
||||
unset TRAVIS_REPO_SLUG
|
||||
REPO_SLUG=RPCS3/rpcs3-binaries-linux \
|
||||
UPLOADTOOL_BODY="$SHA256SUM;${FILESIZE}B"\
|
||||
RELEASE_NAME=build-${TRAVIS_COMMIT}\
|
||||
RELEASE_TITLE=${COMM_TAG}-${COMM_COUNT}\
|
||||
REPO_COMMIT=d812f1254a1157c80fd402f94446310560f54e5f\
|
||||
bash upload.sh rpcs3*.AppImage
|
||||
fi
|
||||
SHA256SUM=$(sha256sum ./rpcs3*.AppImage | awk '{ print $1 }')
|
||||
echo "${SHA256SUM};${FILESIZE}B" > /rpcs3/GitHubReleaseMessage.txt
|
||||
|
||||
fi
|
||||
|
||||
if [ "$DEPLOY_PPA" = "true" ]; then
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
# Variables set by Travis CI
|
||||
TRAVIS_PULL_REQUEST
|
||||
TRAVIS_BRANCH
|
||||
TRAVIS_COMMIT
|
||||
# Variables set by Azure Pipelines
|
||||
IS_AZURE
|
||||
BUILD_REASON
|
||||
@@ -9,8 +5,8 @@ BUILD_SOURCEVERSION
|
||||
BUILD_ARTIFACTSTAGINGDIRECTORY
|
||||
BUILD_REPOSITORY_NAME
|
||||
BUILD_SOURCEBRANCHNAME
|
||||
# Variables for Travis build matrix
|
||||
# Variables for build matrix
|
||||
COMPILER
|
||||
DEPLOY_APPIMAGE
|
||||
# Private Travis CI variables
|
||||
# Private variables
|
||||
GITHUB_TOKEN
|
||||
Regular → Executable
+3
-5
@@ -7,7 +7,7 @@ generate_post_data()
|
||||
cat <<EOF
|
||||
{
|
||||
"tag_name": "build-${BUILD_SOURCEVERSION}",
|
||||
"target_commitish": "7d09e3be30805911226241afbb14f8cdc2eb054e",
|
||||
"target_commitish": "${UPLOAD_COMMIT_HASH}",
|
||||
"name": "${AVVER}",
|
||||
"body": "$body",
|
||||
"draft": false,
|
||||
@@ -16,12 +16,10 @@ generate_post_data()
|
||||
EOF
|
||||
}
|
||||
|
||||
repo_full_name="RPCS3/rpcs3-binaries-win"
|
||||
|
||||
curl -s \
|
||||
-H "Authorization: token ${RPCS3_TOKEN}" \
|
||||
-H "Accept: application/vnd.github.v3+json" \
|
||||
--data "$(generate_post_data)" "https://api.github.com/repos/$repo_full_name/releases" >> release.json
|
||||
--data "$(generate_post_data)" "https://api.github.com/repos/$UPLOAD_REPO_FULL_NAME/releases" >> release.json
|
||||
|
||||
cat release.json
|
||||
id=$(grep '"id"' release.json | cut -d ':' -f2 | head -n1 | awk '{$1=$1;print}')
|
||||
@@ -35,7 +33,7 @@ upload_file()
|
||||
-H "Accept: application/vnd.github.v3+json" \
|
||||
-H "Content-Type: application/octet-stream" \
|
||||
--data-binary @"$2"/"$3" \
|
||||
"https://uploads.github.com/repos/$repo_full_name/releases/$1/assets?name=$3"
|
||||
"https://uploads.github.com/repos/$UPLOAD_REPO_FULL_NAME/releases/$1/assets?name=$3"
|
||||
}
|
||||
|
||||
for file in "$ARTIFACT_DIR"/*; do
|
||||
@@ -8,12 +8,8 @@ sed -i '' 's/quarterly/latest/' /etc/pkg/FreeBSD.conf
|
||||
export ASSUME_ALWAYS_YES=true
|
||||
pkg info # debug
|
||||
|
||||
# XXX Drop after Travis upgrades FreeBSD to 12.2 (see also .ci/build-freebsd.sh)
|
||||
case $(${CXX:-c++} --version) in
|
||||
*version\ 8.0.*)
|
||||
pkg install llvm10
|
||||
;;
|
||||
esac
|
||||
# Prefer newer Clang than in base system (see also .ci/build-freebsd.sh)
|
||||
pkg install llvm11
|
||||
|
||||
# Mandatory dependencies (qt5-dbus and qt5-gui are pulled via qt5-widgets)
|
||||
pkg install git ccache cmake ninja qt5-qmake qt5-buildtools qt5-widgets qt5-concurrent glew openal-soft ffmpeg
|
||||
|
||||
@@ -10,16 +10,16 @@ PR_NUMBER="$SYSTEM_PULLREQUEST_PULLREQUESTID"
|
||||
QT_HOST="http://mirrors.ocf.berkeley.edu/qt/"
|
||||
#QT_HOST="http://qt.mirror.constant.com/"
|
||||
QT_URL_VER=$(echo "$QT_VER" | sed "s/\.//g")
|
||||
QT_PREFIX="online/qtsdkrepository/windows_x86/desktop/qt5_${QT_URL_VER}/qt.qt5.${QT_URL_VER}.win64_msvc2017_64/${QT_VER}-0-${QT_DATE}"
|
||||
QT_SUFFIX="-Windows-Windows_10-MSVC2017-Windows-Windows_10-X86_64.7z"
|
||||
QT_VER_MSVC_UP=$(echo ${QT_VER_MSVC} | tr '[:lower:]' '[:upper:]')
|
||||
QT_PREFIX="online/qtsdkrepository/windows_x86/desktop/qt${QT_VER_MAIN}_${QT_URL_VER}/qt.qt${QT_VER_MAIN}.${QT_URL_VER}.win64_${QT_VER_MSVC}_64/${QT_VER}-0-${QT_DATE}"
|
||||
QT_SUFFIX="-Windows-Windows_10-${QT_VER_MSVC_UP}-Windows-Windows_10-X86_64.7z"
|
||||
QT_BASE_URL="${QT_HOST}${QT_PREFIX}qtbase${QT_SUFFIX}"
|
||||
QT_WINE_URL="${QT_HOST}${QT_PREFIX}qtwinextras${QT_SUFFIX}"
|
||||
QT_DECL_URL="${QT_HOST}${QT_PREFIX}qtdeclarative${QT_SUFFIX}"
|
||||
QT_TOOL_URL="${QT_HOST}${QT_PREFIX}qttools${QT_SUFFIX}"
|
||||
LLVMLIBS_URL='https://github.com/RPCS3/llvm-mirror/releases/download/custom-build-win/llvmlibs_mt.7z'
|
||||
#GLSLANG_URL='https://github.com/RPCS3/glslang/releases/download/custom-build-win/glslanglibs_mt.7z' <- Temporarily disabled auto-builds
|
||||
GLSLANG_URL='https://www.dropbox.com/s/cg48qr4zmnn066v/glslanglibs_mt.7z'
|
||||
VULKAN_SDK_URL="https://www.dropbox.com/s/adanclixregbp2x/VulkanSDK-${VULKAN_VER}-Installer.exe"
|
||||
GLSLANG_URL='https://github.com/RPCS3/glslang/releases/download/custom-build-win/glslanglibs_mt.7z'
|
||||
VULKAN_SDK_URL="https://www.dropbox.com/s/kn005de7gsv5whe/VulkanSDK-1.2.154.1-Installer.exe"
|
||||
|
||||
DEP_URLS=" \
|
||||
$QT_BASE_URL \
|
||||
@@ -76,8 +76,7 @@ for url in $DEP_URLS; do
|
||||
case "$url" in
|
||||
*qt*) checksum=$(curl -L "${url}.sha1"); algo="sha1"; outDir='C:\Qt\' ;;
|
||||
*llvm*) checksum=$(curl -L "${url}.sha256"); algo="sha256"; outDir="." ;;
|
||||
#*glslang*) checksum=$(curl -L "${url}.sha256"); algo="sha256"; outDir="./lib/Release - LLVM-x64" ;; <- Temporarily disabled auto-build
|
||||
*glslang*) checksum=$(curl -L 'https://www.dropbox.com/s/hwnatk68n70jap0/glslanglibs_mt.7z.sha256'); algo="sha256"; outDir="./lib/Release - LLVM-x64" ;;
|
||||
*glslang*) checksum=$(curl -L "${url}.sha256"); algo="sha256"; outDir="./lib/Release - LLVM-x64" ;;
|
||||
*Vulkan*)
|
||||
# Vulkan setup needs to be run in batch environment
|
||||
# Need to subshell this or else it doesn't wait
|
||||
|
||||
+2
-2
@@ -3,9 +3,9 @@ env:
|
||||
|
||||
freebsd_task:
|
||||
matrix:
|
||||
- name: FreeBSD 12.2 (snapshot)
|
||||
- name: FreeBSD 12.2
|
||||
freebsd_instance:
|
||||
image_family: freebsd-12-1-snap
|
||||
image_family: freebsd-12-2
|
||||
cpu: 8
|
||||
memory: 8G
|
||||
env:
|
||||
|
||||
+11
-11
@@ -1,20 +1,20 @@
|
||||
Standard: Cpp11
|
||||
Standard: c++20
|
||||
UseTab: ForIndentation
|
||||
TabWidth: 1
|
||||
IndentWidth: 1
|
||||
AccessModifierOffset: -1
|
||||
TabWidth: 4
|
||||
IndentWidth: 4
|
||||
AccessModifierOffset: -4
|
||||
PointerAlignment: Left
|
||||
NamespaceIndentation: All
|
||||
ColumnLimit: 200
|
||||
ColumnLimit: 0
|
||||
BreakBeforeBraces: Allman
|
||||
BreakConstructorInitializersBeforeComma: true
|
||||
BreakBeforeBinaryOperators: false
|
||||
BreakConstructorInitializers: BeforeColon
|
||||
BreakBeforeBinaryOperators: None
|
||||
BreakBeforeTernaryOperators: false
|
||||
AlwaysBreakTemplateDeclarations: true
|
||||
AllowShortIfStatementsOnASingleLine: false
|
||||
AllowShortBlocksOnASingleLine: false
|
||||
AlwaysBreakTemplateDeclarations: Yes
|
||||
AllowShortIfStatementsOnASingleLine: Never
|
||||
AllowShortBlocksOnASingleLine: Never
|
||||
AllowShortCaseLabelsOnASingleLine: true
|
||||
AllowShortFunctionsOnASingleLine: false
|
||||
AllowShortFunctionsOnASingleLine: Empty
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
Cpp11BracedListStyle: true
|
||||
IndentCaseLabels: false
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
root = true
|
||||
|
||||
[*.{h,cpp,hpp}]
|
||||
charset = utf-8-bom
|
||||
charset = utf-8
|
||||
indent_style = tab
|
||||
indent_size = 4
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
## How to test a PR build
|
||||
|
||||
Please take into account, that RPCS3 build usually takes some time (about 20 min), so you can't access a build, if a PR was just submitted.
|
||||
|
||||
- Open a PR you want to test
|
||||
- Scroll to the very bottom and locate "Checks" section
|
||||
- Expand all checks
|
||||
You are supposed to see something like this
|
||||

|
||||
- Click on **Linux_Build** or **Windows_Build** __Details__
|
||||
- Click **View more details on Azure Pipelines** at the very bottom
|
||||

|
||||
- Click on *1 artifact produced*
|
||||

|
||||
- Select a build for your OS and click three dots on the right, Click **Download artifacts**
|
||||

|
||||
|
||||
- Congratulations! You are now downloading RPCS3 build for specific PR.
|
||||
|
||||
Please note, that PR builds are not supposed to be stable, because they contain new changesets.
|
||||
@@ -0,0 +1,3 @@
|
||||
<!-- Please include a summary of the change and which issue is fixed. -->
|
||||
|
||||
[How to test this PR](.github/PR-BUILD.md)
|
||||
+2
-2
@@ -65,11 +65,11 @@
|
||||
ignore = dirty
|
||||
[submodule "3rdparty/curl"]
|
||||
path = 3rdparty/curl
|
||||
url = https://github.com/RipleyTom/curl.git
|
||||
url = https://github.com/curl/curl.git
|
||||
ignore = dirty
|
||||
[submodule "3rdparty/wolfssl"]
|
||||
path = 3rdparty/wolfssl
|
||||
url = https://github.com/RipleyTom/wolfssl.git
|
||||
url = https://github.com/wolfSSL/wolfssl.git
|
||||
ignore = dirty
|
||||
[submodule "3rdparty/flatbuffers"]
|
||||
path = 3rdparty/flatbuffers
|
||||
|
||||
-46
@@ -1,46 +0,0 @@
|
||||
language: cpp
|
||||
jobs:
|
||||
include:
|
||||
- os: linux
|
||||
dist: xenial
|
||||
env:
|
||||
- NAME="Linux build"
|
||||
- COMPILER="gcc"
|
||||
- DEPLOY_APPIMAGE="true"
|
||||
services: docker
|
||||
cache: ccache
|
||||
compiler: gcc
|
||||
install: "docker pull rpcs3/rpcs3-travis-xenial:1.5"
|
||||
script: 'travis_wait docker run -v $(pwd):/rpcs3 -v "$HOME/.ccache":/root/.ccache --env-file .ci/travis.env rpcs3/rpcs3-travis-xenial:1.5 /rpcs3/.ci/build-linux.sh'
|
||||
- os: linux
|
||||
dist: xenial
|
||||
env:
|
||||
- NAME="Linux build"
|
||||
- COMPILER="clang"
|
||||
services: docker
|
||||
cache: ccache
|
||||
compiler: clang
|
||||
install: "docker pull rpcs3/rpcs3-travis-xenial:1.5"
|
||||
script: 'travis_wait docker run -v $(pwd):/rpcs3 -v "$HOME/.ccache":/root/.ccache --env-file .ci/travis.env rpcs3/rpcs3-travis-xenial:1.5 /rpcs3/.ci/build-linux.sh'
|
||||
# - os: freebsd
|
||||
# compiler: clang
|
||||
# cache: ccache
|
||||
# install: "./.ci/install-freebsd.sh"
|
||||
# script: "./.ci/build-freebsd.sh"
|
||||
# - os: osx
|
||||
# osx_image: xcode11.3
|
||||
# addons:
|
||||
# homebrew:
|
||||
# packages:
|
||||
# - ccache
|
||||
# - glew
|
||||
# - ninja
|
||||
# - qt
|
||||
# script: "/bin/bash -ex .ci/build-mac.sh"
|
||||
# cache: ccache
|
||||
allow_failures:
|
||||
- os: osx
|
||||
|
||||
git:
|
||||
depth: false # Unshallow clone to obtain proper GIT_VERSION
|
||||
submodules: false
|
||||
Vendored
+67
-17
@@ -106,6 +106,36 @@ endif()
|
||||
add_subdirectory(pugixml EXCLUDE_FROM_ALL)
|
||||
|
||||
|
||||
# libusb
|
||||
if(CMAKE_SYSTEM MATCHES "DragonFly|FreeBSD")
|
||||
pkg_check_modules(LIBUSB REQUIRED IMPORTED_TARGET libusb-1.0>=1.0 )
|
||||
CMAKE_DEPENDENT_OPTION( USE_SYS_LIBUSB "Use system libusb-1.0 as shared library" ON
|
||||
"LIBUSB_FOUND" OFF)
|
||||
else()
|
||||
pkg_check_modules(LIBUSB IMPORTED_TARGET libusb-1.0>=1.0 )
|
||||
CMAKE_DEPENDENT_OPTION( USE_SYS_LIBUSB "Use system libusb-1.0 as shared library" OFF
|
||||
"LIBUSB_FOUND" OFF)
|
||||
endif()
|
||||
if(CMAKE_SYSTEM MATCHES "DragonFly|FreeBSD")
|
||||
# Always use system libusb as reference implementation isn't supported
|
||||
add_library(usb-1.0-shared INTERFACE)
|
||||
target_link_libraries(usb-1.0-shared INTERFACE PkgConfig::LIBUSB)
|
||||
elseif(MSVC)
|
||||
# Windows time.h defines timespec but doesn't add any flag for it, which makes libusb attempt to define it again
|
||||
add_definitions(-DHAVE_STRUCT_TIMESPEC=1)
|
||||
add_subdirectory(libusb_cmake EXCLUDE_FROM_ALL)
|
||||
else()
|
||||
if(USE_SYS_LIBUSB)
|
||||
# we have the system libusb and have selected to use it
|
||||
add_library(usb-1.0-shared INTERFACE)
|
||||
target_link_libraries(usb-1.0-shared INTERFACE PkgConfig::LIBUSB)
|
||||
else()
|
||||
# we don't have the system libusb, so we compile from submodule
|
||||
add_subdirectory(libusb_cmake EXCLUDE_FROM_ALL)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
||||
# hidapi
|
||||
add_library(3rdparty_hidapi INTERFACE)
|
||||
target_include_directories(3rdparty_hidapi INTERFACE hidapi/hidapi)
|
||||
@@ -133,24 +163,11 @@ else()
|
||||
endif()
|
||||
|
||||
|
||||
# libusb
|
||||
if(CMAKE_SYSTEM MATCHES "DragonFly|FreeBSD")
|
||||
# Always use system libusb as reference implementation isn't supported
|
||||
add_library(usb-1.0-static INTERFACE)
|
||||
target_link_libraries(usb-1.0-static INTERFACE usb)
|
||||
elseif(MSVC)
|
||||
# Windows time.h defines timespec but doesn't add any flag for it, which makes libusb attempt to define it again
|
||||
add_definitions(-DHAVE_STRUCT_TIMESPEC=1)
|
||||
add_subdirectory(libusb_cmake EXCLUDE_FROM_ALL)
|
||||
else()
|
||||
add_subdirectory(libusb_cmake EXCLUDE_FROM_ALL)
|
||||
endif()
|
||||
|
||||
|
||||
# yaml-cpp
|
||||
# We don't want to install yaml-cpp but its cmake file doesn't have option
|
||||
# to disable it...
|
||||
# So we just install it to a different directory
|
||||
set(YAML_CPP_INSTALL OFF CACHE BOOL "Don't install YAML")
|
||||
set(CMAKE_INSTALL_PREFIX_OLD ${CMAKE_INSTALL_PREFIX})
|
||||
set(CMAKE_INSTALL_PREFIX ${CMAKE_BINARY_DIR}/yaml-cpp_install)
|
||||
|
||||
@@ -164,6 +181,7 @@ set(CMAKE_INSTALL_PREFIX ${CMAKE_INSTALL_PREFIX_OLD})
|
||||
|
||||
# xxHash
|
||||
set(XXHASH_BUNDLED_MODE ON)
|
||||
set(XXHASH_BUILD_XXHSUM OFF)
|
||||
set(BUILD_SHARED_LIBS OFF CACHE BOOL "Make xxHash build static libs")
|
||||
add_subdirectory(xxHash/cmake_unofficial EXCLUDE_FROM_ALL)
|
||||
target_include_directories(xxhash INTERFACE xxHash)
|
||||
@@ -417,7 +435,30 @@ endif()
|
||||
include(llvm.cmake)
|
||||
|
||||
# WOLFSSL
|
||||
add_subdirectory(wolfssl EXCLUDE_FROM_ALL)
|
||||
if(USE_SYSTEM_WOLFSSL)
|
||||
message("-- RPCS3: using shared wolfssl")
|
||||
find_package(WolfSSL REQUIRED)
|
||||
add_library(wolfssl INTERFACE)
|
||||
target_link_libraries(wolfssl INTERFACE WolfSSL_LIBRARIES)
|
||||
target_include_directories(wolfssl INTERFACE WolfSSL_INCLUDE_DIRS)
|
||||
else()
|
||||
SET(BUILD_TESTS NO CACHE BOOL "Build test applications")
|
||||
add_compile_definitions(HAVE_FFDHE_2048 TFM_TIMING_RESISTANT ECC_TIMING_RESISTANT
|
||||
WC_RSA_BLINDING HAVE_AESGCM WOLFSSL_SHA512 WOLFSSL_SHA384 NO_DSA HAVE_ECC TFM_ECC256 ECC_SHAMIR
|
||||
NO_RC4 NO_HC128 NO_RABBIT WOLFSSL_SHA224 WOLFSSL_SHA3 WOLFSSL_SHAKE256 HAVE_POLY1305
|
||||
HAVE_ONE_TIME_AUTH HAVE_CHACHA HAVE_HASHDRBG HAVE_TLS_EXTENSIONS HAVE_SNI HAVE_SUPPORTED_CURVES
|
||||
HAVE_EXTENDED_MASTER NO_RC4 HAVE_ENCRYPT_THEN_MAC NO_PSK NO_MD4
|
||||
WC_NO_ASYNC_THREADING OPENSSL_EXTRA WOLFSSL_DES_ECB WC_NO_HARDEN)
|
||||
set(ENABLED_HARDEN OFF CACHE BOOL "Disable Harden")
|
||||
add_subdirectory(wolfssl EXCLUDE_FROM_ALL)
|
||||
target_include_directories(wolfssl INTERFACE "wolfssl/")
|
||||
# This is needed for CURL
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/wolfssl/wolfssl/options.h.in ${CMAKE_CURRENT_BINARY_DIR}/wolfssl/wolfssl/options.h)
|
||||
set(WolfSSL_LIBRARY "${CMAKE_CURRENT_BINARY_DIR}/wolfssl/libwolfssl.a")
|
||||
set(WolfSSL_LIBRARIES "${CMAKE_CURRENT_BINARY_DIR}/wolfssl/libwolfssl.a")
|
||||
set(WolfSSL_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/wolfssl/" "${CMAKE_CURRENT_BINARY_DIR}/wolfssl/")
|
||||
set(WolfSSL_INCLUDE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/wolfssl/" "${CMAKE_CURRENT_BINARY_DIR}/wolfssl/")
|
||||
endif()
|
||||
|
||||
# CURL
|
||||
if(USE_SYSTEM_CURL)
|
||||
@@ -427,11 +468,20 @@ if(USE_SYSTEM_CURL)
|
||||
target_link_libraries(libcurl INTERFACE CURL::libcurl)
|
||||
else()
|
||||
message("-- RPCS3: building libcurl + wolfssl submodules")
|
||||
option(BUILD_CURL_EXE "Set to ON to build curl executable." OFF)
|
||||
option(CMAKE_USE_WOLFSSL "enable wolfSSL for SSL/TLS" ON)
|
||||
option(HTTP_ONLY "disables all protocols except HTTP (This overrides all CURL_DISABLE_* options)" ON)
|
||||
option(CURL_ZLIB "Set to ON to enable building curl with zlib support." OFF)
|
||||
set(CURL_CA_PATH "none" CACHE STRING "Location of default CA path. Set 'none' to disable or 'auto' for auto-detection. Defaults to 'auto'.")
|
||||
add_subdirectory(curl EXCLUDE_FROM_ALL)
|
||||
endif()
|
||||
|
||||
# add nice ALIAS targets for ease of use
|
||||
add_library(3rdparty::libusb ALIAS usb-1.0-static)
|
||||
if(USE_SYS_LIBUSB)
|
||||
add_library(3rdparty::libusb ALIAS usb-1.0-shared)
|
||||
else()
|
||||
add_library(3rdparty::libusb ALIAS usb-1.0-static)
|
||||
endif()
|
||||
add_library(3rdparty::zlib ALIAS 3rdparty_zlib)
|
||||
add_library(3rdparty::7z ALIAS 3rdparty_7z)
|
||||
add_library(3rdparty::flatbuffers ALIAS 3rdparty_flatbuffers)
|
||||
@@ -453,5 +503,5 @@ add_library(3rdparty::vulkan ALIAS ${VULKAN_TARGET})
|
||||
add_library(3rdparty::openal ALIAS 3rdparty_openal)
|
||||
add_library(3rdparty::ffmpeg ALIAS 3rdparty_ffmpeg)
|
||||
add_library(3rdparty::glew ALIAS 3rdparty_glew)
|
||||
add_library(3rdparty::wolfssl ALIAS wolfssl-3-static)
|
||||
add_library(3rdparty::wolfssl ALIAS wolfssl)
|
||||
add_library(3rdparty::libcurl ALIAS libcurl)
|
||||
|
||||
Vendored
+1
-1
Submodule 3rdparty/curl updated: aa1a12cb23...9d954e49bc
+40
@@ -0,0 +1,40 @@
|
||||
/* options.h.in
|
||||
*
|
||||
* Copyright (C) 2006-2020 wolfSSL Inc.
|
||||
*
|
||||
* This file is part of wolfSSL.
|
||||
*
|
||||
* wolfSSL is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* wolfSSL is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
|
||||
*/
|
||||
|
||||
|
||||
/* default blank options for autoconf */
|
||||
|
||||
#ifndef WOLFSSL_OPTIONS_H
|
||||
#define WOLFSSL_OPTIONS_H
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* WOLFSSL_OPTIONS_H */
|
||||
|
||||
Vendored
+1
-1
Submodule 3rdparty/hidapi updated: 9220f5e77c...8961cf86eb
Vendored
+13
-2
@@ -51,8 +51,8 @@
|
||||
<ClCompile>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
|
||||
<AdditionalIncludeDirectories>curl\include;curl\lib;wolfssl;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>HAVE_SNI;NDEBUG;BUILDING_LIBCURL;CURL_STATICLIB;USE_WOLFSSL;USE_IPV6;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>curl\include;curl\lib;curl_extra;wolfssl;wolfssl\wolfssl;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>HAVE_SNI;NDEBUG;BUILDING_LIBCURL;CURL_STATICLIB;USE_WOLFSSL;USE_IPV6;SIZEOF_LONG=4;SIZEOF_LONG_LONG=8;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<StringPooling>true</StringPooling>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
@@ -97,6 +97,7 @@
|
||||
<ClCompile Include="curl\lib\dict.c" />
|
||||
<ClCompile Include="curl\lib\doh.c" />
|
||||
<ClCompile Include="curl\lib\dotdot.c" />
|
||||
<ClCompile Include="curl\lib\dynbuf.c" />
|
||||
<ClCompile Include="curl\lib\easy.c" />
|
||||
<ClCompile Include="curl\lib\escape.c" />
|
||||
<ClCompile Include="curl\lib\file.c" />
|
||||
@@ -135,6 +136,7 @@
|
||||
<ClCompile Include="curl\lib\memdebug.c" />
|
||||
<ClCompile Include="curl\lib\mime.c" />
|
||||
<ClCompile Include="curl\lib\mprintf.c" />
|
||||
<ClCompile Include="curl\lib\mqtt.c" />
|
||||
<ClCompile Include="curl\lib\multi.c" />
|
||||
<ClCompile Include="curl\lib\netrc.c" />
|
||||
<ClCompile Include="curl\lib\non-ascii.c" />
|
||||
@@ -178,6 +180,7 @@
|
||||
<ClCompile Include="curl\lib\url.c" />
|
||||
<ClCompile Include="curl\lib\urlapi.c" />
|
||||
<ClCompile Include="curl\lib\version.c" />
|
||||
<ClCompile Include="curl\lib\version_win32.c" />
|
||||
<ClCompile Include="curl\lib\warnless.c" />
|
||||
<ClCompile Include="curl\lib\wildcard.c" />
|
||||
<ClCompile Include="curl\lib\x509asn1.c" />
|
||||
@@ -195,12 +198,14 @@
|
||||
<ClCompile Include="curl\lib\vauth\vauth.c" />
|
||||
<ClCompile Include="curl\lib\vquic\ngtcp2.c" />
|
||||
<ClCompile Include="curl\lib\vquic\quiche.c" />
|
||||
<ClCompile Include="curl\lib\vquic\vquic.c" />
|
||||
<ClCompile Include="curl\lib\vssh\libssh.c" />
|
||||
<ClCompile Include="curl\lib\vssh\libssh2.c" />
|
||||
<ClCompile Include="curl\lib\vssh\wolfssh.c" />
|
||||
<ClCompile Include="curl\lib\vtls\bearssl.c" />
|
||||
<ClCompile Include="curl\lib\vtls\gskit.c" />
|
||||
<ClCompile Include="curl\lib\vtls\gtls.c" />
|
||||
<ClCompile Include="curl\lib\vtls\keylog.c" />
|
||||
<ClCompile Include="curl\lib\vtls\mbedtls.c" />
|
||||
<ClCompile Include="curl\lib\vtls\mbedtls_threadlock.c" />
|
||||
<ClCompile Include="curl\lib\vtls\mesalink.c" />
|
||||
@@ -274,6 +279,7 @@
|
||||
<ClInclude Include="curl\lib\dict.h" />
|
||||
<ClInclude Include="curl\lib\doh.h" />
|
||||
<ClInclude Include="curl\lib\dotdot.h" />
|
||||
<ClInclude Include="curl\lib\dynbuf.h" />
|
||||
<ClInclude Include="curl\lib\easyif.h" />
|
||||
<ClInclude Include="curl\lib\escape.h" />
|
||||
<ClInclude Include="curl\lib\file.h" />
|
||||
@@ -300,6 +306,7 @@
|
||||
<ClInclude Include="curl\lib\llist.h" />
|
||||
<ClInclude Include="curl\lib\memdebug.h" />
|
||||
<ClInclude Include="curl\lib\mime.h" />
|
||||
<ClInclude Include="curl\lib\mqtt.h" />
|
||||
<ClInclude Include="curl\lib\multihandle.h" />
|
||||
<ClInclude Include="curl\lib\multiif.h" />
|
||||
<ClInclude Include="curl\lib\netrc.h" />
|
||||
@@ -319,6 +326,7 @@
|
||||
<ClInclude Include="curl\lib\setopt.h" />
|
||||
<ClInclude Include="curl\lib\setup-os400.h" />
|
||||
<ClInclude Include="curl\lib\setup-vms.h" />
|
||||
<ClInclude Include="curl\lib\setup-win32.h" />
|
||||
<ClInclude Include="curl\lib\share.h" />
|
||||
<ClInclude Include="curl\lib\sigpipe.h" />
|
||||
<ClInclude Include="curl\lib\slist.h" />
|
||||
@@ -342,6 +350,7 @@
|
||||
<ClInclude Include="curl\lib\url.h" />
|
||||
<ClInclude Include="curl\lib\urlapi-int.h" />
|
||||
<ClInclude Include="curl\lib\urldata.h" />
|
||||
<ClInclude Include="curl\lib\version_win32.h" />
|
||||
<ClInclude Include="curl\lib\warnless.h" />
|
||||
<ClInclude Include="curl\lib\wildcard.h" />
|
||||
<ClInclude Include="curl\lib\x509asn1.h" />
|
||||
@@ -350,11 +359,13 @@
|
||||
<ClInclude Include="curl\lib\vauth\vauth.h" />
|
||||
<ClInclude Include="curl\lib\vquic\ngtcp2.h" />
|
||||
<ClInclude Include="curl\lib\vquic\quiche.h" />
|
||||
<ClInclude Include="curl\lib\vquic\vquic.h" />
|
||||
<ClInclude Include="curl\lib\vssh\ssh.h" />
|
||||
<ClInclude Include="curl\lib\vssh\wolfssh.h" />
|
||||
<ClInclude Include="curl\lib\vtls\bearssl.h" />
|
||||
<ClInclude Include="curl\lib\vtls\gskit.h" />
|
||||
<ClInclude Include="curl\lib\vtls\gtls.h" />
|
||||
<ClInclude Include="curl\lib\vtls\keylog.h" />
|
||||
<ClInclude Include="curl\lib\vtls\mbedtls.h" />
|
||||
<ClInclude Include="curl\lib\vtls\mbedtls_threadlock.h" />
|
||||
<ClInclude Include="curl\lib\vtls\mesalink.h" />
|
||||
|
||||
Vendored
+1
-1
Submodule 3rdparty/libusb updated: e782eeb251...c33990a300
Vendored
+7
-4
@@ -6,6 +6,7 @@ if (CMAKE_USE_PTHREADS_INIT)
|
||||
endif()
|
||||
|
||||
if (WIN32 OR "${CMAKE_SYSTEM_NAME}" STREQUAL "CYGWIN")
|
||||
add_compile_definitions(PLATFORM_WINDOWS=1)
|
||||
set(OS_WINDOWS 1 CACHE INTERNAL "controls config.h macro definition" FORCE)
|
||||
|
||||
# Enable MingW support for RC language (for CMake pre-2.8)
|
||||
@@ -22,9 +23,9 @@ if (WIN32 OR "${CMAKE_SYSTEM_NAME}" STREQUAL "CYGWIN")
|
||||
endif()
|
||||
|
||||
list(APPEND PLATFORM_SRC
|
||||
poll_windows.c
|
||||
events_windows.c
|
||||
windows_usbdk.c
|
||||
windows_nt_common.c
|
||||
windows_common.c
|
||||
windows_winusb.c
|
||||
threads_windows.c
|
||||
)
|
||||
@@ -36,13 +37,14 @@ if (WIN32 OR "${CMAKE_SYSTEM_NAME}" STREQUAL "CYGWIN")
|
||||
endif()
|
||||
elseif (APPLE)
|
||||
# Apple != OSX alone
|
||||
add_compile_definitions(PLATFORM_POSIX=1 HAVE_CLOCK_GETTIME)
|
||||
set(OS_DARWIN 1 CACHE INTERNAL "controls config.h macro definition" FORCE)
|
||||
|
||||
if ("${CMAKE_SYSTEM_NAME}" STREQUAL "Darwin")
|
||||
set(PLATFORM_SRC
|
||||
darwin_usb.c
|
||||
threads_posix.c
|
||||
poll_posix.c
|
||||
events_posix.c
|
||||
)
|
||||
|
||||
find_package(IOKit REQUIRED)
|
||||
@@ -72,6 +74,7 @@ int main()
|
||||
endif()
|
||||
elseif (UNIX)
|
||||
# Unix is for all *NIX systems including OSX
|
||||
add_compile_definitions(PLATFORM_POSIX=1 HAVE_CLOCK_GETTIME)
|
||||
if ("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux")
|
||||
set(OS_LINUX 1 CACHE INTERNAL "controls config.h macro definition" FORCE)
|
||||
|
||||
@@ -79,7 +82,7 @@ elseif (UNIX)
|
||||
linux_usbfs.c
|
||||
linux_netlink.c
|
||||
threads_posix.c
|
||||
poll_posix.c
|
||||
events_posix.c
|
||||
)
|
||||
|
||||
list(APPEND LIBUSB_LIBRARIES rt)
|
||||
|
||||
Vendored
+5
-6
@@ -41,8 +41,9 @@
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup>
|
||||
<ClCompile>
|
||||
<AdditionalOptions>/utf-8 %(AdditionalOptions)</AdditionalOptions>
|
||||
<AdditionalIncludeDirectories>libusb\msvc;libusb\libusb;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>WINVER=0x0501;_WIN32_WINNT=0x0501;_LIB;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>WINVER=0x0600;_WIN32_WINNT=0x0600;_LIB;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
</ClCompile>
|
||||
@@ -64,11 +65,11 @@
|
||||
<ClCompile Include="libusb\libusb\descriptor.c" />
|
||||
<ClCompile Include="libusb\libusb\hotplug.c" />
|
||||
<ClCompile Include="libusb\libusb\io.c" />
|
||||
<ClCompile Include="libusb\libusb\os\poll_windows.c" />
|
||||
<ClCompile Include="libusb\libusb\os\events_windows.c" />
|
||||
<ClCompile Include="libusb\libusb\strerror.c" />
|
||||
<ClCompile Include="libusb\libusb\sync.c" />
|
||||
<ClCompile Include="libusb\libusb\os\threads_windows.c" />
|
||||
<ClCompile Include="libusb\libusb\os\windows_nt_common.c" />
|
||||
<ClCompile Include="libusb\libusb\os\windows_common.c" />
|
||||
<ClCompile Include="libusb\libusb\os\windows_usbdk.c" />
|
||||
<ClCompile Include="libusb\libusb\os\windows_winusb.c" />
|
||||
</ItemGroup>
|
||||
@@ -77,13 +78,11 @@
|
||||
<ClInclude Include="libusb\libusb\hotplug.h" />
|
||||
<ClInclude Include="libusb\libusb\libusb.h" />
|
||||
<ClInclude Include="libusb\libusb\libusbi.h" />
|
||||
<ClInclude Include="libusb\libusb\os\poll_windows.h" />
|
||||
<ClInclude Include="libusb\libusb\os\events_windows.h" />
|
||||
<ClInclude Include="libusb\libusb\os\threads_windows.h" />
|
||||
<ClInclude Include="libusb\libusb\version.h" />
|
||||
<ClInclude Include="libusb\libusb\version_nano.h" />
|
||||
<ClInclude Include="libusb\libusb\os\windows_common.h" />
|
||||
<ClInclude Include="libusb\libusb\os\windows_nt_common.h" />
|
||||
<ClInclude Include="libusb\libusb\os\windows_nt_shared_types.h" />
|
||||
<ClInclude Include="libusb\libusb\os\windows_usbdk.h" />
|
||||
<ClInclude Include="libusb\libusb\os\windows_winusb.h" />
|
||||
</ItemGroup>
|
||||
|
||||
Vendored
-1
@@ -11,7 +11,6 @@ if(WITH_LLVM)
|
||||
option(LLVM_INCLUDE_TESTS OFF)
|
||||
option(LLVM_INCLUDE_TOOLS OFF)
|
||||
option(LLVM_INCLUDE_UTILS OFF)
|
||||
option(WITH_POLLY OFF)
|
||||
option(LLVM_CCACHE_BUILD ON)
|
||||
|
||||
set(CXX_FLAGS_OLD ${CMAKE_CXX_FLAGS})
|
||||
|
||||
Vendored
+9
-11
@@ -1,11 +1,13 @@
|
||||
add_library(3rdparty_qt5 INTERFACE)
|
||||
|
||||
find_package(Qt5 5.14 CONFIG COMPONENTS Widgets Concurrent)
|
||||
set(QT_MIN_VER 5.15.2)
|
||||
|
||||
find_package(Qt5 ${QT_MIN_VER} CONFIG COMPONENTS Widgets Concurrent)
|
||||
if(WIN32)
|
||||
find_package(Qt5 5.14 COMPONENTS WinExtras REQUIRED)
|
||||
find_package(Qt5 ${QT_MIN_VER} COMPONENTS WinExtras REQUIRED)
|
||||
target_link_libraries(3rdparty_qt5 INTERFACE Qt5::Widgets Qt5::WinExtras Qt5::Concurrent)
|
||||
else()
|
||||
find_package(Qt5 5.14 COMPONENTS DBus Gui)
|
||||
find_package(Qt5 ${QT_MIN_VER} COMPONENTS DBus Gui)
|
||||
if(Qt5DBus_FOUND)
|
||||
target_link_libraries(3rdparty_qt5 INTERFACE Qt5::Widgets Qt5::DBus Qt5::Concurrent)
|
||||
target_compile_definitions(3rdparty_qt5 INTERFACE -DHAVE_QTDBUS)
|
||||
@@ -16,16 +18,12 @@ else()
|
||||
endif()
|
||||
|
||||
if(NOT Qt5Widgets_FOUND)
|
||||
if(Qt5Widgets_VERSION VERSION_LESS 5.14.0)
|
||||
message("Minimum supported Qt5 version is 5.14.0! You have version ${Qt5Widgets_VERSION} installed, please upgrade!")
|
||||
if(Qt5Widgets_VERSION VERSION_LESS ${QT_MIN_VER})
|
||||
message("Minimum supported Qt5 version is ${QT_MIN_VER}! You have version ${Qt5Widgets_VERSION} installed, please upgrade!")
|
||||
if(CMAKE_SYSTEM MATCHES "Linux")
|
||||
message(FATAL_ERROR "Most distros do not provide an up-to-date version of Qt.
|
||||
If you're on Ubuntu or Linux Mint, there are PPAs you can use to install one of the latest qt5 versions.
|
||||
https://launchpad.net/~beineri/+archive/ubuntu/opt-qt-5.14.1-bionic
|
||||
https://launchpad.net/~beineri/+archive/ubuntu/opt-qt-5.14.1-xenial
|
||||
just make sure to run
|
||||
source /opt/qt514/bin/qt514-env.sh
|
||||
before re-running cmake")
|
||||
Find the correct ppa at https://launchpad.net/~beineri and follow the instructions.")
|
||||
elseif(WIN32)
|
||||
message(FATAL_ERROR "You can download the latest version of Qt5 here: https://www.qt.io/download-open-source/")
|
||||
else()
|
||||
@@ -35,7 +33,7 @@ before re-running cmake")
|
||||
|
||||
message("CMake was unable to find Qt5!")
|
||||
if(WIN32)
|
||||
message(FATAL_ERROR "Make sure the QTDIR env variable has been set properly. (for example C:\\Qt\\5.14.1\\msvc2017_64\\)
|
||||
message(FATAL_ERROR "Make sure the QTDIR env variable has been set properly. (for example C:\\Qt\\${QT_MIN_VER}\\msvc2019_64\\)
|
||||
You can also try setting the Qt5_DIR preprocessor definiton.")
|
||||
elseif(CMAKE_SYSTEM MATCHES "Linux")
|
||||
message(FATAL_ERROR "Make sure to install your distro's qt5 package!")
|
||||
|
||||
Vendored
+1
-1
Submodule 3rdparty/wolfssl updated: d0749c6549...39b5448601
Vendored
+2
-2
@@ -48,7 +48,7 @@
|
||||
<ClCompile>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<AdditionalIncludeDirectories>./wolfssl;./wolfssl/IDE/WIN;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>WOLFSSL_LIB;WOLFSSL_USER_SETTINGS;CYASSL_USER_SETTINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>WOLFSSL_LIB;WOLFSSL_DES_ECB;HAVE_FFDHE_2048;TFM_TIMING_RESISTANT;ECC_TIMING_RESISTANT;WC_RSA_BLINDING;HAVE_AESGCM;WOLFSSL_SHA512;WOLFSSL_SHA384;NO_DSA;HAVE_ECC;TFM_ECC256;ECC_SHAMIR;NO_RC4;NO_HC128;NO_RABBIT;WOLFSSL_SHA224;WOLFSSL_SHA3;WOLFSSL_SHAKE256;HAVE_POLY1305;HAVE_ONE_TIME_AUTH;HAVE_CHACHA;HAVE_HASHDRBG;HAVE_TLS_EXTENSIONS;HAVE_SNI;HAVE_SUPPORTED_CURVES;HAVE_EXTENDED_MASTER;NO_RC4;HAVE_ENCRYPT_THEN_MAC;NO_PSK;NO_MD4;WC_NO_ASYNC_THREADING;OPENSSL_EXTRA;WOLFSSL_USER_SETTINGS;CYASSL_USER_SETTINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
@@ -62,7 +62,7 @@
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<AdditionalIncludeDirectories>./wolfssl;./wolfssl/IDE/WIN;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>WOLFSSL_LIB;WOLFSSL_USER_SETTINGS;CYASSL_USER_SETTINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>WOLFSSL_LIB;WOLFSSL_DES_ECB;HAVE_FFDHE_2048;TFM_TIMING_RESISTANT;NO_DSA;TFM_ECC256;NO_RC4;NO_HC128;NO_RABBIT;WOLFSSL_SHA224;WOLFSSL_SHA3;WOLFSSL_SHAKE256;HAVE_POLY1305;HAVE_ONE_TIME_AUTH;HAVE_CHACHA;HAVE_HASHDRBG;HAVE_SNI;HAVE_ENCRYPT_THEN_MAC;NO_MD4;WC_NO_ASYNC_THREADING;WOLFSSL_USER_SETTINGS;CYASSL_USER_SETTINGS;WC_NO_HARDEN;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
|
||||
Vendored
+1
-1
Submodule 3rdparty/xxHash updated: 7cc9639699...94e5f23e73
+15
-15
@@ -9,19 +9,19 @@ Other instructions may be found [here](https://wiki.rpcs3.net/index.php?title=Bu
|
||||
|
||||
* [CMake 3.14.1+](https://www.cmake.org/download/) (add to PATH)
|
||||
* [Python 3.3+](https://www.python.org/downloads/) (add to PATH)
|
||||
* [Qt 5.14.2](https://www.qt.io/download-qt-installer)
|
||||
* [Qt 5.15.2](https://www.qt.io/download-qt-installer)
|
||||
* [Visual Studio 2019](https://visualstudio.microsoft.com/thank-you-downloading-visual-studio/?sku=Community)
|
||||
* [Vulkan SDK 1.1.126+](https://vulkan.lunarg.com/sdk/home) (See "Install the SDK" [here](https://vulkan.lunarg.com/doc/sdk/latest/windows/getting_started.html))
|
||||
|
||||
**Either add the** `QTDIR` **environment variable, e.g.** `<QtInstallFolder>\5.14.2\msvc2017_64\` **, or use the [Visual Studio Qt Plugin](https://marketplace.visualstudio.com/items?itemName=TheQtCompany.QtVisualStudioTools-19123)**
|
||||
**Either add the** `QTDIR` **environment variable, e.g.** `<QtInstallFolder>\5.15.2\msvc2019_64\` **, or use the [Visual Studio Qt Plugin](https://marketplace.visualstudio.com/items?itemName=TheQtCompany.QtVisualStudioTools2019)**
|
||||
|
||||
### Linux
|
||||
|
||||
These are the essentials tools to build RPCS3 on Linux. Some of them can be installed through your favorite package manager.
|
||||
|
||||
* Clang 9+ or GCC 9+
|
||||
* Clang 11+ or GCC 9+
|
||||
* [CMake 3.14.1+](https://www.cmake.org/download/)
|
||||
* [Qt 5.14.2](https://www.qt.io/download-qt-installer)
|
||||
* [Qt 5.15.2](https://www.qt.io/download-qt-installer)
|
||||
* [Vulkan SDK 1.1.126+](https://vulkan.lunarg.com/sdk/home) (See "Install the SDK" [here](https://vulkan.lunarg.com/doc/sdk/latest/linux/getting_started.html))
|
||||
* [SDL2](https://www.libsdl.org/download-2.0.php) (for the FAudio backend)
|
||||
|
||||
@@ -40,11 +40,11 @@ Ubuntu is usually horrendously out of date, and some packages need to be downloa
|
||||
|
||||
Ubuntu usually does not have a new enough Qt package to suit rpcs3's needs. There is a PPA available to work around this. Run the following:
|
||||
```
|
||||
ucodename=$(lsb_release -sc)
|
||||
sudo add-apt-repository ppa:beineri/opt-qt-5.14.2-$ucodename
|
||||
. /etc/os-release
|
||||
sudo add-apt-repository ppa:beineri/opt-qt-5.15.2-$UBUNTU_CODENAME
|
||||
sudo apt-get update
|
||||
. /opt/qt514/bin/qt514-env.sh >/dev/null 2>&1
|
||||
sudo apt-get install qt514-meta-minimal qt514svg
|
||||
sudo apt-get install qt515-meta-minimal qt515svg
|
||||
. /opt/qt515/bin/qt515-env.sh >/dev/null 2>&1
|
||||
```
|
||||
|
||||
##### GCC 9.x installation
|
||||
@@ -62,27 +62,27 @@ You can either use `update-alternatives` to setup `gcc-9`/`g++-9` as your defaul
|
||||
|
||||
For Ubuntu systems, it is strongly recommended to use the PPA from [LunarG](https://packages.lunarg.com/) which will provide a compatible Vulkan SDK to compile RPCS3. If your Vulkan SDK is older, it can lead to compilation errors.
|
||||
```
|
||||
ucodename=$(lsb_release -sc)
|
||||
wget -qO - http://packages.lunarg.com/lunarg-signing-key-pub.asc | sudo apt-key add -
|
||||
sudo wget -qO /etc/apt/sources.list.d/lunarg-vulkan-1.1.126-$ucodename.list http://packages.lunarg.com/vulkan/1.1.126/lunarg-vulkan-1.1.126-$ucodename.list
|
||||
. /etc/os-release
|
||||
wget -qO - https://packages.lunarg.com/lunarg-signing-key-pub.asc | sudo apt-key add -
|
||||
sudo wget -qO /etc/apt/sources.list.d/lunarg-vulkan-1.2.148-$UBUNTU_CODENAME.list https://packages.lunarg.com/vulkan/1.2.148/lunarg-vulkan-1.2.148-$UBUNTU_CODENAME.list
|
||||
sudo apt update
|
||||
sudo apt install vulkan-sdk
|
||||
```
|
||||
|
||||
##### CMake
|
||||
```
|
||||
. /etc/os-release
|
||||
wget -O - https://apt.kitware.com/keys/kitware-archive-latest.asc 2>/dev/null | sudo apt-key add -
|
||||
sudo apt-add-repository "deb https://apt.kitware.com/ubuntu/ $(lsb_release -sc) main"
|
||||
sudo apt-add-repository "deb https://apt.kitware.com/ubuntu/ $UBUNTU_CODENAME main"
|
||||
sudo apt-get update
|
||||
sudo apt-get install kitware-archive-keyring
|
||||
sudo apt-key --keyring /etc/apt/trusted.gpg del C1F34CDD40CD72DA
|
||||
sudo apt-get install cmake
|
||||
|
||||
```
|
||||
|
||||
#### Fedora
|
||||
|
||||
sudo dnf install alsa-lib-devel cmake glew glew-devel libatomic libevdev-devel libudev-devel openal-devel qt5-devel vulkan-devel
|
||||
sudo dnf install alsa-lib-devel cmake glew glew-devel libatomic libevdev-devel libudev-devel openal-devel qt5-devel qt5-qtbase-private-devel vulkan-devel
|
||||
|
||||
#### OpenSUSE
|
||||
|
||||
@@ -103,7 +103,7 @@ git submodule update --init
|
||||
#### Configuring the Qt plugin (if used)
|
||||
|
||||
1) Go to the Qt5 menu and edit Qt5 options.
|
||||
2) Add the path to your Qt installation with compiler e.g. `<QtInstallFolder>\5.14.2\msvc2017_64`.
|
||||
2) Add the path to your Qt installation with compiler e.g. `<QtInstallFolder>\5.15.2\msvc2019_64`.
|
||||
3) While selecting the rpcs3qt project, go to Qt5->Project Setting and select the version you added.
|
||||
|
||||
#### Building the projects
|
||||
|
||||
+4
-4
@@ -7,8 +7,8 @@ if(CMAKE_COMPILER_IS_GNUCXX)
|
||||
message(FATAL_ERROR "RPCS3 requires at least gcc-9.")
|
||||
endif()
|
||||
elseif(${CMAKE_CXX_COMPILER_ID} MATCHES "Clang")
|
||||
if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 9.0)
|
||||
message(FATAL_ERROR "RPCS3 requires at least clang-9.0.")
|
||||
if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 11.0)
|
||||
message(FATAL_ERROR "RPCS3 requires at least clang-11.0.")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
@@ -22,7 +22,7 @@ option(USE_LIBEVDEV "libevdev-based joystick support" ON)
|
||||
option(USE_DISCORD_RPC "Discord rich presence integration" ON)
|
||||
option(USE_SYSTEM_ZLIB "Prefer system ZLIB instead of the builtin one" ON)
|
||||
option(USE_VULKAN "Vulkan render backend" ON)
|
||||
option(USE_PRECOMPILED_HEADERS "Use precompiled headers" ON)
|
||||
option(USE_PRECOMPILED_HEADERS "Use precompiled headers" OFF)
|
||||
|
||||
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/rpcs3/cmake_modules")
|
||||
|
||||
@@ -64,7 +64,7 @@ set(CMAKE_C_FLAGS -w)
|
||||
set(LLVM_ENABLE_WARNINGS OFF CACHE BOOL "")
|
||||
|
||||
if(MSVC)
|
||||
add_compile_options(/wd4530) # C++ exception handler used, but unwind semantics are not enabled
|
||||
add_compile_options(/wd4530 /utf-8) # C++ exception handler used, but unwind semantics are not enabled
|
||||
endif()
|
||||
|
||||
add_subdirectory(Vulkan EXCLUDE_FROM_ALL)
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
RPCS3
|
||||
=====
|
||||
|
||||
[](https://travis-ci.org/RPCS3/rpcs3)
|
||||
[](https://dev.azure.com/nekotekina/nekotekina/_build?definitionId=4&branchName=master)
|
||||
[&logo=cirrus-ci)](https://cirrus-ci.com/github/RPCS3/rpcs3)
|
||||
[](https://discord.me/rpcs3)
|
||||
|
||||
@@ -1,511 +0,0 @@
|
||||
#ifndef BETYPE_H_GUARD
|
||||
#define BETYPE_H_GUARD
|
||||
|
||||
#include "types.h"
|
||||
#include "util/endian.hpp"
|
||||
#include <cstring>
|
||||
#include <cmath>
|
||||
|
||||
#if __has_include(<bit>)
|
||||
#include <bit>
|
||||
#else
|
||||
#include <type_traits>
|
||||
#endif
|
||||
|
||||
// 128-bit vector type and also se_storage<> storage type
|
||||
union alignas(16) v128
|
||||
{
|
||||
uchar _bytes[16];
|
||||
char _chars[16];
|
||||
|
||||
template <typename T, std::size_t N, std::size_t M>
|
||||
struct masked_array_t // array type accessed as (index ^ M)
|
||||
{
|
||||
char m_data[16];
|
||||
|
||||
public:
|
||||
T& operator[](std::size_t index)
|
||||
{
|
||||
return reinterpret_cast<T*>(m_data)[index ^ M];
|
||||
}
|
||||
|
||||
const T& operator[](std::size_t index) const
|
||||
{
|
||||
return reinterpret_cast<const T*>(m_data)[index ^ M];
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, std::size_t N = 16 / sizeof(T)>
|
||||
using normal_array_t = masked_array_t<T, N, std::endian::little == std::endian::native ? 0 : N - 1>;
|
||||
template <typename T, std::size_t N = 16 / sizeof(T)>
|
||||
using reversed_array_t = masked_array_t<T, N, std::endian::little == std::endian::native ? N - 1 : 0>;
|
||||
|
||||
normal_array_t<u64> _u64;
|
||||
normal_array_t<s64> _s64;
|
||||
reversed_array_t<u64> u64r;
|
||||
reversed_array_t<s64> s64r;
|
||||
|
||||
normal_array_t<u32> _u32;
|
||||
normal_array_t<s32> _s32;
|
||||
reversed_array_t<u32> u32r;
|
||||
reversed_array_t<s32> s32r;
|
||||
|
||||
normal_array_t<u16> _u16;
|
||||
normal_array_t<s16> _s16;
|
||||
reversed_array_t<u16> u16r;
|
||||
reversed_array_t<s16> s16r;
|
||||
|
||||
normal_array_t<u8> _u8;
|
||||
normal_array_t<s8> _s8;
|
||||
reversed_array_t<u8> u8r;
|
||||
reversed_array_t<s8> s8r;
|
||||
|
||||
normal_array_t<f32> _f;
|
||||
normal_array_t<f64> _d;
|
||||
reversed_array_t<f32> fr;
|
||||
reversed_array_t<f64> dr;
|
||||
|
||||
__m128 vf;
|
||||
__m128i vi;
|
||||
__m128d vd;
|
||||
|
||||
struct bit_array_128
|
||||
{
|
||||
char m_data[16];
|
||||
|
||||
public:
|
||||
class bit_element
|
||||
{
|
||||
u64& data;
|
||||
const u64 mask;
|
||||
|
||||
public:
|
||||
bit_element(u64& data, const u64 mask)
|
||||
: data(data)
|
||||
, mask(mask)
|
||||
{
|
||||
}
|
||||
|
||||
operator bool() const
|
||||
{
|
||||
return (data & mask) != 0;
|
||||
}
|
||||
|
||||
bit_element& operator=(const bool right)
|
||||
{
|
||||
if (right)
|
||||
{
|
||||
data |= mask;
|
||||
}
|
||||
else
|
||||
{
|
||||
data &= ~mask;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
bit_element& operator=(const bit_element& right)
|
||||
{
|
||||
if (right)
|
||||
{
|
||||
data |= mask;
|
||||
}
|
||||
else
|
||||
{
|
||||
data &= ~mask;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
// Index 0 returns the MSB and index 127 returns the LSB
|
||||
bit_element operator[](u32 index)
|
||||
{
|
||||
const auto data_ptr = reinterpret_cast<u64*>(m_data);
|
||||
|
||||
if constexpr (std::endian::little == std::endian::native)
|
||||
{
|
||||
return bit_element(data_ptr[1 - (index >> 6)], 0x8000000000000000ull >> (index & 0x3F));
|
||||
}
|
||||
else
|
||||
{
|
||||
return bit_element(data_ptr[index >> 6], 0x8000000000000000ull >> (index & 0x3F));
|
||||
}
|
||||
}
|
||||
|
||||
// Index 0 returns the MSB and index 127 returns the LSB
|
||||
bool operator[](u32 index) const
|
||||
{
|
||||
const auto data_ptr = reinterpret_cast<const u64*>(m_data);
|
||||
|
||||
if constexpr (std::endian::little == std::endian::native)
|
||||
{
|
||||
return (data_ptr[1 - (index >> 6)] & (0x8000000000000000ull >> (index & 0x3F))) != 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return (data_ptr[index >> 6] & (0x8000000000000000ull >> (index & 0x3F))) != 0;
|
||||
}
|
||||
}
|
||||
} _bit;
|
||||
|
||||
static v128 from64(u64 _0, u64 _1 = 0)
|
||||
{
|
||||
v128 ret;
|
||||
ret._u64[0] = _0;
|
||||
ret._u64[1] = _1;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static v128 from64r(u64 _1, u64 _0 = 0)
|
||||
{
|
||||
return from64(_0, _1);
|
||||
}
|
||||
|
||||
static v128 from32(u32 _0, u32 _1 = 0, u32 _2 = 0, u32 _3 = 0)
|
||||
{
|
||||
v128 ret;
|
||||
ret._u32[0] = _0;
|
||||
ret._u32[1] = _1;
|
||||
ret._u32[2] = _2;
|
||||
ret._u32[3] = _3;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static v128 from32r(u32 _3, u32 _2 = 0, u32 _1 = 0, u32 _0 = 0)
|
||||
{
|
||||
return from32(_0, _1, _2, _3);
|
||||
}
|
||||
|
||||
static v128 from32p(u32 value)
|
||||
{
|
||||
v128 ret;
|
||||
ret.vi = _mm_set1_epi32(static_cast<s32>(value));
|
||||
return ret;
|
||||
}
|
||||
|
||||
static v128 from16p(u16 value)
|
||||
{
|
||||
v128 ret;
|
||||
ret.vi = _mm_set1_epi16(static_cast<s16>(value));
|
||||
return ret;
|
||||
}
|
||||
|
||||
static v128 from8p(u8 value)
|
||||
{
|
||||
v128 ret;
|
||||
ret.vi = _mm_set1_epi8(static_cast<s8>(value));
|
||||
return ret;
|
||||
}
|
||||
|
||||
static v128 fromBit(u32 bit)
|
||||
{
|
||||
v128 ret = {};
|
||||
ret._bit[bit] = true;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static v128 fromV(__m128i value)
|
||||
{
|
||||
v128 ret;
|
||||
ret.vi = value;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static v128 fromF(__m128 value)
|
||||
{
|
||||
v128 ret;
|
||||
ret.vf = value;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static v128 fromD(__m128d value)
|
||||
{
|
||||
v128 ret;
|
||||
ret.vd = value;
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Unaligned load with optional index offset
|
||||
static v128 loadu(const void* ptr, std::size_t index = 0)
|
||||
{
|
||||
v128 ret;
|
||||
std::memcpy(&ret, static_cast<const u8*>(ptr) + index * sizeof(v128), sizeof(v128));
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Unaligned store with optional index offset
|
||||
static void storeu(v128 value, void* ptr, std::size_t index = 0)
|
||||
{
|
||||
std::memcpy(static_cast<u8*>(ptr) + index * sizeof(v128), &value, sizeof(v128));
|
||||
}
|
||||
|
||||
static inline v128 add8(const v128& left, const v128& right)
|
||||
{
|
||||
return fromV(_mm_add_epi8(left.vi, right.vi));
|
||||
}
|
||||
|
||||
static inline v128 add16(const v128& left, const v128& right)
|
||||
{
|
||||
return fromV(_mm_add_epi16(left.vi, right.vi));
|
||||
}
|
||||
|
||||
static inline v128 add32(const v128& left, const v128& right)
|
||||
{
|
||||
return fromV(_mm_add_epi32(left.vi, right.vi));
|
||||
}
|
||||
|
||||
static inline v128 addfs(const v128& left, const v128& right)
|
||||
{
|
||||
return fromF(_mm_add_ps(left.vf, right.vf));
|
||||
}
|
||||
|
||||
static inline v128 addfd(const v128& left, const v128& right)
|
||||
{
|
||||
return fromD(_mm_add_pd(left.vd, right.vd));
|
||||
}
|
||||
|
||||
static inline v128 sub8(const v128& left, const v128& right)
|
||||
{
|
||||
return fromV(_mm_sub_epi8(left.vi, right.vi));
|
||||
}
|
||||
|
||||
static inline v128 sub16(const v128& left, const v128& right)
|
||||
{
|
||||
return fromV(_mm_sub_epi16(left.vi, right.vi));
|
||||
}
|
||||
|
||||
static inline v128 sub32(const v128& left, const v128& right)
|
||||
{
|
||||
return fromV(_mm_sub_epi32(left.vi, right.vi));
|
||||
}
|
||||
|
||||
static inline v128 subfs(const v128& left, const v128& right)
|
||||
{
|
||||
return fromF(_mm_sub_ps(left.vf, right.vf));
|
||||
}
|
||||
|
||||
static inline v128 subfd(const v128& left, const v128& right)
|
||||
{
|
||||
return fromD(_mm_sub_pd(left.vd, right.vd));
|
||||
}
|
||||
|
||||
static inline v128 maxu8(const v128& left, const v128& right)
|
||||
{
|
||||
return fromV(_mm_max_epu8(left.vi, right.vi));
|
||||
}
|
||||
|
||||
static inline v128 minu8(const v128& left, const v128& right)
|
||||
{
|
||||
return fromV(_mm_min_epu8(left.vi, right.vi));
|
||||
}
|
||||
|
||||
static inline v128 eq8(const v128& left, const v128& right)
|
||||
{
|
||||
return fromV(_mm_cmpeq_epi8(left.vi, right.vi));
|
||||
}
|
||||
|
||||
static inline v128 eq16(const v128& left, const v128& right)
|
||||
{
|
||||
return fromV(_mm_cmpeq_epi16(left.vi, right.vi));
|
||||
}
|
||||
|
||||
static inline v128 eq32(const v128& left, const v128& right)
|
||||
{
|
||||
return fromV(_mm_cmpeq_epi32(left.vi, right.vi));
|
||||
}
|
||||
|
||||
static inline v128 eq32f(const v128& left, const v128& right)
|
||||
{
|
||||
return fromF(_mm_cmpeq_ps(left.vf, right.vf));
|
||||
}
|
||||
|
||||
static inline v128 eq64f(const v128& left, const v128& right)
|
||||
{
|
||||
return fromD(_mm_cmpeq_pd(left.vd, right.vd));
|
||||
}
|
||||
|
||||
static inline bool use_fma = false;
|
||||
|
||||
static inline v128 fma32f(v128 a, const v128& b, const v128& c)
|
||||
{
|
||||
#ifndef __FMA__
|
||||
if (use_fma) [[likely]]
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
a.vf = _mm_fmadd_ps(a.vf, b.vf, c.vf);
|
||||
return a;
|
||||
#else
|
||||
__asm__("vfmadd213ps %[c], %[b], %[a]"
|
||||
: [a] "+x" (a.vf)
|
||||
: [b] "x" (b.vf)
|
||||
, [c] "x" (c.vf));
|
||||
return a;
|
||||
#endif
|
||||
}
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
a._f[i] = std::fmaf(a._f[i], b._f[i], c._f[i]);
|
||||
}
|
||||
return a;
|
||||
#else
|
||||
a.vf = _mm_fmadd_ps(a.vf, b.vf, c.vf);
|
||||
return a;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool operator==(const v128& right) const
|
||||
{
|
||||
return _mm_movemask_epi8(v128::eq32(*this, right).vi) == 0xffff;
|
||||
}
|
||||
|
||||
bool operator!=(const v128& right) const
|
||||
{
|
||||
return !operator==(right);
|
||||
}
|
||||
|
||||
// result = (~left) & (right)
|
||||
static inline v128 andnot(const v128& left, const v128& right)
|
||||
{
|
||||
return fromV(_mm_andnot_si128(left.vi, right.vi));
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
*this = {};
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, std::size_t N, std::size_t M>
|
||||
struct offset32_array<v128::masked_array_t<T, N, M>>
|
||||
{
|
||||
template <typename Arg>
|
||||
static inline u32 index32(const Arg& arg)
|
||||
{
|
||||
return u32{sizeof(T)} * (static_cast<u32>(arg) ^ static_cast<u32>(M));
|
||||
}
|
||||
};
|
||||
|
||||
inline v128 operator|(const v128& left, const v128& right)
|
||||
{
|
||||
return v128::fromV(_mm_or_si128(left.vi, right.vi));
|
||||
}
|
||||
|
||||
inline v128 operator&(const v128& left, const v128& right)
|
||||
{
|
||||
return v128::fromV(_mm_and_si128(left.vi, right.vi));
|
||||
}
|
||||
|
||||
inline v128 operator^(const v128& left, const v128& right)
|
||||
{
|
||||
return v128::fromV(_mm_xor_si128(left.vi, right.vi));
|
||||
}
|
||||
|
||||
inline v128 operator~(const v128& other)
|
||||
{
|
||||
return other ^ v128::from32p(UINT32_MAX); // XOR with ones
|
||||
}
|
||||
|
||||
using stx::se_t;
|
||||
using stx::se_storage;
|
||||
|
||||
// se_t<> with native endianness
|
||||
template <typename T, std::size_t Align = alignof(T)>
|
||||
using nse_t = se_t<T, false, Align>;
|
||||
|
||||
template <typename T, std::size_t Align = alignof(T)>
|
||||
using be_t = se_t<T, std::endian::little == std::endian::native, Align>;
|
||||
template <typename T, std::size_t Align = alignof(T)>
|
||||
using le_t = se_t<T, std::endian::big == std::endian::native, Align>;
|
||||
|
||||
// Type converter: converts native endianness arithmetic/enum types to appropriate se_t<> type
|
||||
template <typename T, bool Se, typename = void>
|
||||
struct to_se
|
||||
{
|
||||
template <typename T2, typename = void>
|
||||
struct to_se_
|
||||
{
|
||||
using type = T2;
|
||||
};
|
||||
|
||||
template <typename T2>
|
||||
struct to_se_<T2, std::enable_if_t<std::is_arithmetic<T2>::value || std::is_enum<T2>::value>>
|
||||
{
|
||||
using type = std::conditional_t<(sizeof(T2) > 1), se_t<T2, Se>, T2>;
|
||||
};
|
||||
|
||||
// Convert arithmetic and enum types
|
||||
using type = typename to_se_<T>::type;
|
||||
};
|
||||
|
||||
template <bool Se>
|
||||
struct to_se<v128, Se>
|
||||
{
|
||||
using type = se_t<v128, Se>;
|
||||
};
|
||||
|
||||
template <bool Se>
|
||||
struct to_se<u128, Se>
|
||||
{
|
||||
using type = se_t<u128, Se>;
|
||||
};
|
||||
|
||||
template <bool Se>
|
||||
struct to_se<s128, Se>
|
||||
{
|
||||
using type = se_t<s128, Se>;
|
||||
};
|
||||
|
||||
template <typename T, bool Se>
|
||||
struct to_se<const T, Se, std::enable_if_t<!std::is_array<T>::value>>
|
||||
{
|
||||
// Move const qualifier
|
||||
using type = const typename to_se<T, Se>::type;
|
||||
};
|
||||
|
||||
template <typename T, bool Se>
|
||||
struct to_se<volatile T, Se, std::enable_if_t<!std::is_array<T>::value && !std::is_const<T>::value>>
|
||||
{
|
||||
// Move volatile qualifier
|
||||
using type = volatile typename to_se<T, Se>::type;
|
||||
};
|
||||
|
||||
template <typename T, bool Se>
|
||||
struct to_se<T[], Se>
|
||||
{
|
||||
// Move array qualifier
|
||||
using type = typename to_se<T, Se>::type[];
|
||||
};
|
||||
|
||||
template <typename T, bool Se, std::size_t N>
|
||||
struct to_se<T[N], Se>
|
||||
{
|
||||
// Move array qualifier
|
||||
using type = typename to_se<T, Se>::type[N];
|
||||
};
|
||||
|
||||
// BE/LE aliases for to_se<>
|
||||
template <typename T>
|
||||
using to_be_t = typename to_se<T, std::endian::little == std::endian::native>::type;
|
||||
template <typename T>
|
||||
using to_le_t = typename to_se<T, std::endian::big == std::endian::native>::type;
|
||||
|
||||
// BE/LE aliases for atomic_t
|
||||
template <typename T>
|
||||
using atomic_be_t = atomic_t<be_t<T>>;
|
||||
template <typename T>
|
||||
using atomic_le_t = atomic_t<le_t<T>>;
|
||||
|
||||
template <typename T, bool Se, std::size_t Align>
|
||||
struct fmt_unveil<se_t<T, Se, Align>, void>
|
||||
{
|
||||
using type = typename fmt_unveil<T>::type;
|
||||
|
||||
static inline auto get(const se_t<T, Se, Align>& arg)
|
||||
{
|
||||
return fmt_unveil<T>::get(arg);
|
||||
}
|
||||
};
|
||||
|
||||
#endif // BETYPE_H_GUARD
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
#pragma once
|
||||
|
||||
#include "types.h"
|
||||
#include "util/types.hpp"
|
||||
#include "Utilities/StrFmt.h"
|
||||
|
||||
template<typename T, uint N>
|
||||
struct bf_base
|
||||
@@ -147,7 +148,7 @@ struct bf_t : bf_base<T, N>
|
||||
|
||||
bf_t& operator &=(vtype right)
|
||||
{
|
||||
this->m_data &= static_cast<vtype>((static_cast<utype>(right) & bf_t::vmask) << bitpos);
|
||||
this->m_data &= static_cast<vtype>(((static_cast<utype>(right) & bf_t::vmask) << bitpos) | ~(bf_t::vmask << bitpos));
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <Utilities/types.h>
|
||||
#include "util/types.hpp"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "windows.h"
|
||||
@@ -176,7 +176,7 @@ public:
|
||||
};
|
||||
u_int miblen = std::size(mib);
|
||||
struct kinfo_proc info;
|
||||
size_t size = sizeof(info);
|
||||
usz size = sizeof(info);
|
||||
if (sysctl(mib, miblen, &info, &size, NULL, 0))
|
||||
{
|
||||
return 0;
|
||||
@@ -194,7 +194,7 @@ public:
|
||||
u_int miblen = std::size(mib);
|
||||
|
||||
// get number of structs
|
||||
size_t size;
|
||||
usz size;
|
||||
if (sysctl(mib, miblen, NULL, &size, NULL, 0))
|
||||
{
|
||||
return 0;
|
||||
|
||||
+11
-13
@@ -1,14 +1,12 @@
|
||||
#include "stdafx.h"
|
||||
#include "stdafx.h"
|
||||
#include "Config.h"
|
||||
#include "Utilities/types.h"
|
||||
#include "util/types.hpp"
|
||||
|
||||
#include "util/yaml.hpp"
|
||||
|
||||
#include <typeinfo>
|
||||
#include <charconv>
|
||||
|
||||
[[noreturn]] void report_fatal_error(const std::string&);
|
||||
|
||||
LOG_CHANNEL(cfg_log, "CFG");
|
||||
|
||||
namespace cfg
|
||||
@@ -18,7 +16,7 @@ namespace cfg
|
||||
{
|
||||
if (_type != type::node)
|
||||
{
|
||||
cfg_log.fatal("Invalid root node" HERE);
|
||||
cfg_log.fatal("Invalid root node");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,7 +27,7 @@ namespace cfg
|
||||
{
|
||||
if (pair.first == name)
|
||||
{
|
||||
cfg_log.fatal("Node already exists: %s" HERE, name);
|
||||
cfg_log.fatal("Node already exists: %s", name);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,12 +36,12 @@ namespace cfg
|
||||
|
||||
bool _base::from_string(const std::string&, bool)
|
||||
{
|
||||
report_fatal_error("from_string() purecall" HERE);
|
||||
fmt::throw_exception("from_string() purecall");
|
||||
}
|
||||
|
||||
bool _base::from_list(std::vector<std::string>&&)
|
||||
{
|
||||
report_fatal_error("from_list() purecall" HERE);
|
||||
fmt::throw_exception("from_list() purecall");
|
||||
}
|
||||
|
||||
// Emit YAML
|
||||
@@ -84,7 +82,7 @@ bool cfg::try_to_int64(s64* out, const std::string& value, s64 min, s64 max)
|
||||
|
||||
if (ret.ec != std::errc() || ret.ptr != end || (start[0] == '-' && sign < 0))
|
||||
{
|
||||
if (out) cfg_log.error("cfg::try_to_int('%s'): invalid integer", value);
|
||||
if (out) cfg_log.error("cfg::try_to_int64('%s'): invalid integer", value);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -92,7 +90,7 @@ bool cfg::try_to_int64(s64* out, const std::string& value, s64 min, s64 max)
|
||||
|
||||
if (result < min || result > max)
|
||||
{
|
||||
if (out) cfg_log.error("cfg::try_to_int('%s'): out of bounds (%d..%d)", value, min, max);
|
||||
if (out) cfg_log.error("cfg::try_to_int64('%s'): out of bounds (%d..%d)", value, min, max);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -123,13 +121,13 @@ bool cfg::try_to_uint64(u64* out, const std::string& value, u64 min, u64 max)
|
||||
|
||||
if (ret.ec != std::errc() || ret.ptr != end)
|
||||
{
|
||||
if (out) cfg_log.error("cfg::try_to_int('%s'): invalid integer", value);
|
||||
if (out) cfg_log.error("cfg::try_to_uint64('%s'): invalid integer", value);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (result < min || result > max)
|
||||
{
|
||||
if (out) cfg_log.error("cfg::try_to_int('%s'): out of bounds (%u..%u)", value, min, max);
|
||||
if (out) cfg_log.error("cfg::try_to_uint64('%s'): out of bounds (%u..%u)", value, min, max);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -380,7 +378,7 @@ void cfg::_bool::from_default()
|
||||
|
||||
void cfg::string::from_default()
|
||||
{
|
||||
m_value = m_value.make(def);
|
||||
m_value = def;
|
||||
}
|
||||
|
||||
void cfg::set_entry::from_default()
|
||||
|
||||
+12
-7
@@ -1,10 +1,10 @@
|
||||
#pragma once
|
||||
#pragma once
|
||||
|
||||
#include "Utilities/types.h"
|
||||
#include "util/types.hpp"
|
||||
#include "Utilities/StrFmt.h"
|
||||
#include "util/logs.hpp"
|
||||
#include "util/atomic.hpp"
|
||||
#include "util/shared_cptr.hpp"
|
||||
#include "util/shared_ptr.hpp"
|
||||
|
||||
#include <utility>
|
||||
#include <string>
|
||||
@@ -203,6 +203,11 @@ namespace cfg
|
||||
return m_value;
|
||||
}
|
||||
|
||||
void set(T value)
|
||||
{
|
||||
m_value = value;
|
||||
}
|
||||
|
||||
void from_default() override
|
||||
{
|
||||
m_value = def;
|
||||
@@ -388,7 +393,7 @@ namespace cfg
|
||||
{
|
||||
const std::string m_name;
|
||||
|
||||
stx::atomic_cptr<std::string> m_value;
|
||||
atomic_ptr<std::string> m_value;
|
||||
|
||||
public:
|
||||
std::string def;
|
||||
@@ -396,7 +401,7 @@ namespace cfg
|
||||
string(node* owner, std::string name, std::string def = {}, bool dynamic = false)
|
||||
: _base(type::string, owner, name, dynamic)
|
||||
, m_name(std::move(name))
|
||||
, m_value(m_value.make(def))
|
||||
, m_value(def)
|
||||
, def(std::move(def))
|
||||
{
|
||||
}
|
||||
@@ -406,7 +411,7 @@ namespace cfg
|
||||
return *m_value.load().get();
|
||||
}
|
||||
|
||||
std::pair<const std::string&, stx::shared_cptr<std::string>> get() const
|
||||
std::pair<const std::string&, shared_ptr<std::string>> get() const
|
||||
{
|
||||
auto v = m_value.load();
|
||||
|
||||
@@ -435,7 +440,7 @@ namespace cfg
|
||||
|
||||
bool from_string(const std::string& value, bool /*dynamic*/ = false) override
|
||||
{
|
||||
m_value = m_value.make(value);
|
||||
m_value = value;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
+234
-161
@@ -1,7 +1,6 @@
|
||||
#include "File.h"
|
||||
#include "File.h"
|
||||
#include "mutex.h"
|
||||
#include "StrFmt.h"
|
||||
#include "BEType.h"
|
||||
#include "Crypto/sha1.h"
|
||||
|
||||
#include <unordered_map>
|
||||
@@ -11,6 +10,8 @@
|
||||
#include <typeinfo>
|
||||
#include <map>
|
||||
|
||||
#include "util/asm.hpp"
|
||||
|
||||
using namespace std::literals::string_literals;
|
||||
|
||||
#ifdef _WIN32
|
||||
@@ -21,10 +22,10 @@ using namespace std::literals::string_literals;
|
||||
static std::unique_ptr<wchar_t[]> to_wchar(const std::string& source)
|
||||
{
|
||||
// String size + null terminator
|
||||
const std::size_t buf_size = source.size() + 1;
|
||||
const usz buf_size = source.size() + 1;
|
||||
|
||||
// Safe size
|
||||
const int size = narrow<int>(buf_size, "to_wchar" HERE);
|
||||
const int size = narrow<int>(buf_size);
|
||||
|
||||
// Buffer for max possible output length
|
||||
std::unique_ptr<wchar_t[]> buffer(new wchar_t[buf_size + 8 + 32768]);
|
||||
@@ -41,10 +42,10 @@ static std::unique_ptr<wchar_t[]> to_wchar(const std::string& source)
|
||||
std::memcpy(buffer.get() + 32768 + 4, L"UNC\\", 4 * sizeof(wchar_t));
|
||||
}
|
||||
|
||||
verify("to_wchar" HERE), MultiByteToWideChar(CP_UTF8, 0, source.c_str(), size, buffer.get() + 32768 + (unc ? 8 : 4), size);
|
||||
ensure(MultiByteToWideChar(CP_UTF8, 0, source.c_str(), size, buffer.get() + 32768 + (unc ? 8 : 4), size)); // "to_wchar"
|
||||
|
||||
// Canonicalize wide path (replace '/', ".", "..", \\ repetitions, etc)
|
||||
verify("to_wchar" HERE), GetFullPathNameW(buffer.get() + 32768, 32768, buffer.get(), nullptr) - 1 < 32768 - 1;
|
||||
ensure(GetFullPathNameW(buffer.get() + 32768, 32768, buffer.get(), nullptr) - 1 < 32768 - 1); // "to_wchar"
|
||||
|
||||
return buffer;
|
||||
}
|
||||
@@ -52,10 +53,10 @@ static std::unique_ptr<wchar_t[]> to_wchar(const std::string& source)
|
||||
static void to_utf8(std::string& out, const wchar_t* source)
|
||||
{
|
||||
// String size
|
||||
const std::size_t length = std::wcslen(source);
|
||||
const usz length = std::wcslen(source);
|
||||
|
||||
// Safe buffer size for max possible output length (including null terminator)
|
||||
const int buf_size = narrow<int>(length * 3 + 1, "to_utf8" HERE);
|
||||
const int buf_size = narrow<int>(length * 3 + 1);
|
||||
|
||||
// Resize buffer
|
||||
out.resize(buf_size - 1);
|
||||
@@ -63,7 +64,7 @@ static void to_utf8(std::string& out, const wchar_t* source)
|
||||
const int result = WideCharToMultiByte(CP_UTF8, 0, source, static_cast<int>(length) + 1, &out.front(), buf_size, NULL, NULL);
|
||||
|
||||
// Fix the size
|
||||
out.resize(verify("to_utf8" HERE, result) - 1);
|
||||
out.resize(ensure(result) - 1);
|
||||
}
|
||||
|
||||
static time_t to_time(const ULARGE_INTEGER& ft)
|
||||
@@ -182,7 +183,7 @@ static std::string path_append(std::string_view path, std::string_view more)
|
||||
{
|
||||
std::string result;
|
||||
|
||||
if (const size_t src_slash_pos = path.find_last_not_of('/'); src_slash_pos != path.npos)
|
||||
if (const usz src_slash_pos = path.find_last_not_of('/'); src_slash_pos != path.npos)
|
||||
{
|
||||
path.remove_suffix(path.length() - src_slash_pos - 1);
|
||||
result = path;
|
||||
@@ -190,7 +191,7 @@ static std::string path_append(std::string_view path, std::string_view more)
|
||||
|
||||
result.push_back('/');
|
||||
|
||||
if (const size_t dst_slash_pos = more.find_first_not_of('/'); dst_slash_pos != more.npos)
|
||||
if (const usz dst_slash_pos = more.find_first_not_of('/'); dst_slash_pos != more.npos)
|
||||
{
|
||||
more.remove_prefix(dst_slash_pos);
|
||||
result.append(more);
|
||||
@@ -315,33 +316,19 @@ std::shared_ptr<fs::device_base> fs::get_virtual_device(const std::string& path)
|
||||
|
||||
std::shared_ptr<fs::device_base> fs::set_virtual_device(const std::string& name, const std::shared_ptr<device_base>& device)
|
||||
{
|
||||
verify(HERE), name.starts_with("//"), name[2] != '/';
|
||||
ensure(name.starts_with("//") && name[2] != '/');
|
||||
|
||||
return get_device_manager().set_device(name, device);
|
||||
}
|
||||
|
||||
std::string fs::get_parent_dir(const std::string& path)
|
||||
{
|
||||
// Search upper bound (set to the last character, npos for empty string)
|
||||
auto last = path.size() - 1;
|
||||
// Get (basically) processed path
|
||||
const auto real_path = fs::escape_path(path);
|
||||
|
||||
#ifdef _WIN32
|
||||
const auto& delim = "/\\";
|
||||
#else
|
||||
const auto& delim = "/";
|
||||
#endif
|
||||
const auto pos = real_path.find_last_of(delim);
|
||||
|
||||
while (true)
|
||||
{
|
||||
const auto pos = path.find_last_of(delim, last, sizeof(delim) - 1);
|
||||
|
||||
// Contiguous slashes are ignored at the end
|
||||
if (std::exchange(last, pos - 1) != pos)
|
||||
{
|
||||
// Return empty string if the path doesn't contain at least 2 elements
|
||||
return path.substr(0, pos != umax && path.find_last_not_of(delim, pos, sizeof(delim) - 1) != umax ? pos : 0);
|
||||
}
|
||||
}
|
||||
return real_path.substr(0, pos == umax ? 0 : pos);
|
||||
}
|
||||
|
||||
bool fs::stat(const std::string& path, stat_t& info)
|
||||
@@ -352,16 +339,83 @@ bool fs::stat(const std::string& path, stat_t& info)
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
WIN32_FILE_ATTRIBUTE_DATA attrs;
|
||||
if (!GetFileAttributesExW(to_wchar(path).get(), GetFileExInfoStandard, &attrs))
|
||||
std::string_view epath = path;
|
||||
|
||||
// '/' and '\\' Not allowed by FindFirstFileExW at the end of path but we should allow it
|
||||
if (auto not_del = epath.find_last_not_of(delim); not_del != umax && not_del != epath.size() - 1)
|
||||
{
|
||||
epath.remove_suffix(epath.size() - 1 - not_del);
|
||||
}
|
||||
|
||||
// Handle drives specially
|
||||
if (epath.find_first_of(delim) == umax && epath.ends_with(':'))
|
||||
{
|
||||
WIN32_FILE_ATTRIBUTE_DATA attrs;
|
||||
|
||||
// Must end with a delimiter
|
||||
if (!GetFileAttributesExW(to_wchar(std::string(epath) + '/').get(), GetFileExInfoStandard, &attrs))
|
||||
{
|
||||
g_tls_error = to_error(GetLastError());
|
||||
return false;
|
||||
}
|
||||
|
||||
info.is_directory = true; // Handle drives as directories
|
||||
info.is_writable = (attrs.dwFileAttributes & FILE_ATTRIBUTE_READONLY) == 0;
|
||||
info.size = attrs.nFileSizeLow | (u64{attrs.nFileSizeHigh} << 32);
|
||||
info.atime = to_time(attrs.ftLastAccessTime);
|
||||
info.mtime = to_time(attrs.ftLastWriteTime);
|
||||
info.ctime = info.mtime;
|
||||
|
||||
if (info.atime < info.mtime)
|
||||
info.atime = info.mtime;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
WIN32_FIND_DATA attrs;
|
||||
|
||||
// Allowed by FindFirstFileExW but we should not allow it
|
||||
if (epath.ends_with("*"))
|
||||
{
|
||||
g_tls_error = fs::error::noent;
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto wchar_ptr = to_wchar(std::string(epath));
|
||||
const std::wstring_view wpath_view = wchar_ptr.get();
|
||||
|
||||
const HANDLE handle = FindFirstFileExW(wpath_view.data(), FindExInfoStandard, &attrs, FindExSearchNameMatch, nullptr, FIND_FIRST_EX_CASE_SENSITIVE);
|
||||
|
||||
if (handle == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
g_tls_error = to_error(GetLastError());
|
||||
return false;
|
||||
}
|
||||
|
||||
struct close_t
|
||||
{
|
||||
HANDLE handle;
|
||||
~close_t() { FindClose(handle); }
|
||||
};
|
||||
|
||||
for (close_t find_manage{handle}; attrs.cFileName != wpath_view.substr(wpath_view.find_last_of(wdelim) + 1);)
|
||||
{
|
||||
if (!FindNextFileW(handle, &attrs))
|
||||
{
|
||||
if (const DWORD err = GetLastError(); err != ERROR_NO_MORE_FILES)
|
||||
{
|
||||
g_tls_error = to_error(err);
|
||||
return false;
|
||||
}
|
||||
|
||||
g_tls_error = fs::error::noent;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
info.is_directory = (attrs.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
|
||||
info.is_writable = (attrs.dwFileAttributes & FILE_ATTRIBUTE_READONLY) == 0;
|
||||
info.size = (u64)attrs.nFileSizeLow | ((u64)attrs.nFileSizeHigh << 32);
|
||||
info.size = attrs.nFileSizeLow | (u64{attrs.nFileSizeHigh} << 32);
|
||||
info.atime = to_time(attrs.ftLastAccessTime);
|
||||
info.mtime = to_time(attrs.ftLastWriteTime);
|
||||
info.ctime = info.mtime;
|
||||
@@ -389,73 +443,19 @@ bool fs::stat(const std::string& path, stat_t& info)
|
||||
|
||||
bool fs::exists(const std::string& path)
|
||||
{
|
||||
if (auto device = get_virtual_device(path))
|
||||
{
|
||||
stat_t info;
|
||||
return device->stat(path, info);
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
if (GetFileAttributesW(to_wchar(path).get()) == INVALID_FILE_ATTRIBUTES)
|
||||
{
|
||||
g_tls_error = to_error(GetLastError());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
#else
|
||||
struct ::stat file_info;
|
||||
if (::stat(path.c_str(), &file_info) != 0)
|
||||
{
|
||||
g_tls_error = to_error(errno);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
#endif
|
||||
fs::stat_t info{};
|
||||
return fs::stat(path, info);
|
||||
}
|
||||
|
||||
bool fs::is_file(const std::string& path)
|
||||
{
|
||||
if (auto device = get_virtual_device(path))
|
||||
fs::stat_t info{};
|
||||
if (!fs::stat(path, info))
|
||||
{
|
||||
stat_t info;
|
||||
if (!device->stat(path, info))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (info.is_directory)
|
||||
{
|
||||
g_tls_error = error::exist;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
const DWORD attrs = GetFileAttributesW(to_wchar(path).get());
|
||||
if (attrs == INVALID_FILE_ATTRIBUTES)
|
||||
{
|
||||
g_tls_error = to_error(GetLastError());
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
struct ::stat file_info;
|
||||
if (::stat(path.c_str(), &file_info) != 0)
|
||||
{
|
||||
g_tls_error = to_error(errno);
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
// TODO: correct file type check
|
||||
#ifdef _WIN32
|
||||
if ((attrs & FILE_ATTRIBUTE_DIRECTORY) != 0)
|
||||
#else
|
||||
if (S_ISDIR(file_info.st_mode))
|
||||
#endif
|
||||
if (info.is_directory)
|
||||
{
|
||||
g_tls_error = error::exist;
|
||||
return false;
|
||||
@@ -466,44 +466,13 @@ bool fs::is_file(const std::string& path)
|
||||
|
||||
bool fs::is_dir(const std::string& path)
|
||||
{
|
||||
if (auto device = get_virtual_device(path))
|
||||
fs::stat_t info{};
|
||||
if (!fs::stat(path, info))
|
||||
{
|
||||
stat_t info;
|
||||
if (!device->stat(path, info))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (info.is_directory == false)
|
||||
{
|
||||
g_tls_error = error::exist;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
const DWORD attrs = GetFileAttributesW(to_wchar(path).get());
|
||||
if (attrs == INVALID_FILE_ATTRIBUTES)
|
||||
{
|
||||
g_tls_error = to_error(GetLastError());
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
struct ::stat file_info;
|
||||
if (::stat(path.c_str(), &file_info) != 0)
|
||||
{
|
||||
g_tls_error = to_error(errno);
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
if ((attrs & FILE_ATTRIBUTE_DIRECTORY) == 0)
|
||||
#else
|
||||
if (!S_ISDIR(file_info.st_mode))
|
||||
#endif
|
||||
if (!info.is_directory)
|
||||
{
|
||||
g_tls_error = error::exist;
|
||||
return false;
|
||||
@@ -538,7 +507,7 @@ bool fs::statfs(const std::string& path, fs::device_stat& info)
|
||||
// Keep cutting path from right until it's short enough
|
||||
while (str.size() > 256)
|
||||
{
|
||||
if (std::size_t x = str.find_last_of('\\') + 1)
|
||||
if (usz x = str.find_last_of('\\') + 1)
|
||||
str.resize(x - 1);
|
||||
else
|
||||
break;
|
||||
@@ -781,7 +750,7 @@ bool fs::copy_file(const std::string& from, const std::string& to, bool overwrit
|
||||
// sendfile will work with non-socket output (i.e. regular file) on Linux 2.6.33+
|
||||
off_t bytes_copied = 0;
|
||||
struct ::stat fileinfo = { 0 };
|
||||
if (::fstat(input, &fileinfo) || ::sendfile(output, input, &bytes_copied, fileinfo.st_size))
|
||||
if (::fstat(input, &fileinfo) == -1 || ::sendfile(output, input, &bytes_copied, fileinfo.st_size) == -1)
|
||||
#else
|
||||
#error "Native file copy implementation is missing"
|
||||
#endif
|
||||
@@ -899,7 +868,7 @@ bool fs::utime(const std::string& path, s64 atime, s64 mtime)
|
||||
|
||||
#ifdef _WIN32
|
||||
// Open the file
|
||||
const auto handle = CreateFileW(to_wchar(path).get(), FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
const auto handle = CreateFileW(to_wchar(path).get(), FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (handle == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
g_tls_error = to_error(GetLastError());
|
||||
@@ -932,14 +901,19 @@ bool fs::utime(const std::string& path, s64 atime, s64 mtime)
|
||||
#endif
|
||||
}
|
||||
|
||||
void fs::file::xnull() const
|
||||
[[noreturn]] void fs::xnull(const src_loc& loc)
|
||||
{
|
||||
fmt::throw_exception("fs::file is null");
|
||||
fmt::throw_exception("Null object.%s", loc);
|
||||
}
|
||||
|
||||
void fs::file::xfail() const
|
||||
[[noreturn]] void fs::xfail(const src_loc& loc)
|
||||
{
|
||||
fmt::throw_exception("Unexpected fs::error %s", g_tls_error);
|
||||
fmt::throw_exception("Unexpected fs::error %s%s", g_tls_error, loc);
|
||||
}
|
||||
|
||||
[[noreturn]] void fs::xovfl()
|
||||
{
|
||||
fmt::throw_exception("Stream overflow.");
|
||||
}
|
||||
|
||||
fs::file::file(const std::string& path, bs_t<open_mode> mode)
|
||||
@@ -985,7 +959,7 @@ fs::file::file(const std::string& path, bs_t<open_mode> mode)
|
||||
disp = mode & fs::trunc ? TRUNCATE_EXISTING : OPEN_EXISTING;
|
||||
}
|
||||
|
||||
DWORD share = 0;
|
||||
DWORD share = FILE_SHARE_DELETE;
|
||||
if (!(mode & fs::unread) || !(mode & fs::write))
|
||||
{
|
||||
share |= FILE_SHARE_READ;
|
||||
@@ -993,7 +967,7 @@ fs::file::file(const std::string& path, bs_t<open_mode> mode)
|
||||
|
||||
if (!(mode & (fs::lock + fs::unread)) || !(mode & fs::write))
|
||||
{
|
||||
share |= FILE_SHARE_WRITE | FILE_SHARE_DELETE;
|
||||
share |= FILE_SHARE_WRITE;
|
||||
}
|
||||
|
||||
const HANDLE handle = CreateFileW(to_wchar(path).get(), access, share, NULL, disp, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
@@ -1022,7 +996,7 @@ fs::file::file(const std::string& path, bs_t<open_mode> mode)
|
||||
stat_t stat() override
|
||||
{
|
||||
FILE_BASIC_INFO basic_info;
|
||||
verify("file::stat" HERE), GetFileInformationByHandleEx(m_handle, FileBasicInfo, &basic_info, sizeof(FILE_BASIC_INFO));
|
||||
ensure(GetFileInformationByHandleEx(m_handle, FileBasicInfo, &basic_info, sizeof(FILE_BASIC_INFO))); // "file::stat"
|
||||
|
||||
stat_t info;
|
||||
info.is_directory = (basic_info.FileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
|
||||
@@ -1040,7 +1014,7 @@ fs::file::file(const std::string& path, bs_t<open_mode> mode)
|
||||
|
||||
void sync() override
|
||||
{
|
||||
verify("file::sync" HERE), FlushFileBuffers(m_handle);
|
||||
ensure(FlushFileBuffers(m_handle)); // "file::sync"
|
||||
}
|
||||
|
||||
bool trunc(u64 length) override
|
||||
@@ -1060,10 +1034,10 @@ fs::file::file(const std::string& path, bs_t<open_mode> mode)
|
||||
u64 read(void* buffer, u64 count) override
|
||||
{
|
||||
// TODO (call ReadFile multiple times if count is too big)
|
||||
const int size = narrow<int>(count, "file::read" HERE);
|
||||
const int size = narrow<int>(count);
|
||||
|
||||
DWORD nread;
|
||||
verify("file::read" HERE), ReadFile(m_handle, buffer, size, &nread, NULL);
|
||||
ensure(ReadFile(m_handle, buffer, size, &nread, NULL)); // "file::read"
|
||||
|
||||
return nread;
|
||||
}
|
||||
@@ -1071,10 +1045,10 @@ fs::file::file(const std::string& path, bs_t<open_mode> mode)
|
||||
u64 write(const void* buffer, u64 count) override
|
||||
{
|
||||
// TODO (call WriteFile multiple times if count is too big)
|
||||
const int size = narrow<int>(count, "file::write" HERE);
|
||||
const int size = narrow<int>(count);
|
||||
|
||||
DWORD nwritten;
|
||||
verify("file::write" HERE), WriteFile(m_handle, buffer, size, &nwritten, NULL);
|
||||
ensure(WriteFile(m_handle, buffer, size, &nwritten, NULL)); // "file::write"
|
||||
|
||||
return nwritten;
|
||||
}
|
||||
@@ -1088,7 +1062,7 @@ fs::file::file(const std::string& path, bs_t<open_mode> mode)
|
||||
whence == seek_set ? FILE_BEGIN :
|
||||
whence == seek_cur ? FILE_CURRENT :
|
||||
whence == seek_end ? FILE_END :
|
||||
(fmt::throw_exception("Invalid whence (0x%x)" HERE, whence), 0);
|
||||
(fmt::throw_exception("Invalid whence (0x%x)", whence), 0);
|
||||
|
||||
if (!SetFilePointerEx(m_handle, pos, &pos, mode))
|
||||
{
|
||||
@@ -1102,7 +1076,7 @@ fs::file::file(const std::string& path, bs_t<open_mode> mode)
|
||||
u64 size() override
|
||||
{
|
||||
LARGE_INTEGER size;
|
||||
verify("file::size" HERE), GetFileSizeEx(m_handle, &size);
|
||||
ensure(GetFileSizeEx(m_handle, &size)); // "file::size"
|
||||
|
||||
return size.QuadPart;
|
||||
}
|
||||
@@ -1151,7 +1125,7 @@ fs::file::file(const std::string& path, bs_t<open_mode> mode)
|
||||
if (mode & fs::trunc && mode & (fs::lock + fs::unread) && mode & fs::write)
|
||||
{
|
||||
// Postpone truncation in order to avoid using O_TRUNC on a locked file
|
||||
verify(HERE), ::ftruncate(fd, 0) == 0;
|
||||
ensure(::ftruncate(fd, 0) == 0);
|
||||
}
|
||||
|
||||
class unix_file final : public file_base
|
||||
@@ -1172,7 +1146,7 @@ fs::file::file(const std::string& path, bs_t<open_mode> mode)
|
||||
stat_t stat() override
|
||||
{
|
||||
struct ::stat file_info;
|
||||
verify("file::stat" HERE), ::fstat(m_fd, &file_info) == 0;
|
||||
ensure(::fstat(m_fd, &file_info) == 0); // "file::stat"
|
||||
|
||||
stat_t info;
|
||||
info.is_directory = S_ISDIR(file_info.st_mode);
|
||||
@@ -1190,7 +1164,7 @@ fs::file::file(const std::string& path, bs_t<open_mode> mode)
|
||||
|
||||
void sync() override
|
||||
{
|
||||
verify("file::sync" HERE), ::fsync(m_fd) == 0;
|
||||
ensure(::fsync(m_fd) == 0); // "file::sync"
|
||||
}
|
||||
|
||||
bool trunc(u64 length) override
|
||||
@@ -1207,7 +1181,7 @@ fs::file::file(const std::string& path, bs_t<open_mode> mode)
|
||||
u64 read(void* buffer, u64 count) override
|
||||
{
|
||||
const auto result = ::read(m_fd, buffer, count);
|
||||
verify("file::read" HERE), result != -1;
|
||||
ensure(result != -1); // "file::read"
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -1215,7 +1189,7 @@ fs::file::file(const std::string& path, bs_t<open_mode> mode)
|
||||
u64 write(const void* buffer, u64 count) override
|
||||
{
|
||||
const auto result = ::write(m_fd, buffer, count);
|
||||
verify("file::write" HERE), result != -1;
|
||||
ensure(result != -1); // "file::write"
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -1226,7 +1200,7 @@ fs::file::file(const std::string& path, bs_t<open_mode> mode)
|
||||
whence == seek_set ? SEEK_SET :
|
||||
whence == seek_cur ? SEEK_CUR :
|
||||
whence == seek_end ? SEEK_END :
|
||||
(fmt::throw_exception("Invalid whence (0x%x)" HERE, whence), 0);
|
||||
(fmt::throw_exception("Invalid whence (0x%x)", whence), 0);
|
||||
|
||||
const auto result = ::lseek(m_fd, offset, mode);
|
||||
|
||||
@@ -1242,7 +1216,7 @@ fs::file::file(const std::string& path, bs_t<open_mode> mode)
|
||||
u64 size() override
|
||||
{
|
||||
struct ::stat file_info;
|
||||
verify("file::size" HERE), ::fstat(m_fd, &file_info) == 0;
|
||||
ensure(::fstat(m_fd, &file_info) == 0); // "file::size"
|
||||
|
||||
return file_info.st_size;
|
||||
}
|
||||
@@ -1258,7 +1232,7 @@ fs::file::file(const std::string& path, bs_t<open_mode> mode)
|
||||
static_assert(offsetof(iovec, iov_len) == offsetof(iovec_clone, iov_len), "Weird iovec::iov_len offset");
|
||||
|
||||
const auto result = ::writev(m_fd, reinterpret_cast<const iovec*>(buffers), buf_count);
|
||||
verify("file::write_gather" HERE), result != -1;
|
||||
ensure(result != -1); // "file::write_gather"
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -1268,7 +1242,7 @@ fs::file::file(const std::string& path, bs_t<open_mode> mode)
|
||||
#endif
|
||||
}
|
||||
|
||||
fs::file::file(const void* ptr, std::size_t size)
|
||||
fs::file::file(const void* ptr, usz size)
|
||||
{
|
||||
class memory_stream : public file_base
|
||||
{
|
||||
@@ -1350,11 +1324,6 @@ fs::native_handle fs::file::get_handle() const
|
||||
#endif
|
||||
}
|
||||
|
||||
void fs::dir::xnull() const
|
||||
{
|
||||
fmt::throw_exception("fs::dir is null");
|
||||
}
|
||||
|
||||
bool fs::dir::open(const std::string& path)
|
||||
{
|
||||
if (path.empty())
|
||||
@@ -1388,7 +1357,7 @@ bool fs::dir::open(const std::string& path)
|
||||
class windows_dir final : public dir_base
|
||||
{
|
||||
std::vector<dir_entry> m_entries;
|
||||
std::size_t m_pos = 0;
|
||||
usz m_pos = 0;
|
||||
|
||||
void add_entry(const WIN32_FIND_DATAW& found)
|
||||
{
|
||||
@@ -1418,7 +1387,7 @@ bool fs::dir::open(const std::string& path)
|
||||
add_entry(found);
|
||||
}
|
||||
|
||||
verify("dir::read" HERE), ERROR_NO_MORE_FILES == GetLastError();
|
||||
ensure(ERROR_NO_MORE_FILES == GetLastError()); // "dir::read"
|
||||
FindClose(handle);
|
||||
}
|
||||
|
||||
@@ -1634,6 +1603,110 @@ bool fs::remove_all(const std::string& path, bool remove_root)
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string fs::escape_path(std::string_view path)
|
||||
{
|
||||
std::string real; real.resize(path.size());
|
||||
|
||||
auto get_char = [&](usz& from, usz& to, usz count)
|
||||
{
|
||||
std::memcpy(&real[to], &path[from], count);
|
||||
from += count, to += count;
|
||||
};
|
||||
|
||||
usz i = 0, j = -1, pos_nondelim = 0, after_delim = 0;
|
||||
|
||||
if (i < path.size())
|
||||
{
|
||||
j = 0;
|
||||
}
|
||||
|
||||
for (; i < path.size();)
|
||||
{
|
||||
real[j] = path[i];
|
||||
#ifdef _Win32
|
||||
if (real[j] == '\\')
|
||||
{
|
||||
real[j] = '/';
|
||||
}
|
||||
#endif
|
||||
// If the current character was preceeded by a delimiter special treatment is required:
|
||||
// If another deleimiter is encountered, remove it (do not write it to output string)
|
||||
// Otherwise test if it is a "." or ".." sequence.
|
||||
if (std::exchange(after_delim, path[i] == delim[0] || path[i] == delim[1]))
|
||||
{
|
||||
if (!after_delim)
|
||||
{
|
||||
if (real[j] == '.')
|
||||
{
|
||||
if (i + 1 == path.size())
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
get_char(i, j, 1);
|
||||
|
||||
switch (real[j])
|
||||
{
|
||||
case '.':
|
||||
{
|
||||
bool remove_element = true;
|
||||
usz k = 1;
|
||||
|
||||
for (; k + i != path.size(); k++)
|
||||
{
|
||||
switch (path[i + k])
|
||||
{
|
||||
case '.': continue;
|
||||
case delim[0]: case delim[1]: break;
|
||||
default: remove_element = false; break;
|
||||
}
|
||||
}
|
||||
|
||||
if (remove_element)
|
||||
{
|
||||
if (i == 1u)
|
||||
{
|
||||
j = pos_nondelim;
|
||||
real[j] = '\0';// Ensure termination at this posistion
|
||||
after_delim = true;
|
||||
i += k;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
get_char(i, j, k);
|
||||
continue;
|
||||
}
|
||||
case '/':
|
||||
{
|
||||
i++;
|
||||
after_delim = true;
|
||||
continue;
|
||||
}
|
||||
default: get_char(i, j, 1); continue;
|
||||
}
|
||||
}
|
||||
|
||||
pos_nondelim = j;
|
||||
get_char(i, j, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
i++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
get_char(i, j, 1);
|
||||
}
|
||||
}
|
||||
|
||||
if (j != umax && (real[j] == delim[0] || real[j] == delim[1])) j--; // Do not include a delmiter at the end
|
||||
|
||||
real.resize(j + 1);
|
||||
return real;
|
||||
}
|
||||
|
||||
u64 fs::get_dir_size(const std::string& path, u64 rounding_alignment)
|
||||
{
|
||||
u64 result = 0;
|
||||
@@ -1642,7 +1715,7 @@ u64 fs::get_dir_size(const std::string& path, u64 rounding_alignment)
|
||||
|
||||
if (!root_dir)
|
||||
{
|
||||
return static_cast<u64>(umax);
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (const auto& entry : root_dir)
|
||||
@@ -1654,7 +1727,7 @@ u64 fs::get_dir_size(const std::string& path, u64 rounding_alignment)
|
||||
|
||||
if (!entry.is_directory)
|
||||
{
|
||||
result += ::align(entry.size, rounding_alignment);
|
||||
result += utils::align(entry.size, rounding_alignment);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
+165
-62
@@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
#pragma once // No BOM and only basic ASCII in this header, or a neko will die
|
||||
|
||||
#include "types.h"
|
||||
#include "util/types.hpp"
|
||||
#include "bit_set.h"
|
||||
|
||||
#include <memory>
|
||||
@@ -8,12 +8,15 @@
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
|
||||
|
||||
namespace fs
|
||||
{
|
||||
#ifdef _WIN32
|
||||
static constexpr auto& delim = "/\\";
|
||||
static constexpr auto& wdelim = L"/\\";
|
||||
using native_handle = void*;
|
||||
#else
|
||||
static constexpr auto& delim = "/";
|
||||
static constexpr auto& wdelim = L"/";
|
||||
using native_handle = int;
|
||||
#endif
|
||||
|
||||
@@ -70,7 +73,7 @@ namespace fs
|
||||
struct iovec_clone
|
||||
{
|
||||
const void* iov_base;
|
||||
std::size_t iov_len;
|
||||
usz iov_len;
|
||||
};
|
||||
|
||||
// File handle base
|
||||
@@ -131,6 +134,12 @@ namespace fs
|
||||
virtual std::unique_ptr<dir_base> open_dir(const std::string& path) = 0;
|
||||
};
|
||||
|
||||
[[noreturn]] void xnull(const src_loc&);
|
||||
[[noreturn]] void xfail(const src_loc&);
|
||||
[[noreturn]] void xovfl();
|
||||
|
||||
constexpr struct pod_tag_t{} pod_tag;
|
||||
|
||||
// Get virtual device for specified path (nullptr for real path)
|
||||
std::shared_ptr<device_base> get_virtual_device(const std::string& path);
|
||||
|
||||
@@ -183,9 +192,6 @@ namespace fs
|
||||
{
|
||||
std::unique_ptr<file_base> m_file;
|
||||
|
||||
[[noreturn]] void xnull() const;
|
||||
[[noreturn]] void xfail() const;
|
||||
|
||||
public:
|
||||
// Default constructor
|
||||
file() = default;
|
||||
@@ -194,7 +200,7 @@ namespace fs
|
||||
explicit file(const std::string& path, bs_t<open_mode> mode = ::fs::read);
|
||||
|
||||
// Open memory for read
|
||||
explicit file(const void* ptr, std::size_t size);
|
||||
explicit file(const void* ptr, usz size);
|
||||
|
||||
// Open file with specified args (forward to constructor)
|
||||
template <typename... Args>
|
||||
@@ -227,144 +233,227 @@ namespace fs
|
||||
}
|
||||
|
||||
// Change file size (possibly appending zero bytes)
|
||||
bool trunc(u64 length) const
|
||||
bool trunc(u64 length,
|
||||
u32 line = __builtin_LINE(),
|
||||
u32 col = __builtin_COLUMN(),
|
||||
const char* file = __builtin_FILE(),
|
||||
const char* func = __builtin_FUNCTION()) const
|
||||
{
|
||||
if (!m_file) xnull();
|
||||
if (!m_file) xnull({line, col, file, func});
|
||||
return m_file->trunc(length);
|
||||
}
|
||||
|
||||
// Get file information
|
||||
stat_t stat() const
|
||||
stat_t stat(
|
||||
u32 line = __builtin_LINE(),
|
||||
u32 col = __builtin_COLUMN(),
|
||||
const char* file = __builtin_FILE(),
|
||||
const char* func = __builtin_FUNCTION()) const
|
||||
{
|
||||
if (!m_file) xnull();
|
||||
if (!m_file) xnull({line, col, file, func});
|
||||
return m_file->stat();
|
||||
}
|
||||
|
||||
// Sync file buffers
|
||||
void sync() const
|
||||
void sync(
|
||||
u32 line = __builtin_LINE(),
|
||||
u32 col = __builtin_COLUMN(),
|
||||
const char* file = __builtin_FILE(),
|
||||
const char* func = __builtin_FUNCTION()) const
|
||||
{
|
||||
if (!m_file) xnull();
|
||||
if (!m_file) xnull({line, col, file, func});
|
||||
return m_file->sync();
|
||||
}
|
||||
|
||||
// Read the data from the file and return the amount of data written in buffer
|
||||
u64 read(void* buffer, u64 count) const
|
||||
u64 read(void* buffer, u64 count,
|
||||
u32 line = __builtin_LINE(),
|
||||
u32 col = __builtin_COLUMN(),
|
||||
const char* file = __builtin_FILE(),
|
||||
const char* func = __builtin_FUNCTION()) const
|
||||
{
|
||||
if (!m_file) xnull();
|
||||
if (!m_file) xnull({line, col, file, func});
|
||||
return m_file->read(buffer, count);
|
||||
}
|
||||
|
||||
// Write the data to the file and return the amount of data actually written
|
||||
u64 write(const void* buffer, u64 count) const
|
||||
u64 write(const void* buffer, u64 count,
|
||||
u32 line = __builtin_LINE(),
|
||||
u32 col = __builtin_COLUMN(),
|
||||
const char* file = __builtin_FILE(),
|
||||
const char* func = __builtin_FUNCTION()) const
|
||||
{
|
||||
if (!m_file) xnull();
|
||||
if (!m_file) xnull({line, col, file, func});
|
||||
return m_file->write(buffer, count);
|
||||
}
|
||||
|
||||
// Change current position, returns resulting position
|
||||
u64 seek(s64 offset, seek_mode whence = seek_set) const
|
||||
u64 seek(s64 offset, seek_mode whence = seek_set,
|
||||
u32 line = __builtin_LINE(),
|
||||
u32 col = __builtin_COLUMN(),
|
||||
const char* file = __builtin_FILE(),
|
||||
const char* func = __builtin_FUNCTION()) const
|
||||
{
|
||||
if (!m_file) xnull();
|
||||
if (!m_file) xnull({line, col, file, func});
|
||||
return m_file->seek(offset, whence);
|
||||
}
|
||||
|
||||
// Get file size
|
||||
u64 size() const
|
||||
u64 size(
|
||||
u32 line = __builtin_LINE(),
|
||||
u32 col = __builtin_COLUMN(),
|
||||
const char* file = __builtin_FILE(),
|
||||
const char* func = __builtin_FUNCTION()) const
|
||||
{
|
||||
if (!m_file) xnull();
|
||||
if (!m_file) xnull({line, col, file, func});
|
||||
return m_file->size();
|
||||
}
|
||||
|
||||
// Get current position
|
||||
u64 pos() const
|
||||
u64 pos(
|
||||
u32 line = __builtin_LINE(),
|
||||
u32 col = __builtin_COLUMN(),
|
||||
const char* file = __builtin_FILE(),
|
||||
const char* func = __builtin_FUNCTION()) const
|
||||
{
|
||||
if (!m_file) xnull();
|
||||
if (!m_file) xnull({line, col, file, func});
|
||||
return m_file->seek(0, seek_cur);
|
||||
}
|
||||
|
||||
// Write std::string unconditionally
|
||||
const file& write(const std::string& str) const
|
||||
// Write std::basic_string unconditionally
|
||||
template <typename T>
|
||||
std::enable_if_t<std::is_trivially_copyable_v<T> && !std::is_pointer_v<T>, const file&> write(const std::basic_string<T>& str,
|
||||
u32 line = __builtin_LINE(),
|
||||
u32 col = __builtin_COLUMN(),
|
||||
const char* file = __builtin_FILE(),
|
||||
const char* func = __builtin_FUNCTION()) const
|
||||
{
|
||||
if (write(str.data(), str.size()) != str.size()) xfail();
|
||||
if (write(str.data(), str.size() * sizeof(T), line, col, file, func) != str.size() * sizeof(T)) xfail({line, col, file, func});
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Write POD unconditionally
|
||||
template <typename T>
|
||||
std::enable_if_t<std::is_trivially_copyable_v<T> && !std::is_pointer_v<T>, const file&> write(const T& data) const
|
||||
std::enable_if_t<std::is_trivially_copyable_v<T> && !std::is_pointer_v<T>, const file&> write(const T& data,
|
||||
pod_tag_t = pod_tag,
|
||||
u32 line = __builtin_LINE(),
|
||||
u32 col = __builtin_COLUMN(),
|
||||
const char* file = __builtin_FILE(),
|
||||
const char* func = __builtin_FUNCTION()) const
|
||||
{
|
||||
if (write(std::addressof(data), sizeof(T)) != sizeof(T)) xfail();
|
||||
if (write(std::addressof(data), sizeof(T), line, col, file, func) != sizeof(T)) xfail({line, col, file, func});
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Write POD std::vector unconditionally
|
||||
template <typename T>
|
||||
std::enable_if_t<std::is_trivially_copyable_v<T> && !std::is_pointer_v<T>, const file&> write(const std::vector<T>& vec) const
|
||||
std::enable_if_t<std::is_trivially_copyable_v<T> && !std::is_pointer_v<T>, const file&> write(const std::vector<T>& vec,
|
||||
u32 line = __builtin_LINE(),
|
||||
u32 col = __builtin_COLUMN(),
|
||||
const char* file = __builtin_FILE(),
|
||||
const char* func = __builtin_FUNCTION()) const
|
||||
{
|
||||
if (write(vec.data(), vec.size() * sizeof(T)) != vec.size() * sizeof(T)) xfail();
|
||||
if (write(vec.data(), vec.size() * sizeof(T), line, col, file, func) != vec.size() * sizeof(T)) xfail({line, col, file, func});
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Read std::string, size must be set by resize() method
|
||||
bool read(std::string& str) const
|
||||
// Read std::basic_string, size must be set by resize() method
|
||||
template <typename T>
|
||||
std::enable_if_t<std::is_trivially_copyable_v<T> && !std::is_pointer_v<T>, bool> read(std::basic_string<T>& str,
|
||||
const char* file = __builtin_FILE(),
|
||||
const char* func = __builtin_FUNCTION(),
|
||||
u32 line = __builtin_LINE(),
|
||||
u32 col = __builtin_COLUMN()) const
|
||||
{
|
||||
return read(&str[0], str.size()) == str.size();
|
||||
return read(&str[0], str.size() * sizeof(T), line, col, file, func) == str.size() * sizeof(T);
|
||||
}
|
||||
|
||||
// Read std::string
|
||||
bool read(std::string& str, std::size_t size) const
|
||||
// Read std::basic_string
|
||||
template <typename T>
|
||||
std::enable_if_t<std::is_trivially_copyable_v<T> && !std::is_pointer_v<T>, bool> read(std::basic_string<T>& str, usz size,
|
||||
const char* file = __builtin_FILE(),
|
||||
const char* func = __builtin_FUNCTION(),
|
||||
u32 line = __builtin_LINE(),
|
||||
u32 col = __builtin_COLUMN()) const
|
||||
{
|
||||
str.resize(size);
|
||||
return read(&str[0], size) == size;
|
||||
return read(&str[0], size * sizeof(T), line, col, file, func) == size * sizeof(T);
|
||||
}
|
||||
|
||||
// Read POD, sizeof(T) is used
|
||||
template <typename T>
|
||||
std::enable_if_t<std::is_trivially_copyable_v<T> && !std::is_pointer_v<T>, bool> read(T& data) const
|
||||
std::enable_if_t<std::is_trivially_copyable_v<T> && !std::is_pointer_v<T>, bool> read(T& data,
|
||||
pod_tag_t = pod_tag,
|
||||
u32 line = __builtin_LINE(),
|
||||
u32 col = __builtin_COLUMN(),
|
||||
const char* file = __builtin_FILE(),
|
||||
const char* func = __builtin_FUNCTION()) const
|
||||
{
|
||||
return read(&data, sizeof(T)) == sizeof(T);
|
||||
return read(&data, sizeof(T), line, col, file, func) == sizeof(T);
|
||||
}
|
||||
|
||||
// Read POD std::vector, size must be set by resize() method
|
||||
template <typename T>
|
||||
std::enable_if_t<std::is_trivially_copyable_v<T> && !std::is_pointer_v<T>, bool> read(std::vector<T>& vec) const
|
||||
std::enable_if_t<std::is_trivially_copyable_v<T> && !std::is_pointer_v<T>, bool> read(std::vector<T>& vec,
|
||||
const char* file = __builtin_FILE(),
|
||||
const char* func = __builtin_FUNCTION(),
|
||||
u32 line = __builtin_LINE(),
|
||||
u32 col = __builtin_COLUMN()) const
|
||||
{
|
||||
return read(vec.data(), sizeof(T) * vec.size()) == sizeof(T) * vec.size();
|
||||
return read(vec.data(), sizeof(T) * vec.size(), line, col, file, func) == sizeof(T) * vec.size();
|
||||
}
|
||||
|
||||
// Read POD std::vector
|
||||
template <typename T>
|
||||
std::enable_if_t<std::is_trivially_copyable_v<T> && !std::is_pointer_v<T>, bool> read(std::vector<T>& vec, std::size_t size) const
|
||||
std::enable_if_t<std::is_trivially_copyable_v<T> && !std::is_pointer_v<T>, bool> read(std::vector<T>& vec, usz size,
|
||||
const char* file = __builtin_FILE(),
|
||||
const char* func = __builtin_FUNCTION(),
|
||||
u32 line = __builtin_LINE(),
|
||||
u32 col = __builtin_COLUMN()) const
|
||||
{
|
||||
vec.resize(size);
|
||||
return read(vec.data(), sizeof(T) * size) == sizeof(T) * size;
|
||||
return read(vec.data(), sizeof(T) * size, line, col, file, func) == sizeof(T) * size;
|
||||
}
|
||||
|
||||
// Read POD (experimental)
|
||||
template <typename T>
|
||||
std::enable_if_t<std::is_trivially_copyable_v<T> && !std::is_pointer_v<T>, T> read() const
|
||||
std::enable_if_t<std::is_trivially_copyable_v<T> && !std::is_pointer_v<T>, T> read(
|
||||
pod_tag_t = pod_tag,
|
||||
u32 line = __builtin_LINE(),
|
||||
u32 col = __builtin_COLUMN(),
|
||||
const char* file = __builtin_FILE(),
|
||||
const char* func = __builtin_FUNCTION()) const
|
||||
{
|
||||
T result;
|
||||
if (!read(result)) xfail();
|
||||
if (!read(result, pod_tag, line, col, file, func)) xfail({line, col, file, func});
|
||||
return result;
|
||||
}
|
||||
|
||||
// Read full file to std::string
|
||||
std::string to_string() const
|
||||
// Read full file to std::basic_string
|
||||
template <typename T = char>
|
||||
std::basic_string<T> to_string(
|
||||
u32 line = __builtin_LINE(),
|
||||
u32 col = __builtin_COLUMN(),
|
||||
const char* file = __builtin_FILE(),
|
||||
const char* func = __builtin_FUNCTION()) const
|
||||
{
|
||||
std::string result;
|
||||
result.resize(size());
|
||||
if (seek(0), !read(result)) xfail();
|
||||
std::basic_string<T> result;
|
||||
result.resize(size() / sizeof(T));
|
||||
if (seek(0), !read(result, file, func, line, col)) xfail({line, col, file, func});
|
||||
return result;
|
||||
}
|
||||
|
||||
// Read full file to std::vector
|
||||
template<typename T>
|
||||
std::enable_if_t<std::is_trivially_copyable_v<T> && !std::is_pointer_v<T>, std::vector<T>> to_vector() const
|
||||
std::enable_if_t<std::is_trivially_copyable_v<T> && !std::is_pointer_v<T>, std::vector<T>> to_vector(
|
||||
u32 line = __builtin_LINE(),
|
||||
u32 col = __builtin_COLUMN(),
|
||||
const char* file = __builtin_FILE(),
|
||||
const char* func = __builtin_FUNCTION()) const
|
||||
{
|
||||
std::vector<T> result;
|
||||
result.resize(size() / sizeof(T));
|
||||
if (seek(0), !read(result)) xfail();
|
||||
if (seek(0), !read(result, file, func, line, col)) xfail({line, col, file, func});
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -372,9 +461,13 @@ namespace fs
|
||||
native_handle get_handle() const;
|
||||
|
||||
// Gathered write
|
||||
u64 write_gather(const iovec_clone* buffers, u64 buf_count) const
|
||||
u64 write_gather(const iovec_clone* buffers, u64 buf_count,
|
||||
u32 line = __builtin_LINE(),
|
||||
u32 col = __builtin_COLUMN(),
|
||||
const char* file = __builtin_FILE(),
|
||||
const char* func = __builtin_FUNCTION()) const
|
||||
{
|
||||
if (!m_file) xnull();
|
||||
if (!m_file) xnull({line, col, file, func});
|
||||
return m_file->write_gather(buffers, buf_count);
|
||||
}
|
||||
};
|
||||
@@ -383,8 +476,6 @@ namespace fs
|
||||
{
|
||||
std::unique_ptr<dir_base> m_dir;
|
||||
|
||||
[[noreturn]] void xnull() const;
|
||||
|
||||
public:
|
||||
dir() = default;
|
||||
|
||||
@@ -420,16 +511,24 @@ namespace fs
|
||||
}
|
||||
|
||||
// Get next directory entry
|
||||
bool read(dir_entry& out) const
|
||||
bool read(dir_entry& out,
|
||||
u32 line = __builtin_LINE(),
|
||||
u32 col = __builtin_COLUMN(),
|
||||
const char* file = __builtin_FILE(),
|
||||
const char* func = __builtin_FUNCTION()) const
|
||||
{
|
||||
if (!m_dir) xnull();
|
||||
if (!m_dir) xnull({line, col, file, func});
|
||||
return m_dir->read(out);
|
||||
}
|
||||
|
||||
// Reset to the beginning
|
||||
void rewind() const
|
||||
void rewind(
|
||||
u32 line = __builtin_LINE(),
|
||||
u32 col = __builtin_COLUMN(),
|
||||
const char* file = __builtin_FILE(),
|
||||
const char* func = __builtin_FUNCTION()) const
|
||||
{
|
||||
if (!m_dir) xnull();
|
||||
if (!m_dir) xnull({line, col, file, func});
|
||||
return m_dir->rewind();
|
||||
}
|
||||
|
||||
@@ -498,6 +597,9 @@ namespace fs
|
||||
// Get common cache directory
|
||||
const std::string& get_cache_dir();
|
||||
|
||||
// Get real path for comparisons (TODO: investigate std::filesystem::path::compare implementation)
|
||||
std::string escape_path(std::string_view path);
|
||||
|
||||
// Delete directory and all its contents recursively
|
||||
bool remove_all(const std::string& path, bool remove_root = true);
|
||||
|
||||
@@ -572,7 +674,7 @@ namespace fs
|
||||
|
||||
if (old_size + size < old_size)
|
||||
{
|
||||
fmt::raw_error("fs::container_stream<>::write(): overflow");
|
||||
xovfl();
|
||||
}
|
||||
|
||||
if (pos > old_size)
|
||||
@@ -628,7 +730,8 @@ namespace fs
|
||||
template <typename... Args>
|
||||
bool write_file(const std::string& path, bs_t<fs::open_mode> mode, const Args&... args)
|
||||
{
|
||||
if (fs::file f{path, mode})
|
||||
// Always use write flag, remove read flag
|
||||
if (fs::file f{path, mode + fs::write - fs::read})
|
||||
{
|
||||
// Write args sequentially
|
||||
(f.write(args), ...);
|
||||
|
||||
+150
-624
@@ -1,16 +1,16 @@
|
||||
#include "types.h"
|
||||
#include "util/types.hpp"
|
||||
#include "util/sysinfo.hpp"
|
||||
#include "JIT.h"
|
||||
#include "StrFmt.h"
|
||||
#include "File.h"
|
||||
#include "util/logs.hpp"
|
||||
#include "mutex.h"
|
||||
#include "sysinfo.h"
|
||||
#include "VirtualMemory.h"
|
||||
#include "util/vm.hpp"
|
||||
#include "util/asm.hpp"
|
||||
#include <immintrin.h>
|
||||
#include <zlib.h>
|
||||
|
||||
#ifdef __linux__
|
||||
#include <sys/mman.h>
|
||||
#define CAN_OVERCOMMIT
|
||||
#endif
|
||||
|
||||
@@ -22,11 +22,8 @@ static u8* get_jit_memory()
|
||||
static void* const s_memory2 = []() -> void*
|
||||
{
|
||||
void* ptr = utils::memory_reserve(0x80000000);
|
||||
|
||||
#ifdef CAN_OVERCOMMIT
|
||||
utils::memory_commit(ptr, 0x80000000);
|
||||
utils::memory_protect(ptr, 0x40000000, utils::protection::wx);
|
||||
#endif
|
||||
return ptr;
|
||||
}();
|
||||
|
||||
@@ -40,7 +37,7 @@ static atomic_t<u64> s_code_pos{0}, s_data_pos{0};
|
||||
static std::vector<u8> s_code_init, s_data_init;
|
||||
|
||||
template <atomic_t<u64>& Ctr, uint Off, utils::protection Prot>
|
||||
static u8* add_jit_memory(std::size_t size, uint align)
|
||||
static u8* add_jit_memory(usz size, uint align)
|
||||
{
|
||||
// Select subrange
|
||||
u8* pointer = get_jit_memory() + Off;
|
||||
@@ -56,8 +53,8 @@ static u8* add_jit_memory(std::size_t size, uint align)
|
||||
// Simple allocation by incrementing pointer to the next free data
|
||||
const u64 pos = Ctr.atomic_op([&](u64& ctr) -> u64
|
||||
{
|
||||
const u64 _pos = ::align(ctr & 0xffff'ffff, align);
|
||||
const u64 _new = ::align(_pos + size, align);
|
||||
const u64 _pos = utils::align(ctr & 0xffff'ffff, align);
|
||||
const u64 _new = utils::align(_pos + size, align);
|
||||
|
||||
if (_new > 0x40000000) [[unlikely]]
|
||||
{
|
||||
@@ -73,7 +70,7 @@ static u8* add_jit_memory(std::size_t size, uint align)
|
||||
// Check the necessity to commit more memory
|
||||
if (_new > olda) [[unlikely]]
|
||||
{
|
||||
newa = ::align(_new, 0x100000);
|
||||
newa = utils::align(_new, 0x200000);
|
||||
}
|
||||
|
||||
ctr += _new - (ctr & 0xffff'ffff);
|
||||
@@ -82,15 +79,13 @@ static u8* add_jit_memory(std::size_t size, uint align)
|
||||
|
||||
if (pos == umax) [[unlikely]]
|
||||
{
|
||||
jit_log.warning("JIT: Out of memory (size=0x%x, align=0x%x, off=0x%x)", size, align, Off);
|
||||
jit_log.error("JIT: Out of memory (size=0x%x, align=0x%x, off=0x%x)", size, align, Off);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (olda != newa) [[unlikely]]
|
||||
{
|
||||
#ifdef CAN_OVERCOMMIT
|
||||
madvise(pointer + olda, newa - olda, MADV_WILLNEED);
|
||||
#else
|
||||
#ifndef CAN_OVERCOMMIT
|
||||
// Commit more memory
|
||||
utils::memory_commit(pointer + olda, newa - olda, Prot);
|
||||
#endif
|
||||
@@ -118,7 +113,7 @@ jit_runtime::~jit_runtime()
|
||||
|
||||
asmjit::Error jit_runtime::_add(void** dst, asmjit::CodeHolder* code) noexcept
|
||||
{
|
||||
std::size_t codeSize = code->getCodeSize();
|
||||
usz codeSize = code->getCodeSize();
|
||||
if (!codeSize) [[unlikely]]
|
||||
{
|
||||
*dst = nullptr;
|
||||
@@ -132,7 +127,7 @@ asmjit::Error jit_runtime::_add(void** dst, asmjit::CodeHolder* code) noexcept
|
||||
return asmjit::kErrorNoVirtualMemory;
|
||||
}
|
||||
|
||||
std::size_t relocSize = code->relocate(p);
|
||||
usz relocSize = code->relocate(p);
|
||||
if (!relocSize) [[unlikely]]
|
||||
{
|
||||
*dst = nullptr;
|
||||
@@ -150,7 +145,7 @@ asmjit::Error jit_runtime::_release(void* ptr) noexcept
|
||||
return asmjit::kErrorOk;
|
||||
}
|
||||
|
||||
u8* jit_runtime::alloc(std::size_t size, uint align, bool exec) noexcept
|
||||
u8* jit_runtime::alloc(usz size, uint align, bool exec) noexcept
|
||||
{
|
||||
if (exec)
|
||||
{
|
||||
@@ -194,56 +189,78 @@ void jit_runtime::finalize() noexcept
|
||||
std::memcpy(alloc(s_data_init.size(), 1, false), s_data_init.data(), s_data_init.size());
|
||||
}
|
||||
|
||||
asmjit::JitRuntime& asmjit::get_global_runtime()
|
||||
asmjit::Runtime& asmjit::get_global_runtime()
|
||||
{
|
||||
// 16 MiB for internal needs
|
||||
static constexpr u64 size = 1024 * 1024 * 16;
|
||||
|
||||
struct custom_runtime final : asmjit::HostRuntime
|
||||
{
|
||||
custom_runtime() noexcept
|
||||
{
|
||||
// Search starting in first 2 GiB of memory
|
||||
for (u64 addr = size;; addr += size)
|
||||
{
|
||||
if (auto ptr = utils::memory_reserve(size, reinterpret_cast<void*>(addr)))
|
||||
{
|
||||
m_pos.raw() = static_cast<std::byte*>(ptr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize "end" pointer
|
||||
m_max = m_pos + size;
|
||||
|
||||
// Make memory writable + executable
|
||||
utils::memory_commit(m_pos, size, utils::protection::wx);
|
||||
}
|
||||
|
||||
asmjit::Error _add(void** dst, asmjit::CodeHolder* code) noexcept override
|
||||
{
|
||||
usz codeSize = code->getCodeSize();
|
||||
if (!codeSize) [[unlikely]]
|
||||
{
|
||||
*dst = nullptr;
|
||||
return asmjit::kErrorNoCodeGenerated;
|
||||
}
|
||||
|
||||
void* p = m_pos.fetch_add(utils::align(codeSize, 4096));
|
||||
if (!p || m_pos > m_max) [[unlikely]]
|
||||
{
|
||||
*dst = nullptr;
|
||||
return asmjit::kErrorNoVirtualMemory;
|
||||
}
|
||||
|
||||
usz relocSize = code->relocate(p);
|
||||
if (!relocSize) [[unlikely]]
|
||||
{
|
||||
*dst = nullptr;
|
||||
return asmjit::kErrorInvalidState;
|
||||
}
|
||||
|
||||
utils::memory_protect(p, utils::align(codeSize, 4096), utils::protection::rx);
|
||||
flush(p, relocSize);
|
||||
*dst = p;
|
||||
|
||||
return asmjit::kErrorOk;
|
||||
}
|
||||
|
||||
asmjit::Error _release(void* ptr) noexcept override
|
||||
{
|
||||
return asmjit::kErrorOk;
|
||||
}
|
||||
|
||||
private:
|
||||
atomic_t<std::byte*> m_pos{};
|
||||
|
||||
std::byte* m_max{};
|
||||
};
|
||||
|
||||
// Magic static
|
||||
static asmjit::JitRuntime g_rt;
|
||||
static custom_runtime g_rt;
|
||||
return g_rt;
|
||||
}
|
||||
|
||||
void asmjit::build_transaction_enter(asmjit::X86Assembler& c, asmjit::Label fallback, const asmjit::X86Gp& ctr, uint less_than)
|
||||
{
|
||||
Label fall = c.newLabel();
|
||||
Label begin = c.newLabel();
|
||||
c.jmp(begin);
|
||||
c.bind(fall);
|
||||
|
||||
if (less_than < 65)
|
||||
{
|
||||
c.add(ctr, 1);
|
||||
c.test(x86::eax, _XABORT_RETRY);
|
||||
c.jz(fallback);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Don't repeat on explicit XABORT instruction (workaround)
|
||||
c.test(x86::eax, _XABORT_EXPLICIT);
|
||||
c.jnz(fallback);
|
||||
|
||||
// Count an attempt without RETRY flag as 65 normal attempts and continue
|
||||
c.push(x86::rax);
|
||||
c.not_(x86::eax);
|
||||
c.and_(x86::eax, _XABORT_RETRY);
|
||||
c.shl(x86::eax, 5);
|
||||
c.add(x86::eax, 1); // eax = RETRY ? 1 : 65
|
||||
c.add(ctr, x86::rax);
|
||||
c.pop(x86::rax);
|
||||
}
|
||||
|
||||
c.cmp(ctr, less_than);
|
||||
c.jae(fallback);
|
||||
c.align(kAlignCode, 16);
|
||||
c.bind(begin);
|
||||
c.xbegin(fall);
|
||||
}
|
||||
|
||||
void asmjit::build_transaction_abort(asmjit::X86Assembler& c, unsigned char code)
|
||||
{
|
||||
c.db(0xc6);
|
||||
c.db(0xf8);
|
||||
c.db(code);
|
||||
}
|
||||
|
||||
#ifdef LLVM_AVAILABLE
|
||||
|
||||
#include <unordered_map>
|
||||
@@ -263,9 +280,9 @@ void asmjit::build_transaction_abort(asmjit::X86Assembler& c, unsigned char code
|
||||
#endif
|
||||
#include "llvm/Support/TargetSelect.h"
|
||||
#include "llvm/Support/FormattedStream.h"
|
||||
#include "llvm/Support/Host.h"
|
||||
#include "llvm/ExecutionEngine/ExecutionEngine.h"
|
||||
#include "llvm/ExecutionEngine/RTDyldMemoryManager.h"
|
||||
#include "llvm/ExecutionEngine/JITEventListener.h"
|
||||
#include "llvm/ExecutionEngine/ObjectCache.h"
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
@@ -279,478 +296,102 @@ void asmjit::build_transaction_abort(asmjit::X86Assembler& c, unsigned char code
|
||||
#include <sys/mman.h>
|
||||
#endif
|
||||
|
||||
class LLVMSegmentAllocator
|
||||
const bool jit_initialize = []() -> bool
|
||||
{
|
||||
public:
|
||||
// Size of virtual memory area reserved: default 512MB
|
||||
static constexpr u32 DEFAULT_SEGMENT_SIZE = 0x20000000;
|
||||
llvm::InitializeNativeTarget();
|
||||
llvm::InitializeNativeTargetAsmPrinter();
|
||||
llvm::InitializeNativeTargetAsmParser();
|
||||
LLVMLinkInMCJIT();
|
||||
return true;
|
||||
}();
|
||||
|
||||
LLVMSegmentAllocator()
|
||||
{
|
||||
llvm::InitializeNativeTarget();
|
||||
llvm::InitializeNativeTargetAsmPrinter();
|
||||
llvm::InitializeNativeTargetAsmParser();
|
||||
LLVMLinkInMCJIT();
|
||||
|
||||
// Try to reserve as much virtual memory in the first 2 GB address space beforehand, if possible.
|
||||
Segment found_segs[16];
|
||||
u32 num_segs = 0;
|
||||
#ifdef MAP_32BIT
|
||||
u64 max_size = 0x80000000u;
|
||||
while (num_segs < 16)
|
||||
{
|
||||
auto ptr = ::mmap(nullptr, max_size, PROT_NONE, MAP_ANON | MAP_PRIVATE | MAP_32BIT, -1, 0);
|
||||
if (ptr != reinterpret_cast<void*>(-1))
|
||||
found_segs[num_segs++] = Segment(ptr, static_cast<u32>(max_size));
|
||||
else if (max_size > 0x1000000)
|
||||
max_size -= 0x1000000;
|
||||
else
|
||||
break;
|
||||
}
|
||||
#else
|
||||
u64 start_addr = 0x10000000;
|
||||
while (num_segs < 16)
|
||||
{
|
||||
u64 max_addr = 0;
|
||||
u64 max_size = 0x1000000;
|
||||
for (u64 addr = start_addr; addr <= (0x80000000u - max_size); addr += 0x1000000)
|
||||
{
|
||||
for (auto curr_size = max_size; (0x80000000u - curr_size) >= addr; curr_size += 0x1000000)
|
||||
{
|
||||
if (auto ptr = utils::memory_reserve(curr_size, reinterpret_cast<void*>(addr)))
|
||||
{
|
||||
if (max_addr == 0 || max_size < curr_size)
|
||||
{
|
||||
max_addr = addr;
|
||||
max_size = curr_size;
|
||||
}
|
||||
utils::memory_release(ptr, curr_size);
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (max_addr == 0)
|
||||
break;
|
||||
|
||||
if (auto ptr = utils::memory_reserve(max_size, reinterpret_cast<void*>(max_addr)))
|
||||
found_segs[num_segs++] = Segment(ptr, static_cast<u32>(max_size));
|
||||
|
||||
start_addr = max_addr + max_size;
|
||||
}
|
||||
#endif
|
||||
if (num_segs)
|
||||
{
|
||||
if (num_segs > 1)
|
||||
{
|
||||
m_segs.resize(num_segs);
|
||||
for (u32 i = 0; i < num_segs; i++)
|
||||
m_segs[i] = found_segs[i];
|
||||
}
|
||||
else
|
||||
m_curr = found_segs[0];
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (auto ptr = utils::memory_reserve(DEFAULT_SEGMENT_SIZE))
|
||||
{
|
||||
m_curr.addr = static_cast<u8*>(ptr);
|
||||
m_curr.size = DEFAULT_SEGMENT_SIZE;
|
||||
m_curr.used = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void* allocate(u32 size)
|
||||
{
|
||||
if (m_curr.remaining() >= size)
|
||||
return m_curr.advance(size);
|
||||
|
||||
if (reserve(size))
|
||||
return m_curr.advance(size);
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool reserve(u32 size)
|
||||
{
|
||||
if (size == 0)
|
||||
return true;
|
||||
|
||||
store_curr();
|
||||
|
||||
u32 best_idx = UINT_MAX;
|
||||
for (u32 i = 0, segs_size = ::size32(m_segs); i < segs_size; i++)
|
||||
{
|
||||
const auto seg_remaining = m_segs[i].remaining();
|
||||
if (seg_remaining < size)
|
||||
continue;
|
||||
|
||||
if (best_idx == UINT_MAX || m_segs[best_idx].remaining() > seg_remaining)
|
||||
best_idx = i;
|
||||
}
|
||||
|
||||
if (best_idx == UINT_MAX)
|
||||
{
|
||||
const auto size_to_reserve = (size > DEFAULT_SEGMENT_SIZE) ? ::align(size+4096, 4096) : DEFAULT_SEGMENT_SIZE;
|
||||
if (auto ptr = utils::memory_reserve(size_to_reserve))
|
||||
{
|
||||
best_idx = ::size32(m_segs);
|
||||
m_segs.emplace_back(ptr, size_to_reserve);
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto& best_seg = m_segs[best_idx];
|
||||
if (best_seg.addr != m_curr.addr)
|
||||
m_curr = best_seg;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::pair<u64, u32> current_segment() const
|
||||
{
|
||||
return std::make_pair(reinterpret_cast<u64>(m_curr.addr), m_curr.size);
|
||||
}
|
||||
|
||||
std::pair<u64, u32> find_segment(u64 addr) const
|
||||
{
|
||||
for (const auto& seg: m_segs)
|
||||
{
|
||||
const u64 seg_addr = reinterpret_cast<u64>(seg.addr);
|
||||
if (addr < seg_addr)
|
||||
continue;
|
||||
|
||||
const auto end_addr = seg_addr + seg.size;
|
||||
if (addr < end_addr)
|
||||
return std::make_pair(seg_addr, seg.size);
|
||||
}
|
||||
|
||||
return std::make_pair(0, 0);
|
||||
}
|
||||
|
||||
void reset()
|
||||
{
|
||||
if (m_segs.empty())
|
||||
{
|
||||
if (m_curr.addr != nullptr)
|
||||
{
|
||||
utils::memory_decommit(m_curr.addr, m_curr.size);
|
||||
m_curr.used = 0;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (store_curr())
|
||||
m_curr = Segment();
|
||||
|
||||
auto allocated_it = std::remove_if(m_segs.begin(), m_segs.end(), [](const Segment& seg)
|
||||
{
|
||||
return reinterpret_cast<u64>(seg.addr + seg.size) > 0x80000000u;
|
||||
});
|
||||
if (allocated_it != m_segs.end())
|
||||
{
|
||||
for (auto it = allocated_it; it != m_segs.end(); ++it)
|
||||
utils::memory_release(it->addr, it->size);
|
||||
|
||||
m_segs.erase(allocated_it, m_segs.end());
|
||||
}
|
||||
|
||||
for (auto& seg : m_segs)
|
||||
{
|
||||
utils::memory_decommit(seg.addr, seg.size);
|
||||
seg.used = 0;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
bool store_curr()
|
||||
{
|
||||
if (m_curr.addr != nullptr)
|
||||
{
|
||||
const auto wanted_addr = m_curr.addr;
|
||||
auto existing_it = std::find_if(m_segs.begin(), m_segs.end(), [wanted_addr](const Segment& seg) { return seg.addr == wanted_addr; });
|
||||
if (existing_it != m_segs.end())
|
||||
existing_it->used = m_curr.used;
|
||||
else
|
||||
m_segs.push_back(m_curr);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
struct Segment
|
||||
{
|
||||
Segment() {}
|
||||
Segment(void* addr, u32 size)
|
||||
: addr(static_cast<u8*>(addr))
|
||||
, size(size)
|
||||
{}
|
||||
|
||||
u8* addr = nullptr;
|
||||
u32 size = 0;
|
||||
u32 used = 0;
|
||||
|
||||
u32 remaining() const
|
||||
{
|
||||
if (size > used)
|
||||
return size - used;
|
||||
|
||||
return 0;
|
||||
}
|
||||
void* advance(u32 offset)
|
||||
{
|
||||
const auto prev_used = used;
|
||||
used += offset;
|
||||
return &addr[prev_used];
|
||||
}
|
||||
};
|
||||
|
||||
Segment m_curr;
|
||||
std::vector<Segment> m_segs;
|
||||
};
|
||||
|
||||
// Memory manager mutex
|
||||
static shared_mutex s_mutex;
|
||||
// LLVM Memory allocator
|
||||
static LLVMSegmentAllocator s_alloc;
|
||||
|
||||
#ifdef _WIN32
|
||||
static std::deque<std::pair<u64, std::vector<RUNTIME_FUNCTION>>> s_unwater;
|
||||
static std::vector<std::vector<RUNTIME_FUNCTION>> s_unwind; // .pdata
|
||||
#else
|
||||
static std::deque<std::pair<u8*, std::size_t>> s_unfire;
|
||||
#endif
|
||||
|
||||
// Reset memory manager
|
||||
extern void jit_finalize()
|
||||
// Simple memory manager
|
||||
struct MemoryManager1 : llvm::RTDyldMemoryManager
|
||||
{
|
||||
#ifdef _WIN32
|
||||
for (auto&& unwind : s_unwind)
|
||||
{
|
||||
if (!RtlDeleteFunctionTable(unwind.data()))
|
||||
{
|
||||
jit_log.fatal("RtlDeleteFunctionTable() failed! Error %u", GetLastError());
|
||||
}
|
||||
}
|
||||
|
||||
s_unwind.clear();
|
||||
#else
|
||||
for (auto&& t : s_unfire)
|
||||
{
|
||||
llvm::RTDyldMemoryManager::deregisterEHFramesInProcess(t.first, t.second);
|
||||
}
|
||||
|
||||
s_unfire.clear();
|
||||
#endif
|
||||
|
||||
s_alloc.reset();
|
||||
}
|
||||
|
||||
// Helper class
|
||||
struct MemoryManager : llvm::RTDyldMemoryManager
|
||||
{
|
||||
std::unordered_map<std::string, u64>& m_link;
|
||||
|
||||
std::array<u8, 16>* m_tramps{};
|
||||
|
||||
u8* m_code_addr{}; // TODO
|
||||
|
||||
MemoryManager(std::unordered_map<std::string, u64>& table)
|
||||
: m_link(table)
|
||||
// 256 MiB for code or data
|
||||
static constexpr u64 c_max_size = 0x20000000 / 2;
|
||||
|
||||
// Allocation unit (2M)
|
||||
static constexpr u64 c_page_size = 2 * 1024 * 1024;
|
||||
|
||||
// Reserve 512 MiB
|
||||
u8* const ptr = static_cast<u8*>(utils::memory_reserve(c_max_size * 2));
|
||||
|
||||
u64 code_ptr = 0;
|
||||
u64 data_ptr = c_max_size;
|
||||
|
||||
MemoryManager1() = default;
|
||||
|
||||
~MemoryManager1() override
|
||||
{
|
||||
utils::memory_release(ptr, c_max_size * 2);
|
||||
}
|
||||
|
||||
[[noreturn]] static void null()
|
||||
{
|
||||
fmt::throw_exception("Null function" HERE);
|
||||
fmt::throw_exception("Null function");
|
||||
}
|
||||
|
||||
llvm::JITSymbol findSymbol(const std::string& name) override
|
||||
{
|
||||
auto& addr = m_link[name];
|
||||
u64 addr = RTDyldMemoryManager::getSymbolAddress(name);
|
||||
|
||||
// Find function address
|
||||
if (!addr)
|
||||
{
|
||||
addr = RTDyldMemoryManager::getSymbolAddress(name);
|
||||
|
||||
if (addr)
|
||||
{
|
||||
jit_log.warning("LLVM: Symbol requested: %s -> 0x%016llx", name, addr);
|
||||
}
|
||||
else
|
||||
{
|
||||
jit_log.error("LLVM: Linkage failed: %s", name);
|
||||
addr = reinterpret_cast<u64>(null);
|
||||
}
|
||||
}
|
||||
|
||||
// Verify address for small code model
|
||||
const u64 code_start = reinterpret_cast<u64>(m_code_addr);
|
||||
const s64 addr_diff = addr - code_start;
|
||||
if (addr_diff < INT_MIN || addr_diff > INT_MAX)
|
||||
{
|
||||
// Lock memory manager
|
||||
std::lock_guard lock(s_mutex);
|
||||
|
||||
// Allocate memory for trampolines
|
||||
if (m_tramps)
|
||||
{
|
||||
const s64 tramps_diff = reinterpret_cast<u64>(m_tramps) - code_start;
|
||||
if (tramps_diff < INT_MIN || tramps_diff > INT_MAX)
|
||||
m_tramps = nullptr; //previously allocated trampoline section too far away now
|
||||
}
|
||||
|
||||
if (!m_tramps)
|
||||
{
|
||||
m_tramps = reinterpret_cast<decltype(m_tramps)>(s_alloc.allocate(4096));
|
||||
utils::memory_commit(m_tramps, 4096, utils::protection::wx);
|
||||
}
|
||||
|
||||
// Create a trampoline
|
||||
auto& data = *m_tramps++;
|
||||
data[0x0] = 0xff; // JMP [rip+2]
|
||||
data[0x1] = 0x25;
|
||||
data[0x2] = 0x02;
|
||||
data[0x3] = 0x00;
|
||||
data[0x4] = 0x00;
|
||||
data[0x5] = 0x00;
|
||||
data[0x6] = 0x48; // MOV rax, imm64 (not executed)
|
||||
data[0x7] = 0xb8;
|
||||
std::memcpy(data.data() + 8, &addr, 8);
|
||||
addr = reinterpret_cast<u64>(&data);
|
||||
|
||||
// Reset pointer (memory page exhausted)
|
||||
if ((reinterpret_cast<u64>(m_tramps) % 4096) == 0)
|
||||
{
|
||||
m_tramps = nullptr;
|
||||
}
|
||||
addr = reinterpret_cast<uptr>(&null);
|
||||
}
|
||||
|
||||
return {addr, llvm::JITSymbolFlags::Exported};
|
||||
}
|
||||
|
||||
bool needsToReserveAllocationSpace() override { return true; }
|
||||
void reserveAllocationSpace(uintptr_t CodeSize, uint32_t CodeAlign, uintptr_t RODataSize, uint32_t RODataAlign, uintptr_t RWDataSize, uint32_t RWDataAlign) override
|
||||
u8* allocate(u64& oldp, uptr size, uint align, utils::protection prot)
|
||||
{
|
||||
const u32 wanted_code_size = ::align(static_cast<u32>(CodeSize), std::min(4096u, CodeAlign));
|
||||
const u32 wanted_rodata_size = ::align(static_cast<u32>(RODataSize), std::min(4096u, RODataAlign));
|
||||
const u32 wanted_rwdata_size = ::align(static_cast<u32>(RWDataSize), std::min(4096u, RWDataAlign));
|
||||
|
||||
// Lock memory manager
|
||||
std::lock_guard lock(s_mutex);
|
||||
|
||||
// Setup segment for current module if needed
|
||||
s_alloc.reserve(wanted_code_size + wanted_rodata_size + wanted_rwdata_size);
|
||||
}
|
||||
|
||||
u8* allocateCodeSection(std::uintptr_t size, uint align, uint sec_id, llvm::StringRef sec_name) override
|
||||
{
|
||||
void* ptr = nullptr;
|
||||
const u32 wanted_size = ::align(static_cast<u32>(size), 4096);
|
||||
if (align > c_page_size)
|
||||
{
|
||||
// Lock memory manager
|
||||
std::lock_guard lock(s_mutex);
|
||||
|
||||
// Simple allocation
|
||||
ptr = s_alloc.allocate(wanted_size);
|
||||
}
|
||||
|
||||
if (ptr == nullptr)
|
||||
{
|
||||
jit_log.fatal("LLVM: Out of memory (size=0x%llx, aligned 0x%x)", size, align);
|
||||
return nullptr;
|
||||
}
|
||||
utils::memory_commit(ptr, size, utils::protection::wx);
|
||||
m_code_addr = static_cast<u8*>(ptr);
|
||||
|
||||
jit_log.notice("LLVM: Code section %u '%s' allocated -> %p (size=0x%llx, aligned 0x%x)", sec_id, sec_name.data(), ptr, size, align);
|
||||
return static_cast<u8*>(ptr);
|
||||
}
|
||||
|
||||
u8* allocateDataSection(std::uintptr_t size, uint align, uint sec_id, llvm::StringRef sec_name, bool is_ro) override
|
||||
{
|
||||
void* ptr = nullptr;
|
||||
const u32 wanted_size = ::align(static_cast<u32>(size), 4096);
|
||||
{
|
||||
// Lock memory manager
|
||||
std::lock_guard lock(s_mutex);
|
||||
|
||||
// Simple allocation
|
||||
ptr = s_alloc.allocate(wanted_size);
|
||||
}
|
||||
|
||||
if (ptr == nullptr)
|
||||
{
|
||||
jit_log.fatal("LLVM: Out of memory (size=0x%llx, aligned 0x%x)", size, align);
|
||||
jit_log.fatal("JIT: Unsupported alignment (size=0x%x, align=0x%x)", size, align);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!is_ro)
|
||||
const u64 olda = utils::align(oldp, align);
|
||||
const u64 newp = utils::align(olda + size, align);
|
||||
|
||||
if ((newp - 1) / c_max_size != oldp / c_max_size)
|
||||
{
|
||||
jit_log.fatal("JIT: Out of memory (size=0x%x, align=0x%x)", size, align);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
utils::memory_commit(ptr, size);
|
||||
if ((oldp - 1) / c_page_size != (newp - 1) / c_page_size)
|
||||
{
|
||||
// Allocate pages on demand
|
||||
const u64 pagea = utils::align(oldp, c_page_size);
|
||||
const u64 psize = utils::align(newp - pagea, c_page_size);
|
||||
utils::memory_commit(this->ptr + pagea, psize, prot);
|
||||
}
|
||||
|
||||
jit_log.notice("LLVM: Data section %u '%s' allocated -> %p (size=0x%llx, aligned 0x%x, %s)", sec_id, sec_name.data(), ptr, size, align, is_ro ? "ro" : "rw");
|
||||
return static_cast<u8*>(ptr);
|
||||
// Update allocation counter
|
||||
oldp = newp;
|
||||
|
||||
return this->ptr + olda;
|
||||
}
|
||||
|
||||
u8* allocateCodeSection(uptr size, uint align, uint sec_id, llvm::StringRef sec_name) override
|
||||
{
|
||||
return allocate(code_ptr, size, align, utils::protection::wx);
|
||||
}
|
||||
|
||||
u8* allocateDataSection(uptr size, uint align, uint sec_id, llvm::StringRef sec_name, bool is_ro) override
|
||||
{
|
||||
return allocate(data_ptr, size, align, utils::protection::rw);
|
||||
}
|
||||
|
||||
bool finalizeMemory(std::string* = nullptr) override
|
||||
{
|
||||
// Lock memory manager
|
||||
std::lock_guard lock(s_mutex);
|
||||
|
||||
// TODO: make only read-only sections read-only
|
||||
//#ifdef _WIN32
|
||||
// DWORD op;
|
||||
// VirtualProtect(s_memory, (u64)m_next - (u64)s_memory, PAGE_READONLY, &op);
|
||||
// VirtualProtect(s_code_addr, s_code_size, PAGE_EXECUTE_READ, &op);
|
||||
//#else
|
||||
// ::mprotect(s_memory, (u64)m_next - (u64)s_memory, PROT_READ);
|
||||
// ::mprotect(s_code_addr, s_code_size, PROT_READ | PROT_EXEC);
|
||||
//#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
void registerEHFrames(u8* addr, u64 load_addr, std::size_t size) override
|
||||
void registerEHFrames(u8* addr, u64 load_addr, usz size) override
|
||||
{
|
||||
// Lock memory manager
|
||||
std::lock_guard lock(s_mutex);
|
||||
#ifdef _WIN32
|
||||
// Fix RUNTIME_FUNCTION records (.pdata section)
|
||||
decltype(s_unwater)::value_type pdata_entry = std::move(s_unwater.front());
|
||||
s_unwater.pop_front();
|
||||
|
||||
// Use given memory segment as a BASE, compute the difference
|
||||
const u64 segment_start = pdata_entry.first;
|
||||
const u64 unwind_diff = (u64)addr - segment_start;
|
||||
|
||||
auto& pdata = pdata_entry.second;
|
||||
for (auto& rf : pdata)
|
||||
{
|
||||
rf.UnwindData += static_cast<DWORD>(unwind_diff);
|
||||
}
|
||||
|
||||
// Register .xdata UNWIND_INFO structs
|
||||
if (!RtlAddFunctionTable(pdata.data(), (DWORD)pdata.size(), segment_start))
|
||||
{
|
||||
jit_log.error("RtlAddFunctionTable() failed! Error %u", GetLastError());
|
||||
}
|
||||
else
|
||||
{
|
||||
s_unwind.emplace_back(std::move(pdata));
|
||||
}
|
||||
#else
|
||||
s_unfire.push_front(std::make_pair(addr, size));
|
||||
#endif
|
||||
|
||||
return RTDyldMemoryManager::registerEHFramesInProcess(addr, size);
|
||||
}
|
||||
|
||||
void deregisterEHFrames() override
|
||||
@@ -767,12 +408,12 @@ struct MemoryManager2 : llvm::RTDyldMemoryManager
|
||||
{
|
||||
}
|
||||
|
||||
u8* allocateCodeSection(std::uintptr_t size, uint align, uint sec_id, llvm::StringRef sec_name) override
|
||||
u8* allocateCodeSection(uptr size, uint align, uint sec_id, llvm::StringRef sec_name) override
|
||||
{
|
||||
return jit_runtime::alloc(size, align, true);
|
||||
}
|
||||
|
||||
u8* allocateDataSection(std::uintptr_t size, uint align, uint sec_id, llvm::StringRef sec_name, bool is_ro) override
|
||||
u8* allocateDataSection(uptr size, uint align, uint sec_id, llvm::StringRef sec_name, bool is_ro) override
|
||||
{
|
||||
return jit_runtime::alloc(size, align, false);
|
||||
}
|
||||
@@ -782,60 +423,7 @@ struct MemoryManager2 : llvm::RTDyldMemoryManager
|
||||
return false;
|
||||
}
|
||||
|
||||
void registerEHFrames(u8* addr, u64 load_addr, std::size_t size) override
|
||||
{
|
||||
#ifndef _WIN32
|
||||
RTDyldMemoryManager::registerEHFramesInProcess(addr, size);
|
||||
{
|
||||
// Lock memory manager
|
||||
std::lock_guard lock(s_mutex);
|
||||
s_unfire.push_front(std::make_pair(addr, size));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void deregisterEHFrames() override
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
// Simple memory manager. I promise there will be no MemoryManager4.
|
||||
struct MemoryManager3 : llvm::RTDyldMemoryManager
|
||||
{
|
||||
std::vector<std::pair<u8*, std::size_t>> allocs;
|
||||
|
||||
MemoryManager3() = default;
|
||||
|
||||
~MemoryManager3() override
|
||||
{
|
||||
for (auto& a : allocs)
|
||||
{
|
||||
utils::memory_release(a.first, a.second);
|
||||
}
|
||||
}
|
||||
|
||||
u8* allocateCodeSection(std::uintptr_t size, uint align, uint sec_id, llvm::StringRef sec_name) override
|
||||
{
|
||||
u8* r = static_cast<u8*>(utils::memory_reserve(size));
|
||||
utils::memory_commit(r, size, utils::protection::wx);
|
||||
allocs.emplace_back(r, size);
|
||||
return r;
|
||||
}
|
||||
|
||||
u8* allocateDataSection(std::uintptr_t size, uint align, uint sec_id, llvm::StringRef sec_name, bool is_ro) override
|
||||
{
|
||||
u8* r = static_cast<u8*>(utils::memory_reserve(size));
|
||||
utils::memory_commit(r, size);
|
||||
allocs.emplace_back(r, size);
|
||||
return r;
|
||||
}
|
||||
|
||||
bool finalizeMemory(std::string* = nullptr) override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void registerEHFrames(u8* addr, u64 load_addr, std::size_t size) override
|
||||
void registerEHFrames(u8* addr, u64 load_addr, usz size) override
|
||||
{
|
||||
}
|
||||
|
||||
@@ -844,64 +432,6 @@ struct MemoryManager3 : llvm::RTDyldMemoryManager
|
||||
}
|
||||
};
|
||||
|
||||
// Helper class
|
||||
struct EventListener : llvm::JITEventListener
|
||||
{
|
||||
MemoryManager& m_mem;
|
||||
|
||||
EventListener(MemoryManager& mem)
|
||||
: m_mem(mem)
|
||||
{
|
||||
}
|
||||
|
||||
void notifyObjectLoaded(ObjectKey K, const llvm::object::ObjectFile& obj, const llvm::RuntimeDyld::LoadedObjectInfo& inf) override
|
||||
{
|
||||
#ifdef _WIN32
|
||||
for (auto it = obj.section_begin(), end = obj.section_end(); it != end; ++it)
|
||||
{
|
||||
llvm::StringRef name;
|
||||
name = it->getName().get();
|
||||
|
||||
if (name == ".pdata")
|
||||
{
|
||||
llvm::StringRef data;
|
||||
data = it->getContents().get();
|
||||
|
||||
std::vector<RUNTIME_FUNCTION> rfs(data.size() / sizeof(RUNTIME_FUNCTION));
|
||||
|
||||
auto offsets = reinterpret_cast<DWORD*>(rfs.data());
|
||||
|
||||
// Initialize .pdata section using relocation info
|
||||
for (auto ri = it->relocation_begin(), end = it->relocation_end(); ri != end; ++ri)
|
||||
{
|
||||
if (ri->getType() == 3 /*R_X86_64_GOT32*/)
|
||||
{
|
||||
const u64 value = *reinterpret_cast<const DWORD*>(data.data() + ri->getOffset());
|
||||
offsets[ri->getOffset() / sizeof(DWORD)] = static_cast<DWORD>(value + ri->getSymbol()->getAddress().get());
|
||||
}
|
||||
}
|
||||
|
||||
// Lock memory manager
|
||||
std::lock_guard lock(s_mutex);
|
||||
|
||||
// Use current memory segment as a BASE, compute the difference
|
||||
const u64 segment_start = s_alloc.current_segment().first;
|
||||
const u64 code_diff = reinterpret_cast<u64>(m_mem.m_code_addr) - segment_start;
|
||||
|
||||
// Fix RUNTIME_FUNCTION records (.pdata section)
|
||||
for (auto& rf : rfs)
|
||||
{
|
||||
rf.BeginAddress += static_cast<DWORD>(code_diff);
|
||||
rf.EndAddress += static_cast<DWORD>(code_diff);
|
||||
}
|
||||
|
||||
s_unwater.emplace_back(segment_start, std::move(rfs));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
// Helper class
|
||||
class ObjectCache final : public llvm::ObjectCache
|
||||
{
|
||||
@@ -923,7 +453,7 @@ public:
|
||||
name.append(".gz");
|
||||
|
||||
z_stream zs{};
|
||||
uLong zsz = compressBound(::narrow<u32>(obj.getBufferSize(), HERE)) + 256;
|
||||
uLong zsz = compressBound(::narrow<u32>(obj.getBufferSize())) + 256;
|
||||
auto zbuf = std::make_unique<uchar[]>(zsz);
|
||||
#ifndef _MSC_VER
|
||||
#pragma GCC diagnostic push
|
||||
@@ -1104,20 +634,19 @@ std::string jit_compiler::cpu(const std::string& _cpu)
|
||||
}
|
||||
|
||||
jit_compiler::jit_compiler(const std::unordered_map<std::string, u64>& _link, const std::string& _cpu, u32 flags)
|
||||
: m_link(_link)
|
||||
, m_cpu(cpu(_cpu))
|
||||
: m_cpu(cpu(_cpu))
|
||||
{
|
||||
std::string result;
|
||||
|
||||
auto null_mod = std::make_unique<llvm::Module> ("null_", m_context);
|
||||
|
||||
if (m_link.empty())
|
||||
if (_link.empty())
|
||||
{
|
||||
std::unique_ptr<llvm::RTDyldMemoryManager> mem;
|
||||
|
||||
if (flags & 0x1)
|
||||
{
|
||||
mem = std::make_unique<MemoryManager3>();
|
||||
mem = std::make_unique<MemoryManager1>();
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1138,21 +667,18 @@ jit_compiler::jit_compiler(const std::unordered_map<std::string, u64>& _link, co
|
||||
else
|
||||
{
|
||||
// Primary JIT
|
||||
auto mem = std::make_unique<MemoryManager>(m_link);
|
||||
m_jit_el = std::make_unique<EventListener>(*mem);
|
||||
|
||||
m_engine.reset(llvm::EngineBuilder(std::move(null_mod))
|
||||
.setErrorStr(&result)
|
||||
.setEngineKind(llvm::EngineKind::JIT)
|
||||
.setMCJITMemoryManager(std::move(mem))
|
||||
.setMCJITMemoryManager(std::make_unique<MemoryManager1>())
|
||||
.setOptLevel(llvm::CodeGenOpt::Aggressive)
|
||||
.setCodeModel(flags & 0x2 ? llvm::CodeModel::Large : llvm::CodeModel::Small)
|
||||
.setMCPU(m_cpu)
|
||||
.create());
|
||||
|
||||
if (m_engine)
|
||||
for (auto&& [name, addr] : _link)
|
||||
{
|
||||
m_engine->RegisterJITEventListener(m_jit_el.get());
|
||||
m_engine->addGlobalMapping(name, addr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+68
-22
@@ -41,7 +41,7 @@ struct jit_runtime final : asmjit::HostRuntime
|
||||
asmjit::Error _release(void* p) noexcept override;
|
||||
|
||||
// Allocate memory
|
||||
static u8* alloc(std::size_t size, uint align, bool exec = true) noexcept;
|
||||
static u8* alloc(usz size, uint align, bool exec = true) noexcept;
|
||||
|
||||
// Should be called at least once after global initialization
|
||||
static void initialize();
|
||||
@@ -53,18 +53,77 @@ struct jit_runtime final : asmjit::HostRuntime
|
||||
namespace asmjit
|
||||
{
|
||||
// Should only be used to build global functions
|
||||
asmjit::JitRuntime& get_global_runtime();
|
||||
asmjit::Runtime& get_global_runtime();
|
||||
|
||||
// Emit xbegin and adjacent loop, return label at xbegin
|
||||
void build_transaction_enter(X86Assembler& c, Label fallback, const X86Gp& ctr, uint less_than);
|
||||
// Emit xbegin and adjacent loop, return label at xbegin (don't use xabort please)
|
||||
template <typename F>
|
||||
[[nodiscard]] inline asmjit::Label build_transaction_enter(asmjit::X86Assembler& c, asmjit::Label fallback, F func)
|
||||
{
|
||||
Label fall = c.newLabel();
|
||||
Label begin = c.newLabel();
|
||||
c.jmp(begin);
|
||||
c.bind(fall);
|
||||
|
||||
// Emit xabort
|
||||
void build_transaction_abort(X86Assembler& c, unsigned char code);
|
||||
// Don't repeat on zero status (may indicate syscall or interrupt)
|
||||
c.test(x86::eax, x86::eax);
|
||||
c.jz(fallback);
|
||||
|
||||
// First invoked after failure (can fallback to proceed, or jump anywhere else)
|
||||
func();
|
||||
|
||||
// Other bad statuses are ignored regardless of repeat flag (TODO)
|
||||
c.align(kAlignCode, 16);
|
||||
c.bind(begin);
|
||||
return fall;
|
||||
|
||||
// xbegin should be issued manually, allows to add more check before entering transaction
|
||||
}
|
||||
|
||||
// Helper to spill RDX (EDX) register for RDTSC
|
||||
inline void build_swap_rdx_with(asmjit::X86Assembler& c, std::array<X86Gp, 4>& args, const asmjit::X86Gp& with)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
c.xchg(args[1], with);
|
||||
args[1] = with;
|
||||
#else
|
||||
c.xchg(args[2], with);
|
||||
args[2] = with;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Get full RDTSC value into chosen register (clobbers rax/rdx or saves only rax with other target)
|
||||
inline void build_get_tsc(asmjit::X86Assembler& c, const asmjit::X86Gp& to = asmjit::x86::rax)
|
||||
{
|
||||
if (&to != &x86::rax && &to != &x86::rdx)
|
||||
{
|
||||
// Swap to save its contents
|
||||
c.xchg(x86::rax, to);
|
||||
}
|
||||
|
||||
c.rdtsc();
|
||||
c.shl(x86::rdx, 32);
|
||||
|
||||
if (&to == &x86::rax)
|
||||
{
|
||||
c.or_(x86::rax, x86::rdx);
|
||||
}
|
||||
else if (&to == &x86::rdx)
|
||||
{
|
||||
c.or_(x86::rdx, x86::rax);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Swap back, maybe there is more effective way to do it
|
||||
c.xchg(x86::rax, to);
|
||||
c.mov(to.r32(), to.r32());
|
||||
c.or_(to.r64(), x86::rdx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Build runtime function with asmjit::X86Assembler
|
||||
template <typename FT, typename F>
|
||||
FT build_function_asm(F&& builder)
|
||||
inline FT build_function_asm(F&& builder)
|
||||
{
|
||||
using namespace asmjit;
|
||||
|
||||
@@ -89,6 +148,7 @@ FT build_function_asm(F&& builder)
|
||||
|
||||
X86Assembler compiler(&code);
|
||||
builder(std::ref(compiler), args);
|
||||
ensure(compiler.getLastError() == 0);
|
||||
|
||||
FT result;
|
||||
|
||||
@@ -107,10 +167,9 @@ FT build_function_asm(F&& builder)
|
||||
#include <string_view>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "types.h"
|
||||
#include "util/types.hpp"
|
||||
#include "mutex.h"
|
||||
|
||||
#include "restore_new.h"
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push, 0)
|
||||
#else
|
||||
@@ -127,7 +186,6 @@ FT build_function_asm(F&& builder)
|
||||
#else
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
#include "define_new_memleakdetect.h"
|
||||
|
||||
// Temporary compiler interface
|
||||
class jit_compiler final
|
||||
@@ -135,15 +193,9 @@ class jit_compiler final
|
||||
// Local LLVM context
|
||||
llvm::LLVMContext m_context;
|
||||
|
||||
// JIT Event Listener
|
||||
std::unique_ptr<struct EventListener> m_jit_el;
|
||||
|
||||
// Execution instance
|
||||
std::unique_ptr<llvm::ExecutionEngine> m_engine;
|
||||
|
||||
// Link table
|
||||
std::unordered_map<std::string, u64> m_link;
|
||||
|
||||
// Arch
|
||||
std::string m_cpu;
|
||||
|
||||
@@ -182,12 +234,6 @@ public:
|
||||
|
||||
// Get CPU info
|
||||
static std::string cpu(const std::string& _cpu);
|
||||
|
||||
// Check JIT purpose
|
||||
bool is_primary() const
|
||||
{
|
||||
return !m_link.empty();
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
+86
-73
@@ -1,8 +1,9 @@
|
||||
#include "StrFmt.h"
|
||||
#include "BEType.h"
|
||||
#include "StrFmt.h"
|
||||
#include "StrUtil.h"
|
||||
#include "cfmt.h"
|
||||
#include "util/endian.hpp"
|
||||
#include "util/logs.hpp"
|
||||
#include "util/v128.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <string_view>
|
||||
@@ -78,14 +79,14 @@ void fmt_class_string<fmt::base57>::format(std::string& out, u64 arg)
|
||||
static constexpr u8 s_tail[8] = {0, 2, 3, 5, 6, 7, 9, 10};
|
||||
|
||||
// Get full output size
|
||||
const std::size_t out_size = _arg.size / 8 * 11 + s_tail[_arg.size % 8];
|
||||
const usz out_size = _arg.size / 8 * 11 + s_tail[_arg.size % 8];
|
||||
|
||||
out.resize(out.size() + out_size);
|
||||
|
||||
const auto ptr = &out.front() + (out.size() - out_size);
|
||||
|
||||
// Each 8 bytes of input data produce 11 bytes of base57 output
|
||||
for (std::size_t i = 0, p = 0; i < _arg.size; i += 8, p += 11)
|
||||
for (usz i = 0, p = 0; i < _arg.size; i += 8, p += 11)
|
||||
{
|
||||
// Load up to 8 bytes
|
||||
be_t<u64> be_value;
|
||||
@@ -235,6 +236,12 @@ void fmt_class_string<bool>::format(std::string& out, u64 arg)
|
||||
out += arg ? "true" : "false";
|
||||
}
|
||||
|
||||
template <>
|
||||
void fmt_class_string<b8>::format(std::string& out, u64 arg)
|
||||
{
|
||||
out += get_object(arg) ? "true" : "false";
|
||||
}
|
||||
|
||||
template <>
|
||||
void fmt_class_string<v128>::format(std::string& out, u64 arg)
|
||||
{
|
||||
@@ -242,70 +249,76 @@ void fmt_class_string<v128>::format(std::string& out, u64 arg)
|
||||
fmt::append(out, "0x%016llx%016llx", vec._u64[1], vec._u64[0]);
|
||||
}
|
||||
|
||||
template <>
|
||||
void fmt_class_string<u128>::format(std::string& out, u64 arg)
|
||||
{
|
||||
// TODO: it should be supported as full-fledged integral type (with %u, %d, etc, fmt)
|
||||
const u128& num = get_object(arg);
|
||||
#ifdef _MSC_VER
|
||||
fmt::append(out, "0x%016llx%016llx", num.hi, num.lo);
|
||||
#else
|
||||
fmt::append(out, "0x%016llx%016llx", static_cast<u64>(num >> 64), static_cast<u64>(num));
|
||||
#endif
|
||||
}
|
||||
|
||||
template <>
|
||||
void fmt_class_string<src_loc>::format(std::string& out, u64 arg)
|
||||
{
|
||||
const src_loc& loc = get_object(arg);
|
||||
|
||||
if (loc.col != umax)
|
||||
{
|
||||
fmt::append(out, "\n(in file %s:%u[:%u]", loc.file, loc.line, loc.col);
|
||||
}
|
||||
else
|
||||
{
|
||||
fmt::append(out, "\n(in file %s:%u", loc.file, loc.line);
|
||||
}
|
||||
|
||||
if (loc.func && *loc.func)
|
||||
{
|
||||
fmt::append(out, ", in function %s)", loc.func);
|
||||
}
|
||||
else
|
||||
{
|
||||
out += ')';
|
||||
}
|
||||
|
||||
// Print error code (may be irrelevant)
|
||||
#ifdef _WIN32
|
||||
if (DWORD error = GetLastError())
|
||||
{
|
||||
fmt::append(out, " (e=0x%08x[%u])", error, error);
|
||||
}
|
||||
#else
|
||||
if (int error = errno)
|
||||
{
|
||||
fmt::append(out, " (errno=%d)", error);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
namespace fmt
|
||||
{
|
||||
void raw_error(const char* msg)
|
||||
{
|
||||
thread_ctrl::emergency_exit(msg);
|
||||
}
|
||||
|
||||
void raw_verify_error(const char* msg, const fmt_type_info* sup, u64 arg)
|
||||
[[noreturn]] void raw_verify_error(const src_loc& loc)
|
||||
{
|
||||
std::string out{"Verification failed"};
|
||||
|
||||
// Print error code (may be irrelevant)
|
||||
#ifdef _WIN32
|
||||
if (DWORD error = GetLastError())
|
||||
{
|
||||
fmt::append(out, " (e=%#x)", error);
|
||||
}
|
||||
#else
|
||||
if (int error = errno)
|
||||
{
|
||||
fmt::append(out, " (e=%d)", error);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (sup)
|
||||
{
|
||||
out += " (";
|
||||
sup->fmt_string(out, arg); // Print value
|
||||
out += ")";
|
||||
}
|
||||
|
||||
if (msg)
|
||||
{
|
||||
out += ": ";
|
||||
out += msg;
|
||||
}
|
||||
|
||||
fmt::append(out, "%s", loc);
|
||||
thread_ctrl::emergency_exit(out);
|
||||
}
|
||||
|
||||
void raw_narrow_error(const char* msg, const fmt_type_info* sup, u64 arg)
|
||||
[[noreturn]] void raw_narrow_error(const src_loc& loc)
|
||||
{
|
||||
std::string out{"Narrow error"};
|
||||
|
||||
if (sup)
|
||||
{
|
||||
out += " (";
|
||||
sup->fmt_string(out, arg); // Print value
|
||||
out += ")";
|
||||
}
|
||||
|
||||
if (msg)
|
||||
{
|
||||
out += ": ";
|
||||
out += msg;
|
||||
}
|
||||
|
||||
std::string out{"Narrowing error"};
|
||||
fmt::append(out, "%s", loc);
|
||||
thread_ctrl::emergency_exit(out);
|
||||
}
|
||||
|
||||
void raw_throw_exception(const char* fmt, const fmt_type_info* sup, const u64* args)
|
||||
[[noreturn]] void raw_throw_exception(const src_loc& loc, const char* fmt, const fmt_type_info* sup, const u64* args)
|
||||
{
|
||||
std::string out;
|
||||
raw_append(out, fmt, sup, args);
|
||||
fmt::append(out, "%s", loc);
|
||||
thread_ctrl::emergency_exit(out);
|
||||
}
|
||||
|
||||
@@ -318,7 +331,7 @@ struct fmt::cfmt_src
|
||||
const fmt_type_info* sup;
|
||||
const u64* args;
|
||||
|
||||
bool test(std::size_t index) const
|
||||
bool test(usz index) const
|
||||
{
|
||||
if (!sup[index].fmt_string)
|
||||
{
|
||||
@@ -329,26 +342,26 @@ struct fmt::cfmt_src
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T get(std::size_t index) const
|
||||
T get(usz index) const
|
||||
{
|
||||
return *reinterpret_cast<const T*>(reinterpret_cast<const u8*>(args + index));
|
||||
}
|
||||
|
||||
void skip(std::size_t extra)
|
||||
void skip(usz extra)
|
||||
{
|
||||
sup += extra + 1;
|
||||
args += extra + 1;
|
||||
}
|
||||
|
||||
std::size_t fmt_string(std::string& out, std::size_t extra) const
|
||||
usz fmt_string(std::string& out, usz extra) const
|
||||
{
|
||||
const std::size_t start = out.size();
|
||||
const usz start = out.size();
|
||||
sup[extra].fmt_string(out, args[extra]);
|
||||
return out.size() - start;
|
||||
}
|
||||
|
||||
// Returns type size (0 if unknown, pointer, unsigned, assumed max)
|
||||
std::size_t type(std::size_t extra) const
|
||||
usz type(usz extra) const
|
||||
{
|
||||
// Hack: use known function pointers to determine type
|
||||
#define TYPE(type) \
|
||||
@@ -366,14 +379,14 @@ struct fmt::cfmt_src
|
||||
return 0;
|
||||
}
|
||||
|
||||
static constexpr std::size_t size_char = 1;
|
||||
static constexpr std::size_t size_short = 2;
|
||||
static constexpr std::size_t size_int = 0;
|
||||
static constexpr std::size_t size_long = sizeof(ulong);
|
||||
static constexpr std::size_t size_llong = sizeof(ullong);
|
||||
static constexpr std::size_t size_size = sizeof(std::size_t);
|
||||
static constexpr std::size_t size_max = sizeof(std::uintmax_t);
|
||||
static constexpr std::size_t size_diff = sizeof(std::ptrdiff_t);
|
||||
static constexpr usz size_char = 1;
|
||||
static constexpr usz size_short = 2;
|
||||
static constexpr usz size_int = 0;
|
||||
static constexpr usz size_long = sizeof(ulong);
|
||||
static constexpr usz size_llong = sizeof(ullong);
|
||||
static constexpr usz size_size = sizeof(usz);
|
||||
static constexpr usz size_max = sizeof(std::uintmax_t);
|
||||
static constexpr usz size_diff = sizeof(std::ptrdiff_t);
|
||||
};
|
||||
|
||||
void fmt::raw_append(std::string& out, const char* fmt, const fmt_type_info* sup, const u64* args) noexcept
|
||||
@@ -409,9 +422,9 @@ std::vector<std::string> fmt::split(const std::string& source, std::initializer_
|
||||
{
|
||||
std::vector<std::string> result;
|
||||
|
||||
size_t cursor_begin = 0;
|
||||
usz cursor_begin = 0;
|
||||
|
||||
for (size_t cursor_end = 0; cursor_end < source.length(); ++cursor_end)
|
||||
for (usz cursor_end = 0; cursor_end < source.length(); ++cursor_end)
|
||||
{
|
||||
for (auto& separator : separators)
|
||||
{
|
||||
@@ -438,7 +451,7 @@ std::vector<std::string> fmt::split(const std::string& source, std::initializer_
|
||||
|
||||
std::string fmt::trim(const std::string& source, const std::string& values)
|
||||
{
|
||||
std::size_t begin = source.find_first_not_of(values);
|
||||
usz begin = source.find_first_not_of(values);
|
||||
|
||||
if (begin == source.npos)
|
||||
return {};
|
||||
@@ -464,7 +477,7 @@ std::string fmt::to_lower(const std::string& string)
|
||||
|
||||
bool fmt::match(const std::string& source, const std::string& mask)
|
||||
{
|
||||
std::size_t source_position = 0, mask_position = 0;
|
||||
usz source_position = 0, mask_position = 0;
|
||||
|
||||
for (; source_position < source.size() && mask_position < mask.size(); ++mask_position, ++source_position)
|
||||
{
|
||||
@@ -473,7 +486,7 @@ bool fmt::match(const std::string& source, const std::string& mask)
|
||||
case '?': break;
|
||||
|
||||
case '*':
|
||||
for (std::size_t test_source_position = source_position; test_source_position < source.size(); ++test_source_position)
|
||||
for (usz test_source_position = source_position; test_source_position < source.size(); ++test_source_position)
|
||||
{
|
||||
if (match(source.substr(test_source_position), mask.substr(mask_position + 1)))
|
||||
{
|
||||
|
||||
+38
-38
@@ -1,18 +1,16 @@
|
||||
#pragma once
|
||||
#pragma once // No BOM and only basic ASCII in this header, or a neko will die
|
||||
|
||||
#include "types.h"
|
||||
#include "util/types.hpp"
|
||||
|
||||
#include <exception>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
namespace fmt
|
||||
{
|
||||
template <typename CharT, std::size_t N, typename... Args>
|
||||
template <typename CharT, usz N, typename... Args>
|
||||
static std::string format(const CharT(&)[N], const Args&...);
|
||||
}
|
||||
|
||||
template <typename T, typename>
|
||||
template <typename T, typename = void>
|
||||
struct fmt_unveil
|
||||
{
|
||||
static_assert(sizeof(T) > 0, "fmt_unveil<> error: incomplete type");
|
||||
@@ -21,7 +19,7 @@ struct fmt_unveil
|
||||
|
||||
static inline u64 get(const T& arg)
|
||||
{
|
||||
return reinterpret_cast<std::uintptr_t>(&arg);
|
||||
return reinterpret_cast<uptr>(&arg);
|
||||
}
|
||||
|
||||
// Temporary value container (can possibly be created by other fmt_unveil<> specializations)
|
||||
@@ -32,7 +30,7 @@ struct fmt_unveil
|
||||
// Allow implicit conversion
|
||||
operator u64() const
|
||||
{
|
||||
return reinterpret_cast<std::uintptr_t>(&arg);
|
||||
return reinterpret_cast<uptr>(&arg);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -66,17 +64,6 @@ struct fmt_unveil<T, std::enable_if_t<std::is_floating_point<T>::value && sizeof
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct fmt_unveil<f16, void>
|
||||
{
|
||||
using type = f16;
|
||||
|
||||
static inline u64 get(const f16& arg)
|
||||
{
|
||||
return fmt_unveil<f64>::get(arg.operator float());
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct fmt_unveil<T, std::enable_if_t<std::is_enum<T>::value>>
|
||||
{
|
||||
@@ -95,29 +82,29 @@ struct fmt_unveil<T*, void>
|
||||
|
||||
static inline u64 get(type arg)
|
||||
{
|
||||
return reinterpret_cast<std::uintptr_t>(arg);
|
||||
return reinterpret_cast<uptr>(arg);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, std::size_t N>
|
||||
template <typename T, usz N>
|
||||
struct fmt_unveil<T[N], void>
|
||||
{
|
||||
using type = std::add_const_t<T>*;
|
||||
|
||||
static inline u64 get(type arg)
|
||||
{
|
||||
return reinterpret_cast<std::uintptr_t>(arg);
|
||||
return reinterpret_cast<uptr>(arg);
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct fmt_unveil<b8, void>
|
||||
template <typename T, bool Se, usz Align>
|
||||
struct fmt_unveil<se_t<T, Se, Align>, void>
|
||||
{
|
||||
using type = bool;
|
||||
using type = typename fmt_unveil<T>::type;
|
||||
|
||||
static inline u64 get(const b8& value)
|
||||
static inline auto get(const se_t<T, Se, Align>& arg)
|
||||
{
|
||||
return fmt_unveil<bool>::get(value);
|
||||
return fmt_unveil<T>::get(arg);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -134,7 +121,7 @@ struct fmt_class_string
|
||||
// Helper function (converts arg to object reference)
|
||||
static SAFE_BUFFERS FORCE_INLINE const T& get_object(u64 arg)
|
||||
{
|
||||
return *reinterpret_cast<const T*>(static_cast<std::uintptr_t>(arg));
|
||||
return *reinterpret_cast<const T*>(static_cast<uptr>(arg));
|
||||
}
|
||||
|
||||
// Enum -> string function type
|
||||
@@ -236,13 +223,16 @@ struct fmt_type_info
|
||||
template <typename... Args>
|
||||
using fmt_args_t = const u64(&&)[sizeof...(Args) + 1];
|
||||
|
||||
template <typename Arg>
|
||||
using fmt_unveil_t = typename fmt_unveil<Arg>::type;
|
||||
|
||||
namespace fmt
|
||||
{
|
||||
// Base-57 format helper
|
||||
struct base57
|
||||
{
|
||||
const uchar* data;
|
||||
std::size_t size;
|
||||
usz size;
|
||||
|
||||
template <typename T>
|
||||
base57(const T& arg)
|
||||
@@ -251,7 +241,7 @@ namespace fmt
|
||||
{
|
||||
}
|
||||
|
||||
base57(const uchar* data, std::size_t size)
|
||||
base57(const uchar* data, usz size)
|
||||
: data(data)
|
||||
, size(size)
|
||||
{
|
||||
@@ -274,7 +264,7 @@ namespace fmt
|
||||
void raw_append(std::string& out, const char*, const fmt_type_info*, const u64*) noexcept;
|
||||
|
||||
// Formatting function
|
||||
template <typename CharT, std::size_t N, typename... Args>
|
||||
template <typename CharT, usz N, typename... Args>
|
||||
SAFE_BUFFERS FORCE_INLINE void append(std::string& out, const CharT(&fmt)[N], const Args&... args)
|
||||
{
|
||||
static constexpr fmt_type_info type_list[sizeof...(Args) + 1]{fmt_type_info::make<fmt_unveil_t<Args>>()...};
|
||||
@@ -282,7 +272,7 @@ namespace fmt
|
||||
}
|
||||
|
||||
// Formatting function
|
||||
template <typename CharT, std::size_t N, typename... Args>
|
||||
template <typename CharT, usz N, typename... Args>
|
||||
SAFE_BUFFERS FORCE_INLINE std::string format(const CharT(&fmt)[N], const Args&... args)
|
||||
{
|
||||
std::string result;
|
||||
@@ -291,13 +281,23 @@ namespace fmt
|
||||
}
|
||||
|
||||
// Internal exception message formatting template, must be explicitly specialized or instantiated in cpp to minimize code bloat
|
||||
[[noreturn]] void raw_throw_exception(const char*, const fmt_type_info*, const u64*);
|
||||
[[noreturn]] void raw_throw_exception(const src_loc&, const char*, const fmt_type_info*, const u64*);
|
||||
|
||||
// Throw exception with formatting
|
||||
template <typename... Args>
|
||||
[[noreturn]] SAFE_BUFFERS FORCE_INLINE void throw_exception(const char* fmt, const Args&... args)
|
||||
template <typename CharT, usz N, typename... Args>
|
||||
struct throw_exception
|
||||
{
|
||||
static constexpr fmt_type_info type_list[sizeof...(Args) + 1]{fmt_type_info::make<fmt_unveil_t<Args>>()...};
|
||||
raw_throw_exception(fmt, type_list, fmt_args_t<Args...>{fmt_unveil<Args>::get(args)...});
|
||||
}
|
||||
[[noreturn]] SAFE_BUFFERS FORCE_INLINE throw_exception(const CharT(&fmt)[N], const Args&... args,
|
||||
u32 line = __builtin_LINE(),
|
||||
u32 col = __builtin_COLUMN(),
|
||||
const char* file = __builtin_FILE(),
|
||||
const char* func = __builtin_FUNCTION())
|
||||
{
|
||||
static constexpr fmt_type_info type_list[sizeof...(Args) + 1]{fmt_type_info::make<fmt_unveil_t<Args>>()...};
|
||||
raw_throw_exception({line, col, file, func}, reinterpret_cast<const char*>(fmt), type_list, fmt_args_t<Args...>{fmt_unveil<Args>::get(args)...});
|
||||
}
|
||||
};
|
||||
|
||||
template <typename CharT, usz N, typename... Args>
|
||||
throw_exception(const CharT(&)[N], const Args&...) -> throw_exception<CharT, N, Args...>;
|
||||
}
|
||||
|
||||
+9
-9
@@ -17,7 +17,7 @@ std::string utf8_path_to_ansi_path(const std::string& src);
|
||||
template <typename D, typename T>
|
||||
inline void strcpy_trunc(D& dst, const T& src)
|
||||
{
|
||||
const std::size_t count = std::size(src) >= std::size(dst) ? std::size(dst) - 1 : std::size(src);
|
||||
const usz count = std::size(src) >= std::size(dst) ? std::size(dst) - 1 : std::size(src);
|
||||
std::memcpy(std::data(dst), std::data(src), count);
|
||||
std::memset(std::data(dst) + count, 0, std::size(dst) - count);
|
||||
}
|
||||
@@ -27,14 +27,14 @@ namespace fmt
|
||||
std::string replace_first(const std::string& src, const std::string& from, const std::string& to);
|
||||
std::string replace_all(const std::string& src, const std::string& from, const std::string& to);
|
||||
|
||||
template <size_t list_size>
|
||||
template <usz list_size>
|
||||
std::string replace_all(std::string src, const std::pair<std::string, std::string> (&list)[list_size])
|
||||
{
|
||||
for (size_t pos = 0; pos < src.length(); ++pos)
|
||||
for (usz pos = 0; pos < src.length(); ++pos)
|
||||
{
|
||||
for (size_t i = 0; i < list_size; ++i)
|
||||
for (usz i = 0; i < list_size; ++i)
|
||||
{
|
||||
const size_t comp_length = list[i].first.length();
|
||||
const usz comp_length = list[i].first.length();
|
||||
|
||||
if (src.length() - pos < comp_length)
|
||||
continue;
|
||||
@@ -51,14 +51,14 @@ namespace fmt
|
||||
return src;
|
||||
}
|
||||
|
||||
template <size_t list_size>
|
||||
template <usz list_size>
|
||||
std::string replace_all(std::string src, const std::pair<std::string, std::function<std::string()>> (&list)[list_size])
|
||||
{
|
||||
for (size_t pos = 0; pos < src.length(); ++pos)
|
||||
for (usz pos = 0; pos < src.length(); ++pos)
|
||||
{
|
||||
for (size_t i = 0; i < list_size; ++i)
|
||||
for (usz i = 0; i < list_size; ++i)
|
||||
{
|
||||
const size_t comp_length = list[i].first.length();
|
||||
const usz comp_length = list[i].first.length();
|
||||
|
||||
if (src.length() - pos < comp_length)
|
||||
continue;
|
||||
|
||||
+419
-113
@@ -1,11 +1,12 @@
|
||||
#include "stdafx.h"
|
||||
#include "stdafx.h"
|
||||
#include "Emu/System.h"
|
||||
#include "Emu/Cell/SPUThread.h"
|
||||
#include "Emu/Cell/PPUThread.h"
|
||||
#include "Emu/Cell/RawSPUThread.h"
|
||||
#include "Emu/Cell/lv2/sys_mmapper.h"
|
||||
#include "Emu/Cell/lv2/sys_event.h"
|
||||
#include "Thread.h"
|
||||
#include "sysinfo.h"
|
||||
#include "Utilities/JIT.h"
|
||||
#include <typeinfo>
|
||||
#include <thread>
|
||||
#include <sstream>
|
||||
@@ -38,6 +39,7 @@
|
||||
#endif
|
||||
#ifdef __linux__
|
||||
#include <sys/timerfd.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#if defined(__APPLE__) || defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
|
||||
@@ -71,8 +73,13 @@
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#include "sync.h"
|
||||
#include "util/vm.hpp"
|
||||
#include "util/logs.hpp"
|
||||
#include "util/asm.hpp"
|
||||
#include "util/v128.hpp"
|
||||
#include "util/v128sse.hpp"
|
||||
#include "util/sysinfo.hpp"
|
||||
#include "Emu/Memory/vm_locking.h"
|
||||
|
||||
LOG_CHANNEL(sig_log, "SIG");
|
||||
LOG_CHANNEL(sys_log, "SYS");
|
||||
@@ -81,8 +88,14 @@ LOG_CHANNEL(vm_log, "VM");
|
||||
thread_local u64 g_tls_fault_all = 0;
|
||||
thread_local u64 g_tls_fault_rsx = 0;
|
||||
thread_local u64 g_tls_fault_spu = 0;
|
||||
thread_local u64 g_tls_wait_time = 0;
|
||||
thread_local u64 g_tls_wait_fail = 0;
|
||||
thread_local bool g_tls_access_violation_recovered = false;
|
||||
extern thread_local std::string(*g_tls_log_prefix)();
|
||||
|
||||
// Report error and call std::abort(), defined in main.cpp
|
||||
[[noreturn]] void report_fatal_error(const std::string&);
|
||||
|
||||
template <>
|
||||
void fmt_class_string<std::thread::id>::format(std::string& out, u64 arg)
|
||||
{
|
||||
@@ -107,7 +120,7 @@ bool IsDebuggerPresent()
|
||||
};
|
||||
u_int miblen = std::size(mib);
|
||||
struct kinfo_proc info;
|
||||
size_t size = sizeof(info);
|
||||
usz size = sizeof(info);
|
||||
|
||||
if (sysctl(mib, miblen, &info, &size, NULL, 0))
|
||||
{
|
||||
@@ -248,7 +261,7 @@ enum x64_op_t : u32
|
||||
X64OP_SBB, // lock sbb [mem], ...
|
||||
};
|
||||
|
||||
void decode_x64_reg_op(const u8* code, x64_op_t& out_op, x64_reg_t& out_reg, size_t& out_size, size_t& out_length)
|
||||
void decode_x64_reg_op(const u8* code, x64_op_t& out_op, x64_reg_t& out_reg, usz& out_size, usz& out_length)
|
||||
{
|
||||
// simple analysis of x64 code allows to reinterpret MOV or other instructions in any desired way
|
||||
out_length = 0;
|
||||
@@ -374,12 +387,12 @@ void decode_x64_reg_op(const u8* code, x64_op_t& out_op, x64_reg_t& out_reg, siz
|
||||
return x64_reg_t{((*code & 0x38) >> 3) + X64R_AL};
|
||||
};
|
||||
|
||||
auto get_op_size = [](const u8 rex, const bool oso) -> size_t
|
||||
auto get_op_size = [](const u8 rex, const bool oso) -> usz
|
||||
{
|
||||
return rex & 8 ? 8 : (oso ? 2 : 4);
|
||||
};
|
||||
|
||||
auto get_modRM_size = [](const u8* code) -> size_t
|
||||
auto get_modRM_size = [](const u8* code) -> usz
|
||||
{
|
||||
switch (*code >> 6) // check Mod
|
||||
{
|
||||
@@ -822,7 +835,7 @@ typedef ucontext_t x64_context;
|
||||
#define XMMREG(context, reg) (reinterpret_cast<v128*>(&(context)->uc_mcontext->__fs.__fpu_xmm0.__xmm_reg[reg]))
|
||||
#define EFLAGS(context) ((context)->uc_mcontext->__ss.__rflags)
|
||||
|
||||
uint64_t* darwin_x64reg(x64_context *context, int reg)
|
||||
u64* darwin_x64reg(x64_context *context, int reg)
|
||||
{
|
||||
auto *state = &context->uc_mcontext->__ss;
|
||||
switch(reg)
|
||||
@@ -965,7 +978,7 @@ static const int reg_table[] =
|
||||
#define RDI(c) (*X64REG((c), 7))
|
||||
#define RIP(c) (*X64REG((c), 16))
|
||||
|
||||
bool get_x64_reg_value(x64_context* context, x64_reg_t reg, size_t d_size, size_t i_size, u64& out_value)
|
||||
bool get_x64_reg_value(x64_context* context, x64_reg_t reg, usz d_size, usz i_size, u64& out_value)
|
||||
{
|
||||
// get x64 reg value (for store operations)
|
||||
if (reg - X64R_RAX < 16)
|
||||
@@ -1056,7 +1069,7 @@ bool get_x64_reg_value(x64_context* context, x64_reg_t reg, size_t d_size, size_
|
||||
return false;
|
||||
}
|
||||
|
||||
bool put_x64_reg_value(x64_context* context, x64_reg_t reg, size_t d_size, u64 value)
|
||||
bool put_x64_reg_value(x64_context* context, x64_reg_t reg, usz d_size, u64 value)
|
||||
{
|
||||
// save x64 reg value (for load operations)
|
||||
if (reg - X64R_RAX < 16)
|
||||
@@ -1075,7 +1088,7 @@ bool put_x64_reg_value(x64_context* context, x64_reg_t reg, size_t d_size, u64 v
|
||||
return false;
|
||||
}
|
||||
|
||||
bool set_x64_cmp_flags(x64_context* context, size_t d_size, u64 x, u64 y, bool carry = true)
|
||||
bool set_x64_cmp_flags(x64_context* context, usz d_size, u64 x, u64 y, bool carry = true)
|
||||
{
|
||||
switch (d_size)
|
||||
{
|
||||
@@ -1151,7 +1164,7 @@ bool set_x64_cmp_flags(x64_context* context, size_t d_size, u64 x, u64 y, bool c
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t get_x64_access_size(x64_context* context, x64_op_t op, x64_reg_t reg, size_t d_size, size_t i_size)
|
||||
usz get_x64_access_size(x64_context* context, x64_op_t op, x64_reg_t reg, usz d_size, usz i_size)
|
||||
{
|
||||
if (op == X64OP_MOVS || op == X64OP_STOS)
|
||||
{
|
||||
@@ -1216,8 +1229,8 @@ bool handle_access_violation(u32 addr, bool is_writing, x64_context* context) no
|
||||
|
||||
x64_op_t op;
|
||||
x64_reg_t reg;
|
||||
size_t d_size;
|
||||
size_t i_size;
|
||||
usz d_size;
|
||||
usz i_size;
|
||||
|
||||
// decode single x64 instruction that causes memory access
|
||||
decode_x64_reg_op(code, op, reg, d_size, i_size);
|
||||
@@ -1230,7 +1243,7 @@ bool handle_access_violation(u32 addr, bool is_writing, x64_context* context) no
|
||||
}
|
||||
};
|
||||
|
||||
if ((d_size | (d_size + addr)) >= 0x100000000ull)
|
||||
if (0x1'0000'0000ull - addr < d_size)
|
||||
{
|
||||
sig_log.error("Invalid d_size (0x%llx)", d_size);
|
||||
report_opcode();
|
||||
@@ -1238,9 +1251,9 @@ bool handle_access_violation(u32 addr, bool is_writing, x64_context* context) no
|
||||
}
|
||||
|
||||
// get length of data being accessed
|
||||
size_t a_size = get_x64_access_size(context, op, reg, d_size, i_size);
|
||||
usz a_size = get_x64_access_size(context, op, reg, d_size, i_size);
|
||||
|
||||
if ((a_size | (a_size + addr)) >= 0x100000000ull)
|
||||
if (0x1'0000'0000ull - addr < a_size)
|
||||
{
|
||||
sig_log.error("Invalid a_size (0x%llx)", a_size);
|
||||
report_opcode();
|
||||
@@ -1248,22 +1261,28 @@ bool handle_access_violation(u32 addr, bool is_writing, x64_context* context) no
|
||||
}
|
||||
|
||||
// check if address is RawSPU MMIO register
|
||||
if (addr - RAW_SPU_BASE_ADDR < (6 * RAW_SPU_OFFSET) && (addr % RAW_SPU_OFFSET) >= RAW_SPU_PROB_OFFSET)
|
||||
do if (addr - RAW_SPU_BASE_ADDR < (6 * RAW_SPU_OFFSET) && (addr % RAW_SPU_OFFSET) >= RAW_SPU_PROB_OFFSET)
|
||||
{
|
||||
auto thread = idm::get<named_thread<spu_thread>>(spu_thread::find_raw_spu((addr - RAW_SPU_BASE_ADDR) / RAW_SPU_OFFSET));
|
||||
|
||||
if (!thread)
|
||||
{
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (a_size != 4 || !d_size || !i_size)
|
||||
if (!a_size || !d_size || !i_size)
|
||||
{
|
||||
sig_log.error("Invalid or unsupported instruction (op=%d, reg=%d, d_size=%lld, a_size=0x%llx, i_size=%lld)", +op, +reg, d_size, a_size, i_size);
|
||||
report_opcode();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (a_size != 4)
|
||||
{
|
||||
// Might be unimplemented, such as writing MFC proxy EAL+EAH using 64-bit store
|
||||
break;
|
||||
}
|
||||
|
||||
switch (op)
|
||||
{
|
||||
case X64OP_LOAD:
|
||||
@@ -1279,7 +1298,7 @@ bool handle_access_violation(u32 addr, bool is_writing, x64_context* context) no
|
||||
|
||||
if (op != X64OP_LOAD_BE)
|
||||
{
|
||||
value = se_storage<u32>::swap(value);
|
||||
value = stx::se_storage<u32>::swap(value);
|
||||
}
|
||||
|
||||
if (op == X64OP_LOAD_CMP)
|
||||
@@ -1321,7 +1340,7 @@ bool handle_access_violation(u32 addr, bool is_writing, x64_context* context) no
|
||||
}
|
||||
|
||||
u32 val32 = static_cast<u32>(reg_value);
|
||||
if (!thread->write_reg(addr, op == X64OP_STORE ? se_storage<u32>::swap(val32) : val32))
|
||||
if (!thread->write_reg(addr, op == X64OP_STORE ? stx::se_storage<u32>::swap(val32) : val32))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -1342,9 +1361,9 @@ bool handle_access_violation(u32 addr, bool is_writing, x64_context* context) no
|
||||
RIP(context) += i_size;
|
||||
g_tls_fault_spu++;
|
||||
return true;
|
||||
}
|
||||
} while (0);
|
||||
|
||||
if (vm::check_addr(addr, std::max(1u, ::narrow<u32>(d_size)), is_writing ? vm::page_writable : vm::page_readable))
|
||||
if (vm::check_addr(addr, is_writing ? vm::page_writable : vm::page_readable))
|
||||
{
|
||||
if (cpu && cpu->test_stopped())
|
||||
{
|
||||
@@ -1354,13 +1373,11 @@ bool handle_access_violation(u32 addr, bool is_writing, x64_context* context) no
|
||||
return true;
|
||||
}
|
||||
|
||||
thread_local bool access_violation_recovered = false;
|
||||
|
||||
// Hack: allocate memory in case the emulator is stopping
|
||||
const auto hack_alloc = [&]()
|
||||
{
|
||||
// If failed the value remains true and std::terminate should be called
|
||||
access_violation_recovered = true;
|
||||
g_tls_access_violation_recovered = true;
|
||||
|
||||
const auto area = vm::reserve_map(vm::any, addr & -0x10000, 0x10000);
|
||||
|
||||
@@ -1369,7 +1386,7 @@ bool handle_access_violation(u32 addr, bool is_writing, x64_context* context) no
|
||||
return false;
|
||||
}
|
||||
|
||||
if (area->flags & 0x100 || (is_writing && vm::check_addr(addr, std::max(1u, ::narrow<u32>(d_size)))))
|
||||
if (area->flags & 0x100 || (is_writing && vm::check_addr(addr)))
|
||||
{
|
||||
// For 4kb pages or read only memory
|
||||
utils::memory_protect(vm::base(addr & -0x1000), 0x1000, utils::protection::rw);
|
||||
@@ -1377,7 +1394,7 @@ bool handle_access_violation(u32 addr, bool is_writing, x64_context* context) no
|
||||
}
|
||||
|
||||
area->falloc(addr & -0x10000, 0x10000);
|
||||
return vm::check_addr(addr, std::max(1u, ::narrow<u32>(d_size)), is_writing ? vm::page_writable : vm::page_readable);
|
||||
return vm::check_addr(addr, is_writing ? vm::page_writable : vm::page_readable);
|
||||
};
|
||||
|
||||
if (cpu)
|
||||
@@ -1389,7 +1406,7 @@ bool handle_access_violation(u32 addr, bool is_writing, x64_context* context) no
|
||||
{
|
||||
if (auto mem = vm::get(vm::any, addr))
|
||||
{
|
||||
std::shared_lock lock(pf_entries->mutex);
|
||||
reader_lock lock(pf_entries->mutex);
|
||||
|
||||
for (const auto& entry : pf_entries->entries)
|
||||
{
|
||||
@@ -1413,7 +1430,7 @@ bool handle_access_violation(u32 addr, bool is_writing, x64_context* context) no
|
||||
{
|
||||
data2 = (SYS_MEMORY_PAGE_FAULT_TYPE_PPU_THREAD << 32) | cpu->id;
|
||||
}
|
||||
else
|
||||
else if (cpu->id_type() == 2)
|
||||
{
|
||||
const auto& spu = static_cast<spu_thread&>(*cpu);
|
||||
|
||||
@@ -1427,12 +1444,12 @@ bool handle_access_violation(u32 addr, bool is_writing, x64_context* context) no
|
||||
u64 data3;
|
||||
{
|
||||
vm::reader_lock rlock;
|
||||
if (vm::check_addr(addr, std::max(1u, ::narrow<u32>(d_size)), is_writing ? vm::page_writable : vm::page_readable))
|
||||
if (vm::check_addr(addr, is_writing ? vm::page_writable : vm::page_readable))
|
||||
{
|
||||
// Memory was allocated inbetween, retry
|
||||
return true;
|
||||
}
|
||||
else if (vm::check_addr(addr, std::max(1u, ::narrow<u32>(d_size))))
|
||||
else if (vm::check_addr(addr))
|
||||
{
|
||||
data3 = SYS_MEMORY_PAGE_FAULT_CAUSE_READ_ONLY; // TODO
|
||||
}
|
||||
@@ -1512,10 +1529,10 @@ bool handle_access_violation(u32 addr, bool is_writing, x64_context* context) no
|
||||
|
||||
if (cpu->id_type() != 1)
|
||||
{
|
||||
if (!access_violation_recovered)
|
||||
if (!g_tls_access_violation_recovered)
|
||||
{
|
||||
vm_log.notice("\n%s", cpu->dump_all());
|
||||
vm_log.error("Access violation %s location 0x%x (%s)", is_writing ? "writing" : "reading", addr, (is_writing && vm::check_addr(addr)) ? "read-only memory" : "unmapped memory");
|
||||
vm_log.error("Access violation %s location 0x%x (%s) [type=u%u]", is_writing ? "writing" : "reading", addr, (is_writing && vm::check_addr(addr)) ? "read-only memory" : "unmapped memory", d_size * 8);
|
||||
}
|
||||
|
||||
// TODO:
|
||||
@@ -1543,16 +1560,16 @@ bool handle_access_violation(u32 addr, bool is_writing, x64_context* context) no
|
||||
|
||||
Emu.Pause();
|
||||
|
||||
if (cpu && !access_violation_recovered)
|
||||
if (cpu && !g_tls_access_violation_recovered)
|
||||
{
|
||||
vm_log.notice("\n%s", cpu->dump_all());
|
||||
}
|
||||
|
||||
// Note: a thread may access violate more than once after hack_alloc recovery
|
||||
// Do not log any further access violations in this case.
|
||||
if (!access_violation_recovered)
|
||||
if (!g_tls_access_violation_recovered)
|
||||
{
|
||||
vm_log.fatal("Access violation %s location 0x%x (%s)", is_writing ? "writing" : "reading", addr, (is_writing && vm::check_addr(addr)) ? "read-only memory" : "unmapped memory");
|
||||
vm_log.fatal("Access violation %s location 0x%x (%s) [type=u%u]", is_writing ? "writing" : "reading", addr, (is_writing && vm::check_addr(addr)) ? "read-only memory" : "unmapped memory", d_size * 8);
|
||||
}
|
||||
|
||||
while (Emu.IsPaused())
|
||||
@@ -1577,21 +1594,27 @@ static LONG exception_handler(PEXCEPTION_POINTERS pExp) noexcept
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
|
||||
const u64 addr64 = pExp->ExceptionRecord->ExceptionInformation[1] - reinterpret_cast<u64>(vm::g_base_addr);
|
||||
const u64 exec64 = (pExp->ExceptionRecord->ExceptionInformation[1] - reinterpret_cast<u64>(vm::g_exec_addr)) / 2;
|
||||
const auto ptr = reinterpret_cast<u8*>(pExp->ExceptionRecord->ExceptionInformation[1]);
|
||||
const bool is_writing = pExp->ExceptionRecord->ExceptionInformation[0] != 0;
|
||||
|
||||
if (pExp->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION && addr64 < 0x100000000ull)
|
||||
if (pExp->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION)
|
||||
{
|
||||
if (thread_ctrl::get_current() && handle_access_violation(static_cast<u32>(addr64), is_writing, pExp->ContextRecord))
|
||||
{
|
||||
return EXCEPTION_CONTINUE_EXECUTION;
|
||||
}
|
||||
}
|
||||
u32 addr = 0;
|
||||
|
||||
if (pExp->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION && exec64 < 0x100000000ull)
|
||||
{
|
||||
if (thread_ctrl::get_current() && handle_access_violation(static_cast<u32>(exec64), is_writing, pExp->ContextRecord))
|
||||
if (auto [addr0, ok] = vm::try_get_addr(ptr); ok)
|
||||
{
|
||||
addr = addr0;
|
||||
}
|
||||
else if (const usz exec64 = (ptr - vm::g_exec_addr) / 2; exec64 <= UINT32_MAX)
|
||||
{
|
||||
addr = static_cast<u32>(exec64);
|
||||
}
|
||||
else
|
||||
{
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
|
||||
if (thread_ctrl::get_current() && handle_access_violation(addr, is_writing, pExp->ContextRecord))
|
||||
{
|
||||
return EXCEPTION_CONTINUE_EXECUTION;
|
||||
}
|
||||
@@ -1732,14 +1755,13 @@ static void signal_handler(int sig, siginfo_t* info, void* uct) noexcept
|
||||
const bool is_writing = context->uc_mcontext.gregs[REG_ERR] & 0x2;
|
||||
#endif
|
||||
|
||||
const u64 addr64 = reinterpret_cast<u64>(info->si_addr) - reinterpret_cast<u64>(vm::g_base_addr);
|
||||
const u64 exec64 = (reinterpret_cast<u64>(info->si_addr) - reinterpret_cast<u64>(vm::g_exec_addr)) / 2;
|
||||
const auto cause = is_writing ? "writing" : "reading";
|
||||
|
||||
if (addr64 < 0x100000000ull)
|
||||
if (auto [addr, ok] = vm::try_get_addr(info->si_addr); ok)
|
||||
{
|
||||
// Try to process access violation
|
||||
if (thread_ctrl::get_current() && handle_access_violation(static_cast<u32>(addr64), is_writing, context))
|
||||
if (thread_ctrl::get_current() && handle_access_violation(addr, is_writing, context))
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -1774,12 +1796,18 @@ static void signal_handler(int sig, siginfo_t* info, void* uct) noexcept
|
||||
|
||||
if (IsDebuggerPresent())
|
||||
{
|
||||
__asm("int3;");
|
||||
// Convert to SIGTRAP
|
||||
raise(SIGTRAP);
|
||||
return;
|
||||
}
|
||||
|
||||
report_fatal_error(msg);
|
||||
}
|
||||
|
||||
void sigpipe_signaling_handler(int)
|
||||
{
|
||||
}
|
||||
|
||||
const bool s_exception_handler_set = []() -> bool
|
||||
{
|
||||
struct ::sigaction sa;
|
||||
@@ -1793,6 +1821,13 @@ const bool s_exception_handler_set = []() -> bool
|
||||
std::abort();
|
||||
}
|
||||
|
||||
sa.sa_handler = sigpipe_signaling_handler;
|
||||
if (::sigaction(SIGPIPE, &sa, NULL) == -1)
|
||||
{
|
||||
std::fprintf(stderr, "sigaction(SIGPIPE) failed (%d).\n", errno);
|
||||
std::abort();
|
||||
}
|
||||
|
||||
std::printf("Debugger: %d\n", +IsDebuggerPresent());
|
||||
return true;
|
||||
}();
|
||||
@@ -1822,33 +1857,81 @@ thread_local DECLARE(thread_ctrl::g_tls_error_callback) = nullptr;
|
||||
|
||||
DECLARE(thread_ctrl::g_native_core_layout) { native_core_arrangement::undefined };
|
||||
|
||||
void thread_base::start(native_entry entry)
|
||||
static atomic_t<u128, 64> s_thread_bits{0};
|
||||
|
||||
static atomic_t<thread_base**> s_thread_pool[128]{};
|
||||
|
||||
void thread_base::start()
|
||||
{
|
||||
for (u128 bits = s_thread_bits.load(); bits; bits &= bits - 1)
|
||||
{
|
||||
const u32 pos = utils::ctz128(bits);
|
||||
|
||||
if (!s_thread_pool[pos])
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
thread_base** tls = s_thread_pool[pos].exchange(nullptr);
|
||||
|
||||
if (!tls)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Receive "that" native thread handle, sent "this" thread_base
|
||||
const u64 _self = reinterpret_cast<u64>(atomic_storage<thread_base*>::load(*tls));
|
||||
m_thread.release(_self);
|
||||
ensure(_self != reinterpret_cast<u64>(this));
|
||||
atomic_storage<thread_base*>::store(*tls, this);
|
||||
s_thread_pool[pos].notify_one();
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
m_thread = ::_beginthreadex(nullptr, 0, entry, this, CREATE_SUSPENDED, nullptr);
|
||||
verify("thread_ctrl::start" HERE), m_thread, ::ResumeThread(reinterpret_cast<HANDLE>(+m_thread)) != -1;
|
||||
m_thread = ::_beginthreadex(nullptr, 0, entry_point, this, CREATE_SUSPENDED, nullptr);
|
||||
ensure(m_thread);
|
||||
ensure(::ResumeThread(reinterpret_cast<HANDLE>(+m_thread)) != -1);
|
||||
#else
|
||||
verify("thread_ctrl::start" HERE), pthread_create(reinterpret_cast<pthread_t*>(&m_thread.raw()), nullptr, entry, this) == 0;
|
||||
ensure(pthread_create(reinterpret_cast<pthread_t*>(&m_thread.raw()), nullptr, entry_point, this) == 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
void thread_base::initialize(void (*error_cb)(), bool(*wait_cb)(const void*))
|
||||
void thread_base::initialize(void (*error_cb)())
|
||||
{
|
||||
#ifndef _WIN32
|
||||
m_thread.release(reinterpret_cast<u64>(pthread_self()));
|
||||
#endif
|
||||
|
||||
// Initialize TLS variables
|
||||
thread_ctrl::g_tls_this_thread = this;
|
||||
|
||||
thread_ctrl::g_tls_error_callback = error_cb;
|
||||
|
||||
// Initialize atomic wait callback
|
||||
atomic_storage_futex::set_wait_callback(wait_cb);
|
||||
|
||||
g_tls_log_prefix = []
|
||||
{
|
||||
return thread_ctrl::get_name_cached();
|
||||
};
|
||||
|
||||
std::string name = thread_ctrl::get_name_cached();
|
||||
atomic_wait_engine::set_wait_callback([](const void*, u64 attempts, u64 stamp0) -> bool
|
||||
{
|
||||
if (attempts == umax)
|
||||
{
|
||||
g_tls_wait_time += __rdtsc() - stamp0;
|
||||
}
|
||||
else if (attempts > 1)
|
||||
{
|
||||
g_tls_wait_fail += attempts - 1;
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
set_name(thread_ctrl::get_name_cached());
|
||||
}
|
||||
|
||||
void thread_base::set_name(std::string name)
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
struct THREADNAME_INFO
|
||||
{
|
||||
@@ -1878,25 +1961,19 @@ void thread_base::initialize(void (*error_cb)(), bool(*wait_cb)(const void*))
|
||||
#endif
|
||||
|
||||
#if defined(__APPLE__)
|
||||
name.resize(std::min<std::size_t>(15, name.size()));
|
||||
name.resize(std::min<usz>(15, name.size()));
|
||||
pthread_setname_np(name.c_str());
|
||||
#elif defined(__DragonFly__) || defined(__FreeBSD__) || defined(__OpenBSD__)
|
||||
pthread_set_name_np(pthread_self(), name.c_str());
|
||||
#elif defined(__NetBSD__)
|
||||
pthread_setname_np(pthread_self(), "%s", name.data());
|
||||
#elif !defined(_WIN32)
|
||||
name.resize(std::min<std::size_t>(15, name.size()));
|
||||
name.resize(std::min<usz>(15, name.size()));
|
||||
pthread_setname_np(pthread_self(), name.c_str());
|
||||
#endif
|
||||
}
|
||||
|
||||
void thread_base::notify_abort() noexcept
|
||||
{
|
||||
m_signal.try_inc();
|
||||
atomic_storage_futex::raw_notify(+m_state_notifier);
|
||||
}
|
||||
|
||||
bool thread_base::finalize(thread_state result_state) noexcept
|
||||
u64 thread_base::finalize(thread_state result_state) noexcept
|
||||
{
|
||||
// Report pending errors
|
||||
error_code::error_report(0, 0, 0, 0);
|
||||
@@ -1934,29 +2011,183 @@ bool thread_base::finalize(thread_state result_state) noexcept
|
||||
return thread_ctrl::get_name_cached();
|
||||
};
|
||||
|
||||
sig_log.notice("Thread time: %fs (%fGc); Faults: %u [rsx:%u, spu:%u]; [soft:%u hard:%u]; Switches:[vol:%u unvol:%u]",
|
||||
sig_log.notice("Thread time: %fs (%fGc); Faults: %u [rsx:%u, spu:%u]; [soft:%u hard:%u]; Switches:[vol:%u unvol:%u]; Wait:[%.3fs, spur:%u]",
|
||||
time / 1000000000.,
|
||||
cycles / 1000000000.,
|
||||
g_tls_fault_all,
|
||||
g_tls_fault_rsx,
|
||||
g_tls_fault_spu,
|
||||
fsoft, fhard, ctxvol, ctxinv);
|
||||
fsoft, fhard, ctxvol, ctxinv,
|
||||
g_tls_wait_time / (utils::get_tsc_freq() / 1.),
|
||||
g_tls_wait_fail);
|
||||
|
||||
// Return true if need to delete thread object
|
||||
const bool ok = m_state.exchange(result_state) <= thread_state::aborting;
|
||||
atomic_wait_engine::set_wait_callback(nullptr);
|
||||
|
||||
// Avoid race with the destructor
|
||||
const u64 _self = m_thread;
|
||||
|
||||
// Set result state (errored or finalized)
|
||||
const bool ok = 0 == (3 & ~m_sync.fetch_op([&](u64& v)
|
||||
{
|
||||
v &= -4;
|
||||
v |= static_cast<u32>(result_state);
|
||||
}));
|
||||
|
||||
// Signal waiting threads
|
||||
m_state.notify_all();
|
||||
m_sync.notify_all(2);
|
||||
|
||||
// No detached thread supported atm
|
||||
return !ok;
|
||||
return _self;
|
||||
}
|
||||
|
||||
void thread_base::finalize() noexcept
|
||||
thread_base::native_entry thread_base::finalize(u64 _self) noexcept
|
||||
{
|
||||
atomic_storage_futex::set_wait_callback([](const void*){ return true; });
|
||||
g_tls_fault_all = 0;
|
||||
g_tls_fault_rsx = 0;
|
||||
g_tls_fault_spu = 0;
|
||||
g_tls_wait_time = 0;
|
||||
g_tls_wait_fail = 0;
|
||||
g_tls_access_violation_recovered = false;
|
||||
|
||||
const auto fake_self = reinterpret_cast<thread_base*>(_self);
|
||||
|
||||
g_tls_log_prefix = []() -> std::string { return {}; };
|
||||
thread_ctrl::g_tls_this_thread = nullptr;
|
||||
thread_ctrl::g_tls_this_thread = fake_self;
|
||||
|
||||
if (!_self)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Try to add self to thread pool
|
||||
set_name("..pool");
|
||||
|
||||
static constexpr u64 s_stop_bit = 0x8000'0000'0000'0000ull;
|
||||
|
||||
static atomic_t<u64> s_pool_ctr = []
|
||||
{
|
||||
std::atexit([]
|
||||
{
|
||||
s_pool_ctr |= s_stop_bit;
|
||||
|
||||
while (u64 remains = s_pool_ctr & ~s_stop_bit)
|
||||
{
|
||||
for (u32 i = 0; i < std::size(s_thread_pool); i++)
|
||||
{
|
||||
if (thread_base** ptls = s_thread_pool[i].exchange(nullptr))
|
||||
{
|
||||
// Extract thread handle
|
||||
const u64 _self = reinterpret_cast<u64>(*ptls);
|
||||
|
||||
// Wake up a thread and make sure it's joined
|
||||
s_thread_pool[i].notify_one();
|
||||
|
||||
#ifdef _WIN32
|
||||
const HANDLE handle = reinterpret_cast<HANDLE>(_self);
|
||||
WaitForSingleObject(handle, INFINITE);
|
||||
CloseHandle(handle);
|
||||
#else
|
||||
pthread_join(reinterpret_cast<pthread_t>(_self), nullptr);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return 0;
|
||||
}();
|
||||
|
||||
s_pool_ctr++;
|
||||
|
||||
u32 pos = -1;
|
||||
|
||||
while (true)
|
||||
{
|
||||
const auto [bits, ok] = s_thread_bits.fetch_op([](u128& bits)
|
||||
{
|
||||
if (~bits) [[likely]]
|
||||
{
|
||||
// Set lowest clear bit
|
||||
bits |= bits + 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
if (ok) [[likely]]
|
||||
{
|
||||
pos = utils::ctz128(~bits);
|
||||
break;
|
||||
}
|
||||
|
||||
s_thread_bits.wait(bits);
|
||||
}
|
||||
|
||||
const auto tls = &thread_ctrl::g_tls_this_thread;
|
||||
s_thread_pool[pos] = tls;
|
||||
|
||||
atomic_wait::list<2> list{};
|
||||
list.set<0>(s_pool_ctr, 0, s_stop_bit);
|
||||
list.set<1>(s_thread_pool[pos], tls);
|
||||
|
||||
while (s_thread_pool[pos] == tls || atomic_storage<thread_base*>::load(*tls) == fake_self)
|
||||
{
|
||||
list.wait();
|
||||
|
||||
if (s_pool_ctr & s_stop_bit)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Free thread pool slot
|
||||
s_thread_bits.atomic_op([pos](u128& val)
|
||||
{
|
||||
val &= ~(u128(1) << pos);
|
||||
});
|
||||
|
||||
s_thread_bits.notify_one();
|
||||
|
||||
if (--s_pool_ctr & s_stop_bit)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Return new entry point
|
||||
utils::prefetch_exec((*tls)->entry_point);
|
||||
return (*tls)->entry_point;
|
||||
}
|
||||
|
||||
thread_base::native_entry thread_base::make_trampoline(u64(*entry)(thread_base* _base))
|
||||
{
|
||||
return build_function_asm<native_entry>([&](asmjit::X86Assembler& c, auto& args)
|
||||
{
|
||||
using namespace asmjit;
|
||||
|
||||
Label _ret = c.newLabel();
|
||||
c.push(x86::rbp);
|
||||
c.sub(x86::rsp, 0x20);
|
||||
|
||||
// Call entry point (TODO: support for detached threads missing?)
|
||||
c.call(imm_ptr(entry));
|
||||
|
||||
// Call finalize, return if zero
|
||||
c.mov(args[0], x86::rax);
|
||||
c.call(imm_ptr<native_entry(*)(u64)>(finalize));
|
||||
c.test(x86::rax, x86::rax);
|
||||
c.jz(_ret);
|
||||
|
||||
// Otherwise, call it as an entry point with first arg = new current thread
|
||||
c.mov(x86::rbp, x86::rax);
|
||||
c.call(imm_ptr(thread_ctrl::get_current));
|
||||
c.mov(args[0], x86::rax);
|
||||
c.add(x86::rsp, 0x28);
|
||||
c.jmp(x86::rbp);
|
||||
|
||||
c.bind(_ret);
|
||||
c.add(x86::rsp, 0x28);
|
||||
c.ret();
|
||||
});
|
||||
}
|
||||
|
||||
void thread_ctrl::_wait_for(u64 usec, bool alert /* true */)
|
||||
@@ -2008,12 +2239,13 @@ void thread_ctrl::_wait_for(u64 usec, bool alert /* true */)
|
||||
}
|
||||
#endif
|
||||
|
||||
if (_this->m_signal && _this->m_signal.exchange(0))
|
||||
if (_this->m_sync.bit_test_reset(2))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_this->m_signal.wait(0, atomic_wait_timeout{usec <= 0xffff'ffff'ffff'ffff / 1000 ? usec * 1000 : 0xffff'ffff'ffff'ffff});
|
||||
// Wait for signal and thread state abort
|
||||
_this->m_sync.wait(0, 4 + 1, atomic_wait_timeout{usec <= 0xffff'ffff'ffff'ffff / 1000 ? usec * 1000 : 0xffff'ffff'ffff'ffff});
|
||||
}
|
||||
|
||||
std::string thread_ctrl::get_name_cached()
|
||||
@@ -2025,63 +2257,110 @@ std::string thread_ctrl::get_name_cached()
|
||||
return {};
|
||||
}
|
||||
|
||||
static thread_local stx::shared_cptr<std::string> name_cache;
|
||||
static thread_local shared_ptr<std::string> name_cache;
|
||||
|
||||
if (!_this->m_tname.is_equal(name_cache)) [[unlikely]]
|
||||
{
|
||||
name_cache = _this->m_tname.load();
|
||||
_this->m_tname.peek_op([&](const shared_ptr<std::string>& ptr)
|
||||
{
|
||||
if (ptr != name_cache)
|
||||
{
|
||||
name_cache = ptr;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return *name_cache;
|
||||
}
|
||||
|
||||
thread_base::thread_base(std::string_view name)
|
||||
: m_tname(stx::shared_cptr<std::string>::make(name))
|
||||
thread_base::thread_base(native_entry entry, std::string_view name)
|
||||
: entry_point(entry)
|
||||
, m_tname(make_single<std::string>(name))
|
||||
{
|
||||
}
|
||||
|
||||
thread_base::~thread_base()
|
||||
{
|
||||
if (m_thread)
|
||||
// Only cleanup on errored status
|
||||
if ((m_sync & 3) == 2)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
CloseHandle(reinterpret_cast<HANDLE>(m_thread.raw()));
|
||||
const HANDLE handle0 = reinterpret_cast<HANDLE>(m_thread.load());
|
||||
WaitForSingleObject(handle0, INFINITE);
|
||||
CloseHandle(handle0);
|
||||
#else
|
||||
pthread_detach(reinterpret_cast<pthread_t>(m_thread.raw()));
|
||||
pthread_join(reinterpret_cast<pthread_t>(m_thread.load()), nullptr);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
bool thread_base::join() const
|
||||
bool thread_base::join(bool dtor) const
|
||||
{
|
||||
for (auto state = m_state.load(); state != thread_state::finished && state != thread_state::errored;)
|
||||
// Check if already finished
|
||||
if (m_sync & 2)
|
||||
{
|
||||
m_state.wait(state);
|
||||
state = m_state;
|
||||
return (m_sync & 3) == 3;
|
||||
}
|
||||
|
||||
return m_state.load() == thread_state::finished;
|
||||
// Hacked for too sleepy threads (1ms) TODO: make sure it's unneeded and remove
|
||||
const auto timeout = dtor && Emu.IsStopped() ? atomic_wait_timeout{1'000'000} : atomic_wait_timeout::inf;
|
||||
|
||||
bool warn = false;
|
||||
auto stamp0 = __rdtsc();
|
||||
|
||||
for (u64 i = 0; (m_sync & 3) <= 1; i++)
|
||||
{
|
||||
m_sync.wait(0, 2, timeout);
|
||||
|
||||
if (m_sync & 2)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (i > 20 && Emu.IsStopped())
|
||||
{
|
||||
stamp0 = __rdtsc();
|
||||
atomic_wait_engine::raw_notify(0, get_native_id());
|
||||
stamp0 = __rdtsc() - stamp0;
|
||||
warn = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (warn)
|
||||
{
|
||||
sig_log.error(u8"Thread [%s] is too sleepy. Took %.3fµs to wake it up!", *m_tname.load(), stamp0 / (utils::get_tsc_freq() / 1000000.));
|
||||
}
|
||||
|
||||
return (m_sync & 3) == 3;
|
||||
}
|
||||
|
||||
void thread_base::notify()
|
||||
{
|
||||
// Increment with saturation
|
||||
if (m_signal.try_inc())
|
||||
{
|
||||
// Considered impossible to have a situation when not notified
|
||||
m_signal.notify_all();
|
||||
}
|
||||
// Set notification
|
||||
m_sync |= 4;
|
||||
m_sync.notify_one(4);
|
||||
}
|
||||
|
||||
u64 thread_base::get_native_id() const
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return GetThreadId(reinterpret_cast<HANDLE>(m_thread.load()));
|
||||
#else
|
||||
return m_thread.load();
|
||||
#endif
|
||||
}
|
||||
|
||||
u64 thread_base::get_cycles()
|
||||
{
|
||||
u64 cycles;
|
||||
u64 cycles = 0;
|
||||
|
||||
const u64 handle = m_thread;
|
||||
|
||||
#ifdef _WIN32
|
||||
if (QueryThreadCycleTime(reinterpret_cast<HANDLE>(m_thread.load()), &cycles))
|
||||
if (QueryThreadCycleTime(reinterpret_cast<HANDLE>(handle), &cycles))
|
||||
{
|
||||
#elif __APPLE__
|
||||
mach_port_name_t port = pthread_mach_thread_np(reinterpret_cast<pthread_t>(m_thread.load()));
|
||||
mach_port_name_t port = pthread_mach_thread_np(reinterpret_cast<pthread_t>(handle));
|
||||
mach_msg_type_number_t count = THREAD_BASIC_INFO_COUNT;
|
||||
thread_basic_info_data_t info;
|
||||
kern_return_t ret = thread_info(port, THREAD_BASIC_INFO, reinterpret_cast<thread_info_t>(&info), &count);
|
||||
@@ -2092,11 +2371,11 @@ u64 thread_base::get_cycles()
|
||||
#else
|
||||
clockid_t _clock;
|
||||
struct timespec thread_time;
|
||||
if (!pthread_getcpuclockid(reinterpret_cast<pthread_t>(m_thread.load()), &_clock) && !clock_gettime(_clock, &thread_time))
|
||||
if (!pthread_getcpuclockid(reinterpret_cast<pthread_t>(handle), &_clock) && !clock_gettime(_clock, &thread_time))
|
||||
{
|
||||
cycles = static_cast<u64>(thread_time.tv_sec) * 1'000'000'000 + thread_time.tv_nsec;
|
||||
#endif
|
||||
if (const u64 old_cycles = m_cycles.exchange(cycles))
|
||||
if (const u64 old_cycles = m_sync.fetch_op([&](u64& v){ v &= 7; v |= (cycles << 3); }) >> 3)
|
||||
{
|
||||
return cycles - old_cycles;
|
||||
}
|
||||
@@ -2106,11 +2385,11 @@ u64 thread_base::get_cycles()
|
||||
}
|
||||
else
|
||||
{
|
||||
return m_cycles;
|
||||
return m_sync >> 3;
|
||||
}
|
||||
}
|
||||
|
||||
void thread_ctrl::emergency_exit(std::string_view reason)
|
||||
[[noreturn]] void thread_ctrl::emergency_exit(std::string_view reason)
|
||||
{
|
||||
sig_log.fatal("Thread terminated due to fatal error: %s", reason);
|
||||
|
||||
@@ -2133,17 +2412,20 @@ void thread_ctrl::emergency_exit(std::string_view reason)
|
||||
{
|
||||
g_tls_error_callback();
|
||||
|
||||
if (_this->finalize(thread_state::errored))
|
||||
u64 _self = _this->finalize(thread_state::errored);
|
||||
|
||||
if (!_self)
|
||||
{
|
||||
// Unused, detached thread support remnant
|
||||
delete _this;
|
||||
}
|
||||
|
||||
thread_base::finalize();
|
||||
thread_base::finalize(0);
|
||||
|
||||
#ifdef _WIN32
|
||||
_endthreadex(0);
|
||||
#else
|
||||
pthread_exit(0);
|
||||
pthread_exit(nullptr);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -2190,8 +2472,8 @@ void thread_ctrl::detect_cpu_layout()
|
||||
else
|
||||
{
|
||||
// Iterate through the buffer until a core with hyperthreading is found
|
||||
auto ptr = reinterpret_cast<std::uintptr_t>(buffer.data());
|
||||
const std::uintptr_t end = ptr + buffer_size;
|
||||
auto ptr = reinterpret_cast<uptr>(buffer.data());
|
||||
const uptr end = ptr + buffer_size;
|
||||
|
||||
while (ptr < end)
|
||||
{
|
||||
@@ -2515,3 +2797,27 @@ u64 thread_ctrl::get_thread_affinity_mask()
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
std::pair<void*, usz> thread_ctrl::get_thread_stack()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
ULONG_PTR _min = 0;
|
||||
ULONG_PTR _max = 0;
|
||||
GetCurrentThreadStackLimits(&_min, &_max);
|
||||
const usz ssize = _max - _min;
|
||||
const auto saddr = reinterpret_cast<void*>(_min);
|
||||
#else
|
||||
void* saddr = 0;
|
||||
usz ssize = 0;
|
||||
pthread_attr_t attr;
|
||||
#ifdef __linux__
|
||||
pthread_getattr_np(pthread_self(), &attr);
|
||||
pthread_attr_getstack(&attr, &saddr, &ssize);
|
||||
#else
|
||||
pthread_attr_get_np(pthread_self(), &attr);
|
||||
pthread_attr_getstackaddr(&attr, &saddr);
|
||||
pthread_attr_getstacksize(&attr, &ssize);
|
||||
#endif
|
||||
#endif
|
||||
return {saddr, ssize};
|
||||
}
|
||||
|
||||
+62
-93
@@ -1,20 +1,16 @@
|
||||
#pragma once
|
||||
|
||||
#include "types.h"
|
||||
#include "util/types.hpp"
|
||||
#include "util/atomic.hpp"
|
||||
#include "util/shared_cptr.hpp"
|
||||
#include "util/shared_ptr.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <string_view>
|
||||
|
||||
#include "mutex.h"
|
||||
#include "cond.h"
|
||||
#include "lockless.h"
|
||||
|
||||
// Report error and call std::abort(), defined in main.cpp
|
||||
[[noreturn]] void report_fatal_error(const std::string&);
|
||||
|
||||
// Hardware core layout
|
||||
enum class native_core_arrangement : u32
|
||||
{
|
||||
@@ -34,12 +30,15 @@ enum class thread_class : u32
|
||||
|
||||
enum class thread_state : u32
|
||||
{
|
||||
created, // Initial state
|
||||
aborting, // The thread has been joined in the destructor or explicitly aborted
|
||||
errored, // Set after the emergency_exit call
|
||||
finished // Final state, always set at the end of thread execution
|
||||
created = 0, // Initial state
|
||||
aborting = 1, // The thread has been joined in the destructor or explicitly aborted
|
||||
errored = 2, // Set after the emergency_exit call
|
||||
finished = 3, // Final state, always set at the end of thread execution
|
||||
mask = 3
|
||||
};
|
||||
|
||||
class need_wakeup {};
|
||||
|
||||
template <class Context>
|
||||
class named_thread;
|
||||
|
||||
@@ -90,6 +89,7 @@ struct thread_thread_name<T, std::void_t<decltype(named_thread<T>::thread_name)>
|
||||
// Thread base class
|
||||
class thread_base
|
||||
{
|
||||
public:
|
||||
// Native thread entry point function type
|
||||
#ifdef _WIN32
|
||||
using native_entry = uint(__stdcall*)(void* arg);
|
||||
@@ -97,38 +97,35 @@ class thread_base
|
||||
using native_entry = void*(*)(void* arg);
|
||||
#endif
|
||||
|
||||
const native_entry entry_point;
|
||||
|
||||
private:
|
||||
// Thread handle (platform-specific)
|
||||
atomic_t<std::uintptr_t> m_thread{0};
|
||||
atomic_t<u64> m_thread{0};
|
||||
|
||||
// Thread playtoy, that shouldn't be used
|
||||
atomic_t<u32> m_signal{0};
|
||||
|
||||
// Thread state
|
||||
atomic_t<thread_state> m_state = thread_state::created;
|
||||
|
||||
// Thread state notification info
|
||||
atomic_t<const void*> m_state_notifier{nullptr};
|
||||
// Thread state and cycles
|
||||
atomic_t<u64> m_sync{0};
|
||||
|
||||
// Thread name
|
||||
stx::atomic_cptr<std::string> m_tname;
|
||||
|
||||
//
|
||||
atomic_t<u64> m_cycles = 0;
|
||||
atomic_ptr<std::string> m_tname;
|
||||
|
||||
// Start thread
|
||||
void start(native_entry);
|
||||
void start();
|
||||
|
||||
// Called at the thread start
|
||||
void initialize(void (*error_cb)(), bool(*wait_cb)(const void*));
|
||||
void initialize(void (*error_cb)());
|
||||
|
||||
// May be called in destructor
|
||||
void notify_abort() noexcept;
|
||||
|
||||
// Called at the thread end, returns true if needs destruction
|
||||
bool finalize(thread_state result) noexcept;
|
||||
// Called at the thread end, returns self handle
|
||||
u64 finalize(thread_state result) noexcept;
|
||||
|
||||
// Cleanup after possibly deleting the thread instance
|
||||
static void finalize() noexcept;
|
||||
static native_entry finalize(u64 _self) noexcept;
|
||||
|
||||
// Set name for debugger
|
||||
static void set_name(std::string);
|
||||
|
||||
// Make entry point
|
||||
static native_entry make_trampoline(u64(*)(thread_base*));
|
||||
|
||||
friend class thread_ctrl;
|
||||
|
||||
@@ -136,7 +133,7 @@ class thread_base
|
||||
friend class named_thread;
|
||||
|
||||
protected:
|
||||
thread_base(std::string_view name);
|
||||
thread_base(native_entry, std::string_view name);
|
||||
|
||||
~thread_base();
|
||||
|
||||
@@ -145,10 +142,13 @@ public:
|
||||
u64 get_cycles();
|
||||
|
||||
// Wait for the thread (it does NOT change thread state, and can be called from multiple threads)
|
||||
bool join() const;
|
||||
bool join(bool dtor = false) const;
|
||||
|
||||
// Notify the thread
|
||||
void notify();
|
||||
|
||||
// Get thread id
|
||||
u64 get_native_id() const;
|
||||
};
|
||||
|
||||
// Collection of global function for current thread
|
||||
@@ -188,14 +188,14 @@ public:
|
||||
// Set current thread name (not recommended)
|
||||
static void set_name(std::string_view name)
|
||||
{
|
||||
g_tls_this_thread->m_tname.store(stx::shared_cptr<std::string>::make(name));
|
||||
g_tls_this_thread->m_tname.store(make_single<std::string>(name));
|
||||
}
|
||||
|
||||
// Set thread name (not recommended)
|
||||
template <typename T>
|
||||
static void set_name(named_thread<T>& thread, std::string_view name)
|
||||
{
|
||||
static_cast<thread_base&>(thread).m_tname.store(stx::shared_cptr<std::string>::make(name));
|
||||
static_cast<thread_base&>(thread).m_tname.store(make_single<std::string>(name));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
@@ -211,15 +211,15 @@ public:
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static void raw_notify(named_thread<T>& thread)
|
||||
static u64 get_native_id(named_thread<T>& thread)
|
||||
{
|
||||
static_cast<thread_base&>(thread).notify_abort();
|
||||
return static_cast<thread_base&>(thread).get_native_id();
|
||||
}
|
||||
|
||||
// Read current state
|
||||
static inline thread_state state()
|
||||
{
|
||||
return g_tls_this_thread->m_state;
|
||||
return static_cast<thread_state>(g_tls_this_thread->m_sync & 3);
|
||||
}
|
||||
|
||||
// Wait once with timeout. May spuriously return false.
|
||||
@@ -261,6 +261,9 @@ public:
|
||||
// Miscellaneous
|
||||
static u64 get_thread_affinity_mask();
|
||||
|
||||
// Get current thread stack addr and size
|
||||
static std::pair<void*, usz> get_thread_stack();
|
||||
|
||||
private:
|
||||
// Miscellaneous
|
||||
static const u64 process_affinity_mask;
|
||||
@@ -273,59 +276,20 @@ class named_thread final : public Context, result_storage_t<Context>, thread_bas
|
||||
using result = result_storage_t<Context>;
|
||||
using thread = thread_base;
|
||||
|
||||
// Type-erased thread entry point
|
||||
#ifdef _WIN32
|
||||
static inline uint __stdcall entry_point(void* arg)
|
||||
#else
|
||||
static inline void* entry_point(void* arg)
|
||||
#endif
|
||||
static u64 entry_point(thread_base* _base)
|
||||
{
|
||||
const auto _this = static_cast<named_thread*>(static_cast<thread*>(arg));
|
||||
|
||||
// Perform self-cleanup if necessary
|
||||
if (_this->entry_point())
|
||||
{
|
||||
delete _this;
|
||||
}
|
||||
|
||||
thread::finalize();
|
||||
return 0;
|
||||
return static_cast<named_thread*>(_base)->entry_point2();
|
||||
}
|
||||
|
||||
bool entry_point()
|
||||
u64 entry_point2()
|
||||
{
|
||||
auto tls_error_cb = []()
|
||||
thread::initialize([]()
|
||||
{
|
||||
if constexpr (!result::empty)
|
||||
{
|
||||
// Construct using default constructor in the case of failure
|
||||
new (static_cast<result*>(static_cast<named_thread*>(thread_ctrl::get_current()))->get()) typename result::type();
|
||||
}
|
||||
};
|
||||
|
||||
thread::initialize(tls_error_cb, [](const void* data)
|
||||
{
|
||||
const auto _this = thread_ctrl::get_current();
|
||||
|
||||
if (_this->m_state >= thread_state::aborting)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
_this->m_state_notifier.release(data);
|
||||
|
||||
if (!data)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (_this->m_state >= thread_state::aborting)
|
||||
{
|
||||
_this->m_state_notifier.release(nullptr);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
if constexpr (result::empty)
|
||||
@@ -342,6 +306,8 @@ class named_thread final : public Context, result_storage_t<Context>, thread_bas
|
||||
return thread::finalize(thread_state::finished);
|
||||
}
|
||||
|
||||
static inline thread::native_entry trampoline = thread::make_trampoline(entry_point);
|
||||
|
||||
friend class thread_ctrl;
|
||||
|
||||
public:
|
||||
@@ -349,26 +315,26 @@ public:
|
||||
template <bool Valid = std::is_default_constructible_v<Context> && thread_thread_name<Context>(), typename = std::enable_if_t<Valid>>
|
||||
named_thread()
|
||||
: Context()
|
||||
, thread(Context::thread_name)
|
||||
, thread(trampoline, Context::thread_name)
|
||||
{
|
||||
thread::start(&named_thread::entry_point);
|
||||
thread::start();
|
||||
}
|
||||
|
||||
// Normal forwarding constructor
|
||||
template <typename... Args, typename = std::enable_if_t<std::is_constructible_v<Context, Args&&...>>>
|
||||
named_thread(std::string_view name, Args&&... args)
|
||||
: Context(std::forward<Args>(args)...)
|
||||
, thread(name)
|
||||
, thread(trampoline, name)
|
||||
{
|
||||
thread::start(&named_thread::entry_point);
|
||||
thread::start();
|
||||
}
|
||||
|
||||
// Lambda constructor, also the implicit deduction guide candidate
|
||||
named_thread(std::string_view name, Context&& f)
|
||||
: Context(std::forward<Context>(f))
|
||||
, thread(name)
|
||||
, thread(trampoline, name)
|
||||
{
|
||||
thread::start(&named_thread::entry_point);
|
||||
thread::start();
|
||||
}
|
||||
|
||||
named_thread(const named_thread&) = delete;
|
||||
@@ -400,19 +366,22 @@ public:
|
||||
// Access thread state
|
||||
operator thread_state() const
|
||||
{
|
||||
return thread::m_state.load();
|
||||
return static_cast<thread_state>(thread::m_sync.load() & 3);
|
||||
}
|
||||
|
||||
// Try to abort by assigning thread_state::aborting (UB if assigning different state)
|
||||
named_thread& operator=(thread_state s)
|
||||
{
|
||||
ASSUME(s == thread_state::aborting);
|
||||
|
||||
if (s == thread_state::aborting && thread::m_state.compare_and_swap_test(thread_state::created, s))
|
||||
if (s == thread_state::aborting && thread::m_sync.fetch_op([](u64& v){ return !(v & 3) && (v |= 1); }).second)
|
||||
{
|
||||
if (s == thread_state::aborting)
|
||||
{
|
||||
thread::notify_abort();
|
||||
thread::m_sync.notify_one(1);
|
||||
}
|
||||
|
||||
if constexpr (std::is_base_of_v<need_wakeup, Context>)
|
||||
{
|
||||
this->wake_up();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -424,7 +393,7 @@ public:
|
||||
{
|
||||
// Assign aborting state forcefully
|
||||
operator=(thread_state::aborting);
|
||||
thread::join();
|
||||
thread::join(true);
|
||||
|
||||
if constexpr (!result::empty)
|
||||
{
|
||||
|
||||
+9
-9
@@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "types.h"
|
||||
#include "util/types.hpp"
|
||||
|
||||
#include <chrono>
|
||||
|
||||
@@ -8,8 +8,8 @@ class Timer
|
||||
{
|
||||
private:
|
||||
bool m_stopped;
|
||||
std::chrono::steady_clock::time_point m_start;
|
||||
std::chrono::steady_clock::time_point m_end;
|
||||
steady_clock::time_point m_start;
|
||||
steady_clock::time_point m_end;
|
||||
|
||||
public:
|
||||
Timer() : m_stopped(false)
|
||||
@@ -19,13 +19,13 @@ public:
|
||||
void Start()
|
||||
{
|
||||
m_stopped = false;
|
||||
m_start = std::chrono::steady_clock::now();
|
||||
m_start = steady_clock::now();
|
||||
}
|
||||
|
||||
void Stop()
|
||||
{
|
||||
m_stopped = true;
|
||||
m_end = std::chrono::steady_clock::now();
|
||||
m_end = steady_clock::now();
|
||||
}
|
||||
|
||||
double GetElapsedTimeInSec() const
|
||||
@@ -40,21 +40,21 @@ public:
|
||||
|
||||
u64 GetElapsedTimeInMicroSec() const
|
||||
{
|
||||
std::chrono::steady_clock::time_point now = m_stopped ? m_end : std::chrono::steady_clock::now();
|
||||
steady_clock::time_point now = m_stopped ? m_end : steady_clock::now();
|
||||
|
||||
return std::chrono::duration_cast<std::chrono::microseconds>(now - m_start).count();
|
||||
}
|
||||
|
||||
u64 GetElapsedTimeInNanoSec() const
|
||||
{
|
||||
std::chrono::steady_clock::time_point now = m_stopped ? m_end : std::chrono::steady_clock::now();
|
||||
steady_clock::time_point now = m_stopped ? m_end : steady_clock::now();
|
||||
|
||||
return std::chrono::duration_cast<std::chrono::nanoseconds>(now - m_start).count();
|
||||
}
|
||||
|
||||
u64 GetMsSince(std::chrono::steady_clock::time_point timestamp)
|
||||
u64 GetMsSince(steady_clock::time_point timestamp)
|
||||
{
|
||||
std::chrono::steady_clock::time_point now = m_stopped ? m_end : std::chrono::steady_clock::now();
|
||||
steady_clock::time_point now = m_stopped ? m_end : steady_clock::now();
|
||||
|
||||
return std::chrono::duration_cast<std::chrono::milliseconds>(now - timestamp).count();
|
||||
}
|
||||
|
||||
+11
-11
@@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
#pragma once
|
||||
|
||||
#include "types.h"
|
||||
#include "util/types.hpp"
|
||||
#include "StrFmt.h"
|
||||
#include <vector>
|
||||
|
||||
@@ -92,7 +92,7 @@ namespace utils
|
||||
void set_length(const u32 new_length)
|
||||
{
|
||||
end = start + new_length - 1;
|
||||
ASSERT(valid());
|
||||
ensure(valid());
|
||||
}
|
||||
|
||||
u32 next_address() const
|
||||
@@ -282,7 +282,7 @@ namespace utils
|
||||
|
||||
public:
|
||||
// Wrapped functions
|
||||
inline void reserve(size_t nr) { data.reserve(nr); }
|
||||
inline void reserve(usz nr) { data.reserve(nr); }
|
||||
inline void clear() { data.clear(); }
|
||||
inline size_type size() const { return data.size(); }
|
||||
inline bool empty() const { return data.empty(); }
|
||||
@@ -456,9 +456,9 @@ namespace utils
|
||||
// Will fail if ranges within the vector overlap our touch each-other
|
||||
bool check_consistency() const
|
||||
{
|
||||
size_t _size = data.size();
|
||||
usz _size = data.size();
|
||||
|
||||
for (size_t i = 0; i < _size; ++i)
|
||||
for (usz i = 0; i < _size; ++i)
|
||||
{
|
||||
const auto &r1 = data[i];
|
||||
if (!r1.valid())
|
||||
@@ -466,7 +466,7 @@ namespace utils
|
||||
continue;
|
||||
}
|
||||
|
||||
for (size_t j = i + 1; j < _size; ++j)
|
||||
for (usz j = i + 1; j < _size; ++j)
|
||||
{
|
||||
const auto &r2 = data[j];
|
||||
if (!r2.valid())
|
||||
@@ -582,15 +582,15 @@ namespace utils
|
||||
|
||||
namespace std
|
||||
{
|
||||
static_assert(sizeof(size_t) >= 2 * sizeof(u32), "size_t must be at least twice the size of u32");
|
||||
static_assert(sizeof(usz) >= 2 * sizeof(u32), "usz must be at least twice the size of u32");
|
||||
|
||||
template <>
|
||||
struct hash<utils::address_range>
|
||||
{
|
||||
std::size_t operator()(const utils::address_range& k) const
|
||||
usz operator()(const utils::address_range& k) const
|
||||
{
|
||||
// we can guarantee a unique hash since our type is 64 bits and size_t as well
|
||||
return (size_t{ k.start } << 32) | size_t{ k.end };
|
||||
// we can guarantee a unique hash since our type is 64 bits and usz as well
|
||||
return (usz{ k.start } << 32) | usz{ k.end };
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
-215
@@ -1,215 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "types.h"
|
||||
|
||||
namespace utils
|
||||
{
|
||||
// Rotate helpers
|
||||
#if defined(__GNUG__)
|
||||
|
||||
inline u8 rol8(u8 x, u8 n)
|
||||
{
|
||||
#if __has_builtin(__builtin_rotateleft8)
|
||||
return __builtin_rotateleft8(x, n);
|
||||
#else
|
||||
u8 result = x;
|
||||
__asm__("rolb %[n], %[result]" : [result] "+g"(result) : [n] "c"(n));
|
||||
return result;
|
||||
#endif
|
||||
}
|
||||
|
||||
inline u8 ror8(u8 x, u8 n)
|
||||
{
|
||||
#if __has_builtin(__builtin_rotateright8)
|
||||
return __builtin_rotateright8(x, n);
|
||||
#else
|
||||
u8 result = x;
|
||||
__asm__("rorb %[n], %[result]" : [result] "+g"(result) : [n] "c"(n));
|
||||
return result;
|
||||
#endif
|
||||
}
|
||||
|
||||
inline u16 rol16(u16 x, u16 n)
|
||||
{
|
||||
#if __has_builtin(__builtin_rotateleft16)
|
||||
return __builtin_rotateleft16(x, n);
|
||||
#else
|
||||
u16 result = x;
|
||||
__asm__("rolw %b[n], %[result]" : [result] "+g"(result) : [n] "c"(n));
|
||||
return result;
|
||||
#endif
|
||||
}
|
||||
|
||||
inline u16 ror16(u16 x, u16 n)
|
||||
{
|
||||
#if __has_builtin(__builtin_rotateright16)
|
||||
return __builtin_rotateright16(x, n);
|
||||
#else
|
||||
u16 result = x;
|
||||
__asm__("rorw %b[n], %[result]" : [result] "+g"(result) : [n] "c"(n));
|
||||
return result;
|
||||
#endif
|
||||
}
|
||||
|
||||
inline u32 rol32(u32 x, u32 n)
|
||||
{
|
||||
#if __has_builtin(__builtin_rotateleft32)
|
||||
return __builtin_rotateleft32(x, n);
|
||||
#else
|
||||
u32 result = x;
|
||||
__asm__("roll %b[n], %[result]" : [result] "+g"(result) : [n] "c"(n));
|
||||
return result;
|
||||
#endif
|
||||
}
|
||||
|
||||
inline u32 ror32(u32 x, u32 n)
|
||||
{
|
||||
#if __has_builtin(__builtin_rotateright32)
|
||||
return __builtin_rotateright32(x, n);
|
||||
#else
|
||||
u32 result = x;
|
||||
__asm__("rorl %b[n], %[result]" : [result] "+g"(result) : [n] "c"(n));
|
||||
return result;
|
||||
#endif
|
||||
}
|
||||
|
||||
inline u64 rol64(u64 x, u64 n)
|
||||
{
|
||||
#if __has_builtin(__builtin_rotateleft64)
|
||||
return __builtin_rotateleft64(x, n);
|
||||
#else
|
||||
u64 result = x;
|
||||
__asm__("rolq %b[n], %[result]" : [result] "+g"(result) : [n] "c"(n));
|
||||
return result;
|
||||
#endif
|
||||
}
|
||||
|
||||
inline u64 ror64(u64 x, u64 n)
|
||||
{
|
||||
#if __has_builtin(__builtin_rotateright64)
|
||||
return __builtin_rotateright64(x, n);
|
||||
#else
|
||||
u64 result = x;
|
||||
__asm__("rorq %b[n], %[result]" : [result] "+g"(result) : [n] "c"(n));
|
||||
return result;
|
||||
#endif
|
||||
}
|
||||
|
||||
constexpr u64 umulh64(u64 a, u64 b)
|
||||
{
|
||||
const __uint128_t x = a;
|
||||
const __uint128_t y = b;
|
||||
return (x * y) >> 64;
|
||||
}
|
||||
|
||||
constexpr s64 mulh64(s64 a, s64 b)
|
||||
{
|
||||
const __int128_t x = a;
|
||||
const __int128_t y = b;
|
||||
return (x * y) >> 64;
|
||||
}
|
||||
|
||||
constexpr s64 div128(s64 high, s64 low, s64 divisor, s64* remainder = nullptr)
|
||||
{
|
||||
const __int128_t x = (__uint128_t{u64(high)} << 64) | u64(low);
|
||||
const __int128_t r = x / divisor;
|
||||
|
||||
if (remainder)
|
||||
{
|
||||
*remainder = x % divisor;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
constexpr u64 udiv128(u64 high, u64 low, u64 divisor, u64* remainder = nullptr)
|
||||
{
|
||||
const __uint128_t x = (__uint128_t{high} << 64) | low;
|
||||
const __uint128_t r = x / divisor;
|
||||
|
||||
if (remainder)
|
||||
{
|
||||
*remainder = x % divisor;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
#elif defined(_MSC_VER)
|
||||
inline u8 rol8(u8 x, u8 n)
|
||||
{
|
||||
return _rotl8(x, n);
|
||||
}
|
||||
|
||||
inline u8 ror8(u8 x, u8 n)
|
||||
{
|
||||
return _rotr8(x, n);
|
||||
}
|
||||
|
||||
inline u16 rol16(u16 x, u16 n)
|
||||
{
|
||||
return _rotl16(x, (u8)n);
|
||||
}
|
||||
|
||||
inline u16 ror16(u16 x, u16 n)
|
||||
{
|
||||
return _rotr16(x, (u8)n);
|
||||
}
|
||||
|
||||
inline u32 rol32(u32 x, u32 n)
|
||||
{
|
||||
return _rotl(x, (int)n);
|
||||
}
|
||||
|
||||
inline u32 ror32(u32 x, u32 n)
|
||||
{
|
||||
return _rotr(x, (int)n);
|
||||
}
|
||||
|
||||
inline u64 rol64(u64 x, u64 n)
|
||||
{
|
||||
return _rotl64(x, (int)n);
|
||||
}
|
||||
|
||||
inline u64 ror64(u64 x, u64 n)
|
||||
{
|
||||
return _rotr64(x, (int)n);
|
||||
}
|
||||
|
||||
inline u64 umulh64(u64 x, u64 y)
|
||||
{
|
||||
return __umulh(x, y);
|
||||
}
|
||||
|
||||
inline s64 mulh64(s64 x, s64 y)
|
||||
{
|
||||
return __mulh(x, y);
|
||||
}
|
||||
|
||||
inline s64 div128(s64 high, s64 low, s64 divisor, s64* remainder = nullptr)
|
||||
{
|
||||
s64 rem;
|
||||
s64 r = _div128(high, low, divisor, &rem);
|
||||
|
||||
if (remainder)
|
||||
{
|
||||
*remainder = rem;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
inline u64 udiv128(u64 high, u64 low, u64 divisor, u64* remainder = nullptr)
|
||||
{
|
||||
u64 rem;
|
||||
u64 r = _udiv128(high, low, divisor, &rem);
|
||||
|
||||
if (remainder)
|
||||
{
|
||||
*remainder = rem;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
#endif
|
||||
} // namespace utils
|
||||
+34
-31
@@ -1,10 +1,13 @@
|
||||
#include "bin_patch.h"
|
||||
#include "bin_patch.h"
|
||||
#include "File.h"
|
||||
#include "Config.h"
|
||||
#include "version.h"
|
||||
#include "Emu/System.h"
|
||||
|
||||
LOG_CHANNEL(patch_log);
|
||||
#include "util/types.hpp"
|
||||
#include "util/endian.hpp"
|
||||
|
||||
LOG_CHANNEL(patch_log, "PAT");
|
||||
|
||||
namespace config_key
|
||||
{
|
||||
@@ -73,7 +76,7 @@ std::string patch_engine::get_patch_config_path()
|
||||
|
||||
if (!fs::create_path(config_dir))
|
||||
{
|
||||
patch_log.error("Could not create path: %s", patch_path);
|
||||
patch_log.error("Could not create path: %s (%s)", patch_path, fs::g_tls_error);
|
||||
}
|
||||
|
||||
return patch_path;
|
||||
@@ -98,19 +101,24 @@ static void append_log_message(std::stringstream* log_messages, const std::strin
|
||||
*log_messages << message << std::endl;
|
||||
};
|
||||
|
||||
bool patch_engine::load(patch_map& patches_map, const std::string& path, bool importing, std::stringstream* log_messages)
|
||||
bool patch_engine::load(patch_map& patches_map, const std::string& path, std::string content, bool importing, std::stringstream* log_messages)
|
||||
{
|
||||
// Load patch file
|
||||
fs::file file{ path };
|
||||
|
||||
if (!file)
|
||||
if (content.empty())
|
||||
{
|
||||
// Do nothing
|
||||
return true;
|
||||
// Load patch file
|
||||
fs::file file{path};
|
||||
|
||||
if (!file)
|
||||
{
|
||||
// Do nothing
|
||||
return true;
|
||||
}
|
||||
|
||||
content = file.to_string();
|
||||
}
|
||||
|
||||
// Interpret yaml nodes
|
||||
auto [root, error] = yaml_load(file.to_string());
|
||||
auto [root, error] = yaml_load(content);
|
||||
|
||||
if (!error.empty() || !root)
|
||||
{
|
||||
@@ -519,7 +527,7 @@ bool patch_engine::read_patch_node(patch_info& info, YAML::Node node, const YAML
|
||||
if (!node)
|
||||
{
|
||||
append_log_message(log_messages, fmt::format("Skipping invalid patch node %s. (key: %s)", info.description, info.hash));
|
||||
patch_log.error("Skipping invalid patch node %s. (key: %s)" HERE, info.description, info.hash);
|
||||
patch_log.error("Skipping invalid patch node %s. (key: %s)", info.description, info.hash);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -543,11 +551,6 @@ bool patch_engine::read_patch_node(patch_info& info, YAML::Node node, const YAML
|
||||
return is_valid;
|
||||
}
|
||||
|
||||
void patch_engine::append(const std::string& patch)
|
||||
{
|
||||
load(m_map, patch);
|
||||
}
|
||||
|
||||
void patch_engine::append_global_patches()
|
||||
{
|
||||
// Legacy patch.yml
|
||||
@@ -574,20 +577,20 @@ void patch_engine::append_title_patches(const std::string& title_id)
|
||||
load(m_map, get_patches_path() + title_id + "_patch.yml");
|
||||
}
|
||||
|
||||
std::size_t patch_engine::apply(const std::string& name, u8* dst)
|
||||
usz patch_engine::apply(const std::string& name, u8* dst)
|
||||
{
|
||||
return apply_patch<false>(name, dst, 0, 0);
|
||||
}
|
||||
|
||||
std::size_t patch_engine::apply_with_ls_check(const std::string& name, u8* dst, u32 filesz, u32 ls_addr)
|
||||
usz patch_engine::apply_with_ls_check(const std::string& name, u8* dst, u32 filesz, u32 ls_addr)
|
||||
{
|
||||
return apply_patch<true>(name, dst, filesz, ls_addr);
|
||||
}
|
||||
|
||||
template <bool check_local_storage>
|
||||
static std::size_t apply_modification(const patch_engine::patch_info& patch, u8* dst, u32 filesz, u32 ls_addr)
|
||||
static usz apply_modification(const patch_engine::patch_info& patch, u8* dst, u32 filesz, u32 ls_addr)
|
||||
{
|
||||
size_t applied = 0;
|
||||
usz applied = 0;
|
||||
|
||||
for (const auto& p : patch.data_list)
|
||||
{
|
||||
@@ -600,7 +603,7 @@ static std::size_t apply_modification(const patch_engine::patch_info& patch, u8*
|
||||
// This patch is out of range for this segment
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
offset -= ls_addr;
|
||||
}
|
||||
|
||||
@@ -678,14 +681,14 @@ static std::size_t apply_modification(const patch_engine::patch_info& patch, u8*
|
||||
}
|
||||
|
||||
template <bool check_local_storage>
|
||||
std::size_t patch_engine::apply_patch(const std::string& name, u8* dst, u32 filesz, u32 ls_addr)
|
||||
usz patch_engine::apply_patch(const std::string& name, u8* dst, u32 filesz, u32 ls_addr)
|
||||
{
|
||||
if (m_map.find(name) == m_map.cend())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t applied_total = 0;
|
||||
usz applied_total = 0;
|
||||
const auto& container = m_map.at(name);
|
||||
const auto serial = Emu.GetTitleID();
|
||||
const auto app_version = Emu.GetAppVersion();
|
||||
@@ -796,7 +799,7 @@ std::size_t patch_engine::apply_patch(const std::string& name, u8* dst, u32 file
|
||||
m_applied_groups.insert(patch.patch_group);
|
||||
}
|
||||
|
||||
const size_t applied = apply_modification<check_local_storage>(patch, dst, filesz, ls_addr);
|
||||
const usz applied = apply_modification<check_local_storage>(patch, dst, filesz, ls_addr);
|
||||
applied_total += applied;
|
||||
|
||||
if (patch.is_legacy)
|
||||
@@ -820,7 +823,7 @@ void patch_engine::save_config(const patch_map& patches_map, bool enable_legacy_
|
||||
fs::file file(path, fs::rewrite);
|
||||
if (!file)
|
||||
{
|
||||
patch_log.fatal("Failed to open patch config file %s", path);
|
||||
patch_log.fatal("Failed to open patch config file %s (%s)", path, fs::g_tls_error);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -903,7 +906,7 @@ void patch_engine::save_config(const patch_map& patches_map, bool enable_legacy_
|
||||
file.write(out.c_str(), out.size());
|
||||
}
|
||||
|
||||
static void append_patches(patch_engine::patch_map& existing_patches, const patch_engine::patch_map& new_patches, size_t& count, size_t& total, std::stringstream* log_messages)
|
||||
static void append_patches(patch_engine::patch_map& existing_patches, const patch_engine::patch_map& new_patches, usz& count, usz& total, std::stringstream* log_messages)
|
||||
{
|
||||
for (const auto& [hash, new_container] : new_patches)
|
||||
{
|
||||
@@ -973,8 +976,8 @@ bool patch_engine::save_patches(const patch_map& patches, const std::string& pat
|
||||
fs::file file(path, fs::rewrite);
|
||||
if (!file)
|
||||
{
|
||||
patch_log.fatal("save_patches: Failed to open patch file %s", path);
|
||||
append_log_message(log_messages, fmt::format("Failed to open patch file %s", path));
|
||||
patch_log.fatal("save_patches: Failed to open patch file %s (%s)", path, fs::g_tls_error);
|
||||
append_log_message(log_messages, fmt::format("Failed to open patch file %s (%s)", path, fs::g_tls_error));
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1055,11 +1058,11 @@ bool patch_engine::save_patches(const patch_map& patches, const std::string& pat
|
||||
return true;
|
||||
}
|
||||
|
||||
bool patch_engine::import_patches(const patch_engine::patch_map& patches, const std::string& path, size_t& count, size_t& total, std::stringstream* log_messages)
|
||||
bool patch_engine::import_patches(const patch_engine::patch_map& patches, const std::string& path, usz& count, usz& total, std::stringstream* log_messages)
|
||||
{
|
||||
patch_engine::patch_map existing_patches;
|
||||
|
||||
if (load(existing_patches, path, true, log_messages))
|
||||
if (load(existing_patches, path, "", true, log_messages))
|
||||
{
|
||||
append_patches(existing_patches, patches, count, total, log_messages);
|
||||
return count == 0 || save_patches(existing_patches, path, log_messages);
|
||||
|
||||
+8
-11
@@ -1,10 +1,10 @@
|
||||
#pragma once
|
||||
#pragma once
|
||||
|
||||
#include "BEType.h"
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "util/types.hpp"
|
||||
#include "util/yaml.hpp"
|
||||
|
||||
namespace patch_key
|
||||
@@ -53,7 +53,7 @@ public:
|
||||
f64 double_value;
|
||||
} value { 0 };
|
||||
};
|
||||
|
||||
|
||||
using patch_app_versions = std::unordered_map<std::string /*app_version*/, bool /*enabled*/>;
|
||||
using patch_serials = std::unordered_map<std::string /*serial*/, patch_app_versions>;
|
||||
using patch_titles = std::unordered_map<std::string /*serial*/, patch_serials>;
|
||||
@@ -99,7 +99,7 @@ public:
|
||||
static std::string get_imported_patch_path();
|
||||
|
||||
// Load from file and append to specified patches map
|
||||
static bool load(patch_map& patches, const std::string& path, bool importing = false, std::stringstream* log_messages = nullptr);
|
||||
static bool load(patch_map& patches, const std::string& path, std::string content = "", bool importing = false, std::stringstream* log_messages = nullptr);
|
||||
|
||||
// Read and add a patch node to the patch info
|
||||
static bool read_patch_node(patch_info& info, YAML::Node node, const YAML::Node& root, std::stringstream* log_messages = nullptr);
|
||||
@@ -117,7 +117,7 @@ public:
|
||||
static bool save_patches(const patch_map& patches, const std::string& path, std::stringstream* log_messages = nullptr);
|
||||
|
||||
// Create or append patches to a file
|
||||
static bool import_patches(const patch_map& patches, const std::string& path, size_t& count, size_t& total, std::stringstream* log_messages = nullptr);
|
||||
static bool import_patches(const patch_map& patches, const std::string& path, usz& count, usz& total, std::stringstream* log_messages = nullptr);
|
||||
|
||||
// Remove a patch from a file
|
||||
static bool remove_patch(const patch_info& info);
|
||||
@@ -132,18 +132,15 @@ public:
|
||||
void append_title_patches(const std::string& title_id);
|
||||
|
||||
// Apply patch (returns the number of entries applied)
|
||||
std::size_t apply(const std::string& name, u8* dst);
|
||||
usz apply(const std::string& name, u8* dst);
|
||||
|
||||
// Apply patch with a check that the address exists in SPU local storage
|
||||
std::size_t apply_with_ls_check(const std::string& name, u8* dst, u32 filesz, u32 ls_addr);
|
||||
usz apply_with_ls_check(const std::string& name, u8* dst, u32 filesz, u32 ls_addr);
|
||||
|
||||
private:
|
||||
// Load from file and append to member patches map
|
||||
void append(const std::string& path);
|
||||
|
||||
// Internal: Apply patch (returns the number of entries applied)
|
||||
template <bool check_local_storage>
|
||||
std::size_t apply_patch(const std::string& name, u8* dst, u32 filesz, u32 ls_addr);
|
||||
usz apply_patch(const std::string& name, u8* dst, u32 filesz, u32 ls_addr);
|
||||
|
||||
// Database
|
||||
patch_map m_map;
|
||||
|
||||
+10
-10
@@ -21,8 +21,9 @@ Examples:
|
||||
Intersection (&) and symmetric difference (^) is also available.
|
||||
*/
|
||||
|
||||
#include "types.h"
|
||||
#include "util/types.hpp"
|
||||
#include "util/atomic.hpp"
|
||||
#include "Utilities/StrFmt.h"
|
||||
|
||||
template <typename T>
|
||||
class atomic_bs_t;
|
||||
@@ -48,8 +49,8 @@ private:
|
||||
}
|
||||
|
||||
public:
|
||||
static constexpr std::size_t bitmax = sizeof(T) * 8;
|
||||
static constexpr std::size_t bitsize = static_cast<under>(T::__bitset_enum_max);
|
||||
static constexpr usz bitmax = sizeof(T) * 8;
|
||||
static constexpr usz bitsize = static_cast<under>(T::__bitset_enum_max);
|
||||
|
||||
static_assert(std::is_enum<T>::value, "bs_t<> error: invalid type (must be enum)");
|
||||
static_assert(bitsize <= bitmax, "bs_t<> error: invalid __bitset_enum_max");
|
||||
@@ -205,7 +206,7 @@ constexpr bs_t<T> operator ^(T lhs, T rhs)
|
||||
|
||||
// Atomic bitset specialization with optimized operations
|
||||
template <typename T>
|
||||
class atomic_bs_t : public atomic_t<::bs_t<T>> // TODO: true specialization
|
||||
class atomic_bs_t : public atomic_t<::bs_t<T>>
|
||||
{
|
||||
// Corresponding bitset type
|
||||
using bs_t = ::bs_t<T>;
|
||||
@@ -379,11 +380,6 @@ public:
|
||||
return lhs.m_data != rhs.load().m_data;
|
||||
}
|
||||
|
||||
bool test(const bs_t& rhs)
|
||||
{
|
||||
return base::load().test(rhs);
|
||||
}
|
||||
|
||||
bool test_and_set(T rhs)
|
||||
{
|
||||
return atomic_storage<under>::bts(m_data.m_data, static_cast<uint>(static_cast<under>(rhs)));
|
||||
@@ -394,10 +390,14 @@ public:
|
||||
return atomic_storage<under>::btr(m_data.m_data, static_cast<uint>(static_cast<under>(rhs)));
|
||||
}
|
||||
|
||||
bool test_and_complement(T rhs)
|
||||
bool test_and_invert(T rhs)
|
||||
{
|
||||
return atomic_storage<under>::btc(m_data.m_data, static_cast<uint>(static_cast<under>(rhs)));
|
||||
}
|
||||
|
||||
bool bit_test_set(uint bit) = delete;
|
||||
bool bit_test_reset(uint bit) = delete;
|
||||
bool bit_test_invert(uint bit) = delete;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
|
||||
+22
-22
@@ -1,12 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#include "types.h"
|
||||
#include "util/types.hpp"
|
||||
#include <climits>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
|
||||
static const size_t size_dropped = std::numeric_limits<size_t>::max();
|
||||
static const usz size_dropped = -1;
|
||||
|
||||
/*
|
||||
C-style format parser. Appends formatted string to `out`, returns number of characters written.
|
||||
@@ -15,13 +15,13 @@ C-style format parser. Appends formatted string to `out`, returns number of char
|
||||
`src`: rvalue reference to argument provider.
|
||||
*/
|
||||
template<typename Dst, typename Char, typename Src>
|
||||
std::size_t cfmt_append(Dst& out, const Char* fmt, Src&& src)
|
||||
usz cfmt_append(Dst& out, const Char* fmt, Src&& src)
|
||||
{
|
||||
const std::size_t start_pos = out.size();
|
||||
const usz start_pos = out.size();
|
||||
|
||||
struct cfmt_context
|
||||
{
|
||||
std::size_t size; // Size of current format sequence
|
||||
usz size; // Size of current format sequence
|
||||
|
||||
u8 args; // Number of extra args used
|
||||
u8 type; // Integral type bytesize
|
||||
@@ -80,7 +80,7 @@ std::size_t cfmt_append(Dst& out, const Char* fmt, Src&& src)
|
||||
|
||||
const auto write_decimal = [&](u64 value, s64 min_size)
|
||||
{
|
||||
const std::size_t start = out.size();
|
||||
const usz start = out.size();
|
||||
|
||||
do
|
||||
{
|
||||
@@ -90,7 +90,7 @@ std::size_t cfmt_append(Dst& out, const Char* fmt, Src&& src)
|
||||
while (0 < --min_size || value);
|
||||
|
||||
// Revert written characters
|
||||
for (std::size_t i = start, j = out.size() - 1; i < j; i++, j--)
|
||||
for (usz i = start, j = out.size() - 1; i < j; i++, j--)
|
||||
{
|
||||
std::swap(out[i], out[j]);
|
||||
}
|
||||
@@ -285,7 +285,7 @@ std::size_t cfmt_append(Dst& out, const Char* fmt, Src&& src)
|
||||
break;
|
||||
}
|
||||
|
||||
const std::size_t start = out.size();
|
||||
const usz start = out.size();
|
||||
out.push_back(src.template get<Char>(ctx.args));
|
||||
|
||||
if (1 < ctx.width)
|
||||
@@ -307,8 +307,8 @@ std::size_t cfmt_append(Dst& out, const Char* fmt, Src&& src)
|
||||
break;
|
||||
}
|
||||
|
||||
const std::size_t start = out.size();
|
||||
const std::size_t size1 = src.fmt_string(out, ctx.args);
|
||||
const usz start = out.size();
|
||||
const usz size1 = src.fmt_string(out, ctx.args);
|
||||
|
||||
if (ctx.dot && size1 > ctx.prec)
|
||||
{
|
||||
@@ -316,7 +316,7 @@ std::size_t cfmt_append(Dst& out, const Char* fmt, Src&& src)
|
||||
out.resize(start + ctx.prec);
|
||||
}
|
||||
|
||||
const std::size_t size2 = out.size() - start;
|
||||
const usz size2 = out.size() - start;
|
||||
|
||||
if (size2 < ctx.width)
|
||||
{
|
||||
@@ -352,7 +352,7 @@ std::size_t cfmt_append(Dst& out, const Char* fmt, Src&& src)
|
||||
const u64 val = src.template get<u64>(ctx.args);
|
||||
const bool negative = ctx.type && static_cast<s64>(val) < 0;
|
||||
|
||||
const std::size_t start = out.size();
|
||||
const usz start = out.size();
|
||||
|
||||
if (!ctx.dot || ctx.prec)
|
||||
{
|
||||
@@ -372,7 +372,7 @@ std::size_t cfmt_append(Dst& out, const Char* fmt, Src&& src)
|
||||
write_decimal(negative ? 0 - val : val, ctx.prec);
|
||||
}
|
||||
|
||||
const std::size_t size2 = out.size() - start;
|
||||
const usz size2 = out.size() - start;
|
||||
|
||||
if (size2 < ctx.width)
|
||||
{
|
||||
@@ -419,7 +419,7 @@ std::size_t cfmt_append(Dst& out, const Char* fmt, Src&& src)
|
||||
// Trunc sign-extended signed types
|
||||
const u64 val = src.template get<u64>(ctx.args) & mask;
|
||||
|
||||
const std::size_t start = out.size();
|
||||
const usz start = out.size();
|
||||
|
||||
if (ctx.alter)
|
||||
{
|
||||
@@ -435,7 +435,7 @@ std::size_t cfmt_append(Dst& out, const Char* fmt, Src&& src)
|
||||
write_octal(val, ctx.prec);
|
||||
}
|
||||
|
||||
const std::size_t size2 = out.size() - start;
|
||||
const usz size2 = out.size() - start;
|
||||
|
||||
if (size2 < ctx.width)
|
||||
{
|
||||
@@ -476,7 +476,7 @@ std::size_t cfmt_append(Dst& out, const Char* fmt, Src&& src)
|
||||
// Trunc sign-extended signed types
|
||||
const u64 val = src.template get<u64>(ctx.args) & mask;
|
||||
|
||||
const std::size_t start = out.size();
|
||||
const usz start = out.size();
|
||||
|
||||
if (ctx.alter)
|
||||
{
|
||||
@@ -493,7 +493,7 @@ std::size_t cfmt_append(Dst& out, const Char* fmt, Src&& src)
|
||||
write_hex(val, ch == 'X', ctx.prec);
|
||||
}
|
||||
|
||||
const std::size_t size2 = out.size() - start;
|
||||
const usz size2 = out.size() - start;
|
||||
|
||||
if (size2 < ctx.width)
|
||||
{
|
||||
@@ -540,14 +540,14 @@ std::size_t cfmt_append(Dst& out, const Char* fmt, Src&& src)
|
||||
// Trunc sign-extended signed types
|
||||
const u64 val = src.template get<u64>(ctx.args) & mask;
|
||||
|
||||
const std::size_t start = out.size();
|
||||
const usz start = out.size();
|
||||
|
||||
if (!ctx.dot || ctx.prec)
|
||||
{
|
||||
write_decimal(val, ctx.prec);
|
||||
}
|
||||
|
||||
const std::size_t size2 = out.size() - start;
|
||||
const usz size2 = out.size() - start;
|
||||
|
||||
if (size2 < ctx.width)
|
||||
{
|
||||
@@ -570,11 +570,11 @@ std::size_t cfmt_append(Dst& out, const Char* fmt, Src&& src)
|
||||
|
||||
const u64 val = src.template get<u64>(ctx.args);
|
||||
|
||||
const std::size_t start = out.size();
|
||||
const usz start = out.size();
|
||||
|
||||
write_hex(val, false, sizeof(void*) * 2);
|
||||
|
||||
const std::size_t size2 = out.size() - start;
|
||||
const usz size2 = out.size() - start;
|
||||
|
||||
if (size2 < ctx.width)
|
||||
{
|
||||
@@ -610,7 +610,7 @@ std::size_t cfmt_append(Dst& out, const Char* fmt, Src&& src)
|
||||
const u64 arg1 = ctx.args >= 1 ? src.template get<u64>(1) : 0;
|
||||
const u64 arg2 = ctx.args >= 2 ? src.template get<u64>(2) : 0;
|
||||
|
||||
if (const std::size_t _size = std::snprintf(0, 0, _fmt.c_str(), arg0, arg1, arg2))
|
||||
if (const usz _size = std::snprintf(0, 0, _fmt.c_str(), arg0, arg1, arg2))
|
||||
{
|
||||
out.resize(out.size() + _size);
|
||||
std::snprintf(&out.front() + out.size() - _size, _size + 1, _fmt.c_str(), arg0, arg1, arg2);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "stdafx.h"
|
||||
#include "stdafx.h"
|
||||
#include "cheat_info.h"
|
||||
#include "Config.h"
|
||||
#include "StrUtil.h"
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#pragma once
|
||||
#pragma once
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "util/types.hpp"
|
||||
|
||||
#include <string>
|
||||
|
||||
enum class cheat_type : u8
|
||||
{
|
||||
|
||||
+5
-5
@@ -1,4 +1,4 @@
|
||||
#include "cond.h"
|
||||
#include "cond.h"
|
||||
#include "sync.h"
|
||||
#include "lockless.h"
|
||||
|
||||
@@ -9,10 +9,10 @@
|
||||
void cond_variable::imp_wait(u32 _old, u64 _timeout) noexcept
|
||||
{
|
||||
// Not supposed to fail
|
||||
verify(HERE), _old;
|
||||
ensure(_old);
|
||||
|
||||
// Wait with timeout
|
||||
m_value.wait<c_signal_mask>(_old, atomic_wait_timeout{_timeout > max_timeout ? UINT64_MAX : _timeout * 1000});
|
||||
m_value.wait(_old, c_signal_mask, atomic_wait_timeout{_timeout > max_timeout ? UINT64_MAX : _timeout * 1000});
|
||||
|
||||
// Cleanup
|
||||
m_value.atomic_op([](u32& value)
|
||||
@@ -50,10 +50,10 @@ void cond_variable::imp_wake(u32 _count) noexcept
|
||||
if (_count > 1 || ((_old + (c_signal_mask & (0 - c_signal_mask))) & c_signal_mask) == c_signal_mask)
|
||||
{
|
||||
// Resort to notify_all if signal count reached max
|
||||
m_value.notify_all();
|
||||
m_value.notify_all(c_signal_mask);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_value.notify_one();
|
||||
m_value.notify_one(c_signal_mask);
|
||||
}
|
||||
}
|
||||
|
||||
+1
-2
@@ -1,8 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "types.h"
|
||||
#include "util/types.hpp"
|
||||
#include "util/atomic.hpp"
|
||||
#include <shared_mutex>
|
||||
|
||||
// Lightweight condition variable
|
||||
class cond_variable
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#pragma once
|
||||
#pragma once
|
||||
|
||||
#include <cmath>
|
||||
|
||||
|
||||
+7
-7
@@ -1,23 +1,23 @@
|
||||
#pragma once
|
||||
|
||||
#include "Utilities/types.h"
|
||||
#include "util/types.hpp"
|
||||
|
||||
namespace rpcs3
|
||||
{
|
||||
template<typename T>
|
||||
static size_t hash_base(T value)
|
||||
static usz hash_base(T value)
|
||||
{
|
||||
return static_cast<size_t>(value);
|
||||
return static_cast<usz>(value);
|
||||
}
|
||||
|
||||
template<typename T, typename U>
|
||||
static size_t hash_struct_base(const T& value)
|
||||
static usz hash_struct_base(const T& value)
|
||||
{
|
||||
// FNV 64-bit
|
||||
size_t result = 14695981039346656037ull;
|
||||
usz result = 14695981039346656037ull;
|
||||
const U *bits = reinterpret_cast<const U*>(&value);
|
||||
|
||||
for (size_t n = 0; n < (sizeof(T) / sizeof(U)); ++n)
|
||||
for (usz n = 0; n < (sizeof(T) / sizeof(U)); ++n)
|
||||
{
|
||||
result ^= bits[n];
|
||||
result *= 1099511628211ull;
|
||||
@@ -27,7 +27,7 @@ namespace rpcs3
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static size_t hash_struct(const T& value)
|
||||
static usz hash_struct(const T& value)
|
||||
{
|
||||
static constexpr auto block_sz = sizeof(T);
|
||||
|
||||
|
||||
+20
-9
@@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
#pragma once
|
||||
|
||||
#include "types.h"
|
||||
#include "util/types.hpp"
|
||||
#include "util/atomic.hpp"
|
||||
|
||||
//! Simple sizeless array base for concurrent access. Cannot shrink, only growths automatically.
|
||||
@@ -8,7 +8,7 @@
|
||||
//!
|
||||
//! T is the type of elements. Currently, default constructor of T shall be constexpr.
|
||||
//! N is initial element count, available without any memory allocation and only stored contiguously.
|
||||
template <typename T, std::size_t N>
|
||||
template <typename T, usz N>
|
||||
class lf_array
|
||||
{
|
||||
// Data (default-initialized)
|
||||
@@ -28,7 +28,7 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
T& operator [](std::size_t index)
|
||||
T& operator [](usz index)
|
||||
{
|
||||
if (index < N) [[likely]]
|
||||
{
|
||||
@@ -51,7 +51,7 @@ public:
|
||||
|
||||
//! Simple lock-free FIFO queue base. Based on lf_array<T, N> itself. Currently uses 32-bit counters.
|
||||
//! There is no "push_end" or "pop_begin" provided, the queue element must signal its state on its own.
|
||||
template<typename T, std::size_t N>
|
||||
template<typename T, usz N>
|
||||
class lf_fifo : public lf_array<T, N>
|
||||
{
|
||||
// LSB 32-bit: push, MSB 32-bit: pop
|
||||
@@ -307,14 +307,25 @@ public:
|
||||
delete m_head.load();
|
||||
}
|
||||
|
||||
void wait() noexcept
|
||||
template <atomic_wait::op Flags = atomic_wait::op::eq>
|
||||
void wait(std::nullptr_t null = nullptr) noexcept
|
||||
{
|
||||
if (m_head == nullptr)
|
||||
{
|
||||
m_head.wait(nullptr);
|
||||
m_head.template wait<Flags>(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
const volatile void* observe() const noexcept
|
||||
{
|
||||
return m_head.load();
|
||||
}
|
||||
|
||||
explicit operator bool() const noexcept
|
||||
{
|
||||
return m_head != nullptr;
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
void push(Args&&... args)
|
||||
{
|
||||
@@ -343,9 +354,9 @@ public:
|
||||
|
||||
// Apply func(data) to each element, return the total length
|
||||
template <typename F>
|
||||
std::size_t apply(F func)
|
||||
usz apply(F func)
|
||||
{
|
||||
std::size_t count = 0;
|
||||
usz count = 0;
|
||||
|
||||
for (auto slice = pop_all(); slice; slice.pop_front())
|
||||
{
|
||||
|
||||
+11
-102
@@ -1,8 +1,10 @@
|
||||
#include "mutex.h"
|
||||
|
||||
#include "util/asm.hpp"
|
||||
|
||||
void shared_mutex::imp_lock_shared(u32 val)
|
||||
{
|
||||
verify("shared_mutex underflow" HERE), val < c_err;
|
||||
ensure(val < c_err); // "shared_mutex underflow"
|
||||
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
@@ -23,14 +25,14 @@ void shared_mutex::imp_lock_shared(u32 val)
|
||||
return;
|
||||
}
|
||||
|
||||
verify("shared_mutex overflow" HERE), (old % c_sig) + c_one < c_sig;
|
||||
ensure((old % c_sig) + c_one < c_sig); // "shared_mutex overflow"
|
||||
imp_wait();
|
||||
lock_downgrade();
|
||||
}
|
||||
|
||||
void shared_mutex::imp_unlock_shared(u32 old)
|
||||
{
|
||||
verify("shared_mutex underflow" HERE), old - 1 < c_err;
|
||||
ensure(old - 1 < c_err); // "shared_mutex underflow"
|
||||
|
||||
// Check reader count, notify the writer if necessary
|
||||
if ((old - 1) % c_one == 0)
|
||||
@@ -39,84 +41,6 @@ void shared_mutex::imp_unlock_shared(u32 old)
|
||||
}
|
||||
}
|
||||
|
||||
void shared_mutex::imp_lock_low(u32 val)
|
||||
{
|
||||
verify("shared_mutex underflow" HERE), val < c_err;
|
||||
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
busy_wait();
|
||||
|
||||
if (try_lock_low())
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Acquire writer lock and downgrade
|
||||
const u32 old = m_value.fetch_add(c_one);
|
||||
|
||||
if (old == 0)
|
||||
{
|
||||
lock_downgrade();
|
||||
return;
|
||||
}
|
||||
|
||||
verify("shared_mutex overflow" HERE), (old % c_sig) + c_one < c_sig;
|
||||
imp_wait();
|
||||
lock_downgrade();
|
||||
}
|
||||
|
||||
void shared_mutex::imp_unlock_low(u32 old)
|
||||
{
|
||||
verify("shared_mutex underflow" HERE), old - 1 < c_err;
|
||||
|
||||
// Check reader count, notify the writer if necessary
|
||||
if ((old - 1) % c_vip == 0)
|
||||
{
|
||||
imp_signal();
|
||||
}
|
||||
}
|
||||
|
||||
void shared_mutex::imp_lock_vip(u32 val)
|
||||
{
|
||||
verify("shared_mutex underflow" HERE), val < c_err;
|
||||
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
busy_wait();
|
||||
|
||||
if (try_lock_vip())
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Acquire writer lock and downgrade
|
||||
const u32 old = m_value.fetch_add(c_one);
|
||||
|
||||
if (old == 0)
|
||||
{
|
||||
lock_downgrade_to_vip();
|
||||
return;
|
||||
}
|
||||
|
||||
verify("shared_mutex overflow" HERE), (old % c_sig) + c_one < c_sig;
|
||||
imp_wait();
|
||||
lock_downgrade_to_vip();
|
||||
}
|
||||
|
||||
void shared_mutex::imp_unlock_vip(u32 old)
|
||||
{
|
||||
verify("shared_mutex underflow" HERE), old - 1 < c_err;
|
||||
|
||||
// Check reader count, notify the writer if necessary
|
||||
if ((old - 1) % c_one / c_vip == 0)
|
||||
{
|
||||
imp_signal();
|
||||
}
|
||||
}
|
||||
|
||||
void shared_mutex::imp_wait()
|
||||
{
|
||||
while (true)
|
||||
@@ -137,19 +61,19 @@ void shared_mutex::imp_wait()
|
||||
break;
|
||||
}
|
||||
|
||||
m_value.wait(old);
|
||||
m_value.wait(old, c_sig);
|
||||
}
|
||||
}
|
||||
|
||||
void shared_mutex::imp_signal()
|
||||
{
|
||||
m_value += c_sig;
|
||||
m_value.notify_one();
|
||||
m_value.notify_one(c_sig);
|
||||
}
|
||||
|
||||
void shared_mutex::imp_lock(u32 val)
|
||||
{
|
||||
verify("shared_mutex underflow" HERE), val < c_err;
|
||||
ensure(val < c_err); // "shared_mutex underflow"
|
||||
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
@@ -168,13 +92,13 @@ void shared_mutex::imp_lock(u32 val)
|
||||
return;
|
||||
}
|
||||
|
||||
verify("shared_mutex overflow" HERE), (old % c_sig) + c_one < c_sig;
|
||||
ensure((old % c_sig) + c_one < c_sig); // "shared_mutex overflow"
|
||||
imp_wait();
|
||||
}
|
||||
|
||||
void shared_mutex::imp_unlock(u32 old)
|
||||
{
|
||||
verify("shared_mutex underflow" HERE), old - c_one < c_err;
|
||||
ensure(old - c_one < c_err); // "shared_mutex underflow"
|
||||
|
||||
// 1) Notify the next writer if necessary
|
||||
// 2) Notify all readers otherwise if necessary (currently indistinguishable from writers)
|
||||
@@ -199,7 +123,7 @@ void shared_mutex::imp_lock_upgrade()
|
||||
// Convert to writer lock
|
||||
const u32 old = m_value.fetch_add(c_one - 1);
|
||||
|
||||
verify("shared_mutex overflow" HERE), (old % c_sig) + c_one - 1 < c_sig;
|
||||
ensure((old % c_sig) + c_one - 1 < c_sig); // "shared_mutex overflow"
|
||||
|
||||
if (old % c_one == 1)
|
||||
{
|
||||
@@ -241,18 +165,3 @@ void shared_mutex::imp_lock_unlock()
|
||||
imp_wait();
|
||||
unlock();
|
||||
}
|
||||
|
||||
bool shared_mutex::downgrade_unique_vip_lock_to_low_or_unlock()
|
||||
{
|
||||
return m_value.atomic_op([](u32& value)
|
||||
{
|
||||
if (value % c_one / c_vip == 1)
|
||||
{
|
||||
value -= c_vip - 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
value -= c_vip;
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
+2
-118
@@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <mutex>
|
||||
#include "types.h"
|
||||
#include "util/types.hpp"
|
||||
#include "util/atomic.hpp"
|
||||
|
||||
// Shared mutex with small size (u32).
|
||||
@@ -12,17 +12,12 @@ class shared_mutex final
|
||||
c_one = 1u << 14, // Fixed-point 1.0 value (one writer, max_readers = c_one - 1)
|
||||
c_sig = 1u << 30,
|
||||
c_err = 1u << 31,
|
||||
c_vip = 1u << 7,
|
||||
};
|
||||
|
||||
atomic_t<u32> m_value{};
|
||||
|
||||
void imp_lock_shared(u32 val);
|
||||
void imp_unlock_shared(u32 old);
|
||||
void imp_lock_low(u32 val);
|
||||
void imp_unlock_low(u32 old);
|
||||
void imp_lock_vip(u32 val);
|
||||
void imp_unlock_vip(u32 old);
|
||||
void imp_wait();
|
||||
void imp_signal();
|
||||
void imp_lock(u32 val);
|
||||
@@ -88,64 +83,6 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
bool try_lock_low()
|
||||
{
|
||||
const u32 value = m_value.load();
|
||||
|
||||
// Conditional increment
|
||||
return value < c_vip - 1 && m_value.compare_and_swap_test(value, value + 1);
|
||||
}
|
||||
|
||||
void lock_low()
|
||||
{
|
||||
const u32 value = m_value.load();
|
||||
|
||||
if (value >= c_vip - 1 || !m_value.compare_and_swap_test(value, value + 1)) [[unlikely]]
|
||||
{
|
||||
imp_lock_low(value);
|
||||
}
|
||||
}
|
||||
|
||||
void unlock_low()
|
||||
{
|
||||
// Unconditional decrement (can result in broken state)
|
||||
const u32 value = m_value.fetch_sub(1);
|
||||
|
||||
if (value >= c_one) [[unlikely]]
|
||||
{
|
||||
imp_unlock_low(value);
|
||||
}
|
||||
}
|
||||
|
||||
bool try_lock_vip()
|
||||
{
|
||||
const u32 value = m_value.load();
|
||||
|
||||
// Conditional increment
|
||||
return (value < c_one - 1 || value & (c_one - c_vip)) && (value % c_vip) == 0 && m_value.compare_and_swap_test(value, value + c_vip);
|
||||
}
|
||||
|
||||
void lock_vip()
|
||||
{
|
||||
const u32 value = m_value.load();
|
||||
|
||||
if ((value >= c_one - 1 && !(value & (c_one - c_vip))) || (value % c_vip) || !m_value.compare_and_swap_test(value, value + c_vip)) [[unlikely]]
|
||||
{
|
||||
imp_lock_vip(value);
|
||||
}
|
||||
}
|
||||
|
||||
void unlock_vip()
|
||||
{
|
||||
// Unconditional decrement (can result in broken state)
|
||||
const u32 value = m_value.fetch_sub(c_vip);
|
||||
|
||||
if (value >= c_one) [[unlikely]]
|
||||
{
|
||||
imp_unlock_vip(value);
|
||||
}
|
||||
}
|
||||
|
||||
bool try_lock()
|
||||
{
|
||||
return m_value.compare_and_swap_test(0, c_one);
|
||||
@@ -214,12 +151,6 @@ public:
|
||||
m_value -= c_one - 1;
|
||||
}
|
||||
|
||||
void lock_downgrade_to_vip()
|
||||
{
|
||||
// Convert to vip lock (can result in broken state)
|
||||
m_value -= c_one - c_vip;
|
||||
}
|
||||
|
||||
// Optimized wait for lockability without locking, relaxed
|
||||
void lock_unlock()
|
||||
{
|
||||
@@ -240,12 +171,9 @@ public:
|
||||
{
|
||||
return m_value.load() < c_one - 1;
|
||||
}
|
||||
|
||||
// Special purpose logic
|
||||
bool downgrade_unique_vip_lock_to_low_or_unlock();
|
||||
};
|
||||
|
||||
// Simplified shared (reader) lock implementation. Mutually incompatible with low_lock and vip_lock.
|
||||
// Simplified shared (reader) lock implementation.
|
||||
class reader_lock final
|
||||
{
|
||||
shared_mutex& m_mutex;
|
||||
@@ -283,47 +211,3 @@ public:
|
||||
m_upgraded ? m_mutex.unlock() : m_mutex.unlock_shared();
|
||||
}
|
||||
};
|
||||
|
||||
// Special shared (reader) lock, mutually exclusive with vip locks. Mutually incompatible with normal shared (reader) lock.
|
||||
class low_lock final
|
||||
{
|
||||
shared_mutex& m_mutex;
|
||||
|
||||
public:
|
||||
low_lock(const low_lock&) = delete;
|
||||
|
||||
low_lock& operator=(const low_lock&) = delete;
|
||||
|
||||
explicit low_lock(shared_mutex& mutex)
|
||||
: m_mutex(mutex)
|
||||
{
|
||||
m_mutex.lock_low();
|
||||
}
|
||||
|
||||
~low_lock()
|
||||
{
|
||||
m_mutex.unlock_low();
|
||||
}
|
||||
};
|
||||
|
||||
// Special shared (reader) lock, mutually exclusive with low locks. Mutually incompatible with normal shared (reader) lock.
|
||||
class vip_lock final
|
||||
{
|
||||
shared_mutex& m_mutex;
|
||||
|
||||
public:
|
||||
vip_lock(const vip_lock&) = delete;
|
||||
|
||||
vip_lock& operator=(const vip_lock&) = delete;
|
||||
|
||||
explicit vip_lock(shared_mutex& mutex)
|
||||
: m_mutex(mutex)
|
||||
{
|
||||
m_mutex.lock_vip();
|
||||
}
|
||||
|
||||
~vip_lock()
|
||||
{
|
||||
m_mutex.unlock_vip();
|
||||
}
|
||||
};
|
||||
|
||||
+1
-4
@@ -1,7 +1,5 @@
|
||||
#include "stdafx.h"
|
||||
#include "restore_new.h"
|
||||
#include "Utilities/rXml.h"
|
||||
#include "define_new_memleakdetect.h"
|
||||
|
||||
rXmlNode::rXmlNode() : handle()
|
||||
{
|
||||
@@ -54,7 +52,7 @@ std::string rXmlNode::GetAttribute(const std::string &name)
|
||||
|
||||
std::string rXmlNode::GetNodeContent()
|
||||
{
|
||||
return handle.text().get();
|
||||
return handle.text().get();
|
||||
}
|
||||
|
||||
rXmlDocument::rXmlDocument() : handle()
|
||||
@@ -70,4 +68,3 @@ std::shared_ptr<rXmlNode> rXmlDocument::GetRoot()
|
||||
{
|
||||
return std::make_shared<rXmlNode>(handle.root());
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
#pragma once
|
||||
#pragma once
|
||||
|
||||
#include <pugixml.hpp>
|
||||
#include <memory>
|
||||
|
||||
+3
-1
@@ -1,5 +1,7 @@
|
||||
#include "sema.h"
|
||||
|
||||
#include "util/asm.hpp"
|
||||
|
||||
void semaphore_base::imp_wait()
|
||||
{
|
||||
for (int i = 0; i < 10; i++)
|
||||
@@ -52,7 +54,7 @@ void semaphore_base::imp_wait()
|
||||
|
||||
void semaphore_base::imp_post(s32 _old)
|
||||
{
|
||||
verify("semaphore_base: overflow" HERE), _old < 0;
|
||||
ensure(_old < 0); // "semaphore_base: overflow"
|
||||
|
||||
m_value.notify_one();
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <mutex>
|
||||
#include "types.h"
|
||||
#include "util/types.hpp"
|
||||
#include "util/atomic.hpp"
|
||||
|
||||
// Lightweight semaphore helper class
|
||||
|
||||
+13
-3
@@ -2,11 +2,14 @@
|
||||
|
||||
/* For internal use. Don't include. */
|
||||
|
||||
#include "types.h"
|
||||
#include "util/types.hpp"
|
||||
#include "util/atomic.hpp"
|
||||
#include "dynamic_library.h"
|
||||
#include "util/dyn_lib.hpp"
|
||||
|
||||
#ifdef _WIN32
|
||||
#ifndef NOMINMAX
|
||||
#define NOMINMAX
|
||||
#endif
|
||||
#include <Windows.h>
|
||||
#include <time.h>
|
||||
#elif __linux__
|
||||
@@ -15,6 +18,7 @@
|
||||
#include <linux/futex.h>
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
#include <algorithm>
|
||||
#include <ctime>
|
||||
@@ -28,6 +32,12 @@ DYNAMIC_IMPORT("ntdll.dll", NtWaitForKeyedEvent, NTSTATUS(HANDLE, PVOID Key, BOO
|
||||
DYNAMIC_IMPORT("ntdll.dll", NtReleaseKeyedEvent, NTSTATUS(HANDLE, PVOID Key, BOOLEAN Alertable, PLARGE_INTEGER Timeout));
|
||||
DYNAMIC_IMPORT("ntdll.dll", NtWaitForSingleObject, NTSTATUS(HANDLE Handle, BOOLEAN Alertable, PLARGE_INTEGER Timeout));
|
||||
DYNAMIC_IMPORT("ntdll.dll", NtDelayExecution, NTSTATUS(BOOLEAN Alertable, PLARGE_INTEGER DelayInterval));
|
||||
DYNAMIC_IMPORT("ntdll.dll", NtWaitForAlertByThreadId, NTSTATUS(PVOID Address, PLARGE_INTEGER Timeout));
|
||||
DYNAMIC_IMPORT("ntdll.dll", NtAlertThreadByThreadId, NTSTATUS(DWORD_PTR ThreadId));
|
||||
|
||||
constexpr NTSTATUS NTSTATUS_SUCCESS = 0;
|
||||
constexpr NTSTATUS NTSTATUS_ALERTED = 0x101;
|
||||
constexpr NTSTATUS NTSTATUS_TIMEOUT = 0x102;
|
||||
#endif
|
||||
|
||||
#ifndef __linux__
|
||||
@@ -61,7 +71,7 @@ inline int futex(volatile void* uaddr, int futex_op, uint val, const timespec* t
|
||||
};
|
||||
|
||||
std::mutex mutex;
|
||||
std::unordered_multimap<volatile void*, waiter*, pointer_hash<volatile void, alignof(int)>> map;
|
||||
std::unordered_multimap<volatile void*, waiter*> map;
|
||||
|
||||
int operator()(volatile void* uaddr, int futex_op, uint val, const timespec* timeout, uint mask)
|
||||
{
|
||||
|
||||
-1046
File diff suppressed because it is too large
Load Diff
-1060
File diff suppressed because it is too large
Load Diff
@@ -67,7 +67,7 @@ namespace utils
|
||||
int vnum2 = 0;
|
||||
|
||||
// Loop until both strings are processed
|
||||
for (size_t i = 0, j = 0; (i < v1.length() || j < v2.length());)
|
||||
for (usz i = 0, j = 0; (i < v1.length() || j < v2.length());)
|
||||
{
|
||||
// Storing numeric part of version 1 in vnum1
|
||||
while (i < v1.length() && v1[i] != '.')
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "types.h"
|
||||
#include "util/types.hpp"
|
||||
#include <string>
|
||||
|
||||
namespace utils
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros">
|
||||
<CmakeGenerator>"Visual Studio $(VisualStudioVersion.Substring(0,2))"</CmakeGenerator>
|
||||
<CmakeCLI>cmake -G $(CmakeGenerator) -A x64 -DCMAKE_CONFIGURATION_TYPES="Debug;Release" -DCMAKE_CXX_STANDARD=20 -DLLVM_USE_CRT_DEBUG=MTd -DLLVM_USE_CRT_RELEASE=MT ../glslang</CmakeCLI>
|
||||
<CmakeCLI>cmake -G $(CmakeGenerator) -A x64 -DCMAKE_CONFIGURATION_TYPES="Debug;Release" -DLLVM_USE_CRT_DEBUG=MTd -DLLVM_USE_CRT_RELEASE=MT ../glslang</CmakeCLI>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<NMakeBuildCommandLine>$(CmakeCLI)
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros">
|
||||
<CmakeGenerator>"Visual Studio $(VisualStudioVersion.Substring(0,2))"</CmakeGenerator>
|
||||
<CmakeCLI>cmake -G $(CmakeGenerator) -A x64 -DCMAKE_CONFIGURATION_TYPES="Debug;Release" -DCMAKE_CXX_STANDARD=20 -DLLVM_USE_CRT_DEBUG=MTd -DLLVM_USE_CRT_RELEASE=MT -DSPIRV-Headers_SOURCE_DIR=$([System.IO.Path]::GetFullPath('$(MSBuildThisFileDirectory)../spirv-headers')) ../spirv-tools</CmakeCLI>
|
||||
<CmakeCLI>cmake -G $(CmakeGenerator) -A x64 -DCMAKE_CONFIGURATION_TYPES="Debug;Release" -DLLVM_USE_CRT_DEBUG=MTd -DLLVM_USE_CRT_RELEASE=MT -DSPIRV-Headers_SOURCE_DIR=$([System.IO.Path]::GetFullPath('$(MSBuildThisFileDirectory)../spirv-headers')) ../spirv-tools</CmakeCLI>
|
||||
<PropsAbsPath>$([System.IO.Path]::GetFullPath('$(MSBuildThisFileDirectory)..\..\common_default.props'))</PropsAbsPath>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
|
||||
@@ -5,10 +5,6 @@
|
||||
<Configuration>Debug - LLVM</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug - MemLeak|x64">
|
||||
<Configuration>Debug - MemLeak</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
@@ -108,10 +104,6 @@
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="..\rpcs3_debug.props" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug - MemLeak|x64'" Label="PropertySheets">
|
||||
<Import Project="..\rpcs3_debug.props" />
|
||||
<Import Project="..\rpcs3_memleak.props" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug - LLVM|x64'" Label="PropertySheets">
|
||||
<Import Project="..\rpcs3_debug.props" />
|
||||
<Import Project="..\rpcs3_llvm.props" />
|
||||
|
||||
+24
-13
@@ -17,10 +17,12 @@ jobs:
|
||||
COMPILER: clang
|
||||
GCC:
|
||||
COMPILER: gcc
|
||||
DEPLOY_APPIMAGE: true
|
||||
variables:
|
||||
CCACHE_DIR: $(Pipeline.Workspace)/ccache
|
||||
IS_AZURE: true
|
||||
UPLOAD_COMMIT_HASH: d812f1254a1157c80fd402f94446310560f54e5f
|
||||
UPLOAD_REPO_FULL_NAME: "RPCS3/rpcs3-binaries-linux"
|
||||
DEPLOY_APPIMAGE: true
|
||||
pool:
|
||||
vmImage: 'ubuntu-latest'
|
||||
steps:
|
||||
@@ -31,30 +33,40 @@ jobs:
|
||||
displayName: ccache
|
||||
|
||||
- bash: |
|
||||
docker pull --quiet rpcs3/rpcs3-travis-xenial:1.5
|
||||
docker pull --quiet rpcs3/rpcs3-travis-xenial:1.7
|
||||
docker run \
|
||||
-v $(pwd):/rpcs3 \
|
||||
--env-file .ci/travis.env \
|
||||
--env-file .ci/docker.env \
|
||||
-v $CCACHE_DIR:/root/.ccache \
|
||||
-v $BUILD_ARTIFACTSTAGINGDIRECTORY:/root/artifacts \
|
||||
rpcs3/rpcs3-travis-xenial:1.5 \
|
||||
rpcs3/rpcs3-travis-xenial:1.7 \
|
||||
/rpcs3/.ci/build-linux.sh
|
||||
displayName: Docker setup and build
|
||||
|
||||
- publish: $(Build.ArtifactStagingDirectory)
|
||||
condition: and(succeeded(), eq(variables['COMPILER'], 'gcc'))
|
||||
artifact: RPCS3 for Linux
|
||||
condition: succeeded()
|
||||
artifact: RPCS3 for Linux ($(COMPILER))
|
||||
|
||||
- bash: .ci/github-upload.sh
|
||||
condition: and(ne(variables['Build.Reason'], 'PullRequest'), eq(variables['Build.Repository.Name'], 'RPCS3/rpcs3'), eq(variables['Build.SourceBranch'], 'refs/heads/master'), eq(variables['COMPILER'], 'gcc'))
|
||||
displayName: Push build to GitHub
|
||||
env:
|
||||
RPCS3_TOKEN: $(RPCS3-Token)
|
||||
|
||||
- job: Windows_Build
|
||||
variables:
|
||||
COMPILER: msvc
|
||||
QT_VER: '5.14.2'
|
||||
QT_DATE: '202003291224'
|
||||
QTDIR: C:\Qt\$(QT_VER)\msvc2017_64
|
||||
VULKAN_VER: '1.2.148.1'
|
||||
VULKAN_SDK_SHA: '5dbeafbc75c334811720fb50bd6ed7c9afd42afd31cad6be0b84cd8383aa9472'
|
||||
QT_VER_MAIN: '5'
|
||||
QT_VER: '5.15.2'
|
||||
QT_VER_MSVC: 'msvc2019'
|
||||
QT_DATE: '202011130602'
|
||||
QTDIR: C:\Qt\$(QT_VER)\$(QT_VER_MSVC)_64
|
||||
VULKAN_VER: '1.2.154.1'
|
||||
VULKAN_SDK_SHA: 'b64471f3a720e649c1fae6535ea83b8c642655ebed1485bfdf15bf4d88f746d9'
|
||||
VULKAN_SDK: C:\VulkanSDK\$(VULKAN_VER)
|
||||
CACHE_DIR: ./cache
|
||||
UPLOAD_COMMIT_HASH: 7d09e3be30805911226241afbb14f8cdc2eb054e
|
||||
UPLOAD_REPO_FULL_NAME: "RPCS3/rpcs3-binaries-win"
|
||||
|
||||
pool:
|
||||
vmImage: "windows-latest"
|
||||
@@ -91,7 +103,6 @@ jobs:
|
||||
maximumCpuCount: true
|
||||
platform: x64
|
||||
configuration: 'Release - LLVM'
|
||||
msbuildArgs: '/p:VCToolsVersion=14.25.28610'
|
||||
displayName: Compile RPCS3
|
||||
|
||||
- bash: .ci/deploy-windows.sh
|
||||
@@ -101,7 +112,7 @@ jobs:
|
||||
condition: succeeded()
|
||||
artifact: RPCS3 for Windows
|
||||
|
||||
- bash: .ci/github-upload-windows.sh
|
||||
- bash: .ci/github-upload.sh
|
||||
condition: and(ne(variables['Build.Reason'], 'PullRequest'), eq(variables['Build.Repository.Name'], 'RPCS3/rpcs3'), eq(variables['Build.SourceBranch'], 'refs/heads/master'))
|
||||
displayName: Push build to GitHub
|
||||
env:
|
||||
|
||||
+1
-1
Submodule llvm updated: f5679565d3...cb7748dfa0
@@ -1,7 +1,7 @@
|
||||
REM You need cmake and python to update the project files
|
||||
REM this script relies on CWD being the path that this script is in
|
||||
|
||||
cmake -G "Visual Studio 15 2017 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" -DLLVM_TARGETS_TO_BUILD=X86 -DLLVM_BUILD_RUNTIME=OFF -DLLVM_BUILD_TOOLS=OFF -DLLVM_INCLUDE_DOCS=OFF -DLLVM_INCLUDE_EXAMPLES=OFF -DLLVM_INCLUDE_TESTS=OFF -DLLVM_INCLUDE_TOOLS=OFF -DLLVM_INCLUDE_UTILS=OFF -DWITH_POLLY=OFF -DCMAKE_SYSTEM_VERSION=6.1 -DCMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION=8.1 ../llvm
|
||||
cmake -G "Visual Studio 16 2019 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" -DLLVM_TARGETS_TO_BUILD=X86 -DLLVM_DEFAULT_TARGET_TRIPLE:STRING=x86_64-pc-windows-msvc -DLLVM_HOST_TRIPLE:STRING=x86_64-pc-windows-msvc -DLLVM_BUILD_RUNTIME=OFF -DLLVM_BUILD_TOOLS=OFF -DLLVM_INCLUDE_DOCS=OFF -DLLVM_INCLUDE_EXAMPLES=OFF -DLLVM_INCLUDE_TESTS=OFF -DLLVM_INCLUDE_TOOLS=OFF -DLLVM_INCLUDE_BENCHMARKS=OFF -DLLVM_INCLUDE_UTILS=OFF -DLLVM_USE_INTEL_JITEVENTS=ON -DLLVM_ENABLE_Z3_SOLVER=OFF -DCMAKE_SYSTEM_VERSION=6.1 -DCMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION=10.0 -DLLVM_USE_CRT_DEBUG=MTd -DLLVM_USE_CRT_RELEASE=MT ../llvm
|
||||
|
||||
RD /S /Q cmake
|
||||
RD /S /Q CMakeFiles
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros">
|
||||
<CmakeGenerator>"Visual Studio $(VisualStudioVersion.Substring(0,2))"</CmakeGenerator>
|
||||
<CmakeCLI>cmake -G $(CmakeGenerator) -A x64 -Thost=x64 -DCMAKE_CONFIGURATION_TYPES="Debug;Release" -DLLVM_TARGETS_TO_BUILD=X86 -DLLVM_BUILD_RUNTIME=OFF -DLLVM_BUILD_TOOLS=OFF -DLLVM_INCLUDE_DOCS=OFF -DLLVM_INCLUDE_EXAMPLES=OFF -DLLVM_INCLUDE_TESTS=OFF -DLLVM_INCLUDE_TOOLS=OFF -DLLVM_INCLUDE_UTILS=OFF -DWITH_POLLY=OFF -DCMAKE_SYSTEM_VERSION=6.1 -DLLVM_TEMPORARILY_ALLOW_OLD_TOOLCHAIN=ON -DCMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION=$(WindowsTargetPlatformVersion) -DCMAKE_CXX_STANDARD=20 -DLLVM_USE_CRT_DEBUG=MTd -DLLVM_USE_CRT_RELEASE=MT ../llvm</CmakeCLI>
|
||||
<CmakeCLI>cmake -G $(CmakeGenerator) -A x64 -Thost=x64 -DCMAKE_CONFIGURATION_TYPES="Debug;Release" -DLLVM_TARGETS_TO_BUILD=X86 -DLLVM_BUILD_RUNTIME=OFF -DLLVM_BUILD_TOOLS=OFF -DLLVM_INCLUDE_DOCS=OFF -DLLVM_INCLUDE_EXAMPLES=OFF -DLLVM_INCLUDE_TESTS=OFF -DLLVM_INCLUDE_TOOLS=OFF -DLLVM_INCLUDE_UTILS=OFF -DCMAKE_SYSTEM_VERSION=6.1 -DLLVM_TEMPORARILY_ALLOW_OLD_TOOLCHAIN=ON -DCMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION=$(WindowsTargetPlatformVersion) -DLLVM_USE_CRT_DEBUG=MTd -DLLVM_USE_CRT_RELEASE=MT ../llvm</CmakeCLI>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<NMakePreprocessorDefinitions>
|
||||
|
||||
@@ -98,7 +98,6 @@ EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug - LLVM|x64 = Debug - LLVM|x64
|
||||
Debug - MemLeak|x64 = Debug - MemLeak|x64
|
||||
Debug|x64 = Debug|x64
|
||||
Release - LLVM|x64 = Release - LLVM|x64
|
||||
Release|x64 = Release|x64
|
||||
@@ -106,8 +105,6 @@ Global
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{AC40FF01-426E-4838-A317-66354CEFAE88}.Debug - LLVM|x64.ActiveCfg = Debug - LLVM|x64
|
||||
{AC40FF01-426E-4838-A317-66354CEFAE88}.Debug - LLVM|x64.Build.0 = Debug - LLVM|x64
|
||||
{AC40FF01-426E-4838-A317-66354CEFAE88}.Debug - MemLeak|x64.ActiveCfg = Debug - MemLeak|x64
|
||||
{AC40FF01-426E-4838-A317-66354CEFAE88}.Debug - MemLeak|x64.Build.0 = Debug - MemLeak|x64
|
||||
{AC40FF01-426E-4838-A317-66354CEFAE88}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{AC40FF01-426E-4838-A317-66354CEFAE88}.Debug|x64.Build.0 = Debug|x64
|
||||
{AC40FF01-426E-4838-A317-66354CEFAE88}.Release - LLVM|x64.ActiveCfg = Release - LLVM|x64
|
||||
@@ -116,8 +113,6 @@ Global
|
||||
{AC40FF01-426E-4838-A317-66354CEFAE88}.Release|x64.Build.0 = Release|x64
|
||||
{C4A10229-4712-4BD2-B63E-50D93C67A038}.Debug - LLVM|x64.ActiveCfg = Debug - LLVM|x64
|
||||
{C4A10229-4712-4BD2-B63E-50D93C67A038}.Debug - LLVM|x64.Build.0 = Debug - LLVM|x64
|
||||
{C4A10229-4712-4BD2-B63E-50D93C67A038}.Debug - MemLeak|x64.ActiveCfg = Debug - MemLeak|x64
|
||||
{C4A10229-4712-4BD2-B63E-50D93C67A038}.Debug - MemLeak|x64.Build.0 = Debug - MemLeak|x64
|
||||
{C4A10229-4712-4BD2-B63E-50D93C67A038}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{C4A10229-4712-4BD2-B63E-50D93C67A038}.Debug|x64.Build.0 = Debug|x64
|
||||
{C4A10229-4712-4BD2-B63E-50D93C67A038}.Release - LLVM|x64.ActiveCfg = Release - LLVM|x64
|
||||
@@ -125,14 +120,11 @@ Global
|
||||
{C4A10229-4712-4BD2-B63E-50D93C67A038}.Release|x64.ActiveCfg = Release|x64
|
||||
{C4A10229-4712-4BD2-B63E-50D93C67A038}.Release|x64.Build.0 = Release|x64
|
||||
{8BC303AB-25BE-4276-8E57-73F171B2D672}.Debug - LLVM|x64.ActiveCfg = Debug|x64
|
||||
{8BC303AB-25BE-4276-8E57-73F171B2D672}.Debug - MemLeak|x64.ActiveCfg = Debug|x64
|
||||
{8BC303AB-25BE-4276-8E57-73F171B2D672}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{8BC303AB-25BE-4276-8E57-73F171B2D672}.Release - LLVM|x64.ActiveCfg = Release|x64
|
||||
{8BC303AB-25BE-4276-8E57-73F171B2D672}.Release|x64.ActiveCfg = Release|x64
|
||||
{3384223A-6D97-4799-9862-359F85312892}.Debug - LLVM|x64.ActiveCfg = Debug - LLVM|x64
|
||||
{3384223A-6D97-4799-9862-359F85312892}.Debug - LLVM|x64.Build.0 = Debug - LLVM|x64
|
||||
{3384223A-6D97-4799-9862-359F85312892}.Debug - MemLeak|x64.ActiveCfg = Debug - MemLeak|x64
|
||||
{3384223A-6D97-4799-9862-359F85312892}.Debug - MemLeak|x64.Build.0 = Debug - MemLeak|x64
|
||||
{3384223A-6D97-4799-9862-359F85312892}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{3384223A-6D97-4799-9862-359F85312892}.Debug|x64.Build.0 = Debug|x64
|
||||
{3384223A-6D97-4799-9862-359F85312892}.Release - LLVM|x64.ActiveCfg = Release - LLVM|x64
|
||||
@@ -141,8 +133,6 @@ Global
|
||||
{3384223A-6D97-4799-9862-359F85312892}.Release|x64.Build.0 = Release|x64
|
||||
{78CB2F39-B809-4A06-8329-8C0A19119D3D}.Debug - LLVM|x64.ActiveCfg = Debug - LLVM|x64
|
||||
{78CB2F39-B809-4A06-8329-8C0A19119D3D}.Debug - LLVM|x64.Build.0 = Debug - LLVM|x64
|
||||
{78CB2F39-B809-4A06-8329-8C0A19119D3D}.Debug - MemLeak|x64.ActiveCfg = Debug - MemLeak|x64
|
||||
{78CB2F39-B809-4A06-8329-8C0A19119D3D}.Debug - MemLeak|x64.Build.0 = Debug - MemLeak|x64
|
||||
{78CB2F39-B809-4A06-8329-8C0A19119D3D}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{78CB2F39-B809-4A06-8329-8C0A19119D3D}.Debug|x64.Build.0 = Debug|x64
|
||||
{78CB2F39-B809-4A06-8329-8C0A19119D3D}.Release - LLVM|x64.ActiveCfg = Release - LLVM|x64
|
||||
@@ -151,8 +141,6 @@ Global
|
||||
{78CB2F39-B809-4A06-8329-8C0A19119D3D}.Release|x64.Build.0 = Release|x64
|
||||
{30A05C4D-F5FD-421C-A864-17A64BDEAA75}.Debug - LLVM|x64.ActiveCfg = Debug - LLVM|x64
|
||||
{30A05C4D-F5FD-421C-A864-17A64BDEAA75}.Debug - LLVM|x64.Build.0 = Debug - LLVM|x64
|
||||
{30A05C4D-F5FD-421C-A864-17A64BDEAA75}.Debug - MemLeak|x64.ActiveCfg = Debug - MemLeak|x64
|
||||
{30A05C4D-F5FD-421C-A864-17A64BDEAA75}.Debug - MemLeak|x64.Build.0 = Debug - MemLeak|x64
|
||||
{30A05C4D-F5FD-421C-A864-17A64BDEAA75}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{30A05C4D-F5FD-421C-A864-17A64BDEAA75}.Debug|x64.Build.0 = Debug|x64
|
||||
{30A05C4D-F5FD-421C-A864-17A64BDEAA75}.Release - LLVM|x64.ActiveCfg = Release - LLVM|x64
|
||||
@@ -160,8 +148,6 @@ Global
|
||||
{30A05C4D-F5FD-421C-A864-17A64BDEAA75}.Release|x64.ActiveCfg = Release|x64
|
||||
{30A05C4D-F5FD-421C-A864-17A64BDEAA75}.Release|x64.Build.0 = Release|x64
|
||||
{EB33566E-DA7F-4D28-9077-88C0B7C77E35}.Debug - LLVM|x64.ActiveCfg = Release|x64
|
||||
{EB33566E-DA7F-4D28-9077-88C0B7C77E35}.Debug - MemLeak|x64.ActiveCfg = Release|x64
|
||||
{EB33566E-DA7F-4D28-9077-88C0B7C77E35}.Debug - MemLeak|x64.Build.0 = Release|x64
|
||||
{EB33566E-DA7F-4D28-9077-88C0B7C77E35}.Debug|x64.ActiveCfg = Release|x64
|
||||
{EB33566E-DA7F-4D28-9077-88C0B7C77E35}.Debug|x64.Build.0 = Release|x64
|
||||
{EB33566E-DA7F-4D28-9077-88C0B7C77E35}.Release - LLVM|x64.ActiveCfg = Release|x64
|
||||
@@ -170,8 +156,6 @@ Global
|
||||
{EB33566E-DA7F-4D28-9077-88C0B7C77E35}.Release|x64.Build.0 = Release|x64
|
||||
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Debug - LLVM|x64.ActiveCfg = Debug Library|x64
|
||||
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Debug - LLVM|x64.Build.0 = Debug Library|x64
|
||||
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Debug - MemLeak|x64.ActiveCfg = Debug Library|x64
|
||||
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Debug - MemLeak|x64.Build.0 = Debug Library|x64
|
||||
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Debug|x64.ActiveCfg = Debug Library|x64
|
||||
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Debug|x64.Build.0 = Debug Library|x64
|
||||
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Release - LLVM|x64.ActiveCfg = Release Library|x64
|
||||
@@ -180,8 +164,6 @@ Global
|
||||
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Release|x64.Build.0 = Release Library|x64
|
||||
{60F89955-91C6-3A36-8000-13C592FEC2DF}.Debug - LLVM|x64.ActiveCfg = Debug|x64
|
||||
{60F89955-91C6-3A36-8000-13C592FEC2DF}.Debug - LLVM|x64.Build.0 = Debug|x64
|
||||
{60F89955-91C6-3A36-8000-13C592FEC2DF}.Debug - MemLeak|x64.ActiveCfg = Debug|x64
|
||||
{60F89955-91C6-3A36-8000-13C592FEC2DF}.Debug - MemLeak|x64.Build.0 = Debug|x64
|
||||
{60F89955-91C6-3A36-8000-13C592FEC2DF}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{60F89955-91C6-3A36-8000-13C592FEC2DF}.Debug|x64.Build.0 = Debug|x64
|
||||
{60F89955-91C6-3A36-8000-13C592FEC2DF}.Release - LLVM|x64.ActiveCfg = Release|x64
|
||||
@@ -189,14 +171,11 @@ Global
|
||||
{60F89955-91C6-3A36-8000-13C592FEC2DF}.Release|x64.ActiveCfg = Release|x64
|
||||
{60F89955-91C6-3A36-8000-13C592FEC2DF}.Release|x64.Build.0 = Release|x64
|
||||
{8F85B6CC-250F-4ACA-A617-E820A74E3E3C}.Debug - LLVM|x64.ActiveCfg = Debug|x64
|
||||
{8F85B6CC-250F-4ACA-A617-E820A74E3E3C}.Debug - MemLeak|x64.ActiveCfg = Debug|x64
|
||||
{8F85B6CC-250F-4ACA-A617-E820A74E3E3C}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{8F85B6CC-250F-4ACA-A617-E820A74E3E3C}.Release - LLVM|x64.ActiveCfg = Release|x64
|
||||
{8F85B6CC-250F-4ACA-A617-E820A74E3E3C}.Release|x64.ActiveCfg = Release|x64
|
||||
{3EE5F075-B546-42C4-B6A8-E3CCEF38B78D}.Debug - LLVM|x64.ActiveCfg = Debug - LLVM|x64
|
||||
{3EE5F075-B546-42C4-B6A8-E3CCEF38B78D}.Debug - LLVM|x64.Build.0 = Debug - LLVM|x64
|
||||
{3EE5F075-B546-42C4-B6A8-E3CCEF38B78D}.Debug - MemLeak|x64.ActiveCfg = Debug - MemLeak|x64
|
||||
{3EE5F075-B546-42C4-B6A8-E3CCEF38B78D}.Debug - MemLeak|x64.Build.0 = Debug - MemLeak|x64
|
||||
{3EE5F075-B546-42C4-B6A8-E3CCEF38B78D}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{3EE5F075-B546-42C4-B6A8-E3CCEF38B78D}.Debug|x64.Build.0 = Debug|x64
|
||||
{3EE5F075-B546-42C4-B6A8-E3CCEF38B78D}.Release - LLVM|x64.ActiveCfg = Release - LLVM|x64
|
||||
@@ -205,8 +184,6 @@ Global
|
||||
{3EE5F075-B546-42C4-B6A8-E3CCEF38B78D}.Release|x64.Build.0 = Release|x64
|
||||
{FDC361C5-7734-493B-8CFB-037308B35122}.Debug - LLVM|x64.ActiveCfg = Debug|x64
|
||||
{FDC361C5-7734-493B-8CFB-037308B35122}.Debug - LLVM|x64.Build.0 = Debug|x64
|
||||
{FDC361C5-7734-493B-8CFB-037308B35122}.Debug - MemLeak|x64.ActiveCfg = Debug|x64
|
||||
{FDC361C5-7734-493B-8CFB-037308B35122}.Debug - MemLeak|x64.Build.0 = Debug|x64
|
||||
{FDC361C5-7734-493B-8CFB-037308B35122}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{FDC361C5-7734-493B-8CFB-037308B35122}.Debug|x64.Build.0 = Debug|x64
|
||||
{FDC361C5-7734-493B-8CFB-037308B35122}.Release - LLVM|x64.ActiveCfg = Release|x64
|
||||
@@ -215,8 +192,6 @@ Global
|
||||
{FDC361C5-7734-493B-8CFB-037308B35122}.Release|x64.Build.0 = Release|x64
|
||||
{70CD65B0-91D6-4FAE-9A7B-4AF55D0D1B12}.Debug - LLVM|x64.ActiveCfg = Debug - LLVM|x64
|
||||
{70CD65B0-91D6-4FAE-9A7B-4AF55D0D1B12}.Debug - LLVM|x64.Build.0 = Debug - LLVM|x64
|
||||
{70CD65B0-91D6-4FAE-9A7B-4AF55D0D1B12}.Debug - MemLeak|x64.ActiveCfg = Debug|x64
|
||||
{70CD65B0-91D6-4FAE-9A7B-4AF55D0D1B12}.Debug - MemLeak|x64.Build.0 = Debug|x64
|
||||
{70CD65B0-91D6-4FAE-9A7B-4AF55D0D1B12}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{70CD65B0-91D6-4FAE-9A7B-4AF55D0D1B12}.Debug|x64.Build.0 = Debug|x64
|
||||
{70CD65B0-91D6-4FAE-9A7B-4AF55D0D1B12}.Release - LLVM|x64.ActiveCfg = Release - LLVM|x64
|
||||
@@ -225,8 +200,6 @@ Global
|
||||
{70CD65B0-91D6-4FAE-9A7B-4AF55D0D1B12}.Release|x64.Build.0 = Release|x64
|
||||
{A107C21C-418A-4697-BB10-20C3AA60E2E4}.Debug - LLVM|x64.ActiveCfg = Debug|x64
|
||||
{A107C21C-418A-4697-BB10-20C3AA60E2E4}.Debug - LLVM|x64.Build.0 = Debug|x64
|
||||
{A107C21C-418A-4697-BB10-20C3AA60E2E4}.Debug - MemLeak|x64.ActiveCfg = Debug|x64
|
||||
{A107C21C-418A-4697-BB10-20C3AA60E2E4}.Debug - MemLeak|x64.Build.0 = Debug|x64
|
||||
{A107C21C-418A-4697-BB10-20C3AA60E2E4}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{A107C21C-418A-4697-BB10-20C3AA60E2E4}.Debug|x64.Build.0 = Debug|x64
|
||||
{A107C21C-418A-4697-BB10-20C3AA60E2E4}.Release - LLVM|x64.ActiveCfg = Release|x64
|
||||
@@ -235,8 +208,6 @@ Global
|
||||
{A107C21C-418A-4697-BB10-20C3AA60E2E4}.Release|x64.Build.0 = Release|x64
|
||||
{939FE206-1182-ABC3-1234-FEAB88E98404}.Debug - LLVM|x64.ActiveCfg = Debug|x64
|
||||
{939FE206-1182-ABC3-1234-FEAB88E98404}.Debug - LLVM|x64.Build.0 = Debug|x64
|
||||
{939FE206-1182-ABC3-1234-FEAB88E98404}.Debug - MemLeak|x64.ActiveCfg = Debug|x64
|
||||
{939FE206-1182-ABC3-1234-FEAB88E98404}.Debug - MemLeak|x64.Build.0 = Debug|x64
|
||||
{939FE206-1182-ABC3-1234-FEAB88E98404}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{939FE206-1182-ABC3-1234-FEAB88E98404}.Debug|x64.Build.0 = Debug|x64
|
||||
{939FE206-1182-ABC3-1234-FEAB88E98404}.Release - LLVM|x64.ActiveCfg = Release|x64
|
||||
@@ -245,8 +216,6 @@ Global
|
||||
{939FE206-1182-ABC3-1234-FEAB88E98404}.Release|x64.Build.0 = Release|x64
|
||||
{349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Debug - LLVM|x64.ActiveCfg = Debug|x64
|
||||
{349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Debug - LLVM|x64.Build.0 = Debug|x64
|
||||
{349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Debug - MemLeak|x64.ActiveCfg = Debug|x64
|
||||
{349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Debug - MemLeak|x64.Build.0 = Debug|x64
|
||||
{349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Debug|x64.Build.0 = Debug|x64
|
||||
{349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Release - LLVM|x64.ActiveCfg = Release|x64
|
||||
@@ -255,8 +224,6 @@ Global
|
||||
{349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Release|x64.Build.0 = Release|x64
|
||||
{5B146DEA-9ACE-4D32-A7FD-3F42464DD69C}.Debug - LLVM|x64.ActiveCfg = Debug|x64
|
||||
{5B146DEA-9ACE-4D32-A7FD-3F42464DD69C}.Debug - LLVM|x64.Build.0 = Debug|x64
|
||||
{5B146DEA-9ACE-4D32-A7FD-3F42464DD69C}.Debug - MemLeak|x64.ActiveCfg = Debug|x64
|
||||
{5B146DEA-9ACE-4D32-A7FD-3F42464DD69C}.Debug - MemLeak|x64.Build.0 = Debug|x64
|
||||
{5B146DEA-9ACE-4D32-A7FD-3F42464DD69C}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{5B146DEA-9ACE-4D32-A7FD-3F42464DD69C}.Debug|x64.Build.0 = Debug|x64
|
||||
{5B146DEA-9ACE-4D32-A7FD-3F42464DD69C}.Release - LLVM|x64.ActiveCfg = Release|x64
|
||||
@@ -265,8 +232,6 @@ Global
|
||||
{5B146DEA-9ACE-4D32-A7FD-3F42464DD69C}.Release|x64.Build.0 = Release|x64
|
||||
{73973223-5EE8-41CA-8E88-1D60E89A237B}.Debug - LLVM|x64.ActiveCfg = Debug|x64
|
||||
{73973223-5EE8-41CA-8E88-1D60E89A237B}.Debug - LLVM|x64.Build.0 = Debug|x64
|
||||
{73973223-5EE8-41CA-8E88-1D60E89A237B}.Debug - MemLeak|x64.ActiveCfg = Debug|x64
|
||||
{73973223-5EE8-41CA-8E88-1D60E89A237B}.Debug - MemLeak|x64.Build.0 = Debug|x64
|
||||
{73973223-5EE8-41CA-8E88-1D60E89A237B}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{73973223-5EE8-41CA-8E88-1D60E89A237B}.Debug|x64.Build.0 = Debug|x64
|
||||
{73973223-5EE8-41CA-8E88-1D60E89A237B}.Release - LLVM|x64.ActiveCfg = Release|x64
|
||||
@@ -275,8 +240,6 @@ Global
|
||||
{73973223-5EE8-41CA-8E88-1D60E89A237B}.Release|x64.Build.0 = Release|x64
|
||||
{DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.Debug - LLVM|x64.ActiveCfg = Debug - LLVM|x64
|
||||
{DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.Debug - LLVM|x64.Build.0 = Debug - LLVM|x64
|
||||
{DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.Debug - MemLeak|x64.ActiveCfg = Debug|x64
|
||||
{DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.Debug - MemLeak|x64.Build.0 = Debug|x64
|
||||
{DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.Debug|x64.Build.0 = Debug|x64
|
||||
{DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.Release - LLVM|x64.ActiveCfg = Release - LLVM|x64
|
||||
@@ -284,7 +247,6 @@ Global
|
||||
{DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.Release|x64.ActiveCfg = Release|x64
|
||||
{DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.Release|x64.Build.0 = Release|x64
|
||||
{4CBD3DDD-5555-49A4-A44D-DD3D8CB516A1}.Debug - LLVM|x64.ActiveCfg = Debug|x64
|
||||
{4CBD3DDD-5555-49A4-A44D-DD3D8CB516A1}.Debug - MemLeak|x64.ActiveCfg = Debug|x64
|
||||
{4CBD3DDD-5555-49A4-A44D-DD3D8CB516A1}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{4CBD3DDD-5555-49A4-A44D-DD3D8CB516A1}.Release - LLVM|x64.ActiveCfg = Release|x64
|
||||
{4CBD3DDD-5555-49A4-A44D-DD3D8CB516A1}.Release|x64.ActiveCfg = Release|x64
|
||||
|
||||
@@ -58,6 +58,7 @@ set(RPCS3_SRC
|
||||
Input/basic_mouse_handler.cpp
|
||||
Input/ds3_pad_handler.cpp
|
||||
Input/ds4_pad_handler.cpp
|
||||
Input/dualsense_pad_handler.cpp
|
||||
Input/evdev_joystick_handler.cpp
|
||||
Input/keyboard_pad_handler.cpp
|
||||
Input/mm_joystick_handler.cpp
|
||||
@@ -107,7 +108,7 @@ if(UNIX)
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
target_link_libraries(rpcs3 ws2_32.lib Winmm.lib Psapi.lib gdi32.lib setupapi.lib)
|
||||
target_link_libraries(rpcs3 ws2_32.lib Iphlpapi.lib Winmm.lib Psapi.lib gdi32.lib setupapi.lib)
|
||||
else()
|
||||
target_link_libraries(rpcs3 ${CMAKE_DL_LIBS})
|
||||
endif()
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "utils.h"
|
||||
#include "utils.h"
|
||||
#include "aes.h"
|
||||
#include "key_vault.h"
|
||||
#include "util/logs.hpp"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
#pragma once
|
||||
|
||||
#include "Utilities/types.h"
|
||||
#include "util/types.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
+75
-44
@@ -1,10 +1,12 @@
|
||||
#include "stdafx.h"
|
||||
#include "stdafx.h"
|
||||
#include "key_vault.h"
|
||||
#include "unedat.h"
|
||||
|
||||
#include "Utilities/mutex.h"
|
||||
#include <cmath>
|
||||
|
||||
#include "util/asm.hpp"
|
||||
|
||||
LOG_CHANNEL(edat_log, "EDAT");
|
||||
|
||||
// Static variables are being modified concurrently in ec.cpp, for now use a mutex
|
||||
@@ -135,15 +137,15 @@ std::tuple<u64, s32, s32> dec_section(unsigned char* metadata)
|
||||
return std::make_tuple(offset, length, compression_end);
|
||||
}
|
||||
|
||||
v128 get_block_key(int block, NPD_HEADER *npd)
|
||||
u128 get_block_key(int block, NPD_HEADER *npd)
|
||||
{
|
||||
unsigned char empty_key[0x10] = {};
|
||||
unsigned char *src_key = (npd->version <= 1) ? empty_key : npd->dev_hash;
|
||||
v128 dest_key{};
|
||||
memcpy(dest_key._bytes, src_key, 0xC);
|
||||
u128 dest_key{};
|
||||
std::memcpy(&dest_key, src_key, 0xC);
|
||||
|
||||
s32 swappedBlock = swap32(block);
|
||||
memcpy(&dest_key._bytes[0xC], &swappedBlock, sizeof(swappedBlock));
|
||||
std::memcpy(reinterpret_cast<uchar*>(&dest_key) + 0xC, &swappedBlock, sizeof(swappedBlock));
|
||||
return dest_key;
|
||||
}
|
||||
|
||||
@@ -248,7 +250,7 @@ s64 decrypt_block(const fs::file* in, u8* out, EDAT_HEADER *edat, NPD_HEADER *np
|
||||
auto b_key = get_block_key(block_num, npd);
|
||||
|
||||
// Encrypt the block key with the crypto key.
|
||||
aesecb128_encrypt(crypt_key, b_key._bytes, key_result);
|
||||
aesecb128_encrypt(crypt_key, reinterpret_cast<uchar*>(&b_key), key_result);
|
||||
if ((edat->flags & EDAT_FLAG_0x10) != 0)
|
||||
aesecb128_encrypt(crypt_key, key_result, hash); // If FLAG 0x10 is set, encrypt again to get the final hash.
|
||||
else
|
||||
@@ -553,9 +555,10 @@ int validate_dev_klic(const u8* klicensee, NPD_HEADER *npd)
|
||||
memcpy(dev + 0xC, &type, 4);
|
||||
|
||||
// Check for an empty dev_hash (can't validate if devklic is NULL);
|
||||
auto klic = v128::loadu(klicensee);
|
||||
u128 klic;
|
||||
std::memcpy(&klic, klicensee, sizeof(klic));
|
||||
|
||||
if (klic == v128{})
|
||||
if (!klic)
|
||||
{
|
||||
// Allow empty dev hash.
|
||||
return 1;
|
||||
@@ -563,10 +566,10 @@ int validate_dev_klic(const u8* klicensee, NPD_HEADER *npd)
|
||||
else
|
||||
{
|
||||
// Generate klicensee xor key.
|
||||
auto key = klic ^ std::bit_cast<v128>(NP_OMAC_KEY_2);
|
||||
u128 key = klic ^ std::bit_cast<u128>(NP_OMAC_KEY_2);
|
||||
|
||||
// Hash with generated key and compare with dev_hash.
|
||||
return cmac_hash_compare(key._bytes, 0x10, dev, 0x60, npd->dev_hash, 0x10);
|
||||
return cmac_hash_compare(reinterpret_cast<uchar*>(&key), 0x10, dev, 0x60, npd->dev_hash, 0x10);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -575,15 +578,33 @@ int validate_npd_hashes(const char* file_name, const u8* klicensee, NPD_HEADER *
|
||||
int title_hash_result = 0;
|
||||
int dev_hash_result = 0;
|
||||
|
||||
const s32 file_name_length = ::narrow<s32>(std::strlen(file_name), HERE);
|
||||
std::unique_ptr<u8[]> buf(new u8[0x30 + file_name_length]);
|
||||
const s32 file_name_length = ::narrow<s32>(std::strlen(file_name));
|
||||
const usz buf_len = 0x30 + file_name_length;
|
||||
|
||||
std::unique_ptr<u8[]> buf(new u8[buf_len]);
|
||||
std::unique_ptr<u8[]> buf_lower(new u8[buf_len]);
|
||||
std::unique_ptr<u8[]> buf_upper(new u8[buf_len]);
|
||||
|
||||
// Build the title buffer (content_id + file_name).
|
||||
memcpy(buf.get(), npd->content_id, 0x30);
|
||||
memcpy(buf.get() + 0x30, file_name, file_name_length);
|
||||
std::memcpy(buf.get(), npd->content_id, 0x30);
|
||||
std::memcpy(buf.get() + 0x30, file_name, file_name_length);
|
||||
|
||||
std::memcpy(buf_lower.get(), buf.get(), buf_len);
|
||||
std::memcpy(buf_upper.get(), buf.get(), buf_len);
|
||||
|
||||
for (usz i = std::basic_string_view<u8>(buf.get() + 0x30, file_name_length).find_last_of('.'); i < buf_len; i++)
|
||||
{
|
||||
const u8 c = static_cast<u8>(buf[i]);
|
||||
buf_upper[i] = std::toupper(c);
|
||||
buf_lower[i] = std::tolower(c);
|
||||
}
|
||||
|
||||
// Hash with NPDRM_OMAC_KEY_3 and compare with title_hash.
|
||||
title_hash_result = cmac_hash_compare(NP_OMAC_KEY_3, 0x10, buf.get(), 0x30 + file_name_length, npd->title_hash, 0x10);
|
||||
// Try to ignore case sensivity with file extension
|
||||
title_hash_result =
|
||||
cmac_hash_compare(NP_OMAC_KEY_3, 0x10, buf.get(), buf_len, npd->title_hash, 0x10) ||
|
||||
cmac_hash_compare(NP_OMAC_KEY_3, 0x10, buf_lower.get(), buf_len, npd->title_hash, 0x10) ||
|
||||
cmac_hash_compare(NP_OMAC_KEY_3, 0x10, buf_upper.get(), buf_len, npd->title_hash, 0x10);
|
||||
|
||||
if (verbose)
|
||||
{
|
||||
@@ -647,7 +668,7 @@ bool extract_all_data(const fs::file* input, const fs::file* output, const char*
|
||||
}
|
||||
|
||||
// Set decryption key.
|
||||
v128 key{};
|
||||
u128 key{};
|
||||
|
||||
// Check EDAT/SDAT flag.
|
||||
if ((EDAT.flags & SDAT_FLAG) == SDAT_FLAG)
|
||||
@@ -661,7 +682,7 @@ bool extract_all_data(const fs::file* input, const fs::file* output, const char*
|
||||
}
|
||||
|
||||
// Generate SDAT key.
|
||||
key = std::bit_cast<v128>(NPD.dev_hash) ^ std::bit_cast<v128>(SDAT_KEY);
|
||||
key = std::bit_cast<u128>(NPD.dev_hash) ^ std::bit_cast<u128>(SDAT_KEY);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -674,7 +695,7 @@ bool extract_all_data(const fs::file* input, const fs::file* output, const char*
|
||||
}
|
||||
|
||||
// Perform header validation (EDAT only).
|
||||
char real_file_name[MAX_PATH];
|
||||
char real_file_name[CRYPTO_MAX_PATH];
|
||||
extract_file_name(input_file_name, real_file_name);
|
||||
if (!validate_npd_hashes(real_file_name, devklic, &NPD, verbose))
|
||||
{
|
||||
@@ -694,21 +715,27 @@ bool extract_all_data(const fs::file* input, const fs::file* output, const char*
|
||||
memcpy(&key, rifkey, 0x10);
|
||||
|
||||
// Make sure we don't have an empty RIF key.
|
||||
if (key == v128{})
|
||||
if (!key)
|
||||
{
|
||||
edat_log.error("EDAT: A valid RAP file is needed for this EDAT file!");
|
||||
edat_log.error("EDAT: A valid RAP file is needed for this EDAT file! (local activation)");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
else if ((NPD.license & 0x1) == 0x1) // Type 1: Use network activation.
|
||||
{
|
||||
edat_log.error("EDAT: Network license not supported!");
|
||||
return 1;
|
||||
memcpy(&key, rifkey, 0x10);
|
||||
|
||||
// Make sure we don't have an empty RIF key.
|
||||
if (!key)
|
||||
{
|
||||
edat_log.error("EDAT: A valid RAP file is needed for this EDAT file! (network activation)");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (verbose)
|
||||
{
|
||||
be_t<v128> data;
|
||||
be_t<u128> data;
|
||||
|
||||
std::memcpy(&data, devklic, sizeof(data));
|
||||
edat_log.notice("DEVKLIC: %s", data);
|
||||
@@ -719,18 +746,18 @@ bool extract_all_data(const fs::file* input, const fs::file* output, const char*
|
||||
|
||||
if (verbose)
|
||||
{
|
||||
edat_log.notice("DECRYPTION KEY: %s", std::bit_cast<be_t<v128>>(key));
|
||||
edat_log.notice("DECRYPTION KEY: %s", std::bit_cast<be_t<u128>>(key));
|
||||
}
|
||||
|
||||
input->seek(0);
|
||||
if (check_data(key._bytes, &EDAT, &NPD, input, verbose))
|
||||
if (check_data(reinterpret_cast<uchar*>(&key), &EDAT, &NPD, input, verbose))
|
||||
{
|
||||
edat_log.error("EDAT: Data parsing failed!");
|
||||
return 1;
|
||||
}
|
||||
|
||||
input->seek(0);
|
||||
if (decrypt_data(input, output, &EDAT, &NPD, key._bytes, verbose))
|
||||
if (decrypt_data(input, output, &EDAT, &NPD, reinterpret_cast<uchar*>(&key), verbose))
|
||||
{
|
||||
edat_log.error("EDAT: Data decryption failed!");
|
||||
return 1;
|
||||
@@ -739,14 +766,14 @@ bool extract_all_data(const fs::file* input, const fs::file* output, const char*
|
||||
return 0;
|
||||
}
|
||||
|
||||
v128 GetEdatRifKeyFromRapFile(const fs::file& rap_file)
|
||||
u128 GetEdatRifKeyFromRapFile(const fs::file& rap_file)
|
||||
{
|
||||
v128 rapkey{};
|
||||
v128 rifkey{};
|
||||
u128 rapkey{};
|
||||
u128 rifkey{};
|
||||
|
||||
rap_file.read<v128>(rapkey);
|
||||
rap_file.read<u128>(rapkey);
|
||||
|
||||
rap_to_rif(rapkey._bytes, rifkey._bytes);
|
||||
rap_to_rif(reinterpret_cast<uchar*>(&rapkey), reinterpret_cast<uchar*>(&rifkey));
|
||||
|
||||
return rifkey;
|
||||
}
|
||||
@@ -774,7 +801,7 @@ bool VerifyEDATHeaderWithKLicense(const fs::file& input, const std::string& inpu
|
||||
}
|
||||
|
||||
// Perform header validation (EDAT only).
|
||||
char real_file_name[MAX_PATH];
|
||||
char real_file_name[CRYPTO_MAX_PATH];
|
||||
extract_file_name(input_file_name.c_str(), real_file_name);
|
||||
if (!validate_npd_hashes(real_file_name, custom_klic, &NPD, false))
|
||||
{
|
||||
@@ -797,8 +824,8 @@ fs::file DecryptEDAT(const fs::file& input, const std::string& input_file_name,
|
||||
input.seek(0);
|
||||
|
||||
// Set keys (RIF and DEVKLIC).
|
||||
v128 rifKey{};
|
||||
v128 devklic{};
|
||||
u128 rifKey{};
|
||||
u128 devklic{};
|
||||
|
||||
// Select the EDAT key mode.
|
||||
switch (mode)
|
||||
@@ -852,7 +879,7 @@ fs::file DecryptEDAT(const fs::file& input, const std::string& input_file_name,
|
||||
|
||||
// Delete the bad output file if any errors arise.
|
||||
fs::file output = fs::make_stream<std::vector<u8>>();
|
||||
if (extract_all_data(&input, &output, input_file_name.c_str(), devklic._bytes, rifKey._bytes, verbose))
|
||||
if (extract_all_data(&input, &output, input_file_name.c_str(), reinterpret_cast<uchar*>(&devklic), reinterpret_cast<uchar*>(&rifKey), verbose))
|
||||
{
|
||||
output.release();
|
||||
return fs::file{};
|
||||
@@ -878,12 +905,12 @@ bool EDATADecrypter::ReadHeader()
|
||||
if ((edatHeader.flags & SDAT_FLAG) == SDAT_FLAG)
|
||||
{
|
||||
// Generate SDAT key.
|
||||
dec_key = std::bit_cast<v128>(npdHeader.dev_hash) ^ std::bit_cast<v128>(SDAT_KEY);
|
||||
dec_key = std::bit_cast<u128>(npdHeader.dev_hash) ^ std::bit_cast<u128>(SDAT_KEY);
|
||||
}
|
||||
else
|
||||
{
|
||||
// verify key
|
||||
if (validate_dev_klic(dev_key._bytes, &npdHeader) == 0)
|
||||
if (validate_dev_klic(reinterpret_cast<uchar*>(&dev_key), &npdHeader) == 0)
|
||||
{
|
||||
edat_log.error("EDAT: Failed validating klic");
|
||||
return false;
|
||||
@@ -896,15 +923,19 @@ bool EDATADecrypter::ReadHeader()
|
||||
{
|
||||
dec_key = std::move(rif_key);
|
||||
|
||||
if (dec_key == v128{})
|
||||
if (!dec_key)
|
||||
{
|
||||
edat_log.warning("EDAT: Empty Dec key!");
|
||||
edat_log.warning("EDAT: Empty Dec key for local activation!");
|
||||
}
|
||||
}
|
||||
else if ((npdHeader.license & 0x1) == 0x1) // Type 1: Use network activation.
|
||||
{
|
||||
edat_log.error("EDAT: Network license not supported!");
|
||||
return false;
|
||||
dec_key = std::move(rif_key);
|
||||
|
||||
if (!dec_key)
|
||||
{
|
||||
edat_log.warning("EDAT: Empty Dec key for network activation!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -919,7 +950,7 @@ bool EDATADecrypter::ReadHeader()
|
||||
}*/
|
||||
|
||||
file_size = edatHeader.file_size;
|
||||
total_blocks = ::aligned_div(edatHeader.file_size, edatHeader.block_size);
|
||||
total_blocks = utils::aligned_div(edatHeader.file_size, edatHeader.block_size);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -932,7 +963,7 @@ u64 EDATADecrypter::ReadData(u64 pos, u8* data, u64 size)
|
||||
// now we need to offset things to account for the actual 'range' requested
|
||||
const u64 startOffset = pos % edatHeader.block_size;
|
||||
|
||||
const u32 num_blocks = static_cast<u32>(::aligned_div(startOffset + size, edatHeader.block_size));
|
||||
const u32 num_blocks = static_cast<u32>(utils::aligned_div(startOffset + size, edatHeader.block_size));
|
||||
const u64 bufSize = num_blocks*edatHeader.block_size;
|
||||
if (data_buf_size < (bufSize))
|
||||
{
|
||||
@@ -947,7 +978,7 @@ u64 EDATADecrypter::ReadData(u64 pos, u8* data, u64 size)
|
||||
for (u32 i = starting_block; i < ending_block; ++i)
|
||||
{
|
||||
edata_file.seek(0);
|
||||
u64 res = decrypt_block(&edata_file, &data_buf[writeOffset], &edatHeader, &npdHeader, dec_key._bytes, i, total_blocks, edatHeader.file_size);
|
||||
u64 res = decrypt_block(&edata_file, &data_buf[writeOffset], &edatHeader, &npdHeader, reinterpret_cast<uchar*>(&dec_key), i, total_blocks, edatHeader.file_size);
|
||||
if (res == umax)
|
||||
{
|
||||
edat_log.error("Error Decrypting data");
|
||||
|
||||
+10
-9
@@ -4,7 +4,6 @@
|
||||
|
||||
#include "utils.h"
|
||||
|
||||
#include "Utilities/BEType.h"
|
||||
#include "Utilities/File.h"
|
||||
|
||||
constexpr u32 SDAT_FLAG = 0x01000000;
|
||||
@@ -17,8 +16,8 @@ constexpr u32 EDAT_DEBUG_DATA_FLAG = 0x80000000;
|
||||
|
||||
struct loaded_npdrm_keys
|
||||
{
|
||||
atomic_t<v128> devKlic{};
|
||||
atomic_t<v128> rifKey{};
|
||||
atomic_t<u128> devKlic{};
|
||||
atomic_t<u128> rifKey{};
|
||||
atomic_t<u32> npdrm_fds{0};
|
||||
};
|
||||
|
||||
@@ -48,7 +47,7 @@ extern fs::file DecryptEDAT(const fs::file& input, const std::string& input_file
|
||||
|
||||
extern bool VerifyEDATHeaderWithKLicense(const fs::file& input, const std::string& input_file_name, const u8* custom_klic, std::string* contentID);
|
||||
|
||||
v128 GetEdatRifKeyFromRapFile(const fs::file& rap_file);
|
||||
u128 GetEdatRifKeyFromRapFile(const fs::file& rap_file);
|
||||
|
||||
struct EDATADecrypter final : fs::file_base
|
||||
{
|
||||
@@ -65,18 +64,20 @@ struct EDATADecrypter final : fs::file_base
|
||||
std::unique_ptr<u8[]> data_buf;
|
||||
u64 data_buf_size{0};
|
||||
|
||||
v128 dec_key{};
|
||||
u128 dec_key{};
|
||||
|
||||
// edat usage
|
||||
v128 rif_key{};
|
||||
v128 dev_key{};
|
||||
u128 rif_key{};
|
||||
u128 dev_key{};
|
||||
public:
|
||||
// SdataByFd usage
|
||||
EDATADecrypter(fs::file&& input)
|
||||
: edata_file(std::move(input)) {}
|
||||
// Edat usage
|
||||
EDATADecrypter(fs::file&& input, const v128& dev_key, const v128& rif_key)
|
||||
: edata_file(std::move(input)), rif_key(rif_key), dev_key(dev_key) {}
|
||||
EDATADecrypter(fs::file&& input, const u128& dev_key, const u128& rif_key)
|
||||
: edata_file(std::move(input))
|
||||
, rif_key(rif_key)
|
||||
, dev_key(dev_key) {}
|
||||
|
||||
~EDATADecrypter() override {}
|
||||
// false if invalid
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "stdafx.h"
|
||||
#include "stdafx.h"
|
||||
#include "aes.h"
|
||||
#include "sha1.h"
|
||||
#include "key_vault.h"
|
||||
@@ -502,7 +502,7 @@ package_error package_reader::check_target_app_version()
|
||||
|
||||
const std::string name{ reinterpret_cast<char*>(buf.get()), entry.name_size };
|
||||
|
||||
// We're looking for the PARAM.SFO file, if there is any
|
||||
// We're looking for the PARAM.SFO file, if there is any
|
||||
if (name != "PARAM.SFO")
|
||||
{
|
||||
continue;
|
||||
@@ -697,7 +697,7 @@ bool package_reader::extract_data(atomic_t<double>& sync)
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t num_failures = 0;
|
||||
usz num_failures = 0;
|
||||
|
||||
std::vector<PKGEntry> entries(header.file_count);
|
||||
|
||||
@@ -857,7 +857,7 @@ void package_reader::archive_seek(const s64 new_offset, const fs::seek_mode damo
|
||||
cur_offset += new_offset;
|
||||
|
||||
u64 _offset = 0;
|
||||
for (size_t i = 0; i < filelist.size(); i++)
|
||||
for (usz i = 0; i < filelist.size(); i++)
|
||||
{
|
||||
if (cur_offset < (_offset + filelist[i].size()))
|
||||
{
|
||||
@@ -872,7 +872,7 @@ void package_reader::archive_seek(const s64 new_offset, const fs::seek_mode damo
|
||||
|
||||
u64 package_reader::archive_read(void* data_ptr, const u64 num_bytes)
|
||||
{
|
||||
ASSERT(filelist.size() > cur_file && filelist[cur_file]);
|
||||
ensure(filelist.size() > cur_file && filelist[cur_file]);
|
||||
|
||||
const u64 num_bytes_left = filelist[cur_file].size() - cur_file_offset;
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include "Utilities/BEType.h"
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
|
||||
@@ -96,7 +95,7 @@ struct PKGExtHeader
|
||||
be_t<u32> ext_hdr_size; // Extended header size. ex: 0x40
|
||||
be_t<u32> ext_data_size; // ex: 0x180
|
||||
be_t<u32> main_and_ext_headers_hmac_offset; // ex: 0x100
|
||||
be_t<u32> metadata_header_hmac_offset; // ex: 0x360, 0x390, 0x490
|
||||
be_t<u32> metadata_header_hmac_offset; // ex: 0x360, 0x390, 0x490
|
||||
be_t<u64> tail_offset; // tail size seams to be always 0x1A0
|
||||
be_t<u32> padding1;
|
||||
be_t<u32> pkg_key_id; // Id of the AES key used for decryption. PSP = 0x1, PSVita = 0xC0000002, PSM = 0xC0000004
|
||||
@@ -118,16 +117,16 @@ struct PKGEntry
|
||||
struct PKGMetaData
|
||||
{
|
||||
private:
|
||||
static std::string to_hex_string(u8 buf[], size_t size)
|
||||
static std::string to_hex_string(u8 buf[], usz size)
|
||||
{
|
||||
std::stringstream sstream;
|
||||
for (size_t i = 0; i < size; i++)
|
||||
for (usz i = 0; i < size; i++)
|
||||
{
|
||||
sstream << std::hex << std::setw(2) << std::setfill('0') << static_cast<int>(buf[i]);
|
||||
}
|
||||
return sstream.str();
|
||||
}
|
||||
static std::string to_hex_string(u8 buf[], size_t size, size_t dotpos)
|
||||
static std::string to_hex_string(u8 buf[], usz size, usz dotpos)
|
||||
{
|
||||
std::string result = to_hex_string(buf, size);
|
||||
if (result.size() > dotpos)
|
||||
@@ -313,14 +312,14 @@ private:
|
||||
u64 archive_read(void* data_ptr, const u64 num_bytes);
|
||||
u64 decrypt(u64 offset, u64 size, const uchar* key);
|
||||
|
||||
const std::size_t BUF_SIZE = 8192 * 1024; // 8 MB
|
||||
const usz BUF_SIZE = 8192 * 1024; // 8 MB
|
||||
|
||||
bool m_is_valid = false;
|
||||
|
||||
std::string m_path;
|
||||
std::string install_dir;
|
||||
std::vector<fs::file> filelist;
|
||||
size_t cur_file = 0;
|
||||
usz cur_file = 0;
|
||||
u64 cur_offset = 0;
|
||||
u64 cur_file_offset = 0;
|
||||
std::unique_ptr<u128[]> buf;
|
||||
|
||||
+20
-17
@@ -1,9 +1,8 @@
|
||||
#include "stdafx.h"
|
||||
#include "stdafx.h"
|
||||
#include "aes.h"
|
||||
#include "sha1.h"
|
||||
#include "utils.h"
|
||||
#include "unself.h"
|
||||
#include "Utilities/BEType.h"
|
||||
#include "Emu/VFS.h"
|
||||
#include "Emu/System.h"
|
||||
|
||||
@@ -714,7 +713,7 @@ bool SCEDecrypter::LoadMetadata(const u8 erk[32], const u8 riv[16])
|
||||
}
|
||||
|
||||
// Perform AES-CTR encryption on the metadata headers.
|
||||
size_t ctr_nc_off = 0;
|
||||
usz ctr_nc_off = 0;
|
||||
u8 ctr_stream_block[0x10];
|
||||
aes_setkey_enc(&aes, meta_info.key, 128);
|
||||
aes_crypt_ctr(&aes, metadata_headers_size, &ctr_nc_off, meta_info.iv, ctr_stream_block, metadata_headers.get(), metadata_headers.get());
|
||||
@@ -745,7 +744,7 @@ bool SCEDecrypter::DecryptData()
|
||||
// Calculate the total data size.
|
||||
for (unsigned int i = 0; i < meta_hdr.section_count; i++)
|
||||
{
|
||||
data_buf_length += ::narrow<u32>(meta_shdr[i].data_size, HERE);
|
||||
data_buf_length += ::narrow<u32>(meta_shdr[i].data_size);
|
||||
}
|
||||
|
||||
// Allocate a buffer to store decrypted data.
|
||||
@@ -757,7 +756,7 @@ bool SCEDecrypter::DecryptData()
|
||||
// Parse the metadata section headers to find the offsets of encrypted data.
|
||||
for (unsigned int i = 0; i < meta_hdr.section_count; i++)
|
||||
{
|
||||
size_t ctr_nc_off = 0;
|
||||
usz ctr_nc_off = 0;
|
||||
u8 ctr_stream_block[0x10];
|
||||
u8 data_key[0x10];
|
||||
u8 data_iv[0x10];
|
||||
@@ -799,7 +798,7 @@ bool SCEDecrypter::DecryptData()
|
||||
}
|
||||
|
||||
// Advance the buffer's offset.
|
||||
data_buf_offset += ::narrow<u32>(meta_shdr[i].data_size, HERE);
|
||||
data_buf_offset += ::narrow<u32>(meta_shdr[i].data_size);
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -823,13 +822,13 @@ std::vector<fs::file> SCEDecrypter::MakeFile()
|
||||
// Decompress if necessary.
|
||||
if (meta_shdr[i].compressed == 2)
|
||||
{
|
||||
const size_t BUFSIZE = 32 * 1024;
|
||||
const usz BUFSIZE = 32 * 1024;
|
||||
u8 tempbuf[BUFSIZE];
|
||||
z_stream strm;
|
||||
strm.zalloc = Z_NULL;
|
||||
strm.zfree = Z_NULL;
|
||||
strm.opaque = Z_NULL;
|
||||
strm.avail_in = ::narrow<uInt>(meta_shdr[i].data_size, HERE);
|
||||
strm.avail_in = ::narrow<uInt>(meta_shdr[i].data_size);
|
||||
strm.avail_out = BUFSIZE;
|
||||
strm.next_in = data_buf.get()+data_buf_offset;
|
||||
strm.next_out = tempbuf;
|
||||
@@ -874,7 +873,7 @@ std::vector<fs::file> SCEDecrypter::MakeFile()
|
||||
}
|
||||
|
||||
// Advance the data buffer offset by data size.
|
||||
data_buf_offset += ::narrow<u32>(meta_shdr[i].data_size, HERE);
|
||||
data_buf_offset += ::narrow<u32>(meta_shdr[i].data_size);
|
||||
|
||||
if (out_f.pos() != out_f.size())
|
||||
fmt::throw_exception("MakeELF written bytes (%llu) does not equal buffer size (%llu).", out_f.pos(), out_f.size());
|
||||
@@ -1112,8 +1111,12 @@ bool SELFDecrypter::DecryptNPDRM(u8 *metadata, u32 metadata_size)
|
||||
|
||||
if (ctrl->npdrm.license == 1) // Network license.
|
||||
{
|
||||
self_log.error("SELF: Can't decrypt network NPDRM!");
|
||||
return false;
|
||||
// Try to find a RAP file to get the key.
|
||||
if (!GetKeyFromRap(ctrl->npdrm.content_id, npdrm_key))
|
||||
{
|
||||
self_log.error("SELF: Can't decrypt network NPDRM!");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (ctrl->npdrm.license == 2) // Local license.
|
||||
{
|
||||
@@ -1205,7 +1208,7 @@ bool SELFDecrypter::LoadMetadata(u8* klic_key)
|
||||
}
|
||||
|
||||
// Perform AES-CTR encryption on the metadata headers.
|
||||
size_t ctr_nc_off = 0;
|
||||
usz ctr_nc_off = 0;
|
||||
u8 ctr_stream_block[0x10];
|
||||
aes_setkey_enc(&aes, meta_info.key, 128);
|
||||
aes_crypt_ctr(&aes, metadata_headers_size, &ctr_nc_off, meta_info.iv, ctr_stream_block, metadata_headers.get(), metadata_headers.get());
|
||||
@@ -1239,7 +1242,7 @@ bool SELFDecrypter::DecryptData()
|
||||
if (meta_shdr[i].encrypted == 3)
|
||||
{
|
||||
if ((meta_shdr[i].key_idx <= meta_hdr.key_count - 1) && (meta_shdr[i].iv_idx <= meta_hdr.key_count))
|
||||
data_buf_length += ::narrow<u32>(meta_shdr[i].data_size, HERE);
|
||||
data_buf_length += ::narrow<u32>(meta_shdr[i].data_size);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1252,7 +1255,7 @@ bool SELFDecrypter::DecryptData()
|
||||
// Parse the metadata section headers to find the offsets of encrypted data.
|
||||
for (unsigned int i = 0; i < meta_hdr.section_count; i++)
|
||||
{
|
||||
size_t ctr_nc_off = 0;
|
||||
usz ctr_nc_off = 0;
|
||||
u8 ctr_stream_block[0x10];
|
||||
u8 data_key[0x10];
|
||||
u8 data_iv[0x10];
|
||||
@@ -1285,7 +1288,7 @@ bool SELFDecrypter::DecryptData()
|
||||
memcpy(data_buf.get() + data_buf_offset, buf.get(), meta_shdr[i].data_size);
|
||||
|
||||
// Advance the buffer's offset.
|
||||
data_buf_offset += ::narrow<u32>(meta_shdr[i].data_size, HERE);
|
||||
data_buf_offset += ::narrow<u32>(meta_shdr[i].data_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1484,7 +1487,7 @@ bool verify_npdrm_self_headers(const fs::file& self, u8* klic_key)
|
||||
return true;
|
||||
}
|
||||
|
||||
v128 get_default_self_klic()
|
||||
u128 get_default_self_klic()
|
||||
{
|
||||
return std::bit_cast<v128>(NP_KLIC_FREE);
|
||||
return std::bit_cast<u128>(NP_KLIC_FREE);
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
#pragma once
|
||||
#pragma once
|
||||
|
||||
#include "key_vault.h"
|
||||
#include "zlib.h"
|
||||
|
||||
#include "Utilities/types.h"
|
||||
#include "util/types.hpp"
|
||||
#include "Utilities/File.h"
|
||||
#include "util/logs.hpp"
|
||||
|
||||
@@ -489,7 +489,7 @@ private:
|
||||
}
|
||||
|
||||
// Advance the data buffer offset by data size.
|
||||
data_buf_offset += ::narrow<u32>(meta_shdr[i].data_size, HERE);
|
||||
data_buf_offset += ::narrow<u32>(meta_shdr[i].data_size);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -509,5 +509,4 @@ private:
|
||||
fs::file decrypt_self(fs::file elf_or_self, u8* klic_key = nullptr, SelfAdditionalInfo* additional_info = nullptr);
|
||||
bool verify_npdrm_self_headers(const fs::file& self, u8* klic_key = nullptr);
|
||||
|
||||
union v128;
|
||||
v128 get_default_self_klic();
|
||||
u128 get_default_self_klic();
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include <time.h>
|
||||
#include "Utilities/StrUtil.h"
|
||||
#include "Utilities/span.h"
|
||||
#include "Utilities/File.h"
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
@@ -120,16 +121,16 @@ void cmac_hash_forge(unsigned char *key, int key_len, unsigned char *in, int in_
|
||||
aes_cmac(&ctx, in_len, in, hash);
|
||||
}
|
||||
|
||||
char* extract_file_name(const char* file_path, char real_file_name[MAX_PATH])
|
||||
char* extract_file_name(const char* file_path, char real_file_name[CRYPTO_MAX_PATH])
|
||||
{
|
||||
std::string_view v(file_path);
|
||||
|
||||
if (auto pos = v.find_last_of("/\\"); pos != umax)
|
||||
if (auto pos = v.find_last_of(fs::delim); pos != umax)
|
||||
{
|
||||
v.remove_prefix(pos + 1);
|
||||
}
|
||||
|
||||
gsl::span r(real_file_name, MAX_PATH);
|
||||
gsl::span r(real_file_name, CRYPTO_MAX_PATH);
|
||||
strcpy_trunc(r, v);
|
||||
return real_file_name;
|
||||
}
|
||||
|
||||
@@ -4,9 +4,7 @@
|
||||
// Licensed under the terms of the GNU GPL, version 3
|
||||
// http://www.gnu.org/licenses/gpl-3.0.txt
|
||||
|
||||
#include "../../Utilities/types.h"
|
||||
|
||||
#define MAX_PATH 4096
|
||||
#include "util/types.hpp"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "aes.h"
|
||||
@@ -14,6 +12,8 @@
|
||||
#include "lz.h"
|
||||
#include "ec.h"
|
||||
|
||||
enum { CRYPTO_MAX_PATH = 4096 };
|
||||
|
||||
// Auxiliary functions (endian swap, xor, and file name).
|
||||
inline u16 swap16(u16 i)
|
||||
{
|
||||
@@ -42,7 +42,7 @@ inline u64 swap64(u64 i)
|
||||
#endif
|
||||
}
|
||||
|
||||
char* extract_file_name(const char* file_path, char real_file_name[MAX_PATH]);
|
||||
char* extract_file_name(const char* file_path, char real_file_name[CRYPTO_MAX_PATH]);
|
||||
|
||||
// Hex string conversion auxiliary functions.
|
||||
u64 hex_to_u64(const char* hex_str);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "stdafx.h"
|
||||
#include "stdafx.h"
|
||||
|
||||
#include "OpenALBackend.h"
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#pragma once
|
||||
#pragma once
|
||||
|
||||
#include "Emu/Audio/AudioBackend.h"
|
||||
#include "3rdparty/OpenAL/include/alext.h"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#ifndef HAVE_ALSA
|
||||
#ifndef HAVE_ALSA
|
||||
#error "ALSA support disabled but still being built."
|
||||
#endif
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "stdafx.h"
|
||||
#include "stdafx.h"
|
||||
#include "AudioBackend.h"
|
||||
#include "Emu/system_config.h"
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
#pragma once
|
||||
|
||||
#include "Utilities/types.h"
|
||||
#include "util/types.hpp"
|
||||
#include "Utilities/StrFmt.h"
|
||||
|
||||
enum : u32
|
||||
{
|
||||
@@ -101,7 +102,7 @@ public:
|
||||
u32 get_sample_size() const;
|
||||
|
||||
u32 get_channels() const;
|
||||
|
||||
|
||||
bool get_convert_to_u16() const;
|
||||
|
||||
bool has_capability(u32 cap) const;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "stdafx.h"
|
||||
#include "stdafx.h"
|
||||
#include "AudioDumper.h"
|
||||
|
||||
#include "Utilities/date_time.h"
|
||||
@@ -33,7 +33,8 @@ void AudioDumper::WriteData(const void* buffer, u32 size)
|
||||
{
|
||||
if (GetCh())
|
||||
{
|
||||
verify(HERE), size, m_output.write(buffer, size) == size;
|
||||
ensure(size);
|
||||
ensure(m_output.write(buffer, size) == size);
|
||||
m_header.Size += size;
|
||||
m_header.RIFF.Size += size;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "Utilities/types.h"
|
||||
#include "util/types.hpp"
|
||||
#include "Utilities/File.h"
|
||||
|
||||
struct WAVHeader
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#ifndef HAVE_FAUDIO
|
||||
#ifndef HAVE_FAUDIO
|
||||
#error "FAudio support disabled but still being built."
|
||||
#endif
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#pragma once
|
||||
#pragma once
|
||||
|
||||
#include "Emu/Audio/AudioBackend.h"
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#ifndef HAVE_PULSE
|
||||
#ifndef HAVE_PULSE
|
||||
#error "PulseAudio support disabled but still being built."
|
||||
#endif
|
||||
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
#ifndef _WIN32
|
||||
#ifndef _WIN32
|
||||
#error "XAudio2 can only be built on Windows."
|
||||
#endif
|
||||
|
||||
#include <algorithm>
|
||||
#include "util/logs.hpp"
|
||||
#include "Utilities/StrFmt.h"
|
||||
#include "Emu/System.h"
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user