1 // Copyright 2014 Citra Emulator Project
2 // Licensed under GPLv2 or any later version
3 // Refer to the license.txt file included.
4 
5 #include <array>
6 #include <chrono>
7 #include <iomanip>
8 #include <sstream>
9 #include "common/archives.h"
10 #include "common/bit_field.h"
11 #include "common/common_types.h"
12 #include "common/logging/log.h"
13 #include "core/core.h"
14 #include "core/hle/ipc.h"
15 #include "core/hle/ipc_helpers.h"
16 #include "core/hle/result.h"
17 #include "core/hle/service/err_f.h"
18 #undef exception_info // We use 'exception_info' as a plain identifier, but MSVC defines this in one
19                       // of its many headers.
20 
21 SERIALIZE_EXPORT_IMPL(Service::ERR::ERR_F)
22 
23 namespace boost::serialization {
24 template <class Archive>
load_construct_data(Archive & ar,Service::ERR::ERR_F * t,const unsigned int)25 void load_construct_data(Archive& ar, Service::ERR::ERR_F* t, const unsigned int) {
26     ::new (t) Service::ERR::ERR_F(Core::Global<Core::System>());
27 }
28 
29 template void load_construct_data<iarchive>(iarchive& ar, Service::ERR::ERR_F* t,
30                                             const unsigned int);
31 } // namespace boost::serialization
32 
33 namespace Service::ERR {
34 
35 enum class FatalErrType : u32 {
36     Generic = 0,
37     Corrupted = 1,
38     CardRemoved = 2,
39     Exception = 3,
40     ResultFailure = 4,
41     Logged = 5,
42 };
43 
44 enum class ExceptionType : u32 {
45     PrefetchAbort = 0,
46     DataAbort = 1,
47     Undefined = 2,
48     VectorFP = 3,
49 };
50 
51 struct ExceptionInfo {
52     u8 exception_type;
53     INSERT_PADDING_BYTES(3);
54     u32 sr;
55     u32 ar;
56     u32 fpexc;
57     u32 fpinst;
58     u32 fpinst2;
59 };
60 static_assert(sizeof(ExceptionInfo) == 0x18, "ExceptionInfo struct has incorrect size");
61 
62 struct ExceptionContext final {
63     std::array<u32, 16> arm_regs;
64     u32 cpsr;
65 };
66 static_assert(sizeof(ExceptionContext) == 0x44, "ExceptionContext struct has incorrect size");
67 
68 struct ExceptionData {
69     ExceptionInfo exception_info;
70     ExceptionContext exception_context;
71     INSERT_PADDING_WORDS(1);
72 };
73 static_assert(sizeof(ExceptionData) == 0x60, "ExceptionData struct has incorrect size");
74 
75 struct ErrInfo {
76     struct ErrInfoCommon {
77         u8 specifier;          // 0x0
78         u8 rev_high;           // 0x1
79         u16 rev_low;           // 0x2
80         u32 result_code;       // 0x4
81         u32 pc_address;        // 0x8
82         u32 pid;               // 0xC
83         u32 title_id_low;      // 0x10
84         u32 title_id_high;     // 0x14
85         u32 app_title_id_low;  // 0x18
86         u32 app_title_id_high; // 0x1C
87     } errinfo_common;
88     static_assert(sizeof(ErrInfoCommon) == 0x20, "ErrInfoCommon struct has incorrect size");
89 
90     union {
91         struct {
92             char data[0x60]; // 0x20
93         } generic;
94 
95         struct {
96             ExceptionData exception_data; // 0x20
97         } exception;
98 
99         struct {
100             char message[0x60]; // 0x20
101         } result_failure;
102     };
103 };
104 
GetErrType(u8 type_code)105 static std::string GetErrType(u8 type_code) {
106     switch (static_cast<FatalErrType>(type_code)) {
107     case FatalErrType::Generic:
108         return "Generic";
109     case FatalErrType::Corrupted:
110         return "Corrupted";
111     case FatalErrType::CardRemoved:
112         return "CardRemoved";
113     case FatalErrType::Exception:
114         return "Exception";
115     case FatalErrType::ResultFailure:
116         return "ResultFailure";
117     case FatalErrType::Logged:
118         return "Logged";
119     default:
120         return "Unknown Error Type";
121     }
122 }
123 
GetExceptionType(u8 type_code)124 static std::string GetExceptionType(u8 type_code) {
125     switch (static_cast<ExceptionType>(type_code)) {
126     case ExceptionType::PrefetchAbort:
127         return "Prefetch Abort";
128     case ExceptionType::DataAbort:
129         return "Data Abort";
130     case ExceptionType::Undefined:
131         return "Undefined Exception";
132     case ExceptionType::VectorFP:
133         return "Vector Floating Point Exception";
134     default:
135         return "Unknown Exception Type";
136     }
137 }
138 
GetCurrentSystemTime()139 static std::string GetCurrentSystemTime() {
140     auto now = std::chrono::system_clock::now();
141     auto time = std::chrono::system_clock::to_time_t(now);
142 
143     std::stringstream time_stream;
144     time_stream << std::put_time(std::localtime(&time), "%Y/%m/%d %H:%M:%S");
145     return time_stream.str();
146 }
147 
LogGenericInfo(const ErrInfo::ErrInfoCommon & errinfo_common)148 static void LogGenericInfo(const ErrInfo::ErrInfoCommon& errinfo_common) {
149     LOG_CRITICAL(Service_ERR, "PID: 0x{:08X}", errinfo_common.pid);
150     LOG_CRITICAL(Service_ERR, "REV: 0x{:08X}_0x{:08X}", errinfo_common.rev_high,
151                  errinfo_common.rev_low);
152     LOG_CRITICAL(Service_ERR, "TID: 0x{:08X}_0x{:08X}", errinfo_common.title_id_high,
153                  errinfo_common.title_id_low);
154     LOG_CRITICAL(Service_ERR, "AID: 0x{:08X}_0x{:08X}", errinfo_common.app_title_id_high,
155                  errinfo_common.app_title_id_low);
156     LOG_CRITICAL(Service_ERR, "ADR: 0x{:08X}", errinfo_common.pc_address);
157 
158     ResultCode result_code{errinfo_common.result_code};
159     LOG_CRITICAL(Service_ERR, "RSL: 0x{:08X}", result_code.raw);
160     LOG_CRITICAL(Service_ERR, "  Level: {}", static_cast<u32>(result_code.level.Value()));
161     LOG_CRITICAL(Service_ERR, "  Summary: {}", static_cast<u32>(result_code.summary.Value()));
162     LOG_CRITICAL(Service_ERR, "  Module: {}", static_cast<u32>(result_code.module.Value()));
163     LOG_CRITICAL(Service_ERR, "  Desc: {}", static_cast<u32>(result_code.description.Value()));
164 }
165 
ThrowFatalError(Kernel::HLERequestContext & ctx)166 void ERR_F::ThrowFatalError(Kernel::HLERequestContext& ctx) {
167     IPC::RequestParser rp(ctx, 1, 32, 0);
168 
169     LOG_CRITICAL(Service_ERR, "Fatal error");
170     const ErrInfo errinfo = rp.PopRaw<ErrInfo>();
171     LOG_CRITICAL(Service_ERR, "Fatal error type: {}", GetErrType(errinfo.errinfo_common.specifier));
172     system.SetStatus(Core::System::ResultStatus::ErrorUnknown);
173 
174     // Generic Info
175     LogGenericInfo(errinfo.errinfo_common);
176 
177     switch (static_cast<FatalErrType>(errinfo.errinfo_common.specifier)) {
178     case FatalErrType::Generic:
179     case FatalErrType::Corrupted:
180     case FatalErrType::CardRemoved:
181     case FatalErrType::Logged: {
182         LOG_CRITICAL(Service_ERR, "Datetime: {}", GetCurrentSystemTime());
183         break;
184     }
185     case FatalErrType::Exception: {
186         const auto& errtype = errinfo.exception;
187 
188         // Register Info
189         LOG_CRITICAL(Service_ERR, "ARM Registers:");
190         for (u32 index = 0; index < errtype.exception_data.exception_context.arm_regs.size();
191              ++index) {
192             if (index < 13) {
193                 LOG_DEBUG(Service_ERR, "r{}=0x{:08X}", index,
194                           errtype.exception_data.exception_context.arm_regs.at(index));
195             } else if (index == 13) {
196                 LOG_CRITICAL(Service_ERR, "SP=0x{:08X}",
197                              errtype.exception_data.exception_context.arm_regs.at(index));
198             } else if (index == 14) {
199                 LOG_CRITICAL(Service_ERR, "LR=0x{:08X}",
200                              errtype.exception_data.exception_context.arm_regs.at(index));
201             } else if (index == 15) {
202                 LOG_CRITICAL(Service_ERR, "PC=0x{:08X}",
203                              errtype.exception_data.exception_context.arm_regs.at(index));
204             }
205         }
206         LOG_CRITICAL(Service_ERR, "CPSR=0x{:08X}", errtype.exception_data.exception_context.cpsr);
207 
208         // Exception Info
209         LOG_CRITICAL(Service_ERR, "EXCEPTION TYPE: {}",
210                      GetExceptionType(errtype.exception_data.exception_info.exception_type));
211         switch (static_cast<ExceptionType>(errtype.exception_data.exception_info.exception_type)) {
212         case ExceptionType::PrefetchAbort:
213             LOG_CRITICAL(Service_ERR, "IFSR: 0x{:08X}", errtype.exception_data.exception_info.sr);
214             LOG_CRITICAL(Service_ERR, "r15: 0x{:08X}", errtype.exception_data.exception_info.ar);
215             break;
216         case ExceptionType::DataAbort:
217             LOG_CRITICAL(Service_ERR, "DFSR: 0x{:08X}", errtype.exception_data.exception_info.sr);
218             LOG_CRITICAL(Service_ERR, "DFAR: 0x{:08X}", errtype.exception_data.exception_info.ar);
219             break;
220         case ExceptionType::VectorFP:
221             LOG_CRITICAL(Service_ERR, "FPEXC: 0x{:08X}",
222                          errtype.exception_data.exception_info.fpinst);
223             LOG_CRITICAL(Service_ERR, "FINST: 0x{:08X}",
224                          errtype.exception_data.exception_info.fpinst);
225             LOG_CRITICAL(Service_ERR, "FINST2: 0x{:08X}",
226                          errtype.exception_data.exception_info.fpinst2);
227             break;
228         case ExceptionType::Undefined:
229             break; // Not logging exception_info for this case
230         }
231         LOG_CRITICAL(Service_ERR, "Datetime: {}", GetCurrentSystemTime());
232         break;
233     }
234 
235     case FatalErrType::ResultFailure: {
236         const auto& errtype = errinfo.result_failure;
237 
238         // Failure Message
239         LOG_CRITICAL(Service_ERR, "Failure Message: {}", errtype.message);
240         LOG_CRITICAL(Service_ERR, "Datetime: {}", GetCurrentSystemTime());
241         break;
242     }
243 
244     } // switch FatalErrType
245 
246     IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
247     rb.Push(RESULT_SUCCESS);
248 }
249 
ERR_F(Core::System & system)250 ERR_F::ERR_F(Core::System& system) : ServiceFramework("err:f", 1), system(system) {
251     static const FunctionInfo functions[] = {
252         {0x00010800, &ERR_F::ThrowFatalError, "ThrowFatalError"},
253         {0x00020042, nullptr, "SetUserString"},
254     };
255     RegisterHandlers(functions);
256 }
257 
258 ERR_F::~ERR_F() = default;
259 
InstallInterfaces(Core::System & system)260 void InstallInterfaces(Core::System& system) {
261     auto errf = std::make_shared<ERR_F>(system);
262     errf->InstallAsNamedPort(system.Kernel());
263 }
264 
265 } // namespace Service::ERR
266