mirror of
https://github.com/Atmosphere-NX/Atmosphere-libs.git
synced 2025-06-30 23:12:13 +02:00
libstrat: refactor for R_TRY
This commit is contained in:
parent
7c9df9cfd8
commit
4a120c3c16
2
Makefile
2
Makefile
@ -20,6 +20,8 @@ SOURCES := source
|
|||||||
DATA := data
|
DATA := data
|
||||||
INCLUDES := include
|
INCLUDES := include
|
||||||
|
|
||||||
|
DEFINES := -DRESULT_ABORT_ON_ASSERT
|
||||||
|
|
||||||
#---------------------------------------------------------------------------------
|
#---------------------------------------------------------------------------------
|
||||||
# options for code generation
|
# options for code generation
|
||||||
#---------------------------------------------------------------------------------
|
#---------------------------------------------------------------------------------
|
||||||
|
@ -13,13 +13,14 @@
|
|||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <switch.h>
|
#include <switch.h>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "iwaitable.hpp"
|
#include "iwaitable.hpp"
|
||||||
|
#include "results.hpp"
|
||||||
|
|
||||||
class IEvent : public IWaitable {
|
class IEvent : public IWaitable {
|
||||||
public:
|
public:
|
||||||
@ -31,7 +32,7 @@ class IEvent : public IWaitable {
|
|||||||
IEvent(bool a = false) : r_h(INVALID_HANDLE), w_h(INVALID_HANDLE), autoclear(a) { }
|
IEvent(bool a = false) : r_h(INVALID_HANDLE), w_h(INVALID_HANDLE), autoclear(a) { }
|
||||||
IEvent(Handle r, bool a = false) : r_h(r), w_h(INVALID_HANDLE), autoclear(a) { }
|
IEvent(Handle r, bool a = false) : r_h(r), w_h(INVALID_HANDLE), autoclear(a) { }
|
||||||
IEvent(Handle r, Handle w, bool a = false) : r_h(r), w_h(w), autoclear(a) { }
|
IEvent(Handle r, Handle w, bool a = false) : r_h(r), w_h(w), autoclear(a) { }
|
||||||
|
|
||||||
~IEvent() {
|
~IEvent() {
|
||||||
if (r_h != INVALID_HANDLE) {
|
if (r_h != INVALID_HANDLE) {
|
||||||
svcCloseHandle(r_h);
|
svcCloseHandle(r_h);
|
||||||
@ -40,17 +41,17 @@ class IEvent : public IWaitable {
|
|||||||
svcCloseHandle(w_h);
|
svcCloseHandle(w_h);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Make it non-copyable */
|
/* Make it non-copyable */
|
||||||
IEvent() = delete;
|
IEvent() = delete;
|
||||||
IEvent(const IEvent &) = delete;
|
IEvent(const IEvent &) = delete;
|
||||||
IEvent& operator=(const IEvent&) = delete;
|
IEvent& operator=(const IEvent&) = delete;
|
||||||
|
|
||||||
|
|
||||||
bool IsAutoClear() {
|
bool IsAutoClear() {
|
||||||
return this->autoclear;
|
return this->autoclear;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Clear() {
|
void Clear() {
|
||||||
std::scoped_lock<HosMutex> lock(this->sig_lock);
|
std::scoped_lock<HosMutex> lock(this->sig_lock);
|
||||||
this->is_signaled = false;
|
this->is_signaled = false;
|
||||||
@ -60,31 +61,31 @@ class IEvent : public IWaitable {
|
|||||||
svcResetSignal(this->r_h);
|
svcResetSignal(this->r_h);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Signal() {
|
void Signal() {
|
||||||
std::scoped_lock<HosMutex> lock(this->sig_lock);
|
std::scoped_lock<HosMutex> lock(this->sig_lock);
|
||||||
|
|
||||||
if (this->w_h == INVALID_HANDLE && this->r_h != INVALID_HANDLE) {
|
if (this->w_h == INVALID_HANDLE && this->r_h != INVALID_HANDLE) {
|
||||||
/* We can't signal an event if we only have a read handle. */
|
/* We can't signal an event if we only have a read handle. */
|
||||||
std::abort();
|
std::abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this->w_h == INVALID_HANDLE && this->is_signaled) {
|
if (this->w_h == INVALID_HANDLE && this->is_signaled) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this->is_signaled = true;
|
this->is_signaled = true;
|
||||||
|
|
||||||
if (this->w_h != INVALID_HANDLE) {
|
if (this->w_h != INVALID_HANDLE) {
|
||||||
svcSignalEvent(this->w_h);
|
svcSignalEvent(this->w_h);
|
||||||
} else {
|
} else {
|
||||||
this->NotifyManagerSignaled();
|
this->NotifyManagerSignaled();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual Result HandleSignaled(u64 timeout) = 0;
|
virtual Result HandleSignaled(u64 timeout) = 0;
|
||||||
|
|
||||||
/* IWaitable */
|
/* IWaitable */
|
||||||
virtual Handle GetHandle() override {
|
virtual Handle GetHandle() override {
|
||||||
return this->r_h;
|
return this->r_h;
|
||||||
}
|
}
|
||||||
@ -98,7 +99,7 @@ class HosEvent : public IEvent {
|
|||||||
HosEvent(F f, bool a = false) : IEvent(a), callback(std::move(f)) { }
|
HosEvent(F f, bool a = false) : IEvent(a), callback(std::move(f)) { }
|
||||||
HosEvent(Handle r, F f, bool a = false) : IEvent(r, a), callback(std::move(f)) { }
|
HosEvent(Handle r, F f, bool a = false) : IEvent(r, a), callback(std::move(f)) { }
|
||||||
HosEvent(Handle r, Handle w, F f, bool a = false) : IEvent(r, w, a), callback(std::move(f)) { }
|
HosEvent(Handle r, Handle w, F f, bool a = false) : IEvent(r, w, a), callback(std::move(f)) { }
|
||||||
|
|
||||||
virtual Result HandleSignaled(u64 timeout) override {
|
virtual Result HandleSignaled(u64 timeout) override {
|
||||||
if (this->IsAutoClear()) {
|
if (this->IsAutoClear()) {
|
||||||
this->Clear();
|
this->Clear();
|
||||||
@ -115,9 +116,7 @@ static IEvent *CreateHosEvent(F f, bool autoclear = false) {
|
|||||||
template <class F>
|
template <class F>
|
||||||
static IEvent *CreateSystemEvent(F f, bool autoclear = false) {
|
static IEvent *CreateSystemEvent(F f, bool autoclear = false) {
|
||||||
Handle w_h, r_h;
|
Handle w_h, r_h;
|
||||||
if (R_FAILED(svcCreateEvent(&w_h, &r_h))) {
|
R_ASSERT(svcCreateEvent(&w_h, &r_h));
|
||||||
std::abort();
|
|
||||||
}
|
|
||||||
return new HosEvent<F>(r_h, w_h, std::move(f), autoclear);
|
return new HosEvent<F>(r_h, w_h, std::move(f), autoclear);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -125,9 +124,7 @@ template <class F>
|
|||||||
static IEvent *CreateInterruptEvent(F f, u64 irq, bool autoclear = false) {
|
static IEvent *CreateInterruptEvent(F f, u64 irq, bool autoclear = false) {
|
||||||
Handle r_h;
|
Handle r_h;
|
||||||
/* flag is "rising edge vs level". */
|
/* flag is "rising edge vs level". */
|
||||||
if (R_FAILED(svcCreateInterruptEvent(&r_h, irq, autoclear ? 0 : 1))) {
|
R_ASSERT(svcCreateInterruptEvent(&r_h, irq, autoclear ? 0 : 1));
|
||||||
std::abort();
|
|
||||||
}
|
|
||||||
return new HosEvent<F>(r_h, INVALID_HANDLE, std::move(f), autoclear);
|
return new HosEvent<F>(r_h, INVALID_HANDLE, std::move(f), autoclear);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,11 +13,12 @@
|
|||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <switch.h>
|
#include <switch.h>
|
||||||
#include <switch/arm/counter.h>
|
#include <switch/arm/counter.h>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
#include "results.hpp"
|
||||||
|
|
||||||
class HosMutex {
|
class HosMutex {
|
||||||
private:
|
private:
|
||||||
@ -29,31 +30,31 @@ class HosMutex {
|
|||||||
HosMutex() {
|
HosMutex() {
|
||||||
mutexInit(GetMutex());
|
mutexInit(GetMutex());
|
||||||
}
|
}
|
||||||
|
|
||||||
void lock() {
|
void lock() {
|
||||||
mutexLock(GetMutex());
|
mutexLock(GetMutex());
|
||||||
}
|
}
|
||||||
|
|
||||||
void unlock() {
|
void unlock() {
|
||||||
mutexUnlock(GetMutex());
|
mutexUnlock(GetMutex());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool try_lock() {
|
bool try_lock() {
|
||||||
return mutexTryLock(GetMutex());
|
return mutexTryLock(GetMutex());
|
||||||
}
|
}
|
||||||
|
|
||||||
void Lock() {
|
void Lock() {
|
||||||
lock();
|
lock();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Unlock() {
|
void Unlock() {
|
||||||
unlock();
|
unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TryLock() {
|
bool TryLock() {
|
||||||
return try_lock();
|
return try_lock();
|
||||||
}
|
}
|
||||||
|
|
||||||
friend class HosCondVar;
|
friend class HosCondVar;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -67,27 +68,27 @@ class HosRecursiveMutex {
|
|||||||
HosRecursiveMutex() {
|
HosRecursiveMutex() {
|
||||||
rmutexInit(GetMutex());
|
rmutexInit(GetMutex());
|
||||||
}
|
}
|
||||||
|
|
||||||
void lock() {
|
void lock() {
|
||||||
rmutexLock(GetMutex());
|
rmutexLock(GetMutex());
|
||||||
}
|
}
|
||||||
|
|
||||||
void unlock() {
|
void unlock() {
|
||||||
rmutexUnlock(GetMutex());
|
rmutexUnlock(GetMutex());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool try_lock() {
|
bool try_lock() {
|
||||||
return rmutexTryLock(GetMutex());
|
return rmutexTryLock(GetMutex());
|
||||||
}
|
}
|
||||||
|
|
||||||
void Lock() {
|
void Lock() {
|
||||||
lock();
|
lock();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Unlock() {
|
void Unlock() {
|
||||||
unlock();
|
unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TryLock() {
|
bool TryLock() {
|
||||||
return try_lock();
|
return try_lock();
|
||||||
}
|
}
|
||||||
@ -100,31 +101,31 @@ class HosCondVar {
|
|||||||
HosCondVar() {
|
HosCondVar() {
|
||||||
condvarInit(&cv);
|
condvarInit(&cv);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result TimedWait(u64 timeout, HosMutex *hm) {
|
Result TimedWait(u64 timeout, HosMutex *hm) {
|
||||||
return TimedWait(timeout, hm->GetMutex());
|
return TimedWait(timeout, hm->GetMutex());
|
||||||
}
|
}
|
||||||
|
|
||||||
Result Wait(HosMutex *hm) {
|
Result Wait(HosMutex *hm) {
|
||||||
return Wait(hm->GetMutex());
|
return Wait(hm->GetMutex());
|
||||||
}
|
}
|
||||||
|
|
||||||
Result TimedWait(u64 timeout, Mutex *m) {
|
Result TimedWait(u64 timeout, Mutex *m) {
|
||||||
return condvarWaitTimeout(&cv, m, timeout);
|
return condvarWaitTimeout(&cv, m, timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result Wait(Mutex *m) {
|
Result Wait(Mutex *m) {
|
||||||
return condvarWait(&cv, m);
|
return condvarWait(&cv, m);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result Wake(int num) {
|
Result Wake(int num) {
|
||||||
return condvarWake(&cv, num);
|
return condvarWake(&cv, num);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result WakeOne() {
|
Result WakeOne() {
|
||||||
return condvarWakeOne(&cv);
|
return condvarWakeOne(&cv);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result WakeAll() {
|
Result WakeAll() {
|
||||||
return condvarWakeAll(&cv);
|
return condvarWakeAll(&cv);
|
||||||
}
|
}
|
||||||
@ -137,19 +138,19 @@ class HosSemaphore {
|
|||||||
HosSemaphore() {
|
HosSemaphore() {
|
||||||
semaphoreInit(&s, 0);
|
semaphoreInit(&s, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
HosSemaphore(u64 c) {
|
HosSemaphore(u64 c) {
|
||||||
semaphoreInit(&s, c);
|
semaphoreInit(&s, c);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Signal() {
|
void Signal() {
|
||||||
semaphoreSignal(&s);
|
semaphoreSignal(&s);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Wait() {
|
void Wait() {
|
||||||
semaphoreWait(&s);
|
semaphoreWait(&s);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TryWait() {
|
bool TryWait() {
|
||||||
return semaphoreTryWait(&s);
|
return semaphoreTryWait(&s);
|
||||||
}
|
}
|
||||||
@ -165,34 +166,34 @@ class TimeoutHelper {
|
|||||||
end_tick = 0;
|
end_tick = 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 cur_tick = armGetSystemTick();
|
u64 cur_tick = armGetSystemTick();
|
||||||
this->end_tick = cur_tick + NsToTick(ns) + 1;
|
this->end_tick = cur_tick + NsToTick(ns) + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline u64 NsToTick(u64 ns) {
|
static inline u64 NsToTick(u64 ns) {
|
||||||
return (ns * 12) / 625;
|
return (ns * 12) / 625;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline u64 TickToNs(u64 tick) {
|
static inline u64 TickToNs(u64 tick) {
|
||||||
return (tick * 625) / 12;
|
return (tick * 625) / 12;
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 NsUntilTimeout() {
|
u64 NsUntilTimeout() {
|
||||||
u64 diff = TickToNs(this->end_tick - armGetSystemTick());
|
u64 diff = TickToNs(this->end_tick - armGetSystemTick());
|
||||||
|
|
||||||
if (TimedOut()) {
|
if (TimedOut()) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return diff;
|
return diff;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TimedOut() {
|
bool TimedOut() {
|
||||||
if (this->end_tick == 0) {
|
if (this->end_tick == 0) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return armGetSystemTick() >= this->end_tick;
|
return armGetSystemTick() >= this->end_tick;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -208,47 +209,47 @@ class HosSignal {
|
|||||||
mutexInit(&m);
|
mutexInit(&m);
|
||||||
signaled = false;
|
signaled = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Signal() {
|
void Signal() {
|
||||||
mutexLock(&m);
|
mutexLock(&m);
|
||||||
signaled = true;
|
signaled = true;
|
||||||
condvarWakeAll(&cv);
|
condvarWakeAll(&cv);
|
||||||
mutexUnlock(&m);
|
mutexUnlock(&m);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Reset() {
|
void Reset() {
|
||||||
mutexLock(&m);
|
mutexLock(&m);
|
||||||
signaled = false;
|
signaled = false;
|
||||||
mutexUnlock(&m);
|
mutexUnlock(&m);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Wait() {
|
void Wait() {
|
||||||
mutexLock(&m);
|
mutexLock(&m);
|
||||||
|
|
||||||
while (!signaled) {
|
while (!signaled) {
|
||||||
condvarWait(&cv, &m);
|
condvarWait(&cv, &m);
|
||||||
}
|
}
|
||||||
|
|
||||||
mutexUnlock(&m);
|
mutexUnlock(&m);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TryWait() {
|
bool TryWait() {
|
||||||
mutexLock(&m);
|
mutexLock(&m);
|
||||||
bool success = signaled;
|
bool success = signaled;
|
||||||
mutexUnlock(&m);
|
mutexUnlock(&m);
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result TimedWait(u64 ns) {
|
Result TimedWait(u64 ns) {
|
||||||
mutexLock(&m);
|
mutexLock(&m);
|
||||||
TimeoutHelper timeout_helper(ns);
|
TimeoutHelper timeout_helper(ns);
|
||||||
|
|
||||||
while (!signaled) {
|
while (!signaled) {
|
||||||
if (R_FAILED(condvarWaitTimeout(&cv, &m, timeout_helper.NsUntilTimeout()))) {
|
if (R_FAILED(condvarWaitTimeout(&cv, &m, timeout_helper.NsUntilTimeout()))) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mutexUnlock(&m);
|
mutexUnlock(&m);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -259,27 +260,25 @@ class HosThread {
|
|||||||
Thread thr = {};
|
Thread thr = {};
|
||||||
public:
|
public:
|
||||||
HosThread() {}
|
HosThread() {}
|
||||||
|
|
||||||
Result Initialize(ThreadFunc entry, void *arg, size_t stack_sz, int prio, int cpuid = -2) {
|
Result Initialize(ThreadFunc entry, void *arg, size_t stack_sz, int prio, int cpuid = -2) {
|
||||||
return threadCreate(&this->thr, entry, arg, stack_sz, prio, cpuid);
|
return threadCreate(&this->thr, entry, arg, stack_sz, prio, cpuid);
|
||||||
}
|
}
|
||||||
|
|
||||||
Handle GetHandle() const {
|
Handle GetHandle() const {
|
||||||
return this->thr.handle;
|
return this->thr.handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result Start() {
|
Result Start() {
|
||||||
return threadStart(&this->thr);
|
return threadStart(&this->thr);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result Join() {
|
Result Join() {
|
||||||
Result rc = threadWaitForExit(&this->thr);
|
R_TRY(threadWaitForExit(&this->thr));
|
||||||
if (R_SUCCEEDED(rc)) {
|
R_TRY(threadClose(&this->thr));
|
||||||
rc = threadClose(&this->thr);
|
return ResultSuccess;
|
||||||
}
|
|
||||||
return rc;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Result CancelSynchronization() {
|
Result CancelSynchronization() {
|
||||||
return svcCancelSynchronization(this->thr.handle);
|
return svcCancelSynchronization(this->thr.handle);
|
||||||
}
|
}
|
||||||
|
@ -572,11 +572,7 @@ constexpr Result WrapIpcCommandImpl(IpcResponseContext *ctx) {
|
|||||||
ipcInitialize(&ctx->reply);
|
ipcInitialize(&ctx->reply);
|
||||||
memset(ctx->out_data, 0, CommandMetaData::OutRawArgSize);
|
memset(ctx->out_data, 0, CommandMetaData::OutRawArgSize);
|
||||||
|
|
||||||
Result rc = Validator::Validate<CommandMetaData>(ctx);
|
R_TRY(Validator::Validate<CommandMetaData>(ctx));
|
||||||
|
|
||||||
if (R_FAILED(rc)) {
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
ClassType *this_ptr = nullptr;
|
ClassType *this_ptr = nullptr;
|
||||||
if (IsDomainObject(ctx->obj_holder)) {
|
if (IsDomainObject(ctx->obj_holder)) {
|
||||||
@ -588,41 +584,19 @@ constexpr Result WrapIpcCommandImpl(IpcResponseContext *ctx) {
|
|||||||
return ResultServiceFrameworkTargetNotFound;
|
return ResultServiceFrameworkTargetNotFound;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t num_out_objects;
|
||||||
std::shared_ptr<IServiceObject> out_objects[CommandMetaData::NumOutSessions];
|
std::shared_ptr<IServiceObject> out_objects[CommandMetaData::NumOutSessions];
|
||||||
|
|
||||||
/* Allocate out object IDs. */
|
auto cleanup_guard = SCOPE_GUARD {
|
||||||
size_t num_out_objects;
|
|
||||||
if (IsDomainObject(ctx->obj_holder)) {
|
|
||||||
for (num_out_objects = 0; num_out_objects < CommandMetaData::NumOutSessions; num_out_objects++) {
|
|
||||||
if (R_FAILED((rc = ctx->obj_holder->GetServiceObject<IDomainObject>()->ReserveObject(&ctx->out_object_ids[num_out_objects])))) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
ctx->out_objs[num_out_objects] = &out_objects[num_out_objects];
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for (num_out_objects = 0; num_out_objects < CommandMetaData::NumOutSessions; num_out_objects++) {
|
|
||||||
Handle server_h, client_h;
|
|
||||||
if (R_FAILED((rc = SessionManagerBase::CreateSessionHandles(&server_h, &client_h)))) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
ctx->out_object_server_handles[num_out_objects] = server_h;
|
|
||||||
ctx->out_handles[CommandMetaData::NumOutHandles + num_out_objects].handle = client_h;
|
|
||||||
ctx->out_objs[num_out_objects] = &out_objects[num_out_objects];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ON_SCOPE_EXIT {
|
|
||||||
/* Clean up objects as necessary. */
|
/* Clean up objects as necessary. */
|
||||||
if (R_FAILED(rc)) {
|
if (IsDomainObject(ctx->obj_holder)) {
|
||||||
if (IsDomainObject(ctx->obj_holder)) {
|
for (unsigned int i = 0; i < num_out_objects; i++) {
|
||||||
for (unsigned int i = 0; i < num_out_objects; i++) {
|
ctx->obj_holder->GetServiceObject<IDomainObject>()->FreeObject(ctx->out_object_ids[i]);
|
||||||
ctx->obj_holder->GetServiceObject<IDomainObject>()->FreeObject(ctx->out_object_ids[i]);
|
}
|
||||||
}
|
} else {
|
||||||
} else {
|
for (unsigned int i = 0; i < num_out_objects; i++) {
|
||||||
for (unsigned int i = 0; i < num_out_objects; i++) {
|
svcCloseHandle(ctx->out_object_server_handles[i]);
|
||||||
svcCloseHandle(ctx->out_object_server_handles[i]);
|
svcCloseHandle(ctx->out_handles[CommandMetaData::NumOutHandles + i].handle);
|
||||||
svcCloseHandle(ctx->out_handles[CommandMetaData::NumOutHandles + i].handle);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -631,25 +605,48 @@ constexpr Result WrapIpcCommandImpl(IpcResponseContext *ctx) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if (R_SUCCEEDED(rc)) {
|
/* Allocate out object IDs. */
|
||||||
|
if (IsDomainObject(ctx->obj_holder)) {
|
||||||
|
for (num_out_objects = 0; num_out_objects < CommandMetaData::NumOutSessions; num_out_objects++) {
|
||||||
|
R_TRY_CLEANUP(ctx->obj_holder->GetServiceObject<IDomainObject>()->ReserveObject(&ctx->out_object_ids[num_out_objects]), {
|
||||||
|
std::apply(Encoder<CommandMetaData, typename CommandMetaData::Args>::EncodeFailure, std::tuple_cat(std::make_tuple(ctx), std::make_tuple(R_CLEANUP_RESULT)));
|
||||||
|
});
|
||||||
|
ctx->out_objs[num_out_objects] = &out_objects[num_out_objects];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (num_out_objects = 0; num_out_objects < CommandMetaData::NumOutSessions; num_out_objects++) {
|
||||||
|
Handle server_h, client_h;
|
||||||
|
R_TRY_CLEANUP(SessionManagerBase::CreateSessionHandles(&server_h, &client_h), {
|
||||||
|
std::apply(Encoder<CommandMetaData, typename CommandMetaData::Args>::EncodeFailure, std::tuple_cat(std::make_tuple(ctx), std::make_tuple(R_CLEANUP_RESULT)));
|
||||||
|
});
|
||||||
|
ctx->out_object_server_handles[num_out_objects] = server_h;
|
||||||
|
ctx->out_handles[CommandMetaData::NumOutHandles + num_out_objects].handle = client_h;
|
||||||
|
ctx->out_objs[num_out_objects] = &out_objects[num_out_objects];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Decode, apply, encode. */
|
||||||
|
{
|
||||||
auto args = Decoder<CommandMetaData>::Decode(ctx);
|
auto args = Decoder<CommandMetaData>::Decode(ctx);
|
||||||
|
|
||||||
if constexpr (CommandMetaData::ReturnsResult) {
|
if constexpr (CommandMetaData::ReturnsResult) {
|
||||||
rc = std::apply( [=](auto&&... args) { return (this_ptr->*IpcCommandImpl)(args...); }, args);
|
R_TRY_CLEANUP(std::apply( [=](auto&&... args) { return (this_ptr->*IpcCommandImpl)(args...); }, args), {
|
||||||
|
std::apply(Encoder<CommandMetaData, decltype(args)>::EncodeFailure, std::tuple_cat(std::make_tuple(ctx), std::make_tuple(R_CLEANUP_RESULT)));
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
std::apply( [=](auto&&... args) { (this_ptr->*IpcCommandImpl)(args...); }, args);
|
std::apply( [=](auto&&... args) { (this_ptr->*IpcCommandImpl)(args...); }, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (R_SUCCEEDED(rc)) {
|
std::apply(Encoder<CommandMetaData, decltype(args)>::EncodeSuccess, std::tuple_cat(std::make_tuple(ctx), args));
|
||||||
std::apply(Encoder<CommandMetaData, decltype(args)>::EncodeSuccess, std::tuple_cat(std::make_tuple(ctx), args));
|
|
||||||
} else {
|
|
||||||
std::apply(Encoder<CommandMetaData, decltype(args)>::EncodeFailure, std::tuple_cat(std::make_tuple(ctx), std::make_tuple(rc)));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
std::apply(Encoder<CommandMetaData, typename CommandMetaData::Args>::EncodeFailure, std::tuple_cat(std::make_tuple(ctx), std::make_tuple(rc)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return rc;
|
/* Cancel object guard, clear remaining object references. */
|
||||||
|
cleanup_guard.Cancel();
|
||||||
|
for (unsigned int i = 0; i < num_out_objects; i++) {
|
||||||
|
ctx->out_objs[i] = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ResultSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <switch.h>
|
#include <switch.h>
|
||||||
|
|
||||||
@ -38,14 +38,14 @@ class ServiceSession : public IWaitable
|
|||||||
ServiceObjectHolder obj_holder;
|
ServiceObjectHolder obj_holder;
|
||||||
ServiceObjectHolder control_holder = ServiceObjectHolder(std::make_shared<IHipcControlService>(this));
|
ServiceObjectHolder control_holder = ServiceObjectHolder(std::make_shared<IHipcControlService>(this));
|
||||||
u8 backup_tls[0x100];
|
u8 backup_tls[0x100];
|
||||||
|
|
||||||
ServiceSession(Handle s_h) : session_handle(s_h) { }
|
ServiceSession(Handle s_h) : session_handle(s_h) { }
|
||||||
public:
|
public:
|
||||||
template<typename T>
|
template<typename T>
|
||||||
ServiceSession(Handle s_h, size_t pbs) : session_handle(s_h), pointer_buffer(pbs), obj_holder(std::make_shared<T>()) { }
|
ServiceSession(Handle s_h, size_t pbs) : session_handle(s_h), pointer_buffer(pbs), obj_holder(std::make_shared<T>()) { }
|
||||||
|
|
||||||
ServiceSession(Handle s_h, size_t pbs, ServiceObjectHolder &&h) : session_handle(s_h), pointer_buffer(pbs), obj_holder(std::move(h)) { }
|
ServiceSession(Handle s_h, size_t pbs, ServiceObjectHolder &&h) : session_handle(s_h), pointer_buffer(pbs), obj_holder(std::move(h)) { }
|
||||||
|
|
||||||
virtual ~ServiceSession() override {
|
virtual ~ServiceSession() override {
|
||||||
svcCloseHandle(this->session_handle);
|
svcCloseHandle(this->session_handle);
|
||||||
}
|
}
|
||||||
@ -53,11 +53,11 @@ class ServiceSession : public IWaitable
|
|||||||
SessionManagerBase *GetSessionManager() {
|
SessionManagerBase *GetSessionManager() {
|
||||||
return static_cast<SessionManagerBase *>(this->GetManager());
|
return static_cast<SessionManagerBase *>(this->GetManager());
|
||||||
}
|
}
|
||||||
|
|
||||||
DomainManager *GetDomainManager() {
|
DomainManager *GetDomainManager() {
|
||||||
return static_cast<DomainManager *>(this->GetSessionManager());
|
return static_cast<DomainManager *>(this->GetSessionManager());
|
||||||
}
|
}
|
||||||
|
|
||||||
Result Receive() {
|
Result Receive() {
|
||||||
int handle_index;
|
int handle_index;
|
||||||
/* Prepare pointer buffer... */
|
/* Prepare pointer buffer... */
|
||||||
@ -66,28 +66,26 @@ class ServiceSession : public IWaitable
|
|||||||
if (this->pointer_buffer.size() > 0) {
|
if (this->pointer_buffer.size() > 0) {
|
||||||
ipcAddRecvStatic(&c, this->pointer_buffer.data(), this->pointer_buffer.size(), 0);
|
ipcAddRecvStatic(&c, this->pointer_buffer.data(), this->pointer_buffer.size(), 0);
|
||||||
ipcPrepareHeader(&c, 0);
|
ipcPrepareHeader(&c, 0);
|
||||||
|
|
||||||
/* Fix libnx bug in serverside C descriptor handling. */
|
/* Fix libnx bug in serverside C descriptor handling. */
|
||||||
((u32 *)armGetTls())[1] &= 0xFFFFC3FF;
|
((u32 *)armGetTls())[1] &= 0xFFFFC3FF;
|
||||||
((u32 *)armGetTls())[1] |= (2) << 10;
|
((u32 *)armGetTls())[1] |= (2) << 10;
|
||||||
} else {
|
} else {
|
||||||
ipcPrepareHeader(&c, 0);
|
ipcPrepareHeader(&c, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Receive. */
|
/* Receive. */
|
||||||
Result rc = svcReplyAndReceive(&handle_index, &this->session_handle, 1, 0, U64_MAX);
|
R_TRY(svcReplyAndReceive(&handle_index, &this->session_handle, 1, 0, U64_MAX));
|
||||||
if (R_SUCCEEDED(rc)) {
|
|
||||||
std::memcpy(this->backup_tls, armGetTls(), sizeof(this->backup_tls));
|
std::memcpy(this->backup_tls, armGetTls(), sizeof(this->backup_tls));
|
||||||
}
|
return ResultSuccess;
|
||||||
|
|
||||||
return rc;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Result Reply() {
|
Result Reply() {
|
||||||
int handle_index;
|
int handle_index;
|
||||||
return svcReplyAndReceive(&handle_index, &this->session_handle, 0, this->session_handle, 0);
|
return svcReplyAndReceive(&handle_index, &this->session_handle, 0, this->session_handle, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* For preparing basic replies. */
|
/* For preparing basic replies. */
|
||||||
Result PrepareBasicResponse(IpcResponseContext *ctx, Result rc) {
|
Result PrepareBasicResponse(IpcResponseContext *ctx, Result rc) {
|
||||||
ipcInitialize(&ctx->reply);
|
ipcInitialize(&ctx->reply);
|
||||||
@ -95,12 +93,12 @@ class ServiceSession : public IWaitable
|
|||||||
u64 magic;
|
u64 magic;
|
||||||
u64 result;
|
u64 result;
|
||||||
} *raw = (decltype(raw))ipcPrepareHeader(&ctx->reply, sizeof(*raw));
|
} *raw = (decltype(raw))ipcPrepareHeader(&ctx->reply, sizeof(*raw));
|
||||||
|
|
||||||
raw->magic = SFCO_MAGIC;
|
raw->magic = SFCO_MAGIC;
|
||||||
raw->result = rc;
|
raw->result = rc;
|
||||||
return raw->result;
|
return raw->result;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result PrepareBasicDomainResponse(IpcResponseContext *ctx, Result rc) {
|
Result PrepareBasicDomainResponse(IpcResponseContext *ctx, Result rc) {
|
||||||
ipcInitialize(&ctx->reply);
|
ipcInitialize(&ctx->reply);
|
||||||
struct {
|
struct {
|
||||||
@ -108,13 +106,13 @@ class ServiceSession : public IWaitable
|
|||||||
u64 magic;
|
u64 magic;
|
||||||
u64 result;
|
u64 result;
|
||||||
} *raw = (decltype(raw))ipcPrepareHeader(&ctx->reply, sizeof(*raw));
|
} *raw = (decltype(raw))ipcPrepareHeader(&ctx->reply, sizeof(*raw));
|
||||||
|
|
||||||
raw->hdr = {};
|
raw->hdr = {};
|
||||||
raw->magic = SFCO_MAGIC;
|
raw->magic = SFCO_MAGIC;
|
||||||
raw->result = rc;
|
raw->result = rc;
|
||||||
return raw->result;
|
return raw->result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* For making a new response context. */
|
/* For making a new response context. */
|
||||||
void InitializeResponseContext(IpcResponseContext *ctx) {
|
void InitializeResponseContext(IpcResponseContext *ctx) {
|
||||||
std::memset(ctx, 0, sizeof(*ctx));
|
std::memset(ctx, 0, sizeof(*ctx));
|
||||||
@ -123,19 +121,18 @@ class ServiceSession : public IWaitable
|
|||||||
ctx->pb = this->pointer_buffer.data();
|
ctx->pb = this->pointer_buffer.data();
|
||||||
ctx->pb_size = this->pointer_buffer.size();
|
ctx->pb_size = this->pointer_buffer.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* IWaitable */
|
/* IWaitable */
|
||||||
virtual Handle GetHandle() {
|
virtual Handle GetHandle() {
|
||||||
return this->session_handle;
|
return this->session_handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual Result GetResponse(IpcResponseContext *ctx) {
|
virtual Result GetResponse(IpcResponseContext *ctx) {
|
||||||
Result rc = ResultKernelConnectionClosed;
|
|
||||||
FirmwareVersion fw = GetRuntimeFirmwareVersion();
|
FirmwareVersion fw = GetRuntimeFirmwareVersion();
|
||||||
|
|
||||||
const ServiceCommandMeta *dispatch_table = ctx->obj_holder->GetDispatchTable();
|
const ServiceCommandMeta *dispatch_table = ctx->obj_holder->GetDispatchTable();
|
||||||
size_t entry_count = ctx->obj_holder->GetDispatchTableEntryCount();
|
size_t entry_count = ctx->obj_holder->GetDispatchTableEntryCount();
|
||||||
|
|
||||||
if (IsDomainObject(ctx->obj_holder)) {
|
if (IsDomainObject(ctx->obj_holder)) {
|
||||||
switch (ctx->request.InMessageType) {
|
switch (ctx->request.InMessageType) {
|
||||||
case DomainMessageType_Invalid:
|
case DomainMessageType_Invalid:
|
||||||
@ -156,22 +153,22 @@ class ServiceSession : public IWaitable
|
|||||||
|
|
||||||
for (size_t i = 0; i < entry_count; i++) {
|
for (size_t i = 0; i < entry_count; i++) {
|
||||||
if (ctx->cmd_id == dispatch_table[i].cmd_id && dispatch_table[i].fw_low <= fw && fw <= dispatch_table[i].fw_high) {
|
if (ctx->cmd_id == dispatch_table[i].cmd_id && dispatch_table[i].fw_low <= fw && fw <= dispatch_table[i].fw_high) {
|
||||||
rc = dispatch_table[i].handler(ctx);
|
R_TRY(dispatch_table[i].handler(ctx));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return rc;
|
return ResultSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual Result HandleReceived() {
|
virtual Result HandleReceived() {
|
||||||
IpcResponseContext ctx;
|
IpcResponseContext ctx;
|
||||||
this->InitializeResponseContext(&ctx);
|
this->InitializeResponseContext(&ctx);
|
||||||
|
|
||||||
ctx.cmd_type = (IpcCommandType)(*(u16 *)(armGetTls()));
|
ctx.cmd_type = (IpcCommandType)(*(u16 *)(armGetTls()));
|
||||||
|
|
||||||
ctx.rc = ResultSuccess;
|
ctx.rc = ResultSuccess;
|
||||||
|
|
||||||
/* Parse based on command type. */
|
/* Parse based on command type. */
|
||||||
switch (ctx.cmd_type) {
|
switch (ctx.cmd_type) {
|
||||||
case IpcCommandType_Invalid:
|
case IpcCommandType_Invalid:
|
||||||
@ -201,14 +198,14 @@ class ServiceSession : public IWaitable
|
|||||||
default:
|
default:
|
||||||
return ResultKernelConnectionClosed;
|
return ResultKernelConnectionClosed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (R_SUCCEEDED(ctx.rc)) {
|
if (R_SUCCEEDED(ctx.rc)) {
|
||||||
ctx.cmd_id = ((u32 *)ctx.request.Raw)[2];
|
ctx.cmd_id = ((u32 *)ctx.request.Raw)[2];
|
||||||
this->PreProcessRequest(&ctx);
|
this->PreProcessRequest(&ctx);
|
||||||
ctx.rc = this->GetResponse(&ctx);
|
ctx.rc = this->GetResponse(&ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ctx.rc == ResultServiceFrameworkRequestDeferredByUser) {
|
if (ctx.rc == ResultServiceFrameworkRequestDeferredByUser) {
|
||||||
/* Session defer. */
|
/* Session defer. */
|
||||||
this->SetDeferred(true);
|
this->SetDeferred(true);
|
||||||
@ -218,124 +215,118 @@ class ServiceSession : public IWaitable
|
|||||||
if (R_SUCCEEDED(ctx.rc)) {
|
if (R_SUCCEEDED(ctx.rc)) {
|
||||||
this->PostProcessResponse(&ctx);
|
this->PostProcessResponse(&ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.rc = this->Reply();
|
ctx.rc = this->Reply();
|
||||||
|
|
||||||
if (ctx.rc == ResultKernelTimedOut) {
|
if (ctx.rc == ResultKernelTimedOut) {
|
||||||
ctx.rc = ResultSuccess;
|
ctx.rc = ResultSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
this->CleanupResponse(&ctx);
|
this->CleanupResponse(&ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ctx.rc;
|
return ctx.rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual Result HandleDeferred() override {
|
virtual Result HandleDeferred() override {
|
||||||
memcpy(armGetTls(), this->backup_tls, sizeof(this->backup_tls));
|
memcpy(armGetTls(), this->backup_tls, sizeof(this->backup_tls));
|
||||||
Result rc = this->HandleReceived();
|
|
||||||
|
auto defer_guard = SCOPE_GUARD {
|
||||||
if (rc != ResultServiceFrameworkRequestDeferredByUser) {
|
|
||||||
this->SetDeferred(false);
|
this->SetDeferred(false);
|
||||||
}
|
};
|
||||||
return rc;
|
|
||||||
|
R_TRY_CATCH(this->HandleReceived()) {
|
||||||
|
R_CATCH(ResultServiceFrameworkRequestDeferredByUser) {
|
||||||
|
defer_guard.Cancel();
|
||||||
|
return ResultServiceFrameworkRequestDeferredByUser;
|
||||||
|
}
|
||||||
|
} R_END_TRY_CATCH;
|
||||||
|
|
||||||
|
return ResultSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual Result HandleSignaled(u64 timeout) {
|
virtual Result HandleSignaled(u64 timeout) {
|
||||||
Result rc;
|
R_TRY(this->Receive());
|
||||||
|
R_TRY(this->HandleReceived());
|
||||||
if (R_SUCCEEDED(rc = this->Receive())) {
|
return ResultSuccess;
|
||||||
rc = this->HandleReceived();
|
|
||||||
}
|
|
||||||
|
|
||||||
return rc;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void PreProcessRequest(IpcResponseContext *ctx) {
|
virtual void PreProcessRequest(IpcResponseContext *ctx) {
|
||||||
/* ... */
|
/* ... */
|
||||||
(void)(ctx);
|
(void)(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void PostProcessResponse(IpcResponseContext *ctx) {
|
virtual void PostProcessResponse(IpcResponseContext *ctx) {
|
||||||
/* ... */
|
/* ... */
|
||||||
(void)(ctx);
|
(void)(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void CleanupResponse(IpcResponseContext *ctx) {
|
virtual void CleanupResponse(IpcResponseContext *ctx) {
|
||||||
std::memset(this->backup_tls, 0, sizeof(this->backup_tls));
|
std::memset(this->backup_tls, 0, sizeof(this->backup_tls));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
class IHipcControlService : public IServiceObject {
|
class IHipcControlService : public IServiceObject {
|
||||||
private:
|
private:
|
||||||
ServiceSession *session;
|
ServiceSession *session;
|
||||||
public:
|
public:
|
||||||
explicit IHipcControlService(ServiceSession *s) : session(s) {
|
explicit IHipcControlService(ServiceSession *s) : session(s) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~IHipcControlService() override { }
|
virtual ~IHipcControlService() override { }
|
||||||
|
|
||||||
Result ConvertCurrentObjectToDomain(Out<u32> object_id) {
|
Result ConvertCurrentObjectToDomain(Out<u32> object_id) {
|
||||||
/* Allocate new domain. */
|
/* Allocate new domain. */
|
||||||
auto new_domain = this->session->GetDomainManager()->AllocateDomain();
|
auto new_domain = this->session->GetDomainManager()->AllocateDomain();
|
||||||
if (new_domain == nullptr) {
|
if (new_domain == nullptr) {
|
||||||
return ResultHipcOutOfDomains;
|
return ResultHipcOutOfDomains;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Reserve an object in the domain for our session. */
|
/* Reserve an object in the domain for our session. */
|
||||||
u32 reserved_id;
|
u32 reserved_id;
|
||||||
Result rc = new_domain->ReserveObject(&reserved_id);
|
R_TRY(new_domain->ReserveObject(&reserved_id));
|
||||||
if (R_FAILED(rc)) {
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
new_domain->SetObject(reserved_id, std::move(this->session->obj_holder));
|
new_domain->SetObject(reserved_id, std::move(this->session->obj_holder));
|
||||||
this->session->obj_holder = std::move(ServiceObjectHolder(std::move(new_domain)));
|
this->session->obj_holder = std::move(ServiceObjectHolder(std::move(new_domain)));
|
||||||
|
|
||||||
/* Return the object id. */
|
/* Return the object id. */
|
||||||
object_id.SetValue(reserved_id);
|
object_id.SetValue(reserved_id);
|
||||||
return ResultSuccess;
|
return ResultSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result CopyFromCurrentDomain(Out<MovedHandle> out_h, u32 id) {
|
Result CopyFromCurrentDomain(Out<MovedHandle> out_h, u32 id) {
|
||||||
auto domain = this->session->obj_holder.GetServiceObject<IDomainObject>();
|
auto domain = this->session->obj_holder.GetServiceObject<IDomainObject>();
|
||||||
if (domain == nullptr) {
|
if (domain == nullptr) {
|
||||||
return ResultHipcTargetNotDomain;
|
return ResultHipcTargetNotDomain;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
auto object = domain->GetObject(id);
|
auto object = domain->GetObject(id);
|
||||||
if (object == nullptr) {
|
if (object == nullptr) {
|
||||||
return ResultHipcDomainObjectNotFound;
|
return ResultHipcDomainObjectNotFound;
|
||||||
}
|
}
|
||||||
|
|
||||||
Handle server_h, client_h;
|
Handle server_h, client_h;
|
||||||
if (R_FAILED(SessionManagerBase::CreateSessionHandles(&server_h, &client_h))) {
|
R_ASSERT(SessionManagerBase::CreateSessionHandles(&server_h, &client_h));
|
||||||
/* N aborts here. Should we error code? */
|
|
||||||
std::abort();
|
|
||||||
}
|
|
||||||
|
|
||||||
this->session->GetSessionManager()->AddSession(server_h, std::move(object->Clone()));
|
this->session->GetSessionManager()->AddSession(server_h, std::move(object->Clone()));
|
||||||
out_h.SetValue(client_h);
|
out_h.SetValue(client_h);
|
||||||
return ResultSuccess;
|
return ResultSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CloneCurrentObject(Out<MovedHandle> out_h) {
|
void CloneCurrentObject(Out<MovedHandle> out_h) {
|
||||||
Handle server_h, client_h;
|
Handle server_h, client_h;
|
||||||
if (R_FAILED(SessionManagerBase::CreateSessionHandles(&server_h, &client_h))) {
|
R_ASSERT(SessionManagerBase::CreateSessionHandles(&server_h, &client_h));
|
||||||
/* N aborts here. Should we error code? */
|
|
||||||
std::abort();
|
|
||||||
}
|
|
||||||
|
|
||||||
this->session->GetSessionManager()->AddSession(server_h, std::move(this->session->obj_holder.Clone()));
|
this->session->GetSessionManager()->AddSession(server_h, std::move(this->session->obj_holder.Clone()));
|
||||||
out_h.SetValue(client_h);
|
out_h.SetValue(client_h);
|
||||||
}
|
}
|
||||||
|
|
||||||
void QueryPointerBufferSize(Out<u16> size) {
|
void QueryPointerBufferSize(Out<u16> size) {
|
||||||
size.SetValue(this->session->pointer_buffer.size());
|
size.SetValue(this->session->pointer_buffer.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
void CloneCurrentObjectEx(Out<MovedHandle> out_h, u32 which) {
|
void CloneCurrentObjectEx(Out<MovedHandle> out_h, u32 which) {
|
||||||
/* TODO: Figure out what this u32 controls. */
|
/* TODO: Figure out what this u32 controls. */
|
||||||
return CloneCurrentObject(out_h);
|
return CloneCurrentObject(out_h);
|
||||||
|
@ -41,9 +41,7 @@ class MitmServer : public IWaitable {
|
|||||||
DoWithSmMitmSession([&]() {
|
DoWithSmMitmSession([&]() {
|
||||||
strncpy(mitm_name, service_name, 8);
|
strncpy(mitm_name, service_name, 8);
|
||||||
mitm_name[8] = '\x00';
|
mitm_name[8] = '\x00';
|
||||||
if (R_FAILED(smMitMInstall(&this->port_handle, &query_h, mitm_name))) {
|
R_ASSERT(smMitMInstall(&this->port_handle, &query_h, mitm_name));
|
||||||
std::abort();
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
#pragma GCC diagnostic pop
|
#pragma GCC diagnostic pop
|
||||||
|
|
||||||
@ -53,9 +51,7 @@ class MitmServer : public IWaitable {
|
|||||||
virtual ~MitmServer() override {
|
virtual ~MitmServer() override {
|
||||||
if (this->port_handle) {
|
if (this->port_handle) {
|
||||||
DoWithSmMitmSession([&]() {
|
DoWithSmMitmSession([&]() {
|
||||||
if (R_FAILED(smMitMUninstall(this->mitm_name))) {
|
R_ASSERT(smMitMUninstall(this->mitm_name));
|
||||||
std::abort();
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
svcCloseHandle(port_handle);
|
svcCloseHandle(port_handle);
|
||||||
}
|
}
|
||||||
@ -73,10 +69,7 @@ class MitmServer : public IWaitable {
|
|||||||
virtual Result HandleSignaled(u64 timeout) override {
|
virtual Result HandleSignaled(u64 timeout) override {
|
||||||
/* If this server's port was signaled, accept a new session. */
|
/* If this server's port was signaled, accept a new session. */
|
||||||
Handle session_h;
|
Handle session_h;
|
||||||
Result rc = svcAcceptSession(&session_h, this->port_handle);
|
R_TRY(svcAcceptSession(&session_h, this->port_handle));
|
||||||
if (R_FAILED(rc)) {
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Create a forward service for this instance. */
|
/* Create a forward service for this instance. */
|
||||||
std::shared_ptr<Service> forward_service(new Service(), [](Service *s) {
|
std::shared_ptr<Service> forward_service(new Service(), [](Service *s) {
|
||||||
@ -88,9 +81,7 @@ class MitmServer : public IWaitable {
|
|||||||
u64 client_pid;
|
u64 client_pid;
|
||||||
|
|
||||||
DoWithSmMitmSession([&]() {
|
DoWithSmMitmSession([&]() {
|
||||||
if (R_FAILED(smMitMAcknowledgeSession(forward_service.get(), &client_pid, mitm_name))) {
|
R_ASSERT(smMitMAcknowledgeSession(forward_service.get(), &client_pid, mitm_name));
|
||||||
std::abort();
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
this->GetSessionManager()->AddWaitable(new MitmSession(session_h, client_pid, forward_service, MakeShared(forward_service, client_pid)));
|
this->GetSessionManager()->AddWaitable(new MitmSession(session_h, client_pid, forward_service, MakeShared(forward_service, client_pid)));
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <switch.h>
|
#include <switch.h>
|
||||||
#include <stratosphere.hpp>
|
#include <stratosphere.hpp>
|
||||||
@ -26,14 +26,14 @@ class MitmSession final : public ServiceSession {
|
|||||||
private:
|
private:
|
||||||
/* This will be for the actual session. */
|
/* This will be for the actual session. */
|
||||||
std::shared_ptr<Service> forward_service;
|
std::shared_ptr<Service> forward_service;
|
||||||
|
|
||||||
struct PostProcessHandlerContext {
|
struct PostProcessHandlerContext {
|
||||||
bool closed;
|
bool closed;
|
||||||
void (*handler)(IMitmServiceObject *, IpcResponseContext *);
|
void (*handler)(IMitmServiceObject *, IpcResponseContext *);
|
||||||
};
|
};
|
||||||
/* Store a handler for the service. */
|
/* Store a handler for the service. */
|
||||||
std::shared_ptr<PostProcessHandlerContext> service_post_process_ctx;
|
std::shared_ptr<PostProcessHandlerContext> service_post_process_ctx;
|
||||||
|
|
||||||
/* For cleanup usage. */
|
/* For cleanup usage. */
|
||||||
u64 client_pid;
|
u64 client_pid;
|
||||||
u32 num_fwd_copy_hnds = 0;
|
u32 num_fwd_copy_hnds = 0;
|
||||||
@ -43,36 +43,32 @@ class MitmSession final : public ServiceSession {
|
|||||||
MitmSession(Handle s_h, u64 pid, std::shared_ptr<Service> fs, std::shared_ptr<T> srv) : ServiceSession(s_h), client_pid(pid) {
|
MitmSession(Handle s_h, u64 pid, std::shared_ptr<Service> fs, std::shared_ptr<T> srv) : ServiceSession(s_h), client_pid(pid) {
|
||||||
this->forward_service = std::move(fs);
|
this->forward_service = std::move(fs);
|
||||||
this->obj_holder = std::move(ServiceObjectHolder(std::move(srv)));
|
this->obj_holder = std::move(ServiceObjectHolder(std::move(srv)));
|
||||||
|
|
||||||
this->service_post_process_ctx = std::make_shared<PostProcessHandlerContext>();
|
this->service_post_process_ctx = std::make_shared<PostProcessHandlerContext>();
|
||||||
this->service_post_process_ctx->closed = false;
|
this->service_post_process_ctx->closed = false;
|
||||||
this->service_post_process_ctx->handler = T::PostProcess;
|
this->service_post_process_ctx->handler = T::PostProcess;
|
||||||
|
|
||||||
size_t pbs;
|
size_t pbs;
|
||||||
if (R_FAILED(ipcQueryPointerBufferSize(forward_service->handle, &pbs))) {
|
R_ASSERT(ipcQueryPointerBufferSize(forward_service->handle, &pbs));
|
||||||
std::abort();
|
|
||||||
}
|
|
||||||
this->pointer_buffer.resize(pbs);
|
this->pointer_buffer.resize(pbs);
|
||||||
this->control_holder.Reset();
|
this->control_holder.Reset();
|
||||||
this->control_holder = std::move(ServiceObjectHolder(std::move(std::make_shared<IMitmHipcControlService>(this))));
|
this->control_holder = std::move(ServiceObjectHolder(std::move(std::make_shared<IMitmHipcControlService>(this))));
|
||||||
}
|
}
|
||||||
|
|
||||||
MitmSession(Handle s_h, u64 pid, std::shared_ptr<Service> fs, ServiceObjectHolder &&h, std::shared_ptr<PostProcessHandlerContext> ppc) : ServiceSession(s_h), client_pid(pid) {
|
MitmSession(Handle s_h, u64 pid, std::shared_ptr<Service> fs, ServiceObjectHolder &&h, std::shared_ptr<PostProcessHandlerContext> ppc) : ServiceSession(s_h), client_pid(pid) {
|
||||||
this->session_handle = s_h;
|
this->session_handle = s_h;
|
||||||
this->forward_service = std::move(fs);
|
this->forward_service = std::move(fs);
|
||||||
this->obj_holder = std::move(h);
|
this->obj_holder = std::move(h);
|
||||||
|
|
||||||
this->service_post_process_ctx = ppc;
|
this->service_post_process_ctx = ppc;
|
||||||
|
|
||||||
size_t pbs;
|
size_t pbs;
|
||||||
if (R_FAILED(ipcQueryPointerBufferSize(forward_service->handle, &pbs))) {
|
R_ASSERT(ipcQueryPointerBufferSize(forward_service->handle, &pbs));
|
||||||
std::abort();
|
|
||||||
}
|
|
||||||
this->pointer_buffer.resize(pbs);
|
this->pointer_buffer.resize(pbs);
|
||||||
this->control_holder.Reset();
|
this->control_holder.Reset();
|
||||||
this->control_holder = std::move(ServiceObjectHolder(std::move(std::make_shared<IMitmHipcControlService>(this))));
|
this->control_holder = std::move(ServiceObjectHolder(std::move(std::make_shared<IMitmHipcControlService>(this))));
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void PreProcessRequest(IpcResponseContext *ctx) override {
|
virtual void PreProcessRequest(IpcResponseContext *ctx) override {
|
||||||
u32 *cmdbuf = (u32 *)armGetTls();
|
u32 *cmdbuf = (u32 *)armGetTls();
|
||||||
u32 *backup_cmdbuf = (u32 *)this->backup_tls;
|
u32 *backup_cmdbuf = (u32 *)this->backup_tls;
|
||||||
@ -82,12 +78,15 @@ class MitmSession final : public ServiceSession {
|
|||||||
backup_cmdbuf[4] = cmdbuf[4];
|
backup_cmdbuf[4] = cmdbuf[4];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Result ForwardRequest(IpcResponseContext *ctx) {
|
Result ForwardRequest(IpcResponseContext *ctx) {
|
||||||
IpcParsedCommand r;
|
/* Dispatch forwards. */
|
||||||
Result rc = serviceIpcDispatch(this->forward_service.get());
|
R_TRY(serviceIpcDispatch(this->forward_service.get()));
|
||||||
if (R_SUCCEEDED(rc)) {
|
|
||||||
if (ctx->request.IsDomainRequest) {
|
/* Parse. */
|
||||||
|
{
|
||||||
|
IpcParsedCommand r;
|
||||||
|
if (ctx->request.IsDomainRequest) {
|
||||||
/* We never work with out object ids, so this should be fine. */
|
/* We never work with out object ids, so this should be fine. */
|
||||||
ipcParseDomainResponse(&r, 0);
|
ipcParseDomainResponse(&r, 0);
|
||||||
} else {
|
} else {
|
||||||
@ -99,24 +98,24 @@ class MitmSession final : public ServiceSession {
|
|||||||
u64 result;
|
u64 result;
|
||||||
} *resp = (decltype(resp))r.Raw;
|
} *resp = (decltype(resp))r.Raw;
|
||||||
|
|
||||||
rc = resp->result;
|
|
||||||
|
|
||||||
for (unsigned int i = 0; i < r.NumHandles; i++) {
|
for (unsigned int i = 0; i < r.NumHandles; i++) {
|
||||||
if (r.WasHandleCopied[i]) {
|
if (r.WasHandleCopied[i]) {
|
||||||
this->fwd_copy_hnds[num_fwd_copy_hnds++] = r.Handles[i];
|
this->fwd_copy_hnds[num_fwd_copy_hnds++] = r.Handles[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
R_TRY(resp->result);
|
||||||
}
|
}
|
||||||
return rc;
|
|
||||||
|
return ResultSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual Result GetResponse(IpcResponseContext *ctx) {
|
virtual Result GetResponse(IpcResponseContext *ctx) {
|
||||||
Result rc = ResultKernelConnectionClosed;
|
|
||||||
FirmwareVersion fw = GetRuntimeFirmwareVersion();
|
FirmwareVersion fw = GetRuntimeFirmwareVersion();
|
||||||
|
|
||||||
const ServiceCommandMeta *dispatch_table = ctx->obj_holder->GetDispatchTable();
|
const ServiceCommandMeta *dispatch_table = ctx->obj_holder->GetDispatchTable();
|
||||||
size_t entry_count = ctx->obj_holder->GetDispatchTableEntryCount();
|
size_t entry_count = ctx->obj_holder->GetDispatchTableEntryCount();
|
||||||
|
|
||||||
if (IsDomainObject(ctx->obj_holder)) {
|
if (IsDomainObject(ctx->obj_holder)) {
|
||||||
switch (ctx->request.InMessageType) {
|
switch (ctx->request.InMessageType) {
|
||||||
case DomainMessageType_Invalid:
|
case DomainMessageType_Invalid:
|
||||||
@ -125,56 +124,61 @@ class MitmSession final : public ServiceSession {
|
|||||||
{
|
{
|
||||||
auto sub_obj = ctx->obj_holder->GetServiceObject<IDomainObject>()->GetObject(ctx->request.InThisObjectId);
|
auto sub_obj = ctx->obj_holder->GetServiceObject<IDomainObject>()->GetObject(ctx->request.InThisObjectId);
|
||||||
if (sub_obj == nullptr) {
|
if (sub_obj == nullptr) {
|
||||||
rc = ForwardRequest(ctx);
|
R_TRY(ForwardRequest(ctx));
|
||||||
return rc;
|
return ResultSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sub_obj->IsMitmObject()) {
|
if (sub_obj->IsMitmObject()) {
|
||||||
rc = ForwardRequest(ctx);
|
R_TRY(ForwardRequest(ctx));
|
||||||
if (R_SUCCEEDED(rc)) {
|
ctx->obj_holder->GetServiceObject<IDomainObject>()->FreeObject(ctx->request.InThisObjectId);
|
||||||
ctx->obj_holder->GetServiceObject<IDomainObject>()->FreeObject(ctx->request.InThisObjectId);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
rc = ctx->obj_holder->GetServiceObject<IDomainObject>()->FreeObject(ctx->request.InThisObjectId);
|
R_TRY(ctx->obj_holder->GetServiceObject<IDomainObject>()->FreeObject(ctx->request.InThisObjectId));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (R_SUCCEEDED(rc) && ctx->request.InThisObjectId == serviceGetObjectId(this->forward_service.get()) && !this->service_post_process_ctx->closed) {
|
if (ctx->request.InThisObjectId == serviceGetObjectId(this->forward_service.get()) && !this->service_post_process_ctx->closed) {
|
||||||
/* If we're not longer MitMing anything, we'll no longer do any postprocessing. */
|
/* If we're not longer MitMing anything, we'll no longer do any postprocessing. */
|
||||||
this->service_post_process_ctx->closed = true;
|
this->service_post_process_ctx->closed = true;
|
||||||
}
|
}
|
||||||
return rc;
|
return ResultSuccess;
|
||||||
}
|
}
|
||||||
case DomainMessageType_SendMessage:
|
case DomainMessageType_SendMessage:
|
||||||
{
|
{
|
||||||
auto sub_obj = ctx->obj_holder->GetServiceObject<IDomainObject>()->GetObject(ctx->request.InThisObjectId);
|
auto sub_obj = ctx->obj_holder->GetServiceObject<IDomainObject>()->GetObject(ctx->request.InThisObjectId);
|
||||||
if (sub_obj == nullptr) {
|
if (sub_obj == nullptr) {
|
||||||
rc = ForwardRequest(ctx);
|
R_TRY(ForwardRequest(ctx));
|
||||||
return rc;
|
return ResultSuccess;
|
||||||
}
|
}
|
||||||
dispatch_table = sub_obj->GetDispatchTable();
|
dispatch_table = sub_obj->GetDispatchTable();
|
||||||
entry_count = sub_obj->GetDispatchTableEntryCount();
|
entry_count = sub_obj->GetDispatchTableEntryCount();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool found_entry = false;
|
Result (*handler)(IpcResponseContext *ctx) = nullptr;
|
||||||
|
|
||||||
for (size_t i = 0; i < entry_count; i++) {
|
for (size_t i = 0; i < entry_count; i++) {
|
||||||
if (ctx->cmd_id == dispatch_table[i].cmd_id && dispatch_table[i].fw_low <= fw && fw <= dispatch_table[i].fw_high) {
|
if (ctx->cmd_id == dispatch_table[i].cmd_id && dispatch_table[i].fw_low <= fw && fw <= dispatch_table[i].fw_high) {
|
||||||
rc = dispatch_table[i].handler(ctx);
|
handler = dispatch_table[i].handler;
|
||||||
found_entry = true;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!found_entry || rc == ResultAtmosphereMitmShouldForwardToSession) {
|
if (handler == nullptr) {
|
||||||
memcpy(armGetTls(), this->backup_tls, sizeof(this->backup_tls));
|
R_TRY(ForwardRequest(ctx));
|
||||||
rc = ForwardRequest(ctx);
|
return ResultSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
return rc;
|
R_TRY_CATCH(handler(ctx)) {
|
||||||
|
R_CATCH(ResultAtmosphereMitmShouldForwardToSession) {
|
||||||
|
std::memcpy(armGetTls(), this->backup_tls, sizeof(this->backup_tls));
|
||||||
|
R_TRY(ForwardRequest(ctx));
|
||||||
|
return ResultSuccess;
|
||||||
|
}
|
||||||
|
} R_END_TRY_CATCH;
|
||||||
|
|
||||||
|
return ResultSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void PostProcessResponse(IpcResponseContext *ctx) override {
|
virtual void PostProcessResponse(IpcResponseContext *ctx) override {
|
||||||
if ((ctx->cmd_type == IpcCommandType_Request || ctx->cmd_type == IpcCommandType_RequestWithContext) && R_SUCCEEDED(ctx->rc)) {
|
if ((ctx->cmd_type == IpcCommandType_Request || ctx->cmd_type == IpcCommandType_RequestWithContext) && R_SUCCEEDED(ctx->rc)) {
|
||||||
if (this->service_post_process_ctx->closed) {
|
if (this->service_post_process_ctx->closed) {
|
||||||
@ -197,11 +201,11 @@ class MitmSession final : public ServiceSession {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void CleanupResponse(IpcResponseContext *ctx) override {
|
virtual void CleanupResponse(IpcResponseContext *ctx) override {
|
||||||
/* Cleanup tls backup. */
|
/* Cleanup tls backup. */
|
||||||
std::memset(this->backup_tls, 0, sizeof(this->backup_tls));
|
std::memset(this->backup_tls, 0, sizeof(this->backup_tls));
|
||||||
|
|
||||||
/* Clean up copy handles. */
|
/* Clean up copy handles. */
|
||||||
for (unsigned int i = 0; i < ctx->request.NumHandles; i++) {
|
for (unsigned int i = 0; i < ctx->request.NumHandles; i++) {
|
||||||
if (ctx->request.WasHandleCopied[i]) {
|
if (ctx->request.WasHandleCopied[i]) {
|
||||||
@ -213,16 +217,16 @@ class MitmSession final : public ServiceSession {
|
|||||||
}
|
}
|
||||||
this->num_fwd_copy_hnds = 0;
|
this->num_fwd_copy_hnds = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
class IMitmHipcControlService : public IServiceObject {
|
class IMitmHipcControlService : public IServiceObject {
|
||||||
private:
|
private:
|
||||||
MitmSession *session;
|
MitmSession *session;
|
||||||
public:
|
public:
|
||||||
explicit IMitmHipcControlService(MitmSession *s) : session(s) {
|
explicit IMitmHipcControlService(MitmSession *s) : session(s) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~IMitmHipcControlService() override { }
|
virtual ~IMitmHipcControlService() override { }
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -230,40 +234,37 @@ class MitmSession final : public ServiceSession {
|
|||||||
if (IsDomainObject(this->session->obj_holder)) {
|
if (IsDomainObject(this->session->obj_holder)) {
|
||||||
return ResultKernelConnectionClosed;
|
return ResultKernelConnectionClosed;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result rc = serviceConvertToDomain(this->session->forward_service.get());
|
R_TRY(serviceConvertToDomain(this->session->forward_service.get()));
|
||||||
if (R_FAILED(rc)) {
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
u32 expected_id = serviceGetObjectId(this->session->forward_service.get());
|
u32 expected_id = serviceGetObjectId(this->session->forward_service.get());
|
||||||
|
|
||||||
/* Allocate new domain. */
|
/* Allocate new domain. */
|
||||||
auto new_domain = this->session->GetDomainManager()->AllocateDomain();
|
auto new_domain = this->session->GetDomainManager()->AllocateDomain();
|
||||||
if (new_domain == nullptr) {
|
if (new_domain == nullptr) {
|
||||||
/* If our domains mismatch, we're in trouble. */
|
/* If our domains mismatch, we're in trouble. */
|
||||||
return ResultKernelConnectionClosed;
|
return ResultKernelConnectionClosed;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Reserve the expected object in the domain for our session. */
|
/* Reserve the expected object in the domain for our session. */
|
||||||
if (R_FAILED(new_domain->ReserveSpecificObject(expected_id))) {
|
if (R_FAILED(new_domain->ReserveSpecificObject(expected_id))) {
|
||||||
return ResultKernelConnectionClosed;
|
return ResultKernelConnectionClosed;
|
||||||
}
|
}
|
||||||
new_domain->SetObject(expected_id, std::move(this->session->obj_holder));
|
new_domain->SetObject(expected_id, std::move(this->session->obj_holder));
|
||||||
this->session->obj_holder = std::move(ServiceObjectHolder(std::move(new_domain)));
|
this->session->obj_holder = std::move(ServiceObjectHolder(std::move(new_domain)));
|
||||||
|
|
||||||
/* Return the object id. */
|
/* Return the object id. */
|
||||||
object_id.SetValue(expected_id);
|
object_id.SetValue(expected_id);
|
||||||
return ResultSuccess;
|
return ResultSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result CopyFromCurrentDomain(Out<MovedHandle> out_h, u32 id) {
|
Result CopyFromCurrentDomain(Out<MovedHandle> out_h, u32 id) {
|
||||||
auto domain = this->session->obj_holder.GetServiceObject<IDomainObject>();
|
auto domain = this->session->obj_holder.GetServiceObject<IDomainObject>();
|
||||||
if (domain == nullptr) {
|
if (domain == nullptr) {
|
||||||
return ResultHipcTargetNotDomain;
|
return ResultHipcTargetNotDomain;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
auto object = domain->GetObject(id);
|
auto object = domain->GetObject(id);
|
||||||
if (object == nullptr) {
|
if (object == nullptr) {
|
||||||
/* Forward onwards. */
|
/* Forward onwards. */
|
||||||
@ -276,31 +277,26 @@ class MitmSession final : public ServiceSession {
|
|||||||
buf[7] = 0;
|
buf[7] = 0;
|
||||||
buf[8] = id;
|
buf[8] = id;
|
||||||
buf[9] = 0;
|
buf[9] = 0;
|
||||||
Result rc = ipcDispatch(this->session->forward_service->handle);
|
R_TRY(ipcDispatch(this->session->forward_service->handle));
|
||||||
if (R_SUCCEEDED(rc)) {
|
{
|
||||||
IpcParsedCommand r;
|
IpcParsedCommand r;
|
||||||
ipcParse(&r);
|
ipcParse(&r);
|
||||||
struct {
|
struct {
|
||||||
u64 magic;
|
u64 magic;
|
||||||
u64 result;
|
u64 result;
|
||||||
} *raw = (decltype(raw))r.Raw;
|
} *raw = (decltype(raw))r.Raw;
|
||||||
rc = raw->result;
|
R_TRY(raw->result);
|
||||||
|
|
||||||
if (R_SUCCEEDED(rc)) {
|
out_h.SetValue(r.Handles[0]);
|
||||||
out_h.SetValue(r.Handles[0]);
|
this->session->fwd_copy_hnds[this->session->num_fwd_copy_hnds++] = r.Handles[0];
|
||||||
this->session->fwd_copy_hnds[this->session->num_fwd_copy_hnds++] = r.Handles[0];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return rc;
|
return ResultSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
Handle server_h, client_h;
|
Handle server_h, client_h;
|
||||||
if (R_FAILED(SessionManagerBase::CreateSessionHandles(&server_h, &client_h))) {
|
R_ASSERT(SessionManagerBase::CreateSessionHandles(&server_h, &client_h));
|
||||||
/* N aborts here. Should we error code? */
|
|
||||||
std::abort();
|
|
||||||
}
|
|
||||||
out_h.SetValue(client_h);
|
out_h.SetValue(client_h);
|
||||||
|
|
||||||
if (id == serviceGetObjectId(this->session->forward_service.get())) {
|
if (id == serviceGetObjectId(this->session->forward_service.get())) {
|
||||||
this->session->GetSessionManager()->AddWaitable(new MitmSession(server_h, this->session->client_pid, this->session->forward_service, std::move(object->Clone()), this->session->service_post_process_ctx));
|
this->session->GetSessionManager()->AddWaitable(new MitmSession(server_h, this->session->client_pid, this->session->forward_service, std::move(object->Clone()), this->session->service_post_process_ctx));
|
||||||
} else {
|
} else {
|
||||||
@ -308,27 +304,24 @@ class MitmSession final : public ServiceSession {
|
|||||||
}
|
}
|
||||||
return ResultSuccess;
|
return ResultSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CloneCurrentObject(Out<MovedHandle> out_h) {
|
void CloneCurrentObject(Out<MovedHandle> out_h) {
|
||||||
Handle server_h, client_h;
|
Handle server_h, client_h;
|
||||||
if (R_FAILED(SessionManagerBase::CreateSessionHandles(&server_h, &client_h))) {
|
R_ASSERT(SessionManagerBase::CreateSessionHandles(&server_h, &client_h));
|
||||||
/* N aborts here. Should we error code? */
|
|
||||||
std::abort();
|
|
||||||
}
|
|
||||||
|
|
||||||
this->session->GetSessionManager()->AddWaitable(new MitmSession(server_h, this->session->client_pid, this->session->forward_service, std::move(this->session->obj_holder.Clone()), this->session->service_post_process_ctx));
|
this->session->GetSessionManager()->AddWaitable(new MitmSession(server_h, this->session->client_pid, this->session->forward_service, std::move(this->session->obj_holder.Clone()), this->session->service_post_process_ctx));
|
||||||
out_h.SetValue(client_h);
|
out_h.SetValue(client_h);
|
||||||
}
|
}
|
||||||
|
|
||||||
void QueryPointerBufferSize(Out<u16> size) {
|
void QueryPointerBufferSize(Out<u16> size) {
|
||||||
size.SetValue(this->session->pointer_buffer.size());
|
size.SetValue(this->session->pointer_buffer.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
void CloneCurrentObjectEx(Out<MovedHandle> out_h, u32 which) {
|
void CloneCurrentObjectEx(Out<MovedHandle> out_h, u32 which) {
|
||||||
/* TODO: Figure out what this u32 controls. */
|
/* TODO: Figure out what this u32 controls. */
|
||||||
return CloneCurrentObject(out_h);
|
return CloneCurrentObject(out_h);
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
DEFINE_SERVICE_DISPATCH_TABLE {
|
DEFINE_SERVICE_DISPATCH_TABLE {
|
||||||
MakeServiceCommandMeta<HipcControlCommand_ConvertCurrentObjectToDomain, &MitmSession::IMitmHipcControlService::ConvertCurrentObjectToDomain>(),
|
MakeServiceCommandMeta<HipcControlCommand_ConvertCurrentObjectToDomain, &MitmSession::IMitmHipcControlService::ConvertCurrentObjectToDomain>(),
|
||||||
|
@ -75,12 +75,14 @@ extern "C" {
|
|||||||
})
|
})
|
||||||
|
|
||||||
/// Evaluates an expression that returns a result, and returns the result (after evaluating a cleanup expression) if it would fail.
|
/// Evaluates an expression that returns a result, and returns the result (after evaluating a cleanup expression) if it would fail.
|
||||||
|
#define R_CLEANUP_RESULT _tmp_r_try_cleanup_rc
|
||||||
|
|
||||||
#define R_TRY_CLEANUP(res_expr, cleanup_expr) \
|
#define R_TRY_CLEANUP(res_expr, cleanup_expr) \
|
||||||
({ \
|
({ \
|
||||||
const Result _tmp_r_try_cleanup_rc = res_expr; \
|
const Result R_CLEANUP_RESULT = res_expr; \
|
||||||
if (R_FAILED(_tmp_r_try_cleanup_rc)) { \
|
if (R_FAILED(R_CLEANUP_RESULT)) { \
|
||||||
({ cleanup_expr }); \
|
({ cleanup_expr }); \
|
||||||
return _tmp_r_try_cleanup_rc; \
|
return R_CLEANUP_RESULT; \
|
||||||
} \
|
} \
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -49,10 +49,7 @@ class IServer : public IWaitable {
|
|||||||
virtual Result HandleSignaled(u64 timeout) override {
|
virtual Result HandleSignaled(u64 timeout) override {
|
||||||
/* If this server's port was signaled, accept a new session. */
|
/* If this server's port was signaled, accept a new session. */
|
||||||
Handle session_h;
|
Handle session_h;
|
||||||
Result rc = svcAcceptSession(&session_h, this->port_handle);
|
R_TRY(svcAcceptSession(&session_h, this->port_handle));
|
||||||
if (R_FAILED(rc)) {
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
this->GetSessionManager()->AddSession(session_h, std::move(ServiceObjectHolder(std::move(MakeShared()))));
|
this->GetSessionManager()->AddSession(session_h, std::move(ServiceObjectHolder(std::move(MakeShared()))));
|
||||||
return ResultSuccess;
|
return ResultSuccess;
|
||||||
@ -64,9 +61,7 @@ class ServiceServer : public IServer<T, MakeShared> {
|
|||||||
public:
|
public:
|
||||||
ServiceServer(const char *service_name, unsigned int max_s) : IServer<T, MakeShared>(max_s) {
|
ServiceServer(const char *service_name, unsigned int max_s) : IServer<T, MakeShared>(max_s) {
|
||||||
DoWithSmSession([&]() {
|
DoWithSmSession([&]() {
|
||||||
if (R_FAILED(smRegisterService(&this->port_handle, service_name, false, this->max_sessions))) {
|
R_ASSERT(smRegisterService(&this->port_handle, service_name, false, this->max_sessions));
|
||||||
std::abort();
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -83,8 +78,6 @@ template <typename T, auto MakeShared = std::make_shared<T>>
|
|||||||
class ManagedPortServer : public IServer<T, MakeShared> {
|
class ManagedPortServer : public IServer<T, MakeShared> {
|
||||||
public:
|
public:
|
||||||
ManagedPortServer(const char *service_name, unsigned int max_s) : IServer<T, MakeShared>(max_s) {
|
ManagedPortServer(const char *service_name, unsigned int max_s) : IServer<T, MakeShared>(max_s) {
|
||||||
if (R_FAILED(svcManageNamedPort(&this->port_handle, service_name, this->max_sessions))) {
|
R_ASSERT(svcManageNamedPort(&this->port_handle, service_name, this->max_sessions));
|
||||||
std::abort();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
@ -13,7 +13,7 @@
|
|||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <switch.h>
|
#include <switch.h>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
@ -70,51 +70,41 @@ static inline Result SmcGetConfig(SplConfigItem config_item, u64 *out_config) {
|
|||||||
args.X[0] = 0xC3000002; /* smcGetConfig */
|
args.X[0] = 0xC3000002; /* smcGetConfig */
|
||||||
args.X[1] = (u64)config_item; /* config item */
|
args.X[1] = (u64)config_item; /* config item */
|
||||||
|
|
||||||
Result rc = svcCallSecureMonitor(&args);
|
R_TRY(svcCallSecureMonitor(&args));
|
||||||
if (R_SUCCEEDED(rc)) {
|
if (args.X[0] != 0) {
|
||||||
if (args.X[0] == 0) {
|
/* SPL result n = SMC result n */
|
||||||
if (out_config) {
|
return MAKERESULT(26, args.X[0]);
|
||||||
*out_config = args.X[1];
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
/* SPL result n = SMC result n */
|
|
||||||
rc = MAKERESULT(26, args.X[0]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return rc;
|
|
||||||
|
if (out_config) {
|
||||||
|
*out_config = args.X[1];
|
||||||
|
}
|
||||||
|
return ResultSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline Result GetRcmBugPatched(bool *out) {
|
static inline Result GetRcmBugPatched(bool *out) {
|
||||||
u64 tmp = 0;
|
u64 tmp = 0;
|
||||||
Result rc = SmcGetConfig((SplConfigItem)65004, &tmp);
|
R_TRY(SmcGetConfig((SplConfigItem)65004, &tmp));
|
||||||
if (R_SUCCEEDED(rc)) {
|
*out = (tmp != 0);
|
||||||
*out = (tmp != 0);
|
return ResultSuccess;
|
||||||
}
|
|
||||||
return rc;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool IsRcmBugPatched() {
|
static inline bool IsRcmBugPatched() {
|
||||||
bool rcm_bug_patched;
|
bool rcm_bug_patched;
|
||||||
if (R_FAILED(GetRcmBugPatched(&rcm_bug_patched))) {
|
R_ASSERT(GetRcmBugPatched(&rcm_bug_patched));
|
||||||
std::abort();
|
|
||||||
}
|
|
||||||
return rcm_bug_patched;
|
return rcm_bug_patched;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline Result GetShouldBlankProdInfo(bool *out) {
|
static inline Result GetShouldBlankProdInfo(bool *out) {
|
||||||
u64 tmp = 0;
|
u64 tmp = 0;
|
||||||
Result rc = SmcGetConfig((SplConfigItem)65005, &tmp);
|
R_TRY(SmcGetConfig((SplConfigItem)65005, &tmp));
|
||||||
if (R_SUCCEEDED(rc)) {
|
*out = (tmp != 0);
|
||||||
*out = (tmp != 0);
|
return ResultSuccess;
|
||||||
}
|
|
||||||
return rc;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool ShouldBlankProdInfo() {
|
static inline bool ShouldBlankProdInfo() {
|
||||||
bool should_blank_prodinfo;
|
bool should_blank_prodinfo;
|
||||||
if (R_FAILED(GetShouldBlankProdInfo(&should_blank_prodinfo))) {
|
R_ASSERT(GetShouldBlankProdInfo(&should_blank_prodinfo));
|
||||||
std::abort();
|
|
||||||
}
|
|
||||||
return should_blank_prodinfo;
|
return should_blank_prodinfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -125,13 +115,8 @@ template<typename F>
|
|||||||
static void DoWithSmSession(F f) {
|
static void DoWithSmSession(F f) {
|
||||||
std::scoped_lock<HosRecursiveMutex &> lk(GetSmSessionMutex());
|
std::scoped_lock<HosRecursiveMutex &> lk(GetSmSessionMutex());
|
||||||
{
|
{
|
||||||
Result rc;
|
R_ASSERT(smInitialize());
|
||||||
if (R_SUCCEEDED((rc = smInitialize()))) {
|
f();
|
||||||
f();
|
|
||||||
} else {
|
|
||||||
/* TODO: fatalSimple(rc); ? */
|
|
||||||
std::abort();
|
|
||||||
}
|
|
||||||
smExit();
|
smExit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -140,13 +125,8 @@ template<typename F>
|
|||||||
static void DoWithSmMitmSession(F f) {
|
static void DoWithSmMitmSession(F f) {
|
||||||
std::scoped_lock<HosRecursiveMutex &> lk(GetSmMitmSessionMutex());
|
std::scoped_lock<HosRecursiveMutex &> lk(GetSmMitmSessionMutex());
|
||||||
{
|
{
|
||||||
Result rc;
|
R_ASSERT(smMitMInitialize());
|
||||||
if (R_SUCCEEDED((rc = smMitMInitialize()))) {
|
f();
|
||||||
f();
|
|
||||||
} else {
|
|
||||||
/* TODO: fatalSimple(rc); ? */
|
|
||||||
std::abort();
|
|
||||||
}
|
|
||||||
smMitMExit();
|
smMitMExit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -75,16 +75,11 @@ class WaitableManager : public SessionManagerBase {
|
|||||||
public:
|
public:
|
||||||
WaitableManager(u32 n, u32 ss = 0x8000) : num_extra_threads(n-1) {
|
WaitableManager(u32 n, u32 ss = 0x8000) : num_extra_threads(n-1) {
|
||||||
u32 prio;
|
u32 prio;
|
||||||
Result rc;
|
|
||||||
if (num_extra_threads) {
|
if (num_extra_threads) {
|
||||||
threads = new HosThread[num_extra_threads];
|
threads = new HosThread[num_extra_threads];
|
||||||
if (R_FAILED((rc = svcGetThreadPriority(&prio, CUR_THREAD_HANDLE)))) {
|
R_ASSERT(svcGetThreadPriority(&prio, CUR_THREAD_HANDLE));
|
||||||
fatalSimple(rc);
|
|
||||||
}
|
|
||||||
for (unsigned int i = 0; i < num_extra_threads; i++) {
|
for (unsigned int i = 0; i < num_extra_threads; i++) {
|
||||||
if (R_FAILED(threads[i].Initialize(&WaitableManager::ProcessLoop, this, ss, prio))) {
|
R_ASSERT(threads[i].Initialize(&WaitableManager::ProcessLoop, this, ss, prio));
|
||||||
std::abort();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -130,11 +125,8 @@ class WaitableManager : public SessionManagerBase {
|
|||||||
/* Set main thread handle. */
|
/* Set main thread handle. */
|
||||||
this->main_thread_handle = GetCurrentThreadHandle();
|
this->main_thread_handle = GetCurrentThreadHandle();
|
||||||
|
|
||||||
Result rc;
|
|
||||||
for (unsigned int i = 0; i < num_extra_threads; i++) {
|
for (unsigned int i = 0; i < num_extra_threads; i++) {
|
||||||
if (R_FAILED((rc = threads[i].Start()))) {
|
R_ASSERT(threads[i].Start());
|
||||||
fatalSimple(rc);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ProcessLoop(this);
|
ProcessLoop(this);
|
||||||
@ -167,8 +159,7 @@ class WaitableManager : public SessionManagerBase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (w) {
|
if (w) {
|
||||||
Result rc = w->HandleSignaled(0);
|
if (w->HandleSignaled(0) == ResultKernelConnectionClosed) {
|
||||||
if (rc == ResultKernelConnectionClosed) {
|
|
||||||
/* Close! */
|
/* Close! */
|
||||||
delete w;
|
delete w;
|
||||||
} else {
|
} else {
|
||||||
@ -189,11 +180,11 @@ class WaitableManager : public SessionManagerBase {
|
|||||||
undeferred_any = false;
|
undeferred_any = false;
|
||||||
for (auto it = this_ptr->deferred_waitables.begin(); it != this_ptr->deferred_waitables.end();) {
|
for (auto it = this_ptr->deferred_waitables.begin(); it != this_ptr->deferred_waitables.end();) {
|
||||||
auto w = *it;
|
auto w = *it;
|
||||||
Result rc = w->HandleDeferred();
|
const bool closed = (w->HandleDeferred() == ResultKernelConnectionClosed);
|
||||||
if (rc == ResultKernelConnectionClosed || !w->IsDeferred()) {
|
if (closed || !w->IsDeferred()) {
|
||||||
/* Remove from the deferred list, set iterator. */
|
/* Remove from the deferred list, set iterator. */
|
||||||
it = this_ptr->deferred_waitables.erase(it);
|
it = this_ptr->deferred_waitables.erase(it);
|
||||||
if (rc == ResultKernelConnectionClosed) {
|
if (closed) {
|
||||||
/* Delete the closed waitable. */
|
/* Delete the closed waitable. */
|
||||||
delete w;
|
delete w;
|
||||||
} else {
|
} else {
|
||||||
@ -249,7 +240,6 @@ class WaitableManager : public SessionManagerBase {
|
|||||||
std::vector<IWaitable *> wait_list;
|
std::vector<IWaitable *> wait_list;
|
||||||
|
|
||||||
int handle_index = 0;
|
int handle_index = 0;
|
||||||
Result rc;
|
|
||||||
while (result == nullptr) {
|
while (result == nullptr) {
|
||||||
/* Sort waitables by priority. */
|
/* Sort waitables by priority. */
|
||||||
std::sort(this->waitables.begin(), this->waitables.end(), IWaitable::Compare);
|
std::sort(this->waitables.begin(), this->waitables.end(), IWaitable::Compare);
|
||||||
@ -269,21 +259,21 @@ class WaitableManager : public SessionManagerBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Wait forever. */
|
/* Wait forever. */
|
||||||
rc = svcWaitSynchronization(&handle_index, handles.data(), num_handles, U64_MAX);
|
const Result wait_res = svcWaitSynchronization(&handle_index, handles.data(), num_handles, U64_MAX);
|
||||||
|
|
||||||
if (this->should_stop) {
|
if (this->should_stop) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (R_SUCCEEDED(rc)) {
|
if (R_SUCCEEDED(wait_res)) {
|
||||||
IWaitable *w = wait_list[handle_index];
|
IWaitable *w = wait_list[handle_index];
|
||||||
size_t w_ind = std::distance(this->waitables.begin(), std::find(this->waitables.begin(), this->waitables.end(), w));
|
size_t w_ind = std::distance(this->waitables.begin(), std::find(this->waitables.begin(), this->waitables.end(), w));
|
||||||
std::for_each(waitables.begin(), waitables.begin() + w_ind + 1, std::mem_fn(&IWaitable::UpdatePriority));
|
std::for_each(waitables.begin(), waitables.begin() + w_ind + 1, std::mem_fn(&IWaitable::UpdatePriority));
|
||||||
result = w;
|
result = w;
|
||||||
} else if (rc == ResultKernelTimedOut) {
|
} else if (wait_res == ResultKernelTimedOut) {
|
||||||
/* Timeout: Just update priorities. */
|
/* Timeout: Just update priorities. */
|
||||||
std::for_each(waitables.begin(), waitables.end(), std::mem_fn(&IWaitable::UpdatePriority));
|
std::for_each(waitables.begin(), waitables.end(), std::mem_fn(&IWaitable::UpdatePriority));
|
||||||
} else if (rc == ResultKernelCancelled) {
|
} else if (wait_res == ResultKernelCancelled) {
|
||||||
/* svcCancelSynchronization was called. */
|
/* svcCancelSynchronization was called. */
|
||||||
AddWaitablesInternal();
|
AddWaitablesInternal();
|
||||||
{
|
{
|
||||||
|
@ -74,20 +74,21 @@ static void _CacheValues(void)
|
|||||||
char file_path[EmummcMaxDirLength+1];
|
char file_path[EmummcMaxDirLength+1];
|
||||||
char nintendo_path[EmummcMaxDirLength+1];
|
char nintendo_path[EmummcMaxDirLength+1];
|
||||||
} __attribute__((aligned(0x1000))) paths;
|
} __attribute__((aligned(0x1000))) paths;
|
||||||
|
|
||||||
{
|
{
|
||||||
SecmonArgs args = {0};
|
SecmonArgs args = {0};
|
||||||
args.X[0] = 0xF0000404; /* smcAmsGetEmunandConfig */
|
args.X[0] = 0xF0000404; /* smcAmsGetEmunandConfig */
|
||||||
args.X[1] = 0; /* NAND */
|
args.X[1] = 0; /* NAND */
|
||||||
args.X[2] = reinterpret_cast<u64>(&paths); /* path output */
|
args.X[2] = reinterpret_cast<u64>(&paths); /* path output */
|
||||||
if (R_FAILED(svcCallSecureMonitor(&args)) || args.X[0] != 0) {
|
R_ASSERT(svcCallSecureMonitor(&args));
|
||||||
|
if (args.X[0] != 0) {
|
||||||
std::abort();
|
std::abort();
|
||||||
}
|
}
|
||||||
std::memcpy(&g_exo_emummc_config, &args.X[1], sizeof(args) - sizeof(args.X[0]));
|
std::memcpy(&g_exo_emummc_config, &args.X[1], sizeof(args) - sizeof(args.X[0]));
|
||||||
}
|
}
|
||||||
|
|
||||||
const EmummcType emummc_type = static_cast<EmummcType>(g_exo_emummc_config.base_cfg.type);
|
const EmummcType emummc_type = static_cast<EmummcType>(g_exo_emummc_config.base_cfg.type);
|
||||||
|
|
||||||
/* Ignore format warnings. */
|
/* Ignore format warnings. */
|
||||||
#pragma GCC diagnostic push
|
#pragma GCC diagnostic push
|
||||||
#pragma GCC diagnostic ignored "-Wformat-truncation"
|
#pragma GCC diagnostic ignored "-Wformat-truncation"
|
||||||
@ -98,11 +99,11 @@ static void _CacheValues(void)
|
|||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::snprintf(g_exo_emummc_config.emu_dir_path, sizeof(g_exo_emummc_config.emu_dir_path), "/%s", paths.nintendo_path);
|
std::snprintf(g_exo_emummc_config.emu_dir_path, sizeof(g_exo_emummc_config.emu_dir_path), "/%s", paths.nintendo_path);
|
||||||
|
|
||||||
g_IsEmummc = g_exo_emummc_config.base_cfg.magic == EmummcStorageMagic && emummc_type != EmummcType_Emmc;
|
g_IsEmummc = g_exo_emummc_config.base_cfg.magic == EmummcStorageMagic && emummc_type != EmummcType_Emmc;
|
||||||
|
|
||||||
/* Default Nintendo redirection path. */
|
/* Default Nintendo redirection path. */
|
||||||
if (g_IsEmummc) {
|
if (g_IsEmummc) {
|
||||||
if (std::strcmp(g_exo_emummc_config.emu_dir_path, "/") == 0) {
|
if (std::strcmp(g_exo_emummc_config.emu_dir_path, "/") == 0) {
|
||||||
|
@ -39,7 +39,8 @@ static void _CacheValues(void)
|
|||||||
SecmonArgs args = {0};
|
SecmonArgs args = {0};
|
||||||
args.X[0] = 0xC3000002; /* smcGetConfig */
|
args.X[0] = 0xC3000002; /* smcGetConfig */
|
||||||
args.X[1] = 65000; /* ConfigItem_ExosphereVersion */
|
args.X[1] = 65000; /* ConfigItem_ExosphereVersion */
|
||||||
if (R_FAILED(svcCallSecureMonitor(&args)) || args.X[0] != 0) {
|
R_ASSERT(svcCallSecureMonitor(&args));
|
||||||
|
if (args.X[0] != 0) {
|
||||||
std::abort();
|
std::abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <switch.h>
|
#include <switch.h>
|
||||||
#include <stratosphere.hpp>
|
#include <stratosphere.hpp>
|
||||||
@ -23,20 +23,21 @@ static std::vector<u64> g_known_tids;
|
|||||||
static HosMutex g_pid_tid_mutex;
|
static HosMutex g_pid_tid_mutex;
|
||||||
|
|
||||||
Result MitmQueryUtils::GetAssociatedTidForPid(u64 pid, u64 *tid) {
|
Result MitmQueryUtils::GetAssociatedTidForPid(u64 pid, u64 *tid) {
|
||||||
Result rc = ResultAtmosphereMitmProcessNotAssociated;
|
std::scoped_lock lk(g_pid_tid_mutex);
|
||||||
std::scoped_lock lk{g_pid_tid_mutex};
|
|
||||||
for (unsigned int i = 0; i < g_known_pids.size(); i++) {
|
for (unsigned int i = 0; i < g_known_pids.size(); i++) {
|
||||||
if (g_known_pids[i] == pid) {
|
if (g_known_pids[i] == pid) {
|
||||||
*tid = g_known_tids[i];
|
*tid = g_known_tids[i];
|
||||||
rc = ResultSuccess;
|
return ResultSuccess;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return rc;
|
|
||||||
|
return ResultAtmosphereMitmProcessNotAssociated;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MitmQueryUtils::AssociatePidToTid(u64 pid, u64 tid) {
|
void MitmQueryUtils::AssociatePidToTid(u64 pid, u64 tid) {
|
||||||
std::scoped_lock lk{g_pid_tid_mutex};
|
std::scoped_lock lk(g_pid_tid_mutex);
|
||||||
|
|
||||||
g_known_pids.push_back(pid);
|
g_known_pids.push_back(pid);
|
||||||
g_known_tids.push_back(tid);
|
g_known_tids.push_back(tid);
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <switch.h>
|
#include <switch.h>
|
||||||
#include <stratosphere.hpp>
|
#include <stratosphere.hpp>
|
||||||
@ -28,23 +28,19 @@ static void ServerQueryManagerThreadFunc(void *arg) {
|
|||||||
|
|
||||||
void RegisterMitmServerQueryHandle(Handle query_h, ServiceObjectHolder &&service) {
|
void RegisterMitmServerQueryHandle(Handle query_h, ServiceObjectHolder &&service) {
|
||||||
std::scoped_lock<HosMutex> lock(g_server_query_mutex);
|
std::scoped_lock<HosMutex> lock(g_server_query_mutex);
|
||||||
|
|
||||||
const bool exists = g_server_query_manager != nullptr;
|
const bool exists = g_server_query_manager != nullptr;
|
||||||
if (!exists) {
|
if (!exists) {
|
||||||
/* Create a new waitable manager if it doesn't exist already. */
|
/* Create a new waitable manager if it doesn't exist already. */
|
||||||
g_server_query_manager = new WaitableManager(1);
|
g_server_query_manager = new WaitableManager(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Add session to the manager. */
|
/* Add session to the manager. */
|
||||||
g_server_query_manager->AddSession(query_h, std::move(service));
|
g_server_query_manager->AddSession(query_h, std::move(service));
|
||||||
|
|
||||||
/* If this is our first time, launch thread. */
|
/* If this is our first time, launch thread. */
|
||||||
if (!exists) {
|
if (!exists) {
|
||||||
if (R_FAILED(g_server_query_manager_thread.Initialize(&ServerQueryManagerThreadFunc, nullptr, 0x4000, 27))) {
|
R_ASSERT(g_server_query_manager_thread.Initialize(&ServerQueryManagerThreadFunc, nullptr, 0x4000, 27));
|
||||||
std::abort();
|
R_ASSERT(g_server_query_manager_thread.Start());
|
||||||
}
|
|
||||||
if (R_FAILED(g_server_query_manager_thread.Start())) {
|
|
||||||
std::abort();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -120,14 +120,9 @@ void StratosphereCrashHandler(ThreadExceptionDump *ctx) {
|
|||||||
|
|
||||||
/* Default exception handler behavior. */
|
/* Default exception handler behavior. */
|
||||||
void __attribute__((weak)) __libstratosphere_exception_handler(AtmosphereFatalErrorContext *ctx) {
|
void __attribute__((weak)) __libstratosphere_exception_handler(AtmosphereFatalErrorContext *ctx) {
|
||||||
Result rc = bpcAmsInitialize();
|
R_ASSERT(bpcAmsInitialize());
|
||||||
if (R_SUCCEEDED(rc)) {
|
R_ASSERT(bpcAmsRebootToFatalError(ctx));
|
||||||
rc = bpcAmsRebootToFatalError(ctx);
|
bpcAmsExit();
|
||||||
bpcAmsExit();
|
|
||||||
}
|
|
||||||
if (R_FAILED(rc)) {
|
|
||||||
std::abort();
|
|
||||||
}
|
|
||||||
while (1) { }
|
while (1) { }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,9 +34,7 @@ class XorShiftGenerator {
|
|||||||
/* Seed using process entropy. */
|
/* Seed using process entropy. */
|
||||||
u64 val = 0;
|
u64 val = 0;
|
||||||
for (size_t i = 0; i < num_seed_dwords; i++) {
|
for (size_t i = 0; i < num_seed_dwords; i++) {
|
||||||
if (R_FAILED(svcGetInfo(&val, 0xB, 0, i))) {
|
R_ASSERT(svcGetInfo(&val, 0xB, 0, i));
|
||||||
std::abort();
|
|
||||||
}
|
|
||||||
this->random_state[i] = result_type(val);
|
this->random_state[i] = result_type(val);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user