2019-09-14 14:41:00 +02:00
|
|
|
#include "KSharedMemory.h"
|
2020-01-01 14:11:25 +01:00
|
|
|
#include "KProcess.h"
|
2020-01-21 08:16:57 +01:00
|
|
|
#include <os.h>
|
2019-11-15 19:14:40 +01:00
|
|
|
#include <android/sharedmem.h>
|
2019-09-14 14:41:00 +02:00
|
|
|
#include <unistd.h>
|
2020-01-07 03:36:08 +01:00
|
|
|
#include <asm/unistd.h>
|
2019-09-14 14:41:00 +02:00
|
|
|
|
2019-09-24 22:54:27 +02:00
|
|
|
namespace skyline::kernel::type {
|
2020-01-21 08:16:57 +01:00
|
|
|
KSharedMemory::KSharedMemory(const DeviceState &state, u64 address, size_t size, const memory::Permission permission, memory::MemoryState memState) : initialState(memState), KMemory(state, KType::KSharedMemory) {
|
2019-11-17 21:19:01 +01:00
|
|
|
fd = ASharedMemory_create("", size);
|
2019-09-24 22:54:27 +02:00
|
|
|
if (fd < 0)
|
2019-11-15 19:14:40 +01:00
|
|
|
throw exception("An error occurred while creating shared memory: {}", fd);
|
2020-01-21 08:16:57 +01:00
|
|
|
address = reinterpret_cast<u64>(mmap(reinterpret_cast<void *>(address), size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_SHARED | ((address) ? MAP_FIXED : 0), fd, 0));
|
2020-01-11 05:52:25 +01:00
|
|
|
if (address == reinterpret_cast<u64>(MAP_FAILED))
|
2020-01-21 08:16:57 +01:00
|
|
|
throw exception("An occurred while mapping shared memory: {}", strerror(errno));
|
|
|
|
kernel = {.address = address, .size = size, .permission = permission};
|
2019-09-14 14:41:00 +02:00
|
|
|
}
|
|
|
|
|
2020-01-21 08:16:57 +01:00
|
|
|
u64 KSharedMemory::Map(const u64 address, const u64 size, memory::Permission permission) {
|
2020-01-07 03:36:08 +01:00
|
|
|
Registers fregs{};
|
|
|
|
fregs.x0 = address;
|
|
|
|
fregs.x1 = size;
|
|
|
|
fregs.x2 = static_cast<u64>(permission.Get());
|
2020-01-11 05:52:25 +01:00
|
|
|
fregs.x3 = static_cast<u64>(MAP_SHARED | ((address) ? MAP_FIXED : 0));
|
2020-01-07 03:36:08 +01:00
|
|
|
fregs.x4 = static_cast<u64>(fd);
|
|
|
|
fregs.x8 = __NR_mmap;
|
2020-01-21 08:16:57 +01:00
|
|
|
state.nce->ExecuteFunction(ThreadCall::Syscall, fregs);
|
2020-01-07 03:36:08 +01:00
|
|
|
if (fregs.x0 < 0)
|
2020-01-21 08:16:57 +01:00
|
|
|
throw exception("An error occurred while mapping shared memory in guest");
|
|
|
|
guest = {.address = fregs.x0, .size = size, .permission = permission};
|
|
|
|
ChunkDescriptor chunk{
|
|
|
|
.address = fregs.x0,
|
|
|
|
.size = size,
|
|
|
|
.state = initialState,
|
|
|
|
};
|
|
|
|
BlockDescriptor block{
|
|
|
|
.address = fregs.x0,
|
|
|
|
.size = size,
|
|
|
|
.permission = permission,
|
|
|
|
};
|
|
|
|
chunk.blockList.push_front(block);
|
|
|
|
state.os->memory.InsertChunk(chunk);
|
2020-01-07 03:36:08 +01:00
|
|
|
return fregs.x0;
|
2019-09-14 14:41:00 +02:00
|
|
|
}
|
|
|
|
|
2020-01-01 14:11:25 +01:00
|
|
|
void KSharedMemory::Resize(size_t size) {
|
|
|
|
if (guest.valid()) {
|
2020-01-07 03:36:08 +01:00
|
|
|
Registers fregs{};
|
|
|
|
fregs.x0 = guest.address;
|
|
|
|
fregs.x1 = guest.size;
|
|
|
|
fregs.x2 = size;
|
2020-01-15 19:58:58 +01:00
|
|
|
fregs.x8 = __NR_mremap;
|
2020-01-21 08:16:57 +01:00
|
|
|
state.nce->ExecuteFunction(ThreadCall::Syscall, fregs);
|
2020-01-07 03:36:08 +01:00
|
|
|
if (fregs.x0 < 0)
|
2020-01-21 08:16:57 +01:00
|
|
|
throw exception("An error occurred while remapping shared memory in guest");
|
2020-01-01 14:11:25 +01:00
|
|
|
guest.size = size;
|
2020-01-21 08:16:57 +01:00
|
|
|
auto chunk = state.os->memory.GetChunk(guest.address);
|
|
|
|
MemoryManager::ResizeChunk(chunk, size);
|
2020-01-01 14:11:25 +01:00
|
|
|
}
|
|
|
|
if (kernel.valid()) {
|
2020-01-07 03:36:08 +01:00
|
|
|
if (mremap(reinterpret_cast<void *>(kernel.address), kernel.size, size, 0) == MAP_FAILED)
|
2020-01-21 08:16:57 +01:00
|
|
|
throw exception("An error occurred while remapping shared region: {}", strerror(errno));
|
2020-01-01 14:11:25 +01:00
|
|
|
kernel.size = size;
|
2019-09-14 14:41:00 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-21 08:16:57 +01:00
|
|
|
void KSharedMemory::UpdatePermission(u64 address, u64 size, memory::Permission permission, bool host) {
|
2020-01-01 14:11:25 +01:00
|
|
|
if (guest.valid() && !host) {
|
2020-01-07 03:36:08 +01:00
|
|
|
Registers fregs{};
|
2020-01-21 08:16:57 +01:00
|
|
|
fregs.x0 = address;
|
|
|
|
fregs.x1 = size;
|
|
|
|
fregs.x2 = static_cast<u64>(permission.Get());
|
2020-01-15 19:58:58 +01:00
|
|
|
fregs.x8 = __NR_mprotect;
|
2020-01-21 08:16:57 +01:00
|
|
|
state.nce->ExecuteFunction(ThreadCall::Syscall, fregs);
|
2020-01-07 03:36:08 +01:00
|
|
|
if (fregs.x0 < 0)
|
2020-01-21 08:16:57 +01:00
|
|
|
throw exception("An error occurred while updating shared memory's permissions in guest");
|
|
|
|
auto chunk = state.os->memory.GetChunk(address);
|
|
|
|
BlockDescriptor block{
|
|
|
|
.address = address,
|
|
|
|
.size = size,
|
|
|
|
.permission = permission,
|
|
|
|
};
|
|
|
|
MemoryManager::InsertBlock(chunk, block);
|
2020-01-01 14:11:25 +01:00
|
|
|
}
|
|
|
|
if (kernel.valid() && host) {
|
2020-01-07 03:36:08 +01:00
|
|
|
if (mprotect(reinterpret_cast<void *>(kernel.address), kernel.size, permission.Get()) == reinterpret_cast<u64>(MAP_FAILED))
|
2020-01-21 08:16:57 +01:00
|
|
|
throw exception("An error occurred while remapping shared memory: {}", strerror(errno));
|
2020-01-01 14:11:25 +01:00
|
|
|
kernel.permission = permission;
|
2019-09-14 14:41:00 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-15 19:58:58 +01:00
|
|
|
KSharedMemory::~KSharedMemory() {
|
|
|
|
try {
|
|
|
|
if (guest.valid() && state.process) {
|
|
|
|
Registers fregs{};
|
|
|
|
fregs.x0 = guest.address;
|
|
|
|
fregs.x1 = guest.size;
|
|
|
|
fregs.x8 = __NR_munmap;
|
2020-01-21 08:16:57 +01:00
|
|
|
state.nce->ExecuteFunction(ThreadCall::Syscall, fregs);
|
2020-01-15 19:58:58 +01:00
|
|
|
}
|
|
|
|
if (kernel.valid())
|
|
|
|
munmap(reinterpret_cast<void *>(kernel.address), kernel.size);
|
|
|
|
} catch (const std::exception &) {
|
|
|
|
}
|
2020-01-21 08:16:57 +01:00
|
|
|
state.os->memory.DeleteChunk(guest.address);
|
2020-01-15 19:58:58 +01:00
|
|
|
close(fd);
|
|
|
|
}
|
2019-09-14 14:41:00 +02:00
|
|
|
};
|