mirror of
https://github.com/skyline-emu/skyline.git
synced 2024-11-05 05:15:08 +01:00
Address CR Comments #2
This commit is contained in:
parent
fbf9f06244
commit
8564edcb16
@ -37,7 +37,6 @@ namespace skyline {
|
||||
|
||||
std::lock_guard guard(mtx);
|
||||
logFile << "0|" << str << "\n";
|
||||
logFile.flush();
|
||||
}
|
||||
|
||||
void Logger::Write(LogLevel level, std::string str) {
|
||||
@ -55,7 +54,6 @@ namespace skyline {
|
||||
|
||||
std::lock_guard guard(mtx);
|
||||
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)
|
||||
|
@ -96,7 +96,7 @@ namespace skyline {
|
||||
* @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
|
||||
*/
|
||||
template<class T>
|
||||
template<typename T>
|
||||
constexpr auto FmtCast(T object) {
|
||||
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)
|
||||
@ -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
|
||||
*/
|
||||
template<class T>
|
||||
template<typename T>
|
||||
T PointerValue(T item) {
|
||||
return item;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
template<typename T>
|
||||
uintptr_t PointerValue(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
|
||||
*/
|
||||
template<class Return, class T>
|
||||
template<typename Return, typename T>
|
||||
Return ValuePointer(T item) {
|
||||
if constexpr (std::is_pointer<Return>::value)
|
||||
return reinterpret_cast<Return>(item);
|
||||
@ -253,7 +253,7 @@ namespace skyline {
|
||||
return result;
|
||||
}
|
||||
|
||||
template<class Type>
|
||||
template<typename Type>
|
||||
constexpr Type HexStringToInt(std::string_view string) {
|
||||
if (string.size() > sizeof(Type) * 2)
|
||||
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
|
||||
*/
|
||||
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()) {}
|
||||
|
||||
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
|
||||
*/
|
||||
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>;
|
||||
template<class T, size_t Size>
|
||||
template<typename T, size_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>;
|
||||
template<class T, size_t Size>
|
||||
template<typename T, size_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>;
|
||||
template<class Container>
|
||||
template<typename Container>
|
||||
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 {
|
||||
private:
|
||||
|
@ -21,6 +21,9 @@ namespace skyline {
|
||||
std::condition_variable produceCondition;
|
||||
|
||||
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(const CircularQueue &) = delete;
|
||||
|
@ -46,7 +46,7 @@ namespace skyline::signal {
|
||||
void ExceptionalSignalHandler(int signal, siginfo *info, ucontext *context) {
|
||||
SignalException signalException;
|
||||
signalException.signal = signal;
|
||||
signalException.pc = context->uc_mcontext.pc;
|
||||
signalException.pc = reinterpret_cast<void *>(context->uc_mcontext.pc);
|
||||
if (signal == SIGSEGV)
|
||||
signalException.fault = info->si_addr;
|
||||
SignalExceptionPtr = std::make_exception_ptr(signalException);
|
||||
|
@ -14,14 +14,14 @@ namespace skyline::signal {
|
||||
class SignalException {
|
||||
public:
|
||||
int signal{};
|
||||
u64 pc{};
|
||||
void* pc{};
|
||||
void *fault{};
|
||||
|
||||
inline std::string what() const {
|
||||
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
|
||||
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));
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -94,7 +94,7 @@ namespace skyline::kernel::ipc {
|
||||
|
||||
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));
|
||||
|
||||
pointer += constant::IpcPaddingSum - padding + cBufferLengthSize;
|
||||
|
@ -7,12 +7,17 @@
|
||||
|
||||
namespace skyline {
|
||||
namespace memory {
|
||||
struct Permission {
|
||||
union Permission {
|
||||
/**
|
||||
* @brief Initializes all permissions to false
|
||||
*/
|
||||
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 write If memory has write permission
|
||||
@ -38,10 +43,14 @@ namespace skyline {
|
||||
return perm;
|
||||
}
|
||||
|
||||
bool r; //!< The permission to read
|
||||
bool w; //!< The permission to write
|
||||
bool x; //!< The permission to execute
|
||||
struct {
|
||||
bool r : 1; //!< The permission to read
|
||||
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
|
||||
|
@ -419,7 +419,7 @@ namespace skyline::kernel::svc {
|
||||
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)) {
|
||||
state.logger->Warn("svcMapSharedMemory: 'permission' invalid: {}{}{}", permission.r ? 'R' : '-', permission.w ? 'W' : '-', permission.x ? 'X' : '-');
|
||||
state.ctx->gpr.w0 = result::InvalidNewMemoryPermission;
|
||||
@ -452,7 +452,7 @@ namespace skyline::kernel::svc {
|
||||
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)) {
|
||||
state.logger->Warn("svcCreateTransferMemory: 'permission' invalid: {}{}{}", permission.r ? 'R' : '-', permission.w ? 'W' : '-', permission.x ? 'X' : '-');
|
||||
state.ctx->gpr.w0 = result::InvalidNewMemoryPermission;
|
||||
|
@ -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 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 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 X4, XZR\n\t"
|
||||
"MOV X5, XZR\n\t"
|
||||
|
@ -27,7 +27,7 @@ namespace skyline::loader {
|
||||
u8 *base{loadInfo.base};
|
||||
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"}) {
|
||||
if (exeFs->FileExists(nso))
|
||||
|
@ -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) {
|
||||
auto &mctx{ctx->uc_mcontext};
|
||||
const auto &state{*reinterpret_cast<ThreadContext *>(*tls)->state};
|
||||
if (signal != SIGINT) {
|
||||
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 cpuContext;
|
||||
|
||||
const auto &ctx{reinterpret_cast<ucontext *>(context)->uc_mcontext};
|
||||
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);
|
||||
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) {
|
||||
instruction = __builtin_bswap32(instruction);
|
||||
|
||||
if (offset == ctx.pc)
|
||||
if (offset == mctx.pc)
|
||||
trace += fmt::format("\n-> 0x{:X} : 0x{:08X}", offset, instruction);
|
||||
else
|
||||
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("Raw Instructions: 0x{}", raw);
|
||||
} 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)
|
||||
cpuContext += fmt::format("\nFault Address: 0x{:X}", ctx.fault_address);
|
||||
if (mctx.fault_address)
|
||||
cpuContext += fmt::format("\nFault Address: 0x{:X}", mctx.fault_address);
|
||||
|
||||
if (ctx.sp)
|
||||
cpuContext += fmt::format("\nStack Pointer: 0x{:X}", ctx.sp);
|
||||
if (mctx.sp)
|
||||
cpuContext += fmt::format("\nStack Pointer: 0x{:X}", mctx.sp);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
context->uc_mcontext.pc = reinterpret_cast<skyline::u64>(&std::longjmp);
|
||||
context->uc_mcontext.regs[0] = reinterpret_cast<u64>(state.thread->originalCtx);
|
||||
context->uc_mcontext.regs[1] = true;
|
||||
mctx.pc = reinterpret_cast<skyline::u64>(&std::longjmp);
|
||||
mctx.regs[0] = reinterpret_cast<u64>(state.thread->originalCtx);
|
||||
mctx.regs[1] = true;
|
||||
|
||||
*tls = nullptr;
|
||||
} 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())};
|
||||
for (const u32 *instruction{start}; instruction < end; instruction++) {
|
||||
auto svc{*reinterpret_cast<const instr::Svc *>(instruction)};
|
||||
auto mrs{*reinterpret_cast<const instr::Mrs *>(instruction)};
|
||||
auto msr{*reinterpret_cast<const instr::Msr *>(instruction)};
|
||||
auto svc{*reinterpret_cast<const instructions::Svc *>(instruction)};
|
||||
auto mrs{*reinterpret_cast<const instructions::Mrs *>(instruction)};
|
||||
auto msr{*reinterpret_cast<const instructions::Msr *>(instruction)};
|
||||
|
||||
if (svc.Verify()) {
|
||||
size += 7;
|
||||
offsets.push_back(instruction - start);
|
||||
} else if (mrs.Verify()) {
|
||||
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);
|
||||
} else {
|
||||
if (rescaleClock) {
|
||||
@ -189,7 +189,7 @@ namespace skyline::nce {
|
||||
*patch++ = 0xA9BF0BE1; // STP X1, X2, [SP, #-16]!
|
||||
|
||||
/* 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)
|
||||
*patch++ = mov;
|
||||
*patch++ = 0xD63F0040; // BLR X2
|
||||
@ -213,39 +213,39 @@ namespace skyline::nce {
|
||||
|
||||
for (auto offset : offsets) {
|
||||
u32 *instruction{reinterpret_cast<u32 *>(text.data()) + offset};
|
||||
auto svc{*reinterpret_cast<instr::Svc *>(instruction)};
|
||||
auto mrs{*reinterpret_cast<instr::Mrs *>(instruction)};
|
||||
auto msr{*reinterpret_cast<instr::Msr *>(instruction)};
|
||||
auto svc{*reinterpret_cast<instructions::Svc *>(instruction)};
|
||||
auto mrs{*reinterpret_cast<instructions::Mrs *>(instruction)};
|
||||
auto msr{*reinterpret_cast<instructions::Msr *>(instruction)};
|
||||
|
||||
if (svc.Verify()) {
|
||||
/* Per-SVC 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 */
|
||||
*patch++ = 0xF81F0FFE; // STR LR, [SP, #-16]!
|
||||
*patch = instr::BL(start - patch).raw;
|
||||
*patch = instructions::BL(start - patch).raw;
|
||||
patch++;
|
||||
|
||||
/* Jump to main SVC trampoline */
|
||||
*patch++ = instr::Movz(regs::W0, static_cast<u16>(svc.value)).raw;
|
||||
*patch = instr::BL((start - patch) + guest::SaveCtxSize).raw;
|
||||
*patch++ = instructions::Movz(registers::W0, static_cast<u16>(svc.value)).raw;
|
||||
*patch = instructions::BL((start - patch) + guest::SaveCtxSize).raw;
|
||||
patch++;
|
||||
|
||||
/* Restore Context and Return */
|
||||
*patch = instr::BL((start - patch) + guest::SaveCtxSize + MainSvcTrampolineSize).raw;
|
||||
*patch = instructions::BL((start - patch) + guest::SaveCtxSize + MainSvcTrampolineSize).raw;
|
||||
patch++;
|
||||
*patch++ = 0xF84107FE; // LDR LR, [SP], #16
|
||||
*patch = instr::B((end - patch) + offset + 1).raw;
|
||||
*patch = instructions::B((end - patch) + offset + 1).raw;
|
||||
patch++;
|
||||
} else if (mrs.Verify()) {
|
||||
if (mrs.srcReg == TpidrroEl0 || mrs.srcReg == TpidrEl0) {
|
||||
/* Emulated TLS Register Load */
|
||||
/* 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 */
|
||||
if (mrs.destReg != regs::X0)
|
||||
if (mrs.destReg != registers::X0)
|
||||
*patch++ = 0xF81F0FE0; // STR X0, [SP, #-16]!
|
||||
|
||||
/* Retrieve emulated TLS register from ThreadContext */
|
||||
@ -256,66 +256,66 @@ namespace skyline::nce {
|
||||
*patch++ = 0xF9415C00; // LDR X0, [X0, #0x2B8] (ThreadContext::tpidrEl0)
|
||||
|
||||
/* Restore Scratch Register and Return */
|
||||
if (mrs.destReg != regs::X0) {
|
||||
*patch++ = instr::Mov(regs::X(mrs.destReg), regs::X0).raw;
|
||||
if (mrs.destReg != registers::X0) {
|
||||
*patch++ = instructions::Mov(registers::X(mrs.destReg), registers::X0).raw;
|
||||
*patch++ = 0xF84107E0; // LDR X0, [SP], #16
|
||||
}
|
||||
*patch = instr::B((end - patch) + offset + 1).raw;
|
||||
*patch = instructions::B((end - patch) + offset + 1).raw;
|
||||
patch++;
|
||||
} else {
|
||||
if (rescaleClock) {
|
||||
if (mrs.srcReg == CntpctEl0) {
|
||||
/* Physical Counter Load Emulation (With Rescaling) */
|
||||
/* 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 */
|
||||
std::memcpy(patch, reinterpret_cast<void *>(&guest::RescaleClock), guest::RescaleClockSize * sizeof(u32));
|
||||
patch += guest::RescaleClockSize;
|
||||
|
||||
/* 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;
|
||||
*patch++ = ldr.raw;
|
||||
|
||||
/* Free 32B stack allocation by RescaleClock and Return */
|
||||
*patch++ = {0x910083FF}; // ADD SP, SP, #32
|
||||
*patch = instr::B((end - patch) + offset + 1).raw;
|
||||
*patch = instructions::B((end - patch) + offset + 1).raw;
|
||||
patch++;
|
||||
} else if (mrs.srcReg == CntfrqEl0) {
|
||||
/* Physical Counter Frequency Load Emulation */
|
||||
/* 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 */
|
||||
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 = instr::B((end - patch) + offset + 1).raw;
|
||||
*patch = instructions::B((end - patch) + offset + 1).raw;
|
||||
patch++;
|
||||
}
|
||||
} else if (mrs.srcReg == CntpctEl0) {
|
||||
/* Physical Counter Load Emulation (Without Rescaling) */
|
||||
// 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) {
|
||||
/* Emulated TLS Register Store */
|
||||
/* 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 */
|
||||
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]!
|
||||
|
||||
/* Store new TLS value into ThreadContext */
|
||||
*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)
|
||||
|
||||
/* Restore Scratch Registers and Return */
|
||||
*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++;
|
||||
}
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ namespace skyline::nce {
|
||||
static void SvcHandler(u16 svc, ThreadContext *ctx);
|
||||
|
||||
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);
|
||||
|
||||
|
@ -4,12 +4,15 @@
|
||||
#include <common.h>
|
||||
|
||||
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 };
|
||||
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 };
|
||||
/**
|
||||
* @note We use unscoped enumerations to leak all register enumerations into the registers namespace
|
||||
*/
|
||||
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
|
||||
*/
|
||||
@ -66,7 +69,7 @@ namespace skyline::nce {
|
||||
* @param srcReg The source system 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->destReg = dstReg;
|
||||
sig = 0xD53;
|
||||
@ -184,7 +187,7 @@ namespace skyline::nce {
|
||||
* @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
|
||||
*/
|
||||
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->imm16 = imm16;
|
||||
hw = shift;
|
||||
@ -197,7 +200,7 @@ namespace skyline::nce {
|
||||
* @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
|
||||
*/
|
||||
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->imm16 = imm16;
|
||||
hw = shift;
|
||||
@ -239,7 +242,7 @@ namespace skyline::nce {
|
||||
* @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
|
||||
*/
|
||||
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->imm16 = imm16;
|
||||
hw = shift;
|
||||
@ -252,7 +255,7 @@ namespace skyline::nce {
|
||||
* @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
|
||||
*/
|
||||
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->imm16 = imm16;
|
||||
hw = shift;
|
||||
@ -291,7 +294,7 @@ namespace skyline::nce {
|
||||
* @note 0 is returned for any instruction that isn't required
|
||||
*/
|
||||
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;
|
||||
|
||||
auto valuePointer{reinterpret_cast<u16 *>(&value)};
|
||||
@ -302,9 +305,9 @@ namespace skyline::nce {
|
||||
auto offsetValue{*(valuePointer + offset)};
|
||||
if (offsetValue) {
|
||||
if (zeroed) {
|
||||
instruction = instr::Movk(destination, offsetValue, offset).raw;
|
||||
instruction = instructions::Movk(destination, offsetValue, offset).raw;
|
||||
} else {
|
||||
instruction = instr::Movz(destination, offsetValue, offset).raw;
|
||||
instruction = instructions::Movz(destination, offsetValue, offset).raw;
|
||||
zeroed = true;
|
||||
}
|
||||
} else {
|
||||
@ -326,7 +329,7 @@ namespace skyline::nce {
|
||||
* @param destReg The destination Xn register to store the value in
|
||||
* @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);
|
||||
sig0 = 0x1F;
|
||||
imm = 0;
|
||||
@ -340,7 +343,7 @@ namespace skyline::nce {
|
||||
* @param destReg The destination Wn register to store the value in
|
||||
* @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);
|
||||
sig0 = 0x1F;
|
||||
imm = 0;
|
||||
|
@ -18,16 +18,20 @@ namespace skyline::kernel {
|
||||
auto romFile{std::make_shared<vfs::OsBacking>(romFd)};
|
||||
auto keyStore{std::make_shared<crypto::KeyStore>(appFilesPath)};
|
||||
|
||||
if (romType == loader::RomFormat::NRO)
|
||||
state.loader = std::make_shared<loader::NroLoader>(romFile);
|
||||
else if (romType == loader::RomFormat::NSO)
|
||||
state.loader = std::make_shared<loader::NsoLoader>(romFile);
|
||||
else if (romType == loader::RomFormat::NCA)
|
||||
state.loader = std::make_shared<loader::NcaLoader>(romFile, keyStore);
|
||||
else if (romType == loader::RomFormat::NSP)
|
||||
state.loader = std::make_shared<loader::NspLoader>(romFile, keyStore);
|
||||
else
|
||||
throw exception("Unsupported ROM extension.");
|
||||
state.loader = [=]() -> std::shared_ptr<loader::Loader> {
|
||||
switch (romType) {
|
||||
case loader::RomFormat::NRO:
|
||||
return std::make_shared<loader::NroLoader>(romFile);
|
||||
case loader::RomFormat::NSO:
|
||||
return std::make_shared<loader::NsoLoader>(romFile);
|
||||
case loader::RomFormat::NCA:
|
||||
return std::make_shared<loader::NcaLoader>(romFile, keyStore);
|
||||
case loader::RomFormat::NSP:
|
||||
return std::make_shared<loader::NspLoader>(romFile, keyStore);
|
||||
default:
|
||||
throw exception("Unsupported ROM extension.");
|
||||
}
|
||||
}();
|
||||
|
||||
auto &process{state.process};
|
||||
process = std::make_shared<kernel::type::KProcess>(state);
|
||||
|
@ -47,7 +47,7 @@ namespace skyline::vfs {
|
||||
/**
|
||||
* @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) {
|
||||
return Read(output.template cast<u8>(), offset);
|
||||
}
|
||||
|
@ -18,7 +18,7 @@ namespace skyline {
|
||||
u32 offset;
|
||||
u32 size;
|
||||
|
||||
template<class T>
|
||||
template<typename T>
|
||||
inline T Read(const std::shared_ptr<vfs::Backing> &backing, size_t baseOffset = 0) {
|
||||
if (sizeof(T) > size)
|
||||
throw exception("Section size ({}) smaller than Read type size ({})", size, sizeof(T));
|
||||
|
Loading…
Reference in New Issue
Block a user