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; return false;
} }
/* HACK: We want to parse the command the fatal caller sent. */ /* 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));
{ {
IpcParsedCommand r; const auto request = hipcParseRequest(thread_tls);
if (R_FAILED(ipcParse(&r))) {
return false; 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. */ /* 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; return false;
} }
struct { if (in_data->header.magic != CMIF_IN_HEADER_MAGIC) {
u32 magic;
u32 version;
u64 cmd_id;
u32 err_code;
} *raw = (decltype(raw))(r.Raw);
if (raw->magic != SFCI_MAGIC) {
return false; return false;
} }
if (raw->cmd_id > 2) { if (in_data->header.version > 1) {
return false; 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; return false;
} }
if (raw->err_code != error_code) { if (in_data->error_code != error_code) {
return false; 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. */ /* Try to debug the process. This may fail, if we called into ourself. */
os::ManagedHandle debug_handle; 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; return;
} }

View file

@ -20,6 +20,6 @@
namespace sts::fatal::srv { 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 <cstdlib>
#include <cstdint> #include <cstdint>
#include <cstring> #include <cstring>
#include <malloc.h>
#include <switch.h> #include <switch.h>
#include <atmosphere.h> #include <atmosphere.h>
@ -32,6 +31,7 @@ extern "C" {
extern u32 __start__; extern u32 __start__;
u32 __nx_applet_type = AppletType_None; u32 __nx_applet_type = AppletType_None;
u32 __nx_fs_num_sessions = 1;
#define INNER_HEAP_SIZE 0x2A0000 #define INNER_HEAP_SIZE 0x2A0000
size_t nx_inner_heap_size = INNER_HEAP_SIZE; size_t nx_inner_heap_size = INNER_HEAP_SIZE;
@ -69,8 +69,10 @@ void __libnx_initheap(void) {
fake_heap_end = (char*)addr + size; fake_heap_end = (char*)addr + size;
} }
using namespace sts;
void __appInit(void) { void __appInit(void) {
SetFirmwareVersionForLibnx(); hos::SetVersionForLibnx();
DoWithSmSession([&]() { DoWithSmSession([&]() {
R_ASSERT(setInitialize()); R_ASSERT(setInitialize());
@ -79,7 +81,7 @@ void __appInit(void) {
R_ASSERT(i2cInitialize()); R_ASSERT(i2cInitialize());
R_ASSERT(bpcInitialize()); R_ASSERT(bpcInitialize());
if (GetRuntimeFirmwareVersion() >= FirmwareVersion_800) { if (hos::GetVersion() >= hos::Version_800) {
R_ASSERT(clkrstInitialize()); R_ASSERT(clkrstInitialize());
} else { } else {
R_ASSERT(pcvInitialize()); R_ASSERT(pcvInitialize());
@ -107,7 +109,7 @@ void __appExit(void) {
spsmExit(); spsmExit();
psmExit(); psmExit();
lblExit(); lblExit();
if (GetRuntimeFirmwareVersion() >= FirmwareVersion_800) { if (hos::GetVersion() >= hos::Version_800) {
clkrstExit(); clkrstExit();
} else { } else {
pcvExit(); pcvExit();
@ -119,26 +121,55 @@ void __appExit(void) {
setExit(); 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) int main(int argc, char **argv)
{ {
/* Load shared font. */ /* 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. */ /* Check whether we should throw fatal due to repair process. */
sts::fatal::srv::CheckRepairStatus(); fatal::srv::CheckRepairStatus();
/* Create waitable manager. */
static auto s_server_manager = WaitableManager(1);
/* Create services. */ /* Create services. */
s_server_manager.AddWaitable(new ServiceServer<sts::fatal::srv::PrivateService>("fatal:p", 4)); R_ASSERT((g_server_manager.RegisterServer<fatal::srv::PrivateService>(PrivateServiceName, PrivateMaxSessions)));
s_server_manager.AddWaitable(new ServiceServer<sts::fatal::srv::UserService>("fatal:u", 4)); R_ASSERT((g_server_manager.RegisterServer<fatal::srv::UserService>(UserServiceName, UserMaxSessions)));
/* Add dirty event holder. */
/* TODO: s_server_manager.AddWaitable(sts::fatal::srv::GetFatalDirtyEvent()); */ /* TODO: s_server_manager.AddWaitable(sts::fatal::srv::GetFatalDirtyEvent()); */
auto dirty_event_holder = sts::fatal::srv::GetFatalDirtyWaitableHolder(); auto *dirty_event_holder = sts::fatal::srv::GetFatalDirtyWaitableHolder();
(void)dirty_event_holder; g_server_manager.AddUserWaitableHolder(dirty_event_holder);
/* Loop forever, servicing our services. */ /* 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; return 0;
} }

View file

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

View file

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

View file

@ -20,7 +20,7 @@
namespace sts::fatal::srv { namespace sts::fatal::srv {
class UserService final : public IServiceObject { class UserService final : public sf::IServiceObject {
private: private:
enum class CommandId { enum class CommandId {
ThrowFatal = 0, ThrowFatal = 0,
@ -29,28 +29,28 @@ namespace sts::fatal::srv {
}; };
private: private:
/* Actual commands. */ /* Actual commands. */
Result ThrowFatal(u32 error, PidDescriptor pid_desc); Result ThrowFatal(u32 error, const sf::ClientProcessId &client_pid);
Result ThrowFatalWithPolicy(u32 error, PidDescriptor pid_desc, FatalType policy); Result ThrowFatalWithPolicy(u32 error, const sf::ClientProcessId &client_pid, FatalType policy);
Result ThrowFatalWithCpuContext(u32 error, PidDescriptor pid_desc, FatalType policy, InBuffer<u8> _ctx); Result ThrowFatalWithCpuContext(u32 error, const sf::ClientProcessId &client_pid, FatalType policy, const CpuContext &cpu_ctx);
public: public:
DEFINE_SERVICE_DISPATCH_TABLE { DEFINE_SERVICE_DISPATCH_TABLE {
MAKE_SERVICE_COMMAND_META(UserService, ThrowFatal), MAKE_SERVICE_COMMAND_META(ThrowFatal),
MAKE_SERVICE_COMMAND_META(UserService, ThrowFatalWithPolicy), MAKE_SERVICE_COMMAND_META(ThrowFatalWithPolicy),
MAKE_SERVICE_COMMAND_META(UserService, ThrowFatalWithCpuContext), MAKE_SERVICE_COMMAND_META(ThrowFatalWithCpuContext),
}; };
}; };
class PrivateService final : public IServiceObject { class PrivateService final : public sf::IServiceObject {
private: private:
enum class CommandId { enum class CommandId {
GetFatalEvent = 0, GetFatalEvent = 0,
}; };
private: private:
/* Actual commands. */ /* Actual commands. */
Result GetFatalEvent(Out<CopiedHandle> out_h); Result GetFatalEvent(sf::OutCopyHandle out_h);
public: public:
DEFINE_SERVICE_DISPATCH_TABLE { 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. */ /* Task implementation. */
Result AdjustClockTask::AdjustClockForModule(PcvModule module, u32 hz) { 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. */ /* On 8.0.0+, convert to module id + use clkrst API. */
PcvModuleId module_id; PcvModuleId module_id;
R_TRY(pcvGetModuleId(&module_id, module)); R_TRY(pcvGetModuleId(&module_id, module));

View file

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

View file

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