// SPDX-License-Identifier: MPL-2.0 // Copyright © 2023 Skyline Team and Contributors (https://github.com/skyline-emu/) #include "KTransferMemory.h" #include "KProcess.h" namespace skyline::kernel::type { KTransferMemory::KTransferMemory(const DeviceState &state, size_t size) : KMemory(state, KType::KTransferMemory, size) {} u8 *KTransferMemory::Map(span map, memory::Permission permission) { std::memcpy(host.data(), map.data(), map.size()); u8 *result{KMemory::Map(map, permission)}; auto oldChunk{state.process->memory.GetChunk(map.data()).value()}; originalMapping = oldChunk.second; if (!originalMapping.state.transferMemoryAllowed) [[unlikely]] { Logger::Warn("Tried to map transfer memory with incompatible state at: 0x{:X} (0x{:X} bytes)", map.data(), map.size()); return nullptr; } else { state.process->memory.MapTransferMemory(guest, permission); state.process->memory.SetLockOnChunks(guest, true); return result; } } void KTransferMemory::Unmap(span map) { KMemory::Unmap(map); guest = span{}; switch (originalMapping.state.type) { case memory::MemoryType::CodeMutable: state.process->memory.MapMutableCodeMemory(map); break; case memory::MemoryType::Heap: state.process->memory.MapHeapMemory(map); break; default: Logger::Warn("Unmapping KTransferMemory with incompatible state: (0x{:X})", originalMapping.state.value); } std::memcpy(map.data(), host.data(), map.size()); } KTransferMemory::~KTransferMemory() { if (state.process && guest.valid()) { if (mmap(guest.data(), guest.size(), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FIXED | MAP_ANONYMOUS, -1, 0) == MAP_FAILED) [[unlikely]] Logger::Warn("An error occurred while unmapping transfer memory in guest: {}", strerror(errno)); switch (originalMapping.state.type) { case memory::MemoryType::CodeMutable: state.process->memory.MapMutableCodeMemory(guest); break; case memory::MemoryType::Heap: state.process->memory.MapHeapMemory(guest); break; default: Logger::Warn("Unmapping KTransferMemory with incompatible state: (0x{:X})", originalMapping.state.value); } std::memcpy(guest.data(), host.data(), guest.size()); } } }