diff --git a/stratosphere/fatal/source/fatal_debug.cpp b/stratosphere/fatal/source/fatal_debug.cpp index ee5f03e98..25b74135a 100644 --- a/stratosphere/fatal/source/fatal_debug.cpp +++ b/stratosphere/fatal/source/fatal_debug.cpp @@ -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) { - return false; + 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(process_id)))) { return; } diff --git a/stratosphere/fatal/source/fatal_debug.hpp b/stratosphere/fatal/source/fatal_debug.hpp index 5caedc55f..e08aac274 100644 --- a/stratosphere/fatal/source/fatal_debug.hpp +++ b/stratosphere/fatal/source/fatal_debug.hpp @@ -20,6 +20,6 @@ namespace sts::fatal::srv { - void TryCollectDebugInformation(ThrowContext *ctx, u64 process_id); + void TryCollectDebugInformation(ThrowContext *ctx, os::ProcessId process_id); } diff --git a/stratosphere/fatal/source/fatal_main.cpp b/stratosphere/fatal/source/fatal_main.cpp index cc80c4599..974a36b4f 100644 --- a/stratosphere/fatal/source/fatal_main.cpp +++ b/stratosphere/fatal/source/fatal_main.cpp @@ -17,7 +17,6 @@ #include #include #include -#include #include #include @@ -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 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("fatal:p", 4)); - s_server_manager.AddWaitable(new ServiceServer("fatal:u", 4)); + R_ASSERT((g_server_manager.RegisterServer(PrivateServiceName, PrivateMaxSessions))); + R_ASSERT((g_server_manager.RegisterServer(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; } diff --git a/stratosphere/fatal/source/fatal_repair.cpp b/stratosphere/fatal/source/fatal_repair.cpp index efe47850f..d3a4edbdc 100644 --- a/stratosphere/fatal/source/fatal_repair.cpp +++ b/stratosphere/fatal/source/fatal_repair.cpp @@ -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; } diff --git a/stratosphere/fatal/source/fatal_service.cpp b/stratosphere/fatal/source/fatal_service.cpp index 45fa9a631..af80725e6 100644 --- a/stratosphere/fatal/source/fatal_service.cpp +++ b/stratosphere/fatal/source/fatal_service.cpp @@ -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(error_code), process_id, FatalType_ErrorScreen); + return g_context.ThrowFatalWithPolicy(static_cast(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 _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(_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 out_h) { + Result PrivateService::GetFatalEvent(sf::OutCopyHandle out_h) { return g_context.GetEvent(out_h.GetHandlePointer()); } diff --git a/stratosphere/fatal/source/fatal_service.hpp b/stratosphere/fatal/source/fatal_service.hpp index 9de9012ea..a57149993 100644 --- a/stratosphere/fatal/source/fatal_service.hpp +++ b/stratosphere/fatal/source/fatal_service.hpp @@ -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 _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 out_h); + Result GetFatalEvent(sf::OutCopyHandle out_h); public: DEFINE_SERVICE_DISPATCH_TABLE { - MAKE_SERVICE_COMMAND_META(PrivateService, GetFatalEvent), + MAKE_SERVICE_COMMAND_META(GetFatalEvent), }; }; diff --git a/stratosphere/fatal/source/fatal_task_clock.cpp b/stratosphere/fatal/source/fatal_task_clock.cpp index 4cf880145..674e5ebde 100644 --- a/stratosphere/fatal/source/fatal_task_clock.cpp +++ b/stratosphere/fatal/source/fatal_task_clock.cpp @@ -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)); diff --git a/stratosphere/fatal/source/fatal_task_screen.cpp b/stratosphere/fatal/source/fatal_task_screen.cpp index 7ad948d06..187d1832b 100644 --- a/stratosphere/fatal/source/fatal_task_screen.cpp +++ b/stratosphere/fatal/source/fatal_task_screen.cpp @@ -15,6 +15,7 @@ */ #include +#include #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); diff --git a/stratosphere/libstratosphere/include/stratosphere/fatal/fatal_types.hpp b/stratosphere/libstratosphere/include/stratosphere/fatal/fatal_types.hpp index b0fe391d6..2a6b19a56 100644 --- a/stratosphere/libstratosphere/include/stratosphere/fatal/fatal_types.hpp +++ b/stratosphere/libstratosphere/include/stratosphere/fatal/fatal_types.hpp @@ -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,