mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-31 13:50:03 +00:00 
			
		
		
		
	Rework the code of err:f service
This commit is contained in:
		
							parent
							
								
									09c3e444d4
								
							
						
					
					
						commit
						691f069743
					
				
					 1 changed files with 196 additions and 116 deletions
				
			
		|  | @ -2,9 +2,15 @@ | ||||||
| // Licensed under GPLv2 or any later version
 | // Licensed under GPLv2 or any later version
 | ||||||
| // Refer to the license.txt file included.
 | // Refer to the license.txt file included.
 | ||||||
| 
 | 
 | ||||||
|  | #include <array> | ||||||
|  | #include <chrono> | ||||||
|  | #include <iomanip> | ||||||
|  | #include <sstream> | ||||||
|  | 
 | ||||||
| #include "common/bit_field.h" | #include "common/bit_field.h" | ||||||
| #include "common/common_types.h" | #include "common/common_types.h" | ||||||
| #include "common/logging/log.h" | #include "common/logging/log.h" | ||||||
|  | #include "core/hle/result.h" | ||||||
| #include "core/hle/service/err_f.h" | #include "core/hle/service/err_f.h" | ||||||
| 
 | 
 | ||||||
| ////////////////////////////////////////////////////////////////////////////////////////////////////
 | ////////////////////////////////////////////////////////////////////////////////////////////////////
 | ||||||
|  | @ -12,13 +18,46 @@ | ||||||
| 
 | 
 | ||||||
| namespace ERR_F { | namespace ERR_F { | ||||||
| 
 | 
 | ||||||
| enum { | enum class FatalErrType : u32 { | ||||||
|     ErrSpecifier0 = 0, |     Generic = 0, | ||||||
|     ErrSpecifier1 = 1, |     Corrupted = 1, | ||||||
|     ErrSpecifier3 = 3, |     CardRemoved = 2, | ||||||
|     ErrSpecifier4 = 4, |     Exception = 3, | ||||||
|  |     ResultFailure = 4, | ||||||
|  |     Logged = 5, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | enum class ExceptionType : u32 { | ||||||
|  |     PrefetchAbort = 0, | ||||||
|  |     DataAbort = 1, | ||||||
|  |     Undefined = 2, | ||||||
|  |     VectorFP = 3, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct ExceptionInfo { | ||||||
|  |     u8 exception_type; | ||||||
|  |     INSERT_PADDING_BYTES(3); | ||||||
|  |     u32 sr; | ||||||
|  |     u32 ar; | ||||||
|  |     u32 fpexc; | ||||||
|  |     u32 fpinst; | ||||||
|  |     u32 fpinst2; | ||||||
|  | }; | ||||||
|  | static_assert(sizeof(ExceptionInfo) == 0x18, "ExceptionInfo struct has incorrect size"); | ||||||
|  | 
 | ||||||
|  | struct ExceptionContext final { | ||||||
|  |     std::array<u32, 16> arm_regs; | ||||||
|  |     u32 cpsr; | ||||||
|  | }; | ||||||
|  | static_assert(sizeof(ExceptionContext) == 0x44, "ExceptionContext struct has incorrect size"); | ||||||
|  | 
 | ||||||
|  | struct ExceptionData { | ||||||
|  |     ExceptionInfo exception_info; | ||||||
|  |     ExceptionContext exception_context; | ||||||
|  |     INSERT_PADDING_WORDS(1); | ||||||
|  | }; | ||||||
|  | static_assert(sizeof(ExceptionData) == 0x60, "ExceptionData struct has incorrect size"); | ||||||
|  | 
 | ||||||
| // This is used instead of ResultCode from result.h
 | // This is used instead of ResultCode from result.h
 | ||||||
| // because we can't have non-trivial data members in unions.
 | // because we can't have non-trivial data members in unions.
 | ||||||
| union RSL { | union RSL { | ||||||
|  | @ -30,150 +69,191 @@ union RSL { | ||||||
|     BitField<27, 5, u32> level; |     BitField<27, 5, u32> level; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| union ErrInfo { | struct ErrInfo { | ||||||
|     u8 specifier; |     struct ErrInfoCommon { | ||||||
|  |         u8 specifier;          // 0x0
 | ||||||
|  |         u8 rev_high;           // 0x1
 | ||||||
|  |         u16 rev_low;           // 0x2
 | ||||||
|  |         RSL result_code;       // 0x4
 | ||||||
|  |         u32 pc_address;        // 0x8
 | ||||||
|  |         u32 pid;               // 0xC
 | ||||||
|  |         u32 title_id_low;      // 0x10
 | ||||||
|  |         u32 title_id_high;     // 0x14
 | ||||||
|  |         u32 app_title_id_low;  // 0x18
 | ||||||
|  |         u32 app_title_id_high; // 0x1C
 | ||||||
|  |     } errinfo_common; | ||||||
|  |     static_assert(sizeof(ErrInfoCommon) == 0x20, "ErrInfoCommon struct has incorrect size"); | ||||||
| 
 | 
 | ||||||
|     struct { |     union { | ||||||
|         u8 specifier;            // 0x0
 |         struct { | ||||||
|         u8 rev_high;             // 0x1
 |             char data[0x60]; // 0x20
 | ||||||
|         u16 rev_low;             // 0x2
 |         } generic; | ||||||
|         RSL result_code;         // 0x4
 |  | ||||||
|         u32 address;             // 0x8
 |  | ||||||
|         INSERT_PADDING_BYTES(4); // 0xC
 |  | ||||||
|         u32 pid_low;             // 0x10
 |  | ||||||
|         u32 pid_high;            // 0x14
 |  | ||||||
|         u32 aid_low;             // 0x18
 |  | ||||||
|         u32 aid_high;            // 0x1C
 |  | ||||||
|     } errtype1; |  | ||||||
| 
 | 
 | ||||||
|     struct { |         struct { | ||||||
|         u8 specifier;               // 0x0
 |             ExceptionData exception_data; // 0x20
 | ||||||
|         u8 rev_high;                // 0x1
 |         } exception; | ||||||
|         u16 rev_low;                // 0x2
 |  | ||||||
|         INSERT_PADDING_BYTES(0xC);  // 0x4
 |  | ||||||
|         u32 pid_low;                // 0x10
 |  | ||||||
|         u32 pid_high;               // 0x14
 |  | ||||||
|         u32 aid_low;                // 0x18
 |  | ||||||
|         u32 aid_high;               // 0x1C
 |  | ||||||
|         u8 error_type;              // 0x20
 |  | ||||||
|         INSERT_PADDING_BYTES(3);    // 0x21
 |  | ||||||
|         u32 fault_status_reg;       // 0x24
 |  | ||||||
|         u32 fault_addr;             // 0x28
 |  | ||||||
|         u32 fpexc;                  // 0x2C
 |  | ||||||
|         u32 finst;                  // 0x30
 |  | ||||||
|         u32 finst2;                 // 0x34
 |  | ||||||
|         INSERT_PADDING_BYTES(0x34); // 0x38
 |  | ||||||
|         u32 sp;                     // 0x6C
 |  | ||||||
|         u32 pc;                     // 0x70
 |  | ||||||
|         u32 lr;                     // 0x74
 |  | ||||||
|         u32 cpsr;                   // 0x78
 |  | ||||||
|     } errtype3; |  | ||||||
| 
 | 
 | ||||||
|     struct { |         struct { | ||||||
|         u8 specifier;             // 0x0
 |             char message[0x60]; // 0x20
 | ||||||
|         u8 rev_high;              // 0x1
 |         } result_failure; | ||||||
|         u16 rev_low;              // 0x2
 |     }; | ||||||
|         RSL result_code;          // 0x4
 |  | ||||||
|         INSERT_PADDING_BYTES(8);  // 0x8
 |  | ||||||
|         u32 pid_low;              // 0x10
 |  | ||||||
|         u32 pid_high;             // 0x14
 |  | ||||||
|         u32 aid_low;              // 0x18
 |  | ||||||
|         u32 aid_high;             // 0x1C
 |  | ||||||
|         char debug_string1[0x2E]; // 0x20
 |  | ||||||
|         char debug_string2[0x2E]; // 0x4E
 |  | ||||||
|     } errtype4; |  | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| enum { PrefetchAbort = 0, DataAbort = 1, UndefInstr = 2, VectorFP = 3 }; | static std::string GetErrType(u8 type_code) { | ||||||
| 
 |     switch (static_cast<FatalErrType>(type_code)) { | ||||||
| static std::string GetErrInfo3Type(u8 type_code) { |     case FatalErrType::Generic: | ||||||
|     switch (type_code) { |         return "Generic"; | ||||||
|     case PrefetchAbort: |     case FatalErrType::Corrupted: | ||||||
|         return "Prefetch Abort"; |         return "Corrupted"; | ||||||
|     case DataAbort: |     case FatalErrType::CardRemoved: | ||||||
|         return "Data Abort"; |         return "CardRemoved"; | ||||||
|     case UndefInstr: |     case FatalErrType::Exception: | ||||||
|         return "Undefined Instruction"; |         return "Exception"; | ||||||
|     case VectorFP: |     case FatalErrType::ResultFailure: | ||||||
|         return "Vector Floating Point"; |         return "ResultFailure"; | ||||||
|  |     case FatalErrType::Logged: | ||||||
|  |         return "Logged"; | ||||||
|     default: |     default: | ||||||
|         return "unknown"; |         return "Unknown Error Type"; | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static std::string GetExceptionType(u8 type_code) { | ||||||
|  |     switch (static_cast<ExceptionType>(type_code)) { | ||||||
|  |     case ExceptionType::PrefetchAbort: | ||||||
|  |         return "Prefetch Abort"; | ||||||
|  |     case ExceptionType::DataAbort: | ||||||
|  |         return "Data Abort"; | ||||||
|  |     case ExceptionType::Undefined: | ||||||
|  |         return "Undefined Exception"; | ||||||
|  |     case ExceptionType::VectorFP: | ||||||
|  |         return "Vector Floating Point Exception"; | ||||||
|  |     default: | ||||||
|  |         return "Unknown Exception Type"; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static std::string GetCurrentSystemTime() { | ||||||
|  |     auto now = std::chrono::system_clock::now(); | ||||||
|  |     auto time = std::chrono::system_clock::to_time_t(now); | ||||||
|  | 
 | ||||||
|  |     std::stringstream time_stream; | ||||||
|  |     time_stream << std::put_time(std::localtime(&time), "%Y/%m/%d %H:%M:%S"); | ||||||
|  |     return time_stream.str(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void LogGenericInfo(const ErrInfo::ErrInfoCommon& errinfo_common) { | ||||||
|  |     LOG_CRITICAL(Service_ERR, "PID: 0x%08X", errinfo_common.pid); | ||||||
|  |     LOG_CRITICAL(Service_ERR, "REV: 0x%08X_0x%08X", errinfo_common.rev_high, | ||||||
|  |                  errinfo_common.rev_low); | ||||||
|  |     LOG_CRITICAL(Service_ERR, "TID: 0x%08X_0x%08X", errinfo_common.title_id_high, | ||||||
|  |                  errinfo_common.title_id_low); | ||||||
|  |     LOG_CRITICAL(Service_ERR, "AID: 0x%08X_0x%08X", errinfo_common.app_title_id_high, | ||||||
|  |                  errinfo_common.app_title_id_low); | ||||||
|  |     LOG_CRITICAL(Service_ERR, "ADR: 0x%08X", errinfo_common.pc_address); | ||||||
|  | 
 | ||||||
|  |     LOG_CRITICAL(Service_ERR, "RSL: 0x%08X", errinfo_common.result_code.raw); | ||||||
|  |     LOG_CRITICAL(Service_ERR, "  Level: %u", errinfo_common.result_code.level.Value()); | ||||||
|  |     LOG_CRITICAL(Service_ERR, "  Summary: %u", errinfo_common.result_code.summary.Value()); | ||||||
|  |     LOG_CRITICAL(Service_ERR, "  Module: %u", errinfo_common.result_code.module.Value()); | ||||||
|  |     LOG_CRITICAL(Service_ERR, "  Desc: %u", errinfo_common.result_code.description.Value()); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /* ThrowFatalError function
 | ||||||
|  |  * Inputs: | ||||||
|  |  *       0 : Header code [0x00010800] | ||||||
|  |  *    1-32 : FatalErrInfo | ||||||
|  |  * Outputs: | ||||||
|  |  *       0 : Header code | ||||||
|  |  *       1 : Result code | ||||||
|  |  */ | ||||||
| static void ThrowFatalError(Service::Interface* self) { | static void ThrowFatalError(Service::Interface* self) { | ||||||
|     u32* cmd_buff = Kernel::GetCommandBuffer(); |     u32* cmd_buff = Kernel::GetCommandBuffer(); | ||||||
| 
 | 
 | ||||||
|     LOG_CRITICAL(Service_ERR, "Fatal error!"); |     LOG_CRITICAL(Service_ERR, "Fatal error"); | ||||||
|     const ErrInfo* errinfo = reinterpret_cast<ErrInfo*>(&cmd_buff[1]); |     const ErrInfo* errinfo = reinterpret_cast<ErrInfo*>(&cmd_buff[1]); | ||||||
|  |     LOG_CRITICAL(Service_ERR, "Fatal error type: %s", | ||||||
|  |                  GetErrType(errinfo->errinfo_common.specifier).c_str()); | ||||||
| 
 | 
 | ||||||
|     switch (errinfo->specifier) { |     // Generic Info
 | ||||||
|     case ErrSpecifier0: |     LogGenericInfo(errinfo->errinfo_common); | ||||||
|     case ErrSpecifier1: { |  | ||||||
|         const auto& errtype = errinfo->errtype1; |  | ||||||
|         LOG_CRITICAL(Service_ERR, "PID: 0x%08X_0x%08X", errtype.pid_low, errtype.pid_high); |  | ||||||
|         LOG_CRITICAL(Service_ERR, "REV: %d", errtype.rev_low | (errtype.rev_high << 16)); |  | ||||||
|         LOG_CRITICAL(Service_ERR, "AID: 0x%08X_0x%08X", errtype.aid_low, errtype.aid_high); |  | ||||||
|         LOG_CRITICAL(Service_ERR, "ADR: 0x%08X", errtype.address); |  | ||||||
| 
 | 
 | ||||||
|         LOG_CRITICAL(Service_ERR, "RSL: 0x%08X", errtype.result_code.raw); |     switch (static_cast<FatalErrType>(errinfo->errinfo_common.specifier)) { | ||||||
|         LOG_CRITICAL(Service_ERR, "  Level: %u", errtype.result_code.level.Value()); |     case FatalErrType::Generic: | ||||||
|         LOG_CRITICAL(Service_ERR, "  Summary: %u", errtype.result_code.summary.Value()); |     case FatalErrType::Corrupted: | ||||||
|         LOG_CRITICAL(Service_ERR, "  Module: %u", errtype.result_code.module.Value()); |     case FatalErrType::CardRemoved: | ||||||
|         LOG_CRITICAL(Service_ERR, "  Desc: %u", errtype.result_code.description.Value()); |     case FatalErrType::Logged: { | ||||||
|  |         LOG_CRITICAL(Service_ERR, "Datetime: %s", GetCurrentSystemTime().c_str()); | ||||||
|         break; |         break; | ||||||
|     } |     } | ||||||
|  |     case FatalErrType::Exception: { | ||||||
|  |         const auto& errtype = errinfo->exception; | ||||||
| 
 | 
 | ||||||
|     case ErrSpecifier3: { |         // Register Info
 | ||||||
|         const auto& errtype = errinfo->errtype3; |         LOG_CRITICAL(Service_ERR, "ARM Registers:"); | ||||||
|         LOG_CRITICAL(Service_ERR, "PID: 0x%08X_0x%08X", errtype.pid_low, errtype.pid_high); |         for (u32 index = 0; index < errtype.exception_data.exception_context.arm_regs.size(); | ||||||
|         LOG_CRITICAL(Service_ERR, "REV: %d", errtype.rev_low | (errtype.rev_high << 16)); |              ++index) { | ||||||
|         LOG_CRITICAL(Service_ERR, "AID: 0x%08X_0x%08X", errtype.aid_low, errtype.aid_high); |             if (index < 13) { | ||||||
|         LOG_CRITICAL(Service_ERR, "TYPE: %s", GetErrInfo3Type(errtype.error_type).c_str()); |                 LOG_DEBUG(Service_ERR, "r%u=0x%08X", index, | ||||||
|  |                           errtype.exception_data.exception_context.arm_regs.at(index)); | ||||||
|  |             } else if (index == 13) { | ||||||
|  |                 LOG_CRITICAL(Service_ERR, "SP=0x%08X", | ||||||
|  |                              errtype.exception_data.exception_context.arm_regs.at(index)); | ||||||
|  |             } else if (index == 14) { | ||||||
|  |                 LOG_CRITICAL(Service_ERR, "LR=0x%08X", | ||||||
|  |                              errtype.exception_data.exception_context.arm_regs.at(index)); | ||||||
|  |             } else if (index == 15) { | ||||||
|  |                 LOG_CRITICAL(Service_ERR, "PC=0x%08X", | ||||||
|  |                              errtype.exception_data.exception_context.arm_regs.at(index)); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         LOG_CRITICAL(Service_ERR, "CPSR=0x%08X", errtype.exception_data.exception_context.cpsr); | ||||||
| 
 | 
 | ||||||
|         LOG_CRITICAL(Service_ERR, "PC: 0x%08X", errtype.pc); |         // Exception Info
 | ||||||
|         LOG_CRITICAL(Service_ERR, "LR: 0x%08X", errtype.lr); |         LOG_CRITICAL( | ||||||
|         LOG_CRITICAL(Service_ERR, "SP: 0x%08X", errtype.sp); |             Service_ERR, "EXCEPTION TYPE: %s", | ||||||
|         LOG_CRITICAL(Service_ERR, "CPSR: 0x%08X", errtype.cpsr); |             GetExceptionType(errtype.exception_data.exception_info.exception_type).c_str()); | ||||||
| 
 |         switch (static_cast<ExceptionType>(errtype.exception_data.exception_info.exception_type)) { | ||||||
|         switch (errtype.error_type) { |         case ExceptionType::PrefetchAbort: | ||||||
|         case PrefetchAbort: |             LOG_CRITICAL(Service_ERR, "IFSR: 0x%08X", errtype.exception_data.exception_info.sr); | ||||||
|         case DataAbort: |             LOG_CRITICAL(Service_ERR, "r15: 0x%08X", errtype.exception_data.exception_info.ar); | ||||||
|             LOG_CRITICAL(Service_ERR, "Fault Address: 0x%08X", errtype.fault_addr); |         case ExceptionType::DataAbort: | ||||||
|             LOG_CRITICAL(Service_ERR, "Fault Status Register: 0x%08X", errtype.fault_status_reg); |             LOG_CRITICAL(Service_ERR, "DFSR: 0x%08X", errtype.exception_data.exception_info.sr); | ||||||
|  |             LOG_CRITICAL(Service_ERR, "DFAR: 0x%08X", errtype.exception_data.exception_info.ar); | ||||||
|             break; |             break; | ||||||
|         case VectorFP: |         case ExceptionType::VectorFP: | ||||||
|             LOG_CRITICAL(Service_ERR, "FPEXC: 0x%08X", errtype.fpexc); |             LOG_CRITICAL(Service_ERR, "FPEXC: 0x%08X", | ||||||
|             LOG_CRITICAL(Service_ERR, "FINST: 0x%08X", errtype.finst); |                          errtype.exception_data.exception_info.fpinst); | ||||||
|             LOG_CRITICAL(Service_ERR, "FINST2: 0x%08X", errtype.finst2); |             LOG_CRITICAL(Service_ERR, "FINST: 0x%08X", | ||||||
|  |                          errtype.exception_data.exception_info.fpinst); | ||||||
|  |             LOG_CRITICAL(Service_ERR, "FINST2: 0x%08X", | ||||||
|  |                          errtype.exception_data.exception_info.fpinst2); | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
|  |         LOG_CRITICAL(Service_ERR, "Datetime: %s", GetCurrentSystemTime().c_str()); | ||||||
|         break; |         break; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     case ErrSpecifier4: { |     case FatalErrType::ResultFailure: { | ||||||
|         const auto& errtype = errinfo->errtype4; |         const auto& errtype = errinfo->result_failure; | ||||||
|         LOG_CRITICAL(Service_ERR, "PID: 0x%08X_0x%08X", errtype.pid_low, errtype.pid_high); |  | ||||||
|         LOG_CRITICAL(Service_ERR, "REV: %d", errtype.rev_low | (errtype.rev_high << 16)); |  | ||||||
|         LOG_CRITICAL(Service_ERR, "AID: 0x%08X_0x%08X", errtype.aid_low, errtype.aid_high); |  | ||||||
| 
 | 
 | ||||||
|         LOG_CRITICAL(Service_ERR, "RSL: 0x%08X", errtype.result_code.raw); |         // Failure Message
 | ||||||
|         LOG_CRITICAL(Service_ERR, "  Level: %u", errtype.result_code.level.Value()); |         LOG_CRITICAL(Service_ERR, "Failure Message: %s", errtype.message); | ||||||
|         LOG_CRITICAL(Service_ERR, "  Summary: %u", errtype.result_code.summary.Value()); |         LOG_CRITICAL(Service_ERR, "Datetime: %s", GetCurrentSystemTime().c_str()); | ||||||
|         LOG_CRITICAL(Service_ERR, "  Module: %u", errtype.result_code.module.Value()); |  | ||||||
|         LOG_CRITICAL(Service_ERR, "  Desc: %u", errtype.result_code.description.Value()); |  | ||||||
| 
 |  | ||||||
|         LOG_CRITICAL(Service_ERR, "%s", errtype.debug_string1); |  | ||||||
|         LOG_CRITICAL(Service_ERR, "%s", errtype.debug_string2); |  | ||||||
|         break; |         break; | ||||||
|     } |     } | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|     cmd_buff[1] = 0; // No error
 |     } // switch FatalErrType
 | ||||||
|  | 
 | ||||||
|  |     cmd_buff[0] = IPC::MakeHeader(0x1, 1, 0); | ||||||
|  |     cmd_buff[1] = RESULT_SUCCESS.raw; // No error
 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| const Interface::FunctionInfo FunctionTable[] = { | const Interface::FunctionInfo FunctionTable[] = { | ||||||
|  |     // clang-format off
 | ||||||
|     {0x00010800, ThrowFatalError, "ThrowFatalError"}, |     {0x00010800, ThrowFatalError, "ThrowFatalError"}, | ||||||
|  |     {0x00020042, nullptr, "SetUserString"}, | ||||||
|  |     // clang-format on
 | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| ////////////////////////////////////////////////////////////////////////////////////////////////////
 | ////////////////////////////////////////////////////////////////////////////////////////////////////
 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue