libstrat: refactor for R_TRY

This commit is contained in:
Michael Scire 2019-06-20 05:01:24 -07:00
parent 7c9df9cfd8
commit 4a120c3c16
17 changed files with 345 additions and 418 deletions

View File

@ -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
#--------------------------------------------------------------------------------- #---------------------------------------------------------------------------------

View File

@ -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);
} }

View File

@ -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);
} }

View File

@ -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;
} }

View File

@ -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);

View File

@ -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)));

View File

@ -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>(),

View File

@ -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; \
} \ } \
}) })

View File

@ -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();
}
} }
}; };

View File

@ -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();
} }
} }

View File

@ -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();
{ {

View File

@ -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) {

View File

@ -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();
} }

View File

@ -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);
} }

View File

@ -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();
}
} }
} }

View File

@ -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) { }
} }

View File

@ -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);
} }
} }