Compare commits

...

307 Commits

Author SHA1 Message Date
Ani 6cd5a7eab9 rpcs3_version: Bump to 0.0.29 2023-07-31 20:03:24 +03:00
Megamouse d119cf6e96 Qt6 port 2023-07-31 20:03:24 +03:00
Megamouse 9b3a878c18 cellAudioIn: reduce log spam
Some logs I've seen are 20% filled with this stuff.
2023-07-31 13:19:55 +03:00
Megamouse 365b264656 cellMsgDialogAbort: do not return CELL_MSGDIALOG_ERROR_DIALOG_NOT_OPENED 2023-07-31 13:19:55 +03:00
Eladash 1184d6aecb Thread.cpp: Fixup SPU access violation log message 2023-07-31 11:55:31 +03:00
Eladash b12edf70bb Optimize RSX Debugger 2023-07-31 11:55:31 +03:00
Elad Ashkenazi 53c1da8f94 Qt: Fix elf_memory_dumping_dialog PPU address 2023-07-31 08:53:10 +03:00
Elad Ashkenazi 213b810279 Debugger: Transition to plain text edit 2023-07-31 08:53:10 +03:00
Elad Ashkenazi 8a4617d3c2 Fix color tag of logs/tty 2023-07-31 08:53:10 +03:00
Megamouse c108b31954 Qt: fix data type of find_dialog text edits 2023-07-31 04:10:09 +03:00
Whatcookie fd6829f757 SPU LLVM: AVX-512 optimization for CFLTU (#14384)
- Takes advantage of vrangeps and the new float to uint instructions from AVX-512
- Down from 6 to 3 instructions

TODO: Somehow ensure that this is what llvm outputs using CreateFPToUI?
2023-07-29 09:01:01 +03:00
Talkashie dabb2cc9a0 Fix typos, improve consistency
Fixes typos where spelling or grammar is objectively wrong.
Changes wording and capitalization in some areas to be more consistent with other areas.
2023-07-28 13:09:06 +03:00
Whatcookie 4ecb06c901 SPU LLVM: Optimize common SFI+ROTQMBY pattern 2023-07-28 10:26:40 +03:00
Whatcookie 375bc4cc69 Utils: Add initial AVX10 support
- Adds detection for AVX10 features
- Also adds new bools for 256-wide AVX-512 instructions, indicated by either AVX-512 support, or AVX10
2023-07-28 06:55:20 +03:00
Elad Ashkenazi 9265ff53d0 Include spu.log inside RPCS3.log when SPU Debug is true 2023-07-27 19:15:32 +03:00
Eladash 75ad56338b SPU/Non-TSX: Implement cuncurrent reservations 2023-07-27 02:50:01 +03:00
Eladash db24ce7708 SPU/MFC: Format command more consistently 2023-07-27 02:50:01 +03:00
Eladash 2d45ecff22 cellSaveData: Adjust to non-TSX 2023-07-27 02:50:01 +03:00
Elad Ashkenazi 5d98f3866c Log TTY output after emulation have been stopped 2023-07-26 17:56:44 +03:00
Elad Ashkenazi 106f31db6a sceNpTrophy: Minor UB fixup
id.data[9] is char while isprint should accept u8.
2023-07-26 17:56:44 +03:00
brian218 9a5bdc9b4f sys_fs: Updated sys_fs_fcntl(0xc0000015&0xc000001c)'s error handling according to real hardware testing 2023-07-26 13:10:51 +03:00
brian218 0b829be798 sys_fs: Fixed up sys_fs_fcntl(0xc0000007) aka cellFsArcadeHddSerialNumber according to real hardware testing 2023-07-26 13:10:51 +03:00
Megamouse 94bb75fb7c sceNpTrophy: Check if a trophy configuration file exists before starting the install process 2023-07-25 22:00:19 +02:00
Eladash 7d84d0f83e sceNpTrophy: Initial commSign checking of CreateContext 2023-07-25 21:40:35 +03:00
oltolm bc40b61ef1 rename fs::stat to fs::get_stat 2023-07-25 12:15:08 +03:00
Megamouse 73c3d5fc81 Fix config path in Emu.Restart() 2023-07-25 11:12:16 +03:00
Megamouse 13575029c0 cellSaveData: add some more error logging 2023-07-25 11:12:16 +03:00
brian218 ea016382f2 Fixed Emu.Restart(graceful=false) no longer worked after #14038 2023-07-25 09:48:11 +03:00
Eladash 782344eed8 Debugger: Make break-all non-default 2023-07-24 17:07:15 +03:00
Eladash 95fb7859d2 Fixup patches 2023-07-24 17:07:15 +03:00
Eladash 9d3e626b55 Minor ppu_initialize fix 2023-07-24 17:07:15 +03:00
Eladash a6e8b9037a ppu: Make install function log message trace 2023-07-24 17:07:15 +03:00
brian218 c9f91ecee9 USIO: Added support for Tekken Tag Tournament 2 Live Monitor edition 2023-07-24 08:39:14 +02:00
oltolm 7cb2d3f143 opengl: fix Qt warnings (#14249) 2023-07-24 07:30:21 +03:00
brian218 a975b4937a USIO: Added support for Tekken Tag Tournament 2 2023-07-23 20:23:00 +02:00
Eladash fce8e0fef0 Savestates: Facilitate multi slots 2023-07-23 17:58:54 +03:00
Eladash 12fe55a258 Thread.cpp: Always print SPU thread name in access violation
Suppress GUI log window prefix removal.
2023-07-23 17:58:54 +03:00
Eladash 3bbc2c1f4c PPU Analyzer: Fixup get_ptr() 2023-07-23 17:58:54 +03:00
Eladash 99671b754f Add ppu_module::get_ref() to ease debugging 2023-07-23 17:58:54 +03:00
Eladash 9fc5f6271b Update SPU reservation notifier mask 2023-07-23 17:58:54 +03:00
Eladash 4647f3046e Qt: Minor logging change 2023-07-23 17:58:54 +03:00
Eladash c44cddabfa CPUThread.cpp: Fix use of cpu_counter::add
This also fixes a crash when saving savestate because main thread uses cpu_counter::suspend_all which adds cuncurrency.
2023-07-23 17:58:54 +03:00
Eladash 9ff91c29f2 Invalidate Savestates 2023-07-23 17:58:54 +03:00
Eladash e303cc536c Qt: Fix GetBootConfirmation() 2023-07-23 17:06:59 +03:00
Eladash afdfefc9ad Game List: Fix allowance of caches/games to be removed while the game is running! 2023-07-23 17:06:59 +03:00
Eladash 3033914e2d Game List: Implement Remove HDD1 Cache option 2023-07-23 17:06:59 +03:00
brian218 70b124cfa0 USIO: Fixed BACKUP MEMORY ERROR for some games (#14248) 2023-07-23 12:17:49 +03:00
Eladash 38a5313ed2 Fix log data loss on force application shutdown 2023-07-21 12:27:35 +03:00
Eladash 9291e2777d File.h: Implement fs::error::xdev 2023-07-21 12:27:35 +03:00
Eladash 465da5136d Qt: Fix saved log filename 2023-07-21 12:27:35 +03:00
Megamouse 568e7481d8 sys_fs: use path instead of u8path
Japanese PS3 games often use unicode paths which hard crash the std::filesystem::string() method.
wstring() would work in these cases, but I guess we can just use path() instead of u8path().
2023-07-20 07:22:07 +03:00
Darkhost1999 a0297933ce Create Missing Paths for Dev_USB/HDD0 and mms
In addiytion, fix 2 warnings.
2023-07-19 12:01:44 +03:00
Eladash 50dad6801b SPU LLVM: Use get_known_bits() in SHUFB 2023-07-18 22:27:45 +03:00
Malcolm Jestadt ee7475a9d4 SPU LLVM: Handle SHUFB special cases with a lookup table
- Needs 3 instructions to handle the special cases, since x86 lacks an 8 bit simd shift instruction
2023-07-18 22:27:45 +03:00
Elad Ashkenazi ba988f1d3f Qt: Exit And Save Log - toolbar action (#14212)
Fixup main_window::IsValidFile
2023-07-18 05:11:53 +03:00
Megamouse db029ed29f Fix default renderer when creating a brand new config 2023-07-17 09:35:26 +02:00
Elad Ashkenazi 41d38975f7 Savestates/sys_fs: Utilize fs::file::get_id to fix an old bug 2023-07-17 08:09:09 +03:00
Eladash eecadab387 Implement fs::file::get_id()
File descripor ID with 2 provided ways to compare between them:
1. is_mirror_of():
 Test if identical:
  For example: when LHS writes one byte to a file at X offset, RHS file be able to read that exact byte at X offset)

2. is_coherent_with():
 Test if both files point to the same file:
  For example: if a file descriptor pointing to the complete file exists and is being truncated to 0 bytes from non-
  -zero size state: this has to affect both RHS and LHS files.
2023-07-17 08:09:09 +03:00
Eladash e27e6c0b2d Implement PPU usleep control setting hack 2023-07-17 07:17:11 +03:00
Eladash 30a5d646ec Qt: Minor fixup 2023-07-16 20:16:20 +02:00
Eladash 882fb3e049 Qt: Cache drag-and-drop result when moving it 2023-07-16 19:49:55 +03:00
Eladash 0423781363 Qt: Restrict file types for drag-and-drop 2023-07-16 17:43:27 +03:00
Megamouse 43cfb3cd10 ecdsa: tiny optimization for key and curve 2023-07-16 09:32:39 +02:00
Megamouse de15c9746f ecdsa: clean up some code 2023-07-16 09:32:39 +02:00
Eladash 1371bf89e0 PPU LLVM: Allow to abort OVL analysis in the middle 2023-07-15 08:26:28 +03:00
Eladash 3b8f8d7fc8 PPU LLVM: Improve precompilation time 2023-07-15 08:26:28 +03:00
Megamouse a828c214b5 Qt/patches: highlight faulty lines in patch creator 2023-07-13 08:40:19 +02:00
Megamouse 3381144d2e Patches: improve location logging of some invalid nodes 2023-07-13 08:40:19 +02:00
Megamouse a19883f875 Patches: do not allow empty patch names 2023-07-13 08:40:19 +02:00
Megamouse 482722af0a Patches: fix logging for locations of node iterators 2023-07-13 08:40:19 +02:00
Megamouse 02bac61c9c Patches: validate yml patch offset values 2023-07-13 08:40:19 +02:00
Megamouse e8ee5831d3 Qt: add validator to patch creator offset lineedit 2023-07-13 08:40:19 +02:00
Eladash 083b4f0d3b Patches: Fix potential RPCS3 crashes due to invalid patches 2023-07-13 07:38:46 +03:00
Eladash c0280b43f2 PPU/Debugger: View the currently used CR field content in register panel 2023-07-12 13:22:06 +03:00
Megamouse d153e977a7 Qt: ignore Qt::Key_unknown when parsing key sequences 2023-07-12 09:35:43 +03:00
kd-11 eee7bf0c97 vk: Don't load depth-stencil textures on the transfer queue 2023-07-12 03:20:08 +03:00
oltolm 0c94606fcf Make compile with msvc, clang and gcc on Windows 2023-07-11 21:40:30 +03:00
nastys ed75bab7b2 macOS CI: add Homebrew and Qt caches 2023-07-11 19:55:36 +02:00
kd-11 bff6e0d277 rsx: Don't assert when surface and texture cache overlap lockable memory
- It's not a serious enough problem and the root cause is understood.
2023-07-11 04:09:30 +03:00
kd-11 c325017675 rsx: Preserve the texcoord transform around destructive modifications 2023-07-11 04:09:30 +03:00
Elad Ashkenazi 4b12c9a9fc Force inherit BDVD/PS3_GAME across game updates (#14159) 2023-07-11 00:30:02 +03:00
kd-11 0d57744efa rsx: Fix AMD shader codegen 2023-07-10 22:44:40 +03:00
Elad Ashkenazi e882d64d8a SPU/PPU Debugger: Add decimal mode to registers panel 2023-07-10 19:06:57 +03:00
Eladash 16f910e350 sys_fs: Fix log levels 2023-07-10 12:39:26 +03:00
Megamouse e2c2ef9788 Write config.yml if it doesn't exist or is empty on boot 2023-07-10 00:50:19 +02:00
kd-11 a98b4adead rsx: Fix projected coordinates calculation again 2023-07-09 19:33:48 +03:00
kd-11 186fe53279 rsx: Fix the default shadow codegen path 2023-07-09 19:33:48 +03:00
kd-11 c9917c826a Fix typo 2023-07-09 19:33:48 +03:00
kd-11 aedebecae2 rsx: Reimplement projected texturing 2023-07-09 19:33:48 +03:00
Eladash 482dd0e8f8 SPU: Remove wrong clamp in MFC_Size
Just crashes real MFC.
2023-07-09 13:33:03 +03:00
Eladash cae2e7de80 LV2: Log allocated guest VM addresses 2023-07-09 13:33:03 +03:00
Eladash e76ce05e29 logs: Add manual set log level with RegEx 2023-07-09 13:33:03 +03:00
Eladash a98174be85 Logs re-enable on Emu.Kill() fixup 2023-07-09 13:33:03 +03:00
Eladash b68cfbf794 Fix spu_thread::dump_callstack_list regression
TODO: Fix in PPU [properly!]
2023-07-09 13:33:03 +03:00
Eladash 17d8f2884e Debug fixes 2023-07-09 13:33:03 +03:00
Megamouse 050b8fa7df Qt: Use detailed text for install message 2023-07-08 20:11:01 +02:00
Megamouse c30c9b2168 Home menu: improve Anisotropic Filter Override value labels 2023-07-08 13:42:05 +02:00
Megamouse 358735a199 Home menu: add optional special label overrides 2023-07-08 13:42:05 +02:00
Megamouse d909bbc297 Home menu: set vblank step size to 30 2023-07-08 13:42:05 +02:00
Megamouse 2adb2f82d7 Home menu: move advanced video options to advanced menu 2023-07-08 13:42:05 +02:00
Michael G 5a013127ec build-mac: Enable Discord Rich Presence for Mac Users 2023-07-08 07:38:14 +03:00
Elad Ashkenazi 1219e5c244 SPU: Fix static interpreter requirement with interrupts
Removed a wrong condition in PPU LLVM as a fixup.
2023-07-07 22:39:49 +03:00
Megamouse 4aec48c2ca Only silence logging during gameplay 2023-07-07 18:28:34 +02:00
Eladash 8d54ddf426 memory viewer: Add RegEx instruction searching mode 2023-07-07 16:03:08 +03:00
Eladash c21cdb8055 Implement PPU LV2 debug 2023-07-07 16:03:08 +03:00
Eladash 05824e6acd UX: Option to pause emulation when RPCS3 is not focused 2023-07-07 14:38:32 +03:00
Ivan Chikish b3b680f073 [simd.hpp] Fix gv_fmafs 2023-07-07 11:09:55 +03:00
Eladash 598fe85243 PPU LLVM/RawSPU: Implement MMIO violation elimination pass 2023-07-06 19:46:36 +03:00
kd-11 e7ac84fca3 rsx: Fine-tune the subimage view bezel dimensions 2023-07-06 14:06:30 +03:00
kd-11 b9ea6be842 rsx: Fix AA factor calculation 2023-07-06 14:06:30 +03:00
kd-11 d46dbc0fa8 rsx: Fill section dimensions when converting atlas op to copy op 2023-07-06 14:06:30 +03:00
Michael G 0e10f12ec0 build-mac: Improve build time for macOS
Co-Authored-By: Megamouse <studienricky89@googlemail.com>
2023-07-06 07:49:06 +02:00
Sanjay Govind 8f178b2c29 sys_usbd: Implement support for Santroller devices 2023-07-05 23:54:37 +02:00
kd-11 d41fe80b8e Clamp MSAA sampling weights to avoid clipping 2023-07-05 02:51:04 +03:00
Megamouse 96e992bd26 CI: Ignore FAudio submodule in windows builds 2023-07-04 23:51:44 +02:00
kd-11 465c421707 rsx: Wrap MSAA coordinates before texelFetch 2023-07-04 23:41:12 +03:00
Elad Ashkenazi f7e9622084 vm_native.cpp: Workaround for rpcs3_vm_sparse.tmp crashes 2023-07-04 20:44:41 +02:00
kd-11 79e000f63d rsx: Fix virtual coordinate clamping 2023-07-04 09:31:51 +03:00
kd-11 10af0e8c93 vk: Disable anisotropy if the anisotropic level is meaningless 2023-07-04 09:31:51 +03:00
kd-11 d13cf0e29a rsx: Fix shader interpreter
- It broke ages ago
2023-07-04 09:31:51 +03:00
kd-11 1671922f7e rsx: Fix shader interpreter compilation 2023-07-04 09:31:51 +03:00
kd-11 c9da795bf3 rsx: Fix vp codegen when unrestricted depth range extension is absent 2023-07-04 09:31:51 +03:00
kd-11 69eb1401a9 vk/gl: Fix debug overlay stats 2023-07-04 09:31:51 +03:00
kd-11 aa06ac119f rsx: Fix sampled descriptor address corruption 2023-07-04 09:31:51 +03:00
kd-11 1afee59c95 rsx: Insert missing texture barrier 2023-07-04 09:31:51 +03:00
kd-11 4decad6f6b rsx: Force compatibility checks when applying fast-path optimizations 2023-07-04 09:31:51 +03:00
kd-11 a37f786a37 rsx: Properly fill in the cyclic ref field for framebuffer references 2023-07-04 09:31:51 +03:00
kd-11 8f98e572e1 rsx: Use designated initializer for the dangerous copy_region_descriptor type
- We need to move more dangerous braced initializations to c++20
- Also adds a base address variable which will come in handy
2023-07-04 09:31:51 +03:00
kd-11 c818f8af82 vk: Fix namespace pollution in sync module 2023-07-04 09:31:51 +03:00
kd-11 fac8bcc20c rsx: Formatting and tidying changes 2023-07-04 09:31:51 +03:00
kd-11 1d004f2788 rsx: Lower single-image-blit to a scaled coordinate fetch 2023-07-04 09:31:51 +03:00
kd-11 cef4ea786a rsx: Trivially detect single-image-blit transfer operations 2023-07-04 09:31:51 +03:00
kd-11 8ebf24d8e7 vk: Do not clear memory if we're going to overwrite it with a copy anyway 2023-07-04 09:31:51 +03:00
kd-11 69b02f7e46 rsx: Implement atlas trivialization pass
- Decompose sequences of copies into the minimally required set.
  This does 2 things:
  a. Reduces GPU workload by doing less transfers
  b. Allows the clipping optimization to kick in and skip a ton of GPU work
2023-07-04 09:31:51 +03:00
kd-11 b788e05396 rsx: Implement GPU copy ellision through coordinate transform
- TODO: Some corner cases still exist where format may not be a match after a cache merge.
2023-07-04 09:31:51 +03:00
kd-11 5dc4e74c98 rsx: Minor optimization to speed up texture state sync a bit given the larger structure in use now 2023-07-04 09:31:51 +03:00
kd-11 436ef1cff6 rsx: Fix shader compilation when texture ops are referenced 2023-07-04 09:31:51 +03:00
kd-11 d77a78cdf1 rsx: Rework texture coordinate handling to support clamping and a more sane scale-bias setup 2023-07-04 09:31:51 +03:00
kd-11 66cb855db0 rsx: Fix fragment program codegen 2023-07-04 09:31:51 +03:00
kd-11 fb3aa9628d rsx: Migrate vertex fetch out of the cpp file 2023-07-04 09:31:51 +03:00
kd-11 89c81d9f22 rsx: Switch common codegen to use the glsl scripts 2023-07-04 09:31:51 +03:00
kd-11 cffcfad42a rsx: Add the glsl files
- Generated from inline strings in GLSLCommon.cpp
2023-07-04 09:31:51 +03:00
Eladash 21f5976d35 cellSpurs: Implement ShutdownTaskset and WorkloadFlagReceiver2 2023-07-02 19:01:13 +03:00
Megamouse 21ada251fe Update dependencies 2023-07-02 07:59:25 +02:00
Megamouse 44801c50f3 Input: update buttons on pressure button toggle 2023-07-01 08:56:10 +02:00
Megamouse 6a1fb8cb73 Input: fix multibutton mousepress (sticks only) 2023-07-01 08:56:10 +02:00
Megamouse 8e8cefb3f6 Input: fix multibutton mousepress (buttons only) 2023-07-01 08:56:10 +02:00
Megamouse e0e4fa3b3e Input: Add tooltips for button mapping 2023-07-01 08:56:10 +02:00
Megamouse b9dbda5ddc Fix some warning 2023-07-01 08:56:10 +02:00
kd-11 931a2c516f vk/rsx: Fix build errors and warnings 2023-06-30 18:38:14 +03:00
kd-11 2f9e1cf4df vk: Get rid of some spammy debug code 2023-06-30 18:38:14 +03:00
kd-11 68d1c38f3b vk: Minor refactor to make early-exit branches trivial and easier to read 2023-06-30 18:38:14 +03:00
kd-11 c4acea6c82 vk: Fix some regressions in synchronization2 behavior 2023-06-30 18:38:14 +03:00
kd-11 7ebabddfe0 vk: Fix GPU hang 2023-06-30 18:38:14 +03:00
kd-11 a047ddffc0 vk: Restructure gpu labels and add them as an event backend 2023-06-30 18:38:14 +03:00
kd-11 92992a5406 vk: Use pipeline barriers for proper event sync 2023-06-30 18:38:14 +03:00
Eladash 593f850693 Qt: Save UI settings and geometry safely on closeEvent 2023-06-29 14:02:25 +02:00
Eladash f87db1ac14 System.cpp: Do not hold the watchdog forever for PPU LLVM compilation cancel
Protects against the case in which the LLVM workers deadlock themselves.
2023-06-29 12:12:56 +03:00
Eladash 363e498462 Remove overlay hack for PPU LLVM OVL precompilation 2023-06-29 12:12:56 +03:00
Eladash a03dd44924 Empty kill and init callback before calling them 2023-06-29 12:12:56 +03:00
Eladash 554b27a82a PPU LLVM: Implement SELF precompilation
Do not use PS3 memory for precompilation.
2023-06-28 18:34:33 +03:00
Eladash 7062ead4fd PPU LLVM: Precompile all disc game data including PRX etc
Even if there is no EBOOT.BIN.
2023-06-28 18:34:33 +03:00
Eladash 5f2f084091 Savestate/IDM: Do not save unsavable containers 2023-06-28 18:34:33 +03:00
Eladash a560121775 Fix Create PPU Cache 2023-06-28 18:34:33 +03:00
Dark b0a346709e RB3MidiGuitar.cpp: Support 5-Fret play
Rock Band 3 has support for playing the regular guitar mode with the
Pro Guitar. While the real MPA does not support this, the game accepts
it just fine so there's no harm in emulating it.
2023-06-27 20:11:10 +02:00
Megamouse 7b64cd2a8e input/overlays: add option to lock overlay input to player one 2023-06-27 19:36:05 +02:00
kd-11 9ecfecb83e Constify 2023-06-27 16:41:30 +03:00
kd-11 ec4565263d Dump extensions info to the log 2023-06-27 16:41:30 +03:00
kd-11 ed1da364e5 vk: Fix a bunch of corner cases when syncing GPU and host memory 2023-06-27 16:41:30 +03:00
kd-11 942dbbc8fa vk: Add explicit sync when doing copy_image_to_buffer 2023-06-27 16:41:30 +03:00
kd-11 3e8f9cbbf2 Add flags to handle sync domain with v2 events 2023-06-27 16:41:30 +03:00
kd-11 322b5dac79 Properly enable synchronization2 feature 2023-06-27 16:41:30 +03:00
kd-11 5a85fee3f1 Silence logspam about unused parameter 2023-06-27 16:41:30 +03:00
kd-11 ca472b6750 Silence log spam about copy ellision 2023-06-27 16:41:30 +03:00
Megamouse 8e3d0af08e Qt: remove obsolete shortcut 2023-06-26 21:23:48 +02:00
Megamouse 12f2b900ca Qt: use shortcut instead of hardcoded keypress event 2023-06-26 21:23:48 +02:00
Megamouse 6228dff809 welcome_dialog: remove weird window close event 2023-06-26 21:23:48 +02:00
Eladash d34b3190f7 Make stopping emulation not pause or crash UI
* Make the UI and main thread available when stopping emulation.
* Make BlockingCallFromMainThread always execute, preventing bugs when it unexpectedly did not.
* Add error code for when starting emulation when Emu.Kill() is in progress.
2023-06-26 20:48:38 +02:00
Eladash 4f5348c7d4 Fix properly RSX replay thread stop bug 2023-06-26 20:48:38 +02:00
Eladash aff871f127 about_dialog: Add new testers 2023-06-25 20:16:55 +03:00
Eladash 9f00359e17 Qt: Add RPCS3 Discord & Wiki to About Dialog 2023-06-25 20:16:55 +03:00
Eladash 0871436488 settings: Display rendering result of 100% resolution scale 2023-06-25 20:16:55 +03:00
Eladash 6aa598b029 Qt: Add Create RPCS3 shortcuts to Wecome Dialog 2023-06-25 20:16:55 +03:00
Eladash 83e22fa9f0 Qt: Make welcome dialog accessible through F1 or Help menu
Enable window close button after "I have read the Quickstart" is checked.
2023-06-25 20:16:55 +03:00
Eladash a230340578 Qt: Fix memory leak in welcome dialog 2023-06-25 20:16:55 +03:00
Eladash 2da78c6591 Qt: Allow to drop RAP&PKG together 2023-06-25 20:16:55 +03:00
Eladash 46350200d7 Qt: Always set QEvent::isAccepted is drag&drop events 2023-06-25 20:16:55 +03:00
Eladash 00502e94b5 Qt: Do not require to close games when adding new disc game directories 2023-06-25 20:16:55 +03:00
brian218 70ce7ee106 sys_fs: Fixed up one of sys_fs_unmount()'s error codes to match real system behavior 2023-06-25 09:08:20 +02:00
brian218 cf4ae38699 sys_fs: Implemented get_normalized_path() 2023-06-25 09:08:20 +02:00
Eladash 09f83e48ff fs: Add get_parent_dir_view
string view version of the argument path, use with care.
2023-06-24 12:00:04 +03:00
Eladash bcbce5dd48 File.cpp: revert get_parent_dir change 2023-06-24 12:00:04 +03:00
kd-11 0a0ef50caf Try to fix build 2023-06-23 15:21:17 +03:00
kd-11 e20f1587cd Workaround for old compilers
Xcode is not yet c++20 compliant
2023-06-23 15:21:17 +03:00
kd-11 715e3856f2 vk: Update async compute (fast) to use the new sync API 2023-06-22 14:59:58 +03:00
kd-11 850166eca1 vk: Reimplement events using synchronization2 extension 2023-06-22 14:59:58 +03:00
Eladash 00cca7be69 Utilities/Memory Viewer: Improve image viewer
* Added image scaling with Ctrl+Plus, Ctrl+Minus.
* Added hover position to see which address is being pointed at, when double clicking on it the image viewer is closed and the memory viewer jumps to the clicked memory data.
2023-06-21 22:28:52 +03:00
Eladash 0a43f69e87 Utilities/Memory Viewer: Add G8 and G32MAX image formats 2023-06-21 22:28:52 +03:00
Eladash c84d2d895e Utilities/Memory Viewer: Add PageDown/PageUp scrolling
* F5 for single refresh.
2023-06-21 22:28:52 +03:00
Eladash 87d5f45277 Utilities/Memory Viewer: Fix memory leak 2023-06-21 22:28:52 +03:00
Eladash 137f37cd41 Debugger/RSX: Add shortcut for RSX semaphores 2023-06-21 22:28:52 +03:00
Eladash 18722d7874 Utilities/Memory Viewer: Add auto-refresh mode 2023-06-21 22:28:52 +03:00
Eladash 307e1351df asm.hpp: Fix mul_saturate 2023-06-21 22:28:52 +03:00
Eladash 441fbd63bb Fix PPU debug setting with PPU interpreter 2023-06-20 18:18:24 +03:00
Eladash 073b723c09 Fix Create PPU Cache 2023-06-19 13:59:56 +03:00
unknown 37bc73865d jit: fix assertion in GDBJITRegistrationListener 2023-06-18 13:06:53 +03:00
RipleyTom e2bced978e Move connect workaround to connect interface 2023-06-18 01:04:01 +02:00
Megamouse a6d8c4343f Windows: silence uncritical performance counter error 2023-06-16 19:36:44 +02:00
kd-11 d5654d64d5 Nicer variable names 2023-06-16 15:29:36 +03:00
kd-11 06459eb37b vk: Latch query copy requests to reduce number of vulkan commands used 2023-06-16 15:29:36 +03:00
Megamouse d08fea551e progress dialog fix 2023-06-16 10:30:27 +02:00
Megamouse 924692bf1c Qt: use shift+click to append the button instead of replacing it 2023-06-15 22:39:30 +02:00
Megamouse ec9e8916b1 evdev: don't release buttons while other buttons are still pressed 2023-06-15 22:39:30 +02:00
Megamouse d3be8ee2b7 input: allow multiple key codes per button 2023-06-15 22:39:30 +02:00
Megamouse 16f869fe5a logging: minor trace optimizations 2023-06-15 19:48:15 +02:00
Megamouse a90858193e Qt/logging: add format function for QString 2023-06-15 19:48:15 +02:00
Ani 6dcf63009e Settings: Move Accurate SPU DMA to Advanced 2023-06-15 01:22:15 +02:00
Ani 5f8f86b5a7 Settings: Add Output Scaling to Home Menu 2023-06-15 01:22:15 +02:00
Ani a78117e094 Settings: Enable hot-reloading of Output Scaling 2023-06-15 01:22:15 +02:00
Ani 44421920b3 Settings: Reorder settings in Debug 2023-06-15 01:22:15 +02:00
Ani 0e79fbda05 Settings: Reorder settings in Emulator 2023-06-15 01:22:15 +02:00
Ani 9ab89c634b Settings: Move Automatically start games after boot to Debug 2023-06-15 01:22:15 +02:00
Ani 0a6f12f448 Settings: Rename to Force GPU Texture Scaling
Before the setting's name was Use GPU Texture Scaling
2023-06-15 01:22:15 +02:00
Ani 8612bdd03d Settings: Rename to Pause emulation after loading savestates
Before the setting's name was Start Savestates Paused
2023-06-15 01:22:15 +02:00
Ani f08d3e12ca Settings: Remove PPU Interpreter (dynamic)
It has been unimplemented for a long while, so no point in displaying
it, it can be added once the feature is implemented again
2023-06-15 01:22:15 +02:00
Ani deda47f461 Settings: Move Accurate GETLLAR to Advanced
Also includes some minor cleanup to move some code to their right blocks 
in settings_dialog and tooltips
2023-06-15 01:22:15 +02:00
Ani 2751f5e254 Settings: Move Accurate PPU Float Condition Control to Debug 2023-06-15 01:22:15 +02:00
Ani 2ac1ff1d0a Settings: Move Accurate PPU Vector NaN Handling to Debug 2023-06-15 01:22:15 +02:00
Ani 30e8c70055 Settings: Move Accurate PPU Non-Java Mode to Debug 2023-06-15 01:22:15 +02:00
Ani 62600b3be0 Settings: Move Accurate PPU Saturation Bit to Debug 2023-06-15 01:22:15 +02:00
Ani 57b9130cf7 Settings: Add Show PPU compilation hint 2023-06-15 01:22:15 +02:00
Ani b557a7fa16 Settings: Move Start Savestates Paused to Emulator
Under Emulator Settings groupbox, this is not really an Advanced setting 
thus it's more fitting on the Emulator tab
2023-06-15 01:22:15 +02:00
Ani 73e336adfa Settings: Move Disable Vertex Cache to Advanced
Under GPU group box, MTRSX now works with Vertex Cache so the use cases
for this settings are very reduced
2023-06-15 01:22:15 +02:00
Ani 86b27a3088 Settings: Remove Full Width AVX-512 from the UI
This is a very niche setting, so it can remain a config.yml setting only
2023-06-15 01:22:15 +02:00
Ani cce699a465 Settings: Enable Full Width AVX-512 by default
It is only known to cause performance hits in old Skylake-X AVX-512 CPUs 
as opposed to the other AVX-512 enabled CPUs, so it should be enabled as 
default
2023-06-15 01:22:15 +02:00
Megamouse d662a39a12 PPUAnalyser: fix std::move nonsense 2023-06-14 11:05:00 +03:00
kd-11 49c6c2c529 vk: Do not hard-sync on first sign of fragmentation
- It is very likely that the resource would be available if we just waited a while for the GPU queue to clear.
- Instead of also discarding the current work, first check if we can get by without a hard sync.
2023-06-14 01:12:11 +03:00
kd-11 29f3eec957 vk: On pool recovery, rescan the subpool table in case a new pool really cannot be created 2023-06-14 01:12:11 +03:00
kd-11 c1d875d841 vk: Handle VK_ERROR_FRAGMENTATION when allocating descriptor pools 2023-06-14 01:12:11 +03:00
Megamouse d28e3c4f08 np_handler: fix warning: check socket in discover_ip_address 2023-06-13 18:08:51 +02:00
Megamouse cedfb95f9b Loader: remove dead code 2023-06-12 19:35:15 +02:00
Elad Ashkenazi 59430ee83e Log Frame: Make clear act clear pending messages (#14004) 2023-06-12 18:46:09 +02:00
Megamouse b436d2a7f4 input: add controller index to SDL controllers 2023-06-12 18:05:34 +02:00
Megamouse 84d2ad70e6 input: add new buttons for Dualsense Edge 2023-06-12 17:29:14 +02:00
Megamouse 1bd9549e45 input: merge some duplicate code 2023-06-12 17:29:14 +02:00
Megamouse 2409a0d04e input: Add dualsense edge PID 2023-06-12 17:29:14 +02:00
Megamouse 635fed0427 fs/linux: fix potential copy_file issue
sendfile is meant to be run in a loop, since there is no guarantee that a single call copies all the data.
The current implementation may lead to corrupt files on linux.
2023-06-12 15:59:32 +03:00
RipleyTom 5d7e75c5d8 Fix EINVAL returned on connect call to connecting socket 2023-06-11 15:42:22 +02:00
Eladash c0e97b4e96 Qt: Improve PS3 Binaries Decryption tool 2023-06-11 00:40:14 +02:00
brian218 b2842dcd52 System.cpp: Updated the definition of user-space LV2 CoreOS SELFs 2023-06-10 17:59:02 +02:00
Jan Beich 112f1016ed CI: switch FreeBSD back to /latest after llvm16 re-appeared
This reverts commit 5e6aa45658.
2023-06-10 10:00:55 +02:00
Megamouse c78c504043 overlays: update progress dialog workaround 2023-06-10 09:09:55 +02:00
kd-11 27349c5c69 vk: Cleaner approach to object lifetime management 2023-06-10 02:54:16 +03:00
kd-11 872aa2b358 vk: Improved OOM handling
- Don't aggressively delete surfaces unless we're really crashing
- Release barrier resources before destroying the surface in case of fatal crash
2023-06-10 02:54:16 +03:00
kd-11 72abc0f219 rsx: Minor annotations and refactoring 2023-06-10 01:36:10 +03:00
kd-11 4d565eade6 rsx: Drop format information from the vertex cache and use a simpler model that is much faster 2023-06-10 01:36:10 +03:00
kd-11 2df7e46cb1 rsx: Import robin-hood unordered map which is much faster than std 2023-06-10 01:36:10 +03:00
kd-11 105205312b rsx: Rewrite the find method to avoid unnecessary allocations 2023-06-10 01:36:10 +03:00
kd-11 97f7461aa9 rsx: Allow the vertex cache to be enabled independently of MTRSX 2023-06-10 01:36:10 +03:00
kd-11 7e2eaf43ca rsx: Capture stats about vertex cache performance 2023-06-10 01:36:10 +03:00
Eladash d752ab0151 SPU/Debugger: Add RawSPU debug data 2023-06-09 14:07:37 +03:00
Eladash c87a7cb2c0 PPU: Fix thread entry detection false positives 2023-06-09 14:07:37 +03:00
Megamouse 6aff2803e5 cellMsgDialog: Fix segfault when closing non-blocking Qt dialogs 2023-06-09 02:03:44 +02:00
Megamouse fcfca6efda Qt: add ability to style richtext href links 2023-06-08 22:58:55 +02:00
Megamouse 0ebe832f8e input: fix some warnings 2023-06-08 22:58:55 +02:00
Megamouse 86ed82dcec PSF: improve load readability 2023-06-08 21:15:39 +02:00
Megamouse 769b69999f fix whitespace 2023-06-08 21:15:39 +02:00
Megamouse 91ee066751 Qt: do not set play/pause button texts to 'Resume' on emu stop or ready
Since the states now always seem to match, this makes no sense anymore
2023-06-08 21:15:39 +02:00
Megamouse 404d08ef6d Qt: always use last boot path for game boot actions
The actual path caused the GUI to try to run elfs directly after booting a game from a loader.
2023-06-08 21:15:39 +02:00
Megamouse 11487cd591 System: fix config path in restore_on_no_boot 2023-06-08 21:15:39 +02:00
Megamouse 51a30977d2 System: use const ref for libs map 2023-06-08 21:15:39 +02:00
Megamouse c0366ba40c Qt: fix start/restart shortcut 2023-06-08 21:15:39 +02:00
Megamouse 3f5bc3464d Rename ProcureCurrentEmulationCourseInformation to GetEmulationIdentifier
This is much easier to understand in my opinion.
The old name just made me scratch my head whenever I read it.
2023-06-08 21:15:39 +02:00
Megamouse fcd6be71b0 debugger_frame: don't query cpu thread if emulation is stopped anyway 2023-06-08 21:15:39 +02:00
brian218 ad22cf5051 unself.cpp: Always reset the old SELF header information before loading 2023-06-08 18:18:57 +02:00
Megamouse 8f66c50721 input: add pressure intensity toggle mode 2023-06-08 16:41:44 +02:00
kd-11 6f834e99d2 vk: Disable conditional rendering on MacOS 2023-06-06 22:05:54 +03:00
kd-11 86c7b31b6d Force disable conditional render on macOS 2023-06-06 22:05:54 +03:00
Eladash 6d918b565f PPU: Sleep after returning from thread entry function 2023-06-06 17:53:09 +02:00
Eladash 52575a44b2 sys_ppu_thread: Optimize joined thread notification 2023-06-06 17:53:09 +02:00
Eladash d5eebd6ab4 debugger: Fix trailing spaces in PPU register dump 2023-06-06 09:48:27 +02:00
Eladash 3f44ecb77a register_editor_dialog: Improve selection 2023-06-06 09:48:27 +02:00
Eladash 9bd4426225 Fix _sys_interrupt_thread_disestablish with lingering thread copies 2023-06-06 09:48:27 +02:00
Eladash 4af0a33f1f Fix sys_ppu_thread_detach/exit with lingering thread copies 2023-06-06 09:48:27 +02:00
Eladash 636bde6343 Logs: Fix trailing space, nbsp and unintended character 2023-06-06 09:48:27 +02:00
Eladash 16579e0b1f Fix spu_thread::cleanup() 2023-06-06 09:48:27 +02:00
Megamouse 292d3faa9e input: fix pad profile override with existing custom pad configs 2023-06-06 08:09:31 +02:00
Megamouse 6d2f7f6e54 sys_fs: fix map entry removal in destructor 2023-06-05 23:14:12 +02:00
brian218 a131a41874 Fixed a bug in fs::get_parent_dir() 2023-06-05 20:15:43 +02:00
brian218 48ffc19193 Update sys_usbd.cpp 2023-06-05 20:15:43 +02:00
Eladash e75c0dbaa1 debugger(CallStack): Make Return act as double click 2023-06-05 17:39:52 +03:00
Eladash 0c0f63a2a8 debugger: Fix potential null dereference 2023-06-05 17:39:52 +03:00
Eladash c9942aa828 debugger: Fix key events when CallStack is focused 2023-06-05 17:39:52 +03:00
Eladash ca56f0747e debugger: Avoid incorrect update timer restart 2023-06-05 17:39:52 +03:00
Eladash e77c01d00a debugger: Fix use of invalid pointers 2023-06-05 17:39:52 +03:00
brian218 c85775922e sys_usbd: Implemented sys_usbd_unregister_extra_ldd() 2023-06-05 13:51:54 +03:00
brian218 da0c9c2ce9 sys_usbd: USB VID/PID logging format fixup 2023-06-05 13:51:54 +03:00
brian218 42b388317e sys_ss: Further implemented Update Manager service for VSH 2023-06-05 13:51:54 +03:00
brian218 6a570ae57e sys_fs: Implemented sys_fs_mount(prot=1) read-only mounting & fixed up some operation and permission checks 2023-06-05 13:51:54 +03:00
Jan Beich 5e6aa45658 CI: temporarily switch FreeBSD to /quarterly packages
llvm16 failed to build on /latest, so the package is missing atm.
As builds are automatic this will resolve itself in a few days.
2023-06-04 23:11:24 +02:00
Jan Beich 5fa8af1c9a CI: upgrade FreeBSD to 13.2
FreeBSD doesn't support /latest and /quarterly package repos on EOL
versions. 13.1 reaches EOL on 2023-07-31, so avoid CI breakage.
2023-06-04 23:11:24 +02:00
Elad Ashkenazi 2e4bf9ef1b Update sys_timer.cpp 2023-06-04 01:26:24 +02:00
Elad Ashkenazi ba9f55679d Update sys_timer.cpp 2023-06-04 01:26:24 +02:00
Elad Ashkenazi 2c999a550b Update sys_mutex.h 2023-06-04 01:26:24 +02:00
Elad Ashkenazi 805de248d3 Update sys_lwmutex.h 2023-06-04 01:26:24 +02:00
Elad Ashkenazi 1240874e41 Update sys_lwmutex.h 2023-06-04 01:26:24 +02:00
Elad Ashkenazi feff50e7e0 Update sys_mutex.h 2023-06-04 01:26:24 +02:00
369 changed files with 14055 additions and 10380 deletions
-5
View File
@@ -1,10 +1,5 @@
#!/bin/sh -ex
# Setup Qt variables
export QT_BASE_DIR=/opt/qt"${QTVERMIN}"
export PATH="$QT_BASE_DIR"/bin:"$PATH"
export LD_LIBRARY_PATH="$QT_BASE_DIR"/lib/x86_64-linux-gnu:"$QT_BASE_DIR"/lib
if [ -z "$CIRRUS_CI" ]; then
cd rpcs3 || exit 1
fi
+55 -19
View File
@@ -1,13 +1,17 @@
#!/bin/sh -ex
export HOMEBREW_NO_AUTO_UPDATE=1
brew install -f --overwrite nasm ninja git p7zip create-dmg ccache pipenv
#/usr/sbin/softwareupdate --install-rosetta --agree-to-license
arch -x86_64 /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
arch -x86_64 /usr/local/homebrew/bin/brew update
arch -x86_64 /usr/local/homebrew/bin/brew install -f --overwrite llvm@16 sdl2 glew cmake
arch -x86_64 /usr/local/homebrew/bin/brew link -f llvm@16
arch -x86_64 /usr/local/bin/brew update
arch -x86_64 /usr/local/bin/brew install -f --overwrite llvm@16 sdl2 glew cmake faudio vulkan-headers
arch -x86_64 /usr/local/bin/brew link -f llvm@16
# moltenvk based on commit for 1.2.4 release
wget https://raw.githubusercontent.com/Homebrew/homebrew-core/b233d4f9f40f26d81da11140defbfd578cfe4a69/Formula/molten-vk.rb
arch -x86_64 /usr/local/bin/brew install -f --overwrite ./molten-vk.rb
#export MACOSX_DEPLOYMENT_TARGET=12.0
export CXX=clang++
export CC=clang
@@ -15,7 +19,7 @@ export CC=clang
export BREW_PATH;
BREW_PATH="$(brew --prefix)"
export BREW_X64_PATH;
BREW_X64_PATH="$("/usr/local/homebrew/bin/brew" --prefix)"
BREW_X64_PATH="$("/usr/local/bin/brew" --prefix)"
export BREW_BIN="/usr/local/bin"
export BREW_SBIN="/usr/local/sbin"
export CMAKE_EXTRA_OPTS='-DLLVM_TARGETS_TO_BUILD=X86'
@@ -24,23 +28,39 @@ export WORKDIR;
WORKDIR="$(pwd)"
# Get Qt
git clone https://github.com/engnr/qt-downloader.git
cd qt-downloader
git checkout f52efee0f18668c6d6de2dec0234b8c4bc54c597
"/opt/homebrew/bin/pipenv" run pip3 install py7zr requests semantic_version lxml
"/opt/homebrew/bin/pipenv" run ./qt-downloader macos desktop 5.15.2 clang_64 --opensource
cd ..
if [ ! -d "/tmp/Qt/$QT_VER" ]; then
mkdir -p "/tmp/Qt"
git clone https://github.com/engnr/qt-downloader.git
cd qt-downloader
git checkout f52efee0f18668c6d6de2dec0234b8c4bc54c597
cd "/tmp/Qt"
"/opt/homebrew/bin/pipenv" run pip3 install py7zr requests semantic_version lxml
mkdir -p "$QT_VER/macos" ; ln -s "macos" "$QT_VER/clang_64"
"/opt/homebrew/bin/pipenv" run "$WORKDIR/qt-downloader/qt-downloader" macos desktop "$QT_VER" clang_64 --opensource --addons qtmultimedia
fi
export Qt5_DIR="$WORKDIR/qt-downloader/5.15.2/clang_64/lib/cmake/Qt5"
cd "$WORKDIR"
ditto "/tmp/Qt/$QT_VER" "qt-downloader/$QT_VER"
export Qt6_DIR="$WORKDIR/qt-downloader/$QT_VER/clang_64/lib/cmake/Qt$QT_VER_MAIN"
export SDL2_DIR="$BREW_X64_PATH/opt/sdl2/lib/cmake/SDL2"
export PATH="$BREW_X64_PATH/opt/llvm@16/bin:$WORKDIR/qt-downloader/5.15.2/clang_64/bin:$BREW_BIN:$BREW_SBIN:/usr/bin:/bin:/usr/sbin:/sbin:/opt/X11/bin:/Library/Apple/usr/bin:$PATH"
export PATH="$BREW_X64_PATH/opt/llvm@16/bin:$WORKDIR/qt-downloader/$QT_VER/clang_64/bin:$BREW_BIN:$BREW_SBIN:/usr/bin:/bin:/usr/sbin:/sbin:/opt/X11/bin:/Library/Apple/usr/bin:$PATH"
export LDFLAGS="-L$BREW_X64_PATH/lib -Wl,-rpath,$BREW_X64_PATH/lib"
export CPPFLAGS="-I$BREW_X64_PATH/include -msse -msse2 -mcx16 -no-pie"
export LIBRARY_PATH="$BREW_X64_PATH/lib"
export LD_LIBRARY_PATH="$BREW_X64_PATH/lib"
git submodule update --init --recursive --depth 1
export VULKAN_SDK
VULKAN_SDK="$BREW_X64_PATH/opt/molten-vk"
ln -s "$VULKAN_SDK/lib/libMoltenVK.dylib" "$VULKAN_SDK/lib/libvulkan.dylib"
export VK_ICD_FILENAMES="$VULKAN_SDK/share/vulkan/icd.d/MoltenVK_icd.json"
export LLVM_DIR
LLVM_DIR="BREW_X64_PATH/opt/llvm@16"
# exclude FAudio, SPIRV and LLVM, and sdl from submodule update
# shellcheck disable=SC2046
git submodule -q update --init --depth=1 --jobs=8 $(awk '/path/ && !/FAudio/ && !/llvm/ && !/SPIRV/ && !/SDL/ { print $3 }' .gitmodules)
# 3rdparty fixes
sed -i '' "s/extern const double NSAppKitVersionNumber;/const double NSAppKitVersionNumber = 1343;/g" 3rdparty/hidapi/hidapi/mac/hid.c
@@ -48,14 +68,30 @@ sed -i '' "s/extern const double NSAppKitVersionNumber;/const double NSAppKitVer
mkdir build && cd build || exit 1
"$BREW_X64_PATH/bin/cmake" .. \
-DUSE_SDL=ON -DUSE_DISCORD_RPC=OFF -DUSE_VULKAN=ON -DUSE_ALSA=OFF -DUSE_PULSE=OFF -DUSE_AUDIOUNIT=ON \
-DLLVM_CCACHE_BUILD=OFF -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 -DLLVM_USE_PERF=OFF -DLLVM_ENABLE_Z3_SOLVER=OFF \
-DUSE_SDL=ON \
-DUSE_DISCORD_RPC=ON \
-DUSE_VULKAN=ON \
-DUSE_ALSA=OFF \
-DUSE_PULSE=OFF \
-DUSE_AUDIOUNIT=ON \
-DLLVM_CCACHE_BUILD=OFF \
-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 \
-DLLVM_USE_PERF=OFF \
-DLLVM_ENABLE_Z3_SOLVER=OFF \
-DUSE_NATIVE_INSTRUCTIONS=OFF \
-DUSE_SYSTEM_MVK=OFF \
-DUSE_SYSTEM_MVK=ON \
-DUSE_SYSTEM_FAUDIO=ON \
-DUSE_SYSTEM_SDL=ON \
$CMAKE_EXTRA_OPTS \
-DLLVM_TARGET_ARCH=X86_64 -DCMAKE_OSX_ARCHITECTURES=x86_64 -DCMAKE_IGNORE_PATH="$BREW_PATH/lib" \
-DLLVM_TARGET_ARCH=X86_64 \
-DCMAKE_OSX_ARCHITECTURES=x86_64 \
-DCMAKE_IGNORE_PATH="$BREW_PATH/lib" \
-G Ninja
"$BREW_PATH/bin/ninja"; build_status=$?;
+1 -1
View File
@@ -15,7 +15,7 @@ echo "AVVER=$AVVER" >> ../.ci/ci-vars.env
cd bin
mkdir "rpcs3.app/Contents/lib/"
cp "/usr/local/Homebrew/opt/llvm@16/lib/c++/libc++abi.1.0.dylib" "rpcs3.app/Contents/lib/libc++abi.1.dylib"
cp "/usr/local/opt/llvm@16/lib/c++/libc++abi.1.0.dylib" "rpcs3.app/Contents/lib/libc++abi.1.dylib"
rm -rf "rpcs3.app/Contents/Frameworks/QtPdf.framework" \
"rpcs3.app/Contents/Frameworks/QtQml.framework" \
+4 -4
View File
@@ -2,7 +2,7 @@
# NOTE: this script is run under root permissions
# shellcheck shell=sh disable=SC2096
# RPCS3 often needs recent Qt5 and Vulkan-Headers
# RPCS3 often needs recent Qt and Vulkan-Headers
sed -i '' 's/quarterly/latest/' /etc/pkg/FreeBSD.conf
export ASSUME_ALWAYS_YES=true
@@ -11,8 +11,8 @@ pkg info # debug
# Prefer newer Clang than in base system (see also .ci/build-freebsd.sh)
pkg install llvm16
# 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 qt5-multimedia qt5-svg glew openal-soft ffmpeg
# Mandatory dependencies (qt6-base and qt6-svg are pulled via qt6-multimedia)
pkg install git ccache cmake ninja qt6-multimedia glew openal-soft ffmpeg
# Optional dependencies (libevdev is pulled by qt5-gui)
# Optional dependencies (libevdev is pulled by qt6-base)
pkg install pkgconf alsa-lib pulseaudio sdl2 evdev-proto vulkan-headers vulkan-loader
+11 -10
View File
@@ -11,25 +11,26 @@ PR_NUMBER="$SYSTEM_PULLREQUEST_PULLREQUESTID"
QT_HOST="http://qt.mirror.constant.com/"
QT_URL_VER=$(echo "$QT_VER" | sed "s/\.//g")
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}"
QT_MM_URL="${QT_HOST}${QT_PREFIX}qtmultimedia${QT_SUFFIX}"
QT_SVG_URL="${QT_HOST}${QT_PREFIX}qtsvg${QT_SUFFIX}"
QT_PREFIX="online/qtsdkrepository/windows_x86/desktop/qt${QT_VER_MAIN}_${QT_URL_VER}/qt.qt${QT_VER_MAIN}.${QT_URL_VER}."
QT_PREFIX_2="win64_${QT_VER_MSVC}_64/${QT_VER}-0-${QT_DATE}"
QT_SUFFIX="-Windows-Windows_10_22H2-${QT_VER_MSVC_UP}-Windows-Windows_10_22H2-X86_64.7z"
QT_BASE_URL="${QT_HOST}${QT_PREFIX}${QT_PREFIX_2}qtbase${QT_SUFFIX}"
QT_DECL_URL="${QT_HOST}${QT_PREFIX}${QT_PREFIX_2}qtdeclarative${QT_SUFFIX}"
QT_TOOL_URL="${QT_HOST}${QT_PREFIX}${QT_PREFIX_2}qttools${QT_SUFFIX}"
QT_MM_URL="${QT_HOST}${QT_PREFIX}addons.qtmultimedia.${QT_PREFIX_2}qtmultimedia${QT_SUFFIX}"
QT_SVG_URL="${QT_HOST}${QT_PREFIX}${QT_PREFIX_2}qtsvg${QT_SUFFIX}"
QT_5CMP_URL="${QT_HOST}${QT_PREFIX}qt5compat.${QT_PREFIX_2}qt5compat${QT_SUFFIX}"
LLVMLIBS_URL='https://github.com/RPCS3/llvm-mirror/releases/download/custom-build-win-16.0.1/llvmlibs_mt.7z'
GLSLANG_URL='https://github.com/RPCS3/glslang/releases/download/custom-build-win/glslanglibs_mt.7z'
VULKAN_SDK_URL="https://www.dropbox.com/s/cs77c3iv5mbo0bt/VulkanSDK-${VULKAN_VER}-Installer.exe"
DEP_URLS=" \
$QT_BASE_URL \
$QT_WINE_URL \
$QT_DECL_URL \
$QT_TOOL_URL \
$QT_MM_URL \
$QT_SVG_URL \
$QT_5CMP_URL \
$LLVMLIBS_URL \
$GLSLANG_URL \
$VULKAN_SDK_URL"
@@ -40,7 +41,7 @@ DEP_URLS=" \
# Pull all the submodules except llvm, since it is built separately and we just download that build
# Note: Tried to use git submodule status, but it takes over 20 seconds
# shellcheck disable=SC2046
git submodule -q update --init --depth=1 --jobs=8 $(awk '/path/ && !/llvm/ && !/SPIRV/ { print $3 }' .gitmodules)
git submodule -q update --init --depth=1 --jobs=8 $(awk '/path/ && !/FAudio/ && !/llvm/ && !/SPIRV/ { print $3 }' .gitmodules)
# Git bash doesn't have rev, so here it is
rev()
+10 -6
View File
@@ -6,6 +6,8 @@ env:
BUILD_SOURCEVERSION: $CIRRUS_CHANGE_IN_REPO
BUILD_SOURCEBRANCHNAME: $CIRRUS_BRANCH
RPCS3_TOKEN: ENCRYPTED[!a4c3850e29ab150692286a74bec29819d25971a7ec431b86de2a35f7ed90c5b2ab3c93469f9298e30924d843599110e9!]
QT_VER_MAIN: '6'
QT_VER: '6.5.2'
windows_task:
matrix:
@@ -17,11 +19,9 @@ windows_task:
env:
CIRRUS_SHELL: "bash"
COMPILER: msvc
QT_VER_MAIN: '5'
BUILD_ARTIFACTSTAGINGDIRECTORY: ${CIRRUS_WORKING_DIR}\artifacts\
QT_VER: '5.15.2'
QT_VER_MSVC: 'msvc2019'
QT_DATE: '202011130602'
QT_DATE: '202307080351'
QTDIR: C:\Qt\${QT_VER}\${QT_VER_MSVC}_64
VULKAN_VER: '1.3.224.1'
VULKAN_SDK_SHA: '2029e652e39ee6a6036cff3765da31e1e6c595fd2413d3cd111dfab7855621ea'
@@ -61,7 +61,7 @@ windows_task:
linux_task:
container:
image: rpcs3/rpcs3-ci-bionic:1.8
image: rpcs3/rpcs3-ci-focal:1.0
cpu: 4
memory: 16G
env:
@@ -108,7 +108,7 @@ freebsd_task:
matrix:
- name: Cirrus FreeBSD
freebsd_instance:
image_family: freebsd-13-1
image_family: freebsd-13-2
cpu: 8
memory: 8G
env:
@@ -121,12 +121,16 @@ freebsd_task:
macos_task:
timeout_in: 12000m
homebrew_cache:
folder: /Users/admin/Library/Caches/Homebrew
qt_cache:
folder: /tmp/Qt
ccache_cache:
folder: /tmp/ccache_dir
matrix:
- name: Cirrus macOS
macos_instance:
image: ghcr.io/cirruslabs/macos-monterey-xcode:14
image: ghcr.io/cirruslabs/macos-monterey-xcode:latest
mac_script:
- mkdir artifacts
- chmod +x ".ci/build-mac.sh"
+5
View File
@@ -31,6 +31,7 @@
*.wav
/build
/build-*
/lib
/tmp
/ipch
@@ -135,3 +136,7 @@ yaml-cpp.pc
cacert.pem
_ReSharper.*/
CMakeUserPresets.json
.cache/
.lldbinit
+36 -38
View File
@@ -4,6 +4,11 @@ include(CMakeDependentOption)
set(CMAKE_CXX_STANDARD 20)
# Warnings are silenced for 3rdparty code
if(NOT MSVC)
add_compile_options("$<$<COMPILE_LANGUAGE:CXX,C>:-w>")
endif()
# Dummy target to use when lib isn't available
add_library(3rdparty_dummy_lib INTERFACE)
@@ -42,16 +47,16 @@ endif()
# libusb
if(CMAKE_SYSTEM MATCHES "DragonFly|FreeBSD")
if(CMAKE_SYSTEM_NAME MATCHES "DragonFly|FreeBSD")
pkg_check_modules(LIBUSB REQUIRED IMPORTED_TARGET libusb-1.0>=1.0 )
CMAKE_DEPENDENT_OPTION( USE_SYSTEM_LIBUSB "Use system libusb-1.0 as shared library" ON
cmake_dependent_option(USE_SYSTEM_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_SYSTEM_LIBUSB "Use system libusb-1.0 as shared library" OFF
cmake_dependent_option(USE_SYSTEM_LIBUSB "Use system libusb-1.0 as shared library" OFF
"LIBUSB_FOUND" OFF)
endif()
if(CMAKE_SYSTEM MATCHES "DragonFly|FreeBSD")
if(CMAKE_SYSTEM_NAME 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)
@@ -100,10 +105,6 @@ endif()
# OpenGL
# Prefer GLVND for OpenGL rather than legacy, unless it's been defined elsewhere, in the case of AppImage builds
if(NOT DEFINED OpenGL_GL_PREFERENCE)
set(OpenGL_GL_PREFERENCE GLVND)
endif()
find_package(OpenGL REQUIRED)
add_library(3rdparty_opengl INTERFACE)
@@ -111,17 +112,14 @@ target_include_directories(3rdparty_opengl INTERFACE GL)
if (WIN32)
if(NOT MSVC)
target_link_libraries(3rdparty_opengl INTERFACE ${OPENGL_LIBRARIES} opengl32.lib glu32.lib)
target_link_libraries(3rdparty_opengl INTERFACE OpenGL::GL OpenGL::GLU)
else()
target_link_libraries(3rdparty_opengl INTERFACE dxgi.lib d2d1.lib dwrite.lib)
endif()
elseif(APPLE)
target_link_libraries(3rdparty_opengl INTERFACE OpenGL::GL OpenGL::GLU)
else()
target_link_libraries(3rdparty_opengl INTERFACE ${OPENGL_LIBRARIES})
target_compile_definitions(3rdparty_opengl
INTERFACE
-DGL_GLEXT_PROTOTYPES
-DGLX_GLXEXT_PROTOTYPES)
target_link_libraries(3rdparty_opengl INTERFACE OpenGL::GL OpenGL::GLU OpenGL::GLX)
endif()
@@ -160,9 +158,9 @@ set(VULKAN_TARGET 3rdparty_dummy_lib)
if(USE_VULKAN)
if(APPLE)
if(USE_SYSTEM_MVK)
message("-- RPCS3: Using system MoltenVK")
message(STATUS "RPCS3: Using system MoltenVK")
else()
message("-- RPCS3: MoltenVK submodule")
message(STATUS "RPCS3: MoltenVK submodule")
execute_process(COMMAND "${CMAKE_COMMAND}" -G "${CMAKE_GENERATOR}" .
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/MoltenVK"
@@ -204,9 +202,9 @@ if(USE_VULKAN)
set(VULKAN_TARGET 3rdparty_vulkan)
else()
message("WARNING! USE_VULKAN was enabled, but libvulkan was not found. RPCS3 will be compiled without Vulkan support.")
message(WARNING "USE_VULKAN was enabled, but libvulkan was not found. RPCS3 will be compiled without Vulkan support.")
if(APPLE)
message( FATAL_ERROR "ERROR! To build without Vulkan support on macOS, please disable USE_VULKAN.")
message(FATAL_ERROR "To build without Vulkan support on macOS, please disable USE_VULKAN.")
endif()
endif()
endif()
@@ -225,7 +223,7 @@ if(USE_FAUDIO)
if (USE_SYSTEM_FAUDIO)
if (NOT SDL2_FOUND OR SDL2_VERSION VERSION_LESS 2.0.12)
message(WARNING
"-- RPCS3: System FAudio requires SDL 2.0.9 or newer. Please note, this warning"
"RPCS3: FAudio requires SDL 2.0.9 or newer. Please note, this warning"
"can also be displayed with SDL2 versions between 2.0.9-2.0.12, as the"
"CMake config files are not correctly installed. Since a valid SDL2"
">=2.0.9 version cannot be found, building with FAudio will be skipped.")
@@ -262,36 +260,36 @@ add_library(3rdparty_ffmpeg INTERFACE)
# Select the version of ffmpeg to use, default is builtin
if(USE_SYSTEM_FFMPEG)
message("-- RPCS3: using shared ffmpeg")
message(STATUS "RPCS3: using shared ffmpeg")
find_package(FFMPEG REQUIRED)
target_include_directories(3rdparty_ffmpeg INTERFACE ${FFMPEG_INCLUDE_DIR})
target_link_libraries(3rdparty_ffmpeg INTERFACE ${FFMPEG_LIBRARIES})
else()
if (NOT MSVC AND WIN32)
message("-- RPCS3: building ffmpeg submodule")
message(STATUS "RPCS3: building ffmpeg submodule")
include(ProcessorCount)
ProcessorCount(N)
ExternalProject_Add(ffmpeg-mingw
DOWNLOAD_COMMAND ""
SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/ffmpeg
BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/ffmpeg
CONFIGURE_COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/ffmpeg/configure --prefix=./windows/x86_64 --arch=x86_64 --disable-avdevice --disable-programs --disable-avfilter --disable-postproc --disable-doc --disable-pthreads --enable-w32threads --disable-network --disable-everything --disable-encoders --disable-muxers --disable-hwaccels --disable-parsers --disable-protocols --enable-dxva2 --enable-static --disable-shared --enable-decoder=aac --enable-decoder=aac_latm --enable-decoder=atrac3 --enable-decoder=atrac3p --enable-decoder=mp3 --enable-decoder=pcm_s16le --enable-decoder=pcm_s8 --enable-decoder=h264 --enable-decoder=mpeg4 --enable-decoder=mpeg2video --enable-decoder=mjpeg --enable-decoder=mjpegb --enable-encoder=pcm_s16le --enable-encoder=ffv1 --enable-encoder=mpeg4 --enable-parser=h264 --enable-parser=mpeg4video --enable-parser=mpegaudio --enable-parser=mpegvideo --enable-parser=mjpeg --enable-parser=aac --enable-parser=aac_latm --enable-muxer=avi --enable-demuxer=h264 --enable-demuxer=m4v --enable-demuxer=mp3 --enable-demuxer=mpegvideo --enable-demuxer=mpegps --enable-demuxer=mjpeg --enable-demuxer=avi --enable-demuxer=aac --enable-demuxer=pmp --enable-demuxer=oma --enable-demuxer=pcm_s16le --enable-demuxer=pcm_s8 --enable-demuxer=wav --enable-hwaccel=h264_dxva2 --enable-indev=dshow --enable-protocol=file
BUILD_COMMAND make -j 4
CONFIGURE_COMMAND bash ${CMAKE_CURRENT_SOURCE_DIR}/ffmpeg/configure --prefix=./windows/x86_64 --arch=x86_64 --disable-avdevice --disable-programs --disable-avfilter --disable-postproc --disable-doc --disable-pthreads --enable-w32threads --disable-network --disable-everything --disable-encoders --disable-muxers --disable-hwaccels --disable-parsers --disable-protocols --enable-dxva2 --enable-static --disable-shared --enable-decoder=aac --enable-decoder=aac_latm --enable-decoder=atrac3 --enable-decoder=atrac3p --enable-decoder=mp3 --enable-decoder=pcm_s16le --enable-decoder=pcm_s8 --enable-decoder=h264 --enable-decoder=mpeg4 --enable-decoder=mpeg2video --enable-decoder=mjpeg --enable-decoder=mjpegb --enable-encoder=pcm_s16le --enable-encoder=ffv1 --enable-encoder=mpeg4 --enable-parser=h264 --enable-parser=mpeg4video --enable-parser=mpegaudio --enable-parser=mpegvideo --enable-parser=mjpeg --enable-parser=aac --enable-parser=aac_latm --enable-muxer=avi --enable-demuxer=h264 --enable-demuxer=m4v --enable-demuxer=mp3 --enable-demuxer=mpegvideo --enable-demuxer=mpegps --enable-demuxer=mjpeg --enable-demuxer=avi --enable-demuxer=aac --enable-demuxer=pmp --enable-demuxer=oma --enable-demuxer=pcm_s16le --enable-demuxer=pcm_s8 --enable-demuxer=wav --enable-hwaccel=h264_dxva2 --enable-indev=dshow --enable-protocol=file
BUILD_COMMAND make -j ${N}
INSTALL_COMMAND make install
)
set(FFMPEG_LIB_AVFORMAT "${CMAKE_CURRENT_BINARY_DIR}/ffmpeg/windows/x86_64/lib/libavformat.a")
set(FFMPEG_LIB_AVCODEC "${CMAKE_CURRENT_BINARY_DIR}/ffmpeg/windows/x86_64/lib/libavcodec.a")
set(FFMPEG_LIB_AVUTIL "${CMAKE_CURRENT_BINARY_DIR}/ffmpeg/windows/x86_64/lib/libavutil.a")
set(FFMPEG_LIB_SWSCALE "${CMAKE_CURRENT_BINARY_DIR}/ffmpeg/windows/x86_64/lib/libswscale.a")
set(FFMPEG_LIB_SWRESAMPLE "${CMAKE_CURRENT_BINARY_DIR}/ffmpeg/windows/x86_64/lib/libswresample.a")
target_link_directories(3rdparty_ffmpeg INTERFACE "${CMAKE_CURRENT_BINARY_DIR}/ffmpeg/windows/x86_64/lib")
target_link_libraries(3rdparty_ffmpeg INTERFACE avformat avcodec avutil swscale swresample iconv)
else()
message("-- RPCS3: using builtin ffmpeg")
message(STATUS "RPCS3: using builtin ffmpeg")
if (WIN32)
set(FFMPEG_LIB_DIR "ffmpeg/windows/x86_64")
target_link_libraries(3rdparty_ffmpeg INTERFACE "Bcrypt.lib")
elseif(CMAKE_SYSTEM MATCHES "Linux")
elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux")
set(FFMPEG_LIB_DIR "ffmpeg/linux/x86_64")
elseif(APPLE)
set(FFMPEG_LIB_DIR "ffmpeg/macos/x86_64")
@@ -304,31 +302,31 @@ else()
find_library(FFMPEG_LIB_AVUTIL avutil PATHS ${FFMPEG_LIB_DIR} NO_DEFAULT_PATH)
find_library(FFMPEG_LIB_SWSCALE swscale PATHS ${FFMPEG_LIB_DIR} NO_DEFAULT_PATH)
find_library(FFMPEG_LIB_SWRESAMPLE swresample PATHS ${FFMPEG_LIB_DIR} NO_DEFAULT_PATH)
endif()
target_include_directories(3rdparty_ffmpeg INTERFACE "ffmpeg/include")
target_link_libraries(3rdparty_ffmpeg
target_link_libraries(3rdparty_ffmpeg
INTERFACE
${FFMPEG_LIB_AVFORMAT}
${FFMPEG_LIB_AVCODEC}
${FFMPEG_LIB_AVUTIL}
${FFMPEG_LIB_SWSCALE}
${FFMPEG_LIB_SWRESAMPLE}
)
)
endif()
target_include_directories(3rdparty_ffmpeg INTERFACE "ffmpeg/include")
endif()
# GLEW
add_library(3rdparty_glew INTERFACE)
if(NOT MSVC)
find_package(GLEW 1.13.0 REQUIRED)
find_package(GLEW REQUIRED)
target_link_libraries(3rdparty_glew INTERFACE GLEW::GLEW)
endif()
# LLVM
include(llvm.cmake)
add_subdirectory(llvm EXCLUDE_FROM_ALL)
# WOLFSSL
add_subdirectory(wolfssl EXCLUDE_FROM_ALL)
+1 -1
View File
@@ -1,5 +1,5 @@
# OpenAL
if (MSVC)
if (WIN32)
find_path(OPENAL_INCLUDE_DIR al.h PATHS include/)
find_library(OPENAL_LIBRARY OpenAL32 PATHS libs/Win64/)
else()
+22 -10
View File
@@ -1,24 +1,36 @@
# CURL
if(USE_SYSTEM_CURL)
message("-- RPCS3: using shared libcurl")
message(STATUS "RPCS3: using shared libcurl")
find_package(CURL REQUIRED)
add_library(libcurl INTERFACE)
target_link_libraries(libcurl INTERFACE CURL::libcurl)
else()
message("-- RPCS3: building libcurl + wolfssl submodules")
add_compile_definitions(HAVE_SNI OPENSSL_EXTRA)
option(BUILD_CURL_EXE "Set to ON to build curl executable." OFF)
option(CURL_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)
option(USE_LIBIDN2 "Use libidn2 for IDN support" OFF) # Disabled because MacOs CI doesn't work otherwise
message(STATUS "RPCS3: building libcurl + wolfssl submodules")
set(BUILD_CURL_EXE OFF CACHE BOOL "Set to ON to build curl executable.")
# If set to ON then CURL can not find our wolfssl
set(CURL_USE_WOLFSSL OFF CACHE BOOL "enable wolfSSL for SSL/TLS")
set(CURL_USE_OPENSSL OFF CACHE BOOL "Use OpenSSL code. Experimental")
set(HTTP_ONLY ON CACHE BOOL "disables all protocols except HTTP (This overrides all CURL_DISABLE_* options)")
set(USE_LIBIDN2 OFF CACHE BOOL "Use libidn2 for IDN support") # Disabled because MacOS CI doesn't work otherwise
set(CURL_CA_PATH "none" CACHE STRING "Location of default CA path. Set 'none' to disable or 'auto' for auto-detection. Defaults to 'auto'.")
if(USE_MSVC_STATIC_CRT)
set(CURL_STATIC_CRT ON CACHE BOOL "Use static crt to build curl" FORCE)
set(CURL_STATIC_CRT ON CACHE BOOL "Use static crt to build curl")
endif()
if(WIN32)
set(ENABLE_UNICODE ON CACHE BOOL "enable Unicode")
endif()
set(CURL_USE_LIBSSH2 OFF CACHE BOOL "Use libSSH2")
set(CURL_USE_LIBPSL OFF CACHE BOOL "Use libPSL")
set(SSL_ENABLED ON)
set(USE_WOLFSSL ON)
add_subdirectory(curl EXCLUDE_FROM_ALL)
set_property(TARGET libcurl PROPERTY FOLDER "3rdparty/")
target_link_libraries(libcurl PRIVATE wolfssl)
if(MSVC)
target_compile_definitions(libcurl PRIVATE HAVE_SSIZE_T)
endif()
endif()
+1 -1
View File
@@ -14,7 +14,7 @@ if(APPLE)
elseif(CMAKE_SYSTEM MATCHES "Linux")
target_link_libraries(3rdparty_hidapi INTERFACE hidapi-hidraw udev)
elseif(WIN32)
target_link_libraries(3rdparty_hidapi INTERFACE hidapi-hid Shlwapi.lib)
target_link_libraries(3rdparty_hidapi INTERFACE hidapi::hidapi hidapi::include Shlwapi.lib)
else()
target_link_libraries(3rdparty_hidapi INTERFACE hidapi-libusb usb)
endif()
+5 -4
View File
@@ -2,14 +2,15 @@
# Select the version of libpng to use, default is builtin
if (NOT USE_SYSTEM_LIBPNG)
# We use libpng's static library and don't need to build the shared library and run the tests
set(PNG_SHARED OFF CACHE BOOL "Build shared lib" FORCE)
set(PNG_TESTS OFF CACHE BOOL "Build libpng tests" FORCE)
set(PNG_BUILD_ZLIB ON CACHE BOOL "ZLIB is already build or package is found" FORCE)
set(PNG_SHARED OFF CACHE BOOL "Build shared lib")
set(PNG_TESTS OFF CACHE BOOL "Build libpng tests")
set(PNG_BUILD_ZLIB ON CACHE BOOL "ZLIB is already build or package is found")
set(SKIP_INSTALL_ALL ON)
add_subdirectory(libpng EXCLUDE_FROM_ALL)
target_include_directories(png_static INTERFACE "${libpng_BINARY_DIR}" "${libpng_SOURCE_DIR}")
target_link_libraries(png_static 3rdparty::zlib)
set(LIBPNG_TARGET png_static PARENT_SCOPE)
set(LIBPNG_TARGET png_static PARENT_SCOPE)
else()
find_package(PNG REQUIRED)
+1 -1
View File
@@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 2.8.4)
cmake_minimum_required(VERSION 3.0)
project(libusb)
+5 -1
View File
@@ -89,7 +89,11 @@ set(PACKAGE_URL "http://www.libusb.org" CACHE INTERNAL "package url" FORCE)
set(PACKAGE_TARNAME "libusb" CACHE INTERNAL "tarball name" FORCE)
set(VERSION "${PACKAGE_VERSION}" CACHE INTERNAL "version" FORCE)
configure_file(config.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config.h @ONLY)
if(MSVC)
file(COPY libusb/msvc/config.h DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
else()
configure_file(config.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config.h @ONLY)
endif()
message(STATUS "Generated configuration file in ${CMAKE_CURRENT_BINARY_DIR}/config.h")
# for generated config.h
+8 -17
View File
@@ -3,22 +3,6 @@ include(os.cmake)
include(config.cmake)
include(FindThreads)
set (LIBUSB_COMMON
core.c
descriptor.c
io.c
sync.c
hotplug.c
strerror.c
libusb-1.0.rc
libusb-1.0.def
)
foreach(SRC IN LISTS LIBUSB_COMMON)
list(APPEND LIBUSB_COMMON_FINAL ${LIBUSB_SOURCE_DIR}/libusb/${SRC})
endforeach()
include_directories(${LIBUSB_SOURCE_DIR}/libusb)
include_directories(${LIBUSB_SOURCE_DIR}/libusb/os)
@@ -28,7 +12,14 @@ endif()
add_library(usb-1.0-static
STATIC
${LIBUSB_COMMON_FINAL}
libusb/libusb/core.c
libusb/libusb/descriptor.c
libusb/libusb/io.c
libusb/libusb/sync.c
libusb/libusb/hotplug.c
libusb/libusb/strerror.c
libusb/libusb/libusb-1.0.rc
libusb/libusb/libusb-1.0.def
${LIBUSB_PLATFORM}
)
+22 -21
View File
@@ -5,42 +5,43 @@ if (CMAKE_USE_PTHREADS_INIT)
set(PTHREADS_ENABLED TRUE)
endif()
if (WIN32 OR "${CMAKE_SYSTEM_NAME}" STREQUAL "CYGWIN")
if (CYGWIN)
add_compile_definitions(PLATFORM_WINDOWS=1)
set(OS_WINDOWS 1 CACHE INTERNAL "controls config.h macro definition" FORCE)
set(OS_WINDOWS 1)
# Enable MingW support for RC language (for CMake pre-2.8)
if (MINGW)
set(CMAKE_RC_COMPILER_INIT windres)
set(CMAKE_RC_COMPILE_OBJECT "<CMAKE_RC_COMPILER> <FLAGS> -O coff <DEFINES> -i <SOURCE> -o <OBJECT>")
endif()
enable_language(RC)
if ("${CMAKE_SYSTEM_NAME}" STREQUAL "CYGWIN")
message(STATUS "Detected cygwin")
set(PTHREADS_ENABLED TRUE)
set(WITHOUT_POLL_H TRUE CACHE INTERNAL "Disable using poll.h even if it's available - use windows poll instead fo cygwin's" FORCE)
endif()
message(STATUS "Detected Cygwin")
set(PTHREADS_ENABLED TRUE)
set(WITHOUT_POLL_H TRUE)
list(APPEND PLATFORM_SRC
events_windows.c
windows_usbdk.c
windows_common.c
windows_winusb.c
threads_windows.c
)
if (PTHREADS_ENABLED AND NOT WITHOUT_PTHREADS)
list(APPEND PLATFORM_SRC threads_posix)
else()
list(APPEND PLATFORM_SRC threads_windows.c)
endif()
elseif(WIN32)
add_compile_definitions(PLATFORM_WINDOWS=1)
set(OS_WINDOWS 1)
set(PTHREADS_ENABLED FALSE)
list(APPEND PLATFORM_SRC
events_windows.c
windows_usbdk.c
windows_common.c
windows_winusb.c
)
list(APPEND PLATFORM_SRC threads_windows.c)
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)
set(OS_DARWIN 1)
if ("${CMAKE_SYSTEM_NAME}" STREQUAL "Darwin")
if (CMAKE_SYSTEM_NAME STREQUAL "Darwin")
set(PLATFORM_SRC
darwin_usb.c
threads_posix.c
@@ -77,7 +78,7 @@ 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)
set(OS_LINUX 1)
set(PLATFORM_SRC
linux_usbfs.c
@@ -108,4 +109,4 @@ set(LIBUSB_LIBRARIES ${LIBUSB_LIBRARIES} PARENT_SCOPE)
if (WITHOUT_PTHREADS)
set(PTHREADS_ENABLED FALSE)
endif()
set(THREADS_POSIX ${PTHREADS_ENABLED} CACHE INTERNAL "use pthreads" FORCE)
set(THREADS_POSIX ${PTHREADS_ENABLED})
+14 -15
View File
@@ -1,6 +1,6 @@
if(WITH_LLVM)
CHECK_CXX_COMPILER_FLAG("-msse -msse2 -mcx16" COMPILER_X86)
CHECK_CXX_COMPILER_FLAG("-march=armv8-a+lse" COMPILER_ARM)
check_cxx_compiler_flag("-msse -msse2 -mcx16" COMPILER_X86)
check_cxx_compiler_flag("-march=armv8-a+lse" COMPILER_ARM)
if(BUILD_LLVM)
message(STATUS "LLVM will be built from the submodule.")
@@ -14,28 +14,26 @@ if(WITH_LLVM)
option(LLVM_INCLUDE_TESTS OFF)
option(LLVM_INCLUDE_TOOLS OFF)
option(LLVM_INCLUDE_UTILS OFF)
option(LLVM_CCACHE_BUILD ON)
# we globally enable ccache
set(LLVM_CCACHE_BUILD OFF CACHE BOOL "Set to ON for a ccache enabled build")
if(WIN32)
set(LLVM_USE_INTEL_JITEVENTS ON)
endif()
if(CMAKE_SYSTEM MATCHES "Linux")
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
set(LLVM_USE_INTEL_JITEVENTS ON)
set(LLVM_USE_PERF ON)
endif()
set(CXX_FLAGS_OLD ${CMAKE_CXX_FLAGS})
if (MSVC)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /D _SILENCE_ALL_CXX17_DEPRECATION_WARNINGS")
add_compile_definitions("$<$<COMPILE_LANGUAGE:CXX>:_SILENCE_ALL_CXX17_DEPRECATION_WARNINGS>")
endif()
# LLVM needs to be built out-of-tree
add_subdirectory(${CMAKE_SOURCE_DIR}/3rdparty/llvm/llvm/llvm ${CMAKE_BINARY_DIR}/3rdparty/llvm/llvm_build EXCLUDE_FROM_ALL)
set(LLVM_DIR "${CMAKE_BINARY_DIR}/3rdparty/llvm/llvm_build/lib/cmake/llvm/")
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/llvm/llvm ${CMAKE_CURRENT_BINARY_DIR}/llvm_build EXCLUDE_FROM_ALL)
set(LLVM_DIR "${CMAKE_CURRENT_BINARY_DIR}/llvm_build/lib/cmake/llvm/")
set(CMAKE_CXX_FLAGS ${CXX_FLAGS_OLD})
set(STATIC_LINK_LLVM ON CACHE BOOL "Link against LLVM statically. This will get set to ON if you build LLVM from the submodule." FORCE)
# now tries to find LLVM again
@@ -72,11 +70,11 @@ if(WITH_LLVM)
set(LLVM_TARGETS_TO_BUILD "X86" CACHE STRING "Semicolon-separated list of targets to build, or \"all\".")
endif()
endif()
if(WIN32 OR CMAKE_SYSTEM MATCHES "Linux")
set (LLVM_ADDITIONAL_LIBS ${LLVM_ADDITIONAL_LIBS} IntelJITEvents)
if((WIN32 AND BUILD_LLVM) OR CMAKE_SYSTEM_NAME STREQUAL "Linux")
list (APPEND LLVM_ADDITIONAL_LIBS IntelJITEvents)
endif()
if(CMAKE_SYSTEM MATCHES "Linux")
set (LLVM_ADDITIONAL_LIBS ${LLVM_ADDITIONAL_LIBS} PerfJITEvents)
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
list (APPEND LLVM_ADDITIONAL_LIBS PerfJITEvents)
endif()
llvm_map_components_to_libnames(LLVM_LIBS
${LLVM_TARGETS_TO_BUILD}
@@ -92,7 +90,8 @@ if(WITH_LLVM)
add_library(3rdparty_llvm INTERFACE)
target_link_libraries(3rdparty_llvm INTERFACE ${LLVM_LIBS})
target_include_directories(3rdparty_llvm INTERFACE ${LLVM_INCLUDE_DIRS})
target_compile_definitions(3rdparty_llvm INTERFACE ${LLVM_DEFINITIONS} -DLLVM_AVAILABLE)
separate_arguments(LLVM_DEFINITIONS_LIST NATIVE_COMMAND ${LLVM_DEFINITIONS})
target_compile_definitions(3rdparty_llvm INTERFACE ${LLVM_DEFINITIONS_LIST} LLVM_AVAILABLE)
add_library(3rdparty::llvm ALIAS 3rdparty_llvm)
else()
+8 -2
View File
@@ -32,6 +32,12 @@
#endif
#endif
#ifdef _WIN32
constexpr SOCKET invalid_socket = INVALID_SOCKET;
#else
constexpr int invalid_socket = -1;
#endif
namespace pine
{
/**
@@ -381,7 +387,7 @@ namespace pine
m_msgsock = accept(m_sock, 0, 0);
if (m_msgsock == -1)
if (m_msgsock == invalid_socket)
{
// everything else is non recoverable in our scope
// we also mark as recoverable socket errors where it would block a
@@ -541,7 +547,7 @@ namespace pine
}
server.sin_port = htons(Impl::get_port());
if (bind(m_sock, (struct sockaddr*)&server, sizeof(server)) == SOCKET_ERROR)
if (bind(m_sock, reinterpret_cast<struct sockaddr*>(&server), sizeof(server)) == SOCKET_ERROR)
{
Impl::error("IPC: Error while binding to socket! Shutting down...");
return;
-45
View File
@@ -1,45 +0,0 @@
add_library(3rdparty_qt5 INTERFACE)
set(QT_MIN_VER 5.15.2)
find_package(Qt5 ${QT_MIN_VER} CONFIG COMPONENTS Widgets Concurrent Multimedia MultimediaWidgets Svg)
if(WIN32)
find_package(Qt5 ${QT_MIN_VER} COMPONENTS WinExtras REQUIRED)
target_link_libraries(3rdparty_qt5 INTERFACE Qt5::Widgets Qt5::WinExtras Qt5::Concurrent Qt5::Multimedia Qt5::MultimediaWidgets Qt5::Svg)
else()
find_package(Qt5 ${QT_MIN_VER} COMPONENTS DBus Gui)
if(Qt5DBus_FOUND)
target_link_libraries(3rdparty_qt5 INTERFACE Qt5::Widgets Qt5::DBus Qt5::Concurrent Qt5::Multimedia Qt5::MultimediaWidgets Qt5::Svg)
target_compile_definitions(3rdparty_qt5 INTERFACE -DHAVE_QTDBUS)
else()
target_link_libraries(3rdparty_qt5 INTERFACE Qt5::Widgets Qt5::Concurrent Qt5::Multimedia Qt5::MultimediaWidgets Qt5::Svg)
endif()
target_include_directories(3rdparty_qt5 INTERFACE ${Qt5Gui_PRIVATE_INCLUDE_DIRS})
endif()
if(NOT Qt5Widgets_FOUND)
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.
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()
message(FATAL_ERROR "Look online for instructions on installing an up-to-date Qt5 on ${CMAKE_SYSTEM}.")
endif()
endif()
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\\${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!")
else()
message(FATAL_ERROR "You need to have Qt5 installed, look online for instructions on installing Qt5 on ${CMAKE_SYSTEM}.")
endif()
endif()
add_library(3rdparty::qt5 ALIAS 3rdparty_qt5)
+45
View File
@@ -0,0 +1,45 @@
add_library(3rdparty_qt6 INTERFACE)
set(QT_MIN_VER 6.4.0)
find_package(Qt6 ${QT_MIN_VER} CONFIG COMPONENTS Widgets Concurrent Multimedia MultimediaWidgets Svg SvgWidgets)
if(WIN32)
find_package(Qt6 ${QT_MIN_VER} COMPONENTS WinExtras REQUIRED)
target_link_libraries(3rdparty_qt6 INTERFACE Qt6::Widgets Qt6::WinExtras Qt6::Concurrent Qt6::Multimedia Qt6::MultimediaWidgets Qt6::Svg Qt6::SvgWidgets)
else()
find_package(Qt6 ${QT_MIN_VER} COMPONENTS DBus Gui)
if(Qt6DBus_FOUND)
target_link_libraries(3rdparty_qt6 INTERFACE Qt6::Widgets Qt6::DBus Qt6::Concurrent Qt6::Multimedia Qt6::MultimediaWidgets Qt6::Svg Qt6::SvgWidgets)
target_compile_definitions(3rdparty_qt6 INTERFACE -DHAVE_QTDBUS)
else()
target_link_libraries(3rdparty_qt6 INTERFACE Qt6::Widgets Qt6::Concurrent Qt6::Multimedia Qt6::MultimediaWidgets Qt6::Svg Qt6::SvgWidgets)
endif()
target_include_directories(3rdparty_qt6 INTERFACE ${Qt6Gui_PRIVATE_INCLUDE_DIRS})
endif()
if(Qt6Widgets_FOUND)
if(Qt6Widgets_VERSION VERSION_LESS ${QT_MIN_VER})
message("Minimum supported Qt version is ${QT_MIN_VER}! You have version ${Qt6Widgets_VERSION} installed, please upgrade!")
if(CMAKE_SYSTEM_NAME STREQUAL "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 qt6 versions.
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 Qt6 here: https://www.qt.io/download-open-source/")
else()
message(FATAL_ERROR "Look online for instructions on installing an up-to-date Qt6 on ${CMAKE_SYSTEM}.")
endif()
endif()
else()
message("CMake was unable to find Qt6!")
if(WIN32)
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 Qt6_DIR preprocessor definiton.")
elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux")
message(FATAL_ERROR "Make sure to install your distro's qt6 package!")
else()
message(FATAL_ERROR "You need to have Qt6 installed, look online for instructions on installing Qt6 on ${CMAKE_SYSTEM}.")
endif()
endif()
add_library(3rdparty::qt6 ALIAS 3rdparty_qt6)
File diff suppressed because it is too large Load Diff
+17 -31
View File
@@ -1,40 +1,26 @@
if(USE_SYSTEM_WOLFSSL)
message("-- RPCS3: using shared wolfssl")
message(STATUS "RPCS3: using shared wolfssl")
pkg_check_modules(WolfSSL REQUIRED IMPORTED_TARGET wolfssl>=4.7.0)
add_library(wolfssl INTERFACE)
target_link_libraries(wolfssl INTERFACE PkgConfig::WolfSSL)
else()
# TODO(cjj19970505@live.cn)
# OPENSSL_EXTRA, and HAVE_SNI are unconfigurable from CMake cache.
# but they do have it in a TODO list (wolfssl/CMakeList, 1021)
add_compile_definitions(OPENSSL_EXTRA WOLFSSL_DES_ECB HAVE_SNI HAVE_WRITE_DUP)
add_compile_definitions(FP_MAX_BITS=8192)
set(WOLFSSL_TLS13 "no" CACHE INTERNAL "")
set(WOLFSSL_SHA224 "yes" CACHE INTERNAL "")
set(WOLFSSL_SHA3 "yes" CACHE INTERNAL "")
set(WOLFSSL_SHAKE256 "yes" CACHE INTERNAL "")
set(WOLFSSL_BASE64_ENCODE "no" CACHE INTERNAL "")
set(WOLFSSL_DES3 "yes" CACHE INTERNAL "")
set(WOLFSSL_POLY1305 "yes" CACHE INTERNAL "")
set(WOLFSSL_CHACHA "yes" CACHE INTERNAL "")
set(WOLFSSL_FILESYSTEM "yes" CACHE INTERNAL "")
set(WOLFSSL_PWDBASED "yes" CACHE INTERNAL "")
set(WOLFSSL_FAST_MATH "yes" CACHE INTERNAL "")
set(WOLFSSL_EXAMPLES "no" CACHE INTERNAL "")
set(WOLFSSL_CRYPT_TESTS "no" CACHE INTERNAL "")
set(WOLFSSL_ASYNC_THREADS "no" CACHE INTERNAL "")
set(WOLFSSL_CONFIG_H "no" CACHE INTERNAL "")
set(WOLFSSL_TLS13 OFF CACHE STRING "Enable wolfSSL TLS v1.3 (default: enabled)")
set(WOLFSSL_SHA3 ON CACHE STRING "Enable wolfSSL SHA-3 support (default: enabled on x86_64/aarch64)")
set(WOLFSSL_SHAKE256 ON CACHE STRING "Enable wolfSSL SHAKE256 support (default: enabled on x86_64/aarch64)")
set(WOLFSSL_BASE64_ENCODE OFF CACHE STRING "Enable Base64 encoding (default: enabled on x86_64)")
set(WOLFSSL_DES3 ON CACHE STRING "Enable DES3 (default: disabled)")
set(WOLFSSL_PWDBASED ON CACHE STRING "Enable PWDBASED (default: disabled)")
set(WOLFSSL_FAST_MATH ON CACHE STRING "Enable fast math ops (default: disabled)")
set(WOLFSSL_EXAMPLES OFF CACHE STRING "Enable examples (default: enabled)")
set(WOLFSSL_CRYPT_TESTS OFF CACHE STRING "Enable Crypt Bench/Test (default: enabled)")
set(WOLFSSL_ASYNC_THREADS OFF CACHE STRING "Enable Asynchronous Threading (default: enabled)")
set(WOLFSSL_BUILD_OUT_OF_TREE ON CACHE STRING "Don't generate files in the source tree (default: no)")
set(WOLFSSL_SNI ON CACHE STRING "Enable SNI (default: disabled)")
set(WOLFSSL_OPENSSLEXTRA ON CACHE STRING "Enable extra OpenSSL API, size+ (default: disabled)")
set(WOLFSSL_HARDEN OFF CACHE STRING "Enable Hardened build, Enables Timing Resistance and Blinding (default: enabled)")
add_subdirectory(wolfssl EXCLUDE_FROM_ALL)
set(WolfSSL_LIBRARY "$<TARGET_FILE:wolfssl>" CACHE INTERNAL "")
# "${CMAKE_CURRENT_SOURCE_DIR}/wolfssl/wolfssl/" provides openssl headers
# So that curl can be built on an environment where openssl headers are not provided
set(WolfSSL_INCLUDE_DIR
"${CMAKE_CURRENT_SOURCE_DIR}/wolfssl/"
"${CMAKE_CURRENT_SOURCE_DIR}/wolfssl/wolfssl/"
"${CMAKE_CURRENT_BINARY_DIR}/wolfssl/"
CACHE INTERNAL "")
target_compile_definitions(wolfssl PUBLIC WOLFSSL_DES_ECB HAVE_WRITE_DUP)
target_compile_definitions(wolfssl PUBLIC FP_MAX_BITS=8192)
endif()
+6
View File
@@ -37,6 +37,7 @@
#define NO_PSK
#define HAVE_EXTENDED_MASTER
#define WOLFSSL_SNIFFER
#define WOLFSSL_IGNORE_FILE_WARN
#define HAVE_AESGCM
#define HAVE_SUPPORTED_CURVES
#define HAVE_TLS_EXTENSIONS
@@ -63,11 +64,16 @@ extern FILE* wolfSSL_fopen_utf8(const char* name, const char* mode);
#define XFWRITE fwrite
#define XFCLOSE fclose
#define XSEEK_END SEEK_END
#define XSEEK_SET SEEK_SET
#define XBADFILE NULL
#define XFGETS fgets
#define XFPRINTF fprintf
#define XFFLUSH fflush
/* For some reason we need to define ssize_t */
#define HAVE_SSIZE_T
#define ssize_t __int64
#include <sys/stat.h>
extern int wolfSSL_stat_utf8(const char* path, struct _stat* buffer);
#define XSTAT wolfSSL_stat_utf8
+1
View File
@@ -73,6 +73,7 @@
<ItemGroup>
<ClCompile Include="wolfssl\src\crl.c" />
<ClCompile Include="wolfssl\src\internal.c" />
<ClCompile Include="wolfssl\src\ssl_asn1.c" />
<ClCompile Include="wolfssl\src\wolfio.c" />
<ClCompile Include="wolfssl\src\keys.c" />
<ClCompile Include="wolfssl\src\ocsp.c" />
+11 -9
View File
@@ -1,14 +1,16 @@
if (USE_SYSTEM_ZLIB)
message(STATUS "-- RPCS3: Using syztem ZLIB")
find_package(ZLIB QUIET)
message(STATUS "RPCS3: Using system ZLIB")
find_package(ZLIB QUIET)
add_library(3rdparty_zlib INTERFACE)
target_link_libraries(3rdparty_zlib INTERFACE ${ZLIB_LIBRARIES})
target_include_directories(3rdparty_zlib INTERFACE ${ZLIB_INCLUDE_DIRS})
else()
message(STATUS "-- RPCS3: Using builtin ZLIB")
message(STATUS "RPCS3: Using builtin ZLIB")
set(SKIP_INSTALL_ALL ON)
add_subdirectory(zlib EXCLUDE_FROM_ALL)
set(ZLIB_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/zlib" "${CMAKE_CURRENT_BINARY_DIR}/zlib")
set(ZLIB_LIBRARY zlibstatic)
endif()
add_library(3rdparty_zlib INTERFACE)
target_link_libraries(3rdparty_zlib INTERFACE ${ZLIB_LIBRARY})
target_include_directories(3rdparty_zlib INTERFACE ${ZLIB_INCLUDE_DIR})
add_library(3rdparty_zlib INTERFACE)
target_link_libraries(3rdparty_zlib INTERFACE zlibstatic)
target_include_directories(3rdparty_zlib INTERFACE zlib ${CMAKE_CURRENT_BINARY_DIR}/zlib)
endif()
+8 -15
View File
@@ -9,11 +9,11 @@ Other instructions may be found [here](https://wiki.rpcs3.net/index.php?title=Bu
* [CMake 3.16.9+](https://www.cmake.org/download/) (add to PATH)
* [Python 3.6+](https://www.python.org/downloads/) (add to PATH)
* [Qt 5.15.2](https://www.qt.io/download-qt-installer)
* [Qt 6.5.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.3.224+](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.15.2\msvc2019_64\` **, or use the [Visual Studio Qt Plugin](https://marketplace.visualstudio.com/items?itemName=TheQtCompany.QtVisualStudioTools2019)**
**Either add the** `QTDIR` **environment variable, e.g.** `<QtInstallFolder>\6.5.2\msvc2019_64\` **, or use the [Visual Studio Qt Plugin](https://marketplace.visualstudio.com/items?itemName=TheQtCompany.QtVisualStudioTools2019)**
### Linux
@@ -21,7 +21,7 @@ These are the essentials tools to build RPCS3 on Linux. Some of them can be inst
* Clang 12+ or GCC 11+
* [CMake 3.16.9+](https://www.cmake.org/download/)
* [Qt 5.15.2](https://www.qt.io/download-qt-installer)
* [Qt 6.5.2](https://www.qt.io/download-qt-installer)
* [Vulkan SDK 1.3.224+](https://vulkan.lunarg.com/sdk/home) (See "Install the SDK" [here](https://vulkan.lunarg.com/doc/sdk/latest/linux/getting_started.html))
* [SDL2](https://github.com/libsdl-org/SDL/releases) (for the FAudio backend)
@@ -29,7 +29,7 @@ These are the essentials tools to build RPCS3 on Linux. Some of them can be inst
#### Arch Linux
sudo pacman -S glew openal cmake vulkan-validation-layers qt5-base qt5-declarative qt5-multimedia sdl2 sndio jack2 base-devel
sudo pacman -S glew openal cmake vulkan-validation-layers qt6-base qt6-declarative qt6-multimedia sdl2 sndio jack2 base-devel
#### Debian & Ubuntu
@@ -38,14 +38,7 @@ These are the essentials tools to build RPCS3 on Linux. Some of them can be inst
Ubuntu is usually horrendously out of date, and some packages need to be downloaded by hand. This part is for Qt, GCC, Vulkan, and CMake
##### Qt PPA
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:
```
. /etc/os-release
sudo add-apt-repository ppa:beineri/opt-qt-5.15.2-$UBUNTU_CODENAME
sudo apt-get update
sudo apt-get install qt515base qt515svg
. /opt/qt515/bin/qt515-env.sh >/dev/null 2>&1
```
Ubuntu usually does not have a new enough Qt package to suit rpcs3's needs. There is currently no PPA available to work around this.
##### GCC 11.x installation
@@ -82,11 +75,11 @@ sudo apt-get install cmake
#### Fedora
sudo dnf install alsa-lib-devel cmake glew glew-devel libatomic libevdev-devel libudev-devel openal-devel qt5-qtbase-devel qt5-qtbase-private-devel vulkan-devel pipewire-jack-audio-connection-kit-devel qt5-qtmultimedia-devel qt5-qtsvg-devel
sudo dnf install alsa-lib-devel cmake glew glew-devel libatomic libevdev-devel libudev-devel openal-devel qt6-qtbase-devel qt6-qtbase-private-devel vulkan-devel pipewire-jack-audio-connection-kit-devel qt6-qtmultimedia-devel qt6-qtsvg-devel
#### OpenSUSE
sudo zypper install git cmake libasound2 libpulse-devel openal-soft-devel glew-devel zlib-devel libedit-devel vulkan-devel libudev-devel libqt5-qtbase-devel libqt5-qtmultimedia-devel libqt5-qtsvg-devel libQt5Gui-private-headers-devel libevdev-devel libsndio7_1 libjack-devel
sudo zypper install git cmake libasound2 libpulse-devel openal-soft-devel glew-devel zlib-devel libedit-devel vulkan-devel libudev-devel libqt6-qtbase-devel libqt6-qtmultimedia-devel libqt6-qtsvg-devel libQt6Gui-private-headers-devel libevdev-devel libsndio7_1 libjack-devel
## Setup the project
@@ -103,7 +96,7 @@ git submodule update --init
#### Configuring the Qt plugin (if used)
1) Go to `Extensions->Qt VS Tools->Qt Versions`.
2) Add the path to your Qt installation with compiler e.g. `<QtInstallFolder>\5.15.2\msvc2019_64`, version will fill in automatically.
2) Add the path to your Qt installation with compiler e.g. `<QtInstallFolder>\6.5.2\msvc2019_64`, version will fill in automatically.
3) Go to `Extensions->Qt VS Tools->Options->Legacy Project Format`.
4) Set `Build: Run pre-build setup` to `true`.
+16 -20
View File
@@ -1,12 +1,14 @@
cmake_minimum_required(VERSION 3.16.9)
project(rpcs3)
project(rpcs3 LANGUAGES C CXX)
if(${CMAKE_CXX_COMPILER_ID} MATCHES "GNU")
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 11)
message(FATAL_ERROR "RPCS3 requires at least gcc-11.")
endif()
elseif(${CMAKE_CXX_COMPILER_ID} MATCHES "Clang")
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 12.0)
message(FATAL_ERROR "RPCS3 requires at least clang-12.0.")
endif()
@@ -25,7 +27,7 @@ option(USE_PRECOMPILED_HEADERS "Use precompiled headers" OFF)
option(USE_SDL "Enables SDL input handler" OFF)
option(USE_SYSTEM_SDL "Prefer system SDL instead of the builtin one" OFF)
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/buildfiles/cmake")
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/buildfiles/cmake")
include(CheckCXXCompilerFlag)
@@ -43,7 +45,7 @@ else()
endif()
if(CMAKE_BUILD_TYPE MATCHES "Debug" AND NOT MSVC)
add_definitions(-D_DEBUG)
add_compile_definitions(_DEBUG)
endif()
if(MSVC)
@@ -75,7 +77,7 @@ if(MSVC)
# TODO(cjj19970505@live.cn)
# offical QT uses dynamic CRT.
# When building our lib with static CRT and debug build type
# and linking with Qt with dynmaic CRT and debug build,
# and linking with Qt with dynamic CRT and debug build,
# error is encountered in runtime (which is expected).
# But building our lib with static CRT and release build type,
# and linking with Qt with dynamic CRT and release build seems to be working,
@@ -90,6 +92,7 @@ if(MSVC)
message(AUTHOR_WARNING "Debug build currently can not work with static CRT.")
endif()
endif()
add_compile_options(/MP)
endif()
if(NOT CMAKE_SIZEOF_VOID_P EQUAL 8)
@@ -98,13 +101,12 @@ endif()
find_program(CCACHE_FOUND ccache)
if(CCACHE_FOUND)
set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ccache)
set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK ccache)
set(CMAKE_CXX_COMPILER_LAUNCHER ccache)
endif()
if(WIN32)
add_definitions(-DUNICODE)
add_definitions(-D_WIN32_WINNT=0x0602)
add_compile_definitions(UNICODE)
add_compile_definitions(_WIN32_WINNT=0x0602)
endif()
if(APPLE AND CMAKE_OSX_ARCHITECTURES STREQUAL "arm64")
@@ -112,10 +114,7 @@ if(APPLE AND CMAKE_OSX_ARCHITECTURES STREQUAL "arm64")
link_directories(/opt/homebrew/lib)
endif()
# Warnings are silenced for 3rdparty code
set(CMAKE_CXX_FLAGS -w)
set(CMAKE_C_FLAGS -w)
set(LLVM_ENABLE_WARNINGS OFF CACHE BOOL "")
set(LLVM_ENABLE_WARNINGS OFF CACHE BOOL "Enable compiler warnings.")
if(MSVC)
add_compile_options(/wd4530 /utf-8) # C++ exception handler used, but unwind semantics are not enabled
@@ -123,9 +122,6 @@ endif()
add_subdirectory(3rdparty)
unset(CMAKE_CXX_FLAGS)
unset(CMAKE_C_FLAGS)
if (DISABLE_LTO)
if (CMAKE_C_FLAGS)
string(REGEX REPLACE "-flto[^ ]*" "" CMAKE_C_FLAGS ${CMAKE_C_FLAGS})
@@ -137,7 +133,7 @@ endif()
string(FIND "${CMAKE_C_FLAGS} ${CMAKE_CXX_FLAGS}" "-flto" FOUND_LTO)
if (NOT FOUND_LTO EQUAL -1)
message(FATAL_ERROR "Rpcs3 doesn't support building with LTO, use -DDISABLE_LTO=TRUE to force-disable it")
message(FATAL_ERROR "RPCS3 doesn't support building with LTO, use -DDISABLE_LTO=TRUE to force-disable it")
endif()
if(NOT WIN32)
@@ -149,6 +145,6 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE "${PROJECT_BINARY_DIR}/bin")
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG "${PROJECT_BINARY_DIR}/bin")
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELWITHDEBINFO "${PROJECT_BINARY_DIR}/bin")
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
add_subdirectory(rpcs3)
set_directory_properties(PROPERTIES VS_STARTUP_PROJECT rpcs3)
+68
View File
@@ -0,0 +1,68 @@
{
"version": 3,
"configurePresets": [
{
"name": "gcc",
"generator": "Ninja",
"binaryDir": "build-gcc",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug",
"USE_FAUDIO": "OFF",
"USE_SYSTEM_CURL": "OFF",
"USE_SYSTEM_ZLIB": "OFF",
"USE_SYSTEM_LIBPNG": "OFF",
"USE_NATIVE_INSTRUCTIONS": "ON",
"USE_PRECOMPILED_HEADERS": "ON",
"BUILD_LLVM": "OFF",
"STATIC_LINK_LLVM": "ON"
}
},
{
"name": "clang",
"generator": "Ninja",
"binaryDir": "build-clang64",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug",
"USE_FAUDIO": "OFF",
"USE_SYSTEM_CURL": "OFF",
"USE_SYSTEM_ZLIB": "OFF",
"USE_SYSTEM_LIBPNG": "OFF",
"LLVM_ENABLE_LIBCXX": "ON",
"USE_NATIVE_INSTRUCTIONS": "ON",
"USE_PRECOMPILED_HEADERS": "ON",
"BUILD_LLVM": "OFF",
"STATIC_LINK_LLVM": "ON"
},
"environment": {
"CXX": "clang++",
"CC": "clang"
}
},
{
"name": "msvc",
"displayName": "Windows x64",
"generator": "Visual Studio 17 2022",
"binaryDir": "build-msvc",
"architecture": {
"value": "x64",
"strategy": "external"
},
"cacheVariables": {
"CMAKE_INSTALL_PREFIX": "${sourceDir}/out/install/${presetName}",
"USE_FAUDIO": "OFF",
"USE_PRECOMPILED_HEADERS": "ON",
"USE_SYSTEM_ZLIB": "OFF",
"USE_NATIVE_INSTRUCTIONS": "ON",
"BUILD_LLVM": "ON",
"STATIC_LINK_LLVM": "ON"
},
"vendor": {
"microsoft.com/VisualStudioSettings/CMake/1.0": {
"hostOS": [
"Windows"
]
}
}
}
]
}
+2 -2
View File
@@ -725,7 +725,7 @@ namespace CRCPP
{
while (size--)
{
#if defined(WIN32) || defined(_WIN32) || defined(WINCE)
#ifdef _MSC_VER
// Disable warning about data loss when doing (remainder >> CHAR_BIT) when
// remainder is one byte long. The algorithm is still correct in this case,
// though it's possible that one additional machine instruction will be executed.
@@ -733,7 +733,7 @@ namespace CRCPP
# pragma warning (disable : 4333)
#endif
remainder = (remainder >> CHAR_BIT) ^ lookupTable[static_cast<unsigned char>(remainder ^ *current++)];
#if defined(WIN32) || defined(_WIN32) || defined(WINCE)
#ifdef _MSC_VER
# pragma warning (pop)
#endif
}
+6
View File
@@ -7,6 +7,12 @@
LOG_CHANNEL(cfg_log, "CFG");
template <>
void fmt_class_string<cfg::node>::format(std::string& out, u64 arg)
{
out += get_object(arg).to_string();
}
namespace cfg
{
_base::_base(type _type)
+150 -17
View File
@@ -130,6 +130,7 @@ static fs::error to_error(DWORD e)
case ERROR_NOT_READY: return fs::error::noent;
case ERROR_FILENAME_EXCED_RANGE: return fs::error::toolong;
case ERROR_DISK_FULL: return fs::error::nospace;
case ERROR_NOT_SAME_DEVICE: return fs::error::xdev;
default: return fs::error::unknown;
}
}
@@ -172,6 +173,7 @@ static fs::error to_error(int e)
case EROFS: return fs::error::readonly;
case EISDIR: return fs::error::isdir;
case ENOSPC: return fs::error::nospace;
case EXDEV: return fs::error::xdev;
default: return fs::error::unknown;
}
}
@@ -225,9 +227,9 @@ namespace fs
{
}
[[noreturn]] stat_t file_base::stat()
[[noreturn]] stat_t file_base::get_stat()
{
fmt::throw_exception("fs::file::stat() not supported.");
fmt::throw_exception("fs::file::get_stat() not supported.");
}
void file_base::sync()
@@ -244,6 +246,11 @@ namespace fs
#endif
}
file_id file_base::get_id()
{
return {};
}
u64 file_base::write_gather(const iovec_clone* buffers, u64 buf_count)
{
u64 total = 0;
@@ -272,6 +279,66 @@ namespace fs
return this->write(buf.get(), total);
}
file_id::operator bool() const
{
return !type.empty() && !data.empty();
}
// Test if identical
// For example: when LHS writes one byte to a file at X offset, RHS file be able to read that exact byte at X offset)
bool file_id::is_mirror_of(const file_id& rhs) const
{
// If either is an invalid ID we cannot compare safely, return false
return rhs && type == rhs.type && data == rhs.data;
}
// Test if both files point to the same file
// For example: if a file descriptor pointing to the complete file exists and is being truncated to 0 bytes from non-
// -zero size state: this has to affect both RHS and LHS files.
bool file_id::is_coherent_with(const file_id& rhs) const
{
struct id_view
{
std::string_view type_view;
std::basic_string_view<u8> data_view;
};
id_view _rhs{rhs.type, {rhs.data.data(), rhs.data.size()}};
id_view _lhs{type, {data.data(), data.size()}};
// Peek through fs::file wrappers
auto peek_wrapppers = [](id_view& id)
{
u64 offset_count = 0;
constexpr auto lv2_view = "lv2_file::file_view: "sv;
for (usz pos = 0; (pos = id.type_view.find(lv2_view, pos)) != umax; pos += lv2_view.size())
{
offset_count++;
}
// Remove offsets data
id.data_view.remove_suffix(sizeof(u64) * offset_count);
// Get last category identifier
if (usz sep = id.type_view.rfind(": "); sep != umax)
{
id.type_view.remove_prefix(sep + 2);
}
};
peek_wrapppers(_rhs);
peek_wrapppers(_lhs);
// If either is an invalid ID we cannot compare safely, return false
if (_rhs.type_view.empty() || _rhs.data_view.empty())
{
return false;
}
return _rhs.type_view == _lhs.type_view && _rhs.data_view == _lhs.data_view;
}
dir_base::~dir_base()
{
}
@@ -384,12 +451,12 @@ shared_ptr<fs::device_base> fs::set_virtual_device(const std::string& name, shar
return get_device_manager().set_device(name, std::move(device));
}
std::string fs::get_parent_dir(std::string_view path, u32 levels)
std::string_view fs::get_parent_dir_view(std::string_view path, u32 parent_level)
{
std::string_view result = path;
// Number of path components to remove
usz to_remove = levels;
usz to_remove = parent_level;
while (to_remove--)
{
@@ -432,10 +499,10 @@ std::string fs::get_parent_dir(std::string_view path, u32 levels)
return "/";
}
return std::string{result};
return result;
}
bool fs::stat(const std::string& path, stat_t& info)
bool fs::get_stat(const std::string& path, stat_t& info)
{
// Ensure consistent information on failure
info = {};
@@ -551,13 +618,13 @@ bool fs::stat(const std::string& path, stat_t& info)
bool fs::exists(const std::string& path)
{
fs::stat_t info{};
return fs::stat(path, info);
return fs::get_stat(path, info);
}
bool fs::is_file(const std::string& path)
{
fs::stat_t info{};
if (!fs::stat(path, info))
if (!fs::get_stat(path, info))
{
return false;
}
@@ -574,7 +641,7 @@ bool fs::is_file(const std::string& path)
bool fs::is_dir(const std::string& path)
{
fs::stat_t info{};
if (!fs::stat(path, info))
if (!fs::get_stat(path, info))
{
return false;
}
@@ -863,9 +930,20 @@ bool fs::copy_file(const std::string& from, const std::string& to, bool overwrit
if (::fcopyfile(input, output, 0, COPYFILE_ALL))
#elif defined(__linux__) || defined(__sun)
// 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) == -1 || ::sendfile(output, input, &bytes_copied, fileinfo.st_size) == -1)
bool result = ::fstat(input, &fileinfo) != -1;
if (result)
{
for (off_t bytes_copied = 0; bytes_copied < fileinfo.st_size; /* Do nothing, bytes_copied is increased by sendfile. */)
{
if (::sendfile(output, input, &bytes_copied, fileinfo.st_size - bytes_copied) == -1)
{
result = false;
break;
}
}
}
if (!result)
#else
#error "Native file copy implementation is missing"
#endif
@@ -1120,7 +1198,7 @@ fs::file::file(const std::string& path, bs_t<open_mode> mode)
CloseHandle(m_handle);
}
stat_t stat() override
stat_t get_stat() override
{
FILE_BASIC_INFO basic_info;
ensure(GetFileInformationByHandleEx(m_handle, FileBasicInfo, &basic_info, sizeof(FILE_BASIC_INFO))); // "file::stat"
@@ -1278,6 +1356,28 @@ fs::file::file(const std::string& path, bs_t<open_mode> mode)
{
return m_handle;
}
file_id get_id() override
{
file_id id{"windows_file"};
id.data.resize(sizeof(FILE_ID_INFO));
FILE_ID_INFO info;
if (!GetFileInformationByHandleEx(m_handle, FileIdInfo, &info, sizeof(info)))
{
// Try GetFileInformationByHandle as a fallback
BY_HANDLE_FILE_INFORMATION info2;
ensure(GetFileInformationByHandle(m_handle, &info2));
info = {};
info.VolumeSerialNumber = info2.dwVolumeSerialNumber;
std::memcpy(&info.FileId, &info2.nFileIndexHigh, 8);
}
std::memcpy(id.data.data(), &info, sizeof(info));
return id;
}
};
m_file = std::make_unique<windows_file>(handle);
@@ -1345,7 +1445,7 @@ fs::file::file(const std::string& path, bs_t<open_mode> mode)
::close(m_fd);
}
stat_t stat() override
stat_t get_stat() override
{
struct ::stat file_info;
ensure(::fstat(m_fd, &file_info) == 0); // "file::stat"
@@ -1470,6 +1570,19 @@ fs::file::file(const std::string& path, bs_t<open_mode> mode)
return m_fd;
}
file_id get_id() override
{
struct ::stat file_info;
ensure(::fstat(m_fd, &file_info) == 0); // "file::get_id"
file_id id{"unix_file"};
id.data.resize(sizeof(file_info.st_dev) + sizeof(file_info.st_ino));
std::memcpy(id.data.data(), &file_info.st_dev, sizeof(file_info.st_dev));
std::memcpy(id.data.data() + sizeof(file_info.st_dev), &file_info.st_ino, sizeof(file_info.st_ino));
return id;
}
u64 write_gather(const iovec_clone* buffers, u64 buf_count) override
{
static_assert(sizeof(iovec) == sizeof(iovec_clone), "Weird iovec size");
@@ -1495,7 +1608,7 @@ fs::file::file(const std::string& path, bs_t<open_mode> mode)
m_file = std::make_unique<unix_file>(fd);
if (mode & fs::isfile && !(mode & fs::write) && stat().is_directory)
if (mode & fs::isfile && !(mode & fs::write) && get_stat().is_directory)
{
m_file.reset();
g_tls_error = error::isdir;
@@ -1604,6 +1717,16 @@ fs::native_handle fs::file::get_handle() const
#endif
}
fs::file_id fs::file::get_id() const
{
if (m_file)
{
return m_file->get_id();
}
return {};
}
bool fs::dir::open(const std::string& path)
{
if (path.empty())
@@ -1646,7 +1769,7 @@ bool fs::dir::open(const std::string& path)
to_utf8(info.name, found.cFileName);
info.is_directory = (found.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
info.is_writable = (found.dwFileAttributes & FILE_ATTRIBUTE_READONLY) == 0;
info.size = ((u64)found.nFileSizeHigh << 32) | (u64)found.nFileSizeLow;
info.size = (static_cast<u64>(found.nFileSizeHigh) << 32) | static_cast<u64>(found.nFileSizeLow);
info.atime = to_time(found.ftLastAccessTime);
info.mtime = to_time(found.ftLastWriteTime);
info.ctime = info.mtime;
@@ -1991,13 +2114,13 @@ fs::file fs::make_gather(std::vector<fs::file> files)
{
}
fs::stat_t stat() override
fs::stat_t get_stat() override
{
fs::stat_t result{};
if (!files.empty())
{
result = files[0].stat();
result = files[0].get_stat();
}
result.is_directory = false;
@@ -2239,9 +2362,19 @@ void fmt_class_string<fs::error>::format(std::string& out, u64 arg)
case fs::error::isdir: return "Is a directory";
case fs::error::toolong: return "Path too long";
case fs::error::nospace: return "Not enough space on the device";
case fs::error::xdev: return "Device mismatch";
case fs::error::unknown: return "Unknown system error";
}
return unknown;
});
}
template<>
void fmt_class_string<fs::file_id>::format(std::string& out, u64 arg)
{
const fs::file_id& id = get_object(arg);
// TODO: Format data
fmt::append(out, "{type='%s'}", id.type);
}
+28 -7
View File
@@ -84,12 +84,22 @@ namespace fs
usz iov_len;
};
struct file_id
{
std::string type;
std::vector<u8> data;
explicit operator bool() const;
bool is_mirror_of(const file_id&) const;
bool is_coherent_with(const file_id&) const;
};
// File handle base
struct file_base
{
virtual ~file_base();
[[noreturn]] virtual stat_t stat();
[[noreturn]] virtual stat_t get_stat();
virtual void sync();
virtual bool trunc(u64 length) = 0;
virtual u64 read(void* buffer, u64 size) = 0;
@@ -98,6 +108,7 @@ namespace fs
virtual u64 seek(s64 offset, seek_mode whence) = 0;
virtual u64 size() = 0;
virtual native_handle get_handle();
virtual file_id get_id();
virtual u64 write_gather(const iovec_clone* buffers, u64 buf_count);
};
@@ -165,11 +176,17 @@ namespace fs
// Set virtual device with specified name (nullptr for deletion)
shared_ptr<device_base> set_virtual_device(const std::string& name, shared_ptr<device_base> device);
// Try to get parent directory (returns empty string on failure)
std::string get_parent_dir(std::string_view path, u32 levels = 1);
// Try to get parent directory
std::string_view get_parent_dir_view(std::string_view path, u32 parent_level = 1);
// String (typical use) version
inline std::string get_parent_dir(std::string_view path, u32 parent_level = 1)
{
return std::string{get_parent_dir_view(path, parent_level)};
}
// Get file information
bool stat(const std::string& path, stat_t& info);
bool get_stat(const std::string& path, stat_t& info);
// Check whether a file or a directory exists (not recommended, use is_file() or is_dir() instead)
bool exists(const std::string& path);
@@ -267,14 +284,14 @@ namespace fs
}
// Get file information
stat_t stat(
stat_t get_stat(
u32 line = __builtin_LINE(),
u32 col = __builtin_COLUMN(),
const char* file = __builtin_FILE(),
const char* func = __builtin_FUNCTION()) const
{
if (!m_file) xnull({line, col, file, func});
return m_file->stat();
return m_file->get_stat();
}
// Sync file buffers
@@ -499,6 +516,9 @@ namespace fs
// Get native handle if available
native_handle get_handle() const;
// Get file ID information (custom ID)
file_id get_id() const;
// Gathered write
u64 write_gather(const iovec_clone* buffers, u64 buf_count,
u32 line = __builtin_LINE(),
@@ -684,6 +704,7 @@ namespace fs
isdir,
toolong,
nospace,
xdev,
unknown
};
@@ -808,7 +829,7 @@ namespace fs
return obj.size();
}
stat_t stat() override
stat_t get_stat() override
{
return m_stat;
}
+1 -1
View File
@@ -1505,7 +1505,7 @@ void jit_compiler::add(const std::string& path)
if (auto object_file = llvm::object::ObjectFile::createObjectFile(*cache))
{
m_engine->addObjectFile( std::move(*object_file) );
m_engine->addObjectFile(llvm::object::OwningBinary<llvm::object::ObjectFile>(std::move(*object_file), std::move(cache)));
}
else
{
+8 -2
View File
@@ -63,7 +63,7 @@ std::string fmt::win_error_to_string(unsigned long error, void* module_handle)
std::string message;
LPWSTR message_buffer = nullptr;
if (FormatMessageW((module_handle ? FORMAT_MESSAGE_FROM_HMODULE : FORMAT_MESSAGE_FROM_SYSTEM) | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS,
module_handle, error, 0, (LPWSTR)&message_buffer, 0, nullptr))
module_handle, error, 0, reinterpret_cast<LPWSTR>(&message_buffer), 0, nullptr))
{
message = fmt::format("%s (0x%x)", fmt::trim(wchar_to_utf8(message_buffer), " \t\n\r\f\v"), error);
}
@@ -589,7 +589,7 @@ std::vector<std::string> fmt::split(std::string_view source, std::initializer_li
return result;
}
std::string fmt::trim(const std::string& source, const std::string& values)
std::string fmt::trim(const std::string& source, std::string_view values)
{
usz begin = source.find_first_not_of(values);
@@ -599,6 +599,12 @@ std::string fmt::trim(const std::string& source, const std::string& values)
return source.substr(begin, source.find_last_not_of(values) + 1);
}
void fmt::trim_back(std::string& source, std::string_view values)
{
const usz index = source.find_last_not_of(values);
source.resize(index + 1);
}
std::string fmt::to_upper(std::string_view string)
{
std::string result;
+21 -1
View File
@@ -124,7 +124,8 @@ namespace fmt
}
std::vector<std::string> split(std::string_view source, std::initializer_list<std::string_view> separators, bool is_skip_empty = true);
std::string trim(const std::string& source, const std::string& values = " \t");
std::string trim(const std::string& source, std::string_view values = " \t");
void trim_back(std::string& source, std::string_view values = " \t");
template <typename T>
std::string merge(const T& source, const std::string& separator)
@@ -186,4 +187,23 @@ namespace fmt
const u8* buf;
usz len;
};
struct string_hash
{
using hash_type = std::hash<std::string_view>;
using is_transparent = void;
std::size_t operator()(const char* str) const
{
return hash_type{}(str);
}
std::size_t operator()(std::string_view str) const
{
return hash_type{}(str);
}
std::size_t operator()(std::string const& str) const
{
return hash_type{}(str);
}
};
}
+7 -11
View File
@@ -110,11 +110,7 @@ std::string dump_useful_thread_info()
if (auto cpu = get_current_cpu_thread())
{
// Wrap it to disable some internal exceptions when printing (not thrown on main thread)
Emu.BlockingCallFromMainThread([&]()
{
cpu->dump_all(result);
});
cpu->dump_all(result);
}
return result;
@@ -1639,7 +1635,7 @@ bool handle_access_violation(u32 addr, bool is_writing, ucontext_t* context) noe
if (!g_tls_access_violation_recovered)
{
vm_log.notice("\n%s", dump_useful_thread_info());
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("[%s] Access violation %s location 0x%x (%s)", cpu->get_name(), is_writing ? "writing" : "reading", addr, (is_writing && vm::check_addr(addr)) ? "read-only memory" : "unmapped memory");
}
// TODO:
@@ -1832,15 +1828,15 @@ static LONG exception_filter(PEXCEPTION_POINTERS pExp) noexcept
const bool s_exception_handler_set = []() -> bool
{
#ifdef USE_ASAN
if (!AddVectoredExceptionHandler(FALSE, (PVECTORED_EXCEPTION_HANDLER)exception_handler))
if (!AddVectoredExceptionHandler(FALSE, static_cast<PVECTORED_EXCEPTION_HANDLER>(exception_handler)))
#else
if (!AddVectoredExceptionHandler(1, (PVECTORED_EXCEPTION_HANDLER)exception_handler))
if (!AddVectoredExceptionHandler(1, static_cast<PVECTORED_EXCEPTION_HANDLER>(exception_handler)))
#endif
{
report_fatal_error("AddVectoredExceptionHandler() failed.");
}
if (!SetUnhandledExceptionFilter((LPTOP_LEVEL_EXCEPTION_FILTER)exception_filter))
if (!SetUnhandledExceptionFilter(static_cast<LPTOP_LEVEL_EXCEPTION_FILTER>(exception_filter)))
{
report_fatal_error("SetUnhandledExceptionFilter() failed.");
}
@@ -2046,7 +2042,7 @@ void thread_base::start()
#ifdef _WIN32
m_thread = ::_beginthreadex(nullptr, 0, entry_point, this, CREATE_SUSPENDED, nullptr);
ensure(m_thread);
ensure(::ResumeThread(reinterpret_cast<HANDLE>(+m_thread)) != -1);
ensure(::ResumeThread(reinterpret_cast<HANDLE>(+m_thread)) != static_cast<DWORD>(-1));
#elif defined(__APPLE__)
pthread_attr_t stack_size_attr;
pthread_attr_init(&stack_size_attr);
@@ -2154,7 +2150,7 @@ u64 thread_base::finalize(thread_state result_state) noexcept
tls_cycles += cycles;
FILETIME ctime, etime, ktime, utime;
GetThreadTimes(GetCurrentThread(), &ctime, &etime, &ktime, &utime);
const u64 time = ((ktime.dwLowDateTime | (u64)ktime.dwHighDateTime << 32) + (utime.dwLowDateTime | (u64)utime.dwHighDateTime << 32)) * 100ull - tls_time;
const u64 time = ((ktime.dwLowDateTime | static_cast<u64>(ktime.dwHighDateTime) << 32) + (utime.dwLowDateTime | static_cast<u64>(utime.dwHighDateTime) << 32)) * 100ull - tls_time;
tls_time += time;
const u64 fsoft = 0;
const u64 fhard = 0;
+151 -30
View File
@@ -77,6 +77,7 @@ void fmt_class_string<patch_type>::format(std::string& out, u64 arg)
case patch_type::lef32: return "lef32";
case patch_type::lef64: return "lef64";
case patch_type::utf8: return "utf8";
case patch_type::c_utf8: return "cutf8";
case patch_type::move_file: return "move_file";
case patch_type::hide_file: return "hide_file";
}
@@ -218,18 +219,18 @@ bool patch_engine::load(patch_map& patches_map, const std::string& path, std::st
// Go through each main key in the file
for (auto pair : root)
{
const auto& main_key = pair.first.Scalar();
const std::string& main_key = pair.first.Scalar();
if (const auto yml_type = pair.second.Type(); yml_type != YAML::NodeType::Map)
if (main_key.empty())
{
append_log_message(log_messages, fmt::format("Error: Skipping key %s: expected Map, found %s (location: %s, file: %s)", main_key, yml_type, get_yaml_node_location(pair.second), path), &patch_log.error);
append_log_message(log_messages, fmt::format("Error: Skipping empty key (location: %s, file: %s)", get_yaml_node_location(pair.first), path), &patch_log.error);
is_valid = false;
continue;
}
if (main_key.empty())
if (const auto yml_type = pair.second.Type(); yml_type != YAML::NodeType::Map)
{
append_log_message(log_messages, fmt::format("Error: Skipping empty key (location: %s, file: %s)", get_yaml_node_location(pair.second), path), &patch_log.error);
append_log_message(log_messages, fmt::format("Error: Skipping key %s: expected Map, found %s (location: %s, file: %s)", main_key, yml_type, get_yaml_node_location(pair.second), path), &patch_log.error);
is_valid = false;
continue;
}
@@ -241,7 +242,7 @@ bool patch_engine::load(patch_map& patches_map, const std::string& path, std::st
}
// Find or create an entry matching the key/hash in our map
auto& container = patches_map[main_key];
patch_container& container = patches_map[main_key];
container.hash = main_key;
container.version = version;
@@ -251,6 +252,13 @@ bool patch_engine::load(patch_map& patches_map, const std::string& path, std::st
// Each key in "Patches" is also the patch description
const std::string& description = patches_entry.first.Scalar();
if (description.empty())
{
append_log_message(log_messages, fmt::format("Error: Empty patch name (key: %s, location: %s, file: %s)", main_key, get_yaml_node_location(patches_entry.first), path), &patch_log.error);
is_valid = false;
continue;
}
// Compile patch information
if (const auto yml_type = patches_entry.second.Type(); yml_type != YAML::NodeType::Map)
@@ -329,7 +337,7 @@ bool patch_engine::load(patch_map& patches_map, const std::string& path, std::st
continue;
}
patch_engine::patch_app_versions app_versions;
patch_app_versions app_versions;
for (const auto version : serial_node.second)
{
@@ -578,6 +586,14 @@ bool patch_engine::load(patch_map& patches_map, const std::string& path, std::st
{
if (!read_patch_node(info, patch_node, root, log_messages))
{
for (const auto& it : patches_entry.second)
{
if (it.first.Scalar() == patch_key::patch)
{
append_log_message(log_messages, fmt::format("Skipping invalid patch node %s: (key: %s, location: %s)", info.description, main_key, get_yaml_node_location(it.first)), &patch_log.error);
break;
}
}
is_valid = false;
}
}
@@ -702,6 +718,33 @@ bool patch_engine::add_patch_data(YAML::Node node, patch_info& info, u32 modifie
std::string error_message;
// Validate offset
switch (p_data.type)
{
case patch_type::move_file:
case patch_type::hide_file:
break;
default:
{
[[maybe_unused]] const u32 offset = get_yaml_node_value<u32>(addr_node, error_message);
if (!error_message.empty())
{
error_message = fmt::format("Skipping patch data entry: [ %s, 0x%.8x, %s ] (key: %s, location: %s) Invalid patch offset '%s' (not a valid u32 or overflow)",
p_data.type, p_data.offset, p_data.original_value.empty() ? "?" : p_data.original_value, info.hash, get_yaml_node_location(node), p_data.original_offset);
append_log_message(log_messages, error_message, &patch_log.error);
return false;
}
if ((0xFFFFFFFF - modifier) < p_data.offset)
{
error_message = fmt::format("Skipping patch data entry: [ %s, 0x%.8x, %s ] (key: %s, location: %s) Invalid combination of patch offset 0x%.8x and modifier 0x%.8x (overflow)",
p_data.type, p_data.offset, p_data.original_value.empty() ? "?" : p_data.original_value, info.hash, get_yaml_node_location(node), p_data.offset, modifier);
append_log_message(log_messages, error_message, &patch_log.error);
return false;
}
break;
}
}
switch (p_data.type)
{
case patch_type::utf8:
@@ -805,7 +848,7 @@ void unmap_vm_area(std::shared_ptr<vm::block_t>& ptr)
}
// Returns old 'applied' size
static usz apply_modification(std::basic_string<u32>& applied, patch_engine::patch_info& patch, u8* dst, u32 filesz, u32 min_addr)
static usz apply_modification(std::basic_string<u32>& applied, patch_engine::patch_info& patch, std::function<u8*(u32, u32)> mem_translate, u32 filesz, u32 min_addr)
{
const usz old_applied_size = applied.size();
@@ -846,8 +889,8 @@ static usz apply_modification(std::basic_string<u32>& applied, patch_engine::pat
{
if (p.type != patch_type::alloc) continue;
// Do not allow null address or if dst is not a VM ptr
if (const u32 alloc_at = vm::try_get_addr(dst + (p.offset & -4096)).first; alloc_at >> 16)
// Do not allow null address or if resultant ptr is not a VM ptr
if (const u32 alloc_at = (p.offset & -4096); alloc_at >> 16)
{
const u32 alloc_size = utils::align(static_cast<u32>(p.value.long_value) + alloc_at % 4096, 4096);
@@ -926,7 +969,74 @@ static usz apply_modification(std::basic_string<u32>& applied, patch_engine::pat
relocate_instructions_at = 0;
}
if (!relocate_instructions_at && (offset < min_addr || offset - min_addr >= filesz))
u32 memory_size = 0;
switch (p.type)
{
case patch_type::invalid:
case patch_type::load:
{
// Invalid in this context
break;
}
case patch_type::alloc:
{
// Applied before
memory_size = 0;
continue;
}
case patch_type::byte:
{
memory_size = sizeof(u8);
break;
}
case patch_type::le16:
case patch_type::be16:
{
memory_size = sizeof(u16);
break;
}
case patch_type::code_alloc:
case patch_type::jump:
case patch_type::jump_link:
case patch_type::jump_func:
case patch_type::le32:
case patch_type::lef32:
case patch_type::bd32:
case patch_type::be32:
case patch_type::bef32:
{
memory_size = sizeof(u32);
break;
}
case patch_type::lef64:
case patch_type::le64:
case patch_type::bd64:
case patch_type::be64:
case patch_type::bef64:
{
memory_size = sizeof(u64);
break;
}
case patch_type::utf8:
{
memory_size = p.original_value.size();
break;
}
case patch_type::c_utf8:
{
memory_size = utils::add_saturate<u32>(p.original_value.size(), 1);
break;
}
case patch_type::move_file:
case patch_type::hide_file:
{
memory_size = 0;
break;
}
}
if (memory_size != 0 && !relocate_instructions_at && (filesz < memory_size || offset < min_addr || offset - min_addr > filesz - memory_size))
{
// This patch is out of range for this segment
continue;
@@ -934,7 +1044,13 @@ static usz apply_modification(std::basic_string<u32>& applied, patch_engine::pat
offset -= min_addr;
auto ptr = dst + offset;
auto ptr = mem_translate(offset, memory_size);
if (!ptr && memory_size != 0 && !relocate_instructions_at)
{
// Memory translation failed
continue;
}
if (relocate_instructions_at)
{
@@ -960,7 +1076,7 @@ static usz apply_modification(std::basic_string<u32>& applied, patch_engine::pat
}
case patch_type::code_alloc:
{
const u32 out_branch = vm::try_get_addr(dst + (offset & -4)).first;
const u32 out_branch = vm::try_get_addr(relocate_instructions_at ? vm::get_super_ptr<u8>(offset & -4) : mem_translate(offset & -4, 4)).first;
// Allow only if points to a PPU executable instruction
if (out_branch < 0x10000 || out_branch >= 0x4000'0000 || !vm::check_addr<4>(out_branch, vm::page_executable))
@@ -1044,7 +1160,7 @@ static usz apply_modification(std::basic_string<u32>& applied, patch_engine::pat
case patch_type::jump:
case patch_type::jump_link:
{
const u32 out_branch = vm::try_get_addr(dst + (offset & -4)).first;
const u32 out_branch = vm::try_get_addr(relocate_instructions_at ? vm::get_super_ptr<u8>(offset & -4) : mem_translate(offset & -4, 4)).first;
const u32 dest = static_cast<u32>(p.value.long_value);
// Allow only if points to a PPU executable instruction
@@ -1060,7 +1176,7 @@ static usz apply_modification(std::basic_string<u32>& applied, patch_engine::pat
{
const std::string& str = p.original_value;
const u32 out_branch = vm::try_get_addr(dst + (offset & -4)).first;
const u32 out_branch = vm::try_get_addr(relocate_instructions_at ? vm::get_super_ptr<u8>(offset & -4) : mem_translate(offset & -4, 4)).first;
const usz sep_pos = str.find_first_of(':');
// Must contain only a single ':' or none
@@ -1076,7 +1192,7 @@ static usz apply_modification(std::basic_string<u32>& applied, patch_engine::pat
if (func_name.starts_with("0x"sv))
{
// Raw hexadeciaml-formatted FNID (real function name cannot contain a digit at the start, derived from C/CPP which were used in PS3 development)
// Raw hexadecimal-formatted FNID (real function name cannot contain a digit at the start, derived from C/CPP which were used in PS3 development)
const auto result = std::from_chars(func_name.data() + 2, func_name.data() + func_name.size() - 2, id, 16);
if (result.ec != std::errc() || str.data() + sep_pos != result.ptr)
@@ -1197,6 +1313,11 @@ static usz apply_modification(std::basic_string<u32>& applied, patch_engine::pat
std::memcpy(ptr, p.original_value.data(), p.original_value.size());
break;
}
case patch_type::c_utf8:
{
std::memcpy(ptr, p.original_value.data(), p.original_value.size() + 1);
break;
}
case patch_type::move_file:
case patch_type::hide_file:
{
@@ -1251,7 +1372,7 @@ static usz apply_modification(std::basic_string<u32>& applied, patch_engine::pat
return old_applied_size;
}
std::basic_string<u32> patch_engine::apply(const std::string& name, u8* dst, u32 filesz, u32 min_addr)
std::basic_string<u32> patch_engine::apply(const std::string& name, std::function<u8*(u32, u32)> mem_translate, u32 filesz, u32 min_addr)
{
if (!m_map.contains(name))
{
@@ -1259,11 +1380,11 @@ std::basic_string<u32> patch_engine::apply(const std::string& name, u8* dst, u32
}
std::basic_string<u32> applied_total;
const auto& container = ::at32(m_map, name);
const auto& serial = Emu.GetTitleID();
const auto& app_version = Emu.GetAppVersion();
const patch_container& container = ::at32(m_map, name);
const std::string& serial = Emu.GetTitleID();
const std::string& app_version = Emu.GetAppVersion();
// Different containers in order to seperate the patches
// Different containers in order to separate the patches
std::vector<std::shared_ptr<patch_info>> patches_for_this_serial_and_this_version;
std::vector<std::shared_ptr<patch_info>> patches_for_this_serial_and_all_versions;
std::vector<std::shared_ptr<patch_info>> patches_for_all_serials_and_this_version;
@@ -1295,7 +1416,7 @@ std::basic_string<u32> patch_engine::apply(const std::string& name, u8* dst, u32
continue;
}
const auto& app_versions = ::at32(serials, found_serial);
const patch_app_versions& app_versions = ::at32(serials, found_serial);
std::string found_app_version;
if (app_versions.contains(app_version))
@@ -1392,7 +1513,7 @@ std::basic_string<u32> patch_engine::apply(const std::string& name, u8* dst, u32
{
if (patch)
{
const usz old_size = apply_modification(applied_total, *patch, dst, filesz, min_addr);
const usz old_size = apply_modification(applied_total, *patch, mem_translate, filesz, min_addr);
if (applied_total.size() != old_size)
{
@@ -1413,11 +1534,11 @@ void patch_engine::unload(const std::string& name)
return;
}
const auto& container = ::at32(m_map, name);
const patch_container& container = ::at32(m_map, name);
for (const auto& [description, patch] : container.patch_info_map)
{
for (auto& entry : patch.data_list)
for (const patch_data& entry : patch.data_list)
{
// Deallocate used memory
if (u32 addr = std::exchange(entry.alloc_addr, 0))
@@ -1545,7 +1666,7 @@ static void append_patches(patch_engine::patch_map& existing_patches, const patc
continue;
}
auto& container = existing_patches[hash];
patch_engine::patch_container& container = existing_patches[hash];
for (const auto& [description, new_info] : new_container.patch_info_map)
{
@@ -1556,7 +1677,7 @@ static void append_patches(patch_engine::patch_map& existing_patches, const patc
continue;
}
auto& info = container.patch_info_map[description];
patch_engine::patch_info& info = container.patch_info_map[description];
bool ok;
const bool version_is_bigger = utils::compare_versions(new_info.patch_version, info.patch_version, ok) > 0;
@@ -1719,7 +1840,7 @@ bool patch_engine::save_patches(const patch_map& patches, const std::string& pat
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;
patch_map existing_patches;
if (load(existing_patches, path, "", true, log_messages))
{
@@ -1732,13 +1853,13 @@ bool patch_engine::import_patches(const patch_engine::patch_map& patches, const
bool patch_engine::remove_patch(const patch_info& info)
{
patch_engine::patch_map patches;
patch_map patches;
if (load(patches, info.source_path))
{
if (patches.contains(info.hash))
{
auto& container = patches[info.hash];
patch_container& container = patches[info.hash];
if (container.patch_info_map.contains(info.description))
{
+4 -2
View File
@@ -3,6 +3,7 @@
#include <vector>
#include <string>
#include <unordered_map>
#include <functional>
#include "util/types.hpp"
#include "util/yaml.hpp"
@@ -52,13 +53,14 @@ enum class patch_type
bef32,
bef64,
utf8, // Text of string (not null-terminated automatically)
c_utf8, // Text of string (null-terminated automatically)
move_file, // Move file
hide_file, // Hide file
};
static constexpr bool patch_type_uses_hex_offset(patch_type type)
{
return type >= patch_type::alloc && type <= patch_type::utf8;
return type >= patch_type::alloc && type <= patch_type::c_utf8;
}
enum class patch_configurable_type
@@ -212,7 +214,7 @@ public:
void append_title_patches(const std::string& title_id);
// Apply patch (returns the number of entries applied)
std::basic_string<u32> apply(const std::string& name, u8* dst, u32 filesz = -1, u32 min_addr = 0);
std::basic_string<u32> apply(const std::string& name, std::function<u8*(u32, u32)> mem_translate, u32 filesz = -1, u32 min_addr = 0);
// Deallocate memory used by patches
void unload(const std::string& name);
+5 -5
View File
@@ -73,12 +73,12 @@ namespace utils
std::vector<std::string> get_backtrace_symbols(const std::vector<void*>& stack)
{
std::vector<std::string> result = {};
std::vector<u8> symbol_buf(sizeof(SYMBOL_INFO) + sizeof(TCHAR) * 256);
std::vector<u8> symbol_buf(sizeof(SYMBOL_INFOW) + sizeof(TCHAR) * 256);
const auto hProcess = ::GetCurrentProcess();
auto sym = reinterpret_cast<SYMBOL_INFO*>(symbol_buf.data());
sym->SizeOfStruct = sizeof(SYMBOL_INFO);
auto sym = reinterpret_cast<SYMBOL_INFOW*>(symbol_buf.data());
sym->SizeOfStruct = sizeof(SYMBOL_INFOW);
sym->MaxNameLen = 256;
IMAGEHLP_LINEW64 line_info{};
@@ -90,7 +90,7 @@ namespace utils
for (const auto& pointer : stack)
{
DWORD64 unused;
SymFromAddr(hProcess, reinterpret_cast<DWORD64>(pointer), &unused, sym);
SymFromAddrW(hProcess, reinterpret_cast<DWORD64>(pointer), &unused, sym);
if (sym->NameLen)
{
@@ -98,7 +98,7 @@ namespace utils
// Attempt to get file and line information if available
DWORD unused2;
if (SymGetLineFromAddrW(hProcess, reinterpret_cast<DWORD64>(pointer), &unused2, &line_info))
if (SymGetLineFromAddrW64(hProcess, reinterpret_cast<DWORD64>(pointer), &unused2, &line_info))
{
const auto full_path = fmt::format("%s:%u %s", wstr_to_utf8(line_info.FileName, -1), line_info.LineNumber, function_name);
result.push_back(full_path);
+3 -3
View File
@@ -65,10 +65,10 @@ jobs:
- job: Windows_Build
variables:
COMPILER: msvc
QT_VER_MAIN: '5'
QT_VER: '5.15.2'
QT_VER_MAIN: '6'
QT_VER: '6.5.2'
QT_VER_MSVC: 'msvc2019'
QT_DATE: '202011130602'
QT_DATE: '202307080351'
QTDIR: C:\Qt\$(QT_VER)\$(QT_VER_MSVC)_64
VULKAN_VER: '1.3.224.1'
VULKAN_SDK_SHA: '2029e652e39ee6a6036cff3765da31e1e6c595fd2413d3cd111dfab7855621ea'
+2 -2
View File
@@ -44,13 +44,13 @@ QLabel#gamelist_icon_background_color {
}
/* log stylesheet */
QTextEdit#tty_frame {
QPlainTextEdit#tty_frame {
background-color:#ffffff;
}
QLabel#tty_text {
color:#000000;
}
QTextEdit#log_frame {
QPlainTextEdit#log_frame {
background-color:#ffffff;
}
QLabel#log_level_always {
@@ -253,7 +253,7 @@ QLabel#thumbnail_icon_color {
}
/* Set Log colors */
QTextEdit#log_frame {
QPlainTextEdit#log_frame {
background-color: #000; /* Black */
}
QLabel#log_level_always {
@@ -285,7 +285,7 @@ QLabel#log_stack {
}
/* Set TTY colors */
QTextEdit#tty_frame {
QPlainTextEdit#tty_frame {
background-color: #000; /* Black */
}
QLabel#tty_text {
@@ -384,3 +384,6 @@ QTreeView::branch:open:has-children:has-siblings:hover {
#game_list_grid_item[focus="true"] #game_list_grid_item_title_label {
background-color: #0078D7;
}
/* Richtext link color */
QLabel#richtext_link_color { color: #87cefa; }
+5 -2
View File
@@ -579,7 +579,7 @@ QLabel#thumbnail_icon_color {
}
/* Log colors */
QTextEdit#log_frame {
QPlainTextEdit#log_frame {
background-color: #23262d;
}
@@ -620,7 +620,7 @@ QLabel#log_stack {
}
/* TTY colors */
QTextEdit#tty_frame {
QPlainTextEdit#tty_frame {
background-color: #23262d;
}
@@ -680,3 +680,6 @@ QTreeView::branch:open:has-children:has-siblings:hover {
background-color: #2d3038;
color: #8cf944;
}
/* Richtext link color */
QLabel#richtext_link_color { color: #8cf944; }
+5 -2
View File
@@ -292,7 +292,7 @@ QLabel#debugger_frame_pc {
}
/* Set Log colors */
QTextEdit#log_frame {
QPlainTextEdit#log_frame {
background-color: #000000; /* Black */
}
QLabel#log_level_always {
@@ -323,7 +323,7 @@ QLabel#log_stack {
color: #ffffff; /* White */
}
/* Set TTY colors */
QTextEdit#tty_frame {
QPlainTextEdit#tty_frame {
background-color: #000000; /* Black */
}
QLabel#tty_text {
@@ -384,3 +384,6 @@ QTreeView::branch:open:has-children:has-siblings:hover {
color: #e6e6e6;
background-color: #4c4b4b;
}
/* Richtext link color */
QLabel#richtext_link_color { color: #87cefa; }
@@ -250,7 +250,7 @@ QLabel#thumbnail_icon_color {
}
/* Set Log colors */
QTextEdit#log_frame {
QPlainTextEdit#log_frame {
background-color: #181d24; /* Black */
}
QLabel#log_level_always {
@@ -282,7 +282,7 @@ QLabel#log_stack {
}
/* Set TTY colors */
QTextEdit#tty_frame {
QPlainTextEdit#tty_frame {
background-color: #181d24; /* Black */
}
QLabel#tty_text {
@@ -381,3 +381,6 @@ QTreeView::branch:open:has-children:has-siblings:hover {
#game_list_grid_item[focus="true"] #game_list_grid_item_title_label {
background-color: #0078D7;
}
/* Richtext link color */
QLabel#richtext_link_color { color: #87cefa; }
@@ -504,3 +504,6 @@ QWidget#trophy_notification_frame {
background-color: #4d4940;
color: #ffd785;
}
/* Richtext link color */
QLabel#richtext_link_color { color: #87cefa; }
+4 -1
View File
@@ -611,7 +611,7 @@ QLineEdit:focus {
}
/* Log colors */
QTextEdit#log_frame {
QPlainTextEdit#log_frame {
background-color: #111525;
}
@@ -720,3 +720,6 @@ QTreeView::branch:open:has-children:has-siblings:hover {
background-color: #0f1d36;
color: #2397ff;
}
/* Richtext link color */
QLabel#richtext_link_color { color: #0074e7; }
+1 -1
View File
@@ -619,7 +619,7 @@ QLineEdit:focus {
}
/* Log colors */
QTextEdit#log_frame {
QPlainTextEdit#log_frame {
background-color: #FFFFFF;
}
+26 -26
View File
@@ -1,9 +1,11 @@
# Check and configure compiler options for RPCS3
if(MSVC)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /Zc:throwingNew- /constexpr:steps16777216 /D _CRT_SECURE_NO_DEPRECATE=1 /D _CRT_NON_CONFORMING_SWPRINTFS=1 /D _SCL_SECURE_NO_WARNINGS=1")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /D NOMINMAX /D _ENABLE_EXTENDED_ALIGNED_STORAGE=1 /D _HAS_EXCEPTIONS=0")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /SUBSYSTEM:WINDOWS /DYNAMICBASE:NO /BASE:0x10000 /FIXED")
add_compile_options(/Zc:throwingNew- /constexpr:steps16777216)
add_compile_definitions(
_CRT_SECURE_NO_DEPRECATE=1 _CRT_NON_CONFORMING_SWPRINTFS=1 _SCL_SECURE_NO_WARNINGS=1
NOMINMAX _ENABLE_EXTENDED_ALIGNED_STORAGE=1 _HAS_EXCEPTIONS=0)
add_link_options(/DYNAMICBASE:NO /BASE:0x10000 /FIXED)
#TODO: Some of these could be cleaned up
add_compile_options(/wd4805) # Comparing boolean and int
@@ -12,19 +14,19 @@ if(MSVC)
add_link_options(/ignore:4281) # Undesirable base address 0x10000
# MSVC 2017 uses iterator as base class internally, causing a lot of warning spam
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /D _SILENCE_CXX17_ITERATOR_BASE_CLASS_DEPRECATION_WARNING=1")
add_compile_definitions(_SILENCE_CXX17_ITERATOR_BASE_CLASS_DEPRECATION_WARNING=1)
# Increase stack limit to 8 MB
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /STACK:8388608,1048576")
add_link_options(/STACK:8388608,1048576)
else()
# Some distros have the compilers set to use PIE by default, but RPCS3 doesn't work with PIE, so we need to disable it.
CHECK_CXX_COMPILER_FLAG("-no-pie" HAS_NO_PIE)
CHECK_CXX_COMPILER_FLAG("-march=native" COMPILER_SUPPORTS_MARCH_NATIVE)
CHECK_CXX_COMPILER_FLAG("-msse -msse2 -mcx16" COMPILER_X86)
check_cxx_compiler_flag("-no-pie" HAS_NO_PIE)
check_cxx_compiler_flag("-march=native" COMPILER_SUPPORTS_MARCH_NATIVE)
check_cxx_compiler_flag("-msse -msse2 -mcx16" COMPILER_X86)
if (APPLE)
CHECK_CXX_COMPILER_FLAG("-march=armv8.4-a" COMPILER_ARM)
check_cxx_compiler_flag("-march=armv8.4-a" COMPILER_ARM)
else()
CHECK_CXX_COMPILER_FLAG("-march=armv8.1-a" COMPILER_ARM)
check_cxx_compiler_flag("-march=armv8.1-a" COMPILER_ARM)
endif()
add_compile_options(-Wall)
@@ -65,24 +67,24 @@ else()
add_compile_options(-Wstrict-aliasing=1)
#add_compile_options(-Wnull-dereference)
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
add_compile_options(-Werror=inconsistent-missing-override)
elseif(${CMAKE_CXX_COMPILER_ID} MATCHES "GNU")
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
add_compile_options(-Werror=suggest-override)
add_compile_options(-Wclobbered)
add_compile_options(-Wcast-function-type)
# add_compile_options(-Wcast-function-type)
add_compile_options(-Wduplicated-branches)
add_compile_options(-Wduplicated-cond)
endif()
#TODO Clean the code so these are removed
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
add_compile_options(-fconstexpr-steps=16777216)
add_compile_options(-Wno-unused-lambda-capture)
add_compile_options(-Wno-unused-private-field)
add_compile_options(-Wno-delete-non-virtual-dtor)
add_compile_options(-Wno-unused-command-line-argument)
elseif(${CMAKE_CXX_COMPILER_ID} MATCHES "GNU")
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
add_compile_options(-Wno-class-memaccess)
endif()
@@ -92,10 +94,10 @@ else()
if(NOT APPLE AND NOT WIN32)
# This hides our LLVM from mesa's LLVM, otherwise we get some unresolvable conflicts.
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wl,--exclude-libs,ALL")
add_link_options(-Wl,--exclude-libs,ALL)
if(HAS_NO_PIE)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -no-pie")
add_link_options(-no-pie)
endif()
elseif(APPLE)
if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
@@ -103,20 +105,18 @@ else()
endif()
if (CMAKE_OSX_ARCHITECTURES MATCHES "x86_64")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-image_base,0x10000 -Wl,-pagezero_size,0x10000")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-no_pie")
add_link_options(-Wl,-image_base,0x10000 -Wl,-pagezero_size,0x10000)
add_link_options(-Wl,-no_pie)
endif()
elseif(WIN32)
set(CMAKE_RC_COMPILER_INIT windres)
enable_language(RC)
set(CMAKE_RC_COMPILE_OBJECT "<CMAKE_RC_COMPILER> <FLAGS> -O coff <DEFINES> -i <SOURCE> -o <OBJECT>")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D__STDC_FORMAT_MACROS=1")
add_compile_definitions(__STDC_FORMAT_MACROS=1)
# Workaround for mingw64 (MSYS2)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wl,--allow-multiple-definition")
add_link_options(-Wl,--allow-multiple-definition)
# Increase stack limit to 8 MB
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wl,--stack -Wl,8388608")
add_link_options(-Wl,--stack -Wl,8388608)
add_link_options(-Wl,--image-base,0x10000)
endif()
endif()
File diff suppressed because it is too large Load Diff
+48 -66
View File
@@ -1,9 +1,4 @@
if(USE_PRECOMPILED_HEADERS AND NOT COMMAND target_precompile_headers)
include(cotire)
endif()
# Define GNU standard installation directories
# Define GNU standard installation directories
include(GNUInstallDirs)
# Generate git-version.h at build time.
@@ -16,10 +11,10 @@ include(CheckFunctionExists)
set(CMAKE_CXX_STANDARD 20)
set(ADDITIONAL_LIBS "")
if(CMAKE_SYSTEM MATCHES "Linux")
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
#on some Linux distros shm_unlink and similar functions are in librt only
set(ADDITIONAL_LIBS ${ADDITIONAL_LIBS} "rt")
elseif(NOT MSVC AND NOT CMAKE_CXX_FLAGS MATCHES "LIBICONV_PLUG")
elseif(NOT WIN32 AND NOT CMAKE_CXX_FLAGS MATCHES "LIBICONV_PLUG")
#it seems like glibc includes the iconv functions we use but other libc
#implementations like the one on OSX don't seem implement them
set(ADDITIONAL_LIBS ${ADDITIONAL_LIBS} "iconv")
@@ -34,24 +29,31 @@ if(UNIX AND NOT APPLE)
endif()
endif()
if(NOT RPCS3_SRC_DIR)
set(RPCS3_SRC_DIR ${CMAKE_CURRENT_LIST_DIR})
message("-- Initializing RPCS3_SRC_DIR=${RPCS3_SRC_DIR}")
else()
message("-- Using Custom RPCS3_SRC_DIR=${RPCS3_SRC_DIR}")
endif()
# Qt5
# Qt
# finds Qt libraries and setups custom commands for MOC and UIC
# Must be done here because generated MOC and UIC targets cant
# be found otherwise
include(${CMAKE_SOURCE_DIR}/3rdparty/qt5.cmake)
include(${CMAKE_SOURCE_DIR}/3rdparty/qt6.cmake)
# subdirectories
add_subdirectory(Emu)
add_subdirectory(rpcs3qt)
set(RPCS3_SRC
if(WIN32)
add_executable(rpcs3 WIN32)
target_sources(rpcs3 PRIVATE rpcs3.rc)
elseif(APPLE)
add_executable(rpcs3 MACOSX_BUNDLE)
target_sources(rpcs3 PRIVATE rpcs3.icns)
set_target_properties(rpcs3
PROPERTIES
MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/rpcs3.plist.in")
else()
add_executable(rpcs3)
endif()
target_sources(rpcs3
PRIVATE
display_sleep_control.cpp
headless_application.cpp
main.cpp
@@ -75,36 +77,20 @@ set(RPCS3_SRC
Input/xinput_pad_handler.cpp
)
if(WIN32)
add_executable(rpcs3 WIN32 ${RPCS3_SRC})
elseif(APPLE)
add_executable(rpcs3 MACOSX_BUNDLE ${RPCS3_SRC} "${RPCS3_SRC_DIR}/rpcs3.icns")
set_target_properties(rpcs3
PROPERTIES
MACOSX_BUNDLE_INFO_PLIST "${RPCS3_SRC_DIR}/rpcs3.plist.in")
else()
add_executable(rpcs3 ${RPCS3_SRC})
endif()
gen_git_version(${RPCS3_SRC_DIR})
gen_git_version(${CMAKE_CURRENT_SOURCE_DIR})
set_target_properties(rpcs3
PROPERTIES
AUTOMOC ON
AUTOUIC ON)
target_link_libraries(rpcs3 rpcs3_emu rpcs3_ui)
target_link_libraries(rpcs3 3rdparty::discordRPC 3rdparty::qt5 3rdparty::hidapi 3rdparty::libusb 3rdparty::wolfssl 3rdparty::libcurl)
target_link_libraries(rpcs3 ${ADDITIONAL_LIBS})
# Win resource file
if(WIN32)
target_sources(rpcs3 PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/rpcs3.rc")
endif()
target_link_libraries(rpcs3 PRIVATE rpcs3_emu rpcs3_ui)
target_link_libraries(rpcs3 PRIVATE 3rdparty::discordRPC 3rdparty::qt6 3rdparty::hidapi 3rdparty::libusb 3rdparty::wolfssl 3rdparty::libcurl 3rdparty::zlib)
target_link_libraries(rpcs3 PRIVATE ${ADDITIONAL_LIBS})
# Unix display manager
if(X11_FOUND)
target_include_directories(rpcs3 PUBLIC ${X11_INCLUDE_DIR})
target_link_libraries(rpcs3 ${X11_LIBRARIES})
target_link_libraries(rpcs3 PRIVATE ${X11_LIBRARIES})
elseif(USE_VULKAN AND UNIX AND NOT WAYLAND_FOUND AND NOT APPLE)
# Wayland has been checked in 3rdparty/CMakeLists.txt already.
message(FATAL_ERROR "RPCS3 requires either X11 or Wayland (or both) for Vulkan.")
@@ -113,30 +99,26 @@ endif()
if(UNIX)
set(CMAKE_THREAD_PREFER_PTHREAD TRUE)
find_package(Threads REQUIRED)
target_link_libraries(rpcs3 Threads::Threads)
target_link_libraries(rpcs3 PRIVATE Threads::Threads)
endif()
if(WIN32)
target_link_libraries(rpcs3 ws2_32.lib Iphlpapi.lib Winmm.lib Psapi.lib gdi32.lib setupapi.lib)
target_link_libraries(rpcs3 PRIVATE ws2_32 Iphlpapi Winmm Psapi gdi32 setupapi pdh)
else()
target_link_libraries(rpcs3 ${CMAKE_DL_LIBS})
target_link_libraries(rpcs3 PRIVATE ${CMAKE_DL_LIBS})
endif()
if(USE_PRECOMPILED_HEADERS)
if(COMMAND target_precompile_headers)
target_precompile_headers(rpcs3 PRIVATE "${RPCS3_SRC_DIR}/stdafx.h")
else()
set_target_properties(rpcs3 PROPERTIES
COTIRE_CXX_PREFIX_HEADER_INIT "${RPCS3_SRC_DIR}/stdafx.h"
COTIRE_ADD_UNITY_BUILD OFF)
cotire(rpcs3)
endif()
target_precompile_headers(rpcs3 PRIVATE stdafx.h)
endif()
get_target_property(_qmake_executable Qt5::qmake IMPORTED_LOCATION)
get_target_property(_qmake_executable Qt6::qmake IMPORTED_LOCATION)
get_filename_component(_qt_bin_dir "${_qmake_executable}" DIRECTORY)
find_program(MACDEPLOYQT_EXECUTABLE macdeployqt HINTS "${_qt_bin_dir}")
if(APPLE)
find_program(MACDEPLOYQT_EXECUTABLE macdeployqt HINTS "${_qt_bin_dir}")
elseif(WIN32)
find_program(WINDEPLOYQT_EXECUTABLE windeployqt HINTS "${_qt_bin_dir}")
endif()
# Copy icons to executable directory
if(APPLE)
@@ -147,7 +129,7 @@ if(APPLE)
endif()
add_custom_command(TARGET rpcs3 POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy
${RPCS3_SRC_DIR}/rpcs3.icns $<TARGET_FILE_DIR:rpcs3>/../Resources/rpcs3.icns
${CMAKE_CURRENT_SOURCE_DIR}/rpcs3.icns $<TARGET_FILE_DIR:rpcs3>/../Resources/rpcs3.icns
COMMAND ${CMAKE_COMMAND} -E copy_directory
${CMAKE_SOURCE_DIR}/bin/Icons $<TARGET_FILE_DIR:rpcs3>/../Resources/Icons
COMMAND ${CMAKE_COMMAND} -E copy_directory
@@ -174,27 +156,27 @@ elseif(WIN32)
# Qt installed from Qt installer has following hierarchy:
# bin/ for release and debug dlls and windeployqt tools
# lib/cmake/Qt5/ for Qt5_Dir
# lib/cmake/Qt6/ for Qt6_Dir
# Qt installed from vcpkg has following hierarchy:
# bin/ for release dlls
# debug/bin/ for debug dlls
# tools/qt5/bin/ for tools including windeployqt
# tools/qt5/debug/bin/ for tools with debug build including windeployqt
# share/cmake/Qt5/ for Qt5_Dir
# tools/qt6/bin/ for tools including windeployqt
# tools/qt6/debug/bin/ for tools with debug build including windeployqt
# share/cmake/Qt6/ for Qt6_Dir
# If Qt5 is installed from official Qt installer
list(APPEND _QT5_TOOLS_PATHS "${Qt5_DIR}/../../../bin/")
# If Qt is installed from official Qt installer
# list(APPEND _QT6_TOOLS_PATHS "${Qt6_DIR}/../../../bin/")
# If Qt5 is installed from vcpkg
list(APPEND _QT5_TOOLS_PATHS "${Qt5_DIR}/../../../tools/qt5$<$<CONFIG:Debug>:/debug>/bin/")
# If Qt is installed from vcpkg
# list(APPEND _QT6_TOOLS_PATHS "${Qt6_DIR}/../../../tools/qt6$<$<CONFIG:Debug>:/debug>/bin/")
add_custom_command(TARGET rpcs3 POST_BUILD
COMMAND set PATH=${_QT5_TOOLS_PATHS}$<SEMICOLON>%PATH%
# COMMAND set PATH=${_QT6_TOOLS_PATHS}$<SEMICOLON>%PATH%
COMMAND "${CMAKE_COMMAND}" -E copy_directory "${CMAKE_SOURCE_DIR}/bin" "$<TARGET_FILE_DIR:rpcs3>"
# If Qt5 is installed from vcpkg, add binary path to PATH
# If Qt is installed from vcpkg, add binary path to PATH
# otherwise windeployqt tool won't be able to locate necessary dlls
COMMAND set PATH=${Qt5_DIR}/../../../$<$<CONFIG:Debug>:debug/>bin/$<SEMICOLON>%PATH%
COMMAND "${_WINDEPLOYQT}" --no-angle --no-compiler-runtime --no-opengl-sw --no-patchqt --no-translations --no-quick --plugindir "$<TARGET_FILE_DIR:rpcs3>/qt/plugins" $<$<CONFIG:Debug>:--debug> $<$<CONFIG:Release>:--release> "$<TARGET_FILE:rpcs3>")
# COMMAND set PATH=${Qt6_DIR}/../../../$<$<CONFIG:Debug>:debug/>bin/$<SEMICOLON>%PATH%
COMMAND "${WINDEPLOYQT_EXECUTABLE}" --no-compiler-runtime --no-opengl-sw --no-patchqt --no-translations --no-quick --no-system-d3d-compiler --no-quick-import --plugindir "$<TARGET_FILE_DIR:rpcs3>/qt6/plugins" --verbose 0 "$<TARGET_FILE:rpcs3>")
endif()
# Unix installation
+57 -50
View File
@@ -11,46 +11,77 @@
LOG_CHANNEL(dec_log, "DECRYPT");
void decrypt_sprx_libraries(std::vector<std::string> modules, std::function<std::string(std::string old_path, std::string path, bool tried)> input_cb)
usz decrypt_binaries_t::decrypt(std::string klic_input)
{
if (modules.empty())
if (m_index >= m_modules.size())
{
std::cout << "No paths specified" << std::endl; // For CLI
return;
m_index = umax;
return umax;
}
dec_log.notice("Decrypting binaries...");
std::cout << "Decrypting binaries..." << std::endl; // For CLI
// Always start with no KLIC
std::vector<u128> klics{u128{}};
if (const auto keys = g_fxo->try_get<loaded_npdrm_keys>())
if (m_klics.empty())
{
// Second klic: get it from a running game
if (const u128 klic = keys->last_key())
dec_log.notice("Decrypting binaries...");
std::cout << "Decrypting binaries..." << std::endl; // For CLI
// Always start with no KLIC
m_klics.emplace_back(u128{});
if (const auto keys = g_fxo->try_get<loaded_npdrm_keys>())
{
klics.emplace_back(klic);
// Second klic: get it from a running game
if (const u128 klic = keys->last_key())
{
m_klics.emplace_back(klic);
}
}
// Try to use the key that has been for the current running ELF
m_klics.insert(m_klics.end(), Emu.klic.begin(), Emu.klic.end());
}
if (std::string_view text = std::string_view{klic_input}.substr(klic_input.find_first_of('x') + 1); text.size() == 32)
{
// Allowed to fail (would simply repeat the operation if fails again)
u64 lo = 0;
u64 hi = 0;
bool success = false;
if (auto res = std::from_chars(text.data() + 0, text.data() + 16, lo, 16); res.ec == std::errc() && res.ptr == text.data() + 16)
{
if (res = std::from_chars(text.data() + 16, text.data() + 32, hi, 16); res.ec == std::errc() && res.ptr == text.data() + 32)
{
success = true;
}
}
if (success)
{
lo = std::bit_cast<be_t<u64>>(lo);
hi = std::bit_cast<be_t<u64>>(hi);
if (u128 input_key = ((u128{hi} << 64) | lo))
{
m_klics.emplace_back(input_key);
}
}
}
// Try to use the key that has been for the current running ELF
klics.insert(klics.end(), Emu.klic.begin(), Emu.klic.end());
for (const std::string& _module : modules)
while (m_index < m_modules.size())
{
const std::string& _module = m_modules[m_index];
const std::string old_path = _module;
fs::file elf_file;
bool tried = false;
bool invalid = false;
usz key_it = 0;
u32 file_magic{};
while (true)
{
for (; key_it < klics.size(); key_it++)
for (; key_it < m_klics.size(); key_it++)
{
if (!elf_file.open(old_path) || !elf_file.read(file_magic))
{
@@ -62,7 +93,7 @@ void decrypt_sprx_libraries(std::vector<std::string> modules, std::function<std:
case "SCE\0"_u32:
{
// First KLIC is no KLIC
elf_file = decrypt_self(std::move(elf_file), key_it != 0 ? reinterpret_cast<u8*>(&klics[key_it]) : nullptr);
elf_file = decrypt_self(std::move(elf_file), key_it != 0 ? reinterpret_cast<u8*>(&m_klics[key_it]) : nullptr);
if (!elf_file)
{
@@ -75,7 +106,7 @@ void decrypt_sprx_libraries(std::vector<std::string> modules, std::function<std:
case "NPD\0"_u32:
{
// EDAT / SDAT
elf_file = DecryptEDAT(elf_file, old_path, key_it != 0 ? 8 : 1, reinterpret_cast<u8*>(&klics[key_it]), true);
elf_file = DecryptEDAT(elf_file, old_path, key_it != 0 ? 8 : 1, reinterpret_cast<u8*>(&m_klics[key_it]), true);
if (!elf_file)
{
@@ -111,11 +142,13 @@ void decrypt_sprx_libraries(std::vector<std::string> modules, std::function<std:
new_file.write(elf_file.to_string());
dec_log.success("Decrypted %s -> %s", old_path, new_path);
std::cout << "Decrypted " << old_path << " -> " << new_path << std::endl; // For CLI
m_index++;
}
else
{
dec_log.error("Failed to create %s", new_path);
std::cout << "Failed to create " << new_path << std::endl; // For CLI
m_index = umax;
}
break;
@@ -124,42 +157,16 @@ void decrypt_sprx_libraries(std::vector<std::string> modules, std::function<std:
if (!invalid)
{
// Allow the user to manually type KLIC if decryption failed
const std::string filename = old_path.substr(old_path.find_last_of(fs::delim) + 1);
const std::string text = input_cb ? input_cb(old_path, filename, tried) : "";
if (!text.empty())
{
auto& klic = (tried ? klics.back() : klics.emplace_back());
ensure(text.size() == 32);
// It must succeed (only hex characters are present)
u64 lo_ = 0;
u64 hi_ = 0;
std::from_chars(&text[0], &text[16], lo_, 16);
std::from_chars(&text[16], &text[32], hi_, 16);
be_t<u64> lo = std::bit_cast<be_t<u64>>(lo_);
be_t<u64> hi = std::bit_cast<be_t<u64>>(hi_);
klic = (u128{+hi} << 64) | +lo;
// Retry with specified KLIC
key_it -= +std::exchange(tried, true); // Rewind on second and above attempt
dec_log.notice("KLIC entered for %s: %s", filename, klic);
continue;
}
dec_log.notice("User has cancelled entering KLIC.");
return m_index;
}
dec_log.error("Failed to decrypt \"%s\".", old_path);
std::cout << "Failed to decrypt \"" << old_path << "\"." << std::endl; // For CLI
break;
return m_index;
}
}
dec_log.notice("Finished decrypting all binaries.");
std::cout << "Finished decrypting all binaries." << std::endl; // For CLI
return m_index;
}
+24 -1
View File
@@ -1,3 +1,26 @@
#pragma once
void decrypt_sprx_libraries(std::vector<std::string> modules, std::function<std::string(std::string old_path, std::string path, bool tried)> input_cb);
class decrypt_binaries_t
{
std::vector<u128> m_klics;
std::vector<std::string> m_modules;
usz m_index = 0;
public:
decrypt_binaries_t(std::vector<std::string> modules) noexcept
: m_modules(std::move(modules))
{
}
usz decrypt(std::string klic_input = {});
bool done() const
{
return m_index >= m_klics.size();
}
const std::string& operator[](usz index) const
{
return ::at32(m_modules, index);
}
};
+65 -101
View File
@@ -5,21 +5,9 @@
#include "utils.h"
#include <cstring>
static void bn_zero(u8* d, u32 n)
static inline int bn_compare(u8* a, u8* b, u32 n)
{
memset(d, 0, n);
}
static void bn_copy(u8* d, u8* a, u32 n)
{
memcpy(d, a, n);
}
static int bn_compare(u8* a, u8* b, u32 n)
{
u32 i;
for (i = 0; i < n; i++)
for (u32 i = 0; i < n; i++)
{
if (a[i] < b[i])
return -1;
@@ -32,14 +20,10 @@ static int bn_compare(u8* a, u8* b, u32 n)
static u8 bn_add_1(u8* d, u8* a, u8* b, u32 n)
{
u32 i;
u32 dig;
u8 c;
c = 0;
for (i = n - 1; i < n; i--)
u8 c = 0;
for (u32 i = n - 1; i != umax; i--)
{
dig = a[i] + b[i] + c;
const u32 dig = a[i] + b[i] + c;
c = dig >> 8;
d[i] = dig;
}
@@ -49,14 +33,10 @@ static u8 bn_add_1(u8* d, u8* a, u8* b, u32 n)
static u8 bn_sub_1(u8* d, u8* a, u8* b, u32 n)
{
u32 i;
u32 dig;
u8 c;
c = 1;
for (i = n - 1; i < n; i--)
u8 c = 1;
for (u32 i = n - 1; i != umax; i--)
{
dig = a[i] + 255 - b[i] + c;
const u32 dig = a[i] + 255 - b[i] + c;
c = dig >> 8;
d[i] = dig;
}
@@ -105,15 +85,12 @@ static constexpr u8 inv256[0x80] = {
static void bn_mon_muladd_dig(u8* d, u8* a, u8 b, u8* N, u32 n)
{
u32 dig;
u32 i;
const u8 z = -(d[n - 1] + a[n - 1] * b) * inv256[N[n - 1] / 2];
dig = d[n - 1] + a[n - 1] * b + N[n - 1] * z;
u32 dig = d[n - 1] + a[n - 1] * b + N[n - 1] * z;
dig >>= 8;
for (i = n - 2; i < n; i--)
for (u32 i = n - 2; i < n; i--)
{
dig += d[i] + a[i] * b + N[i] * z;
d[i + 1] = dig;
@@ -132,21 +109,17 @@ static void bn_mon_muladd_dig(u8* d, u8* a, u8 b, u8* N, u32 n)
static void bn_mon_mul(u8* d, u8* a, u8* b, u8* N, u32 n)
{
u8 t[512];
u32 i;
memset(t, 0, n);
bn_zero(t, n);
for (i = n - 1; i < n; i--)
for (u32 i = n - 1; i != umax; i--)
bn_mon_muladd_dig(t, a, b[i], N, n);
bn_copy(d, t, n);
memcpy(d, t, n);
}
static void bn_to_mon(u8* d, u8* N, u32 n)
{
u32 i;
for (i = 0; i < 8 * n; i++)
for (u32 i = 0; i < 8 * n; i++)
bn_add(d, d, d, N, n);
}
@@ -154,7 +127,7 @@ static void bn_from_mon(u8* d, u8* N, u32 n)
{
u8 t[512];
bn_zero(t, n);
memset(t, 0, n);
t[n - 1] = 1;
bn_mon_mul(d, d, t, N, n);
}
@@ -162,29 +135,29 @@ static void bn_from_mon(u8* d, u8* N, u32 n)
static void bn_mon_exp(u8* d, u8* a, u8* N, u32 n, u8* e, u32 en)
{
u8 t[512];
u32 i;
u8 mask;
bn_zero(d, n);
memset(d, 0, n);
d[n - 1] = 1;
bn_to_mon(d, N, n);
for (i = 0; i < en; i++)
for (mask = 0x80; mask != 0; mask >>= 1)
for (u32 i = 0; i < en; i++)
{
for (u8 mask = 0x80; mask != 0; mask >>= 1)
{
bn_mon_mul(t, d, d, N, n);
if ((e[i] & mask) != 0)
bn_mon_mul(d, t, a, N, n);
else
bn_copy(d, t, n);
memcpy(d, t, n);
}
}
}
static void bn_mon_inv(u8* d, u8* a, u8* N, u32 n)
{
u8 t[512], s[512];
bn_zero(s, n);
memset(s, 0, n);
s[n - 1] = 2;
bn_sub_1(t, N, s, n);
bn_mon_exp(d, a, N, n, t, n);
@@ -203,26 +176,16 @@ static thread_local u8 ec_N[21]{};
static thread_local point ec_G{}; // mon
static thread_local point ec_Q{}; // mon
static thread_local u8 ec_k[21]{};
static thread_local bool ec_curve_initialized{};
static thread_local bool ec_pub_initialized{};
static void elt_copy(u8* d, u8* a)
static inline bool elt_is_zero(u8* d)
{
memcpy(d, a, 20);
}
static void elt_zero(u8* d)
{
memset(d, 0, 20);
}
static int elt_is_zero(u8* d)
{
u32 i;
for (i = 0; i < 20; i++)
for (u32 i = 0; i < 20; i++)
if (d[i] != 0)
return 0;
return false;
return 1;
return true;
}
static void elt_add(u8* d, u8* a, u8* b)
@@ -248,7 +211,7 @@ static void elt_square(u8* d, u8* a)
static void elt_inv(u8* d, u8* a)
{
u8 s[20];
elt_copy(s, a);
memcpy(s, a, 20);
bn_mon_inv(d, s, ec_p, 20);
}
@@ -264,13 +227,13 @@ static void point_from_mon(point* p)
bn_from_mon(p->y, ec_p, 20);
}
static void point_zero(point* p)
static inline void point_zero(point* p)
{
elt_zero(p->x);
elt_zero(p->y);
memset(p->x, 0, 20);
memset(p->y, 0, 20);
}
static int point_is_zero(point* p)
static inline bool point_is_zero(point* p)
{
return elt_is_zero(p->x) && elt_is_zero(p->y);
}
@@ -278,15 +241,13 @@ static int point_is_zero(point* p)
static void point_double(point* r, point* p)
{
u8 s[20], t[20];
point pp;
u8 *px, *py, *rx, *ry;
pp = *p;
point pp = *p;
px = pp.x;
py = pp.y;
rx = r->x;
ry = r->y;
u8* px = pp.x;
u8* py = pp.y;
u8* rx = r->x;
u8* ry = r->y;
if (elt_is_zero(py))
{
@@ -314,30 +275,28 @@ static void point_double(point* r, point* p)
static void point_add(point* r, point* p, point* q)
{
u8 s[20], t[20], u[20];
u8 *px, *py, *qx, *qy, *rx, *ry;
point pp, qq;
pp = *p;
qq = *q;
point pp = *p;
point qq = *q;
px = pp.x;
py = pp.y;
qx = qq.x;
qy = qq.y;
rx = r->x;
ry = r->y;
u8* px = pp.x;
u8* py = pp.y;
u8* qx = qq.x;
u8* qy = qq.y;
u8* rx = r->x;
u8* ry = r->y;
if (point_is_zero(&pp))
{
elt_copy(rx, qx);
elt_copy(ry, qy);
memcpy(rx, qx, 20);
memcpy(ry, qy, 20);
return;
}
if (point_is_zero(&qq))
{
elt_copy(rx, px);
elt_copy(ry, py);
memcpy(rx, px, 20);
memcpy(ry, py, 20);
return;
}
@@ -369,21 +328,20 @@ static void point_add(point* r, point* p, point* q)
static void point_mul(point* d, u8* a, point* b) // a is bignum
{
u32 i;
u8 mask;
point_zero(d);
for (i = 0; i < 21; i++)
for (mask = 0x80; mask != 0; mask >>= 1)
for (u32 i = 0; i < 21; i++)
{
for (u8 mask = 0x80; mask != 0; mask >>= 1)
{
point_double(d, d);
if ((a[i] & mask) != 0)
point_add(d, d, b);
}
}
}
static int check_ecdsa(struct point* Q, u8* R, u8* S, u8* hash)
static bool check_ecdsa(struct point* Q, u8* R, u8* S, u8* hash)
{
u8 Sinv[21];
u8 e[21];
@@ -424,8 +382,10 @@ static int check_ecdsa(struct point* Q, u8* R, u8* S, u8* hash)
return (bn_compare(rr, R, 21) == 0);
}
int ecdsa_set_curve(const u8* p, const u8* a, const u8* b, const u8* N, const u8* Gx, const u8* Gy)
void ecdsa_set_curve(const u8* p, const u8* a, const u8* b, const u8* N, const u8* Gx, const u8* Gy)
{
if (ec_curve_initialized) return;
memcpy(ec_p, p, 20);
memcpy(ec_a, a, 20);
memcpy(ec_b, b, 20);
@@ -438,14 +398,18 @@ int ecdsa_set_curve(const u8* p, const u8* a, const u8* b, const u8* N, const u8
point_to_mon(&ec_G);
return 0;
ec_curve_initialized = true;
}
void ecdsa_set_pub(const u8* Q)
{
if (ec_pub_initialized) return;
memcpy(ec_Q.x, Q, 20);
memcpy(ec_Q.y, Q+20, 20);
memcpy(ec_Q.y, Q + 20, 20);
point_to_mon(&ec_Q);
ec_pub_initialized = true;
}
void ecdsa_set_priv(const u8* k)
@@ -453,7 +417,7 @@ void ecdsa_set_priv(const u8* k)
memcpy(ec_k, k, sizeof ec_k);
}
int ecdsa_verify(u8* hash, u8* R, u8* S)
bool ecdsa_verify(u8* hash, u8* R, u8* S)
{
return check_ecdsa(&ec_Q, R, S, hash);
}
+2 -2
View File
@@ -6,7 +6,7 @@
#include "util/types.hpp"
int ecdsa_set_curve(const u8* p, const u8* a, const u8* b, const u8* N, const u8* Gx, const u8* Gy);
void ecdsa_set_curve(const u8* p, const u8* a, const u8* b, const u8* N, const u8* Gx, const u8* Gy);
void ecdsa_set_pub(const u8* Q);
void ecdsa_set_priv(const u8* k);
int ecdsa_verify(u8* hash, u8* R, u8* S);
bool ecdsa_verify(u8* hash, u8* R, u8* S);
+4
View File
@@ -493,7 +493,9 @@ int check_data(unsigned char *key, EDAT_HEADER *edat, NPD_HEADER *npd, const fs:
memcpy(signature_r + 01, metadata_signature, 0x14);
memcpy(signature_s + 01, metadata_signature + 0x14, 0x14);
if ((!memcmp(signature_r, zero_buf, 0x15)) || (!memcmp(signature_s, zero_buf, 0x15)))
{
edat_log.warning("Metadata signature is invalid!");
}
else
{
// Setup signature hash.
@@ -524,7 +526,9 @@ int check_data(unsigned char *key, EDAT_HEADER *edat, NPD_HEADER *npd, const fs:
memcpy(signature_s + 01, header_signature + 0x14, 0x14);
if ((!memcmp(signature_r, zero_buf, 0x15)) || (!memcmp(signature_s, zero_buf, 0x15)))
{
edat_log.warning("Header signature is invalid!");
}
else
{
// Setup header signature hash.
+9 -2
View File
@@ -95,9 +95,9 @@ public:
bool ReadHeader();
u64 ReadData(u64 pos, u8* data, u64 size);
fs::stat_t stat() override
fs::stat_t get_stat() override
{
fs::stat_t stats = edata_file.stat();
fs::stat_t stats = edata_file.get_stat();
stats.is_writable = false; // TODO
stats.size = file_size;
return stats;
@@ -143,4 +143,11 @@ public:
}
u64 size() override { return file_size; }
fs::file_id get_id() override
{
fs::file_id id = edata_file.get_id();
id.type.insert(0, "EDATADecrypter: "sv);
return id;
}
};
+4 -4
View File
@@ -67,7 +67,7 @@ bool package_reader::read_header()
}
pkg_log.notice("Path: '%s'", m_path);
pkg_log.notice("Header: pkg_magic = 0x%x = \"%s\"", +m_header.pkg_magic, std::string(reinterpret_cast<const char*>(&m_header.pkg_magic), 4));
pkg_log.notice("Header: pkg_magic = 0x%x = \"%s\"", +m_header.pkg_magic, std::string_view(reinterpret_cast<const char*>(&m_header.pkg_magic + 1), 3)); // Skip 0x7F
pkg_log.notice("Header: pkg_type = 0x%x = %d", m_header.pkg_type, m_header.pkg_type);
pkg_log.notice("Header: pkg_platform = 0x%x = %d", m_header.pkg_platform, m_header.pkg_platform);
pkg_log.notice("Header: meta_offset = 0x%x = %d", m_header.meta_offset, m_header.meta_offset);
@@ -94,7 +94,7 @@ bool package_reader::read_header()
return false;
}
pkg_log.notice("Extended header: magic = 0x%x = \"%s\"", +ext_header.magic, std::string(reinterpret_cast<const char*>(&ext_header.magic), 4));
pkg_log.notice("Extended header: magic = 0x%x = \"%s\"", +ext_header.magic, std::string_view(reinterpret_cast<const char*>(&ext_header.magic + 1), 3));
pkg_log.notice("Extended header: unknown_1 = 0x%x = %d", ext_header.unknown_1, ext_header.unknown_1);
pkg_log.notice("Extended header: ext_hdr_size = 0x%x = %d", ext_header.ext_hdr_size, ext_header.ext_hdr_size);
pkg_log.notice("Extended header: ext_data_size = 0x%x = %d", ext_header.ext_data_size, ext_header.ext_data_size);
@@ -782,7 +782,7 @@ bool package_reader::fill_data(std::map<std::string, install_entry*>& all_instal
const bool is_psp = (entry.type & PKG_FILE_ENTRY_PSP) != 0u;
decrypt(entry.name_offset, entry.name_size, is_psp ? PKG_AES_KEY2 : m_dec_key.data());
const std::string name{reinterpret_cast<char*>(m_bufs.back().get()), entry.name_size};
const std::string_view name{reinterpret_cast<char*>(m_bufs.back().get()), entry.name_size};
std::string path = m_install_path + vfs::escape(name);
if (entry.pad || (entry.type & ~PKG_FILE_ENTRY_KNOWN_BITS))
@@ -833,7 +833,7 @@ bool package_reader::fill_data(std::map<std::string, install_entry*>& all_instal
m_install_entries.push_back({
.weak_reference = map_ptr,
.name = name,
.name = std::string(name),
.file_offset = entry.file_offset,
.file_size = entry.file_size,
.type = entry.type,
+2 -2
View File
@@ -871,7 +871,7 @@ bool SELFDecrypter::LoadHeaders(bool isElf32, SelfAdditionalInfo* out_info)
if (out_info)
{
out_info->valid = false;
*out_info = {};
}
// Check SCE magic.
@@ -1411,7 +1411,7 @@ fs::file decrypt_self(fs::file elf_or_self, u8* klic_key, SelfAdditionalInfo* ou
{
if (out_info)
{
out_info->valid = false;
*out_info = {};
}
if (!elf_or_self)
+1 -1
View File
@@ -158,6 +158,6 @@ AudioChannelCnt AudioBackend::convert_channel_count(u64 raw)
case 1:
return AudioChannelCnt::STEREO;
case 0:
fmt::throw_exception("Usupported channel count");
fmt::throw_exception("Unsupported channel count");
}
}
+1 -1
View File
@@ -543,7 +543,7 @@ void CubebBackend::device_collection_changed_cb(cubeb* context, void* user_ptr)
if (context != cubeb->m_ctx)
{
Cubeb.error("device_collection_changed_cb called with unkown context");
Cubeb.error("device_collection_changed_cb called with unknown context");
return;
}
@@ -12,7 +12,13 @@
#include <Windows.h>
#include <system_error>
#ifdef _MSC_VER
#pragma comment(lib, "xaudio2_9redist.lib")
#endif
#ifndef XAUDIO2_USE_DEFAULT_PROCESSOR
#define XAUDIO2_USE_DEFAULT_PROCESSOR XAUDIO2_DEFAULT_PROCESSOR
#endif
LOG_CHANNEL(XAudio);
@@ -26,6 +32,7 @@ void fmt_class_string<ERole>::format(std::string& out, u64 arg)
case eConsole: return "eConsole";
case eMultimedia: return "eMultimedia";
case eCommunications: return "eCommunications";
case ERole_enum_count: return unknown;
}
return unknown;
@@ -42,6 +49,7 @@ void fmt_class_string<EDataFlow>::format(std::string& out, u64 arg)
case eRender: return "eRender";
case eCapture: return "eCapture";
case eAll: return "eAll";
case EDataFlow_enum_count: return unknown;
}
return unknown;
@@ -309,9 +317,12 @@ f64 XAudio2Backend::GetCallbackFrameLen()
return _10ms;
}
#if _MSC_VER
Microsoft::WRL::ComPtr<IXAudio2Extension> xaudio_ext{};
#endif
f64 min_latency{};
#if _MSC_VER
if (HRESULT hr = m_xaudio2_instance->QueryInterface(IID_IXAudio2Extension, std::bit_cast<void**>(xaudio_ext.GetAddressOf())); FAILED(hr))
{
XAudio.error("QueryInterface() failed: %s (0x%08x)", std::system_category().message(hr), static_cast<u32>(hr));
@@ -326,6 +337,7 @@ f64 XAudio2Backend::GetCallbackFrameLen()
min_latency = static_cast<f64>(samples_per_q) / freq;
}
}
#endif
return std::max<f64>(min_latency, _10ms); // 10ms is the minimum for XAudio
}
+4
View File
@@ -8,7 +8,11 @@
#include "Utilities/mutex.h"
#include "Emu/Audio/AudioBackend.h"
#ifdef _MSC_VER
#include <xaudio2redist.h>
#else
#include <xaudio2.h>
#endif
#include <wrl/client.h>
#include <MMDeviceAPI.h>
+1
View File
@@ -6,6 +6,7 @@
#ifndef _MSC_VER
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wsuggest-override"
#pragma GCC diagnostic ignored "-Wold-style-cast"
#endif
#include "SoundTouch.h"
#ifndef _MSC_VER
+34 -25
View File
@@ -1,4 +1,4 @@
add_library(rpcs3_emu
add_library(rpcs3_emu STATIC
cache_utils.cpp
games_config.cpp
IdManager.cpp
@@ -19,8 +19,9 @@ add_library(rpcs3_emu
IPC_socket.cpp
)
# prevent WolfSSL from warning about not having harden options
add_compile_definitions(WC_NO_HARDEN)
if(USE_ASAN)
set_source_files_properties(../../Utilities/Thread.cpp PROPERTIES COMPILE_DEFINITIONS USE_ASAN)
endif()
target_link_libraries(rpcs3_emu
PRIVATE
@@ -36,7 +37,7 @@ target_link_libraries(rpcs3_emu
# For stdafx.h
target_include_directories(rpcs3_emu
PUBLIC
${RPCS3_SRC_DIR})
${PROJECT_SOURCE_DIR}/rpcs3)
# Utilities
target_sources(rpcs3_emu PRIVATE
@@ -78,15 +79,27 @@ target_link_libraries(rpcs3_emu
3rdparty::pugixml)
if(MSVC)
set_source_files_properties("../../Utilities/JIT.cpp" PROPERTIES COMPILE_FLAGS /GR-)
set_source_files_properties("../../Utilities/JIT.cpp" PROPERTIES
COMPILE_FLAGS /GR-
SKIP_PRECOMPILE_HEADERS ON
)
else()
set_source_files_properties("../../Utilities/JIT.cpp" PROPERTIES COMPILE_FLAGS -fno-rtti)
set_source_files_properties("../../Utilities/JIT.cpp" PROPERTIES
COMPILE_FLAGS -fno-rtti
SKIP_PRECOMPILE_HEADERS ON
)
endif()
if(MSVC)
set_source_files_properties("../util/yaml.cpp" PROPERTIES COMPILE_FLAGS /EHsc)
set_source_files_properties("../util/yaml.cpp" PROPERTIES
COMPILE_FLAGS /EHsc
SKIP_PRECOMPILE_HEADERS ON
)
else()
set_source_files_properties("../util/yaml.cpp" PROPERTIES COMPILE_FLAGS -fexceptions)
set_source_files_properties("../util/yaml.cpp" PROPERTIES
COMPILE_FLAGS -fexceptions
SKIP_PRECOMPILE_HEADERS ON
)
endif()
# Crypto
@@ -139,9 +152,13 @@ if(USE_FAUDIO)
endif()
if(WIN32)
target_include_directories(rpcs3_emu PUBLIC "${RPCS3_SRC_DIR}/../3rdparty/XAudio2Redist/include")
target_link_libraries(rpcs3_emu PRIVATE "${RPCS3_SRC_DIR}/../3rdparty/XAudio2Redist/libs/xaudio2_9redist.lib")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /DELAYLOAD:xaudio2_9redist.dll")
target_include_directories(rpcs3_emu PUBLIC "${PROJECT_SOURCE_DIR}/3rdparty/XAudio2Redist/include")
if(MSVC)
target_link_libraries(rpcs3_emu PRIVATE "${PROJECT_SOURCE_DIR}/3rdparty/XAudio2Redist/libs/xaudio2_9redist.lib")
target_link_options(rpcs3_emu PRIVATE /DELAYLOAD:xaudio2_9redist.dll)
else()
target_link_libraries(rpcs3_emu PRIVATE xaudio2_8)
endif()
target_sources(rpcs3_emu PRIVATE
Audio/XAudio2/XAudio2Backend.cpp
Audio/XAudio2/xaudio2_enumerator.cpp
@@ -366,7 +383,10 @@ target_sources(rpcs3_emu PRIVATE
)
if(NOT MSVC)
set_source_files_properties(Cell/PPUTranslator.cpp PROPERTIES COMPILE_FLAGS -fno-rtti)
set_source_files_properties(Cell/PPUTranslator.cpp PROPERTIES
COMPILE_FLAGS -fno-rtti
SKIP_PRECOMPILE_HEADERS ON
)
endif()
target_link_libraries(rpcs3_emu
@@ -576,23 +596,12 @@ target_link_libraries(rpcs3_emu
if(APPLE)
check_function_exists(clock_gettime HAVE_CLOCK_GETTIME)
if (${HAVE_CLOCK_GETTIME})
if (HAVE_CLOCK_GETTIME)
target_compile_definitions(rpcs3_emu PUBLIC -DHAVE_CLOCK_GETTIME)
endif()
endif()
if(USE_PRECOMPILED_HEADERS)
if(COMMAND target_precompile_headers)
target_precompile_headers(rpcs3_emu PRIVATE "${RPCS3_SRC_DIR}/stdafx.h")
else()
# Setup cotire
option(UNITY_BUILD_EMU "Use unity build for rpcs3_emu target" OFF)
set_target_properties(rpcs3_emu PROPERTIES
COTIRE_CXX_PREFIX_HEADER_INIT "${RPCS3_SRC_DIR}/stdafx.h"
COTIRE_ADD_UNITY_BUILD ${UNITY_BUILD_EMU})
cotire(rpcs3_emu)
endif()
target_precompile_headers(rpcs3_emu PRIVATE "${PROJECT_SOURCE_DIR}/rpcs3/stdafx.h")
endif()
+34 -10
View File
@@ -682,6 +682,7 @@ static atomic_t<u32> s_dummy_atomic = 0;
bool cpu_thread::check_state() noexcept
{
bool cpu_sleep_called = false;
bool cpu_memory_checked = false;
bool cpu_can_stop = true;
bool escape{}, retval{};
@@ -770,7 +771,7 @@ bool cpu_thread::check_state() noexcept
if (!is_stopped(flags) && flags.none_of(cpu_flag::ret))
{
// Check pause flags which hold thread inside check_state (ignore suspend/debug flags on cpu_flag::temp)
if (flags & (cpu_flag::pause + cpu_flag::memory) || (cpu_can_stop && flags & (cpu_flag::dbg_global_pause + cpu_flag::dbg_pause + cpu_flag::suspend + cpu_flag::yield + cpu_flag::preempt)))
if (flags & cpu_flag::pause || (!cpu_memory_checked && flags & cpu_flag::memory) || (cpu_can_stop && flags & (cpu_flag::dbg_global_pause + cpu_flag::dbg_pause + cpu_flag::suspend + cpu_flag::yield + cpu_flag::preempt)))
{
if (!(flags & cpu_flag::wait))
{
@@ -789,12 +790,25 @@ bool cpu_thread::check_state() noexcept
return store;
}
if (flags & cpu_flag::wait)
if (flags & (cpu_flag::wait + cpu_flag::memory))
{
flags -= cpu_flag::wait;
flags -= (cpu_flag::wait + cpu_flag::memory);
store = true;
}
if (s_tls_thread_slot == umax)
{
if (cpu_flag::wait - this->state.load())
{
// Force wait flag (must be set during ownership of s_cpu_lock), this makes the atomic op fail as a side effect
this->state += cpu_flag::wait;
store = true;
}
// Restore thread in the suspend list
cpu_counter::add(this);
}
retval = false;
}
else
@@ -843,10 +857,12 @@ bool cpu_thread::check_state() noexcept
if (escape)
{
if (s_tls_thread_slot == umax && !retval)
if (vm::g_range_lock_bits[1] && vm::g_tls_locked && *vm::g_tls_locked == this)
{
// Restore thread in the suspend list
cpu_counter::add(this);
state += cpu_flag::wait + cpu_flag::memory;
cpu_sleep_called = false;
cpu_memory_checked = false;
continue;
}
if (cpu_can_stop && state0 & cpu_flag::pending)
@@ -859,6 +875,7 @@ bool cpu_thread::check_state() noexcept
// Work could have changed flags
// Reset internal flags as if check_state() has just been called
cpu_sleep_called = false;
cpu_memory_checked = false;
continue;
}
}
@@ -876,6 +893,7 @@ bool cpu_thread::check_state() noexcept
{
cpu_sleep();
cpu_sleep_called = true;
cpu_memory_checked = false;
if (s_tls_thread_slot != umax)
{
@@ -900,6 +918,7 @@ bool cpu_thread::check_state() noexcept
if (state0 & cpu_flag::memory)
{
vm::passive_lock(*this);
cpu_memory_checked = true;
continue;
}
@@ -997,7 +1016,7 @@ cpu_thread& cpu_thread::operator=(thread_state)
{
if (u32 resv = atomic_storage<u32>::load(thread->raddr))
{
vm::reservation_notifier(resv).notify_one();
vm::reservation_notifier(resv).notify_all(-128);
}
}
}
@@ -1093,9 +1112,11 @@ std::shared_ptr<CPUDisAsm> make_disasm(const cpu_thread* cpu);
void cpu_thread::dump_all(std::string& ret) const
{
std::any func_data;
ret += dump_misc();
ret += '\n';
dump_regs(ret);
dump_regs(ret, func_data);
ret += '\n';
ret += dump_callstack();
ret += '\n';
@@ -1118,7 +1139,7 @@ void cpu_thread::dump_all(std::string& ret) const
}
}
void cpu_thread::dump_regs(std::string&) const
void cpu_thread::dump_regs(std::string&, std::any&) const
{
}
@@ -1312,7 +1333,10 @@ bool cpu_thread::suspend_work::push(cpu_thread* _this) noexcept
void cpu_thread::cleanup() noexcept
{
ensure(!s_cpu_counter);
if (u64 count = s_cpu_counter)
{
fmt::throw_exception("cpu_thread::cleanup(): %u threads are still active! (created=%u, destroyed=%u)", count, +g_threads_created, +g_threads_deleted);
}
sys_log.notice("All CPU threads have been stopped. [+: %u]", +g_threads_created);
+2 -1
View File
@@ -4,6 +4,7 @@
#include "../Utilities/bit_set.h"
#include <vector>
#include <any>
template <typename Derived, typename Base>
concept DerivedFrom = std::is_base_of_v<Base, Derived> &&
@@ -159,7 +160,7 @@ public:
virtual void dump_all(std::string&) const;
// Get CPU register dump
virtual void dump_regs(std::string&) const;
virtual void dump_regs(std::string& ret, std::any& custom_data) const;
// Get CPU call stack dump
virtual std::string dump_callstack() const;
+1 -1
View File
@@ -70,5 +70,5 @@ void fmt_class_string<spu_mfc_cmd>::format(std::string& out, u64 arg)
const u8 tag = cmd.tag;
fmt::append(out, "%s #%02u 0x%05x:0x%08llx 0x%x%s", cmd.cmd, tag & 0x7f, cmd.lsa, u64{cmd.eah} << 32 | cmd.eal, cmd.size, (tag & 0x80) ? " (stalled)" : "");
fmt::append(out, "%-8s #%02u 0x%05x:0x%08llx 0x%x%s", cmd.cmd, tag & 0x7f, cmd.lsa, u64{cmd.eah} << 32 | cmd.eal, cmd.size, (tag & 0x80) ? " (stalled)" : "");
}
+2 -2
View File
@@ -202,7 +202,7 @@ error_code cellVideoOutSetupDisplay(u32 videoOut)
error_code cellAudioInGetDeviceInfo(u32 deviceNumber, u32 deviceIndex, vm::ptr<CellAudioInDeviceInfo> info)
{
cellAvconfExt.todo("cellAudioInGetDeviceInfo(deviceNumber=0x%x, deviceIndex=0x%x, info=*0x%x)", deviceNumber, deviceIndex, info);
cellAvconfExt.trace("cellAudioInGetDeviceInfo(deviceNumber=0x%x, deviceIndex=0x%x, info=*0x%x)", deviceNumber, deviceIndex, info);
if (deviceIndex != 0 || !info)
{
@@ -277,7 +277,7 @@ error_code cellVideoOutGetGamma(u32 videoOut, vm::ptr<f32> gamma)
error_code cellAudioInGetAvailableDeviceInfo(u32 count, vm::ptr<CellAudioInDeviceInfo> device_info)
{
cellAvconfExt.todo("cellAudioInGetAvailableDeviceInfo(count=%d, info=*0x%x)", count, device_info);
cellAvconfExt.trace("cellAudioInGetAvailableDeviceInfo(count=%d, info=*0x%x)", count, device_info);
if (count > 16 || !device_info)
{
-1
View File
@@ -1891,7 +1891,6 @@ bool camera_context::on_handler_state(camera_handler_base::camera_handler_state
{
switch (state)
{
case camera_handler_base::camera_handler_state::not_available:
case camera_handler_base::camera_handler_state::closed:
{
if (is_attached)
+1 -11
View File
@@ -335,17 +335,7 @@ public:
[[maybe_unused]] const s32 version = GET_OR_USE_SERIALIZATION_VERSION(ar.is_writing(), cellGem);
ar(attribute, vc_attribute, status_flags, enable_pitch_correction, inertial_counter, controllers
, connected_controllers, update_started, camera_frame, memory_ptr);
if (version == 1 && !ar.is_writing())
{
u32 ts = ar;
start_timestamp_us = ts;
}
else
{
ar(start_timestamp_us);
}
, connected_controllers, update_started, camera_frame, memory_ptr, start_timestamp_us);
}
gem_config_data(utils::serial& ar)
+3 -1
View File
@@ -7,8 +7,10 @@
#ifdef _WIN32
#include <windows.h>
#include <codecvt>
#ifdef _MSC_VER
#pragma comment(lib, "Winhttp.lib")
#endif
#endif
LOG_CHANNEL(cellHttpUtil);
@@ -130,7 +132,7 @@ error_code cellHttpUtilParseUri(vm::ptr<CellHttpUri> uri, vm::cptr<char> str, vm
parseError = "Error, URI didn't contain a slash";
break;
default:
parseError = "Error, unkown error #" + std::to_string(static_cast<int>(URL.m_ErrorCode));
parseError = "Error, unknown error #" + std::to_string(static_cast<int>(URL.m_ErrorCode));
break;
}
cellHttpUtil.error("%s, while parsing URI, %s.", parseError, str.get_ptr());
+6 -6
View File
@@ -6,7 +6,7 @@
#include <Windows.h>
#endif
#ifdef _MSC_VER
#ifdef _WIN32
typedef int HostCode;
#else
#include <iconv.h>
@@ -24,7 +24,7 @@ LOG_CHANNEL(cellL10n);
// If this makes your compilation fail, try replace the string code with one in "iconv -l"
bool _L10nCodeParse(s32 code, HostCode& retCode)
{
#ifdef _MSC_VER
#ifdef _WIN32
retCode = 0;
if ((code >= _L10N_CODE_) || (code < 0)) return false;
switch (code)
@@ -161,7 +161,7 @@ bool _L10nCodeParse(s32 code, HostCode& retCode)
#endif
}
#ifdef _MSC_VER
#ifdef _WIN32
// Use code page to transform std::string to std::wstring.
s32 _OEM2Wide(HostCode oem_code, const std::string& src, std::wstring& dst)
@@ -206,7 +206,7 @@ std::string _OemToOem(HostCode src_code, HostCode dst_code, const std::string& s
#endif
s32 _ConvertStr(s32 src_code, const void *src, s32 src_len, s32 dst_code, void *dst, s32 *dst_len, bool allowIncomplete)
s32 _ConvertStr(s32 src_code, const void *src, s32 src_len, s32 dst_code, void *dst, s32 *dst_len, [[maybe_unused]] bool allowIncomplete)
{
HostCode srcCode = 0, dstCode = 0; //OEM code pages
bool src_page_converted = _L10nCodeParse(src_code, srcCode); //Check if code is in list.
@@ -216,13 +216,13 @@ s32 _ConvertStr(s32 src_code, const void *src, s32 src_len, s32 dst_code, void *
|| ((!dst_page_converted) && (dstCode == 0)))
return ConverterUnknown;
#ifdef _MSC_VER
#ifdef _WIN32
const std::string wrapped_source = std::string(static_cast<const char *>(src), src_len);
const std::string target = _OemToOem(srcCode, dstCode, wrapped_source);
if (dst != nullptr)
{
if (target.length() > *dst_len) return DSTExhausted;
if (target.length() > static_cast<usz>(*dst_len)) return DSTExhausted;
memcpy(dst, target.c_str(), target.length());
}
*dst_len = ::narrow<s32>(target.size());
+5 -3
View File
@@ -214,9 +214,9 @@ error_code open_msg_dialog(bool is_blocking, u32 type, vm::cptr<char> msgString,
dlg->type = _type;
dlg->on_close = [callback, userData, &return_code, wptr = std::weak_ptr<MsgDialogBase>(dlg)](s32 status)
dlg->on_close = [callback, userData, is_blocking, &return_code, wptr = std::weak_ptr<MsgDialogBase>(dlg)](s32 status)
{
if (return_code)
if (is_blocking && return_code)
{
*return_code = status;
}
@@ -533,13 +533,15 @@ error_code cellMsgDialogAbort()
sysutil_send_system_cmd(CELL_SYSUTIL_DRAWING_END, 0);
return CELL_OK;
}
return CELL_OK; // Not CELL_MSGDIALOG_ERROR_DIALOG_NOT_OPENED, tested on HW.
}
const auto dlg = g_fxo->get<msg_info>().get();
if (!dlg)
{
return CELL_MSGDIALOG_ERROR_DIALOG_NOT_OPENED;
return CELL_OK; // Not CELL_MSGDIALOG_ERROR_DIALOG_NOT_OPENED, tested on HW.
}
if (!dlg->state.compare_and_swap_test(MsgDialogState::Open, MsgDialogState::Abort))
+1 -1
View File
@@ -155,7 +155,7 @@ error_code select_photo(std::string dst_dir)
{
fs::stat_t f_info{};
if (!fs::stat(info.path, f_info) || f_info.is_directory)
if (!fs::get_stat(info.path, f_info) || f_info.is_directory)
{
cellPhotoImportUtil.error("Path does not belong to a valid file: '%s'", info.path);
result = CELL_PHOTO_IMPORT_ERROR_ACCESS_ERROR; // TODO: is this correct ?
+15 -10
View File
@@ -864,7 +864,7 @@ static NEVER_INLINE error_code savedata_op(ppu_thread& ppu, u32 operation, u32 v
if (listSet->fixedListNum > CELL_SAVEDATA_LISTITEM_MAX)
{
// ****** sysutil savedata parameter error : 38 ******
return {CELL_SAVEDATA_ERROR_PARAM, "38"};
return {CELL_SAVEDATA_ERROR_PARAM, "38 (fixedListNum=%d)", listSet->fixedListNum};
}
if (listSet->fixedListNum && !listSet->fixedList)
@@ -921,7 +921,7 @@ static NEVER_INLINE error_code savedata_op(ppu_thread& ppu, u32 operation, u32 v
default:
{
// ****** sysutil savedata parameter error : 43 ******
return {CELL_SAVEDATA_ERROR_PARAM, "43"};
return {CELL_SAVEDATA_ERROR_PARAM, "43 (iconPosition=0x%x)", listSet->newData->iconPosition};
}
}
@@ -1316,7 +1316,7 @@ static NEVER_INLINE error_code savedata_op(ppu_thread& ppu, u32 operation, u32 v
default :
// ****** sysutil savedata parameter error : 81 ******
return {CELL_SAVEDATA_ERROR_PARAM, "81"};
return {CELL_SAVEDATA_ERROR_PARAM, "81 (option=0x%x)", fixedSet->option};
}
if (selected == -1)
@@ -1380,6 +1380,7 @@ static NEVER_INLINE error_code savedata_op(ppu_thread& ppu, u32 operation, u32 v
bool recreated = false;
lv2_sleep(ppu, 250);
ppu.state += cpu_flag::wait;
// Check if RPCS3_BLIST section exist in PARAM.SFO
// This section contains the list of files in the save ordered as they would be in BSD filesystem
@@ -1397,7 +1398,7 @@ static NEVER_INLINE error_code savedata_op(ppu_thread& ppu, u32 operation, u32 v
}
fs::stat_t dir_info{};
if (!fs::stat(dir_path, dir_info))
if (!fs::get_stat(dir_path, dir_info))
{
// funcStat is called even if the directory doesn't exist.
}
@@ -1523,6 +1524,7 @@ static NEVER_INLINE error_code savedata_op(ppu_thread& ppu, u32 operation, u32 v
// Stat Callback
funcStat(ppu, result, statGet, statSet);
ppu.state += cpu_flag::wait;
if (const s32 res = result->result; res != CELL_SAVEDATA_CBRESULT_OK_NEXT)
{
@@ -1542,7 +1544,7 @@ static NEVER_INLINE error_code savedata_op(ppu_thread& ppu, u32 operation, u32 v
if (statSet->setParam->attribute > CELL_SAVEDATA_ATTR_NODUPLICATE)
{
// ****** sysutil savedata parameter error : 57 ******
return {CELL_SAVEDATA_ERROR_PARAM, "57"};
return {CELL_SAVEDATA_ERROR_PARAM, "57 (attribute=0x%x)", statSet->setParam->attribute};
}
if (g_ps3_process_info.sdk_ver > 0x36FFFF)
@@ -1551,7 +1553,7 @@ static NEVER_INLINE error_code savedata_op(ppu_thread& ppu, u32 operation, u32 v
if (statSet->setParam->parental_level)
{
// ****** sysutil savedata parameter error : 58 ******
return {CELL_SAVEDATA_ERROR_PARAM, "58"};
return {CELL_SAVEDATA_ERROR_PARAM, "58 (sdk_ver=0x%x, parental_level=%d)", g_ps3_process_info.sdk_ver, statSet->setParam->parental_level};
}
}
else
@@ -1559,7 +1561,7 @@ static NEVER_INLINE error_code savedata_op(ppu_thread& ppu, u32 operation, u32 v
if (statSet->setParam->parental_level > 11)
{
// ****** sysutil savedata parameter error : 58 ******
return {CELL_SAVEDATA_ERROR_PARAM, "58"};
return {CELL_SAVEDATA_ERROR_PARAM, "58 (sdk_ver=0x%x, parental_level=%d)", g_ps3_process_info.sdk_ver, statSet->setParam->parental_level};
}
}
@@ -1689,6 +1691,7 @@ static NEVER_INLINE error_code savedata_op(ppu_thread& ppu, u32 operation, u32 v
std::memset(result.get_ptr(), 0, ::offset32(&CellSaveDataCBResult::userdata));
funcFile(ppu, result, fileGet, fileSet);
ppu.state += cpu_flag::wait;
if (const s32 res = result->result; res != CELL_SAVEDATA_CBRESULT_OK_NEXT)
{
@@ -2045,7 +2048,7 @@ static NEVER_INLINE error_code savedata_get_list_item(vm::cptr<char> dirName, vm
else if (userId > CELL_USERINFO_USER_MAX)
{
// ****** sysutil savedata parameter error : 137 ******
return {CELL_SAVEDATA_ERROR_PARAM, "137"};
return {CELL_SAVEDATA_ERROR_PARAM, "137 (userId=0x%x)", userId};
}
if (!dirName)
@@ -2099,7 +2102,7 @@ static NEVER_INLINE error_code savedata_get_list_item(vm::cptr<char> dirName, vm
if (dir)
{
fs::stat_t dir_info{};
if (!fs::stat(save_path, dir_info))
if (!fs::get_stat(save_path, dir_info))
{
return CELL_SAVEDATA_ERROR_INTERNAL;
}
@@ -2406,8 +2409,10 @@ error_code cellSaveDataFixedExport(ppu_thread& ppu, vm::cptr<char> dirName, u32
return CELL_OK;
}
error_code cellSaveDataGetListItem(vm::cptr<char> dirName, vm::ptr<CellSaveDataDirStat> dir, vm::ptr<CellSaveDataSystemFileParam> sysFileParam, vm::ptr<u32> bind, vm::ptr<u32> sizeKB)
error_code cellSaveDataGetListItem(ppu_thread& ppu, vm::cptr<char> dirName, vm::ptr<CellSaveDataDirStat> dir, vm::ptr<CellSaveDataSystemFileParam> sysFileParam, vm::ptr<u32> bind, vm::ptr<u32> sizeKB)
{
ppu.state += cpu_flag::wait;
cellSaveData.warning("cellSaveDataGetListItem(dirName=%s, dir=*0x%x, sysFileParam=*0x%x, bind=*0x%x, sizeKB=*0x%x)", dirName, dir, sysFileParam, bind, sizeKB);
return savedata_get_list_item(dirName, dir, sysFileParam, bind, sizeKB, 0);
+107 -13
View File
@@ -3091,7 +3091,8 @@ s32 _cellSpursWorkloadFlagReceiver(ppu_thread& ppu, vm::ptr<CellSpurs> spurs, u3
u8 FlagReceiver; // 0x77
};
s32 res;
s32 res = CELL_OK;
vm::reservation_op(ppu, vm::unsafe_ptr_cast<wklFlagOp>(spurs), [&](wklFlagOp& val)
{
if (is_set)
@@ -3129,17 +3130,83 @@ s32 _cellSpursWorkloadFlagReceiver(ppu_thread& ppu, vm::ptr<CellSpurs> spurs, u3
}
res = CELL_OK;
return;
});
return res;
}
/// Set/unset the recipient of the workload flag
s32 _cellSpursWorkloadFlagReceiver2()
s32 _cellSpursWorkloadFlagReceiver2(ppu_thread& ppu, vm::ptr<CellSpurs> spurs, u32 wid, u32 is_set, u32 print_debug_output)
{
UNIMPLEMENTED_FUNC(cellSpurs);
return CELL_OK;
cellSpurs.warning("_cellSpursWorkloadFlagReceiver2(spurs=*0x%x, wid=%d, is_set=%d, print_debug_output=%d)", spurs, wid, is_set, print_debug_output);
if (!spurs)
{
return CELL_SPURS_POLICY_MODULE_ERROR_NULL_POINTER;
}
if (!spurs.aligned())
{
return CELL_SPURS_POLICY_MODULE_ERROR_ALIGN;
}
if (wid >= spurs->max_workloads())
{
return CELL_SPURS_POLICY_MODULE_ERROR_INVAL;
}
if ((spurs->wklEnabled.load() & (0x80000000u >> wid)) == 0u)
{
return CELL_SPURS_POLICY_MODULE_ERROR_SRCH;
}
if (spurs->exception)
{
return CELL_SPURS_POLICY_MODULE_ERROR_STAT;
}
atomic_fence_acq_rel();
s32 res = CELL_OK;
vm::atomic_op<true>(spurs->wklFlagReceiver, [&](u8& FlagReceiver)
{
if (is_set)
{
if (FlagReceiver != 0xff)
{
res = CELL_SPURS_POLICY_MODULE_ERROR_BUSY;
return;
}
}
else
{
if (FlagReceiver != wid)
{
res = CELL_SPURS_POLICY_MODULE_ERROR_PERM;
return;
}
}
if (is_set)
{
if (FlagReceiver == 0xff)
{
FlagReceiver = static_cast<u8>(wid);
}
}
else
{
if (FlagReceiver == wid)
{
FlagReceiver = 0xff;
}
}
res = CELL_OK;
});
return res;
}
/// Request assignment of idle SPUs
@@ -3961,19 +4028,46 @@ s32 cellSpursGetTasksetId(vm::ptr<CellSpursTaskset> taskset, vm::ptr<u32> wid)
return CELL_SPURS_TASK_ERROR_ALIGN;
}
if (taskset->wid >= CELL_SPURS_MAX_WORKLOAD)
{
return CELL_SPURS_TASK_ERROR_INVAL;
}
// Does not check its validity
*wid = taskset->wid;
return CELL_OK;
}
s32 cellSpursShutdownTaskset(vm::ptr<CellSpursTaskset> taskset)
s32 cellSpursShutdownTaskset(ppu_thread& ppu, vm::ptr<CellSpursTaskset> taskset)
{
UNIMPLEMENTED_FUNC(cellSpurs);
return CELL_OK;
cellSpurs.warning("cellSpursShutdownTaskset(taskset=*0x%x)", taskset);
if (!taskset)
{
return CELL_SPURS_TASK_ERROR_NULL_POINTER;
}
if (!taskset.aligned())
{
return CELL_SPURS_TASK_ERROR_ALIGN;
}
const u32 wid = taskset->wid;
if (wid >= CELL_SPURS_MAX_WORKLOAD)
{
return CELL_SPURS_TASK_ERROR_INVAL;
}
const auto spurs = +taskset->spurs;
u32 shutdown_error = ppu_execute<&cellSpursShutdownWorkload>(ppu, spurs, wid);
if (shutdown_error == CELL_SPURS_POLICY_MODULE_ERROR_STAT)
{
shutdown_error = CELL_SPURS_TASK_ERROR_STAT;
}
else if (shutdown_error == CELL_SPURS_POLICY_MODULE_ERROR_ALIGN || shutdown_error == CELL_SPURS_POLICY_MODULE_ERROR_SRCH)
{
// printf is used on fw in this case
cellSpurs.error("cellSpursShutdownTaskset(taskset=*0x%x): Failed with %s (spurs=0x%x, wid=%d)", CellError{ shutdown_error }, spurs, wid);
}
return shutdown_error;
}
s32 _spurs::create_task(vm::ptr<CellSpursTaskset> taskset, vm::ptr<u32> task_id, vm::cptr<void> elf, vm::cptr<void> context, u32 size, vm::ptr<CellSpursTaskLsPattern> ls_pattern, vm::ptr<CellSpursTaskArgument> arg)
+6 -4
View File
@@ -139,18 +139,19 @@ error_code cellSysCacheMount(vm::ptr<CellSysCacheParam> param)
{
});
std::lock_guard lock0(g_mp_sys_dev_hdd1.mutex);
// Check if can reuse existing cache (won't if cache id is an empty string)
if (param->cacheId[0] && cache_id == cache.cache_id)
{
// Isn't mounted yet on first call to cellSysCacheMount
vfs::mount("/dev_hdd1", new_path);
if (vfs::mount("/dev_hdd1", new_path))
g_fxo->get<lv2_fs_mount_info_map>().add("/dev_hdd1", &g_mp_sys_dev_hdd1);
cellSysutil.success("Mounted existing cache at %s", new_path);
return not_an_error(CELL_SYSCACHE_RET_OK_RELAYED);
}
std::lock_guard lock0(g_mp_sys_dev_hdd1.mutex);
// Clear existing cache
if (!cache.cache_id.empty())
{
@@ -160,7 +161,8 @@ error_code cellSysCacheMount(vm::ptr<CellSysCacheParam> param)
// Set new cache id
cache.cache_id = std::move(cache_id);
fs::create_dir(new_path);
vfs::mount("/dev_hdd1", new_path);
if (vfs::mount("/dev_hdd1", new_path))
g_fxo->get<lv2_fs_mount_info_map>().add("/dev_hdd1", &g_mp_sys_dev_hdd1);
return not_an_error(CELL_SYSCACHE_RET_OK_CLEARED);
}
+1 -1
View File
@@ -468,7 +468,7 @@ error_code npDrmIsAvailable(vm::cptr<u8> k_licensee_addr, vm::cptr<char> drm_pat
if (k_licensee_addr)
{
std::memcpy(&k_licensee, k_licensee_addr.get_ptr(), sizeof(k_licensee));
sceNp.notice("npDrmIsAvailable(): KLicense key %s", std::bit_cast<be_t<u128>>(k_licensee));
sceNp.notice("npDrmIsAvailable(): KLicense key or KLIC=%s", std::bit_cast<be_t<u128>>(k_licensee));
}
if (Emu.GetFakeCat() == "PE")
+61 -31
View File
@@ -244,6 +244,15 @@ void fmt_class_string<SceNpCommunicationSignature>::format(std::string& out, u64
fmt::append(out, "%s", sign.data);
}
template <>
void fmt_class_string<SceNpCommunicationId>::format(std::string& out, u64 arg)
{
const auto& id = get_object(arg);
const u8 term = id.data[9];
fmt::append(out, "{ data='%s', term='%s' (0x%x), num=%d, dummy=%d }", id.data, std::isprint(term) ? fmt::format("%c", term) : "", term, id.num, id.dummy);
}
// Helpers
static error_code NpTrophyGetTrophyInfo(const trophy_context_t* ctxt, s32 trophyId, SceNpTrophyDetails* details, SceNpTrophyData* data);
@@ -442,27 +451,48 @@ error_code sceNpTrophyCreateContext(vm::ptr<u32> context, vm::cptr<SceNpCommunic
return SCE_NP_TROPHY_ERROR_NOT_SUPPORTED;
}
sceNpTrophy.warning("sceNpTrophyCreateContext(): commId = %s", *commId);
// rough checks for further fmt::format call
if (commId->num > 99)
const s32 comm_num = commId->num;
if (comm_num > 99)
{
return SCE_NP_TROPHY_ERROR_INVALID_NP_COMM_ID;
}
// NOTE: commId->term is unused in our code (at least until someone finds out if we need to account for it)
// generate trophy context name, limited to 9 characters
std::string_view name_sv(commId->data, 9);
// Generate trophy context name, limited to 9 characters
// Read once for thread-safety reasons
std::string name_str(commId->data, 9);
// resize the name if it was shorter than expected
if (const auto pos = name_sv.find_first_of('\0'); pos != std::string_view::npos)
if (const auto pos = name_str.find_first_of('\0'); pos != std::string_view::npos)
{
name_sv = name_sv.substr(0, pos);
name_str = name_str.substr(0, pos);
}
sceNpTrophy.warning("sceNpTrophyCreateContext(): data='%s' term=0x%x (0x%x) num=%d", name_sv, commId->data[9], commId->data[9], commId->num);
const SceNpCommunicationSignature commSign_data = *commSign;
if (read_from_ptr<be_t<u32>>(commSign_data.data, 0) != NP_TROPHY_COMM_SIGN_MAGIC)
{
return SCE_NP_TROPHY_ERROR_INVALID_NP_COMM_ID;
}
if (std::basic_string_view<u8>(&commSign_data.data[6], 6).find_first_not_of('\0') != umax)
{
// 6 padding bytes - must be 0
return SCE_NP_TROPHY_ERROR_INVALID_NP_COMM_ID;
}
if (read_from_ptr<be_t<u16>>(commSign_data.data, 4) != 0x100)
{
// Signifies version (1.00), although only one constant is allowed
return SCE_NP_TROPHY_ERROR_INVALID_NP_COMM_ID;
}
// append the commId number as "_xx"
std::string name = fmt::format("%s_%02d", name_sv, commId->num);
std::string name = fmt::format("%s_%02d", name_str, comm_num);
// create trophy context
const auto ctxt = idm::make_ptr<trophy_context_t>();
@@ -546,12 +576,28 @@ error_code sceNpTrophyRegisterContext(ppu_thread& ppu, u32 context, u32 handle,
}
};
// TODO: Callbacks
// From RE-ing a game's state machine, it seems the possible order is one of the following:
// * Install (Not installed) - Setup - Progress * ? - Finalize - Complete - Installed
// * Reinstall (Corrupted) - Setup - Progress * ? - Finalize - Complete - Installed
// * Update (Required update) - Setup - Progress * ? - Finalize - Complete - Installed
// * Installed
// open trophy pack file
std::string trp_path = vfs::get(Emu.GetDir() + "TROPDIR/" + ctxt->trp_name + "/TROPHY.TRP");
fs::file stream(trp_path);
if (!stream && Emu.GetCat() == "GD")
{
sceNpTrophy.warning("sceNpTrophyRegisterContext failed to open trophy file from boot path: '%s' (%s)", trp_path, fs::g_tls_error);
trp_path = vfs::get("/dev_bdvd/PS3_GAME/TROPDIR/" + ctxt->trp_name + "/TROPHY.TRP");
stream.open(trp_path);
}
// check if exists and opened
if (!stream)
{
const std::string msg = fmt::format("Failed to open trophy file: '%s' (%s)", trp_path, fs::g_tls_error);
return {SCE_NP_TROPHY_ERROR_CONF_DOES_NOT_EXIST, msg};
}
// TODO:
// SCE_NP_TROPHY_STATUS_DATA_CORRUPT -> reinstall
// SCE_NP_TROPHY_STATUS_REQUIRES_UPDATE -> reinstall (for example if a patch has updates for the trophy data)
// SCE_NP_TROPHY_STATUS_CHANGES_DETECTED -> reinstall (only possible in dev mode)
const std::string trophyPath = "/dev_hdd0/home/" + Emu.GetUsr() + "/trophy/" + ctxt->trp_name;
const s32 trp_status = fs::is_dir(vfs::get(trophyPath)) ? SCE_NP_TROPHY_STATUS_INSTALLED : SCE_NP_TROPHY_STATUS_NOT_INSTALLED;
@@ -560,6 +606,7 @@ error_code sceNpTrophyRegisterContext(ppu_thread& ppu, u32 context, u32 handle,
sceNpTrophy.notice("sceNpTrophyRegisterContext(): Callback is being called (trp_status=%u)", trp_status);
// "Ask permission" to install the trophy data.
// The callback is called once and then if it returns >= 0 the cb is called through events(coming from vsh) that are passed to the CB through cellSysutilCheckCallback
if (statusCb(ppu, context, trp_status, 0, 0, arg) < 0)
{
@@ -599,24 +646,6 @@ error_code sceNpTrophyRegisterContext(ppu_thread& ppu, u32 context, u32 handle,
return SCE_NP_TROPHY_ERROR_UNKNOWN_HANDLE;
}
// open trophy pack file
std::string trp_path = vfs::get(Emu.GetDir() + "TROPDIR/" + ctxt->trp_name + "/TROPHY.TRP");
fs::file stream(trp_path);
if (!stream && Emu.GetCat() == "GD")
{
sceNpTrophy.warning("sceNpTrophyRegisterContext failed to open trophy file from boot path: '%s' (%s)", trp_path, fs::g_tls_error);
trp_path = vfs::get("/dev_bdvd/PS3_GAME/TROPDIR/" + ctxt->trp_name + "/TROPHY.TRP");
stream.open(trp_path);
}
// check if exists and opened
if (!stream)
{
const std::string msg = fmt::format("Failed to open trophy file: '%s' (%s)", trp_path, fs::g_tls_error);
return {SCE_NP_TROPHY_ERROR_CONF_DOES_NOT_EXIST, msg};
}
TRPLoader trp(stream);
if (!trp.LoadHeader())
{
@@ -696,6 +725,7 @@ error_code sceNpTrophyRegisterContext(ppu_thread& ppu, u32 context, u32 handle,
{
sysutil_register_cb([statusCb, status, context, completed, arg, wkptr](ppu_thread& cb_ppu) -> s32
{
// TODO: it is possible that we need to check the return value here as well.
statusCb(cb_ppu, context, status.first, completed, status.second, arg);
const auto queued = wkptr.lock();
+5
View File
@@ -151,6 +151,11 @@ enum
SCE_NP_TROPHY_STATUS_CHANGES_DETECTED = 9,
};
enum : u32
{
NP_TROPHY_COMM_SIGN_MAGIC = 0xB9DDE13B,
};
using SceNpTrophyStatusCallback = s32(u32 context, u32 status, s32 completed, s32 total, vm::ptr<void> arg);
// Forward declare this function since trophyunlock needs it
+117 -83
View File
@@ -78,7 +78,7 @@ void ppu_module::validate(u32 reloc)
if (size && size != funcs[index].size)
{
if (size + 4 != funcs[index].size || vm::read32(addr + size) != ppu_instructions::NOP())
if (size + 4 != funcs[index].size || get_ref<u32>(addr + size) != ppu_instructions::NOP())
{
ppu_validator.error("%s.yml : function size mismatch at 0x%x(size=0x%x) (0x%x, 0x%x)", path, found, funcs[index].size, addr, size);
}
@@ -112,9 +112,9 @@ void ppu_module::validate(u32 reloc)
}
}
static u32 ppu_test(const vm::cptr<u32> ptr, vm::cptr<void> fend, ppu_pattern_array pat)
static u32 ppu_test(const be_t<u32>* ptr, const void* fend, ppu_pattern_array pat)
{
vm::cptr<u32> cur = ptr;
const be_t<u32>* cur = ptr;
for (auto& p : pat)
{
@@ -141,10 +141,10 @@ static u32 ppu_test(const vm::cptr<u32> ptr, vm::cptr<void> fend, ppu_pattern_ar
cur++;
}
return cur.addr() - ptr.addr();
return (cur - ptr) * sizeof(*ptr);
}
static u32 ppu_test(vm::cptr<u32> ptr, vm::cptr<void> fend, ppu_pattern_matrix pats)
static u32 ppu_test(const be_t<u32>* ptr, const void* fend, ppu_pattern_matrix pats)
{
for (auto pat : pats)
{
@@ -585,6 +585,14 @@ bool ppu_module::analyse(u32 lib_toc, u32 entry, const u32 sec_end, const std::b
return func;
};
static const auto advance = [](auto& _ptr, auto& ptr, u32 count)
{
const auto old_ptr = ptr;
_ptr += count;
ptr += count;
return old_ptr;
};
// Register new TOC and find basic set of functions
auto add_toc = [&](u32 toc)
{
@@ -596,16 +604,24 @@ bool ppu_module::analyse(u32 lib_toc, u32 entry, const u32 sec_end, const std::b
// Grope for OPD section (TODO: optimization, better constraints)
for (const auto& seg : segs)
{
if (!seg.addr) continue;
if (seg.size < 8) continue;
for (vm::cptr<u32> ptr = vm::cast(seg.addr); ptr.addr() < seg.addr + seg.size; ptr++)
const vm::cptr<void> seg_end = vm::cast(seg.addr + seg.size - 8);
vm::cptr<u32> _ptr = vm::cast(seg.addr);
auto ptr = get_ptr<u32>(_ptr);
for (; _ptr <= seg_end;)
{
if (ptr[0] >= start && ptr[0] < end && ptr[0] % 4 == 0 && ptr[1] == toc)
if (ptr[1] == toc && ptr[0] >= start && ptr[0] < end && ptr[0] % 4 == 0)
{
// New function
ppu_log.trace("OPD*: [0x%x] 0x%x (TOC=0x%x)", ptr, ptr[0], ptr[1]);
add_func(*ptr, addr_heap.count(ptr.addr()) ? toc : 0, 0);
ptr++;
ppu_log.trace("OPD*: [0x%x] 0x%x (TOC=0x%x)", _ptr, ptr[0], ptr[1]);
add_func(*ptr, addr_heap.count(_ptr.addr()) ? toc : 0, 0);
advance(_ptr, ptr, 2);
}
else
{
advance(_ptr, ptr, 1);
}
}
}
@@ -621,9 +637,13 @@ bool ppu_module::analyse(u32 lib_toc, u32 entry, const u32 sec_end, const std::b
// Find references indiscriminately
for (const auto& seg : segs)
{
if (!seg.addr) continue;
if (seg.size < 4) continue;
for (vm::cptr<u32> ptr = vm::cast(seg.addr); ptr.addr() < seg.addr + seg.size; ptr++)
vm::cptr<u32> _ptr = vm::cast(seg.addr);
const vm::cptr<void> seg_end = vm::cast(seg.addr + seg.size - 4);
auto ptr = get_ptr<u32>(_ptr);
for (vm::cptr<u32> _ptr = vm::cast(seg.addr); _ptr <= seg_end; advance(_ptr, ptr, 1))
{
const u32 value = *ptr;
@@ -651,15 +671,17 @@ bool ppu_module::analyse(u32 lib_toc, u32 entry, const u32 sec_end, const std::b
vm::cptr<void> sec_end = vm::cast(sec.addr + sec.size);
// Probe
for (vm::cptr<u32> ptr = vm::cast(sec.addr); ptr < sec_end; ptr += 2)
for (vm::cptr<u32> _ptr = vm::cast(sec.addr); _ptr < sec_end; _ptr += 2)
{
if (ptr + 6 <= sec_end && !ptr[0] && !ptr[2] && ptr[1] == ptr[4] && ptr[3] == ptr[5])
auto ptr = get_ptr<u32>(_ptr);
if (_ptr + 6 <= sec_end && !ptr[0] && !ptr[2] && ptr[1] == ptr[4] && ptr[3] == ptr[5])
{
// Special OPD format case (some homebrews)
ptr += 4;
advance(_ptr, ptr, 4);
}
if (ptr + 2 > sec_end)
if (_ptr + 2 > sec_end)
{
sec_end.set(0);
break;
@@ -673,7 +695,7 @@ bool ppu_module::analyse(u32 lib_toc, u32 entry, const u32 sec_end, const std::b
//const u32 _toc_end = _toc + 0x8000;
// TODO: improve TOC constraints
if (_toc % 4 || !vm::check_addr(_toc) || _toc >= 0x40000000 || (_toc >= start && _toc < end))
if (_toc % 4 || !get_ptr<u32>(_toc) || _toc >= 0x40000000 || (_toc >= start && _toc < end))
{
sec_end.set(0);
break;
@@ -689,18 +711,20 @@ bool ppu_module::analyse(u32 lib_toc, u32 entry, const u32 sec_end, const std::b
if (sec_end) ppu_log.notice("Reading OPD section at 0x%x...", sec.addr);
// Mine
for (vm::cptr<u32> ptr = vm::cast(sec.addr); ptr < sec_end; ptr += 2)
for (vm::cptr<u32> _ptr = vm::cast(sec.addr); _ptr < sec_end; _ptr += 2)
{
auto ptr = get_ptr<u32>(_ptr);
// Special case: see "Probe"
if (!ptr[0]) ptr += 4;
if (!ptr[0]) advance(_ptr, ptr, 4);
// Add function and TOC
const u32 addr = ptr[0];
const u32 toc = ptr[1];
ppu_log.trace("OPD: [0x%x] 0x%x (TOC=0x%x)", ptr, addr, toc);
ppu_log.trace("OPD: [0x%x] 0x%x (TOC=0x%x)", _ptr, addr, toc);
TOCs.emplace(toc);
auto& func = add_func(addr, addr_heap.count(ptr.addr()) ? toc : 0, 0);
auto& func = add_func(addr, addr_heap.count(_ptr.addr()) ? toc : 0, 0);
func.attr += ppu_attr::known_addr;
known_functions.emplace(addr);
}
@@ -709,7 +733,7 @@ bool ppu_module::analyse(u32 lib_toc, u32 entry, const u32 sec_end, const std::b
// Register TOC from entry point
if (entry && !lib_toc)
{
lib_toc = vm::read32(entry) ? vm::read32(entry + 4) : vm::read32(entry + 20);
lib_toc = get_ref<u32>(entry) ? get_ref<u32>(entry + 4) : get_ref<u32>(entry + 20);
}
// Secondary attempt
@@ -733,23 +757,25 @@ bool ppu_module::analyse(u32 lib_toc, u32 entry, const u32 sec_end, const std::b
vm::cptr<void> sec_end = vm::cast(sec.addr + sec.size);
// Probe
for (vm::cptr<u32> ptr = vm::cast(sec.addr); ptr < sec_end;)
for (vm::cptr<u32> _ptr = vm::cast(sec.addr); _ptr < sec_end;)
{
if (!ptr.aligned() || ptr.addr() < sec.addr || ptr >= sec_end)
if (!_ptr.aligned() || _ptr.addr() < sec.addr || _ptr >= sec_end)
{
sec_end.set(0);
break;
}
const auto ptr = get_ptr<u32>(_ptr);
const u32 size = ptr[0] + 4;
if (size == 4 && ptr + 1 == sec_end)
if (size == 4 && _ptr + 1 == sec_end)
{
// Null terminator
break;
}
if (size % 4 || size < 0x10 || ptr + size / 4 > sec_end)
if (size % 4 || size < 0x10 || _ptr + size / 4 > sec_end)
{
sec_end.set(0);
break;
@@ -757,7 +783,7 @@ bool ppu_module::analyse(u32 lib_toc, u32 entry, const u32 sec_end, const std::b
if (ptr[1])
{
const u32 cie_off = ptr.addr() - ptr[1] + 4;
const u32 cie_off = _ptr.addr() - ptr[1] + 4;
if (cie_off % 4 || cie_off < sec.addr || cie_off >= sec_end.addr())
{
@@ -766,14 +792,16 @@ bool ppu_module::analyse(u32 lib_toc, u32 entry, const u32 sec_end, const std::b
}
}
ptr = vm::cast(ptr.addr() + size);
_ptr = vm::cast(_ptr.addr() + size);
}
if (sec_end && sec.size > 4) ppu_log.notice("Reading .eh_frame section at 0x%x...", sec.addr);
// Mine
for (vm::cptr<u32> ptr = vm::cast(sec.addr); ptr < sec_end; ptr = vm::cast(ptr.addr() + ptr[0] + 4))
for (vm::cptr<u32> _ptr = vm::cast(sec.addr); _ptr < sec_end; _ptr = vm::cast(_ptr.addr() + *get_ptr<u32>(_ptr) + 4))
{
const auto ptr = get_ptr<u32>(_ptr);
if (ptr[0] == 0u)
{
// Null terminator
@@ -788,7 +816,7 @@ bool ppu_module::analyse(u32 lib_toc, u32 entry, const u32 sec_end, const std::b
else
{
// Get associated CIE (currently unused)
const vm::cptr<u32> cie = vm::cast(ptr.addr() - ptr[1] + 4);
const vm::cptr<u32> cie = vm::cast(_ptr.addr() - ptr[1] + 4);
u32 addr = 0;
u32 size = 0;
@@ -817,7 +845,7 @@ bool ppu_module::analyse(u32 lib_toc, u32 entry, const u32 sec_end, const std::b
// TODO: absolute/relative offset (approximation)
if (addr > 0xc0000000)
{
addr += ptr.addr() + 8;
addr += _ptr.addr() + 8;
}
ppu_log.trace(".eh_frame: [0x%x] FDE 0x%x (cie=*0x%x, addr=0x%x, size=0x%x)", ptr, ptr[0], cie, addr, size);
@@ -875,15 +903,16 @@ bool ppu_module::analyse(u32 lib_toc, u32 entry, const u32 sec_end, const std::b
if (func.blocks.empty())
{
// Special function analysis
const vm::cptr<u32> ptr = vm::cast(func.addr);
const vm::cptr<u32> _ptr = vm::cast(func.addr);
const vm::cptr<void> fend = vm::cast(end);
const auto ptr = get_ptr<u32>(_ptr);
using namespace ppu_instructions;
if (ptr + 1 <= fend && (ptr[0] & 0xfc000001) == B({}, {}))
if (_ptr + 1 <= fend && (ptr[0] & 0xfc000001) == B({}, {}))
{
// Simple trampoline
const u32 target = (ptr[0] & 0x2 ? 0 : ptr.addr()) + ppu_opcode_t{ptr[0]}.bt24;
const u32 target = (ptr[0] & 0x2 ? 0 : _ptr.addr()) + ppu_opcode_t{ptr[0]}.bt24;
if (target == func.addr)
{
@@ -913,7 +942,7 @@ bool ppu_module::analyse(u32 lib_toc, u32 entry, const u32 sec_end, const std::b
}
}
if (ptr + 0x4 <= fend &&
if (_ptr + 0x4 <= fend &&
(ptr[0] & 0xffff0000) == LIS(r11, 0) &&
(ptr[1] & 0xffff0000) == ADDI(r11, r11, 0) &&
ptr[2] == MTCTR(r11) &&
@@ -941,7 +970,7 @@ bool ppu_module::analyse(u32 lib_toc, u32 entry, const u32 sec_end, const std::b
}
}
if (ptr + 0x7 <= fend &&
if (_ptr + 0x7 <= fend &&
ptr[0] == STD(r2, r1, 0x28) &&
(ptr[1] & 0xffff0000) == ADDIS(r12, r2, {}) &&
(ptr[2] & 0xffff0000) == LWZ(r11, r12, {}) &&
@@ -957,9 +986,10 @@ bool ppu_module::analyse(u32 lib_toc, u32 entry, const u32 sec_end, const std::b
func.attr += ppu_attr::known_size;
// Look for another imports to fill gaps (hack)
auto p2 = ptr + 7;
auto _p2 = _ptr + 7;
auto p2 = get_ptr<u32>(_p2);
while (p2 + 0x7 <= fend &&
while (_p2 + 0x7 <= fend &&
p2[0] == STD(r2, r1, 0x28) &&
(p2[1] & 0xffff0000) == ADDIS(r12, r2, {}) &&
(p2[2] & 0xffff0000) == LWZ(r11, r12, {}) &&
@@ -968,18 +998,18 @@ bool ppu_module::analyse(u32 lib_toc, u32 entry, const u32 sec_end, const std::b
p2[5] == MTCTR(r11) &&
p2[6] == BCTR())
{
auto& next = add_func(p2.addr(), -1, func.addr);
auto& next = add_func(_p2.addr(), -1, func.addr);
next.size = 0x1C;
next.blocks.emplace(next.addr, next.size);
next.attr += ppu_attr::known_addr;
next.attr += ppu_attr::known_size;
p2 += 7;
advance(_p2, p2, 7);
}
continue;
}
if (ptr + 0x7 <= fend &&
if (_ptr + 0x7 <= fend &&
ptr[0] == STD(r2, r1, 0x28) &&
(ptr[1] & 0xffff0000) == ADDIS(r2, r2, {}) &&
(ptr[2] & 0xffff0000) == ADDI(r2, r2, {}) &&
@@ -1008,11 +1038,11 @@ bool ppu_module::analyse(u32 lib_toc, u32 entry, const u32 sec_end, const std::b
add_toc(toc);
add_func(func.addr, toc, 0);
}
else if (new_func.toc - func.toc != toc_add)
{
//func.toc = -1;
//new_func.toc = -1;
}
//else if (new_func.toc - func.toc != toc_add)
//{
// func.toc = -1;
// new_func.toc = -1;
//}
if (new_func.blocks.empty())
{
@@ -1029,7 +1059,7 @@ bool ppu_module::analyse(u32 lib_toc, u32 entry, const u32 sec_end, const std::b
}
}
if (ptr + 4 <= fend &&
if (_ptr + 4 <= fend &&
ptr[0] == STD(r2, r1, 0x28) &&
(ptr[1] & 0xffff0000) == ADDIS(r2, r2, {}) &&
(ptr[2] & 0xffff0000) == ADDI(r2, r2, {}) &&
@@ -1037,7 +1067,7 @@ bool ppu_module::analyse(u32 lib_toc, u32 entry, const u32 sec_end, const std::b
{
// Trampoline with TOC
const u32 toc_add = (ptr[1] << 16) + s16(ptr[2]);
const u32 target = (ptr[3] & 0x2 ? 0 : (ptr + 3).addr()) + ppu_opcode_t{ptr[3]}.bt24;
const u32 target = (ptr[3] & 0x2 ? 0 : (_ptr + 3).addr()) + ppu_opcode_t{ptr[3]}.bt24;
if (target >= start && target < end)
{
@@ -1055,11 +1085,11 @@ bool ppu_module::analyse(u32 lib_toc, u32 entry, const u32 sec_end, const std::b
add_toc(toc);
add_func(func.addr, toc, 0);
}
else if (new_func.toc - func.toc != toc_add)
{
//func.toc = -1;
//new_func.toc = -1;
}
//else if (new_func.toc - func.toc != toc_add)
//{
// func.toc = -1;
// new_func.toc = -1;
//}
if (new_func.blocks.empty())
{
@@ -1076,7 +1106,7 @@ bool ppu_module::analyse(u32 lib_toc, u32 entry, const u32 sec_end, const std::b
}
}
if (ptr + 8 <= fend &&
if (_ptr + 8 <= fend &&
(ptr[0] & 0xffff0000) == LI(r12, 0) &&
(ptr[1] & 0xffff0000) == ORIS(r12, r12, 0) &&
(ptr[2] & 0xffff0000) == LWZ(r12, r12, 0) &&
@@ -1095,9 +1125,10 @@ bool ppu_module::analyse(u32 lib_toc, u32 entry, const u32 sec_end, const std::b
func.attr += ppu_attr::known_size;
// Look for another imports to fill gaps (hack)
auto p2 = ptr + 8;
auto _p2 = _ptr + 8;
auto p2 = get_ptr<u32>(_p2);
while (p2 + 8 <= fend &&
while (_p2 + 8 <= fend &&
(p2[0] & 0xffff0000) == LI(r12, 0) &&
(p2[1] & 0xffff0000) == ORIS(r12, r12, 0) &&
(p2[2] & 0xffff0000) == LWZ(r12, r12, 0) &&
@@ -1107,19 +1138,19 @@ bool ppu_module::analyse(u32 lib_toc, u32 entry, const u32 sec_end, const std::b
p2[6] == MTCTR(r0) &&
p2[7] == BCTR())
{
auto& next = add_func(p2.addr(), -1, func.addr);
auto& next = add_func(_p2.addr(), -1, func.addr);
next.size = 0x20;
next.blocks.emplace(next.addr, next.size);
next.attr += ppu_attr::known_addr;
next.attr += ppu_attr::known_size;
p2 += 8;
advance(_p2, p2, 8);
known_functions.emplace(next.addr);
}
continue;
}
if (ptr + 3 <= fend &&
if (_ptr + 3 <= fend &&
ptr[0] == 0x7c0004acu &&
ptr[1] == 0x00000000u &&
ptr[2] == BLR())
@@ -1131,7 +1162,7 @@ bool ppu_module::analyse(u32 lib_toc, u32 entry, const u32 sec_end, const std::b
continue;
}
if (const u32 len = ppu_test(ptr, fend, ppu_patterns::abort))
if (const u32 len = ppu_test(ptr, get_ptr<void>(fend), ppu_patterns::abort))
{
// Function "abort"
ppu_log.notice("Function [0x%x]: 'abort'", func.addr);
@@ -1199,10 +1230,13 @@ bool ppu_module::analyse(u32 lib_toc, u32 entry, const u32 sec_end, const std::b
{
auto& block = block_queue[j].get();
for (vm::cptr<u32> _ptr = vm::cast(block.first); _ptr.addr() < func_end;)
vm::cptr<u32> _ptr = vm::cast(block.first);
auto ptr = ensure(get_ptr<u32>(_ptr));
for (; _ptr.addr() < func_end;)
{
const u32 iaddr = _ptr.addr();
const ppu_opcode_t op{*_ptr++};
const ppu_opcode_t op{*advance(_ptr, ptr, 1)};
const ppu_itype::type type = s_ppu_itype.decode(op.opcode);
if (type == ppu_itype::UNK)
@@ -1276,9 +1310,9 @@ bool ppu_module::analyse(u32 lib_toc, u32 entry, const u32 sec_end, const std::b
const u32 jt_addr = _ptr.addr();
const u32 jt_end = func_end;
for (; _ptr.addr() < jt_end; _ptr++)
for (; _ptr.addr() < jt_end; advance(_ptr, ptr, 1))
{
const u32 addr = jt_addr + *_ptr;
const u32 addr = jt_addr + *ptr;
if (addr == jt_addr)
{
@@ -1331,7 +1365,7 @@ bool ppu_module::analyse(u32 lib_toc, u32 entry, const u32 sec_end, const std::b
block.second = _ptr.addr() - block.first;
break;
}
else if (type == ppu_itype::STDU && func.attr & ppu_attr::no_size && (op.opcode == *_ptr || *_ptr == ppu_instructions::BLR()))
else if (type == ppu_itype::STDU && func.attr & ppu_attr::no_size && (op.opcode == *ptr || *ptr == ppu_instructions::BLR()))
{
// Hack
ppu_log.success("[0x%x] Instruction repetition: 0x%08x", iaddr, op.opcode);
@@ -1391,7 +1425,7 @@ bool ppu_module::analyse(u32 lib_toc, u32 entry, const u32 sec_end, const std::b
for (vm::cptr<u32> _ptr = vm::cast(block.first); _ptr.addr() < block.first + block.second;)
{
const u32 iaddr = _ptr.addr();
const ppu_opcode_t op{*_ptr++};
const ppu_opcode_t op{get_ref<u32>(_ptr++)};
const ppu_itype::type type = s_ppu_itype.decode(op.opcode);
if (type == ppu_itype::B || type == ppu_itype::BC)
@@ -1465,14 +1499,15 @@ bool ppu_module::analyse(u32 lib_toc, u32 entry, const u32 sec_end, const std::b
for (vm::cptr<u32> _ptr = vm::cast(start); _ptr.addr() < next;)
{
const u32 addr = _ptr.addr();
const ppu_opcode_t op{*_ptr++};
const ppu_opcode_t op{get_ref<u32>(_ptr++)};
const ppu_itype::type type = s_ppu_itype.decode(op.opcode);
if (type == ppu_itype::UNK)
{
break;
}
else if (addr == start && op.opcode == ppu_instructions::NOP())
if (addr == start && op.opcode == ppu_instructions::NOP())
{
if (start == func.addr + func.size)
{
@@ -1483,16 +1518,19 @@ bool ppu_module::analyse(u32 lib_toc, u32 entry, const u32 sec_end, const std::b
start += 4;
continue;
}
else if (type == ppu_itype::SC && op.opcode != ppu_instructions::SC(0))
if (type == ppu_itype::SC && op.opcode != ppu_instructions::SC(0))
{
break;
}
else if (addr == start && op.opcode == ppu_instructions::BLR())
if (addr == start && op.opcode == ppu_instructions::BLR())
{
start += 4;
continue;
}
else if (type == ppu_itype::B || type == ppu_itype::BC)
if (type == ppu_itype::B || type == ppu_itype::BC)
{
const u32 target = (op.aa ? 0 : addr) + (type == ppu_itype::B ? +op.bt24 : +op.bt14);
@@ -1539,7 +1577,7 @@ bool ppu_module::analyse(u32 lib_toc, u32 entry, const u32 sec_end, const std::b
end = 0;
}
for (auto&& [_, func] : as_rvalue(std::move(fmap)))
for (auto&& [_, func] : as_rvalue(fmap))
{
if (func.attr & ppu_attr::no_size && entry)
{
@@ -1560,7 +1598,7 @@ bool ppu_module::analyse(u32 lib_toc, u32 entry, const u32 sec_end, const std::b
continue;
}
for (auto [addr, size] : func.blocks)
for (const auto& [addr, size] : func.blocks)
{
if (!size)
{
@@ -1598,12 +1636,12 @@ bool ppu_module::analyse(u32 lib_toc, u32 entry, const u32 sec_end, const std::b
for (auto& rel : this->relocs)
{
// Disabled (TODO)
if (1 || !vm::check_addr<4>(rel.addr))
//if (!vm::check_addr<4>(rel.addr))
{
continue;
}
const u32 target = vm::_ref<u32>(rel.addr);
const u32 target = get_ref<u32>(rel.addr);
if (target % 4 || target < start || target >= end)
{
@@ -1680,7 +1718,7 @@ bool ppu_module::analyse(u32 lib_toc, u32 entry, const u32 sec_end, const std::b
for (; i_pos < lim; i_pos += 4)
{
const u32 opc = vm::_ref<u32>(i_pos);
const u32 opc = get_ref<u32>(i_pos);
switch (auto type = s_ppu_itype.decode(opc))
{
@@ -1722,9 +1760,7 @@ bool ppu_module::analyse(u32 lib_toc, u32 entry, const u32 sec_end, const std::b
break;
}
const auto found = fmap.find(target);
if (target != i_pos && found == fmap.cend())
if (target != i_pos && !fmap.contains(target))
{
if (block_set.count(target) == 0)
{
@@ -1782,9 +1818,7 @@ bool ppu_module::analyse(u32 lib_toc, u32 entry, const u32 sec_end, const std::b
else if (is_good && is_fallback && lim < end)
{
// Register fallback target
const auto found = fmap.find(lim);
if (found == fmap.cend() && block_set.count(lim) == 0)
if (!fmap.contains(lim) && !block_set.contains(lim))
{
ppu_log.trace("Block target found: 0x%x (i_pos=0x%x)", lim, i_pos);
block_queue.emplace_back(lim, 0);
+82 -2
View File
@@ -3,8 +3,11 @@
#include <string>
#include <map>
#include <set>
#include <deque>
#include "util/types.hpp"
#include "util/endian.hpp"
#include "util/asm.hpp"
#include "util/to_endian.hpp"
#include "Utilities/bit_set.h"
#include "PPUOpcodes.h"
@@ -65,6 +68,7 @@ struct ppu_segment
u32 type;
u32 flags;
u32 filesz;
void* ptr{};
};
// PPU Module Information
@@ -89,6 +93,8 @@ struct ppu_module
std::vector<ppu_segment> segs{};
std::vector<ppu_segment> secs{};
std::vector<ppu_function> funcs{};
std::deque<std::shared_ptr<void>> allocations;
std::map<u32, u32> addr_to_seg_index;
// Copy info without functions
void copy_part(const ppu_module& info)
@@ -99,16 +105,90 @@ struct ppu_module
relocs = info.relocs;
segs = info.segs;
secs = info.secs;
allocations = info.allocations;
addr_to_seg_index = info.addr_to_seg_index;
}
bool analyse(u32 lib_toc, u32 entry, u32 end, const std::basic_string<u32>& applied, std::function<bool()> check_aborted = {});
void validate(u32 reloc);
template <typename T>
to_be_t<T>* get_ptr(u32 addr, u32 size_bytes) const
{
auto it = addr_to_seg_index.upper_bound(addr);
if (it == addr_to_seg_index.begin())
{
return nullptr;
}
it--;
const auto& seg = segs[it->second];
const u32 seg_size = seg.size;
const u32 seg_addr = seg.addr;
if (seg_size >= std::max<usz>(size_bytes, 1) && addr <= utils::align<u32>(seg_addr + seg_size, 0x10000) - size_bytes)
{
return reinterpret_cast<to_be_t<T>*>(static_cast<u8*>(seg.ptr) + (addr - seg_addr));
}
return nullptr;
}
template <typename T>
to_be_t<T>* get_ptr(u32 addr) const
{
constexpr usz size_element = std::is_void_v<T> ? 0 : sizeof(std::conditional_t<std::is_void_v<T>, char, T>);
return get_ptr<T>(addr, u32{size_element});
}
template <typename T, typename U> requires requires (const U& obj) { +obj.size() * 0; }
to_be_t<T>* get_ptr(U&& addr) const
{
constexpr usz size_element = std::is_void_v<T> ? 0 : sizeof(std::conditional_t<std::is_void_v<T>, char, T>);
return get_ptr<T>(addr.addr(), u32{size_element});
}
template <typename T>
to_be_t<T>& get_ref(u32 addr,
u32 line = __builtin_LINE(),
u32 col = __builtin_COLUMN(),
const char* file = __builtin_FILE(),
const char* func = __builtin_FUNCTION()) const
{
constexpr usz size_element = std::is_void_v<T> ? 0 : sizeof(std::conditional_t<std::is_void_v<T>, char, T>);
if (auto ptr = get_ptr<T>(addr, u32{size_element}))
{
return *ptr;
}
fmt::throw_exception("get_ref(): Failure! (addr=0x%x)%s", addr, src_loc{line, col, file, func});
return *std::add_pointer_t<to_be_t<T>>{};
}
template <typename T, typename U> requires requires (const U& obj) { +obj.size() * 0; }
to_be_t<T>& get_ref(U&& addr,
u32 line = __builtin_LINE(),
u32 col = __builtin_COLUMN(),
const char* file = __builtin_FILE(),
const char* func = __builtin_FUNCTION()) const
{
constexpr usz size_element = std::is_void_v<T> ? 0 : sizeof(std::conditional_t<std::is_void_v<T>, char, T>);
if (auto ptr = get_ptr<T>(addr.addr(), u32{size_element}))
{
return *ptr;
}
fmt::throw_exception("get_ref(): Failure! (addr=0x%x)%s", addr.addr(), src_loc{line, col, file, func});
return *std::add_pointer_t<to_be_t<T>>{};
}
};
struct main_ppu_module : public ppu_module
{
u32 elf_entry;
u32 seg0_code_end;
u32 elf_entry{};
u32 seg0_code_end{};
std::basic_string<u32> applied_pathes;
};
+5
View File
@@ -14,6 +14,11 @@
std::memcpy(ppu.syscall_args, ppu.gpr + 3, sizeof(ppu.syscall_args)); \
ppu_func_detail::do_call(ppu, func);\
static_cast<void>(ppu.test_stopped());\
auto& history = ppu.syscall_history.data[ppu.syscall_history.index++ % ppu.syscall_history.data.size()];\
history.cia = ppu.cia;\
history.func_name = ppu.current_function;\
history.error = ppu.gpr[3];\
if (ppu.syscall_history.count_debug_arguments) std::copy_n(ppu.syscall_args, std::size(history.args), history.args.data());\
ppu.current_function = old_f;\
ppu.cia += 4;\
__VA_ARGS__;\
+208 -108
View File
@@ -335,9 +335,12 @@ static void ppu_initialize_modules(ppu_linkage_info* link, utils::serial* ar = n
u32 alloc_addr = 0;
// "Use" all the modules for correct linkage
for (auto& _module : registered)
if (ppu_loader.trace)
{
ppu_loader.trace("Registered static module: %s", _module->name);
for (auto& _module : registered)
{
ppu_loader.trace("Registered static module: %s", _module->name);
}
}
struct hle_vars_save
@@ -751,7 +754,7 @@ static auto ppu_load_exports(ppu_linkage_info* link, u32 exports_start, u32 expo
if (lib.num_tlsvar)
{
ppu_loader.fatal("Unexpected num_tlsvar (%u)!", lib.num_tlsvar);
ppu_loader.error("Unexpected num_tlsvar (%u)!", lib.num_tlsvar);
}
const bool should_load = ppu_register_library_lock(module_name, true);
@@ -886,7 +889,7 @@ static auto ppu_load_imports(std::vector<ppu_reloc>& relocs, ppu_linkage_info* l
if (lib.num_tlsvar)
{
ppu_loader.fatal("Unexpected num_tlsvar (%u)!", lib.num_tlsvar);
ppu_loader.error("Unexpected num_tlsvar (%u)!", lib.num_tlsvar);
}
// Static module
@@ -1048,20 +1051,23 @@ void init_ppu_functions(utils::serial* ar, bool full = false)
if (full)
{
ensure(ar);
// Initialize HLE modules
ppu_initialize_modules(&g_fxo->get<ppu_linkage_info>(), ar);
}
}
static void ppu_check_patch_spu_images(const ppu_segment& seg)
static void ppu_check_patch_spu_images(const ppu_module& mod, const ppu_segment& seg)
{
const std::string_view seg_view{vm::get_super_ptr<char>(seg.addr), seg.size};
if (!seg.size)
{
return;
}
const std::string_view seg_view{ensure(mod.get_ptr<char>(seg.addr)), seg.size};
for (usz i = seg_view.find("\177ELF"); i < seg.size; i = seg_view.find("\177ELF", i + 4))
{
const auto elf_header = vm::get_super_ptr<u8>(seg.addr + i);
const auto elf_header = ensure(mod.get_ptr<u8>(seg.addr + i));
// Try to load SPU image
const spu_exec_object obj(fs::file(elf_header, seg.size - i));
@@ -1102,7 +1108,7 @@ static void ppu_check_patch_spu_images(const ppu_segment& seg)
sha1_update(&sha2, (elf_header + prog.p_offset), prog.p_filesz);
// We assume that the string SPUNAME exists 0x14 bytes into the NOTE segment
name = reinterpret_cast<char*>(elf_header + prog.p_offset + 0x14);
name = ensure(mod.get_ptr<const char>(seg.addr + i + prog.p_offset + 0x14));
if (!name.empty())
{
@@ -1136,12 +1142,12 @@ static void ppu_check_patch_spu_images(const ppu_segment& seg)
for (const auto& prog : obj.progs)
{
// Apply the patch
applied += g_fxo->get<patch_engine>().apply(hash, (elf_header + prog.p_offset), prog.p_filesz, prog.p_vaddr);
applied += g_fxo->get<patch_engine>().apply(hash, [&](u32 addr, u32 /*size*/) { return addr + elf_header + prog.p_offset; }, prog.p_filesz, prog.p_vaddr);
if (!Emu.GetTitleID().empty())
{
// Alternative patch
applied += g_fxo->get<patch_engine>().apply(Emu.GetTitleID() + '-' + hash, (elf_header + prog.p_offset), prog.p_filesz, prog.p_vaddr);
applied += g_fxo->get<patch_engine>().apply(Emu.GetTitleID() + '-' + hash, [&](u32 addr, u32 /*size*/) { return addr + elf_header + prog.p_offset; }, prog.p_filesz, prog.p_vaddr);
}
}
@@ -1247,7 +1253,7 @@ const char* get_prx_name_by_cia(u32 addr)
return nullptr;
}
std::shared_ptr<lv2_prx> ppu_load_prx(const ppu_prx_object& elf, const std::string& path, s64 file_offset, utils::serial* ar)
std::shared_ptr<lv2_prx> ppu_load_prx(const ppu_prx_object& elf, bool virtual_load, const std::string& path, s64 file_offset, utils::serial* ar)
{
if (elf != elf_error::ok)
{
@@ -1255,7 +1261,7 @@ std::shared_ptr<lv2_prx> ppu_load_prx(const ppu_prx_object& elf, const std::stri
}
// Create new PRX object
const auto prx = !ar ? idm::make_ptr<lv2_obj, lv2_prx>() : std::make_shared<lv2_prx>();
const auto prx = !ar && !virtual_load ? idm::make_ptr<lv2_obj, lv2_prx>() : std::make_shared<lv2_prx>();
// Access linkage information object
auto& link = g_fxo->get<ppu_linkage_info>();
@@ -1270,6 +1276,9 @@ std::shared_ptr<lv2_prx> ppu_load_prx(const ppu_prx_object& elf, const std::stri
u32 end = 0;
u32 toc = 0;
// 0x100000: Workaround for analyser glitches
u32 allocating_address = 0x100000;
for (const auto& prog : elf.progs)
{
ppu_loader.notice("** Segment: p_type=0x%x, p_vaddr=0x%llx, p_filesz=0x%llx, p_memsz=0x%llx, flags=0x%x", prog.p_type, prog.p_vaddr, prog.p_filesz, prog.p_memsz, prog.p_flags);
@@ -1294,15 +1303,42 @@ std::shared_ptr<lv2_prx> ppu_load_prx(const ppu_prx_object& elf, const std::stri
// Alloc segment memory
// Or use saved address
const u32 addr = !ar ? vm::alloc(mem_size, vm::main) : ar->operator u32();
u32 addr = 0;
if (!vm::check_addr(addr))
if (virtual_load)
{
addr = std::exchange(allocating_address, allocating_address + utils::align<u32>(mem_size, 0x10000));
}
else
{
addr = (!ar ? vm::alloc(mem_size, vm::main) : ar->operator u32());
}
_seg.ptr = vm::base(addr);
if (virtual_load)
{
// Leave additional room for the analyser so it can safely access beyond limit a bit
// Because with VM the address sapce is not really a limit so any u32 address is valid there, here it is UB to create pointer that goes beyond the boundaries
// TODO: Use make_shared_for_overwrite when all compilers support it
const usz alloc_size = utils::align<usz>(mem_size, 0x10000) + 4096;
prx->allocations.push_back(std::shared_ptr<u8[]>(new u8[alloc_size]));
_seg.ptr = prx->allocations.back().get();
std::memset(static_cast<u8*>(_seg.ptr) + prog.bin.size(), 0, alloc_size - 4096 - prog.bin.size());
}
else if (!vm::check_addr(addr))
{
fmt::throw_exception("vm::alloc() failed (size=0x%x)", mem_size);
}
_seg.addr = addr;
_seg.size = mem_size;
_seg.filesz = file_size;
prx->addr_to_seg_index.emplace(addr, prx->segs.size() - 1);
// Copy segment data
if (!ar) std::memcpy(vm::base(addr), prog.bin.data(), file_size);
if (!ar) std::memcpy(ensure(prx->get_ptr<void>(addr)), prog.bin.data(), file_size);
ppu_loader.warning("**** Loaded to 0x%x...0x%x (size=0x%x)", addr, addr + mem_size - 1, mem_size);
// Hash segment
@@ -1311,7 +1347,7 @@ std::shared_ptr<lv2_prx> ppu_load_prx(const ppu_prx_object& elf, const std::stri
sha1_update(&sha, prog.bin.data(), prog.bin.size());
// Initialize executable code if necessary
if (prog.p_flags & 0x1)
if (prog.p_flags & 0x1 && !virtual_load)
{
if (ar)
{
@@ -1321,10 +1357,6 @@ std::shared_ptr<lv2_prx> ppu_load_prx(const ppu_prx_object& elf, const std::stri
ppu_register_range(addr, mem_size);
}
_seg.addr = addr;
_seg.size = mem_size;
_seg.filesz = file_size;
}
break;
@@ -1420,63 +1452,63 @@ std::shared_ptr<lv2_prx> ppu_load_prx(const ppu_prx_object& elf, const std::stri
{
case 1: // R_PPC64_ADDR32
{
const u32 value = vm::_ref<u32>(raddr) = static_cast<u32>(rdata);
const u32 value = *ensure(prx->get_ptr<u32>(raddr)) = static_cast<u32>(rdata);
ppu_loader.trace("**** RELOCATION(1): 0x%x <- 0x%08x (0x%llx)", raddr, value, rdata);
break;
}
case 4: //R_PPC64_ADDR16_LO
{
const u16 value = vm::_ref<u16>(raddr) = static_cast<u16>(rdata);
const u16 value = *ensure(prx->get_ptr<u16>(raddr)) = static_cast<u16>(rdata);
ppu_loader.trace("**** RELOCATION(4): 0x%x <- 0x%04x (0x%llx)", raddr, value, rdata);
break;
}
case 5: //R_PPC64_ADDR16_HI
{
const u16 value = vm::_ref<u16>(raddr) = static_cast<u16>(rdata >> 16);
const u16 value = *ensure(prx->get_ptr<u16>(raddr)) = static_cast<u16>(rdata >> 16);
ppu_loader.trace("**** RELOCATION(5): 0x%x <- 0x%04x (0x%llx)", raddr, value, rdata);
break;
}
case 6: //R_PPC64_ADDR16_HA
{
const u16 value = vm::_ref<u16>(raddr) = static_cast<u16>(rdata >> 16) + (rdata & 0x8000 ? 1 : 0);
const u16 value = *ensure(prx->get_ptr<u16>(raddr)) = static_cast<u16>(rdata >> 16) + (rdata & 0x8000 ? 1 : 0);
ppu_loader.trace("**** RELOCATION(6): 0x%x <- 0x%04x (0x%llx)", raddr, value, rdata);
break;
}
case 10: //R_PPC64_REL24
{
const u32 value = vm::_ref<ppu_bf_t<be_t<u32>, 6, 24>>(raddr) = static_cast<u32>(rdata - raddr) >> 2;
const u32 value = *ensure(prx->get_ptr<ppu_bf_t<be_t<u32>, 6, 24>>(raddr)) = static_cast<u32>(rdata - raddr) >> 2;
ppu_loader.warning("**** RELOCATION(10): 0x%x <- 0x%06x (0x%llx)", raddr, value, rdata);
break;
}
case 11: //R_PPC64_REL14
{
const u32 value = vm::_ref<ppu_bf_t<be_t<u32>, 16, 14>>(raddr) = static_cast<u32>(rdata - raddr) >> 2;
const u32 value = *ensure(prx->get_ptr<ppu_bf_t<be_t<u32>, 16, 14>>(raddr)) = static_cast<u32>(rdata - raddr) >> 2;
ppu_loader.warning("**** RELOCATION(11): 0x%x <- 0x%06x (0x%llx)", raddr, value, rdata);
break;
}
case 38: //R_PPC64_ADDR64
{
const u64 value = vm::_ref<u64>(raddr) = rdata;
const u64 value = *ensure(prx->get_ptr<u64>(raddr)) = rdata;
ppu_loader.trace("**** RELOCATION(38): 0x%x <- 0x%016llx (0x%llx)", raddr, value, rdata);
break;
}
case 44: //R_PPC64_REL64
{
const u64 value = vm::_ref<u64>(raddr) = rdata - raddr;
const u64 value = *ensure(prx->get_ptr<u64>(raddr)) = rdata - raddr;
ppu_loader.trace("**** RELOCATION(44): 0x%x <- 0x%016llx (0x%llx)", raddr, value, rdata);
break;
}
case 57: //R_PPC64_ADDR16_LO_DS
{
const u16 value = vm::_ref<ppu_bf_t<be_t<u16>, 0, 14>>(raddr) = static_cast<u16>(rdata) >> 2;
const u16 value = *ensure(prx->get_ptr<ppu_bf_t<be_t<u16>, 0, 14>>(raddr)) = static_cast<u16>(rdata) >> 2;
ppu_loader.trace("**** RELOCATION(57): 0x%x <- 0x%04x (0x%llx)", raddr, value, rdata);
break;
}
@@ -1511,7 +1543,7 @@ std::shared_ptr<lv2_prx> ppu_load_prx(const ppu_prx_object& elf, const std::stri
};
// Access library information (TODO)
const vm::cptr<ppu_prx_library_info> lib_info = vm::cast(prx->segs[0].addr + elf.progs[0].p_paddr - elf.progs[0].p_offset);
const auto lib_info = ensure(prx->get_ptr<const ppu_prx_library_info>(prx->segs[0].addr + elf.progs[0].p_paddr - elf.progs[0].p_offset));
const std::string lib_name = lib_info->name;
strcpy_trunc(prx->module_info_name, lib_name);
@@ -1522,7 +1554,7 @@ std::shared_ptr<lv2_prx> ppu_load_prx(const ppu_prx_object& elf, const std::stri
prx->exports_start = lib_info->exports_start;
prx->exports_end = lib_info->exports_end;
for (usz start = prx->exports_start, size = 0;; size++, start += vm::read8(start) ? vm::read8(start) : sizeof(ppu_prx_module_info))
for (usz start = prx->exports_start, size = 0;; size++)
{
if (start >= prx->exports_end)
{
@@ -1530,18 +1562,25 @@ std::shared_ptr<lv2_prx> ppu_load_prx(const ppu_prx_object& elf, const std::stri
prx->m_external_loaded_flags.resize(size);
break;
}
const u8 increment = *ensure(prx->get_ptr<u8>(start));
start += increment ? increment : sizeof(ppu_prx_module_info);
}
ppu_loader.warning("Library %s (rtoc=0x%x):", lib_name, lib_info->toc);
prx->specials = ppu_load_exports(&link, prx->exports_start, prx->exports_end, true);
prx->imports = ppu_load_imports(prx->relocs, &link, lib_info->imports_start, lib_info->imports_end);
if (!virtual_load)
{
prx->specials = ppu_load_exports(&link, prx->exports_start, prx->exports_end, true);
prx->imports = ppu_load_imports(prx->relocs, &link, lib_info->imports_start, lib_info->imports_end);
}
std::stable_sort(prx->relocs.begin(), prx->relocs.end());
toc = lib_info->toc;
}
else
{
ppu_loader.fatal("Library %s: PRX library info not found");
ppu_loader.error("Library %s: PRX library info not found");
}
prx->start.set(prx->specials[0xbc9a0086]);
@@ -1578,12 +1617,12 @@ std::shared_ptr<lv2_prx> ppu_load_prx(const ppu_prx_object& elf, const std::stri
const std::string hash_seg = fmt::format("%s-%u", hash, i);
// Apply the patch
auto _applied = g_fxo->get<patch_engine>().apply(hash_seg, vm::get_super_ptr(seg.addr), seg.size);
auto _applied = g_fxo->get<patch_engine>().apply(hash_seg, [&](u32 addr, u32 size) { return prx->get_ptr<u8>(addr + seg.addr, size); }, seg.size);
if (!Emu.GetTitleID().empty())
{
// Alternative patch
_applied += g_fxo->get<patch_engine>().apply(Emu.GetTitleID() + '-' + hash_seg, vm::get_super_ptr(seg.addr), seg.size);
_applied += g_fxo->get<patch_engine>().apply(Emu.GetTitleID() + '-' + hash_seg, [&](u32 addr, u32 size) { return prx->get_ptr<u8>(addr + seg.addr, size); }, seg.size);
}
// Rebase patch offsets
@@ -1604,12 +1643,15 @@ std::shared_ptr<lv2_prx> ppu_load_prx(const ppu_prx_object& elf, const std::stri
// Embedded SPU elf patching
for (const auto& seg : prx->segs)
{
ppu_check_patch_spu_images(seg);
ppu_check_patch_spu_images(*prx, seg);
}
prx->analyse(toc, 0, end, applied);
try_spawn_ppu_if_exclusive_program(*prx);
if (!ar && !virtual_load)
{
try_spawn_ppu_if_exclusive_program(*prx);
}
return prx;
}
@@ -1666,7 +1708,10 @@ void ppu_unload_prx(const lv2_prx& prx)
{
if (!seg.size) continue;
vm::dealloc(seg.addr, vm::main);
if (seg.ptr == vm::base(seg.addr))
{
vm::dealloc(seg.addr, vm::main);
}
const std::string hash_seg = fmt::format("%s-%u", hash, &seg - prx.segs.data());
@@ -1681,7 +1726,7 @@ void ppu_unload_prx(const lv2_prx& prx)
}
}
bool ppu_load_exec(const ppu_exec_object& elf, utils::serial* ar)
bool ppu_load_exec(const ppu_exec_object& elf, bool virtual_load, const std::string& elf_path, utils::serial* ar)
{
if (elf != elf_error::ok)
{
@@ -1752,6 +1797,14 @@ bool ppu_load_exec(const ppu_exec_object& elf, utils::serial* ar)
} error_handler{_main};
if (virtual_load)
{
// No need for cleanup
error_handler.errored = false;
}
const auto old_process_info = g_ps3_process_info;
// Allocate memory at fixed positions
for (const auto& prog : elf.progs)
{
@@ -1773,13 +1826,25 @@ bool ppu_load_exec(const ppu_exec_object& elf, utils::serial* ar)
{
if (prog.bin.size() > size || prog.bin.size() != prog.p_filesz)
{
ppu_loader.fatal("ppu_load_exec(): Invalid binary size (0x%llx, memsz=0x%x)", prog.bin.size(), size);
ppu_loader.error("ppu_load_exec(): Invalid binary size (0x%llx, memsz=0x%x)", prog.bin.size(), size);
return false;
}
const bool already_loaded = ar && vm::check_addr(addr, vm::page_readable, size);
if (already_loaded)
_seg.ptr = vm::base(addr);
if (virtual_load)
{
// Leave additional room for the analyser so it can safely access beyond limit a bit
// Because with VM the address sapce is not really a limit so any u32 address is valid there, here it is UB to create pointer that goes beyond the boundaries
// TODO: Use make_shared_for_overwrite when all compilers support it
const usz alloc_size = utils::align<usz>(size, 0x10000) + 4096;
_main.allocations.push_back(std::shared_ptr<u8[]>(new u8[alloc_size]));
_seg.ptr = _main.allocations.back().get();
std::memset(static_cast<u8*>(_seg.ptr) + prog.bin.size(), 0, alloc_size - 4096 - prog.bin.size());
}
else if (already_loaded)
{
}
else if (!vm::falloc(addr, size, vm::main))
@@ -1788,15 +1853,19 @@ bool ppu_load_exec(const ppu_exec_object& elf, utils::serial* ar)
if (!vm::falloc(addr, size))
{
ppu_loader.fatal("ppu_load_exec(): vm::falloc() failed (addr=0x%x, memsz=0x%x)", addr, size);
ppu_loader.error("ppu_load_exec(): vm::falloc() failed (addr=0x%x, memsz=0x%x)", addr, size);
return false;
}
}
// Store only LOAD segments (TODO)
_main.segs.emplace_back(_seg);
_main.addr_to_seg_index.emplace(addr, _main.segs.size() - 1);
// Copy segment data, hash it
if (!already_loaded)
{
std::memcpy(vm::base(addr), prog.bin.data(), prog.bin.size());
std::memcpy(_main.get_ptr<void>(addr), prog.bin.data(), prog.bin.size());
}
else
{
@@ -1811,7 +1880,7 @@ bool ppu_load_exec(const ppu_exec_object& elf, utils::serial* ar)
sha1_update(&sha, prog.bin.data(), prog.bin.size());
// Initialize executable code if necessary
if (prog.p_flags & 0x1)
if (prog.p_flags & 0x1 && !virtual_load)
{
if (already_loaded && ar)
{
@@ -1821,9 +1890,6 @@ bool ppu_load_exec(const ppu_exec_object& elf, utils::serial* ar)
ppu_register_range(addr, size);
}
// Store only LOAD segments (TODO)
_main.segs.emplace_back(_seg);
}
}
@@ -1867,12 +1933,12 @@ bool ppu_load_exec(const ppu_exec_object& elf, utils::serial* ar)
Emu.SetExecutableHash(hash);
// Apply the patch
auto applied = g_fxo->get<patch_engine>().apply(!ar ? hash : std::string{}, vm::g_base_addr);
auto applied = g_fxo->get<patch_engine>().apply(!ar ? hash : std::string{}, [&](u32 addr, u32 size) { return _main.get_ptr<u8>(addr, size); });
if (!ar && !Emu.GetTitleID().empty())
{
// Alternative patch
applied += g_fxo->get<patch_engine>().apply(Emu.GetTitleID() + '-' + hash, vm::g_base_addr);
applied += g_fxo->get<patch_engine>().apply(Emu.GetTitleID() + '-' + hash, [&](u32 addr, u32 size) { return _main.get_ptr<u8>(addr, size); });
}
if (applied.empty())
@@ -1890,11 +1956,11 @@ bool ppu_load_exec(const ppu_exec_object& elf, utils::serial* ar)
// Embedded SPU elf patching
for (const auto& seg : _main.segs)
{
ppu_check_patch_spu_images(seg);
ppu_check_patch_spu_images(_main, seg);
}
// Static HLE patching
if (g_cfg.core.hook_functions)
if (g_cfg.core.hook_functions && !virtual_load)
{
auto shle = g_fxo->init<statichle_handler>(0);
@@ -1942,7 +2008,7 @@ bool ppu_load_exec(const ppu_exec_object& elf, utils::serial* ar)
if ((prog.p_vaddr | prog.p_filesz | prog.p_memsz) > u32{umax})
{
ppu_loader.fatal("ppu_load_exec(): TLS segment is invalid!");
ppu_loader.error("ppu_load_exec(): TLS segment is invalid!");
return false;
}
@@ -1969,7 +2035,7 @@ bool ppu_load_exec(const ppu_exec_object& elf, utils::serial* ar)
//be_t<u32> crash_dump_param_addr;
};
const auto& info = vm::_ref<process_param_t>(vm::cast(prog.p_vaddr));
const auto& info = *ensure(_main.get_ptr<process_param_t>(vm::cast(prog.p_vaddr)));
if (info.size < sizeof(process_param_t))
{
@@ -2024,7 +2090,7 @@ bool ppu_load_exec(const ppu_exec_object& elf, utils::serial* ar)
be_t<u32> unk2;
};
const auto& proc_prx_param = vm::_ref<const ppu_proc_prx_param_t>(vm::cast(prog.p_vaddr));
const auto& proc_prx_param = *ensure(_main.get_ptr<const ppu_proc_prx_param_t>(vm::cast(prog.p_vaddr)));
ppu_loader.notice("* libent_start = *0x%x", proc_prx_param.libent_start);
ppu_loader.notice("* libstub_start = *0x%x", proc_prx_param.libstub_start);
@@ -2033,12 +2099,16 @@ bool ppu_load_exec(const ppu_exec_object& elf, utils::serial* ar)
if (proc_prx_param.magic != 0x1b434cecu)
{
ppu_loader.fatal("ppu_load_exec(): Bad magic! (0x%x)", proc_prx_param.magic);
ppu_loader.error("ppu_load_exec(): Bad magic! (0x%x)", proc_prx_param.magic);
return false;
}
ppu_load_exports(&link, proc_prx_param.libent_start, proc_prx_param.libent_end);
ppu_load_imports(_main.relocs, &link, proc_prx_param.libstub_start, proc_prx_param.libstub_end);
if (!virtual_load)
{
ppu_load_exports(&link, proc_prx_param.libent_start, proc_prx_param.libent_end);
ppu_load_imports(_main.relocs, &link, proc_prx_param.libstub_start, proc_prx_param.libstub_end);
}
std::stable_sort(_main.relocs.begin(), _main.relocs.end());
}
break;
@@ -2105,7 +2175,7 @@ bool ppu_load_exec(const ppu_exec_object& elf, utils::serial* ar)
load_libs.emplace("libsysmodule.sprx");
}
if (ar || Emu.IsVsh())
if (ar || Emu.IsVsh() || virtual_load)
{
// Cannot be used with vsh.self or savestates (they self-manage itself)
load_libs.clear();
@@ -2121,35 +2191,45 @@ bool ppu_load_exec(const ppu_exec_object& elf, utils::serial* ar)
}
// Program entry
u32 entry = 0;
u32 entry = static_cast<u32>(elf.header.e_entry); // Run entry from elf (HLE)
// Set path (TODO)
_main.name.clear();
_main.path = vfs::get(Emu.argv[0]);
_main.path = elf_path;
_main.elf_entry = static_cast<u32>(elf.header.e_entry);
_main.seg0_code_end = end;
_main.applied_pathes = applied;
// Set SDK version
g_ps3_process_info.sdk_ver = sdk_version;
// Set ppc fixed allocations segment permission
g_ps3_process_info.ppc_seg = ppc_seg;
if (Emu.init_mem_containers)
if (!virtual_load)
{
// Refer to sys_process_exit2 for explanation
Emu.init_mem_containers(mem_size);
}
else if (!ar)
{
g_fxo->init<id_manager::id_map<lv2_memory_container>>();
g_fxo->init<lv2_memory_container>(mem_size);
}
// Set SDK version
g_ps3_process_info.sdk_ver = sdk_version;
void init_fxo_for_exec(utils::serial* ar, bool full);
init_fxo_for_exec(ar, false);
// Set ppc fixed allocations segment permission
g_ps3_process_info.ppc_seg = ppc_seg;
if (Emu.init_mem_containers)
{
// Refer to sys_process_exit2 for explanation
// Make init_mem_containers empty before call
const auto callback = std::move(Emu.init_mem_containers);
callback(mem_size);
}
else if (!ar)
{
g_fxo->init<id_manager::id_map<lv2_memory_container>>();
g_fxo->init<lv2_memory_container>(mem_size);
}
void init_fxo_for_exec(utils::serial* ar, bool full);
init_fxo_for_exec(ar, false);
}
else
{
g_ps3_process_info = old_process_info;
Emu.ConfigurePPUCache();
}
liblv2_begin = 0;
liblv2_end = 0;
@@ -2164,13 +2244,13 @@ bool ppu_load_exec(const ppu_exec_object& elf, utils::serial* ar)
{
ppu_loader.warning("Loading library: %s", name);
auto prx = ppu_load_prx(obj, lle_dir + name, 0, nullptr);
auto prx = ppu_load_prx(obj, false, lle_dir + name, 0, nullptr);
prx->state = PRX_STATE_STARTED;
prx->load_exports();
if (prx->funcs.empty())
{
ppu_loader.fatal("Module %s has no functions!", name);
ppu_loader.error("Module %s has no functions!", name);
}
else
{
@@ -2195,7 +2275,7 @@ bool ppu_load_exec(const ppu_exec_object& elf, utils::serial* ar)
}
}
if (ar)
if (ar || virtual_load)
{
error_handler.errored = false;
return true;
@@ -2264,6 +2344,7 @@ bool ppu_load_exec(const ppu_exec_object& elf, utils::serial* ar)
ppu_thread_params p{};
p.stack_addr = vm::cast(vm::alloc(primary_stacksize, vm::stack, 4096));
p.stack_size = primary_stacksize;
p.entry = vm::_ref<ppu_func_opd_t>(entry);
auto ppu = idm::make_ptr<named_thread<ppu_thread>>(p, "main_thread", primary_prio, 1);
@@ -2278,7 +2359,7 @@ bool ppu_load_exec(const ppu_exec_object& elf, utils::serial* ar)
ppu->cmd_push({ppu_cmd::initialize, 0});
if (!entry && !Emu.IsVsh())
if (entry == static_cast<u32>(elf.header.e_entry) && !Emu.IsVsh())
{
// Set TLS args, call sys_initialize_tls
ppu->cmd_list
@@ -2288,11 +2369,6 @@ bool ppu_load_exec(const ppu_exec_object& elf, utils::serial* ar)
});
}
if (!entry)
{
entry = static_cast<u32>(elf.header.e_entry); // Run entry from elf
}
// Run start functions
for (const auto& prx : loaded_modules)
{
@@ -2315,7 +2391,7 @@ bool ppu_load_exec(const ppu_exec_object& elf, utils::serial* ar)
{ ppu_cmd::set_args, 8 }, u64{Emu.argv.size()}, u64{argv.addr()}, u64{envp.addr()}, u64{0}, u64{ppu->id}, u64{tls_vaddr}, u64{tls_fsize}, u64{tls_vsize},
{ ppu_cmd::set_gpr, 11 }, u64{elf.header.e_entry},
{ ppu_cmd::set_gpr, 12 }, u64{malloc_pagesize},
{ ppu_cmd::lle_call, entry },
{ ppu_cmd::entry_call, 0 },
});
// Set actual memory protection (experimental)
@@ -2335,7 +2411,7 @@ bool ppu_load_exec(const ppu_exec_object& elf, utils::serial* ar)
return true;
}
std::pair<std::shared_ptr<lv2_overlay>, CellError> ppu_load_overlay(const ppu_exec_object& elf, const std::string& path, s64 file_offset, utils::serial* ar)
std::pair<std::shared_ptr<lv2_overlay>, CellError> ppu_load_overlay(const ppu_exec_object& elf, bool virtual_load, const std::string& path, s64 file_offset, utils::serial* ar)
{
if (elf != elf_error::ok)
{
@@ -2399,11 +2475,23 @@ std::pair<std::shared_ptr<lv2_overlay>, CellError> ppu_load_overlay(const ppu_ex
const bool already_loaded = !!ar; // Unimplemented optimization for savestates
if (already_loaded)
_seg.ptr = vm::base(addr);
if (virtual_load)
{
// Leave additional room for the analyser so it can safely access beyond limit a bit
// Because with VM the address sapce is not really a limit so any u32 address is valid there, here it is UB to create pointer that goes beyond the boundaries
// TODO: Use make_shared_for_overwrite when all compilers support it
const usz alloc_size = utils::align<usz>(size, 0x10000) + 4096;
ovlm->allocations.push_back(std::shared_ptr<u8[]>(new u8[alloc_size]));
_seg.ptr = ovlm->allocations.back().get();
std::memset(static_cast<u8*>(_seg.ptr) + prog.bin.size(), 0, alloc_size - 4096 - prog.bin.size());
}
else if (already_loaded)
{
if (!vm::check_addr(addr, vm::page_readable, size))
{
ppu_loader.fatal("ppu_load_overlay(): Archived PPU overlay memory has not been found! (addr=0x%x, memsz=0x%x)", addr, size);
ppu_loader.error("ppu_load_overlay(): Archived PPU overlay memory has not been found! (addr=0x%x, memsz=0x%x)", addr, size);
return {nullptr, CELL_EABORT};
}
}
@@ -2421,14 +2509,18 @@ std::pair<std::shared_ptr<lv2_overlay>, CellError> ppu_load_overlay(const ppu_ex
return {nullptr, CELL_EBUSY};
}
// Store only LOAD segments (TODO)
ovlm->segs.emplace_back(_seg);
ovlm->addr_to_seg_index.emplace(addr, ovlm->segs.size() - 1);
// Copy segment data, hash it
if (!already_loaded) std::memcpy(vm::base(addr), prog.bin.data(), prog.bin.size());
if (!already_loaded) std::memcpy(ensure(ovlm->get_ptr<void>(addr)), prog.bin.data(), prog.bin.size());
sha1_update(&sha, reinterpret_cast<const uchar*>(&prog.p_vaddr), sizeof(prog.p_vaddr));
sha1_update(&sha, reinterpret_cast<const uchar*>(&prog.p_memsz), sizeof(prog.p_memsz));
sha1_update(&sha, prog.bin.data(), prog.bin.size());
// Initialize executable code if necessary
if (prog.p_flags & 0x1)
if (prog.p_flags & 0x1 && !virtual_load)
{
if (ar)
{
@@ -2438,9 +2530,6 @@ std::pair<std::shared_ptr<lv2_overlay>, CellError> ppu_load_overlay(const ppu_ex
ppu_register_range(addr, size);
}
// Store only LOAD segments (TODO)
ovlm->segs.emplace_back(_seg);
}
}
@@ -2482,18 +2571,18 @@ std::pair<std::shared_ptr<lv2_overlay>, CellError> ppu_load_overlay(const ppu_ex
}
// Apply the patch
auto applied = g_fxo->get<patch_engine>().apply(hash, vm::g_base_addr);
auto applied = g_fxo->get<patch_engine>().apply(hash, [ovlm](u32 addr, u32 size) { return ovlm->get_ptr<u8>(addr, size); });
if (!Emu.GetTitleID().empty())
{
// Alternative patch
applied += g_fxo->get<patch_engine>().apply(Emu.GetTitleID() + '-' + hash, vm::g_base_addr);
applied += g_fxo->get<patch_engine>().apply(Emu.GetTitleID() + '-' + hash, [ovlm](u32 addr, u32 size) { return ovlm->get_ptr<u8>(addr, size); });
}
// Embedded SPU elf patching
for (const auto& seg : ovlm->segs)
{
ppu_check_patch_spu_images(seg);
ppu_check_patch_spu_images(*ovlm, seg);
}
if (applied.empty())
@@ -2526,7 +2615,7 @@ std::pair<std::shared_ptr<lv2_overlay>, CellError> ppu_load_overlay(const ppu_ex
//and a lot of zeros.
};
const auto& info = vm::_ref<process_param_t>(vm::cast(prog.p_vaddr));
const auto& info = *ensure(ovlm->get_ptr<process_param_t>(vm::cast(prog.p_vaddr)));
if (info.size < sizeof(process_param_t))
{
@@ -2564,7 +2653,7 @@ std::pair<std::shared_ptr<lv2_overlay>, CellError> ppu_load_overlay(const ppu_ex
be_t<u32> unk2;
};
const auto& proc_prx_param = vm::_ref<const ppu_proc_prx_param_t>(vm::cast(prog.p_vaddr));
const auto& proc_prx_param = *ensure(ovlm->get_ptr<const ppu_proc_prx_param_t>(vm::cast(prog.p_vaddr)));
ppu_loader.notice("* libent_start = *0x%x", proc_prx_param.libent_start);
ppu_loader.notice("* libstub_start = *0x%x", proc_prx_param.libstub_start);
@@ -2576,8 +2665,11 @@ std::pair<std::shared_ptr<lv2_overlay>, CellError> ppu_load_overlay(const ppu_ex
fmt::throw_exception("Bad magic! (0x%x)", proc_prx_param.magic);
}
ppu_load_exports(&link, proc_prx_param.libent_start, proc_prx_param.libent_end);
ppu_load_imports(ovlm->relocs, &link, proc_prx_param.libstub_start, proc_prx_param.libstub_end);
if (!virtual_load)
{
ppu_load_exports(&link, proc_prx_param.libent_start, proc_prx_param.libent_end);
ppu_load_imports(ovlm->relocs, &link, proc_prx_param.libstub_start, proc_prx_param.libstub_end);
}
}
break;
}
@@ -2590,13 +2682,21 @@ std::pair<std::shared_ptr<lv2_overlay>, CellError> ppu_load_overlay(const ppu_ex
ovlm->entry = static_cast<u32>(elf.header.e_entry);
const auto cpu = cpu_thread::get_current();
// Analyse executable (TODO)
ovlm->analyse(0, ovlm->entry, end, applied);
if (!ovlm->analyse(0, ovlm->entry, end, applied, !cpu ? std::function<bool()>() : [cpu, is_being_used_in_emulation = (vm::base(ovlm->segs[0].addr) == ovlm->segs[0].ptr)]()
{
return is_being_used_in_emulation && cpu->state & cpu_flag::exit;
}))
{
return {nullptr, CellError{CELL_CANCEL + 0u}};
}
// Validate analyser results (not required)
ovlm->validate(0);
if (!ar)
if (!ar && !virtual_load)
{
idm::import_existing<lv2_obj, lv2_overlay>(ovlm);
try_spawn_ppu_if_exclusive_program(*ovlm);
@@ -2644,7 +2744,7 @@ bool ppu_load_rel_exec(const ppu_rel_object& elf)
if (!addr)
{
ppu_loader.fatal("ppu_load_rel_exec(): vm::alloc() failed (memsz=0x%x)", memsize);
ppu_loader.error("ppu_load_rel_exec(): vm::alloc() failed (memsz=0x%x)", memsize);
return false;
}
+4 -1
View File
@@ -674,6 +674,7 @@ namespace ppu_instructions
inline u32 ADDI(u32 rt, u32 ra, s32 si) { ppu_opcode_t op{ 0x0eu << 26 }; op.rd = rt; op.ra = ra; op.simm16 = si; return op.opcode; }
inline u32 ADDIS(u32 rt, u32 ra, s32 si) { ppu_opcode_t op{ 0x0fu << 26 }; op.rd = rt; op.ra = ra; op.simm16 = si; return op.opcode; }
inline u32 XORIS(u32 rt, u32 ra, s32 si) { ppu_opcode_t op{ 0x1bu << 26 }; op.rd = rt; op.ra = ra; op.simm16 = si; return op.opcode; }
inline u32 ORI(u32 rt, u32 ra, u32 ui) { ppu_opcode_t op{ 0x18u << 26 }; op.rd = rt; op.ra = ra; op.uimm16 = ui; return op.opcode; }
inline u32 ORIS(u32 rt, u32 ra, u32 ui) { ppu_opcode_t op{ 0x19u << 26 }; op.rd = rt; op.ra = ra; op.uimm16 = ui; return op.opcode; }
inline u32 OR(u32 ra, u32 rs, u32 rb, bool rc = false) { ppu_opcode_t op{ 0x1fu << 26 | 0x1bcu << 1 }; op.rs = rs; op.ra = ra; op.rb = rb; op.rc = rc; return op.opcode; }
@@ -685,6 +686,7 @@ namespace ppu_instructions
inline u32 MFSPR(u32 rt, u32 spr) { ppu_opcode_t op{ 0x1fu << 26 | 0x153u << 1 }; op.rd = rt; op.spr = spr; return op.opcode; }
inline u32 MTSPR(u32 spr, u32 rs) { ppu_opcode_t op{ 0x1fu << 26 | 0x1d3u << 1 }; op.rs = rs; op.spr = spr; return op.opcode; }
inline u32 LWZ(u32 rt, u32 ra, s32 si) { ppu_opcode_t op{ 0x20u << 26 }; op.rd = rt; op.ra = ra; op.simm16 = si; return op.opcode; }
inline u32 STW(u32 rt, u32 ra, s32 si) { ppu_opcode_t op{ 0x24u << 26 }; op.rd = rt; op.ra = ra; op.simm16 = si; return op.opcode; }
inline u32 STD(u32 rs, u32 ra, s32 si) { ppu_opcode_t op{ 0x3eu << 26 }; op.rs = rs; op.ra = ra; op.ds = si / 4; return op.opcode; }
inline u32 STDU(u32 rs, u32 ra, s32 si) { ppu_opcode_t op{ 0x3eu << 26 | 1 }; op.rs = rs; op.ra = ra; op.ds = si / 4; return op.opcode; }
inline u32 LD(u32 rt, u32 ra, s32 si) { ppu_opcode_t op{ 0x3au << 26 }; op.rd = rt; op.ra = ra; op.ds = si / 4; return op.opcode; }
@@ -697,6 +699,7 @@ namespace ppu_instructions
inline u32 STVX(u32 vs, u32 ra, u32 rb) { ppu_opcode_t op{ 31 << 26 | 231 << 1 }; op.vs = vs; op.ra = ra; op.rb = rb; return op.opcode; }
inline u32 LFD(u32 frd, u32 ra, s32 si) { ppu_opcode_t op{ 50u << 26 }; op.frd = frd; op.ra = ra; op.simm16 = si; return op.opcode; }
inline u32 LVX(u32 vd, u32 ra, u32 rb) { ppu_opcode_t op{ 31 << 26 | 103 << 1 }; op.vd = vd; op.ra = ra; op.rb = rb; return op.opcode; }
inline constexpr u32 EIEIO() { return 0x7c0006ac; }
namespace implicts
{
@@ -734,7 +737,7 @@ namespace ppu_instructions
inline u32 CLRLDI(u32 x, u32 y, u32 n) { return RLDICL(x, y, 0, n, false); }
inline u32 CLRRDI(u32 x, u32 y, u32 n) { return RLDICR(x, y, 0, 63 - n, false); }
inline u32 TRAP() { return 0x7FE00008; } // tw 31,r0,r0
inline constexpr u32 TRAP() { return 0x7FE00008; } // tw 31,r0,r0
}
using namespace implicts;
+485 -107
View File
@@ -62,7 +62,9 @@
#include <thread>
#include <cfenv>
#include <cctype>
#include <span>
#include <optional>
#include "util/asm.hpp"
#include "util/vm.hpp"
#include "util/v128.hpp"
@@ -131,14 +133,26 @@ void fmt_class_string<typename ppu_thread::call_history_t>::format(std::string&
PPUDisAsm dis_asm(cpu_disasm_mode::normal, vm::g_sudo_addr);
for (u64 count = 0, idx = history.index - 1; idx != umax && count < ppu_thread::call_history_max_size; count++, idx--)
for (u64 count = 0, idx = history.index - 1; idx != umax && count < history.data.size(); count++, idx--)
{
const u32 pc = history.data[idx % ppu_thread::call_history_max_size];
const u32 pc = history.data[idx % history.data.size()];
dis_asm.disasm(pc);
fmt::append(out, "\n(%u) 0x%08x: %s", count, pc, dis_asm.last_opcode);
}
}
template <>
void fmt_class_string<typename ppu_thread::syscall_history_t>::format(std::string& out, u64 arg)
{
const auto& history = get_object(arg);
for (u64 count = 0, idx = history.index - 1; idx != umax && count < history.data.size(); count++, idx--)
{
const auto& entry = history.data[idx % history.data.size()];
fmt::append(out, "\n(%u) 0x%08x: %s, 0x%x, r3=0x%x, r4=0x%x, r5=0x%x, r6=0x%x", count, entry.cia, entry.func_name, entry.error, entry.args[0], entry.args[1], entry.args[2], entry.args[3]);
}
}
extern const ppu_decoder<ppu_itype> g_ppu_itype{};
extern const ppu_decoder<ppu_iname> g_ppu_iname{};
@@ -161,9 +175,10 @@ extern void ppu_initialize();
extern void ppu_finalize(const ppu_module& info);
extern bool ppu_initialize(const ppu_module& info, bool = false);
static void ppu_initialize2(class jit_compiler& jit, const ppu_module& module_part, const std::string& cache_path, const std::string& obj_name);
extern std::pair<std::shared_ptr<lv2_overlay>, CellError> ppu_load_overlay(const ppu_exec_object&, const std::string& path, s64 file_offset, utils::serial* = nullptr);
extern bool ppu_load_exec(const ppu_exec_object&, bool virtual_load, const std::string&, utils::serial* = nullptr);
extern std::pair<std::shared_ptr<lv2_overlay>, CellError> ppu_load_overlay(const ppu_exec_object&, bool virtual_load, const std::string& path, s64 file_offset, utils::serial* = nullptr);
extern void ppu_unload_prx(const lv2_prx&);
extern std::shared_ptr<lv2_prx> ppu_load_prx(const ppu_prx_object&, const std::string&, s64 file_offset, utils::serial* = nullptr);
extern std::shared_ptr<lv2_prx> ppu_load_prx(const ppu_prx_object&, bool virtual_load, const std::string&, s64 file_offset, utils::serial* = nullptr);
extern void ppu_execute_syscall(ppu_thread& ppu, u64 code);
static void ppu_break(ppu_thread&, ppu_opcode_t, be_t<u32>*, ppu_intrp_func*);
@@ -484,16 +499,198 @@ void ppu_reservation_fallback(ppu_thread& ppu)
}
}
static std::unordered_map<u32, u32>* s_ppu_toc;
u32 ppu_read_mmio_aware_u32(u8* vm_base, u32 eal)
{
if (eal >= RAW_SPU_BASE_ADDR)
{
// RawSPU MMIO
auto thread = idm::get<named_thread<spu_thread>>(spu_thread::find_raw_spu((eal - RAW_SPU_BASE_ADDR) / RAW_SPU_OFFSET));
if (!thread)
{
// Access Violation
}
else if ((eal - RAW_SPU_BASE_ADDR) % RAW_SPU_OFFSET + sizeof(u32) - 1 < SPU_LS_SIZE) // LS access
{
}
else if (u32 value{}; thread->read_reg(eal, value))
{
return std::bit_cast<be_t<u32>>(value);
}
else
{
fmt::throw_exception("Invalid RawSPU MMIO offset (addr=0x%x)", eal);
}
}
// Value is assumed to be swapped
return read_from_ptr<u32>(vm_base + eal);
}
void ppu_write_mmio_aware_u32(u8* vm_base, u32 eal, u32 value)
{
if (eal >= RAW_SPU_BASE_ADDR)
{
// RawSPU MMIO
auto thread = idm::get<named_thread<spu_thread>>(spu_thread::find_raw_spu((eal - RAW_SPU_BASE_ADDR) / RAW_SPU_OFFSET));
if (!thread)
{
// Access Violation
}
else if ((eal - RAW_SPU_BASE_ADDR) % RAW_SPU_OFFSET + sizeof(u32) - 1 < SPU_LS_SIZE) // LS access
{
}
else if (thread->write_reg(eal, std::bit_cast<be_t<u32>>(value)))
{
return;
}
else
{
fmt::throw_exception("Invalid RawSPU MMIO offset (addr=0x%x)", eal);
}
}
// Value is assumed swapped
write_to_ptr<u32>(vm_base + eal, value);
}
extern bool ppu_test_address_may_be_mmio(std::span<const be_t<u32>> insts)
{
std::set<u32> reg_offsets;
bool found_raw_spu_base = false;
bool found_spu_area_offset_element = false;
for (u32 inst : insts)
{
// Common around MMIO (orders IO)
if (inst == ppu_instructions::EIEIO())
{
return true;
}
const u32 op_imm16 = (inst & 0xfc00ffff);
// RawSPU MMIO base
// 0xe00000000 is a common constant so try to find an ORIS 0x10 or ADDIS 0x10 nearby (for multiplying SPU ID by it)
if (op_imm16 == ppu_instructions::ADDIS({}, {}, -0x2000) || op_imm16 == ppu_instructions::ORIS({}, {}, 0xe000) || op_imm16 == ppu_instructions::XORIS({}, {}, 0xe000))
{
found_raw_spu_base = true;
if (found_spu_area_offset_element)
{
// Found both
return true;
}
}
else if (op_imm16 == ppu_instructions::ORIS({}, {}, 0x10) || op_imm16 == ppu_instructions::ADDIS({}, {}, 0x10))
{
found_spu_area_offset_element = true;
if (found_raw_spu_base)
{
// Found both
return true;
}
}
// RawSPU MMIO base + problem state offset
else if (op_imm16 == ppu_instructions::ADDIS({}, {}, -0x1ffc))
{
return true;
}
else if (op_imm16 == ppu_instructions::ORIS({}, {}, 0xe004))
{
return true;
}
else if (op_imm16 == ppu_instructions::XORIS({}, {}, 0xe004))
{
return true;
}
// RawSPU MMIO base + problem state offset + 64k of SNR1 offset
else if (op_imm16 == ppu_instructions::ADDIS({}, {}, -0x1ffb))
{
return true;
}
else if (op_imm16 == ppu_instructions::ORIS({}, {}, 0xe005))
{
return true;
}
else if (op_imm16 == ppu_instructions::XORIS({}, {}, 0xe005))
{
return true;
}
// RawSPU MMIO base + problem state offset + 264k of SNR2 offset (STW allows 32K+- offset so in order to access SNR2 it needs to first add another 64k)
// SNR2 is the only register currently implemented that has its 0x80000 bit is set so its the only one its hardcoded access is done this way
else if (op_imm16 == ppu_instructions::ADDIS({}, {}, -0x1ffa))
{
return true;
}
else if (op_imm16 == ppu_instructions::ORIS({}, {}, 0xe006))
{
return true;
}
else if (op_imm16 == ppu_instructions::XORIS({}, {}, 0xe006))
{
return true;
}
// Try to detect a function that receives RawSPU problem state base pointer as an argument
else if ((op_imm16 & ~0xffff) == ppu_instructions::LWZ({}, {}, 0) ||
(op_imm16 & ~0xffff) == ppu_instructions::STW({}, {}, 0) ||
(op_imm16 & ~0xffff) == ppu_instructions::ADDI({}, {}, 0))
{
const bool is_load = (op_imm16 & ~0xffff) == ppu_instructions::LWZ({}, {}, 0);
const bool is_store = (op_imm16 & ~0xffff) == ppu_instructions::STW({}, {}, 0);
const bool is_neither = !is_store && !is_load;
const bool is_snr = (is_store || is_neither) && ((op_imm16 & 0xffff) == (SPU_RdSigNotify2_offs & 0xffff) || (op_imm16 & 0xffff) == (SPU_RdSigNotify1_offs & 0xffff));
if (is_snr || spu_thread::test_is_problem_state_register_offset(op_imm16 & 0xffff, is_load || is_neither, is_store || is_neither))
{
reg_offsets.insert(op_imm16 & 0xffff);
if (reg_offsets.size() >= 2)
{
// Assume high MMIO likelyhood if more than one offset appears in nearby code
// Such as common IN_MBOX + OUT_MBOX
return true;
}
}
}
}
return false;
}
struct ppu_toc_manager
{
std::unordered_map<u32, u32> toc_map;
shared_mutex mutex;
};
static void ppu_check_toc(ppu_thread& ppu, ppu_opcode_t op, be_t<u32>* this_op, ppu_intrp_func* next_fn)
{
// Compare TOC with expected value
const auto found = s_ppu_toc->find(ppu.cia);
ppu.cia = vm::get_addr(this_op);
if (ppu.gpr[2] != found->second)
{
ppu_log.error("Unexpected TOC (0x%x, expected 0x%x)", ppu.gpr[2], found->second);
auto& toc_manager = g_fxo->get<ppu_toc_manager>();
reader_lock lock(toc_manager.mutex);
auto& ppu_toc = toc_manager.toc_map;
const auto found = ppu_toc.find(ppu.cia);
if (found != ppu_toc.end())
{
const u32 toc = atomic_storage<u32>::load(found->second);
// Compare TOC with expected value
if (toc != umax && ppu.gpr[2] != toc)
{
ppu_log.error("Unexpected TOC (0x%x, expected 0x%x)", ppu.gpr[2], toc);
atomic_storage<u32>::exchange(found->second, u32{umax});
}
}
}
// Fallback to the interpreter function
@@ -887,7 +1084,7 @@ void ppu_remove_hle_instructions(u32 addr, u32 size)
}
}
atomic_t<bool> g_debugger_pause_all_threads_on_bp = true;
atomic_t<bool> g_debugger_pause_all_threads_on_bp = false;
// Breakpoint entry point
static void ppu_break(ppu_thread& ppu, ppu_opcode_t, be_t<u32>* this_op, ppu_intrp_func* next_fn)
@@ -1038,8 +1235,30 @@ std::array<u32, 2> op_branch_targets(u32 pc, ppu_opcode_t op)
return res;
}
void ppu_thread::dump_regs(std::string& ret) const
void ppu_thread::dump_regs(std::string& ret, std::any& custom_data) const
{
const system_state emu_state = Emu.GetStatus(false);
const bool is_stopped_or_frozen = state & cpu_flag::exit || emu_state == system_state::frozen || emu_state <= system_state::stopping;
const ppu_debugger_mode mode = debugger_mode.load();
const bool is_decimal = !is_stopped_or_frozen && mode == ppu_debugger_mode::is_decimal;
struct dump_registers_data_t
{
u32 preferred_cr_field_index = 7;
};
dump_registers_data_t* func_data = nullptr;
func_data = std::any_cast<dump_registers_data_t>(&custom_data);
if (!func_data)
{
custom_data.reset();
custom_data = std::make_any<dump_registers_data_t>();
func_data = ensure(std::any_cast<dump_registers_data_t>(&custom_data));
}
PPUDisAsm dis_asm(cpu_disasm_mode::normal, vm::g_sudo_addr);
for (uint i = 0; i < 32; ++i)
@@ -1081,7 +1300,14 @@ void ppu_thread::dump_regs(std::string& ret) const
if (!printed_error)
{
fmt::append(ret, "0x%-8llx", reg);
if (is_decimal)
{
fmt::append(ret, "%-11d", reg);
}
else
{
fmt::append(ret, "0x%-8llx", reg);
}
}
constexpr u32 max_str_len = 32;
@@ -1153,9 +1379,63 @@ void ppu_thread::dump_regs(std::string& ret) const
}
}
fmt::append(ret, "\n");
fmt::trim_back(ret);
ret += '\n';
}
const u32 current_cia = cia;
const u32 cr_packed = cr.pack();
for (u32 addr :
{
current_cia,
current_cia + 4,
current_cia + 8,
current_cia - 4,
current_cia + 12,
})
{
dis_asm.disasm(addr);
if (dis_asm.last_opcode.size() <= 4)
{
continue;
}
if (usz index = dis_asm.last_opcode.rfind(",cr"); index < dis_asm.last_opcode.size() - 4)
{
const char result = dis_asm.last_opcode[index + 3];
if (result >= '0' && result <= '7')
{
func_data->preferred_cr_field_index = result - '0';
break;
}
}
if (usz index = dis_asm.last_opcode.rfind(" cr"); index < dis_asm.last_opcode.size() - 4)
{
const char result = dis_asm.last_opcode[index + 3];
if (result >= '0' && result <= '7')
{
func_data->preferred_cr_field_index = result - '0';
break;
}
}
if (dis_asm.last_opcode.find("stdcx.") != umax || dis_asm.last_opcode.find("stwcx.") != umax)
{
// Modifying CR0
func_data->preferred_cr_field_index = 0;
break;
}
}
const u32 displayed_cr_field = (cr_packed >> ((7 - func_data->preferred_cr_field_index) * 4)) & 0xf;
fmt::append(ret, "CR: 0x%08x, CR%d: [LT=%u GT=%u EQ=%u SO=%u]\n", cr_packed, func_data->preferred_cr_field_index, displayed_cr_field >> 3, (displayed_cr_field >> 2) & 1, (displayed_cr_field >> 1) & 1, displayed_cr_field & 1);
for (uint i = 0; i < 32; ++i)
{
const f64 r = fpr[i];
@@ -1189,8 +1469,7 @@ void ppu_thread::dump_regs(std::string& ret) const
}
}
fmt::append(ret, "CIA: 0x%x\n", cia);
fmt::append(ret, "CR: 0x%08x\n", cr.pack());
fmt::append(ret, "CIA: 0x%x\n", current_cia);
fmt::append(ret, "LR: 0x%llx\n", lr);
fmt::append(ret, "CTR: 0x%llx\n", ctr);
fmt::append(ret, "VRSAVE: 0x%08x\n", vrsave);
@@ -1407,7 +1686,7 @@ void ppu_thread::dump_all(std::string& ret) const
{
cpu_thread::dump_all(ret);
if (!call_history.data.empty())
if (call_history.data.size() > 1)
{
ret +=
"\nCalling History:"
@@ -1415,6 +1694,15 @@ void ppu_thread::dump_all(std::string& ret) const
fmt::append(ret, "%s", call_history);
}
if (syscall_history.data.size() > 1)
{
ret +=
"\nHLE/LV2 History:"
"\n================";
fmt::append(ret, "%s", syscall_history);
}
}
extern thread_local std::string(*g_tls_log_prefix)();
@@ -1479,6 +1767,14 @@ void ppu_thread::cpu_task()
cmd_pop(), fast_call(opd[0], opd[1]);
break;
}
case ppu_cmd::entry_call:
{
#ifdef __APPLE__
pthread_jit_write_protect_np(true);
#endif
cmd_pop(), fast_call(entry_func.addr, entry_func.rtoc, true);
break;
}
case ppu_cmd::hle_call:
{
cmd_pop(), ::at32(ppu_function_manager::get(), arg)(*this, {arg}, vm::_ptr<u32>(cia - 4), &ppu_ret);
@@ -1502,7 +1798,7 @@ void ppu_thread::cpu_task()
case ppu_cmd::cia_call:
{
loaded_from_savestate = true;
cmd_pop(), fast_call(std::exchange(cia, 0), gpr[2]);
cmd_pop(), fast_call(std::exchange(cia, 0), gpr[2], true);
break;
}
case ppu_cmd::initialize:
@@ -1526,7 +1822,7 @@ void ppu_thread::cpu_task()
// Wait until the progress dialog is closed.
// We don't want to open a cell dialog while a native progress dialog is still open.
thread_ctrl::wait_on<atomic_wait::op_ne>(g_progr_ptotal, 0);
g_fxo->get<progress_dialog_workaround>().skip_the_progress_dialog = true;
g_fxo->get<progress_dialog_workaround>().show_overlay_message_only = true;
// Sadly we can't postpone initializing guest time because we need to run PPU threads
// (the farther it's postponed, the less accuracy of guest time has been lost)
@@ -1609,7 +1905,7 @@ void ppu_thread::cpu_on_stop()
}
// TODO: More conditions
if (Emu.IsStopped() && g_cfg.core.spu_debug)
if (Emu.IsStopped() && g_cfg.core.ppu_debug)
{
std::string ret;
dump_all(ret);
@@ -1656,7 +1952,7 @@ void ppu_thread::exec_task()
ppu_thread::~ppu_thread()
{
perf_log.notice("Perf stats for STCX reload: successs %u, failure %u", last_succ, last_fail);
perf_log.notice("Perf stats for STCX reload: success %u, failure %u", last_succ, last_fail);
perf_log.notice("Perf stats for instructions: total %u", exec_bytes / 4);
}
@@ -1693,10 +1989,9 @@ ppu_thread::ppu_thread(const ppu_thread_params& param, std::string_view name, u3
state += cpu_flag::memory;
}
if (g_cfg.core.ppu_call_history)
{
call_history.data.resize(call_history_max_size);
}
call_history.data.resize(g_cfg.core.ppu_call_history ? call_history_max_size : 1);
syscall_history.data.resize(g_cfg.core.ppu_call_history ? syscall_history_max_size : 1);
syscall_history.count_debug_arguments = static_cast<u32>(g_cfg.core.ppu_call_history ? std::size(syscall_history.data[0].args) : 0);
#ifdef __APPLE__
pthread_jit_write_protect_np(true);
@@ -1735,21 +2030,7 @@ void ppu_thread::serialize_common(utils::serial& ar)
{
[[maybe_unused]] const s32 version = GET_OR_USE_SERIALIZATION_VERSION(ar.is_writing(), ppu);
ar(gpr, fpr, cr, fpscr.bits, lr, ctr, vrsave, cia, xer, sat, nj);
if (ar.is_writing())
{
ar(prio.load().all);
}
else if (version < 2)
{
prio.raw().all = 0;
prio.raw().prio = ar.operator s32();
}
else
{
ar(prio.raw().all);
}
ar(gpr, fpr, cr, fpscr.bits, lr, ctr, vrsave, cia, xer, sat, nj, prio.raw().all);
ar(optional_savestate_state, vr);
@@ -1773,6 +2054,10 @@ ppu_thread::ppu_thread(utils::serial& ar)
atomic_t<bool> inited = false;
};
call_history.data.resize(g_cfg.core.ppu_call_history ? call_history_max_size : 1);
syscall_history.data.resize(g_cfg.core.ppu_call_history ? syscall_history_max_size : 1);
syscall_history.count_debug_arguments = static_cast<u32>(g_cfg.core.ppu_call_history ? std::size(syscall_history.data[0].args) : 0);
serialize_common(ar);
// Restore jm_mask
@@ -1999,7 +2284,7 @@ be_t<u64>* ppu_thread::get_stack_arg(s32 i, u64 align)
return vm::_ptr<u64>(vm::cast((gpr[1] + 0x30 + 0x8 * (i - 1)) & (0 - align)));
}
void ppu_thread::fast_call(u32 addr, u64 rtoc)
void ppu_thread::fast_call(u32 addr, u64 rtoc, bool is_thread_entry)
{
const auto old_cia = cia;
const auto old_rtoc = gpr[2];
@@ -2054,12 +2339,7 @@ void ppu_thread::fast_call(u32 addr, u64 rtoc)
auto at_ret = [&]()
{
if (std::uncaught_exceptions())
{
cpu_on_stop();
current_function = old_func;
}
else if (old_cia)
if (old_cia)
{
if (state & cpu_flag::again)
{
@@ -2070,6 +2350,20 @@ void ppu_thread::fast_call(u32 addr, u64 rtoc)
gpr[2] = old_rtoc;
lr = old_lr;
}
else if (state & cpu_flag::ret && cia == g_fxo->get<ppu_function_manager>().func_addr(1, true) + 4 && is_thread_entry)
{
std::string ret;
dump_all(ret);
ppu_log.error("Returning from the thread entry function! (func=0x%x)", entry_func.addr);
ppu_log.notice("Thread context: %s", ret);
lv2_obj::sleep(*this);
// For savestates
state += cpu_flag::again;
std::memcpy(syscall_args, &gpr[3], sizeof(syscall_args));
}
current_function = old_func;
g_tls_log_prefix = old_fmt;
@@ -2249,7 +2543,7 @@ static T ppu_load_acquire_reservation(ppu_thread& ppu, u32 addr)
ppu.use_full_rdata = false;
}
if ((addr & addr_mask) == (ppu.last_faddr & addr_mask))
if (ppu_log.trace && (addr & addr_mask) == (ppu.last_faddr & addr_mask))
{
ppu_log.trace(u8"LARX after fail: addr=0x%x, faddr=0x%x, time=%u c", addr, ppu.last_faddr, (perf0.get() - ppu.last_ftsc));
}
@@ -2837,9 +3131,9 @@ namespace
{
}
fs::stat_t stat() override
fs::stat_t get_stat() override
{
return m_file.stat();
return m_file.get_stat();
}
bool trunc(u64) override
@@ -2956,10 +3250,6 @@ extern void ppu_precompile(std::vector<std::string>& dir_queue, std::vector<ppu_
const std::string firmware_sprx_path = vfs::get("/dev_flash/sys/external/");
// Map fixed address executables area, fake overlay support
const bool had_ovl = !vm::map(0x3000'0000, 0x1000'0000, 0x202).operator bool();
const u32 ppc_seg = std::exchange(g_ps3_process_info.ppc_seg, 0x3);
std::vector<std::pair<std::string, u64>> file_queue;
file_queue.reserve(2000);
@@ -3044,7 +3334,7 @@ extern void ppu_precompile(std::vector<std::string>& dir_queue, std::vector<ppu_
}
// Check .self filename
if (upper.ends_with(".SELF"))
if (upper.ends_with(".SELF") && Emu.GetBoot() != dir_queue[i] + entry.name)
{
// Get full path
file_queue.emplace_back(dir_queue[i] + entry.name, 0);
@@ -3101,7 +3391,8 @@ extern void ppu_precompile(std::vector<std::string>& dir_queue, std::vector<ppu_
atomic_t<usz> fnext = 0;
shared_mutex sprx_mtx, ovl_mtx;
lf_queue<std::string> possible_exec_file_paths;
shared_mutex ovl_mtx;
named_thread_group workers("SPRX Worker ", std::min<u32>(utils::get_thread_count(), ::size32(file_queue)), [&]
{
@@ -3153,17 +3444,11 @@ extern void ppu_precompile(std::vector<std::string>& dir_queue, std::vector<ppu_
if (ppu_prx_object obj = src; (prx_err = obj, obj == elf_error::ok))
{
std::unique_lock lock(sprx_mtx);
if (auto prx = ppu_load_prx(obj, path, offset))
if (auto prx = ppu_load_prx(obj, true, path, offset))
{
lock.unlock();
obj.clear(), src.close(); // Clear decrypted file and elf object memory
ppu_initialize(*prx);
idm::remove<lv2_obj, lv2_prx>(idm::last_id());
lock.lock();
ppu_unload_prx(*prx);
lock.unlock();
ppu_finalize(*prx);
continue;
}
@@ -3176,13 +3461,16 @@ extern void ppu_precompile(std::vector<std::string>& dir_queue, std::vector<ppu_
{
while (ovl_err == elf_error::ok)
{
// Only one thread compiles OVL atm, other can compile PRX cuncurrently
std::unique_lock lock(ovl_mtx);
auto [ovlm, error] = ppu_load_overlay(obj, path, offset);
auto [ovlm, error] = ppu_load_overlay(obj, true, path, offset);
if (error)
{
if (error == CELL_CANCEL + 0u)
{
// Emulation stopped
break;
}
// Abort
ovl_err = elf_error::header_type;
break;
@@ -3190,15 +3478,13 @@ extern void ppu_precompile(std::vector<std::string>& dir_queue, std::vector<ppu_
obj.clear(), src.close(); // Clear decrypted file and elf object memory
ppu_initialize(*ovlm);
for (auto& seg : ovlm->segs)
{
vm::dealloc(seg.addr);
// Does not really require this lock, this is done for performance reasons.
// Seems like too many created threads is hard for Windows to manage efficiently with many CPU threads.
std::lock_guard lock(ovl_mtx);
ppu_initialize(*ovlm);
}
lock.unlock();
idm::remove<lv2_obj, lv2_overlay>(idm::last_id());
ppu_finalize(*ovlm);
break;
}
@@ -3209,7 +3495,8 @@ extern void ppu_precompile(std::vector<std::string>& dir_queue, std::vector<ppu_
}
}
ppu_log.notice("Failed to precompile '%s' (prx: %s, ovl: %s)", path, prx_err, ovl_err);
ppu_log.notice("Failed to precompile '%s' (prx: %s, ovl: %s): Attempting tratment as executable file", path, prx_err, ovl_err);
possible_exec_file_paths.push(path);
continue;
}
});
@@ -3217,14 +3504,97 @@ extern void ppu_precompile(std::vector<std::string>& dir_queue, std::vector<ppu_
// Join every thread
workers.join();
// Revert changes
if (!had_ovl)
named_thread exec_worker("PPU Exec Worker", [&]
{
ensure(vm::unmap(0x3000'0000).second);
}
if (!possible_exec_file_paths)
{
return;
}
g_ps3_process_info.ppc_seg = ppc_seg;
#ifdef __APPLE__
pthread_jit_write_protect_np(false);
#endif
// Set low priority
thread_ctrl::scoped_priority low_prio(-1);
auto slice = possible_exec_file_paths.pop_all();
auto main_module = std::move(g_fxo->get<main_ppu_module>());
for (; slice; slice.pop_front(), g_progr_fdone++)
{
g_progr_ftotal++;
if (Emu.IsStopped())
{
continue;
}
const std::string path = *slice;
ppu_log.notice("Trying to load as executable: %s", path);
// Load MSELF, SPRX or SELF
fs::file src{path};
if (!src)
{
ppu_log.error("Failed to open '%s' (%s)", path, fs::g_tls_error);
continue;
}
// Some files may fail to decrypt due to the lack of klic
src = decrypt_self(std::move(src));
if (!src)
{
ppu_log.notice("Failed to decrypt '%s'", path);
continue;
}
elf_error exec_err{};
if (ppu_exec_object obj = src; (exec_err = obj, obj == elf_error::ok))
{
while (exec_err == elf_error::ok)
{
main_ppu_module& _main = g_fxo->get<main_ppu_module>();
_main = {};
if (!ppu_load_exec(obj, true, path))
{
// Abort
exec_err = elf_error::header_type;
break;
}
if (!_main.analyse(0, _main.elf_entry, _main.seg0_code_end, _main.applied_pathes, [](){ return Emu.IsStopped(); }))
{
break;
}
obj.clear(), src.close(); // Clear decrypted file and elf object memory
ppu_initialize(_main);
ppu_finalize(_main);
_main = {};
break;
}
if (exec_err == elf_error::ok)
{
continue;
}
}
ppu_log.notice("Failed to precompile '%s' as executable (%s)", path, exec_err);
continue;
}
g_fxo->get<main_ppu_module>() = std::move(main_module);
});
exec_worker();
}
extern void ppu_initialize()
@@ -3321,7 +3691,7 @@ extern void ppu_initialize()
{
const std::string eseibrd = mount_point + "/vsh/module/eseibrd.sprx";
if (auto prx = ppu_load_prx(ppu_prx_object{decrypt_self(fs::file{eseibrd})}, eseibrd, 0))
if (auto prx = ppu_load_prx(ppu_prx_object{decrypt_self(fs::file{eseibrd})}, true, eseibrd, 0))
{
// Check if cache exists for this infinitesimally small prx
dev_flash_located = ppu_initialize(*prx, true);
@@ -3335,7 +3705,7 @@ extern void ppu_initialize()
}
// Avoid compilation if main's cache exists or it is a standalone SELF with no PARAM.SFO
if (compile_main && g_cfg.core.ppu_llvm_precompilation && !Emu.GetTitleID().empty())
if (compile_main && g_cfg.core.ppu_llvm_precompilation && !Emu.GetTitleID().empty() && !Emu.IsChildProcess())
{
// Try to add all related directories
const std::set<std::string> dirs = Emu.GetGameDirs();
@@ -3367,24 +3737,20 @@ extern void ppu_initialize()
}
}
struct ppu_toc_manager
{
std::unordered_map<u32, u32> toc_map;
shared_mutex mutex;
};
bool ppu_initialize(const ppu_module& info, bool check_only)
{
if (g_cfg.core.ppu_decoder != ppu_decoder_type::llvm)
{
if (check_only)
if (check_only || vm::base(info.segs[0].addr) != info.segs[0].ptr)
{
return false;
}
// Temporarily
s_ppu_toc = &g_fxo->get<ppu_toc_manager>().toc_map;
auto& toc_manager = g_fxo->get<ppu_toc_manager>();
std::lock_guard lock(toc_manager.mutex);
auto& ppu_toc = toc_manager.toc_map;
for (const auto& func : info.funcs)
{
@@ -3395,7 +3761,7 @@ bool ppu_initialize(const ppu_module& info, bool check_only)
if (g_cfg.core.ppu_debug && func.size && func.toc != umax)
{
s_ppu_toc->emplace(func.addr, func.toc);
ppu_toc[func.addr] = func.toc;
ppu_ref(func.addr) = &ppu_check_toc;
}
}
@@ -3423,6 +3789,8 @@ bool ppu_initialize(const ppu_module& info, bool check_only)
{ "__resupdate", reinterpret_cast<u64>(vm::reservation_update) },
{ "__resinterp", reinterpret_cast<u64>(ppu_reservation_fallback) },
{ "__escape", reinterpret_cast<u64>(+ppu_escape) },
{ "__read_maybe_mmio32", reinterpret_cast<u64>(+ppu_read_mmio_aware_u32) },
{ "__write_maybe_mmio32", reinterpret_cast<u64>(+ppu_write_mmio_aware_u32) },
};
for (u64 index = 0; index < 1024; index++)
@@ -3514,6 +3882,10 @@ bool ppu_initialize(const ppu_module& info, bool check_only)
bool has_mfvscr = false;
const bool is_being_used_in_emulation = vm::base(info.segs[0].addr) == info.segs[0].ptr;
const cpu_thread* cpu = cpu_thread::get_current();
for (auto& func : info.funcs)
{
if (func.size == 0)
@@ -3528,9 +3900,11 @@ bool ppu_initialize(const ppu_module& info, bool check_only)
continue;
}
for (u32 i = addr; i < addr + size; i += 4)
auto i_ptr = ensure(info.get_ptr<u32>(addr));
for (u32 i = addr; i < addr + size; i += 4, i_ptr++)
{
if (g_ppu_itype.decode(vm::read32(i)) == ppu_itype::MFVSCR)
if (g_ppu_itype.decode(*i_ptr) == ppu_itype::MFVSCR)
{
ppu_log.warning("MFVSCR found");
has_mfvscr = true;
@@ -3553,7 +3927,7 @@ bool ppu_initialize(const ppu_module& info, bool check_only)
while (!jit_mod.init && fpos < info.funcs.size())
{
// Initialize compiler instance
if (!jit && get_current_cpu_thread())
if (!jit && is_being_used_in_emulation)
{
jit = std::make_shared<jit_compiler>(s_link_table, g_cfg.core.llvm_cpu);
}
@@ -3673,7 +4047,7 @@ bool ppu_initialize(const ppu_module& info, bool check_only)
if (roff > addr)
{
// Hash from addr to the beginning of the relocation
sha1_update(&ctx, vm::_ptr<const u8>(addr), roff - addr);
sha1_update(&ctx, ensure(info.get_ptr<const u8>(addr)), roff - addr);
}
// Hash relocation type instead
@@ -3686,9 +4060,11 @@ bool ppu_initialize(const ppu_module& info, bool check_only)
if (has_dcbz == 1)
{
for (u32 i = addr, end = block.second + block.first - 1; i <= end; i += 4)
auto i_ptr = ensure(info.get_ptr<u32>(addr));
for (u32 i = addr, end = block.second + block.first - 1; i <= end; i += 4, i_ptr++)
{
if (g_ppu_itype.decode(vm::read32(i)) == ppu_itype::DCBZ)
if (g_ppu_itype.decode(*i_ptr) == ppu_itype::DCBZ)
{
has_dcbz = 2;
break;
@@ -3697,7 +4073,7 @@ bool ppu_initialize(const ppu_module& info, bool check_only)
}
// Hash from addr to the end of the block
sha1_update(&ctx, vm::_ptr<const u8>(addr), block.second - (addr - block.first));
sha1_update(&ctx, ensure(info.get_ptr<const u8>(addr)), block.second - (addr - block.first));
}
if (reloc)
@@ -3707,9 +4083,11 @@ bool ppu_initialize(const ppu_module& info, bool check_only)
if (has_dcbz == 1)
{
for (u32 i = func.addr, end = func.addr + func.size - 1; i <= end; i += 4)
auto i_ptr = ensure(info.get_ptr<u32>(func.addr));
for (u32 i = func.addr, end = func.addr + func.size - 1; i <= end; i += 4, i_ptr++)
{
if (g_ppu_itype.decode(vm::read32(i)) == ppu_itype::DCBZ)
if (g_ppu_itype.decode(*i_ptr) == ppu_itype::DCBZ)
{
has_dcbz = 2;
break;
@@ -3717,7 +4095,7 @@ bool ppu_initialize(const ppu_module& info, bool check_only)
}
}
sha1_update(&ctx, vm::_ptr<const u8>(func.addr), func.size);
sha1_update(&ctx, ensure(info.get_ptr<const u8>(func.addr)), func.size);
}
if (false)
@@ -3885,7 +4263,7 @@ bool ppu_initialize(const ppu_module& info, bool check_only)
g_watchdog_hold_ctr--;
if (Emu.IsStopped() || !get_current_cpu_thread())
if (!is_being_used_in_emulation || (cpu ? cpu->state.all_of(cpu_flag::exit) : Emu.IsStopped()))
{
return compiled_new;
}
@@ -3898,7 +4276,7 @@ bool ppu_initialize(const ppu_module& info, bool check_only)
for (auto [obj_name, is_compiled] : link_workload)
{
if (Emu.IsStopped())
if (cpu ? cpu->state.all_of(cpu_flag::exit) : Emu.IsStopped())
{
break;
}
@@ -3913,7 +4291,7 @@ bool ppu_initialize(const ppu_module& info, bool check_only)
}
}
if (Emu.IsStopped() || !get_current_cpu_thread())
if (!is_being_used_in_emulation || (cpu ? cpu->state.all_of(cpu_flag::exit) : Emu.IsStopped()))
{
return compiled_new;
}
@@ -3938,7 +4316,7 @@ bool ppu_initialize(const ppu_module& info, bool check_only)
ppu_register_function_at(func.addr, 4, addr);
if (g_cfg.core.ppu_debug)
ppu_log.notice("Installing function %s at 0x%x: %p (reloc = 0x%x)", name, func.addr, ppu_ref(func.addr), reloc);
ppu_log.trace("Installing function %s at 0x%x: %p (reloc = 0x%x)", name, func.addr, ppu_ref(func.addr), reloc);
}
jit_mod.init = true;
@@ -3957,7 +4335,7 @@ bool ppu_initialize(const ppu_module& info, bool check_only)
ppu_register_function_at(func.addr, 4, addr);
if (g_cfg.core.ppu_debug)
ppu_log.notice("Reinstalling function at 0x%x: %p (reloc=0x%x)", func.addr, ppu_ref(func.addr), reloc);
ppu_log.trace("Reinstalling function at 0x%x: %p (reloc=0x%x)", func.addr, ppu_ref(func.addr), reloc);
}
index = 0;
+29 -2
View File
@@ -22,6 +22,7 @@ enum class ppu_cmd : u32
ptr_call, // Execute function by pointer
opd_call, // Execute function by provided rtoc and address (unlike lle_call, does not read memory)
cia_call, // Execute from current CIA, mo GPR modification applied
entry_call, // Load addr and rtoc from entry_func
initialize, // ppu_initialize()
sleep,
reset_stack, // resets stack address
@@ -124,6 +125,14 @@ struct cmd64
}
};
enum class ppu_debugger_mode : u32
{
_default,
is_decimal,
max_mode,
};
class ppu_thread : public cpu_thread
{
public:
@@ -132,7 +141,7 @@ public:
static const u32 id_count = 100;
static constexpr std::pair<u32, u32> id_invl_range = {12, 12};
virtual void dump_regs(std::string&) const override;
virtual void dump_regs(std::string&, std::any& custom_data) const override;
virtual std::string dump_callstack() const override;
virtual std::vector<std::pair<u32, u32>> dump_callstack_list() const override;
virtual std::string dump_misc() const override;
@@ -299,6 +308,7 @@ public:
u64 exec_bytes = 0; // Amount of "bytes" executed (4 for each instruction)
u32 dbg_step_pc = 0;
atomic_t<ppu_debugger_mode> debugger_mode{};
struct call_history_t
{
@@ -310,6 +320,23 @@ public:
static constexpr u32 call_history_max_size = 4096;
struct syscall_history_t
{
struct entry_t
{
u64 cia;
const char* func_name;
u64 error;
std::array<u64, 4> args;
};
std::vector<entry_t> data;
u64 index = 0;
u32 count_debug_arguments;
} syscall_history;
static constexpr u32 syscall_history_max_size = 2048;
struct hle_func_call_with_toc_info_t
{
u32 cia;
@@ -339,7 +366,7 @@ public:
be_t<u64>* get_stack_arg(s32 i, u64 align = alignof(u64));
void exec_task();
void fast_call(u32 addr, u64 rtoc);
void fast_call(u32 addr, u64 rtoc, bool is_thread_entry = false);
static std::pair<vm::addr_t, u32> stack_push(u32 size, u32 align_v);
static void stack_pop_verbose(u32 addr, u32 size) noexcept;
+177 -5
View File
@@ -5,6 +5,7 @@
#include "Emu/Cell/Common.h"
#include "PPUTranslator.h"
#include "PPUThread.h"
#include "SPUThread.h"
#include "util/types.hpp"
#include "util/endian.hpp"
@@ -12,6 +13,7 @@
#include "util/v128.hpp"
#include "util/simd.hpp"
#include <algorithm>
#include <span>
using namespace llvm;
@@ -129,6 +131,7 @@ Type* PPUTranslator::GetContextType()
}
u32 ppu_get_far_jump(u32 pc);
bool ppu_test_address_may_be_mmio(std::span<const be_t<u32>> insts);
Function* PPUTranslator::Translate(const ppu_function& info)
{
@@ -150,7 +153,7 @@ Function* PPUTranslator::Translate(const ppu_function& info)
for (u32 addr = m_addr; addr < m_addr + info.size; addr += 4)
{
const u32 op = vm::read32(vm::cast(addr + base));
const u32 op = *ensure(m_info.get_ptr<u32>(addr + base));
switch (g_ppu_itype.decode(op))
{
@@ -214,7 +217,7 @@ Function* PPUTranslator::Translate(const ppu_function& info)
const auto block = std::make_pair(info.addr, info.size);
{
// Optimize BLR (prefetch LR)
if (vm::read32(vm::cast(block.first + block.second - 4)) == ppu_instructions::BLR())
if (*ensure(m_info.get_ptr<u32>(block.first + block.second - 4)) == ppu_instructions::BLR())
{
RegLoad(m_lr);
}
@@ -239,7 +242,10 @@ Function* PPUTranslator::Translate(const ppu_function& info)
m_rel = nullptr;
}
const u32 op = vm::read32(vm::cast(m_addr + base));
// Reset MMIO hint
m_may_be_mmio = true;
const u32 op = *ensure(m_info.get_ptr<u32>(m_addr + base));
(this->*(s_ppu_decoder.decode(op)))({op});
@@ -600,15 +606,53 @@ Value* PPUTranslator::ReadMemory(Value* addr, Type* type, bool is_be, u32 align)
{
const u32 size = ::narrow<u32>(+type->getPrimitiveSizeInBits());
if (m_may_be_mmio && size == 32)
{
// Test for MMIO patterns
struct instructions_to_test
{
be_t<u32> insts[128];
};
m_may_be_mmio = false;
if (auto ptr = m_info.get_ptr<instructions_to_test>(std::max<u32>(m_info.segs[0].addr, (m_reloc ? m_reloc->addr : 0) + utils::sub_saturate<u32>(m_addr, sizeof(instructions_to_test) / 2))))
{
if (ppu_test_address_may_be_mmio(std::span(ptr->insts)))
{
m_may_be_mmio = true;
}
}
}
if (is_be ^ m_is_be && size > 8)
{
llvm::Value* value{};
// Read, byteswap, bitcast
const auto int_type = m_ir->getIntNTy(size);
const auto value = m_ir->CreateAlignedLoad(int_type, GetMemory(addr), llvm::MaybeAlign{align});
value->setVolatile(true);
if (m_may_be_mmio && size == 32)
{
ppu_log.notice("LLVM: Detected potential MMIO32 read at [0x%08x]", m_addr + (m_reloc ? m_reloc->addr : 0));
value = Call(GetType<u32>(), "__read_maybe_mmio32", m_base, addr);
}
else
{
const auto inst = m_ir->CreateAlignedLoad(int_type, GetMemory(addr), llvm::MaybeAlign{align});
inst->setVolatile(true);
value = inst;
}
return bitcast(Call(int_type, fmt::format("llvm.bswap.i%u", size), value), type);
}
if (m_may_be_mmio && size == 32)
{
ppu_log.notice("LLVM: Detected potential MMIO32 read at [0x%08x]", m_addr + (m_reloc ? m_reloc->addr : 0));
return Call(GetType<u32>(), "__read_maybe_mmio32", m_base, addr);
}
// Read normally
const auto r = m_ir->CreateAlignedLoad(type, GetMemory(addr), llvm::MaybeAlign{align});
r->setVolatile(true);
@@ -627,6 +671,25 @@ void PPUTranslator::WriteMemory(Value* addr, Value* value, bool is_be, u32 align
value = Call(int_type, fmt::format("llvm.bswap.i%u", size), bitcast(value, int_type));
}
if (m_may_be_mmio && size == 32)
{
// Test for MMIO patterns
struct instructions_to_test
{
be_t<u32> insts[128];
};
if (auto ptr = m_info.get_ptr<instructions_to_test>(std::max<u32>(m_info.segs[0].addr, (m_reloc ? m_reloc->addr : 0) + utils::sub_saturate<u32>(m_addr, sizeof(instructions_to_test) / 2))))
{
if (ppu_test_address_may_be_mmio(std::span(ptr->insts)))
{
ppu_log.notice("LLVM: Detected potential MMIO32 write at [0x%08x]", m_addr + (m_reloc ? m_reloc->addr : 0));
Call(GetType<void>(), "__write_maybe_mmio32", m_base, addr, value);
return;
}
}
}
// Write
m_ir->CreateAlignedStore(value, GetMemory(addr), llvm::MaybeAlign{align})->setVolatile(true);
}
@@ -2527,6 +2590,7 @@ void PPUTranslator::LDX(ppu_opcode_t op)
void PPUTranslator::LWZX(ppu_opcode_t op)
{
m_may_be_mmio &= (op.ra != 1u && op.ra != 13u && op.rb != 1u && op.rb != 13u); // Stack register and TLS address register are unlikely to be used in MMIO address calculation
SetGpr(op.rd, ReadMemory(op.ra ? m_ir->CreateAdd(GetGpr(op.ra), GetGpr(op.rb)) : GetGpr(op.rb), GetType<u32>()));
}
@@ -2601,6 +2665,8 @@ void PPUTranslator::DCBST(ppu_opcode_t)
void PPUTranslator::LWZUX(ppu_opcode_t op)
{
m_may_be_mmio &= (op.ra != 1u && op.ra != 13u && op.rb != 1u && op.rb != 13u); // Stack register and TLS address register are unlikely to be used in MMIO address calculation
const auto addr = m_ir->CreateAdd(GetGpr(op.ra), GetGpr(op.rb));
SetGpr(op.rd, ReadMemory(addr, GetType<u32>()));
SetGpr(op.ra, addr);
@@ -2811,6 +2877,7 @@ void PPUTranslator::STWCX(ppu_opcode_t op)
void PPUTranslator::STWX(ppu_opcode_t op)
{
m_may_be_mmio &= (op.ra != 1u && op.ra != 13u && op.rb != 1u && op.rb != 13u); // Stack register and TLS address register are unlikely to be used in MMIO address calculation
WriteMemory(op.ra ? m_ir->CreateAdd(GetGpr(op.ra), GetGpr(op.rb)) : GetGpr(op.rb), GetGpr(op.rs, 32));
}
@@ -2830,6 +2897,7 @@ void PPUTranslator::STDUX(ppu_opcode_t op)
void PPUTranslator::STWUX(ppu_opcode_t op)
{
const auto addr = m_ir->CreateAdd(GetGpr(op.ra), GetGpr(op.rb));
m_may_be_mmio &= (op.ra != 1u && op.ra != 13u && op.rb != 1u && op.rb != 13u); // Stack register and TLS address register are unlikely to be used in MMIO address calculation
WriteMemory(addr, GetGpr(op.rs, 32));
SetGpr(op.ra, addr);
}
@@ -3213,6 +3281,7 @@ void PPUTranslator::LWBRX(ppu_opcode_t op)
void PPUTranslator::LFSX(ppu_opcode_t op)
{
m_may_be_mmio &= (op.ra != 1u && op.ra != 13u && op.rb != 1u && op.rb != 13u); // Stack register and TLS address register are unlikely to be used in MMIO address calculation
SetFpr(op.frd, ReadMemory(op.ra ? m_ir->CreateAdd(GetGpr(op.ra), GetGpr(op.rb)) : GetGpr(op.rb), GetType<f32>()));
}
@@ -3541,6 +3610,44 @@ void PPUTranslator::LWZ(ppu_opcode_t op)
m_rel = nullptr;
}
m_may_be_mmio &= (op.ra != 1u && op.ra != 13u); // Stack register and TLS address register are unlikely to be used in MMIO address calculation
m_may_be_mmio &= op.simm16 == 0 || spu_thread::test_is_problem_state_register_offset(op.uimm16, true, false); // Either exact MMIO address or MMIO base with completing s16 address offset
if (m_may_be_mmio && !op.simm16)
{
struct instructions_data
{
be_t<u32> insts[2];
};
// Quick invalidation: expect exact MMIO address, so if the register is being reused with different offset than it's likely not MMIO
if (auto ptr = m_info.get_ptr<instructions_data>(m_addr + 4 + (m_reloc ? m_reloc->addr : 0)))
{
for (u32 inst : ptr->insts)
{
ppu_opcode_t test_op{inst};
if (test_op.simm16 == op.simm16 || test_op.ra != op.ra)
{
// Same offset (at least according to this test) or different register
continue;
}
switch (g_ppu_itype.decode(inst))
{
case ppu_itype::LWZ:
case ppu_itype::STW:
{
// Not MMIO
m_may_be_mmio = false;
break;
}
default: break;
}
}
}
}
SetGpr(op.rd, ReadMemory(op.ra ? m_ir->CreateAdd(GetGpr(op.ra), imm) : imm, GetType<u32>()));
}
@@ -3554,6 +3661,9 @@ void PPUTranslator::LWZU(ppu_opcode_t op)
m_rel = nullptr;
}
m_may_be_mmio &= (op.ra != 1u && op.ra != 13u); // Stack register and TLS address register are unlikely to be used in MMIO address calculation
m_may_be_mmio &= op.simm16 == 0 || spu_thread::test_is_problem_state_register_offset(op.uimm16, true, false); // Either exact MMIO address or MMIO base with completing s16 address offset
const auto addr = m_ir->CreateAdd(GetGpr(op.ra), imm);
SetGpr(op.rd, ReadMemory(addr, GetType<u32>()));
SetGpr(op.ra, addr);
@@ -3597,6 +3707,44 @@ void PPUTranslator::STW(ppu_opcode_t op)
m_rel = nullptr;
}
m_may_be_mmio &= (op.ra != 1u && op.ra != 13u); // Stack register and TLS address register are unlikely to be used in MMIO address calculation
m_may_be_mmio &= op.simm16 == 0 || spu_thread::test_is_problem_state_register_offset(op.uimm16, false, true); // Either exact MMIO address or MMIO base with completing s16 address offset
if (m_may_be_mmio && !op.simm16)
{
struct instructions_data
{
be_t<u32> insts[3];
};
// Quick invalidation: expect exact MMIO address, so if the register is being reused with different offset than it's likely not MMIO
if (auto ptr = m_info.get_ptr<instructions_data>(m_addr + 4 + (m_reloc ? m_reloc->addr : 0)))
{
for (u32 inst : ptr->insts)
{
ppu_opcode_t test_op{inst};
if (test_op.simm16 == op.simm16 || test_op.ra != op.ra)
{
// Same offset (at least according to this test) or different register
continue;
}
switch (g_ppu_itype.decode(inst))
{
case ppu_itype::LWZ:
case ppu_itype::STW:
{
// Not MMIO
m_may_be_mmio = false;
break;
}
default: break;
}
}
}
}
const auto value = GetGpr(op.rs, 32);
const auto addr = op.ra ? m_ir->CreateAdd(GetGpr(op.ra), imm) : imm;
WriteMemory(addr, value);
@@ -3621,6 +3769,9 @@ void PPUTranslator::STWU(ppu_opcode_t op)
m_rel = nullptr;
}
m_may_be_mmio &= (op.ra != 1u && op.ra != 13u);// Stack register and TLS address register are unlikely to be used in MMIO address calculatio
m_may_be_mmio &= op.simm16 == 0 || spu_thread::test_is_problem_state_register_offset(op.uimm16, false, true); // Either exact MMIO address or MMIO base with completing s16 address offset
const auto addr = m_ir->CreateAdd(GetGpr(op.ra), imm);
WriteMemory(addr, GetGpr(op.rs, 32));
SetGpr(op.ra, addr);
@@ -3740,6 +3891,8 @@ void PPUTranslator::STHU(ppu_opcode_t op)
void PPUTranslator::LMW(ppu_opcode_t op)
{
m_may_be_mmio &= op.rd == 31u && (op.ra != 1u && op.ra != 13u); // Stack register and TLS address register are unlikely to be used in MMIO address calculatio
for (u32 i = 0; i < 32 - op.rd; i++)
{
SetGpr(i + op.rd, ReadMemory(op.ra ? m_ir->CreateAdd(m_ir->getInt64(op.simm16 + i * 4), GetGpr(op.ra)) : m_ir->getInt64(op.simm16 + i * 4), GetType<u32>()));
@@ -3748,6 +3901,8 @@ void PPUTranslator::LMW(ppu_opcode_t op)
void PPUTranslator::STMW(ppu_opcode_t op)
{
m_may_be_mmio &= op.rs == 31u && (op.ra != 1u && op.ra != 13u); // Stack register and TLS address register are unlikely to be used in MMIO address calculatio
for (u32 i = 0; i < 32 - op.rs; i++)
{
WriteMemory(op.ra ? m_ir->CreateAdd(m_ir->getInt64(op.simm16 + i * 4), GetGpr(op.ra)) : m_ir->getInt64(op.simm16 + i * 4), GetGpr(i + op.rs, 32));
@@ -3764,6 +3919,9 @@ void PPUTranslator::LFS(ppu_opcode_t op)
m_rel = nullptr;
}
m_may_be_mmio &= (op.ra != 1u && op.ra != 13u); // Stack register and TLS address register are unlikely to be used in MMIO address calculatio
m_may_be_mmio &= op.simm16 == 0 || spu_thread::test_is_problem_state_register_offset(op.uimm16, true, false); // Either exact MMIO address or MMIO base with completing s16 address offset
SetFpr(op.frd, ReadMemory(op.ra ? m_ir->CreateAdd(GetGpr(op.ra), imm) : imm, GetType<f32>()));
}
@@ -3777,6 +3935,9 @@ void PPUTranslator::LFSU(ppu_opcode_t op)
m_rel = nullptr;
}
m_may_be_mmio &= (op.ra != 1u && op.ra != 13u); // Stack register and TLS address register are unlikely to be used in MMIO address calculatio
m_may_be_mmio &= op.simm16 == 0 || spu_thread::test_is_problem_state_register_offset(op.uimm16, true, false); // Either exact MMIO address or MMIO base with completing s16 address offset
const auto addr = m_ir->CreateAdd(GetGpr(op.ra), imm);
SetFpr(op.frd, ReadMemory(addr, GetType<f32>()));
SetGpr(op.ra, addr);
@@ -3819,7 +3980,12 @@ void PPUTranslator::STFS(ppu_opcode_t op)
imm = SExt(ReadMemory(GetAddr(+2), GetType<u16>()), GetType<u64>());
m_rel = nullptr;
}
else
{
m_may_be_mmio &= op.simm16 == 0 || spu_thread::test_is_problem_state_register_offset(op.uimm16, false, true); // Either exact MMIO address or MMIO base with completing s16 address offset
}
m_may_be_mmio &= (op.ra != 1u && op.ra != 13u); // Stack register and TLS address register are unlikely to be used in MMIO address calculation
WriteMemory(op.ra ? m_ir->CreateAdd(GetGpr(op.ra), imm) : imm, GetFpr(op.frs, 32));
}
@@ -3832,6 +3998,12 @@ void PPUTranslator::STFSU(ppu_opcode_t op)
imm = SExt(ReadMemory(GetAddr(+2), GetType<u16>()), GetType<u64>());
m_rel = nullptr;
}
else
{
m_may_be_mmio &= op.simm16 == 0 || spu_thread::test_is_problem_state_register_offset(op.uimm16, false, true); // Either exact MMIO address or MMIO base with completing s16 address offset
}
m_may_be_mmio &= (op.ra != 1u && op.ra != 13u); // Stack register and TLS address register are unlikely to be used in MMIO address calculation
const auto addr = m_ir->CreateAdd(GetGpr(op.ra), imm);
WriteMemory(addr, GetFpr(op.frs, 32));
+1
View File
@@ -68,6 +68,7 @@ class PPUTranslator final : public cpu_translator
llvm::Value** const m_fc = m_locals + 131; // FPSCR bits (used partially)
llvm::Value* nan_vec4;
bool m_may_be_mmio = false;
#define DEF_VALUE(loc, glb, pos)\
llvm::Value*& loc = m_locals[pos];\
+44
View File
@@ -318,6 +318,50 @@ bool spu_thread::write_reg(const u32 addr, const u32 value)
return false;
}
bool spu_thread::test_is_problem_state_register_offset(u32 offset, bool for_read, bool for_write) noexcept
{
if (for_read)
{
switch (offset)
{
case MFC_CMDStatus_offs:
case MFC_QStatus_offs:
case SPU_Out_MBox_offs:
case SPU_MBox_Status_offs:
case SPU_Status_offs:
case Prxy_TagStatus_offs:
case SPU_NPC_offs:
case SPU_RunCntl_offs:
return true;
default: break;
}
}
if (for_write)
{
switch (offset)
{
case MFC_LSA_offs:
case MFC_EAH_offs:
case MFC_EAL_offs:
case MFC_Size_Tag_offs:
case MFC_Class_CMD_offs:
case Prxy_QueryType_offs:
case Prxy_QueryMask_offs:
case SPU_In_MBox_offs:
case SPU_RunCntl_offs:
case SPU_NPC_offs:
case SPU_RdSigNotify1_offs:
case SPU_RdSigNotify2_offs:
case (SPU_RdSigNotify2_offs & 0xffff): // Fow now accept both (this is used for an optimization so it can be imperfect)
return true;
default: break;
}
}
return false;
}
void spu_load_exec(const spu_exec_object& elf)
{
spu_thread::g_raw_spu_ctr++;
+48 -17
View File
@@ -1551,7 +1551,8 @@ spu_function_t spu_runtime::rebuild_ubertrampoline(u32 id_inst)
spu_function_t spu_runtime::find(const u32* ls, u32 addr) const
{
for (auto& item : ::at32(m_stuff, ls[addr / 4] >> 12))
const u32 index = ls[addr / 4] >> 12;
for (const auto& item : ::at32(m_stuff, index))
{
if (const auto ptr = item.compiled.load())
{
@@ -3846,16 +3847,24 @@ void spu_recompiler_base::dump(const spu_program& result, std::string& out)
fmt::append(hash, "%s", fmt::base57(output));
}
fmt::append(out, "========== SPU BLOCK 0x%05x (size %u, %s) ==========\n", result.entry_point, result.data.size(), hash);
fmt::append(out, "========== SPU BLOCK 0x%05x (size %u, %s) ==========\n\n", result.entry_point, result.data.size(), hash);
for (auto& bb : m_bbs)
{
for (u32 pos = bb.first, end = bb.first + bb.second.size * 4; pos < end; pos += 4)
{
dis_asm.disasm(pos);
fmt::append(out, ">%s\n", dis_asm.last_opcode);
if (!dis_asm.last_opcode.ends_with('\n'))
{
dis_asm.last_opcode += '\n';
}
fmt::append(out, ">%s", dis_asm.last_opcode);
}
out += '\n';
if (m_block_info[bb.first / 4])
{
fmt::append(out, "A: [0x%05x] %s\n", bb.first, m_entry_info[bb.first / 4] ? (m_ret_info[bb.first / 4] ? "Chunk" : "Entry") : "Block");
@@ -5822,7 +5831,7 @@ public:
if (g_cfg.core.spu_debug)
{
out.flush();
fs::file(m_spurt->get_cache_path() + "spu-ir.log", fs::write + fs::append).write(log);
fs::write_file(m_spurt->get_cache_path() + "spu-ir.log", fs::create + fs::write + fs::append, log);
}
#if defined(__APPLE__)
@@ -6240,7 +6249,7 @@ public:
if (g_cfg.core.spu_debug)
{
fs::file(m_spurt->get_cache_path() + "spu-ir.log", fs::write + fs::append).write(log);
fs::write_file(m_spurt->get_cache_path() + "spu-ir.log", fs::create + fs::write + fs::append, log);
}
fmt::throw_exception("Compilation failed");
@@ -6275,7 +6284,7 @@ public:
if (g_cfg.core.spu_debug)
{
out.flush();
fs::file(m_spurt->get_cache_path() + "spu-ir.log", fs::write + fs::append).write(log);
fs::write_file(m_spurt->get_cache_path() + "spu-ir.log", fs::create + fs::write + fs::append, log);
}
return spu_runtime::g_interpreter;
@@ -6811,7 +6820,7 @@ public:
}
case MFC_Size:
{
set_reg_fixed(s_reg_mfc_size, trunc<u16>(val & 0x7fff).eval(m_ir));
set_reg_fixed(s_reg_mfc_size, trunc<u16>(val).eval(m_ir));
return;
}
case MFC_TagID:
@@ -7779,19 +7788,27 @@ public:
void ROTQMBY(spu_opcode_t op)
{
const auto a = get_vr<u8[16]>(op.ra);
const auto b = get_vr<u8[16]>(op.rb);
const auto b = get_vr<u32[4]>(op.rb);
auto minusb = eval(-b);
if (auto [ok, x] = match_expr(b, -match<u32[4]>()); ok)
{
minusb = eval(x);
}
const auto minusbx = bitcast<u8[16]>(minusb);
// Data with swapped endian from a load instruction
if (auto [ok, as] = match_expr(a, byteswap(match<u8[16]>())); ok)
{
const auto sc = build<u8[16]>(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0);
const auto sh = sc - (-splat_scalar(b) & 0x1f);
const auto sh = sc - (splat_scalar(minusbx) & 0x1f);
set_vr(op.rt, pshufb(as, sh));
return;
}
const auto sc = build<u8[16]>(112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127);
const auto sh = sc + (-splat_scalar(b) & 0x1f);
const auto sh = sc + (splat_scalar(minusbx) & 0x1f);
set_vr(op.rt, pshufb(a, sh));
}
@@ -8571,8 +8588,13 @@ public:
return;
}
// (TODO: implement via known-bits-lookup) Check whether shuffle mask doesn't contain fixed value selectors
const auto [perm_only, dummy1] = match_expr(c, match<u8[16]>() & 31);
// Check whether shuffle mask doesn't contain fixed value selectors
bool perm_only = false;
if (auto k = get_known_bits(c); !!(k.Zero & 0x80))
{
perm_only = true;
}
const auto a = get_vr<u8[16]>(op.ra);
const auto b = get_vr<u8[16]>(op.rb);
@@ -8598,7 +8620,7 @@ public:
return;
}
const auto x = avg(noncast<u8[16]>(sext<s8[16]>((c & 0xc0) == 0xc0)), noncast<u8[16]>(sext<s8[16]>((c & 0xe0) == 0xc0)));
const auto x = pshufb(build<u8[16]>(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x80, 0x80), (c >> 4));
const auto ax = pshufb(as, c);
const auto bx = pshufb(bs, c);
@@ -8614,7 +8636,7 @@ public:
if (data == v128::from8p(data._u8[0]))
{
// See above
const auto x = avg(noncast<u8[16]>(sext<s8[16]>((c & 0xc0) == 0xc0)), noncast<u8[16]>(sext<s8[16]>((c & 0xe0) == 0xc0)));
const auto x = pshufb(build<u8[16]>(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x80, 0x80), (c >> 4));
const auto ax = pshufb(as, c);
if (perm_only)
@@ -8633,7 +8655,7 @@ public:
if (data == v128::from8p(data._u8[0]))
{
// See above
const auto x = avg(noncast<u8[16]>(sext<s8[16]>((c & 0xc0) == 0xc0)), noncast<u8[16]>(sext<s8[16]>((c & 0xe0) == 0xc0)));
const auto x = pshufb(build<u8[16]>(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x80, 0x80), (c >> 4));
const auto bx = pshufb(bs, c);
if (perm_only)
@@ -8661,7 +8683,7 @@ public:
return;
}
const auto x = avg(noncast<u8[16]>(sext<s8[16]>((c & 0xc0) == 0xc0)), noncast<u8[16]>(sext<s8[16]>((c & 0xe0) == 0xc0)));
const auto x = pshufb(build<u8[16]>(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x80, 0x80), (c >> 4));
const auto cr = eval(c ^ 0xf);
const auto ax = pshufb(a, cr);
const auto bx = pshufb(b, cr);
@@ -9849,6 +9871,15 @@ public:
a = eval(a * s);
value_t<s32[4]> r;
if (m_use_avx512)
{
const auto sc = clamp_smax(a);
r.value = m_ir->CreateFPToUI(sc.value, get_type<s32[4]>());
set_vr(op.rt, r);
return;
}
r.value = m_ir->CreateFPToUI(a.value, get_type<s32[4]>());
set_vr(op.rt, select(bitcast<s32[4]>(a) > splat<s32[4]>(((32 + 127) << 23) - 1), splat<s32[4]>(-1), r & ~(bitcast<s32[4]>(a) >> 31)));
}
@@ -11237,7 +11268,7 @@ struct spu_fast : public spu_recompiler_base
{
std::string log;
this->dump(func, log);
fs::file(m_spurt->get_cache_path() + "spu.log", fs::write + fs::append).write(log);
fs::write_file(m_spurt->get_cache_path() + "spu.log", fs::create + fs::write + fs::append, log);
}
// Allocate executable area with necessary size
+79 -41
View File
@@ -326,6 +326,29 @@ extern thread_local u64 g_tls_fault_spu;
const spu_decoder<spu_itype> s_spu_itype;
namespace vm
{
extern atomic_t<u64, 64> g_range_lock_set[64];
// Defined here for performance reasons
writer_lock::~writer_lock() noexcept
{
if (range_lock)
{
if (!*range_lock)
{
return;
}
g_range_lock_bits[1] &= ~(1ull << (range_lock - g_range_lock_set));
range_lock->release(0);
return;
}
g_range_lock_bits[1].release(0);
}
}
namespace spu
{
namespace scheduler
@@ -1017,9 +1040,14 @@ spu_imm_table_t::spu_imm_table_t()
}
}
void spu_thread::dump_regs(std::string& ret) const
void spu_thread::dump_regs(std::string& ret, std::any& /*custom_data*/) const
{
const bool floats_only = debugger_float_mode.load();
const system_state emu_state = Emu.GetStatus(false);
const bool is_stopped_or_frozen = state & cpu_flag::exit || emu_state == system_state::frozen || emu_state <= system_state::stopping;
const spu_debugger_mode mode = debugger_mode.load();
const bool floats_only = !is_stopped_or_frozen && mode == spu_debugger_mode::is_float;
const bool is_decimal = !is_stopped_or_frozen && mode == spu_debugger_mode::is_decimal;
SPUDisAsm dis_asm(cpu_disasm_mode::normal, ls);
@@ -1097,12 +1125,26 @@ void spu_thread::dump_regs(std::string& ret) const
if (!printed_error)
{
// Shortand formatting
fmt::append(ret, "%08x", i3);
if (is_decimal)
{
fmt::append(ret, "%-11d", i3);
}
else
{
fmt::append(ret, "%08x", i3);
}
}
}
else
{
fmt::append(ret, "%08x %08x %08x %08x", r.u32r[0], r.u32r[1], r.u32r[2], r.u32r[3]);
if (is_decimal)
{
fmt::append(ret, "%-11d %-11d %-11d %-11d", r.u32r[0], r.u32r[1], r.u32r[2], r.u32r[3]);
}
else
{
fmt::append(ret, "%08x %08x %08x %08x", r.u32r[0], r.u32r[1], r.u32r[2], r.u32r[3]);
}
}
if (i3 >= 0x80 && is_exec_code(i3, ls))
@@ -1143,6 +1185,17 @@ void spu_thread::dump_regs(std::string& ret) const
fmt::append(ret, "SNR1: %s\n", ch_snr1);
fmt::append(ret, "SNR2: %s\n", ch_snr2);
if (get_type() != spu_type::threaded)
{
for (usz i = 0; i < int_ctrl.size(); i++)
{
fmt::append(ret, "Int Ctrl[%u]: stat=0x%x, mask=0x%x\n", i, +int_ctrl[i].stat, +int_ctrl[i].mask);
}
fmt::append(ret, "MFC Prxy Cmd: [%s written: %x]\n", mfc_prxy_cmd, mfc_prxy_write_state.all);
fmt::append(ret, "MFC Prxy Mask: 0x%x\n", +mfc_prxy_mask);
}
const u32 addr = raddr;
fmt::append(ret, "Reservation Addr: %s\n", addr ? fmt::format("0x%x", addr) : "N/A");
@@ -1200,26 +1253,7 @@ std::vector<std::pair<u32, u32>> spu_thread::dump_callstack_list() const
return !addr || !is_exec_code(addr, ls);
};
if (is_invalid(lr))
{
if (first)
{
// Function hasn't saved LR, could be because it's a leaf function
// Use LR directly instead
lr = gpr0;
if (is_invalid(lr))
{
// Skip it, workaround
continue;
}
}
else
{
break;
}
}
else if (first && lr._u32[3] != gpr0._u32[3] && !is_invalid(gpr0))
if (first && lr._u32[3] != gpr0._u32[3] && !is_invalid(gpr0))
{
// Detect functions with no stack or before LR has been stored
std::vector<bool> passed(SPU_LS_SIZE / 4);
@@ -1308,8 +1342,15 @@ std::vector<std::pair<u32, u32>> spu_thread::dump_callstack_list() const
}
}
// TODO: function addresses too
call_stack_list.emplace_back(lr._u32[3], sp);
if (!is_invalid(lr))
{
// TODO: function addresses too
call_stack_list.emplace_back(lr._u32[3], sp);
}
else if (!first)
{
break;
}
const u32 temp_sp = _ref<u32>(sp);
@@ -1767,11 +1808,8 @@ void spu_thread::cleanup()
// Free range lock (and signals cleanup was called to the destructor)
vm::free_range_lock(range_lock);
// Signal the debugger about the termination
if (!state.test_and_set(cpu_flag::exit))
{
state.notify_one();
}
// Terminate and join thread
static_cast<named_thread<spu_thread>&>(*this) = thread_state::finished;
}
spu_thread::~spu_thread()
@@ -1783,7 +1821,7 @@ spu_thread::~spu_thread()
utils::memory_release(ls - SPU_LS_SIZE * 2, SPU_LS_SIZE * 5);
perf_log.notice("Perf stats for transactions: success %u, failure %u", stx, ftx);
perf_log.notice("Perf stats for PUTLLC reload: successs %u, failure %u", last_succ, last_fail);
perf_log.notice("Perf stats for PUTLLC reload: success %u, failure %u", last_succ, last_fail);
}
u8* spu_thread::map_ls(utils::shm& shm, void* ptr)
@@ -3533,19 +3571,18 @@ bool spu_thread::do_putllc(const spu_mfc_cmd& args)
{
// Full lock (heavyweight)
// TODO: vm::check_addr
vm::writer_lock lock(addr);
vm::writer_lock lock(addr, range_lock);
if (cmp_rdata(rdata, super_data))
{
mov_rdata(super_data, to_write);
res += 64;
return true;
}
res -= 64;
return false;
}();
res += success ? 64 : 0 - 64;
return success;
}())
{
@@ -3680,7 +3717,8 @@ void do_cell_atomic_128_store(u32 addr, const void* to_write)
vm::_ref<atomic_t<u32>>(addr) += 0;
// Hard lock
vm::writer_lock lock(addr);
auto spu = cpu ? cpu->try_get<spu_thread>() : nullptr;
vm::writer_lock lock(addr, spu ? spu->range_lock : nullptr);
mov_rdata(sdata, *static_cast<const spu_rdata_t*>(to_write));
vm::reservation_acquire(addr) += 32;
}
@@ -4446,7 +4484,7 @@ bool spu_thread::reservation_check(u32 addr, const decltype(rdata)& data) const
// Set range_lock first optimistically
range_lock->store(u64{128} << 32 | addr);
u64 lock_val = vm::g_range_lock;
u64 lock_val = *std::prev(std::end(vm::g_range_lock_set));
u64 old_lock = 0;
while (lock_val != old_lock)
@@ -4501,7 +4539,7 @@ bool spu_thread::reservation_check(u32 addr, const decltype(rdata)& data) const
break;
}
old_lock = std::exchange(lock_val, vm::g_range_lock);
old_lock = std::exchange(lock_val, *std::prev(std::end(vm::g_range_lock_set)));
}
if (!range_lock->load()) [[unlikely]]
@@ -4604,9 +4642,9 @@ void spu_thread::set_interrupt_status(bool enable)
// Detect enabling interrupts with events masked
if (auto mask = ch_events.load().mask; mask & SPU_EVENT_INTR_BUSY_CHECK)
{
if (g_cfg.core.spu_decoder != spu_decoder_type::_static)
if (g_cfg.core.spu_decoder != spu_decoder_type::_static && g_cfg.core.spu_decoder != spu_decoder_type::dynamic)
{
fmt::throw_exception("SPU Interrupts not implemented (mask=0x%x): Use static interpreter", mask);
fmt::throw_exception("SPU Interrupts not implemented (mask=0x%x): Use [%s] SPU decoder", mask, spu_decoder_type::dynamic);
}
spu_log.trace("SPU Interrupts (mask=0x%x) are using CPU busy checking mode", mask);
@@ -5282,7 +5320,7 @@ bool spu_thread::set_ch_value(u32 ch, u32 value)
case MFC_Size:
{
ch_mfc_cmd.size = value & 0x7fff;
ch_mfc_cmd.size = static_cast<u16>(std::min<u32>(value, 0xffff));
return true;
}
+13 -3
View File
@@ -608,10 +608,19 @@ struct spu_memory_segment_dump_data
u32 flags = umax;
};
enum class spu_debugger_mode : u32
{
_default,
is_float,
is_decimal,
max_mode,
};
class spu_thread : public cpu_thread
{
public:
virtual void dump_regs(std::string&) const override;
virtual void dump_regs(std::string&, std::any& custom_data) const override;
virtual std::string dump_callstack() const override;
virtual std::vector<std::pair<u32, u32>> dump_callstack_list() const override;
virtual std::string dump_misc() const override;
@@ -782,7 +791,7 @@ public:
std::vector<mfc_cmd_dump> mfc_history;
u64 mfc_dump_idx = 0;
static constexpr u32 max_mfc_dump_idx = 2048;
static constexpr u32 max_mfc_dump_idx = 4096;
bool in_cpu_work = false;
bool allow_interrupts_in_cpu_work = false;
@@ -794,7 +803,7 @@ public:
u64 start_time{}; // Starting time of STOP or RDCH bloking function
bool unsavable = false; // Flag indicating whether saving the spu thread state is currently unsafe
atomic_t<u8> debugger_float_mode = 0;
atomic_t<spu_debugger_mode> debugger_mode{};
// PC-based breakpoint list
std::array<atomic_t<bool>, SPU_LS_SIZE / 4> local_breakpoints{};
@@ -865,6 +874,7 @@ public:
bool read_reg(const u32 addr, u32& value);
bool write_reg(const u32 addr, const u32 value);
static bool test_is_problem_state_register_offset(u32 offset, bool for_read, bool for_write) noexcept;
static atomic_t<u32> g_raw_spu_ctr;
static atomic_t<u32> g_raw_spu_id[5];
+20 -2
View File
@@ -84,6 +84,12 @@ void fmt_class_string<lv2_protocol>::format(std::string& out, u64 arg)
});
}
template <>
void fmt_class_string<lv2_obj::name_64>::format(std::string& out, u64 arg)
{
out += lv2_obj::name64(get_object(arg).data);
}
static void null_func_(ppu_thread& ppu, ppu_opcode_t, be_t<u32>* this_op, ppu_intrp_func*)
{
ppu_log.todo("Unimplemented syscall %s -> CELL_OK (r3=0x%llx, r4=0x%llx, r5=0x%llx, r6=0x%llx, r7=0x%llx, r8=0x%llx, r9=0x%llx, r10=0x%llx)", ppu_syscall_code(ppu.gpr[11]),
@@ -576,7 +582,7 @@ const std::array<std::pair<ppu_intrp_func_t, std::string_view>, 1024> g_ppu_sysc
null_func,//BIND_SYSC(sys_usbd_...), //555 (0x22B)
BIND_SYSC(sys_usbd_get_device_speed), //556 (0x22C)
null_func,//BIND_SYSC(sys_usbd_...), //557 (0x22D)
null_func,//BIND_SYSC(sys_usbd_...), //558 (0x22E)
BIND_SYSC(sys_usbd_unregister_extra_ldd), //558 (0x22E)
BIND_SYSC(sys_usbd_register_extra_ldd), //559 (0x22F)
null_func,//BIND_SYSC(sys_...), //560 (0x230) ROOT
null_func,//BIND_SYSC(sys_...), //561 (0x231) ROOT
@@ -1123,7 +1129,7 @@ public:
if (!m_stats.empty())
{
ppu_log.notice("PPU Syscall Usage Stats: %s", m_stats);
ppu_log.notice("PPU Syscall Usage Stats:%s", m_stats);
}
}
@@ -1231,6 +1237,18 @@ namespace cpu_counter
void remove(cpu_thread*) noexcept;
}
std::string lv2_obj::name64(u64 name_u64)
{
const auto ptr = reinterpret_cast<const char*>(&name_u64);
// NTS string, ignore invalid/newline characters
// Example: "lv2\n\0tx" will be printed as "lv2"
std::string str{ptr, std::find(ptr, ptr + 7, '\0')};
str.erase(std::remove_if(str.begin(), str.end(), [](uchar c){ return !std::isprint(c); }), str.end());
return str;
}
bool lv2_obj::sleep(cpu_thread& cpu, const u64 timeout)
{
// Should already be performed when using this flag

Some files were not shown because too many files have changed in this diff Show More