Compare commits

..

4 Commits

Author SHA1 Message Date
CDAGaming
6d18e0dcef Clang Fix
Alphabetical Includes xD
2018-01-17 07:35:28 -06:00
CDAGaming
4a69ee067f Clang Format Fixes 2018-01-17 07:28:24 -06:00
CDAGaming
d776c66f39 Upgrade Inih & Apply XCode Update
*Blame Git for not doing this the first Time*
2018-01-17 06:42:32 -06:00
CDAGaming
793c054474 Update inih Submodule and Reorganize Submodules 2018-01-17 06:42:25 -06:00
231 changed files with 3369 additions and 5413 deletions

14
.gitmodules vendored
View File

@@ -1,6 +1,3 @@
[submodule "inih"]
path = externals/inih/inih
url = https://github.com/svn2github/inih
[submodule "boost"]
path = externals/boost
url = https://github.com/yuzu-emu/ext-boost.git
@@ -10,15 +7,18 @@
[submodule "dynarmic"]
path = externals/dynarmic
url = https://github.com/MerryMage/dynarmic.git
[submodule "xbyak"]
path = externals/xbyak
url = https://github.com/herumi/xbyak.git
[submodule "fmt"]
path = externals/fmt
url = https://github.com/fmtlib/fmt.git
[submodule "inih"]
path = externals/inih/inih
url = https://github.com/benhoyt/inih.git
[submodule "lz4"]
path = externals/lz4
url = http://github.com/lz4/lz4.git
[submodule "unicorn"]
path = externals/unicorn
url = https://github.com/yuzu-emu/unicorn
url = https://github.com/yuzu-emu/unicorn.git
[submodule "xbyak"]
path = externals/xbyak
url = https://github.com/herumi/xbyak.git

View File

@@ -6,12 +6,8 @@ matrix:
dist: trusty
addons:
apt:
sources:
- sourceline: 'deb http://apt.llvm.org/trusty/ llvm-toolchain-trusty-6.0 main'
key_url: 'https://apt.llvm.org/llvm-snapshot.gpg.key'
- sourceline: 'deb http://ppa.launchpad.net/ubuntu-toolchain-r/test/ubuntu trusty main'
packages:
- clang-format-6.0
- clang-format-3.9
script: "./.travis/clang-format/script.sh"
- os: linux
env: NAME="linux build"
@@ -36,14 +32,9 @@ matrix:
deploy:
provider: releases
api_key:
secure: ElsIAlbvVXBNKsP31nVPysh+mf0GQA4DiL/y5iJeQxKQYR6iRoNo+RfzOBmdswdo0bE/PGeBAlfzCkp15gjhWf6Je0N6dRpczmcmLq6SSQFn1Mpq00xMJB2AgQIlaHs6KFgoUA173EBKbPwgU/NubTFpJFm/Wa+NcSWAHQXKL9KT2M3qKpxNkPl3mKEVsbch4REP+T/46vsa+ikw0VE0kIs6V93LqUQZpI2F0Dhihx8Cxr5iedkE1QsNK+QSX9iItMHbfek9OH980gP7L3lkZltyAA1Pk0c37OAgz2PwczwNKwCT8jg9PMzdcKmWouvLyAkZFuA806ElzwHY3oEd91Zm6+Bk5n24yBKZ9027AZzw38NK2Z2m9Akb8+ar8PdsKU6N5pDutX9qSLayr0oMgJ0s7/xnGBGdL3gfkPCFc50xO/2DxlsOR+zAhPNM9Y76hhGy6A7/40+9uzrJvd4nAuDvIXRzi2Yl2L7mKBE4suMKbFLtk2LlgM0qY5JMVTQ8NliaEtqopfPur2KWFVJUpWDNLtNX8xGqhfwg7cLjIiGmnxSaJBTDuZI6dpEjkWkU0n1xYhGqEqit8DbehYzazozMJ+Vsr8hku7jGlUtlw+U6HG1e19O2y4aGeSwYPROcCNz+BLwmVM8oZE3Roy3qoaa2yiFf+sy6rUHznrhsfEM=
secure: IuTT8DjxzNgOtaEsyOpz1JaSmtDtHSsWZnJKmSBwXAzgP2ZU4Ja3/q0z5PwbC5Ql7kuFahuYTE5oi7lbJBuu2P3y1Wj2zvFozGUkA3JUvEXDNOPS9QTJ1EYd6O+wenZoj7d/Pn+ZeIgyEafnnZsGBb8lMQnV9MfIHgYlZQ5EyF3n4XikT2h1UbDBYx74ciXZIxFEulx68kDr9Q4/U+zIYQmYv2N+lgXSLDkFrCJ046gRcujPYGPqE6jVw0kKni80CTTpuDF5prU8yIBeiffjkJ3Qx1a17G07eZ4r83P4XUOlaHbRBmA/8ywZvLF2Gep3wGKfSFgMWbPxBJk5ZSYcOOAgMsEcg0+gBK9gLTwO4pbmc2GvqP21yRQBzgtbFoEtAHLu5lVPBkZU7kZuRMJtRdqvFIwOLhpnRS8IknFOD5vjtaFiNdGWaK9ePdsGvplijnXcPafkumakc4+eVEiXb6/KzdX1zXdur5tuUPFytm0Oy6IJcGIf8FHXGvUlmWsnPzwfusij9JgeQOP+uegc9PdBfL+h7L5rk+ilELt3cXD5K7wgov/4hkl5istNJ2bm0IioIstWss8QQQTkyscGoeh/oXmUpOL4FdsTvsWhDR3QKeq8nSzgDkqLe0iSbplQGnC7o7ytNbldmxJvf3nylwglA8w3HlqLHtZLkUOcuQ0=
file_glob: true
file: "artifacts/*"
skip_cleanup: true
on:
tags: true
notifications:
webhooks:
urls:
- https://api.yuzu-emu.org/code/travis/notify

View File

@@ -7,7 +7,7 @@ if grep -nr '\s$' src *.yml *.txt *.md Doxyfile .gitignore .gitmodules .travis*
fi
# Default clang-format points to default 3.5 version one
CLANG_FORMAT=clang-format-6.0
CLANG_FORMAT=clang-format-3.9
$CLANG_FORMAT --version
if [ "$TRAVIS_EVENT_TYPE" = "pull_request" ]; then

View File

@@ -8,7 +8,7 @@ export UNICORNDIR=$(pwd)/externals/unicorn
mkdir build && cd build
cmake --version
cmake .. -DYUZU_BUILD_UNICORN=ON -DCMAKE_BUILD_TYPE=Release
cmake .. -DYUZU_BUILD_UNICORN=ON -DCMAKE_OSX_ARCHITECTURES="x86_64;x86_64h" -DCMAKE_BUILD_TYPE=Release
make -j4
ctest -VV -C Release

View File

@@ -3,19 +3,14 @@ cmake_minimum_required(VERSION 3.6)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMakeModules")
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/externals/cmake-modules")
include(DownloadExternals)
include(CMakeDependentOption)
project(yuzu)
# Set bundled sdl2/qt as dependent options.
# OFF by default, but if ENABLE_SDL2 and MSVC are true then ON
option(ENABLE_SDL2 "Enable the SDL2 frontend" ON)
CMAKE_DEPENDENT_OPTION(YUZU_USE_BUNDLED_SDL2 "Download bundled SDL2 binaries" ON "ENABLE_SDL2;MSVC" OFF)
option(YUZU_USE_BUNDLED_SDL2 "Download bundled SDL2 binaries" OFF)
option(ENABLE_QT "Enable the Qt frontend" ON)
CMAKE_DEPENDENT_OPTION(YUZU_USE_BUNDLED_QT "Download bundled Qt binaries" ON "ENABLE_QT;MSVC" OFF)
option(YUZU_USE_BUNDLED_UNICORN "Build/Download bundled Unicorn" ON)
option(YUZU_USE_BUNDLED_QT "Download bundled Qt binaries" OFF)
if(NOT EXISTS ${CMAKE_SOURCE_DIR}/.git/hooks/pre-commit)
message(STATUS "Copying pre-commit hook")
@@ -59,18 +54,15 @@ function(detect_architecture symbol arch)
endif()
endfunction()
if (NOT ENABLE_GENERIC)
if (MSVC)
detect_architecture("_M_AMD64" x86_64)
detect_architecture("_M_IX86" x86)
detect_architecture("_M_ARM" ARM)
else()
detect_architecture("__x86_64__" x86_64)
detect_architecture("__i386__" x86)
detect_architecture("__arm__" ARM)
endif()
if (MSVC)
detect_architecture("_M_AMD64" x86_64)
detect_architecture("_M_IX86" x86)
detect_architecture("_M_ARM" ARM)
else()
detect_architecture("__x86_64__" x86_64)
detect_architecture("__i386__" x86)
detect_architecture("__arm__" ARM)
endif()
if (NOT DEFINED ARCHITECTURE)
set(ARCHITECTURE "GENERIC")
set(ARCHITECTURE_GENERIC 1)
@@ -211,7 +203,8 @@ else()
endif()
# If unicorn isn't found, msvc -> download bundled unicorn; everyone else -> build external
if (YUZU_USE_BUNDLED_UNICORN)
find_package(Unicorn QUIET)
if (NOT UNICORN_FOUND)
if (MSVC)
message(STATUS "unicorn not found, falling back to bundled")
# Detect toolchain and platform
@@ -250,7 +243,7 @@ if (YUZU_USE_BUNDLED_UNICORN)
find_package(PythonInterp 2.7 REQUIRED)
add_custom_command(OUTPUT ${LIBUNICORN_LIBRARY}
COMMAND ${CMAKE_COMMAND} -E env UNICORN_ARCHS="aarch64" PYTHON="${PYTHON_EXECUTABLE}" /bin/sh make.sh macos-universal-no
COMMAND ${CMAKE_COMMAND} -E env UNICORN_ARCHS="aarch64" PYTHON="${PYTHON_EXECUTABLE}" /bin/sh make.sh
WORKING_DIRECTORY ${UNICORN_PREFIX}
)
# ALL makes this custom target build every time
@@ -260,8 +253,6 @@ if (YUZU_USE_BUNDLED_UNICORN)
)
unset(UNICORN_LIB_NAME)
endif()
else()
find_package(Unicorn REQUIRED)
endif()
if (UNICORN_FOUND)
@@ -325,53 +316,6 @@ if (UNIX OR MINGW)
endif()
endif()
# 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 "-6.0")
find_program(CLANG_FORMAT
NAMES clang-format${CLANG_FORMAT_POSTFIX}
clang-format
PATHS ${CMAKE_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 "${CMAKE_BINARY_DIR}/externals/clang-format${CLANG_FORMAT_POSTFIX}.exe")
file(DOWNLOAD
https://github.com/yuzu-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 ${CMAKE_SOURCE_DIR}/src)
set(CCOMMENT "Running clang format against all the .h and .cpp files in src/")
if (WIN32)
add_custom_target(clang-format
COMMAND powershell.exe -Command "${CLANG_FORMAT} -i @(Get-ChildItem -Recurse ${SRCS}/* -Include \'*.h\', \'*.cpp\')"
COMMENT ${CCOMMENT})
elseif(MINGW)
add_custom_target(clang-format
COMMAND find `cygpath -u ${SRCS}` -iname *.h -o -iname *.cpp | xargs `cygpath -u ${CLANG_FORMAT}` -i
COMMENT ${CCOMMENT})
else()
add_custom_target(clang-format
COMMAND find ${SRCS} -iname *.h -o -iname *.cpp | xargs ${CLANG_FORMAT} -i
COMMENT ${CCOMMENT})
endif()
unset(SRCS)
unset(CCOMMENT)
endif()
# Include source code
# ===================
@@ -379,14 +323,12 @@ 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)
function(create_directory_groups)
# 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)
foreach(file_name ${ARGV})
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}")
@@ -423,7 +365,7 @@ if(ENABLE_QT AND UNIX AND NOT APPLE)
install(FILES "${CMAKE_SOURCE_DIR}/dist/yuzu.desktop"
DESTINATION "${CMAKE_INSTALL_PREFIX}/share/applications")
install(FILES "${CMAKE_SOURCE_DIR}/dist/yuzu.svg"
DESTINATION "${CMAKE_INSTALL_PREFIX}/share/icons/hicolor/scalable/apps")
DESTINATION "${CMAKE_INSTALL_PREFIX}/share/pixmaps")
install(FILES "${CMAKE_SOURCE_DIR}/dist/yuzu.xml"
DESTINATION "${CMAKE_INSTALL_PREFIX}/share/mime/packages")
endif()

View File

@@ -5,16 +5,7 @@
If you believe you have a valid issue report, please post text or a screenshot from the log (the console window that opens alongside yuzu) and build version (hex string visible in the titlebar and zip filename), as well as your hardware and software information if applicable.
# Contributing
yuzu is a brand new project, so we have a great opportunity to keep things clean and well organized early on. As such, coding style is very important when making commits. We run clang-format on our CI to check the code. Please use it to format your code when contributing. However, it doesn't cover all the rules below. Some of them aren't very strict rules since we want to be flexible and we understand that under certain circumstances some of them can be counterproductive. Just try to follow as many of them as possible.
# Using clang format (version 6.0)
When generating the native build script for your toolset, cmake will try to find the correct version of clang format (or will download it on windows). Before running cmake, please install clang format version 6.0 for your platform as follows:
* Windows: do nothing; cmake will download a pre built binary for MSVC and MINGW. MSVC users can additionally install a clang format Visual Studio extension to add features like format on save.
* OSX: run `brew install clang-format`.
* Linux: use your package manager to get an appropriate binary.
If clang format is found, then cmake will add a custom build target that can be run at any time to run clang format against *all* source files and update the formatting in them. This should be used before making a pull request so that the reviewers can spend more time reviewing the code instead of having to worry about minor style violations. On MSVC, you can run clang format by building the clang-format project in the solution. On OSX, you can either use the Makefile target `make clang-format` or by building the clang-format target in XCode. For Makefile builds, you can use the clang-format target with `make clang-format`
yuzu is a brand new project, so we have a great opportunity to keep things clean and well organized early on. As such, coding style is very important when making commits. We run clang-format on our CI to check the code. Please use it to format your code when contributing. However, it doesn't cover all the rules below. Some of them aren't very strict rules since we want to be flexible and we understand that under certain circumstances some of them can be counterproductive. Just try to follow as many of them as possible:
### General Rules
* A lot of code was taken from other projects (e.g. Citra, Dolphin, PPSSPP, Gekko). In general, when editing other people's code, follow the style of the module you're in (or better yet, fix the style if it drastically differs from our guide).

View File

@@ -13,8 +13,8 @@ environment:
# Tell msys2 to inherit the current directory when starting the shell
CHERE_INVOKING: 1
matrix:
- BUILD_TYPE: msvc
- BUILD_TYPE: mingw
- BUILD_TYPE: msvc
platform:
- x64
@@ -80,19 +80,12 @@ after_build:
$env:BUILD_SYMBOLS = $MSVC_BUILD_PDB
$env:BUILD_UPDATE = $MSVC_SEVENZIP
$BUILD_DIR = ".\msvc_build\bin\Release"
# Make a debug symbol upload
mkdir pdb
Get-ChildItem "$BUILD_DIR\" -Recurse -Filter "*.pdb" | Copy-Item -destination .\pdb
Get-ChildItem ".\msvc_build\bin\" -Recurse -Filter "*.pdb" | Copy-Item -destination .\pdb
7z a -tzip $MSVC_BUILD_PDB .\pdb\*.pdb
rm "$BUILD_DIR\*.pdb"
mkdir $RELEASE_DIST
# get rid of extra exes by copying everything over, then deleting all the exes, then copying just the exes we want
Copy-Item "$BUILD_DIR\*" -Destination $RELEASE_DIST -Recurse
rm "$RELEASE_DIST\*.exe"
Get-ChildItem "$BUILD_DIR" -Recurse -Filter "yuzu*.exe" | Copy-Item -destination $RELEASE_DIST
Get-ChildItem ".\msvc_build\bin\" -Recurse -Filter "yuzu*.exe" | Copy-Item -destination $RELEASE_DIST
Copy-Item .\license.txt -Destination $RELEASE_DIST
Copy-Item .\README.md -Destination $RELEASE_DIST
7z a -tzip $MSVC_BUILD_ZIP $RELEASE_DIST\*
@@ -170,7 +163,7 @@ deploy:
provider: GitHub
release: $(appveyor_repo_tag_name)
auth_token:
secure: QqePPnXbkzmXct5c8hZ2X5AbsthbI6cS1Sr+VBzcD8oUOIjfWJJKXVAQGUbQAbb0
secure: "argb6oi2TYLB4wDy+HoCC8PuGAmsnocSk12CQ5614XAPO+NVPndlkLv1utnDFfg2"
artifact: update,build
draft: false
prerelease: false

View File

@@ -1,9 +1,11 @@
add_library(getopt
getopt.c
getopt.h
)
create_target_directory_groups(getopt)
set(SRCS
getopt.c
)
set(HEADERS
getopt.h
)
create_directory_groups(${SRCS} ${HEADERS})
add_library(getopt ${SRCS} ${HEADERS})
target_compile_definitions(getopt PUBLIC STATIC_GETOPT)
target_include_directories(getopt INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})

View File

@@ -1,10 +1,13 @@
add_library(glad STATIC
src/glad.c
include/KHR/khrplatform.h
include/glad/glad.h
)
set(SRCS
src/glad.c
)
set(HEADERS
include/KHR/khrplatform.h
include/glad/glad.h
)
create_target_directory_groups(glad)
create_directory_groups(${SRCS} ${HEADERS})
add_library(glad STATIC ${SRCS} ${HEADERS})
target_include_directories(glad PUBLIC "include/")
if ("${CMAKE_SYSTEM_NAME}" MATCHES "Linux")

View File

@@ -1,9 +1,12 @@
add_library(inih
inih/ini.c
inih/ini.h
inih/cpp/INIReader.cpp
inih/cpp/INIReader.h
)
set(SRCS
inih/ini.c
inih/cpp/INIReader.cpp
)
set(HEADERS
inih/ini.h
inih/cpp/INIReader.h
)
create_target_directory_groups(inih)
create_directory_groups(${SRCS} ${HEADERS})
add_library(inih ${SRCS} ${HEADERS})
target_include_directories(inih INTERFACE .)

View File

@@ -17,79 +17,85 @@ if ($ENV{CI})
string(SUBSTRING ${WORD} 1 -1 REMAINDER)
string(TOUPPER ${FIRST_LETTER} FIRST_LETTER)
# this leaves a trailing space on the last word, but we actually want that
# because of how it's styled in the title bar.
# because of how its styled in the title bar.
set(REPO_NAME "${REPO_NAME}${FIRST_LETTER}${REMAINDER} ")
endforeach()
endif()
endif()
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/scm_rev.cpp.in" "${CMAKE_CURRENT_SOURCE_DIR}/scm_rev.cpp" @ONLY)
add_library(common STATIC
alignment.h
assert.h
bit_field.h
bit_set.h
break_points.cpp
break_points.h
chunk_file.h
code_block.h
color.h
common_funcs.h
common_paths.h
common_types.h
file_util.cpp
file_util.h
hash.cpp
hash.h
linear_disk_cache.h
logging/backend.cpp
logging/backend.h
logging/filter.cpp
logging/filter.h
logging/log.h
logging/text_formatter.cpp
logging/text_formatter.h
math_util.h
memory_util.cpp
memory_util.h
microprofile.cpp
microprofile.h
microprofileui.h
misc.cpp
param_package.cpp
param_package.h
platform.h
quaternion.h
scm_rev.cpp
scm_rev.h
scope_exit.h
string_util.cpp
string_util.h
swap.h
synchronized_wrapper.h
telemetry.cpp
telemetry.h
thread.cpp
thread.h
thread_queue_list.h
threadsafe_queue.h
timer.cpp
timer.h
vector_math.h
)
set(SRCS
break_points.cpp
file_util.cpp
hash.cpp
logging/filter.cpp
logging/text_formatter.cpp
logging/backend.cpp
memory_util.cpp
microprofile.cpp
misc.cpp
param_package.cpp
scm_rev.cpp
string_util.cpp
telemetry.cpp
thread.cpp
timer.cpp
)
set(HEADERS
alignment.h
assert.h
bit_field.h
bit_set.h
break_points.h
chunk_file.h
code_block.h
color.h
common_funcs.h
common_paths.h
common_types.h
file_util.h
hash.h
linear_disk_cache.h
logging/text_formatter.h
logging/filter.h
logging/log.h
logging/backend.h
math_util.h
memory_util.h
microprofile.h
microprofileui.h
param_package.h
platform.h
quaternion.h
scm_rev.h
scope_exit.h
string_util.h
swap.h
synchronized_wrapper.h
telemetry.h
thread.h
thread_queue_list.h
threadsafe_queue.h
timer.h
vector_math.h
)
if(ARCHITECTURE_x86_64)
target_sources(common
PRIVATE
set(SRCS ${SRCS}
x64/cpu_detect.cpp
)
set(HEADERS ${HEADERS}
x64/cpu_detect.h
x64/xbyak_abi.h
x64/xbyak_util.h
)
)
endif()
create_target_directory_groups(common)
create_directory_groups(${SRCS} ${HEADERS})
add_library(common STATIC ${SRCS} ${HEADERS})
target_link_libraries(common PUBLIC Boost::boost microprofile)
if (ARCHITECTURE_x86_64)
target_link_libraries(common PRIVATE xbyak)

View File

@@ -236,7 +236,7 @@ public:
IntTy m_val;
};
} // namespace Common
} // Common
typedef Common::BitSet<u8> BitSet8;
typedef Common::BitSet<u16> BitSet16;

View File

@@ -607,9 +607,8 @@ public:
u32 cookie = arbitraryNumber;
Do(cookie);
if (mode == PointerWrap::MODE_READ && cookie != arbitraryNumber) {
LOG_ERROR(Common,
"After \"%s\", found %d (0x%X) instead of save marker %d (0x%X). "
"Aborting savestate load...",
LOG_ERROR(Common, "After \"%s\", found %d (0x%X) instead of save marker %d (0x%X). "
"Aborting savestate load...",
prevName, cookie, cookie, arbitraryNumber, arbitraryNumber);
SetError(ERROR_FAILURE);
}

View File

@@ -256,4 +256,4 @@ inline void EncodeX24S8(u8 stencil, u8* bytes) {
bytes[3] = stencil;
}
} // namespace Color
} // namespace

View File

@@ -873,19 +873,20 @@ bool IOFile::Flush() {
}
bool IOFile::Resize(u64 size) {
if (!IsOpen() || 0 !=
if (!IsOpen() ||
0 !=
#ifdef _WIN32
// ector: _chsize sucks, not 64-bit safe
// F|RES: changed to _chsize_s. i think it is 64-bit safe
_chsize_s(_fileno(m_file), size)
// ector: _chsize sucks, not 64-bit safe
// F|RES: changed to _chsize_s. i think it is 64-bit safe
_chsize_s(_fileno(m_file), size)
#else
// TODO: handle 64bit and growing
ftruncate(fileno(m_file), size)
// TODO: handle 64bit and growing
ftruncate(fileno(m_file), size)
#endif
)
)
m_good = false;
return m_good;
}
} // namespace FileUtil
} // namespace

View File

@@ -253,7 +253,7 @@ private:
bool m_good = true;
};
} // namespace FileUtil
} // namespace
// To deal with Windows being dumb at unicode:
template <typename T>

View File

@@ -32,26 +32,17 @@ namespace Log {
CLS(Kernel) \
SUB(Kernel, SVC) \
CLS(Service) \
SUB(Service, ACC) \
SUB(Service, Audio) \
SUB(Service, AM) \
SUB(Service, APM) \
SUB(Service, FS) \
SUB(Service, HID) \
SUB(Service, LM) \
SUB(Service, NIFM) \
SUB(Service, NVDRV) \
SUB(Service, PCTL) \
SUB(Service, SET) \
SUB(Service, SM) \
SUB(Service, Time) \
SUB(Service, VI) \
SUB(Service, FS) \
SUB(Service, GSP) \
SUB(Service, CFG) \
SUB(Service, DSP) \
SUB(Service, HID) \
CLS(HW) \
SUB(HW, Memory) \
SUB(HW, LCD) \
SUB(HW, GPU) \
SUB(HW, AES) \
CLS(IPC) \
CLS(Frontend) \
CLS(Render) \
SUB(Render, Software) \
@@ -100,8 +91,8 @@ const char* GetLevelName(Level log_level) {
Entry CreateEntry(Class log_class, Level log_level, const char* filename, unsigned int line_nr,
const char* function, const char* format, va_list args) {
using std::chrono::duration_cast;
using std::chrono::steady_clock;
using std::chrono::duration_cast;
static steady_clock::time_point time_origin = steady_clock::now();
@@ -140,4 +131,4 @@ void LogMessage(Class log_class, Level log_level, const char* filename, unsigned
PrintColoredMessage(entry);
}
} // namespace Log
}

View File

@@ -47,4 +47,4 @@ Entry CreateEntry(Class log_class, Level log_level, const char* filename, unsign
const char* function, const char* format, va_list args);
void SetFilter(Filter* filter);
} // namespace Log
}

View File

@@ -94,4 +94,4 @@ bool Filter::ParseFilterRule(const std::string::const_iterator begin,
bool Filter::CheckMessage(Class log_class, Level level) const {
return static_cast<u8>(level) >= static_cast<u8>(class_levels[static_cast<size_t>(log_class)]);
}
} // namespace Log
}

View File

@@ -50,4 +50,4 @@ public:
private:
std::array<Level, (size_t)Class::Count> class_levels;
};
} // namespace Log
}

View File

@@ -49,26 +49,17 @@ enum class Class : ClassType {
Kernel_SVC, ///< Kernel system calls
Service, ///< HLE implementation of system services. Each major service
/// should have its own subclass.
Service_ACC, ///< The ACC (Accounts) service
Service_AM, ///< The AM (Applet manager) service
Service_APM, ///< The APM (Performance) service
Service_Audio, ///< The Audio (Audio control) service
Service_FS, ///< The FS (Filesystem) service
Service_SM, ///< The SRV (Service Directory) implementation
Service_FS, ///< The FS (Filesystem) service implementation
Service_GSP, ///< The GSP (GPU control) service
Service_CFG, ///< The CFG (Configuration) service
Service_DSP, ///< The DSP (DSP control) service
Service_HID, ///< The HID (Human interface device) service
Service_LM, ///< The LM (Logger) service
Service_NIFM, ///< The NIFM (Network interface) service
Service_NVDRV, ///< The NVDRV (Nvidia driver) service
Service_PCTL, ///< The PCTL (Parental control) service
Service_SET, ///< The SET (Settings) service
Service_SM, ///< The SM (Service manager) service
Service_Time, ///< The time service
Service_VI, ///< The VI (Video interface) service
HW, ///< Low-level hardware emulation
HW_Memory, ///< Memory-map and address translation
HW_LCD, ///< LCD register emulation
HW_GPU, ///< GPU control emulation
HW_AES, ///< AES engine emulation
IPC, ///< IPC interface
Frontend, ///< Emulator UI
Render, ///< Emulator video output and hardware acceleration
Render_Software, ///< Software renderer backend

View File

@@ -129,4 +129,4 @@ void PrintColoredMessage(const Entry& entry) {
#undef ESC
#endif
}
} // namespace Log
}

View File

@@ -28,4 +28,4 @@ void FormatLogMessage(const Entry& entry, char* out_text, size_t text_len);
void PrintMessage(const Entry& entry);
/// Prints the same message as `PrintMessage`, but colored acoording to the severity level.
void PrintColoredMessage(const Entry& entry);
} // namespace Log
}

View File

@@ -40,12 +40,11 @@ void* AllocateExecutableMemory(size_t size, bool low) {
if (low && (!map_hint))
map_hint = (char*)round_page(512 * 1024 * 1024); /* 0.5 GB rounded up to the next page */
#endif
void* ptr = mmap(map_hint, size, PROT_READ | PROT_WRITE | PROT_EXEC,
MAP_ANON | MAP_PRIVATE
void* ptr = mmap(map_hint, size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_ANON | MAP_PRIVATE
#if defined(ARCHITECTURE_X64) && defined(MAP_32BIT)
| (low ? MAP_32BIT : 0)
| (low ? MAP_32BIT : 0)
#endif
,
,
-1, 0);
#endif /* defined(_WIN32) */

View File

@@ -46,4 +46,4 @@ inline Quaternion<float> MakeQuaternion(const Math::Vec3<float>& axis, float ang
return {axis * std::sin(angle / 2), std::cos(angle / 2)};
}
} // namespace Math
} // namspace Math

View File

@@ -12,4 +12,4 @@ extern const char g_scm_desc[];
extern const char g_build_name[];
extern const char g_build_date[];
} // namespace Common
} // namespace

View File

@@ -22,7 +22,7 @@ template <typename Func>
ScopeExitHelper<Func> ScopeExit(Func&& func) {
return ScopeExitHelper<Func>(std::move(func));
}
} // namespace detail
}
/**
* This macro allows you to conveniently specify a block of code that will run on scope exit. Handy

View File

@@ -202,7 +202,7 @@ bool SplitPath(const std::string& full_path, std::string* _pPath, std::string* _
#ifdef _WIN32
":"
#endif
);
);
if (std::string::npos == dir_end)
dir_end = 0;
else
@@ -462,4 +462,4 @@ std::string StringFromFixedZeroTerminatedBuffer(const char* buffer, size_t max_l
return std::string(buffer, len);
}
} // namespace Common
}

View File

@@ -134,4 +134,4 @@ bool ComparePartialString(InIt begin, InIt end, const char* other) {
* NUL-terminated then the string ends at max_len characters.
*/
std::string StringFromFixedZeroTerminatedBuffer(const char* buffer, size_t max_len);
} // namespace Common
}

View File

@@ -53,10 +53,10 @@ template <typename T>
class Field : public FieldInterface {
public:
Field(FieldType type, std::string name, const T& value)
: name(std::move(name)), type(type), value(value) {}
: type(type), name(std::move(name)), value(value) {}
Field(FieldType type, std::string name, T&& value)
: name(std::move(name)), type(type), value(std::move(value)) {}
: type(type), name(std::move(name)), value(std::move(value)) {}
Field(const Field& other) : Field(other.type, other.name, other.value) {}

View File

@@ -158,4 +158,4 @@ private:
std::array<Queue, NUM_QUEUES> queues;
};
} // namespace Common
} // namespace

View File

@@ -60,41 +60,20 @@ const Xbyak::Reg ABI_PARAM4 = Xbyak::util::r9;
const BitSet32 ABI_ALL_CALLER_SAVED = BuildRegSet({
// GPRs
Xbyak::util::rcx,
Xbyak::util::rdx,
Xbyak::util::r8,
Xbyak::util::r9,
Xbyak::util::r10,
Xbyak::util::rcx, Xbyak::util::rdx, Xbyak::util::r8, Xbyak::util::r9, Xbyak::util::r10,
Xbyak::util::r11,
// XMMs
Xbyak::util::xmm0,
Xbyak::util::xmm1,
Xbyak::util::xmm2,
Xbyak::util::xmm3,
Xbyak::util::xmm4,
Xbyak::util::xmm0, Xbyak::util::xmm1, Xbyak::util::xmm2, Xbyak::util::xmm3, Xbyak::util::xmm4,
Xbyak::util::xmm5,
});
const BitSet32 ABI_ALL_CALLEE_SAVED = BuildRegSet({
// GPRs
Xbyak::util::rbx,
Xbyak::util::rsi,
Xbyak::util::rdi,
Xbyak::util::rbp,
Xbyak::util::r12,
Xbyak::util::r13,
Xbyak::util::r14,
Xbyak::util::r15,
Xbyak::util::rbx, Xbyak::util::rsi, Xbyak::util::rdi, Xbyak::util::rbp, Xbyak::util::r12,
Xbyak::util::r13, Xbyak::util::r14, Xbyak::util::r15,
// XMMs
Xbyak::util::xmm6,
Xbyak::util::xmm7,
Xbyak::util::xmm8,
Xbyak::util::xmm9,
Xbyak::util::xmm10,
Xbyak::util::xmm11,
Xbyak::util::xmm12,
Xbyak::util::xmm13,
Xbyak::util::xmm14,
Xbyak::util::xmm6, Xbyak::util::xmm7, Xbyak::util::xmm8, Xbyak::util::xmm9, Xbyak::util::xmm10,
Xbyak::util::xmm11, Xbyak::util::xmm12, Xbyak::util::xmm13, Xbyak::util::xmm14,
Xbyak::util::xmm15,
});
@@ -111,40 +90,18 @@ const Xbyak::Reg ABI_PARAM4 = Xbyak::util::rcx;
const BitSet32 ABI_ALL_CALLER_SAVED = BuildRegSet({
// GPRs
Xbyak::util::rcx,
Xbyak::util::rdx,
Xbyak::util::rdi,
Xbyak::util::rsi,
Xbyak::util::r8,
Xbyak::util::r9,
Xbyak::util::r10,
Xbyak::util::r11,
Xbyak::util::rcx, Xbyak::util::rdx, Xbyak::util::rdi, Xbyak::util::rsi, Xbyak::util::r8,
Xbyak::util::r9, Xbyak::util::r10, Xbyak::util::r11,
// XMMs
Xbyak::util::xmm0,
Xbyak::util::xmm1,
Xbyak::util::xmm2,
Xbyak::util::xmm3,
Xbyak::util::xmm4,
Xbyak::util::xmm5,
Xbyak::util::xmm6,
Xbyak::util::xmm7,
Xbyak::util::xmm8,
Xbyak::util::xmm9,
Xbyak::util::xmm10,
Xbyak::util::xmm11,
Xbyak::util::xmm12,
Xbyak::util::xmm13,
Xbyak::util::xmm14,
Xbyak::util::xmm15,
Xbyak::util::xmm0, Xbyak::util::xmm1, Xbyak::util::xmm2, Xbyak::util::xmm3, Xbyak::util::xmm4,
Xbyak::util::xmm5, Xbyak::util::xmm6, Xbyak::util::xmm7, Xbyak::util::xmm8, Xbyak::util::xmm9,
Xbyak::util::xmm10, Xbyak::util::xmm11, Xbyak::util::xmm12, Xbyak::util::xmm13,
Xbyak::util::xmm14, Xbyak::util::xmm15,
});
const BitSet32 ABI_ALL_CALLEE_SAVED = BuildRegSet({
// GPRs
Xbyak::util::rbx,
Xbyak::util::rbp,
Xbyak::util::r12,
Xbyak::util::r13,
Xbyak::util::r14,
Xbyak::util::rbx, Xbyak::util::rbp, Xbyak::util::r12, Xbyak::util::r13, Xbyak::util::r14,
Xbyak::util::r15,
});

View File

@@ -1,220 +1,175 @@
add_library(core STATIC
arm/arm_interface.h
arm/unicorn/arm_unicorn.cpp
arm/unicorn/arm_unicorn.h
core.cpp
core.h
core_timing.cpp
core_timing.h
file_sys/directory.h
file_sys/errors.h
file_sys/filesystem.cpp
file_sys/filesystem.h
file_sys/path_parser.cpp
file_sys/path_parser.h
file_sys/romfs_factory.cpp
file_sys/romfs_factory.h
file_sys/romfs_filesystem.cpp
file_sys/romfs_filesystem.h
file_sys/storage.h
frontend/emu_window.cpp
frontend/emu_window.h
frontend/framebuffer_layout.cpp
frontend/framebuffer_layout.h
frontend/input.h
gdbstub/gdbstub.cpp
gdbstub/gdbstub.h
hle/config_mem.cpp
hle/config_mem.h
hle/ipc.h
hle/ipc_helpers.h
hle/kernel/address_arbiter.cpp
hle/kernel/address_arbiter.h
hle/kernel/client_port.cpp
hle/kernel/client_port.h
hle/kernel/client_session.cpp
hle/kernel/client_session.h
hle/kernel/condition_variable.cpp
hle/kernel/condition_variable.h
hle/kernel/errors.h
hle/kernel/event.cpp
hle/kernel/event.h
hle/kernel/handle_table.cpp
hle/kernel/handle_table.h
hle/kernel/hle_ipc.cpp
hle/kernel/hle_ipc.h
hle/kernel/kernel.cpp
hle/kernel/kernel.h
hle/kernel/memory.cpp
hle/kernel/memory.h
hle/kernel/mutex.cpp
hle/kernel/mutex.h
hle/kernel/object_address_table.cpp
hle/kernel/object_address_table.h
hle/kernel/process.cpp
hle/kernel/process.h
hle/kernel/resource_limit.cpp
hle/kernel/resource_limit.h
hle/kernel/server_port.cpp
hle/kernel/server_port.h
hle/kernel/server_session.cpp
hle/kernel/server_session.h
hle/kernel/session.h
hle/kernel/shared_memory.cpp
hle/kernel/shared_memory.h
hle/kernel/svc.cpp
hle/kernel/svc.h
hle/kernel/svc_wrap.h
hle/kernel/thread.cpp
hle/kernel/thread.h
hle/kernel/timer.cpp
hle/kernel/timer.h
hle/kernel/vm_manager.cpp
hle/kernel/vm_manager.h
hle/kernel/wait_object.cpp
hle/kernel/wait_object.h
hle/lock.cpp
hle/lock.h
hle/result.h
hle/romfs.cpp
hle/romfs.h
hle/service/acc/acc.cpp
hle/service/acc/acc.h
hle/service/acc/acc_u0.cpp
hle/service/acc/acc_u0.h
hle/service/am/am.cpp
hle/service/am/am.h
hle/service/am/applet_ae.cpp
hle/service/am/applet_ae.h
hle/service/am/applet_oe.cpp
hle/service/am/applet_oe.h
hle/service/aoc/aoc_u.cpp
hle/service/aoc/aoc_u.h
hle/service/apm/apm.cpp
hle/service/apm/apm.h
hle/service/audio/audio.cpp
hle/service/audio/audio.h
hle/service/audio/audin_u.cpp
hle/service/audio/audin_u.h
hle/service/audio/audout_u.cpp
hle/service/audio/audout_u.h
hle/service/audio/audrec_u.cpp
hle/service/audio/audrec_u.h
hle/service/audio/audren_u.cpp
hle/service/audio/audren_u.h
hle/service/audio/audren_u.cpp
hle/service/audio/audren_u.h
hle/service/audio/codecctl.cpp
hle/service/audio/codecctl.h
hle/service/filesystem/filesystem.cpp
hle/service/filesystem/filesystem.h
hle/service/filesystem/fsp_srv.cpp
hle/service/filesystem/fsp_srv.h
hle/service/hid/hid.cpp
hle/service/hid/hid.h
hle/service/lm/lm.cpp
hle/service/lm/lm.h
hle/service/nifm/nifm.cpp
hle/service/nifm/nifm.h
hle/service/nifm/nifm_a.cpp
hle/service/nifm/nifm_a.h
hle/service/nifm/nifm_s.cpp
hle/service/nifm/nifm_s.h
hle/service/nifm/nifm_u.cpp
hle/service/nifm/nifm_u.h
hle/service/nvdrv/devices/nvdevice.h
hle/service/nvdrv/devices/nvdisp_disp0.cpp
hle/service/nvdrv/devices/nvdisp_disp0.h
hle/service/nvdrv/devices/nvhost_as_gpu.cpp
hle/service/nvdrv/devices/nvhost_as_gpu.h
hle/service/nvdrv/devices/nvhost_ctrl.cpp
hle/service/nvdrv/devices/nvhost_ctrl.h
hle/service/nvdrv/devices/nvmap.cpp
hle/service/nvdrv/devices/nvmap.h
hle/service/nvdrv/interface.cpp
hle/service/nvdrv/interface.h
hle/service/nvdrv/nvdrv.cpp
hle/service/nvdrv/nvdrv.h
hle/service/nvdrv/nvmemp.cpp
hle/service/nvdrv/nvmemp.h
hle/service/nvflinger/buffer_queue.cpp
hle/service/nvflinger/buffer_queue.h
hle/service/nvflinger/nvflinger.cpp
hle/service/nvflinger/nvflinger.h
hle/service/pctl/pctl.cpp
hle/service/pctl/pctl.h
hle/service/pctl/pctl_a.cpp
hle/service/pctl/pctl_a.h
hle/service/service.cpp
hle/service/service.h
hle/service/set/set.cpp
hle/service/set/set.h
hle/service/sm/controller.cpp
hle/service/sm/controller.h
hle/service/sm/sm.cpp
hle/service/sm/sm.h
hle/service/sockets/bsd_u.cpp
hle/service/sockets/bsd_u.h
hle/service/sockets/sfdnsres.cpp
hle/service/sockets/sfdnsres.h
hle/service/sockets/sockets.cpp
hle/service/sockets/sockets.h
hle/service/time/time.cpp
hle/service/time/time.h
hle/service/time/time_s.cpp
hle/service/time/time_s.h
hle/service/time/time_u.cpp
hle/service/time/time_u.h
hle/service/vi/vi.cpp
hle/service/vi/vi.h
hle/service/vi/vi_m.cpp
hle/service/vi/vi_m.h
hle/service/vi/vi_s.cpp
hle/service/vi/vi_s.h
hle/service/vi/vi_u.cpp
hle/service/vi/vi_u.h
hle/shared_page.cpp
hle/shared_page.h
hw/hw.cpp
hw/hw.h
hw/lcd.cpp
hw/lcd.h
loader/deconstructed_rom_directory.cpp
loader/deconstructed_rom_directory.h
loader/elf.cpp
loader/elf.h
loader/linker.cpp
loader/linker.h
loader/loader.cpp
loader/loader.h
loader/nro.cpp
loader/nro.h
loader/nso.cpp
loader/nso.h
memory.cpp
memory.h
memory_hook.h
memory_setup.h
perf_stats.cpp
perf_stats.h
settings.cpp
settings.h
telemetry_session.cpp
telemetry_session.h
tracer/citrace.h
tracer/recorder.cpp
tracer/recorder.h
)
set(SRCS
arm/dynarmic/arm_dynarmic.cpp
arm/unicorn/arm_unicorn.cpp
core.cpp
core_timing.cpp
file_sys/archive_backend.cpp
file_sys/disk_archive.cpp
file_sys/ivfc_archive.cpp
file_sys/path_parser.cpp
file_sys/savedata_archive.cpp
file_sys/title_metadata.cpp
frontend/emu_window.cpp
frontend/framebuffer_layout.cpp
gdbstub/gdbstub.cpp
hle/config_mem.cpp
hle/kernel/address_arbiter.cpp
hle/kernel/client_port.cpp
hle/kernel/client_session.cpp
hle/kernel/condition_variable.cpp
hle/kernel/domain.cpp
hle/kernel/event.cpp
hle/kernel/handle_table.cpp
hle/kernel/hle_ipc.cpp
hle/kernel/kernel.cpp
hle/kernel/memory.cpp
hle/kernel/mutex.cpp
hle/kernel/object_address_table.cpp
hle/kernel/process.cpp
hle/kernel/resource_limit.cpp
hle/kernel/server_port.cpp
hle/kernel/server_session.cpp
hle/kernel/shared_memory.cpp
hle/kernel/svc.cpp
hle/kernel/thread.cpp
hle/kernel/timer.cpp
hle/kernel/vm_manager.cpp
hle/kernel/wait_object.cpp
hle/lock.cpp
hle/romfs.cpp
hle/service/acc/acc.cpp
hle/service/acc/acc_u0.cpp
hle/service/am/am.cpp
hle/service/am/applet_oe.cpp
hle/service/aoc/aoc_u.cpp
hle/service/apm/apm.cpp
hle/service/audio/audio.cpp
hle/service/audio/audout_u.cpp
hle/service/hid/hid.cpp
hle/service/lm/lm.cpp
hle/service/nvdrv/devices/nvdisp_disp0.cpp
hle/service/nvdrv/devices/nvhost_as_gpu.cpp
hle/service/nvdrv/devices/nvmap.cpp
hle/service/nvdrv/interface.cpp
hle/service/nvdrv/nvdrv.cpp
hle/service/pctl/pctl.cpp
hle/service/pctl/pctl_a.cpp
hle/service/service.cpp
hle/service/sm/controller.cpp
hle/service/sm/sm.cpp
hle/service/time/time.cpp
hle/service/time/time_s.cpp
hle/service/vi/vi.cpp
hle/service/vi/vi_m.cpp
hle/shared_page.cpp
hw/hw.cpp
hw/lcd.cpp
loader/elf.cpp
loader/linker.cpp
loader/loader.cpp
loader/nro.cpp
loader/nso.cpp
tracer/recorder.cpp
memory.cpp
perf_stats.cpp
settings.cpp
telemetry_session.cpp
)
create_target_directory_groups(core)
set(HEADERS
arm/arm_interface.h
arm/dynarmic/arm_dynarmic.h
arm/unicorn/arm_unicorn.h
core.h
core_timing.h
file_sys/archive_backend.h
file_sys/directory_backend.h
file_sys/disk_archive.h
file_sys/errors.h
file_sys/file_backend.h
file_sys/ivfc_archive.h
file_sys/path_parser.h
file_sys/savedata_archive.h
frontend/emu_window.h
frontend/framebuffer_layout.h
frontend/input.h
gdbstub/gdbstub.h
hle/config_mem.h
hle/ipc.h
hle/ipc_helpers.h
hle/kernel/address_arbiter.h
hle/kernel/client_port.h
hle/kernel/client_session.h
hle/kernel/condition_variable.h
hle/kernel/domain.h
hle/kernel/errors.h
hle/kernel/event.h
hle/kernel/handle_table.h
hle/kernel/hle_ipc.h
hle/kernel/kernel.h
hle/kernel/memory.h
hle/kernel/mutex.h
hle/kernel/object_address_table.h
hle/kernel/process.h
hle/kernel/resource_limit.h
hle/kernel/server_port.h
hle/kernel/server_session.h
hle/kernel/session.h
hle/kernel/shared_memory.h
hle/kernel/sync_object.h
hle/kernel/svc.h
hle/kernel/svc_wrap.h
hle/kernel/thread.h
hle/kernel/timer.h
hle/kernel/vm_manager.h
hle/kernel/wait_object.h
hle/lock.h
hle/result.h
hle/romfs.h
hle/service/acc/acc.h
hle/service/acc/acc_u0.h
hle/service/am/am.h
hle/service/am/applet_oe.h
hle/service/aoc/aoc_u.h
hle/service/apm/apm.h
hle/service/audio/audio.h
hle/service/audio/audout_u.h
hle/service/hid/hid.h
hle/service/lm/lm.h
hle/service/nvdrv/devices/nvdevice.h
hle/service/nvdrv/devices/nvdisp_disp0.h
hle/service/nvdrv/devices/nvhost_as_gpu.h
hle/service/nvdrv/devices/nvmap.h
hle/service/nvdrv/interface.h
hle/service/nvdrv/nvdrv.h
hle/service/pctl/pctl.h
hle/service/pctl/pctl_a.h
hle/service/service.h
hle/service/sm/controller.h
hle/service/sm/sm.h
hle/service/time/time.h
hle/service/time/time_s.h
hle/service/vi/vi.h
hle/service/vi/vi_m.h
hle/shared_page.h
hw/hw.h
hw/lcd.h
loader/elf.h
loader/linker.h
loader/loader.h
loader/nro.h
loader/nso.h
tracer/recorder.h
tracer/citrace.h
memory.h
memory_setup.h
mmio.h
perf_stats.h
settings.h
telemetry_session.h
)
target_link_libraries(core PUBLIC common PRIVATE video_core)
create_directory_groups(${SRCS} ${HEADERS})
add_library(core STATIC ${SRCS} ${HEADERS})
target_link_libraries(core PUBLIC common PRIVATE dynarmic video_core)
target_link_libraries(core PUBLIC Boost::boost PRIVATE fmt lz4_static unicorn)
if (ARCHITECTURE_x86_64)
target_sources(core PRIVATE
arm/dynarmic/arm_dynarmic.cpp
arm/dynarmic/arm_dynarmic.h
)
target_link_libraries(core PRIVATE dynarmic)
endif()

View File

@@ -46,7 +46,7 @@ public:
ARM_Interface::ThreadContext ctx;
parent.SaveContext(ctx);
parent.inner_unicorn.LoadContext(ctx);
parent.inner_unicorn.ExecuteInstructions(static_cast<int>(num_instructions));
parent.inner_unicorn.ExecuteInstructions(num_instructions);
parent.inner_unicorn.SaveContext(ctx);
parent.LoadContext(ctx);
num_interpreted_instructions += num_instructions;
@@ -163,9 +163,9 @@ void ARM_Dynarmic::LoadContext(const ARM_Interface::ThreadContext& ctx) {
jit.SetRegisters(ctx.cpu_registers);
jit.SetSP(ctx.sp);
jit.SetPC(ctx.pc);
jit.SetPstate(static_cast<u32>(ctx.cpsr));
jit.SetPstate(ctx.cpsr);
jit.SetVectors(ctx.fpu_registers);
jit.SetFpcr(static_cast<u32>(ctx.fpscr));
jit.SetFpcr(ctx.fpscr);
cb->tpidrr0_el0 = ctx.tls_address;
}

View File

@@ -5,9 +5,7 @@
#include <memory>
#include <utility>
#include "common/logging/log.h"
#ifdef ARCHITECTURE_x86_64
#include "core/arm/dynarmic/arm_dynarmic.h"
#endif
#include "core/arm/unicorn/arm_unicorn.h"
#include "core/core.h"
#include "core/core_timing.h"
@@ -82,6 +80,7 @@ System::ResultStatus System::Load(EmuWindow* emu_window, const std::string& file
if (system_mode.second != Loader::ResultStatus::Success) {
LOG_CRITICAL(Core, "Failed to determine system mode (Error %i)!",
static_cast<int>(system_mode.second));
System::Shutdown();
switch (system_mode.second) {
case Loader::ResultStatus::ErrorEncrypted:
@@ -145,12 +144,7 @@ System::ResultStatus System::Init(EmuWindow* emu_window, u32 system_mode) {
break;
case Settings::CpuCore::Dynarmic:
default:
#ifdef ARCHITECTURE_x86_64
cpu_core = std::make_unique<ARM_Dynarmic>();
#else
cpu_core = std::make_unique<ARM_Unicorn>();
LOG_WARNING(Core, "CPU JIT requested, but Dynarmic not available");
#endif
break;
}

View File

@@ -51,13 +51,13 @@ public:
* requested is not guaranteed to run, as this will be interrupted preemptively if a hardware
* update is requested (e.g. on a thread switch).
* @param tight_loop Number of instructions to execute.
* @return Result status, indicating whether or not the operation succeeded.
* @return Result status, indicating whethor or not the operation succeeded.
*/
ResultStatus RunLoop(int tight_loop = 100000);
/**
* Step the CPU one instruction
* @return Result status, indicating whether or not the operation succeeded.
* @return Result status, indicating whethor or not the operation succeeded.
*/
ResultStatus SingleStep();

View File

@@ -122,7 +122,7 @@ u64 GetTicks() {
}
void AddTicks(u64 ticks) {
downcount -= static_cast<int>(ticks);
downcount -= ticks;
}
u64 GetIdleTicks() {
@@ -208,7 +208,7 @@ void Advance() {
Event evt = std::move(event_queue.front());
std::pop_heap(event_queue.begin(), event_queue.end(), std::greater<Event>());
event_queue.pop_back();
evt.type->callback(evt.userdata, static_cast<int>(global_timer - evt.time));
evt.type->callback(evt.userdata, global_timer - evt.time);
}
is_global_timer_sane = false;

View File

@@ -1,4 +1,4 @@
// Copyright 2018 yuzu emulator team
// Copyright 2015 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
@@ -7,7 +7,7 @@
#include <sstream>
#include "common/logging/log.h"
#include "common/string_util.h"
#include "core/file_sys/filesystem.h"
#include "core/file_sys/archive_backend.h"
#include "core/memory.h"
namespace FileSys {
@@ -119,4 +119,4 @@ std::vector<u8> Path::AsBinary() const {
return {};
}
}
} // namespace FileSys
}

View File

@@ -1,4 +1,4 @@
// Copyright 2018 yuzu emulator team
// Copyright 2014 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
@@ -15,7 +15,7 @@
namespace FileSys {
class StorageBackend;
class FileBackend;
class DirectoryBackend;
// Path string type
@@ -71,9 +71,9 @@ struct ArchiveFormatInfo {
};
static_assert(std::is_pod<ArchiveFormatInfo>::value, "ArchiveFormatInfo is not POD");
class FileSystemBackend : NonCopyable {
class ArchiveBackend : NonCopyable {
public:
virtual ~FileSystemBackend() {}
virtual ~ArchiveBackend() {}
/**
* Get a descriptive name for the archive (e.g. "RomFS", "SaveData", etc.)
@@ -81,12 +81,13 @@ public:
virtual std::string GetName() const = 0;
/**
* Create a file specified by its path
* @param path Path relative to the Archive
* @param size The size of the new file, filled with zeroes
* @return Result of the operation
* Open a file specified by its path, using the specified mode
* @param path Path relative to the archive
* @param mode Mode to open the file with
* @return Opened file, or error code
*/
virtual ResultCode CreateFile(const Path& path, u64 size) const = 0;
virtual ResultVal<std::unique_ptr<FileBackend>> OpenFile(const Path& path,
const Mode& mode) const = 0;
/**
* Delete a file specified by its path
@@ -96,11 +97,12 @@ public:
virtual ResultCode DeleteFile(const Path& path) const = 0;
/**
* Create a directory specified by its path
* @param path Path relative to the archive
* Rename a File specified by its path
* @param src_path Source path relative to the archive
* @param dest_path Destination path relative to the archive
* @return Result of the operation
*/
virtual ResultCode CreateDirectory(const Path& path) const = 0;
virtual ResultCode RenameFile(const Path& src_path, const Path& dest_path) const = 0;
/**
* Delete a directory specified by its path
@@ -117,12 +119,19 @@ public:
virtual ResultCode DeleteDirectoryRecursively(const Path& path) const = 0;
/**
* Rename a File specified by its path
* @param src_path Source path relative to the archive
* @param dest_path Destination path relative to the archive
* Create a file specified by its path
* @param path Path relative to the Archive
* @param size The size of the new file, filled with zeroes
* @return Result of the operation
*/
virtual ResultCode RenameFile(const Path& src_path, const Path& dest_path) const = 0;
virtual ResultCode CreateFile(const Path& path, u64 size) const = 0;
/**
* Create a directory specified by its path
* @param path Path relative to the archive
* @return Result of the operation
*/
virtual ResultCode CreateDirectory(const Path& path) const = 0;
/**
* Rename a Directory specified by its path
@@ -132,15 +141,6 @@ public:
*/
virtual ResultCode RenameDirectory(const Path& src_path, const Path& dest_path) const = 0;
/**
* Open a file specified by its path, using the specified mode
* @param path Path relative to the archive
* @param mode Mode to open the file with
* @return Opened file, or error code
*/
virtual ResultVal<std::unique_ptr<StorageBackend>> OpenFile(const Path& path,
const Mode& mode) const = 0;
/**
* Open a directory specified by its path
* @param path Path relative to the archive
@@ -152,12 +152,12 @@ public:
* Get the free space
* @return The number of free bytes in the archive
*/
virtual u64 GetFreeSpaceSize() const = 0;
virtual u64 GetFreeBytes() const = 0;
};
class FileSystemFactory : NonCopyable {
class ArchiveFactory : NonCopyable {
public:
virtual ~FileSystemFactory() {}
virtual ~ArchiveFactory() {}
/**
* Get a descriptive name for the archive (e.g. "RomFS", "SaveData", etc.)
@@ -169,7 +169,7 @@ public:
* @param path Path to the archive
* @return An ArchiveBackend corresponding operating specified archive path.
*/
virtual ResultVal<std::unique_ptr<FileSystemBackend>> Open(const Path& path) = 0;
virtual ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path) = 0;
/**
* Deletes the archive contents and then re-creates the base folder

View File

@@ -1,4 +1,4 @@
// Copyright 2018 yuzu emulator team
// Copyright 2014 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.

View File

@@ -0,0 +1,99 @@
// Copyright 2014 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <algorithm>
#include <cstdio>
#include <memory>
#include "common/common_types.h"
#include "common/file_util.h"
#include "common/logging/log.h"
#include "core/file_sys/disk_archive.h"
#include "core/file_sys/errors.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
// FileSys namespace
namespace FileSys {
ResultVal<size_t> DiskFile::Read(const u64 offset, const size_t length, u8* buffer) const {
if (!mode.read_flag)
return ERROR_INVALID_OPEN_FLAGS;
file->Seek(offset, SEEK_SET);
return MakeResult<size_t>(file->ReadBytes(buffer, length));
}
ResultVal<size_t> DiskFile::Write(const u64 offset, const size_t length, const bool flush,
const u8* buffer) const {
if (!mode.write_flag)
return ERROR_INVALID_OPEN_FLAGS;
file->Seek(offset, SEEK_SET);
size_t written = file->WriteBytes(buffer, length);
if (flush)
file->Flush();
return MakeResult<size_t>(written);
}
u64 DiskFile::GetSize() const {
return file->GetSize();
}
bool DiskFile::SetSize(const u64 size) const {
file->Resize(size);
file->Flush();
return true;
}
bool DiskFile::Close() const {
return file->Close();
}
////////////////////////////////////////////////////////////////////////////////////////////////////
DiskDirectory::DiskDirectory(const std::string& path) : directory() {
unsigned size = FileUtil::ScanDirectoryTree(path, directory);
directory.size = size;
directory.isDirectory = true;
children_iterator = directory.children.begin();
}
u32 DiskDirectory::Read(const u32 count, Entry* entries) {
u32 entries_read = 0;
while (entries_read < count && children_iterator != directory.children.cend()) {
const FileUtil::FSTEntry& file = *children_iterator;
const std::string& filename = file.virtualName;
Entry& entry = entries[entries_read];
LOG_TRACE(Service_FS, "File %s: size=%llu dir=%d", filename.c_str(), file.size,
file.isDirectory);
// TODO(Link Mauve): use a proper conversion to UTF-16.
for (size_t j = 0; j < FILENAME_LENGTH; ++j) {
entry.filename[j] = filename[j];
if (!filename[j])
break;
}
FileUtil::SplitFilename83(filename, entry.short_name, entry.extension);
entry.is_directory = file.isDirectory;
entry.is_hidden = (filename[0] == '.');
entry.is_read_only = 0;
entry.file_size = file.size;
// We emulate a SD card where the archive bit has never been cleared, as it would be on
// most user SD cards.
// Some homebrews (blargSNES for instance) are known to mistakenly use the archive bit as a
// file bit.
entry.is_archive = !file.isDirectory;
++entries_read;
++children_iterator;
}
return entries_read;
}
} // namespace FileSys

View File

@@ -0,0 +1,68 @@
// Copyright 2014 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <cstddef>
#include <memory>
#include <string>
#include <vector>
#include "common/common_types.h"
#include "common/file_util.h"
#include "core/file_sys/archive_backend.h"
#include "core/file_sys/directory_backend.h"
#include "core/file_sys/file_backend.h"
#include "core/hle/result.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
// FileSys namespace
namespace FileSys {
class DiskFile : public FileBackend {
public:
DiskFile(FileUtil::IOFile&& file_, const Mode& mode_)
: file(new FileUtil::IOFile(std::move(file_))) {
mode.hex = mode_.hex;
}
ResultVal<size_t> Read(u64 offset, size_t length, u8* buffer) const override;
ResultVal<size_t> Write(u64 offset, size_t length, bool flush, const u8* buffer) const override;
u64 GetSize() const override;
bool SetSize(u64 size) const override;
bool Close() const override;
void Flush() const override {
file->Flush();
}
protected:
Mode mode;
std::unique_ptr<FileUtil::IOFile> file;
};
class DiskDirectory : public DirectoryBackend {
public:
DiskDirectory(const std::string& path);
~DiskDirectory() override {
Close();
}
u32 Read(const u32 count, Entry* entries) override;
bool Close() const override {
return true;
}
protected:
u32 total_entries_in_directory;
FileUtil::FSTEntry directory;
// We need to remember the last entry we returned, so a subsequent call to Read will continue
// from the next one. This iterator will always point to the next unread entry.
std::vector<FileUtil::FSTEntry>::iterator children_iterator;
};
} // namespace FileSys

View File

@@ -1,4 +1,4 @@
// Copyright 2018 yuzu emulator team
// Copyright 2014 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
@@ -8,12 +8,15 @@
#include "common/common_types.h"
#include "core/hle/result.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
// FileSys namespace
namespace FileSys {
class StorageBackend : NonCopyable {
class FileBackend : NonCopyable {
public:
StorageBackend() {}
virtual ~StorageBackend() {}
FileBackend() {}
virtual ~FileBackend() {}
/**
* Read data from the file
@@ -36,9 +39,10 @@ public:
const u8* buffer) const = 0;
/**
* Flushes the file
* Get the size of the file in bytes
* @return Size of the file in bytes
*/
virtual void Flush() const = 0;
virtual u64 GetSize() const = 0;
/**
* Set the size of the file in bytes
@@ -47,17 +51,16 @@ public:
*/
virtual bool SetSize(u64 size) const = 0;
/**
* Get the size of the file in bytes
* @return Size of the file in bytes
*/
virtual u64 GetSize() const = 0;
/**
* Close the file
* @return true if the file closed correctly
*/
virtual bool Close() const = 0;
/**
* Flushes the file
*/
virtual void Flush() const = 0;
};
} // namespace FileSys

View File

@@ -1,4 +1,4 @@
// Copyright 2018 yuzu emulator team
// Copyright 2014 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
@@ -6,80 +6,84 @@
#include <memory>
#include "common/common_types.h"
#include "common/logging/log.h"
#include "core/file_sys/romfs_filesystem.h"
#include "core/file_sys/ivfc_archive.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
// FileSys namespace
namespace FileSys {
std::string RomFS_FileSystem::GetName() const {
return "RomFS";
std::string IVFCArchive::GetName() const {
return "IVFC";
}
ResultVal<std::unique_ptr<StorageBackend>> RomFS_FileSystem::OpenFile(const Path& path,
const Mode& mode) const {
return MakeResult<std::unique_ptr<StorageBackend>>(
std::make_unique<RomFS_Storage>(romfs_file, data_offset, data_size));
ResultVal<std::unique_ptr<FileBackend>> IVFCArchive::OpenFile(const Path& path,
const Mode& mode) const {
return MakeResult<std::unique_ptr<FileBackend>>(
std::make_unique<IVFCFile>(romfs_file, data_offset, data_size));
}
ResultCode RomFS_FileSystem::DeleteFile(const Path& path) const {
LOG_CRITICAL(Service_FS, "Attempted to delete a file from an ROMFS archive (%s).",
ResultCode IVFCArchive::DeleteFile(const Path& path) const {
LOG_CRITICAL(Service_FS, "Attempted to delete a file from an IVFC archive (%s).",
GetName().c_str());
// TODO(bunnei): Use correct error code
return ResultCode(-1);
}
ResultCode RomFS_FileSystem::RenameFile(const Path& src_path, const Path& dest_path) const {
LOG_CRITICAL(Service_FS, "Attempted to rename a file within an ROMFS archive (%s).",
ResultCode IVFCArchive::RenameFile(const Path& src_path, const Path& dest_path) const {
LOG_CRITICAL(Service_FS, "Attempted to rename a file within an IVFC archive (%s).",
GetName().c_str());
// TODO(wwylele): Use correct error code
return ResultCode(-1);
}
ResultCode RomFS_FileSystem::DeleteDirectory(const Path& path) const {
LOG_CRITICAL(Service_FS, "Attempted to delete a directory from an ROMFS archive (%s).",
ResultCode IVFCArchive::DeleteDirectory(const Path& path) const {
LOG_CRITICAL(Service_FS, "Attempted to delete a directory from an IVFC archive (%s).",
GetName().c_str());
// TODO(wwylele): Use correct error code
return ResultCode(-1);
}
ResultCode RomFS_FileSystem::DeleteDirectoryRecursively(const Path& path) const {
LOG_CRITICAL(Service_FS, "Attempted to delete a directory from an ROMFS archive (%s).",
ResultCode IVFCArchive::DeleteDirectoryRecursively(const Path& path) const {
LOG_CRITICAL(Service_FS, "Attempted to delete a directory from an IVFC archive (%s).",
GetName().c_str());
// TODO(wwylele): Use correct error code
return ResultCode(-1);
}
ResultCode RomFS_FileSystem::CreateFile(const Path& path, u64 size) const {
LOG_CRITICAL(Service_FS, "Attempted to create a file in an ROMFS archive (%s).",
ResultCode IVFCArchive::CreateFile(const Path& path, u64 size) const {
LOG_CRITICAL(Service_FS, "Attempted to create a file in an IVFC archive (%s).",
GetName().c_str());
// TODO(bunnei): Use correct error code
return ResultCode(-1);
}
ResultCode RomFS_FileSystem::CreateDirectory(const Path& path) const {
LOG_CRITICAL(Service_FS, "Attempted to create a directory in an ROMFS archive (%s).",
ResultCode IVFCArchive::CreateDirectory(const Path& path) const {
LOG_CRITICAL(Service_FS, "Attempted to create a directory in an IVFC archive (%s).",
GetName().c_str());
// TODO(wwylele): Use correct error code
return ResultCode(-1);
}
ResultCode RomFS_FileSystem::RenameDirectory(const Path& src_path, const Path& dest_path) const {
LOG_CRITICAL(Service_FS, "Attempted to rename a file within an ROMFS archive (%s).",
ResultCode IVFCArchive::RenameDirectory(const Path& src_path, const Path& dest_path) const {
LOG_CRITICAL(Service_FS, "Attempted to rename a file within an IVFC archive (%s).",
GetName().c_str());
// TODO(wwylele): Use correct error code
return ResultCode(-1);
}
ResultVal<std::unique_ptr<DirectoryBackend>> RomFS_FileSystem::OpenDirectory(
const Path& path) const {
return MakeResult<std::unique_ptr<DirectoryBackend>>(std::make_unique<ROMFSDirectory>());
ResultVal<std::unique_ptr<DirectoryBackend>> IVFCArchive::OpenDirectory(const Path& path) const {
return MakeResult<std::unique_ptr<DirectoryBackend>>(std::make_unique<IVFCDirectory>());
}
u64 RomFS_FileSystem::GetFreeSpaceSize() const {
LOG_WARNING(Service_FS, "Attempted to get the free space in an ROMFS archive");
u64 IVFCArchive::GetFreeBytes() const {
LOG_WARNING(Service_FS, "Attempted to get the free space in an IVFC archive");
return 0;
}
ResultVal<size_t> RomFS_Storage::Read(const u64 offset, const size_t length, u8* buffer) const {
////////////////////////////////////////////////////////////////////////////////////////////////////
ResultVal<size_t> IVFCFile::Read(const u64 offset, const size_t length, u8* buffer) const {
LOG_TRACE(Service_FS, "called offset=%llu, length=%zu", offset, length);
romfs_file->Seek(data_offset + offset, SEEK_SET);
size_t read_length = (size_t)std::min((u64)length, data_size - offset);
@@ -87,19 +91,19 @@ ResultVal<size_t> RomFS_Storage::Read(const u64 offset, const size_t length, u8*
return MakeResult<size_t>(romfs_file->ReadBytes(buffer, read_length));
}
ResultVal<size_t> RomFS_Storage::Write(const u64 offset, const size_t length, const bool flush,
const u8* buffer) const {
LOG_ERROR(Service_FS, "Attempted to write to ROMFS file");
ResultVal<size_t> IVFCFile::Write(const u64 offset, const size_t length, const bool flush,
const u8* buffer) const {
LOG_ERROR(Service_FS, "Attempted to write to IVFC file");
// TODO(Subv): Find error code
return MakeResult<size_t>(0);
}
u64 RomFS_Storage::GetSize() const {
u64 IVFCFile::GetSize() const {
return data_size;
}
bool RomFS_Storage::SetSize(const u64 size) const {
LOG_ERROR(Service_FS, "Attempted to set the size of an ROMFS file");
bool IVFCFile::SetSize(const u64 size) const {
LOG_ERROR(Service_FS, "Attempted to set the size of an IVFC file");
return false;
}

View File

@@ -1,4 +1,4 @@
// Copyright 2018 yuzu emulator team
// Copyright 2014 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
@@ -10,27 +10,30 @@
#include <vector>
#include "common/common_types.h"
#include "common/file_util.h"
#include "core/file_sys/directory.h"
#include "core/file_sys/filesystem.h"
#include "core/file_sys/storage.h"
#include "core/file_sys/archive_backend.h"
#include "core/file_sys/directory_backend.h"
#include "core/file_sys/file_backend.h"
#include "core/hle/result.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
// FileSys namespace
namespace FileSys {
/**
* Helper which implements an interface to deal with Switch .istorage ROMFS images used in some
* archives This should be subclassed by concrete archive types, which will provide the input data
* (load the raw ROMFS archive) and override any required methods
* Helper which implements an interface to deal with IVFC images used in some archives
* This should be subclassed by concrete archive types, which will provide the
* input data (load the raw IVFC archive) and override any required methods
*/
class RomFS_FileSystem : public FileSystemBackend {
class IVFCArchive : public ArchiveBackend {
public:
RomFS_FileSystem(std::shared_ptr<FileUtil::IOFile> file, u64 offset, u64 size)
IVFCArchive(std::shared_ptr<FileUtil::IOFile> file, u64 offset, u64 size)
: romfs_file(file), data_offset(offset), data_size(size) {}
std::string GetName() const override;
ResultVal<std::unique_ptr<StorageBackend>> OpenFile(const Path& path,
const Mode& mode) const override;
ResultVal<std::unique_ptr<FileBackend>> OpenFile(const Path& path,
const Mode& mode) const override;
ResultCode DeleteFile(const Path& path) const override;
ResultCode RenameFile(const Path& src_path, const Path& dest_path) const override;
ResultCode DeleteDirectory(const Path& path) const override;
@@ -39,7 +42,7 @@ public:
ResultCode CreateDirectory(const Path& path) const override;
ResultCode RenameDirectory(const Path& src_path, const Path& dest_path) const override;
ResultVal<std::unique_ptr<DirectoryBackend>> OpenDirectory(const Path& path) const override;
u64 GetFreeSpaceSize() const override;
u64 GetFreeBytes() const override;
protected:
std::shared_ptr<FileUtil::IOFile> romfs_file;
@@ -47,9 +50,9 @@ protected:
u64 data_size;
};
class RomFS_Storage : public StorageBackend {
class IVFCFile : public FileBackend {
public:
RomFS_Storage(std::shared_ptr<FileUtil::IOFile> file, u64 offset, u64 size)
IVFCFile(std::shared_ptr<FileUtil::IOFile> file, u64 offset, u64 size)
: romfs_file(file), data_offset(offset), data_size(size) {}
ResultVal<size_t> Read(u64 offset, size_t length, u8* buffer) const override;
@@ -67,7 +70,7 @@ private:
u64 data_size;
};
class ROMFSDirectory : public DirectoryBackend {
class IVFCDirectory : public DirectoryBackend {
public:
u32 Read(const u32 count, Entry* entries) override {
return 0;

View File

@@ -6,7 +6,7 @@
#include <string>
#include <vector>
#include "core/file_sys/filesystem.h"
#include "core/file_sys/archive_backend.h"
namespace FileSys {

View File

@@ -1,38 +0,0 @@
// Copyright 2018 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <algorithm>
#include <memory>
#include "common/common_types.h"
#include "common/logging/log.h"
#include "core/file_sys/romfs_factory.h"
#include "core/file_sys/romfs_filesystem.h"
namespace FileSys {
RomFS_Factory::RomFS_Factory(Loader::AppLoader& app_loader) {
// Load the RomFS from the app
if (Loader::ResultStatus::Success != app_loader.ReadRomFS(romfs_file, data_offset, data_size)) {
LOG_ERROR(Service_FS, "Unable to read RomFS!");
}
}
ResultVal<std::unique_ptr<FileSystemBackend>> RomFS_Factory::Open(const Path& path) {
auto archive = std::make_unique<RomFS_FileSystem>(romfs_file, data_offset, data_size);
return MakeResult<std::unique_ptr<FileSystemBackend>>(std::move(archive));
}
ResultCode RomFS_Factory::Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info) {
LOG_ERROR(Service_FS, "Unimplemented Format archive %s", GetName().c_str());
// TODO(bunnei): Find the right error code for this
return ResultCode(-1);
}
ResultVal<ArchiveFormatInfo> RomFS_Factory::GetFormatInfo(const Path& path) const {
LOG_ERROR(Service_FS, "Unimplemented GetFormatInfo archive %s", GetName().c_str());
// TODO(bunnei): Find the right error code for this
return ResultCode(-1);
}
} // namespace FileSys

View File

@@ -1,35 +0,0 @@
// Copyright 2018 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <memory>
#include <string>
#include <vector>
#include "common/common_types.h"
#include "core/file_sys/filesystem.h"
#include "core/hle/result.h"
#include "core/loader/loader.h"
namespace FileSys {
/// File system interface to the RomFS archive
class RomFS_Factory final : public FileSystemFactory {
public:
explicit RomFS_Factory(Loader::AppLoader& app_loader);
std::string GetName() const override {
return "ArchiveFactory_RomFS";
}
ResultVal<std::unique_ptr<FileSystemBackend>> Open(const Path& path) override;
ResultCode Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info) override;
ResultVal<ArchiveFormatInfo> GetFormatInfo(const Path& path) const override;
private:
std::shared_ptr<FileUtil::IOFile> romfs_file;
u64 data_offset;
u64 data_size;
};
} // namespace FileSys

View File

@@ -0,0 +1,330 @@
// Copyright 2016 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include "common/file_util.h"
#include "core/file_sys/disk_archive.h"
#include "core/file_sys/errors.h"
#include "core/file_sys/path_parser.h"
#include "core/file_sys/savedata_archive.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
// FileSys namespace
namespace FileSys {
ResultVal<std::unique_ptr<FileBackend>> SaveDataArchive::OpenFile(const Path& path,
const Mode& mode) const {
LOG_DEBUG(Service_FS, "called path=%s mode=%01X", path.DebugStr().c_str(), mode.hex);
const PathParser path_parser(path);
if (!path_parser.IsValid()) {
LOG_ERROR(Service_FS, "Invalid path %s", path.DebugStr().c_str());
return ERROR_INVALID_PATH;
}
if (mode.hex == 0) {
LOG_ERROR(Service_FS, "Empty open mode");
return ERROR_UNSUPPORTED_OPEN_FLAGS;
}
if (mode.create_flag && !mode.write_flag) {
LOG_ERROR(Service_FS, "Create flag set but write flag not set");
return ERROR_UNSUPPORTED_OPEN_FLAGS;
}
const auto full_path = path_parser.BuildHostPath(mount_point);
switch (path_parser.GetHostStatus(mount_point)) {
case PathParser::InvalidMountPoint:
LOG_CRITICAL(Service_FS, "(unreachable) Invalid mount point %s", mount_point.c_str());
return ERROR_FILE_NOT_FOUND;
case PathParser::PathNotFound:
LOG_ERROR(Service_FS, "Path not found %s", full_path.c_str());
return ERROR_PATH_NOT_FOUND;
case PathParser::FileInPath:
case PathParser::DirectoryFound:
LOG_ERROR(Service_FS, "Unexpected file or directory in %s", full_path.c_str());
return ERROR_UNEXPECTED_FILE_OR_DIRECTORY;
case PathParser::NotFound:
if (!mode.create_flag) {
LOG_ERROR(Service_FS, "Non-existing file %s can't be open without mode create.",
full_path.c_str());
return ERROR_FILE_NOT_FOUND;
} else {
// Create the file
FileUtil::CreateEmptyFile(full_path);
}
break;
case PathParser::FileFound:
break; // Expected 'success' case
}
FileUtil::IOFile file(full_path, mode.write_flag ? "r+b" : "rb");
if (!file.IsOpen()) {
LOG_CRITICAL(Service_FS, "(unreachable) Unknown error opening %s", full_path.c_str());
return ERROR_FILE_NOT_FOUND;
}
auto disk_file = std::make_unique<DiskFile>(std::move(file), mode);
return MakeResult<std::unique_ptr<FileBackend>>(std::move(disk_file));
}
ResultCode SaveDataArchive::DeleteFile(const Path& path) const {
const PathParser path_parser(path);
if (!path_parser.IsValid()) {
LOG_ERROR(Service_FS, "Invalid path %s", path.DebugStr().c_str());
return ERROR_INVALID_PATH;
}
const auto full_path = path_parser.BuildHostPath(mount_point);
switch (path_parser.GetHostStatus(mount_point)) {
case PathParser::InvalidMountPoint:
LOG_CRITICAL(Service_FS, "(unreachable) Invalid mount point %s", mount_point.c_str());
return ERROR_FILE_NOT_FOUND;
case PathParser::PathNotFound:
LOG_ERROR(Service_FS, "Path not found %s", full_path.c_str());
return ERROR_PATH_NOT_FOUND;
case PathParser::FileInPath:
case PathParser::DirectoryFound:
case PathParser::NotFound:
LOG_ERROR(Service_FS, "File not found %s", full_path.c_str());
return ERROR_FILE_NOT_FOUND;
case PathParser::FileFound:
break; // Expected 'success' case
}
if (FileUtil::Delete(full_path)) {
return RESULT_SUCCESS;
}
LOG_CRITICAL(Service_FS, "(unreachable) Unknown error deleting %s", full_path.c_str());
return ERROR_FILE_NOT_FOUND;
}
ResultCode SaveDataArchive::RenameFile(const Path& src_path, const Path& dest_path) const {
const PathParser path_parser_src(src_path);
// TODO: Verify these return codes with HW
if (!path_parser_src.IsValid()) {
LOG_ERROR(Service_FS, "Invalid src path %s", src_path.DebugStr().c_str());
return ERROR_INVALID_PATH;
}
const PathParser path_parser_dest(dest_path);
if (!path_parser_dest.IsValid()) {
LOG_ERROR(Service_FS, "Invalid dest path %s", dest_path.DebugStr().c_str());
return ERROR_INVALID_PATH;
}
const auto src_path_full = path_parser_src.BuildHostPath(mount_point);
const auto dest_path_full = path_parser_dest.BuildHostPath(mount_point);
if (FileUtil::Rename(src_path_full, dest_path_full)) {
return RESULT_SUCCESS;
}
// TODO(bunnei): Use correct error code
return ResultCode(-1);
}
template <typename T>
static ResultCode DeleteDirectoryHelper(const Path& path, const std::string& mount_point,
T deleter) {
const PathParser path_parser(path);
if (!path_parser.IsValid()) {
LOG_ERROR(Service_FS, "Invalid path %s", path.DebugStr().c_str());
return ERROR_INVALID_PATH;
}
if (path_parser.IsRootDirectory())
return ERROR_DIRECTORY_NOT_EMPTY;
const auto full_path = path_parser.BuildHostPath(mount_point);
switch (path_parser.GetHostStatus(mount_point)) {
case PathParser::InvalidMountPoint:
LOG_CRITICAL(Service_FS, "(unreachable) Invalid mount point %s", mount_point.c_str());
return ERROR_PATH_NOT_FOUND;
case PathParser::PathNotFound:
case PathParser::NotFound:
LOG_ERROR(Service_FS, "Path not found %s", full_path.c_str());
return ERROR_PATH_NOT_FOUND;
case PathParser::FileInPath:
case PathParser::FileFound:
LOG_ERROR(Service_FS, "Unexpected file or directory %s", full_path.c_str());
return ERROR_UNEXPECTED_FILE_OR_DIRECTORY;
case PathParser::DirectoryFound:
break; // Expected 'success' case
}
if (deleter(full_path)) {
return RESULT_SUCCESS;
}
LOG_ERROR(Service_FS, "Directory not empty %s", full_path.c_str());
return ERROR_DIRECTORY_NOT_EMPTY;
}
ResultCode SaveDataArchive::DeleteDirectory(const Path& path) const {
return DeleteDirectoryHelper(path, mount_point, FileUtil::DeleteDir);
}
ResultCode SaveDataArchive::DeleteDirectoryRecursively(const Path& path) const {
return DeleteDirectoryHelper(
path, mount_point, [](const std::string& p) { return FileUtil::DeleteDirRecursively(p); });
}
ResultCode SaveDataArchive::CreateFile(const FileSys::Path& path, u64 size) const {
const PathParser path_parser(path);
if (!path_parser.IsValid()) {
LOG_ERROR(Service_FS, "Invalid path %s", path.DebugStr().c_str());
return ERROR_INVALID_PATH;
}
const auto full_path = path_parser.BuildHostPath(mount_point);
switch (path_parser.GetHostStatus(mount_point)) {
case PathParser::InvalidMountPoint:
LOG_CRITICAL(Service_FS, "(unreachable) Invalid mount point %s", mount_point.c_str());
return ERROR_FILE_NOT_FOUND;
case PathParser::PathNotFound:
LOG_ERROR(Service_FS, "Path not found %s", full_path.c_str());
return ERROR_PATH_NOT_FOUND;
case PathParser::FileInPath:
LOG_ERROR(Service_FS, "Unexpected file in path %s", full_path.c_str());
return ERROR_UNEXPECTED_FILE_OR_DIRECTORY;
case PathParser::DirectoryFound:
case PathParser::FileFound:
LOG_ERROR(Service_FS, "%s already exists", full_path.c_str());
return ERROR_FILE_ALREADY_EXISTS;
case PathParser::NotFound:
break; // Expected 'success' case
}
if (size == 0) {
FileUtil::CreateEmptyFile(full_path);
return RESULT_SUCCESS;
}
FileUtil::IOFile file(full_path, "wb");
// Creates a sparse file (or a normal file on filesystems without the concept of sparse files)
// We do this by seeking to the right size, then writing a single null byte.
if (file.Seek(size - 1, SEEK_SET) && file.WriteBytes("", 1) == 1) {
return RESULT_SUCCESS;
}
LOG_ERROR(Service_FS, "Too large file");
// TODO(bunnei): Use correct error code
return ResultCode(-1);
}
ResultCode SaveDataArchive::CreateDirectory(const Path& path) const {
const PathParser path_parser(path);
if (!path_parser.IsValid()) {
LOG_ERROR(Service_FS, "Invalid path %s", path.DebugStr().c_str());
return ERROR_INVALID_PATH;
}
const auto full_path = path_parser.BuildHostPath(mount_point);
switch (path_parser.GetHostStatus(mount_point)) {
case PathParser::InvalidMountPoint:
LOG_CRITICAL(Service_FS, "(unreachable) Invalid mount point %s", mount_point.c_str());
return ERROR_FILE_NOT_FOUND;
case PathParser::PathNotFound:
LOG_ERROR(Service_FS, "Path not found %s", full_path.c_str());
return ERROR_PATH_NOT_FOUND;
case PathParser::FileInPath:
LOG_ERROR(Service_FS, "Unexpected file in path %s", full_path.c_str());
return ERROR_UNEXPECTED_FILE_OR_DIRECTORY;
case PathParser::DirectoryFound:
case PathParser::FileFound:
LOG_ERROR(Service_FS, "%s already exists", full_path.c_str());
return ERROR_DIRECTORY_ALREADY_EXISTS;
case PathParser::NotFound:
break; // Expected 'success' case
}
if (FileUtil::CreateDir(mount_point + path.AsString())) {
return RESULT_SUCCESS;
}
LOG_CRITICAL(Service_FS, "(unreachable) Unknown error creating %s", mount_point.c_str());
// TODO(bunnei): Use correct error code
return ResultCode(-1);
}
ResultCode SaveDataArchive::RenameDirectory(const Path& src_path, const Path& dest_path) const {
const PathParser path_parser_src(src_path);
// TODO: Verify these return codes with HW
if (!path_parser_src.IsValid()) {
LOG_ERROR(Service_FS, "Invalid src path %s", src_path.DebugStr().c_str());
return ERROR_INVALID_PATH;
}
const PathParser path_parser_dest(dest_path);
if (!path_parser_dest.IsValid()) {
LOG_ERROR(Service_FS, "Invalid dest path %s", dest_path.DebugStr().c_str());
return ERROR_INVALID_PATH;
}
const auto src_path_full = path_parser_src.BuildHostPath(mount_point);
const auto dest_path_full = path_parser_dest.BuildHostPath(mount_point);
if (FileUtil::Rename(src_path_full, dest_path_full)) {
return RESULT_SUCCESS;
}
// TODO(bunnei): Use correct error code
return ResultCode(-1);
}
ResultVal<std::unique_ptr<DirectoryBackend>> SaveDataArchive::OpenDirectory(
const Path& path) const {
const PathParser path_parser(path);
if (!path_parser.IsValid()) {
LOG_ERROR(Service_FS, "Invalid path %s", path.DebugStr().c_str());
return ERROR_INVALID_PATH;
}
const auto full_path = path_parser.BuildHostPath(mount_point);
switch (path_parser.GetHostStatus(mount_point)) {
case PathParser::InvalidMountPoint:
LOG_CRITICAL(Service_FS, "(unreachable) Invalid mount point %s", mount_point.c_str());
return ERROR_FILE_NOT_FOUND;
case PathParser::PathNotFound:
case PathParser::NotFound:
LOG_ERROR(Service_FS, "Path not found %s", full_path.c_str());
return ERROR_PATH_NOT_FOUND;
case PathParser::FileInPath:
case PathParser::FileFound:
LOG_ERROR(Service_FS, "Unexpected file in path %s", full_path.c_str());
return ERROR_UNEXPECTED_FILE_OR_DIRECTORY;
case PathParser::DirectoryFound:
break; // Expected 'success' case
}
auto directory = std::make_unique<DiskDirectory>(full_path);
return MakeResult<std::unique_ptr<DirectoryBackend>>(std::move(directory));
}
u64 SaveDataArchive::GetFreeBytes() const {
// TODO: Stubbed to return 1GiB
return 1024 * 1024 * 1024;
}
} // namespace FileSys

View File

@@ -0,0 +1,43 @@
// Copyright 2016 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <string>
#include "core/file_sys/archive_backend.h"
#include "core/file_sys/directory_backend.h"
#include "core/file_sys/file_backend.h"
#include "core/hle/result.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
// FileSys namespace
namespace FileSys {
/// Archive backend for general save data archive type (SaveData and SystemSaveData)
class SaveDataArchive : public ArchiveBackend {
public:
explicit SaveDataArchive(const std::string& mount_point_) : mount_point(mount_point_) {}
std::string GetName() const override {
return "SaveDataArchive: " + mount_point;
}
ResultVal<std::unique_ptr<FileBackend>> OpenFile(const Path& path,
const Mode& mode) const override;
ResultCode DeleteFile(const Path& path) const override;
ResultCode RenameFile(const Path& src_path, const Path& dest_path) const override;
ResultCode DeleteDirectory(const Path& path) const override;
ResultCode DeleteDirectoryRecursively(const Path& path) const override;
ResultCode CreateFile(const Path& path, u64 size) const override;
ResultCode CreateDirectory(const Path& path) const override;
ResultCode RenameDirectory(const Path& src_path, const Path& dest_path) const override;
ResultVal<std::unique_ptr<DirectoryBackend>> OpenDirectory(const Path& path) const override;
u64 GetFreeBytes() const override;
protected:
std::string mount_point;
};
} // namespace FileSys

View File

@@ -0,0 +1,163 @@
// Copyright 2017 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <cinttypes>
#include "common/alignment.h"
#include "common/file_util.h"
#include "common/logging/log.h"
#include "core/file_sys/title_metadata.h"
#include "core/loader/loader.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
// FileSys namespace
namespace FileSys {
static u32 GetSignatureSize(u32 signature_type) {
switch (signature_type) {
case Rsa4096Sha1:
case Rsa4096Sha256:
return 0x200;
case Rsa2048Sha1:
case Rsa2048Sha256:
return 0x100;
case EllipticSha1:
case EcdsaSha256:
return 0x3C;
}
}
Loader::ResultStatus TitleMetadata::Load() {
FileUtil::IOFile file(filepath, "rb");
if (!file.IsOpen())
return Loader::ResultStatus::Error;
if (!file.ReadBytes(&signature_type, sizeof(u32_be)))
return Loader::ResultStatus::Error;
// Signature lengths are variable, and the body follows the signature
u32 signature_size = GetSignatureSize(signature_type);
tmd_signature.resize(signature_size);
if (!file.ReadBytes(&tmd_signature[0], signature_size))
return Loader::ResultStatus::Error;
// The TMD body start position is rounded to the nearest 0x40 after the signature
size_t body_start = Common::AlignUp(signature_size + sizeof(u32), 0x40);
file.Seek(body_start, SEEK_SET);
// Read our TMD body, then load the amount of ContentChunks specified
if (file.ReadBytes(&tmd_body, sizeof(TitleMetadata::Body)) != sizeof(TitleMetadata::Body))
return Loader::ResultStatus::Error;
for (u16 i = 0; i < tmd_body.content_count; i++) {
ContentChunk chunk;
if (file.ReadBytes(&chunk, sizeof(ContentChunk)) == sizeof(ContentChunk)) {
tmd_chunks.push_back(chunk);
} else {
LOG_ERROR(Service_FS, "Malformed TMD %s, failed to load content chunk index %u!",
filepath.c_str(), i);
return Loader::ResultStatus::ErrorInvalidFormat;
}
}
return Loader::ResultStatus::Success;
}
Loader::ResultStatus TitleMetadata::Save() {
UNIMPLEMENTED();
return Loader::ResultStatus::Success;
}
u64 TitleMetadata::GetTitleID() const {
return tmd_body.title_id;
}
u32 TitleMetadata::GetTitleType() const {
return tmd_body.title_type;
}
u16 TitleMetadata::GetTitleVersion() const {
return tmd_body.title_version;
}
u64 TitleMetadata::GetSystemVersion() const {
return tmd_body.system_version;
}
size_t TitleMetadata::GetContentCount() const {
return tmd_chunks.size();
}
u32 TitleMetadata::GetBootContentID() const {
return tmd_chunks[TMDContentIndex::Main].id;
}
u32 TitleMetadata::GetManualContentID() const {
return tmd_chunks[TMDContentIndex::Manual].id;
}
u32 TitleMetadata::GetDLPContentID() const {
return tmd_chunks[TMDContentIndex::DLP].id;
}
void TitleMetadata::SetTitleID(u64 title_id) {
tmd_body.title_id = title_id;
}
void TitleMetadata::SetTitleType(u32 type) {
tmd_body.title_type = type;
}
void TitleMetadata::SetTitleVersion(u16 version) {
tmd_body.title_version = version;
}
void TitleMetadata::SetSystemVersion(u64 version) {
tmd_body.system_version = version;
}
void TitleMetadata::AddContentChunk(const ContentChunk& chunk) {
tmd_chunks.push_back(chunk);
}
void TitleMetadata::Print() const {
LOG_DEBUG(Service_FS, "%s - %u chunks", filepath.c_str(),
static_cast<u32>(tmd_body.content_count));
// Content info describes ranges of content chunks
LOG_DEBUG(Service_FS, "Content info:");
for (size_t i = 0; i < tmd_body.contentinfo.size(); i++) {
if (tmd_body.contentinfo[i].command_count == 0)
break;
LOG_DEBUG(Service_FS, " Index %04X, Command Count %04X",
static_cast<u32>(tmd_body.contentinfo[i].index),
static_cast<u32>(tmd_body.contentinfo[i].command_count));
}
// For each content info, print their content chunk range
for (size_t i = 0; i < tmd_body.contentinfo.size(); i++) {
u16 index = static_cast<u16>(tmd_body.contentinfo[i].index);
u16 count = static_cast<u16>(tmd_body.contentinfo[i].command_count);
if (count == 0)
continue;
LOG_DEBUG(Service_FS, "Content chunks for content info index %zu:", i);
for (u16 j = index; j < index + count; j++) {
// Don't attempt to print content we don't have
if (j > tmd_body.content_count)
break;
const ContentChunk& chunk = tmd_chunks[j];
LOG_DEBUG(Service_FS, " ID %08X, Index %04X, Type %04x, Size %016" PRIX64,
static_cast<u32>(chunk.id), static_cast<u32>(chunk.index),
static_cast<u32>(chunk.type), static_cast<u64>(chunk.size));
}
}
}
} // namespace FileSys

View File

@@ -0,0 +1,125 @@
// Copyright 2017 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <string>
#include <vector>
#include "common/common_types.h"
#include "common/swap.h"
namespace Loader {
enum class ResultStatus;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
// FileSys namespace
namespace FileSys {
enum TMDSignatureType : u32 {
Rsa4096Sha1 = 0x10000,
Rsa2048Sha1 = 0x10001,
EllipticSha1 = 0x10002,
Rsa4096Sha256 = 0x10003,
Rsa2048Sha256 = 0x10004,
EcdsaSha256 = 0x10005
};
enum TMDContentTypeFlag : u16 {
Encrypted = 1 << 1,
Disc = 1 << 2,
CFM = 1 << 3,
Optional = 1 << 14,
Shared = 1 << 15
};
/**
* Helper which implements an interface to read and write Title Metadata (TMD) files.
* If a file path is provided and the file exists, it can be parsed and used, otherwise
* it must be created. The TMD file can then be interpreted, modified and/or saved.
*/
class TitleMetadata {
public:
struct ContentChunk {
u32_be id;
u16_be index;
u16_be type;
u64_be size;
std::array<u8, 0x20> hash;
};
static_assert(sizeof(ContentChunk) == 0x30, "TMD ContentChunk structure size is wrong");
struct ContentInfo {
u16_be index;
u16_be command_count;
std::array<u8, 0x20> hash;
};
static_assert(sizeof(ContentInfo) == 0x24, "TMD ContentInfo structure size is wrong");
#pragma pack(push, 1)
struct Body {
std::array<u8, 0x40> issuer;
u8 version;
u8 ca_crl_version;
u8 signer_crl_version;
u8 reserved;
u64_be system_version;
u64_be title_id;
u32_be title_type;
u16_be group_id;
u32_be savedata_size;
u32_be srl_private_savedata_size;
std::array<u8, 4> reserved_2;
u8 srl_flag;
std::array<u8, 0x31> reserved_3;
u32_be access_rights;
u16_be title_version;
u16_be content_count;
u16_be boot_content;
std::array<u8, 2> reserved_4;
std::array<u8, 0x20> contentinfo_hash;
std::array<ContentInfo, 64> contentinfo;
};
static_assert(sizeof(Body) == 0x9C4, "TMD body structure size is wrong");
#pragma pack(pop)
explicit TitleMetadata(std::string& path) : filepath(std::move(path)) {}
Loader::ResultStatus Load();
Loader::ResultStatus Save();
u64 GetTitleID() const;
u32 GetTitleType() const;
u16 GetTitleVersion() const;
u64 GetSystemVersion() const;
size_t GetContentCount() const;
u32 GetBootContentID() const;
u32 GetManualContentID() const;
u32 GetDLPContentID() const;
void SetTitleID(u64 title_id);
void SetTitleType(u32 type);
void SetTitleVersion(u16 version);
void SetSystemVersion(u64 version);
void AddContentChunk(const ContentChunk& chunk);
void Print() const;
private:
enum TMDContentIndex { Main = 0, Manual = 1, DLP = 2 };
Body tmd_body;
u32_be signature_type;
std::vector<u8> tmd_signature;
std::vector<ContentChunk> tmd_chunks;
std::string filepath;
};
} // namespace FileSys

View File

@@ -57,10 +57,9 @@ const u32 SIGTERM = 15;
const u32 MSG_WAITALL = 8;
#endif
const u32 X30_REGISTER = 30;
const u32 SP_REGISTER = 31;
const u32 PC_REGISTER = 32;
const u32 CPSR_REGISTER = 33;
const u32 R15_REGISTER = 15;
const u32 CPSR_REGISTER = 25;
const u32 FPSCR_REGISTER = 58;
// For sample XML files see the GDB source /gdb/features
// GDB also wants the l character at the start
@@ -69,62 +68,48 @@ static const char* target_xml =
R"(l<?xml version="1.0"?>
<!DOCTYPE target SYSTEM "gdb-target.dtd">
<target version="1.0">
<feature name="org.gnu.gdb.aarch64.core">
<reg name="x0" bitsize="64"/>
<reg name="x1" bitsize="64"/>
<reg name="x2" bitsize="64"/>
<reg name="x3" bitsize="64"/>
<reg name="x4" bitsize="64"/>
<reg name="x5" bitsize="64"/>
<reg name="x6" bitsize="64"/>
<reg name="x7" bitsize="64"/>
<reg name="x8" bitsize="64"/>
<reg name="x9" bitsize="64"/>
<reg name="x10" bitsize="64"/>
<reg name="x11" bitsize="64"/>
<reg name="x12" bitsize="64"/>
<reg name="x13" bitsize="64"/>
<reg name="x14" bitsize="64"/>
<reg name="x15" bitsize="64"/>
<reg name="x16" bitsize="64"/>
<reg name="x17" bitsize="64"/>
<reg name="x18" bitsize="64"/>
<reg name="x19" bitsize="64"/>
<reg name="x20" bitsize="64"/>
<reg name="x21" bitsize="64"/>
<reg name="x22" bitsize="64"/>
<reg name="x23" bitsize="64"/>
<reg name="x24" bitsize="64"/>
<reg name="x25" bitsize="64"/>
<reg name="x26" bitsize="64"/>
<reg name="x27" bitsize="64"/>
<reg name="x28" bitsize="64"/>
<reg name="x29" bitsize="64"/>
<reg name="x30" bitsize="64"/>
<reg name="sp" bitsize="64" type="data_ptr"/>
<feature name="org.gnu.gdb.arm.core">
<reg name="r0" bitsize="32"/>
<reg name="r1" bitsize="32"/>
<reg name="r2" bitsize="32"/>
<reg name="r3" bitsize="32"/>
<reg name="r4" bitsize="32"/>
<reg name="r5" bitsize="32"/>
<reg name="r6" bitsize="32"/>
<reg name="r7" bitsize="32"/>
<reg name="r8" bitsize="32"/>
<reg name="r9" bitsize="32"/>
<reg name="r10" bitsize="32"/>
<reg name="r11" bitsize="32"/>
<reg name="r12" bitsize="32"/>
<reg name="sp" bitsize="32" type="data_ptr"/>
<reg name="lr" bitsize="32"/>
<reg name="pc" bitsize="32" type="code_ptr"/>
<reg name="pc" bitsize="64" type="code_ptr"/>
<!-- The CPSR is register 25, rather than register 16, because
the FPA registers historically were placed between the PC
and the CPSR in the "g" packet. -->
<flags id="cpsr_flags" size="4">
<field name="SP" start="0" end="0"/>
<field name="" start="1" end="1"/>
<field name="EL" start="2" end="3"/>
<field name="nRW" start="4" end="4"/>
<field name="" start="5" end="5"/>
<field name="F" start="6" end="6"/>
<field name="I" start="7" end="7"/>
<field name="A" start="8" end="8"/>
<field name="D" start="9" end="9"/>
<field name="IL" start="20" end="20"/>
<field name="SS" start="21" end="21"/>
<field name="V" start="28" end="28"/>
<field name="C" start="29" end="29"/>
<field name="Z" start="30" end="30"/>
<field name="N" start="31" end="31"/>
</flags>
<reg name="cpsr" bitsize="32" type="cpsr_flags"/>
<reg name="cpsr" bitsize="32" regnum="25"/>
</feature>
<feature name="org.gnu.gdb.arm.vfp">
<reg name="d0" bitsize="64" type="float"/>
<reg name="d1" bitsize="64" type="float"/>
<reg name="d2" bitsize="64" type="float"/>
<reg name="d3" bitsize="64" type="float"/>
<reg name="d4" bitsize="64" type="float"/>
<reg name="d5" bitsize="64" type="float"/>
<reg name="d6" bitsize="64" type="float"/>
<reg name="d7" bitsize="64" type="float"/>
<reg name="d8" bitsize="64" type="float"/>
<reg name="d9" bitsize="64" type="float"/>
<reg name="d10" bitsize="64" type="float"/>
<reg name="d11" bitsize="64" type="float"/>
<reg name="d12" bitsize="64" type="float"/>
<reg name="d13" bitsize="64" type="float"/>
<reg name="d14" bitsize="64" type="float"/>
<reg name="d15" bitsize="64" type="float"/>
<reg name="fpscr" bitsize="32" type="int" group="float"/>
</feature>
</target>
)";
@@ -158,12 +143,12 @@ WSADATA InitData;
struct Breakpoint {
bool active;
PAddr addr;
u64 len;
u32 len;
};
static std::map<u64, Breakpoint> breakpoints_execute;
static std::map<u64, Breakpoint> breakpoints_read;
static std::map<u64, Breakpoint> breakpoints_write;
static std::map<u32, Breakpoint> breakpoints_execute;
static std::map<u32, Breakpoint> breakpoints_read;
static std::map<u32, Breakpoint> breakpoints_write;
/**
* Turns hex string character into the equivalent byte.
@@ -198,11 +183,11 @@ static u8 NibbleToHex(u8 n) {
}
/**
* Converts input hex string characters into an array of equivalent of u8 bytes.
*
* @param src Pointer to array of output hex string characters.
* @param len Length of src array.
*/
* Converts input hex string characters into an array of equivalent of u8 bytes.
*
* @param src Pointer to array of output hex string characters.
* @param len Length of src array.
*/
static u32 HexToInt(const u8* src, size_t len) {
u32 output = 0;
while (len-- > 0) {
@@ -212,21 +197,6 @@ static u32 HexToInt(const u8* src, size_t len) {
return output;
}
/**
* Converts input hex string characters into an array of equivalent of u8 bytes.
*
* @param src Pointer to array of output hex string characters.
* @param len Length of src array.
*/
static u64 HexToLong(const u8* src, size_t len) {
u64 output = 0;
while (len-- > 0) {
output = (output << 4) | HexCharToValue(src[0]);
src++;
}
return output;
}
/**
* Converts input array of u8 bytes into their equivalent hex string characters.
*
@@ -264,21 +234,8 @@ static void GdbHexToMem(u8* dest, const u8* src, size_t len) {
*/
static void IntToGdbHex(u8* dest, u32 v) {
for (int i = 0; i < 8; i += 2) {
dest[i + 1] = NibbleToHex(static_cast<u8>(v >> (4 * i)));
dest[i] = NibbleToHex(static_cast<u8>(v >> (4 * (i + 1))));
}
}
/**
* Convert a u64 into a gdb-formatted hex string.
*
* @param dest Pointer to buffer to store output hex string characters.
* @param v Value to convert.
*/
static void LongToGdbHex(u8* dest, u64 v) {
for (int i = 0; i < 16; i += 2) {
dest[i + 1] = NibbleToHex(static_cast<u8>(v >> (4 * i)));
dest[i] = NibbleToHex(static_cast<u8>(v >> (4 * (i + 1))));
dest[i + 1] = NibbleToHex(v >> (4 * i));
dest[i] = NibbleToHex(v >> (4 * (i + 1)));
}
}
@@ -298,22 +255,6 @@ static u32 GdbHexToInt(const u8* src) {
return output;
}
/**
* Convert a gdb-formatted hex string into a u64.
*
* @param src Pointer to hex string.
*/
static u64 GdbHexToLong(const u8* src) {
u64 output = 0;
for (int i = 0; i < 16; i += 2) {
output = (output << 4) | HexCharToValue(src[15 - i - 1]);
output = (output << 4) | HexCharToValue(src[15 - i]);
}
return output;
}
/// Read a byte from the gdb client.
static u8 ReadByte() {
u8 c;
@@ -336,7 +277,7 @@ static u8 CalculateChecksum(const u8* buffer, size_t length) {
*
* @param type Type of breakpoint list.
*/
static std::map<u64, Breakpoint>& GetBreakpointList(BreakpointType type) {
static std::map<u32, Breakpoint>& GetBreakpointList(BreakpointType type) {
switch (type) {
case BreakpointType::Execute:
return breakpoints_execute;
@@ -356,19 +297,19 @@ static std::map<u64, Breakpoint>& GetBreakpointList(BreakpointType type) {
* @param addr Address of breakpoint.
*/
static void RemoveBreakpoint(BreakpointType type, PAddr addr) {
std::map<u64, Breakpoint>& p = GetBreakpointList(type);
std::map<u32, Breakpoint>& p = GetBreakpointList(type);
auto bp = p.find(static_cast<u64>(addr));
auto bp = p.find(addr);
if (bp != p.end()) {
LOG_DEBUG(Debug_GDBStub, "gdb: removed a breakpoint: %08x bytes at %08x of type %d\n",
bp->second.len, bp->second.addr, type);
p.erase(static_cast<u64>(addr));
p.erase(addr);
}
}
BreakpointAddress GetNextBreakpointFromAddress(PAddr addr, BreakpointType type) {
std::map<u64, Breakpoint>& p = GetBreakpointList(type);
auto next_breakpoint = p.lower_bound(static_cast<u64>(addr));
std::map<u32, Breakpoint>& p = GetBreakpointList(type);
auto next_breakpoint = p.lower_bound(addr);
BreakpointAddress breakpoint;
if (next_breakpoint != p.end()) {
@@ -387,11 +328,11 @@ bool CheckBreakpoint(PAddr addr, BreakpointType type) {
return false;
}
std::map<u64, Breakpoint>& p = GetBreakpointList(type);
std::map<u32, Breakpoint>& p = GetBreakpointList(type);
auto bp = p.find(static_cast<u64>(addr));
auto bp = p.find(addr);
if (bp != p.end()) {
u64 len = bp->second.len;
u32 len = bp->second.len;
// IDA Pro defaults to 4-byte breakpoints for all non-hardware breakpoints
// no matter if it's a 4-byte or 2-byte instruction. When you execute a
@@ -478,7 +419,7 @@ static void HandleQuery() {
SendReply("T0");
} else if (strncmp(query, "Supported", strlen("Supported")) == 0) {
// PacketSize needs to be large enough for target xml
SendReply("PacketSize=2000;qXfer:features:read+");
SendReply("PacketSize=800;qXfer:features:read+");
} else if (strncmp(query, "Xfer:features:read:target.xml:",
strlen("Xfer:features:read:target.xml:")) == 0) {
SendReply(target_xml);
@@ -509,7 +450,9 @@ static void SendSignal(u32 signal) {
latest_signal = signal;
std::string buffer = Common::StringFromFormat("T%02x", latest_signal);
std::string buffer =
Common::StringFromFormat("T%02x%02x:%08x;%02x:%08x;", latest_signal, 15,
htonl(Core::CPU().GetPC()), 13, htonl(Core::CPU().GetReg(13)));
LOG_DEBUG(Debug_GDBStub, "Response: %s", buffer.c_str());
SendReply(buffer.c_str());
}
@@ -595,12 +538,16 @@ static void ReadRegister() {
id |= HexCharToValue(command_buffer[2]);
}
if (id <= SP_REGISTER) {
LongToGdbHex(reply, Core::CPU().GetReg(static_cast<int>(id)));
} else if (id == PC_REGISTER) {
LongToGdbHex(reply, Core::CPU().GetPC());
if (id <= R15_REGISTER) {
IntToGdbHex(reply, Core::CPU().GetReg(id));
} else if (id == CPSR_REGISTER) {
IntToGdbHex(reply, Core::CPU().GetCPSR());
} else if (id > CPSR_REGISTER && id < FPSCR_REGISTER) {
IntToGdbHex(reply, Core::CPU().GetVFPReg(
id - CPSR_REGISTER -
1)); // VFP registers should start at 26, so one after CSPR_REGISTER
} else if (id == FPSCR_REGISTER) {
UNIMPLEMENTED();
} else {
return SendReply("E01");
}
@@ -615,19 +562,21 @@ static void ReadRegisters() {
u8* bufptr = buffer;
for (int reg = 0; reg <= SP_REGISTER; reg++) {
LongToGdbHex(bufptr + reg * 16, Core::CPU().GetReg(reg));
for (int reg = 0; reg <= R15_REGISTER; reg++) {
IntToGdbHex(bufptr + reg * CHAR_BIT, Core::CPU().GetReg(reg));
}
bufptr += (32 * 16);
LongToGdbHex(bufptr, Core::CPU().GetPC());
bufptr += 16;
bufptr += (16 * CHAR_BIT);
IntToGdbHex(bufptr, Core::CPU().GetCPSR());
bufptr += 8;
bufptr += CHAR_BIT;
for (int reg = 0; reg <= 31; reg++) {
IntToGdbHex(bufptr + reg * CHAR_BIT, Core::CPU().GetVFPReg(reg));
}
bufptr += (32 * CHAR_BIT);
SendReply(reinterpret_cast<char*>(buffer));
}
@@ -643,12 +592,14 @@ static void WriteRegister() {
id |= HexCharToValue(command_buffer[2]);
}
if (id <= SP_REGISTER) {
Core::CPU().SetReg(id, GdbHexToLong(buffer_ptr));
} else if (id == PC_REGISTER) {
Core::CPU().SetPC(GdbHexToLong(buffer_ptr));
if (id <= R15_REGISTER) {
Core::CPU().SetReg(id, GdbHexToInt(buffer_ptr));
} else if (id == CPSR_REGISTER) {
Core::CPU().SetCPSR(GdbHexToInt(buffer_ptr));
} else if (id > CPSR_REGISTER && id < FPSCR_REGISTER) {
Core::CPU().SetVFPReg(id - CPSR_REGISTER - 1, GdbHexToInt(buffer_ptr));
} else if (id == FPSCR_REGISTER) {
UNIMPLEMENTED();
} else {
return SendReply("E01");
}
@@ -663,14 +614,20 @@ static void WriteRegisters() {
if (command_buffer[0] != 'G')
return SendReply("E01");
for (int i = 0, reg = 0; reg <= CPSR_REGISTER; i++, reg++) {
if (reg <= SP_REGISTER) {
Core::CPU().SetReg(reg, GdbHexToLong(buffer_ptr + i * 16));
} else if (reg == PC_REGISTER) {
Core::CPU().SetPC(GdbHexToLong(buffer_ptr + i * 16));
for (int i = 0, reg = 0; reg <= FPSCR_REGISTER; i++, reg++) {
if (reg <= R15_REGISTER) {
Core::CPU().SetReg(reg, GdbHexToInt(buffer_ptr + i * CHAR_BIT));
} else if (reg == CPSR_REGISTER) {
Core::CPU().SetCPSR(GdbHexToInt(buffer_ptr + i * 16));
} else {
Core::CPU().SetCPSR(GdbHexToInt(buffer_ptr + i * CHAR_BIT));
} else if (reg == CPSR_REGISTER - 1) {
// Dummy FPA register, ignore
} else if (reg < CPSR_REGISTER) {
// Dummy FPA registers, ignore
i += 2;
} else if (reg > CPSR_REGISTER && reg < FPSCR_REGISTER) {
Core::CPU().SetVFPReg(reg - CPSR_REGISTER - 1, GdbHexToInt(buffer_ptr + i * CHAR_BIT));
i++; // Skip padding
} else if (reg == FPSCR_REGISTER) {
UNIMPLEMENTED();
}
}
@@ -684,13 +641,13 @@ static void ReadMemory() {
auto start_offset = command_buffer + 1;
auto addr_pos = std::find(start_offset, command_buffer + command_length, ',');
VAddr addr = HexToLong(start_offset, static_cast<u64>(addr_pos - start_offset));
VAddr addr = HexToInt(start_offset, static_cast<u32>(addr_pos - start_offset));
start_offset = addr_pos + 1;
u64 len =
HexToLong(start_offset, static_cast<u64>((command_buffer + command_length) - start_offset));
u32 len =
HexToInt(start_offset, static_cast<u32>((command_buffer + command_length) - start_offset));
LOG_DEBUG(Debug_GDBStub, "gdb: addr: %016llx len: %016llx\n", addr, len);
LOG_DEBUG(Debug_GDBStub, "gdb: addr: %08x len: %08x\n", addr, len);
if (len * 2 > sizeof(reply)) {
SendReply("E01");
@@ -712,11 +669,11 @@ static void ReadMemory() {
static void WriteMemory() {
auto start_offset = command_buffer + 1;
auto addr_pos = std::find(start_offset, command_buffer + command_length, ',');
VAddr addr = HexToLong(start_offset, static_cast<u64>(addr_pos - start_offset));
VAddr addr = HexToInt(start_offset, static_cast<u32>(addr_pos - start_offset));
start_offset = addr_pos + 1;
auto len_pos = std::find(start_offset, command_buffer + command_length, ':');
u64 len = HexToLong(start_offset, static_cast<u64>(len_pos - start_offset));
u32 len = HexToInt(start_offset, static_cast<u32>(len_pos - start_offset));
if (!Memory::IsValidVirtualAddress(addr)) {
return SendReply("E00");
@@ -769,8 +726,8 @@ static void Continue() {
* @param addr Address of breakpoint.
* @param len Length of breakpoint.
*/
static bool CommitBreakpoint(BreakpointType type, PAddr addr, u64 len) {
std::map<u64, Breakpoint>& p = GetBreakpointList(type);
static bool CommitBreakpoint(BreakpointType type, PAddr addr, u32 len) {
std::map<u32, Breakpoint>& p = GetBreakpointList(type);
Breakpoint breakpoint;
breakpoint.active = true;
@@ -809,11 +766,11 @@ static void AddBreakpoint() {
auto start_offset = command_buffer + 3;
auto addr_pos = std::find(start_offset, command_buffer + command_length, ',');
PAddr addr = HexToLong(start_offset, static_cast<u64>(addr_pos - start_offset));
PAddr addr = HexToInt(start_offset, static_cast<u32>(addr_pos - start_offset));
start_offset = addr_pos + 1;
u64 len =
HexToLong(start_offset, static_cast<u64>((command_buffer + command_length) - start_offset));
u32 len =
HexToInt(start_offset, static_cast<u32>((command_buffer + command_length) - start_offset));
if (type == BreakpointType::Access) {
// Access is made up of Read and Write types, so add both breakpoints
@@ -858,7 +815,7 @@ static void RemoveBreakpoint() {
auto start_offset = command_buffer + 3;
auto addr_pos = std::find(start_offset, command_buffer + command_length, ',');
PAddr addr = HexToLong(start_offset, static_cast<u64>(addr_pos - start_offset));
PAddr addr = HexToInt(start_offset, static_cast<u32>(addr_pos - start_offset));
if (type == BreakpointType::Access) {
// Access is made up of Read and Write types, so add both breakpoints
@@ -948,7 +905,7 @@ void ToggleServer(bool status) {
server_enabled = status;
// Start server
if (!IsConnected() && Core::System::GetInstance().IsPoweredOn()) {
if (!IsConnected() && Core::System().GetInstance().IsPoweredOn()) {
Init();
}
} else {
@@ -1077,4 +1034,4 @@ bool GetCpuStepFlag() {
void SetCpuStepFlag(bool is_step) {
step_loop = is_step;
}
}; // namespace GDBStub
};

View File

@@ -91,4 +91,4 @@ bool GetCpuStepFlag();
* @param is_step
*/
void SetCpuStepFlag(bool is_step);
} // namespace GDBStub
}

View File

@@ -28,4 +28,4 @@ void Init() {
config_mem.firm_ctr_sdk_ver = 0x0000F297;
}
} // namespace ConfigMem
} // namespace

View File

@@ -53,4 +53,4 @@ extern ConfigMemDef config_mem;
void Init();
} // namespace ConfigMem
} // namespace

View File

@@ -133,10 +133,6 @@ struct BufferDescriptorC {
address |= static_cast<VAddr>(address_bits_32_47) << 32;
return address;
}
u64 Size() const {
return static_cast<u64>(size);
}
};
static_assert(sizeof(BufferDescriptorC) == 8, "BufferDescriptorC size is incorrect");
@@ -147,11 +143,6 @@ struct DataPayloadHeader {
static_assert(sizeof(DataPayloadHeader) == 8, "DataPayloadRequest size is incorrect");
struct DomainMessageHeader {
enum class CommandType : u32_le {
SendMessage = 1,
CloseVirtualHandle = 2,
};
union {
// Used when responding to an IPC request, Server -> Client.
struct {
@@ -162,7 +153,7 @@ struct DomainMessageHeader {
// Used when performing an IPC request, Client -> Server.
struct {
union {
BitField<0, 8, CommandType> command;
BitField<0, 8, u32_le> command;
BitField<16, 16, u32_le> size;
};
u32_le object_id;

View File

@@ -11,6 +11,7 @@
#include "core/hle/ipc.h"
#include "core/hle/kernel/client_port.h"
#include "core/hle/kernel/client_session.h"
#include "core/hle/kernel/domain.h"
#include "core/hle/kernel/handle_table.h"
#include "core/hle/kernel/hle_ipc.h"
#include "core/hle/kernel/kernel.h"
@@ -30,6 +31,11 @@ public:
RequestHelperBase(Kernel::HLERequestContext& context)
: context(&context), cmdbuf(context.CommandBuffer()) {}
void ValidateHeader() {
// DEBUG_ASSERT_MSG(index == TotalSize(), "Operations do not match the header (cmd 0x%x)",
// header.raw);
}
void Skip(unsigned size_in_words, bool set_to_null) {
if (set_to_null)
memset(cmdbuf + index, 0, size_in_words * sizeof(u32));
@@ -48,36 +54,16 @@ public:
unsigned GetCurrentOffset() const {
return static_cast<unsigned>(index);
}
void SetCurrentOffset(unsigned offset) {
index = static_cast<ptrdiff_t>(offset);
}
};
class ResponseBuilder : public RequestHelperBase {
class RequestBuilder : public RequestHelperBase {
public:
ResponseBuilder(u32* command_buffer) : RequestHelperBase(command_buffer) {}
u32 normal_params_size{};
u32 num_handles_to_copy{};
u32 num_objects_to_move{}; ///< Domain objects or move handles, context dependent
std::ptrdiff_t datapayload_index{};
/// Flags used for customizing the behavior of ResponseBuilder
enum class Flags : u32 {
None = 0,
/// Uses move handles to move objects in the response, even when in a domain. This is
/// required when PushMoveObjects is used.
AlwaysMoveHandles = 1,
};
ResponseBuilder(Kernel::HLERequestContext& context, u32 normal_params_size,
u32 num_handles_to_copy = 0, u32 num_objects_to_move = 0,
Flags flags = Flags::None)
: RequestHelperBase(context), normal_params_size(normal_params_size),
num_handles_to_copy(num_handles_to_copy), num_objects_to_move(num_objects_to_move) {
RequestBuilder(u32* command_buffer) : RequestHelperBase(command_buffer) {}
RequestBuilder(Kernel::HLERequestContext& context, unsigned normal_params_size,
u32 num_handles_to_copy = 0, u32 num_handles_to_move = 0,
u32 num_domain_objects = 0)
: RequestHelperBase(context) {
memset(cmdbuf, 0, sizeof(u32) * IPC::COMMAND_BUFFER_LENGTH);
context.ClearIncomingObjects();
@@ -87,19 +73,12 @@ public:
// The entire size of the raw data section in u32 units, including the 16 bytes of mandatory
// padding.
u32 raw_data_size = sizeof(IPC::DataPayloadHeader) / 4 + 4 + normal_params_size;
u32 num_handles_to_move{};
u32 num_domain_objects{};
const bool always_move_handles{
(static_cast<u32>(flags) & static_cast<u32>(Flags::AlwaysMoveHandles)) != 0};
if (!context.Session()->IsDomain() || always_move_handles) {
num_handles_to_move = num_objects_to_move;
} else {
num_domain_objects = num_objects_to_move;
}
if (context.Session()->IsDomain()) {
if (context.IsDomain()) {
raw_data_size += sizeof(DomainMessageHeader) / 4 + num_domain_objects;
} else {
// If we're not in a domain, turn the domain object parameters into move handles.
num_handles_to_move += num_domain_objects;
num_domain_objects = 0;
}
header.data_size.Assign(raw_data_size);
@@ -118,7 +97,7 @@ public:
AlignWithPadding();
if (context.Session()->IsDomain()) {
if (context.IsDomain()) {
IPC::DomainMessageHeader domain_header{};
domain_header.num_objects = num_domain_objects;
PushRaw(domain_header);
@@ -127,43 +106,23 @@ public:
IPC::DataPayloadHeader data_payload_header{};
data_payload_header.magic = Common::MakeMagic('S', 'F', 'C', 'O');
PushRaw(data_payload_header);
datapayload_index = index;
}
template <class T>
void PushIpcInterface(std::shared_ptr<T> iface) {
if (context->Session()->IsDomain()) {
context->AddDomainObject(std::move(iface));
} else {
auto sessions = Kernel::ServerSession::CreateSessionPair(iface->GetServiceName());
auto server = std::get<Kernel::SharedPtr<Kernel::ServerSession>>(sessions);
auto client = std::get<Kernel::SharedPtr<Kernel::ClientSession>>(sessions);
iface->ClientConnected(server);
context->AddMoveObject(std::move(client));
}
}
template <class T, class... Args>
void PushIpcInterface(Args&&... args) {
PushIpcInterface<T>(std::make_shared<T>(std::forward<Args>(args)...));
}
void ValidateHeader() {
const size_t num_domain_objects = context->NumDomainObjects();
const size_t num_move_objects = context->NumMoveObjects();
ASSERT_MSG(!num_domain_objects || !num_move_objects,
"cannot move normal handles and domain objects");
ASSERT_MSG((index - datapayload_index) == normal_params_size,
"normal_params_size value is incorrect");
ASSERT_MSG((num_domain_objects + num_move_objects) == num_objects_to_move,
"num_objects_to_move value is incorrect");
ASSERT_MSG(context->NumCopyObjects() == num_handles_to_copy,
"num_handles_to_copy value is incorrect");
auto iface = std::make_shared<T>(std::forward<Args>(args)...);
if (context->IsDomain()) {
context->AddDomainObject(std::move(iface));
} else {
auto port = iface->CreatePort();
auto session = port->Connect();
ASSERT(session.Succeeded());
context->AddMoveObject(std::move(session).Unwrap());
}
}
// Validate on destruction, as there shouldn't be any case where we don't want it
~ResponseBuilder() {
~RequestBuilder() {
ValidateHeader();
}
@@ -191,52 +150,52 @@ public:
/// Push ///
template <>
inline void ResponseBuilder::Push(u32 value) {
inline void RequestBuilder::Push(u32 value) {
cmdbuf[index++] = value;
}
template <typename T>
void ResponseBuilder::PushRaw(const T& value) {
void RequestBuilder::PushRaw(const T& value) {
std::memcpy(cmdbuf + index, &value, sizeof(T));
index += (sizeof(T) + 3) / 4; // round up to word length
}
template <>
inline void ResponseBuilder::Push(ResultCode value) {
inline void RequestBuilder::Push(ResultCode value) {
// Result codes are actually 64-bit in the IPC buffer, but only the high part is discarded.
Push(value.raw);
Push<u32>(0);
}
template <>
inline void ResponseBuilder::Push(u8 value) {
inline void RequestBuilder::Push(u8 value) {
PushRaw(value);
}
template <>
inline void ResponseBuilder::Push(u16 value) {
inline void RequestBuilder::Push(u16 value) {
PushRaw(value);
}
template <>
inline void ResponseBuilder::Push(u64 value) {
inline void RequestBuilder::Push(u64 value) {
Push(static_cast<u32>(value));
Push(static_cast<u32>(value >> 32));
}
template <>
inline void ResponseBuilder::Push(bool value) {
inline void RequestBuilder::Push(bool value) {
Push(static_cast<u8>(value));
}
template <typename First, typename... Other>
void ResponseBuilder::Push(const First& first_value, const Other&... other_values) {
void RequestBuilder::Push(const First& first_value, const Other&... other_values) {
Push(first_value);
Push(other_values...);
}
template <typename... O>
inline void ResponseBuilder::PushCopyObjects(Kernel::SharedPtr<O>... pointers) {
inline void RequestBuilder::PushCopyObjects(Kernel::SharedPtr<O>... pointers) {
auto objects = {pointers...};
for (auto& object : objects) {
context->AddCopyObject(std::move(object));
@@ -244,7 +203,7 @@ inline void ResponseBuilder::PushCopyObjects(Kernel::SharedPtr<O>... pointers) {
}
template <typename... O>
inline void ResponseBuilder::PushMoveObjects(Kernel::SharedPtr<O>... pointers) {
inline void RequestBuilder::PushMoveObjects(Kernel::SharedPtr<O>... pointers) {
auto objects = {pointers...};
for (auto& object : objects) {
context->AddMoveObject(std::move(object));
@@ -263,10 +222,15 @@ public:
Skip(CommandIdSize, false);
}
ResponseBuilder MakeBuilder(u32 normal_params_size, u32 num_handles_to_copy,
u32 num_handles_to_move,
ResponseBuilder::Flags flags = ResponseBuilder::Flags::None) {
return {*context, normal_params_size, num_handles_to_copy, num_handles_to_move, flags};
RequestBuilder MakeBuilder(u32 normal_params_size, u32 num_handles_to_copy,
u32 num_handles_to_move, u32 num_domain_objects,
bool validate_header = true) {
if (validate_header) {
ValidateHeader();
}
return {*context, normal_params_size, num_handles_to_copy, num_handles_to_move,
num_domain_objects};
}
template <typename T>
@@ -336,11 +300,6 @@ inline u64 RequestParser::Pop() {
return msw << 32 | lsw;
}
template <>
inline s64 RequestParser::Pop() {
return static_cast<s64>(Pop<u64>());
}
template <>
inline bool RequestParser::Pop() {
return Pop<u8>() != 0;

View File

@@ -57,4 +57,4 @@ private:
~AddressArbiter() override;
};
} // namespace Kernel
} // namespace FileSys

View File

@@ -39,4 +39,4 @@ ResultVal<SharedPtr<ClientSession>> ClientPort::Connect() {
return MakeResult(std::get<SharedPtr<ClientSession>>(sessions));
}
} // namespace Kernel
} // namespace

View File

@@ -47,4 +47,4 @@ private:
~ClientPort() override;
};
} // namespace Kernel
} // namespace

View File

@@ -48,4 +48,4 @@ ResultCode ClientSession::SendSyncRequest(SharedPtr<Thread> thread) {
return server->HandleSyncRequest(std::move(thread));
}
} // namespace Kernel
} // namespace

View File

@@ -7,7 +7,7 @@
#include <memory>
#include <string>
#include "common/common_types.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/sync_object.h"
#include "core/hle/result.h"
namespace Kernel {
@@ -16,7 +16,7 @@ class ServerSession;
class Session;
class Thread;
class ClientSession final : public Object {
class ClientSession final : public SyncObject {
public:
friend class ServerSession;
@@ -33,7 +33,7 @@ public:
return HANDLE_TYPE;
}
ResultCode SendSyncRequest(SharedPtr<Thread> thread);
ResultCode SendSyncRequest(SharedPtr<Thread> thread) override;
std::string name; ///< Name of client port (optional)
@@ -45,4 +45,4 @@ private:
~ClientSession() override;
};
} // namespace Kernel
} // namespace

View File

@@ -15,12 +15,13 @@ ConditionVariable::ConditionVariable() {}
ConditionVariable::~ConditionVariable() {}
ResultVal<SharedPtr<ConditionVariable>> ConditionVariable::Create(VAddr guest_addr,
VAddr mutex_addr,
std::string name) {
SharedPtr<ConditionVariable> condition_variable(new ConditionVariable);
condition_variable->name = std::move(name);
condition_variable->guest_addr = guest_addr;
condition_variable->mutex_addr = 0;
condition_variable->mutex_addr = mutex_addr;
// Condition variables are referenced by guest address, so track this in the kernel
g_object_address_table.Insert(guest_addr, condition_variable);
@@ -42,7 +43,7 @@ void ConditionVariable::Acquire(Thread* thread) {
ResultCode ConditionVariable::Release(s32 target) {
if (target == -1) {
// When -1, wake up all waiting threads
SetAvailableCount(static_cast<s32>(GetWaitingThreads().size()));
SetAvailableCount(GetWaitingThreads().size());
WakeupAllWaitingThreads();
} else {
// Otherwise, wake up just a single thread

View File

@@ -4,8 +4,8 @@
#pragma once
#include <string>
#include <queue>
#include <string>
#include "common/common_types.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/wait_object.h"
@@ -19,10 +19,12 @@ public:
* Creates a condition variable.
* @param guest_addr Address of the object tracking the condition variable in guest memory. If
* specified, this condition variable will update the guest object when its state changes.
* @param mutex_addr Optional address of a guest mutex associated with this condition variable,
* used by the OS for implementing events.
* @param name Optional name of condition variable.
* @return The created condition variable.
*/
static ResultVal<SharedPtr<ConditionVariable>> Create(VAddr guest_addr,
static ResultVal<SharedPtr<ConditionVariable>> Create(VAddr guest_addr, VAddr mutex_addr = 0,
std::string name = "Unknown");
std::string GetTypeName() const override {

View File

@@ -0,0 +1,44 @@
// Copyright 2018 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include "core/hle/kernel/client_port.h"
#include "core/hle/kernel/domain.h"
#include "core/hle/kernel/handle_table.h"
#include "core/hle/kernel/hle_ipc.h"
#include "core/hle/kernel/process.h"
#include "core/hle/kernel/session.h"
#include "core/hle/kernel/thread.h"
namespace Kernel {
ResultVal<SharedPtr<Domain>> Domain::Create(std::string name) {
SharedPtr<Domain> domain(new Domain);
domain->name = std::move(name);
return MakeResult(std::move(domain));
}
ResultVal<SharedPtr<Domain>> Domain::CreateFromSession(const Session& session) {
auto res = Create(session.port->GetName() + "_Domain");
auto& domain = res.Unwrap();
domain->request_handlers.push_back(std::move(session.server->hle_handler));
Kernel::g_handle_table.ConvertSessionToDomain(session, domain);
return res;
}
ResultCode Domain::SendSyncRequest(SharedPtr<Thread> thread) {
Kernel::HLERequestContext context(this);
u32* cmd_buf = (u32*)Memory::GetPointer(Kernel::GetCurrentThread()->GetTLSAddress());
context.PopulateFromIncomingCommandBuffer(cmd_buf, *Kernel::g_current_process,
Kernel::g_handle_table);
auto& domain_message_header = context.GetDomainMessageHeader();
if (domain_message_header) {
// If there is a DomainMessageHeader, then this is CommandType "Request"
const u32 object_id{context.GetDomainMessageHeader()->object_id};
return request_handlers[object_id - 1]->HandleSyncRequest(context);
}
return request_handlers.front()->HandleSyncRequest(context);
}
} // namespace Kernel

View File

@@ -0,0 +1,45 @@
// Copyright 2018 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <memory>
#include <string>
#include <vector>
#include "core/hle/kernel/sync_object.h"
#include "core/hle/result.h"
namespace Kernel {
class Session;
class SessionRequestHandler;
class Domain final : public SyncObject {
public:
std::string GetTypeName() const override {
return "Domain";
}
static const HandleType HANDLE_TYPE = HandleType::Domain;
HandleType GetHandleType() const override {
return HANDLE_TYPE;
}
static ResultVal<SharedPtr<Domain>> CreateFromSession(const Session& server);
ResultCode SendSyncRequest(SharedPtr<Thread> thread) override;
/// The name of this domain (optional)
std::string name;
std::vector<std::shared_ptr<SessionRequestHandler>> request_handlers;
private:
Domain() = default;
~Domain() override = default;
static ResultVal<SharedPtr<Domain>> Create(std::string name = "Unknown");
};
} // namespace Kernel

View File

@@ -52,4 +52,4 @@ void Event::WakeupAllWaitingThreads() {
signaled = false;
}
} // namespace Kernel
} // namespace

View File

@@ -49,4 +49,4 @@ private:
~Event() override;
};
} // namespace Kernel
} // namespace

View File

@@ -5,10 +5,12 @@
#include <utility>
#include "common/assert.h"
#include "common/logging/log.h"
#include "core/hle/kernel/client_session.h"
#include "core/hle/kernel/errors.h"
#include "core/hle/kernel/handle_table.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/process.h"
#include "core/hle/kernel/session.h"
#include "core/hle/kernel/thread.h"
namespace Kernel {
@@ -53,6 +55,14 @@ ResultVal<Handle> HandleTable::Duplicate(Handle handle) {
return Create(std::move(object));
}
void HandleTable::ConvertSessionToDomain(const Session& session, SharedPtr<Object> domain) {
for (auto& object : objects) {
if (DynamicObjectCast<ClientSession>(object) == session.client) {
object = domain;
}
}
}
ResultCode HandleTable::Close(Handle handle) {
if (!IsValid(handle))
return ERR_INVALID_HANDLE;
@@ -94,4 +104,4 @@ void HandleTable::Clear() {
next_free_slot = 0;
}
} // namespace Kernel
} // namespace

View File

@@ -17,6 +17,8 @@ enum KernelHandle : Handle {
CurrentProcess = 0xFFFF8001,
};
class Session;
/**
* This class allows the creation of Handles, which are references to objects that can be tested
* for validity and looked up. Here they are used to pass references to kernel objects to/from the
@@ -59,6 +61,11 @@ public:
*/
ResultVal<Handle> Duplicate(Handle handle);
/**
* Convert all handles of the specified Session to the specified Domain.
*/
void ConvertSessionToDomain(const Session& session, SharedPtr<Object> domain);
/**
* Closes a handle, removing it from the table and decreasing the object's ref-count.
* @return `RESULT_SUCCESS` or one of the following errors:
@@ -123,4 +130,4 @@ private:
extern HandleTable g_handle_table;
} // namespace Kernel
} // namespace

View File

@@ -7,6 +7,7 @@
#include "common/common_funcs.h"
#include "common/common_types.h"
#include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/domain.h"
#include "core/hle/kernel/handle_table.h"
#include "core/hle/kernel/hle_ipc.h"
#include "core/hle/kernel/kernel.h"
@@ -25,6 +26,10 @@ void SessionRequestHandler::ClientDisconnected(SharedPtr<ServerSession> server_s
boost::range::remove_erase(connected_sessions, server_session);
}
HLERequestContext::HLERequestContext(SharedPtr<Kernel::Domain> domain) : domain(std::move(domain)) {
cmd_buf[0] = 0;
}
HLERequestContext::HLERequestContext(SharedPtr<Kernel::ServerSession> server_session)
: server_session(std::move(server_session)) {
cmd_buf[0] = 0;
@@ -76,13 +81,18 @@ void HLERequestContext::ParseCommandBuffer(u32_le* src_cmdbuf, bool incoming) {
for (unsigned i = 0; i < command_header->num_buf_w_descriptors; ++i) {
buffer_w_desciptors.push_back(rp.PopRaw<IPC::BufferDescriptorABW>());
}
buffer_c_offset = rp.GetCurrentOffset() + command_header->data_size;
if (command_header->buf_c_descriptor_flags !=
IPC::CommandHeader::BufferDescriptorCFlag::Disabled) {
if (command_header->buf_c_descriptor_flags !=
IPC::CommandHeader::BufferDescriptorCFlag::OneDescriptor) {
UNIMPLEMENTED();
}
}
// Padding to align to 16 bytes
rp.AlignWithPadding();
if (Session()->IsDomain() && (command_header->type == IPC::CommandType::Request || !incoming)) {
if (IsDomain() && (command_header->type == IPC::CommandType::Request || !incoming)) {
// If this is an incoming message, only CommandType "Request" has a domain header
// All outgoing domain messages have the domain header
domain_message_header =
@@ -92,45 +102,13 @@ void HLERequestContext::ParseCommandBuffer(u32_le* src_cmdbuf, bool incoming) {
data_payload_header =
std::make_unique<IPC::DataPayloadHeader>(rp.PopRaw<IPC::DataPayloadHeader>());
data_payload_offset = rp.GetCurrentOffset();
if (domain_message_header && domain_message_header->command ==
IPC::DomainMessageHeader::CommandType::CloseVirtualHandle) {
// CloseVirtualHandle command does not have SFC* or any data
return;
}
if (incoming) {
ASSERT(data_payload_header->magic == Common::MakeMagic('S', 'F', 'C', 'I'));
} else {
ASSERT(data_payload_header->magic == Common::MakeMagic('S', 'F', 'C', 'O'));
}
rp.SetCurrentOffset(buffer_c_offset);
// For Inline buffers, the response data is written directly to buffer_c_offset
// and in this case we don't have any BufferDescriptorC on the request.
if (command_header->buf_c_descriptor_flags >
IPC::CommandHeader::BufferDescriptorCFlag::InlineDescriptor) {
if (command_header->buf_c_descriptor_flags ==
IPC::CommandHeader::BufferDescriptorCFlag::OneDescriptor) {
buffer_c_desciptors.push_back(rp.PopRaw<IPC::BufferDescriptorC>());
} else {
unsigned num_buf_c_descriptors =
static_cast<unsigned>(command_header->buf_c_descriptor_flags.Value()) - 2;
// This is used to detect possible underflows, in case something is broken
// with the two ifs above and the flags value is == 0 || == 1.
ASSERT(num_buf_c_descriptors < 14);
for (unsigned i = 0; i < num_buf_c_descriptors; ++i) {
buffer_c_desciptors.push_back(rp.PopRaw<IPC::BufferDescriptorC>());
}
}
}
rp.SetCurrentOffset(data_payload_offset);
data_payload_offset = rp.GetCurrentOffset();
command = rp.Pop<u32_le>();
rp.Skip(1, false); // The command is actually an u64, but we don't use the high part.
}
@@ -195,16 +173,16 @@ ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(u32_le* dst_cmdbuf, P
// TODO(Subv): Translate the X/A/B/W buffers.
if (Session()->IsDomain()) {
if (IsDomain()) {
ASSERT(domain_message_header->num_objects == domain_objects.size());
// Write the domain objects to the command buffer, these go after the raw untranslated data.
// TODO(Subv): This completely ignores C buffers.
size_t domain_offset = size - domain_message_header->num_objects;
auto& request_handlers = server_session->domain_request_handlers;
auto& request_handlers = domain->request_handlers;
for (auto& object : domain_objects) {
request_handlers.emplace_back(object);
dst_cmdbuf[domain_offset++] = static_cast<u32_le>(request_handlers.size());
dst_cmdbuf[domain_offset++] = request_handlers.size();
}
}
return RESULT_SUCCESS;

View File

@@ -86,6 +86,7 @@ protected:
*/
class HLERequestContext {
public:
HLERequestContext(SharedPtr<Kernel::Domain> domain);
HLERequestContext(SharedPtr<Kernel::ServerSession> session);
~HLERequestContext();
@@ -94,11 +95,18 @@ public:
return cmd_buf.data();
}
/**
* Returns the domain through which this request was made.
*/
const SharedPtr<Kernel::Domain>& Domain() const {
return domain;
}
/**
* Returns the session through which this request was made. This can be used as a map key to
* access per-client data on services.
*/
const SharedPtr<Kernel::ServerSession>& Session() const {
const SharedPtr<Kernel::ServerSession>& ServerSession() const {
return server_session;
}
@@ -135,14 +143,14 @@ public:
return buffer_b_desciptors;
}
const std::vector<IPC::BufferDescriptorC>& BufferDescriptorC() const {
return buffer_c_desciptors;
}
const std::unique_ptr<IPC::DomainMessageHeader>& GetDomainMessageHeader() const {
return domain_message_header;
}
bool IsDomain() const {
return domain != nullptr;
}
template <typename T>
SharedPtr<T> GetCopyObject(size_t index) {
ASSERT(index < copy_objects.size());
@@ -175,20 +183,9 @@ public:
domain_objects.clear();
}
size_t NumMoveObjects() const {
return move_objects.size();
}
size_t NumCopyObjects() const {
return copy_objects.size();
}
size_t NumDomainObjects() const {
return domain_objects.size();
}
private:
std::array<u32, IPC::COMMAND_BUFFER_LENGTH> cmd_buf;
SharedPtr<Kernel::Domain> domain;
SharedPtr<Kernel::ServerSession> server_session;
// TODO(yuriks): Check common usage of this and optimize size accordingly
boost::container::small_vector<SharedPtr<Object>, 8> move_objects;
@@ -203,10 +200,8 @@ private:
std::vector<IPC::BufferDescriptorABW> buffer_a_desciptors;
std::vector<IPC::BufferDescriptorABW> buffer_b_desciptors;
std::vector<IPC::BufferDescriptorABW> buffer_w_desciptors;
std::vector<IPC::BufferDescriptorC> buffer_c_desciptors;
unsigned data_payload_offset{};
unsigned buffer_c_offset{};
u32_le command{};
};

View File

@@ -31,6 +31,7 @@ enum class HandleType : u32 {
ServerPort,
ClientSession,
ServerSession,
Domain,
};
enum {
@@ -83,12 +84,27 @@ public:
case HandleType::CodeSet:
case HandleType::ClientPort:
case HandleType::ClientSession:
case HandleType::Domain:
return false;
}
UNREACHABLE();
}
/**
* Check if svcSendSyncRequest can be called on the object
* @return True svcSendSyncRequest can be called on the object, otherwise false
*/
bool IsSyncable() const {
switch (GetHandleType()) {
case HandleType::ClientSession:
case HandleType::Domain:
return true;
}
UNREACHABLE();
}
public:
static unsigned int next_object_id;

View File

@@ -151,4 +151,4 @@ void ResourceLimitsInit() {
void ResourceLimitsShutdown() {}
} // namespace Kernel
} // namespace

View File

@@ -123,4 +123,4 @@ void ResourceLimitsInit();
// Destroys the resource limits
void ResourceLimitsShutdown();
} // namespace Kernel
} // namespace

View File

@@ -50,4 +50,4 @@ std::tuple<SharedPtr<ServerPort>, SharedPtr<ClientPort>> ServerPort::CreatePortP
return std::make_tuple(std::move(server_port), std::move(client_port));
}
} // namespace Kernel
} // namespace

View File

@@ -72,4 +72,4 @@ private:
~ServerPort() override;
};
} // namespace Kernel
} // namespace

View File

@@ -4,7 +4,6 @@
#include <tuple>
#include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/client_port.h"
#include "core/hle/kernel/client_session.h"
#include "core/hle/kernel/handle_table.h"
@@ -62,38 +61,6 @@ ResultCode ServerSession::HandleSyncRequest(SharedPtr<Thread> thread) {
// from its ClientSession, so wake up any threads that may be waiting on a svcReplyAndReceive or
// similar.
Kernel::HLERequestContext context(this);
u32* cmd_buf = (u32*)Memory::GetPointer(thread->GetTLSAddress());
context.PopulateFromIncomingCommandBuffer(cmd_buf, *Kernel::g_current_process,
Kernel::g_handle_table);
// If the session has been converted to a domain, handle the doomain request
if (IsDomain()) {
auto& domain_message_header = context.GetDomainMessageHeader();
if (domain_message_header) {
// If there is a DomainMessageHeader, then this is CommandType "Request"
const u32 object_id{context.GetDomainMessageHeader()->object_id};
switch (domain_message_header->command) {
case IPC::DomainMessageHeader::CommandType::SendMessage:
return domain_request_handlers[object_id - 1]->HandleSyncRequest(context);
case IPC::DomainMessageHeader::CommandType::CloseVirtualHandle: {
LOG_DEBUG(IPC, "CloseVirtualHandle, object_id=0x%08X", object_id);
domain_request_handlers[object_id - 1] = nullptr;
IPC::ResponseBuilder rb{context, 2};
rb.Push(RESULT_SUCCESS);
return RESULT_SUCCESS;
}
}
LOG_CRITICAL(IPC, "Unknown domain command=%d", domain_message_header->command.Value());
ASSERT(false);
}
// If there is no domain header, the regular session handler is used
}
// If this ServerSession has an associated HLE handler, forward the request to it.
ResultCode result{RESULT_SUCCESS};
if (hle_handler != nullptr) {
@@ -102,6 +69,11 @@ ResultCode ServerSession::HandleSyncRequest(SharedPtr<Thread> thread) {
if (translate_result.IsError())
return translate_result;
Kernel::HLERequestContext context(this);
u32* cmd_buf = (u32*)Memory::GetPointer(Kernel::GetCurrentThread()->GetTLSAddress());
context.PopulateFromIncomingCommandBuffer(cmd_buf, *Kernel::g_current_process,
Kernel::g_handle_table);
result = hle_handler->HandleSyncRequest(context);
} else {
// Add the thread to the list of threads that have issued a sync request with this
@@ -112,15 +84,6 @@ ResultCode ServerSession::HandleSyncRequest(SharedPtr<Thread> thread) {
// If this ServerSession does not have an HLE implementation, just wake up the threads waiting
// on it.
WakeupAllWaitingThreads();
// Handle scenario when ConvertToDomain command was issued, as we must do the conversion at the
// end of the command such that only commands following this one are handled as domains
if (convert_to_domain) {
ASSERT_MSG(domain_request_handlers.empty(), "already a domain");
domain_request_handlers = {hle_handler};
convert_to_domain = false;
}
return result;
}

View File

@@ -79,10 +79,7 @@ public:
std::string name; ///< The name of this session (optional)
std::shared_ptr<Session> parent; ///< The parent session, which links to the client endpoint.
std::shared_ptr<SessionRequestHandler>
hle_handler; ///< This session's HLE request handler (applicable when not a domain)
/// This is the list of domain request handlers (after conversion to a domain)
std::vector<std::shared_ptr<SessionRequestHandler>> domain_request_handlers;
hle_handler; ///< This session's HLE request handler (optional)
/// List of threads that are pending a response after a sync request. This list is processed in
/// a LIFO manner, thus, the last request will be dispatched first.
@@ -94,16 +91,6 @@ public:
/// TODO(Subv): Find a better name for this.
SharedPtr<Thread> currently_handling;
/// Returns true if the session has been converted to a domain, otherwise False
bool IsDomain() const {
return !domain_request_handlers.empty();
}
/// Converts the session to a domain at the end of the current command
void ConvertToDomain() {
convert_to_domain = true;
}
private:
ServerSession();
~ServerSession() override;
@@ -115,9 +102,6 @@ private:
* @return The created server session
*/
static ResultVal<SharedPtr<ServerSession>> Create(std::string name = "Unknown");
/// When set to True, converts the session to a domain at the end of the command
bool convert_to_domain{};
};
/**
@@ -129,4 +113,4 @@ private:
* in the command buffer.
*/
ResultCode TranslateHLERequest(ServerSession* server_session);
} // namespace Kernel
}

View File

@@ -9,4 +9,4 @@ namespace Kernel {
Session::Session() {}
Session::~Session() {}
} // namespace Kernel
}

View File

@@ -24,4 +24,4 @@ public:
ServerSession* server = nullptr; ///< The server endpoint of the session.
SharedPtr<ClientPort> port; ///< The port that this session is associated with (optional).
};
} // namespace Kernel
}

View File

@@ -14,7 +14,7 @@ namespace Kernel {
SharedMemory::SharedMemory() {}
SharedMemory::~SharedMemory() {}
SharedPtr<SharedMemory> SharedMemory::Create(SharedPtr<Process> owner_process, u64 size,
SharedPtr<SharedMemory> SharedMemory::Create(SharedPtr<Process> owner_process, u32 size,
MemoryPermission permissions,
MemoryPermission other_permissions, VAddr address,
MemoryRegion region, std::string name) {
@@ -136,8 +136,7 @@ ResultCode SharedMemory::Map(Process* target_process, VAddr address, MemoryPermi
// can not map it in its own address space unless it was created with addr=0, result 0xD900182C.
if (address != 0) {
// TODO(shinyquagsire23): Check for virtual/mappable memory here too?
if (address >= Memory::HEAP_VADDR && address < Memory::HEAP_VADDR_END) {
if (address < Memory::HEAP_VADDR) {
LOG_ERROR(Kernel, "cannot map id=%u, address=0x%llx name=%s, invalid address",
GetObjectId(), address, name.c_str());
return ERR_INVALID_ADDRESS;

View File

@@ -39,7 +39,7 @@ public:
* linear heap.
* @param name Optional object name, used for debugging purposes.
*/
static SharedPtr<SharedMemory> Create(SharedPtr<Process> owner_process, u64 size,
static SharedPtr<SharedMemory> Create(SharedPtr<Process> owner_process, u32 size,
MemoryPermission permissions,
MemoryPermission other_permissions, VAddr address = 0,
MemoryRegion region = MemoryRegion::BASE,
@@ -98,10 +98,10 @@ public:
ResultCode Unmap(Process* target_process, VAddr address);
/**
* Gets a pointer to the shared memory block
* @param offset Offset from the start of the shared memory block to get pointer
* @return Pointer to the shared memory block from the specified offset
*/
* Gets a pointer to the shared memory block
* @param offset Offset from the start of the shared memory block to get pointer
* @return Pointer to the shared memory block from the specified offset
*/
u8* GetPointer(u32 offset = 0);
/// Process that created this shared memory block.
@@ -116,7 +116,7 @@ public:
/// Offset into the backing block for this shared memory.
size_t backing_block_offset;
/// Size of the memory block. Page-aligned.
u64 size;
u32 size;
/// Permission restrictions applied to the process which created the block.
MemoryPermission permissions;
/// Permission restrictions applied to other processes mapping the block.
@@ -129,4 +129,4 @@ private:
~SharedMemory() override;
};
} // namespace Kernel
} // namespace

View File

@@ -20,6 +20,7 @@
#include "core/hle/kernel/shared_memory.h"
#include "core/hle/kernel/svc.h"
#include "core/hle/kernel/svc_wrap.h"
#include "core/hle/kernel/sync_object.h"
#include "core/hle/kernel/thread.h"
#include "core/hle/lock.h"
#include "core/hle/result.h"
@@ -56,7 +57,7 @@ static ResultCode UnmapMemory(VAddr dst_addr, VAddr src_addr, u64 size) {
}
/// Connect to an OS service given the port name, returns the handle to the port to out
static ResultCode ConnectToNamedPort(Handle* out_handle, VAddr port_name_address) {
static ResultCode ConnectToPort(Handle* out_handle, VAddr port_name_address) {
if (!Memory::IsValidVirtualAddress(port_name_address))
return ERR_NOT_FOUND;
@@ -86,7 +87,7 @@ static ResultCode ConnectToNamedPort(Handle* out_handle, VAddr port_name_address
/// Makes a blocking IPC call to an OS service.
static ResultCode SendSyncRequest(Handle handle) {
SharedPtr<ClientSession> session = g_handle_table.Get<ClientSession>(handle);
SharedPtr<SyncObject> session = g_handle_table.Get<SyncObject>(handle);
if (!session) {
LOG_ERROR(Kernel_SVC, "called with invalid handle=0x%08X", handle);
return ERR_INVALID_HANDLE;
@@ -252,18 +253,16 @@ static ResultCode CancelSynchronization(Handle thread_handle) {
}
/// Attempts to locks a mutex, creating it if it does not already exist
static ResultCode ArbitrateLock(Handle holding_thread_handle, VAddr mutex_addr,
Handle requesting_thread_handle) {
LOG_TRACE(Kernel_SVC,
"called holding_thread_handle=0x%08X, mutex_addr=0x%llx, "
"requesting_current_thread_handle=0x%08X",
static ResultCode LockMutex(Handle holding_thread_handle, VAddr mutex_addr,
Handle requesting_thread_handle) {
LOG_TRACE(Kernel_SVC, "called holding_thread_handle=0x%08X, mutex_addr=0x%llx, "
"requesting_current_thread_handle=0x%08X",
holding_thread_handle, mutex_addr, requesting_thread_handle);
SharedPtr<Thread> holding_thread = g_handle_table.Get<Thread>(holding_thread_handle);
SharedPtr<Thread> requesting_thread = g_handle_table.Get<Thread>(requesting_thread_handle);
ASSERT(requesting_thread);
ASSERT(requesting_thread == GetCurrentThread());
SharedPtr<Mutex> mutex = g_object_address_table.Get<Mutex>(mutex_addr);
if (!mutex) {
@@ -278,7 +277,7 @@ static ResultCode ArbitrateLock(Handle holding_thread_handle, VAddr mutex_addr,
}
/// Unlock a mutex
static ResultCode ArbitrateUnlock(VAddr mutex_addr) {
static ResultCode UnlockMutex(VAddr mutex_addr) {
LOG_TRACE(Kernel_SVC, "called mutex_addr=0x%llx", mutex_addr);
SharedPtr<Mutex> mutex = g_object_address_table.Get<Mutex>(mutex_addr);
@@ -315,7 +314,7 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id)
*result = g_current_process->allowed_thread_priority_mask;
break;
case GetInfoType::MapRegionBaseAddr:
*result = vm_manager.GetMapRegionBaseAddr();
*result = vm_manager.GetAddressSpaceBaseAddr();
break;
case GetInfoType::MapRegionSize:
*result = vm_manager.GetAddressSpaceSize();
@@ -332,9 +331,6 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id)
case GetInfoType::TotalHeapUsage:
*result = vm_manager.GetTotalHeapUsage();
break;
case GetInfoType::IsCurrentProcessBeingDebugged:
*result = 0;
break;
case GetInfoType::RandomEntropy:
*result = 0;
break;
@@ -419,7 +415,8 @@ static ResultCode MapSharedMemory(Handle shared_memory_handle, VAddr addr, u64 s
"called, shared_memory_handle=0x%08X, addr=0x%llx, size=0x%llx, permissions=0x%08X",
shared_memory_handle, addr, size, permissions);
SharedPtr<SharedMemory> shared_memory = g_handle_table.Get<SharedMemory>(shared_memory_handle);
SharedPtr<SharedMemory> shared_memory =
Kernel::g_handle_table.Get<SharedMemory>(shared_memory_handle);
if (!shared_memory) {
return ERR_INVALID_HANDLE;
}
@@ -434,7 +431,7 @@ static ResultCode MapSharedMemory(Handle shared_memory_handle, VAddr addr, u64 s
case MemoryPermission::WriteExecute:
case MemoryPermission::ReadWriteExecute:
case MemoryPermission::DontCare:
return shared_memory->Map(g_current_process.get(), addr, permissions_type,
return shared_memory->Map(Kernel::g_current_process.get(), addr, permissions_type,
MemoryPermission::DontCare);
default:
LOG_ERROR(Kernel_SVC, "unknown permissions=0x%08X", permissions);
@@ -549,9 +546,8 @@ static ResultCode CreateThread(Handle* out_handle, VAddr entry_point, u64 arg, V
Core::System::GetInstance().PrepareReschedule();
LOG_TRACE(Kernel_SVC,
"called entrypoint=0x%08X (%s), arg=0x%08X, stacktop=0x%08X, "
"threadpriority=0x%08X, processorid=0x%08X : created handle=0x%08X",
LOG_TRACE(Kernel_SVC, "called entrypoint=0x%08X (%s), arg=0x%08X, stacktop=0x%08X, "
"threadpriority=0x%08X, processorid=0x%08X : created handle=0x%08X",
entry_point, name.c_str(), arg, stack_top, priority, processor_id, *out_handle);
return RESULT_SUCCESS;
@@ -615,29 +611,20 @@ static ResultCode WaitProcessWideKeyAtomic(VAddr mutex_addr, VAddr condition_var
mutex->name = Common::StringFromFormat("mutex-%llx", mutex_addr);
}
ASSERT(mutex->GetOwnerHandle() == thread_handle);
SharedPtr<ConditionVariable> condition_variable =
g_object_address_table.Get<ConditionVariable>(condition_variable_addr);
if (!condition_variable) {
// Create a new condition_variable for the specified address if one does not already exist
condition_variable = ConditionVariable::Create(condition_variable_addr).Unwrap();
condition_variable =
ConditionVariable::Create(condition_variable_addr, mutex_addr).Unwrap();
condition_variable->name =
Common::StringFromFormat("condition-variable-%llx", condition_variable_addr);
}
if (condition_variable->mutex_addr) {
// Previously created the ConditionVariable using WaitProcessWideKeyAtomic, verify
// everything is correct
ASSERT(condition_variable->mutex_addr == mutex_addr);
} else {
// Previously created the ConditionVariable using SignalProcessWideKey, set the mutex
// associated with it
condition_variable->mutex_addr = mutex_addr;
}
if (mutex->GetOwnerHandle()) {
// Release the mutex if the current thread is holding it
mutex->Release(thread.get());
}
ASSERT(condition_variable->GetAvailableCount() == 0);
ASSERT(condition_variable->mutex_addr == mutex_addr);
auto wakeup_callback = [mutex, nano_seconds](ThreadWakeupReason reason,
SharedPtr<Thread> thread,
@@ -679,6 +666,8 @@ static ResultCode WaitProcessWideKeyAtomic(VAddr mutex_addr, VAddr condition_var
CASCADE_CODE(
WaitSynchronization1(condition_variable, thread.get(), nano_seconds, wakeup_callback));
mutex->Release(thread.get());
return RESULT_SUCCESS;
}
@@ -748,19 +737,6 @@ static ResultCode SetThreadCoreMask(u64, u64, u64) {
return RESULT_SUCCESS;
}
static ResultCode CreateSharedMemory(Handle* handle, u64 size, u32 local_permissions,
u32 remote_permissions) {
LOG_TRACE(Kernel_SVC, "called, size=0x%llx, localPerms=0x%08x, remotePerms=0x%08x", size,
local_permissions, remote_permissions);
auto sharedMemHandle =
SharedMemory::Create(g_handle_table.Get<Process>(KernelHandle::CurrentProcess), size,
static_cast<MemoryPermission>(local_permissions),
static_cast<MemoryPermission>(remote_permissions));
CASCADE_RESULT(*handle, g_handle_table.Create(sharedMemHandle));
return RESULT_SUCCESS;
}
namespace {
struct FunctionDef {
using Func = void();
@@ -798,12 +774,12 @@ static const FunctionDef SVC_Table[] = {
{0x17, SvcWrap<ResetSignal>, "ResetSignal"},
{0x18, SvcWrap<WaitSynchronization>, "WaitSynchronization"},
{0x19, SvcWrap<CancelSynchronization>, "CancelSynchronization"},
{0x1A, SvcWrap<ArbitrateLock>, "ArbitrateLock"},
{0x1B, SvcWrap<ArbitrateUnlock>, "ArbitrateUnlock"},
{0x1A, SvcWrap<LockMutex>, "LockMutex"},
{0x1B, SvcWrap<UnlockMutex>, "UnlockMutex"},
{0x1C, SvcWrap<WaitProcessWideKeyAtomic>, "WaitProcessWideKeyAtomic"},
{0x1D, SvcWrap<SignalProcessWideKey>, "SignalProcessWideKey"},
{0x1E, SvcWrap<GetSystemTick>, "GetSystemTick"},
{0x1F, SvcWrap<ConnectToNamedPort>, "ConnectToNamedPort"},
{0x1F, SvcWrap<ConnectToPort>, "ConnectToPort"},
{0x20, nullptr, "SendSyncRequestLight"},
{0x21, SvcWrap<SendSyncRequest>, "SendSyncRequest"},
{0x22, nullptr, "SendSyncRequestWithUserBuffer"},
@@ -847,12 +823,12 @@ static const FunctionDef SVC_Table[] = {
{0x48, nullptr, "Unknown"},
{0x49, nullptr, "Unknown"},
{0x4A, nullptr, "Unknown"},
{0x4B, nullptr, "CreateJitMemory"},
{0x4C, nullptr, "MapJitMemory"},
{0x4B, nullptr, "Unknown"},
{0x4C, nullptr, "Unknown"},
{0x4D, nullptr, "SleepSystem"},
{0x4E, nullptr, "ReadWriteRegister"},
{0x4F, nullptr, "SetProcessActivity"},
{0x50, SvcWrap<CreateSharedMemory>, "CreateSharedMemory"},
{0x50, nullptr, "CreateSharedMemory"},
{0x51, nullptr, "MapTransferMemory"},
{0x52, nullptr, "UnmapTransferMemory"},
{0x53, nullptr, "CreateInterruptEvent"},

View File

@@ -14,11 +14,7 @@ struct MemoryInfo {
u32 type;
u32 attributes;
u32 permission;
u32 device_refcount;
u32 ipc_refcount;
INSERT_PADDING_WORDS(1);
};
static_assert(sizeof(MemoryInfo) == 0x28, "MemoryInfo has incorrect size.");
struct PageInfo {
u64 flags;

View File

@@ -145,15 +145,6 @@ void SvcWrap() {
FuncReturn(retval);
}
template <ResultCode func(Handle*, u64, u32, u32)>
void SvcWrap() {
u32 param_1 = 0;
u32 retval =
func(&param_1, PARAM(1), (u32)(PARAM(2) & 0xFFFFFFFF), (u32)(PARAM(3) & 0xFFFFFFFF)).raw;
Core::CPU().SetReg(1, param_1);
FuncReturn(retval);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
// Function wrappers that return type u32

View File

@@ -0,0 +1,35 @@
// Copyright 2018 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <boost/smart_ptr/intrusive_ptr.hpp>
#include "core/hle/kernel/kernel.h"
#include "core/hle/result.h"
namespace Kernel {
class Thread;
/// Class that represents a Kernel object that svcSendSyncRequest can be called on
class SyncObject : public Object {
public:
/**
* Handle a sync request from the emulated application.
* @param thread Thread that initiated the request.
* @returns ResultCode from the operation.
*/
virtual ResultCode SendSyncRequest(SharedPtr<Thread> thread) = 0;
};
// Specialization of DynamicObjectCast for SyncObjects
template <>
inline SharedPtr<SyncObject> DynamicObjectCast<SyncObject>(SharedPtr<Object> object) {
if (object != nullptr && object->IsSyncable()) {
return boost::static_pointer_cast<SyncObject>(std::move(object));
}
return nullptr;
}
} // namespace Kernel

View File

@@ -111,4 +111,4 @@ void TimersInit() {
void TimersShutdown() {}
} // namespace Kernel
} // namespace

View File

@@ -76,4 +76,4 @@ void TimersInit();
/// Tears down the timer variables
void TimersShutdown();
} // namespace Kernel
} // namespace

View File

@@ -10,8 +10,8 @@
#include "core/hle/kernel/errors.h"
#include "core/hle/kernel/vm_manager.h"
#include "core/memory.h"
#include "core/memory_hook.h"
#include "core/memory_setup.h"
#include "core/mmio.h"
namespace Kernel {
@@ -60,8 +60,8 @@ void VMManager::Reset() {
vma_map.emplace(initial_vma.base, initial_vma);
page_table.pointers.fill(nullptr);
page_table.special_regions.clear();
page_table.attributes.fill(Memory::PageType::Unmapped);
page_table.cached_res_count.fill(0);
UpdatePageTableForVMA(initial_vma);
}
@@ -121,7 +121,7 @@ ResultVal<VMManager::VMAHandle> VMManager::MapBackingMemory(VAddr target, u8* me
ResultVal<VMManager::VMAHandle> VMManager::MapMMIO(VAddr target, PAddr paddr, u64 size,
MemoryState state,
Memory::MemoryHookPointer mmio_handler) {
Memory::MMIORegionPointer mmio_handler) {
// This is the appropriately sized VMA that will turn into our allocation.
CASCADE_RESULT(VMAIter vma_handle, CarveVMA(target, size));
VirtualMemoryArea& final_vma = vma_handle->second;
@@ -375,11 +375,6 @@ u64 VMManager::GetAddressSpaceSize() {
return MAX_ADDRESS;
}
VAddr VMManager::GetMapRegionBaseAddr() {
LOG_WARNING(Kernel, "(STUBBED) called");
return Memory::HEAP_VADDR;
}
VAddr VMManager::GetNewMapRegionBaseAddr() {
LOG_WARNING(Kernel, "(STUBBED) called");
return 0x8000000;

View File

@@ -10,7 +10,7 @@
#include "common/common_types.h"
#include "core/hle/result.h"
#include "core/memory.h"
#include "core/memory_hook.h"
#include "core/mmio.h"
namespace Kernel {
@@ -81,7 +81,7 @@ struct VirtualMemoryArea {
// Settings for type = MMIO
/// Physical address of the register area this VMA maps to.
PAddr paddr = 0;
Memory::MemoryHookPointer mmio_handler = nullptr;
Memory::MMIORegionPointer mmio_handler = nullptr;
/// Tests if this area can be merged to the right with `next`.
bool CanBeMergedWith(const VirtualMemoryArea& next) const;
@@ -160,7 +160,7 @@ public:
* @param mmio_handler The handler that will implement read and write for this MMIO region.
*/
ResultVal<VMAHandle> MapMMIO(VAddr target, PAddr paddr, u64 size, MemoryState state,
Memory::MemoryHookPointer mmio_handler);
Memory::MMIORegionPointer mmio_handler);
/// Unmaps a range of addresses, splitting VMAs as necessary.
ResultCode UnmapRange(VAddr target, u64 size);
@@ -192,9 +192,6 @@ public:
/// Gets the total address space address size, used by svcGetInfo
u64 GetAddressSpaceSize();
/// Gets the map region base address, used by svcGetInfo
VAddr GetMapRegionBaseAddr();
/// Gets the base address for a new memory region, used by svcGetInfo
VAddr GetNewMapRegionBaseAddr();

View File

@@ -19,8 +19,6 @@
enum class ErrorDescription : u32 {
Success = 0,
RemoteProcessDead = 301,
InvalidOffset = 6061,
InvalidLength = 6062,
};
/**

View File

@@ -9,93 +9,15 @@
namespace Service {
namespace Account {
class IProfile final : public ServiceFramework<IProfile> {
public:
IProfile() : ServiceFramework("IProfile") {
static const FunctionInfo functions[] = {
{1, &IProfile::GetBase, "GetBase"},
};
RegisterHandlers(functions);
}
private:
void GetBase(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_ACC, "(STUBBED) called");
ProfileBase profile_base{};
IPC::ResponseBuilder rb{ctx, 16};
rb.Push(RESULT_SUCCESS);
rb.PushRaw(profile_base);
}
};
class IManagerForApplication final : public ServiceFramework<IManagerForApplication> {
public:
IManagerForApplication() : ServiceFramework("IManagerForApplication") {
static const FunctionInfo functions[] = {
{0, &IManagerForApplication::CheckAvailability, "CheckAvailability"},
{1, &IManagerForApplication::GetAccountId, "GetAccountId"},
};
RegisterHandlers(functions);
}
private:
void CheckAvailability(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_ACC, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
rb.Push(true); // TODO: Check when this is supposed to return true and when not
}
void GetAccountId(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_ACC, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(RESULT_SUCCESS);
rb.Push<u64>(0x12345678ABCDEF);
}
};
void ACC_U0::GetUserExistence(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_ACC, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
rb.Push(true); // TODO: Check when this is supposed to return true and when not
}
void ACC_U0::GetProfile(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IProfile>();
LOG_DEBUG(Service_ACC, "called");
}
void ACC_U0::InitializeApplicationInfo(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_ACC, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
LOG_WARNING(Service, "(STUBBED) called");
IPC::RequestBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
}
void ACC_U0::GetBaasAccountManagerForApplication(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IManagerForApplication>();
LOG_DEBUG(Service_ACC, "called");
}
void ACC_U0::GetLastOpenedUser(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_ACC, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 6};
rb.Push(RESULT_SUCCESS);
rb.Push<u64>(0x0);
rb.Push<u64>(0x0);
}
ACC_U0::ACC_U0() : ServiceFramework("acc:u0") {
static const FunctionInfo functions[] = {
{1, &ACC_U0::GetUserExistence, "GetUserExistence"},
{4, &ACC_U0::GetLastOpenedUser, "GetLastOpenedUser"},
{5, &ACC_U0::GetProfile, "GetProfile"},
{100, &ACC_U0::InitializeApplicationInfo, "InitializeApplicationInfo"},
{101, &ACC_U0::GetBaasAccountManagerForApplication, "GetBaasAccountManagerForApplication"},
};
RegisterHandlers(functions);
}

View File

@@ -9,29 +9,13 @@
namespace Service {
namespace Account {
// TODO: RE this structure
struct UserData {
INSERT_PADDING_BYTES(0x80);
};
static_assert(sizeof(UserData) == 0x80, "UserData structure has incorrect size");
// TODO: RE this structure
struct ProfileBase {
INSERT_PADDING_BYTES(0x38);
};
static_assert(sizeof(ProfileBase) == 0x38, "ProfileBase structure has incorrect size");
class ACC_U0 final : public ServiceFramework<ACC_U0> {
public:
ACC_U0();
~ACC_U0() = default;
private:
void GetUserExistence(Kernel::HLERequestContext& ctx);
void GetLastOpenedUser(Kernel::HLERequestContext& ctx);
void GetProfile(Kernel::HLERequestContext& ctx);
void InitializeApplicationInfo(Kernel::HLERequestContext& ctx);
void GetBaasAccountManagerForApplication(Kernel::HLERequestContext& ctx);
};
} // namespace Account

View File

@@ -2,348 +2,14 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/event.h"
#include "core/hle/service/am/am.h"
#include "core/hle/service/am/applet_ae.h"
#include "core/hle/service/am/applet_oe.h"
#include "core/hle/service/apm/apm.h"
#include "core/hle/service/nvflinger/nvflinger.h"
namespace Service {
namespace AM {
IWindowController::IWindowController() : ServiceFramework("IWindowController") {
static const FunctionInfo functions[] = {
{1, &IWindowController::GetAppletResourceUserId, "GetAppletResourceUserId"},
{10, &IWindowController::AcquireForegroundRights, "AcquireForegroundRights"},
};
RegisterHandlers(functions);
}
void IWindowController::GetAppletResourceUserId(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(RESULT_SUCCESS);
rb.Push<u64>(0);
}
void IWindowController::AcquireForegroundRights(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
}
IAudioController::IAudioController() : ServiceFramework("IAudioController") {}
IDisplayController::IDisplayController() : ServiceFramework("IDisplayController") {}
IDebugFunctions::IDebugFunctions() : ServiceFramework("IDebugFunctions") {}
ISelfController::ISelfController(std::shared_ptr<NVFlinger::NVFlinger> nvflinger)
: ServiceFramework("ISelfController"), nvflinger(std::move(nvflinger)) {
static const FunctionInfo functions[] = {
{1, &ISelfController::LockExit, "LockExit"},
{2, &ISelfController::UnlockExit, "UnlockExit"},
{11, &ISelfController::SetOperationModeChangedNotification,
"SetOperationModeChangedNotification"},
{12, &ISelfController::SetPerformanceModeChangedNotification,
"SetPerformanceModeChangedNotification"},
{13, &ISelfController::SetFocusHandlingMode, "SetFocusHandlingMode"},
{14, &ISelfController::SetRestartMessageEnabled, "SetRestartMessageEnabled"},
{16, &ISelfController::SetOutOfFocusSuspendingEnabled, "SetOutOfFocusSuspendingEnabled"},
{40, &ISelfController::CreateManagedDisplayLayer, "CreateManagedDisplayLayer"},
};
RegisterHandlers(functions);
}
void ISelfController::SetFocusHandlingMode(Kernel::HLERequestContext& ctx) {
// Takes 3 input u8s with each field located immediately after the previous u8, these are
// bool flags. No output.
IPC::RequestParser rp{ctx};
struct FocusHandlingModeParams {
u8 unknown0;
u8 unknown1;
u8 unknown2;
};
auto flags = rp.PopRaw<FocusHandlingModeParams>();
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
LOG_WARNING(Service_AM, "(STUBBED) called");
}
void ISelfController::SetRestartMessageEnabled(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
LOG_WARNING(Service_AM, "(STUBBED) called");
}
void ISelfController::SetPerformanceModeChangedNotification(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
bool flag = rp.Pop<bool>();
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
LOG_WARNING(Service_AM, "(STUBBED) called flag=%u", static_cast<u32>(flag));
}
void ISelfController::SetOperationModeChangedNotification(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
bool flag = rp.Pop<bool>();
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
LOG_WARNING(Service_AM, "(STUBBED) called flag=%u", static_cast<u32>(flag));
}
void ISelfController::SetOutOfFocusSuspendingEnabled(Kernel::HLERequestContext& ctx) {
// Takes 3 input u8s with each field located immediately after the previous u8, these are
// bool flags. No output.
IPC::RequestParser rp{ctx};
bool enabled = rp.Pop<bool>();
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
LOG_WARNING(Service_AM, "(STUBBED) called enabled=%u", static_cast<u32>(enabled));
}
void ISelfController::LockExit(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
LOG_WARNING(Service_AM, "(STUBBED) called");
}
void ISelfController::UnlockExit(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
LOG_WARNING(Service_AM, "(STUBBED) called");
}
void ISelfController::CreateManagedDisplayLayer(Kernel::HLERequestContext& ctx) {
// TODO(Subv): Find out how AM determines the display to use, for now just create the layer
// in the Default display.
u64 display_id = nvflinger->OpenDisplay("Default");
u64 layer_id = nvflinger->CreateLayer(display_id);
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(RESULT_SUCCESS);
rb.Push(layer_id);
LOG_WARNING(Service_AM, "(STUBBED) called");
}
ICommonStateGetter::ICommonStateGetter() : ServiceFramework("ICommonStateGetter") {
static const FunctionInfo functions[] = {
{0, &ICommonStateGetter::GetEventHandle, "GetEventHandle"},
{1, &ICommonStateGetter::ReceiveMessage, "ReceiveMessage"},
{5, &ICommonStateGetter::GetOperationMode, "GetOperationMode"},
{6, &ICommonStateGetter::GetPerformanceMode, "GetPerformanceMode"},
{9, &ICommonStateGetter::GetCurrentFocusState, "GetCurrentFocusState"},
};
RegisterHandlers(functions);
event = Kernel::Event::Create(Kernel::ResetType::OneShot, "ICommonStateGetter:Event");
}
void ICommonStateGetter::GetEventHandle(Kernel::HLERequestContext& ctx) {
event->Signal();
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(RESULT_SUCCESS);
rb.PushCopyObjects(event);
LOG_WARNING(Service_AM, "(STUBBED) called");
}
void ICommonStateGetter::ReceiveMessage(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
rb.Push<u32>(15);
LOG_WARNING(Service_AM, "(STUBBED) called");
}
void ICommonStateGetter::GetCurrentFocusState(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
rb.Push(static_cast<u8>(FocusState::InFocus));
LOG_WARNING(Service_AM, "(STUBBED) called");
}
void ICommonStateGetter::GetOperationMode(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
rb.Push(static_cast<u8>(OperationMode::Handheld));
LOG_WARNING(Service_AM, "(STUBBED) called");
}
void ICommonStateGetter::GetPerformanceMode(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
rb.Push(static_cast<u32>(APM::PerformanceMode::Handheld));
LOG_WARNING(Service_AM, "(STUBBED) called");
}
ILibraryAppletCreator::ILibraryAppletCreator() : ServiceFramework("ILibraryAppletCreator") {}
class IStorageAccessor final : public ServiceFramework<IStorageAccessor> {
public:
explicit IStorageAccessor(std::vector<u8> buffer)
: ServiceFramework("IStorageAccessor"), buffer(std::move(buffer)) {
static const FunctionInfo functions[] = {
{0, &IStorageAccessor::GetSize, "GetSize"},
{11, &IStorageAccessor::Read, "Read"},
};
RegisterHandlers(functions);
}
private:
std::vector<u8> buffer;
void GetSize(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(RESULT_SUCCESS);
rb.Push(static_cast<u64>(buffer.size()));
LOG_DEBUG(Service_AM, "called");
}
void Read(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
u64 offset = rp.Pop<u64>();
const auto& output_buffer = ctx.BufferDescriptorC()[0];
ASSERT(offset + output_buffer.Size() <= buffer.size());
Memory::WriteBlock(output_buffer.Address(), buffer.data() + offset, output_buffer.Size());
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
LOG_DEBUG(Service_AM, "called");
}
};
class IStorage final : public ServiceFramework<IStorage> {
public:
explicit IStorage(std::vector<u8> buffer)
: ServiceFramework("IStorage"), buffer(std::move(buffer)) {
static const FunctionInfo functions[] = {
{0, &IStorage::Open, "Open"},
};
RegisterHandlers(functions);
}
private:
std::vector<u8> buffer;
void Open(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<AM::IStorageAccessor>(buffer);
LOG_DEBUG(Service_AM, "called");
}
};
IApplicationFunctions::IApplicationFunctions() : ServiceFramework("IApplicationFunctions") {
static const FunctionInfo functions[] = {
{1, &IApplicationFunctions::PopLaunchParameter, "PopLaunchParameter"},
{21, &IApplicationFunctions::GetDesiredLanguage, "GetDesiredLanguage"},
{22, &IApplicationFunctions::SetTerminateResult, "SetTerminateResult"},
{66, &IApplicationFunctions::InitializeGamePlayRecording, "InitializeGamePlayRecording"},
{67, &IApplicationFunctions::SetGamePlayRecordingState, "SetGamePlayRecordingState"},
{40, &IApplicationFunctions::NotifyRunning, "NotifyRunning"},
};
RegisterHandlers(functions);
}
void IApplicationFunctions::PopLaunchParameter(Kernel::HLERequestContext& ctx) {
constexpr u8 data[0x88] = {
0xca, 0x97, 0x94, 0xc7, // Magic
1, 0, 0, 0, // IsAccountSelected (bool)
1, 0, 0, 0, // User Id (word 0)
0, 0, 0, 0, // User Id (word 1)
0, 0, 0, 0, // User Id (word 2)
0, 0, 0, 0 // User Id (word 3)
};
std::vector<u8> buffer(data, data + sizeof(data));
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<AM::IStorage>(buffer);
LOG_DEBUG(Service_AM, "called");
}
void IApplicationFunctions::SetTerminateResult(Kernel::HLERequestContext& ctx) {
// Takes an input u32 Result, no output.
// For example, in some cases official apps use this with error 0x2A2 then uses svcBreak.
IPC::RequestParser rp{ctx};
u32 result = rp.Pop<u32>();
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
LOG_WARNING(Service_AM, "(STUBBED) called, result=0x%08X", result);
}
void IApplicationFunctions::GetDesiredLanguage(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(RESULT_SUCCESS);
rb.Push<u64>(SystemLanguage::English);
LOG_WARNING(Service_AM, "(STUBBED) called");
}
void IApplicationFunctions::InitializeGamePlayRecording(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
LOG_WARNING(Service_AM, "(STUBBED) called");
}
void IApplicationFunctions::SetGamePlayRecordingState(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
LOG_WARNING(Service_AM, "(STUBBED) called");
}
void IApplicationFunctions::NotifyRunning(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
rb.Push<u8>(0); // Unknown, seems to be ignored by official processes
LOG_WARNING(Service_AM, "(STUBBED) called");
}
void InstallInterfaces(SM::ServiceManager& service_manager,
std::shared_ptr<NVFlinger::NVFlinger> nvflinger) {
std::make_shared<AppletAE>(nvflinger)->InstallAsService(service_manager);
std::make_shared<AppletOE>(nvflinger)->InstallAsService(service_manager);
void InstallInterfaces(SM::ServiceManager& service_manager) {
std::make_shared<AppletOE>()->InstallAsService(service_manager);
}
} // namespace AM

View File

@@ -4,112 +4,13 @@
#pragma once
#include <memory>
#include "core/hle/service/service.h"
namespace Kernel {
class Event;
}
namespace Service {
namespace NVFlinger {
class NVFlinger;
}
namespace AM {
// TODO: Add more languages
enum SystemLanguage {
Japanese = 0,
English = 1,
};
class IWindowController final : public ServiceFramework<IWindowController> {
public:
IWindowController();
private:
void GetAppletResourceUserId(Kernel::HLERequestContext& ctx);
void AcquireForegroundRights(Kernel::HLERequestContext& ctx);
};
class IAudioController final : public ServiceFramework<IAudioController> {
public:
IAudioController();
};
class IDisplayController final : public ServiceFramework<IDisplayController> {
public:
IDisplayController();
};
class IDebugFunctions final : public ServiceFramework<IDebugFunctions> {
public:
IDebugFunctions();
};
class ISelfController final : public ServiceFramework<ISelfController> {
public:
ISelfController(std::shared_ptr<NVFlinger::NVFlinger> nvflinger);
private:
void SetFocusHandlingMode(Kernel::HLERequestContext& ctx);
void SetRestartMessageEnabled(Kernel::HLERequestContext& ctx);
void SetPerformanceModeChangedNotification(Kernel::HLERequestContext& ctx);
void SetOperationModeChangedNotification(Kernel::HLERequestContext& ctx);
void SetOutOfFocusSuspendingEnabled(Kernel::HLERequestContext& ctx);
void LockExit(Kernel::HLERequestContext& ctx);
void UnlockExit(Kernel::HLERequestContext& ctx);
void CreateManagedDisplayLayer(Kernel::HLERequestContext& ctx);
std::shared_ptr<NVFlinger::NVFlinger> nvflinger;
};
class ICommonStateGetter final : public ServiceFramework<ICommonStateGetter> {
public:
ICommonStateGetter();
private:
enum class FocusState : u8 {
InFocus = 1,
NotInFocus = 2,
};
enum class OperationMode : u8 {
Handheld = 0,
Docked = 1,
};
void GetEventHandle(Kernel::HLERequestContext& ctx);
void ReceiveMessage(Kernel::HLERequestContext& ctx);
void GetCurrentFocusState(Kernel::HLERequestContext& ctx);
void GetOperationMode(Kernel::HLERequestContext& ctx);
void GetPerformanceMode(Kernel::HLERequestContext& ctx);
Kernel::SharedPtr<Kernel::Event> event;
};
class ILibraryAppletCreator final : public ServiceFramework<ILibraryAppletCreator> {
public:
ILibraryAppletCreator();
};
class IApplicationFunctions final : public ServiceFramework<IApplicationFunctions> {
public:
IApplicationFunctions();
private:
void PopLaunchParameter(Kernel::HLERequestContext& ctx);
void SetTerminateResult(Kernel::HLERequestContext& ctx);
void GetDesiredLanguage(Kernel::HLERequestContext& ctx);
void InitializeGamePlayRecording(Kernel::HLERequestContext& ctx);
void SetGamePlayRecordingState(Kernel::HLERequestContext& ctx);
void NotifyRunning(Kernel::HLERequestContext& ctx);
};
/// Registers all AM services with the specified service manager.
void InstallInterfaces(SM::ServiceManager& service_manager,
std::shared_ptr<NVFlinger::NVFlinger> nvflinger);
void InstallInterfaces(SM::ServiceManager& service_manager);
} // namespace AM
} // namespace Service

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