Implement SvcUnmapSharedMemory + Remove Redundant [[unlikely]]

This commit is contained in:
PixelyIon 2021-07-04 05:58:55 +05:30
parent a9de99357b
commit d595b9fe4f
11 changed files with 81 additions and 23 deletions

View File

@ -24,6 +24,6 @@ namespace skyline::input {
NpadManager npad;
TouchManager touch;
Input(const DeviceState &state) : state(state), kHid(std::make_shared<kernel::type::KSharedMemory>(state, sizeof(HidSharedMemory))), hid(reinterpret_cast<HidSharedMemory *>(kHid->kernel.ptr)), npad(state, hid), touch(state, hid) {}
Input(const DeviceState &state) : state(state), kHid(std::make_shared<kernel::type::KSharedMemory>(state, sizeof(HidSharedMemory))), hid(reinterpret_cast<HidSharedMemory *>(kHid->host.ptr)), npad(state, hid), touch(state, hid) {}
};
}

View File

@ -62,7 +62,7 @@ namespace skyline::kernel {
throw exception("Cannot find a suitable carveout for the guest address space");
auto result{mmap(reinterpret_cast<void *>(base.address), base.size, PROT_NONE, MAP_FIXED | MAP_ANONYMOUS | MAP_PRIVATE, -1, 0)};
if (result == MAP_FAILED) [[unlikely]]
if (result == MAP_FAILED)
throw exception("Failed to mmap guest address space: {}", strerror(errno));
chunks = {

View File

@ -216,7 +216,7 @@ namespace skyline::kernel {
auto &front{core.queue.front()};
if (front != thread)
front->scheduleCondition.notify_one(); // If we aren't at the front of the queue, only then should we wake the thread at the front up
} else if (!thread->forceYield) [[unlikely]] {
} else if (!thread->forceYield) {
throw exception("T{} called Rotate while not being in C{}'s queue", thread->id, thread->coreId);
}

View File

@ -508,6 +508,35 @@ namespace skyline::kernel::svc {
}
}
void UnmapSharedMemory(const DeviceState &state) {
try {
auto object{state.process->GetHandle<type::KSharedMemory>(state.ctx->gpr.w0)};
auto pointer{reinterpret_cast<u8 *>(state.ctx->gpr.x1)};
if (!util::PageAligned(pointer)) {
state.ctx->gpr.w0 = result::InvalidAddress;
state.logger->Warn("'pointer' not page aligned: 0x{:X}", pointer);
return;
}
size_t size{state.ctx->gpr.x2};
if (!util::PageAligned(size)) {
state.ctx->gpr.w0 = result::InvalidSize;
state.logger->Warn("'size' {}: 0x{:X}", size ? "not page aligned" : "is zero", size);
return;
}
state.logger->Debug("Unmapping shared memory at 0x{:X} - 0x{:X} (0x{:X} bytes)", pointer, pointer + size, size);
object->Unmap(pointer, size);
state.ctx->gpr.w0 = Result{};
} catch (const std::out_of_range &) {
state.logger->Warn("'handle' invalid: 0x{:X}", static_cast<u32>(state.ctx->gpr.w0));
state.ctx->gpr.w0 = result::InvalidHandle;
}
}
void CreateTransferMemory(const DeviceState &state) {
auto pointer{reinterpret_cast<u8 *>(state.ctx->gpr.x1)};
if (!util::PageAligned(pointer)) {

View File

@ -103,11 +103,17 @@ namespace skyline::kernel::svc {
void ClearEvent(const DeviceState &state);
/**
* @brief Maps the block supplied by the handle
* @brief Maps shared memory into a memory region
* @url https://switchbrew.org/wiki/SVC#MapSharedMemory
*/
void MapSharedMemory(const DeviceState &state);
/**
* @brief Unmaps shared memory which has been mapped
* @url https://switchbrew.org/wiki/SVC#UnmapSharedMemory
*/
void UnmapSharedMemory(const DeviceState &state);
/**
* @brief Returns a handle to a KSharedMemory object
* @url https://switchbrew.org/wiki/SVC#CreateTransferMemory
@ -269,7 +275,7 @@ namespace skyline::kernel::svc {
SVC_NONE, // 0x11
SVC_ENTRY(ClearEvent), // 0x12
SVC_ENTRY(MapSharedMemory), // 0x13
SVC_NONE, // 0x14
SVC_ENTRY(UnmapSharedMemory), // 0x14
SVC_ENTRY(CreateTransferMemory), // 0x15
SVC_ENTRY(CloseHandle), // 0x16
SVC_ENTRY(ResetSignal), // 0x17

View File

@ -13,12 +13,11 @@ namespace skyline::kernel::type {
if (fd < 0)
throw exception("An error occurred while creating shared memory: {}", fd);
kernel.ptr = reinterpret_cast<u8 *>(mmap(nullptr, size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_SHARED, fd, 0));
if (kernel.ptr == MAP_FAILED)
[[unlikely]]
host.ptr = reinterpret_cast<u8 *>(mmap(nullptr, size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_SHARED, fd, 0));
if (host.ptr == MAP_FAILED)
throw exception("An occurred while mapping shared memory: {}", strerror(errno));
kernel.size = size;
host.size = size;
}
u8 *KSharedMemory::Map(u8 *ptr, u64 size, memory::Permission permission) {
@ -26,10 +25,11 @@ namespace skyline::kernel::type {
throw exception("KPrivateMemory allocation isn't inside guest address space: 0x{:X} - 0x{:X}", ptr, ptr + size);
if (!util::PageAligned(ptr) || !util::PageAligned(size))
throw exception("KSharedMemory mapping isn't page-aligned: 0x{:X} - 0x{:X} (0x{:X})", ptr, ptr + size, size);
if (guest.Valid())
throw exception("Mapping KSharedMemory multiple times on guest is not supported: Requested Mapping: 0x{:X} - 0x{:X} (0x{:X}), Current Mapping: 0x{:X} - 0x{:X} (0x{:X})", ptr, ptr + size, size, guest.ptr, guest.ptr + guest.size, guest.size);
guest.ptr = reinterpret_cast<u8 *>(mmap(ptr, size, permission.Get(), MAP_SHARED | (ptr ? MAP_FIXED : 0), fd, 0));
if (guest.ptr == MAP_FAILED)
[[unlikely]]
throw exception("An error occurred while mapping shared memory in guest: {}", strerror(errno));
guest.size = size;
@ -43,6 +43,25 @@ namespace skyline::kernel::type {
return guest.ptr;
}
void KSharedMemory::Unmap(u8 *ptr, u64 size) {
if (!state.process->memory.base.IsInside(ptr) || !state.process->memory.base.IsInside(ptr + size))
throw exception("KPrivateMemory allocation isn't inside guest address space: 0x{:X} - 0x{:X}", ptr, ptr + size);
if (!util::PageAligned(ptr) || !util::PageAligned(size))
throw exception("KSharedMemory mapping isn't page-aligned: 0x{:X} - 0x{:X} (0x{:X})", ptr, ptr + size, size);
if (guest.ptr != ptr && guest.size != size)
throw exception("Unmapping KSharedMemory partially is not supported: Requested Unmap: 0x{:X} - 0x{:X} (0x{:X}), Current Mapping: 0x{:X} - 0x{:X} (0x{:X})", ptr, ptr + size, size, guest.ptr, guest.ptr + guest.size, guest.size);
if (mmap(ptr, size, PROT_NONE, MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, 0, 0) == MAP_FAILED)
throw exception("An error occurred while unmapping shared memory in guest: {}", strerror(errno));
guest = {};
state.process->memory.InsertChunk(ChunkDescriptor{
.ptr = ptr,
.size = size,
.state = memory::states::Unmapped,
});
}
void KSharedMemory::UpdatePermission(u8 *ptr, size_t size, memory::Permission permission) {
if (ptr && !util::PageAligned(ptr))
throw exception("KSharedMemory permission updated with a non-page-aligned address: 0x{:X}", ptr);
@ -50,7 +69,6 @@ namespace skyline::kernel::type {
if (guest.Valid()) {
mprotect(ptr, size, permission.Get());
if (guest.ptr == MAP_FAILED)
[[unlikely]]
throw exception("An error occurred while updating shared memory's permissions in guest: {}", strerror(errno));
state.process->memory.InsertChunk(ChunkDescriptor{
@ -63,8 +81,8 @@ namespace skyline::kernel::type {
}
KSharedMemory::~KSharedMemory() {
if (kernel.Valid())
munmap(kernel.ptr, kernel.size);
if (host.Valid())
munmap(host.ptr, host.size);
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

View File

@ -22,7 +22,7 @@ namespace skyline::kernel::type {
constexpr bool Valid() {
return ptr && size;
}
} kernel, guest{};
} host, guest{}; //!< We keep two mirrors of the underlying shared memory for guest access and host access, the host mirror is persistently mapped and should be used by anything accessing the memory on the host
KSharedMemory(const DeviceState &state, size_t size, memory::MemoryState memState = memory::states::SharedMemory, KType type = KType::KSharedMemory);
@ -31,6 +31,11 @@ namespace skyline::kernel::type {
*/
u8 *Map(u8 *ptr, u64 size, memory::Permission permission);
/**
* @note 'ptr' needs to be in guest-reserved address space
*/
void Unmap(u8 *ptr, u64 size);
span<u8> Get() override {
return span(guest.ptr, guest.size);
}

View File

@ -15,7 +15,7 @@ namespace skyline::kernel::type {
* @note 'ptr' needs to be in guest-reserved address space
*/
KTransferMemory(const DeviceState &state, u8 *ptr, size_t size, memory::Permission permission, memory::MemoryState memState = memory::states::TransferMemory) : KSharedMemory(state, size, memState, KType::KTransferMemory) {
std::memcpy(kernel.ptr, ptr, size);
std::memcpy(host.ptr, ptr, size);
Map(ptr, size, permission);
}
};

View File

@ -23,7 +23,7 @@ namespace skyline::nce {
if (svc) [[likely]] {
TRACE_EVENT("kernel", perfetto::StaticString{svc.name});
(svc.function)(state);
} else [[unlikely]] {
} else {
throw exception("Unimplemented SVC 0x{:X}", svcId);
}

View File

@ -33,11 +33,11 @@ namespace skyline::service::pl {
constexpr u32 SharedFontMagic{0x36F81A1E}; //!< The encrypted magic for a single font in the shared font data
constexpr u32 SharedFontKey{SharedFontMagic ^ SharedFontResult}; //!< The XOR key for encrypting the font size
auto ptr{reinterpret_cast<u32 *>(fontSharedMem->kernel.ptr)};
auto ptr{reinterpret_cast<u32 *>(fontSharedMem->host.ptr)};
for (auto &font : fontTable) {
*ptr++ = SharedFontResult;
*ptr++ = font.length ^ SharedFontKey;
font.offset = reinterpret_cast<u64>(ptr) - reinterpret_cast<u64>(fontSharedMem->kernel.ptr);
font.offset = reinterpret_cast<u64>(ptr) - reinterpret_cast<u64>(fontSharedMem->host.ptr);
std::memcpy(ptr, font.data, font.length);
ptr = reinterpret_cast<u32 *>(reinterpret_cast<u8 *>(ptr) + font.length);

View File

@ -57,7 +57,7 @@ namespace skyline::service::timesrv::core {
return out;
}
TimeSharedMemory::TimeSharedMemory(const DeviceState &state) : kTimeSharedMemory(std::make_shared<kernel::type::KSharedMemory>(state, TimeSharedMemorySize)), timeSharedMemory(reinterpret_cast<TimeSharedMemoryLayout *>(kTimeSharedMemory->kernel.ptr)) {}
TimeSharedMemory::TimeSharedMemory(const DeviceState &state) : kTimeSharedMemory(std::make_shared<kernel::type::KSharedMemory>(state, TimeSharedMemorySize)), timeSharedMemory(reinterpret_cast<TimeSharedMemoryLayout *>(kTimeSharedMemory->host.ptr)) {}
void TimeSharedMemory::SetupStandardSteadyClock(UUID rtcId, TimeSpanType baseTimePoint) {
SteadyClockTimePoint context{