24 changed files with 697 additions and 428 deletions
-
1src/core/CMakeLists.txt
-
34src/core/arm/skyeye_common/armdefs.h
-
18src/core/arm/skyeye_common/armemu.h
-
15src/core/hle/kernel/address_arbiter.cpp
-
2src/core/hle/kernel/address_arbiter.h
-
176src/core/hle/kernel/archive.cpp
-
23src/core/hle/kernel/archive.h
-
43src/core/hle/kernel/event.cpp
-
12src/core/hle/kernel/event.h
-
44src/core/hle/kernel/kernel.h
-
35src/core/hle/kernel/mutex.cpp
-
3src/core/hle/kernel/mutex.h
-
43src/core/hle/kernel/shared_memory.cpp
-
5src/core/hle/kernel/shared_memory.h
-
78src/core/hle/kernel/thread.cpp
-
7src/core/hle/kernel/thread.h
-
400src/core/hle/result.h
-
66src/core/hle/service/fs_user.cpp
-
17src/core/hle/service/gsp_gpu.cpp
-
5src/core/hle/service/hid_user.cpp
-
2src/core/hle/service/service.cpp
-
22src/core/hle/service/service.h
-
6src/core/hle/service/srv.cpp
-
68src/core/hle/svc.cpp
@ -0,0 +1,400 @@ |
|||||
|
// Copyright 2014 Citra Emulator Project |
||||
|
// Licensed under GPLv2 |
||||
|
// Refer to the license.txt file included. |
||||
|
|
||||
|
#pragma once |
||||
|
|
||||
|
#include <cassert> |
||||
|
#include <cstddef> |
||||
|
#include <type_traits> |
||||
|
#include <utility> |
||||
|
|
||||
|
#include "common/common_types.h" |
||||
|
#include "common/bit_field.h" |
||||
|
|
||||
|
// All the constants in this file come from http://3dbrew.org/wiki/Error_codes |
||||
|
|
||||
|
/// Detailed description of the error. This listing is likely incomplete. |
||||
|
enum class ErrorDescription : u32 { |
||||
|
Success = 0, |
||||
|
InvalidSection = 1000, |
||||
|
TooLarge = 1001, |
||||
|
NotAuthorized = 1002, |
||||
|
AlreadyDone = 1003, |
||||
|
InvalidSize = 1004, |
||||
|
InvalidEnumValue = 1005, |
||||
|
InvalidCombination = 1006, |
||||
|
NoData = 1007, |
||||
|
Busy = 1008, |
||||
|
MisalignedAddress = 1009, |
||||
|
MisalignedSize = 1010, |
||||
|
OutOfMemory = 1011, |
||||
|
NotImplemented = 1012, |
||||
|
InvalidAddress = 1013, |
||||
|
InvalidPointer = 1014, |
||||
|
InvalidHandle = 1015, |
||||
|
NotInitialized = 1016, |
||||
|
AlreadyInitialized = 1017, |
||||
|
NotFound = 1018, |
||||
|
CancelRequested = 1019, |
||||
|
AlreadyExists = 1020, |
||||
|
OutOfRange = 1021, |
||||
|
Timeout = 1022, |
||||
|
InvalidResultValue = 1023, |
||||
|
}; |
||||
|
|
||||
|
/** |
||||
|
* Identifies the module which caused the error. Error codes can be propagated through a call |
||||
|
* chain, meaning that this doesn't always correspond to the module where the API call made is |
||||
|
* contained. |
||||
|
*/ |
||||
|
enum class ErrorModule : u32 { |
||||
|
Common = 0, |
||||
|
Kernel = 1, |
||||
|
Util = 2, |
||||
|
FileServer = 3, |
||||
|
LoaderServer = 4, |
||||
|
TCB = 5, |
||||
|
OS = 6, |
||||
|
DBG = 7, |
||||
|
DMNT = 8, |
||||
|
PDN = 9, |
||||
|
GX = 10, |
||||
|
I2C = 11, |
||||
|
GPIO = 12, |
||||
|
DD = 13, |
||||
|
CODEC = 14, |
||||
|
SPI = 15, |
||||
|
PXI = 16, |
||||
|
FS = 17, |
||||
|
DI = 18, |
||||
|
HID = 19, |
||||
|
CAM = 20, |
||||
|
PI = 21, |
||||
|
PM = 22, |
||||
|
PM_LOW = 23, |
||||
|
FSI = 24, |
||||
|
SRV = 25, |
||||
|
NDM = 26, |
||||
|
NWM = 27, |
||||
|
SOC = 28, |
||||
|
LDR = 29, |
||||
|
ACC = 30, |
||||
|
RomFS = 31, |
||||
|
AM = 32, |
||||
|
HIO = 33, |
||||
|
Updater = 34, |
||||
|
MIC = 35, |
||||
|
FND = 36, |
||||
|
MP = 37, |
||||
|
MPWL = 38, |
||||
|
AC = 39, |
||||
|
HTTP = 40, |
||||
|
DSP = 41, |
||||
|
SND = 42, |
||||
|
DLP = 43, |
||||
|
HIO_LOW = 44, |
||||
|
CSND = 45, |
||||
|
SSL = 46, |
||||
|
AM_LOW = 47, |
||||
|
NEX = 48, |
||||
|
Friends = 49, |
||||
|
RDT = 50, |
||||
|
Applet = 51, |
||||
|
NIM = 52, |
||||
|
PTM = 53, |
||||
|
MIDI = 54, |
||||
|
MC = 55, |
||||
|
SWC = 56, |
||||
|
FatFS = 57, |
||||
|
NGC = 58, |
||||
|
CARD = 59, |
||||
|
CARDNOR = 60, |
||||
|
SDMC = 61, |
||||
|
BOSS = 62, |
||||
|
DBM = 63, |
||||
|
Config = 64, |
||||
|
PS = 65, |
||||
|
CEC = 66, |
||||
|
IR = 67, |
||||
|
UDS = 68, |
||||
|
PL = 69, |
||||
|
CUP = 70, |
||||
|
Gyroscope = 71, |
||||
|
MCU = 72, |
||||
|
NS = 73, |
||||
|
News = 74, |
||||
|
RO_1 = 75, |
||||
|
GD = 76, |
||||
|
CardSPI = 77, |
||||
|
EC = 78, |
||||
|
RO_2 = 79, |
||||
|
WebBrowser = 80, |
||||
|
Test = 81, |
||||
|
ENC = 82, |
||||
|
PIA = 83, |
||||
|
|
||||
|
Application = 254, |
||||
|
InvalidResult = 255 |
||||
|
}; |
||||
|
|
||||
|
/// A less specific error cause. |
||||
|
enum class ErrorSummary : u32 { |
||||
|
Success = 0, |
||||
|
NothingHappened = 1, |
||||
|
WouldBlock = 2, |
||||
|
OutOfResource = 3, ///< There are no more kernel resources (memory, table slots) to |
||||
|
///< execute the operation. |
||||
|
NotFound = 4, ///< A file or resource was not found. |
||||
|
InvalidState = 5, |
||||
|
NotSupported = 6, ///< The operation is not supported or not implemented. |
||||
|
InvalidArgument = 7, ///< Returned when a passed argument is invalid in the current runtime |
||||
|
///< context. (Invalid handle, out-of-bounds pointer or size, etc.) |
||||
|
WrongArgument = 8, ///< Returned when a passed argument is in an incorrect format for use |
||||
|
///< with the function. (E.g. Invalid enum value) |
||||
|
Canceled = 9, |
||||
|
StatusChanged = 10, |
||||
|
Internal = 11, |
||||
|
|
||||
|
InvalidResult = 63 |
||||
|
}; |
||||
|
|
||||
|
/// The severity of the error. |
||||
|
enum class ErrorLevel : u32 { |
||||
|
Success = 0, |
||||
|
Info = 1, |
||||
|
|
||||
|
Status = 25, |
||||
|
Temporary = 26, |
||||
|
Permanent = 27, |
||||
|
Usage = 28, |
||||
|
Reinitialize = 29, |
||||
|
Reset = 30, |
||||
|
Fatal = 31 |
||||
|
}; |
||||
|
|
||||
|
/// Encapsulates a CTR-OS error code, allowing it to be separated into its constituent fields. |
||||
|
union ResultCode { |
||||
|
u32 raw; |
||||
|
|
||||
|
BitField<0, 10, ErrorDescription> description; |
||||
|
BitField<10, 8, ErrorModule> module; |
||||
|
|
||||
|
BitField<21, 6, ErrorSummary> summary; |
||||
|
BitField<27, 5, ErrorLevel> level; |
||||
|
|
||||
|
// The last bit of `level` is checked by apps and the kernel to determine if a result code is an error |
||||
|
BitField<31, 1, u32> is_error; |
||||
|
|
||||
|
explicit ResultCode(u32 raw) : raw(raw) {} |
||||
|
ResultCode(ErrorDescription description_, ErrorModule module_, |
||||
|
ErrorSummary summary_, ErrorLevel level_) : raw(0) { |
||||
|
description = description_; |
||||
|
module = module_; |
||||
|
summary = summary_; |
||||
|
level = level_; |
||||
|
} |
||||
|
|
||||
|
ResultCode& operator=(const ResultCode& o) { raw = o.raw; return *this; } |
||||
|
|
||||
|
bool IsSuccess() const { |
||||
|
return is_error == 0; |
||||
|
} |
||||
|
|
||||
|
bool IsError() const { |
||||
|
return is_error == 1; |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
inline bool operator==(const ResultCode a, const ResultCode b) { |
||||
|
return a.raw == b.raw; |
||||
|
} |
||||
|
|
||||
|
inline bool operator!=(const ResultCode a, const ResultCode b) { |
||||
|
return a.raw != b.raw; |
||||
|
} |
||||
|
|
||||
|
// Convenience functions for creating some common kinds of errors: |
||||
|
|
||||
|
/// The default success `ResultCode`. |
||||
|
const ResultCode RESULT_SUCCESS(0); |
||||
|
|
||||
|
/// Might be returned instead of a dummy success for unimplemented APIs. |
||||
|
inline ResultCode UnimplementedFunction(ErrorModule module) { |
||||
|
return ResultCode(ErrorDescription::NotImplemented, module, |
||||
|
ErrorSummary::NotSupported, ErrorLevel::Permanent); |
||||
|
} |
||||
|
/// Returned when a function is passed an invalid handle. |
||||
|
inline ResultCode InvalidHandle(ErrorModule module) { |
||||
|
return ResultCode(ErrorDescription::InvalidHandle, module, |
||||
|
ErrorSummary::InvalidArgument, ErrorLevel::Permanent); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* This is an optional value type. It holds a `ResultCode` and, if that code is a success code, |
||||
|
* also holds a result of type `T`. If the code is an error code then trying to access the inner |
||||
|
* value fails, thus ensuring that the ResultCode of functions is always checked properly before |
||||
|
* their return value is used. It is similar in concept to the `std::optional` type |
||||
|
* (http://en.cppreference.com/w/cpp/experimental/optional) originally proposed for inclusion in |
||||
|
* C++14, or the `Result` type in Rust (http://doc.rust-lang.org/std/result/index.html). |
||||
|
* |
||||
|
* An example of how it could be used: |
||||
|
* \code |
||||
|
* ResultVal<int> Frobnicate(float strength) { |
||||
|
* if (strength < 0.f || strength > 1.0f) { |
||||
|
* // Can't frobnicate too weakly or too strongly |
||||
|
* return ResultCode(ErrorDescription::OutOfRange, ErrorModule::Common, |
||||
|
* ErrorSummary::InvalidArgument, ErrorLevel::Permanent); |
||||
|
* } else { |
||||
|
* // Frobnicated! Give caller a cookie |
||||
|
* return MakeResult<int>(42); |
||||
|
* } |
||||
|
* } |
||||
|
* \endcode |
||||
|
* |
||||
|
* \code |
||||
|
* ResultVal<int> frob_result = Frobnicate(0.75f); |
||||
|
* if (frob_result) { |
||||
|
* // Frobbed ok |
||||
|
* printf("My cookie is %d\n", *frob_result); |
||||
|
* } else { |
||||
|
* printf("Guess I overdid it. :( Error code: %ux\n", frob_result.code().hex); |
||||
|
* } |
||||
|
* \endcode |
||||
|
*/ |
||||
|
template <typename T> |
||||
|
class ResultVal { |
||||
|
public: |
||||
|
/// Constructs an empty `ResultVal` with the given error code. The code must not be a success code. |
||||
|
ResultVal(ResultCode error_code = ResultCode(-1)) |
||||
|
: result_code(error_code) |
||||
|
{ |
||||
|
assert(error_code.IsError()); |
||||
|
UpdateDebugPtr(); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Similar to the non-member function `MakeResult`, with the exception that you can manually |
||||
|
* specify the success code. `success_code` must not be an error code. |
||||
|
*/ |
||||
|
template <typename... Args> |
||||
|
static ResultVal WithCode(ResultCode success_code, Args&&... args) { |
||||
|
ResultVal<T> result; |
||||
|
result.emplace(success_code, std::forward<Args>(args)...); |
||||
|
return result; |
||||
|
} |
||||
|
|
||||
|
ResultVal(const ResultVal& o) |
||||
|
: result_code(o.result_code) |
||||
|
{ |
||||
|
if (!o.empty()) { |
||||
|
new (&storage) T(*o.GetPointer()); |
||||
|
} |
||||
|
UpdateDebugPtr(); |
||||
|
} |
||||
|
|
||||
|
ResultVal(ResultVal&& o) |
||||
|
: result_code(o.result_code) |
||||
|
{ |
||||
|
if (!o.empty()) { |
||||
|
new (&storage) T(std::move(*o.GetPointer())); |
||||
|
} |
||||
|
UpdateDebugPtr(); |
||||
|
} |
||||
|
|
||||
|
~ResultVal() { |
||||
|
if (!empty()) { |
||||
|
GetPointer()->~T(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
ResultVal& operator=(const ResultVal& o) { |
||||
|
if (*this) { |
||||
|
if (o) { |
||||
|
*GetPointer() = *o.GetPointer(); |
||||
|
} else { |
||||
|
GetPointer()->~T(); |
||||
|
} |
||||
|
} else { |
||||
|
if (o) { |
||||
|
new (&storage) T(*o.GetPointer()); |
||||
|
} |
||||
|
} |
||||
|
result_code = o.result_code; |
||||
|
UpdateDebugPtr(); |
||||
|
|
||||
|
return *this; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Replaces the current result with a new constructed result value in-place. The code must not |
||||
|
* be an error code. |
||||
|
*/ |
||||
|
template <typename... Args> |
||||
|
void emplace(ResultCode success_code, Args&&... args) { |
||||
|
assert(success_code.IsSuccess()); |
||||
|
if (!empty()) { |
||||
|
GetPointer()->~T(); |
||||
|
} |
||||
|
new (&storage) T(std::forward<Args>(args)...); |
||||
|
result_code = success_code; |
||||
|
UpdateDebugPtr(); |
||||
|
} |
||||
|
|
||||
|
/// Returns true if the `ResultVal` contains an error code and no value. |
||||
|
bool empty() const { return result_code.IsError(); } |
||||
|
|
||||
|
/// Returns true if the `ResultVal` contains a return value. |
||||
|
bool Succeeded() const { return result_code.IsSuccess(); } |
||||
|
/// Returns true if the `ResultVal` contains an error code and no value. |
||||
|
bool Failed() const { return empty(); } |
||||
|
|
||||
|
ResultCode Code() const { return result_code; } |
||||
|
|
||||
|
const T& operator* () const { return *GetPointer(); } |
||||
|
T& operator* () { return *GetPointer(); } |
||||
|
const T* operator->() const { return GetPointer(); } |
||||
|
T* operator->() { return GetPointer(); } |
||||
|
|
||||
|
/// Returns the value contained in this `ResultVal`, or the supplied default if it is missing. |
||||
|
template <typename U> |
||||
|
T ValueOr(U&& value) const { |
||||
|
return !empty() ? *GetPointer() : std::move(value); |
||||
|
} |
||||
|
|
||||
|
private: |
||||
|
typedef typename std::aligned_storage<sizeof(T), std::alignment_of<T>::value>::type StorageType; |
||||
|
|
||||
|
StorageType storage; |
||||
|
ResultCode result_code; |
||||
|
#if _DEBUG |
||||
|
// The purpose of this pointer is to aid inspecting the type with a debugger, eliminating the |
||||
|
// need to cast `storage` to a pointer or pay attention to `result_code`. |
||||
|
const T* debug_ptr; |
||||
|
#endif |
||||
|
|
||||
|
void UpdateDebugPtr() { |
||||
|
#if _DEBUG |
||||
|
debug_ptr = empty() ? nullptr : static_cast<const T*>(static_cast<const void*>(&storage)); |
||||
|
#endif |
||||
|
} |
||||
|
|
||||
|
const T* GetPointer() const { |
||||
|
assert(!empty()); |
||||
|
return static_cast<const T*>(static_cast<const void*>(&storage)); |
||||
|
} |
||||
|
|
||||
|
T* GetPointer() { |
||||
|
assert(!empty()); |
||||
|
return static_cast<T*>(static_cast<void*>(&storage)); |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
/** |
||||
|
* This function is a helper used to construct `ResultVal`s. It receives the arguments to construct |
||||
|
* `T` with and creates a success `ResultVal` contained the constructed value. |
||||
|
*/ |
||||
|
template <typename T, typename... Args> |
||||
|
ResultVal<T> MakeResult(Args&&... args) { |
||||
|
return ResultVal<T>::WithCode(RESULT_SUCCESS, std::forward<Args>(args)...); |
||||
|
} |
||||
Write
Preview
Loading…
Cancel
Save
Reference in new issue