mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2025-12-11 14:19:10 +00:00
Compare commits
125 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
86911747bf | ||
|
|
7799211100 | ||
|
|
03e5cd2749 | ||
|
|
4980aa3fd5 | ||
|
|
7a42b9df79 | ||
|
|
2e931c9f72 | ||
|
|
2a03b4d03b | ||
|
|
8c4f386641 | ||
|
|
02dcf4d45c | ||
|
|
00d401e103 | ||
|
|
8ba6d7add0 | ||
|
|
12a8cf5ee9 | ||
|
|
7e54255d29 | ||
|
|
58ae9c3ade | ||
|
|
f2691d83b8 | ||
|
|
7425cb41a5 | ||
|
|
ffb2a583f9 | ||
|
|
02cbebbf78 | ||
|
|
99d013f612 | ||
|
|
84b0aff35b | ||
|
|
47e2619b51 | ||
|
|
79d6c8a377 | ||
|
|
b3084646a8 | ||
|
|
e40461b0c2 | ||
|
|
6e1f25d99f | ||
|
|
08aba86ca1 | ||
|
|
d89653551e | ||
|
|
584b7d2b15 | ||
|
|
6f4c6ae0bb | ||
|
|
32a5ff15bb | ||
|
|
552d2da17a | ||
|
|
b62c44c914 | ||
|
|
fe43558779 | ||
|
|
acfa56f6bc | ||
|
|
a58289a353 | ||
|
|
6de4736e50 | ||
|
|
ff43fec76a | ||
|
|
57ddf939d4 | ||
|
|
724c56d8aa | ||
|
|
af18453950 | ||
|
|
b6d98d4b72 | ||
|
|
4f6dc8fddb | ||
|
|
f57f668c92 | ||
|
|
a298ddb057 | ||
|
|
093ebb568c | ||
|
|
103de64bba | ||
|
|
3e8cd57986 | ||
|
|
1316443c59 | ||
|
|
776a680e85 | ||
|
|
cad5ac34b0 | ||
|
|
dde91c1c4d | ||
|
|
f3c189feb3 | ||
|
|
8f8f0757af | ||
|
|
ae12f351f8 | ||
|
|
e8c425850e | ||
|
|
7e6c741ed7 | ||
|
|
420b917a0a | ||
|
|
21c8150841 | ||
|
|
7f0cf8784b | ||
|
|
402ee7d006 | ||
|
|
dbaf38dc7d | ||
|
|
5f825fc8a8 | ||
|
|
7fcea3277d | ||
|
|
11edfecb75 | ||
|
|
a10af46153 | ||
|
|
91885e8a41 | ||
|
|
86bc2d427f | ||
|
|
a01e057632 | ||
|
|
79c9d9ebd1 | ||
|
|
099d01f96c | ||
|
|
369d92fa56 | ||
|
|
89cf4dbfcb | ||
|
|
7bccfeb8cc | ||
|
|
1cf032eeb1 | ||
|
|
303f086b14 | ||
|
|
996aa9d17a | ||
|
|
a0b80893db | ||
|
|
17aefc1aef | ||
|
|
6e28ac711f | ||
|
|
c126925dd9 | ||
|
|
7b276e0a08 | ||
|
|
6fba3a4380 | ||
|
|
fd535bae6b | ||
|
|
f5526977d3 | ||
|
|
bb578ae377 | ||
|
|
28a5277e2b | ||
|
|
53a8024e43 | ||
|
|
aee25dcaf9 | ||
|
|
11c0d79045 | ||
|
|
7391f7708a | ||
|
|
bdd756a090 | ||
|
|
c488b7132d | ||
|
|
93e75481c7 | ||
|
|
cfdc45dfcb | ||
|
|
6f941c277a | ||
|
|
61e8919cf1 | ||
|
|
0ad40cff1b | ||
|
|
51dda8e8a5 | ||
|
|
3602864523 | ||
|
|
758ef332f2 | ||
|
|
f732704b83 | ||
|
|
ce2c7a7d01 | ||
|
|
1e755d3cfc | ||
|
|
adbe725d79 | ||
|
|
4e6bfe1772 | ||
|
|
bb49254fad | ||
|
|
f1ddf028c2 | ||
|
|
4706b6b4e5 | ||
|
|
ff2a9dd37a | ||
|
|
2f0fec806a | ||
|
|
af3710887c | ||
|
|
eb67c847a7 | ||
|
|
50a2f48427 | ||
|
|
b3cc2efdb2 | ||
|
|
0021e68aab | ||
|
|
e196e35669 | ||
|
|
28819dede1 | ||
|
|
33729d634e | ||
|
|
f3504b2d25 | ||
|
|
7cbe7c762a | ||
|
|
ca564b928c | ||
|
|
fed14ad4ed | ||
|
|
ba299c4c00 | ||
|
|
e2b1b059ed | ||
|
|
f39744cf62 |
40
.ci/clang-format.sh
Executable file
40
.ci/clang-format.sh
Executable 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
|
||||
@@ -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
25
.github/linux-appimage-qt.sh
vendored
Executable 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
21
.github/linux-appimage-sdl.sh
vendored
Executable 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
9
.github/shadps4.desktop
vendored
Normal 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
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
18
.github/workflows/ci.yml
vendored
Normal 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
24
.github/workflows/format.yml
vendored
Normal 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
62
.github/workflows/linux-qt.yml
vendored
Normal 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
58
.github/workflows/linux.yml
vendored
Normal 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
|
||||
@@ -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
|
||||
12
.github/workflows/windows.yml
vendored
12
.github/workflows/windows.yml
vendored
@@ -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
3
.gitignore
vendored
@@ -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
45
.gitmodules
vendored
@@ -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
31
.reuse/dep5
Normal 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
|
||||
408
CMakeLists.txt
408
CMakeLists.txt
@@ -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
128
CONTRIBUTING.md
Normal 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
|
||||
```
|
||||
117
LICENSES/GPL-2.0-or-later.txt
Normal file
117
LICENSES/GPL-2.0-or-later.txt
Normal 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
9
LICENSES/MIT.txt
Normal 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.
|
||||
40
README.md
40
README.md
@@ -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
|
||||
|
||||
 Elf Loader
|
||||
|
||||
 Logging system
|
||||
|
||||
 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|[](https://github.com/georgemoralis/shadPS4/actions/workflows/windows.yml)
|
||||
|Windows SDL build|[](https://github.com/shadps4-emu/shadPS4/actions/workflows/windows.yml)
|
||||
|Linux SDL build|[](https://github.com/shadps4-emu/shadPS4/actions/workflows/linux.yml)
|
||||
|
||||
To discuss the development of this emulator, please join our Discord server: [](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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
<!--
|
||||
SPDX-FileCopyrightText: 2024 shadPS4 Emulator Project
|
||||
SPDX-License-Identifier: GPL-2.0-or-later
|
||||
-->
|
||||
|
||||
## Linux
|
||||
|
||||
|
||||
@@ -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
36
externals/CMakeLists.txt
vendored
Normal 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
1
externals/cryptopp
vendored
Submodule
Submodule externals/cryptopp added at 782057f5f1
1
externals/cryptopp-cmake
vendored
Submodule
1
externals/cryptopp-cmake
vendored
Submodule
Submodule externals/cryptopp-cmake added at a99c80c266
1
externals/cryptoppwin
vendored
Submodule
1
externals/cryptoppwin
vendored
Submodule
Submodule externals/cryptoppwin added at 0dd224c681
1
externals/discord-rpc
vendored
Submodule
1
externals/discord-rpc
vendored
Submodule
Submodule externals/discord-rpc added at 4ec218155d
1
externals/sdl3
vendored
Submodule
1
externals/sdl3
vendored
Submodule
Submodule externals/sdl3 added at 70b0d33106
1
externals/zlib-ng
vendored
Submodule
1
externals/zlib-ng
vendored
Submodule
Submodule externals/zlib-ng added at af8169a724
BIN
screenshots/screenshot.png
Normal file
BIN
screenshots/screenshot.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 810 KiB |
@@ -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
259
src/.clang-format
Normal 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
|
||||
...
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
};
|
||||
@@ -1,8 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "types.h"
|
||||
|
||||
namespace GPU {
|
||||
|
||||
void convertTileToLinear(void* dst, const void* src, u32 width, u32 height, bool neo);
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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, ¶m) : 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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -1,6 +0,0 @@
|
||||
#pragma once
|
||||
#include <types.h>
|
||||
|
||||
namespace HLE::Libs::LibKernel::CPUManagement {
|
||||
int PS4_SYSV_ABI sceKernelIsNeoMode();
|
||||
};
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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);
|
||||
|
||||
};
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
};
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
};
|
||||
@@ -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; }
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
};
|
||||
@@ -1,4 +0,0 @@
|
||||
#include "types.h"
|
||||
|
||||
u64 UnresolvedStub();
|
||||
u64 GetStub(const char *nid);
|
||||
@@ -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
|
||||
@@ -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);
|
||||
};
|
||||
@@ -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), ¶m, 1));
|
||||
|
||||
if (ptr == 0) {
|
||||
auto err = static_cast<u32>(GetLastError());
|
||||
LOG_ERROR_IF(true, "VirtualAlloc2() failed: 0x{:X}\n", err);
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
} // namespace VirtualMemory
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
@@ -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();
|
||||
|
||||
}
|
||||
@@ -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
|
||||
|
||||
};
|
||||
@@ -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); }
|
||||
@@ -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
|
||||
@@ -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; }
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
};
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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
Reference in New Issue
Block a user