diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml index a4a819fd..30c29deb 100644 --- a/.idea/codeStyles/Project.xml +++ b/.idea/codeStyles/Project.xml @@ -20,6 +20,7 @@ + diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 51267723..4f092d61 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -2,14 +2,11 @@ - - - + android:launchMode="singleInstance" + android:screenOrientation="landscape"> - - - - - diff --git a/app/src/main/cpp/skyline/common.cpp b/app/src/main/cpp/skyline/common.cpp index d8a68ae0..a4c5dd86 100644 --- a/app/src/main/cpp/skyline/common.cpp +++ b/app/src/main/cpp/skyline/common.cpp @@ -30,16 +30,18 @@ namespace skyline { num++; return; } - } else + } else { flag.compare_exchange_weak(none, group); + } } else if (flag == group && (next == Group::None || utils::GetTimeNs() >= end)) { std::lock_guard lock(mtx); if (flag == group) { num++; return; } - } else + } else { next.compare_exchange_weak(none, group); + } none = Group::None; asm volatile("yield"); } diff --git a/app/src/main/cpp/skyline/common.h b/app/src/main/cpp/skyline/common.h index 4ce173db..3600c746 100644 --- a/app/src/main/cpp/skyline/common.h +++ b/app/src/main/cpp/skyline/common.h @@ -122,8 +122,7 @@ namespace skyline { template inline TypeVal AlignUp(TypeVal value, TypeMul multiple) { static_assert(std::is_integral() && std::is_integral()); - multiple--; - return (value + multiple) & ~multiple; + return (value + multiple) & ~(multiple - 1); } /** @@ -137,8 +136,7 @@ namespace skyline { template inline TypeVal AlignDown(TypeVal value, TypeMul multiple) { static_assert(std::is_integral() && std::is_integral()); - multiple--; - return value & ~multiple; + return value & ~(multiple - 1); } /** @@ -212,9 +210,9 @@ namespace skyline { void unlock(); private: - std::atomic flag = Group::None; //!< An atomic flag to hold which group holds the mutex - std::atomic next = Group::None; //!< An atomic flag to hold which group will hold the mutex next - std::atomic num = 0; //!< An atomic u8 keeping track of how many users are holding the mutex + std::atomic flag{Group::None}; //!< An atomic flag to hold which group holds the mutex + std::atomic next{Group::None}; //!< An atomic flag to hold which group will hold the mutex next + std::atomic num{0}; //!< An atomic u8 keeping track of how many users are holding the mutex Mutex mtx; //!< A mutex to lock before changing of num and flag }; diff --git a/app/src/main/cpp/skyline/gpu.cpp b/app/src/main/cpp/skyline/gpu.cpp index d6984297..f0c1e84b 100644 --- a/app/src/main/cpp/skyline/gpu.cpp +++ b/app/src/main/cpp/skyline/gpu.cpp @@ -44,7 +44,7 @@ namespace skyline::gpu { resolution = buffer->resolution; format = buffer->gbpBuffer.format; } - u8 *inBuffer = buffer->dataBuffer.data(); + u8 *inBuffer = buffer->GetAddress(); madvise(inBuffer, buffer->gbpBuffer.size, MADV_SEQUENTIAL); ANativeWindow_Buffer windowBuffer; ARect rect; diff --git a/app/src/main/cpp/skyline/gpu/devices/nvhost_channel.cpp b/app/src/main/cpp/skyline/gpu/devices/nvhost_channel.cpp index 96679302..48c3f482 100644 --- a/app/src/main/cpp/skyline/gpu/devices/nvhost_channel.cpp +++ b/app/src/main/cpp/skyline/gpu/devices/nvhost_channel.cpp @@ -21,7 +21,7 @@ namespace skyline::gpu::device { void NvHostChannel::SetErrorNotifier(skyline::gpu::device::IoctlData &buffer) {} void NvHostChannel::SetPriority(skyline::gpu::device::IoctlData &buffer) { - auto priority = state.process->ReadMemory(buffer.input[0].address); + auto priority = state.process->GetObject(buffer.input[0].address); switch (priority) { case NvChannelPriority::Low: timeslice = 1300; diff --git a/app/src/main/cpp/skyline/gpu/devices/nvhost_ctrl_gpu.cpp b/app/src/main/cpp/skyline/gpu/devices/nvhost_ctrl_gpu.cpp index cbffc080..a2660621 100644 --- a/app/src/main/cpp/skyline/gpu/devices/nvhost_ctrl_gpu.cpp +++ b/app/src/main/cpp/skyline/gpu/devices/nvhost_ctrl_gpu.cpp @@ -73,7 +73,7 @@ namespace skyline::gpu::device { u64 gpuCharacteristicsBufSize; // InOut u64 gpuCharacteristicsBufAddr; // In GpuCharacteristics gpuCharacteristics; // Out - } data = state.process->ReadMemory(buffer.input[0].address); + } data = state.process->GetObject(buffer.input[0].address); data.gpuCharacteristics = { .arch = 0x120, .impl = 0xB, @@ -119,7 +119,7 @@ namespace skyline::gpu::device { u32 maskBufSize; // In u32 reserved[3]; // In u64 maskBuf; // Out - } data = state.process->ReadMemory(buffer.input[0].address); + } data = state.process->GetObject(buffer.input[0].address); if (data.maskBufSize) data.maskBuf = 0x3; state.process->WriteMemory(data, buffer.output[0].address); diff --git a/app/src/main/cpp/skyline/gpu/devices/nvmap.cpp b/app/src/main/cpp/skyline/gpu/devices/nvmap.cpp index d0512955..08421c0b 100644 --- a/app/src/main/cpp/skyline/gpu/devices/nvmap.cpp +++ b/app/src/main/cpp/skyline/gpu/devices/nvmap.cpp @@ -17,7 +17,7 @@ namespace skyline::gpu::device { struct Data { u32 size; // In u32 handle; // Out - } data = state.process->ReadMemory(buffer.input[0].address); + } data = state.process->GetObject(buffer.input[0].address); handleTable[handleIndex] = std::make_shared(idIndex++, data.size); data.handle = handleIndex++; state.process->WriteMemory(data, buffer.output[0].address); @@ -28,7 +28,7 @@ namespace skyline::gpu::device { struct Data { u32 id; // In u32 handle; // Out - } data = state.process->ReadMemory(buffer.input[0].address); + } data = state.process->GetObject(buffer.input[0].address); bool found{}; for (const auto &object : handleTable) { if (object.second->id == data.id) { @@ -53,7 +53,7 @@ namespace skyline::gpu::device { u8 kind; // In u8 _pad0_[7]; u64 address; // InOut - } data = state.process->ReadMemory(buffer.input[0].address); + } data = state.process->GetObject(buffer.input[0].address); auto &object = handleTable.at(data.handle); object->heapMask = data.heapMask; object->flags = data.flags; @@ -71,7 +71,7 @@ namespace skyline::gpu::device { u32 address; // Out u32 size; // Out u64 flags; // Out - } data = state.process->ReadMemory(buffer.input[0].address); + } data = state.process->GetObject(buffer.input[0].address); const auto &object = handleTable.at(data.handle); if (object.use_count() > 1) { data.address = static_cast(object->address); @@ -91,7 +91,7 @@ namespace skyline::gpu::device { u32 handle; // In Parameter parameter; // In u32 result; // Out - } data = state.process->ReadMemory(buffer.input[0].address); + } data = state.process->GetObject(buffer.input[0].address); auto &object = handleTable.at(data.handle); switch (data.parameter) { case Parameter::Size: @@ -132,7 +132,7 @@ namespace skyline::gpu::device { struct Data { u32 id; // Out u32 handle; // In - } data = state.process->ReadMemory(buffer.input[0].address); + } data = state.process->GetObject(buffer.input[0].address); data.id = handleTable.at(data.handle)->id; state.process->WriteMemory(data, buffer.output[0].address); state.logger->Debug("GetId: Input: Handle: 0x{:X}, Output: ID: 0x{:X}, Status: {}", data.handle, data.id, buffer.status); diff --git a/app/src/main/cpp/skyline/gpu/display.cpp b/app/src/main/cpp/skyline/gpu/display.cpp index 49c7b614..83a3f1b5 100644 --- a/app/src/main/cpp/skyline/gpu/display.cpp +++ b/app/src/main/cpp/skyline/gpu/display.cpp @@ -3,7 +3,7 @@ #include namespace skyline::gpu { - Buffer::Buffer(const DeviceState &state, u32 slot, GbpBuffer &gbpBuffer) : state(state), slot(slot), gbpBuffer(gbpBuffer), resolution{gbpBuffer.width, gbpBuffer.height}, dataBuffer(gbpBuffer.size) { + Buffer::Buffer(const DeviceState &state, u32 slot, GbpBuffer &gbpBuffer) : state(state), slot(slot), gbpBuffer(gbpBuffer), resolution{gbpBuffer.width, gbpBuffer.height} { if (gbpBuffer.nvmapHandle) nvBuffer = state.gpu->GetDevice(device::NvDeviceType::nvmap)->handleTable.at(gbpBuffer.nvmapHandle); else { @@ -30,8 +30,8 @@ namespace skyline::gpu { } } - void Buffer::UpdateBuffer() { - state.process->ReadMemory(dataBuffer.data(), nvBuffer->address + gbpBuffer.offset, gbpBuffer.size); + u8 *Buffer::GetAddress() { + return state.process->GetPointer(nvBuffer->address + gbpBuffer.offset); } BufferQueue::BufferQueue(const DeviceState &state) : state(state) {} @@ -89,7 +89,6 @@ namespace skyline::gpu { } *data = reinterpret_cast(in.data.data() + constant::TokenLength); auto buffer = queue.at(data->slot); buffer->status = BufferStatus::Queued; - buffer->UpdateBuffer(); displayQueue.emplace(buffer); state.gpu->bufferEvent->Signal(); struct { diff --git a/app/src/main/cpp/skyline/gpu/display.h b/app/src/main/cpp/skyline/gpu/display.h index 0d08022e..2e153af5 100644 --- a/app/src/main/cpp/skyline/gpu/display.h +++ b/app/src/main/cpp/skyline/gpu/display.h @@ -104,7 +104,6 @@ namespace skyline::gpu { Resolution resolution; //!< The resolution of this buffer GbpBuffer gbpBuffer; //!< The information about the underlying buffer BufferStatus status{BufferStatus::Free}; //!< The status of this buffer - std::vector dataBuffer; //!< The vector holding the actual pixel data std::shared_ptr nvBuffer{}; //!< A shared pointer to the buffer's nvmap object /** @@ -115,9 +114,9 @@ namespace skyline::gpu { Buffer(const DeviceState &state, u32 slot, GbpBuffer &gbpBuffer); /** - * @brief This reads the buffer from the process into the dataBuffer vector + * @return The address of the buffer on the kernel */ - void UpdateBuffer(); + u8* GetAddress(); }; /** diff --git a/app/src/main/cpp/skyline/kernel/ipc.cpp b/app/src/main/cpp/skyline/kernel/ipc.cpp index 000e3851..396b075b 100644 --- a/app/src/main/cpp/skyline/kernel/ipc.cpp +++ b/app/src/main/cpp/skyline/kernel/ipc.cpp @@ -12,88 +12,88 @@ namespace skyline::kernel::ipc { OutputBuffer::OutputBuffer(kernel::ipc::BufferDescriptorC *cBuf) : IpcBuffer(cBuf->address, cBuf->size, IpcBufferType::C) {} - IpcRequest::IpcRequest(bool isDomain, const DeviceState &state) : isDomain(isDomain), state(state), tls() { - u8 *currPtr = tls.data(); - state.process->ReadMemory(currPtr, state.thread->tls, constant::TlsIpcSize); + IpcRequest::IpcRequest(bool isDomain, const DeviceState &state) : isDomain(isDomain), state(state) { + u8 *tls = state.process->GetPointer(state.thread->tls); + u8 *pointer = tls; - header = reinterpret_cast(currPtr); - currPtr += sizeof(CommandHeader); + header = reinterpret_cast(pointer); + pointer += sizeof(CommandHeader); if (header->handleDesc) { - handleDesc = reinterpret_cast(currPtr); - currPtr += sizeof(HandleDescriptor) + (handleDesc->sendPid ? sizeof(u64) : 0); + handleDesc = reinterpret_cast(pointer); + pointer += sizeof(HandleDescriptor) + (handleDesc->sendPid ? sizeof(u64) : 0); for (uint index = 0; handleDesc->copyCount > index; index++) { - copyHandles.push_back(*reinterpret_cast(currPtr)); - currPtr += sizeof(handle_t); + copyHandles.push_back(*reinterpret_cast(pointer)); + pointer += sizeof(handle_t); } for (uint index = 0; handleDesc->moveCount > index; index++) { - moveHandles.push_back(*reinterpret_cast(currPtr)); - currPtr += sizeof(handle_t); + moveHandles.push_back(*reinterpret_cast(pointer)); + pointer += sizeof(handle_t); } } for (uint index = 0; header->xNo > index; index++) { - auto bufX = reinterpret_cast(currPtr); + auto bufX = reinterpret_cast(pointer); if (bufX->Address()) { inputBuf.emplace_back(bufX); state.logger->Debug("Buf X #{} AD: 0x{:X} SZ: 0x{:X} CTR: {}", index, u64(bufX->Address()), u16(bufX->size), u16(bufX->Counter())); } - currPtr += sizeof(BufferDescriptorX); + pointer += sizeof(BufferDescriptorX); } for (uint index = 0; header->aNo > index; index++) { - auto bufA = reinterpret_cast(currPtr); + auto bufA = reinterpret_cast(pointer); if (bufA->Address()) { inputBuf.emplace_back(bufA); state.logger->Debug("Buf A #{} AD: 0x{:X} SZ: 0x{:X}", index, u64(bufA->Address()), u64(bufA->Size())); } - currPtr += sizeof(BufferDescriptorABW); + pointer += sizeof(BufferDescriptorABW); } for (uint index = 0; header->bNo > index; index++) { - auto bufB = reinterpret_cast(currPtr); + auto bufB = reinterpret_cast(pointer); if (bufB->Address()) { outputBuf.emplace_back(bufB); state.logger->Debug("Buf B #{} AD: 0x{:X} SZ: 0x{:X}", index, u64(bufB->Address()), u64(bufB->Size())); } - currPtr += sizeof(BufferDescriptorABW); + pointer += sizeof(BufferDescriptorABW); } for (uint index = 0; header->wNo > index; index++) { - auto bufW = reinterpret_cast(currPtr); + auto bufW = reinterpret_cast(pointer); if (bufW->Address()) { inputBuf.emplace_back(bufW, IpcBufferType::W); outputBuf.emplace_back(bufW, IpcBufferType::W); state.logger->Debug("Buf W #{} AD: 0x{:X} SZ: 0x{:X}", index, u64(bufW->Address()), u16(bufW->Size())); } - currPtr += sizeof(BufferDescriptorABW); + pointer += sizeof(BufferDescriptorABW); } - u64 padding = ((((reinterpret_cast(currPtr) - reinterpret_cast(tls.data())) - 1U) & ~(constant::IpcPaddingSum - 1U)) + constant::IpcPaddingSum + (reinterpret_cast(tls.data()) - reinterpret_cast(currPtr))); // Calculate the amount of padding at the front - currPtr += padding; + u64 padding = ((((reinterpret_cast(pointer) - reinterpret_cast(tls)) - 1U) & ~(constant::IpcPaddingSum - 1U)) + constant::IpcPaddingSum + (reinterpret_cast(tls) - reinterpret_cast(pointer))); // Calculate the amount of padding at the front + pointer += padding; if (isDomain && (header->type == CommandType::Request)) { - domain = reinterpret_cast(currPtr); - currPtr += sizeof(DomainHeaderRequest); + domain = reinterpret_cast(pointer); + pointer += sizeof(DomainHeaderRequest); - payload = reinterpret_cast(currPtr); - currPtr += sizeof(PayloadHeader); + payload = reinterpret_cast(pointer); + pointer += sizeof(PayloadHeader); - cmdArg = currPtr; + cmdArg = pointer; cmdArgSz = domain->payloadSz - sizeof(PayloadHeader); - currPtr += domain->payloadSz; + pointer += domain->payloadSz; for (uint index = 0; domain->inputCount > index; index++) { - domainObjects.push_back(*reinterpret_cast(currPtr)); - currPtr += sizeof(handle_t); + domainObjects.push_back(*reinterpret_cast(pointer)); + pointer += sizeof(handle_t); } } else { - payload = reinterpret_cast(currPtr); - currPtr += sizeof(PayloadHeader); + payload = reinterpret_cast(pointer); + pointer += sizeof(PayloadHeader); - cmdArg = currPtr; + cmdArg = pointer; cmdArgSz = (header->rawSize * sizeof(u32)) - (constant::IpcPaddingSum + sizeof(PayloadHeader)); - currPtr += cmdArgSz; + pointer += cmdArgSz; } payloadOffset = cmdArg; @@ -101,22 +101,22 @@ namespace skyline::kernel::ipc { if (payload->magic != constant::SfciMagic && header->type != CommandType::Control) state.logger->Debug("Unexpected Magic in PayloadHeader: 0x{:X}", u32(payload->magic)); - currPtr += constant::IpcPaddingSum - padding; + pointer += constant::IpcPaddingSum - padding; if (header->cFlag == BufferCFlag::SingleDescriptor) { - auto bufC = reinterpret_cast(currPtr); + auto bufC = reinterpret_cast(pointer); if (bufC->address) { outputBuf.emplace_back(bufC); state.logger->Debug("Buf C: AD: 0x{:X} SZ: 0x{:X}", u64(bufC->address), u16(bufC->size)); } } else if (header->cFlag > BufferCFlag::SingleDescriptor) { for (uint index = 0; (static_cast(header->cFlag) - 2) > index; index++) { // (cFlag - 2) C descriptors are present - auto bufC = reinterpret_cast(currPtr); + auto bufC = reinterpret_cast(pointer); if (bufC->address) { outputBuf.emplace_back(bufC); state.logger->Debug("Buf C #{} AD: 0x{:X} SZ: 0x{:X}", index, u64(bufC->address), u16(bufC->size)); } - currPtr += sizeof(BufferDescriptorC); + pointer += sizeof(BufferDescriptorC); } } @@ -133,63 +133,57 @@ namespace skyline::kernel::ipc { IpcResponse::IpcResponse(bool isDomain, const DeviceState &state) : isDomain(isDomain), state(state) {} void IpcResponse::WriteResponse() { - std::array tls{}; - u8 *currPtr = tls.data(); - auto header = reinterpret_cast(currPtr); + auto tls = state.process->GetPointer(state.thread->tls); + u8 *pointer = tls; + memset(tls, 0, constant::TlsIpcSize); + + auto header = reinterpret_cast(pointer); header->rawSize = static_cast((sizeof(PayloadHeader) + argVec.size() + (domainObjects.size() * sizeof(handle_t)) + constant::IpcPaddingSum + (isDomain ? sizeof(DomainHeaderRequest) : 0)) / sizeof(u32)); // Size is in 32-bit units because Nintendo header->handleDesc = (!copyHandles.empty() || !moveHandles.empty()); - currPtr += sizeof(CommandHeader); + pointer += sizeof(CommandHeader); if (header->handleDesc) { - auto handleDesc = reinterpret_cast(currPtr); + auto handleDesc = reinterpret_cast(pointer); handleDesc->copyCount = static_cast(copyHandles.size()); handleDesc->moveCount = static_cast(moveHandles.size()); - currPtr += sizeof(HandleDescriptor); + pointer += sizeof(HandleDescriptor); for (unsigned int copyHandle : copyHandles) { - *reinterpret_cast(currPtr) = copyHandle; - currPtr += sizeof(handle_t); + *reinterpret_cast(pointer) = copyHandle; + pointer += sizeof(handle_t); } for (unsigned int moveHandle : moveHandles) { - *reinterpret_cast(currPtr) = moveHandle; - currPtr += sizeof(handle_t); + *reinterpret_cast(pointer) = moveHandle; + pointer += sizeof(handle_t); } } - u64 padding = ((((reinterpret_cast(currPtr) - reinterpret_cast(tls.data())) - 1U) & ~(constant::IpcPaddingSum - 1U)) + constant::IpcPaddingSum + (reinterpret_cast(tls.data()) - reinterpret_cast(currPtr))); // Calculate the amount of padding at the front - currPtr += padding; + u64 padding = ((((reinterpret_cast(pointer) - reinterpret_cast(tls)) - 1U) & ~(constant::IpcPaddingSum - 1U)) + constant::IpcPaddingSum + (reinterpret_cast(tls) - reinterpret_cast(pointer))); // Calculate the amount of padding at the front + pointer += padding; if (isDomain) { - auto domain = reinterpret_cast(currPtr); + auto domain = reinterpret_cast(pointer); domain->outputCount = static_cast(domainObjects.size()); - currPtr += sizeof(DomainHeaderResponse); + pointer += sizeof(DomainHeaderResponse); } - auto payload = reinterpret_cast(currPtr); + auto payload = reinterpret_cast(pointer); payload->magic = constant::SfcoMagic; payload->version = 1; payload->value = errorCode; - currPtr += sizeof(PayloadHeader); + pointer += sizeof(PayloadHeader); if (!argVec.empty()) - memcpy(currPtr, argVec.data(), argVec.size()); - currPtr += argVec.size(); + memcpy(pointer, argVec.data(), argVec.size()); + pointer += argVec.size(); if (isDomain) { for (auto &domainObject : domainObjects) { - *reinterpret_cast(currPtr) = domainObject; - currPtr += sizeof(handle_t); + *reinterpret_cast(pointer) = domainObject; + pointer += sizeof(handle_t); } } state.logger->Debug("Output: Raw Size: {}, Command ID: 0x{:X}, Copy Handles: {}, Move Handles: {}", u32(header->rawSize), u32(payload->value), copyHandles.size(), moveHandles.size()); - - state.process->WriteMemory(tls.data(), state.thread->tls, constant::TlsIpcSize); - } - - std::vector BufferDescriptorABW::Read(const DeviceState &state) { - std::vector vec(Size()); - state.process->ReadMemory(vec.data(), Address(), Size()); - return std::move(vec); } } diff --git a/app/src/main/cpp/skyline/kernel/ipc.h b/app/src/main/cpp/skyline/kernel/ipc.h index aa4805db..266bf01b 100644 --- a/app/src/main/cpp/skyline/kernel/ipc.h +++ b/app/src/main/cpp/skyline/kernel/ipc.h @@ -98,12 +98,12 @@ namespace skyline::kernel::ipc { * @brief This is a buffer descriptor for X buffers: https://switchbrew.org/wiki/IPC_Marshalling#Buffer_descriptor_X_.22Pointer.22 */ struct BufferDescriptorX { - u16 counter0_5 : 6; - u16 address36_38 : 3; - u16 counter9_11 : 3; - u16 address32_35 : 4; - u16 size : 16; - u32 address0_31 : 32; + u16 counter0_5 : 6; //!< The first 5 bits of the counter + u16 address36_38 : 3; //!< Bit 36-38 of the address + u16 counter9_11 : 3; //!< Bit 9-11 of the counter + u16 address32_35 : 4; //!< Bit 32-35 of the address + u16 size : 16; //!< The 16 bit size of the buffer + u32 address0_31 : 32; //!< The first 32-bits of the address BufferDescriptorX(u64 address, u16 counter, u16 size) : size(size) { address0_31 = static_cast(address & 0x7FFFFFFF80000000); @@ -113,10 +113,16 @@ namespace skyline::kernel::ipc { counter9_11 = static_cast(address & 0x38); } + /** + * @return The address of the buffer + */ inline u64 Address() const { return static_cast(address0_31) | static_cast(address32_35) << 32 | static_cast(address36_38) << 36; } + /** + * @return The buffer counter + */ inline u16 Counter() const { return static_cast(counter0_5) | static_cast(counter9_11) << 9; } @@ -127,13 +133,13 @@ namespace skyline::kernel::ipc { * @brief This is a buffer descriptor for A/B/W buffers: https://switchbrew.org/wiki/IPC_Marshalling#Buffer_descriptor_A.2FB.2FW_.22Send.22.2F.22Receive.22.2F.22Exchange.22 */ struct BufferDescriptorABW { - u32 size0_31 : 32; - u32 address0_31 : 32; - u8 flags : 2; - u8 address36_38 : 3; + u32 size0_31 : 32; //!< The first 32 bits of the size + u32 address0_31 : 32; //!< The first 32 bits of the address + u8 flags : 2; //!< The buffer flags + u8 address36_38 : 3; //!< Bit 36-38 of the address u32 : 19; - u8 size32_35 : 4; - u8 address32_35 : 4; + u8 size32_35 : 4; //!< Bit 32-35 of the size + u8 address32_35 : 4; //!< Bit 32-35 of the address BufferDescriptorABW(u64 address, u64 size) { address0_31 = static_cast(address & 0x7FFFFFFF80000000); @@ -143,12 +149,16 @@ namespace skyline::kernel::ipc { size32_35 = static_cast(size & 0x78000000); } - std::vector Read(const DeviceState &state); - + /** + * @return The address of the buffer + */ inline u64 Address() const { return static_cast(address0_31) | static_cast(address32_35) << 32 | static_cast(address36_38) << 36; } + /** + * @return The size of the buffer + */ inline u64 Size() const { return static_cast(size0_31) | static_cast(size32_35) << 32; } @@ -159,8 +169,8 @@ namespace skyline::kernel::ipc { * @brief This is a buffer descriptor for C buffers: https://switchbrew.org/wiki/IPC_Marshalling#Buffer_descriptor_C_.22ReceiveList.22 */ struct BufferDescriptorC { - u64 address : 48; - u32 size : 16; + u64 address : 48; //!< The 48-bit address of the buffer + u32 size : 16; //!< The 16-bit size of the buffer BufferDescriptorC(u64 address, u16 size) : address(address), size(size) {} }; @@ -232,7 +242,7 @@ namespace skyline::kernel::ipc { u8 *payloadOffset; //!< This is the offset of the data read from the payload public: - std::array tls; //!< A static-sized array where TLS data is actually copied to + //std::array tls; //!< A static-sized array where TLS data is actually copied to CommandHeader *header{}; //!< The header of the request HandleDescriptor *handleDesc{}; //!< The handle descriptor in case CommandHeader::handle_desc is true in the header bool isDomain{}; //!< If this is a domain request diff --git a/app/src/main/cpp/skyline/kernel/memory.cpp b/app/src/main/cpp/skyline/kernel/memory.cpp index 887b9552..99c4ad1e 100644 --- a/app/src/main/cpp/skyline/kernel/memory.cpp +++ b/app/src/main/cpp/skyline/kernel/memory.cpp @@ -3,87 +3,111 @@ namespace skyline::kernel { ChunkDescriptor *MemoryManager::GetChunk(u64 address) { - for (auto &chunk : chunkList) - if (chunk.address <= address && (chunk.address + chunk.size) > address) - return &chunk; + auto chunk = std::upper_bound(chunkList.begin(), chunkList.end(), address, [](const u64 address, const ChunkDescriptor &chunk) -> bool { + return address < chunk.address; + }); + if (chunk-- != chunkList.begin()) { + if ((chunk->address + chunk->size) > address) + return chunk.base(); + } return nullptr; } - BlockDescriptor *MemoryManager::GetBlock(u64 address) { - auto chunk = GetChunk(address); - if (chunk) - for (auto &block : chunk->blockList) - if (block.address <= address && (block.address + block.size) > address) - return █ + BlockDescriptor *MemoryManager::GetBlock(u64 address, ChunkDescriptor *chunk) { + if (!chunk) + chunk = GetChunk(address); + if (chunk) { + auto block = std::upper_bound(chunk->blockList.begin(), chunk->blockList.end(), address, [](const u64 address, const BlockDescriptor &block) -> bool { + return address < block.address; + }); + if (block-- != chunk->blockList.begin()) { + if ((block->address + block->size) > address) + return block.base(); + } + } return nullptr; } void MemoryManager::InsertChunk(const ChunkDescriptor &chunk) { - auto it = chunkList.begin(); - if (chunkList.empty() || it->address > chunk.address) - chunkList.push_front(chunk); - else { - auto prevIt = it; - while (true) { - if (it == chunkList.end() || (prevIt->address < chunk.address && it->address > chunk.address)) { - if (prevIt->address + prevIt->size > chunk.address) - throw exception("InsertChunk: Descriptors are colliding: 0x{:X} and 0x{:X}", prevIt->address, chunk.address); - chunkList.insert_after(prevIt, chunk); - break; - } - prevIt = it++; - } + auto upperChunk = std::upper_bound(chunkList.begin(), chunkList.end(), chunk.address, [](const u64 address, const ChunkDescriptor &chunk) -> bool { + return address < chunk.address; + }); + if (upperChunk != chunkList.begin()) { + auto lowerChunk = std::prev(upperChunk); + if (lowerChunk->address + lowerChunk->size > chunk.address) + throw exception("InsertChunk: Descriptors are colliding: 0x{:X} - 0x{:X} and 0x{:X} - 0x{:X}", lowerChunk->address, lowerChunk->address + lowerChunk->size, chunk.address, chunk.address + chunk.size); } + chunkList.insert(upperChunk, chunk); } void MemoryManager::DeleteChunk(u64 address) { - chunkList.remove_if([address](const ChunkDescriptor &chunk) { - return chunk.address <= address && (chunk.address + chunk.size) > address; - }); + for (auto chunk = chunkList.begin(), end = chunkList.end(); chunk != end;) { + if (chunk->address <= address && (chunk->address + chunk->size) > address) + chunk = chunkList.erase(chunk); + else + ++chunk; + } } void MemoryManager::ResizeChunk(ChunkDescriptor *chunk, size_t size) { - if (std::next(chunk->blockList.begin()) == chunk->blockList.end()) + if (chunk->blockList.size() == 1) { chunk->blockList.begin()->size = size; - else if (size > chunk->size) { - auto end = chunk->blockList.begin(); - for (; std::next(end) != chunk->blockList.end(); end++); - auto baseBlock = (*chunk->blockList.begin()); + } else if (size > chunk->size) { + auto begin = chunk->blockList.begin(); + auto end = std::prev(chunk->blockList.end()); BlockDescriptor block{ .address = (end->address + end->size), .size = (chunk->address + size) - (end->address + end->size), - .permission = baseBlock.permission, - .attributes = baseBlock.attributes, + .permission = begin->permission, + .attributes = begin->attributes, }; - chunk->blockList.insert_after(end, block); - } else if (chunk->size < size) { + chunk->blockList.push_back(block); + } else if (size < chunk->size) { auto endAddress = chunk->address + size; - chunk->blockList.remove_if([endAddress](const BlockDescriptor &block) { - return block.address > endAddress; - }); - auto end = chunk->blockList.begin(); - for (; std::next(end) != chunk->blockList.end(); end++); + for (auto block = chunk->blockList.begin(), end = chunk->blockList.end(); block != end;) { + if (block->address > endAddress) + block = chunk->blockList.erase(block); + else + ++block; + } + auto end = std::prev(chunk->blockList.end()); end->size = endAddress - end->address; } chunk->size = size; } - void MemoryManager::InsertBlock(ChunkDescriptor *chunk, BlockDescriptor block) { + void MemoryManager::InsertBlock(ChunkDescriptor *chunk, const BlockDescriptor block) { for (auto iter = chunk->blockList.begin(); iter != chunk->blockList.end(); iter++) { - if (iter->address <= block.address && (iter->address + iter->size) > block.address) { - if (iter->address == block.address && iter->size == block.size) { - iter->attributes = block.attributes; - iter->permission = block.permission; + if (iter->address <= block.address) { + if ((iter->address + iter->size) > block.address) { + if (iter->address == block.address && iter->size == block.size) { + iter->attributes = block.attributes; + iter->permission = block.permission; + } else { + auto endBlock = *iter; + endBlock.address = (block.address + block.size); + endBlock.size = (iter->address + iter->size) - endBlock.address; + iter->size = iter->address - block.address; + chunk->blockList.insert(std::next(iter), {block, endBlock}); + } + } else if (std::next(iter) != chunk->blockList.end()) { + auto nextIter = std::next(iter); + auto nextEnd = nextIter->address + nextIter->size; + if(nextEnd > block.address) { + iter->size = block.address - iter->address; + nextIter->address = block.address + block.size; + nextIter->size = nextEnd - nextIter->address; + chunk->blockList.insert(nextIter, block); + } else { + throw exception("InsertBlock: Inserting block across more than one block is not allowed"); + } } else { - auto endBlock = *iter; - endBlock.address = (block.address + block.size); - endBlock.size = (iter->address + iter->size) - endBlock.address; - iter->size = (iter->address - block.address); - chunk->blockList.insert_after(iter, {block, endBlock}); + throw exception("InsertBlock: Inserting block with end past chunk end is not allowed"); } - break; + return; } } + throw exception("InsertBlock: Block offset not present within current block list"); } void MemoryManager::InitializeRegions(u64 address, u64 size, const memory::AddressSpaceType type) { @@ -132,9 +156,7 @@ namespace skyline::kernel { std::optional MemoryManager::Get(u64 address) { auto chunk = GetChunk(address); if (chunk) - for (auto &block : chunk->blockList) - if (block.address <= address && (block.address + block.size) > address) - return DescriptorPack{block, *chunk}; + return DescriptorPack{*GetBlock(address, chunk), *chunk}; return std::nullopt; } diff --git a/app/src/main/cpp/skyline/kernel/memory.h b/app/src/main/cpp/skyline/kernel/memory.h index ed53fbd8..50fb666e 100644 --- a/app/src/main/cpp/skyline/kernel/memory.h +++ b/app/src/main/cpp/skyline/kernel/memory.h @@ -13,22 +13,14 @@ namespace skyline { /** * @brief This constructor initializes all permissions to false */ - Permission() { - r = 0; - w = 0; - x = 0; - }; + Permission() : r(), w(), x() {}; /** * @param read If memory has read permission * @param write If memory has write permission * @param execute If memory has execute permission */ - Permission(bool read, bool write, bool execute) { - r = read; - w = write; - x = execute; - }; + Permission(bool read, bool write, bool execute) : r(read), w(write), x(execute) {}; /** * @brief Equality operator between two Permission objects @@ -199,7 +191,8 @@ namespace skyline { * @brief Checks if the specified address is within the region * @param address The address to check * @return If the address is inside the region - */inline bool IsInside(u64 address) { + */ + inline bool IsInside(u64 address) { return (this->address <= address) && ((this->address + this->size) > address); } }; @@ -249,7 +242,7 @@ namespace skyline { u64 size; //!< The size of the current chunk in bytes u64 host; //!< The address of the chunk in the host memory::MemoryState state; //!< The MemoryState for the current block - std::forward_list blockList; //!< This linked list holds the block descriptors for all the children blocks of this Chunk + std::vector blockList; //!< This vector holds the block descriptors for all the children blocks of this Chunk }; /** @@ -266,7 +259,7 @@ namespace skyline { class MemoryManager { private: const DeviceState &state; //!< The state of the device - std::forward_list chunkList; //!< This linked list holds all the chunk descriptors + std::vector chunkList; //!< This vector holds all the chunk descriptors memory::Region base{memory::Regions::Base}; //!< The Region object for the entire address space memory::Region code{memory::Regions::Code}; //!< The Region object for the code memory region memory::Region alias{memory::Regions::Alias}; //!< The Region object for the alias memory region @@ -284,7 +277,7 @@ namespace skyline { * @param address The address to find a block at * @return A pointer to the BlockDescriptor or nullptr in case chunk was not found */ - BlockDescriptor *GetBlock(u64 address); + BlockDescriptor *GetBlock(u64 address, ChunkDescriptor* chunk = nullptr); /** * @brief Inserts a chunk into the memory map @@ -310,7 +303,7 @@ namespace skyline { * @param chunk The chunk to insert the block into * @param block The block to insert */ - static void InsertBlock(ChunkDescriptor *chunk, BlockDescriptor block); + static void InsertBlock(ChunkDescriptor *chunk, const BlockDescriptor block); /** * @brief This initializes all of the regions in the address space diff --git a/app/src/main/cpp/skyline/kernel/svc.cpp b/app/src/main/cpp/skyline/kernel/svc.cpp index 7f4f52a3..d8410ec7 100644 --- a/app/src/main/cpp/skyline/kernel/svc.cpp +++ b/app/src/main/cpp/skyline/kernel/svc.cpp @@ -232,9 +232,9 @@ namespace skyline::kernel::svc { auto handle = state.ctx->registers.w0; try { auto priority = state.process->GetHandle(handle)->priority; + state.logger->Debug("svcGetThreadPriority: Writing thread priority {}", priority); state.ctx->registers.w1 = priority; state.ctx->registers.w0 = constant::status::Success; - state.logger->Debug("svcGetThreadPriority: Writing thread priority {}", priority); } catch (const std::exception &) { state.logger->Warn("svcGetThreadPriority: 'handle' invalid: 0x{:X}", handle); state.ctx->registers.w0 = constant::status::InvHandle; @@ -245,9 +245,9 @@ namespace skyline::kernel::svc { auto handle = state.ctx->registers.w0; auto priority = state.ctx->registers.w1; try { + state.logger->Debug("svcSetThreadPriority: Setting thread priority to {}", priority); state.process->GetHandle(handle)->UpdatePriority(static_cast(priority)); state.ctx->registers.w0 = constant::status::Success; - state.logger->Debug("svcSetThreadPriority: Setting thread priority to {}", priority); } catch (const std::exception &) { state.logger->Warn("svcSetThreadPriority: 'handle' invalid: 0x{:X}", handle); state.ctx->registers.w0 = constant::status::InvHandle; @@ -499,9 +499,9 @@ namespace skyline::kernel::svc { char port[constant::PortSize + 1]{0}; state.process->ReadMemory(port, state.ctx->registers.x1, constant::PortSize); handle_t handle{}; - if (std::strcmp(port, "sm:") == 0) + if (std::strcmp(port, "sm:") == 0) { handle = state.os->serviceManager.NewSession(service::Service::sm); - else { + } else { state.logger->Warn("svcConnectToNamedPort: Connecting to invalid port: '{}'", port); state.ctx->registers.w0 = constant::status::NotFound; return; @@ -519,9 +519,9 @@ namespace skyline::kernel::svc { void GetThreadId(DeviceState &state) { pid_t pid{}; auto handle = state.ctx->registers.w1; - if (handle != constant::ThreadSelf) { + if (handle != constant::ThreadSelf) pid = state.process->GetHandle(handle)->pid; - } else + else pid = state.thread->pid; state.logger->Debug("svcGetThreadId: Handle: 0x{:X}, PID: {}", handle, pid); state.ctx->registers.x1 = static_cast(pid); @@ -529,8 +529,7 @@ namespace skyline::kernel::svc { } void OutputDebugString(DeviceState &state) { - std::string debug(state.ctx->registers.x1, '\0'); - state.process->ReadMemory(debug.data(), state.ctx->registers.x0, state.ctx->registers.x1); + auto debug = state.process->GetString(state.ctx->registers.x0, state.ctx->registers.x1); if (debug.back() == '\n') debug.pop_back(); state.logger->Info("Debug Output: {}", debug); diff --git a/app/src/main/cpp/skyline/kernel/types/KPrivateMemory.cpp b/app/src/main/cpp/skyline/kernel/types/KPrivateMemory.cpp index aab6bc2a..a9f423ec 100644 --- a/app/src/main/cpp/skyline/kernel/types/KPrivateMemory.cpp +++ b/app/src/main/cpp/skyline/kernel/types/KPrivateMemory.cpp @@ -70,7 +70,7 @@ namespace skyline::kernel::type { auto chunk = state.os->memory.GetChunk(address); state.process->WriteMemory(reinterpret_cast(chunk->host), address, std::min(nSize, size), true); for (const auto &block : chunk->blockList) { - if((block.address - chunk->address) < size) { + if ((block.address - chunk->address) < size) { fregs = { .x0 = block.address, .x1 = std::min(block.size, (chunk->address + nSize) - block.address), @@ -80,8 +80,9 @@ namespace skyline::kernel::type { state.nce->ExecuteFunction(ThreadCall::Syscall, fregs); if (fregs.x0 < 0) throw exception("An error occurred while updating private memory's permissions in child process"); - } else + } else { break; + } } munmap(reinterpret_cast(chunk->host), size); auto host = mmap(reinterpret_cast(chunk->host), nSize, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_SHARED, fd, 0); diff --git a/app/src/main/cpp/skyline/kernel/types/KProcess.cpp b/app/src/main/cpp/skyline/kernel/types/KProcess.cpp index 0cdb99bb..f6b5a170 100644 --- a/app/src/main/cpp/skyline/kernel/types/KProcess.cpp +++ b/app/src/main/cpp/skyline/kernel/types/KProcess.cpp @@ -35,8 +35,9 @@ namespace skyline::kernel::type { if (tlsPages.empty()) { auto region = state.os->memory.GetRegion(memory::Regions::TlsIo); address = region.size ? region.address : 0; - } else + } else { address = (*(tlsPages.end() - 1))->address + PAGE_SIZE; + } auto tlsMem = NewHandle(address, PAGE_SIZE, memory::Permission(true, true, false), memory::MemoryStates::ThreadLocal).item; tlsPages.push_back(std::make_shared(tlsMem->address)); auto &tlsPage = tlsPages.back(); @@ -72,7 +73,7 @@ namespace skyline::kernel::type { fregs.x1 = stackTop; fregs.x3 = tlsMem->Map(0, size, memory::Permission{true, true, false}); fregs.x8 = __NR_clone; - fregs.x5 = reinterpret_cast(&guest::entry); + fregs.x5 = reinterpret_cast(&guest::GuestEntry); fregs.x6 = entryPoint; state.nce->ExecuteFunction(ThreadCall::Clone, fregs); if (static_cast(fregs.x0) < 0) @@ -156,7 +157,7 @@ namespace skyline::kernel::type { case type::KType::KTransferMemory: { auto mem = std::static_pointer_cast(object); if (mem->IsInside(address)) - return std::optional>({mem, handle}); + return std::make_optional>({mem, handle}); } default: break; @@ -186,11 +187,12 @@ namespace skyline::kernel::type { while (!status->flag); lock.lock(); status->flag = false; - for (auto it = mtxWaiters.begin(); it != mtxWaiters.end(); ++it) + for (auto it = mtxWaiters.begin(); it != mtxWaiters.end(); ++it) { if ((*it)->handle == state.thread->handle) { mtxWaiters.erase(it); break; } + } return true; } @@ -231,20 +233,20 @@ namespace skyline::kernel::type { lock.unlock(); bool timedOut{}; auto start = utils::GetTimeNs(); - while (!status->flag) { + while (!status->flag) if ((utils::GetTimeNs() - start) >= timeout) timedOut = true; - } lock.lock(); if (!status->flag) timedOut = false; else status->flag = false; - for (auto it = condWaiters.begin(); it != condWaiters.end(); ++it) + for (auto it = condWaiters.begin(); it != condWaiters.end(); ++it) { if ((*it)->handle == state.thread->handle) { condWaiters.erase(it); break; } + } lock.unlock(); return !timedOut; } diff --git a/app/src/main/cpp/skyline/kernel/types/KProcess.h b/app/src/main/cpp/skyline/kernel/types/KProcess.h index 30e36e91..c04180b3 100644 --- a/app/src/main/cpp/skyline/kernel/types/KProcess.h +++ b/app/src/main/cpp/skyline/kernel/types/KProcess.h @@ -137,41 +137,6 @@ namespace skyline::kernel::type { */ std::shared_ptr CreateThread(u64 entryPoint, u64 entryArg, u64 stackTop, u8 priority); - /** - * @brief Returns an object from process memory - * @tparam Type The type of the object to be read - * @param address The address of the object - * @return An object of type T with read data - */ - template - inline Type ReadMemory(u64 address) const { - Type item{}; - ReadMemory(&item, address, sizeof(Type)); - return item; - } - - /** - * @brief Writes an object to process memory - * @tparam Type The type of the object to be written - * @param item The object to write - * @param address The address of the object - */ - template - inline void WriteMemory(Type &item, u64 address) const { - WriteMemory(&item, address, sizeof(Type)); - } - - /** - * @brief Writes an object to process memory - * @tparam Type The type of the object to be written - * @param item The object to write - * @param address The address of the object - */ - template - inline void WriteMemory(const Type &item, u64 address) const { - WriteMemory(&item, address, sizeof(Type)); - } - /** * @brief This returns the host address for a specific address in guest memory * @param address The corresponding guest address @@ -191,7 +156,87 @@ namespace skyline::kernel::type { } /** - * @brief Read data from the process's memory + * @brief Returns a reference to an object from guest memory + * @tparam Type The type of the object to be read + * @param address The address of the object + * @return A reference to object with type T + */ + template + inline Type &GetReference(u64 address) const { + auto source = GetPointer(address); + if (source) + return *source; + else + throw exception("Cannot retrieve reference to object not in shared guest memory"); + } + + /** + * @brief Returns a copy of an object from guest memory + * @tparam Type The type of the object to be read + * @param address The address of the object + * @return A copy of the object from guest memory + */ + template + inline Type GetObject(u64 address) const { + auto source = GetPointer(address); + if (source) { + return *source; + } else { + Type item{}; + ReadMemory(&item, address, sizeof(Type)); + return item; + } + } + + /** + * @brief Returns a string from guest memory + * @param address The address of the object + * @param maxSize The maximum size of the string + * @return A copy of a string in guest memory + */ + inline std::string GetString(u64 address, const size_t maxSize) const { + auto source = GetPointer(address); + if (source) + return std::string(source, maxSize); + std::string debug(maxSize, '\0'); + ReadMemory(debug.data(), address, maxSize); + return debug; + } + + /** + * @brief Writes an object to guest memory + * @tparam Type The type of the object to be written + * @param item The object to write + * @param address The address of the object + */ + template + inline void WriteMemory(Type &item, u64 address) const { + auto destination = GetPointer(address); + if (destination) { + *destination = item; + } else { + WriteMemory(&item, address, sizeof(Type)); + } + } + + /** + * @brief Writes an object to guest memory + * @tparam Type The type of the object to be written + * @param item The object to write + * @param address The address of the object + */ + template + inline void WriteMemory(const Type &item, u64 address) const { + auto destination = GetPointer(address); + if (destination) { + *destination = item; + } else { + WriteMemory(&item, address, sizeof(Type)); + } + } + + /** + * @brief Read data from the guest's memory * @param destination The address to the location where the process memory is written * @param offset The address to read from in process memory * @param size The amount of memory to be read @@ -200,7 +245,7 @@ namespace skyline::kernel::type { void ReadMemory(void *destination, const u64 offset, const size_t size, const bool forceGuest = false) const; /** - * @brief Write to the process's memory + * @brief Write to the guest's memory * @param source The address of where the data to be written is present * @param offset The address to write to in process memory * @param size The amount of memory to be written @@ -209,7 +254,7 @@ namespace skyline::kernel::type { void WriteMemory(void *source, const u64 offset, const size_t size, const bool forceGuest = false) const; /** - * @brief Copy one chunk to another in the process's memory + * @brief Copy one chunk to another in the guest's memory * @param source The address of where the data to read is present * @param destination The address to write the read data to * @param size The amount of memory to be copied diff --git a/app/src/main/cpp/skyline/kernel/types/KSharedMemory.cpp b/app/src/main/cpp/skyline/kernel/types/KSharedMemory.cpp index 1d9363d6..a812ae44 100644 --- a/app/src/main/cpp/skyline/kernel/types/KSharedMemory.cpp +++ b/app/src/main/cpp/skyline/kernel/types/KSharedMemory.cpp @@ -33,18 +33,18 @@ namespace skyline::kernel::type { if (fregs.x0 < 0) throw exception("An error occurred while mapping shared memory in guest"); guest = {.address = fregs.x0, .size = size, .permission = permission}; - ChunkDescriptor chunk{ - .address = fregs.x0, - .host = kernel.address, - .size = size, - .state = initialState, - }; BlockDescriptor block{ .address = fregs.x0, .size = size, .permission = permission, }; - chunk.blockList.push_front(block); + ChunkDescriptor chunk{ + .address = fregs.x0, + .host = kernel.address, + .size = size, + .state = initialState, + .blockList = {block}, + }; state.os->memory.InsertChunk(chunk); return fregs.x0; } @@ -78,7 +78,7 @@ namespace skyline::kernel::type { state.process->WriteMemory(reinterpret_cast(kernel.address), guest.address, std::min(guest.size, size), true); auto chunk = state.os->memory.GetChunk(guest.address); for (const auto &block : chunk->blockList) { - if((block.address - chunk->address) < guest.size) { + if ((block.address - chunk->address) < guest.size) { fregs = { .x0 = block.address, .x1 = std::min(block.size, (chunk->address + size) - block.address), @@ -88,8 +88,9 @@ namespace skyline::kernel::type { state.nce->ExecuteFunction(ThreadCall::Syscall, fregs); if (fregs.x0 < 0) throw exception("An error occurred while updating private memory's permissions in child process"); - } else + } else { break; + } } munmap(reinterpret_cast(kernel.address), kernel.size); auto host = mmap(reinterpret_cast(chunk->host), size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_SHARED, fd, 0); diff --git a/app/src/main/cpp/skyline/kernel/types/KThread.cpp b/app/src/main/cpp/skyline/kernel/types/KThread.cpp index e4554945..dc1d6783 100644 --- a/app/src/main/cpp/skyline/kernel/types/KThread.cpp +++ b/app/src/main/cpp/skyline/kernel/types/KThread.cpp @@ -5,7 +5,7 @@ namespace skyline::kernel::type { KThread::KThread(const DeviceState &state, handle_t handle, pid_t self_pid, u64 entryPoint, u64 entryArg, u64 stackTop, u64 tls, u8 priority, KProcess *parent, std::shared_ptr &tlsMemory) : handle(handle), pid(self_pid), entryPoint(entryPoint), entryArg(entryArg), stackTop(stackTop), tls(tls), priority(priority), parent(parent), ctxMemory(tlsMemory), KSyncObject(state, - KType::KThread) { + KType::KThread) { UpdatePriority(priority); } diff --git a/app/src/main/cpp/skyline/kernel/types/KThread.h b/app/src/main/cpp/skyline/kernel/types/KThread.h index 49d15352..09b4d9ae 100644 --- a/app/src/main/cpp/skyline/kernel/types/KThread.h +++ b/app/src/main/cpp/skyline/kernel/types/KThread.h @@ -19,7 +19,7 @@ namespace skyline::kernel::type { Running, //!< The thread is running currently Dead //!< The thread is dead and not running } status = Status::Created; //!< The state of the thread - std::atomic cancelSync; //!< This is to flag to a thread to cancel a synchronization call it currently is in + std::atomic cancelSync{false}; //!< This is to flag to a thread to cancel a synchronization call it currently is in std::shared_ptr ctxMemory; //!< The KSharedMemory of the shared memory allocated by the guest process TLS handle_t handle; // The handle of the object in the handle table pid_t pid; //!< The PID of the current thread (As in kernel PID and not PGID [In short, Linux implements threads as processes that share a lot of stuff at the kernel level]) diff --git a/app/src/main/cpp/skyline/kernel/types/KTransferMemory.cpp b/app/src/main/cpp/skyline/kernel/types/KTransferMemory.cpp index eca2d69a..32abd61a 100644 --- a/app/src/main/cpp/skyline/kernel/types/KTransferMemory.cpp +++ b/app/src/main/cpp/skyline/kernel/types/KTransferMemory.cpp @@ -101,11 +101,11 @@ namespace skyline::kernel::type { if (mHost && !host) { state.os->memory.DeleteChunk(address); hostChunk = chunk; - } else if (!mHost && host) + } else if (!mHost && host) { state.os->memory.InsertChunk(chunk); - else if (mHost && host) + } else if (mHost && host) { hostChunk = chunk; - else if (!mHost && !host) { + } else if (!mHost && !host) { state.os->memory.DeleteChunk(address); state.os->memory.InsertChunk(chunk); } @@ -174,9 +174,9 @@ namespace skyline::kernel::type { } KTransferMemory::~KTransferMemory() { - if (host) + if (host) { munmap(reinterpret_cast(address), size); - else if (state.process) { + } else if (state.process) { try { Registers fregs{ .x0 = address, diff --git a/app/src/main/cpp/skyline/nce.cpp b/app/src/main/cpp/skyline/nce.cpp index 369a766e..92433c21 100644 --- a/app/src/main/cpp/skyline/nce.cpp +++ b/app/src/main/cpp/skyline/nce.cpp @@ -33,8 +33,9 @@ namespace skyline { if (kernel::svc::SvcTable[svc]) { state.logger->Debug("SVC called 0x{:X}", svc); (*kernel::svc::SvcTable[svc])(state); - } else + } else { throw exception("Unimplemented SVC 0x{:X}", svc); + } } catch (const std::exception &e) { throw exception("{} (SVC: 0x{:X})", e.what(), svc); } @@ -57,8 +58,9 @@ namespace skyline { state.os->KillThread(thread); Halt = true; jniMtx.unlock(); - } else + } else { state.os->KillThread(thread); + } } } @@ -160,29 +162,11 @@ namespace skyline { state.logger->Debug("Process Trace:{}", trace); state.logger->Debug("Raw Instructions: 0x{}", raw); state.logger->Debug("CPU Context:{}", regStr); - } else + } else { state.logger->Debug("CPU Context:{}", regStr); + } } - const std::array CntpctEl0 = { - 0xD10083FF, // SUB SP, SP, #32 - 0xA90107E0, // STP X0, X1, [SP, #16] - 0xD28F0860, // MOV X0, #30787 - 0xF2AE3680, // MOVK X0, #29108, LSL #16 - 0xD53BE001, // MRS X1, CNTFRQ_EL0 - 0xF2CB5880, // MOVK X0, #23236, LSL #32 - 0xD345FC21, // LSR X1, X1, #5 - 0xF2E14F80, // MOVK X0, #2684, LSL #48 - 0x9BC07C21, // UMULH X1, X1, X0 - 0xD347FC21, // LSR X1, X1, #7 - 0xD53BE040, // MRS X0, CNTVCT_EL0 - 0x9AC10801, // UDIV X1, X0, X1 - 0x8B010421, // ADD X1, X1, X1, LSL #1 - 0xD37AE420, // LSL X0, X1, #6 - 0xF90003E0, // STR X0, [SP, #0] - 0xA94107E0, // LDP X0, X1, [SP, #16] - }; - std::vector NCE::PatchCode(std::vector &code, u64 baseAddress, i64 offset) { u32 *start = reinterpret_cast(code.data()); u32 *end = start + (code.size() / sizeof(u32)); @@ -190,15 +174,13 @@ namespace skyline { std::vector patch((guest::saveCtxSize + guest::loadCtxSize + guest::svcHandlerSize) / sizeof(u32)); - std::memcpy(patch.data(), reinterpret_cast(&guest::saveCtx), guest::saveCtxSize); + std::memcpy(patch.data(), reinterpret_cast(&guest::SaveCtx), guest::saveCtxSize); offset += guest::saveCtxSize; - std::memcpy(reinterpret_cast(patch.data()) + guest::saveCtxSize, - reinterpret_cast(&guest::loadCtx), guest::loadCtxSize); + std::memcpy(reinterpret_cast(patch.data()) + guest::saveCtxSize, reinterpret_cast(&guest::LoadCtx), guest::loadCtxSize); offset += guest::loadCtxSize; - std::memcpy(reinterpret_cast(patch.data()) + guest::saveCtxSize + guest::loadCtxSize, - reinterpret_cast(&guest::svcHandler), guest::svcHandlerSize); + std::memcpy(reinterpret_cast(patch.data()) + guest::saveCtxSize + guest::loadCtxSize, reinterpret_cast(&guest::SvcHandler), guest::svcHandlerSize); offset += guest::svcHandlerSize; static u64 frequency{}; @@ -276,7 +258,7 @@ namespace skyline { } else if (frequency != constant::TegraX1Freq) { if (instrMrs->srcReg == constant::CntpctEl0) { instr::B bjunc(offset); - offset += CntpctEl0.size() * sizeof(u32); + offset += guest::rescaleClockSize; instr::Ldr ldr(0xF94003E0); // LDR XOUT, [SP] ldr.destReg = instrMrs->destReg; offset += sizeof(ldr); @@ -286,8 +268,9 @@ namespace skyline { offset += sizeof(bret); *address = bjunc.raw; - for (const auto &instr : CntpctEl0) - patch.push_back(instr); + auto size = patch.size(); + patch.resize(size + (guest::rescaleClockSize / sizeof(u32))); + std::memcpy(patch.data() + size, reinterpret_cast(&guest::RescaleClock), guest::rescaleClockSize); patch.push_back(ldr.raw); patch.push_back(addSp); patch.push_back(bret.raw); @@ -316,4 +299,3 @@ namespace skyline { return patch; } } - diff --git a/app/src/main/cpp/skyline/nce/guest.S b/app/src/main/cpp/skyline/nce/guest.S index 6bd172dc..189c178c 100644 --- a/app/src/main/cpp/skyline/nce/guest.S +++ b/app/src/main/cpp/skyline/nce/guest.S @@ -1,6 +1,6 @@ .text -.global saveCtx -saveCtx: +.global SaveCtx +SaveCtx: STR LR, [SP, #-16]! MRS LR, TPIDR_EL0 STP X0, X1, [LR, #16] @@ -19,11 +19,11 @@ saveCtx: STP X26, X27, [LR, #224] STP X28, X29, [LR, #240] LDR LR, [SP], #16 - DSB SY + DSB ST RET -.global loadCtx -loadCtx: +.global LoadCtx +LoadCtx: STR LR, [SP, #-16]! MRS LR, TPIDR_EL0 LDP X0, X1, [LR, #16] @@ -43,3 +43,23 @@ loadCtx: LDP X28, X29, [LR, #240] LDR LR, [SP], #16 RET + +.global RescaleClock +RescaleClock: + SUB SP, SP, #32 + STP X0, X1, [SP, #16] + MOV X0, #30787 + MOVK X0, #29108, LSL #16 + MOVK X0, #23236, LSL #32 + MOVK X0, #2684, LSL #48 + MRS X1, CNTFRQ_EL0 + LSR X1, X1, #5 + UMULH X1, X1, X0 + LSR X1, X1, #7 + MRS X0, CNTVCT_EL0 + UDIV X1, X0, X1 + ADD X1, X1, X1, LSL #1 + LSL X0, X1, #6 + STR X0, [SP, #0] + LDP X0, X1, [SP, #16] + diff --git a/app/src/main/cpp/skyline/nce/guest.cpp b/app/src/main/cpp/skyline/nce/guest.cpp index 63226960..282c6d1b 100644 --- a/app/src/main/cpp/skyline/nce/guest.cpp +++ b/app/src/main/cpp/skyline/nce/guest.cpp @@ -7,7 +7,7 @@ #define FORCE_INLINE __attribute__((always_inline)) inline // NOLINT(cppcoreguidelines-macro-usage) namespace skyline::guest { - FORCE_INLINE void saveCtxStack() { + FORCE_INLINE void SaveCtxStack() { asm("SUB SP, SP, #240\n\t" "STP X0, X1, [SP, #0]\n\t" "STP X2, X3, [SP, #16]\n\t" @@ -27,7 +27,7 @@ namespace skyline::guest { ); } - FORCE_INLINE void loadCtxStack() { + FORCE_INLINE void LoadCtxStack() { asm("LDP X0, X1, [SP, #0]\n\t" "LDP X2, X3, [SP, #16]\n\t" "LDP X4, X5, [SP, #32]\n\t" @@ -47,7 +47,7 @@ namespace skyline::guest { ); } - FORCE_INLINE void saveCtxTls() { + FORCE_INLINE void SaveCtxTls() { asm("STR LR, [SP, #-16]!\n\t" "MRS LR, TPIDR_EL0\n\t" "STP X0, X1, [LR, #16]\n\t" @@ -65,11 +65,12 @@ namespace skyline::guest { "STP X24, X25, [LR, #208]\n\t" "STP X26, X27, [LR, #224]\n\t" "STP X28, X29, [LR, #240]\n\t" - "LDR LR, [SP], #16" + "LDR LR, [SP], #16\n\t" + "DSB ST" ); } - FORCE_INLINE void loadCtxTls() { + FORCE_INLINE void LoadCtxTls() { asm("STR LR, [SP, #-16]!\n\t" "MRS LR, TPIDR_EL0\n\t" "LDP X0, X1, [LR, #16]\n\t" @@ -91,7 +92,10 @@ namespace skyline::guest { ); } - void svcHandler(u64 pc, u32 svc) { + /** + * @note Do not use any functions that cannot be inlined from this, as this function is placed at an arbitrary address in the guest. In addition, do not use any static variables or globals as the .bss section is not copied into the guest. + */ + void SvcHandler(u64 pc, u32 svc) { volatile ThreadContext *ctx; asm("MRS %0, TPIDR_EL0":"=r"(ctx)); ctx->pc = pc; @@ -112,7 +116,7 @@ namespace skyline::guest { "MOV LR, SP\n\t" "SVC #0\n\t" "MOV SP, LR\n\t" - "LDR LR, [SP], #16" ::: "x0", "x1", "x2", "x3", "x4", "x5", "x8"); + "LDR LR, [SP], #16":: : "x0", "x1", "x2", "x3", "x4", "x5", "x8"); break; } default: { @@ -131,7 +135,7 @@ namespace skyline::guest { "MOV LR, SP\n\t" "SVC #0\n\t" "MOV SP, LR\n\t" - "LDR LR, [SP], #16" :: "r"(&spec) : "x0", "x1", "x2", "x3", "x4", "x5", "x8"); + "LDR LR, [SP], #16"::"r"(&spec) : "x0", "x1", "x2", "x3", "x4", "x5", "x8"); } } return; @@ -153,35 +157,35 @@ namespace skyline::guest { "LDR Q2, [SP], #16\n\t" "LDR Q1, [SP], #16\n\t" "LDR Q0, [SP], #16\n\t" - "LDP X1, X2, [SP], #16" :: "r"(ctx->registers.x0)); + "LDP X1, X2, [SP], #16"::"r"(ctx->registers.x0)); return; } while (true) { ctx->state = ThreadState::WaitKernel; while (ctx->state == ThreadState::WaitKernel); - if (ctx->state == ThreadState::WaitRun) + if (ctx->state == ThreadState::WaitRun) { break; - else if (ctx->state == ThreadState::WaitFunc) { + } else if (ctx->state == ThreadState::WaitFunc) { if (ctx->commandId == static_cast(ThreadCall::Syscall)) { - saveCtxStack(); - loadCtxTls(); + SaveCtxStack(); + LoadCtxTls(); asm("STR LR, [SP, #-16]!\n\t" "MOV LR, SP\n\t" "SVC #0\n\t" "MOV SP, LR\n\t" "LDR LR, [SP], #16"); - saveCtxTls(); - loadCtxStack(); + SaveCtxTls(); + LoadCtxStack(); } else if (ctx->commandId == static_cast(ThreadCall::Memcopy)) { - auto src = reinterpret_cast(ctx->registers.x0); - auto dest = reinterpret_cast(ctx->registers.x1); + auto src = reinterpret_cast(ctx->registers.x0); + auto dest = reinterpret_cast(ctx->registers.x1); auto size = ctx->registers.x2; auto end = src + size; while (src < end) *(src++) = *(dest++); } else if (ctx->commandId == static_cast(ThreadCall::Clone)) { - saveCtxStack(); - loadCtxTls(); + SaveCtxStack(); + LoadCtxTls(); asm("STR LR, [SP, #-16]!\n\t" "MOV LR, SP\n\t" "SVC #0\n\t" @@ -221,15 +225,15 @@ namespace skyline::guest { ".parent:\n\t" "MOV SP, LR\n\t" "LDR LR, [SP], #16"); - saveCtxTls(); - loadCtxStack(); + SaveCtxTls(); + LoadCtxStack(); } } } ctx->state = ThreadState::Running; } - void signalHandler(int signal, siginfo_t *info, ucontext_t *ucontext) { + void SignalHandler(int signal, siginfo_t *info, ucontext_t *ucontext) { volatile ThreadContext *ctx; asm("MRS %0, TPIDR_EL0":"=r"(ctx)); for (u8 index = 0; index < 30; index++) @@ -245,29 +249,29 @@ namespace skyline::guest { } } - void entry(u64 address) { + void GuestEntry(u64 address) { volatile ThreadContext *ctx; asm("MRS %0, TPIDR_EL0":"=r"(ctx)); while (true) { ctx->state = ThreadState::WaitInit; while (ctx->state == ThreadState::WaitInit); - if (ctx->state == ThreadState::WaitRun) + if (ctx->state == ThreadState::WaitRun) { break; - else if (ctx->state == ThreadState::WaitFunc) { + } else if (ctx->state == ThreadState::WaitFunc) { if (ctx->commandId == static_cast(ThreadCall::Syscall)) { - saveCtxStack(); - loadCtxTls(); + SaveCtxStack(); + LoadCtxTls(); asm("STR LR, [SP, #-16]!\n\t" "MOV LR, SP\n\t" "SVC #0\n\t" "MOV SP, LR\n\t" "LDR LR, [SP], #16"); - saveCtxTls(); - loadCtxStack(); + SaveCtxTls(); + LoadCtxStack(); } } else if (ctx->commandId == static_cast(ThreadCall::Memcopy)) { - auto src = reinterpret_cast(ctx->registers.x0); - auto dest = reinterpret_cast(ctx->registers.x1); + auto src = reinterpret_cast(ctx->registers.x0); + auto dest = reinterpret_cast(ctx->registers.x1); auto size = ctx->registers.x2; auto end = src + size; while (src < end) @@ -275,7 +279,7 @@ namespace skyline::guest { } } struct sigaction sigact{ - .sa_sigaction = reinterpret_cast(reinterpret_cast(signalHandler)), + .sa_sigaction = reinterpret_cast(reinterpret_cast(SignalHandler)), .sa_flags = SA_SIGINFO, }; for (int signal : {SIGILL, SIGTRAP, SIGBUS, SIGFPE, SIGSEGV}) @@ -312,7 +316,7 @@ namespace skyline::guest { "MOV X27, XZR\n\t" "MOV X28, XZR\n\t" "MOV X29, XZR\n\t" - "RET" :: "r"(address), "r"(ctx->registers.x0), "r"(ctx->registers.x1) : "x0", "x1", "lr"); + "RET"::"r"(address), "r"(ctx->registers.x0), "r"(ctx->registers.x1) : "x0", "x1", "lr"); __builtin_unreachable(); } } diff --git a/app/src/main/cpp/skyline/nce/guest.h b/app/src/main/cpp/skyline/nce/guest.h index f94e663b..9165b0a3 100644 --- a/app/src/main/cpp/skyline/nce/guest.h +++ b/app/src/main/cpp/skyline/nce/guest.h @@ -4,17 +4,19 @@ namespace skyline { namespace guest { constexpr size_t saveCtxSize = 20 * sizeof(u32); constexpr size_t loadCtxSize = 20 * sizeof(u32); + constexpr size_t rescaleClockSize = 16 * sizeof(u32); #ifdef NDEBUG constexpr size_t svcHandlerSize = 225 * sizeof(u32); #else constexpr size_t svcHandlerSize = 400 * sizeof(u32); #endif - void entry(u64 address); + void GuestEntry(u64 address); - extern "C" void saveCtx(void); - extern "C" void loadCtx(void); + extern "C" void SaveCtx(void); + extern "C" void LoadCtx(void); + extern "C" __noreturn void RescaleClock(void); - void svcHandler(u64 pc, u32 svc); + void SvcHandler(u64 pc, u32 svc); } } diff --git a/app/src/main/cpp/skyline/nce/guest_common.h b/app/src/main/cpp/skyline/nce/guest_common.h index 3dc880c6..a13e1c9b 100644 --- a/app/src/main/cpp/skyline/nce/guest_common.h +++ b/app/src/main/cpp/skyline/nce/guest_common.h @@ -121,12 +121,12 @@ namespace skyline { * @brief This enumeration is used to convey the state of a thread to the kernel */ enum class ThreadState : u32 { - NotReady = 0, //!< The thread hasn't yet entered the entry handler - Running = 1, //!< The thread is currently executing code + NotReady = 0, //!< The thread hasn't yet entered the entry handler + Running = 1, //!< The thread is currently executing code WaitKernel = 2, //!< The thread is currently waiting on the kernel - WaitRun = 3, //!< The thread should be ready to run - WaitInit = 4, //!< The thread is waiting to be initialized - WaitFunc = 5, //!< The kernel is waiting for the thread to run a function + WaitRun = 3, //!< The thread should be ready to run + WaitInit = 4, //!< The thread is waiting to be initialized + WaitFunc = 5, //!< The kernel is waiting for the thread to run a function GuestCrash = 6, //!< This is a notification to the kernel that the guest has crashed }; diff --git a/app/src/main/cpp/skyline/os.cpp b/app/src/main/cpp/skyline/os.cpp index 955bbc5e..be457580 100644 --- a/app/src/main/cpp/skyline/os.cpp +++ b/app/src/main/cpp/skyline/os.cpp @@ -28,7 +28,7 @@ namespace skyline::kernel { } auto tlsMem = std::make_shared(state, 0, (sizeof(ThreadContext) + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1), memory::Permission{true, true, false}, memory::MemoryStates::Reserved); tlsMem->guest = tlsMem->kernel; - pid_t pid = clone(reinterpret_cast(&guest::entry), stack + stackSize, CLONE_FILES | CLONE_FS | CLONE_SETTLS | SIGCHLD, reinterpret_cast(entry), nullptr, reinterpret_cast(tlsMem->guest.address)); + pid_t pid = clone(reinterpret_cast(&guest::GuestEntry), stack + stackSize, CLONE_FILES | CLONE_FS | CLONE_SETTLS | SIGCHLD, reinterpret_cast(entry), nullptr, reinterpret_cast(tlsMem->guest.address)); if (pid == -1) throw exception("Call to clone() has failed: {}", strerror(errno)); state.logger->Debug("Successfully created process with PID: {}", pid); diff --git a/app/src/main/cpp/skyline/services/hid/hid.cpp b/app/src/main/cpp/skyline/services/hid/hid.cpp index deff2f45..639e1be5 100644 --- a/app/src/main/cpp/skyline/services/hid/hid.cpp +++ b/app/src/main/cpp/skyline/services/hid/hid.cpp @@ -40,7 +40,7 @@ namespace skyline::service::hid { size_t numId = buffer.size / sizeof(NpadId); u64 address = buffer.address; for (size_t i = 0; i < numId; i++) { - auto id = state.process->ReadMemory(address); + auto id = state.process->GetObject(address); deviceMap[id] = JoyConDevice(id); address += sizeof(NpadId); } diff --git a/app/src/main/cpp/skyline/services/nvdrv/nvdrv.cpp b/app/src/main/cpp/skyline/services/nvdrv/nvdrv.cpp index eb56c015..77f26b5a 100644 --- a/app/src/main/cpp/skyline/services/nvdrv/nvdrv.cpp +++ b/app/src/main/cpp/skyline/services/nvdrv/nvdrv.cpp @@ -13,8 +13,7 @@ namespace skyline::service::nvdrv { void nvdrv::Open(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { auto buffer = request.inputBuf.at(0); - std::string path(buffer.size, '\0'); - state.process->ReadMemory(path.data(), buffer.address, buffer.size); + auto path = state.process->GetString(buffer.address, buffer.size); response.Push(state.gpu->OpenDevice(path)); response.Push(constant::status::Success); } diff --git a/app/src/main/java/emu/skyline/MainActivity.kt b/app/src/main/java/emu/skyline/MainActivity.kt index 3b7adf48..bb198e0b 100644 --- a/app/src/main/java/emu/skyline/MainActivity.kt +++ b/app/src/main/java/emu/skyline/MainActivity.kt @@ -181,7 +181,7 @@ class MainActivity : AppCompatActivity(), View.OnClickListener { override fun onOptionsItemSelected(item: MenuItem): Boolean { return when (item.itemId) { R.id.action_settings -> { - startActivity(Intent(this, SettingsActivity::class.java)) + startActivityForResult(Intent(this, SettingsActivity::class.java), 3) true } R.id.action_refresh -> { @@ -193,35 +193,33 @@ class MainActivity : AppCompatActivity(), View.OnClickListener { } } - override fun onResume() { - super.onResume() - if (sharedPreferences.getBoolean("refresh_required", false)) - refreshFiles(false) - } - - override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { - super.onActivityResult(requestCode, resultCode, data) + override fun onActivityResult(requestCode: Int, resultCode: Int, intent: Intent?) { + super.onActivityResult(requestCode, resultCode, intent) if (resultCode == RESULT_OK) { when (requestCode) { 1 -> { - val uri = data!!.data!! + val uri = intent!!.data!! contentResolver.takePersistableUriPermission(uri, Intent.FLAG_GRANT_READ_URI_PERMISSION) sharedPreferences.edit().putString("search_location", uri.toString()).apply() refreshFiles(!sharedPreferences.getBoolean("refresh_required", false)) } 2 -> { try { - val uri = (data!!.data!!) - val intent = Intent(this, GameActivity::class.java) - intent.data = uri + val uri = (intent!!.data!!) + val intentGame = Intent(this, GameActivity::class.java) + intentGame.data = uri if (resultCode != 0) - startActivityForResult(intent, resultCode) + startActivityForResult(intentGame, resultCode) else - startActivity(intent) + startActivity(intentGame) } catch (e: Exception) { notifyUser(e.message!!) } } + 3 -> { + if (sharedPreferences.getBoolean("refresh_required", false)) + refreshFiles(false) + } } } }