Compare commits
151 Commits
__refs_pul
...
__refs_pul
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b117ca5fce | ||
|
|
f14328bf0a | ||
|
|
c2fee0e519 | ||
|
|
06ece52cfe | ||
|
|
8aaf418bd6 | ||
|
|
3c1ce290d0 | ||
|
|
6b18a1592f | ||
|
|
21a4e7deea | ||
|
|
52ad5fa0e8 | ||
|
|
d9b1c24f4f | ||
|
|
80162888e6 | ||
|
|
021cd56bc9 | ||
|
|
36a1e6a982 | ||
|
|
abae7577d2 | ||
|
|
a6a82bb004 | ||
|
|
e779686a76 | ||
|
|
945e39471d | ||
|
|
7a7ffa602d | ||
|
|
04d265562f | ||
|
|
ddcb711ee8 | ||
|
|
864280fabc | ||
|
|
7d1c0fd1ad | ||
|
|
fddafa14c8 | ||
|
|
54c7e8e40e | ||
|
|
e3402d976d | ||
|
|
20be92d5e6 | ||
|
|
89b8801a97 | ||
|
|
00207cc965 | ||
|
|
e86b26cd2b | ||
|
|
41890a84be | ||
|
|
23d3cd7604 | ||
|
|
d6cddffb78 | ||
|
|
520e4e5d4b | ||
|
|
b8fbd125e6 | ||
|
|
cb2209d06a | ||
|
|
854ac468b9 | ||
|
|
150a3c0890 | ||
|
|
d9ee5b874c | ||
|
|
8a1bcc3d30 | ||
|
|
00e7190e29 | ||
|
|
1efdb4897e | ||
|
|
c13fbe6a41 | ||
|
|
76ef6e5c2b | ||
|
|
34510bcda8 | ||
|
|
085b388a7a | ||
|
|
9dec087fca | ||
|
|
c0e320ad0d | ||
|
|
845607481c | ||
|
|
bbeb859122 | ||
|
|
fc91e21206 | ||
|
|
9d296f8a35 | ||
|
|
30ce9b2b5c | ||
|
|
22f02076c6 | ||
|
|
26223f8124 | ||
|
|
5dfcf7cf26 | ||
|
|
37b23efece | ||
|
|
93b84e9308 | ||
|
|
33db37e669 | ||
|
|
a1868286b0 | ||
|
|
28e36de56f | ||
|
|
c05c8a7a06 | ||
|
|
d0ed3ff4b7 | ||
|
|
d9ee58a3b5 | ||
|
|
d6b7195192 | ||
|
|
66be5150d6 | ||
|
|
7c1af3aa10 | ||
|
|
e6a9459b04 | ||
|
|
f7d6e08688 | ||
|
|
9959c95966 | ||
|
|
8502cda17a | ||
|
|
09789c3ffc | ||
|
|
15e0c4c4ec | ||
|
|
52746ed8dc | ||
|
|
88a3c05b7b | ||
|
|
7f506be2ee | ||
|
|
5b0a9f8ba8 | ||
|
|
3fd5998d84 | ||
|
|
e8f3d85ea5 | ||
|
|
e5bb07a973 | ||
|
|
5ba5f82082 | ||
|
|
3f8c9b25d8 | ||
|
|
872d480c60 | ||
|
|
ba4e1adda1 | ||
|
|
7c31661869 | ||
|
|
0e2f617abc | ||
|
|
acde8d3f68 | ||
|
|
a56c4ac91b | ||
|
|
d6374b2522 | ||
|
|
d7438d067f | ||
|
|
a655b59cef | ||
|
|
a973271b8c | ||
|
|
c39c8e6982 | ||
|
|
78bd66d037 | ||
|
|
ea8f633dc0 | ||
|
|
140cd5e209 | ||
|
|
06c1f75f21 | ||
|
|
a6d5ff05dc | ||
|
|
908f24eb88 | ||
|
|
7931a68d4e | ||
|
|
580e3564c9 | ||
|
|
74a4a50470 | ||
|
|
774fa0b828 | ||
|
|
65ae1ac4e5 | ||
|
|
a504bad3fb | ||
|
|
a074363a5d | ||
|
|
7ccb0b16cd | ||
|
|
6b629f4816 | ||
|
|
e796351a0d | ||
|
|
57279e1981 | ||
|
|
28719ee3b4 | ||
|
|
cb2bce8006 | ||
|
|
628153cccd | ||
|
|
4555b63750 | ||
|
|
4366241739 | ||
|
|
20cc0b8d3c | ||
|
|
2d70c30fb2 | ||
|
|
26d0381161 | ||
|
|
d09e98f566 | ||
|
|
38658b38b4 | ||
|
|
da02946f4f | ||
|
|
e8abe4b77c | ||
|
|
cb68ce7c2f | ||
|
|
cf4ecc1945 | ||
|
|
108be41316 | ||
|
|
c6147a439d | ||
|
|
eadc834bb3 | ||
|
|
b4857e326f | ||
|
|
aa92da205e | ||
|
|
35ebbbc167 | ||
|
|
72477731ed | ||
|
|
ca82589350 | ||
|
|
d85c1141b9 | ||
|
|
93de7a7b40 | ||
|
|
a05f94dcc8 | ||
|
|
cec7da37b9 | ||
|
|
4fad477aeb | ||
|
|
c791192d64 | ||
|
|
6a1a2d4aa5 | ||
|
|
74cee1b65d | ||
|
|
798d76f4c7 | ||
|
|
746dab407e | ||
|
|
c1ba3e3d4a | ||
|
|
1650593927 | ||
|
|
7d88fc83bf | ||
|
|
d68716efdc | ||
|
|
758d84db9a | ||
|
|
96d518a59f | ||
|
|
0e7ad1c367 | ||
|
|
f27c65eb91 | ||
|
|
996ddb202b | ||
|
|
9d411699d8 |
3
.gitmodules
vendored
3
.gitmodules
vendored
@@ -40,3 +40,6 @@
|
||||
[submodule "Vulkan-Headers"]
|
||||
path = externals/Vulkan-Headers
|
||||
url = https://github.com/KhronosGroup/Vulkan-Headers.git
|
||||
[submodule "externals/zstd"]
|
||||
path = externals/zstd
|
||||
url = https://github.com/facebook/zstd
|
||||
|
||||
@@ -309,7 +309,7 @@ if (CLANG_FORMAT)
|
||||
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 "Get-ChildItem ${SRCS}/* -Include *.cpp,*.h -Recurse | Foreach {${CLANG_FORMAT} -i $_.fullname}"
|
||||
COMMAND powershell.exe -Command "Get-ChildItem '${SRCS}/*' -Include *.cpp,*.h -Recurse | Foreach {&'${CLANG_FORMAT}' -i $_.fullname}"
|
||||
COMMENT ${CCOMMENT})
|
||||
elseif(MINGW)
|
||||
add_custom_target(clang-format
|
||||
|
||||
4
externals/CMakeLists.txt
vendored
4
externals/CMakeLists.txt
vendored
@@ -49,6 +49,10 @@ add_subdirectory(open_source_archives EXCLUDE_FROM_ALL)
|
||||
add_library(unicorn-headers INTERFACE)
|
||||
target_include_directories(unicorn-headers INTERFACE ./unicorn/include)
|
||||
|
||||
# Zstandard
|
||||
add_subdirectory(zstd/build/cmake EXCLUDE_FROM_ALL)
|
||||
target_include_directories(libzstd_static INTERFACE ./zstd/lib)
|
||||
|
||||
# SoundTouch
|
||||
add_subdirectory(soundtouch)
|
||||
|
||||
|
||||
1
externals/zstd
vendored
Submodule
1
externals/zstd
vendored
Submodule
Submodule externals/zstd added at 470344d33e
@@ -91,6 +91,8 @@ add_library(common STATIC
|
||||
logging/log.h
|
||||
logging/text_formatter.cpp
|
||||
logging/text_formatter.h
|
||||
lz4_compression.cpp
|
||||
lz4_compression.h
|
||||
math_util.h
|
||||
memory_hook.cpp
|
||||
memory_hook.h
|
||||
@@ -123,6 +125,8 @@ add_library(common STATIC
|
||||
uint128.h
|
||||
vector_math.h
|
||||
web_result.h
|
||||
zstd_compression.cpp
|
||||
zstd_compression.h
|
||||
)
|
||||
|
||||
if(ARCHITECTURE_x86_64)
|
||||
@@ -136,3 +140,4 @@ endif()
|
||||
create_target_directory_groups(common)
|
||||
|
||||
target_link_libraries(common PUBLIC Boost::boost fmt microprofile)
|
||||
target_link_libraries(common PRIVATE lz4_static libzstd_static)
|
||||
|
||||
@@ -57,3 +57,21 @@ __declspec(noinline, noreturn)
|
||||
|
||||
#define UNIMPLEMENTED_IF(cond) ASSERT_MSG(!(cond), "Unimplemented code!")
|
||||
#define UNIMPLEMENTED_IF_MSG(cond, ...) ASSERT_MSG(!(cond), __VA_ARGS__)
|
||||
|
||||
// If the assert is ignored, execute _b_
|
||||
#define ASSERT_OR_EXECUTE(_a_, _b_) \
|
||||
do { \
|
||||
ASSERT(_a_); \
|
||||
if (!(_a_)) { \
|
||||
_b_ \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
// If the assert is ignored, execute _b_
|
||||
#define ASSERT_OR_EXECUTE_MSG(_a_, _b_, ...) \
|
||||
do { \
|
||||
ASSERT_MSG(_a_, __VA_ARGS__); \
|
||||
if (!(_a_)) { \
|
||||
_b_ \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
@@ -32,7 +32,7 @@ inline u32 CountLeadingZeroes32(u32 value) {
|
||||
return 32;
|
||||
}
|
||||
|
||||
inline u64 CountLeadingZeroes64(u64 value) {
|
||||
inline u32 CountLeadingZeroes64(u64 value) {
|
||||
unsigned long leading_zero = 0;
|
||||
|
||||
if (_BitScanReverse64(&leading_zero, value) != 0) {
|
||||
@@ -47,15 +47,15 @@ inline u32 CountLeadingZeroes32(u32 value) {
|
||||
return 32;
|
||||
}
|
||||
|
||||
return __builtin_clz(value);
|
||||
return static_cast<u32>(__builtin_clz(value));
|
||||
}
|
||||
|
||||
inline u64 CountLeadingZeroes64(u64 value) {
|
||||
inline u32 CountLeadingZeroes64(u64 value) {
|
||||
if (value == 0) {
|
||||
return 64;
|
||||
}
|
||||
|
||||
return __builtin_clzll(value);
|
||||
return static_cast<u32>(__builtin_clzll(value));
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -70,7 +70,7 @@ inline u32 CountTrailingZeroes32(u32 value) {
|
||||
return 32;
|
||||
}
|
||||
|
||||
inline u64 CountTrailingZeroes64(u64 value) {
|
||||
inline u32 CountTrailingZeroes64(u64 value) {
|
||||
unsigned long trailing_zero = 0;
|
||||
|
||||
if (_BitScanForward64(&trailing_zero, value) != 0) {
|
||||
@@ -85,15 +85,15 @@ inline u32 CountTrailingZeroes32(u32 value) {
|
||||
return 32;
|
||||
}
|
||||
|
||||
return __builtin_ctz(value);
|
||||
return static_cast<u32>(__builtin_ctz(value));
|
||||
}
|
||||
|
||||
inline u64 CountTrailingZeroes64(u64 value) {
|
||||
inline u32 CountTrailingZeroes64(u64 value) {
|
||||
if (value == 0) {
|
||||
return 64;
|
||||
}
|
||||
|
||||
return __builtin_ctzll(value);
|
||||
return static_cast<u32>(__builtin_ctzll(value));
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
76
src/common/lz4_compression.cpp
Normal file
76
src/common/lz4_compression.cpp
Normal file
@@ -0,0 +1,76 @@
|
||||
// Copyright 2019 yuzu Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <algorithm>
|
||||
#include <lz4hc.h>
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/lz4_compression.h"
|
||||
|
||||
namespace Common::Compression {
|
||||
|
||||
std::vector<u8> CompressDataLZ4(const u8* source, std::size_t source_size) {
|
||||
ASSERT_MSG(source_size <= LZ4_MAX_INPUT_SIZE, "Source size exceeds LZ4 maximum input size");
|
||||
|
||||
const auto source_size_int = static_cast<int>(source_size);
|
||||
const int max_compressed_size = LZ4_compressBound(source_size_int);
|
||||
std::vector<u8> compressed(max_compressed_size);
|
||||
|
||||
const int compressed_size = LZ4_compress_default(reinterpret_cast<const char*>(source),
|
||||
reinterpret_cast<char*>(compressed.data()),
|
||||
source_size_int, max_compressed_size);
|
||||
|
||||
if (compressed_size <= 0) {
|
||||
// Compression failed
|
||||
return {};
|
||||
}
|
||||
|
||||
compressed.resize(compressed_size);
|
||||
|
||||
return compressed;
|
||||
}
|
||||
|
||||
std::vector<u8> CompressDataLZ4HC(const u8* source, std::size_t source_size,
|
||||
s32 compression_level) {
|
||||
ASSERT_MSG(source_size <= LZ4_MAX_INPUT_SIZE, "Source size exceeds LZ4 maximum input size");
|
||||
|
||||
compression_level = std::clamp(compression_level, LZ4HC_CLEVEL_MIN, LZ4HC_CLEVEL_MAX);
|
||||
|
||||
const auto source_size_int = static_cast<int>(source_size);
|
||||
const int max_compressed_size = LZ4_compressBound(source_size_int);
|
||||
std::vector<u8> compressed(max_compressed_size);
|
||||
|
||||
const int compressed_size = LZ4_compress_HC(
|
||||
reinterpret_cast<const char*>(source), reinterpret_cast<char*>(compressed.data()),
|
||||
source_size_int, max_compressed_size, compression_level);
|
||||
|
||||
if (compressed_size <= 0) {
|
||||
// Compression failed
|
||||
return {};
|
||||
}
|
||||
|
||||
compressed.resize(compressed_size);
|
||||
|
||||
return compressed;
|
||||
}
|
||||
|
||||
std::vector<u8> CompressDataLZ4HCMax(const u8* source, std::size_t source_size) {
|
||||
return CompressDataLZ4HC(source, source_size, LZ4HC_CLEVEL_MAX);
|
||||
}
|
||||
|
||||
std::vector<u8> DecompressDataLZ4(const std::vector<u8>& compressed,
|
||||
std::size_t uncompressed_size) {
|
||||
std::vector<u8> uncompressed(uncompressed_size);
|
||||
const int size_check = LZ4_decompress_safe(reinterpret_cast<const char*>(compressed.data()),
|
||||
reinterpret_cast<char*>(uncompressed.data()),
|
||||
static_cast<int>(compressed.size()),
|
||||
static_cast<int>(uncompressed.size()));
|
||||
if (static_cast<int>(uncompressed_size) != size_check) {
|
||||
// Decompression failed
|
||||
return {};
|
||||
}
|
||||
return uncompressed;
|
||||
}
|
||||
|
||||
} // namespace Common::Compression
|
||||
55
src/common/lz4_compression.h
Normal file
55
src/common/lz4_compression.h
Normal file
@@ -0,0 +1,55 @@
|
||||
// Copyright 2019 yuzu Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "common/common_types.h"
|
||||
|
||||
namespace Common::Compression {
|
||||
|
||||
/**
|
||||
* Compresses a source memory region with LZ4 and returns the compressed data in a vector.
|
||||
*
|
||||
* @param source the uncompressed source memory region.
|
||||
* @param source_size the size in bytes of the uncompressed source memory region.
|
||||
*
|
||||
* @return the compressed data.
|
||||
*/
|
||||
std::vector<u8> CompressDataLZ4(const u8* source, std::size_t source_size);
|
||||
|
||||
/**
|
||||
* Utilizes the LZ4 subalgorithm LZ4HC with the specified compression level. Higher compression
|
||||
* levels result in a smaller compressed size, but require more CPU time for compression. The
|
||||
* compression level has almost no impact on decompression speed. Data compressed with LZ4HC can
|
||||
* also be decompressed with the default LZ4 decompression.
|
||||
*
|
||||
* @param source the uncompressed source memory region.
|
||||
* @param source_size the size in bytes of the uncompressed source memory region.
|
||||
* @param compression_level the used compression level. Should be between 3 and 12.
|
||||
*
|
||||
* @return the compressed data.
|
||||
*/
|
||||
std::vector<u8> CompressDataLZ4HC(const u8* source, std::size_t source_size, s32 compression_level);
|
||||
|
||||
/**
|
||||
* Utilizes the LZ4 subalgorithm LZ4HC with the highest possible compression level.
|
||||
*
|
||||
* @param source the uncompressed source memory region.
|
||||
* @param source_size the size in bytes of the uncompressed source memory region.
|
||||
*
|
||||
* @return the compressed data.
|
||||
*/
|
||||
std::vector<u8> CompressDataLZ4HCMax(const u8* source, std::size_t source_size);
|
||||
|
||||
/**
|
||||
* Decompresses a source memory region with LZ4 and returns the uncompressed data in a vector.
|
||||
*
|
||||
* @param compressed the compressed source memory region.
|
||||
* @param uncompressed_size the size in bytes of the uncompressed data.
|
||||
*
|
||||
* @return the decompressed data.
|
||||
*/
|
||||
std::vector<u8> DecompressDataLZ4(const std::vector<u8>& compressed, std::size_t uncompressed_size);
|
||||
|
||||
} // namespace Common::Compression
|
||||
@@ -72,7 +72,7 @@ public:
|
||||
u64 prios = mlq.used_priorities;
|
||||
prios &= ~((1ULL << (current_priority + 1)) - 1);
|
||||
if (prios == 0) {
|
||||
current_priority = mlq.depth();
|
||||
current_priority = static_cast<u32>(mlq.depth());
|
||||
} else {
|
||||
current_priority = CountTrailingZeroes64(prios);
|
||||
it = GetBeginItForPrio();
|
||||
|
||||
53
src/common/zstd_compression.cpp
Normal file
53
src/common/zstd_compression.cpp
Normal file
@@ -0,0 +1,53 @@
|
||||
// Copyright 2019 yuzu Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <zstd.h>
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/zstd_compression.h"
|
||||
|
||||
namespace Common::Compression {
|
||||
|
||||
std::vector<u8> CompressDataZSTD(const u8* source, std::size_t source_size, s32 compression_level) {
|
||||
compression_level = std::clamp(compression_level, 1, ZSTD_maxCLevel());
|
||||
|
||||
const std::size_t max_compressed_size = ZSTD_compressBound(source_size);
|
||||
std::vector<u8> compressed(max_compressed_size);
|
||||
|
||||
const std::size_t compressed_size =
|
||||
ZSTD_compress(compressed.data(), compressed.size(), source, source_size, compression_level);
|
||||
|
||||
if (ZSTD_isError(compressed_size)) {
|
||||
// Compression failed
|
||||
return {};
|
||||
}
|
||||
|
||||
compressed.resize(compressed_size);
|
||||
|
||||
return compressed;
|
||||
}
|
||||
|
||||
std::vector<u8> CompressDataZSTDDefault(const u8* source, std::size_t source_size) {
|
||||
return CompressDataZSTD(source, source_size, ZSTD_CLEVEL_DEFAULT);
|
||||
}
|
||||
|
||||
std::vector<u8> DecompressDataZSTD(const std::vector<u8>& compressed) {
|
||||
const std::size_t decompressed_size =
|
||||
ZSTD_getDecompressedSize(compressed.data(), compressed.size());
|
||||
std::vector<u8> decompressed(decompressed_size);
|
||||
|
||||
const std::size_t uncompressed_result_size = ZSTD_decompress(
|
||||
decompressed.data(), decompressed.size(), compressed.data(), compressed.size());
|
||||
|
||||
if (decompressed_size != uncompressed_result_size || ZSTD_isError(uncompressed_result_size)) {
|
||||
// Decompression failed
|
||||
return {};
|
||||
}
|
||||
return decompressed;
|
||||
}
|
||||
|
||||
} // namespace Common::Compression
|
||||
42
src/common/zstd_compression.h
Normal file
42
src/common/zstd_compression.h
Normal file
@@ -0,0 +1,42 @@
|
||||
// Copyright 2019 yuzu Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "common/common_types.h"
|
||||
|
||||
namespace Common::Compression {
|
||||
|
||||
/**
|
||||
* Compresses a source memory region with Zstandard and returns the compressed data in a vector.
|
||||
*
|
||||
* @param source the uncompressed source memory region.
|
||||
* @param source_size the size in bytes of the uncompressed source memory region.
|
||||
* @param compression_level the used compression level. Should be between 1 and 22.
|
||||
*
|
||||
* @return the compressed data.
|
||||
*/
|
||||
std::vector<u8> CompressDataZSTD(const u8* source, std::size_t source_size, s32 compression_level);
|
||||
|
||||
/**
|
||||
* Compresses a source memory region with Zstandard with the default compression level and returns
|
||||
* the compressed data in a vector.
|
||||
*
|
||||
* @param source the uncompressed source memory region.
|
||||
* @param source_size the size in bytes of the uncompressed source memory region.
|
||||
*
|
||||
* @return the compressed data.
|
||||
*/
|
||||
std::vector<u8> CompressDataZSTDDefault(const u8* source, std::size_t source_size);
|
||||
|
||||
/**
|
||||
* Decompresses a source memory region with Zstandard and returns the uncompressed data in a vector.
|
||||
*
|
||||
* @param compressed the compressed source memory region.
|
||||
*
|
||||
* @return the decompressed data.
|
||||
*/
|
||||
std::vector<u8> DecompressDataZSTD(const std::vector<u8>& compressed);
|
||||
|
||||
} // namespace Common::Compression
|
||||
@@ -458,7 +458,7 @@ add_library(core STATIC
|
||||
create_target_directory_groups(core)
|
||||
|
||||
target_link_libraries(core PUBLIC common PRIVATE audio_core video_core)
|
||||
target_link_libraries(core PUBLIC Boost::boost PRIVATE fmt lz4_static mbedtls opus unicorn open_source_archives)
|
||||
target_link_libraries(core PUBLIC Boost::boost PRIVATE fmt mbedtls opus unicorn open_source_archives)
|
||||
if (ENABLE_WEB_SERVICE)
|
||||
target_compile_definitions(core PRIVATE -DENABLE_WEB_SERVICE)
|
||||
target_link_libraries(core PRIVATE web_service)
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include "core/core_timing.h"
|
||||
#include "core/core_timing_util.h"
|
||||
#include "core/gdbstub/gdbstub.h"
|
||||
#include "core/hle/kernel/kernel.h"
|
||||
#include "core/hle/kernel/process.h"
|
||||
#include "core/hle/kernel/svc.h"
|
||||
#include "core/hle/kernel/vm_manager.h"
|
||||
@@ -26,7 +27,6 @@ using Vector = Dynarmic::A64::Vector;
|
||||
class ARM_Dynarmic_Callbacks : public Dynarmic::A64::UserCallbacks {
|
||||
public:
|
||||
explicit ARM_Dynarmic_Callbacks(ARM_Dynarmic& parent) : parent(parent) {}
|
||||
~ARM_Dynarmic_Callbacks() = default;
|
||||
|
||||
u8 MemoryRead8(u64 vaddr) override {
|
||||
return Memory::Read8(vaddr);
|
||||
@@ -100,7 +100,7 @@ public:
|
||||
}
|
||||
|
||||
void CallSVC(u32 swi) override {
|
||||
Kernel::CallSVC(swi);
|
||||
Kernel::CallSVC(parent.system, swi);
|
||||
}
|
||||
|
||||
void AddTicks(u64 ticks) override {
|
||||
@@ -113,14 +113,14 @@ public:
|
||||
// Always execute at least one tick.
|
||||
amortized_ticks = std::max<u64>(amortized_ticks, 1);
|
||||
|
||||
parent.core_timing.AddTicks(amortized_ticks);
|
||||
parent.system.CoreTiming().AddTicks(amortized_ticks);
|
||||
num_interpreted_instructions = 0;
|
||||
}
|
||||
u64 GetTicksRemaining() override {
|
||||
return std::max(parent.core_timing.GetDowncount(), 0);
|
||||
return std::max(parent.system.CoreTiming().GetDowncount(), 0);
|
||||
}
|
||||
u64 GetCNTPCT() override {
|
||||
return Timing::CpuCyclesToClockCycles(parent.core_timing.GetTicks());
|
||||
return Timing::CpuCyclesToClockCycles(parent.system.CoreTiming().GetTicks());
|
||||
}
|
||||
|
||||
ARM_Dynarmic& parent;
|
||||
@@ -130,7 +130,7 @@ public:
|
||||
};
|
||||
|
||||
std::unique_ptr<Dynarmic::A64::Jit> ARM_Dynarmic::MakeJit() const {
|
||||
auto* current_process = Core::CurrentProcess();
|
||||
auto* current_process = system.Kernel().CurrentProcess();
|
||||
auto** const page_table = current_process->VMManager().page_table.pointers.data();
|
||||
|
||||
Dynarmic::A64::UserConfig config;
|
||||
@@ -164,7 +164,6 @@ MICROPROFILE_DEFINE(ARM_Jit_Dynarmic, "ARM JIT", "Dynarmic", MP_RGB(255, 64, 64)
|
||||
|
||||
void ARM_Dynarmic::Run() {
|
||||
MICROPROFILE_SCOPE(ARM_Jit_Dynarmic);
|
||||
ASSERT(Memory::GetCurrentPageTable() == current_page_table);
|
||||
|
||||
jit->Run();
|
||||
}
|
||||
@@ -173,10 +172,10 @@ void ARM_Dynarmic::Step() {
|
||||
cb->InterpreterFallback(jit->GetPC(), 1);
|
||||
}
|
||||
|
||||
ARM_Dynarmic::ARM_Dynarmic(Timing::CoreTiming& core_timing, ExclusiveMonitor& exclusive_monitor,
|
||||
ARM_Dynarmic::ARM_Dynarmic(System& system, ExclusiveMonitor& exclusive_monitor,
|
||||
std::size_t core_index)
|
||||
: cb(std::make_unique<ARM_Dynarmic_Callbacks>(*this)), inner_unicorn{core_timing},
|
||||
core_index{core_index}, core_timing{core_timing},
|
||||
: cb(std::make_unique<ARM_Dynarmic_Callbacks>(*this)), inner_unicorn{system},
|
||||
core_index{core_index}, system{system},
|
||||
exclusive_monitor{dynamic_cast<DynarmicExclusiveMonitor&>(exclusive_monitor)} {
|
||||
ThreadContext ctx{};
|
||||
inner_unicorn.SaveContext(ctx);
|
||||
@@ -279,7 +278,6 @@ void ARM_Dynarmic::ClearExclusiveState() {
|
||||
|
||||
void ARM_Dynarmic::PageTableChanged() {
|
||||
jit = MakeJit();
|
||||
current_page_table = Memory::GetCurrentPageTable();
|
||||
}
|
||||
|
||||
DynarmicExclusiveMonitor::DynarmicExclusiveMonitor(std::size_t core_count) : monitor(core_count) {}
|
||||
|
||||
@@ -12,24 +12,16 @@
|
||||
#include "core/arm/exclusive_monitor.h"
|
||||
#include "core/arm/unicorn/arm_unicorn.h"
|
||||
|
||||
namespace Common {
|
||||
struct PageTable;
|
||||
}
|
||||
|
||||
namespace Core::Timing {
|
||||
class CoreTiming;
|
||||
}
|
||||
|
||||
namespace Core {
|
||||
|
||||
class ARM_Dynarmic_Callbacks;
|
||||
class DynarmicExclusiveMonitor;
|
||||
class System;
|
||||
|
||||
class ARM_Dynarmic final : public ARM_Interface {
|
||||
public:
|
||||
ARM_Dynarmic(Timing::CoreTiming& core_timing, ExclusiveMonitor& exclusive_monitor,
|
||||
std::size_t core_index);
|
||||
~ARM_Dynarmic();
|
||||
ARM_Dynarmic(System& system, ExclusiveMonitor& exclusive_monitor, std::size_t core_index);
|
||||
~ARM_Dynarmic() override;
|
||||
|
||||
void MapBackingMemory(VAddr address, std::size_t size, u8* memory,
|
||||
Kernel::VMAPermission perms) override;
|
||||
@@ -67,16 +59,14 @@ private:
|
||||
ARM_Unicorn inner_unicorn;
|
||||
|
||||
std::size_t core_index;
|
||||
Timing::CoreTiming& core_timing;
|
||||
System& system;
|
||||
DynarmicExclusiveMonitor& exclusive_monitor;
|
||||
|
||||
Common::PageTable* current_page_table = nullptr;
|
||||
};
|
||||
|
||||
class DynarmicExclusiveMonitor final : public ExclusiveMonitor {
|
||||
public:
|
||||
explicit DynarmicExclusiveMonitor(std::size_t core_count);
|
||||
~DynarmicExclusiveMonitor();
|
||||
~DynarmicExclusiveMonitor() override;
|
||||
|
||||
void SetExclusive(std::size_t core_index, VAddr addr) override;
|
||||
void ClearExclusive() override;
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
#include "core/core.h"
|
||||
#include "core/core_timing.h"
|
||||
#include "core/hle/kernel/svc.h"
|
||||
#include "core/memory.h"
|
||||
|
||||
namespace Core {
|
||||
|
||||
@@ -49,20 +48,6 @@ static void CodeHook(uc_engine* uc, uint64_t address, uint32_t size, void* user_
|
||||
}
|
||||
}
|
||||
|
||||
static void InterruptHook(uc_engine* uc, u32 intNo, void* user_data) {
|
||||
u32 esr{};
|
||||
CHECKED(uc_reg_read(uc, UC_ARM64_REG_ESR, &esr));
|
||||
|
||||
auto ec = esr >> 26;
|
||||
auto iss = esr & 0xFFFFFF;
|
||||
|
||||
switch (ec) {
|
||||
case 0x15: // SVC
|
||||
Kernel::CallSVC(iss);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static bool UnmappedMemoryHook(uc_engine* uc, uc_mem_type type, u64 addr, int size, u64 value,
|
||||
void* user_data) {
|
||||
ARM_Interface::ThreadContext ctx{};
|
||||
@@ -72,7 +57,7 @@ static bool UnmappedMemoryHook(uc_engine* uc, uc_mem_type type, u64 addr, int si
|
||||
return {};
|
||||
}
|
||||
|
||||
ARM_Unicorn::ARM_Unicorn(Timing::CoreTiming& core_timing) : core_timing{core_timing} {
|
||||
ARM_Unicorn::ARM_Unicorn(System& system) : system{system} {
|
||||
CHECKED(uc_open(UC_ARCH_ARM64, UC_MODE_ARM, &uc));
|
||||
|
||||
auto fpv = 3 << 20;
|
||||
@@ -177,7 +162,7 @@ void ARM_Unicorn::Run() {
|
||||
if (GDBStub::IsServerEnabled()) {
|
||||
ExecuteInstructions(std::max(4000000, 0));
|
||||
} else {
|
||||
ExecuteInstructions(std::max(core_timing.GetDowncount(), 0));
|
||||
ExecuteInstructions(std::max(system.CoreTiming().GetDowncount(), 0));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -190,14 +175,15 @@ MICROPROFILE_DEFINE(ARM_Jit_Unicorn, "ARM JIT", "Unicorn", MP_RGB(255, 64, 64));
|
||||
void ARM_Unicorn::ExecuteInstructions(int num_instructions) {
|
||||
MICROPROFILE_SCOPE(ARM_Jit_Unicorn);
|
||||
CHECKED(uc_emu_start(uc, GetPC(), 1ULL << 63, 0, num_instructions));
|
||||
core_timing.AddTicks(num_instructions);
|
||||
system.CoreTiming().AddTicks(num_instructions);
|
||||
if (GDBStub::IsServerEnabled()) {
|
||||
if (last_bkpt_hit) {
|
||||
if (last_bkpt_hit && last_bkpt.type == GDBStub::BreakpointType::Execute) {
|
||||
uc_reg_write(uc, UC_ARM64_REG_PC, &last_bkpt.address);
|
||||
}
|
||||
|
||||
Kernel::Thread* thread = Kernel::GetCurrentThread();
|
||||
SaveContext(thread->GetContext());
|
||||
if (last_bkpt_hit || GDBStub::GetCpuStepFlag()) {
|
||||
if (last_bkpt_hit || GDBStub::IsMemoryBreak() || GDBStub::GetCpuStepFlag()) {
|
||||
last_bkpt_hit = false;
|
||||
GDBStub::Break();
|
||||
GDBStub::SendTrap(thread, 5);
|
||||
@@ -272,4 +258,20 @@ void ARM_Unicorn::RecordBreak(GDBStub::BreakpointAddress bkpt) {
|
||||
last_bkpt_hit = true;
|
||||
}
|
||||
|
||||
void ARM_Unicorn::InterruptHook(uc_engine* uc, u32 int_no, void* user_data) {
|
||||
u32 esr{};
|
||||
CHECKED(uc_reg_read(uc, UC_ARM64_REG_ESR, &esr));
|
||||
|
||||
const auto ec = esr >> 26;
|
||||
const auto iss = esr & 0xFFFFFF;
|
||||
|
||||
auto* const arm_instance = static_cast<ARM_Unicorn*>(user_data);
|
||||
|
||||
switch (ec) {
|
||||
case 0x15: // SVC
|
||||
Kernel::CallSVC(arm_instance->system, iss);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Core
|
||||
|
||||
@@ -9,16 +9,14 @@
|
||||
#include "core/arm/arm_interface.h"
|
||||
#include "core/gdbstub/gdbstub.h"
|
||||
|
||||
namespace Core::Timing {
|
||||
class CoreTiming;
|
||||
}
|
||||
|
||||
namespace Core {
|
||||
|
||||
class System;
|
||||
|
||||
class ARM_Unicorn final : public ARM_Interface {
|
||||
public:
|
||||
explicit ARM_Unicorn(Timing::CoreTiming& core_timing);
|
||||
~ARM_Unicorn();
|
||||
explicit ARM_Unicorn(System& system);
|
||||
~ARM_Unicorn() override;
|
||||
|
||||
void MapBackingMemory(VAddr address, std::size_t size, u8* memory,
|
||||
Kernel::VMAPermission perms) override;
|
||||
@@ -47,10 +45,12 @@ public:
|
||||
void RecordBreak(GDBStub::BreakpointAddress bkpt);
|
||||
|
||||
private:
|
||||
static void InterruptHook(uc_engine* uc, u32 int_no, void* user_data);
|
||||
|
||||
uc_engine* uc{};
|
||||
Timing::CoreTiming& core_timing;
|
||||
System& system;
|
||||
GDBStub::BreakpointAddress last_bkpt{};
|
||||
bool last_bkpt_hit;
|
||||
bool last_bkpt_hit = false;
|
||||
};
|
||||
|
||||
} // namespace Core
|
||||
|
||||
@@ -55,13 +55,13 @@ Cpu::Cpu(System& system, ExclusiveMonitor& exclusive_monitor, CpuBarrier& cpu_ba
|
||||
: cpu_barrier{cpu_barrier}, core_timing{system.CoreTiming()}, core_index{core_index} {
|
||||
if (Settings::values.use_cpu_jit) {
|
||||
#ifdef ARCHITECTURE_x86_64
|
||||
arm_interface = std::make_unique<ARM_Dynarmic>(core_timing, exclusive_monitor, core_index);
|
||||
arm_interface = std::make_unique<ARM_Dynarmic>(system, exclusive_monitor, core_index);
|
||||
#else
|
||||
arm_interface = std::make_unique<ARM_Unicorn>();
|
||||
arm_interface = std::make_unique<ARM_Unicorn>(system);
|
||||
LOG_WARNING(Core, "CPU JIT requested, but Dynarmic not available");
|
||||
#endif
|
||||
} else {
|
||||
arm_interface = std::make_unique<ARM_Unicorn>(core_timing);
|
||||
arm_interface = std::make_unique<ARM_Unicorn>(system);
|
||||
}
|
||||
|
||||
scheduler = std::make_unique<Kernel::Scheduler>(system, *arm_interface);
|
||||
|
||||
@@ -67,7 +67,7 @@ std::string NACP::GetDeveloperName(Language language) const {
|
||||
}
|
||||
|
||||
u64 NACP::GetTitleId() const {
|
||||
return raw.title_id;
|
||||
return raw.save_data_owner_id;
|
||||
}
|
||||
|
||||
u64 NACP::GetDLCBaseTitleId() const {
|
||||
@@ -80,11 +80,11 @@ std::string NACP::GetVersionString() const {
|
||||
}
|
||||
|
||||
u64 NACP::GetDefaultNormalSaveSize() const {
|
||||
return raw.normal_save_data_size;
|
||||
return raw.user_account_save_data_size;
|
||||
}
|
||||
|
||||
u64 NACP::GetDefaultJournalSaveSize() const {
|
||||
return raw.journal_sava_data_size;
|
||||
return raw.user_account_save_data_journal_size;
|
||||
}
|
||||
|
||||
std::vector<u8> NACP::GetRawBytes() const {
|
||||
|
||||
@@ -38,23 +38,35 @@ struct RawNACP {
|
||||
u8 video_capture_mode;
|
||||
bool data_loss_confirmation;
|
||||
INSERT_PADDING_BYTES(1);
|
||||
u64_le title_id;
|
||||
u64_le presence_group_id;
|
||||
std::array<u8, 0x20> rating_age;
|
||||
std::array<char, 0x10> version_string;
|
||||
u64_le dlc_base_title_id;
|
||||
u64_le title_id_2;
|
||||
u64_le normal_save_data_size;
|
||||
u64_le journal_sava_data_size;
|
||||
INSERT_PADDING_BYTES(0x18);
|
||||
u64_le product_code;
|
||||
u64_le save_data_owner_id;
|
||||
u64_le user_account_save_data_size;
|
||||
u64_le user_account_save_data_journal_size;
|
||||
u64_le device_save_data_size;
|
||||
u64_le device_save_data_journal_size;
|
||||
u64_le bcat_delivery_cache_storage_size;
|
||||
char application_error_code_category[8];
|
||||
std::array<u64_le, 0x8> local_communication;
|
||||
u8 logo_type;
|
||||
u8 logo_handling;
|
||||
bool runtime_add_on_content_install;
|
||||
INSERT_PADDING_BYTES(5);
|
||||
u64_le title_id_update;
|
||||
std::array<u8, 0x40> bcat_passphrase;
|
||||
INSERT_PADDING_BYTES(0xEC0);
|
||||
u64_le seed_for_pseudo_device_id;
|
||||
std::array<u8, 0x41> bcat_passphrase;
|
||||
INSERT_PADDING_BYTES(7);
|
||||
u64_le user_account_save_data_max_size;
|
||||
u64_le user_account_save_data_max_journal_size;
|
||||
u64_le device_save_data_max_size;
|
||||
u64_le device_save_data_max_journal_size;
|
||||
u64_le temporary_storage_size;
|
||||
u64_le cache_storage_size;
|
||||
u64_le cache_storage_journal_size;
|
||||
u64_le cache_storage_data_and_journal_max_size;
|
||||
u64_le cache_storage_max_index;
|
||||
INSERT_PADDING_BYTES(0xE70);
|
||||
};
|
||||
static_assert(sizeof(RawNACP) == 0x4000, "RawNACP has incorrect size.");
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
*/
|
||||
|
||||
#include <cstring>
|
||||
#include <string_view>
|
||||
#include "common/alignment.h"
|
||||
#include "common/assert.h"
|
||||
#include "core/file_sys/fsmitm_romfsbuild.h"
|
||||
@@ -97,7 +98,8 @@ struct RomFSBuildFileContext {
|
||||
VirtualFile source;
|
||||
};
|
||||
|
||||
static u32 romfs_calc_path_hash(u32 parent, std::string path, u32 start, std::size_t path_len) {
|
||||
static u32 romfs_calc_path_hash(u32 parent, std::string_view path, u32 start,
|
||||
std::size_t path_len) {
|
||||
u32 hash = parent ^ 123456789;
|
||||
for (u32 i = 0; i < path_len; i++) {
|
||||
hash = (hash >> 5) | (hash << 27);
|
||||
|
||||
@@ -10,14 +10,6 @@
|
||||
|
||||
namespace FileSys {
|
||||
|
||||
bool operator>=(TitleType lhs, TitleType rhs) {
|
||||
return static_cast<std::size_t>(lhs) >= static_cast<std::size_t>(rhs);
|
||||
}
|
||||
|
||||
bool operator<=(TitleType lhs, TitleType rhs) {
|
||||
return static_cast<std::size_t>(lhs) <= static_cast<std::size_t>(rhs);
|
||||
}
|
||||
|
||||
CNMT::CNMT(VirtualFile file) {
|
||||
if (file->ReadObject(&header) != sizeof(CNMTHeader))
|
||||
return;
|
||||
|
||||
@@ -29,9 +29,6 @@ enum class TitleType : u8 {
|
||||
DeltaTitle = 0x83,
|
||||
};
|
||||
|
||||
bool operator>=(TitleType lhs, TitleType rhs);
|
||||
bool operator<=(TitleType lhs, TitleType rhs);
|
||||
|
||||
enum class ContentRecordType : u8 {
|
||||
Meta = 0,
|
||||
Program = 1,
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstring>
|
||||
#include <vector>
|
||||
|
||||
#include "common/logging/log.h"
|
||||
@@ -17,28 +16,30 @@ ProgramMetadata::ProgramMetadata() = default;
|
||||
ProgramMetadata::~ProgramMetadata() = default;
|
||||
|
||||
Loader::ResultStatus ProgramMetadata::Load(VirtualFile file) {
|
||||
std::size_t total_size = static_cast<std::size_t>(file->GetSize());
|
||||
if (total_size < sizeof(Header))
|
||||
const std::size_t total_size = file->GetSize();
|
||||
if (total_size < sizeof(Header)) {
|
||||
return Loader::ResultStatus::ErrorBadNPDMHeader;
|
||||
}
|
||||
|
||||
// TODO(DarkLordZach): Use ReadObject when Header/AcidHeader becomes trivially copyable.
|
||||
std::vector<u8> npdm_header_data = file->ReadBytes(sizeof(Header));
|
||||
if (sizeof(Header) != npdm_header_data.size())
|
||||
if (sizeof(Header) != file->ReadObject(&npdm_header)) {
|
||||
return Loader::ResultStatus::ErrorBadNPDMHeader;
|
||||
std::memcpy(&npdm_header, npdm_header_data.data(), sizeof(Header));
|
||||
}
|
||||
|
||||
std::vector<u8> acid_header_data = file->ReadBytes(sizeof(AcidHeader), npdm_header.acid_offset);
|
||||
if (sizeof(AcidHeader) != acid_header_data.size())
|
||||
if (sizeof(AcidHeader) != file->ReadObject(&acid_header, npdm_header.acid_offset)) {
|
||||
return Loader::ResultStatus::ErrorBadACIDHeader;
|
||||
std::memcpy(&acid_header, acid_header_data.data(), sizeof(AcidHeader));
|
||||
}
|
||||
|
||||
if (sizeof(AciHeader) != file->ReadObject(&aci_header, npdm_header.aci_offset))
|
||||
if (sizeof(AciHeader) != file->ReadObject(&aci_header, npdm_header.aci_offset)) {
|
||||
return Loader::ResultStatus::ErrorBadACIHeader;
|
||||
}
|
||||
|
||||
if (sizeof(FileAccessControl) != file->ReadObject(&acid_file_access, acid_header.fac_offset))
|
||||
if (sizeof(FileAccessControl) != file->ReadObject(&acid_file_access, acid_header.fac_offset)) {
|
||||
return Loader::ResultStatus::ErrorBadFileAccessControl;
|
||||
if (sizeof(FileAccessHeader) != file->ReadObject(&aci_file_access, aci_header.fah_offset))
|
||||
}
|
||||
|
||||
if (sizeof(FileAccessHeader) != file->ReadObject(&aci_file_access, aci_header.fah_offset)) {
|
||||
return Loader::ResultStatus::ErrorBadFileAccessHeader;
|
||||
}
|
||||
|
||||
aci_kernel_capabilities.resize(aci_header.kac_size / sizeof(u32));
|
||||
const u64 read_size = aci_header.kac_size;
|
||||
|
||||
@@ -58,7 +58,6 @@ public:
|
||||
void Print() const;
|
||||
|
||||
private:
|
||||
// TODO(DarkLordZach): BitField is not trivially copyable.
|
||||
struct Header {
|
||||
std::array<char, 4> magic;
|
||||
std::array<u8, 8> reserved;
|
||||
@@ -85,7 +84,6 @@ private:
|
||||
|
||||
static_assert(sizeof(Header) == 0x80, "NPDM header structure size is wrong");
|
||||
|
||||
// TODO(DarkLordZach): BitField is not trivially copyable.
|
||||
struct AcidHeader {
|
||||
std::array<u8, 0x100> signature;
|
||||
std::array<u8, 0x100> nca_modulus;
|
||||
|
||||
@@ -16,8 +16,10 @@ namespace FileSys {
|
||||
constexpr char SAVE_DATA_SIZE_FILENAME[] = ".yuzu_save_size";
|
||||
|
||||
std::string SaveDataDescriptor::DebugInfo() const {
|
||||
return fmt::format("[type={:02X}, title_id={:016X}, user_id={:016X}{:016X}, save_id={:016X}]",
|
||||
static_cast<u8>(type), title_id, user_id[1], user_id[0], save_id);
|
||||
return fmt::format("[type={:02X}, title_id={:016X}, user_id={:016X}{:016X}, save_id={:016X}, "
|
||||
"rank={}, index={}]",
|
||||
static_cast<u8>(type), title_id, user_id[1], user_id[0], save_id,
|
||||
static_cast<u8>(rank), index);
|
||||
}
|
||||
|
||||
SaveDataFactory::SaveDataFactory(VirtualDir save_directory) : dir(std::move(save_directory)) {
|
||||
@@ -28,7 +30,7 @@ SaveDataFactory::SaveDataFactory(VirtualDir save_directory) : dir(std::move(save
|
||||
|
||||
SaveDataFactory::~SaveDataFactory() = default;
|
||||
|
||||
ResultVal<VirtualDir> SaveDataFactory::Open(SaveDataSpaceId space, SaveDataDescriptor meta) {
|
||||
ResultVal<VirtualDir> SaveDataFactory::Open(SaveDataSpaceId space, const SaveDataDescriptor& meta) {
|
||||
if (meta.type == SaveDataType::SystemSaveData || meta.type == SaveDataType::SaveData) {
|
||||
if (meta.zero_1 != 0) {
|
||||
LOG_WARNING(Service_FS,
|
||||
|
||||
@@ -32,12 +32,19 @@ enum class SaveDataType : u8 {
|
||||
CacheStorage = 5,
|
||||
};
|
||||
|
||||
enum class SaveDataRank : u8 {
|
||||
Primary,
|
||||
Secondary,
|
||||
};
|
||||
|
||||
struct SaveDataDescriptor {
|
||||
u64_le title_id;
|
||||
u128 user_id;
|
||||
u64_le save_id;
|
||||
SaveDataType type;
|
||||
INSERT_PADDING_BYTES(7);
|
||||
SaveDataRank rank;
|
||||
u16_le index;
|
||||
INSERT_PADDING_BYTES(4);
|
||||
u64_le zero_1;
|
||||
u64_le zero_2;
|
||||
u64_le zero_3;
|
||||
@@ -57,7 +64,7 @@ public:
|
||||
explicit SaveDataFactory(VirtualDir dir);
|
||||
~SaveDataFactory();
|
||||
|
||||
ResultVal<VirtualDir> Open(SaveDataSpaceId space, SaveDataDescriptor meta);
|
||||
ResultVal<VirtualDir> Open(SaveDataSpaceId space, const SaveDataDescriptor& meta);
|
||||
|
||||
VirtualDir GetSaveDataSpaceDirectory(SaveDataSpaceId space) const;
|
||||
|
||||
|
||||
@@ -1030,7 +1030,7 @@ static void Step() {
|
||||
|
||||
/// Tell the CPU if we hit a memory breakpoint.
|
||||
bool IsMemoryBreak() {
|
||||
if (IsConnected()) {
|
||||
if (!IsConnected()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -139,10 +139,8 @@ public:
|
||||
context->AddDomainObject(std::move(iface));
|
||||
} else {
|
||||
auto& kernel = Core::System::GetInstance().Kernel();
|
||||
auto sessions =
|
||||
auto [server, client] =
|
||||
Kernel::ServerSession::CreateSessionPair(kernel, 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));
|
||||
}
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <tuple>
|
||||
|
||||
#include "core/hle/kernel/client_port.h"
|
||||
#include "core/hle/kernel/client_session.h"
|
||||
#include "core/hle/kernel/errors.h"
|
||||
@@ -31,18 +29,18 @@ ResultVal<SharedPtr<ClientSession>> ClientPort::Connect() {
|
||||
active_sessions++;
|
||||
|
||||
// Create a new session pair, let the created sessions inherit the parent port's HLE handler.
|
||||
auto sessions = ServerSession::CreateSessionPair(kernel, server_port->GetName(), this);
|
||||
auto [server, client] = ServerSession::CreateSessionPair(kernel, server_port->GetName(), this);
|
||||
|
||||
if (server_port->HasHLEHandler()) {
|
||||
server_port->GetHLEHandler()->ClientConnected(std::get<SharedPtr<ServerSession>>(sessions));
|
||||
server_port->GetHLEHandler()->ClientConnected(server);
|
||||
} else {
|
||||
server_port->AppendPendingSession(std::get<SharedPtr<ServerSession>>(sessions));
|
||||
server_port->AppendPendingSession(server);
|
||||
}
|
||||
|
||||
// Wake the threads waiting on the ServerPort
|
||||
server_port->WakeupAllWaitingThreads();
|
||||
|
||||
return MakeResult(std::get<SharedPtr<ClientSession>>(sessions));
|
||||
return MakeResult(client);
|
||||
}
|
||||
|
||||
void ClientPort::ConnectionClosed() {
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "core/hle/kernel/thread.h"
|
||||
#include "core/hle/lock.h"
|
||||
#include "core/hle/result.h"
|
||||
#include "core/memory.h"
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
@@ -115,7 +116,7 @@ struct KernelCore::Impl {
|
||||
|
||||
// Creates the default system resource limit
|
||||
void InitializeSystemResourceLimit(KernelCore& kernel) {
|
||||
system_resource_limit = ResourceLimit::Create(kernel, "System");
|
||||
system_resource_limit = ResourceLimit::Create(kernel);
|
||||
|
||||
// If setting the default system values fails, then something seriously wrong has occurred.
|
||||
ASSERT(system_resource_limit->SetLimitValue(ResourceType::PhysicalMemory, 0x200000000)
|
||||
@@ -181,6 +182,7 @@ void KernelCore::AppendNewProcess(SharedPtr<Process> process) {
|
||||
|
||||
void KernelCore::MakeCurrentProcess(Process* process) {
|
||||
impl->current_process = process;
|
||||
Memory::SetCurrentPageTable(&process->VMManager().page_table);
|
||||
}
|
||||
|
||||
Process* KernelCore::CurrentProcess() {
|
||||
@@ -191,6 +193,10 @@ const Process* KernelCore::CurrentProcess() const {
|
||||
return impl->current_process;
|
||||
}
|
||||
|
||||
const std::vector<SharedPtr<Process>>& KernelCore::GetProcessList() const {
|
||||
return impl->process_list;
|
||||
}
|
||||
|
||||
void KernelCore::AddNamedPort(std::string name, SharedPtr<ClientPort> port) {
|
||||
impl->named_ports.emplace(std::move(name), std::move(port));
|
||||
}
|
||||
|
||||
@@ -72,6 +72,9 @@ public:
|
||||
/// Retrieves a const pointer to the current process.
|
||||
const Process* CurrentProcess() const;
|
||||
|
||||
/// Retrieves the list of processes.
|
||||
const std::vector<SharedPtr<Process>>& GetProcessList() const;
|
||||
|
||||
/// Adds a port to the named port table
|
||||
void AddNamedPort(std::string name, SharedPtr<ClientPort> port);
|
||||
|
||||
|
||||
@@ -24,7 +24,6 @@ bool Object::IsWaitable() const {
|
||||
case HandleType::WritableEvent:
|
||||
case HandleType::SharedMemory:
|
||||
case HandleType::TransferMemory:
|
||||
case HandleType::AddressArbiter:
|
||||
case HandleType::ResourceLimit:
|
||||
case HandleType::ClientPort:
|
||||
case HandleType::ClientSession:
|
||||
|
||||
@@ -25,7 +25,6 @@ enum class HandleType : u32 {
|
||||
TransferMemory,
|
||||
Thread,
|
||||
Process,
|
||||
AddressArbiter,
|
||||
ResourceLimit,
|
||||
ClientPort,
|
||||
ServerPort,
|
||||
|
||||
@@ -32,9 +32,6 @@ namespace {
|
||||
* @param priority The priority to give the main thread
|
||||
*/
|
||||
void SetupMainThread(Process& owner_process, KernelCore& kernel, VAddr entry_point, u32 priority) {
|
||||
// Setup page table so we can write to memory
|
||||
Memory::SetCurrentPageTable(&owner_process.VMManager().page_table);
|
||||
|
||||
// Initialize new "main" thread
|
||||
const VAddr stack_top = owner_process.VMManager().GetTLSIORegionEndAddress();
|
||||
auto thread_res = Thread::Create(kernel, "main", entry_point, priority, 0,
|
||||
@@ -80,6 +77,14 @@ u64 Process::GetTotalPhysicalMemoryUsed() const {
|
||||
return vm_manager.GetCurrentHeapSize() + main_thread_stack_size + code_memory_size;
|
||||
}
|
||||
|
||||
void Process::RegisterThread(const Thread* thread) {
|
||||
thread_list.push_back(thread);
|
||||
}
|
||||
|
||||
void Process::UnregisterThread(const Thread* thread) {
|
||||
thread_list.remove(thread);
|
||||
}
|
||||
|
||||
ResultCode Process::ClearSignalState() {
|
||||
if (status == ProcessStatus::Exited) {
|
||||
LOG_ERROR(Kernel, "called on a terminated process instance.");
|
||||
@@ -249,7 +254,7 @@ void Process::Acquire(Thread* thread) {
|
||||
ASSERT_MSG(!ShouldWait(thread), "Object unavailable!");
|
||||
}
|
||||
|
||||
bool Process::ShouldWait(Thread* thread) const {
|
||||
bool Process::ShouldWait(const Thread* thread) const {
|
||||
return !is_signaled;
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <array>
|
||||
#include <bitset>
|
||||
#include <cstddef>
|
||||
#include <list>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <boost/container/static_vector.hpp>
|
||||
@@ -189,6 +190,19 @@ public:
|
||||
/// Retrieves the total physical memory used by this process in bytes.
|
||||
u64 GetTotalPhysicalMemoryUsed() const;
|
||||
|
||||
/// Gets the list of all threads created with this process as their owner.
|
||||
const std::list<const Thread*>& GetThreadList() const {
|
||||
return thread_list;
|
||||
}
|
||||
|
||||
/// Registers a thread as being created under this process,
|
||||
/// adding it to this process' thread list.
|
||||
void RegisterThread(const Thread* thread);
|
||||
|
||||
/// Unregisters a thread from this process, removing it
|
||||
/// from this process' thread list.
|
||||
void UnregisterThread(const Thread* thread);
|
||||
|
||||
/// Clears the signaled state of the process if and only if it's signaled.
|
||||
///
|
||||
/// @pre The process must not be already terminated. If this is called on a
|
||||
@@ -237,7 +251,7 @@ private:
|
||||
~Process() override;
|
||||
|
||||
/// Checks if the specified thread should wait until this process is available.
|
||||
bool ShouldWait(Thread* thread) const override;
|
||||
bool ShouldWait(const Thread* thread) const override;
|
||||
|
||||
/// Acquires/locks this process for the specified thread if it's available.
|
||||
void Acquire(Thread* thread) override;
|
||||
@@ -308,6 +322,9 @@ private:
|
||||
/// Random values for svcGetInfo RandomEntropy
|
||||
std::array<u64, RANDOM_ENTROPY_SIZE> random_entropy;
|
||||
|
||||
/// List of threads that are running with this process as their owner.
|
||||
std::list<const Thread*> thread_list;
|
||||
|
||||
/// System context
|
||||
Core::System& system;
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ namespace Kernel {
|
||||
ReadableEvent::ReadableEvent(KernelCore& kernel) : WaitObject{kernel} {}
|
||||
ReadableEvent::~ReadableEvent() = default;
|
||||
|
||||
bool ReadableEvent::ShouldWait(Thread* thread) const {
|
||||
bool ReadableEvent::ShouldWait(const Thread* thread) const {
|
||||
return !signaled;
|
||||
}
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ public:
|
||||
return HANDLE_TYPE;
|
||||
}
|
||||
|
||||
bool ShouldWait(Thread* thread) const override;
|
||||
bool ShouldWait(const Thread* thread) const override;
|
||||
void Acquire(Thread* thread) override;
|
||||
|
||||
/// Unconditionally clears the readable event's state.
|
||||
|
||||
@@ -16,11 +16,8 @@ constexpr std::size_t ResourceTypeToIndex(ResourceType type) {
|
||||
ResourceLimit::ResourceLimit(KernelCore& kernel) : Object{kernel} {}
|
||||
ResourceLimit::~ResourceLimit() = default;
|
||||
|
||||
SharedPtr<ResourceLimit> ResourceLimit::Create(KernelCore& kernel, std::string name) {
|
||||
SharedPtr<ResourceLimit> resource_limit(new ResourceLimit(kernel));
|
||||
|
||||
resource_limit->name = std::move(name);
|
||||
return resource_limit;
|
||||
SharedPtr<ResourceLimit> ResourceLimit::Create(KernelCore& kernel) {
|
||||
return new ResourceLimit(kernel);
|
||||
}
|
||||
|
||||
s64 ResourceLimit::GetCurrentResourceValue(ResourceType resource) const {
|
||||
|
||||
@@ -31,16 +31,14 @@ constexpr bool IsValidResourceType(ResourceType type) {
|
||||
|
||||
class ResourceLimit final : public Object {
|
||||
public:
|
||||
/**
|
||||
* Creates a resource limit object.
|
||||
*/
|
||||
static SharedPtr<ResourceLimit> Create(KernelCore& kernel, std::string name = "Unknown");
|
||||
/// Creates a resource limit object.
|
||||
static SharedPtr<ResourceLimit> Create(KernelCore& kernel);
|
||||
|
||||
std::string GetTypeName() const override {
|
||||
return "ResourceLimit";
|
||||
}
|
||||
std::string GetName() const override {
|
||||
return name;
|
||||
return GetTypeName();
|
||||
}
|
||||
|
||||
static const HandleType HANDLE_TYPE = HandleType::ResourceLimit;
|
||||
@@ -95,9 +93,6 @@ private:
|
||||
ResourceArray limits{};
|
||||
/// Current resource limit values.
|
||||
ResourceArray values{};
|
||||
|
||||
/// Name of resource limit object.
|
||||
std::string name;
|
||||
};
|
||||
|
||||
} // namespace Kernel
|
||||
|
||||
@@ -101,7 +101,6 @@ void Scheduler::SwitchContext(Thread* new_thread) {
|
||||
auto* const thread_owner_process = current_thread->GetOwnerProcess();
|
||||
if (previous_process != thread_owner_process) {
|
||||
system.Kernel().MakeCurrentProcess(thread_owner_process);
|
||||
Memory::SetCurrentPageTable(&thread_owner_process->VMManager().page_table);
|
||||
}
|
||||
|
||||
cpu_core.LoadContext(new_thread->GetContext());
|
||||
|
||||
@@ -30,7 +30,7 @@ void ServerPort::AppendPendingSession(SharedPtr<ServerSession> pending_session)
|
||||
pending_sessions.push_back(std::move(pending_session));
|
||||
}
|
||||
|
||||
bool ServerPort::ShouldWait(Thread* thread) const {
|
||||
bool ServerPort::ShouldWait(const Thread* thread) const {
|
||||
// If there are no pending sessions, we wait until a new one is added.
|
||||
return pending_sessions.empty();
|
||||
}
|
||||
@@ -39,9 +39,8 @@ void ServerPort::Acquire(Thread* thread) {
|
||||
ASSERT_MSG(!ShouldWait(thread), "object unavailable!");
|
||||
}
|
||||
|
||||
std::tuple<SharedPtr<ServerPort>, SharedPtr<ClientPort>> ServerPort::CreatePortPair(
|
||||
KernelCore& kernel, u32 max_sessions, std::string name) {
|
||||
|
||||
ServerPort::PortPair ServerPort::CreatePortPair(KernelCore& kernel, u32 max_sessions,
|
||||
std::string name) {
|
||||
SharedPtr<ServerPort> server_port(new ServerPort(kernel));
|
||||
SharedPtr<ClientPort> client_port(new ClientPort(kernel));
|
||||
|
||||
@@ -51,7 +50,7 @@ std::tuple<SharedPtr<ServerPort>, SharedPtr<ClientPort>> ServerPort::CreatePortP
|
||||
client_port->max_sessions = max_sessions;
|
||||
client_port->active_sessions = 0;
|
||||
|
||||
return std::make_tuple(std::move(server_port), std::move(client_port));
|
||||
return std::make_pair(std::move(server_port), std::move(client_port));
|
||||
}
|
||||
|
||||
} // namespace Kernel
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include "common/common_types.h"
|
||||
#include "core/hle/kernel/object.h"
|
||||
@@ -23,6 +23,7 @@ class SessionRequestHandler;
|
||||
class ServerPort final : public WaitObject {
|
||||
public:
|
||||
using HLEHandler = std::shared_ptr<SessionRequestHandler>;
|
||||
using PortPair = std::pair<SharedPtr<ServerPort>, SharedPtr<ClientPort>>;
|
||||
|
||||
/**
|
||||
* Creates a pair of ServerPort and an associated ClientPort.
|
||||
@@ -32,8 +33,8 @@ public:
|
||||
* @param name Optional name of the ports
|
||||
* @return The created port tuple
|
||||
*/
|
||||
static std::tuple<SharedPtr<ServerPort>, SharedPtr<ClientPort>> CreatePortPair(
|
||||
KernelCore& kernel, u32 max_sessions, std::string name = "UnknownPort");
|
||||
static PortPair CreatePortPair(KernelCore& kernel, u32 max_sessions,
|
||||
std::string name = "UnknownPort");
|
||||
|
||||
std::string GetTypeName() const override {
|
||||
return "ServerPort";
|
||||
@@ -75,7 +76,7 @@ public:
|
||||
/// waiting to be accepted by this port.
|
||||
void AppendPendingSession(SharedPtr<ServerSession> pending_session);
|
||||
|
||||
bool ShouldWait(Thread* thread) const override;
|
||||
bool ShouldWait(const Thread* thread) const override;
|
||||
void Acquire(Thread* thread) override;
|
||||
|
||||
private:
|
||||
|
||||
@@ -46,7 +46,7 @@ ResultVal<SharedPtr<ServerSession>> ServerSession::Create(KernelCore& kernel, st
|
||||
return MakeResult(std::move(server_session));
|
||||
}
|
||||
|
||||
bool ServerSession::ShouldWait(Thread* thread) const {
|
||||
bool ServerSession::ShouldWait(const Thread* thread) const {
|
||||
// Closed sessions should never wait, an error will be returned from svcReplyAndReceive.
|
||||
if (parent->client == nullptr)
|
||||
return false;
|
||||
@@ -204,6 +204,6 @@ ServerSession::SessionPair ServerSession::CreateSessionPair(KernelCore& kernel,
|
||||
client_session->parent = parent;
|
||||
server_session->parent = parent;
|
||||
|
||||
return std::make_tuple(std::move(server_session), std::move(client_session));
|
||||
return std::make_pair(std::move(server_session), std::move(client_session));
|
||||
}
|
||||
} // namespace Kernel
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "core/hle/kernel/object.h"
|
||||
@@ -41,6 +42,10 @@ public:
|
||||
return "ServerSession";
|
||||
}
|
||||
|
||||
std::string GetName() const override {
|
||||
return name;
|
||||
}
|
||||
|
||||
static const HandleType HANDLE_TYPE = HandleType::ServerSession;
|
||||
HandleType GetHandleType() const override {
|
||||
return HANDLE_TYPE;
|
||||
@@ -54,7 +59,7 @@ public:
|
||||
return parent.get();
|
||||
}
|
||||
|
||||
using SessionPair = std::tuple<SharedPtr<ServerSession>, SharedPtr<ClientSession>>;
|
||||
using SessionPair = std::pair<SharedPtr<ServerSession>, SharedPtr<ClientSession>>;
|
||||
|
||||
/**
|
||||
* Creates a pair of ServerSession and an associated ClientSession.
|
||||
@@ -82,7 +87,7 @@ public:
|
||||
*/
|
||||
ResultCode HandleSyncRequest(SharedPtr<Thread> thread);
|
||||
|
||||
bool ShouldWait(Thread* thread) const override;
|
||||
bool ShouldWait(const Thread* thread) const override;
|
||||
|
||||
void Acquire(Thread* thread) override;
|
||||
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
#include "core/hle/kernel/errors.h"
|
||||
#include "core/hle/kernel/kernel.h"
|
||||
#include "core/hle/kernel/shared_memory.h"
|
||||
#include "core/memory.h"
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
@@ -119,7 +118,15 @@ ResultCode SharedMemory::Map(Process& target_process, VAddr address, MemoryPermi
|
||||
ConvertPermissions(permissions));
|
||||
}
|
||||
|
||||
ResultCode SharedMemory::Unmap(Process& target_process, VAddr address) {
|
||||
ResultCode SharedMemory::Unmap(Process& target_process, VAddr address, u64 unmap_size) {
|
||||
if (unmap_size != size) {
|
||||
LOG_ERROR(Kernel,
|
||||
"Invalid size passed to Unmap. Size must be equal to the size of the "
|
||||
"memory managed. Shared memory size=0x{:016X}, Unmap size=0x{:016X}",
|
||||
size, unmap_size);
|
||||
return ERR_INVALID_SIZE;
|
||||
}
|
||||
|
||||
// TODO(Subv): Verify what happens if the application tries to unmap an address that is not
|
||||
// mapped to a SharedMemory.
|
||||
return target_process.VMManager().UnmapRange(address, size);
|
||||
|
||||
@@ -104,11 +104,17 @@ public:
|
||||
|
||||
/**
|
||||
* Unmaps a shared memory block from the specified address in system memory
|
||||
*
|
||||
* @param target_process Process from which to unmap the memory block.
|
||||
* @param address Address in system memory where the shared memory block is mapped
|
||||
* @param address Address in system memory where the shared memory block is mapped.
|
||||
* @param unmap_size The amount of bytes to unmap from this shared memory instance.
|
||||
*
|
||||
* @return Result code of the unmap operation
|
||||
*
|
||||
* @pre The given size to unmap must be the same size as the amount of memory managed by
|
||||
* the SharedMemory instance itself, otherwise ERR_INVALID_SIZE will be returned.
|
||||
*/
|
||||
ResultCode Unmap(Process& target_process, VAddr address);
|
||||
ResultCode Unmap(Process& target_process, VAddr address, u64 unmap_size);
|
||||
|
||||
/**
|
||||
* Gets a pointer to the shared memory block
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -6,8 +6,12 @@
|
||||
|
||||
#include "common/common_types.h"
|
||||
|
||||
namespace Core {
|
||||
class System;
|
||||
}
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
void CallSVC(u32 immediate);
|
||||
void CallSVC(Core::System& system, u32 immediate);
|
||||
|
||||
} // namespace Kernel
|
||||
|
||||
@@ -11,270 +11,312 @@
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
static inline u64 Param(int n) {
|
||||
return Core::CurrentArmInterface().GetReg(n);
|
||||
static inline u64 Param(const Core::System& system, int n) {
|
||||
return system.CurrentArmInterface().GetReg(n);
|
||||
}
|
||||
|
||||
/**
|
||||
* HLE a function return from the current ARM userland process
|
||||
* @param res Result to return
|
||||
* @param system System context
|
||||
* @param result Result to return
|
||||
*/
|
||||
static inline void FuncReturn(u64 res) {
|
||||
Core::CurrentArmInterface().SetReg(0, res);
|
||||
static inline void FuncReturn(Core::System& system, u64 result) {
|
||||
system.CurrentArmInterface().SetReg(0, result);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Function wrappers that return type ResultCode
|
||||
|
||||
template <ResultCode func(u64)>
|
||||
void SvcWrap() {
|
||||
FuncReturn(func(Param(0)).raw);
|
||||
template <ResultCode func(Core::System&, u64)>
|
||||
void SvcWrap(Core::System& system) {
|
||||
FuncReturn(system, func(system, Param(system, 0)).raw);
|
||||
}
|
||||
|
||||
template <ResultCode func(u32)>
|
||||
void SvcWrap() {
|
||||
FuncReturn(func(static_cast<u32>(Param(0))).raw);
|
||||
template <ResultCode func(Core::System&, u32)>
|
||||
void SvcWrap(Core::System& system) {
|
||||
FuncReturn(system, func(system, static_cast<u32>(Param(system, 0))).raw);
|
||||
}
|
||||
|
||||
template <ResultCode func(u32, u32)>
|
||||
void SvcWrap() {
|
||||
FuncReturn(func(static_cast<u32>(Param(0)), static_cast<u32>(Param(1))).raw);
|
||||
template <ResultCode func(Core::System&, u32, u32)>
|
||||
void SvcWrap(Core::System& system) {
|
||||
FuncReturn(
|
||||
system,
|
||||
func(system, static_cast<u32>(Param(system, 0)), static_cast<u32>(Param(system, 1))).raw);
|
||||
}
|
||||
|
||||
template <ResultCode func(u32*)>
|
||||
void SvcWrap() {
|
||||
template <ResultCode func(Core::System&, u32*)>
|
||||
void SvcWrap(Core::System& system) {
|
||||
u32 param = 0;
|
||||
const u32 retval = func(¶m).raw;
|
||||
Core::CurrentArmInterface().SetReg(1, param);
|
||||
FuncReturn(retval);
|
||||
const u32 retval = func(system, ¶m).raw;
|
||||
system.CurrentArmInterface().SetReg(1, param);
|
||||
FuncReturn(system, retval);
|
||||
}
|
||||
|
||||
template <ResultCode func(u32*, u32)>
|
||||
void SvcWrap() {
|
||||
template <ResultCode func(Core::System&, u32*, u32)>
|
||||
void SvcWrap(Core::System& system) {
|
||||
u32 param_1 = 0;
|
||||
u32 retval = func(¶m_1, static_cast<u32>(Param(1))).raw;
|
||||
Core::CurrentArmInterface().SetReg(1, param_1);
|
||||
FuncReturn(retval);
|
||||
const u32 retval = func(system, ¶m_1, static_cast<u32>(Param(system, 1))).raw;
|
||||
system.CurrentArmInterface().SetReg(1, param_1);
|
||||
FuncReturn(system, retval);
|
||||
}
|
||||
|
||||
template <ResultCode func(u32*, u32*)>
|
||||
void SvcWrap() {
|
||||
template <ResultCode func(Core::System&, u32*, u32*)>
|
||||
void SvcWrap(Core::System& system) {
|
||||
u32 param_1 = 0;
|
||||
u32 param_2 = 0;
|
||||
const u32 retval = func(¶m_1, ¶m_2).raw;
|
||||
const u32 retval = func(system, ¶m_1, ¶m_2).raw;
|
||||
|
||||
auto& arm_interface = Core::CurrentArmInterface();
|
||||
auto& arm_interface = system.CurrentArmInterface();
|
||||
arm_interface.SetReg(1, param_1);
|
||||
arm_interface.SetReg(2, param_2);
|
||||
|
||||
FuncReturn(retval);
|
||||
FuncReturn(system, retval);
|
||||
}
|
||||
|
||||
template <ResultCode func(u32*, u64)>
|
||||
void SvcWrap() {
|
||||
template <ResultCode func(Core::System&, u32*, u64)>
|
||||
void SvcWrap(Core::System& system) {
|
||||
u32 param_1 = 0;
|
||||
const u32 retval = func(¶m_1, Param(1)).raw;
|
||||
Core::CurrentArmInterface().SetReg(1, param_1);
|
||||
FuncReturn(retval);
|
||||
const u32 retval = func(system, ¶m_1, Param(system, 1)).raw;
|
||||
system.CurrentArmInterface().SetReg(1, param_1);
|
||||
FuncReturn(system, retval);
|
||||
}
|
||||
|
||||
template <ResultCode func(u64*, u32)>
|
||||
void SvcWrap() {
|
||||
template <ResultCode func(Core::System&, u32*, u64, u32)>
|
||||
void SvcWrap(Core::System& system) {
|
||||
u32 param_1 = 0;
|
||||
const u32 retval =
|
||||
func(system, ¶m_1, Param(system, 1), static_cast<u32>(Param(system, 2))).raw;
|
||||
|
||||
system.CurrentArmInterface().SetReg(1, param_1);
|
||||
FuncReturn(system, retval);
|
||||
}
|
||||
|
||||
template <ResultCode func(Core::System&, u64*, u32)>
|
||||
void SvcWrap(Core::System& system) {
|
||||
u64 param_1 = 0;
|
||||
const u32 retval = func(¶m_1, static_cast<u32>(Param(1))).raw;
|
||||
Core::CurrentArmInterface().SetReg(1, param_1);
|
||||
FuncReturn(retval);
|
||||
const u32 retval = func(system, ¶m_1, static_cast<u32>(Param(system, 1))).raw;
|
||||
|
||||
system.CurrentArmInterface().SetReg(1, param_1);
|
||||
FuncReturn(system, retval);
|
||||
}
|
||||
|
||||
template <ResultCode func(u64, s32)>
|
||||
void SvcWrap() {
|
||||
FuncReturn(func(Param(0), static_cast<s32>(Param(1))).raw);
|
||||
template <ResultCode func(Core::System&, u64, s32)>
|
||||
void SvcWrap(Core::System& system) {
|
||||
FuncReturn(system, func(system, Param(system, 0), static_cast<s32>(Param(system, 1))).raw);
|
||||
}
|
||||
|
||||
template <ResultCode func(u64, u32)>
|
||||
void SvcWrap() {
|
||||
FuncReturn(func(Param(0), static_cast<u32>(Param(1))).raw);
|
||||
template <ResultCode func(Core::System&, u64, u32)>
|
||||
void SvcWrap(Core::System& system) {
|
||||
FuncReturn(system, func(system, Param(system, 0), static_cast<u32>(Param(system, 1))).raw);
|
||||
}
|
||||
|
||||
template <ResultCode func(u64*, u64)>
|
||||
void SvcWrap() {
|
||||
template <ResultCode func(Core::System&, u64*, u64)>
|
||||
void SvcWrap(Core::System& system) {
|
||||
u64 param_1 = 0;
|
||||
u32 retval = func(¶m_1, Param(1)).raw;
|
||||
Core::CurrentArmInterface().SetReg(1, param_1);
|
||||
FuncReturn(retval);
|
||||
const u32 retval = func(system, ¶m_1, Param(system, 1)).raw;
|
||||
|
||||
system.CurrentArmInterface().SetReg(1, param_1);
|
||||
FuncReturn(system, retval);
|
||||
}
|
||||
|
||||
template <ResultCode func(u64*, u32, u32)>
|
||||
void SvcWrap() {
|
||||
template <ResultCode func(Core::System&, u64*, u32, u32)>
|
||||
void SvcWrap(Core::System& system) {
|
||||
u64 param_1 = 0;
|
||||
u32 retval = func(¶m_1, static_cast<u32>(Param(1)), static_cast<u32>(Param(2))).raw;
|
||||
Core::CurrentArmInterface().SetReg(1, param_1);
|
||||
FuncReturn(retval);
|
||||
const u32 retval = func(system, ¶m_1, static_cast<u32>(Param(system, 1)),
|
||||
static_cast<u32>(Param(system, 2)))
|
||||
.raw;
|
||||
|
||||
system.CurrentArmInterface().SetReg(1, param_1);
|
||||
FuncReturn(system, retval);
|
||||
}
|
||||
|
||||
template <ResultCode func(u32, u64)>
|
||||
void SvcWrap() {
|
||||
FuncReturn(func(static_cast<u32>(Param(0)), Param(1)).raw);
|
||||
template <ResultCode func(Core::System&, u32, u64)>
|
||||
void SvcWrap(Core::System& system) {
|
||||
FuncReturn(system, func(system, static_cast<u32>(Param(system, 0)), Param(system, 1)).raw);
|
||||
}
|
||||
|
||||
template <ResultCode func(u32, u32, u64)>
|
||||
void SvcWrap() {
|
||||
FuncReturn(func(static_cast<u32>(Param(0)), static_cast<u32>(Param(1)), Param(2)).raw);
|
||||
template <ResultCode func(Core::System&, u32, u32, u64)>
|
||||
void SvcWrap(Core::System& system) {
|
||||
FuncReturn(system, func(system, static_cast<u32>(Param(system, 0)),
|
||||
static_cast<u32>(Param(system, 1)), Param(system, 2))
|
||||
.raw);
|
||||
}
|
||||
|
||||
template <ResultCode func(u32, u32*, u64*)>
|
||||
void SvcWrap() {
|
||||
template <ResultCode func(Core::System&, u32, u32*, u64*)>
|
||||
void SvcWrap(Core::System& system) {
|
||||
u32 param_1 = 0;
|
||||
u64 param_2 = 0;
|
||||
ResultCode retval = func(static_cast<u32>(Param(2)), ¶m_1, ¶m_2);
|
||||
Core::CurrentArmInterface().SetReg(1, param_1);
|
||||
Core::CurrentArmInterface().SetReg(2, param_2);
|
||||
FuncReturn(retval.raw);
|
||||
const ResultCode retval = func(system, static_cast<u32>(Param(system, 2)), ¶m_1, ¶m_2);
|
||||
|
||||
system.CurrentArmInterface().SetReg(1, param_1);
|
||||
system.CurrentArmInterface().SetReg(2, param_2);
|
||||
FuncReturn(system, retval.raw);
|
||||
}
|
||||
|
||||
template <ResultCode func(u64, u64, u32, u32)>
|
||||
void SvcWrap() {
|
||||
template <ResultCode func(Core::System&, u64, u64, u32, u32)>
|
||||
void SvcWrap(Core::System& system) {
|
||||
FuncReturn(system, func(system, Param(system, 0), Param(system, 1),
|
||||
static_cast<u32>(Param(system, 2)), static_cast<u32>(Param(system, 3)))
|
||||
.raw);
|
||||
}
|
||||
|
||||
template <ResultCode func(Core::System&, u64, u64, u32, u64)>
|
||||
void SvcWrap(Core::System& system) {
|
||||
FuncReturn(system, func(system, Param(system, 0), Param(system, 1),
|
||||
static_cast<u32>(Param(system, 2)), Param(system, 3))
|
||||
.raw);
|
||||
}
|
||||
|
||||
template <ResultCode func(Core::System&, u32, u64, u32)>
|
||||
void SvcWrap(Core::System& system) {
|
||||
FuncReturn(system, func(system, static_cast<u32>(Param(system, 0)), Param(system, 1),
|
||||
static_cast<u32>(Param(system, 2)))
|
||||
.raw);
|
||||
}
|
||||
|
||||
template <ResultCode func(Core::System&, u64, u64, u64)>
|
||||
void SvcWrap(Core::System& system) {
|
||||
FuncReturn(system, func(system, Param(system, 0), Param(system, 1), Param(system, 2)).raw);
|
||||
}
|
||||
|
||||
template <ResultCode func(Core::System&, u64, u64, u32)>
|
||||
void SvcWrap(Core::System& system) {
|
||||
FuncReturn(
|
||||
func(Param(0), Param(1), static_cast<u32>(Param(2)), static_cast<u32>(Param(3))).raw);
|
||||
system,
|
||||
func(system, Param(system, 0), Param(system, 1), static_cast<u32>(Param(system, 2))).raw);
|
||||
}
|
||||
|
||||
template <ResultCode func(u64, u64, u32, u64)>
|
||||
void SvcWrap() {
|
||||
FuncReturn(func(Param(0), Param(1), static_cast<u32>(Param(2)), Param(3)).raw);
|
||||
template <ResultCode func(Core::System&, u32, u64, u64, u32)>
|
||||
void SvcWrap(Core::System& system) {
|
||||
FuncReturn(system, func(system, static_cast<u32>(Param(system, 0)), Param(system, 1),
|
||||
Param(system, 2), static_cast<u32>(Param(system, 3)))
|
||||
.raw);
|
||||
}
|
||||
|
||||
template <ResultCode func(u32, u64, u32)>
|
||||
void SvcWrap() {
|
||||
FuncReturn(func(static_cast<u32>(Param(0)), Param(1), static_cast<u32>(Param(2))).raw);
|
||||
}
|
||||
|
||||
template <ResultCode func(u64, u64, u64)>
|
||||
void SvcWrap() {
|
||||
FuncReturn(func(Param(0), Param(1), Param(2)).raw);
|
||||
}
|
||||
|
||||
template <ResultCode func(u64, u64, u32)>
|
||||
void SvcWrap() {
|
||||
FuncReturn(func(Param(0), Param(1), static_cast<u32>(Param(2))).raw);
|
||||
}
|
||||
|
||||
template <ResultCode func(u32, u64, u64, u32)>
|
||||
void SvcWrap() {
|
||||
template <ResultCode func(Core::System&, u32, u64, u64)>
|
||||
void SvcWrap(Core::System& system) {
|
||||
FuncReturn(
|
||||
func(static_cast<u32>(Param(0)), Param(1), Param(2), static_cast<u32>(Param(3))).raw);
|
||||
system,
|
||||
func(system, static_cast<u32>(Param(system, 0)), Param(system, 1), Param(system, 2)).raw);
|
||||
}
|
||||
|
||||
template <ResultCode func(u32, u64, u64)>
|
||||
void SvcWrap() {
|
||||
FuncReturn(func(static_cast<u32>(Param(0)), Param(1), Param(2)).raw);
|
||||
}
|
||||
|
||||
template <ResultCode func(u32*, u64, u64, s64)>
|
||||
void SvcWrap() {
|
||||
template <ResultCode func(Core::System&, u32*, u64, u64, s64)>
|
||||
void SvcWrap(Core::System& system) {
|
||||
u32 param_1 = 0;
|
||||
ResultCode retval =
|
||||
func(¶m_1, Param(1), static_cast<u32>(Param(2)), static_cast<s64>(Param(3)));
|
||||
Core::CurrentArmInterface().SetReg(1, param_1);
|
||||
FuncReturn(retval.raw);
|
||||
const u32 retval = func(system, ¶m_1, Param(system, 1), static_cast<u32>(Param(system, 2)),
|
||||
static_cast<s64>(Param(system, 3)))
|
||||
.raw;
|
||||
|
||||
system.CurrentArmInterface().SetReg(1, param_1);
|
||||
FuncReturn(system, retval);
|
||||
}
|
||||
|
||||
template <ResultCode func(u64, u64, u32, s64)>
|
||||
void SvcWrap() {
|
||||
FuncReturn(
|
||||
func(Param(0), Param(1), static_cast<u32>(Param(2)), static_cast<s64>(Param(3))).raw);
|
||||
template <ResultCode func(Core::System&, u64, u64, u32, s64)>
|
||||
void SvcWrap(Core::System& system) {
|
||||
FuncReturn(system, func(system, Param(system, 0), Param(system, 1),
|
||||
static_cast<u32>(Param(system, 2)), static_cast<s64>(Param(system, 3)))
|
||||
.raw);
|
||||
}
|
||||
|
||||
template <ResultCode func(u64*, u64, u64, u64)>
|
||||
void SvcWrap() {
|
||||
template <ResultCode func(Core::System&, u64*, u64, u64, u64)>
|
||||
void SvcWrap(Core::System& system) {
|
||||
u64 param_1 = 0;
|
||||
u32 retval = func(¶m_1, Param(1), Param(2), Param(3)).raw;
|
||||
Core::CurrentArmInterface().SetReg(1, param_1);
|
||||
FuncReturn(retval);
|
||||
const u32 retval =
|
||||
func(system, ¶m_1, Param(system, 1), Param(system, 2), Param(system, 3)).raw;
|
||||
|
||||
system.CurrentArmInterface().SetReg(1, param_1);
|
||||
FuncReturn(system, retval);
|
||||
}
|
||||
|
||||
template <ResultCode func(u32*, u64, u64, u64, u32, s32)>
|
||||
void SvcWrap() {
|
||||
template <ResultCode func(Core::System&, u32*, u64, u64, u64, u32, s32)>
|
||||
void SvcWrap(Core::System& system) {
|
||||
u32 param_1 = 0;
|
||||
u32 retval = func(¶m_1, Param(1), Param(2), Param(3), static_cast<u32>(Param(4)),
|
||||
static_cast<s32>(Param(5)))
|
||||
.raw;
|
||||
Core::CurrentArmInterface().SetReg(1, param_1);
|
||||
FuncReturn(retval);
|
||||
const u32 retval = func(system, ¶m_1, Param(system, 1), Param(system, 2), Param(system, 3),
|
||||
static_cast<u32>(Param(system, 4)), static_cast<s32>(Param(system, 5)))
|
||||
.raw;
|
||||
|
||||
system.CurrentArmInterface().SetReg(1, param_1);
|
||||
FuncReturn(system, retval);
|
||||
}
|
||||
|
||||
template <ResultCode func(u32*, u64, u64, u32)>
|
||||
void SvcWrap() {
|
||||
template <ResultCode func(Core::System&, u32*, u64, u64, u32)>
|
||||
void SvcWrap(Core::System& system) {
|
||||
u32 param_1 = 0;
|
||||
u32 retval = func(¶m_1, Param(1), Param(2), static_cast<u32>(Param(3))).raw;
|
||||
Core::CurrentArmInterface().SetReg(1, param_1);
|
||||
FuncReturn(retval);
|
||||
const u32 retval = func(system, ¶m_1, Param(system, 1), Param(system, 2),
|
||||
static_cast<u32>(Param(system, 3)))
|
||||
.raw;
|
||||
|
||||
system.CurrentArmInterface().SetReg(1, param_1);
|
||||
FuncReturn(system, retval);
|
||||
}
|
||||
|
||||
template <ResultCode func(Handle*, u64, u32, u32)>
|
||||
void SvcWrap() {
|
||||
template <ResultCode func(Core::System&, Handle*, u64, u32, u32)>
|
||||
void SvcWrap(Core::System& system) {
|
||||
u32 param_1 = 0;
|
||||
u32 retval =
|
||||
func(¶m_1, Param(1), static_cast<u32>(Param(2)), static_cast<u32>(Param(3))).raw;
|
||||
Core::CurrentArmInterface().SetReg(1, param_1);
|
||||
FuncReturn(retval);
|
||||
const u32 retval = func(system, ¶m_1, Param(system, 1), static_cast<u32>(Param(system, 2)),
|
||||
static_cast<u32>(Param(system, 3)))
|
||||
.raw;
|
||||
|
||||
system.CurrentArmInterface().SetReg(1, param_1);
|
||||
FuncReturn(system, retval);
|
||||
}
|
||||
|
||||
template <ResultCode func(u64, u32, s32, s64)>
|
||||
void SvcWrap() {
|
||||
FuncReturn(func(Param(0), static_cast<u32>(Param(1)), static_cast<s32>(Param(2)),
|
||||
static_cast<s64>(Param(3)))
|
||||
.raw);
|
||||
template <ResultCode func(Core::System&, u64, u32, s32, s64)>
|
||||
void SvcWrap(Core::System& system) {
|
||||
FuncReturn(system, func(system, Param(system, 0), static_cast<u32>(Param(system, 1)),
|
||||
static_cast<s32>(Param(system, 2)), static_cast<s64>(Param(system, 3)))
|
||||
.raw);
|
||||
}
|
||||
|
||||
template <ResultCode func(u64, u32, s32, s32)>
|
||||
void SvcWrap() {
|
||||
FuncReturn(func(Param(0), static_cast<u32>(Param(1)), static_cast<s32>(Param(2)),
|
||||
static_cast<s32>(Param(3)))
|
||||
.raw);
|
||||
template <ResultCode func(Core::System&, u64, u32, s32, s32)>
|
||||
void SvcWrap(Core::System& system) {
|
||||
FuncReturn(system, func(system, Param(system, 0), static_cast<u32>(Param(system, 1)),
|
||||
static_cast<s32>(Param(system, 2)), static_cast<s32>(Param(system, 3)))
|
||||
.raw);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Function wrappers that return type u32
|
||||
|
||||
template <u32 func()>
|
||||
void SvcWrap() {
|
||||
FuncReturn(func());
|
||||
template <u32 func(Core::System&)>
|
||||
void SvcWrap(Core::System& system) {
|
||||
FuncReturn(system, func(system));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Function wrappers that return type u64
|
||||
|
||||
template <u64 func()>
|
||||
void SvcWrap() {
|
||||
FuncReturn(func());
|
||||
template <u64 func(Core::System&)>
|
||||
void SvcWrap(Core::System& system) {
|
||||
FuncReturn(system, func(system));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// Function wrappers that return type void
|
||||
|
||||
template <void func()>
|
||||
void SvcWrap() {
|
||||
func();
|
||||
template <void func(Core::System&)>
|
||||
void SvcWrap(Core::System& system) {
|
||||
func(system);
|
||||
}
|
||||
|
||||
template <void func(s64)>
|
||||
void SvcWrap() {
|
||||
func(static_cast<s64>(Param(0)));
|
||||
template <void func(Core::System&, s64)>
|
||||
void SvcWrap(Core::System& system) {
|
||||
func(system, static_cast<s64>(Param(system, 0)));
|
||||
}
|
||||
|
||||
template <void func(u64, u64 len)>
|
||||
void SvcWrap() {
|
||||
func(Param(0), Param(1));
|
||||
template <void func(Core::System&, u64, u64)>
|
||||
void SvcWrap(Core::System& system) {
|
||||
func(system, Param(system, 0), Param(system, 1));
|
||||
}
|
||||
|
||||
template <void func(u64, u64, u64)>
|
||||
void SvcWrap() {
|
||||
func(Param(0), Param(1), Param(2));
|
||||
template <void func(Core::System&, u64, u64, u64)>
|
||||
void SvcWrap(Core::System& system) {
|
||||
func(system, Param(system, 0), Param(system, 1), Param(system, 2));
|
||||
}
|
||||
|
||||
template <void func(u32, u64, u64)>
|
||||
void SvcWrap() {
|
||||
func(static_cast<u32>(Param(0)), Param(1), Param(2));
|
||||
template <void func(Core::System&, u32, u64, u64)>
|
||||
void SvcWrap(Core::System& system) {
|
||||
func(system, static_cast<u32>(Param(system, 0)), Param(system, 1), Param(system, 2));
|
||||
}
|
||||
|
||||
} // namespace Kernel
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
bool Thread::ShouldWait(Thread* thread) const {
|
||||
bool Thread::ShouldWait(const Thread* thread) const {
|
||||
return status != ThreadStatus::Dead;
|
||||
}
|
||||
|
||||
@@ -62,6 +62,8 @@ void Thread::Stop() {
|
||||
}
|
||||
wait_objects.clear();
|
||||
|
||||
owner_process->UnregisterThread(this);
|
||||
|
||||
// Mark the TLS slot in the thread's page as free.
|
||||
owner_process->FreeTLSSlot(tls_address);
|
||||
}
|
||||
@@ -202,6 +204,8 @@ ResultVal<SharedPtr<Thread>> Thread::Create(KernelCore& kernel, std::string name
|
||||
thread->scheduler->AddThread(thread);
|
||||
thread->tls_address = thread->owner_process->MarkNextAvailableTLSSlotAsUsed(*thread);
|
||||
|
||||
thread->owner_process->RegisterThread(thread.get());
|
||||
|
||||
// TODO(peachum): move to ScheduleThread() when scheduler is added so selected core is used
|
||||
// to initialize the context
|
||||
ResetThreadContext(thread->context, stack_top, entry_point, arg);
|
||||
@@ -229,16 +233,16 @@ void Thread::SetWaitSynchronizationOutput(s32 output) {
|
||||
context.cpu_registers[1] = output;
|
||||
}
|
||||
|
||||
s32 Thread::GetWaitObjectIndex(WaitObject* object) const {
|
||||
s32 Thread::GetWaitObjectIndex(const WaitObject* object) const {
|
||||
ASSERT_MSG(!wait_objects.empty(), "Thread is not waiting for anything");
|
||||
auto match = std::find(wait_objects.rbegin(), wait_objects.rend(), object);
|
||||
const auto match = std::find(wait_objects.rbegin(), wait_objects.rend(), object);
|
||||
return static_cast<s32>(std::distance(match, wait_objects.rend()) - 1);
|
||||
}
|
||||
|
||||
VAddr Thread::GetCommandBufferAddress() const {
|
||||
// Offset from the start of TLS at which the IPC command buffer begins.
|
||||
static constexpr int CommandHeaderOffset = 0x80;
|
||||
return GetTLSAddress() + CommandHeaderOffset;
|
||||
constexpr u64 command_header_offset = 0x80;
|
||||
return GetTLSAddress() + command_header_offset;
|
||||
}
|
||||
|
||||
void Thread::SetStatus(ThreadStatus new_status) {
|
||||
@@ -367,7 +371,7 @@ void Thread::ChangeScheduler() {
|
||||
system.CpuCore(processor_id).PrepareReschedule();
|
||||
}
|
||||
|
||||
bool Thread::AllWaitObjectsReady() {
|
||||
bool Thread::AllWaitObjectsReady() const {
|
||||
return std::none_of(
|
||||
wait_objects.begin(), wait_objects.end(),
|
||||
[this](const SharedPtr<WaitObject>& object) { return object->ShouldWait(this); });
|
||||
|
||||
@@ -111,7 +111,7 @@ public:
|
||||
return HANDLE_TYPE;
|
||||
}
|
||||
|
||||
bool ShouldWait(Thread* thread) const override;
|
||||
bool ShouldWait(const Thread* thread) const override;
|
||||
void Acquire(Thread* thread) override;
|
||||
|
||||
/**
|
||||
@@ -205,7 +205,7 @@ public:
|
||||
* object in the list.
|
||||
* @param object Object to query the index of.
|
||||
*/
|
||||
s32 GetWaitObjectIndex(WaitObject* object) const;
|
||||
s32 GetWaitObjectIndex(const WaitObject* object) const;
|
||||
|
||||
/**
|
||||
* Stops a thread, invalidating it from further use
|
||||
@@ -299,7 +299,7 @@ public:
|
||||
}
|
||||
|
||||
/// Determines whether all the objects this thread is waiting on are ready.
|
||||
bool AllWaitObjectsReady();
|
||||
bool AllWaitObjectsReady() const;
|
||||
|
||||
const MutexWaitingThreads& GetMutexWaitingThreads() const {
|
||||
return wait_mutex_threads;
|
||||
|
||||
@@ -14,8 +14,8 @@ namespace Kernel {
|
||||
TransferMemory::TransferMemory(KernelCore& kernel) : Object{kernel} {}
|
||||
TransferMemory::~TransferMemory() = default;
|
||||
|
||||
SharedPtr<TransferMemory> TransferMemory::Create(KernelCore& kernel, VAddr base_address,
|
||||
size_t size, MemoryPermission permissions) {
|
||||
SharedPtr<TransferMemory> TransferMemory::Create(KernelCore& kernel, VAddr base_address, u64 size,
|
||||
MemoryPermission permissions) {
|
||||
SharedPtr<TransferMemory> transfer_memory{new TransferMemory(kernel)};
|
||||
|
||||
transfer_memory->base_address = base_address;
|
||||
@@ -26,7 +26,15 @@ SharedPtr<TransferMemory> TransferMemory::Create(KernelCore& kernel, VAddr base_
|
||||
return transfer_memory;
|
||||
}
|
||||
|
||||
ResultCode TransferMemory::MapMemory(VAddr address, size_t size, MemoryPermission permissions) {
|
||||
const u8* TransferMemory::GetPointer() const {
|
||||
return backing_block.get()->data();
|
||||
}
|
||||
|
||||
u64 TransferMemory::GetSize() const {
|
||||
return memory_size;
|
||||
}
|
||||
|
||||
ResultCode TransferMemory::MapMemory(VAddr address, u64 size, MemoryPermission permissions) {
|
||||
if (memory_size != size) {
|
||||
return ERR_INVALID_SIZE;
|
||||
}
|
||||
@@ -39,13 +47,13 @@ ResultCode TransferMemory::MapMemory(VAddr address, size_t size, MemoryPermissio
|
||||
return ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
backing_block = std::make_shared<std::vector<u8>>(size);
|
||||
|
||||
const auto map_state = owner_permissions == MemoryPermission::None
|
||||
? MemoryState::TransferMemoryIsolated
|
||||
: MemoryState::TransferMemory;
|
||||
auto& vm_manager = owner_process->VMManager();
|
||||
const auto map_result = vm_manager.MapMemoryBlock(
|
||||
address, std::make_shared<std::vector<u8>>(size), 0, size, map_state);
|
||||
|
||||
const auto map_result = vm_manager.MapMemoryBlock(address, backing_block, 0, size, map_state);
|
||||
if (map_result.Failed()) {
|
||||
return map_result.Code();
|
||||
}
|
||||
@@ -54,7 +62,7 @@ ResultCode TransferMemory::MapMemory(VAddr address, size_t size, MemoryPermissio
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
ResultCode TransferMemory::UnmapMemory(VAddr address, size_t size) {
|
||||
ResultCode TransferMemory::UnmapMemory(VAddr address, u64 size) {
|
||||
if (memory_size != size) {
|
||||
return ERR_INVALID_SIZE;
|
||||
}
|
||||
|
||||
@@ -4,6 +4,9 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "core/hle/kernel/object.h"
|
||||
|
||||
union ResultCode;
|
||||
@@ -25,7 +28,7 @@ class TransferMemory final : public Object {
|
||||
public:
|
||||
static constexpr HandleType HANDLE_TYPE = HandleType::TransferMemory;
|
||||
|
||||
static SharedPtr<TransferMemory> Create(KernelCore& kernel, VAddr base_address, size_t size,
|
||||
static SharedPtr<TransferMemory> Create(KernelCore& kernel, VAddr base_address, u64 size,
|
||||
MemoryPermission permissions);
|
||||
|
||||
TransferMemory(const TransferMemory&) = delete;
|
||||
@@ -46,6 +49,12 @@ public:
|
||||
return HANDLE_TYPE;
|
||||
}
|
||||
|
||||
/// Gets a pointer to the backing block of this instance.
|
||||
const u8* GetPointer() const;
|
||||
|
||||
/// Gets the size of the memory backing this instance in bytes.
|
||||
u64 GetSize() const;
|
||||
|
||||
/// Attempts to map transfer memory with the given range and memory permissions.
|
||||
///
|
||||
/// @param address The base address to being mapping memory at.
|
||||
@@ -56,7 +65,7 @@ public:
|
||||
/// the same values that were given when creating the transfer memory
|
||||
/// instance.
|
||||
///
|
||||
ResultCode MapMemory(VAddr address, size_t size, MemoryPermission permissions);
|
||||
ResultCode MapMemory(VAddr address, u64 size, MemoryPermission permissions);
|
||||
|
||||
/// Unmaps the transfer memory with the given range
|
||||
///
|
||||
@@ -66,17 +75,20 @@ public:
|
||||
/// @pre The given address and size must be the same as the ones used
|
||||
/// to create the transfer memory instance.
|
||||
///
|
||||
ResultCode UnmapMemory(VAddr address, size_t size);
|
||||
ResultCode UnmapMemory(VAddr address, u64 size);
|
||||
|
||||
private:
|
||||
explicit TransferMemory(KernelCore& kernel);
|
||||
~TransferMemory() override;
|
||||
|
||||
/// Memory block backing this instance.
|
||||
std::shared_ptr<std::vector<u8>> backing_block;
|
||||
|
||||
/// The base address for the memory managed by this instance.
|
||||
VAddr base_address = 0;
|
||||
|
||||
/// Size of the memory, in bytes, that this instance manages.
|
||||
size_t memory_size = 0;
|
||||
u64 memory_size = 0;
|
||||
|
||||
/// The memory permissions that are applied to this instance.
|
||||
MemoryPermission owner_permissions{};
|
||||
|
||||
@@ -24,7 +24,7 @@ public:
|
||||
* @param thread The thread about which we're deciding.
|
||||
* @return True if the current thread should wait due to this object being unavailable
|
||||
*/
|
||||
virtual bool ShouldWait(Thread* thread) const = 0;
|
||||
virtual bool ShouldWait(const Thread* thread) const = 0;
|
||||
|
||||
/// Acquire/lock the object for the specified thread if it is available
|
||||
virtual void Acquire(Thread* thread) = 0;
|
||||
|
||||
@@ -119,10 +119,6 @@ union ResultCode {
|
||||
BitField<0, 9, ErrorModule> module;
|
||||
BitField<9, 13, u32> description;
|
||||
|
||||
// The last bit of `level` is checked by apps and the kernel to determine if a result code is an
|
||||
// error
|
||||
BitField<31, 1, u32> is_error;
|
||||
|
||||
constexpr explicit ResultCode(u32 raw) : raw(raw) {}
|
||||
|
||||
constexpr ResultCode(ErrorModule module_, u32 description_)
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
#include "core/hle/kernel/kernel.h"
|
||||
#include "core/hle/kernel/process.h"
|
||||
#include "core/hle/kernel/readable_event.h"
|
||||
#include "core/hle/kernel/shared_memory.h"
|
||||
#include "core/hle/kernel/transfer_memory.h"
|
||||
#include "core/hle/kernel/writable_event.h"
|
||||
#include "core/hle/service/acc/profile_manager.h"
|
||||
#include "core/hle/service/am/am.h"
|
||||
@@ -239,8 +239,8 @@ ISelfController::ISelfController(std::shared_ptr<NVFlinger::NVFlinger> nvflinger
|
||||
{0, nullptr, "Exit"},
|
||||
{1, &ISelfController::LockExit, "LockExit"},
|
||||
{2, &ISelfController::UnlockExit, "UnlockExit"},
|
||||
{3, nullptr, "EnterFatalSection"},
|
||||
{4, nullptr, "LeaveFatalSection"},
|
||||
{3, &ISelfController::EnterFatalSection, "EnterFatalSection"},
|
||||
{4, &ISelfController::LeaveFatalSection, "LeaveFatalSection"},
|
||||
{9, &ISelfController::GetLibraryAppletLaunchableEvent, "GetLibraryAppletLaunchableEvent"},
|
||||
{10, &ISelfController::SetScreenShotPermission, "SetScreenShotPermission"},
|
||||
{11, &ISelfController::SetOperationModeChangedNotification, "SetOperationModeChangedNotification"},
|
||||
@@ -285,41 +285,54 @@ ISelfController::ISelfController(std::shared_ptr<NVFlinger::NVFlinger> nvflinger
|
||||
|
||||
ISelfController::~ISelfController() = default;
|
||||
|
||||
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.
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
void ISelfController::SetRestartMessageEnabled(Kernel::HLERequestContext& ctx) {
|
||||
void ISelfController::LockExit(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
|
||||
void ISelfController::SetPerformanceModeChangedNotification(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
|
||||
bool flag = rp.Pop<bool>();
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called flag={}", flag);
|
||||
void ISelfController::UnlockExit(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
|
||||
void ISelfController::EnterFatalSection(Kernel::HLERequestContext& ctx) {
|
||||
++num_fatal_sections_entered;
|
||||
LOG_DEBUG(Service_AM, "called. Num fatal sections entered: {}", num_fatal_sections_entered);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
|
||||
void ISelfController::LeaveFatalSection(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called.");
|
||||
|
||||
// Entry and exit of fatal sections must be balanced.
|
||||
if (num_fatal_sections_entered == 0) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultCode{ErrorModule::AM, 512});
|
||||
return;
|
||||
}
|
||||
|
||||
--num_fatal_sections_entered;
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
|
||||
void ISelfController::GetLibraryAppletLaunchableEvent(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
launchable_event.writable->Signal();
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushCopyObjects(launchable_event.readable);
|
||||
}
|
||||
|
||||
void ISelfController::SetScreenShotPermission(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
@@ -337,6 +350,42 @@ void ISelfController::SetOperationModeChangedNotification(Kernel::HLERequestCont
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
|
||||
void ISelfController::SetPerformanceModeChangedNotification(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
|
||||
bool flag = rp.Pop<bool>();
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called flag={}", flag);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
|
||||
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;
|
||||
};
|
||||
const auto flags = rp.PopRaw<FocusHandlingModeParams>();
|
||||
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called. unknown0={}, unknown1={}, unknown2={}",
|
||||
flags.unknown0, flags.unknown1, flags.unknown2);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
|
||||
void ISelfController::SetRestartMessageEnabled(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
|
||||
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.
|
||||
@@ -349,30 +398,6 @@ void ISelfController::SetOutOfFocusSuspendingEnabled(Kernel::HLERequestContext&
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
|
||||
void ISelfController::LockExit(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
|
||||
void ISelfController::UnlockExit(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
|
||||
void ISelfController::GetLibraryAppletLaunchableEvent(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
launchable_event.writable->Signal();
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushCopyObjects(launchable_event.readable);
|
||||
}
|
||||
|
||||
void ISelfController::SetScreenShotImageOrientation(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
@@ -907,19 +932,19 @@ void ILibraryAppletCreator::CreateTransferMemoryStorage(Kernel::HLERequestContex
|
||||
rp.SetCurrentOffset(3);
|
||||
const auto handle{rp.Pop<Kernel::Handle>()};
|
||||
|
||||
const auto shared_mem =
|
||||
Core::System::GetInstance().CurrentProcess()->GetHandleTable().Get<Kernel::SharedMemory>(
|
||||
const auto transfer_mem =
|
||||
Core::System::GetInstance().CurrentProcess()->GetHandleTable().Get<Kernel::TransferMemory>(
|
||||
handle);
|
||||
|
||||
if (shared_mem == nullptr) {
|
||||
if (transfer_mem == nullptr) {
|
||||
LOG_ERROR(Service_AM, "shared_mem is a nullpr for handle={:08X}", handle);
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultCode(-1));
|
||||
return;
|
||||
}
|
||||
|
||||
const u8* mem_begin = shared_mem->GetPointer();
|
||||
const u8* mem_end = mem_begin + shared_mem->GetSize();
|
||||
const u8* const mem_begin = transfer_mem->GetPointer();
|
||||
const u8* const mem_end = mem_begin + transfer_mem->GetSize();
|
||||
std::vector<u8> memory{mem_begin, mem_end};
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
|
||||
@@ -117,17 +117,19 @@ public:
|
||||
~ISelfController() override;
|
||||
|
||||
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 EnterFatalSection(Kernel::HLERequestContext& ctx);
|
||||
void LeaveFatalSection(Kernel::HLERequestContext& ctx);
|
||||
void GetLibraryAppletLaunchableEvent(Kernel::HLERequestContext& ctx);
|
||||
void SetScreenShotPermission(Kernel::HLERequestContext& ctx);
|
||||
void SetOperationModeChangedNotification(Kernel::HLERequestContext& ctx);
|
||||
void SetPerformanceModeChangedNotification(Kernel::HLERequestContext& ctx);
|
||||
void SetFocusHandlingMode(Kernel::HLERequestContext& ctx);
|
||||
void SetRestartMessageEnabled(Kernel::HLERequestContext& ctx);
|
||||
void SetOutOfFocusSuspendingEnabled(Kernel::HLERequestContext& ctx);
|
||||
void SetScreenShotImageOrientation(Kernel::HLERequestContext& ctx);
|
||||
void CreateManagedDisplayLayer(Kernel::HLERequestContext& ctx);
|
||||
void SetScreenShotPermission(Kernel::HLERequestContext& ctx);
|
||||
void SetHandlesRequestToDisplay(Kernel::HLERequestContext& ctx);
|
||||
void SetIdleTimeDetectionExtension(Kernel::HLERequestContext& ctx);
|
||||
void GetIdleTimeDetectionExtension(Kernel::HLERequestContext& ctx);
|
||||
@@ -135,6 +137,7 @@ private:
|
||||
std::shared_ptr<NVFlinger::NVFlinger> nvflinger;
|
||||
Kernel::EventPair launchable_event;
|
||||
u32 idle_time_detection_extension = 0;
|
||||
u64 num_fatal_sections_entered = 0;
|
||||
};
|
||||
|
||||
class ICommonStateGetter final : public ServiceFramework<ICommonStateGetter> {
|
||||
|
||||
@@ -2,9 +2,6 @@
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "common/logging/log.h"
|
||||
#include "core/hle/ipc_helpers.h"
|
||||
#include "core/hle/kernel/hle_ipc.h"
|
||||
#include "core/hle/service/audio/audin_u.h"
|
||||
|
||||
namespace Service::Audio {
|
||||
@@ -33,7 +30,6 @@ public:
|
||||
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
~IAudioIn() = default;
|
||||
};
|
||||
|
||||
AudInU::AudInU() : ServiceFramework("audin:u") {
|
||||
|
||||
@@ -150,7 +150,6 @@ private:
|
||||
void GetReleasedAudioOutBufferImpl(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Audio, "called {}", ctx.Description());
|
||||
|
||||
IPC::RequestParser rp{ctx};
|
||||
const u64 max_count{ctx.GetWriteBufferSize() / sizeof(u64)};
|
||||
const auto released_buffers{audio_core.GetTagsAndReleaseBuffers(stream, max_count)};
|
||||
|
||||
@@ -194,12 +193,9 @@ private:
|
||||
void AudOutU::ListAudioOutsImpl(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Audio, "called");
|
||||
|
||||
IPC::RequestParser rp{ctx};
|
||||
|
||||
ctx.WriteBuffer(DefaultDevice);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push<u32>(1); // Amount of audio devices
|
||||
}
|
||||
|
||||
@@ -2,9 +2,6 @@
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "common/logging/log.h"
|
||||
#include "core/hle/ipc_helpers.h"
|
||||
#include "core/hle/kernel/hle_ipc.h"
|
||||
#include "core/hle/service/audio/audrec_u.h"
|
||||
|
||||
namespace Service::Audio {
|
||||
@@ -30,7 +27,6 @@ public:
|
||||
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
~IFinalOutputRecorder() = default;
|
||||
};
|
||||
|
||||
AudRecU::AudRecU() : ServiceFramework("audrec:u") {
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "common/alignment.h"
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "common/string_util.h"
|
||||
#include "core/core.h"
|
||||
#include "core/hle/ipc_helpers.h"
|
||||
#include "core/hle/kernel/hle_ipc.h"
|
||||
@@ -184,7 +185,6 @@ public:
|
||||
private:
|
||||
void ListAudioDeviceName(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_Audio, "(STUBBED) called");
|
||||
IPC::RequestParser rp{ctx};
|
||||
|
||||
constexpr std::array<char, 15> audio_interface{{"AudioInterface"}};
|
||||
ctx.WriteBuffer(audio_interface);
|
||||
@@ -195,13 +195,13 @@ private:
|
||||
}
|
||||
|
||||
void SetAudioDeviceOutputVolume(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_Audio, "(STUBBED) called");
|
||||
|
||||
IPC::RequestParser rp{ctx};
|
||||
f32 volume = static_cast<f32>(rp.Pop<u32>());
|
||||
const f32 volume = rp.Pop<f32>();
|
||||
|
||||
auto file_buffer = ctx.ReadBuffer();
|
||||
auto end = std::find(file_buffer.begin(), file_buffer.end(), '\0');
|
||||
const auto device_name_buffer = ctx.ReadBuffer();
|
||||
const std::string name = Common::StringFromBuffer(device_name_buffer);
|
||||
|
||||
LOG_WARNING(Service_Audio, "(STUBBED) called. name={}, volume={}", name, volume);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
@@ -209,7 +209,6 @@ private:
|
||||
|
||||
void GetActiveAudioDeviceName(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_Audio, "(STUBBED) called");
|
||||
IPC::RequestParser rp{ctx};
|
||||
|
||||
constexpr std::array<char, 12> audio_interface{{"AudioDevice"}};
|
||||
ctx.WriteBuffer(audio_interface);
|
||||
|
||||
@@ -197,13 +197,16 @@ ResultCode VfsDirectoryServiceWrapper::RenameDirectory(const std::string& src_pa
|
||||
|
||||
ResultVal<FileSys::VirtualFile> VfsDirectoryServiceWrapper::OpenFile(const std::string& path_,
|
||||
FileSys::Mode mode) const {
|
||||
std::string path(FileUtil::SanitizePath(path_));
|
||||
auto npath = path;
|
||||
while (npath.size() > 0 && (npath[0] == '/' || npath[0] == '\\'))
|
||||
npath = npath.substr(1);
|
||||
const std::string path(FileUtil::SanitizePath(path_));
|
||||
std::string_view npath = path;
|
||||
while (!npath.empty() && (npath[0] == '/' || npath[0] == '\\')) {
|
||||
npath.remove_prefix(1);
|
||||
}
|
||||
|
||||
auto file = backing->GetFileRelative(npath);
|
||||
if (file == nullptr)
|
||||
if (file == nullptr) {
|
||||
return FileSys::ERROR_PATH_NOT_FOUND;
|
||||
}
|
||||
|
||||
if (mode == FileSys::Mode::Append) {
|
||||
return MakeResult<FileSys::VirtualFile>(
|
||||
@@ -319,15 +322,15 @@ ResultVal<FileSys::VirtualFile> OpenRomFS(u64 title_id, FileSys::StorageId stora
|
||||
}
|
||||
|
||||
ResultVal<FileSys::VirtualDir> OpenSaveData(FileSys::SaveDataSpaceId space,
|
||||
FileSys::SaveDataDescriptor save_struct) {
|
||||
const FileSys::SaveDataDescriptor& descriptor) {
|
||||
LOG_TRACE(Service_FS, "Opening Save Data for space_id={:01X}, save_struct={}",
|
||||
static_cast<u8>(space), save_struct.DebugInfo());
|
||||
static_cast<u8>(space), descriptor.DebugInfo());
|
||||
|
||||
if (save_data_factory == nullptr) {
|
||||
return FileSys::ERROR_ENTITY_NOT_FOUND;
|
||||
}
|
||||
|
||||
return save_data_factory->Open(space, save_struct);
|
||||
return save_data_factory->Open(space, descriptor);
|
||||
}
|
||||
|
||||
ResultVal<FileSys::VirtualDir> OpenSaveDataSpace(FileSys::SaveDataSpaceId space) {
|
||||
|
||||
@@ -46,7 +46,7 @@ ResultVal<FileSys::VirtualFile> OpenRomFSCurrentProcess();
|
||||
ResultVal<FileSys::VirtualFile> OpenRomFS(u64 title_id, FileSys::StorageId storage_id,
|
||||
FileSys::ContentRecordType type);
|
||||
ResultVal<FileSys::VirtualDir> OpenSaveData(FileSys::SaveDataSpaceId space,
|
||||
FileSys::SaveDataDescriptor save_struct);
|
||||
const FileSys::SaveDataDescriptor& descriptor);
|
||||
ResultVal<FileSys::VirtualDir> OpenSaveDataSpace(FileSys::SaveDataSpaceId space);
|
||||
ResultVal<FileSys::VirtualDir> OpenSDMC();
|
||||
|
||||
|
||||
@@ -315,61 +315,53 @@ public:
|
||||
void CreateFile(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
|
||||
auto file_buffer = ctx.ReadBuffer();
|
||||
std::string name = Common::StringFromBuffer(file_buffer);
|
||||
const auto file_buffer = ctx.ReadBuffer();
|
||||
const std::string name = Common::StringFromBuffer(file_buffer);
|
||||
|
||||
u64 mode = rp.Pop<u64>();
|
||||
u32 size = rp.Pop<u32>();
|
||||
const u64 mode = rp.Pop<u64>();
|
||||
const u32 size = rp.Pop<u32>();
|
||||
|
||||
LOG_DEBUG(Service_FS, "called file {} mode 0x{:X} size 0x{:08X}", name, mode, size);
|
||||
LOG_DEBUG(Service_FS, "called. file={}, mode=0x{:X}, size=0x{:08X}", name, mode, size);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(backend.CreateFile(name, size));
|
||||
}
|
||||
|
||||
void DeleteFile(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto file_buffer = ctx.ReadBuffer();
|
||||
const std::string name = Common::StringFromBuffer(file_buffer);
|
||||
|
||||
auto file_buffer = ctx.ReadBuffer();
|
||||
std::string name = Common::StringFromBuffer(file_buffer);
|
||||
|
||||
LOG_DEBUG(Service_FS, "called file {}", name);
|
||||
LOG_DEBUG(Service_FS, "called. file={}", name);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(backend.DeleteFile(name));
|
||||
}
|
||||
|
||||
void CreateDirectory(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto file_buffer = ctx.ReadBuffer();
|
||||
const std::string name = Common::StringFromBuffer(file_buffer);
|
||||
|
||||
auto file_buffer = ctx.ReadBuffer();
|
||||
std::string name = Common::StringFromBuffer(file_buffer);
|
||||
|
||||
LOG_DEBUG(Service_FS, "called directory {}", name);
|
||||
LOG_DEBUG(Service_FS, "called. directory={}", name);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(backend.CreateDirectory(name));
|
||||
}
|
||||
|
||||
void DeleteDirectory(Kernel::HLERequestContext& ctx) {
|
||||
const IPC::RequestParser rp{ctx};
|
||||
|
||||
const auto file_buffer = ctx.ReadBuffer();
|
||||
std::string name = Common::StringFromBuffer(file_buffer);
|
||||
const std::string name = Common::StringFromBuffer(file_buffer);
|
||||
|
||||
LOG_DEBUG(Service_FS, "called directory {}", name);
|
||||
LOG_DEBUG(Service_FS, "called. directory={}", name);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(backend.DeleteDirectory(name));
|
||||
}
|
||||
|
||||
void DeleteDirectoryRecursively(Kernel::HLERequestContext& ctx) {
|
||||
const IPC::RequestParser rp{ctx};
|
||||
|
||||
const auto file_buffer = ctx.ReadBuffer();
|
||||
std::string name = Common::StringFromBuffer(file_buffer);
|
||||
const std::string name = Common::StringFromBuffer(file_buffer);
|
||||
|
||||
LOG_DEBUG(Service_FS, "called directory {}", name);
|
||||
LOG_DEBUG(Service_FS, "called. directory={}", name);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(backend.DeleteDirectoryRecursively(name));
|
||||
@@ -386,18 +378,16 @@ public:
|
||||
}
|
||||
|
||||
void RenameFile(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
|
||||
std::vector<u8> buffer;
|
||||
buffer.resize(ctx.BufferDescriptorX()[0].Size());
|
||||
Memory::ReadBlock(ctx.BufferDescriptorX()[0].Address(), buffer.data(), buffer.size());
|
||||
std::string src_name = Common::StringFromBuffer(buffer);
|
||||
const std::string src_name = Common::StringFromBuffer(buffer);
|
||||
|
||||
buffer.resize(ctx.BufferDescriptorX()[1].Size());
|
||||
Memory::ReadBlock(ctx.BufferDescriptorX()[1].Address(), buffer.data(), buffer.size());
|
||||
std::string dst_name = Common::StringFromBuffer(buffer);
|
||||
const std::string dst_name = Common::StringFromBuffer(buffer);
|
||||
|
||||
LOG_DEBUG(Service_FS, "called file '{}' to file '{}'", src_name, dst_name);
|
||||
LOG_DEBUG(Service_FS, "called. file '{}' to file '{}'", src_name, dst_name);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(backend.RenameFile(src_name, dst_name));
|
||||
@@ -406,12 +396,12 @@ public:
|
||||
void OpenFile(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
|
||||
auto file_buffer = ctx.ReadBuffer();
|
||||
std::string name = Common::StringFromBuffer(file_buffer);
|
||||
const auto file_buffer = ctx.ReadBuffer();
|
||||
const std::string name = Common::StringFromBuffer(file_buffer);
|
||||
|
||||
auto mode = static_cast<FileSys::Mode>(rp.Pop<u32>());
|
||||
const auto mode = static_cast<FileSys::Mode>(rp.Pop<u32>());
|
||||
|
||||
LOG_DEBUG(Service_FS, "called file {} mode {}", name, static_cast<u32>(mode));
|
||||
LOG_DEBUG(Service_FS, "called. file={}, mode={}", name, static_cast<u32>(mode));
|
||||
|
||||
auto result = backend.OpenFile(name, mode);
|
||||
if (result.Failed()) {
|
||||
@@ -430,13 +420,13 @@ public:
|
||||
void OpenDirectory(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
|
||||
auto file_buffer = ctx.ReadBuffer();
|
||||
std::string name = Common::StringFromBuffer(file_buffer);
|
||||
const auto file_buffer = ctx.ReadBuffer();
|
||||
const std::string name = Common::StringFromBuffer(file_buffer);
|
||||
|
||||
// TODO(Subv): Implement this filter.
|
||||
u32 filter_flags = rp.Pop<u32>();
|
||||
const u32 filter_flags = rp.Pop<u32>();
|
||||
|
||||
LOG_DEBUG(Service_FS, "called directory {} filter {}", name, filter_flags);
|
||||
LOG_DEBUG(Service_FS, "called. directory={}, filter={}", name, filter_flags);
|
||||
|
||||
auto result = backend.OpenDirectory(name);
|
||||
if (result.Failed()) {
|
||||
@@ -453,12 +443,10 @@ public:
|
||||
}
|
||||
|
||||
void GetEntryType(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto file_buffer = ctx.ReadBuffer();
|
||||
const std::string name = Common::StringFromBuffer(file_buffer);
|
||||
|
||||
auto file_buffer = ctx.ReadBuffer();
|
||||
std::string name = Common::StringFromBuffer(file_buffer);
|
||||
|
||||
LOG_DEBUG(Service_FS, "called file {}", name);
|
||||
LOG_DEBUG(Service_FS, "called. file={}", name);
|
||||
|
||||
auto result = backend.GetEntryType(name);
|
||||
if (result.Failed()) {
|
||||
@@ -616,7 +604,9 @@ private:
|
||||
u64_le save_id;
|
||||
u64_le title_id;
|
||||
u64_le save_image_size;
|
||||
INSERT_PADDING_BYTES(0x28);
|
||||
u16_le index;
|
||||
FileSys::SaveDataRank rank;
|
||||
INSERT_PADDING_BYTES(0x25);
|
||||
};
|
||||
static_assert(sizeof(SaveDataInfo) == 0x60, "SaveDataInfo has incorrect size.");
|
||||
|
||||
@@ -779,16 +769,17 @@ void FSP_SRV::CreateSaveDataFileSystem(Kernel::HLERequestContext& ctx) {
|
||||
}
|
||||
|
||||
void FSP_SRV::OpenSaveDataFileSystem(Kernel::HLERequestContext& ctx) {
|
||||
LOG_INFO(Service_FS, "called.");
|
||||
|
||||
struct Parameters {
|
||||
FileSys::SaveDataSpaceId save_data_space_id;
|
||||
FileSys::SaveDataDescriptor descriptor;
|
||||
};
|
||||
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto parameters = rp.PopRaw<Parameters>();
|
||||
|
||||
auto space_id = rp.PopRaw<FileSys::SaveDataSpaceId>();
|
||||
auto unk = rp.Pop<u32>();
|
||||
LOG_INFO(Service_FS, "called with unknown={:08X}", unk);
|
||||
|
||||
auto save_struct = rp.PopRaw<FileSys::SaveDataDescriptor>();
|
||||
|
||||
auto dir = OpenSaveData(space_id, save_struct);
|
||||
|
||||
auto dir = OpenSaveData(parameters.save_data_space_id, parameters.descriptor);
|
||||
if (dir.Failed()) {
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 0};
|
||||
rb.Push(FileSys::ERROR_ENTITY_NOT_FOUND);
|
||||
|
||||
@@ -18,7 +18,7 @@ class nvmap;
|
||||
class nvdisp_disp0 final : public nvdevice {
|
||||
public:
|
||||
explicit nvdisp_disp0(std::shared_ptr<nvmap> nvmap_dev);
|
||||
~nvdisp_disp0();
|
||||
~nvdisp_disp0() override;
|
||||
|
||||
u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override;
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace Service::Nvidia {
|
||||
class NVDRV final : public ServiceFramework<NVDRV> {
|
||||
public:
|
||||
NVDRV(std::shared_ptr<Module> nvdrv, const char* name);
|
||||
~NVDRV();
|
||||
~NVDRV() override;
|
||||
|
||||
private:
|
||||
void Open(Kernel::HLERequestContext& ctx);
|
||||
|
||||
@@ -11,7 +11,7 @@ namespace Service::Nvidia {
|
||||
class NVMEMP final : public ServiceFramework<NVMEMP> {
|
||||
public:
|
||||
NVMEMP();
|
||||
~NVMEMP();
|
||||
~NVMEMP() override;
|
||||
|
||||
private:
|
||||
void Cmd0(Kernel::HLERequestContext& ctx);
|
||||
|
||||
@@ -90,7 +90,7 @@ private:
|
||||
Kernel::HLERequestContext& ctx);
|
||||
|
||||
ServiceFrameworkBase(const char* service_name, u32 max_sessions, InvokerFn* handler_invoker);
|
||||
~ServiceFrameworkBase();
|
||||
~ServiceFrameworkBase() override;
|
||||
|
||||
void RegisterHandlersBase(const FunctionInfoBase* functions, std::size_t n);
|
||||
void ReportUnimplementedFunction(Kernel::HLERequestContext& ctx, const FunctionInfoBase* info);
|
||||
|
||||
@@ -11,7 +11,7 @@ namespace Service::Set {
|
||||
class SET_CAL final : public ServiceFramework<SET_CAL> {
|
||||
public:
|
||||
explicit SET_CAL();
|
||||
~SET_CAL();
|
||||
~SET_CAL() override;
|
||||
};
|
||||
|
||||
} // namespace Service::Set
|
||||
|
||||
@@ -8,12 +8,20 @@
|
||||
namespace Service::Sockets {
|
||||
|
||||
void SFDNSRES::GetAddrInfo(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
struct Parameters {
|
||||
u8 use_nsd_resolve;
|
||||
u32 unknown;
|
||||
u64 process_id;
|
||||
};
|
||||
|
||||
LOG_WARNING(Service, "(STUBBED) called");
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto parameters = rp.PopRaw<Parameters>();
|
||||
|
||||
LOG_WARNING(Service,
|
||||
"(STUBBED) called. use_nsd_resolve={}, unknown=0x{:08X}, process_id=0x{:016X}",
|
||||
parameters.use_nsd_resolve, parameters.unknown, parameters.process_id);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
|
||||
|
||||
@@ -26,9 +26,7 @@ Module::Interface::~Interface() = default;
|
||||
void Module::Interface::GetRandomBytes(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_SPL, "called");
|
||||
|
||||
IPC::RequestParser rp{ctx};
|
||||
|
||||
std::size_t size = ctx.GetWriteBufferSize();
|
||||
const std::size_t size = ctx.GetWriteBufferSize();
|
||||
|
||||
std::uniform_int_distribution<u16> distribution(0, std::numeric_limits<u8>::max());
|
||||
std::vector<u8> data(size);
|
||||
|
||||
@@ -64,13 +64,19 @@ public:
|
||||
};
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
~ISslContext() = default;
|
||||
|
||||
private:
|
||||
void SetOption(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_SSL, "(STUBBED) called");
|
||||
struct Parameters {
|
||||
u8 enable;
|
||||
u32 option;
|
||||
};
|
||||
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto parameters = rp.PopRaw<Parameters>();
|
||||
|
||||
LOG_WARNING(Service_SSL, "(STUBBED) called. enable={}, option={}", parameters.enable,
|
||||
parameters.option);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
|
||||
@@ -498,7 +498,6 @@ public:
|
||||
};
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
~IHOSBinderDriver() = default;
|
||||
|
||||
private:
|
||||
enum class TransactionId {
|
||||
@@ -692,7 +691,6 @@ public:
|
||||
};
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
~ISystemDisplayService() = default;
|
||||
|
||||
private:
|
||||
void SetLayerZ(Kernel::HLERequestContext& ctx) {
|
||||
@@ -818,7 +816,6 @@ public:
|
||||
};
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
~IManagerDisplayService() = default;
|
||||
|
||||
private:
|
||||
void CloseDisplay(Kernel::HLERequestContext& ctx) {
|
||||
@@ -884,7 +881,6 @@ private:
|
||||
class IApplicationDisplayService final : public ServiceFramework<IApplicationDisplayService> {
|
||||
public:
|
||||
explicit IApplicationDisplayService(std::shared_ptr<NVFlinger::NVFlinger> nv_flinger);
|
||||
~IApplicationDisplayService() = default;
|
||||
|
||||
private:
|
||||
enum class ConvertedScaleMode : u64 {
|
||||
@@ -1037,7 +1033,6 @@ private:
|
||||
void ListDisplays(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_VI, "(STUBBED) called");
|
||||
|
||||
IPC::RequestParser rp{ctx};
|
||||
DisplayInfo display_info;
|
||||
display_info.width *= static_cast<u64>(Settings::values.resolution_factor);
|
||||
display_info.height *= static_cast<u64>(Settings::values.resolution_factor);
|
||||
|
||||
@@ -4,11 +4,12 @@
|
||||
|
||||
#include <cinttypes>
|
||||
#include <vector>
|
||||
#include <lz4.h>
|
||||
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/file_util.h"
|
||||
#include "common/hex_util.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "common/lz4_compression.h"
|
||||
#include "common/swap.h"
|
||||
#include "core/core.h"
|
||||
#include "core/file_sys/patch_manager.h"
|
||||
@@ -35,15 +36,11 @@ static_assert(sizeof(MODHeader) == 0x1c, "MODHeader has incorrect size.");
|
||||
|
||||
std::vector<u8> DecompressSegment(const std::vector<u8>& compressed_data,
|
||||
const NSOSegmentHeader& header) {
|
||||
std::vector<u8> uncompressed_data(header.size);
|
||||
const int bytes_uncompressed =
|
||||
LZ4_decompress_safe(reinterpret_cast<const char*>(compressed_data.data()),
|
||||
reinterpret_cast<char*>(uncompressed_data.data()),
|
||||
static_cast<int>(compressed_data.size()), header.size);
|
||||
const std::vector<u8> uncompressed_data =
|
||||
Common::Compression::DecompressDataLZ4(compressed_data, header.size);
|
||||
|
||||
ASSERT_MSG(bytes_uncompressed == static_cast<int>(header.size) &&
|
||||
bytes_uncompressed == static_cast<int>(uncompressed_data.size()),
|
||||
"{} != {} != {}", bytes_uncompressed, header.size, uncompressed_data.size());
|
||||
ASSERT_MSG(uncompressed_data.size() == static_cast<int>(header.size), "{} != {}", header.size,
|
||||
uncompressed_data.size());
|
||||
|
||||
return uncompressed_data;
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ class AppLoader_NCA;
|
||||
class AppLoader_XCI final : public AppLoader {
|
||||
public:
|
||||
explicit AppLoader_XCI(FileSys::VirtualFile file);
|
||||
~AppLoader_XCI();
|
||||
~AppLoader_XCI() override;
|
||||
|
||||
/**
|
||||
* Returns the type of the file
|
||||
|
||||
@@ -38,10 +38,6 @@ void SetCurrentPageTable(Common::PageTable* page_table) {
|
||||
}
|
||||
}
|
||||
|
||||
Common::PageTable* GetCurrentPageTable() {
|
||||
return current_page_table;
|
||||
}
|
||||
|
||||
static void MapPages(Common::PageTable& page_table, VAddr base, u64 size, u8* memory,
|
||||
Common::PageType type) {
|
||||
LOG_DEBUG(HW_Memory, "Mapping {} onto {:016X}-{:016X}", fmt::ptr(memory), base * PAGE_SIZE,
|
||||
|
||||
@@ -28,16 +28,6 @@ constexpr u64 PAGE_MASK = PAGE_SIZE - 1;
|
||||
|
||||
/// Virtual user-space memory regions
|
||||
enum : VAddr {
|
||||
/// Read-only page containing kernel and system configuration values.
|
||||
CONFIG_MEMORY_VADDR = 0x1FF80000,
|
||||
CONFIG_MEMORY_SIZE = 0x00001000,
|
||||
CONFIG_MEMORY_VADDR_END = CONFIG_MEMORY_VADDR + CONFIG_MEMORY_SIZE,
|
||||
|
||||
/// Usually read-only page containing mostly values read from hardware.
|
||||
SHARED_PAGE_VADDR = 0x1FF81000,
|
||||
SHARED_PAGE_SIZE = 0x00001000,
|
||||
SHARED_PAGE_VADDR_END = SHARED_PAGE_VADDR + SHARED_PAGE_SIZE,
|
||||
|
||||
/// TLS (Thread-Local Storage) related.
|
||||
TLS_ENTRY_SIZE = 0x200,
|
||||
|
||||
@@ -50,9 +40,8 @@ enum : VAddr {
|
||||
KERNEL_REGION_END = KERNEL_REGION_VADDR + KERNEL_REGION_SIZE,
|
||||
};
|
||||
|
||||
/// Currently active page table
|
||||
/// Changes the currently active page table.
|
||||
void SetCurrentPageTable(Common::PageTable* page_table);
|
||||
Common::PageTable* GetCurrentPageTable();
|
||||
|
||||
/// Determines if the given VAddr is valid for the specified process.
|
||||
bool IsValidVirtualAddress(const Kernel::Process& process, VAddr vaddr);
|
||||
|
||||
@@ -17,7 +17,6 @@ TestEnvironment::TestEnvironment(bool mutable_memory_)
|
||||
: mutable_memory(mutable_memory_),
|
||||
test_memory(std::make_shared<TestMemory>(this)), kernel{Core::System::GetInstance()} {
|
||||
auto process = Kernel::Process::Create(Core::System::GetInstance(), "");
|
||||
kernel.MakeCurrentProcess(process.get());
|
||||
page_table = &process->VMManager().page_table;
|
||||
|
||||
std::fill(page_table->pointers.begin(), page_table->pointers.end(), nullptr);
|
||||
@@ -28,7 +27,7 @@ TestEnvironment::TestEnvironment(bool mutable_memory_)
|
||||
Memory::MapIoRegion(*page_table, 0x00000000, 0x80000000, test_memory);
|
||||
Memory::MapIoRegion(*page_table, 0x80000000, 0x80000000, test_memory);
|
||||
|
||||
Memory::SetCurrentPageTable(page_table);
|
||||
kernel.MakeCurrentProcess(process.get());
|
||||
}
|
||||
|
||||
TestEnvironment::~TestEnvironment() {
|
||||
|
||||
@@ -128,7 +128,9 @@ if (ENABLE_VULKAN)
|
||||
renderer_vulkan/vk_scheduler.cpp
|
||||
renderer_vulkan/vk_scheduler.h
|
||||
renderer_vulkan/vk_stream_buffer.cpp
|
||||
renderer_vulkan/vk_stream_buffer.h)
|
||||
renderer_vulkan/vk_stream_buffer.h
|
||||
renderer_vulkan/vk_swapchain.cpp
|
||||
renderer_vulkan/vk_swapchain.h)
|
||||
|
||||
target_include_directories(video_core PRIVATE ../../externals/Vulkan-Headers/include)
|
||||
target_compile_definitions(video_core PRIVATE HAS_VULKAN)
|
||||
@@ -137,4 +139,4 @@ endif()
|
||||
create_target_directory_groups(video_core)
|
||||
|
||||
target_link_libraries(video_core PUBLIC common core)
|
||||
target_link_libraries(video_core PRIVATE glad lz4_static)
|
||||
target_link_libraries(video_core PRIVATE glad)
|
||||
|
||||
@@ -6,12 +6,13 @@
|
||||
#include "common/logging/log.h"
|
||||
#include "common/math_util.h"
|
||||
#include "video_core/engines/fermi_2d.h"
|
||||
#include "video_core/memory_manager.h"
|
||||
#include "video_core/rasterizer_interface.h"
|
||||
|
||||
namespace Tegra::Engines {
|
||||
|
||||
Fermi2D::Fermi2D(VideoCore::RasterizerInterface& rasterizer, MemoryManager& memory_manager)
|
||||
: memory_manager(memory_manager), rasterizer{rasterizer} {}
|
||||
: rasterizer{rasterizer}, memory_manager{memory_manager} {}
|
||||
|
||||
void Fermi2D::CallMethod(const GPU::MethodCall& method_call) {
|
||||
ASSERT_MSG(method_call.method < Regs::NUM_REGS,
|
||||
|
||||
@@ -10,7 +10,10 @@
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/common_types.h"
|
||||
#include "video_core/gpu.h"
|
||||
#include "video_core/memory_manager.h"
|
||||
|
||||
namespace Tegra {
|
||||
class MemoryManager;
|
||||
}
|
||||
|
||||
namespace VideoCore {
|
||||
class RasterizerInterface;
|
||||
@@ -115,10 +118,9 @@ public:
|
||||
};
|
||||
} regs{};
|
||||
|
||||
MemoryManager& memory_manager;
|
||||
|
||||
private:
|
||||
VideoCore::RasterizerInterface& rasterizer;
|
||||
MemoryManager& memory_manager;
|
||||
|
||||
/// Performs the copy from the source surface to the destination surface as configured in the
|
||||
/// registers.
|
||||
|
||||
@@ -9,7 +9,10 @@
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/common_types.h"
|
||||
#include "video_core/gpu.h"
|
||||
#include "video_core/memory_manager.h"
|
||||
|
||||
namespace Tegra {
|
||||
class MemoryManager;
|
||||
}
|
||||
|
||||
namespace Tegra::Engines {
|
||||
|
||||
@@ -40,10 +43,11 @@ public:
|
||||
static_assert(sizeof(Regs) == Regs::NUM_REGS * sizeof(u32),
|
||||
"KeplerCompute Regs has wrong size");
|
||||
|
||||
MemoryManager& memory_manager;
|
||||
|
||||
/// Write the value to the register identified by method.
|
||||
void CallMethod(const GPU::MethodCall& method_call);
|
||||
|
||||
private:
|
||||
MemoryManager& memory_manager;
|
||||
};
|
||||
|
||||
#define ASSERT_REG_POSITION(field_name, position) \
|
||||
|
||||
@@ -5,9 +5,9 @@
|
||||
#include "common/assert.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "core/core.h"
|
||||
#include "core/memory.h"
|
||||
#include "video_core/engines/kepler_memory.h"
|
||||
#include "video_core/engines/maxwell_3d.h"
|
||||
#include "video_core/memory_manager.h"
|
||||
#include "video_core/rasterizer_interface.h"
|
||||
#include "video_core/renderer_base.h"
|
||||
|
||||
@@ -15,7 +15,7 @@ namespace Tegra::Engines {
|
||||
|
||||
KeplerMemory::KeplerMemory(Core::System& system, VideoCore::RasterizerInterface& rasterizer,
|
||||
MemoryManager& memory_manager)
|
||||
: system{system}, memory_manager(memory_manager), rasterizer{rasterizer} {}
|
||||
: system{system}, rasterizer{rasterizer}, memory_manager{memory_manager} {}
|
||||
|
||||
KeplerMemory::~KeplerMemory() = default;
|
||||
|
||||
|
||||
@@ -10,12 +10,15 @@
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/common_types.h"
|
||||
#include "video_core/gpu.h"
|
||||
#include "video_core/memory_manager.h"
|
||||
|
||||
namespace Core {
|
||||
class System;
|
||||
}
|
||||
|
||||
namespace Tegra {
|
||||
class MemoryManager;
|
||||
}
|
||||
|
||||
namespace VideoCore {
|
||||
class RasterizerInterface;
|
||||
}
|
||||
@@ -82,8 +85,8 @@ public:
|
||||
|
||||
private:
|
||||
Core::System& system;
|
||||
MemoryManager& memory_manager;
|
||||
VideoCore::RasterizerInterface& rasterizer;
|
||||
MemoryManager& memory_manager;
|
||||
|
||||
void ProcessData(u32 data);
|
||||
};
|
||||
|
||||
@@ -7,11 +7,10 @@
|
||||
#include "common/assert.h"
|
||||
#include "core/core.h"
|
||||
#include "core/core_timing.h"
|
||||
#include "core/memory.h"
|
||||
#include "video_core/debug_utils/debug_utils.h"
|
||||
#include "video_core/engines/maxwell_3d.h"
|
||||
#include "video_core/memory_manager.h"
|
||||
#include "video_core/rasterizer_interface.h"
|
||||
#include "video_core/renderer_base.h"
|
||||
#include "video_core/textures/texture.h"
|
||||
|
||||
namespace Tegra::Engines {
|
||||
@@ -21,8 +20,8 @@ constexpr u32 MacroRegistersStart = 0xE00;
|
||||
|
||||
Maxwell3D::Maxwell3D(Core::System& system, VideoCore::RasterizerInterface& rasterizer,
|
||||
MemoryManager& memory_manager)
|
||||
: memory_manager(memory_manager), system{system}, rasterizer{rasterizer},
|
||||
macro_interpreter(*this) {
|
||||
: system{system}, rasterizer{rasterizer}, memory_manager{memory_manager}, macro_interpreter{
|
||||
*this} {
|
||||
InitializeRegisterDefaults();
|
||||
}
|
||||
|
||||
@@ -250,6 +249,10 @@ void Maxwell3D::CallMethod(const GPU::MethodCall& method_call) {
|
||||
ProcessQueryGet();
|
||||
break;
|
||||
}
|
||||
case MAXWELL3D_REG_INDEX(sync_info): {
|
||||
ProcessSyncPoint();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -327,6 +330,14 @@ void Maxwell3D::ProcessQueryGet() {
|
||||
}
|
||||
}
|
||||
|
||||
void Maxwell3D::ProcessSyncPoint() {
|
||||
const u32 sync_point = regs.sync_info.sync_point.Value();
|
||||
const u32 increment = regs.sync_info.increment.Value();
|
||||
const u32 cache_flush = regs.sync_info.unknown.Value();
|
||||
LOG_DEBUG(HW_GPU, "Syncpoint set {}, increment: {}, unk: {}", sync_point, increment,
|
||||
cache_flush);
|
||||
}
|
||||
|
||||
void Maxwell3D::DrawArrays() {
|
||||
LOG_DEBUG(HW_GPU, "called, topology={}, count={}", static_cast<u32>(regs.draw.topology.Value()),
|
||||
regs.vertex_buffer.count);
|
||||
|
||||
@@ -16,13 +16,16 @@
|
||||
#include "common/math_util.h"
|
||||
#include "video_core/gpu.h"
|
||||
#include "video_core/macro_interpreter.h"
|
||||
#include "video_core/memory_manager.h"
|
||||
#include "video_core/textures/texture.h"
|
||||
|
||||
namespace Core {
|
||||
class System;
|
||||
}
|
||||
|
||||
namespace Tegra {
|
||||
class MemoryManager;
|
||||
}
|
||||
|
||||
namespace VideoCore {
|
||||
class RasterizerInterface;
|
||||
}
|
||||
@@ -576,7 +579,17 @@ public:
|
||||
u32 bind;
|
||||
} macros;
|
||||
|
||||
INSERT_PADDING_WORDS(0x188);
|
||||
INSERT_PADDING_WORDS(0x69);
|
||||
|
||||
struct {
|
||||
union {
|
||||
BitField<0, 16, u32> sync_point;
|
||||
BitField<16, 1, u32> unknown;
|
||||
BitField<20, 1, u32> increment;
|
||||
};
|
||||
} sync_info;
|
||||
|
||||
INSERT_PADDING_WORDS(0x11E);
|
||||
|
||||
u32 tfb_enabled;
|
||||
|
||||
@@ -1093,7 +1106,6 @@ public:
|
||||
};
|
||||
|
||||
State state{};
|
||||
MemoryManager& memory_manager;
|
||||
|
||||
struct DirtyFlags {
|
||||
std::bitset<8> color_buffer{0xFF};
|
||||
@@ -1141,6 +1153,8 @@ private:
|
||||
|
||||
VideoCore::RasterizerInterface& rasterizer;
|
||||
|
||||
MemoryManager& memory_manager;
|
||||
|
||||
/// Start offsets of each macro in macro_memory
|
||||
std::unordered_map<u32, u32> macro_offsets;
|
||||
|
||||
@@ -1180,6 +1194,9 @@ private:
|
||||
/// Handles a write to the QUERY_GET register.
|
||||
void ProcessQueryGet();
|
||||
|
||||
/// Handles writes to syncing register.
|
||||
void ProcessSyncPoint();
|
||||
|
||||
/// Handles a write to the CB_DATA[i] register.
|
||||
void ProcessCBData(u32 value);
|
||||
|
||||
@@ -1195,6 +1212,7 @@ private:
|
||||
"Field " #field_name " has invalid position")
|
||||
|
||||
ASSERT_REG_POSITION(macros, 0x45);
|
||||
ASSERT_REG_POSITION(sync_info, 0xB2);
|
||||
ASSERT_REG_POSITION(tfb_enabled, 0x1D1);
|
||||
ASSERT_REG_POSITION(rt, 0x200);
|
||||
ASSERT_REG_POSITION(viewport_transform, 0x280);
|
||||
|
||||
@@ -5,9 +5,9 @@
|
||||
#include "common/assert.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "core/core.h"
|
||||
#include "core/memory.h"
|
||||
#include "video_core/engines/maxwell_3d.h"
|
||||
#include "video_core/engines/maxwell_dma.h"
|
||||
#include "video_core/memory_manager.h"
|
||||
#include "video_core/rasterizer_interface.h"
|
||||
#include "video_core/renderer_base.h"
|
||||
#include "video_core/textures/decoders.h"
|
||||
@@ -16,7 +16,7 @@ namespace Tegra::Engines {
|
||||
|
||||
MaxwellDMA::MaxwellDMA(Core::System& system, VideoCore::RasterizerInterface& rasterizer,
|
||||
MemoryManager& memory_manager)
|
||||
: memory_manager(memory_manager), system{system}, rasterizer{rasterizer} {}
|
||||
: system{system}, rasterizer{rasterizer}, memory_manager{memory_manager} {}
|
||||
|
||||
void MaxwellDMA::CallMethod(const GPU::MethodCall& method_call) {
|
||||
ASSERT_MSG(method_call.method < Regs::NUM_REGS,
|
||||
|
||||
@@ -10,12 +10,15 @@
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/common_types.h"
|
||||
#include "video_core/gpu.h"
|
||||
#include "video_core/memory_manager.h"
|
||||
|
||||
namespace Core {
|
||||
class System;
|
||||
}
|
||||
|
||||
namespace Tegra {
|
||||
class MemoryManager;
|
||||
}
|
||||
|
||||
namespace VideoCore {
|
||||
class RasterizerInterface;
|
||||
}
|
||||
@@ -139,13 +142,13 @@ public:
|
||||
};
|
||||
} regs{};
|
||||
|
||||
MemoryManager& memory_manager;
|
||||
|
||||
private:
|
||||
Core::System& system;
|
||||
|
||||
VideoCore::RasterizerInterface& rasterizer;
|
||||
|
||||
MemoryManager& memory_manager;
|
||||
|
||||
/// Performs the copy from the source buffer to the destination buffer as configured in the
|
||||
/// registers.
|
||||
void HandleCopy();
|
||||
|
||||
@@ -31,7 +31,7 @@ u32 FramebufferConfig::BytesPerPixel(PixelFormat format) {
|
||||
|
||||
GPU::GPU(Core::System& system, VideoCore::RendererBase& renderer) : renderer{renderer} {
|
||||
auto& rasterizer{renderer.Rasterizer()};
|
||||
memory_manager = std::make_unique<Tegra::MemoryManager>();
|
||||
memory_manager = std::make_unique<Tegra::MemoryManager>(rasterizer);
|
||||
dma_pusher = std::make_unique<Tegra::DmaPusher>(*this);
|
||||
maxwell_3d = std::make_unique<Engines::Maxwell3D>(system, rasterizer, *memory_manager);
|
||||
fermi_2d = std::make_unique<Engines::Fermi2D>(rasterizer, *memory_manager);
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
namespace VideoCommon {
|
||||
|
||||
GPUAsynch::GPUAsynch(Core::System& system, VideoCore::RendererBase& renderer)
|
||||
: Tegra::GPU(system, renderer), gpu_thread{renderer, *dma_pusher} {}
|
||||
: Tegra::GPU(system, renderer), gpu_thread{system, renderer, *dma_pusher} {}
|
||||
|
||||
GPUAsynch::~GPUAsynch() = default;
|
||||
|
||||
|
||||
@@ -4,6 +4,9 @@
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/microprofile.h"
|
||||
#include "core/core.h"
|
||||
#include "core/core_timing.h"
|
||||
#include "core/core_timing_util.h"
|
||||
#include "core/frontend/scope_acquire_window_context.h"
|
||||
#include "video_core/dma_pusher.h"
|
||||
#include "video_core/gpu.h"
|
||||
@@ -36,7 +39,6 @@ static void RunThread(VideoCore::RendererBase& renderer, Tegra::DmaPusher& dma_p
|
||||
dma_pusher.Push(std::move(submit_list->entries));
|
||||
dma_pusher.DispatchCalls();
|
||||
} else if (const auto data = std::get_if<SwapBuffersCommand>(&next.data)) {
|
||||
state.DecrementFramesCounter();
|
||||
renderer.SwapBuffers(std::move(data->framebuffer));
|
||||
} else if (const auto data = std::get_if<FlushRegionCommand>(&next.data)) {
|
||||
renderer.Rasterizer().FlushRegion(data->addr, data->size);
|
||||
@@ -47,13 +49,18 @@ static void RunThread(VideoCore::RendererBase& renderer, Tegra::DmaPusher& dma_p
|
||||
} else {
|
||||
UNREACHABLE();
|
||||
}
|
||||
state.signaled_fence = next.fence;
|
||||
state.TrySynchronize();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ThreadManager::ThreadManager(VideoCore::RendererBase& renderer, Tegra::DmaPusher& dma_pusher)
|
||||
: renderer{renderer}, thread{RunThread, std::ref(renderer), std::ref(dma_pusher),
|
||||
std::ref(state)} {}
|
||||
ThreadManager::ThreadManager(Core::System& system, VideoCore::RendererBase& renderer,
|
||||
Tegra::DmaPusher& dma_pusher)
|
||||
: system{system}, thread{RunThread, std::ref(renderer), std::ref(dma_pusher), std::ref(state)} {
|
||||
synchronization_event = system.CoreTiming().RegisterEvent(
|
||||
"GPUThreadSynch", [this](u64 fence, s64) { state.WaitForSynchronization(fence); });
|
||||
}
|
||||
|
||||
ThreadManager::~ThreadManager() {
|
||||
// Notify GPU thread that a shutdown is pending
|
||||
@@ -62,14 +69,14 @@ ThreadManager::~ThreadManager() {
|
||||
}
|
||||
|
||||
void ThreadManager::SubmitList(Tegra::CommandList&& entries) {
|
||||
PushCommand(SubmitListCommand(std::move(entries)));
|
||||
const u64 fence{PushCommand(SubmitListCommand(std::move(entries)))};
|
||||
const s64 synchronization_ticks{Core::Timing::usToCycles(9000)};
|
||||
system.CoreTiming().ScheduleEvent(synchronization_ticks, synchronization_event, fence);
|
||||
}
|
||||
|
||||
void ThreadManager::SwapBuffers(
|
||||
std::optional<std::reference_wrapper<const Tegra::FramebufferConfig>> framebuffer) {
|
||||
state.IncrementFramesCounter();
|
||||
PushCommand(SwapBuffersCommand(std::move(framebuffer)));
|
||||
state.WaitForFrames();
|
||||
}
|
||||
|
||||
void ThreadManager::FlushRegion(CacheAddr addr, u64 size) {
|
||||
@@ -79,7 +86,7 @@ void ThreadManager::FlushRegion(CacheAddr addr, u64 size) {
|
||||
void ThreadManager::InvalidateRegion(CacheAddr addr, u64 size) {
|
||||
if (state.queue.Empty()) {
|
||||
// It's quicker to invalidate a single region on the CPU if the queue is already empty
|
||||
renderer.Rasterizer().InvalidateRegion(addr, size);
|
||||
system.Renderer().Rasterizer().InvalidateRegion(addr, size);
|
||||
} else {
|
||||
PushCommand(InvalidateRegionCommand(addr, size));
|
||||
}
|
||||
@@ -90,9 +97,25 @@ void ThreadManager::FlushAndInvalidateRegion(CacheAddr addr, u64 size) {
|
||||
InvalidateRegion(addr, size);
|
||||
}
|
||||
|
||||
void ThreadManager::PushCommand(CommandData&& command_data) {
|
||||
state.queue.Push(CommandDataContainer(std::move(command_data)));
|
||||
u64 ThreadManager::PushCommand(CommandData&& command_data) {
|
||||
const u64 fence{++state.last_fence};
|
||||
state.queue.Push(CommandDataContainer(std::move(command_data), fence));
|
||||
state.SignalCommands();
|
||||
return fence;
|
||||
}
|
||||
|
||||
MICROPROFILE_DEFINE(GPU_wait, "GPU", "Wait for the GPU", MP_RGB(128, 128, 192));
|
||||
void SynchState::WaitForSynchronization(u64 fence) {
|
||||
if (signaled_fence >= fence) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Wait for the GPU to be idle (all commands to be executed)
|
||||
{
|
||||
MICROPROFILE_SCOPE(GPU_wait);
|
||||
std::unique_lock<std::mutex> lock{synchronization_mutex};
|
||||
synchronization_condition.wait(lock, [this, fence] { return signaled_fence >= fence; });
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace VideoCommon::GPUThread
|
||||
|
||||
@@ -19,9 +19,12 @@ struct FramebufferConfig;
|
||||
class DmaPusher;
|
||||
} // namespace Tegra
|
||||
|
||||
namespace VideoCore {
|
||||
class RendererBase;
|
||||
} // namespace VideoCore
|
||||
namespace Core {
|
||||
class System;
|
||||
namespace Timing {
|
||||
struct EventType;
|
||||
} // namespace Timing
|
||||
} // namespace Core
|
||||
|
||||
namespace VideoCommon::GPUThread {
|
||||
|
||||
@@ -75,63 +78,47 @@ using CommandData =
|
||||
struct CommandDataContainer {
|
||||
CommandDataContainer() = default;
|
||||
|
||||
CommandDataContainer(CommandData&& data) : data{std::move(data)} {}
|
||||
CommandDataContainer(CommandData&& data, u64 next_fence)
|
||||
: data{std::move(data)}, fence{next_fence} {}
|
||||
|
||||
CommandDataContainer& operator=(const CommandDataContainer& t) {
|
||||
data = std::move(t.data);
|
||||
fence = t.fence;
|
||||
return *this;
|
||||
}
|
||||
|
||||
CommandData data;
|
||||
u64 fence{};
|
||||
};
|
||||
|
||||
/// Struct used to synchronize the GPU thread
|
||||
struct SynchState final {
|
||||
std::atomic_bool is_running{true};
|
||||
std::atomic_int queued_frame_count{};
|
||||
std::mutex frames_mutex;
|
||||
std::mutex synchronization_mutex;
|
||||
std::mutex commands_mutex;
|
||||
std::condition_variable commands_condition;
|
||||
std::condition_variable frames_condition;
|
||||
std::condition_variable synchronization_condition;
|
||||
|
||||
void IncrementFramesCounter() {
|
||||
std::lock_guard lock{frames_mutex};
|
||||
++queued_frame_count;
|
||||
/// Returns true if the gap in GPU commands is small enough that we can consider the CPU and GPU
|
||||
/// synchronized. This is entirely empirical.
|
||||
bool IsSynchronized() const {
|
||||
constexpr std::size_t max_queue_gap{5};
|
||||
return queue.Size() <= max_queue_gap;
|
||||
}
|
||||
|
||||
void DecrementFramesCounter() {
|
||||
{
|
||||
std::lock_guard lock{frames_mutex};
|
||||
--queued_frame_count;
|
||||
|
||||
if (queued_frame_count) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
frames_condition.notify_one();
|
||||
}
|
||||
|
||||
void WaitForFrames() {
|
||||
{
|
||||
std::lock_guard lock{frames_mutex};
|
||||
if (!queued_frame_count) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Wait for the GPU to be idle (all commands to be executed)
|
||||
{
|
||||
std::unique_lock lock{frames_mutex};
|
||||
frames_condition.wait(lock, [this] { return !queued_frame_count; });
|
||||
void TrySynchronize() {
|
||||
if (IsSynchronized()) {
|
||||
std::lock_guard<std::mutex> lock{synchronization_mutex};
|
||||
synchronization_condition.notify_one();
|
||||
}
|
||||
}
|
||||
|
||||
void WaitForSynchronization(u64 fence);
|
||||
|
||||
void SignalCommands() {
|
||||
{
|
||||
std::unique_lock lock{commands_mutex};
|
||||
if (queue.Empty()) {
|
||||
return;
|
||||
}
|
||||
if (queue.Empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
commands_condition.notify_one();
|
||||
@@ -144,12 +131,15 @@ struct SynchState final {
|
||||
|
||||
using CommandQueue = Common::SPSCQueue<CommandDataContainer>;
|
||||
CommandQueue queue;
|
||||
u64 last_fence{};
|
||||
std::atomic<u64> signaled_fence{};
|
||||
};
|
||||
|
||||
/// Class used to manage the GPU thread
|
||||
class ThreadManager final {
|
||||
public:
|
||||
explicit ThreadManager(VideoCore::RendererBase& renderer, Tegra::DmaPusher& dma_pusher);
|
||||
explicit ThreadManager(Core::System& system, VideoCore::RendererBase& renderer,
|
||||
Tegra::DmaPusher& dma_pusher);
|
||||
~ThreadManager();
|
||||
|
||||
/// Push GPU command entries to be processed
|
||||
@@ -170,11 +160,12 @@ public:
|
||||
|
||||
private:
|
||||
/// Pushes a command to be executed by the GPU thread
|
||||
void PushCommand(CommandData&& command_data);
|
||||
u64 PushCommand(CommandData&& command_data);
|
||||
|
||||
private:
|
||||
SynchState state;
|
||||
VideoCore::RendererBase& renderer;
|
||||
Core::System& system;
|
||||
Core::Timing::EventType* synchronization_event{};
|
||||
std::thread thread;
|
||||
std::thread::id thread_id;
|
||||
};
|
||||
|
||||
@@ -223,27 +223,21 @@ void MacroInterpreter::ProcessResult(ResultOperation operation, u32 reg, u32 res
|
||||
}
|
||||
|
||||
u32 MacroInterpreter::FetchParameter() {
|
||||
ASSERT(next_parameter_index < parameters.size());
|
||||
return parameters[next_parameter_index++];
|
||||
return parameters.at(next_parameter_index++);
|
||||
}
|
||||
|
||||
u32 MacroInterpreter::GetRegister(u32 register_id) const {
|
||||
// Register 0 is supposed to always return 0.
|
||||
if (register_id == 0)
|
||||
return 0;
|
||||
|
||||
ASSERT(register_id < registers.size());
|
||||
return registers[register_id];
|
||||
return registers.at(register_id);
|
||||
}
|
||||
|
||||
void MacroInterpreter::SetRegister(u32 register_id, u32 value) {
|
||||
// Register 0 is supposed to always return 0. NOP is implemented as a store to the zero
|
||||
// register.
|
||||
if (register_id == 0)
|
||||
// Register 0 is hardwired as the zero register.
|
||||
// Ensure no writes to it actually occur.
|
||||
if (register_id == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
ASSERT(register_id < registers.size());
|
||||
registers[register_id] = value;
|
||||
registers.at(register_id) = value;
|
||||
}
|
||||
|
||||
void MacroInterpreter::SetMethodAddress(u32 address) {
|
||||
|
||||
@@ -5,16 +5,13 @@
|
||||
#include "common/alignment.h"
|
||||
#include "common/assert.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "core/core.h"
|
||||
#include "core/memory.h"
|
||||
#include "video_core/gpu.h"
|
||||
#include "video_core/memory_manager.h"
|
||||
#include "video_core/rasterizer_interface.h"
|
||||
#include "video_core/renderer_base.h"
|
||||
|
||||
namespace Tegra {
|
||||
|
||||
MemoryManager::MemoryManager() {
|
||||
MemoryManager::MemoryManager(VideoCore::RasterizerInterface& rasterizer) : rasterizer{rasterizer} {
|
||||
std::fill(page_table.pointers.begin(), page_table.pointers.end(), nullptr);
|
||||
std::fill(page_table.attributes.begin(), page_table.attributes.end(),
|
||||
Common::PageType::Unmapped);
|
||||
@@ -70,23 +67,23 @@ GPUVAddr MemoryManager::UnmapBuffer(GPUVAddr gpu_addr, u64 size) {
|
||||
const u64 aligned_size{Common::AlignUp(size, page_size)};
|
||||
const CacheAddr cache_addr{ToCacheAddr(GetPointer(gpu_addr))};
|
||||
|
||||
Core::System::GetInstance().Renderer().Rasterizer().FlushAndInvalidateRegion(cache_addr,
|
||||
aligned_size);
|
||||
rasterizer.FlushAndInvalidateRegion(cache_addr, aligned_size);
|
||||
UnmapRange(gpu_addr, aligned_size);
|
||||
|
||||
return gpu_addr;
|
||||
}
|
||||
|
||||
GPUVAddr MemoryManager::FindFreeRegion(GPUVAddr region_start, u64 size) {
|
||||
GPUVAddr MemoryManager::FindFreeRegion(GPUVAddr region_start, u64 size) const {
|
||||
// Find the first Free VMA.
|
||||
const VMAHandle vma_handle{std::find_if(vma_map.begin(), vma_map.end(), [&](const auto& vma) {
|
||||
if (vma.second.type != VirtualMemoryArea::Type::Unmapped) {
|
||||
return false;
|
||||
}
|
||||
const VMAHandle vma_handle{
|
||||
std::find_if(vma_map.begin(), vma_map.end(), [region_start, size](const auto& vma) {
|
||||
if (vma.second.type != VirtualMemoryArea::Type::Unmapped) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const VAddr vma_end{vma.second.base + vma.second.size};
|
||||
return vma_end > region_start && vma_end >= region_start + size;
|
||||
})};
|
||||
const VAddr vma_end{vma.second.base + vma.second.size};
|
||||
return vma_end > region_start && vma_end >= region_start + size;
|
||||
})};
|
||||
|
||||
if (vma_handle == vma_map.end()) {
|
||||
return {};
|
||||
@@ -99,12 +96,12 @@ bool MemoryManager::IsAddressValid(GPUVAddr addr) const {
|
||||
return (addr >> page_bits) < page_table.pointers.size();
|
||||
}
|
||||
|
||||
std::optional<VAddr> MemoryManager::GpuToCpuAddress(GPUVAddr addr) {
|
||||
std::optional<VAddr> MemoryManager::GpuToCpuAddress(GPUVAddr addr) const {
|
||||
if (!IsAddressValid(addr)) {
|
||||
return {};
|
||||
}
|
||||
|
||||
VAddr cpu_addr{page_table.backing_addr[addr >> page_bits]};
|
||||
const VAddr cpu_addr{page_table.backing_addr[addr >> page_bits]};
|
||||
if (cpu_addr) {
|
||||
return cpu_addr + (addr & page_mask);
|
||||
}
|
||||
@@ -113,7 +110,7 @@ std::optional<VAddr> MemoryManager::GpuToCpuAddress(GPUVAddr addr) {
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T MemoryManager::Read(GPUVAddr addr) {
|
||||
T MemoryManager::Read(GPUVAddr addr) const {
|
||||
if (!IsAddressValid(addr)) {
|
||||
return {};
|
||||
}
|
||||
@@ -165,10 +162,10 @@ void MemoryManager::Write(GPUVAddr addr, T data) {
|
||||
}
|
||||
}
|
||||
|
||||
template u8 MemoryManager::Read<u8>(GPUVAddr addr);
|
||||
template u16 MemoryManager::Read<u16>(GPUVAddr addr);
|
||||
template u32 MemoryManager::Read<u32>(GPUVAddr addr);
|
||||
template u64 MemoryManager::Read<u64>(GPUVAddr addr);
|
||||
template u8 MemoryManager::Read<u8>(GPUVAddr addr) const;
|
||||
template u16 MemoryManager::Read<u16>(GPUVAddr addr) const;
|
||||
template u32 MemoryManager::Read<u32>(GPUVAddr addr) const;
|
||||
template u64 MemoryManager::Read<u64>(GPUVAddr addr) const;
|
||||
template void MemoryManager::Write<u8>(GPUVAddr addr, u8 data);
|
||||
template void MemoryManager::Write<u16>(GPUVAddr addr, u16 data);
|
||||
template void MemoryManager::Write<u32>(GPUVAddr addr, u32 data);
|
||||
@@ -179,8 +176,8 @@ u8* MemoryManager::GetPointer(GPUVAddr addr) {
|
||||
return {};
|
||||
}
|
||||
|
||||
u8* page_pointer{page_table.pointers[addr >> page_bits]};
|
||||
if (page_pointer) {
|
||||
u8* const page_pointer{page_table.pointers[addr >> page_bits]};
|
||||
if (page_pointer != nullptr) {
|
||||
return page_pointer + (addr & page_mask);
|
||||
}
|
||||
|
||||
@@ -188,15 +185,100 @@ u8* MemoryManager::GetPointer(GPUVAddr addr) {
|
||||
return {};
|
||||
}
|
||||
|
||||
void MemoryManager::ReadBlock(GPUVAddr src_addr, void* dest_buffer, std::size_t size) {
|
||||
std::memcpy(dest_buffer, GetPointer(src_addr), size);
|
||||
const u8* MemoryManager::GetPointer(GPUVAddr addr) const {
|
||||
if (!IsAddressValid(addr)) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const u8* const page_pointer{page_table.pointers[addr >> page_bits]};
|
||||
if (page_pointer != nullptr) {
|
||||
return page_pointer + (addr & page_mask);
|
||||
}
|
||||
|
||||
LOG_ERROR(HW_GPU, "Unknown GetPointer @ 0x{:016X}", addr);
|
||||
return {};
|
||||
}
|
||||
|
||||
void MemoryManager::ReadBlock(GPUVAddr src_addr, void* dest_buffer, std::size_t size) const {
|
||||
std::size_t remaining_size{size};
|
||||
std::size_t page_index{src_addr >> page_bits};
|
||||
std::size_t page_offset{src_addr & page_mask};
|
||||
|
||||
while (remaining_size > 0) {
|
||||
const std::size_t copy_amount{
|
||||
std::min(static_cast<std::size_t>(page_size) - page_offset, remaining_size)};
|
||||
|
||||
switch (page_table.attributes[page_index]) {
|
||||
case Common::PageType::Memory: {
|
||||
const u8* src_ptr{page_table.pointers[page_index] + page_offset};
|
||||
rasterizer.FlushRegion(ToCacheAddr(src_ptr), copy_amount);
|
||||
std::memcpy(dest_buffer, src_ptr, copy_amount);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
page_index++;
|
||||
page_offset = 0;
|
||||
dest_buffer = static_cast<u8*>(dest_buffer) + copy_amount;
|
||||
remaining_size -= copy_amount;
|
||||
}
|
||||
}
|
||||
|
||||
void MemoryManager::WriteBlock(GPUVAddr dest_addr, const void* src_buffer, std::size_t size) {
|
||||
std::memcpy(GetPointer(dest_addr), src_buffer, size);
|
||||
std::size_t remaining_size{size};
|
||||
std::size_t page_index{dest_addr >> page_bits};
|
||||
std::size_t page_offset{dest_addr & page_mask};
|
||||
|
||||
while (remaining_size > 0) {
|
||||
const std::size_t copy_amount{
|
||||
std::min(static_cast<std::size_t>(page_size) - page_offset, remaining_size)};
|
||||
|
||||
switch (page_table.attributes[page_index]) {
|
||||
case Common::PageType::Memory: {
|
||||
u8* dest_ptr{page_table.pointers[page_index] + page_offset};
|
||||
rasterizer.InvalidateRegion(ToCacheAddr(dest_ptr), copy_amount);
|
||||
std::memcpy(dest_ptr, src_buffer, copy_amount);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
page_index++;
|
||||
page_offset = 0;
|
||||
src_buffer = static_cast<const u8*>(src_buffer) + copy_amount;
|
||||
remaining_size -= copy_amount;
|
||||
}
|
||||
}
|
||||
|
||||
void MemoryManager::CopyBlock(GPUVAddr dest_addr, GPUVAddr src_addr, std::size_t size) {
|
||||
std::memcpy(GetPointer(dest_addr), GetPointer(src_addr), size);
|
||||
std::size_t remaining_size{size};
|
||||
std::size_t page_index{src_addr >> page_bits};
|
||||
std::size_t page_offset{src_addr & page_mask};
|
||||
|
||||
while (remaining_size > 0) {
|
||||
const std::size_t copy_amount{
|
||||
std::min(static_cast<std::size_t>(page_size) - page_offset, remaining_size)};
|
||||
|
||||
switch (page_table.attributes[page_index]) {
|
||||
case Common::PageType::Memory: {
|
||||
const u8* src_ptr{page_table.pointers[page_index] + page_offset};
|
||||
rasterizer.FlushRegion(ToCacheAddr(src_ptr), copy_amount);
|
||||
WriteBlock(dest_addr, src_ptr, copy_amount);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
page_index++;
|
||||
page_offset = 0;
|
||||
dest_addr += static_cast<VAddr>(copy_amount);
|
||||
src_addr += static_cast<VAddr>(copy_amount);
|
||||
remaining_size -= copy_amount;
|
||||
}
|
||||
}
|
||||
|
||||
void MemoryManager::MapPages(GPUVAddr base, u64 size, u8* memory, Common::PageType type,
|
||||
@@ -336,7 +418,7 @@ MemoryManager::VMAIter MemoryManager::CarveVMA(GPUVAddr base, u64 size) {
|
||||
const VirtualMemoryArea& vma{vma_handle->second};
|
||||
if (vma.type == VirtualMemoryArea::Type::Mapped) {
|
||||
// Region is already allocated
|
||||
return {};
|
||||
return vma_handle;
|
||||
}
|
||||
|
||||
const VAddr start_in_vma{base - vma.base};
|
||||
|
||||
@@ -10,6 +10,10 @@
|
||||
#include "common/common_types.h"
|
||||
#include "common/page_table.h"
|
||||
|
||||
namespace VideoCore {
|
||||
class RasterizerInterface;
|
||||
}
|
||||
|
||||
namespace Tegra {
|
||||
|
||||
/**
|
||||
@@ -43,24 +47,25 @@ struct VirtualMemoryArea {
|
||||
|
||||
class MemoryManager final {
|
||||
public:
|
||||
MemoryManager();
|
||||
MemoryManager(VideoCore::RasterizerInterface& rasterizer);
|
||||
|
||||
GPUVAddr AllocateSpace(u64 size, u64 align);
|
||||
GPUVAddr AllocateSpace(GPUVAddr addr, u64 size, u64 align);
|
||||
GPUVAddr MapBufferEx(VAddr cpu_addr, u64 size);
|
||||
GPUVAddr MapBufferEx(VAddr cpu_addr, GPUVAddr addr, u64 size);
|
||||
GPUVAddr UnmapBuffer(GPUVAddr addr, u64 size);
|
||||
std::optional<VAddr> GpuToCpuAddress(GPUVAddr addr);
|
||||
std::optional<VAddr> GpuToCpuAddress(GPUVAddr addr) const;
|
||||
|
||||
template <typename T>
|
||||
T Read(GPUVAddr addr);
|
||||
T Read(GPUVAddr addr) const;
|
||||
|
||||
template <typename T>
|
||||
void Write(GPUVAddr addr, T data);
|
||||
|
||||
u8* GetPointer(GPUVAddr addr);
|
||||
const u8* GetPointer(GPUVAddr addr) const;
|
||||
|
||||
void ReadBlock(GPUVAddr src_addr, void* dest_buffer, std::size_t size);
|
||||
void ReadBlock(GPUVAddr src_addr, void* dest_buffer, std::size_t size) const;
|
||||
void WriteBlock(GPUVAddr dest_addr, const void* src_buffer, std::size_t size);
|
||||
void CopyBlock(GPUVAddr dest_addr, GPUVAddr src_addr, std::size_t size);
|
||||
|
||||
@@ -127,7 +132,7 @@ private:
|
||||
void UpdatePageTableForVMA(const VirtualMemoryArea& vma);
|
||||
|
||||
/// Finds a free (unmapped region) of the specified size starting at the specified address.
|
||||
GPUVAddr FindFreeRegion(GPUVAddr region_start, u64 size);
|
||||
GPUVAddr FindFreeRegion(GPUVAddr region_start, u64 size) const;
|
||||
|
||||
private:
|
||||
static constexpr u64 page_bits{16};
|
||||
@@ -143,6 +148,7 @@ private:
|
||||
|
||||
Common::PageTable page_table{page_bits};
|
||||
VMAMap vma_map;
|
||||
VideoCore::RasterizerInterface& rasterizer;
|
||||
};
|
||||
|
||||
} // namespace Tegra
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
|
||||
#include "common/alignment.h"
|
||||
#include "core/core.h"
|
||||
#include "core/memory.h"
|
||||
#include "video_core/renderer_opengl/gl_buffer_cache.h"
|
||||
#include "video_core/renderer_opengl/gl_rasterizer.h"
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
|
||||
#include <glad/glad.h>
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "core/core.h"
|
||||
#include "video_core/renderer_opengl/gl_global_cache.h"
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#include "common/assert.h"
|
||||
#include "common/common_types.h"
|
||||
#include "core/core.h"
|
||||
#include "core/memory.h"
|
||||
#include "video_core/memory_manager.h"
|
||||
#include "video_core/renderer_opengl/gl_buffer_cache.h"
|
||||
#include "video_core/renderer_opengl/gl_primitive_assembler.h"
|
||||
|
||||
|
||||
@@ -4,11 +4,9 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <glad/glad.h>
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "video_core/memory_manager.h"
|
||||
|
||||
namespace OpenGL {
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user