Compare commits
89 Commits
__refs_pul
...
__refs_pul
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cc4521fc70 | ||
|
|
f058de337e | ||
|
|
f271316822 | ||
|
|
dace6087d6 | ||
|
|
3d627df4d8 | ||
|
|
9662ca918d | ||
|
|
a2cc3b10bb | ||
|
|
94fce28010 | ||
|
|
94e8dfc0c7 | ||
|
|
932fbd5a25 | ||
|
|
7d544c1b9d | ||
|
|
f7a1827aaa | ||
|
|
7c4fb09a7c | ||
|
|
d01bf170c4 | ||
|
|
e23543918b | ||
|
|
69a9bd8187 | ||
|
|
e65966bcfc | ||
|
|
67ff974387 | ||
|
|
b6b78203cc | ||
|
|
0d673a84b6 | ||
|
|
54c2a4cafc | ||
|
|
69b3f98d3a | ||
|
|
d57e00801d | ||
|
|
0b1842294f | ||
|
|
c267aea29b | ||
|
|
f1969ee1f3 | ||
|
|
24dfb43ac6 | ||
|
|
3135dbc29c | ||
|
|
c4b5319446 | ||
|
|
d77af9f8fd | ||
|
|
cb5b68cb0a | ||
|
|
f820e58be4 | ||
|
|
c9ac23683b | ||
|
|
bee5a7acb1 | ||
|
|
b358e88512 | ||
|
|
50d2abaaa9 | ||
|
|
af159a4d08 | ||
|
|
e633021532 | ||
|
|
232d95b56e | ||
|
|
033b46253e | ||
|
|
5a6dc4d041 | ||
|
|
0e6a608245 | ||
|
|
1bf5a337a5 | ||
|
|
b84f4cfb62 | ||
|
|
f0d3f1b376 | ||
|
|
f926559ef4 | ||
|
|
93f7677402 | ||
|
|
756e773096 | ||
|
|
02602afd10 | ||
|
|
d6583d68f6 | ||
|
|
1d555fdd25 | ||
|
|
8b27e73bd7 | ||
|
|
699900eed0 | ||
|
|
74eb16521f | ||
|
|
8a5e6fce07 | ||
|
|
864cbbaf4c | ||
|
|
0e35f1bb18 | ||
|
|
568bcbc29d | ||
|
|
f5ce71793e | ||
|
|
ec38b4e883 | ||
|
|
61586e8794 | ||
|
|
4a6a9b6622 | ||
|
|
d4012a4540 | ||
|
|
7f10db1c20 | ||
|
|
bb175ab430 | ||
|
|
8cdb48224d | ||
|
|
81e14c072a | ||
|
|
0368260c99 | ||
|
|
377c60645c | ||
|
|
0a9fedfac9 | ||
|
|
3533d33ff5 | ||
|
|
423a3ed2c8 | ||
|
|
bb893188eb | ||
|
|
54e74b3572 | ||
|
|
da6d4cde56 | ||
|
|
17d8e25cbf | ||
|
|
cfbae58b2b | ||
|
|
73b7748984 | ||
|
|
8b4b560df5 | ||
|
|
dd254c603d | ||
|
|
4dcdd3a837 | ||
|
|
3fa2b218ac | ||
|
|
fe2609cb77 | ||
|
|
eb36463e03 | ||
|
|
c3becdbca7 | ||
|
|
60fecee1ec | ||
|
|
9359655712 | ||
|
|
af42320021 | ||
|
|
0080a8da58 |
3
.gitmodules
vendored
3
.gitmodules
vendored
@@ -13,9 +13,6 @@
|
||||
[submodule "dynarmic"]
|
||||
path = externals/dynarmic
|
||||
url = https://github.com/MerryMage/dynarmic.git
|
||||
[submodule "xbyak"]
|
||||
path = externals/xbyak
|
||||
url = https://github.com/herumi/xbyak.git
|
||||
[submodule "fmt"]
|
||||
path = externals/fmt
|
||||
url = https://github.com/fmtlib/fmt.git
|
||||
|
||||
@@ -377,7 +377,7 @@ if (CLANG_FORMAT)
|
||||
set(CCOMMENT "Running clang format against all the .h and .cpp files in src/")
|
||||
if (WIN32)
|
||||
add_custom_target(clang-format
|
||||
COMMAND powershell.exe -Command "${CLANG_FORMAT} -i @(Get-ChildItem -Recurse ${SRCS}/* -Include \'*.h\', \'*.cpp\')"
|
||||
COMMAND powershell.exe -Command "Get-ChildItem ${SRCS}/* -Include *.cpp,*.h -Recurse | Foreach {${CLANG_FORMAT} -i $_.fullname}"
|
||||
COMMENT ${CCOMMENT})
|
||||
elseif(MINGW)
|
||||
add_custom_target(clang-format
|
||||
|
||||
9
externals/CMakeLists.txt
vendored
9
externals/CMakeLists.txt
vendored
@@ -9,7 +9,6 @@ target_include_directories(catch-single-include INTERFACE catch/single_include)
|
||||
|
||||
# Dynarmic
|
||||
if (ARCHITECTURE_x86_64)
|
||||
add_library(xbyak INTERFACE)
|
||||
set(DYNARMIC_TESTS OFF)
|
||||
set(DYNARMIC_NO_BUNDLED_FMT ON)
|
||||
add_subdirectory(dynarmic)
|
||||
@@ -53,14 +52,6 @@ target_include_directories(unicorn-headers INTERFACE ./unicorn/include)
|
||||
# SoundTouch
|
||||
add_subdirectory(soundtouch)
|
||||
|
||||
# Xbyak
|
||||
if (ARCHITECTURE_x86_64)
|
||||
# Defined before "dynarmic" above
|
||||
# add_library(xbyak INTERFACE)
|
||||
target_include_directories(xbyak INTERFACE ./xbyak/xbyak)
|
||||
target_compile_definitions(xbyak INTERFACE XBYAK_NO_OP_NAMES)
|
||||
endif()
|
||||
|
||||
# Opus
|
||||
add_subdirectory(opus)
|
||||
target_include_directories(opus INTERFACE ./opus/include)
|
||||
|
||||
2390
externals/glad/include/glad/glad.h
vendored
2390
externals/glad/include/glad/glad.h
vendored
File diff suppressed because one or more lines are too long
2549
externals/glad/src/glad.c
vendored
2549
externals/glad/src/glad.c
vendored
File diff suppressed because one or more lines are too long
1
externals/xbyak
vendored
1
externals/xbyak
vendored
Submodule externals/xbyak deleted from 1de435ed04
@@ -44,7 +44,6 @@ add_library(common STATIC
|
||||
detached_tasks.cpp
|
||||
detached_tasks.h
|
||||
bit_field.h
|
||||
bit_set.h
|
||||
cityhash.cpp
|
||||
cityhash.h
|
||||
color.h
|
||||
@@ -95,14 +94,9 @@ if(ARCHITECTURE_x86_64)
|
||||
PRIVATE
|
||||
x64/cpu_detect.cpp
|
||||
x64/cpu_detect.h
|
||||
x64/xbyak_abi.h
|
||||
x64/xbyak_util.h
|
||||
)
|
||||
endif()
|
||||
|
||||
create_target_directory_groups(common)
|
||||
|
||||
target_link_libraries(common PUBLIC Boost::boost fmt microprofile)
|
||||
if (ARCHITECTURE_x86_64)
|
||||
target_link_libraries(common PRIVATE xbyak)
|
||||
endif()
|
||||
|
||||
@@ -1,244 +0,0 @@
|
||||
// This file is under the public domain.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#ifdef _WIN32
|
||||
#include <intrin.h>
|
||||
#endif
|
||||
#include <initializer_list>
|
||||
#include <new>
|
||||
#include <type_traits>
|
||||
#include "common/common_types.h"
|
||||
|
||||
// namespace avoids conflict with OS X Carbon; don't use BitSet<T> directly
|
||||
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.
|
||||
// using the set bits of an integer to represent a set of integers. Like that
|
||||
// class, it acts like an array of bools:
|
||||
// BitSet32 bs;
|
||||
// bs[1] = true;
|
||||
// but also like the underlying integer ([0] = least significant bit):
|
||||
// BitSet32 bs2 = ...;
|
||||
// bs = (bs ^ bs2) & BitSet32(0xffff);
|
||||
// The following additional functionality is provided:
|
||||
// - Construction using an initializer list.
|
||||
// BitSet bs { 1, 2, 4, 8 };
|
||||
// - Efficiently iterating through the set bits:
|
||||
// for (int i : bs)
|
||||
// [i is the *index* of a set bit]
|
||||
// (This uses the appropriate CPU instruction to find the next set bit in one
|
||||
// operation.)
|
||||
// - Counting set bits using .Count() - see comment on that method.
|
||||
|
||||
// TODO: use constexpr when MSVC gets out of the Dark Ages
|
||||
|
||||
template <typename IntTy>
|
||||
class BitSet {
|
||||
static_assert(!std::is_signed_v<IntTy>, "BitSet should not be used with signed types");
|
||||
|
||||
public:
|
||||
// A reference to a particular bit, returned from operator[].
|
||||
class Ref {
|
||||
public:
|
||||
Ref(Ref&& other) : m_bs(other.m_bs), m_mask(other.m_mask) {}
|
||||
Ref(BitSet* bs, IntTy mask) : m_bs(bs), m_mask(mask) {}
|
||||
operator bool() const {
|
||||
return (m_bs->m_val & m_mask) != 0;
|
||||
}
|
||||
bool operator=(bool set) {
|
||||
m_bs->m_val = (m_bs->m_val & ~m_mask) | (set ? m_mask : 0);
|
||||
return set;
|
||||
}
|
||||
|
||||
private:
|
||||
BitSet* m_bs;
|
||||
IntTy m_mask;
|
||||
};
|
||||
|
||||
// A STL-like iterator is required to be able to use range-based for loops.
|
||||
class Iterator {
|
||||
public:
|
||||
Iterator(const Iterator& other) : m_val(other.m_val), m_bit(other.m_bit) {}
|
||||
Iterator(IntTy val) : m_val(val), m_bit(0) {}
|
||||
Iterator& operator=(Iterator other) {
|
||||
new (this) Iterator(other);
|
||||
return *this;
|
||||
}
|
||||
int operator*() {
|
||||
return m_bit + ComputeLsb();
|
||||
}
|
||||
Iterator& operator++() {
|
||||
int lsb = ComputeLsb();
|
||||
m_val >>= lsb + 1;
|
||||
m_bit += lsb + 1;
|
||||
m_has_lsb = false;
|
||||
return *this;
|
||||
}
|
||||
Iterator operator++(int _) {
|
||||
Iterator other(*this);
|
||||
++*this;
|
||||
return other;
|
||||
}
|
||||
bool operator==(Iterator other) const {
|
||||
return m_val == other.m_val;
|
||||
}
|
||||
bool operator!=(Iterator other) const {
|
||||
return m_val != other.m_val;
|
||||
}
|
||||
|
||||
private:
|
||||
int ComputeLsb() {
|
||||
if (!m_has_lsb) {
|
||||
m_lsb = LeastSignificantSetBit(m_val);
|
||||
m_has_lsb = true;
|
||||
}
|
||||
return m_lsb;
|
||||
}
|
||||
IntTy m_val;
|
||||
int m_bit;
|
||||
int m_lsb = -1;
|
||||
bool m_has_lsb = false;
|
||||
};
|
||||
|
||||
BitSet() : m_val(0) {}
|
||||
explicit BitSet(IntTy val) : m_val(val) {}
|
||||
BitSet(std::initializer_list<int> init) {
|
||||
m_val = 0;
|
||||
for (int bit : init)
|
||||
m_val |= (IntTy)1 << bit;
|
||||
}
|
||||
|
||||
static BitSet AllTrue(std::size_t count) {
|
||||
return BitSet(count == sizeof(IntTy) * 8 ? ~(IntTy)0 : (((IntTy)1 << count) - 1));
|
||||
}
|
||||
|
||||
Ref operator[](std::size_t bit) {
|
||||
return Ref(this, (IntTy)1 << bit);
|
||||
}
|
||||
const Ref operator[](std::size_t bit) const {
|
||||
return (*const_cast<BitSet*>(this))[bit];
|
||||
}
|
||||
bool operator==(BitSet other) const {
|
||||
return m_val == other.m_val;
|
||||
}
|
||||
bool operator!=(BitSet other) const {
|
||||
return m_val != other.m_val;
|
||||
}
|
||||
bool operator<(BitSet other) const {
|
||||
return m_val < other.m_val;
|
||||
}
|
||||
bool operator>(BitSet other) const {
|
||||
return m_val > other.m_val;
|
||||
}
|
||||
BitSet operator|(BitSet other) const {
|
||||
return BitSet(m_val | other.m_val);
|
||||
}
|
||||
BitSet operator&(BitSet other) const {
|
||||
return BitSet(m_val & other.m_val);
|
||||
}
|
||||
BitSet operator^(BitSet other) const {
|
||||
return BitSet(m_val ^ other.m_val);
|
||||
}
|
||||
BitSet operator~() const {
|
||||
return BitSet(~m_val);
|
||||
}
|
||||
BitSet& operator|=(BitSet other) {
|
||||
return *this = *this | other;
|
||||
}
|
||||
BitSet& operator&=(BitSet other) {
|
||||
return *this = *this & other;
|
||||
}
|
||||
BitSet& operator^=(BitSet other) {
|
||||
return *this = *this ^ other;
|
||||
}
|
||||
operator u32() = delete;
|
||||
operator bool() {
|
||||
return m_val != 0;
|
||||
}
|
||||
|
||||
// Warning: Even though on modern CPUs this is a single fast instruction,
|
||||
// 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 {
|
||||
return Iterator(m_val);
|
||||
}
|
||||
Iterator end() const {
|
||||
return Iterator(0);
|
||||
}
|
||||
|
||||
IntTy m_val;
|
||||
};
|
||||
|
||||
} // namespace Common
|
||||
|
||||
typedef Common::BitSet<u8> BitSet8;
|
||||
typedef Common::BitSet<u16> BitSet16;
|
||||
typedef Common::BitSet<u32> BitSet32;
|
||||
typedef Common::BitSet<u64> BitSet64;
|
||||
@@ -25,23 +25,6 @@
|
||||
|
||||
namespace Common {
|
||||
|
||||
int CurrentThreadId() {
|
||||
#ifdef _MSC_VER
|
||||
return GetCurrentThreadId();
|
||||
#elif defined __APPLE__
|
||||
return mach_thread_self();
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
// Supporting functions
|
||||
void SleepCurrentThread(int ms) {
|
||||
Sleep(ms);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
|
||||
void SetThreadAffinity(std::thread::native_handle_type thread, u32 mask) {
|
||||
@@ -62,7 +45,7 @@ void SwitchCurrentThread() {
|
||||
|
||||
// This is implemented much nicer in upcoming msvc++, see:
|
||||
// http://msdn.microsoft.com/en-us/library/xcb2z8hs(VS.100).aspx
|
||||
void SetCurrentThreadName(const char* szThreadName) {
|
||||
void SetCurrentThreadName(const char* name) {
|
||||
static const DWORD MS_VC_EXCEPTION = 0x406D1388;
|
||||
|
||||
#pragma pack(push, 8)
|
||||
@@ -75,7 +58,7 @@ void SetCurrentThreadName(const char* szThreadName) {
|
||||
#pragma pack(pop)
|
||||
|
||||
info.dwType = 0x1000;
|
||||
info.szName = szThreadName;
|
||||
info.szName = name;
|
||||
info.dwThreadID = -1; // dwThreadID;
|
||||
info.dwFlags = 0;
|
||||
|
||||
@@ -107,10 +90,6 @@ void SetCurrentThreadAffinity(u32 mask) {
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
void SleepCurrentThread(int ms) {
|
||||
usleep(1000 * ms);
|
||||
}
|
||||
|
||||
void SwitchCurrentThread() {
|
||||
usleep(1000 * 1);
|
||||
}
|
||||
@@ -118,15 +97,15 @@ void SwitchCurrentThread() {
|
||||
|
||||
// MinGW with the POSIX threading model does not support pthread_setname_np
|
||||
#if !defined(_WIN32) || defined(_MSC_VER)
|
||||
void SetCurrentThreadName(const char* szThreadName) {
|
||||
void SetCurrentThreadName(const char* name) {
|
||||
#ifdef __APPLE__
|
||||
pthread_setname_np(szThreadName);
|
||||
pthread_setname_np(name);
|
||||
#elif defined(__Bitrig__) || defined(__DragonFly__) || defined(__FreeBSD__) || defined(__OpenBSD__)
|
||||
pthread_set_name_np(pthread_self(), szThreadName);
|
||||
pthread_set_name_np(pthread_self(), name);
|
||||
#elif defined(__NetBSD__)
|
||||
pthread_setname_np(pthread_self(), "%s", (void*)szThreadName);
|
||||
pthread_setname_np(pthread_self(), "%s", (void*)name);
|
||||
#else
|
||||
pthread_setname_np(pthread_self(), szThreadName);
|
||||
pthread_setname_np(pthread_self(), name);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -13,15 +13,8 @@
|
||||
|
||||
namespace Common {
|
||||
|
||||
int CurrentThreadId();
|
||||
|
||||
void SetThreadAffinity(std::thread::native_handle_type thread, u32 mask);
|
||||
void SetCurrentThreadAffinity(u32 mask);
|
||||
|
||||
class Event {
|
||||
public:
|
||||
Event() : is_set(false) {}
|
||||
|
||||
void Set() {
|
||||
std::lock_guard<std::mutex> lk(mutex);
|
||||
if (!is_set) {
|
||||
@@ -53,14 +46,14 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
bool is_set;
|
||||
bool is_set = false;
|
||||
std::condition_variable condvar;
|
||||
std::mutex mutex;
|
||||
};
|
||||
|
||||
class Barrier {
|
||||
public:
|
||||
explicit Barrier(std::size_t count_) : count(count_), waiting(0), generation(0) {}
|
||||
explicit Barrier(std::size_t count_) : count(count_) {}
|
||||
|
||||
/// Blocks until all "count" threads have called Sync()
|
||||
void Sync() {
|
||||
@@ -80,12 +73,13 @@ public:
|
||||
private:
|
||||
std::condition_variable condvar;
|
||||
std::mutex mutex;
|
||||
const std::size_t count;
|
||||
std::size_t waiting;
|
||||
std::size_t generation; // Incremented once each time the barrier is used
|
||||
std::size_t count;
|
||||
std::size_t waiting = 0;
|
||||
std::size_t generation = 0; // Incremented once each time the barrier is used
|
||||
};
|
||||
|
||||
void SleepCurrentThread(int ms);
|
||||
void SetThreadAffinity(std::thread::native_handle_type thread, u32 mask);
|
||||
void SetCurrentThreadAffinity(u32 mask);
|
||||
void SwitchCurrentThread(); // On Linux, this is equal to sleep 1ms
|
||||
void SetCurrentThreadName(const char* name);
|
||||
|
||||
|
||||
@@ -1,222 +0,0 @@
|
||||
// Copyright 2016 Citra Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <initializer_list>
|
||||
#include <xbyak.h>
|
||||
#include "common/assert.h"
|
||||
#include "common/bit_set.h"
|
||||
|
||||
namespace Common::X64 {
|
||||
|
||||
inline int RegToIndex(const Xbyak::Reg& reg) {
|
||||
using Kind = Xbyak::Reg::Kind;
|
||||
ASSERT_MSG((reg.getKind() & (Kind::REG | Kind::XMM)) != 0,
|
||||
"RegSet only support GPRs and XMM registers.");
|
||||
ASSERT_MSG(reg.getIdx() < 16, "RegSet only supports XXM0-15.");
|
||||
return reg.getIdx() + (reg.getKind() == Kind::REG ? 0 : 16);
|
||||
}
|
||||
|
||||
inline Xbyak::Reg64 IndexToReg64(int reg_index) {
|
||||
ASSERT(reg_index < 16);
|
||||
return Xbyak::Reg64(reg_index);
|
||||
}
|
||||
|
||||
inline Xbyak::Xmm IndexToXmm(int reg_index) {
|
||||
ASSERT(reg_index >= 16 && reg_index < 32);
|
||||
return Xbyak::Xmm(reg_index - 16);
|
||||
}
|
||||
|
||||
inline Xbyak::Reg IndexToReg(int reg_index) {
|
||||
if (reg_index < 16) {
|
||||
return IndexToReg64(reg_index);
|
||||
} else {
|
||||
return IndexToXmm(reg_index);
|
||||
}
|
||||
}
|
||||
|
||||
inline BitSet32 BuildRegSet(std::initializer_list<Xbyak::Reg> regs) {
|
||||
BitSet32 bits;
|
||||
for (const Xbyak::Reg& reg : regs) {
|
||||
bits[RegToIndex(reg)] = true;
|
||||
}
|
||||
return bits;
|
||||
}
|
||||
|
||||
const BitSet32 ABI_ALL_GPRS(0x0000FFFF);
|
||||
const BitSet32 ABI_ALL_XMMS(0xFFFF0000);
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
// Microsoft x64 ABI
|
||||
const Xbyak::Reg ABI_RETURN = Xbyak::util::rax;
|
||||
const Xbyak::Reg ABI_PARAM1 = Xbyak::util::rcx;
|
||||
const Xbyak::Reg ABI_PARAM2 = Xbyak::util::rdx;
|
||||
const Xbyak::Reg ABI_PARAM3 = Xbyak::util::r8;
|
||||
const Xbyak::Reg ABI_PARAM4 = Xbyak::util::r9;
|
||||
|
||||
const BitSet32 ABI_ALL_CALLER_SAVED = BuildRegSet({
|
||||
// GPRs
|
||||
Xbyak::util::rcx,
|
||||
Xbyak::util::rdx,
|
||||
Xbyak::util::r8,
|
||||
Xbyak::util::r9,
|
||||
Xbyak::util::r10,
|
||||
Xbyak::util::r11,
|
||||
// XMMs
|
||||
Xbyak::util::xmm0,
|
||||
Xbyak::util::xmm1,
|
||||
Xbyak::util::xmm2,
|
||||
Xbyak::util::xmm3,
|
||||
Xbyak::util::xmm4,
|
||||
Xbyak::util::xmm5,
|
||||
});
|
||||
|
||||
const BitSet32 ABI_ALL_CALLEE_SAVED = BuildRegSet({
|
||||
// GPRs
|
||||
Xbyak::util::rbx,
|
||||
Xbyak::util::rsi,
|
||||
Xbyak::util::rdi,
|
||||
Xbyak::util::rbp,
|
||||
Xbyak::util::r12,
|
||||
Xbyak::util::r13,
|
||||
Xbyak::util::r14,
|
||||
Xbyak::util::r15,
|
||||
// XMMs
|
||||
Xbyak::util::xmm6,
|
||||
Xbyak::util::xmm7,
|
||||
Xbyak::util::xmm8,
|
||||
Xbyak::util::xmm9,
|
||||
Xbyak::util::xmm10,
|
||||
Xbyak::util::xmm11,
|
||||
Xbyak::util::xmm12,
|
||||
Xbyak::util::xmm13,
|
||||
Xbyak::util::xmm14,
|
||||
Xbyak::util::xmm15,
|
||||
});
|
||||
|
||||
constexpr std::size_t ABI_SHADOW_SPACE = 0x20;
|
||||
|
||||
#else
|
||||
|
||||
// System V x86-64 ABI
|
||||
const Xbyak::Reg ABI_RETURN = Xbyak::util::rax;
|
||||
const Xbyak::Reg ABI_PARAM1 = Xbyak::util::rdi;
|
||||
const Xbyak::Reg ABI_PARAM2 = Xbyak::util::rsi;
|
||||
const Xbyak::Reg ABI_PARAM3 = Xbyak::util::rdx;
|
||||
const Xbyak::Reg ABI_PARAM4 = Xbyak::util::rcx;
|
||||
|
||||
const BitSet32 ABI_ALL_CALLER_SAVED = BuildRegSet({
|
||||
// GPRs
|
||||
Xbyak::util::rcx,
|
||||
Xbyak::util::rdx,
|
||||
Xbyak::util::rdi,
|
||||
Xbyak::util::rsi,
|
||||
Xbyak::util::r8,
|
||||
Xbyak::util::r9,
|
||||
Xbyak::util::r10,
|
||||
Xbyak::util::r11,
|
||||
// XMMs
|
||||
Xbyak::util::xmm0,
|
||||
Xbyak::util::xmm1,
|
||||
Xbyak::util::xmm2,
|
||||
Xbyak::util::xmm3,
|
||||
Xbyak::util::xmm4,
|
||||
Xbyak::util::xmm5,
|
||||
Xbyak::util::xmm6,
|
||||
Xbyak::util::xmm7,
|
||||
Xbyak::util::xmm8,
|
||||
Xbyak::util::xmm9,
|
||||
Xbyak::util::xmm10,
|
||||
Xbyak::util::xmm11,
|
||||
Xbyak::util::xmm12,
|
||||
Xbyak::util::xmm13,
|
||||
Xbyak::util::xmm14,
|
||||
Xbyak::util::xmm15,
|
||||
});
|
||||
|
||||
const BitSet32 ABI_ALL_CALLEE_SAVED = BuildRegSet({
|
||||
// GPRs
|
||||
Xbyak::util::rbx,
|
||||
Xbyak::util::rbp,
|
||||
Xbyak::util::r12,
|
||||
Xbyak::util::r13,
|
||||
Xbyak::util::r14,
|
||||
Xbyak::util::r15,
|
||||
});
|
||||
|
||||
constexpr std::size_t ABI_SHADOW_SPACE = 0;
|
||||
|
||||
#endif
|
||||
|
||||
inline void ABI_CalculateFrameSize(BitSet32 regs, std::size_t rsp_alignment,
|
||||
std::size_t needed_frame_size, s32* out_subtraction,
|
||||
s32* out_xmm_offset) {
|
||||
int count = (regs & ABI_ALL_GPRS).Count();
|
||||
rsp_alignment -= count * 8;
|
||||
std::size_t subtraction = 0;
|
||||
int xmm_count = (regs & ABI_ALL_XMMS).Count();
|
||||
if (xmm_count) {
|
||||
// If we have any XMMs to save, we must align the stack here.
|
||||
subtraction = rsp_alignment & 0xF;
|
||||
}
|
||||
subtraction += 0x10 * xmm_count;
|
||||
std::size_t xmm_base_subtraction = subtraction;
|
||||
subtraction += needed_frame_size;
|
||||
subtraction += ABI_SHADOW_SPACE;
|
||||
// Final alignment.
|
||||
rsp_alignment -= subtraction;
|
||||
subtraction += rsp_alignment & 0xF;
|
||||
|
||||
*out_subtraction = (s32)subtraction;
|
||||
*out_xmm_offset = (s32)(subtraction - xmm_base_subtraction);
|
||||
}
|
||||
|
||||
inline std::size_t ABI_PushRegistersAndAdjustStack(Xbyak::CodeGenerator& code, BitSet32 regs,
|
||||
std::size_t rsp_alignment,
|
||||
std::size_t needed_frame_size = 0) {
|
||||
s32 subtraction, xmm_offset;
|
||||
ABI_CalculateFrameSize(regs, rsp_alignment, needed_frame_size, &subtraction, &xmm_offset);
|
||||
|
||||
for (int reg_index : (regs & ABI_ALL_GPRS)) {
|
||||
code.push(IndexToReg64(reg_index));
|
||||
}
|
||||
|
||||
if (subtraction != 0) {
|
||||
code.sub(code.rsp, subtraction);
|
||||
}
|
||||
|
||||
for (int reg_index : (regs & ABI_ALL_XMMS)) {
|
||||
code.movaps(code.xword[code.rsp + xmm_offset], IndexToXmm(reg_index));
|
||||
xmm_offset += 0x10;
|
||||
}
|
||||
|
||||
return ABI_SHADOW_SPACE;
|
||||
}
|
||||
|
||||
inline void ABI_PopRegistersAndAdjustStack(Xbyak::CodeGenerator& code, BitSet32 regs,
|
||||
std::size_t rsp_alignment,
|
||||
std::size_t needed_frame_size = 0) {
|
||||
s32 subtraction, xmm_offset;
|
||||
ABI_CalculateFrameSize(regs, rsp_alignment, needed_frame_size, &subtraction, &xmm_offset);
|
||||
|
||||
for (int reg_index : (regs & ABI_ALL_XMMS)) {
|
||||
code.movaps(IndexToXmm(reg_index), code.xword[code.rsp + xmm_offset]);
|
||||
xmm_offset += 0x10;
|
||||
}
|
||||
|
||||
if (subtraction != 0) {
|
||||
code.add(code.rsp, subtraction);
|
||||
}
|
||||
|
||||
// GPRs need to be popped in reverse order
|
||||
for (int reg_index = 15; reg_index >= 0; reg_index--) {
|
||||
if (regs[reg_index]) {
|
||||
code.pop(IndexToReg64(reg_index));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Common::X64
|
||||
@@ -1,47 +0,0 @@
|
||||
// Copyright 2016 Citra Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <type_traits>
|
||||
#include <xbyak.h>
|
||||
#include "common/x64/xbyak_abi.h"
|
||||
|
||||
namespace Common::X64 {
|
||||
|
||||
// Constants for use with cmpps/cmpss
|
||||
enum {
|
||||
CMP_EQ = 0,
|
||||
CMP_LT = 1,
|
||||
CMP_LE = 2,
|
||||
CMP_UNORD = 3,
|
||||
CMP_NEQ = 4,
|
||||
CMP_NLT = 5,
|
||||
CMP_NLE = 6,
|
||||
CMP_ORD = 7,
|
||||
};
|
||||
|
||||
inline bool IsWithin2G(uintptr_t ref, uintptr_t target) {
|
||||
u64 distance = target - (ref + 5);
|
||||
return !(distance >= 0x8000'0000ULL && distance <= ~0x8000'0000ULL);
|
||||
}
|
||||
|
||||
inline bool IsWithin2G(const Xbyak::CodeGenerator& code, uintptr_t target) {
|
||||
return IsWithin2G(reinterpret_cast<uintptr_t>(code.getCurr()), target);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void CallFarFunction(Xbyak::CodeGenerator& code, const T f) {
|
||||
static_assert(std::is_pointer_v<T>, "Argument must be a (function) pointer.");
|
||||
std::size_t addr = reinterpret_cast<std::size_t>(f);
|
||||
if (IsWithin2G(code, addr)) {
|
||||
code.call(f);
|
||||
} else {
|
||||
// ABI_RETURN is a safe temp register to use before a call
|
||||
code.mov(ABI_RETURN, addr);
|
||||
code.call(ABI_RETURN);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Common::X64
|
||||
@@ -12,6 +12,8 @@ add_library(core STATIC
|
||||
core_timing.h
|
||||
core_timing_util.cpp
|
||||
core_timing_util.h
|
||||
cpu_core_manager.cpp
|
||||
cpu_core_manager.h
|
||||
crypto/aes_util.cpp
|
||||
crypto/aes_util.h
|
||||
crypto/encryption_layer.cpp
|
||||
@@ -156,6 +158,8 @@ add_library(core STATIC
|
||||
hle/service/am/applets/applets.h
|
||||
hle/service/am/applets/software_keyboard.cpp
|
||||
hle/service/am/applets/software_keyboard.h
|
||||
hle/service/am/applets/stub_applet.cpp
|
||||
hle/service/am/applets/stub_applet.h
|
||||
hle/service/am/idle.cpp
|
||||
hle/service/am/idle.h
|
||||
hle/service/am/omm.cpp
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include "core/core.h"
|
||||
#include "core/core_cpu.h"
|
||||
#include "core/core_timing.h"
|
||||
#include "core/cpu_core_manager.h"
|
||||
#include "core/file_sys/mode.h"
|
||||
#include "core/file_sys/vfs_concat.h"
|
||||
#include "core/file_sys/vfs_real.h"
|
||||
@@ -28,7 +29,6 @@
|
||||
#include "core/hle/service/sm/sm.h"
|
||||
#include "core/loader/loader.h"
|
||||
#include "core/perf_stats.h"
|
||||
#include "core/settings.h"
|
||||
#include "core/telemetry_session.h"
|
||||
#include "frontend/applets/software_keyboard.h"
|
||||
#include "video_core/debug_utils/debug_utils.h"
|
||||
@@ -71,64 +71,22 @@ FileSys::VirtualFile GetGameFileFromPath(const FileSys::VirtualFilesystem& vfs,
|
||||
|
||||
return vfs->OpenFile(path, FileSys::Mode::Read);
|
||||
}
|
||||
|
||||
/// Runs a CPU core while the system is powered on
|
||||
void RunCpuCore(Cpu& cpu_state) {
|
||||
while (Core::System::GetInstance().IsPoweredOn()) {
|
||||
cpu_state.RunLoop(true);
|
||||
}
|
||||
}
|
||||
} // Anonymous namespace
|
||||
|
||||
struct System::Impl {
|
||||
Cpu& CurrentCpuCore() {
|
||||
if (Settings::values.use_multi_core) {
|
||||
const auto& search = thread_to_cpu.find(std::this_thread::get_id());
|
||||
ASSERT(search != thread_to_cpu.end());
|
||||
ASSERT(search->second);
|
||||
return *search->second;
|
||||
}
|
||||
|
||||
// Otherwise, use single-threaded mode active_core variable
|
||||
return *cpu_cores[active_core];
|
||||
return cpu_core_manager.GetCurrentCore();
|
||||
}
|
||||
|
||||
ResultStatus RunLoop(bool tight_loop) {
|
||||
status = ResultStatus::Success;
|
||||
|
||||
// Update thread_to_cpu in case Core 0 is run from a different host thread
|
||||
thread_to_cpu[std::this_thread::get_id()] = cpu_cores[0].get();
|
||||
|
||||
if (GDBStub::IsServerEnabled()) {
|
||||
GDBStub::HandlePacket();
|
||||
|
||||
// If the loop is halted and we want to step, use a tiny (1) number of instructions to
|
||||
// execute. Otherwise, get out of the loop function.
|
||||
if (GDBStub::GetCpuHaltFlag()) {
|
||||
if (GDBStub::GetCpuStepFlag()) {
|
||||
tight_loop = false;
|
||||
} else {
|
||||
return ResultStatus::Success;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (active_core = 0; active_core < NUM_CPU_CORES; ++active_core) {
|
||||
cpu_cores[active_core]->RunLoop(tight_loop);
|
||||
if (Settings::values.use_multi_core) {
|
||||
// Cores 1-3 are run on other threads in this mode
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (GDBStub::IsServerEnabled()) {
|
||||
GDBStub::SetCpuStepFlag(false);
|
||||
}
|
||||
cpu_core_manager.RunLoop(tight_loop);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
ResultStatus Init(Frontend::EmuWindow& emu_window) {
|
||||
ResultStatus Init(System& system, Frontend::EmuWindow& emu_window) {
|
||||
LOG_DEBUG(HW_Memory, "initialized OK");
|
||||
|
||||
CoreTiming::Init();
|
||||
@@ -145,12 +103,6 @@ struct System::Impl {
|
||||
auto main_process = Kernel::Process::Create(kernel, "main");
|
||||
kernel.MakeCurrentProcess(main_process.get());
|
||||
|
||||
cpu_barrier = std::make_unique<CpuBarrier>();
|
||||
cpu_exclusive_monitor = Cpu::MakeExclusiveMonitor(cpu_cores.size());
|
||||
for (std::size_t index = 0; index < cpu_cores.size(); ++index) {
|
||||
cpu_cores[index] = std::make_unique<Cpu>(*cpu_exclusive_monitor, *cpu_barrier, index);
|
||||
}
|
||||
|
||||
telemetry_session = std::make_unique<Core::TelemetrySession>();
|
||||
service_manager = std::make_shared<Service::SM::ServiceManager>();
|
||||
|
||||
@@ -164,17 +116,8 @@ struct System::Impl {
|
||||
|
||||
gpu_core = std::make_unique<Tegra::GPU>(renderer->Rasterizer());
|
||||
|
||||
// Create threads for CPU cores 1-3, and build thread_to_cpu map
|
||||
// CPU core 0 is run on the main thread
|
||||
thread_to_cpu[std::this_thread::get_id()] = cpu_cores[0].get();
|
||||
if (Settings::values.use_multi_core) {
|
||||
for (std::size_t index = 0; index < cpu_core_threads.size(); ++index) {
|
||||
cpu_core_threads[index] =
|
||||
std::make_unique<std::thread>(RunCpuCore, std::ref(*cpu_cores[index + 1]));
|
||||
thread_to_cpu[cpu_core_threads[index]->get_id()] = cpu_cores[index + 1].get();
|
||||
}
|
||||
}
|
||||
|
||||
cpu_core_manager.Initialize(system);
|
||||
is_powered_on = true;
|
||||
LOG_DEBUG(Core, "Initialized OK");
|
||||
|
||||
// Reset counters and set time origin to current frame
|
||||
@@ -184,7 +127,8 @@ struct System::Impl {
|
||||
return ResultStatus::Success;
|
||||
}
|
||||
|
||||
ResultStatus Load(Frontend::EmuWindow& emu_window, const std::string& filepath) {
|
||||
ResultStatus Load(System& system, Frontend::EmuWindow& emu_window,
|
||||
const std::string& filepath) {
|
||||
app_loader = Loader::GetLoader(GetGameFileFromPath(virtual_filesystem, filepath));
|
||||
|
||||
if (!app_loader) {
|
||||
@@ -201,7 +145,7 @@ struct System::Impl {
|
||||
return ResultStatus::ErrorSystemMode;
|
||||
}
|
||||
|
||||
ResultStatus init_result{Init(emu_window)};
|
||||
ResultStatus init_result{Init(system, emu_window)};
|
||||
if (init_result != ResultStatus::Success) {
|
||||
LOG_CRITICAL(Core, "Failed to initialize system (Error {})!",
|
||||
static_cast<int>(init_result));
|
||||
@@ -231,6 +175,8 @@ struct System::Impl {
|
||||
Telemetry().AddField(Telemetry::FieldType::Performance, "Shutdown_Frametime",
|
||||
perf_results.frametime * 1000.0);
|
||||
|
||||
is_powered_on = false;
|
||||
|
||||
// Shutdown emulation session
|
||||
renderer.reset();
|
||||
GDBStub::Shutdown();
|
||||
@@ -240,19 +186,7 @@ struct System::Impl {
|
||||
gpu_core.reset();
|
||||
|
||||
// Close all CPU/threading state
|
||||
cpu_barrier->NotifyEnd();
|
||||
if (Settings::values.use_multi_core) {
|
||||
for (auto& thread : cpu_core_threads) {
|
||||
thread->join();
|
||||
thread.reset();
|
||||
}
|
||||
}
|
||||
thread_to_cpu.clear();
|
||||
for (auto& cpu_core : cpu_cores) {
|
||||
cpu_core.reset();
|
||||
}
|
||||
cpu_exclusive_monitor.reset();
|
||||
cpu_barrier.reset();
|
||||
cpu_core_manager.Shutdown();
|
||||
|
||||
// Shutdown kernel and core timing
|
||||
kernel.Shutdown();
|
||||
@@ -289,11 +223,8 @@ struct System::Impl {
|
||||
std::unique_ptr<VideoCore::RendererBase> renderer;
|
||||
std::unique_ptr<Tegra::GPU> gpu_core;
|
||||
std::shared_ptr<Tegra::DebugContext> debug_context;
|
||||
std::unique_ptr<ExclusiveMonitor> cpu_exclusive_monitor;
|
||||
std::unique_ptr<CpuBarrier> cpu_barrier;
|
||||
std::array<std::unique_ptr<Cpu>, NUM_CPU_CORES> cpu_cores;
|
||||
std::array<std::unique_ptr<std::thread>, NUM_CPU_CORES - 1> cpu_core_threads;
|
||||
std::size_t active_core{}; ///< Active core, only used in single thread mode
|
||||
CpuCoreManager cpu_core_manager;
|
||||
bool is_powered_on = false;
|
||||
|
||||
/// Frontend applets
|
||||
std::unique_ptr<Core::Frontend::SoftwareKeyboardApplet> software_keyboard;
|
||||
@@ -307,9 +238,6 @@ struct System::Impl {
|
||||
ResultStatus status = ResultStatus::Success;
|
||||
std::string status_details = "";
|
||||
|
||||
/// Map of guest threads to CPU cores
|
||||
std::map<std::thread::id, Cpu*> thread_to_cpu;
|
||||
|
||||
Core::PerfStats perf_stats;
|
||||
Core::FrameLimiter frame_limiter;
|
||||
};
|
||||
@@ -334,17 +262,15 @@ System::ResultStatus System::SingleStep() {
|
||||
}
|
||||
|
||||
void System::InvalidateCpuInstructionCaches() {
|
||||
for (auto& cpu : impl->cpu_cores) {
|
||||
cpu->ArmInterface().ClearInstructionCache();
|
||||
}
|
||||
impl->cpu_core_manager.InvalidateAllInstructionCaches();
|
||||
}
|
||||
|
||||
System::ResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::string& filepath) {
|
||||
return impl->Load(emu_window, filepath);
|
||||
return impl->Load(*this, emu_window, filepath);
|
||||
}
|
||||
|
||||
bool System::IsPoweredOn() const {
|
||||
return impl->cpu_barrier && impl->cpu_barrier->IsAlive();
|
||||
return impl->is_powered_on;
|
||||
}
|
||||
|
||||
void System::PrepareReschedule() {
|
||||
@@ -408,21 +334,20 @@ const ARM_Interface& System::ArmInterface(std::size_t core_index) const {
|
||||
}
|
||||
|
||||
Cpu& System::CpuCore(std::size_t core_index) {
|
||||
ASSERT(core_index < NUM_CPU_CORES);
|
||||
return *impl->cpu_cores[core_index];
|
||||
return impl->cpu_core_manager.GetCore(core_index);
|
||||
}
|
||||
|
||||
const Cpu& System::CpuCore(std::size_t core_index) const {
|
||||
ASSERT(core_index < NUM_CPU_CORES);
|
||||
return *impl->cpu_cores[core_index];
|
||||
return impl->cpu_core_manager.GetCore(core_index);
|
||||
}
|
||||
|
||||
ExclusiveMonitor& System::Monitor() {
|
||||
return *impl->cpu_exclusive_monitor;
|
||||
return impl->cpu_core_manager.GetExclusiveMonitor();
|
||||
}
|
||||
|
||||
const ExclusiveMonitor& System::Monitor() const {
|
||||
return *impl->cpu_exclusive_monitor;
|
||||
return impl->cpu_core_manager.GetExclusiveMonitor();
|
||||
}
|
||||
|
||||
Tegra::GPU& System::GPU() {
|
||||
@@ -506,7 +431,7 @@ const Core::Frontend::SoftwareKeyboardApplet& System::GetSoftwareKeyboard() cons
|
||||
}
|
||||
|
||||
System::ResultStatus System::Init(Frontend::EmuWindow& emu_window) {
|
||||
return impl->Init(emu_window);
|
||||
return impl->Init(*this, emu_window);
|
||||
}
|
||||
|
||||
void System::Shutdown() {
|
||||
|
||||
142
src/core/cpu_core_manager.cpp
Normal file
142
src/core/cpu_core_manager.cpp
Normal file
@@ -0,0 +1,142 @@
|
||||
// Copyright 2018 yuzu emulator team
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "core/arm/exclusive_monitor.h"
|
||||
#include "core/core.h"
|
||||
#include "core/core_cpu.h"
|
||||
#include "core/cpu_core_manager.h"
|
||||
#include "core/gdbstub/gdbstub.h"
|
||||
#include "core/settings.h"
|
||||
|
||||
namespace Core {
|
||||
namespace {
|
||||
void RunCpuCore(const System& system, Cpu& cpu_state) {
|
||||
while (system.IsPoweredOn()) {
|
||||
cpu_state.RunLoop(true);
|
||||
}
|
||||
}
|
||||
} // Anonymous namespace
|
||||
|
||||
CpuCoreManager::CpuCoreManager() = default;
|
||||
CpuCoreManager::~CpuCoreManager() = default;
|
||||
|
||||
void CpuCoreManager::Initialize(System& system) {
|
||||
barrier = std::make_unique<CpuBarrier>();
|
||||
exclusive_monitor = Cpu::MakeExclusiveMonitor(cores.size());
|
||||
|
||||
for (std::size_t index = 0; index < cores.size(); ++index) {
|
||||
cores[index] = std::make_unique<Cpu>(*exclusive_monitor, *barrier, index);
|
||||
}
|
||||
|
||||
// Create threads for CPU cores 1-3, and build thread_to_cpu map
|
||||
// CPU core 0 is run on the main thread
|
||||
thread_to_cpu[std::this_thread::get_id()] = cores[0].get();
|
||||
if (!Settings::values.use_multi_core) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (std::size_t index = 0; index < core_threads.size(); ++index) {
|
||||
core_threads[index] = std::make_unique<std::thread>(RunCpuCore, std::cref(system),
|
||||
std::ref(*cores[index + 1]));
|
||||
thread_to_cpu[core_threads[index]->get_id()] = cores[index + 1].get();
|
||||
}
|
||||
}
|
||||
|
||||
void CpuCoreManager::Shutdown() {
|
||||
barrier->NotifyEnd();
|
||||
if (Settings::values.use_multi_core) {
|
||||
for (auto& thread : core_threads) {
|
||||
thread->join();
|
||||
thread.reset();
|
||||
}
|
||||
}
|
||||
|
||||
thread_to_cpu.clear();
|
||||
for (auto& cpu_core : cores) {
|
||||
cpu_core.reset();
|
||||
}
|
||||
|
||||
exclusive_monitor.reset();
|
||||
barrier.reset();
|
||||
}
|
||||
|
||||
Cpu& CpuCoreManager::GetCore(std::size_t index) {
|
||||
return *cores.at(index);
|
||||
}
|
||||
|
||||
const Cpu& CpuCoreManager::GetCore(std::size_t index) const {
|
||||
return *cores.at(index);
|
||||
}
|
||||
|
||||
ExclusiveMonitor& CpuCoreManager::GetExclusiveMonitor() {
|
||||
return *exclusive_monitor;
|
||||
}
|
||||
|
||||
const ExclusiveMonitor& CpuCoreManager::GetExclusiveMonitor() const {
|
||||
return *exclusive_monitor;
|
||||
}
|
||||
|
||||
Cpu& CpuCoreManager::GetCurrentCore() {
|
||||
if (Settings::values.use_multi_core) {
|
||||
const auto& search = thread_to_cpu.find(std::this_thread::get_id());
|
||||
ASSERT(search != thread_to_cpu.end());
|
||||
ASSERT(search->second);
|
||||
return *search->second;
|
||||
}
|
||||
|
||||
// Otherwise, use single-threaded mode active_core variable
|
||||
return *cores[active_core];
|
||||
}
|
||||
|
||||
const Cpu& CpuCoreManager::GetCurrentCore() const {
|
||||
if (Settings::values.use_multi_core) {
|
||||
const auto& search = thread_to_cpu.find(std::this_thread::get_id());
|
||||
ASSERT(search != thread_to_cpu.end());
|
||||
ASSERT(search->second);
|
||||
return *search->second;
|
||||
}
|
||||
|
||||
// Otherwise, use single-threaded mode active_core variable
|
||||
return *cores[active_core];
|
||||
}
|
||||
|
||||
void CpuCoreManager::RunLoop(bool tight_loop) {
|
||||
// Update thread_to_cpu in case Core 0 is run from a different host thread
|
||||
thread_to_cpu[std::this_thread::get_id()] = cores[0].get();
|
||||
|
||||
if (GDBStub::IsServerEnabled()) {
|
||||
GDBStub::HandlePacket();
|
||||
|
||||
// If the loop is halted and we want to step, use a tiny (1) number of instructions to
|
||||
// execute. Otherwise, get out of the loop function.
|
||||
if (GDBStub::GetCpuHaltFlag()) {
|
||||
if (GDBStub::GetCpuStepFlag()) {
|
||||
tight_loop = false;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (active_core = 0; active_core < NUM_CPU_CORES; ++active_core) {
|
||||
cores[active_core]->RunLoop(tight_loop);
|
||||
if (Settings::values.use_multi_core) {
|
||||
// Cores 1-3 are run on other threads in this mode
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (GDBStub::IsServerEnabled()) {
|
||||
GDBStub::SetCpuStepFlag(false);
|
||||
}
|
||||
}
|
||||
|
||||
void CpuCoreManager::InvalidateAllInstructionCaches() {
|
||||
for (auto& cpu : cores) {
|
||||
cpu->ArmInterface().ClearInstructionCache();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Core
|
||||
59
src/core/cpu_core_manager.h
Normal file
59
src/core/cpu_core_manager.h
Normal file
@@ -0,0 +1,59 @@
|
||||
// Copyright 2018 yuzu emulator team
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <thread>
|
||||
|
||||
namespace Core {
|
||||
|
||||
class Cpu;
|
||||
class CpuBarrier;
|
||||
class ExclusiveMonitor;
|
||||
class System;
|
||||
|
||||
class CpuCoreManager {
|
||||
public:
|
||||
CpuCoreManager();
|
||||
CpuCoreManager(const CpuCoreManager&) = delete;
|
||||
CpuCoreManager(CpuCoreManager&&) = delete;
|
||||
|
||||
~CpuCoreManager();
|
||||
|
||||
CpuCoreManager& operator=(const CpuCoreManager&) = delete;
|
||||
CpuCoreManager& operator=(CpuCoreManager&&) = delete;
|
||||
|
||||
void Initialize(System& system);
|
||||
void Shutdown();
|
||||
|
||||
Cpu& GetCore(std::size_t index);
|
||||
const Cpu& GetCore(std::size_t index) const;
|
||||
|
||||
Cpu& GetCurrentCore();
|
||||
const Cpu& GetCurrentCore() const;
|
||||
|
||||
ExclusiveMonitor& GetExclusiveMonitor();
|
||||
const ExclusiveMonitor& GetExclusiveMonitor() const;
|
||||
|
||||
void RunLoop(bool tight_loop);
|
||||
|
||||
void InvalidateAllInstructionCaches();
|
||||
|
||||
private:
|
||||
static constexpr std::size_t NUM_CPU_CORES = 4;
|
||||
|
||||
std::unique_ptr<ExclusiveMonitor> exclusive_monitor;
|
||||
std::unique_ptr<CpuBarrier> barrier;
|
||||
std::array<std::unique_ptr<Cpu>, NUM_CPU_CORES> cores;
|
||||
std::array<std::unique_ptr<std::thread>, NUM_CPU_CORES - 1> core_threads;
|
||||
std::size_t active_core{}; ///< Active core, only used in single thread mode
|
||||
|
||||
/// Map of guest threads to CPU cores
|
||||
std::map<std::thread::id, Cpu*> thread_to_cpu;
|
||||
};
|
||||
|
||||
} // namespace Core
|
||||
@@ -26,6 +26,11 @@ namespace FileSys {
|
||||
constexpr u64 SINGLE_BYTE_MODULUS = 0x100;
|
||||
constexpr u64 DLC_BASE_TITLE_ID_MASK = 0xFFFFFFFFFFFFE000;
|
||||
|
||||
constexpr std::array<const char*, 14> EXEFS_FILE_NAMES{
|
||||
"main", "main.npdm", "rtld", "sdk", "subsdk0", "subsdk1", "subsdk2",
|
||||
"subsdk3", "subsdk4", "subsdk5", "subsdk6", "subsdk7", "subsdk8", "subsdk9",
|
||||
};
|
||||
|
||||
struct NSOBuildHeader {
|
||||
u32_le magic;
|
||||
INSERT_PADDING_BYTES(0x3C);
|
||||
@@ -57,6 +62,15 @@ VirtualDir PatchManager::PatchExeFS(VirtualDir exefs) const {
|
||||
if (exefs == nullptr)
|
||||
return exefs;
|
||||
|
||||
if (Settings::values.dump_exefs) {
|
||||
LOG_INFO(Loader, "Dumping ExeFS for title_id={:016X}", title_id);
|
||||
const auto dump_dir = Service::FileSystem::GetModificationDumpRoot(title_id);
|
||||
if (dump_dir != nullptr) {
|
||||
const auto exefs_dir = GetOrCreateDirectoryRelative(dump_dir, "/exefs");
|
||||
VfsRawCopyD(exefs, exefs_dir);
|
||||
}
|
||||
}
|
||||
|
||||
const auto installed = Service::FileSystem::GetUnionContents();
|
||||
|
||||
// Game Updates
|
||||
@@ -70,6 +84,30 @@ VirtualDir PatchManager::PatchExeFS(VirtualDir exefs) const {
|
||||
exefs = update->GetExeFS();
|
||||
}
|
||||
|
||||
// LayeredExeFS
|
||||
const auto load_dir = Service::FileSystem::GetModificationLoadRoot(title_id);
|
||||
if (load_dir != nullptr && load_dir->GetSize() > 0) {
|
||||
auto patch_dirs = load_dir->GetSubdirectories();
|
||||
std::sort(
|
||||
patch_dirs.begin(), patch_dirs.end(),
|
||||
[](const VirtualDir& l, const VirtualDir& r) { return l->GetName() < r->GetName(); });
|
||||
|
||||
std::vector<VirtualDir> layers;
|
||||
layers.reserve(patch_dirs.size() + 1);
|
||||
for (const auto& subdir : patch_dirs) {
|
||||
auto exefs_dir = subdir->GetSubdirectory("exefs");
|
||||
if (exefs_dir != nullptr)
|
||||
layers.push_back(std::move(exefs_dir));
|
||||
}
|
||||
layers.push_back(exefs);
|
||||
|
||||
auto layered = LayeredVfsDirectory::MakeLayeredDirectory(std::move(layers));
|
||||
if (layered != nullptr) {
|
||||
LOG_INFO(Loader, " ExeFS: LayeredExeFS patches applied successfully");
|
||||
exefs = std::move(layered);
|
||||
}
|
||||
}
|
||||
|
||||
return exefs;
|
||||
}
|
||||
|
||||
@@ -314,18 +352,25 @@ std::map<std::string, std::string, std::less<>> PatchManager::GetPatchVersionNam
|
||||
if (IsDirValidAndNonEmpty(exefs_dir)) {
|
||||
bool ips = false;
|
||||
bool ipswitch = false;
|
||||
bool layeredfs = false;
|
||||
|
||||
for (const auto& file : exefs_dir->GetFiles()) {
|
||||
if (file->GetExtension() == "ips")
|
||||
if (file->GetExtension() == "ips") {
|
||||
ips = true;
|
||||
else if (file->GetExtension() == "pchtxt")
|
||||
} else if (file->GetExtension() == "pchtxt") {
|
||||
ipswitch = true;
|
||||
} else if (std::find(EXEFS_FILE_NAMES.begin(), EXEFS_FILE_NAMES.end(),
|
||||
file->GetName()) != EXEFS_FILE_NAMES.end()) {
|
||||
layeredfs = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (ips)
|
||||
AppendCommaIfNotEmpty(types, "IPS");
|
||||
if (ipswitch)
|
||||
AppendCommaIfNotEmpty(types, "IPSwitch");
|
||||
if (layeredfs)
|
||||
AppendCommaIfNotEmpty(types, "LayeredExeFS");
|
||||
}
|
||||
if (IsDirValidAndNonEmpty(mod->GetSubdirectory("romfs")))
|
||||
AppendCommaIfNotEmpty(types, "LayeredFS");
|
||||
|
||||
@@ -71,10 +71,6 @@ constexpr u32 PSTATE_REGISTER = 33;
|
||||
constexpr u32 UC_ARM64_REG_Q0 = 34;
|
||||
constexpr u32 FPCR_REGISTER = 66;
|
||||
|
||||
// TODO/WiP - Used while working on support for FPU
|
||||
constexpr u32 TODO_DUMMY_REG_997 = 997;
|
||||
constexpr u32 TODO_DUMMY_REG_998 = 998;
|
||||
|
||||
// For sample XML files see the GDB source /gdb/features
|
||||
// GDB also wants the l character at the start
|
||||
// This XML defines what the registers are for this specific ARM device
|
||||
@@ -260,6 +256,36 @@ static void RegWrite(std::size_t id, u64 val, Kernel::Thread* thread = nullptr)
|
||||
}
|
||||
}
|
||||
|
||||
static u128 FpuRead(std::size_t id, Kernel::Thread* thread = nullptr) {
|
||||
if (!thread) {
|
||||
return u128{0};
|
||||
}
|
||||
|
||||
auto& thread_context = thread->GetContext();
|
||||
|
||||
if (id >= UC_ARM64_REG_Q0 && id < FPCR_REGISTER) {
|
||||
return thread_context.vector_registers[id - UC_ARM64_REG_Q0];
|
||||
} else if (id == FPCR_REGISTER) {
|
||||
return u128{thread_context.fpcr, 0};
|
||||
} else {
|
||||
return u128{0};
|
||||
}
|
||||
}
|
||||
|
||||
static void FpuWrite(std::size_t id, u128 val, Kernel::Thread* thread = nullptr) {
|
||||
if (!thread) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto& thread_context = thread->GetContext();
|
||||
|
||||
if (id >= UC_ARM64_REG_Q0 && id < FPCR_REGISTER) {
|
||||
thread_context.vector_registers[id - UC_ARM64_REG_Q0] = val;
|
||||
} else if (id == FPCR_REGISTER) {
|
||||
thread_context.fpcr = val[0];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Turns hex string character into the equivalent byte.
|
||||
*
|
||||
@@ -409,6 +435,27 @@ static u64 GdbHexToLong(const u8* src) {
|
||||
return output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a gdb-formatted hex string into a u128.
|
||||
*
|
||||
* @param src Pointer to hex string.
|
||||
*/
|
||||
static u128 GdbHexToU128(const u8* src) {
|
||||
u128 output;
|
||||
|
||||
for (int i = 0; i < 16; i += 2) {
|
||||
output[0] = (output[0] << 4) | HexCharToValue(src[15 - i - 1]);
|
||||
output[0] = (output[0] << 4) | HexCharToValue(src[15 - i]);
|
||||
}
|
||||
|
||||
for (int i = 0; i < 16; i += 2) {
|
||||
output[1] = (output[1] << 4) | HexCharToValue(src[16 + 15 - i - 1]);
|
||||
output[1] = (output[1] << 4) | HexCharToValue(src[16 + 15 - i]);
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
/// Read a byte from the gdb client.
|
||||
static u8 ReadByte() {
|
||||
u8 c;
|
||||
@@ -599,8 +646,7 @@ static void HandleQuery() {
|
||||
for (u32 core = 0; core < Core::NUM_CPU_CORES; core++) {
|
||||
const auto& threads = Core::System::GetInstance().Scheduler(core).GetThreadList();
|
||||
for (const auto& thread : threads) {
|
||||
val += fmt::format("{:x}", thread->GetThreadID());
|
||||
val += ",";
|
||||
val += fmt::format("{:x},", thread->GetThreadID());
|
||||
}
|
||||
}
|
||||
val.pop_back();
|
||||
@@ -791,11 +837,15 @@ static void ReadRegister() {
|
||||
} else if (id == PSTATE_REGISTER) {
|
||||
IntToGdbHex(reply, static_cast<u32>(RegRead(id, current_thread)));
|
||||
} else if (id >= UC_ARM64_REG_Q0 && id < FPCR_REGISTER) {
|
||||
LongToGdbHex(reply, RegRead(id, current_thread));
|
||||
u128 r = FpuRead(id, current_thread);
|
||||
LongToGdbHex(reply, r[0]);
|
||||
LongToGdbHex(reply + 16, r[1]);
|
||||
} else if (id == FPCR_REGISTER) {
|
||||
LongToGdbHex(reply, RegRead(TODO_DUMMY_REG_998, current_thread));
|
||||
} else {
|
||||
LongToGdbHex(reply, RegRead(TODO_DUMMY_REG_997, current_thread));
|
||||
u128 r = FpuRead(id, current_thread);
|
||||
IntToGdbHex(reply, static_cast<u32>(r[0]));
|
||||
} else if (id == FPCR_REGISTER + 1) {
|
||||
u128 r = FpuRead(id, current_thread);
|
||||
IntToGdbHex(reply, static_cast<u32>(r[0] >> 32));
|
||||
}
|
||||
|
||||
SendReply(reinterpret_cast<char*>(reply));
|
||||
@@ -822,13 +872,18 @@ static void ReadRegisters() {
|
||||
|
||||
bufptr += 8;
|
||||
|
||||
for (u32 reg = UC_ARM64_REG_Q0; reg <= UC_ARM64_REG_Q0 + 31; reg++) {
|
||||
LongToGdbHex(bufptr + reg * 16, RegRead(reg, current_thread));
|
||||
u128 r;
|
||||
|
||||
for (u32 reg = UC_ARM64_REG_Q0; reg < FPCR_REGISTER; reg++) {
|
||||
r = FpuRead(reg, current_thread);
|
||||
LongToGdbHex(bufptr + reg * 32, r[0]);
|
||||
LongToGdbHex(bufptr + reg * 32 + 16, r[1]);
|
||||
}
|
||||
|
||||
bufptr += 32 * 32;
|
||||
|
||||
LongToGdbHex(bufptr, RegRead(TODO_DUMMY_REG_998, current_thread));
|
||||
r = FpuRead(FPCR_REGISTER, current_thread);
|
||||
IntToGdbHex(bufptr, static_cast<u32>(r[0]));
|
||||
|
||||
bufptr += 8;
|
||||
|
||||
@@ -853,14 +908,12 @@ static void WriteRegister() {
|
||||
} else if (id == PSTATE_REGISTER) {
|
||||
RegWrite(id, GdbHexToInt(buffer_ptr), current_thread);
|
||||
} else if (id >= UC_ARM64_REG_Q0 && id < FPCR_REGISTER) {
|
||||
RegWrite(id, GdbHexToLong(buffer_ptr), current_thread);
|
||||
FpuWrite(id, GdbHexToU128(buffer_ptr), current_thread);
|
||||
} else if (id == FPCR_REGISTER) {
|
||||
RegWrite(TODO_DUMMY_REG_998, GdbHexToLong(buffer_ptr), current_thread);
|
||||
} else {
|
||||
RegWrite(TODO_DUMMY_REG_997, GdbHexToLong(buffer_ptr), current_thread);
|
||||
} else if (id == FPCR_REGISTER + 1) {
|
||||
}
|
||||
|
||||
// Update Unicorn context skipping scheduler, no running threads at this point
|
||||
// Update ARM context, skipping scheduler - no running threads at this point
|
||||
Core::System::GetInstance()
|
||||
.ArmInterface(current_core)
|
||||
.LoadContext(current_thread->GetContext());
|
||||
@@ -885,13 +938,13 @@ static void WriteRegisters() {
|
||||
} else if (reg >= UC_ARM64_REG_Q0 && reg < FPCR_REGISTER) {
|
||||
RegWrite(reg, GdbHexToLong(buffer_ptr + i * 16), current_thread);
|
||||
} else if (reg == FPCR_REGISTER) {
|
||||
RegWrite(TODO_DUMMY_REG_998, GdbHexToLong(buffer_ptr + i * 16), current_thread);
|
||||
} else {
|
||||
UNIMPLEMENTED();
|
||||
RegWrite(FPCR_REGISTER, GdbHexToLong(buffer_ptr + i * 16), current_thread);
|
||||
} else if (reg == FPCR_REGISTER + 1) {
|
||||
RegWrite(FPCR_REGISTER, GdbHexToLong(buffer_ptr + i * 16), current_thread);
|
||||
}
|
||||
}
|
||||
|
||||
// Update Unicorn context skipping scheduler, no running threads at this point
|
||||
// Update ARM context, skipping scheduler - no running threads at this point
|
||||
Core::System::GetInstance()
|
||||
.ArmInterface(current_core)
|
||||
.LoadContext(current_thread->GetContext());
|
||||
@@ -917,12 +970,6 @@ static void ReadMemory() {
|
||||
SendReply("E01");
|
||||
}
|
||||
|
||||
const auto& vm_manager = Core::CurrentProcess()->VMManager();
|
||||
if (addr < vm_manager.GetCodeRegionBaseAddress() ||
|
||||
addr >= vm_manager.GetMapRegionEndAddress()) {
|
||||
return SendReply("E00");
|
||||
}
|
||||
|
||||
if (!Memory::IsValidVirtualAddress(addr)) {
|
||||
return SendReply("E00");
|
||||
}
|
||||
@@ -967,7 +1014,7 @@ void Break(bool is_memory_break) {
|
||||
static void Step() {
|
||||
if (command_length > 1) {
|
||||
RegWrite(PC_REGISTER, GdbHexToLong(command_buffer + 1), current_thread);
|
||||
// Update Unicorn context skipping scheduler, no running threads at this point
|
||||
// Update ARM context, skipping scheduler - no running threads at this point
|
||||
Core::System::GetInstance()
|
||||
.ArmInterface(current_core)
|
||||
.LoadContext(current_thread->GetContext());
|
||||
@@ -1010,7 +1057,7 @@ static bool CommitBreakpoint(BreakpointType type, VAddr addr, u64 len) {
|
||||
breakpoint.addr = addr;
|
||||
breakpoint.len = len;
|
||||
Memory::ReadBlock(addr, breakpoint.inst.data(), breakpoint.inst.size());
|
||||
static constexpr std::array<u8, 4> btrap{{0x00, 0x7d, 0x20, 0xd4}};
|
||||
static constexpr std::array<u8, 4> btrap{0x00, 0x7d, 0x20, 0xd4};
|
||||
Memory::WriteBlock(addr, btrap.data(), btrap.size());
|
||||
Core::System::GetInstance().InvalidateCpuInstructionCaches();
|
||||
p.insert({addr, breakpoint});
|
||||
@@ -1321,13 +1368,15 @@ void SetCpuStepFlag(bool is_step) {
|
||||
}
|
||||
|
||||
void SendTrap(Kernel::Thread* thread, int trap) {
|
||||
if (send_trap) {
|
||||
if (!halt_loop || current_thread == thread) {
|
||||
current_thread = thread;
|
||||
SendSignal(thread, trap);
|
||||
}
|
||||
halt_loop = true;
|
||||
send_trap = false;
|
||||
if (!send_trap) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!halt_loop || current_thread == thread) {
|
||||
current_thread = thread;
|
||||
SendSignal(thread, trap);
|
||||
}
|
||||
halt_loop = true;
|
||||
send_trap = false;
|
||||
}
|
||||
}; // namespace GDBStub
|
||||
|
||||
@@ -12,12 +12,23 @@
|
||||
#include "core/hle/kernel/thread.h"
|
||||
|
||||
namespace Kernel {
|
||||
namespace {
|
||||
constexpr u16 GetSlot(Handle handle) {
|
||||
return handle >> 15;
|
||||
}
|
||||
|
||||
constexpr u16 GetGeneration(Handle handle) {
|
||||
return handle & 0x7FFF;
|
||||
}
|
||||
} // Anonymous namespace
|
||||
|
||||
HandleTable::HandleTable() {
|
||||
next_generation = 1;
|
||||
Clear();
|
||||
}
|
||||
|
||||
HandleTable::~HandleTable() = default;
|
||||
|
||||
ResultVal<Handle> HandleTable::Create(SharedPtr<Object> obj) {
|
||||
DEBUG_ASSERT(obj != nullptr);
|
||||
|
||||
|
||||
@@ -43,6 +43,7 @@ enum KernelHandle : Handle {
|
||||
class HandleTable final : NonCopyable {
|
||||
public:
|
||||
HandleTable();
|
||||
~HandleTable();
|
||||
|
||||
/**
|
||||
* Allocates a handle for the given object.
|
||||
@@ -89,18 +90,8 @@ public:
|
||||
void Clear();
|
||||
|
||||
private:
|
||||
/**
|
||||
* This is the maximum limit of handles allowed per process in CTR-OS. It can be further
|
||||
* reduced by ExHeader values, but this is not emulated here.
|
||||
*/
|
||||
static const std::size_t MAX_COUNT = 4096;
|
||||
|
||||
static u16 GetSlot(Handle handle) {
|
||||
return handle >> 15;
|
||||
}
|
||||
static u16 GetGeneration(Handle handle) {
|
||||
return handle & 0x7FFF;
|
||||
}
|
||||
/// This is the maximum limit of handles allowed per process in Horizon
|
||||
static constexpr std::size_t MAX_COUNT = 1024;
|
||||
|
||||
/// Stores the Object referenced by the handle or null if the slot is empty.
|
||||
std::array<SharedPtr<Object>, MAX_COUNT> objects;
|
||||
|
||||
@@ -63,43 +63,77 @@ bool IsInsideNewMapRegion(const VMManager& vm, VAddr address, u64 size) {
|
||||
vm.GetNewMapRegionEndAddress());
|
||||
}
|
||||
|
||||
// 8 GiB
|
||||
constexpr u64 MAIN_MEMORY_SIZE = 0x200000000;
|
||||
|
||||
// Helper function that performs the common sanity checks for svcMapMemory
|
||||
// and svcUnmapMemory. This is doable, as both functions perform their sanitizing
|
||||
// in the same order.
|
||||
ResultCode MapUnmapMemorySanityChecks(const VMManager& vm_manager, VAddr dst_addr, VAddr src_addr,
|
||||
u64 size) {
|
||||
if (!Common::Is4KBAligned(dst_addr) || !Common::Is4KBAligned(src_addr)) {
|
||||
if (!Common::Is4KBAligned(dst_addr)) {
|
||||
LOG_ERROR(Kernel_SVC, "Destination address is not aligned to 4KB, 0x{:016X}", dst_addr);
|
||||
return ERR_INVALID_ADDRESS;
|
||||
}
|
||||
|
||||
if (size == 0 || !Common::Is4KBAligned(size)) {
|
||||
if (!Common::Is4KBAligned(src_addr)) {
|
||||
LOG_ERROR(Kernel_SVC, "Source address is not aligned to 4KB, 0x{:016X}", src_addr);
|
||||
return ERR_INVALID_SIZE;
|
||||
}
|
||||
|
||||
if (size == 0) {
|
||||
LOG_ERROR(Kernel_SVC, "Size is 0");
|
||||
return ERR_INVALID_SIZE;
|
||||
}
|
||||
|
||||
if (!Common::Is4KBAligned(size)) {
|
||||
LOG_ERROR(Kernel_SVC, "Size is not aligned to 4KB, 0x{:016X}", size);
|
||||
return ERR_INVALID_SIZE;
|
||||
}
|
||||
|
||||
if (!IsValidAddressRange(dst_addr, size)) {
|
||||
LOG_ERROR(Kernel_SVC,
|
||||
"Destination is not a valid address range, addr=0x{:016X}, size=0x{:016X}",
|
||||
dst_addr, size);
|
||||
return ERR_INVALID_ADDRESS_STATE;
|
||||
}
|
||||
|
||||
if (!IsValidAddressRange(src_addr, size)) {
|
||||
LOG_ERROR(Kernel_SVC, "Source is not a valid address range, addr=0x{:016X}, size=0x{:016X}",
|
||||
src_addr, size);
|
||||
return ERR_INVALID_ADDRESS_STATE;
|
||||
}
|
||||
|
||||
if (!IsInsideAddressSpace(vm_manager, src_addr, size)) {
|
||||
LOG_ERROR(Kernel_SVC,
|
||||
"Source is not within the address space, addr=0x{:016X}, size=0x{:016X}",
|
||||
src_addr, size);
|
||||
return ERR_INVALID_ADDRESS_STATE;
|
||||
}
|
||||
|
||||
if (!IsInsideNewMapRegion(vm_manager, dst_addr, size)) {
|
||||
LOG_ERROR(Kernel_SVC,
|
||||
"Destination is not within the new map region, addr=0x{:016X}, size=0x{:016X}",
|
||||
dst_addr, size);
|
||||
return ERR_INVALID_MEMORY_RANGE;
|
||||
}
|
||||
|
||||
const VAddr dst_end_address = dst_addr + size;
|
||||
if (dst_end_address > vm_manager.GetHeapRegionBaseAddress() &&
|
||||
vm_manager.GetHeapRegionEndAddress() > dst_addr) {
|
||||
LOG_ERROR(Kernel_SVC,
|
||||
"Destination does not fit within the heap region, addr=0x{:016X}, "
|
||||
"size=0x{:016X}, end_addr=0x{:016X}",
|
||||
dst_addr, size, dst_end_address);
|
||||
return ERR_INVALID_MEMORY_RANGE;
|
||||
}
|
||||
|
||||
if (dst_end_address > vm_manager.GetMapRegionBaseAddress() &&
|
||||
vm_manager.GetMapRegionEndAddress() > dst_addr) {
|
||||
LOG_ERROR(Kernel_SVC,
|
||||
"Destination does not fit within the map region, addr=0x{:016X}, "
|
||||
"size=0x{:016X}, end_addr=0x{:016X}",
|
||||
dst_addr, size, dst_end_address);
|
||||
return ERR_INVALID_MEMORY_RANGE;
|
||||
}
|
||||
|
||||
@@ -111,8 +145,15 @@ ResultCode MapUnmapMemorySanityChecks(const VMManager& vm_manager, VAddr dst_add
|
||||
static ResultCode SetHeapSize(VAddr* heap_addr, u64 heap_size) {
|
||||
LOG_TRACE(Kernel_SVC, "called, heap_size=0x{:X}", heap_size);
|
||||
|
||||
// Size must be a multiple of 0x200000 (2MB) and be equal to or less than 4GB.
|
||||
if ((heap_size & 0xFFFFFFFE001FFFFF) != 0) {
|
||||
// Size must be a multiple of 0x200000 (2MB) and be equal to or less than 8GB.
|
||||
if ((heap_size % 0x200000) != 0) {
|
||||
LOG_ERROR(Kernel_SVC, "The heap size is not a multiple of 2MB, heap_size=0x{:016X}",
|
||||
heap_size);
|
||||
return ERR_INVALID_SIZE;
|
||||
}
|
||||
|
||||
if (heap_size >= 0x200000000) {
|
||||
LOG_ERROR(Kernel_SVC, "The heap size is not less than 8GB, heap_size=0x{:016X}", heap_size);
|
||||
return ERR_INVALID_SIZE;
|
||||
}
|
||||
|
||||
@@ -127,20 +168,31 @@ static ResultCode SetMemoryPermission(VAddr addr, u64 size, u32 prot) {
|
||||
LOG_TRACE(Kernel_SVC, "called, addr=0x{:X}, size=0x{:X}, prot=0x{:X}", addr, size, prot);
|
||||
|
||||
if (!Common::Is4KBAligned(addr)) {
|
||||
LOG_ERROR(Kernel_SVC, "Address is not aligned to 4KB, addr=0x{:016X}", addr);
|
||||
return ERR_INVALID_ADDRESS;
|
||||
}
|
||||
|
||||
if (size == 0 || !Common::Is4KBAligned(size)) {
|
||||
if (size == 0) {
|
||||
LOG_ERROR(Kernel_SVC, "Size is 0");
|
||||
return ERR_INVALID_SIZE;
|
||||
}
|
||||
|
||||
if (!Common::Is4KBAligned(size)) {
|
||||
LOG_ERROR(Kernel_SVC, "Size is not aligned to 4KB, size=0x{:016X}", size);
|
||||
return ERR_INVALID_SIZE;
|
||||
}
|
||||
|
||||
if (!IsValidAddressRange(addr, size)) {
|
||||
LOG_ERROR(Kernel_SVC, "Region is not a valid address range, addr=0x{:016X}, size=0x{:016X}",
|
||||
addr, size);
|
||||
return ERR_INVALID_ADDRESS_STATE;
|
||||
}
|
||||
|
||||
const auto permission = static_cast<MemoryPermission>(prot);
|
||||
if (permission != MemoryPermission::None && permission != MemoryPermission::Read &&
|
||||
permission != MemoryPermission::ReadWrite) {
|
||||
LOG_ERROR(Kernel_SVC, "Invalid memory permission specified, Got memory permission=0x{:08X}",
|
||||
static_cast<u32>(permission));
|
||||
return ERR_INVALID_MEMORY_PERMISSIONS;
|
||||
}
|
||||
|
||||
@@ -148,11 +200,15 @@ static ResultCode SetMemoryPermission(VAddr addr, u64 size, u32 prot) {
|
||||
auto& vm_manager = current_process->VMManager();
|
||||
|
||||
if (!IsInsideAddressSpace(vm_manager, addr, size)) {
|
||||
LOG_ERROR(Kernel_SVC,
|
||||
"Source is not within the address space, addr=0x{:016X}, size=0x{:016X}", addr,
|
||||
size);
|
||||
return ERR_INVALID_ADDRESS_STATE;
|
||||
}
|
||||
|
||||
const VMManager::VMAHandle iter = vm_manager.FindVMA(addr);
|
||||
if (iter == vm_manager.vma_map.end()) {
|
||||
LOG_ERROR(Kernel_SVC, "Unable to find VMA for address=0x{:016X}", addr);
|
||||
return ERR_INVALID_ADDRESS_STATE;
|
||||
}
|
||||
|
||||
@@ -207,6 +263,9 @@ static ResultCode UnmapMemory(VAddr dst_addr, VAddr src_addr, u64 size) {
|
||||
/// Connect to an OS service given the port name, returns the handle to the port to out
|
||||
static ResultCode ConnectToNamedPort(Handle* out_handle, VAddr port_name_address) {
|
||||
if (!Memory::IsValidVirtualAddress(port_name_address)) {
|
||||
LOG_ERROR(Kernel_SVC,
|
||||
"Port Name Address is not a valid virtual address, port_name_address=0x{:016X}",
|
||||
port_name_address);
|
||||
return ERR_NOT_FOUND;
|
||||
}
|
||||
|
||||
@@ -214,6 +273,8 @@ static ResultCode ConnectToNamedPort(Handle* out_handle, VAddr port_name_address
|
||||
// Read 1 char beyond the max allowed port name to detect names that are too long.
|
||||
std::string port_name = Memory::ReadCString(port_name_address, PortNameMaxLength + 1);
|
||||
if (port_name.size() > PortNameMaxLength) {
|
||||
LOG_ERROR(Kernel_SVC, "Port name is too long, expected {} but got {}", PortNameMaxLength,
|
||||
port_name.size());
|
||||
return ERR_OUT_OF_RANGE;
|
||||
}
|
||||
|
||||
@@ -262,6 +323,7 @@ static ResultCode GetThreadId(u32* thread_id, Handle thread_handle) {
|
||||
const auto& handle_table = Core::CurrentProcess()->GetHandleTable();
|
||||
const SharedPtr<Thread> thread = handle_table.Get<Thread>(thread_handle);
|
||||
if (!thread) {
|
||||
LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}", thread_handle);
|
||||
return ERR_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
@@ -276,6 +338,8 @@ static ResultCode GetProcessId(u32* process_id, Handle process_handle) {
|
||||
const auto& handle_table = Core::CurrentProcess()->GetHandleTable();
|
||||
const SharedPtr<Process> process = handle_table.Get<Process>(process_handle);
|
||||
if (!process) {
|
||||
LOG_ERROR(Kernel_SVC, "Process handle does not exist, process_handle=0x{:08X}",
|
||||
process_handle);
|
||||
return ERR_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
@@ -305,12 +369,18 @@ static ResultCode WaitSynchronization(Handle* index, VAddr handles_address, u64
|
||||
LOG_TRACE(Kernel_SVC, "called handles_address=0x{:X}, handle_count={}, nano_seconds={}",
|
||||
handles_address, handle_count, nano_seconds);
|
||||
|
||||
if (!Memory::IsValidVirtualAddress(handles_address))
|
||||
if (!Memory::IsValidVirtualAddress(handles_address)) {
|
||||
LOG_ERROR(Kernel_SVC,
|
||||
"Handle address is not a valid virtual address, handle_address=0x{:016X}",
|
||||
handles_address);
|
||||
return ERR_INVALID_POINTER;
|
||||
}
|
||||
|
||||
static constexpr u64 MaxHandles = 0x40;
|
||||
|
||||
if (handle_count > MaxHandles) {
|
||||
LOG_ERROR(Kernel_SVC, "Handle count specified is too large, expected {} but got {}",
|
||||
MaxHandles, handle_count);
|
||||
return ERR_OUT_OF_RANGE;
|
||||
}
|
||||
|
||||
@@ -325,6 +395,7 @@ static ResultCode WaitSynchronization(Handle* index, VAddr handles_address, u64
|
||||
const auto object = handle_table.Get<WaitObject>(handle);
|
||||
|
||||
if (object == nullptr) {
|
||||
LOG_ERROR(Kernel_SVC, "Object is a nullptr");
|
||||
return ERR_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
@@ -348,11 +419,13 @@ static ResultCode WaitSynchronization(Handle* index, VAddr handles_address, u64
|
||||
|
||||
// If a timeout value of 0 was provided, just return the Timeout error code instead of
|
||||
// suspending the thread.
|
||||
if (nano_seconds == 0)
|
||||
if (nano_seconds == 0) {
|
||||
return RESULT_TIMEOUT;
|
||||
}
|
||||
|
||||
for (auto& object : objects)
|
||||
for (auto& object : objects) {
|
||||
object->AddWaitingThread(thread);
|
||||
}
|
||||
|
||||
thread->SetWaitObjects(std::move(objects));
|
||||
thread->SetStatus(ThreadStatus::WaitSynchAny);
|
||||
@@ -373,6 +446,8 @@ static ResultCode CancelSynchronization(Handle thread_handle) {
|
||||
const auto& handle_table = Core::CurrentProcess()->GetHandleTable();
|
||||
const SharedPtr<Thread> thread = handle_table.Get<Thread>(thread_handle);
|
||||
if (!thread) {
|
||||
LOG_ERROR(Kernel_SVC, "Thread handle does not exist, thread_handle=0x{:08X}",
|
||||
thread_handle);
|
||||
return ERR_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
@@ -391,10 +466,13 @@ static ResultCode ArbitrateLock(Handle holding_thread_handle, VAddr mutex_addr,
|
||||
holding_thread_handle, mutex_addr, requesting_thread_handle);
|
||||
|
||||
if (Memory::IsKernelVirtualAddress(mutex_addr)) {
|
||||
LOG_ERROR(Kernel_SVC, "Mutex Address is a kernel virtual address, mutex_addr={:016X}",
|
||||
mutex_addr);
|
||||
return ERR_INVALID_ADDRESS_STATE;
|
||||
}
|
||||
|
||||
if (!Common::IsWordAligned(mutex_addr)) {
|
||||
LOG_ERROR(Kernel_SVC, "Mutex Address is not word aligned, mutex_addr={:016X}", mutex_addr);
|
||||
return ERR_INVALID_ADDRESS;
|
||||
}
|
||||
|
||||
@@ -408,10 +486,13 @@ static ResultCode ArbitrateUnlock(VAddr mutex_addr) {
|
||||
LOG_TRACE(Kernel_SVC, "called mutex_addr=0x{:X}", mutex_addr);
|
||||
|
||||
if (Memory::IsKernelVirtualAddress(mutex_addr)) {
|
||||
LOG_ERROR(Kernel_SVC, "Mutex Address is a kernel virtual address, mutex_addr={:016X}",
|
||||
mutex_addr);
|
||||
return ERR_INVALID_ADDRESS_STATE;
|
||||
}
|
||||
|
||||
if (!Common::IsWordAligned(mutex_addr)) {
|
||||
LOG_ERROR(Kernel_SVC, "Mutex Address is not word aligned, mutex_addr={:016X}", mutex_addr);
|
||||
return ERR_INVALID_ADDRESS;
|
||||
}
|
||||
|
||||
@@ -602,10 +683,14 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id)
|
||||
break;
|
||||
case GetInfoType::RandomEntropy:
|
||||
if (handle != 0) {
|
||||
LOG_ERROR(Kernel_SVC, "Process Handle is non zero, expected 0 result but got {:016X}",
|
||||
handle);
|
||||
return ERR_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
if (info_sub_id >= Process::RANDOM_ENTROPY_SIZE) {
|
||||
LOG_ERROR(Kernel_SVC, "Entropy size is out of range, expected {} but got {}",
|
||||
Process::RANDOM_ENTROPY_SIZE, info_sub_id);
|
||||
return ERR_INVALID_COMBINATION;
|
||||
}
|
||||
|
||||
@@ -643,12 +728,16 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id)
|
||||
case GetInfoType::ThreadTickCount: {
|
||||
constexpr u64 num_cpus = 4;
|
||||
if (info_sub_id != 0xFFFFFFFFFFFFFFFF && info_sub_id >= num_cpus) {
|
||||
LOG_ERROR(Kernel_SVC, "Core count is out of range, expected {} but got {}", num_cpus,
|
||||
info_sub_id);
|
||||
return ERR_INVALID_COMBINATION;
|
||||
}
|
||||
|
||||
const auto thread =
|
||||
current_process->GetHandleTable().Get<Thread>(static_cast<Handle>(handle));
|
||||
if (!thread) {
|
||||
LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}",
|
||||
static_cast<Handle>(handle));
|
||||
return ERR_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
@@ -671,7 +760,8 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id)
|
||||
break;
|
||||
}
|
||||
default:
|
||||
UNIMPLEMENTED();
|
||||
LOG_WARNING(Kernel_SVC, "(STUBBED) Unimplemented svcGetInfo id=0x{:016X}", info_id);
|
||||
return ERR_INVALID_ENUM_VALUE;
|
||||
}
|
||||
|
||||
return RESULT_SUCCESS;
|
||||
@@ -690,14 +780,22 @@ static ResultCode GetThreadContext(VAddr thread_context, Handle handle) {
|
||||
const auto* current_process = Core::CurrentProcess();
|
||||
const SharedPtr<Thread> thread = current_process->GetHandleTable().Get<Thread>(handle);
|
||||
if (!thread) {
|
||||
LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}", handle);
|
||||
return ERR_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
if (thread->GetOwnerProcess() != current_process) {
|
||||
LOG_ERROR(Kernel_SVC,
|
||||
"The current process does not own the current thread, thread_handle={:08X} "
|
||||
"thread_pid={}, "
|
||||
"current_process_pid={}",
|
||||
handle, thread->GetOwnerProcess()->GetProcessID(),
|
||||
current_process->GetProcessID());
|
||||
return ERR_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
if (thread == GetCurrentThread()) {
|
||||
LOG_ERROR(Kernel_SVC, "The thread handle specified is the current running thread");
|
||||
return ERR_ALREADY_REGISTERED;
|
||||
}
|
||||
|
||||
@@ -718,9 +816,12 @@ static ResultCode GetThreadContext(VAddr thread_context, Handle handle) {
|
||||
|
||||
/// Gets the priority for the specified thread
|
||||
static ResultCode GetThreadPriority(u32* priority, Handle handle) {
|
||||
LOG_TRACE(Kernel_SVC, "called");
|
||||
|
||||
const auto& handle_table = Core::CurrentProcess()->GetHandleTable();
|
||||
const SharedPtr<Thread> thread = handle_table.Get<Thread>(handle);
|
||||
if (!thread) {
|
||||
LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}", handle);
|
||||
return ERR_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
@@ -730,7 +831,13 @@ static ResultCode GetThreadPriority(u32* priority, Handle handle) {
|
||||
|
||||
/// Sets the priority for the specified thread
|
||||
static ResultCode SetThreadPriority(Handle handle, u32 priority) {
|
||||
LOG_TRACE(Kernel_SVC, "called");
|
||||
|
||||
if (priority > THREADPRIO_LOWEST) {
|
||||
LOG_ERROR(
|
||||
Kernel_SVC,
|
||||
"An invalid priority was specified, expected {} but got {} for thread_handle={:08X}",
|
||||
THREADPRIO_LOWEST, priority, handle);
|
||||
return ERR_INVALID_THREAD_PRIORITY;
|
||||
}
|
||||
|
||||
@@ -738,6 +845,7 @@ static ResultCode SetThreadPriority(Handle handle, u32 priority) {
|
||||
|
||||
SharedPtr<Thread> thread = current_process->GetHandleTable().Get<Thread>(handle);
|
||||
if (!thread) {
|
||||
LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}", handle);
|
||||
return ERR_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
@@ -760,32 +868,46 @@ static ResultCode MapSharedMemory(Handle shared_memory_handle, VAddr addr, u64 s
|
||||
shared_memory_handle, addr, size, permissions);
|
||||
|
||||
if (!Common::Is4KBAligned(addr)) {
|
||||
LOG_ERROR(Kernel_SVC, "Address is not aligned to 4KB, addr=0x{:016X}", addr);
|
||||
return ERR_INVALID_ADDRESS;
|
||||
}
|
||||
|
||||
if (size == 0 || !Common::Is4KBAligned(size)) {
|
||||
if (size == 0) {
|
||||
LOG_ERROR(Kernel_SVC, "Size is 0");
|
||||
return ERR_INVALID_SIZE;
|
||||
}
|
||||
|
||||
if (!Common::Is4KBAligned(size)) {
|
||||
LOG_ERROR(Kernel_SVC, "Size is not aligned to 4KB, size=0x{:016X}", size);
|
||||
return ERR_INVALID_SIZE;
|
||||
}
|
||||
|
||||
if (!IsValidAddressRange(addr, size)) {
|
||||
LOG_ERROR(Kernel_SVC, "Region is not a valid address range, addr=0x{:016X}, size=0x{:016X}",
|
||||
addr, size);
|
||||
return ERR_INVALID_ADDRESS_STATE;
|
||||
}
|
||||
|
||||
const auto permissions_type = static_cast<MemoryPermission>(permissions);
|
||||
if (permissions_type != MemoryPermission::Read &&
|
||||
permissions_type != MemoryPermission::ReadWrite) {
|
||||
LOG_ERROR(Kernel_SVC, "Invalid permissions=0x{:08X}", permissions);
|
||||
LOG_ERROR(Kernel_SVC, "Expected Read or ReadWrite permission but got permissions=0x{:08X}",
|
||||
permissions);
|
||||
return ERR_INVALID_MEMORY_PERMISSIONS;
|
||||
}
|
||||
|
||||
auto* const current_process = Core::CurrentProcess();
|
||||
auto shared_memory = current_process->GetHandleTable().Get<SharedMemory>(shared_memory_handle);
|
||||
if (!shared_memory) {
|
||||
LOG_ERROR(Kernel_SVC, "Shared memory does not exist, shared_memory_handle=0x{:08X}",
|
||||
shared_memory_handle);
|
||||
return ERR_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
const auto& vm_manager = current_process->VMManager();
|
||||
if (!vm_manager.IsWithinASLRRegion(addr, size)) {
|
||||
LOG_ERROR(Kernel_SVC, "Region is not within the ASLR region. addr=0x{:016X}, size={:016X}",
|
||||
addr, size);
|
||||
return ERR_INVALID_MEMORY_RANGE;
|
||||
}
|
||||
|
||||
@@ -797,25 +919,38 @@ static ResultCode UnmapSharedMemory(Handle shared_memory_handle, VAddr addr, u64
|
||||
shared_memory_handle, addr, size);
|
||||
|
||||
if (!Common::Is4KBAligned(addr)) {
|
||||
LOG_ERROR(Kernel_SVC, "Address is not aligned to 4KB, addr=0x{:016X}", addr);
|
||||
return ERR_INVALID_ADDRESS;
|
||||
}
|
||||
|
||||
if (size == 0 || !Common::Is4KBAligned(size)) {
|
||||
if (size == 0) {
|
||||
LOG_ERROR(Kernel_SVC, "Size is 0");
|
||||
return ERR_INVALID_SIZE;
|
||||
}
|
||||
|
||||
if (!Common::Is4KBAligned(size)) {
|
||||
LOG_ERROR(Kernel_SVC, "Size is not aligned to 4KB, size=0x{:016X}", size);
|
||||
return ERR_INVALID_SIZE;
|
||||
}
|
||||
|
||||
if (!IsValidAddressRange(addr, size)) {
|
||||
LOG_ERROR(Kernel_SVC, "Region is not a valid address range, addr=0x{:016X}, size=0x{:016X}",
|
||||
addr, size);
|
||||
return ERR_INVALID_ADDRESS_STATE;
|
||||
}
|
||||
|
||||
auto* const current_process = Core::CurrentProcess();
|
||||
auto shared_memory = current_process->GetHandleTable().Get<SharedMemory>(shared_memory_handle);
|
||||
if (!shared_memory) {
|
||||
LOG_ERROR(Kernel_SVC, "Shared memory does not exist, shared_memory_handle=0x{:08X}",
|
||||
shared_memory_handle);
|
||||
return ERR_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
const auto& vm_manager = current_process->VMManager();
|
||||
if (!vm_manager.IsWithinASLRRegion(addr, size)) {
|
||||
LOG_ERROR(Kernel_SVC, "Region is not within the ASLR region. addr=0x{:016X}, size={:016X}",
|
||||
addr, size);
|
||||
return ERR_INVALID_MEMORY_RANGE;
|
||||
}
|
||||
|
||||
@@ -825,9 +960,12 @@ static ResultCode UnmapSharedMemory(Handle shared_memory_handle, VAddr addr, u64
|
||||
/// Query process memory
|
||||
static ResultCode QueryProcessMemory(MemoryInfo* memory_info, PageInfo* /*page_info*/,
|
||||
Handle process_handle, u64 addr) {
|
||||
LOG_TRACE(Kernel_SVC, "called process=0x{:08X} addr={:X}", process_handle, addr);
|
||||
const auto& handle_table = Core::CurrentProcess()->GetHandleTable();
|
||||
SharedPtr<Process> process = handle_table.Get<Process>(process_handle);
|
||||
if (!process) {
|
||||
LOG_ERROR(Kernel_SVC, "Process handle does not exist, process_handle=0x{:08X}",
|
||||
process_handle);
|
||||
return ERR_INVALID_HANDLE;
|
||||
}
|
||||
auto vma = process->VMManager().FindVMA(addr);
|
||||
@@ -843,8 +981,6 @@ static ResultCode QueryProcessMemory(MemoryInfo* memory_info, PageInfo* /*page_i
|
||||
memory_info->size = vma->second.size;
|
||||
memory_info->type = static_cast<u32>(vma->second.meminfo_state);
|
||||
}
|
||||
|
||||
LOG_TRACE(Kernel_SVC, "called process=0x{:08X} addr={:X}", process_handle, addr);
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -873,7 +1009,14 @@ static void ExitProcess() {
|
||||
/// Creates a new thread
|
||||
static ResultCode CreateThread(Handle* out_handle, VAddr entry_point, u64 arg, VAddr stack_top,
|
||||
u32 priority, s32 processor_id) {
|
||||
LOG_TRACE(Kernel_SVC,
|
||||
"called entrypoint=0x{:08X} ({}), arg=0x{:08X}, stacktop=0x{:08X}, "
|
||||
"threadpriority=0x{:08X}, processorid=0x{:08X} : created handle=0x{:08X}",
|
||||
entry_point, name, arg, stack_top, priority, processor_id, *out_handle);
|
||||
|
||||
if (priority > THREADPRIO_LOWEST) {
|
||||
LOG_ERROR(Kernel_SVC, "An invalid priority was specified, expected {} but got {}",
|
||||
THREADPRIO_LOWEST, priority);
|
||||
return ERR_INVALID_THREAD_PRIORITY;
|
||||
}
|
||||
|
||||
@@ -904,6 +1047,8 @@ static ResultCode CreateThread(Handle* out_handle, VAddr entry_point, u64 arg, V
|
||||
|
||||
const auto new_guest_handle = current_process->GetHandleTable().Create(thread);
|
||||
if (new_guest_handle.Failed()) {
|
||||
LOG_ERROR(Kernel_SVC, "Failed to create handle with error=0x{:X}",
|
||||
new_guest_handle.Code().raw);
|
||||
return new_guest_handle.Code();
|
||||
}
|
||||
thread->SetGuestHandle(*new_guest_handle);
|
||||
@@ -911,11 +1056,6 @@ static ResultCode CreateThread(Handle* out_handle, VAddr entry_point, u64 arg, V
|
||||
|
||||
Core::System::GetInstance().CpuCore(thread->GetProcessorID()).PrepareReschedule();
|
||||
|
||||
LOG_TRACE(Kernel_SVC,
|
||||
"called entrypoint=0x{:08X} ({}), arg=0x{:08X}, stacktop=0x{:08X}, "
|
||||
"threadpriority=0x{:08X}, processorid=0x{:08X} : created handle=0x{:08X}",
|
||||
entry_point, name, arg, stack_top, priority, processor_id, *out_handle);
|
||||
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -926,6 +1066,8 @@ static ResultCode StartThread(Handle thread_handle) {
|
||||
const auto& handle_table = Core::CurrentProcess()->GetHandleTable();
|
||||
const SharedPtr<Thread> thread = handle_table.Get<Thread>(thread_handle);
|
||||
if (!thread) {
|
||||
LOG_ERROR(Kernel_SVC, "Thread handle does not exist, thread_handle=0x{:08X}",
|
||||
thread_handle);
|
||||
return ERR_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
@@ -1105,10 +1247,12 @@ static ResultCode WaitForAddress(VAddr address, u32 type, s32 value, s64 timeout
|
||||
address, type, value, timeout);
|
||||
// If the passed address is a kernel virtual address, return invalid memory state.
|
||||
if (Memory::IsKernelVirtualAddress(address)) {
|
||||
LOG_ERROR(Kernel_SVC, "Address is a kernel virtual address, address={:016X}", address);
|
||||
return ERR_INVALID_ADDRESS_STATE;
|
||||
}
|
||||
// If the address is not properly aligned to 4 bytes, return invalid address.
|
||||
if (address % sizeof(u32) != 0) {
|
||||
if (!Common::IsWordAligned(address)) {
|
||||
LOG_ERROR(Kernel_SVC, "Address is not word aligned, address={:016X}", address);
|
||||
return ERR_INVALID_ADDRESS;
|
||||
}
|
||||
|
||||
@@ -1120,6 +1264,10 @@ static ResultCode WaitForAddress(VAddr address, u32 type, s32 value, s64 timeout
|
||||
case AddressArbiter::ArbitrationType::WaitIfEqual:
|
||||
return AddressArbiter::WaitForAddressIfEqual(address, value, timeout);
|
||||
default:
|
||||
LOG_ERROR(Kernel_SVC,
|
||||
"Invalid arbitration type, expected WaitIfLessThan, DecrementAndWaitIfLessThan "
|
||||
"or WaitIfEqual but got {}",
|
||||
type);
|
||||
return ERR_INVALID_ENUM_VALUE;
|
||||
}
|
||||
}
|
||||
@@ -1130,10 +1278,12 @@ static ResultCode SignalToAddress(VAddr address, u32 type, s32 value, s32 num_to
|
||||
address, type, value, num_to_wake);
|
||||
// If the passed address is a kernel virtual address, return invalid memory state.
|
||||
if (Memory::IsKernelVirtualAddress(address)) {
|
||||
LOG_ERROR(Kernel_SVC, "Address is a kernel virtual address, address={:016X}", address);
|
||||
return ERR_INVALID_ADDRESS_STATE;
|
||||
}
|
||||
// If the address is not properly aligned to 4 bytes, return invalid address.
|
||||
if (address % sizeof(u32) != 0) {
|
||||
if (!Common::IsWordAligned(address)) {
|
||||
LOG_ERROR(Kernel_SVC, "Address is not word aligned, address={:016X}", address);
|
||||
return ERR_INVALID_ADDRESS;
|
||||
}
|
||||
|
||||
@@ -1146,12 +1296,18 @@ static ResultCode SignalToAddress(VAddr address, u32 type, s32 value, s32 num_to
|
||||
return AddressArbiter::ModifyByWaitingCountAndSignalToAddressIfEqual(address, value,
|
||||
num_to_wake);
|
||||
default:
|
||||
LOG_ERROR(Kernel_SVC,
|
||||
"Invalid signal type, expected Signal, IncrementAndSignalIfEqual "
|
||||
"or ModifyByWaitingCountAndSignalIfEqual but got {}",
|
||||
type);
|
||||
return ERR_INVALID_ENUM_VALUE;
|
||||
}
|
||||
}
|
||||
|
||||
/// This returns the total CPU ticks elapsed since the CPU was powered-on
|
||||
static u64 GetSystemTick() {
|
||||
LOG_TRACE(Kernel_SVC, "called");
|
||||
|
||||
const u64 result{CoreTiming::GetTicks()};
|
||||
|
||||
// Advance time to defeat dumb games that busy-wait for the frame to end.
|
||||
@@ -1225,6 +1381,8 @@ static ResultCode GetThreadCoreMask(Handle thread_handle, u32* core, u64* mask)
|
||||
const auto& handle_table = Core::CurrentProcess()->GetHandleTable();
|
||||
const SharedPtr<Thread> thread = handle_table.Get<Thread>(thread_handle);
|
||||
if (!thread) {
|
||||
LOG_ERROR(Kernel_SVC, "Thread handle does not exist, thread_handle=0x{:08X}",
|
||||
thread_handle);
|
||||
return ERR_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
@@ -1235,12 +1393,14 @@ static ResultCode GetThreadCoreMask(Handle thread_handle, u32* core, u64* mask)
|
||||
}
|
||||
|
||||
static ResultCode SetThreadCoreMask(Handle thread_handle, u32 core, u64 mask) {
|
||||
LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, mask=0x{:16X}, core=0x{:X}", thread_handle,
|
||||
LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, mask=0x{:016X}, core=0x{:X}", thread_handle,
|
||||
mask, core);
|
||||
|
||||
const auto& handle_table = Core::CurrentProcess()->GetHandleTable();
|
||||
const SharedPtr<Thread> thread = handle_table.Get<Thread>(thread_handle);
|
||||
if (!thread) {
|
||||
LOG_ERROR(Kernel_SVC, "Thread handle does not exist, thread_handle=0x{:08X}",
|
||||
thread_handle);
|
||||
return ERR_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
@@ -1255,6 +1415,7 @@ static ResultCode SetThreadCoreMask(Handle thread_handle, u32 core, u64 mask) {
|
||||
}
|
||||
|
||||
if (mask == 0) {
|
||||
LOG_ERROR(Kernel_SVC, "Mask is 0");
|
||||
return ERR_INVALID_COMBINATION;
|
||||
}
|
||||
|
||||
@@ -1264,11 +1425,14 @@ static ResultCode SetThreadCoreMask(Handle thread_handle, u32 core, u64 mask) {
|
||||
if (core == OnlyChangeMask) {
|
||||
core = thread->GetIdealCore();
|
||||
} else if (core >= Core::NUM_CPU_CORES && core != static_cast<u32>(-1)) {
|
||||
LOG_ERROR(Kernel_SVC, "Invalid core specified, got {}", core);
|
||||
return ERR_INVALID_PROCESSOR_ID;
|
||||
}
|
||||
|
||||
// Error out if the input core isn't enabled in the input mask.
|
||||
if (core < Core::NUM_CPU_CORES && (mask & (1ull << core)) == 0) {
|
||||
LOG_ERROR(Kernel_SVC, "Core is not enabled for the current mask, core={}, mask={:016X}",
|
||||
core, mask);
|
||||
return ERR_INVALID_COMBINATION;
|
||||
}
|
||||
|
||||
@@ -1281,21 +1445,36 @@ static ResultCode CreateSharedMemory(Handle* handle, u64 size, u32 local_permiss
|
||||
u32 remote_permissions) {
|
||||
LOG_TRACE(Kernel_SVC, "called, size=0x{:X}, localPerms=0x{:08X}, remotePerms=0x{:08X}", size,
|
||||
local_permissions, remote_permissions);
|
||||
if (size == 0) {
|
||||
LOG_ERROR(Kernel_SVC, "Size is 0");
|
||||
return ERR_INVALID_SIZE;
|
||||
}
|
||||
if (!Common::Is4KBAligned(size)) {
|
||||
LOG_ERROR(Kernel_SVC, "Size is not aligned to 4KB, 0x{:016X}", size);
|
||||
return ERR_INVALID_SIZE;
|
||||
}
|
||||
|
||||
// Size must be a multiple of 4KB and be less than or equal to
|
||||
// approx. 8 GB (actually (1GB - 512B) * 8)
|
||||
if (size == 0 || (size & 0xFFFFFFFE00000FFF) != 0) {
|
||||
if (size >= MAIN_MEMORY_SIZE) {
|
||||
LOG_ERROR(Kernel_SVC, "Size is not less than 8GB, 0x{:016X}", size);
|
||||
return ERR_INVALID_SIZE;
|
||||
}
|
||||
|
||||
const auto local_perms = static_cast<MemoryPermission>(local_permissions);
|
||||
if (local_perms != MemoryPermission::Read && local_perms != MemoryPermission::ReadWrite) {
|
||||
LOG_ERROR(Kernel_SVC,
|
||||
"Invalid local memory permissions, expected Read or ReadWrite but got "
|
||||
"local_permissions={}",
|
||||
static_cast<u32>(local_permissions));
|
||||
return ERR_INVALID_MEMORY_PERMISSIONS;
|
||||
}
|
||||
|
||||
const auto remote_perms = static_cast<MemoryPermission>(remote_permissions);
|
||||
if (remote_perms != MemoryPermission::Read && remote_perms != MemoryPermission::ReadWrite &&
|
||||
remote_perms != MemoryPermission::DontCare) {
|
||||
LOG_ERROR(Kernel_SVC,
|
||||
"Invalid remote memory permissions, expected Read, ReadWrite or DontCare but got "
|
||||
"remote_permissions={}",
|
||||
static_cast<u32>(remote_permissions));
|
||||
return ERR_INVALID_MEMORY_PERMISSIONS;
|
||||
}
|
||||
|
||||
@@ -1315,6 +1494,7 @@ static ResultCode ClearEvent(Handle handle) {
|
||||
const auto& handle_table = Core::CurrentProcess()->GetHandleTable();
|
||||
SharedPtr<Event> evt = handle_table.Get<Event>(handle);
|
||||
if (evt == nullptr) {
|
||||
LOG_ERROR(Kernel_SVC, "Event handle does not exist, handle=0x{:08X}", handle);
|
||||
return ERR_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
@@ -1333,11 +1513,14 @@ static ResultCode GetProcessInfo(u64* out, Handle process_handle, u32 type) {
|
||||
const auto& handle_table = Core::CurrentProcess()->GetHandleTable();
|
||||
const auto process = handle_table.Get<Process>(process_handle);
|
||||
if (!process) {
|
||||
LOG_ERROR(Kernel_SVC, "Process handle does not exist, process_handle=0x{:08X}",
|
||||
process_handle);
|
||||
return ERR_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
const auto info_type = static_cast<InfoType>(type);
|
||||
if (info_type != InfoType::Status) {
|
||||
LOG_ERROR(Kernel_SVC, "Expected info_type to be Status but got {} instead", type);
|
||||
return ERR_INVALID_ENUM_VALUE;
|
||||
}
|
||||
|
||||
|
||||
@@ -216,10 +216,11 @@ void Module::Interface::GetLastOpenedUser(Kernel::HLERequestContext& ctx) {
|
||||
void Module::Interface::GetProfile(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
UUID user_id = rp.PopRaw<UUID>();
|
||||
LOG_DEBUG(Service_ACC, "called user_id={}", user_id.Format());
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<IProfile>(user_id, *profile_manager);
|
||||
LOG_DEBUG(Service_ACC, "called user_id={}", user_id.Format());
|
||||
}
|
||||
|
||||
void Module::Interface::IsUserRegistrationRequestPermitted(Kernel::HLERequestContext& ctx) {
|
||||
@@ -236,10 +237,10 @@ void Module::Interface::InitializeApplicationInfo(Kernel::HLERequestContext& ctx
|
||||
}
|
||||
|
||||
void Module::Interface::GetBaasAccountManagerForApplication(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_ACC, "called");
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<IManagerForApplication>();
|
||||
LOG_DEBUG(Service_ACC, "called");
|
||||
}
|
||||
|
||||
void Module::Interface::TrySelectUserWithoutInteraction(Kernel::HLERequestContext& ctx) {
|
||||
|
||||
@@ -6,8 +6,6 @@
|
||||
#include <cinttypes>
|
||||
#include <cstring>
|
||||
#include <stack>
|
||||
#include "applets/applets.h"
|
||||
#include "applets/software_keyboard.h"
|
||||
#include "audio_core/audio_renderer.h"
|
||||
#include "core/core.h"
|
||||
#include "core/hle/ipc_helpers.h"
|
||||
@@ -18,6 +16,9 @@
|
||||
#include "core/hle/service/am/am.h"
|
||||
#include "core/hle/service/am/applet_ae.h"
|
||||
#include "core/hle/service/am/applet_oe.h"
|
||||
#include "core/hle/service/am/applets/applets.h"
|
||||
#include "core/hle/service/am/applets/software_keyboard.h"
|
||||
#include "core/hle/service/am/applets/stub_applet.h"
|
||||
#include "core/hle/service/am/idle.h"
|
||||
#include "core/hle/service/am/omm.h"
|
||||
#include "core/hle/service/am/spsm.h"
|
||||
@@ -216,6 +217,7 @@ ISelfController::~ISelfController() = default;
|
||||
void ISelfController::SetFocusHandlingMode(Kernel::HLERequestContext& ctx) {
|
||||
// Takes 3 input u8s with each field located immediately after the previous
|
||||
// u8, these are bool flags. No output.
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
IPC::RequestParser rp{ctx};
|
||||
|
||||
@@ -228,44 +230,40 @@ void ISelfController::SetFocusHandlingMode(Kernel::HLERequestContext& ctx) {
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void ISelfController::SetRestartMessageEnabled(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void ISelfController::SetPerformanceModeChangedNotification(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
|
||||
bool flag = rp.Pop<bool>();
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called flag={}", flag);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called flag={}", flag);
|
||||
}
|
||||
|
||||
void ISelfController::SetScreenShotPermission(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void ISelfController::SetOperationModeChangedNotification(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
|
||||
bool flag = rp.Pop<bool>();
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called flag={}", flag);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called flag={}", flag);
|
||||
}
|
||||
|
||||
void ISelfController::SetOutOfFocusSuspendingEnabled(Kernel::HLERequestContext& ctx) {
|
||||
@@ -274,45 +272,45 @@ void ISelfController::SetOutOfFocusSuspendingEnabled(Kernel::HLERequestContext&
|
||||
IPC::RequestParser rp{ctx};
|
||||
|
||||
bool enabled = rp.Pop<bool>();
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called enabled={}", enabled);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called enabled={}", enabled);
|
||||
}
|
||||
|
||||
void ISelfController::LockExit(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void ISelfController::UnlockExit(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void ISelfController::GetLibraryAppletLaunchableEvent(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
launchable_event->Signal();
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushCopyObjects(launchable_event);
|
||||
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void ISelfController::SetScreenShotImageOrientation(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void ISelfController::CreateManagedDisplayLayer(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
// TODO(Subv): Find out how AM determines the display to use, for now just
|
||||
// create the layer in the Default display.
|
||||
u64 display_id = nvflinger->OpenDisplay("Default");
|
||||
@@ -321,32 +319,31 @@ void ISelfController::CreateManagedDisplayLayer(Kernel::HLERequestContext& ctx)
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push(layer_id);
|
||||
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void ISelfController::SetHandlesRequestToDisplay(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void ISelfController::SetIdleTimeDetectionExtension(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
idle_time_detection_extension = rp.Pop<u32>();
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called idle_time_detection_extension={}",
|
||||
idle_time_detection_extension);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void ISelfController::GetIdleTimeDetectionExtension(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push<u32>(idle_time_detection_extension);
|
||||
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
}
|
||||
|
||||
AppletMessageQueue::AppletMessageQueue() {
|
||||
@@ -437,59 +434,63 @@ ICommonStateGetter::ICommonStateGetter(std::shared_ptr<AppletMessageQueue> msg_q
|
||||
ICommonStateGetter::~ICommonStateGetter() = default;
|
||||
|
||||
void ICommonStateGetter::GetBootMode(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
|
||||
rb.Push<u8>(static_cast<u8>(Service::PM::SystemBootMode::Normal)); // Normal boot mode
|
||||
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
}
|
||||
|
||||
void ICommonStateGetter::GetEventHandle(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushCopyObjects(msg_queue->GetMesssageRecieveEvent());
|
||||
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
}
|
||||
|
||||
void ICommonStateGetter::ReceiveMessage(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushEnum<AppletMessageQueue::AppletMessage>(msg_queue->PopMessage());
|
||||
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
}
|
||||
|
||||
void ICommonStateGetter::GetCurrentFocusState(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push(static_cast<u8>(FocusState::InFocus));
|
||||
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void ICommonStateGetter::GetDefaultDisplayResolutionChangeEvent(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushCopyObjects(msg_queue->GetOperationModeChangedEvent());
|
||||
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
}
|
||||
|
||||
void ICommonStateGetter::GetDefaultDisplayResolution(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
|
||||
if (Settings::values.use_docked_mode) {
|
||||
rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedWidth));
|
||||
rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedHeight));
|
||||
rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedWidth) *
|
||||
static_cast<u32>(Settings::values.resolution_factor));
|
||||
rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedHeight) *
|
||||
static_cast<u32>(Settings::values.resolution_factor));
|
||||
} else {
|
||||
rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedWidth));
|
||||
rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedHeight));
|
||||
rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedWidth) *
|
||||
static_cast<u32>(Settings::values.resolution_factor));
|
||||
rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedHeight) *
|
||||
static_cast<u32>(Settings::values.resolution_factor));
|
||||
}
|
||||
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
}
|
||||
|
||||
IStorage::IStorage(std::vector<u8> buffer)
|
||||
@@ -512,28 +513,27 @@ const std::vector<u8>& IStorage::GetData() const {
|
||||
|
||||
void ICommonStateGetter::GetOperationMode(Kernel::HLERequestContext& ctx) {
|
||||
const bool use_docked_mode{Settings::values.use_docked_mode};
|
||||
LOG_DEBUG(Service_AM, "called, use_docked_mode={}", use_docked_mode);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push(static_cast<u8>(use_docked_mode ? OperationMode::Docked : OperationMode::Handheld));
|
||||
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
}
|
||||
|
||||
void ICommonStateGetter::GetPerformanceMode(Kernel::HLERequestContext& ctx) {
|
||||
const bool use_docked_mode{Settings::values.use_docked_mode};
|
||||
LOG_DEBUG(Service_AM, "called, use_docked_mode={}", use_docked_mode);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push(static_cast<u32>(use_docked_mode ? APM::PerformanceMode::Docked
|
||||
: APM::PerformanceMode::Handheld));
|
||||
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
}
|
||||
|
||||
class ILibraryAppletAccessor final : public ServiceFramework<ILibraryAppletAccessor> {
|
||||
public:
|
||||
explicit ILibraryAppletAccessor(std::shared_ptr<Applets::Applet> applet)
|
||||
: ServiceFramework("ILibraryAppletAccessor"), applet(std::move(applet)),
|
||||
broker(std::make_shared<Applets::AppletDataBroker>()) {
|
||||
: ServiceFramework("ILibraryAppletAccessor"), applet(std::move(applet)) {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &ILibraryAppletAccessor::GetAppletStateChangedEvent, "GetAppletStateChangedEvent"},
|
||||
@@ -562,71 +562,76 @@ public:
|
||||
|
||||
private:
|
||||
void GetAppletStateChangedEvent(Kernel::HLERequestContext& ctx) {
|
||||
const auto event = broker->GetStateChangedEvent();
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
const auto event = applet->GetBroker().GetStateChangedEvent();
|
||||
event->Signal();
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushCopyObjects(event);
|
||||
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
}
|
||||
|
||||
void IsCompleted(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push<u32>(applet->TransactionComplete());
|
||||
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
}
|
||||
|
||||
void GetResult(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(applet->GetStatus());
|
||||
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
}
|
||||
|
||||
void Start(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
ASSERT(applet != nullptr);
|
||||
|
||||
applet->Initialize(broker);
|
||||
applet->Initialize();
|
||||
applet->Execute();
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
}
|
||||
|
||||
void PushInData(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::RequestParser rp{ctx};
|
||||
broker->PushNormalDataFromGame(*rp.PopIpcInterface<IStorage>());
|
||||
applet->GetBroker().PushNormalDataFromGame(*rp.PopIpcInterface<IStorage>());
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
}
|
||||
|
||||
void PopOutData(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
|
||||
const auto storage = broker->PopNormalDataToGame();
|
||||
const auto storage = applet->GetBroker().PopNormalDataToGame();
|
||||
if (storage == nullptr) {
|
||||
LOG_ERROR(Service_AM,
|
||||
"storage is a nullptr. There is no data in the current normal channel");
|
||||
|
||||
rb.Push(ERR_NO_DATA_IN_CHANNEL);
|
||||
return;
|
||||
}
|
||||
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<IStorage>(std::move(*storage));
|
||||
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
}
|
||||
|
||||
void PushInteractiveInData(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::RequestParser rp{ctx};
|
||||
broker->PushInteractiveDataFromGame(*rp.PopIpcInterface<IStorage>());
|
||||
applet->GetBroker().PushInteractiveDataFromGame(*rp.PopIpcInterface<IStorage>());
|
||||
|
||||
ASSERT(applet->IsInitialized());
|
||||
applet->ExecuteInteractive();
|
||||
@@ -634,52 +639,52 @@ private:
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
}
|
||||
|
||||
void PopInteractiveOutData(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
|
||||
const auto storage = broker->PopInteractiveDataToGame();
|
||||
const auto storage = applet->GetBroker().PopInteractiveDataToGame();
|
||||
if (storage == nullptr) {
|
||||
LOG_ERROR(Service_AM,
|
||||
"storage is a nullptr. There is no data in the current interactive channel");
|
||||
|
||||
rb.Push(ERR_NO_DATA_IN_CHANNEL);
|
||||
return;
|
||||
}
|
||||
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<IStorage>(std::move(*storage));
|
||||
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
}
|
||||
|
||||
void GetPopOutDataEvent(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushCopyObjects(broker->GetNormalDataEvent());
|
||||
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
rb.PushCopyObjects(applet->GetBroker().GetNormalDataEvent());
|
||||
}
|
||||
|
||||
void GetPopInteractiveOutDataEvent(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushCopyObjects(broker->GetInteractiveDataEvent());
|
||||
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
rb.PushCopyObjects(applet->GetBroker().GetInteractiveDataEvent());
|
||||
}
|
||||
|
||||
std::shared_ptr<Applets::Applet> applet;
|
||||
std::shared_ptr<Applets::AppletDataBroker> broker;
|
||||
};
|
||||
|
||||
void IStorage::Open(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<IStorageAccessor>(*this);
|
||||
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
}
|
||||
|
||||
IStorageAccessor::IStorageAccessor(IStorage& storage)
|
||||
@@ -698,21 +703,27 @@ IStorageAccessor::IStorageAccessor(IStorage& storage)
|
||||
IStorageAccessor::~IStorageAccessor() = default;
|
||||
|
||||
void IStorageAccessor::GetSize(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push(static_cast<u64>(backing.buffer.size()));
|
||||
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
}
|
||||
|
||||
void IStorageAccessor::Write(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
|
||||
const u64 offset{rp.Pop<u64>()};
|
||||
LOG_DEBUG(Service_AM, "called, offset={}", offset);
|
||||
|
||||
const std::vector<u8> data{ctx.ReadBuffer()};
|
||||
|
||||
if (data.size() > backing.buffer.size() - offset) {
|
||||
LOG_ERROR(Service_AM,
|
||||
"offset is out of bounds, backing_buffer_sz={}, data_size={}, offset={}",
|
||||
backing.buffer.size(), data.size(), offset);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ERR_SIZE_OUT_OF_BOUNDS);
|
||||
}
|
||||
@@ -721,17 +732,20 @@ void IStorageAccessor::Write(Kernel::HLERequestContext& ctx) {
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
|
||||
LOG_DEBUG(Service_AM, "called, offset={}", offset);
|
||||
}
|
||||
|
||||
void IStorageAccessor::Read(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
|
||||
const u64 offset{rp.Pop<u64>()};
|
||||
LOG_DEBUG(Service_AM, "called, offset={}", offset);
|
||||
|
||||
const std::size_t size{ctx.GetWriteBufferSize()};
|
||||
|
||||
if (size > backing.buffer.size() - offset) {
|
||||
LOG_ERROR(Service_AM, "offset is out of bounds, backing_buffer_sz={}, size={}, offset={}",
|
||||
backing.buffer.size(), size, offset);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ERR_SIZE_OUT_OF_BOUNDS);
|
||||
}
|
||||
@@ -740,8 +754,6 @@ void IStorageAccessor::Read(Kernel::HLERequestContext& ctx) {
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
|
||||
LOG_DEBUG(Service_AM, "called, offset={}", offset);
|
||||
}
|
||||
|
||||
ILibraryAppletCreator::ILibraryAppletCreator() : ServiceFramework("ILibraryAppletCreator") {
|
||||
@@ -763,8 +775,9 @@ static std::shared_ptr<Applets::Applet> GetAppletFromId(AppletId id) {
|
||||
case AppletId::SoftwareKeyboard:
|
||||
return std::make_shared<Applets::SoftwareKeyboard>();
|
||||
default:
|
||||
UNREACHABLE_MSG("Unimplemented AppletId [{:08X}]!", static_cast<u32>(id));
|
||||
return nullptr;
|
||||
LOG_ERROR(Service_AM, "Unimplemented AppletId [{:08X}]! -- Falling back to stub!",
|
||||
static_cast<u32>(id));
|
||||
return std::make_shared<Applets::StubApplet>();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -779,6 +792,8 @@ void ILibraryAppletCreator::CreateLibraryApplet(Kernel::HLERequestContext& ctx)
|
||||
const auto applet = GetAppletFromId(applet_id);
|
||||
|
||||
if (applet == nullptr) {
|
||||
LOG_ERROR(Service_AM, "Applet doesn't exist! applet_id={}", static_cast<u32>(applet_id));
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultCode(-1));
|
||||
return;
|
||||
@@ -788,23 +803,23 @@ void ILibraryAppletCreator::CreateLibraryApplet(Kernel::HLERequestContext& ctx)
|
||||
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<AM::ILibraryAppletAccessor>(applet);
|
||||
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
}
|
||||
|
||||
void ILibraryAppletCreator::CreateStorage(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const u64 size{rp.Pop<u64>()};
|
||||
LOG_DEBUG(Service_AM, "called, size={}", size);
|
||||
|
||||
std::vector<u8> buffer(size);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<AM::IStorage>(std::move(buffer));
|
||||
|
||||
LOG_DEBUG(Service_AM, "called, size={}", size);
|
||||
}
|
||||
|
||||
void ILibraryAppletCreator::CreateTransferMemoryStorage(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::RequestParser rp{ctx};
|
||||
|
||||
rp.SetCurrentOffset(3);
|
||||
@@ -815,6 +830,7 @@ void ILibraryAppletCreator::CreateTransferMemoryStorage(Kernel::HLERequestContex
|
||||
handle);
|
||||
|
||||
if (shared_mem == nullptr) {
|
||||
LOG_ERROR(Service_AM, "shared_mem is a nullpr for handle={:08X}", handle);
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultCode(-1));
|
||||
return;
|
||||
@@ -878,38 +894,45 @@ IApplicationFunctions::IApplicationFunctions() : ServiceFramework("IApplicationF
|
||||
IApplicationFunctions::~IApplicationFunctions() = default;
|
||||
|
||||
void IApplicationFunctions::EnableApplicationCrashReport(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void IApplicationFunctions::BeginBlockingHomeButtonShortAndLongPressed(
|
||||
Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void IApplicationFunctions::EndBlockingHomeButtonShortAndLongPressed(
|
||||
Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void IApplicationFunctions::BeginBlockingHomeButton(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void IApplicationFunctions::EndBlockingHomeButton(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void IApplicationFunctions::PopLaunchParameter(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
LaunchParameters params{};
|
||||
|
||||
params.magic = POP_LAUNCH_PARAMETER_MAGIC;
|
||||
@@ -928,21 +951,19 @@ void IApplicationFunctions::PopLaunchParameter(Kernel::HLERequestContext& ctx) {
|
||||
std::memcpy(buffer.data(), ¶ms, buffer.size());
|
||||
|
||||
rb.PushIpcInterface<AM::IStorage>(buffer);
|
||||
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
}
|
||||
|
||||
void IApplicationFunctions::CreateApplicationAndRequestToStartForQuest(
|
||||
Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void IApplicationFunctions::EnsureSaveData(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
u128 uid = rp.PopRaw<u128>(); // What does this do?
|
||||
|
||||
LOG_WARNING(Service, "(STUBBED) called uid = {:016X}{:016X}", uid[1], uid[0]);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
@@ -957,60 +978,62 @@ void IApplicationFunctions::SetTerminateResult(Kernel::HLERequestContext& ctx) {
|
||||
|
||||
IPC::RequestParser rp{ctx};
|
||||
u32 result = rp.Pop<u32>();
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called, result=0x{:08X}", result);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called, result=0x{:08X}", result);
|
||||
}
|
||||
|
||||
void IApplicationFunctions::GetDisplayVersion(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 6};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push<u64>(1);
|
||||
rb.Push<u64>(0);
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void IApplicationFunctions::GetDesiredLanguage(Kernel::HLERequestContext& ctx) {
|
||||
// TODO(bunnei): This should be configurable
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push(
|
||||
static_cast<u64>(Service::Set::GetLanguageCodeFromIndex(Settings::values.language_index)));
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
}
|
||||
|
||||
void IApplicationFunctions::InitializeGamePlayRecording(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void IApplicationFunctions::SetGamePlayRecordingState(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void IApplicationFunctions::NotifyRunning(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push<u8>(0); // Unknown, seems to be ignored by official processes
|
||||
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void IApplicationFunctions::GetPseudoDeviceId(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 6};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
|
||||
// Returns a 128-bit UUID
|
||||
rb.Push<u64>(0);
|
||||
rb.Push<u64>(0);
|
||||
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void InstallInterfaces(SM::ServiceManager& service_manager,
|
||||
@@ -1047,9 +1070,10 @@ IHomeMenuFunctions::IHomeMenuFunctions() : ServiceFramework("IHomeMenuFunctions"
|
||||
IHomeMenuFunctions::~IHomeMenuFunctions() = default;
|
||||
|
||||
void IHomeMenuFunctions::RequestToGetForeground(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
}
|
||||
|
||||
IGlobalStateController::IGlobalStateController() : ServiceFramework("IGlobalStateController") {
|
||||
|
||||
@@ -32,66 +32,75 @@ public:
|
||||
|
||||
private:
|
||||
void GetCommonStateGetter(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<ICommonStateGetter>(msg_queue);
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
}
|
||||
|
||||
void GetSelfController(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<ISelfController>(nvflinger);
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
}
|
||||
|
||||
void GetWindowController(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<IWindowController>();
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
}
|
||||
|
||||
void GetAudioController(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<IAudioController>();
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
}
|
||||
|
||||
void GetDisplayController(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<IDisplayController>();
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
}
|
||||
|
||||
void GetProcessWindingController(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<IProcessWindingController>();
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
}
|
||||
|
||||
void GetDebugFunctions(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<IDebugFunctions>();
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
}
|
||||
|
||||
void GetLibraryAppletCreator(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<ILibraryAppletCreator>();
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
}
|
||||
|
||||
void GetApplicationFunctions(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<IApplicationFunctions>();
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
}
|
||||
|
||||
std::shared_ptr<NVFlinger::NVFlinger> nvflinger;
|
||||
@@ -122,97 +131,110 @@ public:
|
||||
|
||||
private:
|
||||
void GetCommonStateGetter(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<ICommonStateGetter>(msg_queue);
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
}
|
||||
|
||||
void GetSelfController(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<ISelfController>(nvflinger);
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
}
|
||||
|
||||
void GetWindowController(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<IWindowController>();
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
}
|
||||
|
||||
void GetAudioController(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<IAudioController>();
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
}
|
||||
|
||||
void GetDisplayController(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<IDisplayController>();
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
}
|
||||
|
||||
void GetDebugFunctions(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<IDebugFunctions>();
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
}
|
||||
|
||||
void GetLibraryAppletCreator(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<ILibraryAppletCreator>();
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
}
|
||||
|
||||
void GetHomeMenuFunctions(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<IHomeMenuFunctions>();
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
}
|
||||
|
||||
void GetGlobalStateController(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<IGlobalStateController>();
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
}
|
||||
|
||||
void GetApplicationCreator(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<IApplicationCreator>();
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
}
|
||||
std::shared_ptr<NVFlinger::NVFlinger> nvflinger;
|
||||
std::shared_ptr<AppletMessageQueue> msg_queue;
|
||||
};
|
||||
|
||||
void AppletAE::OpenSystemAppletProxy(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<ISystemAppletProxy>(nvflinger, msg_queue);
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
}
|
||||
|
||||
void AppletAE::OpenLibraryAppletProxy(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<ILibraryAppletProxy>(nvflinger, msg_queue);
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
}
|
||||
|
||||
void AppletAE::OpenLibraryAppletProxyOld(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<ILibraryAppletProxy>(nvflinger, msg_queue);
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
}
|
||||
|
||||
AppletAE::AppletAE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger,
|
||||
|
||||
@@ -35,59 +35,67 @@ public:
|
||||
|
||||
private:
|
||||
void GetAudioController(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<IAudioController>();
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
}
|
||||
|
||||
void GetDisplayController(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<IDisplayController>();
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
}
|
||||
|
||||
void GetDebugFunctions(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<IDebugFunctions>();
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
}
|
||||
|
||||
void GetWindowController(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<IWindowController>();
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
}
|
||||
|
||||
void GetSelfController(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<ISelfController>(nvflinger);
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
}
|
||||
|
||||
void GetCommonStateGetter(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<ICommonStateGetter>(msg_queue);
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
}
|
||||
|
||||
void GetLibraryAppletCreator(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<ILibraryAppletCreator>();
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
}
|
||||
|
||||
void GetApplicationFunctions(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<IApplicationFunctions>();
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
}
|
||||
|
||||
std::shared_ptr<NVFlinger::NVFlinger> nvflinger;
|
||||
@@ -95,10 +103,11 @@ private:
|
||||
};
|
||||
|
||||
void AppletOE::OpenApplicationProxy(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<IApplicationProxy>(nvflinger, msg_queue);
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
}
|
||||
|
||||
AppletOE::AppletOE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger,
|
||||
|
||||
@@ -98,10 +98,8 @@ Applet::Applet() = default;
|
||||
|
||||
Applet::~Applet() = default;
|
||||
|
||||
void Applet::Initialize(std::shared_ptr<AppletDataBroker> broker_) {
|
||||
broker = std::move(broker_);
|
||||
|
||||
const auto common = broker->PopNormalDataToApplet();
|
||||
void Applet::Initialize() {
|
||||
const auto common = broker.PopNormalDataToApplet();
|
||||
ASSERT(common != nullptr);
|
||||
|
||||
const auto common_data = common->GetData();
|
||||
|
||||
@@ -4,14 +4,17 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <queue>
|
||||
#include "common/swap.h"
|
||||
#include "core/hle/kernel/event.h"
|
||||
#include "core/hle/kernel/kernel.h"
|
||||
|
||||
union ResultCode;
|
||||
|
||||
namespace Kernel {
|
||||
class Event;
|
||||
}
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
class IStorage;
|
||||
@@ -43,19 +46,26 @@ public:
|
||||
|
||||
private:
|
||||
// Queues are named from applet's perspective
|
||||
std::queue<std::unique_ptr<IStorage>>
|
||||
in_channel; // PopNormalDataToApplet and PushNormalDataFromGame
|
||||
std::queue<std::unique_ptr<IStorage>>
|
||||
out_channel; // PopNormalDataToGame and PushNormalDataFromApplet
|
||||
std::queue<std::unique_ptr<IStorage>>
|
||||
in_interactive_channel; // PopInteractiveDataToApplet and PushInteractiveDataFromGame
|
||||
std::queue<std::unique_ptr<IStorage>>
|
||||
out_interactive_channel; // PopInteractiveDataToGame and PushInteractiveDataFromApplet
|
||||
|
||||
// PopNormalDataToApplet and PushNormalDataFromGame
|
||||
std::queue<std::unique_ptr<IStorage>> in_channel;
|
||||
|
||||
// PopNormalDataToGame and PushNormalDataFromApplet
|
||||
std::queue<std::unique_ptr<IStorage>> out_channel;
|
||||
|
||||
// PopInteractiveDataToApplet and PushInteractiveDataFromGame
|
||||
std::queue<std::unique_ptr<IStorage>> in_interactive_channel;
|
||||
|
||||
// PopInteractiveDataToGame and PushInteractiveDataFromApplet
|
||||
std::queue<std::unique_ptr<IStorage>> out_interactive_channel;
|
||||
|
||||
Kernel::SharedPtr<Kernel::Event> state_changed_event;
|
||||
Kernel::SharedPtr<Kernel::Event> pop_out_data_event; // Signaled on PushNormalDataFromApplet
|
||||
Kernel::SharedPtr<Kernel::Event>
|
||||
pop_interactive_out_data_event; // Signaled on PushInteractiveDataFromApplet
|
||||
|
||||
// Signaled on PushNormalDataFromApplet
|
||||
Kernel::SharedPtr<Kernel::Event> pop_out_data_event;
|
||||
|
||||
// Signaled on PushInteractiveDataFromApplet
|
||||
Kernel::SharedPtr<Kernel::Event> pop_interactive_out_data_event;
|
||||
};
|
||||
|
||||
class Applet {
|
||||
@@ -63,7 +73,7 @@ public:
|
||||
Applet();
|
||||
virtual ~Applet();
|
||||
|
||||
virtual void Initialize(std::shared_ptr<AppletDataBroker> broker);
|
||||
virtual void Initialize();
|
||||
|
||||
virtual bool TransactionComplete() const = 0;
|
||||
virtual ResultCode GetStatus() const = 0;
|
||||
@@ -74,6 +84,14 @@ public:
|
||||
return initialized;
|
||||
}
|
||||
|
||||
AppletDataBroker& GetBroker() {
|
||||
return broker;
|
||||
}
|
||||
|
||||
const AppletDataBroker& GetBroker() const {
|
||||
return broker;
|
||||
}
|
||||
|
||||
protected:
|
||||
struct CommonArguments {
|
||||
u32_le arguments_version;
|
||||
@@ -85,8 +103,8 @@ protected:
|
||||
};
|
||||
static_assert(sizeof(CommonArguments) == 0x20, "CommonArguments has incorrect size.");
|
||||
|
||||
CommonArguments common_args;
|
||||
std::shared_ptr<AppletDataBroker> broker;
|
||||
CommonArguments common_args{};
|
||||
AppletDataBroker broker;
|
||||
bool initialized = false;
|
||||
};
|
||||
|
||||
|
||||
@@ -42,21 +42,21 @@ SoftwareKeyboard::SoftwareKeyboard() = default;
|
||||
|
||||
SoftwareKeyboard::~SoftwareKeyboard() = default;
|
||||
|
||||
void SoftwareKeyboard::Initialize(std::shared_ptr<AppletDataBroker> broker_) {
|
||||
void SoftwareKeyboard::Initialize() {
|
||||
complete = false;
|
||||
initial_text.clear();
|
||||
final_data.clear();
|
||||
|
||||
Applet::Initialize(std::move(broker_));
|
||||
Applet::Initialize();
|
||||
|
||||
const auto keyboard_config_storage = broker->PopNormalDataToApplet();
|
||||
const auto keyboard_config_storage = broker.PopNormalDataToApplet();
|
||||
ASSERT(keyboard_config_storage != nullptr);
|
||||
const auto& keyboard_config = keyboard_config_storage->GetData();
|
||||
|
||||
ASSERT(keyboard_config.size() >= sizeof(KeyboardConfig));
|
||||
std::memcpy(&config, keyboard_config.data(), sizeof(KeyboardConfig));
|
||||
|
||||
const auto work_buffer_storage = broker->PopNormalDataToApplet();
|
||||
const auto work_buffer_storage = broker.PopNormalDataToApplet();
|
||||
ASSERT(work_buffer_storage != nullptr);
|
||||
const auto& work_buffer = work_buffer_storage->GetData();
|
||||
|
||||
@@ -81,7 +81,7 @@ void SoftwareKeyboard::ExecuteInteractive() {
|
||||
if (complete)
|
||||
return;
|
||||
|
||||
const auto storage = broker->PopInteractiveDataToApplet();
|
||||
const auto storage = broker.PopInteractiveDataToApplet();
|
||||
ASSERT(storage != nullptr);
|
||||
const auto data = storage->GetData();
|
||||
const auto status = static_cast<bool>(data[0]);
|
||||
@@ -95,13 +95,13 @@ void SoftwareKeyboard::ExecuteInteractive() {
|
||||
std::memcpy(string.data(), data.data() + 4, string.size() * 2);
|
||||
frontend.SendTextCheckDialog(
|
||||
Common::UTF16StringFromFixedZeroTerminatedBuffer(string.data(), string.size()),
|
||||
[this] { broker->SignalStateChanged(); });
|
||||
[this] { broker.SignalStateChanged(); });
|
||||
}
|
||||
}
|
||||
|
||||
void SoftwareKeyboard::Execute() {
|
||||
if (complete) {
|
||||
broker->PushNormalDataFromApplet(IStorage{final_data});
|
||||
broker.PushNormalDataFromApplet(IStorage{final_data});
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -145,17 +145,17 @@ void SoftwareKeyboard::WriteText(std::optional<std::u16string> text) {
|
||||
final_data = output_main;
|
||||
|
||||
if (complete) {
|
||||
broker->PushNormalDataFromApplet(IStorage{output_main});
|
||||
broker.PushNormalDataFromApplet(IStorage{output_main});
|
||||
} else {
|
||||
broker->PushInteractiveDataFromApplet(IStorage{output_sub});
|
||||
broker.PushInteractiveDataFromApplet(IStorage{output_sub});
|
||||
}
|
||||
|
||||
broker->SignalStateChanged();
|
||||
broker.SignalStateChanged();
|
||||
} else {
|
||||
output_main[0] = 1;
|
||||
complete = true;
|
||||
broker->PushNormalDataFromApplet(IStorage{output_main});
|
||||
broker->SignalStateChanged();
|
||||
broker.PushNormalDataFromApplet(IStorage{output_main});
|
||||
broker.SignalStateChanged();
|
||||
}
|
||||
}
|
||||
} // namespace Service::AM::Applets
|
||||
|
||||
@@ -4,7 +4,12 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/swap.h"
|
||||
#include "core/hle/service/am/am.h"
|
||||
#include "core/hle/service/am/applets/applets.h"
|
||||
|
||||
@@ -50,7 +55,7 @@ public:
|
||||
SoftwareKeyboard();
|
||||
~SoftwareKeyboard() override;
|
||||
|
||||
void Initialize(std::shared_ptr<AppletDataBroker> broker) override;
|
||||
void Initialize() override;
|
||||
|
||||
bool TransactionComplete() const override;
|
||||
ResultCode GetStatus() const override;
|
||||
|
||||
70
src/core/hle/service/am/applets/stub_applet.cpp
Normal file
70
src/core/hle/service/am/applets/stub_applet.cpp
Normal file
@@ -0,0 +1,70 @@
|
||||
// Copyright 2018 yuzu emulator team
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "common/hex_util.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "core/hle/result.h"
|
||||
#include "core/hle/service/am/am.h"
|
||||
#include "core/hle/service/am/applets/stub_applet.h"
|
||||
|
||||
namespace Service::AM::Applets {
|
||||
|
||||
static void LogCurrentStorage(AppletDataBroker& broker, std::string prefix) {
|
||||
std::unique_ptr<IStorage> storage = broker.PopNormalDataToApplet();
|
||||
for (; storage != nullptr; storage = broker.PopNormalDataToApplet()) {
|
||||
const auto data = storage->GetData();
|
||||
LOG_INFO(Service_AM,
|
||||
"called (STUBBED), during {} recieved normal data with size={:08X}, data={}",
|
||||
prefix, data.size(), Common::HexVectorToString(data));
|
||||
}
|
||||
|
||||
storage = broker.PopInteractiveDataToApplet();
|
||||
for (; storage != nullptr; storage = broker.PopInteractiveDataToApplet()) {
|
||||
const auto data = storage->GetData();
|
||||
LOG_INFO(Service_AM,
|
||||
"called (STUBBED), during {} recieved interactive data with size={:08X}, data={}",
|
||||
prefix, data.size(), Common::HexVectorToString(data));
|
||||
}
|
||||
}
|
||||
|
||||
StubApplet::StubApplet() = default;
|
||||
|
||||
StubApplet::~StubApplet() = default;
|
||||
|
||||
void StubApplet::Initialize() {
|
||||
LOG_WARNING(Service_AM, "called (STUBBED)");
|
||||
Applet::Initialize();
|
||||
LogCurrentStorage(broker, "Initialize");
|
||||
}
|
||||
|
||||
bool StubApplet::TransactionComplete() const {
|
||||
LOG_WARNING(Service_AM, "called (STUBBED)");
|
||||
return true;
|
||||
}
|
||||
|
||||
ResultCode StubApplet::GetStatus() const {
|
||||
LOG_WARNING(Service_AM, "called (STUBBED)");
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
void StubApplet::ExecuteInteractive() {
|
||||
LOG_WARNING(Service_AM, "called (STUBBED)");
|
||||
LogCurrentStorage(broker, "ExecuteInteractive");
|
||||
|
||||
broker.PushNormalDataFromApplet(IStorage{std::vector<u8>(0x1000)});
|
||||
broker.PushInteractiveDataFromApplet(IStorage{std::vector<u8>(0x1000)});
|
||||
broker.SignalStateChanged();
|
||||
}
|
||||
|
||||
void StubApplet::Execute() {
|
||||
LOG_WARNING(Service_AM, "called (STUBBED)");
|
||||
LogCurrentStorage(broker, "Execute");
|
||||
|
||||
broker.PushNormalDataFromApplet(IStorage{std::vector<u8>(0x1000)});
|
||||
broker.PushInteractiveDataFromApplet(IStorage{std::vector<u8>(0x1000)});
|
||||
broker.SignalStateChanged();
|
||||
}
|
||||
} // namespace Service::AM::Applets
|
||||
24
src/core/hle/service/am/applets/stub_applet.h
Normal file
24
src/core/hle/service/am/applets/stub_applet.h
Normal file
@@ -0,0 +1,24 @@
|
||||
// Copyright 2018 yuzu emulator team
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/hle/service/am/applets/applets.h"
|
||||
|
||||
namespace Service::AM::Applets {
|
||||
|
||||
class StubApplet final : public Applet {
|
||||
public:
|
||||
StubApplet();
|
||||
~StubApplet() override;
|
||||
|
||||
void Initialize() override;
|
||||
|
||||
bool TransactionComplete() const override;
|
||||
ResultCode GetStatus() const override;
|
||||
void ExecuteInteractive() override;
|
||||
void Execute() override;
|
||||
};
|
||||
|
||||
} // namespace Service::AM::Applets
|
||||
@@ -68,6 +68,8 @@ AOC_U::AOC_U() : ServiceFramework("aoc:u"), add_on_content(AccumulateAOCTitleIDs
|
||||
AOC_U::~AOC_U() = default;
|
||||
|
||||
void AOC_U::CountAddOnContent(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AOC, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
|
||||
@@ -82,6 +84,7 @@ void AOC_U::ListAddOnContent(Kernel::HLERequestContext& ctx) {
|
||||
|
||||
const auto offset = rp.PopRaw<u32>();
|
||||
auto count = rp.PopRaw<u32>();
|
||||
LOG_DEBUG(Service_AOC, "called with offset={}, count={}", offset, count);
|
||||
|
||||
const auto current = Core::System::GetInstance().CurrentProcess()->GetTitleID();
|
||||
|
||||
@@ -110,6 +113,8 @@ void AOC_U::ListAddOnContent(Kernel::HLERequestContext& ctx) {
|
||||
}
|
||||
|
||||
void AOC_U::GetAddOnContentBaseId(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AOC, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
const auto title_id = Core::System::GetInstance().CurrentProcess()->GetTitleID();
|
||||
@@ -128,7 +133,6 @@ void AOC_U::PrepareAddOnContent(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
|
||||
const auto aoc_id = rp.PopRaw<u32>();
|
||||
|
||||
LOG_WARNING(Service_AOC, "(STUBBED) called with aoc_id={:08X}", aoc_id);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
|
||||
@@ -40,24 +40,22 @@ private:
|
||||
|
||||
auto mode = static_cast<PerformanceMode>(rp.Pop<u32>());
|
||||
u32 config = rp.Pop<u32>();
|
||||
LOG_WARNING(Service_APM, "(STUBBED) called mode={} config={}", static_cast<u32>(mode),
|
||||
config);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
|
||||
LOG_WARNING(Service_APM, "(STUBBED) called mode={} config={}", static_cast<u32>(mode),
|
||||
config);
|
||||
}
|
||||
|
||||
void GetPerformanceConfiguration(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
|
||||
auto mode = static_cast<PerformanceMode>(rp.Pop<u32>());
|
||||
LOG_WARNING(Service_APM, "(STUBBED) called mode={}", static_cast<u32>(mode));
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push<u32>(static_cast<u32>(PerformanceConfiguration::Config1));
|
||||
|
||||
LOG_WARNING(Service_APM, "(STUBBED) called mode={}", static_cast<u32>(mode));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -73,11 +71,11 @@ APM::APM(std::shared_ptr<Module> apm, const char* name)
|
||||
APM::~APM() = default;
|
||||
|
||||
void APM::OpenSession(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_APM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<ISession>();
|
||||
|
||||
LOG_DEBUG(Service_APM, "called");
|
||||
}
|
||||
|
||||
APM_Sys::APM_Sys() : ServiceFramework{"apm:sys"} {
|
||||
@@ -98,11 +96,11 @@ APM_Sys::APM_Sys() : ServiceFramework{"apm:sys"} {
|
||||
APM_Sys::~APM_Sys() = default;
|
||||
|
||||
void APM_Sys::GetPerformanceEvent(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_APM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<ISession>();
|
||||
|
||||
LOG_DEBUG(Service_APM, "called");
|
||||
}
|
||||
|
||||
} // namespace Service::APM
|
||||
|
||||
@@ -59,11 +59,11 @@ public:
|
||||
|
||||
private:
|
||||
void AcquireRegistrar(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_ARP, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<IRegistrar>();
|
||||
|
||||
LOG_DEBUG(Service_ARP, "called");
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -44,8 +44,10 @@ enum class AudioState : u32 {
|
||||
|
||||
class IAudioOut final : public ServiceFramework<IAudioOut> {
|
||||
public:
|
||||
IAudioOut(AudoutParams audio_params, AudioCore::AudioOut& audio_core)
|
||||
: ServiceFramework("IAudioOut"), audio_core(audio_core), audio_params(audio_params) {
|
||||
IAudioOut(AudoutParams audio_params, AudioCore::AudioOut& audio_core, std::string&& device_name,
|
||||
std::string&& unique_name)
|
||||
: ServiceFramework("IAudioOut"), audio_core(audio_core), audio_params(audio_params),
|
||||
device_name(std::move(device_name)) {
|
||||
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &IAudioOut::GetAudioOutState, "GetAudioOutState"},
|
||||
@@ -69,7 +71,7 @@ public:
|
||||
Kernel::Event::Create(kernel, Kernel::ResetType::Sticky, "IAudioOutBufferReleased");
|
||||
|
||||
stream = audio_core.OpenStream(audio_params.sample_rate, audio_params.channel_count,
|
||||
"IAudioOut", [=]() { buffer_event->Signal(); });
|
||||
std::move(unique_name), [=]() { buffer_event->Signal(); });
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -84,6 +86,7 @@ private:
|
||||
|
||||
void GetAudioOutState(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Audio, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push(static_cast<u32>(stream->IsPlaying() ? AudioState::Started : AudioState::Stopped));
|
||||
@@ -146,6 +149,7 @@ private:
|
||||
|
||||
void GetReleasedAudioOutBufferImpl(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Audio, "called {}", ctx.Description());
|
||||
|
||||
IPC::RequestParser rp{ctx};
|
||||
const u64 max_count{ctx.GetWriteBufferSize() / sizeof(u64)};
|
||||
const auto released_buffers{audio_core.GetTagsAndReleaseBuffers(stream, max_count)};
|
||||
@@ -161,6 +165,7 @@ private:
|
||||
|
||||
void ContainsAudioOutBuffer(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Audio, "called");
|
||||
|
||||
IPC::RequestParser rp{ctx};
|
||||
const u64 tag{rp.Pop<u64>()};
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
@@ -170,6 +175,7 @@ private:
|
||||
|
||||
void GetAudioOutBufferCount(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Audio, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push(static_cast<u32>(stream->GetQueueSize()));
|
||||
@@ -177,6 +183,7 @@ private:
|
||||
|
||||
AudioCore::AudioOut& audio_core;
|
||||
AudioCore::StreamPtr stream;
|
||||
std::string device_name;
|
||||
|
||||
AudoutParams audio_params{};
|
||||
|
||||
@@ -186,6 +193,7 @@ private:
|
||||
|
||||
void AudOutU::ListAudioOutsImpl(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Audio, "called");
|
||||
|
||||
IPC::RequestParser rp{ctx};
|
||||
|
||||
ctx.WriteBuffer(DefaultDevice);
|
||||
@@ -199,7 +207,15 @@ void AudOutU::ListAudioOutsImpl(Kernel::HLERequestContext& ctx) {
|
||||
void AudOutU::OpenAudioOutImpl(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Audio, "called");
|
||||
|
||||
ctx.WriteBuffer(DefaultDevice);
|
||||
const auto device_name_data{ctx.ReadBuffer()};
|
||||
std::string device_name;
|
||||
if (device_name_data[0] != '\0') {
|
||||
device_name.assign(device_name_data.begin(), device_name_data.end());
|
||||
} else {
|
||||
device_name.assign(DefaultDevice.begin(), DefaultDevice.end());
|
||||
}
|
||||
ctx.WriteBuffer(device_name);
|
||||
|
||||
IPC::RequestParser rp{ctx};
|
||||
auto params{rp.PopRaw<AudoutParams>()};
|
||||
if (params.channel_count <= 2) {
|
||||
@@ -212,10 +228,9 @@ void AudOutU::OpenAudioOutImpl(Kernel::HLERequestContext& ctx) {
|
||||
params.sample_rate = DefaultSampleRate;
|
||||
}
|
||||
|
||||
// TODO(bunnei): Support more than one IAudioOut interface. When we add this, ListAudioOutsImpl
|
||||
// will likely need to be updated as well.
|
||||
ASSERT_MSG(!audio_out_interface, "Unimplemented");
|
||||
audio_out_interface = std::make_shared<IAudioOut>(params, *audio_core);
|
||||
std::string unique_name{fmt::format("{}-{}", device_name, audio_out_interfaces.size())};
|
||||
auto audio_out_interface = std::make_shared<IAudioOut>(
|
||||
params, *audio_core, std::move(device_name), std::move(unique_name));
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 6, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
@@ -224,6 +239,8 @@ void AudOutU::OpenAudioOutImpl(Kernel::HLERequestContext& ctx) {
|
||||
rb.Push<u32>(static_cast<u32>(AudioCore::Codec::PcmFormat::Int16));
|
||||
rb.Push<u32>(static_cast<u32>(AudioState::Stopped));
|
||||
rb.PushIpcInterface<Audio::IAudioOut>(audio_out_interface);
|
||||
|
||||
audio_out_interfaces.push_back(std::move(audio_out_interface));
|
||||
}
|
||||
|
||||
AudOutU::AudOutU() : ServiceFramework("audout:u") {
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
namespace AudioCore {
|
||||
@@ -24,7 +25,7 @@ public:
|
||||
~AudOutU() override;
|
||||
|
||||
private:
|
||||
std::shared_ptr<IAudioOut> audio_out_interface;
|
||||
std::vector<std::shared_ptr<IAudioOut>> audio_out_interfaces;
|
||||
std::unique_ptr<AudioCore::AudioOut> audio_core;
|
||||
|
||||
void ListAudioOutsImpl(Kernel::HLERequestContext& ctx);
|
||||
|
||||
@@ -52,74 +52,79 @@ private:
|
||||
}
|
||||
|
||||
void GetSampleRate(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Audio, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push<u32>(renderer->GetSampleRate());
|
||||
LOG_DEBUG(Service_Audio, "called");
|
||||
}
|
||||
|
||||
void GetSampleCount(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Audio, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push<u32>(renderer->GetSampleCount());
|
||||
LOG_DEBUG(Service_Audio, "called");
|
||||
}
|
||||
|
||||
void GetState(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Audio, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push<u32>(static_cast<u32>(renderer->GetStreamState()));
|
||||
LOG_DEBUG(Service_Audio, "called");
|
||||
}
|
||||
|
||||
void GetMixBufferCount(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Audio, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push<u32>(renderer->GetMixBufferCount());
|
||||
LOG_DEBUG(Service_Audio, "called");
|
||||
}
|
||||
|
||||
void RequestUpdateImpl(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_Audio, "(STUBBED) called");
|
||||
|
||||
ctx.WriteBuffer(renderer->UpdateAudioRenderer(ctx.ReadBuffer()));
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_WARNING(Service_Audio, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void Start(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_Audio, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
|
||||
LOG_WARNING(Service_Audio, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void Stop(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_Audio, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
|
||||
LOG_WARNING(Service_Audio, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void QuerySystemEvent(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_Audio, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushCopyObjects(system_event);
|
||||
|
||||
LOG_WARNING(Service_Audio, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void SetRenderingTimeLimit(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
rendering_time_limit_percent = rp.Pop<u32>();
|
||||
LOG_DEBUG(Service_Audio, "called. rendering_time_limit_percent={}",
|
||||
rendering_time_limit_percent);
|
||||
|
||||
ASSERT(rendering_time_limit_percent >= 0 && rendering_time_limit_percent <= 100);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
|
||||
LOG_DEBUG(Service_Audio, "called. rendering_time_limit_percent={}",
|
||||
rendering_time_limit_percent);
|
||||
}
|
||||
|
||||
void GetRenderingTimeLimit(Kernel::HLERequestContext& ctx) {
|
||||
@@ -211,6 +216,7 @@ private:
|
||||
|
||||
void GetActiveChannelCount(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_Audio, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push<u32>(1);
|
||||
@@ -235,19 +241,20 @@ AudRenU::AudRenU() : ServiceFramework("audren:u") {
|
||||
AudRenU::~AudRenU() = default;
|
||||
|
||||
void AudRenU::OpenAudioRenderer(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Audio, "called");
|
||||
|
||||
IPC::RequestParser rp{ctx};
|
||||
auto params = rp.PopRaw<AudioCore::AudioRendererParameter>();
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<Audio::IAudioRenderer>(std::move(params));
|
||||
|
||||
LOG_DEBUG(Service_Audio, "called");
|
||||
}
|
||||
|
||||
void AudRenU::GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
auto params = rp.PopRaw<AudioCore::AudioRendererParameter>();
|
||||
LOG_DEBUG(Service_Audio, "called");
|
||||
|
||||
u64 buffer_sz = Common::AlignUp(4 * params.mix_buffer_count, 0x40);
|
||||
buffer_sz += params.unknown_c * 1024;
|
||||
@@ -301,26 +308,26 @@ void AudRenU::GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx) {
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push<u64>(output_sz);
|
||||
|
||||
LOG_DEBUG(Service_Audio, "called, buffer_size=0x{:X}", output_sz);
|
||||
LOG_DEBUG(Service_Audio, "buffer_size=0x{:X}", output_sz);
|
||||
}
|
||||
|
||||
void AudRenU::GetAudioDevice(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Audio, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<Audio::IAudioDevice>();
|
||||
|
||||
LOG_DEBUG(Service_Audio, "called");
|
||||
}
|
||||
|
||||
void AudRenU::GetAudioDeviceServiceWithRevisionInfo(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_Audio, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<Audio::IAudioDevice>();
|
||||
|
||||
LOG_WARNING(Service_Audio, "(STUBBED) called"); // TODO(ogniK): Figure out what is different
|
||||
// based on the current revision
|
||||
rb.PushIpcInterface<Audio::IAudioDevice>(); // TODO(ogniK): Figure out what is different
|
||||
// based on the current revision
|
||||
}
|
||||
|
||||
bool AudRenU::IsFeatureSupported(AudioFeatures feature, u32_le revision) const {
|
||||
|
||||
@@ -46,10 +46,13 @@ public:
|
||||
|
||||
private:
|
||||
void DecodeInterleaved(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Audio, "called");
|
||||
|
||||
u32 consumed = 0;
|
||||
u32 sample_count = 0;
|
||||
std::vector<opus_int16> samples(ctx.GetWriteBufferSize() / sizeof(opus_int16));
|
||||
if (!Decoder_DecodeInterleaved(consumed, sample_count, ctx.ReadBuffer(), samples)) {
|
||||
LOG_ERROR(Audio, "Failed to decode opus data");
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
// TODO(ogniK): Use correct error code
|
||||
rb.Push(ResultCode(-1));
|
||||
@@ -63,12 +66,15 @@ private:
|
||||
}
|
||||
|
||||
void DecodeInterleavedWithPerformance(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Audio, "called");
|
||||
|
||||
u32 consumed = 0;
|
||||
u32 sample_count = 0;
|
||||
u64 performance = 0;
|
||||
std::vector<opus_int16> samples(ctx.GetWriteBufferSize() / sizeof(opus_int16));
|
||||
if (!Decoder_DecodeInterleaved(consumed, sample_count, ctx.ReadBuffer(), samples,
|
||||
performance)) {
|
||||
LOG_ERROR(Audio, "Failed to decode opus data");
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
// TODO(ogniK): Use correct error code
|
||||
rb.Push(ResultCode(-1));
|
||||
@@ -88,24 +94,39 @@ private:
|
||||
std::optional<std::reference_wrapper<u64>> performance_time = std::nullopt) {
|
||||
const auto start_time = std::chrono::high_resolution_clock::now();
|
||||
std::size_t raw_output_sz = output.size() * sizeof(opus_int16);
|
||||
if (sizeof(OpusHeader) > input.size())
|
||||
if (sizeof(OpusHeader) > input.size()) {
|
||||
LOG_ERROR(Audio, "Input is smaller than the header size, header_sz={}, input_sz={}",
|
||||
sizeof(OpusHeader), input.size());
|
||||
return false;
|
||||
}
|
||||
OpusHeader hdr{};
|
||||
std::memcpy(&hdr, input.data(), sizeof(OpusHeader));
|
||||
if (sizeof(OpusHeader) + static_cast<u32>(hdr.sz) > input.size()) {
|
||||
LOG_ERROR(Audio, "Input does not fit in the opus header size. data_sz={}, input_sz={}",
|
||||
sizeof(OpusHeader) + static_cast<u32>(hdr.sz), input.size());
|
||||
return false;
|
||||
}
|
||||
auto frame = input.data() + sizeof(OpusHeader);
|
||||
auto decoded_sample_count = opus_packet_get_nb_samples(
|
||||
frame, static_cast<opus_int32>(input.size() - sizeof(OpusHeader)),
|
||||
static_cast<opus_int32>(sample_rate));
|
||||
if (decoded_sample_count * channel_count * sizeof(u16) > raw_output_sz)
|
||||
if (decoded_sample_count * channel_count * sizeof(u16) > raw_output_sz) {
|
||||
LOG_ERROR(
|
||||
Audio,
|
||||
"Decoded data does not fit into the output data, decoded_sz={}, raw_output_sz={}",
|
||||
decoded_sample_count * channel_count * sizeof(u16), raw_output_sz);
|
||||
return false;
|
||||
}
|
||||
const int frame_size = (static_cast<int>(raw_output_sz / sizeof(s16) / channel_count));
|
||||
auto out_sample_count =
|
||||
opus_decode(decoder.get(), frame, hdr.sz, output.data(),
|
||||
(static_cast<int>(raw_output_sz / sizeof(s16) / channel_count)), 0);
|
||||
if (out_sample_count < 0)
|
||||
opus_decode(decoder.get(), frame, hdr.sz, output.data(), frame_size, 0);
|
||||
if (out_sample_count < 0) {
|
||||
LOG_ERROR(Audio,
|
||||
"Incorrect sample count received from opus_decode, "
|
||||
"output_sample_count={}, frame_size={}, data_sz_from_hdr={}",
|
||||
out_sample_count, frame_size, static_cast<u32>(hdr.sz));
|
||||
return false;
|
||||
}
|
||||
const auto end_time = std::chrono::high_resolution_clock::now() - start_time;
|
||||
sample_count = out_sample_count;
|
||||
consumed = static_cast<u32>(sizeof(OpusHeader) + hdr.sz);
|
||||
@@ -134,14 +155,17 @@ static std::size_t WorkerBufferSize(u32 channel_count) {
|
||||
|
||||
void HwOpus::GetWorkBufferSize(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
auto sample_rate = rp.Pop<u32>();
|
||||
auto channel_count = rp.Pop<u32>();
|
||||
const auto sample_rate = rp.Pop<u32>();
|
||||
const auto channel_count = rp.Pop<u32>();
|
||||
LOG_DEBUG(Audio, "called with sample_rate={}, channel_count={}", sample_rate, channel_count);
|
||||
|
||||
ASSERT_MSG(sample_rate == 48000 || sample_rate == 24000 || sample_rate == 16000 ||
|
||||
sample_rate == 12000 || sample_rate == 8000,
|
||||
"Invalid sample rate");
|
||||
ASSERT_MSG(channel_count == 1 || channel_count == 2, "Invalid channel count");
|
||||
u32 worker_buffer_sz = static_cast<u32>(WorkerBufferSize(channel_count));
|
||||
LOG_DEBUG(Audio, "called worker_buffer_sz={}", worker_buffer_sz);
|
||||
|
||||
const u32 worker_buffer_sz = static_cast<u32>(WorkerBufferSize(channel_count));
|
||||
LOG_DEBUG(Audio, "worker_buffer_sz={}", worker_buffer_sz);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
@@ -155,6 +179,7 @@ void HwOpus::OpenOpusDecoder(Kernel::HLERequestContext& ctx) {
|
||||
auto buffer_sz = rp.Pop<u32>();
|
||||
LOG_DEBUG(Audio, "called sample_rate={}, channel_count={}, buffer_size={}", sample_rate,
|
||||
channel_count, buffer_sz);
|
||||
|
||||
ASSERT_MSG(sample_rate == 48000 || sample_rate == 24000 || sample_rate == 16000 ||
|
||||
sample_rate == 12000 || sample_rate == 8000,
|
||||
"Invalid sample rate");
|
||||
@@ -164,7 +189,8 @@ void HwOpus::OpenOpusDecoder(Kernel::HLERequestContext& ctx) {
|
||||
ASSERT_MSG(buffer_sz >= worker_sz, "Worker buffer too large");
|
||||
std::unique_ptr<OpusDecoder, OpusDeleter> decoder{
|
||||
static_cast<OpusDecoder*>(operator new(worker_sz))};
|
||||
if (opus_decoder_init(decoder.get(), sample_rate, channel_count)) {
|
||||
if (const int err = opus_decoder_init(decoder.get(), sample_rate, channel_count)) {
|
||||
LOG_ERROR(Audio, "Failed to init opus decoder with error={}", err);
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
// TODO(ogniK): Use correct error code
|
||||
rb.Push(ResultCode(-1));
|
||||
|
||||
@@ -33,10 +33,11 @@ public:
|
||||
};
|
||||
|
||||
void Module::Interface::CreateBcatService(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_BCAT, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<IBcatService>();
|
||||
LOG_DEBUG(Service_BCAT, "called");
|
||||
}
|
||||
|
||||
Module::Interface::Interface(std::shared_ptr<Module> module, const char* name)
|
||||
|
||||
@@ -34,13 +34,14 @@ public:
|
||||
|
||||
private:
|
||||
void RegisterEvent(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_BTM, "(STUBBED) called");
|
||||
|
||||
auto& kernel = Core::System::GetInstance().Kernel();
|
||||
register_event =
|
||||
Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "BT:RegisterEvent");
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushCopyObjects(register_event);
|
||||
LOG_WARNING(Service_BTM, "(STUBBED) called");
|
||||
}
|
||||
Kernel::SharedPtr<Kernel::Event> register_event;
|
||||
};
|
||||
|
||||
@@ -57,40 +57,44 @@ public:
|
||||
|
||||
private:
|
||||
void GetScanEvent(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_BTM, "(STUBBED) called");
|
||||
|
||||
auto& kernel = Core::System::GetInstance().Kernel();
|
||||
scan_event =
|
||||
Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "IBtmUserCore:ScanEvent");
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushCopyObjects(scan_event);
|
||||
LOG_WARNING(Service_BTM, "(STUBBED) called");
|
||||
}
|
||||
void GetConnectionEvent(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_BTM, "(STUBBED) called");
|
||||
|
||||
auto& kernel = Core::System::GetInstance().Kernel();
|
||||
connection_event = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot,
|
||||
"IBtmUserCore:ConnectionEvent");
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushCopyObjects(connection_event);
|
||||
LOG_WARNING(Service_BTM, "(STUBBED) called");
|
||||
}
|
||||
void GetDiscoveryEvent(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_BTM, "(STUBBED) called");
|
||||
|
||||
auto& kernel = Core::System::GetInstance().Kernel();
|
||||
service_discovery =
|
||||
Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "IBtmUserCore:Discovery");
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushCopyObjects(service_discovery);
|
||||
LOG_WARNING(Service_BTM, "(STUBBED) called");
|
||||
}
|
||||
void GetConfigEvent(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_BTM, "(STUBBED) called");
|
||||
|
||||
auto& kernel = Core::System::GetInstance().Kernel();
|
||||
config_event =
|
||||
Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "IBtmUserCore:ConfigEvent");
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushCopyObjects(config_event);
|
||||
LOG_WARNING(Service_BTM, "(STUBBED) called");
|
||||
}
|
||||
Kernel::SharedPtr<Kernel::Event> scan_event;
|
||||
Kernel::SharedPtr<Kernel::Event> connection_event;
|
||||
@@ -111,10 +115,11 @@ public:
|
||||
|
||||
private:
|
||||
void GetCoreImpl(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_BTM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<IBtmUserCore>();
|
||||
LOG_DEBUG(Service_BTM, "called");
|
||||
}
|
||||
};
|
||||
|
||||
@@ -209,11 +214,11 @@ public:
|
||||
|
||||
private:
|
||||
void GetCoreImpl(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_BTM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<IBtmSystemCore>();
|
||||
|
||||
LOG_DEBUG(Service_BTM, "called");
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -42,11 +42,11 @@ public:
|
||||
|
||||
private:
|
||||
void Initialize(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_FGM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<IRequest>();
|
||||
|
||||
LOG_DEBUG(Service_FGM, "called");
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -341,6 +341,10 @@ std::shared_ptr<FileSys::RegisteredCacheUnion> GetUnionContents() {
|
||||
return registered_cache_union;
|
||||
}
|
||||
|
||||
void ClearUnionContents() {
|
||||
registered_cache_union = nullptr;
|
||||
}
|
||||
|
||||
FileSys::RegisteredCache* GetSystemNANDContents() {
|
||||
LOG_TRACE(Service_FS, "Opening System NAND Contents");
|
||||
|
||||
@@ -391,6 +395,7 @@ void CreateFactories(FileSys::VfsFilesystem& vfs, bool overwrite) {
|
||||
bis_factory = nullptr;
|
||||
save_data_factory = nullptr;
|
||||
sdmc_factory = nullptr;
|
||||
ClearUnionContents();
|
||||
}
|
||||
|
||||
auto nand_directory = vfs.OpenDirectory(FileUtil::GetUserPath(FileUtil::UserPath::NANDDir),
|
||||
|
||||
@@ -49,6 +49,7 @@ ResultVal<FileSys::VirtualDir> OpenSaveDataSpace(FileSys::SaveDataSpaceId space)
|
||||
ResultVal<FileSys::VirtualDir> OpenSDMC();
|
||||
|
||||
std::shared_ptr<FileSys::RegisteredCacheUnion> GetUnionContents();
|
||||
void ClearUnionContents();
|
||||
|
||||
FileSys::RegisteredCache* GetSystemNANDContents();
|
||||
FileSys::RegisteredCache* GetUserNANDContents();
|
||||
|
||||
@@ -62,11 +62,13 @@ private:
|
||||
|
||||
// Error checking
|
||||
if (length < 0) {
|
||||
LOG_ERROR(Service_FS, "Length is less than 0, length={}", length);
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(FileSys::ERROR_INVALID_SIZE);
|
||||
return;
|
||||
}
|
||||
if (offset < 0) {
|
||||
LOG_ERROR(Service_FS, "Offset is less than 0, offset={}", offset);
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(FileSys::ERROR_INVALID_OFFSET);
|
||||
return;
|
||||
@@ -107,11 +109,13 @@ private:
|
||||
|
||||
// Error checking
|
||||
if (length < 0) {
|
||||
LOG_ERROR(Service_FS, "Length is less than 0, length={}", length);
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(FileSys::ERROR_INVALID_SIZE);
|
||||
return;
|
||||
}
|
||||
if (offset < 0) {
|
||||
LOG_ERROR(Service_FS, "Offset is less than 0, offset={}", offset);
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(FileSys::ERROR_INVALID_OFFSET);
|
||||
return;
|
||||
@@ -138,11 +142,13 @@ private:
|
||||
|
||||
// Error checking
|
||||
if (length < 0) {
|
||||
LOG_ERROR(Service_FS, "Length is less than 0, length={}", length);
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(FileSys::ERROR_INVALID_SIZE);
|
||||
return;
|
||||
}
|
||||
if (offset < 0) {
|
||||
LOG_ERROR(Service_FS, "Offset is less than 0, offset={}", offset);
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(FileSys::ERROR_INVALID_OFFSET);
|
||||
return;
|
||||
@@ -180,9 +186,10 @@ private:
|
||||
void SetSize(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const u64 size = rp.Pop<u64>();
|
||||
backend->Resize(size);
|
||||
LOG_DEBUG(Service_FS, "called, size={}", size);
|
||||
|
||||
backend->Resize(size);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
@@ -465,6 +472,8 @@ public:
|
||||
}
|
||||
|
||||
void ReadSaveDataInfo(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_FS, "called");
|
||||
|
||||
// Calculate how many entries we can fit in the output buffer
|
||||
const u64 count_entries = ctx.GetWriteBufferSize() / sizeof(SaveDataInfo);
|
||||
|
||||
@@ -703,6 +712,8 @@ void FSP_SRV::OpenFileSystemWithPatch(Kernel::HLERequestContext& ctx) {
|
||||
|
||||
const auto type = rp.PopRaw<FileSystemType>();
|
||||
const auto title_id = rp.PopRaw<u64>();
|
||||
LOG_WARNING(Service_FS, "(STUBBED) called with type={}, title_id={:016X}",
|
||||
static_cast<u8>(type), title_id);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 0};
|
||||
rb.Push(ResultCode(-1));
|
||||
@@ -738,6 +749,7 @@ void FSP_SRV::MountSaveData(Kernel::HLERequestContext& ctx) {
|
||||
auto space_id = rp.PopRaw<FileSys::SaveDataSpaceId>();
|
||||
auto unk = rp.Pop<u32>();
|
||||
LOG_INFO(Service_FS, "called with unknown={:08X}", unk);
|
||||
|
||||
auto save_struct = rp.PopRaw<FileSys::SaveDataDescriptor>();
|
||||
|
||||
auto dir = OpenSaveData(space_id, save_struct);
|
||||
@@ -763,6 +775,7 @@ void FSP_SRV::OpenReadOnlySaveDataFileSystem(Kernel::HLERequestContext& ctx) {
|
||||
void FSP_SRV::OpenSaveDataInfoReaderBySaveDataSpaceId(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto space = rp.PopRaw<FileSys::SaveDataSpaceId>();
|
||||
LOG_INFO(Service_FS, "called, space={}", static_cast<u8>(space));
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
|
||||
@@ -71,8 +71,9 @@ void Controller_DebugPad::OnUpdate(u8* data, std::size_t size) {
|
||||
|
||||
void Controller_DebugPad::OnLoadInputDevices() {
|
||||
std::transform(Settings::values.debug_pad_buttons.begin(),
|
||||
Settings::values.debug_pad_buttons.end(), buttons.begin(),
|
||||
Input::CreateDevice<Input::ButtonDevice>);
|
||||
Settings::values.debug_pad_buttons.begin() +
|
||||
Settings::NativeButton::NUM_BUTTONS_HID,
|
||||
buttons.begin(), Input::CreateDevice<Input::ButtonDevice>);
|
||||
std::transform(Settings::values.debug_pad_analogs.begin(),
|
||||
Settings::values.debug_pad_analogs.end(), analogs.begin(),
|
||||
Input::CreateDevice<Input::AnalogDevice>);
|
||||
|
||||
@@ -524,6 +524,8 @@ void Controller_NPad::SetNpadMode(u32 npad_id, NPadAssignments assignment_mode)
|
||||
|
||||
void Controller_NPad::VibrateController(const std::vector<u32>& controller_ids,
|
||||
const std::vector<Vibration>& vibrations) {
|
||||
LOG_WARNING(Service_HID, "(STUBBED) called");
|
||||
|
||||
if (!can_controllers_vibrate) {
|
||||
return;
|
||||
}
|
||||
@@ -533,7 +535,6 @@ void Controller_NPad::VibrateController(const std::vector<u32>& controller_ids,
|
||||
// TODO(ogniK): Vibrate the physical controller
|
||||
}
|
||||
}
|
||||
LOG_WARNING(Service_HID, "(STUBBED) called");
|
||||
last_processed_vibration = vibrations.back();
|
||||
}
|
||||
|
||||
|
||||
@@ -124,10 +124,11 @@ public:
|
||||
|
||||
private:
|
||||
void GetSharedMemoryHandle(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_HID, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushCopyObjects(shared_mem);
|
||||
LOG_DEBUG(Service_HID, "called");
|
||||
}
|
||||
|
||||
void UpdateControllers(u64 userdata, int cycles_late) {
|
||||
@@ -163,9 +164,10 @@ public:
|
||||
|
||||
private:
|
||||
void ActivateVibrationDevice(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_HID, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_WARNING(Service_HID, "(STUBBED) called");
|
||||
}
|
||||
};
|
||||
|
||||
@@ -303,6 +305,8 @@ private:
|
||||
std::shared_ptr<IAppletResource> applet_resource;
|
||||
|
||||
void CreateAppletResource(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_HID, "called");
|
||||
|
||||
if (applet_resource == nullptr) {
|
||||
applet_resource = std::make_shared<IAppletResource>();
|
||||
}
|
||||
@@ -310,206 +314,228 @@ private:
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<IAppletResource>(applet_resource);
|
||||
LOG_DEBUG(Service_HID, "called");
|
||||
}
|
||||
|
||||
void ActivateXpad(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_HID, "called");
|
||||
|
||||
applet_resource->ActivateController(HidController::XPad);
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_DEBUG(Service_HID, "called");
|
||||
}
|
||||
|
||||
void ActivateDebugPad(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_HID, "called");
|
||||
|
||||
applet_resource->ActivateController(HidController::DebugPad);
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_DEBUG(Service_HID, "called");
|
||||
}
|
||||
|
||||
void ActivateTouchScreen(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_HID, "called");
|
||||
|
||||
applet_resource->ActivateController(HidController::Touchscreen);
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_DEBUG(Service_HID, "called");
|
||||
}
|
||||
|
||||
void ActivateMouse(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_HID, "called");
|
||||
|
||||
applet_resource->ActivateController(HidController::Mouse);
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_DEBUG(Service_HID, "called");
|
||||
}
|
||||
|
||||
void ActivateKeyboard(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_HID, "called");
|
||||
|
||||
applet_resource->ActivateController(HidController::Keyboard);
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_DEBUG(Service_HID, "called");
|
||||
}
|
||||
|
||||
void ActivateGesture(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_HID, "called");
|
||||
|
||||
applet_resource->ActivateController(HidController::Gesture);
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_DEBUG(Service_HID, "called");
|
||||
}
|
||||
|
||||
void ActivateNpadWithRevision(Kernel::HLERequestContext& ctx) {
|
||||
// Should have no effect with how our npad sets up the data
|
||||
LOG_DEBUG(Service_HID, "called");
|
||||
|
||||
applet_resource->ActivateController(HidController::NPad);
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_DEBUG(Service_HID, "called");
|
||||
}
|
||||
|
||||
void StartSixAxisSensor(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
auto handle = rp.PopRaw<u32>();
|
||||
LOG_WARNING(Service_HID, "(STUBBED) called with handle={}", handle);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_WARNING(Service_HID, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void SetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_HID, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_WARNING(Service_HID, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void IsSixAxisSensorAtRest(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_HID, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
// TODO (Hexagon12): Properly implement reading gyroscope values from controllers.
|
||||
rb.Push(true);
|
||||
LOG_WARNING(Service_HID, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void SetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
auto supported_styleset = rp.PopRaw<u32>();
|
||||
LOG_DEBUG(Service_HID, "called with supported_styleset={}", supported_styleset);
|
||||
|
||||
applet_resource->GetController<Controller_NPad>(HidController::NPad)
|
||||
.SetSupportedStyleSet({supported_styleset});
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
|
||||
LOG_DEBUG(Service_HID, "called");
|
||||
}
|
||||
|
||||
void GetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_HID, "called");
|
||||
|
||||
auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push<u32>(controller.GetSupportedStyleSet().raw);
|
||||
LOG_DEBUG(Service_HID, "called");
|
||||
}
|
||||
|
||||
void SetSupportedNpadIdType(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_HID, "called");
|
||||
|
||||
applet_resource->GetController<Controller_NPad>(HidController::NPad)
|
||||
.SetSupportedNPadIdTypes(ctx.ReadBuffer().data(), ctx.GetReadBufferSize());
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_DEBUG(Service_HID, "called");
|
||||
}
|
||||
|
||||
void ActivateNpad(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_HID, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
applet_resource->ActivateController(HidController::NPad);
|
||||
LOG_DEBUG(Service_HID, "called");
|
||||
}
|
||||
|
||||
void AcquireNpadStyleSetUpdateEventHandle(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
auto npad_id = rp.PopRaw<u32>();
|
||||
LOG_DEBUG(Service_HID, "called with npad_id={}", npad_id);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushCopyObjects(applet_resource->GetController<Controller_NPad>(HidController::NPad)
|
||||
.GetStyleSetChangedEvent());
|
||||
LOG_DEBUG(Service_HID, "called");
|
||||
}
|
||||
|
||||
void DisconnectNpad(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
auto npad_id = rp.PopRaw<u32>();
|
||||
LOG_DEBUG(Service_HID, "called with npad_id={}", npad_id);
|
||||
|
||||
applet_resource->GetController<Controller_NPad>(HidController::NPad)
|
||||
.DisconnectNPad(npad_id);
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_DEBUG(Service_HID, "called");
|
||||
}
|
||||
|
||||
void GetPlayerLedPattern(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
auto npad_id = rp.PopRaw<u32>();
|
||||
LOG_DEBUG(Service_HID, "called with npad_id={}", npad_id);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushRaw<u64>(applet_resource->GetController<Controller_NPad>(HidController::NPad)
|
||||
.GetLedPattern(npad_id)
|
||||
.raw);
|
||||
LOG_DEBUG(Service_HID, "called");
|
||||
}
|
||||
|
||||
void SetNpadJoyHoldType(Kernel::HLERequestContext& ctx) {
|
||||
auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad);
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto hold_type = rp.PopRaw<u64>();
|
||||
LOG_DEBUG(Service_HID, "called with hold_type={}", hold_type);
|
||||
|
||||
auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad);
|
||||
controller.SetHoldType(Controller_NPad::NpadHoldType{hold_type});
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_DEBUG(Service_HID, "called");
|
||||
}
|
||||
|
||||
void GetNpadJoyHoldType(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_HID, "called");
|
||||
|
||||
const auto& controller =
|
||||
applet_resource->GetController<Controller_NPad>(HidController::NPad);
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push<u64>(static_cast<u64>(controller.GetHoldType()));
|
||||
LOG_DEBUG(Service_HID, "called");
|
||||
}
|
||||
|
||||
void SetNpadJoyAssignmentModeSingleByDefault(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
auto npad_id = rp.PopRaw<u32>();
|
||||
LOG_WARNING(Service_HID, "(STUBBED) called with npad_id={}", npad_id);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_WARNING(Service_HID, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void BeginPermitVibrationSession(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_HID, "called");
|
||||
|
||||
applet_resource->GetController<Controller_NPad>(HidController::NPad)
|
||||
.SetVibrationEnabled(true);
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_DEBUG(Service_HID, "called");
|
||||
}
|
||||
|
||||
void EndPermitVibrationSession(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_HID, "called");
|
||||
|
||||
applet_resource->GetController<Controller_NPad>(HidController::NPad)
|
||||
.SetVibrationEnabled(false);
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_DEBUG(Service_HID, "called");
|
||||
}
|
||||
|
||||
void SendVibrationValue(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto controller_id = rp.PopRaw<u32>();
|
||||
const auto vibration_values = rp.PopRaw<Controller_NPad::Vibration>();
|
||||
LOG_DEBUG(Service_HID, "called with controller_id={}", controller_id);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
|
||||
applet_resource->GetController<Controller_NPad>(HidController::NPad)
|
||||
.VibrateController({controller_id}, {vibration_values});
|
||||
LOG_DEBUG(Service_HID, "called");
|
||||
}
|
||||
|
||||
void SendVibrationValues(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_HID, "called");
|
||||
|
||||
const auto controllers = ctx.ReadBuffer(0);
|
||||
const auto vibrations = ctx.ReadBuffer(1);
|
||||
|
||||
@@ -527,86 +553,96 @@ private:
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_DEBUG(Service_HID, "called");
|
||||
}
|
||||
|
||||
void GetActualVibrationValue(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_HID, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 6};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushRaw<Controller_NPad::Vibration>(
|
||||
applet_resource->GetController<Controller_NPad>(HidController::NPad)
|
||||
.GetLastVibration());
|
||||
LOG_DEBUG(Service_HID, "called");
|
||||
}
|
||||
|
||||
void SetNpadJoyAssignmentModeDual(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto npad_id = rp.PopRaw<u32>();
|
||||
LOG_DEBUG(Service_HID, "called with npad_id={}", npad_id);
|
||||
|
||||
auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad);
|
||||
controller.SetNpadMode(npad_id, Controller_NPad::NPadAssignments::Dual);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_DEBUG(Service_HID, "called");
|
||||
}
|
||||
|
||||
void MergeSingleJoyAsDualJoy(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_HID, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_WARNING(Service_HID, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void SetNpadHandheldActivationMode(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
auto mode = rp.PopRaw<u32>();
|
||||
LOG_WARNING(Service_HID, "(STUBBED) called with mode={}", mode);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_WARNING(Service_HID, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_HID, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push<u32>(1);
|
||||
rb.Push<u32>(0);
|
||||
LOG_DEBUG(Service_HID, "called");
|
||||
}
|
||||
|
||||
void CreateActiveVibrationDeviceList(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_HID, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<IActiveVibrationDeviceList>();
|
||||
LOG_DEBUG(Service_HID, "called");
|
||||
}
|
||||
|
||||
void ActivateConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_HID, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_WARNING(Service_HID, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void StartConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_HID, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_WARNING(Service_HID, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void StopSixAxisSensor(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_HID, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_WARNING(Service_HID, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void SetIsPalmaAllConnectable(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_HID, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_WARNING(Service_HID, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void SetPalmaBoostMode(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_HID, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_WARNING(Service_HID, "(STUBBED) called");
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -44,115 +44,133 @@ IRS::IRS() : ServiceFramework{"irs"} {
|
||||
}
|
||||
|
||||
void IRS::ActivateIrsensor(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void IRS::DeactivateIrsensor(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void IRS::GetIrsensorSharedMemoryHandle(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_IRS, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushCopyObjects(shared_mem);
|
||||
LOG_DEBUG(Service_IRS, "called");
|
||||
}
|
||||
|
||||
void IRS::StopImageProcessor(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void IRS::RunMomentProcessor(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void IRS::RunClusteringProcessor(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void IRS::RunImageTransferProcessor(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void IRS::GetImageTransferProcessorState(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 5};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushRaw<u64>(CoreTiming::GetTicks());
|
||||
rb.PushRaw<u32>(0);
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void IRS::RunTeraPluginProcessor(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void IRS::GetNpadIrCameraHandle(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushRaw<u32>(device_handle);
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void IRS::RunPointingProcessor(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void IRS::SuspendImageProcessor(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void IRS::CheckFirmwareVersion(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void IRS::SetFunctionLevel(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void IRS::RunImageTransferExProcessor(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void IRS::RunIrLedProcessor(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void IRS::StopImageProcessorAsync(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void IRS::ActivateIrsensorWithFunctionLevel(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called");
|
||||
}
|
||||
|
||||
IRS::~IRS() = default;
|
||||
|
||||
@@ -55,29 +55,29 @@ public:
|
||||
|
||||
private:
|
||||
void EnableVrMode(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_LBL, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
|
||||
vr_mode_enabled = true;
|
||||
|
||||
LOG_DEBUG(Service_LBL, "called");
|
||||
}
|
||||
|
||||
void DisableVrMode(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_LBL, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
|
||||
vr_mode_enabled = false;
|
||||
|
||||
LOG_DEBUG(Service_LBL, "called");
|
||||
}
|
||||
|
||||
void IsVrModeEnabled(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_LBL, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push(vr_mode_enabled);
|
||||
|
||||
LOG_DEBUG(Service_LBL, "called");
|
||||
}
|
||||
|
||||
bool vr_mode_enabled = false;
|
||||
|
||||
@@ -44,11 +44,11 @@ public:
|
||||
}
|
||||
|
||||
void CreateMonitorService(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_LDN, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<IMonitorService>();
|
||||
|
||||
LOG_DEBUG(Service_LDN, "called");
|
||||
}
|
||||
};
|
||||
|
||||
@@ -104,11 +104,11 @@ public:
|
||||
}
|
||||
|
||||
void CreateSystemLocalCommunicationService(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_LDN, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<ILocalCommunicationService>("ISystemLocalCommunicationService");
|
||||
|
||||
LOG_DEBUG(Service_LDN, "called");
|
||||
}
|
||||
};
|
||||
|
||||
@@ -125,11 +125,11 @@ public:
|
||||
}
|
||||
|
||||
void CreateUserLocalCommunicationService(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_LDN, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<ILocalCommunicationService>("IUserLocalCommunicationService");
|
||||
|
||||
LOG_DEBUG(Service_LDN, "called");
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -97,6 +97,8 @@ public:
|
||||
rp.Skip(2, false);
|
||||
const VAddr nrr_addr{rp.Pop<VAddr>()};
|
||||
const u64 nrr_size{rp.Pop<u64>()};
|
||||
LOG_DEBUG(Service_LDR, "called with nrr_addr={:016X}, nrr_size={:016X}", nrr_addr,
|
||||
nrr_size);
|
||||
|
||||
if (!initialized) {
|
||||
LOG_ERROR(Service_LDR, "LDR:RO not initialized before use!");
|
||||
@@ -189,6 +191,7 @@ public:
|
||||
IPC::RequestParser rp{ctx};
|
||||
rp.Skip(2, false);
|
||||
const auto nrr_addr{rp.Pop<VAddr>()};
|
||||
LOG_DEBUG(Service_LDR, "called with nrr_addr={:016X}", nrr_addr);
|
||||
|
||||
if (!Common::Is4KBAligned(nrr_addr)) {
|
||||
LOG_ERROR(Service_LDR, "NRR Address has invalid alignment (actual {:016X})!", nrr_addr);
|
||||
@@ -219,6 +222,10 @@ public:
|
||||
const u64 nro_size{rp.Pop<u64>()};
|
||||
const VAddr bss_addr{rp.Pop<VAddr>()};
|
||||
const u64 bss_size{rp.Pop<u64>()};
|
||||
LOG_DEBUG(
|
||||
Service_LDR,
|
||||
"called with nro_addr={:016X}, nro_size={:016X}, bss_addr={:016X}, bss_size={:016X}",
|
||||
nro_addr, nro_size, bss_addr, bss_size);
|
||||
|
||||
if (!initialized) {
|
||||
LOG_ERROR(Service_LDR, "LDR:RO not initialized before use!");
|
||||
@@ -345,6 +352,8 @@ public:
|
||||
rp.Skip(2, false);
|
||||
const VAddr mapped_addr{rp.PopRaw<VAddr>()};
|
||||
const VAddr heap_addr{rp.PopRaw<VAddr>()};
|
||||
LOG_DEBUG(Service_LDR, "called with mapped_addr={:016X}, heap_addr={:016X}", mapped_addr,
|
||||
heap_addr);
|
||||
|
||||
if (!initialized) {
|
||||
LOG_ERROR(Service_LDR, "LDR:RO not initialized before use!");
|
||||
@@ -393,11 +402,12 @@ public:
|
||||
}
|
||||
|
||||
void Initialize(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_LDR, "(STUBBED) called");
|
||||
|
||||
initialized = true;
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_WARNING(Service_LDR, "(STUBBED) called");
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
@@ -209,11 +209,11 @@ public:
|
||||
* 0: ResultCode
|
||||
*/
|
||||
void OpenLogger(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_LM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<ILogger>();
|
||||
|
||||
LOG_DEBUG(Service_LM, "called");
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -31,12 +31,14 @@ public:
|
||||
private:
|
||||
void Initialize(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_MM, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
|
||||
void Finalize(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_MM, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
@@ -45,15 +47,16 @@ private:
|
||||
IPC::RequestParser rp{ctx};
|
||||
min = rp.Pop<u32>();
|
||||
max = rp.Pop<u32>();
|
||||
current = min;
|
||||
|
||||
LOG_WARNING(Service_MM, "(STUBBED) called, min=0x{:X}, max=0x{:X}", min, max);
|
||||
|
||||
current = min;
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
|
||||
void Get(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_MM, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push(current);
|
||||
@@ -61,6 +64,7 @@ private:
|
||||
|
||||
void InitializeWithId(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_MM, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push<u32>(id); // Any non zero value
|
||||
@@ -68,6 +72,7 @@ private:
|
||||
|
||||
void FinalizeWithId(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_MM, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
@@ -77,16 +82,17 @@ private:
|
||||
u32 input_id = rp.Pop<u32>();
|
||||
min = rp.Pop<u32>();
|
||||
max = rp.Pop<u32>();
|
||||
current = min;
|
||||
|
||||
LOG_WARNING(Service_MM, "(STUBBED) called, input_id=0x{:X}, min=0x{:X}, max=0x{:X}",
|
||||
input_id, min, max);
|
||||
|
||||
current = min;
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
|
||||
void GetWithId(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_MM, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push(current);
|
||||
|
||||
@@ -43,11 +43,11 @@ public:
|
||||
|
||||
private:
|
||||
void CreateAmInterface(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_NFC, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<IAm>();
|
||||
|
||||
LOG_DEBUG(Service_NFC, "called");
|
||||
}
|
||||
};
|
||||
|
||||
@@ -91,11 +91,11 @@ public:
|
||||
|
||||
private:
|
||||
void CreateUserInterface(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_NFC, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<MFIUser>();
|
||||
|
||||
LOG_DEBUG(Service_NFC, "called");
|
||||
}
|
||||
};
|
||||
|
||||
@@ -138,19 +138,19 @@ private:
|
||||
};
|
||||
|
||||
void InitializeOld(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_NFC, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
|
||||
// We don't deal with hardware initialization so we can just stub this.
|
||||
LOG_DEBUG(Service_NFC, "called");
|
||||
}
|
||||
|
||||
void IsNfcEnabledOld(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_NFC, "IsNfcEnabledOld");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushRaw<u8>(Settings::values.enable_nfc);
|
||||
|
||||
LOG_DEBUG(Service_NFC, "IsNfcEnabledOld");
|
||||
}
|
||||
|
||||
void GetStateOld(Kernel::HLERequestContext& ctx) {
|
||||
@@ -183,11 +183,11 @@ public:
|
||||
|
||||
private:
|
||||
void CreateUserInterface(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_NFC, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<IUser>();
|
||||
|
||||
LOG_DEBUG(Service_NFC, "called");
|
||||
}
|
||||
};
|
||||
|
||||
@@ -241,11 +241,11 @@ public:
|
||||
|
||||
private:
|
||||
void CreateSystemInterface(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_NFC, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<ISystem>();
|
||||
|
||||
LOG_DEBUG(Service_NFC, "called");
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -108,30 +108,29 @@ private:
|
||||
static_assert(sizeof(CommonInfo) == 0x40, "CommonInfo is an invalid size");
|
||||
|
||||
void Initialize(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_NFC, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
|
||||
state = State::Initialized;
|
||||
|
||||
LOG_DEBUG(Service_NFC, "called");
|
||||
}
|
||||
|
||||
void GetState(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_NFC, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3, 0};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushRaw<u32>(static_cast<u32>(state));
|
||||
|
||||
LOG_DEBUG(Service_NFC, "called");
|
||||
}
|
||||
|
||||
void ListDevices(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const u32 array_size = rp.Pop<u32>();
|
||||
LOG_DEBUG(Service_NFP, "called, array_size={}", array_size);
|
||||
|
||||
ctx.WriteBuffer(&device_handle, sizeof(device_handle));
|
||||
|
||||
LOG_DEBUG(Service_NFP, "called, array_size={}", array_size);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push<u32>(1);
|
||||
@@ -141,6 +140,7 @@ private:
|
||||
IPC::RequestParser rp{ctx};
|
||||
const u64 dev_handle = rp.Pop<u64>();
|
||||
LOG_DEBUG(Service_NFP, "called, dev_handle=0x{:X}", dev_handle);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push<u32>(npad_id);
|
||||
@@ -150,6 +150,7 @@ private:
|
||||
IPC::RequestParser rp{ctx};
|
||||
const u64 dev_handle = rp.Pop<u64>();
|
||||
LOG_DEBUG(Service_NFP, "called, dev_handle=0x{:X}", dev_handle);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushCopyObjects(nfp_interface.GetNFCEvent());
|
||||
@@ -168,6 +169,7 @@ private:
|
||||
|
||||
void StopDetection(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_NFP, "called");
|
||||
|
||||
switch (device_state) {
|
||||
case DeviceState::TagFound:
|
||||
case DeviceState::TagNearby:
|
||||
@@ -185,6 +187,7 @@ private:
|
||||
|
||||
void GetDeviceState(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_NFP, "called");
|
||||
|
||||
auto nfc_event = nfp_interface.GetNFCEvent();
|
||||
if (!nfc_event->ShouldWait(Kernel::GetCurrentThread()) && !has_attached_handle) {
|
||||
device_state = DeviceState::TagFound;
|
||||
@@ -323,6 +326,7 @@ private:
|
||||
|
||||
void Module::Interface::CreateUserInterface(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_NFP, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<IUser>(*this);
|
||||
|
||||
@@ -63,12 +63,14 @@ public:
|
||||
private:
|
||||
void Submit(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_NIFM, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
|
||||
void GetRequestState(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_NIFM, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push<u32>(0);
|
||||
@@ -76,12 +78,14 @@ private:
|
||||
|
||||
void GetResult(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_NIFM, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
|
||||
void GetSystemEventReadableHandles(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_NIFM, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushCopyObjects(event1, event2);
|
||||
@@ -89,12 +93,14 @@ private:
|
||||
|
||||
void Cancel(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_NIFM, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
|
||||
void SetConnectionConfirmationOption(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_NIFM, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
@@ -122,32 +128,36 @@ private:
|
||||
void GetClientId(Kernel::HLERequestContext& ctx) {
|
||||
static constexpr u32 client_id = 1;
|
||||
LOG_WARNING(Service_NIFM, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push<u64>(client_id); // Client ID needs to be non zero otherwise it's considered invalid
|
||||
}
|
||||
void CreateScanRequest(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_NIFM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<IScanRequest>();
|
||||
|
||||
LOG_DEBUG(Service_NIFM, "called");
|
||||
}
|
||||
void CreateRequest(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_NIFM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<IRequest>();
|
||||
|
||||
LOG_DEBUG(Service_NIFM, "called");
|
||||
}
|
||||
void RemoveNetworkProfile(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_NIFM, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
void CreateTemporaryNetworkProfile(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_NIFM, "called");
|
||||
|
||||
ASSERT_MSG(ctx.GetReadBufferSize() == 0x17c, "NetworkProfileData is not the correct size");
|
||||
u128 uuid{};
|
||||
auto buffer = ctx.ReadBuffer();
|
||||
@@ -158,23 +168,24 @@ private:
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<INetworkProfile>();
|
||||
rb.PushRaw<u128>(uuid);
|
||||
|
||||
LOG_DEBUG(Service_NIFM, "called");
|
||||
}
|
||||
void IsWirelessCommunicationEnabled(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_NIFM, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push<u8>(0);
|
||||
}
|
||||
void IsEthernetCommunicationEnabled(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_NIFM, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push<u8>(0);
|
||||
}
|
||||
void IsAnyInternetRequestAccepted(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_NIFM, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push<u8>(0);
|
||||
@@ -235,17 +246,19 @@ public:
|
||||
}
|
||||
|
||||
void CreateGeneralServiceOld(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_NIFM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<IGeneralService>();
|
||||
LOG_DEBUG(Service_NIFM, "called");
|
||||
}
|
||||
|
||||
void CreateGeneralService(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_NIFM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<IGeneralService>();
|
||||
LOG_DEBUG(Service_NIFM, "called");
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -148,47 +148,53 @@ private:
|
||||
|
||||
void StartTask(Kernel::HLERequestContext& ctx) {
|
||||
// No need to connect to the internet, just finish the task straight away.
|
||||
LOG_DEBUG(Service_NIM, "called");
|
||||
|
||||
finished_event->Signal();
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_DEBUG(Service_NIM, "called");
|
||||
}
|
||||
|
||||
void GetFinishNotificationEvent(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_NIM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushCopyObjects(finished_event);
|
||||
LOG_DEBUG(Service_NIM, "called");
|
||||
}
|
||||
|
||||
void GetResult(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_NIM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_DEBUG(Service_NIM, "called");
|
||||
}
|
||||
|
||||
void Cancel(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_NIM, "called");
|
||||
|
||||
finished_event->Clear();
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_DEBUG(Service_NIM, "called");
|
||||
}
|
||||
|
||||
void IsProcessing(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_NIM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushRaw<u32>(0); // We instantly process the request
|
||||
LOG_DEBUG(Service_NIM, "called");
|
||||
}
|
||||
|
||||
void GetServerTime(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_NIM, "called");
|
||||
|
||||
const s64 server_time{std::chrono::duration_cast<std::chrono::seconds>(
|
||||
std::chrono::system_clock::now().time_since_epoch())
|
||||
.count()};
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushRaw<s64>(server_time);
|
||||
LOG_DEBUG(Service_NIM, "called");
|
||||
}
|
||||
};
|
||||
|
||||
@@ -208,23 +214,26 @@ public:
|
||||
|
||||
private:
|
||||
void OpenEnsureNetworkClockAvailabilityService(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_NIM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<IEnsureNetworkClockAvailabilityService>();
|
||||
LOG_DEBUG(Service_NIM, "called");
|
||||
}
|
||||
|
||||
// TODO(ogniK): Do we need these?
|
||||
void SuspendAutonomicTimeCorrection(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_NIM, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_WARNING(Service_NIM, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void ResumeAutonomicTimeCorrection(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_NIM, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_WARNING(Service_NIM, "(STUBBED) called");
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -433,11 +433,11 @@ public:
|
||||
private:
|
||||
template <typename T>
|
||||
void PushInterface(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_NS, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<T>();
|
||||
|
||||
LOG_DEBUG(Service_NS, "called");
|
||||
}
|
||||
};
|
||||
|
||||
@@ -526,11 +526,11 @@ public:
|
||||
|
||||
private:
|
||||
void OpenSystemUpdateControl(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_NS, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<ISystemUpdateControl>();
|
||||
|
||||
LOG_DEBUG(Service_NS, "called");
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -281,6 +281,7 @@ void PL_U::RequestLoad(Kernel::HLERequestContext& ctx) {
|
||||
const u32 shared_font_type{rp.Pop<u32>()};
|
||||
// Games don't call this so all fonts should be loaded
|
||||
LOG_DEBUG(Service_NS, "called, shared_font_type={}", shared_font_type);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
@@ -288,8 +289,8 @@ void PL_U::RequestLoad(Kernel::HLERequestContext& ctx) {
|
||||
void PL_U::GetLoadState(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const u32 font_id{rp.Pop<u32>()};
|
||||
|
||||
LOG_DEBUG(Service_NS, "called, font_id={}", font_id);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push<u32>(static_cast<u32>(LoadState::Done));
|
||||
@@ -298,8 +299,8 @@ void PL_U::GetLoadState(Kernel::HLERequestContext& ctx) {
|
||||
void PL_U::GetSize(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const u32 font_id{rp.Pop<u32>()};
|
||||
|
||||
LOG_DEBUG(Service_NS, "called, font_id={}", font_id);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push<u32>(impl->GetSharedFontRegion(font_id).size);
|
||||
@@ -308,8 +309,8 @@ void PL_U::GetSize(Kernel::HLERequestContext& ctx) {
|
||||
void PL_U::GetSharedMemoryAddressOffset(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const u32 font_id{rp.Pop<u32>()};
|
||||
|
||||
LOG_DEBUG(Service_NS, "called, font_id={}", font_id);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push<u32>(impl->GetSharedFontRegion(font_id).offset);
|
||||
@@ -317,6 +318,7 @@ void PL_U::GetSharedMemoryAddressOffset(Kernel::HLERequestContext& ctx) {
|
||||
|
||||
void PL_U::GetSharedMemoryNativeHandle(Kernel::HLERequestContext& ctx) {
|
||||
// Map backing memory for the font data
|
||||
LOG_DEBUG(Service_NS, "called");
|
||||
Core::CurrentProcess()->VMManager().MapMemoryBlock(SHARED_FONT_MEM_VADDR, impl->shared_font, 0,
|
||||
SHARED_FONT_MEM_SIZE,
|
||||
Kernel::MemoryState::Shared);
|
||||
@@ -328,7 +330,6 @@ void PL_U::GetSharedMemoryNativeHandle(Kernel::HLERequestContext& ctx) {
|
||||
Kernel::MemoryPermission::Read, SHARED_FONT_MEM_VADDR, Kernel::MemoryRegion::BASE,
|
||||
"PL_U:shared_font_mem");
|
||||
|
||||
LOG_DEBUG(Service_NS, "called");
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushCopyObjects(impl->shared_font_mem);
|
||||
@@ -338,6 +339,7 @@ void PL_U::GetSharedFontInOrderOfPriority(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const u64 language_code{rp.Pop<u64>()}; // TODO(ogniK): Find out what this is used for
|
||||
LOG_DEBUG(Service_NS, "called, language_code={:X}", language_code);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
std::vector<u32> font_codes;
|
||||
std::vector<u32> font_offsets;
|
||||
|
||||
@@ -54,6 +54,7 @@ u32 nvhost_as_gpu::InitalizeEx(const std::vector<u8>& input, std::vector<u8>& ou
|
||||
IoctlInitalizeEx params{};
|
||||
std::memcpy(¶ms, input.data(), input.size());
|
||||
LOG_WARNING(Service_NVDRV, "(STUBBED) called, big_page_size=0x{:X}", params.big_page_size);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -191,6 +192,7 @@ u32 nvhost_as_gpu::BindChannel(const std::vector<u8>& input, std::vector<u8>& ou
|
||||
IoctlBindChannel params{};
|
||||
std::memcpy(¶ms, input.data(), input.size());
|
||||
LOG_DEBUG(Service_NVDRV, "called, fd={:X}", params.fd);
|
||||
|
||||
channel = params.fd;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
#include <cstring>
|
||||
#include "common/assert.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "core/core_timing.h"
|
||||
#include "core/core_timing_util.h"
|
||||
#include "core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h"
|
||||
|
||||
namespace Service::Nvidia::Devices {
|
||||
@@ -33,6 +35,8 @@ u32 nvhost_ctrl_gpu::ioctl(Ioctl command, const std::vector<u8>& input, std::vec
|
||||
return ZBCQueryTable(input, output);
|
||||
case IoctlCommand::IocFlushL2:
|
||||
return FlushL2(input, output);
|
||||
case IoctlCommand::IocGetGpuTime:
|
||||
return GetGpuTime(input, output);
|
||||
}
|
||||
UNIMPLEMENTED_MSG("Unimplemented ioctl");
|
||||
return 0;
|
||||
@@ -99,6 +103,7 @@ u32 nvhost_ctrl_gpu::GetTPCMasks(const std::vector<u8>& input, std::vector<u8>&
|
||||
|
||||
u32 nvhost_ctrl_gpu::GetActiveSlotMask(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
LOG_DEBUG(Service_NVDRV, "called");
|
||||
|
||||
IoctlActiveSlotMask params{};
|
||||
if (input.size() > 0) {
|
||||
std::memcpy(¶ms, input.data(), input.size());
|
||||
@@ -111,6 +116,7 @@ u32 nvhost_ctrl_gpu::GetActiveSlotMask(const std::vector<u8>& input, std::vector
|
||||
|
||||
u32 nvhost_ctrl_gpu::ZCullGetCtxSize(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
LOG_DEBUG(Service_NVDRV, "called");
|
||||
|
||||
IoctlZcullGetCtxSize params{};
|
||||
if (input.size() > 0) {
|
||||
std::memcpy(¶ms, input.data(), input.size());
|
||||
@@ -122,6 +128,7 @@ u32 nvhost_ctrl_gpu::ZCullGetCtxSize(const std::vector<u8>& input, std::vector<u
|
||||
|
||||
u32 nvhost_ctrl_gpu::ZCullGetInfo(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
LOG_DEBUG(Service_NVDRV, "called");
|
||||
|
||||
IoctlNvgpuGpuZcullGetInfoArgs params{};
|
||||
|
||||
if (input.size() > 0) {
|
||||
@@ -144,6 +151,7 @@ u32 nvhost_ctrl_gpu::ZCullGetInfo(const std::vector<u8>& input, std::vector<u8>&
|
||||
|
||||
u32 nvhost_ctrl_gpu::ZBCSetTable(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
LOG_WARNING(Service_NVDRV, "(STUBBED) called");
|
||||
|
||||
IoctlZbcSetTable params{};
|
||||
std::memcpy(¶ms, input.data(), input.size());
|
||||
// TODO(ogniK): What does this even actually do?
|
||||
@@ -153,6 +161,7 @@ u32 nvhost_ctrl_gpu::ZBCSetTable(const std::vector<u8>& input, std::vector<u8>&
|
||||
|
||||
u32 nvhost_ctrl_gpu::ZBCQueryTable(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
LOG_WARNING(Service_NVDRV, "(STUBBED) called");
|
||||
|
||||
IoctlZbcQueryTable params{};
|
||||
std::memcpy(¶ms, input.data(), input.size());
|
||||
// TODO : To implement properly
|
||||
@@ -162,6 +171,7 @@ u32 nvhost_ctrl_gpu::ZBCQueryTable(const std::vector<u8>& input, std::vector<u8>
|
||||
|
||||
u32 nvhost_ctrl_gpu::FlushL2(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
LOG_WARNING(Service_NVDRV, "(STUBBED) called");
|
||||
|
||||
IoctlFlushL2 params{};
|
||||
std::memcpy(¶ms, input.data(), input.size());
|
||||
// TODO : To implement properly
|
||||
@@ -169,4 +179,14 @@ u32 nvhost_ctrl_gpu::FlushL2(const std::vector<u8>& input, std::vector<u8>& outp
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 nvhost_ctrl_gpu::GetGpuTime(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
LOG_DEBUG(Service_NVDRV, "called");
|
||||
|
||||
IoctlGetGpuTime params{};
|
||||
std::memcpy(¶ms, input.data(), input.size());
|
||||
params.gpu_time = CoreTiming::cyclesToNs(CoreTiming::GetTicks());
|
||||
std::memcpy(output.data(), ¶ms, output.size());
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace Service::Nvidia::Devices
|
||||
|
||||
@@ -156,6 +156,11 @@ private:
|
||||
};
|
||||
static_assert(sizeof(IoctlFlushL2) == 8, "IoctlFlushL2 is incorrect size");
|
||||
|
||||
struct IoctlGetGpuTime {
|
||||
u64_le gpu_time;
|
||||
};
|
||||
static_assert(sizeof(IoctlGetGpuTime) == 8, "IoctlGetGpuTime is incorrect size");
|
||||
|
||||
u32 GetCharacteristics(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
u32 GetTPCMasks(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
u32 GetActiveSlotMask(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
@@ -164,6 +169,7 @@ private:
|
||||
u32 ZBCSetTable(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
u32 ZBCQueryTable(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
u32 FlushL2(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
u32 GetGpuTime(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
};
|
||||
|
||||
} // namespace Service::Nvidia::Devices
|
||||
|
||||
@@ -61,12 +61,14 @@ u32 nvhost_gpu::SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output
|
||||
IoctlSetNvmapFD params{};
|
||||
std::memcpy(¶ms, input.data(), input.size());
|
||||
LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd);
|
||||
|
||||
nvmap_fd = params.nvmap_fd;
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 nvhost_gpu::SetClientData(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
LOG_DEBUG(Service_NVDRV, "called");
|
||||
|
||||
IoctlClientData params{};
|
||||
std::memcpy(¶ms, input.data(), input.size());
|
||||
user_data = params.data;
|
||||
@@ -75,6 +77,7 @@ u32 nvhost_gpu::SetClientData(const std::vector<u8>& input, std::vector<u8>& out
|
||||
|
||||
u32 nvhost_gpu::GetClientData(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
LOG_DEBUG(Service_NVDRV, "called");
|
||||
|
||||
IoctlClientData params{};
|
||||
std::memcpy(¶ms, input.data(), input.size());
|
||||
params.data = user_data;
|
||||
@@ -86,6 +89,7 @@ u32 nvhost_gpu::ZCullBind(const std::vector<u8>& input, std::vector<u8>& output)
|
||||
std::memcpy(&zcull_params, input.data(), input.size());
|
||||
LOG_DEBUG(Service_NVDRV, "called, gpu_va={:X}, mode={:X}", zcull_params.gpu_va,
|
||||
zcull_params.mode);
|
||||
|
||||
std::memcpy(output.data(), &zcull_params, output.size());
|
||||
return 0;
|
||||
}
|
||||
@@ -95,6 +99,7 @@ u32 nvhost_gpu::SetErrorNotifier(const std::vector<u8>& input, std::vector<u8>&
|
||||
std::memcpy(¶ms, input.data(), input.size());
|
||||
LOG_WARNING(Service_NVDRV, "(STUBBED) called, offset={:X}, size={:X}, mem={:X}", params.offset,
|
||||
params.size, params.mem);
|
||||
|
||||
std::memcpy(output.data(), ¶ms, output.size());
|
||||
return 0;
|
||||
}
|
||||
@@ -102,6 +107,7 @@ u32 nvhost_gpu::SetErrorNotifier(const std::vector<u8>& input, std::vector<u8>&
|
||||
u32 nvhost_gpu::SetChannelPriority(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
std::memcpy(&channel_priority, input.data(), input.size());
|
||||
LOG_DEBUG(Service_NVDRV, "(STUBBED) called, priority={:X}", channel_priority);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -113,6 +119,7 @@ u32 nvhost_gpu::AllocGPFIFOEx2(const std::vector<u8>& input, std::vector<u8>& ou
|
||||
"unk1={:X}, unk2={:X}, unk3={:X}",
|
||||
params.num_entries, params.flags, params.unk0, params.unk1, params.unk2,
|
||||
params.unk3);
|
||||
|
||||
params.fence_out.id = 0;
|
||||
params.fence_out.value = 0;
|
||||
std::memcpy(output.data(), ¶ms, output.size());
|
||||
@@ -124,6 +131,7 @@ u32 nvhost_gpu::AllocateObjectContext(const std::vector<u8>& input, std::vector<
|
||||
std::memcpy(¶ms, input.data(), input.size());
|
||||
LOG_WARNING(Service_NVDRV, "(STUBBED) called, class_num={:X}, flags={:X}", params.class_num,
|
||||
params.flags);
|
||||
|
||||
params.obj_id = 0x0;
|
||||
std::memcpy(output.data(), ¶ms, output.size());
|
||||
return 0;
|
||||
@@ -179,6 +187,7 @@ u32 nvhost_gpu::GetWaitbase(const std::vector<u8>& input, std::vector<u8>& outpu
|
||||
IoctlGetWaitbase params{};
|
||||
std::memcpy(¶ms, input.data(), sizeof(IoctlGetWaitbase));
|
||||
LOG_INFO(Service_NVDRV, "called, unknown=0x{:X}", params.unknown);
|
||||
|
||||
params.value = 0; // Seems to be hard coded at 0
|
||||
std::memcpy(output.data(), ¶ms, output.size());
|
||||
return 0;
|
||||
@@ -188,6 +197,7 @@ u32 nvhost_gpu::ChannelSetTimeout(const std::vector<u8>& input, std::vector<u8>&
|
||||
IoctlChannelSetTimeout params{};
|
||||
std::memcpy(¶ms, input.data(), sizeof(IoctlChannelSetTimeout));
|
||||
LOG_INFO(Service_NVDRV, "called, timeout=0x{:X}", params.timeout);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -30,6 +30,7 @@ u32 nvhost_nvdec::SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& outp
|
||||
IoctlSetNvmapFD params{};
|
||||
std::memcpy(¶ms, input.data(), input.size());
|
||||
LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd);
|
||||
|
||||
nvmap_fd = params.nvmap_fd;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ u32 nvhost_nvjpg::SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& outp
|
||||
IoctlSetNvmapFD params{};
|
||||
std::memcpy(¶ms, input.data(), input.size());
|
||||
LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd);
|
||||
|
||||
nvmap_fd = params.nvmap_fd;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ u32 nvhost_vic::SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output
|
||||
IoctlSetNvmapFD params{};
|
||||
std::memcpy(¶ms, input.data(), input.size());
|
||||
LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd);
|
||||
|
||||
nvmap_fd = params.nvmap_fd;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -54,6 +54,7 @@ u32 nvmap::IocCreate(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
LOG_DEBUG(Service_NVDRV, "size=0x{:08X}", params.size);
|
||||
|
||||
if (!params.size) {
|
||||
LOG_ERROR(Service_NVDRV, "Size is 0");
|
||||
return static_cast<u32>(NvErrCodes::InvalidValue);
|
||||
}
|
||||
// Create a new nvmap object and obtain a handle to it.
|
||||
@@ -78,10 +79,12 @@ u32 nvmap::IocAlloc(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
LOG_DEBUG(Service_NVDRV, "called, addr={:X}", params.addr);
|
||||
|
||||
if (!params.handle) {
|
||||
LOG_ERROR(Service_NVDRV, "Handle is 0");
|
||||
return static_cast<u32>(NvErrCodes::InvalidValue);
|
||||
}
|
||||
|
||||
if ((params.align - 1) & params.align) {
|
||||
LOG_ERROR(Service_NVDRV, "Incorrect alignment used, alignment={:08X}", params.align);
|
||||
return static_cast<u32>(NvErrCodes::InvalidValue);
|
||||
}
|
||||
|
||||
@@ -92,10 +95,12 @@ u32 nvmap::IocAlloc(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
|
||||
auto object = GetObject(params.handle);
|
||||
if (!object) {
|
||||
LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle);
|
||||
return static_cast<u32>(NvErrCodes::InvalidValue);
|
||||
}
|
||||
|
||||
if (object->status == Object::Status::Allocated) {
|
||||
LOG_ERROR(Service_NVDRV, "Object is already allocated, handle={:08X}", params.handle);
|
||||
return static_cast<u32>(NvErrCodes::OperationNotPermitted);
|
||||
}
|
||||
|
||||
@@ -116,11 +121,13 @@ u32 nvmap::IocGetId(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
LOG_WARNING(Service_NVDRV, "called");
|
||||
|
||||
if (!params.handle) {
|
||||
LOG_ERROR(Service_NVDRV, "Handle is zero");
|
||||
return static_cast<u32>(NvErrCodes::InvalidValue);
|
||||
}
|
||||
|
||||
auto object = GetObject(params.handle);
|
||||
if (!object) {
|
||||
LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle);
|
||||
return static_cast<u32>(NvErrCodes::OperationNotPermitted);
|
||||
}
|
||||
|
||||
@@ -139,11 +146,13 @@ u32 nvmap::IocFromId(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
auto itr = std::find_if(handles.begin(), handles.end(),
|
||||
[&](const auto& entry) { return entry.second->id == params.id; });
|
||||
if (itr == handles.end()) {
|
||||
LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle);
|
||||
return static_cast<u32>(NvErrCodes::InvalidValue);
|
||||
}
|
||||
|
||||
auto& object = itr->second;
|
||||
if (object->status != Object::Status::Allocated) {
|
||||
LOG_ERROR(Service_NVDRV, "Object is not allocated, handle={:08X}", params.handle);
|
||||
return static_cast<u32>(NvErrCodes::InvalidValue);
|
||||
}
|
||||
|
||||
@@ -166,10 +175,12 @@ u32 nvmap::IocParam(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
|
||||
auto object = GetObject(params.handle);
|
||||
if (!object) {
|
||||
LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle);
|
||||
return static_cast<u32>(NvErrCodes::InvalidValue);
|
||||
}
|
||||
|
||||
if (object->status != Object::Status::Allocated) {
|
||||
LOG_ERROR(Service_NVDRV, "Object is not allocated, handle={:08X}", params.handle);
|
||||
return static_cast<u32>(NvErrCodes::OperationNotPermitted);
|
||||
}
|
||||
|
||||
@@ -209,9 +220,14 @@ u32 nvmap::IocFree(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
|
||||
auto itr = handles.find(params.handle);
|
||||
if (itr == handles.end()) {
|
||||
LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle);
|
||||
return static_cast<u32>(NvErrCodes::InvalidValue);
|
||||
}
|
||||
if (!itr->second->refcount) {
|
||||
LOG_ERROR(
|
||||
Service_NVDRV,
|
||||
"There is no references to this object. The object is already freed. handle={:08X}",
|
||||
params.handle);
|
||||
return static_cast<u32>(NvErrCodes::InvalidValue);
|
||||
}
|
||||
|
||||
|
||||
@@ -55,6 +55,7 @@ void NVDRV::Close(Kernel::HLERequestContext& ctx) {
|
||||
|
||||
void NVDRV::Initialize(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_NVDRV, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push<u32>(0);
|
||||
@@ -75,8 +76,8 @@ void NVDRV::QueryEvent(Kernel::HLERequestContext& ctx) {
|
||||
void NVDRV::SetClientPID(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
pid = rp.Pop<u64>();
|
||||
|
||||
LOG_WARNING(Service_NVDRV, "(STUBBED) called, pid=0x{:X}", pid);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push<u32>(0);
|
||||
@@ -84,6 +85,23 @@ void NVDRV::SetClientPID(Kernel::HLERequestContext& ctx) {
|
||||
|
||||
void NVDRV::FinishInitialize(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_NVDRV, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
|
||||
void NVDRV::GetStatus(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_NVDRV, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
|
||||
void NVDRV::DumpGraphicsMemoryInfo(Kernel::HLERequestContext& ctx) {
|
||||
// According to SwitchBrew, this has no inputs and no outputs, so effectively does nothing on
|
||||
// retail hardware.
|
||||
LOG_DEBUG(Service_NVDRV, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
@@ -97,10 +115,10 @@ NVDRV::NVDRV(std::shared_ptr<Module> nvdrv, const char* name)
|
||||
{3, &NVDRV::Initialize, "Initialize"},
|
||||
{4, &NVDRV::QueryEvent, "QueryEvent"},
|
||||
{5, nullptr, "MapSharedMem"},
|
||||
{6, nullptr, "GetStatus"},
|
||||
{6, &NVDRV::GetStatus, "GetStatus"},
|
||||
{7, nullptr, "ForceSetClientPID"},
|
||||
{8, &NVDRV::SetClientPID, "SetClientPID"},
|
||||
{9, nullptr, "DumpGraphicsMemoryInfo"},
|
||||
{9, &NVDRV::DumpGraphicsMemoryInfo, "DumpGraphicsMemoryInfo"},
|
||||
{10, nullptr, "InitializeDevtools"},
|
||||
{11, &NVDRV::Ioctl, "Ioctl2"},
|
||||
{12, nullptr, "Ioctl3"},
|
||||
|
||||
@@ -24,6 +24,8 @@ private:
|
||||
void QueryEvent(Kernel::HLERequestContext& ctx);
|
||||
void SetClientPID(Kernel::HLERequestContext& ctx);
|
||||
void FinishInitialize(Kernel::HLERequestContext& ctx);
|
||||
void GetStatus(Kernel::HLERequestContext& ctx);
|
||||
void DumpGraphicsMemoryInfo(Kernel::HLERequestContext& ctx);
|
||||
|
||||
std::shared_ptr<Module> nvdrv;
|
||||
|
||||
|
||||
@@ -20,13 +20,13 @@ BufferQueue::BufferQueue(u32 id, u64 layer_id) : id(id), layer_id(layer_id) {
|
||||
BufferQueue::~BufferQueue() = default;
|
||||
|
||||
void BufferQueue::SetPreallocatedBuffer(u32 slot, const IGBPBuffer& igbp_buffer) {
|
||||
LOG_WARNING(Service, "Adding graphics buffer {}", slot);
|
||||
|
||||
Buffer buffer{};
|
||||
buffer.slot = slot;
|
||||
buffer.igbp_buffer = igbp_buffer;
|
||||
buffer.status = Buffer::Status::Free;
|
||||
|
||||
LOG_WARNING(Service, "Adding graphics buffer {}", slot);
|
||||
|
||||
queue.emplace_back(buffer);
|
||||
buffer_wait_event->Signal();
|
||||
}
|
||||
@@ -92,6 +92,7 @@ void BufferQueue::ReleaseBuffer(u32 slot) {
|
||||
|
||||
u32 BufferQueue::Query(QueryType type) {
|
||||
LOG_WARNING(Service, "(STUBBED) called type={}", static_cast<u32>(type));
|
||||
|
||||
switch (type) {
|
||||
case QueryType::NativeWindowFormat:
|
||||
// TODO(Subv): Use an enum for this
|
||||
|
||||
@@ -114,29 +114,33 @@ public:
|
||||
private:
|
||||
void Initialize(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_PCTL, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 0};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
|
||||
void CheckFreeCommunicationPermission(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_PCTL, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
};
|
||||
|
||||
void Module::Interface::CreateService(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_PCTL, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<IParentalControlService>();
|
||||
LOG_DEBUG(Service_PCTL, "called");
|
||||
}
|
||||
|
||||
void Module::Interface::CreateServiceWithoutInitialize(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_PCTL, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<IParentalControlService>();
|
||||
LOG_DEBUG(Service_PCTL, "called");
|
||||
}
|
||||
|
||||
Module::Interface::Interface(std::shared_ptr<Module> module, const char* name)
|
||||
|
||||
@@ -20,11 +20,11 @@ public:
|
||||
|
||||
private:
|
||||
void GetBootMode(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_PM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push<u32>(static_cast<u32>(SystemBootMode::Normal)); // Normal boot mode
|
||||
|
||||
LOG_DEBUG(Service_PM, "called");
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -61,11 +61,11 @@ public:
|
||||
|
||||
private:
|
||||
void GetPmModule(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_PSC, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<IPmModule>();
|
||||
|
||||
LOG_DEBUG(Service_PSC, "called");
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -49,38 +49,39 @@ static std::array<LanguageCode, size> MakeLanguageCodeSubset() {
|
||||
static void PushResponseLanguageCode(Kernel::HLERequestContext& ctx, std::size_t max_size) {
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
if (available_language_codes.size() > max_size)
|
||||
if (available_language_codes.size() > max_size) {
|
||||
rb.Push(static_cast<u32>(max_size));
|
||||
else
|
||||
} else {
|
||||
rb.Push(static_cast<u32>(available_language_codes.size()));
|
||||
}
|
||||
}
|
||||
|
||||
void SET::GetAvailableLanguageCodes(Kernel::HLERequestContext& ctx) {
|
||||
if (available_language_codes.size() > pre4_0_0_max_entries)
|
||||
ctx.WriteBuffer(MakeLanguageCodeSubset<pre4_0_0_max_entries>());
|
||||
else
|
||||
ctx.WriteBuffer(available_language_codes);
|
||||
|
||||
PushResponseLanguageCode(ctx, pre4_0_0_max_entries);
|
||||
|
||||
LOG_DEBUG(Service_SET, "called");
|
||||
|
||||
if (available_language_codes.size() > pre4_0_0_max_entries) {
|
||||
ctx.WriteBuffer(MakeLanguageCodeSubset<pre4_0_0_max_entries>());
|
||||
} else {
|
||||
ctx.WriteBuffer(available_language_codes);
|
||||
}
|
||||
PushResponseLanguageCode(ctx, pre4_0_0_max_entries);
|
||||
}
|
||||
|
||||
void SET::GetAvailableLanguageCodes2(Kernel::HLERequestContext& ctx) {
|
||||
if (available_language_codes.size() > post4_0_0_max_entries)
|
||||
ctx.WriteBuffer(MakeLanguageCodeSubset<post4_0_0_max_entries>());
|
||||
else
|
||||
ctx.WriteBuffer(available_language_codes);
|
||||
|
||||
PushResponseLanguageCode(ctx, post4_0_0_max_entries);
|
||||
|
||||
LOG_DEBUG(Service_SET, "called");
|
||||
|
||||
if (available_language_codes.size() > post4_0_0_max_entries) {
|
||||
ctx.WriteBuffer(MakeLanguageCodeSubset<post4_0_0_max_entries>());
|
||||
} else {
|
||||
ctx.WriteBuffer(available_language_codes);
|
||||
}
|
||||
PushResponseLanguageCode(ctx, post4_0_0_max_entries);
|
||||
}
|
||||
|
||||
void SET::GetAvailableLanguageCodeCount(Kernel::HLERequestContext& ctx) {
|
||||
PushResponseLanguageCode(ctx, pre4_0_0_max_entries);
|
||||
|
||||
LOG_DEBUG(Service_SET, "called");
|
||||
|
||||
PushResponseLanguageCode(ctx, pre4_0_0_max_entries);
|
||||
}
|
||||
|
||||
void SET::GetAvailableLanguageCodeCount2(Kernel::HLERequestContext& ctx) {
|
||||
@@ -90,11 +91,11 @@ void SET::GetAvailableLanguageCodeCount2(Kernel::HLERequestContext& ctx) {
|
||||
}
|
||||
|
||||
void SET::GetLanguageCode(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_SET, "called {}", Settings::values.language_index);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push(static_cast<u64>(available_language_codes[Settings::values.language_index]));
|
||||
|
||||
LOG_DEBUG(Service_SET, "called {}", Settings::values.language_index);
|
||||
}
|
||||
|
||||
SET::SET() : ServiceFramework("set") {
|
||||
|
||||
@@ -10,22 +10,22 @@
|
||||
namespace Service::Set {
|
||||
|
||||
void SET_SYS::GetColorSetId(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_SET, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushEnum(color_set);
|
||||
|
||||
LOG_DEBUG(Service_SET, "called");
|
||||
}
|
||||
|
||||
void SET_SYS::SetColorSetId(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_SET, "called");
|
||||
|
||||
IPC::RequestParser rp{ctx};
|
||||
color_set = rp.PopEnum<ColorSet>();
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
|
||||
LOG_DEBUG(Service_SET, "called");
|
||||
}
|
||||
|
||||
SET_SYS::SET_SYS() : ServiceFramework("set:sys") {
|
||||
|
||||
@@ -14,25 +14,26 @@ namespace Service::SM {
|
||||
|
||||
void Controller::ConvertSessionToDomain(Kernel::HLERequestContext& ctx) {
|
||||
ASSERT_MSG(ctx.Session()->IsSession(), "Session is already a domain");
|
||||
LOG_DEBUG(Service, "called, server_session={}", ctx.Session()->GetObjectId());
|
||||
ctx.Session()->ConvertToDomain();
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push<u32>(1); // Converted sessions start with 1 request handler
|
||||
|
||||
LOG_DEBUG(Service, "called, server_session={}", ctx.Session()->GetObjectId());
|
||||
}
|
||||
|
||||
void Controller::DuplicateSession(Kernel::HLERequestContext& ctx) {
|
||||
// TODO(bunnei): This is just creating a new handle to the same Session. I assume this is wrong
|
||||
// and that we probably want to actually make an entirely new Session, but we still need to
|
||||
// verify this on hardware.
|
||||
LOG_DEBUG(Service, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
Kernel::SharedPtr<Kernel::ClientSession> session{ctx.Session()->parent->client};
|
||||
rb.PushMoveObjects(session);
|
||||
|
||||
LOG_DEBUG(Service, "called, session={}", session->GetObjectId());
|
||||
LOG_DEBUG(Service, "session={}", session->GetObjectId());
|
||||
}
|
||||
|
||||
void Controller::DuplicateSessionEx(Kernel::HLERequestContext& ctx) {
|
||||
@@ -42,11 +43,11 @@ void Controller::DuplicateSessionEx(Kernel::HLERequestContext& ctx) {
|
||||
}
|
||||
|
||||
void Controller::QueryPointerBufferSize(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push<u16>(0x500);
|
||||
|
||||
LOG_WARNING(Service, "(STUBBED) called");
|
||||
}
|
||||
|
||||
Controller::Controller() : ServiceFramework("IpcController") {
|
||||
|
||||
@@ -63,6 +63,17 @@ ResultVal<Kernel::SharedPtr<Kernel::ServerPort>> ServiceManager::RegisterService
|
||||
return MakeResult<Kernel::SharedPtr<Kernel::ServerPort>>(std::move(server_port));
|
||||
}
|
||||
|
||||
ResultCode ServiceManager::UnregisterService(std::string name) {
|
||||
CASCADE_CODE(ValidateServiceName(name));
|
||||
|
||||
const auto iter = registered_services.find(name);
|
||||
if (iter == registered_services.end())
|
||||
return ERR_SERVICE_NOT_REGISTERED;
|
||||
|
||||
registered_services.erase(iter);
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
ResultVal<Kernel::SharedPtr<Kernel::ClientPort>> ServiceManager::GetServicePort(
|
||||
const std::string& name) {
|
||||
|
||||
@@ -92,9 +103,10 @@ SM::~SM() = default;
|
||||
* 0: ResultCode
|
||||
*/
|
||||
void SM::Initialize(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_SM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_DEBUG(Service_SM, "called");
|
||||
}
|
||||
|
||||
void SM::GetService(Kernel::HLERequestContext& ctx) {
|
||||
@@ -127,13 +139,53 @@ void SM::GetService(Kernel::HLERequestContext& ctx) {
|
||||
}
|
||||
}
|
||||
|
||||
void SM::RegisterService(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
|
||||
const auto name_buf = rp.PopRaw<std::array<char, 8>>();
|
||||
const auto end = std::find(name_buf.begin(), name_buf.end(), '\0');
|
||||
|
||||
const std::string name(name_buf.begin(), end);
|
||||
|
||||
const auto unk_bool = static_cast<bool>(rp.PopRaw<u32>());
|
||||
const auto session_count = rp.PopRaw<u32>();
|
||||
|
||||
LOG_DEBUG(Service_SM, "called with unk_bool={}", unk_bool);
|
||||
|
||||
auto handle = service_manager->RegisterService(name, session_count);
|
||||
if (handle.Failed()) {
|
||||
LOG_ERROR(Service_SM, "failed to register service with error_code={:08X}",
|
||||
handle.Code().raw);
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(handle.Code());
|
||||
return;
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles};
|
||||
rb.Push(handle.Code());
|
||||
rb.PushMoveObjects(std::move(handle).Unwrap());
|
||||
}
|
||||
|
||||
void SM::UnregisterService(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
|
||||
const auto name_buf = rp.PopRaw<std::array<char, 8>>();
|
||||
const auto end = std::find(name_buf.begin(), name_buf.end(), '\0');
|
||||
|
||||
const std::string name(name_buf.begin(), end);
|
||||
LOG_DEBUG(Service_SM, "called with name={}", name);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(service_manager->UnregisterService(name));
|
||||
}
|
||||
|
||||
SM::SM(std::shared_ptr<ServiceManager> service_manager)
|
||||
: ServiceFramework("sm:", 4), service_manager(std::move(service_manager)) {
|
||||
static const FunctionInfo functions[] = {
|
||||
{0x00000000, &SM::Initialize, "Initialize"},
|
||||
{0x00000001, &SM::GetService, "GetService"},
|
||||
{0x00000002, nullptr, "RegisterService"},
|
||||
{0x00000003, nullptr, "UnregisterService"},
|
||||
{0x00000002, &SM::RegisterService, "RegisterService"},
|
||||
{0x00000003, &SM::UnregisterService, "UnregisterService"},
|
||||
};
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
@@ -35,6 +35,8 @@ public:
|
||||
private:
|
||||
void Initialize(Kernel::HLERequestContext& ctx);
|
||||
void GetService(Kernel::HLERequestContext& ctx);
|
||||
void RegisterService(Kernel::HLERequestContext& ctx);
|
||||
void UnregisterService(Kernel::HLERequestContext& ctx);
|
||||
|
||||
std::shared_ptr<ServiceManager> service_manager;
|
||||
};
|
||||
@@ -48,6 +50,7 @@ public:
|
||||
|
||||
ResultVal<Kernel::SharedPtr<Kernel::ServerPort>> RegisterService(std::string name,
|
||||
unsigned int max_sessions);
|
||||
ResultCode UnregisterService(std::string name);
|
||||
ResultVal<Kernel::SharedPtr<Kernel::ClientPort>> GetServicePort(const std::string& name);
|
||||
ResultVal<Kernel::SharedPtr<Kernel::ClientSession>> ConnectToService(const std::string& name);
|
||||
|
||||
|
||||
@@ -24,6 +24,8 @@ Module::Interface::Interface(std::shared_ptr<Module> module, const char* name)
|
||||
Module::Interface::~Interface() = default;
|
||||
|
||||
void Module::Interface::GetRandomBytes(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_SPL, "called");
|
||||
|
||||
IPC::RequestParser rp{ctx};
|
||||
|
||||
std::size_t size = ctx.GetWriteBufferSize();
|
||||
@@ -36,7 +38,6 @@ void Module::Interface::GetRandomBytes(Kernel::HLERequestContext& ctx) {
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_DEBUG(Service_SPL, "called");
|
||||
}
|
||||
|
||||
void InstallInterfaces(SM::ServiceManager& service_manager) {
|
||||
|
||||
@@ -69,6 +69,7 @@ public:
|
||||
private:
|
||||
void SetOption(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_SSL, "(STUBBED) called");
|
||||
|
||||
IPC::RequestParser rp{ctx};
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
@@ -114,6 +115,7 @@ private:
|
||||
|
||||
void SetInterfaceVersion(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_SSL, "called");
|
||||
|
||||
IPC::RequestParser rp{ctx};
|
||||
ssl_version = rp.Pop<u32>();
|
||||
|
||||
|
||||
@@ -72,6 +72,7 @@ private:
|
||||
std::chrono::system_clock::now().time_since_epoch())
|
||||
.count()};
|
||||
LOG_DEBUG(Service_Time, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push<u64>(time_since_epoch);
|
||||
@@ -79,6 +80,7 @@ private:
|
||||
|
||||
void GetSystemClockContext(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_Time, "(STUBBED) called");
|
||||
|
||||
SystemClockContext system_clock_ontext{};
|
||||
IPC::ResponseBuilder rb{ctx, (sizeof(SystemClockContext) / 4) + 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
@@ -98,6 +100,7 @@ public:
|
||||
private:
|
||||
void GetCurrentTimePoint(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Time, "called");
|
||||
|
||||
SteadyClockTimePoint steady_clock_time_point{
|
||||
CoreTiming::cyclesToMs(CoreTiming::GetTicks()) / 1000};
|
||||
IPC::ResponseBuilder rb{ctx, (sizeof(SteadyClockTimePoint) / 4) + 2};
|
||||
@@ -130,6 +133,7 @@ private:
|
||||
|
||||
void GetDeviceLocationName(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Time, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, (sizeof(LocationName) / 4) + 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushRaw(location_name);
|
||||
@@ -137,6 +141,7 @@ private:
|
||||
|
||||
void GetTotalLocationNameCount(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_Time, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push<u32>(0);
|
||||
@@ -154,7 +159,6 @@ private:
|
||||
void ToCalendarTime(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const u64 posix_time = rp.Pop<u64>();
|
||||
|
||||
LOG_WARNING(Service_Time, "(STUBBED) called, posix_time=0x{:016X}", posix_time);
|
||||
|
||||
TimeZoneRule time_zone_rule{};
|
||||
@@ -175,7 +179,6 @@ private:
|
||||
void ToCalendarTimeWithMyRule(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const u64 posix_time = rp.Pop<u64>();
|
||||
|
||||
LOG_WARNING(Service_Time, "(STUBBED) called, posix_time=0x{:016X}", posix_time);
|
||||
|
||||
CalendarTime calendar_time{2018, 1, 1, 0, 0, 0};
|
||||
@@ -192,6 +195,7 @@ private:
|
||||
void ToPosixTime(Kernel::HLERequestContext& ctx) {
|
||||
// TODO(ogniK): Figure out how to handle multiple times
|
||||
LOG_WARNING(Service_Time, "(STUBBED) called");
|
||||
|
||||
IPC::RequestParser rp{ctx};
|
||||
auto calendar_time = rp.PopRaw<CalendarTime>();
|
||||
auto posix_time = CalendarToPosix(calendar_time, {});
|
||||
@@ -204,6 +208,7 @@ private:
|
||||
|
||||
void ToPosixTimeWithMyRule(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_Time, "(STUBBED) called");
|
||||
|
||||
IPC::RequestParser rp{ctx};
|
||||
auto calendar_time = rp.PopRaw<CalendarTime>();
|
||||
auto posix_time = CalendarToPosix(calendar_time, {});
|
||||
@@ -216,38 +221,43 @@ private:
|
||||
};
|
||||
|
||||
void Module::Interface::GetStandardUserSystemClock(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Time, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<ISystemClock>();
|
||||
LOG_DEBUG(Service_Time, "called");
|
||||
}
|
||||
|
||||
void Module::Interface::GetStandardNetworkSystemClock(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Time, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<ISystemClock>();
|
||||
LOG_DEBUG(Service_Time, "called");
|
||||
}
|
||||
|
||||
void Module::Interface::GetStandardSteadyClock(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Time, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<ISteadyClock>();
|
||||
LOG_DEBUG(Service_Time, "called");
|
||||
}
|
||||
|
||||
void Module::Interface::GetTimeZoneService(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Time, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<ITimeZoneService>();
|
||||
LOG_DEBUG(Service_Time, "called");
|
||||
}
|
||||
|
||||
void Module::Interface::GetStandardLocalSystemClock(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Time, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<ISystemClock>();
|
||||
LOG_DEBUG(Service_Time, "called");
|
||||
}
|
||||
|
||||
void Module::Interface::GetClockSnapshot(Kernel::HLERequestContext& ctx) {
|
||||
@@ -265,6 +275,7 @@ void Module::Interface::GetClockSnapshot(Kernel::HLERequestContext& ctx) {
|
||||
const std::time_t time(time_since_epoch);
|
||||
const std::tm* tm = std::localtime(&time);
|
||||
if (tm == nullptr) {
|
||||
LOG_ERROR(Service_Time, "tm is a nullptr");
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultCode(-1)); // TODO(ogniK): Find appropriate error code
|
||||
return;
|
||||
|
||||
@@ -159,11 +159,11 @@ public:
|
||||
|
||||
private:
|
||||
void GetPdSession(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_USB, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<IPdSession>();
|
||||
|
||||
LOG_DEBUG(Service_USB, "called");
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -504,13 +504,17 @@ private:
|
||||
u32 id = rp.Pop<u32>();
|
||||
auto transaction = static_cast<TransactionId>(rp.Pop<u32>());
|
||||
u32 flags = rp.Pop<u32>();
|
||||
auto buffer_queue = nv_flinger->GetBufferQueue(id);
|
||||
|
||||
LOG_DEBUG(Service_VI, "called, transaction={:X}", static_cast<u32>(transaction));
|
||||
|
||||
auto buffer_queue = nv_flinger->GetBufferQueue(id);
|
||||
|
||||
if (transaction == TransactionId::Connect) {
|
||||
IGBPConnectRequestParcel request{ctx.ReadBuffer()};
|
||||
IGBPConnectResponseParcel response{1280, 720};
|
||||
IGBPConnectResponseParcel response{
|
||||
static_cast<u32>(static_cast<u32>(DisplayResolution::UndockedWidth) *
|
||||
Settings::values.resolution_factor),
|
||||
static_cast<u32>(static_cast<u32>(DisplayResolution::UndockedHeight) *
|
||||
Settings::values.resolution_factor)};
|
||||
ctx.WriteBuffer(response.Serialize());
|
||||
} else if (transaction == TransactionId::SetPreallocatedBuffer) {
|
||||
IGBPSetPreallocatedBufferRequestParcel request{ctx.ReadBuffer()};
|
||||
@@ -589,9 +593,9 @@ private:
|
||||
u32 id = rp.Pop<u32>();
|
||||
s32 addval = rp.PopRaw<s32>();
|
||||
u32 type = rp.Pop<u32>();
|
||||
|
||||
LOG_WARNING(Service_VI, "(STUBBED) called id={}, addval={:08X}, type={:08X}", id, addval,
|
||||
type);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
@@ -600,12 +604,11 @@ private:
|
||||
IPC::RequestParser rp{ctx};
|
||||
u32 id = rp.Pop<u32>();
|
||||
u32 unknown = rp.Pop<u32>();
|
||||
LOG_WARNING(Service_VI, "(STUBBED) called id={}, unknown={:08X}", id, unknown);
|
||||
|
||||
auto buffer_queue = nv_flinger->GetBufferQueue(id);
|
||||
|
||||
// TODO(Subv): Find out what this actually is.
|
||||
|
||||
LOG_WARNING(Service_VI, "(STUBBED) called id={}, unknown={:08X}", id, unknown);
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushCopyObjects(buffer_queue->GetBufferWaitEvent());
|
||||
@@ -669,6 +672,7 @@ public:
|
||||
private:
|
||||
void SetLayerZ(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_VI, "(STUBBED) called");
|
||||
|
||||
IPC::RequestParser rp{ctx};
|
||||
u64 layer_id = rp.Pop<u64>();
|
||||
u64 z_value = rp.Pop<u64>();
|
||||
@@ -681,28 +685,33 @@ private:
|
||||
IPC::RequestParser rp{ctx};
|
||||
u64 layer_id = rp.Pop<u64>();
|
||||
bool visibility = rp.Pop<bool>();
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_WARNING(Service_VI, "(STUBBED) called, layer_id=0x{:08X}, visibility={}", layer_id,
|
||||
visibility);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
|
||||
void GetDisplayMode(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_VI, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 6};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
|
||||
if (Settings::values.use_docked_mode) {
|
||||
rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedWidth));
|
||||
rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedHeight));
|
||||
rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedWidth) *
|
||||
static_cast<u32>(Settings::values.resolution_factor));
|
||||
rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedHeight) *
|
||||
static_cast<u32>(Settings::values.resolution_factor));
|
||||
} else {
|
||||
rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedWidth));
|
||||
rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedHeight));
|
||||
rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedWidth) *
|
||||
static_cast<u32>(Settings::values.resolution_factor));
|
||||
rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedHeight) *
|
||||
static_cast<u32>(Settings::values.resolution_factor));
|
||||
}
|
||||
|
||||
rb.PushRaw<float>(60.0f);
|
||||
rb.PushRaw<float>(60.0f); // This wouldn't seem to be correct for 30 fps games.
|
||||
rb.Push<u32>(0);
|
||||
|
||||
LOG_DEBUG(Service_VI, "called");
|
||||
}
|
||||
};
|
||||
|
||||
@@ -785,6 +794,7 @@ public:
|
||||
private:
|
||||
void CloseDisplay(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_VI, "(STUBBED) called");
|
||||
|
||||
IPC::RequestParser rp{ctx};
|
||||
u64 display = rp.Pop<u64>();
|
||||
|
||||
@@ -794,6 +804,7 @@ private:
|
||||
|
||||
void CreateManagedLayer(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_VI, "(STUBBED) called");
|
||||
|
||||
IPC::RequestParser rp{ctx};
|
||||
u32 unknown = rp.Pop<u32>();
|
||||
rp.Skip(1, false);
|
||||
@@ -809,6 +820,7 @@ private:
|
||||
|
||||
void AddToLayerStack(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_VI, "(STUBBED) called");
|
||||
|
||||
IPC::RequestParser rp{ctx};
|
||||
u32 stack = rp.Pop<u32>();
|
||||
u64 layer_id = rp.Pop<u64>();
|
||||
@@ -821,10 +833,11 @@ private:
|
||||
IPC::RequestParser rp{ctx};
|
||||
u64 layer_id = rp.Pop<u64>();
|
||||
bool visibility = rp.Pop<bool>();
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_WARNING(Service_VI, "(STUBBED) called, layer_id=0x{:X}, visibility={}", layer_id,
|
||||
visibility);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
|
||||
std::shared_ptr<NVFlinger::NVFlinger> nv_flinger;
|
||||
@@ -870,6 +883,7 @@ private:
|
||||
|
||||
void OpenDisplay(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_VI, "(STUBBED) called");
|
||||
|
||||
IPC::RequestParser rp{ctx};
|
||||
auto name_buf = rp.PopRaw<std::array<u8, 0x40>>();
|
||||
auto end = std::find(name_buf.begin(), name_buf.end(), '\0');
|
||||
@@ -885,6 +899,7 @@ private:
|
||||
|
||||
void CloseDisplay(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_VI, "(STUBBED) called");
|
||||
|
||||
IPC::RequestParser rp{ctx};
|
||||
u64 display_id = rp.Pop<u64>();
|
||||
|
||||
@@ -894,6 +909,7 @@ private:
|
||||
|
||||
void GetDisplayResolution(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_VI, "(STUBBED) called");
|
||||
|
||||
IPC::RequestParser rp{ctx};
|
||||
u64 display_id = rp.Pop<u64>();
|
||||
|
||||
@@ -901,16 +917,21 @@ private:
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
|
||||
if (Settings::values.use_docked_mode) {
|
||||
rb.Push(static_cast<u64>(DisplayResolution::DockedWidth));
|
||||
rb.Push(static_cast<u64>(DisplayResolution::DockedHeight));
|
||||
rb.Push(static_cast<u64>(DisplayResolution::DockedWidth) *
|
||||
static_cast<u32>(Settings::values.resolution_factor));
|
||||
rb.Push(static_cast<u64>(DisplayResolution::DockedHeight) *
|
||||
static_cast<u32>(Settings::values.resolution_factor));
|
||||
} else {
|
||||
rb.Push(static_cast<u64>(DisplayResolution::UndockedWidth));
|
||||
rb.Push(static_cast<u64>(DisplayResolution::UndockedHeight));
|
||||
rb.Push(static_cast<u64>(DisplayResolution::UndockedWidth) *
|
||||
static_cast<u32>(Settings::values.resolution_factor));
|
||||
rb.Push(static_cast<u64>(DisplayResolution::UndockedHeight) *
|
||||
static_cast<u32>(Settings::values.resolution_factor));
|
||||
}
|
||||
}
|
||||
|
||||
void SetLayerScalingMode(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_VI, "(STUBBED) called");
|
||||
|
||||
IPC::RequestParser rp{ctx};
|
||||
u32 scaling_mode = rp.Pop<u32>();
|
||||
u64 unknown = rp.Pop<u64>();
|
||||
@@ -920,17 +941,21 @@ private:
|
||||
}
|
||||
|
||||
void ListDisplays(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_VI, "(STUBBED) called");
|
||||
|
||||
IPC::RequestParser rp{ctx};
|
||||
DisplayInfo display_info;
|
||||
display_info.width *= static_cast<u64>(Settings::values.resolution_factor);
|
||||
display_info.height *= static_cast<u64>(Settings::values.resolution_factor);
|
||||
ctx.WriteBuffer(&display_info, sizeof(DisplayInfo));
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push<u64>(1);
|
||||
LOG_WARNING(Service_VI, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void OpenLayer(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_VI, "called");
|
||||
|
||||
IPC::RequestParser rp{ctx};
|
||||
auto name_buf = rp.PopRaw<std::array<u8, 0x40>>();
|
||||
auto end = std::find(name_buf.begin(), name_buf.end(), '\0');
|
||||
@@ -981,6 +1006,7 @@ private:
|
||||
|
||||
void GetDisplayVsyncEvent(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_VI, "(STUBBED) called");
|
||||
|
||||
IPC::RequestParser rp{ctx};
|
||||
u64 display_id = rp.Pop<u64>();
|
||||
|
||||
|
||||
@@ -403,6 +403,7 @@ struct Values {
|
||||
bool use_gdbstub;
|
||||
u16 gdbstub_port;
|
||||
std::string program_args;
|
||||
bool dump_exefs;
|
||||
bool dump_nso;
|
||||
|
||||
// WebService
|
||||
|
||||
@@ -389,6 +389,13 @@ public:
|
||||
ReverseSubtract = 3,
|
||||
Min = 4,
|
||||
Max = 5,
|
||||
|
||||
// These values are used by Nouveau and some games.
|
||||
AddGL = 0x8006,
|
||||
SubtractGL = 0x8007,
|
||||
ReverseSubtractGL = 0x8008,
|
||||
MinGL = 0x800a,
|
||||
MaxGL = 0x800b
|
||||
};
|
||||
|
||||
enum class Factor : u32 {
|
||||
@@ -624,7 +631,16 @@ public:
|
||||
}
|
||||
} zeta;
|
||||
|
||||
INSERT_PADDING_WORDS(0x5B);
|
||||
INSERT_PADDING_WORDS(0x41);
|
||||
|
||||
union {
|
||||
BitField<0, 4, u32> stencil;
|
||||
BitField<4, 4, u32> unknown;
|
||||
BitField<8, 4, u32> scissor;
|
||||
BitField<12, 4, u32> viewport;
|
||||
} clear_flags;
|
||||
|
||||
INSERT_PADDING_WORDS(0x19);
|
||||
|
||||
std::array<VertexAttribute, NumVertexAttributes> vertex_attrib_format;
|
||||
|
||||
@@ -1127,6 +1143,7 @@ ASSERT_REG_POSITION(stencil_back_func_mask, 0x3D7);
|
||||
ASSERT_REG_POSITION(color_mask_common, 0x3E4);
|
||||
ASSERT_REG_POSITION(rt_separate_frag_data, 0x3EB);
|
||||
ASSERT_REG_POSITION(zeta, 0x3F8);
|
||||
ASSERT_REG_POSITION(clear_flags, 0x43E);
|
||||
ASSERT_REG_POSITION(vertex_attrib_format, 0x458);
|
||||
ASSERT_REG_POSITION(rt_control, 0x487);
|
||||
ASSERT_REG_POSITION(zeta_width, 0x48a);
|
||||
|
||||
@@ -153,6 +153,7 @@ enum class PredCondition : u64 {
|
||||
NotEqual = 5,
|
||||
GreaterEqual = 6,
|
||||
LessThanWithNan = 9,
|
||||
LessEqualWithNan = 11,
|
||||
GreaterThanWithNan = 12,
|
||||
NotEqualWithNan = 13,
|
||||
GreaterEqualWithNan = 14,
|
||||
@@ -261,7 +262,7 @@ enum class FlowCondition : u64 {
|
||||
Fcsm_Tr = 0x1C, // TODO(bunnei): What is this used for?
|
||||
};
|
||||
|
||||
enum class ControlCode : u64 {
|
||||
enum class ConditionCode : u64 {
|
||||
F = 0,
|
||||
LT = 1,
|
||||
EQ = 2,
|
||||
@@ -569,7 +570,6 @@ union Instruction {
|
||||
BitField<39, 2, u64> tab5cb8_2;
|
||||
BitField<41, 3, u64> tab5c68_1;
|
||||
BitField<44, 2, u64> tab5c68_0;
|
||||
BitField<47, 1, u64> cc;
|
||||
BitField<48, 1, u64> negate_b;
|
||||
} fmul;
|
||||
|
||||
@@ -831,7 +831,7 @@ union Instruction {
|
||||
union {
|
||||
BitField<0, 3, u64> pred0;
|
||||
BitField<3, 3, u64> pred3;
|
||||
BitField<8, 5, ControlCode> cc; // flag in cc
|
||||
BitField<8, 5, ConditionCode> cc; // flag in cc
|
||||
BitField<39, 3, u64> pred39;
|
||||
BitField<42, 1, u64> neg_pred39;
|
||||
BitField<45, 4, PredOperation> op; // op with pred39
|
||||
@@ -1235,7 +1235,7 @@ union Instruction {
|
||||
BitField<60, 1, u64> is_b_gpr;
|
||||
BitField<59, 1, u64> is_c_gpr;
|
||||
BitField<20, 24, s64> smem_imm;
|
||||
BitField<0, 5, ControlCode> flow_control_code;
|
||||
BitField<0, 5, ConditionCode> flow_condition_code;
|
||||
|
||||
Attribute attribute;
|
||||
Sampler sampler;
|
||||
|
||||
@@ -17,6 +17,8 @@ u32 FramebufferConfig::BytesPerPixel(PixelFormat format) {
|
||||
switch (format) {
|
||||
case PixelFormat::ABGR8:
|
||||
return 4;
|
||||
default:
|
||||
return 4;
|
||||
}
|
||||
|
||||
UNREACHABLE();
|
||||
|
||||
@@ -35,6 +35,7 @@ void MacroInterpreter::Reset() {
|
||||
// The next parameter index starts at 1, because $r1 already has the value of the first
|
||||
// parameter.
|
||||
next_parameter_index = 1;
|
||||
carry_flag = false;
|
||||
}
|
||||
|
||||
bool MacroInterpreter::Step(u32 offset, bool is_delay_slot) {
|
||||
@@ -135,14 +136,28 @@ MacroInterpreter::Opcode MacroInterpreter::GetOpcode(u32 offset) const {
|
||||
return {macro_memory[offset + pc / sizeof(u32)]};
|
||||
}
|
||||
|
||||
u32 MacroInterpreter::GetALUResult(ALUOperation operation, u32 src_a, u32 src_b) const {
|
||||
u32 MacroInterpreter::GetALUResult(ALUOperation operation, u32 src_a, u32 src_b) {
|
||||
switch (operation) {
|
||||
case ALUOperation::Add:
|
||||
return src_a + src_b;
|
||||
// TODO(Subv): Implement AddWithCarry
|
||||
case ALUOperation::Subtract:
|
||||
return src_a - src_b;
|
||||
// TODO(Subv): Implement SubtractWithBorrow
|
||||
case ALUOperation::Add: {
|
||||
const u64 result{static_cast<u64>(src_a) + src_b};
|
||||
carry_flag = result > 0xffffffff;
|
||||
return static_cast<u32>(result);
|
||||
}
|
||||
case ALUOperation::AddWithCarry: {
|
||||
const u64 result{static_cast<u64>(src_a) + src_b + (carry_flag ? 1ULL : 0ULL)};
|
||||
carry_flag = result > 0xffffffff;
|
||||
return static_cast<u32>(result);
|
||||
}
|
||||
case ALUOperation::Subtract: {
|
||||
const u64 result{static_cast<u64>(src_a) - src_b};
|
||||
carry_flag = result < 0x100000000;
|
||||
return static_cast<u32>(result);
|
||||
}
|
||||
case ALUOperation::SubtractWithBorrow: {
|
||||
const u64 result{static_cast<u64>(src_a) - src_b - (carry_flag ? 0ULL : 1ULL)};
|
||||
carry_flag = result < 0x100000000;
|
||||
return static_cast<u32>(result);
|
||||
}
|
||||
case ALUOperation::Xor:
|
||||
return src_a ^ src_b;
|
||||
case ALUOperation::Or:
|
||||
|
||||
@@ -117,7 +117,7 @@ private:
|
||||
bool Step(u32 offset, bool is_delay_slot);
|
||||
|
||||
/// Calculates the result of an ALU operation. src_a OP src_b;
|
||||
u32 GetALUResult(ALUOperation operation, u32 src_a, u32 src_b) const;
|
||||
u32 GetALUResult(ALUOperation operation, u32 src_a, u32 src_b);
|
||||
|
||||
/// Performs the result operation on the input result and stores it in the specified register
|
||||
/// (if necessary).
|
||||
@@ -165,5 +165,7 @@ private:
|
||||
std::vector<u32> parameters;
|
||||
/// Index of the next parameter that will be fetched by the 'parm' instruction.
|
||||
u32 next_parameter_index = 0;
|
||||
|
||||
bool carry_flag{};
|
||||
};
|
||||
} // namespace Tegra
|
||||
|
||||
@@ -9,6 +9,13 @@
|
||||
|
||||
namespace Tegra {
|
||||
|
||||
MemoryManager::MemoryManager() {
|
||||
// Mark the first page as reserved, so that 0 is not a valid GPUVAddr. Otherwise, games might
|
||||
// try to use 0 as a valid address, which is also used to mean nullptr. This fixes a bug with
|
||||
// Undertale using 0 for a render target.
|
||||
PageSlot(0) = static_cast<u64>(PageStatus::Reserved);
|
||||
}
|
||||
|
||||
GPUVAddr MemoryManager::AllocateSpace(u64 size, u64 align) {
|
||||
const std::optional<GPUVAddr> gpu_addr{FindFreeBlock(0, size, align, PageStatus::Unmapped)};
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ using GPUVAddr = u64;
|
||||
|
||||
class MemoryManager final {
|
||||
public:
|
||||
MemoryManager() = default;
|
||||
MemoryManager();
|
||||
|
||||
GPUVAddr AllocateSpace(u64 size, u64 align);
|
||||
GPUVAddr AllocateSpace(GPUVAddr gpu_addr, u64 size, u64 align);
|
||||
@@ -37,6 +37,7 @@ private:
|
||||
enum class PageStatus : u64 {
|
||||
Unmapped = 0xFFFFFFFFFFFFFFFFULL,
|
||||
Allocated = 0xFFFFFFFFFFFFFFFEULL,
|
||||
Reserved = 0xFFFFFFFFFFFFFFFDULL,
|
||||
};
|
||||
|
||||
std::optional<GPUVAddr> FindFreeBlock(GPUVAddr region_start, u64 size, u64 align,
|
||||
|
||||
@@ -98,14 +98,9 @@ RasterizerOpenGL::RasterizerOpenGL(Core::Frontend::EmuWindow& window, ScreenInfo
|
||||
has_ARB_direct_state_access = true;
|
||||
} else if (extension == "GL_ARB_multi_bind") {
|
||||
has_ARB_multi_bind = true;
|
||||
} else if (extension == "GL_ARB_separate_shader_objects") {
|
||||
has_ARB_separate_shader_objects = true;
|
||||
} else if (extension == "GL_ARB_vertex_attrib_binding") {
|
||||
has_ARB_vertex_attrib_binding = true;
|
||||
}
|
||||
}
|
||||
|
||||
ASSERT_MSG(has_ARB_separate_shader_objects, "has_ARB_separate_shader_objects is unsupported");
|
||||
OpenGLState::ApplyDefaultState();
|
||||
|
||||
// Create render framebuffer
|
||||
@@ -542,6 +537,30 @@ void RasterizerOpenGL::Clear() {
|
||||
ASSERT_MSG(regs.zeta_enable != 0, "Tried to clear stencil but buffer is not enabled!");
|
||||
use_stencil = true;
|
||||
clear_state.stencil.test_enabled = true;
|
||||
if (regs.clear_flags.stencil) {
|
||||
// Stencil affects the clear so fill it with the used masks
|
||||
clear_state.stencil.front.test_func = GL_ALWAYS;
|
||||
clear_state.stencil.front.test_mask = regs.stencil_front_func_mask;
|
||||
clear_state.stencil.front.action_stencil_fail = GL_KEEP;
|
||||
clear_state.stencil.front.action_depth_fail = GL_KEEP;
|
||||
clear_state.stencil.front.action_depth_pass = GL_KEEP;
|
||||
clear_state.stencil.front.write_mask = regs.stencil_front_mask;
|
||||
if (regs.stencil_two_side_enable) {
|
||||
clear_state.stencil.back.test_func = GL_ALWAYS;
|
||||
clear_state.stencil.back.test_mask = regs.stencil_back_func_mask;
|
||||
clear_state.stencil.back.action_stencil_fail = GL_KEEP;
|
||||
clear_state.stencil.back.action_depth_fail = GL_KEEP;
|
||||
clear_state.stencil.back.action_depth_pass = GL_KEEP;
|
||||
clear_state.stencil.back.write_mask = regs.stencil_back_mask;
|
||||
} else {
|
||||
clear_state.stencil.back.test_func = GL_ALWAYS;
|
||||
clear_state.stencil.back.test_mask = 0xFFFFFFFF;
|
||||
clear_state.stencil.back.write_mask = 0xFFFFFFFF;
|
||||
clear_state.stencil.back.action_stencil_fail = GL_KEEP;
|
||||
clear_state.stencil.back.action_depth_fail = GL_KEEP;
|
||||
clear_state.stencil.back.action_depth_pass = GL_KEEP;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!use_color && !use_depth && !use_stencil) {
|
||||
@@ -553,6 +572,14 @@ void RasterizerOpenGL::Clear() {
|
||||
|
||||
ConfigureFramebuffers(clear_state, use_color, use_depth || use_stencil, false,
|
||||
regs.clear_buffers.RT.Value());
|
||||
if (regs.clear_flags.scissor) {
|
||||
SyncScissorTest(clear_state);
|
||||
}
|
||||
|
||||
if (regs.clear_flags.viewport) {
|
||||
clear_state.EmulateViewportWithScissor();
|
||||
}
|
||||
|
||||
clear_state.Apply();
|
||||
|
||||
if (use_color) {
|
||||
@@ -588,7 +615,7 @@ void RasterizerOpenGL::DrawArrays() {
|
||||
SyncLogicOpState();
|
||||
SyncCullMode();
|
||||
SyncPrimitiveRestart();
|
||||
SyncScissorTest();
|
||||
SyncScissorTest(state);
|
||||
// Alpha Testing is synced on shaders.
|
||||
SyncTransformFeedback();
|
||||
SyncPointState();
|
||||
@@ -815,7 +842,7 @@ void RasterizerOpenGL::SamplerInfo::SyncWithConfig(const Tegra::Texture::TSCEntr
|
||||
}
|
||||
const u32 bias = config.mip_lod_bias.Value();
|
||||
// Sign extend the 13-bit value.
|
||||
const u32 mask = 1U << (13 - 1);
|
||||
constexpr u32 mask = 1U << (13 - 1);
|
||||
const float bias_lod = static_cast<s32>((bias ^ mask) - mask) / 256.f;
|
||||
if (lod_bias != bias_lod) {
|
||||
lod_bias = bias_lod;
|
||||
@@ -947,8 +974,8 @@ void RasterizerOpenGL::SyncViewport(OpenGLState& current_state) {
|
||||
auto& viewport = current_state.viewports[i];
|
||||
viewport.x = viewport_rect.left;
|
||||
viewport.y = viewport_rect.bottom;
|
||||
viewport.width = static_cast<GLfloat>(viewport_rect.GetWidth());
|
||||
viewport.height = static_cast<GLfloat>(viewport_rect.GetHeight());
|
||||
viewport.width = viewport_rect.GetWidth();
|
||||
viewport.height = viewport_rect.GetHeight();
|
||||
viewport.depth_range_far = regs.viewports[i].depth_range_far;
|
||||
viewport.depth_range_near = regs.viewports[i].depth_range_near;
|
||||
}
|
||||
@@ -1120,11 +1147,11 @@ void RasterizerOpenGL::SyncLogicOpState() {
|
||||
state.logic_op.operation = MaxwellToGL::LogicOp(regs.logic_op.operation);
|
||||
}
|
||||
|
||||
void RasterizerOpenGL::SyncScissorTest() {
|
||||
void RasterizerOpenGL::SyncScissorTest(OpenGLState& current_state) {
|
||||
const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
|
||||
for (std::size_t i = 0; i < Tegra::Engines::Maxwell3D::Regs::NumViewports; i++) {
|
||||
const auto& src = regs.scissor_test[i];
|
||||
auto& dst = state.viewports[i].scissor;
|
||||
auto& dst = current_state.viewports[i].scissor;
|
||||
dst.enabled = (src.enable != 0);
|
||||
if (dst.enabled == 0) {
|
||||
return;
|
||||
|
||||
@@ -91,19 +91,20 @@ private:
|
||||
void SyncWithConfig(const Tegra::Texture::TSCEntry& info);
|
||||
|
||||
private:
|
||||
Tegra::Texture::TextureFilter mag_filter;
|
||||
Tegra::Texture::TextureFilter min_filter;
|
||||
Tegra::Texture::TextureMipmapFilter mip_filter;
|
||||
Tegra::Texture::WrapMode wrap_u;
|
||||
Tegra::Texture::WrapMode wrap_v;
|
||||
Tegra::Texture::WrapMode wrap_p;
|
||||
bool uses_depth_compare;
|
||||
Tegra::Texture::DepthCompareFunc depth_compare_func;
|
||||
GLvec4 border_color;
|
||||
float min_lod;
|
||||
float max_lod;
|
||||
float lod_bias;
|
||||
float max_anisotropic;
|
||||
Tegra::Texture::TextureFilter mag_filter = Tegra::Texture::TextureFilter::Nearest;
|
||||
Tegra::Texture::TextureFilter min_filter = Tegra::Texture::TextureFilter::Nearest;
|
||||
Tegra::Texture::TextureMipmapFilter mip_filter = Tegra::Texture::TextureMipmapFilter::None;
|
||||
Tegra::Texture::WrapMode wrap_u = Tegra::Texture::WrapMode::ClampToEdge;
|
||||
Tegra::Texture::WrapMode wrap_v = Tegra::Texture::WrapMode::ClampToEdge;
|
||||
Tegra::Texture::WrapMode wrap_p = Tegra::Texture::WrapMode::ClampToEdge;
|
||||
bool uses_depth_compare = false;
|
||||
Tegra::Texture::DepthCompareFunc depth_compare_func =
|
||||
Tegra::Texture::DepthCompareFunc::Always;
|
||||
GLvec4 border_color = {};
|
||||
float min_lod = 0.0f;
|
||||
float max_lod = 16.0f;
|
||||
float lod_bias = 0.0f;
|
||||
float max_anisotropic = 1.0f;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -171,7 +172,7 @@ private:
|
||||
void SyncMultiSampleState();
|
||||
|
||||
/// Syncs the scissor test state to match the guest state
|
||||
void SyncScissorTest();
|
||||
void SyncScissorTest(OpenGLState& current_state);
|
||||
|
||||
/// Syncs the transform feedback state to match the guest state
|
||||
void SyncTransformFeedback();
|
||||
@@ -187,8 +188,6 @@ private:
|
||||
|
||||
bool has_ARB_direct_state_access = false;
|
||||
bool has_ARB_multi_bind = false;
|
||||
bool has_ARB_separate_shader_objects = false;
|
||||
bool has_ARB_vertex_attrib_binding = false;
|
||||
|
||||
OpenGLState state;
|
||||
|
||||
|
||||
@@ -265,11 +265,11 @@ static constexpr std::array<FormatTuple, VideoCore::Surface::MaxPixelFormat> tex
|
||||
{GL_COMPRESSED_RG_RGTC2, GL_RG, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm,
|
||||
true}, // DXN2UNORM
|
||||
{GL_COMPRESSED_SIGNED_RG_RGTC2, GL_RG, GL_INT, ComponentType::SNorm, true}, // DXN2SNORM
|
||||
{GL_COMPRESSED_RGBA_BPTC_UNORM_ARB, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm,
|
||||
{GL_COMPRESSED_RGBA_BPTC_UNORM, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm,
|
||||
true}, // BC7U
|
||||
{GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_ARB, GL_RGB, GL_UNSIGNED_INT_8_8_8_8,
|
||||
ComponentType::Float, true}, // BC6H_UF16
|
||||
{GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_ARB, GL_RGB, GL_UNSIGNED_INT_8_8_8_8, ComponentType::Float,
|
||||
{GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT, GL_RGB, GL_UNSIGNED_INT_8_8_8_8, ComponentType::Float,
|
||||
true}, // BC6H_UF16
|
||||
{GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT, GL_RGB, GL_UNSIGNED_INT_8_8_8_8, ComponentType::Float,
|
||||
true}, // BC6H_SF16
|
||||
{GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_4X4
|
||||
{GL_RG8, GL_RG, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // G8R8U
|
||||
@@ -306,8 +306,8 @@ static constexpr std::array<FormatTuple, VideoCore::Surface::MaxPixelFormat> tex
|
||||
true}, // DXT23_SRGB
|
||||
{GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm,
|
||||
true}, // DXT45_SRGB
|
||||
{GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_ARB, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8,
|
||||
ComponentType::UNorm, true}, // BC7U_SRGB
|
||||
{GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm,
|
||||
true}, // BC7U_SRGB
|
||||
{GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_4X4_SRGB
|
||||
{GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_8X8_SRGB
|
||||
{GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_8X5_SRGB
|
||||
@@ -346,7 +346,7 @@ static GLenum SurfaceTargetToGL(SurfaceTarget target) {
|
||||
case SurfaceTarget::TextureCubemap:
|
||||
return GL_TEXTURE_CUBE_MAP;
|
||||
case SurfaceTarget::TextureCubeArray:
|
||||
return GL_TEXTURE_CUBE_MAP_ARRAY_ARB;
|
||||
return GL_TEXTURE_CUBE_MAP_ARRAY;
|
||||
}
|
||||
LOG_CRITICAL(Render_OpenGL, "Unimplemented texture target={}", static_cast<u32>(target));
|
||||
UNREACHABLE();
|
||||
@@ -726,7 +726,7 @@ static void CopySurface(const Surface& src_surface, const Surface& dst_surface,
|
||||
const std::size_t buffer_size = std::max(src_params.size_in_bytes, dst_params.size_in_bytes);
|
||||
|
||||
glBindBuffer(GL_PIXEL_PACK_BUFFER, copy_pbo_handle);
|
||||
glBufferData(GL_PIXEL_PACK_BUFFER, buffer_size, nullptr, GL_STREAM_DRAW_ARB);
|
||||
glBufferData(GL_PIXEL_PACK_BUFFER, buffer_size, nullptr, GL_STREAM_DRAW);
|
||||
if (source_format.compressed) {
|
||||
glGetCompressedTextureImage(src_surface->Texture().handle, src_attachment,
|
||||
static_cast<GLsizei>(src_params.size_in_bytes), nullptr);
|
||||
@@ -1275,6 +1275,31 @@ Surface RasterizerCacheOpenGL::GetUncachedSurface(const SurfaceParams& params) {
|
||||
return surface;
|
||||
}
|
||||
|
||||
void RasterizerCacheOpenGL::FastLayeredCopySurface(const Surface& src_surface,
|
||||
const Surface& dst_surface) {
|
||||
const auto& init_params{src_surface->GetSurfaceParams()};
|
||||
const auto& dst_params{dst_surface->GetSurfaceParams()};
|
||||
VAddr address = init_params.addr;
|
||||
const std::size_t layer_size = dst_params.LayerMemorySize();
|
||||
for (u32 layer = 0; layer < dst_params.depth; layer++) {
|
||||
for (u32 mipmap = 0; mipmap < dst_params.max_mip_level; mipmap++) {
|
||||
const VAddr sub_address = address + dst_params.GetMipmapLevelOffset(mipmap);
|
||||
const Surface& copy = TryGet(sub_address);
|
||||
if (!copy)
|
||||
continue;
|
||||
const auto& src_params{copy->GetSurfaceParams()};
|
||||
const u32 width{std::min(src_params.width, dst_params.MipWidth(mipmap))};
|
||||
const u32 height{std::min(src_params.height, dst_params.MipHeight(mipmap))};
|
||||
|
||||
glCopyImageSubData(copy->Texture().handle, SurfaceTargetToGL(src_params.target), 0, 0,
|
||||
0, 0, dst_surface->Texture().handle,
|
||||
SurfaceTargetToGL(dst_params.target), mipmap, 0, 0, layer, width,
|
||||
height, 1);
|
||||
}
|
||||
address += layer_size;
|
||||
}
|
||||
}
|
||||
|
||||
void RasterizerCacheOpenGL::FermiCopySurface(
|
||||
const Tegra::Engines::Fermi2D::Regs::Surface& src_config,
|
||||
const Tegra::Engines::Fermi2D::Regs::Surface& dst_config) {
|
||||
@@ -1340,11 +1365,13 @@ Surface RasterizerCacheOpenGL::RecreateSurface(const Surface& old_surface,
|
||||
CopySurface(old_surface, new_surface, copy_pbo.handle);
|
||||
}
|
||||
break;
|
||||
case SurfaceTarget::TextureCubemap:
|
||||
case SurfaceTarget::Texture3D:
|
||||
AccurateCopySurface(old_surface, new_surface);
|
||||
break;
|
||||
case SurfaceTarget::TextureCubemap:
|
||||
case SurfaceTarget::Texture2DArray:
|
||||
case SurfaceTarget::TextureCubeArray:
|
||||
AccurateCopySurface(old_surface, new_surface);
|
||||
FastLayeredCopySurface(old_surface, new_surface);
|
||||
break;
|
||||
default:
|
||||
LOG_CRITICAL(Render_OpenGL, "Unimplemented surface target={}",
|
||||
|
||||
@@ -350,6 +350,7 @@ private:
|
||||
|
||||
/// Performs a slow but accurate surface copy, flushing to RAM and reinterpreting the data
|
||||
void AccurateCopySurface(const Surface& src_surface, const Surface& dst_surface);
|
||||
void FastLayeredCopySurface(const Surface& src_surface, const Surface& dst_surface);
|
||||
|
||||
/// The surface reserve is a "backup" cache, this is where we put unique surfaces that have
|
||||
/// previously been used. This is to prevent surfaces from being constantly created and
|
||||
|
||||
@@ -84,6 +84,7 @@ CachedShader::CachedShader(VAddr addr, Maxwell::ShaderProgram program_type)
|
||||
}
|
||||
|
||||
entries = program_result.second;
|
||||
shader_length = entries.shader_length;
|
||||
|
||||
if (program_type != Maxwell::ShaderProgram::Geometry) {
|
||||
OGLShader shader;
|
||||
|
||||
@@ -30,7 +30,7 @@ public:
|
||||
}
|
||||
|
||||
std::size_t GetSizeInBytes() const override {
|
||||
return GLShader::MAX_PROGRAM_CODE_LENGTH * sizeof(u64);
|
||||
return shader_length;
|
||||
}
|
||||
|
||||
// We do not have to flush this cache as things in it are never modified by us.
|
||||
@@ -82,6 +82,7 @@ private:
|
||||
u32 max_vertices, const std::string& debug_name);
|
||||
|
||||
VAddr addr;
|
||||
std::size_t shader_length;
|
||||
Maxwell::ShaderProgram program_type;
|
||||
GLShader::ShaderSetup setup;
|
||||
GLShader::ShaderEntries entries;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -163,6 +163,7 @@ private:
|
||||
struct ShaderEntries {
|
||||
std::vector<ConstBufferEntry> const_buffer_entries;
|
||||
std::vector<SamplerEntry> texture_samplers;
|
||||
std::size_t shader_length;
|
||||
};
|
||||
|
||||
using ProgramResult = std::pair<std::string, ShaderEntries>;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user