125 Commits

Author SHA1 Message Date
georgemoralis
86911747bf v0.0.3 - codename salad 2024-03-23 10:05:45 +02:00
georgemoralis
7799211100 removed module 2024-03-23 10:00:38 +02:00
georgemoralis
03e5cd2749 force gitmodule 2024-03-23 09:54:57 +02:00
georgemoralis
4980aa3fd5 pushed v.0.0.3 version - codename salad 2024-03-23 09:43:03 +02:00
georgemoralis
7a42b9df79 moved moduleGenerator to a new repo 2024-03-23 09:29:25 +02:00
georgemoralis
2e931c9f72 More modules (#99)
* added dummy sceAudio lib

* added lseek in file_system

* updated sdl3

* forgot sdl3 in cmake

* cmake is case sensitive in linux

* fixed SDL_CreateWindowWithPosition

* fixed vulkan issues with latest sdl3

* some progress in sceAudio

* improvements in audio

* more sound improvements

* first working sound output , from openorbis sound demo

* updated sdl3 , zlib-ng can now be build with msvc+clangci

* fixed cmake

* fix for audio buffering

* clang format fix

* format fix

* better error handling for sceAudioOutput
2024-03-22 18:12:37 +02:00
georgemoralis
2a03b4d03b Autogen system,user,dialog modules (#98)
* some rework on system_service, user_service

* fixed clang format

* more clang fix

* more clang fix

* added error codes in system service

* some libc functions

* fixed fprintf

* small fix

* linux fix

* error handling in user service

* error codes reorganized
2024-03-14 14:18:16 +02:00
georgemoralis
8c4f386641 made an option for logging to be synced by default instead of async 2024-03-11 14:06:39 +02:00
georgemoralis
02dcf4d45c LLE libc + other fixes part1 (#97)
* app0 folder is absolute

* some improvements on symbols types

* clang format

* missing libs.h

* improved symbols_resolver

* moved config to config folder

* functions to dump import functions

* improved logging output

* option for debugdump and improvements

* Apply suggestions from code review

Co-authored-by: GPUCode <47210458+GPUCode@users.noreply.github.com>

* clang format

---------

Co-authored-by: GPUCode <47210458+GPUCode@users.noreply.github.com>
2024-03-11 13:26:33 +02:00
Jonah
00d401e103 - gui: firmware version display text correction (fw >= 10) 2024-03-08 11:54:30 -07:00
Younes
8ba6d7add0 - pkg extraction: fix a rare issue when there is extra entries with uroot and flat_path_table (this is how it should be handled anyway!) (#96)
- gui:
      - fix crash when switching between List and Grid modes.
      - fix fw display text (it was showing wrong numbers in certain cases)
      - made sfo viewer show numbers in hex.
2024-03-08 14:38:19 +02:00
Jonah
12a8cf5ee9 - Fixed a bug where folders where not created in the correct location which led to missing folders and files (incomplete/wrong extraction) 2024-03-06 00:04:14 -07:00
raziel1000
7e54255d29 - Fixed pkg extraction. 2024-03-02 14:06:10 -07:00
qurious-pixel
58ae9c3ade add window icons (#92) 2024-03-02 18:39:46 +02:00
Younes
f2691d83b8 - Added Play, Pause, Stop and several other UI icons. (#91)
* - Added Play, Pause, Stop and several other UI icons.
- Added a screenshot :3

* update reuse

* reuse again

* screenshot
2024-03-01 10:47:28 +02:00
qurious-pixel
7425cb41a5 linux qt artifact name (#89) 2024-03-01 08:23:02 +02:00
georgemoralis
ffb2a583f9 missing dll in windows-qt ci 2024-03-01 00:11:19 +02:00
georgemoralis
02cbebbf78 file formats and qt (#88)
* added psf file format

* clang format fix

* crypto functions for pkg decryption

* pkg decryption

* initial add of qt gui , not yet usable

* renamed ini for qt gui settings into shadps4qt.ini

* file detection and loader support

* option to build QT qui

* clang format fix

* fixed reuse

* Update src/core/file_format/pkg.cpp

Co-authored-by: GPUCode <47210458+GPUCode@users.noreply.github.com>

* Update src/core/file_format/pkg.cpp

Co-authored-by: GPUCode <47210458+GPUCode@users.noreply.github.com>

* Update src/core/file_format/pkg.cpp

Co-authored-by: GPUCode <47210458+GPUCode@users.noreply.github.com>

* Update src/core/file_format/pkg.cpp

Co-authored-by: GPUCode <47210458+GPUCode@users.noreply.github.com>

* Update src/core/loader.h

Co-authored-by: GPUCode <47210458+GPUCode@users.noreply.github.com>

* Update src/core/loader.cpp

Co-authored-by: GPUCode <47210458+GPUCode@users.noreply.github.com>

* uppercase fix

* clang format fix

* small fixes

* let's try windows qt build ci

* some more fixes for ci

* Update src/core/file_format/pkg.cpp

Co-authored-by: GPUCode <47210458+GPUCode@users.noreply.github.com>

* Update src/core/file_format/pkg.cpp

Co-authored-by: GPUCode <47210458+GPUCode@users.noreply.github.com>

* Update src/core/file_format/pkg.cpp

Co-authored-by: GPUCode <47210458+GPUCode@users.noreply.github.com>

* Update src/core/file_format/pkg.cpp

Co-authored-by: GPUCode <47210458+GPUCode@users.noreply.github.com>

* Update .github/workflows/windows-qt.yml

Co-authored-by: GPUCode <47210458+GPUCode@users.noreply.github.com>

* Update src/core/loader.cpp

Co-authored-by: GPUCode <47210458+GPUCode@users.noreply.github.com>

* Update src/core/file_format/psf.cpp

Co-authored-by: GPUCode <47210458+GPUCode@users.noreply.github.com>

* loader namespace

* Update src/core/loader.cpp

Co-authored-by: GPUCode <47210458+GPUCode@users.noreply.github.com>

* constexpr magic

* linux qt ci by qurious

* fix for linux qt

* Make script executable

* ci fix?

---------

Co-authored-by: raziel1000 <ckraziel@gmail.com>
Co-authored-by: GPUCode <47210458+GPUCode@users.noreply.github.com>
Co-authored-by: GPUCode <geoster3d@gmail.com>
2024-03-01 00:00:35 +02:00
georgemoralis
99d013f612 initialaze submodules properly 2024-02-28 19:01:34 +02:00
georgemoralis
84b0aff35b added cryptoopp and zlib-ng modules 2024-02-28 18:45:51 +02:00
georgemoralis
47e2619b51 update discord submodule 2024-02-28 14:36:44 +02:00
GPUCode
79d6c8a377 common: Rewrite logging based on cut down citra logger (#86)
* common: Rewrite logging based on cut down Citra logger

* code: Misc fixes

* core: Bring back tls handler

* linker: Cleanup

* config: Remove log level

* logging: Enable console output by default

* core: Fix windows build
2024-02-28 00:10:34 +02:00
georgemoralis
b3084646a8 submodules fixes (#87)
* update discord-rpc

* ignore gitmodules on reuse

* imgui not used atm removed
2024-02-27 20:24:47 +02:00
georgemoralis
e40461b0c2 Update README.md
updated build badges , added linux
2024-02-25 20:48:17 +02:00
qurious-pixel
6e1f25d99f Linux CI (#84)
* Linux CI

* misc formatting

* .reuse
2024-02-25 17:20:53 +02:00
georgemoralis
08aba86ca1 Modules generation tool (#81)
* Modules generation tool

* apply clang format to generator

* @whereismyfoodat suggestions

* added reuse headers

* reuse part2

* reuse part3

* reuse part3

* replace with hex_id the unknown functions to avoid compile errors with unknown characters from encode_id

* fixes in generation

* some sample module code from autogen tool

* clang format fix
2024-02-24 22:39:29 +02:00
georgemoralis
d89653551e Merge pull request #83 from GPUCode/main
chore: Make shadps4 REUSE compliant
2024-02-24 09:00:45 +02:00
GPUCode
584b7d2b15 chore: Make shadps4 REUSE compliant 2024-02-23 23:33:43 +02:00
GPUCode
6f4c6ae0bb code: Add clang-format target and CI workflow (#82)
* code: Add clang format target, rules and CI workflow

* code: Run clang format on sources
2024-02-23 22:57:57 +02:00
georgemoralis
32a5ff15bb Merge pull request #80 from shadps4-emu/linux
common: Rework timekeeping with native RDTSC and port to linux
2024-02-23 14:45:05 +02:00
georgemoralis
552d2da17a should work without lib 2024-02-23 14:33:01 +02:00
georgemoralis
b62c44c914 ugly workaround :D 2024-02-23 14:10:44 +02:00
GPUCode
fe43558779 common: Rework timekeeping with native RDTSC and port to linux 2024-02-23 11:30:06 +02:00
georgemoralis
acfa56f6bc Merge pull request #77 from georgemoralis/TLS_works
TLS branch WIP
2024-01-27 19:14:37 +02:00
Stefanos Kornilios Mitsis Poiitidis
a58289a353 Merge branch 'TLS_works' of github.com:georgemoralis/shadPS4 into TLS_works 2024-01-27 17:00:12 +02:00
Stefanos Kornilios Mitsis Poiitidis
6de4736e50 skip over 0x66 prefixes in TLS 2024-01-27 16:59:59 +02:00
georgemoralis
ff43fec76a some fs work for openorbis (WIP) 2024-01-26 18:01:27 +02:00
georgemoralis
57ddf939d4 orbis weird sceVideoOut calls 2024-01-24 14:46:02 +02:00
Stefanos Kornilios Mitsis Poiitidis
724c56d8aa Basic TLS with patching + int 0x80 2024-01-20 14:29:23 +02:00
georgemoralis
af18453950 initial PT_TLS support 2023-11-21 17:27:11 +02:00
georgemoralis
b6d98d4b72 some cleanups 2023-11-21 16:54:10 +02:00
georgemoralis
4f6dc8fddb functions libkernel to get openrorbis working (without tls) 2023-11-19 12:55:07 +02:00
georgemoralis
f57f668c92 small correction 2023-11-19 10:48:59 +02:00
georgemoralis
a298ddb057 Merge pull request #76 from georgemoralis/threads_and_openorbis_stuff_part1
initial fs implementation (mounting /app0/)
2023-11-19 10:23:23 +02:00
georgemoralis
093ebb568c initial fs implementation (mounting /app0/) 2023-11-19 10:22:46 +02:00
georgemoralis
103de64bba Merge pull request #75 from georgemoralis/threads_and_openorbis_stuff_part1
Threads and openorbis stuff part1
2023-11-18 10:51:36 +02:00
georgemoralis
3e8cd57986 scePthreadCond functions 2023-11-16 13:31:12 +02:00
georgemoralis
1316443c59 initial ScePthreadCond works 2023-11-16 09:14:10 +02:00
georgemoralis
776a680e85 prefix in libc functions to avoid messing with std ones 2023-11-16 09:13:50 +02:00
georgemoralis
cad5ac34b0 some threadman fixes 2023-11-16 08:49:26 +02:00
georgemoralis
dde91c1c4d Merge pull request #71 from georgemoralis/undertale
Undertale-mutexes
2023-11-12 20:26:51 +02:00
georgemoralis
f3c189feb3 cleanup createMutex 2023-11-12 20:23:42 +02:00
georgemoralis
8f8f0757af fixed issue in scePthreadAttrSetschedpolicy 2023-11-12 15:09:18 +02:00
georgemoralis
ae12f351f8 better posix errors 2023-11-12 13:23:35 +02:00
wheremyfoodat
e8c425850e some adjustments 2023-11-12 10:57:50 +02:00
georgemoralis
7e6c741ed7 added sceSystemServiceGetStatus 2023-11-11 16:25:53 +02:00
georgemoralis
420b917a0a Merge pull request #72 from wheremyfoodat/libc_undertale
[Libc] Add getptolower/getptoupper/getpctype
2023-11-11 12:31:05 +02:00
wheremyfoodat
21c8150841 [Libc] Add getptolower/getptoupper/getpctype 2023-11-11 12:28:15 +02:00
georgemoralis
7f0cf8784b improved mutex creation 2023-11-11 12:13:43 +02:00
georgemoralis
402ee7d006 init mutex if it doesn't exist when trying to lock (found in openorbis) 2023-11-11 10:49:44 +02:00
georgemoralis
dbaf38dc7d mutex debugging log 2023-11-11 10:01:16 +02:00
georgemoralis
5f825fc8a8 implemented posix error return codes 2023-11-11 09:45:47 +02:00
georgemoralis
7fcea3277d some mutexlock , mutexunlock implementations 2023-11-10 23:30:28 +02:00
georgemoralis
11edfecb75 some dummy mutexlock-unlock 2023-11-10 21:08:32 +02:00
georgemoralis
a10af46153 some refactoring on thread class 2023-11-10 20:51:02 +02:00
georgemoralis
91885e8a41 added sceMutexInit functions 2023-11-10 19:52:41 +02:00
georgemoralis
86bc2d427f moved thread_management to proper package 2023-11-10 17:31:56 +02:00
georgemoralis
a01e057632 Merge pull request #69 from GPUCode/main
core: Cleanup and reorganize
2023-11-06 06:55:36 +02:00
GPUCode
79c9d9ebd1 kernel: To snake case 2023-11-06 01:19:57 +02:00
GPUCode
099d01f96c common: Move timer to common 2023-11-06 01:17:28 +02:00
GPUCode
369d92fa56 core: Reorganize 2023-11-06 01:11:54 +02:00
georgemoralis
89cf4dbfcb Merge pull request #68 from GPUCode/main
cmake: Refactor third party library management
2023-11-05 22:05:34 +02:00
GPUCode
7bccfeb8cc emulator: Use fmt::format instead of snprintf 2023-11-05 17:14:50 +02:00
GPUCode
1cf032eeb1 cmake: Add directory groups 2023-11-05 17:08:47 +02:00
GPUCode
303f086b14 common: Move classes to common namespace 2023-11-05 16:56:28 +02:00
GPUCode
996aa9d17a cmake: Add include directory to winpthread 2023-11-05 16:30:11 +02:00
GPUCode
a0b80893db cmake: Update CMakeLists.txt 2023-11-05 14:21:20 +02:00
GPUCode
17aefc1aef src: Move certain headers in common 2023-11-05 13:41:26 +02:00
GPUCode
6e28ac711f cmake: Refactor library management 2023-11-05 13:22:32 +02:00
georgemoralis
c126925dd9 libc fprintf implementation for stdout,stderr case (needed from undertale) 2023-11-01 13:02:39 +02:00
georgemoralis
7b276e0a08 some HLE implementation for undertale game to process further 2023-11-01 12:40:56 +02:00
georgemoralis
6fba3a4380 finished libc refactoring 2023-10-31 19:08:33 +02:00
georgemoralis
fd535bae6b libc separate stdlib functions to libc_stdlib 2023-10-31 18:12:05 +02:00
georgemoralis
f5526977d3 libc separated string functions to libc_string 2023-10-31 17:32:56 +02:00
georgemoralis
bb578ae377 cleanup libc (wip) and separated it to several files 2023-10-31 15:53:46 +02:00
georgemoralis
28a5277e2b reorganized libc package 2023-10-31 15:37:24 +02:00
georgemoralis
53a8024e43 core renaming 2023-10-31 14:28:42 +02:00
georgemoralis
aee25dcaf9 Merge pull request #65 from georgemoralis/timers_again
Timers and general refactoring
2023-10-31 14:10:36 +02:00
georgemoralis
11c0d79045 refactoring system service 2023-10-31 14:04:35 +02:00
georgemoralis
7391f7708a user service refactoring 2023-10-31 13:35:52 +02:00
georgemoralis
bdd756a090 log scePadOpen 2023-10-31 09:04:08 +02:00
georgemoralis
c488b7132d refactored libpad to new package 2023-10-31 09:01:20 +02:00
georgemoralis
93e75481c7 refactoring Core folder to core 2023-10-31 08:47:58 +02:00
georgemoralis
cfdc45dfcb file_system reorganized (dummy) 2023-10-30 23:04:57 +02:00
georgemoralis
6f941c277a reimplemented sceKernelReadTsc in proper package and some abi fixes 2023-10-30 20:22:25 +02:00
georgemoralis
61e8919cf1 pause emu with p button 2023-10-30 14:52:01 +02:00
georgemoralis
0ad40cff1b implemented sceKernelGetProcessTimeCounter , sceKernelGetProcessTimeCounterFrequency 2023-10-30 12:53:52 +02:00
georgemoralis
51dda8e8a5 namespace update 2023-10-30 12:43:39 +02:00
georgemoralis
3602864523 added timestamp in buttons state 2023-10-30 08:57:43 +02:00
georgemoralis
758ef332f2 implemented sceKernelGetProcessTime 2023-10-30 08:48:52 +02:00
georgemoralis
f732704b83 implemented fps counter 2023-10-29 23:46:34 +02:00
georgemoralis
ce2c7a7d01 restored previous timer class 2023-10-29 23:46:18 +02:00
georgemoralis
1e755d3cfc fixed return in flip() function 2023-10-29 23:36:15 +02:00
georgemoralis
adbe725d79 more debugging in elf loader 2023-10-28 09:12:43 +03:00
georgemoralis
4e6bfe1772 switched elf logging to fmt 2023-10-28 08:55:58 +03:00
georgemoralis
bb49254fad Merge pull request #64 from georgemoralis/logging_exception
log exceptions and flush log file
2023-10-28 00:10:19 +03:00
georgemoralis
f1ddf028c2 Update src/Util/log.cpp
Co-authored-by: GPUCode <47210458+GPUCode@users.noreply.github.com>
2023-10-28 00:09:47 +03:00
georgemoralis
4706b6b4e5 Update src/Util/log.cpp
Co-authored-by: GPUCode <47210458+GPUCode@users.noreply.github.com>
2023-10-27 20:56:21 +03:00
georgemoralis
ff2a9dd37a Update src/Util/log.cpp
Co-authored-by: GPUCode <47210458+GPUCode@users.noreply.github.com>
2023-10-27 20:55:18 +03:00
georgemoralis
2f0fec806a log exceptions and flush log file 2023-10-27 18:57:48 +03:00
georgemoralis
af3710887c improved logging in elf loader 2023-10-27 18:28:05 +03:00
georgemoralis
eb67c847a7 removed obsolute fs 2023-10-27 11:07:19 +03:00
georgemoralis
50a2f48427 Update README.md 2023-10-27 09:45:15 +03:00
georgemoralis
b3cc2efdb2 Merge pull request #62 from GPUCode/new-elf
code: Rework elf loader and general cleanup
2023-10-27 09:44:30 +03:00
GPUCode
0021e68aab vulkan: Remove orphan new part 2 2023-10-26 23:46:05 +03:00
GPUCode
e196e35669 vulkan: Remove orphan new part 1 2023-10-26 23:38:37 +03:00
GPUCode
28819dede1 code: Replace printf/scanf with type safe fmt 2023-10-26 23:29:19 +03:00
GPUCode
33729d634e main: Remove remnants of imgui example 2023-10-26 23:15:11 +03:00
GPUCode
f3504b2d25 singleton: Use unique_ptr 2023-10-26 23:13:24 +03:00
GPUCode
7cbe7c762a linker: Eliminate orphan news
* Most of these can just be on the stack, with the rest being std::vectors
2023-10-26 23:07:15 +03:00
GPUCode
ca564b928c core: Rework elf loader 2023-10-26 22:55:13 +03:00
georgemoralis
fed14ad4ed Merge pull request #61 from GPUCode/stl-threads
core: Switch threading primitives to STL types
2023-10-22 17:35:51 +03:00
GPUCode
ba299c4c00 core: Remove Timer in favour of std::chrono 2023-10-22 17:17:43 +03:00
GPUCode
e2b1b059ed core: Switch to std threading primitives 2023-10-22 17:10:25 +03:00
georgemoralis
f39744cf62 started 0.0.3 WIP 2023-10-22 00:20:51 +03:00
302 changed files with 27614 additions and 7419 deletions

40
.ci/clang-format.sh Executable file
View File

@@ -0,0 +1,40 @@
#!/bin/bash -ex
# SPDX-FileCopyrightText: 2023 Citra Emulator Project
# SPDX-License-Identifier: GPL-2.0-or-later
if grep -nrI '\s$' src *.yml *.txt *.md Doxyfile .gitignore .gitmodules .ci* dist/*.desktop \
dist/*.svg dist/*.xml; then
echo Trailing whitespace found, aborting
exit 1
fi
# Default clang-format points to default 3.5 version one
CLANG_FORMAT=clang-format-15
$CLANG_FORMAT --version
if [ "$GITHUB_EVENT_NAME" = "pull_request" ]; then
# Get list of every file modified in this pull request
files_to_lint="$(git diff --name-only --diff-filter=ACMRTUXB $COMMIT_RANGE | grep '^src/[^.]*[.]\(cpp\|h\)$' || true)"
else
# Check everything for branch pushes
files_to_lint="$(find src/ -name '*.cpp' -or -name '*.h')"
fi
# Turn off tracing for this because it's too verbose
set +x
for f in $files_to_lint; do
d=$(diff -u "$f" <($CLANG_FORMAT "$f") || true)
if ! [ -z "$d" ]; then
echo "!!! $f not compliant to coding style, here is the fix:"
echo "$d"
fail=1
fi
done
set -x
if [ "$fail" = 1 ]; then
exit 1
fi

View File

@@ -1,7 +0,0 @@
BasedOnStyle: Google
IndentWidth: 4
ColumnLimit: 150
AccessModifierOffset: -2
TabWidth: 4
AllowShortEnumsOnASingleLine: true
AllowShortCaseLabelsOnASingleLine: true

25
.github/linux-appimage-qt.sh vendored Executable file
View File

@@ -0,0 +1,25 @@
# SPDX-FileCopyrightText: 2024 shadPS4 Emulator Project
# SPDX-License-Identifier: GPL-2.0-or-later
#!/bin/bash
if [[ -z $GITHUB_WORKSPACE ]]; then
GITHUB_WORKSPACE="${PWD%/*}"
fi
export PATH="$Qt6_DIR/bin:$PATH"
# Prepare Tools for building the AppImage
wget -q https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage
wget -q https://github.com/linuxdeploy/linuxdeploy-plugin-qt/releases/download/continuous/linuxdeploy-plugin-qt-x86_64.AppImage
wget -q https://github.com/linuxdeploy/linuxdeploy-plugin-checkrt/releases/download/continuous/linuxdeploy-plugin-checkrt-x86_64.sh
chmod a+x linuxdeploy-x86_64.AppImage
chmod a+x linuxdeploy-plugin-qt-x86_64.AppImage
chmod a+x linuxdeploy-plugin-checkrt-x86_64.sh
# Build AppImage
./linuxdeploy-x86_64.AppImage --appdir AppDir
./linuxdeploy-plugin-checkrt-x86_64.sh --appdir AppDir
./linuxdeploy-x86_64.AppImage --appdir AppDir -d "$GITHUB_WORKSPACE"/.github/shadps4.desktop -e "$GITHUB_WORKSPACE"/build/shadps4 -i "$GITHUB_WORKSPACE"/.github/shadps4.png --plugin qt --output appimage
mv Shadps4-x86_64.AppImage Shadps4-qt.AppImage

21
.github/linux-appimage-sdl.sh vendored Executable file
View File

@@ -0,0 +1,21 @@
# SPDX-FileCopyrightText: 2024 shadPS4 Emulator Project
# SPDX-License-Identifier: GPL-2.0-or-later
#!/bin/bash
if [[ -z $GITHUB_WORKSPACE ]]; then
GITHUB_WORKSPACE="${PWD%/*}"
fi
# Prepare Tools for building the AppImage
wget -q https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage
wget -q https://github.com/linuxdeploy/linuxdeploy-plugin-checkrt/releases/download/continuous/linuxdeploy-plugin-checkrt-x86_64.sh
chmod a+x linuxdeploy-x86_64.AppImage
chmod a+x linuxdeploy-plugin-checkrt-x86_64.sh
# Build AppImage
./linuxdeploy-x86_64.AppImage --appdir AppDir
./linuxdeploy-plugin-checkrt-x86_64.sh --appdir AppDir
./linuxdeploy-x86_64.AppImage --appdir AppDir -d "$GITHUB_WORKSPACE"/.github/shadps4.desktop -e "$GITHUB_WORKSPACE"/build/shadps4 -i "$GITHUB_WORKSPACE"/.github/shadps4.png --output appimage
mv Shadps4-x86_64.AppImage Shadps4-sdl.AppImage

9
.github/shadps4.desktop vendored Normal file
View File

@@ -0,0 +1,9 @@
[Desktop Entry]
Name=Shadps4
Exec=shadps4
Terminal=false
Type=Application
Icon=shadps4
Comment=shadps4 emulator
Categories=Game;
StartupWMClass=shadps4;

BIN
.github/shadps4.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 141 KiB

18
.github/workflows/ci.yml vendored Normal file
View File

@@ -0,0 +1,18 @@
# SPDX-FileCopyrightText: 2021 yuzu Emulator Project
# SPDX-License-Identifier: GPL-2.0-or-later
name: Reuse
on:
push:
branches: [ main ]
tags: [ "*" ]
pull_request:
branches: [ main ]
jobs:
reuse:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: fsfe/reuse-action@v1

24
.github/workflows/format.yml vendored Normal file
View File

@@ -0,0 +1,24 @@
# SPDX-FileCopyrightText: 2024 shadPS4 Emulator Project
# SPDX-License-Identifier: GPL-2.0-or-later
name: Clang Format
on:
push:
branches: [ "*" ]
pull_request:
branches: [ main ]
jobs:
clang-format:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Install
run: sudo apt-get install clang-format-15
- name: Build
env:
COMMIT_RANGE: ${{ github.event.pull_request.base.sha }}..${{ github.event.pull_request.head.sha }}
run: ./.ci/clang-format.sh

62
.github/workflows/linux-qt.yml vendored Normal file
View File

@@ -0,0 +1,62 @@
# SPDX-FileCopyrightText: 2024 shadPS4 Emulator Project
# SPDX-License-Identifier: GPL-2.0-or-later
name: Linux-Qt
on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
env:
# Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.)
BUILD_TYPE: Release
CLANG_VER: 17
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Fetch submodules
run: git submodule update --init --recursive
- name: Install misc packages
run: >
sudo apt-get update && sudo apt install libx11-dev libgl1-mesa-glx mesa-common-dev libfuse2
libwayland-dev libxcb-keysyms1 libxcb-randr0 libxcb-render-util0 libxcb-icccm4 libxcb-image0-dev
libxcb-cursor-dev libxxhash-dev libvulkan-dev
- name: Install newer Clang
run: |
wget https://apt.llvm.org/llvm.sh
chmod +x ./llvm.sh
sudo ./llvm.sh ${{env.CLANG_VER}}
- name: Install Qt
uses: jurplel/install-qt-action@v3
with:
version: 6.6.1
host: linux
target: desktop
#arch: clang++-17
dir: ${{ runner.temp }}
#modules: qtcharts qt3d
setup-python: false
- name: Configure CMake
run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_C_COMPILER=clang-${{env.CLANG_VER}} -DCMAKE_CXX_COMPILER=clang++-${{env.CLANG_VER}} -DENABLE_QT_GUI=ON
- name: Build
run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} --parallel
- name: Run AppImage packaging script
run: ./.github/linux-appimage-qt.sh
- name: Upload executable
uses: actions/upload-artifact@v4
with:
name: shadps4-linux-qt
path: Shadps4-qt.AppImage

58
.github/workflows/linux.yml vendored Normal file
View File

@@ -0,0 +1,58 @@
# SPDX-FileCopyrightText: 2024 shadPS4 Emulator Project
# SPDX-License-Identifier: GPL-2.0-or-later
name: Linux
on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
workflow_dispatch:
env:
# Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.)
BUILD_TYPE: Release
CLANG_VER: 17
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Install misc packages
run: >
sudo apt-get update && sudo apt install libx11-dev libgl1-mesa-glx mesa-common-dev libfuse2 libwayland-dev libxxhash-dev libvulkan-dev
- name: Install newer Clang
run: |
wget https://apt.llvm.org/llvm.sh
chmod +x ./llvm.sh
sudo ./llvm.sh ${{env.CLANG_VER}}
- name: Configure CMake
run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_C_COMPILER=clang-${{env.CLANG_VER}} -DCMAKE_CXX_COMPILER=clang++-${{env.CLANG_VER}}
- name: Build
run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} --parallel
- name: Upload executable
uses: actions/upload-artifact@v4
with:
name: shadps4-ubuntu64
path: |
${{github.workspace}}/build/shadps4
${{github.workspace}}/build/libSDL3.so.0.0.0
- name: Run AppImage packaging script
run: ./.github/linux-appimage-sdl.sh
- name: Upload executable
uses: actions/upload-artifact@v4
with:
name: shadps4-sdl-appimage
path: Shadps4-sdl.AppImage

View File

@@ -1,9 +1,7 @@
# This workflow uses actions that are not certified by GitHub.
# They are provided by a third-party and are governed by
# separate terms of service, privacy policy, and support
# documentation.
# SPDX-FileCopyrightText: 2024 shadPS4 Emulator Project
# SPDX-License-Identifier: GPL-2.0-or-later
name: Linux
name: Windows-Qt
on:
push:
@@ -20,31 +18,38 @@ permissions:
jobs:
build:
runs-on: ubuntu-latest
runs-on: windows-latest
steps:
- name: Install dev packages
run: |
sudo apt install libxext-dev doxygen libgl-dev
- uses: actions/checkout@v3
with:
submodules: recursive
- name: Setup Qt
uses: jurplel/install-qt-action@v3
with:
arch: win64_msvc2019_64
version: 6.6.1
- name: Configure CMake
# Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make.
# See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type
run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}}
run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -T ClangCL -DENABLE_QT_GUI=ON
- name: Build
# Build your program with the given configuration
run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} --parallel `nproc`
run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} --parallel
- name: Upload a Build Artifact
uses: actions/upload-artifact@v3.1.2
- name: Deploy
run: |
mkdir upload
move build/Release/shadps4.exe upload
move build/Release/zlib-ng2.dll upload
move build/Release/libwinpthread-1.dll upload
windeployqt --dir upload upload/shadps4.exe
- name: Upload executable
uses: actions/upload-artifact@v2
with:
name: shadps4-ubuntu64
# A file, directory or wildcard pattern that describes what to upload
path: |
${{github.workspace}}/build/shadps4
${{github.workspace}}/build/libSDL3.so.0.0.0
name: shadps4-win64-qt
path: upload

View File

@@ -1,7 +1,5 @@
# This workflow uses actions that are not certified by GitHub.
# They are provided by a third-party and are governed by
# separate terms of service, privacy policy, and support
# documentation.
# SPDX-FileCopyrightText: 2024 shadPS4 Emulator Project
# SPDX-License-Identifier: GPL-2.0-or-later
name: Windows
@@ -21,21 +19,17 @@ permissions:
jobs:
build:
runs-on: windows-latest
steps:
- uses: actions/checkout@v3
with:
submodules: recursive
- name: Configure CMake
# Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make.
# See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type
run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -T ClangCL
- name: Build
# Build your program with the given configuration
run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}}
run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} --parallel
- name: Upload a Build Artifact
uses: actions/upload-artifact@v3.1.2
with:

3
.gitignore vendored
View File

@@ -1,3 +1,6 @@
# SPDX-FileCopyrightText: 2024 shadPS4 Emulator Project
# SPDX-License-Identifier: GPL-2.0-or-later
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
##

45
.gitmodules vendored
View File

@@ -1,19 +1,7 @@
[submodule "third-party/imgui"]
path = third-party/imgui
url = https://github.com/ocornut/imgui
shallow = true
[submodule "third-party/SDL"]
path = third-party/SDL
url = https://github.com/libsdl-org/SDL
shallow = true
[submodule "third-party/fmt"]
path = third-party/fmt
url = https://github.com/fmtlib/fmt.git
shallow = true
[submodule "third-party/spdlog"]
path = third-party/spdlog
url = https://github.com/gabime/spdlog
shallow = true
[submodule "third-party/magic_enum"]
path = third-party/magic_enum
url = https://github.com/Neargye/magic_enum.git
@@ -26,18 +14,37 @@
path = third-party/winpthread
url = https://github.com/shadps4/winpthread.git
branch = main
[submodule "third-party/discord-rpc"]
path = third-party/discord-rpc
url = https://github.com/discord/discord-rpc
[submodule "third-party/toml11"]
path = third-party/toml11
url = https://github.com/ToruNiina/toml11
branch = master
[submodule "third-party/vulkan"]
path = third-party/vulkan
url = https://github.com/shadps4/vulkan.git
branch = main
[submodule "third-party/xxHash"]
path = third-party/xxHash
url = https://github.com/Cyan4973/xxHash.git
branch = dev
[submodule "third-party/vulkan"]
path = third-party/vulkan
url = https://github.com/GPUCode/vulkan
[submodule "externals/discord-rpc"]
path = externals/discord-rpc
url = https://github.com/shadps4-emu/ext-discord-rpc.git
branch = master
[submodule "externals/cryptopp-cmake"]
path = externals/cryptopp-cmake
url = https://github.com/shadps4-emu/ext-cryptopp-cmake.git
branch = master
[submodule "externals/cryptopp"]
path = externals/cryptopp
url = https://github.com/shadps4-emu/ext-cryptopp.git
branch = master
[submodule "externals/cryptoppwin"]
path = externals/cryptoppwin
url = https://github.com/shadps4-emu/ext-cryptoppwin.git
branch = main
[submodule "externals/zlib-ng"]
path = externals/zlib-ng
url = https://github.com/shadps4-emu/ext-zlib-ng.git
[submodule "externals/sdl3"]
path = externals/sdl3
url = https://github.com/shadps4-emu/ext-SDL.git

31
.reuse/dep5 Normal file
View File

@@ -0,0 +1,31 @@
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Comment: It is best to use this file to record copyright information about
generated, binary and third party files
Files: CMakeSettings.json
scripts/ps4_names.txt
documents/changelog.txt
documents/readme.txt
.github/shadps4.desktop
.github/shadps4.png
.gitmodules
src/images/shadps4.ico
screenshots/screenshot.png
src/images/controller_icon.png
src/images/exit_icon.png
src/images/file_icon.png
src/images/folder_icon.png
src/images/grid_icon.png
src/images/iconsize_icon.png
src/images/list_icon.png
src/images/list_mode_icon.png
src/images/pause_icon.png
src/images/play_icon.png
src/images/refresh_icon.png
src/images/settings_icon.png
src/images/stop_icon.png
src/images/themes_icon.png
src/shadps4.rc
src/shadps4.qrc
Copyright: shadPS4 Emulator Project
License: GPL-2.0-or-later

View File

@@ -1,112 +1,372 @@
# SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
# SPDX-License-Identifier: GPL-2.0-or-later
cmake_minimum_required(VERSION 3.16.3)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD 23)
set(CMAKE_CXX_STANDARD_REQUIRED True)
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Release)
if (NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Release)
endif()
project(shadps4)
include_directories(third-party/)
include_directories(third-party/discord-rpc/include)
include_directories(third-party/imgui/)
include_directories(third-party/imgui/backends)
include_directories(third-party/sdl/)
include_directories(third-party/fmt/include)
include_directories(third-party/magic_enum/include)
include_directories(third-party/zydis/include/Zydis)
include_directories(third-party/winpthread/include)
include_directories(third-party/vulkan/include)
include_directories(third-party/xxhash/include)
include_directories(third-party/result/include)
add_subdirectory("third-party")
#=================== EXAMPLE ===================
option(ENABLE_QT_GUI "Enable the Qt GUI. If not selected then the emulator uses a minimal SDL-based UI instead" OFF)
if(ENABLE_QT_GUI)
find_package(Qt6 REQUIRED COMPONENTS Widgets Concurrent)
qt_standard_project_setup()
set(CMAKE_AUTORCC ON)
endif()
# This function should be passed a list of all files in a target. It will automatically generate
# file groups following the directory hierarchy, so that the layout of the files in IDEs matches the
# one in the filesystem.
function(create_target_directory_groups target_name)
# Place any files that aren't in the source list in a separate group so that they don't get in
# the way.
source_group("Other Files" REGULAR_EXPRESSION ".")
get_target_property(target_sources "${target_name}" SOURCES)
foreach(file_name IN LISTS target_sources)
get_filename_component(dir_name "${file_name}" PATH)
# Group names use '\' as a separator even though the entire rest of CMake uses '/'...
string(REPLACE "/" "\\" group_name "${dir_name}")
source_group("${group_name}" FILES "${file_name}")
endforeach()
endfunction()
# Setup a custom clang-format target (if clang-format can be found) that will run
# against all the src files. This should be used before making a pull request.
# =======================================================================
set(CLANG_FORMAT_POSTFIX "-15")
find_program(CLANG_FORMAT
NAMES clang-format${CLANG_FORMAT_POSTFIX}
clang-format
PATHS ${PROJECT_BINARY_DIR}/externals)
# if find_program doesn't find it, try to download from externals
if (NOT CLANG_FORMAT)
if (WIN32)
message(STATUS "Clang format not found! Downloading...")
set(CLANG_FORMAT "${PROJECT_BINARY_DIR}/externals/clang-format${CLANG_FORMAT_POSTFIX}.exe")
file(DOWNLOAD
https://github.com/citra-emu/ext-windows-bin/raw/master/clang-format${CLANG_FORMAT_POSTFIX}.exe
"${CLANG_FORMAT}" SHOW_PROGRESS
STATUS DOWNLOAD_SUCCESS)
if (NOT DOWNLOAD_SUCCESS EQUAL 0)
message(WARNING "Could not download clang format! Disabling the clang format target")
file(REMOVE ${CLANG_FORMAT})
unset(CLANG_FORMAT)
endif()
else()
message(WARNING "Clang format not found! Disabling the clang format target")
endif()
endif()
if (CLANG_FORMAT)
set(SRCS ${PROJECT_SOURCE_DIR}/src)
set(CCOMMENT "Running clang format against all the .h and .cpp files in src/")
if (WIN32)
if(MINGW)
add_custom_target(clang-format
COMMAND find `cygpath -u ${SRCS}` -iname *.h -o -iname *.cpp -o -iname *.mm | xargs `cygpath -u ${CLANG_FORMAT}` -i
COMMENT ${CCOMMENT})
else()
add_custom_target(clang-format
COMMAND powershell.exe -Command "Get-ChildItem '${SRCS}/*' -Include *.cpp,*.h,*.mm -Recurse | Foreach {&'${CLANG_FORMAT}' -i $_.fullname}"
COMMENT ${CCOMMENT})
endif()
else()
add_custom_target(clang-format
COMMAND find ${SRCS} -iname *.h -o -iname *.cpp -o -iname *.mm | xargs ${CLANG_FORMAT} -i
COMMENT ${CCOMMENT})
endif()
unset(SRCS)
unset(CCOMMENT)
endif()
add_subdirectory(externals)
add_subdirectory(third-party)
include_directories(src)
set(LIBC_SOURCES src/Emulator/HLE/Libraries/LibC/Libc.cpp
src/Emulator/HLE/Libraries/LibC/Libc.h
src/Emulator/HLE/Libraries/LibC/printf.h
src/Emulator/HLE/Libraries/LibC/va_ctx.h
src/Emulator/HLE/Libraries/LibC/libc_cxa.cpp
src/Emulator/HLE/Libraries/LibC/libc_cxa.h
set(AUDIO_CORE src/audio_core/sdl_audio.cpp
src/audio_core/sdl_audio.h
)
set(USERSERVICE_SOURCES src/Emulator/HLE/Libraries/LibUserService/user_service.cpp
src/Emulator/HLE/Libraries/LibUserService/user_service.h
set(LIBRARIES src/core/libraries/library_common.h
src/core/libraries/error_codes.h
src/core/libraries/libscecommondialog.cpp
src/core/libraries/libscecommondialog.h
src/core/libraries/libscegnmdriver.cpp
src/core/libraries/libscegnmdriver.h
src/core/libraries/libscemsgdialog.cpp
src/core/libraries/libscemsgdialog.h
src/core/libraries/libscesystemservice.cpp
src/core/libraries/libscesystemservice.h
src/core/libraries/libsceuserservice.cpp
src/core/libraries/libsceuserservice.h
src/core/libraries/libsceaudioout.cpp
src/core/libraries/libsceaudioout.h
)
set(PAD_SOURCES src/Emulator/HLE/Libraries/LibPad/pad.cpp
src/Emulator/HLE/Libraries/LibPad/pad.h
set(LIBC_SOURCES src/core/hle/libraries/libc/libc.cpp
src/core/hle/libraries/libc/libc.h
src/core/hle/libraries/libc/printf.h
src/core/hle/libraries/libc/va_ctx.h
src/core/hle/libraries/libc/libc_cxa.cpp
src/core/hle/libraries/libc/libc_cxa.h
src/core/hle/libraries/libc/libc_stdio.cpp
src/core/hle/libraries/libc/libc_stdio.h
src/core/hle/libraries/libc/libc_math.cpp
src/core/hle/libraries/libc/libc_math.h
src/core/hle/libraries/libc/libc_string.cpp
src/core/hle/libraries/libc/libc_string.h
src/core/hle/libraries/libc/libc_stdlib.cpp
src/core/hle/libraries/libc/libc_stdlib.h
)
set(SYSTEMSERVICE_SOURCES src/Emulator/HLE/Libraries/LibSystemService/system_service.cpp
src/Emulator/HLE/Libraries/LibSystemService/system_service.h
set(PAD_SOURCES src/core/hle/libraries/libpad/pad.cpp
src/core/hle/libraries/libpad/pad.h
)
set(FILESYSTEM_SOURCES src/Emulator/HLE/Libraries/LibKernel/FileSystem/file_system.cpp
src/Emulator/HLE/Libraries/LibKernel/FileSystem/file_system.h
src/Emulator/HLE/Libraries/LibKernel/FileSystem/posix_file_system.cpp
src/Emulator/HLE/Libraries/LibKernel/FileSystem/posix_file_system.h
set(FILESYSTEM_SOURCES src/core/hle/libraries/libkernel/file_system.cpp
src/core/hle/libraries/libkernel/file_system.h
src/core/file_sys/fs.cpp
src/core/file_sys/fs.h
)
set(HOST_SOURCES src/Emulator/Host/controller.cpp
src/Emulator/Host/controller.h
)
set(UTIL_SOURCES src/Emulator/Util/singleton.h
# the above is shared in sdl and qt version (TODO share them all)
if(ENABLE_QT_GUI)
qt_add_resources(RESOURCE_FILES src/shadps4.qrc)
set(QT_GUI
src/qt_gui/main_window_ui.h
src/qt_gui/main_window.cpp
src/qt_gui/main_window.h
src/qt_gui/gui_settings.cpp
src/qt_gui/gui_settings.h
src/qt_gui/settings.cpp
src/qt_gui/settings.h
src/qt_gui/gui_save.h
src/qt_gui/custom_dock_widget.h
src/qt_gui/custom_table_widget_item.cpp
src/qt_gui/custom_table_widget_item.h
src/qt_gui/game_list_item.h
src/qt_gui/game_list_table.cpp
src/qt_gui/game_list_table.h
src/qt_gui/game_list_utils.h
src/qt_gui/game_info.h
src/qt_gui/game_list_grid.cpp
src/qt_gui/game_list_grid.h
src/qt_gui/game_list_grid_delegate.cpp
src/qt_gui/game_list_grid_delegate.h
src/qt_gui/game_list_frame.cpp
src/qt_gui/game_list_frame.h
src/qt_gui/qt_utils.h
src/qt_gui/game_install_dialog.cpp
src/qt_gui/game_install_dialog.h
src/qt_gui/main_window_themes.cpp
src/qt_gui/main_window_themes.h
src/qt_gui/main.cpp
${RESOURCE_FILES}
)
endif()
set(COMMON src/common/logging/backend.cpp
src/common/logging/backend.h
src/common/logging/filter.cpp
src/common/logging/filter.h
src/common/logging/formatter.h
src/common/logging/log_entry.h
src/common/logging/log.h
src/common/logging/text_formatter.cpp
src/common/logging/text_formatter.h
src/common/logging/types.h
src/common/assert.cpp
src/common/assert.h
src/common/bounded_threadsafe_queue.h
src/common/concepts.h
src/common/config.cpp
src/common/config.h
src/common/debug.h
src/common/disassembler.cpp
src/common/disassembler.h
src/common/discord.cpp
src/common/discord.h
src/common/endian.h
src/common/io_file.cpp
src/common/io_file.h
src/common/error.cpp
src/common/error.h
src/common/native_clock.cpp
src/common/native_clock.h
src/common/path_util.cpp
src/common/path_util.h
src/common/rdtsc.cpp
src/common/rdtsc.h
src/common/singleton.h
src/common/string_util.cpp
src/common/string_util.h
src/common/thread.cpp
src/common/thread.h
src/common/types.h
src/common/uint128.h
src/common/version.h
)
set(CORE src/core/loader.cpp
src/core/loader.h
)
set(CRYPTO src/core/crypto/crypto.cpp
src/core/crypto/crypto.h
src/core/crypto/keys.h
)
set(FILE_FORMAT src/core/file_format/pfs.h
src/core/file_format/pkg.cpp
src/core/file_format/pkg.h
src/core/file_format/pkg_type.cpp
src/core/file_format/pkg_type.h
src/core/file_format/psf.cpp
src/core/file_format/psf.h
)
if(ENABLE_QT_GUI)
qt_add_executable(shadps4
${QT_GUI}
${COMMON}
${CORE}
${CRYPTO}
${FILE_FORMAT}
)
else()
add_executable(shadps4
${AUDIO_CORE}
${LIBC_SOURCES}
${USERSERVICE_SOURCES}
${PAD_SOURCES}
${SYSTEMSERVICE_SOURCES}
${FILESYSTEM_SOURCES}
${HOST_SOURCES}
${UTIL_SOURCES}
${LIBRARIES}
src/main.cpp
src/types.h
src/Core/FsFile.cpp
src/Core/FsFile.h
src/Core/PS4/Loader/Elf.cpp
src/Core/PS4/Loader/Elf.h
src/GUI/ElfViewer.cpp
src/GUI/ElfViewer.h
src/Util/log.h
src/Util/log.cpp
src/Util/config.cpp
src/Util/config.h
src/Core/virtual_memory.cpp
src/Core/virtual_memory.h
src/Core/PS4/Linker.cpp
src/Core/PS4/Linker.h
src/Core/PS4/Stubs.cpp
src/Core/PS4/Stubs.h
src/Core/PS4/Util/aerolib.cpp
src/Lib/Threads.cpp
src/Lib/Threads.h
src/Core/PS4/HLE/Kernel/Objects/physical_memory.h
src/Core/PS4/HLE/Kernel/Objects/physical_memory.cpp
src/Util/string_util.cpp
src/Util/string_util.cpp
src/Core/PS4/HLE/Graphics/video_out.cpp
src/Core/PS4/HLE/Graphics/video_out.h
src/discord.h
src/discord.cpp
src/Core/PS4/HLE/Kernel/event_queues.cpp
src/Core/PS4/HLE/Kernel/event_queues.h
src/Core/PS4/HLE/Kernel/cpu_management.cpp
src/Core/PS4/HLE/Kernel/cpu_management.h
"src/Util/Disassembler.cpp" "src/Util/Disassembler.h" "src/Core/PS4/Util/aerolib.h" "src/Core/PS4/Loader/SymbolsResolver.h" "src/Core/PS4/Loader/SymbolsResolver.cpp" "src/Core/PS4/HLE/Libs.cpp" "src/Core/PS4/HLE/Libs.h" "src/Core/PS4/HLE/LibC.cpp" "src/Core/PS4/HLE/LibC.h" "src/Lib/Timer.cpp" "src/Lib/Timer.h" "src/Core/PS4/HLE/LibKernel.cpp" "src/Core/PS4/HLE/LibKernel.h" "src/Core/PS4/HLE/LibSceGnmDriver.cpp" "src/Core/PS4/HLE/LibSceGnmDriver.h" "src/Core/PS4/HLE/Kernel/ThreadManagement.cpp" "src/Core/PS4/HLE/Kernel/ThreadManagement.h" "src/Core/PS4/HLE/ErrorCodes.h" "src/debug.h" "src/Core/PS4/HLE/Kernel/memory_management.cpp" "src/Core/PS4/HLE/Kernel/memory_management.h" "src/Core/PS4/GPU/gpu_memory.cpp" "src/Core/PS4/GPU/gpu_memory.h" "src/emulator.cpp" "src/emulator.h" "src/Core/PS4/HLE/Kernel/Objects/event_queue.h" "src/Core/PS4/HLE/Kernel/Objects/event_queue.cpp" "src/Core/PS4/HLE/Graphics/Objects/video_out_ctx.cpp" "src/Core/PS4/HLE/Graphics/Objects/video_out_ctx.h" "src/Core/PS4/HLE/Graphics/graphics_ctx.h" "src/vulkan_util.cpp" "src/vulkan_util.h" "src/Core/PS4/GPU/video_out_buffer.cpp" "src/Core/PS4/GPU/video_out_buffer.h" "src/Core/PS4/HLE/Graphics/graphics_render.cpp" "src/Core/PS4/HLE/Graphics/graphics_render.h" "src/Core/PS4/GPU/tile_manager.cpp" "src/Core/PS4/GPU/tile_manager.h" "src/version.h" "src/Emulator/HLE/Libraries/LibSystemService/system_service.cpp" "src/Emulator/HLE/Libraries/LibSystemService/system_service.h" "src/Emulator/HLE/Libraries/LibKernel/FileSystem/meta_file_system.h" "src/Emulator/HLE/Libraries/LibKernel/FileSystem/meta_file_system.cpp")
src/core/loader/elf.cpp
src/core/loader/elf.h
src/core/virtual_memory.cpp
src/core/virtual_memory.h
src/core/linker.cpp
src/core/linker.h
src/core/aerolib/stubs.cpp
src/core/aerolib/stubs.h
src/core/aerolib/aerolib.cpp
src/core/aerolib/aerolib.h
src/core/hle/kernel/Objects/physical_memory.h
src/core/hle/kernel/Objects/physical_memory.cpp
src/core/PS4/HLE/Graphics/video_out.cpp
src/core/PS4/HLE/Graphics/video_out.h
src/core/hle/kernel/event_queues.cpp
src/core/hle/kernel/event_queues.h
src/core/hle/kernel/cpu_management.cpp
src/core/hle/kernel/cpu_management.h
src/core/loader/symbols_resolver.h
src/core/loader/symbols_resolver.cpp
src/core/hle/libraries/libs.cpp
src/core/hle/libraries/libs.h
src/core/hle/libraries/libkernel/libkernel.cpp
src/core/hle/libraries/libkernel/libkernel.h
src/core/hle/libraries/libscegnmdriver/libscegnmdriver.cpp
src/core/hle/libraries/libscegnmdriver/libscegnmdriver.h
src/core/hle/libraries/libkernel/thread_management.cpp
src/core/hle/libraries/libkernel/thread_management.h
src/core/hle/kernel/memory_management.cpp
src/core/hle/kernel/memory_management.h
src/core/hle/error_codes.h
src/core/PS4/GPU/gpu_memory.cpp
src/core/PS4/GPU/gpu_memory.h
src/emulator.cpp
src/emulator.h
src/core/hle/kernel/Objects/event_queue.h
src/core/hle/kernel/Objects/event_queue.cpp
src/core/PS4/HLE/Graphics/Objects/video_out_ctx.cpp
src/core/PS4/HLE/Graphics/Objects/video_out_ctx.h
src/core/PS4/HLE/Graphics/graphics_ctx.h
src/vulkan_util.cpp
src/vulkan_util.h
src/core/PS4/GPU/video_out_buffer.cpp
src/core/PS4/GPU/video_out_buffer.h
src/core/PS4/HLE/Graphics/graphics_render.cpp
src/core/PS4/HLE/Graphics/graphics_render.h
src/core/PS4/GPU/tile_manager.cpp
src/core/PS4/GPU/tile_manager.h
src/core/hle/libraries/libkernel/time_management.cpp
src/core/hle/libraries/libkernel/time_management.h
src/core/tls.cpp
src/core/tls.h
${COMMON}
${CORE}
${CRYPTO}
${FILE_FORMAT}
)
endif()
find_package(OpenGL REQUIRED)
target_link_libraries(shadps4 PUBLIC fmt mincore spdlog IMGUI SDL3-shared ${OPENGL_LIBRARY} vulkan-1 spirv-tools-opt spirv-tools)
create_target_directory_groups(shadps4)
target_link_libraries(shadps4 PRIVATE magic_enum::magic_enum fmt::fmt toml11::toml11)
target_link_libraries(shadps4 PRIVATE discord-rpc vulkan-1 xxhash Zydis)
if(NOT ENABLE_QT_GUI)
target_link_libraries(shadps4 PRIVATE SDL3-shared)
endif()
if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND MSVC)
target_link_libraries(shadps4 PRIVATE cryptoppwin zlib)
else()
target_link_libraries(shadps4 PRIVATE cryptopp::cryptopp zlib)
endif()
if(ENABLE_QT_GUI)
target_link_libraries(shadps4 PRIVATE Qt6::Widgets Qt6::Concurrent)
endif()
if (WIN32)
target_link_libraries(shadps4 PRIVATE mincore winpthread clang_rt.builtins-x86_64.lib)
add_definitions(-D_CRT_SECURE_NO_WARNINGS -D_CRT_NONSTDC_NO_DEPRECATE -D_SCL_SECURE_NO_WARNINGS)
add_definitions(-DNOMINMAX -DWIN32_LEAN_AND_MEAN)
endif()
if(WIN32)
target_sources(shadps4 PRIVATE src/shadps4.rc)
endif()
target_include_directories(shadps4 PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
if(ENABLE_QT_GUI)
set_target_properties(shadps4 PROPERTIES
WIN32_EXECUTABLE ON
MACOSX_BUNDLE ON
)
endif()
add_custom_command(TARGET shadps4 POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
$<TARGET_FILE:zlib>
$<TARGET_FILE_DIR:shadps4>
)
if(NOT ENABLE_QT_GUI)
add_custom_command(TARGET shadps4 POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
$<TARGET_FILE:SDL3-shared>
$<TARGET_FILE_DIR:shadps4>)
add_custom_command(TARGET shadps4 POST_BUILD
endif()
if (WIN32)
add_custom_command(TARGET shadps4 POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
"${PROJECT_SOURCE_DIR}/third-party/winpthread/bin/libwinpthread-1.dll" $<TARGET_FILE_DIR:shadps4>)
endif()

128
CONTRIBUTING.md Normal file
View File

@@ -0,0 +1,128 @@
<!--
SPDX-FileCopyrightText: 2024 shadPS4 Emulator Project
SPDX-License-Identifier: GPL-2.0-or-later
-->
# Style guidelines
## General Rules
* Line width is typically 100 characters. Please do not use 80-characters.
* Don't ever introduce new external dependencies into Core
* Don't use any platform specific code in Core
* Use namespaces often
* Avoid the use of C-style casts and instead prefer C++-style static_cast and reinterpret_cast. Try to avoid using dynamic_cast. Never use const_cast except for when dealing with external const-incorrect APIs.
## Naming Rules
* Functions: `PascalCase`
* Variables: `lower_case_underscored. Prefix with g_ if global.`
* Classes: `PascalCase`
* Files and Directories: `lower_case_underscored`
* Namespaces: `PascalCase`, `_` may also be used for clarity (e.g. `ARM_InitCore`)
# Indentation/Whitespace Style
Follow the indentation/whitespace style shown below. Do not use tabs, use 4-spaces instead.
# Comments
* For regular comments, use C++ style (//) comments, even for multi-line ones.
* For doc-comments (Doxygen comments), use /// if it's a single line, else use the /** */ style featured in the example. Start the text on the second line, not the first containing /**.
* For items that are both defined and declared in two separate files, put the doc-comment only next to the associated declaration. (In a header file, usually.) Otherwise, put it next to the implementation. Never duplicate doc-comments in both places.
```
// Includes should be sorted lexicographically
// STD includes first
#include <array>
#include <map>
#include <memory>
// then, library includes
#include <nihstro/shared_binary.h>
// finally, shadps4 includes
#include "common/math_util.h"
#include "common/vector_math.h"
// each major module is separated
#include "video_core/pica.h"
#include "video_core/video_core.h"
namespace Example {
// Namespace contents are not indented
// Declare globals at the top (better yet, don't use globals at all!)
int g_foo{}; // {} can be used to initialize types as 0, false, or nullptr
char* g_some_pointer{}; // Pointer * and reference & stick to the type name, and make sure to initialize as nullptr!
/// A colorful enum.
enum class SomeEnum {
Red, ///< The color of fire.
Green, ///< The color of grass.
Blue, ///< Not actually the color of water.
};
/**
* Very important struct that does a lot of stuff.
* Note that the asterisks are indented by one space to align to the first line.
*/
struct Position {
// Always intitialize member variables!
int x{};
int y{};
};
// Use "typename" rather than "class" here
template <typename T>
void FooBar() {
const std::string some_string{"prefer uniform initialization"};
const std::array<int, 4> some_array{
5,
25,
7,
42,
};
if (note == the_space_after_the_if) {
CallAFunction();
} else {
// Use a space after the // when commenting
}
// Place a single space after the for loop semicolons, prefer pre-increment
for (int i = 0; i != 25; ++i) {
// This is how we write loops
}
DoStuff(this, function, call, takes, up, multiple,
lines, like, this);
if (this || condition_takes_up_multiple &&
lines && like && this || everything ||
alright || then) {
// Leave a blank space before the if block body if the condition was continued across
// several lines.
}
// No indentation for case labels
switch (var) {
case 1: {
const int case_var{var + 3};
DoSomething(case_var);
break;
}
case 3:
DoSomething(var);
return;
default:
// Yes, even break for the last case
break;
}
}
} // namespace Example
```

View File

@@ -0,0 +1,117 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too.
When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights.
We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations.
Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and modification follow.
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program.
You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License.
c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program.
In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License.
3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable.
If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance.
5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License.
7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances.
It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice.
This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation.
10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found.
one line to give the program's name and an idea of what it does. Copyright (C) yyyy name of author
This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker.
signature of Ty Coon, 1 April 1989 Ty Coon, President of Vice

9
LICENSES/MIT.txt Normal file
View File

@@ -0,0 +1,9 @@
MIT License
Copyright (c) <year> <copyright holders>
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@@ -1,7 +1,12 @@
<!--
SPDX-FileCopyrightText: 2024 shadPS4 Emulator Project
SPDX-License-Identifier: GPL-2.0-or-later
-->
# shadPS4
An early PS4 emulator for Windows and Linux written in C++
by shadow , skmp , wheremyfoodat
by shadow , skmp , wheremyfoodat , GPUCode
[Check us on twitter](https://twitter.com/shadps4 "Check us on twitter")
@@ -9,12 +14,6 @@ by shadow , skmp , wheremyfoodat
Early progress , a small amount of ps4 sdk demos and homebrew games working
![](https://geps.dev/progress/60) Elf Loader
![](https://geps.dev/progress/80) Logging system
![](https://geps.dev/progress/10) Everything else
# Why?
The project started as a fun project. Due to short free time, it will probably take a while since it will be able to run something decent, but I am trying to do regular small commits.
@@ -33,33 +32,22 @@ Check building instructions in [linux build](https://github.com/georgemoralis/sh
|Platform|Build status|
|--------|------------|
|Windows build|[![Windows](https://github.com/georgemoralis/shadPS4/actions/workflows/windows.yml/badge.svg)](https://github.com/georgemoralis/shadPS4/actions/workflows/windows.yml)
|Windows SDL build|[![Windows-sdl](https://github.com/shadps4-emu/shadPS4/actions/workflows/windows.yml/badge.svg)](https://github.com/shadps4-emu/shadPS4/actions/workflows/windows.yml)
|Linux SDL build|[![Linux-sdl](https://github.com/shadps4-emu/shadPS4/actions/workflows/linux.yml/badge.svg)](https://github.com/shadps4-emu/shadPS4/actions/workflows/linux.yml)
To discuss the development of this emulator, please join our Discord server: [![Discord](https://img.shields.io/discord/1080089157554155590)](https://discord.gg/MyZRaBngxA)
# Who are you?
# Main team
Old emulator fans and devs can recognize me as "shadow". I was the founder and coder for a lot of emulation projects:
* PCSX
* PCSX2
* PCSP
* JPCSP
* arcadeflex
* rpcs3 contributor
- gmoralis (a.k.a. shadow)
- gpucode (a.k.a. emufan4568)
- skmp (a.k.a. drk||Raziel)
- wheremyfoodat (a.k.a. rodakinos)
# Contribution
I currently accept any contribution, here is a list of some items that may be useful:
We currently accept any contribution, just open a pr and we will check it :)
* PKG extractor (there was initial work on this, search project history commits).
* Initial GUI with imgui, SDL3 and Vulkan.
* to be filled...
# Documentation
Wiki has some documentation for PS4 PKG format
[PKG PS4 File Format](https://github.com/georgemoralis/shadPS4/wiki/PKG-Information "PKG PS4 File Format")
# Sister Projects
- [Panda3DS](https://github.com/wheremyfoodat/Panda3DS): An multiplatform 3DS emulator from our co-author wheremyfoodat

View File

@@ -1,3 +1,8 @@
<!--
SPDX-FileCopyrightText: 2024 shadPS4 Emulator Project
SPDX-License-Identifier: GPL-2.0-or-later
-->
# How to build shadps4 in windows
## Download VStudio Community 2022 17.7.4

View File

@@ -1,3 +1,19 @@
v0.0.3 23/03/2024 - codename salad
=================
-Switching to std::thread
-Use unique_ptr where possible
-Replace printf/scanf with type safe fmt
-Implemented sceKernelGetProcessTime
-Implemented sceKernelGetProcessTimeCounter , sceKernelGetProcessTimeCounterFrequency
-Pause emu with P button
-Timers rewrote with std::chrono
-Added sceSystemServiceGetStatus
-Initial FileSystem implementation
-Initial TLS work
-New logging implementation
-Some functions implemented for userService,systemService
-Added sceAudioOut module and output using sdl audio
v0.0.2 21/10/2023
=================
-using cstdint header in variable types

View File

@@ -1,3 +1,7 @@
<!--
SPDX-FileCopyrightText: 2024 shadPS4 Emulator Project
SPDX-License-Identifier: GPL-2.0-or-later
-->
## Linux

View File

@@ -8,7 +8,7 @@ shadps4 - An ps4 emulator
1.Intro
=======
shadPS4 is a ps4 emulator for windows. Although atm it can't run a lot of stuff , it can emulate perfectly videoout_basic demo from ps4 sdk. Since developing focused on that , don't expect to run anything else atm (ok maybe if you are extreme lucky , you might find something else that works)
shadPS4 is a ps4 emulator for windows and linux . Although atm it can't run a lot of stuff , we are working torwards to make it more compatible
2.Current status
================
@@ -17,11 +17,10 @@ shadps4 is a HLE emulator . Currently on a small amount of functions is emulated
3.Contributors
==============
Although atm project is mostly 1 man's work there are several commits from other devs (ironically there are all greeks)
- wheremyfoodat - (pcsx-redux dev and Panda3DS founder and dev)
- skmp - (nulldc , reincast and some many others emus founder and dev)
- OFFTKP - (paris... what to tell about paris , ok hydra is one of his best effords :) )
- gmoralis (a.k.a. shadow)
- gpucode (a.k.a. emufan4568)
- skmp (a.k.a. drk||Raziel)
- wheremyfoodat (a.k.a. rodakinos)
4.Greetings
===========

36
externals/CMakeLists.txt vendored Normal file
View File

@@ -0,0 +1,36 @@
# SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
# SPDX-License-Identifier: GPL-2.0-or-later
if (MSVC)
# Silence "deprecation" warnings
add_definitions(-D_CRT_SECURE_NO_WARNINGS -D_CRT_NONSTDC_NO_DEPRECATE -D_SCL_SECURE_NO_WARNINGS)
endif()
# Discord-RPC
set(BUILD_EXAMPLES OFF CACHE BOOL "")
add_subdirectory(discord-rpc EXCLUDE_FROM_ALL)
target_include_directories(discord-rpc INTERFACE ./discord-rpc/include)
if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND MSVC)
# If it is clang and MSVC we will add a static lib
# CryptoPP
add_subdirectory(cryptoppwin EXCLUDE_FROM_ALL)
target_include_directories(cryptoppwin INTERFACE cryptoppwin/include)
else()
# CryptoPP
set(CRYPTOPP_BUILD_TESTING OFF)
set(CRYPTOPP_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/cryptopp/)
add_subdirectory(cryptopp-cmake EXCLUDE_FROM_ALL)
endif()
# Zlib-Ng
set(ZLIB_ENABLE_TESTS OFF)
set(WITH_GTEST OFF)
set(WITH_NEW_STRATEGIES ON)
set(WITH_NATIVE_INSTRUCTIONS ON)
add_subdirectory(zlib-ng)
if(NOT ENABLE_QT_GUI)
# SDL3
add_subdirectory(sdl3 EXCLUDE_FROM_ALL)
endif()

1
externals/cryptopp vendored Submodule

Submodule externals/cryptopp added at 782057f5f1

1
externals/cryptopp-cmake vendored Submodule

1
externals/cryptoppwin vendored Submodule

Submodule externals/cryptoppwin added at 0dd224c681

1
externals/discord-rpc vendored Submodule

Submodule externals/discord-rpc added at 4ec218155d

1
externals/sdl3 vendored Submodule

Submodule externals/sdl3 added at 70b0d33106

1
externals/zlib-ng vendored Submodule

Submodule externals/zlib-ng added at af8169a724

BIN
screenshots/screenshot.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 810 KiB

View File

@@ -1,3 +1,6 @@
# SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
# SPDX-License-Identifier: GPL-2.0-or-later
# Helper script that generates stub implementation of all known nids + lookup tables
# for shadps4

259
src/.clang-format Normal file
View File

@@ -0,0 +1,259 @@
# SPDX-FileCopyrightText: 2016 Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
# SPDX-License-Identifier: GPL-2.0-or-later
---
Language: Cpp
# BasedOnStyle: LLVM
AccessModifierOffset: -4
AlignAfterOpenBracket: Align
AlignConsecutiveAssignments: false
AlignConsecutiveDeclarations: false
AlignEscapedNewlinesLeft: false
AlignOperands: true
AlignTrailingComments: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortBlocksOnASingleLine: false
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: Empty
AllowShortIfStatementsOnASingleLine: false
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: true
BinPackArguments: true
BinPackParameters: true
BraceWrapping:
AfterClass: false
AfterControlStatement: false
AfterEnum: false
AfterFunction: false
AfterNamespace: false
AfterObjCDeclaration: false
AfterStruct: false
AfterUnion: false
BeforeCatch: false
BeforeElse: false
IndentBraces: false
BreakBeforeBinaryOperators: None
BreakBeforeBraces: Attach
BreakBeforeTernaryOperators: true
BreakConstructorInitializersBeforeComma: false
ColumnLimit: 100
CommentPragmas: '^ IWYU pragma:'
ConstructorInitializerAllOnOneLineOrOnePerLine: false
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
DerivePointerAlignment: false
DisableFormat: false
ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ]
IncludeCategories:
- Regex: '^\<[^Q][^/.>]*\>'
Priority: -2
- Regex: '^\<'
Priority: -1
- Regex: '^\"'
Priority: 0
IndentCaseLabels: false
IndentWidth: 4
IndentWrappedFunctionNames: false
KeepEmptyLinesAtTheStartOfBlocks: true
MacroBlockBegin: ''
MacroBlockEnd: ''
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
ObjCBlockIndentWidth: 2
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: true
PenaltyBreakBeforeFirstCallParameter: 19
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakString: 1000
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 150
PointerAlignment: Left
ReflowComments: true
SortIncludes: true
SpaceAfterCStyleCast: false
SpaceBeforeAssignmentOperators: true
SpaceBeforeParens: ControlStatements
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 1
SpacesInAngles: false
SpacesInContainerLiterals: true
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
Standard: Cpp11
TabWidth: 4
UseTab: Never
---
Language: Java
# BasedOnStyle: LLVM
AccessModifierOffset: -4
AlignAfterOpenBracket: Align
AlignConsecutiveAssignments: false
AlignConsecutiveDeclarations: false
AlignEscapedNewlinesLeft: false
AlignOperands: true
AlignTrailingComments: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortBlocksOnASingleLine: false
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: Empty
AllowShortIfStatementsOnASingleLine: false
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: true
BinPackArguments: true
BinPackParameters: true
BraceWrapping:
AfterClass: false
AfterControlStatement: false
AfterEnum: false
AfterFunction: false
AfterNamespace: false
AfterObjCDeclaration: false
AfterStruct: false
AfterUnion: false
BeforeCatch: false
BeforeElse: false
IndentBraces: false
BreakBeforeBinaryOperators: None
BreakBeforeBraces: Attach
BreakBeforeTernaryOperators: true
BreakConstructorInitializersBeforeComma: false
ColumnLimit: 100
ConstructorInitializerAllOnOneLineOrOnePerLine: false
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
DerivePointerAlignment: false
DisableFormat: false
IncludeCategories:
- Regex: '^\<[^Q][^/.>]*\>'
Priority: -2
- Regex: '^\<'
Priority: -1
- Regex: '^\"'
Priority: 0
IndentCaseLabels: false
IndentWidth: 4
IndentWrappedFunctionNames: false
KeepEmptyLinesAtTheStartOfBlocks: true
MacroBlockBegin: ''
MacroBlockEnd: ''
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
ObjCBlockIndentWidth: 2
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: true
PenaltyBreakBeforeFirstCallParameter: 19
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakString: 1000
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 150
PointerAlignment: Left
ReflowComments: true
SortIncludes: true
SpaceAfterCStyleCast: false
SpaceBeforeAssignmentOperators: true
SpaceBeforeParens: ControlStatements
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 1
SpacesInAngles: false
SpacesInContainerLiterals: true
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
TabWidth: 4
UseTab: Never
---
Language: ObjC
# BasedOnStyle: LLVM
AccessModifierOffset: -4
AlignAfterOpenBracket: Align
AlignConsecutiveAssignments: false
AlignConsecutiveDeclarations: false
AlignEscapedNewlinesLeft: false
AlignOperands: true
AlignTrailingComments: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortBlocksOnASingleLine: false
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: Empty
AllowShortIfStatementsOnASingleLine: false
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: true
BinPackArguments: true
BinPackParameters: true
BraceWrapping:
AfterClass: false
AfterControlStatement: false
AfterEnum: false
AfterFunction: false
AfterNamespace: false
AfterObjCDeclaration: false
AfterStruct: false
AfterUnion: false
BeforeCatch: false
BeforeElse: false
IndentBraces: false
BreakBeforeBinaryOperators: None
BreakBeforeBraces: Attach
BreakBeforeTernaryOperators: true
BreakConstructorInitializersBeforeComma: false
ColumnLimit: 100
ConstructorInitializerAllOnOneLineOrOnePerLine: false
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
DerivePointerAlignment: false
DisableFormat: false
IncludeCategories:
- Regex: '^\<[^Q][^/.>]*\>'
Priority: -2
- Regex: '^\<'
Priority: -1
- Regex: '^\"'
Priority: 0
IndentCaseLabels: false
IndentWidth: 4
IndentWrappedFunctionNames: false
KeepEmptyLinesAtTheStartOfBlocks: true
MacroBlockBegin: ''
MacroBlockEnd: ''
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
ObjCBlockIndentWidth: 2
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: true
PenaltyBreakBeforeFirstCallParameter: 19
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakString: 1000
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 150
PointerAlignment: Left
ReflowComments: true
SortIncludes: true
SpaceAfterCStyleCast: false
SpaceBeforeAssignmentOperators: true
SpaceBeforeParens: ControlStatements
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 1
SpacesInAngles: false
SpacesInContainerLiterals: true
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
TabWidth: 4
UseTab: Never
...

View File

@@ -1,122 +0,0 @@
#include "FsFile.h"
FsFile::FsFile()
{
m_file = nullptr;
}
FsFile::FsFile(const std::string& path, fsOpenMode mode)
{
Open(path, mode);
}
bool FsFile::Open(const std::string& path, fsOpenMode mode)
{
Close();
#ifdef _WIN64
fopen_s(&m_file, path.c_str(), getOpenMode(mode));
#else
m_file = std::fopen(path.c_str(), getOpenMode(mode));
#endif
return IsOpen();
}
bool FsFile::Close()
{
if (!IsOpen() || std::fclose(m_file) != 0) {
m_file = nullptr;
return false;
}
m_file = nullptr;
return true;
}
FsFile::~FsFile()
{
Close();
}
bool FsFile::Write(const void* src, u64 size)
{
if (!IsOpen() || std::fwrite(src, 1, size, m_file) != size) {
return false;
}
return true;
}
bool FsFile::Read(void* dst, u64 size)
{
if (!IsOpen() || std::fread(dst, 1, size, m_file) != size) {
return false;
}
return true;
}
u32 FsFile::ReadBytes(void* dst, u64 size)
{
return std::fread(dst, 1, size, m_file);
}
bool FsFile::Seek(s64 offset, fsSeekMode mode)
{
#ifdef _WIN64
if (!IsOpen() || _fseeki64(m_file, offset, getSeekMode(mode)) != 0) {
return false;
}
#else
if (!IsOpen() || fseeko64(m_file, offset, getSeekMode(mode)) != 0) {
return false;
}
#endif
return true;
}
u64 FsFile::Tell() const
{
if (IsOpen()) {
#ifdef _WIN64
return _ftelli64(m_file);
#else
return ftello64(m_file);
#endif
}
else {
return -1;
}
}
u64 FsFile::getFileSize()
{
#ifdef _WIN64
u64 pos = _ftelli64(m_file);
if (_fseeki64(m_file, 0, SEEK_END) != 0) {
return 0;
}
u64 size = _ftelli64(m_file);
if (_fseeki64(m_file, pos, SEEK_SET) != 0) {
return 0;
}
#else
u64 pos = ftello64(m_file);
if (fseeko64(m_file, 0, SEEK_END) != 0) {
return 0;
}
u64 size = ftello64(m_file);
if (fseeko64(m_file, pos, SEEK_SET) != 0) {
return 0;
}
#endif
return size;
}
bool FsFile::IsOpen() const
{
return m_file != nullptr;
}

View File

@@ -1,62 +0,0 @@
#pragma once
#include <cstdio>
#include <string>
#include "../types.h"
enum fsOpenMode
{
fsRead = 0x1,
fsWrite = 0x2,
fsReadWrite = fsRead | fsWrite
};
enum fsSeekMode
{
fsSeekSet,
fsSeekCur,
fsSeekEnd,
};
class FsFile
{
std::FILE* m_file;
public:
FsFile();
FsFile(const std::string& path, fsOpenMode mode = fsRead);
bool Open(const std::string& path, fsOpenMode mode = fsRead);
bool IsOpen() const;
bool Close();
bool Read(void* dst, u64 size);
u32 ReadBytes(void* dst, u64 size);
bool Write(const void* src, u64 size);
bool Seek(s64 offset, fsSeekMode mode);
u64 getFileSize();
u64 Tell() const;
~FsFile();
const char* getOpenMode(fsOpenMode mode)
{
switch (mode) {
case fsRead: return "rb";
case fsWrite: return "wb";
case fsReadWrite: return "r+b";
}
return "r";
}
const int getSeekMode(fsSeekMode mode)
{
switch (mode) {
case fsSeekSet: return SEEK_SET;
case fsSeekCur: return SEEK_CUR;
case fsSeekEnd: return SEEK_END;
}
return SEEK_SET;
}
std::FILE* fileDescr()
{
return m_file;
}
};

View File

@@ -1,8 +0,0 @@
#pragma once
#include "types.h"
namespace GPU {
void convertTileToLinear(void* dst, const void* src, u32 width, u32 height, bool neo);
}

View File

@@ -1,22 +0,0 @@
#pragma once
constexpr int SCE_OK = 0;
constexpr int SCE_KERNEL_ERROR_EBADF = 0x80020009;
constexpr int SCE_KERNEL_ERROR_ENOMEM = 0x8002000c; // Insufficient memory
constexpr int SCE_KERNEL_ERROR_EFAULT = 0x8002000e; // Invalid address pointer
constexpr int SCE_KERNEL_ERROR_EINVAL = 0x80020016; // null or invalid states
constexpr int SCE_KERNEL_ERROR_EAGAIN = 0x80020023; // Memory cannot be allocated
constexpr int SCE_KERNEL_ERROR_ENAMETOOLONG = 0x8002003f; // character strings exceeds valid size
// videoOut
constexpr int SCE_VIDEO_OUT_ERROR_INVALID_VALUE = 0x80290001; // invalid argument
constexpr int SCE_VIDEO_OUT_ERROR_INVALID_ADDRESS = 0x80290002; // invalid addresses
constexpr int SCE_VIDEO_OUT_ERROR_INVALID_TILING_MODE = 0x80290007; // invalid tiling mode
constexpr int SCE_VIDEO_OUT_ERROR_INVALID_ASPECT_RATIO = 0x80290008; // invalid aspect ration
constexpr int SCE_VIDEO_OUT_ERROR_RESOURCE_BUSY = 0x80290009; // already opened
constexpr int SCE_VIDEO_OUT_ERROR_INVALID_INDEX = 0x8029000A; // invalid buffer index
constexpr int SCE_VIDEO_OUT_ERROR_INVALID_HANDLE = 0x8029000B; // invalid handle
constexpr int SCE_VIDEO_OUT_ERROR_INVALID_EVENT_QUEUE = 0x8029000C; // Invalid event queue
constexpr int SCE_VIDEO_OUT_ERROR_SLOT_OCCUPIED = 0x80290010; // slot already used
constexpr int SCE_VIDEO_OUT_ERROR_FLIP_QUEUE_FULL = 0x80290012; // flip queue is full
constexpr int SCE_VIDEO_OUT_ERROR_INVALID_OPTION = 0x8029001A; // Invalid buffer attribute option

View File

@@ -1,134 +0,0 @@
#include "video_out_ctx.h"
#include <Core/PS4/HLE/LibKernel.h>
#include <debug.h>
namespace HLE::Graphics::Objects {
void VideoOutCtx::Init(u32 width, u32 height) {
m_video_out_ctx.m_resolution.fullWidth = width;
m_video_out_ctx.m_resolution.fullHeight = height;
m_video_out_ctx.m_resolution.paneWidth = width;
m_video_out_ctx.m_resolution.paneHeight = height;
}
int VideoOutCtx::Open() {
Lib::LockMutexGuard lock(m_mutex);
int handle = -1;
if (!m_video_out_ctx.isOpened) {
handle = 1; // positive return , should be more than 1 ?
}
m_video_out_ctx.isOpened = true;
m_video_out_ctx.m_flip_status = SceVideoOutFlipStatus();
m_video_out_ctx.m_flip_status.flipArg = -1;
m_video_out_ctx.m_flip_status.currentBuffer = -1;
m_video_out_ctx.m_flip_status.count = 0;
m_video_out_ctx.m_vblank_status = SceVideoOutVblankStatus();
return handle;
}
void VideoOutCtx::Close(s32 handle) {
Lib::LockMutexGuard lock(m_mutex);
m_video_out_ctx.isOpened = false;
if (m_video_out_ctx.m_flip_evtEq.size() > 0)
{
BREAKPOINT(); //we need to clear all events if they have been created
}
m_video_out_ctx.m_flip_rate = 0;
// clear buffers
for (auto& buffer : m_video_out_ctx.buffers) {
buffer.buffer = nullptr;
buffer.buffer_render = nullptr;
buffer.buffer_size = 0;
buffer.set_id = 0;
}
m_video_out_ctx.buffers_sets.clear();
m_video_out_ctx.buffers_registration_index = 0;
}
VideoConfigInternal* VideoOutCtx::getCtx(int handle) {
if (handle != 1) return nullptr;
return &m_video_out_ctx; // assuming that it's the only ctx TODO check if we need more
}
void FlipQueue::getFlipStatus(VideoConfigInternal* cfg, SceVideoOutFlipStatus* out) {
Lib::LockMutexGuard lock(m_mutex);
*out = cfg->m_flip_status;
}
bool FlipQueue::submitFlip(VideoConfigInternal* cfg, s32 index, s64 flip_arg) {
Lib::LockMutexGuard lock(m_mutex);
if (m_requests.size() >= 2) {
return false;
}
Request r{};
r.cfg = cfg;
r.index = index;
r.flip_arg = flip_arg;
r.submit_tsc = HLE::Libs::LibKernel::sceKernelReadTsc();
m_requests.push_back(r);
cfg->m_flip_status.flipPendingNum = static_cast<int>(m_requests.size());
cfg->m_flip_status.gcQueueNum = 0;
m_submit_cond.SignalCondVar();
return true;
}
bool FlipQueue::flip(u32 micros) {
m_mutex.LockMutex();
if (m_requests.size() == 0) {
m_submit_cond.WaitCondVarFor(&m_mutex, micros);
if (m_requests.size() == 0) {
m_mutex.UnlockMutex();
return false;
}
}
auto request = m_requests.at(0); // proceed first request
m_mutex.UnlockMutex();
auto* buffer = request.cfg->buffers[request.index].buffer_render;
Emu::DrawBuffer(buffer);
m_mutex.LockMutex();
request.cfg->m_mutex.LockMutex();
for (auto& flip_eq : request.cfg->m_flip_evtEq) {
if (flip_eq != nullptr) {
flip_eq->triggerEvent(SCE_VIDEO_OUT_EVENT_FLIP, HLE::Kernel::Objects::EVFILT_VIDEO_OUT, reinterpret_cast<void*>(request.flip_arg));
}
}
request.cfg->m_mutex.UnlockMutex();
m_requests.erase(m_requests.begin());
m_done_cond.SignalCondVar();
request.cfg->m_flip_status.count++;
//TODO request.cfg->m_flip_status.processTime = LibKernel::KernelGetProcessTime();
request.cfg->m_flip_status.tsc = HLE::Libs::LibKernel::sceKernelReadTsc();
request.cfg->m_flip_status.submitTsc = request.submit_tsc;
request.cfg->m_flip_status.flipArg = request.flip_arg;
request.cfg->m_flip_status.currentBuffer = request.index;
request.cfg->m_flip_status.flipPendingNum = static_cast<int>(m_requests.size());
m_mutex.UnlockMutex();
return false;
}
}; // namespace HLE::Graphics::Objects

View File

@@ -1,63 +0,0 @@
#pragma once
#include "graphics_ctx.h"
namespace GPU {
class CommandPool {
public:
CommandPool() = default;
~CommandPool() {}
HLE::Libs::Graphics::VulkanCommandPool* getPool(int id) {
if (m_pool[id] == nullptr) {
createPool(id);
}
return m_pool[id];
}
private:
void createPool(int id);
void deleteAllPool();
HLE::Libs::Graphics::VulkanCommandPool* m_pool[11] = {};
};
class CommandBuffer {
public:
explicit CommandBuffer(int queue) : m_queue(queue) { allocateBuffer(); }
virtual ~CommandBuffer() { freeBuffer(); }
void allocateBuffer();
void freeBuffer();
void waitForFence();
void begin() const;
void end() const;
void executeWithSemaphore();
void execute();
u32 getIndex() const { return m_index; }
HLE::Libs::Graphics::VulkanCommandPool* getPool() { return m_pool; }
private:
int m_queue = -1;
u32 m_index = static_cast<u32>(-1);
HLE::Libs::Graphics::VulkanCommandPool* m_pool = nullptr;
bool m_execute = false;
};
class Framebuffer {
public:
Framebuffer() {}
virtual ~Framebuffer() {}
};
class RenderCtx {
public:
RenderCtx() : m_framebuffer(new Framebuffer) {}
virtual ~RenderCtx() {}
void setGraphicCtx(HLE::Libs::Graphics::GraphicCtx* ctx) { m_graphic_ctx = ctx; }
HLE::Libs::Graphics::GraphicCtx* getGraphicCtx() { return m_graphic_ctx; }
private:
Framebuffer* m_framebuffer = nullptr;
HLE::Libs::Graphics::GraphicCtx* m_graphic_ctx = nullptr;
};
void renderCreateCtx();
}; // namespace GPU

View File

@@ -1,322 +0,0 @@
#include "video_out.h"
#include <Core/PS4/GPU/gpu_memory.h>
#include <Core/PS4/GPU/video_out_buffer.h>
#include <Core/PS4/HLE/ErrorCodes.h>
#include <Core/PS4/HLE/LibSceGnmDriver.h>
#include <Core/PS4/HLE/Libs.h>
#include <Core/PS4/HLE/UserManagement/UsrMngCodes.h>
#include <Util/config.h>
#include <Util/log.h>
#include <debug.h>
#include <stdio.h>
#include <magic_enum.hpp>
#include <string>
#include "Objects/video_out_ctx.h"
#include "Emulator/Util/singleton.h"
#include "emulator.h"
#include "graphics_render.h"
namespace HLE::Libs::Graphics::VideoOut {
constexpr bool log_file_videoout = true; // disable it to disable logging
void videoOutInit(u32 width, u32 height) {
auto* videoOut = singleton<HLE::Graphics::Objects::VideoOutCtx>::instance();
videoOut->Init(width, height);
}
bool videoOutFlip(u32 micros) {
auto* videoOut = singleton<HLE::Graphics::Objects::VideoOutCtx>::instance();
return videoOut->getFlipQueue().flip(micros);
}
std::string getPixelFormatString(s32 format) {
switch (format) {
case SCE_VIDEO_OUT_PIXEL_FORMAT_A8R8G8B8_SRGB: return "PIXEL_FORMAT_A8R8G8B8_SRGB";
case SCE_VIDEO_OUT_PIXEL_FORMAT_A8B8G8R8_SRGB: return "PIXEL_FORMAT_A8B8G8R8_SRGB";
case SCE_VIDEO_OUT_PIXEL_FORMAT_A2R10G10B10: return "PIXEL_FORMAT_A2R10G10B10";
case SCE_VIDEO_OUT_PIXEL_FORMAT_A2R10G10B10_SRGB: return "PIXEL_FORMAT_A2R10G10B10_SRGB";
case SCE_VIDEO_OUT_PIXEL_FORMAT_A2R10G10B10_BT2020_PQ: return "PIXEL_FORMAT_A2R10G10B10_BT2020_PQ";
case SCE_VIDEO_OUT_PIXEL_FORMAT_A16R16G16B16_FLOAT: return "PIXEL_FORMAT_A16R16G16B16_FLOAT";
case SCE_VIDEO_OUT_PIXEL_FORMAT_YCBCR420_BT709: return "PIXEL_FORMAT_YCBCR420_BT709";
default: return "Unknown pixel format";
}
}
void PS4_SYSV_ABI sceVideoOutSetBufferAttribute(SceVideoOutBufferAttribute* attribute, u32 pixelFormat, u32 tilingMode, u32 aspectRatio, u32 width,
u32 height, u32 pitchInPixel) {
PRINT_FUNCTION_NAME();
auto tileMode = magic_enum::enum_cast<SceVideoOutTilingMode>(tilingMode);
auto aspectR = magic_enum::enum_cast<AspectRatioMode>(aspectRatio);
LOG_INFO_IF(log_file_videoout, "pixelFormat = {}\n", getPixelFormatString(pixelFormat));
LOG_INFO_IF(log_file_videoout, "tilingMode = {}\n", magic_enum::enum_name(tileMode.value()));
LOG_INFO_IF(log_file_videoout, "aspectRatio = {}\n", magic_enum::enum_name(aspectR.value()));
LOG_INFO_IF(log_file_videoout, "width = {}\n", width);
LOG_INFO_IF(log_file_videoout, "height = {}\n", height);
LOG_INFO_IF(log_file_videoout, "pitchInPixel = {}\n", pitchInPixel);
memset(attribute, 0, sizeof(SceVideoOutBufferAttribute));
attribute->pixelFormat = pixelFormat;
attribute->tilingMode = tilingMode;
attribute->aspectRatio = aspectRatio;
attribute->width = width;
attribute->height = height;
attribute->pitchInPixel = pitchInPixel;
attribute->option = SCE_VIDEO_OUT_BUFFER_ATTRIBUTE_OPTION_NONE;
}
static void flip_reset_event_func(HLE::Kernel::Objects::EqueueEvent* event) {
event->isTriggered = false;
event->event.fflags = 0;
event->event.data = 0;
}
static void flip_trigger_event_func(HLE::Kernel::Objects::EqueueEvent* event, void* trigger_data) {
event->isTriggered = true;
event->event.fflags++;
event->event.data = reinterpret_cast<intptr_t>(trigger_data);
}
static void flip_delete_event_func(LibKernel::EventQueues::SceKernelEqueue eq, HLE::Kernel::Objects::EqueueEvent* event) {
BREAKPOINT(); // TODO
}
s32 PS4_SYSV_ABI sceVideoOutAddFlipEvent(LibKernel::EventQueues::SceKernelEqueue eq, s32 handle, void* udata) {
PRINT_FUNCTION_NAME();
auto* videoOut = singleton<HLE::Graphics::Objects::VideoOutCtx>::instance();
auto* ctx = videoOut->getCtx(handle);
if (ctx == nullptr) {
return SCE_VIDEO_OUT_ERROR_INVALID_HANDLE;
}
Lib::LockMutexGuard lock(ctx->m_mutex);
if (eq == nullptr) {
return SCE_VIDEO_OUT_ERROR_INVALID_EVENT_QUEUE;
}
HLE::Kernel::Objects::EqueueEvent event;
event.isTriggered = false;
event.event.ident = SCE_VIDEO_OUT_EVENT_FLIP;
event.event.filter = HLE::Kernel::Objects::EVFILT_VIDEO_OUT;
event.event.udata = udata;
event.event.fflags = 0;
event.event.data = 0;
event.filter.delete_event_func = flip_delete_event_func;
event.filter.reset_event_func = flip_reset_event_func;
event.filter.trigger_event_func = flip_trigger_event_func;
event.filter.data = ctx;
int result = eq->addEvent(event);
ctx->m_flip_evtEq.push_back(eq);
return result;
}
s32 PS4_SYSV_ABI sceVideoOutRegisterBuffers(s32 handle, s32 startIndex, void* const* addresses, s32 bufferNum,
const SceVideoOutBufferAttribute* attribute) {
PRINT_FUNCTION_NAME();
auto* videoOut = singleton<HLE::Graphics::Objects::VideoOutCtx>::instance();
auto* ctx = videoOut->getCtx(handle);
if (handle == 1) { // main port
if (startIndex < 0 || startIndex > 15) {
LOG_TRACE_IF(log_file_videoout, "invalid startIndex = {}\n", startIndex);
return SCE_VIDEO_OUT_ERROR_INVALID_VALUE;
}
if (bufferNum < 1 || bufferNum > 16) {
LOG_TRACE_IF(log_file_videoout, "invalid bufferNum = {}\n", bufferNum);
return SCE_VIDEO_OUT_ERROR_INVALID_VALUE;
}
}
if (addresses == nullptr) {
LOG_TRACE_IF(log_file_videoout, "addresses are null\n");
return SCE_VIDEO_OUT_ERROR_INVALID_ADDRESS;
}
if (attribute == nullptr) {
LOG_TRACE_IF(log_file_videoout, "attribute is null\n");
return SCE_VIDEO_OUT_ERROR_INVALID_OPTION;
}
if (attribute->aspectRatio != 0) {
LOG_TRACE_IF(log_file_videoout, "invalid aspect ratio = {}\n", attribute->aspectRatio);
return SCE_VIDEO_OUT_ERROR_INVALID_ASPECT_RATIO;
}
if (attribute->tilingMode < 0 || attribute->tilingMode > 1) {
LOG_TRACE_IF(log_file_videoout, "invalid tilingMode = {}\n", attribute->tilingMode);
return SCE_VIDEO_OUT_ERROR_INVALID_TILING_MODE;
}
LOG_INFO_IF(log_file_videoout, "startIndex = {}\n", startIndex);
LOG_INFO_IF(log_file_videoout, "bufferNum = {}\n", bufferNum);
LOG_INFO_IF(log_file_videoout, "pixelFormat = {}\n", log_hex_full(attribute->pixelFormat));
LOG_INFO_IF(log_file_videoout, "tilingMode = {}\n", attribute->tilingMode);
LOG_INFO_IF(log_file_videoout, "aspectRatio = {}\n", attribute->aspectRatio);
LOG_INFO_IF(log_file_videoout, "width = {}\n", attribute->width);
LOG_INFO_IF(log_file_videoout, "height = {}\n", attribute->height);
LOG_INFO_IF(log_file_videoout, "pitchInPixel = {}\n", attribute->pitchInPixel);
LOG_INFO_IF(log_file_videoout, "option = {}\n", attribute->option);
int registration_index = ctx->buffers_registration_index++;
Emu::checkAndWaitForGraphicsInit();
GPU::renderCreateCtx();
// try to calculate buffer size
u64 buffer_size = 0; // still calculation is probably partial or wrong :D
if (attribute->tilingMode == 0) {
buffer_size = 1920 * 1088 * 4;
} else {
buffer_size = 1920 * 1080 * 4;
}
u64 buffer_pitch = attribute->pitchInPixel;
VideoOutBufferSetInternal buf{};
buf.start_index = startIndex;
buf.num = bufferNum;
buf.set_id = registration_index;
buf.attr = *attribute;
ctx->buffers_sets.push_back(buf);
GPU::VideoOutBufferFormat format = GPU::VideoOutBufferFormat::Unknown;
if (attribute->pixelFormat == 0x80000000) {
format = GPU::VideoOutBufferFormat::B8G8R8A8Srgb;
} else if (attribute->pixelFormat == 0x80002200) {
format = GPU::VideoOutBufferFormat::R8G8B8A8Srgb;
}
GPU::VideoOutBufferObj buffer_info(format, attribute->width, attribute->height, attribute->tilingMode == 0, Config::isNeoMode(), buffer_pitch);
for (int i = 0; i < bufferNum; i++) {
if (ctx->buffers[i + startIndex].buffer != nullptr) {
LOG_TRACE_IF(log_file_videoout, "buffer slot {} is occupied!\n", i + startIndex);
return SCE_VIDEO_OUT_ERROR_SLOT_OCCUPIED;
}
ctx->buffers[i + startIndex].set_id = registration_index;
ctx->buffers[i + startIndex].buffer = addresses[i];
ctx->buffers[i + startIndex].buffer_size = buffer_size;
ctx->buffers[i + startIndex].buffer_pitch = buffer_pitch;
ctx->buffers[i + startIndex].buffer_render = static_cast<Graphics::VideoOutVulkanImage*>(
GPU::memoryCreateObj(0, videoOut->getGraphicCtx(), nullptr, reinterpret_cast<uint64_t>(addresses[i]), buffer_size, buffer_info));
LOG_INFO_IF(log_file_videoout, "buffers[{}] = {}\n", i + startIndex, log_hex_full(reinterpret_cast<uint64_t>(addresses[i])));
}
return registration_index;
}
s32 PS4_SYSV_ABI sceVideoOutSetFlipRate(s32 handle, s32 rate) {
PRINT_FUNCTION_NAME();
auto* videoOut = singleton<HLE::Graphics::Objects::VideoOutCtx>::instance();
videoOut->getCtx(handle)->m_flip_rate = rate;
return SCE_OK;
}
s32 PS4_SYSV_ABI sceVideoOutIsFlipPending(s32 handle) {
PRINT_FUNCTION_NAME();
auto* videoOut = singleton<HLE::Graphics::Objects::VideoOutCtx>::instance();
s32 pending = videoOut->getCtx(handle)->m_flip_status.flipPendingNum;
return pending;
}
s32 PS4_SYSV_ABI sceVideoOutSubmitFlip(s32 handle, s32 bufferIndex, s32 flipMode, s64 flipArg) {
PRINT_FUNCTION_NAME();
auto* videoOut = singleton<HLE::Graphics::Objects::VideoOutCtx>::instance();
auto* ctx = videoOut->getCtx(handle);
if (flipMode != 1) {
// BREAKPOINT(); // only flipmode==1 is supported
LOG_TRACE_IF(log_file_videoout, "sceVideoOutSubmitFlip flipmode {}\n", bufferIndex);//openBOR needs 2 but seems to work
}
if (bufferIndex == -1) {
BREAKPOINT(); // blank output not supported
}
if (bufferIndex < -1 || bufferIndex > 15) {
LOG_TRACE_IF(log_file_videoout, "sceVideoOutSubmitFlip invalid bufferIndex {}\n", bufferIndex);
return SCE_VIDEO_OUT_ERROR_INVALID_INDEX;
}
LOG_INFO_IF(log_file_videoout, "bufferIndex = {}\n", bufferIndex);
LOG_INFO_IF(log_file_videoout, "flipMode = {}\n", flipMode);
LOG_INFO_IF(log_file_videoout, "flipArg = {}\n", flipArg);
if (!videoOut->getFlipQueue().submitFlip(ctx, bufferIndex, flipArg)) {
LOG_TRACE_IF(log_file_videoout, "sceVideoOutSubmitFlip flip queue is full\n");
return SCE_VIDEO_OUT_ERROR_FLIP_QUEUE_FULL;
}
HLE::Libs::LibSceGnmDriver::sceGnmFlushGarlic(); // hackish should be done that neccesary for niko's homebrew
return SCE_OK;
}
s32 PS4_SYSV_ABI sceVideoOutGetFlipStatus(s32 handle, SceVideoOutFlipStatus* status) {
PRINT_FUNCTION_NAME();
auto* videoOut = singleton<HLE::Graphics::Objects::VideoOutCtx>::instance();
auto* ctx = videoOut->getCtx(handle);
videoOut->getFlipQueue().getFlipStatus(ctx, status);
LOG_INFO_IF(log_file_videoout, "count = {}\n", status->count);
LOG_INFO_IF(log_file_videoout, "processTime = {}\n", status->processTime);
LOG_INFO_IF(log_file_videoout, "tsc = {}\n", status->tsc);
LOG_INFO_IF(log_file_videoout, "submitTsc = {}\n", status->submitTsc);
LOG_INFO_IF(log_file_videoout, "flipArg = {}\n", status->flipArg);
LOG_INFO_IF(log_file_videoout, "gcQueueNum = {}\n", status->gcQueueNum);
LOG_INFO_IF(log_file_videoout, "flipPendingNum = {}\n", status->flipPendingNum);
LOG_INFO_IF(log_file_videoout, "currentBuffer = {}\n", status->currentBuffer);
return 0;
}
s32 PS4_SYSV_ABI sceVideoOutGetResolutionStatus(s32 handle, SceVideoOutResolutionStatus* status) {
PRINT_FUNCTION_NAME();
auto* videoOut = singleton<HLE::Graphics::Objects::VideoOutCtx>::instance();
*status = videoOut->getCtx(handle)->m_resolution;
return SCE_OK;
}
s32 PS4_SYSV_ABI sceVideoOutOpen(SceUserServiceUserId userId, s32 busType, s32 index, const void* param) {
PRINT_FUNCTION_NAME();
if (userId != SCE_USER_SERVICE_USER_ID_SYSTEM && userId != 0) {
BREAKPOINT();
}
if (busType != SCE_VIDEO_OUT_BUS_TYPE_MAIN) {
BREAKPOINT();
}
if (index != 0) {
LOG_TRACE_IF(log_file_videoout, "sceVideoOutOpen index!=0\n");
return SCE_VIDEO_OUT_ERROR_INVALID_VALUE;
}
if (param != nullptr) {
BREAKPOINT();
}
auto* videoOut = singleton<HLE::Graphics::Objects::VideoOutCtx>::instance();
int handle = videoOut->Open();
if (handle < 0) {
LOG_TRACE_IF(log_file_videoout, "sceVideoOutOpen all available handles are open\n");
return SCE_VIDEO_OUT_ERROR_RESOURCE_BUSY; // it is alreadyOpened
}
return handle;
}
s32 PS4_SYSV_ABI sceVideoOutClose(s32 handle) {
auto* videoOut = singleton<HLE::Graphics::Objects::VideoOutCtx>::instance();
videoOut->Close(handle);
return SCE_OK;
}
s32 PS4_SYSV_ABI sceVideoOutUnregisterBuffers(s32 handle, s32 attributeIndex) { BREAKPOINT(); }
void videoOutRegisterLib(SymbolsResolver* sym) {
LIB_FUNCTION("SbU3dwp80lQ", "libSceVideoOut", 1, "libSceVideoOut", 0, 0, sceVideoOutGetFlipStatus);
LIB_FUNCTION("U46NwOiJpys", "libSceVideoOut", 1, "libSceVideoOut", 0, 0, sceVideoOutSubmitFlip);
LIB_FUNCTION("w3BY+tAEiQY", "libSceVideoOut", 1, "libSceVideoOut", 0, 0, sceVideoOutRegisterBuffers);
LIB_FUNCTION("HXzjK9yI30k", "libSceVideoOut", 1, "libSceVideoOut", 0, 0, sceVideoOutAddFlipEvent);
LIB_FUNCTION("CBiu4mCE1DA", "libSceVideoOut", 1, "libSceVideoOut", 0, 0, sceVideoOutSetFlipRate);
LIB_FUNCTION("i6-sR91Wt-4", "libSceVideoOut", 1, "libSceVideoOut", 0, 0, sceVideoOutSetBufferAttribute);
LIB_FUNCTION("6kPnj51T62Y", "libSceVideoOut", 1, "libSceVideoOut", 0, 0, sceVideoOutGetResolutionStatus);
LIB_FUNCTION("Up36PTk687E", "libSceVideoOut", 1, "libSceVideoOut", 0, 0, sceVideoOutOpen);
LIB_FUNCTION("zgXifHT9ErY", "libSceVideoOut", 1, "libSceVideoOut", 0, 0, sceVideoOutIsFlipPending);
LIB_FUNCTION("N5KDtkIjjJ4", "libSceVideoOut", 1, "libSceVideoOut", 0, 0, sceVideoOutUnregisterBuffers);
LIB_FUNCTION("uquVH4-Du78", "libSceVideoOut", 1, "libSceVideoOut", 0, 0, sceVideoOutClose);
}
} // namespace HLE::Libs::Graphics::VideoOut

View File

@@ -1,125 +0,0 @@
#include "ThreadManagement.h"
#include <debug.h>
#include "../ErrorCodes.h"
namespace HLE::Libs::LibKernel::ThreadManagement {
thread_local PthreadInternal* g_pthread_self = nullptr;
PThreadCxt* g_pthread_cxt = nullptr;
void Pthread_Init_Self_MainThread() {
g_pthread_self = new PthreadInternal{};
scePthreadAttrInit(&g_pthread_self->attr);
g_pthread_self->pth = pthread_self();
g_pthread_self->name = "Main_Thread";
}
int scePthreadAttrInit(ScePthreadAttr* attr) {
*attr = new PthreadAttrInternal{};
int result = pthread_attr_init(&(*attr)->pth_attr);
(*attr)->affinity = 0x7f;
(*attr)->guard_size = 0x1000;
SceKernelSchedParam param{};
param.sched_priority = 700;
result = (result == 0 ? scePthreadAttrSetinheritsched(attr, 4) : result);
result = (result == 0 ? scePthreadAttrSetschedparam(attr, &param) : result);
result = (result == 0 ? scePthreadAttrSetschedpolicy(attr, SCHED_OTHER) : result);
result = (result == 0 ? scePthreadAttrSetdetachstate(attr, PTHREAD_CREATE_JOINABLE) : result);
switch (result) {
case 0: return SCE_OK;
case ENOMEM: return SCE_KERNEL_ERROR_ENOMEM;
default: return SCE_KERNEL_ERROR_EINVAL;
}
}
int scePthreadAttrSetdetachstate(ScePthreadAttr* attr, int detachstate) {
if (attr == nullptr || *attr == nullptr) {
return SCE_KERNEL_ERROR_EINVAL;
}
int pstate = PTHREAD_CREATE_JOINABLE;
switch (detachstate) {
case 0: pstate = PTHREAD_CREATE_JOINABLE; break;
case 1: pstate = PTHREAD_CREATE_DETACHED; break;
default: BREAKPOINT(); // unknown state
}
int result = pthread_attr_setdetachstate(&(*attr)->pth_attr, pstate);
(*attr)->detached = (pstate == PTHREAD_CREATE_DETACHED);
if (result == 0) {
return SCE_OK;
}
return SCE_KERNEL_ERROR_EINVAL;
}
int scePthreadAttrSetinheritsched(ScePthreadAttr* attr, int inheritSched) {
if (attr == nullptr || *attr == nullptr) {
return SCE_KERNEL_ERROR_EINVAL;
}
int pinherit_sched = PTHREAD_INHERIT_SCHED;
switch (inheritSched) {
case 0: pinherit_sched = PTHREAD_EXPLICIT_SCHED; break;
case 4: pinherit_sched = PTHREAD_INHERIT_SCHED; break;
default: BREAKPOINT(); // unknown inheritSched
}
int result = pthread_attr_setinheritsched(&(*attr)->pth_attr, pinherit_sched);
if (result == 0) {
return SCE_OK;
}
return SCE_KERNEL_ERROR_EINVAL;
}
int scePthreadAttrSetschedparam(ScePthreadAttr* attr, const SceKernelSchedParam* param) {
if (param == nullptr || attr == nullptr || *attr == nullptr) {
return SCE_KERNEL_ERROR_EINVAL;
}
SceKernelSchedParam pparam{};
if (param->sched_priority <= 478) {
pparam.sched_priority = +2;
} else if (param->sched_priority >= 733) {
pparam.sched_priority = -2;
} else {
pparam.sched_priority = 0;
}
int result = pthread_attr_setschedparam(&(*attr)->pth_attr, &pparam);
if (result == 0) {
return SCE_OK;
}
return SCE_KERNEL_ERROR_EINVAL;
}
int scePthreadAttrSetschedpolicy(ScePthreadAttr* attr, int policy) {
if (attr == nullptr || *attr == nullptr) {
return SCE_KERNEL_ERROR_EINVAL;
}
if (policy != SCHED_OTHER) {
BREAKPOINT(); // invest if policy is other and if winpthreadlibrary support it
}
(*attr)->policy = policy;
int result = pthread_attr_setschedpolicy(&(*attr)->pth_attr, policy);
if (result == 0) {
return SCE_OK;
}
return SCE_KERNEL_ERROR_EINVAL;
}
}; // namespace HLE::Libs::LibKernel::ThreadManagement

View File

@@ -1,42 +0,0 @@
#pragma once
#define _TIMESPEC_DEFINED
#include <pthread.h>
#include <sched.h>
#include "../../../../types.h"
#include <string>
namespace HLE::Libs::LibKernel::ThreadManagement {
struct PthreadAttrInternal;
using SceKernelSchedParam = ::sched_param;
using ScePthreadAttr = PthreadAttrInternal*;
struct PthreadInternal {
u08 reserved[4096];
std::string name;
pthread_t pth;
ScePthreadAttr attr;
};
struct PthreadAttrInternal {
u08 reserved[64];
u64 affinity;
size_t guard_size;
int policy;
bool detached;
pthread_attr_t pth_attr;
};
class PThreadCxt {};
void Pthread_Init_Self_MainThread();
//HLE FUNCTIONS
int scePthreadAttrInit(ScePthreadAttr* attr);
int scePthreadAttrSetdetachstate(ScePthreadAttr* attr, int detachstate);
int scePthreadAttrSetinheritsched(ScePthreadAttr* attr, int inheritSched);
int scePthreadAttrSetschedparam(ScePthreadAttr* attr, const SceKernelSchedParam* param);
int scePthreadAttrSetschedpolicy(ScePthreadAttr* attr, int policy);
} // namespace HLE::Libs::LibKernel::ThreadManagement

View File

@@ -1,13 +0,0 @@
#include "cpu_management.h"
#include "Util/config.h"
#include <Util/log.h>
#include <Core/PS4/HLE/Libs.h>
namespace HLE::Libs::LibKernel::CPUManagement {
int PS4_SYSV_ABI sceKernelIsNeoMode() {
PRINT_FUNCTION_NAME();
bool isNeo = Config::isNeoMode();
return isNeo ? 1 : 0;
}
}; // namespace HLE::Libs::LibKernel::CPUManagement

View File

@@ -1,6 +0,0 @@
#pragma once
#include <types.h>
namespace HLE::Libs::LibKernel::CPUManagement {
int PS4_SYSV_ABI sceKernelIsNeoMode();
};

View File

@@ -1,66 +0,0 @@
#include "event_queues.h"
#include <Core/PS4/HLE/ErrorCodes.h>
#include <Core/PS4/HLE/Libs.h>
#include <Util/log.h>
#include <debug.h>
namespace HLE::Libs::LibKernel::EventQueues {
constexpr bool log_file_equeues = true; // disable it to disable logging
int PS4_SYSV_ABI sceKernelCreateEqueue(SceKernelEqueue* eq, const char* name) {
PRINT_FUNCTION_NAME();
if (eq == nullptr) {
LOG_TRACE_IF(log_file_equeues, "sceKernelCreateEqueue returned SCE_KERNEL_ERROR_EINVAL eq invalid\n");
return SCE_KERNEL_ERROR_EINVAL;
}
if (name == nullptr) {
LOG_TRACE_IF(log_file_equeues, "sceKernelCreateEqueue returned SCE_KERNEL_ERROR_EFAULT name invalid\n");
return SCE_KERNEL_ERROR_EFAULT;
}
if (name == NULL) {
LOG_TRACE_IF(log_file_equeues, "sceKernelCreateEqueue returned SCE_KERNEL_ERROR_EINVAL name is null\n");
return SCE_KERNEL_ERROR_EINVAL;
}
if (strlen(name) > 31) { // max is 32 including null terminator
LOG_TRACE_IF(log_file_equeues, "sceKernelCreateEqueue returned SCE_KERNEL_ERROR_ENAMETOOLONG name size exceeds 32 bytes\n");
return SCE_KERNEL_ERROR_ENAMETOOLONG;
}
*eq = new Kernel::Objects::EqueueInternal;
(*eq)->setName(std::string(name));
LOG_INFO_IF(log_file_equeues, "sceKernelCreateEqueue created with name \"{}\"\n", name);
return SCE_OK;
}
int PS4_SYSV_ABI sceKernelWaitEqueue(SceKernelEqueue eq, HLE::Kernel::Objects::SceKernelEvent* ev, int num, int* out, SceKernelUseconds* timo) {
PRINT_FUNCTION_NAME();
if (eq == nullptr) {
return SCE_KERNEL_ERROR_EBADF;
}
if (ev == nullptr) {
return SCE_KERNEL_ERROR_EFAULT;
}
if (num < 1) {
return SCE_KERNEL_ERROR_EINVAL;
}
if (timo == nullptr) { // wait until an event arrives without timing out
*out = eq->waitForEvents(ev, num, 0);
}
if (timo != nullptr) {
if (*timo == 0) {//only events that have already arrived at the time of this function call can be received
BREAKPOINT();
} else { // wait until an event arrives with timing out
BREAKPOINT();
}
}
return SCE_OK;
}
}; // namespace HLE::Libs::LibKernel::EventQueues

View File

@@ -1,14 +0,0 @@
#pragma once
#include <types.h>
#include "Objects/event_queue.h"
namespace HLE::Libs::LibKernel::EventQueues {
using SceKernelUseconds = u32;
using SceKernelEqueue = Kernel::Objects::EqueueInternal*;
int PS4_SYSV_ABI sceKernelCreateEqueue(SceKernelEqueue* eq, const char* name);
int PS4_SYSV_ABI sceKernelWaitEqueue(SceKernelEqueue eq, HLE::Kernel::Objects::SceKernelEvent* ev, int num, int* out, SceKernelUseconds *timo);
}; // namespace HLE::Libs::LibKernel::EventQueues

View File

@@ -1,129 +0,0 @@
#include "memory_management.h"
#include <Core/PS4/GPU/gpu_memory.h>
#include <Core/virtual_memory.h>
#include <Util/log.h>
#include <debug.h>
#include <bit>
#include <magic_enum.hpp>
#include "Emulator/Util/singleton.h"
#include "../ErrorCodes.h"
#include "../Libs.h"
#include "Objects/physical_memory.h"
namespace HLE::Libs::LibKernel::MemoryManagement {
constexpr bool log_file_memory = true; // disable it to disable logging
bool isPowerOfTwo(u64 n) { return std::popcount(n) == 1; }
bool is16KBAligned(u64 n) { return ((n % (16ull * 1024) == 0)); }
u64 PS4_SYSV_ABI sceKernelGetDirectMemorySize() {
PRINT_FUNCTION_NAME();
return SCE_KERNEL_MAIN_DMEM_SIZE;
}
int PS4_SYSV_ABI sceKernelAllocateDirectMemory(s64 searchStart, s64 searchEnd, u64 len, u64 alignment, int memoryType, s64* physAddrOut) {
PRINT_FUNCTION_NAME();
if (searchStart < 0 || searchEnd <= searchStart) {
LOG_TRACE_IF(log_file_memory, "sceKernelAllocateDirectMemory returned SCE_KERNEL_ERROR_EINVAL searchStart,searchEnd invalid\n");
return SCE_KERNEL_ERROR_EINVAL;
}
bool isInRange = (searchStart < len && searchEnd > len);
if (len <= 0 || !is16KBAligned(len) || !isInRange) {
LOG_TRACE_IF(log_file_memory, "sceKernelAllocateDirectMemory returned SCE_KERNEL_ERROR_EINVAL memory range invalid\n");
return SCE_KERNEL_ERROR_EINVAL;
}
if ((alignment != 0 || is16KBAligned(alignment)) && !isPowerOfTwo(alignment)) {
LOG_TRACE_IF(log_file_memory, "sceKernelAllocateDirectMemory returned SCE_KERNEL_ERROR_EINVAL alignment invalid\n");
return SCE_KERNEL_ERROR_EINVAL;
}
if (physAddrOut == nullptr) {
LOG_TRACE_IF(log_file_memory, "sceKernelAllocateDirectMemory returned SCE_KERNEL_ERROR_EINVAL physAddrOut is null\n");
return SCE_KERNEL_ERROR_EINVAL;
}
auto memtype = magic_enum::enum_cast<MemoryTypes>(memoryType);
LOG_INFO_IF(log_file_memory, "search_start = {}\n", log_hex_full(searchStart));
LOG_INFO_IF(log_file_memory, "search_end = {}\n", log_hex_full(searchEnd));
LOG_INFO_IF(log_file_memory, "len = {}\n", log_hex_full(len));
LOG_INFO_IF(log_file_memory, "alignment = {}\n", log_hex_full(alignment));
LOG_INFO_IF(log_file_memory, "memory_type = {}\n", magic_enum::enum_name(memtype.value()));
u64 physical_addr = 0;
auto* physical_memory = singleton<HLE::Kernel::Objects::PhysicalMemory>::instance();
if (!physical_memory->Alloc(searchStart, searchEnd, len, alignment, &physical_addr, memoryType)) {
LOG_TRACE_IF(log_file_memory, "sceKernelAllocateDirectMemory returned SCE_KERNEL_ERROR_EAGAIN can't allocate physical memory\n");
return SCE_KERNEL_ERROR_EAGAIN;
}
*physAddrOut = static_cast<s64>(physical_addr);
LOG_INFO_IF(true, "physAddrOut = {}\n", log_hex_full(physical_addr));
return SCE_OK;
}
int PS4_SYSV_ABI sceKernelMapDirectMemory(void** addr, u64 len, int prot, int flags, s64 directMemoryStart, u64 alignment) {
PRINT_FUNCTION_NAME();
if (len == 0 || !is16KBAligned(len)) {
LOG_TRACE_IF(log_file_memory, "sceKernelMapDirectMemory returned SCE_KERNEL_ERROR_EINVAL len invalid\n");
return SCE_KERNEL_ERROR_EINVAL;
}
if (!is16KBAligned(directMemoryStart)) {
LOG_TRACE_IF(log_file_memory, "sceKernelMapDirectMemory returned SCE_KERNEL_ERROR_EINVAL directMemoryStart invalid\n");
return SCE_KERNEL_ERROR_EINVAL;
}
if (alignment != 0) {
if ((!isPowerOfTwo(alignment) && !is16KBAligned(alignment))) {
LOG_TRACE_IF(log_file_memory, "sceKernelMapDirectMemory returned SCE_KERNEL_ERROR_EINVAL alignment invalid\n");
return SCE_KERNEL_ERROR_EINVAL;
}
}
LOG_INFO_IF(log_file_memory, "len = {}\n", log_hex_full(len));
LOG_INFO_IF(log_file_memory, "prot = {}\n", log_hex_full(prot));
LOG_INFO_IF(log_file_memory, "flags = {}\n", log_hex_full(flags));
LOG_INFO_IF(log_file_memory, "directMemoryStart = {}\n", log_hex_full(directMemoryStart));
LOG_INFO_IF(log_file_memory, "alignment = {}\n", log_hex_full(alignment));
VirtualMemory::MemoryMode cpu_mode = VirtualMemory::MemoryMode::NoAccess;
GPU::MemoryMode gpu_mode = GPU::MemoryMode::NoAccess;
switch (prot) {
case 0x32:
case 0x33: // SCE_KERNEL_PROT_CPU_READ|SCE_KERNEL_PROT_CPU_WRITE|SCE_KERNEL_PROT_GPU_READ|SCE_KERNEL_PROT_GPU_ALL
cpu_mode = VirtualMemory::MemoryMode::ReadWrite;
gpu_mode = GPU::MemoryMode::ReadWrite;
break;
default: BREAKPOINT();
}
auto in_addr = reinterpret_cast<u64>(*addr);
u64 out_addr = 0;
if (flags == 0) {
out_addr = VirtualMemory::memory_alloc_aligned(in_addr, len, cpu_mode, alignment);
}
LOG_INFO_IF(log_file_memory, "in_addr = {}\n", log_hex_full(in_addr));
LOG_INFO_IF(log_file_memory, "out_addr = {}\n", log_hex_full(out_addr));
*addr = reinterpret_cast<void*>(out_addr); // return out_addr to first functions parameter
if (out_addr == 0) {
return SCE_KERNEL_ERROR_ENOMEM;
}
auto* physical_memory = singleton<HLE::Kernel::Objects::PhysicalMemory>::instance();
if (!physical_memory->Map(out_addr, directMemoryStart, len, prot, cpu_mode, gpu_mode)) {
BREAKPOINT();
}
if (gpu_mode != GPU::MemoryMode::NoAccess) {
GPU::memorySetAllocArea(out_addr, len);
}
return SCE_OK;
}
} // namespace HLE::Libs::LibKernel::MemoryManagement

View File

@@ -1,36 +0,0 @@
#pragma once
#include <types.h>
// constants
constexpr u64 SCE_KERNEL_MAIN_DMEM_SIZE = 5376_MB; // ~ 6GB
namespace HLE::Libs::LibKernel::MemoryManagement {
// memory types
enum MemoryTypes : u32 {
SCE_KERNEL_WB_ONION = 0, // write - back mode (Onion bus)
SCE_KERNEL_WC_GARLIC = 3, // write - combining mode (Garlic bus)
SCE_KERNEL_WB_GARLIC = 10 // write - back mode (Garlic bus)
};
enum MemoryFlags : u32 {
SCE_KERNEL_MAP_FIXED = 0x0010, // Fixed
SCE_KERNEL_MAP_NO_OVERWRITE = 0x0080,
SCE_KERNEL_MAP_NO_COALESCE = 0x400000
};
enum MemoryProtection : u32 {
SCE_KERNEL_PROT_CPU_READ = 0x01, // Permit reads from the CPU
SCE_KERNEL_PROT_CPU_RW = 0x02, // Permit reads/writes from the CPU
SCE_KERNEL_PROT_CPU_WRITE = 0x02, // Permit reads/writes from the CPU (same)
SCE_KERNEL_PROT_GPU_READ = 0x10, // Permit reads from the GPU
SCE_KERNEL_PROT_GPU_WRITE = 0x20, // Permit writes from the GPU
SCE_KERNEL_PROT_GPU_RW = 0x30 // Permit reads/writes from the GPU
};
u64 PS4_SYSV_ABI sceKernelGetDirectMemorySize();
int PS4_SYSV_ABI sceKernelAllocateDirectMemory(s64 searchStart, s64 searchEnd, u64 len, u64 alignment, int memoryType, s64* physAddrOut);
int PS4_SYSV_ABI sceKernelMapDirectMemory(void** addr, u64 len, int prot, int flags, s64 directMemoryStart, u64 alignment);
}; // namespace HLE::Libs::LibKernel::MemoryManagement

View File

@@ -1,98 +0,0 @@
#include "LibC.h"
#include <debug.h>
#include <pthread.h>
#include "../Loader/Elf.h"
#include "Emulator/HLE/Libraries/LibC/libc.h"
#include "Emulator/HLE/Libraries/LibC/libc_cxa.h"
#include "ErrorCodes.h"
#include "Libs.h"
namespace HLE::Libs::LibC {
static u32 g_need_sceLibc = 1;
static PS4_SYSV_ABI void init_env() // every game/demo should probably
{
// dummy no need atm
}
static PS4_SYSV_ABI void catchReturnFromMain(int status) {
// dummy
}
static PS4_SYSV_ABI void _Assert() { BREAKPOINT(); }
PS4_SYSV_ABI int puts(const char* s) {
std::puts(s);
return SCE_OK;
}
PS4_SYSV_ABI int rand() { return std::rand(); }
PS4_SYSV_ABI void _ZdlPv(void* ptr) { std::free(ptr); }
PS4_SYSV_ABI void _ZSt11_Xbad_allocv() { BREAKPOINT(); }
PS4_SYSV_ABI void _ZSt14_Xlength_errorPKc() { BREAKPOINT(); }
PS4_SYSV_ABI void* _Znwm(u64 count) {
if (count == 0) {
BREAKPOINT();
}
void* ptr = std::malloc(count);
return ptr;
}
float PS4_SYSV_ABI _Fsin(float arg) { return std::sinf(arg); }
typedef int(PS4_SYSV_ABI* pfunc_QsortCmp)(const void*, const void*);
thread_local static pfunc_QsortCmp compair_ps4;
int qsort_compair(const void* arg1, const void* arg2) { return compair_ps4(arg1, arg2); }
void PS4_SYSV_ABI qsort(void* ptr, size_t count,size_t size, int(PS4_SYSV_ABI* comp)(const void*, const void*)) {
compair_ps4 = comp;
std::qsort(ptr, count, size, qsort_compair);
}
void LibC_Register(SymbolsResolver* sym) {
LIB_FUNCTION("bzQExy189ZI", "libc", 1, "libc", 1, 1, init_env);
LIB_FUNCTION("3GPpjQdAMTw", "libc", 1, "libc", 1, 1, Emulator::HLE::Libraries::LibC::Cxa::__cxa_guard_acquire);
LIB_FUNCTION("9rAeANT2tyE", "libc", 1, "libc", 1, 1, Emulator::HLE::Libraries::LibC::Cxa::__cxa_guard_release);
LIB_FUNCTION("2emaaluWzUw", "libc", 1, "libc", 1, 1, Emulator::HLE::Libraries::LibC::Cxa::__cxa_guard_abort);
LIB_FUNCTION("DfivPArhucg", "libc", 1, "libc", 1, 1, Emulator::HLE::Libraries::LibC::memcmp);
LIB_FUNCTION("Q3VBxCXhUHs", "libc", 1, "libc", 1, 1, Emulator::HLE::Libraries::LibC::memcpy);
LIB_FUNCTION("8zTFvBIAIN8", "libc", 1, "libc", 1, 1, Emulator::HLE::Libraries::LibC::memset);
LIB_FUNCTION("XKRegsFpEpk", "libc", 1, "libc", 1, 1, catchReturnFromMain);
LIB_FUNCTION("uMei1W9uyNo", "libc", 1, "libc", 1, 1, Emulator::HLE::Libraries::LibC::exit);
LIB_FUNCTION("8G2LB+A3rzg", "libc", 1, "libc", 1, 1, Emulator::HLE::Libraries::LibC::atexit);
LIB_FUNCTION("-QgqOT5u2Vk", "libc", 1, "libc", 1, 1, _Assert);
LIB_FUNCTION("hcuQgD53UxM", "libc", 1, "libc", 1, 1, Emulator::HLE::Libraries::LibC::printf);
LIB_FUNCTION("Q2V+iqvjgC0", "libc", 1, "libc", 1, 1, Emulator::HLE::Libraries::LibC::vsnprintf);
LIB_FUNCTION("YQ0navp+YIc", "libc", 1, "libc", 1, 1, puts);
LIB_FUNCTION("cpCOXWMgha0", "libc", 1, "libc", 1, 1, rand);
LIB_FUNCTION("ZtjspkJQ+vw", "libc", 1, "libc", 1, 1, _Fsin);
LIB_FUNCTION("AEJdIVZTEmo", "libc", 1, "libc", 1, 1, qsort);
LIB_FUNCTION("Ovb2dSJOAuE", "libc", 1, "libc", 1, 1, Emulator::HLE::Libraries::LibC::strcmp);
LIB_FUNCTION("gQX+4GDQjpM", "libc", 1, "libc", 1, 1, Emulator::HLE::Libraries::LibC::malloc);
LIB_FUNCTION("tIhsqj0qsFE", "libc", 1, "libc", 1, 1, Emulator::HLE::Libraries::LibC::free);
LIB_FUNCTION("j4ViWNHEgww", "libc", 1, "libc", 1, 1, Emulator::HLE::Libraries::LibC::strlen);
LIB_FUNCTION("6sJWiWSRuqk", "libc", 1, "libc", 1, 1, Emulator::HLE::Libraries::LibC::strncpy);
LIB_FUNCTION("+P6FRGH4LfA", "libc", 1, "libc", 1, 1, Emulator::HLE::Libraries::LibC::memmove);
LIB_FUNCTION("kiZSXIWd9vg", "libc", 1, "libc", 1, 1, Emulator::HLE::Libraries::LibC::strcpy);
LIB_FUNCTION("Ls4tzzhimqQ", "libc", 1, "libc", 1, 1, Emulator::HLE::Libraries::LibC::strcat);
LIB_FUNCTION("EH-x713A99c", "libc", 1, "libc", 1, 1, Emulator::HLE::Libraries::LibC::atan2f);
LIB_FUNCTION("QI-x0SL8jhw", "libc", 1, "libc", 1, 1, Emulator::HLE::Libraries::LibC::acosf);
LIB_FUNCTION("ZE6RNL+eLbk", "libc", 1, "libc", 1, 1, Emulator::HLE::Libraries::LibC::tanf);
LIB_FUNCTION("GZWjF-YIFFk", "libc", 1, "libc", 1, 1, Emulator::HLE::Libraries::LibC::asinf);
LIB_FUNCTION("9LCjpWyQ5Zc", "libc", 1, "libc", 1, 1, Emulator::HLE::Libraries::LibC::pow);
LIB_FUNCTION("cCXjU72Z0Ow", "libc", 1, "libc", 1, 1, Emulator::HLE::Libraries::LibC::_Sin);
LIB_OBJ("P330P3dFF68", "libc", 1, "libc", 1, 1, &HLE::Libs::LibC::g_need_sceLibc);
LIB_FUNCTION("z+P+xCnWLBk", "libc", 1, "libc", 1, 1, _ZdlPv);
LIB_FUNCTION("eT2UsmTewbU", "libc", 1, "libc", 1, 1, _ZSt11_Xbad_allocv);
LIB_FUNCTION("tQIo+GIPklo", "libc", 1, "libc", 1, 1, _ZSt14_Xlength_errorPKc);
LIB_FUNCTION("fJnpuVVBbKk", "libc", 1, "libc", 1, 1, _Znwm);
}
}; // namespace HLE::Libs::LibC

View File

@@ -1,13 +0,0 @@
#pragma once
#include "../Loader/SymbolsResolver.h"
namespace HLE::Libs::LibC {
void LibC_Register(SymbolsResolver* sym);
//functions
static PS4_SYSV_ABI void init_env();
static PS4_SYSV_ABI void _Assert();
static PS4_SYSV_ABI void catchReturnFromMain(int status);
};

View File

@@ -1,54 +0,0 @@
#include "LibKernel.h"
#include <Util/log.h>
#include <debug.h>
#include "Emulator/Util/singleton.h"
#include "../Loader/Elf.h"
#include "Kernel/Objects/physical_memory.h"
#include "Kernel/cpu_management.h"
#include "Kernel/event_queues.h"
#include "Kernel/memory_management.h"
#include "Libs.h"
#include "Emulator/HLE/Libraries/LibKernel/FileSystem/file_system.h"
#include "Emulator/HLE/Libraries/LibKernel/FileSystem/posix_file_system.h"
namespace HLE::Libs::LibKernel {
static u64 g_stack_chk_guard = 0xDEADBEEF54321ABC; // dummy return
int32_t PS4_SYSV_ABI sceKernelReleaseDirectMemory(off_t start, size_t len) {
BREAKPOINT();
return 0;
}
static PS4_SYSV_ABI void stack_chk_fail() { BREAKPOINT(); }
u64 PS4_SYSV_ABI sceKernelReadTsc() {
LARGE_INTEGER c;
QueryPerformanceCounter(&c);
return c.QuadPart;
}
int PS4_SYSV_ABI sceKernelMunmap(void* addr, size_t len) { BREAKPOINT(); }
void LibKernel_Register(SymbolsResolver* sym) {
// obj
LIB_OBJ("f7uOxY9mM1U", "libkernel", 1, "libkernel", 1, 1, &HLE::Libs::LibKernel::g_stack_chk_guard);
// memory
LIB_FUNCTION("rTXw65xmLIA", "libkernel", 1, "libkernel", 1, 1, MemoryManagement::sceKernelAllocateDirectMemory);
LIB_FUNCTION("pO96TwzOm5E", "libkernel", 1, "libkernel", 1, 1, MemoryManagement::sceKernelGetDirectMemorySize);
LIB_FUNCTION("L-Q3LEjIbgA", "libkernel", 1, "libkernel", 1, 1, MemoryManagement::sceKernelMapDirectMemory);
LIB_FUNCTION("MBuItvba6z8", "libkernel", 1, "libkernel", 1, 1, sceKernelReleaseDirectMemory);
LIB_FUNCTION("cQke9UuBQOk", "libkernel", 1, "libkernel", 1, 1, sceKernelMunmap);
// equeue
LIB_FUNCTION("D0OdFMjp46I", "libkernel", 1, "libkernel", 1, 1, EventQueues::sceKernelCreateEqueue);
LIB_FUNCTION("fzyMKs9kim0", "libkernel", 1, "libkernel", 1, 1, EventQueues::sceKernelWaitEqueue);
// misc
LIB_FUNCTION("WslcK1FQcGI", "libkernel", 1, "libkernel", 1, 1, CPUManagement::sceKernelIsNeoMode);
LIB_FUNCTION("Ou3iL1abvng", "libkernel", 1, "libkernel", 1, 1, stack_chk_fail);
// time
LIB_FUNCTION("-2IRUCO--PM", "libkernel", 1, "libkernel", 1, 1, sceKernelReadTsc);
// fs
LIB_FUNCTION("1G3lF1Gg1k8", "libkernel", 1, "libkernel", 1, 1, Emulator::HLE::Libraries::LibKernel::FileSystem::sceKernelOpen);
LIB_FUNCTION("wuCroIGjt2g", "libScePosix", 1, "libkernel", 1, 1, Emulator::HLE::Libraries::LibKernel::FileSystem::POSIX::open);
}
}; // namespace HLE::Libs::LibKernel

View File

@@ -1,11 +0,0 @@
#include "../Loader/SymbolsResolver.h"
namespace HLE::Libs::LibKernel {
void LibKernel_Register(SymbolsResolver* sym);
// functions
u64 PS4_SYSV_ABI sceKernelReadTsc();
int32_t PS4_SYSV_ABI sceKernelReleaseDirectMemory(off_t start, size_t len);
}; // namespace HLE::Libs::LibKernel

View File

@@ -1,27 +0,0 @@
#include "LibSceGnmDriver.h"
#include "Libs.h"
#include "../Loader/Elf.h"
#include <Util/log.h>
#include <debug.h>
#include <Core/PS4/GPU/gpu_memory.h>
#include <emulator.h>
namespace HLE::Libs::LibSceGnmDriver {
int32_t sceGnmSubmitDone()
{
PRINT_DUMMY_FUNCTION_NAME();
return 0;
}
void sceGnmFlushGarlic() { PRINT_FUNCTION_NAME();
GPU::flushGarlic(Emu::getGraphicCtx());
}
void LibSceGnmDriver_Register(SymbolsResolver* sym)
{
LIB_FUNCTION("yvZ73uQUqrk", "libSceGnmDriver", 1, "libSceGnmDriver", 1, 1, sceGnmSubmitDone);
LIB_FUNCTION("iBt3Oe00Kvc", "libSceGnmDriver", 1, "libSceGnmDriver", 1, 1, sceGnmFlushGarlic);
}
};

View File

@@ -1,9 +0,0 @@
#pragma once
#include "../Loader/SymbolsResolver.h"
namespace HLE::Libs::LibSceGnmDriver {
void LibSceGnmDriver_Register(SymbolsResolver* sym);
int32_t sceGnmSubmitDone();
void sceGnmFlushGarlic();
}; // namespace HLE::Libs::LibSceGnmDriver

View File

@@ -1,22 +0,0 @@
#include "Libs.h"
#include "LibC.h"
#include "LibKernel.h"
#include "LibSceGnmDriver.h"
#include <Core/PS4/HLE/Graphics/video_out.h>
#include "Emulator/HLE/Libraries/LibUserService/user_service.h"
#include "Emulator/HLE/Libraries/LibPad/pad.h"
#include <Emulator/HLE/Libraries/LibSystemService/system_service.h>
namespace HLE::Libs {
void Init_HLE_Libs(SymbolsResolver *sym) {
LibC::LibC_Register(sym);
LibKernel::LibKernel_Register(sym);
Graphics::VideoOut::videoOutRegisterLib(sym);
LibSceGnmDriver::LibSceGnmDriver_Register(sym);
Emulator::HLE::Libraries::LibUserService::libUserService_Register(sym);
Emulator::HLE::Libraries::LibPad::libPad_Register(sym);
Emulator::HLE::Libraries::LibSystemService::libSystemService_Register(sym);
}
} // namespace HLE::Libs

View File

@@ -1,43 +0,0 @@
#pragma once
#include "../Loader/SymbolsResolver.h"
#include <Core/PS4/Loader/Elf.h>
#define LIB_FUNCTION(nid, lib, libversion, mod, moduleVersionMajor, moduleVersionMinor, function) \
{\
SymbolRes sr{}; \
sr.name = nid; \
sr.library = lib; \
sr.library_version = libversion;\
sr.module = mod;\
sr.module_version_major = moduleVersionMajor;\
sr.module_version_minor = moduleVersionMinor;\
sr.type = STT_FUN;\
auto func = reinterpret_cast<u64>(function);\
sym->AddSymbol(sr, func);\
}
#define LIB_OBJ(nid, lib, libversion, mod, moduleVersionMajor, moduleVersionMinor, function) \
{ \
SymbolRes sr{}; \
sr.name = nid; \
sr.library = lib; \
sr.library_version = libversion; \
sr.module = mod; \
sr.module_version_major = moduleVersionMajor; \
sr.module_version_minor = moduleVersionMinor; \
sr.type = STT_OBJECT; \
auto func = reinterpret_cast<u64>(function); \
sym->AddSymbol(sr, func); \
}
#define PRINT_FUNCTION_NAME() \
{ \
LOG_INFO_IF(true, "{}()\n", __func__); \
}
#define PRINT_DUMMY_FUNCTION_NAME() \
{ LOG_WARN_IF(true, "dummy {}()\n", __func__); }
namespace HLE::Libs {
void Init_HLE_Libs(SymbolsResolver* sym);
}

View File

@@ -1,12 +0,0 @@
#pragma once
//constants
constexpr int SCE_USER_SERVICE_MAX_LOGIN_USERS = 4; //max users logged in at once
constexpr int SCE_USER_SERVICE_MAX_USER_NAME_LENGTH = 16;//Max length for user name
constexpr int SCE_USER_SERVICE_USER_ID_INVALID = -1;//invalid user ID
constexpr int SCE_USER_SERVICE_USER_ID_SYSTEM = 255; //generic id for device
constexpr int SCE_USER_SERVICE_USER_ID_EVERYONE = 254; // generic id for user (mostly used in common dialogs)

View File

@@ -1,686 +0,0 @@
#include "Linker.h"
#include "../virtual_memory.h"
#include <Util/log.h>
#include "../../Util/Disassembler.h"
#include <Util/string_util.h>
#include "Util/aerolib.h"
#include "Loader/SymbolsResolver.h"
#include "HLE/Kernel/ThreadManagement.h"
#include "Stubs.h"
constexpr bool debug_loader = true;
static u64 g_load_addr = SYSTEM_RESERVED + CODE_BASE_OFFSET;
Linker::Linker()
{
m_HLEsymbols = new SymbolsResolver;
}
Linker::~Linker()
{
}
static u64 get_aligned_size(const elf_program_header* phdr)
{
return (phdr->p_align != 0 ? (phdr->p_memsz + (phdr->p_align - 1)) & ~(phdr->p_align - 1) : phdr->p_memsz);
}
static u64 calculate_base_size(const elf_header* ehdr, const elf_program_header* phdr)
{
u64 base_size = 0;
for (u16 i = 0; i < ehdr->e_phnum; i++)
{
if (phdr[i].p_memsz != 0 && (phdr[i].p_type == PT_LOAD || phdr[i].p_type == PT_SCE_RELRO))
{
auto phdrh = phdr + i;
u64 last_addr = phdr[i].p_vaddr + get_aligned_size(phdrh);
if (last_addr > base_size)
{
base_size = last_addr;
}
}
}
return base_size;
}
static std::string encodeId(u64 nVal)
{
std::string enc;
const char pCodes[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-";
if (nVal < 0x40u)
{
enc += pCodes[nVal];
}
else
{
if (nVal < 0x1000u)
{
enc += pCodes[static_cast<u16>(nVal >> 6u) & 0x3fu];
enc += pCodes[nVal & 0x3fu];
}
else
{
enc += pCodes[static_cast<u16>(nVal >> 12u) & 0x3fu];
enc += pCodes[static_cast<u16>(nVal >> 6u) & 0x3fu];
enc += pCodes[nVal & 0x3fu];
}
}
return enc;
}
Module* Linker::LoadModule(const std::string& elf_name)
{
Lib::LockMutexGuard lock(m_mutex);
auto* m = new Module;
m->linker = this;
m->elf = new Elf;
m->elf->Open(elf_name);//load elf
if (m->elf->isElfFile())
{
LoadModuleToMemory(m);
LoadDynamicInfo(m);
LoadSymbols(m);
Relocate(m);
}
else
{
return nullptr;//it is not a valid elf file //TODO check it why!
}
m_modules.push_back(m);//added it to load modules
return m;
}
Module* Linker::FindModule(/*u32 id*/)
{
//find module . TODO atm we only have 1 module so we don't need to iterate on vector
Module* m = m_modules.at(0);
if (m)
{
return m;
}
return nullptr;
}
void Linker::LoadModuleToMemory(Module* m)
{
//get elf header, program header
auto* elf_header = m->elf->GetElfHeader();
auto* elf_pheader = m->elf->GetProgramHeader();
u64 base_size = calculate_base_size(elf_header, elf_pheader);
m->aligned_base_size = (base_size & ~(static_cast<u64>(0x1000) - 1)) + 0x1000;//align base size to 0x1000 block size (TODO is that the default block size or it can be changed?
m->base_virtual_addr = VirtualMemory::memory_alloc(g_load_addr, m->aligned_base_size, VirtualMemory::MemoryMode::ExecuteReadWrite);
LOG_INFO_IF(debug_loader, "====Load Module to Memory ========\n");
LOG_INFO_IF(debug_loader, "base_virtual_addr ......: {:#018x}\n", m->base_virtual_addr);
LOG_INFO_IF(debug_loader, "base_size ..............: {:#018x}\n", base_size);
LOG_INFO_IF(debug_loader, "aligned_base_size ......: {:#018x}\n", m->aligned_base_size);
for (u16 i = 0; i < elf_header->e_phnum; i++)
{
switch(elf_pheader[i].p_type)
{
case PT_LOAD:
case PT_SCE_RELRO:
if (elf_pheader[i].p_memsz != 0)
{
u64 segment_addr = elf_pheader[i].p_vaddr + m->base_virtual_addr;
u64 segment_file_size = elf_pheader[i].p_filesz;
u64 segment_memory_size = get_aligned_size(elf_pheader + i);
auto segment_mode = m->elf->ElfPheaderFlagsStr((elf_pheader + i)->p_flags);
LOG_INFO_IF(debug_loader, "program header = [{}] type = {}\n",i,m->elf->ElfPheaderTypeStr(elf_pheader[i].p_type));
LOG_INFO_IF(debug_loader, "segment_addr ..........: {:#018x}\n", segment_addr);
LOG_INFO_IF(debug_loader, "segment_file_size .....: {}\n", segment_file_size);
LOG_INFO_IF(debug_loader, "segment_memory_size ...: {}\n", segment_memory_size);
LOG_INFO_IF(debug_loader, "segment_mode ..........: {}\n", segment_mode);
m->elf->LoadSegment(segment_addr, elf_pheader[i].p_offset, segment_file_size);
}
else
{
LOG_ERROR_IF(debug_loader, "p_memsz==0 in type {}\n", m->elf->ElfPheaderTypeStr(elf_pheader[i].p_type));
}
break;
case PT_DYNAMIC:
if (elf_pheader[i].p_filesz != 0)
{
void* dynamic = new u08[elf_pheader[i].p_filesz];
m->elf->LoadSegment(reinterpret_cast<u64>(dynamic), elf_pheader[i].p_offset, elf_pheader[i].p_filesz);
m->m_dynamic = dynamic;
}
else
{
LOG_ERROR_IF(debug_loader, "p_filesz==0 in type {}\n", m->elf->ElfPheaderTypeStr(elf_pheader[i].p_type));
}
break;
case PT_SCE_DYNLIBDATA:
if (elf_pheader[i].p_filesz != 0)
{
void* dynamic = new u08[elf_pheader[i].p_filesz];
m->elf->LoadSegment(reinterpret_cast<u64>(dynamic), elf_pheader[i].p_offset, elf_pheader[i].p_filesz);
m->m_dynamic_data = dynamic;
}
else
{
LOG_ERROR_IF(debug_loader, "p_filesz==0 in type {}\n", m->elf->ElfPheaderTypeStr(elf_pheader[i].p_type));
}
break;
default:
LOG_ERROR_IF(debug_loader, "Unimplemented type {}\n", m->elf->ElfPheaderTypeStr(elf_pheader[i].p_type));
}
}
LOG_INFO_IF(debug_loader, "program entry addr ..........: {:#018x}\n", m->elf->GetElfEntry() + m->base_virtual_addr);
auto* rt1 = reinterpret_cast<uint8_t*>(m->elf->GetElfEntry() + m->base_virtual_addr);
ZyanU64 runtime_address = m->elf->GetElfEntry() + m->base_virtual_addr;
// Loop over the instructions in our buffer.
ZyanUSize offset = 0;
ZydisDisassembledInstruction instruction;
while (ZYAN_SUCCESS(ZydisDisassembleIntel(
/* machine_mode: */ ZYDIS_MACHINE_MODE_LONG_64,
/* runtime_address: */ runtime_address,
/* buffer: */ rt1 + offset,
/* length: */ sizeof(rt1) - offset,
/* instruction: */ &instruction
))) {
printf("%016" PRIX64 " %s\n", runtime_address, instruction.text);
offset += instruction.info.length;
runtime_address += instruction.info.length;
}
}
void Linker::LoadDynamicInfo(Module* m)
{
m->dynamic_info = new DynamicModuleInfo;
for (const auto* dyn = static_cast<elf_dynamic*>(m->m_dynamic); dyn->d_tag != DT_NULL; dyn++)
{
switch (dyn->d_tag)
{
case DT_SCE_HASH: //Offset of the hash table.
m->dynamic_info->hash_table = reinterpret_cast<void*>(static_cast<uint8_t*>(m->m_dynamic_data) + dyn->d_un.d_ptr);
break;
case DT_SCE_HASHSZ: //Size of the hash table
m->dynamic_info->hash_table_size = dyn->d_un.d_val;
break;
case DT_SCE_STRTAB://Offset of the string table.
m->dynamic_info->str_table = reinterpret_cast<char*>(static_cast<uint8_t*>(m->m_dynamic_data) + dyn->d_un.d_ptr);
break;
case DT_SCE_STRSZ: //Size of the string table.
m->dynamic_info->str_table_size = dyn->d_un.d_val;
break;
case DT_SCE_SYMTAB://Offset of the symbol table.
m->dynamic_info->symbol_table = reinterpret_cast<elf_symbol*>(static_cast<uint8_t*>(m->m_dynamic_data) + dyn->d_un.d_ptr);
break;
case DT_SCE_SYMTABSZ://Size of the symbol table.
m->dynamic_info->symbol_table_total_size = dyn->d_un.d_val;
break;
case DT_INIT:
m->dynamic_info->init_virtual_addr = dyn->d_un.d_ptr;
break;
case DT_FINI:
m->dynamic_info->fini_virtual_addr = dyn->d_un.d_ptr;
break;
case DT_SCE_PLTGOT: //Offset of the global offset table.
m->dynamic_info->pltgot_virtual_addr = dyn->d_un.d_ptr;
break;
case DT_SCE_JMPREL: //Offset of the table containing jump slots.
m->dynamic_info->jmp_relocation_table = reinterpret_cast<elf_relocation*>(static_cast<uint8_t*>(m->m_dynamic_data) + dyn->d_un.d_ptr);
break;
case DT_SCE_PLTRELSZ: //Size of the global offset table.
m->dynamic_info->jmp_relocation_table_size = dyn->d_un.d_val;
break;
case DT_SCE_PLTREL: //The type of relocations in the relocation table. Should be DT_RELA
m->dynamic_info->jmp_relocation_type = dyn->d_un.d_val;
if (m->dynamic_info->jmp_relocation_type != DT_RELA)
{
LOG_WARN_IF(debug_loader, "DT_SCE_PLTREL is NOT DT_RELA should check!");
}
break;
case DT_SCE_RELA: //Offset of the relocation table.
m->dynamic_info->relocation_table = reinterpret_cast<elf_relocation*>(static_cast<uint8_t*>(m->m_dynamic_data) + dyn->d_un.d_ptr);
break;
case DT_SCE_RELASZ: //Size of the relocation table.
m->dynamic_info->relocation_table_size = dyn->d_un.d_val;
break;
case DT_SCE_RELAENT : //The size of relocation table entries.
m->dynamic_info->relocation_table_entries_size = dyn->d_un.d_val;
if (m->dynamic_info->relocation_table_entries_size != 0x18) //this value should always be 0x18
{
LOG_WARN_IF(debug_loader, "DT_SCE_RELAENT is NOT 0x18 should check!");
}
break;
case DT_INIT_ARRAY:// Address of the array of pointers to initialization functions
m->dynamic_info->init_array_virtual_addr = dyn->d_un.d_ptr;
break;
case DT_FINI_ARRAY: // Address of the array of pointers to termination functions
m->dynamic_info->fini_array_virtual_addr = dyn->d_un.d_ptr;
break;
case DT_INIT_ARRAYSZ://Size in bytes of the array of initialization functions
m->dynamic_info->init_array_size = dyn->d_un.d_val;
break;
case DT_FINI_ARRAYSZ://Size in bytes of the array of terminationfunctions
m->dynamic_info->fini_array_size = dyn->d_un.d_val;
break;
case DT_PREINIT_ARRAY://Address of the array of pointers to pre - initialization functions
m->dynamic_info->preinit_array_virtual_addr = dyn->d_un.d_ptr;
break;
case DT_PREINIT_ARRAYSZ://Size in bytes of the array of pre - initialization functions
m->dynamic_info->preinit_array_size = dyn->d_un.d_val;
break;
case DT_SCE_SYMENT: //The size of symbol table entries
m->dynamic_info->symbol_table_entries_size = dyn->d_un.d_val;
if (m->dynamic_info->symbol_table_entries_size != 0x18) //this value should always be 0x18
{
LOG_WARN_IF(debug_loader, "DT_SCE_SYMENT is NOT 0x18 should check!");
}
break;
case DT_DEBUG:
m->dynamic_info->debug = dyn->d_un.d_val;
break;
case DT_TEXTREL:
m->dynamic_info->textrel = dyn->d_un.d_val;
break;
case DT_FLAGS:
m->dynamic_info->flags = dyn->d_un.d_val;
if (m->dynamic_info->flags != 0x04) //this value should always be DF_TEXTREL (0x04)
{
LOG_WARN_IF(debug_loader, "DT_FLAGS is NOT 0x04 should check!");
}
break;
case DT_NEEDED://Offset of the library string in the string table to be linked in.
if (m->dynamic_info->str_table != nullptr)//in theory this should already be filled from about just make a test case
{
m->dynamic_info->needed.push_back(m->dynamic_info->str_table + dyn->d_un.d_val);
}
else
{
LOG_ERROR_IF(debug_loader, "DT_NEEDED str table is not loaded should check!");
}
break;
case DT_SCE_NEEDED_MODULE:
{
ModuleInfo info{};
info.value = dyn->d_un.d_val;
info.name = m->dynamic_info->str_table + info.name_offset;
info.enc_id = encodeId(info.id);
m->dynamic_info->import_modules.push_back(info);
}
break;
case DT_SCE_IMPORT_LIB:
{
LibraryInfo info{};
info.value = dyn->d_un.d_val;
info.name = m->dynamic_info->str_table + info.name_offset;
info.enc_id = encodeId(info.id);
m->dynamic_info->import_libs.push_back(info);
}
break;
case DT_SCE_FINGERPRINT:
//The fingerprint is a 24 byte (0x18) size buffer that contains a unique identifier for the given app.
//How exactly this is generated isn't known, however it is not necessary to have a valid fingerprint.
//While an invalid fingerprint will cause a warning to be printed to the kernel log, the ELF will still load and run.
LOG_INFO_IF(debug_loader, "unsupported DT_SCE_FINGERPRINT value = ..........: {:#018x}\n", dyn->d_un.d_val);
break;
case DT_SCE_IMPORT_LIB_ATTR:
//The upper 32-bits should contain the module index multiplied by 0x10000. The lower 32-bits should be a constant 0x9.
LOG_INFO_IF(debug_loader, "unsupported DT_SCE_IMPORT_LIB_ATTR value = ..........: {:#018x}\n", dyn->d_un.d_val);
break;
case DT_SCE_ORIGINAL_FILENAME:
m->dynamic_info->filename = m->dynamic_info->str_table + dyn->d_un.d_val;
break;
case DT_SCE_MODULE_INFO://probably only useable in shared modules
{
ModuleInfo info{};
info.value = dyn->d_un.d_val;
info.name = m->dynamic_info->str_table + info.name_offset;
info.enc_id = encodeId(info.id);
m->dynamic_info->export_modules.push_back(info);
}
break;
case DT_SCE_MODULE_ATTR:
//TODO?
LOG_INFO_IF(debug_loader, "unsupported DT_SCE_MODULE_ATTR value = ..........: {:#018x}\n", dyn->d_un.d_val);
break;
case DT_SCE_EXPORT_LIB:
{
LibraryInfo info{};
info.value = dyn->d_un.d_val;
info.name = m->dynamic_info->str_table + info.name_offset;
info.enc_id = encodeId(info.id);
m->dynamic_info->export_libs.push_back(info);
}
break;
default:
LOG_INFO_IF(debug_loader, "unsupported dynamic tag ..........: {:#018x}\n", dyn->d_tag);
}
}
}
const ModuleInfo* Linker::FindModule(const Module& m, const std::string& id)
{
const auto& import_modules = m.dynamic_info->import_modules;
int index = 0;
for (auto mod : import_modules)
{
if (mod.enc_id.compare(id) == 0)
{
return &import_modules.at(index);
}
index++;
}
const auto& export_modules = m.dynamic_info->export_modules;
index = 0;
for (auto mod : export_modules)
{
if (mod.enc_id.compare(id) == 0)
{
return &export_modules.at(index);
}
index++;
}
return nullptr;
}
const LibraryInfo* Linker::FindLibrary(const Module& m, const std::string& id)
{
const auto& import_libs = m.dynamic_info->import_libs;
int index = 0;
for (auto lib : import_libs)
{
if (lib.enc_id.compare(id) == 0)
{
return &import_libs.at(index);
}
index++;
}
const auto& export_libs = m.dynamic_info->export_libs;
index = 0;
for (auto lib : export_libs)
{
if (lib.enc_id.compare(id) == 0)
{
return &export_libs.at(index);
}
index++;
}
return nullptr;
}
void Linker::LoadSymbols(Module* m)
{
if (m->dynamic_info->symbol_table == nullptr || m->dynamic_info->str_table == nullptr || m->dynamic_info->symbol_table_total_size==0)
{
LOG_INFO_IF(debug_loader, "Symbol table not found!\n");
return;
}
m->export_sym = new SymbolsResolver;
m->import_sym = new SymbolsResolver;
for (auto* sym = m->dynamic_info->symbol_table;
reinterpret_cast<uint8_t*>(sym) < reinterpret_cast<uint8_t*>(m->dynamic_info->symbol_table) + m->dynamic_info->symbol_table_total_size;
sym++)
{
std::string id = std::string(m->dynamic_info->str_table + sym->st_name);
auto ids = StringUtil::split_string(id, '#');
if (ids.size() == 3)//symbols are 3 parts name , library , module
{
const auto* library = FindLibrary(*m, ids.at(1));
const auto* module = FindModule(*m, ids.at(2));
auto bind = sym->GetBind();
auto type = sym->GetType();
auto visibility = sym->GetVisibility();
if (library != nullptr || module != nullptr)
{
switch (bind)
{
case STB_GLOBAL:
case STB_WEAK:
break;
default:
LOG_INFO_IF(debug_loader, "Unsupported bind {} for name symbol {} \n", bind,ids.at(0));
continue;
}
switch (type)
{
case STT_OBJECT:
case STT_FUN:
break;
default:
LOG_INFO_IF(debug_loader, "Unsupported type {} for name symbol {} \n", type, ids.at(0));
continue;
}
switch (visibility)
{
case STV_DEFAULT:
break;
default:
LOG_INFO_IF(debug_loader, "Unsupported visibility {} for name symbol {} \n", visibility, ids.at(0));
continue;
}
//if st_value!=0 then it's export symbol
bool is_sym_export = sym->st_value != 0;
std::string nidName = "";
auto aeronid = aerolib::find_by_nid(ids.at(0).c_str());
if (aeronid != nullptr)
{
nidName = aeronid->name;
}
else
{
nidName = "UNK";
}
SymbolRes sym_r{};
sym_r.name = ids.at(0);
sym_r.nidName = nidName;
sym_r.library = library->name;
sym_r.library_version = library->version;
sym_r.module = module->name;
sym_r.module_version_major = module->version_major;
sym_r.module_version_minor = module->version_minor;
sym_r.type = type;
if (is_sym_export)
{
m->export_sym->AddSymbol(sym_r, sym->st_value + m->base_virtual_addr);
}
else
{
m->import_sym->AddSymbol(sym_r,0);
}
LOG_INFO_IF(debug_loader, "name {} function {} library {} module {} bind {} type {} visibility {}\n", ids.at(0),nidName,library->name, module->name, bind, type, visibility);
}
}
}
}
static void relocate(u32 idx, elf_relocation* rel, Module* m, bool isJmpRel) {
auto type = rel->GetType();
auto symbol = rel->GetSymbol();
auto addend = rel->rel_addend;
auto* symbolsTlb = m->dynamic_info->symbol_table;
auto* namesTlb = m->dynamic_info->str_table;
u64 rel_value = 0;
u64 rel_base_virtual_addr = m->base_virtual_addr;
u64 rel_virtual_addr = m->base_virtual_addr + rel->rel_offset;
bool rel_isResolved = false;
u08 rel_sym_type = 0;
std::string rel_name;
u08 rel_bind_type = -1; //-1 means it didn't resolve
switch (type) {
case R_X86_64_RELATIVE:
if (symbol != 0) // should be always zero
{
LOG_INFO_IF(debug_loader, "R_X86_64_RELATIVE symbol not zero = {:#010x}\n", type, symbol);
}
rel_value = rel_base_virtual_addr + addend;
rel_isResolved = true;
break;
case R_X86_64_64:
case R_X86_64_JUMP_SLOT: // similar but addend is not take into account
{
auto sym = symbolsTlb[symbol];
auto sym_bind = sym.GetBind();
auto sym_type = sym.GetType();
auto sym_visibility = sym.GetVisibility();
u64 symbol_vitrual_addr = 0;
SymbolRecord symrec{};
switch (sym_type) {
case STT_FUN: rel_sym_type = 2; break;
case STT_OBJECT: rel_sym_type = 1; break;
default: LOG_INFO_IF(debug_loader, "unknown symbol type {}\n", sym_type);
}
if (sym_visibility != 0) // should be zero log if else
{
LOG_INFO_IF(debug_loader, "symbol visilibity !=0\n");
}
switch (sym_bind) {
case STB_GLOBAL:
rel_bind_type = STB_GLOBAL;
rel_name = namesTlb + sym.st_name;
m->linker->Resolve(rel_name, rel_sym_type, m, &symrec);
symbol_vitrual_addr = symrec.virtual_address;
rel_isResolved = (symbol_vitrual_addr != 0);
rel_name = symrec.name;
if (type == R_X86_64_JUMP_SLOT) {
addend = 0;
}
rel_value = (rel_isResolved ? symbol_vitrual_addr + addend : 0);
if (!rel_isResolved) {
LOG_INFO_IF(debug_loader, "R_X86_64_64-R_X86_64_JUMP_SLOT sym_type {} bind STB_GLOBAL symbol : {:#010x}\n", sym_type, symbol);
}
break;
default: LOG_INFO_IF(debug_loader, "UNK bind {}\n", sym_bind);
}
} break;
default: LOG_INFO_IF(debug_loader, "UNK type {:#010x} rel symbol : {:#010x}\n", type, symbol);
}
if (rel_isResolved) {
VirtualMemory::memory_patch(rel_virtual_addr, rel_value);
}
else
{
LOG_INFO_IF(debug_loader, "function not patched! {}\n",rel_name);
}
}
void Linker::Relocate(Module* m)
{
u32 idx = 0;
for (auto* rel = m->dynamic_info->relocation_table; reinterpret_cast<u08*>(rel) < reinterpret_cast<u08*>(m->dynamic_info->relocation_table) + m->dynamic_info->relocation_table_size; rel++, idx++)
{
relocate(idx, rel, m, false);
}
idx = 0;
for (auto* rel = m->dynamic_info->jmp_relocation_table; reinterpret_cast<u08*>(rel) < reinterpret_cast<u08*>(m->dynamic_info->jmp_relocation_table) + m->dynamic_info->jmp_relocation_table_size; rel++, idx++)
{
relocate(idx, rel, m, true);
}
}
void Linker::Resolve(const std::string& name, int Symtype, Module* m, SymbolRecord* return_info) {
auto ids = StringUtil::split_string(name, '#');
if (ids.size() == 3) // symbols are 3 parts name , library , module
{
const auto* library = FindLibrary(*m, ids.at(1));
const auto* module = FindModule(*m, ids.at(2));
if (library != nullptr && module != nullptr) {
SymbolRes sr{};
sr.name = ids.at(0);
sr.library = library->name;
sr.library_version = library->version;
sr.module = module->name;
sr.module_version_major = module->version_major;
sr.module_version_minor = module->version_minor;
sr.type = Symtype;
const SymbolRecord* rec = nullptr;
if (m_HLEsymbols != nullptr) {
rec = m_HLEsymbols->FindSymbol(sr);
}
if (rec != nullptr) {
*return_info = *rec;
} else {
auto aeronid = aerolib::find_by_nid(sr.name.c_str());
if (aeronid) {
return_info->name = aeronid->name;
return_info->virtual_address = GetStub(aeronid->nid);
} else {
return_info->virtual_address = GetStub(sr.name.c_str());
return_info->name = "Unknown !!!";
}
LOG_ERROR_IF(debug_loader, "Linker: Stub resolved {} as {} (lib: {}, mod: {}) \n", sr.name, return_info->name, library->name, module->name);
}
}
else
{
__debugbreak();//den tha prepei na ftasoume edo
}
}
else
{
__debugbreak();//oute edo mallon
}
}
using exit_func_t = PS4_SYSV_ABI void (*)();
using entry_func_t = PS4_SYSV_ABI void (*)(EntryParams* params, exit_func_t atexit_func);
static PS4_SYSV_ABI void ProgramExitFunc() {
printf("exit function called\n");
}
static void run_main_entry(u64 addr, EntryParams* params, exit_func_t exit_func) {
//reinterpret_cast<entry_func_t>(addr)(params, exit_func); // can't be used, stack has to have a specific layout
asm volatile (
"andq $-16, %%rsp\n"// Align to 16 bytes
"subq $8, %%rsp\n" // videoout_basic expects the stack to be misaligned
// Kernel also pushes some more things here during process init
// at least: environment, auxv, possibly other things
"pushq 8(%1)\n" // copy EntryParams to top of stack like the kernel does
"pushq 0(%1)\n" // OpenOrbis expects to find it there
"movq %1, %%rdi\n" // also pass params and exit func
"movq %2, %%rsi\n" // as before
"jmp *%0\n" // can't use call here, as that would mangle the prepared stack.
// there's no coming back
:
: "r"(addr), "r"(params), "r"(exit_func)
: "rax", "rsi", "rdi", "rsp", "rbp"
);
}
void Linker::Execute()
{
HLE::Libs::LibKernel::ThreadManagement::Pthread_Init_Self_MainThread();
EntryParams p{};
p.argc = 1;
p.argv[0] = "eboot.bin"; //hmm should be ok?
run_main_entry(m_modules.at(0)->elf->GetElfEntry()+m_modules.at(0)->base_virtual_addr, &p, ProgramExitFunc);
}

View File

@@ -1,134 +0,0 @@
#pragma once
#include <vector>
#include "Loader/Elf.h"
#include "Loader/SymbolsResolver.h"
#include "Lib/Threads.h"
struct DynamicModuleInfo;
class Linker;
struct EntryParams {
int argc;
u32 padding;
const char* argv[3];
};
/*this struct keeps neccesary info about loaded modules.Main executeable is included too as well*/
struct Module
{
Elf* elf = nullptr;
u64 aligned_base_size = 0;
u64 base_virtual_addr = 0; //base virtual address
Linker* linker = nullptr;
void* m_dynamic = nullptr;
void* m_dynamic_data = nullptr;
DynamicModuleInfo* dynamic_info = nullptr;
SymbolsResolver* export_sym = nullptr;
SymbolsResolver* import_sym = nullptr;
};
struct ModuleInfo
{
std::string name;
union
{
u64 value;
struct
{
u32 name_offset;
u08 version_minor;
u08 version_major;
u16 id;
};
};
std::string enc_id;
};
struct LibraryInfo
{
std::string name;
union
{
u64 value;
struct
{
u32 name_offset;
u16 version;
u16 id;
};
};
std::string enc_id;
};
struct DynamicModuleInfo
{
void* hash_table = nullptr;
u64 hash_table_size = 0;
char* str_table = nullptr;
u64 str_table_size = 0;
elf_symbol* symbol_table = nullptr;
u64 symbol_table_total_size = 0;
u64 symbol_table_entries_size = 0;
u64 init_virtual_addr = 0;
u64 fini_virtual_addr = 0;
u64 pltgot_virtual_addr = 0;
u64 init_array_virtual_addr = 0;
u64 fini_array_virtual_addr = 0;
u64 preinit_array_virtual_addr = 0;
u64 init_array_size = 0;
u64 fini_array_size = 0;
u64 preinit_array_size = 0;
elf_relocation* jmp_relocation_table = nullptr;
u64 jmp_relocation_table_size = 0;
s64 jmp_relocation_type = 0;
elf_relocation* relocation_table = nullptr;
u64 relocation_table_size = 0;
u64 relocation_table_entries_size = 0;
u64 debug = 0;
u64 textrel = 0;
u64 flags = 0;
std::vector<const char*> needed;
std::vector<ModuleInfo> import_modules;
std::vector<ModuleInfo> export_modules;
std::vector<LibraryInfo> import_libs;
std::vector<LibraryInfo> export_libs;
std::string filename;//filename with absolute path
};
class Linker
{
public:
Linker();
virtual ~Linker();
Module* LoadModule(const std::string& elf_name);
Module* FindModule(/*u32 id*/);
void LoadModuleToMemory(Module* m);
void LoadDynamicInfo(Module* m);
void LoadSymbols(Module* m);
SymbolsResolver* getHLESymbols() { return m_HLEsymbols; }
void Relocate(Module* m);
void Resolve(const std::string& name, int Symtype, Module* m, SymbolRecord* return_info);
void Execute();
private:
const ModuleInfo* FindModule(const Module& m, const std::string& id);
const LibraryInfo* FindLibrary(const Module& program, const std::string& id);
std::vector<Module*> m_modules;
SymbolsResolver* m_HLEsymbols = nullptr;
Lib::Mutex m_mutex;
};

View File

@@ -1,462 +0,0 @@
#include "Elf.h"
#include <Util/log.h>
#include <debug.h>
#include <fmt/core.h>
#include <spdlog/pattern_formatter.h>
#include <spdlog/sinks/stdout_color_sinks.h>
#include <magic_enum.hpp>
#include "spdlog/sinks/basic_file_sink.h"
#include "spdlog/spdlog.h"
constexpr bool debug_elf = true;
template <>
struct magic_enum::customize::enum_range<e_type_s> {
static constexpr int min = 0xfe00;
static constexpr int max = 0xfe18;
// (max - min) must be less than UINT16_MAX.
};
Elf::~Elf() { Reset(); }
static self_header* load_self(FsFile& f) {
// read self header
auto* self = new self_header;
f.Read(self, sizeof(self_header));
return self;
}
static self_segment_header* load_self_segments(FsFile& f, u16 num) {
auto* segs = new self_segment_header[num];
f.Read(segs, sizeof(self_segment_header) * num);
return segs;
}
static elf_header* load_elf_header(FsFile& f) {
auto* m_elf_header = new elf_header;
f.Read(m_elf_header, sizeof(elf_header));
return m_elf_header;
}
static elf_program_header* load_program_header(FsFile& f, u64 offset, u16 num) {
auto* phdr = new elf_program_header[num];
f.Seek(offset, fsSeekMode::fsSeekSet);
f.Read(phdr, sizeof(elf_program_header) * num);
return phdr;
}
static elf_section_header* load_section_header(FsFile& f, u64 offset, u16 num) {
if (num == 0) // just in case we don't have section headers
{
return nullptr;
}
auto* shdr = new elf_section_header[num];
f.Seek(offset, fsSeekMode::fsSeekSet);
f.Read(shdr, sizeof(elf_section_header) * num);
return shdr;
}
void Elf::Reset() // reset all variables
{
if (m_f != nullptr) {
m_f->Close();
delete m_f;
}
delete m_self;
delete m_elf_header;
delete m_self_id_header;
delete[] m_self_segments;
delete[] m_elf_phdr;
delete[] m_elf_shdr;
m_self = nullptr;
m_self_segments = nullptr;
m_elf_header = nullptr;
m_elf_phdr = nullptr;
m_elf_shdr = nullptr;
m_self_id_header = nullptr;
}
void Elf::Open(const std::string& file_name) {
Reset(); // reset all variables
m_f = new FsFile;
m_f->Open(file_name, fsOpenMode::fsRead);
m_self = load_self(*m_f);
bool isself = isSelfFile();
if (!isself) {
delete m_self;
m_self = nullptr;
m_f->Seek(0, fsSeekMode::fsSeekSet); // it is not an self file move to the start of file
} else {
m_self_segments = load_self_segments(*m_f, m_self->segment_count);
}
auto elfheader_pos = m_f->Tell(); // get the entry pos for elf file
m_elf_header = load_elf_header(*m_f);
if (!isElfFile()) {
delete m_elf_header;
m_elf_header = nullptr;
}
if (m_elf_header != nullptr) {
m_elf_phdr = load_program_header(*m_f, elfheader_pos + m_elf_header->e_phoff, m_elf_header->e_phnum);
m_elf_shdr = load_section_header(*m_f, elfheader_pos + m_elf_header->e_shoff, m_elf_header->e_shnum);
}
if (isself && m_elf_header != nullptr) {
u64 header_size = 0;
header_size += sizeof(self_header);
header_size += sizeof(self_segment_header) * m_self->segment_count;
header_size += sizeof(elf_header);
header_size += m_elf_header->e_phnum * m_elf_header->e_phentsize;
header_size += m_elf_header->e_shnum * m_elf_header->e_shentsize;
header_size += 15;
header_size &= ~15; // align
if (m_elf_header->e_ehsize - header_size >= sizeof(elf_program_id_header)) {
m_f->Seek(header_size, fsSeekMode::fsSeekSet);
m_self_id_header = new elf_program_id_header;
m_f->Read(m_self_id_header, sizeof(elf_program_id_header));
}
}
DebugDump();
}
bool Elf::isSelfFile() const {
if (m_f == nullptr) {
return false;
}
if (m_self == nullptr) {
return false; // if we can't load self header return false
}
if (m_self->magic != self_header::signature) {
printf("Not a SELF file. Magic file mismatched! current = 0x%08X required = 0x%08X\n", m_self->magic, self_header::signature);
return false;
}
if (m_self->version != 0x00 || m_self->mode != 0x01 || m_self->endian != 0x01 || m_self->attributes != 0x12) {
printf("Unknown SELF file\n");
return false;
}
if (m_self->category != 0x01 || m_self->program_type != 0x01) {
printf("Unknown SELF file\n");
return false;
}
return true;
}
bool Elf::isElfFile() const {
if (m_f == nullptr) {
return false;
}
if (m_elf_header == nullptr) {
return false;
}
if (m_elf_header->e_ident.magic[EI_MAG0] != ELFMAG0 || m_elf_header->e_ident.magic[EI_MAG1] != ELFMAG1 ||
m_elf_header->e_ident.magic[EI_MAG2] != ELFMAG2 || m_elf_header->e_ident.magic[EI_MAG3] != ELFMAG3) {
printf("ERROR:Not an ELF file magic is wrong!\n");
return false;
}
if (m_elf_header->e_ident.ei_class != ELF_CLASS_64) {
printf("ERROR:e_ident[EI_CLASS] expected 0x02 is (0x%x)\n", m_elf_header->e_ident.ei_class);
return false;
}
if (m_elf_header->e_ident.ei_data != ELF_DATA_2LSB) {
printf("ERROR:e_ident[EI_DATA] expected 0x01 is (0x%x)\n", m_elf_header->e_ident.ei_data);
return false;
}
if (m_elf_header->e_ident.ei_version != ELF_VERSION_CURRENT) {
printf("ERROR:e_ident[EI_VERSION] expected 0x01 is (0x%x)\n", m_elf_header->e_ident.ei_version);
return false;
}
if (m_elf_header->e_ident.ei_osabi != ELF_OSABI_FREEBSD) {
printf("ERROR:e_ident[EI_OSABI] expected 0x09 is (0x%x)\n", m_elf_header->e_ident.ei_osabi);
return false;
}
if (m_elf_header->e_ident.ei_abiversion != ELF_ABI_VERSION_AMDGPU_HSA_V2) {
printf("ERROR:e_ident[EI_ABIVERSION] expected 0x00 is (0x%x)\n", m_elf_header->e_ident.ei_abiversion);
return false;
}
if (m_elf_header->e_type != ET_SCE_DYNEXEC&& m_elf_header->e_type != ET_SCE_DYNAMIC&& m_elf_header->e_type != ET_SCE_EXEC) {
printf("ERROR:e_type expected 0xFE10 OR 0xFE18 OR 0xfe00 is (%04x)\n", m_elf_header->e_type);
return false;
}
if (m_elf_header->e_machine != EM_X86_64) {
printf("ERROR:e_machine expected 0x3E is (%04x)\n", m_elf_header->e_machine);
return false;
}
if (m_elf_header->e_version != EV_CURRENT) {
printf("ERROR:m_elf_header->e_version expected 0x01 is (0x%x)\n", m_elf_header->e_version);
return false;
}
if (m_elf_header->e_phentsize != sizeof(elf_program_header)) {
printf("ERROR:e_phentsize (%d) != sizeof(elf_program_header)\n", m_elf_header->e_phentsize);
return false;
}
if (m_elf_header->e_shentsize > 0 &&
m_elf_header->e_shentsize != sizeof(elf_section_header)) // commercial games doesn't appear to have section headers
{
printf("ERROR:e_shentsize (%d) != sizeof(elf_section_header)\n", m_elf_header->e_shentsize);
return false;
}
return true;
}
void Elf::DebugDump() {
if (m_self != nullptr) { // if we load elf instead
spdlog::info(SElfHeaderStr());
spdlog::info("\n");
for (u16 i = 0; i < m_self->segment_count; i++) {
spdlog::info(SELFSegHeader(i));
}
spdlog::info("\n");
}
spdlog::info(ElfHeaderStr());
if (m_elf_header->e_phentsize > 0) {
spdlog::info("Program headers:\n");
for (u16 i = 0; i < m_elf_header->e_phnum; i++) {
spdlog::info(ElfPHeaderStr(i));
}
}
if (m_elf_header->e_shentsize > 0) {
spdlog::info("Section headers:\n");
for (u16 i = 0; i < m_elf_header->e_shnum; i++) {
spdlog::info("--- shdr {} --\n", i);
spdlog::info("sh_name ........: {}\n", (m_elf_shdr + i)->sh_name);
spdlog::info("sh_type ........: {:#010x}\n", (m_elf_shdr + i)->sh_type);
spdlog::info("sh_flags .......: {:#018x}\n", (m_elf_shdr + i)->sh_flags);
spdlog::info("sh_addr ........: {:#018x}\n", (m_elf_shdr + i)->sh_addr);
spdlog::info("sh_offset ......: {:#018x}\n", (m_elf_shdr + i)->sh_offset);
spdlog::info("sh_size ........: {:#018x}\n", (m_elf_shdr + i)->sh_size);
spdlog::info("sh_link ........: {:#010x}\n", (m_elf_shdr + i)->sh_link);
spdlog::info("sh_info ........: {:#010x}\n", (m_elf_shdr + i)->sh_info);
spdlog::info("sh_addralign ...: {:#018x}\n", (m_elf_shdr + i)->sh_addralign);
spdlog::info("sh_entsize .....: {:#018x}\n", (m_elf_shdr + i)->sh_entsize);
}
}
if (m_self_id_header != nullptr) {
spdlog::info("SELF info:\n");
spdlog::info("auth id ............: {:#018x}\n", m_self_id_header->authid);
auto program_type = magic_enum::enum_cast<program_type_es>(m_self_id_header->program_type);
if (program_type.has_value()) {
spdlog::info("program type .......: {}\n", magic_enum::enum_name(program_type.value()));
} else {
spdlog::info("program type UNK....: {:#018x}\n", (int)m_self_id_header->program_type);
}
spdlog::info("app version ........: {:#018x}\n", m_self_id_header->appver);
spdlog::info("fw version .........: {:#018x}\n", m_self_id_header->firmver);
std::string digest;
for (int i = 0; i < 32; i++) digest += fmt::format("{:02X}", m_self_id_header->digest[i]);
spdlog::info("digest..............: 0x{}\n",digest);
}
}
std::string Elf::SElfHeaderStr() {
std::string header = fmt::format("======= SELF HEADER =========\n", m_self->magic);
header += fmt::format("magic ..............: 0x{:X}\n", m_self->magic);
header += fmt::format("version ............: {}\n", m_self->version);
header += fmt::format("mode ...............: {:#04x}\n", m_self->mode);
header += fmt::format("endian .............: {}\n", m_self->endian);
header += fmt::format("attributes .........: {:#04x}\n", m_self->attributes);
header += fmt::format("category ...........: {:#04x}\n", m_self->category);
header += fmt::format("program_type........: {:#04x}\n", m_self->program_type);
header += fmt::format("padding1 ...........: {:#06x}\n", m_self->padding1);
header += fmt::format("header size ........: {}\n", m_self->header_size);
header += fmt::format("meta size ..........: {}\n", m_self->meta_size);
header += fmt::format("file size ..........: {}\n", m_self->file_size);
header += fmt::format("padding2 ...........: {:#010x}\n", m_self->padding2);
header += fmt::format("segment count ......: {}\n", m_self->segment_count);
header += fmt::format("unknown 1A .........: {:#06x}\n", m_self->unknown1A);
header += fmt::format("padding3 ...........: {:#010x}\n", m_self->padding3);
return header;
}
std::string Elf::SELFSegHeader(u16 no) {
auto segment_header = m_self_segments[no];
std::string header = fmt::format("====== SEGMENT HEADER {} ========\n", no);
header += fmt::format("flags ............: {:#018x}\n", segment_header.flags);
header += fmt::format("file offset ......: {:#018x}\n", segment_header.file_offset);
header += fmt::format("file size ........: {}\n", segment_header.file_size);
header += fmt::format("memory size ......: {}\n", segment_header.memory_size);
return header;
}
std::string Elf::ElfHeaderStr() {
std::string header = fmt::format("======= Elf header ===========\n");
header += fmt::format("ident ............: 0x");
for (auto i : m_elf_header->e_ident.magic) {
header += fmt::format("{:02X}", i);
}
header += fmt::format("\n");
auto ident_class = magic_enum::enum_cast<ident_class_es>(m_elf_header->e_ident.ei_class);
if (ident_class.has_value()) {
header += fmt::format("ident class.......: {}\n", magic_enum::enum_name(ident_class.value()));
}
auto ident_data = magic_enum::enum_cast<ident_endian_es>(m_elf_header->e_ident.ei_data);
if (ident_data.has_value()) {
header += fmt::format("ident data .......: {}\n", magic_enum::enum_name(ident_data.value()));
}
auto ident_version = magic_enum::enum_cast<ident_version_es>(m_elf_header->e_ident.ei_version);
if (ident_version.has_value()) {
header += fmt::format("ident version.....: {}\n", magic_enum::enum_name(ident_version.value()));
}
auto ident_osabi = magic_enum::enum_cast<ident_osabi_es>(m_elf_header->e_ident.ei_osabi);
if (ident_osabi.has_value()) {
header += fmt::format("ident osabi .....: {}\n", magic_enum::enum_name(ident_osabi.value()));
}
auto ident_abiversion = magic_enum::enum_cast<ident_abiversion_es>(m_elf_header->e_ident.ei_abiversion);
if (ident_abiversion.has_value()) {
header += fmt::format("ident abiversion..: {}\n", magic_enum::enum_name(ident_abiversion.value()));
}
header += fmt::format("ident UNK ........: 0x");
for (auto i : m_elf_header->e_ident.pad) {
header += fmt::format("{:02X}", i);
}
header += fmt::format("\n");
auto type = magic_enum::enum_cast<e_type_s>(m_elf_header->e_type);
if (type.has_value()) {
header += fmt::format("type ............: {}\n", magic_enum::enum_name(type.value()));
}
auto machine = magic_enum::enum_cast<e_machine_es>(m_elf_header->e_machine);
if (machine.has_value()) {
header += fmt::format("machine ..........: {}\n", magic_enum::enum_name(machine.value()));
}
auto version = magic_enum::enum_cast<e_version_es>(m_elf_header->e_version);
if (version.has_value()) {
header += fmt::format("version ..........: {}\n", magic_enum::enum_name(version.value()));
}
header += fmt::format("entry ............: {:#018x}\n", m_elf_header->e_entry);
header += fmt::format("phoff ............: {:#018x}\n", m_elf_header->e_phoff);
header += fmt::format("shoff ............: {:#018x}\n", m_elf_header->e_shoff);
header += fmt::format("flags ............: {:#010x}\n", m_elf_header->e_flags);
header += fmt::format("ehsize ...........: {}\n", m_elf_header->e_ehsize);
header += fmt::format("phentsize ........: {}\n", m_elf_header->e_phentsize);
header += fmt::format("phnum ............: {}\n", m_elf_header->e_phnum);
header += fmt::format("shentsize ........: {}\n", m_elf_header->e_shentsize);
header += fmt::format("shnum ............: {}\n", m_elf_header->e_shnum);
header += fmt::format("shstrndx .........: {}\n", m_elf_header->e_shstrndx);
return header;
}
std::string Elf::ElfPheaderTypeStr(u32 type) {
switch (type) {
case PT_NULL: return "Null";
case PT_LOAD: return "Loadable";
case PT_DYNAMIC: return "Dynamic";
case PT_INTERP: return "Interpreter Path";
case PT_NOTE: return "Note";
case PT_SHLIB: return "Section Header Library";
case PT_PHDR: return "Program Header";
case PT_TLS: return "Thread-Local Storage";
case PT_NUM: return "Defined Sections Number";
case PT_SCE_RELA: return "SCE Relative";
case PT_SCE_DYNLIBDATA: return "SCE Dynamic Library Data";
case PT_SCE_PROCPARAM: return "SCE Processor Parameters";
case PT_SCE_MODULE_PARAM: return "SCE Module Parameters";
case PT_SCE_RELRO: return "SCE Read-Only After Relocation";
case PT_GNU_EH_FRAME: return "GNU Entry Header Frame";
case PT_GNU_STACK: return "GNU Stack (executability)";
case PT_GNU_RELRO: return "GNU Read-Only After Relocation";
case PT_SCE_COMMENT: return "SCE Comment";
case PT_SCE_LIBVERSION: return "SCE Library Version";
default: return "Unknown Section";
}
}
std::string Elf::ElfPheaderFlagsStr(u32 flags) {
std::string flg = "(";
flg += (flags & PF_READ) ? "R" : "_";
flg += (flags & PF_WRITE) ? "W" : "_";
flg += (flags & PF_EXEC) ? "X" : "_";
flg += ")";
return flg;
}
std::string Elf::ElfPHeaderStr(u16 no) {
std::string header = fmt::format("====== PROGRAM HEADER {} ========\n", no);
header += fmt::format("p_type ....: {}\n", ElfPheaderTypeStr((m_elf_phdr + no)->p_type));
auto flags = magic_enum::enum_cast<elf_program_flags>((m_elf_phdr + no)->p_flags);
if (flags.has_value()) {
header += fmt::format("p_flags ...: {}\n", magic_enum::enum_name(flags.value()));
}
// header += fmt::format("p_flags ...: {:#010x}\n", (m_elf_phdr + no)->p_flags);
header += fmt::format("p_offset ..: {:#018x}\n", (m_elf_phdr + no)->p_offset);
header += fmt::format("p_vaddr ...: {:#018x}\n", (m_elf_phdr + no)->p_vaddr);
header += fmt::format("p_paddr ...: {:#018x}\n", (m_elf_phdr + no)->p_paddr);
header += fmt::format("p_filesz ..: {:#018x}\n", (m_elf_phdr + no)->p_filesz);
header += fmt::format("p_memsz ...: {:#018x}\n", (m_elf_phdr + no)->p_memsz);
header += fmt::format("p_align ...: {:#018x}\n", (m_elf_phdr + no)->p_align);
return header;
}
void Elf::LoadSegment(u64 virtual_addr, u64 file_offset, u64 size) {
if (m_self != nullptr) {
for (uint16_t i = 0; i < m_self->segment_count; i++) {
const auto& seg = m_self_segments[i];
if (seg.IsBlocked()) {
auto phdr_id = seg.GetId();
const auto& phdr = m_elf_phdr[phdr_id];
if (file_offset >= phdr.p_offset && file_offset < phdr.p_offset + phdr.p_filesz) {
auto offset = file_offset - phdr.p_offset;
m_f->Seek(offset + seg.file_offset, fsSeekMode::fsSeekSet);
m_f->Read(reinterpret_cast<void*>(static_cast<uintptr_t>(virtual_addr)), size);
return;
}
}
}
BREAKPOINT(); // hmm we didn't return something...
} else {
// it's elf file
m_f->Seek(file_offset, fsSeekMode::fsSeekSet);
m_f->Read(reinterpret_cast<void*>(static_cast<uintptr_t>(virtual_addr)), size);
}
}
u64 Elf::GetElfEntry() { return m_elf_header->e_entry; }

View File

@@ -1,484 +0,0 @@
#pragma once
#include <string>
#include <inttypes.h>
#include "../../../types.h"
#include "../../FsFile.h"
struct self_header
{
static const u32 signature = 0x1D3D154Fu;
u32 magic;
u08 version;
u08 mode;
u08 endian;// 1 is little endian
u08 attributes;
u08 category;
u08 program_type;
u16 padding1;
u16 header_size;
u16 meta_size;
u32 file_size;
u32 padding2;
u16 segment_count;
u16 unknown1A; //always 0x22
u32 padding3;
};
struct self_segment_header
{
bool IsBlocked() const {
return (flags & 0x800) != 0;//0 or 0x800
}
u32 GetId() const {
return (flags >> 20u) & 0xFFFu;
}
bool IsOrdered() const {
return (flags & 1) != 0;//0 or 1
}
bool IsEncrypted() const {
return (flags & 2) != 0;//0 or 2
}
bool IsSigned() const {
return (flags & 4) != 0;//0 or 4
}
bool IsCompressed() const {
return (flags & 8) != 0;//0 or 8
}
u64 flags;
u64 file_offset;
u64 file_size;
u64 memory_size;
};
constexpr u08 EI_MAG0 = 0;/* e_ident[] indexes */
constexpr u08 EI_MAG1 = 1;
constexpr u08 EI_MAG2 = 2;
constexpr u08 EI_MAG3 = 3;
constexpr u08 EI_CLASS = 4;
constexpr u08 EI_DATA = 5;
constexpr u08 EI_VERSION = 6;
constexpr u08 EI_OSABI = 7;
constexpr u08 EI_ABIVERSION = 8;
// Magic number
constexpr u08 ELFMAG0 = 0x7F;
constexpr u08 ELFMAG1 = 'E';
constexpr u08 ELFMAG2 = 'L';
constexpr u08 ELFMAG3 = 'F';
typedef enum : u16 {
ET_NONE = 0x0,
ET_REL = 0x1,
ET_EXEC = 0x2,
ET_DYN = 0x3,
ET_CORE = 0x4,
ET_SCE_EXEC = 0xfe00,
ET_SCE_STUBLIB = 0xfe0c,
ET_SCE_DYNEXEC = 0xfe10,
ET_SCE_DYNAMIC = 0xfe18
} e_type_s;
typedef enum : u16 {
EM_NONE = 0, /* No machine */
EM_M32 = 1, /* AT&T WE 32100 */
EM_SPARC = 2, /* SPARC */
EM_386 = 3, /* Intel 80386 */
EM_68K = 4, /* Motorola 68000 */
EM_88K = 5, /* Motorola 88000 */
EM_860 = 7, /* Intel 80860 */
EM_MIPS = 8, /* MIPS I Architecture */
EM_S370 = 9, /* IBM System/370 Processor */
EM_MIPS_RS3_LE = 10, /* MIPS RS3000 Little-endian */
EM_PARISC = 15, /* Hewlett-Packard PA-RISC */
EM_VPP500 = 17, /* Fujitsu VPP500 */
EM_SPARC32PLUS = 18, /* Enhanced instruction set SPARC */
EM_960 = 19, /* Intel 80960 */
EM_PPC = 20, /* PowerPC */
EM_PPC64 = 21, /* 64-bit PowerPC */
EM_S390 = 22, /* IBM System/390 Processor */
EM_V800 = 36, /* NEC V800 */
EM_FR20 = 37, /* Fujitsu FR20 */
EM_RH32 = 38, /* TRW RH-32 */
EM_RCE = 39, /* Motorola RCE */
EM_ARM = 40, /* Advanced RISC Machines ARM */
EM_ALPHA = 41, /* Digital Alpha */
EM_SH = 42, /* Hitachi SH */
EM_SPARCV9 = 43, /* SPARC Version 9 */
EM_TRICORE = 44, /* Siemens TriCore embedded processor */
EM_ARC = 45, /* Argonaut RISC Core, Argonaut Technologies Inc. */
EM_H8_300 = 46, /* Hitachi H8/300 */
EM_H8_300H = 47, /* Hitachi H8/300H */
EM_H8S = 48, /* Hitachi H8S */
EM_H8_500 = 49, /* Hitachi H8/500 */
EM_IA_64 = 50, /* Intel IA-64 processor architecture */
EM_MIPS_X = 51, /* Stanford MIPS-X */
EM_COLDFIRE = 52, /* Motorola ColdFire */
EM_68HC12 = 53, /* Motorola M68HC12 */
EM_MMA = 54, /* Fujitsu MMA Multimedia Accelerator */
EM_PCP = 55, /* Siemens PCP */
EM_NCPU = 56, /* Sony nCPU embedded RISC processor */
EM_NDR1 = 57, /* Denso NDR1 microprocessor */
EM_STARCORE = 58, /* Motorola Star*Core processor */
EM_ME16 = 59, /* Toyota ME16 processor */
EM_ST100 = 60, /* STMicroelectronics ST100 processor */
EM_TINYJ = 61, /* Advanced Logic Corp. TinyJ embedded processor family */
EM_X86_64 = 62, /* AMD x86-64 architecture (PS4) */
EM_PDSP = 63, /* Sony DSP Processor */
EM_PDP10 = 64, /* Digital Equipment Corp. PDP-10 */
EM_PDP11 = 65, /* Digital Equipment Corp. PDP-11 */
EM_FX66 = 66, /* Siemens FX66 microcontroller */
EM_ST9PLUS = 67, /* STMicroelectronics ST9+ 8/16 bit microcontroller */
EM_ST7 = 68, /* STMicroelectronics ST7 8-bit microcontroller */
EM_68HC16 = 69, /* Motorola MC68HC16 Microcontroller */
EM_68HC11 = 70, /* Motorola MC68HC11 Microcontroller */
EM_68HC08 = 71, /* Motorola MC68HC08 Microcontroller */
EM_68HC05 = 72, /* Motorola MC68HC05 Microcontroller */
EM_SVX = 73, /* Silicon Graphics SVx */
EM_ST19 = 75, /* Digital VAX */
EM_CRIS = 76, /* Axis Communications 32-bit embedded processor */
EM_JAVELIN = 77, /* Infineon Technologies 32-bit embedded processor */
EM_FIREPATH = 78, /* Element 14 64-bit DSP Processor */
EM_ZSP = 79, /* LSI Logic 16-bit DSP Processor */
EM_MMIX = 80, /* Donald Knuth's educational 64-bit processor */
EM_HUANY = 81, /* Harvard University machine-independent object files */
EM_PRISM = 82, /* SiTera Prism */
EM_AVR = 83, /* Atmel AVR 8-bit microcontroller */
EM_FR30 = 84, /* Fujitsu FR30 */
EM_D10V = 85, /* Mitsubishi D10V */
EM_D30V = 86, /* Mitsubishi D30V */
EM_V850 = 87, /* NEC v850 */
EM_M32R = 88, /* Mitsubishi M32R */
EM_MN10300 = 89, /* Matsushita MN10300 */
EM_MN10200 = 90, /* Matsushita MN10200 */
EM_PJ = 91, /* PicoJava */
EM_OPENRISC = 92, /* OpenRISC 32-bit embedded processor */
EM_ARC_A5 = 93, /* ARC Cores Tangent-A5 */
EM_XTENSA = 94, /* Tensilica Xtensa Architecture */
EM_VIDEOCORE = 95, /* Alphamosaic VideoCore processor */
EM_TMM_GPP = 96, /* Thompson Multimedia General Purpose Processor */
EM_NS32K = 97, /* National Semiconductor 32000 series */
EM_TPC = 98, /* Tenor Network TPC processor */
EM_SNP1K = 99, /* Trebia SNP 1000 processor */
EM_ST200 = 100, /* STMicroelectronics (www.st.com) ST200 microcontroller */
EM_IP2K = 101, /* Ubicom IP2xxx microcontroller family */
EM_MAX = 102, /* MAX Processor */
EM_CR = 103, /* National Semiconductor CompactRISC microprocessor */
EM_F2MC16 = 104, /* Fujitsu F2MC16 */
EM_MSP430 = 105, /* Texas Instruments embedded microcontroller msp430 */
EM_BLACKFIN = 106, /* Analog Devices Blackfin (DSP) processor */
EM_SE_C33 = 107, /* S1C33 Family of Seiko Epson processors */
EM_SEP = 108, /* Sharp embedded microprocessor */
EM_ARCA = 109, /* Arca RISC Microprocessor */
EM_UNICORE = 110 /* Microprocessor series from PKU-Unity Ltd. and MPRC */
} e_machine_es;
typedef enum :u32 {
EV_NONE = 0x0,
EV_CURRENT = 0x1
} e_version_es;
typedef enum : u08 {
ELF_CLASS_NONE =0x0,
ELF_CLASS_32 =0x1,
ELF_CLASS_64 =0x2,
ELF_CLASS_NUM =0x3
} ident_class_es;
typedef enum : u08 {
ELF_DATA_NONE = 0x0,
ELF_DATA_2LSB = 0x1,
ELF_DATA_2MSB = 0x2,
ELF_DATA_NUM = 0x3
} ident_endian_es;
typedef enum :u08 {
ELF_VERSION_NONE = 0x0,
ELF_VERSION_CURRENT = 0x1,
ELF_VERSION_NUM = 0x2
} ident_version_es;
typedef enum :u08 {
ELF_OSABI_NONE = 0x0, /* No extensions or unspecified */
ELF_OSABI_HPUX = 0x1, /* Hewlett-Packard HP-UX */
ELF_OSABI_NETBSD = 0x2, /* NetBSD */
ELF_OSABI_LINUX = 0x3, /* Linux */
ELF_OSABI_SOLARIS = 0x6, /* Sun Solaris */
ELF_OSABI_AIX = 0x7, /* AIX */
ELF_OSABI_IRIX = 0x8, /* IRIX */
ELF_OSABI_FREEBSD = 0x9, /* FreeBSD (PS4) */
ELF_OSABI_TRU64 = 0xA, /* Compaq TRU64 UNIX */
ELF_OSABI_MODESTO = 0xB, /* Novell Modesto */
ELF_OSABI_OPENBSD = 0xC, /* Open BSD */
ELF_OSABI_OPENVMS = 0xD, /* Open VMS */
ELF_OSABI_NSK = 0xE, /* Hewlett-Packard Non-Stop Kernel */
ELF_OSABI_AROS = 0xF, /* Amiga Research OS */
ELF_OSABI_ARM_AEABI = 0x40, /* ARM EABI */
ELF_OSABI_ARM = 0x61, /* ARM */
ELF_OSABI_STANDALONE = 0xFF /* Standalone (embedded applications) */
} ident_osabi_es;
typedef enum :u08 {
ELF_ABI_VERSION_AMDGPU_HSA_V2=0x0,
ELF_ABI_VERSION_AMDGPU_HSA_V3=0x1,
ELF_ABI_VERSION_AMDGPU_HSA_V4=0x2,
ELF_ABI_VERSION_AMDGPU_HSA_V5=0x3
} ident_abiversion_es;
struct elf_ident {
u08 magic[4];
ident_class_es ei_class;
ident_endian_es ei_data;
ident_version_es ei_version;
ident_osabi_es ei_osabi;
ident_abiversion_es ei_abiversion;
u08 pad[6];
};
struct elf_header
{
static const u32 signature = 0x7F454C46u;
elf_ident e_ident; /* ELF identification */
e_type_s e_type; /* Object file type */
e_machine_es e_machine; /* Machine type */
e_version_es e_version; /* Object file version */
u64 e_entry; /* Entry point address */
u64 e_phoff; /* Program header offset */
u64 e_shoff; /* Section header offset */
u32 e_flags; /* Processor-specific flags */
u16 e_ehsize; /* ELF header size */
u16 e_phentsize; /* Size of program header entry */
u16 e_phnum; /* Number of program header entries */
u16 e_shentsize; /* Size of section header entry */
u16 e_shnum; /* Number of section header entries */
u16 e_shstrndx; /* Section name string table index */
};
typedef enum : u32 {
PT_NULL = 0x0,
PT_LOAD = 0x1,
PT_DYNAMIC = 0x2,
PT_INTERP = 0x3,
PT_NOTE = 0x4,
PT_SHLIB = 0x5,
PT_PHDR = 0x6,
PT_TLS = 0x7,
PT_NUM = 0x8,
PT_SCE_RELA = 0x60000000,
PT_SCE_DYNLIBDATA = 0x61000000,
PT_SCE_PROCPARAM = 0x61000001,
PT_SCE_MODULE_PARAM = 0x61000002,
PT_SCE_RELRO = 0x61000010,
PT_GNU_EH_FRAME = 0x6474e550,
PT_GNU_STACK = 0x6474e551,
PT_GNU_RELRO = 0x6474e552,
PT_SCE_COMMENT = 0x6fffff00,
PT_SCE_LIBVERSION = 0x6fffff01,
PT_LOSUNW = 0x6ffffffa,
PT_SUNWBSS = 0x6ffffffa,
PT_SUNWSTACK = 0x6ffffffb,
PT_HISUNW = 0x6fffffff,
PT_HIOS = 0x6fffffff,
PT_LOPROC = 0x70000000,
PT_HIPROC = 0x7fffffff
} elf_program_type;
typedef enum : u32 {
PF_NONE = 0x0,
PF_EXEC = 0x1,
PF_WRITE = 0x2,
PF_WRITE_EXEC = 0x3,
PF_READ = 0x4,
PF_READ_EXEC = 0x5,
PF_READ_WRITE = 0x6,
PF_READ_WRITE_EXEC = 0x7
} elf_program_flags;
struct elf_program_header
{
elf_program_type p_type; /* Type of segment */
elf_program_flags p_flags; /* Segment attributes */
u64 p_offset; /* Offset in file */
u64 p_vaddr; /* Virtual address in memory */
u64 p_paddr; /* Reserved */
u64 p_filesz; /* Size of segment in file */
u64 p_memsz; /* Size of segment in memory */
u64 p_align; /* Alignment of segment */
};
struct elf_section_header
{
u32 sh_name; /* Section name */
u32 sh_type; /* Section type */
u64 sh_flags; /* Section attributes */
u64 sh_addr; /* Virtual address in memory */
u64 sh_offset; /* Offset in file */
u64 sh_size; /* Size of section */
u32 sh_link; /* Link to other section */
u32 sh_info; /* Miscellaneous information */
u64 sh_addralign; /* Address alignment boundary */
u64 sh_entsize; /* Size of entries, if section has table */
};
typedef enum :u64 {
PT_FAKE = 0x1,
PT_NPDRM_EXEC = 0x4,
PT_NPDRM_DYNLIB = 0x5,
PT_SYSTEM_EXEC = 0x8,
PT_SYSTEM_DYNLIB = 0x9,
PT_HOST_KERNEL = 0xC,
PT_SECURE_MODULE = 0xE,
PT_SECURE_KERNEL = 0xF
} program_type_es;
struct elf_program_id_header
{
u64 authid;
program_type_es program_type;
u64 appver;
u64 firmver;
u08 digest[32];
};
constexpr s64 DT_NULL = 0;
constexpr s64 DT_NEEDED = 0x00000001;
constexpr s64 DT_RELA = 0x00000007;
constexpr s64 DT_INIT = 0x0000000c;
constexpr s64 DT_FINI = 0x0000000d;
constexpr s64 DT_DEBUG = 0x00000015;
constexpr s64 DT_TEXTREL = 0x00000016;
constexpr s64 DT_INIT_ARRAY = 0x00000019;
constexpr s64 DT_FINI_ARRAY = 0x0000001a;
constexpr s64 DT_INIT_ARRAYSZ = 0x0000001b;
constexpr s64 DT_FINI_ARRAYSZ = 0x0000001c;
constexpr s64 DT_FLAGS = 0x0000001e;
constexpr s64 DT_PREINIT_ARRAY = 0x00000020;
constexpr s64 DT_PREINIT_ARRAYSZ = 0x00000021;
constexpr s64 DT_SCE_FINGERPRINT = 0x61000007;
constexpr s64 DT_SCE_ORIGINAL_FILENAME = 0x61000009;
constexpr s64 DT_SCE_MODULE_INFO = 0x6100000d;
constexpr s64 DT_SCE_NEEDED_MODULE = 0x6100000f;
constexpr s64 DT_SCE_MODULE_ATTR = 0x61000011;
constexpr s64 DT_SCE_EXPORT_LIB = 0x61000013;
constexpr s64 DT_SCE_IMPORT_LIB = 0x61000015;
constexpr s64 DT_SCE_IMPORT_LIB_ATTR = 0x61000019;
constexpr s64 DT_SCE_HASH = 0x61000025;
constexpr s64 DT_SCE_PLTGOT = 0x61000027;
constexpr s64 DT_SCE_JMPREL = 0x61000029;
constexpr s64 DT_SCE_PLTREL = 0x6100002b;
constexpr s64 DT_SCE_PLTRELSZ = 0x6100002d;
constexpr s64 DT_SCE_RELA = 0x6100002f;
constexpr s64 DT_SCE_RELASZ = 0x61000031;
constexpr s64 DT_SCE_RELAENT = 0x61000033;
constexpr s64 DT_SCE_SYMENT = 0x6100003b;
constexpr s64 DT_SCE_HASHSZ = 0x6100003d;
constexpr s64 DT_SCE_STRTAB = 0x61000035;
constexpr s64 DT_SCE_STRSZ = 0x61000037;
constexpr s64 DT_SCE_SYMTAB = 0x61000039;
constexpr s64 DT_SCE_SYMTABSZ = 0x6100003f;
struct elf_dynamic
{
s64 d_tag;
union
{
u64 d_val;
u64 d_ptr;
} d_un;
};
constexpr u08 STB_LOCAL = 0;
constexpr u08 STB_GLOBAL = 1;
constexpr u08 STB_WEAK = 2;
constexpr u08 STT_NOTYPE = 0;
constexpr u08 STT_OBJECT = 1;
constexpr u08 STT_FUN = 2;
constexpr u08 STT_SECTION = 3;
constexpr u08 STT_FILE = 4;
constexpr u08 STT_COMMON = 5;
constexpr u08 STT_TLS = 6;
constexpr u08 STT_LOOS = 10;
constexpr u08 STT_SCE = 11; //module_start/module_stop
constexpr u08 STT_HIOS = 12;
constexpr u08 STT_LOPRO = 13;
constexpr u08 STT_SPARC_REGISTER = 13;
constexpr u08 STT_HIPROC = 15;
constexpr u08 STV_DEFAULT = 0;
constexpr u08 STV_INTERNAL = 1;
constexpr u08 STV_HIDDEN = 2;
constexpr u08 STV_PROTECTED = 3;
struct elf_symbol
{
u08 GetBind() const { return st_info >> 4u; }
u08 GetType() const { return st_info & 0xfu; }
u08 GetVisibility() const { return st_other & 3u; }
u32 st_name;
u08 st_info;
u08 st_other;
u16 st_shndx;
u64 st_value;
u64 st_size;
};
struct elf_relocation
{
u32 GetSymbol() const { return static_cast<u32>(rel_info >> 32u); }
u32 GetType() const { return static_cast<u32>(rel_info & 0xffffffff); }
u64 rel_offset;
u64 rel_info;
s64 rel_addend;
};
constexpr u32 R_X86_64_64 = 1; // Direct 64 bit
constexpr u32 R_X86_64_JUMP_SLOT = 7; // Create PLT entry
constexpr u32 R_X86_64_RELATIVE = 8; // Adjust by program base
class Elf
{
public:
Elf() = default;
virtual ~Elf();
void Open(const std::string & file_name);
bool isSelfFile() const;
bool isElfFile() const;
void DebugDump();
[[nodiscard]] const self_header* GetSElfHeader() const { return m_self; }
[[nodiscard]] const elf_header* GetElfHeader() const { return m_elf_header; }
[[nodiscard]] const elf_program_header* GetProgramHeader() const { return m_elf_phdr; }
[[nodiscard]] const self_segment_header* GetSegmentHeader() const { return m_self_segments; }
std::string SElfHeaderStr();
std::string SELFSegHeader(u16 no);
std::string ElfHeaderStr();
std::string ElfPHeaderStr(u16 no);
std::string ElfPheaderTypeStr(u32 type);
std::string ElfPheaderFlagsStr(u32 flags);
void LoadSegment(u64 virtual_addr, u64 file_offset, u64 size);
u64 GetElfEntry();
private:
void Reset();
FsFile* m_f = nullptr;
self_header* m_self = nullptr;
self_segment_header* m_self_segments = nullptr;
elf_header* m_elf_header = nullptr;
elf_program_header* m_elf_phdr = nullptr;
elf_section_header* m_elf_shdr = nullptr;
elf_program_id_header* m_self_id_header = nullptr;
};

View File

@@ -1,32 +0,0 @@
#include "../../../types.h"
#include "SymbolsResolver.h"
#include <Util/log.h>
void SymbolsResolver::AddSymbol(const SymbolRes& s, u64 virtual_addr)
{
SymbolRecord r{};
r.name = GenerateName(s);
r.virtual_address = virtual_addr;
m_symbols.push_back(r);
}
std::string SymbolsResolver::GenerateName(const SymbolRes& s) {
char str[256];
sprintf(str, "%s lib[%s_v%d]mod[%s_v%d.%d]", s.name.c_str(),s.library.c_str(), s.library_version, s.module.c_str(),
s.module_version_major, s.module_version_minor);
return std::string(str);
}
const SymbolRecord* SymbolsResolver::FindSymbol(const SymbolRes& s) const {
std::string name = GenerateName(s);
int index = 0;
for (auto symbol : m_symbols) {
if (symbol.name.compare(name) == 0) {
return &m_symbols.at(index);
}
index++;
}
LOG_INFO_IF(true, "unresolved! {}\n", name);
return nullptr;
}

View File

@@ -1,40 +0,0 @@
#pragma once
#include <string>
#include <vector>
#include <unordered_map>
#include "../../../types.h"
struct SymbolRecord
{
std::string name;
u64 virtual_address;
};
struct SymbolRes
{
std::string name;
std::string nidName;
std::string library;
u16 library_version;
std::string module;
u08 module_version_major;
u08 module_version_minor;
u32 type;
};
class SymbolsResolver
{
public:
SymbolsResolver() = default;
virtual ~SymbolsResolver() = default;
void AddSymbol(const SymbolRes& s, u64 virtual_addr);
const SymbolRecord* FindSymbol(const SymbolRes& s) const;
static std::string GenerateName(const SymbolRes& s);
private:
std::vector<SymbolRecord> m_symbols;
};

View File

@@ -1,4 +0,0 @@
#include "types.h"
u64 UnresolvedStub();
u64 GetStub(const char *nid);

View File

@@ -1,38 +0,0 @@
#include "aerolib.h"
#include "types.h"
#include <string.h>
#include "Util/log.h"
namespace aerolib {
// Use a direct table here + binary search as contents are static
nid_entry nids[] = {
#define STUB(nid, name) \
{ nid, #name },
#include "aerolib.inl"
#undef STUB
};
nid_entry* find_by_nid(const char* nid) {
s64 l = 0;
s64 r = sizeof(nids) / sizeof(nids[0]) - 1;
while (l <= r) {
size_t m = l + (r - l) / 2;
int cmp = strcmp(nids[m].nid, nid);
if (cmp == 0)
return &nids[m];
else if (cmp < 0)
l = m + 1;
else
r = m - 1;
}
return nullptr;
}
} // namespace aerolib

View File

@@ -1,11 +0,0 @@
#include <stdint.h>
namespace aerolib {
struct nid_entry {
const char* nid;
const char* name;
};
nid_entry* find_by_nid(const char* nid);
};

View File

@@ -1,143 +0,0 @@
#include "virtual_memory.h"
#include "Core/PS4/Loader/Elf.h"
#ifdef _WIN64
#include <windows.h>
#else
#include <sys/mman.h>
#endif
#if !defined(_WIN64)
enum PosixPageProtection {
PAGE_NOACCESS = 0,
PAGE_READONLY = PROT_READ,
PAGE_READWRITE = PROT_READ | PROT_WRITE,
PAGE_EXECUTE = PROT_EXEC,
PAGE_EXECUTE_READ = PROT_EXEC | PROT_READ,
PAGE_EXECUTE_READWRITE = PROT_EXEC | PROT_READ | PROT_WRITE
};
#endif
#include <debug.h>
#include "../Util/Log.h"
namespace VirtualMemory {
static u32 convertMemoryMode(MemoryMode mode) {
switch (mode) {
case MemoryMode::Read: return PAGE_READONLY;
case MemoryMode::Write:
case MemoryMode::ReadWrite: return PAGE_READWRITE;
case MemoryMode::Execute: return PAGE_EXECUTE;
case MemoryMode::ExecuteRead: return PAGE_EXECUTE_READ;
case MemoryMode::ExecuteWrite:
case MemoryMode::ExecuteReadWrite: return PAGE_EXECUTE_READWRITE;
case MemoryMode::NoAccess: return PAGE_NOACCESS;
default: return PAGE_NOACCESS;
}
}
static MemoryMode convertMemoryMode(u32 mode) {
switch (mode) {
case PAGE_NOACCESS: return MemoryMode::NoAccess;
case PAGE_READONLY: return MemoryMode::Read;
case PAGE_READWRITE: return MemoryMode::ReadWrite;
case PAGE_EXECUTE: return MemoryMode::Execute;
case PAGE_EXECUTE_READ: return MemoryMode::ExecuteRead;
case PAGE_EXECUTE_READWRITE: return MemoryMode::ExecuteReadWrite;
default: return MemoryMode::NoAccess;
}
}
u64 memory_alloc(u64 address, u64 size, MemoryMode mode) {
#ifdef _WIN64
auto ptr = reinterpret_cast<uintptr_t>(VirtualAlloc(reinterpret_cast<LPVOID>(static_cast<uintptr_t>(address)), size,
static_cast<DWORD>(MEM_COMMIT) | static_cast<DWORD>(MEM_RESERVE), convertMemoryMode(mode)));
if (ptr == 0) {
auto err = static_cast<u32>(GetLastError());
LOG_ERROR_IF(true, "VirtualAlloc() failed: 0x{:X}\n", err);
}
#else
auto ptr = reinterpret_cast<uintptr_t>(
mmap(reinterpret_cast<void*>(static_cast<uintptr_t>(address)), size, PROT_EXEC | PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0));
if (ptr == reinterpret_cast<uintptr_t> MAP_FAILED) {
LOG_ERROR_IF(true, "mmap() failed: {}\n", std::strerror(errno));
}
#endif
return ptr;
}
bool memory_protect(u64 address, u64 size, MemoryMode mode, MemoryMode* old_mode) {
#ifdef _WIN64
DWORD old_protect = 0;
if (VirtualProtect(reinterpret_cast<LPVOID>(static_cast<uintptr_t>(address)), size, convertMemoryMode(mode), &old_protect) == 0) {
auto err = static_cast<u32>(GetLastError());
LOG_ERROR_IF(true, "VirtualProtect() failed: 0x{:X}\n", err);
return false;
}
if (old_mode != nullptr) {
*old_mode = convertMemoryMode(old_protect);
}
return true;
#else
#error Unimplement memory_protect function
#endif
}
bool memory_flush(u64 address, u64 size) {
#ifdef _WIN64
if (::FlushInstructionCache(GetCurrentProcess(), reinterpret_cast<LPVOID>(static_cast<uintptr_t>(address)), size) == 0) {
auto err = static_cast<u32>(GetLastError());
LOG_ERROR_IF(true, "FlushInstructionCache() failed: 0x{:X}\n", err);
return false;
}
return true;
#else // linux probably doesn't have something similar
return true;
#endif
}
bool memory_patch(u64 vaddr, u64 value) {
MemoryMode old_mode{};
memory_protect(vaddr, 8, MemoryMode::ReadWrite, &old_mode);
auto* ptr = reinterpret_cast<uint64_t*>(vaddr);
bool ret = (*ptr != value);
*ptr = value;
memory_protect(vaddr, 8, old_mode, nullptr);
// if mode is executable flush it so insure that cpu finds it
if ((old_mode == MemoryMode::Execute || old_mode == MemoryMode::ExecuteRead || old_mode == MemoryMode::ExecuteWrite ||
old_mode == MemoryMode::ExecuteReadWrite)) {
memory_flush(vaddr, 8);
}
return ret;
}
static u64 AlignUp(u64 pos, u64 align) { return (align != 0 ? (pos + (align - 1)) & ~(align - 1) : pos); }
u64 memory_alloc_aligned(u64 address, u64 size, MemoryMode mode, u64 alignment) {
// try allocate aligned address inside user area
MEM_ADDRESS_REQUIREMENTS req{};
MEM_EXTENDED_PARAMETER param{};
req.LowestStartingAddress = (address == 0 ? reinterpret_cast<PVOID>(USER_MIN) : reinterpret_cast<PVOID>(AlignUp(address, alignment)));
req.HighestEndingAddress = reinterpret_cast<PVOID>(USER_MAX);
req.Alignment = alignment;
param.Type = MemExtendedParameterAddressRequirements;
param.Pointer = &req;
auto ptr = reinterpret_cast<uintptr_t>(VirtualAlloc2(
GetCurrentProcess(), nullptr, size, static_cast<DWORD>(MEM_COMMIT) | static_cast<DWORD>(MEM_RESERVE), convertMemoryMode(mode), &param, 1));
if (ptr == 0) {
auto err = static_cast<u32>(GetLastError());
LOG_ERROR_IF(true, "VirtualAlloc2() failed: 0x{:X}\n", err);
}
return ptr;
}
} // namespace VirtualMemory

View File

@@ -1,63 +0,0 @@
#include "libc.h"
#include <debug.h>
#include <cmath>
#include <cstdlib>
#include <cstring>
namespace Emulator::HLE::Libraries::LibC {
PS4_SYSV_ABI int printf(VA_ARGS) {
VA_CTX(ctx);
return printf_ctx(&ctx);
}
int PS4_SYSV_ABI vsnprintf(char* s, size_t n, const char* format, VaList* arg) { return vsnprintf_ctx(s, n, format, arg); }
PS4_SYSV_ABI void exit(int code) { std::exit(code); }
PS4_SYSV_ABI int atexit(void (*func)()) {
int rt = std::atexit(func);
if (rt != 0) {
BREAKPOINT();
}
return rt;
}
int PS4_SYSV_ABI memcmp(const void* s1, const void* s2, size_t n) { return std::memcmp(s1, s2, n); }
void* PS4_SYSV_ABI memcpy(void* dest, const void* src, size_t n) { return std::memcpy(dest, src, n); }
void* PS4_SYSV_ABI memset(void* s, int c, size_t n) { return std::memset(s, c, n); }
void* PS4_SYSV_ABI malloc(size_t size) { return std::malloc(size); }
void PS4_SYSV_ABI free(void* ptr) { std::free(ptr); }
int PS4_SYSV_ABI strcmp(const char* str1, const char* str2) { return std::strcmp(str1, str2); }
size_t PS4_SYSV_ABI strlen(const char* str) { return std::strlen(str); }
char* PS4_SYSV_ABI strncpy(char* dest, const char* src, size_t count) { return std::strncpy(dest, src, count); }
void* PS4_SYSV_ABI memmove(void* dest, const void* src, std::size_t count) { return std::memmove(dest, src, count); }
char* PS4_SYSV_ABI strcpy(char* dest, const char* src) { return std::strcpy(dest, src); }
char* PS4_SYSV_ABI strcat(char* dest, const char* src) { return std::strcat(dest, src); }
// math
float PS4_SYSV_ABI atan2f(float y, float x) { return std::atan2f(y, x); }
float PS4_SYSV_ABI acosf(float num) { return std::acosf(num); }
float PS4_SYSV_ABI tanf(float num) { return std::tanf(num); }
float PS4_SYSV_ABI asinf(float num) { return std::asinf(num); }
double PS4_SYSV_ABI pow(double base, double exponent) { return std::pow(base, exponent); }
double PS4_SYSV_ABI _Sin(double x) { return std::sin(x); }
}; // namespace Emulator::HLE::Libraries::LibC

View File

@@ -1,32 +0,0 @@
#pragma once
#include <types.h>
#include "printf.h"
namespace Emulator::HLE::Libraries::LibC {
// HLE functions
PS4_SYSV_ABI int printf(VA_ARGS);
int PS4_SYSV_ABI vsnprintf(char* s, size_t n, const char* format, VaList* arg);
PS4_SYSV_ABI void exit(int code);
PS4_SYSV_ABI int atexit(void (*func)());
int PS4_SYSV_ABI memcmp(const void* s1, const void* s2, size_t n);
void* PS4_SYSV_ABI memcpy(void* dest, const void* src, size_t n);
void* PS4_SYSV_ABI memset(void* s, int c, size_t n);
void* PS4_SYSV_ABI malloc(size_t size);
void PS4_SYSV_ABI free(void* ptr);
int PS4_SYSV_ABI strcmp(const char* str1, const char* str2);
size_t PS4_SYSV_ABI strlen(const char* str);
char* PS4_SYSV_ABI strncpy(char* dest, const char* src, size_t count);
void* PS4_SYSV_ABI memmove(void* dest, const void* src, std::size_t count);
char* PS4_SYSV_ABI strcpy(char* destination, const char* source);
char* PS4_SYSV_ABI strcat(char* dest, const char* src);
float PS4_SYSV_ABI atan2f(float y, float x);
float PS4_SYSV_ABI acosf(float num);
float PS4_SYSV_ABI tanf(float num);
float PS4_SYSV_ABI asinf(float num);
double PS4_SYSV_ABI pow(double base, double exponent);
double PS4_SYSV_ABI _Sin(double x);
} // namespace Emulator::HLE::Libraries::LibC

View File

@@ -1,11 +0,0 @@
#pragma once
#define _TIMESPEC_DEFINED
#include <pthread.h>
#include <types.h>
namespace Emulator::HLE::Libraries::LibC::Cxa {
int PS4_SYSV_ABI __cxa_guard_acquire(u64* guard_object);
void PS4_SYSV_ABI __cxa_guard_release(u64* guard_object);
void PS4_SYSV_ABI __cxa_guard_abort(u64* guard_object);
} // namespace Emulator::HLE::Libraries::LibC::Cxa

View File

@@ -1,106 +0,0 @@
#include <types.h>
#include <xmmintrin.h>
#define VA_ARGS \
uint64_t rdi, uint64_t rsi, uint64_t rdx, uint64_t rcx, uint64_t r8, uint64_t r9, uint64_t overflow_arg_area, __m128 xmm0, __m128 xmm1, \
__m128 xmm2, __m128 xmm3, __m128 xmm4, __m128 xmm5, __m128 xmm6, __m128 xmm7, ...
#define VA_CTX(ctx) \
alignas(16) VaCtx ctx; \
(ctx).reg_save_area.gp[0] = rdi; \
(ctx).reg_save_area.gp[1] = rsi; \
(ctx).reg_save_area.gp[2] = rdx; \
(ctx).reg_save_area.gp[3] = rcx; \
(ctx).reg_save_area.gp[4] = r8; \
(ctx).reg_save_area.gp[5] = r9; \
(ctx).reg_save_area.fp[0] = xmm0; \
(ctx).reg_save_area.fp[1] = xmm1; \
(ctx).reg_save_area.fp[2] = xmm2; \
(ctx).reg_save_area.fp[3] = xmm3; \
(ctx).reg_save_area.fp[4] = xmm4; \
(ctx).reg_save_area.fp[5] = xmm5; \
(ctx).reg_save_area.fp[6] = xmm6; \
(ctx).reg_save_area.fp[7] = xmm7; \
(ctx).va_list.reg_save_area = &(ctx).reg_save_area; \
(ctx).va_list.gp_offset = offsetof(VaRegSave, gp); \
(ctx).va_list.fp_offset = offsetof(VaRegSave, fp); \
(ctx).va_list.overflow_arg_area = &overflow_arg_area;
namespace Emulator::HLE::Libraries::LibC {
// https://stackoverflow.com/questions/4958384/what-is-the-format-of-the-x86-64-va-list-structure
struct VaList {
u32 gp_offset;
u32 fp_offset;
void* overflow_arg_area;
void* reg_save_area;
};
struct VaRegSave {
u64 gp[6];
__m128 fp[8];
};
struct VaCtx {
VaRegSave reg_save_area;
VaList va_list;
};
template <class T, uint32_t Size>
T vaArgRegSaveAreaGp(VaList* l) {
auto* addr = reinterpret_cast<T*>(static_cast<u08*>(l->reg_save_area) + l->gp_offset);
l->gp_offset += Size;
return *addr;
}
template <class T, u64 Align, u64 Size>
T vaArgOverflowArgArea(VaList* l) {
auto ptr = ((reinterpret_cast<u64>(l->overflow_arg_area) + (Align - 1)) & ~(Align - 1));
auto* addr = reinterpret_cast<T*>(ptr);
l->overflow_arg_area = reinterpret_cast<void*>(ptr + Size);
return *addr;
}
template <class T, uint32_t Size>
T vaArgRegSaveAreaFp(VaList* l) {
auto* addr = reinterpret_cast<T*>(static_cast<u08*>(l->reg_save_area) + l->fp_offset);
l->fp_offset += Size;
return *addr;
}
inline int vaArgInteger(VaList* l) {
if (l->gp_offset <= 40) {
return vaArgRegSaveAreaGp<int, 8>(l);
}
return vaArgOverflowArgArea<int, 1, 8>(l);
}
inline long long vaArgLongLong(VaList* l) {
if (l->gp_offset <= 40) {
return vaArgRegSaveAreaGp<long long, 8>(l);
}
return vaArgOverflowArgArea<long long, 1, 8>(l);
}
inline long vaArgLong(VaList* l) {
if (l->gp_offset <= 40) {
return vaArgRegSaveAreaGp<long, 8>(l);
}
return vaArgOverflowArgArea<long, 1, 8>(l);
}
inline double vaArgDouble(VaList* l) {
if (l->fp_offset <= 160) {
return vaArgRegSaveAreaFp<double, 16>(l);
}
return vaArgOverflowArgArea<double, 1, 8>(l);
}
template <class T>
T* vaArgPtr(VaList* l) {
if (l->gp_offset <= 40) {
return vaArgRegSaveAreaGp<T*, 8>(l);
}
return vaArgOverflowArgArea<T*, 1, 8>(l);
}
} // namespace Emulator::HLE::Libraries::LibC

View File

@@ -1,13 +0,0 @@
#include "file_system.h"
#include <debug.h>
#include <Util/log.h>
namespace Emulator::HLE::Libraries::LibKernel::FileSystem {
constexpr bool log_file_fs = true; // disable it to disable logging
int PS4_SYSV_ABI sceKernelOpen(const char* path, int flags, u16 mode) {
LOG_INFO_IF(log_file_fs, "sceKernelOpen path = {} flags = {} mode = {}\n", path, log_hex_full(flags), log_hex_full(mode));
return 0;
}
} // namespace Emulator::HLE::Libraries::LibKernel::FileSystem

View File

@@ -1,7 +0,0 @@
#pragma once
#include <types.h>
namespace Emulator::HLE::Libraries::LibKernel::FileSystem {
int PS4_SYSV_ABI sceKernelOpen(const char *path, int flags, /* SceKernelMode*/ u16 mode);
}

View File

@@ -1,27 +0,0 @@
#pragma once
#include <types.h>
#include <string>
namespace Emulator::Host::GenericFS {
enum FileAccess {
FILEACCESS_READ = 0,
FILEACCESS_WRITE = 1,
FILEACCESS_READWRITE = 2
};
class GenericHandleAllocator {
public:
virtual u32 requestHandle() = 0;
virtual void releaseHandle(u32 handle) = 0;
};
class AbstractFileSystem {
public:
virtual bool ownsHandle(u32 handle) = 0;
virtual u32 openFile(std::string filename, FileAccess access) = 0;
virtual void closeFile(u32 handle) = 0;
};
} // namespace Emulator::Host::GenericFS

View File

@@ -1,52 +0,0 @@
#include "meta_file_system.h"
namespace Emulator::Host::GenericFS {
void MetaFileSystem::mount(std::string prefix, AbstractFileSystem* system) {
System x;
x.prefix = prefix;
x.system = system;
fileSystems.push_back(x);
}
void MetaFileSystem::unMount(AbstractFileSystem* system) {}
void MetaFileSystem::unMountAll() { fileSystems.clear(); }
AbstractFileSystem* MetaFileSystem::getHandleOwner(u32 handle) {
for (u32 i = 0; i < fileSystems.size(); i++) {
if (fileSystems[i].system->ownsHandle(handle)) return fileSystems[i].system; // got it!
}
return nullptr;
}
bool MetaFileSystem::mapFilePath(std::string inpath, std::string* outpath, AbstractFileSystem** system) {
for (unsigned int i = 0; i < fileSystems.size(); i++) {
int prefLen = fileSystems[i].prefix.size();
if (fileSystems[i].prefix == inpath.substr(0, prefLen))
{
*outpath = inpath.substr(prefLen);
*system = fileSystems[i].system;
return true;
}
}
return false;
}
u32 MetaFileSystem::openFile(std::string filename, FileAccess access) {
AbstractFileSystem* system;
std::string of;
if (mapFilePath(filename, &of, &system)) {
return system->openFile(of, access);
}
return 0;
}
void MetaFileSystem::closeFile(u32 handle) {
AbstractFileSystem* sys = getHandleOwner(handle);
if (sys) sys->closeFile(handle);
}
} // namespace Emulator::Host::GenericFS

View File

@@ -1,40 +0,0 @@
#pragma once
#include <types.h>
#include <string>
#include <vector>
#include "generic_file_system.h"
namespace Emulator::Host::GenericFS {
class MetaFileSystem : public GenericHandleAllocator, AbstractFileSystem {
struct System {
std::string prefix;
AbstractFileSystem *system;
};
u32 current;
std::vector<System> fileSystems;
std::string currentDirectory;
std::vector<u32> handler;
public:
MetaFileSystem() : current(0) {}
void mount(std::string prefix, AbstractFileSystem *system);
void unMount(AbstractFileSystem *system);
void unMountAll();
AbstractFileSystem *getHandleOwner(u32 handle);
bool mapFilePath(std::string inpath, std::string *outpath, AbstractFileSystem **system);
u32 requestHandle() {
handler.push_back(current);
current++;
return handler.back();
}
void releaseHandle(u32 handle) { handler.erase(std::remove(handler.begin(), handler.end(), handle), handler.end()); }
bool ownsHandle(u32 handle) { return false; }
u32 openFile(std::string filename, FileAccess access);
void closeFile(u32 handle);
};
} // namespace Emulator::Host::GenericFS

View File

@@ -1,15 +0,0 @@
#include "posix_file_system.h"
#include <debug.h>
#include "file_system.h"
namespace Emulator::HLE::Libraries::LibKernel::FileSystem::POSIX {
int PS4_SYSV_ABI open(const char* path, int flags, /* SceKernelMode*/ u16 mode) {
int result = sceKernelOpen(path, flags, mode);
if (result < 0) {
BREAKPOINT(); // posix calls different only for their return values
}
return result;
}
} // namespace Emulator::HLE::Libraries::LibKernel::FileSystem::POSIX

View File

@@ -1,6 +0,0 @@
#pragma once
#include "types.h"
namespace Emulator::HLE::Libraries::LibKernel::FileSystem::POSIX {
int PS4_SYSV_ABI open(const char *path, int flags, /* SceKernelMode*/ u16 mode);
}

View File

@@ -1,55 +0,0 @@
#include "pad.h"
#include <Core/PS4/HLE/ErrorCodes.h>
#include <Core/PS4/HLE/Libs.h>
#include "Emulator/Util/singleton.h"
#include "Emulator/Host/controller.h"
#include <debug.h>
#include <Util/log.h>
namespace Emulator::HLE::Libraries::LibPad {
constexpr bool log_file_pad = true; // disable it to disable logging
int PS4_SYSV_ABI scePadInit() { return SCE_OK; }
int PS4_SYSV_ABI scePadOpen(Emulator::HLE::Libraries::LibUserService::SceUserServiceUserId userId, s32 type, s32 index,
const ScePadOpenParam* pParam) {
return 1; // dummy
}
int PS4_SYSV_ABI scePadReadState(int32_t handle, ScePadData* pData) {
auto* controller = singleton<Emulator::Host::Controller::GameController>::instance();
int connectedCount = 0;
bool isConnected = false;
Emulator::Host::Controller::State state;
controller->readState(&state, &isConnected, &connectedCount);
pData->buttons = state.buttonsState;
pData->leftStick.x = 128; // dummy
pData->leftStick.y = 128; // dummy
pData->rightStick.x = 0; // dummy
pData->rightStick.y = 0; // dummy
pData->analogButtons.r2 = 0;//dummy
pData->analogButtons.l2 = 0;//dummy
pData->orientation.x = 0;
pData->orientation.y = 0;
pData->orientation.z = 0;
pData->orientation.w = 0;
pData->connected = true; // isConnected; //TODO fix me proper
pData->connectedCount = 1;//connectedCount;
pData->deviceUniqueDataLen = 0;
return SCE_OK;
}
void libPad_Register(SymbolsResolver* sym) {
LIB_FUNCTION("hv1luiJrqQM", "libScePad", 1, "libScePad", 1, 1, scePadInit);
LIB_FUNCTION("xk0AcarP3V4", "libScePad", 1, "libScePad", 1, 1, scePadOpen);
LIB_FUNCTION("YndgXqQVV7c", "libScePad", 1, "libScePad", 1, 1, scePadReadState);
}
} // namespace Emulator::HLE::Libraries::LibPad

View File

@@ -1,98 +0,0 @@
#pragma once
#include <Emulator/HLE/Libraries/LibUserService/user_service.h>
#include <types.h>
#include "Core/PS4/Loader/SymbolsResolver.h"
namespace Emulator::HLE::Libraries::LibPad {
typedef enum : u32 {
SCE_PAD_BUTTON_L3 = 0x00000002,
SCE_PAD_BUTTON_R3 = 0x00000004,
SCE_PAD_BUTTON_OPTIONS = 0x00000008,
SCE_PAD_BUTTON_UP = 0x00000010,
SCE_PAD_BUTTON_RIGHT = 0x00000020,
SCE_PAD_BUTTON_DOWN = 0x00000040,
SCE_PAD_BUTTON_LEFT = 0x00000080,
SCE_PAD_BUTTON_L2 = 0x00000100,
SCE_PAD_BUTTON_R2 = 0x00000200,
SCE_PAD_BUTTON_L1 = 0x00000400,
SCE_PAD_BUTTON_R1 = 0x00000800,
SCE_PAD_BUTTON_TRIANGLE = 0x00001000,
SCE_PAD_BUTTON_CIRCLE = 0x00002000,
SCE_PAD_BUTTON_CROSS = 0x00004000,
SCE_PAD_BUTTON_SQUARE = 0x00008000,
SCE_PAD_BUTTON_TOUCH_PAD = 0x00100000,
SCE_PAD_BUTTON_INTERCEPTED = 0x80000000,
} ScePadButton;
struct ScePadOpenParam {
u08 reserve[8];
};
struct ScePadAnalogStick {
u08 x;
u08 y;
};
struct ScePadAnalogButtons {
u08 l2;
u08 r2;
u08 padding[2];
};
struct SceFQuaternion {
float x, y, z, w;
};
struct SceFVector3 {
float x, y, z;
};
struct ScePadTouch {
u16 x;
u16 y;
u08 id;
u08 reserve[3];
};
constexpr int SCE_PAD_MAX_TOUCH_NUM = 2;
typedef struct ScePadTouchData {
u08 touchNum;
u08 reserve[3];
u32 reserve1;
ScePadTouch touch[SCE_PAD_MAX_TOUCH_NUM];
} ScePadTouchData;
struct ScePadExtensionUnitData {
u32 extensionUnitId;
u08 reserve[1];
u08 dataLength;
u08 data[10];
};
struct ScePadData {
u32 buttons;
ScePadAnalogStick leftStick;
ScePadAnalogStick rightStick;
ScePadAnalogButtons analogButtons;
SceFQuaternion orientation;
SceFVector3 acceleration;
SceFVector3 angularVelocity;
ScePadTouchData touchData;
bool connected;
u64 timestamp;
ScePadExtensionUnitData extensionUnitData;
uint8_t connectedCount;
uint8_t reserve[2];
uint8_t deviceUniqueDataLen;
uint8_t deviceUniqueData[12];
};
// hle functions
int PS4_SYSV_ABI scePadInit();
int PS4_SYSV_ABI scePadOpen(Emulator::HLE::Libraries::LibUserService::SceUserServiceUserId userId, s32 type, s32 index,
const ScePadOpenParam* pParam);
int PS4_SYSV_ABI scePadReadState(int32_t handle, ScePadData* pData);
void libPad_Register(SymbolsResolver* sym);
}; // namespace Emulator::HLE::Libraries::LibPad

View File

@@ -1,16 +0,0 @@
#include <Core/PS4/HLE/ErrorCodes.h>
#include <Core/PS4/HLE/Libs.h>
#include "system_service.h"
namespace Emulator::HLE::Libraries::LibSystemService {
s32 PS4_SYSV_ABI sceSystemServiceHideSplashScreen() {
// dummy
return SCE_OK;
}
void libSystemService_Register(SymbolsResolver* sym) {
LIB_FUNCTION("Vo5V8KAwCmk", "libSceSystemService", 1, "libSceSystemService", 1, 1, sceSystemServiceHideSplashScreen);
}
}; // namespace Emulator::HLE::Libraries::LibUserService

View File

@@ -1,11 +0,0 @@
#pragma once
#include "Core/PS4/Loader/SymbolsResolver.h"
namespace Emulator::HLE::Libraries::LibSystemService {
//HLE functions
s32 PS4_SYSV_ABI sceSystemServiceHideSplashScreen();
void libSystemService_Register(SymbolsResolver* sym);
}; // namespace Emulator::HLE::Libraries::LibUserService

View File

@@ -1,26 +0,0 @@
#include "user_service.h"
#include <Core/PS4/HLE/ErrorCodes.h>
#include <Core/PS4/HLE/Libs.h>
namespace Emulator::HLE::Libraries::LibUserService {
s32 PS4_SYSV_ABI sceUserServiceInitialize(const SceUserServiceInitializeParams* initParams) {
// dummy
return SCE_OK;
}
s32 PS4_SYSV_ABI sceUserServiceGetLoginUserIdList(SceUserServiceLoginUserIdList* userIdList) {
// dummy
userIdList->user_id[0] = 1;
userIdList->user_id[1] = -1;
userIdList->user_id[2] = -1;
userIdList->user_id[3] = -1;
return SCE_OK;
}
void libUserService_Register(SymbolsResolver* sym) {
LIB_FUNCTION("j3YMu1MVNNo", "libSceUserService", 1, "libSceUserService", 1, 1, sceUserServiceInitialize);
LIB_FUNCTION("fPhymKNvK-A", "libSceUserService", 1, "libSceUserService", 1, 1, sceUserServiceGetLoginUserIdList);
}
}; // namespace Emulator::HLE::Libraries::LibUserService

View File

@@ -1,20 +0,0 @@
#pragma once
#include "Core/PS4/Loader/SymbolsResolver.h"
namespace Emulator::HLE::Libraries::LibUserService {
using SceUserServiceUserId = s32;
struct SceUserServiceInitializeParams {
s32 priority;
};
struct SceUserServiceLoginUserIdList {
int user_id[4];
};
s32 PS4_SYSV_ABI sceUserServiceInitialize(const SceUserServiceInitializeParams* initParams);
s32 PS4_SYSV_ABI sceUserServiceGetLoginUserIdList(SceUserServiceLoginUserIdList* userIdList);
void libUserService_Register(SymbolsResolver* sym);
}; // namespace Emulator::HLE::Libraries::LibUserService

View File

@@ -1,11 +1,18 @@
#include "controller.h"
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "Emulator/Host/controller.h"
#include "core/hle/libraries/libkernel/time_management.h"
namespace Emulator::Host::Controller {
GameController::GameController() { m_states_num = 0;
GameController::GameController() {
m_states_num = 0;
m_last_state = State();
}
void GameController::readState(State* state, bool* isConnected, int* connectedCount) {
Lib::LockMutexGuard lock(m_mutex);
std::scoped_lock lock{m_mutex};
*isConnected = m_connected;
*connectedCount = m_connected_count;
@@ -37,8 +44,9 @@ void GameController::addState(const State& state) {
}
void GameController::checKButton(int id, u32 button, bool isPressed) {
Lib::LockMutexGuard lock(m_mutex);
std::scoped_lock lock{m_mutex};
auto state = getLastState();
state.time = Core::Libraries::LibKernel::sceKernelGetProcessTime();
if (isPressed) {
state.buttonsState |= button;
} else {
@@ -48,4 +56,4 @@ void GameController::checKButton(int id, u32 button, bool isPressed) {
addState(state);
}
} // namespace Emulator::Host::Controller
} // namespace Emulator::Host::Controller

View File

@@ -1,16 +1,21 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <types.h>
#include "Lib/Threads.h"
#include <mutex>
#include "common/types.h"
namespace Emulator::Host::Controller {
struct State {
u32 buttonsState =0;
u32 buttonsState = 0;
u64 time = 0;
};
constexpr u32 MAX_STATES = 64;
class GameController {
public:
public:
GameController();
virtual ~GameController() = default;
@@ -19,9 +24,8 @@ class GameController {
void checKButton(int id, u32 button, bool isPressed);
void addState(const State& state);
private:
Lib::Mutex m_mutex;
private:
std::mutex m_mutex;
bool m_connected = false;
State m_last_state;
int m_connected_count = 0;
@@ -30,4 +34,4 @@ class GameController {
State m_states[MAX_STATES];
};
} // namespace Emulator::HLE::Libraries::Controller
} // namespace Emulator::Host::Controller

View File

@@ -1,24 +0,0 @@
#pragma once
#include <cstdlib>
#include <new>
template <class T>
class singleton {
public:
static T* instance() {
if (!m_instance) {
m_instance = static_cast<T*>(std::malloc(sizeof(T)));
new (m_instance) T;
}
return m_instance;
}
protected:
singleton();
~singleton();
private:
static inline T* m_instance = nullptr;
};

View File

@@ -1,101 +0,0 @@
#include "ElfViewer.h"
#include "imgui.h"
ElfViewer::ElfViewer(Elf* elf)
{
this->elf = elf;
}
//function to display Self/Elf window
void ElfViewer::display(bool enabled)
{
int SELF_HEADER = 0;
int ELF_HEADER = 1;
int SEG_HEADER_START = 100;
int ELF_PROGRAM_HEADER_START = 200;
static int selected = -1;
ImGui::Begin("Self/Elf Viewer", &enabled);
ImGui::BeginChild("Left Tree pane", ImVec2(300, 0), false);//left tree
if (elf->isSelfFile())
{
if (ImGui::TreeNode("Self"))
{
if (ImGui::TreeNodeEx("Self Header", ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen, "Self Header"))
{
if (ImGui::IsItemClicked())
selected = SELF_HEADER;
}
if (ImGui::TreeNode("Self Segment Header"))
{
const auto* self = elf->GetSElfHeader();
for (u16 i = 0; i < self->segment_count; i++)
{
if (ImGui::TreeNodeEx((void*)(intptr_t)i, ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen, "%d", i))
{
if (ImGui::IsItemClicked())
selected = SEG_HEADER_START+i;
}
}
ImGui::TreePop();
}
ImGui::TreeNodeEx("Self Id Header", ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen, "Self Id Header");
ImGui::TreePop();
}
}
if (ImGui::TreeNode("Elf"))
{
const auto* elf_header = elf->GetElfHeader();
if (ImGui::TreeNodeEx("Elf Header", ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen, "Elf Header"))
{
if (ImGui::IsItemClicked())
selected = ELF_HEADER;
}
if (ImGui::TreeNode("Elf Program Headers"))
{
for (u16 i = 0; i < elf_header->e_phnum; i++)
{
const auto* pheader = elf->GetProgramHeader();
std::string ProgramInfo = elf->ElfPheaderFlagsStr((pheader + i)->p_flags) + " " + elf->ElfPheaderTypeStr((pheader + i)->p_type);
if (ImGui::TreeNodeEx((void*)(intptr_t)i,ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen, "%d - %s", i,ProgramInfo.c_str()))
{
if (ImGui::IsItemClicked())
selected = ELF_PROGRAM_HEADER_START + i;
}
}
ImGui::TreePop();
}
if (elf_header->e_shnum != 0)
{
if (ImGui::TreeNode("Elf Section Headers"))
{
ImGui::TreePop();
}
}
ImGui::TreePop();
}
ImGui::EndChild();//end of left tree
ImGui::SameLine();
ImGui::BeginChild("Table View", ImVec2(0, -ImGui::GetFrameHeightWithSpacing())); // Leave room for 1 line below us
if (selected == SELF_HEADER) {
ImGui::TextWrapped(elf->SElfHeaderStr().c_str());
}
if (selected >= 100 && selected < 200)
{
ImGui::TextWrapped(elf->SELFSegHeader(selected-100).c_str());
}
if (selected == ELF_HEADER) {
ImGui::TextWrapped(elf->ElfHeaderStr().c_str());
}
if (selected >= 200 && selected < 300)
{
ImGui::TextWrapped(elf->ElfPHeaderStr(selected - 200).c_str());
}
ImGui::EndChild();
ImGui::End();
}

View File

@@ -1,11 +0,0 @@
#pragma once
#include "../Core/PS4/Loader/Elf.h"
class ElfViewer {
private:
Elf* elf;
public:
ElfViewer(Elf* elf);
void display(bool enabled);//display imgui window
};

View File

@@ -1,79 +0,0 @@
#include "Threads.h"
#include <sstream>
static std::thread::id g_main_thread;
static int g_main_thread_int;
static std::atomic<int> g_thread_counter = 0;
void Lib::InitThreads() {
g_main_thread = std::this_thread::get_id();
g_main_thread_int = Lib::Thread::GetThreadIdUnique();
}
Lib::Thread::Thread(thread_func_t func, void* arg) {
m_thread = new ThreadStructInternal(func, arg);
while (!m_thread->started) {
SleepThreadMicro(1000);
}
}
Lib::Thread::~Thread() { delete m_thread; }
void Lib::Thread::JoinThread() { m_thread->m_thread.join(); }
void Lib::Thread::DetachThread() { m_thread->m_thread.detach(); }
std::string Lib::Thread::GetId() const {
std::stringstream ss;
ss << m_thread->m_thread.get_id();
return ss.str().c_str();
}
int Lib::Thread::GetUniqueId() const { return m_thread->unique_id; }
void Lib::Thread::SleepThread(u32 millis) { std::this_thread::sleep_for(std::chrono::milliseconds(millis)); }
void Lib::Thread::SleepThreadMicro(u32 micros) { std::this_thread::sleep_for(std::chrono::microseconds(micros)); }
void Lib::Thread::SleepThreadNano(u64 nanos) { std::this_thread::sleep_for(std::chrono::nanoseconds(nanos)); }
bool Lib::Thread::IsMainThread() { return g_main_thread == std::this_thread::get_id(); }
std::string Lib::Thread::GetThreadId() {
std::stringstream ss;
ss << std::this_thread::get_id();
return ss.str().c_str();
}
int Lib::Thread::GetThreadIdUnique() {
static thread_local int tid = ++g_thread_counter;
return tid;
}
Lib::Mutex::Mutex() { m_mutex = new MutexStructInternal(); }
Lib::Mutex::~Mutex() { delete m_mutex; }
void Lib::Mutex::LockMutex() { EnterCriticalSection(&m_mutex->m_cs); }
void Lib::Mutex::UnlockMutex() { LeaveCriticalSection(&m_mutex->m_cs); }
bool Lib::Mutex::TryLockMutex() { return (TryEnterCriticalSection(&m_mutex->m_cs) != 0); }
Lib::ConditionVariable::ConditionVariable() { m_cond_var = new ConditionVariableStructInternal(); }
Lib::ConditionVariable::~ConditionVariable() { delete m_cond_var; }
void Lib::ConditionVariable::WaitCondVar(Mutex* mutex) { SleepConditionVariableCS(&m_cond_var->m_cv, &mutex->m_mutex->m_cs, INFINITE); }
bool Lib::ConditionVariable::WaitCondVarFor(Mutex* mutex, u32 micros) {
bool ok = false;
ok = !(SleepConditionVariableCS(&m_cond_var->m_cv, &mutex->m_mutex->m_cs, (micros < 1000 ? 1 : micros / 1000)) == 0 &&
GetLastError() == ERROR_TIMEOUT);
return ok;
}
void Lib::ConditionVariable::SignalCondVar() { WakeConditionVariable(&m_cond_var->m_cv); }
void Lib::ConditionVariable::SignalCondVarAll() { WakeAllConditionVariable(&m_cond_var->m_cv); }

View File

@@ -1,131 +0,0 @@
#pragma once
#include "windows.h"
#include <synchapi.h>
#include <atomic>
#include <condition_variable>
#include <string>
#include <thread>
#include "../types.h"
namespace Lib {
using thread_func_t = void (*)(void*);
void InitThreads();
struct ThreadStructInternal;
struct MutexStructInternal;
struct ConditionVariableStructInternal;
class Thread {
public:
Thread(thread_func_t func, void* arg);
virtual ~Thread();
void JoinThread();
void DetachThread();
std::string GetId() const;
int GetUniqueId() const;
static void SleepThread(u32 millis);
static void SleepThreadMicro(u32 micros);
static void SleepThreadNano(u64 nanos);
static bool IsMainThread();
// Get current thread id (reusable id)
static std::string GetThreadId();
// Get current thread id (unique id)
static int GetThreadIdUnique();
public:
Thread(const Thread&) = delete;
Thread& operator=(const Thread&) = delete;
Thread(Thread&&) = delete;
Thread& operator=(Thread&&) = delete;
private:
ThreadStructInternal* m_thread;
};
struct ThreadStructInternal {
ThreadStructInternal(thread_func_t f, void* a) : func(f), arg(a), m_thread(&Run, this) {}
static void Run(ThreadStructInternal* t) {
t->unique_id = Lib::Thread::GetThreadIdUnique();
t->started = true;
t->func(t->arg);
}
thread_func_t func;
void* arg;
std::atomic_bool started = false;
int unique_id = 0;
std::thread m_thread;
};
class Mutex {
public:
Mutex();
virtual ~Mutex();
void LockMutex();
void UnlockMutex();
bool TryLockMutex();
friend class ConditionVariable;
public:
Mutex(const Mutex&) = delete;
Mutex& operator=(const Mutex&) = delete;
Mutex(Mutex&&) = delete;
Mutex& operator=(Mutex&&) = delete;
private:
MutexStructInternal* m_mutex;
};
struct MutexStructInternal {
MutexStructInternal() { InitializeCriticalSectionAndSpinCount(&m_cs, 4000); }
~MutexStructInternal() { DeleteCriticalSection(&m_cs); }
CRITICAL_SECTION m_cs{};
};
class ConditionVariable {
public:
ConditionVariable();
virtual ~ConditionVariable();
void WaitCondVar(Mutex* mutex);
bool WaitCondVarFor(Mutex* mutex, u32 micros);
void SignalCondVar();
void SignalCondVarAll();
private:
ConditionVariableStructInternal* m_cond_var;
};
struct ConditionVariableStructInternal {
ConditionVariableStructInternal() { InitializeConditionVariable(&m_cv); }
~ConditionVariableStructInternal() = default;
CONDITION_VARIABLE m_cv{};
};
class LockMutexGuard {
public:
explicit LockMutexGuard(Mutex& m) : m_mutex(m) { m_mutex.LockMutex(); }
~LockMutexGuard() { m_mutex.UnlockMutex(); }
private:
Mutex& m_mutex;
public:
LockMutexGuard(const LockMutexGuard&) = delete;
LockMutexGuard& operator=(const LockMutexGuard&) = delete;
LockMutexGuard(LockMutexGuard&&) noexcept = delete;
LockMutexGuard& operator=(LockMutexGuard&&) noexcept = delete;
};
} // namespace Lib

View File

@@ -1,103 +0,0 @@
#include "Timer.h"
#ifdef _WIN64
#include <windows.h>
#endif
Lib::Timer::Timer() {
#ifdef _WIN64
LARGE_INTEGER f;
QueryPerformanceFrequency(&f);
m_Frequency = f.QuadPart;
#else
#error Unimplemented Timer constructor
#endif
}
void Lib::Timer::Start() {
#ifdef _WIN64
LARGE_INTEGER c;
QueryPerformanceCounter(&c);
m_StartTime = c.QuadPart;
#else
#error Unimplemented Timer::Start()
#endif
m_is_timer_paused = false;
}
void Lib::Timer::Pause() {
#ifdef _WIN64
LARGE_INTEGER c;
QueryPerformanceCounter(&c);
m_PauseTime = c.QuadPart;
#else
#error Unimplemented Timer::Pause()
#endif
m_is_timer_paused = true;
}
void Lib::Timer::Resume() {
u64 current_time = 0;
#ifdef _WIN64
LARGE_INTEGER c;
QueryPerformanceCounter(&c);
current_time = c.QuadPart;
#else
#error Unimplemented Timer::Resume()
#endif
m_StartTime += current_time - m_PauseTime;
m_is_timer_paused = false;
}
bool Lib::Timer::IsPaused() const { return m_is_timer_paused; }
double Lib::Timer::GetTimeMsec() const {
if (m_is_timer_paused) {
return 1000.0 * (static_cast<double>(m_PauseTime - m_StartTime)) / static_cast<double>(m_Frequency);
}
u64 current_time = 0;
#ifdef _WIN64
LARGE_INTEGER c;
QueryPerformanceCounter(&c);
current_time = c.QuadPart;
#else
#error Unimplemented Timer::GetTimeMsec()
#endif
return 1000.0 * (static_cast<double>(current_time - m_StartTime)) / static_cast<double>(m_Frequency);
}
double Lib::Timer::GetTimeSec() const {
if (m_is_timer_paused) {
return (static_cast<double>(m_PauseTime - m_StartTime)) / static_cast<double>(m_Frequency);
}
u64 current_time = 0;
#ifdef _WIN64
LARGE_INTEGER c;
QueryPerformanceCounter(&c);
current_time = c.QuadPart;
#else
#error Unimplemented Timer::GetTimeSec()
#endif
return (static_cast<double>(current_time - m_StartTime)) / static_cast<double>(m_Frequency);
}
u64 Lib::Timer::GetTicks() const {
if (m_is_timer_paused) {
return (m_PauseTime - m_StartTime);
}
u64 current_time = 0;
#ifdef _WIN64
LARGE_INTEGER c;
QueryPerformanceCounter(&c);
current_time = c.QuadPart;
#else
#error Unimplemented Timer::GetTicks()
#endif
return (current_time - m_StartTime);
}
u64 Lib::Timer::GetFrequency() const { return m_Frequency; }

View File

@@ -1,34 +0,0 @@
#pragma once
#include "../types.h"
namespace Lib {
class Timer final
{
public:
Timer();
~Timer() = default;
void Start();
void Pause();
void Resume();
bool IsPaused() const;
double GetTimeMsec() const;// return time in milliseconds
double GetTimeSec() const;// return time in seconds
u64 GetTicks() const;// return time in ticks
u64 GetFrequency() const;// return ticks frequency
public:
Timer(const Timer&) = delete;
Timer& operator=(const Timer&) = delete;
Timer(Timer&&) = delete;
Timer& operator=(Timer&&) = delete;
private:
bool m_is_timer_paused = true;
u64 m_Frequency = 0;
u64 m_StartTime = 0;
u64 m_PauseTime = 0;
};
}

View File

@@ -1,36 +0,0 @@
#include "Disassembler.h"
#include <stdio.h>
Disassembler::Disassembler()
{
ZydisDecoderInit(&m_decoder, ZYDIS_MACHINE_MODE_LONG_64, ZYDIS_STACK_WIDTH_64);
ZydisFormatterInit(&m_formatter, ZYDIS_FORMATTER_STYLE_INTEL);
}
Disassembler::~Disassembler()
{
}
void Disassembler::printInstruction(void* code,u64 address)//print a single instruction
{
ZydisDecodedInstruction instruction;
ZydisDecodedOperand operands[ZYDIS_MAX_OPERAND_COUNT_VISIBLE];
ZyanStatus status = ZydisDecoderDecodeFull(&m_decoder, code, sizeof(code), &instruction, operands);
if (!ZYAN_SUCCESS(status))
{
printf("decode instruction failed at %p\n", code);
}
else
{
printInst(instruction, operands,address);
}
}
void Disassembler::printInst(ZydisDecodedInstruction& inst, ZydisDecodedOperand* operands,u64 address)
{
const int bufLen = 256;
char szBuffer[bufLen];
ZydisFormatterFormatInstruction(&m_formatter, &inst, operands,inst.operand_count_visible, szBuffer, sizeof(szBuffer), address, ZYAN_NULL);
printf("instruction: %s\n", szBuffer);
}

View File

@@ -1,17 +0,0 @@
#pragma once
#include "Zydis.h"
#include "../types.h"
class Disassembler
{
public:
Disassembler();
~Disassembler();
void printInst(ZydisDecodedInstruction& inst, ZydisDecodedOperand* operands,u64 address);
void printInstruction(void* code,u64 address);
private:
ZydisDecoder m_decoder;
ZydisFormatter m_formatter;
};

View File

@@ -1,15 +0,0 @@
#pragma once
#include <filesystem>
#include <types.h>
namespace Config {
void load(const std::filesystem::path& path);
void save(const std::filesystem::path& path);
bool isNeoMode();
u32 getLogLevel();
u32 getScreenWidth();
u32 getScreenHeight();
}; // namespace Config

View File

@@ -1,28 +0,0 @@
#include <spdlog/common.h>
#include <spdlog/pattern_formatter.h>
#include <spdlog/sinks/basic_file_sink.h>
#include <spdlog/sinks/stdout_color_sinks.h>
#include <spdlog/spdlog.h>
#include <vector>
#include <Util/config.h>
namespace logging {
std::vector<spdlog::sink_ptr> sinks;
int init(bool use_stdout) {
sinks.clear(); // clear existing sinks
if (use_stdout) // if we use stdout window then init it as well
sinks.push_back(std::make_shared<spdlog::sinks::stdout_color_sink_mt>());
sinks.push_back(std::make_shared<spdlog::sinks::basic_file_sink_mt>(L"shadps4.txt", true));
spdlog::set_default_logger(std::make_shared<spdlog::logger>("shadps4 logger", begin(sinks), end(sinks)));
auto f = std::make_unique<spdlog::pattern_formatter>("%^|%L|: %v%$", spdlog::pattern_time_type::local, std::string("")); // disable eol
spdlog::set_formatter(std::move(f));
spdlog::set_level(static_cast<spdlog::level::level_enum>(Config::getLogLevel()));
spdlog::level::level_enum t = spdlog::get_level();
return 0; // all ok
}
void set_level(spdlog::level::level_enum log_level) { spdlog::set_level(log_level); }
} // namespace logging

View File

@@ -1,73 +0,0 @@
#pragma once
#define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_TRACE
#include <spdlog/spdlog.h>
namespace logging {
#define LOG_TRACE SPDLOG_TRACE
#define LOG_DEBUG SPDLOG_DEBUG
#define LOG_INFO SPDLOG_INFO
#define LOG_WARN SPDLOG_WARN
#define LOG_ERROR SPDLOG_ERROR
#define LOG_CRITICAL SPDLOG_CRITICAL
#define LOG_TRACE_IF(flag, ...) \
if (flag) LOG_TRACE(__VA_ARGS__)
#define LOG_DEBUG_IF(flag, ...) \
if (flag) LOG_DEBUG(__VA_ARGS__)
#define LOG_INFO_IF(flag, ...) \
if (flag) LOG_INFO(__VA_ARGS__)
#define LOG_WARN_IF(flag, ...) \
if (flag) LOG_WARN(__VA_ARGS__)
#define LOG_ERROR_IF(flag, ...) \
if (flag) LOG_ERROR(__VA_ARGS__)
#define LOG_CRITICAL_IF(flag, ...) \
if (flag) LOG_CRITICAL(__VA_ARGS__)
int init(bool use_stdout);
void set_level(spdlog::level::level_enum log_level);
} // namespace logging
// copyright vita3k emu https://github.com/Vita3K/Vita3K/blob/master/vita3k/util/include/util/log.h
/*
returns: A string with the input number formatted in hexadecimal
Examples:
* `12` returns: `"0xC"`
* `1337` returns: `"0x539"`
* `72742069` returns: `"0x455F4B5"`
*/
template <typename T>
std::string log_hex(T val) {
using unsigned_type = typename std::make_unsigned<T>::type;
std::stringstream ss;
ss << "0x";
ss << std::hex << static_cast<unsigned_type>(val);
return ss.str();
}
/*
returns: A string with the input number formatted in hexadecimal with padding of the inputted type size
Examples:
* `uint8_t 5` returns: `"0x05"`
* `uint8_t 15` returns: `"0x0F"`
* `uint8_t 255` returns: `"0xFF"`
* `uint16_t 15` returns: `"0x000F"`
* `uint16_t 1337` returns: `"0x0539"`
* `uint16_t 65535` returns: `"0xFFFF"`
* `uint32_t 15` returns: `"0x0000000F"`
* `uint32_t 1337` returns: `"0x00000539"`
* `uint32_t 65535` returns: `"0x0000FFFF"`
* `uint32_t 134217728` returns: `"0x08000000"`
*/
template <typename T>
std::string log_hex_full(T val) {
std::stringstream ss;
ss << "0x";
ss << std::setfill('0') << std::setw(sizeof(T) * 2) << std::hex << val;
return ss.str();
}

View File

@@ -1,24 +0,0 @@
#include "string_util.h"
#include <algorithm>
#include <sstream>
#include <string>
namespace StringUtil {
std::vector<std::string> split_string(const std::string &str, char delimiter) {
std::stringstream str_stream(str);
std::string segment;
std::vector<std::string> seglist;
const size_t num_segments = std::count_if(str.begin(), str.end(), [&](char c) { return c == delimiter; }) + (str.empty() ? 1 : 0);
seglist.reserve(num_segments);
while (std::getline(str_stream, segment, delimiter)) {
seglist.push_back(segment);
}
return seglist;
}
} // namespace StringUtil

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