mirror of
https://github.com/skyline-emu/skyline.git
synced 2024-12-23 23:41:52 +01:00
Implement SvcMap/UnmapPhysicalMemory + Fix W-Register Writing + Improve Accuracy of SvcGetInfo
This commit is contained in:
parent
657beea070
commit
324381908b
@ -17,8 +17,8 @@ namespace skyline::kernel {
|
|||||||
case memory::AddressSpaceType::AddressSpace36Bit: {
|
case memory::AddressSpaceType::AddressSpace36Bit: {
|
||||||
addressSpace.address = 0;
|
addressSpace.address = 0;
|
||||||
addressSpace.size = 1UL << 36;
|
addressSpace.size = 1UL << 36;
|
||||||
base.size = 0x78000000 + 0x180000000 + 0x180000000 + 0x180000000;
|
base.size = 0x78000000 + 0x180000000 + 0x78000000 + 0x180000000;
|
||||||
break;
|
throw exception("36-bit address spaces are not supported"); // Due to VMM base being forced at 0x800000 and it being used by ART
|
||||||
}
|
}
|
||||||
|
|
||||||
case memory::AddressSpaceType::AddressSpace39Bit: {
|
case memory::AddressSpaceType::AddressSpace39Bit: {
|
||||||
@ -67,18 +67,17 @@ namespace skyline::kernel {
|
|||||||
|
|
||||||
switch (addressSpace.size) {
|
switch (addressSpace.size) {
|
||||||
case 1UL << 36: {
|
case 1UL << 36: {
|
||||||
code.address = base.address;
|
code.address = 0x800000;
|
||||||
code.size = 0x78000000;
|
code.size = 0x78000000;
|
||||||
if (code.address > address || (code.size - (address - code.address)) < size)
|
if (code.address > address || (code.size - (address - code.address)) < size)
|
||||||
throw exception("Code mapping larger than 36-bit code region");
|
throw exception("Code mapping larger than 36-bit code region");
|
||||||
alias.address = code.address + code.size;
|
alias.address = code.address + code.size;
|
||||||
alias.size = 0x180000000;
|
alias.size = 0x180000000;
|
||||||
stack.address = alias.address;
|
stack.address = alias.address + alias.size;
|
||||||
stack.size = 0x180000000;
|
stack.size = 0x78000000;
|
||||||
heap.address = alias.address + alias.size;
|
tlsIo = stack; //!< TLS/IO is shared with Stack on 36-bit
|
||||||
|
heap.address = stack.address + stack.size;
|
||||||
heap.size = 0x180000000;
|
heap.size = 0x180000000;
|
||||||
tlsIo.address = code.address;
|
|
||||||
tlsIo.size = 0;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -100,7 +99,7 @@ namespace skyline::kernel {
|
|||||||
throw exception("Regions initialized without VMM initialization");
|
throw exception("Regions initialized without VMM initialization");
|
||||||
}
|
}
|
||||||
|
|
||||||
auto newSize{code.size + alias.size + stack.size + heap.size + tlsIo.size};
|
auto newSize{code.size + alias.size + stack.size + heap.size + ((addressSpace.size == 1UL << 39) ? tlsIo.size : 0)};
|
||||||
if (newSize > base.size)
|
if (newSize > base.size)
|
||||||
throw exception("Region size has exceeded pre-allocated area: 0x{:X}/0x{:X}", newSize, base.size);
|
throw exception("Region size has exceeded pre-allocated area: 0x{:X}/0x{:X}", newSize, base.size);
|
||||||
if (newSize != base.size)
|
if (newSize != base.size)
|
||||||
@ -177,10 +176,17 @@ namespace skyline::kernel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
size_t MemoryManager::GetMemoryUsage() {
|
size_t MemoryManager::GetMemoryUsage() {
|
||||||
|
std::shared_lock lock(mutex);
|
||||||
size_t size{};
|
size_t size{};
|
||||||
for (const auto &chunk : chunks)
|
for (const auto &chunk : chunks)
|
||||||
if (chunk.state != memory::states::Unmapped)
|
if (chunk.state != memory::states::Unmapped)
|
||||||
size += chunk.size;
|
size += chunk.size;
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t MemoryManager::GetKMemoryBlockSize() {
|
||||||
|
std::shared_lock lock(mutex);
|
||||||
|
constexpr size_t KMemoryBlockSize{0x40};
|
||||||
|
return util::AlignUp(chunks.size() * KMemoryBlockSize, PAGE_SIZE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -240,6 +240,11 @@ namespace skyline {
|
|||||||
* @return The cumulative size of all memory mappings in bytes
|
* @return The cumulative size of all memory mappings in bytes
|
||||||
*/
|
*/
|
||||||
size_t GetMemoryUsage();
|
size_t GetMemoryUsage();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The total page-aligned size used to store memory block metadata, if they were KMemoryBlocks rather than ChunkDescriptor
|
||||||
|
*/
|
||||||
|
size_t GetKMemoryBlockSize();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
namespace skyline::kernel::svc {
|
namespace skyline::kernel::svc {
|
||||||
void SetHeapSize(const DeviceState &state) {
|
void SetHeapSize(const DeviceState &state) {
|
||||||
auto size{state.ctx->gpr.w1};
|
u32 size{state.ctx->gpr.w1};
|
||||||
|
|
||||||
if (!util::IsAligned(size, 0x200000)) {
|
if (!util::IsAligned(size, 0x200000)) {
|
||||||
state.ctx->gpr.w0 = result::InvalidSize;
|
state.ctx->gpr.w0 = result::InvalidSize;
|
||||||
@ -35,7 +35,7 @@ namespace skyline::kernel::svc {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto size{state.ctx->gpr.x1};
|
size_t size{state.ctx->gpr.x1};
|
||||||
if (!util::PageAligned(size)) {
|
if (!util::PageAligned(size)) {
|
||||||
state.ctx->gpr.w0 = result::InvalidSize;
|
state.ctx->gpr.w0 = result::InvalidSize;
|
||||||
state.logger->Warn("svcSetMemoryAttribute: 'size' {}: 0x{:X}", size ? "not page aligned" : "is zero", size);
|
state.logger->Warn("svcSetMemoryAttribute: 'size' {}: 0x{:X}", size ? "not page aligned" : "is zero", size);
|
||||||
@ -76,9 +76,9 @@ namespace skyline::kernel::svc {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void MapMemory(const DeviceState &state) {
|
void MapMemory(const DeviceState &state) {
|
||||||
auto destination{reinterpret_cast<u8*>(state.ctx->gpr.x0)};
|
auto destination{reinterpret_cast<u8 *>(state.ctx->gpr.x0)};
|
||||||
auto source{reinterpret_cast<u8*>(state.ctx->gpr.x1)};
|
auto source{reinterpret_cast<u8 *>(state.ctx->gpr.x1)};
|
||||||
auto size{state.ctx->gpr.x2};
|
size_t size{state.ctx->gpr.x2};
|
||||||
|
|
||||||
if (!util::PageAligned(destination) || !util::PageAligned(source)) {
|
if (!util::PageAligned(destination) || !util::PageAligned(source)) {
|
||||||
state.ctx->gpr.w0 = result::InvalidAddress;
|
state.ctx->gpr.w0 = result::InvalidAddress;
|
||||||
@ -124,9 +124,9 @@ namespace skyline::kernel::svc {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void UnmapMemory(const DeviceState &state) {
|
void UnmapMemory(const DeviceState &state) {
|
||||||
auto source{reinterpret_cast<u8*>(state.ctx->gpr.x0)};
|
auto source{reinterpret_cast<u8 *>(state.ctx->gpr.x0)};
|
||||||
auto destination{reinterpret_cast<u8*>(state.ctx->gpr.x1)};
|
auto destination{reinterpret_cast<u8 *>(state.ctx->gpr.x1)};
|
||||||
auto size{state.ctx->gpr.x2};
|
size_t size{state.ctx->gpr.x2};
|
||||||
|
|
||||||
if (!util::PageAligned(destination) || !util::PageAligned(source)) {
|
if (!util::PageAligned(destination) || !util::PageAligned(source)) {
|
||||||
state.ctx->gpr.w0 = result::InvalidAddress;
|
state.ctx->gpr.w0 = result::InvalidAddress;
|
||||||
@ -182,7 +182,7 @@ namespace skyline::kernel::svc {
|
|||||||
void QueryMemory(const DeviceState &state) {
|
void QueryMemory(const DeviceState &state) {
|
||||||
memory::MemoryInfo memInfo{};
|
memory::MemoryInfo memInfo{};
|
||||||
|
|
||||||
auto pointer{reinterpret_cast<u8*>(state.ctx->gpr.x2)};
|
auto pointer{reinterpret_cast<u8 *>(state.ctx->gpr.x2)};
|
||||||
auto chunk{state.process->memory.Get(pointer)};
|
auto chunk{state.process->memory.Get(pointer)};
|
||||||
|
|
||||||
if (chunk) {
|
if (chunk) {
|
||||||
@ -196,7 +196,7 @@ namespace skyline::kernel::svc {
|
|||||||
.ipcRefCount = 0,
|
.ipcRefCount = 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
state.logger->Debug("svcQueryMemory: Address: 0x{:X}, Size: 0x{:X}, Type: 0x{:X}, Is Uncached: {}, Permissions: {}{}{}", memInfo.address, memInfo.size, memInfo.type, static_cast<bool>(chunk->attributes.isUncached), chunk->permission.r ? 'R' : '-', chunk->permission.w ? 'W' : '-', chunk->permission.x ? 'X' : '-');
|
state.logger->Debug("svcQueryMemory: Pointer: 0x{:X}, Region Start: 0x{:X}, Size: 0x{:X}, Type: 0x{:X}, Is Uncached: {}, Permissions: {}{}{}", pointer, memInfo.address, memInfo.size, memInfo.type, static_cast<bool>(chunk->attributes.isUncached), chunk->permission.r ? 'R' : '-', chunk->permission.w ? 'W' : '-', chunk->permission.x ? 'X' : '-');
|
||||||
} else {
|
} else {
|
||||||
auto addressSpaceEnd{reinterpret_cast<u64>(state.process->memory.addressSpace.address + state.process->memory.addressSpace.size)};
|
auto addressSpaceEnd{reinterpret_cast<u64>(state.process->memory.addressSpace.address + state.process->memory.addressSpace.size)};
|
||||||
|
|
||||||
@ -209,7 +209,7 @@ namespace skyline::kernel::svc {
|
|||||||
state.logger->Debug("svcQueryMemory: Trying to query memory outside of the application's address space: 0x{:X}", pointer);
|
state.logger->Debug("svcQueryMemory: Trying to query memory outside of the application's address space: 0x{:X}", pointer);
|
||||||
}
|
}
|
||||||
|
|
||||||
*reinterpret_cast<memory::MemoryInfo*>(state.ctx->gpr.x0) = memInfo;
|
*reinterpret_cast<memory::MemoryInfo *>(state.ctx->gpr.x0) = memInfo;
|
||||||
|
|
||||||
state.ctx->gpr.w0 = Result{};
|
state.ctx->gpr.w0 = Result{};
|
||||||
}
|
}
|
||||||
@ -220,10 +220,10 @@ namespace skyline::kernel::svc {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void CreateThread(const DeviceState &state) {
|
void CreateThread(const DeviceState &state) {
|
||||||
auto entry{reinterpret_cast<void*>(state.ctx->gpr.x1)};
|
auto entry{reinterpret_cast<void *>(state.ctx->gpr.x1)};
|
||||||
auto entryArgument{state.ctx->gpr.x2};
|
auto entryArgument{state.ctx->gpr.x2};
|
||||||
auto stackTop{reinterpret_cast<u8*>(state.ctx->gpr.x3)};
|
auto stackTop{reinterpret_cast<u8 *>(state.ctx->gpr.x3)};
|
||||||
auto priority{static_cast<i8>(state.ctx->gpr.w4)};
|
auto priority{static_cast<i8>(static_cast<u32>(state.ctx->gpr.w4))};
|
||||||
|
|
||||||
if (!constant::HosPriority.Valid(priority)) {
|
if (!constant::HosPriority.Valid(priority)) {
|
||||||
state.ctx->gpr.w0 = result::InvalidAddress;
|
state.ctx->gpr.w0 = result::InvalidAddress;
|
||||||
@ -243,7 +243,7 @@ namespace skyline::kernel::svc {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void StartThread(const DeviceState &state) {
|
void StartThread(const DeviceState &state) {
|
||||||
auto handle{state.ctx->gpr.w0};
|
KHandle handle{state.ctx->gpr.w0};
|
||||||
try {
|
try {
|
||||||
auto thread{state.process->GetHandle<type::KThread>(handle)};
|
auto thread{state.process->GetHandle<type::KThread>(handle)};
|
||||||
state.logger->Debug("svcStartThread: Starting thread: 0x{:X}, PID: {}", handle, thread->id);
|
state.logger->Debug("svcStartThread: Starting thread: 0x{:X}, PID: {}", handle, thread->id);
|
||||||
@ -262,7 +262,7 @@ namespace skyline::kernel::svc {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void SleepThread(const DeviceState &state) {
|
void SleepThread(const DeviceState &state) {
|
||||||
auto in{state.ctx->gpr.x0};
|
u64 in{state.ctx->gpr.x0};
|
||||||
|
|
||||||
switch (in) {
|
switch (in) {
|
||||||
case 0:
|
case 0:
|
||||||
@ -281,7 +281,7 @@ namespace skyline::kernel::svc {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void GetThreadPriority(const DeviceState &state) {
|
void GetThreadPriority(const DeviceState &state) {
|
||||||
auto handle{state.ctx->gpr.w1};
|
KHandle handle{state.ctx->gpr.w1};
|
||||||
try {
|
try {
|
||||||
auto priority{state.process->GetHandle<type::KThread>(handle)->priority};
|
auto priority{state.process->GetHandle<type::KThread>(handle)->priority};
|
||||||
state.logger->Debug("svcGetThreadPriority: Writing thread priority {}", priority);
|
state.logger->Debug("svcGetThreadPriority: Writing thread priority {}", priority);
|
||||||
@ -295,8 +295,8 @@ namespace skyline::kernel::svc {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void SetThreadPriority(const DeviceState &state) {
|
void SetThreadPriority(const DeviceState &state) {
|
||||||
auto handle{state.ctx->gpr.w0};
|
KHandle handle{state.ctx->gpr.w0};
|
||||||
auto priority{state.ctx->gpr.w1};
|
u32 priority{state.ctx->gpr.w1};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
state.logger->Debug("svcSetThreadPriority: Setting thread priority to {}", priority);
|
state.logger->Debug("svcSetThreadPriority: Setting thread priority to {}", priority);
|
||||||
@ -325,7 +325,7 @@ namespace skyline::kernel::svc {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto size{state.ctx->gpr.x2};
|
size_t size{state.ctx->gpr.x2};
|
||||||
if (!util::PageAligned(size)) {
|
if (!util::PageAligned(size)) {
|
||||||
state.ctx->gpr.w0 = result::InvalidSize;
|
state.ctx->gpr.w0 = result::InvalidSize;
|
||||||
state.logger->Warn("svcMapSharedMemory: 'size' {}: 0x{:X}", size ? "not page aligned" : "is zero", size);
|
state.logger->Warn("svcMapSharedMemory: 'size' {}: 0x{:X}", size ? "not page aligned" : "is zero", size);
|
||||||
@ -345,7 +345,7 @@ namespace skyline::kernel::svc {
|
|||||||
|
|
||||||
state.ctx->gpr.w0 = Result{};
|
state.ctx->gpr.w0 = Result{};
|
||||||
} catch (const std::exception &) {
|
} catch (const std::exception &) {
|
||||||
state.logger->Warn("svcMapSharedMemory: 'handle' invalid: 0x{:X}", state.ctx->gpr.w0);
|
state.logger->Warn("svcMapSharedMemory: 'handle' invalid: 0x{:X}", static_cast<u32>(state.ctx->gpr.w0));
|
||||||
state.ctx->gpr.w0 = result::InvalidHandle;
|
state.ctx->gpr.w0 = result::InvalidHandle;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -358,7 +358,7 @@ namespace skyline::kernel::svc {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto size{state.ctx->gpr.x2};
|
size_t size{state.ctx->gpr.x2};
|
||||||
if (!util::PageAligned(size)) {
|
if (!util::PageAligned(size)) {
|
||||||
state.ctx->gpr.w0 = result::InvalidSize;
|
state.ctx->gpr.w0 = result::InvalidSize;
|
||||||
state.logger->Warn("svcCreateTransferMemory: 'size' {}: 0x{:X}", size ? "not page aligned" : "is zero", size);
|
state.logger->Warn("svcCreateTransferMemory: 'size' {}: 0x{:X}", size ? "not page aligned" : "is zero", size);
|
||||||
@ -380,7 +380,7 @@ namespace skyline::kernel::svc {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void CloseHandle(const DeviceState &state) {
|
void CloseHandle(const DeviceState &state) {
|
||||||
auto handle{static_cast<KHandle>(state.ctx->gpr.w0)};
|
KHandle handle{static_cast<KHandle>(state.ctx->gpr.w0)};
|
||||||
try {
|
try {
|
||||||
state.process->CloseHandle(handle);
|
state.process->CloseHandle(handle);
|
||||||
state.logger->Debug("svcCloseHandle: Closing handle: 0x{:X}", handle);
|
state.logger->Debug("svcCloseHandle: Closing handle: 0x{:X}", handle);
|
||||||
@ -392,7 +392,7 @@ namespace skyline::kernel::svc {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ResetSignal(const DeviceState &state) {
|
void ResetSignal(const DeviceState &state) {
|
||||||
auto handle{state.ctx->gpr.w0};
|
KHandle handle{state.ctx->gpr.w0};
|
||||||
try {
|
try {
|
||||||
auto object{state.process->GetHandle(handle)};
|
auto object{state.process->GetHandle(handle)};
|
||||||
switch (object->objectType) {
|
switch (object->objectType) {
|
||||||
@ -423,7 +423,7 @@ namespace skyline::kernel::svc {
|
|||||||
void WaitSynchronization(const DeviceState &state) {
|
void WaitSynchronization(const DeviceState &state) {
|
||||||
constexpr u8 maxSyncHandles{0x40}; // The total amount of handles that can be passed to WaitSynchronization
|
constexpr u8 maxSyncHandles{0x40}; // The total amount of handles that can be passed to WaitSynchronization
|
||||||
|
|
||||||
auto numHandles{state.ctx->gpr.w2};
|
u32 numHandles{state.ctx->gpr.w2};
|
||||||
if (numHandles > maxSyncHandles) {
|
if (numHandles > maxSyncHandles) {
|
||||||
state.ctx->gpr.w0 = result::OutOfHandles;
|
state.ctx->gpr.w0 = result::OutOfHandles;
|
||||||
return;
|
return;
|
||||||
@ -431,7 +431,7 @@ namespace skyline::kernel::svc {
|
|||||||
|
|
||||||
std::string handleStr;
|
std::string handleStr;
|
||||||
std::vector<std::shared_ptr<type::KSyncObject>> objectTable;
|
std::vector<std::shared_ptr<type::KSyncObject>> objectTable;
|
||||||
span waitHandles(reinterpret_cast<KHandle*>(state.ctx->gpr.x1), numHandles);
|
span waitHandles(reinterpret_cast<KHandle *>(state.ctx->gpr.x1), numHandles);
|
||||||
|
|
||||||
for (const auto &handle : waitHandles) {
|
for (const auto &handle : waitHandles) {
|
||||||
handleStr += fmt::format("* 0x{:X}\n", handle);
|
handleStr += fmt::format("* 0x{:X}\n", handle);
|
||||||
@ -453,7 +453,7 @@ namespace skyline::kernel::svc {
|
|||||||
objectTable.push_back(std::static_pointer_cast<type::KSyncObject>(object));
|
objectTable.push_back(std::static_pointer_cast<type::KSyncObject>(object));
|
||||||
}
|
}
|
||||||
|
|
||||||
auto timeout{state.ctx->gpr.x3};
|
u64 timeout{state.ctx->gpr.x3};
|
||||||
state.logger->Debug("svcWaitSynchronization: Waiting on handles:\n{}Timeout: 0x{:X} ns", handleStr, timeout);
|
state.logger->Debug("svcWaitSynchronization: Waiting on handles:\n{}Timeout: 0x{:X} ns", handleStr, timeout);
|
||||||
|
|
||||||
auto start{util::GetTimeNs()};
|
auto start{util::GetTimeNs()};
|
||||||
@ -487,21 +487,21 @@ namespace skyline::kernel::svc {
|
|||||||
try {
|
try {
|
||||||
state.process->GetHandle<type::KThread>(state.ctx->gpr.w0)->cancelSync = true;
|
state.process->GetHandle<type::KThread>(state.ctx->gpr.w0)->cancelSync = true;
|
||||||
} catch (const std::exception &) {
|
} catch (const std::exception &) {
|
||||||
state.logger->Warn("svcCancelSynchronization: 'handle' invalid: 0x{:X}", state.ctx->gpr.w0);
|
state.logger->Warn("svcCancelSynchronization: 'handle' invalid: 0x{:X}", static_cast<u32>(state.ctx->gpr.w0));
|
||||||
state.ctx->gpr.w0 = result::InvalidHandle;
|
state.ctx->gpr.w0 = result::InvalidHandle;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ArbitrateLock(const DeviceState &state) {
|
void ArbitrateLock(const DeviceState &state) {
|
||||||
auto pointer{reinterpret_cast<u32*>(state.ctx->gpr.x1)};
|
auto pointer{reinterpret_cast<u32 *>(state.ctx->gpr.x1)};
|
||||||
if (!util::WordAligned(pointer)) {
|
if (!util::WordAligned(pointer)) {
|
||||||
state.logger->Warn("svcArbitrateLock: 'pointer' not word aligned: 0x{:X}", pointer);
|
state.logger->Warn("svcArbitrateLock: 'pointer' not word aligned: 0x{:X}", pointer);
|
||||||
state.ctx->gpr.w0 = result::InvalidAddress;
|
state.ctx->gpr.w0 = result::InvalidAddress;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto ownerHandle{state.ctx->gpr.w0};
|
KHandle ownerHandle{state.ctx->gpr.w0};
|
||||||
auto requesterHandle{state.ctx->gpr.w2};
|
KHandle requesterHandle{state.ctx->gpr.w2};
|
||||||
if (requesterHandle != state.thread->handle)
|
if (requesterHandle != state.thread->handle)
|
||||||
throw exception("svcWaitProcessWideKeyAtomic: Handle doesn't match current thread: 0x{:X} for thread 0x{:X}", requesterHandle, state.thread->handle);
|
throw exception("svcWaitProcessWideKeyAtomic: Handle doesn't match current thread: 0x{:X} for thread 0x{:X}", requesterHandle, state.thread->handle);
|
||||||
|
|
||||||
@ -516,7 +516,7 @@ namespace skyline::kernel::svc {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ArbitrateUnlock(const DeviceState &state) {
|
void ArbitrateUnlock(const DeviceState &state) {
|
||||||
auto mutex{reinterpret_cast<u32*>(state.ctx->gpr.x0)};
|
auto mutex{reinterpret_cast<u32 *>(state.ctx->gpr.x0)};
|
||||||
if (!util::WordAligned(mutex)) {
|
if (!util::WordAligned(mutex)) {
|
||||||
state.logger->Warn("svcArbitrateUnlock: 'mutex' not word aligned: 0x{:X}", mutex);
|
state.logger->Warn("svcArbitrateUnlock: 'mutex' not word aligned: 0x{:X}", mutex);
|
||||||
state.ctx->gpr.w0 = result::InvalidAddress;
|
state.ctx->gpr.w0 = result::InvalidAddress;
|
||||||
@ -535,15 +535,15 @@ namespace skyline::kernel::svc {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void WaitProcessWideKeyAtomic(const DeviceState &state) {
|
void WaitProcessWideKeyAtomic(const DeviceState &state) {
|
||||||
auto mutex{reinterpret_cast<u32*>(state.ctx->gpr.x0)};
|
auto mutex{reinterpret_cast<u32 *>(state.ctx->gpr.x0)};
|
||||||
if (!util::WordAligned(mutex)) {
|
if (!util::WordAligned(mutex)) {
|
||||||
state.logger->Warn("svcWaitProcessWideKeyAtomic: 'mutex' not word aligned: 0x{:X}", mutex);
|
state.logger->Warn("svcWaitProcessWideKeyAtomic: 'mutex' not word aligned: 0x{:X}", mutex);
|
||||||
state.ctx->gpr.w0 = result::InvalidAddress;
|
state.ctx->gpr.w0 = result::InvalidAddress;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto conditional{reinterpret_cast<void*>(state.ctx->gpr.x1)};
|
auto conditional{reinterpret_cast<void *>(state.ctx->gpr.x1)};
|
||||||
auto handle{state.ctx->gpr.w2};
|
KHandle handle{state.ctx->gpr.w2};
|
||||||
if (handle != state.thread->handle)
|
if (handle != state.thread->handle)
|
||||||
throw exception("svcWaitProcessWideKeyAtomic: Handle doesn't match current thread: 0x{:X} for thread 0x{:X}", handle, state.thread->handle);
|
throw exception("svcWaitProcessWideKeyAtomic: Handle doesn't match current thread: 0x{:X} for thread 0x{:X}", handle, state.thread->handle);
|
||||||
|
|
||||||
@ -553,7 +553,7 @@ namespace skyline::kernel::svc {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto timeout{state.ctx->gpr.x3};
|
u64 timeout{state.ctx->gpr.x3};
|
||||||
state.logger->Debug("svcWaitProcessWideKeyAtomic: Mutex: 0x{:X}, Conditional-Variable: 0x{:X}, Timeout: {} ns", mutex, conditional, timeout);
|
state.logger->Debug("svcWaitProcessWideKeyAtomic: Mutex: 0x{:X}, Conditional-Variable: 0x{:X}, Timeout: {} ns", mutex, conditional, timeout);
|
||||||
|
|
||||||
if (state.process->ConditionalVariableWait(conditional, mutex, timeout)) {
|
if (state.process->ConditionalVariableWait(conditional, mutex, timeout)) {
|
||||||
@ -566,8 +566,8 @@ namespace skyline::kernel::svc {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void SignalProcessWideKey(const DeviceState &state) {
|
void SignalProcessWideKey(const DeviceState &state) {
|
||||||
auto conditional{reinterpret_cast<void*>(state.ctx->gpr.x0)};
|
auto conditional{reinterpret_cast<void *>(state.ctx->gpr.x0)};
|
||||||
auto count{state.ctx->gpr.w1};
|
KHandle count{state.ctx->gpr.w1};
|
||||||
|
|
||||||
state.logger->Debug("svcSignalProcessWideKey: Signalling Conditional-Variable at 0x{:X} for {}", conditional, count);
|
state.logger->Debug("svcSignalProcessWideKey: Signalling Conditional-Variable at 0x{:X} for {}", conditional, count);
|
||||||
state.process->ConditionalVariableSignal(conditional, count);
|
state.process->ConditionalVariableSignal(conditional, count);
|
||||||
@ -589,7 +589,7 @@ namespace skyline::kernel::svc {
|
|||||||
|
|
||||||
void ConnectToNamedPort(const DeviceState &state) {
|
void ConnectToNamedPort(const DeviceState &state) {
|
||||||
constexpr u8 portSize = 0x8; //!< The size of a port name string
|
constexpr u8 portSize = 0x8; //!< The size of a port name string
|
||||||
std::string_view port(span(reinterpret_cast<char*>(state.ctx->gpr.x1), portSize).as_string(true));
|
std::string_view port(span(reinterpret_cast<char *>(state.ctx->gpr.x1), portSize).as_string(true));
|
||||||
|
|
||||||
KHandle handle{};
|
KHandle handle{};
|
||||||
if (port.compare("sm:") >= 0) {
|
if (port.compare("sm:") >= 0) {
|
||||||
@ -613,7 +613,7 @@ namespace skyline::kernel::svc {
|
|||||||
|
|
||||||
void GetThreadId(const DeviceState &state) {
|
void GetThreadId(const DeviceState &state) {
|
||||||
constexpr KHandle threadSelf{0xFFFF8000}; // The handle used by threads to refer to themselves
|
constexpr KHandle threadSelf{0xFFFF8000}; // The handle used by threads to refer to themselves
|
||||||
auto handle{state.ctx->gpr.w1};
|
KHandle handle{state.ctx->gpr.w1};
|
||||||
pid_t pid{};
|
pid_t pid{};
|
||||||
|
|
||||||
if (handle != threadSelf)
|
if (handle != threadSelf)
|
||||||
@ -628,7 +628,7 @@ namespace skyline::kernel::svc {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void OutputDebugString(const DeviceState &state) {
|
void OutputDebugString(const DeviceState &state) {
|
||||||
auto debug{span(reinterpret_cast<u8*>(state.ctx->gpr.x0), state.ctx->gpr.x1).as_string()};
|
auto debug{span(reinterpret_cast<u8 *>(state.ctx->gpr.x0), state.ctx->gpr.x1).as_string()};
|
||||||
|
|
||||||
if (debug.back() == '\n')
|
if (debug.back() == '\n')
|
||||||
debug.remove_suffix(1);
|
debug.remove_suffix(1);
|
||||||
@ -638,91 +638,196 @@ namespace skyline::kernel::svc {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void GetInfo(const DeviceState &state) {
|
void GetInfo(const DeviceState &state) {
|
||||||
auto id0{state.ctx->gpr.w1};
|
enum class InfoState : u32 {
|
||||||
auto handle{state.ctx->gpr.w2};
|
// 1.0.0+
|
||||||
auto id1{state.ctx->gpr.x3};
|
AllowedCpuIdBitmask = 0x0,
|
||||||
|
AllowedThreadPriorityMask = 0x1,
|
||||||
|
AliasRegionBaseAddr = 0x2,
|
||||||
|
AliasRegionSize = 0x3,
|
||||||
|
HeapRegionBaseAddr = 0x4,
|
||||||
|
HeapRegionSize = 0x5,
|
||||||
|
TotalMemoryAvailable = 0x6,
|
||||||
|
TotalMemoryUsage = 0x7,
|
||||||
|
IsCurrentProcessBeingDebugged = 0x8,
|
||||||
|
ResourceLimit = 0x9,
|
||||||
|
IdleTickCount = 0xA,
|
||||||
|
RandomEntropy = 0xB,
|
||||||
|
// 2.0.0+
|
||||||
|
AddressSpaceBaseAddr = 0xC,
|
||||||
|
AddressSpaceSize = 0xD,
|
||||||
|
StackRegionBaseAddr = 0xE,
|
||||||
|
StackRegionSize = 0xF,
|
||||||
|
// 3.0.0+
|
||||||
|
TotalSystemResourceAvailable = 0x10,
|
||||||
|
TotalSystemResourceUsage = 0x11,
|
||||||
|
TitleId = 0x12,
|
||||||
|
// 4.0.0+
|
||||||
|
PrivilegedProcessId = 0x13,
|
||||||
|
// 5.0.0+
|
||||||
|
UserExceptionContextAddr = 0x14,
|
||||||
|
// 6.0.0+
|
||||||
|
TotalMemoryAvailableWithoutSystemResource = 0x15,
|
||||||
|
TotalMemoryUsageWithoutSystemResource = 0x16,
|
||||||
|
};
|
||||||
|
|
||||||
u64 out{};
|
InfoState info{static_cast<u32>(state.ctx->gpr.w1)};
|
||||||
|
KHandle handle{state.ctx->gpr.w2};
|
||||||
|
u64 id1{state.ctx->gpr.x3};
|
||||||
|
|
||||||
constexpr u64 totalPhysicalMemory{0xF8000000}; // ~4 GB of RAM
|
constexpr u64 totalPhysicalMemory{0xF8000000}; // ~4 GB of RAM
|
||||||
|
|
||||||
switch (id0) {
|
u64 out{};
|
||||||
case constant::infoState::AllowedCpuIdBitmask:
|
switch (info) {
|
||||||
case constant::infoState::AllowedThreadPriorityMask:
|
case InfoState::AllowedCpuIdBitmask:
|
||||||
case constant::infoState::IsCurrentProcessBeingDebugged:
|
case InfoState::AllowedThreadPriorityMask:
|
||||||
case constant::infoState::TitleId:
|
case InfoState::IsCurrentProcessBeingDebugged:
|
||||||
case constant::infoState::PrivilegedProcessId:
|
case InfoState::TitleId:
|
||||||
|
case InfoState::PrivilegedProcessId:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case constant::infoState::AliasRegionBaseAddr:
|
case InfoState::AliasRegionBaseAddr:
|
||||||
out = state.process->memory.alias.address;
|
out = state.process->memory.alias.address;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case constant::infoState::AliasRegionSize:
|
case InfoState::AliasRegionSize:
|
||||||
out = state.process->memory.alias.size;
|
out = state.process->memory.alias.size;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case constant::infoState::HeapRegionBaseAddr:
|
case InfoState::HeapRegionBaseAddr:
|
||||||
out = state.process->memory.heap.address;
|
out = state.process->memory.heap.address;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case constant::infoState::HeapRegionSize:
|
case InfoState::HeapRegionSize:
|
||||||
out = state.process->memory.heap.size;
|
out = state.process->memory.heap.size;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case constant::infoState::TotalMemoryAvailable:
|
case InfoState::TotalMemoryAvailable:
|
||||||
out = totalPhysicalMemory;
|
out = totalPhysicalMemory;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case constant::infoState::TotalMemoryUsage:
|
case InfoState::TotalMemoryUsage:
|
||||||
out = state.process->memory.GetMemoryUsage();
|
out = state.process->memory.GetMemoryUsage();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case constant::infoState::AddressSpaceBaseAddr:
|
case InfoState::AddressSpaceBaseAddr:
|
||||||
out = state.process->memory.base.address;
|
out = state.process->memory.base.address;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case constant::infoState::AddressSpaceSize:
|
case InfoState::AddressSpaceSize:
|
||||||
out = state.process->memory.base.size;
|
out = state.process->memory.base.size;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case constant::infoState::StackRegionBaseAddr:
|
case InfoState::StackRegionBaseAddr:
|
||||||
out = state.process->memory.stack.address;
|
out = state.process->memory.stack.address;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case constant::infoState::StackRegionSize:
|
case InfoState::StackRegionSize:
|
||||||
out = state.process->memory.stack.size;
|
out = state.process->memory.stack.size;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case constant::infoState::PersonalMmHeapSize:
|
case InfoState::TotalSystemResourceAvailable:
|
||||||
out = totalPhysicalMemory;
|
out = totalPhysicalMemory; // TODO: NPDM specifies this in it's PersonalMmHeapSize field
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case constant::infoState::PersonalMmHeapUsage:
|
case InfoState::TotalSystemResourceUsage:
|
||||||
out = state.process->heap->size + state.process->mainThreadStack->size;
|
// A very rough approximation of what this should be on the Switch, the amount of memory allocated for storing the memory blocks (https://switchbrew.org/wiki/Kernel_objects#KMemoryBlockManager)
|
||||||
|
out = state.process->memory.GetKMemoryBlockSize();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case constant::infoState::TotalMemoryAvailableWithoutMmHeap:
|
case InfoState::TotalMemoryAvailableWithoutSystemResource:
|
||||||
out = totalPhysicalMemory; // TODO: NPDM specifies SystemResourceSize, subtract that from this
|
out = totalPhysicalMemory; // TODO: Subtract TotalSystemResourceAvailable from this
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case constant::infoState::TotalMemoryUsedWithoutMmHeap:
|
case InfoState::TotalMemoryUsageWithoutSystemResource:
|
||||||
out = state.process->heap->size + state.process->mainThreadStack->size; // TODO: Same as above
|
out = state.process->memory.GetMemoryUsage();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case constant::infoState::UserExceptionContextAddr:
|
case InfoState::UserExceptionContextAddr:
|
||||||
out = reinterpret_cast<u64>(state.process->tlsPages[0]->Get(0));
|
out = reinterpret_cast<u64>(state.process->tlsPages[0]->Get(0));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
state.logger->Warn("svcGetInfo: Unimplemented case ID0: {}, ID1: {}", id0, id1);
|
state.logger->Warn("svcGetInfo: Unimplemented case ID0: {}, ID1: {}", static_cast<u32>(info), id1);
|
||||||
state.ctx->gpr.w0 = result::InvalidEnumValue;
|
state.ctx->gpr.w0 = result::InvalidEnumValue;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
state.logger->Debug("svcGetInfo: ID0: {}, ID1: {}, Out: 0x{:X}", id0, id1, out);
|
state.logger->Debug("svcGetInfo: ID0: {}, ID1: {}, Out: 0x{:X}", static_cast<u32>(info), id1, out);
|
||||||
|
|
||||||
state.ctx->gpr.x1 = out;
|
state.ctx->gpr.x1 = out;
|
||||||
state.ctx->gpr.w0 = Result{};
|
state.ctx->gpr.w0 = Result{};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MapPhysicalMemory(const DeviceState &state) {
|
||||||
|
auto pointer{reinterpret_cast<u8 *>(state.ctx->gpr.x0)};
|
||||||
|
size_t size{state.ctx->gpr.x1};
|
||||||
|
|
||||||
|
if (!util::PageAligned(pointer)) {
|
||||||
|
state.ctx->gpr.w0 = result::InvalidAddress;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!size || !util::PageAligned(size)) {
|
||||||
|
state.ctx->gpr.w0 = result::InvalidSize;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!state.process->memory.alias.IsInside(pointer) || !state.process->memory.alias.IsInside(pointer + size)) {
|
||||||
|
state.ctx->gpr.w0 = result::InvalidMemoryRegion;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
state.process->NewHandle<type::KPrivateMemory>(pointer, size, memory::Permission{true, true, false}, memory::states::Heap);
|
||||||
|
|
||||||
|
state.ctx->gpr.w0 = Result{};
|
||||||
|
}
|
||||||
|
|
||||||
|
void UnmapPhysicalMemory(const DeviceState &state) {
|
||||||
|
auto pointer{reinterpret_cast<u8 *>(state.ctx->gpr.x0)};
|
||||||
|
size_t size{state.ctx->gpr.x1};
|
||||||
|
|
||||||
|
if (!util::PageAligned(pointer)) {
|
||||||
|
state.ctx->gpr.w0 = result::InvalidAddress;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!size || !util::PageAligned(size)) {
|
||||||
|
state.ctx->gpr.w0 = result::InvalidSize;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!state.process->memory.alias.IsInside(pointer) || !state.process->memory.alias.IsInside(pointer + size)) {
|
||||||
|
state.ctx->gpr.w0 = result::InvalidMemoryRegion;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto end{pointer + size};
|
||||||
|
while (pointer < end) {
|
||||||
|
auto memory{state.process->GetMemoryObject(pointer)};
|
||||||
|
if (memory) {
|
||||||
|
auto item{static_pointer_cast<type::KPrivateMemory>(memory->item)};
|
||||||
|
auto initialSize{item->size};
|
||||||
|
if (item->memState == memory::states::Heap) {
|
||||||
|
if (item->ptr >= pointer) {
|
||||||
|
if (item->size <= size) {
|
||||||
|
item->Resize(0);
|
||||||
|
state.process->CloseHandle(memory->handle);
|
||||||
|
} else {
|
||||||
|
item->Remap(pointer + size, item->size - (size + (item->ptr - pointer)));
|
||||||
|
}
|
||||||
|
} else if (item->ptr < pointer) {
|
||||||
|
item->Resize(pointer - item->ptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pointer += initialSize;
|
||||||
|
size -= initialSize;
|
||||||
|
} else {
|
||||||
|
auto block{*state.process->memory.Get(pointer)};
|
||||||
|
pointer += block.size;
|
||||||
|
size -= block.size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
state.ctx->gpr.w0 = Result{};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,346 +5,324 @@
|
|||||||
|
|
||||||
#include <common.h>
|
#include <common.h>
|
||||||
|
|
||||||
namespace skyline {
|
namespace skyline::kernel::svc {
|
||||||
namespace constant::infoState {
|
/**
|
||||||
// 1.0.0+
|
* @brief Sets the process heap to a given size, it can both extend and shrink the heap
|
||||||
constexpr u8 AllowedCpuIdBitmask{0x0};
|
* @url https://switchbrew.org/wiki/SVC#SetHeapSize
|
||||||
constexpr u8 AllowedThreadPriorityMask{0x1};
|
*/
|
||||||
constexpr u8 AliasRegionBaseAddr{0x2};
|
void SetHeapSize(const DeviceState &state);
|
||||||
constexpr u8 AliasRegionSize{0x3};
|
|
||||||
constexpr u8 HeapRegionBaseAddr{0x4};
|
|
||||||
constexpr u8 HeapRegionSize{0x5};
|
|
||||||
constexpr u8 TotalMemoryAvailable{0x6};
|
|
||||||
constexpr u8 TotalMemoryUsage{0x7};
|
|
||||||
constexpr u8 IsCurrentProcessBeingDebugged{0x8};
|
|
||||||
constexpr u8 ResourceLimit{0x9};
|
|
||||||
constexpr u8 IdleTickCount{0xA};
|
|
||||||
constexpr u8 RandomEntropy{0xB};
|
|
||||||
// 2.0.0+
|
|
||||||
constexpr u8 AddressSpaceBaseAddr{0xC};
|
|
||||||
constexpr u8 AddressSpaceSize{0xD};
|
|
||||||
constexpr u8 StackRegionBaseAddr{0xE};
|
|
||||||
constexpr u8 StackRegionSize{0xF};
|
|
||||||
// 3.0.0+
|
|
||||||
constexpr u8 PersonalMmHeapSize{0x10};
|
|
||||||
constexpr u8 PersonalMmHeapUsage{0x11};
|
|
||||||
constexpr u8 TitleId{0x12};
|
|
||||||
// 4.0.0+
|
|
||||||
constexpr u8 PrivilegedProcessId{0x13};
|
|
||||||
// 5.0.0+
|
|
||||||
constexpr u8 UserExceptionContextAddr{0x14};
|
|
||||||
// 6.0.0+
|
|
||||||
constexpr u8 TotalMemoryAvailableWithoutMmHeap{0x15};
|
|
||||||
constexpr u8 TotalMemoryUsedWithoutMmHeap{0x16};
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace kernel::svc {
|
/**
|
||||||
/**
|
* @brief Change attribute of page-aligned memory region, this is used to turn on/off caching for a given memory area
|
||||||
* @brief Sets the process heap to a given size, it can both extend and shrink the heap
|
* @url https://switchbrew.org/wiki/SVC#SetMemoryAttribute
|
||||||
* @url https://switchbrew.org/wiki/SVC#SetHeapSize
|
*/
|
||||||
*/
|
void SetMemoryAttribute(const DeviceState &state);
|
||||||
void SetHeapSize(const DeviceState &state);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Change attribute of page-aligned memory region, this is used to turn on/off caching for a given memory area
|
* @brief Maps a memory range into a different range, mainly used for adding guard pages around stack
|
||||||
* @url https://switchbrew.org/wiki/SVC#SetMemoryAttribute
|
* @url https://switchbrew.org/wiki/SVC#SetMemoryAttribute
|
||||||
*/
|
*/
|
||||||
void SetMemoryAttribute(const DeviceState &state);
|
void MapMemory(const DeviceState &state);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Maps a memory range into a different range, mainly used for adding guard pages around stack
|
* @brief Unmaps a region that was previously mapped with #MapMemory
|
||||||
* @url https://switchbrew.org/wiki/SVC#SetMemoryAttribute
|
* @url https://switchbrew.org/wiki/SVC#UnmapMemory
|
||||||
*/
|
*/
|
||||||
void MapMemory(const DeviceState &state);
|
void UnmapMemory(const DeviceState &state);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Unmaps a region that was previously mapped with #MapMemory
|
* @brief Query information about an address
|
||||||
* @url https://switchbrew.org/wiki/SVC#UnmapMemory
|
* @url https://switchbrew.org/wiki/SVC#QueryMemory
|
||||||
*/
|
*/
|
||||||
void UnmapMemory(const DeviceState &state);
|
void QueryMemory(const DeviceState &state);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Query information about an address
|
* @brief Exits the current process
|
||||||
* @url https://switchbrew.org/wiki/SVC#QueryMemory
|
* @url https://switchbrew.org/wiki/SVC#ExitProcess
|
||||||
*/
|
*/
|
||||||
void QueryMemory(const DeviceState &state);
|
void ExitProcess(const DeviceState &state);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Exits the current process
|
* @brief Create a thread in the current process
|
||||||
* @url https://switchbrew.org/wiki/SVC#ExitProcess
|
* @url https://switchbrew.org/wiki/SVC#CreateThread
|
||||||
*/
|
*/
|
||||||
void ExitProcess(const DeviceState &state);
|
void CreateThread(const DeviceState &state);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Create a thread in the current process
|
* @brief Starts the thread for the provided handle
|
||||||
* @url https://switchbrew.org/wiki/SVC#CreateThread
|
* @url https://switchbrew.org/wiki/SVC#StartThread
|
||||||
*/
|
*/
|
||||||
void CreateThread(const DeviceState &state);
|
void StartThread(const DeviceState &state);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Starts the thread for the provided handle
|
* @brief Exits the current thread
|
||||||
* @url https://switchbrew.org/wiki/SVC#StartThread
|
* @url https://switchbrew.org/wiki/SVC#ExitThread
|
||||||
*/
|
*/
|
||||||
void StartThread(const DeviceState &state);
|
void ExitThread(const DeviceState &state);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Exits the current thread
|
* @brief Sleep for a specified amount of time, or yield thread
|
||||||
* @url https://switchbrew.org/wiki/SVC#ExitThread
|
* @url https://switchbrew.org/wiki/SVC#SleepThread
|
||||||
*/
|
*/
|
||||||
void ExitThread(const DeviceState &state);
|
void SleepThread(const DeviceState &state);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Sleep for a specified amount of time, or yield thread
|
* @brief Get priority of provided thread handle
|
||||||
* @url https://switchbrew.org/wiki/SVC#SleepThread
|
* @url https://switchbrew.org/wiki/SVC#GetThreadPriority
|
||||||
*/
|
*/
|
||||||
void SleepThread(const DeviceState &state);
|
void GetThreadPriority(const DeviceState &state);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get priority of provided thread handle
|
* @brief Set priority of provided thread handle
|
||||||
* @url https://switchbrew.org/wiki/SVC#GetThreadPriority
|
* @url https://switchbrew.org/wiki/SVC#SetThreadPriority
|
||||||
*/
|
*/
|
||||||
void GetThreadPriority(const DeviceState &state);
|
void SetThreadPriority(const DeviceState &state);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Set priority of provided thread handle
|
* @brief Clears a KEvent of it's signal
|
||||||
* @url https://switchbrew.org/wiki/SVC#SetThreadPriority
|
* @url https://switchbrew.org/wiki/SVC#ClearEvent
|
||||||
*/
|
*/
|
||||||
void SetThreadPriority(const DeviceState &state);
|
void ClearEvent(const DeviceState &state);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Clears a KEvent of it's signal
|
* @brief Maps the block supplied by the handle
|
||||||
* @url https://switchbrew.org/wiki/SVC#ClearEvent
|
* @url https://switchbrew.org/wiki/SVC#MapSharedMemory
|
||||||
*/
|
*/
|
||||||
void ClearEvent(const DeviceState &state);
|
void MapSharedMemory(const DeviceState &state);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Maps the block supplied by the handle
|
* @brief Returns a handle to a KSharedMemory object
|
||||||
* @url https://switchbrew.org/wiki/SVC#MapSharedMemory
|
* @url https://switchbrew.org/wiki/SVC#CreateTransferMemory
|
||||||
*/
|
*/
|
||||||
void MapSharedMemory(const DeviceState &state);
|
void CreateTransferMemory(const DeviceState &state);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Returns a handle to a KSharedMemory object
|
* @brief Closes the specified handle
|
||||||
* @url https://switchbrew.org/wiki/SVC#CreateTransferMemory
|
* @url https://switchbrew.org/wiki/SVC#CloseHandle
|
||||||
*/
|
*/
|
||||||
void CreateTransferMemory(const DeviceState &state);
|
void CloseHandle(const DeviceState &state);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Closes the specified handle
|
* @brief Resets a particular KEvent or KProcess which is signalled
|
||||||
* @url https://switchbrew.org/wiki/SVC#CloseHandle
|
* @url https://switchbrew.org/wiki/SVC#ResetSignal
|
||||||
*/
|
*/
|
||||||
void CloseHandle(const DeviceState &state);
|
void ResetSignal(const DeviceState &state);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Resets a particular KEvent or KProcess which is signalled
|
* @brief Stalls a thread till a KSyncObject signals or the timeout has ended
|
||||||
* @url https://switchbrew.org/wiki/SVC#ResetSignal
|
* @url https://switchbrew.org/wiki/SVC#WaitSynchronization
|
||||||
*/
|
*/
|
||||||
void ResetSignal(const DeviceState &state);
|
void WaitSynchronization(const DeviceState &state);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Stalls a thread till a KSyncObject signals or the timeout has ended
|
* @brief If the referenced thread is currently in a synchronization call, that call will be interrupted
|
||||||
* @url https://switchbrew.org/wiki/SVC#WaitSynchronization
|
* @url https://switchbrew.org/wiki/SVC#CancelSynchronization
|
||||||
*/
|
*/
|
||||||
void WaitSynchronization(const DeviceState &state);
|
void CancelSynchronization(const DeviceState &state);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief If the referenced thread is currently in a synchronization call, that call will be interrupted
|
* @brief Locks a specified mutex
|
||||||
* @url https://switchbrew.org/wiki/SVC#CancelSynchronization
|
* @url https://switchbrew.org/wiki/SVC#ArbitrateLock
|
||||||
*/
|
*/
|
||||||
void CancelSynchronization(const DeviceState &state);
|
void ArbitrateLock(const DeviceState &state);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Locks a specified mutex
|
* @brief Unlocks a specified mutex
|
||||||
* @url https://switchbrew.org/wiki/SVC#ArbitrateLock
|
* @url https://switchbrew.org/wiki/SVC#ArbitrateUnlock
|
||||||
*/
|
*/
|
||||||
void ArbitrateLock(const DeviceState &state);
|
void ArbitrateUnlock(const DeviceState &state);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Unlocks a specified mutex
|
* @brief Waits on a process-wide key (Conditional-Variable)
|
||||||
* @url https://switchbrew.org/wiki/SVC#ArbitrateUnlock
|
* @url https://switchbrew.org/wiki/SVC#WaitProcessWideKeyAtomic
|
||||||
*/
|
*/
|
||||||
void ArbitrateUnlock(const DeviceState &state);
|
void WaitProcessWideKeyAtomic(const DeviceState &state);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Waits on a process-wide key (Conditional-Variable)
|
* @brief Signals a process-wide key (Conditional-Variable)
|
||||||
* @url https://switchbrew.org/wiki/SVC#WaitProcessWideKeyAtomic
|
* @url https://switchbrew.org/wiki/SVC#SignalProcessWideKey
|
||||||
*/
|
*/
|
||||||
void WaitProcessWideKeyAtomic(const DeviceState &state);
|
void SignalProcessWideKey(const DeviceState &state);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Signals a process-wide key (Conditional-Variable)
|
* @brief Returns the value of CNTPCT_EL0 on the Switch
|
||||||
* @url https://switchbrew.org/wiki/SVC#SignalProcessWideKey
|
* @url https://switchbrew.org/wiki/SVC#GetSystemTick
|
||||||
*/
|
*/
|
||||||
void SignalProcessWideKey(const DeviceState &state);
|
void GetSystemTick(const DeviceState &state);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Returns the value of CNTPCT_EL0 on the Switch
|
* @brief Connects to a named IPC port
|
||||||
* @url https://switchbrew.org/wiki/SVC#GetSystemTick
|
* @url https://switchbrew.org/wiki/SVC#ConnectToNamedPort
|
||||||
*/
|
*/
|
||||||
void GetSystemTick(const DeviceState &state);
|
void ConnectToNamedPort(const DeviceState &state);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Connects to a named IPC port
|
* @brief Send a synchronous IPC request to a service
|
||||||
* @url https://switchbrew.org/wiki/SVC#ConnectToNamedPort
|
* @url https://switchbrew.org/wiki/SVC#SendSyncRequest
|
||||||
*/
|
*/
|
||||||
void ConnectToNamedPort(const DeviceState &state);
|
void SendSyncRequest(const DeviceState &state);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Send a synchronous IPC request to a service
|
* @brief Retrieves the PID of a specific thread
|
||||||
* @url https://switchbrew.org/wiki/SVC#SendSyncRequest
|
* @url https://switchbrew.org/wiki/SVC#GetThreadId
|
||||||
*/
|
*/
|
||||||
void SendSyncRequest(const DeviceState &state);
|
void GetThreadId(const DeviceState &state);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Retrieves the PID of a specific thread
|
* @brief Outputs a debug string
|
||||||
* @url https://switchbrew.org/wiki/SVC#GetThreadId
|
* @url https://switchbrew.org/wiki/SVC#OutputDebugString
|
||||||
*/
|
*/
|
||||||
void GetThreadId(const DeviceState &state);
|
void OutputDebugString(const DeviceState &state);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Outputs a debug string
|
* @brief Retrieves a piece of information
|
||||||
* @url https://switchbrew.org/wiki/SVC#OutputDebugString
|
* @url https://switchbrew.org/wiki/SVC#GetInfo
|
||||||
*/
|
*/
|
||||||
void OutputDebugString(const DeviceState &state);
|
void GetInfo(const DeviceState &state);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Retrieves a piece of information
|
* @brief Maps physical memory to a part of virtual memory
|
||||||
* @url https://switchbrew.org/wiki/SVC#GetInfo
|
* @url https://switchbrew.org/wiki/SVC#MapPhysicalMemory
|
||||||
*/
|
*/
|
||||||
void GetInfo(const DeviceState &state);
|
void MapPhysicalMemory(const DeviceState &state);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The SVC Table maps all SVCs to their corresponding functions
|
* @brief Unmaps previously mapped physical memory
|
||||||
*/
|
* @url https://switchbrew.org/wiki/SVC#UnmapPhysicalMemory
|
||||||
static std::array<void (*)(const DeviceState &), 0x80> SvcTable{
|
*/
|
||||||
nullptr, // 0x00 (Does not exist)
|
void UnmapPhysicalMemory(const DeviceState &state);
|
||||||
SetHeapSize, // 0x01
|
|
||||||
nullptr, // 0x02
|
/**
|
||||||
SetMemoryAttribute, // 0x03
|
* @brief The SVC Table maps all SVCs to their corresponding functions
|
||||||
MapMemory, // 0x04
|
*/
|
||||||
UnmapMemory, // 0x05
|
static std::array<void (*)(const DeviceState &), 0x80> SvcTable{
|
||||||
QueryMemory, // 0x06
|
nullptr, // 0x00 (Does not exist)
|
||||||
ExitProcess, // 0x07
|
SetHeapSize, // 0x01
|
||||||
CreateThread, // 0x08
|
nullptr, // 0x02
|
||||||
StartThread, // 0x09
|
SetMemoryAttribute, // 0x03
|
||||||
ExitThread, // 0x0A
|
MapMemory, // 0x04
|
||||||
SleepThread, // 0x0B
|
UnmapMemory, // 0x05
|
||||||
GetThreadPriority, // 0x0C
|
QueryMemory, // 0x06
|
||||||
SetThreadPriority, // 0x0D
|
ExitProcess, // 0x07
|
||||||
nullptr, // 0x0E
|
CreateThread, // 0x08
|
||||||
nullptr, // 0x0F
|
StartThread, // 0x09
|
||||||
nullptr, // 0x10
|
ExitThread, // 0x0A
|
||||||
nullptr, // 0x11
|
SleepThread, // 0x0B
|
||||||
ClearEvent, // 0x12
|
GetThreadPriority, // 0x0C
|
||||||
MapSharedMemory, // 0x13
|
SetThreadPriority, // 0x0D
|
||||||
nullptr, // 0x14
|
nullptr, // 0x0E
|
||||||
CreateTransferMemory, // 0x15
|
nullptr, // 0x0F
|
||||||
CloseHandle, // 0x16
|
nullptr, // 0x10
|
||||||
ResetSignal, // 0x17
|
nullptr, // 0x11
|
||||||
WaitSynchronization, // 0x18
|
ClearEvent, // 0x12
|
||||||
CancelSynchronization, // 0x19
|
MapSharedMemory, // 0x13
|
||||||
ArbitrateLock, // 0x1A
|
nullptr, // 0x14
|
||||||
ArbitrateUnlock, // 0x1B
|
CreateTransferMemory, // 0x15
|
||||||
WaitProcessWideKeyAtomic, // 0x1C
|
CloseHandle, // 0x16
|
||||||
SignalProcessWideKey, // 0x1D
|
ResetSignal, // 0x17
|
||||||
GetSystemTick, // 0x1E
|
WaitSynchronization, // 0x18
|
||||||
ConnectToNamedPort, // 0x1F
|
CancelSynchronization, // 0x19
|
||||||
nullptr, // 0x20
|
ArbitrateLock, // 0x1A
|
||||||
SendSyncRequest, // 0x21
|
ArbitrateUnlock, // 0x1B
|
||||||
nullptr, // 0x22
|
WaitProcessWideKeyAtomic, // 0x1C
|
||||||
nullptr, // 0x23
|
SignalProcessWideKey, // 0x1D
|
||||||
nullptr, // 0x24
|
GetSystemTick, // 0x1E
|
||||||
GetThreadId, // 0x25
|
ConnectToNamedPort, // 0x1F
|
||||||
nullptr, // 0x26
|
nullptr, // 0x20
|
||||||
OutputDebugString, // 0x27
|
SendSyncRequest, // 0x21
|
||||||
nullptr, // 0x28
|
nullptr, // 0x22
|
||||||
GetInfo, // 0x29
|
nullptr, // 0x23
|
||||||
nullptr, // 0x2A
|
nullptr, // 0x24
|
||||||
nullptr, // 0x2B
|
GetThreadId, // 0x25
|
||||||
nullptr, // 0x2C
|
nullptr, // 0x26
|
||||||
nullptr, // 0x2D
|
OutputDebugString, // 0x27
|
||||||
nullptr, // 0x2E
|
nullptr, // 0x28
|
||||||
nullptr, // 0x2F
|
GetInfo, // 0x29
|
||||||
nullptr, // 0x30
|
nullptr, // 0x2A
|
||||||
nullptr, // 0x31
|
nullptr, // 0x2B
|
||||||
nullptr, // 0x32
|
MapPhysicalMemory, // 0x2C
|
||||||
nullptr, // 0x33
|
UnmapPhysicalMemory, // 0x2D
|
||||||
nullptr, // 0x34
|
nullptr, // 0x2E
|
||||||
nullptr, // 0x35
|
nullptr, // 0x2F
|
||||||
nullptr, // 0x36
|
nullptr, // 0x30
|
||||||
nullptr, // 0x37
|
nullptr, // 0x31
|
||||||
nullptr, // 0x38
|
nullptr, // 0x32
|
||||||
nullptr, // 0x39
|
nullptr, // 0x33
|
||||||
nullptr, // 0x3A
|
nullptr, // 0x34
|
||||||
nullptr, // 0x3B
|
nullptr, // 0x35
|
||||||
nullptr, // 0x3C
|
nullptr, // 0x36
|
||||||
nullptr, // 0x3D
|
nullptr, // 0x37
|
||||||
nullptr, // 0x3E
|
nullptr, // 0x38
|
||||||
nullptr, // 0x3F
|
nullptr, // 0x39
|
||||||
nullptr, // 0x40
|
nullptr, // 0x3A
|
||||||
nullptr, // 0x41
|
nullptr, // 0x3B
|
||||||
nullptr, // 0x42
|
nullptr, // 0x3C
|
||||||
nullptr, // 0x43
|
nullptr, // 0x3D
|
||||||
nullptr, // 0x44
|
nullptr, // 0x3E
|
||||||
nullptr, // 0x45
|
nullptr, // 0x3F
|
||||||
nullptr, // 0x46
|
nullptr, // 0x40
|
||||||
nullptr, // 0x47
|
nullptr, // 0x41
|
||||||
nullptr, // 0x48
|
nullptr, // 0x42
|
||||||
nullptr, // 0x49
|
nullptr, // 0x43
|
||||||
nullptr, // 0x4A
|
nullptr, // 0x44
|
||||||
nullptr, // 0x4B
|
nullptr, // 0x45
|
||||||
nullptr, // 0x4C
|
nullptr, // 0x46
|
||||||
nullptr, // 0x4D
|
nullptr, // 0x47
|
||||||
nullptr, // 0x4E
|
nullptr, // 0x48
|
||||||
nullptr, // 0x4F
|
nullptr, // 0x49
|
||||||
nullptr, // 0x50
|
nullptr, // 0x4A
|
||||||
nullptr, // 0x51
|
nullptr, // 0x4B
|
||||||
nullptr, // 0x52
|
nullptr, // 0x4C
|
||||||
nullptr, // 0x53
|
nullptr, // 0x4D
|
||||||
nullptr, // 0x54
|
nullptr, // 0x4E
|
||||||
nullptr, // 0x55
|
nullptr, // 0x4F
|
||||||
nullptr, // 0x56
|
nullptr, // 0x50
|
||||||
nullptr, // 0x57
|
nullptr, // 0x51
|
||||||
nullptr, // 0x58
|
nullptr, // 0x52
|
||||||
nullptr, // 0x59
|
nullptr, // 0x53
|
||||||
nullptr, // 0x5A
|
nullptr, // 0x54
|
||||||
nullptr, // 0x5B
|
nullptr, // 0x55
|
||||||
nullptr, // 0x5C
|
nullptr, // 0x56
|
||||||
nullptr, // 0x5D
|
nullptr, // 0x57
|
||||||
nullptr, // 0x5E
|
nullptr, // 0x58
|
||||||
nullptr, // 0x5F
|
nullptr, // 0x59
|
||||||
nullptr, // 0x60
|
nullptr, // 0x5A
|
||||||
nullptr, // 0x61
|
nullptr, // 0x5B
|
||||||
nullptr, // 0x62
|
nullptr, // 0x5C
|
||||||
nullptr, // 0x63
|
nullptr, // 0x5D
|
||||||
nullptr, // 0x64
|
nullptr, // 0x5E
|
||||||
nullptr, // 0x65
|
nullptr, // 0x5F
|
||||||
nullptr, // 0x66
|
nullptr, // 0x60
|
||||||
nullptr, // 0x67
|
nullptr, // 0x61
|
||||||
nullptr, // 0x68
|
nullptr, // 0x62
|
||||||
nullptr, // 0x69
|
nullptr, // 0x63
|
||||||
nullptr, // 0x6A
|
nullptr, // 0x64
|
||||||
nullptr, // 0x6B
|
nullptr, // 0x65
|
||||||
nullptr, // 0x6C
|
nullptr, // 0x66
|
||||||
nullptr, // 0x6D
|
nullptr, // 0x67
|
||||||
nullptr, // 0x6E
|
nullptr, // 0x68
|
||||||
nullptr, // 0x6F
|
nullptr, // 0x69
|
||||||
nullptr, // 0x70
|
nullptr, // 0x6A
|
||||||
nullptr, // 0x71
|
nullptr, // 0x6B
|
||||||
nullptr, // 0x72
|
nullptr, // 0x6C
|
||||||
nullptr, // 0x73
|
nullptr, // 0x6D
|
||||||
nullptr, // 0x74
|
nullptr, // 0x6E
|
||||||
nullptr, // 0x75
|
nullptr, // 0x6F
|
||||||
nullptr, // 0x76
|
nullptr, // 0x70
|
||||||
nullptr, // 0x77
|
nullptr, // 0x71
|
||||||
nullptr, // 0x78
|
nullptr, // 0x72
|
||||||
nullptr, // 0x79
|
nullptr, // 0x73
|
||||||
nullptr, // 0x7A
|
nullptr, // 0x74
|
||||||
nullptr, // 0x7B
|
nullptr, // 0x75
|
||||||
nullptr, // 0x7C
|
nullptr, // 0x76
|
||||||
nullptr, // 0x7D
|
nullptr, // 0x77
|
||||||
nullptr, // 0x7E
|
nullptr, // 0x78
|
||||||
nullptr // 0x7F
|
nullptr, // 0x79
|
||||||
};
|
nullptr, // 0x7A
|
||||||
}
|
nullptr, // 0x7B
|
||||||
|
nullptr, // 0x7C
|
||||||
|
nullptr, // 0x7D
|
||||||
|
nullptr, // 0x7E
|
||||||
|
nullptr // 0x7F
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
#include "KProcess.h"
|
#include "KProcess.h"
|
||||||
|
|
||||||
namespace skyline::kernel::type {
|
namespace skyline::kernel::type {
|
||||||
KPrivateMemory::KPrivateMemory(const DeviceState &state, u8* ptr, size_t size, memory::Permission permission, memory::MemoryState memState) : ptr(ptr), size(size), permission(permission), memState(memState), KMemory(state, KType::KPrivateMemory) {
|
KPrivateMemory::KPrivateMemory(const DeviceState &state, u8 *ptr, size_t size, memory::Permission permission, memory::MemoryState memState) : ptr(ptr), size(size), permission(permission), memState(memState), KMemory(state, KType::KPrivateMemory) {
|
||||||
if (!state.process->memory.base.IsInside(ptr) || !state.process->memory.base.IsInside(ptr + 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);
|
throw exception("KPrivateMemory allocation isn't inside guest address space: 0x{:X} - 0x{:X}", ptr, ptr + size);
|
||||||
if (!util::PageAligned(ptr) || !util::PageAligned(size))
|
if (!util::PageAligned(ptr) || !util::PageAligned(size))
|
||||||
@ -47,7 +47,20 @@ namespace skyline::kernel::type {
|
|||||||
size = nSize;
|
size = nSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
void KPrivateMemory::UpdatePermission(u8* ptr, size_t size, memory::Permission permission) {
|
void KPrivateMemory::Remap(u8 *nPtr, size_t nSize) {
|
||||||
|
if (!state.process->memory.base.IsInside(nPtr) || !state.process->memory.base.IsInside(nPtr + nSize))
|
||||||
|
throw exception("KPrivateMemory remapping isn't inside guest address space: 0x{:X} - 0x{:X}", nPtr, nPtr + nSize);
|
||||||
|
if (!util::PageAligned(nPtr) || !util::PageAligned(nSize))
|
||||||
|
throw exception("KPrivateMemory remapping isn't page-aligned: 0x{:X} - 0x{:X} (0x{:X})", nPtr, nPtr + nSize, nSize);
|
||||||
|
|
||||||
|
if (mprotect(ptr, size, PROT_NONE) < 0)
|
||||||
|
throw exception("An occurred while remapping private memory: {}", strerror(errno));
|
||||||
|
|
||||||
|
if (mprotect(nPtr, nSize, PROT_NONE) < 0)
|
||||||
|
throw exception("An occurred while remapping private memory: {}", strerror(errno));
|
||||||
|
}
|
||||||
|
|
||||||
|
void KPrivateMemory::UpdatePermission(u8 *ptr, size_t size, memory::Permission permission) {
|
||||||
ptr = std::clamp(ptr, this->ptr, this->ptr + this->size);
|
ptr = std::clamp(ptr, this->ptr, this->ptr + this->size);
|
||||||
size = std::min(size, static_cast<size_t>((this->ptr + this->size) - ptr));
|
size = std::min(size, static_cast<size_t>((this->ptr + this->size) - ptr));
|
||||||
|
|
||||||
|
@ -24,6 +24,11 @@ namespace skyline::kernel::type {
|
|||||||
|
|
||||||
void Resize(size_t size);
|
void Resize(size_t size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @note Only contents of any overlapping regions will be retained
|
||||||
|
*/
|
||||||
|
void Remap(u8* ptr, size_t size);
|
||||||
|
|
||||||
inline span<u8> Get() override {
|
inline span<u8> Get() override {
|
||||||
return span(ptr, size);
|
return span(ptr, size);
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,9 @@ namespace skyline {
|
|||||||
* @brief KProcess manages process-global state such as memory, kernel handles allocated to the process and synchronization primitives
|
* @brief KProcess manages process-global state such as memory, kernel handles allocated to the process and synchronization primitives
|
||||||
*/
|
*/
|
||||||
class KProcess : public KSyncObject {
|
class KProcess : public KSyncObject {
|
||||||
|
public:
|
||||||
|
MemoryManager memory; // This is here to ensure it is present during the destruction of dependent objects
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<std::shared_ptr<KObject>> handles;
|
std::vector<std::shared_ptr<KObject>> handles;
|
||||||
std::shared_mutex handleMutex;
|
std::shared_mutex handleMutex;
|
||||||
@ -63,7 +66,6 @@ namespace skyline {
|
|||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
MemoryManager memory;
|
|
||||||
std::shared_ptr<KPrivateMemory> mainThreadStack;
|
std::shared_ptr<KPrivateMemory> mainThreadStack;
|
||||||
std::shared_ptr<KPrivateMemory> heap;
|
std::shared_ptr<KPrivateMemory> heap;
|
||||||
std::vector<std::shared_ptr<KThread>> threads;
|
std::vector<std::shared_ptr<KThread>> threads;
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
// SPDX-License-Identifier: MPL-2.0
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
// Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
// Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
||||||
|
|
||||||
#include <nce.h>
|
|
||||||
#include <kernel/types/KProcess.h>
|
#include <kernel/types/KProcess.h>
|
||||||
#include "nso.h"
|
#include "nso.h"
|
||||||
#include "nca.h"
|
#include "nca.h"
|
||||||
|
@ -35,7 +35,9 @@ namespace skyline::nce {
|
|||||||
|
|
||||||
void NCE::SignalHandler(int signal, siginfo *, void *context) {
|
void NCE::SignalHandler(int signal, siginfo *, void *context) {
|
||||||
ThreadContext *threadCtx;
|
ThreadContext *threadCtx;
|
||||||
asm("MRS %0, TPIDR_EL0":"=r"(threadCtx));
|
asm volatile("MRS %x0, TPIDR_EL0":"=r"(threadCtx));
|
||||||
|
asm volatile("MSR TPIDR_EL0, %x0"::"r"(threadCtx->hostTpidrEl0));
|
||||||
|
|
||||||
const auto &state{*threadCtx->state};
|
const auto &state{*threadCtx->state};
|
||||||
state.logger->Warn("Thread #{} has crashed due to signal: {}", state.thread->id, strsignal(signal));
|
state.logger->Warn("Thread #{} has crashed due to signal: {}", state.thread->id, strsignal(signal));
|
||||||
|
|
||||||
@ -68,9 +70,11 @@ namespace skyline::nce {
|
|||||||
for (u8 index{}; index < ((sizeof(mcontext_t::regs) / sizeof(u64)) - 2); index += 2)
|
for (u8 index{}; index < ((sizeof(mcontext_t::regs) / sizeof(u64)) - 2); index += 2)
|
||||||
cpuContext += fmt::format("\n{}X{}: 0x{:<16X} {}{}: 0x{:X}", index < 10 ? ' ' : '\0', index, ctx.regs[index], index < 10 ? ' ' : '\0', index + 1, ctx.regs[index]);
|
cpuContext += fmt::format("\n{}X{}: 0x{:<16X} {}{}: 0x{:X}", index < 10 ? ' ' : '\0', index, ctx.regs[index], index < 10 ? ' ' : '\0', index + 1, ctx.regs[index]);
|
||||||
|
|
||||||
state.logger->Debug("Process Trace:{}", trace);
|
state.logger->Warn("Process Trace:{}", trace);
|
||||||
state.logger->Debug("Raw Instructions: 0x{}", raw);
|
state.logger->Warn("Raw Instructions: 0x{}", raw);
|
||||||
state.logger->Debug("CPU Context:{}", cpuContext);
|
state.logger->Warn("CPU Context:{}", cpuContext);
|
||||||
|
|
||||||
|
asm volatile("MSR TPIDR_EL0, %x0"::"r"(threadCtx));
|
||||||
}
|
}
|
||||||
|
|
||||||
NCE::NCE(DeviceState &state) : state(state) {}
|
NCE::NCE(DeviceState &state) : state(state) {}
|
||||||
|
@ -8,6 +8,20 @@
|
|||||||
namespace skyline {
|
namespace skyline {
|
||||||
struct DeviceState;
|
struct DeviceState;
|
||||||
namespace nce {
|
namespace nce {
|
||||||
|
struct WRegister {
|
||||||
|
u32 lower;
|
||||||
|
u32 upper;
|
||||||
|
|
||||||
|
constexpr operator u32() {
|
||||||
|
return lower;
|
||||||
|
}
|
||||||
|
|
||||||
|
void operator=(u32 value) {
|
||||||
|
lower = value;
|
||||||
|
upper = 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The state of callee-saved general purpose registers in the guest
|
* @brief The state of callee-saved general purpose registers in the guest
|
||||||
* @note Read about ARMv8 registers here: https://developer.arm.com/architectures/learn-the-architecture/armv8-a-instruction-set-architecture/registers-in-aarch64-general-purpose-registers
|
* @note Read about ARMv8 registers here: https://developer.arm.com/architectures/learn-the-architecture/armv8-a-instruction-set-architecture/registers-in-aarch64-general-purpose-registers
|
||||||
@ -37,44 +51,25 @@ namespace skyline {
|
|||||||
u64 x18;
|
u64 x18;
|
||||||
};
|
};
|
||||||
struct {
|
struct {
|
||||||
u32 w0;
|
WRegister w0;
|
||||||
u32 __w0__;
|
WRegister w1;
|
||||||
u32 w1;
|
WRegister w2;
|
||||||
u32 __w1__;
|
WRegister w3;
|
||||||
u32 w2;
|
WRegister w4;
|
||||||
u32 __w2__;
|
WRegister w5;
|
||||||
u32 w3;
|
WRegister w6;
|
||||||
u32 __w3__;
|
WRegister w7;
|
||||||
u32 w4;
|
WRegister w8;
|
||||||
u32 __w4__;
|
WRegister w9;
|
||||||
u32 w5;
|
WRegister w10;
|
||||||
u32 __w5__;
|
WRegister w11;
|
||||||
u32 w6;
|
WRegister w12;
|
||||||
u32 __w6__;
|
WRegister w13;
|
||||||
u32 w7;
|
WRegister w14;
|
||||||
u32 __w7__;
|
WRegister w15;
|
||||||
u32 w8;
|
WRegister w16;
|
||||||
u32 __w8__;
|
WRegister w17;
|
||||||
u32 w9;
|
WRegister w18;
|
||||||
u32 __w9__;
|
|
||||||
u32 w10;
|
|
||||||
u32 __w10__;
|
|
||||||
u32 w11;
|
|
||||||
u32 __w11__;
|
|
||||||
u32 w12;
|
|
||||||
u32 __w12__;
|
|
||||||
u32 w13;
|
|
||||||
u32 __w13__;
|
|
||||||
u32 w14;
|
|
||||||
u32 __w14__;
|
|
||||||
u32 w15;
|
|
||||||
u32 __w15__;
|
|
||||||
u32 w16;
|
|
||||||
u32 __w16__;
|
|
||||||
u32 w17;
|
|
||||||
u32 __w17__;
|
|
||||||
u32 w18;
|
|
||||||
u32 __w18__;
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user