Compare commits

...

687 Commits

Author SHA1 Message Date
Ani 8e4451d1ab rpcs3_version: Bump to 0.0.15 (#9866) 2021-02-28 23:32:23 +00:00
Megamouse 0b5c6350ae cellScreenshot: fix overlay scaling (#9867)
* cellScreenshot: fix overlay scaling
2021-02-28 23:00:49 +00:00
Eladash 48cd56acc2 Report deadlocked thread names in failures to stop emulation (#9865)
* Report deadlocked thread names in failures to stop emulation

Co-authored-by: Nekotekina <nekotekina@gmail.com>
2021-03-01 01:06:48 +03:00
Nekotekina 71e16bfac3 shared_ptr.hpp: minor fixup 2021-03-01 00:28:28 +03:00
Nekotekina b7c579adf9 Tentative fix for -Wattributes
These warnings enabled conditionally for GCC 10.1+.
2021-03-01 00:22:32 +03:00
Eladash 461fa6a88a Firmware installation bugfixes (#9855)
* Fix race condition in PUP installation abortion.
* Fix freezes of emulator in case the PUP installation failed due to filesystem errors.
* Use fs::create_path as opposed to fs::create_dir as it is can create upper directories in case they are missing and is better in error handling.
* Report TAR errors on failure to create directories.
* Fix pup_object constructor to not crash on invalid PUP file header. (report an error)
* Fix pup_object::validate_hashes to not crash on invalid PUP file entries. (report an error)
* Do not call Qt functions inside a named_thread because it is wrong.
2021-02-28 22:59:27 +03:00
Florin9doi dfee46604a Buzz settings 2021-02-28 22:36:47 +03:00
Megamouse a7c9827ad4 Improve cellScreenshot (#9851)
* Fix screenshot logging

* Update libpng to 1.6.37

* cellScreenshot: Write text chunks
* cellScreenshot: add overlay image
* screenshot_manager: add /dev_hdd0/photo/

* read_png_file: use deleter instead of manual close

* cellScreenshot: use Qt for overlays
* cellScreenshot: don't apply overlay to regular img
* screenshot_manager: add mount hack for VFS
* cellScreenshot: escape the whole path
2021-02-28 22:05:04 +03:00
Nekotekina f580bee32c Rewrite cellNetCtlNetStartDialogLoadAsync hack 2021-02-28 20:20:17 +03:00
Nekotekina de9d859f4a named_thread: implement task queue
atomic_ptr: implement push_head()

thread_ctrl::state() triggers task queue execution.
2021-02-28 20:20:17 +03:00
Nekotekina 3aaa0172d5 named_thread: implement "default" event loop
Fixup "sleepy" thread at startup on Windows.
Permit threads which lack operator()() overload.
2021-02-28 20:16:13 +03:00
Nekotekina 29e7eda887 named_thread: rewrite result_storage
Use SFINAE as permitted by std::invoke_result_t<>
2021-02-28 20:16:13 +03:00
Megamouse 7cb32a3680 Qt: set parent for QThread
This may or may not have caused a leak
2021-02-28 18:48:34 +03:00
Megamouse a4d4ab1df9 remove unused variable 2021-02-28 18:48:34 +03:00
kd-11 4bef176e9b vk: Fix inadvertent self-assign 2021-02-28 18:00:20 +03:00
kd-11 d2de8a87bf vk: Explicit initialization of command pool queue family 2021-02-26 15:08:14 +03:00
kd-11 12cad7c393 vk: Add per-queue-family scratch resources and double buffer them 2021-02-26 15:08:14 +03:00
kd-11 be1238cc95 vk: Add support for queue family migration and refactor some texture upload code 2021-02-26 15:08:14 +03:00
RipleyTom 67378c7dea Add CELL_NET_CTL_INFO_DHCP_HOSTNAME impl 2021-02-26 11:58:42 +03:00
Eladash c13039396c Fix stop count incremention in Emu.Stop (#9843)
Until emulation is completely stopped, further CallAfter callbacks may be issued with incorrect stop count memorized.
2021-02-25 14:37:31 +03:00
Megamouse e940632d93 Fix Nan in cpu_stats::get_usage
And apply same logic to linux and windows
2021-02-25 13:08:27 +03:00
Megamouse 6db25aa7fa overlays: Fix cpu usage in low detail mode 2021-02-25 13:08:27 +03:00
Eladash 0012f39384 Fix TTY handling of control characters 2021-02-24 16:42:39 +03:00
kd-11 0e7e5b59ae vk: Handle old GPUs without proper async queues 2021-02-23 23:22:41 +03:00
kd-11 d459da1378 Formatting fixes only
- Mostly remove camelcase usage in old code.
- Properly annotate vulkan API imports with _vk prefix to make it clear they are not regular variables.
2021-02-23 23:22:41 +03:00
Nekotekina 3063369322 vk::render_device::create: try to remove failing assertion 2021-02-23 19:46:37 +03:00
Nekotekina a90ad62fc0 Remove garbage SPUW perf report 2021-02-23 18:24:50 +03:00
Nekotekina cd01a1eb09 Move CPUStats.h -> util/cpu_stats.cpp 2021-02-23 18:24:50 +03:00
Nekotekina 090a769bf6 Implement fs::sync (Linux/POSIX) 2021-02-23 18:24:50 +03:00
Nekotekina 014846cf31 cellSaveData: fix minor issues 2021-02-23 18:24:50 +03:00
Megamouse b83cb2dbf5 product_info: add Harmonix Pro-Drum Kit (#9822)
Co-authored-by: DrGeelfood <79338929+DrGeelfood@users.noreply.github.com>
2021-02-23 18:23:53 +03:00
Eladash 112b7f6571 Fix Emulation::CallAfter
Most CallAfter usages were extremely wrong when ordered after Emu.Stop(). could result in anywhere from emulation stopping hangs to even segfaults.
track_emu_state = true is now the default, I haven't found cases which need need it disabled.
2021-02-23 17:55:36 +03:00
Eladash 68a878264c Minor GUI fix for PPU interpreter at "precompilation" 2021-02-23 17:35:45 +03:00
Megamouse a771f168eb overlays: fix perf overlay switching detail levels
The body was lagging behind the text. This was fixed by calling an updated version of init() on settings change.
This introduced spikes in the frametime graph, so the data had to become members and m_force_update was adjusted to not interfere with data aquisition.
2021-02-23 13:27:54 +03:00
Megamouse 79b5b79de1 overlays: fix initial size of perf_overlay body
You could see that it was not properly adjusted in the first frame in high detail mode.
2021-02-23 13:27:54 +03:00
Megamouse 7cc8380330 overlays: fix perf_metrics_overlay division by 0 2021-02-23 13:27:54 +03:00
Megamouse e91df31f8c overlays: Fix perf_metrics_overlay visibility
Also change auto type to compiled_resource in order to silence a warning about accidental copy by value
2021-02-23 13:27:54 +03:00
Megamouse 663b2c9c5e overlays: Fix frametime graph spikes
The frametime_timer was restarted at the end of the update method, instead of immediately after reading its value.
This means that the frametime was lower than expected when an expensive task was executed in-between.
2021-02-23 13:27:54 +03:00
RipleyTom 801467e565 Fix rpcn registration 2021-02-23 13:17:49 +03:00
Eladash 447d2b6f93 Atomic RSX capture writes 2021-02-23 11:29:23 +03:00
Eladash 9ccf39b27f Atomic SPU LS capture writes 2021-02-23 11:29:23 +03:00
Eladash d4af8dd89a Fix atomicity of savedata/trophy data writes 2021-02-23 11:29:23 +03:00
Eladash 932f31e37b Atomic PARAM.SFO writes 2021-02-23 11:29:23 +03:00
Megamouse 0878db4e17 remove unused variable 2021-02-23 05:03:38 +01:00
Megamouse 037586d7bb fix no-gui crash if no firmware was installed
It's a bit mysterious, but the confirmation box doesn't like being called in this mode.
So let's just return false.
2021-02-23 05:03:38 +01:00
kd-11 cb7cf40b5e vk: Move queue family management from swapchain to logical device 2021-02-23 00:04:53 +03:00
kd-11 3632412c48 vk/dma: Simplify map_dma interface 2021-02-23 00:04:53 +03:00
Nekotekina 4b858648e5 Add supporters 2021-02-22 19:37:42 +03:00
Nekotekina 85bebebb36 Add commits 2021-02-22 19:37:32 +03:00
Nekotekina 980be9e0e8 JIT.cpp: fix overcommit bug (should have been Linux-specific)
Closes #9820

Co-authored-by: Eladash <elad3356p@gmail.com>
2021-02-22 13:35:01 +03:00
Nekotekina ad1027455a Fix minor inconsistency in utils::memory_reset (Linux) 2021-02-22 13:00:01 +03:00
Nekotekina 9dc238187f Simplify utils::align() a bit
std::is_unsigned implies std::is_integral I believe.
2021-02-22 13:00:01 +03:00
Eladash 73d45f3bf0 Remove vm::cleanup_unlock 2021-02-22 12:47:45 +03:00
Eladash 96400234a8 Remove cpu_thread destructor 2021-02-22 12:47:45 +03:00
Megamouse 2e5f321583 evdev: fix build 2021-02-22 10:45:40 +01:00
Megamouse 5a9b29b73a hid: log more info when adding a device
And minor format changes
2021-02-22 10:45:40 +01:00
Megamouse 1b2260132b only call hid_exit when all hid_handlers are done 2021-02-22 10:45:40 +01:00
Megamouse 1479468730 Input: fix build 2021-02-22 10:45:40 +01:00
Megamouse f0b7afd7cc cellPad: minor optimization 2021-02-22 10:45:40 +01:00
Megamouse 870d26f9d8 Input: replace a bunch of static_pointer_cast 2021-02-22 10:45:40 +01:00
Megamouse f6d465667a Input: unify some more code 2021-02-22 10:45:40 +01:00
Megamouse aaae30cb84 DS3: inherit from hid_pad_handler 2021-02-22 10:45:40 +01:00
Megamouse fbb9396813 DualSense: inherit from hid_pad_handler 2021-02-22 10:45:40 +01:00
Megamouse b9a4abce0e DS4: inherit from hid_pad_handler 2021-02-22 10:45:40 +01:00
Megamouse d0cc5c0fc7 DS4: enumerate devices periodically 2021-02-22 10:45:40 +01:00
kd-11 b7c2bfbcde vk: Fix cyclic read-write in dma_block::load/flush
Some DMA block entries are stubs whose parents are DMA_block_EXT
entries.
Performing load() in this case becomes a memcpy(address,
same_address_again, length) which wastes performance and introduces
bugs.
2021-02-22 01:13:31 +03:00
RipleyTom 8be2a55ccc Add mutex lock for NP changes 2021-02-21 18:04:55 +03:00
RipleyTom 81270f3142 Remove now useless code from sys_bnet_connect 2021-02-21 18:04:55 +03:00
Eladash eb0d006168 Fix most of "[x] thread is too sleepy" at Emu.Stop() (#9813)
* Fixes some thread sleep/wait calls
2021-02-21 16:43:02 +03:00
Oschowa a47bda026b Audio/AL: Request our default sampling rate (48kHz) from AL when creating the
context.
Otherwise AL might downsample and output in 44.1kHz unnecessarily, which
happens at least on my system. Also tested on an audio device that
doesn't support 48kHz to makes sure that still works.
2021-02-20 14:31:38 +03:00
RipleyTom 5129d0da45 check alcGetString return pointers 2021-02-20 07:39:56 +01:00
Eladash b86ec2ffcf Fix potential overflows in utils::aligned_div, utils::rounded_div 2021-02-19 16:10:03 +03:00
Eladash 20eb4352fb debugger: Fix single stepping (#9793) 2021-02-19 14:53:09 +03:00
Nekotekina e76d8eb046 Fix -Wstring-aliasing (gcc) 2021-02-18 19:38:22 +03:00
Nekotekina c8fefc4434 Fix -Wpessimizing-move (Clang) 2021-02-18 14:38:56 +03:00
Nekotekina 2c18d67769 Fix -Wsometimed-uninitialized (Clang) 2021-02-18 14:15:52 +03:00
Nekotekina 428771f1d7 Fix -Wself-assign (clang) 2021-02-18 14:07:22 +03:00
Nekotekina 038148bf06 Fix almost all GCC warnings 2021-02-17 22:59:04 +03:00
RipleyTom 6786734d95 Fix mic device default in config 2021-02-17 18:15:58 +03:00
Nekotekina 1446254a03 Add error on missing 'override'
For consistency.
2021-02-15 20:21:30 +03:00
Nekotekina 3bcd76bd4e Fix regression (incorrectly removed specialization)
Changed CRLF->LF in VKPipelineCompiler.h
2021-02-15 17:05:51 +03:00
Nekotekina 0bcece4585 Make -Woverloaded-virtual an error
Had to devirtualize some functions.
2021-02-15 15:50:05 +03:00
Nekotekina 035ab590ec Reset -ftemplate-depth to normal
It became obsolete.
2021-02-15 14:40:29 +03:00
Nekotekina 8e6e57de86 Enable -Wunused-function warning 2021-02-15 14:39:53 +03:00
Eladash 4c1026436f Log "Missing Firmware" if firmware is missing 2021-02-15 09:50:52 +01:00
kd-11 9f97bab717 vk: Fixup and refactor for exclusive fullscreen stuff 2021-02-15 10:27:36 +03:00
13xforever 76518d4c59 add a hidden option to prevent switching to exclusive full screen mode
this is helpful for people streaming RPCS3, or to prevent disabling HDR mode in Windows
2021-02-14 22:01:33 +03:00
kd-11 eba7d3b172 rsx: Add duplicate section detection when there are too many sections in the surface cache
- Check for useless sections.
  Helps in games that create a bunch of sections randomly for one-time use
2021-02-14 20:42:34 +03:00
kd-11 b8311caa6b vk: Silence some compiler warnings 2021-02-14 20:42:34 +03:00
Eladash 5b044a93c1 Fix vm::falloc() for misaligned args (#9764)
Force addr/size alignment.
2021-02-14 13:19:14 +03:00
Eladash f009d36811 Update log messages of PPU/SPU hashes and patches applied 2021-02-14 09:35:42 +01:00
Eladash f43260bd58 Atomic waiting refactoring (#9208)
* Use atomic waitables instead instead of global thread wait as often as possible.
* Add ::is_stopped() and and ::is_paued() which can be used in atomic loops and with atomic wait. (constexpr cpu flags test functions)
* Fix notification bug of sys_spu_thread_group_exit/terminate. (old bug, enhanced by #9117)
* Function time statistics at Emu.Stop() restored. (instead of current "X syscall failed with 0x00000000 : 0")
2021-02-13 17:50:07 +03:00
Eladash cf384795d2 debugger: Improve PPU string constraints 2021-02-13 16:00:26 +03:00
Eladash 423cc1685c PPU LLVM: Reduce PRX/OVL compilation memory usage a little 2021-02-13 13:05:41 +03:00
Nekotekina 0a23a5ef50 Rewrite fs::get_parent_dir
Don't analyse full path if possible.
2021-02-12 21:43:30 +03:00
Nekotekina 629d608d4f Patch engine: add bd32, bd64 and utf8 patch types
bd32 is the same as be32 with a hint it's not executable.
utf8 is NOT null-terminated string, null can be added manually.
2021-02-12 21:43:30 +03:00
Nekotekina 00be247913 Add commits to the list 2021-02-12 21:43:30 +03:00
Eladash 5ed0cc293d Fix PS3 process exit/exitspawn 2021-02-12 19:39:47 +03:00
Eladash 5401cb7392 kernel explorer: Display all PRX/OVL segments 2021-02-12 15:27:59 +03:00
Eladash e26ae9899c Reimplement/fix PRX patches 2021-02-12 15:27:59 +03:00
Alex Saveau 48296c2ba6 Fixup for multi-thread shader compilation (loading stage) (#9762)
* Multi-thread shader compilation

This offers a huge improvement in startup performance. With around 13,000 shaders we go from ~1:30 to under 10 seconds. It looks like this was the original intention of the author given the outer scope recompile variable.

Signed-off-by: Alex Saveau <saveau.alexandre@gmail.com>
2021-02-12 14:39:35 +03:00
Ani b858fceb4f vk: Support incomplete lavapipe
Disable features still unimplemented by lavapipe when using it:
- samplerAnisotropy
- shaderStorageBufferArrayDynamicIndexing
- wideLines
as of mesa 21.1.0-dev (aea36ee05e9, 2020-02-10)
2021-02-11 14:49:37 +03:00
kd-11 195fb1cf66 rsx: Improve texture cache invalidate
- Bunch of improvements
- Properly signal renderer to rebind textures!
- TODO: Range checks, should be pretty easy
2021-02-10 11:37:14 +03:00
kd-11 52acc23ecf rsx: Fix protection bug 2021-02-10 11:37:14 +03:00
kd-11 0a34fc4bcd vk: Offload garbage collection to offloader thread 2021-02-10 11:37:14 +03:00
kd-11 bec91aab7b rsx: Relax inheritance checks a bit
- It is not a fatal error for a texture to be defined where a framebuffer once existed.
2021-02-10 11:37:14 +03:00
kd-11 5a049d41fd gpu-open/vma: Optimize CheckAllocation method
- Avoids doing useless work. The scanning algorithm is painfully slow on hardware with alignment requirement > 1
- Upto 50ms saved for ~600 allocations when many small allocations exist
2021-02-10 11:37:14 +03:00
kd-11 6f4dbf4fcd vk/vma: Always use aligned requests
- Performance optimization when combined with vma optimizations added by me
2021-02-10 11:37:14 +03:00
kd-11 bf66c36ba4 rsx/texture_cache: Add support for reusing dirty images if possible
- Avoids a silly situation where a texture is discarded and an identical copy created immediately afterward.
  Unfortunately allocating memory blocks is really slow so avoid it as much as possible.
2021-02-10 11:37:14 +03:00
kd-11 0c10f47e85 rsx: Lower cache block length to 256 pages
- Drastically lowers time wasted iterating blocks when many small objects
  are present
2021-02-10 11:37:14 +03:00
kd-11 1bad9a939f rsx: Refactor texture cache utils
- Also lays groundwork for optional hashed sections
2021-02-10 11:37:14 +03:00
Megamouse 8d6504d6e3 GUI: initial log viewer 2021-02-09 22:56:28 +01:00
Ivan 04c187deb5 Revert "Replace GetEmuDir() with GetExeDir() in handle_rpcs3"
This reverts commit f9eb6a31bd.
2021-02-09 22:24:09 +03:00
Megamouse bc938ce630 dualsense: implement player LEDs 2021-02-09 19:21:37 +01:00
Megamouse e5f95a450d dualsense: update description 2021-02-09 19:21:37 +01:00
Megamouse b31d38eef7 LED settings: set modal and add has_battery check 2021-02-09 19:21:37 +01:00
Megamouse db402cb8af dualsense: add player LED support 2021-02-09 19:21:37 +01:00
Megamouse 1af6550db7 dualsense: add lightbar support 2021-02-09 19:21:37 +01:00
Megamouse 7795f5207f dualsense: fix switched motors
The left one seems to be the large motor
2021-02-09 19:21:37 +01:00
Megamouse a9b8a50c31 dualsense: add output report structs based on linux driver 2021-02-09 19:21:37 +01:00
Megamouse a9418fa1e7 dualsense: implement SetPadData for rumble in GUI 2021-02-09 19:21:37 +01:00
Megamouse 08f48d27e8 Input: minor simplification
This might prevent some copy paste error in the future
2021-02-09 19:21:37 +01:00
Megamouse 25a66da4ca Input: rename some functions 2021-02-09 19:21:37 +01:00
Megamouse ff61bc9e7c dualsense: add mic button 2021-02-09 19:21:37 +01:00
Megamouse 3e8f4ba018 dualsense: add gyro support 2021-02-09 19:21:37 +01:00
Jordy Vieira f9eb6a31bd Replace GetEmuDir() with GetExeDir() in handle_rpcs3 2021-02-09 20:06:26 +03:00
Nekotekina 4f8cac731b Fix SAFE_BUFFERS attribute for GCC 2021-02-09 12:33:50 +03:00
Nekotekina 3e496f6625 Add -fstack-protector (Non-MSVC) 2021-02-09 12:06:17 +03:00
kd-11 2d62f9c4c5 vk: Improve spec compliance (#9748)
- Always comply when running under strict mode
- Only allow hacky transport for known-to-work GPUs
2021-02-08 22:11:01 +00:00
Eladash 78811b8816 GUI: Always remove manually added fonts in OnChangeStyleSheetRequest() 2021-02-08 21:38:53 +01:00
Eladash e38cd5149a Fix firmware updating/reinstallation 2021-02-08 21:38:53 +01:00
Megamouse dc2a1e270a Qt: Repaint log on stylesheet change 2021-02-08 13:24:07 +03:00
Megamouse 44ab50553d Qt: Replace relative paths in stylesheets instead of changing the working directory 2021-02-07 20:07:58 +03:00
Megamouse 7c683c368d Qt: Fix weird naming issue on linux 2021-02-07 20:07:58 +03:00
Megamouse 62ca7a9b60 Qt: Simplify stylesheet logic 2021-02-07 20:07:58 +03:00
Nekotekina 632e36ab44 Qt: fix stylesheets on various platforms
Replace relative paths to resources.
Paths should start from GuiConfigs.
2021-02-07 14:09:50 +03:00
Nekotekina 0057c89eaa PPU Analyser: follow fallbacks in some cases
Fallback is an "invisible" branch to the next instruction.
This may be necessary for certain cases when patches are used.
2021-02-07 11:02:45 +03:00
Nekotekina 9e9a55df46 PPU LLVM: compile instructions from patches
For now, only as a single instruction at a time.
2021-02-07 11:02:31 +03:00
Nekotekina 9463238490 PPU Analyser: minor fixups for end pointer
Add more sanity checks for sections.
Remove some redundancy.
2021-02-07 11:02:31 +03:00
Nekotekina b7ff2ecffb Patch system: export some info for future use
For now it's just a list of addresses.
For now it's not used (just a stub).
2021-02-07 11:02:31 +03:00
Eladash fad89f1c3b Fix tiny race in PPU breakpoints (#9731)
If the PPU has just being paused by the debugger, before it entered the breakpoint handler, the PPU would continue onto the next instruction skipping the breakpoint but then being paused on it instead.
2021-02-07 00:25:40 +03:00
Nekotekina 5063eefa96 Fixup for downloader 2021-02-06 15:21:00 +03:00
Nekotekina 1b34fa26ac Update commits.lst (example) 2021-02-06 12:57:14 +03:00
Nekotekina 25827c12a3 Make out of source builds get copy of /GuiConfigs/, /git/, etc.
Reduce quality of kot-bg.jpg.
2021-02-06 12:55:14 +03:00
Nekotekina cb32fd15ee Add supporters 2021-02-06 00:37:53 +03:00
Nekotekina d6dcab443d Updater: add minor sanity check 2021-02-06 00:37:53 +03:00
Nekotekina c32fec774f Create mini-cache for commits
Located in bin/git/commits.lst;
Created with GitHub API with --get-commit-db key.
Can be lazily appended with the same key.
2021-02-06 00:37:53 +03:00
kd-11 ddac4686a7 rsx: Clear vertex output register if nothing is written to it
- On NVIDIA GPUs, gl_Position is not initialized. Always clear to 0 to avoid on-screen crap
2021-02-05 22:22:07 +03:00
Megamouse 2865865382 Don't use std::exit during Qt initialization 2021-02-05 17:32:48 +01:00
Eladash 7ce835e878 Support logger stopping at std::exit (#9722) 2021-02-05 17:07:17 +03:00
Megamouse 7e0fdbbe99 Fix rpcs3.vcxproj 2021-02-04 23:11:05 +01:00
Megamouse fd1f2ca1c6 Rename some variables to snake_case 2021-02-04 23:11:05 +01:00
Nekotekina a6a92f7b6b Qt: remove Q_OBJECT for mouse/kb handlers
Had to move QObject in parent list for g_fxo changes.
2021-02-04 23:11:05 +01:00
Eladash 4f85f151fd SPU: Always signal the debugger about termination 2021-02-03 15:05:38 +03:00
Eladash 478ae0715e Tiny fix for zombie PPU threads 2021-02-03 15:05:38 +03:00
Megamouse 714eb6dcc5 Disable LimitCacheSize option in custom configs
It doesn't make sense on a per game basis and is used before loading them anyway
2021-02-02 18:37:18 +01:00
Megamouse 89942ed92a optimize add_only boot process
No need for hardcore stuff while adding games to the list
2021-02-02 18:37:18 +01:00
Megamouse 6ed9251f44 Remove tooltip event filter from gamelist
Fixes a weird issue where tooltips for the wrong game would popup.
I don't know why the event filter was needed.
Maybe the tooltips didn't work otherwise back then or it was just some copy paste from google.
2021-02-02 15:46:42 +01:00
Megamouse 2c32a721fc Allow BootGame with indirect paths 2021-02-02 13:21:26 +01:00
Nekotekina 08aaae7999 PPU LLVM: workaround patch handling
Try to address #9704
2021-02-02 10:33:13 +03:00
Nekotekina 78bad361ab Fix fs::unread (Linux)
Detach from fs::lock
Handle existing file case (unlink it).
2021-02-02 01:05:53 +03:00
Eladash 2005c89baa memory viewer: Implement RSX mode
* Set the ground for RSX modes of register editor and insttruction editor, do not use shared ptrs directly.
* Make register editor and instruction editor modeless to allow to copypaste values from thread context etc in the background.
2021-02-02 01:05:36 +03:00
Megamouse 8c6aa9db31 Print report_fatal_error to cmd
useful if used like:
start /w ./rpsc3 --headless <path>
2021-02-01 21:44:23 +01:00
Nekotekina 58eef983e2 PPU Analyser: fix constraints for all elfs.
Added for main executable and OVLs.
Forgot to use it not just for SPRX.
2021-02-01 19:14:24 +03:00
Nekotekina 390b192f0a TSX: workaround for check_state freezes 2021-02-01 19:14:24 +03:00
Nekotekina 7b40859eff Remove unused header 2021-02-01 19:14:01 +03:00
Nekotekina d0126f0fa0 Fix freezes in HLE Vdec and SPU LLVM precompilation.
Freezes could accidentally occur on close or ingame.
Deprecate range-for loop on lf_queue.
This is a part of PR #9208

Co-authored-by: Eladash <elad3356p@gmail.com>
2021-02-01 19:14:01 +03:00
Nekotekina 0c034ad7de PPU LLVM: upgrade to GHC call conv
Get rid of some global variables.
Implement ppu_escape (unused yet).
Bump PPU cache version to v4.
2021-02-01 11:30:50 +03:00
Nekotekina aeeceb7d0b Minor fixups 2021-02-01 11:30:50 +03:00
Nekotekina d5f16ce272 PPU Analyser: better constraints for SPRX 2021-02-01 11:30:50 +03:00
Nekotekina c89362f6a2 PPU LLVM: don't use module name as PRX indicator 2021-02-01 11:30:50 +03:00
Nekotekina 8a029159cd PPU Analyser: compile certain functions on per-instruction basis
PPU LLVM: optimize small blocks
2021-02-01 11:30:50 +03:00
Nekotekina 891ebd0cb1 PPU Analyser: use reloc info (disabled for now)
Add blocks from relocations.
2021-02-01 11:30:50 +03:00
Nekotekina 382509d778 PPU LLVM: Implement inline __add_get_ov 2021-02-01 11:30:50 +03:00
Nekotekina f9ee8978ff PPU LLVM: improve analyser
Compile possibly executable holes between detected functions.
Add unused "PPU LLVM Greedy Mode" option (for future updates).
Add "nounwind" attribute to compiled functions (reduces size).
2021-02-01 11:30:50 +03:00
Eladash e71c2df39d Debugger: Add some more shortcut descriptions in F1 helper 2021-02-01 00:21:50 +03:00
Eladash cfc7865f82 Debugger: Allow to unpause a thread which has been paused by global pause 2021-02-01 00:21:50 +03:00
Nekotekina cf6606065d PPU: fix some typos in asm code 2021-01-31 20:00:04 +03:00
Megamouse 9feb92df1b More informative Error message on Vulkan driver crash
The message might not be the only reason, but at least it might help someone like me, who had no idea what he was looking at.
2021-01-31 15:51:21 +01:00
Megamouse be26810cd7 RSX: Implement set_value for progress dialogs 2021-01-31 15:02:26 +01:00
Megamouse df79b6c238 RSX: update shader loading dialog at 60 fps
Looks much smoother
2021-01-31 15:02:26 +01:00
Eladash 82c86ed2f7 Implement standalone OVL (overlay) loading mode
* Allow to load OVL alone.
* Add error checks in ppu_load_exec(), do not crash on error.
* Fix crash on exit from standalone PRX mode, allow kernel explorer to work with it as well for the added OVL mode.
2021-01-31 15:47:05 +03:00
Eladash 9077563dac Add missing destructor of progress dialog 2021-01-31 12:55:20 +01:00
Eladash 8d15f44b33 Fix ppu progress dialog percentage 2021-01-31 12:55:20 +01:00
Eladash b3fbada10e Fix potential crash of progress dialog 2021-01-31 12:55:20 +01:00
Megamouse 31cdd7bdd2 Prevent minor race in Progress Dialog Server 2021-01-31 12:18:32 +03:00
Megamouse c464e90d5d Fix stop exit of check_only ppu_initialize 2021-01-31 12:18:32 +03:00
Megamouse 670d2b191c Minor optimization for check_only ppu_initialize 2021-01-31 12:18:32 +03:00
Megamouse 7bddb87306 Simplify compile threads 2021-01-31 12:18:32 +03:00
Megamouse 2025f02105 Search for more game data directories.
Also properly remove duplicate paths
2021-01-31 11:42:33 +03:00
Megamouse 1078626eea Fix ppu compilation progress dialog
We could only increase the value because we completely based the dialog on cellMsgDialog.
This led to an issue where the dialog would increase its maximum and thus decrease the current percentage.
It then couldn't decrease and was stuck on the old percentage.
2021-01-30 21:34:16 +01:00
Eladash 16c6b44f55 Fix #9680 (#9687)
Fix regression from #9680
2021-01-30 19:05:02 +03:00
Eladash 6b3b06df25 rsx: Set frame limit to auto by default 2021-01-30 16:53:14 +03:00
Eladash e3b3b0cda7 PPU LLVM: Precompile all executable (PRX, MSELF, overlay) code at startup (#9680)
* Precompile LLVM cache at startup of games, like the GUI "Create PPU Cache" option.
* Allow OVL (overlay) precompilation as well (used by certain games).

Co-authored-by: Megamouse <studienricky89@googlemail.com>
Co-authored-by: Nekotekina <nekotekina@gmail.com>
2021-01-30 16:08:22 +03:00
Nekotekina bb2cc196a6 Fixup for preloading SPRX from MSELF
Forgot to append the offset.
Forgot to use different loop variable.
2021-01-29 21:26:34 +03:00
Eladash d3bc96a201 Fix minor issue with usage of STL thread::hardware_concurrency() 2021-01-29 18:23:29 +03:00
Nekotekina 11ba6e45ab Add MSELF support to SPRX precompilation.
Add ppu_precompile() function in PPUThread.cpp

Co-authored-by: Eladash <elad3356p@gmail.com>
2021-01-29 13:34:43 +03:00
Eladash a742501a4f Do not account RSX for TSX pauses 2021-01-29 10:31:15 +03:00
Eladash 70346028c5 Fix GCM HLE
Oops.
2021-01-29 10:31:15 +03:00
Megamouse 3359458175 Handle missing cases of Emu.BootGame failure 2021-01-28 20:54:27 +01:00
Nekotekina 6784301376 Check for rsx::thread existence in Emu.Stop/Pause/Resume 2021-01-28 20:23:13 +03:00
Megamouse 51d19e7c31 Input: remove debug error 2021-01-28 18:02:23 +01:00
Eladash 0652870204 New RSX Debugger 2021-01-28 17:40:26 +03:00
Nekotekina 67dd6754a6 Seal cereal includes in util/cereal.cpp 2021-01-28 10:48:53 +03:00
Nekotekina 34274ec391 Purge unused typeid() invocations 2021-01-28 10:23:29 +03:00
Eladash 28feea0447 Unfatal Segfaults 2021-01-27 21:54:29 +03:00
Nekotekina 53267e283b PPU LLVM: implement ppu_finalize
Properly free certain compiled PRX/OVL modules (except dev_flash)
2021-01-27 18:03:49 +03:00
Nekotekina 15ed963a29 UI: Add supporters 2021-01-27 14:23:26 +03:00
Nekotekina c652d0b183 Detect execution access violation
Don't try to handle it, treat as fatal.
2021-01-27 11:53:10 +03:00
Nekotekina 22c55cbcfa Add trace logging to thread_ctrl::set_thread_affinity_mask 2021-01-26 19:59:48 +03:00
Nekotekina c24d89dd34 Threads: fix typo in emergency_exit (dump useful info) 2021-01-26 19:58:47 +03:00
Nekotekina f10ea1fb9b Thread pool: try to fix resetting affinity mask
Attempt to address #9657
2021-01-26 16:45:36 +03:00
Nekotekina eb72cc9f04 Thread pool: reset thread affinity mask 2021-01-25 22:05:38 +03:00
Nekotekina ee288340b0 Implement thread_ctrl::scoped_priority
RAII priority control (+1, or -1)
2021-01-25 21:49:16 +03:00
Nekotekina a69248299d SPU: Don't use shm::map_critical in SPU LS allocations
Use shm::try_map instead until proper area is found.
2021-01-25 17:45:47 +03:00
Nekotekina caa83d20f7 vm_native.cpp: implement shm::try_map
Treats addr as a hint, emulating windows behaviour.
2021-01-25 16:55:19 +03:00
Malcolm Jestadt 486d48e4f8 SPU LLVM: Optimize ROTQBY family for VBMI
- Avoid masking pshufb index by 0xf by using vpermb instead.
- Also fix conversion of vperm2b index to ShuffleVector index.
2021-01-25 13:18:23 +03:00
Nekotekina 8480674708 Thread pool: reset priority 2021-01-24 16:45:28 +03:00
Ani 7c62574e59 spu: Restore workers priority after initialization 2021-01-24 16:40:59 +03:00
kd-11 22584fb2d1 vk/dma: Disable pasthrough DMA for NVIDIA+windows
- The driver seems to cache page mapping as long as allocation has not been removed
- This is undesirable as we cannot stop the emulator to remove stale allocations every time a page is unmapped
2021-01-24 14:24:55 +03:00
kd-11 90ac9165e2 vk/dma: Unmap pages from GPU when they are unmapped in Cell 2021-01-24 14:24:55 +03:00
kd-11 bcb69a54b2 gl: Avoid type shenanigans used to fake byteswap for select formats
- Just use the reversed type instead.
  The new uploader backend combines swizzle+swap so there is no need for tricks anymore
2021-01-24 14:24:55 +03:00
kd-11 f93cb262ba vk/dma: Fix multiple logical bugs
- Fix range chaining.
- Add validation checks that no overlaps exist.
2021-01-24 14:24:55 +03:00
kd-11 67949bb5b7 vk/dma: Allow interoperability between pass-through and write-back DMA caching types 2021-01-24 14:24:55 +03:00
kd-11 e56da4eb46 vk: Workaround for amdgpu kernel driver 2021-01-24 14:24:55 +03:00
kd-11 f7fdfe52bc vk: Fix custom event signals 2021-01-24 14:24:55 +03:00
kd-11 7de0ff337b vk: Polishing and cleanup
Some spec violations fixes
Make the option dynamic
2021-01-24 14:24:55 +03:00
kd-11 e1c0a917fa vk/dma: Modify default page size to 64k 2021-01-24 14:24:55 +03:00
kd-11 ead180aa60 win32: Be a bit more optimistic with allocated ranges; we get contiguous ranges more often than not 2021-01-24 14:24:55 +03:00
kd-11 58d367d704 vk: Add host-imported DMA buffers 2021-01-24 14:24:55 +03:00
kd-11 a1ab6c28c1 vk/rsx: Fix some more bugs 2021-01-24 14:24:55 +03:00
kd-11 59e46f09b7 vk/dma: Disable memory inheritance
- It is not possible to emulate passthrough memory cleanly, and we don't need to
  A stupid race condition appears when trying to synchronize DMA blocks with memory inheritance.
  Since the usage pattern is to acquire a range and then load or write+flush, this new data is going to be..
  overwritten by the commandbuffer execution sequence later. Acquiring a scratch buffer to hold CPU content during the transition is not worth the effort..
  as the data will be destroyed anyway during the transfer process immediately afterwards.

  Fixes data corruption when moving data around using the emulated DMA passthrough
2021-01-24 14:24:55 +03:00
kd-11 7766076042 rsx/vk: DMA stuff 2021-01-24 14:24:55 +03:00
Eladash b96864c7e6 rsx: Improve gs frame exit workaround
Move to close(), hide before potential hanging at Emu.Stop()
2021-01-23 12:45:53 +03:00
Eladash 79513f06a4 rsx/gui: Delay game window pop-up until first frame 2021-01-23 12:45:53 +03:00
RipleyTom 00ff53499a fix UserInfo2_to_SceNpUserInfo2 2021-01-22 20:51:10 +03:00
Eladash 142b44d4be debugger: Implement F1 helper 2021-01-22 00:39:41 +01:00
Eladash 7f28489c70 Improve ppu_thread_cleaner a bit
Always join thread.
2021-01-21 21:32:13 +03:00
Eladash a58c12db0b SPU: fixup after #9630
Co-Authored-By: Ivan <nekotekina@gmail.com>
2021-01-21 21:32:13 +03:00
Eladash 12e1be2626 Implement thread_ctrl::wait_on (see #9208) 2021-01-21 18:31:51 +03:00
Eladash f81674232e Remove SPU and PPU destructors 2021-01-21 18:31:51 +03:00
kd-11 eb086b0e3f rsx: Add support shadow1D and shadowCube 2021-01-21 10:24:49 +03:00
kd-11 b6b9085773 rsx: Use unsigned variables to avoid sign problems when calculating stipple bits 2021-01-21 10:24:49 +03:00
Nekotekina 241989c5fa Fix new warnings
Added CELL_GCM_CONTEXT_DMA_NOTIFY_MAIN_0+ enums.
Added CELL_GCM_CONTEXT_DMA_TO_MEMORY_GET_NOTIFY0+ enums.

Co-authored-by: Eladash <elad3356p@gmail.com>
2021-01-20 12:27:37 +03:00
Nekotekina f944573b3c Fix old warnings: remove strncpy
Use strcpy_trunc instead.
Change some sce structs.
2021-01-20 12:26:09 +03:00
Nekotekina c66b155dcb Remove unnecessary fmt::throw_exception destructor body
Tested with GCC and Clang in Debug mode, it now works.
2021-01-20 09:02:25 +03:00
RipleyTom 5662867730 Change the way skylander ID is generated 2021-01-20 08:46:39 +03:00
Eladash dbecf0fa50 Introducing RSX debugger entry (main debugger) 2021-01-19 22:55:12 +03:00
Megamouse 62cb532460 Qt: hotfix for downloader
I accidentally broke the download progress bar in the last related PR.
I should've put more trust in the sanity of the younger version of myself.
This should fix it.
2021-01-18 22:41:31 +01:00
Nekotekina f9bc682115 Refactor some 'offending' code a bit (no effect)
It appears linkage errors were rare even in debug mode (GCC/clang).
2021-01-18 21:58:28 +03:00
Nekotekina 6cf0c5cd6d Fix fmt::throw_exception destructor v2
Remove destructor for MSVC.
2021-01-18 21:19:34 +03:00
Nekotekina 8a2a76da1e texture_cache: fix some warnings in AUDIT 2021-01-18 13:49:59 +03:00
Nekotekina e07484f057 Rewrite fmt::throw_exception destructor
Add _DEBUG in debug mode for consistency with MSVC.
2021-01-18 13:49:16 +03:00
Eladash 0070fce286 Compilation fix (#9622) 2021-01-18 13:41:39 +03:00
Malcolm Jestadt a2e8e3090c SPU LLVM: Optimize FSM following comparison
- FSM following a comparison instruction can be optimized to a single shuffle instruction
2021-01-17 16:52:44 +03:00
Nekotekina 0ac68def49 vm_native.cpp: minor compilation fix 2021-01-17 15:14:11 +03:00
Nekotekina def364fe28 SPU LLVM: add splat_scalar helper
Unrolls into zshuffle from the preferred slot.
2021-01-17 15:13:28 +03:00
Alex James c06707c891 CMake: Unset LIBUSB_LIBRARIES when using libusb submodule
If the system has libusb installed but USE_SYS_LIBUSB is false, the
static libusb will link against the system libusb (as pkg_check_modules
sets LIBUSB_LIBRARIES, and 3rdparty/libusb_cmake/libusb.cmake links the
usb-1.0-static target with LIBUSB_LIBRARIES). Unset LIBUSB_LIBRARIES to
avoid this when using the libusb submodule.
2021-01-17 13:51:03 +03:00
Alex James d7a8d385d8 CMake: Use find_package to find SDL2
This ensures that the SDL2 uses an absolute library path, which is
necessary when SDL2 isn't present in the default link directories (e.g.
on macOS).
2021-01-17 13:51:03 +03:00
Nekotekina 3567c43fb5 LLVM: generate trampolines for "null" functions
Embed name into the trampoline for easier debugging.
Only warn about it during the compilation phase.
2021-01-15 21:38:33 +03:00
Nekotekina aaaeb66cc8 vm: Minor fix in vm::close
Supplied size was wrong.
2021-01-15 20:12:30 +03:00
Nekotekina 4ed76a15ff Use different approach in shm::unmap_critical (Linux)
For now, set protection to PROT_NONE.
Attempt to address #9609
2021-01-15 20:11:09 +03:00
Nekotekina b5837d1271 Memory: use MADV_DONTDUMP if available (Linux)
Also refactor other madvise() usage
2021-01-15 19:54:41 +03:00
Eladash e4c3b1c2bd vm: Remove vm::dealloc_verbose_nothrow 2021-01-15 17:37:52 +03:00
Nekotekina ea916fd7e1 Memory: fix critical bug in shm::unmap_critical (Linux)
It was leaving holes in reserved areas.
Windows is unaffected.
2021-01-14 18:04:29 +03:00
Nekotekina 4bee8dc37f Crypto: modernize key_vault.h
Use constexpr, remove warning guards
2021-01-14 15:23:52 +03:00
Nekotekina 8b01d05146 Crypto: modernize ec.h
Add const, use u8
2021-01-14 15:17:07 +03:00
Nekotekina 376e564cff Crypto: make global vars in ec.cpp thread_local 2021-01-14 12:01:41 +03:00
Nekotekina caf02d1841 Crypto: don't modify EDAT_IV (all zeros)
I didn't notice where it gets restored to zeros.
2021-01-13 21:57:38 +03:00
Nekotekina 6cf73fad13 Crypto: workaround -Wunused-variable
Ignore for key vault for now.
2021-01-13 19:02:14 +03:00
Megamouse cfe660ab35 Qt/curl: fix segfault in curl
The QThread lived longer than the m_curl object.
This lead to a crash when closing RPCS3 while the download is still in progress.
2021-01-13 19:01:58 +03:00
Megamouse 8eaf76394c Qt/Input: Use ellipsis as "mouse deadzone"
This is experimental and smoothens the existing square shaped deadzone
2021-01-13 11:25:33 +01:00
Megamouse a692adefd7 Remove legacy patch support 2021-01-13 10:39:17 +01:00
Eladash e05f1c37ad memory viewer: Close all instances after emulation exit 2021-01-12 23:57:36 +03:00
Eladash 923fcc3b3d utils::shm: Hotfix after #9578 2021-01-12 23:57:36 +03:00
Eladash c50b9bc4b4 utils::shm: Make map_self() atomic (#9578) 2021-01-12 19:53:18 +03:00
Eladash e1f95ceb54 sceNpTrophy: Fix sceNpTrophyRegisterContext for handler abortion (#9586)
* Implement handler abortion during context registration.
* Fixed recursive calls to sceNpTrophy functions such as by callbacks from registering context.
* Turns out the reader lock for context registeration was incorrect because ctxt->tropusr and trophy directory are being modified. Made it an exclusive lock after callback.
2021-01-12 19:14:51 +03:00
Megamouse eb77495d5f Implement richtext_item_delegate
And use it in pkg_install_dialog
2021-01-12 14:13:15 +01:00
Megamouse 270d602a26 Add filename to multi pkg installation
Some packages are indistinguishable otherwise
2021-01-12 14:13:15 +01:00
Megamouse dd41ee68de Simplify numbered_widget_item 2021-01-12 14:13:15 +01:00
Megamouse 46dc40f3f1 Add filename to single pkg installation
Some file info is indistinguishable otherwise
2021-01-12 14:13:15 +01:00
Megamouse 7c7af2e102 fix rebase conflicts 2021-01-12 14:13:15 +01:00
Megamouse 36189b8c3b Try to distinguish between Update and DLC (Part 2) 2021-01-12 14:13:15 +01:00
Megamouse cde802b16c Move blocking code in order to free the explorer 2021-01-12 14:13:15 +01:00
Megamouse 1500e5f588 Try to distinguish between Update and DLC 2021-01-12 14:13:15 +01:00
Megamouse fbe91fb245 fix linux compilation 2021-01-12 14:13:15 +01:00
Megamouse 321e7d6977 Don't hide the PKG install progress dialog after each package 2021-01-12 14:13:15 +01:00
Megamouse 56488a4ac9 Use boolean values in unedat 2021-01-12 14:13:15 +01:00
Megamouse 4a75f44d47 Minor include cleanup in utlis.h 2021-01-12 14:13:15 +01:00
Megamouse deb4b03200 Add VERSION fallback to GetPkgInfo 2021-01-12 14:13:15 +01:00
Megamouse df94c906da Add more info to PKG install progress dialog
And fix installation of single packages
2021-01-12 14:13:15 +01:00
Megamouse 4d50d9daa4 unpkg: add missing break and some cleanup 2021-01-12 14:13:15 +01:00
Megamouse 0624bdc72d Use package reader in pkg_install_dialog 2021-01-12 14:13:15 +01:00
Megamouse ccec6e53c0 Rename package_reader member variables 2021-01-12 14:13:15 +01:00
Megamouse 68d411918d Read patchsets from compat db 2021-01-12 14:13:15 +01:00
Nekotekina f14d47bfe6 LLVM: log certain null functions 2021-01-12 15:39:43 +03:00
Nekotekina 0af452720e RSX: Fix possible bug in memory streaming utils 2021-01-12 15:06:31 +03:00
Nekotekina db8e6fe7a7 Enable -Wunused-variable 2021-01-12 14:34:14 +03:00
Nekotekina 631d7d0ce7 Enable -Wunknown-pragmas 2021-01-12 13:01:17 +03:00
Nekotekina ed345e5b65 Enable -Winvalid-offsetof 2021-01-12 13:01:17 +03:00
Nekotekina d3a66af7d6 Enable -Wcomment warning 2021-01-12 13:01:17 +03:00
Megamouse 52deff06ba Random stuff (#9589)
* minor coding style adjustment

* Qt: simplify osk dialog buttons

* replace std::find_if with convenience functions

* RSX: use sv in swizzle comparison

idk, I'll remove this if it was intentional.

* overlays/osk: rename enter to return

This one confused me and make me look for a bug that caused the "enter" key to be disabled, while it was actually the return key (obviously xD).
2021-01-12 12:59:50 +03:00
Megamouse 838cbe1840 tiny include fix 2021-01-11 13:04:46 +03:00
Eladash 70804e2ba6 kernel explorer: Make it single-instance tool 2021-01-10 20:30:23 +01:00
Eladash 07c925223b rsx: Fix index array offset bits 2021-01-10 18:40:02 +03:00
kd-11 c2cbc62be6 vk: Refactor some uber-headers
- VKHelpers was the rug everything was swept under for a long time.
  This commit essentially deprecates its usage across most of the backend.
2021-01-10 12:04:31 +03:00
Nekotekina 9d74d42f2a Fix compilation for gcc-11
In response to #9557
2021-01-09 14:38:01 +03:00
Nekotekina a36f25c7b2 Update LLVM to latest commit 2021-01-09 11:05:12 +03:00
Nekotekina 86fb5412fa Update ASMJIT to oldstable 2021-01-09 11:05:11 +03:00
Nekotekina c5b9ab3aca Update ASMJIT submodule URL 2021-01-09 11:05:11 +03:00
Eladash bf6f43ec3a Utils: Rewrite fmt::split 2021-01-08 22:23:48 +03:00
Megamouse 36159c2bd4 Add comment for deprecated avcodec_register_all
Apparently this is now done automatically and doesn't even need to be called at all
2021-01-08 14:36:49 +03:00
Megamouse 72e1d03860 Qt: ugly fix for ugly deprecation warning
Apparently Qt wants us to implement each comparison on our own, and there is no simple replacement for this.
2021-01-08 14:36:49 +03:00
Megamouse ed1b8f2545 game_list: fix deprecation warning
We only need to check if the data is valid for clicks on empty space in the game grid. I don't remember why I initially checked < 0
2021-01-08 14:36:49 +03:00
Nekotekina 1ad0f24ecd Fix or silence Qt warnings 2021-01-07 13:18:48 +03:00
Nekotekina 586440622b Silence another warning (clang) 2021-01-07 12:46:45 +03:00
Nekotekina 6231b07d2a Silence one warning (clang) 2021-01-07 12:42:15 +03:00
Nekotekina 1dcf5e4f85 Error on no return type warning
Added non-existing noreturn destructor to fmt::throw_exception (for clang).
2021-01-07 11:56:16 +03:00
Nekotekina 9ba8f4795c Remove redundant #pragma once 2021-01-06 23:33:37 +03:00
Eladash 951fe3491e PS3 Loader: Fix sections memorizing 2021-01-06 23:21:38 +03:00
Nekotekina 6ae1f1b02c VFS: fixup handling . and .. after #9528 2021-01-05 16:16:01 +03:00
Nekotekina 673e84920b fixed_typemap.hpp: remove useless reporters 2021-01-05 16:16:01 +03:00
Eladash d1e1c14dc3 VFS: Escape path components which end with space or period 2021-01-05 16:15:47 +03:00
Megamouse 11db3151ae VK refactoring Part 2 (#9542) 2021-01-05 10:49:03 +03:00
Josh Lay 65f81aca0f Docs: Update BUILDING.md (Fedora)
The package `qt5-devel` isn't available, but the `qt5-qtbase-devel` package is 😄 

Before:
```
[root@workstation ~]# dnf install alsa-lib-devel cmake glew glew-devel libatomic libevdev-devel libudev-devel openal-devel qt5-devel qt5-qtbase-private-devel vulkan-devel
Last metadata expiration check: 0:06:39 ago on Mon 04 Jan 2021 08:00:59 PM CST.

Package alsa-lib-devel-1.2.4-5.fc33.x86_64 is already installed.
Package cmake-3.18.4-2.fc33.x86_64 is already installed.
Package glew-2.1.0-8.fc33.x86_64 is already installed.
Package libatomic-10.2.1-9.fc33.i686 is already installed.
Package libatomic-10.2.1-9.fc33.x86_64 is already installed.
Package systemd-devel-246.7-2.fc33.x86_64 is already installed.
No match for argument: qt5-devel
Package vulkan-loader-devel-1.2.148.1-1.fc33.x86_64 is already installed.
Error: Unable to find a match: qt5-devel
[root@workstation ~]#
```
After:
```
[root@workstation ~]# 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
[...]
Installed:
  cups-devel-1:2.3.3op1-1.fc33.x86_64            glew-devel-2.1.0-8.fc33.x86_64  libevdev-devel-1.9.1-3.fc33.x86_64  openal-soft-devel-1.19.1-9.fc33.x86_64 
  qt5-qtbase-private-devel-5.15.2-2.fc33.x86_64 

Complete!
[root@workstation ~]# 
```
Build verified working on Fedora 33 with 187216096d
2021-01-05 10:27:56 +03:00
matoro 187216096d Build: Add include for building on certain configs 2021-01-04 10:04:51 +03:00
kd-11 3f9b699eef rsx: Fix ambiguous call to min(float16_t, float) 2021-01-04 02:28:24 +03:00
kd-11 5f8564c655 Update Utilities/Thread.cpp
Co-authored-by: Bird Egop <sampletext32@bk.ru>
2021-01-03 19:31:18 +03:00
kd-11 cbe0000d23 Improved Zen chip detection 2021-01-03 19:31:18 +03:00
Eladash 0e278d2299 rsx: Make FP shader cache load lock-free 2021-01-03 01:47:07 +03:00
Eladash 21d725daa5 rsx: Fix shader cache of 2 or less pipelines 2021-01-03 01:47:07 +03:00
Eladash 247e90b3d0 rsx: Shaders cache loading and saving bugfixes
* Fixed crash whenever files are missing from the cache.
* Fixed crash whenever files are empty.
* Fixed crash whenever file creation/overwrite of cache files failed. (handled by fs::write_file)
* Fixed crash whenever there are any subdirectories inside the pipelines cache directories.
* Overwrite invalid shader cache files if encountered such.
* Optimizations have been added.
2021-01-03 01:47:07 +03:00
Ani 2b8eb8deb6 rpcs3_version: Bump to 0.0.14 2020-12-31 23:15:54 +03:00
Megamouse 7262f3d0b7 VK: make static chip_family_tables const 2020-12-31 22:57:17 +03:00
Megamouse 6f80fd0063 VK: move static chip_family_tables to cpp 2020-12-31 22:57:17 +03:00
Megamouse 7a51b7a019 VK: move helpers to vkutils 2020-12-31 22:57:17 +03:00
Megamouse d9eb31000d VK: refactoring part 1 2020-12-31 22:57:17 +03:00
Chris f8589de476 Initial playlist-based custom soundtracks support (#9362)
* Initial playlist-based custom soundtracks support

This is the initial implementation of playlist-based (cellSearch) custom soundtracks support.
It is based on the initial work by @Megamouse and currently uses a directory-based approach to manage albums and utilizes FFMPEG to read audio metadata.

Background: The real PS3 can import music in XMB from USB into its internal storage (/dev_hdd0/music) and additionally stores metadata (artist, trackname, tracknumber, ...) in a database (/dev_hdd0/mms/db/metadata_db_hdd). Games can make use of imported music via cellSearch.

For the time being, this implementation does NOT make use of metadata_db_hdd as the db-format is not well understood and a folder-based approch is easier to use. Users only have to create folders inside /dev_hdd0/music and add music to it to create a "playlist". This playlists contents will be sorted alphabetically. As a result, users could prefix numbers to the audio-files to force a specific order.

The only really supported audio format is MP3. I also added support for AAC, AC3, WMA, ATRAC3 and ATRAC3 plus, however, non of these formats were successfully tested for several reasons. AC3 and WMA are not enabled in the current FFMPEG build which makes reading codec-specific data impossible. We could enable these later if we want to. AAC actually could work but I was not able to get it working in WipeOut HD Fury. My guess is that the game does not support AAC. Finally, I could not find any ATRAC3 (or Plus) music to test with.

This implementation currently only implements parts of cellSearchStartListSearch() and cellSearchStartContentSearchInList(). There are several other functions which are still completely unimplemented and will probably be needed by other games. However, this implementation is a starting-point and is enough for WipeOut and maybe a few other games.

A video which showcases this custom soundtrack support is available here: https://www.youtube.com/watch?v=4nu1OCtONTY

Next steps:
 - Utilize sortKey in cellSearchStartContentSearchInList()
 - Eliminate TODOs
 - Implement the missing other functions
 - Test on more games - I do not own many that support custom soundtracks

Signed-off-by: gladiac1337 <gladiac@gmail.com>

Co-authored-by: Megamouse <studienricky89@googlemail.com>
Co-authored-by: Ani <ani-leo@outlook.com>
Co-authored-by: Ivan <nekotekina@gmail.com>
2020-12-31 22:47:09 +03:00
Florin9doi f1c61067bc Buzz! emulated controller (#9504)
* Buzz emulated controller
Co-authored-by: Florin9doi <Florin9doi@users.noreply.github.com>
Co-authored-by: Ivan <nekotekina@gmail.com>
2020-12-31 21:02:03 +03:00
Nekotekina 8a5620592b Implement util/fifo_mutex.hpp
Prototype. Uses 2 bytes.
Added minor fix to slow_mutex.hpp as well.
2020-12-31 20:07:50 +03:00
Nekotekina 5227e65808 vm: implement vm::atomic_op, fetch_op helpers
Can help to reduce lambda depth hell a little.
2020-12-30 20:11:02 +03:00
Eladash c4c6dc19a5 memory viewer: Implement SPU mode, fix address GOTO 2020-12-30 15:42:56 +03:00
Eladash 7fc26b1fab rsx: Implement Texture LOD Bias addend setting 2020-12-30 15:37:21 +03:00
Eladash c0e121abef rsx: Fix RSXTexture.h spacing 2020-12-30 15:37:21 +03:00
Eladash 7db13fdeff rsx: Move Anisotropic Filter Override to RSX state 2020-12-30 15:37:21 +03:00
JohnHolmesII e68027b464 Format: Update clang format
Old clang format file was extremely broken, causing issues when viewing
code on github, and also featuring stale values.

- Fix indentation information
- Force wrapping on lambdas
2020-12-30 15:24:43 +03:00
JohnHolmesII 220b69058c Docs: Update BUILDING.md 2020-12-30 09:03:24 +03:00
JohnHolmesII 9c3e55787e CMake: Update required Qt version 2020-12-30 09:03:24 +03:00
Malcolm Jestadt c952e99f3e SPU LLVM: Fix edgecase in icelake codegen 2020-12-29 22:01:11 +03:00
Nekotekina 35322b5d14 Remove deprecated _bit accessor from v128
Complicated (a lot of code), confusing (ambiguous)
2020-12-29 21:04:28 +03:00
Nekotekina 6b96807112 Reimplement utils::popcnt64
Implement utils::popcnt128
2020-12-29 15:28:02 +03:00
JohnHolmesII 57621d1c4e Types: Use nullptr over 0 2020-12-29 14:17:34 +03:00
JohnHolmesII e04b2eebc3 Warnings: Silence false warnings about fatal code paths 2020-12-29 14:17:34 +03:00
JohnHolmesII 02b684b810 Warnings: Warnings use kebab case, Mr. Kot 2020-12-29 14:17:34 +03:00
JohnHolmesII 76b1acf99d Warnings: Ensure death functions are all marked noreturn 2020-12-29 14:17:34 +03:00
kd-11 18c120ab9f rsx: Revert an accidental deletion 2020-12-28 21:49:11 +03:00
kd-11 f87dd91b52 rsx: Allow attempted fetch of non-existent surface 2020-12-28 21:49:11 +03:00
RipleyTom 4a8a161a43 Improve skylander portal emulator 2020-12-27 22:20:58 +01:00
Nekotekina e3dec420a2 vm_native.cpp: conditionally define c_madv_free 2020-12-27 12:19:50 +03:00
Nekotekina 1e32311a65 Use MAP_NORESERVE when available in mmap (Linux)
Used in: memory_reserve, memory_decommit (vm_native.cpp)
2020-12-27 10:20:42 +03:00
Marin Baron 92e5bb88e8 Remove std typeinfo 2020-12-27 00:30:16 +03:00
Eladash 66581d115b vm: Fix access violations on super memory, support super memory in vm::get_addr 2020-12-26 17:56:49 +03:00
RipleyTom 4399324955 Disables precompiled headers by default (#9499) 2020-12-25 20:41:49 +00:00
Florin9doi 733f31f90e Allow USB passthrough for THQ uDraw GameTablet 2020-12-25 14:27:24 +03:00
RipleyTom bef2c50b03 Remove bom in Utilities dir 2020-12-25 10:07:40 +03:00
kd-11 a96b4412d3 rsx: Do not rely on program env state, instead, always use program ucode analysis results when doing codegen
- Some things can be present in program env but not ucode state
  e.g A texture can be active and bound in a redirected manner but not actually be used in ucode
  In such a case, only the ucode analysis or decompilation can decide whether to inject decoding routines
2020-12-25 02:39:08 +03:00
kd-11 bee76fc8d1 rsx: Refactor shader codegen and fix shadow sampling on depth-float 2020-12-25 02:39:08 +03:00
kd-11 d9cb1a6319 vk: Fix more spec violations 2020-12-25 02:39:08 +03:00
Nekotekina 567d23d856 Implement util/auto_typemap.hpp
Used in vm::block_t as an example.
2020-12-24 14:55:25 +03:00
Eladash c94a98e15a Fix minor typo 2020-12-23 20:50:33 +03:00
Eladash 72e6e87d82 Fix SPU ELF loader 2020-12-23 20:50:33 +03:00
Eladash 0055d84bd6 Partial revert of 43c87e99b0 2020-12-23 08:25:56 +03:00
Eladash d17d22139e SPU Debugger: Print reservation data 2020-12-23 08:25:56 +03:00
Eladash 87b6284275 memory viewer: Only allow "words" steps in powers of 2 2020-12-23 08:25:56 +03:00
Eladash 2c6b974f24 Fixup memory viewer SPU headers for RawSPU 2020-12-23 08:25:56 +03:00
Eladash 020acc8235 GUI: Rewrite GOTO address tools in debugger tools 2020-12-23 08:25:56 +03:00
Nekotekina a8e0d261b7 types.hpp: more cleanup
Also fix compilation.
2020-12-22 19:08:09 +03:00
Nekotekina 6357b9a04f perf_meter.cpp: register only named threads
Can workaround some possible problems.
2020-12-22 14:32:30 +03:00
Nekotekina 43a58df8a0 Butcher narrow cast a little (don't print value).
Also remove some forward declarations from util/types.hpp
If they don't work properly, it's easier to remove them.
2020-12-22 14:32:30 +03:00
Nekotekina b7bf316c1a Don't randomly include "stdafx.h"
It's file for precompiled headers.
Include what is used, don't rely on transitive includes.
2020-12-22 14:32:30 +03:00
Nekotekina 41ee792f95 MSVC: remove MemLeak build support
There are better memleak detection tools.
1) Requires to guard placement new and external libs
2) Doesn't work thoroughly
2020-12-22 14:32:30 +03:00
Bird Egop 6c1b6c1704 Add PR-BUILD.md and Pull Request Template 2020-12-22 14:31:44 +03:00
Fro Zen acadaeed3a Change skylander variants to use hex 2020-12-22 08:58:36 +01:00
Jan Beich 96bde3df81 atomic.hpp: revert Clang < 11 workaround for u128 2020-12-22 09:00:34 +03:00
Jan Beich 5cb70ddbd5 CMake: bump minimum Clang to 11 2020-12-22 09:00:34 +03:00
Jan Beich b9b9a0465f CI: switch FreeBSD to Clang 11 (similar to e2303f3378) 2020-12-22 09:00:34 +03:00
Nekotekina bd269bccaf types.hpp: remove intrinsic includes
Replace v128 with u128 in some places.
Removed some unused files.
2020-12-21 21:11:25 +03:00
Nekotekina 5f618814f6 atomic.hpp: use u128 as storage for masks/values 2020-12-21 13:51:23 +03:00
Eladash 43c87e99b0 Debugger: Switch from NoThread when the emulation is running
And fix UpdateUnitList() when the emulation is stopped at initial startup.
2020-12-21 13:46:26 +03:00
Eladash 74a09a6338 PPU memory must be exec memory when using debugger's "Next Instruction" feature 2020-12-21 13:46:26 +03:00
Eladash 2b9c407dc3 Mask PC in debugger_frame::keyPressEvent for SPU
SPU only has 256kb of memory, need to work with this.
2020-12-21 13:46:26 +03:00
Eladash 59ed222205 Disasm: read instruction contents only once
Memory is volatile and may be changed by guest threads, ensure the decoded instruction matches with the data.
2020-12-21 13:46:26 +03:00
Eladash 2c06043617 Debugger: correctness fixes and cleanup
* Remove m_current_choice, it's not correct to rely on thread name entry. In extreme corner cases a newly thread can be created, old destroyed with the same entry name. (reoccuring LV2 SPU/PPU ID)
* Remove m_no_thread_selected, can be easily replaced with std::weak_ptr expired() function and is more accurate this way.
* In HandleBreakpointRequest: only remove breakpoint on valid PPU thread and not any thread! also fix potential nullptr deref if thread has recently been destroyed.
2020-12-21 13:46:26 +03:00
Eladash ef884642e4 Cleanup disasm classes a bit 2020-12-21 13:46:26 +03:00
kd-11 e449111c33 vk: Fixup for renderpass issues 2020-12-19 12:58:44 +03:00
Megamouse 066e53da55 minor cleanup 2020-12-19 08:33:53 +01:00
Eladash c74b2cb085 memory viewer: Fix resizing down 2020-12-18 21:00:09 +01:00
Nekotekina eec11bfba9 Move align helpers to util/asm.hpp
Also add some files:
GLTextureCache.cpp
VKTextureCache.cpp
2020-12-18 18:07:42 +03:00
Nekotekina d254a5736b Fix bug with vector arg alignment in BIND_FUNC and callbacks. 2020-12-18 18:07:42 +03:00
Megamouse b655e4aa47 Emu: implement on_exit callback 2020-12-18 16:05:40 +01:00
Nekotekina 1adec3d8e5 Hotfix: Emu.Quit after Emu.Stop 2020-12-18 13:37:14 +03:00
Nekotekina db9b7db531 Cleanup and move sysinfo.h -> util/sysinfo.hpp 2020-12-18 12:55:54 +03:00
Nekotekina 05099e2ae1 Replace uint64_t with u64 2020-12-18 12:23:53 +03:00
Nekotekina 77352a2a86 Replace uint32_t with u32 2020-12-18 12:23:53 +03:00
Nekotekina ae633292c0 Replace int32_t with s32 2020-12-18 12:23:53 +03:00
Nekotekina d6042cf891 Replace uint16_t with u16 2020-12-18 12:23:53 +03:00
Nekotekina 534c63bf57 Replace uint8_t with u8 2020-12-18 12:23:53 +03:00
Nekotekina fb29933d3d Add usz alias for std::size_t 2020-12-18 12:23:53 +03:00
Nekotekina 360c4d1554 Simplify f16 type 2020-12-18 12:23:53 +03:00
Nekotekina 4cfa9b11f3 Move busy_wait() to asm.hpp 2020-12-18 12:23:53 +03:00
Megamouse 908465b274 memory viewer: improve layout and resize 2020-12-18 09:58:12 +01:00
Megamouse a7f10d142e fix warning 2020-12-18 09:58:12 +01:00
Megamouse e855673802 memory viewer: check width and height in image viewer 2020-12-18 09:58:12 +01:00
Megamouse 112ac7bd13 memory viewer: fix RGB Image viewer crash 2020-12-18 09:58:12 +01:00
Megamouse ec7963df3d memory viewer: use enum for color formats 2020-12-18 09:58:12 +01:00
Megamouse 343d006ae2 memory viewer: more cleanup 2020-12-18 09:58:12 +01:00
Megamouse ed8e5498d1 memory viewer: fix horrible overflow that freezes rpcs3 2020-12-18 09:58:12 +01:00
Megamouse 3cfead4ca6 memory viewer cleanup 2020-12-18 09:58:12 +01:00
Eladash c8947eee6a GUI: Make memory viewer address edit accept 0x/0X prefixes
Max length is 10, added regexp validator accordinally.
2020-12-17 22:57:13 +01:00
Eladash 6c1ca7d797 GUI: Polish the memory viewer 2020-12-17 22:57:13 +01:00
Eladash 2172974db9 Link the memory viewer with the debugger 2020-12-17 19:36:35 +01:00
Eladash ba03df8511 GUI: Improve PS3 decryption tool 2020-12-17 18:49:04 +01:00
kd-11 fb47d1f788 vk: Register ampere GPU PCI IDs 2020-12-17 19:56:48 +03:00
Nekotekina 3c86e14ea4 Fix hexadecimal line numbers in error reports 2020-12-17 17:00:06 +03:00
Nekotekina c16fb61bea fixed_typemap.hpp: Fix assignment operator for g_ptr
Maybe RPCS3 hangs will finally be gone.
2020-12-17 16:47:25 +03:00
Nekotekina 2acead357b Update LLVM commit (minor fixups) 2020-12-17 16:47:25 +03:00
kd-11 235db57f0e rsx: Do not reset vertex program texture mask when updating ucode analysis
- Fixes incorrect texture type detection in some games after program env/ucode separation
2020-12-17 09:36:20 +03:00
kd-11 cfbde005fb vk: Force ampere GPUs to use the slower but spec-compliant depth-color resize route
- TODO: More investigation and optimizations
2020-12-17 09:36:20 +03:00
kd-11 0a865bd9dc vk: Workaround for validation layers bug 2020-12-17 09:36:20 +03:00
Nekotekina 6b3f722ff0 Hotfix: useless error 2020-12-16 11:57:29 +03:00
Fro Zen 3dbecada4e Almost all Skylander variants (#9443)
* Update skylander_dialog.cpp

* Fix formatting, sorted

* Support for skylanders variant

* Remove duplicate Legendary Hand of Fate

* Removed accidental Series 2 Dark Spyro

There is no series 2 dark spyro, also im removing these as im finding them so sorry if theres tons of commits

* Add LightCore Hex

* Remove Vehicle tag

* Add Big Bang Trigger Happy

Co-authored-by: RipleyTom <RipleyTom@users.noreply.github.com>
2020-12-16 11:02:59 +03:00
Megamouse d21f87af5d Fix unresponsive UI during SPU compilation 2020-12-16 11:01:51 +03:00
Megamouse 0bfec59af8 Fix stop during shader compilation 2020-12-16 11:01:51 +03:00
kd-11 035a76f26d Fix build 2020-12-16 10:10:06 +03:00
kd-11 42f4e831a2 vk: Clean up some leftovers from shader decompiler rewrites 2020-12-16 10:10:06 +03:00
kd-11 d3686dbb75 rsx: Add some texture upload statistics to the texture cache 2020-12-16 10:10:06 +03:00
kd-11 fb1c790350 rsx: Make debug overlay dynamic 2020-12-16 10:10:06 +03:00
kd-11 0ef5743261 rsx: Fix sampler descriptor updates for framebuffer resources
- Each desc manages its own lifetime now instead of relying on global timestamp check
- Fixes situation where same object remains active without update for long
2020-12-16 10:10:06 +03:00
Nekotekina e82bef425f vm: fix warnings and add narrow cast for u64 ptrs 2020-12-15 20:10:16 +03:00
Nekotekina 24c246a9f6 Fix potential thread_pool crash on exit
Minor issue.
2020-12-15 20:01:26 +03:00
Nekotekina e39348ad96 Make lf_queue<> compatible with atomic_wait 2020-12-15 19:19:36 +03:00
Nekotekina ca5f0444bf shared_ptr.hpp: add wait support for atomic_ptr<>
As well as default mask and value transformation function overload.
2020-12-15 12:52:21 +03:00
Nekotekina 4a883ba6ea atomic.hpp: use SFINAE for waitable atomic detection
Add default_mask<> variable.
Refactor get_value<>().
2020-12-15 12:50:44 +03:00
Eladash bfe1a8673a PPU: Allow HLE execution from pure instruction decoder type interpreter 2020-12-15 11:18:51 +03:00
Eladash 0445ef393f FW SPRX install: Fix IDM ID's leak 2020-12-15 11:16:45 +03:00
Eladash 7eb16e13bb PRX loader: Fix libfs_155.sprx loading
Fix relocations' segments referencing when there are "empty" (memsize=0) LOAD segments.
2020-12-15 11:16:45 +03:00
Megamouse 03ad5c6830 Salvaging code (#9432)
* Minor input refactoring

* fix sys_config_unregister_io_error_listener log message

* Remove unused variables in RepaintTextColors

Co-authored-by: GermanAizek <GermanAizek@yandex.ru>
2020-12-14 14:33:43 +01:00
Megamouse ab23e5ca0e Minor tooltip grammar fix 2020-12-14 09:01:07 +03:00
Megamouse 35ecd00559 Remove BOM from new files 2020-12-14 09:01:07 +03:00
Eladash e5603fec1e Firmware libraries settings overhaul 2020-12-13 21:52:24 +03:00
Nekotekina e321765c54 Split BEType.h to util/v128.hpp and util/to_endian.hpp 2020-12-13 16:34:45 +03:00
Nekotekina 62fdcf50ea vm: initialize g_pages at vm::init
Can reduce compile time/overhead.
2020-12-13 15:39:36 +03:00
Nekotekina 09d293592e shared_ptr.hpp: fix is_same_ptr<>() trait
Implemented as constexpr function.
2020-12-13 15:39:36 +03:00
kd-11 f83c2f0b6b rsx: Restructure and simplify some header include chains 2020-12-13 15:38:35 +03:00
kd-11 d775c8dc73 rsx: Move shader analysis+prefetch to the end of the draw call 2020-12-13 15:38:35 +03:00
Fro Zen 8e07b19bc7 Add variant support for Skylanders (#9424)
* Update skylander_dialog.cpp

Co-authored-by: RipleyTom <RipleyTom@users.noreply.github.com>
2020-12-13 14:30:38 +03:00
Luke Barr cb8ef46ec7 Initial DualSense Support (#9308)
* Initial DualSense Support

* Add Vibration Support

* Add CRC32 Validation to Incoming Bluetooth Packets
Cleanup report sizes

* Consistency, remove button comments, add two buttons.

Co-authored-by: Ani <ani-leo@outlook.com>
2020-12-13 00:00:45 +01:00
Fro Zen ee814cfd0c Update skylander_dialog.cpp (#9419) 2020-12-12 19:16:15 +03:00
Nekotekina a6a5292cd7 Use uptr (std::uintptr_t alias) 2020-12-12 16:29:55 +03:00
Nekotekina b59f142d4e Move types.h to util/types.hpp 2020-12-12 15:12:01 +03:00
Nekotekina 666a18f5e5 Remove ceil2/floor2 from types.h 2020-12-12 15:12:01 +03:00
Nekotekina dff4392c10 Move error_code to ErrorCodes.h 2020-12-12 15:12:01 +03:00
Nekotekina b09b7c1184 Remove any_pod<> from types.h
Add simplified any32 to GCM.h
Add simplified cmd64 to PPUThread.h
2020-12-12 13:12:39 +03:00
Nekotekina 6e05dcadb6 Reduce std::numeric_limits dependency
Please, stop pretending...
You need these templates for generic code.
In other words, in another templates.
Stop increasing compilation time for no reason.
2020-12-12 12:35:18 +03:00
Nekotekina bc7acf9f7a RSX: remove overly long integer sequence (opcode_list)
Convert to constexpr array and move to gcm_printing.cpp
2020-12-12 11:38:35 +03:00
Nekotekina cb19316a17 Fix u128 constructors (MSVC) 2020-12-12 09:54:39 +03:00
Nekotekina 33c3977036 endian.hpp: minor simplification
And stop pretending...
2020-12-11 22:00:26 +03:00
Nekotekina 7a015b6fc0 VKMemAlloc.cpp: use shared_mutex in vk_mem_alloc.h
Because it allows to use custom implementation.
Also fix compilation.
2020-12-11 19:05:11 +03:00
Nekotekina aa3aef4beb std::chrono cleanup: always use steady_clock 2020-12-11 19:01:56 +03:00
Nekotekina 12a48fc6d1 Fixup for fs::file::read 2020-12-11 07:33:15 +03:00
Nekotekina 72284b4530 Use atomic_t<> in VKMemAlloc 2020-12-10 18:58:11 +03:00
Nekotekina 65c04e4ddd Remove constexpr from ppu/spu decoders.
We don't need them at compile time (yet).
But can reduce compile time and complexity.
2020-12-10 15:06:01 +03:00
Nekotekina b382d3b3e9 Remove ASSUME macro
It's dangerous and sometimes bluntly misused feature.
Its optimization potential is near-zero.
2020-12-10 14:08:02 +03:00
Nekotekina 61b882b2a6 Always print system error code on 'throwing' errors.
Print system error code in src_loc fmt.
Error code may be irrelevant though.
2020-12-10 12:43:49 +03:00
Nekotekina 36c8654fb8 Remove HERE macro
Some cleanup.
Add location to some functions.
2020-12-10 12:30:22 +03:00
kd-11 d25c401aec vk: Validate image creation inputs
- Should avoid things like res scaling breaking when very large scaling is in use
2020-12-09 21:30:08 +03:00
kd-11 aac874a842 vk: Add even more D32_SFLOAT missing locations 2020-12-09 21:30:08 +03:00
Nekotekina 5d934c8759 Improve narrow() and size32() with src_loc detection 2020-12-09 16:26:20 +03:00
Nekotekina e055d16b2c Replace verify() with ensure() with auto src location.
Expression ensure(x) returns x.
Using comma operator removed.
2020-12-09 15:43:38 +03:00
Nekotekina 38745e5782 SPU ASMJIT: fixup mfence replacement 2020-12-09 11:15:40 +03:00
RipleyTom d0c271e534 Simplify g_pages
This was done because otherwise msvc runs out of heap space on azure.
2020-12-09 11:15:08 +03:00
RipleyTom 33635c5723 Set msvc toolkit back to mainline 2020-12-09 11:15:08 +03:00
kd-11 f8d2830ac7 vk: Properly register D32_SFLOAT as a depth-stencil format (#9396) 2020-12-09 02:06:27 +00:00
Megamouse a7e5c255b4 Qt 5.15.2 (#8867)
* Qt15: replace deprecated stuff

* Use Qt 5.15.1

* Move windows to Qt 5.15.2

* Move Ubuntu to Qt 5.15.2
2020-12-08 22:22:08 +01:00
Nekotekina 062c605eb1 atomic.hpp: fixup (rsp addressing) 2020-12-08 08:51:27 +03:00
Eladash 2602be426f Allow emulation to work without firmware (#9367)
* Allow emulation to work without firmware
* Fix HLE prx path detection.
* Fix manual list loading bugs.
* Fix HLE gcm
* GUI: Fix fonts search
* GUI: Hardcode sprx list
Do not depend on /dev_flash/sys/external/ contents.
2020-12-07 20:10:34 +03:00
RipleyTom 51dcb4a79d Remove bom from .hpp files 2020-12-07 20:03:44 +03:00
Nekotekina 24e4e329ed atomic.hpp: add atomic_t<bool> specialization
May be required in future, plus adds/hides some methods.
2020-12-07 17:13:12 +03:00
Nekotekina eb66302907 atomic.hpp: replace std::atomic with atomic_t
Dual dependency is nothing good.
2020-12-07 17:13:12 +03:00
Nekotekina b16cc618b5 atomic.hpp: add some features and optimizations
Add atomic_t<>::observe() (relaxed load)
Add atomic_fence_XXX() (barrier functions)
Get rid of MFENCE instruction, replace with no-op LOCK OR on stack.
Remove <atomic> dependence from stdafx.h and relevant headers.
2020-12-07 17:13:12 +03:00
Nekotekina 77aa9e58f2 shared_ptr.hpp: add trivial conversion for shared/single types
These conversions don't exist in std::shared_ptr-alike types.
But I don't want to bother with == operators until we have proper C++20.
Removed trivial conversion for atomic_ptr because it's heavyweight.
2020-12-07 15:33:28 +03:00
kd-11 3a0b3a85a5 rsx: Separate program environment state from program ucode state
- Allows for conservative texture uploads
- Allows to update a program object without running full ucode analysis for no reason
2020-12-07 00:45:27 +03:00
Eladash 15a12afe25 Debugger: Implement code flow tracking 2020-12-06 15:32:13 +03:00
Eladash 427cf91447 Debugger: rewrite GetPc() 2020-12-06 15:32:13 +03:00
RipleyTom af8c661a64 Remove BOM markers 2020-12-06 15:30:12 +03:00
RipleyTom 7b694ebeb4 Set default to utf-8 for MSVC 2020-12-06 15:30:12 +03:00
Nekotekina d1e7837422 atomic_t: cleanup type requirements
Add C++17 requirements.
Remove alignment requirements (auto-align type).
What's missing is to detect padding and forbid it.
2020-12-04 19:11:36 +03:00
Nekotekina 8efc22bd45 atomic.hpp: simplify and unify bit test instructions
Also make them available on all platform.
Rename some rare methods.
2020-12-04 14:33:38 +03:00
Nekotekina 983439076b shared_ptr.hpp: fixups and updates
Fix atomic_ptr load() edge case.
Implement atomic_ptr::peek_op() to make possible to reduce load() overhead.
Implement atomic_ptr::compare_exchange() and friends.
Implement null_ptr constant, remove nullptr_t assignment/construction.
2020-12-04 14:10:53 +03:00
Nekotekina 019f566239 atomic.cpp: more phase splitting in notify_all() 2020-12-04 14:10:53 +03:00
Nekotekina 332410d20b shared_ptr.hpp: improve atomic_ptr methods 2020-12-04 14:10:53 +03:00
JoãoPaulo c2a85bde08 Update FW 4.87 Latest Version (#9366)
Updates the latest FW version according to: https://www.playstation.com/en-us/support/system-updates/ps3/
List of changes:
・ Updated blu-ray keys for new movie releases
・ Minor security fix
2020-12-03 18:16:38 +01:00
Nekotekina 13a0b88755 atomic.cpp: improve hashtable access
Simplified, tried to use all ptr bits.
Try to prevent self-collisions (bug).
Hashtable size doubled (to 8 MiB).
2020-12-01 10:19:31 +03:00
Nekotekina 32f39fec1c Make cpu_counter::remove() async
Remove both mutex and assertion from it.
2020-12-01 10:18:41 +03:00
Nekotekina cad3a6c547 sceNp.cpp: fix some UTF-8 string mismatch 2020-11-30 03:21:34 +03:00
kd-11 2aa5c437e8 rsx: Fix upscaled image reconstruction
- Base the upscaling on the real source and not the "attr" parameter.
- In case of reconstruction, the source is much larger than the subslice in "attr"
2020-11-30 01:20:17 +03:00
kd-11 67f48ce21c rsx: Fix uncaught depth-func changes
- Depth func of always or never usually disqualifies depth testing.
  Invalidate contested surfaces when depth func is changed.
2020-11-30 00:46:36 +03:00
kd-11 845a7d9968 Fix RSX replay thread lifecycle 2020-11-29 22:39:52 +03:00
Dylan Fenn 924774d3ef Add missing Fedora dependancy to BUILDING.md 2020-11-29 21:41:03 +03:00
Nekotekina e0635cf65c Remove unneeded non-ASCII character (unedat.cpp) 2020-11-29 16:18:22 +03:00
Nekotekina 3b8e3a9714 stdafx.h: remove BOM from custom included headers
Also add warnings about adding them.
2020-11-29 15:35:05 +03:00
Nekotekina 2bee096246 Try to set 2-3 GiB working space and show error if it's failed (Windows) 2020-11-27 14:49:07 +03:00
Nekotekina 872655369a shared_ptr.hpp: fix critical bugs
Fix array initialization.
Fix reference counting.
Fix offset to refctr.
Add some features.
2020-11-27 14:32:41 +03:00
Nekotekina 0892758994 Minor debugging enhancement
Use raise(SIGTRAP) in failed SIGSEGV handling and return.
2020-11-26 20:11:26 +03:00
Nekotekina 22a24446c1 Threads: fix minor race
Has already been in "fixed" state in past...
2020-11-26 20:11:26 +03:00
Nekotekina b5d498ffda Homebrew atomic_ptr rewritten (util/shared_ptr.hpp)
It's analogous to C++20 atomic std::shared_ptr

The following things brought into global namespace:
single_ptr
shared_ptr
atomic_ptr
make_single
2020-11-26 20:11:26 +03:00
Nekotekina bd90e3e37f atomic.cpp: shrink and simplify main hashtable
Reduce collision detection to 1 or 0 for now.
I think it should be offloaded to notifiers.
2020-11-26 20:11:26 +03:00
Nekotekina 8b6d615aa6 atomic.hpp: remove/deprecate incomplete notify features
Notification with "phantom value" could be useful in theory.
As an alternative way of sending signal from the notifier.
But current implementation is just useless.
Also fixed slow_mutex (not used anywhere).
2020-11-26 06:31:36 +03:00
Megamouse 9e352da052 Handle some undefined behavior regarding null pads 2020-11-26 00:45:49 +01:00
Nekotekina ca9898e838 JIT: increase likeliness of allocating 2M large pages
On top of enabled transparent hugepages hint (Linux).
2020-11-25 10:41:17 +03:00
Nekotekina 95b8467a76 perf_meter.hpp: move logic to noinline function
May improve performance if perf meter is disabled.
2020-11-25 10:41:17 +03:00
Nekotekina 2b674d4d8c utils::shm: allow 2M hugepages on demand 2020-11-25 10:41:17 +03:00
Nekotekina 487b572aa6 Linux: remove assertions on MADV_HUGEPAGE
It's a hint and is allowed to fail.
2020-11-25 10:41:17 +03:00
Nekotekina 600c0ea5ba atomic.cpp: fix windows/std path
Always check condition after rearming internal semaphore.
2020-11-25 10:41:17 +03:00
Nekotekina 00e64920c8 Implement "slow mutex" without spin-waiting.
Benefits: only 1 byte.
Testing atomic wait.
2020-11-25 10:41:17 +03:00
Megamouse 9efedbe76a Minor changes related to Emu.Stop() 2020-11-25 00:11:07 +01:00
Nekotekina d8e9382573 asm.hpp: constexpr refactoring
Removed asm (what an irony), made many functions constexpr.
Removed some unused function, readding them should be trivial.
2020-11-24 13:20:40 +03:00
Nekotekina ab248e170c vm_native.cpp: add MADV_HUGEPAGE
It enables Transparend Huge Pages for some regions on Linux.
Although it can't be actively useful, it seems to do something.
Maybe it's even harmful for recompilers.
2020-11-24 12:31:11 +03:00
Nekotekina 27097cbcfe atomic.hpp: alter atomic_storage<>::store a bit
Always fallback to exchange. May improve codegen on gcc.
2020-11-24 12:31:11 +03:00
Nekotekina 43952e18e2 Implement prefetch_write() and prefetch_exec() wrappers
Do some refactoring to prefetch_read() in util/asm.hpp as well.
Make all these function constexpr because they are no-ops.
2020-11-24 12:31:11 +03:00
Megamouse 5076da8f77 Fix auto exit
- Don't quit on stop if force boot was set
- Don't stop the emulator on gs_frame close when it was already stopped. This would remove the force boot flag by mistake.
2020-11-24 11:17:03 +03:00
kd-11 8228a4adcd gl: Disable depth test before rendering text to the backbuffer which does have a Z buffer 2020-11-24 11:10:43 +03:00
Nekotekina 721883f64e Azure: attempt to produce clang artifact 2020-11-24 08:11:45 +03:00
Nekotekina b55c759f71 Remove any mentions of scam CI 2020-11-24 08:11:45 +03:00
Eladash 3f028fbb83 Fix SPU LS MMIO 2020-11-24 03:44:30 +03:00
Nekotekina f0cba1371c vm: adjustments
Increase max range lock size (less than 512 MiB)
Remove "range_executable" flag, make it reserved.
2020-11-24 01:09:04 +03:00
Nekotekina 14fa96fdef atomic.cpp: don't use empty notify callback
Instead, allow setting it to null and check for null.
Similar could be done for wait cb, but it's set for all named threads.
2020-11-24 01:09:04 +03:00
Nekotekina b954a41f2a Threads: minor simplification 2020-11-24 01:09:04 +03:00
kd-11 f1c65dcefc vk: Improve support for RDNA
- Add support for RDNA2
- Add RDNA MSAA workaround
2020-11-23 19:20:00 +03:00
Nekotekina d4c17ecda5 Simplify communication with thread pool
Add "entry_point" member to "thread_base".
Don't use "m_thread" to exchange values.
2020-11-23 11:32:34 +03:00
Nekotekina a4458e2c8c Clean thread pool at exit.
Execute TLS destructors.
Test atomic wait list.
2020-11-23 10:20:42 +03:00
Nekotekina 16cc88dd0e atomic.hpp: fix atomic_wait::list regression
Typo-regressions. Also improve static asserts.
2020-11-23 09:26:25 +03:00
Nekotekina 280f5f0b54 atomic.hpp: redefine op::ne to actually mean "not equal"
WTF is "native endianness", it's native by default.
2020-11-23 09:24:16 +03:00
Nekotekina e38eaa7cd7 Remove old travis badge (kill it with fire) 2020-11-23 09:22:51 +03:00
Zion Nimchuk a27bd2275c Pushing master AppImage Artifacts to GitHub Releases via Azure 2020-11-23 06:50:27 +03:00
Nekotekina 7d00c69a4f Attempt 2: Try to make Azure push linux builds 2020-11-22 19:24:54 +03:00
Nekotekina a2c189b45a Azure: try to deploy GCC artifact (upload to github) 2020-11-22 18:29:46 +03:00
Nekotekina 41320688b7 Removed .travis.yml
Non-functional CI
2020-11-22 17:03:35 +03:00
Nekotekina f85c8584b0 Attempt to fix #9316 2020-11-22 12:57:50 +03:00
Nekotekina 6cf50f8f6c Second attempt to fix hanging RPCS3 process
Now fix exit logic a bit.
Remove Init() call from Stop().
Remove Stop() call from Quit().
2020-11-22 12:45:19 +03:00
Nekotekina d70ab11477 atomic.cpp: remove redundant constexpr
Static initialization is all-zeros anyway.
But constexpr was killing my intellisense.
And probably also affected compile time.

Also make some internal structures hidden ("static").
2020-11-22 12:07:49 +03:00
kd-11 cab4c78b7b rsx: Some shader compiler threads tuning
- Allow more threads for wide CPUs
- Simplify 'auto' selection a bit
2020-11-21 20:43:15 +03:00
kd-11 14358d5e84 qt: Add shader compiler threads to GUI 2020-11-21 20:43:15 +03:00
kd-11 7553429130 gl: Thread shader source compilation dispatch
- glCompileShader is in itself much slower than anticipated
2020-11-21 20:43:15 +03:00
kd-11 3ddfa288cf rsx: Use multithreaded shader compiler backend 2020-11-21 20:43:15 +03:00
Nekotekina e89a568765 Attempt to fix Emu.Quit()
There was some kind of "initialization order fiasco" of g_fxo.
Not only should it be used after main, but also destroyed before exit.
2020-11-21 18:27:16 +03:00
Nekotekina 71f1021648 Fix thread pool entry point and get_cycles()
Fix possible race between thread handle availability.
Don't treat zero thread as invalid one.
Now entry point is full is assembly.
Attempt to fix #9282
Also fix some TLS.
2020-11-21 17:18:42 +03:00
Nekotekina 60cff6f3d4 Attempt to fix #9271 2020-11-21 07:09:48 +03:00
Nekotekina 5f010c2f4c atomic.cpp: optimize "cond" allocation with TLS
Billions of events can reduce to thousands, saving CPU time a few s.
Only 4 slots are available (arbitrarily), and only 1 is usually used.
Other slots are used only for waiting on multiple atomics.
2020-11-20 19:13:22 +03:00
Nekotekina c0f3d1f06d Basic constexpr support for u128 (MSVC)
Added explicit conversion op to u64.
Added constexpr path for +,-,>>,<< ops.
Make almost all methods constexpr.
Removed a lot of redundancy.
2020-11-20 15:04:17 +03:00
Nekotekina 6c18e00977 atomic.cpp: use deterministic "cond" allocation
Takes ~80 ns instead of ~40 ns, same about deallocation.
Loops don't exist here, only 4-level semaphore tree.
Worst case only happens with concurrence, not from looping.
This optimization is not really necessary at current state of RPCS3.
This is more like to test C++ compilers and MSVC u128 implementation.
2020-11-20 15:04:17 +03:00
Nekotekina 72ac1aa537 atomic.cpp: use some actual hash for hashtable (std::minstd_rand)
Should only take about 5ns for initialization.
Should also make collisions almost impossible.

I also suspect I fixed some bad bug in process...
2020-11-20 15:04:17 +03:00
Nekotekina 5bcaa25c02 CPU: remove descheduled threads from suspend_all list 2020-11-20 13:53:34 +03:00
Eladash 85880ffded SPU: Log STOP full opcode (#9292)
Co-authored-by: Ani <ani-leo@outlook.com>
2020-11-20 13:53:16 +03:00
Megamouse 5b207c3b95 hotfix for infinite loop when booting game data 2020-11-19 23:53:10 +01:00
Megamouse 3087f15dd8 Update disc boot detection and hope it works 2020-11-19 21:55:06 +01:00
Nekotekina 36f1193497 Fix u128 type on MSVC (subtraction, minus)
All subtraction operations were broken.
2020-11-19 16:38:06 +03:00
Nekotekina 292af1e4cd CPU: use u128 in bit counter
Apparently, u64 was not enough.
2020-11-19 16:05:08 +03:00
Nekotekina d4d5dc99f3 Fix perf_meter<> after adding thread pool.
Print and reset sorted information after emulation stop/pause.
Print useless average value.
2020-11-19 14:44:58 +03:00
Nekotekina 3e1344e4e4 vm.cpp: minor optimization for filling stack guards
Use REP STOSQ on all compilers.
2020-11-19 14:44:58 +03:00
Nekotekina 6d37bc62a5 CPU: remove cpu_counter from g_fxo
Convert it to a namespace, simplify add/remove functions.
Don't add() threads just creates, they are trapped in check_state() anyway.
Don't add() threads which are leaving check_state() because stopped.
2020-11-19 09:46:22 +03:00
Nekotekina e9f7c100a0 CPU: update suspend interface (dummy) 2020-11-18 19:15:56 +03:00
Nekotekina 190676c982 CPU: Fix g_suspend_counter waiting logic 2020-11-18 14:38:01 +03:00
Eladash 28cbba5a7d SPU LLVM: fix AND instruction family (#9290)
Incorrect immediate test (looks like copypasta)
2020-11-18 14:36:26 +03:00
kd-11 0e7a705254 rsx: Resolution scaling overhaul
- Enforce square pixels instead of per-axis scaling
2020-11-18 09:29:34 +03:00
Nekotekina 68931b4c43 Debugger: fill stack guard with STACKGRD 2020-11-17 16:32:59 +03:00
Nekotekina a4e28df9cf Update hidapi 2020-11-17 15:40:09 +03:00
Nekotekina 65c81c5e83 Fix memory viewer for SPU LS 2020-11-17 15:22:04 +03:00
Nekotekina ccd0d2046d SPU: increase max SPU count
According to max SPU TG count.
2020-11-17 15:22:04 +03:00
Nekotekina 0fec99e75b SPU: absolutely unacceptable hack for SPU LS
Make normal threads inaccessible in PS3 memory.
2020-11-17 15:22:04 +03:00
Nekotekina f8d1f070f5 sys_memory: HORRIBLE HACK for sys_memory_get_page_attributes 2020-11-17 15:22:04 +03:00
Nekotekina 3dd48a24ce atomic.cpp: remove tiny redundancy 2020-11-17 15:22:04 +03:00
Nekotekina 984e97cbdc Potential fix for Linux compilation 2020-11-17 15:22:04 +03:00
Eladash 50ea1a12c9 Debugger: Fix scrolling in first registers panel 2020-11-17 09:39:39 +01:00
Eladash 992a372fc7 cellGame fixes 2020-11-17 09:04:35 +01:00
Nekotekina d789250976 Add thread_ctrl::get_thread_stack
Returns addr and size of current thread's stack.
2020-11-17 05:33:46 +03:00
Nekotekina d7e1cf7dd2 vm: respect initial protection for allocation mapping
Unused yet.
2020-11-17 05:33:46 +03:00
Nekotekina ea5f5aea5f vm: memory locking rewritten
Added vm::lock_sudo method (wrapper for utils::memory_lock).
Put locking outside of vm::g_mutex scope.
Prelock sudo memory for RSX, vm::stack, vm::main.
Prelock sudo memory for shared memory objects.
Don't check for TSX path.
2020-11-16 12:46:15 +03:00
Nekotekina eaf0bbc108 SPU: don't allocate SPU LS in vm::main
Create its own shared memory object.
Use vm::spu to allocate all SPU types.
Use vm::writer_lock for shm::map_critical.
2020-11-16 12:46:15 +03:00
Eladash b1710bb712 SPU Debugger: Implement float registers view + General debugger fixes (#9265)
* SPU Debugger: Fix try_get_insert_mask_info
* Debugger: Always update thread state on context's data change
No longer needing to press on thread's instructions for actions to work!
2020-11-15 08:45:28 +03:00
Nekotekina dfae7bd073 SPU: Fix some stat printing 2020-11-15 04:41:16 +03:00
Nekotekina 333fe9a561 atomic.cpp: fix notification on windows 2020-11-15 04:40:44 +03:00
Nekotekina badb3dc2dd atomic.cpp/threads: remove old wait callback
Add new wait callback which simply collects statistics.
Shift workarounds towards actual problem detection.
2020-11-14 18:16:27 +03:00
Nekotekina 3ac819ee70 atomic.cpp: fix waiting on multiple variables
Silly bugs are so silly...
2020-11-14 17:25:02 +03:00
Nekotekina 00f877e812 atomic.cpp: fix rare overload scenario
If slot allocation fails, increase reference counter in every slot.
This prevents search routine from "losing" some slots.
2020-11-14 13:56:23 +03:00
Nekotekina 1e269751bf Temporarily disable memory locking if TSX is not used
It's a very heavy operation that could cause some problem under mutex lock.
2020-11-14 11:12:58 +03:00
Nekotekina 5b69eda39a Fix suspend_all bug (TSX, TSX-FA)
Could cause freezes.
2020-11-14 10:56:05 +03:00
Nekotekina 71ca413067 Don't add lonely cpu_flag::memory on TSX path (bug) 2020-11-14 09:03:33 +03:00
Nekotekina 0c7f9458c0 Fix thread pool resource management.
Make sure no tail call happens (change ret address to a trampoline).
Make sure thread handles don't leak if the pool is full.
2020-11-13 17:17:45 +03:00
Nekotekina ab365fe494 Fixed thread pool a bit
Use 128-bit allocator instead of queue.
When pool is full (128), threads just terminate as before.
2020-11-13 13:32:44 +03:00
Nekotekina e48f160a29 atomic.cpp: continuation of fixing all-ones masks
Also added missing const noexcept.
2020-11-13 12:40:02 +03:00
Nekotekina cfda4d0ade atomic.cpp: optimize raw_notify() for unspecified pointer mode
Remove unnecessary optimization from cond_alloc().
Optimistic case was absolutely dominating anyway.
Although the whole function is a dirty hack.
Now scanning through all threads is faster.
2020-11-13 07:05:33 +03:00
RipleyTom debfae06a8 Improve disconnected state handling of dns queries 2020-11-13 07:05:06 +03:00
RipleyTom e6f2f8ad0d Add some error checking in sceNp2.cpp 2020-11-13 05:28:00 +03:00
Nekotekina 67785a918c Implement simple thread pool 2020-11-13 03:32:24 +03:00
Nekotekina 50d80c64fa Add .gdbinit config file
Set to ignore SIGSEGV and SIGPIPE signals.
2020-11-12 23:43:38 +03:00
RipleyTom 1378645413 Adds SIGPIPE to ignored exceptions(unix) 2020-11-12 07:08:59 +03:00
Nekotekina 3888b0429c atomic.cpp: print some stats on stop 2020-11-12 05:52:22 +03:00
Nekotekina 70761a4ef0 atomic.cpp: fix notification bug from few commits before
Make sure forced notification ignores mask comparison.
Also fix masks provided by smaller types to correct ones.
2020-11-12 05:01:44 +03:00
Nekotekina e37df998e9 atomic.cpp: minor optimization
Silly MSVC emits unnecessary initialize-on-first-use code guards.
Didn't check other compiler. But workaround just works anyway.
2020-11-12 03:41:19 +03:00
Nekotekina c30cdfb3a7 atomic.cpp: merge more atomic variables for simplicity
Compress 16-bit ref counter and two 48+64 bit slot allocators.
This allowed to remove some weird unnecessary logic paths.
Adjust hashtable size to keep it the same.
2020-11-12 03:39:05 +03:00
Nekotekina 350b704cd7 atomic.cpp: combine two atomics (ref ctr and wait ptr)
Should fit into cache line perfectly.
Also makes ptr check more robust.
2020-11-12 01:06:12 +03:00
Nekotekina ad013d59f4 atomic.cpp: don't load actual memory on empty mask
It's not an optimization. It just allows some tricks safely.
2020-11-11 23:59:09 +03:00
Nekotekina d391133524 atomic.cpp: minor notification improvement
Check mask before locking the reference.
Can help to not bother non-eligible waiters.
2020-11-11 23:51:41 +03:00
Nekotekina 4b823469f7 atomic.cpp: restore notify_all() behaviour
Restore batch notification with non-blocking attempts.
2020-11-11 22:43:13 +03:00
Nekotekina 7cd1e767be atomic.cpp: implement some atomic wait operations.
Instead of plain waiting while equal to some value,
it can be something like less, or greater, or even bitcount.
But it's a draft and untested. Hopefully doesn't break anything.
2020-11-11 20:46:37 +03:00
Eladash 829a697c39 Fix vm::check_addr calls in Thread.cpp 2020-11-11 17:40:46 +03:00
Eladash fefab50e06 Fix vm::range_lock, imporve vm::check_addr 2020-11-11 10:30:09 +03:00
Eladash 6e27ab60ca Registers Editor: Implement SPU/PPU register value broadcast 2020-11-11 10:27:45 +03:00
Eladash 74274f6d77 Debugger: Improve SPU/PPU vector registers 2020-11-11 10:27:45 +03:00
RipleyTom 908b2703f3 Fix missing controller mapping 2020-11-11 07:16:45 +03:00
Nekotekina c047ab6147 atomic.cpp: waitable atomics got brutally rewritten
Hashtable increased and flatten, tree-alike extensions removed.
Some things simplified, so it can actually decrease perf a bit.
But most platforms shouldn't be affected.
Removed limit of 56 waiters per pointer.
Real limit now is about 65535.
2020-11-11 05:35:27 +03:00
Eladash 52fa69d93d SPU Debugger: Improve registers panel 2020-11-10 22:51:52 +03:00
RipleyTom a83df01bfd rpcn 0.3.5 (#9227) 2020-11-10 08:55:49 +00:00
Eladash b32d989a10 Fix PPU stack contents on allocation 2020-11-10 06:30:35 +03:00
Nekotekina d1ee7c651f Make memory locking optional (mlock, VirtualLock).
Fix desired locking operation (to fix "sudo" memory).
It was discovered that some systems have outdated configuration.
With too tight limit, it's almost impossible to lock anything in memory.
2020-11-10 06:05:37 +03:00
Nekotekina dcbe8ef5f4 Import VirtualAlloc2 if available (Win10+)
Import MapViewOfFile3 as well.
Unused, this crap is tricky.
2020-11-10 03:04:38 +03:00
Nekotekina bd5253047b Improve DYNAMIC_IMPORT
Don't call get_proc_address every time if if failed.
Also rename Utilities/dynamic_library.h to util/dyn_lib.hpp
2020-11-10 01:44:31 +03:00
Nekotekina cdaa8cb5c4 CPU: Improve suspend_all g_suspend_counter handling
Increase in two stages, giving more chances to use it.
Second stage is when all wait flags have been seen.
2020-11-09 23:54:36 +03:00
Nekotekina 083397a555 vm: lock memory under "sudo" addr
Remove memory touching from transactions.
2020-11-09 23:54:36 +03:00
Nekotekina e98eb4659e Implement utils::memory_lock 2020-11-09 22:57:36 +03:00
Nekotekina d1988d384c vm: remove unnecessary memset() on stop 2020-11-09 22:57:36 +03:00
Nekotekina bc61835d97 CPU: use unsigned (u8) priority in suspend_all 2020-11-09 22:57:36 +03:00
RipleyTom 8a50880613 Fix path not being saved on install pkgs 2020-11-09 14:23:54 +03:00
Nekotekina b05d12df0e Hotfix for shm->map_self()
Make sure mmap returns 64K-aligned results, as on Windows.
2020-11-08 22:15:59 +03:00
Nekotekina 733b46d51a sys_semaphore: add state check to sys_semaphore_get_value
Also to sys_semaphore_create, although we don't do it.
2020-11-08 19:03:41 +03:00
Nekotekina 8bc9868c1f SPU/vm: Improve vm::range_lock a bit
Use some prefetching
Use optimistic locking
2020-11-08 17:23:17 +03:00
Nekotekina 3507cd0a37 SPU: improve spu_thread::reservation_check
Use optimistic locking and optimistic loop (expecting 1 iteration).
2020-11-08 16:43:15 +03:00
Nekotekina 21ec32b465 vm: implement g_shmem for range locks
Renamed from g_shareable. Contains pointers instead of bits.
Used in range locks to prevent any "collision" between memory.
2020-11-08 16:43:15 +03:00
Nekotekina 1c99a2e7fb vm: add map_self() method to utils::shm
Add complementary unmap_self() method.
Move VirtualMemory to util/vm.hpp
Minor associated include cleanup.
Move asm.h to util/asm.hpp
2020-11-08 16:43:15 +03:00
Nekotekina b68bdafadc vm: refactor vm::range_lock again
Move bits to the highest, set RWX order.
Use only one reserved value (W = locked).
Assume lock size 128 for range_locked.
Add new "Size" template argument that replaces normal argument.
2020-11-08 16:43:15 +03:00
Eladash bacfa9be19 Debugger fixups (#9226)
Fix logic error in callstacks handling code, always set first to false after first iteration.
 Add explicit check for zero return addresses. Current code validity checks may not check for it properly when it sits on interrupt handler entry point (which may contain valid code).
 Do not allow 0x3FFF0 to be a back chain address because it needs space for LR save area, only 0x3FFE0 and below satisfy this criteria.
2020-11-08 16:42:20 +03:00
Eladash 5265eb81e0 kernel-explorer: Add basic process info 2020-11-08 09:17:13 +03:00
Eladash 516da4ecdd Debugger: Improve SPU/PPU callstack handling 2020-11-08 09:17:13 +03:00
Megamouse 6fcc68699a unify patch log 2020-11-07 19:22:40 +01:00
Eladash 3cb5fd8ebc Debugger: Implement SPU callstack, fix PPU callstack 2020-11-07 20:45:57 +03:00
Nekotekina fd7ea82965 atomic.cpp: fix 3-arg notify functions
Third arg forces comparison with itself, and possibly forced wakeup.
2020-11-07 19:18:14 +03:00
Nekotekina 0bd989b118 atomic.cpp: allow waiting on multiple variables simultaneously
Arbitrary maximum set to 8, but really we need 2, maybe 3.
Added atomic_wait::list object for multi-waiting.
Added atomic_wait::get_unique_tsc just in case.
2020-11-07 18:18:02 +03:00
Nekotekina bd0b292b39 atomic.cpp: adjust assumed pointer mask
Increase waiter mask (allow 65535 waiters).
Assume 47-bit pointers instead of 48-bit.
2020-11-07 15:08:46 +03:00
Nekotekina 31f0a0c064 atomic.cpp: add minor safety check 2020-11-07 15:08:46 +03:00
Nekotekina 3e445eff8e atomic.cpp: maintenance of wait() function
Move hashtable allocation into another function.
2020-11-07 15:08:46 +03:00
Eladash 6dcd482dd0 SPU reservations: Do not illegally dereference reservation data 2020-11-07 14:03:09 +03:00
Morgan Creekmore a28ab0a408 Set AccountAge to 18 to fix age restriction checks, fix incorrect logged function name (#9218) 2020-11-07 09:47:44 +00:00
Megamouse a3eb5c2d63 More Header cleanup 2020-11-06 22:14:05 +01:00
Jan Beich e2303f3378 CI/FreeBSD: switch TravisCI to Clang 11 2020-11-06 18:20:23 +00:00
Jan Beich acb17b0298 CI/FreeBSD: enable on TravisCI as ccache works nowadays 2020-11-06 18:20:23 +00:00
Jan Beich fde7cf1fab CI/FreeBSD: switch CirrusCI to 12.2-RELEASE 2020-11-06 18:20:23 +00:00
Jan Beich c2cb7e1004 CI/FreeBSD: avoid downloading commit history in submodules 2020-11-06 18:20:23 +00:00
Jan Beich 4075f5c497 CI/FreeBSD: clear ccache stats, so new hits are easier to notice 2020-11-06 18:20:23 +00:00
Jan Beich debd44fa9b CI/FreeBSD: stop forcing ccache after f528aada24 2020-11-06 18:20:23 +00:00
Nekotekina 0a5742587a atomic.cpp: upgrade raw_notify()
Now it searches all semaphores if data arg is nullptr.
Also it tries to wake up all threads if thread_id is 0.
2020-11-06 17:15:40 +03:00
Nekotekina ad4df2d946 atomic.cpp: refactor native signaling functions
Add native_alert() and try_native_alert()
2020-11-06 17:15:40 +03:00
Nekotekina bfe9580551 atomic.cpp: fix cond_handle data structures
Fix a critical bug with possible id out of range.
2020-11-06 16:56:59 +03:00
Nekotekina 1e45437498 Remove unused atomic with lock bit 2020-11-06 16:48:43 +03:00
Ani f9c8f78000 llvm: Update submodule (Zen3 workaround) (#9212) 2020-11-06 11:41:51 +00:00
RipleyTom 4554eedd19 Extend timeout on travis 2020-11-06 13:54:59 +03:00
Nekotekina 557f0c5a8a atomic.cpp: remove load() from notify functions
Only compare masks for overlap for second overload (with mask provided).
Explicit "new value" can be provided in new 3-arg overloads.
Also rename atomic_storage_futex -> atomic_wait_engine.
2020-11-06 04:44:31 +03:00
Nekotekina 9fb8d449fe atomic.cpp: more improvements
Add ref counters for internal semaphores for concurrent notifying.
Lack of them could result in loss of notification.
2020-11-06 00:14:53 +03:00
Nekotekina 1bb7c74c93 atomic.cpp: various cleanups and fixes
Add pointer comparison to notifiers (to prevent spurious wakeups).
Fix a bug with a possible double notification in raw_notify().
Fix a bug with incorrect allocatin bit slots for cond_handle.
Add a semaphore counter to track max allowed number of threads.
Use #define for some constants to STRINGIZE them in errors.
Add some error messages when certain limits are reached.
Fix a bug with a wrong check simply throwing std::abort.
Use "special" notify_all patch with batch processing for every arch.
Fix Win7 bug who no one probably noticed.
2020-11-06 00:10:16 +03:00
Nekotekina cc07e5306e Improve shared_mutex
Wait/notify only on c_sig, should reduce spurious wakeup noise.
2020-11-06 00:10:16 +03:00
Nekotekina 34fa010601 Improve cond_var notifiers
But nobody uses it anyway, so clean up includes.
2020-11-06 00:10:16 +03:00
Nekotekina 7d56069243 Fix HAS_OVERCOMMIT usage in JIT.cpp 2020-11-05 18:50:19 +03:00
Nekotekina fc77fb9b4c Update LLVM commit id 2020-11-05 06:45:43 +03:00
Nekotekina ebdf93e5dc Fix 1 warning in MSVC 2020-11-05 06:45:01 +03:00
Nekotekina 5248240e10 atomic.cpp: improvements.
Reduced static memory amount for waitable atomics.
Allow notifier to skip notifications if wait/notify masks don't overlap.
Improve raw_notify to wake up the thread by its id, add thread_id arg.
Add optional mask argument to notify_one() and notify_all().
2020-11-05 05:51:43 +03:00
Nekotekina b66628baca Improve low-level mmap utilities (Linux/BSD)
Add madvise (MADV_WILLNEED) on utils::memory_commit
Add madvise (MADV_FREE or MADV_DONTNEED) on utils::memory_decommit
Improve shm_open pseudo-random name (not used on Linux)
2020-11-04 14:59:26 +03:00
Nekotekina ba5ed5f380 Fix vm::lock_range wrong check
Minor header refactoring.
2020-11-04 14:59:26 +03:00
Nekotekina 8d5e119582 Improve cpu_flag::temp handling
Ignore cpu_flag::suspend
Ignore cpu_flag::signal
2020-11-04 14:59:26 +03:00
Nekotekina d022e7cd27 sys_prx: add cpu_flag::wait 2020-11-04 14:59:26 +03:00
Nekotekina 5d7acda80e vm: minor refactoring
Renamed internal main range locking method.
2020-11-04 14:59:25 +03:00
Nekotekina 9b595c68a5 Fix some switch warnings 2020-11-04 14:59:25 +03:00
Nekotekina 2d38d8a639 Fix NEVER_INLINE attribute
Similarly to FORCE_INLINE, it doesn't imply inline on some compilers.
2020-11-04 14:59:25 +03:00
Nekotekina dea8aa675a Optimize cpu check_state() a bit
Move cpu_flag::dbg_pause check from the start.
To the moment before it actually goes to sleep.
2020-11-04 14:59:25 +03:00
Megamouse 027eba2b59 Add Quadro to fast version of VK get_driver_vendor 2020-11-04 12:13:56 +01:00
Megamouse 91b8e7504e Set some things to log level always 2020-11-04 12:13:56 +01:00
Megamouse 088931525d Add option to log qDebug 2020-11-03 06:42:51 +01:00
Megamouse ef9638e094 Log Qt version 2020-11-03 06:42:51 +01:00
902 changed files with 52405 additions and 28632 deletions
+9 -15
View File
@@ -1,25 +1,18 @@
#!/bin/sh -ex
ccache -s # debug
# Pull all the submodules except llvm
# Note: Tried to use git submodule status, but it takes over 20 seconds
# shellcheck disable=SC2046
git submodule -q update --init $(awk '/path/ && !/llvm/ { print $3 }' .gitmodules)
git submodule -q update --init --depth 1 $(awk '/path/ && !/llvm/ { print $3 }' .gitmodules)
# XXX Drop after Travis upgrades FreeBSD to 12.2 (see also .ci/install-freebsd.sh)
case $(${CXX:-c++} --version) in
*version\ 8.0.*)
fetch https://github.com/llvm/llvm-project/releases/download/llvmorg-10.0.0/libcxx-10.0.0.src.tar.xz
tar xf libcxx-10.0.0.src.tar.xz
export CC=clang10 CXX=clang++10
export CXXFLAGS="$CXXFLAGS -nostdinc++ -isystem $PWD/libcxx-10.0.0.src/include"
;;
esac
# Prefer newer Clang than in base system (see also .ci/install-freebsd.sh)
# libc++ isn't in llvm* packages, so download manually
fetch https://github.com/llvm/llvm-project/releases/download/llvmorg-11.0.0/libcxx-11.0.0.src.tar.xz
tar xf libcxx-11.0.0.src.tar.xz
export CC=clang11 CXX=clang++11
export CXXFLAGS="$CXXFLAGS -nostdinc++ -isystem $PWD/libcxx-11.0.0.src/include"
CONFIGURE_ARGS="
-DCMAKE_C_COMPILER_LAUNCHER=ccache
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache
-DWITH_LLVM=OFF
-DUSE_PRECOMPILED_HEADERS=OFF
-DUSE_NATIVE_INSTRUCTIONS=OFF
@@ -32,4 +25,5 @@ CONFIGURE_ARGS="
cmake -B build -G Ninja $CONFIGURE_ARGS
cmake --build build
ccache -s # debug
ccache --show-stats
ccache --zero-stats
+3 -5
View File
@@ -55,11 +55,9 @@ ninja; build_status=$?;
cd ..
# If it compiled succesfully let's deploy depending on the build pipeline (Travis, Azure Pipelines).
# Travis only deploys on master, and it publishes to GitHub releases. Azure publishes PRs as artifacts
# only.
{ [ "$IS_AZURE" = "true" ] ||
{ [ "$TRAVIS_BRANCH" = "master" ] && [ "$TRAVIS_PULL_REQUEST" = "false" ]; };
# If it compiled succesfully let's deploy depending on the build pipeline (Azure Pipelines).
# Azure publishes PRs as artifacts only.
{ [ "$IS_AZURE" = "true" ];
} && SHOULD_DEPLOY="true" || SHOULD_DEPLOY="false"
if [ "$build_status" -eq 0 ] && [ "$SHOULD_DEPLOY" = "true" ]; then
+3 -11
View File
@@ -41,7 +41,6 @@ if [ "$DEPLOY_APPIMAGE" = "true" ]; then
COMM_HASH="$(git rev-parse --short=8 HEAD)"
RPCS3_APPIMAGE="rpcs3-v${COMM_TAG}-${COMM_COUNT}-${COMM_HASH}_linux64.AppImage"
curl -sLO https://github.com/hcorion/uploadtool/raw/master/upload.sh
mv ./RPCS3*.AppImage "$RPCS3_APPIMAGE"
# If we're building using Azure Pipelines, let's copy over the AppImage artifact
@@ -50,16 +49,9 @@ if [ "$DEPLOY_APPIMAGE" = "true" ]; then
fi
FILESIZE=$(stat -c %s ./rpcs3*.AppImage)
SHA256SUM=$(sha256sum ./rpcs3*.AppImage)
if [ -n "$GITHUB_TOKEN" ]; then
unset TRAVIS_REPO_SLUG
REPO_SLUG=RPCS3/rpcs3-binaries-linux \
UPLOADTOOL_BODY="$SHA256SUM;${FILESIZE}B"\
RELEASE_NAME=build-${TRAVIS_COMMIT}\
RELEASE_TITLE=${COMM_TAG}-${COMM_COUNT}\
REPO_COMMIT=d812f1254a1157c80fd402f94446310560f54e5f\
bash upload.sh rpcs3*.AppImage
fi
SHA256SUM=$(sha256sum ./rpcs3*.AppImage | awk '{ print $1 }')
echo "${SHA256SUM};${FILESIZE}B" > /rpcs3/GitHubReleaseMessage.txt
fi
if [ "$DEPLOY_PPA" = "true" ]; then
+2 -6
View File
@@ -1,7 +1,3 @@
# Variables set by Travis CI
TRAVIS_PULL_REQUEST
TRAVIS_BRANCH
TRAVIS_COMMIT
# Variables set by Azure Pipelines
IS_AZURE
BUILD_REASON
@@ -9,8 +5,8 @@ BUILD_SOURCEVERSION
BUILD_ARTIFACTSTAGINGDIRECTORY
BUILD_REPOSITORY_NAME
BUILD_SOURCEBRANCHNAME
# Variables for Travis build matrix
# Variables for build matrix
COMPILER
DEPLOY_APPIMAGE
# Private Travis CI variables
# Private variables
GITHUB_TOKEN
+3 -5
View File
@@ -7,7 +7,7 @@ generate_post_data()
cat <<EOF
{
"tag_name": "build-${BUILD_SOURCEVERSION}",
"target_commitish": "7d09e3be30805911226241afbb14f8cdc2eb054e",
"target_commitish": "${UPLOAD_COMMIT_HASH}",
"name": "${AVVER}",
"body": "$body",
"draft": false,
@@ -16,12 +16,10 @@ generate_post_data()
EOF
}
repo_full_name="RPCS3/rpcs3-binaries-win"
curl -s \
-H "Authorization: token ${RPCS3_TOKEN}" \
-H "Accept: application/vnd.github.v3+json" \
--data "$(generate_post_data)" "https://api.github.com/repos/$repo_full_name/releases" >> release.json
--data "$(generate_post_data)" "https://api.github.com/repos/$UPLOAD_REPO_FULL_NAME/releases" >> release.json
cat release.json
id=$(grep '"id"' release.json | cut -d ':' -f2 | head -n1 | awk '{$1=$1;print}')
@@ -35,7 +33,7 @@ upload_file()
-H "Accept: application/vnd.github.v3+json" \
-H "Content-Type: application/octet-stream" \
--data-binary @"$2"/"$3" \
"https://uploads.github.com/repos/$repo_full_name/releases/$1/assets?name=$3"
"https://uploads.github.com/repos/$UPLOAD_REPO_FULL_NAME/releases/$1/assets?name=$3"
}
for file in "$ARTIFACT_DIR"/*; do
+2 -6
View File
@@ -8,12 +8,8 @@ sed -i '' 's/quarterly/latest/' /etc/pkg/FreeBSD.conf
export ASSUME_ALWAYS_YES=true
pkg info # debug
# XXX Drop after Travis upgrades FreeBSD to 12.2 (see also .ci/build-freebsd.sh)
case $(${CXX:-c++} --version) in
*version\ 8.0.*)
pkg install llvm10
;;
esac
# Prefer newer Clang than in base system (see also .ci/build-freebsd.sh)
pkg install llvm11
# Mandatory dependencies (qt5-dbus and qt5-gui are pulled via qt5-widgets)
pkg install git ccache cmake ninja qt5-qmake qt5-buildtools qt5-widgets qt5-concurrent glew openal-soft ffmpeg
+3 -2
View File
@@ -10,8 +10,9 @@ PR_NUMBER="$SYSTEM_PULLREQUEST_PULLREQUESTID"
QT_HOST="http://mirrors.ocf.berkeley.edu/qt/"
#QT_HOST="http://qt.mirror.constant.com/"
QT_URL_VER=$(echo "$QT_VER" | sed "s/\.//g")
QT_PREFIX="online/qtsdkrepository/windows_x86/desktop/qt5_${QT_URL_VER}/qt.qt5.${QT_URL_VER}.win64_msvc2017_64/${QT_VER}-0-${QT_DATE}"
QT_SUFFIX="-Windows-Windows_10-MSVC2017-Windows-Windows_10-X86_64.7z"
QT_VER_MSVC_UP=$(echo ${QT_VER_MSVC} | tr '[:lower:]' '[:upper:]')
QT_PREFIX="online/qtsdkrepository/windows_x86/desktop/qt${QT_VER_MAIN}_${QT_URL_VER}/qt.qt${QT_VER_MAIN}.${QT_URL_VER}.win64_${QT_VER_MSVC}_64/${QT_VER}-0-${QT_DATE}"
QT_SUFFIX="-Windows-Windows_10-${QT_VER_MSVC_UP}-Windows-Windows_10-X86_64.7z"
QT_BASE_URL="${QT_HOST}${QT_PREFIX}qtbase${QT_SUFFIX}"
QT_WINE_URL="${QT_HOST}${QT_PREFIX}qtwinextras${QT_SUFFIX}"
QT_DECL_URL="${QT_HOST}${QT_PREFIX}qtdeclarative${QT_SUFFIX}"
+2 -2
View File
@@ -3,9 +3,9 @@ env:
freebsd_task:
matrix:
- name: FreeBSD 12.2 (snapshot)
- name: FreeBSD 12.2
freebsd_instance:
image_family: freebsd-12-1-snap
image_family: freebsd-12-2
cpu: 8
memory: 8G
env:
+11 -11
View File
@@ -1,20 +1,20 @@
Standard: Cpp11
Standard: c++20
UseTab: ForIndentation
TabWidth: 1
IndentWidth: 1
AccessModifierOffset: -1
TabWidth: 4
IndentWidth: 4
AccessModifierOffset: -4
PointerAlignment: Left
NamespaceIndentation: All
ColumnLimit: 200
ColumnLimit: 0
BreakBeforeBraces: Allman
BreakConstructorInitializersBeforeComma: true
BreakBeforeBinaryOperators: false
BreakConstructorInitializers: BeforeColon
BreakBeforeBinaryOperators: None
BreakBeforeTernaryOperators: false
AlwaysBreakTemplateDeclarations: true
AllowShortIfStatementsOnASingleLine: false
AllowShortBlocksOnASingleLine: false
AlwaysBreakTemplateDeclarations: Yes
AllowShortIfStatementsOnASingleLine: Never
AllowShortBlocksOnASingleLine: Never
AllowShortCaseLabelsOnASingleLine: true
AllowShortFunctionsOnASingleLine: false
AllowShortFunctionsOnASingleLine: Empty
AllowShortLoopsOnASingleLine: false
Cpp11BracedListStyle: true
IndentCaseLabels: false
+1 -1
View File
@@ -1,7 +1,7 @@
root = true
[*.{h,cpp,hpp}]
charset = utf-8-bom
charset = utf-8
indent_style = tab
indent_size = 4
trim_trailing_whitespace = true
+2
View File
@@ -0,0 +1,2 @@
handle SIGSEGV nostop noprint
handle SIGPIPE nostop noprint
+20
View File
@@ -0,0 +1,20 @@
## How to test a PR build
Please take into account, that RPCS3 build usually takes some time (about 20 min), so you can't access a build, if a PR was just submitted.
- Open a PR you want to test
- Scroll to the very bottom and locate "Checks" section
- Expand all checks
You are supposed to see something like this
![image](https://user-images.githubusercontent.com/44116740/102790039-f98f6d00-43b5-11eb-9134-2359b732508d.png)
- Click on **Linux_Build** or **Windows_Build** __Details__
- Click **View more details on Azure Pipelines** at the very bottom
![image](https://user-images.githubusercontent.com/44116740/102790281-45daad00-43b6-11eb-90e7-0fa8c37c31c6.png)
- Click on *1 artifact produced*
![image](https://user-images.githubusercontent.com/44116740/102790526-9a7e2800-43b6-11eb-9925-be1ea1c8bdad.png)
- Select a build for your OS and click three dots on the right, Click **Download artifacts**
![image](https://user-images.githubusercontent.com/44116740/102790636-c9949980-43b6-11eb-9692-1e3ba567b9be.png)
- Congratulations! You are now downloading RPCS3 build for specific PR.
Please note, that PR builds are not supposed to be stable, because they contain new changesets.
@@ -0,0 +1,3 @@
<!-- Please include a summary of the change and which issue is fixed. -->
[How to test this PR](.github/PR-BUILD.md)
+5
View File
@@ -52,6 +52,9 @@
/bin/GuiConfigs/*.dat
/bin/GuiConfigs/*.dat.*
# Some data from git
!/bin/git/
# Visual Studio Files
.vs/*
.vscode/*
@@ -116,3 +119,5 @@ yaml-cpp.pc
# ssl certificate
cacert.pem
_ReSharper.*/
+2 -1
View File
@@ -4,7 +4,8 @@
ignore = dirty
[submodule "asmjit"]
path = asmjit
url = https://github.com/kobalicek/asmjit
url = https://github.com/asmjit/asmjit
branch = oldstable
ignore = dirty
[submodule "llvm"]
path = llvm
-46
View File
@@ -1,46 +0,0 @@
language: cpp
jobs:
include:
- os: linux
dist: xenial
env:
- NAME="Linux build"
- COMPILER="gcc"
- DEPLOY_APPIMAGE="true"
services: docker
cache: ccache
compiler: gcc
install: "docker pull rpcs3/rpcs3-travis-xenial:1.6"
script: 'travis_wait docker run -v $(pwd):/rpcs3 -v "$HOME/.ccache":/root/.ccache --env-file .ci/travis.env rpcs3/rpcs3-travis-xenial:1.6 /rpcs3/.ci/build-linux.sh'
- os: linux
dist: xenial
env:
- NAME="Linux build"
- COMPILER="clang"
services: docker
cache: ccache
compiler: clang
install: "docker pull rpcs3/rpcs3-travis-xenial:1.6"
script: 'travis_wait docker run -v $(pwd):/rpcs3 -v "$HOME/.ccache":/root/.ccache --env-file .ci/travis.env rpcs3/rpcs3-travis-xenial:1.6 /rpcs3/.ci/build-linux.sh'
# - os: freebsd
# compiler: clang
# cache: ccache
# install: "./.ci/install-freebsd.sh"
# script: "./.ci/build-freebsd.sh"
# - os: osx
# osx_image: xcode11.3
# addons:
# homebrew:
# packages:
# - ccache
# - glew
# - ninja
# - qt
# script: "/bin/bash -ex .ci/build-mac.sh"
# cache: ccache
allow_failures:
- os: osx
git:
depth: false # Unshallow clone to obtain proper GIT_VERSION
submodules: false
+2 -1
View File
@@ -131,6 +131,7 @@ else()
target_link_libraries(usb-1.0-shared INTERFACE PkgConfig::LIBUSB)
else()
# we don't have the system libusb, so we compile from submodule
unset(LIBUSB_LIBRARIES CACHE)
add_subdirectory(libusb_cmake EXCLUDE_FROM_ALL)
endif()
endif()
@@ -354,7 +355,7 @@ target_link_libraries(3rdparty_openal INTERFACE ${OPENAL_LIBRARY})
set(FAUDIO_TARGET 3rdparty_dummy_lib)
if(USE_FAUDIO)
# FAudio depends on SDL2
pkg_check_modules(SDL2 sdl2)
find_package(SDL2)
if (NOT SDL2_FOUND OR SDL2_VERSION VERSION_LESS 2.0.9)
message("-- RPCS3: FAudio requires SDL 2.0.9 or newer.")
else()
+4 -4
View File
@@ -8848,7 +8848,7 @@ bool VmaBlockMetadata_Generic::CheckAllocation(
// Check previous suballocations for BufferImageGranularity conflicts.
// Make bigger alignment if necessary.
if(bufferImageGranularity > 1)
if(bufferImageGranularity > 1 && bufferImageGranularity != allocAlignment)
{
bool bufferImageGranularityConflict = false;
VmaSuballocationList::const_iterator prevSuballocItem = suballocItem;
@@ -8932,7 +8932,7 @@ bool VmaBlockMetadata_Generic::CheckAllocation(
// Check next suballocations for BufferImageGranularity conflicts.
// If conflict exists, we must mark more allocations lost or fail.
if(bufferImageGranularity > 1)
if(bufferImageGranularity > 1 && (allocSize % bufferImageGranularity || *pOffset % bufferImageGranularity))
{
VmaSuballocationList::const_iterator nextSuballocItem = lastSuballocItem;
++nextSuballocItem;
@@ -8991,7 +8991,7 @@ bool VmaBlockMetadata_Generic::CheckAllocation(
// Check previous suballocations for BufferImageGranularity conflicts.
// Make bigger alignment if necessary.
if(bufferImageGranularity > 1)
if(bufferImageGranularity > 1 && bufferImageGranularity != allocAlignment)
{
bool bufferImageGranularityConflict = false;
VmaSuballocationList::const_iterator prevSuballocItem = suballocItem;
@@ -9031,7 +9031,7 @@ bool VmaBlockMetadata_Generic::CheckAllocation(
// Check next suballocations for BufferImageGranularity conflicts.
// If conflict exists, allocation cannot be made here.
if(bufferImageGranularity > 1)
if(bufferImageGranularity > 1 && (allocSize % bufferImageGranularity || *pOffset % bufferImageGranularity))
{
VmaSuballocationList::const_iterator nextSuballocItem = suballocItem;
++nextSuballocItem;
+9 -11
View File
@@ -1,11 +1,13 @@
add_library(3rdparty_qt5 INTERFACE)
find_package(Qt5 5.14 CONFIG COMPONENTS Widgets Concurrent)
set(QT_MIN_VER 5.15.2)
find_package(Qt5 ${QT_MIN_VER} CONFIG COMPONENTS Widgets Concurrent)
if(WIN32)
find_package(Qt5 5.14 COMPONENTS WinExtras REQUIRED)
find_package(Qt5 ${QT_MIN_VER} COMPONENTS WinExtras REQUIRED)
target_link_libraries(3rdparty_qt5 INTERFACE Qt5::Widgets Qt5::WinExtras Qt5::Concurrent)
else()
find_package(Qt5 5.14 COMPONENTS DBus Gui)
find_package(Qt5 ${QT_MIN_VER} COMPONENTS DBus Gui)
if(Qt5DBus_FOUND)
target_link_libraries(3rdparty_qt5 INTERFACE Qt5::Widgets Qt5::DBus Qt5::Concurrent)
target_compile_definitions(3rdparty_qt5 INTERFACE -DHAVE_QTDBUS)
@@ -16,16 +18,12 @@ else()
endif()
if(NOT Qt5Widgets_FOUND)
if(Qt5Widgets_VERSION VERSION_LESS 5.14.0)
message("Minimum supported Qt5 version is 5.14.0! You have version ${Qt5Widgets_VERSION} installed, please upgrade!")
if(Qt5Widgets_VERSION VERSION_LESS ${QT_MIN_VER})
message("Minimum supported Qt5 version is ${QT_MIN_VER}! You have version ${Qt5Widgets_VERSION} installed, please upgrade!")
if(CMAKE_SYSTEM MATCHES "Linux")
message(FATAL_ERROR "Most distros do not provide an up-to-date version of Qt.
If you're on Ubuntu or Linux Mint, there are PPAs you can use to install one of the latest qt5 versions.
https://launchpad.net/~beineri/+archive/ubuntu/opt-qt-5.14.1-bionic
https://launchpad.net/~beineri/+archive/ubuntu/opt-qt-5.14.1-xenial
just make sure to run
source /opt/qt514/bin/qt514-env.sh
before re-running cmake")
Find the correct ppa at https://launchpad.net/~beineri and follow the instructions.")
elseif(WIN32)
message(FATAL_ERROR "You can download the latest version of Qt5 here: https://www.qt.io/download-open-source/")
else()
@@ -35,7 +33,7 @@ before re-running cmake")
message("CMake was unable to find Qt5!")
if(WIN32)
message(FATAL_ERROR "Make sure the QTDIR env variable has been set properly. (for example C:\\Qt\\5.14.1\\msvc2017_64\\)
message(FATAL_ERROR "Make sure the QTDIR env variable has been set properly. (for example C:\\Qt\\${QT_MIN_VER}\\msvc2019_64\\)
You can also try setting the Qt5_DIR preprocessor definiton.")
elseif(CMAKE_SYSTEM MATCHES "Linux")
message(FATAL_ERROR "Make sure to install your distro's qt5 package!")
+9 -9
View File
@@ -9,19 +9,19 @@ Other instructions may be found [here](https://wiki.rpcs3.net/index.php?title=Bu
* [CMake 3.14.1+](https://www.cmake.org/download/) (add to PATH)
* [Python 3.3+](https://www.python.org/downloads/) (add to PATH)
* [Qt 5.14.2](https://www.qt.io/download-qt-installer)
* [Qt 5.15.2](https://www.qt.io/download-qt-installer)
* [Visual Studio 2019](https://visualstudio.microsoft.com/thank-you-downloading-visual-studio/?sku=Community)
* [Vulkan SDK 1.1.126+](https://vulkan.lunarg.com/sdk/home) (See "Install the SDK" [here](https://vulkan.lunarg.com/doc/sdk/latest/windows/getting_started.html))
**Either add the** `QTDIR` **environment variable, e.g.** `<QtInstallFolder>\5.14.2\msvc2017_64\` **, or use the [Visual Studio Qt Plugin](https://marketplace.visualstudio.com/items?itemName=TheQtCompany.QtVisualStudioTools2019)**
**Either add the** `QTDIR` **environment variable, e.g.** `<QtInstallFolder>\5.15.2\msvc2019_64\` **, or use the [Visual Studio Qt Plugin](https://marketplace.visualstudio.com/items?itemName=TheQtCompany.QtVisualStudioTools2019)**
### Linux
These are the essentials tools to build RPCS3 on Linux. Some of them can be installed through your favorite package manager.
* Clang 9+ or GCC 9+
* Clang 11+ or GCC 9+
* [CMake 3.14.1+](https://www.cmake.org/download/)
* [Qt 5.14.2](https://www.qt.io/download-qt-installer)
* [Qt 5.15.2](https://www.qt.io/download-qt-installer)
* [Vulkan SDK 1.1.126+](https://vulkan.lunarg.com/sdk/home) (See "Install the SDK" [here](https://vulkan.lunarg.com/doc/sdk/latest/linux/getting_started.html))
* [SDL2](https://www.libsdl.org/download-2.0.php) (for the FAudio backend)
@@ -41,10 +41,10 @@ Ubuntu is usually horrendously out of date, and some packages need to be downloa
Ubuntu usually does not have a new enough Qt package to suit rpcs3's needs. There is a PPA available to work around this. Run the following:
```
. /etc/os-release
sudo add-apt-repository ppa:beineri/opt-qt-5.14.2-$UBUNTU_CODENAME
sudo add-apt-repository ppa:beineri/opt-qt-5.15.2-$UBUNTU_CODENAME
sudo apt-get update
sudo apt-get install qt514-meta-minimal qt514svg
. /opt/qt514/bin/qt514-env.sh >/dev/null 2>&1
sudo apt-get install qt515-meta-minimal qt515svg
. /opt/qt515/bin/qt515-env.sh >/dev/null 2>&1
```
##### GCC 9.x installation
@@ -82,7 +82,7 @@ sudo apt-get install cmake
#### Fedora
sudo dnf install alsa-lib-devel cmake glew glew-devel libatomic libevdev-devel libudev-devel openal-devel qt5-devel vulkan-devel
sudo dnf install alsa-lib-devel cmake glew glew-devel libatomic libevdev-devel libudev-devel openal-devel qt5-qtbase-devel qt5-qtbase-private-devel vulkan-devel
#### OpenSUSE
@@ -103,7 +103,7 @@ git submodule update --init
#### Configuring the Qt plugin (if used)
1) Go to the Qt5 menu and edit Qt5 options.
2) Add the path to your Qt installation with compiler e.g. `<QtInstallFolder>\5.14.2\msvc2017_64`.
2) Add the path to your Qt installation with compiler e.g. `<QtInstallFolder>\5.15.2\msvc2019_64`.
3) While selecting the rpcs3qt project, go to Qt5->Project Setting and select the version you added.
#### Building the projects
+6 -4
View File
@@ -7,8 +7,8 @@ if(CMAKE_COMPILER_IS_GNUCXX)
message(FATAL_ERROR "RPCS3 requires at least gcc-9.")
endif()
elseif(${CMAKE_CXX_COMPILER_ID} MATCHES "Clang")
if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 9.0)
message(FATAL_ERROR "RPCS3 requires at least clang-9.0.")
if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 11.0)
message(FATAL_ERROR "RPCS3 requires at least clang-11.0.")
endif()
endif()
@@ -22,7 +22,7 @@ option(USE_LIBEVDEV "libevdev-based joystick support" ON)
option(USE_DISCORD_RPC "Discord rich presence integration" ON)
option(USE_SYSTEM_ZLIB "Prefer system ZLIB instead of the builtin one" ON)
option(USE_VULKAN "Vulkan render backend" ON)
option(USE_PRECOMPILED_HEADERS "Use precompiled headers" ON)
option(USE_PRECOMPILED_HEADERS "Use precompiled headers" OFF)
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/rpcs3/cmake_modules")
@@ -36,6 +36,8 @@ endif()
if(NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
add_definitions(-DNDEBUG)
elseif(NOT MSVC)
add_definitions(-D_DEBUG)
endif()
if(NOT CMAKE_SIZEOF_VOID_P EQUAL 8)
@@ -64,7 +66,7 @@ set(CMAKE_C_FLAGS -w)
set(LLVM_ENABLE_WARNINGS OFF CACHE BOOL "")
if(MSVC)
add_compile_options(/wd4530) # C++ exception handler used, but unwind semantics are not enabled
add_compile_options(/wd4530 /utf-8) # C++ exception handler used, but unwind semantics are not enabled
endif()
add_subdirectory(Vulkan EXCLUDE_FROM_ALL)
-1
View File
@@ -1,7 +1,6 @@
RPCS3
=====
[![Travis (.org) branch](https://img.shields.io/travis/RPCS3/rpcs3/master?label=Travis%20CI&logo=travis)](https://travis-ci.org/RPCS3/rpcs3)
[![Azure Build Status](https://dev.azure.com/nekotekina/nekotekina/_apis/build/status/RPCS3.rpcs3?branchName=master)](https://dev.azure.com/nekotekina/nekotekina/_build?definitionId=4&branchName=master)
[![Cirrus CI - Base Branch Build Status](https://img.shields.io/cirrus/github/RPCS3/rpcs3?label=Cirrus%20CI%20(FreeBSD)&logo=cirrus-ci)](https://cirrus-ci.com/github/RPCS3/rpcs3)
[![RPCS3 discord server](https://img.shields.io/discord/272035812277878785?color=%237289DA&label=RPCS3%20Discord&logo=discord&logoColor=white)](https://discord.me/rpcs3)
-511
View File
@@ -1,511 +0,0 @@
#ifndef BETYPE_H_GUARD
#define BETYPE_H_GUARD
#include "types.h"
#include "util/endian.hpp"
#include <cstring>
#include <cmath>
#if __has_include(<bit>)
#include <bit>
#else
#include <type_traits>
#endif
// 128-bit vector type and also se_storage<> storage type
union alignas(16) v128
{
uchar _bytes[16];
char _chars[16];
template <typename T, std::size_t N, std::size_t M>
struct masked_array_t // array type accessed as (index ^ M)
{
char m_data[16];
public:
T& operator[](std::size_t index)
{
return reinterpret_cast<T*>(m_data)[index ^ M];
}
const T& operator[](std::size_t index) const
{
return reinterpret_cast<const T*>(m_data)[index ^ M];
}
};
template <typename T, std::size_t N = 16 / sizeof(T)>
using normal_array_t = masked_array_t<T, N, std::endian::little == std::endian::native ? 0 : N - 1>;
template <typename T, std::size_t N = 16 / sizeof(T)>
using reversed_array_t = masked_array_t<T, N, std::endian::little == std::endian::native ? N - 1 : 0>;
normal_array_t<u64> _u64;
normal_array_t<s64> _s64;
reversed_array_t<u64> u64r;
reversed_array_t<s64> s64r;
normal_array_t<u32> _u32;
normal_array_t<s32> _s32;
reversed_array_t<u32> u32r;
reversed_array_t<s32> s32r;
normal_array_t<u16> _u16;
normal_array_t<s16> _s16;
reversed_array_t<u16> u16r;
reversed_array_t<s16> s16r;
normal_array_t<u8> _u8;
normal_array_t<s8> _s8;
reversed_array_t<u8> u8r;
reversed_array_t<s8> s8r;
normal_array_t<f32> _f;
normal_array_t<f64> _d;
reversed_array_t<f32> fr;
reversed_array_t<f64> dr;
__m128 vf;
__m128i vi;
__m128d vd;
struct bit_array_128
{
char m_data[16];
public:
class bit_element
{
u64& data;
const u64 mask;
public:
bit_element(u64& data, const u64 mask)
: data(data)
, mask(mask)
{
}
operator bool() const
{
return (data & mask) != 0;
}
bit_element& operator=(const bool right)
{
if (right)
{
data |= mask;
}
else
{
data &= ~mask;
}
return *this;
}
bit_element& operator=(const bit_element& right)
{
if (right)
{
data |= mask;
}
else
{
data &= ~mask;
}
return *this;
}
};
// Index 0 returns the MSB and index 127 returns the LSB
bit_element operator[](u32 index)
{
const auto data_ptr = reinterpret_cast<u64*>(m_data);
if constexpr (std::endian::little == std::endian::native)
{
return bit_element(data_ptr[1 - (index >> 6)], 0x8000000000000000ull >> (index & 0x3F));
}
else
{
return bit_element(data_ptr[index >> 6], 0x8000000000000000ull >> (index & 0x3F));
}
}
// Index 0 returns the MSB and index 127 returns the LSB
bool operator[](u32 index) const
{
const auto data_ptr = reinterpret_cast<const u64*>(m_data);
if constexpr (std::endian::little == std::endian::native)
{
return (data_ptr[1 - (index >> 6)] & (0x8000000000000000ull >> (index & 0x3F))) != 0;
}
else
{
return (data_ptr[index >> 6] & (0x8000000000000000ull >> (index & 0x3F))) != 0;
}
}
} _bit;
static v128 from64(u64 _0, u64 _1 = 0)
{
v128 ret;
ret._u64[0] = _0;
ret._u64[1] = _1;
return ret;
}
static v128 from64r(u64 _1, u64 _0 = 0)
{
return from64(_0, _1);
}
static v128 from32(u32 _0, u32 _1 = 0, u32 _2 = 0, u32 _3 = 0)
{
v128 ret;
ret._u32[0] = _0;
ret._u32[1] = _1;
ret._u32[2] = _2;
ret._u32[3] = _3;
return ret;
}
static v128 from32r(u32 _3, u32 _2 = 0, u32 _1 = 0, u32 _0 = 0)
{
return from32(_0, _1, _2, _3);
}
static v128 from32p(u32 value)
{
v128 ret;
ret.vi = _mm_set1_epi32(static_cast<s32>(value));
return ret;
}
static v128 from16p(u16 value)
{
v128 ret;
ret.vi = _mm_set1_epi16(static_cast<s16>(value));
return ret;
}
static v128 from8p(u8 value)
{
v128 ret;
ret.vi = _mm_set1_epi8(static_cast<s8>(value));
return ret;
}
static v128 fromBit(u32 bit)
{
v128 ret = {};
ret._bit[bit] = true;
return ret;
}
static v128 fromV(__m128i value)
{
v128 ret;
ret.vi = value;
return ret;
}
static v128 fromF(__m128 value)
{
v128 ret;
ret.vf = value;
return ret;
}
static v128 fromD(__m128d value)
{
v128 ret;
ret.vd = value;
return ret;
}
// Unaligned load with optional index offset
static v128 loadu(const void* ptr, std::size_t index = 0)
{
v128 ret;
std::memcpy(&ret, static_cast<const u8*>(ptr) + index * sizeof(v128), sizeof(v128));
return ret;
}
// Unaligned store with optional index offset
static void storeu(v128 value, void* ptr, std::size_t index = 0)
{
std::memcpy(static_cast<u8*>(ptr) + index * sizeof(v128), &value, sizeof(v128));
}
static inline v128 add8(const v128& left, const v128& right)
{
return fromV(_mm_add_epi8(left.vi, right.vi));
}
static inline v128 add16(const v128& left, const v128& right)
{
return fromV(_mm_add_epi16(left.vi, right.vi));
}
static inline v128 add32(const v128& left, const v128& right)
{
return fromV(_mm_add_epi32(left.vi, right.vi));
}
static inline v128 addfs(const v128& left, const v128& right)
{
return fromF(_mm_add_ps(left.vf, right.vf));
}
static inline v128 addfd(const v128& left, const v128& right)
{
return fromD(_mm_add_pd(left.vd, right.vd));
}
static inline v128 sub8(const v128& left, const v128& right)
{
return fromV(_mm_sub_epi8(left.vi, right.vi));
}
static inline v128 sub16(const v128& left, const v128& right)
{
return fromV(_mm_sub_epi16(left.vi, right.vi));
}
static inline v128 sub32(const v128& left, const v128& right)
{
return fromV(_mm_sub_epi32(left.vi, right.vi));
}
static inline v128 subfs(const v128& left, const v128& right)
{
return fromF(_mm_sub_ps(left.vf, right.vf));
}
static inline v128 subfd(const v128& left, const v128& right)
{
return fromD(_mm_sub_pd(left.vd, right.vd));
}
static inline v128 maxu8(const v128& left, const v128& right)
{
return fromV(_mm_max_epu8(left.vi, right.vi));
}
static inline v128 minu8(const v128& left, const v128& right)
{
return fromV(_mm_min_epu8(left.vi, right.vi));
}
static inline v128 eq8(const v128& left, const v128& right)
{
return fromV(_mm_cmpeq_epi8(left.vi, right.vi));
}
static inline v128 eq16(const v128& left, const v128& right)
{
return fromV(_mm_cmpeq_epi16(left.vi, right.vi));
}
static inline v128 eq32(const v128& left, const v128& right)
{
return fromV(_mm_cmpeq_epi32(left.vi, right.vi));
}
static inline v128 eq32f(const v128& left, const v128& right)
{
return fromF(_mm_cmpeq_ps(left.vf, right.vf));
}
static inline v128 eq64f(const v128& left, const v128& right)
{
return fromD(_mm_cmpeq_pd(left.vd, right.vd));
}
static inline bool use_fma = false;
static inline v128 fma32f(v128 a, const v128& b, const v128& c)
{
#ifndef __FMA__
if (use_fma) [[likely]]
{
#ifdef _MSC_VER
a.vf = _mm_fmadd_ps(a.vf, b.vf, c.vf);
return a;
#else
__asm__("vfmadd213ps %[c], %[b], %[a]"
: [a] "+x" (a.vf)
: [b] "x" (b.vf)
, [c] "x" (c.vf));
return a;
#endif
}
for (int i = 0; i < 4; i++)
{
a._f[i] = std::fmaf(a._f[i], b._f[i], c._f[i]);
}
return a;
#else
a.vf = _mm_fmadd_ps(a.vf, b.vf, c.vf);
return a;
#endif
}
bool operator==(const v128& right) const
{
return _mm_movemask_epi8(v128::eq32(*this, right).vi) == 0xffff;
}
bool operator!=(const v128& right) const
{
return !operator==(right);
}
// result = (~left) & (right)
static inline v128 andnot(const v128& left, const v128& right)
{
return fromV(_mm_andnot_si128(left.vi, right.vi));
}
void clear()
{
*this = {};
}
};
template <typename T, std::size_t N, std::size_t M>
struct offset32_array<v128::masked_array_t<T, N, M>>
{
template <typename Arg>
static inline u32 index32(const Arg& arg)
{
return u32{sizeof(T)} * (static_cast<u32>(arg) ^ static_cast<u32>(M));
}
};
inline v128 operator|(const v128& left, const v128& right)
{
return v128::fromV(_mm_or_si128(left.vi, right.vi));
}
inline v128 operator&(const v128& left, const v128& right)
{
return v128::fromV(_mm_and_si128(left.vi, right.vi));
}
inline v128 operator^(const v128& left, const v128& right)
{
return v128::fromV(_mm_xor_si128(left.vi, right.vi));
}
inline v128 operator~(const v128& other)
{
return other ^ v128::from32p(UINT32_MAX); // XOR with ones
}
using stx::se_t;
using stx::se_storage;
// se_t<> with native endianness
template <typename T, std::size_t Align = alignof(T)>
using nse_t = se_t<T, false, Align>;
template <typename T, std::size_t Align = alignof(T)>
using be_t = se_t<T, std::endian::little == std::endian::native, Align>;
template <typename T, std::size_t Align = alignof(T)>
using le_t = se_t<T, std::endian::big == std::endian::native, Align>;
// Type converter: converts native endianness arithmetic/enum types to appropriate se_t<> type
template <typename T, bool Se, typename = void>
struct to_se
{
template <typename T2, typename = void>
struct to_se_
{
using type = T2;
};
template <typename T2>
struct to_se_<T2, std::enable_if_t<std::is_arithmetic<T2>::value || std::is_enum<T2>::value>>
{
using type = std::conditional_t<(sizeof(T2) > 1), se_t<T2, Se>, T2>;
};
// Convert arithmetic and enum types
using type = typename to_se_<T>::type;
};
template <bool Se>
struct to_se<v128, Se>
{
using type = se_t<v128, Se>;
};
template <bool Se>
struct to_se<u128, Se>
{
using type = se_t<u128, Se>;
};
template <bool Se>
struct to_se<s128, Se>
{
using type = se_t<s128, Se>;
};
template <typename T, bool Se>
struct to_se<const T, Se, std::enable_if_t<!std::is_array<T>::value>>
{
// Move const qualifier
using type = const typename to_se<T, Se>::type;
};
template <typename T, bool Se>
struct to_se<volatile T, Se, std::enable_if_t<!std::is_array<T>::value && !std::is_const<T>::value>>
{
// Move volatile qualifier
using type = volatile typename to_se<T, Se>::type;
};
template <typename T, bool Se>
struct to_se<T[], Se>
{
// Move array qualifier
using type = typename to_se<T, Se>::type[];
};
template <typename T, bool Se, std::size_t N>
struct to_se<T[N], Se>
{
// Move array qualifier
using type = typename to_se<T, Se>::type[N];
};
// BE/LE aliases for to_se<>
template <typename T>
using to_be_t = typename to_se<T, std::endian::little == std::endian::native>::type;
template <typename T>
using to_le_t = typename to_se<T, std::endian::big == std::endian::native>::type;
// BE/LE aliases for atomic_t
template <typename T, std::size_t Align = alignof(T)>
using atomic_be_t = atomic_t<be_t<T>, Align>;
template <typename T, std::size_t Align = alignof(T)>
using atomic_le_t = atomic_t<le_t<T>, Align>;
template <typename T, bool Se, std::size_t Align>
struct fmt_unveil<se_t<T, Se, Align>, void>
{
using type = typename fmt_unveil<T>::type;
static inline auto get(const se_t<T, Se, Align>& arg)
{
return fmt_unveil<T>::get(arg);
}
};
#endif // BETYPE_H_GUARD
+3 -2
View File
@@ -1,6 +1,7 @@
#pragma once
#pragma once
#include "types.h"
#include "util/types.hpp"
#include "Utilities/StrFmt.h"
template<typename T, uint N>
struct bf_base
+11 -14
View File
@@ -1,14 +1,11 @@
#include "stdafx.h"
#include "stdafx.h"
#include "Config.h"
#include "Utilities/types.h"
#include "util/types.hpp"
#include "util/yaml.hpp"
#include <typeinfo>
#include <charconv>
[[noreturn]] void report_fatal_error(const std::string&);
LOG_CHANNEL(cfg_log, "CFG");
namespace cfg
@@ -18,7 +15,7 @@ namespace cfg
{
if (_type != type::node)
{
cfg_log.fatal("Invalid root node" HERE);
cfg_log.fatal("Invalid root node");
}
}
@@ -29,7 +26,7 @@ namespace cfg
{
if (pair.first == name)
{
cfg_log.fatal("Node already exists: %s" HERE, name);
cfg_log.fatal("Node already exists: %s", name);
}
}
@@ -38,12 +35,12 @@ namespace cfg
bool _base::from_string(const std::string&, bool)
{
report_fatal_error("from_string() purecall" HERE);
fmt::throw_exception("from_string() purecall");
}
bool _base::from_list(std::vector<std::string>&&)
{
report_fatal_error("from_list() purecall" HERE);
fmt::throw_exception("from_list() purecall");
}
// Emit YAML
@@ -84,7 +81,7 @@ bool cfg::try_to_int64(s64* out, const std::string& value, s64 min, s64 max)
if (ret.ec != std::errc() || ret.ptr != end || (start[0] == '-' && sign < 0))
{
if (out) cfg_log.error("cfg::try_to_int('%s'): invalid integer", value);
if (out) cfg_log.error("cfg::try_to_int64('%s'): invalid integer", value);
return false;
}
@@ -92,7 +89,7 @@ bool cfg::try_to_int64(s64* out, const std::string& value, s64 min, s64 max)
if (result < min || result > max)
{
if (out) cfg_log.error("cfg::try_to_int('%s'): out of bounds (%d..%d)", value, min, max);
if (out) cfg_log.error("cfg::try_to_int64('%s'): out of bounds (%d..%d)", value, min, max);
return false;
}
@@ -123,13 +120,13 @@ bool cfg::try_to_uint64(u64* out, const std::string& value, u64 min, u64 max)
if (ret.ec != std::errc() || ret.ptr != end)
{
if (out) cfg_log.error("cfg::try_to_int('%s'): invalid integer", value);
if (out) cfg_log.error("cfg::try_to_uint64('%s'): invalid integer", value);
return false;
}
if (result < min || result > max)
{
if (out) cfg_log.error("cfg::try_to_int('%s'): out of bounds (%u..%u)", value, min, max);
if (out) cfg_log.error("cfg::try_to_uint64('%s'): out of bounds (%u..%u)", value, min, max);
return false;
}
@@ -380,7 +377,7 @@ void cfg::_bool::from_default()
void cfg::string::from_default()
{
m_value = m_value.make(def);
m_value = def;
}
void cfg::set_entry::from_default()
+7 -7
View File
@@ -1,10 +1,10 @@
#pragma once
#pragma once
#include "Utilities/types.h"
#include "util/types.hpp"
#include "Utilities/StrFmt.h"
#include "util/logs.hpp"
#include "util/atomic.hpp"
#include "util/shared_cptr.hpp"
#include "util/shared_ptr.hpp"
#include <utility>
#include <string>
@@ -393,7 +393,7 @@ namespace cfg
{
const std::string m_name;
stx::atomic_cptr<std::string> m_value;
atomic_ptr<std::string> m_value;
public:
std::string def;
@@ -401,7 +401,7 @@ namespace cfg
string(node* owner, std::string name, std::string def = {}, bool dynamic = false)
: _base(type::string, owner, name, dynamic)
, m_name(std::move(name))
, m_value(m_value.make(def))
, m_value(def)
, def(std::move(def))
{
}
@@ -411,7 +411,7 @@ namespace cfg
return *m_value.load().get();
}
std::pair<const std::string&, stx::shared_cptr<std::string>> get() const
std::pair<const std::string&, shared_ptr<std::string>> get() const
{
auto v = m_value.load();
@@ -440,7 +440,7 @@ namespace cfg
bool from_string(const std::string& value, bool /*dynamic*/ = false) override
{
m_value = m_value.make(value);
m_value = value;
return true;
}
};
+181 -61
View File
@@ -1,16 +1,16 @@
#include "File.h"
#include "File.h"
#include "mutex.h"
#include "StrFmt.h"
#include "BEType.h"
#include "Crypto/sha1.h"
#include <unordered_map>
#include <algorithm>
#include <cstring>
#include <cerrno>
#include <typeinfo>
#include <map>
#include "util/asm.hpp"
using namespace std::literals::string_literals;
#ifdef _WIN32
@@ -18,13 +18,18 @@ using namespace std::literals::string_literals;
#include <cwchar>
#include <Windows.h>
namespace utils
{
u64 get_unique_tsc();
}
static std::unique_ptr<wchar_t[]> to_wchar(const std::string& source)
{
// String size + null terminator
const std::size_t buf_size = source.size() + 1;
const usz buf_size = source.size() + 1;
// Safe size
const int size = narrow<int>(buf_size, "to_wchar" HERE);
const int size = narrow<int>(buf_size);
// Buffer for max possible output length
std::unique_ptr<wchar_t[]> buffer(new wchar_t[buf_size + 8 + 32768]);
@@ -41,10 +46,10 @@ static std::unique_ptr<wchar_t[]> to_wchar(const std::string& source)
std::memcpy(buffer.get() + 32768 + 4, L"UNC\\", 4 * sizeof(wchar_t));
}
verify("to_wchar" HERE), MultiByteToWideChar(CP_UTF8, 0, source.c_str(), size, buffer.get() + 32768 + (unc ? 8 : 4), size);
ensure(MultiByteToWideChar(CP_UTF8, 0, source.c_str(), size, buffer.get() + 32768 + (unc ? 8 : 4), size)); // "to_wchar"
// Canonicalize wide path (replace '/', ".", "..", \\ repetitions, etc)
verify("to_wchar" HERE), GetFullPathNameW(buffer.get() + 32768, 32768, buffer.get(), nullptr) - 1 < 32768 - 1;
ensure(GetFullPathNameW(buffer.get() + 32768, 32768, buffer.get(), nullptr) - 1 < 32768 - 1); // "to_wchar"
return buffer;
}
@@ -52,10 +57,10 @@ static std::unique_ptr<wchar_t[]> to_wchar(const std::string& source)
static void to_utf8(std::string& out, const wchar_t* source)
{
// String size
const std::size_t length = std::wcslen(source);
const usz length = std::wcslen(source);
// Safe buffer size for max possible output length (including null terminator)
const int buf_size = narrow<int>(length * 3 + 1, "to_utf8" HERE);
const int buf_size = narrow<int>(length * 3 + 1);
// Resize buffer
out.resize(buf_size - 1);
@@ -63,7 +68,7 @@ static void to_utf8(std::string& out, const wchar_t* source)
const int result = WideCharToMultiByte(CP_UTF8, 0, source, static_cast<int>(length) + 1, &out.front(), buf_size, NULL, NULL);
// Fix the size
out.resize(verify("to_utf8" HERE, result) - 1);
out.resize(ensure(result) - 1);
}
static time_t to_time(const ULARGE_INTEGER& ft)
@@ -182,7 +187,7 @@ static std::string path_append(std::string_view path, std::string_view more)
{
std::string result;
if (const size_t src_slash_pos = path.find_last_not_of('/'); src_slash_pos != path.npos)
if (const usz src_slash_pos = path.find_last_not_of('/'); src_slash_pos != path.npos)
{
path.remove_suffix(path.length() - src_slash_pos - 1);
result = path;
@@ -190,7 +195,7 @@ static std::string path_append(std::string_view path, std::string_view more)
result.push_back('/');
if (const size_t dst_slash_pos = more.find_first_not_of('/'); dst_slash_pos != more.npos)
if (const usz dst_slash_pos = more.find_first_not_of('/'); dst_slash_pos != more.npos)
{
more.remove_prefix(dst_slash_pos);
result.append(more);
@@ -227,7 +232,7 @@ namespace fs
stat_t file_base::stat()
{
fmt::throw_exception("fs::file::stat() not supported for %s", typeid(*this).name());
fmt::throw_exception("fs::file::stat() not supported.");
}
void file_base::sync()
@@ -315,19 +320,60 @@ std::shared_ptr<fs::device_base> fs::get_virtual_device(const std::string& path)
std::shared_ptr<fs::device_base> fs::set_virtual_device(const std::string& name, const std::shared_ptr<device_base>& device)
{
verify(HERE), name.starts_with("//"), name[2] != '/';
ensure(name.starts_with("//") && name[2] != '/');
return get_device_manager().set_device(name, device);
}
std::string fs::get_parent_dir(const std::string& path)
{
// Get (basically) processed path
const auto real_path = fs::escape_path(path);
std::string_view result = path;
const auto pos = real_path.find_last_of(delim);
// Number of path components to remove
usz to_remove = 1;
return real_path.substr(0, pos == umax ? 0 : pos);
while (to_remove--)
{
// Trim contiguous delimiters at the end
if (usz sz = result.find_last_not_of(delim) + 1)
{
result = result.substr(0, sz);
}
else
{
return "/";
}
const auto elem = result.substr(result.find_last_of(delim) + 1);
if (elem.empty() || elem.size() == result.size())
{
break;
}
if (elem == ".")
{
to_remove += 1;
}
if (elem == "..")
{
to_remove += 2;
}
result.remove_suffix(elem.size());
}
if (usz sz = result.find_last_not_of(delim) + 1)
{
result = result.substr(0, sz);
}
else
{
return "/";
}
return std::string{result};
}
bool fs::stat(const std::string& path, stat_t& info)
@@ -355,7 +401,7 @@ bool fs::stat(const std::string& path, stat_t& info)
if (!GetFileAttributesExW(to_wchar(std::string(epath) + '/').get(), GetFileExInfoStandard, &attrs))
{
g_tls_error = to_error(GetLastError());
return false;
return false;
}
info.is_directory = true; // Handle drives as directories
@@ -404,7 +450,7 @@ bool fs::stat(const std::string& path, stat_t& info)
if (const DWORD err = GetLastError(); err != ERROR_NO_MORE_FILES)
{
g_tls_error = to_error(err);
return false;
return false;
}
g_tls_error = fs::error::noent;
@@ -506,7 +552,7 @@ bool fs::statfs(const std::string& path, fs::device_stat& info)
// Keep cutting path from right until it's short enough
while (str.size() > 256)
{
if (std::size_t x = str.find_last_of('\\') + 1)
if (usz x = str.find_last_of('\\') + 1)
str.resize(x - 1);
else
break;
@@ -900,14 +946,29 @@ bool fs::utime(const std::string& path, s64 atime, s64 mtime)
#endif
}
void fs::file::xnull() const
void fs::sync()
{
fmt::throw_exception("fs::file is null");
#ifdef _WIN32
fs::g_tls_error = fs::error::unknown;
#else
::sync();
fs::g_tls_error = fs::error::ok;
#endif
}
void fs::file::xfail() const
[[noreturn]] void fs::xnull(const src_loc& loc)
{
fmt::throw_exception("Unexpected fs::error %s", g_tls_error);
fmt::throw_exception("Null object.%s", loc);
}
[[noreturn]] void fs::xfail(const src_loc& loc)
{
fmt::throw_exception("Unexpected fs::error %s%s", g_tls_error, loc);
}
[[noreturn]] void fs::xovfl()
{
fmt::throw_exception("Stream overflow.");
}
fs::file::file(const std::string& path, bs_t<open_mode> mode)
@@ -990,7 +1051,7 @@ fs::file::file(const std::string& path, bs_t<open_mode> mode)
stat_t stat() override
{
FILE_BASIC_INFO basic_info;
verify("file::stat" HERE), GetFileInformationByHandleEx(m_handle, FileBasicInfo, &basic_info, sizeof(FILE_BASIC_INFO));
ensure(GetFileInformationByHandleEx(m_handle, FileBasicInfo, &basic_info, sizeof(FILE_BASIC_INFO))); // "file::stat"
stat_t info;
info.is_directory = (basic_info.FileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
@@ -1008,7 +1069,7 @@ fs::file::file(const std::string& path, bs_t<open_mode> mode)
void sync() override
{
verify("file::sync" HERE), FlushFileBuffers(m_handle);
ensure(FlushFileBuffers(m_handle)); // "file::sync"
}
bool trunc(u64 length) override
@@ -1028,10 +1089,10 @@ fs::file::file(const std::string& path, bs_t<open_mode> mode)
u64 read(void* buffer, u64 count) override
{
// TODO (call ReadFile multiple times if count is too big)
const int size = narrow<int>(count, "file::read" HERE);
const int size = narrow<int>(count);
DWORD nread;
verify("file::read" HERE), ReadFile(m_handle, buffer, size, &nread, NULL);
ensure(ReadFile(m_handle, buffer, size, &nread, NULL)); // "file::read"
return nread;
}
@@ -1039,24 +1100,27 @@ fs::file::file(const std::string& path, bs_t<open_mode> mode)
u64 write(const void* buffer, u64 count) override
{
// TODO (call WriteFile multiple times if count is too big)
const int size = narrow<int>(count, "file::write" HERE);
const int size = narrow<int>(count);
DWORD nwritten;
verify("file::write" HERE), WriteFile(m_handle, buffer, size, &nwritten, NULL);
ensure(WriteFile(m_handle, buffer, size, &nwritten, NULL)); // "file::write"
return nwritten;
}
u64 seek(s64 offset, seek_mode whence) override
{
if (whence > seek_end)
{
fmt::throw_exception("Invalid whence (0x%x)", whence);
}
LARGE_INTEGER pos;
pos.QuadPart = offset;
const DWORD mode =
whence == seek_set ? FILE_BEGIN :
whence == seek_cur ? FILE_CURRENT :
whence == seek_end ? FILE_END :
(fmt::throw_exception("Invalid whence (0x%x)" HERE, whence), 0);
whence == seek_cur ? FILE_CURRENT : FILE_END;
if (!SetFilePointerEx(m_handle, pos, &pos, mode))
{
@@ -1070,7 +1134,7 @@ fs::file::file(const std::string& path, bs_t<open_mode> mode)
u64 size() override
{
LARGE_INTEGER size;
verify("file::size" HERE), GetFileSizeEx(m_handle, &size);
ensure(GetFileSizeEx(m_handle, &size)); // "file::size"
return size.QuadPart;
}
@@ -1091,13 +1155,22 @@ fs::file::file(const std::string& path, bs_t<open_mode> mode)
if (mode & fs::append) flags |= O_APPEND;
if (mode & fs::create) flags |= O_CREAT;
if (mode & fs::trunc && !(mode & (fs::lock + fs::unread))) flags |= O_TRUNC;
if (mode & fs::trunc && !(mode & fs::lock)) flags |= O_TRUNC;
if (mode & fs::excl) flags |= O_EXCL;
int perm = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
if (mode & fs::write && mode & fs::unread)
{
if (!(mode & (fs::excl + fs::lock)) && mode & fs::trunc)
{
// Alternative to truncation for "unread" flag (TODO)
if (mode & fs::create)
{
::unlink(path.c_str());
}
}
perm = 0;
}
@@ -1109,17 +1182,17 @@ fs::file::file(const std::string& path, bs_t<open_mode> mode)
return;
}
if (mode & fs::write && mode & (fs::lock + fs::unread) && ::flock(fd, LOCK_EX | LOCK_NB) != 0)
if (mode & fs::write && mode & fs::lock && ::flock(fd, LOCK_EX | LOCK_NB) != 0)
{
g_tls_error = errno == EWOULDBLOCK ? fs::error::acces : to_error(errno);
::close(fd);
return;
}
if (mode & fs::trunc && mode & (fs::lock + fs::unread) && mode & fs::write)
if (mode & fs::trunc && mode & fs::lock && mode & fs::write)
{
// Postpone truncation in order to avoid using O_TRUNC on a locked file
verify(HERE), ::ftruncate(fd, 0) == 0;
ensure(::ftruncate(fd, 0) == 0);
}
class unix_file final : public file_base
@@ -1140,7 +1213,7 @@ fs::file::file(const std::string& path, bs_t<open_mode> mode)
stat_t stat() override
{
struct ::stat file_info;
verify("file::stat" HERE), ::fstat(m_fd, &file_info) == 0;
ensure(::fstat(m_fd, &file_info) == 0); // "file::stat"
stat_t info;
info.is_directory = S_ISDIR(file_info.st_mode);
@@ -1158,7 +1231,7 @@ fs::file::file(const std::string& path, bs_t<open_mode> mode)
void sync() override
{
verify("file::sync" HERE), ::fsync(m_fd) == 0;
ensure(::fsync(m_fd) == 0); // "file::sync"
}
bool trunc(u64 length) override
@@ -1175,7 +1248,7 @@ fs::file::file(const std::string& path, bs_t<open_mode> mode)
u64 read(void* buffer, u64 count) override
{
const auto result = ::read(m_fd, buffer, count);
verify("file::read" HERE), result != -1;
ensure(result != -1); // "file::read"
return result;
}
@@ -1183,18 +1256,21 @@ fs::file::file(const std::string& path, bs_t<open_mode> mode)
u64 write(const void* buffer, u64 count) override
{
const auto result = ::write(m_fd, buffer, count);
verify("file::write" HERE), result != -1;
ensure(result != -1); // "file::write"
return result;
}
u64 seek(s64 offset, seek_mode whence) override
{
if (whence > seek_end)
{
fmt::throw_exception("Invalid whence (0x%x)", whence);
}
const int mode =
whence == seek_set ? SEEK_SET :
whence == seek_cur ? SEEK_CUR :
whence == seek_end ? SEEK_END :
(fmt::throw_exception("Invalid whence (0x%x)" HERE, whence), 0);
whence == seek_cur ? SEEK_CUR : SEEK_END;
const auto result = ::lseek(m_fd, offset, mode);
@@ -1210,7 +1286,7 @@ fs::file::file(const std::string& path, bs_t<open_mode> mode)
u64 size() override
{
struct ::stat file_info;
verify("file::size" HERE), ::fstat(m_fd, &file_info) == 0;
ensure(::fstat(m_fd, &file_info) == 0); // "file::size"
return file_info.st_size;
}
@@ -1226,7 +1302,7 @@ fs::file::file(const std::string& path, bs_t<open_mode> mode)
static_assert(offsetof(iovec, iov_len) == offsetof(iovec_clone, iov_len), "Weird iovec::iov_len offset");
const auto result = ::writev(m_fd, reinterpret_cast<const iovec*>(buffers), buf_count);
verify("file::write_gather" HERE), result != -1;
ensure(result != -1); // "file::write_gather"
return result;
}
@@ -1236,7 +1312,7 @@ fs::file::file(const std::string& path, bs_t<open_mode> mode)
#endif
}
fs::file::file(const void* ptr, std::size_t size)
fs::file::file(const void* ptr, usz size)
{
class memory_stream : public file_base
{
@@ -1318,11 +1394,6 @@ fs::native_handle fs::file::get_handle() const
#endif
}
void fs::dir::xnull() const
{
fmt::throw_exception("fs::dir is null");
}
bool fs::dir::open(const std::string& path)
{
if (path.empty())
@@ -1356,7 +1427,7 @@ bool fs::dir::open(const std::string& path)
class windows_dir final : public dir_base
{
std::vector<dir_entry> m_entries;
std::size_t m_pos = 0;
usz m_pos = 0;
void add_entry(const WIN32_FIND_DATAW& found)
{
@@ -1386,7 +1457,7 @@ bool fs::dir::open(const std::string& path)
add_entry(found);
}
verify("dir::read" HERE), ERROR_NO_MORE_FILES == GetLastError();
ensure(ERROR_NO_MORE_FILES == GetLastError()); // "dir::read"
FindClose(handle);
}
@@ -1606,13 +1677,13 @@ std::string fs::escape_path(std::string_view path)
{
std::string real; real.resize(path.size());
auto get_char = [&](std::size_t& from, std::size_t& to, std::size_t count)
auto get_char = [&](usz& from, usz& to, usz count)
{
std::memcpy(&real[to], &path[from], count);
from += count, to += count;
};
std::size_t i = 0, j = -1, pos_nondelim = 0, after_delim = 0;
usz i = 0, j = -1, pos_nondelim = 0, after_delim = 0;
if (i < path.size())
{
@@ -1649,7 +1720,7 @@ std::string fs::escape_path(std::string_view path)
case '.':
{
bool remove_element = true;
std::size_t k = 1;
usz k = 1;
for (; k + i != path.size(); k++)
{
@@ -1714,7 +1785,7 @@ u64 fs::get_dir_size(const std::string& path, u64 rounding_alignment)
if (!root_dir)
{
return static_cast<u64>(umax);
return -1;
}
for (const auto& entry : root_dir)
@@ -1726,7 +1797,7 @@ u64 fs::get_dir_size(const std::string& path, u64 rounding_alignment)
if (!entry.is_directory)
{
result += ::align(entry.size, rounding_alignment);
result += utils::align(entry.size, rounding_alignment);
}
else
{
@@ -1859,6 +1930,55 @@ fs::file fs::make_gather(std::vector<fs::file> files)
return result;
}
fs::pending_file::pending_file(const std::string& path)
{
do
{
m_path = fmt::format(u8"%s/%s.%s.tmp", get_parent_dir(path), std::string_view(path).substr(path.find_last_of(fs::delim) + 1), fmt::base57(utils::get_unique_tsc()));
if (file.open(m_path, fs::create + fs::write + fs::read + fs::excl))
{
m_dest = path;
break;
}
m_path.clear();
}
while (fs::g_tls_error == fs::error::exist); // Only retry if failed due to existing file
}
fs::pending_file::~pending_file()
{
file.close();
if (!m_path.empty())
{
fs::remove_file(m_path);
}
}
bool fs::pending_file::commit(bool overwrite)
{
if (!file || m_path.empty())
{
fs::g_tls_error = fs::error::noent;
return false;
}
// The temporary file's contents must be on disk before rename
file.sync();
file.close();
if (fs::rename(m_path, m_dest, overwrite))
{
// Disable the destructor
m_path.clear();
return true;
}
return false;
}
template<>
void fmt_class_string<fs::seek_mode>::format(std::string& out, u64 arg)
{
+197 -63
View File
@@ -1,6 +1,6 @@
#pragma once
#pragma once // No BOM and only basic ASCII in this header, or a neko will die
#include "types.h"
#include "util/types.hpp"
#include "bit_set.h"
#include <memory>
@@ -73,7 +73,7 @@ namespace fs
struct iovec_clone
{
const void* iov_base;
std::size_t iov_len;
usz iov_len;
};
// File handle base
@@ -96,6 +96,11 @@ namespace fs
struct dir_entry : stat_t
{
std::string name;
dir_entry()
: stat_t{}
{
}
};
// Directory handle base
@@ -134,6 +139,12 @@ namespace fs
virtual std::unique_ptr<dir_base> open_dir(const std::string& path) = 0;
};
[[noreturn]] void xnull(const src_loc&);
[[noreturn]] void xfail(const src_loc&);
[[noreturn]] void xovfl();
constexpr struct pod_tag_t{} pod_tag;
// Get virtual device for specified path (nullptr for real path)
std::shared_ptr<device_base> get_virtual_device(const std::string& path);
@@ -182,13 +193,13 @@ namespace fs
// Set file access/modification time
bool utime(const std::string& path, s64 atime, s64 mtime);
// Synchronize filesystems (TODO)
void sync();
class file final
{
std::unique_ptr<file_base> m_file;
[[noreturn]] void xnull() const;
[[noreturn]] void xfail() const;
public:
// Default constructor
file() = default;
@@ -197,7 +208,7 @@ namespace fs
explicit file(const std::string& path, bs_t<open_mode> mode = ::fs::read);
// Open memory for read
explicit file(const void* ptr, std::size_t size);
explicit file(const void* ptr, usz size);
// Open file with specified args (forward to constructor)
template <typename... Args>
@@ -230,144 +241,227 @@ namespace fs
}
// Change file size (possibly appending zero bytes)
bool trunc(u64 length) const
bool trunc(u64 length,
u32 line = __builtin_LINE(),
u32 col = __builtin_COLUMN(),
const char* file = __builtin_FILE(),
const char* func = __builtin_FUNCTION()) const
{
if (!m_file) xnull();
if (!m_file) xnull({line, col, file, func});
return m_file->trunc(length);
}
// Get file information
stat_t stat() const
stat_t stat(
u32 line = __builtin_LINE(),
u32 col = __builtin_COLUMN(),
const char* file = __builtin_FILE(),
const char* func = __builtin_FUNCTION()) const
{
if (!m_file) xnull();
if (!m_file) xnull({line, col, file, func});
return m_file->stat();
}
// Sync file buffers
void sync() const
void sync(
u32 line = __builtin_LINE(),
u32 col = __builtin_COLUMN(),
const char* file = __builtin_FILE(),
const char* func = __builtin_FUNCTION()) const
{
if (!m_file) xnull();
if (!m_file) xnull({line, col, file, func});
return m_file->sync();
}
// Read the data from the file and return the amount of data written in buffer
u64 read(void* buffer, u64 count) const
u64 read(void* buffer, u64 count,
u32 line = __builtin_LINE(),
u32 col = __builtin_COLUMN(),
const char* file = __builtin_FILE(),
const char* func = __builtin_FUNCTION()) const
{
if (!m_file) xnull();
if (!m_file) xnull({line, col, file, func});
return m_file->read(buffer, count);
}
// Write the data to the file and return the amount of data actually written
u64 write(const void* buffer, u64 count) const
u64 write(const void* buffer, u64 count,
u32 line = __builtin_LINE(),
u32 col = __builtin_COLUMN(),
const char* file = __builtin_FILE(),
const char* func = __builtin_FUNCTION()) const
{
if (!m_file) xnull();
if (!m_file) xnull({line, col, file, func});
return m_file->write(buffer, count);
}
// Change current position, returns resulting position
u64 seek(s64 offset, seek_mode whence = seek_set) const
u64 seek(s64 offset, seek_mode whence = seek_set,
u32 line = __builtin_LINE(),
u32 col = __builtin_COLUMN(),
const char* file = __builtin_FILE(),
const char* func = __builtin_FUNCTION()) const
{
if (!m_file) xnull();
if (!m_file) xnull({line, col, file, func});
return m_file->seek(offset, whence);
}
// Get file size
u64 size() const
u64 size(
u32 line = __builtin_LINE(),
u32 col = __builtin_COLUMN(),
const char* file = __builtin_FILE(),
const char* func = __builtin_FUNCTION()) const
{
if (!m_file) xnull();
if (!m_file) xnull({line, col, file, func});
return m_file->size();
}
// Get current position
u64 pos() const
u64 pos(
u32 line = __builtin_LINE(),
u32 col = __builtin_COLUMN(),
const char* file = __builtin_FILE(),
const char* func = __builtin_FUNCTION()) const
{
if (!m_file) xnull();
if (!m_file) xnull({line, col, file, func});
return m_file->seek(0, seek_cur);
}
// Write std::string unconditionally
const file& write(const std::string& str) const
// Write std::basic_string unconditionally
template <typename T>
std::enable_if_t<std::is_trivially_copyable_v<T> && !std::is_pointer_v<T>, const file&> write(const std::basic_string<T>& str,
u32 line = __builtin_LINE(),
u32 col = __builtin_COLUMN(),
const char* file = __builtin_FILE(),
const char* func = __builtin_FUNCTION()) const
{
if (write(str.data(), str.size()) != str.size()) xfail();
if (write(str.data(), str.size() * sizeof(T), line, col, file, func) != str.size() * sizeof(T)) xfail({line, col, file, func});
return *this;
}
// Write POD unconditionally
template <typename T>
std::enable_if_t<std::is_trivially_copyable_v<T> && !std::is_pointer_v<T>, const file&> write(const T& data) const
std::enable_if_t<std::is_trivially_copyable_v<T> && !std::is_pointer_v<T>, const file&> write(const T& data,
pod_tag_t = pod_tag,
u32 line = __builtin_LINE(),
u32 col = __builtin_COLUMN(),
const char* file = __builtin_FILE(),
const char* func = __builtin_FUNCTION()) const
{
if (write(std::addressof(data), sizeof(T)) != sizeof(T)) xfail();
if (write(std::addressof(data), sizeof(T), line, col, file, func) != sizeof(T)) xfail({line, col, file, func});
return *this;
}
// Write POD std::vector unconditionally
template <typename T>
std::enable_if_t<std::is_trivially_copyable_v<T> && !std::is_pointer_v<T>, const file&> write(const std::vector<T>& vec) const
std::enable_if_t<std::is_trivially_copyable_v<T> && !std::is_pointer_v<T>, const file&> write(const std::vector<T>& vec,
u32 line = __builtin_LINE(),
u32 col = __builtin_COLUMN(),
const char* file = __builtin_FILE(),
const char* func = __builtin_FUNCTION()) const
{
if (write(vec.data(), vec.size() * sizeof(T)) != vec.size() * sizeof(T)) xfail();
if (write(vec.data(), vec.size() * sizeof(T), line, col, file, func) != vec.size() * sizeof(T)) xfail({line, col, file, func});
return *this;
}
// Read std::string, size must be set by resize() method
bool read(std::string& str) const
// Read std::basic_string, size must be set by resize() method
template <typename T>
std::enable_if_t<std::is_trivially_copyable_v<T> && !std::is_pointer_v<T>, bool> read(std::basic_string<T>& str,
const char* file = __builtin_FILE(),
const char* func = __builtin_FUNCTION(),
u32 line = __builtin_LINE(),
u32 col = __builtin_COLUMN()) const
{
return read(&str[0], str.size()) == str.size();
return read(&str[0], str.size() * sizeof(T), line, col, file, func) == str.size() * sizeof(T);
}
// Read std::string
bool read(std::string& str, std::size_t size) const
// Read std::basic_string
template <typename T>
std::enable_if_t<std::is_trivially_copyable_v<T> && !std::is_pointer_v<T>, bool> read(std::basic_string<T>& str, usz size,
const char* file = __builtin_FILE(),
const char* func = __builtin_FUNCTION(),
u32 line = __builtin_LINE(),
u32 col = __builtin_COLUMN()) const
{
str.resize(size);
return read(&str[0], size) == size;
return read(&str[0], size * sizeof(T), line, col, file, func) == size * sizeof(T);
}
// Read POD, sizeof(T) is used
template <typename T>
std::enable_if_t<std::is_trivially_copyable_v<T> && !std::is_pointer_v<T>, bool> read(T& data) const
std::enable_if_t<std::is_trivially_copyable_v<T> && !std::is_pointer_v<T>, bool> read(T& data,
pod_tag_t = pod_tag,
u32 line = __builtin_LINE(),
u32 col = __builtin_COLUMN(),
const char* file = __builtin_FILE(),
const char* func = __builtin_FUNCTION()) const
{
return read(&data, sizeof(T)) == sizeof(T);
return read(&data, sizeof(T), line, col, file, func) == sizeof(T);
}
// Read POD std::vector, size must be set by resize() method
template <typename T>
std::enable_if_t<std::is_trivially_copyable_v<T> && !std::is_pointer_v<T>, bool> read(std::vector<T>& vec) const
std::enable_if_t<std::is_trivially_copyable_v<T> && !std::is_pointer_v<T>, bool> read(std::vector<T>& vec,
const char* file = __builtin_FILE(),
const char* func = __builtin_FUNCTION(),
u32 line = __builtin_LINE(),
u32 col = __builtin_COLUMN()) const
{
return read(vec.data(), sizeof(T) * vec.size()) == sizeof(T) * vec.size();
return read(vec.data(), sizeof(T) * vec.size(), line, col, file, func) == sizeof(T) * vec.size();
}
// Read POD std::vector
template <typename T>
std::enable_if_t<std::is_trivially_copyable_v<T> && !std::is_pointer_v<T>, bool> read(std::vector<T>& vec, std::size_t size) const
std::enable_if_t<std::is_trivially_copyable_v<T> && !std::is_pointer_v<T>, bool> read(std::vector<T>& vec, usz size,
const char* file = __builtin_FILE(),
const char* func = __builtin_FUNCTION(),
u32 line = __builtin_LINE(),
u32 col = __builtin_COLUMN()) const
{
vec.resize(size);
return read(vec.data(), sizeof(T) * size) == sizeof(T) * size;
return read(vec.data(), sizeof(T) * size, line, col, file, func) == sizeof(T) * size;
}
// Read POD (experimental)
template <typename T>
std::enable_if_t<std::is_trivially_copyable_v<T> && !std::is_pointer_v<T>, T> read() const
std::enable_if_t<std::is_trivially_copyable_v<T> && !std::is_pointer_v<T>, T> read(
pod_tag_t = pod_tag,
u32 line = __builtin_LINE(),
u32 col = __builtin_COLUMN(),
const char* file = __builtin_FILE(),
const char* func = __builtin_FUNCTION()) const
{
T result;
if (!read(result)) xfail();
if (!read(result, pod_tag, line, col, file, func)) xfail({line, col, file, func});
return result;
}
// Read full file to std::string
std::string to_string() const
// Read full file to std::basic_string
template <typename T = char>
std::basic_string<T> to_string(
u32 line = __builtin_LINE(),
u32 col = __builtin_COLUMN(),
const char* file = __builtin_FILE(),
const char* func = __builtin_FUNCTION()) const
{
std::string result;
result.resize(size());
if (seek(0), !read(result)) xfail();
std::basic_string<T> result;
result.resize(size() / sizeof(T));
if (seek(0), !read(result, file, func, line, col)) xfail({line, col, file, func});
return result;
}
// Read full file to std::vector
template<typename T>
std::enable_if_t<std::is_trivially_copyable_v<T> && !std::is_pointer_v<T>, std::vector<T>> to_vector() const
std::enable_if_t<std::is_trivially_copyable_v<T> && !std::is_pointer_v<T>, std::vector<T>> to_vector(
u32 line = __builtin_LINE(),
u32 col = __builtin_COLUMN(),
const char* file = __builtin_FILE(),
const char* func = __builtin_FUNCTION()) const
{
std::vector<T> result;
result.resize(size() / sizeof(T));
if (seek(0), !read(result)) xfail();
if (seek(0), !read(result, file, func, line, col)) xfail({line, col, file, func});
return result;
}
@@ -375,9 +469,13 @@ namespace fs
native_handle get_handle() const;
// Gathered write
u64 write_gather(const iovec_clone* buffers, u64 buf_count) const
u64 write_gather(const iovec_clone* buffers, u64 buf_count,
u32 line = __builtin_LINE(),
u32 col = __builtin_COLUMN(),
const char* file = __builtin_FILE(),
const char* func = __builtin_FUNCTION()) const
{
if (!m_file) xnull();
if (!m_file) xnull({line, col, file, func});
return m_file->write_gather(buffers, buf_count);
}
};
@@ -386,8 +484,6 @@ namespace fs
{
std::unique_ptr<dir_base> m_dir;
[[noreturn]] void xnull() const;
public:
dir() = default;
@@ -423,16 +519,24 @@ namespace fs
}
// Get next directory entry
bool read(dir_entry& out) const
bool read(dir_entry& out,
u32 line = __builtin_LINE(),
u32 col = __builtin_COLUMN(),
const char* file = __builtin_FILE(),
const char* func = __builtin_FUNCTION()) const
{
if (!m_dir) xnull();
if (!m_dir) xnull({line, col, file, func});
return m_dir->read(out);
}
// Reset to the beginning
void rewind() const
void rewind(
u32 line = __builtin_LINE(),
u32 col = __builtin_COLUMN(),
const char* file = __builtin_FILE(),
const char* func = __builtin_FUNCTION()) const
{
if (!m_dir) xnull();
if (!m_dir) xnull({line, col, file, func});
return m_dir->rewind();
}
@@ -501,6 +605,22 @@ namespace fs
// Get common cache directory
const std::string& get_cache_dir();
// Unique pending file creation destined to be renamed to the destination file
struct pending_file
{
fs::file file;
// This is meant to modify files atomically, overwriting is likely
bool commit(bool overwrite = true);
pending_file(const std::string& path);
~pending_file();
private:
std::string m_path; // Pending file path
std::string m_dest; // Destination file path
};
// Get real path for comparisons (TODO: investigate std::filesystem::path::compare implementation)
std::string escape_path(std::string_view path);
@@ -578,7 +698,7 @@ namespace fs
if (old_size + size < old_size)
{
fmt::raw_error("fs::container_stream<>::write(): overflow");
xovfl();
}
if (pos > old_size)
@@ -631,14 +751,28 @@ namespace fs
return result;
}
template <typename... Args>
template <bool Flush = false, typename... Args>
bool write_file(const std::string& path, bs_t<fs::open_mode> mode, const Args&... args)
{
// Always use write flag, remove read flag
if (fs::file f{path, mode + fs::write - fs::read})
{
// Write args sequentially
(f.write(args), ...);
if constexpr (sizeof...(args) == 2u && (std::is_pointer_v<Args> || ...))
{
// Specialization for [const void*, usz] args
f.write(args...);
}
else
{
// Write args sequentially
(f.write(args), ...);
}
if constexpr (Flush)
{
f.sync();
}
return true;
}
+119 -43
View File
@@ -1,16 +1,17 @@
#include "types.h"
#include "util/types.hpp"
#include "util/sysinfo.hpp"
#include "JIT.h"
#include "StrFmt.h"
#include "File.h"
#include "util/logs.hpp"
#include "mutex.h"
#include "sysinfo.h"
#include "VirtualMemory.h"
#include "util/vm.hpp"
#include "util/asm.hpp"
#include <charconv>
#include <immintrin.h>
#include <zlib.h>
#ifdef __linux__
#include <sys/mman.h>
#define CAN_OVERCOMMIT
#endif
@@ -22,7 +23,6 @@ static u8* get_jit_memory()
static void* const s_memory2 = []() -> void*
{
void* ptr = utils::memory_reserve(0x80000000);
#ifdef CAN_OVERCOMMIT
utils::memory_commit(ptr, 0x80000000);
utils::memory_protect(ptr, 0x40000000, utils::protection::wx);
@@ -40,7 +40,7 @@ static atomic_t<u64> s_code_pos{0}, s_data_pos{0};
static std::vector<u8> s_code_init, s_data_init;
template <atomic_t<u64>& Ctr, uint Off, utils::protection Prot>
static u8* add_jit_memory(std::size_t size, uint align)
static u8* add_jit_memory(usz size, uint align)
{
// Select subrange
u8* pointer = get_jit_memory() + Off;
@@ -56,8 +56,8 @@ static u8* add_jit_memory(std::size_t size, uint align)
// Simple allocation by incrementing pointer to the next free data
const u64 pos = Ctr.atomic_op([&](u64& ctr) -> u64
{
const u64 _pos = ::align(ctr & 0xffff'ffff, align);
const u64 _new = ::align(_pos + size, align);
const u64 _pos = utils::align(ctr & 0xffff'ffff, align);
const u64 _new = utils::align(_pos + size, align);
if (_new > 0x40000000) [[unlikely]]
{
@@ -73,7 +73,7 @@ static u8* add_jit_memory(std::size_t size, uint align)
// Check the necessity to commit more memory
if (_new > olda) [[unlikely]]
{
newa = ::align(_new, 0x100000);
newa = utils::align(_new, 0x200000);
}
ctr += _new - (ctr & 0xffff'ffff);
@@ -82,15 +82,13 @@ static u8* add_jit_memory(std::size_t size, uint align)
if (pos == umax) [[unlikely]]
{
jit_log.error("JIT: Out of memory (size=0x%x, align=0x%x, off=0x%x)", size, align, Off);
jit_log.error("Out of memory (size=0x%x, align=0x%x, off=0x%x)", size, align, Off);
return nullptr;
}
if (olda != newa) [[unlikely]]
{
#ifdef CAN_OVERCOMMIT
madvise(pointer + olda, newa - olda, MADV_WILLNEED);
#else
#ifndef CAN_OVERCOMMIT
// Commit more memory
utils::memory_commit(pointer + olda, newa - olda, Prot);
#endif
@@ -118,7 +116,7 @@ jit_runtime::~jit_runtime()
asmjit::Error jit_runtime::_add(void** dst, asmjit::CodeHolder* code) noexcept
{
std::size_t codeSize = code->getCodeSize();
usz codeSize = code->getCodeSize();
if (!codeSize) [[unlikely]]
{
*dst = nullptr;
@@ -132,7 +130,7 @@ asmjit::Error jit_runtime::_add(void** dst, asmjit::CodeHolder* code) noexcept
return asmjit::kErrorNoVirtualMemory;
}
std::size_t relocSize = code->relocate(p);
usz relocSize = code->relocate(p);
if (!relocSize) [[unlikely]]
{
*dst = nullptr;
@@ -150,7 +148,7 @@ asmjit::Error jit_runtime::_release(void* ptr) noexcept
return asmjit::kErrorOk;
}
u8* jit_runtime::alloc(std::size_t size, uint align, bool exec) noexcept
u8* jit_runtime::alloc(usz size, uint align, bool exec) noexcept
{
if (exec)
{
@@ -222,28 +220,29 @@ asmjit::Runtime& asmjit::get_global_runtime()
asmjit::Error _add(void** dst, asmjit::CodeHolder* code) noexcept override
{
std::size_t codeSize = code->getCodeSize();
usz codeSize = code->getCodeSize();
if (!codeSize) [[unlikely]]
{
*dst = nullptr;
return asmjit::kErrorNoCodeGenerated;
}
void* p = m_pos.fetch_add(::align(codeSize, 4096));
void* p = m_pos.fetch_add(utils::align(codeSize, 4096));
if (!p || m_pos > m_max) [[unlikely]]
{
*dst = nullptr;
jit_log.fatal("Out of memory (static asmjit)");
return asmjit::kErrorNoVirtualMemory;
}
std::size_t relocSize = code->relocate(p);
usz relocSize = code->relocate(p);
if (!relocSize) [[unlikely]]
{
*dst = nullptr;
return asmjit::kErrorInvalidState;
}
utils::memory_protect(p, ::align(codeSize, 4096), utils::protection::rx);
utils::memory_protect(p, utils::align(codeSize, 4096), utils::protection::rx);
flush(p, relocSize);
*dst = p;
@@ -310,14 +309,74 @@ const bool jit_initialize = []() -> bool
return true;
}();
[[noreturn]] static void null(const char* name)
{
fmt::throw_exception("Null function: %s", name);
}
namespace vm
{
extern u8* const g_sudo_addr;
}
static shared_mutex null_mtx;
static std::unordered_map<std::string, u64> null_funcs;
static u64 make_null_function(const std::string& name)
{
if (name.starts_with("__0x"))
{
u32 addr = -1;
auto res = std::from_chars(name.c_str() + 4, name.c_str() + name.size(), addr, 16);
if (res.ec == std::errc() && res.ptr == name.c_str() + name.size() && addr < 0x8000'0000)
{
// Point the garbage to reserved, non-executable memory
return reinterpret_cast<u64>(vm::g_sudo_addr + addr);
}
}
std::lock_guard lock(null_mtx);
if (u64& func_ptr = null_funcs[name]) [[likely]]
{
// Already exists
return func_ptr;
}
else
{
using namespace asmjit;
// Build a "null" function that contains its name
const auto func = build_function_asm<void (*)()>([&](X86Assembler& c, auto& args)
{
Label data = c.newLabel();
c.lea(args[0], x86::qword_ptr(data, 0));
c.jmp(imm_ptr(&null));
c.align(kAlignCode, 16);
c.bind(data);
// Copy function name bytes
for (char ch : name)
c.db(ch);
c.db(0);
c.align(kAlignData, 16);
});
func_ptr = reinterpret_cast<u64>(func);
return func_ptr;
}
}
// Simple memory manager
struct MemoryManager1 : llvm::RTDyldMemoryManager
{
// 256 MiB for code or data
static constexpr u64 c_max_size = 0x20000000 / 2;
// Allocation unit
static constexpr u64 c_page_size = 4096;
// Allocation unit (2M)
static constexpr u64 c_page_size = 2 * 1024 * 1024;
// Reserve 512 MiB
u8* const ptr = static_cast<u8*>(utils::memory_reserve(c_max_size * 2));
@@ -332,45 +391,45 @@ struct MemoryManager1 : llvm::RTDyldMemoryManager
utils::memory_release(ptr, c_max_size * 2);
}
[[noreturn]] static void null()
{
fmt::throw_exception("Null function" HERE);
}
llvm::JITSymbol findSymbol(const std::string& name) override
{
u64 addr = RTDyldMemoryManager::getSymbolAddress(name);
if (!addr)
{
addr = reinterpret_cast<uptr>(&null);
addr = make_null_function(name);
if (!addr)
{
fmt::throw_exception("Failed to link '%s'", name);
}
}
return {addr, llvm::JITSymbolFlags::Exported};
}
u8* allocate(u64& oldp, std::uintptr_t size, uint align, utils::protection prot)
u8* allocate(u64& oldp, uptr size, uint align, utils::protection prot)
{
if (align > c_page_size)
{
jit_log.fatal("JIT: Unsupported alignment (size=0x%x, align=0x%x)", size, align);
jit_log.fatal("Unsupported alignment (size=0x%x, align=0x%x)", size, align);
return nullptr;
}
const u64 olda = ::align(oldp, align);
const u64 newp = ::align(olda + size, align);
const u64 olda = utils::align(oldp, align);
const u64 newp = utils::align(olda + size, align);
if ((newp - 1) / c_max_size != oldp / c_max_size)
{
jit_log.fatal("JIT: Out of memory (size=0x%x, align=0x%x)", size, align);
jit_log.fatal("Out of memory (size=0x%x, align=0x%x)", size, align);
return nullptr;
}
if ((oldp - 1) / c_page_size != (newp - 1) / c_page_size)
{
// Allocate pages on demand
const u64 pagea = ::align(oldp, c_page_size);
const u64 psize = ::align(newp - pagea, c_page_size);
const u64 pagea = utils::align(oldp, c_page_size);
const u64 psize = utils::align(newp - pagea, c_page_size);
utils::memory_commit(this->ptr + pagea, psize, prot);
}
@@ -380,12 +439,12 @@ struct MemoryManager1 : llvm::RTDyldMemoryManager
return this->ptr + olda;
}
u8* allocateCodeSection(std::uintptr_t size, uint align, uint sec_id, llvm::StringRef sec_name) override
u8* allocateCodeSection(uptr size, uint align, uint sec_id, llvm::StringRef sec_name) override
{
return allocate(code_ptr, size, align, utils::protection::wx);
}
u8* allocateDataSection(std::uintptr_t size, uint align, uint sec_id, llvm::StringRef sec_name, bool is_ro) override
u8* allocateDataSection(uptr size, uint align, uint sec_id, llvm::StringRef sec_name, bool is_ro) override
{
return allocate(data_ptr, size, align, utils::protection::rw);
}
@@ -395,7 +454,7 @@ struct MemoryManager1 : llvm::RTDyldMemoryManager
return false;
}
void registerEHFrames(u8* addr, u64 load_addr, std::size_t size) override
void registerEHFrames(u8* addr, u64 load_addr, usz size) override
{
}
@@ -413,12 +472,29 @@ struct MemoryManager2 : llvm::RTDyldMemoryManager
{
}
u8* allocateCodeSection(std::uintptr_t size, uint align, uint sec_id, llvm::StringRef sec_name) override
llvm::JITSymbol findSymbol(const std::string& name) override
{
u64 addr = RTDyldMemoryManager::getSymbolAddress(name);
if (!addr)
{
addr = make_null_function(name);
if (!addr)
{
fmt::throw_exception("Failed to link '%s' (MM2)", name);
}
}
return {addr, llvm::JITSymbolFlags::Exported};
}
u8* allocateCodeSection(uptr size, uint align, uint sec_id, llvm::StringRef sec_name) override
{
return jit_runtime::alloc(size, align, true);
}
u8* allocateDataSection(std::uintptr_t size, uint align, uint sec_id, llvm::StringRef sec_name, bool is_ro) override
u8* allocateDataSection(uptr size, uint align, uint sec_id, llvm::StringRef sec_name, bool is_ro) override
{
return jit_runtime::alloc(size, align, false);
}
@@ -428,7 +504,7 @@ struct MemoryManager2 : llvm::RTDyldMemoryManager
return false;
}
void registerEHFrames(u8* addr, u64 load_addr, std::size_t size) override
void registerEHFrames(u8* addr, u64 load_addr, usz size) override
{
}
@@ -458,7 +534,7 @@ public:
name.append(".gz");
z_stream zs{};
uLong zsz = compressBound(::narrow<u32>(obj.getBufferSize(), HERE)) + 256;
uLong zsz = compressBound(::narrow<u32>(obj.getBufferSize())) + 256;
auto zbuf = std::make_unique<uchar[]>(zsz);
#ifndef _MSC_VER
#pragma GCC diagnostic push
@@ -683,7 +759,7 @@ jit_compiler::jit_compiler(const std::unordered_map<std::string, u64>& _link, co
for (auto&& [name, addr] : _link)
{
m_engine->addGlobalMapping(name, addr);
m_engine->updateGlobalMapping(name, addr);
}
}
+7 -5
View File
@@ -41,7 +41,7 @@ struct jit_runtime final : asmjit::HostRuntime
asmjit::Error _release(void* p) noexcept override;
// Allocate memory
static u8* alloc(std::size_t size, uint align, bool exec = true) noexcept;
static u8* alloc(usz size, uint align, bool exec = true) noexcept;
// Should be called at least once after global initialization
static void initialize();
@@ -148,7 +148,7 @@ inline FT build_function_asm(F&& builder)
X86Assembler compiler(&code);
builder(std::ref(compiler), args);
ASSERT(compiler.getLastError() == 0);
ensure(compiler.getLastError() == 0);
FT result;
@@ -167,10 +167,9 @@ inline FT build_function_asm(F&& builder)
#include <string_view>
#include <unordered_map>
#include "types.h"
#include "util/types.hpp"
#include "mutex.h"
#include "restore_new.h"
#ifdef _MSC_VER
#pragma warning(push, 0)
#else
@@ -178,6 +177,10 @@ inline FT build_function_asm(F&& builder)
#pragma GCC diagnostic ignored "-Wall"
#pragma GCC diagnostic ignored "-Wextra"
#pragma GCC diagnostic ignored "-Wold-style-cast"
#pragma GCC diagnostic ignored "-Wsuggest-override"
#ifdef __clang__
#pragma clang diagnostic ignored "-Winconsistent-missing-override"
#endif
#endif
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
@@ -187,7 +190,6 @@ inline FT build_function_asm(F&& builder)
#else
#pragma GCC diagnostic pop
#endif
#include "define_new_memleakdetect.h"
// Temporary compiler interface
class jit_compiler final
+108 -86
View File
@@ -1,8 +1,9 @@
#include "StrFmt.h"
#include "BEType.h"
#include "StrFmt.h"
#include "StrUtil.h"
#include "cfmt.h"
#include "util/endian.hpp"
#include "util/logs.hpp"
#include "util/v128.hpp"
#include <algorithm>
#include <string_view>
@@ -78,14 +79,14 @@ void fmt_class_string<fmt::base57>::format(std::string& out, u64 arg)
static constexpr u8 s_tail[8] = {0, 2, 3, 5, 6, 7, 9, 10};
// Get full output size
const std::size_t out_size = _arg.size / 8 * 11 + s_tail[_arg.size % 8];
const usz out_size = _arg.size / 8 * 11 + s_tail[_arg.size % 8];
out.resize(out.size() + out_size);
const auto ptr = &out.front() + (out.size() - out_size);
// Each 8 bytes of input data produce 11 bytes of base57 output
for (std::size_t i = 0, p = 0; i < _arg.size; i += 8, p += 11)
for (usz i = 0, p = 0; i < _arg.size; i += 8, p += 11)
{
// Load up to 8 bytes
be_t<u64> be_value;
@@ -235,6 +236,12 @@ void fmt_class_string<bool>::format(std::string& out, u64 arg)
out += arg ? "true" : "false";
}
template <>
void fmt_class_string<b8>::format(std::string& out, u64 arg)
{
out += get_object(arg) ? "true" : "false";
}
template <>
void fmt_class_string<v128>::format(std::string& out, u64 arg)
{
@@ -242,70 +249,76 @@ void fmt_class_string<v128>::format(std::string& out, u64 arg)
fmt::append(out, "0x%016llx%016llx", vec._u64[1], vec._u64[0]);
}
template <>
void fmt_class_string<u128>::format(std::string& out, u64 arg)
{
// TODO: it should be supported as full-fledged integral type (with %u, %d, etc, fmt)
const u128& num = get_object(arg);
#ifdef _MSC_VER
fmt::append(out, "0x%016llx%016llx", num.hi, num.lo);
#else
fmt::append(out, "0x%016llx%016llx", static_cast<u64>(num >> 64), static_cast<u64>(num));
#endif
}
template <>
void fmt_class_string<src_loc>::format(std::string& out, u64 arg)
{
const src_loc& loc = get_object(arg);
if (loc.col != umax)
{
fmt::append(out, "\n(in file %s:%u[:%u]", loc.file, loc.line, loc.col);
}
else
{
fmt::append(out, "\n(in file %s:%u", loc.file, loc.line);
}
if (loc.func && *loc.func)
{
fmt::append(out, ", in function %s)", loc.func);
}
else
{
out += ')';
}
// Print error code (may be irrelevant)
#ifdef _WIN32
if (DWORD error = GetLastError())
{
fmt::append(out, " (e=0x%08x[%u])", error, error);
}
#else
if (int error = errno)
{
fmt::append(out, " (errno=%d)", error);
}
#endif
}
namespace fmt
{
void raw_error(const char* msg)
{
thread_ctrl::emergency_exit(msg);
}
void raw_verify_error(const char* msg, const fmt_type_info* sup, u64 arg)
[[noreturn]] void raw_verify_error(const src_loc& loc)
{
std::string out{"Verification failed"};
// Print error code (may be irrelevant)
#ifdef _WIN32
if (DWORD error = GetLastError())
{
fmt::append(out, " (e=%#x)", error);
}
#else
if (int error = errno)
{
fmt::append(out, " (e=%d)", error);
}
#endif
if (sup)
{
out += " (";
sup->fmt_string(out, arg); // Print value
out += ")";
}
if (msg)
{
out += ": ";
out += msg;
}
fmt::append(out, "%s", loc);
thread_ctrl::emergency_exit(out);
}
void raw_narrow_error(const char* msg, const fmt_type_info* sup, u64 arg)
[[noreturn]] void raw_narrow_error(const src_loc& loc)
{
std::string out{"Narrow error"};
if (sup)
{
out += " (";
sup->fmt_string(out, arg); // Print value
out += ")";
}
if (msg)
{
out += ": ";
out += msg;
}
std::string out{"Narrowing error"};
fmt::append(out, "%s", loc);
thread_ctrl::emergency_exit(out);
}
void raw_throw_exception(const char* fmt, const fmt_type_info* sup, const u64* args)
[[noreturn]] void raw_throw_exception(const src_loc& loc, const char* fmt, const fmt_type_info* sup, const u64* args)
{
std::string out;
raw_append(out, fmt, sup, args);
fmt::append(out, "%s", loc);
thread_ctrl::emergency_exit(out);
}
@@ -318,7 +331,7 @@ struct fmt::cfmt_src
const fmt_type_info* sup;
const u64* args;
bool test(std::size_t index) const
bool test(usz index) const
{
if (!sup[index].fmt_string)
{
@@ -329,26 +342,26 @@ struct fmt::cfmt_src
}
template <typename T>
T get(std::size_t index) const
T get(usz index) const
{
return *reinterpret_cast<const T*>(reinterpret_cast<const u8*>(args + index));
}
void skip(std::size_t extra)
void skip(usz extra)
{
sup += extra + 1;
args += extra + 1;
}
std::size_t fmt_string(std::string& out, std::size_t extra) const
usz fmt_string(std::string& out, usz extra) const
{
const std::size_t start = out.size();
const usz start = out.size();
sup[extra].fmt_string(out, args[extra]);
return out.size() - start;
}
// Returns type size (0 if unknown, pointer, unsigned, assumed max)
std::size_t type(std::size_t extra) const
usz type(usz extra) const
{
// Hack: use known function pointers to determine type
#define TYPE(type) \
@@ -366,14 +379,14 @@ struct fmt::cfmt_src
return 0;
}
static constexpr std::size_t size_char = 1;
static constexpr std::size_t size_short = 2;
static constexpr std::size_t size_int = 0;
static constexpr std::size_t size_long = sizeof(ulong);
static constexpr std::size_t size_llong = sizeof(ullong);
static constexpr std::size_t size_size = sizeof(std::size_t);
static constexpr std::size_t size_max = sizeof(std::uintmax_t);
static constexpr std::size_t size_diff = sizeof(std::ptrdiff_t);
static constexpr usz size_char = 1;
static constexpr usz size_short = 2;
static constexpr usz size_int = 0;
static constexpr usz size_long = sizeof(ulong);
static constexpr usz size_llong = sizeof(ullong);
static constexpr usz size_size = sizeof(usz);
static constexpr usz size_max = sizeof(std::uintmax_t);
static constexpr usz size_diff = sizeof(std::ptrdiff_t);
};
void fmt::raw_append(std::string& out, const char* fmt, const fmt_type_info* sup, const u64* args) noexcept
@@ -405,32 +418,41 @@ std::string fmt::replace_all(const std::string& src, const std::string& from, co
return target;
}
std::vector<std::string> fmt::split(const std::string& source, std::initializer_list<std::string> separators, bool is_skip_empty)
std::vector<std::string> fmt::split(std::string_view source, std::initializer_list<std::string_view> separators, bool is_skip_empty)
{
std::vector<std::string> result;
size_t cursor_begin = 0;
for (size_t cursor_end = 0; cursor_end < source.length(); ++cursor_end)
for (usz index = 0; index < source.size();)
{
usz pos = -1;
usz sep_size = 0;
for (auto& separator : separators)
{
if (strncmp(source.c_str() + cursor_end, separator.c_str(), separator.length()) == 0)
if (usz pos0 = source.find(separator, index); pos0 != umax)
{
std::string candidate = source.substr(cursor_begin, cursor_end - cursor_begin);
if (!is_skip_empty || !candidate.empty())
result.push_back(candidate);
cursor_begin = cursor_end + separator.length();
cursor_end = cursor_begin - 1;
pos = pos0;
sep_size = separator.size();
break;
}
}
}
if (cursor_begin != source.length())
{
result.push_back(source.substr(cursor_begin));
if (!sep_size)
{
result.emplace_back(&source[index], source.size() - index);
return result;
}
std::string_view piece = {&source[index], pos - index};
index = pos + sep_size;
if (piece.empty() && is_skip_empty)
{
continue;
}
result.emplace_back(std::string(piece));
}
return result;
@@ -438,7 +460,7 @@ std::vector<std::string> fmt::split(const std::string& source, std::initializer_
std::string fmt::trim(const std::string& source, const std::string& values)
{
std::size_t begin = source.find_first_not_of(values);
usz begin = source.find_first_not_of(values);
if (begin == source.npos)
return {};
@@ -464,7 +486,7 @@ std::string fmt::to_lower(const std::string& string)
bool fmt::match(const std::string& source, const std::string& mask)
{
std::size_t source_position = 0, mask_position = 0;
usz source_position = 0, mask_position = 0;
for (; source_position < source.size() && mask_position < mask.size(); ++mask_position, ++source_position)
{
@@ -473,7 +495,7 @@ bool fmt::match(const std::string& source, const std::string& mask)
case '?': break;
case '*':
for (std::size_t test_source_position = source_position; test_source_position < source.size(); ++test_source_position)
for (usz test_source_position = source_position; test_source_position < source.size(); ++test_source_position)
{
if (match(source.substr(test_source_position), mask.substr(mask_position + 1)))
{
+48 -42
View File
@@ -1,16 +1,16 @@
#pragma once
#pragma once // No BOM and only basic ASCII in this header, or a neko will die
#include "types.h"
#include "util/types.hpp"
#include <string>
namespace fmt
{
template <typename CharT, std::size_t N, typename... Args>
template <typename CharT, usz N, typename... Args>
static std::string format(const CharT(&)[N], const Args&...);
}
template <typename T, typename>
template <typename T, typename = void>
struct fmt_unveil
{
static_assert(sizeof(T) > 0, "fmt_unveil<> error: incomplete type");
@@ -19,7 +19,7 @@ struct fmt_unveil
static inline u64 get(const T& arg)
{
return reinterpret_cast<std::uintptr_t>(&arg);
return reinterpret_cast<uptr>(&arg);
}
// Temporary value container (can possibly be created by other fmt_unveil<> specializations)
@@ -30,7 +30,7 @@ struct fmt_unveil
// Allow implicit conversion
operator u64() const
{
return reinterpret_cast<std::uintptr_t>(&arg);
return reinterpret_cast<uptr>(&arg);
}
};
@@ -64,17 +64,6 @@ struct fmt_unveil<T, std::enable_if_t<std::is_floating_point<T>::value && sizeof
}
};
template <>
struct fmt_unveil<f16, void>
{
using type = f16;
static inline u64 get(const f16& arg)
{
return fmt_unveil<f64>::get(arg.operator float());
}
};
template <typename T>
struct fmt_unveil<T, std::enable_if_t<std::is_enum<T>::value>>
{
@@ -93,29 +82,29 @@ struct fmt_unveil<T*, void>
static inline u64 get(type arg)
{
return reinterpret_cast<std::uintptr_t>(arg);
return reinterpret_cast<uptr>(arg);
}
};
template <typename T, std::size_t N>
template <typename T, usz N>
struct fmt_unveil<T[N], void>
{
using type = std::add_const_t<T>*;
static inline u64 get(type arg)
{
return reinterpret_cast<std::uintptr_t>(arg);
return reinterpret_cast<uptr>(arg);
}
};
template <>
struct fmt_unveil<b8, void>
template <typename T, bool Se, usz Align>
struct fmt_unveil<se_t<T, Se, Align>, void>
{
using type = bool;
using type = typename fmt_unveil<T>::type;
static inline u64 get(const b8& value)
static inline auto get(const se_t<T, Se, Align>& arg)
{
return fmt_unveil<bool>::get(value);
return fmt_unveil<T>::get(arg);
}
};
@@ -130,16 +119,16 @@ struct fmt_class_string
using type = T;
// Helper function (converts arg to object reference)
static SAFE_BUFFERS FORCE_INLINE const T& get_object(u64 arg)
static FORCE_INLINE SAFE_BUFFERS(const T&) get_object(u64 arg)
{
return *reinterpret_cast<const T*>(static_cast<std::uintptr_t>(arg));
return *reinterpret_cast<const T*>(static_cast<uptr>(arg));
}
// Enum -> string function type
using convert_t = const char*(*)(T value);
// Helper function (safely converts arg to enum value)
static SAFE_BUFFERS FORCE_INLINE void format_enum(std::string& out, u64 arg, convert_t convert)
static FORCE_INLINE SAFE_BUFFERS(void) format_enum(std::string& out, u64 arg, convert_t convert)
{
const auto value = static_cast<std::underlying_type_t<T>>(arg);
@@ -158,7 +147,7 @@ struct fmt_class_string
}
// Helper function (bitset formatting)
static SAFE_BUFFERS FORCE_INLINE void format_bitset(std::string& out, u64 arg, const char* prefix, const char* delim, const char* suffix, void (*fmt)(std::string&, u64))
static FORCE_INLINE SAFE_BUFFERS(void) format_bitset(std::string& out, u64 arg, const char* prefix, const char* delim, const char* suffix, void (*fmt)(std::string&, u64))
{
// Start from raw value
fmt_class_string<u64>::format(out, arg);
@@ -234,13 +223,16 @@ struct fmt_type_info
template <typename... Args>
using fmt_args_t = const u64(&&)[sizeof...(Args) + 1];
template <typename Arg>
using fmt_unveil_t = typename fmt_unveil<Arg>::type;
namespace fmt
{
// Base-57 format helper
struct base57
{
const uchar* data;
std::size_t size;
usz size;
template <typename T>
base57(const T& arg)
@@ -249,7 +241,7 @@ namespace fmt
{
}
base57(const uchar* data, std::size_t size)
base57(const uchar* data, usz size)
: data(data)
, size(size)
{
@@ -257,7 +249,7 @@ namespace fmt
};
template <typename... Args>
SAFE_BUFFERS FORCE_INLINE const fmt_type_info* get_type_info()
FORCE_INLINE SAFE_BUFFERS(const fmt_type_info*) get_type_info()
{
// Constantly initialized null-terminated list of type-specific information
static constexpr fmt_type_info result[sizeof...(Args) + 1]{fmt_type_info::make<fmt_unveil_t<Args>>()...};
@@ -272,16 +264,16 @@ namespace fmt
void raw_append(std::string& out, const char*, const fmt_type_info*, const u64*) noexcept;
// Formatting function
template <typename CharT, std::size_t N, typename... Args>
SAFE_BUFFERS FORCE_INLINE void append(std::string& out, const CharT(&fmt)[N], const Args&... args)
template <typename CharT, usz N, typename... Args>
FORCE_INLINE SAFE_BUFFERS(void) append(std::string& out, const CharT(&fmt)[N], const Args&... args)
{
static constexpr fmt_type_info type_list[sizeof...(Args) + 1]{fmt_type_info::make<fmt_unveil_t<Args>>()...};
raw_append(out, reinterpret_cast<const char*>(fmt), type_list, fmt_args_t<Args...>{fmt_unveil<Args>::get(args)...});
}
// Formatting function
template <typename CharT, std::size_t N, typename... Args>
SAFE_BUFFERS FORCE_INLINE std::string format(const CharT(&fmt)[N], const Args&... args)
template <typename CharT, usz N, typename... Args>
FORCE_INLINE SAFE_BUFFERS(std::string) format(const CharT(&fmt)[N], const Args&... args)
{
std::string result;
append(result, fmt, args...);
@@ -289,13 +281,27 @@ namespace fmt
}
// Internal exception message formatting template, must be explicitly specialized or instantiated in cpp to minimize code bloat
[[noreturn]] void raw_throw_exception(const char*, const fmt_type_info*, const u64*);
[[noreturn]] void raw_throw_exception(const src_loc&, const char*, const fmt_type_info*, const u64*);
// Throw exception with formatting
template <typename... Args>
[[noreturn]] SAFE_BUFFERS FORCE_INLINE void throw_exception(const char* fmt, const Args&... args)
template <typename CharT, usz N, typename... Args>
struct throw_exception
{
static constexpr fmt_type_info type_list[sizeof...(Args) + 1]{fmt_type_info::make<fmt_unveil_t<Args>>()...};
raw_throw_exception(fmt, type_list, fmt_args_t<Args...>{fmt_unveil<Args>::get(args)...});
}
[[noreturn]] FORCE_INLINE SAFE_BUFFERS() throw_exception(const CharT(&fmt)[N], const Args&... args,
u32 line = __builtin_LINE(),
u32 col = __builtin_COLUMN(),
const char* file = __builtin_FILE(),
const char* func = __builtin_FUNCTION())
{
static constexpr fmt_type_info type_list[sizeof...(Args) + 1]{fmt_type_info::make<fmt_unveil_t<Args>>()...};
raw_throw_exception({line, col, file, func}, reinterpret_cast<const char*>(fmt), type_list, fmt_args_t<Args...>{fmt_unveil<Args>::get(args)...});
}
#ifndef _MSC_VER
[[noreturn]] ~throw_exception();
#endif
};
template <typename CharT, usz N, typename... Args>
throw_exception(const CharT(&)[N], const Args&...) -> throw_exception<CharT, N, Args...>;
}
+10 -10
View File
@@ -17,7 +17,7 @@ std::string utf8_path_to_ansi_path(const std::string& src);
template <typename D, typename T>
inline void strcpy_trunc(D& dst, const T& src)
{
const std::size_t count = std::size(src) >= std::size(dst) ? std::size(dst) - 1 : std::size(src);
const usz count = std::size(src) >= std::size(dst) ? std::size(dst) - 1 : std::size(src);
std::memcpy(std::data(dst), std::data(src), count);
std::memset(std::data(dst) + count, 0, std::size(dst) - count);
}
@@ -27,14 +27,14 @@ namespace fmt
std::string replace_first(const std::string& src, const std::string& from, const std::string& to);
std::string replace_all(const std::string& src, const std::string& from, const std::string& to);
template <size_t list_size>
template <usz list_size>
std::string replace_all(std::string src, const std::pair<std::string, std::string> (&list)[list_size])
{
for (size_t pos = 0; pos < src.length(); ++pos)
for (usz pos = 0; pos < src.length(); ++pos)
{
for (size_t i = 0; i < list_size; ++i)
for (usz i = 0; i < list_size; ++i)
{
const size_t comp_length = list[i].first.length();
const usz comp_length = list[i].first.length();
if (src.length() - pos < comp_length)
continue;
@@ -51,14 +51,14 @@ namespace fmt
return src;
}
template <size_t list_size>
template <usz list_size>
std::string replace_all(std::string src, const std::pair<std::string, std::function<std::string()>> (&list)[list_size])
{
for (size_t pos = 0; pos < src.length(); ++pos)
for (usz pos = 0; pos < src.length(); ++pos)
{
for (size_t i = 0; i < list_size; ++i)
for (usz i = 0; i < list_size; ++i)
{
const size_t comp_length = list[i].first.length();
const usz comp_length = list[i].first.length();
if (src.length() - pos < comp_length)
continue;
@@ -75,7 +75,7 @@ namespace fmt
return src;
}
std::vector<std::string> split(const std::string& source, std::initializer_list<std::string> separators, bool is_skip_empty = true);
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");
template <typename T>
+691 -253
View File
File diff suppressed because it is too large Load Diff
+435 -117
View File
@@ -1,20 +1,16 @@
#pragma once
#include "types.h"
#include "util/types.hpp"
#include "util/atomic.hpp"
#include "util/shared_cptr.hpp"
#include "util/shared_ptr.hpp"
#include <string>
#include <memory>
#include <string_view>
#include "mutex.h"
#include "cond.h"
#include "lockless.h"
// Report error and call std::abort(), defined in main.cpp
[[noreturn]] void report_fatal_error(const std::string&);
// Hardware core layout
enum class native_core_arrangement : u32
{
@@ -34,10 +30,11 @@ enum class thread_class : u32
enum class thread_state : u32
{
created, // Initial state
aborting, // The thread has been joined in the destructor or explicitly aborted
errored, // Set after the emergency_exit call
finished // Final state, always set at the end of thread execution
created = 0, // Initial state
aborting = 1, // The thread has been joined in the destructor or explicitly aborted
errored = 2, // Set after the emergency_exit call
finished = 3, // Final state, always set at the end of thread execution
mask = 3
};
class need_wakeup {};
@@ -45,10 +42,22 @@ class need_wakeup {};
template <class Context>
class named_thread;
template <typename T>
class thread_base;
template <typename Ctx, typename X = void, typename... Args>
struct result_storage
{
static_assert(std::is_default_constructible_v<T> && noexcept(T()));
static constexpr bool empty = true;
using type = void;
};
template <typename Ctx, typename... Args>
struct result_storage<Ctx, std::enable_if_t<!std::is_void_v<std::invoke_result_t<Ctx, Args&&...>>>, Args...>
{
using T = std::invoke_result_t<Ctx, Args&&...>;
static_assert(std::is_default_constructible_v<T>);
alignas(T) std::byte data[sizeof(T)];
@@ -56,33 +65,53 @@ struct result_storage
using type = T;
T* get()
T* _get()
{
return reinterpret_cast<T*>(&data);
}
const T* get() const
const T* _get() const
{
return reinterpret_cast<const T*>(&data);
}
void init() noexcept
{
new (data) T();
}
void destroy() noexcept
{
get()->~T();
_get()->~T();
}
};
template <>
struct result_storage<void>
// Base class for task queue (linked list)
class thread_future
{
static constexpr bool empty = true;
friend class thread_base;
using type = void;
shared_ptr<thread_future> next{};
shared_ptr<thread_future>* prev{};
protected:
atomic_t<void(*)(thread_base*, thread_future*)> exec{};
public:
// Get reference to the atomic variable for inspection and waiting for
const auto& get_wait() const
{
return exec;
}
// Wait (preset)
void wait() const
{
exec.wait<atomic_wait::op_ne>(nullptr);
}
};
template <class Context, typename... Args>
using result_storage_t = result_storage<std::invoke_result_t<Context, Args...>>;
template <typename T, typename = void>
struct thread_thread_name : std::bool_constant<false> {};
@@ -92,6 +121,7 @@ struct thread_thread_name<T, std::void_t<decltype(named_thread<T>::thread_name)>
// Thread base class
class thread_base
{
public:
// Native thread entry point function type
#ifdef _WIN32
using native_entry = uint(__stdcall*)(void* arg);
@@ -99,38 +129,38 @@ class thread_base
using native_entry = void*(*)(void* arg);
#endif
const native_entry entry_point;
private:
// Thread handle (platform-specific)
atomic_t<std::uintptr_t> m_thread{0};
atomic_t<u64> m_thread{0};
// Thread playtoy, that shouldn't be used
atomic_t<u32> m_signal{0};
// Thread state
atomic_t<thread_state> m_state = thread_state::created;
// Thread state notification info
atomic_t<const void*> m_state_notifier{nullptr};
// Thread state and cycles
atomic_t<u64> m_sync{0};
// Thread name
stx::atomic_cptr<std::string> m_tname;
atomic_ptr<std::string> m_tname;
//
atomic_t<u64> m_cycles = 0;
// Thread task queue (reversed linked list)
atomic_ptr<thread_future> m_taskq{};
// Start thread
void start(native_entry);
void start();
// Called at the thread start
void initialize(void (*error_cb)(), bool(*wait_cb)(const void*));
void initialize(void (*error_cb)());
// May be called in destructor
void notify_abort() noexcept;
// Called at the thread end, returns true if needs destruction
bool finalize(thread_state result) noexcept;
// Called at the thread end, returns self handle
u64 finalize(thread_state result) noexcept;
// Cleanup after possibly deleting the thread instance
static void finalize() noexcept;
static native_entry finalize(u64 _self) noexcept;
// Set name for debugger
static void set_name(std::string);
// Make entry point
static native_entry make_trampoline(u64(*)(thread_base*));
friend class thread_ctrl;
@@ -138,7 +168,7 @@ class thread_base
friend class named_thread;
protected:
thread_base(std::string_view name);
thread_base(native_entry, std::string_view name);
~thread_base();
@@ -147,10 +177,20 @@ public:
u64 get_cycles();
// Wait for the thread (it does NOT change thread state, and can be called from multiple threads)
bool join() const;
bool join(bool dtor = false) const;
// Notify the thread
void notify();
// Get thread id
u64 get_native_id() const;
// Add work to the queue
void push(shared_ptr<thread_future>);
private:
// Clear task queue (execute unless aborting)
void exec();
};
// Collection of global function for current thread
@@ -190,14 +230,14 @@ public:
// Set current thread name (not recommended)
static void set_name(std::string_view name)
{
g_tls_this_thread->m_tname.store(stx::shared_cptr<std::string>::make(name));
g_tls_this_thread->m_tname.store(make_single<std::string>(name));
}
// Set thread name (not recommended)
template <typename T>
static void set_name(named_thread<T>& thread, std::string_view name)
{
static_cast<thread_base&>(thread).m_tname.store(stx::shared_cptr<std::string>::make(name));
static_cast<thread_base&>(thread).m_tname.store(make_single<std::string>(name));
}
template <typename T>
@@ -213,16 +253,13 @@ public:
}
template <typename T>
static void raw_notify(named_thread<T>& thread)
static u64 get_native_id(named_thread<T>& thread)
{
static_cast<thread_base&>(thread).notify_abort();
return static_cast<thread_base&>(thread).get_native_id();
}
// Read current state
static inline thread_state state()
{
return g_tls_this_thread->m_state;
}
// Read current state, possibly executing some tasks
static thread_state state();
// Wait once with timeout. May spuriously return false.
static inline void wait_for(u64 usec, bool alert = true)
@@ -236,6 +273,24 @@ public:
_wait_for(-1, true);
}
// Wait for both thread sync var and provided atomic var
template <atomic_wait::op Op = atomic_wait::op::eq, typename T, typename U>
static inline void wait_on(T& wait, U old, u64 usec = -1)
{
auto _this = g_tls_this_thread;
if (_this->m_sync.bit_test_reset(2) || _this->m_taskq)
{
return;
}
atomic_wait::list<3> list{};
list.set<0, Op>(wait, old);
list.set<1>(_this->m_sync, 0, 4 + 1);
list.set<2>(_this->m_taskq, nullptr);
list.wait(atomic_wait_timeout{usec <= 0xffff'ffff'ffff'ffff / 1000 ? usec * 1000 : 0xffff'ffff'ffff'ffff});
}
// Exit.
[[noreturn]] static void emergency_exit(std::string_view reason);
@@ -263,6 +318,27 @@ public:
// Miscellaneous
static u64 get_thread_affinity_mask();
// Get current thread stack addr and size
static std::pair<void*, usz> get_thread_stack();
// Sets the native thread priority and returns it to zero at destructor
struct scoped_priority
{
explicit scoped_priority(int prio)
{
set_native_priority(prio);
}
scoped_priority(const scoped_priority&) = delete;
scoped_priority& operator=(const scoped_priority&) = delete;
~scoped_priority()
{
set_native_priority(0);
}
};
private:
// Miscellaneous
static const u64 process_affinity_mask;
@@ -270,82 +346,54 @@ private:
// Derived from the callable object Context, possibly a lambda
template <class Context>
class named_thread final : public Context, result_storage_t<Context>, thread_base
class named_thread final : public Context, result_storage<Context>, thread_base
{
using result = result_storage_t<Context>;
using result = result_storage<Context>;
using thread = thread_base;
// Type-erased thread entry point
#ifdef _WIN32
static inline uint __stdcall entry_point(void* arg)
#else
static inline void* entry_point(void* arg)
#endif
static u64 entry_point(thread_base* _base)
{
const auto _this = static_cast<named_thread*>(static_cast<thread*>(arg));
// Perform self-cleanup if necessary
if (_this->entry_point())
{
delete _this;
}
thread::finalize();
return 0;
return static_cast<named_thread*>(_base)->entry_point2();
}
bool entry_point()
u64 entry_point2()
{
auto tls_error_cb = []()
thread::initialize([]()
{
if constexpr (!result::empty)
{
// Construct using default constructor in the case of failure
new (static_cast<result*>(static_cast<named_thread*>(thread_ctrl::get_current()))->get()) typename result::type();
static_cast<result*>(static_cast<named_thread*>(thread_ctrl::get_current()))->init();
}
};
thread::initialize(tls_error_cb, [](const void* data)
{
const auto _this = thread_ctrl::get_current();
if (_this->m_state >= thread_state::aborting)
{
_this->m_state_notifier.store(data);
return false;
}
if (!data)
{
_this->m_state_notifier.release(data);
return true;
}
_this->m_state_notifier.store(data);
if (_this->m_state >= thread_state::aborting)
{
_this->m_state_notifier.release(nullptr);
return false;
}
return true;
});
if constexpr (result::empty)
{
// No result
Context::operator()();
if constexpr (std::is_invocable_v<Context>)
{
Context::operator()();
}
else
{
// Default event loop
while (thread_ctrl::state() != thread_state::aborting)
{
thread_ctrl::wait();
}
}
}
else
{
// Construct the result using placement new (copy elision should happen)
new (result::get()) typename result::type(Context::operator()());
new (result::_get()) decltype(auto)(Context::operator()());
}
return thread::finalize(thread_state::finished);
}
static inline thread::native_entry trampoline = thread::make_trampoline(entry_point);
friend class thread_ctrl;
public:
@@ -353,26 +401,26 @@ public:
template <bool Valid = std::is_default_constructible_v<Context> && thread_thread_name<Context>(), typename = std::enable_if_t<Valid>>
named_thread()
: Context()
, thread(Context::thread_name)
, thread(trampoline, Context::thread_name)
{
thread::start(&named_thread::entry_point);
thread::start();
}
// Normal forwarding constructor
template <typename... Args, typename = std::enable_if_t<std::is_constructible_v<Context, Args&&...>>>
named_thread(std::string_view name, Args&&... args)
: Context(std::forward<Args>(args)...)
, thread(name)
, thread(trampoline, name)
{
thread::start(&named_thread::entry_point);
thread::start();
}
// Lambda constructor, also the implicit deduction guide candidate
named_thread(std::string_view name, Context&& f)
: Context(std::forward<Context>(f))
, thread(name)
, thread(trampoline, name)
{
thread::start(&named_thread::entry_point);
thread::start();
}
named_thread(const named_thread&) = delete;
@@ -386,7 +434,7 @@ public:
if constexpr (!result::empty)
{
return *result::get();
return *result::_get();
}
}
@@ -397,26 +445,296 @@ public:
if constexpr (!result::empty)
{
return *result::get();
return *result::_get();
}
}
// Send command to the thread to invoke directly (references should be passed via std::ref())
template <bool Discard = true, typename Arg, typename... Args>
auto operator()(Arg&& arg, Args&&... args)
{
// Overloaded operator() of the Context.
constexpr bool v1 = std::is_invocable_v<Context, Arg&&, Args&&...>;
// Anything invocable, not necessarily involving the Context.
constexpr bool v2 = std::is_invocable_v<Arg&&, Args&&...>;
// Could be pointer to a non-static member function (or data member) of the Context.
constexpr bool v3 = std::is_member_pointer_v<std::decay_t<Arg>> && std::is_invocable_v<Arg, Context&, Args&&...>;
// Only one invocation type shall be valid, otherwise we don't know.
static_assert((v1 + v2 + v3) == 1, "Ambiguous or invalid named_thread call.");
if constexpr (v1)
{
class future : public thread_future, result_storage<Context, void, Arg, Args...>
{
// A tuple to store arguments
decltype(std::make_tuple(std::forward<Arg, Args...>(arg, args...))) m_args;
public:
future(Arg&& arg, Args&&... args)
: m_args(std::forward<Arg, Args...>(arg, args...))
{
thread_future::exec.raw() = +[](thread_base* tb, thread_future* tf)
{
const auto _this = static_cast<future*>(tf);
if (!tb) [[unlikely]]
{
if constexpr (!future::empty && !Discard)
{
_this->init();
}
return;
}
if constexpr (future::empty || Discard)
{
std::apply(*static_cast<Context*>(static_cast<named_thread*>(tb)), _this->m_args);
}
else
{
new (_this->_get()) decltype(auto)(std::apply(*static_cast<Context*>(static_cast<named_thread*>(tb)), _this->m_args));
}
};
}
future(const future&) = delete;
future& operator=(const future&) = delete;
~future()
{
if constexpr (!future::empty && !Discard)
{
// Should be set to null if executed
if (!this->exec)
{
this->destroy();
}
}
}
decltype(auto) get()
{
if constexpr (!future::empty && !Discard)
{
return *this->_get();
}
}
decltype(auto) get() const
{
if constexpr (!future::empty && !Discard)
{
return *this->_get();
}
}
};
single_ptr<future> target = make_single<future>(std::forward<Arg, Args...>(arg, args...));
if constexpr (!Discard)
{
shared_ptr<future> result = std::move(target);
// Copy result
thread::push(result);
return result;
}
else
{
// Move target
thread::push(std::move(target));
return;
}
}
else if constexpr (v2)
{
class future : public thread_future, result_storage<std::decay_t<Arg>, void, Args...>
{
decltype(std::make_tuple(std::forward<Args...>(args...))) m_args;
std::decay_t<Arg> m_func;
public:
future(Arg func, Args&&... args)
: m_args(std::forward<Args...>(args...))
, m_func(func)
{
thread_future::exec.raw() = +[](thread_base* tb, thread_future* tf)
{
const auto _this = static_cast<future*>(tf);
if (!tb) [[unlikely]]
{
if constexpr (!future::empty && !Discard)
{
_this->init();
}
return;
}
if constexpr (future::empty || Discard)
{
std::apply(_this->m_func, _this->m_args);
}
else
{
new (_this->_get()) decltype(auto)(std::apply(_this->m_func, _this->m_args));
}
};
}
future(const future&) = delete;
future& operator=(const future&) = delete;
~future()
{
if constexpr (!future::empty && !Discard)
{
if (!this->exec)
{
this->destroy();
}
}
}
decltype(auto) get()
{
if constexpr (!future::empty && !Discard)
{
return *this->_get();
}
}
decltype(auto) get() const
{
if constexpr (!future::empty && !Discard)
{
return *this->_get();
}
}
};
single_ptr<future> target = make_single<future>(std::forward<Arg, Args...>(arg, args...));
if constexpr (!Discard)
{
shared_ptr<future> result = std::move(target);
thread::push(result);
return result;
}
else
{
thread::push(std::move(target));
return;
}
}
else if constexpr (v3)
{
class future : public thread_future, result_storage<std::decay_t<Arg>, void, Context&, Args...>
{
decltype(std::make_tuple(std::forward<Args...>(args...))) m_args;
std::decay_t<Arg> m_func;
public:
future(Arg func, Args&&... args)
: m_args(std::forward<Args...>(args...))
, m_func(func)
{
thread_future::exec.raw() = +[](thread_base* tb, thread_future* tf)
{
const auto _this = static_cast<future*>(tf);
if (!tb) [[unlikely]]
{
if constexpr (!future::empty && !Discard)
{
_this->init();
}
return;
}
if constexpr (future::empty || Discard)
{
std::apply(_this->m_func, *static_cast<Context*>(static_cast<named_thread*>(tb)), _this->m_args);
}
else
{
new (_this->_get()) decltype(auto)(std::apply(_this->m_func, *static_cast<Context*>(static_cast<named_thread*>(tb)), _this->m_args));
}
};
}
future(const future&) = delete;
future& operator=(const future&) = delete;
~future()
{
if constexpr (!future::empty && !Discard)
{
if (!this->exec)
{
this->destroy();
}
}
}
decltype(auto) get()
{
if constexpr (!future::empty && !Discard)
{
return *this->_get();
}
}
decltype(auto) get() const
{
if constexpr (!future::empty && !Discard)
{
return *this->_get();
}
}
};
single_ptr<future> target = make_single<future>(std::forward<Arg, Args...>(arg, args...));
if constexpr (!Discard)
{
shared_ptr<future> result = std::move(target);
thread::push(result);
return result;
}
else
{
thread::push(std::move(target));
return;
}
}
}
// Access thread state
operator thread_state() const
{
return thread::m_state.load();
return static_cast<thread_state>(thread::m_sync.load() & 3);
}
// Try to abort by assigning thread_state::aborting (UB if assigning different state)
named_thread& operator=(thread_state s)
{
ASSUME(s == thread_state::aborting);
if (s == thread_state::aborting && thread::m_state.compare_and_swap_test(thread_state::created, s))
if (s == thread_state::aborting && thread::m_sync.fetch_op([](u64& v){ return !(v & 3) && (v |= 1); }).second)
{
if (s == thread_state::aborting)
{
thread::notify_abort();
thread::m_sync.notify_one(1);
}
if constexpr (std::is_base_of_v<need_wakeup, Context>)
@@ -433,7 +751,7 @@ public:
{
// Assign aborting state forcefully
operator=(thread_state::aborting);
thread::join();
thread::join(true);
if constexpr (!result::empty)
{
+9 -9
View File
@@ -1,6 +1,6 @@
#pragma once
#include "types.h"
#include "util/types.hpp"
#include <chrono>
@@ -8,8 +8,8 @@ class Timer
{
private:
bool m_stopped;
std::chrono::steady_clock::time_point m_start;
std::chrono::steady_clock::time_point m_end;
steady_clock::time_point m_start;
steady_clock::time_point m_end;
public:
Timer() : m_stopped(false)
@@ -19,13 +19,13 @@ public:
void Start()
{
m_stopped = false;
m_start = std::chrono::steady_clock::now();
m_start = steady_clock::now();
}
void Stop()
{
m_stopped = true;
m_end = std::chrono::steady_clock::now();
m_end = steady_clock::now();
}
double GetElapsedTimeInSec() const
@@ -40,21 +40,21 @@ public:
u64 GetElapsedTimeInMicroSec() const
{
std::chrono::steady_clock::time_point now = m_stopped ? m_end : std::chrono::steady_clock::now();
steady_clock::time_point now = m_stopped ? m_end : steady_clock::now();
return std::chrono::duration_cast<std::chrono::microseconds>(now - m_start).count();
}
u64 GetElapsedTimeInNanoSec() const
{
std::chrono::steady_clock::time_point now = m_stopped ? m_end : std::chrono::steady_clock::now();
steady_clock::time_point now = m_stopped ? m_end : steady_clock::now();
return std::chrono::duration_cast<std::chrono::nanoseconds>(now - m_start).count();
}
u64 GetMsSince(std::chrono::steady_clock::time_point timestamp)
u64 GetMsSince(steady_clock::time_point timestamp)
{
std::chrono::steady_clock::time_point now = m_stopped ? m_end : std::chrono::steady_clock::now();
steady_clock::time_point now = m_stopped ? m_end : steady_clock::now();
return std::chrono::duration_cast<std::chrono::milliseconds>(now - timestamp).count();
}
-312
View File
@@ -1,312 +0,0 @@
#include "stdafx.h"
#include "util/logs.hpp"
#include "VirtualMemory.h"
#ifdef _WIN32
#include <Windows.h>
#else
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#endif
#ifdef __linux__
#include <sys/syscall.h>
#ifdef __NR_memfd_create
#elif __x86_64__
#define __NR_memfd_create 319
#elif __aarch64__
#define __NR_memfd_create 279
#endif
static int memfd_create_(const char *name, uint flags)
{
return syscall(__NR_memfd_create, name, flags);
}
#endif
namespace utils
{
// Convert memory protection (internal)
static auto operator +(protection prot)
{
#ifdef _WIN32
DWORD _prot = PAGE_NOACCESS;
switch (prot)
{
case protection::rw: _prot = PAGE_READWRITE; break;
case protection::ro: _prot = PAGE_READONLY; break;
case protection::no: break;
case protection::wx: _prot = PAGE_EXECUTE_READWRITE; break;
case protection::rx: _prot = PAGE_EXECUTE_READ; break;
}
#else
int _prot = PROT_NONE;
switch (prot)
{
case protection::rw: _prot = PROT_READ | PROT_WRITE; break;
case protection::ro: _prot = PROT_READ; break;
case protection::no: break;
case protection::wx: _prot = PROT_READ | PROT_WRITE | PROT_EXEC; break;
case protection::rx: _prot = PROT_READ | PROT_EXEC; break;
}
#endif
return _prot;
}
void* memory_reserve(std::size_t size, void* use_addr)
{
#ifdef _WIN32
return ::VirtualAlloc(use_addr, size, MEM_RESERVE, PAGE_NOACCESS);
#else
if (use_addr && reinterpret_cast<uptr>(use_addr) % 0x10000)
{
return nullptr;
}
if (!use_addr)
{
// Hack: Ensure aligned 64k allocations
size += 0x10000;
}
auto ptr = ::mmap(use_addr, size, PROT_NONE, MAP_ANON | MAP_PRIVATE, -1, 0);
if (ptr == reinterpret_cast<void*>(-1))
{
return nullptr;
}
if (use_addr && ptr != use_addr)
{
::munmap(ptr, size);
return nullptr;
}
if (!use_addr && ptr)
{
// Continuation of the hack above
const auto misalign = reinterpret_cast<uptr>(ptr) % 0x10000;
::munmap(ptr, 0x10000 - misalign);
if (misalign)
{
::munmap(static_cast<u8*>(ptr) + size - misalign, misalign);
}
ptr = static_cast<u8*>(ptr) + (0x10000 - misalign);
}
return ptr;
#endif
}
void memory_commit(void* pointer, std::size_t size, protection prot)
{
#ifdef _WIN32
verify(HERE), ::VirtualAlloc(pointer, size, MEM_COMMIT, +prot);
#else
const u64 ptr64 = reinterpret_cast<u64>(pointer);
verify(HERE), ::mprotect(reinterpret_cast<void*>(ptr64 & -4096), size + (ptr64 & 4095), +prot) != -1;
#endif
}
void memory_decommit(void* pointer, std::size_t size)
{
#ifdef _WIN32
verify(HERE), ::VirtualFree(pointer, size, MEM_DECOMMIT);
#else
verify(HERE), ::mmap(pointer, size, PROT_NONE, MAP_FIXED | MAP_ANON | MAP_PRIVATE, -1, 0) != reinterpret_cast<void*>(-1);
#endif
}
void memory_reset(void* pointer, std::size_t size, protection prot)
{
#ifdef _WIN32
memory_decommit(pointer, size);
memory_commit(pointer, size, prot);
#else
verify(HERE), ::mmap(pointer, size, +prot, MAP_FIXED | MAP_ANON | MAP_PRIVATE, -1, 0) != reinterpret_cast<void*>(-1);
#endif
}
void memory_release(void* pointer, std::size_t size)
{
#ifdef _WIN32
verify(HERE), ::VirtualFree(pointer, 0, MEM_RELEASE);
#else
verify(HERE), ::munmap(pointer, size) != -1;
#endif
}
void memory_protect(void* pointer, std::size_t size, protection prot)
{
#ifdef _WIN32
for (u64 addr = reinterpret_cast<u64>(pointer), end = addr + size; addr < end;)
{
const u64 boundary = (addr + 0x10000) & -0x10000;
const u64 block_size = std::min(boundary, end) - addr;
DWORD old;
if (!::VirtualProtect(reinterpret_cast<LPVOID>(addr), block_size, +prot, &old))
{
fmt::throw_exception("VirtualProtect failed (%p, 0x%x, addr=0x%x, error=%#x)", pointer, size, addr, GetLastError());
}
// Next region
addr += block_size;
}
#else
const u64 ptr64 = reinterpret_cast<u64>(pointer);
verify(HERE), ::mprotect(reinterpret_cast<void*>(ptr64 & -4096), size + (ptr64 & 4095), +prot) != -1;
#endif
}
shm::shm(u32 size, u32 flags)
: m_size(::align(size, 0x10000))
, m_flags(flags)
{
#ifdef _WIN32
m_handle = ::CreateFileMappingW(INVALID_HANDLE_VALUE, NULL, PAGE_EXECUTE_READWRITE, 0, m_size, NULL);
verify(HERE), m_handle != INVALID_HANDLE_VALUE;
#elif __linux__
m_file = ::memfd_create_("", 0);
verify(HERE), m_file >= 0;
verify(HERE), ::ftruncate(m_file, m_size) >= 0;
#else
while ((m_file = ::shm_open("/rpcs3-mem1", O_RDWR | O_CREAT | O_EXCL, S_IWUSR | S_IRUSR)) == -1)
{
if (errno == EMFILE)
{
fmt::throw_exception("Too many open files. Raise the limit and try again.");
}
verify(HERE), errno == EEXIST;
}
verify(HERE), ::shm_unlink("/rpcs3-mem1") >= 0;
verify(HERE), ::ftruncate(m_file, m_size) >= 0;
#endif
}
shm::~shm()
{
#ifdef _WIN32
::CloseHandle(m_handle);
#else
::close(m_file);
#endif
}
u8* shm::map(void* ptr, protection prot) const
{
#ifdef _WIN32
DWORD access = FILE_MAP_WRITE;
switch (prot)
{
case protection::rw:
case protection::ro:
case protection::no:
break;
case protection::wx:
case protection::rx:
access |= FILE_MAP_EXECUTE;
break;
}
if (auto ret = static_cast<u8*>(::MapViewOfFileEx(m_handle, access, 0, 0, m_size, ptr)))
{
if (prot != protection::rw && prot != protection::wx)
{
DWORD old;
if (!::VirtualProtect(ret, m_size, +prot, &old))
{
::UnmapViewOfFile(ret);
return nullptr;
}
}
return ret;
}
return nullptr;
#else
const u64 ptr64 = reinterpret_cast<u64>(ptr);
return static_cast<u8*>(::mmap(reinterpret_cast<void*>(ptr64 & -0x10000), m_size, +prot, MAP_SHARED | (ptr ? MAP_FIXED : 0), m_file, 0));
#endif
}
u8* shm::map_critical(void* ptr, protection prot)
{
const auto target = reinterpret_cast<u8*>(reinterpret_cast<u64>(ptr) & -0x10000);
#ifdef _WIN32
::MEMORY_BASIC_INFORMATION mem;
if (!::VirtualQuery(target, &mem, sizeof(mem)) || mem.State != MEM_RESERVE || !::VirtualFree(mem.AllocationBase, 0, MEM_RELEASE))
{
return nullptr;
}
const auto base = (u8*)mem.AllocationBase;
const auto size = mem.RegionSize + (target - base);
if (base < target && !::VirtualAlloc(base, target - base, MEM_RESERVE, PAGE_NOACCESS))
{
return nullptr;
}
if (target + m_size < base + size && !::VirtualAlloc(target + m_size, base + size - target - m_size, MEM_RESERVE, PAGE_NOACCESS))
{
return nullptr;
}
#endif
return this->map(target, prot);
}
void shm::unmap(void* ptr) const
{
#ifdef _WIN32
::UnmapViewOfFile(ptr);
#else
::munmap(ptr, m_size);
#endif
}
void shm::unmap_critical(void* ptr)
{
const auto target = reinterpret_cast<u8*>(reinterpret_cast<u64>(ptr) & -0x10000);
this->unmap(target);
#ifdef _WIN32
::MEMORY_BASIC_INFORMATION mem, mem2;
if (!::VirtualQuery(target - 1, &mem, sizeof(mem)) || !::VirtualQuery(target + m_size, &mem2, sizeof(mem2)))
{
return;
}
if (mem.State == MEM_RESERVE && !::VirtualFree(mem.AllocationBase, 0, MEM_RELEASE))
{
return;
}
if (mem2.State == MEM_RESERVE && !::VirtualFree(mem2.AllocationBase, 0, MEM_RELEASE))
{
return;
}
const auto size1 = mem.State == MEM_RESERVE ? target - (u8*)mem.AllocationBase : 0;
const auto size2 = mem2.State == MEM_RESERVE ? mem2.RegionSize : 0;
if (!::VirtualAlloc(mem.State == MEM_RESERVE ? mem.AllocationBase : target, m_size + size1 + size2, MEM_RESERVE, PAGE_NOACCESS))
{
return;
}
#endif
}
}
+11 -11
View File
@@ -1,6 +1,6 @@
#pragma once
#pragma once
#include "types.h"
#include "util/types.hpp"
#include "StrFmt.h"
#include <vector>
@@ -92,7 +92,7 @@ namespace utils
void set_length(const u32 new_length)
{
end = start + new_length - 1;
ASSERT(valid());
ensure(valid());
}
u32 next_address() const
@@ -282,7 +282,7 @@ namespace utils
public:
// Wrapped functions
inline void reserve(size_t nr) { data.reserve(nr); }
inline void reserve(usz nr) { data.reserve(nr); }
inline void clear() { data.clear(); }
inline size_type size() const { return data.size(); }
inline bool empty() const { return data.empty(); }
@@ -456,9 +456,9 @@ namespace utils
// Will fail if ranges within the vector overlap our touch each-other
bool check_consistency() const
{
size_t _size = data.size();
usz _size = data.size();
for (size_t i = 0; i < _size; ++i)
for (usz i = 0; i < _size; ++i)
{
const auto &r1 = data[i];
if (!r1.valid())
@@ -466,7 +466,7 @@ namespace utils
continue;
}
for (size_t j = i + 1; j < _size; ++j)
for (usz j = i + 1; j < _size; ++j)
{
const auto &r2 = data[j];
if (!r2.valid())
@@ -582,15 +582,15 @@ namespace utils
namespace std
{
static_assert(sizeof(size_t) >= 2 * sizeof(u32), "size_t must be at least twice the size of u32");
static_assert(sizeof(usz) >= 2 * sizeof(u32), "usz must be at least twice the size of u32");
template <>
struct hash<utils::address_range>
{
std::size_t operator()(const utils::address_range& k) const
usz operator()(const utils::address_range& k) const
{
// we can guarantee a unique hash since our type is 64 bits and size_t as well
return (size_t{ k.start } << 32) | size_t{ k.end };
// we can guarantee a unique hash since our type is 64 bits and usz as well
return (usz{ k.start } << 32) | usz{ k.end };
}
};
}
-279
View File
@@ -1,279 +0,0 @@
#pragma once
#include "types.h"
extern bool g_use_rtm;
extern u64 g_rtm_tx_limit1;
namespace utils
{
// Transaction helper (result = pair of success and op result, or just bool)
template <typename F, typename R = std::invoke_result_t<F>>
inline auto tx_start(F op)
{
uint status = -1;
for (auto stamp0 = __rdtsc(), stamp1 = stamp0; g_use_rtm && stamp1 - stamp0 <= g_rtm_tx_limit1; stamp1 = __rdtsc())
{
#ifndef _MSC_VER
__asm__ goto ("xbegin %l[retry];" ::: "memory" : retry);
#else
status = _xbegin();
if (status != _XBEGIN_STARTED) [[unlikely]]
{
goto retry;
}
#endif
if constexpr (std::is_void_v<R>)
{
std::invoke(op);
#ifndef _MSC_VER
__asm__ volatile ("xend;" ::: "memory");
#else
_xend();
#endif
return true;
}
else
{
auto result = std::invoke(op);
#ifndef _MSC_VER
__asm__ volatile ("xend;" ::: "memory");
#else
_xend();
#endif
return std::make_pair(true, std::move(result));
}
retry:
#ifndef _MSC_VER
__asm__ volatile ("movl %%eax, %0;" : "=r" (status) :: "memory");
#endif
if (!status) [[unlikely]]
{
break;
}
}
if constexpr (std::is_void_v<R>)
{
return false;
}
else
{
return std::make_pair(false, R());
}
};
// Rotate helpers
#if defined(__GNUG__)
inline u8 rol8(u8 x, u8 n)
{
#if __has_builtin(__builtin_rotateleft8)
return __builtin_rotateleft8(x, n);
#else
u8 result = x;
__asm__("rolb %[n], %[result]" : [result] "+g"(result) : [n] "c"(n));
return result;
#endif
}
inline u8 ror8(u8 x, u8 n)
{
#if __has_builtin(__builtin_rotateright8)
return __builtin_rotateright8(x, n);
#else
u8 result = x;
__asm__("rorb %[n], %[result]" : [result] "+g"(result) : [n] "c"(n));
return result;
#endif
}
inline u16 rol16(u16 x, u16 n)
{
#if __has_builtin(__builtin_rotateleft16)
return __builtin_rotateleft16(x, n);
#else
u16 result = x;
__asm__("rolw %b[n], %[result]" : [result] "+g"(result) : [n] "c"(n));
return result;
#endif
}
inline u16 ror16(u16 x, u16 n)
{
#if __has_builtin(__builtin_rotateright16)
return __builtin_rotateright16(x, n);
#else
u16 result = x;
__asm__("rorw %b[n], %[result]" : [result] "+g"(result) : [n] "c"(n));
return result;
#endif
}
inline u32 rol32(u32 x, u32 n)
{
#if __has_builtin(__builtin_rotateleft32)
return __builtin_rotateleft32(x, n);
#else
u32 result = x;
__asm__("roll %b[n], %[result]" : [result] "+g"(result) : [n] "c"(n));
return result;
#endif
}
inline u32 ror32(u32 x, u32 n)
{
#if __has_builtin(__builtin_rotateright32)
return __builtin_rotateright32(x, n);
#else
u32 result = x;
__asm__("rorl %b[n], %[result]" : [result] "+g"(result) : [n] "c"(n));
return result;
#endif
}
inline u64 rol64(u64 x, u64 n)
{
#if __has_builtin(__builtin_rotateleft64)
return __builtin_rotateleft64(x, n);
#else
u64 result = x;
__asm__("rolq %b[n], %[result]" : [result] "+g"(result) : [n] "c"(n));
return result;
#endif
}
inline u64 ror64(u64 x, u64 n)
{
#if __has_builtin(__builtin_rotateright64)
return __builtin_rotateright64(x, n);
#else
u64 result = x;
__asm__("rorq %b[n], %[result]" : [result] "+g"(result) : [n] "c"(n));
return result;
#endif
}
constexpr u64 umulh64(u64 a, u64 b)
{
const __uint128_t x = a;
const __uint128_t y = b;
return (x * y) >> 64;
}
constexpr s64 mulh64(s64 a, s64 b)
{
const __int128_t x = a;
const __int128_t y = b;
return (x * y) >> 64;
}
constexpr s64 div128(s64 high, s64 low, s64 divisor, s64* remainder = nullptr)
{
const __int128_t x = (__uint128_t{u64(high)} << 64) | u64(low);
const __int128_t r = x / divisor;
if (remainder)
{
*remainder = x % divisor;
}
return r;
}
constexpr u64 udiv128(u64 high, u64 low, u64 divisor, u64* remainder = nullptr)
{
const __uint128_t x = (__uint128_t{high} << 64) | low;
const __uint128_t r = x / divisor;
if (remainder)
{
*remainder = x % divisor;
}
return r;
}
#elif defined(_MSC_VER)
inline u8 rol8(u8 x, u8 n)
{
return _rotl8(x, n);
}
inline u8 ror8(u8 x, u8 n)
{
return _rotr8(x, n);
}
inline u16 rol16(u16 x, u16 n)
{
return _rotl16(x, (u8)n);
}
inline u16 ror16(u16 x, u16 n)
{
return _rotr16(x, (u8)n);
}
inline u32 rol32(u32 x, u32 n)
{
return _rotl(x, (int)n);
}
inline u32 ror32(u32 x, u32 n)
{
return _rotr(x, (int)n);
}
inline u64 rol64(u64 x, u64 n)
{
return _rotl64(x, (int)n);
}
inline u64 ror64(u64 x, u64 n)
{
return _rotr64(x, (int)n);
}
inline u64 umulh64(u64 x, u64 y)
{
return __umulh(x, y);
}
inline s64 mulh64(s64 x, s64 y)
{
return __mulh(x, y);
}
inline s64 div128(s64 high, s64 low, s64 divisor, s64* remainder = nullptr)
{
s64 rem;
s64 r = _div128(high, low, divisor, &rem);
if (remainder)
{
*remainder = rem;
}
return r;
}
inline u64 udiv128(u64 high, u64 low, u64 divisor, u64* remainder = nullptr)
{
u64 rem;
u64 r = _udiv128(high, low, divisor, &rem);
if (remainder)
{
*remainder = rem;
}
return r;
}
#endif
} // namespace utils
+61 -152
View File
@@ -1,15 +1,13 @@
#include "bin_patch.h"
#include "bin_patch.h"
#include "File.h"
#include "Config.h"
#include "version.h"
#include "Emu/System.h"
LOG_CHANNEL(patch_log);
#include "util/types.hpp"
#include "util/endian.hpp"
namespace config_key
{
static const std::string enable_legacy_patches = "Enable Legacy Patches";
}
LOG_CHANNEL(patch_log, "PAT");
template <>
void fmt_class_string<YAML::NodeType::value>::format(std::string& out, u64 arg)
@@ -46,9 +44,12 @@ void fmt_class_string<patch_type>::format(std::string& out, u64 arg)
case patch_type::bef64: return "bef64";
case patch_type::be16: return "be16";
case patch_type::be32: return "be32";
case patch_type::bd32: return "bd32";
case patch_type::be64: return "be64";
case patch_type::bd64: return "bd64";
case patch_type::lef32: return "lef32";
case patch_type::lef64: return "lef64";
case patch_type::utf8: return "utf8";
}
return unknown;
@@ -125,16 +126,14 @@ bool patch_engine::load(patch_map& patches_map, const std::string& path, std::st
}
// Load patch config to determine which patches are enabled
bool enable_legacy_patches = false;
patch_map patch_config;
if (!importing)
{
patch_config = load_config(enable_legacy_patches);
patch_config = load_config();
}
std::string version;
bool is_legacy_patch = false;
if (const auto version_node = root[patch_key::version])
{
@@ -150,17 +149,12 @@ bool patch_engine::load(patch_map& patches_map, const std::string& path, std::st
// We don't need the Version node in local memory anymore
root.remove(patch_key::version);
}
else if (importing)
else
{
append_log_message(log_messages, fmt::format("Error: No '%s' entry found. Patch engine version = %s (file: %s)", patch_key::version, patch_engine_version, path));
patch_log.error("No '%s' entry found. Patch engine version = %s (file: %s)", patch_key::version, patch_engine_version, path);
return false;
}
else
{
patch_log.warning("Patch engine version %s: Reading legacy patch file %s", patch_engine_version, path);
is_legacy_patch = true;
}
bool is_valid = true;
@@ -169,30 +163,6 @@ bool patch_engine::load(patch_map& patches_map, const std::string& path, std::st
{
const auto& main_key = pair.first.Scalar();
// Use old logic and yaml layout if this is a legacy patch
if (is_legacy_patch)
{
struct patch_info info{};
info.hash = main_key;
info.is_enabled = enable_legacy_patches;
info.is_legacy = true;
info.source_path = path;
if (!read_patch_node(info, pair.second, root, log_messages))
{
is_valid = false;
}
// Find or create an entry matching the key/hash in our map
auto& container = patches_map[main_key];
container.hash = main_key;
container.is_legacy = true;
container.patch_info_map["legacy"] = info;
continue;
}
// Use new logic and yaml layout
if (const auto yml_type = pair.second.Type(); yml_type != YAML::NodeType::Map)
{
append_log_message(log_messages, fmt::format("Error: Skipping key %s: expected Map, found %s", main_key, yml_type));
@@ -209,7 +179,6 @@ 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];
container.is_legacy = false;
container.hash = main_key;
container.version = version;
@@ -428,35 +397,6 @@ bool patch_engine::add_patch_data(YAML::Node node, patch_info& info, u32 modifie
{
// Special syntax: anchors (named sequence)
// Most legacy patches don't use the anchor syntax correctly, so try to sanitize it.
if (info.is_legacy)
{
if (const auto yml_type = addr_node.Type(); yml_type == YAML::NodeType::Scalar)
{
if (!root)
{
patch_log.fatal("Trying to parse legacy patch with invalid root."); // Sanity Check
return false;
}
const auto anchor = addr_node.Scalar();
const auto anchor_node = root[anchor];
if (anchor_node)
{
addr_node = anchor_node;
append_log_message(log_messages, fmt::format("Incorrect anchor syntax found in legacy patch: %s (key: %s)", anchor, info.hash));
patch_log.warning("Incorrect anchor syntax found in legacy patch: %s (key: %s)", anchor, info.hash);
}
else
{
append_log_message(log_messages, fmt::format("Anchor not found in legacy patch: %s (key: %s)", anchor, info.hash));
patch_log.error("Anchor not found in legacy patch: %s (key: %s)", anchor, info.hash);
return false;
}
}
}
// Check if the anchor was resolved.
if (const auto yml_type = addr_node.Type(); yml_type != YAML::NodeType::Sequence)
{
@@ -490,6 +430,10 @@ bool patch_engine::add_patch_data(YAML::Node node, patch_info& info, u32 modifie
switch (p_data.type)
{
case patch_type::utf8:
{
break;
}
case patch_type::bef32:
case patch_type::lef32:
case patch_type::bef64:
@@ -524,7 +468,7 @@ bool patch_engine::read_patch_node(patch_info& info, YAML::Node node, const YAML
if (!node)
{
append_log_message(log_messages, fmt::format("Skipping invalid patch node %s. (key: %s)", info.description, info.hash));
patch_log.error("Skipping invalid patch node %s. (key: %s)" HERE, info.description, info.hash);
patch_log.error("Skipping invalid patch node %s. (key: %s)", info.description, info.hash);
return false;
}
@@ -550,10 +494,7 @@ bool patch_engine::read_patch_node(patch_info& info, YAML::Node node, const YAML
void patch_engine::append_global_patches()
{
// Legacy patch.yml
load(m_map, fs::get_config_dir() + "patch.yml");
// New patch.yml
// Regular patch.yml
load(m_map, get_patches_path() + "patch.yml");
// Imported patch.yml
@@ -567,45 +508,30 @@ void patch_engine::append_title_patches(const std::string& title_id)
return;
}
// Legacy patch.yml
load(m_map, fs::get_config_dir() + "data/" + title_id + "/patch.yml");
// New patch.yml
// Regular patch.yml
load(m_map, get_patches_path() + title_id + "_patch.yml");
}
std::size_t patch_engine::apply(const std::string& name, u8* dst)
static std::basic_string<u32> apply_modification(const patch_engine::patch_info& patch, u8* dst, u32 filesz, u32 min_addr)
{
return apply_patch<false>(name, dst, 0, 0);
}
std::size_t patch_engine::apply_with_ls_check(const std::string& name, u8* dst, u32 filesz, u32 ls_addr)
{
return apply_patch<true>(name, dst, filesz, ls_addr);
}
template <bool check_local_storage>
static std::size_t apply_modification(const patch_engine::patch_info& patch, u8* dst, u32 filesz, u32 ls_addr)
{
size_t applied = 0;
std::basic_string<u32> applied;
for (const auto& p : patch.data_list)
{
u32 offset = p.offset;
if constexpr (check_local_storage)
if (offset < min_addr || offset - min_addr >= filesz)
{
if (offset < ls_addr || offset >= (ls_addr + filesz))
{
// This patch is out of range for this segment
continue;
}
offset -= ls_addr;
// This patch is out of range for this segment
continue;
}
offset -= min_addr;
auto ptr = dst + offset;
u32 resval = -1;
switch (p.type)
{
case patch_type::invalid:
@@ -649,9 +575,15 @@ static std::size_t apply_modification(const patch_engine::patch_info& patch, u8*
*reinterpret_cast<be_t<u16, 1>*>(ptr) = static_cast<u16>(p.value.long_value);
break;
}
case patch_type::bd32:
{
*reinterpret_cast<be_t<u32, 1>*>(ptr) = static_cast<u32>(p.value.long_value);
break;
}
case patch_type::be32:
{
*reinterpret_cast<be_t<u32, 1>*>(ptr) = static_cast<u32>(p.value.long_value);
if (offset % 4 == 0) resval = offset;
break;
}
case patch_type::bef32:
@@ -659,9 +591,22 @@ static std::size_t apply_modification(const patch_engine::patch_info& patch, u8*
*reinterpret_cast<be_t<u32, 1>*>(ptr) = std::bit_cast<u32, f32>(static_cast<f32>(p.value.double_value));
break;
}
case patch_type::bd64:
{
*reinterpret_cast<be_t<u64, 1>*>(ptr) = static_cast<u64>(p.value.long_value);
break;
}
case patch_type::be64:
{
*reinterpret_cast<be_t<u64, 1>*>(ptr) = static_cast<u64>(p.value.long_value);
if (offset % 4)
{
break;
}
resval = offset;
applied.push_back((offset + 7) & -4); // Two 32-bit locations
break;
}
case patch_type::bef64:
@@ -669,29 +614,33 @@ static std::size_t apply_modification(const patch_engine::patch_info& patch, u8*
*reinterpret_cast<be_t<u64, 1>*>(ptr) = std::bit_cast<u64, f64>(p.value.double_value);
break;
}
case patch_type::utf8:
{
std::memcpy(ptr, p.original_value.data(), p.original_value.size());
break;
}
}
++applied;
// Possibly an executable instruction
applied.push_back(resval);
}
return applied;
}
template <bool check_local_storage>
std::size_t patch_engine::apply_patch(const std::string& name, u8* dst, u32 filesz, u32 ls_addr)
std::basic_string<u32> patch_engine::apply(const std::string& name, u8* dst, u32 filesz, u32 min_addr)
{
if (m_map.find(name) == m_map.cend())
{
return 0;
return {};
}
size_t applied_total = 0;
std::basic_string<u32> applied_total;
const auto& container = m_map.at(name);
const auto serial = Emu.GetTitleID();
const auto app_version = Emu.GetAppVersion();
// Different containers in order to seperate the patches
std::vector<patch_engine::patch_info> legacy_patches;
std::vector<patch_engine::patch_info> patches_for_this_serial_and_this_version;
std::vector<patch_engine::patch_info> patches_for_this_serial_and_all_versions;
std::vector<patch_engine::patch_info> patches_for_all_serials_and_this_version;
@@ -700,17 +649,6 @@ std::size_t patch_engine::apply_patch(const std::string& name, u8* dst, u32 file
// Sort patches into different vectors based on their serial and version
for (const auto& [description, patch] : container.patch_info_map)
{
// Find out if this legacy patch is enabled
if (patch.is_legacy)
{
if (patch.is_enabled)
{
legacy_patches.push_back(patch);
}
continue;
}
// Find out if this patch is enabled
for (const auto& [title, serials] : patch.titles)
{
@@ -777,7 +715,6 @@ std::size_t patch_engine::apply_patch(const std::string& name, u8* dst, u32 file
// Sort specific patches in front of global patches
std::vector<patch_engine::patch_info> sorted_patches;
sorted_patches.insert(sorted_patches.end(), legacy_patches.begin(), legacy_patches.end());
sorted_patches.insert(sorted_patches.end(), patches_for_this_serial_and_this_version.begin(), patches_for_this_serial_and_this_version.end());
sorted_patches.insert(sorted_patches.end(), patches_for_this_serial_and_all_versions.begin(), patches_for_this_serial_and_all_versions.end());
sorted_patches.insert(sorted_patches.end(), patches_for_all_serials_and_this_version.begin(), patches_for_all_serials_and_this_version.end());
@@ -796,23 +733,17 @@ std::size_t patch_engine::apply_patch(const std::string& name, u8* dst, u32 file
m_applied_groups.insert(patch.patch_group);
}
const size_t applied = apply_modification<check_local_storage>(patch, dst, filesz, ls_addr);
auto applied = apply_modification(patch, dst, filesz, min_addr);
applied_total += applied;
if (patch.is_legacy)
{
patch_log.success("Applied legacy patch (hash='%s')(<- %d)", patch.hash, applied);
}
else
{
patch_log.success("Applied patch (hash='%s', description='%s', author='%s', patch_version='%s', file_version='%s') (<- %d)", patch.hash, patch.description, patch.author, patch.patch_version, patch.version, applied);
}
patch_log.success("Applied patch (hash='%s', description='%s', author='%s', patch_version='%s', file_version='%s') (<- %u)", patch.hash, patch.description, patch.author, patch.patch_version, patch.version, applied.size());
}
return applied_total;
}
void patch_engine::save_config(const patch_map& patches_map, bool enable_legacy_patches)
void patch_engine::save_config(const patch_map& patches_map)
{
const std::string path = get_patch_config_path();
patch_log.notice("Saving patch config file %s", path);
@@ -827,26 +758,13 @@ void patch_engine::save_config(const patch_map& patches_map, bool enable_legacy_
YAML::Emitter out;
out << YAML::BeginMap;
// Save "Enable Legacy Patches"
out << config_key::enable_legacy_patches << enable_legacy_patches;
// Save 'enabled' state per hash, description, serial and app_version
patch_map config_map;
for (const auto& [hash, container] : patches_map)
{
if (container.is_legacy)
{
continue;
}
for (const auto& [description, patch] : container.patch_info_map)
{
if (patch.is_legacy)
{
continue;
}
for (const auto& [title, serials] : patch.titles)
{
for (const auto& [serial, app_versions] : serials)
@@ -903,7 +821,7 @@ void patch_engine::save_config(const patch_map& patches_map, bool enable_legacy_
file.write(out.c_str(), out.size());
}
static void append_patches(patch_engine::patch_map& existing_patches, const patch_engine::patch_map& new_patches, size_t& count, size_t& total, std::stringstream* log_messages)
static void append_patches(patch_engine::patch_map& existing_patches, const patch_engine::patch_map& new_patches, usz& count, usz& total, std::stringstream* log_messages)
{
for (const auto& [hash, new_container] : new_patches)
{
@@ -1055,7 +973,7 @@ bool patch_engine::save_patches(const patch_map& patches, const std::string& pat
return true;
}
bool patch_engine::import_patches(const patch_engine::patch_map& patches, const std::string& path, size_t& count, size_t& total, std::stringstream* log_messages)
bool patch_engine::import_patches(const patch_engine::patch_map& patches, const std::string& path, usz& count, usz& total, std::stringstream* log_messages)
{
patch_engine::patch_map existing_patches;
@@ -1089,10 +1007,8 @@ bool patch_engine::remove_patch(const patch_info& info)
return false;
}
patch_engine::patch_map patch_engine::load_config(bool& enable_legacy_patches)
patch_engine::patch_map patch_engine::load_config()
{
enable_legacy_patches = true; // Default to true
patch_map config_map;
const std::string path = get_patch_config_path();
@@ -1108,13 +1024,6 @@ patch_engine::patch_map patch_engine::load_config(bool& enable_legacy_patches)
return config_map;
}
// Try to load "Enable Legacy Patches" (default to true)
if (auto enable_legacy_node = root[config_key::enable_legacy_patches])
{
enable_legacy_patches = enable_legacy_node.as<bool>(true);
root.remove(config_key::enable_legacy_patches); // Remove the node in order to skip it in the next part
}
for (const auto pair : root)
{
const auto& hash = pair.first.Scalar();
+10 -17
View File
@@ -1,10 +1,10 @@
#pragma once
#pragma once
#include "BEType.h"
#include <vector>
#include <string>
#include <unordered_map>
#include "util/types.hpp"
#include "util/yaml.hpp"
namespace patch_key
@@ -34,9 +34,12 @@ enum class patch_type
lef64,
be16,
be32,
bd32, // be32 with data hint (non-code)
be64,
bd64, // be64 with data hint (non-code)
bef32,
bef64,
utf8, // Text of string (not null-terminated automatically)
};
class patch_engine
@@ -53,7 +56,7 @@ public:
f64 double_value;
} value { 0 };
};
using patch_app_versions = std::unordered_map<std::string /*app_version*/, bool /*enabled*/>;
using patch_serials = std::unordered_map<std::string /*serial*/, patch_app_versions>;
using patch_titles = std::unordered_map<std::string /*serial*/, patch_serials>;
@@ -73,8 +76,6 @@ public:
// Redundant information for accessibility (see patch_container)
std::string hash;
std::string version;
bool is_legacy = false;
bool is_enabled = false; // only for legacy patches
};
struct patch_container
@@ -82,7 +83,6 @@ public:
std::unordered_map<std::string /*description*/, patch_info> patch_info_map;
std::string hash;
std::string version;
bool is_legacy = false;
};
using patch_map = std::unordered_map<std::string /*hash*/, patch_container>;
@@ -111,19 +111,19 @@ public:
static bool add_patch_data(YAML::Node node, patch_info& info, u32 modifier, const YAML::Node& root, std::stringstream* log_messages = nullptr);
// Save to patch_config.yml
static void save_config(const patch_map& patches_map, bool enable_legacy_patches);
static void save_config(const patch_map& patches_map);
// Save a patch file
static bool save_patches(const patch_map& patches, const std::string& path, std::stringstream* log_messages = nullptr);
// Create or append patches to a file
static bool import_patches(const patch_map& patches, const std::string& path, size_t& count, size_t& total, std::stringstream* log_messages = nullptr);
static bool import_patches(const patch_map& patches, const std::string& path, usz& count, usz& total, std::stringstream* log_messages = nullptr);
// Remove a patch from a file
static bool remove_patch(const patch_info& info);
// Load patch_config.yml
static patch_map load_config(bool& enable_legacy_patches);
static patch_map load_config();
// Load from file and append to member patches map
void append_global_patches();
@@ -132,16 +132,9 @@ public:
void append_title_patches(const std::string& title_id);
// Apply patch (returns the number of entries applied)
std::size_t apply(const std::string& name, u8* dst);
// Apply patch with a check that the address exists in SPU local storage
std::size_t apply_with_ls_check(const std::string& name, u8* dst, u32 filesz, u32 ls_addr);
std::basic_string<u32> apply(const std::string& name, u8* dst, u32 filesz = UINT32_MAX, u32 min_addr = 0);
private:
// Internal: Apply patch (returns the number of entries applied)
template <bool check_local_storage>
std::size_t apply_patch(const std::string& name, u8* dst, u32 filesz, u32 ls_addr);
// Database
patch_map m_map;
+10 -10
View File
@@ -21,8 +21,9 @@ Examples:
Intersection (&) and symmetric difference (^) is also available.
*/
#include "types.h"
#include "util/types.hpp"
#include "util/atomic.hpp"
#include "Utilities/StrFmt.h"
template <typename T>
class atomic_bs_t;
@@ -48,8 +49,8 @@ private:
}
public:
static constexpr std::size_t bitmax = sizeof(T) * 8;
static constexpr std::size_t bitsize = static_cast<under>(T::__bitset_enum_max);
static constexpr usz bitmax = sizeof(T) * 8;
static constexpr usz bitsize = static_cast<under>(T::__bitset_enum_max);
static_assert(std::is_enum<T>::value, "bs_t<> error: invalid type (must be enum)");
static_assert(bitsize <= bitmax, "bs_t<> error: invalid __bitset_enum_max");
@@ -205,7 +206,7 @@ constexpr bs_t<T> operator ^(T lhs, T rhs)
// Atomic bitset specialization with optimized operations
template <typename T>
class atomic_bs_t : public atomic_t<::bs_t<T>> // TODO: true specialization
class atomic_bs_t : public atomic_t<::bs_t<T>>
{
// Corresponding bitset type
using bs_t = ::bs_t<T>;
@@ -379,11 +380,6 @@ public:
return lhs.m_data != rhs.load().m_data;
}
bool test(const bs_t& rhs)
{
return base::load().test(rhs);
}
bool test_and_set(T rhs)
{
return atomic_storage<under>::bts(m_data.m_data, static_cast<uint>(static_cast<under>(rhs)));
@@ -394,10 +390,14 @@ public:
return atomic_storage<under>::btr(m_data.m_data, static_cast<uint>(static_cast<under>(rhs)));
}
bool test_and_complement(T rhs)
bool test_and_invert(T rhs)
{
return atomic_storage<under>::btc(m_data.m_data, static_cast<uint>(static_cast<under>(rhs)));
}
bool bit_test_set(uint bit) = delete;
bool bit_test_reset(uint bit) = delete;
bool bit_test_invert(uint bit) = delete;
};
template <typename T>
+22 -22
View File
@@ -1,12 +1,12 @@
#pragma once
#include "types.h"
#include "util/types.hpp"
#include <climits>
#include <string>
#include <vector>
#include <algorithm>
static const size_t size_dropped = std::numeric_limits<size_t>::max();
static const usz size_dropped = -1;
/*
C-style format parser. Appends formatted string to `out`, returns number of characters written.
@@ -15,13 +15,13 @@ C-style format parser. Appends formatted string to `out`, returns number of char
`src`: rvalue reference to argument provider.
*/
template<typename Dst, typename Char, typename Src>
std::size_t cfmt_append(Dst& out, const Char* fmt, Src&& src)
usz cfmt_append(Dst& out, const Char* fmt, Src&& src)
{
const std::size_t start_pos = out.size();
const usz start_pos = out.size();
struct cfmt_context
{
std::size_t size; // Size of current format sequence
usz size; // Size of current format sequence
u8 args; // Number of extra args used
u8 type; // Integral type bytesize
@@ -80,7 +80,7 @@ std::size_t cfmt_append(Dst& out, const Char* fmt, Src&& src)
const auto write_decimal = [&](u64 value, s64 min_size)
{
const std::size_t start = out.size();
const usz start = out.size();
do
{
@@ -90,7 +90,7 @@ std::size_t cfmt_append(Dst& out, const Char* fmt, Src&& src)
while (0 < --min_size || value);
// Revert written characters
for (std::size_t i = start, j = out.size() - 1; i < j; i++, j--)
for (usz i = start, j = out.size() - 1; i < j; i++, j--)
{
std::swap(out[i], out[j]);
}
@@ -285,7 +285,7 @@ std::size_t cfmt_append(Dst& out, const Char* fmt, Src&& src)
break;
}
const std::size_t start = out.size();
const usz start = out.size();
out.push_back(src.template get<Char>(ctx.args));
if (1 < ctx.width)
@@ -307,8 +307,8 @@ std::size_t cfmt_append(Dst& out, const Char* fmt, Src&& src)
break;
}
const std::size_t start = out.size();
const std::size_t size1 = src.fmt_string(out, ctx.args);
const usz start = out.size();
const usz size1 = src.fmt_string(out, ctx.args);
if (ctx.dot && size1 > ctx.prec)
{
@@ -316,7 +316,7 @@ std::size_t cfmt_append(Dst& out, const Char* fmt, Src&& src)
out.resize(start + ctx.prec);
}
const std::size_t size2 = out.size() - start;
const usz size2 = out.size() - start;
if (size2 < ctx.width)
{
@@ -352,7 +352,7 @@ std::size_t cfmt_append(Dst& out, const Char* fmt, Src&& src)
const u64 val = src.template get<u64>(ctx.args);
const bool negative = ctx.type && static_cast<s64>(val) < 0;
const std::size_t start = out.size();
const usz start = out.size();
if (!ctx.dot || ctx.prec)
{
@@ -372,7 +372,7 @@ std::size_t cfmt_append(Dst& out, const Char* fmt, Src&& src)
write_decimal(negative ? 0 - val : val, ctx.prec);
}
const std::size_t size2 = out.size() - start;
const usz size2 = out.size() - start;
if (size2 < ctx.width)
{
@@ -419,7 +419,7 @@ std::size_t cfmt_append(Dst& out, const Char* fmt, Src&& src)
// Trunc sign-extended signed types
const u64 val = src.template get<u64>(ctx.args) & mask;
const std::size_t start = out.size();
const usz start = out.size();
if (ctx.alter)
{
@@ -435,7 +435,7 @@ std::size_t cfmt_append(Dst& out, const Char* fmt, Src&& src)
write_octal(val, ctx.prec);
}
const std::size_t size2 = out.size() - start;
const usz size2 = out.size() - start;
if (size2 < ctx.width)
{
@@ -476,7 +476,7 @@ std::size_t cfmt_append(Dst& out, const Char* fmt, Src&& src)
// Trunc sign-extended signed types
const u64 val = src.template get<u64>(ctx.args) & mask;
const std::size_t start = out.size();
const usz start = out.size();
if (ctx.alter)
{
@@ -493,7 +493,7 @@ std::size_t cfmt_append(Dst& out, const Char* fmt, Src&& src)
write_hex(val, ch == 'X', ctx.prec);
}
const std::size_t size2 = out.size() - start;
const usz size2 = out.size() - start;
if (size2 < ctx.width)
{
@@ -540,14 +540,14 @@ std::size_t cfmt_append(Dst& out, const Char* fmt, Src&& src)
// Trunc sign-extended signed types
const u64 val = src.template get<u64>(ctx.args) & mask;
const std::size_t start = out.size();
const usz start = out.size();
if (!ctx.dot || ctx.prec)
{
write_decimal(val, ctx.prec);
}
const std::size_t size2 = out.size() - start;
const usz size2 = out.size() - start;
if (size2 < ctx.width)
{
@@ -570,11 +570,11 @@ std::size_t cfmt_append(Dst& out, const Char* fmt, Src&& src)
const u64 val = src.template get<u64>(ctx.args);
const std::size_t start = out.size();
const usz start = out.size();
write_hex(val, false, sizeof(void*) * 2);
const std::size_t size2 = out.size() - start;
const usz size2 = out.size() - start;
if (size2 < ctx.width)
{
@@ -610,7 +610,7 @@ std::size_t cfmt_append(Dst& out, const Char* fmt, Src&& src)
const u64 arg1 = ctx.args >= 1 ? src.template get<u64>(1) : 0;
const u64 arg2 = ctx.args >= 2 ? src.template get<u64>(2) : 0;
if (const std::size_t _size = std::snprintf(0, 0, _fmt.c_str(), arg0, arg1, arg2))
if (const usz _size = std::snprintf(0, 0, _fmt.c_str(), arg0, arg1, arg2))
{
out.resize(out.size() + _size);
std::snprintf(&out.front() + out.size() - _size, _size + 1, _fmt.c_str(), arg0, arg1, arg2);
+1 -1
View File
@@ -1,4 +1,4 @@
#include "stdafx.h"
#include "stdafx.h"
#include "cheat_info.h"
#include "Config.h"
#include "StrUtil.h"
+4 -2
View File
@@ -1,6 +1,8 @@
#pragma once
#pragma once
#include "stdafx.h"
#include "util/types.hpp"
#include <string>
enum class cheat_type : u8
{
+4 -4
View File
@@ -1,4 +1,4 @@
#include "cond.h"
#include "cond.h"
#include "sync.h"
#include "lockless.h"
@@ -9,7 +9,7 @@
void cond_variable::imp_wait(u32 _old, u64 _timeout) noexcept
{
// Not supposed to fail
verify(HERE), _old;
ensure(_old);
// Wait with timeout
m_value.wait(_old, c_signal_mask, atomic_wait_timeout{_timeout > max_timeout ? UINT64_MAX : _timeout * 1000});
@@ -50,10 +50,10 @@ void cond_variable::imp_wake(u32 _count) noexcept
if (_count > 1 || ((_old + (c_signal_mask & (0 - c_signal_mask))) & c_signal_mask) == c_signal_mask)
{
// Resort to notify_all if signal count reached max
m_value.notify_all();
m_value.notify_all(c_signal_mask);
}
else
{
m_value.notify_one();
m_value.notify_one(c_signal_mask);
}
}
+1 -2
View File
@@ -1,8 +1,7 @@
#pragma once
#include "types.h"
#include "util/types.hpp"
#include "util/atomic.hpp"
#include <shared_mutex>
// Lightweight condition variable
class cond_variable
+1 -1
View File
@@ -1,4 +1,4 @@
#pragma once
#pragma once
#include <cmath>
+19 -9
View File
@@ -1,33 +1,43 @@
#pragma once
#include "Utilities/types.h"
#include "util/types.hpp"
namespace rpcs3
{
constexpr usz fnv_seed = 14695981039346656037ull;
constexpr usz fnv_prime = 1099511628211ull;
template<typename T>
static size_t hash_base(T value)
static usz hash_base(T value)
{
return static_cast<size_t>(value);
return static_cast<usz>(value);
}
template<typename T, typename = std::enable_if_t<std::is_integral<T>::value, bool>>
static inline usz hash64(usz hash_value, const T data)
{
hash_value ^= data;
hash_value *= fnv_prime;
return hash_value;
}
template<typename T, typename U>
static size_t hash_struct_base(const T& value)
static usz hash_struct_base(const T& value)
{
// FNV 64-bit
size_t result = 14695981039346656037ull;
usz result = fnv_seed;
const U *bits = reinterpret_cast<const U*>(&value);
for (size_t n = 0; n < (sizeof(T) / sizeof(U)); ++n)
for (usz n = 0; n < (sizeof(T) / sizeof(U)); ++n)
{
result ^= bits[n];
result *= 1099511628211ull;
result = hash64(result, bits[n]);
}
return result;
}
template<typename T>
static size_t hash_struct(const T& value)
static usz hash_struct(const T& value)
{
static constexpr auto block_sz = sizeof(T);
+20 -67
View File
@@ -1,6 +1,6 @@
#pragma once
#pragma once
#include "types.h"
#include "util/types.hpp"
#include "util/atomic.hpp"
//! Simple sizeless array base for concurrent access. Cannot shrink, only growths automatically.
@@ -8,7 +8,7 @@
//!
//! T is the type of elements. Currently, default constructor of T shall be constexpr.
//! N is initial element count, available without any memory allocation and only stored contiguously.
template <typename T, std::size_t N>
template <typename T, usz N>
class lf_array
{
// Data (default-initialized)
@@ -28,7 +28,7 @@ public:
}
}
T& operator [](std::size_t index)
T& operator [](usz index)
{
if (index < N) [[likely]]
{
@@ -51,7 +51,7 @@ public:
//! Simple lock-free FIFO queue base. Based on lf_array<T, N> itself. Currently uses 32-bit counters.
//! There is no "push_end" or "pop_begin" provided, the queue element must signal its state on its own.
template<typename T, std::size_t N>
template<typename T, usz N>
class lf_fifo : public lf_array<T, N>
{
// LSB 32-bit: push, MSB 32-bit: pop
@@ -307,14 +307,25 @@ public:
delete m_head.load();
}
void wait() noexcept
template <atomic_wait::op Flags = atomic_wait::op::eq>
void wait(std::nullptr_t null = nullptr) noexcept
{
if (m_head == nullptr)
{
m_head.wait(nullptr);
m_head.template wait<Flags>(nullptr);
}
}
const volatile void* observe() const noexcept
{
return m_head.load();
}
explicit operator bool() const noexcept
{
return m_head != nullptr;
}
template <typename... Args>
void push(Args&&... args)
{
@@ -343,9 +354,9 @@ public:
// Apply func(data) to each element, return the total length
template <typename F>
std::size_t apply(F func)
usz apply(F func)
{
std::size_t count = 0;
usz count = 0;
for (auto slice = pop_all(); slice; slice.pop_front())
{
@@ -354,64 +365,6 @@ public:
return count;
}
// Iterator that enables direct endless range-for loop: for (auto* ptr : queue) ...
class iterator
{
lf_queue* _this = nullptr;
lf_queue_slice<T> m_data;
public:
constexpr iterator() = default;
explicit iterator(lf_queue* _this)
: _this(_this)
{
m_data = _this->pop_all();
}
bool operator !=(const iterator& rhs) const
{
return _this != rhs._this;
}
T* operator *() const
{
return m_data ? m_data.get() : nullptr;
}
iterator& operator ++()
{
if (m_data)
{
m_data.pop_front();
}
if (!m_data)
{
m_data = _this->pop_all();
if (!m_data)
{
_this->wait();
m_data = _this->pop_all();
}
}
return *this;
}
};
iterator begin()
{
return iterator{this};
}
iterator end()
{
return iterator{};
}
};
// Concurrent linked list, elements remain until destroyed.
+11 -9
View File
@@ -1,8 +1,10 @@
#include "mutex.h"
#include "util/asm.hpp"
void shared_mutex::imp_lock_shared(u32 val)
{
verify("shared_mutex underflow" HERE), val < c_err;
ensure(val < c_err); // "shared_mutex underflow"
for (int i = 0; i < 10; i++)
{
@@ -23,14 +25,14 @@ void shared_mutex::imp_lock_shared(u32 val)
return;
}
verify("shared_mutex overflow" HERE), (old % c_sig) + c_one < c_sig;
ensure((old % c_sig) + c_one < c_sig); // "shared_mutex overflow"
imp_wait();
lock_downgrade();
}
void shared_mutex::imp_unlock_shared(u32 old)
{
verify("shared_mutex underflow" HERE), old - 1 < c_err;
ensure(old - 1 < c_err); // "shared_mutex underflow"
// Check reader count, notify the writer if necessary
if ((old - 1) % c_one == 0)
@@ -59,19 +61,19 @@ void shared_mutex::imp_wait()
break;
}
m_value.wait(old);
m_value.wait(old, c_sig);
}
}
void shared_mutex::imp_signal()
{
m_value += c_sig;
m_value.notify_one();
m_value.notify_one(c_sig);
}
void shared_mutex::imp_lock(u32 val)
{
verify("shared_mutex underflow" HERE), val < c_err;
ensure(val < c_err); // "shared_mutex underflow"
for (int i = 0; i < 10; i++)
{
@@ -90,13 +92,13 @@ void shared_mutex::imp_lock(u32 val)
return;
}
verify("shared_mutex overflow" HERE), (old % c_sig) + c_one < c_sig;
ensure((old % c_sig) + c_one < c_sig); // "shared_mutex overflow"
imp_wait();
}
void shared_mutex::imp_unlock(u32 old)
{
verify("shared_mutex underflow" HERE), old - c_one < c_err;
ensure(old - c_one < c_err); // "shared_mutex underflow"
// 1) Notify the next writer if necessary
// 2) Notify all readers otherwise if necessary (currently indistinguishable from writers)
@@ -121,7 +123,7 @@ void shared_mutex::imp_lock_upgrade()
// Convert to writer lock
const u32 old = m_value.fetch_add(c_one - 1);
verify("shared_mutex overflow" HERE), (old % c_sig) + c_one - 1 < c_sig;
ensure((old % c_sig) + c_one - 1 < c_sig); // "shared_mutex overflow"
if (old % c_one == 1)
{
+1 -1
View File
@@ -1,7 +1,7 @@
#pragma once
#include <mutex>
#include "types.h"
#include "util/types.hpp"
#include "util/atomic.hpp"
// Shared mutex with small size (u32).
+1 -4
View File
@@ -1,7 +1,5 @@
#include "stdafx.h"
#include "restore_new.h"
#include "Utilities/rXml.h"
#include "define_new_memleakdetect.h"
rXmlNode::rXmlNode() : handle()
{
@@ -54,7 +52,7 @@ std::string rXmlNode::GetAttribute(const std::string &name)
std::string rXmlNode::GetNodeContent()
{
return handle.text().get();
return handle.text().get();
}
rXmlDocument::rXmlDocument() : handle()
@@ -70,4 +68,3 @@ std::shared_ptr<rXmlNode> rXmlDocument::GetRoot()
{
return std::make_shared<rXmlNode>(handle.root());
}
+1 -1
View File
@@ -1,4 +1,4 @@
#pragma once
#pragma once
#include <pugixml.hpp>
#include <memory>
+3 -1
View File
@@ -1,5 +1,7 @@
#include "sema.h"
#include "util/asm.hpp"
void semaphore_base::imp_wait()
{
for (int i = 0; i < 10; i++)
@@ -52,7 +54,7 @@ void semaphore_base::imp_wait()
void semaphore_base::imp_post(s32 _old)
{
verify("semaphore_base: overflow" HERE), _old < 0;
ensure(_old < 0); // "semaphore_base: overflow"
m_value.notify_one();
}
+1 -1
View File
@@ -1,7 +1,7 @@
#pragma once
#include <mutex>
#include "types.h"
#include "util/types.hpp"
#include "util/atomic.hpp"
// Lightweight semaphore helper class
+7 -3
View File
@@ -2,11 +2,14 @@
/* For internal use. Don't include. */
#include "types.h"
#include "util/types.hpp"
#include "util/atomic.hpp"
#include "dynamic_library.h"
#include "util/dyn_lib.hpp"
#ifdef _WIN32
#ifndef NOMINMAX
#define NOMINMAX
#endif
#include <Windows.h>
#include <time.h>
#elif __linux__
@@ -15,6 +18,7 @@
#include <linux/futex.h>
#include <sys/time.h>
#include <unistd.h>
#include <fcntl.h>
#endif
#include <algorithm>
#include <ctime>
@@ -67,7 +71,7 @@ inline int futex(volatile void* uaddr, int futex_op, uint val, const timespec* t
};
std::mutex mutex;
std::unordered_multimap<volatile void*, waiter*, pointer_hash<volatile void, alignof(int)>> map;
std::unordered_multimap<volatile void*, waiter*> map;
int operator()(volatile void* uaddr, int futex_op, uint val, const timespec* timeout, uint mask)
{
-1046
View File
File diff suppressed because it is too large Load Diff
-1093
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -67,7 +67,7 @@ namespace utils
int vnum2 = 0;
// Loop until both strings are processed
for (size_t i = 0, j = 0; (i < v1.length() || j < v2.length());)
for (usz i = 0, j = 0; (i < v1.length() || j < v2.length());)
{
// Storing numeric part of version 1 in vnum1
while (i < v1.length() && v1[i] != '.')
+1 -1
View File
@@ -1,6 +1,6 @@
#pragma once
#include "types.h"
#include "util/types.hpp"
#include <string>
namespace utils
+1 -1
Submodule asmjit updated: fc251c914e...723f58581a
-8
View File
@@ -5,10 +5,6 @@
<Configuration>Debug - LLVM</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug - MemLeak|x64">
<Configuration>Debug - MemLeak</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
@@ -108,10 +104,6 @@
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="..\rpcs3_debug.props" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug - MemLeak|x64'" Label="PropertySheets">
<Import Project="..\rpcs3_debug.props" />
<Import Project="..\rpcs3_memleak.props" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug - LLVM|x64'" Label="PropertySheets">
<Import Project="..\rpcs3_debug.props" />
<Import Project="..\rpcs3_llvm.props" />
+22 -11
View File
@@ -17,10 +17,12 @@ jobs:
COMPILER: clang
GCC:
COMPILER: gcc
DEPLOY_APPIMAGE: true
variables:
CCACHE_DIR: $(Pipeline.Workspace)/ccache
IS_AZURE: true
UPLOAD_COMMIT_HASH: d812f1254a1157c80fd402f94446310560f54e5f
UPLOAD_REPO_FULL_NAME: "RPCS3/rpcs3-binaries-linux"
DEPLOY_APPIMAGE: true
pool:
vmImage: 'ubuntu-latest'
steps:
@@ -31,30 +33,40 @@ jobs:
displayName: ccache
- bash: |
docker pull --quiet rpcs3/rpcs3-travis-xenial:1.6
docker pull --quiet rpcs3/rpcs3-travis-xenial:1.7
docker run \
-v $(pwd):/rpcs3 \
--env-file .ci/travis.env \
--env-file .ci/docker.env \
-v $CCACHE_DIR:/root/.ccache \
-v $BUILD_ARTIFACTSTAGINGDIRECTORY:/root/artifacts \
rpcs3/rpcs3-travis-xenial:1.6 \
rpcs3/rpcs3-travis-xenial:1.7 \
/rpcs3/.ci/build-linux.sh
displayName: Docker setup and build
- publish: $(Build.ArtifactStagingDirectory)
condition: and(succeeded(), eq(variables['COMPILER'], 'gcc'))
artifact: RPCS3 for Linux
condition: succeeded()
artifact: RPCS3 for Linux ($(COMPILER))
- bash: .ci/github-upload.sh
condition: and(ne(variables['Build.Reason'], 'PullRequest'), eq(variables['Build.Repository.Name'], 'RPCS3/rpcs3'), eq(variables['Build.SourceBranch'], 'refs/heads/master'), eq(variables['COMPILER'], 'gcc'))
displayName: Push build to GitHub
env:
RPCS3_TOKEN: $(RPCS3-Token)
- job: Windows_Build
variables:
COMPILER: msvc
QT_VER: '5.14.2'
QT_DATE: '202003291224'
QTDIR: C:\Qt\$(QT_VER)\msvc2017_64
QT_VER_MAIN: '5'
QT_VER: '5.15.2'
QT_VER_MSVC: 'msvc2019'
QT_DATE: '202011130602'
QTDIR: C:\Qt\$(QT_VER)\$(QT_VER_MSVC)_64
VULKAN_VER: '1.2.154.1'
VULKAN_SDK_SHA: 'b64471f3a720e649c1fae6535ea83b8c642655ebed1485bfdf15bf4d88f746d9'
VULKAN_SDK: C:\VulkanSDK\$(VULKAN_VER)
CACHE_DIR: ./cache
UPLOAD_COMMIT_HASH: 7d09e3be30805911226241afbb14f8cdc2eb054e
UPLOAD_REPO_FULL_NAME: "RPCS3/rpcs3-binaries-win"
pool:
vmImage: "windows-latest"
@@ -91,7 +103,6 @@ jobs:
maximumCpuCount: true
platform: x64
configuration: 'Release - LLVM'
msbuildArgs: '/p:VCToolsVersion=14.25.28610'
displayName: Compile RPCS3
- bash: .ci/deploy-windows.sh
@@ -101,7 +112,7 @@ jobs:
condition: succeeded()
artifact: RPCS3 for Windows
- bash: .ci/github-upload-windows.sh
- bash: .ci/github-upload.sh
condition: and(ne(variables['Build.Reason'], 'PullRequest'), eq(variables['Build.Repository.Name'], 'RPCS3/rpcs3'), eq(variables['Build.SourceBranch'], 'refs/heads/master'))
displayName: Push build to GitHub
env:
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 MiB

After

Width:  |  Height:  |  Size: 331 KiB

+1
View File
@@ -0,0 +1 @@
Cached data from GitHub API.
+11776
View File
File diff suppressed because one or more lines are too long
+1 -1
Submodule llvm updated: 8c02f52a12...716bb292ba
-38
View File
@@ -98,7 +98,6 @@ EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug - LLVM|x64 = Debug - LLVM|x64
Debug - MemLeak|x64 = Debug - MemLeak|x64
Debug|x64 = Debug|x64
Release - LLVM|x64 = Release - LLVM|x64
Release|x64 = Release|x64
@@ -106,8 +105,6 @@ Global
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{AC40FF01-426E-4838-A317-66354CEFAE88}.Debug - LLVM|x64.ActiveCfg = Debug - LLVM|x64
{AC40FF01-426E-4838-A317-66354CEFAE88}.Debug - LLVM|x64.Build.0 = Debug - LLVM|x64
{AC40FF01-426E-4838-A317-66354CEFAE88}.Debug - MemLeak|x64.ActiveCfg = Debug - MemLeak|x64
{AC40FF01-426E-4838-A317-66354CEFAE88}.Debug - MemLeak|x64.Build.0 = Debug - MemLeak|x64
{AC40FF01-426E-4838-A317-66354CEFAE88}.Debug|x64.ActiveCfg = Debug|x64
{AC40FF01-426E-4838-A317-66354CEFAE88}.Debug|x64.Build.0 = Debug|x64
{AC40FF01-426E-4838-A317-66354CEFAE88}.Release - LLVM|x64.ActiveCfg = Release - LLVM|x64
@@ -116,8 +113,6 @@ Global
{AC40FF01-426E-4838-A317-66354CEFAE88}.Release|x64.Build.0 = Release|x64
{C4A10229-4712-4BD2-B63E-50D93C67A038}.Debug - LLVM|x64.ActiveCfg = Debug - LLVM|x64
{C4A10229-4712-4BD2-B63E-50D93C67A038}.Debug - LLVM|x64.Build.0 = Debug - LLVM|x64
{C4A10229-4712-4BD2-B63E-50D93C67A038}.Debug - MemLeak|x64.ActiveCfg = Debug - MemLeak|x64
{C4A10229-4712-4BD2-B63E-50D93C67A038}.Debug - MemLeak|x64.Build.0 = Debug - MemLeak|x64
{C4A10229-4712-4BD2-B63E-50D93C67A038}.Debug|x64.ActiveCfg = Debug|x64
{C4A10229-4712-4BD2-B63E-50D93C67A038}.Debug|x64.Build.0 = Debug|x64
{C4A10229-4712-4BD2-B63E-50D93C67A038}.Release - LLVM|x64.ActiveCfg = Release - LLVM|x64
@@ -125,14 +120,11 @@ Global
{C4A10229-4712-4BD2-B63E-50D93C67A038}.Release|x64.ActiveCfg = Release|x64
{C4A10229-4712-4BD2-B63E-50D93C67A038}.Release|x64.Build.0 = Release|x64
{8BC303AB-25BE-4276-8E57-73F171B2D672}.Debug - LLVM|x64.ActiveCfg = Debug|x64
{8BC303AB-25BE-4276-8E57-73F171B2D672}.Debug - MemLeak|x64.ActiveCfg = Debug|x64
{8BC303AB-25BE-4276-8E57-73F171B2D672}.Debug|x64.ActiveCfg = Debug|x64
{8BC303AB-25BE-4276-8E57-73F171B2D672}.Release - LLVM|x64.ActiveCfg = Release|x64
{8BC303AB-25BE-4276-8E57-73F171B2D672}.Release|x64.ActiveCfg = Release|x64
{3384223A-6D97-4799-9862-359F85312892}.Debug - LLVM|x64.ActiveCfg = Debug - LLVM|x64
{3384223A-6D97-4799-9862-359F85312892}.Debug - LLVM|x64.Build.0 = Debug - LLVM|x64
{3384223A-6D97-4799-9862-359F85312892}.Debug - MemLeak|x64.ActiveCfg = Debug - MemLeak|x64
{3384223A-6D97-4799-9862-359F85312892}.Debug - MemLeak|x64.Build.0 = Debug - MemLeak|x64
{3384223A-6D97-4799-9862-359F85312892}.Debug|x64.ActiveCfg = Debug|x64
{3384223A-6D97-4799-9862-359F85312892}.Debug|x64.Build.0 = Debug|x64
{3384223A-6D97-4799-9862-359F85312892}.Release - LLVM|x64.ActiveCfg = Release - LLVM|x64
@@ -141,8 +133,6 @@ Global
{3384223A-6D97-4799-9862-359F85312892}.Release|x64.Build.0 = Release|x64
{78CB2F39-B809-4A06-8329-8C0A19119D3D}.Debug - LLVM|x64.ActiveCfg = Debug - LLVM|x64
{78CB2F39-B809-4A06-8329-8C0A19119D3D}.Debug - LLVM|x64.Build.0 = Debug - LLVM|x64
{78CB2F39-B809-4A06-8329-8C0A19119D3D}.Debug - MemLeak|x64.ActiveCfg = Debug - MemLeak|x64
{78CB2F39-B809-4A06-8329-8C0A19119D3D}.Debug - MemLeak|x64.Build.0 = Debug - MemLeak|x64
{78CB2F39-B809-4A06-8329-8C0A19119D3D}.Debug|x64.ActiveCfg = Debug|x64
{78CB2F39-B809-4A06-8329-8C0A19119D3D}.Debug|x64.Build.0 = Debug|x64
{78CB2F39-B809-4A06-8329-8C0A19119D3D}.Release - LLVM|x64.ActiveCfg = Release - LLVM|x64
@@ -151,8 +141,6 @@ Global
{78CB2F39-B809-4A06-8329-8C0A19119D3D}.Release|x64.Build.0 = Release|x64
{30A05C4D-F5FD-421C-A864-17A64BDEAA75}.Debug - LLVM|x64.ActiveCfg = Debug - LLVM|x64
{30A05C4D-F5FD-421C-A864-17A64BDEAA75}.Debug - LLVM|x64.Build.0 = Debug - LLVM|x64
{30A05C4D-F5FD-421C-A864-17A64BDEAA75}.Debug - MemLeak|x64.ActiveCfg = Debug - MemLeak|x64
{30A05C4D-F5FD-421C-A864-17A64BDEAA75}.Debug - MemLeak|x64.Build.0 = Debug - MemLeak|x64
{30A05C4D-F5FD-421C-A864-17A64BDEAA75}.Debug|x64.ActiveCfg = Debug|x64
{30A05C4D-F5FD-421C-A864-17A64BDEAA75}.Debug|x64.Build.0 = Debug|x64
{30A05C4D-F5FD-421C-A864-17A64BDEAA75}.Release - LLVM|x64.ActiveCfg = Release - LLVM|x64
@@ -160,8 +148,6 @@ Global
{30A05C4D-F5FD-421C-A864-17A64BDEAA75}.Release|x64.ActiveCfg = Release|x64
{30A05C4D-F5FD-421C-A864-17A64BDEAA75}.Release|x64.Build.0 = Release|x64
{EB33566E-DA7F-4D28-9077-88C0B7C77E35}.Debug - LLVM|x64.ActiveCfg = Release|x64
{EB33566E-DA7F-4D28-9077-88C0B7C77E35}.Debug - MemLeak|x64.ActiveCfg = Release|x64
{EB33566E-DA7F-4D28-9077-88C0B7C77E35}.Debug - MemLeak|x64.Build.0 = Release|x64
{EB33566E-DA7F-4D28-9077-88C0B7C77E35}.Debug|x64.ActiveCfg = Release|x64
{EB33566E-DA7F-4D28-9077-88C0B7C77E35}.Debug|x64.Build.0 = Release|x64
{EB33566E-DA7F-4D28-9077-88C0B7C77E35}.Release - LLVM|x64.ActiveCfg = Release|x64
@@ -170,8 +156,6 @@ Global
{EB33566E-DA7F-4D28-9077-88C0B7C77E35}.Release|x64.Build.0 = Release|x64
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Debug - LLVM|x64.ActiveCfg = Debug Library|x64
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Debug - LLVM|x64.Build.0 = Debug Library|x64
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Debug - MemLeak|x64.ActiveCfg = Debug Library|x64
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Debug - MemLeak|x64.Build.0 = Debug Library|x64
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Debug|x64.ActiveCfg = Debug Library|x64
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Debug|x64.Build.0 = Debug Library|x64
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Release - LLVM|x64.ActiveCfg = Release Library|x64
@@ -180,8 +164,6 @@ Global
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Release|x64.Build.0 = Release Library|x64
{60F89955-91C6-3A36-8000-13C592FEC2DF}.Debug - LLVM|x64.ActiveCfg = Debug|x64
{60F89955-91C6-3A36-8000-13C592FEC2DF}.Debug - LLVM|x64.Build.0 = Debug|x64
{60F89955-91C6-3A36-8000-13C592FEC2DF}.Debug - MemLeak|x64.ActiveCfg = Debug|x64
{60F89955-91C6-3A36-8000-13C592FEC2DF}.Debug - MemLeak|x64.Build.0 = Debug|x64
{60F89955-91C6-3A36-8000-13C592FEC2DF}.Debug|x64.ActiveCfg = Debug|x64
{60F89955-91C6-3A36-8000-13C592FEC2DF}.Debug|x64.Build.0 = Debug|x64
{60F89955-91C6-3A36-8000-13C592FEC2DF}.Release - LLVM|x64.ActiveCfg = Release|x64
@@ -189,14 +171,11 @@ Global
{60F89955-91C6-3A36-8000-13C592FEC2DF}.Release|x64.ActiveCfg = Release|x64
{60F89955-91C6-3A36-8000-13C592FEC2DF}.Release|x64.Build.0 = Release|x64
{8F85B6CC-250F-4ACA-A617-E820A74E3E3C}.Debug - LLVM|x64.ActiveCfg = Debug|x64
{8F85B6CC-250F-4ACA-A617-E820A74E3E3C}.Debug - MemLeak|x64.ActiveCfg = Debug|x64
{8F85B6CC-250F-4ACA-A617-E820A74E3E3C}.Debug|x64.ActiveCfg = Debug|x64
{8F85B6CC-250F-4ACA-A617-E820A74E3E3C}.Release - LLVM|x64.ActiveCfg = Release|x64
{8F85B6CC-250F-4ACA-A617-E820A74E3E3C}.Release|x64.ActiveCfg = Release|x64
{3EE5F075-B546-42C4-B6A8-E3CCEF38B78D}.Debug - LLVM|x64.ActiveCfg = Debug - LLVM|x64
{3EE5F075-B546-42C4-B6A8-E3CCEF38B78D}.Debug - LLVM|x64.Build.0 = Debug - LLVM|x64
{3EE5F075-B546-42C4-B6A8-E3CCEF38B78D}.Debug - MemLeak|x64.ActiveCfg = Debug - MemLeak|x64
{3EE5F075-B546-42C4-B6A8-E3CCEF38B78D}.Debug - MemLeak|x64.Build.0 = Debug - MemLeak|x64
{3EE5F075-B546-42C4-B6A8-E3CCEF38B78D}.Debug|x64.ActiveCfg = Debug|x64
{3EE5F075-B546-42C4-B6A8-E3CCEF38B78D}.Debug|x64.Build.0 = Debug|x64
{3EE5F075-B546-42C4-B6A8-E3CCEF38B78D}.Release - LLVM|x64.ActiveCfg = Release - LLVM|x64
@@ -205,8 +184,6 @@ Global
{3EE5F075-B546-42C4-B6A8-E3CCEF38B78D}.Release|x64.Build.0 = Release|x64
{FDC361C5-7734-493B-8CFB-037308B35122}.Debug - LLVM|x64.ActiveCfg = Debug|x64
{FDC361C5-7734-493B-8CFB-037308B35122}.Debug - LLVM|x64.Build.0 = Debug|x64
{FDC361C5-7734-493B-8CFB-037308B35122}.Debug - MemLeak|x64.ActiveCfg = Debug|x64
{FDC361C5-7734-493B-8CFB-037308B35122}.Debug - MemLeak|x64.Build.0 = Debug|x64
{FDC361C5-7734-493B-8CFB-037308B35122}.Debug|x64.ActiveCfg = Debug|x64
{FDC361C5-7734-493B-8CFB-037308B35122}.Debug|x64.Build.0 = Debug|x64
{FDC361C5-7734-493B-8CFB-037308B35122}.Release - LLVM|x64.ActiveCfg = Release|x64
@@ -215,8 +192,6 @@ Global
{FDC361C5-7734-493B-8CFB-037308B35122}.Release|x64.Build.0 = Release|x64
{70CD65B0-91D6-4FAE-9A7B-4AF55D0D1B12}.Debug - LLVM|x64.ActiveCfg = Debug - LLVM|x64
{70CD65B0-91D6-4FAE-9A7B-4AF55D0D1B12}.Debug - LLVM|x64.Build.0 = Debug - LLVM|x64
{70CD65B0-91D6-4FAE-9A7B-4AF55D0D1B12}.Debug - MemLeak|x64.ActiveCfg = Debug|x64
{70CD65B0-91D6-4FAE-9A7B-4AF55D0D1B12}.Debug - MemLeak|x64.Build.0 = Debug|x64
{70CD65B0-91D6-4FAE-9A7B-4AF55D0D1B12}.Debug|x64.ActiveCfg = Debug|x64
{70CD65B0-91D6-4FAE-9A7B-4AF55D0D1B12}.Debug|x64.Build.0 = Debug|x64
{70CD65B0-91D6-4FAE-9A7B-4AF55D0D1B12}.Release - LLVM|x64.ActiveCfg = Release - LLVM|x64
@@ -225,8 +200,6 @@ Global
{70CD65B0-91D6-4FAE-9A7B-4AF55D0D1B12}.Release|x64.Build.0 = Release|x64
{A107C21C-418A-4697-BB10-20C3AA60E2E4}.Debug - LLVM|x64.ActiveCfg = Debug|x64
{A107C21C-418A-4697-BB10-20C3AA60E2E4}.Debug - LLVM|x64.Build.0 = Debug|x64
{A107C21C-418A-4697-BB10-20C3AA60E2E4}.Debug - MemLeak|x64.ActiveCfg = Debug|x64
{A107C21C-418A-4697-BB10-20C3AA60E2E4}.Debug - MemLeak|x64.Build.0 = Debug|x64
{A107C21C-418A-4697-BB10-20C3AA60E2E4}.Debug|x64.ActiveCfg = Debug|x64
{A107C21C-418A-4697-BB10-20C3AA60E2E4}.Debug|x64.Build.0 = Debug|x64
{A107C21C-418A-4697-BB10-20C3AA60E2E4}.Release - LLVM|x64.ActiveCfg = Release|x64
@@ -235,8 +208,6 @@ Global
{A107C21C-418A-4697-BB10-20C3AA60E2E4}.Release|x64.Build.0 = Release|x64
{939FE206-1182-ABC3-1234-FEAB88E98404}.Debug - LLVM|x64.ActiveCfg = Debug|x64
{939FE206-1182-ABC3-1234-FEAB88E98404}.Debug - LLVM|x64.Build.0 = Debug|x64
{939FE206-1182-ABC3-1234-FEAB88E98404}.Debug - MemLeak|x64.ActiveCfg = Debug|x64
{939FE206-1182-ABC3-1234-FEAB88E98404}.Debug - MemLeak|x64.Build.0 = Debug|x64
{939FE206-1182-ABC3-1234-FEAB88E98404}.Debug|x64.ActiveCfg = Debug|x64
{939FE206-1182-ABC3-1234-FEAB88E98404}.Debug|x64.Build.0 = Debug|x64
{939FE206-1182-ABC3-1234-FEAB88E98404}.Release - LLVM|x64.ActiveCfg = Release|x64
@@ -245,8 +216,6 @@ Global
{939FE206-1182-ABC3-1234-FEAB88E98404}.Release|x64.Build.0 = Release|x64
{349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Debug - LLVM|x64.ActiveCfg = Debug|x64
{349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Debug - LLVM|x64.Build.0 = Debug|x64
{349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Debug - MemLeak|x64.ActiveCfg = Debug|x64
{349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Debug - MemLeak|x64.Build.0 = Debug|x64
{349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Debug|x64.ActiveCfg = Debug|x64
{349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Debug|x64.Build.0 = Debug|x64
{349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Release - LLVM|x64.ActiveCfg = Release|x64
@@ -255,8 +224,6 @@ Global
{349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Release|x64.Build.0 = Release|x64
{5B146DEA-9ACE-4D32-A7FD-3F42464DD69C}.Debug - LLVM|x64.ActiveCfg = Debug|x64
{5B146DEA-9ACE-4D32-A7FD-3F42464DD69C}.Debug - LLVM|x64.Build.0 = Debug|x64
{5B146DEA-9ACE-4D32-A7FD-3F42464DD69C}.Debug - MemLeak|x64.ActiveCfg = Debug|x64
{5B146DEA-9ACE-4D32-A7FD-3F42464DD69C}.Debug - MemLeak|x64.Build.0 = Debug|x64
{5B146DEA-9ACE-4D32-A7FD-3F42464DD69C}.Debug|x64.ActiveCfg = Debug|x64
{5B146DEA-9ACE-4D32-A7FD-3F42464DD69C}.Debug|x64.Build.0 = Debug|x64
{5B146DEA-9ACE-4D32-A7FD-3F42464DD69C}.Release - LLVM|x64.ActiveCfg = Release|x64
@@ -265,8 +232,6 @@ Global
{5B146DEA-9ACE-4D32-A7FD-3F42464DD69C}.Release|x64.Build.0 = Release|x64
{73973223-5EE8-41CA-8E88-1D60E89A237B}.Debug - LLVM|x64.ActiveCfg = Debug|x64
{73973223-5EE8-41CA-8E88-1D60E89A237B}.Debug - LLVM|x64.Build.0 = Debug|x64
{73973223-5EE8-41CA-8E88-1D60E89A237B}.Debug - MemLeak|x64.ActiveCfg = Debug|x64
{73973223-5EE8-41CA-8E88-1D60E89A237B}.Debug - MemLeak|x64.Build.0 = Debug|x64
{73973223-5EE8-41CA-8E88-1D60E89A237B}.Debug|x64.ActiveCfg = Debug|x64
{73973223-5EE8-41CA-8E88-1D60E89A237B}.Debug|x64.Build.0 = Debug|x64
{73973223-5EE8-41CA-8E88-1D60E89A237B}.Release - LLVM|x64.ActiveCfg = Release|x64
@@ -275,8 +240,6 @@ Global
{73973223-5EE8-41CA-8E88-1D60E89A237B}.Release|x64.Build.0 = Release|x64
{DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.Debug - LLVM|x64.ActiveCfg = Debug - LLVM|x64
{DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.Debug - LLVM|x64.Build.0 = Debug - LLVM|x64
{DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.Debug - MemLeak|x64.ActiveCfg = Debug|x64
{DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.Debug - MemLeak|x64.Build.0 = Debug|x64
{DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.Debug|x64.ActiveCfg = Debug|x64
{DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.Debug|x64.Build.0 = Debug|x64
{DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.Release - LLVM|x64.ActiveCfg = Release - LLVM|x64
@@ -284,7 +247,6 @@ Global
{DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.Release|x64.ActiveCfg = Release|x64
{DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.Release|x64.Build.0 = Release|x64
{4CBD3DDD-5555-49A4-A44D-DD3D8CB516A1}.Debug - LLVM|x64.ActiveCfg = Debug|x64
{4CBD3DDD-5555-49A4-A44D-DD3D8CB516A1}.Debug - MemLeak|x64.ActiveCfg = Debug|x64
{4CBD3DDD-5555-49A4-A44D-DD3D8CB516A1}.Debug|x64.ActiveCfg = Debug|x64
{4CBD3DDD-5555-49A4-A44D-DD3D8CB516A1}.Release - LLVM|x64.ActiveCfg = Release|x64
{4CBD3DDD-5555-49A4-A44D-DD3D8CB516A1}.Release|x64.ActiveCfg = Release|x64
+12
View File
@@ -58,7 +58,9 @@ set(RPCS3_SRC
Input/basic_mouse_handler.cpp
Input/ds3_pad_handler.cpp
Input/ds4_pad_handler.cpp
Input/dualsense_pad_handler.cpp
Input/evdev_joystick_handler.cpp
Input/hid_pad_handler.cpp
Input/keyboard_pad_handler.cpp
Input/mm_joystick_handler.cpp
Input/pad_thread.cpp
@@ -133,11 +135,19 @@ if(APPLE)
${CMAKE_SOURCE_DIR}/bin/Icons $<TARGET_FILE_DIR:rpcs3>/../Resources/Icons
COMMAND ${CMAKE_COMMAND} -E copy_directory
${CMAKE_SOURCE_DIR}/bin/GuiConfigs $<TARGET_FILE_DIR:rpcs3>/../Resources/GuiConfigs
COMMAND ${CMAKE_COMMAND} -E copy_directory
${CMAKE_SOURCE_DIR}/bin/git $<TARGET_FILE_DIR:rpcs3>/../Resources/git
COMMAND "${Qt5_DIR}/../../../bin/macdeployqt" "${PROJECT_BINARY_DIR}/bin/rpcs3.app")
elseif(UNIX)
add_custom_command(TARGET rpcs3 POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory
${CMAKE_SOURCE_DIR}/bin/Icons $<TARGET_FILE_DIR:rpcs3>/Icons)
add_custom_command(TARGET rpcs3 POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory
${CMAKE_SOURCE_DIR}/bin/GuiConfigs $<TARGET_FILE_DIR:rpcs3>/GuiConfigs)
add_custom_command(TARGET rpcs3 POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory
${CMAKE_SOURCE_DIR}/bin/git $<TARGET_FILE_DIR:rpcs3>/git)
elseif(WIN32)
add_custom_command(TARGET rpcs3 POST_BUILD
COMMAND "${CMAKE_COMMAND}" -E copy_directory "${CMAKE_SOURCE_DIR}/bin" "$<TARGET_FILE_DIR:rpcs3>"
@@ -162,4 +172,6 @@ if(UNIX AND NOT APPLE)
DESTINATION ${CMAKE_INSTALL_PREFIX}/share/rpcs3)
install(DIRECTORY ../bin/GuiConfigs
DESTINATION ${CMAKE_INSTALL_PREFIX}/share/rpcs3)
install(DIRECTORY ../bin/git
DESTINATION ${CMAKE_INSTALL_PREFIX}/share/rpcs3)
endif()
+105 -102
View File
@@ -3,8 +3,9 @@
// http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
#include "utils.h"
#include <string>
void bn_print(char *name, u8 *a, u32 n)
void bn_print(char* name, u8* a, u32 n)
{
u32 i;
@@ -16,20 +17,22 @@ void bn_print(char *name, u8 *a, u32 n)
printf("\n");
}
static void bn_zero(u8 *d, u32 n)
static void bn_zero(u8* d, u32 n)
{
memset(d, 0, n);
}
void bn_copy(u8 *d, u8 *a, u32 n)
void bn_copy(u8* d, u8* a, u32 n)
{
memcpy(d, a, n);
}
int bn_compare(u8 *a, u8 *b, u32 n)
int bn_compare(u8* a, u8* b, u32 n)
{
u32 i;
for (i = 0; i < n; i++) {
for (i = 0; i < n; i++)
{
if (a[i] < b[i])
return -1;
if (a[i] > b[i])
@@ -39,45 +42,47 @@ int bn_compare(u8 *a, u8 *b, u32 n)
return 0;
}
static u8 bn_add_1(u8 *d, 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--) {
dig = a[i] + b[i] + c;
c = dig >> 8;
for (i = n - 1; i < n; i--)
{
dig = a[i] + b[i] + c;
c = dig >> 8;
d[i] = dig;
}
return c;
}
static u8 bn_sub_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--) {
dig = a[i] + 255 - b[i] + c;
c = dig >> 8;
for (i = n - 1; i < n; i--)
{
dig = a[i] + 255 - b[i] + c;
c = dig >> 8;
d[i] = dig;
}
return 1 - c;
}
void bn_reduce(u8 *d, u8 *N, u32 n)
void bn_reduce(u8* d, u8* N, u32 n)
{
if (bn_compare(d, N, n) >= 0)
bn_sub_1(d, d, N, n);
}
void bn_add(u8 *d, u8 *a, u8 *b, u8 *N, u32 n)
void bn_add(u8* d, u8* a, u8* b, u8* N, u32 n)
{
if (bn_add_1(d, a, b, n))
bn_sub_1(d, d, N, n);
@@ -85,13 +90,13 @@ void bn_add(u8 *d, u8 *a, u8 *b, u8 *N, u32 n)
bn_reduce(d, N, n);
}
void bn_sub(u8 *d, u8 *a, u8 *b, u8 *N, u32 n)
void bn_sub(u8* d, u8* a, u8* b, u8* N, u32 n)
{
if (bn_sub_1(d, a, b, n))
bn_add_1(d, d, N, n);
}
static const u8 inv256[0x80] = {
static constexpr u8 inv256[0x80] = {
0x01, 0xab, 0xcd, 0xb7, 0x39, 0xa3, 0xc5, 0xef,
0xf1, 0x1b, 0x3d, 0xa7, 0x29, 0x13, 0x35, 0xdf,
0xe1, 0x8b, 0xad, 0x97, 0x19, 0x83, 0xa5, 0xcf,
@@ -110,19 +115,20 @@ static const u8 inv256[0x80] = {
0x11, 0x3b, 0x5d, 0xc7, 0x49, 0x33, 0x55, 0xff,
};
static void bn_mon_muladd_dig(u8 *d, u8 *a, u8 b, u8 *N, u32 n)
static void bn_mon_muladd_dig(u8* d, u8* a, u8 b, u8* N, u32 n)
{
u32 dig;
u32 i;
u8 z = -(d[n-1] + a[n-1]*b) * inv256[N[n-1]/2];
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;
dig = d[n - 1] + a[n - 1] * b + N[n - 1] * z;
dig >>= 8;
for (i = n - 2; i < n; i--) {
dig += d[i] + a[i]*b + N[i]*z;
d[i+1] = dig;
for (i = n - 2; i < n; i--)
{
dig += d[i] + a[i] * b + N[i] * z;
d[i + 1] = dig;
dig >>= 8;
}
@@ -135,7 +141,7 @@ static void bn_mon_muladd_dig(u8 *d, u8 *a, u8 b, u8 *N, u32 n)
bn_reduce(d, N, n);
}
void bn_mon_mul(u8 *d, u8 *a, u8 *b, u8 *N, u32 n)
void bn_mon_mul(u8* d, u8* a, u8* b, u8* N, u32 n)
{
u8 t[512];
u32 i;
@@ -148,35 +154,36 @@ void bn_mon_mul(u8 *d, u8 *a, u8 *b, u8 *N, u32 n)
bn_copy(d, t, n);
}
void bn_to_mon(u8 *d, u8 *N, u32 n)
void bn_to_mon(u8* d, u8* N, u32 n)
{
u32 i;
for (i = 0; i < 8*n; i++)
for (i = 0; i < 8 * n; i++)
bn_add(d, d, d, N, n);
}
void bn_from_mon(u8 *d, u8 *N, u32 n)
void bn_from_mon(u8* d, u8* N, u32 n)
{
u8 t[512];
bn_zero(t, n);
t[n-1] = 1;
t[n - 1] = 1;
bn_mon_mul(d, d, t, N, n);
}
static void bn_mon_exp(u8 *d, u8 *a, u8 *N, u32 n, u8 *e, u32 en)
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);
d[n-1] = 1;
d[n - 1] = 1;
bn_to_mon(d, N, n);
for (i = 0; i < en; i++)
for (mask = 0x80; mask != 0; mask >>= 1) {
for (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);
@@ -185,50 +192,41 @@ static void bn_mon_exp(u8 *d, u8 *a, u8 *N, u32 n, u8 *e, u32 en)
}
}
void bn_mon_inv(u8 *d, u8 *a, u8 *N, u32 n)
void bn_mon_inv(u8* d, u8* a, u8* N, u32 n)
{
u8 t[512], s[512];
bn_zero(s, n);
s[n-1] = 2;
s[n - 1] = 2;
bn_sub_1(t, N, s, n);
bn_mon_exp(d, a, N, n, t, n);
}
void bn_copy(u8 *d, u8 *a, u32 n);
int bn_compare(u8 *a, u8 *b, u32 n);
void bn_reduce(u8 *d, u8 *N, u32 n);
void bn_add(u8 *d, u8 *a, u8 *b, u8 *N, u32 n);
void bn_sub(u8 *d, u8 *a, u8 *b, u8 *N, u32 n);
void bn_to_mon(u8 *d, u8 *N, u32 n);
void bn_from_mon(u8 *d, u8 *N, u32 n);
void bn_mon_mul(u8 *d, u8 *a, u8 *b, u8 *N, u32 n);
void bn_mon_inv(u8 *d, u8 *a, u8 *N, u32 n);
struct point {
struct point
{
u8 x[20];
u8 y[20];
};
static u8 ec_p[20];
static u8 ec_a[20]; // mon
static u8 ec_b[20]; // mon
static u8 ec_N[21];
static struct point ec_G; // mon
static struct point ec_Q; // mon
static u8 ec_k[21];
static thread_local u8 ec_p[20]{};
static thread_local u8 ec_a[20]{}; // mon
static thread_local u8 ec_b[20]{}; // mon
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 void elt_copy(u8 *d, u8 *a)
static void elt_copy(u8* d, u8* a)
{
memcpy(d, a, 20);
}
static void elt_zero(u8 *d)
static void elt_zero(u8* d)
{
memset(d, 0, 20);
}
static int elt_is_zero(u8 *d)
static int elt_is_zero(u8* d)
{
u32 i;
@@ -239,47 +237,47 @@ static int elt_is_zero(u8 *d)
return 1;
}
static void elt_add(u8 *d, u8 *a, u8 *b)
static void elt_add(u8* d, u8* a, u8* b)
{
bn_add(d, a, b, ec_p, 20);
}
static void elt_sub(u8 *d, u8 *a, u8 *b)
static void elt_sub(u8* d, u8* a, u8* b)
{
bn_sub(d, a, b, ec_p, 20);
}
static void elt_mul(u8 *d, u8 *a, u8 *b)
static void elt_mul(u8* d, u8* a, u8* b)
{
bn_mon_mul(d, a, b, ec_p, 20);
}
static void elt_square(u8 *d, u8 *a)
static void elt_square(u8* d, u8* a)
{
elt_mul(d, a, a);
}
static void elt_inv(u8 *d, u8 *a)
static void elt_inv(u8* d, u8* a)
{
u8 s[20];
elt_copy(s, a);
bn_mon_inv(d, s, ec_p, 20);
}
static void point_to_mon(struct point *p)
static void point_to_mon(point* p)
{
bn_to_mon(p->x, ec_p, 20);
bn_to_mon(p->y, ec_p, 20);
}
static void point_from_mon(struct point *p)
static void point_from_mon(point* p)
{
bn_from_mon(p->x, ec_p, 20);
bn_from_mon(p->y, ec_p, 20);
}
#if 0
static int point_is_on_curve(u8 *p)
static int point_is_on_curve(u8* p)
{
u8 s[20], t[20];
u8 *x, *y;
@@ -302,21 +300,21 @@ static int point_is_on_curve(u8 *p)
}
#endif
static void point_zero(struct point *p)
static void point_zero(point* p)
{
elt_zero(p->x);
elt_zero(p->y);
}
static int point_is_zero(struct point *p)
static int point_is_zero(point* p)
{
return elt_is_zero(p->x) && elt_is_zero(p->y);
}
static void point_double(struct point *r, struct point *p)
static void point_double(point* r, point* p)
{
u8 s[20], t[20];
struct point pp;
point pp;
u8 *px, *py, *rx, *ry;
pp = *p;
@@ -326,33 +324,34 @@ static void point_double(struct point *r, struct point *p)
rx = r->x;
ry = r->y;
if (elt_is_zero(py)) {
if (elt_is_zero(py))
{
point_zero(r);
return;
}
elt_square(t, px); // t = px*px
elt_add(s, t, t); // s = 2*px*px
elt_add(s, s, t); // s = 3*px*px
elt_add(s, s, ec_a); // s = 3*px*px + a
elt_add(t, py, py); // t = 2*py
elt_inv(t, t); // t = 1/(2*py)
elt_mul(s, s, t); // s = (3*px*px+a)/(2*py)
elt_square(t, px); // t = px*px
elt_add(s, t, t); // s = 2*px*px
elt_add(s, s, t); // s = 3*px*px
elt_add(s, s, ec_a); // s = 3*px*px + a
elt_add(t, py, py); // t = 2*py
elt_inv(t, t); // t = 1/(2*py)
elt_mul(s, s, t); // s = (3*px*px+a)/(2*py)
elt_square(rx, s); // rx = s*s
elt_add(t, px, px); // t = 2*px
elt_sub(rx, rx, t); // rx = s*s - 2*px
elt_square(rx, s); // rx = s*s
elt_add(t, px, px); // t = 2*px
elt_sub(rx, rx, t); // rx = s*s - 2*px
elt_sub(t, px, rx); // t = -(rx-px)
elt_mul(ry, s, t); // ry = -s*(rx-px)
elt_sub(ry, ry, py); // ry = -s*(rx-px) - py
elt_sub(t, px, rx); // t = -(rx-px)
elt_mul(ry, s, t); // ry = -s*(rx-px)
elt_sub(ry, ry, py); // ry = -s*(rx-px) - py
}
static void point_add(struct point *r, struct point *p, struct point *q)
static void point_add(point* r, point* p, point* q)
{
u8 s[20], t[20], u[20];
u8 *px, *py, *qx, *qy, *rx, *ry;
struct point pp, qq;
point pp, qq;
pp = *p;
qq = *q;
@@ -364,13 +363,15 @@ static void point_add(struct point *r, struct point *p, struct point *q)
rx = r->x;
ry = r->y;
if (point_is_zero(&pp)) {
if (point_is_zero(&pp))
{
elt_copy(rx, qx);
elt_copy(ry, qy);
return;
}
if (point_is_zero(&qq)) {
if (point_is_zero(&qq))
{
elt_copy(rx, px);
elt_copy(ry, py);
return;
@@ -378,7 +379,8 @@ static void point_add(struct point *r, struct point *p, struct point *q)
elt_sub(u, qx, px);
if (elt_is_zero(u)) {
if (elt_is_zero(u))
{
elt_sub(u, qy, py);
if (elt_is_zero(u))
point_double(r, &pp);
@@ -388,20 +390,20 @@ static void point_add(struct point *r, struct point *p, struct point *q)
return;
}
elt_inv(t, u); // t = 1/(qx-px)
elt_sub(u, qy, py); // u = qy-py
elt_mul(s, t, u); // s = (qy-py)/(qx-px)
elt_inv(t, u); // t = 1/(qx-px)
elt_sub(u, qy, py); // u = qy-py
elt_mul(s, t, u); // s = (qy-py)/(qx-px)
elt_square(rx, s); // rx = s*s
elt_add(t, px, qx); // t = px+qx
elt_sub(rx, rx, t); // rx = s*s - (px+qx)
elt_square(rx, s); // rx = s*s
elt_add(t, px, qx); // t = px+qx
elt_sub(rx, rx, t); // rx = s*s - (px+qx)
elt_sub(t, px, rx); // t = -(rx-px)
elt_mul(ry, s, t); // ry = -s*(rx-px)
elt_sub(ry, ry, py); // ry = -s*(rx-px) - py
elt_sub(t, px, rx); // t = -(rx-px)
elt_mul(ry, s, t); // ry = -s*(rx-px)
elt_sub(ry, ry, py); // ry = -s*(rx-px) - py
}
static void point_mul(struct point *d, u8 *a, struct point *b) // a is bignum
static void point_mul(point* d, u8* a, point* b) // a is bignum
{
u32 i;
u8 mask;
@@ -409,14 +411,15 @@ static void point_mul(struct point *d, u8 *a, struct point *b) // a is bignum
point_zero(d);
for (i = 0; i < 21; i++)
for (mask = 0x80; mask != 0; mask >>= 1) {
for (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 int check_ecdsa(struct point* Q, u8* R, u8* S, u8* hash)
{
u8 Sinv[21];
u8 e[21];
@@ -458,13 +461,13 @@ static int check_ecdsa(struct point *Q, u8 *R, u8 *S, u8 *hash)
}
#if 0
static void ec_priv_to_pub(u8 *k, u8 *Q)
static void ec_priv_to_pub(u8* k, u8* Q)
{
point_mul(Q, k, ec_G);
}
#endif
int ecdsa_set_curve(u8* p, u8* a, u8* b, u8* N, u8* Gx, u8* Gy)
int ecdsa_set_curve(const u8* p, const u8* a, const u8* b, const u8* N, const u8* Gx, const u8* Gy)
{
memcpy(ec_p, p, 20);
memcpy(ec_a, a, 20);
@@ -481,19 +484,19 @@ int ecdsa_set_curve(u8* p, u8* a, u8* b, u8* N, u8* Gx, u8* Gy)
return 0;
}
void ecdsa_set_pub(u8 *Q)
void ecdsa_set_pub(const u8* Q)
{
memcpy(ec_Q.x, Q, 20);
memcpy(ec_Q.y, Q+20, 20);
point_to_mon(&ec_Q);
}
void ecdsa_set_priv(u8 *k)
void ecdsa_set_priv(const u8* k)
{
memcpy(ec_k, k, sizeof ec_k);
}
int ecdsa_verify(u8 *hash, u8 *R, u8 *S)
int ecdsa_verify(u8* hash, u8* R, u8* S)
{
return check_ecdsa(&ec_Q, R, S, hash);
}
+5 -6
View File
@@ -4,10 +4,9 @@
// Licensed under the terms of the GNU GPL, version 3
// http://www.gnu.org/licenses/gpl-3.0.txt
#include <string.h>
#include <stdio.h>
#include "util/types.hpp"
int ecdsa_set_curve(unsigned char *p, unsigned char *a, unsigned char *b, unsigned char *N, unsigned char *Gx, unsigned char *Gy);
void ecdsa_set_pub(unsigned char *Q);
void ecdsa_set_priv(unsigned char *k);
int ecdsa_verify(unsigned char *hash, unsigned char *R, unsigned char *S);
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_pub(const u8* Q);
void ecdsa_set_priv(const u8* k);
int ecdsa_verify(u8* hash, u8* R, u8* S);
+817 -815
View File
File diff suppressed because it is too large Load Diff
+221 -221
View File
@@ -1,221 +1,221 @@
#pragma once
#include "Utilities/types.h"
#include <string>
#include <vector>
#include <memory>
enum SELF_KEY_TYPE
{
KEY_LV0 = 1,
KEY_LV1,
KEY_LV2,
KEY_APP,
KEY_ISO,
KEY_LDR,
KEY_UNK7,
KEY_NPDRM
};
struct SELF_KEY
{
u64 version_start;
u64 version_end;
u16 revision;
u32 self_type;
u8 erk[0x20];
u8 riv[0x10];
u8 pub[0x28];
u8 priv[0x15];
u32 curve_type;
SELF_KEY(u64 ver_start, u64 ver_end, u16 rev, u32 type, const std::string& e, const std::string& r, const std::string& pb, const std::string& pr, u32 ct);
};
static u8 PKG_AES_KEY_IDU[0x10] = {
0x5d, 0xb9, 0x11, 0xe6, 0xb7, 0xe5, 0x0a, 0x7d, 0x32, 0x15, 0x38, 0xfd, 0x7c, 0x66, 0xf1, 0x7b
};
static u8 PKG_AES_KEY[0x10] = {
0x2e, 0x7b, 0x71, 0xd7, 0xc9, 0xc9, 0xa1, 0x4e, 0xa3, 0x22, 0x1f, 0x18, 0x88, 0x28, 0xb8, 0xf8
};
static u8 PKG_AES_KEY2[0x10] = {
0x07, 0xf2, 0xc6, 0x82, 0x90, 0xb5, 0x0d, 0x2c, 0x33, 0x81, 0x8d, 0x70, 0x9b, 0x60, 0xe6, 0x2b
};
static u8 PKG_AES_KEY_VITA_1[0x10] = {
0xE3, 0x1A, 0x70, 0xC9, 0xCE, 0x1D, 0xD7, 0x2B, 0xF3, 0xC0, 0x62, 0x29, 0x63, 0xF2, 0xEC, 0xCB
};
static u8 PKG_AES_KEY_VITA_2[0x10] = {
0x42, 0x3A, 0xCA, 0x3A, 0x2B, 0xD5, 0x64, 0x9F, 0x96, 0x86, 0xAB, 0xAD, 0x6F, 0xD8, 0x80, 0x1F
};
static u8 PKG_AES_KEY_VITA_3[0x10] = {
0xAF, 0x07, 0xFD, 0x59, 0x65, 0x25, 0x27, 0xBA, 0xF1, 0x33, 0x89, 0x66, 0x8B, 0x17, 0xD9, 0xEA
};
static u8 NP_IDPS[0x10] = {
0x5E, 0x06, 0xE0, 0x4F, 0xD9, 0x4A, 0x71, 0xBF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01
};
static u8 NP_KLIC_FREE[0x10] = {
0x72, 0xF9, 0x90, 0x78, 0x8F, 0x9C, 0xFF, 0x74, 0x57, 0x25, 0xF0, 0x8E, 0x4C, 0x12, 0x83, 0x87
};
static u8 NP_OMAC_KEY_2[0x10] = {
0x6B, 0xA5, 0x29, 0x76, 0xEF, 0xDA, 0x16, 0xEF, 0x3C, 0x33, 0x9F, 0xB2, 0x97, 0x1E, 0x25, 0x6B
};
static u8 NP_OMAC_KEY_3[0x10] = {
0x9B, 0x51, 0x5F, 0xEA, 0xCF, 0x75, 0x06, 0x49, 0x81, 0xAA, 0x60, 0x4D, 0x91, 0xA5, 0x4E, 0x97
};
static u8 NP_KLIC_KEY[0x10] = {
0xF2, 0xFB, 0xCA, 0x7A, 0x75, 0xB0, 0x4E, 0xDC, 0x13, 0x90, 0x63, 0x8C, 0xCD, 0xFD, 0xD1, 0xEE
};
static u8 NP_RIF_KEY[0x10] = {
0xDA, 0x7D, 0x4B, 0x5E, 0x49, 0x9A, 0x4F, 0x53, 0xB1, 0xC1, 0xA1, 0x4A, 0x74, 0x84, 0x44, 0x3B
};
// PSP Minis
static u8 NP_PSP_KEY_1[0x10] = {
0x2A, 0x6A, 0xFB, 0xCF, 0x43, 0xD1, 0x57, 0x9F, 0x7D, 0x73, 0x87, 0x41, 0xA1, 0x3B, 0xD4, 0x2E
};
// PSP Remasters
static u8 NP_PSP_KEY_2[0x10] = {
0x0D, 0xB8, 0x57, 0x32, 0x36, 0x6C, 0xD7, 0x34, 0xFC, 0x87, 0x9E, 0x74, 0x33, 0x43, 0xBB, 0x4F
};
static u8 NP_PSX_KEY[0x10] = {
0x52, 0xC0, 0xB5, 0xCA, 0x76, 0xD6, 0x13, 0x4B, 0xB4, 0x5F, 0xC6, 0x6C, 0xA6, 0x37, 0xF2, 0xC1
};
static u8 RAP_KEY[0x10] = {
0x86, 0x9F, 0x77, 0x45, 0xC1, 0x3F, 0xD8, 0x90, 0xCC, 0xF2, 0x91, 0x88, 0xE3, 0xCC, 0x3E, 0xDF
};
static u8 RAP_PBOX[0x10] = {
0x0C, 0x03, 0x06, 0x04, 0x01, 0x0B, 0x0F, 0x08, 0x02, 0x07, 0x00, 0x05, 0x0A, 0x0E, 0x0D, 0x09
};
static u8 RAP_E1[0x10] = {
0xA9, 0x3E, 0x1F, 0xD6, 0x7C, 0x55, 0xA3, 0x29, 0xB7, 0x5F, 0xDD, 0xA6, 0x2A, 0x95, 0xC7, 0xA5
};
static u8 RAP_E2[0x10] = {
0x67, 0xD4, 0x5D, 0xA3, 0x29, 0x6D, 0x00, 0x6A, 0x4E, 0x7C, 0x53, 0x7B, 0xF5, 0x53, 0x8C, 0x74
};
static u8 SDAT_KEY[0x10] = {
0x0D, 0x65, 0x5E, 0xF8, 0xE6, 0x74, 0xA9, 0x8A, 0xB8, 0x50, 0x5C, 0xFA, 0x7D, 0x01, 0x29, 0x33
};
static u8 EDAT_KEY_0[0x10] = {
0xBE, 0x95, 0x9C, 0xA8, 0x30, 0x8D, 0xEF, 0xA2, 0xE5, 0xE1, 0x80, 0xC6, 0x37, 0x12, 0xA9, 0xAE
};
static u8 EDAT_HASH_0[0x10] = {
0xEF, 0xFE, 0x5B, 0xD1, 0x65, 0x2E, 0xEB, 0xC1, 0x19, 0x18, 0xCF, 0x7C, 0x04, 0xD4, 0xF0, 0x11
};
static u8 EDAT_KEY_1[0x10] = {
0x4C, 0xA9, 0xC1, 0x4B, 0x01, 0xC9, 0x53, 0x09, 0x96, 0x9B, 0xEC, 0x68, 0xAA, 0x0B, 0xC0, 0x81
};
static u8 EDAT_HASH_1[0x10] = {
0x3D, 0x92, 0x69, 0x9B, 0x70, 0x5B, 0x07, 0x38, 0x54, 0xD8, 0xFC, 0xC6, 0xC7, 0x67, 0x27, 0x47
};
static u8 EDAT_IV[0x10] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
static u8 VSH_CURVE_P[0x14] = {
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
};
static u8 VSH_CURVE_A[0x14] = {
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC
};
static u8 VSH_CURVE_B[0x14] = {
0xA6, 0x8B, 0xED, 0xC3, 0x34, 0x18, 0x02, 0x9C, 0x1D, 0x3C, 0xE3, 0x3B, 0x9A, 0x32, 0x1F, 0xCC, 0xBB, 0x9E, 0x0F, 0x0B
};
static u8 VSH_CURVE_N[0x15] = {
0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xB5, 0xAE, 0x3C, 0x52, 0x3E, 0x63, 0x94, 0x4F, 0x21, 0x27
};
static u8 VSH_CURVE_GX[0x14] = {
0x12, 0x8E, 0xC4, 0x25, 0x64, 0x87, 0xFD, 0x8F, 0xDF, 0x64, 0xE2, 0x43, 0x7B, 0xC0, 0xA1, 0xF6, 0xD5, 0xAF, 0xDE, 0x2C
};
static u8 VSH_CURVE_GY[0x14] = {
0x59, 0x58, 0x55, 0x7E, 0xB1, 0xDB, 0x00, 0x12, 0x60, 0x42, 0x55, 0x24, 0xDB, 0xC3, 0x79, 0xD5, 0xAC, 0x5F, 0x4A, 0xDF
};
static u8 VSH_PUB[0x28] = {
0x62, 0x27, 0xB0, 0x0A, 0x02, 0x85, 0x6F, 0xB0, 0x41, 0x08, 0x87, 0x67, 0x19, 0xE0, 0xA0, 0x18, 0x32, 0x91, 0xEE, 0xB9,
0x6E, 0x73, 0x6A, 0xBF, 0x81, 0xF7, 0x0E, 0xE9, 0x16, 0x1B, 0x0D, 0xDE, 0xB0, 0x26, 0x76, 0x1A, 0xFF, 0x7B, 0xC8, 0x5B
};
static u8 SCEPKG_RIV[0x10] = {
0x4A, 0xCE, 0xF0, 0x12, 0x24, 0xFB, 0xEE, 0xDF, 0x82, 0x45, 0xF8, 0xFF, 0x10, 0x21, 0x1E, 0x6E
};
static u8 SCEPKG_ERK[0x20] = {
0xA9, 0x78, 0x18, 0xBD, 0x19, 0x3A, 0x67, 0xA1, 0x6F, 0xE8, 0x3A, 0x85, 0x5E, 0x1B, 0xE9, 0xFB, 0x56, 0x40, 0x93, 0x8D,
0x4D, 0xBC, 0xB2, 0xCB, 0x52, 0xC5, 0xA2, 0xF8, 0xB0, 0x2B, 0x10, 0x31
};
static u8 PUP_KEY[0x40] = {
0xF4, 0x91, 0xAD, 0x94, 0xC6, 0x81, 0x10, 0x96, 0x91, 0x5F, 0xD5, 0xD2, 0x44, 0x81, 0xAE, 0xDC, 0xED, 0xED, 0xBE, 0x6B,
0xE5, 0x13, 0x72, 0x4D, 0xD8, 0xF7, 0xB6, 0x91, 0xE8, 0x8A, 0x38, 0xF4, 0xB5, 0x16, 0x2B, 0xFB, 0xEC, 0xBE, 0x3A, 0x62,
0x18, 0x5D, 0xD7, 0xC9, 0x4D, 0xA2, 0x22, 0x5A, 0xDA, 0x3F, 0xBF, 0xCE, 0x55, 0x5B, 0x9E, 0xA9, 0x64, 0x98, 0x29, 0xEB,
0x30, 0xCE, 0x83, 0x66
};
class KeyVault
{
std::vector<SELF_KEY> sk_LV0_arr;
std::vector<SELF_KEY> sk_LV1_arr;
std::vector<SELF_KEY> sk_LV2_arr;
std::vector<SELF_KEY> sk_APP_arr;
std::vector<SELF_KEY> sk_ISO_arr;
std::vector<SELF_KEY> sk_LDR_arr;
std::vector<SELF_KEY> sk_UNK7_arr;
std::vector<SELF_KEY> sk_NPDRM_arr;
std::unique_ptr<u8[]> klicensee_key;
public:
KeyVault();
SELF_KEY FindSelfKey(u32 type, u16 revision, u64 version);
void SetKlicenseeKey(u8 *key);
u8 *GetKlicenseeKey();
private:
void LoadSelfLV0Keys();
void LoadSelfLDRKeys();
void LoadSelfLV1Keys();
void LoadSelfLV2Keys();
void LoadSelfISOKeys();
void LoadSelfAPPKeys();
void LoadSelfUNK7Keys();
void LoadSelfNPDRMKeys();
SELF_KEY GetSelfLV0Key() const;
SELF_KEY GetSelfLDRKey() const;
SELF_KEY GetSelfLV1Key(u64 version) const;
SELF_KEY GetSelfLV2Key(u64 version) const;
SELF_KEY GetSelfISOKey(u16 revision, u64 version) const;
SELF_KEY GetSelfAPPKey(u16 revision) const;
SELF_KEY GetSelfUNK7Key(u64 version) const;
SELF_KEY GetSelfNPDRMKey(u16 revision) const;
};
// RAP to RIF function.
void rap_to_rif(unsigned char* rap, unsigned char* rif);
#pragma once
#include "util/types.hpp"
#include <string>
#include <vector>
#include <memory>
enum SELF_KEY_TYPE
{
KEY_LV0 = 1,
KEY_LV1,
KEY_LV2,
KEY_APP,
KEY_ISO,
KEY_LDR,
KEY_UNK7,
KEY_NPDRM
};
struct SELF_KEY
{
u64 version_start;
u64 version_end;
u16 revision;
u32 self_type;
u8 erk[0x20];
u8 riv[0x10];
u8 pub[0x28];
u8 priv[0x15];
u32 curve_type;
SELF_KEY(u64 ver_start, u64 ver_end, u16 rev, u32 type, const std::string& e, const std::string& r, const std::string& pb, const std::string& pr, u32 ct);
};
constexpr u8 PKG_AES_KEY_IDU[0x10] = {
0x5d, 0xb9, 0x11, 0xe6, 0xb7, 0xe5, 0x0a, 0x7d, 0x32, 0x15, 0x38, 0xfd, 0x7c, 0x66, 0xf1, 0x7b
};
constexpr u8 PKG_AES_KEY[0x10] = {
0x2e, 0x7b, 0x71, 0xd7, 0xc9, 0xc9, 0xa1, 0x4e, 0xa3, 0x22, 0x1f, 0x18, 0x88, 0x28, 0xb8, 0xf8
};
constexpr u8 PKG_AES_KEY2[0x10] = {
0x07, 0xf2, 0xc6, 0x82, 0x90, 0xb5, 0x0d, 0x2c, 0x33, 0x81, 0x8d, 0x70, 0x9b, 0x60, 0xe6, 0x2b
};
constexpr u8 PKG_AES_KEY_VITA_1[0x10] = {
0xE3, 0x1A, 0x70, 0xC9, 0xCE, 0x1D, 0xD7, 0x2B, 0xF3, 0xC0, 0x62, 0x29, 0x63, 0xF2, 0xEC, 0xCB
};
constexpr u8 PKG_AES_KEY_VITA_2[0x10] = {
0x42, 0x3A, 0xCA, 0x3A, 0x2B, 0xD5, 0x64, 0x9F, 0x96, 0x86, 0xAB, 0xAD, 0x6F, 0xD8, 0x80, 0x1F
};
constexpr u8 PKG_AES_KEY_VITA_3[0x10] = {
0xAF, 0x07, 0xFD, 0x59, 0x65, 0x25, 0x27, 0xBA, 0xF1, 0x33, 0x89, 0x66, 0x8B, 0x17, 0xD9, 0xEA
};
constexpr u8 NP_IDPS[0x10] = {
0x5E, 0x06, 0xE0, 0x4F, 0xD9, 0x4A, 0x71, 0xBF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01
};
constexpr u8 NP_KLIC_FREE[0x10] = {
0x72, 0xF9, 0x90, 0x78, 0x8F, 0x9C, 0xFF, 0x74, 0x57, 0x25, 0xF0, 0x8E, 0x4C, 0x12, 0x83, 0x87
};
constexpr u8 NP_OMAC_KEY_2[0x10] = {
0x6B, 0xA5, 0x29, 0x76, 0xEF, 0xDA, 0x16, 0xEF, 0x3C, 0x33, 0x9F, 0xB2, 0x97, 0x1E, 0x25, 0x6B
};
constexpr u8 NP_OMAC_KEY_3[0x10] = {
0x9B, 0x51, 0x5F, 0xEA, 0xCF, 0x75, 0x06, 0x49, 0x81, 0xAA, 0x60, 0x4D, 0x91, 0xA5, 0x4E, 0x97
};
constexpr u8 NP_KLIC_KEY[0x10] = {
0xF2, 0xFB, 0xCA, 0x7A, 0x75, 0xB0, 0x4E, 0xDC, 0x13, 0x90, 0x63, 0x8C, 0xCD, 0xFD, 0xD1, 0xEE
};
constexpr u8 NP_RIF_KEY[0x10] = {
0xDA, 0x7D, 0x4B, 0x5E, 0x49, 0x9A, 0x4F, 0x53, 0xB1, 0xC1, 0xA1, 0x4A, 0x74, 0x84, 0x44, 0x3B
};
// PSP Minis
constexpr u8 NP_PSP_KEY_1[0x10] = {
0x2A, 0x6A, 0xFB, 0xCF, 0x43, 0xD1, 0x57, 0x9F, 0x7D, 0x73, 0x87, 0x41, 0xA1, 0x3B, 0xD4, 0x2E
};
// PSP Remasters
constexpr u8 NP_PSP_KEY_2[0x10] = {
0x0D, 0xB8, 0x57, 0x32, 0x36, 0x6C, 0xD7, 0x34, 0xFC, 0x87, 0x9E, 0x74, 0x33, 0x43, 0xBB, 0x4F
};
constexpr u8 NP_PSX_KEY[0x10] = {
0x52, 0xC0, 0xB5, 0xCA, 0x76, 0xD6, 0x13, 0x4B, 0xB4, 0x5F, 0xC6, 0x6C, 0xA6, 0x37, 0xF2, 0xC1
};
constexpr u8 RAP_KEY[0x10] = {
0x86, 0x9F, 0x77, 0x45, 0xC1, 0x3F, 0xD8, 0x90, 0xCC, 0xF2, 0x91, 0x88, 0xE3, 0xCC, 0x3E, 0xDF
};
constexpr u8 RAP_PBOX[0x10] = {
0x0C, 0x03, 0x06, 0x04, 0x01, 0x0B, 0x0F, 0x08, 0x02, 0x07, 0x00, 0x05, 0x0A, 0x0E, 0x0D, 0x09
};
constexpr u8 RAP_E1[0x10] = {
0xA9, 0x3E, 0x1F, 0xD6, 0x7C, 0x55, 0xA3, 0x29, 0xB7, 0x5F, 0xDD, 0xA6, 0x2A, 0x95, 0xC7, 0xA5
};
constexpr u8 RAP_E2[0x10] = {
0x67, 0xD4, 0x5D, 0xA3, 0x29, 0x6D, 0x00, 0x6A, 0x4E, 0x7C, 0x53, 0x7B, 0xF5, 0x53, 0x8C, 0x74
};
constexpr u8 SDAT_KEY[0x10] = {
0x0D, 0x65, 0x5E, 0xF8, 0xE6, 0x74, 0xA9, 0x8A, 0xB8, 0x50, 0x5C, 0xFA, 0x7D, 0x01, 0x29, 0x33
};
constexpr u8 EDAT_KEY_0[0x10] = {
0xBE, 0x95, 0x9C, 0xA8, 0x30, 0x8D, 0xEF, 0xA2, 0xE5, 0xE1, 0x80, 0xC6, 0x37, 0x12, 0xA9, 0xAE
};
constexpr u8 EDAT_HASH_0[0x10] = {
0xEF, 0xFE, 0x5B, 0xD1, 0x65, 0x2E, 0xEB, 0xC1, 0x19, 0x18, 0xCF, 0x7C, 0x04, 0xD4, 0xF0, 0x11
};
constexpr u8 EDAT_KEY_1[0x10] = {
0x4C, 0xA9, 0xC1, 0x4B, 0x01, 0xC9, 0x53, 0x09, 0x96, 0x9B, 0xEC, 0x68, 0xAA, 0x0B, 0xC0, 0x81
};
constexpr u8 EDAT_HASH_1[0x10] = {
0x3D, 0x92, 0x69, 0x9B, 0x70, 0x5B, 0x07, 0x38, 0x54, 0xD8, 0xFC, 0xC6, 0xC7, 0x67, 0x27, 0x47
};
constexpr u8 EDAT_IV[0x10] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
constexpr u8 VSH_CURVE_P[0x14] = {
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
};
constexpr u8 VSH_CURVE_A[0x14] = {
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC
};
constexpr u8 VSH_CURVE_B[0x14] = {
0xA6, 0x8B, 0xED, 0xC3, 0x34, 0x18, 0x02, 0x9C, 0x1D, 0x3C, 0xE3, 0x3B, 0x9A, 0x32, 0x1F, 0xCC, 0xBB, 0x9E, 0x0F, 0x0B
};
constexpr u8 VSH_CURVE_N[0x15] = {
0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xB5, 0xAE, 0x3C, 0x52, 0x3E, 0x63, 0x94, 0x4F, 0x21, 0x27
};
constexpr u8 VSH_CURVE_GX[0x14] = {
0x12, 0x8E, 0xC4, 0x25, 0x64, 0x87, 0xFD, 0x8F, 0xDF, 0x64, 0xE2, 0x43, 0x7B, 0xC0, 0xA1, 0xF6, 0xD5, 0xAF, 0xDE, 0x2C
};
constexpr u8 VSH_CURVE_GY[0x14] = {
0x59, 0x58, 0x55, 0x7E, 0xB1, 0xDB, 0x00, 0x12, 0x60, 0x42, 0x55, 0x24, 0xDB, 0xC3, 0x79, 0xD5, 0xAC, 0x5F, 0x4A, 0xDF
};
constexpr u8 VSH_PUB[0x28] = {
0x62, 0x27, 0xB0, 0x0A, 0x02, 0x85, 0x6F, 0xB0, 0x41, 0x08, 0x87, 0x67, 0x19, 0xE0, 0xA0, 0x18, 0x32, 0x91, 0xEE, 0xB9,
0x6E, 0x73, 0x6A, 0xBF, 0x81, 0xF7, 0x0E, 0xE9, 0x16, 0x1B, 0x0D, 0xDE, 0xB0, 0x26, 0x76, 0x1A, 0xFF, 0x7B, 0xC8, 0x5B
};
constexpr u8 SCEPKG_RIV[0x10] = {
0x4A, 0xCE, 0xF0, 0x12, 0x24, 0xFB, 0xEE, 0xDF, 0x82, 0x45, 0xF8, 0xFF, 0x10, 0x21, 0x1E, 0x6E
};
constexpr u8 SCEPKG_ERK[0x20] = {
0xA9, 0x78, 0x18, 0xBD, 0x19, 0x3A, 0x67, 0xA1, 0x6F, 0xE8, 0x3A, 0x85, 0x5E, 0x1B, 0xE9, 0xFB, 0x56, 0x40, 0x93, 0x8D,
0x4D, 0xBC, 0xB2, 0xCB, 0x52, 0xC5, 0xA2, 0xF8, 0xB0, 0x2B, 0x10, 0x31
};
constexpr u8 PUP_KEY[0x40] = {
0xF4, 0x91, 0xAD, 0x94, 0xC6, 0x81, 0x10, 0x96, 0x91, 0x5F, 0xD5, 0xD2, 0x44, 0x81, 0xAE, 0xDC, 0xED, 0xED, 0xBE, 0x6B,
0xE5, 0x13, 0x72, 0x4D, 0xD8, 0xF7, 0xB6, 0x91, 0xE8, 0x8A, 0x38, 0xF4, 0xB5, 0x16, 0x2B, 0xFB, 0xEC, 0xBE, 0x3A, 0x62,
0x18, 0x5D, 0xD7, 0xC9, 0x4D, 0xA2, 0x22, 0x5A, 0xDA, 0x3F, 0xBF, 0xCE, 0x55, 0x5B, 0x9E, 0xA9, 0x64, 0x98, 0x29, 0xEB,
0x30, 0xCE, 0x83, 0x66
};
class KeyVault
{
std::vector<SELF_KEY> sk_LV0_arr;
std::vector<SELF_KEY> sk_LV1_arr;
std::vector<SELF_KEY> sk_LV2_arr;
std::vector<SELF_KEY> sk_APP_arr;
std::vector<SELF_KEY> sk_ISO_arr;
std::vector<SELF_KEY> sk_LDR_arr;
std::vector<SELF_KEY> sk_UNK7_arr;
std::vector<SELF_KEY> sk_NPDRM_arr;
std::unique_ptr<u8[]> klicensee_key;
public:
KeyVault();
SELF_KEY FindSelfKey(u32 type, u16 revision, u64 version);
void SetKlicenseeKey(u8* key);
u8* GetKlicenseeKey();
private:
void LoadSelfLV0Keys();
void LoadSelfLDRKeys();
void LoadSelfLV1Keys();
void LoadSelfLV2Keys();
void LoadSelfISOKeys();
void LoadSelfAPPKeys();
void LoadSelfUNK7Keys();
void LoadSelfNPDRMKeys();
SELF_KEY GetSelfLV0Key() const;
SELF_KEY GetSelfLDRKey() const;
SELF_KEY GetSelfLV1Key(u64 version) const;
SELF_KEY GetSelfLV2Key(u64 version) const;
SELF_KEY GetSelfISOKey(u16 revision, u64 version) const;
SELF_KEY GetSelfAPPKey(u16 revision) const;
SELF_KEY GetSelfUNK7Key(u64 version) const;
SELF_KEY GetSelfNPDRMKey(u16 revision) const;
};
// RAP to RIF function.
void rap_to_rif(unsigned char* rap, unsigned char* rif);
+65 -56
View File
@@ -1,10 +1,15 @@
#include "stdafx.h"
#include "stdafx.h"
#include "key_vault.h"
#include "unedat.h"
#include "sha1.h"
#include "lz.h"
#include "ec.h"
#include "Utilities/mutex.h"
#include <cmath>
#include "util/asm.hpp"
LOG_CHANNEL(edat_log, "EDAT");
// Static variables are being modified concurrently in ec.cpp, for now use a mutex
@@ -13,12 +18,14 @@ static shared_mutex ec_mtx;
void generate_key(int crypto_mode, int version, unsigned char *key_final, unsigned char *iv_final, unsigned char *key, unsigned char *iv)
{
int mode = crypto_mode & 0xF0000000;
uchar temp_iv[16]{};
switch (mode)
{
case 0x10000000:
// Encrypted ERK.
// Decrypt the key with EDAT_KEY + EDAT_IV and copy the original IV.
aescbc128_decrypt(version ? EDAT_KEY_1 : EDAT_KEY_0, EDAT_IV, key, key_final, 0x10);
memcpy(temp_iv, EDAT_IV, 0x10);
aescbc128_decrypt(const_cast<u8*>(version ? EDAT_KEY_1 : EDAT_KEY_0), temp_iv, key, key_final, 0x10);
memcpy(iv_final, iv, 0x10);
break;
case 0x20000000:
@@ -39,12 +46,14 @@ void generate_key(int crypto_mode, int version, unsigned char *key_final, unsign
void generate_hash(int hash_mode, int version, unsigned char *hash_final, unsigned char *hash)
{
int mode = hash_mode & 0xF0000000;
uchar temp_iv[16]{};
switch (mode)
{
case 0x10000000:
// Encrypted HASH.
// Decrypt the hash with EDAT_KEY + EDAT_IV.
aescbc128_decrypt(version ? EDAT_KEY_1 : EDAT_KEY_0, EDAT_IV, hash, hash_final, 0x10);
memcpy(temp_iv, EDAT_IV, 0x10);
aescbc128_decrypt(const_cast<u8*>(version ? EDAT_KEY_1 : EDAT_KEY_0), temp_iv, hash, hash_final, 0x10);
break;
case 0x20000000:
// Default HASH.
@@ -135,15 +144,15 @@ std::tuple<u64, s32, s32> dec_section(unsigned char* metadata)
return std::make_tuple(offset, length, compression_end);
}
v128 get_block_key(int block, NPD_HEADER *npd)
u128 get_block_key(int block, NPD_HEADER *npd)
{
unsigned char empty_key[0x10] = {};
unsigned char *src_key = (npd->version <= 1) ? empty_key : npd->dev_hash;
v128 dest_key{};
memcpy(dest_key._bytes, src_key, 0xC);
u128 dest_key{};
std::memcpy(&dest_key, src_key, 0xC);
s32 swappedBlock = swap32(block);
memcpy(&dest_key._bytes[0xC], &swappedBlock, sizeof(swappedBlock));
std::memcpy(reinterpret_cast<uchar*>(&dest_key) + 0xC, &swappedBlock, sizeof(swappedBlock));
return dest_key;
}
@@ -248,7 +257,7 @@ s64 decrypt_block(const fs::file* in, u8* out, EDAT_HEADER *edat, NPD_HEADER *np
auto b_key = get_block_key(block_num, npd);
// Encrypt the block key with the crypto key.
aesecb128_encrypt(crypt_key, b_key._bytes, key_result);
aesecb128_encrypt(crypt_key, reinterpret_cast<uchar*>(&b_key), key_result);
if ((edat->flags & EDAT_FLAG_0x10) != 0)
aesecb128_encrypt(crypt_key, key_result, hash); // If FLAG 0x10 is set, encrypt again to get the final hash.
else
@@ -537,7 +546,7 @@ int check_data(unsigned char *key, EDAT_HEADER *edat, NPD_HEADER *npd, const fs:
return 0;
}
int validate_dev_klic(const u8* klicensee, NPD_HEADER *npd)
bool validate_dev_klic(const u8* klicensee, NPD_HEADER *npd)
{
unsigned char dev[0x60] = { 0 };
@@ -553,30 +562,31 @@ int validate_dev_klic(const u8* klicensee, NPD_HEADER *npd)
memcpy(dev + 0xC, &type, 4);
// Check for an empty dev_hash (can't validate if devklic is NULL);
auto klic = v128::loadu(klicensee);
u128 klic;
std::memcpy(&klic, klicensee, sizeof(klic));
if (klic == v128{})
if (!klic)
{
// Allow empty dev hash.
return 1;
return true;
}
else
{
// Generate klicensee xor key.
auto key = klic ^ std::bit_cast<v128>(NP_OMAC_KEY_2);
// Hash with generated key and compare with dev_hash.
return cmac_hash_compare(key._bytes, 0x10, dev, 0x60, npd->dev_hash, 0x10);
}
// Generate klicensee xor key.
u128 key = klic ^ std::bit_cast<u128>(NP_OMAC_KEY_2);
// Hash with generated key and compare with dev_hash.
return cmac_hash_compare(reinterpret_cast<uchar*>(&key), 0x10, dev, 0x60, npd->dev_hash, 0x10);
}
int validate_npd_hashes(const char* file_name, const u8* klicensee, NPD_HEADER *npd, bool verbose)
bool validate_npd_hashes(const char* file_name, const u8* klicensee, NPD_HEADER *npd, bool verbose)
{
int title_hash_result = 0;
int dev_hash_result = 0;
if (!file_name)
{
fmt::throw_exception("Empty filename");
}
const s32 file_name_length = ::narrow<s32>(std::strlen(file_name), HERE);
const std::size_t buf_len = 0x30 + file_name_length;
const usz file_name_length = std::strlen(file_name);
const usz buf_len = 0x30 + file_name_length;
std::unique_ptr<u8[]> buf(new u8[buf_len]);
std::unique_ptr<u8[]> buf_lower(new u8[buf_len]);
@@ -589,7 +599,7 @@ int validate_npd_hashes(const char* file_name, const u8* klicensee, NPD_HEADER *
std::memcpy(buf_lower.get(), buf.get(), buf_len);
std::memcpy(buf_upper.get(), buf.get(), buf_len);
for (std::size_t i = std::basic_string_view<u8>(buf.get() + 0x30, file_name_length).find_last_of('.'); i < buf_len; i++)
for (usz i = std::basic_string_view<u8>(buf.get() + 0x30, file_name_length).find_last_of('.'); i < buf_len; i++)
{
const u8 c = static_cast<u8>(buf[i]);
buf_upper[i] = std::toupper(c);
@@ -598,10 +608,10 @@ int validate_npd_hashes(const char* file_name, const u8* klicensee, NPD_HEADER *
// Hash with NPDRM_OMAC_KEY_3 and compare with title_hash.
// Try to ignore case sensivity with file extension
title_hash_result =
cmac_hash_compare(NP_OMAC_KEY_3, 0x10, buf.get(), buf_len, npd->title_hash, 0x10) ||
cmac_hash_compare(NP_OMAC_KEY_3, 0x10, buf_lower.get(), buf_len, npd->title_hash, 0x10) ||
cmac_hash_compare(NP_OMAC_KEY_3, 0x10, buf_upper.get(), buf_len, npd->title_hash, 0x10);
const bool title_hash_result =
cmac_hash_compare(const_cast<u8*>(NP_OMAC_KEY_3), 0x10, buf.get(), buf_len, npd->title_hash, 0x10) ||
cmac_hash_compare(const_cast<u8*>(NP_OMAC_KEY_3), 0x10, buf_lower.get(), buf_len, npd->title_hash, 0x10) ||
cmac_hash_compare(const_cast<u8*>(NP_OMAC_KEY_3), 0x10, buf_upper.get(), buf_len, npd->title_hash, 0x10);
if (verbose)
{
@@ -611,10 +621,9 @@ int validate_npd_hashes(const char* file_name, const u8* klicensee, NPD_HEADER *
edat_log.warning("EDAT: NPD title hash is invalid!");
}
const bool dev_hash_result = validate_dev_klic(klicensee, npd);
dev_hash_result = validate_dev_klic(klicensee, npd);
return (title_hash_result && dev_hash_result);
return title_hash_result && dev_hash_result;
}
void read_npd_edat_header(const fs::file* input, NPD_HEADER& NPD, EDAT_HEADER& EDAT)
@@ -665,7 +674,7 @@ bool extract_all_data(const fs::file* input, const fs::file* output, const char*
}
// Set decryption key.
v128 key{};
u128 key{};
// Check EDAT/SDAT flag.
if ((EDAT.flags & SDAT_FLAG) == SDAT_FLAG)
@@ -679,7 +688,7 @@ bool extract_all_data(const fs::file* input, const fs::file* output, const char*
}
// Generate SDAT key.
key = std::bit_cast<v128>(NPD.dev_hash) ^ std::bit_cast<v128>(SDAT_KEY);
key = std::bit_cast<u128>(NPD.dev_hash) ^ std::bit_cast<u128>(SDAT_KEY);
}
else
{
@@ -712,7 +721,7 @@ bool extract_all_data(const fs::file* input, const fs::file* output, const char*
memcpy(&key, rifkey, 0x10);
// Make sure we don't have an empty RIF key.
if (key == v128{})
if (!key)
{
edat_log.error("EDAT: A valid RAP file is needed for this EDAT file! (local activation)");
return 1;
@@ -723,7 +732,7 @@ bool extract_all_data(const fs::file* input, const fs::file* output, const char*
memcpy(&key, rifkey, 0x10);
// Make sure we don't have an empty RIF key.
if (key == v128{})
if (!key)
{
edat_log.error("EDAT: A valid RAP file is needed for this EDAT file! (network activation)");
return 1;
@@ -732,7 +741,7 @@ bool extract_all_data(const fs::file* input, const fs::file* output, const char*
if (verbose)
{
be_t<v128> data;
be_t<u128> data;
std::memcpy(&data, devklic, sizeof(data));
edat_log.notice("DEVKLIC: %s", data);
@@ -743,18 +752,18 @@ bool extract_all_data(const fs::file* input, const fs::file* output, const char*
if (verbose)
{
edat_log.notice("DECRYPTION KEY: %s", std::bit_cast<be_t<v128>>(key));
edat_log.notice("DECRYPTION KEY: %s", std::bit_cast<be_t<u128>>(key));
}
input->seek(0);
if (check_data(key._bytes, &EDAT, &NPD, input, verbose))
if (check_data(reinterpret_cast<uchar*>(&key), &EDAT, &NPD, input, verbose))
{
edat_log.error("EDAT: Data parsing failed!");
return 1;
}
input->seek(0);
if (decrypt_data(input, output, &EDAT, &NPD, key._bytes, verbose))
if (decrypt_data(input, output, &EDAT, &NPD, reinterpret_cast<uchar*>(&key), verbose))
{
edat_log.error("EDAT: Data decryption failed!");
return 1;
@@ -763,14 +772,14 @@ bool extract_all_data(const fs::file* input, const fs::file* output, const char*
return 0;
}
v128 GetEdatRifKeyFromRapFile(const fs::file& rap_file)
u128 GetEdatRifKeyFromRapFile(const fs::file& rap_file)
{
v128 rapkey{};
v128 rifkey{};
u128 rapkey{};
u128 rifkey{};
rap_file.read<v128>(rapkey);
rap_file.read<u128>(rapkey);
rap_to_rif(rapkey._bytes, rifkey._bytes);
rap_to_rif(reinterpret_cast<uchar*>(&rapkey), reinterpret_cast<uchar*>(&rifkey));
return rifkey;
}
@@ -821,8 +830,8 @@ fs::file DecryptEDAT(const fs::file& input, const std::string& input_file_name,
input.seek(0);
// Set keys (RIF and DEVKLIC).
v128 rifKey{};
v128 devklic{};
u128 rifKey{};
u128 devklic{};
// Select the EDAT key mode.
switch (mode)
@@ -876,7 +885,7 @@ fs::file DecryptEDAT(const fs::file& input, const std::string& input_file_name,
// Delete the bad output file if any errors arise.
fs::file output = fs::make_stream<std::vector<u8>>();
if (extract_all_data(&input, &output, input_file_name.c_str(), devklic._bytes, rifKey._bytes, verbose))
if (extract_all_data(&input, &output, input_file_name.c_str(), reinterpret_cast<uchar*>(&devklic), reinterpret_cast<uchar*>(&rifKey), verbose))
{
output.release();
return fs::file{};
@@ -902,12 +911,12 @@ bool EDATADecrypter::ReadHeader()
if ((edatHeader.flags & SDAT_FLAG) == SDAT_FLAG)
{
// Generate SDAT key.
dec_key = std::bit_cast<v128>(npdHeader.dev_hash) ^ std::bit_cast<v128>(SDAT_KEY);
dec_key = std::bit_cast<u128>(npdHeader.dev_hash) ^ std::bit_cast<u128>(SDAT_KEY);
}
else
{
// verify key
if (validate_dev_klic(dev_key._bytes, &npdHeader) == 0)
if (!validate_dev_klic(reinterpret_cast<uchar*>(&dev_key), &npdHeader))
{
edat_log.error("EDAT: Failed validating klic");
return false;
@@ -920,16 +929,16 @@ bool EDATADecrypter::ReadHeader()
{
dec_key = std::move(rif_key);
if (dec_key == v128{})
if (!dec_key)
{
edat_log.warning("EDAT: Empty Dec key for local actívation!");
edat_log.warning("EDAT: Empty Dec key for local activation!");
}
}
else if ((npdHeader.license & 0x1) == 0x1) // Type 1: Use network activation.
{
dec_key = std::move(rif_key);
if (dec_key == v128{})
if (!dec_key)
{
edat_log.warning("EDAT: Empty Dec key for network activation!");
}
@@ -947,7 +956,7 @@ bool EDATADecrypter::ReadHeader()
}*/
file_size = edatHeader.file_size;
total_blocks = ::aligned_div(edatHeader.file_size, edatHeader.block_size);
total_blocks = utils::aligned_div(edatHeader.file_size, edatHeader.block_size);
return true;
}
@@ -960,7 +969,7 @@ u64 EDATADecrypter::ReadData(u64 pos, u8* data, u64 size)
// now we need to offset things to account for the actual 'range' requested
const u64 startOffset = pos % edatHeader.block_size;
const u32 num_blocks = static_cast<u32>(::aligned_div(startOffset + size, edatHeader.block_size));
const u32 num_blocks = static_cast<u32>(utils::aligned_div(startOffset + size, edatHeader.block_size));
const u64 bufSize = num_blocks*edatHeader.block_size;
if (data_buf_size < (bufSize))
{
@@ -975,7 +984,7 @@ u64 EDATADecrypter::ReadData(u64 pos, u8* data, u64 size)
for (u32 i = starting_block; i < ending_block; ++i)
{
edata_file.seek(0);
u64 res = decrypt_block(&edata_file, &data_buf[writeOffset], &edatHeader, &npdHeader, dec_key._bytes, i, total_blocks, edatHeader.file_size);
u64 res = decrypt_block(&edata_file, &data_buf[writeOffset], &edatHeader, &npdHeader, reinterpret_cast<uchar*>(&dec_key), i, total_blocks, edatHeader.file_size);
if (res == umax)
{
edat_log.error("Error Decrypting data");
+10 -9
View File
@@ -4,7 +4,6 @@
#include "utils.h"
#include "Utilities/BEType.h"
#include "Utilities/File.h"
constexpr u32 SDAT_FLAG = 0x01000000;
@@ -17,8 +16,8 @@ constexpr u32 EDAT_DEBUG_DATA_FLAG = 0x80000000;
struct loaded_npdrm_keys
{
atomic_t<v128> devKlic{};
atomic_t<v128> rifKey{};
atomic_t<u128> devKlic{};
atomic_t<u128> rifKey{};
atomic_t<u32> npdrm_fds{0};
};
@@ -48,7 +47,7 @@ extern fs::file DecryptEDAT(const fs::file& input, const std::string& input_file
extern bool VerifyEDATHeaderWithKLicense(const fs::file& input, const std::string& input_file_name, const u8* custom_klic, std::string* contentID);
v128 GetEdatRifKeyFromRapFile(const fs::file& rap_file);
u128 GetEdatRifKeyFromRapFile(const fs::file& rap_file);
struct EDATADecrypter final : fs::file_base
{
@@ -65,18 +64,20 @@ struct EDATADecrypter final : fs::file_base
std::unique_ptr<u8[]> data_buf;
u64 data_buf_size{0};
v128 dec_key{};
u128 dec_key{};
// edat usage
v128 rif_key{};
v128 dev_key{};
u128 rif_key{};
u128 dev_key{};
public:
// SdataByFd usage
EDATADecrypter(fs::file&& input)
: edata_file(std::move(input)) {}
// Edat usage
EDATADecrypter(fs::file&& input, const v128& dev_key, const v128& rif_key)
: edata_file(std::move(input)), rif_key(rif_key), dev_key(dev_key) {}
EDATADecrypter(fs::file&& input, const u128& dev_key, const u128& rif_key)
: edata_file(std::move(input))
, rif_key(rif_key)
, dev_key(dev_key) {}
~EDATADecrypter() override {}
// false if invalid
+284 -262
View File
@@ -1,4 +1,4 @@
#include "stdafx.h"
#include "stdafx.h"
#include "aes.h"
#include "sha1.h"
#include "key_vault.h"
@@ -20,7 +20,7 @@ package_reader::package_reader(const std::string& path)
return;
}
filelist.emplace_back(fs::file{ path });
m_filelist.emplace_back(fs::file{path});
m_is_valid = read_header();
@@ -30,6 +30,18 @@ package_reader::package_reader(const std::string& path)
}
m_is_valid = read_metadata();
if (!m_is_valid)
{
return;
}
const bool param_sfo_found = read_param_sfo();
if (!param_sfo_found)
{
pkg_log.notice("PKG does not contain a PARAM.SFO");
}
}
package_reader::~package_reader()
@@ -38,34 +50,34 @@ package_reader::~package_reader()
bool package_reader::read_header()
{
if (m_path.empty() || filelist.empty())
if (m_path.empty() || m_filelist.empty())
{
pkg_log.error("Reading PKG header: no file to read!");
return false;
}
if (archive_read(&header, sizeof(header)) != sizeof(header))
if (archive_read(&m_header, sizeof(m_header)) != sizeof(m_header))
{
pkg_log.error("Reading PKG header: file is too short!");
return false;
}
pkg_log.notice("Header: pkg_magic = 0x%x = \"%s\"", +header.pkg_magic, std::string(reinterpret_cast<const char*>(&header.pkg_magic), 4));
pkg_log.notice("Header: pkg_type = 0x%x = %d", header.pkg_type, header.pkg_type);
pkg_log.notice("Header: pkg_platform = 0x%x = %d", header.pkg_platform, header.pkg_platform);
pkg_log.notice("Header: meta_offset = 0x%x = %d", header.meta_offset, header.meta_offset);
pkg_log.notice("Header: meta_count = 0x%x = %d", header.meta_count, header.meta_count);
pkg_log.notice("Header: meta_size = 0x%x = %d", header.meta_size, header.meta_size);
pkg_log.notice("Header: file_count = 0x%x = %d", header.file_count, header.file_count);
pkg_log.notice("Header: pkg_size = 0x%x = %d", header.pkg_size, header.pkg_size);
pkg_log.notice("Header: data_offset = 0x%x = %d", header.data_offset, header.data_offset);
pkg_log.notice("Header: data_size = 0x%x = %d", header.data_size, header.data_size);
pkg_log.notice("Header: title_id = %s", header.title_id);
pkg_log.notice("Header: qa_digest = 0x%x 0x%x", header.qa_digest[0], header.qa_digest[1]);
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_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);
pkg_log.notice("Header: meta_count = 0x%x = %d", m_header.meta_count, m_header.meta_count);
pkg_log.notice("Header: meta_size = 0x%x = %d", m_header.meta_size, m_header.meta_size);
pkg_log.notice("Header: file_count = 0x%x = %d", m_header.file_count, m_header.file_count);
pkg_log.notice("Header: pkg_size = 0x%x = %d", m_header.pkg_size, m_header.pkg_size);
pkg_log.notice("Header: data_offset = 0x%x = %d", m_header.data_offset, m_header.data_offset);
pkg_log.notice("Header: data_size = 0x%x = %d", m_header.data_size, m_header.data_size);
pkg_log.notice("Header: title_id = %s", m_header.title_id);
pkg_log.notice("Header: qa_digest = 0x%x 0x%x", m_header.qa_digest[0], m_header.qa_digest[1]);
//pkg_log.notice("Header: klicensee = 0x%x = %d", header.klicensee, header.klicensee);
// Get extended PKG information for PSP or PSVita
if (header.pkg_platform == PKG_PLATFORM_TYPE_PSP_PSVITA)
if (m_header.pkg_platform == PKG_PLATFORM_TYPE_PSP_PSVITA)
{
PKGExtHeader ext_header;
@@ -90,13 +102,13 @@ bool package_reader::read_header()
//pkg_log.notice("Extended header: padding2 = 0x%x = %d", ext_header.padding2, ext_header.padding2);
}
if (header.pkg_magic != std::bit_cast<le_t<u32>>("\x7FPKG"_u32))
if (m_header.pkg_magic != std::bit_cast<le_t<u32>>("\x7FPKG"_u32))
{
pkg_log.error("Not a PKG file!");
return false;
}
switch (const u16 type = header.pkg_type)
switch (const u16 type = m_header.pkg_type)
{
case PKG_RELEASE_TYPE_DEBUG: break;
case PKG_RELEASE_TYPE_RELEASE: break;
@@ -107,7 +119,7 @@ bool package_reader::read_header()
}
}
switch (const u16 platform = header.pkg_platform)
switch (const u16 platform = m_header.pkg_platform)
{
case PKG_PLATFORM_TYPE_PS3: break;
case PKG_PLATFORM_TYPE_PSP_PSVITA: break;
@@ -118,20 +130,20 @@ bool package_reader::read_header()
}
}
if (header.pkg_size > filelist[0].size())
if (m_header.pkg_size > m_filelist[0].size())
{
// Check if multi-files pkg
if (!m_path.ends_with("_00.pkg"))
{
pkg_log.error("PKG file size mismatch (pkg_size=0x%llx)", header.pkg_size);
pkg_log.error("PKG file size mismatch (pkg_size=0x%llx)", m_header.pkg_size);
return false;
}
const std::string name_wo_number = m_path.substr(0, m_path.size() - 7);
u64 cursize = filelist[0].size();
while (cursize < header.pkg_size)
u64 cursize = m_filelist[0].size();
while (cursize < m_header.pkg_size)
{
const std::string archive_filename = fmt::format("%s_%02d.pkg", name_wo_number, filelist.size());
const std::string archive_filename = fmt::format("%s_%02d.pkg", name_wo_number, m_filelist.size());
fs::file archive_file(archive_filename);
if (!archive_file)
@@ -141,13 +153,13 @@ bool package_reader::read_header()
}
cursize += archive_file.size();
filelist.emplace_back(std::move(archive_file));
m_filelist.emplace_back(std::move(archive_file));
}
}
if (header.data_size + header.data_offset > header.pkg_size)
if (m_header.data_size + m_header.data_offset > m_header.pkg_size)
{
pkg_log.error("PKG data size mismatch (data_size=0x%llx, data_offset=0x%llx, file_size=0x%llx)", header.data_size, header.data_offset, header.pkg_size);
pkg_log.error("PKG data size mismatch (data_size=0x%llx, data_offset=0x%llx, file_size=0x%llx)", m_header.data_size, m_header.data_offset, m_header.pkg_size);
return false;
}
@@ -156,21 +168,21 @@ bool package_reader::read_header()
bool package_reader::read_metadata()
{
if (!m_is_valid)
if (!decrypt_data())
{
return false;
}
// Read title ID and use it as an installation directory
install_dir.resize(9);
m_install_dir.resize(9);
archive_seek(55);
archive_read(&install_dir.front(), install_dir.size());
archive_read(&m_install_dir.front(), m_install_dir.size());
// Read package metadata
archive_seek(header.meta_offset);
archive_seek(m_header.meta_offset);
for (u32 i = 0; i < header.meta_count; i++)
for (u32 i = 0; i < m_header.meta_count; i++)
{
struct packet_T
{
@@ -185,40 +197,38 @@ bool package_reader::read_metadata()
{
case 0x1:
{
if (packet.size == sizeof(metadata.drm_type))
if (packet.size == sizeof(m_metadata.drm_type))
{
archive_read(&metadata.drm_type, sizeof(metadata.drm_type));
pkg_log.notice("Metadata: DRM Type = 0x%x = %d", metadata.drm_type, metadata.drm_type);
archive_read(&m_metadata.drm_type, sizeof(m_metadata.drm_type));
pkg_log.notice("Metadata: DRM Type = 0x%x = %d", m_metadata.drm_type, m_metadata.drm_type);
continue;
}
else
{
pkg_log.error("Metadata: DRM Type size mismatch (0x%x)", packet.size);
}
break;
}
case 0x2:
{
if (packet.size == sizeof(metadata.content_type))
if (packet.size == sizeof(m_metadata.content_type))
{
archive_read(&metadata.content_type, sizeof(metadata.content_type));
pkg_log.notice("Metadata: Content Type = 0x%x = %d", metadata.content_type, metadata.content_type);
archive_read(&m_metadata.content_type, sizeof(m_metadata.content_type));
pkg_log.notice("Metadata: Content Type = 0x%x = %d", m_metadata.content_type, m_metadata.content_type);
continue;
}
else
{
pkg_log.error("Metadata: Content Type size mismatch (0x%x)", packet.size);
}
break;
}
case 0x3:
{
if (packet.size == sizeof(metadata.package_type))
if (packet.size == sizeof(m_metadata.package_type))
{
archive_read(&metadata.package_type, sizeof(metadata.package_type));
pkg_log.notice("Metadata: Package Type = 0x%x = %d", metadata.package_type, metadata.package_type);
archive_read(&m_metadata.package_type, sizeof(m_metadata.package_type));
pkg_log.notice("Metadata: Package Type = 0x%x = %d", m_metadata.package_type, m_metadata.package_type);
continue;
}
else
@@ -229,10 +239,10 @@ bool package_reader::read_metadata()
}
case 0x4:
{
if (packet.size == sizeof(metadata.package_size))
if (packet.size == sizeof(m_metadata.package_size))
{
archive_read(&metadata.package_size, sizeof(metadata.package_size));
pkg_log.notice("Metadata: Package Size = 0x%x = %d", metadata.package_size, metadata.package_size);
archive_read(&m_metadata.package_size, sizeof(m_metadata.package_size));
pkg_log.notice("Metadata: Package Size = 0x%x = %d", m_metadata.package_size, m_metadata.package_size);
continue;
}
else
@@ -243,11 +253,11 @@ bool package_reader::read_metadata()
}
case 0x5:
{
if (packet.size == sizeof(metadata.package_revision.data))
if (packet.size == sizeof(m_metadata.package_revision.data))
{
archive_read(&metadata.package_revision.data, sizeof(metadata.package_revision.data));
metadata.package_revision.interpret_data();
pkg_log.notice("Metadata: Package Revision = %s", metadata.package_revision.to_string());
archive_read(&m_metadata.package_revision.data, sizeof(m_metadata.package_revision.data));
m_metadata.package_revision.interpret_data();
pkg_log.notice("Metadata: Package Revision = %s", m_metadata.package_revision.to_string());
continue;
}
else
@@ -258,13 +268,13 @@ bool package_reader::read_metadata()
}
case 0x6:
{
metadata.title_id.resize(12);
m_metadata.title_id.resize(12);
if (packet.size == metadata.title_id.size())
if (packet.size == m_metadata.title_id.size())
{
archive_read(&metadata.title_id, metadata.title_id.size());
metadata.title_id = fmt::trim(metadata.title_id);
pkg_log.notice("Metadata: Title ID = %s", metadata.title_id);
archive_read(&m_metadata.title_id, m_metadata.title_id.size());
m_metadata.title_id = fmt::trim(m_metadata.title_id);
pkg_log.notice("Metadata: Title ID = %s", m_metadata.title_id);
continue;
}
else
@@ -275,10 +285,10 @@ bool package_reader::read_metadata()
}
case 0x7:
{
if (packet.size == sizeof(metadata.qa_digest))
if (packet.size == sizeof(m_metadata.qa_digest))
{
archive_read(&metadata.qa_digest, sizeof(metadata.qa_digest));
pkg_log.notice("Metadata: QA Digest = 0x%x", metadata.qa_digest);
archive_read(&m_metadata.qa_digest, sizeof(m_metadata.qa_digest));
pkg_log.notice("Metadata: QA Digest = 0x%x", m_metadata.qa_digest);
continue;
}
else
@@ -289,11 +299,11 @@ bool package_reader::read_metadata()
}
case 0x8:
{
if (packet.size == sizeof(metadata.software_revision.data))
if (packet.size == sizeof(m_metadata.software_revision.data))
{
archive_read(&metadata.software_revision.data, sizeof(metadata.software_revision.data));
metadata.software_revision.interpret_data();
pkg_log.notice("Metadata: Software Revision = %s", metadata.software_revision.to_string());
archive_read(&m_metadata.software_revision.data, sizeof(m_metadata.software_revision.data));
m_metadata.software_revision.interpret_data();
pkg_log.notice("Metadata: Software Revision = %s", m_metadata.software_revision.to_string());
continue;
}
else
@@ -304,10 +314,10 @@ bool package_reader::read_metadata()
}
case 0x9:
{
if (packet.size == sizeof(metadata.unk_0x9))
if (packet.size == sizeof(m_metadata.unk_0x9))
{
archive_read(&metadata.unk_0x9, sizeof(metadata.unk_0x9));
pkg_log.notice("Metadata: unk_0x9 = 0x%x = %d", metadata.unk_0x9, metadata.unk_0x9);
archive_read(&m_metadata.unk_0x9, sizeof(m_metadata.unk_0x9));
pkg_log.notice("Metadata: unk_0x9 = 0x%x = %d", m_metadata.unk_0x9, m_metadata.unk_0x9);
continue;
}
else
@@ -321,26 +331,25 @@ bool package_reader::read_metadata()
if (packet.size > 8)
{
// Read an actual installation directory (DLC)
install_dir.resize(packet.size);
archive_read(&install_dir.front(), packet.size);
install_dir = install_dir.c_str() + 8;
metadata.install_dir = install_dir;
pkg_log.notice("Metadata: Install Dir = %s", metadata.install_dir);
m_install_dir.resize(packet.size);
archive_read(&m_install_dir.front(), packet.size);
m_install_dir = m_install_dir.c_str() + 8;
m_metadata.install_dir = m_install_dir;
pkg_log.notice("Metadata: Install Dir = %s", m_metadata.install_dir);
continue;
}
else
{
pkg_log.error("Metadata: Install Dir size mismatch (0x%x)", packet.size);
}
break;
}
case 0xB:
{
if (packet.size == sizeof(metadata.unk_0xB))
if (packet.size == sizeof(m_metadata.unk_0xB))
{
archive_read(&metadata.unk_0xB, sizeof(metadata.unk_0xB));
pkg_log.notice("Metadata: unk_0xB = 0x%x = %d", metadata.unk_0xB, metadata.unk_0xB);
archive_read(&m_metadata.unk_0xB, sizeof(m_metadata.unk_0xB));
pkg_log.notice("Metadata: unk_0xB = 0x%x = %d", m_metadata.unk_0xB, m_metadata.unk_0xB);
continue;
}
else
@@ -356,10 +365,10 @@ bool package_reader::read_metadata()
}
case 0xD: // PSVita stuff
{
if (packet.size == sizeof(metadata.item_info))
if (packet.size == sizeof(m_metadata.item_info))
{
archive_read(&metadata.item_info, sizeof(metadata.item_info));
pkg_log.notice("Metadata: PSVita item info = %s", metadata.item_info.to_string());
archive_read(&m_metadata.item_info, sizeof(m_metadata.item_info));
pkg_log.notice("Metadata: PSVita item info = %s", m_metadata.item_info.to_string());
continue;
}
else
@@ -370,10 +379,10 @@ bool package_reader::read_metadata()
}
case 0xE: // PSVita stuff
{
if (packet.size == sizeof(metadata.sfo_info))
if (packet.size == sizeof(m_metadata.sfo_info))
{
archive_read(&metadata.sfo_info, sizeof(metadata.sfo_info));
pkg_log.notice("Metadata: PSVita sfo info = %s", metadata.sfo_info.to_string());
archive_read(&m_metadata.sfo_info, sizeof(m_metadata.sfo_info));
pkg_log.notice("Metadata: PSVita sfo info = %s", m_metadata.sfo_info.to_string());
continue;
}
else
@@ -384,10 +393,10 @@ bool package_reader::read_metadata()
}
case 0xF: // PSVita stuff
{
if (packet.size == sizeof(metadata.unknown_data_info))
if (packet.size == sizeof(m_metadata.unknown_data_info))
{
archive_read(&metadata.unknown_data_info, sizeof(metadata.unknown_data_info));
pkg_log.notice("Metadata: PSVita unknown data info = %s", metadata.unknown_data_info.to_string());
archive_read(&m_metadata.unknown_data_info, sizeof(m_metadata.unknown_data_info));
pkg_log.notice("Metadata: PSVita unknown data info = %s", m_metadata.unknown_data_info.to_string());
continue;
}
else
@@ -398,10 +407,10 @@ bool package_reader::read_metadata()
}
case 0x10: // PSVita stuff
{
if (packet.size == sizeof(metadata.entirety_info))
if (packet.size == sizeof(m_metadata.entirety_info))
{
archive_read(&metadata.entirety_info, sizeof(metadata.entirety_info));
pkg_log.notice("Metadata: PSVita entirety info = %s", metadata.entirety_info.to_string());
archive_read(&m_metadata.entirety_info, sizeof(m_metadata.entirety_info));
pkg_log.notice("Metadata: PSVita entirety info = %s", m_metadata.entirety_info.to_string());
continue;
}
else
@@ -412,23 +421,24 @@ bool package_reader::read_metadata()
}
case 0x11: // PSVita stuff
{
if (packet.size == sizeof(metadata.version_info))
if (packet.size == sizeof(m_metadata.version_info))
{
archive_read(&metadata.version_info, sizeof(metadata.version_info));
pkg_log.notice("Metadata: PSVita version info = %s", metadata.version_info.to_string());
archive_read(&m_metadata.version_info, sizeof(m_metadata.version_info));
pkg_log.notice("Metadata: PSVita version info = %s", m_metadata.version_info.to_string());
continue;
}
else
{
pkg_log.error("Metadata: Version info size mismatch (0x%x)", packet.size);
}
break;
}
case 0x12: // PSVita stuff
{
if (packet.size == sizeof(metadata.self_info))
if (packet.size == sizeof(m_metadata.self_info))
{
archive_read(&metadata.self_info, sizeof(metadata.self_info));
pkg_log.notice("Metadata: PSVita self info = %s", metadata.self_info.to_string());
archive_read(&m_metadata.self_info, sizeof(m_metadata.self_info));
pkg_log.notice("Metadata: PSVita self info = %s", m_metadata.self_info.to_string());
continue;
}
else
@@ -457,36 +467,35 @@ bool package_reader::decrypt_data()
return false;
}
if (header.pkg_platform == PKG_PLATFORM_TYPE_PSP_PSVITA && metadata.content_type >= 0x15 && metadata.content_type <= 0x17)
if (m_header.pkg_platform == PKG_PLATFORM_TYPE_PSP_PSVITA && m_metadata.content_type >= 0x15 && m_metadata.content_type <= 0x17)
{
// PSVita
// TODO: Not all the keys seem to match the content types. I was only able to install a dlc (0x16) with PKG_AES_KEY_VITA_1
aes_context ctx;
aes_setkey_enc(&ctx, metadata.content_type == 0x15u ? PKG_AES_KEY_VITA_1 : metadata.content_type == 0x16u ? PKG_AES_KEY_VITA_2 : PKG_AES_KEY_VITA_3, 128);
aes_crypt_ecb(&ctx, AES_ENCRYPT, reinterpret_cast<const uchar*>(&header.klicensee), dec_key.data());
decrypt(0, header.file_count * sizeof(PKGEntry), dec_key.data());
aes_setkey_enc(&ctx, m_metadata.content_type == 0x15u ? PKG_AES_KEY_VITA_1 : m_metadata.content_type == 0x16u ? PKG_AES_KEY_VITA_2 : PKG_AES_KEY_VITA_3, 128);
aes_crypt_ecb(&ctx, AES_ENCRYPT, reinterpret_cast<const uchar*>(&m_header.klicensee), m_dec_key.data());
decrypt(0, m_header.file_count * sizeof(PKGEntry), m_dec_key.data());
}
else
{
std::memcpy(dec_key.data(), PKG_AES_KEY, dec_key.size());
decrypt(0, header.file_count * sizeof(PKGEntry), header.pkg_platform == PKG_PLATFORM_TYPE_PSP_PSVITA ? PKG_AES_KEY2 : dec_key.data());
std::memcpy(m_dec_key.data(), PKG_AES_KEY, m_dec_key.size());
decrypt(0, m_header.file_count * sizeof(PKGEntry), m_header.pkg_platform == PKG_PLATFORM_TYPE_PSP_PSVITA ? PKG_AES_KEY2 : m_dec_key.data());
}
return true;
}
// TODO: maybe also check if VERSION matches
package_error package_reader::check_target_app_version()
bool package_reader::read_param_sfo()
{
if (!decrypt_data())
{
return package_error::other;
return false;
}
std::vector<PKGEntry> entries(header.file_count);
std::vector<PKGEntry> entries(m_header.file_count);
std::memcpy(entries.data(), buf.get(), entries.size() * sizeof(PKGEntry));
std::memcpy(entries.data(), m_buf.get(), entries.size() * sizeof(PKGEntry));
for (const auto& entry : entries)
{
@@ -498,11 +507,11 @@ package_error package_reader::check_target_app_version()
const bool is_psp = (entry.type & PKG_FILE_ENTRY_PSP) != 0u;
decrypt(entry.name_offset, entry.name_size, is_psp ? PKG_AES_KEY2 : dec_key.data());
decrypt(entry.name_offset, entry.name_size, is_psp ? PKG_AES_KEY2 : m_dec_key.data());
const std::string name{ reinterpret_cast<char*>(buf.get()), entry.name_size };
const std::string name{reinterpret_cast<char*>(m_buf.get()), entry.name_size};
// We're looking for the PARAM.SFO file, if there is any
// We're looking for the PARAM.SFO file, if there is any
if (name != "PARAM.SFO")
{
continue;
@@ -515,133 +524,146 @@ package_error package_reader::check_target_app_version()
{
const u64 block_size = std::min<u64>(BUF_SIZE, entry.file_size - pos);
if (decrypt(entry.file_offset + pos, block_size, is_psp ? PKG_AES_KEY2 : dec_key.data()) != block_size)
if (decrypt(entry.file_offset + pos, block_size, is_psp ? PKG_AES_KEY2 : m_dec_key.data()) != block_size)
{
pkg_log.error("Failed to decrypt PARAM.SFO file");
return package_error::other;
return false;
}
if (tmp.write(buf.get(), block_size) != block_size)
if (tmp.write(m_buf.get(), block_size) != block_size)
{
pkg_log.error("Failed to write to temporary PARAM.SFO file");
return package_error::other;
return false;
}
}
tmp.seek(0);
const auto psf = psf::load_object(tmp);
m_psf = psf::load_object(tmp);
const auto category = psf::get_string(psf, "CATEGORY", "");
const auto title_id = psf::get_string(psf, "TITLE_ID", "");
const auto app_ver = psf::get_string(psf, "APP_VER", "");
const auto target_app_ver = psf::get_string(psf, "TARGET_APP_VER", "");
if (category != "GD")
{
// We allow anything that isn't an update for now
return package_error::no_error;
}
if (title_id.empty())
{
// Let's allow packages without ID for now
return package_error::no_error;
}
if (app_ver.empty())
{
if (!target_app_ver.empty())
{
// Let's see if this case exists
pkg_log.fatal("Trying to install an unversioned patch with a target app version (%s). Please contact a developer!", target_app_ver);
}
// This is probably not a version dependant patch, so we may install the package
return package_error::no_error;
}
const fs::file installed_sfo_file(Emu.GetHddDir() + "game/" + std::string(title_id) + "/PARAM.SFO");
if (!installed_sfo_file)
{
if (!target_app_ver.empty())
{
// We are unable to compare anything with the target app version
pkg_log.error("A target app version is required (%s), but no PARAM.SFO was found for %s", target_app_ver, title_id);
return package_error::app_version;
}
// There is nothing we need to compare, so we may install the package
return package_error::no_error;
}
const auto installed_psf = psf::load_object(installed_sfo_file);
const auto installed_title_id = psf::get_string(installed_psf, "TITLE_ID", "");
const auto installed_app_ver = psf::get_string(installed_psf, "APP_VER", "");
if (title_id != installed_title_id || installed_app_ver.empty())
{
// Let's allow this package for now
return package_error::no_error;
}
std::add_pointer_t<char> ev0, ev1;
const double old_version = std::strtod(installed_app_ver.data(), &ev0);
if (installed_app_ver.data() + installed_app_ver.size() != ev0)
{
pkg_log.error("Failed to convert the installed app version to double (%s)", installed_app_ver);
return package_error::other;
}
if (target_app_ver.empty())
{
// This is most likely the first patch. Let's make sure its version is high enough for the installed game.
const double new_version = std::strtod(app_ver.data(), &ev1);
if (app_ver.data() + app_ver.size() != ev1)
{
pkg_log.error("Failed to convert the package's app version to double (%s)", app_ver);
return package_error::other;
}
if (new_version >= old_version)
{
// Yay! The patch has a higher or equal version than the installed game.
return package_error::no_error;
}
pkg_log.error("The new app version (%s) is smaller than the installed app version (%s)", app_ver, installed_app_ver);
return package_error::app_version;
}
// Check if the installed app version matches the target app version
const double target_version = std::strtod(target_app_ver.data(), &ev1);
if (target_app_ver.data() + target_app_ver.size() != ev1)
{
pkg_log.error("Failed to convert the package's target app version to double (%s)", target_app_ver);
return package_error::other;
}
if (target_version == old_version)
{
// Yay! This patch is for the installed game version.
return package_error::no_error;
}
pkg_log.error("The installed app version (%s) does not match the target app version (%s)", installed_app_ver, target_app_ver);
return package_error::app_version;
return true;
}
else
{
pkg_log.error("Failed to create temporary PARAM.SFO file");
return false;
}
}
pkg_log.error("Failed to create temporary PARAM.SFO file");
return false;
}
// TODO: maybe also check if VERSION matches
package_error package_reader::check_target_app_version()
{
if (!m_is_valid)
{
return package_error::other;
}
return package_error::no_error;
const auto category = psf::get_string(m_psf, "CATEGORY", "");
const auto title_id = psf::get_string(m_psf, "TITLE_ID", "");
const auto app_ver = psf::get_string(m_psf, "APP_VER", "");
const auto target_app_ver = psf::get_string(m_psf, "TARGET_APP_VER", "");
if (category != "GD")
{
// We allow anything that isn't an update for now
return package_error::no_error;
}
if (title_id.empty())
{
// Let's allow packages without ID for now
return package_error::no_error;
}
if (app_ver.empty())
{
if (!target_app_ver.empty())
{
// Let's see if this case exists
pkg_log.fatal("Trying to install an unversioned patch with a target app version (%s). Please contact a developer!", target_app_ver);
}
// This is probably not a version dependant patch, so we may install the package
return package_error::no_error;
}
const fs::file installed_sfo_file(Emu.GetHddDir() + "game/" + std::string(title_id) + "/PARAM.SFO");
if (!installed_sfo_file)
{
if (!target_app_ver.empty())
{
// We are unable to compare anything with the target app version
pkg_log.error("A target app version is required (%s), but no PARAM.SFO was found for %s", target_app_ver, title_id);
return package_error::app_version;
}
// There is nothing we need to compare, so we may install the package
return package_error::no_error;
}
const auto installed_psf = psf::load_object(installed_sfo_file);
const auto installed_title_id = psf::get_string(installed_psf, "TITLE_ID", "");
const auto installed_app_ver = psf::get_string(installed_psf, "APP_VER", "");
if (title_id != installed_title_id || installed_app_ver.empty())
{
// Let's allow this package for now
return package_error::no_error;
}
std::add_pointer_t<char> ev0, ev1;
const double old_version = std::strtod(installed_app_ver.data(), &ev0);
if (installed_app_ver.data() + installed_app_ver.size() != ev0)
{
pkg_log.error("Failed to convert the installed app version to double (%s)", installed_app_ver);
return package_error::other;
}
if (target_app_ver.empty())
{
// This is most likely the first patch. Let's make sure its version is high enough for the installed game.
const double new_version = std::strtod(app_ver.data(), &ev1);
if (app_ver.data() + app_ver.size() != ev1)
{
pkg_log.error("Failed to convert the package's app version to double (%s)", app_ver);
return package_error::other;
}
if (new_version >= old_version)
{
// Yay! The patch has a higher or equal version than the installed game.
return package_error::no_error;
}
pkg_log.error("The new app version (%s) is smaller than the installed app version (%s)", app_ver, installed_app_ver);
return package_error::app_version;
}
// Check if the installed app version matches the target app version
const double target_version = std::strtod(target_app_ver.data(), &ev1);
if (target_app_ver.data() + target_app_ver.size() != ev1)
{
pkg_log.error("Failed to convert the package's target app version to double (%s)", target_app_ver);
return package_error::other;
}
if (target_version == old_version)
{
// Yay! This patch is for the installed game version.
return package_error::no_error;
}
pkg_log.error("The installed app version (%s) does not match the target app version (%s)", installed_app_ver, target_app_ver);
return package_error::app_version;
}
bool package_reader::extract_data(atomic_t<double>& sync)
@@ -655,7 +677,7 @@ bool package_reader::extract_data(atomic_t<double>& sync)
std::string dir = Emulator::GetHddDir();
// Based on https://www.psdevwiki.com/ps3/PKG_files#ContentType
switch (metadata.content_type)
switch (m_metadata.content_type)
{
case PKG_CONTENT_TYPE_THEME:
dir += "theme/";
@@ -681,7 +703,7 @@ bool package_reader::extract_data(atomic_t<double>& sync)
break;
}
dir += install_dir + '/';
dir += m_install_dir + '/';
// If false, an existing directory is being overwritten: cannot cancel the operation
const bool was_null = !fs::is_dir(dir);
@@ -697,11 +719,11 @@ bool package_reader::extract_data(atomic_t<double>& sync)
return false;
}
size_t num_failures = 0;
usz num_failures = 0;
std::vector<PKGEntry> entries(header.file_count);
std::vector<PKGEntry> entries(m_header.file_count);
std::memcpy(entries.data(), buf.get(), entries.size() * sizeof(PKGEntry));
std::memcpy(entries.data(), m_buf.get(), entries.size() * sizeof(PKGEntry));
for (const auto& entry : entries)
{
@@ -714,9 +736,9 @@ bool package_reader::extract_data(atomic_t<double>& sync)
const bool is_psp = (entry.type & PKG_FILE_ENTRY_PSP) != 0u;
decrypt(entry.name_offset, entry.name_size, is_psp ? PKG_AES_KEY2 : dec_key.data());
decrypt(entry.name_offset, entry.name_size, is_psp ? PKG_AES_KEY2 : m_dec_key.data());
const std::string name{ reinterpret_cast<char*>(buf.get()), entry.name_size };
const std::string name{reinterpret_cast<char*>(m_buf.get()), entry.name_size};
const std::string path = dir + vfs::escape(name);
pkg_log.notice("Entry 0x%08x: %s", entry.type, name);
@@ -754,21 +776,21 @@ bool package_reader::extract_data(atomic_t<double>& sync)
{
const u64 block_size = std::min<u64>(BUF_SIZE, entry.file_size - pos);
if (decrypt(entry.file_offset + pos, block_size, is_psp ? PKG_AES_KEY2 : dec_key.data()) != block_size)
if (decrypt(entry.file_offset + pos, block_size, is_psp ? PKG_AES_KEY2 : m_dec_key.data()) != block_size)
{
extract_success = false;
pkg_log.error("Failed to extract file %s", path);
break;
}
if (out.write(buf.get(), block_size) != block_size)
if (out.write(m_buf.get(), block_size) != block_size)
{
extract_success = false;
pkg_log.error("Failed to write file %s", path);
break;
}
if (sync.fetch_add((block_size + 0.0) / header.data_size) < 0.)
if (sync.fetch_add((block_size + 0.0) / m_header.data_size) < 0.)
{
if (was_null)
{
@@ -852,55 +874,55 @@ bool package_reader::extract_data(atomic_t<double>& sync)
void package_reader::archive_seek(const s64 new_offset, const fs::seek_mode damode)
{
if (damode == fs::seek_set)
cur_offset = new_offset;
m_cur_offset = new_offset;
else if (damode == fs::seek_cur)
cur_offset += new_offset;
m_cur_offset += new_offset;
u64 _offset = 0;
for (size_t i = 0; i < filelist.size(); i++)
for (usz i = 0; i < m_filelist.size(); i++)
{
if (cur_offset < (_offset + filelist[i].size()))
if (m_cur_offset < (_offset + m_filelist[i].size()))
{
cur_file = i;
cur_file_offset = cur_offset - _offset;
filelist[i].seek(cur_file_offset);
m_cur_file = i;
m_cur_file_offset = m_cur_offset - _offset;
m_filelist[i].seek(m_cur_file_offset);
break;
}
_offset += filelist[i].size();
_offset += m_filelist[i].size();
}
};
u64 package_reader::archive_read(void* data_ptr, const u64 num_bytes)
{
ASSERT(filelist.size() > cur_file && filelist[cur_file]);
ensure(m_filelist.size() > m_cur_file && m_filelist[m_cur_file]);
const u64 num_bytes_left = filelist[cur_file].size() - cur_file_offset;
const u64 num_bytes_left = m_filelist[m_cur_file].size() - m_cur_file_offset;
// check if it continues in another file
if (num_bytes > num_bytes_left)
{
filelist[cur_file].read(data_ptr, num_bytes_left);
m_filelist[m_cur_file].read(data_ptr, num_bytes_left);
if ((cur_file + 1) < filelist.size())
if ((m_cur_file + 1) < m_filelist.size())
{
++cur_file;
++m_cur_file;
}
else
{
cur_offset += num_bytes_left;
cur_file_offset = filelist[cur_file].size();
m_cur_offset += num_bytes_left;
m_cur_file_offset = m_filelist[m_cur_file].size();
return num_bytes_left;
}
const u64 num_read = filelist[cur_file].read(static_cast<u8*>(data_ptr) + num_bytes_left, num_bytes - num_bytes_left);
cur_offset += (num_read + num_bytes_left);
cur_file_offset = num_read;
const u64 num_read = m_filelist[m_cur_file].read(static_cast<u8*>(data_ptr) + num_bytes_left, num_bytes - num_bytes_left);
m_cur_offset += (num_read + num_bytes_left);
m_cur_file_offset = num_read;
return (num_read + num_bytes_left);
}
const u64 num_read = filelist[cur_file].read(data_ptr, num_bytes);
const u64 num_read = m_filelist[m_cur_file].read(data_ptr, num_bytes);
cur_offset += num_read;
cur_file_offset += num_read;
m_cur_offset += num_read;
m_cur_file_offset += num_read;
return num_read;
};
@@ -912,29 +934,29 @@ u64 package_reader::decrypt(u64 offset, u64 size, const uchar* key)
return 0;
}
if (!buf)
if (!m_buf)
{
// Allocate buffer with BUF_SIZE size or more if required
buf.reset(new u128[std::max<u64>(BUF_SIZE, sizeof(PKGEntry) * header.file_count) / sizeof(u128)]);
m_buf.reset(new u128[std::max<u64>(BUF_SIZE, sizeof(PKGEntry) * m_header.file_count) / sizeof(u128)]);
}
archive_seek(header.data_offset + offset);
archive_seek(m_header.data_offset + offset);
// Read the data and set available size
const u64 read = archive_read(buf.get(), size);
const u64 read = archive_read(m_buf.get(), size);
// Get block count
const u64 blocks = (read + 15) / 16;
if (header.pkg_type == PKG_RELEASE_TYPE_DEBUG)
if (m_header.pkg_type == PKG_RELEASE_TYPE_DEBUG)
{
// Debug key
be_t<u64> input[8] =
{
header.qa_digest[0],
header.qa_digest[0],
header.qa_digest[1],
header.qa_digest[1],
m_header.qa_digest[0],
m_header.qa_digest[0],
m_header.qa_digest[1],
m_header.qa_digest[1],
};
for (u64 i = 0; i < blocks; i++)
@@ -950,10 +972,10 @@ u64 package_reader::decrypt(u64 offset, u64 size, const uchar* key)
sha1(reinterpret_cast<const u8*>(input), sizeof(input), hash.data);
buf[i] ^= hash._v128;
m_buf[i] ^= hash._v128;
}
}
else if (header.pkg_type == PKG_RELEASE_TYPE_RELEASE)
else if (m_header.pkg_type == PKG_RELEASE_TYPE_RELEASE)
{
aes_context ctx;
@@ -961,7 +983,7 @@ u64 package_reader::decrypt(u64 offset, u64 size, const uchar* key)
aes_setkey_enc(&ctx, key, 128);
// Initialize stream cipher for start position
be_t<u128> input = header.klicensee.value() + offset / 16;
be_t<u128> input = m_header.klicensee.value() + offset / 16;
// Increment stream position for every block
for (u64 i = 0; i < blocks; i++, input++)
@@ -970,12 +992,12 @@ u64 package_reader::decrypt(u64 offset, u64 size, const uchar* key)
aes_crypt_ecb(&ctx, AES_ENCRYPT, reinterpret_cast<const u8*>(&input), reinterpret_cast<u8*>(&key));
buf[i] ^= key;
m_buf[i] ^= key;
}
}
else
{
pkg_log.error("Unknown release type (0x%x)", header.pkg_type);
pkg_log.error("Unknown release type (0x%x)", m_header.pkg_type);
}
// Return the amount of data written in buf
+22 -16
View File
@@ -1,13 +1,16 @@
#pragma once
#include "Utilities/BEType.h"
#include "Loader/PSF.h"
#include "util/endian.hpp"
#include "util/types.hpp"
#include "Utilities/File.h"
#include <sstream>
#include <iomanip>
// Constants
enum
{
PKG_HEADER_SIZE = 0xC0, //sizeof(pkg_header) + sizeof(pkg_unk_checksum)
PKG_HEADER_SIZE = 0xC0, // sizeof(pkg_header) + sizeof(pkg_unk_checksum)
PKG_HEADER_SIZE2 = 0x280,
};
@@ -96,7 +99,7 @@ struct PKGExtHeader
be_t<u32> ext_hdr_size; // Extended header size. ex: 0x40
be_t<u32> ext_data_size; // ex: 0x180
be_t<u32> main_and_ext_headers_hmac_offset; // ex: 0x100
be_t<u32> metadata_header_hmac_offset; // ex: 0x360, 0x390, 0x490
be_t<u32> metadata_header_hmac_offset; // ex: 0x360, 0x390, 0x490
be_t<u64> tail_offset; // tail size seams to be always 0x1A0
be_t<u32> padding1;
be_t<u32> pkg_key_id; // Id of the AES key used for decryption. PSP = 0x1, PSVita = 0xC0000002, PSM = 0xC0000004
@@ -118,16 +121,16 @@ struct PKGEntry
struct PKGMetaData
{
private:
static std::string to_hex_string(u8 buf[], size_t size)
static std::string to_hex_string(u8 buf[], usz size)
{
std::stringstream sstream;
for (size_t i = 0; i < size; i++)
for (usz i = 0; i < size; i++)
{
sstream << std::hex << std::setw(2) << std::setfill('0') << static_cast<int>(buf[i]);
}
return sstream.str();
}
static std::string to_hex_string(u8 buf[], size_t size, size_t dotpos)
static std::string to_hex_string(u8 buf[], usz size, usz dotpos)
{
std::string result = to_hex_string(buf, size);
if (result.size() > dotpos)
@@ -304,28 +307,31 @@ public:
package_error check_target_app_version();
bool extract_data(atomic_t<double>& sync);
psf::registry get_psf() const { return m_psf; }
private:
bool read_header();
bool read_metadata();
bool read_param_sfo();
bool decrypt_data();
void archive_seek(const s64 new_offset, const fs::seek_mode damode = fs::seek_set);
u64 archive_read(void* data_ptr, const u64 num_bytes);
u64 decrypt(u64 offset, u64 size, const uchar* key);
const std::size_t BUF_SIZE = 8192 * 1024; // 8 MB
const usz BUF_SIZE = 8192 * 1024; // 8 MB
bool m_is_valid = false;
std::string m_path;
std::string install_dir;
std::vector<fs::file> filelist;
size_t cur_file = 0;
u64 cur_offset = 0;
u64 cur_file_offset = 0;
std::unique_ptr<u128[]> buf;
std::array<uchar, 16> dec_key{};
std::string m_install_dir;
std::vector<fs::file> m_filelist;
usz m_cur_file = 0;
u64 m_cur_offset = 0;
u64 m_cur_file_offset = 0;
std::unique_ptr<u128[]> m_buf;
std::array<uchar, 16> m_dec_key{};
PKGHeader header{};
PKGMetaData metadata{};
PKGHeader m_header{};
PKGMetaData m_metadata{};
psf::registry m_psf;
};
+14 -15
View File
@@ -1,9 +1,8 @@
#include "stdafx.h"
#include "stdafx.h"
#include "aes.h"
#include "sha1.h"
#include "utils.h"
#include "unself.h"
#include "Utilities/BEType.h"
#include "Emu/VFS.h"
#include "Emu/System.h"
@@ -714,7 +713,7 @@ bool SCEDecrypter::LoadMetadata(const u8 erk[32], const u8 riv[16])
}
// Perform AES-CTR encryption on the metadata headers.
size_t ctr_nc_off = 0;
usz ctr_nc_off = 0;
u8 ctr_stream_block[0x10];
aes_setkey_enc(&aes, meta_info.key, 128);
aes_crypt_ctr(&aes, metadata_headers_size, &ctr_nc_off, meta_info.iv, ctr_stream_block, metadata_headers.get(), metadata_headers.get());
@@ -745,7 +744,7 @@ bool SCEDecrypter::DecryptData()
// Calculate the total data size.
for (unsigned int i = 0; i < meta_hdr.section_count; i++)
{
data_buf_length += ::narrow<u32>(meta_shdr[i].data_size, HERE);
data_buf_length += ::narrow<u32>(meta_shdr[i].data_size);
}
// Allocate a buffer to store decrypted data.
@@ -757,7 +756,7 @@ bool SCEDecrypter::DecryptData()
// Parse the metadata section headers to find the offsets of encrypted data.
for (unsigned int i = 0; i < meta_hdr.section_count; i++)
{
size_t ctr_nc_off = 0;
usz ctr_nc_off = 0;
u8 ctr_stream_block[0x10];
u8 data_key[0x10];
u8 data_iv[0x10];
@@ -799,7 +798,7 @@ bool SCEDecrypter::DecryptData()
}
// Advance the buffer's offset.
data_buf_offset += ::narrow<u32>(meta_shdr[i].data_size, HERE);
data_buf_offset += ::narrow<u32>(meta_shdr[i].data_size);
}
return true;
@@ -823,13 +822,13 @@ std::vector<fs::file> SCEDecrypter::MakeFile()
// Decompress if necessary.
if (meta_shdr[i].compressed == 2)
{
const size_t BUFSIZE = 32 * 1024;
const usz BUFSIZE = 32 * 1024;
u8 tempbuf[BUFSIZE];
z_stream strm;
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
strm.avail_in = ::narrow<uInt>(meta_shdr[i].data_size, HERE);
strm.avail_in = ::narrow<uInt>(meta_shdr[i].data_size);
strm.avail_out = BUFSIZE;
strm.next_in = data_buf.get()+data_buf_offset;
strm.next_out = tempbuf;
@@ -874,7 +873,7 @@ std::vector<fs::file> SCEDecrypter::MakeFile()
}
// Advance the data buffer offset by data size.
data_buf_offset += ::narrow<u32>(meta_shdr[i].data_size, HERE);
data_buf_offset += ::narrow<u32>(meta_shdr[i].data_size);
if (out_f.pos() != out_f.size())
fmt::throw_exception("MakeELF written bytes (%llu) does not equal buffer size (%llu).", out_f.pos(), out_f.size());
@@ -1209,7 +1208,7 @@ bool SELFDecrypter::LoadMetadata(u8* klic_key)
}
// Perform AES-CTR encryption on the metadata headers.
size_t ctr_nc_off = 0;
usz ctr_nc_off = 0;
u8 ctr_stream_block[0x10];
aes_setkey_enc(&aes, meta_info.key, 128);
aes_crypt_ctr(&aes, metadata_headers_size, &ctr_nc_off, meta_info.iv, ctr_stream_block, metadata_headers.get(), metadata_headers.get());
@@ -1243,7 +1242,7 @@ bool SELFDecrypter::DecryptData()
if (meta_shdr[i].encrypted == 3)
{
if ((meta_shdr[i].key_idx <= meta_hdr.key_count - 1) && (meta_shdr[i].iv_idx <= meta_hdr.key_count))
data_buf_length += ::narrow<u32>(meta_shdr[i].data_size, HERE);
data_buf_length += ::narrow<u32>(meta_shdr[i].data_size);
}
}
@@ -1256,7 +1255,7 @@ bool SELFDecrypter::DecryptData()
// Parse the metadata section headers to find the offsets of encrypted data.
for (unsigned int i = 0; i < meta_hdr.section_count; i++)
{
size_t ctr_nc_off = 0;
usz ctr_nc_off = 0;
u8 ctr_stream_block[0x10];
u8 data_key[0x10];
u8 data_iv[0x10];
@@ -1289,7 +1288,7 @@ bool SELFDecrypter::DecryptData()
memcpy(data_buf.get() + data_buf_offset, buf.get(), meta_shdr[i].data_size);
// Advance the buffer's offset.
data_buf_offset += ::narrow<u32>(meta_shdr[i].data_size, HERE);
data_buf_offset += ::narrow<u32>(meta_shdr[i].data_size);
}
}
}
@@ -1488,7 +1487,7 @@ bool verify_npdrm_self_headers(const fs::file& self, u8* klic_key)
return true;
}
v128 get_default_self_klic()
u128 get_default_self_klic()
{
return std::bit_cast<v128>(NP_KLIC_FREE);
return std::bit_cast<u128>(NP_KLIC_FREE);
}
+4 -5
View File
@@ -1,9 +1,9 @@
#pragma once
#pragma once
#include "key_vault.h"
#include "zlib.h"
#include "Utilities/types.h"
#include "util/types.hpp"
#include "Utilities/File.h"
#include "util/logs.hpp"
@@ -489,7 +489,7 @@ private:
}
// Advance the data buffer offset by data size.
data_buf_offset += ::narrow<u32>(meta_shdr[i].data_size, HERE);
data_buf_offset += ::narrow<u32>(meta_shdr[i].data_size);
}
}
@@ -509,5 +509,4 @@ private:
fs::file decrypt_self(fs::file elf_or_self, u8* klic_key = nullptr, SelfAdditionalInfo* additional_info = nullptr);
bool verify_npdrm_self_headers(const fs::file& self, u8* klic_key = nullptr);
union v128;
v128 get_default_self_klic();
u128 get_default_self_klic();
+2
View File
@@ -3,6 +3,8 @@
// http://www.gnu.org/licenses/gpl-3.0.txt
#include "utils.h"
#include "aes.h"
#include "sha1.h"
#include <cstring>
#include <stdio.h>
#include <time.h>
+2 -6
View File
@@ -1,16 +1,12 @@
#pragma once
#pragma once
// Copyright (C) 2014 Hykem <hykem@hotmail.com>
// Licensed under the terms of the GNU GPL, version 3
// http://www.gnu.org/licenses/gpl-3.0.txt
#include "../../Utilities/types.h"
#include "util/types.hpp"
#include <stdlib.h>
#include "aes.h"
#include "sha1.h"
#include "lz.h"
#include "ec.h"
enum { CRYPTO_MAX_PATH = 4096 };
+4 -2
View File
@@ -1,4 +1,4 @@
#include "stdafx.h"
#include "stdafx.h"
#include "OpenALBackend.h"
@@ -14,10 +14,12 @@ LOG_CHANNEL(OpenAL);
OpenALBackend::OpenALBackend()
: AudioBackend()
{
ALCint attribs[] = {ALC_FREQUENCY, DEFAULT_AUDIO_SAMPLING_RATE, 0, 0};
ALCdevice* m_device = alcOpenDevice(nullptr);
checkForAlcError("alcOpenDevice");
ALCcontext* m_context = alcCreateContext(m_device, nullptr);
ALCcontext* m_context = alcCreateContext(m_device, attribs);
checkForAlcError("alcCreateContext");
alcMakeContextCurrent(m_context);
+1 -1
View File
@@ -1,4 +1,4 @@
#pragma once
#pragma once
#include "Emu/Audio/AudioBackend.h"
#include "3rdparty/OpenAL/include/alext.h"
+1 -1
View File
@@ -1,4 +1,4 @@
#ifndef HAVE_ALSA
#ifndef HAVE_ALSA
#error "ALSA support disabled but still being built."
#endif
+1 -1
View File
@@ -1,4 +1,4 @@
#include "stdafx.h"
#include "stdafx.h"
#include "AudioBackend.h"
#include "Emu/system_config.h"
+4 -3
View File
@@ -1,6 +1,7 @@
#pragma once
#pragma once
#include "Utilities/types.h"
#include "util/types.hpp"
#include "Utilities/StrFmt.h"
enum : u32
{
@@ -101,7 +102,7 @@ public:
u32 get_sample_size() const;
u32 get_channels() const;
bool get_convert_to_u16() const;
bool has_capability(u32 cap) const;
+3 -2
View File
@@ -1,4 +1,4 @@
#include "stdafx.h"
#include "stdafx.h"
#include "AudioDumper.h"
#include "Utilities/date_time.h"
@@ -33,7 +33,8 @@ void AudioDumper::WriteData(const void* buffer, u32 size)
{
if (GetCh())
{
verify(HERE), size, m_output.write(buffer, size) == size;
ensure(size);
ensure(m_output.write(buffer, size) == size);
m_header.Size += size;
m_header.RIFF.Size += size;
}
+1 -1
View File
@@ -1,6 +1,6 @@
#pragma once
#include "Utilities/types.h"
#include "util/types.hpp"
#include "Utilities/File.h"
struct WAVHeader
+1 -1
View File
@@ -1,4 +1,4 @@
#ifndef HAVE_FAUDIO
#ifndef HAVE_FAUDIO
#error "FAudio support disabled but still being built."
#endif
+1 -1
View File
@@ -1,4 +1,4 @@
#pragma once
#pragma once
#include "Emu/Audio/AudioBackend.h"
+1 -1
View File
@@ -1,4 +1,4 @@
#ifndef HAVE_PULSE
#ifndef HAVE_PULSE
#error "PulseAudio support disabled but still being built."
#endif
+2 -1
View File
@@ -1,7 +1,8 @@
#ifndef _WIN32
#ifndef _WIN32
#error "XAudio2 can only be built on Windows."
#endif
#include <algorithm>
#include "util/logs.hpp"
#include "Utilities/StrFmt.h"
#include "Emu/System.h"
+1 -1
View File
@@ -1,4 +1,4 @@
#pragma once
#pragma once
#ifndef _WIN32
#error "XAudio2 can only be built on Windows."
+37 -8
View File
@@ -33,17 +33,18 @@ target_include_directories(rpcs3_emu
# Utilities
target_sources(rpcs3_emu PRIVATE
../util/atomic.cpp
../util/atomic2.cpp
../util/shared_cptr.cpp
../util/fixed_typemap.cpp
../util/logs.cpp
../util/yaml.cpp
../util/cereal.cpp
../util/vm_native.cpp
../util/dyn_lib.cpp
../util/sysinfo.cpp
../util/cpu_stats.cpp
../../Utilities/bin_patch.cpp
../../Utilities/cheat_info.cpp
../../Utilities/cond.cpp
../../Utilities/Config.cpp
../../Utilities/dynamic_library.cpp
../../Utilities/File.cpp
../../Utilities/JIT.cpp
../../Utilities/LUrlParser.cpp
@@ -51,10 +52,8 @@ target_sources(rpcs3_emu PRIVATE
../../Utilities/rXml.cpp
../../Utilities/sema.cpp
../../Utilities/StrFmt.cpp
../../Utilities/sysinfo.cpp
../../Utilities/Thread.cpp
../../Utilities/version.cpp
../../Utilities/VirtualMemory.cpp
)
target_include_directories(rpcs3_emu PUBLIC "${CMAKE_SOURCE_DIR}")
@@ -76,6 +75,11 @@ else()
set_source_files_properties("../util/yaml.cpp" PROPERTIES COMPILE_FLAGS -fexceptions)
endif()
if (MSVC)
set_source_files_properties("../util/cereal.cpp" PROPERTIES COMPILE_FLAGS /GR)
else()
set_source_files_properties("../util/cereal.cpp" PROPERTIES COMPILE_FLAGS -frtti)
endif()
# Crypto
target_sources(rpcs3_emu PRIVATE
@@ -124,9 +128,12 @@ if(USE_PULSE AND PULSE_FOUND)
target_link_libraries(rpcs3_emu PUBLIC 3rdparty::pulse)
endif()
if(USE_FAUDIO AND SDL2_FOUND AND NOT SDL2_VERSION VERSION_LESS 2.0.9)
target_sources(rpcs3_emu PRIVATE Audio/FAudio/FAudioBackend.cpp)
target_link_libraries(rpcs3_emu PUBLIC 3rdparty::faudio)
if(USE_FAUDIO)
find_package(SDL2)
if(SDL2_FOUND AND NOT SDL2_VERSION VERSION_LESS 2.0.9)
target_sources(rpcs3_emu PRIVATE Audio/FAudio/FAudioBackend.cpp)
target_link_libraries(rpcs3_emu PUBLIC 3rdparty::faudio)
endif()
endif()
if(WIN32)
@@ -360,11 +367,13 @@ target_sources(rpcs3_emu PRIVATE
Io/usb_device.cpp
Io/Skylander.cpp
Io/GHLtar.cpp
Io/Buzz.cpp
)
# Np
target_sources(rpcs3_emu PRIVATE
NP/fb_helpers.cpp
NP/np_contexts.cpp
NP/np_handler.cpp
NP/signaling_handler.cpp
NP/np_structs_extra.cpp
@@ -391,11 +400,14 @@ target_sources(rpcs3_emu PRIVATE
RSX/RSXTexture.cpp
RSX/RSXThread.cpp
RSX/rsx_utils.cpp
RSX/RSXDisAsm.cpp
RSX/Common/BufferUtils.cpp
RSX/Common/FragmentProgramDecompiler.cpp
RSX/Common/GLSLCommon.cpp
RSX/Common/ProgramStateCache.cpp
RSX/Common/surface_store.cpp
RSX/Common/TextureUtils.cpp
RSX/Common/texture_cache.cpp
RSX/Common/VertexProgramDecompiler.cpp
RSX/Null/NullGSRender.cpp
RSX/Overlays/overlay_animation.cpp
@@ -421,17 +433,32 @@ target_sources(rpcs3_emu PRIVATE
RSX/GL/GLFragmentProgram.cpp
RSX/GL/GLGSRender.cpp
RSX/GL/GLHelpers.cpp
RSX/GL/GLPipelineCompiler.cpp
RSX/GL/GLPresent.cpp
RSX/GL/GLRenderTargets.cpp
RSX/GL/GLShaderInterpreter.cpp
RSX/GL/GLTexture.cpp
RSX/GL/GLVertexBuffers.cpp
RSX/GL/GLVertexProgram.cpp
RSX/GL/GLTextureCache.cpp
RSX/GL/OpenGL.cpp
)
if(TARGET 3rdparty_vulkan)
target_sources(rpcs3_emu PRIVATE
RSX/VK/vkutils/barriers.cpp
RSX/VK/vkutils/buffer_object.cpp
RSX/VK/vkutils/chip_class.cpp
RSX/VK/vkutils/commands.cpp
RSX/VK/vkutils/data_heap.cpp
RSX/VK/vkutils/image.cpp
RSX/VK/vkutils/image_helpers.cpp
RSX/VK/vkutils/scratch.cpp
RSX/VK/vkutils/sync.cpp
RSX/VK/vkutils/memory.cpp
RSX/VK/vkutils/device.cpp
RSX/VK/vkutils/sampler.cpp
RSX/VK/vkutils/shared.cpp
RSX/VK/VKCommandStream.cpp
RSX/VK/VKCommonDecompiler.cpp
RSX/VK/VKDMA.cpp
@@ -442,6 +469,7 @@ if(TARGET 3rdparty_vulkan)
RSX/VK/VKGSRender.cpp
RSX/VK/VKHelpers.cpp
RSX/VK/VKMemAlloc.cpp
RSX/VK/VKPipelineCompiler.cpp
RSX/VK/VKPresent.cpp
RSX/VK/VKProgramPipeline.cpp
RSX/VK/VKQueryPool.cpp
@@ -452,6 +480,7 @@ if(TARGET 3rdparty_vulkan)
RSX/VK/VKTexture.cpp
RSX/VK/VKVertexBuffers.cpp
RSX/VK/VKVertexProgram.cpp
RSX/VK/VKTextureCache.cpp
)
endif()
+58 -29
View File
@@ -1,60 +1,85 @@
#pragma once
#include <string>
#include <limits>
#include "Utilities/StrFmt.h"
enum CPUDisAsmMode
enum class cpu_disasm_mode
{
CPUDisAsm_DumpMode,
CPUDisAsm_InterpreterMode,
//CPUDisAsm_NormalMode,
CPUDisAsm_CompilerElfMode,
dump,
interpreter,
normal,
compiler_elf,
list, // RSX exclusive
};
class cpu_thread;
class CPUDisAsm
{
protected:
const CPUDisAsmMode m_mode;
const cpu_disasm_mode m_mode;
const std::add_pointer_t<const u8> m_offset;
const std::add_pointer_t<const cpu_thread> m_cpu;
u32 m_op = 0;
virtual void Write(const std::string& value)
void Write(const std::string& value)
{
switch(m_mode)
switch (m_mode)
{
case CPUDisAsm_DumpMode:
case cpu_disasm_mode::dump:
{
last_opcode = fmt::format("\t%08x:\t%02x %02x %02x %02x\t%s\n", dump_pc,
offset[dump_pc],
offset[dump_pc + 1],
offset[dump_pc + 2],
offset[dump_pc + 3], value);
break;
static_cast<u8>(m_op >> 24),
static_cast<u8>(m_op >> 16),
static_cast<u8>(m_op >> 8),
static_cast<u8>(m_op >> 0), value);
break;
}
case CPUDisAsm_InterpreterMode:
case cpu_disasm_mode::interpreter:
{
last_opcode = fmt::format("[%08x] %02x %02x %02x %02x: %s", dump_pc,
offset[dump_pc],
offset[dump_pc + 1],
offset[dump_pc + 2],
offset[dump_pc + 3], value);
break;
static_cast<u8>(m_op >> 24),
static_cast<u8>(m_op >> 16),
static_cast<u8>(m_op >> 8),
static_cast<u8>(m_op >> 0), value);
break;
}
case CPUDisAsm_CompilerElfMode:
last_opcode = value + "\n";
break;
case cpu_disasm_mode::compiler_elf:
{
last_opcode = value + '\n';
break;
}
case cpu_disasm_mode::normal:
{
last_opcode = value;
break;
}
default: fmt::throw_exception("Unreachable");
}
}
public:
std::string last_opcode;
u32 dump_pc;
const u8* offset;
template <typename T, std::enable_if_t<std::is_base_of_v<CPUDisAsm, T>, int> = 0>
static T copy_and_change_mode(const T& dis, cpu_disasm_mode mode)
{
return T{mode, dis.m_offset, dis.m_cpu};
}
protected:
CPUDisAsm(CPUDisAsmMode mode)
CPUDisAsm(cpu_disasm_mode mode, const u8* offset, const cpu_thread* cpu = nullptr)
: m_mode(mode)
, offset(0)
, m_offset(offset)
, m_cpu(cpu)
{
}
virtual u32 DisAsmBranchTarget(const s32 imm) = 0;
virtual u32 DisAsmBranchTarget(const s32 imm) { return 0; };
// TODO: Add builtin fmt helpper for best performance
template <typename T, std::enable_if_t<std::is_integral_v<T>, int> = 0>
@@ -79,9 +104,13 @@ protected:
return fmt::format("%s%s", v < 0 ? "-" : "", av);
}
static std::string FixOp(std::string op)
std::string FixOp(std::string op) const
{
op.resize(std::max<std::size_t>(op.length(), 10), ' ');
if (m_mode != cpu_disasm_mode::normal)
{
op.resize(std::max<usz>(op.length(), 10), ' ');
}
return op;
}
+359 -232
View File
@@ -1,4 +1,4 @@
#include "stdafx.h"
#include "stdafx.h"
#include "CPUThread.h"
#include "Emu/System.h"
@@ -8,13 +8,17 @@
#include "Emu/GDB.h"
#include "Emu/Cell/PPUThread.h"
#include "Emu/Cell/SPUThread.h"
#include "Emu/RSX/RSXThread.h"
#include "Emu/perf_meter.hpp"
#include "util/asm.hpp"
#include <thread>
#include <unordered_map>
#include <numeric>
#include <map>
#include <immintrin.h>
#include <emmintrin.h>
DECLARE(cpu_thread::g_threads_created){0};
DECLARE(cpu_thread::g_threads_deleted){0};
DECLARE(cpu_thread::g_suspend_counter){0};
@@ -22,7 +26,10 @@ DECLARE(cpu_thread::g_suspend_counter){0};
LOG_CHANNEL(profiler);
LOG_CHANNEL(sys_log, "SYS");
static thread_local u64 s_tls_thread_slot = -1;
static thread_local u32 s_tls_thread_slot = -1;
// Suspend counter stamp
static thread_local u64 s_tls_sctr = -1;
extern thread_local void(*g_tls_log_control)(const char* fmt, u64 progress);
@@ -43,7 +50,6 @@ void fmt_class_string<cpu_flag>::format(std::string& out, u64 arg)
case cpu_flag::signal: return "sig";
case cpu_flag::memory: return "mem";
case cpu_flag::dbg_global_pause: return "G-PAUSE";
case cpu_flag::dbg_global_stop: return "G-EXIT";
case cpu_flag::dbg_pause: return "PAUSE";
case cpu_flag::dbg_step: return "STEP";
case cpu_flag::__bitset_enum_max: break;
@@ -179,7 +185,7 @@ struct cpu_prof
if (threads.empty())
{
// Wait for messages if no work (don't waste CPU)
registered.wait();
thread_ctrl::wait_on(registered, nullptr);
continue;
}
@@ -248,39 +254,43 @@ using cpu_profiler = named_thread<cpu_prof>;
thread_local cpu_thread* g_tls_current_cpu_thread = nullptr;
struct cpu_counter
// Total number of CPU threads
static atomic_t<u64, 64> s_cpu_counter{0};
// List of posted tasks for suspend_all
//static atomic_t<cpu_thread::suspend_work*> s_cpu_work[128]{};
// Linked list of pushed tasks for suspend_all
static atomic_t<cpu_thread::suspend_work*> s_pushed{};
// Lock for suspend_all operations
static shared_mutex s_cpu_lock;
// Bit allocator for threads which need to be suspended
static atomic_t<u128> s_cpu_bits{};
// List of active threads which need to be suspended
static atomic_t<cpu_thread*> s_cpu_list[128]{};
namespace cpu_counter
{
// For synchronizing suspend_all operation
alignas(64) shared_mutex cpu_suspend_lock;
// Workload linked list
alignas(64) atomic_t<cpu_thread::suspend_work*> cpu_suspend_work{};
// Semaphore for global thread array (global counter)
alignas(64) atomic_t<u32> cpu_array_sema{0};
// Semaphore subdivision for each array slot (64 x N in total)
alignas(64) atomic_t<u64> cpu_array_bits[3]{};
// Copy of array bits for internal use
alignas(64) u64 cpu_copy_bits[3]{};
// All registered threads
atomic_t<cpu_thread*> cpu_array[sizeof(cpu_array_bits) * 8]{};
u64 add(cpu_thread* _this, bool restore = false) noexcept
void add(cpu_thread* _this) noexcept
{
u64 array_slot = -1;
if (!restore && !cpu_array_sema.try_inc(sizeof(cpu_counter::cpu_array_bits) * 8))
switch (_this->id_type())
{
sys_log.fatal("Too many threads.");
return array_slot;
case 1:
case 2:
break;
default: return;
}
for (u32 i = 0;; i = (i + 1) % ::size32(cpu_array_bits))
std::lock_guard lock(s_cpu_lock);
u32 id = -1;
for (u64 i = 0;; i++)
{
const auto [bits, ok] = cpu_array_bits[i].fetch_op([](u64& bits) -> u64
const auto [bits, ok] = s_cpu_bits.fetch_op([](u128& bits)
{
if (~bits) [[likely]]
{
@@ -295,95 +305,99 @@ struct cpu_counter
if (ok) [[likely]]
{
// Get actual slot number
array_slot = i * 64 + std::countr_one(bits);
id = utils::ctz128(~bits);
// Register thread
if (cpu_array[array_slot].compare_and_swap_test(nullptr, _this)) [[likely]]
if (s_cpu_list[id].compare_and_swap_test(nullptr, _this)) [[likely]]
{
break;
}
sys_log.fatal("Unexpected slot registration failure (%u).", array_slot);
cpu_array_bits[array_slot / 64] &= ~(1ull << (array_slot % 64));
sys_log.fatal("Unexpected slot registration failure (%u).", id);
id = -1;
continue;
}
if (i > 50)
{
sys_log.fatal("Too many threads.");
return;
}
busy_wait(300);
}
if (!restore)
{
// First time (thread created)
_this->state += cpu_flag::wait;
cpu_suspend_lock.lock_unlock();
}
return array_slot;
s_tls_thread_slot = id;
}
void remove(cpu_thread* _this, u64 slot) noexcept
static void remove_cpu_bit(u32 bit)
{
// Unregister and wait if necessary
_this->state += cpu_flag::wait;
s_cpu_bits.atomic_op([=](u128& val)
{
val &= ~(u128{1} << (bit % 128));
});
}
std::lock_guard lock(cpu_suspend_lock);
void remove(cpu_thread* _this) noexcept
{
// Return if not registered
const u32 slot = s_tls_thread_slot;
if (!cpu_array[slot].compare_and_swap_test(_this, nullptr))
if (slot == umax)
{
return;
}
if (slot >= std::size(s_cpu_list))
{
sys_log.fatal("Index out of bounds (%u).", slot);
return;
}
// Asynchronous unregister
if (!s_cpu_list[slot].compare_and_swap_test(_this, nullptr))
{
sys_log.fatal("Inconsistency for array slot %u", slot);
return;
}
cpu_array_bits[slot / 64] &= ~(1ull << (slot % 64));
cpu_array_sema--;
remove_cpu_bit(slot);
s_tls_thread_slot = -1;
}
// Remove temporarily
void remove(cpu_thread* _this) noexcept
template <typename F>
u128 for_all_cpu(/*mutable*/ u128 copy, F func) noexcept
{
// Unregister temporarily (called from check_state)
const u64 index = s_tls_thread_slot;
if (index >= std::size(cpu_array))
for (u128 bits = copy; bits; bits &= bits - 1)
{
sys_log.fatal("Index out of bounds (%u).", index);
return;
}
const u32 index = utils::ctz128(bits);
if (cpu_array[index].load() == _this && cpu_array[index].compare_and_swap_test(_this, nullptr))
{
cpu_array_bits[index / 64] &= ~(1ull << (index % 64));
return;
}
sys_log.fatal("Thread not found in cpu_array (%s).", _this->get_name());
}
};
template <bool UseCopy = false, typename F>
void for_all_cpu(F func) noexcept
{
const auto ctr = g_fxo->get<cpu_counter>();
for (u32 i = 0; i < ::size32(ctr->cpu_array_bits); i++)
{
for (u64 bits = (UseCopy ? ctr->cpu_copy_bits[i] : ctr->cpu_array_bits[i].load()); bits; bits &= bits - 1)
{
const u64 index = i * 64 + std::countr_zero(bits);
if (cpu_thread* cpu = ctr->cpu_array[index].load())
if (cpu_thread* cpu = s_cpu_list[index].load())
{
if constexpr (std::is_invocable_v<F, cpu_thread*, u64>)
if constexpr (std::is_invocable_v<F, cpu_thread*, u32>)
{
func(cpu, index);
if (!func(cpu, index))
copy &= ~(u128{1} << index);
continue;
}
if constexpr (std::is_invocable_v<F, cpu_thread*>)
{
func(cpu);
if (!func(cpu))
copy &= ~(u128{1} << index);
continue;
}
sys_log.fatal("cpu_counter::for_all_cpu: bad callback");
}
else
{
copy &= ~(u128{1} << index);
}
}
return copy;
}
}
@@ -415,10 +429,15 @@ void cpu_thread::operator()()
}
}
while (!g_fxo->get<cpu_counter>() && !g_fxo->get<cpu_profiler>())
while (!g_fxo->get<cpu_profiler>())
{
if (Emu.IsStopped())
{
return;
}
// Can we have a little race, right? First thread is started concurrently with g_fxo->init()
std::this_thread::sleep_for(1ms);
thread_ctrl::wait_for(1000);
}
switch (id_type())
@@ -441,14 +460,9 @@ void cpu_thread::operator()()
}
// Register thread in g_cpu_array
s_tls_thread_slot = g_fxo->get<cpu_counter>()->add(this);
s_cpu_counter++;
if (s_tls_thread_slot == umax)
{
return;
}
atomic_storage_futex::set_notify_callback([](const void*, u64 progress)
atomic_wait_engine::set_notify_callback([](const void*, u64 progress)
{
static thread_local bool wait_set = false;
@@ -466,7 +480,7 @@ void cpu_thread::operator()()
if (progress == umax && std::exchange(wait_set, false))
{
// Operation finished: need to clean wait flag
verify(HERE), !_cpu->check_state();
ensure(!_cpu->check_state());
return;
}
});
@@ -486,22 +500,16 @@ void cpu_thread::operator()()
if (progress == umax && std::exchange(wait_set, false))
{
verify(HERE), !_cpu->check_state();
ensure(!_cpu->check_state());
return;
}
};
static thread_local struct thread_cleanup_t
{
cpu_thread* _this;
cpu_thread* _this = nullptr;
std::string name;
thread_cleanup_t(cpu_thread* _this)
: _this(_this)
, name(thread_ctrl::get_name())
{
}
void cleanup()
{
if (_this == nullptr)
@@ -514,11 +522,22 @@ void cpu_thread::operator()()
ptr->compare_and_swap(_this, nullptr);
}
atomic_storage_futex::set_notify_callback(nullptr);
atomic_wait_engine::set_notify_callback(nullptr);
g_tls_log_control = [](const char*, u64){};
g_fxo->get<cpu_counter>()->remove(_this, s_tls_thread_slot);
if (s_tls_thread_slot != umax)
{
cpu_counter::remove(_this);
}
s_cpu_lock.lock_unlock();
s_cpu_counter--;
g_tls_current_cpu_thread = nullptr;
g_threads_deleted++;
_this = nullptr;
}
@@ -527,17 +546,27 @@ void cpu_thread::operator()()
{
if (_this)
{
sys_log.warning("CPU Thread '%s' terminated abnormally:\n%s", name, _this->dump_all());
sys_log.warning("CPU Thread '%s' terminated abnormally!", name);
cleanup();
}
}
} cleanup{this};
} cleanup;
cleanup._this = this;
cleanup.name = thread_ctrl::get_name();
// Check thread status
while (!(state & (cpu_flag::exit + cpu_flag::dbg_global_stop)) && thread_ctrl::state() != thread_state::aborting)
while (!(state & cpu_flag::exit) && thread_ctrl::state() != thread_state::aborting)
{
// Check stop status
if (!(state & cpu_flag::stop))
const auto state0 = +state;
if (is_stopped(state0 - cpu_flag::stop))
{
break;
}
if (!(state0 & cpu_flag::stop))
{
cpu_task();
@@ -549,7 +578,7 @@ void cpu_thread::operator()()
continue;
}
thread_ctrl::wait();
thread_ctrl::wait_on(state, state0);
if (state & cpu_flag::ret && state.test_and_reset(cpu_flag::ret))
{
@@ -563,8 +592,6 @@ void cpu_thread::operator()()
cpu_thread::~cpu_thread()
{
vm::cleanup_unlock(*this);
g_threads_deleted++;
}
cpu_thread::cpu_thread(u32 id)
@@ -573,29 +600,55 @@ cpu_thread::cpu_thread(u32 id)
g_threads_created++;
}
void cpu_thread::cpu_wait(bs_t<cpu_flag> old)
{
thread_ctrl::wait_on(state, old);
}
bool cpu_thread::check_state() noexcept
{
if (state & cpu_flag::dbg_pause)
{
g_fxo->get<gdb_server>()->pause_from(this);
}
bool cpu_sleep_called = false;
bool cpu_can_stop = true;
bool escape, retval;
u64 susp_ctr = -1;
while (true)
{
// Process all flags in a single atomic op
bs_t<cpu_flag> state1;
const auto state0 = state.fetch_op([&](bs_t<cpu_flag>& flags)
{
bool store = false;
if (flags & cpu_flag::pause && !(flags & cpu_flag::wait))
if (flags & cpu_flag::pause && s_tls_thread_slot != umax)
{
// Save value before state is saved and cpu_flag::wait is observed
susp_ctr = g_suspend_counter;
if (s_tls_sctr == umax)
{
u64 ctr = g_suspend_counter;
if (flags & cpu_flag::wait)
{
if ((ctr & 3) == 2)
{
s_tls_sctr = ctr;
}
}
else
{
s_tls_sctr = ctr;
}
}
}
else
{
// Cleanup after asynchronous remove()
if (flags & cpu_flag::pause && s_tls_thread_slot == umax)
{
flags -= cpu_flag::pause;
store = true;
}
s_tls_sctr = -1;
}
if (flags & cpu_flag::temp) [[unlikely]]
@@ -607,18 +660,38 @@ bool cpu_thread::check_state() noexcept
store = true;
}
if (flags & cpu_flag::signal)
if (cpu_can_stop && flags & cpu_flag::signal)
{
flags -= cpu_flag::signal;
cpu_sleep_called = false;
store = true;
}
// Atomically clean wait flag and escape
if (!(flags & (cpu_flag::exit + cpu_flag::dbg_global_stop + cpu_flag::ret + cpu_flag::stop)))
// Can't process dbg_step if we only paused temporarily
if (cpu_can_stop && flags & cpu_flag::dbg_step)
{
// Check pause flags which hold thread inside check_state
if (flags & (cpu_flag::pause + cpu_flag::suspend + cpu_flag::dbg_global_pause + cpu_flag::dbg_pause + cpu_flag::memory))
if (u32 pc = get_pc(), *pc2 = get_pc2(); pc != umax && pc2)
{
if (pc != *pc2)
{
flags -= cpu_flag::dbg_step;
flags += cpu_flag::dbg_pause;
store = true;
}
}
else
{
// Can't test, ignore flag
flags -= cpu_flag::dbg_step;
store = true;
}
}
// Atomically clean wait flag and escape
if (!(flags & (cpu_flag::exit + cpu_flag::ret + cpu_flag::stop)))
{
// Check pause flags which hold thread inside check_state (ignore suspend on cpu_flag::temp)
if (flags & (cpu_flag::pause + cpu_flag::dbg_global_pause + cpu_flag::dbg_pause + cpu_flag::memory + (cpu_can_stop ? cpu_flag::suspend : cpu_flag::pause)))
{
if (!(flags & cpu_flag::wait))
{
@@ -627,6 +700,7 @@ bool cpu_thread::check_state() noexcept
}
escape = false;
state1 = flags;
return store;
}
@@ -649,50 +723,50 @@ bool cpu_thread::check_state() noexcept
retval = cpu_can_stop;
}
if (cpu_can_stop && flags & cpu_flag::dbg_step)
{
// Can't process dbg_step if we only paused temporarily
flags += cpu_flag::dbg_pause;
flags -= cpu_flag::dbg_step;
store = true;
}
escape = true;
state1 = flags;
return store;
}).first;
if (escape)
{
if (s_tls_thread_slot == umax)
if (s_tls_thread_slot == umax && !retval)
{
// Restore thread in the suspend list
std::lock_guard lock(g_fxo->get<cpu_counter>()->cpu_suspend_lock);
s_tls_thread_slot = g_fxo->get<cpu_counter>()->add(this, true);
cpu_counter::add(this);
}
verify(HERE), cpu_can_stop || !retval;
if (retval)
{
cpu_on_stop();
}
ensure(cpu_can_stop || !retval);
return retval;
}
if (!cpu_sleep_called && state0 & cpu_flag::suspend)
if (cpu_can_stop && !cpu_sleep_called && state0 & cpu_flag::suspend)
{
cpu_sleep();
cpu_sleep_called = true;
if (cpu_can_stop && s_tls_thread_slot != umax)
if (s_tls_thread_slot != umax)
{
// Exclude inactive threads from the suspend list (optimization)
std::lock_guard lock(g_fxo->get<cpu_counter>()->cpu_suspend_lock);
g_fxo->get<cpu_counter>()->remove(this);
s_tls_thread_slot = -1;
cpu_counter::remove(this);
}
continue;
}
if (state0 & (cpu_flag::suspend + cpu_flag::dbg_global_pause + cpu_flag::dbg_pause))
if (state0 & ((cpu_can_stop ? cpu_flag::suspend : cpu_flag::dbg_pause) + cpu_flag::dbg_global_pause + cpu_flag::dbg_pause))
{
thread_ctrl::wait();
if (state0 & cpu_flag::dbg_pause)
{
g_fxo->get<gdb_server>()->pause_from(this);
}
cpu_wait(state1);
}
else
{
@@ -705,38 +779,29 @@ bool cpu_thread::check_state() noexcept
// If only cpu_flag::pause was set, wait on suspend counter instead
if (state0 & cpu_flag::pause)
{
if (state0 & cpu_flag::wait)
{
// Otherwise, value must be reliable because cpu_flag::wait hasn't been observed yet
susp_ctr = -1;
}
// Hard way
if (susp_ctr == umax) [[unlikely]]
{
g_fxo->get<cpu_counter>()->cpu_suspend_lock.lock_unlock();
continue;
}
// Wait for current suspend_all operation
for (u64 i = 0;; i++)
{
if (i < 20)
u64 ctr = g_suspend_counter;
if (ctr >> 2 == s_tls_sctr >> 2 && state & cpu_flag::pause)
{
busy_wait(300);
if (i < 20 || ctr & 1)
{
busy_wait(300);
}
else
{
// TODO: fix the workaround
g_suspend_counter.wait(ctr, -4, atomic_wait_timeout{100});
}
}
else
{
g_suspend_counter.wait(susp_ctr);
}
if (!(state & cpu_flag::pause))
{
s_tls_sctr = -1;
break;
}
}
susp_ctr = -1;
}
}
}
@@ -753,14 +818,17 @@ void cpu_thread::notify()
{
thread_ctrl::notify(*static_cast<named_thread<spu_thread>*>(this));
}
else
else if (id_type() != 0x55)
{
fmt::throw_exception("Invalid cpu_thread type" HERE);
fmt::throw_exception("Invalid cpu_thread type");
}
}
void cpu_thread::abort()
{
state += cpu_flag::exit;
state.notify_one(cpu_flag::exit);
// Downcast to correct type
if (id_type() == 1)
{
@@ -772,7 +840,7 @@ void cpu_thread::abort()
}
else
{
fmt::throw_exception("Invalid cpu_thread type" HERE);
fmt::throw_exception("Invalid cpu_thread type");
}
}
@@ -789,13 +857,71 @@ std::string cpu_thread::get_name() const
}
else
{
fmt::throw_exception("Invalid cpu_thread type" HERE);
fmt::throw_exception("Invalid cpu_thread type");
}
}
u32 cpu_thread::get_pc() const
{
const u32* pc = nullptr;
switch (id_type())
{
case 1:
{
pc = &static_cast<const ppu_thread*>(this)->cia;
break;
}
case 2:
{
pc = &static_cast<const spu_thread*>(this)->pc;
break;
}
case 0x55:
{
const auto ctrl = static_cast<const rsx::thread*>(this)->ctrl;
return ctrl ? ctrl->get : UINT32_MAX;
}
default: break;
}
return pc ? atomic_storage<u32>::load(*pc) : UINT32_MAX;
}
u32* cpu_thread::get_pc2()
{
switch (id_type())
{
case 1:
{
return &static_cast<ppu_thread*>(this)->dbg_step_pc;
}
case 2:
{
return &static_cast<spu_thread*>(this)->dbg_step_pc;
}
case 0x55:
{
const auto ctrl = static_cast<rsx::thread*>(this)->ctrl;
return ctrl ? &static_cast<rsx::thread*>(this)->dbg_step_pc : nullptr;
}
default: break;
}
return nullptr;
}
std::string cpu_thread::dump_all() const
{
return {};
std::string ret = cpu_thread::dump_misc();
ret += '\n';
ret += dump_misc();
ret += '\n';
ret += dump_regs();
ret += '\n';
ret += dump_callstack();
return ret;
}
std::string cpu_thread::dump_regs() const
@@ -805,7 +931,16 @@ std::string cpu_thread::dump_regs() const
std::string cpu_thread::dump_callstack() const
{
return {};
std::string ret;
fmt::append(ret, "Call stack:\n=========\n0x%08x (0x0) called\n", get_pc());
for (const auto& sp : dump_callstack_list())
{
fmt::append(ret, "> from 0x%08x (sp=0x%08x)\n", sp.first, sp.second);
}
return ret;
}
std::vector<std::pair<u32, u32>> cpu_thread::dump_callstack_list() const
@@ -815,24 +950,18 @@ std::vector<std::pair<u32, u32>> cpu_thread::dump_callstack_list() const
std::string cpu_thread::dump_misc() const
{
return fmt::format("Type: %s\n" "State: %s\n", typeid(*this).name(), state.load());
return fmt::format("Type: %s\n" "State: %s\n", id_type() == 1 ? "PPU" : id_type() == 2 ? "SPU" : "CPU", state.load());
}
bool cpu_thread::suspend_work::push(cpu_thread* _this, bool cancel_if_not_suspended) noexcept
bool cpu_thread::suspend_work::push(cpu_thread* _this) noexcept
{
// Can't allow pre-set wait bit (it'd be a problem)
verify(HERE), !_this || !(_this->state & cpu_flag::wait);
// cpu_counter object
const auto ctr = g_fxo->get<cpu_counter>();
// Try to push workload
auto& queue = ctr->cpu_suspend_work;
ensure(!_this || !(_this->state & cpu_flag::wait));
do
{
// Load current head
next = queue.load();
next = s_pushed.load();
if (!next && cancel_if_not_suspended) [[unlikely]]
{
@@ -843,11 +972,11 @@ bool cpu_thread::suspend_work::push(cpu_thread* _this, bool cancel_if_not_suspen
if (!_this && next)
{
// If _this == nullptr, it only works if this is the first workload pushed
ctr->cpu_suspend_lock.lock_unlock();
s_cpu_lock.lock_unlock();
continue;
}
}
while (!queue.compare_and_swap_test(next, this));
while (!s_pushed.compare_and_swap_test(next, this));
if (!next)
{
@@ -855,63 +984,68 @@ bool cpu_thread::suspend_work::push(cpu_thread* _this, bool cancel_if_not_suspen
perf_meter<"SUSPEND"_u64> perf0;
// First thread to push the work to the workload list pauses all threads and processes it
std::lock_guard lock(ctr->cpu_suspend_lock);
std::lock_guard lock(s_cpu_lock);
u128 copy = s_cpu_bits.load();
// Try to prefetch cpu->state earlier
for_all_cpu([&](cpu_thread* cpu)
copy = cpu_counter::for_all_cpu(copy, [&](cpu_thread* cpu)
{
if (cpu != _this)
{
_m_prefetchw(&cpu->state);
utils::prefetch_write(&cpu->state);
return true;
}
return false;
});
// Copy of thread bits
decltype(ctr->cpu_copy_bits) copy2{};
// Initialization (first increment)
g_suspend_counter += 2;
for (u32 i = 0; i < ::size32(ctr->cpu_copy_bits); i++)
{
copy2[i] = ctr->cpu_copy_bits[i] = ctr->cpu_array_bits[i].load();
}
// Copy snapshot for finalization
u128 copy2 = copy;
for_all_cpu([&](cpu_thread* cpu, u64 index)
copy = cpu_counter::for_all_cpu(copy, [&](cpu_thread* cpu, u32 index)
{
if (cpu == _this || cpu->state.fetch_add(cpu_flag::pause) & cpu_flag::wait)
if (cpu->state.fetch_add(cpu_flag::pause) & cpu_flag::wait)
{
// Clear bits as long as wait flag is set
ctr->cpu_copy_bits[index / 64] &= ~(1ull << (index % 64));
return false;
}
if (cpu == _this)
{
copy2[index / 64] &= ~(1ull << (index % 64));
}
return true;
});
while (true)
while (copy)
{
// Check only CPUs which haven't acknowledged their waiting state yet
for_all_cpu<true>([&](cpu_thread* cpu, u64 index)
copy = cpu_counter::for_all_cpu(copy, [&](cpu_thread* cpu, u32 index)
{
if (cpu->state & cpu_flag::wait)
{
ctr->cpu_copy_bits[index / 64] &= ~(1ull << (index % 64));
return false;
}
return true;
});
if (!std::accumulate(std::begin(ctr->cpu_copy_bits), std::end(ctr->cpu_copy_bits), u64{0}, std::bit_or()))
if (!copy)
{
break;
}
_mm_pause();
utils::pause();
}
// Extract queue and reverse element order (FILO to FIFO) (TODO: maybe leave order as is?)
auto* head = queue.exchange(nullptr);
// Second increment: all threads paused
g_suspend_counter++;
s8 min_prio = head->prio;
s8 max_prio = head->prio;
// Extract queue and reverse element order (FILO to FIFO) (TODO: maybe leave order as is?)
auto* head = s_pushed.exchange(nullptr);
u8 min_prio = head->prio;
u8 max_prio = head->prio;
if (auto* prev = head->next)
{
@@ -925,8 +1059,8 @@ bool cpu_thread::suspend_work::push(cpu_thread* _this, bool cancel_if_not_suspen
head = std::exchange(prev, pre2);
// Fill priority range
min_prio = std::min<s8>(min_prio, head->prio);
max_prio = std::max<s8>(max_prio, head->prio);
min_prio = std::min<u8>(min_prio, head->prio);
max_prio = std::max<u8>(max_prio, head->prio);
}
while (prev);
}
@@ -936,13 +1070,14 @@ bool cpu_thread::suspend_work::push(cpu_thread* _this, bool cancel_if_not_suspen
{
for (u32 i = 0; i < work->prf_size; i++)
{
_m_prefetchw(work->prf_list[0]);
utils::prefetch_write(work->prf_list[0]);
}
}
for_all_cpu<true>([&](cpu_thread* cpu)
cpu_counter::for_all_cpu(copy2, [&](cpu_thread* cpu)
{
_m_prefetchw(&cpu->state);
utils::prefetch_write(&cpu->state);
return true;
});
// Execute all stored workload
@@ -959,25 +1094,22 @@ bool cpu_thread::suspend_work::push(cpu_thread* _this, bool cancel_if_not_suspen
}
}
// Not sure if needed, may be overkill. Some workloads may execute instructions with non-temporal hint.
_mm_sfence();
// Finalization (last increment)
ensure(g_suspend_counter++ & 1);
// Finalization
g_suspend_counter++;
// Exact bitset for flag pause removal
std::memcpy(ctr->cpu_copy_bits, copy2, sizeof(copy2));
for_all_cpu<true>([&](cpu_thread* cpu)
cpu_counter::for_all_cpu(copy2, [&](cpu_thread* cpu)
{
cpu->state -= cpu_flag::pause;
return true;
});
}
else
{
// Seems safe to set pause on self because wait flag hasn't been observed yet
_this->state += cpu_flag::pause + cpu_flag::temp;
s_tls_sctr = g_suspend_counter;
_this->state += cpu_flag::pause + cpu_flag::wait + cpu_flag::temp;
_this->check_state();
s_tls_sctr = -1;
return true;
}
@@ -995,11 +1127,8 @@ void cpu_thread::stop_all() noexcept
}
else
{
std::lock_guard lock(g_fxo->get<cpu_counter>()->cpu_suspend_lock);
auto on_stop = [](u32, cpu_thread& cpu)
{
cpu.state += cpu_flag::dbg_global_stop;
cpu.abort();
};
@@ -1009,15 +1138,13 @@ void cpu_thread::stop_all() noexcept
sys_log.notice("All CPU threads have been signaled.");
while (g_fxo->get<cpu_counter>()->cpu_array_sema)
while (s_cpu_counter)
{
std::this_thread::sleep_for(10ms);
std::this_thread::sleep_for(1ms);
}
sys_log.notice("All CPU threads have been stopped. [+: %u]", +g_threads_created);
std::lock_guard lock(g_fxo->get<cpu_counter>()->cpu_suspend_lock);
g_threads_deleted -= g_threads_created.load();
g_threads_created = 0;
}
@@ -1026,7 +1153,7 @@ void cpu_thread::flush_profilers() noexcept
{
if (!g_fxo->get<cpu_profiler>())
{
profiler.fatal("cpu_thread::flush_profilers() has been called incorrectly." HERE);
profiler.fatal("cpu_thread::flush_profilers() has been called incorrectly.");
return;
}
+69 -17
View File
@@ -1,4 +1,4 @@
#pragma once
#pragma once
#include "../Utilities/Thread.h"
#include "../Utilities/bit_set.h"
@@ -19,13 +19,24 @@ enum class cpu_flag : u32
memory, // Thread must unlock memory mutex
dbg_global_pause, // Emulation paused
dbg_global_stop, // Emulation stopped
dbg_pause, // Thread paused
dbg_step, // Thread forced to pause after one step (one instruction, etc)
__bitset_enum_max
};
// Test stopped state
constexpr bool is_stopped(bs_t<cpu_flag> state)
{
return !!(state & (cpu_flag::stop + cpu_flag::exit));
}
// Test paused state
constexpr bool is_paused(bs_t<cpu_flag> state)
{
return !!(state & (cpu_flag::suspend + cpu_flag::dbg_global_pause + cpu_flag::dbg_pause));
}
class cpu_thread
{
public:
@@ -61,16 +72,25 @@ public:
return false;
}
// Test stopped state
bool is_stopped() const
// Wrappers
static constexpr bool is_stopped(bs_t<cpu_flag> s)
{
return !!(state & (cpu_flag::stop + cpu_flag::exit + cpu_flag::dbg_global_stop));
return ::is_stopped(s);
}
static constexpr bool is_paused(bs_t<cpu_flag> s)
{
return ::is_paused(s);
}
bool is_stopped() const
{
return ::is_stopped(state);
}
// Test paused state
bool is_paused() const
{
return !!(state & (cpu_flag::suspend + cpu_flag::dbg_global_pause + cpu_flag::dbg_pause));
return ::is_paused(state);
}
bool has_pause_flag() const
@@ -84,6 +104,9 @@ public:
return id >> 24;
}
u32 get_pc() const;
u32* get_pc2(); // Last PC before stepping for the debugger (may be null)
void notify();
private:
@@ -120,11 +143,19 @@ public:
// Callback for cpu_flag::ret
virtual void cpu_return() {}
// Callback for thread_ctrl::wait or RSX wait
virtual void cpu_wait(bs_t<cpu_flag> flags);
// Callback for function abortion stats on Emu.Stop()
virtual void cpu_on_stop() {}
// For internal use
struct suspend_work
{
// Task priority
s8 prio;
u8 prio;
bool cancel_if_not_suspended;
bool was_posted;
// Size of prefetch list workload
u32 prf_size;
@@ -140,16 +171,21 @@ public:
suspend_work* next;
// Internal method
bool push(cpu_thread* _this, bool cancel_if_not_suspended = false) noexcept;
bool push(cpu_thread* _this) noexcept;
// Called after suspend_post
void post() noexcept;
};
// Suspend all threads and execute op (may be executed by other thread than caller!)
template <s8 Prio = 0, typename F>
template <u8 Prio = 0, typename F>
static auto suspend_all(cpu_thread* _this, std::initializer_list<void*> hints, F op)
{
constexpr u8 prio = Prio > 3 ? 3 : Prio;
if constexpr (std::is_void_v<std::invoke_result_t<F>>)
{
suspend_work work{Prio, ::size32(hints), hints.begin(), &op, nullptr, [](void* func, void*)
suspend_work work{prio, false, false, ::size32(hints), hints.begin(), &op, nullptr, [](void* func, void*)
{
std::invoke(*static_cast<F*>(func));
}};
@@ -161,7 +197,7 @@ public:
{
std::invoke_result_t<F> result;
suspend_work work{Prio, ::size32(hints), hints.begin(), &op, &result, [](void* func, void* res_buf)
suspend_work work{prio, false, false, ::size32(hints), hints.begin(), &op, &result, [](void* func, void* res_buf)
{
*static_cast<std::invoke_result_t<F>*>(res_buf) = std::invoke(*static_cast<F*>(func));
}};
@@ -171,22 +207,38 @@ public:
}
}
template <u8 Prio = 0, typename F>
static suspend_work suspend_post(cpu_thread* _this, std::initializer_list<void*> hints, F& op)
{
constexpr u8 prio = Prio > 3 ? 3 : Prio;
static_assert(std::is_void_v<std::invoke_result_t<F>>, "cpu_thread::suspend_post only supports void as return type");
return suspend_work{prio, false, true, ::size32(hints), hints.begin(), &op, nullptr, [](void* func, void*)
{
std::invoke(*static_cast<F*>(func));
}};
}
// Push the workload only if threads are being suspended by suspend_all()
template <s8 Prio = 0, typename F>
template <u8 Prio = 0, typename F>
static bool if_suspended(cpu_thread* _this, std::initializer_list<void*> hints, F op)
{
static_assert(std::is_void_v<std::invoke_result_t<F>>, "Unimplemented (must return void)");
constexpr u8 prio = Prio > 3 ? 3 : Prio;
static_assert(std::is_void_v<std::invoke_result_t<F>>, "cpu_thread::if_suspended only supports void as return type");
{
suspend_work work{Prio, ::size32(hints), hints.begin(), &op, nullptr, [](void* func, void*)
suspend_work work{prio, true, false, ::size32(hints), hints.begin(), &op, nullptr, [](void* func, void*)
{
std::invoke(*static_cast<F*>(func));
}};
return work.push(_this, true);
return work.push(_this);
}
}
// Stop all threads with cpu_flag::dbg_global_stop
// Stop all threads with cpu_flag::exit
static void stop_all() noexcept;
// Send signal to the profiler(s) to flush results

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