2014-11-02 04:06:13 +01:00
|
|
|
// Copyright 2014 Citra Emulator Project
|
2014-12-17 06:38:14 +01:00
|
|
|
// Licensed under GPLv2 or any later version
|
2014-11-02 04:06:13 +01:00
|
|
|
// Refer to the license.txt file included.
|
|
|
|
|
2016-02-02 07:17:41 +01:00
|
|
|
#include "common/bit_field.h"
|
|
|
|
#include "common/common_types.h"
|
2015-05-06 09:06:12 +02:00
|
|
|
#include "common/logging/log.h"
|
2016-09-21 08:52:38 +02:00
|
|
|
#include "core/hle/service/err_f.h"
|
2015-05-06 09:06:12 +02:00
|
|
|
|
2014-11-02 04:06:13 +01:00
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Namespace ERR_F
|
|
|
|
|
|
|
|
namespace ERR_F {
|
|
|
|
|
2015-02-18 00:15:04 +01:00
|
|
|
enum {
|
|
|
|
ErrSpecifier0 = 0,
|
|
|
|
ErrSpecifier1 = 1,
|
|
|
|
ErrSpecifier3 = 3,
|
|
|
|
ErrSpecifier4 = 4,
|
|
|
|
};
|
|
|
|
|
|
|
|
// This is used instead of ResultCode from result.h
|
|
|
|
// because we can't have non-trivial data members in unions.
|
|
|
|
union RSL {
|
|
|
|
u32 raw;
|
|
|
|
|
|
|
|
BitField<0, 10, u32> description;
|
|
|
|
BitField<10, 8, u32> module;
|
|
|
|
BitField<21, 6, u32> summary;
|
|
|
|
BitField<27, 5, u32> level;
|
|
|
|
};
|
|
|
|
|
|
|
|
union ErrInfo {
|
|
|
|
u8 specifier;
|
|
|
|
|
|
|
|
struct {
|
2016-09-18 02:38:01 +02:00
|
|
|
u8 specifier; // 0x0
|
|
|
|
u8 rev_high; // 0x1
|
|
|
|
u16 rev_low; // 0x2
|
|
|
|
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
|
2015-02-18 00:15:04 +01:00
|
|
|
} errtype1;
|
|
|
|
|
|
|
|
struct {
|
2016-09-18 02:38:01 +02:00
|
|
|
u8 specifier; // 0x0
|
|
|
|
u8 rev_high; // 0x1
|
|
|
|
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
|
2015-02-18 00:15:04 +01:00
|
|
|
} errtype3;
|
|
|
|
|
|
|
|
struct {
|
2016-09-18 02:38:01 +02:00
|
|
|
u8 specifier; // 0x0
|
|
|
|
u8 rev_high; // 0x1
|
|
|
|
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
|
2015-02-18 00:15:04 +01:00
|
|
|
} errtype4;
|
|
|
|
};
|
|
|
|
|
2016-09-18 02:38:01 +02:00
|
|
|
enum { PrefetchAbort = 0, DataAbort = 1, UndefInstr = 2, VectorFP = 3 };
|
2015-02-18 00:15:04 +01:00
|
|
|
|
|
|
|
static std::string GetErrInfo3Type(u8 type_code) {
|
|
|
|
switch (type_code) {
|
2016-09-18 02:38:01 +02:00
|
|
|
case PrefetchAbort:
|
|
|
|
return "Prefetch Abort";
|
|
|
|
case DataAbort:
|
|
|
|
return "Data Abort";
|
|
|
|
case UndefInstr:
|
|
|
|
return "Undefined Instruction";
|
|
|
|
case VectorFP:
|
|
|
|
return "Vector Floating Point";
|
|
|
|
default:
|
|
|
|
return "unknown";
|
2015-02-18 00:15:04 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void ThrowFatalError(Service::Interface* self) {
|
|
|
|
u32* cmd_buff = Kernel::GetCommandBuffer();
|
|
|
|
|
|
|
|
LOG_CRITICAL(Service_ERR, "Fatal error!");
|
|
|
|
const ErrInfo* errinfo = reinterpret_cast<ErrInfo*>(&cmd_buff[1]);
|
|
|
|
|
|
|
|
switch (errinfo->specifier) {
|
|
|
|
case ErrSpecifier0:
|
2016-09-18 02:38:01 +02:00
|
|
|
case ErrSpecifier1: {
|
2015-02-18 00:15:04 +01:00
|
|
|
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);
|
2016-09-18 02:38:01 +02:00
|
|
|
LOG_CRITICAL(Service_ERR, " Level: %u", errtype.result_code.level.Value());
|
2015-02-18 00:15:04 +01:00
|
|
|
LOG_CRITICAL(Service_ERR, " Summary: %u", errtype.result_code.summary.Value());
|
2016-09-18 02:38:01 +02:00
|
|
|
LOG_CRITICAL(Service_ERR, " Module: %u", errtype.result_code.module.Value());
|
|
|
|
LOG_CRITICAL(Service_ERR, " Desc: %u", errtype.result_code.description.Value());
|
2015-02-18 00:15:04 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2016-09-18 02:38:01 +02:00
|
|
|
case ErrSpecifier3: {
|
2015-02-18 00:15:04 +01:00
|
|
|
const auto& errtype = errinfo->errtype3;
|
|
|
|
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, "TYPE: %s", GetErrInfo3Type(errtype.error_type).c_str());
|
|
|
|
|
|
|
|
LOG_CRITICAL(Service_ERR, "PC: 0x%08X", errtype.pc);
|
|
|
|
LOG_CRITICAL(Service_ERR, "LR: 0x%08X", errtype.lr);
|
|
|
|
LOG_CRITICAL(Service_ERR, "SP: 0x%08X", errtype.sp);
|
|
|
|
LOG_CRITICAL(Service_ERR, "CPSR: 0x%08X", errtype.cpsr);
|
|
|
|
|
|
|
|
switch (errtype.error_type) {
|
|
|
|
case PrefetchAbort:
|
|
|
|
case DataAbort:
|
|
|
|
LOG_CRITICAL(Service_ERR, "Fault Address: 0x%08X", errtype.fault_addr);
|
|
|
|
LOG_CRITICAL(Service_ERR, "Fault Status Register: 0x%08X", errtype.fault_status_reg);
|
|
|
|
break;
|
|
|
|
case VectorFP:
|
|
|
|
LOG_CRITICAL(Service_ERR, "FPEXC: 0x%08X", errtype.fpexc);
|
|
|
|
LOG_CRITICAL(Service_ERR, "FINST: 0x%08X", errtype.finst);
|
|
|
|
LOG_CRITICAL(Service_ERR, "FINST2: 0x%08X", errtype.finst2);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2016-09-18 02:38:01 +02:00
|
|
|
case ErrSpecifier4: {
|
2015-02-18 00:15:04 +01:00
|
|
|
const auto& errtype = errinfo->errtype4;
|
|
|
|
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);
|
2016-09-18 02:38:01 +02:00
|
|
|
LOG_CRITICAL(Service_ERR, " Level: %u", errtype.result_code.level.Value());
|
2015-02-18 00:15:04 +01:00
|
|
|
LOG_CRITICAL(Service_ERR, " Summary: %u", errtype.result_code.summary.Value());
|
2016-09-18 02:38:01 +02:00
|
|
|
LOG_CRITICAL(Service_ERR, " Module: %u", errtype.result_code.module.Value());
|
|
|
|
LOG_CRITICAL(Service_ERR, " Desc: %u", errtype.result_code.description.Value());
|
2015-02-18 00:15:04 +01:00
|
|
|
|
|
|
|
LOG_CRITICAL(Service_ERR, "%s", errtype.debug_string1);
|
|
|
|
LOG_CRITICAL(Service_ERR, "%s", errtype.debug_string2);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
cmd_buff[1] = 0; // No error
|
|
|
|
}
|
|
|
|
|
2016-09-19 03:01:46 +02:00
|
|
|
const Interface::FunctionInfo FunctionTable[] = {
|
|
|
|
{0x00010800, ThrowFatalError, "ThrowFatalError"},
|
|
|
|
};
|
2014-11-02 04:06:13 +01:00
|
|
|
|
2014-12-21 20:52:10 +01:00
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Interface class
|
2014-11-19 09:49:13 +01:00
|
|
|
|
2014-12-21 20:52:10 +01:00
|
|
|
Interface::Interface() {
|
2015-01-30 19:56:49 +01:00
|
|
|
Register(FunctionTable);
|
2014-12-21 20:52:10 +01:00
|
|
|
}
|
2014-11-19 09:49:13 +01:00
|
|
|
|
2014-11-02 04:06:13 +01:00
|
|
|
} // namespace
|