skyline/app/src/main/cpp/skyline/kernel/types/KTransferMemory.cpp
◱ PixelyIon c005d7df74 Framebuffer and NativeActivity
What was added:
* Framebuffer
* NativeActivity
* NV Services
* IOCTL Handler
* NV Devices:
* * /dev/nvmap - 0xC0080101, 0xC0080103, 0xC0200104, 0xC0180105, 0xC00C0109, 0xC008010E
* * /dev/nvhost-as-gpu
* * /dev/nvhost-channel - 0x40044801, 0xC0104809, 0xC010480B, 0xC018480C, 0x4004480D, 0xC020481A, 0x40084714
* * /dev/nvhost-ctrl
* * /dev/nvhost-ctrl-gpu - 0x80044701, 0x80284702, 0xC0184706, 0xC0B04705, 0x80084714
* SVCs:
* * SetMemoryAttribute
* * CreateTransferMemory
* * ResetSignal
* * GetSystemTick
* Addition of Compact Logger
What was fixed:
* SVCs:
* * SetHeapSize
* * SetMemoryAttribute
* * QueryMemory
* A release build would not set CMAKE_BUILD_TYPE to "RELEASE"
* The logger code was simplified
2019-11-15 19:30:04 +00:00

106 lines
4.8 KiB
C++

#include "KTransferMemory.h"
#include <nce.h>
#include <os.h>
constexpr const char *ASHMEM_NAME_DEF = "dev/ashmem";
constexpr int ASHMEM_SET_SIZE = 0x40087703;
namespace skyline::kernel::type {
u64 MapTransferFunc(u64 address, size_t size, u64 perms) {
return reinterpret_cast<u64>(mmap(reinterpret_cast<void *>(address), size, static_cast<int>(perms), MAP_ANONYMOUS | MAP_PRIVATE | ((address) ? MAP_FIXED : 0), -1, 0)); // NOLINT(hicpp-signed-bitwise)
}
KTransferMemory::KTransferMemory(const DeviceState &state, pid_t pid, u64 address, size_t size, const memory::Permission permission) : owner(pid), cSize(size), permission(permission), KObject(state, KType::KTransferMemory) {
if (pid) {
user_pt_regs fregs = {0};
fregs.regs[0] = address;
fregs.regs[1] = size;
fregs.regs[2] = static_cast<u64 >(permission.Get());
state.nce->ExecuteFunction(reinterpret_cast<void *>(MapTransferFunc), fregs, pid);
if (reinterpret_cast<void *>(fregs.regs[0]) == MAP_FAILED)
throw exception("An error occurred while mapping shared region in child process");
cAddress = fregs.regs[0];
} else {
address = MapTransferFunc(address, size, static_cast<u64>(permission.Get()));
if (reinterpret_cast<void *>(address) == MAP_FAILED)
throw exception("An error occurred while mapping transfer memory in kernel");
cAddress = address;
}
}
u64 UnmapTransferFunc(u64 address, size_t size) {
return static_cast<u64>(munmap(reinterpret_cast<void *>(address), size));
}
u64 KTransferMemory::Transfer(pid_t process, u64 address, u64 size) {
if (process) {
user_pt_regs fregs = {0};
fregs.regs[0] = address;
fregs.regs[1] = size;
fregs.regs[2] = static_cast<u64 >(permission.Get());
state.nce->ExecuteFunction(reinterpret_cast<void *>(MapTransferFunc), fregs, process);
if (reinterpret_cast<void *>(fregs.regs[0]) == MAP_FAILED)
throw exception("An error occurred while mapping transfer memory in child process");
address = fregs.regs[0];
} else {
address = MapTransferFunc(address, size, static_cast<u64>(permission.Get()));
if (reinterpret_cast<void *>(address) == MAP_FAILED)
throw exception("An error occurred while mapping transfer memory in kernel");
}
size_t copySz = std::min(size, cSize);
if (process && owner) {
std::vector<u8> 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<void *>(cAddress), address, copySz);
} else if (!process && owner) {
state.os->processMap.at(owner)->ReadMemory(reinterpret_cast<void *>(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;
fregs.regs[1] = size;
fregs.regs[2] = static_cast<u64 >(permission.Get());
state.nce->ExecuteFunction(reinterpret_cast<void *>(UnmapTransferFunc), fregs, owner);
if (reinterpret_cast<void *>(fregs.regs[0]) == MAP_FAILED)
throw exception("An error occurred while unmapping transfer memory in child process");
} else {
if (reinterpret_cast<void *>(UnmapTransferFunc(address, size)) == MAP_FAILED)
throw exception("An error occurred while unmapping transfer memory in kernel");
}
owner = process;
cAddress = address;
cSize = size;
return address;
}
memory::MemoryInfo KTransferMemory::GetInfo() {
memory::MemoryInfo info{};
info.baseAddress = cAddress;
info.size = cSize;
info.type = static_cast<u64>(memory::Type::TransferMemory);
info.memoryAttribute.isIpcLocked = (info.ipcRefCount > 0);
info.memoryAttribute.isDeviceShared = (info.deviceRefCount > 0);
info.perms = permission;
info.ipcRefCount = ipcRefCount;
info.deviceRefCount = deviceRefCount;
return info;
}
KTransferMemory::~KTransferMemory() {
if (owner) {
try {
user_pt_regs fregs = {0};
fregs.regs[0] = cAddress;
fregs.regs[1] = cSize;
state.nce->ExecuteFunction(reinterpret_cast<void *>(UnmapTransferFunc), fregs, owner);
} catch (const std::exception &) {
}
} else
UnmapTransferFunc(cAddress, cSize);
}
};