Add Mutexes to Logger, Introduce util::MakeMagic and Refactor IPC

This commit adds mutexes to the logger so they produce a valid log file rather than breaking due to a race condition. It also introduced `util::MakeMagic` so the magic functions are far more clear. A small refactor of IPC was also done which cleared up some of the for loops.
This commit is contained in:
◱ PixelyIon 2020-04-18 02:49:19 +05:30 committed by ◱ PixelyIon
parent 91644255da
commit af98455ede
14 changed files with 383 additions and 366 deletions

View File

@ -24,7 +24,7 @@ namespace skyline {
void GroupMutex::lock(Group group) { void GroupMutex::lock(Group group) {
auto none = Group::None; auto none = Group::None;
constexpr u64 timeout = 100; // The timeout in ns constexpr u64 timeout = 100; // The timeout in ns
auto end = utils::GetTimeNs() + timeout; auto end = util::GetTimeNs() + timeout;
while (true) { while (true) {
if (next == group) { if (next == group) {
@ -41,7 +41,7 @@ namespace skyline {
} else { } else {
flag.compare_exchange_weak(none, group); flag.compare_exchange_weak(none, group);
} }
} else if (flag == group && (next == Group::None || utils::GetTimeNs() >= end)) { } else if (flag == group && (next == Group::None || util::GetTimeNs() >= end)) {
std::lock_guard lock(mtx); std::lock_guard lock(mtx);
if (flag == group) { if (flag == group) {
@ -127,13 +127,14 @@ namespace skyline {
Logger::~Logger() { Logger::~Logger() {
WriteHeader("Logging ended"); WriteHeader("Logging ended");
logFile.flush();
} }
void Logger::WriteHeader(const std::string &str) { void Logger::WriteHeader(const std::string &str) {
syslog(LOG_ALERT, "%s", str.c_str()); syslog(LOG_ALERT, "%s", str.c_str());
std::lock_guard guard(mtx);
logFile << "0|" << str << "\n"; logFile << "0|" << str << "\n";
logFile.flush();
} }
void Logger::Write(const LogLevel level, std::string str) { void Logger::Write(const LogLevel level, std::string str) {
@ -143,12 +144,12 @@ namespace skyline {
if (character == '\n') if (character == '\n')
character = '\\'; character = '\\';
std::lock_guard guard(mtx);
logFile << "1|" << levelStr[static_cast<u8>(level)] << "|" << str << "\n"; logFile << "1|" << levelStr[static_cast<u8>(level)] << "|" << str << "\n";
logFile.flush();
} }
DeviceState::DeviceState(kernel::OS *os, std::shared_ptr<kernel::type::KProcess> &process, std::shared_ptr<JvmManager> jvmManager, std::shared_ptr<Settings> settings, std::shared_ptr<Logger> logger) DeviceState::DeviceState(kernel::OS *os, std::shared_ptr<kernel::type::KProcess> &process, std::shared_ptr<JvmManager> jvmManager, std::shared_ptr<Settings> settings, std::shared_ptr<Logger> logger)
: os(os), jvmManager(std::move(jvmManager)), settings(std::move(settings)), logger(std::move(logger)), process(process) { : os(os), jvm(std::move(jvmManager)), settings(std::move(settings)), logger(std::move(logger)), process(process) {
// We assign these later as they use the state in their constructor and we don't want null pointers // We assign these later as they use the state in their constructor and we don't want null pointers
nce = std::move(std::make_shared<NCE>(*this)); nce = std::move(std::make_shared<NCE>(*this));
gpu = std::move(std::make_shared<gpu::GPU>(*this)); gpu = std::move(std::make_shared<gpu::GPU>(*this));

View File

@ -68,7 +68,7 @@ namespace skyline {
NSP, //!< The NSP format from "nspwn" exploit: https://switchbrew.org/wiki/Switch_System_Flaws NSP, //!< The NSP format from "nspwn" exploit: https://switchbrew.org/wiki/Switch_System_Flaws
}; };
namespace utils { namespace util {
/** /**
* @brief Returns the current time in nanoseconds * @brief Returns the current time in nanoseconds
* @return The current time in nanoseconds * @return The current time in nanoseconds
@ -93,7 +93,7 @@ namespace skyline {
* @return The aligned value * @return The aligned value
*/ */
template<typename TypeVal, typename TypeMul> template<typename TypeVal, typename TypeMul>
inline TypeVal AlignUp(TypeVal value, TypeMul multiple) { constexpr inline TypeVal AlignUp(TypeVal value, TypeMul multiple) {
static_assert(std::is_integral<TypeVal>() && std::is_integral<TypeMul>()); static_assert(std::is_integral<TypeVal>() && std::is_integral<TypeMul>());
multiple--; multiple--;
return (value + multiple) & ~(multiple); return (value + multiple) & ~(multiple);
@ -108,7 +108,7 @@ namespace skyline {
* @return The aligned value * @return The aligned value
*/ */
template<typename TypeVal, typename TypeMul> template<typename TypeVal, typename TypeMul>
inline TypeVal AlignDown(TypeVal value, TypeMul multiple) { constexpr inline TypeVal AlignDown(TypeVal value, TypeMul multiple) {
static_assert(std::is_integral<TypeVal>() && std::is_integral<TypeMul>()); static_assert(std::is_integral<TypeVal>() && std::is_integral<TypeMul>());
return value & ~(multiple - 1); return value & ~(multiple - 1);
} }
@ -117,7 +117,7 @@ namespace skyline {
* @param address The address to check for alignment * @param address The address to check for alignment
* @return If the address is page aligned * @return If the address is page aligned
*/ */
inline bool PageAligned(u64 address) { constexpr inline bool PageAligned(u64 address) {
return !(address & (PAGE_SIZE - 1U)); return !(address & (PAGE_SIZE - 1U));
} }
@ -125,9 +125,26 @@ namespace skyline {
* @param address The address to check for alignment * @param address The address to check for alignment
* @return If the address is word aligned * @return If the address is word aligned
*/ */
inline bool WordAligned(u64 address) { constexpr inline bool WordAligned(u64 address) {
return !(address & 3U); return !(address & 3U);
} }
/**
* @param string The string to create a magic from
* @return The magic of the supplied string
*/
template<typename Type>
constexpr Type MakeMagic(std::string_view string) {
Type object{};
auto offset = 0;
for(auto& character : string) {
object |= static_cast<Type>(character) << offset;
offset += sizeof(character) * 8;
}
return object;
}
} }
/** /**
@ -198,6 +215,7 @@ namespace skyline {
std::ofstream logFile; //!< An output stream to the log file std::ofstream logFile; //!< An output stream to the log file
const char *levelStr[4] = {"0", "1", "2", "3"}; //!< This is used to denote the LogLevel when written out to a file const char *levelStr[4] = {"0", "1", "2", "3"}; //!< This is used to denote the LogLevel when written out to a file
static constexpr int levelSyslog[4] = {LOG_ERR, LOG_WARNING, LOG_INFO, LOG_DEBUG}; //!< This corresponds to LogLevel and provides it's equivalent for syslog static constexpr int levelSyslog[4] = {LOG_ERR, LOG_WARNING, LOG_INFO, LOG_DEBUG}; //!< This corresponds to LogLevel and provides it's equivalent for syslog
Mutex mtx; //!< A mutex to lock before logging anything
public: public:
enum class LogLevel { Error, Warn, Info, Debug }; //!< The level of a particular log enum class LogLevel { Error, Warn, Info, Debug }; //!< The level of a particular log
@ -360,7 +378,7 @@ namespace skyline {
std::shared_ptr<NCE> nce; //!< This holds a reference to the NCE class std::shared_ptr<NCE> nce; //!< This holds a reference to the NCE class
std::shared_ptr<gpu::GPU> gpu; //!< This holds a reference to the GPU class std::shared_ptr<gpu::GPU> gpu; //!< This holds a reference to the GPU class
std::shared_ptr<audio::Audio> audio; //!< This holds a reference to the Audio class std::shared_ptr<audio::Audio> audio; //!< This holds a reference to the Audio class
std::shared_ptr<JvmManager> jvmManager; //!< This holds a reference to the JvmManager class std::shared_ptr<JvmManager> jvm; //!< This holds a reference to the JvmManager class
std::shared_ptr<Settings> settings; //!< This holds a reference to the Settings class std::shared_ptr<Settings> settings; //!< This holds a reference to the Settings class
std::shared_ptr<Logger> logger; //!< This holds a reference to the Logger class std::shared_ptr<Logger> logger; //!< This holds a reference to the Logger class
}; };

View File

@ -10,7 +10,7 @@ extern bool Halt;
extern jobject Surface; extern jobject Surface;
namespace skyline::gpu { namespace skyline::gpu {
GPU::GPU(const DeviceState &state) : state(state), window(ANativeWindow_fromSurface(state.jvmManager->GetEnv(), Surface)), vsyncEvent(std::make_shared<kernel::type::KEvent>(state)), bufferEvent(std::make_shared<kernel::type::KEvent>(state)) { GPU::GPU(const DeviceState &state) : state(state), window(ANativeWindow_fromSurface(state.jvm->GetEnv(), Surface)), vsyncEvent(std::make_shared<kernel::type::KEvent>(state)), bufferEvent(std::make_shared<kernel::type::KEvent>(state)) {
ANativeWindow_acquire(window); ANativeWindow_acquire(window);
resolution.width = static_cast<u32>(ANativeWindow_getWidth(window)); resolution.width = static_cast<u32>(ANativeWindow_getWidth(window));
resolution.height = static_cast<u32>(ANativeWindow_getHeight(window)); resolution.height = static_cast<u32>(ANativeWindow_getHeight(window));
@ -25,7 +25,7 @@ namespace skyline::gpu {
if (surfaceUpdate) { if (surfaceUpdate) {
if (Surface == nullptr) if (Surface == nullptr)
return; return;
window = ANativeWindow_fromSurface(state.jvmManager->GetEnv(), Surface); window = ANativeWindow_fromSurface(state.jvm->GetEnv(), Surface);
ANativeWindow_acquire(window); ANativeWindow_acquire(window);
resolution.width = static_cast<u32>(ANativeWindow_getWidth(window)); resolution.width = static_cast<u32>(ANativeWindow_getWidth(window));
resolution.height = static_cast<u32>(ANativeWindow_getHeight(window)); resolution.height = static_cast<u32>(ANativeWindow_getHeight(window));
@ -51,7 +51,7 @@ namespace skyline::gpu {
ARect rect; ARect rect;
ANativeWindow_lock(window, &windowBuffer, &rect); ANativeWindow_lock(window, &windowBuffer, &rect);
memcpy(windowBuffer.bits, texture->backing.data(), texture->backing.size()); std::memcpy(windowBuffer.bits, texture->backing.data(), texture->backing.size());
ANativeWindow_unlockAndPost(window); ANativeWindow_unlockAndPost(window);
vsyncEvent->Signal(); vsyncEvent->Signal();

View File

@ -26,8 +26,8 @@ namespace skyline::gpu {
constexpr auto gobHeight = 8; // The height of a GOB in lines constexpr auto gobHeight = 8; // The height of a GOB in lines
auto robHeight = gobHeight * guest->tileConfig.blockHeight; // The height of a single ROB (Row of Blocks) in lines auto robHeight = gobHeight * guest->tileConfig.blockHeight; // The height of a single ROB (Row of Blocks) in lines
auto surfaceHeightRobs = utils::AlignUp(dimensions.height / format.blockHeight, robHeight) / robHeight; // The height of the surface in ROBs (Row Of Blocks) auto surfaceHeightRobs = util::AlignUp(dimensions.height / format.blockHeight, robHeight) / robHeight; // The height of the surface in ROBs (Row Of Blocks)
auto robWidthBytes = utils::AlignUp((guest->tileConfig.surfaceWidth / format.blockWidth) * format.bpb, gobWidth); // The width of a ROB in bytes auto robWidthBytes = util::AlignUp((guest->tileConfig.surfaceWidth / format.blockWidth) * format.bpb, gobWidth); // The width of a ROB in bytes
auto robWidthBlocks = robWidthBytes / gobWidth; // The width of a ROB in blocks (and GOBs because block width == 1 on the Tegra X1) auto robWidthBlocks = robWidthBytes / gobWidth; // The width of a ROB in blocks (and GOBs because block width == 1 on the Tegra X1)
auto robBytes = robWidthBytes * robHeight; // The size of a ROB in bytes auto robBytes = robWidthBytes * robHeight; // The size of a ROB in bytes
auto gobYOffset = robWidthBytes * gobHeight; // The offset of the next Y-axis GOB from the current one in linear space auto gobYOffset = robWidthBytes * gobHeight; // The offset of the next Y-axis GOB from the current one in linear space

View File

@ -25,17 +25,17 @@ namespace skyline::kernel::ipc {
if (header->handleDesc) { if (header->handleDesc) {
handleDesc = reinterpret_cast<HandleDescriptor *>(pointer); handleDesc = reinterpret_cast<HandleDescriptor *>(pointer);
pointer += sizeof(HandleDescriptor) + (handleDesc->sendPid ? sizeof(u64) : 0); pointer += sizeof(HandleDescriptor) + (handleDesc->sendPid ? sizeof(u64) : 0);
for (uint index = 0; handleDesc->copyCount > index; index++) { for (u32 index = 0; handleDesc->copyCount > index; index++) {
copyHandles.push_back(*reinterpret_cast<KHandle *>(pointer)); copyHandles.push_back(*reinterpret_cast<KHandle *>(pointer));
pointer += sizeof(KHandle); pointer += sizeof(KHandle);
} }
for (uint index = 0; handleDesc->moveCount > index; index++) { for (u32 index = 0; handleDesc->moveCount > index; index++) {
moveHandles.push_back(*reinterpret_cast<KHandle *>(pointer)); moveHandles.push_back(*reinterpret_cast<KHandle *>(pointer));
pointer += sizeof(KHandle); pointer += sizeof(KHandle);
} }
} }
for (uint index = 0; header->xNo > index; index++) { for (u8 index = 0; header->xNo > index; index++) {
auto bufX = reinterpret_cast<BufferDescriptorX *>(pointer); auto bufX = reinterpret_cast<BufferDescriptorX *>(pointer);
if (bufX->Address()) { if (bufX->Address()) {
inputBuf.emplace_back(bufX); inputBuf.emplace_back(bufX);
@ -44,7 +44,7 @@ namespace skyline::kernel::ipc {
pointer += sizeof(BufferDescriptorX); pointer += sizeof(BufferDescriptorX);
} }
for (uint index = 0; header->aNo > index; index++) { for (u8 index = 0; header->aNo > index; index++) {
auto bufA = reinterpret_cast<BufferDescriptorABW *>(pointer); auto bufA = reinterpret_cast<BufferDescriptorABW *>(pointer);
if (bufA->Address()) { if (bufA->Address()) {
inputBuf.emplace_back(bufA); inputBuf.emplace_back(bufA);
@ -53,7 +53,7 @@ namespace skyline::kernel::ipc {
pointer += sizeof(BufferDescriptorABW); pointer += sizeof(BufferDescriptorABW);
} }
for (uint index = 0; header->bNo > index; index++) { for (u8 index = 0; header->bNo > index; index++) {
auto bufB = reinterpret_cast<BufferDescriptorABW *>(pointer); auto bufB = reinterpret_cast<BufferDescriptorABW *>(pointer);
if (bufB->Address()) { if (bufB->Address()) {
outputBuf.emplace_back(bufB); outputBuf.emplace_back(bufB);
@ -62,7 +62,7 @@ namespace skyline::kernel::ipc {
pointer += sizeof(BufferDescriptorABW); pointer += sizeof(BufferDescriptorABW);
} }
for (uint index = 0; header->wNo > index; index++) { for (u8 index = 0; header->wNo > index; index++) {
auto bufW = reinterpret_cast<BufferDescriptorABW *>(pointer); auto bufW = reinterpret_cast<BufferDescriptorABW *>(pointer);
if (bufW->Address()) { if (bufW->Address()) {
inputBuf.emplace_back(bufW, IpcBufferType::W); inputBuf.emplace_back(bufW, IpcBufferType::W);
@ -72,9 +72,8 @@ namespace skyline::kernel::ipc {
pointer += sizeof(BufferDescriptorABW); pointer += sizeof(BufferDescriptorABW);
} }
constexpr auto ipcPaddingSum = 0x10; // The sum of the padding surrounding the data payload auto offset = reinterpret_cast<u64>(pointer) - reinterpret_cast<u64>(tls); // We calculate the relative offset as the absolute one might differ
auto padding = util::AlignUp(offset, constant::IpcPaddingSum) - offset; // Calculate the amount of padding at the front
u64 padding = ((((reinterpret_cast<u64>(pointer) - reinterpret_cast<u64>(tls)) - 1U) & ~(ipcPaddingSum - 1U)) + ipcPaddingSum + (reinterpret_cast<u64>(tls) - reinterpret_cast<u64>(pointer))); // Calculate the amount of padding at the front
pointer += padding; pointer += padding;
if (isDomain && (header->type == CommandType::Request)) { if (isDomain && (header->type == CommandType::Request)) {
@ -88,7 +87,7 @@ namespace skyline::kernel::ipc {
cmdArgSz = domain->payloadSz - sizeof(PayloadHeader); cmdArgSz = domain->payloadSz - sizeof(PayloadHeader);
pointer += domain->payloadSz; pointer += domain->payloadSz;
for (uint index = 0; domain->inputCount > index; index++) { for (u8 index = 0; domain->inputCount > index; index++) {
domainObjects.push_back(*reinterpret_cast<KHandle *>(pointer)); domainObjects.push_back(*reinterpret_cast<KHandle *>(pointer));
pointer += sizeof(KHandle); pointer += sizeof(KHandle);
} }
@ -97,18 +96,16 @@ namespace skyline::kernel::ipc {
pointer += sizeof(PayloadHeader); pointer += sizeof(PayloadHeader);
cmdArg = pointer; cmdArg = pointer;
cmdArgSz = (header->rawSize * sizeof(u32)) - (ipcPaddingSum + sizeof(PayloadHeader)); cmdArgSz = (header->rawSize * sizeof(u32)) - (constant::IpcPaddingSum + sizeof(PayloadHeader));
pointer += cmdArgSz; pointer += cmdArgSz;
} }
payloadOffset = cmdArg; payloadOffset = cmdArg;
constexpr auto sfciMagic = 0x49434653; //!< SFCI in reverse, present in received IPC messages if (payload->magic != util::MakeMagic<u32>("SFCI") && header->type != CommandType::Control) // SFCI is the magic in received IPC messages
if (payload->magic != sfciMagic && header->type != CommandType::Control)
state.logger->Debug("Unexpected Magic in PayloadHeader: 0x{:X}", u32(payload->magic)); state.logger->Debug("Unexpected Magic in PayloadHeader: 0x{:X}", u32(payload->magic));
pointer += ipcPaddingSum - padding; pointer += constant::IpcPaddingSum - padding;
if (header->cFlag == BufferCFlag::SingleDescriptor) { if (header->cFlag == BufferCFlag::SingleDescriptor) {
auto bufC = reinterpret_cast<BufferDescriptorC *>(pointer); auto bufC = reinterpret_cast<BufferDescriptorC *>(pointer);
@ -117,7 +114,7 @@ namespace skyline::kernel::ipc {
state.logger->Debug("Buf C: AD: 0x{:X} SZ: 0x{:X}", u64(bufC->address), u16(bufC->size)); state.logger->Debug("Buf C: AD: 0x{:X} SZ: 0x{:X}", u64(bufC->address), u16(bufC->size));
} }
} else if (header->cFlag > BufferCFlag::SingleDescriptor) { } else if (header->cFlag > BufferCFlag::SingleDescriptor) {
for (uint index = 0; (static_cast<u8>(header->cFlag) - 2) > index; index++) { // (cFlag - 2) C descriptors are present for (u8 index = 0; (static_cast<u8>(header->cFlag) - 2) > index; index++) { // (cFlag - 2) C descriptors are present
auto bufC = reinterpret_cast<BufferDescriptorC *>(pointer); auto bufC = reinterpret_cast<BufferDescriptorC *>(pointer);
if (bufC->address) { if (bufC->address) {
outputBuf.emplace_back(bufC); outputBuf.emplace_back(bufC);
@ -143,13 +140,10 @@ namespace skyline::kernel::ipc {
auto tls = state.process->GetPointer<u8>(state.thread->tls); auto tls = state.process->GetPointer<u8>(state.thread->tls);
u8 *pointer = tls; u8 *pointer = tls;
constexpr auto tlsIpcSize = 0x100; // The size of the IPC command buffer in a TLS slot memset(tls, 0, constant::TlsIpcSize);
memset(tls, 0, tlsIpcSize);
constexpr auto ipcPaddingSum = 0x10; // The sum of the padding surrounding the data payload
auto header = reinterpret_cast<CommandHeader *>(pointer); auto header = reinterpret_cast<CommandHeader *>(pointer);
header->rawSize = static_cast<u32>((sizeof(PayloadHeader) + argVec.size() + (domainObjects.size() * sizeof(KHandle)) + ipcPaddingSum + (isDomain ? sizeof(DomainHeaderRequest) : 0)) / sizeof(u32)); // Size is in 32-bit units because Nintendo header->rawSize = static_cast<u32>((sizeof(PayloadHeader) + argVec.size() + (domainObjects.size() * sizeof(KHandle)) + constant::IpcPaddingSum + (isDomain ? sizeof(DomainHeaderRequest) : 0)) / sizeof(u32)); // Size is in 32-bit units because Nintendo
header->handleDesc = (!copyHandles.empty() || !moveHandles.empty()); header->handleDesc = (!copyHandles.empty() || !moveHandles.empty());
pointer += sizeof(CommandHeader); pointer += sizeof(CommandHeader);
@ -159,18 +153,19 @@ namespace skyline::kernel::ipc {
handleDesc->moveCount = static_cast<u8>(moveHandles.size()); handleDesc->moveCount = static_cast<u8>(moveHandles.size());
pointer += sizeof(HandleDescriptor); pointer += sizeof(HandleDescriptor);
for (unsigned int copyHandle : copyHandles) { for (auto copyHandle : copyHandles) {
*reinterpret_cast<KHandle *>(pointer) = copyHandle; *reinterpret_cast<KHandle *>(pointer) = copyHandle;
pointer += sizeof(KHandle); pointer += sizeof(KHandle);
} }
for (unsigned int moveHandle : moveHandles) { for (auto moveHandle : moveHandles) {
*reinterpret_cast<KHandle *>(pointer) = moveHandle; *reinterpret_cast<KHandle *>(pointer) = moveHandle;
pointer += sizeof(KHandle); pointer += sizeof(KHandle);
} }
} }
u64 padding = ((((reinterpret_cast<u64>(pointer) - reinterpret_cast<u64>(tls)) - 1U) & ~(ipcPaddingSum - 1U)) + ipcPaddingSum + (reinterpret_cast<u64>(tls) - reinterpret_cast<u64>(pointer))); // Calculate the amount of padding at the front auto offset = reinterpret_cast<u64>(pointer) - reinterpret_cast<u64>(tls); // We calculate the relative offset as the absolute one might differ
auto padding = util::AlignUp(offset, constant::IpcPaddingSum) - offset; // Calculate the amount of padding at the front
pointer += padding; pointer += padding;
if (isDomain) { if (isDomain) {
@ -179,16 +174,14 @@ namespace skyline::kernel::ipc {
pointer += sizeof(DomainHeaderResponse); pointer += sizeof(DomainHeaderResponse);
} }
constexpr auto sfcoMagic = 0x4F434653; // SFCO in reverse, IPC Response Magic
auto payload = reinterpret_cast<PayloadHeader *>(pointer); auto payload = reinterpret_cast<PayloadHeader *>(pointer);
payload->magic = sfcoMagic; payload->magic = util::MakeMagic<u32>("SFCO"); // SFCO is the magic in IPC responses
payload->version = 1; payload->version = 1;
payload->value = errorCode; payload->value = errorCode;
pointer += sizeof(PayloadHeader); pointer += sizeof(PayloadHeader);
if (!argVec.empty()) if (!argVec.empty())
memcpy(pointer, argVec.data(), argVec.size()); std::memcpy(pointer, argVec.data(), argVec.size());
pointer += argVec.size(); pointer += argVec.size();
if (isDomain) { if (isDomain) {

View File

@ -6,7 +6,13 @@
#include <array> #include <array>
#include <common.h> #include <common.h>
namespace skyline::kernel::ipc { namespace skyline {
namespace constant {
constexpr auto IpcPaddingSum = 0x10; // The sum of the padding surrounding the data payload
constexpr auto TlsIpcSize = 0x100; // The size of the IPC command buffer in a TLS slot
}
namespace kernel::ipc {
/** /**
* @brief This reflects the value in CommandStruct::type * @brief This reflects the value in CommandStruct::type
*/ */
@ -327,4 +333,5 @@ namespace skyline::kernel::ipc {
*/ */
void WriteResponse(); void WriteResponse();
}; };
}
} }

View File

@ -144,8 +144,8 @@ namespace skyline::kernel {
case memory::AddressSpaceType::AddressSpace39Bit: { case memory::AddressSpaceType::AddressSpace39Bit: {
base.address = constant::BaseAddress; base.address = constant::BaseAddress;
base.size = 0x7FF8000000; base.size = 0x7FF8000000;
code.address = utils::AlignDown(address, 0x200000); code.address = util::AlignDown(address, 0x200000);
code.size = utils::AlignUp(address + size, 0x200000) - code.address; code.size = util::AlignUp(address + size, 0x200000) - code.address;
alias.address = code.address + code.size; alias.address = code.address + code.size;
alias.size = 0x1000000000; alias.size = 0x1000000000;
heap.address = alias.address + alias.size; heap.address = alias.address + alias.size;

View File

@ -28,14 +28,14 @@ namespace skyline::kernel::svc {
void SetMemoryAttribute(DeviceState &state) { void SetMemoryAttribute(DeviceState &state) {
auto address = state.ctx->registers.x0; auto address = state.ctx->registers.x0;
if (!utils::PageAligned(address)) { if (!util::PageAligned(address)) {
state.ctx->registers.w0 = constant::status::InvAddress; state.ctx->registers.w0 = constant::status::InvAddress;
state.logger->Warn("svcSetMemoryAttribute: 'address' not page aligned: 0x{:X}", address); state.logger->Warn("svcSetMemoryAttribute: 'address' not page aligned: 0x{:X}", address);
return; return;
} }
auto size = state.ctx->registers.x1; auto size = state.ctx->registers.x1;
if (!utils::PageAligned(size)) { if (!util::PageAligned(size)) {
state.ctx->registers.w0 = constant::status::InvSize; state.ctx->registers.w0 = constant::status::InvSize;
state.logger->Warn("svcSetMemoryAttribute: 'size' {}: 0x{:X}", size ? "not page aligned" : "is zero", size); state.logger->Warn("svcSetMemoryAttribute: 'size' {}: 0x{:X}", size ? "not page aligned" : "is zero", size);
return; return;
@ -77,13 +77,13 @@ namespace skyline::kernel::svc {
auto source = state.ctx->registers.x1; auto source = state.ctx->registers.x1;
auto size = state.ctx->registers.x2; auto size = state.ctx->registers.x2;
if (!utils::PageAligned(destination) || !utils::PageAligned(source)) { if (!util::PageAligned(destination) || !util::PageAligned(source)) {
state.ctx->registers.w0 = constant::status::InvAddress; state.ctx->registers.w0 = constant::status::InvAddress;
state.logger->Warn("svcMapMemory: Addresses not page aligned: Source: 0x{:X}, Destination: 0x{:X} (Size: 0x{:X} bytes)", source, destination, size); state.logger->Warn("svcMapMemory: Addresses not page aligned: Source: 0x{:X}, Destination: 0x{:X} (Size: 0x{:X} bytes)", source, destination, size);
return; return;
} }
if (!utils::PageAligned(size)) { if (!util::PageAligned(size)) {
state.ctx->registers.w0 = constant::status::InvSize; state.ctx->registers.w0 = constant::status::InvSize;
state.logger->Warn("svcMapMemory: 'size' {}: 0x{:X}", size ? "not page aligned" : "is zero", size); state.logger->Warn("svcMapMemory: 'size' {}: 0x{:X}", size ? "not page aligned" : "is zero", size);
return; return;
@ -126,13 +126,13 @@ namespace skyline::kernel::svc {
auto destination = state.ctx->registers.x1; auto destination = state.ctx->registers.x1;
auto size = state.ctx->registers.x2; auto size = state.ctx->registers.x2;
if (!utils::PageAligned(destination) || !utils::PageAligned(source)) { if (!util::PageAligned(destination) || !util::PageAligned(source)) {
state.ctx->registers.w0 = constant::status::InvAddress; state.ctx->registers.w0 = constant::status::InvAddress;
state.logger->Warn("svcUnmapMemory: Addresses not page aligned: Source: 0x{:X}, Destination: 0x{:X} (Size: 0x{:X} bytes)", source, destination, size); state.logger->Warn("svcUnmapMemory: Addresses not page aligned: Source: 0x{:X}, Destination: 0x{:X} (Size: 0x{:X} bytes)", source, destination, size);
return; return;
} }
if (!utils::PageAligned(size)) { if (!util::PageAligned(size)) {
state.ctx->registers.w0 = constant::status::InvSize; state.ctx->registers.w0 = constant::status::InvSize;
state.logger->Warn("svcUnmapMemory: 'size' {}: 0x{:X}", size ? "not page aligned" : "is zero", size); state.logger->Warn("svcUnmapMemory: 'size' {}: 0x{:X}", size ? "not page aligned" : "is zero", size);
return; return;
@ -307,14 +307,14 @@ namespace skyline::kernel::svc {
auto object = state.process->GetHandle<type::KSharedMemory>(state.ctx->registers.w0); auto object = state.process->GetHandle<type::KSharedMemory>(state.ctx->registers.w0);
u64 address = state.ctx->registers.x1; u64 address = state.ctx->registers.x1;
if (!utils::PageAligned(address)) { if (!util::PageAligned(address)) {
state.ctx->registers.w0 = constant::status::InvAddress; state.ctx->registers.w0 = constant::status::InvAddress;
state.logger->Warn("svcMapSharedMemory: 'address' not page aligned: 0x{:X}", address); state.logger->Warn("svcMapSharedMemory: 'address' not page aligned: 0x{:X}", address);
return; return;
} }
auto size = state.ctx->registers.x2; auto size = state.ctx->registers.x2;
if (!utils::PageAligned(size)) { if (!util::PageAligned(size)) {
state.ctx->registers.w0 = constant::status::InvSize; state.ctx->registers.w0 = constant::status::InvSize;
state.logger->Warn("svcMapSharedMemory: 'size' {}: 0x{:X}", size ? "not page aligned" : "is zero", size); state.logger->Warn("svcMapSharedMemory: 'size' {}: 0x{:X}", size ? "not page aligned" : "is zero", size);
return; return;
@ -341,14 +341,14 @@ namespace skyline::kernel::svc {
void CreateTransferMemory(DeviceState &state) { void CreateTransferMemory(DeviceState &state) {
u64 address = state.ctx->registers.x1; u64 address = state.ctx->registers.x1;
if (!utils::PageAligned(address)) { if (!util::PageAligned(address)) {
state.ctx->registers.w0 = constant::status::InvAddress; state.ctx->registers.w0 = constant::status::InvAddress;
state.logger->Warn("svcCreateTransferMemory: 'address' not page aligned: 0x{:X}", address); state.logger->Warn("svcCreateTransferMemory: 'address' not page aligned: 0x{:X}", address);
return; return;
} }
u64 size = state.ctx->registers.x2; u64 size = state.ctx->registers.x2;
if (!utils::PageAligned(size)) { if (!util::PageAligned(size)) {
state.ctx->registers.w0 = constant::status::InvSize; state.ctx->registers.w0 = constant::status::InvSize;
state.logger->Warn("svcCreateTransferMemory: 'size' {}: 0x{:X}", size ? "not page aligned" : "is zero", size); state.logger->Warn("svcCreateTransferMemory: 'size' {}: 0x{:X}", size ? "not page aligned" : "is zero", size);
return; return;
@ -449,7 +449,7 @@ namespace skyline::kernel::svc {
auto timeout = state.ctx->registers.x3; auto timeout = state.ctx->registers.x3;
state.logger->Debug("svcWaitSynchronization: Waiting on handles:\n{}Timeout: 0x{:X} ns", handleStr, timeout); state.logger->Debug("svcWaitSynchronization: Waiting on handles:\n{}Timeout: 0x{:X} ns", handleStr, timeout);
auto start = utils::GetTimeNs(); auto start = util::GetTimeNs();
while (true) { while (true) {
if (state.thread->cancelSync) { if (state.thread->cancelSync) {
state.thread->cancelSync = false; state.thread->cancelSync = false;
@ -468,7 +468,7 @@ namespace skyline::kernel::svc {
index++; index++;
} }
if ((utils::GetTimeNs() - start) >= timeout) { if ((util::GetTimeNs() - start) >= timeout) {
state.logger->Debug("svcWaitSynchronization: Wait has timed out"); state.logger->Debug("svcWaitSynchronization: Wait has timed out");
state.ctx->registers.w0 = constant::status::Timeout; state.ctx->registers.w0 = constant::status::Timeout;
return; return;
@ -487,7 +487,7 @@ namespace skyline::kernel::svc {
void ArbitrateLock(DeviceState &state) { void ArbitrateLock(DeviceState &state) {
auto address = state.ctx->registers.x1; auto address = state.ctx->registers.x1;
if (!utils::WordAligned(address)) { if (!util::WordAligned(address)) {
state.logger->Warn("svcArbitrateLock: 'address' not word aligned: 0x{:X}", address); state.logger->Warn("svcArbitrateLock: 'address' not word aligned: 0x{:X}", address);
state.ctx->registers.w0 = constant::status::InvAddress; state.ctx->registers.w0 = constant::status::InvAddress;
return; return;
@ -510,7 +510,7 @@ namespace skyline::kernel::svc {
void ArbitrateUnlock(DeviceState &state) { void ArbitrateUnlock(DeviceState &state) {
auto address = state.ctx->registers.x0; auto address = state.ctx->registers.x0;
if (!utils::WordAligned(address)) { if (!util::WordAligned(address)) {
state.logger->Warn("svcArbitrateUnlock: 'address' not word aligned: 0x{:X}", address); state.logger->Warn("svcArbitrateUnlock: 'address' not word aligned: 0x{:X}", address);
state.ctx->registers.w0 = constant::status::InvAddress; state.ctx->registers.w0 = constant::status::InvAddress;
return; return;
@ -529,7 +529,7 @@ namespace skyline::kernel::svc {
void WaitProcessWideKeyAtomic(DeviceState &state) { void WaitProcessWideKeyAtomic(DeviceState &state) {
auto mtxAddress = state.ctx->registers.x0; auto mtxAddress = state.ctx->registers.x0;
if (!utils::WordAligned(mtxAddress)) { if (!util::WordAligned(mtxAddress)) {
state.logger->Warn("svcWaitProcessWideKeyAtomic: mutex address not word aligned: 0x{:X}", mtxAddress); state.logger->Warn("svcWaitProcessWideKeyAtomic: mutex address not word aligned: 0x{:X}", mtxAddress);
state.ctx->registers.w0 = constant::status::InvAddress; state.ctx->registers.w0 = constant::status::InvAddress;
return; return;

View File

@ -10,7 +10,7 @@
namespace skyline::kernel::type { namespace skyline::kernel::type {
KPrivateMemory::KPrivateMemory(const DeviceState &state, u64 address, size_t size, memory::Permission permission, const memory::MemoryState memState) : size(size), KMemory(state, KType::KPrivateMemory) { KPrivateMemory::KPrivateMemory(const DeviceState &state, u64 address, size_t size, memory::Permission permission, const memory::MemoryState memState) : size(size), KMemory(state, KType::KPrivateMemory) {
if (address && !utils::PageAligned(address)) if (address && !util::PageAligned(address))
throw exception("KPrivateMemory was created with non-page-aligned address: 0x{:X}", address); throw exception("KPrivateMemory was created with non-page-aligned address: 0x{:X}", address);
fd = ASharedMemory_create("KPrivateMemory", size); fd = ASharedMemory_create("KPrivateMemory", size);

View File

@ -112,7 +112,7 @@ namespace skyline::kernel::type {
auto source = GetHostAddress(offset); auto source = GetHostAddress(offset);
if (source) { if (source) {
memcpy(destination, reinterpret_cast<void *>(source), size); std::memcpy(destination, reinterpret_cast<void *>(source), size);
return; return;
} }
} }
@ -136,7 +136,7 @@ namespace skyline::kernel::type {
auto destination = GetHostAddress(offset); auto destination = GetHostAddress(offset);
if (destination) { if (destination) {
memcpy(reinterpret_cast<void *>(destination), source, size); std::memcpy(reinterpret_cast<void *>(destination), source, size);
return; return;
} }
} }
@ -160,7 +160,7 @@ namespace skyline::kernel::type {
auto destinationHost = GetHostAddress(destination); auto destinationHost = GetHostAddress(destination);
if (sourceHost && destinationHost) { if (sourceHost && destinationHost) {
memcpy(reinterpret_cast<void *>(destinationHost), reinterpret_cast<const void *>(sourceHost), size); std::memcpy(reinterpret_cast<void *>(destinationHost), reinterpret_cast<const void *>(sourceHost), size);
} else { } else {
if (size <= PAGE_SIZE) { if (size <= PAGE_SIZE) {
std::vector<u8> buffer(size); std::vector<u8> buffer(size);
@ -282,9 +282,9 @@ namespace skyline::kernel::type {
lock.unlock(); lock.unlock();
bool timedOut{}; bool timedOut{};
auto start = utils::GetTimeNs(); auto start = util::GetTimeNs();
while (!status->flag) while (!status->flag)
if ((utils::GetTimeNs() - start) >= timeout) if ((util::GetTimeNs() - start) >= timeout)
timedOut = true; timedOut = true;
lock.lock(); lock.lock();

View File

@ -10,7 +10,7 @@
namespace skyline::kernel::type { namespace skyline::kernel::type {
KSharedMemory::KSharedMemory(const DeviceState &state, u64 address, size_t size, const memory::Permission permission, memory::MemoryState memState, int mmapFlags) : initialState(memState), KMemory(state, KType::KSharedMemory) { KSharedMemory::KSharedMemory(const DeviceState &state, u64 address, size_t size, const memory::Permission permission, memory::MemoryState memState, int mmapFlags) : initialState(memState), KMemory(state, KType::KSharedMemory) {
if (address && !utils::PageAligned(address)) if (address && !util::PageAligned(address))
throw exception("KSharedMemory was created with non-page-aligned address: 0x{:X}", address); throw exception("KSharedMemory was created with non-page-aligned address: 0x{:X}", address);
fd = ASharedMemory_create("KSharedMemory", size); fd = ASharedMemory_create("KSharedMemory", size);
@ -25,7 +25,7 @@ namespace skyline::kernel::type {
} }
u64 KSharedMemory::Map(const u64 address, const u64 size, memory::Permission permission) { u64 KSharedMemory::Map(const u64 address, const u64 size, memory::Permission permission) {
if (address && !utils::PageAligned(address)) if (address && !util::PageAligned(address))
throw exception("KSharedMemory was mapped to a non-page-aligned address: 0x{:X}", address); throw exception("KSharedMemory was mapped to a non-page-aligned address: 0x{:X}", address);
Registers fregs{ Registers fregs{
@ -129,7 +129,7 @@ namespace skyline::kernel::type {
throw exception("An error occurred while creating shared memory: {}", fd); throw exception("An error occurred while creating shared memory: {}", fd);
std::vector<u8> data(std::min(size, kernel.size)); std::vector<u8> data(std::min(size, kernel.size));
memcpy(data.data(), reinterpret_cast<const void *>(kernel.address), std::min(size, kernel.size)); std::memcpy(data.data(), reinterpret_cast<const void *>(kernel.address), std::min(size, kernel.size));
munmap(reinterpret_cast<void *>(kernel.address), kernel.size); munmap(reinterpret_cast<void *>(kernel.address), kernel.size);
@ -137,7 +137,7 @@ namespace skyline::kernel::type {
if (address == MAP_FAILED) if (address == MAP_FAILED)
throw exception("An occurred while mapping shared memory: {}", strerror(errno)); throw exception("An occurred while mapping shared memory: {}", strerror(errno));
memcpy(address, data.data(), std::min(size, kernel.size)); std::memcpy(address, data.data(), std::min(size, kernel.size));
kernel.address = reinterpret_cast<u64>(address); kernel.address = reinterpret_cast<u64>(address);
kernel.size = size; kernel.size = size;

View File

@ -8,7 +8,7 @@
namespace skyline::kernel::type { namespace skyline::kernel::type {
KTransferMemory::KTransferMemory(const DeviceState &state, bool host, u64 address, size_t size, const memory::Permission permission, memory::MemoryState memState) : host(host), size(size), KMemory(state, KType::KTransferMemory) { KTransferMemory::KTransferMemory(const DeviceState &state, bool host, u64 address, size_t size, const memory::Permission permission, memory::MemoryState memState) : host(host), size(size), KMemory(state, KType::KTransferMemory) {
if (address && !utils::PageAligned(address)) if (address && !util::PageAligned(address))
throw exception("KTransferMemory was created with non-page-aligned address: 0x{:X}", address); throw exception("KTransferMemory was created with non-page-aligned address: 0x{:X}", address);
BlockDescriptor block{ BlockDescriptor block{
@ -53,7 +53,7 @@ namespace skyline::kernel::type {
} }
u64 KTransferMemory::Transfer(bool mHost, u64 nAddress, u64 nSize) { u64 KTransferMemory::Transfer(bool mHost, u64 nAddress, u64 nSize) {
if (nAddress && !utils::PageAligned(nAddress)) if (nAddress && !util::PageAligned(nAddress))
throw exception("KTransferMemory was transferred to a non-page-aligned address: 0x{:X}", nAddress); throw exception("KTransferMemory was transferred to a non-page-aligned address: 0x{:X}", nAddress);
nSize = nSize ? nSize : size; nSize = nSize ? nSize : size;
@ -95,7 +95,7 @@ namespace skyline::kernel::type {
else if (!mHost && !host) else if (!mHost && !host)
state.process->CopyMemory(address, nAddress, block.size); state.process->CopyMemory(address, nAddress, block.size);
else if (mHost && host) else if (mHost && host)
memcpy(reinterpret_cast<void *>(nAddress), reinterpret_cast<void *>(address), block.size); std::memcpy(reinterpret_cast<void *>(nAddress), reinterpret_cast<void *>(address), block.size);
} }
if (!block.permission.w) { if (!block.permission.w) {
if (mHost) { if (mHost) {

View File

@ -9,9 +9,7 @@ namespace skyline::loader {
NroLoader::NroLoader(const int romFd) : Loader(romFd) { NroLoader::NroLoader(const int romFd) : Loader(romFd) {
ReadOffset((u32 *) &header, 0x0, sizeof(NroHeader)); ReadOffset((u32 *) &header, 0x0, sizeof(NroHeader));
constexpr auto nroMagic = 0x304F524E; // "NRO0" in reverse, this is written at the start of every NRO file if (header.magic != util::MakeMagic<u32>("NRO0"))
if (header.magic != nroMagic)
throw exception("Invalid NRO magic! 0x{0:X}", header.magic); throw exception("Invalid NRO magic! 0x{0:X}", header.magic);
} }
@ -30,7 +28,7 @@ namespace skyline::loader {
u64 rodataSize = rodata.size(); u64 rodataSize = rodata.size();
u64 dataSize = data.size(); u64 dataSize = data.size();
u64 patchSize = patch.size() * sizeof(u32); u64 patchSize = patch.size() * sizeof(u32);
u64 padding = utils::AlignUp(textSize + rodataSize + dataSize + header.bssSize + patchSize, PAGE_SIZE) - (textSize + rodataSize + dataSize + header.bssSize + patchSize); u64 padding = util::AlignUp(textSize + rodataSize + dataSize + header.bssSize + patchSize, PAGE_SIZE) - (textSize + rodataSize + dataSize + header.bssSize + patchSize);
process->NewHandle<kernel::type::KPrivateMemory>(constant::BaseAddress, textSize, memory::Permission{true, true, true}, memory::states::CodeStatic); // R-X process->NewHandle<kernel::type::KPrivateMemory>(constant::BaseAddress, textSize, memory::Permission{true, true, true}, memory::states::CodeStatic); // R-X
state.logger->Debug("Successfully mapped section .text @ 0x{0:X}, Size = 0x{1:X}", constant::BaseAddress, textSize); state.logger->Debug("Successfully mapped section .text @ 0x{0:X}, Size = 0x{1:X}", constant::BaseAddress, textSize);

View File

@ -8,7 +8,7 @@
namespace skyline { namespace skyline {
namespace constant { namespace constant {
constexpr u32 SupportedRevision = 7; //!< The audren revision our implementation supports constexpr u32 SupportedRevision = 7; //!< The audren revision our implementation supports
constexpr u32 Rev0Magic = ('R' << 0) | ('E' << 8) | ('V' << 16) | ('0' << 24); //!< The HOS 1.0 revision magic constexpr u32 Rev0Magic = util::MakeMagic<u32>("REV0"); //!< The HOS 1.0 revision magic
constexpr u32 RevMagic = Rev0Magic + (SupportedRevision << 24); //!< The revision magic for our supported revision constexpr u32 RevMagic = Rev0Magic + (SupportedRevision << 24); //!< The revision magic for our supported revision
namespace supportTags { namespace supportTags {