mirror of
https://github.com/skyline-emu/skyline.git
synced 2024-11-30 08:34:14 +01:00
Fix KTransferMemory Destruction Behavior + Add Missing SVC Handle Logs
KTransferMemory needs to be reset to RW on destruction unlike KSharedMemory which is simply freed on destruction, not emulating this behavior accurately leads to `deko_examples` from `switch-examples` to lead to a SEGFAULT on selecting an example as it expects the memory to be R/W while it ends up being freed instead
This commit is contained in:
parent
192459f726
commit
18cf0b82d6
@ -474,7 +474,8 @@ namespace skyline::kernel::svc {
|
|||||||
|
|
||||||
void MapSharedMemory(const DeviceState &state) {
|
void MapSharedMemory(const DeviceState &state) {
|
||||||
try {
|
try {
|
||||||
auto object{state.process->GetHandle<type::KSharedMemory>(state.ctx->gpr.w0)};
|
KHandle handle{state.ctx->gpr.w0};
|
||||||
|
auto object{state.process->GetHandle<type::KSharedMemory>(handle)};
|
||||||
auto pointer{reinterpret_cast<u8 *>(state.ctx->gpr.x1)};
|
auto pointer{reinterpret_cast<u8 *>(state.ctx->gpr.x1)};
|
||||||
|
|
||||||
if (!util::PageAligned(pointer)) {
|
if (!util::PageAligned(pointer)) {
|
||||||
@ -497,7 +498,7 @@ namespace skyline::kernel::svc {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
state.logger->Debug("Mapping shared memory at 0x{:X} - 0x{:X} (0x{:X} bytes) ({}{}{})", pointer, pointer + size, size, permission.r ? 'R' : '-', permission.w ? 'W' : '-', permission.x ? 'X' : '-');
|
state.logger->Debug("Mapping shared memory (0x{:X}) at 0x{:X} - 0x{:X} (0x{:X} bytes) ({}{}{})", handle, pointer, pointer + size, size, permission.r ? 'R' : '-', permission.w ? 'W' : '-', permission.x ? 'X' : '-');
|
||||||
|
|
||||||
object->Map(pointer, size, permission);
|
object->Map(pointer, size, permission);
|
||||||
|
|
||||||
@ -510,7 +511,8 @@ namespace skyline::kernel::svc {
|
|||||||
|
|
||||||
void UnmapSharedMemory(const DeviceState &state) {
|
void UnmapSharedMemory(const DeviceState &state) {
|
||||||
try {
|
try {
|
||||||
auto object{state.process->GetHandle<type::KSharedMemory>(state.ctx->gpr.w0)};
|
KHandle handle{state.ctx->gpr.w0};
|
||||||
|
auto object{state.process->GetHandle<type::KSharedMemory>(handle)};
|
||||||
auto pointer{reinterpret_cast<u8 *>(state.ctx->gpr.x1)};
|
auto pointer{reinterpret_cast<u8 *>(state.ctx->gpr.x1)};
|
||||||
|
|
||||||
if (!util::PageAligned(pointer)) {
|
if (!util::PageAligned(pointer)) {
|
||||||
@ -526,7 +528,7 @@ namespace skyline::kernel::svc {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
state.logger->Debug("Unmapping shared memory at 0x{:X} - 0x{:X} (0x{:X} bytes)", pointer, pointer + size, size);
|
state.logger->Debug("Unmapping shared memory (0x{:X}) at 0x{:X} - 0x{:X} (0x{:X} bytes)", handle, pointer, pointer + size, size);
|
||||||
|
|
||||||
object->Unmap(pointer, size);
|
object->Unmap(pointer, size);
|
||||||
|
|
||||||
@ -559,8 +561,8 @@ namespace skyline::kernel::svc {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto tmem{state.process->NewHandle<type::KTransferMemory>(pointer, size, permission)};
|
auto tmem{state.process->NewHandle<type::KTransferMemory>(pointer, size, permission, permission.raw ? memory::states::TransferMemory : memory::states::TransferMemoryIsolated)};
|
||||||
state.logger->Debug("Creating transfer memory at 0x{:X} - 0x{:X} (0x{:X} bytes) ({}{}{})", pointer, pointer + size, size, permission.r ? 'R' : '-', permission.w ? 'W' : '-', permission.x ? 'X' : '-');
|
state.logger->Debug("Creating transfer memory (0x{:X}) at 0x{:X} - 0x{:X} (0x{:X} bytes) ({}{}{})", tmem.handle, pointer, pointer + size, size, permission.r ? 'R' : '-', permission.w ? 'W' : '-', permission.x ? 'X' : '-');
|
||||||
|
|
||||||
state.ctx->gpr.w0 = Result{};
|
state.ctx->gpr.w0 = Result{};
|
||||||
state.ctx->gpr.w1 = tmem.handle;
|
state.ctx->gpr.w1 = tmem.handle;
|
||||||
|
@ -38,6 +38,9 @@ namespace skyline::kernel::type {
|
|||||||
.size = size,
|
.size = size,
|
||||||
.permission = permission,
|
.permission = permission,
|
||||||
.state = memoryState,
|
.state = memoryState,
|
||||||
|
.attributes = memory::MemoryAttribute{
|
||||||
|
.isBorrowed = objectType == KType::KTransferMemory,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
return guest.ptr;
|
return guest.ptr;
|
||||||
@ -76,22 +79,48 @@ namespace skyline::kernel::type {
|
|||||||
.size = size,
|
.size = size,
|
||||||
.permission = permission,
|
.permission = permission,
|
||||||
.state = memoryState,
|
.state = memoryState,
|
||||||
|
.attributes = memory::MemoryAttribute{
|
||||||
|
.isBorrowed = objectType == KType::KTransferMemory,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
KSharedMemory::~KSharedMemory() {
|
KSharedMemory::~KSharedMemory() {
|
||||||
if (host.Valid())
|
|
||||||
munmap(host.ptr, host.size);
|
|
||||||
|
|
||||||
if (state.process && guest.Valid()) {
|
if (state.process && guest.Valid()) {
|
||||||
mmap(guest.ptr, guest.size, PROT_NONE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); // As this is the destructor, we cannot throw on this failing
|
if (objectType != KType::KTransferMemory) {
|
||||||
|
mmap(guest.ptr, guest.size, PROT_NONE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); // It doesn't particularly matter if this fails as it shouldn't really affect anything
|
||||||
state.process->memory.InsertChunk(ChunkDescriptor{
|
state.process->memory.InsertChunk(ChunkDescriptor{
|
||||||
.ptr = guest.ptr,
|
.ptr = guest.ptr,
|
||||||
.size = guest.size,
|
.size = guest.size,
|
||||||
.state = memory::states::Unmapped,
|
.state = memory::states::Unmapped,
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
// KTransferMemory remaps the region with R/W permissions during destruction
|
||||||
|
constexpr memory::Permission UnborrowPermission{true, true, false};
|
||||||
|
|
||||||
|
if (mmap(guest.ptr, guest.size, UnborrowPermission.Get(), MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1, 0) == MAP_FAILED)
|
||||||
|
// It is likely that these exceptions will end up as asserts as the destructor is implicitly noexcept but we want to be notified about these not working so that's fine as it can be discovered in the debugger
|
||||||
|
throw exception("An error occurred while remapping transfer memory as anonymous memory in guest: {}", strerror(errno));
|
||||||
|
else if (!host.Valid())
|
||||||
|
throw exception("Expected host mapping of transfer memory to be valid during KTransferMemory destruction");
|
||||||
|
|
||||||
|
std::memcpy(guest.ptr, host.ptr, host.size);
|
||||||
|
|
||||||
|
state.process->memory.InsertChunk(ChunkDescriptor{
|
||||||
|
.ptr = guest.ptr,
|
||||||
|
.size = guest.size,
|
||||||
|
.permission = UnborrowPermission,
|
||||||
|
.state = memoryState,
|
||||||
|
.attributes = memory::MemoryAttribute{
|
||||||
|
.isBorrowed = false,
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (host.Valid())
|
||||||
|
munmap(host.ptr, host.size);
|
||||||
|
|
||||||
close(fd);
|
close(fd);
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
namespace skyline::kernel::type {
|
namespace skyline::kernel::type {
|
||||||
/**
|
/**
|
||||||
* @brief KTransferMemory is used to transfer memory from one application to another on HOS, we emulate this abstraction using KSharedMemory as it's essentially the same with the main difference being that KSharedMemory is allocated by the kernel while KTransferMemory is created from memory that's been allocated by the guest beforehand
|
* @brief KTransferMemory is used to transfer memory from one application to another on HOS, we emulate this abstraction using KSharedMemory as it's essentially the same with the main difference being that KSharedMemory is allocated by the kernel while KTransferMemory is created from memory that's been allocated by the guest beforehand
|
||||||
|
* @note KSharedMemory::{Map, Unmap, ~KSharedMemory} contains code to handle differences in memory attributes and destruction
|
||||||
*/
|
*/
|
||||||
class KTransferMemory : public KSharedMemory {
|
class KTransferMemory : public KSharedMemory {
|
||||||
public:
|
public:
|
||||||
|
Loading…
Reference in New Issue
Block a user