2018-11-10 11:16:13 +00:00
/*
2021-10-04 20:59:10 +01:00
* Copyright ( c ) Atmosphère - NX
2018-11-10 11:16:13 +00:00
*
* This program is free software ; you can redistribute it and / or modify it
* under the terms and conditions of the GNU General Public License ,
* version 2 , as published by the Free Software Foundation .
*
* This program is distributed in the hope it will be useful , but WITHOUT
* ANY WARRANTY ; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE . See the GNU General Public License for
* more details .
*
* You should have received a copy of the GNU General Public License
* along with this program . If not , see < http : //www.gnu.org/licenses/>.
*/
2020-05-11 23:02:10 +01:00
# include <stratosphere.hpp>
2018-11-10 11:16:13 +00:00
# include "fatal_task_screen.hpp"
2018-11-10 20:38:24 +00:00
# include "fatal_config.hpp"
2018-11-13 14:03:30 +00:00
# include "fatal_font.hpp"
2019-10-24 10:30:10 +01:00
namespace ams : : fatal : : srv {
2018-11-13 14:03:30 +00:00
2019-07-19 03:09:35 +01:00
/* Include Atmosphere logo into its own anonymous namespace. */
namespace {
2018-11-13 14:03:30 +00:00
2019-07-19 03:09:35 +01:00
# include "fatal_ams_logo.inc"
2018-11-13 14:03:30 +00:00
2019-07-19 03:09:35 +01:00
}
2018-11-13 14:03:30 +00:00
2019-07-19 03:09:35 +01:00
namespace {
2018-11-10 11:16:13 +00:00
2019-07-19 03:09:35 +01:00
/* Screen definitions. */
constexpr u32 FatalScreenWidth = 1280 ;
constexpr u32 FatalScreenHeight = 720 ;
constexpr u32 FatalScreenBpp = 2 ;
constexpr u32 FatalLayerZ = 100 ;
2021-10-11 20:41:43 +01:00
constexpr u32 FatalScreenWidthAlignedBytes = util : : AlignUp ( FatalScreenWidth * FatalScreenBpp , 64 ) ;
2019-07-19 03:09:35 +01:00
constexpr u32 FatalScreenWidthAligned = FatalScreenWidthAlignedBytes / FatalScreenBpp ;
2021-01-18 16:48:47 +00:00
/* 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. */
2023-03-01 10:20:42 +00:00
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 ;
}
}
2023-03-01 10:21:51 +00:00
/* We couldn't use heap, so try insecure memory, from the system nonsecure pool. */
2023-03-01 10:20:42 +00:00
{
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 ;
}
}
}
2021-01-18 16:48:47 +00:00
}
}
2021-01-19 00:54:55 +00:00
extern " C " : : Result __nx_nv_create_tmem ( TransferMemory * t , u32 * out_size , Permission perm ) {
* out_size = sizeof ( ams : : fatal : : srv : : g_nv_transfer_memory ) ;
return tmemCreateFromMemory ( t , ams : : fatal : : srv : : g_nv_transfer_memory , sizeof ( ams : : fatal : : srv : : g_nv_transfer_memory ) , perm ) ;
2021-01-18 16:48:47 +00:00
}
namespace ams : : fatal : : srv {
namespace {
2019-07-19 03:09:35 +01:00
/* 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 ) ) ) ;
tmp_pos * = 16 * 16 * 4 ;
tmp_pos + = ( ( y % 16 ) / 8 ) * 512 + ( ( x % 32 ) / 16 ) * 256 + ( ( y % 8 ) / 2 ) * 64 + ( ( x % 16 ) / 8 ) * 32 + ( y % 2 ) * 16 + ( x % 8 ) * 2 ; //This line is a modified version of code from the Tegra X1 datasheet.
return tmp_pos / 2 ;
2018-11-13 06:26:13 +00:00
}
2019-06-18 00:41:03 +01:00
2019-07-19 03:09:35 +01:00
/* Task definitions. */
2019-10-19 04:31:15 +01:00
class ShowFatalTask : public ITaskWithStack < 0x8000 > {
2019-07-19 03:09:35 +01:00
private :
2021-10-10 08:14:06 +01:00
ViDisplay m_display ;
ViLayer m_layer ;
NWindow m_win ;
NvMap m_map ;
2019-07-19 03:09:35 +01:00
private :
Result SetupDisplayInternal ( ) ;
Result SetupDisplayExternal ( ) ;
Result PrepareScreenForDrawing ( ) ;
2021-01-18 16:48:47 +00:00
void PreRenderFrameBuffer ( ) ;
2021-01-19 00:54:55 +00:00
Result InitializeNativeWindow ( ) ;
void DisplayPreRenderedFrame ( ) ;
2019-07-19 03:09:35 +01:00
Result ShowFatal ( ) ;
public :
virtual Result Run ( ) override ;
virtual const char * GetName ( ) const override {
return " ShowFatal " ;
}
} ;
2019-10-19 04:31:15 +01:00
class BacklightControlTask : public ITaskWithDefaultStack {
2019-07-19 03:09:35 +01:00
private :
void TurnOnBacklight ( ) ;
public :
virtual Result Run ( ) override ;
virtual const char * GetName ( ) const override {
return " BacklightControlTask " ;
}
} ;
/* Task globals. */
ShowFatalTask g_show_fatal_task ;
BacklightControlTask g_backlight_control_task ;
/* Task implementations. */
Result ShowFatalTask : : SetupDisplayInternal ( ) {
ViDisplay temp_display ;
/* Try to open the display. */
2021-10-09 22:49:53 +01:00
R_TRY_CATCH ( viOpenDisplay ( " Internal " , std : : addressof ( temp_display ) ) ) {
2019-10-24 09:40:44 +01:00
R_CONVERT ( vi : : ResultNotFound , ResultSuccess ( ) ) ;
2019-07-19 03:09:35 +01:00
} R_END_TRY_CATCH ;
2019-04-22 20:40:53 +01:00
2019-07-19 03:09:35 +01:00
/* Guarantee we close the display. */
2021-10-09 22:49:53 +01:00
ON_SCOPE_EXIT { viCloseDisplay ( std : : addressof ( temp_display ) ) ; } ;
2019-04-22 20:40:53 +01:00
2019-07-19 03:09:35 +01:00
/* Turn on the screen. */
2020-04-14 06:19:44 +01:00
if ( hos : : GetVersion ( ) > = hos : : Version_3_0_0 ) {
2021-10-09 22:49:53 +01:00
R_TRY ( viSetDisplayPowerState ( std : : addressof ( temp_display ) , ViPowerState_On ) ) ;
2019-08-06 02:55:04 +01:00
} else {
/* Prior to 3.0.0, the ViPowerState enum was different (0 = Off, 1 = On). */
2021-10-09 22:49:53 +01:00
R_TRY ( viSetDisplayPowerState ( std : : addressof ( temp_display ) , ViPowerState_On_Deprecated ) ) ;
2019-08-06 02:55:04 +01:00
}
2019-04-22 20:40:53 +01:00
2019-07-19 03:09:35 +01:00
/* Set alpha to 1.0f. */
2021-10-09 22:49:53 +01:00
R_TRY ( viSetDisplayAlpha ( std : : addressof ( temp_display ) , 1.0f ) ) ;
2018-11-13 06:26:13 +00:00
2022-03-26 07:14:36 +00:00
R_SUCCEED ( ) ;
2018-11-13 06:26:13 +00:00
}
2019-06-18 00:41:03 +01:00
2019-07-19 03:09:35 +01:00
Result ShowFatalTask : : SetupDisplayExternal ( ) {
ViDisplay temp_display ;
/* Try to open the display. */
2021-10-09 22:49:53 +01:00
R_TRY_CATCH ( viOpenDisplay ( " External " , std : : addressof ( temp_display ) ) ) {
2019-10-24 09:40:44 +01:00
R_CONVERT ( vi : : ResultNotFound , ResultSuccess ( ) ) ;
2019-07-19 03:09:35 +01:00
} R_END_TRY_CATCH ;
2019-04-22 20:40:53 +01:00
2019-07-19 03:09:35 +01:00
/* Guarantee we close the display. */
2021-10-09 22:49:53 +01:00
ON_SCOPE_EXIT { viCloseDisplay ( std : : addressof ( temp_display ) ) ; } ;
2019-04-22 20:40:53 +01:00
2019-07-19 03:09:35 +01:00
/* Set alpha to 1.0f. */
2021-10-09 22:49:53 +01:00
R_TRY ( viSetDisplayAlpha ( std : : addressof ( temp_display ) , 1.0f ) ) ;
2018-11-13 06:26:13 +00:00
2022-03-26 07:14:36 +00:00
R_SUCCEED ( ) ;
2019-07-19 03:09:35 +01:00
}
2019-04-22 20:40:53 +01:00
2019-07-19 03:09:35 +01:00
Result ShowFatalTask : : PrepareScreenForDrawing ( ) {
/* Connect to vi. */
R_TRY ( viInitialize ( ViServiceType_Manager ) ) ;
2019-04-22 20:40:53 +01:00
2019-07-19 03:09:35 +01:00
/* Close other content. */
viSetContentVisibility ( false ) ;
2019-04-22 20:40:53 +01:00
2019-07-19 03:09:35 +01:00
/* Setup the two displays. */
R_TRY ( SetupDisplayInternal ( ) ) ;
R_TRY ( SetupDisplayExternal ( ) ) ;
2019-04-22 20:40:53 +01:00
2019-07-19 03:09:35 +01:00
/* Open the default display. */
2021-10-10 08:14:06 +01:00
R_TRY ( viOpenDefaultDisplay ( std : : addressof ( m_display ) ) ) ;
2019-04-22 20:40:53 +01:00
2019-07-19 03:09:35 +01:00
/* Reset the display magnification to its default value. */
2019-10-27 22:57:30 +00:00
s32 display_width , display_height ;
2021-10-10 08:14:06 +01:00
R_TRY ( viGetDisplayLogicalResolution ( std : : addressof ( m_display ) , std : : addressof ( display_width ) , std : : addressof ( display_height ) ) ) ;
2019-04-22 20:40:53 +01:00
2019-07-19 03:09:35 +01:00
/* viSetDisplayMagnification was added in 3.0.0. */
2020-04-14 06:19:44 +01:00
if ( hos : : GetVersion ( ) > = hos : : Version_3_0_0 ) {
2021-10-10 08:14:06 +01:00
R_TRY ( viSetDisplayMagnification ( std : : addressof ( m_display ) , 0 , 0 , display_width , display_height ) ) ;
2019-07-19 03:09:35 +01:00
}
2019-04-22 20:40:53 +01:00
2019-07-19 03:09:35 +01:00
/* Create layer to draw to. */
2021-10-10 08:14:06 +01:00
R_TRY ( viCreateLayer ( std : : addressof ( m_display ) , std : : addressof ( m_layer ) ) ) ;
2019-04-22 20:40:53 +01:00
2019-07-19 03:09:35 +01:00
/* Setup the layer. */
{
/* Display a layer of 1280 x 720 at 1.5x magnification */
/* NOTE: N uses 2 (770x400) RGBA4444 buffers (tiled buffer + linear). */
/* We use a single 1280x720 tiled RGB565 buffer. */
2021-01-19 00:54:55 +00:00
constexpr s32 RawWidth = FatalScreenWidth ;
constexpr s32 RawHeight = FatalScreenHeight ;
constexpr s32 LayerWidth = ( ( RawWidth ) * 3 ) / 2 ;
constexpr s32 LayerHeight = ( ( RawHeight ) * 3 ) / 2 ;
2019-04-22 20:40:53 +01:00
2021-01-19 00:54:55 +00:00
const float layer_x = static_cast < float > ( ( display_width - LayerWidth ) / 2 ) ;
const float layer_y = static_cast < float > ( ( display_height - LayerHeight ) / 2 ) ;
2018-11-10 19:59:55 +00:00
2021-10-10 08:14:06 +01:00
R_TRY ( viSetLayerSize ( std : : addressof ( m_layer ) , LayerWidth , LayerHeight ) ) ;
2018-11-10 19:59:55 +00:00
2019-07-19 03:09:35 +01:00
/* Set the layer's Z at display maximum, to be above everything else .*/
2021-10-10 08:14:06 +01:00
R_TRY ( viSetLayerZ ( std : : addressof ( m_layer ) , FatalLayerZ ) ) ;
2019-04-22 20:40:53 +01:00
2019-07-19 03:09:35 +01:00
/* Center the layer in the screen. */
2021-10-10 08:14:06 +01:00
R_TRY ( viSetLayerPosition ( std : : addressof ( m_layer ) , layer_x , layer_y ) ) ;
2019-04-22 20:40:53 +01:00
2019-07-19 03:09:35 +01:00
/* Create framebuffer. */
2021-10-10 08:14:06 +01:00
R_TRY ( nwindowCreateFromLayer ( std : : addressof ( m_win ) , std : : addressof ( m_layer ) ) ) ;
2021-01-19 00:54:55 +00:00
R_TRY ( this - > InitializeNativeWindow ( ) ) ;
2019-07-19 03:09:35 +01:00
}
2019-04-22 20:40:53 +01:00
2022-03-26 07:14:36 +00:00
R_SUCCEED ( ) ;
2018-11-13 14:03:30 +00:00
}
2019-04-22 20:40:53 +01:00
2021-01-18 16:48:47 +00:00
void ShowFatalTask : : PreRenderFrameBuffer ( ) {
2019-07-19 03:09:35 +01:00
const FatalConfig & config = GetFatalConfig ( ) ;
2019-04-22 20:40:53 +01:00
2023-03-01 10:20:42 +00:00
/* Allocate a frame buffer. */
InitializeFrameBufferPointer ( ) ;
AMS_ABORT_UNLESS ( g_framebuffer_pointer ! = nullptr ) ;
2021-01-18 16:48:47 +00:00
/* Pre-render the image into the static framebuffer. */
2023-03-01 10:20:42 +00:00
u16 * tiled_buf = reinterpret_cast < u16 * > ( g_framebuffer_pointer ) ;
2019-04-22 20:40:53 +01:00
2021-01-18 16:48:47 +00:00
/* 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 ) ) ; } ;
2019-04-22 20:40:53 +01:00
2019-07-19 03:09:35 +01:00
/* Let the font manager know about our framebuffer. */
font : : ConfigureFontFramebuffer ( tiled_buf , GetPixelOffset ) ;
font : : SetFontColor ( 0xFFFF ) ;
2019-04-22 20:40:53 +01:00
2019-07-19 03:09:35 +01:00
/* Draw a background. */
2023-03-01 10:20:42 +00:00
for ( size_t i = 0 ; i < FrameBufferRequiredSizeBytes / sizeof ( * tiled_buf ) ; i + + ) {
2019-07-19 03:09:35 +01:00
tiled_buf [ i ] = 0x39C9 ;
2018-11-14 11:23:28 +00:00
}
2018-11-14 01:53:26 +00:00
2020-01-04 06:35:11 +00:00
/* Draw the atmosphere logo in the upper right corner. */
const u32 start_x = 32 , start_y = 64 ;
2019-07-19 03:09:35 +01:00
for ( size_t y = 0 ; y < AtmosphereLogoHeight ; y + + ) {
for ( size_t x = 0 ; x < AtmosphereLogoWidth ; x + + ) {
2020-01-04 06:35:11 +00:00
tiled_buf [ GetPixelOffset ( FatalScreenWidth - AtmosphereLogoWidth - start_x + x , start_x + y ) ] = AtmosphereLogoData [ y * AtmosphereLogoWidth + x ] ;
2019-07-19 03:09:35 +01:00
}
2018-11-14 03:30:40 +00:00
}
2019-04-22 20:40:53 +01:00
2020-01-04 06:35:11 +00:00
/* Draw error message and firmware. */
font : : SetPosition ( start_x , start_y ) ;
2019-07-19 03:09:35 +01:00
font : : SetFontSize ( 16.0f ) ;
2021-10-10 08:14:06 +01:00
font : : PrintFormat ( config . GetErrorMessage ( ) , m_context - > result . GetModule ( ) , m_context - > result . GetDescription ( ) , m_context - > result . GetValue ( ) ) ;
2019-07-19 03:09:35 +01:00
font : : AddSpacingLines ( 0.5f ) ;
2021-10-10 08:14:06 +01:00
font : : PrintFormatLine ( " Program: %016lX " , static_cast < u64 > ( m_context - > program_id ) ) ;
2019-07-19 03:09:35 +01:00
font : : AddSpacingLines ( 0.5f ) ;
2020-09-18 05:18:44 +01:00
2021-09-05 18:08:30 +01:00
font : : PrintFormatLine ( " Firmware: %s (Atmosphère %u.%u.%u-%s) " , config . GetFirmwareVersion ( ) . display_version , ATMOSPHERE_RELEASE_VERSION , ams : : GetGitRevision ( ) ) ;
2019-07-19 03:09:35 +01:00
font : : AddSpacingLines ( 1.5f ) ;
2021-10-10 08:14:06 +01:00
if ( ! exosphere : : ResultVersionMismatch : : Includes ( m_context - > result ) ) {
2019-07-19 03:09:35 +01:00
font : : Print ( config . GetErrorDescription ( ) ) ;
2018-11-14 11:23:28 +00:00
} else {
2019-07-19 03:09:35 +01:00
/* Print a special message for atmosphere version mismatch. */
2020-05-11 23:02:10 +01:00
font : : Print ( " Atmosphère version mismatch detected. \n \n "
" Please press the POWER Button to restart the console normally, or a VOL button \n "
" to reboot to a payload (or RCM, if none is present). If you are unable to \n "
" restart the console, hold the POWER Button for 12 seconds to turn the console off. \n \n "
" Please ensure that all Atmosphère components are updated. \n "
" github.com/Atmosphere-NX/Atmosphere/releases \n " ) ;
2018-11-14 11:23:28 +00:00
}
2018-11-14 01:53:26 +00:00
2019-07-19 03:09:35 +01:00
/* Add a line. */
2020-01-04 06:35:11 +00:00
for ( size_t x = start_x ; x < FatalScreenWidth - start_x ; x + + ) {
2019-07-19 03:09:35 +01:00
tiled_buf [ GetPixelOffset ( x , font : : GetY ( ) ) ] = 0xFFFF ;
2018-11-14 01:53:26 +00:00
}
2019-04-22 20:40:53 +01:00
2019-07-19 03:09:35 +01:00
font : : AddSpacingLines ( 1.5f ) ;
2019-04-22 20:40:53 +01:00
2019-07-19 03:09:35 +01:00
u32 backtrace_y = font : : GetY ( ) ;
u32 backtrace_x = 0 ;
2020-01-04 06:35:11 +00:00
u32 pc_x = 0 ;
2019-04-22 20:40:53 +01:00
2019-07-19 03:09:35 +01:00
/* Note architecutre. */
2021-10-10 08:14:06 +01:00
const bool is_aarch32 = m_context - > cpu_ctx . architecture = = CpuContext : : Architecture_Aarch32 ;
2019-04-22 20:40:53 +01:00
2019-07-19 03:09:35 +01:00
/* Print GPRs. */
font : : SetFontSize ( 14.0f ) ;
font : : Print ( " General Purpose Registers " ) ;
font : : PrintLine ( " " ) ;
2020-01-04 06:35:11 +00:00
font : : SetPosition ( start_x , font : : GetY ( ) ) ;
2019-07-19 03:09:35 +01:00
font : : AddSpacingLines ( 0.5f ) ;
if ( is_aarch32 ) {
for ( size_t i = 0 ; i < ( aarch32 : : RegisterName_GeneralPurposeCount / 2 ) ; i + + ) {
u32 x = font : : GetX ( ) ;
font : : PrintFormat ( " %s: " , aarch32 : : CpuContext : : RegisterNameStrings [ i ] ) ;
font : : SetPosition ( x + 47 , font : : GetY ( ) ) ;
2021-10-10 08:14:06 +01:00
if ( m_context - > cpu_ctx . aarch32_ctx . HasRegisterValue ( static_cast < aarch32 : : RegisterName > ( i ) ) ) {
font : : PrintMonospaceU32 ( m_context - > cpu_ctx . aarch32_ctx . r [ i ] ) ;
2019-07-19 03:09:35 +01:00
font : : PrintMonospaceBlank ( 8 ) ;
2020-01-04 04:21:12 +00:00
} else {
font : : PrintMonospaceBlank ( 16 ) ;
2019-07-19 03:09:35 +01:00
}
font : : Print ( " " ) ;
2020-01-04 06:35:11 +00:00
pc_x = font : : GetX ( ) ;
2019-07-19 03:09:35 +01:00
font : : PrintFormat ( " %s: " , aarch32 : : CpuContext : : RegisterNameStrings [ i + ( aarch32 : : RegisterName_GeneralPurposeCount / 2 ) ] ) ;
2020-01-04 06:35:11 +00:00
font : : SetPosition ( pc_x + 47 , font : : GetY ( ) ) ;
2021-10-10 08:14:06 +01:00
if ( m_context - > cpu_ctx . aarch32_ctx . HasRegisterValue ( static_cast < aarch32 : : RegisterName > ( i + ( aarch32 : : RegisterName_GeneralPurposeCount / 2 ) ) ) ) {
font : : PrintMonospaceU32 ( m_context - > cpu_ctx . aarch32_ctx . r [ i + ( aarch32 : : RegisterName_GeneralPurposeCount / 2 ) ] ) ;
2019-07-19 03:09:35 +01:00
font : : PrintMonospaceBlank ( 8 ) ;
2020-01-04 04:21:12 +00:00
} else {
font : : PrintMonospaceBlank ( 16 ) ;
2019-07-19 03:09:35 +01:00
}
if ( i = = ( aarch32 : : RegisterName_GeneralPurposeCount / 2 ) - 1 ) {
font : : Print ( " " ) ;
backtrace_x = font : : GetX ( ) ;
}
font : : PrintLine ( " " ) ;
2020-01-04 06:35:11 +00:00
font : : SetPosition ( start_x , font : : GetY ( ) ) ;
2018-11-14 02:11:08 +00:00
}
2019-07-19 03:09:35 +01:00
} else {
for ( size_t i = 0 ; i < aarch64 : : RegisterName_GeneralPurposeCount / 2 ; i + + ) {
u32 x = font : : GetX ( ) ;
font : : PrintFormat ( " %s: " , aarch64 : : CpuContext : : RegisterNameStrings [ i ] ) ;
font : : SetPosition ( x + 47 , font : : GetY ( ) ) ;
2021-10-10 08:14:06 +01:00
if ( m_context - > cpu_ctx . aarch64_ctx . HasRegisterValue ( static_cast < aarch64 : : RegisterName > ( i ) ) ) {
font : : PrintMonospaceU64 ( m_context - > cpu_ctx . aarch64_ctx . x [ i ] ) ;
2019-07-19 03:09:35 +01:00
} else {
font : : PrintMonospaceBlank ( 16 ) ;
}
font : : Print ( " " ) ;
2020-01-04 06:35:11 +00:00
pc_x = font : : GetX ( ) ;
2019-07-19 03:09:35 +01:00
font : : PrintFormat ( " %s: " , aarch64 : : CpuContext : : RegisterNameStrings [ i + ( aarch64 : : RegisterName_GeneralPurposeCount / 2 ) ] ) ;
2020-01-04 06:35:11 +00:00
font : : SetPosition ( pc_x + 47 , font : : GetY ( ) ) ;
2021-10-10 08:14:06 +01:00
if ( m_context - > cpu_ctx . aarch64_ctx . HasRegisterValue ( static_cast < aarch64 : : RegisterName > ( i + ( aarch64 : : RegisterName_GeneralPurposeCount / 2 ) ) ) ) {
font : : PrintMonospaceU64 ( m_context - > cpu_ctx . aarch64_ctx . x [ i + ( aarch64 : : RegisterName_GeneralPurposeCount / 2 ) ] ) ;
2019-07-19 03:09:35 +01:00
} else {
font : : PrintMonospaceBlank ( 16 ) ;
}
if ( i = = ( aarch64 : : RegisterName_GeneralPurposeCount / 2 ) - 1 ) {
font : : Print ( " " ) ;
backtrace_x = font : : GetX ( ) ;
}
font : : PrintLine ( " " ) ;
2020-01-04 06:35:11 +00:00
font : : SetPosition ( start_x , font : : GetY ( ) ) ;
2018-11-14 02:11:08 +00:00
}
2019-07-19 03:09:35 +01:00
}
2019-04-22 20:40:53 +01:00
2020-01-04 06:35:11 +00:00
/* Print PC. */
{
font : : SetPosition ( pc_x , backtrace_y ) ;
const u32 x = font : : GetX ( ) ;
font : : Print ( " PC: " ) ;
font : : SetPosition ( x + 47 , font : : GetY ( ) ) ;
}
if ( is_aarch32 ) {
2021-10-10 08:14:06 +01:00
font : : PrintMonospaceU32 ( m_context - > cpu_ctx . aarch32_ctx . pc ) ;
2020-01-04 06:35:11 +00:00
} else {
2021-10-10 08:14:06 +01:00
font : : PrintMonospaceU64 ( m_context - > cpu_ctx . aarch64_ctx . pc ) ;
2020-01-04 06:35:11 +00:00
}
2019-07-19 03:09:35 +01:00
/* Print Backtrace. */
u32 bt_size ;
if ( is_aarch32 ) {
2021-10-10 08:14:06 +01:00
bt_size = m_context - > cpu_ctx . aarch32_ctx . stack_trace_size ;
2019-07-19 03:09:35 +01:00
} else {
2021-10-10 08:14:06 +01:00
bt_size = m_context - > cpu_ctx . aarch64_ctx . stack_trace_size ;
2019-07-19 03:09:35 +01:00
}
2019-04-22 20:40:53 +01:00
2019-07-19 03:09:35 +01:00
font : : SetPosition ( backtrace_x , backtrace_y ) ;
if ( bt_size = = 0 ) {
if ( is_aarch32 ) {
font : : Print ( " Start Address: " ) ;
2021-10-10 08:14:06 +01:00
font : : PrintMonospaceU32 ( m_context - > cpu_ctx . aarch32_ctx . base_address ) ;
2019-07-19 03:09:35 +01:00
font : : PrintLine ( " " ) ;
} else {
font : : Print ( " Start Address: " ) ;
2021-10-10 08:14:06 +01:00
font : : PrintMonospaceU64 ( m_context - > cpu_ctx . aarch64_ctx . base_address ) ;
2019-07-19 03:09:35 +01:00
font : : PrintLine ( " " ) ;
2018-11-14 02:11:08 +00:00
}
2019-07-19 03:09:35 +01:00
} else {
if ( is_aarch32 ) {
font : : Print ( " Backtrace - Start Address: " ) ;
2021-10-10 08:14:06 +01:00
font : : PrintMonospaceU32 ( m_context - > cpu_ctx . aarch32_ctx . base_address ) ;
2019-07-19 03:09:35 +01:00
font : : PrintLine ( " " ) ;
font : : AddSpacingLines ( 0.5f ) ;
for ( u32 i = 0 ; i < aarch32 : : CpuContext : : MaxStackTraceDepth / 2 ; i + + ) {
u32 bt_cur = 0 , bt_next = 0 ;
2021-10-10 08:14:06 +01:00
if ( i < m_context - > cpu_ctx . aarch32_ctx . stack_trace_size ) {
bt_cur = m_context - > cpu_ctx . aarch32_ctx . stack_trace [ i ] ;
2019-07-19 03:09:35 +01:00
}
2021-10-10 08:14:06 +01:00
if ( i + aarch32 : : CpuContext : : MaxStackTraceDepth / 2 < m_context - > cpu_ctx . aarch32_ctx . stack_trace_size ) {
bt_next = m_context - > cpu_ctx . aarch32_ctx . stack_trace [ i + aarch32 : : CpuContext : : MaxStackTraceDepth / 2 ] ;
2019-07-19 03:09:35 +01:00
}
2021-10-10 08:14:06 +01:00
if ( i < m_context - > cpu_ctx . aarch32_ctx . stack_trace_size ) {
2019-07-19 03:09:35 +01:00
u32 x = font : : GetX ( ) ;
font : : PrintFormat ( " BT[%02d]: " , i ) ;
font : : SetPosition ( x + 72 , font : : GetY ( ) ) ;
font : : PrintMonospaceU32 ( bt_cur ) ;
2020-01-04 04:21:12 +00:00
font : : PrintMonospaceBlank ( 8 ) ;
2019-07-19 03:09:35 +01:00
font : : Print ( " " ) ;
}
2021-10-10 08:14:06 +01:00
if ( i + aarch32 : : CpuContext : : MaxStackTraceDepth / 2 < m_context - > cpu_ctx . aarch32_ctx . stack_trace_size ) {
2019-07-19 03:09:35 +01:00
u32 x = font : : GetX ( ) ;
font : : PrintFormat ( " BT[%02d]: " , i + aarch32 : : CpuContext : : MaxStackTraceDepth / 2 ) ;
font : : SetPosition ( x + 72 , font : : GetY ( ) ) ;
font : : PrintMonospaceU32 ( bt_next ) ;
2020-01-04 04:21:12 +00:00
font : : PrintMonospaceBlank ( 8 ) ;
2019-07-19 03:09:35 +01:00
}
font : : PrintLine ( " " ) ;
font : : SetPosition ( backtrace_x , font : : GetY ( ) ) ;
}
} else {
font : : Print ( " Backtrace - Start Address: " ) ;
2021-10-10 08:14:06 +01:00
font : : PrintMonospaceU64 ( m_context - > cpu_ctx . aarch64_ctx . base_address ) ;
2019-07-19 03:09:35 +01:00
font : : PrintLine ( " " ) ;
font : : AddSpacingLines ( 0.5f ) ;
for ( u32 i = 0 ; i < aarch64 : : CpuContext : : MaxStackTraceDepth / 2 ; i + + ) {
u64 bt_cur = 0 , bt_next = 0 ;
2021-10-10 08:14:06 +01:00
if ( i < m_context - > cpu_ctx . aarch64_ctx . stack_trace_size ) {
bt_cur = m_context - > cpu_ctx . aarch64_ctx . stack_trace [ i ] ;
2019-07-19 03:09:35 +01:00
}
2021-10-10 08:14:06 +01:00
if ( i + aarch64 : : CpuContext : : MaxStackTraceDepth / 2 < m_context - > cpu_ctx . aarch64_ctx . stack_trace_size ) {
bt_next = m_context - > cpu_ctx . aarch64_ctx . stack_trace [ i + aarch64 : : CpuContext : : MaxStackTraceDepth / 2 ] ;
2019-07-19 03:09:35 +01:00
}
2021-10-10 08:14:06 +01:00
if ( i < m_context - > cpu_ctx . aarch64_ctx . stack_trace_size ) {
2019-07-19 03:09:35 +01:00
u32 x = font : : GetX ( ) ;
font : : PrintFormat ( " BT[%02d]: " , i ) ;
font : : SetPosition ( x + 72 , font : : GetY ( ) ) ;
font : : PrintMonospaceU64 ( bt_cur ) ;
font : : Print ( " " ) ;
}
2021-10-10 08:14:06 +01:00
if ( i + aarch64 : : CpuContext : : MaxStackTraceDepth / 2 < m_context - > cpu_ctx . aarch64_ctx . stack_trace_size ) {
2019-07-19 03:09:35 +01:00
u32 x = font : : GetX ( ) ;
font : : PrintFormat ( " BT[%02d]: " , i + aarch64 : : CpuContext : : MaxStackTraceDepth / 2 ) ;
font : : SetPosition ( x + 72 , font : : GetY ( ) ) ;
font : : PrintMonospaceU64 ( bt_next ) ;
}
font : : PrintLine ( " " ) ;
font : : SetPosition ( backtrace_x , font : : GetY ( ) ) ;
}
2018-11-14 02:11:08 +00:00
}
2019-07-19 03:09:35 +01:00
}
2021-01-18 16:48:47 +00:00
}
2021-01-19 00:54:55 +00:00
Result ShowFatalTask : : InitializeNativeWindow ( ) {
/* Setup nv driver. */
R_TRY ( nvInitialize ( ) ) ;
R_TRY ( nvMapInit ( ) ) ;
R_TRY ( nvFenceInit ( ) ) ;
/* Create nvmap. */
2023-03-01 10:20:42 +00:00
R_TRY ( nvMapCreate ( std : : addressof ( m_map ) , g_framebuffer_pointer , FrameBufferRequiredSizeBytes , 0x20000 , NvKind_Pitch , true ) ) ;
2021-01-19 00:54:55 +00:00
/* Setup graphics buffer. */
{
NvGraphicBuffer grbuf = { } ;
grbuf . header . num_ints = ( sizeof ( NvGraphicBuffer ) - sizeof ( NativeHandle ) ) / 4 ;
grbuf . unk0 = - 1 ;
grbuf . magic = 0xDAFFCAFF ;
grbuf . pid = 42 ;
grbuf . usage = GRALLOC_USAGE_HW_COMPOSER | GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE ;
grbuf . format = PIXEL_FORMAT_RGB_565 ;
grbuf . ext_format = PIXEL_FORMAT_RGB_565 ;
grbuf . num_planes = 1 ;
grbuf . planes [ 0 ] . width = FatalScreenWidth ;
grbuf . planes [ 0 ] . height = FatalScreenHeight ;
grbuf . planes [ 0 ] . color_format = NvColorFormat_R5G6B5 ;
grbuf . planes [ 0 ] . layout = NvLayout_BlockLinear ;
grbuf . planes [ 0 ] . kind = NvKind_Generic_16BX2 ;
grbuf . planes [ 0 ] . block_height_log2 = 4 ;
2021-10-10 08:14:06 +01:00
grbuf . nvmap_id = nvMapGetId ( std : : addressof ( m_map ) ) ;
2021-01-19 00:54:55 +00:00
grbuf . stride = FatalScreenWidthAligned ;
2023-03-01 10:20:42 +00:00
grbuf . total_size = FrameBufferRequiredSizeBytes ;
2021-01-19 00:54:55 +00:00
grbuf . planes [ 0 ] . pitch = FatalScreenWidthAlignedBytes ;
2023-03-01 10:20:42 +00:00
grbuf . planes [ 0 ] . size = FrameBufferRequiredSizeBytes ;
2021-01-19 00:54:55 +00:00
grbuf . planes [ 0 ] . offset = 0 ;
2021-10-10 08:14:06 +01:00
R_TRY ( nwindowConfigureBuffer ( std : : addressof ( m_win ) , 0 , std : : addressof ( grbuf ) ) ) ;
2021-01-19 00:54:55 +00:00
}
2022-03-26 07:14:36 +00:00
R_SUCCEED ( ) ;
2021-01-19 00:54:55 +00:00
}
void ShowFatalTask : : DisplayPreRenderedFrame ( ) {
s32 slot ;
2021-10-10 08:14:06 +01:00
R_ABORT_UNLESS ( nwindowDequeueBuffer ( std : : addressof ( m_win ) , std : : addressof ( slot ) , nullptr ) ) ;
2023-03-01 10:20:42 +00:00
dd : : FlushDataCache ( g_framebuffer_pointer , FrameBufferRequiredSizeBytes ) ;
2021-10-10 08:14:06 +01:00
R_ABORT_UNLESS ( nwindowQueueBuffer ( std : : addressof ( m_win ) , m_win . cur_slot , NULL ) ) ;
2021-01-19 00:54:55 +00:00
}
2021-01-18 16:48:47 +00:00
Result ShowFatalTask : : ShowFatal ( ) {
/* Pre-render the framebuffer. */
PreRenderFrameBuffer ( ) ;
/* Prepare screen for drawing. */
2021-04-14 07:58:10 +01:00
R_ABORT_UNLESS ( PrepareScreenForDrawing ( ) ) ;
2021-01-18 16:48:47 +00:00
2021-01-19 00:54:55 +00:00
/* Display the pre-rendered frame. */
this - > DisplayPreRenderedFrame ( ) ;
2019-04-22 20:40:53 +01:00
2022-03-26 07:14:36 +00:00
R_SUCCEED ( ) ;
2018-11-14 01:53:26 +00:00
}
2019-04-22 20:40:53 +01:00
2019-07-19 03:09:35 +01:00
Result ShowFatalTask : : Run ( ) {
/* Don't show the fatal error screen until we've verified the battery is okay. */
2021-10-10 08:14:06 +01:00
m_context - > battery_event - > Wait ( ) ;
2019-04-22 20:40:53 +01:00
2022-03-26 21:48:33 +00:00
R_RETURN ( ShowFatal ( ) ) ;
2019-07-19 03:09:35 +01:00
}
2019-04-22 20:40:53 +01:00
2019-07-19 03:09:35 +01:00
void BacklightControlTask : : TurnOnBacklight ( ) {
2022-03-26 06:47:20 +00:00
R_ABORT_UNLESS ( : : lblInitialize ( ) ) ;
: : lblSwitchBacklightOn ( 0 ) ;
: : lblExit ( ) ;
2019-07-19 03:09:35 +01:00
}
2018-11-10 19:59:55 +00:00
2019-07-19 03:09:35 +01:00
Result BacklightControlTask : : Run ( ) {
TurnOnBacklight ( ) ;
2022-03-26 07:14:36 +00:00
R_SUCCEED ( ) ;
2019-07-19 03:09:35 +01:00
}
2018-11-10 19:59:55 +00:00
2019-07-19 03:09:35 +01:00
}
2018-11-10 11:16:13 +00:00
2019-07-19 03:09:35 +01:00
ITask * GetShowFatalTask ( const ThrowContext * ctx ) {
g_show_fatal_task . Initialize ( ctx ) ;
2021-10-09 22:49:53 +01:00
return std : : addressof ( g_show_fatal_task ) ;
2019-07-19 03:09:35 +01:00
}
ITask * GetBacklightControlTask ( const ThrowContext * ctx ) {
g_backlight_control_task . Initialize ( ctx ) ;
2021-10-09 22:49:53 +01:00
return std : : addressof ( g_backlight_control_task ) ;
2019-07-19 03:09:35 +01:00
}
2018-11-10 11:16:13 +00:00
}