fatal: wip (pending libnx pr) update for new sf semantics

This commit is contained in:
Michael Scire 2021-01-18 08:48:47 -08:00
parent a63b97fbbd
commit ea9d360b14
7 changed files with 191 additions and 28 deletions

View file

@ -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)) {
thread_id = cur_thread_id;
thread_tls = thread_id_to_tls[thread_id];
if (IsThreadFatalCaller(ctx->result, debug_handle, cur_thread_id, cur_thread_tls, &thread_ctx)) {
thread_id = cur_thread_id;
thread_tls = cur_thread_tls;
found_fatal_caller = true;
break;
}

View file

@ -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++) {

View file

@ -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);

View file

@ -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();

View file

@ -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));

View file

@ -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>);
}

View file

@ -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);