mirror of
https://github.com/skyline-emu/skyline.git
synced 2024-12-23 08:31:48 +01:00
Optimize Memory Implementation using Shared Memory
This commit further improves the memory implementation by using shared memory for all allocations so we won't have to depend on a kernel call for doing any host <-> guest memory transfers.
This commit is contained in:
parent
d02267c34f
commit
03b65bd90a
@ -4,7 +4,7 @@
|
|||||||
namespace skyline::kernel {
|
namespace skyline::kernel {
|
||||||
ChunkDescriptor *MemoryManager::GetChunk(u64 address) {
|
ChunkDescriptor *MemoryManager::GetChunk(u64 address) {
|
||||||
for (auto &chunk : chunkList)
|
for (auto &chunk : chunkList)
|
||||||
if (chunk.address <= address && (chunk.address + chunk.size) >= address)
|
if (chunk.address <= address && (chunk.address + chunk.size) > address)
|
||||||
return &chunk;
|
return &chunk;
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@ -13,7 +13,7 @@ namespace skyline::kernel {
|
|||||||
auto chunk = GetChunk(address);
|
auto chunk = GetChunk(address);
|
||||||
if (chunk)
|
if (chunk)
|
||||||
for (auto &block : chunk->blockList)
|
for (auto &block : chunk->blockList)
|
||||||
if (block.address <= address && (block.address + block.size) >= address)
|
if (block.address <= address && (block.address + block.size) > address)
|
||||||
return █
|
return █
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@ -38,7 +38,7 @@ namespace skyline::kernel {
|
|||||||
|
|
||||||
void MemoryManager::DeleteChunk(u64 address) {
|
void MemoryManager::DeleteChunk(u64 address) {
|
||||||
chunkList.remove_if([address](const ChunkDescriptor &chunk) {
|
chunkList.remove_if([address](const ChunkDescriptor &chunk) {
|
||||||
return chunk.address <= address && (chunk.address + chunk.size) >= address;
|
return chunk.address <= address && (chunk.address + chunk.size) > address;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -70,7 +70,7 @@ namespace skyline::kernel {
|
|||||||
|
|
||||||
void MemoryManager::InsertBlock(ChunkDescriptor *chunk, BlockDescriptor block) {
|
void MemoryManager::InsertBlock(ChunkDescriptor *chunk, BlockDescriptor block) {
|
||||||
for (auto iter = chunk->blockList.begin(); iter != chunk->blockList.end(); iter++) {
|
for (auto iter = chunk->blockList.begin(); iter != chunk->blockList.end(); iter++) {
|
||||||
if (iter->address <= block.address && (iter->address + iter->size) >= block.address) {
|
if (iter->address <= block.address && (iter->address + iter->size) > block.address) {
|
||||||
if (iter->address == block.address && iter->size == block.size) {
|
if (iter->address == block.address && iter->size == block.size) {
|
||||||
iter->attributes = block.attributes;
|
iter->attributes = block.attributes;
|
||||||
iter->permission = block.permission;
|
iter->permission = block.permission;
|
||||||
@ -133,7 +133,7 @@ namespace skyline::kernel {
|
|||||||
auto chunk = GetChunk(address);
|
auto chunk = GetChunk(address);
|
||||||
if (chunk)
|
if (chunk)
|
||||||
for (auto &block : chunk->blockList)
|
for (auto &block : chunk->blockList)
|
||||||
if (block.address <= address && (block.address + block.size) >= address)
|
if (block.address <= address && (block.address + block.size) > address)
|
||||||
return DescriptorPack{block, *chunk};
|
return DescriptorPack{block, *chunk};
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
@ -245,6 +245,7 @@ namespace skyline {
|
|||||||
struct ChunkDescriptor {
|
struct ChunkDescriptor {
|
||||||
u64 address; //!< The address of the current chunk
|
u64 address; //!< The address of the current chunk
|
||||||
u64 size; //!< The size of the current chunk in bytes
|
u64 size; //!< The size of the current chunk in bytes
|
||||||
|
u64 host; //!< The address of the chunk in the host
|
||||||
memory::MemoryState state; //!< The MemoryState for the current block
|
memory::MemoryState state; //!< The MemoryState for the current block
|
||||||
std::forward_list<BlockDescriptor> blockList; //!< This linked list holds the block descriptors for all the children blocks of this Chunk
|
std::forward_list<BlockDescriptor> blockList; //!< This linked list holds the block descriptors for all the children blocks of this Chunk
|
||||||
};
|
};
|
||||||
|
@ -5,8 +5,8 @@ namespace skyline::kernel::svc {
|
|||||||
void SetHeapSize(DeviceState &state) {
|
void SetHeapSize(DeviceState &state) {
|
||||||
const u32 size = state.ctx->registers.w1;
|
const u32 size = state.ctx->registers.w1;
|
||||||
if (size % constant::HeapSizeDiv != 0) {
|
if (size % constant::HeapSizeDiv != 0) {
|
||||||
state.ctx->registers.x1 = 0;
|
|
||||||
state.ctx->registers.w0 = constant::status::InvSize;
|
state.ctx->registers.w0 = constant::status::InvSize;
|
||||||
|
state.ctx->registers.x1 = 0;
|
||||||
state.logger->Warn("svcSetHeapSize: 'size' not divisible by 2MB: {}", size);
|
state.logger->Warn("svcSetHeapSize: 'size' not divisible by 2MB: {}", size);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1,22 +1,32 @@
|
|||||||
#include "KPrivateMemory.h"
|
#include "KPrivateMemory.h"
|
||||||
#include "KProcess.h"
|
#include "KProcess.h"
|
||||||
#include <os.h>
|
#include <os.h>
|
||||||
|
#include <android/sharedmem.h>
|
||||||
#include <asm/unistd.h>
|
#include <asm/unistd.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
namespace skyline::kernel::type {
|
namespace skyline::kernel::type {
|
||||||
KPrivateMemory::KPrivateMemory(const DeviceState &state, u64 address, size_t size, memory::Permission permission, const memory::MemoryState memState) : address(address), size(size), KMemory(state, KType::KPrivateMemory) {
|
KPrivateMemory::KPrivateMemory(const DeviceState &state, u64 address, size_t size, memory::Permission permission, const memory::MemoryState memState) : size(size), KMemory(state, KType::KPrivateMemory) {
|
||||||
Registers fregs{};
|
if (address && !utils::PageAligned(address))
|
||||||
fregs.x0 = address;
|
throw exception("KPrivateMemory was created with non-page-aligned address: 0x{:X}", address);
|
||||||
fregs.x1 = size;
|
fd = ASharedMemory_create("KPrivateMemory", size);
|
||||||
fregs.x2 = static_cast<u64>(permission.Get());
|
if (fd < 0)
|
||||||
fregs.x3 = static_cast<u64>(MAP_PRIVATE | MAP_ANONYMOUS | ((address) ? MAP_FIXED : 0));
|
throw exception("An error occurred while creating shared memory: {}", fd);
|
||||||
fregs.x4 = static_cast<u64>(-1);
|
auto host = mmap(nullptr, size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_SHARED, fd, 0);
|
||||||
fregs.x8 = __NR_mmap;
|
if (host == MAP_FAILED)
|
||||||
|
throw exception("An occurred while mapping shared memory: {}", strerror(errno));
|
||||||
|
Registers fregs{
|
||||||
|
.x0 = address,
|
||||||
|
.x1 = size,
|
||||||
|
.x2 = static_cast<u64>(permission.Get()),
|
||||||
|
.x3 = static_cast<u64>(MAP_SHARED | ((address) ? MAP_FIXED : 0)),
|
||||||
|
.x4 = static_cast<u64>(fd),
|
||||||
|
.x8 = __NR_mmap,
|
||||||
|
};
|
||||||
state.nce->ExecuteFunction(ThreadCall::Syscall, fregs);
|
state.nce->ExecuteFunction(ThreadCall::Syscall, fregs);
|
||||||
if (fregs.x0 < 0)
|
if (fregs.x0 < 0)
|
||||||
throw exception("An error occurred while mapping private section in child process");
|
throw exception("An error occurred while mapping private memory in child process");
|
||||||
if (!this->address)
|
this->address = fregs.x0;
|
||||||
this->address = fregs.x0;
|
|
||||||
BlockDescriptor block{
|
BlockDescriptor block{
|
||||||
.address = fregs.x0,
|
.address = fregs.x0,
|
||||||
.size = size,
|
.size = size,
|
||||||
@ -25,6 +35,7 @@ namespace skyline::kernel::type {
|
|||||||
ChunkDescriptor chunk{
|
ChunkDescriptor chunk{
|
||||||
.address = fregs.x0,
|
.address = fregs.x0,
|
||||||
.size = size,
|
.size = size,
|
||||||
|
.host = reinterpret_cast<u64>(host),
|
||||||
.state = memState,
|
.state = memState,
|
||||||
.blockList = {block},
|
.blockList = {block},
|
||||||
};
|
};
|
||||||
@ -32,33 +43,70 @@ namespace skyline::kernel::type {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void KPrivateMemory::Resize(size_t nSize) {
|
void KPrivateMemory::Resize(size_t nSize) {
|
||||||
Registers fregs{};
|
if (close(fd) < 0)
|
||||||
fregs.x0 = address;
|
throw exception("An error occurred while trying to close shared memory FD: {}", strerror(errno));
|
||||||
fregs.x1 = size;
|
fd = ASharedMemory_create("KPrivateMemory", nSize);
|
||||||
fregs.x2 = nSize;
|
if (fd < 0)
|
||||||
fregs.x8 = __NR_mremap;
|
throw exception("An error occurred while creating shared memory: {}", fd);
|
||||||
|
Registers fregs{
|
||||||
|
.x0 = address,
|
||||||
|
.x1 = size,
|
||||||
|
.x8 = __NR_munmap
|
||||||
|
};
|
||||||
state.nce->ExecuteFunction(ThreadCall::Syscall, fregs);
|
state.nce->ExecuteFunction(ThreadCall::Syscall, fregs);
|
||||||
if (fregs.x0 < 0)
|
if (fregs.x0 < 0)
|
||||||
throw exception("An error occurred while remapping private section in child process");
|
throw exception("An error occurred while unmapping private memory in child process");
|
||||||
size = nSize;
|
fregs = {
|
||||||
|
.x0 = address,
|
||||||
|
.x1 = nSize,
|
||||||
|
.x2 = static_cast<u64>(PROT_READ | PROT_WRITE | PROT_EXEC),
|
||||||
|
.x3 = static_cast<u64>(MAP_SHARED | MAP_FIXED),
|
||||||
|
.x4 = static_cast<u64>(fd),
|
||||||
|
.x8 = __NR_mmap,
|
||||||
|
};
|
||||||
|
state.nce->ExecuteFunction(ThreadCall::Syscall, fregs);
|
||||||
|
if (fregs.x0 < 0)
|
||||||
|
throw exception("An error occurred while remapping private memory in child process");
|
||||||
auto chunk = state.os->memory.GetChunk(address);
|
auto chunk = state.os->memory.GetChunk(address);
|
||||||
MemoryManager::ResizeChunk(chunk, size);
|
state.process->WriteMemory(reinterpret_cast<void *>(chunk->host), address, std::min(nSize, size), true);
|
||||||
|
for (const auto &block : chunk->blockList) {
|
||||||
|
if((block.address - chunk->address) < size) {
|
||||||
|
fregs = {
|
||||||
|
.x0 = block.address,
|
||||||
|
.x1 = std::min(block.size, (chunk->address + nSize) - block.address),
|
||||||
|
.x2 = static_cast<u64>(block.permission.Get()),
|
||||||
|
.x8 = __NR_mprotect,
|
||||||
|
};
|
||||||
|
state.nce->ExecuteFunction(ThreadCall::Syscall, fregs);
|
||||||
|
if (fregs.x0 < 0)
|
||||||
|
throw exception("An error occurred while updating private memory's permissions in child process");
|
||||||
|
} else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
munmap(reinterpret_cast<void *>(chunk->host), size);
|
||||||
|
auto host = mmap(reinterpret_cast<void *>(chunk->host), nSize, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_SHARED, fd, 0);
|
||||||
|
if (host == MAP_FAILED)
|
||||||
|
throw exception("An occurred while mapping shared memory: {}", strerror(errno));
|
||||||
|
chunk->host = reinterpret_cast<u64>(host);
|
||||||
|
MemoryManager::ResizeChunk(chunk, nSize);
|
||||||
|
size = nSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
void KPrivateMemory::UpdatePermission(const u64 address, const u64 size, memory::Permission permission) {
|
void KPrivateMemory::UpdatePermission(const u64 address, const u64 size, memory::Permission permission) {
|
||||||
Registers fregs{};
|
Registers fregs{
|
||||||
fregs.x0 = address;
|
.x0 = address,
|
||||||
fregs.x1 = size;
|
.x1 = size,
|
||||||
fregs.x2 = static_cast<u64>(permission.Get());
|
.x2 = static_cast<u64>(permission.Get()),
|
||||||
fregs.x8 = __NR_mprotect;
|
.x8 = __NR_mprotect,
|
||||||
|
};
|
||||||
state.nce->ExecuteFunction(ThreadCall::Syscall, fregs);
|
state.nce->ExecuteFunction(ThreadCall::Syscall, fregs);
|
||||||
if (fregs.x0 < 0)
|
if (fregs.x0 < 0)
|
||||||
throw exception("An error occurred while updating private section's permissions in child process");
|
throw exception("An error occurred while updating private memory's permissions in child process");
|
||||||
auto chunk = state.os->memory.GetChunk(address);
|
auto chunk = state.os->memory.GetChunk(address);
|
||||||
BlockDescriptor block{
|
BlockDescriptor block{
|
||||||
.address = address,
|
.address = address,
|
||||||
.size = size,
|
.size = size,
|
||||||
.permission = permission,
|
.permission = permission,
|
||||||
};
|
};
|
||||||
MemoryManager::InsertBlock(chunk, block);
|
MemoryManager::InsertBlock(chunk, block);
|
||||||
}
|
}
|
||||||
@ -66,14 +114,17 @@ namespace skyline::kernel::type {
|
|||||||
KPrivateMemory::~KPrivateMemory() {
|
KPrivateMemory::~KPrivateMemory() {
|
||||||
try {
|
try {
|
||||||
if (state.process) {
|
if (state.process) {
|
||||||
Registers fregs{};
|
Registers fregs{
|
||||||
fregs.x0 = address;
|
.x0 = address,
|
||||||
fregs.x1 = size;
|
.x1 = size,
|
||||||
fregs.x8 = __NR_munmap;
|
.x8 = __NR_munmap,
|
||||||
|
};
|
||||||
state.nce->ExecuteFunction(ThreadCall::Syscall, fregs);
|
state.nce->ExecuteFunction(ThreadCall::Syscall, fregs);
|
||||||
}
|
}
|
||||||
} catch (const std::exception &) {
|
} catch (const std::exception &) {
|
||||||
}
|
}
|
||||||
|
auto chunk = state.os->memory.GetChunk(address);
|
||||||
|
munmap(reinterpret_cast<void *>(chunk->host), chunk->size);
|
||||||
state.os->memory.DeleteChunk(address);
|
state.os->memory.DeleteChunk(address);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -7,6 +7,9 @@ namespace skyline::kernel::type {
|
|||||||
* @brief KPrivateMemory is used to map memory local to the guest process
|
* @brief KPrivateMemory is used to map memory local to the guest process
|
||||||
*/
|
*/
|
||||||
class KPrivateMemory : public KMemory {
|
class KPrivateMemory : public KMemory {
|
||||||
|
private:
|
||||||
|
int fd; //!< A file descriptor to the underlying shared memory
|
||||||
|
|
||||||
public:
|
public:
|
||||||
u64 address{}; //!< The address of the allocated memory
|
u64 address{}; //!< The address of the allocated memory
|
||||||
size_t size{}; //!< The size of the allocated memory
|
size_t size{}; //!< The size of the allocated memory
|
||||||
|
@ -83,45 +83,68 @@ namespace skyline::kernel::type {
|
|||||||
return process;
|
return process;
|
||||||
}
|
}
|
||||||
|
|
||||||
void KProcess::ReadMemory(void *destination, u64 offset, size_t size) const {
|
u64 KProcess::GetHostAddress(u64 address) const {
|
||||||
|
auto chunk = state.os->memory.GetChunk(address);
|
||||||
|
return (chunk && chunk->host) ? chunk->host + (address - chunk->address) : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void KProcess::ReadMemory(void *destination, const u64 offset, const size_t size, const bool forceGuest) const {
|
||||||
|
if (!forceGuest) {
|
||||||
|
auto source = GetHostAddress(offset);
|
||||||
|
if (source) {
|
||||||
|
memcpy(destination, reinterpret_cast<void *>(source), size);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
struct iovec local{
|
struct iovec local{
|
||||||
.iov_base = destination,
|
.iov_base = destination,
|
||||||
.iov_len = size
|
.iov_len = size,
|
||||||
};
|
};
|
||||||
struct iovec remote{
|
struct iovec remote{
|
||||||
.iov_base = reinterpret_cast<void *>(offset),
|
.iov_base = reinterpret_cast<void *>(offset),
|
||||||
.iov_len = size
|
.iov_len = size,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (process_vm_readv(pid, &local, 1, &remote, 1, 0) < 0)
|
if (process_vm_readv(pid, &local, 1, &remote, 1, 0) < 0)
|
||||||
pread64(memFd, destination, size, offset);
|
pread64(memFd, destination, size, offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
void KProcess::WriteMemory(void *source, u64 offset, size_t size) const {
|
void KProcess::WriteMemory(void *source, const u64 offset, const size_t size, const bool forceGuest) const {
|
||||||
|
if(!forceGuest) {
|
||||||
|
auto destination = GetHostAddress(offset);
|
||||||
|
if (destination) {
|
||||||
|
memcpy(reinterpret_cast<void *>(destination), source, size);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
struct iovec local{
|
struct iovec local{
|
||||||
.iov_base = source,
|
.iov_base = source,
|
||||||
.iov_len = size
|
.iov_len = size,
|
||||||
};
|
};
|
||||||
struct iovec remote{
|
struct iovec remote{
|
||||||
.iov_base = reinterpret_cast<void *>(offset),
|
.iov_base = reinterpret_cast<void *>(offset),
|
||||||
.iov_len = size
|
.iov_len = size,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (process_vm_writev(pid, &local, 1, &remote, 1, 0) < 0)
|
if (process_vm_writev(pid, &local, 1, &remote, 1, 0) < 0)
|
||||||
pwrite64(memFd, source, size, offset);
|
pwrite64(memFd, source, size, offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
void KProcess::CopyMemory(u64 source, u64 destination, size_t size) const {
|
void KProcess::CopyMemory(u64 source, u64 destination, size_t size) const {
|
||||||
if (size <= PAGE_SIZE) {
|
auto sourceHost = GetHostAddress(source);
|
||||||
std::vector<u8> buffer(size);
|
auto destinationHost = GetHostAddress(destination);
|
||||||
state.process->ReadMemory(buffer.data(), source, size);
|
if(sourceHost && destinationHost) {
|
||||||
state.process->WriteMemory(buffer.data(), destination, size);
|
memcpy(reinterpret_cast<void *>(destinationHost), reinterpret_cast<const void *>(sourceHost), size);
|
||||||
} else {
|
} else {
|
||||||
Registers fregs{};
|
if (size <= PAGE_SIZE) {
|
||||||
fregs.x0 = source;
|
std::vector<u8> buffer(size);
|
||||||
fregs.x1 = destination;
|
state.process->ReadMemory(buffer.data(), source, size);
|
||||||
fregs.x2 = size;
|
state.process->WriteMemory(buffer.data(), destination, size);
|
||||||
state.nce->ExecuteFunction(ThreadCall::Memcopy, fregs);
|
} else {
|
||||||
|
Registers fregs{};
|
||||||
|
fregs.x0 = source;
|
||||||
|
fregs.x1 = destination;
|
||||||
|
fregs.x2 = size;
|
||||||
|
state.nce->ExecuteFunction(ThreadCall::Memcopy, fregs);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -145,8 +168,8 @@ namespace skyline::kernel::type {
|
|||||||
void KProcess::MutexLock(u64 address, handle_t owner, bool alwaysLock) {
|
void KProcess::MutexLock(u64 address, handle_t owner, bool alwaysLock) {
|
||||||
std::unique_lock lock(mutexLock);
|
std::unique_lock lock(mutexLock);
|
||||||
u32 mtxVal = ReadMemory<u32>(address);
|
u32 mtxVal = ReadMemory<u32>(address);
|
||||||
if(alwaysLock) {
|
if (alwaysLock) {
|
||||||
if(!mtxVal) {
|
if (!mtxVal) {
|
||||||
state.logger->Warn("Mutex Value was 0");
|
state.logger->Warn("Mutex Value was 0");
|
||||||
mtxVal = (constant::MtxOwnerMask & state.thread->handle);
|
mtxVal = (constant::MtxOwnerMask & state.thread->handle);
|
||||||
WriteMemory<u32>(mtxVal, address);
|
WriteMemory<u32>(mtxVal, address);
|
||||||
@ -159,7 +182,7 @@ namespace skyline::kernel::type {
|
|||||||
}
|
}
|
||||||
auto &mtxWaiters = mutexes[address];
|
auto &mtxWaiters = mutexes[address];
|
||||||
std::shared_ptr<WaitStatus> status;
|
std::shared_ptr<WaitStatus> status;
|
||||||
for (auto it = mtxWaiters.begin();;++it) {
|
for (auto it = mtxWaiters.begin();; ++it) {
|
||||||
if (it != mtxWaiters.end() && (*it)->priority >= state.thread->priority)
|
if (it != mtxWaiters.end() && (*it)->priority >= state.thread->priority)
|
||||||
continue;
|
continue;
|
||||||
status = std::make_shared<WaitStatus>(state.thread->priority, state.thread->pid);
|
status = std::make_shared<WaitStatus>(state.thread->priority, state.thread->pid);
|
||||||
@ -170,7 +193,7 @@ namespace skyline::kernel::type {
|
|||||||
while (!status->flag);
|
while (!status->flag);
|
||||||
lock.lock();
|
lock.lock();
|
||||||
for (auto it = mtxWaiters.begin(); it != mtxWaiters.end(); ++it)
|
for (auto it = mtxWaiters.begin(); it != mtxWaiters.end(); ++it)
|
||||||
if((*it)->pid == state.thread->pid) {
|
if ((*it)->pid == state.thread->pid) {
|
||||||
mtxWaiters.erase(it);
|
mtxWaiters.erase(it);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -197,7 +220,7 @@ namespace skyline::kernel::type {
|
|||||||
std::unique_lock lock(conditionalLock);
|
std::unique_lock lock(conditionalLock);
|
||||||
auto &condWaiters = conditionals[address];
|
auto &condWaiters = conditionals[address];
|
||||||
std::shared_ptr<WaitStatus> status;
|
std::shared_ptr<WaitStatus> status;
|
||||||
for (auto it = condWaiters.begin();;++it) {
|
for (auto it = condWaiters.begin();; ++it) {
|
||||||
if (it != condWaiters.end() && (*it)->priority >= state.thread->priority)
|
if (it != condWaiters.end() && (*it)->priority >= state.thread->priority)
|
||||||
continue;
|
continue;
|
||||||
status = std::make_shared<WaitStatus>(state.thread->priority, state.thread->pid);
|
status = std::make_shared<WaitStatus>(state.thread->priority, state.thread->pid);
|
||||||
@ -213,7 +236,7 @@ namespace skyline::kernel::type {
|
|||||||
}
|
}
|
||||||
lock.lock();
|
lock.lock();
|
||||||
for (auto it = condWaiters.begin(); it != condWaiters.end(); ++it)
|
for (auto it = condWaiters.begin(); it != condWaiters.end(); ++it)
|
||||||
if((*it)->pid == state.thread->pid) {
|
if ((*it)->pid == state.thread->pid) {
|
||||||
condWaiters.erase(it);
|
condWaiters.erase(it);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -169,21 +169,41 @@ namespace skyline::kernel::type {
|
|||||||
WriteMemory(&item, address, sizeof(Type));
|
WriteMemory(&item, address, sizeof(Type));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief This returns the host address for a specific address in guest memory
|
||||||
|
* @param address The corresponding guest address
|
||||||
|
* @return The corresponding host address
|
||||||
|
*/
|
||||||
|
u64 GetHostAddress(const u64 address) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @tparam Type The type of the pointer to return
|
||||||
|
* @param address The address on the guest
|
||||||
|
* @return A pointer corresponding to a certain address on the guest
|
||||||
|
* @note This can return a nullptr if the address is invalid
|
||||||
|
*/
|
||||||
|
template<typename Type>
|
||||||
|
inline Type* GetPointer(const u64 address) const {
|
||||||
|
return reinterpret_cast<Type*>(GetHostAddress(address));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Read data from the process's memory
|
* @brief Read data from the process's memory
|
||||||
* @param destination The address to the location where the process memory is written
|
* @param destination The address to the location where the process memory is written
|
||||||
* @param offset The address to read from in process memory
|
* @param offset The address to read from in process memory
|
||||||
* @param size The amount of memory to be read
|
* @param size The amount of memory to be read
|
||||||
|
* @param forceGuest This flag forces the write to be performed in guest address space
|
||||||
*/
|
*/
|
||||||
void ReadMemory(void *destination, u64 offset, size_t size) const;
|
void ReadMemory(void *destination, const u64 offset, const size_t size, const bool forceGuest = false) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Write to the process's memory
|
* @brief Write to the process's memory
|
||||||
* @param source The address of where the data to be written is present
|
* @param source The address of where the data to be written is present
|
||||||
* @param offset The address to write to in process memory
|
* @param offset The address to write to in process memory
|
||||||
* @param size The amount of memory to be written
|
* @param size The amount of memory to be written
|
||||||
|
* @param forceGuest This flag forces the write to be performed in guest address space
|
||||||
*/
|
*/
|
||||||
void WriteMemory(void *source, u64 offset, size_t size) const;
|
void WriteMemory(void *source, const u64 offset, const size_t size, const bool forceGuest = false) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Copy one chunk to another in the process's memory
|
* @brief Copy one chunk to another in the process's memory
|
||||||
@ -191,7 +211,7 @@ namespace skyline::kernel::type {
|
|||||||
* @param destination The address to write the read data to
|
* @param destination The address to write the read data to
|
||||||
* @param size The amount of memory to be copied
|
* @param size The amount of memory to be copied
|
||||||
*/
|
*/
|
||||||
void CopyMemory(u64 source, u64 destination, size_t size) const;
|
void CopyMemory(const u64 source, const u64 destination, const size_t size) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Creates a new handle to a KObject and adds it to the process handle_table
|
* @brief Creates a new handle to a KObject and adds it to the process handle_table
|
||||||
|
@ -7,7 +7,9 @@
|
|||||||
|
|
||||||
namespace skyline::kernel::type {
|
namespace skyline::kernel::type {
|
||||||
KSharedMemory::KSharedMemory(const DeviceState &state, u64 address, size_t size, const memory::Permission permission, memory::MemoryState memState) : initialState(memState), KMemory(state, KType::KSharedMemory) {
|
KSharedMemory::KSharedMemory(const DeviceState &state, u64 address, size_t size, const memory::Permission permission, memory::MemoryState memState) : initialState(memState), KMemory(state, KType::KSharedMemory) {
|
||||||
fd = ASharedMemory_create("", size);
|
if (address && !utils::PageAligned(address))
|
||||||
|
throw exception("KSharedMemory was created with non-page-aligned address: 0x{:X}", address);
|
||||||
|
fd = ASharedMemory_create("KSharedMemory", size);
|
||||||
if (fd < 0)
|
if (fd < 0)
|
||||||
throw exception("An error occurred while creating shared memory: {}", fd);
|
throw exception("An error occurred while creating shared memory: {}", fd);
|
||||||
address = reinterpret_cast<u64>(mmap(reinterpret_cast<void *>(address), size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_SHARED | ((address) ? MAP_FIXED : 0), fd, 0));
|
address = reinterpret_cast<u64>(mmap(reinterpret_cast<void *>(address), size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_SHARED | ((address) ? MAP_FIXED : 0), fd, 0));
|
||||||
@ -17,19 +19,23 @@ namespace skyline::kernel::type {
|
|||||||
}
|
}
|
||||||
|
|
||||||
u64 KSharedMemory::Map(const u64 address, const u64 size, memory::Permission permission) {
|
u64 KSharedMemory::Map(const u64 address, const u64 size, memory::Permission permission) {
|
||||||
Registers fregs{};
|
if (address && !utils::PageAligned(address))
|
||||||
fregs.x0 = address;
|
throw exception("KSharedMemory was mapped to a non-page-aligned address: 0x{:X}", address);
|
||||||
fregs.x1 = size;
|
Registers fregs{
|
||||||
fregs.x2 = static_cast<u64>(permission.Get());
|
.x0 = address,
|
||||||
fregs.x3 = static_cast<u64>(MAP_SHARED | ((address) ? MAP_FIXED : 0));
|
.x1 = size,
|
||||||
fregs.x4 = static_cast<u64>(fd);
|
.x2 = static_cast<u64>(permission.Get()),
|
||||||
fregs.x8 = __NR_mmap;
|
.x3 = static_cast<u64>(MAP_SHARED | ((address) ? MAP_FIXED : 0)),
|
||||||
|
.x4 = static_cast<u64>(fd),
|
||||||
|
.x8 = __NR_mmap,
|
||||||
|
};
|
||||||
state.nce->ExecuteFunction(ThreadCall::Syscall, fregs);
|
state.nce->ExecuteFunction(ThreadCall::Syscall, fregs);
|
||||||
if (fregs.x0 < 0)
|
if (fregs.x0 < 0)
|
||||||
throw exception("An error occurred while mapping shared memory in guest");
|
throw exception("An error occurred while mapping shared memory in guest");
|
||||||
guest = {.address = fregs.x0, .size = size, .permission = permission};
|
guest = {.address = fregs.x0, .size = size, .permission = permission};
|
||||||
ChunkDescriptor chunk{
|
ChunkDescriptor chunk{
|
||||||
.address = fregs.x0,
|
.address = fregs.x0,
|
||||||
|
.host = kernel.address,
|
||||||
.size = size,
|
.size = size,
|
||||||
.state = initialState,
|
.state = initialState,
|
||||||
};
|
};
|
||||||
@ -44,33 +50,81 @@ namespace skyline::kernel::type {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void KSharedMemory::Resize(size_t size) {
|
void KSharedMemory::Resize(size_t size) {
|
||||||
if (guest.valid()) {
|
if (guest.valid() && kernel.valid()) {
|
||||||
Registers fregs{};
|
if (close(fd) < 0)
|
||||||
fregs.x0 = guest.address;
|
throw exception("An error occurred while trying to close shared memory FD: {}", strerror(errno));
|
||||||
fregs.x1 = guest.size;
|
fd = ASharedMemory_create("KSharedMemory", size);
|
||||||
fregs.x2 = size;
|
if (fd < 0)
|
||||||
fregs.x8 = __NR_mremap;
|
throw exception("An error occurred while creating shared memory: {}", fd);
|
||||||
|
Registers fregs{
|
||||||
|
.x0 = guest.address,
|
||||||
|
.x1 = guest.size,
|
||||||
|
.x8 = __NR_munmap
|
||||||
|
};
|
||||||
state.nce->ExecuteFunction(ThreadCall::Syscall, fregs);
|
state.nce->ExecuteFunction(ThreadCall::Syscall, fregs);
|
||||||
if (fregs.x0 < 0)
|
if (fregs.x0 < 0)
|
||||||
throw exception("An error occurred while remapping shared memory in guest");
|
throw exception("An error occurred while unmapping private memory in child process");
|
||||||
guest.size = size;
|
fregs = {
|
||||||
|
.x0 = guest.address,
|
||||||
|
.x1 = size,
|
||||||
|
.x2 = static_cast<u64>(PROT_READ | PROT_WRITE | PROT_EXEC),
|
||||||
|
.x3 = static_cast<u64>(MAP_SHARED | MAP_FIXED),
|
||||||
|
.x4 = static_cast<u64>(fd),
|
||||||
|
.x8 = __NR_mmap,
|
||||||
|
};
|
||||||
|
state.nce->ExecuteFunction(ThreadCall::Syscall, fregs);
|
||||||
|
if (fregs.x0 < 0)
|
||||||
|
throw exception("An error occurred while remapping private memory in child process");
|
||||||
|
state.process->WriteMemory(reinterpret_cast<void *>(kernel.address), guest.address, std::min(guest.size, size), true);
|
||||||
auto chunk = state.os->memory.GetChunk(guest.address);
|
auto chunk = state.os->memory.GetChunk(guest.address);
|
||||||
|
for (const auto &block : chunk->blockList) {
|
||||||
|
if((block.address - chunk->address) < guest.size) {
|
||||||
|
fregs = {
|
||||||
|
.x0 = block.address,
|
||||||
|
.x1 = std::min(block.size, (chunk->address + size) - block.address),
|
||||||
|
.x2 = static_cast<u64>(block.permission.Get()),
|
||||||
|
.x8 = __NR_mprotect,
|
||||||
|
};
|
||||||
|
state.nce->ExecuteFunction(ThreadCall::Syscall, fregs);
|
||||||
|
if (fregs.x0 < 0)
|
||||||
|
throw exception("An error occurred while updating private memory's permissions in child process");
|
||||||
|
} else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
munmap(reinterpret_cast<void *>(kernel.address), kernel.size);
|
||||||
|
auto host = mmap(reinterpret_cast<void *>(chunk->host), size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_SHARED, fd, 0);
|
||||||
|
if (host == MAP_FAILED)
|
||||||
|
throw exception("An occurred while mapping shared memory: {}", strerror(errno));
|
||||||
|
guest.size = size;
|
||||||
MemoryManager::ResizeChunk(chunk, size);
|
MemoryManager::ResizeChunk(chunk, size);
|
||||||
}
|
} else if (kernel.valid()) {
|
||||||
if (kernel.valid()) {
|
if (close(fd) < 0)
|
||||||
if (mremap(reinterpret_cast<void *>(kernel.address), kernel.size, size, 0) == MAP_FAILED)
|
throw exception("An error occurred while trying to close shared memory FD: {}", strerror(errno));
|
||||||
throw exception("An error occurred while remapping shared region: {}", strerror(errno));
|
fd = ASharedMemory_create("KSharedMemory", size);
|
||||||
|
if (fd < 0)
|
||||||
|
throw exception("An error occurred while creating shared memory: {}", fd);
|
||||||
|
std::vector<u8> data(std::min(size, kernel.size));
|
||||||
|
memcpy(data.data(), reinterpret_cast<const void *>(kernel.address), std::min(size, kernel.size));
|
||||||
|
munmap(reinterpret_cast<void *>(kernel.address), kernel.size);
|
||||||
|
auto address = mmap(reinterpret_cast<void *>(kernel.address), size, kernel.permission.Get(), MAP_SHARED, fd, 0);
|
||||||
|
if (address == MAP_FAILED)
|
||||||
|
throw exception("An occurred while mapping shared memory: {}", strerror(errno));
|
||||||
|
memcpy(address, data.data(), std::min(size, kernel.size));
|
||||||
|
kernel.address = reinterpret_cast<u64>(address);
|
||||||
kernel.size = size;
|
kernel.size = size;
|
||||||
|
} else {
|
||||||
|
throw exception("Cannot resize KSharedMemory that's only on guest");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void KSharedMemory::UpdatePermission(u64 address, u64 size, memory::Permission permission, bool host) {
|
void KSharedMemory::UpdatePermission(u64 address, u64 size, memory::Permission permission, bool host) {
|
||||||
if (guest.valid() && !host) {
|
if (guest.valid() && !host) {
|
||||||
Registers fregs{};
|
Registers fregs{
|
||||||
fregs.x0 = address;
|
.x0 = address,
|
||||||
fregs.x1 = size;
|
.x1 = size,
|
||||||
fregs.x2 = static_cast<u64>(permission.Get());
|
.x2 = static_cast<u64>(permission.Get()),
|
||||||
fregs.x8 = __NR_mprotect;
|
.x8 = __NR_mprotect,
|
||||||
|
};
|
||||||
state.nce->ExecuteFunction(ThreadCall::Syscall, fregs);
|
state.nce->ExecuteFunction(ThreadCall::Syscall, fregs);
|
||||||
if (fregs.x0 < 0)
|
if (fregs.x0 < 0)
|
||||||
throw exception("An error occurred while updating shared memory's permissions in guest");
|
throw exception("An error occurred while updating shared memory's permissions in guest");
|
||||||
@ -92,16 +146,17 @@ namespace skyline::kernel::type {
|
|||||||
KSharedMemory::~KSharedMemory() {
|
KSharedMemory::~KSharedMemory() {
|
||||||
try {
|
try {
|
||||||
if (guest.valid() && state.process) {
|
if (guest.valid() && state.process) {
|
||||||
Registers fregs{};
|
Registers fregs{
|
||||||
fregs.x0 = guest.address;
|
.x0 = guest.address,
|
||||||
fregs.x1 = guest.size;
|
.x1 = guest.size,
|
||||||
fregs.x8 = __NR_munmap;
|
.x8 = __NR_munmap,
|
||||||
|
};
|
||||||
state.nce->ExecuteFunction(ThreadCall::Syscall, fregs);
|
state.nce->ExecuteFunction(ThreadCall::Syscall, fregs);
|
||||||
}
|
}
|
||||||
if (kernel.valid())
|
|
||||||
munmap(reinterpret_cast<void *>(kernel.address), kernel.size);
|
|
||||||
} catch (const std::exception &) {
|
} catch (const std::exception &) {
|
||||||
}
|
}
|
||||||
|
if (kernel.valid())
|
||||||
|
munmap(reinterpret_cast<void *>(kernel.address), kernel.size);
|
||||||
state.os->memory.DeleteChunk(guest.address);
|
state.os->memory.DeleteChunk(guest.address);
|
||||||
close(fd);
|
close(fd);
|
||||||
}
|
}
|
||||||
|
@ -70,7 +70,6 @@ namespace skyline::kernel::type {
|
|||||||
UpdatePermission(address, size, permission, false);
|
UpdatePermission(address, size, permission, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Updates the permissions of a chunk of mapped memory
|
* @brief Updates the permissions of a chunk of mapped memory
|
||||||
* @param permission The new permissions to be set for the memory
|
* @param permission The new permissions to be set for the memory
|
||||||
|
@ -5,6 +5,8 @@
|
|||||||
|
|
||||||
namespace skyline::kernel::type {
|
namespace skyline::kernel::type {
|
||||||
KTransferMemory::KTransferMemory(const DeviceState &state, bool host, u64 address, size_t size, const memory::Permission permission, memory::MemoryState memState) : host(host), size(size), KMemory(state, KType::KTransferMemory) {
|
KTransferMemory::KTransferMemory(const DeviceState &state, bool host, u64 address, size_t size, const memory::Permission permission, memory::MemoryState memState) : host(host), size(size), KMemory(state, KType::KTransferMemory) {
|
||||||
|
if (address && !utils::PageAligned(address))
|
||||||
|
throw exception("KTransferMemory was created with non-page-aligned address: 0x{:X}", address);
|
||||||
BlockDescriptor block{
|
BlockDescriptor block{
|
||||||
.size = size,
|
.size = size,
|
||||||
.permission = permission,
|
.permission = permission,
|
||||||
@ -23,13 +25,14 @@ namespace skyline::kernel::type {
|
|||||||
chunk.blockList.front().address = address;
|
chunk.blockList.front().address = address;
|
||||||
hostChunk = chunk;
|
hostChunk = chunk;
|
||||||
} else {
|
} else {
|
||||||
Registers fregs{};
|
Registers fregs{
|
||||||
fregs.x0 = address;
|
.x0 = address,
|
||||||
fregs.x1 = size;
|
.x1 = size,
|
||||||
fregs.x2 = static_cast<u64 >(permission.Get());
|
.x2 = static_cast<u64 >(permission.Get()),
|
||||||
fregs.x3 = static_cast<u64>(MAP_ANONYMOUS | MAP_PRIVATE | ((address) ? MAP_FIXED : 0));
|
.x3 = static_cast<u64>(MAP_ANONYMOUS | MAP_PRIVATE | ((address) ? MAP_FIXED : 0)),
|
||||||
fregs.x4 = static_cast<u64>(-1);
|
.x4 = static_cast<u64>(-1),
|
||||||
fregs.x8 = __NR_mmap;
|
.x8 = __NR_mmap,
|
||||||
|
};
|
||||||
state.nce->ExecuteFunction(ThreadCall::Syscall, fregs);
|
state.nce->ExecuteFunction(ThreadCall::Syscall, fregs);
|
||||||
if (fregs.x0 < 0)
|
if (fregs.x0 < 0)
|
||||||
throw exception("An error occurred while mapping shared region in child process");
|
throw exception("An error occurred while mapping shared region in child process");
|
||||||
@ -41,6 +44,8 @@ namespace skyline::kernel::type {
|
|||||||
}
|
}
|
||||||
|
|
||||||
u64 KTransferMemory::Transfer(bool mHost, u64 nAddress, u64 nSize) {
|
u64 KTransferMemory::Transfer(bool mHost, u64 nAddress, u64 nSize) {
|
||||||
|
if (nAddress && !utils::PageAligned(nAddress))
|
||||||
|
throw exception("KTransferMemory was transferred to a non-page-aligned address: 0x{:X}", nAddress);
|
||||||
nSize = nSize ? nSize : size;
|
nSize = nSize ? nSize : size;
|
||||||
ChunkDescriptor chunk = host ? hostChunk : *state.os->memory.GetChunk(address);
|
ChunkDescriptor chunk = host ? hostChunk : *state.os->memory.GetChunk(address);
|
||||||
chunk.address = nAddress;
|
chunk.address = nAddress;
|
||||||
@ -49,13 +54,14 @@ namespace skyline::kernel::type {
|
|||||||
for (auto &block : chunk.blockList) {
|
for (auto &block : chunk.blockList) {
|
||||||
block.address = nAddress + (block.address - address);
|
block.address = nAddress + (block.address - address);
|
||||||
if ((mHost && !host) || (!mHost && !host)) {
|
if ((mHost && !host) || (!mHost && !host)) {
|
||||||
Registers fregs{};
|
Registers fregs{
|
||||||
fregs.x0 = block.address;
|
.x0 = block.address,
|
||||||
fregs.x1 = block.size;
|
.x1 = block.size,
|
||||||
fregs.x2 = (block.permission.w) ? static_cast<u64>(block.permission.Get()) : (PROT_READ | PROT_WRITE);
|
.x2 = (block.permission.w) ? static_cast<u64>(block.permission.Get()) : (PROT_READ | PROT_WRITE),
|
||||||
fregs.x3 = static_cast<u64>(MAP_ANONYMOUS | MAP_PRIVATE | ((nAddress) ? MAP_FIXED : 0));
|
.x3 = static_cast<u64>(MAP_ANONYMOUS | MAP_PRIVATE | ((nAddress) ? MAP_FIXED : 0)),
|
||||||
fregs.x4 = static_cast<u64>(-1);
|
.x4 = static_cast<u64>(-1),
|
||||||
fregs.x8 = __NR_mmap;
|
.x8 = __NR_mmap,
|
||||||
|
};
|
||||||
state.nce->ExecuteFunction(ThreadCall::Syscall, fregs);
|
state.nce->ExecuteFunction(ThreadCall::Syscall, fregs);
|
||||||
if (fregs.x0 < 0)
|
if (fregs.x0 < 0)
|
||||||
throw exception("An error occurred while mapping transfer memory in child process");
|
throw exception("An error occurred while mapping transfer memory in child process");
|
||||||
@ -80,11 +86,12 @@ namespace skyline::kernel::type {
|
|||||||
if (mprotect(reinterpret_cast<void *>(block.address), block.size, block.permission.Get()) == reinterpret_cast<u64>(MAP_FAILED))
|
if (mprotect(reinterpret_cast<void *>(block.address), block.size, block.permission.Get()) == reinterpret_cast<u64>(MAP_FAILED))
|
||||||
throw exception("An error occurred while remapping transfer memory: {}", strerror(errno));
|
throw exception("An error occurred while remapping transfer memory: {}", strerror(errno));
|
||||||
} else {
|
} else {
|
||||||
Registers fregs{};
|
Registers fregs{
|
||||||
fregs.x0 = block.address;
|
.x0 = block.address,
|
||||||
fregs.x1 = block.size;
|
.x1 = block.size,
|
||||||
fregs.x2 = static_cast<u64>(block.permission.Get());
|
.x2 = static_cast<u64>(block.permission.Get()),
|
||||||
fregs.x8 = __NR_mprotect;
|
.x8 = __NR_mprotect,
|
||||||
|
};
|
||||||
state.nce->ExecuteFunction(ThreadCall::Syscall, fregs);
|
state.nce->ExecuteFunction(ThreadCall::Syscall, fregs);
|
||||||
if (fregs.x0 < 0)
|
if (fregs.x0 < 0)
|
||||||
throw exception("An error occurred while updating transfer memory's permissions in guest");
|
throw exception("An error occurred while updating transfer memory's permissions in guest");
|
||||||
@ -103,10 +110,11 @@ namespace skyline::kernel::type {
|
|||||||
state.os->memory.InsertChunk(chunk);
|
state.os->memory.InsertChunk(chunk);
|
||||||
}
|
}
|
||||||
if ((mHost && !host) || (!mHost && !host)) {
|
if ((mHost && !host) || (!mHost && !host)) {
|
||||||
Registers fregs{};
|
Registers fregs{
|
||||||
fregs.x0 = address;
|
.x0 = address,
|
||||||
fregs.x1 = size;
|
.x1 = size,
|
||||||
fregs.x8 = __NR_munmap;
|
.x8 = __NR_munmap,
|
||||||
|
};
|
||||||
state.nce->ExecuteFunction(ThreadCall::Syscall, fregs);
|
state.nce->ExecuteFunction(ThreadCall::Syscall, fregs);
|
||||||
if (fregs.x0 < 0)
|
if (fregs.x0 < 0)
|
||||||
throw exception("An error occurred while unmapping transfer memory in child process");
|
throw exception("An error occurred while unmapping transfer memory in child process");
|
||||||
@ -125,11 +133,12 @@ namespace skyline::kernel::type {
|
|||||||
if (mremap(reinterpret_cast<void *>(address), size, nSize, 0) == MAP_FAILED)
|
if (mremap(reinterpret_cast<void *>(address), size, nSize, 0) == MAP_FAILED)
|
||||||
throw exception("An error occurred while remapping transfer memory in host: {}", strerror(errno));
|
throw exception("An error occurred while remapping transfer memory in host: {}", strerror(errno));
|
||||||
} else {
|
} else {
|
||||||
Registers fregs{};
|
Registers fregs{
|
||||||
fregs.x0 = address;
|
.x0 = address,
|
||||||
fregs.x1 = size;
|
.x1 = size,
|
||||||
fregs.x2 = nSize;
|
.x2 = nSize,
|
||||||
fregs.x8 = __NR_mremap;
|
.x8 = __NR_mremap,
|
||||||
|
};
|
||||||
state.nce->ExecuteFunction(ThreadCall::Syscall, fregs);
|
state.nce->ExecuteFunction(ThreadCall::Syscall, fregs);
|
||||||
if (fregs.x0 < 0)
|
if (fregs.x0 < 0)
|
||||||
throw exception("An error occurred while remapping transfer memory in guest");
|
throw exception("An error occurred while remapping transfer memory in guest");
|
||||||
@ -150,11 +159,12 @@ namespace skyline::kernel::type {
|
|||||||
throw exception("An occurred while remapping transfer memory: {}", strerror(errno));
|
throw exception("An occurred while remapping transfer memory: {}", strerror(errno));
|
||||||
MemoryManager::InsertBlock(&hostChunk, block);
|
MemoryManager::InsertBlock(&hostChunk, block);
|
||||||
} else {
|
} else {
|
||||||
Registers fregs{};
|
Registers fregs{
|
||||||
fregs.x0 = address;
|
.x0 = address,
|
||||||
fregs.x1 = size;
|
.x1 = size,
|
||||||
fregs.x2 = static_cast<u64>(permission.Get());
|
.x2 = static_cast<u64>(permission.Get()),
|
||||||
fregs.x8 = __NR_mprotect;
|
.x8 = __NR_mprotect,
|
||||||
|
};
|
||||||
state.nce->ExecuteFunction(ThreadCall::Syscall, fregs);
|
state.nce->ExecuteFunction(ThreadCall::Syscall, fregs);
|
||||||
if (fregs.x0 < 0)
|
if (fregs.x0 < 0)
|
||||||
throw exception("An error occurred while updating transfer memory's permissions in guest");
|
throw exception("An error occurred while updating transfer memory's permissions in guest");
|
||||||
@ -168,10 +178,11 @@ namespace skyline::kernel::type {
|
|||||||
munmap(reinterpret_cast<void *>(address), size);
|
munmap(reinterpret_cast<void *>(address), size);
|
||||||
else if (state.process) {
|
else if (state.process) {
|
||||||
try {
|
try {
|
||||||
Registers fregs{};
|
Registers fregs{
|
||||||
fregs.x0 = address;
|
.x0 = address,
|
||||||
fregs.x1 = size;
|
.x1 = size,
|
||||||
fregs.x8 = __NR_munmap;
|
.x8 = __NR_munmap,
|
||||||
|
};
|
||||||
state.nce->ExecuteFunction(ThreadCall::Syscall, fregs);
|
state.nce->ExecuteFunction(ThreadCall::Syscall, fregs);
|
||||||
state.os->memory.DeleteChunk(address);
|
state.os->memory.DeleteChunk(address);
|
||||||
} catch (const std::exception &) {
|
} catch (const std::exception &) {
|
||||||
|
Loading…
Reference in New Issue
Block a user