Rework the code of err:f service

This commit is contained in:
JamePeng 2016-10-02 16:04:50 +08:00
parent 09c3e444d4
commit 691f069743

View File

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