fatal: Implement fatal:p, fatal:u stub.

This commit is contained in:
Michael Scire 2018-11-10 00:11:38 -08:00
parent bb29a2458f
commit b9091e9466
12 changed files with 664 additions and 1 deletions

View file

@ -0,0 +1,45 @@
/*
* Copyright (c) 2018 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <switch.h>
#include "fatal_event_manager.hpp"
FatalEventManager::FatalEventManager() {
/* Just create all the events. */
for (size_t i = 0; i < FatalEventManager::NumFatalEvents; i++) {
if (R_FAILED(eventCreate(&this->events[i], true))) {
std::abort();
}
}
}
Result FatalEventManager::GetEvent(Handle *out) {
std::scoped_lock<HosMutex> lk{this->lock};
/* Only allow GetEvent to succeed NumFatalEvents times. */
if (this->events_gotten >= FatalEventManager::NumFatalEvents) {
return 0x8A3;
}
*out = this->events[this->events_gotten++].revent;
return 0;
}
void FatalEventManager::SignalEvents() {
for (size_t i = 0; i < FatalEventManager::NumFatalEvents; i++) {
eventFire(&this->events[i]);
}
}

View file

@ -0,0 +1,32 @@
/*
* Copyright (c) 2018 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <switch.h>
#include <stratosphere.hpp>
class FatalEventManager {
private:
static constexpr size_t NumFatalEvents = 3;
HosMutex lock;
size_t events_gotten = 0;
Event events[3];
public:
FatalEventManager();
Result GetEvent(Handle *out);
void SignalEvents();
};

View file

@ -0,0 +1,97 @@
/*
* Copyright (c) 2018 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <cstdlib>
#include <cstdint>
#include <cstring>
#include <malloc.h>
#include <switch.h>
#include <atmosphere.h>
#include <stratosphere.hpp>
#include "fatal_types.hpp"
#include "fatal_private.hpp"
#include "fatal_user.hpp"
extern "C" {
extern u32 __start__;
u32 __nx_applet_type = AppletType_None;
#define INNER_HEAP_SIZE 0x20000
size_t nx_inner_heap_size = INNER_HEAP_SIZE;
char nx_inner_heap[INNER_HEAP_SIZE];
void __libnx_initheap(void);
void __appInit(void);
void __appExit(void);
}
void __libnx_initheap(void) {
void* addr = nx_inner_heap;
size_t size = nx_inner_heap_size;
/* Newlib */
extern char* fake_heap_start;
extern char* fake_heap_end;
fake_heap_start = (char*)addr;
fake_heap_end = (char*)addr + size;
}
void __appInit(void) {
Result rc;
rc = smInitialize();
if (R_FAILED(rc)) {
fatalSimple(MAKERESULT(Module_Libnx, LibnxError_InitFail_SM));
}
rc = setsysInitialize();
if (R_FAILED(rc)) {
fatalSimple(rc);
}
CheckAtmosphereVersion(CURRENT_ATMOSPHERE_VERSION);
}
void __appExit(void) {
/* Cleanup services. */
setsysExit();
smExit();
}
int main(int argc, char **argv)
{
consoleDebugInit(debugDevice_SVC);
/* TODO: What's a good timeout value to use here? */
auto server_manager = new WaitableManager(1);
/* TODO: Create services. */
server_manager->AddWaitable(new ServiceServer<PrivateService>("fatal:p", 4));
server_manager->AddWaitable(new ServiceServer<UserService>("fatal:u", 4));
/* Loop forever, servicing our services. */
server_manager->Process();
delete server_manager;
return 0;
}

View file

@ -0,0 +1,25 @@
/*
* Copyright (c) 2018 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <switch.h>
#include "fatal_private.hpp"
#include "fatal_event_manager.hpp"
static FatalEventManager g_EventManager;
Result PrivateService::GetFatalEvent(Out<CopiedHandle> out_h) {
return g_EventManager.GetEvent(out_h.GetHandlePointer());
}

View file

@ -0,0 +1,33 @@
/*
* Copyright (c) 2018 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <switch.h>
#include <stratosphere.hpp>
enum PrivateCmd {
Private_Cmd_GetFatalEvent = 0,
};
class PrivateService final : public IServiceObject {
private:
/* Actual commands. */
Result GetFatalEvent(Out<CopiedHandle> out_h);
public:
DEFINE_SERVICE_DISPATCH_TABLE {
MakeServiceCommandMeta<Private_Cmd_GetFatalEvent, &PrivateService::GetFatalEvent>(),
};
};

View file

@ -0,0 +1,97 @@
/*
* Copyright (c) 2018 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <switch.h>
#include <stratosphere.hpp>
enum FatalResult : Result {
FatalResult_TooManyEvents = 0x8A3,
FatalResult_InRepairWithoutVolHeld = 0xAA3,
FatalResult_InRepairWithoutTimeReviserCartridge = 0xCA3,
};
struct Aarch64CpuContext {
using RegisterType = u64;
static constexpr size_t MaxStackTraceDepth = 0x20;
/* Registers, exception context. N left names for these fields in fatal .rodata. */
union {
RegisterType x[31];
struct {
RegisterType _x[29];
RegisterType fp;
RegisterType lr;
RegisterType sp;
RegisterType pc;
};
};
RegisterType pstate;
RegisterType afsr0;
RegisterType afsr1;
RegisterType esr;
RegisterType far;
/* Misc. */
RegisterType stack_trace[MaxStackTraceDepth];
RegisterType start_address;
RegisterType register_set_flags;
u32 stack_trace_size;
};
struct Aarch32CpuContext {
using RegisterType = u32;
static constexpr size_t MaxStackTraceDepth = 0x20;
/* Registers, exception context. N left names for these fields in fatal .rodata. */
union {
RegisterType r[16];
struct {
RegisterType _x[11];
RegisterType fp;
RegisterType ip;
RegisterType sp;
RegisterType lr;
RegisterType pc;
};
};
RegisterType pstate;
RegisterType afsr0;
RegisterType afsr1;
RegisterType esr;
RegisterType far;
/* Misc. Yes, stack_trace_size is really laid out differently than aarch64... */
RegisterType stack_trace[MaxStackTraceDepth];
u32 stack_trace_size;
RegisterType start_address;
RegisterType register_set_flags;
};
struct FatalCpuContext {
union {
Aarch64CpuContext aarch64_ctx;
Aarch64CpuContext aarch32_ctx;
};
bool is_aarch32;
u32 type;
};
static_assert(sizeof(Aarch64CpuContext) == 0x248, "Aarch64CpuContext definition!");
static_assert(sizeof(Aarch32CpuContext) == 0xE0, "Aarch32CpuContext definition!");
static_assert(sizeof(FatalCpuContext) == 0x250, "FatalCpuContext definition!");
static_assert(std::is_pod_v<FatalCpuContext>, "FatalCpuContext definition!");

View file

@ -0,0 +1,43 @@
/*
* Copyright (c) 2018 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <switch.h>
#include "fatal_user.hpp"
Result UserService::ThrowFatalImpl(u32 error, u64 pid, FatalType policy, FatalCpuContext *context) {
/* TODO */
return 0;
}
Result UserService::ThrowFatal(u32 error, PidDescriptor pid_desc) {
FatalCpuContext ctx = {0};
return ThrowFatalImpl(error, pid_desc.pid, FatalType_ErrorReportAndErrorScreen, &ctx);
}
Result UserService::ThrowFatalWithPolicy(u32 error, PidDescriptor pid_desc, FatalType policy) {
FatalCpuContext ctx = {0};
return ThrowFatalImpl(error, pid_desc.pid, policy, &ctx);
}
Result UserService::ThrowFatalWithCpuContext(u32 error, PidDescriptor pid_desc, FatalType policy, InBuffer<FatalCpuContext> _ctx) {
/* Require exactly one context passed in. */
if (_ctx.num_elements != 1) {
return 0xF601;
}
return ThrowFatalImpl(error, pid_desc.pid, policy, _ctx.buffer);
}

View file

@ -0,0 +1,43 @@
/*
* Copyright (c) 2018 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <switch.h>
#include <stratosphere.hpp>
#include "fatal_types.hpp"
enum UserCmd {
User_Cmd_ThrowFatal = 0,
User_Cmd_ThrowFatalWithPolicy = 1,
User_Cmd_ThrowFatalWithCpuContext = 2,
};
class UserService final : public IServiceObject {
private:
Result ThrowFatalImpl(u32 error, u64 pid, FatalType policy, FatalCpuContext *context);
/* Actual commands. */
Result ThrowFatal(u32 error, PidDescriptor pid_desc);
Result ThrowFatalWithPolicy(u32 error, PidDescriptor pid_desc, FatalType policy);
Result ThrowFatalWithCpuContext(u32 error, PidDescriptor pid_desc, FatalType policy, InBuffer<FatalCpuContext> _ctx);
public:
DEFINE_SERVICE_DISPATCH_TABLE {
MakeServiceCommandMeta<User_Cmd_ThrowFatal, &UserService::ThrowFatal>(),
MakeServiceCommandMeta<User_Cmd_ThrowFatalWithPolicy, &UserService::ThrowFatalWithPolicy>(),
MakeServiceCommandMeta<User_Cmd_ThrowFatalWithCpuContext, &UserService::ThrowFatalWithCpuContext>(),
};
};