mirror of
https://github.com/Atmosphere-NX/Atmosphere.git
synced 2024-11-17 17:36:44 +00:00
fatal: wip (pending libnx pr) update for new sf semantics
This commit is contained in:
parent
ed7c0605f9
commit
402e4d1adb
7 changed files with 191 additions and 28 deletions
|
@ -28,6 +28,31 @@ namespace ams::fatal::srv {
|
|||
u64 lr;
|
||||
};
|
||||
|
||||
constexpr inline size_t MaxThreads = 0x60;
|
||||
|
||||
constinit std::pair<u64, u64> g_thread_id_to_tls_map[MaxThreads];
|
||||
constinit size_t g_tls_map_index = 0;
|
||||
|
||||
void ResetThreadTlsMap() {
|
||||
g_tls_map_index = 0;
|
||||
}
|
||||
|
||||
void SetThreadTls(u64 thread_id, u64 tls) {
|
||||
if (g_tls_map_index < MaxThreads) {
|
||||
g_thread_id_to_tls_map[g_tls_map_index++] = std::make_pair(thread_id, tls);
|
||||
}
|
||||
}
|
||||
|
||||
bool GetThreadTls(u64 *out, u64 thread_id) {
|
||||
for (size_t i = 0; i < g_tls_map_index; ++i) {
|
||||
if (g_thread_id_to_tls_map[i].first == thread_id) {
|
||||
*out = g_thread_id_to_tls_map[i].second;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IsThreadFatalCaller(Result result, u32 debug_handle, u64 thread_id, u64 thread_tls_addr, ThreadContext *thread_ctx) {
|
||||
/* Verify that the thread is running or waiting. */
|
||||
{
|
||||
|
@ -177,7 +202,7 @@ namespace ams::fatal::srv {
|
|||
ON_SCOPE_EXIT { R_ABORT_UNLESS(svc::CloseHandle(debug_handle)); };
|
||||
|
||||
/* First things first, check if process is 64 bits, and get list of thread infos. */
|
||||
std::unordered_map<u64, u64> thread_id_to_tls;
|
||||
ResetThreadTlsMap();
|
||||
{
|
||||
bool got_create_process = false;
|
||||
svc::DebugEventInfo d;
|
||||
|
@ -189,7 +214,7 @@ namespace ams::fatal::srv {
|
|||
got_create_process = true;
|
||||
break;
|
||||
case svc::DebugEvent_CreateThread:
|
||||
thread_id_to_tls[d.info.create_thread.thread_id] = d.info.create_thread.tls_address;
|
||||
SetThreadTls(d.info.create_thread.thread_id, d.info.create_thread.tls_address);
|
||||
break;
|
||||
case svc::DebugEvent_Exception:
|
||||
case svc::DebugEvent_ExitProcess:
|
||||
|
@ -224,13 +249,14 @@ namespace ams::fatal::srv {
|
|||
/* We need to locate the thread that's called fatal. */
|
||||
for (s32 i = 0; i < thread_count; i++) {
|
||||
const u64 cur_thread_id = thread_ids[i];
|
||||
if (thread_id_to_tls.find(cur_thread_id) == thread_id_to_tls.end()) {
|
||||
u64 cur_thread_tls;
|
||||
if (!GetThreadTls(std::addressof(cur_thread_tls), cur_thread_id)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (IsThreadFatalCaller(ctx->result, debug_handle, cur_thread_id, thread_id_to_tls[cur_thread_id], &thread_ctx)) {
|
||||
if (IsThreadFatalCaller(ctx->result, debug_handle, cur_thread_id, cur_thread_tls, &thread_ctx)) {
|
||||
thread_id = cur_thread_id;
|
||||
thread_tls = thread_id_to_tls[thread_id];
|
||||
thread_tls = cur_thread_tls;
|
||||
found_fatal_caller = true;
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -17,12 +17,41 @@
|
|||
#include "fatal_config.hpp"
|
||||
#include "fatal_font.hpp"
|
||||
|
||||
namespace ams::fatal::srv::font {
|
||||
|
||||
constinit lmem::HeapHandle g_font_heap_handle;
|
||||
|
||||
void SetHeapMemory(void *memory, size_t memory_size) {
|
||||
g_font_heap_handle = lmem::CreateExpHeap(memory, memory_size, lmem::CreateOption_None);
|
||||
}
|
||||
|
||||
void *AllocateForFont(size_t size) {
|
||||
return lmem::AllocateFromExpHeap(g_font_heap_handle, size);
|
||||
}
|
||||
|
||||
void DeallocateForFont(void *p) {
|
||||
if (p != nullptr) {
|
||||
return lmem::FreeToExpHeap(g_font_heap_handle, p);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
#define STBTT_assert(x) AMS_ASSERT(x)
|
||||
#define STBTT_malloc(x,u) ((void)(u),ams::fatal::srv::font::AllocateForFont(x))
|
||||
#define STBTT_free(x,u) ((void)(u),ams::fatal::srv::font::DeallocateForFont(x))
|
||||
|
||||
#define STBTT_STATIC
|
||||
#define STB_TRUETYPE_IMPLEMENTATION
|
||||
#include "stb_truetype.h"
|
||||
#undef STBTT_STATIC
|
||||
#undef STB_TRUETYPE_IMPLEMENTATION
|
||||
|
||||
#undef STBTT_malloc
|
||||
#undef STBTT_free
|
||||
#undef STBTT_assert
|
||||
|
||||
/* Define color conversion macros. */
|
||||
#define RGB888_TO_RGB565(r, g, b) ((((r >> 3) << 11) & 0xF800) | (((g >> 2) << 5) & 0x7E0) | ((b >> 3) & 0x1F))
|
||||
#define RGB565_GET_R8(c) ((((c >> 11) & 0x1F) << 3) | ((c >> 13) & 7))
|
||||
|
@ -66,7 +95,7 @@ namespace ams::fatal::srv::font {
|
|||
void DrawCodePoint(u32 codepoint, u32 x, u32 y) {
|
||||
int width = 0, height = 0;
|
||||
u8* imageptr = stbtt_GetCodepointBitmap(&g_stb_font, g_font_size, g_font_size, codepoint, &width, &height, 0, 0);
|
||||
ON_SCOPE_EXIT { std::free(imageptr); };
|
||||
ON_SCOPE_EXIT { DeallocateForFont(imageptr); };
|
||||
|
||||
for (int tmpy = 0; tmpy < height; tmpy++) {
|
||||
for (int tmpx = 0; tmpx < width; tmpx++) {
|
||||
|
|
|
@ -20,6 +20,7 @@ namespace ams::fatal::srv::font {
|
|||
|
||||
Result InitializeSharedFont();
|
||||
void ConfigureFontFramebuffer(u16 *fb, u32 (*unswizzle_func)(u32, u32));
|
||||
void SetHeapMemory(void *memory, size_t memory_size);
|
||||
|
||||
void SetFontColor(u16 color);
|
||||
void SetPosition(u32 x, u32 y);
|
||||
|
|
|
@ -25,7 +25,7 @@ extern "C" {
|
|||
u32 __nx_applet_type = AppletType_None;
|
||||
u32 __nx_fs_num_sessions = 1;
|
||||
|
||||
#define INNER_HEAP_SIZE 0x240000
|
||||
#define INNER_HEAP_SIZE 0x0
|
||||
size_t nx_inner_heap_size = INNER_HEAP_SIZE;
|
||||
char nx_inner_heap[INNER_HEAP_SIZE];
|
||||
|
||||
|
@ -40,6 +40,9 @@ extern "C" {
|
|||
alignas(16) u8 __nx_exception_stack[ams::os::MemoryPageSize];
|
||||
u64 __nx_exception_stack_size = sizeof(__nx_exception_stack);
|
||||
void __libnx_exception_handler(ThreadExceptionDump *ctx);
|
||||
|
||||
void *__libnx_thread_alloc(size_t size);
|
||||
void __libnx_thread_free(void *mem);
|
||||
}
|
||||
|
||||
namespace ams {
|
||||
|
@ -56,6 +59,29 @@ namespace ams {
|
|||
|
||||
using namespace ams;
|
||||
|
||||
namespace ams::fatal {
|
||||
|
||||
namespace {
|
||||
|
||||
constinit u8 g_fs_heap_memory[2_KB];
|
||||
lmem::HeapHandle g_fs_heap_handle;
|
||||
|
||||
void *AllocateForFs(size_t size) {
|
||||
return lmem::AllocateFromExpHeap(g_fs_heap_handle, size);
|
||||
}
|
||||
|
||||
void DeallocateForFs(void *p, size_t size) {
|
||||
return lmem::FreeToExpHeap(g_fs_heap_handle, p);
|
||||
}
|
||||
|
||||
void InitializeFsHeap() {
|
||||
g_fs_heap_handle = lmem::CreateExpHeap(g_fs_heap_memory, sizeof(g_fs_heap_memory), lmem::CreateOption_ThreadSafe);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void __libnx_exception_handler(ThreadExceptionDump *ctx) {
|
||||
ams::CrashHandler(ctx);
|
||||
}
|
||||
|
@ -75,6 +101,9 @@ void __libnx_initheap(void) {
|
|||
void __appInit(void) {
|
||||
hos::InitializeForStratosphere();
|
||||
|
||||
fatal::InitializeFsHeap();
|
||||
fs::SetAllocator(fatal::AllocateForFs, fatal::DeallocateForFs);
|
||||
|
||||
sm::DoWithSession([&]() {
|
||||
R_ABORT_UNLESS(setInitialize());
|
||||
R_ABORT_UNLESS(setsysInitialize());
|
||||
|
@ -137,8 +166,38 @@ namespace {
|
|||
|
||||
sf::hipc::ServerManager<NumServers, ServerOptions, NumSessions> g_server_manager;
|
||||
|
||||
constinit sf::UnmanagedServiceObject<fatal::impl::IService, fatal::srv::Service> g_user_service_object;
|
||||
constinit sf::UnmanagedServiceObject<fatal::impl::IPrivateService, fatal::srv::Service> g_private_service_object;
|
||||
|
||||
}
|
||||
|
||||
namespace ams {
|
||||
|
||||
void *Malloc(size_t size) {
|
||||
AMS_ABORT("ams::Malloc was called");
|
||||
}
|
||||
|
||||
void Free(void *ptr) {
|
||||
AMS_ABORT("ams::Free was called");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void *operator new(size_t size) {
|
||||
AMS_ABORT("operator new(size_t) was called");
|
||||
}
|
||||
|
||||
void operator delete(void *p) {
|
||||
AMS_ABORT("operator delete(void *) was called");
|
||||
}
|
||||
|
||||
void *__libnx_thread_alloc(size_t size) {
|
||||
AMS_ABORT("__libnx_thread_alloc was called");
|
||||
}
|
||||
|
||||
void __libnx_thread_free(void *mem) {
|
||||
AMS_ABORT("__libnx_thread_free was called");
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
|
@ -156,8 +215,8 @@ int main(int argc, char **argv)
|
|||
fatal::srv::CheckRepairStatus();
|
||||
|
||||
/* Create services. */
|
||||
R_ABORT_UNLESS((g_server_manager.RegisterServer<fatal::impl::IPrivateService, fatal::srv::PrivateService>(PrivateServiceName, PrivateMaxSessions)));
|
||||
R_ABORT_UNLESS((g_server_manager.RegisterServer<fatal::impl::IService, fatal::srv::Service>(UserServiceName, UserMaxSessions)));
|
||||
R_ABORT_UNLESS(g_server_manager.RegisterObjectForServer(g_user_service_object.GetShared(), UserServiceName, UserMaxSessions));
|
||||
R_ABORT_UNLESS(g_server_manager.RegisterObjectForServer(g_private_service_object.GetShared(), PrivateServiceName, PrivateMaxSessions));
|
||||
|
||||
/* Add dirty event holder. */
|
||||
auto *dirty_event_holder = ams::fatal::srv::GetFatalDirtyWaitableHolder();
|
||||
|
|
|
@ -145,7 +145,7 @@ namespace ams::fatal::srv {
|
|||
return g_context.ThrowFatalWithCpuContext(result, client_pid.GetValue(), policy, cpu_ctx);
|
||||
}
|
||||
|
||||
Result PrivateService::GetFatalEvent(sf::OutCopyHandle out_h) {
|
||||
Result Service::GetFatalEvent(sf::OutCopyHandle out_h) {
|
||||
const os::SystemEventType *event;
|
||||
R_TRY(g_context.GetEvent(std::addressof(event)));
|
||||
out_h.SetValue(os::GetReadableHandleOfSystemEvent(event));
|
||||
|
|
|
@ -18,19 +18,15 @@
|
|||
|
||||
namespace ams::fatal::srv {
|
||||
|
||||
class Service final {
|
||||
class Service {
|
||||
public:
|
||||
Result ThrowFatal(Result error, const sf::ClientProcessId &client_pid);
|
||||
Result ThrowFatalWithPolicy(Result error, const sf::ClientProcessId &client_pid, FatalPolicy policy);
|
||||
Result ThrowFatalWithCpuContext(Result error, const sf::ClientProcessId &client_pid, FatalPolicy policy, const CpuContext &cpu_ctx);
|
||||
};
|
||||
static_assert(fatal::impl::IsIService<Service>);
|
||||
|
||||
class PrivateService final {
|
||||
public:
|
||||
Result GetFatalEvent(sf::OutCopyHandle out_h);
|
||||
};
|
||||
static_assert(fatal::impl::IsIPrivateService<PrivateService>);
|
||||
static_assert(fatal::impl::IsIService<Service>);
|
||||
static_assert(fatal::impl::IsIPrivateService<Service>);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
namespace ams::fatal::srv {
|
||||
|
||||
/* Include Atmosphere logo into its own anonymous namespace. */
|
||||
|
||||
namespace {
|
||||
|
||||
#include "fatal_ams_logo.inc"
|
||||
|
@ -39,6 +38,44 @@ namespace ams::fatal::srv {
|
|||
constexpr u32 FatalScreenWidthAlignedBytes = (FatalScreenWidth * FatalScreenBpp + 63) & ~63;
|
||||
constexpr u32 FatalScreenWidthAligned = FatalScreenWidthAlignedBytes / FatalScreenBpp;
|
||||
|
||||
/* There should only be a single transfer memory (for nv). */
|
||||
alignas(os::MemoryPageSize) constinit u8 g_nv_transfer_memory[0x40000];
|
||||
|
||||
/* There should only be a single (1280*768) framebuffer. */
|
||||
alignas(os::MemoryPageSize) constinit u8 g_framebuffer_memory[FatalScreenWidthAlignedBytes * util::AlignUp(FatalScreenHeight, 128)];
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extern "C" void *__libnx_tmem_alloc(size_t size) {
|
||||
return ams::fatal::srv::g_nv_transfer_memory;
|
||||
}
|
||||
|
||||
extern "C" void __libnx_tmem_free(void *mem) {
|
||||
/* ... */
|
||||
}
|
||||
|
||||
extern "C" void *__libnx_framebuffer_alloc(size_t size) {
|
||||
return ams::fatal::srv::g_framebuffer_memory;
|
||||
}
|
||||
|
||||
extern "C" void __libnx_framebuffer_free(void *mem) {
|
||||
/* ... */
|
||||
}
|
||||
|
||||
extern "C" void *__libnx_framebuffer_linear_alloc(size_t size) {
|
||||
AMS_ABORT("__libnx_framebuffer_linear_alloc was called");
|
||||
}
|
||||
|
||||
extern "C" void __libnx_framebuffer_linear_free(void *mem) {
|
||||
AMS_ABORT("__libnx_framebuffer_linear_free was called");
|
||||
}
|
||||
|
||||
namespace ams::fatal::srv {
|
||||
|
||||
namespace {
|
||||
|
||||
/* Pixel calculation helper. */
|
||||
constexpr u32 GetPixelOffset(u32 x, u32 y) {
|
||||
u32 tmp_pos = ((y & 127) / 16) + (x/32*8) + ((y/16/8)*(((FatalScreenWidthAligned/2)/16*8)));
|
||||
|
@ -60,6 +97,7 @@ namespace ams::fatal::srv {
|
|||
Result SetupDisplayInternal();
|
||||
Result SetupDisplayExternal();
|
||||
Result PrepareScreenForDrawing();
|
||||
void PreRenderFrameBuffer();
|
||||
Result ShowFatal();
|
||||
public:
|
||||
virtual Result Run() override;
|
||||
|
@ -178,24 +216,22 @@ namespace ams::fatal::srv {
|
|||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result ShowFatalTask::ShowFatal() {
|
||||
void ShowFatalTask::PreRenderFrameBuffer() {
|
||||
const FatalConfig &config = GetFatalConfig();
|
||||
|
||||
/* Prepare screen for drawing. */
|
||||
sm::DoWithSession([&]() {
|
||||
R_ABORT_UNLESS(PrepareScreenForDrawing());
|
||||
});
|
||||
/* Pre-render the image into the static framebuffer. */
|
||||
u16 *tiled_buf = reinterpret_cast<u16 *>(g_framebuffer_memory);
|
||||
|
||||
/* Dequeue a buffer. */
|
||||
u16 *tiled_buf = reinterpret_cast<u16 *>(framebufferBegin(&this->fb, NULL));
|
||||
R_UNLESS(tiled_buf != nullptr, ResultNullGraphicsBuffer());
|
||||
/* Temporarily use the NV transfer memory as font backing heap. */
|
||||
font::SetHeapMemory(g_nv_transfer_memory, sizeof(g_nv_transfer_memory));
|
||||
ON_SCOPE_EXIT { std::memset(g_nv_transfer_memory, 0, sizeof(g_nv_transfer_memory)); };
|
||||
|
||||
/* Let the font manager know about our framebuffer. */
|
||||
font::ConfigureFontFramebuffer(tiled_buf, GetPixelOffset);
|
||||
font::SetFontColor(0xFFFF);
|
||||
|
||||
/* Draw a background. */
|
||||
for (size_t i = 0; i < this->fb.fb_size / sizeof(*tiled_buf); i++) {
|
||||
for (size_t i = 0; i < sizeof(g_framebuffer_memory) / sizeof(*tiled_buf); i++) {
|
||||
tiled_buf[i] = 0x39C9;
|
||||
}
|
||||
|
||||
|
@ -412,6 +448,22 @@ namespace ams::fatal::srv {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Result ShowFatalTask::ShowFatal() {
|
||||
/* Pre-render the framebuffer. */
|
||||
PreRenderFrameBuffer();
|
||||
|
||||
/* Prepare screen for drawing. */
|
||||
sm::DoWithSession([&]() {
|
||||
R_ABORT_UNLESS(PrepareScreenForDrawing());
|
||||
});
|
||||
|
||||
/* Dequeue a buffer. */
|
||||
R_UNLESS(framebufferBegin(&this->fb, NULL) != nullptr, ResultNullGraphicsBuffer());
|
||||
|
||||
/* We've already pre-rendered the frame into the static buffer. */
|
||||
/* ... */
|
||||
|
||||
/* Enqueue the buffer. */
|
||||
framebufferEnd(&fb);
|
||||
|
|
Loading…
Reference in a new issue