fatal: update for new-ipc

This commit is contained in:
Michael Scire 2019-10-17 19:39:22 -07:00 committed by SciresM
parent 8d16d2152b
commit 799c158b86
9 changed files with 113 additions and 73 deletions

View file

@ -65,40 +65,54 @@ namespace sts::fatal::srv {
return false;
}
/* HACK: We want to parse the command the fatal caller sent. */
/* The easiest way to do this is to copy their TLS over ours, and parse ours. */
std::memcpy(armGetTls(), thread_tls, sizeof(thread_tls));
/* We want to parse the command the fatal caller sent. */
{
IpcParsedCommand r;
if (R_FAILED(ipcParse(&r))) {
return false;
}
const auto request = hipcParseRequest(thread_tls);
const struct {
CmifInHeader header;
u32 error_code;
} *in_data = decltype(in_data)(request.data.data_words);
static_assert(sizeof(*in_data) == 0x14, "InData!");
/* Fatal command takes in a PID, only one buffer max. */
if (!r.HasPid || r.NumStatics || r.NumStaticsOut || r.NumHandles) {
if ((request.meta.type != CmifCommandType_Request && request.meta.type != CmifCommandType_RequestWithContext) ||
!request.meta.send_pid ||
request.meta.num_send_statics ||
request.meta.num_recv_statics ||
request.meta.num_recv_buffers ||
request.meta.num_exch_buffers ||
request.meta.num_copy_handles ||
request.meta.num_move_handles ||
request.meta.num_data_words < ((sizeof(*in_data) + 0x10) / sizeof(u32)))
{
return false;
}
struct {
u32 magic;
u32 version;
u64 cmd_id;
u32 err_code;
} *raw = (decltype(raw))(r.Raw);
if (raw->magic != SFCI_MAGIC) {
if (in_data->header.magic != CMIF_IN_HEADER_MAGIC) {
return false;
}
if (raw->cmd_id > 2) {
if (in_data->header.version > 1) {
return false;
}
if (raw->cmd_id != 2 && r.NumBuffers) {
switch (in_data->header.command_id) {
case 0:
case 1:
if (request.meta.num_send_buffers != 0) {
return false;
}
break;
case 2:
if (request.meta.num_send_buffers != 1) {
return false;
}
default:
return false;
}
if (raw->err_code != error_code) {
if (in_data->error_code != error_code) {
return false;
}
}
@ -154,10 +168,10 @@ namespace sts::fatal::srv {
}
void TryCollectDebugInformation(ThrowContext *ctx, u64 process_id) {
void TryCollectDebugInformation(ThrowContext *ctx, os::ProcessId process_id) {
/* Try to debug the process. This may fail, if we called into ourself. */
os::ManagedHandle debug_handle;
if (R_FAILED(svcDebugActiveProcess(debug_handle.GetPointer(), process_id))) {
if (R_FAILED(svcDebugActiveProcess(debug_handle.GetPointer(), static_cast<u64>(process_id)))) {
return;
}

View file

@ -20,6 +20,6 @@
namespace sts::fatal::srv {
void TryCollectDebugInformation(ThrowContext *ctx, u64 process_id);
void TryCollectDebugInformation(ThrowContext *ctx, os::ProcessId process_id);
}

View file

@ -17,7 +17,6 @@
#include <cstdlib>
#include <cstdint>
#include <cstring>
#include <malloc.h>
#include <switch.h>
#include <atmosphere.h>
@ -32,6 +31,7 @@ extern "C" {
extern u32 __start__;
u32 __nx_applet_type = AppletType_None;
u32 __nx_fs_num_sessions = 1;
#define INNER_HEAP_SIZE 0x2A0000
size_t nx_inner_heap_size = INNER_HEAP_SIZE;
@ -69,8 +69,10 @@ void __libnx_initheap(void) {
fake_heap_end = (char*)addr + size;
}
using namespace sts;
void __appInit(void) {
SetFirmwareVersionForLibnx();
hos::SetVersionForLibnx();
DoWithSmSession([&]() {
R_ASSERT(setInitialize());
@ -79,7 +81,7 @@ void __appInit(void) {
R_ASSERT(i2cInitialize());
R_ASSERT(bpcInitialize());
if (GetRuntimeFirmwareVersion() >= FirmwareVersion_800) {
if (hos::GetVersion() >= hos::Version_800) {
R_ASSERT(clkrstInitialize());
} else {
R_ASSERT(pcvInitialize());
@ -107,7 +109,7 @@ void __appExit(void) {
spsmExit();
psmExit();
lblExit();
if (GetRuntimeFirmwareVersion() >= FirmwareVersion_800) {
if (hos::GetVersion() >= hos::Version_800) {
clkrstExit();
} else {
pcvExit();
@ -119,26 +121,55 @@ void __appExit(void) {
setExit();
}
namespace {
using ServerOptions = sf::hipc::DefaultServerManagerOptions;
constexpr sm::ServiceName UserServiceName = sm::ServiceName::Encode("fatal:u");
constexpr size_t UserMaxSessions = 4;
constexpr sm::ServiceName PrivateServiceName = sm::ServiceName::Encode("fatal:p");
constexpr size_t PrivateMaxSessions = 4;
/* fatal:u, fatal:p. */
/* TODO: Consider max sessions enforcement? */
constexpr size_t NumServers = 2;
constexpr size_t NumSessions = UserMaxSessions + PrivateMaxSessions;
sf::hipc::ServerManager<NumServers, ServerOptions, NumSessions> g_server_manager;
}
int main(int argc, char **argv)
{
/* Load shared font. */
R_ASSERT(sts::fatal::srv::font::InitializeSharedFont());
R_ASSERT(fatal::srv::font::InitializeSharedFont());
/* Check whether we should throw fatal due to repair process. */
sts::fatal::srv::CheckRepairStatus();
/* Create waitable manager. */
static auto s_server_manager = WaitableManager(1);
fatal::srv::CheckRepairStatus();
/* Create services. */
s_server_manager.AddWaitable(new ServiceServer<sts::fatal::srv::PrivateService>("fatal:p", 4));
s_server_manager.AddWaitable(new ServiceServer<sts::fatal::srv::UserService>("fatal:u", 4));
R_ASSERT((g_server_manager.RegisterServer<fatal::srv::PrivateService>(PrivateServiceName, PrivateMaxSessions)));
R_ASSERT((g_server_manager.RegisterServer<fatal::srv::UserService>(UserServiceName, UserMaxSessions)));
/* Add dirty event holder. */
/* TODO: s_server_manager.AddWaitable(sts::fatal::srv::GetFatalDirtyEvent()); */
auto dirty_event_holder = sts::fatal::srv::GetFatalDirtyWaitableHolder();
(void)dirty_event_holder;
auto *dirty_event_holder = sts::fatal::srv::GetFatalDirtyWaitableHolder();
g_server_manager.AddUserWaitableHolder(dirty_event_holder);
/* Loop forever, servicing our services. */
s_server_manager.Process();
/* Because fatal has a user wait holder, we need to specify how to process manually. */
while (auto *signaled_holder = g_server_manager.WaitSignaled()) {
if (signaled_holder == dirty_event_holder) {
/* Dirty event holder was signaled. */
fatal::srv::OnFatalDirtyEvent();
g_server_manager.AddUserWaitableHolder(signaled_holder);
} else {
/* A server/session was signaled. Have the manager handle it. */
R_ASSERT(g_server_manager.Process(signaled_holder));
}
}
return 0;
}

View file

@ -23,7 +23,7 @@ namespace sts::fatal::srv {
bool IsInRepair() {
/* Before firmware 3.0.0, this wasn't implemented. */
if (GetRuntimeFirmwareVersion() < FirmwareVersion_300) {
if (hos::GetVersion() < hos::Version_300) {
return false;
}
@ -62,7 +62,7 @@ namespace sts::fatal::srv {
bool NeedsRunTimeReviser() {
/* Before firmware 5.0.0, this wasn't implemented. */
if (GetRuntimeFirmwareVersion() < FirmwareVersion_300) {
if (hos::GetVersion() < hos::Version_300) {
return false;
}

View file

@ -51,22 +51,22 @@ namespace sts::fatal::srv {
return this->event_manager.GetEvent(out);
}
Result ThrowFatal(u32 error_code, u64 process_id) {
Result ThrowFatal(u32 error_code, os::ProcessId process_id) {
return this->ThrowFatalWithCpuContext(error_code, process_id, FatalType_ErrorReportAndErrorScreen, {});
}
Result ThrowFatalWithPolicy(u32 error_code, u64 process_id, FatalType policy) {
Result ThrowFatalWithPolicy(u32 error_code, os::ProcessId process_id, FatalType policy) {
return this->ThrowFatalWithCpuContext(error_code, process_id, policy, {});
}
Result ThrowFatalWithCpuContext(u32 error_code, u64 process_id, FatalType policy, const CpuContext &cpu_ctx);
Result ThrowFatalWithCpuContext(u32 error_code, os::ProcessId process_id, FatalType policy, const CpuContext &cpu_ctx);
};
/* Context global. */
ServiceContext g_context;
/* Throw implementation. */
Result ServiceContext::ThrowFatalWithCpuContext(u32 error_code, u64 process_id, FatalType policy, const CpuContext &cpu_ctx) {
Result ServiceContext::ThrowFatalWithCpuContext(u32 error_code, os::ProcessId process_id, FatalType policy, const CpuContext &cpu_ctx) {
/* We don't support Error Report only fatals. */
if (policy == FatalType_ErrorReport) {
return ResultSuccess;
@ -92,7 +92,7 @@ namespace sts::fatal::srv {
if (!this->context.is_creport) {
/* On firmware version 2.0.0, use debugging SVCs to collect information. */
if (GetRuntimeFirmwareVersion() >= FirmwareVersion_200) {
if (hos::GetVersion() >= hos::Version_200) {
fatal::srv::TryCollectDebugInformation(&this->context, process_id);
}
} else {
@ -132,28 +132,22 @@ namespace sts::fatal::srv {
}
Result ThrowFatalForSelf(Result error_code) {
u64 process_id = 0;
R_ASSERT(svcGetProcessId(&process_id, CUR_PROCESS_HANDLE));
return g_context.ThrowFatalWithPolicy(static_cast<u32>(error_code), process_id, FatalType_ErrorScreen);
return g_context.ThrowFatalWithPolicy(static_cast<u32>(error_code), os::GetCurrentProcessId(), FatalType_ErrorScreen);
}
Result UserService::ThrowFatal(u32 error, PidDescriptor pid_desc) {
return g_context.ThrowFatal(error, pid_desc.pid);
Result UserService::ThrowFatal(u32 error, const sf::ClientProcessId &client_pid) {
return g_context.ThrowFatal(error, client_pid.GetValue());
}
Result UserService::ThrowFatalWithPolicy(u32 error, PidDescriptor pid_desc, FatalType policy) {
return g_context.ThrowFatalWithPolicy(error, pid_desc.pid, policy);
Result UserService::ThrowFatalWithPolicy(u32 error, const sf::ClientProcessId &client_pid, FatalType policy) {
return g_context.ThrowFatalWithPolicy(error, client_pid.GetValue(), policy);
}
Result UserService::ThrowFatalWithCpuContext(u32 error, PidDescriptor pid_desc, FatalType policy, InBuffer<u8> _ctx) {
if (_ctx.num_elements < sizeof(CpuContext)) {
return g_context.ThrowFatalWithPolicy(error, pid_desc.pid, policy);
} else {
return g_context.ThrowFatalWithCpuContext(error, pid_desc.pid, policy, *reinterpret_cast<const CpuContext *>(_ctx.buffer));
}
Result UserService::ThrowFatalWithCpuContext(u32 error, const sf::ClientProcessId &client_pid, FatalType policy, const CpuContext &cpu_ctx) {
return g_context.ThrowFatalWithCpuContext(error, client_pid.GetValue(), policy, cpu_ctx);
}
Result PrivateService::GetFatalEvent(Out<CopiedHandle> out_h) {
Result PrivateService::GetFatalEvent(sf::OutCopyHandle out_h) {
return g_context.GetEvent(out_h.GetHandlePointer());
}

View file

@ -20,7 +20,7 @@
namespace sts::fatal::srv {
class UserService final : public IServiceObject {
class UserService final : public sf::IServiceObject {
private:
enum class CommandId {
ThrowFatal = 0,
@ -29,28 +29,28 @@ namespace sts::fatal::srv {
};
private:
/* 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<u8> _ctx);
Result ThrowFatal(u32 error, const sf::ClientProcessId &client_pid);
Result ThrowFatalWithPolicy(u32 error, const sf::ClientProcessId &client_pid, FatalType policy);
Result ThrowFatalWithCpuContext(u32 error, const sf::ClientProcessId &client_pid, FatalType policy, const CpuContext &cpu_ctx);
public:
DEFINE_SERVICE_DISPATCH_TABLE {
MAKE_SERVICE_COMMAND_META(UserService, ThrowFatal),
MAKE_SERVICE_COMMAND_META(UserService, ThrowFatalWithPolicy),
MAKE_SERVICE_COMMAND_META(UserService, ThrowFatalWithCpuContext),
MAKE_SERVICE_COMMAND_META(ThrowFatal),
MAKE_SERVICE_COMMAND_META(ThrowFatalWithPolicy),
MAKE_SERVICE_COMMAND_META(ThrowFatalWithCpuContext),
};
};
class PrivateService final : public IServiceObject {
class PrivateService final : public sf::IServiceObject {
private:
enum class CommandId {
GetFatalEvent = 0,
};
private:
/* Actual commands. */
Result GetFatalEvent(Out<CopiedHandle> out_h);
Result GetFatalEvent(sf::OutCopyHandle out_h);
public:
DEFINE_SERVICE_DISPATCH_TABLE {
MAKE_SERVICE_COMMAND_META(PrivateService, GetFatalEvent),
MAKE_SERVICE_COMMAND_META(GetFatalEvent),
};
};

View file

@ -38,7 +38,7 @@ namespace sts::fatal::srv {
/* Task implementation. */
Result AdjustClockTask::AdjustClockForModule(PcvModule module, u32 hz) {
if (GetRuntimeFirmwareVersion() >= FirmwareVersion_800) {
if (hos::GetVersion() >= hos::Version_800) {
/* On 8.0.0+, convert to module id + use clkrst API. */
PcvModuleId module_id;
R_TRY(pcvGetModuleId(&module_id, module));

View file

@ -15,6 +15,7 @@
*/
#include <atmosphere/version.h>
#include <malloc.h>
#include "fatal_task_screen.hpp"
#include "fatal_config.hpp"
@ -101,7 +102,7 @@ namespace sts::fatal::srv {
ON_SCOPE_EXIT { viCloseDisplay(&temp_display); };
/* Turn on the screen. */
if (GetRuntimeFirmwareVersion() >= FirmwareVersion_300) {
if (hos::GetVersion() >= hos::Version_300) {
R_TRY(viSetDisplayPowerState(&temp_display, ViPowerState_On));
} else {
/* Prior to 3.0.0, the ViPowerState enum was different (0 = Off, 1 = On). */
@ -151,7 +152,7 @@ namespace sts::fatal::srv {
R_TRY(viGetDisplayLogicalResolution(&this->display, &display_width, &display_height));
/* viSetDisplayMagnification was added in 3.0.0. */
if (GetRuntimeFirmwareVersion() >= FirmwareVersion_300) {
if (hos::GetVersion() >= hos::Version_300) {
R_TRY(viSetDisplayMagnification(&this->display, 0, 0, display_width, display_height));
}
@ -414,7 +415,6 @@ namespace sts::fatal::srv {
}
}
/* Enqueue the buffer. */
framebufferEnd(&fb);

View file

@ -19,6 +19,7 @@
#include "../defines.hpp"
#include "../results.hpp"
#include "../ncm/ncm_types.hpp"
#include "../sf/sf_buffer_tags.hpp"
namespace sts::fatal {
@ -293,7 +294,7 @@ namespace sts::fatal {
}
struct CpuContext {
struct CpuContext : sf::LargeData, sf::PrefersMapAliasTransferMode {
enum Architecture {
Architecture_Aarch64 = 0,
Architecture_Aarch32 = 1,