Compare commits
16 Commits
auto-objec
...
msvc-clean
Author | SHA1 | Date | |
---|---|---|---|
2e963dee02 | |||
b62278d16e | |||
3f55c6b813 | |||
6c55ebac77 | |||
5c2a0c4e37 | |||
0afaa31df5 | |||
bd1ffc34ef | |||
d487afd43c | |||
d4c26a6d95 | |||
2db9328087 | |||
6b4ff943da | |||
9a6d15ab74 | |||
60584e861d | |||
070853b465 | |||
24b5ffbfca | |||
4d9eedd0d8 |
10
.ci/linux.sh
10
.ci/linux.sh
@ -1,13 +1,15 @@
|
|||||||
#!/bin/sh -ex
|
#!/bin/bash -ex
|
||||||
|
|
||||||
|
if [ "$TARGET" = "appimage" ]; then
|
||||||
|
export COMPILER_FLAGS=(-DCMAKE_CXX_COMPILER=clang++ -DCMAKE_C_COMPILER=clang -DCMAKE_LINKER=/etc/bin/ld.lld)
|
||||||
|
fi
|
||||||
|
|
||||||
mkdir build && cd build
|
mkdir build && cd build
|
||||||
cmake .. -G Ninja \
|
cmake .. -G Ninja \
|
||||||
-DCMAKE_BUILD_TYPE=Release \
|
-DCMAKE_BUILD_TYPE=Release \
|
||||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
||||||
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
||||||
-DCMAKE_CXX_COMPILER=clang++ \
|
"${COMPILER_FLAGS[@]}" \
|
||||||
-DCMAKE_C_COMPILER=clang \
|
|
||||||
-DCMAKE_LINKER=/etc/bin/ld.lld \
|
|
||||||
-DENABLE_QT_TRANSLATION=ON \
|
-DENABLE_QT_TRANSLATION=ON \
|
||||||
-DCITRA_ENABLE_COMPATIBILITY_REPORTING=ON \
|
-DCITRA_ENABLE_COMPATIBILITY_REPORTING=ON \
|
||||||
-DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON \
|
-DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON \
|
||||||
|
@ -124,6 +124,13 @@ else()
|
|||||||
add_compile_options("-stdlib=libc++")
|
add_compile_options("-stdlib=libc++")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if (CMAKE_CXX_COMPILER_ID STREQUAL GNU)
|
||||||
|
# GCC may warn when it ignores attributes like maybe_unused,
|
||||||
|
# which is a problem for older versions (e.g. GCC 11).
|
||||||
|
add_compile_options("-Wno-attributes")
|
||||||
|
add_compile_options("-Wno-interference-size")
|
||||||
|
endif()
|
||||||
|
|
||||||
if (MINGW)
|
if (MINGW)
|
||||||
add_definitions(-DMINGW_HAS_SECURE_API)
|
add_definitions(-DMINGW_HAS_SECURE_API)
|
||||||
if (COMPILE_WITH_DWARF)
|
if (COMPILE_WITH_DWARF)
|
||||||
|
@ -29,7 +29,7 @@ android {
|
|||||||
namespace = "org.citra.citra_emu"
|
namespace = "org.citra.citra_emu"
|
||||||
|
|
||||||
compileSdkVersion = "android-34"
|
compileSdkVersion = "android-34"
|
||||||
ndkVersion = "25.2.9519653"
|
ndkVersion = "26.1.10909125"
|
||||||
|
|
||||||
compileOptions {
|
compileOptions {
|
||||||
sourceCompatibility = JavaVersion.VERSION_17
|
sourceCompatibility = JavaVersion.VERSION_17
|
||||||
|
@ -83,14 +83,6 @@ class GMainWindow : public QMainWindow {
|
|||||||
/// Max number of recently loaded items to keep track of
|
/// Max number of recently loaded items to keep track of
|
||||||
static const int max_recent_files_item = 10;
|
static const int max_recent_files_item = 10;
|
||||||
|
|
||||||
// TODO: Make use of this!
|
|
||||||
enum {
|
|
||||||
UI_IDLE,
|
|
||||||
UI_EMU_BOOTING,
|
|
||||||
UI_EMU_RUNNING,
|
|
||||||
UI_EMU_STOPPING,
|
|
||||||
};
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void filterBarSetChecked(bool state);
|
void filterBarSetChecked(bool state);
|
||||||
void UpdateUITheme();
|
void UpdateUITheme();
|
||||||
|
@ -90,7 +90,6 @@ add_library(citra_common STATIC
|
|||||||
file_util.cpp
|
file_util.cpp
|
||||||
file_util.h
|
file_util.h
|
||||||
hash.h
|
hash.h
|
||||||
linear_disk_cache.h
|
|
||||||
literals.h
|
literals.h
|
||||||
logging/backend.cpp
|
logging/backend.cpp
|
||||||
logging/backend.h
|
logging/backend.h
|
||||||
@ -110,7 +109,6 @@ add_library(citra_common STATIC
|
|||||||
microprofile.cpp
|
microprofile.cpp
|
||||||
microprofile.h
|
microprofile.h
|
||||||
microprofileui.h
|
microprofileui.h
|
||||||
misc.cpp
|
|
||||||
param_package.cpp
|
param_package.cpp
|
||||||
param_package.h
|
param_package.h
|
||||||
polyfill_thread.h
|
polyfill_thread.h
|
||||||
@ -127,6 +125,7 @@ add_library(citra_common STATIC
|
|||||||
serialization/boost_discrete_interval.hpp
|
serialization/boost_discrete_interval.hpp
|
||||||
serialization/boost_flat_set.h
|
serialization/boost_flat_set.h
|
||||||
serialization/boost_small_vector.hpp
|
serialization/boost_small_vector.hpp
|
||||||
|
serialization/boost_std_variant.hpp
|
||||||
serialization/boost_vector.hpp
|
serialization/boost_vector.hpp
|
||||||
static_lru_cache.h
|
static_lru_cache.h
|
||||||
string_literal.h
|
string_literal.h
|
||||||
|
@ -2,78 +2,14 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <bit>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#ifdef _WIN32
|
|
||||||
#include <intrin.h>
|
|
||||||
#endif
|
|
||||||
#include <initializer_list>
|
#include <initializer_list>
|
||||||
#include <new>
|
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
|
|
||||||
// namespace avoids conflict with OS X Carbon; don't use BitSet<T> directly
|
|
||||||
namespace Common {
|
namespace Common {
|
||||||
|
|
||||||
// Helper functions:
|
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
|
||||||
template <typename T>
|
|
||||||
static inline int CountSetBits(T v) {
|
|
||||||
// from https://graphics.stanford.edu/~seander/bithacks.html
|
|
||||||
// GCC has this built in, but MSVC's intrinsic will only emit the actual
|
|
||||||
// POPCNT instruction, which we're not depending on
|
|
||||||
v = v - ((v >> 1) & (T) ~(T)0 / 3);
|
|
||||||
v = (v & (T) ~(T)0 / 15 * 3) + ((v >> 2) & (T) ~(T)0 / 15 * 3);
|
|
||||||
v = (v + (v >> 4)) & (T) ~(T)0 / 255 * 15;
|
|
||||||
return (T)(v * ((T) ~(T)0 / 255)) >> (sizeof(T) - 1) * 8;
|
|
||||||
}
|
|
||||||
static inline int LeastSignificantSetBit(u8 val) {
|
|
||||||
unsigned long index;
|
|
||||||
_BitScanForward(&index, val);
|
|
||||||
return (int)index;
|
|
||||||
}
|
|
||||||
static inline int LeastSignificantSetBit(u16 val) {
|
|
||||||
unsigned long index;
|
|
||||||
_BitScanForward(&index, val);
|
|
||||||
return (int)index;
|
|
||||||
}
|
|
||||||
static inline int LeastSignificantSetBit(u32 val) {
|
|
||||||
unsigned long index;
|
|
||||||
_BitScanForward(&index, val);
|
|
||||||
return (int)index;
|
|
||||||
}
|
|
||||||
static inline int LeastSignificantSetBit(u64 val) {
|
|
||||||
unsigned long index;
|
|
||||||
_BitScanForward64(&index, val);
|
|
||||||
return (int)index;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
static inline int CountSetBits(u8 val) {
|
|
||||||
return __builtin_popcount(val);
|
|
||||||
}
|
|
||||||
static inline int CountSetBits(u16 val) {
|
|
||||||
return __builtin_popcount(val);
|
|
||||||
}
|
|
||||||
static inline int CountSetBits(u32 val) {
|
|
||||||
return __builtin_popcount(val);
|
|
||||||
}
|
|
||||||
static inline int CountSetBits(u64 val) {
|
|
||||||
return __builtin_popcountll(val);
|
|
||||||
}
|
|
||||||
static inline int LeastSignificantSetBit(u8 val) {
|
|
||||||
return __builtin_ctz(val);
|
|
||||||
}
|
|
||||||
static inline int LeastSignificantSetBit(u16 val) {
|
|
||||||
return __builtin_ctz(val);
|
|
||||||
}
|
|
||||||
static inline int LeastSignificantSetBit(u32 val) {
|
|
||||||
return __builtin_ctz(val);
|
|
||||||
}
|
|
||||||
static inline int LeastSignificantSetBit(u64 val) {
|
|
||||||
return __builtin_ctzll(val);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Similar to std::bitset, this is a class which encapsulates a bitset, i.e.
|
// Similar to std::bitset, this is a class which encapsulates a bitset, i.e.
|
||||||
// using the set bits of an integer to represent a set of integers. Like that
|
// using the set bits of an integer to represent a set of integers. Like that
|
||||||
// class, it acts like an array of bools:
|
// class, it acts like an array of bools:
|
||||||
@ -92,22 +28,19 @@ static inline int LeastSignificantSetBit(u64 val) {
|
|||||||
// operation.)
|
// operation.)
|
||||||
// - Counting set bits using .Count() - see comment on that method.
|
// - Counting set bits using .Count() - see comment on that method.
|
||||||
|
|
||||||
// TODO: use constexpr when MSVC gets out of the Dark Ages
|
|
||||||
|
|
||||||
template <typename IntTy>
|
template <typename IntTy>
|
||||||
|
requires std::is_unsigned_v<IntTy>
|
||||||
class BitSet {
|
class BitSet {
|
||||||
static_assert(!std::is_signed_v<IntTy>, "BitSet should not be used with signed types");
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// A reference to a particular bit, returned from operator[].
|
// A reference to a particular bit, returned from operator[].
|
||||||
class Ref {
|
class Ref {
|
||||||
public:
|
public:
|
||||||
Ref(Ref&& other) : m_bs(other.m_bs), m_mask(other.m_mask) {}
|
constexpr Ref(Ref&& other) : m_bs(other.m_bs), m_mask(other.m_mask) {}
|
||||||
Ref(BitSet* bs, IntTy mask) : m_bs(bs), m_mask(mask) {}
|
constexpr Ref(BitSet* bs, IntTy mask) : m_bs(bs), m_mask(mask) {}
|
||||||
operator bool() const {
|
constexpr operator bool() const {
|
||||||
return (m_bs->m_val & m_mask) != 0;
|
return (m_bs->m_val & m_mask) != 0;
|
||||||
}
|
}
|
||||||
bool operator=(bool set) {
|
constexpr bool operator=(bool set) {
|
||||||
m_bs->m_val = (m_bs->m_val & ~m_mask) | (set ? m_mask : 0);
|
m_bs->m_val = (m_bs->m_val & ~m_mask) | (set ? m_mask : 0);
|
||||||
return set;
|
return set;
|
||||||
}
|
}
|
||||||
@ -120,26 +53,26 @@ public:
|
|||||||
// A STL-like iterator is required to be able to use range-based for loops.
|
// A STL-like iterator is required to be able to use range-based for loops.
|
||||||
class Iterator {
|
class Iterator {
|
||||||
public:
|
public:
|
||||||
Iterator(const Iterator& other) : m_val(other.m_val) {}
|
constexpr Iterator(const Iterator& other) : m_val(other.m_val) {}
|
||||||
Iterator(IntTy val) : m_val(val) {}
|
constexpr Iterator(IntTy val) : m_val(val) {}
|
||||||
int operator*() {
|
constexpr int operator*() {
|
||||||
// This will never be called when m_val == 0, because that would be the end() iterator
|
// This will never be called when m_val == 0, because that would be the end() iterator
|
||||||
return LeastSignificantSetBit(m_val);
|
return std::countr_zero(m_val);
|
||||||
}
|
}
|
||||||
Iterator& operator++() {
|
constexpr Iterator& operator++() {
|
||||||
// Unset least significant set bit
|
// Unset least significant set bit
|
||||||
m_val &= m_val - IntTy(1);
|
m_val &= m_val - IntTy(1);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
Iterator operator++(int _) {
|
constexpr Iterator operator++(int) {
|
||||||
Iterator other(*this);
|
Iterator other(*this);
|
||||||
++*this;
|
++*this;
|
||||||
return other;
|
return other;
|
||||||
}
|
}
|
||||||
bool operator==(Iterator other) const {
|
constexpr bool operator==(Iterator other) const {
|
||||||
return m_val == other.m_val;
|
return m_val == other.m_val;
|
||||||
}
|
}
|
||||||
bool operator!=(Iterator other) const {
|
constexpr bool operator!=(Iterator other) const {
|
||||||
return m_val != other.m_val;
|
return m_val != other.m_val;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -147,74 +80,69 @@ public:
|
|||||||
IntTy m_val;
|
IntTy m_val;
|
||||||
};
|
};
|
||||||
|
|
||||||
BitSet() : m_val(0) {}
|
constexpr BitSet() : m_val(0) {}
|
||||||
explicit BitSet(IntTy val) : m_val(val) {}
|
constexpr explicit BitSet(IntTy val) : m_val(val) {}
|
||||||
BitSet(std::initializer_list<int> init) {
|
constexpr BitSet(std::initializer_list<int> init) {
|
||||||
m_val = 0;
|
m_val = 0;
|
||||||
for (int bit : init)
|
for (int bit : init)
|
||||||
m_val |= (IntTy)1 << bit;
|
m_val |= (IntTy)1 << bit;
|
||||||
}
|
}
|
||||||
|
|
||||||
static BitSet AllTrue(std::size_t count) {
|
constexpr static BitSet AllTrue(std::size_t count) {
|
||||||
return BitSet(count == sizeof(IntTy) * 8 ? ~(IntTy)0 : (((IntTy)1 << count) - 1));
|
return BitSet(count == sizeof(IntTy) * 8 ? ~(IntTy)0 : (((IntTy)1 << count) - 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ref operator[](std::size_t bit) {
|
constexpr Ref operator[](std::size_t bit) {
|
||||||
return Ref(this, (IntTy)1 << bit);
|
return Ref(this, (IntTy)1 << bit);
|
||||||
}
|
}
|
||||||
const Ref operator[](std::size_t bit) const {
|
constexpr const Ref operator[](std::size_t bit) const {
|
||||||
return (*const_cast<BitSet*>(this))[bit];
|
return (*const_cast<BitSet*>(this))[bit];
|
||||||
}
|
}
|
||||||
bool operator==(BitSet other) const {
|
constexpr bool operator==(BitSet other) const {
|
||||||
return m_val == other.m_val;
|
return m_val == other.m_val;
|
||||||
}
|
}
|
||||||
bool operator!=(BitSet other) const {
|
constexpr bool operator!=(BitSet other) const {
|
||||||
return m_val != other.m_val;
|
return m_val != other.m_val;
|
||||||
}
|
}
|
||||||
bool operator<(BitSet other) const {
|
constexpr bool operator<(BitSet other) const {
|
||||||
return m_val < other.m_val;
|
return m_val < other.m_val;
|
||||||
}
|
}
|
||||||
bool operator>(BitSet other) const {
|
constexpr bool operator>(BitSet other) const {
|
||||||
return m_val > other.m_val;
|
return m_val > other.m_val;
|
||||||
}
|
}
|
||||||
BitSet operator|(BitSet other) const {
|
constexpr BitSet operator|(BitSet other) const {
|
||||||
return BitSet(m_val | other.m_val);
|
return BitSet(m_val | other.m_val);
|
||||||
}
|
}
|
||||||
BitSet operator&(BitSet other) const {
|
constexpr BitSet operator&(BitSet other) const {
|
||||||
return BitSet(m_val & other.m_val);
|
return BitSet(m_val & other.m_val);
|
||||||
}
|
}
|
||||||
BitSet operator^(BitSet other) const {
|
constexpr BitSet operator^(BitSet other) const {
|
||||||
return BitSet(m_val ^ other.m_val);
|
return BitSet(m_val ^ other.m_val);
|
||||||
}
|
}
|
||||||
BitSet operator~() const {
|
constexpr BitSet operator~() const {
|
||||||
return BitSet(~m_val);
|
return BitSet(~m_val);
|
||||||
}
|
}
|
||||||
BitSet& operator|=(BitSet other) {
|
constexpr BitSet& operator|=(BitSet other) {
|
||||||
return *this = *this | other;
|
return *this = *this | other;
|
||||||
}
|
}
|
||||||
BitSet& operator&=(BitSet other) {
|
constexpr BitSet& operator&=(BitSet other) {
|
||||||
return *this = *this & other;
|
return *this = *this & other;
|
||||||
}
|
}
|
||||||
BitSet& operator^=(BitSet other) {
|
constexpr BitSet& operator^=(BitSet other) {
|
||||||
return *this = *this ^ other;
|
return *this = *this ^ other;
|
||||||
}
|
}
|
||||||
operator u32() = delete;
|
operator u32() = delete;
|
||||||
operator bool() {
|
constexpr operator bool() {
|
||||||
return m_val != 0;
|
return m_val != 0;
|
||||||
}
|
}
|
||||||
|
constexpr u32 Count() const {
|
||||||
// Warning: Even though on modern CPUs this is a single fast instruction,
|
return std::popcount(m_val);
|
||||||
// Dolphin's official builds do not currently assume POPCNT support on x86,
|
|
||||||
// so slower explicit bit twiddling is generated. Still should generally
|
|
||||||
// be faster than a loop.
|
|
||||||
unsigned int Count() const {
|
|
||||||
return CountSetBits(m_val);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Iterator begin() const {
|
constexpr Iterator begin() const {
|
||||||
return Iterator(m_val);
|
return Iterator(m_val);
|
||||||
}
|
}
|
||||||
Iterator end() const {
|
constexpr Iterator end() const {
|
||||||
return Iterator(0);
|
return Iterator(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
|
|
||||||
/// Textually concatenates two tokens. The double-expansion is required by the C preprocessor.
|
/// Textually concatenates two tokens. The double-expansion is required by the C preprocessor.
|
||||||
@ -46,14 +45,8 @@ __declspec(dllimport) void __stdcall DebugBreak(void);
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
#if (_MSC_VER < 1900)
|
|
||||||
// Function Cross-Compatibility
|
|
||||||
#define snprintf _snprintf
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Locale Cross-Compatibility
|
// Locale Cross-Compatibility
|
||||||
#define locale_t _locale_t
|
#define locale_t _locale_t
|
||||||
|
|
||||||
#endif // _MSC_VER
|
#endif // _MSC_VER
|
||||||
|
|
||||||
#define DECLARE_ENUM_FLAG_OPERATORS(type) \
|
#define DECLARE_ENUM_FLAG_OPERATORS(type) \
|
||||||
@ -109,9 +102,3 @@ __declspec(dllimport) void __stdcall DebugBreak(void);
|
|||||||
using T = std::underlying_type_t<type>; \
|
using T = std::underlying_type_t<type>; \
|
||||||
return static_cast<T>(key) == 0; \
|
return static_cast<T>(key) == 0; \
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generic function to get last error message.
|
|
||||||
// Call directly after the command or use the error num.
|
|
||||||
// This function might change the error code.
|
|
||||||
// Defined in Misc.cpp.
|
|
||||||
[[nodiscard]] std::string GetLastErrorMsg();
|
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
#include "common/common_funcs.h"
|
#include "common/common_funcs.h"
|
||||||
#include "common/common_paths.h"
|
#include "common/common_paths.h"
|
||||||
|
#include "common/error.h"
|
||||||
#include "common/file_util.h"
|
#include "common/file_util.h"
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
#include "common/scope_exit.h"
|
#include "common/scope_exit.h"
|
||||||
@ -90,6 +91,8 @@
|
|||||||
// REMEMBER: strdup considered harmful!
|
// REMEMBER: strdup considered harmful!
|
||||||
namespace FileUtil {
|
namespace FileUtil {
|
||||||
|
|
||||||
|
using Common::GetLastErrorMsg;
|
||||||
|
|
||||||
// Remove any ending forward slashes from directory paths
|
// Remove any ending forward slashes from directory paths
|
||||||
// Modifies argument.
|
// Modifies argument.
|
||||||
static void StripTailDirSlashes(std::string& fname) {
|
static void StripTailDirSlashes(std::string& fname) {
|
||||||
|
@ -1,168 +0,0 @@
|
|||||||
// Copyright 2013 Dolphin Emulator Project / 2014 Citra Emulator Project
|
|
||||||
// Licensed under GPLv2 or any later version
|
|
||||||
// Refer to the license.txt file included.
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <fstream>
|
|
||||||
#include <vector>
|
|
||||||
#include "common/common_types.h"
|
|
||||||
|
|
||||||
// defined in Version.cpp
|
|
||||||
extern const char* scm_rev_git_str;
|
|
||||||
|
|
||||||
// On disk format:
|
|
||||||
// header{
|
|
||||||
// u32 'DCAC';
|
|
||||||
// u32 version; // svn_rev
|
|
||||||
// u16 sizeof(key_type);
|
|
||||||
// u16 sizeof(value_type);
|
|
||||||
//}
|
|
||||||
|
|
||||||
// key_value_pair{
|
|
||||||
// u32 value_size;
|
|
||||||
// key_type key;
|
|
||||||
// value_type[value_size] value;
|
|
||||||
//}
|
|
||||||
|
|
||||||
template <typename K, typename V>
|
|
||||||
class LinearDiskCacheReader {
|
|
||||||
public:
|
|
||||||
virtual void Read(const K& key, const V* value, u32 value_size) = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Dead simple unsorted key-value store with append functionality.
|
|
||||||
// No random read functionality, all reading is done in OpenAndRead.
|
|
||||||
// Keys and values can contain any characters, including \0.
|
|
||||||
//
|
|
||||||
// Suitable for caching generated shader bytecode between executions.
|
|
||||||
// Not tuned for extreme performance but should be reasonably fast.
|
|
||||||
// Does not support keys or values larger than 2GB, which should be reasonable.
|
|
||||||
// Keys must have non-zero length; values can have zero length.
|
|
||||||
|
|
||||||
// K and V are some POD type
|
|
||||||
// K : the key type
|
|
||||||
// V : value array type
|
|
||||||
template <typename K, typename V>
|
|
||||||
class LinearDiskCache {
|
|
||||||
public:
|
|
||||||
// return number of read entries
|
|
||||||
u32 OpenAndRead(const char* filename, LinearDiskCacheReader<K, V>& reader) {
|
|
||||||
using std::ios_base;
|
|
||||||
|
|
||||||
// close any currently opened file
|
|
||||||
Close();
|
|
||||||
m_num_entries = 0;
|
|
||||||
|
|
||||||
// try opening for reading/writing
|
|
||||||
OpenFStream(m_file, filename, ios_base::in | ios_base::out | ios_base::binary);
|
|
||||||
|
|
||||||
m_file.seekg(0, std::ios::end);
|
|
||||||
std::fstream::pos_type end_pos = m_file.tellg();
|
|
||||||
m_file.seekg(0, std::ios::beg);
|
|
||||||
std::fstream::pos_type start_pos = m_file.tellg();
|
|
||||||
std::streamoff file_size = end_pos - start_pos;
|
|
||||||
|
|
||||||
if (m_file.is_open() && ValidateHeader()) {
|
|
||||||
// good header, read some key/value pairs
|
|
||||||
K key;
|
|
||||||
|
|
||||||
std::vector<V> value;
|
|
||||||
u32 value_size;
|
|
||||||
u32 entry_number;
|
|
||||||
|
|
||||||
std::fstream::pos_type last_pos = m_file.tellg();
|
|
||||||
|
|
||||||
while (Read(&value_size)) {
|
|
||||||
std::streamoff next_extent =
|
|
||||||
(last_pos - start_pos) + sizeof(value_size) + value_size;
|
|
||||||
if (next_extent > file_size)
|
|
||||||
break;
|
|
||||||
|
|
||||||
value.clear();
|
|
||||||
value.resize(value_size);
|
|
||||||
|
|
||||||
// read key/value and pass to reader
|
|
||||||
if (Read(&key) && Read(value.data(), value_size) && Read(&entry_number) &&
|
|
||||||
entry_number == m_num_entries + 1) {
|
|
||||||
reader.Read(key, value.data(), value_size);
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_num_entries++;
|
|
||||||
last_pos = m_file.tellg();
|
|
||||||
}
|
|
||||||
m_file.seekp(last_pos);
|
|
||||||
m_file.clear();
|
|
||||||
|
|
||||||
value.clear();
|
|
||||||
return m_num_entries;
|
|
||||||
}
|
|
||||||
|
|
||||||
// failed to open file for reading or bad header
|
|
||||||
// close and recreate file
|
|
||||||
Close();
|
|
||||||
m_file.open(filename, ios_base::out | ios_base::trunc | ios_base::binary);
|
|
||||||
WriteHeader();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Sync() {
|
|
||||||
m_file.flush();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Close() {
|
|
||||||
if (m_file.is_open())
|
|
||||||
m_file.close();
|
|
||||||
// clear any error flags
|
|
||||||
m_file.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Appends a key-value pair to the store.
|
|
||||||
void Append(const K& key, const V* value, u32 value_size) {
|
|
||||||
// TODO: Should do a check that we don't already have "key"? (I think each caller does that
|
|
||||||
// already.)
|
|
||||||
Write(&value_size);
|
|
||||||
Write(&key);
|
|
||||||
Write(value, value_size);
|
|
||||||
m_num_entries++;
|
|
||||||
Write(&m_num_entries);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
void WriteHeader() {
|
|
||||||
Write(&m_header);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ValidateHeader() {
|
|
||||||
char file_header[sizeof(Header)];
|
|
||||||
|
|
||||||
return (Read(file_header, sizeof(Header)) &&
|
|
||||||
!memcmp((const char*)&m_header, file_header, sizeof(Header)));
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename D>
|
|
||||||
bool Write(const D* data, u32 count = 1) {
|
|
||||||
return m_file.write((const char*)data, count * sizeof(D)).good();
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename D>
|
|
||||||
bool Read(const D* data, u32 count = 1) {
|
|
||||||
return m_file.read((char*)data, count * sizeof(D)).good();
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Header {
|
|
||||||
Header() : id(*(u32*)"DCAC"), key_t_size(sizeof(K)), value_t_size(sizeof(V)) {
|
|
||||||
std::memcpy(ver, scm_rev_git_str, 40);
|
|
||||||
}
|
|
||||||
|
|
||||||
const u32 id;
|
|
||||||
const u16 key_t_size, value_t_size;
|
|
||||||
char ver[40];
|
|
||||||
|
|
||||||
} m_header;
|
|
||||||
|
|
||||||
std::fstream m_file;
|
|
||||||
u32 m_num_entries;
|
|
||||||
};
|
|
@ -1,48 +0,0 @@
|
|||||||
// Copyright 2013 Dolphin Emulator Project / 2014 Citra Emulator Project
|
|
||||||
// Licensed under GPLv2 or any later version
|
|
||||||
// Refer to the license.txt file included.
|
|
||||||
|
|
||||||
#include <cstddef>
|
|
||||||
#ifdef _WIN32
|
|
||||||
#include <windows.h>
|
|
||||||
#else
|
|
||||||
#include <cerrno>
|
|
||||||
#include <cstring>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "common/common_funcs.h"
|
|
||||||
|
|
||||||
// Generic function to get last error message.
|
|
||||||
// Call directly after the command or use the error num.
|
|
||||||
// This function might change the error code.
|
|
||||||
std::string GetLastErrorMsg() {
|
|
||||||
#ifdef _WIN32
|
|
||||||
LPSTR err_str;
|
|
||||||
|
|
||||||
DWORD res = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
|
||||||
FORMAT_MESSAGE_IGNORE_INSERTS,
|
|
||||||
nullptr, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
|
||||||
reinterpret_cast<LPSTR>(&err_str), 1, nullptr);
|
|
||||||
if (!res) {
|
|
||||||
return "(FormatMessageA failed to format error)";
|
|
||||||
}
|
|
||||||
std::string ret(err_str);
|
|
||||||
LocalFree(err_str);
|
|
||||||
return ret;
|
|
||||||
#else
|
|
||||||
char err_str[255];
|
|
||||||
#if (defined(__GLIBC__) || __ANDROID_API__ >= 23) && \
|
|
||||||
(_GNU_SOURCE || (_POSIX_C_SOURCE < 200112L && _XOPEN_SOURCE < 600))
|
|
||||||
// Thread safe (GNU-specific)
|
|
||||||
const char* str = strerror_r(errno, err_str, sizeof(err_str));
|
|
||||||
return std::string(str);
|
|
||||||
#else
|
|
||||||
// Thread safe (XSI-compliant)
|
|
||||||
int second_err = strerror_r(errno, err_str, sizeof(err_str));
|
|
||||||
if (second_err != 0) {
|
|
||||||
return "(strerror_r failed to format error)";
|
|
||||||
}
|
|
||||||
return std::string(err_str);
|
|
||||||
#endif // GLIBC etc.
|
|
||||||
#endif // _WIN32
|
|
||||||
}
|
|
@ -105,9 +105,7 @@ public:
|
|||||||
private:
|
private:
|
||||||
// It is important to separate the below atomics for performance reasons:
|
// It is important to separate the below atomics for performance reasons:
|
||||||
// Having them on the same cache-line would result in false-sharing between them.
|
// Having them on the same cache-line would result in false-sharing between them.
|
||||||
// TODO: Remove this ifdef whenever clang and GCC support
|
#ifdef __cpp_lib_hardware_interference_size
|
||||||
// std::hardware_destructive_interference_size.
|
|
||||||
#if defined(_MSC_VER) && _MSC_VER >= 1911
|
|
||||||
static constexpr std::size_t padding_size =
|
static constexpr std::size_t padding_size =
|
||||||
std::hardware_destructive_interference_size - sizeof(std::atomic_size_t);
|
std::hardware_destructive_interference_size - sizeof(std::atomic_size_t);
|
||||||
#else
|
#else
|
||||||
|
204
src/common/serialization/boost_std_variant.hpp
Normal file
204
src/common/serialization/boost_std_variant.hpp
Normal file
@ -0,0 +1,204 @@
|
|||||||
|
#ifndef BOOST_SERIALIZATION_STD_VARIANT_HPP
|
||||||
|
#define BOOST_SERIALIZATION_STD_VARIANT_HPP
|
||||||
|
|
||||||
|
// MS compatible compilers support #pragma once
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
# pragma once
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
|
||||||
|
// variant.hpp - non-intrusive serialization of variant types
|
||||||
|
//
|
||||||
|
// copyright (c) 2019 Samuel Debionne, ESRF
|
||||||
|
//
|
||||||
|
// Use, modification and distribution is subject to the Boost Software
|
||||||
|
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||||
|
// http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
//
|
||||||
|
// See http://www.boost.org for updates, documentation, and revision history.
|
||||||
|
//
|
||||||
|
// Widely inspired form boost::variant serialization
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <boost/serialization/throw_exception.hpp>
|
||||||
|
|
||||||
|
#include <variant>
|
||||||
|
|
||||||
|
#include <boost/archive/archive_exception.hpp>
|
||||||
|
|
||||||
|
#include <boost/serialization/split_free.hpp>
|
||||||
|
#include <boost/serialization/serialization.hpp>
|
||||||
|
#include <boost/serialization/nvp.hpp>
|
||||||
|
|
||||||
|
namespace boost {
|
||||||
|
namespace serialization {
|
||||||
|
|
||||||
|
template<class Archive>
|
||||||
|
struct std_variant_save_visitor
|
||||||
|
{
|
||||||
|
std_variant_save_visitor(Archive& ar) :
|
||||||
|
m_ar(ar)
|
||||||
|
{}
|
||||||
|
template<class T>
|
||||||
|
void operator()(T const & value) const
|
||||||
|
{
|
||||||
|
m_ar << BOOST_SERIALIZATION_NVP(value);
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
Archive & m_ar;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
template<class Archive>
|
||||||
|
struct std_variant_load_visitor
|
||||||
|
{
|
||||||
|
std_variant_load_visitor(Archive& ar) :
|
||||||
|
m_ar(ar)
|
||||||
|
{}
|
||||||
|
template<class T>
|
||||||
|
void operator()(T & value) const
|
||||||
|
{
|
||||||
|
m_ar >> BOOST_SERIALIZATION_NVP(value);
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
Archive & m_ar;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class Archive, class ...Types>
|
||||||
|
void save(
|
||||||
|
Archive & ar,
|
||||||
|
std::variant<Types...> const & v,
|
||||||
|
unsigned int /*version*/
|
||||||
|
){
|
||||||
|
const std::size_t which = v.index();
|
||||||
|
ar << BOOST_SERIALIZATION_NVP(which);
|
||||||
|
std_variant_save_visitor<Archive> visitor(ar);
|
||||||
|
std::visit(visitor, v);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Minimalist metaprogramming for handling parameter pack
|
||||||
|
namespace mp {
|
||||||
|
namespace detail {
|
||||||
|
template <typename Seq>
|
||||||
|
struct front_impl;
|
||||||
|
|
||||||
|
template <template <typename...> class Seq, typename T, typename... Ts>
|
||||||
|
struct front_impl<Seq<T, Ts...>> {
|
||||||
|
using type = T;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Seq>
|
||||||
|
struct pop_front_impl;
|
||||||
|
|
||||||
|
template <template <typename...> class Seq, typename T, typename... Ts>
|
||||||
|
struct pop_front_impl<Seq<T, Ts...>> {
|
||||||
|
using type = Seq<Ts...>;
|
||||||
|
};
|
||||||
|
} //namespace detail
|
||||||
|
|
||||||
|
template <typename... Ts>
|
||||||
|
struct typelist {};
|
||||||
|
|
||||||
|
template <typename Seq>
|
||||||
|
using front = typename detail::front_impl<Seq>::type;
|
||||||
|
|
||||||
|
template <typename Seq>
|
||||||
|
using pop_front = typename detail::pop_front_impl<Seq>::type;
|
||||||
|
} // namespace mp
|
||||||
|
|
||||||
|
template<std::size_t N, class Seq>
|
||||||
|
struct variant_impl
|
||||||
|
{
|
||||||
|
template<class Archive, class V>
|
||||||
|
static void load (
|
||||||
|
Archive & ar,
|
||||||
|
std::size_t which,
|
||||||
|
V & v,
|
||||||
|
const unsigned int version
|
||||||
|
){
|
||||||
|
if(which == 0){
|
||||||
|
// note: A non-intrusive implementation (such as this one)
|
||||||
|
// necessary has to copy the value. This wouldn't be necessary
|
||||||
|
// with an implementation that de-serialized to the address of the
|
||||||
|
// aligned storage included in the variant.
|
||||||
|
using type = mp::front<Seq>;
|
||||||
|
type value;
|
||||||
|
ar >> BOOST_SERIALIZATION_NVP(value);
|
||||||
|
v = std::move(value);
|
||||||
|
type * new_address = & std::get<type>(v);
|
||||||
|
ar.reset_object_address(new_address, & value);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
//typedef typename mpl::pop_front<S>::type type;
|
||||||
|
using types = mp::pop_front<Seq>;
|
||||||
|
variant_impl<N - 1, types>::load(ar, which - 1, v, version);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class Seq>
|
||||||
|
struct variant_impl<0, Seq>
|
||||||
|
{
|
||||||
|
template<class Archive, class V>
|
||||||
|
static void load (
|
||||||
|
Archive & /*ar*/,
|
||||||
|
std::size_t /*which*/,
|
||||||
|
V & /*v*/,
|
||||||
|
const unsigned int /*version*/
|
||||||
|
){}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class Archive, class... Types>
|
||||||
|
void load(
|
||||||
|
Archive & ar,
|
||||||
|
std::variant<Types...>& v,
|
||||||
|
const unsigned int version
|
||||||
|
){
|
||||||
|
std::size_t which;
|
||||||
|
ar >> BOOST_SERIALIZATION_NVP(which);
|
||||||
|
if(which >= sizeof...(Types))
|
||||||
|
// this might happen if a type was removed from the list of variant types
|
||||||
|
boost::serialization::throw_exception(
|
||||||
|
boost::archive::archive_exception(
|
||||||
|
boost::archive::archive_exception::unsupported_version
|
||||||
|
)
|
||||||
|
);
|
||||||
|
variant_impl<sizeof...(Types), mp::typelist<Types...>>::load(ar, which, v, version);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Archive,class... Types>
|
||||||
|
inline void serialize(
|
||||||
|
Archive & ar,
|
||||||
|
std::variant<Types...> & v,
|
||||||
|
const unsigned int file_version
|
||||||
|
){
|
||||||
|
split_free(ar,v,file_version);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Specialization for std::monostate
|
||||||
|
template<class Archive>
|
||||||
|
void serialize(Archive &ar, std::monostate &, const unsigned int /*version*/)
|
||||||
|
{}
|
||||||
|
|
||||||
|
} // namespace serialization
|
||||||
|
} // namespace boost
|
||||||
|
|
||||||
|
//template<typename T0_, BOOST_VARIANT_ENUM_SHIFTED_PARAMS(typename T)>
|
||||||
|
|
||||||
|
#include <boost/serialization/tracking.hpp>
|
||||||
|
|
||||||
|
namespace boost {
|
||||||
|
namespace serialization {
|
||||||
|
|
||||||
|
template<class... Types>
|
||||||
|
struct tracking_level<
|
||||||
|
std::variant<Types...>
|
||||||
|
>{
|
||||||
|
typedef mpl::integral_c_tag tag;
|
||||||
|
typedef mpl::int_< ::boost::serialization::track_always> type;
|
||||||
|
BOOST_STATIC_CONSTANT(int, value = type::value);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace serialization
|
||||||
|
} // namespace boost
|
||||||
|
|
||||||
|
#endif //BOOST_SERIALIZATION_VARIANT_HPP
|
@ -17,43 +17,14 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <type_traits>
|
|
||||||
|
|
||||||
#if defined(_MSC_VER)
|
#if defined(_MSC_VER)
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#endif
|
#endif
|
||||||
|
#include <bit>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
#include <type_traits>
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
|
|
||||||
// GCC
|
|
||||||
#ifdef __GNUC__
|
|
||||||
|
|
||||||
#if __BYTE_ORDER__ && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) && !defined(COMMON_LITTLE_ENDIAN)
|
|
||||||
#define COMMON_LITTLE_ENDIAN 1
|
|
||||||
#elif __BYTE_ORDER__ && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) && !defined(COMMON_BIG_ENDIAN)
|
|
||||||
#define COMMON_BIG_ENDIAN 1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// LLVM/clang
|
|
||||||
#elif defined(__clang__)
|
|
||||||
|
|
||||||
#if __LITTLE_ENDIAN__ && !defined(COMMON_LITTLE_ENDIAN)
|
|
||||||
#define COMMON_LITTLE_ENDIAN 1
|
|
||||||
#elif __BIG_ENDIAN__ && !defined(COMMON_BIG_ENDIAN)
|
|
||||||
#define COMMON_BIG_ENDIAN 1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// MSVC
|
|
||||||
#elif defined(_MSC_VER) && !defined(COMMON_BIG_ENDIAN) && !defined(COMMON_LITTLE_ENDIAN)
|
|
||||||
|
|
||||||
#define COMMON_LITTLE_ENDIAN 1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Worst case, default to little endian.
|
|
||||||
#if !COMMON_BIG_ENDIAN && !COMMON_LITTLE_ENDIAN
|
|
||||||
#define COMMON_LITTLE_ENDIAN 1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace Common {
|
namespace Common {
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
@ -675,17 +646,8 @@ struct AddEndian<T, SwapTag> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Alias LETag/BETag as KeepTag/SwapTag depending on the system
|
// Alias LETag/BETag as KeepTag/SwapTag depending on the system
|
||||||
#if COMMON_LITTLE_ENDIAN
|
using LETag = std::conditional_t<std::endian::native == std::endian::little, KeepTag, SwapTag>;
|
||||||
|
using BETag = std::conditional_t<std::endian::native == std::endian::big, KeepTag, SwapTag>;
|
||||||
using LETag = KeepTag;
|
|
||||||
using BETag = SwapTag;
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
using BETag = KeepTag;
|
|
||||||
using LETag = SwapTag;
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Aliases for LE types
|
// Aliases for LE types
|
||||||
using u16_le = AddEndian<u16, LETag>::type;
|
using u16_le = AddEndian<u16, LETag>::type;
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
#include <mach/mach.h>
|
#include <mach/mach.h>
|
||||||
#elif defined(_WIN32)
|
#elif defined(_WIN32)
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
#include "common/string_util.h"
|
||||||
#else
|
#else
|
||||||
#if defined(__Bitrig__) || defined(__DragonFly__) || defined(__FreeBSD__) || defined(__OpenBSD__)
|
#if defined(__Bitrig__) || defined(__DragonFly__) || defined(__FreeBSD__) || defined(__OpenBSD__)
|
||||||
#include <pthread_np.h>
|
#include <pthread_np.h>
|
||||||
@ -82,29 +83,8 @@ void SetCurrentThreadPriority(ThreadPriority new_priority) {
|
|||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
|
|
||||||
// Sets the debugger-visible name of the current thread.
|
// Sets the debugger-visible name of the current thread.
|
||||||
// Uses trick documented in:
|
|
||||||
// https://docs.microsoft.com/en-us/visualstudio/debugger/how-to-set-a-thread-name-in-native-code
|
|
||||||
void SetCurrentThreadName(const char* name) {
|
void SetCurrentThreadName(const char* name) {
|
||||||
static const DWORD MS_VC_EXCEPTION = 0x406D1388;
|
SetThreadDescription(GetCurrentThread(), UTF8ToUTF16W(name).data());
|
||||||
|
|
||||||
#pragma pack(push, 8)
|
|
||||||
struct THREADNAME_INFO {
|
|
||||||
DWORD dwType; // must be 0x1000
|
|
||||||
LPCSTR szName; // pointer to name (in user addr space)
|
|
||||||
DWORD dwThreadID; // thread ID (-1=caller thread)
|
|
||||||
DWORD dwFlags; // reserved for future use, must be zero
|
|
||||||
} info;
|
|
||||||
#pragma pack(pop)
|
|
||||||
|
|
||||||
info.dwType = 0x1000;
|
|
||||||
info.szName = name;
|
|
||||||
info.dwThreadID = std::numeric_limits<DWORD>::max();
|
|
||||||
info.dwFlags = 0;
|
|
||||||
|
|
||||||
__try {
|
|
||||||
RaiseException(MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(ULONG_PTR), (ULONG_PTR*)&info);
|
|
||||||
} __except (EXCEPTION_CONTINUE_EXECUTION) {
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#else // !MSVC_VER, so must be POSIX threads
|
#else // !MSVC_VER, so must be POSIX threads
|
||||||
|
@ -234,6 +234,8 @@ add_library(citra_core STATIC
|
|||||||
hle/service/boss/boss_p.h
|
hle/service/boss/boss_p.h
|
||||||
hle/service/boss/boss_u.cpp
|
hle/service/boss/boss_u.cpp
|
||||||
hle/service/boss/boss_u.h
|
hle/service/boss/boss_u.h
|
||||||
|
hle/service/boss/online_service.cpp
|
||||||
|
hle/service/boss/online_service.h
|
||||||
hle/service/cam/cam.cpp
|
hle/service/cam/cam.cpp
|
||||||
hle/service/cam/cam.h
|
hle/service/cam/cam.h
|
||||||
hle/service/cam/cam_c.cpp
|
hle/service/cam/cam_c.cpp
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include "common/archives.h"
|
#include "common/archives.h"
|
||||||
|
#include "common/error.h"
|
||||||
#include "common/file_util.h"
|
#include "common/file_util.h"
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
#include "common/settings.h"
|
#include "common/settings.h"
|
||||||
@ -103,7 +104,7 @@ ResultVal<std::unique_ptr<FileBackend>> SDMCArchive::OpenFileBase(const Path& pa
|
|||||||
|
|
||||||
FileUtil::IOFile file(full_path, mode.write_flag ? "r+b" : "rb");
|
FileUtil::IOFile file(full_path, mode.write_flag ? "r+b" : "rb");
|
||||||
if (!file.IsOpen()) {
|
if (!file.IsOpen()) {
|
||||||
LOG_CRITICAL(Service_FS, "Error opening {}: {}", full_path, GetLastErrorMsg());
|
LOG_CRITICAL(Service_FS, "Error opening {}: {}", full_path, Common::GetLastErrorMsg());
|
||||||
return ERROR_NOT_FOUND;
|
return ERROR_NOT_FOUND;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -245,6 +245,12 @@ private:
|
|||||||
};
|
};
|
||||||
static_assert(sizeof(CaptureBufferInfo) == 0x20, "CaptureBufferInfo struct has incorrect size");
|
static_assert(sizeof(CaptureBufferInfo) == 0x20, "CaptureBufferInfo struct has incorrect size");
|
||||||
|
|
||||||
|
enum class SleepQueryReply : u32 {
|
||||||
|
Reject = 0,
|
||||||
|
Accept = 1,
|
||||||
|
Later = 2,
|
||||||
|
};
|
||||||
|
|
||||||
class AppletManager : public std::enable_shared_from_this<AppletManager> {
|
class AppletManager : public std::enable_shared_from_this<AppletManager> {
|
||||||
public:
|
public:
|
||||||
explicit AppletManager(Core::System& system);
|
explicit AppletManager(Core::System& system);
|
||||||
|
@ -935,6 +935,28 @@ void Module::APTInterface::SendDspWakeUp(Kernel::HLERequestContext& ctx) {
|
|||||||
rb.Push(apt->applet_manager->SendDspWakeUp(from_app_id, object));
|
rb.Push(apt->applet_manager->SendDspWakeUp(from_app_id, object));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Module::APTInterface::ReplySleepQuery(Kernel::HLERequestContext& ctx) {
|
||||||
|
IPC::RequestParser rp(ctx);
|
||||||
|
const auto from_app_id = rp.PopEnum<AppletId>();
|
||||||
|
const auto reply_value = rp.PopEnum<SleepQueryReply>();
|
||||||
|
|
||||||
|
LOG_WARNING(Service_APT, "(STUBBED) called, from_app_id={:08X}, reply_value={:08X}",
|
||||||
|
from_app_id, reply_value);
|
||||||
|
|
||||||
|
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
||||||
|
rb.Push(RESULT_SUCCESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Module::APTInterface::ReplySleepNotificationComplete(Kernel::HLERequestContext& ctx) {
|
||||||
|
IPC::RequestParser rp(ctx);
|
||||||
|
const auto from_app_id = rp.PopEnum<AppletId>();
|
||||||
|
|
||||||
|
LOG_WARNING(Service_APT, "(STUBBED) called, from_app_id={:08X}", from_app_id);
|
||||||
|
|
||||||
|
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
||||||
|
rb.Push(RESULT_SUCCESS);
|
||||||
|
}
|
||||||
|
|
||||||
void Module::APTInterface::PrepareToJumpToHomeMenu(Kernel::HLERequestContext& ctx) {
|
void Module::APTInterface::PrepareToJumpToHomeMenu(Kernel::HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp(ctx);
|
IPC::RequestParser rp(ctx);
|
||||||
|
|
||||||
|
@ -755,6 +755,27 @@ public:
|
|||||||
*/
|
*/
|
||||||
void SendDspWakeUp(Kernel::HLERequestContext& ctx);
|
void SendDspWakeUp(Kernel::HLERequestContext& ctx);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* APT::ReplySleepQuery service function
|
||||||
|
* Inputs:
|
||||||
|
* 1 : Source App ID
|
||||||
|
* 2 : Reply Value
|
||||||
|
* Outputs:
|
||||||
|
* 0 : Header code
|
||||||
|
* 1 : Result code
|
||||||
|
*/
|
||||||
|
void ReplySleepQuery(Kernel::HLERequestContext& ctx);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* APT::ReplySleepNotificationComplete service function
|
||||||
|
* Inputs:
|
||||||
|
* 1 : Source App ID
|
||||||
|
* Outputs:
|
||||||
|
* 0 : Header code
|
||||||
|
* 1 : Result code
|
||||||
|
*/
|
||||||
|
void ReplySleepNotificationComplete(Kernel::HLERequestContext& ctx);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* APT::PrepareToJumpToHomeMenu service function
|
* APT::PrepareToJumpToHomeMenu service function
|
||||||
* Inputs:
|
* Inputs:
|
||||||
|
@ -72,8 +72,8 @@ APT_A::APT_A(std::shared_ptr<Module> apt)
|
|||||||
{0x003B, &APT_A::CancelLibraryApplet, "CancelLibraryApplet"},
|
{0x003B, &APT_A::CancelLibraryApplet, "CancelLibraryApplet"},
|
||||||
{0x003C, &APT_A::SendDspSleep, "SendDspSleep"},
|
{0x003C, &APT_A::SendDspSleep, "SendDspSleep"},
|
||||||
{0x003D, &APT_A::SendDspWakeUp, "SendDspWakeUp"},
|
{0x003D, &APT_A::SendDspWakeUp, "SendDspWakeUp"},
|
||||||
{0x003E, nullptr, "ReplySleepQuery"},
|
{0x003E, &APT_A::ReplySleepQuery, "ReplySleepQuery"},
|
||||||
{0x003F, nullptr, "ReplySleepNotificationComplete"},
|
{0x003F, &APT_A::ReplySleepNotificationComplete, "ReplySleepNotificationComplete"},
|
||||||
{0x0040, &APT_A::SendCaptureBufferInfo, "SendCaptureBufferInfo"},
|
{0x0040, &APT_A::SendCaptureBufferInfo, "SendCaptureBufferInfo"},
|
||||||
{0x0041, &APT_A::ReceiveCaptureBufferInfo, "ReceiveCaptureBufferInfo"},
|
{0x0041, &APT_A::ReceiveCaptureBufferInfo, "ReceiveCaptureBufferInfo"},
|
||||||
{0x0042, nullptr, "SleepSystem"},
|
{0x0042, nullptr, "SleepSystem"},
|
||||||
|
@ -72,8 +72,8 @@ APT_S::APT_S(std::shared_ptr<Module> apt)
|
|||||||
{0x003B, &APT_S::CancelLibraryApplet, "CancelLibraryApplet"},
|
{0x003B, &APT_S::CancelLibraryApplet, "CancelLibraryApplet"},
|
||||||
{0x003C, &APT_S::SendDspSleep, "SendDspSleep"},
|
{0x003C, &APT_S::SendDspSleep, "SendDspSleep"},
|
||||||
{0x003D, &APT_S::SendDspWakeUp, "SendDspWakeUp"},
|
{0x003D, &APT_S::SendDspWakeUp, "SendDspWakeUp"},
|
||||||
{0x003E, nullptr, "ReplySleepQuery"},
|
{0x003E, &APT_S::ReplySleepQuery, "ReplySleepQuery"},
|
||||||
{0x003F, nullptr, "ReplySleepNotificationComplete"},
|
{0x003F, &APT_S::ReplySleepNotificationComplete, "ReplySleepNotificationComplete"},
|
||||||
{0x0040, &APT_S::SendCaptureBufferInfo, "SendCaptureBufferInfo"},
|
{0x0040, &APT_S::SendCaptureBufferInfo, "SendCaptureBufferInfo"},
|
||||||
{0x0041, &APT_S::ReceiveCaptureBufferInfo, "ReceiveCaptureBufferInfo"},
|
{0x0041, &APT_S::ReceiveCaptureBufferInfo, "ReceiveCaptureBufferInfo"},
|
||||||
{0x0042, nullptr, "SleepSystem"},
|
{0x0042, nullptr, "SleepSystem"},
|
||||||
|
@ -72,8 +72,8 @@ APT_U::APT_U(std::shared_ptr<Module> apt)
|
|||||||
{0x003B, &APT_U::CancelLibraryApplet, "CancelLibraryApplet"},
|
{0x003B, &APT_U::CancelLibraryApplet, "CancelLibraryApplet"},
|
||||||
{0x003C, &APT_U::SendDspSleep, "SendDspSleep"},
|
{0x003C, &APT_U::SendDspSleep, "SendDspSleep"},
|
||||||
{0x003D, &APT_U::SendDspWakeUp, "SendDspWakeUp"},
|
{0x003D, &APT_U::SendDspWakeUp, "SendDspWakeUp"},
|
||||||
{0x003E, nullptr, "ReplySleepQuery"},
|
{0x003E, &APT_U::ReplySleepQuery, "ReplySleepQuery"},
|
||||||
{0x003F, nullptr, "ReplySleepNotificationComplete"},
|
{0x003F, &APT_U::ReplySleepNotificationComplete, "ReplySleepNotificationComplete"},
|
||||||
{0x0040, &APT_U::SendCaptureBufferInfo, "SendCaptureBufferInfo"},
|
{0x0040, &APT_U::SendCaptureBufferInfo, "SendCaptureBufferInfo"},
|
||||||
{0x0041, &APT_U::ReceiveCaptureBufferInfo, "ReceiveCaptureBufferInfo"},
|
{0x0041, &APT_U::ReceiveCaptureBufferInfo, "ReceiveCaptureBufferInfo"},
|
||||||
{0x0042, nullptr, "SleepSystem"},
|
{0x0042, nullptr, "SleepSystem"},
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
// Licensed under GPLv2 or any later version
|
// Licensed under GPLv2 or any later version
|
||||||
// Refer to the license.txt file included.
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include "common/archives.h"
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
#include "core/core.h"
|
#include "core/core.h"
|
||||||
#include "core/hle/ipc_helpers.h"
|
#include "core/hle/ipc_helpers.h"
|
||||||
@ -10,17 +11,66 @@
|
|||||||
#include "core/hle/service/boss/boss_p.h"
|
#include "core/hle/service/boss/boss_p.h"
|
||||||
#include "core/hle/service/boss/boss_u.h"
|
#include "core/hle/service/boss/boss_u.h"
|
||||||
|
|
||||||
|
SERVICE_CONSTRUCT_IMPL(Service::BOSS::Module)
|
||||||
|
SERIALIZE_EXPORT_IMPL(Service::BOSS::Module)
|
||||||
|
SERIALIZE_EXPORT_IMPL(Service::BOSS::Module::SessionData)
|
||||||
|
|
||||||
namespace Service::BOSS {
|
namespace Service::BOSS {
|
||||||
|
|
||||||
|
template <class Archive>
|
||||||
|
void Module::serialize(Archive& ar, const unsigned int) {
|
||||||
|
ar& task_finish_event;
|
||||||
|
ar& new_arrival_flag;
|
||||||
|
ar& ns_data_new_flag;
|
||||||
|
ar& ns_data_new_flag_privileged;
|
||||||
|
ar& output_flag;
|
||||||
|
}
|
||||||
|
SERIALIZE_IMPL(Module)
|
||||||
|
|
||||||
|
template <class Archive>
|
||||||
|
void Module::SessionData::serialize(Archive& ar, const unsigned int) {
|
||||||
|
ar& boost::serialization::base_object<Kernel::SessionRequestHandler::SessionDataBase>(*this);
|
||||||
|
ar& online_service;
|
||||||
|
}
|
||||||
|
SERIALIZE_IMPL(Module::SessionData)
|
||||||
|
|
||||||
|
std::shared_ptr<OnlineService> Module::Interface::GetSessionService(
|
||||||
|
Kernel::HLERequestContext& ctx) {
|
||||||
|
const auto session_data = GetSessionData(ctx.Session());
|
||||||
|
if (session_data == nullptr || session_data->online_service == nullptr) {
|
||||||
|
LOG_WARNING(Service_BOSS, "Client attempted to use uninitialized BOSS session.");
|
||||||
|
|
||||||
|
// TODO: Error code for uninitialized session.
|
||||||
|
IPC::RequestParser rp(ctx);
|
||||||
|
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
||||||
|
rb.Push(RESULT_UNKNOWN);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return session_data->online_service;
|
||||||
|
}
|
||||||
|
|
||||||
void Module::Interface::InitializeSession(Kernel::HLERequestContext& ctx) {
|
void Module::Interface::InitializeSession(Kernel::HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp(ctx);
|
IPC::RequestParser rp(ctx);
|
||||||
const u64 programID = rp.Pop<u64>();
|
const u64 program_id = rp.Pop<u64>();
|
||||||
rp.PopPID();
|
rp.PopPID();
|
||||||
|
|
||||||
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
const auto session_data = GetSessionData(ctx.Session());
|
||||||
rb.Push(RESULT_SUCCESS);
|
if (session_data->online_service == nullptr) {
|
||||||
|
u64 curr_program_id;
|
||||||
|
u64 curr_extdata_id;
|
||||||
|
boss->system.GetAppLoader().ReadProgramId(curr_program_id);
|
||||||
|
boss->system.GetAppLoader().ReadExtdataId(curr_extdata_id);
|
||||||
|
|
||||||
LOG_WARNING(Service_BOSS, "(STUBBED) programID={:#018X}", programID);
|
session_data->online_service =
|
||||||
|
std::make_shared<OnlineService>(curr_program_id, curr_extdata_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto result = session_data->online_service->InitializeSession(program_id);
|
||||||
|
|
||||||
|
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
||||||
|
rb.Push(result);
|
||||||
|
|
||||||
|
LOG_DEBUG(Service_BOSS, "called, program_id={:#018x}", program_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Module::Interface::SetStorageInfo(Kernel::HLERequestContext& ctx) {
|
void Module::Interface::SetStorageInfo(Kernel::HLERequestContext& ctx) {
|
||||||
@ -33,7 +83,7 @@ void Module::Interface::SetStorageInfo(Kernel::HLERequestContext& ctx) {
|
|||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
|
|
||||||
LOG_WARNING(Service_BOSS,
|
LOG_WARNING(Service_BOSS,
|
||||||
"(STUBBED) extdata_id={:#018X}, boss_size={:#010X}, extdata_type={:#04X}",
|
"(STUBBED) extdata_id={:#018x}, boss_size={:#010x}, extdata_type={:#04x}",
|
||||||
extdata_id, boss_size, extdata_type);
|
extdata_id, boss_size, extdata_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -80,7 +130,7 @@ void Module::Interface::RegisterPrivateClientCert(Kernel::HLERequestContext& ctx
|
|||||||
rb.PushMappedBuffer(buffer1);
|
rb.PushMappedBuffer(buffer1);
|
||||||
rb.PushMappedBuffer(buffer2);
|
rb.PushMappedBuffer(buffer2);
|
||||||
|
|
||||||
LOG_WARNING(Service_BOSS, "(STUBBED) buffer1_size={:#010X}, buffer2_size={:#010X}, ",
|
LOG_WARNING(Service_BOSS, "(STUBBED) buffer1_size={:#010x}, buffer2_size={:#010x}, ",
|
||||||
buffer1_size, buffer2_size);
|
buffer1_size, buffer2_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -89,9 +139,9 @@ void Module::Interface::GetNewArrivalFlag(Kernel::HLERequestContext& ctx) {
|
|||||||
|
|
||||||
IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
|
IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
rb.Push<u8>(new_arrival_flag);
|
rb.Push<u8>(boss->new_arrival_flag);
|
||||||
|
|
||||||
LOG_WARNING(Service_BOSS, "(STUBBED) new_arrival_flag={}", new_arrival_flag);
|
LOG_WARNING(Service_BOSS, "(STUBBED) new_arrival_flag={}", boss->new_arrival_flag);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Module::Interface::RegisterNewArrivalEvent(Kernel::HLERequestContext& ctx) {
|
void Module::Interface::RegisterNewArrivalEvent(Kernel::HLERequestContext& ctx) {
|
||||||
@ -106,12 +156,12 @@ void Module::Interface::RegisterNewArrivalEvent(Kernel::HLERequestContext& ctx)
|
|||||||
|
|
||||||
void Module::Interface::SetOptoutFlag(Kernel::HLERequestContext& ctx) {
|
void Module::Interface::SetOptoutFlag(Kernel::HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp(ctx);
|
IPC::RequestParser rp(ctx);
|
||||||
output_flag = rp.Pop<u8>();
|
boss->output_flag = rp.Pop<u8>();
|
||||||
|
|
||||||
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
|
|
||||||
LOG_WARNING(Service_BOSS, "output_flag={}", output_flag);
|
LOG_WARNING(Service_BOSS, "output_flag={}", boss->output_flag);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Module::Interface::GetOptoutFlag(Kernel::HLERequestContext& ctx) {
|
void Module::Interface::GetOptoutFlag(Kernel::HLERequestContext& ctx) {
|
||||||
@ -119,9 +169,9 @@ void Module::Interface::GetOptoutFlag(Kernel::HLERequestContext& ctx) {
|
|||||||
|
|
||||||
IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
|
IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
rb.Push<u8>(output_flag);
|
rb.Push<u8>(boss->output_flag);
|
||||||
|
|
||||||
LOG_WARNING(Service_BOSS, "output_flag={}", output_flag);
|
LOG_WARNING(Service_BOSS, "output_flag={}", boss->output_flag);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Module::Interface::RegisterTask(Kernel::HLERequestContext& ctx) {
|
void Module::Interface::RegisterTask(Kernel::HLERequestContext& ctx) {
|
||||||
@ -131,12 +181,18 @@ void Module::Interface::RegisterTask(Kernel::HLERequestContext& ctx) {
|
|||||||
const u8 unk_param3 = rp.Pop<u8>();
|
const u8 unk_param3 = rp.Pop<u8>();
|
||||||
auto& buffer = rp.PopMappedBuffer();
|
auto& buffer = rp.PopMappedBuffer();
|
||||||
|
|
||||||
|
const auto online_service = GetSessionService(ctx);
|
||||||
|
if (online_service == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
online_service->RegisterTask(size, buffer);
|
||||||
|
|
||||||
IPC::RequestBuilder rb = rp.MakeBuilder(1, 2);
|
IPC::RequestBuilder rb = rp.MakeBuilder(1, 2);
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
rb.PushMappedBuffer(buffer);
|
rb.PushMappedBuffer(buffer);
|
||||||
|
|
||||||
LOG_WARNING(Service_BOSS, "(STUBBED) size={:#010X}, unk_param2={:#04X}, unk_param3={:#04X}",
|
LOG_DEBUG(Service_BOSS, "called, size={:#010x}, unk_param2={:#04x}, unk_param3={:#04x}", size,
|
||||||
size, unk_param2, unk_param3);
|
unk_param2, unk_param3);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Module::Interface::UnregisterTask(Kernel::HLERequestContext& ctx) {
|
void Module::Interface::UnregisterTask(Kernel::HLERequestContext& ctx) {
|
||||||
@ -145,11 +201,17 @@ void Module::Interface::UnregisterTask(Kernel::HLERequestContext& ctx) {
|
|||||||
const u8 unk_param2 = rp.Pop<u8>();
|
const u8 unk_param2 = rp.Pop<u8>();
|
||||||
auto& buffer = rp.PopMappedBuffer();
|
auto& buffer = rp.PopMappedBuffer();
|
||||||
|
|
||||||
|
const auto online_service = GetSessionService(ctx);
|
||||||
|
if (online_service == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const auto result = online_service->UnregisterTask(size, buffer);
|
||||||
|
|
||||||
IPC::RequestBuilder rb = rp.MakeBuilder(1, 2);
|
IPC::RequestBuilder rb = rp.MakeBuilder(1, 2);
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(result);
|
||||||
rb.PushMappedBuffer(buffer);
|
rb.PushMappedBuffer(buffer);
|
||||||
|
|
||||||
LOG_WARNING(Service_BOSS, "(STUBBED) size={:#010X}, unk_param2={:#04X}", size, unk_param2);
|
LOG_DEBUG(Service_BOSS, "called, size={:#010x}, unk_param2={:#04x}", size, unk_param2);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Module::Interface::ReconfigureTask(Kernel::HLERequestContext& ctx) {
|
void Module::Interface::ReconfigureTask(Kernel::HLERequestContext& ctx) {
|
||||||
@ -162,16 +224,22 @@ void Module::Interface::ReconfigureTask(Kernel::HLERequestContext& ctx) {
|
|||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
rb.PushMappedBuffer(buffer);
|
rb.PushMappedBuffer(buffer);
|
||||||
|
|
||||||
LOG_WARNING(Service_BOSS, "(STUBBED) size={:#010X}, unk_param2={:#04X}", size, unk_param2);
|
LOG_WARNING(Service_BOSS, "(STUBBED) size={:#010x}, unk_param2={:#04x}", size, unk_param2);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Module::Interface::GetTaskIdList(Kernel::HLERequestContext& ctx) {
|
void Module::Interface::GetTaskIdList(Kernel::HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp(ctx);
|
IPC::RequestParser rp(ctx);
|
||||||
|
|
||||||
|
const auto online_service = GetSessionService(ctx);
|
||||||
|
if (online_service == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
online_service->GetTaskIdList();
|
||||||
|
|
||||||
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
|
|
||||||
LOG_WARNING(Service_BOSS, "(STUBBED) called");
|
LOG_DEBUG(Service_BOSS, "called");
|
||||||
}
|
}
|
||||||
|
|
||||||
void Module::Interface::GetStepIdList(Kernel::HLERequestContext& ctx) {
|
void Module::Interface::GetStepIdList(Kernel::HLERequestContext& ctx) {
|
||||||
@ -183,7 +251,7 @@ void Module::Interface::GetStepIdList(Kernel::HLERequestContext& ctx) {
|
|||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
rb.PushMappedBuffer(buffer);
|
rb.PushMappedBuffer(buffer);
|
||||||
|
|
||||||
LOG_WARNING(Service_BOSS, "(STUBBED) size={:#010X}", size);
|
LOG_WARNING(Service_BOSS, "(STUBBED) size={:#010x}", size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Module::Interface::GetNsDataIdList(Kernel::HLERequestContext& ctx) {
|
void Module::Interface::GetNsDataIdList(Kernel::HLERequestContext& ctx) {
|
||||||
@ -194,15 +262,21 @@ void Module::Interface::GetNsDataIdList(Kernel::HLERequestContext& ctx) {
|
|||||||
const u32 start_ns_data_id = rp.Pop<u32>();
|
const u32 start_ns_data_id = rp.Pop<u32>();
|
||||||
auto& buffer = rp.PopMappedBuffer();
|
auto& buffer = rp.PopMappedBuffer();
|
||||||
|
|
||||||
|
const auto online_service = GetSessionService(ctx);
|
||||||
|
if (online_service == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const u16 entries_count = online_service->GetNsDataIdList(filter, max_entries, buffer);
|
||||||
|
|
||||||
IPC::RequestBuilder rb = rp.MakeBuilder(3, 2);
|
IPC::RequestBuilder rb = rp.MakeBuilder(3, 2);
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
rb.Push<u16>(0); /// Actual number of output entries
|
rb.Push<u16>(entries_count); /// Actual number of output entries
|
||||||
rb.Push<u16>(0); /// Last word-index copied to output in the internal NsDataId list.
|
rb.Push<u16>(0); /// Last word-index copied to output in the internal NsDataId list.
|
||||||
rb.PushMappedBuffer(buffer);
|
rb.PushMappedBuffer(buffer);
|
||||||
|
|
||||||
LOG_WARNING(Service_BOSS,
|
LOG_DEBUG(Service_BOSS,
|
||||||
"(STUBBED) filter={:#010X}, max_entries={:#010X}, "
|
"filter={:#010x}, max_entries={:#010x}, "
|
||||||
"word_index_start={:#06X}, start_ns_data_id={:#010X}",
|
"word_index_start={:#06x}, start_ns_data_id={:#010x}",
|
||||||
filter, max_entries, word_index_start, start_ns_data_id);
|
filter, max_entries, word_index_start, start_ns_data_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -214,15 +288,21 @@ void Module::Interface::GetNsDataIdList1(Kernel::HLERequestContext& ctx) {
|
|||||||
const u32 start_ns_data_id = rp.Pop<u32>();
|
const u32 start_ns_data_id = rp.Pop<u32>();
|
||||||
auto& buffer = rp.PopMappedBuffer();
|
auto& buffer = rp.PopMappedBuffer();
|
||||||
|
|
||||||
|
const auto online_service = GetSessionService(ctx);
|
||||||
|
if (online_service == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const u16 entries_count = online_service->GetNsDataIdList(filter, max_entries, buffer);
|
||||||
|
|
||||||
IPC::RequestBuilder rb = rp.MakeBuilder(3, 2);
|
IPC::RequestBuilder rb = rp.MakeBuilder(3, 2);
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
rb.Push<u16>(0); /// Actual number of output entries
|
rb.Push<u16>(entries_count); /// Actual number of output entries
|
||||||
rb.Push<u16>(0); /// Last word-index copied to output in the internal NsDataId list.
|
rb.Push<u16>(0); /// Last word-index copied to output in the internal NsDataId list.
|
||||||
rb.PushMappedBuffer(buffer);
|
rb.PushMappedBuffer(buffer);
|
||||||
|
|
||||||
LOG_WARNING(Service_BOSS,
|
LOG_DEBUG(Service_BOSS,
|
||||||
"(STUBBED) filter={:#010X}, max_entries={:#010X}, "
|
"filter={:#010x}, max_entries={:#010x}, "
|
||||||
"word_index_start={:#06X}, start_ns_data_id={:#010X}",
|
"word_index_start={:#06x}, start_ns_data_id={:#010x}",
|
||||||
filter, max_entries, word_index_start, start_ns_data_id);
|
filter, max_entries, word_index_start, start_ns_data_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -234,15 +314,21 @@ void Module::Interface::GetNsDataIdList2(Kernel::HLERequestContext& ctx) {
|
|||||||
const u32 start_ns_data_id = rp.Pop<u32>();
|
const u32 start_ns_data_id = rp.Pop<u32>();
|
||||||
auto& buffer = rp.PopMappedBuffer();
|
auto& buffer = rp.PopMappedBuffer();
|
||||||
|
|
||||||
|
const auto online_service = GetSessionService(ctx);
|
||||||
|
if (online_service == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const u16 entries_count = online_service->GetNsDataIdList(filter, max_entries, buffer);
|
||||||
|
|
||||||
IPC::RequestBuilder rb = rp.MakeBuilder(3, 2);
|
IPC::RequestBuilder rb = rp.MakeBuilder(3, 2);
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
rb.Push<u16>(0); /// Actual number of output entries
|
rb.Push<u16>(entries_count); /// Actual number of output entries
|
||||||
rb.Push<u16>(0); /// Last word-index copied to output in the internal NsDataId list.
|
rb.Push<u16>(0); /// Last word-index copied to output in the internal NsDataId list.
|
||||||
rb.PushMappedBuffer(buffer);
|
rb.PushMappedBuffer(buffer);
|
||||||
|
|
||||||
LOG_WARNING(Service_BOSS,
|
LOG_DEBUG(Service_BOSS,
|
||||||
"(STUBBED) filter={:#010X}, max_entries={:#010X}, "
|
"filter={:#010x}, max_entries={:#010x}, "
|
||||||
"word_index_start={:#06X}, start_ns_data_id={:#010X}",
|
"word_index_start={:#06x}, start_ns_data_id={:#010x}",
|
||||||
filter, max_entries, word_index_start, start_ns_data_id);
|
filter, max_entries, word_index_start, start_ns_data_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -254,15 +340,21 @@ void Module::Interface::GetNsDataIdList3(Kernel::HLERequestContext& ctx) {
|
|||||||
const u32 start_ns_data_id = rp.Pop<u32>();
|
const u32 start_ns_data_id = rp.Pop<u32>();
|
||||||
auto& buffer = rp.PopMappedBuffer();
|
auto& buffer = rp.PopMappedBuffer();
|
||||||
|
|
||||||
|
const auto online_service = GetSessionService(ctx);
|
||||||
|
if (online_service == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const u16 entries_count = online_service->GetNsDataIdList(filter, max_entries, buffer);
|
||||||
|
|
||||||
IPC::RequestBuilder rb = rp.MakeBuilder(3, 2);
|
IPC::RequestBuilder rb = rp.MakeBuilder(3, 2);
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
rb.Push<u16>(0); /// Actual number of output entries
|
rb.Push<u16>(entries_count); /// Actual number of output entries
|
||||||
rb.Push<u16>(0); /// Last word-index copied to output in the internal NsDataId list.
|
rb.Push<u16>(0); /// Last word-index copied to output in the internal NsDataId list.
|
||||||
rb.PushMappedBuffer(buffer);
|
rb.PushMappedBuffer(buffer);
|
||||||
|
|
||||||
LOG_WARNING(Service_BOSS,
|
LOG_DEBUG(Service_BOSS,
|
||||||
"(STUBBED) filter={:#010X}, max_entries={:#010X}, "
|
"filter={:#010x}, max_entries={:#010x}, "
|
||||||
"word_index_start={:#06X}, start_ns_data_id={:#010X}",
|
"word_index_start={:#06x}, start_ns_data_id={:#010x}",
|
||||||
filter, max_entries, word_index_start, start_ns_data_id);
|
filter, max_entries, word_index_start, start_ns_data_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -272,11 +364,17 @@ void Module::Interface::SendProperty(Kernel::HLERequestContext& ctx) {
|
|||||||
const u32 size = rp.Pop<u32>();
|
const u32 size = rp.Pop<u32>();
|
||||||
auto& buffer = rp.PopMappedBuffer();
|
auto& buffer = rp.PopMappedBuffer();
|
||||||
|
|
||||||
|
const auto online_service = GetSessionService(ctx);
|
||||||
|
if (online_service == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const auto result = online_service->SendProperty(property_id, size, buffer);
|
||||||
|
|
||||||
IPC::RequestBuilder rb = rp.MakeBuilder(1, 2);
|
IPC::RequestBuilder rb = rp.MakeBuilder(1, 2);
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(result);
|
||||||
rb.PushMappedBuffer(buffer);
|
rb.PushMappedBuffer(buffer);
|
||||||
|
|
||||||
LOG_WARNING(Service_BOSS, "(STUBBED) property_id={:#06X}, size={:#010X}", property_id, size);
|
LOG_DEBUG(Service_BOSS, "property_id={:#06x}, size={:#010x}", property_id, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Module::Interface::SendPropertyHandle(Kernel::HLERequestContext& ctx) {
|
void Module::Interface::SendPropertyHandle(Kernel::HLERequestContext& ctx) {
|
||||||
@ -287,7 +385,7 @@ void Module::Interface::SendPropertyHandle(Kernel::HLERequestContext& ctx) {
|
|||||||
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
|
|
||||||
LOG_WARNING(Service_BOSS, "(STUBBED) property_id={:#06X}", property_id);
|
LOG_WARNING(Service_BOSS, "(STUBBED) property_id={:#06x}", property_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Module::Interface::ReceiveProperty(Kernel::HLERequestContext& ctx) {
|
void Module::Interface::ReceiveProperty(Kernel::HLERequestContext& ctx) {
|
||||||
@ -296,12 +394,18 @@ void Module::Interface::ReceiveProperty(Kernel::HLERequestContext& ctx) {
|
|||||||
const u32 size = rp.Pop<u32>();
|
const u32 size = rp.Pop<u32>();
|
||||||
auto& buffer = rp.PopMappedBuffer();
|
auto& buffer = rp.PopMappedBuffer();
|
||||||
|
|
||||||
|
const auto online_service = GetSessionService(ctx);
|
||||||
|
if (online_service == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const auto result = online_service->ReceiveProperty(property_id, size, buffer);
|
||||||
|
|
||||||
IPC::RequestBuilder rb = rp.MakeBuilder(2, 2);
|
IPC::RequestBuilder rb = rp.MakeBuilder(2, 2);
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(result);
|
||||||
rb.Push<u32>(size); /// Should be actual read size
|
rb.Push<u32>(size);
|
||||||
rb.PushMappedBuffer(buffer);
|
rb.PushMappedBuffer(buffer);
|
||||||
|
|
||||||
LOG_WARNING(Service_BOSS, "(STUBBED) property_id={:#06X}, size={:#010X}", property_id, size);
|
LOG_DEBUG(Service_BOSS, "property_id={:#06x}, size={:#010x}", property_id, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Module::Interface::UpdateTaskInterval(Kernel::HLERequestContext& ctx) {
|
void Module::Interface::UpdateTaskInterval(Kernel::HLERequestContext& ctx) {
|
||||||
@ -314,7 +418,7 @@ void Module::Interface::UpdateTaskInterval(Kernel::HLERequestContext& ctx) {
|
|||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
rb.PushMappedBuffer(buffer);
|
rb.PushMappedBuffer(buffer);
|
||||||
|
|
||||||
LOG_WARNING(Service_BOSS, "(STUBBED) size={:#010X}, unk_param2={:#06X}", size, unk_param2);
|
LOG_WARNING(Service_BOSS, "(STUBBED) size={:#010x}, unk_param2={:#06x}", size, unk_param2);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Module::Interface::UpdateTaskCount(Kernel::HLERequestContext& ctx) {
|
void Module::Interface::UpdateTaskCount(Kernel::HLERequestContext& ctx) {
|
||||||
@ -323,11 +427,15 @@ void Module::Interface::UpdateTaskCount(Kernel::HLERequestContext& ctx) {
|
|||||||
const u32 unk_param2 = rp.Pop<u32>();
|
const u32 unk_param2 = rp.Pop<u32>();
|
||||||
auto& buffer = rp.PopMappedBuffer();
|
auto& buffer = rp.PopMappedBuffer();
|
||||||
|
|
||||||
|
std::string task_id(size, 0);
|
||||||
|
buffer.Read(task_id.data(), 0, size);
|
||||||
|
|
||||||
IPC::RequestBuilder rb = rp.MakeBuilder(1, 2);
|
IPC::RequestBuilder rb = rp.MakeBuilder(1, 2);
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
rb.PushMappedBuffer(buffer);
|
rb.PushMappedBuffer(buffer);
|
||||||
|
|
||||||
LOG_WARNING(Service_BOSS, "(STUBBED) size={:#010X}, unk_param2={:#010X}", size, unk_param2);
|
LOG_WARNING(Service_BOSS, "(STUBBED) size={:#010x}, unk_param2={:#010x}, task_id={}", size,
|
||||||
|
unk_param2, task_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Module::Interface::GetTaskInterval(Kernel::HLERequestContext& ctx) {
|
void Module::Interface::GetTaskInterval(Kernel::HLERequestContext& ctx) {
|
||||||
@ -340,7 +448,7 @@ void Module::Interface::GetTaskInterval(Kernel::HLERequestContext& ctx) {
|
|||||||
rb.Push<u32>(0); // stub 0 ( 32bit value)
|
rb.Push<u32>(0); // stub 0 ( 32bit value)
|
||||||
rb.PushMappedBuffer(buffer);
|
rb.PushMappedBuffer(buffer);
|
||||||
|
|
||||||
LOG_WARNING(Service_BOSS, "(STUBBED) size={:#010X}", size);
|
LOG_WARNING(Service_BOSS, "(STUBBED) size={:#010x}", size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Module::Interface::GetTaskCount(Kernel::HLERequestContext& ctx) {
|
void Module::Interface::GetTaskCount(Kernel::HLERequestContext& ctx) {
|
||||||
@ -348,12 +456,15 @@ void Module::Interface::GetTaskCount(Kernel::HLERequestContext& ctx) {
|
|||||||
const u32 size = rp.Pop<u32>();
|
const u32 size = rp.Pop<u32>();
|
||||||
auto& buffer = rp.PopMappedBuffer();
|
auto& buffer = rp.PopMappedBuffer();
|
||||||
|
|
||||||
|
std::string task_id(size, 0);
|
||||||
|
buffer.Read(task_id.data(), 0, size);
|
||||||
|
|
||||||
IPC::RequestBuilder rb = rp.MakeBuilder(2, 2);
|
IPC::RequestBuilder rb = rp.MakeBuilder(2, 2);
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
rb.Push<u32>(0); // stub 0 ( 32bit value)
|
rb.Push<u32>(0); // stub 0 ( 32bit value)
|
||||||
rb.PushMappedBuffer(buffer);
|
rb.PushMappedBuffer(buffer);
|
||||||
|
|
||||||
LOG_WARNING(Service_BOSS, "(STUBBED) size={:#010X}", size);
|
LOG_WARNING(Service_BOSS, "(STUBBED) size={:#010x}, task_id={}", size, task_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Module::Interface::GetTaskServiceStatus(Kernel::HLERequestContext& ctx) {
|
void Module::Interface::GetTaskServiceStatus(Kernel::HLERequestContext& ctx) {
|
||||||
@ -361,12 +472,16 @@ void Module::Interface::GetTaskServiceStatus(Kernel::HLERequestContext& ctx) {
|
|||||||
const u32 size = rp.Pop<u32>();
|
const u32 size = rp.Pop<u32>();
|
||||||
auto& buffer = rp.PopMappedBuffer();
|
auto& buffer = rp.PopMappedBuffer();
|
||||||
|
|
||||||
|
// Not sure what this is but it's not the task status. Maybe it's the status of the service
|
||||||
|
// after running the task?
|
||||||
|
constexpr u8 task_service_status = 1;
|
||||||
|
|
||||||
IPC::RequestBuilder rb = rp.MakeBuilder(2, 2);
|
IPC::RequestBuilder rb = rp.MakeBuilder(2, 2);
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
rb.Push<u8>(0); // stub 0 ( 8bit value)
|
rb.Push<u8>(task_service_status);
|
||||||
rb.PushMappedBuffer(buffer);
|
rb.PushMappedBuffer(buffer);
|
||||||
|
|
||||||
LOG_WARNING(Service_BOSS, "(STUBBED) size={:#010X}", size);
|
LOG_WARNING(Service_BOSS, "(STUBBED) size={:#010x}", size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Module::Interface::StartTask(Kernel::HLERequestContext& ctx) {
|
void Module::Interface::StartTask(Kernel::HLERequestContext& ctx) {
|
||||||
@ -378,7 +493,7 @@ void Module::Interface::StartTask(Kernel::HLERequestContext& ctx) {
|
|||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
rb.PushMappedBuffer(buffer);
|
rb.PushMappedBuffer(buffer);
|
||||||
|
|
||||||
LOG_WARNING(Service_BOSS, "(STUBBED) size={:#010X}", size);
|
LOG_WARNING(Service_BOSS, "(STUBBED) size={:#010x}", size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Module::Interface::StartTaskImmediate(Kernel::HLERequestContext& ctx) {
|
void Module::Interface::StartTaskImmediate(Kernel::HLERequestContext& ctx) {
|
||||||
@ -390,7 +505,7 @@ void Module::Interface::StartTaskImmediate(Kernel::HLERequestContext& ctx) {
|
|||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
rb.PushMappedBuffer(buffer);
|
rb.PushMappedBuffer(buffer);
|
||||||
|
|
||||||
LOG_WARNING(Service_BOSS, "(STUBBED) size={:#010X}", size);
|
LOG_WARNING(Service_BOSS, "(STUBBED) size={:#010x}", size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Module::Interface::CancelTask(Kernel::HLERequestContext& ctx) {
|
void Module::Interface::CancelTask(Kernel::HLERequestContext& ctx) {
|
||||||
@ -402,7 +517,7 @@ void Module::Interface::CancelTask(Kernel::HLERequestContext& ctx) {
|
|||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
rb.PushMappedBuffer(buffer);
|
rb.PushMappedBuffer(buffer);
|
||||||
|
|
||||||
LOG_WARNING(Service_BOSS, "(STUBBED) size={:#010X}", size);
|
LOG_WARNING(Service_BOSS, "(STUBBED) size={:#010x}", size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Module::Interface::GetTaskFinishHandle(Kernel::HLERequestContext& ctx) {
|
void Module::Interface::GetTaskFinishHandle(Kernel::HLERequestContext& ctx) {
|
||||||
@ -428,7 +543,7 @@ void Module::Interface::GetTaskState(Kernel::HLERequestContext& ctx) {
|
|||||||
rb.Push<u8>(0); /// unknown, usually 0
|
rb.Push<u8>(0); /// unknown, usually 0
|
||||||
rb.PushMappedBuffer(buffer);
|
rb.PushMappedBuffer(buffer);
|
||||||
|
|
||||||
LOG_WARNING(Service_BOSS, "(STUBBED) size={:#010X}, state={:#06X}", size, state);
|
LOG_WARNING(Service_BOSS, "(STUBBED) size={:#010x}, state={:#06x}", size, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Module::Interface::GetTaskResult(Kernel::HLERequestContext& ctx) {
|
void Module::Interface::GetTaskResult(Kernel::HLERequestContext& ctx) {
|
||||||
@ -443,7 +558,7 @@ void Module::Interface::GetTaskResult(Kernel::HLERequestContext& ctx) {
|
|||||||
rb.Push<u8>(0); // stub 0 (8 bit value)
|
rb.Push<u8>(0); // stub 0 (8 bit value)
|
||||||
rb.PushMappedBuffer(buffer);
|
rb.PushMappedBuffer(buffer);
|
||||||
|
|
||||||
LOG_WARNING(Service_BOSS, "(STUBBED) size={:#010X}", size);
|
LOG_WARNING(Service_BOSS, "(STUBBED) size={:#010x}", size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Module::Interface::GetTaskCommErrorCode(Kernel::HLERequestContext& ctx) {
|
void Module::Interface::GetTaskCommErrorCode(Kernel::HLERequestContext& ctx) {
|
||||||
@ -458,7 +573,7 @@ void Module::Interface::GetTaskCommErrorCode(Kernel::HLERequestContext& ctx) {
|
|||||||
rb.Push<u8>(0); // stub 0 (8 bit value)
|
rb.Push<u8>(0); // stub 0 (8 bit value)
|
||||||
rb.PushMappedBuffer(buffer);
|
rb.PushMappedBuffer(buffer);
|
||||||
|
|
||||||
LOG_WARNING(Service_BOSS, "(STUBBED) size={:#010X}", size);
|
LOG_WARNING(Service_BOSS, "(STUBBED) size={:#010x}", size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Module::Interface::GetTaskStatus(Kernel::HLERequestContext& ctx) {
|
void Module::Interface::GetTaskStatus(Kernel::HLERequestContext& ctx) {
|
||||||
@ -473,7 +588,7 @@ void Module::Interface::GetTaskStatus(Kernel::HLERequestContext& ctx) {
|
|||||||
rb.Push<u8>(0); // stub 0 (8 bit value)
|
rb.Push<u8>(0); // stub 0 (8 bit value)
|
||||||
rb.PushMappedBuffer(buffer);
|
rb.PushMappedBuffer(buffer);
|
||||||
|
|
||||||
LOG_WARNING(Service_BOSS, "(STUBBED) size={:#010X}, unk_param2={:#04X}, unk_param3={:#04X}",
|
LOG_WARNING(Service_BOSS, "(STUBBED) size={:#010x}, unk_param2={:#04x}, unk_param3={:#04x}",
|
||||||
size, unk_param2, unk_param3);
|
size, unk_param2, unk_param3);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -488,7 +603,7 @@ void Module::Interface::GetTaskError(Kernel::HLERequestContext& ctx) {
|
|||||||
rb.Push<u8>(0); // stub 0 (8 bit value)
|
rb.Push<u8>(0); // stub 0 (8 bit value)
|
||||||
rb.PushMappedBuffer(buffer);
|
rb.PushMappedBuffer(buffer);
|
||||||
|
|
||||||
LOG_WARNING(Service_BOSS, "(STUBBED) size={:#010X}, unk_param2={:#04X}", size, unk_param2);
|
LOG_WARNING(Service_BOSS, "(STUBBED) size={:#010x}, unk_param2={:#04x}", size, unk_param2);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Module::Interface::GetTaskInfo(Kernel::HLERequestContext& ctx) {
|
void Module::Interface::GetTaskInfo(Kernel::HLERequestContext& ctx) {
|
||||||
@ -501,7 +616,7 @@ void Module::Interface::GetTaskInfo(Kernel::HLERequestContext& ctx) {
|
|||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
rb.PushMappedBuffer(buffer);
|
rb.PushMappedBuffer(buffer);
|
||||||
|
|
||||||
LOG_WARNING(Service_BOSS, "(STUBBED) size={:#010X}, unk_param2={:#04X}", size, unk_param2);
|
LOG_WARNING(Service_BOSS, "(STUBBED) size={:#010x}, unk_param2={:#04x}", size, unk_param2);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Module::Interface::DeleteNsData(Kernel::HLERequestContext& ctx) {
|
void Module::Interface::DeleteNsData(Kernel::HLERequestContext& ctx) {
|
||||||
@ -511,7 +626,7 @@ void Module::Interface::DeleteNsData(Kernel::HLERequestContext& ctx) {
|
|||||||
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
|
|
||||||
LOG_WARNING(Service_BOSS, "(STUBBED) ns_data_id={:#010X}", ns_data_id);
|
LOG_WARNING(Service_BOSS, "(STUBBED) ns_data_id={:#010x}", ns_data_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Module::Interface::GetNsDataHeaderInfo(Kernel::HLERequestContext& ctx) {
|
void Module::Interface::GetNsDataHeaderInfo(Kernel::HLERequestContext& ctx) {
|
||||||
@ -525,7 +640,7 @@ void Module::Interface::GetNsDataHeaderInfo(Kernel::HLERequestContext& ctx) {
|
|||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
rb.PushMappedBuffer(buffer);
|
rb.PushMappedBuffer(buffer);
|
||||||
|
|
||||||
LOG_WARNING(Service_BOSS, "(STUBBED) ns_data_id={:#010X}, type={:#04X}, size={:#010X}",
|
LOG_WARNING(Service_BOSS, "(STUBBED) ns_data_id={:#010x}, type={:#04x}, size={:#010x}",
|
||||||
ns_data_id, type, size);
|
ns_data_id, type, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -542,7 +657,7 @@ void Module::Interface::ReadNsData(Kernel::HLERequestContext& ctx) {
|
|||||||
rb.Push<u32>(0); /// unknown
|
rb.Push<u32>(0); /// unknown
|
||||||
rb.PushMappedBuffer(buffer);
|
rb.PushMappedBuffer(buffer);
|
||||||
|
|
||||||
LOG_WARNING(Service_BOSS, "(STUBBED) ns_data_id={:#010X}, offset={:#018X}, size={:#010X}",
|
LOG_WARNING(Service_BOSS, "(STUBBED) ns_data_id={:#010x}, offset={:#018x}, size={:#010x}",
|
||||||
ns_data_id, offset, size);
|
ns_data_id, offset, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -554,7 +669,7 @@ void Module::Interface::SetNsDataAdditionalInfo(Kernel::HLERequestContext& ctx)
|
|||||||
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
|
|
||||||
LOG_WARNING(Service_BOSS, "(STUBBED) unk_param1={:#010X}, unk_param2={:#010X}", unk_param1,
|
LOG_WARNING(Service_BOSS, "(STUBBED) unk_param1={:#010x}, unk_param2={:#010x}", unk_param1,
|
||||||
unk_param2);
|
unk_param2);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -566,19 +681,19 @@ void Module::Interface::GetNsDataAdditionalInfo(Kernel::HLERequestContext& ctx)
|
|||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
rb.Push<u32>(0); // stub 0 (32bit value)
|
rb.Push<u32>(0); // stub 0 (32bit value)
|
||||||
|
|
||||||
LOG_WARNING(Service_BOSS, "(STUBBED) unk_param1={:#010X}", unk_param1);
|
LOG_WARNING(Service_BOSS, "(STUBBED) unk_param1={:#010x}", unk_param1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Module::Interface::SetNsDataNewFlag(Kernel::HLERequestContext& ctx) {
|
void Module::Interface::SetNsDataNewFlag(Kernel::HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp(ctx);
|
IPC::RequestParser rp(ctx);
|
||||||
const u32 unk_param1 = rp.Pop<u32>();
|
const u32 unk_param1 = rp.Pop<u32>();
|
||||||
ns_data_new_flag = rp.Pop<u8>();
|
boss->ns_data_new_flag = rp.Pop<u8>();
|
||||||
|
|
||||||
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
|
|
||||||
LOG_WARNING(Service_BOSS, "(STUBBED) unk_param1={:#010X}, ns_data_new_flag={:#04X}", unk_param1,
|
LOG_WARNING(Service_BOSS, "(STUBBED) unk_param1={:#010x}, ns_data_new_flag={:#04x}", unk_param1,
|
||||||
ns_data_new_flag);
|
boss->ns_data_new_flag);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Module::Interface::GetNsDataNewFlag(Kernel::HLERequestContext& ctx) {
|
void Module::Interface::GetNsDataNewFlag(Kernel::HLERequestContext& ctx) {
|
||||||
@ -587,10 +702,10 @@ void Module::Interface::GetNsDataNewFlag(Kernel::HLERequestContext& ctx) {
|
|||||||
|
|
||||||
IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
|
IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
rb.Push<u8>(ns_data_new_flag);
|
rb.Push<u8>(boss->ns_data_new_flag);
|
||||||
|
|
||||||
LOG_WARNING(Service_BOSS, "(STUBBED) unk_param1={:#010X}, ns_data_new_flag={:#04X}", unk_param1,
|
LOG_WARNING(Service_BOSS, "(STUBBED) unk_param1={:#010x}, ns_data_new_flag={:#04x}", unk_param1,
|
||||||
ns_data_new_flag);
|
boss->ns_data_new_flag);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Module::Interface::GetNsDataLastUpdate(Kernel::HLERequestContext& ctx) {
|
void Module::Interface::GetNsDataLastUpdate(Kernel::HLERequestContext& ctx) {
|
||||||
@ -602,7 +717,7 @@ void Module::Interface::GetNsDataLastUpdate(Kernel::HLERequestContext& ctx) {
|
|||||||
rb.Push<u32>(0); // stub 0 (32bit value)
|
rb.Push<u32>(0); // stub 0 (32bit value)
|
||||||
rb.Push<u32>(0); // stub 0 (32bit value)
|
rb.Push<u32>(0); // stub 0 (32bit value)
|
||||||
|
|
||||||
LOG_WARNING(Service_BOSS, "(STUBBED) unk_param1={:#010X}", unk_param1);
|
LOG_WARNING(Service_BOSS, "(STUBBED) unk_param1={:#010x}", unk_param1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Module::Interface::GetErrorCode(Kernel::HLERequestContext& ctx) {
|
void Module::Interface::GetErrorCode(Kernel::HLERequestContext& ctx) {
|
||||||
@ -613,7 +728,7 @@ void Module::Interface::GetErrorCode(Kernel::HLERequestContext& ctx) {
|
|||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
rb.Push<u32>(0); /// output value
|
rb.Push<u32>(0); /// output value
|
||||||
|
|
||||||
LOG_WARNING(Service_BOSS, "(STUBBED) input={:#010X}", input);
|
LOG_WARNING(Service_BOSS, "(STUBBED) input={:#010x}", input);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Module::Interface::RegisterStorageEntry(Kernel::HLERequestContext& ctx) {
|
void Module::Interface::RegisterStorageEntry(Kernel::HLERequestContext& ctx) {
|
||||||
@ -628,8 +743,8 @@ void Module::Interface::RegisterStorageEntry(Kernel::HLERequestContext& ctx) {
|
|||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
|
|
||||||
LOG_WARNING(Service_BOSS,
|
LOG_WARNING(Service_BOSS,
|
||||||
"(STUBBED) unk_param1={:#010X}, unk_param2={:#010X}, unk_param3={:#010X}, "
|
"(STUBBED) unk_param1={:#010x}, unk_param2={:#010x}, unk_param3={:#010x}, "
|
||||||
"unk_param4={:#010X}, unk_param5={:#04X}",
|
"unk_param4={:#010x}, unk_param5={:#04x}",
|
||||||
unk_param1, unk_param2, unk_param3, unk_param4, unk_param5);
|
unk_param1, unk_param2, unk_param3, unk_param4, unk_param5);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -655,8 +770,8 @@ void Module::Interface::SetStorageOption(Kernel::HLERequestContext& ctx) {
|
|||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
|
|
||||||
LOG_WARNING(Service_BOSS,
|
LOG_WARNING(Service_BOSS,
|
||||||
"(STUBBED) unk_param1={:#04X}, unk_param2={:#010X}, "
|
"(STUBBED) unk_param1={:#04x}, unk_param2={:#010x}, "
|
||||||
"unk_param3={:#08X}, unk_param4={:#08X}",
|
"unk_param3={:#08x}, unk_param4={:#08x}",
|
||||||
unk_param1, unk_param2, unk_param3, unk_param4);
|
unk_param1, unk_param2, unk_param3, unk_param4);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -682,7 +797,7 @@ void Module::Interface::StartBgImmediate(Kernel::HLERequestContext& ctx) {
|
|||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
rb.PushMappedBuffer(buffer);
|
rb.PushMappedBuffer(buffer);
|
||||||
|
|
||||||
LOG_WARNING(Service_BOSS, "(STUBBED) size={:#010X}", size);
|
LOG_WARNING(Service_BOSS, "(STUBBED) size={:#010x}", size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Module::Interface::GetTaskProperty0(Kernel::HLERequestContext& ctx) {
|
void Module::Interface::GetTaskProperty0(Kernel::HLERequestContext& ctx) {
|
||||||
@ -695,7 +810,7 @@ void Module::Interface::GetTaskProperty0(Kernel::HLERequestContext& ctx) {
|
|||||||
rb.Push<u8>(0); /// current state of PropertyID 0x0 stub 0 (8bit value)
|
rb.Push<u8>(0); /// current state of PropertyID 0x0 stub 0 (8bit value)
|
||||||
rb.PushMappedBuffer(buffer);
|
rb.PushMappedBuffer(buffer);
|
||||||
|
|
||||||
LOG_WARNING(Service_BOSS, "(STUBBED) size={:#010X}", size);
|
LOG_WARNING(Service_BOSS, "(STUBBED) size={:#010x}", size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Module::Interface::RegisterImmediateTask(Kernel::HLERequestContext& ctx) {
|
void Module::Interface::RegisterImmediateTask(Kernel::HLERequestContext& ctx) {
|
||||||
@ -709,7 +824,7 @@ void Module::Interface::RegisterImmediateTask(Kernel::HLERequestContext& ctx) {
|
|||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
rb.PushMappedBuffer(buffer);
|
rb.PushMappedBuffer(buffer);
|
||||||
|
|
||||||
LOG_WARNING(Service_BOSS, "(STUBBED) size={:#010X}, unk_param2={:#04X}, unk_param3={:#04X}",
|
LOG_WARNING(Service_BOSS, "(STUBBED) size={:#010x}, unk_param2={:#04x}, unk_param3={:#04x}",
|
||||||
size, unk_param2, unk_param3);
|
size, unk_param2, unk_param3);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -725,7 +840,7 @@ void Module::Interface::SetTaskQuery(Kernel::HLERequestContext& ctx) {
|
|||||||
rb.PushMappedBuffer(buffer1);
|
rb.PushMappedBuffer(buffer1);
|
||||||
rb.PushMappedBuffer(buffer2);
|
rb.PushMappedBuffer(buffer2);
|
||||||
|
|
||||||
LOG_WARNING(Service_BOSS, "(STUBBED) buffer1_size={:#010X}, buffer2_size={:#010X}",
|
LOG_WARNING(Service_BOSS, "(STUBBED) buffer1_size={:#010x}, buffer2_size={:#010x}",
|
||||||
buffer1_size, buffer2_size);
|
buffer1_size, buffer2_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -741,7 +856,7 @@ void Module::Interface::GetTaskQuery(Kernel::HLERequestContext& ctx) {
|
|||||||
rb.PushMappedBuffer(buffer1);
|
rb.PushMappedBuffer(buffer1);
|
||||||
rb.PushMappedBuffer(buffer2);
|
rb.PushMappedBuffer(buffer2);
|
||||||
|
|
||||||
LOG_WARNING(Service_BOSS, "(STUBBED) buffer1_size={:#010X}, buffer2_size={:#010X}",
|
LOG_WARNING(Service_BOSS, "(STUBBED) buffer1_size={:#010x}, buffer2_size={:#010x}",
|
||||||
buffer1_size, buffer2_size);
|
buffer1_size, buffer2_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -753,7 +868,7 @@ void Module::Interface::InitializeSessionPrivileged(Kernel::HLERequestContext& c
|
|||||||
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
|
|
||||||
LOG_WARNING(Service_BOSS, "(STUBBED) programID={:#018X}", programID);
|
LOG_WARNING(Service_BOSS, "(STUBBED) programID={:#018x}", programID);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Module::Interface::GetAppNewFlag(Kernel::HLERequestContext& ctx) {
|
void Module::Interface::GetAppNewFlag(Kernel::HLERequestContext& ctx) {
|
||||||
@ -764,7 +879,7 @@ void Module::Interface::GetAppNewFlag(Kernel::HLERequestContext& ctx) {
|
|||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
rb.Push<u8>(0); // 0 = nothing new, 1 = new content
|
rb.Push<u8>(0); // 0 = nothing new, 1 = new content
|
||||||
|
|
||||||
LOG_WARNING(Service_BOSS, "(STUBBED) programID={:#018X}", programID);
|
LOG_WARNING(Service_BOSS, "(STUBBED) programID={:#018x}", programID);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Module::Interface::GetNsDataIdListPrivileged(Kernel::HLERequestContext& ctx) {
|
void Module::Interface::GetNsDataIdListPrivileged(Kernel::HLERequestContext& ctx) {
|
||||||
@ -783,8 +898,8 @@ void Module::Interface::GetNsDataIdListPrivileged(Kernel::HLERequestContext& ctx
|
|||||||
rb.PushMappedBuffer(buffer);
|
rb.PushMappedBuffer(buffer);
|
||||||
|
|
||||||
LOG_WARNING(Service_BOSS,
|
LOG_WARNING(Service_BOSS,
|
||||||
"(STUBBED) programID={:#018X}, filter={:#010X}, max_entries={:#010X}, "
|
"(STUBBED) programID={:#018x}, filter={:#010x}, max_entries={:#010x}, "
|
||||||
"word_index_start={:#06X}, start_ns_data_id={:#010X}",
|
"word_index_start={:#06x}, start_ns_data_id={:#010x}",
|
||||||
programID, filter, max_entries, word_index_start, start_ns_data_id);
|
programID, filter, max_entries, word_index_start, start_ns_data_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -804,8 +919,8 @@ void Module::Interface::GetNsDataIdListPrivileged1(Kernel::HLERequestContext& ct
|
|||||||
rb.PushMappedBuffer(buffer);
|
rb.PushMappedBuffer(buffer);
|
||||||
|
|
||||||
LOG_WARNING(Service_BOSS,
|
LOG_WARNING(Service_BOSS,
|
||||||
"(STUBBED) programID={:#018X}, filter={:#010X}, max_entries={:#010X}, "
|
"(STUBBED) programID={:#018x}, filter={:#010x}, max_entries={:#010x}, "
|
||||||
"word_index_start={:#06X}, start_ns_data_id={:#010X}",
|
"word_index_start={:#06x}, start_ns_data_id={:#010x}",
|
||||||
programID, filter, max_entries, word_index_start, start_ns_data_id);
|
programID, filter, max_entries, word_index_start, start_ns_data_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -819,7 +934,7 @@ void Module::Interface::SendPropertyPrivileged(Kernel::HLERequestContext& ctx) {
|
|||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
rb.PushMappedBuffer(buffer);
|
rb.PushMappedBuffer(buffer);
|
||||||
|
|
||||||
LOG_WARNING(Service_BOSS, "(STUBBED) property_id={:#06X}, size={:#010X}", property_id, size);
|
LOG_WARNING(Service_BOSS, "(STUBBED) property_id={:#06x}, size={:#010x}", property_id, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Module::Interface::DeleteNsDataPrivileged(Kernel::HLERequestContext& ctx) {
|
void Module::Interface::DeleteNsDataPrivileged(Kernel::HLERequestContext& ctx) {
|
||||||
@ -830,7 +945,7 @@ void Module::Interface::DeleteNsDataPrivileged(Kernel::HLERequestContext& ctx) {
|
|||||||
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
|
|
||||||
LOG_WARNING(Service_BOSS, "(STUBBED) programID={:#018X}, ns_data_id={:#010X}", programID,
|
LOG_WARNING(Service_BOSS, "(STUBBED) programID={:#018x}, ns_data_id={:#010x}", programID,
|
||||||
ns_data_id);
|
ns_data_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -847,7 +962,7 @@ void Module::Interface::GetNsDataHeaderInfoPrivileged(Kernel::HLERequestContext&
|
|||||||
rb.PushMappedBuffer(buffer);
|
rb.PushMappedBuffer(buffer);
|
||||||
|
|
||||||
LOG_WARNING(Service_BOSS,
|
LOG_WARNING(Service_BOSS,
|
||||||
"(STUBBED) programID={:#018X} ns_data_id={:#010X}, type={:#04X}, size={:#010X}",
|
"(STUBBED) programID={:#018x} ns_data_id={:#010x}, type={:#04x}, size={:#010x}",
|
||||||
programID, ns_data_id, type, size);
|
programID, ns_data_id, type, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -866,7 +981,7 @@ void Module::Interface::ReadNsDataPrivileged(Kernel::HLERequestContext& ctx) {
|
|||||||
rb.PushMappedBuffer(buffer);
|
rb.PushMappedBuffer(buffer);
|
||||||
|
|
||||||
LOG_WARNING(Service_BOSS,
|
LOG_WARNING(Service_BOSS,
|
||||||
"(STUBBED) programID={:#018X}, ns_data_id={:#010X}, offset={:#018X}, size={:#010X}",
|
"(STUBBED) programID={:#018x}, ns_data_id={:#010x}, offset={:#018x}, size={:#010x}",
|
||||||
programID, ns_data_id, offset, size);
|
programID, ns_data_id, offset, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -874,15 +989,15 @@ void Module::Interface::SetNsDataNewFlagPrivileged(Kernel::HLERequestContext& ct
|
|||||||
IPC::RequestParser rp(ctx);
|
IPC::RequestParser rp(ctx);
|
||||||
const u64 programID = rp.Pop<u64>();
|
const u64 programID = rp.Pop<u64>();
|
||||||
const u32 unk_param1 = rp.Pop<u32>();
|
const u32 unk_param1 = rp.Pop<u32>();
|
||||||
ns_data_new_flag_privileged = rp.Pop<u8>();
|
boss->ns_data_new_flag_privileged = rp.Pop<u8>();
|
||||||
|
|
||||||
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
|
|
||||||
LOG_WARNING(
|
LOG_WARNING(
|
||||||
Service_BOSS,
|
Service_BOSS,
|
||||||
"(STUBBED) programID={:#018X}, unk_param1={:#010X}, ns_data_new_flag_privileged={:#04X}",
|
"(STUBBED) programID={:#018x}, unk_param1={:#010x}, ns_data_new_flag_privileged={:#04x}",
|
||||||
programID, unk_param1, ns_data_new_flag_privileged);
|
programID, unk_param1, boss->ns_data_new_flag_privileged);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Module::Interface::GetNsDataNewFlagPrivileged(Kernel::HLERequestContext& ctx) {
|
void Module::Interface::GetNsDataNewFlagPrivileged(Kernel::HLERequestContext& ctx) {
|
||||||
@ -892,18 +1007,18 @@ void Module::Interface::GetNsDataNewFlagPrivileged(Kernel::HLERequestContext& ct
|
|||||||
|
|
||||||
IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
|
IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
rb.Push<u8>(ns_data_new_flag_privileged);
|
rb.Push<u8>(boss->ns_data_new_flag_privileged);
|
||||||
|
|
||||||
LOG_WARNING(
|
LOG_WARNING(
|
||||||
Service_BOSS,
|
Service_BOSS,
|
||||||
"(STUBBED) programID={:#018X}, unk_param1={:#010X}, ns_data_new_flag_privileged={:#04X}",
|
"(STUBBED) programID={:#018x}, unk_param1={:#010x}, ns_data_new_flag_privileged={:#04x}",
|
||||||
programID, unk_param1, ns_data_new_flag_privileged);
|
programID, unk_param1, boss->ns_data_new_flag_privileged);
|
||||||
}
|
}
|
||||||
|
|
||||||
Module::Interface::Interface(std::shared_ptr<Module> boss, const char* name, u32 max_session)
|
Module::Interface::Interface(std::shared_ptr<Module> boss, const char* name, u32 max_session)
|
||||||
: ServiceFramework(name, max_session), boss(std::move(boss)) {}
|
: ServiceFramework(name, max_session), boss(std::move(boss)) {}
|
||||||
|
|
||||||
Module::Module(Core::System& system) {
|
Module::Module(Core::System& system_) : system(system_) {
|
||||||
using namespace Kernel;
|
using namespace Kernel;
|
||||||
// TODO: verify ResetType
|
// TODO: verify ResetType
|
||||||
task_finish_event =
|
task_finish_event =
|
||||||
|
@ -5,10 +5,11 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <boost/serialization/shared_ptr.hpp>
|
#include <boost/serialization/export.hpp>
|
||||||
#include "core/global.h"
|
#include "core/global.h"
|
||||||
#include "core/hle/kernel/event.h"
|
#include "core/hle/kernel/event.h"
|
||||||
#include "core/hle/kernel/resource_limit.h"
|
#include "core/hle/kernel/resource_limit.h"
|
||||||
|
#include "core/hle/service/boss/online_service.h"
|
||||||
#include "core/hle/service/service.h"
|
#include "core/hle/service/service.h"
|
||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
@ -19,10 +20,19 @@ namespace Service::BOSS {
|
|||||||
|
|
||||||
class Module final {
|
class Module final {
|
||||||
public:
|
public:
|
||||||
explicit Module(Core::System& system);
|
explicit Module(Core::System& system_);
|
||||||
~Module() = default;
|
~Module() = default;
|
||||||
|
|
||||||
class Interface : public ServiceFramework<Interface> {
|
struct SessionData : public Kernel::SessionRequestHandler::SessionDataBase {
|
||||||
|
std::shared_ptr<OnlineService> online_service{};
|
||||||
|
|
||||||
|
private:
|
||||||
|
template <class Archive>
|
||||||
|
void serialize(Archive& ar, const unsigned int);
|
||||||
|
friend class boost::serialization::access;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Interface : public ServiceFramework<Interface, SessionData> {
|
||||||
public:
|
public:
|
||||||
Interface(std::shared_ptr<Module> boss, const char* name, u32 max_session);
|
Interface(std::shared_ptr<Module> boss, const char* name, u32 max_session);
|
||||||
~Interface() = default;
|
~Interface() = default;
|
||||||
@ -958,29 +968,20 @@ public:
|
|||||||
protected:
|
protected:
|
||||||
std::shared_ptr<Module> boss;
|
std::shared_ptr<Module> boss;
|
||||||
|
|
||||||
private:
|
std::shared_ptr<OnlineService> GetSessionService(Kernel::HLERequestContext& ctx);
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
Core::System& system;
|
||||||
|
std::shared_ptr<Kernel::Event> task_finish_event;
|
||||||
|
|
||||||
u8 new_arrival_flag;
|
u8 new_arrival_flag;
|
||||||
u8 ns_data_new_flag;
|
u8 ns_data_new_flag;
|
||||||
u8 ns_data_new_flag_privileged;
|
u8 ns_data_new_flag_privileged;
|
||||||
u8 output_flag;
|
u8 output_flag;
|
||||||
|
|
||||||
template <class Archive>
|
template <class Archive>
|
||||||
void serialize(Archive& ar, const unsigned int) {
|
void serialize(Archive& ar, const unsigned int);
|
||||||
ar& new_arrival_flag;
|
|
||||||
ar& ns_data_new_flag;
|
|
||||||
ar& ns_data_new_flag_privileged;
|
|
||||||
ar& output_flag;
|
|
||||||
}
|
|
||||||
friend class boost::serialization::access;
|
|
||||||
};
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::shared_ptr<Kernel::Event> task_finish_event;
|
|
||||||
|
|
||||||
template <class Archive>
|
|
||||||
void serialize(Archive& ar, const unsigned int) {
|
|
||||||
ar& task_finish_event;
|
|
||||||
}
|
|
||||||
friend class boost::serialization::access;
|
friend class boost::serialization::access;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -988,9 +989,6 @@ void InstallInterfaces(Core::System& system);
|
|||||||
|
|
||||||
} // namespace Service::BOSS
|
} // namespace Service::BOSS
|
||||||
|
|
||||||
namespace boost::serialization {
|
SERVICE_CONSTRUCT(Service::BOSS::Module)
|
||||||
template <class Archive>
|
BOOST_CLASS_EXPORT_KEY(Service::BOSS::Module)
|
||||||
void load_construct_data(Archive& ar, Service::BOSS::Module* t, const unsigned int) {
|
BOOST_CLASS_EXPORT_KEY(Service::BOSS::Module::SessionData)
|
||||||
::new (t) Service::BOSS::Module(Core::Global<Core::System>());
|
|
||||||
}
|
|
||||||
} // namespace boost::serialization
|
|
||||||
|
400
src/core/hle/service/boss/online_service.cpp
Normal file
400
src/core/hle/service/boss/online_service.cpp
Normal file
@ -0,0 +1,400 @@
|
|||||||
|
// Copyright 2023 Citra Emulator Project
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include <boost/serialization/map.hpp>
|
||||||
|
#include "common/archives.h"
|
||||||
|
#include "common/file_util.h"
|
||||||
|
#include "common/serialization/boost_std_variant.hpp"
|
||||||
|
#include "common/string_util.h"
|
||||||
|
#include "core/core.h"
|
||||||
|
#include "core/file_sys/archive_backend.h"
|
||||||
|
#include "core/file_sys/archive_extsavedata.h"
|
||||||
|
#include "core/file_sys/archive_systemsavedata.h"
|
||||||
|
#include "core/file_sys/directory_backend.h"
|
||||||
|
#include "core/file_sys/errors.h"
|
||||||
|
#include "core/file_sys/file_backend.h"
|
||||||
|
#include "core/hle/kernel/hle_ipc.h"
|
||||||
|
#include "core/hle/service/boss/online_service.h"
|
||||||
|
|
||||||
|
namespace Service::BOSS {
|
||||||
|
|
||||||
|
OnlineService::OnlineService(u64 program_id_, u64 extdata_id_)
|
||||||
|
: program_id(program_id_), extdata_id(extdata_id_) {}
|
||||||
|
|
||||||
|
template <class Archive>
|
||||||
|
void OnlineService::serialize(Archive& ar, const unsigned int) {
|
||||||
|
ar& current_props;
|
||||||
|
ar& task_id_list;
|
||||||
|
ar& program_id;
|
||||||
|
ar& extdata_id;
|
||||||
|
}
|
||||||
|
SERIALIZE_IMPL(OnlineService)
|
||||||
|
|
||||||
|
template <class Archive>
|
||||||
|
void BossTaskProperties::serialize(Archive& ar, const unsigned int) {
|
||||||
|
ar& task_result;
|
||||||
|
ar& properties;
|
||||||
|
}
|
||||||
|
SERIALIZE_IMPL(BossTaskProperties)
|
||||||
|
|
||||||
|
ResultCode OnlineService::InitializeSession(u64 init_program_id) {
|
||||||
|
// The BOSS service uses three databases:
|
||||||
|
// BOSS_A: Archive? A list of program ids and some properties that are keyed on program
|
||||||
|
// BOSS_SS: Saved Strings? Includes the url and the other string properties, and also some other
|
||||||
|
// properties?, keyed on task_id
|
||||||
|
// BOSS_SV: Saved Values? Includes task id and most properties keyed on task_id
|
||||||
|
|
||||||
|
// It saves data in its databases in the following format:
|
||||||
|
// A four byte header (always 00 80 34 12?) followed by any number of 0x800(BOSS_A) and
|
||||||
|
// 0xC00(BOSS_SS and BOSS_SV) entries.
|
||||||
|
|
||||||
|
current_props = BossTaskProperties();
|
||||||
|
|
||||||
|
if (init_program_id == 0) {
|
||||||
|
init_program_id = program_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string& nand_directory = FileUtil::GetUserPath(FileUtil::UserPath::NANDDir);
|
||||||
|
FileSys::ArchiveFactory_SystemSaveData systemsavedata_factory(nand_directory);
|
||||||
|
|
||||||
|
// Open the SystemSaveData archive 0x00010034
|
||||||
|
const FileSys::Path archive_path(boss_system_savedata_id);
|
||||||
|
auto archive_result = systemsavedata_factory.Open(archive_path, 0);
|
||||||
|
|
||||||
|
std::unique_ptr<FileSys::ArchiveBackend> boss_system_save_data_archive;
|
||||||
|
if (archive_result.Succeeded()) {
|
||||||
|
boss_system_save_data_archive = std::move(archive_result).Unwrap();
|
||||||
|
} else if (archive_result.Code() == FileSys::ERROR_NOT_FOUND) {
|
||||||
|
// If the archive didn't exist, create the files inside
|
||||||
|
systemsavedata_factory.Format(archive_path, FileSys::ArchiveFormatInfo(), 0);
|
||||||
|
|
||||||
|
// Open it again to get a valid archive now that the folder exists
|
||||||
|
auto create_archive_result = systemsavedata_factory.Open(archive_path, 0);
|
||||||
|
if (!create_archive_result.Succeeded()) {
|
||||||
|
LOG_ERROR(Service_BOSS, "Could not open BOSS savedata");
|
||||||
|
return ResultCode(1);
|
||||||
|
}
|
||||||
|
boss_system_save_data_archive = std::move(create_archive_result).Unwrap();
|
||||||
|
} else {
|
||||||
|
LOG_ERROR(Service_BOSS, "Could not open BOSS savedata");
|
||||||
|
return ResultCode(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
FileSys::Mode open_mode = {};
|
||||||
|
open_mode.read_flag.Assign(1);
|
||||||
|
|
||||||
|
// TODO: Read data from BOSS_A.db
|
||||||
|
|
||||||
|
auto boss_sv_result =
|
||||||
|
boss_system_save_data_archive->OpenFile(FileSys::Path("/BOSS_SV.db"), open_mode);
|
||||||
|
auto boss_ss_result =
|
||||||
|
boss_system_save_data_archive->OpenFile(FileSys::Path("/BOSS_SS.db"), open_mode);
|
||||||
|
if (!boss_sv_result.Succeeded() || !boss_ss_result.Succeeded()) {
|
||||||
|
LOG_ERROR(Service_BOSS, "Could not open BOSS database.");
|
||||||
|
return RESULT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto boss_sv = std::move(boss_sv_result).Unwrap();
|
||||||
|
auto boss_ss = std::move(boss_ss_result).Unwrap();
|
||||||
|
if (!(boss_sv->GetSize() > BOSS_SAVE_HEADER_SIZE &&
|
||||||
|
((boss_sv->GetSize() - BOSS_SAVE_HEADER_SIZE) % BOSS_S_ENTRY_SIZE) == 0 &&
|
||||||
|
boss_sv->GetSize() == boss_ss->GetSize())) {
|
||||||
|
LOG_ERROR(Service_BOSS, "BOSS database has incorrect size.");
|
||||||
|
return RESULT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read the files if they already exist
|
||||||
|
const u64 num_entries = (boss_sv->GetSize() - BOSS_SAVE_HEADER_SIZE) / BOSS_S_ENTRY_SIZE;
|
||||||
|
for (u64 i = 0; i < num_entries; i++) {
|
||||||
|
const u64 entry_offset = i * BOSS_S_ENTRY_SIZE + BOSS_SAVE_HEADER_SIZE;
|
||||||
|
|
||||||
|
BossSVData sv_data;
|
||||||
|
boss_sv->Read(entry_offset, sizeof(BossSVData), reinterpret_cast<u8*>(&sv_data));
|
||||||
|
|
||||||
|
BossSSData ss_data;
|
||||||
|
boss_ss->Read(entry_offset, sizeof(BossSSData), reinterpret_cast<u8*>(&ss_data));
|
||||||
|
|
||||||
|
if (sv_data.program_id != init_program_id) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<u8> url_vector(URL_SIZE);
|
||||||
|
std::memcpy(url_vector.data(), ss_data.url.data(), URL_SIZE);
|
||||||
|
current_props.properties[PropertyID::Url] = url_vector;
|
||||||
|
|
||||||
|
const auto task_id = std::string(sv_data.task_id.data());
|
||||||
|
if (task_id_list.contains(task_id)) {
|
||||||
|
LOG_WARNING(Service_BOSS, "TaskId already in list, will be replaced");
|
||||||
|
task_id_list.erase(task_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
task_id_list.emplace(task_id, std::move(current_props));
|
||||||
|
current_props = BossTaskProperties();
|
||||||
|
}
|
||||||
|
|
||||||
|
return RESULT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnlineService::RegisterTask(const u32 size, Kernel::MappedBuffer& buffer) {
|
||||||
|
std::string task_id(size, 0);
|
||||||
|
buffer.Read(task_id.data(), 0, size);
|
||||||
|
|
||||||
|
if (task_id_list.contains(task_id)) {
|
||||||
|
LOG_WARNING(Service_BOSS, "TaskId already in list, will be replaced");
|
||||||
|
task_id_list.erase(task_id);
|
||||||
|
}
|
||||||
|
task_id_list.emplace(task_id, std::move(current_props));
|
||||||
|
current_props = BossTaskProperties();
|
||||||
|
}
|
||||||
|
|
||||||
|
ResultCode OnlineService::UnregisterTask(const u32 size, Kernel::MappedBuffer& buffer) {
|
||||||
|
if (size > TASK_ID_SIZE) {
|
||||||
|
LOG_WARNING(Service_BOSS, "TaskId cannot be longer than 8");
|
||||||
|
return ResultCode(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string task_id(size, 0);
|
||||||
|
buffer.Read(task_id.data(), 0, size);
|
||||||
|
if (task_id_list.erase(task_id) == 0) {
|
||||||
|
LOG_WARNING(Service_BOSS, "TaskId not in list");
|
||||||
|
return ResultCode(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return RESULT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnlineService::GetTaskIdList() {
|
||||||
|
current_props.properties[PropertyID::TotalTasks] = static_cast<u16>(task_id_list.size());
|
||||||
|
|
||||||
|
const auto num_task_ids = TASKIDLIST_SIZE / TASK_ID_SIZE;
|
||||||
|
std::vector<std::array<u8, TASK_ID_SIZE>> task_ids(num_task_ids);
|
||||||
|
|
||||||
|
u16 num_returned_task_ids = 0;
|
||||||
|
for (const auto& iter : task_id_list) {
|
||||||
|
const std::string current_task_id = iter.first;
|
||||||
|
if (current_task_id.size() > TASK_ID_SIZE || num_returned_task_ids >= num_task_ids) {
|
||||||
|
LOG_WARNING(Service_BOSS, "TaskId {} too long or too many TaskIds", current_task_id);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
std::memcpy(task_ids[num_returned_task_ids++].data(), current_task_id.data(), TASK_ID_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto* task_list_prop =
|
||||||
|
std::get_if<std::vector<u8>>(¤t_props.properties[PropertyID::TaskIdList]);
|
||||||
|
if (task_list_prop && task_list_prop->size() == TASKIDLIST_SIZE) {
|
||||||
|
std::memcpy(task_list_prop->data(), task_ids.data(), TASKIDLIST_SIZE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<FileSys::Entry> OnlineService::GetBossExtDataFiles() {
|
||||||
|
FileSys::ArchiveFactory_ExtSaveData boss_extdata_archive_factory(
|
||||||
|
FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir), FileSys::ExtSaveDataType::Boss);
|
||||||
|
const FileSys::Path boss_path{GetBossDataDir()};
|
||||||
|
auto archive_result = boss_extdata_archive_factory.Open(boss_path, 0);
|
||||||
|
if (!archive_result.Succeeded()) {
|
||||||
|
LOG_WARNING(Service_BOSS, "Extdata opening failed");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
auto boss_archive = std::move(archive_result).Unwrap();
|
||||||
|
auto dir_result = boss_archive->OpenDirectory("/");
|
||||||
|
if (!dir_result.Succeeded()) {
|
||||||
|
LOG_WARNING(Service_BOSS, "Extdata directory opening failed");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
auto dir = std::move(dir_result).Unwrap();
|
||||||
|
|
||||||
|
// Keep reading the directory 32 files at a time until all files have been checked
|
||||||
|
std::vector<FileSys::Entry> boss_files;
|
||||||
|
constexpr u32 files_to_read = 32;
|
||||||
|
u32 entry_count = 0;
|
||||||
|
std::size_t i = 0;
|
||||||
|
do {
|
||||||
|
boss_files.resize(boss_files.size() + files_to_read);
|
||||||
|
entry_count = dir->Read(files_to_read, boss_files.data() + (i++ * files_to_read));
|
||||||
|
} while (files_to_read <= entry_count);
|
||||||
|
|
||||||
|
boss_files.resize(i * files_to_read + entry_count);
|
||||||
|
return boss_files;
|
||||||
|
}
|
||||||
|
|
||||||
|
FileSys::Path OnlineService::GetBossDataDir() {
|
||||||
|
const u32 high = static_cast<u32>(extdata_id >> 32);
|
||||||
|
const u32 low = static_cast<u32>(extdata_id & 0xFFFFFFFF);
|
||||||
|
return FileSys::ConstructExtDataBinaryPath(1, high, low);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<NsDataEntry> OnlineService::GetNsDataEntries() {
|
||||||
|
FileSys::ArchiveFactory_ExtSaveData boss_extdata_archive_factory(
|
||||||
|
FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir), FileSys::ExtSaveDataType::Boss);
|
||||||
|
const FileSys::Path boss_path{GetBossDataDir()};
|
||||||
|
auto archive_result = boss_extdata_archive_factory.Open(boss_path, 0);
|
||||||
|
if (!archive_result.Succeeded()) {
|
||||||
|
LOG_WARNING(Service_BOSS, "Extdata opening failed");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
auto boss_archive = std::move(archive_result).Unwrap().get();
|
||||||
|
|
||||||
|
std::vector<NsDataEntry> ns_data;
|
||||||
|
std::vector<FileSys::Entry> boss_files = GetBossExtDataFiles();
|
||||||
|
for (const auto& current_file : boss_files) {
|
||||||
|
constexpr u32 boss_header_length = 0x34;
|
||||||
|
if (current_file.is_directory || current_file.file_size < boss_header_length) {
|
||||||
|
LOG_WARNING(Service_BOSS, "SpotPass extdata contains directory or file is too short");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
FileSys::Mode mode{};
|
||||||
|
mode.read_flag.Assign(1);
|
||||||
|
|
||||||
|
NsDataEntry entry{.filename = Common::UTF16ToUTF8(current_file.filename)};
|
||||||
|
auto file_result = boss_archive->OpenFile("/" + entry.filename, mode);
|
||||||
|
if (!file_result.Succeeded()) {
|
||||||
|
LOG_WARNING(Service_BOSS, "Opening SpotPass file failed.");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto file = std::move(file_result).Unwrap();
|
||||||
|
file->Read(0, boss_header_length, reinterpret_cast<u8*>(&entry.header));
|
||||||
|
if (entry.header.header_length != BOSS_EXTDATA_HEADER_LENGTH) {
|
||||||
|
LOG_WARNING(
|
||||||
|
Service_BOSS,
|
||||||
|
"Incorrect header length or non-SpotPass file; expected {:#010x}, found {:#010x}",
|
||||||
|
BOSS_EXTDATA_HEADER_LENGTH, entry.header.header_length);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entry.header.program_id != program_id) {
|
||||||
|
LOG_WARNING(Service_BOSS,
|
||||||
|
"Mismatched program ID in SpotPass data. Was expecting "
|
||||||
|
"{:#018x}, found {:#018x}",
|
||||||
|
program_id, static_cast<u64>(entry.header.program_id));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check the payload size is correct, excluding header
|
||||||
|
if (entry.header.payload_size != (current_file.file_size - boss_header_length)) {
|
||||||
|
LOG_WARNING(Service_BOSS,
|
||||||
|
"Mismatched file size, was expecting {:#010x}, found {:#010x}",
|
||||||
|
static_cast<u32>(entry.header.payload_size),
|
||||||
|
current_file.file_size - boss_header_length);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ns_data.push_back(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ns_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
u16 OnlineService::GetNsDataIdList(const u32 filter, const u32 max_entries,
|
||||||
|
Kernel::MappedBuffer& buffer) {
|
||||||
|
std::vector<NsDataEntry> ns_data = GetNsDataEntries();
|
||||||
|
std::vector<u32> output_entries;
|
||||||
|
for (const auto& current_entry : ns_data) {
|
||||||
|
const u32 datatype_raw = static_cast<u32>(current_entry.header.datatype);
|
||||||
|
const u16 datatype_high = static_cast<u16>(datatype_raw >> 16);
|
||||||
|
const u16 datatype_low = static_cast<u16>(datatype_raw & 0xFFFF);
|
||||||
|
const u16 filter_high = static_cast<u16>(filter >> 16);
|
||||||
|
const u16 filter_low = static_cast<u16>(filter & 0xFFFF);
|
||||||
|
if (filter != 0xFFFFFFFF &&
|
||||||
|
(filter_high != datatype_high || (filter_low & datatype_low) == 0)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (output_entries.size() >= max_entries) {
|
||||||
|
LOG_WARNING(Service_BOSS, "Reached maximum number of entries");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
output_entries.push_back(current_entry.header.ns_data_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer.Write(output_entries.data(), 0, sizeof(u32) * output_entries.size());
|
||||||
|
return static_cast<u16>(output_entries.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class... Ts>
|
||||||
|
struct overload : Ts... {
|
||||||
|
using Ts::operator()...;
|
||||||
|
};
|
||||||
|
template <class... Ts>
|
||||||
|
overload(Ts...) -> overload<Ts...>;
|
||||||
|
|
||||||
|
ResultCode OnlineService::SendProperty(const u16 id, const u32 size, Kernel::MappedBuffer& buffer) {
|
||||||
|
const auto property_id = static_cast<PropertyID>(id);
|
||||||
|
if (!current_props.properties.contains(property_id)) {
|
||||||
|
LOG_ERROR(Service_BOSS, "Unknown property with id {:#06x}", property_id);
|
||||||
|
return ResultCode(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto& prop = current_props.properties[property_id];
|
||||||
|
auto read_pod = [&]<typename T>(T& old_prop) {
|
||||||
|
static_assert(std::is_trivial<T>::value, "Only trivial types are allowed for read_pod");
|
||||||
|
if (size != sizeof(old_prop)) {
|
||||||
|
LOG_ERROR(Service_BOSS, "Unexpected size of property {:#06x}, was expecting {}, got {}",
|
||||||
|
property_id, sizeof(old_prop), size);
|
||||||
|
}
|
||||||
|
T cur_prop = 0;
|
||||||
|
buffer.Read(&cur_prop, 0, size);
|
||||||
|
prop = cur_prop;
|
||||||
|
};
|
||||||
|
|
||||||
|
auto read_vector = [&]<typename T>(std::vector<T>& old_prop) {
|
||||||
|
if (size != old_prop.size()) {
|
||||||
|
LOG_ERROR(Service_BOSS, "Unexpected size of property {:#06x}, was expecting {}, got {}",
|
||||||
|
property_id, old_prop.size(), size);
|
||||||
|
}
|
||||||
|
std::vector<T> cur_prop(size);
|
||||||
|
buffer.Read(cur_prop.data(), 0, size);
|
||||||
|
prop = cur_prop;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::visit(overload{[&](u8& cur_prop) { read_pod(cur_prop); },
|
||||||
|
[&](u16& cur_prop) { read_pod(cur_prop); },
|
||||||
|
[&](u32& cur_prop) { read_pod(cur_prop); },
|
||||||
|
[&](std::vector<u8>& cur_prop) { read_vector(cur_prop); },
|
||||||
|
[&](std::vector<u32>& cur_prop) { read_vector(cur_prop); }},
|
||||||
|
prop);
|
||||||
|
|
||||||
|
return RESULT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
ResultCode OnlineService::ReceiveProperty(const u16 id, const u32 size,
|
||||||
|
Kernel::MappedBuffer& buffer) {
|
||||||
|
const auto property_id = static_cast<PropertyID>(id);
|
||||||
|
if (!current_props.properties.contains(property_id)) {
|
||||||
|
LOG_ERROR(Service_BOSS, "Unknown property with id {:#06x}", property_id);
|
||||||
|
return ResultCode(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto write_pod = [&]<typename T>(T& cur_prop) {
|
||||||
|
static_assert(std::is_trivial<T>::value, "Only trivial types are allowed for write_pod");
|
||||||
|
if (size != sizeof(cur_prop)) {
|
||||||
|
LOG_ERROR(Service_BOSS, "Unexpected size of property {:#06x}, was expecting {}, got {}",
|
||||||
|
property_id, sizeof(cur_prop), size);
|
||||||
|
}
|
||||||
|
buffer.Write(&cur_prop, 0, size);
|
||||||
|
};
|
||||||
|
|
||||||
|
auto write_vector = [&]<typename T>(std::vector<T>& cur_prop) {
|
||||||
|
if (size != cur_prop.size()) {
|
||||||
|
LOG_ERROR(Service_BOSS, "Unexpected size of property {:#06x}, was expecting {}, got {}",
|
||||||
|
property_id, cur_prop.size(), size);
|
||||||
|
}
|
||||||
|
buffer.Write(cur_prop.data(), 0, size);
|
||||||
|
};
|
||||||
|
|
||||||
|
auto& prop = current_props.properties[property_id];
|
||||||
|
std::visit(overload{[&](u8& cur_prop) { write_pod(cur_prop); },
|
||||||
|
[&](u16& cur_prop) { write_pod(cur_prop); },
|
||||||
|
[&](u32& cur_prop) { write_pod(cur_prop); },
|
||||||
|
[&](std::vector<u8>& cur_prop) { write_vector(cur_prop); },
|
||||||
|
[&](std::vector<u32>& cur_prop) { write_vector(cur_prop); }},
|
||||||
|
prop);
|
||||||
|
|
||||||
|
return RESULT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Service::BOSS
|
169
src/core/hle/service/boss/online_service.h
Normal file
169
src/core/hle/service/boss/online_service.h
Normal file
@ -0,0 +1,169 @@
|
|||||||
|
// Copyright 2023 Citra Emulator Project
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <variant>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "common/common_types.h"
|
||||||
|
#include "core/hle/result.h"
|
||||||
|
#include "core/loader/loader.h"
|
||||||
|
|
||||||
|
namespace Kernel {
|
||||||
|
class MappedBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace FileSys {
|
||||||
|
struct Entry;
|
||||||
|
class Path;
|
||||||
|
} // namespace FileSys
|
||||||
|
|
||||||
|
namespace Service::BOSS {
|
||||||
|
|
||||||
|
constexpr u32 BOSS_PAYLOAD_HEADER_LENGTH = 0x28;
|
||||||
|
constexpr u32 BOSS_MAGIC = Loader::MakeMagic('b', 'o', 's', 's');
|
||||||
|
constexpr u32 BOSS_PAYLOAD_MAGIC = 0x10001;
|
||||||
|
constexpr u64 NEWS_PROG_ID = 0x0004013000003502;
|
||||||
|
|
||||||
|
constexpr u32 BOSS_CONTENT_HEADER_LENGTH = 0x132;
|
||||||
|
constexpr u32 BOSS_HEADER_WITH_HASH_LENGTH = 0x13C;
|
||||||
|
constexpr u32 BOSS_ENTIRE_HEADER_LENGTH = BOSS_CONTENT_HEADER_LENGTH + BOSS_HEADER_WITH_HASH_LENGTH;
|
||||||
|
constexpr u32 BOSS_EXTDATA_HEADER_LENGTH = 0x18;
|
||||||
|
constexpr u32 BOSS_S_ENTRY_SIZE = 0xC00;
|
||||||
|
constexpr u32 BOSS_SAVE_HEADER_SIZE = 4;
|
||||||
|
|
||||||
|
constexpr size_t TASK_ID_SIZE = 8;
|
||||||
|
constexpr size_t URL_SIZE = 0x200;
|
||||||
|
constexpr size_t HEADERS_SIZE = 0x360;
|
||||||
|
constexpr size_t CERTIDLIST_SIZE = 3;
|
||||||
|
constexpr size_t TASKIDLIST_SIZE = 0x400;
|
||||||
|
|
||||||
|
constexpr std::array<u8, 8> boss_system_savedata_id{
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x01, 0x00,
|
||||||
|
};
|
||||||
|
|
||||||
|
#pragma pack(push, 4)
|
||||||
|
struct BossHeader {
|
||||||
|
u8 header_length;
|
||||||
|
std::array<u8, 11> zero1;
|
||||||
|
u32_be unknown;
|
||||||
|
u32_be download_date;
|
||||||
|
std::array<u8, 4> zero2;
|
||||||
|
u64_be program_id;
|
||||||
|
std::array<u8, 4> zero3;
|
||||||
|
u32_be datatype;
|
||||||
|
u32_be payload_size;
|
||||||
|
u32_be ns_data_id;
|
||||||
|
u32_be version;
|
||||||
|
};
|
||||||
|
#pragma pack(pop)
|
||||||
|
static_assert(sizeof(BossHeader) == 0x34, "BossHeader has incorrect size");
|
||||||
|
|
||||||
|
struct NsDataEntry {
|
||||||
|
std::string filename;
|
||||||
|
BossHeader header;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class PropertyID : u16 {
|
||||||
|
Interval = 0x03,
|
||||||
|
Duration = 0x04,
|
||||||
|
Url = 0x07,
|
||||||
|
Headers = 0x0D,
|
||||||
|
CertId = 0x0E,
|
||||||
|
CertIdList = 0x0F,
|
||||||
|
LoadCert = 0x10,
|
||||||
|
LoadRootCert = 0x11,
|
||||||
|
TotalTasks = 0x35,
|
||||||
|
TaskIdList = 0x36,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct BossSVData {
|
||||||
|
INSERT_PADDING_BYTES(0x10);
|
||||||
|
u64 program_id;
|
||||||
|
std::array<char, TASK_ID_SIZE> task_id;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct BossSSData {
|
||||||
|
INSERT_PADDING_BYTES(0x21C);
|
||||||
|
std::array<u8, URL_SIZE> url;
|
||||||
|
};
|
||||||
|
|
||||||
|
using BossTaskProperty = std::variant<u8, u16, u32, std::vector<u8>, std::vector<u32>>;
|
||||||
|
struct BossTaskProperties {
|
||||||
|
bool task_result;
|
||||||
|
std::map<PropertyID, BossTaskProperty> properties{
|
||||||
|
{static_cast<PropertyID>(0x00), u8()},
|
||||||
|
{static_cast<PropertyID>(0x01), u8()},
|
||||||
|
{static_cast<PropertyID>(0x02), u32()},
|
||||||
|
{PropertyID::Interval, u32()},
|
||||||
|
{PropertyID::Duration, u32()},
|
||||||
|
{static_cast<PropertyID>(0x05), u8()},
|
||||||
|
{static_cast<PropertyID>(0x06), u8()},
|
||||||
|
{PropertyID::Url, std::vector<u8>(URL_SIZE)},
|
||||||
|
{static_cast<PropertyID>(0x08), u32()},
|
||||||
|
{static_cast<PropertyID>(0x09), u8()},
|
||||||
|
{static_cast<PropertyID>(0x0A), std::vector<u8>(0x100)},
|
||||||
|
{static_cast<PropertyID>(0x0B), std::vector<u8>(0x200)},
|
||||||
|
{static_cast<PropertyID>(0x0C), u32()},
|
||||||
|
{PropertyID::Headers, std::vector<u8>(HEADERS_SIZE)},
|
||||||
|
{PropertyID::CertId, u32()},
|
||||||
|
{PropertyID::CertIdList, std::vector<u32>(CERTIDLIST_SIZE)},
|
||||||
|
{PropertyID::LoadCert, u8()},
|
||||||
|
{PropertyID::LoadRootCert, u8()},
|
||||||
|
{static_cast<PropertyID>(0x12), u8()},
|
||||||
|
{static_cast<PropertyID>(0x13), u32()},
|
||||||
|
{static_cast<PropertyID>(0x14), u32()},
|
||||||
|
{static_cast<PropertyID>(0x15), std::vector<u8>(0x40)},
|
||||||
|
{static_cast<PropertyID>(0x16), u32()},
|
||||||
|
{static_cast<PropertyID>(0x18), u8()},
|
||||||
|
{static_cast<PropertyID>(0x19), u8()},
|
||||||
|
{static_cast<PropertyID>(0x1A), u8()},
|
||||||
|
{static_cast<PropertyID>(0x1B), u32()},
|
||||||
|
{static_cast<PropertyID>(0x1C), u32()},
|
||||||
|
{PropertyID::TotalTasks, u16()},
|
||||||
|
{PropertyID::TaskIdList, std::vector<u8>(TASKIDLIST_SIZE)},
|
||||||
|
{static_cast<PropertyID>(0x3B), u32()},
|
||||||
|
{static_cast<PropertyID>(0x3E), std::vector<u8>(0x200)},
|
||||||
|
{static_cast<PropertyID>(0x3F), u8()},
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class Archive>
|
||||||
|
void serialize(Archive& ar, const unsigned int);
|
||||||
|
friend class boost::serialization::access;
|
||||||
|
};
|
||||||
|
|
||||||
|
class OnlineService final {
|
||||||
|
public:
|
||||||
|
explicit OnlineService(u64 program_id_, u64 extdata_id_);
|
||||||
|
|
||||||
|
ResultCode InitializeSession(u64 init_program_id);
|
||||||
|
void RegisterTask(const u32 size, Kernel::MappedBuffer& buffer);
|
||||||
|
ResultCode UnregisterTask(const u32 size, Kernel::MappedBuffer& buffer);
|
||||||
|
void GetTaskIdList();
|
||||||
|
u16 GetNsDataIdList(const u32 filter, const u32 max_entries, Kernel::MappedBuffer& buffer);
|
||||||
|
ResultCode SendProperty(const u16 id, const u32 size, Kernel::MappedBuffer& buffer);
|
||||||
|
ResultCode ReceiveProperty(const u16 id, const u32 size, Kernel::MappedBuffer& buffer);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<FileSys::Entry> GetBossExtDataFiles();
|
||||||
|
FileSys::Path GetBossDataDir();
|
||||||
|
std::vector<NsDataEntry> GetNsDataEntries();
|
||||||
|
|
||||||
|
BossTaskProperties current_props;
|
||||||
|
std::map<std::string, BossTaskProperties> task_id_list;
|
||||||
|
|
||||||
|
u64 program_id;
|
||||||
|
u64 extdata_id;
|
||||||
|
|
||||||
|
// For serialization
|
||||||
|
explicit OnlineService() = default;
|
||||||
|
|
||||||
|
template <class Archive>
|
||||||
|
void serialize(Archive& ar, const unsigned int);
|
||||||
|
friend class boost::serialization::access;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Service::BOSS
|
@ -334,6 +334,24 @@ void FS_USER::OpenArchive(Kernel::HLERequestContext& ctx) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FS_USER::ControlArchive(Kernel::HLERequestContext& ctx) {
|
||||||
|
IPC::RequestParser rp(ctx);
|
||||||
|
const auto archive_handle = rp.PopRaw<ArchiveHandle>();
|
||||||
|
const auto action = rp.Pop<u32>();
|
||||||
|
const auto input_size = rp.Pop<u32>();
|
||||||
|
const auto output_size = rp.Pop<u32>();
|
||||||
|
[[maybe_unused]] const auto input = rp.PopMappedBuffer();
|
||||||
|
[[maybe_unused]] const auto output = rp.PopMappedBuffer();
|
||||||
|
|
||||||
|
LOG_WARNING(Service_FS,
|
||||||
|
"(STUBBED) called, archive_handle={:016X}, action={:08X}, input_size={:08X}, "
|
||||||
|
"output_size={:08X}",
|
||||||
|
archive_handle, action, input_size, output_size);
|
||||||
|
|
||||||
|
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
||||||
|
rb.Push(RESULT_SUCCESS);
|
||||||
|
}
|
||||||
|
|
||||||
void FS_USER::CloseArchive(Kernel::HLERequestContext& ctx) {
|
void FS_USER::CloseArchive(Kernel::HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp(ctx);
|
IPC::RequestParser rp(ctx);
|
||||||
const auto archive_handle = rp.PopRaw<ArchiveHandle>();
|
const auto archive_handle = rp.PopRaw<ArchiveHandle>();
|
||||||
@ -1010,7 +1028,7 @@ FS_USER::FS_USER(Core::System& system)
|
|||||||
{0x080A, &FS_USER::RenameDirectory, "RenameDirectory"},
|
{0x080A, &FS_USER::RenameDirectory, "RenameDirectory"},
|
||||||
{0x080B, &FS_USER::OpenDirectory, "OpenDirectory"},
|
{0x080B, &FS_USER::OpenDirectory, "OpenDirectory"},
|
||||||
{0x080C, &FS_USER::OpenArchive, "OpenArchive"},
|
{0x080C, &FS_USER::OpenArchive, "OpenArchive"},
|
||||||
{0x080D, nullptr, "ControlArchive"},
|
{0x080D, &FS_USER::ControlArchive, "ControlArchive"},
|
||||||
{0x080E, &FS_USER::CloseArchive, "CloseArchive"},
|
{0x080E, &FS_USER::CloseArchive, "CloseArchive"},
|
||||||
{0x080F, &FS_USER::FormatThisUserSaveData, "FormatThisUserSaveData"},
|
{0x080F, &FS_USER::FormatThisUserSaveData, "FormatThisUserSaveData"},
|
||||||
{0x0810, &FS_USER::CreateLegacySystemSaveData, "CreateLegacySystemSaveData"},
|
{0x0810, &FS_USER::CreateLegacySystemSaveData, "CreateLegacySystemSaveData"},
|
||||||
|
@ -262,6 +262,22 @@ private:
|
|||||||
*/
|
*/
|
||||||
void OpenArchive(Kernel::HLERequestContext& ctx);
|
void OpenArchive(Kernel::HLERequestContext& ctx);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FS_User::ControlArchive service function
|
||||||
|
* Inputs:
|
||||||
|
* 1-2 : Archive Handle
|
||||||
|
* 3 : Action
|
||||||
|
* 4 : Input Size
|
||||||
|
* 5 : Output Size
|
||||||
|
* 6 : (Input Size << 4) | 0xA
|
||||||
|
* 7 : Input Pointer
|
||||||
|
* 8 : (Output Size << 4) | 0xC
|
||||||
|
* 9 : Output Pointer
|
||||||
|
* Outputs:
|
||||||
|
* 1 : Result of function, 0 on success, otherwise error code
|
||||||
|
*/
|
||||||
|
void ControlArchive(Kernel::HLERequestContext& ctx);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* FS_User::CloseArchive service function
|
* FS_User::CloseArchive service function
|
||||||
* Inputs:
|
* Inputs:
|
||||||
|
@ -97,10 +97,8 @@ struct FrameBufferUpdate {
|
|||||||
static_assert(sizeof(FrameBufferUpdate) == 0x40, "Struct has incorrect size");
|
static_assert(sizeof(FrameBufferUpdate) == 0x40, "Struct has incorrect size");
|
||||||
// TODO: Not sure if this padding is correct.
|
// TODO: Not sure if this padding is correct.
|
||||||
// Chances are the second block is stored at offset 0x24 rather than 0x20.
|
// Chances are the second block is stored at offset 0x24 rather than 0x20.
|
||||||
#ifndef _MSC_VER
|
|
||||||
static_assert(offsetof(FrameBufferUpdate, framebuffer_info[1]) == 0x20,
|
static_assert(offsetof(FrameBufferUpdate, framebuffer_info[1]) == 0x20,
|
||||||
"FrameBufferInfo element has incorrect alignment");
|
"FrameBufferInfo element has incorrect alignment");
|
||||||
#endif
|
|
||||||
|
|
||||||
/// GSP command
|
/// GSP command
|
||||||
struct Command {
|
struct Command {
|
||||||
|
@ -64,22 +64,14 @@ private:
|
|||||||
};
|
};
|
||||||
static_assert(std::is_standard_layout<Regs>::value, "Structure does not use standard layout");
|
static_assert(std::is_standard_layout<Regs>::value, "Structure does not use standard layout");
|
||||||
|
|
||||||
// TODO: MSVC does not support using offsetof() on non-static data members even though this
|
|
||||||
// is technically allowed since C++11. This macro should be enabled once MSVC adds
|
|
||||||
// support for that.
|
|
||||||
#ifndef _MSC_VER
|
|
||||||
#define ASSERT_REG_POSITION(field_name, position) \
|
#define ASSERT_REG_POSITION(field_name, position) \
|
||||||
static_assert(offsetof(Regs, field_name) == position * 4, \
|
static_assert(offsetof(Regs, field_name) == position * 4, \
|
||||||
"Field " #field_name " has invalid position")
|
"Field " #field_name " has invalid position")
|
||||||
|
|
||||||
ASSERT_REG_POSITION(color_fill_top, 0x81);
|
ASSERT_REG_POSITION(color_fill_top, 0x81);
|
||||||
ASSERT_REG_POSITION(backlight_top, 0x90);
|
ASSERT_REG_POSITION(backlight_top, 0x90);
|
||||||
ASSERT_REG_POSITION(color_fill_bottom, 0x281);
|
ASSERT_REG_POSITION(color_fill_bottom, 0x281);
|
||||||
ASSERT_REG_POSITION(backlight_bottom, 0x290);
|
ASSERT_REG_POSITION(backlight_bottom, 0x290);
|
||||||
|
|
||||||
#undef ASSERT_REG_POSITION
|
|
||||||
#endif // !defined(_MSC_VER)
|
|
||||||
|
|
||||||
extern Regs g_regs;
|
extern Regs g_regs;
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
|
@ -198,7 +198,27 @@ BlitHelper::BlitHelper(const Instance& instance_, Scheduler& scheduler_, Descrip
|
|||||||
MakeComputePipeline(depth_to_buffer_comp, compute_buffer_pipeline_layout)},
|
MakeComputePipeline(depth_to_buffer_comp, compute_buffer_pipeline_layout)},
|
||||||
depth_blit_pipeline{MakeDepthStencilBlitPipeline()},
|
depth_blit_pipeline{MakeDepthStencilBlitPipeline()},
|
||||||
linear_sampler{device.createSampler(SAMPLER_CREATE_INFO<vk::Filter::eLinear>)},
|
linear_sampler{device.createSampler(SAMPLER_CREATE_INFO<vk::Filter::eLinear>)},
|
||||||
nearest_sampler{device.createSampler(SAMPLER_CREATE_INFO<vk::Filter::eNearest>)} {}
|
nearest_sampler{device.createSampler(SAMPLER_CREATE_INFO<vk::Filter::eNearest>)} {
|
||||||
|
|
||||||
|
if (instance.HasDebuggingToolAttached()) {
|
||||||
|
SetObjectName(device, compute_pipeline_layout, "BlitHelper: compute_pipeline_layout");
|
||||||
|
SetObjectName(device, compute_buffer_pipeline_layout,
|
||||||
|
"BlitHelper: compute_buffer_pipeline_layout");
|
||||||
|
SetObjectName(device, two_textures_pipeline_layout,
|
||||||
|
"BlitHelper: two_textures_pipeline_layout");
|
||||||
|
SetObjectName(device, full_screen_vert, "BlitHelper: full_screen_vert");
|
||||||
|
SetObjectName(device, d24s8_to_rgba8_comp, "BlitHelper: d24s8_to_rgba8_comp");
|
||||||
|
SetObjectName(device, depth_to_buffer_comp, "BlitHelper: depth_to_buffer_comp");
|
||||||
|
SetObjectName(device, blit_depth_stencil_frag, "BlitHelper: blit_depth_stencil_frag");
|
||||||
|
SetObjectName(device, d24s8_to_rgba8_pipeline, "BlitHelper: d24s8_to_rgba8_pipeline");
|
||||||
|
SetObjectName(device, depth_to_buffer_pipeline, "BlitHelper: depth_to_buffer_pipeline");
|
||||||
|
if (depth_blit_pipeline) {
|
||||||
|
SetObjectName(device, depth_blit_pipeline, "BlitHelper: depth_blit_pipeline");
|
||||||
|
}
|
||||||
|
SetObjectName(device, linear_sampler, "BlitHelper: linear_sampler");
|
||||||
|
SetObjectName(device, nearest_sampler, "BlitHelper: nearest_sampler");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
BlitHelper::~BlitHelper() {
|
BlitHelper::~BlitHelper() {
|
||||||
device.destroyPipelineLayout(compute_pipeline_layout);
|
device.destroyPipelineLayout(compute_pipeline_layout);
|
||||||
|
@ -33,4 +33,24 @@ vk::UniqueInstance CreateInstance(const Common::DynamicLibrary& library,
|
|||||||
|
|
||||||
DebugCallback CreateDebugCallback(vk::Instance instance, bool& debug_utils_supported);
|
DebugCallback CreateDebugCallback(vk::Instance instance, bool& debug_utils_supported);
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
concept VulkanHandleType = vk::isVulkanHandleType<T>::value;
|
||||||
|
|
||||||
|
template <VulkanHandleType HandleType>
|
||||||
|
void SetObjectName(vk::Device device, const HandleType& handle, std::string_view debug_name) {
|
||||||
|
const vk::DebugUtilsObjectNameInfoEXT name_info = {
|
||||||
|
.objectType = HandleType::objectType,
|
||||||
|
.objectHandle = reinterpret_cast<u64>(static_cast<typename HandleType::NativeType>(handle)),
|
||||||
|
.pObjectName = debug_name.data(),
|
||||||
|
};
|
||||||
|
device.setDebugUtilsObjectNameEXT(name_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <VulkanHandleType HandleType, typename... Args>
|
||||||
|
void SetObjectName(vk::Device device, const HandleType& handle, const char* format,
|
||||||
|
const Args&... args) {
|
||||||
|
const std::string debug_name = fmt::vformat(format, fmt::make_format_args(args...));
|
||||||
|
SetObjectName(device, handle, debug_name);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Vulkan
|
} // namespace Vulkan
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
#include "video_core/renderer_vulkan/vk_present_window.h"
|
#include "video_core/renderer_vulkan/vk_present_window.h"
|
||||||
#include "video_core/renderer_vulkan/vk_scheduler.h"
|
#include "video_core/renderer_vulkan/vk_scheduler.h"
|
||||||
#include "video_core/renderer_vulkan/vk_swapchain.h"
|
#include "video_core/renderer_vulkan/vk_swapchain.h"
|
||||||
|
#include "vk_platform.h"
|
||||||
|
|
||||||
#include <vk_mem_alloc.h>
|
#include <vk_mem_alloc.h>
|
||||||
|
|
||||||
@ -135,6 +136,16 @@ PresentWindow::PresentWindow(Frontend::EmuWindow& emu_window_, const Instance& i
|
|||||||
free_queue.push(&frame);
|
free_queue.push(&frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (instance.HasDebuggingToolAttached()) {
|
||||||
|
for (u32 i = 0; i < num_images; ++i) {
|
||||||
|
Vulkan::SetObjectName(device, swap_chain[i].cmdbuf, "Swapchain Command Buffer {}", i);
|
||||||
|
Vulkan::SetObjectName(device, swap_chain[i].render_ready,
|
||||||
|
"Swapchain Semaphore: render_ready {}", i);
|
||||||
|
Vulkan::SetObjectName(device, swap_chain[i].present_done,
|
||||||
|
"Swapchain Fence: present_done {}", i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (use_present_thread) {
|
if (use_present_thread) {
|
||||||
present_thread = std::jthread([this](std::stop_token token) { PresentThread(token); });
|
present_thread = std::jthread([this](std::stop_token token) { PresentThread(token); });
|
||||||
}
|
}
|
||||||
|
@ -101,6 +101,15 @@ void CommandPool::Allocate(std::size_t begin, std::size_t end) {
|
|||||||
|
|
||||||
auto buffers = device.allocateCommandBuffers(buffer_alloc_info);
|
auto buffers = device.allocateCommandBuffers(buffer_alloc_info);
|
||||||
std::copy(buffers.begin(), buffers.end(), pool.cmdbufs.begin());
|
std::copy(buffers.begin(), buffers.end(), pool.cmdbufs.begin());
|
||||||
|
|
||||||
|
if (instance.HasDebuggingToolAttached()) {
|
||||||
|
Vulkan::SetObjectName(device, pool.handle, "CommandPool: Pool({})",
|
||||||
|
COMMAND_BUFFER_POOL_SIZE);
|
||||||
|
|
||||||
|
for (u32 i = 0; i < pool.cmdbufs.size(); ++i) {
|
||||||
|
Vulkan::SetObjectName(device, pool.cmdbufs[i], "CommandPool: Command Buffer {}", i);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
vk::CommandBuffer CommandPool::Commit() {
|
vk::CommandBuffer CommandPool::Commit() {
|
||||||
|
@ -173,7 +173,7 @@ void StreamBuffer::CreateBuffers(u64 prefered_size) {
|
|||||||
|
|
||||||
stream_buffer_size = static_cast<u64>(requirements.memoryRequirements.size);
|
stream_buffer_size = static_cast<u64>(requirements.memoryRequirements.size);
|
||||||
|
|
||||||
LOG_INFO(Render_Vulkan, "Creating {} buffer with size {} KB with flags {}",
|
LOG_INFO(Render_Vulkan, "Creating {} buffer with size {} KiB with flags {}",
|
||||||
BufferTypeName(type), stream_buffer_size / 1024,
|
BufferTypeName(type), stream_buffer_size / 1024,
|
||||||
vk::to_string(mem_type.propertyFlags));
|
vk::to_string(mem_type.propertyFlags));
|
||||||
|
|
||||||
@ -198,6 +198,14 @@ void StreamBuffer::CreateBuffers(u64 prefered_size) {
|
|||||||
|
|
||||||
device.bindBufferMemory(buffer, memory, 0);
|
device.bindBufferMemory(buffer, memory, 0);
|
||||||
mapped = reinterpret_cast<u8*>(device.mapMemory(memory, 0, VK_WHOLE_SIZE));
|
mapped = reinterpret_cast<u8*>(device.mapMemory(memory, 0, VK_WHOLE_SIZE));
|
||||||
|
|
||||||
|
if (instance.HasDebuggingToolAttached()) {
|
||||||
|
Vulkan::SetObjectName(device, buffer, "StreamBuffer({}): {} KiB {}", BufferTypeName(type),
|
||||||
|
stream_buffer_size / 1024, vk::to_string(mem_type.propertyFlags));
|
||||||
|
Vulkan::SetObjectName(device, memory, "StreamBufferMemory({}): {} Kib {}",
|
||||||
|
BufferTypeName(type), stream_buffer_size / 1024,
|
||||||
|
vk::to_string(mem_type.propertyFlags));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void StreamBuffer::ReserveWatches(std::vector<Watch>& watches, std::size_t grow_size) {
|
void StreamBuffer::ReserveWatches(std::vector<Watch>& watches, std::size_t grow_size) {
|
||||||
|
@ -247,12 +247,27 @@ void Swapchain::RefreshSemaphores() {
|
|||||||
for (vk::Semaphore& semaphore : present_ready) {
|
for (vk::Semaphore& semaphore : present_ready) {
|
||||||
semaphore = device.createSemaphore({});
|
semaphore = device.createSemaphore({});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (instance.HasDebuggingToolAttached()) {
|
||||||
|
for (u32 i = 0; i < image_count; ++i) {
|
||||||
|
Vulkan::SetObjectName(device, image_acquired[i],
|
||||||
|
"Swapchain Semaphore: image_acquired {}", i);
|
||||||
|
Vulkan::SetObjectName(device, present_ready[i], "Swapchain Semaphore: present_ready {}",
|
||||||
|
i);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Swapchain::SetupImages() {
|
void Swapchain::SetupImages() {
|
||||||
vk::Device device = instance.GetDevice();
|
vk::Device device = instance.GetDevice();
|
||||||
images = device.getSwapchainImagesKHR(swapchain);
|
images = device.getSwapchainImagesKHR(swapchain);
|
||||||
image_count = static_cast<u32>(images.size());
|
image_count = static_cast<u32>(images.size());
|
||||||
|
|
||||||
|
if (instance.HasDebuggingToolAttached()) {
|
||||||
|
for (u32 i = 0; i < image_count; ++i) {
|
||||||
|
Vulkan::SetObjectName(device, images[i], "Swapchain Image {}", i);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Vulkan
|
} // namespace Vulkan
|
||||||
|
@ -189,15 +189,6 @@ Handle MakeHandle(const Instance* instance, u32 width, u32 height, u32 levels, T
|
|||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!debug_name.empty() && instance->HasDebuggingToolAttached()) {
|
|
||||||
const vk::DebugUtilsObjectNameInfoEXT name_info = {
|
|
||||||
.objectType = vk::ObjectType::eImage,
|
|
||||||
.objectHandle = reinterpret_cast<u64>(unsafe_image),
|
|
||||||
.pObjectName = debug_name.data(),
|
|
||||||
};
|
|
||||||
instance->GetDevice().setDebugUtilsObjectNameEXT(name_info);
|
|
||||||
}
|
|
||||||
|
|
||||||
const vk::Image image{unsafe_image};
|
const vk::Image image{unsafe_image};
|
||||||
const vk::ImageViewCreateInfo view_info = {
|
const vk::ImageViewCreateInfo view_info = {
|
||||||
.image = image,
|
.image = image,
|
||||||
@ -214,6 +205,12 @@ Handle MakeHandle(const Instance* instance, u32 width, u32 height, u32 levels, T
|
|||||||
};
|
};
|
||||||
vk::UniqueImageView image_view = instance->GetDevice().createImageViewUnique(view_info);
|
vk::UniqueImageView image_view = instance->GetDevice().createImageViewUnique(view_info);
|
||||||
|
|
||||||
|
if (!debug_name.empty() && instance->HasDebuggingToolAttached()) {
|
||||||
|
Vulkan::SetObjectName(instance->GetDevice(), image, debug_name);
|
||||||
|
Vulkan::SetObjectName(instance->GetDevice(), image_view.get(), "{} View({})", debug_name,
|
||||||
|
vk::to_string(aspect));
|
||||||
|
}
|
||||||
|
|
||||||
return Handle{
|
return Handle{
|
||||||
.alloc = allocation,
|
.alloc = allocation,
|
||||||
.image = image,
|
.image = image,
|
||||||
|
Reference in New Issue
Block a user