fatal: dynamically allocate memory as required (preferring system > nonsecure > unsafe)

This commit is contained in:
Michael Scire 2023-03-01 03:20:42 -07:00
parent 982389dceb
commit 5fb6f52b9e
2 changed files with 56 additions and 8 deletions

View file

@ -78,6 +78,9 @@
"svcReplyAndReceive": "0x43",
"svcReplyAndReceiveWithUserBuffer": "0x44",
"svcCreateEvent": "0x45",
"svcMapPhysicalMemoryUnsafe": "0x48",
"svcUnmapPhysicalMemoryUnsafe": "0x48",
"svcSetUnsafeLimit": "0x4A",
"svcReadWriteRegister": "0x4E",
"svcDebugActiveProcess": "0x60",
"svcGetDebugEvent": "0x63",
@ -86,7 +89,9 @@
"svcQueryDebugProcessMemory": "0x69",
"svcReadDebugProcessMemory": "0x6a",
"svcGetDebugThreadParam": "0x6d",
"svcCallSecureMonitor": "0x7f"
"svcCallSecureMonitor": "0x7f",
"svcMapInsecureMemory": "0x90",
"svcUnmapInsecureMemory": "0x91"
}
}, {
"type": "min_kernel_version",

View file

@ -42,7 +42,46 @@ namespace ams::fatal::srv {
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)];
constexpr size_t FrameBufferRequiredSizeBytes = FatalScreenWidthAlignedBytes * util::AlignUp(FatalScreenHeight, 128);
constexpr size_t FrameBufferRequiredSizePageAligned = util::AlignUp(FrameBufferRequiredSizeBytes, os::MemoryPageSize);
constexpr size_t FrameBufferRequiredSizeHeapAligned = util::AlignUp(FrameBufferRequiredSizeBytes, os::MemoryHeapUnitSize);
constinit u8 *g_framebuffer_pointer = nullptr;
void InitializeFrameBufferPointer() {
/* Try to get a framebuffer from heap. */
{
if (R_SUCCEEDED(os::SetMemoryHeapSize(FrameBufferRequiredSizeHeapAligned))) {
g_framebuffer_pointer = reinterpret_cast<u8 *>(os::GetMemoryHeapAddress());
return;
}
}
/* We couldn't use heap, so try insecure memory, from the application pool. */
{
uintptr_t address = 0;
if (R_SUCCEEDED(os::AllocateInsecureMemory(std::addressof(address), FrameBufferRequiredSizePageAligned))) {
g_framebuffer_pointer = reinterpret_cast<u8 *>(address);
return;
}
}
/* Neither heap nor insecure is available, so we're going to have to try to raid the unsafe pool. */
{
/* First, increase the limit to an extremely high value. */
size_t large_size = std::max(64_MB, FrameBufferRequiredSizeHeapAligned);
while (svc::ResultLimitReached::Includes(svc::SetUnsafeLimit(large_size))) {
large_size *= 2;
}
/* Next, map some unsafe memory. */
uintptr_t address = 0;
if (R_SUCCEEDED(os::AllocateUnsafeMemory(std::addressof(address), FrameBufferRequiredSizePageAligned))) {
g_framebuffer_pointer = reinterpret_cast<u8 *>(address);
return;
}
}
}
}
@ -202,8 +241,12 @@ namespace ams::fatal::srv {
void ShowFatalTask::PreRenderFrameBuffer() {
const FatalConfig &config = GetFatalConfig();
/* Allocate a frame buffer. */
InitializeFrameBufferPointer();
AMS_ABORT_UNLESS(g_framebuffer_pointer != nullptr);
/* Pre-render the image into the static framebuffer. */
u16 *tiled_buf = reinterpret_cast<u16 *>(g_framebuffer_memory);
u16 *tiled_buf = reinterpret_cast<u16 *>(g_framebuffer_pointer);
/* Temporarily use the NV transfer memory as font backing heap. */
font::SetHeapMemory(g_nv_transfer_memory, sizeof(g_nv_transfer_memory));
@ -214,7 +257,7 @@ namespace ams::fatal::srv {
font::SetFontColor(0xFFFF);
/* Draw a background. */
for (size_t i = 0; i < sizeof(g_framebuffer_memory) / sizeof(*tiled_buf); i++) {
for (size_t i = 0; i < FrameBufferRequiredSizeBytes / sizeof(*tiled_buf); i++) {
tiled_buf[i] = 0x39C9;
}
@ -439,7 +482,7 @@ namespace ams::fatal::srv {
R_TRY(nvFenceInit());
/* Create nvmap. */
R_TRY(nvMapCreate(std::addressof(m_map), g_framebuffer_memory, sizeof(g_framebuffer_memory), 0x20000, NvKind_Pitch, true));
R_TRY(nvMapCreate(std::addressof(m_map), g_framebuffer_pointer, FrameBufferRequiredSizeBytes, 0x20000, NvKind_Pitch, true));
/* Setup graphics buffer. */
{
@ -460,9 +503,9 @@ namespace ams::fatal::srv {
grbuf.planes[0].block_height_log2 = 4;
grbuf.nvmap_id = nvMapGetId(std::addressof(m_map));
grbuf.stride = FatalScreenWidthAligned;
grbuf.total_size = sizeof(g_framebuffer_memory);
grbuf.total_size = FrameBufferRequiredSizeBytes;
grbuf.planes[0].pitch = FatalScreenWidthAlignedBytes;
grbuf.planes[0].size = sizeof(g_framebuffer_memory);
grbuf.planes[0].size = FrameBufferRequiredSizeBytes;
grbuf.planes[0].offset = 0;
R_TRY(nwindowConfigureBuffer(std::addressof(m_win), 0, std::addressof(grbuf)));
@ -474,7 +517,7 @@ namespace ams::fatal::srv {
void ShowFatalTask::DisplayPreRenderedFrame() {
s32 slot;
R_ABORT_UNLESS(nwindowDequeueBuffer(std::addressof(m_win), std::addressof(slot), nullptr));
dd::FlushDataCache(g_framebuffer_memory, sizeof(g_framebuffer_memory));
dd::FlushDataCache(g_framebuffer_pointer, FrameBufferRequiredSizeBytes);
R_ABORT_UNLESS(nwindowQueueBuffer(std::addressof(m_win), m_win.cur_slot, NULL));
}