diff --git a/app/src/main/cpp/skyline/common.cpp b/app/src/main/cpp/skyline/common.cpp index 872492b3..e66ca49e 100644 --- a/app/src/main/cpp/skyline/common.cpp +++ b/app/src/main/cpp/skyline/common.cpp @@ -91,7 +91,7 @@ namespace skyline { } DeviceState::DeviceState(kernel::OS *os, std::shared_ptr &thisProcess, std::shared_ptr &thisThread, std::shared_ptr jvmManager, std::shared_ptr settings, std::shared_ptr logger) - : os(os), jvmManager(std::move(jvmManager)), settings(std::move(settings)), logger(std::move(logger)), thisProcess(thisProcess), thisThread(thisThread) { + : os(os), jvmManager(std::move(jvmManager)), settings(std::move(settings)), logger(std::move(logger)), process(thisProcess), thread(thisThread) { // 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(*this)); gpu = std::move(std::make_shared(*this)); diff --git a/app/src/main/cpp/skyline/common.h b/app/src/main/cpp/skyline/common.h index e3715439..252e7d88 100644 --- a/app/src/main/cpp/skyline/common.h +++ b/app/src/main/cpp/skyline/common.h @@ -306,8 +306,8 @@ namespace skyline { DeviceState(kernel::OS *os, std::shared_ptr &thisProcess, std::shared_ptr &thisThread, std::shared_ptr jvmManager, std::shared_ptr settings, std::shared_ptr logger); kernel::OS *os; //!< This holds a reference to the OS class - std::shared_ptr &thisProcess; //!< This holds a reference to the current process object - std::shared_ptr &thisThread; //!< This holds a reference to the current thread object + std::shared_ptr &process; //!< This holds a reference to the process object + std::shared_ptr &thread; //!< This holds a reference to the current thread object std::shared_ptr nce; //!< This holds a reference to the NCE class std::shared_ptr gpu; //!< This holds a reference to the GPU class std::shared_ptr jvmManager; //!< This holds a reference to the JvmManager class diff --git a/app/src/main/cpp/skyline/gpu.h b/app/src/main/cpp/skyline/gpu.h index ad105a18..4ee7c5c1 100644 --- a/app/src/main/cpp/skyline/gpu.h +++ b/app/src/main/cpp/skyline/gpu.h @@ -18,7 +18,7 @@ namespace skyline::gpu { std::unordered_map> deviceMap; //!< A map from a NvDeviceType to the NvDevice object std::unordered_map> fdMap; //!< A map from an FD to a shared pointer to it's NvDevice object bool surfaceUpdate{}; //!< If the surface needs to be updated - double prevTime{}; + double prevTime{}; //!< The time passed from the last frame public: DisplayId displayId{DisplayId::Null}; //!< The ID of this display 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 75426419..96679302 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.thisProcess->ReadMemory(buffer.input[0].address); + auto priority = state.process->ReadMemory(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 8d5a59a3..cbffc080 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 @@ -12,7 +12,7 @@ namespace skyline::gpu::device { void NvHostCtrlGpu::ZCullGetCtxSize(IoctlData &buffer) { u32 size = 0x1; - state.thisProcess->WriteMemory(size, buffer.output[0].address); + state.process->WriteMemory(size, buffer.output[0].address); } void NvHostCtrlGpu::ZCullGetInfo(skyline::gpu::device::IoctlData &buffer) { @@ -28,7 +28,7 @@ namespace skyline::gpu::device { u32 subregionHeightAlignPixels{0x40}; u32 subregionCount{0x10}; } zCullInfo; - state.thisProcess->WriteMemory(zCullInfo, buffer.output[0].address); + state.process->WriteMemory(zCullInfo, buffer.output[0].address); } void NvHostCtrlGpu::GetCharacteristics(IoctlData &buffer) { @@ -73,7 +73,7 @@ namespace skyline::gpu::device { u64 gpuCharacteristicsBufSize; // InOut u64 gpuCharacteristicsBufAddr; // In GpuCharacteristics gpuCharacteristics; // Out - } data = state.thisProcess->ReadMemory(buffer.input[0].address); + } data = state.process->ReadMemory(buffer.input[0].address); data.gpuCharacteristics = { .arch = 0x120, .impl = 0xB, @@ -111,7 +111,7 @@ namespace skyline::gpu::device { .grCompbitStoreBaseHw = 0x0 }; data.gpuCharacteristicsBufSize = 0xA0; - state.thisProcess->WriteMemory(data, buffer.output[0].address); + state.process->WriteMemory(data, buffer.output[0].address); } void NvHostCtrlGpu::GetTpcMasks(IoctlData &buffer) { @@ -119,10 +119,10 @@ namespace skyline::gpu::device { u32 maskBufSize; // In u32 reserved[3]; // In u64 maskBuf; // Out - } data = state.thisProcess->ReadMemory(buffer.input[0].address); + } data = state.process->ReadMemory(buffer.input[0].address); if (data.maskBufSize) data.maskBuf = 0x3; - state.thisProcess->WriteMemory(data, buffer.output[0].address); + state.process->WriteMemory(data, buffer.output[0].address); } void NvHostCtrlGpu::GetActiveSlotMask(IoctlData &buffer) { @@ -133,6 +133,6 @@ namespace skyline::gpu::device { .slot = 0x07, .mask = 0x01 }; - state.thisProcess->WriteMemory(data, buffer.output[0].address); + 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 b6396f7c..d0512955 100644 --- a/app/src/main/cpp/skyline/gpu/devices/nvmap.cpp +++ b/app/src/main/cpp/skyline/gpu/devices/nvmap.cpp @@ -17,10 +17,10 @@ namespace skyline::gpu::device { struct Data { u32 size; // In u32 handle; // Out - } data = state.thisProcess->ReadMemory(buffer.input[0].address); + } data = state.process->ReadMemory(buffer.input[0].address); handleTable[handleIndex] = std::make_shared(idIndex++, data.size); data.handle = handleIndex++; - state.thisProcess->WriteMemory(data, buffer.output[0].address); + state.process->WriteMemory(data, buffer.output[0].address); state.logger->Debug("Create: Input: Size: 0x{:X}, Output: Handle: 0x{:X}, Status: {}", data.size, data.handle, buffer.status); } @@ -28,7 +28,7 @@ namespace skyline::gpu::device { struct Data { u32 id; // In u32 handle; // Out - } data = state.thisProcess->ReadMemory(buffer.input[0].address); + } data = state.process->ReadMemory(buffer.input[0].address); bool found{}; for (const auto &object : handleTable) { if (object.second->id == data.id) { @@ -38,7 +38,7 @@ namespace skyline::gpu::device { } } if (found) - state.thisProcess->WriteMemory(data, buffer.output[0].address); + state.process->WriteMemory(data, buffer.output[0].address); else buffer.status = NvStatus::BadValue; state.logger->Debug("FromId: Input: Handle: 0x{:X}, Output: ID: 0x{:X}, Status: {}", data.handle, data.id, buffer.status); @@ -53,7 +53,7 @@ namespace skyline::gpu::device { u8 kind; // In u8 _pad0_[7]; u64 address; // InOut - } data = state.thisProcess->ReadMemory(buffer.input[0].address); + } data = state.process->ReadMemory(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.thisProcess->ReadMemory(buffer.input[0].address); + } data = state.process->ReadMemory(buffer.input[0].address); const auto &object = handleTable.at(data.handle); if (object.use_count() > 1) { data.address = static_cast(object->address); @@ -82,7 +82,7 @@ namespace skyline::gpu::device { } data.size = object->size; handleTable.erase(data.handle); - state.thisProcess->WriteMemory(data, buffer.output[0].address); + state.process->WriteMemory(data, buffer.output[0].address); } void NvMap::Param(IoctlData &buffer) { @@ -91,7 +91,7 @@ namespace skyline::gpu::device { u32 handle; // In Parameter parameter; // In u32 result; // Out - } data = state.thisProcess->ReadMemory(buffer.input[0].address); + } data = state.process->ReadMemory(buffer.input[0].address); auto &object = handleTable.at(data.handle); switch (data.parameter) { case Parameter::Size: @@ -124,7 +124,7 @@ namespace skyline::gpu::device { buffer.status = NvStatus::NotImplemented; break; } - state.thisProcess->WriteMemory(data, buffer.output[0].address); + state.process->WriteMemory(data, buffer.output[0].address); state.logger->Debug("Param: Input: Handle: 0x{:X}, Parameter: {}, Output: Result: 0x{:X}, Status: {}", data.handle, data.parameter, data.result, buffer.status); } @@ -132,9 +132,9 @@ namespace skyline::gpu::device { struct Data { u32 id; // Out u32 handle; // In - } data = state.thisProcess->ReadMemory(buffer.input[0].address); + } data = state.process->ReadMemory(buffer.input[0].address); data.id = handleTable.at(data.handle)->id; - state.thisProcess->WriteMemory(data, buffer.output[0].address); + 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 05fcf65c..3a243138 100644 --- a/app/src/main/cpp/skyline/gpu/display.cpp +++ b/app/src/main/cpp/skyline/gpu/display.cpp @@ -31,7 +31,7 @@ namespace skyline::gpu { } void Buffer::UpdateBuffer() { - state.thisProcess->ReadMemory(dataBuffer.data(), nvBuffer->address + gbpBuffer.offset, gbpBuffer.size); + state.process->ReadMemory(dataBuffer.data(), nvBuffer->address + gbpBuffer.offset, gbpBuffer.size); } BufferQueue::WaitContext::WaitContext(std::shared_ptr thread, DequeueIn input, kernel::ipc::OutputBuffer& buffer) : thread(std::move(thread)), input(input), buffer(buffer) {} @@ -59,8 +59,8 @@ namespace skyline::gpu { } } if (slot == -1) { - state.thisThread->Sleep(); - waitVec.emplace_back(state.thisThread, *data, buffer); + state.thread->Sleep(); + waitVec.emplace_back(state.thread, *data, buffer); state.logger->Debug("DequeueBuffer: Width: {}, Height: {}, Format: {}, Usage: {}, Timestamps: {}, No Free Buffers", data->width, data->height, data->format, data->usage, data->timestamps); return true; } @@ -135,7 +135,7 @@ namespace skyline::gpu { gpu::Parcel out(state); DequeueOut output(slotNo); out.WriteData(output); - out.WriteParcel(context->buffer, context->thread->pid); + out.WriteParcel(context->buffer); slot->status = BufferStatus::Dequeued; waitVec.erase(context); break; diff --git a/app/src/main/cpp/skyline/gpu/parcel.cpp b/app/src/main/cpp/skyline/gpu/parcel.cpp index f0d71ba3..fd3a6d79 100644 --- a/app/src/main/cpp/skyline/gpu/parcel.cpp +++ b/app/src/main/cpp/skyline/gpu/parcel.cpp @@ -6,22 +6,22 @@ namespace skyline::gpu { Parcel::Parcel(kernel::ipc::InputBuffer &buffer, const DeviceState &state) : Parcel(buffer.address, buffer.size, state) {} Parcel::Parcel(u64 address, u64 size, const DeviceState &state) : state(state) { - state.thisProcess->ReadMemory(&header, address, sizeof(ParcelHeader)); + state.process->ReadMemory(&header, address, sizeof(ParcelHeader)); if (size < (sizeof(ParcelHeader) + header.dataSize + header.objectsSize)) throw exception("The size of the parcel according to the header exceeds the specified size"); data.resize(header.dataSize); - state.thisProcess->ReadMemory(data.data(), address + header.dataOffset, header.dataSize); + state.process->ReadMemory(data.data(), address + header.dataOffset, header.dataSize); objects.resize(header.objectsSize); - state.thisProcess->ReadMemory(objects.data(), address + header.objectsOffset, header.objectsSize); + state.process->ReadMemory(objects.data(), address + header.objectsOffset, header.objectsSize); } Parcel::Parcel(const DeviceState &state) : state(state) {} - u64 Parcel::WriteParcel(kernel::ipc::OutputBuffer& buffer, pid_t process) { - return WriteParcel(buffer.address, buffer.size, process); + u64 Parcel::WriteParcel(kernel::ipc::OutputBuffer& buffer) { + return WriteParcel(buffer.address, buffer.size); } - u64 Parcel::WriteParcel(u64 address, u64 maxSize, pid_t process) { + u64 Parcel::WriteParcel(u64 address, u64 maxSize) { header.dataSize = static_cast(data.size()); header.dataOffset = sizeof(ParcelHeader); header.objectsSize = static_cast(objects.size()); @@ -29,16 +29,9 @@ namespace skyline::gpu { u64 totalSize = sizeof(ParcelHeader) + header.dataSize + header.objectsSize; if (maxSize < totalSize) throw exception("The size of the parcel exceeds maxSize"); - if (process) { - auto &object = state.os->processMap.at(process); - object->WriteMemory(header, address); - object->WriteMemory(data.data(), address + header.dataOffset, data.size()); - object->WriteMemory(objects.data(), address + header.objectsOffset, objects.size()); - } else { - state.thisProcess->WriteMemory(header, address); - state.thisProcess->WriteMemory(data.data(), address + header.dataOffset, data.size()); - state.thisProcess->WriteMemory(objects.data(), address + header.objectsOffset, objects.size()); - } + state.process->WriteMemory(header, address); + state.process->WriteMemory(data.data(), address + header.dataOffset, data.size()); + state.process->WriteMemory(objects.data(), address + header.objectsOffset, objects.size()); return totalSize; } } diff --git a/app/src/main/cpp/skyline/gpu/parcel.h b/app/src/main/cpp/skyline/gpu/parcel.h index b282e5c1..c0c66dcf 100644 --- a/app/src/main/cpp/skyline/gpu/parcel.h +++ b/app/src/main/cpp/skyline/gpu/parcel.h @@ -80,18 +80,16 @@ namespace skyline::gpu { /** * @brief Writes the Parcel object into a particular output buffer on a process * @param buffer The buffer to write into - * @param process The process to write the Parcel to * @return The total size of the message */ - u64 WriteParcel(kernel::ipc::OutputBuffer& buffer, pid_t process = 0); + u64 WriteParcel(kernel::ipc::OutputBuffer& buffer); /** * @brief Writes the Parcel object into the process's memory * @param address The address to write the Parcel object to * @param maxSize The maximum size of the Parcel - * @param process The process to write the Parcel to * @return The total size of the message */ - u64 WriteParcel(u64 address, u64 maxSize, pid_t process = 0); + u64 WriteParcel(u64 address, u64 maxSize); }; } diff --git a/app/src/main/cpp/skyline/guest.h b/app/src/main/cpp/skyline/guest.h index 9deb5919..5cd9a46a 100644 --- a/app/src/main/cpp/skyline/guest.h +++ b/app/src/main/cpp/skyline/guest.h @@ -1,8 +1,179 @@ #pragma once -namespace skyline::guest { - constexpr size_t saveCtxSize = 20 * sizeof(u32); - constexpr size_t loadCtxSize = 20 * sizeof(u32); - extern "C" void saveCtx(void); - extern "C" void loadCtx(void); +namespace skyline { + namespace guest { + constexpr size_t saveCtxSize = 20 * sizeof(u32); + constexpr size_t loadCtxSize = 20 * sizeof(u32); + extern "C" void saveCtx(void); + extern "C" void loadCtx(void); + } + + namespace instr { + /** + * @brief A bit-field struct that encapsulates a BRK instruction. See https://developer.arm.com/docs/ddi0596/latest/base-instructions-alphabetic-order/brk-breakpoint-instruction. + */ + struct Brk { + /** + * @brief Creates a BRK instruction with a specific immediate value, used for generating BRK opcodes + * @param value The immediate value of the instruction + */ + explicit Brk(u16 value) { + start = 0x0; // First 5 bits of a BRK instruction are 0 + this->value = value; + end = 0x6A1; // Last 11 bits of a BRK instruction stored as u16 + } + + /** + * @brief Returns if the opcode is valid or not + * @return If the opcode represents a valid BRK instruction + */ + inline bool Verify() { + return (start == 0x0 && end == 0x6A1); + } + + union { + struct { + u8 start : 5; + u32 value : 16; + u16 end : 11; + }; + u32 raw{}; + }; + }; + + static_assert(sizeof(Brk) == sizeof(u32)); + + /** + * @brief A bit-field struct that encapsulates a SVC instruction. See https://developer.arm.com/docs/ddi0596/latest/base-instructions-alphabetic-order/svc-supervisor-call. + */ + struct Svc { + /** + * @brief Returns if the opcode is valid or not + * @return If the opcode represents a valid SVC instruction + */ + inline bool Verify() { + return (start == 0x1 && end == 0x6A0); + } + + union { + struct { + u8 start : 5; + u32 value : 16; + u16 end : 11; + }; + u32 raw{}; + }; + }; + + static_assert(sizeof(Svc) == sizeof(u32)); + + /** + * @brief A bit-field struct that encapsulates a MRS instruction. See https://developer.arm.com/docs/ddi0596/latest/base-instructions-alphabetic-order/mrs-move-system-register. + */ + struct Mrs { + /** + * @brief Creates a MRS instruction, used for generating BRK opcodes + * @param srcReg The source system register + * @param dstReg The destination Xn register + */ + Mrs(u32 srcReg, u8 dstReg) { + this->srcReg = srcReg; + this->dstReg = dstReg; + end = 0xD53; // Last 12 bits of a MRS instruction stored as u16 + } + + /** + * @brief Returns if the opcode is valid or not + * @return If the opcode represents a valid MRS instruction + */ + inline bool Verify() { + return (end == 0xD53); + } + + union { + struct { + u8 dstReg : 5; + u32 srcReg : 15; + u16 end : 12; + }; + u32 raw{}; + }; + }; + + static_assert(sizeof(Mrs) == sizeof(u32)); + + /** + * @brief A bit-field struct that encapsulates a B instruction. See https://developer.arm.com/docs/ddi0596/latest/base-instructions-alphabetic-order/b-branch. + */ + struct B { + public: + explicit B(i64 offset) { + this->offset = static_cast(offset / 4); + end = 0x5; + } + + /** + * @brief Returns the offset of the instruction + * @return The offset encoded within the instruction + */ + inline i32 Offset() { + return offset * 4; + } + + /** + * @brief Returns if the opcode is valid or not + * @return If the opcode represents a valid Branch instruction + */ + inline bool Verify() { + return (end == 0x5); + } + + union { + struct { + i32 offset : 26; + u8 end : 6; + }; + u32 raw{}; + }; + }; + + static_assert(sizeof(B) == sizeof(u32)); + + /** + * @brief A bit-field struct that encapsulates a BL instruction. See https://developer.arm.com/docs/ddi0596/latest/base-instructions-alphabetic-order/b-branch. + */ + struct BL { + public: + explicit BL(i64 offset) { + this->offset = static_cast(offset / 4); + end = 0x25; + } + + /** + * @brief Returns the offset of the instruction + * @return The offset encoded within the instruction + */ + inline i32 Offset() { + return offset * 4; + } + + /** + * @brief Returns if the opcode is valid or not + * @return If the opcode represents a valid Branch instruction + */ + inline bool Verify() { + return (end == 0x85); + } + + union { + struct { + i32 offset : 26; + u8 end : 6; + }; + u32 raw{}; + }; + }; + + static_assert(sizeof(BL) == sizeof(u32)); + } } diff --git a/app/src/main/cpp/skyline/kernel/ipc.cpp b/app/src/main/cpp/skyline/kernel/ipc.cpp index a030f688..4012c058 100644 --- a/app/src/main/cpp/skyline/kernel/ipc.cpp +++ b/app/src/main/cpp/skyline/kernel/ipc.cpp @@ -14,7 +14,7 @@ namespace skyline::kernel::ipc { IpcRequest::IpcRequest(bool isDomain, const DeviceState &state) : isDomain(isDomain), state(state), tls() { u8 *currPtr = tls.data(); - state.thisProcess->ReadMemory(currPtr, state.thisThread->tls, constant::TlsIpcSize); + state.process->ReadMemory(currPtr, state.thread->tls, constant::TlsIpcSize); header = reinterpret_cast(currPtr); currPtr += sizeof(CommandHeader); @@ -184,12 +184,12 @@ namespace skyline::kernel::ipc { 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.thisProcess->WriteMemory(tls.data(), state.thisThread->tls, constant::TlsIpcSize); + state.process->WriteMemory(tls.data(), state.thread->tls, constant::TlsIpcSize); } std::vector BufferDescriptorABW::Read(const DeviceState &state) { std::vector vec(Size()); - state.thisProcess->ReadMemory(vec.data(), Address(), Size()); + state.process->ReadMemory(vec.data(), Address(), Size()); return std::move(vec); } } diff --git a/app/src/main/cpp/skyline/kernel/svc.cpp b/app/src/main/cpp/skyline/kernel/svc.cpp index 16072814..30161954 100644 --- a/app/src/main/cpp/skyline/kernel/svc.cpp +++ b/app/src/main/cpp/skyline/kernel/svc.cpp @@ -12,12 +12,12 @@ namespace skyline::kernel::svc { } std::shared_ptr heap; try { - heap = state.thisProcess->memoryRegionMap.at(memory::Region::Heap); + heap = state.process->memoryRegionMap.at(memory::Region::Heap); heap->Resize(size, true); } catch (const exception &) { state.logger->Warn("svcSetHeapSize: Falling back to recreating memory"); - state.thisProcess->UnmapPrivateRegion(memory::Region::Heap); - heap = state.thisProcess->MapPrivateRegion(constant::HeapAddr, size, {true, true, false}, memory::Type::Heap, memory::Region::Heap).item; + state.process->UnmapPrivateRegion(memory::Region::Heap); + heap = state.process->MapPrivateRegion(constant::HeapAddr, size, {true, true, false}, memory::Type::Heap, memory::Region::Heap).item; } state.nce->SetRegister(Wreg::W0, constant::status::Success); state.nce->SetRegister(Xreg::X1, heap->address); @@ -47,7 +47,7 @@ namespace skyline::kernel::svc { } memory::MemoryAttribute attribute = *reinterpret_cast(&maskedValue); bool found = false; - for (const auto&[address, region] : state.thisProcess->memoryMap) { + for (const auto&[address, region] : state.process->memoryMap) { if (addr >= address && addr < (address + region->size)) { bool subFound = false; for (auto &subregion : region->regionInfoVec) { @@ -72,54 +72,53 @@ namespace skyline::kernel::svc { } void QueryMemory(DeviceState &state) { - memory::MemoryInfo memInf; + memory::MemoryInfo memInfo{}; u64 addr = state.nce->GetRegister(Xreg::X2); bool found = false; - for (const auto&[address, region] : state.thisProcess->memoryMap) { + for (const auto&[address, region] : state.process->memoryMap) { if (addr >= address && addr < (address + region->size)) { - memInf = region->GetInfo(addr); + memInfo = region->GetInfo(addr); found = true; break; } } if (!found) { - for (const auto &object : state.thisProcess->handleTable) { + for (const auto &object : state.process->handleTable) { if (object.second->objectType == type::KType::KSharedMemory) { - const auto &mem = state.thisProcess->GetHandle(object.first); - if (mem->procInfMap.count(state.thisProcess->mainThread)) { - const auto &map = mem->procInfMap.at(state.thisProcess->mainThread); - if (addr >= map.address && addr < (map.address + map.size)) { - memInf = mem->GetInfo(state.thisProcess->mainThread); + const auto &mem = state.process->GetHandle(object.first); + if (mem->guest.valid()) { + if (addr >= mem->guest.address && addr < (mem->guest.address + mem->guest.size)) { + memInfo = mem->GetInfo(); found = true; break; } } } else if (object.second->objectType == type::KType::KTransferMemory) { - const auto &mem = state.thisProcess->GetHandle(object.first); + const auto &mem = state.process->GetHandle(object.first); if (addr >= mem->cAddress && addr < (mem->cAddress + mem->cSize)) { - memInf = mem->GetInfo(); + memInfo = mem->GetInfo(); found = true; break; } } } if (!found) { - memInf = { - .baseAddress = constant::BaseEnd, - .size = static_cast(-constant::BaseEnd + 1), + memInfo = { + .baseAddress = constant::BaseAddr, + .size = static_cast(constant::BaseEnd), .type = static_cast(memory::Type::Unmapped) }; state.logger->Debug("svcQueryMemory: Cannot find block of address: 0x{:X}", addr); } } - state.logger->Debug("svcQueryMemory: Address: 0x{:X}, Size: 0x{:X}, Type: {}, Is Uncached: {}, Permissions: {}{}{}", memInf.baseAddress, memInf.size, memInf.type, static_cast(memInf.memoryAttribute.isUncached), memInf.perms.r ? "R" : "-", memInf.perms.w ? "W" : "-", memInf.perms.x ? "X" : "-"); - state.thisProcess->WriteMemory(memInf, state.nce->GetRegister(Xreg::X0)); + state.logger->Debug("svcQueryMemory: Address: 0x{:X}, Size: 0x{:X}, Type: {}, Is Uncached: {}, Permissions: {}{}{}", memInfo.baseAddress, memInfo.size, memInfo.type, static_cast(memInfo.memoryAttribute.isUncached), memInfo.r ? "R" : "-", memInfo.w ? "W" : "-", memInfo.x ? "X" : "-"); + state.process->WriteMemory(memInfo, state.nce->GetRegister(Xreg::X0)); state.nce->SetRegister(Wreg::W0, constant::status::Success); } void ExitProcess(DeviceState &state) { - state.logger->Debug("svcExitProcess: Exiting current process: {}", state.thisProcess->mainThread); - state.os->KillThread(state.thisProcess->mainThread); + state.logger->Debug("svcExitProcess: Exiting current process: {}", state.process->pid); + state.os->KillThread(state.process->pid); } void CreateThread(DeviceState &state) { @@ -132,7 +131,7 @@ namespace skyline::kernel::svc { state.logger->Warn("svcCreateThread: 'priority' invalid: {}", priority); return; } - auto thread = state.thisProcess->CreateThread(entryAddr, entryArg, stackTop, priority); + auto thread = state.process->CreateThread(entryAddr, entryArg, stackTop, priority); state.logger->Debug("svcCreateThread: Created thread with handle 0x{:X} (Entry Point: 0x{:X}, Argument: 0x{:X}, Stack Pointer: 0x{:X}, Priority: {}, PID: {})", thread->handle, entryAddr, entryArg, stackTop, priority, thread->pid); state.nce->SetRegister(Wreg::W1, thread->handle); state.nce->SetRegister(Wreg::W0, constant::status::Success); @@ -141,7 +140,7 @@ namespace skyline::kernel::svc { void StartThread(DeviceState &state) { auto handle = state.nce->GetRegister(Wreg::W0); try { - auto thread = state.thisProcess->GetHandle(handle); + auto thread = state.process->GetHandle(handle); state.logger->Debug("svcStartThread: Starting thread: 0x{:X}, PID: {}", handle, thread->pid); thread->Start(); } catch (const std::exception&) { @@ -151,8 +150,8 @@ namespace skyline::kernel::svc { } void ExitThread(DeviceState &state) { - state.logger->Debug("svcExitProcess: Exiting current thread: {}", state.thisThread->pid); - state.os->KillThread(state.thisThread->pid); + state.logger->Debug("svcExitProcess: Exiting current thread: {}", state.thread->pid); + state.os->KillThread(state.thread->pid); } void SleepThread(DeviceState &state) { @@ -162,19 +161,19 @@ namespace skyline::kernel::svc { case 1: case 2: state.logger->Debug("svcSleepThread: Yielding thread: {}", in); - state.thisThread->status = type::KThread::Status::Runnable; // Will cause the application to awaken on the next iteration of the main loop + state.thread->status = type::KThread::Status::Runnable; // Will cause the application to awaken on the next iteration of the main loop break; default: state.logger->Debug("svcSleepThread: Thread sleeping for {} ns", in); - state.thisThread->timeout = GetCurrTimeNs() + in; - state.thisThread->status = type::KThread::Status::Sleeping; + state.thread->timeout = GetCurrTimeNs() + in; + state.thread->status = type::KThread::Status::Sleeping; } } void GetThreadPriority(DeviceState &state) { auto handle = state.nce->GetRegister(Wreg::W0); try { - auto priority = state.thisProcess->GetHandle(handle)->priority; + auto priority = state.process->GetHandle(handle)->priority; state.nce->SetRegister(Wreg::W1, priority); state.nce->SetRegister(Wreg::W0, constant::status::Success); state.logger->Debug("svcGetThreadPriority: Writing thread priority {}", priority); @@ -188,7 +187,7 @@ namespace skyline::kernel::svc { auto handle = state.nce->GetRegister(Wreg::W0); auto priority = state.nce->GetRegister(Wreg::W1); try { - state.thisProcess->GetHandle(handle)->UpdatePriority(static_cast(priority)); + state.process->GetHandle(handle)->UpdatePriority(static_cast(priority)); state.nce->SetRegister(Wreg::W0, constant::status::Success); state.logger->Debug("svcSetThreadPriority: Setting thread priority to {}", priority); } catch (const std::exception&) { @@ -199,7 +198,7 @@ namespace skyline::kernel::svc { void MapSharedMemory(DeviceState &state) { try { - auto object = state.thisProcess->GetHandle(state.nce->GetRegister(Wreg::W0)); + auto object = state.process->GetHandle(state.nce->GetRegister(Wreg::W0)); u64 addr = state.nce->GetRegister(Xreg::X1); if ((addr & (PAGE_SIZE - 1U))) { state.nce->SetRegister(Wreg::W0, constant::status::InvAddress); @@ -220,7 +219,7 @@ namespace skyline::kernel::svc { return; } state.logger->Debug("svcMapSharedMemory: Mapping shared memory at 0x{:X} for {} bytes ({}{}{})", addr, size, permission.r ? "R" : "-", permission.w ? "W" : "-", permission.x ? "X" : "-"); - object->Map(addr, size, permission, state.thisProcess->mainThread); + object->Map(addr, size, permission); state.nce->SetRegister(Wreg::W0, constant::status::Success); } catch (const std::exception &) { state.logger->Warn("svcMapSharedMemory: 'handle' invalid: 0x{:X}", state.nce->GetRegister(Wreg::W0)); @@ -249,7 +248,7 @@ namespace skyline::kernel::svc { return; } state.logger->Debug("svcCreateTransferMemory: Creating transfer memory at 0x{:X} for {} bytes ({}{}{})", addr, size, permission.r ? "R" : "-", permission.w ? "W" : "-", permission.x ? "X" : "-"); - auto shmem = state.thisProcess->NewHandle(state.thisProcess->mainThread, addr, size, permission); + auto shmem = state.process->NewHandle(state.process->pid, addr, size, permission); state.nce->SetRegister(Wreg::W0, constant::status::Success); state.nce->SetRegister(Wreg::W1, shmem.handle); } @@ -257,7 +256,7 @@ namespace skyline::kernel::svc { void CloseHandle(DeviceState &state) { auto handle = static_cast(state.nce->GetRegister(Wreg::W0)); try { - state.thisProcess->handleTable.erase(handle); + state.process->handleTable.erase(handle); state.logger->Debug("svcCloseHandle: Closing handle: 0x{:X}", handle); state.nce->SetRegister(Wreg::W0, constant::status::Success); } catch(const std::exception&) { @@ -269,7 +268,7 @@ namespace skyline::kernel::svc { void ResetSignal(DeviceState &state) { auto handle = state.nce->GetRegister(Wreg::W0); try { - auto &object = state.thisProcess->handleTable.at(handle); + auto &object = state.process->handleTable.at(handle); switch (object->objectType) { case (type::KType::KEvent): std::static_pointer_cast(object)->ResetSignal(); @@ -299,12 +298,12 @@ namespace skyline::kernel::svc { return; } std::vector waitHandles(numHandles); - state.thisProcess->ReadMemory(waitHandles.data(), state.nce->GetRegister(Xreg::X1), numHandles * sizeof(handle_t)); + state.process->ReadMemory(waitHandles.data(), state.nce->GetRegister(Xreg::X1), numHandles * sizeof(handle_t)); std::string handleStr; uint index{}; for (const auto &handle : waitHandles) { handleStr += fmt::format("* 0x{:X}\n", handle); - auto object = state.thisProcess->handleTable.at(handle); + auto object = state.process->handleTable.at(handle); switch (object->objectType) { case type::KType::KProcess: case type::KType::KThread: @@ -313,7 +312,7 @@ namespace skyline::kernel::svc { break; default: { state.nce->SetRegister(Wreg::W0, constant::status::InvHandle); - state.thisThread->ClearWaitObjects(); + state.thread->ClearWaitObjects(); return; } } @@ -322,19 +321,19 @@ namespace skyline::kernel::svc { state.logger->Debug("svcWaitSynchronization: Signalled handle: 0x{:X}", handle); state.nce->SetRegister(Wreg::W0, constant::status::Success); state.nce->SetRegister(Wreg::W1, index); - state.thisThread->ClearWaitObjects(); + state.thread->ClearWaitObjects(); return; } - state.thisThread->waitObjects.push_back(syncObject); - syncObject->waitThreads.emplace_back(state.thisThread->pid, index); + state.thread->waitObjects.push_back(syncObject); + syncObject->waitThreads.emplace_back(state.thread->pid, index); } auto timeout = state.nce->GetRegister(Xreg::X3); state.logger->Debug("svcWaitSynchronization: Waiting on handles:\n{}Timeout: 0x{:X} ns", handleStr, timeout); if (state.nce->GetRegister(Xreg::X3) != std::numeric_limits::max()) - state.thisThread->timeout = GetCurrTimeNs() + timeout; + state.thread->timeout = GetCurrTimeNs() + timeout; else - state.thisThread->timeout = 0; - state.thisThread->status = type::KThread::Status::WaitSync; + state.thread->timeout = 0; + state.thread->status = type::KThread::Status::WaitSync; } void ArbitrateLock(DeviceState &state) { @@ -345,10 +344,10 @@ namespace skyline::kernel::svc { return; } auto handle = state.nce->GetRegister(Wreg::W2); - if (handle != state.thisThread->handle) + if (handle != state.thread->handle) throw exception("svcArbitrateLock: Called from another thread"); state.logger->Debug("svcArbitrateLock: Locking mutex at 0x{:X} for thread 0x{:X}", addr, handle); - state.thisProcess->MutexLock(addr); + state.process->MutexLock(addr); state.nce->SetRegister(Wreg::W0, constant::status::Success); } @@ -360,7 +359,7 @@ namespace skyline::kernel::svc { return; } state.logger->Debug("svcArbitrateUnlock: Unlocking mutex at 0x{:X}", addr); - state.thisProcess->MutexUnlock(addr); + state.process->MutexUnlock(addr); state.nce->SetRegister(Wreg::W0, constant::status::Success); } @@ -372,24 +371,24 @@ namespace skyline::kernel::svc { return; } auto handle = state.nce->GetRegister(Wreg::W2); - if (handle != state.thisThread->handle) + if (handle != state.thread->handle) throw exception("svcWaitProcessWideKeyAtomic: Called from another thread"); - state.thisProcess->MutexUnlock(mtxAddr); + state.process->MutexUnlock(mtxAddr); auto condAddr = state.nce->GetRegister(Xreg::X1); - auto &cvarVec = state.thisProcess->condVarMap[condAddr]; + auto &cvarVec = state.process->condVarMap[condAddr]; for (auto thread = cvarVec.begin();; thread++) { - if ((*thread)->priority < state.thisThread->priority) { - cvarVec.insert(thread, state.thisThread); + if ((*thread)->priority < state.thread->priority) { + cvarVec.insert(thread, state.thread); break; } else if (thread + 1 == cvarVec.end()) { - cvarVec.push_back(state.thisThread); + cvarVec.push_back(state.thread); break; } } auto timeout = state.nce->GetRegister(Xreg::X3); state.logger->Debug("svcWaitProcessWideKeyAtomic: Mutex: 0x{:X}, Conditional-Variable: 0x:{:X}, Timeout: {} ns", mtxAddr, condAddr, timeout); - state.thisThread->status = type::KThread::Status::WaitCondVar; - state.thisThread->timeout = GetCurrTimeNs() + timeout; + state.thread->status = type::KThread::Status::WaitCondVar; + state.thread->timeout = GetCurrTimeNs() + timeout; state.nce->SetRegister(Wreg::W0, constant::status::Success); } @@ -397,17 +396,17 @@ namespace skyline::kernel::svc { auto address = state.nce->GetRegister(Xreg::X0); auto count = state.nce->GetRegister(Wreg::W1); state.nce->SetRegister(Wreg::W0, constant::status::Success); - if (!state.thisProcess->condVarMap.count(address)) { + if (!state.process->condVarMap.count(address)) { state.logger->Debug("svcSignalProcessWideKey: No Conditional-Variable at 0x{:X}", address); return; } - auto &cvarVec = state.thisProcess->condVarMap.at(address); + auto &cvarVec = state.process->condVarMap.at(address); count = std::min(count, static_cast(cvarVec.size())); for (uint index = 0; index < count; index++) cvarVec[index]->status = type::KThread::Status::Runnable; cvarVec.erase(cvarVec.begin(), cvarVec.begin() + count); if (cvarVec.empty()) - state.thisProcess->condVarMap.erase(address); + state.process->condVarMap.erase(address); state.logger->Debug("svcSignalProcessWideKey: Signalling Conditional-Variable at 0x{:X} for {}", address, count); } @@ -426,7 +425,7 @@ namespace skyline::kernel::svc { void ConnectToNamedPort(DeviceState &state) { char port[constant::PortSize + 1]{0}; - state.os->thisProcess->ReadMemory(port, state.nce->GetRegister(Xreg::X1), constant::PortSize); + state.process->ReadMemory(port, state.nce->GetRegister(Xreg::X1), constant::PortSize); handle_t handle{}; if (std::strcmp(port, "sm:") == 0) handle = state.os->serviceManager.NewSession(service::Service::sm); @@ -449,9 +448,9 @@ namespace skyline::kernel::svc { pid_t pid{}; auto handle = state.nce->GetRegister(Wreg::W1); if (handle != constant::ThreadSelf) { - pid = state.thisProcess->GetHandle(handle)->pid; + pid = state.process->GetHandle(handle)->pid; } else - pid = state.thisThread->pid; + pid = state.thread->pid; state.logger->Debug("svcGetThreadId: Handle: 0x{:X}, PID: {}", handle, pid); state.nce->SetRegister(Xreg::X1, static_cast(pid)); state.nce->SetRegister(Wreg::W0, constant::status::Success); @@ -459,7 +458,7 @@ namespace skyline::kernel::svc { void OutputDebugString(DeviceState &state) { std::string debug(state.nce->GetRegister(Xreg::X1), '\0'); - state.os->thisProcess->ReadMemory(debug.data(), state.nce->GetRegister(Xreg::X0), state.nce->GetRegister(Xreg::X1)); + state.process->ReadMemory(debug.data(), state.nce->GetRegister(Xreg::X0), state.nce->GetRegister(Xreg::X1)); if(debug.back() == '\n') debug.pop_back(); state.logger->Info("Debug Output: {}", debug); @@ -485,16 +484,16 @@ namespace skyline::kernel::svc { out = constant::MapSize; break; case constant::infoState::HeapRegionBaseAddr: - out = state.os->thisProcess->memoryRegionMap.at(memory::Region::Heap)->address; + out = state.process->memoryRegionMap.at(memory::Region::Heap)->address; break; case constant::infoState::HeapRegionSize: - out = state.os->thisProcess->memoryRegionMap.at(memory::Region::Heap)->size; + out = state.process->memoryRegionMap.at(memory::Region::Heap)->size; break; case constant::infoState::TotalMemoryAvailable: out = constant::TotalPhyMem; break; case constant::infoState::TotalMemoryUsage: - out = state.os->thisProcess->memoryRegionMap.at(memory::Region::Heap)->address + state.thisProcess->mainThreadStackSz + state.thisProcess->GetProgramSize(); + out = state.process->memoryRegionMap.at(memory::Region::Heap)->address + state.process->mainThreadStackSz + state.process->GetProgramSize(); break; case constant::infoState::AddressSpaceBaseAddr: out = constant::BaseAddr; @@ -503,25 +502,25 @@ namespace skyline::kernel::svc { out = constant::BaseSize; break; case constant::infoState::StackRegionBaseAddr: - out = state.thisThread->stackTop; + out = state.thread->stackTop; break; case constant::infoState::StackRegionSize: - out = state.thisProcess->mainThreadStackSz; + out = state.process->mainThreadStackSz; break; case constant::infoState::PersonalMmHeapSize: out = constant::TotalPhyMem; break; case constant::infoState::PersonalMmHeapUsage: - out = state.os->thisProcess->memoryRegionMap.at(memory::Region::Heap)->address + state.thisProcess->mainThreadStackSz; + out = state.process->memoryRegionMap.at(memory::Region::Heap)->address + state.process->mainThreadStackSz; break; case constant::infoState::TotalMemoryAvailableWithoutMmHeap: out = constant::TotalPhyMem; // TODO: NPDM specifies SystemResourceSize, subtract that from this break; case constant::infoState::TotalMemoryUsedWithoutMmHeap: - out = state.os->thisProcess->memoryRegionMap.at(memory::Region::Heap)->address + state.thisProcess->mainThreadStackSz; // TODO: Same as above + out = state.process->memoryRegionMap.at(memory::Region::Heap)->address + state.process->mainThreadStackSz; // TODO: Same as above break; case constant::infoState::UserExceptionContextAddr: - out = state.thisProcess->tlsPages[0]->Get(0); + out = state.process->tlsPages[0]->Get(0); break; default: state.logger->Warn("svcGetInfo: Unimplemented case ID0: {}, ID1: {}", id0, id1); diff --git a/app/src/main/cpp/skyline/kernel/types/KPrivateMemory.cpp b/app/src/main/cpp/skyline/kernel/types/KPrivateMemory.cpp index 861751c5..9d0b30a1 100644 --- a/app/src/main/cpp/skyline/kernel/types/KPrivateMemory.cpp +++ b/app/src/main/cpp/skyline/kernel/types/KPrivateMemory.cpp @@ -1,4 +1,5 @@ #include "KPrivateMemory.h" +#include "KProcess.h" #include namespace skyline::kernel::type { @@ -11,13 +12,13 @@ namespace skyline::kernel::type { return dstAddress; } - KPrivateMemory::KPrivateMemory(const DeviceState &state, pid_t pid, u64 dstAddress, u64 srcAddress, size_t size, memory::Permission permission, const memory::Type type) : state(state), owner(pid), address(dstAddress), size(size), permission(permission), type(type), KObject(state, KType::KPrivateMemory) { + KPrivateMemory::KPrivateMemory(const DeviceState &state, u64 dstAddress, u64 srcAddress, size_t size, memory::Permission permission, const memory::Type type, const pid_t pid) : state(state), address(dstAddress), size(size), permission(permission), type(type), KObject(state, KType::KPrivateMemory) { user_pt_regs fregs = {0}; fregs.regs[0] = dstAddress; fregs.regs[1] = srcAddress; fregs.regs[2] = size; fregs.regs[3] = static_cast(permission.Get()); - state.nce->ExecuteFunction(reinterpret_cast(MapPrivateFunc), fregs, pid); + state.nce->ExecuteFunction(reinterpret_cast(MapPrivateFunc), fregs, pid ? pid : state.process->pid); if (reinterpret_cast(fregs.regs[0]) == MAP_FAILED) throw exception("An error occurred while mapping private region in child process"); if (!this->address) @@ -34,7 +35,7 @@ namespace skyline::kernel::type { fregs.regs[1] = size; fregs.regs[2] = newSize; fregs.regs[3] = canMove ? MREMAP_MAYMOVE : 0; - state.nce->ExecuteFunction(reinterpret_cast(RemapPrivateFunc), fregs, owner); + state.nce->ExecuteFunction(reinterpret_cast(RemapPrivateFunc), fregs, state.process->pid); if (reinterpret_cast(fregs.regs[0]) == MAP_FAILED) throw exception("An error occurred while remapping private region in child process"); address = fregs.regs[0]; @@ -51,7 +52,7 @@ namespace skyline::kernel::type { fregs.regs[0] = address; fregs.regs[1] = size; fregs.regs[2] = static_cast(permission.Get()); - state.nce->ExecuteFunction(reinterpret_cast(UpdatePermissionPrivateFunc), fregs, owner); + state.nce->ExecuteFunction(reinterpret_cast(UpdatePermissionPrivateFunc), fregs, state.process->pid); if (static_cast(fregs.regs[0]) == -1) throw exception("An error occurred while updating private region's permissions in child process"); this->permission = permission; @@ -61,14 +62,15 @@ namespace skyline::kernel::type { memory::MemoryInfo info{}; info.baseAddress = address; info.size = size; - info.type = static_cast(type); - for (const auto ®ion : regionInfoVec) { + info.type = static_cast(type); + for (const auto ®ion : regionInfoVec) if ((address >= region.address) && (address < (region.address + region.size))) info.memoryAttribute.isUncached = region.isUncached; - } info.memoryAttribute.isIpcLocked = (info.ipcRefCount > 0); info.memoryAttribute.isDeviceShared = (info.deviceRefCount > 0); - info.perms = permission; + info.r = permission.r; + info.w = permission.w; + info.x = permission.x; info.ipcRefCount = ipcRefCount; info.deviceRefCount = deviceRefCount; return info; @@ -83,7 +85,7 @@ namespace skyline::kernel::type { user_pt_regs fregs = {0}; fregs.regs[0] = address; fregs.regs[1] = size; - state.nce->ExecuteFunction(reinterpret_cast(UnmapPrivateFunc), fregs, owner); + state.nce->ExecuteFunction(reinterpret_cast(UnmapPrivateFunc), fregs, state.process->pid); } catch (const std::exception &) { } } diff --git a/app/src/main/cpp/skyline/kernel/types/KPrivateMemory.h b/app/src/main/cpp/skyline/kernel/types/KPrivateMemory.h index ea838af9..e3b8204e 100644 --- a/app/src/main/cpp/skyline/kernel/types/KPrivateMemory.h +++ b/app/src/main/cpp/skyline/kernel/types/KPrivateMemory.h @@ -12,7 +12,6 @@ namespace skyline::kernel::type { const DeviceState &state; //!< The state of the device public: - pid_t owner; //!< The PID of the process owning this memory u64 address; //!< The address of the allocated memory size_t size; //!< The size of the allocated memory u16 ipcRefCount{}; //!< The amount of reference to this memory for IPC @@ -23,14 +22,14 @@ namespace skyline::kernel::type { /** * @param state The state of the device - * @param pid The PID of the main * @param dstAddress The address to map to (If NULL then an arbitrary address is picked) * @param srcAddress The address to map from (If NULL then no copy is performed) * @param size The size of the allocation * @param permission The permissions for the allocated memory * @param type The type of the memory + * @param pid The PID of the me */ - KPrivateMemory(const DeviceState &state, pid_t pid, u64 dstAddress, u64 srcAddress, size_t size, memory::Permission permission, const memory::Type type); + KPrivateMemory(const DeviceState &state, u64 dstAddress, u64 srcAddress, size_t size, memory::Permission permission, const memory::Type type, const pid_t pid=0); /** * @brief Remap a chunk of memory as to change the size occupied by it diff --git a/app/src/main/cpp/skyline/kernel/types/KProcess.cpp b/app/src/main/cpp/skyline/kernel/types/KProcess.cpp index 7374a44d..466a5ce6 100644 --- a/app/src/main/cpp/skyline/kernel/types/KProcess.cpp +++ b/app/src/main/cpp/skyline/kernel/types/KProcess.cpp @@ -29,7 +29,7 @@ namespace skyline::kernel::type { if (!tlsPage->Full()) return tlsPage->ReserveSlot(); } - auto tlsMem = NewHandle(mainThread, 0, 0, PAGE_SIZE, memory::Permission(true, true, false), memory::Type::ThreadLocal).item; + auto tlsMem = NewHandle(0, 0, PAGE_SIZE, memory::Permission(true, true, false), memory::Type::ThreadLocal, pid).item; memoryMap[tlsMem->address] = tlsMem; tlsPages.push_back(std::make_shared(tlsMem->address)); auto &tlsPage = tlsPages.back(); @@ -38,7 +38,7 @@ namespace skyline::kernel::type { return tlsPage->ReserveSlot(); } - KProcess::KProcess(const DeviceState &state, pid_t pid, u64 entryPoint, u64 stackBase, u64 stackSize) : mainThread(pid), mainThreadStackSz(stackSize), KSyncObject(state, KType::KProcess) { + KProcess::KProcess(const DeviceState &state, pid_t pid, u64 entryPoint, u64 stackBase, u64 stackSize) : pid(pid), mainThreadStackSz(stackSize), KSyncObject(state, KType::KProcess) { state.nce->WaitRdy(pid); threadMap[pid] = NewHandle(pid, entryPoint, 0x0, stackBase + stackSize, GetTlsSlot(), constant::DefaultPriority, this).item; MapPrivateRegion(constant::HeapAddr, constant::DefHeapSize, {true, true, false}, memory::Type::Heap, memory::Region::Heap); @@ -68,13 +68,12 @@ namespace skyline::kernel::type { user_pt_regs fregs = {0}; fregs.regs[0] = entryPoint; fregs.regs[1] = stackTop; - state.nce->ExecuteFunction((void *) CreateThreadFunc, fregs, mainThread); + state.nce->ExecuteFunction((void *) CreateThreadFunc, fregs, pid); auto pid = static_cast(fregs.regs[0]); if (pid == -1) throw exception("Cannot create thread: Address: 0x{:X}, Stack Top: 0x{:X}", entryPoint, stackTop); auto process = NewHandle(pid, entryPoint, entryArg, stackTop, GetTlsSlot(), priority, this).item; threadMap[pid] = process; - state.os->processMap[pid] = state.os->processMap[mainThread]; return process; } @@ -91,7 +90,7 @@ namespace skyline::kernel::type { } KProcess::HandleOut KProcess::MapPrivateRegion(u64 address, size_t size, const memory::Permission perms, const memory::Type type, const memory::Region region) { - auto mem = NewHandle(mainThread, address, 0, size, perms, type); + auto mem = NewHandle(address, 0, size, perms, type, pid); memoryMap[mem.item->address] = mem.item; memoryRegionMap[region] = mem.item; return mem; @@ -113,29 +112,29 @@ namespace skyline::kernel::type { } void KProcess::MutexLock(u64 address) { - auto mtxVec = state.thisProcess->mutexMap[address]; - u32 mtxVal = state.thisProcess->ReadMemory(address); + auto mtxVec = state.process->mutexMap[address]; + u32 mtxVal = state.process->ReadMemory(address); if (mtxVec.empty()) { - mtxVal = (mtxVal & ~constant::MtxOwnerMask) | state.thisThread->handle; - state.thisProcess->WriteMemory(mtxVal, address); + mtxVal = (mtxVal & ~constant::MtxOwnerMask) | state.thread->handle; + state.process->WriteMemory(mtxVal, address); } else { for (auto thread = mtxVec.begin();; thread++) { - if ((*thread)->priority < state.thisThread->priority) { - mtxVec.insert(thread, state.thisThread); + if ((*thread)->priority < state.thread->priority) { + mtxVec.insert(thread, state.thread); break; } else if (thread + 1 == mtxVec.end()) { - mtxVec.push_back(state.thisThread); + mtxVec.push_back(state.thread); break; } } - state.thisThread->status = KThread::Status::WaitMutex; + state.thread->status = KThread::Status::WaitMutex; } } void KProcess::MutexUnlock(u64 address) { - auto mtxVec = state.thisProcess->mutexMap[address]; - u32 mtxVal = state.thisProcess->ReadMemory(address); - if ((mtxVal & constant::MtxOwnerMask) != state.thisThread->pid) + auto mtxVec = state.process->mutexMap[address]; + u32 mtxVal = state.process->ReadMemory(address); + if ((mtxVal & constant::MtxOwnerMask) != state.thread->pid) throw exception("A non-owner thread tried to release a mutex"); if (mtxVec.empty()) { mtxVal = 0; @@ -147,7 +146,7 @@ namespace skyline::kernel::type { if (!mtxVec.empty()) mtxVal |= (~constant::MtxOwnerMask); } - state.thisProcess->WriteMemory(mtxVal, address); + state.process->WriteMemory(mtxVal, address); } void KProcess::ResetSignal() { diff --git a/app/src/main/cpp/skyline/kernel/types/KProcess.h b/app/src/main/cpp/skyline/kernel/types/KProcess.h index 9c4ef621..3546350f 100644 --- a/app/src/main/cpp/skyline/kernel/types/KProcess.h +++ b/app/src/main/cpp/skyline/kernel/types/KProcess.h @@ -63,7 +63,7 @@ namespace skyline::kernel::type { Exiting //!< The process is exiting } status = Status::Created; //!< The state of the process handle_t handleIndex = constant::BaseHandleIndex; //!< This is used to keep track of what to map as an handle - pid_t mainThread; //!< The PID of the main thread + pid_t pid; //!< The PID of the main thread size_t mainThreadStackSz; //!< The size of the main thread's stack (All other threads map stack themselves so we don't know the size per-se) int memFd; //!< The file descriptor to the memory of the process std::unordered_map> memoryMap; //!< A mapping from every address to a shared pointer of it's corresponding KPrivateMemory, used to keep track of KPrivateMemory instances diff --git a/app/src/main/cpp/skyline/kernel/types/KSharedMemory.cpp b/app/src/main/cpp/skyline/kernel/types/KSharedMemory.cpp index bb993f6a..c2c57c02 100644 --- a/app/src/main/cpp/skyline/kernel/types/KSharedMemory.cpp +++ b/app/src/main/cpp/skyline/kernel/types/KSharedMemory.cpp @@ -1,4 +1,5 @@ #include "KSharedMemory.h" +#include "KProcess.h" #include #include #include @@ -15,19 +16,19 @@ namespace skyline::kernel::type { address = MapSharedFunc(address, size, static_cast(permission.Get()), static_cast(fd)); if (address == reinterpret_cast(MAP_FAILED)) // NOLINT(hicpp-signed-bitwise) throw exception("An occurred while mapping shared region: {}", strerror(errno)); - procInfMap[0] = {address, size, permission}; + kernel = {address, size, permission}; } - u64 KSharedMemory::Map(u64 address, u64 size, memory::Permission permission, pid_t pid) { + u64 KSharedMemory::Map(u64 address, u64 size, memory::Permission permission) { user_pt_regs fregs = {0}; fregs.regs[0] = address; fregs.regs[1] = size; fregs.regs[2] = static_cast(permission.Get()); fregs.regs[3] = static_cast(fd); - state.nce->ExecuteFunction(reinterpret_cast(MapSharedFunc), fregs, pid); + state.nce->ExecuteFunction(reinterpret_cast(MapSharedFunc), fregs, state.process->pid); if (reinterpret_cast(fregs.regs[0]) == MAP_FAILED) throw exception("An error occurred while mapping shared region in child process"); - procInfMap[pid] = {fregs.regs[0], size, permission}; + guest = {fregs.regs[0], size, permission}; return fregs.regs[0]; } @@ -36,16 +37,16 @@ namespace skyline::kernel::type { } KSharedMemory::~KSharedMemory() { - for (auto[process, procInf] : procInfMap) { - try { - if(process) { - user_pt_regs fregs = {0}; - fregs.regs[0] = procInf.address; - fregs.regs[1] = procInf.size; - state.nce->ExecuteFunction(reinterpret_cast(UnmapSharedFunc), fregs, process); - } else - UnmapSharedFunc(procInf.address, procInf.size); - } catch (const std::exception &) {} + try { + if (guest.valid()) { + user_pt_regs fregs = {0}; + fregs.regs[0] = guest.address; + fregs.regs[1] = guest.size; + state.nce->ExecuteFunction(reinterpret_cast(UnmapSharedFunc), fregs, state.process->pid); + } + if (kernel.valid()) + UnmapSharedFunc(kernel.address, kernel.size); + } catch (const std::exception &) { } close(fd); } @@ -54,21 +55,21 @@ namespace skyline::kernel::type { return reinterpret_cast(mremap(reinterpret_cast(address), oldSize, size, 0)); } - void KSharedMemory::Resize(size_t newSize) { - for (auto&[process, procInf] : procInfMap) { - if(process) { - user_pt_regs fregs = {0}; - fregs.regs[0] = procInf.address; - fregs.regs[1] = procInf.size; - fregs.regs[2] = newSize; - state.nce->ExecuteFunction(reinterpret_cast(RemapSharedFunc), fregs, process); - if (reinterpret_cast(fregs.regs[0]) == MAP_FAILED) - throw exception("An error occurred while remapping shared region in child process"); - } else { - if (RemapSharedFunc(procInf.address, procInf.size, newSize) == reinterpret_cast(MAP_FAILED)) - throw exception("An occurred while remapping shared region: {}", strerror(errno)); - } - procInf.size = newSize; + void KSharedMemory::Resize(size_t size) { + if (guest.valid()) { + user_pt_regs fregs = {0}; + fregs.regs[0] = guest.address; + fregs.regs[1] = guest.size; + fregs.regs[2] = size; + state.nce->ExecuteFunction(reinterpret_cast(RemapSharedFunc), fregs, state.process->pid); + if (reinterpret_cast(fregs.regs[0]) == MAP_FAILED) + throw exception("An error occurred while remapping shared region in child process"); + guest.size = size; + } + if (kernel.valid()) { + if (RemapSharedFunc(kernel.address, kernel.size, size) == reinterpret_cast(MAP_FAILED)) + throw exception("An occurred while remapping shared region: {}", strerror(errno)); + kernel.size = size; } } @@ -76,33 +77,34 @@ namespace skyline::kernel::type { return static_cast(mprotect(reinterpret_cast(address), size, static_cast(perms))); } - void KSharedMemory::UpdatePermission(pid_t pid, memory::Permission permission) { - for (auto&[process, procInf] : procInfMap) { - if(process) { - user_pt_regs fregs = {0}; - fregs.regs[0] = procInf.address; - fregs.regs[1] = procInf.size; - fregs.regs[2] = static_cast(procInf.permission.Get()); - state.nce->ExecuteFunction(reinterpret_cast(UpdatePermissionSharedFunc), fregs, process); - if (static_cast(fregs.regs[0]) == -1) - throw exception("An error occurred while updating shared region's permissions in child process"); - } else { - if (UpdatePermissionSharedFunc(procInf.address, procInf.size, static_cast(permission.Get())) == reinterpret_cast(MAP_FAILED)) - throw exception("An occurred while remapping shared region: {}", strerror(errno)); - } - procInf.permission = permission; + void KSharedMemory::UpdatePermission(memory::Permission permission, bool host) { + if (guest.valid() && !host) { + user_pt_regs fregs = {0}; + fregs.regs[0] = guest.address; + fregs.regs[1] = guest.size; + fregs.regs[2] = static_cast(guest.permission.Get()); + state.nce->ExecuteFunction(reinterpret_cast(UpdatePermissionSharedFunc), fregs, state.process->pid); + if (static_cast(fregs.regs[0]) == -1) + throw exception("An error occurred while updating shared region's permissions in child process"); + guest.permission = permission; + } + if (kernel.valid() && host) { + if (UpdatePermissionSharedFunc(kernel.address, kernel.size, static_cast(permission.Get())) == reinterpret_cast(MAP_FAILED)) + throw exception("An occurred while remapping shared region: {}", strerror(errno)); + kernel.permission = permission; } } - memory::MemoryInfo KSharedMemory::GetInfo(pid_t pid) { + memory::MemoryInfo KSharedMemory::GetInfo() { memory::MemoryInfo info{}; - const auto &procInf = procInfMap.at(pid); - info.baseAddress = procInf.address; - info.size = procInf.size; - info.type = static_cast(type); + info.baseAddress = guest.address; + info.size = guest.size; + info.type = static_cast(type); info.memoryAttribute.isIpcLocked = (info.ipcRefCount > 0); info.memoryAttribute.isDeviceShared = (info.deviceRefCount > 0); - info.perms = procInf.permission; + info.r = guest.permission.r; + info.w = guest.permission.w; + info.x = guest.permission.x; info.ipcRefCount = ipcRefCount; info.deviceRefCount = deviceRefCount; return info; diff --git a/app/src/main/cpp/skyline/kernel/types/KSharedMemory.h b/app/src/main/cpp/skyline/kernel/types/KSharedMemory.h index 77758f93..8e4a0247 100644 --- a/app/src/main/cpp/skyline/kernel/types/KSharedMemory.h +++ b/app/src/main/cpp/skyline/kernel/types/KSharedMemory.h @@ -15,12 +15,18 @@ namespace skyline::kernel::type { /** * @brief This holds the address and size of a process's mapping */ - struct ProcessInfo { + struct MapInfo { u64 address; size_t size; memory::Permission permission; - }; - std::unordered_map procInfMap; //!< Maps from a PID to where the memory was mapped to + + /** + * @brief Returns if the object is valid + * @return If the MapInfo object is valid + */ + inline bool valid() { return address && size && permission.Get(); } + } kernel, guest; + u16 ipcRefCount{}; //!< The amount of reference to this memory for IPC u16 deviceRefCount{}; //!< The amount of reference to this memory for IPC memory::Type type; //!< The type of this memory allocation @@ -35,33 +41,32 @@ namespace skyline::kernel::type { KSharedMemory(const DeviceState &state, u64 address, size_t size, const memory::Permission permission, memory::Type type); /** - * @brief Maps the shared memory at an address + * @brief Maps the shared memory at an address in the guest * @param address The address to map to (If NULL an arbitrary address is picked) * @param size The amount of shared memory to map * @param permission The permission of the kernel process - * @param pid The PID of the process * @return The address of the allocation */ - u64 Map(const u64 address, const u64 size, memory::Permission permission, pid_t pid); + u64 Map(const u64 address, const u64 size, memory::Permission permission); /** * @brief Resize a chunk of memory as to change the size occupied by it - * @param newSize The new size of the memory + * @param size The new size of the memory */ - void Resize(size_t newSize); + void Resize(size_t size); /** - * Updates the permissions of a chunk of mapped memory - * @param pid The PID of the requesting process + * @brief Updates the permissions of a chunk of mapped memory * @param permission The new permissions to be set for the memory + * @param kernel Set the permissions for the kernel rather than the guest */ - void UpdatePermission(pid_t pid, memory::Permission permission); + void UpdatePermission(memory::Permission permission, bool host=0); /** - * @param pid The PID of the requesting process + * @brief Creates a MemoryInfo struct from the current instance * @return A Memory::MemoryInfo struct based on attributes of the memory */ - memory::MemoryInfo GetInfo(pid_t pid); + memory::MemoryInfo GetInfo(); /** * @brief The destructor of shared memory, it deallocates the memory from all processes diff --git a/app/src/main/cpp/skyline/kernel/types/KSyncObject.cpp b/app/src/main/cpp/skyline/kernel/types/KSyncObject.cpp index 6115a627..2e4d168f 100644 --- a/app/src/main/cpp/skyline/kernel/types/KSyncObject.cpp +++ b/app/src/main/cpp/skyline/kernel/types/KSyncObject.cpp @@ -9,7 +9,7 @@ namespace skyline::kernel::type { void KSyncObject::Signal() { for (const auto &info : waitThreads) { state.nce->SetRegister(Wreg::W1, info.index); - state.os->processMap.at(info.process)->threadMap.at(info.process)->status = KThread::Status::Runnable; + state.process->threadMap.at(info.process)->status = KThread::Status::Runnable; } waitThreads.clear(); } diff --git a/app/src/main/cpp/skyline/kernel/types/KThread.cpp b/app/src/main/cpp/skyline/kernel/types/KThread.cpp index 3537ee35..1dd26c0d 100644 --- a/app/src/main/cpp/skyline/kernel/types/KThread.cpp +++ b/app/src/main/cpp/skyline/kernel/types/KThread.cpp @@ -14,7 +14,7 @@ namespace skyline::kernel::type { void KThread::Start() { if(status == Status::Created) { - if (pid == parent->mainThread) + if (pid == parent->pid) parent->status = KProcess::Status::Started; status = Status::Running; state.nce->StartProcess(entryPoint, entryArg, stackTop, handle, pid); diff --git a/app/src/main/cpp/skyline/kernel/types/KTransferMemory.cpp b/app/src/main/cpp/skyline/kernel/types/KTransferMemory.cpp index d2437c4c..662cb1b3 100644 --- a/app/src/main/cpp/skyline/kernel/types/KTransferMemory.cpp +++ b/app/src/main/cpp/skyline/kernel/types/KTransferMemory.cpp @@ -45,17 +45,12 @@ namespace skyline::kernel::type { throw exception("An error occurred while mapping transfer memory in kernel"); } size_t copySz = std::min(size, cSize); - if (process && owner) { - std::vector tempBuf(copySz); - state.os->processMap.at(process)->ReadMemory(tempBuf.data(), cAddress, copySz); - state.os->processMap.at(owner)->WriteMemory(tempBuf.data(), address, copySz); - } else if (process && !owner) { - state.os->processMap.at(process)->WriteMemory(reinterpret_cast(cAddress), address, copySz); + if (process && !owner) { + state.process->WriteMemory(reinterpret_cast(cAddress), address, copySz); } else if (!process && owner) { - state.os->processMap.at(owner)->ReadMemory(reinterpret_cast(address), cAddress, copySz); - } else { + state.process->ReadMemory(reinterpret_cast(address), cAddress, copySz); + } else throw exception("Transferring from kernel to kernel is not supported"); - } if (owner) { user_pt_regs fregs = {0}; fregs.regs[0] = address; @@ -81,7 +76,9 @@ namespace skyline::kernel::type { info.type = static_cast(memory::Type::TransferMemory); info.memoryAttribute.isIpcLocked = (info.ipcRefCount > 0); info.memoryAttribute.isDeviceShared = (info.deviceRefCount > 0); - info.perms = permission; + info.r = permission.r; + info.w = permission.w; + info.x = permission.x; info.ipcRefCount = ipcRefCount; info.deviceRefCount = deviceRefCount; return info; diff --git a/app/src/main/cpp/skyline/memory.h b/app/src/main/cpp/skyline/memory.h index 16c4171e..7eed229f 100644 --- a/app/src/main/cpp/skyline/memory.h +++ b/app/src/main/cpp/skyline/memory.h @@ -30,12 +30,12 @@ namespace skyline::memory { /** * @brief Equality operator between two Permission objects */ - bool operator==(const Permission &rhs) const { return (this->r == rhs.r && this->w == rhs.w && this->x == rhs.x); }; + inline bool operator==(const Permission &rhs) const { return (this->r == rhs.r && this->w == rhs.w && this->x == rhs.x); }; /** * @brief Inequality operator between two Permission objects */ - bool operator!=(const Permission &rhs) const { return !operator==(rhs); }; + inline bool operator!=(const Permission &rhs) const { return !operator==(rhs); }; /** * @return The value of the permission struct in mmap(2) format @@ -51,18 +51,24 @@ namespace skyline::memory { return perm; }; - bool r : 1, w : 1, x : 1; + bool r; + bool w; + bool x; }; /** * @brief This holds certain attributes of a chunk of memory: https://switchbrew.org/wiki/SVC#MemoryAttribute */ - struct MemoryAttribute { - bool isBorrowed : 1; - bool isIpcLocked : 1; - bool isDeviceShared : 1; - bool isUncached : 1; + union MemoryAttribute { + struct { + bool isBorrowed : 1; + bool isIpcLocked : 1; + bool isDeviceShared : 1; + bool isUncached : 1; + }; + u32 value; }; + static_assert(sizeof(MemoryAttribute) == sizeof(u32)); /** * @brief This describes the properties of a region of the allocated memory @@ -81,12 +87,17 @@ namespace skyline::memory { struct MemoryInfo { u64 baseAddress; u64 size; - u64 type; + u32 type; MemoryAttribute memoryAttribute; - Permission perms; + union { + u32 _pad0_; + struct { + bool r : 1, w : 1, x : 1; + }; + }; u32 ipcRefCount; u32 deviceRefCount; - u32 : 32; + u32 : 32; }; static_assert(sizeof(MemoryInfo) == 0x28); diff --git a/app/src/main/cpp/skyline/nce.cpp b/app/src/main/cpp/skyline/nce.cpp index e65e3016..0d635dd6 100644 --- a/app/src/main/cpp/skyline/nce.cpp +++ b/app/src/main/cpp/skyline/nce.cpp @@ -9,175 +9,6 @@ extern bool Halt; extern skyline::Mutex jniMtx; namespace skyline { - namespace instr { - /** - * @brief A bit-field struct that encapsulates a BRK instruction. See https://developer.arm.com/docs/ddi0596/latest/base-instructions-alphabetic-order/brk-breakpoint-instruction. - */ - struct Brk { - /** - * @brief Creates a BRK instruction with a specific immediate value, used for generating BRK opcodes - * @param value The immediate value of the instruction - */ - explicit Brk(u16 value) { - start = 0x0; // First 5 bits of a BRK instruction are 0 - this->value = value; - end = 0x6A1; // Last 11 bits of a BRK instruction stored as u16 - } - - /** - * @brief Returns if the opcode is valid or not - * @return If the opcode represents a valid BRK instruction - */ - inline bool Verify() { - return (start == 0x0 && end == 0x6A1); - } - - union { - struct { - u8 start : 5; - u32 value : 16; - u16 end : 11; - }; - u32 raw{}; - }; - }; - - static_assert(sizeof(Brk) == sizeof(u32)); - - /** - * @brief A bit-field struct that encapsulates a SVC instruction. See https://developer.arm.com/docs/ddi0596/latest/base-instructions-alphabetic-order/svc-supervisor-call. - */ - struct Svc { - /** - * @brief Returns if the opcode is valid or not - * @return If the opcode represents a valid SVC instruction - */ - inline bool Verify() { - return (start == 0x1 && end == 0x6A0); - } - - union { - struct { - u8 start : 5; - u32 value : 16; - u16 end : 11; - }; - u32 raw{}; - }; - }; - - static_assert(sizeof(Svc) == sizeof(u32)); - - /** - * @brief A bit-field struct that encapsulates a MRS instruction. See https://developer.arm.com/docs/ddi0596/latest/base-instructions-alphabetic-order/mrs-move-system-register. - */ - struct Mrs { - /** - * @brief Creates a MRS instruction, used for generating BRK opcodes - * @param srcReg The source system register - * @param dstReg The destination Xn register - */ - Mrs(u32 srcReg, u8 dstReg) { - this->srcReg = srcReg; - this->dstReg = dstReg; - end = 0xD53; // Last 12 bits of a MRS instruction stored as u16 - } - - /** - * @brief Returns if the opcode is valid or not - * @return If the opcode represents a valid MRS instruction - */ - inline bool Verify() { - return (end == 0xD53); - } - - union { - struct { - u8 dstReg : 5; - u32 srcReg : 15; - u16 end : 12; - }; - u32 raw{}; - }; - }; - - static_assert(sizeof(Mrs) == sizeof(u32)); - - /** - * @brief A bit-field struct that encapsulates a B instruction. See https://developer.arm.com/docs/ddi0596/latest/base-instructions-alphabetic-order/b-branch. - */ - struct B { - public: - explicit B(i64 offset) { - this->offset = static_cast(offset / 4); - end = 0x5; - } - - /** - * @brief Returns the offset of the instruction - * @return The offset encoded within the instruction - */ - inline i32 Offset() { - return offset * 4; - } - - /** - * @brief Returns if the opcode is valid or not - * @return If the opcode represents a valid Branch instruction - */ - inline bool Verify() { - return (end == 0x5); - } - - union { - struct { - i32 offset : 26; - u8 end : 6; - }; - u32 raw{}; - }; - }; - - static_assert(sizeof(B) == sizeof(u32)); - - /** - * @brief A bit-field struct that encapsulates a BL instruction. See https://developer.arm.com/docs/ddi0596/latest/base-instructions-alphabetic-order/b-branch. - */ - struct BL { - public: - explicit BL(i64 offset) { - this->offset = static_cast(offset / 4); - end = 0x25; - } - - /** - * @brief Returns the offset of the instruction - * @return The offset encoded within the instruction - */ - inline i32 Offset() { - return offset * 4; - } - - /** - * @brief Returns if the opcode is valid or not - * @return If the opcode represents a valid Branch instruction - */ - inline bool Verify() { - return (end == 0x85); - } - - union { - struct { - i32 offset : 26; - u8 end : 6; - }; - u32 raw{}; - }; - }; - - static_assert(sizeof(BL) == sizeof(u32)); - } - void NCE::ReadRegisters(user_pt_regs ®isters, pid_t pid) const { iovec iov = {®isters, sizeof(registers)}; long status = ptrace(PTRACE_GETREGSET, pid ? pid : currPid, NT_PRSTATUS, &iov); @@ -203,15 +34,14 @@ namespace skyline { void NCE::Execute() { int status = 0; - while (!Halt && !state.os->processMap.empty()) { + while (!Halt && state.os->process) { std::lock_guard jniGd(jniMtx); - for (const auto &process : state.os->processMap) { - state.os->thisProcess = process.second; - state.os->thisThread = process.second->threadMap.at(process.first); - currPid = process.first; + for (const auto &thread : state.os->process->threadMap) { + state.os->thisThread = thread.second; + currPid = thread.first; auto &currRegs = registerMap[currPid]; - if (state.thisThread->status == kernel::type::KThread::Status::Running) { - if (waitpid(state.thisThread->pid, &status, WNOHANG) == state.thisThread->pid) { + if (state.thread->status == kernel::type::KThread::Status::Running) { + if (waitpid(state.thread->pid, &status, WNOHANG) == state.thread->pid) { if (WIFSTOPPED(status) && (WSTOPSIG(status) == SIGTRAP || WSTOPSIG(status) == SIGSTOP)) { // NOLINT(hicpp-signed-bitwise) ReadRegisters(currRegs); auto instr = ReadBrk(currRegs.pc); @@ -219,11 +49,11 @@ namespace skyline { // We store the instruction value as the immediate value in BRK. 0x0 to 0x7F are SVC, 0x80 to 0x9E is MRS for TPIDRRO_EL0. if (instr.value <= constant::SvcLast) { state.os->SvcHandler(static_cast(instr.value)); - if (state.thisThread->status != kernel::type::KThread::Status::Running) + if (state.thread->status != kernel::type::KThread::Status::Running) continue; } else if (instr.value > constant::SvcLast && instr.value <= constant::SvcLast + constant::NumRegs) { // Catch MRS that reads the value of TPIDRRO_EL0 (TLS) - SetRegister(static_cast(instr.value - (constant::SvcLast + 1)), state.thisThread->tls); + SetRegister(static_cast(instr.value - (constant::SvcLast + 1)), state.thread->tls); } else if (instr.value == constant::BrkRdy) continue; else { @@ -244,17 +74,18 @@ namespace skyline { state.os->KillThread(currPid); } } - } else if ((state.thisThread->status == kernel::type::KThread::Status::WaitSync || state.thisThread->status == kernel::type::KThread::Status::Sleeping || state.thisThread->status == kernel::type::KThread::Status::WaitCondVar) && state.thisThread->timeout != 0) { // timeout == 0 means sleep forever - if (state.thisThread->timeout <= GetCurrTimeNs()) { - state.logger->Info("An event has timed out: {}", state.thisThread->status); - if (state.thisThread->status == kernel::type::KThread::Status::WaitSync || state.thisThread->status == kernel::type::KThread::Status::WaitCondVar) + } else if ((state.thread->status == kernel::type::KThread::Status::WaitSync || state.thread->status == kernel::type::KThread::Status::Sleeping || state.thread->status == kernel::type::KThread::Status::WaitCondVar) && state.thread->timeout != 0) { // timeout == 0 means sleep forever + if (state.thread->timeout <= GetCurrTimeNs()) { + if(state.thread->status != kernel::type::KThread::Status::Sleeping) + state.logger->Info("An event has timed out: {}", state.thread->status); + if (state.thread->status == kernel::type::KThread::Status::WaitSync || state.thread->status == kernel::type::KThread::Status::WaitCondVar) SetRegister(Wreg::W0, constant::status::Timeout); - state.thisThread->status = kernel::type::KThread::Status::Runnable; + state.thread->status = kernel::type::KThread::Status::Runnable; } } - if (state.thisThread->status == kernel::type::KThread::Status::Runnable) { - state.thisThread->ClearWaitObjects(); - state.thisThread->status = kernel::type::KThread::Status::Running; + if (state.thread->status == kernel::type::KThread::Status::Runnable) { + state.thread->ClearWaitObjects(); + state.thread->status = kernel::type::KThread::Status::Running; currRegs.pc += sizeof(u32); WriteRegisters(currRegs); ResumeProcess(); @@ -263,9 +94,6 @@ namespace skyline { state.os->serviceManager.Loop(); state.gpu->Loop(); } - for (const auto &process : state.os->processMap) { - state.os->KillThread(process.first); - } } void BrkLr() { diff --git a/app/src/main/cpp/skyline/nce.h b/app/src/main/cpp/skyline/nce.h index 3c66ad7e..508fa0ef 100644 --- a/app/src/main/cpp/skyline/nce.h +++ b/app/src/main/cpp/skyline/nce.h @@ -12,6 +12,7 @@ namespace skyline { namespace instr { struct Brk; } + /** * @brief The NCE (Native Code Execution) class is responsible for managing the state of catching instructions and directly controlling processes/threads */ diff --git a/app/src/main/cpp/skyline/os.cpp b/app/src/main/cpp/skyline/os.cpp index c1c46dde..bafac64f 100644 --- a/app/src/main/cpp/skyline/os.cpp +++ b/app/src/main/cpp/skyline/os.cpp @@ -3,7 +3,7 @@ #include "loader/nro.h" namespace skyline::kernel { - OS::OS(std::shared_ptr& jvmManager, std::shared_ptr &logger, std::shared_ptr &settings) : state(this, thisProcess, thisThread, jvmManager, settings, logger), serviceManager(state) {} + OS::OS(std::shared_ptr& jvmManager, std::shared_ptr &logger, std::shared_ptr &settings) : state(this, process, thisThread, jvmManager, settings, logger), serviceManager(state) {} void OS::Execute(const int romFd, const TitleFormat romType) { auto process = CreateProcess(constant::BaseAddr, constant::DefStackSize); @@ -12,7 +12,7 @@ namespace skyline::kernel { loader.LoadProcessData(process, state); } else throw exception("Unsupported ROM extension."); - process->threadMap.at(process->mainThread)->Start(); // The kernel itself is responsible for starting the main thread + process->threadMap.at(process->pid)->Start(); // The kernel itself is responsible for starting the main thread state.nce->Execute(); } @@ -36,27 +36,22 @@ namespace skyline::kernel { pid_t pid = clone(&ExecuteChild, stack + stackSize, CLONE_FILES | CLONE_FS | SIGCHLD, nullptr); // NOLINT(hicpp-signed-bitwise) if (pid == -1) throw exception("Call to clone() has failed: {}", strerror(errno)); - std::shared_ptr process = std::make_shared(state, pid, address, reinterpret_cast(stack), stackSize); - processMap[pid] = process; - processVec.push_back(pid); + process = std::make_shared(state, pid, address, reinterpret_cast(stack), stackSize); state.logger->Debug("Successfully created process with PID: {}", pid); return process; } void OS::KillThread(pid_t pid) { - auto process = processMap.at(pid); - if (process->mainThread == pid) { + if (process->pid == pid) { state.logger->Debug("Killing process with PID: {}", pid); for (auto&[key, value]: process->threadMap) { value->Kill(); - processMap.erase(key); } - processVec.erase(std::remove(processVec.begin(), processVec.end(), pid), processVec.end()); + process.reset(); } else { state.logger->Debug("Killing thread with TID: {}", pid); process->threadMap.at(pid)->Kill(); process->threadMap.erase(pid); - processMap.erase(pid); } } diff --git a/app/src/main/cpp/skyline/os.h b/app/src/main/cpp/skyline/os.h index fe3f8780..61a44a4a 100644 --- a/app/src/main/cpp/skyline/os.h +++ b/app/src/main/cpp/skyline/os.h @@ -19,9 +19,7 @@ namespace skyline::kernel { DeviceState state; //!< The state of the device public: - std::unordered_map> processMap; //!< A mapping from a threat's PID to it's KProcess object - std::vector processVec; //!< A vector of all processes by their main thread's PID - std::shared_ptr thisProcess; //!< The corresponding KProcess object of the process that's called an SVC + std::shared_ptr process; //!< The KProcess object for the emulator, representing the guest process std::shared_ptr thisThread; //!< The corresponding KThread object of the thread that's called an SVC service::ServiceManager serviceManager; //!< This manages all of the service functions diff --git a/app/src/main/cpp/skyline/services/am/appletController.cpp b/app/src/main/cpp/skyline/services/am/appletController.cpp index 23401c68..b556c24c 100644 --- a/app/src/main/cpp/skyline/services/am/appletController.cpp +++ b/app/src/main/cpp/skyline/services/am/appletController.cpp @@ -20,7 +20,7 @@ namespace skyline::service::am { } void ICommonStateGetter::GetEventHandle(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { - auto handle = state.thisProcess->InsertItem(messageEvent); + auto handle = state.process->InsertItem(messageEvent); state.logger->Debug("Event Handle: 0x{:X}", handle); response.copyHandles.push_back(handle); } @@ -86,7 +86,7 @@ namespace skyline::service::am { }) {} void IWindowController::GetAppletResourceUserId(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { - response.Push(static_cast(state.thisProcess->mainThread)); + response.Push(static_cast(state.process->pid)); } void IWindowController::AcquireForegroundRights(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {} diff --git a/app/src/main/cpp/skyline/services/hid/hid.cpp b/app/src/main/cpp/skyline/services/hid/hid.cpp index 065aa45d..f6b9fd62 100644 --- a/app/src/main/cpp/skyline/services/hid/hid.cpp +++ b/app/src/main/cpp/skyline/services/hid/hid.cpp @@ -8,7 +8,7 @@ namespace skyline::service::hid { void IAppletResource::GetSharedMemoryHandle(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { hidSharedMemory = std::make_shared(state, NULL, constant::hidSharedMemSize, memory::Permission(true, false, false), memory::Type::SharedMemory); - auto handle = state.thisProcess->InsertItem(hidSharedMemory); + auto handle = state.process->InsertItem(hidSharedMemory); state.logger->Debug("HID Shared Memory Handle: {}", handle); response.copyHandles.push_back(handle); } @@ -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.thisProcess->ReadMemory(address); + auto id = state.process->ReadMemory(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 176734ee..eb56c015 100644 --- a/app/src/main/cpp/skyline/services/nvdrv/nvdrv.cpp +++ b/app/src/main/cpp/skyline/services/nvdrv/nvdrv.cpp @@ -14,7 +14,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.thisProcess->ReadMemory(path.data(), buffer.address, buffer.size); + state.process->ReadMemory(path.data(), buffer.address, buffer.size); response.Push(state.gpu->OpenDevice(path)); response.Push(constant::status::Success); } @@ -39,7 +39,7 @@ namespace skyline::service::nvdrv { auto fd = request.Pop(); auto eventId = request.Pop(); auto event = std::make_shared(state); - auto handle = state.thisProcess->InsertItem(event); + auto handle = state.process->InsertItem(event); state.logger->Debug("QueryEvent: FD: {}, Event ID: {}, Handle: {}", fd, eventId, handle); response.copyHandles.push_back(handle); } diff --git a/app/src/main/cpp/skyline/services/nvnflinger/dispdrv.cpp b/app/src/main/cpp/skyline/services/nvnflinger/dispdrv.cpp index b7a98fd8..c14abc68 100644 --- a/app/src/main/cpp/skyline/services/nvnflinger/dispdrv.cpp +++ b/app/src/main/cpp/skyline/services/nvnflinger/dispdrv.cpp @@ -64,7 +64,7 @@ namespace skyline::service::nvnflinger { } void dispdrv::GetNativeHandle(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { - handle_t handle = state.thisProcess->InsertItem(state.gpu->bufferEvent); + handle_t handle = state.process->InsertItem(state.gpu->bufferEvent); state.logger->Debug("BufferEvent Handle: 0x{:X}", handle); response.copyHandles.push_back(handle); response.Push(constant::status::Success); diff --git a/app/src/main/cpp/skyline/services/serviceman.cpp b/app/src/main/cpp/skyline/services/serviceman.cpp index dc864f7f..e6cbcbc7 100644 --- a/app/src/main/cpp/skyline/services/serviceman.cpp +++ b/app/src/main/cpp/skyline/services/serviceman.cpp @@ -120,7 +120,7 @@ namespace skyline::service { } handle_t ServiceManager::NewSession(const Service serviceType) { - return state.thisProcess->NewHandle(GetService(serviceType)).handle; + return state.process->NewHandle(GetService(serviceType)).handle; } std::shared_ptr ServiceManager::NewService(const std::string &serviceName, type::KSession &session, ipc::IpcResponse &response) { @@ -131,7 +131,7 @@ namespace skyline::service { response.domainObjects.push_back(session.handleIndex); handle = session.handleIndex; } else { - handle = state.thisProcess->NewHandle(serviceObject).handle; + handle = state.process->NewHandle(serviceObject).handle; response.moveHandles.push_back(handle); } state.logger->Debug("Service has been created: \"{}\" (0x{:X})", serviceName, handle); @@ -145,14 +145,14 @@ namespace skyline::service { response.domainObjects.push_back(session.handleIndex); handle = session.handleIndex++; } else { - handle = state.thisProcess->NewHandle(serviceObject).handle; + handle = state.process->NewHandle(serviceObject).handle; response.moveHandles.push_back(handle); } state.logger->Debug("Service has been registered: \"{}\" (0x{:X})", serviceObject->getName(), handle); } void ServiceManager::CloseSession(const handle_t handle) { - auto session = state.thisProcess->GetHandle(handle); + auto session = state.process->GetHandle(handle); if (session->serviceStatus == type::KSession::ServiceStatus::Open) { if (session->isDomain) { for (const auto &[objectId, service] : session->domainTable) @@ -170,7 +170,7 @@ namespace skyline::service { } void ServiceManager::SyncRequestHandler(const handle_t handle) { - auto session = state.thisProcess->GetHandle(handle); + auto session = state.process->GetHandle(handle); state.logger->Debug("----Start----"); state.logger->Debug("Handle is 0x{:X}", handle); @@ -211,7 +211,7 @@ namespace skyline::service { break; case ipc::ControlCommand::CloneCurrentObject: case ipc::ControlCommand::CloneCurrentObjectEx: - response.Push(state.thisProcess->InsertItem(session)); + response.Push(state.process->InsertItem(session)); break; case ipc::ControlCommand::QueryPointerBufferSize: response.Push(0x1000); diff --git a/app/src/main/cpp/skyline/services/set/sys.cpp b/app/src/main/cpp/skyline/services/set/sys.cpp index 84aea751..c9ff5304 100644 --- a/app/src/main/cpp/skyline/services/set/sys.cpp +++ b/app/src/main/cpp/skyline/services/set/sys.cpp @@ -6,6 +6,6 @@ namespace skyline::service::set { void sys::GetFirmwareVersion(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { SysVerTitle title{.minor=9, .major=0, .micro=0, .revMajor=4, .platform="NX", .verHash="4de65c071fd0869695b7629f75eb97b2551dbf2f", .dispVer="9.0.0", .dispTitle="NintendoSDK Firmware for NX 9.0.0-4.0"}; - state.thisProcess->WriteMemory(title, request.outputBuf.at(0).address); + state.process->WriteMemory(title, request.outputBuf.at(0).address); } } diff --git a/app/src/main/cpp/skyline/services/vi/vi_m.cpp b/app/src/main/cpp/skyline/services/vi/vi_m.cpp index 3a55945d..bede4b77 100644 --- a/app/src/main/cpp/skyline/services/vi/vi_m.cpp +++ b/app/src/main/cpp/skyline/services/vi/vi_m.cpp @@ -105,7 +105,7 @@ namespace skyline::service::vi { } void IApplicationDisplayService::GetDisplayVsyncEvent(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { - handle_t handle = state.thisProcess->InsertItem(state.gpu->vsyncEvent); + handle_t handle = state.process->InsertItem(state.gpu->vsyncEvent); state.logger->Debug("VSync Event Handle: 0x{:X}", handle); response.copyHandles.push_back(handle); }