2014-11-02 03:06:13 +00:00
|
|
|
// Copyright 2014 Citra Emulator Project
|
2014-12-17 05:38:14 +00:00
|
|
|
// Licensed under GPLv2 or any later version
|
2014-11-02 03:06:13 +00:00
|
|
|
// Refer to the license.txt file included.
|
|
|
|
|
2016-10-02 08:04:50 +00:00
|
|
|
#include <array>
|
|
|
|
#include <chrono>
|
|
|
|
#include <iomanip>
|
|
|
|
#include <sstream>
|
2019-12-26 18:14:22 +00:00
|
|
|
#include "common/archives.h"
|
2016-02-02 06:17:41 +00:00
|
|
|
#include "common/bit_field.h"
|
|
|
|
#include "common/common_types.h"
|
2015-05-06 07:06:12 +00:00
|
|
|
#include "common/logging/log.h"
|
2017-03-08 21:28:30 +00:00
|
|
|
#include "core/core.h"
|
2017-06-06 08:29:46 +00:00
|
|
|
#include "core/hle/ipc.h"
|
2017-12-04 19:03:11 +00:00
|
|
|
#include "core/hle/ipc_helpers.h"
|
2016-10-02 08:04:50 +00:00
|
|
|
#include "core/hle/result.h"
|
2016-09-21 06:52:38 +00:00
|
|
|
#include "core/hle/service/err_f.h"
|
2019-08-10 23:20:09 +00:00
|
|
|
#undef exception_info
|
2015-05-06 07:06:12 +00:00
|
|
|
|
2019-12-26 18:14:22 +00:00
|
|
|
SERIALIZE_EXPORT_IMPL(Service::ERR::ERR_F)
|
|
|
|
|
|
|
|
namespace boost::serialization {
|
2019-12-27 21:07:29 +00:00
|
|
|
template <class Archive>
|
|
|
|
void load_construct_data(Archive& ar, Service::ERR::ERR_F* t, const unsigned int) {
|
|
|
|
::new (t) Service::ERR::ERR_F(Core::Global<Core::System>());
|
2019-12-26 18:14:22 +00:00
|
|
|
}
|
|
|
|
|
2019-12-27 21:07:29 +00:00
|
|
|
template void load_construct_data<iarchive>(iarchive& ar, Service::ERR::ERR_F* t,
|
|
|
|
const unsigned int);
|
|
|
|
} // namespace boost::serialization
|
|
|
|
|
2018-09-22 12:23:08 +00:00
|
|
|
namespace Service::ERR {
|
2014-11-02 03:06:13 +00:00
|
|
|
|
2016-10-02 08:04:50 +00:00
|
|
|
enum class FatalErrType : u32 {
|
|
|
|
Generic = 0,
|
|
|
|
Corrupted = 1,
|
|
|
|
CardRemoved = 2,
|
|
|
|
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;
|
2015-02-17 23:15:04 +00:00
|
|
|
};
|
2016-10-02 08:04:50 +00:00
|
|
|
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");
|
2015-02-17 23:15:04 +00:00
|
|
|
|
2016-10-02 08:04:50 +00:00
|
|
|
struct ErrInfo {
|
|
|
|
struct ErrInfoCommon {
|
|
|
|
u8 specifier; // 0x0
|
|
|
|
u8 rev_high; // 0x1
|
|
|
|
u16 rev_low; // 0x2
|
2017-12-04 19:03:11 +00:00
|
|
|
u32 result_code; // 0x4
|
2016-10-02 08:04:50 +00:00
|
|
|
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");
|
|
|
|
|
|
|
|
union {
|
|
|
|
struct {
|
|
|
|
char data[0x60]; // 0x20
|
|
|
|
} generic;
|
|
|
|
|
|
|
|
struct {
|
|
|
|
ExceptionData exception_data; // 0x20
|
|
|
|
} exception;
|
|
|
|
|
|
|
|
struct {
|
|
|
|
char message[0x60]; // 0x20
|
|
|
|
} result_failure;
|
|
|
|
};
|
2015-02-17 23:15:04 +00:00
|
|
|
};
|
|
|
|
|
2016-10-02 08:04:50 +00:00
|
|
|
static std::string GetErrType(u8 type_code) {
|
|
|
|
switch (static_cast<FatalErrType>(type_code)) {
|
|
|
|
case FatalErrType::Generic:
|
|
|
|
return "Generic";
|
|
|
|
case FatalErrType::Corrupted:
|
|
|
|
return "Corrupted";
|
|
|
|
case FatalErrType::CardRemoved:
|
|
|
|
return "CardRemoved";
|
|
|
|
case FatalErrType::Exception:
|
|
|
|
return "Exception";
|
|
|
|
case FatalErrType::ResultFailure:
|
|
|
|
return "ResultFailure";
|
|
|
|
case FatalErrType::Logged:
|
|
|
|
return "Logged";
|
|
|
|
default:
|
|
|
|
return "Unknown Error Type";
|
|
|
|
}
|
|
|
|
}
|
2015-02-17 23:15:04 +00:00
|
|
|
|
2016-10-02 08:04:50 +00:00
|
|
|
static std::string GetExceptionType(u8 type_code) {
|
|
|
|
switch (static_cast<ExceptionType>(type_code)) {
|
|
|
|
case ExceptionType::PrefetchAbort:
|
2016-09-18 00:38:01 +00:00
|
|
|
return "Prefetch Abort";
|
2016-10-02 08:04:50 +00:00
|
|
|
case ExceptionType::DataAbort:
|
2016-09-18 00:38:01 +00:00
|
|
|
return "Data Abort";
|
2016-10-02 08:04:50 +00:00
|
|
|
case ExceptionType::Undefined:
|
|
|
|
return "Undefined Exception";
|
|
|
|
case ExceptionType::VectorFP:
|
|
|
|
return "Vector Floating Point Exception";
|
2016-09-18 00:38:01 +00:00
|
|
|
default:
|
2016-10-02 08:04:50 +00:00
|
|
|
return "Unknown Exception Type";
|
2015-02-17 23:15:04 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-02 08:04:50 +00:00
|
|
|
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) {
|
2018-06-29 11:18:07 +00:00
|
|
|
LOG_CRITICAL(Service_ERR, "PID: 0x{:08X}", errinfo_common.pid);
|
|
|
|
LOG_CRITICAL(Service_ERR, "REV: 0x{:08X}_0x{:08X}", errinfo_common.rev_high,
|
2018-06-29 13:56:12 +00:00
|
|
|
errinfo_common.rev_low);
|
2018-06-29 11:18:07 +00:00
|
|
|
LOG_CRITICAL(Service_ERR, "TID: 0x{:08X}_0x{:08X}", errinfo_common.title_id_high,
|
2018-06-29 13:56:12 +00:00
|
|
|
errinfo_common.title_id_low);
|
2018-06-29 11:18:07 +00:00
|
|
|
LOG_CRITICAL(Service_ERR, "AID: 0x{:08X}_0x{:08X}", errinfo_common.app_title_id_high,
|
2018-06-29 13:56:12 +00:00
|
|
|
errinfo_common.app_title_id_low);
|
2018-06-29 11:18:07 +00:00
|
|
|
LOG_CRITICAL(Service_ERR, "ADR: 0x{:08X}", errinfo_common.pc_address);
|
2016-10-02 08:04:50 +00:00
|
|
|
|
2017-12-04 19:03:11 +00:00
|
|
|
ResultCode result_code{errinfo_common.result_code};
|
2018-06-29 11:18:07 +00:00
|
|
|
LOG_CRITICAL(Service_ERR, "RSL: 0x{:08X}", result_code.raw);
|
|
|
|
LOG_CRITICAL(Service_ERR, " Level: {}", static_cast<u32>(result_code.level.Value()));
|
|
|
|
LOG_CRITICAL(Service_ERR, " Summary: {}", static_cast<u32>(result_code.summary.Value()));
|
|
|
|
LOG_CRITICAL(Service_ERR, " Module: {}", static_cast<u32>(result_code.module.Value()));
|
|
|
|
LOG_CRITICAL(Service_ERR, " Desc: {}", static_cast<u32>(result_code.description.Value()));
|
2016-10-02 08:04:50 +00:00
|
|
|
}
|
|
|
|
|
2017-12-04 19:03:11 +00:00
|
|
|
void ERR_F::ThrowFatalError(Kernel::HLERequestContext& ctx) {
|
|
|
|
IPC::RequestParser rp(ctx, 1, 32, 0);
|
2015-02-17 23:15:04 +00:00
|
|
|
|
2018-06-29 11:18:07 +00:00
|
|
|
LOG_CRITICAL(Service_ERR, "Fatal error");
|
2017-12-04 19:03:11 +00:00
|
|
|
const ErrInfo errinfo = rp.PopRaw<ErrInfo>();
|
2018-06-29 13:56:12 +00:00
|
|
|
LOG_CRITICAL(Service_ERR, "Fatal error type: {}", GetErrType(errinfo.errinfo_common.specifier));
|
2018-10-05 14:59:43 +00:00
|
|
|
system.SetStatus(Core::System::ResultStatus::ErrorUnknown);
|
2015-02-17 23:15:04 +00:00
|
|
|
|
2016-10-02 08:04:50 +00:00
|
|
|
// Generic Info
|
2017-12-04 19:03:11 +00:00
|
|
|
LogGenericInfo(errinfo.errinfo_common);
|
2016-10-02 08:04:50 +00:00
|
|
|
|
2017-12-04 19:03:11 +00:00
|
|
|
switch (static_cast<FatalErrType>(errinfo.errinfo_common.specifier)) {
|
2016-10-02 08:04:50 +00:00
|
|
|
case FatalErrType::Generic:
|
|
|
|
case FatalErrType::Corrupted:
|
|
|
|
case FatalErrType::CardRemoved:
|
|
|
|
case FatalErrType::Logged: {
|
2018-06-29 11:18:07 +00:00
|
|
|
LOG_CRITICAL(Service_ERR, "Datetime: {}", GetCurrentSystemTime());
|
2015-02-17 23:15:04 +00:00
|
|
|
break;
|
|
|
|
}
|
2016-10-02 08:04:50 +00:00
|
|
|
case FatalErrType::Exception: {
|
2017-12-04 19:03:11 +00:00
|
|
|
const auto& errtype = errinfo.exception;
|
2016-10-02 08:04:50 +00:00
|
|
|
|
|
|
|
// Register Info
|
2018-06-29 11:18:07 +00:00
|
|
|
LOG_CRITICAL(Service_ERR, "ARM Registers:");
|
2016-10-02 08:04:50 +00:00
|
|
|
for (u32 index = 0; index < errtype.exception_data.exception_context.arm_regs.size();
|
|
|
|
++index) {
|
|
|
|
if (index < 13) {
|
2018-06-29 11:18:07 +00:00
|
|
|
LOG_DEBUG(Service_ERR, "r{}=0x{:08X}", index,
|
2018-06-29 13:56:12 +00:00
|
|
|
errtype.exception_data.exception_context.arm_regs.at(index));
|
2016-10-02 08:04:50 +00:00
|
|
|
} else if (index == 13) {
|
2018-06-29 11:18:07 +00:00
|
|
|
LOG_CRITICAL(Service_ERR, "SP=0x{:08X}",
|
2018-06-29 13:56:12 +00:00
|
|
|
errtype.exception_data.exception_context.arm_regs.at(index));
|
2016-10-02 08:04:50 +00:00
|
|
|
} else if (index == 14) {
|
2018-06-29 11:18:07 +00:00
|
|
|
LOG_CRITICAL(Service_ERR, "LR=0x{:08X}",
|
2018-06-29 13:56:12 +00:00
|
|
|
errtype.exception_data.exception_context.arm_regs.at(index));
|
2016-10-02 08:04:50 +00:00
|
|
|
} else if (index == 15) {
|
2018-06-29 11:18:07 +00:00
|
|
|
LOG_CRITICAL(Service_ERR, "PC=0x{:08X}",
|
2018-06-29 13:56:12 +00:00
|
|
|
errtype.exception_data.exception_context.arm_regs.at(index));
|
2016-10-02 08:04:50 +00:00
|
|
|
}
|
|
|
|
}
|
2018-06-29 11:18:07 +00:00
|
|
|
LOG_CRITICAL(Service_ERR, "CPSR=0x{:08X}", errtype.exception_data.exception_context.cpsr);
|
2015-02-17 23:15:04 +00:00
|
|
|
|
2016-10-02 08:04:50 +00:00
|
|
|
// Exception Info
|
2018-06-29 11:18:07 +00:00
|
|
|
LOG_CRITICAL(Service_ERR, "EXCEPTION TYPE: {}",
|
2018-06-29 13:56:12 +00:00
|
|
|
GetExceptionType(errtype.exception_data.exception_info.exception_type));
|
2016-10-02 08:04:50 +00:00
|
|
|
switch (static_cast<ExceptionType>(errtype.exception_data.exception_info.exception_type)) {
|
|
|
|
case ExceptionType::PrefetchAbort:
|
2018-06-29 11:18:07 +00:00
|
|
|
LOG_CRITICAL(Service_ERR, "IFSR: 0x{:08X}", errtype.exception_data.exception_info.sr);
|
|
|
|
LOG_CRITICAL(Service_ERR, "r15: 0x{:08X}", errtype.exception_data.exception_info.ar);
|
2018-03-29 00:31:36 +00:00
|
|
|
break;
|
2016-10-02 08:04:50 +00:00
|
|
|
case ExceptionType::DataAbort:
|
2018-06-29 11:18:07 +00:00
|
|
|
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);
|
2015-02-17 23:15:04 +00:00
|
|
|
break;
|
2016-10-02 08:04:50 +00:00
|
|
|
case ExceptionType::VectorFP:
|
2018-06-29 11:18:07 +00:00
|
|
|
LOG_CRITICAL(Service_ERR, "FPEXC: 0x{:08X}",
|
2018-06-29 13:56:12 +00:00
|
|
|
errtype.exception_data.exception_info.fpinst);
|
2018-06-29 11:18:07 +00:00
|
|
|
LOG_CRITICAL(Service_ERR, "FINST: 0x{:08X}",
|
2018-06-29 13:56:12 +00:00
|
|
|
errtype.exception_data.exception_info.fpinst);
|
2018-06-29 11:18:07 +00:00
|
|
|
LOG_CRITICAL(Service_ERR, "FINST2: 0x{:08X}",
|
2018-06-29 13:56:12 +00:00
|
|
|
errtype.exception_data.exception_info.fpinst2);
|
2015-02-17 23:15:04 +00:00
|
|
|
break;
|
2017-01-29 16:46:23 +00:00
|
|
|
case ExceptionType::Undefined:
|
|
|
|
break; // Not logging exception_info for this case
|
2015-02-17 23:15:04 +00:00
|
|
|
}
|
2018-06-29 11:18:07 +00:00
|
|
|
LOG_CRITICAL(Service_ERR, "Datetime: {}", GetCurrentSystemTime());
|
2015-02-17 23:15:04 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2016-10-02 08:04:50 +00:00
|
|
|
case FatalErrType::ResultFailure: {
|
2017-12-04 19:03:11 +00:00
|
|
|
const auto& errtype = errinfo.result_failure;
|
2015-02-17 23:15:04 +00:00
|
|
|
|
2016-10-02 08:04:50 +00:00
|
|
|
// Failure Message
|
2018-06-29 11:18:07 +00:00
|
|
|
LOG_CRITICAL(Service_ERR, "Failure Message: {}", errtype.message);
|
|
|
|
LOG_CRITICAL(Service_ERR, "Datetime: {}", GetCurrentSystemTime());
|
2015-02-17 23:15:04 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2016-10-02 08:04:50 +00:00
|
|
|
} // switch FatalErrType
|
|
|
|
|
2017-12-04 19:03:11 +00:00
|
|
|
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
|
|
|
rb.Push(RESULT_SUCCESS);
|
2015-02-17 23:15:04 +00:00
|
|
|
}
|
|
|
|
|
2018-10-05 14:59:43 +00:00
|
|
|
ERR_F::ERR_F(Core::System& system) : ServiceFramework("err:f", 1), system(system) {
|
2017-12-04 19:03:11 +00:00
|
|
|
static const FunctionInfo functions[] = {
|
|
|
|
{0x00010800, &ERR_F::ThrowFatalError, "ThrowFatalError"},
|
|
|
|
{0x00020042, nullptr, "SetUserString"},
|
|
|
|
};
|
|
|
|
RegisterHandlers(functions);
|
|
|
|
}
|
|
|
|
|
|
|
|
ERR_F::~ERR_F() = default;
|
2014-11-02 03:06:13 +00:00
|
|
|
|
2018-10-05 14:59:43 +00:00
|
|
|
void InstallInterfaces(Core::System& system) {
|
|
|
|
auto errf = std::make_shared<ERR_F>(system);
|
2018-10-12 23:00:16 +00:00
|
|
|
errf->InstallAsNamedPort(system.Kernel());
|
2014-12-21 19:52:10 +00:00
|
|
|
}
|
2014-11-19 08:49:13 +00:00
|
|
|
|
2018-09-22 12:23:08 +00:00
|
|
|
} // namespace Service::ERR
|