Address CR Comments #2

This commit is contained in:
◱ PixelyIon 2020-11-22 23:51:35 +05:30
parent fbf9f06244
commit 8564edcb16
16 changed files with 116 additions and 99 deletions

View File

@ -37,7 +37,6 @@ namespace skyline {
std::lock_guard guard(mtx); std::lock_guard guard(mtx);
logFile << "0|" << str << "\n"; logFile << "0|" << str << "\n";
logFile.flush();
} }
void Logger::Write(LogLevel level, std::string str) { void Logger::Write(LogLevel level, std::string str) {
@ -55,7 +54,6 @@ namespace skyline {
std::lock_guard guard(mtx); std::lock_guard guard(mtx);
logFile << "1|" << levelCharacter[static_cast<u8>(level)] << '|' << threadName << '|' << str << '\n'; logFile << "1|" << levelCharacter[static_cast<u8>(level)] << '|' << threadName << '|' << str << '\n';
logFile.flush();
} }
DeviceState::DeviceState(kernel::OS *os, std::shared_ptr<JvmManager> jvmManager, std::shared_ptr<Settings> settings, std::shared_ptr<Logger> logger) DeviceState::DeviceState(kernel::OS *os, std::shared_ptr<JvmManager> jvmManager, std::shared_ptr<Settings> settings, std::shared_ptr<Logger> logger)

View File

@ -96,7 +96,7 @@ namespace skyline {
* @note There's the exception of signed char pointers as they represent C Strings * @note There's the exception of signed char pointers as they represent C Strings
* @note This does not cover std::shared_ptr or std::unique_ptr and those will have to be explicitly casted to uintptr_t or passed through fmt::ptr * @note This does not cover std::shared_ptr or std::unique_ptr and those will have to be explicitly casted to uintptr_t or passed through fmt::ptr
*/ */
template<class T> template<typename T>
constexpr auto FmtCast(T object) { constexpr auto FmtCast(T object) {
if constexpr (std::is_pointer<T>::value) if constexpr (std::is_pointer<T>::value)
if constexpr (std::is_same<char, typename std::remove_cv<typename std::remove_pointer<T>::type>::type>::value) if constexpr (std::is_same<char, typename std::remove_cv<typename std::remove_pointer<T>::type>::type>::value)
@ -147,12 +147,12 @@ namespace skyline {
/** /**
* @brief A way to implicitly convert a pointer to uintptr_t and leave it unaffected if it isn't a pointer * @brief A way to implicitly convert a pointer to uintptr_t and leave it unaffected if it isn't a pointer
*/ */
template<class T> template<typename T>
T PointerValue(T item) { T PointerValue(T item) {
return item; return item;
} }
template<class T> template<typename T>
uintptr_t PointerValue(T *item) { uintptr_t PointerValue(T *item) {
return reinterpret_cast<uintptr_t>(item); return reinterpret_cast<uintptr_t>(item);
} }
@ -160,7 +160,7 @@ namespace skyline {
/** /**
* @brief A way to implicitly convert an integral to a pointer, if the return type is a pointer * @brief A way to implicitly convert an integral to a pointer, if the return type is a pointer
*/ */
template<class Return, class T> template<typename Return, typename T>
Return ValuePointer(T item) { Return ValuePointer(T item) {
if constexpr (std::is_pointer<Return>::value) if constexpr (std::is_pointer<Return>::value)
return reinterpret_cast<Return>(item); return reinterpret_cast<Return>(item);
@ -253,7 +253,7 @@ namespace skyline {
return result; return result;
} }
template<class Type> template<typename Type>
constexpr Type HexStringToInt(std::string_view string) { constexpr Type HexStringToInt(std::string_view string) {
if (string.size() > sizeof(Type) * 2) if (string.size() > sizeof(Type) * 2)
throw exception("String size larger than type: {} (sizeof(Type): {})", string.size(), sizeof(Type)); throw exception("String size larger than type: {} (sizeof(Type): {})", string.size(), sizeof(Type));
@ -299,7 +299,7 @@ namespace skyline {
/** /**
* @brief We want to support implicitly casting from std::string_view -> span as it is just a specialization of a data view which span is a generic form of, the opposite doesn't hold true as not all data held by a span is string data therefore the conversion isn't implicit there * @brief We want to support implicitly casting from std::string_view -> span as it is just a specialization of a data view which span is a generic form of, the opposite doesn't hold true as not all data held by a span is string data therefore the conversion isn't implicit there
*/ */
template<class Traits> template<typename Traits>
constexpr span(const std::basic_string_view<T, Traits> &string) : std::span<T, Extent>(const_cast<T *>(string.data()), string.size()) {} constexpr span(const std::basic_string_view<T, Traits> &string) : std::span<T, Extent>(const_cast<T *>(string.data()), string.size()) {}
template<typename Out> template<typename Out>
@ -375,21 +375,21 @@ namespace skyline {
/** /**
* @brief Deduction guides required for arguments to span, CTAD will fail for iterators, arrays and containers without this * @brief Deduction guides required for arguments to span, CTAD will fail for iterators, arrays and containers without this
*/ */
template<class It, class End, size_t Extent = std::dynamic_extent> template<typename It, typename End, size_t Extent = std::dynamic_extent>
span(It, End) -> span<typename std::iterator_traits<It>::value_type, Extent>; span(It, End) -> span<typename std::iterator_traits<It>::value_type, Extent>;
template<class T, size_t Size> template<typename T, size_t Size>
span(T (&)[Size]) -> span<T, Size>; span(T (&)[Size]) -> span<T, Size>;
template<class T, size_t Size> template<typename T, size_t Size>
span(std::array<T, Size> &) -> span<T, Size>; span(std::array<T, Size> &) -> span<T, Size>;
template<class T, size_t Size> template<typename T, size_t Size>
span(const std::array<T, Size> &) -> span<const T, Size>; span(const std::array<T, Size> &) -> span<const T, Size>;
template<class Container> template<typename Container>
span(Container &) -> span<typename Container::value_type>; span(Container &) -> span<typename Container::value_type>;
template<class Container> template<typename Container>
span(const Container &) -> span<const typename Container::value_type>; span(const Container &) -> span<const typename Container::value_type>;
/** /**
* @brief The Logger class is to write log output to file and logcat * @brief A wrapper around writing logs into a log file and logcat using Android Log APIs
*/ */
class Logger { class Logger {
private: private:

View File

@ -21,6 +21,9 @@ namespace skyline {
std::condition_variable produceCondition; std::condition_variable produceCondition;
public: public:
/**
* @note The internal allocation is an item larger as we require a sentinel value
*/
inline CircularQueue(size_t size) : vector((size + 1) * sizeof(Type)) {} inline CircularQueue(size_t size) : vector((size + 1) * sizeof(Type)) {}
inline CircularQueue(const CircularQueue &) = delete; inline CircularQueue(const CircularQueue &) = delete;

View File

@ -46,7 +46,7 @@ namespace skyline::signal {
void ExceptionalSignalHandler(int signal, siginfo *info, ucontext *context) { void ExceptionalSignalHandler(int signal, siginfo *info, ucontext *context) {
SignalException signalException; SignalException signalException;
signalException.signal = signal; signalException.signal = signal;
signalException.pc = context->uc_mcontext.pc; signalException.pc = reinterpret_cast<void *>(context->uc_mcontext.pc);
if (signal == SIGSEGV) if (signal == SIGSEGV)
signalException.fault = info->si_addr; signalException.fault = info->si_addr;
SignalExceptionPtr = std::make_exception_ptr(signalException); SignalExceptionPtr = std::make_exception_ptr(signalException);

View File

@ -14,14 +14,14 @@ namespace skyline::signal {
class SignalException { class SignalException {
public: public:
int signal{}; int signal{};
u64 pc{}; void* pc{};
void *fault{}; void *fault{};
inline std::string what() const { inline std::string what() const {
if (!fault) if (!fault)
return fmt::format("Signal: {} (PC: 0x{:X})", strsignal(signal), pc); return fmt::format("Signal: {} (PC: 0x{:X})", strsignal(signal), reinterpret_cast<uintptr_t>(pc));
else else
return fmt::format("Signal: {} @ 0x{:X} (PC: 0x{:X})", strsignal(signal), reinterpret_cast<uintptr_t>(fault), pc); return fmt::format("Signal: {} @ 0x{:X} (PC: 0x{:X})", strsignal(signal), reinterpret_cast<uintptr_t>(fault), reinterpret_cast<uintptr_t>(pc));
} }
}; };

View File

@ -94,7 +94,7 @@ namespace skyline::kernel::ipc {
payloadOffset = cmdArg; payloadOffset = cmdArg;
if (payload->magic != util::MakeMagic<u32>("SFCI") && (header->type != CommandType::Control && header->type != CommandType::ControlWithContext)) // SFCI is the magic in received IPC messages if (payload->magic != util::MakeMagic<u32>("SFCI") && (header->type != CommandType::Control && header->type != CommandType::ControlWithContext && header->type != CommandType::Close) && (!domain || domain->command != DomainCommand::CloseVHandle)) // SFCI is the magic in received IPC messages
state.logger->Debug("Unexpected Magic in PayloadHeader: 0x{:X}", static_cast<u32>(payload->magic)); state.logger->Debug("Unexpected Magic in PayloadHeader: 0x{:X}", static_cast<u32>(payload->magic));
pointer += constant::IpcPaddingSum - padding + cBufferLengthSize; pointer += constant::IpcPaddingSum - padding + cBufferLengthSize;

View File

@ -7,12 +7,17 @@
namespace skyline { namespace skyline {
namespace memory { namespace memory {
struct Permission { union Permission {
/** /**
* @brief Initializes all permissions to false * @brief Initializes all permissions to false
*/ */
constexpr Permission() : r(), w(), x() {} constexpr Permission() : r(), w(), x() {}
/**
* @brief Initializes permissions where the first three bits correspond to RWX
*/
constexpr explicit Permission(u8 raw) : raw(raw) {}
/** /**
* @param read If memory has read permission * @param read If memory has read permission
* @param write If memory has write permission * @param write If memory has write permission
@ -38,10 +43,14 @@ namespace skyline {
return perm; return perm;
} }
bool r; //!< The permission to read struct {
bool w; //!< The permission to write bool r : 1; //!< The permission to read
bool x; //!< The permission to execute bool w : 1; //!< The permission to write
bool x : 1; //!< The permission to execute
};
u8 raw;
}; };
static_assert(sizeof(Permission) == sizeof(u8));
/** /**
* @url https://switchbrew.org/wiki/SVC#MemoryAttribute * @url https://switchbrew.org/wiki/SVC#MemoryAttribute

View File

@ -419,7 +419,7 @@ namespace skyline::kernel::svc {
return; return;
} }
auto permission{*reinterpret_cast<memory::Permission *>(&state.ctx->gpr.w3)}; memory::Permission permission(state.ctx->gpr.w3);
if ((permission.w && !permission.r) || (permission.x && !permission.r)) { if ((permission.w && !permission.r) || (permission.x && !permission.r)) {
state.logger->Warn("svcMapSharedMemory: 'permission' invalid: {}{}{}", permission.r ? 'R' : '-', permission.w ? 'W' : '-', permission.x ? 'X' : '-'); state.logger->Warn("svcMapSharedMemory: 'permission' invalid: {}{}{}", permission.r ? 'R' : '-', permission.w ? 'W' : '-', permission.x ? 'X' : '-');
state.ctx->gpr.w0 = result::InvalidNewMemoryPermission; state.ctx->gpr.w0 = result::InvalidNewMemoryPermission;
@ -452,7 +452,7 @@ namespace skyline::kernel::svc {
return; return;
} }
auto permission{*reinterpret_cast<memory::Permission *>(&state.ctx->gpr.w3)}; memory::Permission permission(state.ctx->gpr.w3);
if ((permission.w && !permission.r) || (permission.x && !permission.r)) { if ((permission.w && !permission.r) || (permission.x && !permission.r)) {
state.logger->Warn("svcCreateTransferMemory: 'permission' invalid: {}{}{}", permission.r ? 'R' : '-', permission.w ? 'W' : '-', permission.x ? 'X' : '-'); state.logger->Warn("svcCreateTransferMemory: 'permission' invalid: {}{}{}", permission.r ? 'R' : '-', permission.w ? 'W' : '-', permission.x ? 'X' : '-');
state.ctx->gpr.w0 = result::InvalidNewMemoryPermission; state.ctx->gpr.w0 = result::InvalidNewMemoryPermission;

View File

@ -62,7 +62,7 @@ namespace skyline::kernel::type {
"MOV LR, %x2\n\t" // Store entry in Link Register so it is jumped to on return "MOV LR, %x2\n\t" // Store entry in Link Register so it is jumped to on return
"MOV X0, %x3\n\t" // Store the argument in X0 "MOV X0, %x3\n\t" // Store the argument in X0
"MOV X1, %x4\n\t" // Store the thread handle in X1, NCA applications require this "MOV X1, %x4\n\t" // Store the thread handle in X1, NCA applications require this
"MOV X2, XZR\n\t" "MOV X2, XZR\n\t" // Zero out other GP and SIMD registers, not doing this will break applications
"MOV X3, XZR\n\t" "MOV X3, XZR\n\t"
"MOV X4, XZR\n\t" "MOV X4, XZR\n\t"
"MOV X5, XZR\n\t" "MOV X5, XZR\n\t"

View File

@ -27,7 +27,7 @@ namespace skyline::loader {
u8 *base{loadInfo.base}; u8 *base{loadInfo.base};
void *entry{loadInfo.entry}; void *entry{loadInfo.entry};
state.logger->Info("Loaded nso 'rtld' at 0x{:X} (.text @ 0x{:X})", base, entry); state.logger->Info("Loaded 'rtld.nso' at 0x{:X} (.text @ 0x{:X})", base, entry);
for (const auto &nso : {"main", "subsdk0", "subsdk1", "subsdk2", "subsdk3", "subsdk4", "subsdk5", "subsdk6", "subsdk7", "sdk"}) { for (const auto &nso : {"main", "subsdk0", "subsdk1", "subsdk2", "subsdk3", "subsdk4", "subsdk5", "subsdk6", "subsdk7", "sdk"}) {
if (exeFs->FileExists(nso)) if (exeFs->FileExists(nso))

View File

@ -45,8 +45,9 @@ namespace skyline::nce {
} }
} }
void NCE::SignalHandler(int signal, siginfo *info, ucontext *context, void **tls) { void NCE::SignalHandler(int signal, siginfo *info, ucontext *ctx, void **tls) {
if (*tls) { if (*tls) {
auto &mctx{ctx->uc_mcontext};
const auto &state{*reinterpret_cast<ThreadContext *>(*tls)->state}; const auto &state{*reinterpret_cast<ThreadContext *>(*tls)->state};
if (signal != SIGINT) { if (signal != SIGINT) {
state.logger->Warn("Thread #{} has crashed due to signal: {}", state.thread->id, strsignal(signal)); state.logger->Warn("Thread #{} has crashed due to signal: {}", state.thread->id, strsignal(signal));
@ -55,15 +56,14 @@ namespace skyline::nce {
std::string trace; std::string trace;
std::string cpuContext; std::string cpuContext;
const auto &ctx{reinterpret_cast<ucontext *>(context)->uc_mcontext};
constexpr u16 instructionCount{20}; // The amount of previous instructions to print constexpr u16 instructionCount{20}; // The amount of previous instructions to print
auto offset{ctx.pc - (instructionCount * sizeof(u32)) + (2 * sizeof(u32))}; auto offset{mctx.pc - (instructionCount * sizeof(u32)) + (2 * sizeof(u32))};
span instructions(reinterpret_cast<u32 *>(offset), instructionCount); span instructions(reinterpret_cast<u32 *>(offset), instructionCount);
if (mprotect(util::AlignDown(instructions.data(), PAGE_SIZE), util::AlignUp(instructions.size_bytes(), PAGE_SIZE), PROT_READ | PROT_WRITE | PROT_EXEC) == 0) { if (mprotect(util::AlignDown(instructions.data(), PAGE_SIZE), util::AlignUp(instructions.size_bytes(), PAGE_SIZE), PROT_READ | PROT_WRITE | PROT_EXEC) == 0) {
for (auto &instruction : instructions) { for (auto &instruction : instructions) {
instruction = __builtin_bswap32(instruction); instruction = __builtin_bswap32(instruction);
if (offset == ctx.pc) if (offset == mctx.pc)
trace += fmt::format("\n-> 0x{:X} : 0x{:08X}", offset, instruction); trace += fmt::format("\n-> 0x{:X} : 0x{:08X}", offset, instruction);
else else
trace += fmt::format("\n 0x{:X} : 0x{:08X}", offset, instruction); trace += fmt::format("\n 0x{:X} : 0x{:08X}", offset, instruction);
@ -75,28 +75,28 @@ namespace skyline::nce {
state.logger->Debug("Process Trace:{}", trace); state.logger->Debug("Process Trace:{}", trace);
state.logger->Debug("Raw Instructions: 0x{}", raw); state.logger->Debug("Raw Instructions: 0x{}", raw);
} else { } else {
cpuContext += fmt::format("\nPC: 0x{:X} ('mprotect' failed with '{}')", ctx.pc, strerror(errno)); cpuContext += fmt::format("\nPC: 0x{:X} ('mprotect' failed with '{}')", mctx.pc, strerror(errno));
} }
if (ctx.fault_address) if (mctx.fault_address)
cpuContext += fmt::format("\nFault Address: 0x{:X}", ctx.fault_address); cpuContext += fmt::format("\nFault Address: 0x{:X}", mctx.fault_address);
if (ctx.sp) if (mctx.sp)
cpuContext += fmt::format("\nStack Pointer: 0x{:X}", ctx.sp); cpuContext += fmt::format("\nStack Pointer: 0x{:X}", mctx.sp);
for (u8 index{}; index < ((sizeof(mcontext_t::regs) / sizeof(u64)) - 2); index += 2) for (u8 index{}; index < ((sizeof(mcontext_t::regs) / sizeof(u64)) - 2); index += 2)
cpuContext += fmt::format("\n{}X{}: 0x{:<16X} {}{}: 0x{:X}", index < 10 ? ' ' : '\0', index, ctx.regs[index], index < 10 ? 'X' : '\0', index + 1, ctx.regs[index]); cpuContext += fmt::format("\n{}X{}: 0x{:<16X} {}{}: 0x{:X}", index < 10 ? ' ' : '\0', index, mctx.regs[index], index < 10 ? 'X' : '\0', index + 1, mctx.regs[index]);
state.logger->Debug("CPU Context:{}", cpuContext); state.logger->Debug("CPU Context:{}", cpuContext);
} }
context->uc_mcontext.pc = reinterpret_cast<skyline::u64>(&std::longjmp); mctx.pc = reinterpret_cast<skyline::u64>(&std::longjmp);
context->uc_mcontext.regs[0] = reinterpret_cast<u64>(state.thread->originalCtx); mctx.regs[0] = reinterpret_cast<u64>(state.thread->originalCtx);
context->uc_mcontext.regs[1] = true; mctx.regs[1] = true;
*tls = nullptr; *tls = nullptr;
} else { } else {
signal::ExceptionalSignalHandler(signal, info, context); //!< Delegate throwing a host exception to the exceptional signal handler signal::ExceptionalSignalHandler(signal, info, ctx); //!< Delegate throwing a host exception to the exceptional signal handler
} }
} }
@ -131,16 +131,16 @@ namespace skyline::nce {
auto start{reinterpret_cast<const u32 *>(text.data())}, end{reinterpret_cast<const u32 *>(text.data() + text.size())}; auto start{reinterpret_cast<const u32 *>(text.data())}, end{reinterpret_cast<const u32 *>(text.data() + text.size())};
for (const u32 *instruction{start}; instruction < end; instruction++) { for (const u32 *instruction{start}; instruction < end; instruction++) {
auto svc{*reinterpret_cast<const instr::Svc *>(instruction)}; auto svc{*reinterpret_cast<const instructions::Svc *>(instruction)};
auto mrs{*reinterpret_cast<const instr::Mrs *>(instruction)}; auto mrs{*reinterpret_cast<const instructions::Mrs *>(instruction)};
auto msr{*reinterpret_cast<const instr::Msr *>(instruction)}; auto msr{*reinterpret_cast<const instructions::Msr *>(instruction)};
if (svc.Verify()) { if (svc.Verify()) {
size += 7; size += 7;
offsets.push_back(instruction - start); offsets.push_back(instruction - start);
} else if (mrs.Verify()) { } else if (mrs.Verify()) {
if (mrs.srcReg == TpidrroEl0 || mrs.srcReg == TpidrEl0) { if (mrs.srcReg == TpidrroEl0 || mrs.srcReg == TpidrEl0) {
size += ((mrs.destReg != regs::X0) ? 6 : 3); size += ((mrs.destReg != registers::X0) ? 6 : 3);
offsets.push_back(instruction - start); offsets.push_back(instruction - start);
} else { } else {
if (rescaleClock) { if (rescaleClock) {
@ -189,7 +189,7 @@ namespace skyline::nce {
*patch++ = 0xA9BF0BE1; // STP X1, X2, [SP, #-16]! *patch++ = 0xA9BF0BE1; // STP X1, X2, [SP, #-16]!
/* Jump to SvcHandler */ /* Jump to SvcHandler */
for (const auto &mov : instr::MoveRegister(regs::X2, reinterpret_cast<u64>(&NCE::SvcHandler))) for (const auto &mov : instructions::MoveRegister(registers::X2, reinterpret_cast<u64>(&NCE::SvcHandler)))
if (mov) if (mov)
*patch++ = mov; *patch++ = mov;
*patch++ = 0xD63F0040; // BLR X2 *patch++ = 0xD63F0040; // BLR X2
@ -213,39 +213,39 @@ namespace skyline::nce {
for (auto offset : offsets) { for (auto offset : offsets) {
u32 *instruction{reinterpret_cast<u32 *>(text.data()) + offset}; u32 *instruction{reinterpret_cast<u32 *>(text.data()) + offset};
auto svc{*reinterpret_cast<instr::Svc *>(instruction)}; auto svc{*reinterpret_cast<instructions::Svc *>(instruction)};
auto mrs{*reinterpret_cast<instr::Mrs *>(instruction)}; auto mrs{*reinterpret_cast<instructions::Mrs *>(instruction)};
auto msr{*reinterpret_cast<instr::Msr *>(instruction)}; auto msr{*reinterpret_cast<instructions::Msr *>(instruction)};
if (svc.Verify()) { if (svc.Verify()) {
/* Per-SVC Trampoline */ /* Per-SVC Trampoline */
/* Rewrite SVC with B to trampoline */ /* Rewrite SVC with B to trampoline */
*instruction = instr::B((end - patch) + offset, true).raw; *instruction = instructions::B((end - patch) + offset, true).raw;
/* Save Context */ /* Save Context */
*patch++ = 0xF81F0FFE; // STR LR, [SP, #-16]! *patch++ = 0xF81F0FFE; // STR LR, [SP, #-16]!
*patch = instr::BL(start - patch).raw; *patch = instructions::BL(start - patch).raw;
patch++; patch++;
/* Jump to main SVC trampoline */ /* Jump to main SVC trampoline */
*patch++ = instr::Movz(regs::W0, static_cast<u16>(svc.value)).raw; *patch++ = instructions::Movz(registers::W0, static_cast<u16>(svc.value)).raw;
*patch = instr::BL((start - patch) + guest::SaveCtxSize).raw; *patch = instructions::BL((start - patch) + guest::SaveCtxSize).raw;
patch++; patch++;
/* Restore Context and Return */ /* Restore Context and Return */
*patch = instr::BL((start - patch) + guest::SaveCtxSize + MainSvcTrampolineSize).raw; *patch = instructions::BL((start - patch) + guest::SaveCtxSize + MainSvcTrampolineSize).raw;
patch++; patch++;
*patch++ = 0xF84107FE; // LDR LR, [SP], #16 *patch++ = 0xF84107FE; // LDR LR, [SP], #16
*patch = instr::B((end - patch) + offset + 1).raw; *patch = instructions::B((end - patch) + offset + 1).raw;
patch++; patch++;
} else if (mrs.Verify()) { } else if (mrs.Verify()) {
if (mrs.srcReg == TpidrroEl0 || mrs.srcReg == TpidrEl0) { if (mrs.srcReg == TpidrroEl0 || mrs.srcReg == TpidrEl0) {
/* Emulated TLS Register Load */ /* Emulated TLS Register Load */
/* Rewrite MRS with B to trampoline */ /* Rewrite MRS with B to trampoline */
*instruction = instr::B((end - patch) + offset, true).raw; *instruction = instructions::B((end - patch) + offset, true).raw;
/* Allocate Scratch Register */ /* Allocate Scratch Register */
if (mrs.destReg != regs::X0) if (mrs.destReg != registers::X0)
*patch++ = 0xF81F0FE0; // STR X0, [SP, #-16]! *patch++ = 0xF81F0FE0; // STR X0, [SP, #-16]!
/* Retrieve emulated TLS register from ThreadContext */ /* Retrieve emulated TLS register from ThreadContext */
@ -256,66 +256,66 @@ namespace skyline::nce {
*patch++ = 0xF9415C00; // LDR X0, [X0, #0x2B8] (ThreadContext::tpidrEl0) *patch++ = 0xF9415C00; // LDR X0, [X0, #0x2B8] (ThreadContext::tpidrEl0)
/* Restore Scratch Register and Return */ /* Restore Scratch Register and Return */
if (mrs.destReg != regs::X0) { if (mrs.destReg != registers::X0) {
*patch++ = instr::Mov(regs::X(mrs.destReg), regs::X0).raw; *patch++ = instructions::Mov(registers::X(mrs.destReg), registers::X0).raw;
*patch++ = 0xF84107E0; // LDR X0, [SP], #16 *patch++ = 0xF84107E0; // LDR X0, [SP], #16
} }
*patch = instr::B((end - patch) + offset + 1).raw; *patch = instructions::B((end - patch) + offset + 1).raw;
patch++; patch++;
} else { } else {
if (rescaleClock) { if (rescaleClock) {
if (mrs.srcReg == CntpctEl0) { if (mrs.srcReg == CntpctEl0) {
/* Physical Counter Load Emulation (With Rescaling) */ /* Physical Counter Load Emulation (With Rescaling) */
/* Rewrite MRS with B to trampoline */ /* Rewrite MRS with B to trampoline */
*instruction = instr::B((end - patch) + offset, true).raw; *instruction = instructions::B((end - patch) + offset, true).raw;
/* Rescale host clock */ /* Rescale host clock */
std::memcpy(patch, reinterpret_cast<void *>(&guest::RescaleClock), guest::RescaleClockSize * sizeof(u32)); std::memcpy(patch, reinterpret_cast<void *>(&guest::RescaleClock), guest::RescaleClockSize * sizeof(u32));
patch += guest::RescaleClockSize; patch += guest::RescaleClockSize;
/* Load result from stack into destination register */ /* Load result from stack into destination register */
instr::Ldr ldr(0xF94003E0); // LDR XOUT, [SP] instructions::Ldr ldr(0xF94003E0); // LDR XOUT, [SP]
ldr.destReg = mrs.destReg; ldr.destReg = mrs.destReg;
*patch++ = ldr.raw; *patch++ = ldr.raw;
/* Free 32B stack allocation by RescaleClock and Return */ /* Free 32B stack allocation by RescaleClock and Return */
*patch++ = {0x910083FF}; // ADD SP, SP, #32 *patch++ = {0x910083FF}; // ADD SP, SP, #32
*patch = instr::B((end - patch) + offset + 1).raw; *patch = instructions::B((end - patch) + offset + 1).raw;
patch++; patch++;
} else if (mrs.srcReg == CntfrqEl0) { } else if (mrs.srcReg == CntfrqEl0) {
/* Physical Counter Frequency Load Emulation */ /* Physical Counter Frequency Load Emulation */
/* Rewrite MRS with B to trampoline */ /* Rewrite MRS with B to trampoline */
*instruction = instr::B((end - patch) + offset, true).raw; *instruction = instructions::B((end - patch) + offset, true).raw;
/* Write back Tegra X1 Counter Frequency and Return */ /* Write back Tegra X1 Counter Frequency and Return */
for (const auto &mov : instr::MoveRegister(regs::X(mrs.destReg), TegraX1Freq)) for (const auto &mov : instructions::MoveRegister(registers::X(mrs.destReg), TegraX1Freq))
*patch++ = mov; *patch++ = mov;
*patch = instr::B((end - patch) + offset + 1).raw; *patch = instructions::B((end - patch) + offset + 1).raw;
patch++; patch++;
} }
} else if (mrs.srcReg == CntpctEl0) { } else if (mrs.srcReg == CntpctEl0) {
/* Physical Counter Load Emulation (Without Rescaling) */ /* Physical Counter Load Emulation (Without Rescaling) */
// We just convert CNTPCT_EL0 -> CNTVCT_EL0 as Linux doesn't allow access to the physical counter // We just convert CNTPCT_EL0 -> CNTVCT_EL0 as Linux doesn't allow access to the physical counter
*instruction = instr::Mrs(CntvctEl0, regs::X(mrs.destReg)).raw; *instruction = instructions::Mrs(CntvctEl0, registers::X(mrs.destReg)).raw;
} }
} }
} else if (msr.Verify() && msr.destReg == TpidrEl0) { } else if (msr.Verify() && msr.destReg == TpidrEl0) {
/* Emulated TLS Register Store */ /* Emulated TLS Register Store */
/* Rewrite MSR with B to trampoline */ /* Rewrite MSR with B to trampoline */
*instruction = instr::B((end - patch) + offset, true).raw; *instruction = instructions::B((end - patch) + offset, true).raw;
/* Allocate Scratch Registers */ /* Allocate Scratch Registers */
bool x0x1{mrs.srcReg != regs::X0 && mrs.srcReg != regs::X1}; bool x0x1{mrs.srcReg != registers::X0 && mrs.srcReg != registers::X1};
*patch++ = x0x1 ? 0xA9BF07E0 : 0xA9BF0FE2; // STP X(0/2), X(1/3), [SP, #-16]! *patch++ = x0x1 ? 0xA9BF07E0 : 0xA9BF0FE2; // STP X(0/2), X(1/3), [SP, #-16]!
/* Store new TLS value into ThreadContext */ /* Store new TLS value into ThreadContext */
*patch++ = x0x1 ? 0xD53BD040 : 0xD53BD042; // MRS X(0/2), TPIDR_EL0 *patch++ = x0x1 ? 0xD53BD040 : 0xD53BD042; // MRS X(0/2), TPIDR_EL0
*patch++ = instr::Mov(x0x1 ? regs::X1 : regs::X3, regs::X(msr.srcReg)).raw; *patch++ = instructions::Mov(x0x1 ? registers::X1 : registers::X3, registers::X(msr.srcReg)).raw;
*patch++ = x0x1 ? 0xF9015C01 : 0xF9015C03; // STR X(1/3), [X0, #0x4B8] (ThreadContext::tpidrEl0) *patch++ = x0x1 ? 0xF9015C01 : 0xF9015C03; // STR X(1/3), [X0, #0x4B8] (ThreadContext::tpidrEl0)
/* Restore Scratch Registers and Return */ /* Restore Scratch Registers and Return */
*patch++ = x0x1 ? 0xA8C107E0 : 0xA8C10FE2; // LDP X(0/2), X(1/3), [SP], #16 *patch++ = x0x1 ? 0xA8C107E0 : 0xA8C10FE2; // LDP X(0/2), X(1/3), [SP], #16
*patch = instr::B((end - patch) + offset + 1).raw; *patch = instructions::B((end - patch) + offset + 1).raw;
patch++; patch++;
} }
} }

View File

@ -17,7 +17,7 @@ namespace skyline::nce {
static void SvcHandler(u16 svc, ThreadContext *ctx); static void SvcHandler(u16 svc, ThreadContext *ctx);
public: public:
static void SignalHandler(int signal, siginfo *info, ucontext *context, void **tls); static void SignalHandler(int signal, siginfo *info, ucontext *ctx, void **tls);
NCE(const DeviceState &state); NCE(const DeviceState &state);

View File

@ -4,12 +4,15 @@
#include <common.h> #include <common.h>
namespace skyline::nce { namespace skyline::nce {
namespace regs { /**
enum X { X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X12, X13, X14, X15, X16, X17, X18, X19, X20, X21, X22, X23, X24, X25, X26, X27, X28, X29, X30 }; * @note We use unscoped enumerations to leak all register enumerations into the registers namespace
enum W { W0, W1, W2, W3, W4, W5, W6, W7, W8, W9, W10, W11, W12, W13, W14, W15, W16, W17, W18, W19, W20, W21, W22, W23, W24, W25, W26, W27, W28, W29, W30 }; */
namespace registers {
enum X : u8 { X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X12, X13, X14, X15, X16, X17, X18, X19, X20, X21, X22, X23, X24, X25, X26, X27, X28, X29, X30 };
enum W : u8 { W0, W1, W2, W3, W4, W5, W6, W7, W8, W9, W10, W11, W12, W13, W14, W15, W16, W17, W18, W19, W20, W21, W22, W23, W24, W25, W26, W27, W28, W29, W30 };
} }
namespace instr { namespace instructions {
/** /**
* @url https://developer.arm.com/docs/ddi0596/latest/base-instructions-alphabetic-order/brk-breakpoint-instruction * @url https://developer.arm.com/docs/ddi0596/latest/base-instructions-alphabetic-order/brk-breakpoint-instruction
*/ */
@ -66,7 +69,7 @@ namespace skyline::nce {
* @param srcReg The source system register * @param srcReg The source system register
* @param dstReg The destination Xn register * @param dstReg The destination Xn register
*/ */
constexpr Mrs(u32 srcReg, regs::X dstReg) { constexpr Mrs(u32 srcReg, registers::X dstReg) {
this->srcReg = srcReg; this->srcReg = srcReg;
this->destReg = dstReg; this->destReg = dstReg;
sig = 0xD53; sig = 0xD53;
@ -184,7 +187,7 @@ namespace skyline::nce {
* @param imm16 The 16-bit value to store * @param imm16 The 16-bit value to store
* @param shift The offset (in units of 16-bits) in the register to store the value at * @param shift The offset (in units of 16-bits) in the register to store the value at
*/ */
constexpr Movz(regs::X destReg, u16 imm16, u8 shift = 0) { constexpr Movz(registers::X destReg, u16 imm16, u8 shift = 0) {
this->destReg = static_cast<u8>(destReg); this->destReg = static_cast<u8>(destReg);
this->imm16 = imm16; this->imm16 = imm16;
hw = shift; hw = shift;
@ -197,7 +200,7 @@ namespace skyline::nce {
* @param imm16 The 16-bit value to store * @param imm16 The 16-bit value to store
* @param shift The offset (in units of 16-bits) in the register to store the value at * @param shift The offset (in units of 16-bits) in the register to store the value at
*/ */
constexpr Movz(regs::W destReg, u16 imm16, u8 shift = 0) { constexpr Movz(registers::W destReg, u16 imm16, u8 shift = 0) {
this->destReg = static_cast<u8>(destReg); this->destReg = static_cast<u8>(destReg);
this->imm16 = imm16; this->imm16 = imm16;
hw = shift; hw = shift;
@ -239,7 +242,7 @@ namespace skyline::nce {
* @param imm16 The 16-bit value to store * @param imm16 The 16-bit value to store
* @param shift The offset (in units of 16-bits) in the register to store the value at * @param shift The offset (in units of 16-bits) in the register to store the value at
*/ */
constexpr Movk(regs::X destReg, u16 imm16, u8 shift = 0) { constexpr Movk(registers::X destReg, u16 imm16, u8 shift = 0) {
this->destReg = static_cast<u8>(destReg); this->destReg = static_cast<u8>(destReg);
this->imm16 = imm16; this->imm16 = imm16;
hw = shift; hw = shift;
@ -252,7 +255,7 @@ namespace skyline::nce {
* @param imm16 The 16-bit value to store * @param imm16 The 16-bit value to store
* @param shift The offset (in units of 16-bits) in the register to store the value at * @param shift The offset (in units of 16-bits) in the register to store the value at
*/ */
constexpr Movk(regs::W destReg, u16 imm16, u8 shift = 0) { constexpr Movk(registers::W destReg, u16 imm16, u8 shift = 0) {
this->destReg = static_cast<u8>(destReg); this->destReg = static_cast<u8>(destReg);
this->imm16 = imm16; this->imm16 = imm16;
hw = shift; hw = shift;
@ -291,7 +294,7 @@ namespace skyline::nce {
* @note 0 is returned for any instruction that isn't required * @note 0 is returned for any instruction that isn't required
*/ */
template<typename Type> template<typename Type>
constexpr std::array<u32, sizeof(Type) / sizeof(u16)> MoveRegister(regs::X destination, Type value) { constexpr std::array<u32, sizeof(Type) / sizeof(u16)> MoveRegister(registers::X destination, Type value) {
std::array<u32, sizeof(Type) / sizeof(u16)> instructions; std::array<u32, sizeof(Type) / sizeof(u16)> instructions;
auto valuePointer{reinterpret_cast<u16 *>(&value)}; auto valuePointer{reinterpret_cast<u16 *>(&value)};
@ -302,9 +305,9 @@ namespace skyline::nce {
auto offsetValue{*(valuePointer + offset)}; auto offsetValue{*(valuePointer + offset)};
if (offsetValue) { if (offsetValue) {
if (zeroed) { if (zeroed) {
instruction = instr::Movk(destination, offsetValue, offset).raw; instruction = instructions::Movk(destination, offsetValue, offset).raw;
} else { } else {
instruction = instr::Movz(destination, offsetValue, offset).raw; instruction = instructions::Movz(destination, offsetValue, offset).raw;
zeroed = true; zeroed = true;
} }
} else { } else {
@ -326,7 +329,7 @@ namespace skyline::nce {
* @param destReg The destination Xn register to store the value in * @param destReg The destination Xn register to store the value in
* @param srcReg The source Xn register to retrieve the value from * @param srcReg The source Xn register to retrieve the value from
*/ */
constexpr Mov(regs::X destReg, regs::X srcReg) { constexpr Mov(registers::X destReg, registers::X srcReg) {
this->destReg = static_cast<u8>(destReg); this->destReg = static_cast<u8>(destReg);
sig0 = 0x1F; sig0 = 0x1F;
imm = 0; imm = 0;
@ -340,7 +343,7 @@ namespace skyline::nce {
* @param destReg The destination Wn register to store the value in * @param destReg The destination Wn register to store the value in
* @param srcReg The source Wn register to retrieve the value from * @param srcReg The source Wn register to retrieve the value from
*/ */
constexpr Mov(regs::W destReg, regs::W srcReg) { constexpr Mov(registers::W destReg, registers::W srcReg) {
this->destReg = static_cast<u8>(destReg); this->destReg = static_cast<u8>(destReg);
sig0 = 0x1F; sig0 = 0x1F;
imm = 0; imm = 0;

View File

@ -18,16 +18,20 @@ namespace skyline::kernel {
auto romFile{std::make_shared<vfs::OsBacking>(romFd)}; auto romFile{std::make_shared<vfs::OsBacking>(romFd)};
auto keyStore{std::make_shared<crypto::KeyStore>(appFilesPath)}; auto keyStore{std::make_shared<crypto::KeyStore>(appFilesPath)};
if (romType == loader::RomFormat::NRO) state.loader = [=]() -> std::shared_ptr<loader::Loader> {
state.loader = std::make_shared<loader::NroLoader>(romFile); switch (romType) {
else if (romType == loader::RomFormat::NSO) case loader::RomFormat::NRO:
state.loader = std::make_shared<loader::NsoLoader>(romFile); return std::make_shared<loader::NroLoader>(romFile);
else if (romType == loader::RomFormat::NCA) case loader::RomFormat::NSO:
state.loader = std::make_shared<loader::NcaLoader>(romFile, keyStore); return std::make_shared<loader::NsoLoader>(romFile);
else if (romType == loader::RomFormat::NSP) case loader::RomFormat::NCA:
state.loader = std::make_shared<loader::NspLoader>(romFile, keyStore); return std::make_shared<loader::NcaLoader>(romFile, keyStore);
else case loader::RomFormat::NSP:
throw exception("Unsupported ROM extension."); return std::make_shared<loader::NspLoader>(romFile, keyStore);
default:
throw exception("Unsupported ROM extension.");
}
}();
auto &process{state.process}; auto &process{state.process};
process = std::make_shared<kernel::type::KProcess>(state); process = std::make_shared<kernel::type::KProcess>(state);

View File

@ -47,7 +47,7 @@ namespace skyline::vfs {
/** /**
* @brief Implicit casting for reading into spans of different types * @brief Implicit casting for reading into spans of different types
*/ */
template<class T, typename std::enable_if<!std::is_same_v<T, u8>, bool>::type = true> template<typename T, typename std::enable_if<!std::is_same_v<T, u8>, bool>::type = true>
inline size_t Read(span <T> output, size_t offset = 0) { inline size_t Read(span <T> output, size_t offset = 0) {
return Read(output.template cast<u8>(), offset); return Read(output.template cast<u8>(), offset);
} }

View File

@ -18,7 +18,7 @@ namespace skyline {
u32 offset; u32 offset;
u32 size; u32 size;
template<class T> template<typename T>
inline T Read(const std::shared_ptr<vfs::Backing> &backing, size_t baseOffset = 0) { inline T Read(const std::shared_ptr<vfs::Backing> &backing, size_t baseOffset = 0) {
if (sizeof(T) > size) if (sizeof(T) > size)
throw exception("Section size ({}) smaller than Read type size ({})", size, sizeof(T)); throw exception("Section size ({}) smaller than Read type size ({})", size, sizeof(T));