Refactor OS/Kernel

This refactors the OS/Kernel by adding spacing and fixing/adding comments in some cases, in addition to some other minor fixes here and there.
This commit is contained in:
◱ PixelyIon 2020-03-26 00:27:05 +05:30 committed by ◱ PixelyIon
parent 773ee25e5a
commit 9f0ad46903
9 changed files with 256 additions and 27 deletions

View File

@ -6,25 +6,30 @@ namespace skyline::kernel {
auto chunk = std::upper_bound(chunkList.begin(), chunkList.end(), address, [](const u64 address, const ChunkDescriptor &chunk) -> bool {
return address < chunk.address;
});
if (chunk-- != chunkList.begin()) {
if ((chunk->address + chunk->size) > address)
return chunk.base();
}
return nullptr;
}
BlockDescriptor *MemoryManager::GetBlock(u64 address, ChunkDescriptor *chunk) {
if (!chunk)
chunk = GetChunk(address);
if (chunk) {
auto block = std::upper_bound(chunk->blockList.begin(), chunk->blockList.end(), address, [](const u64 address, const BlockDescriptor &block) -> bool {
return address < block.address;
});
if (block-- != chunk->blockList.begin()) {
if ((block->address + block->size) > address)
return block.base();
}
}
return nullptr;
}
@ -32,11 +37,14 @@ namespace skyline::kernel {
auto upperChunk = std::upper_bound(chunkList.begin(), chunkList.end(), chunk.address, [](const u64 address, const ChunkDescriptor &chunk) -> bool {
return address < chunk.address;
});
if (upperChunk != chunkList.begin()) {
auto lowerChunk = std::prev(upperChunk);
if (lowerChunk->address + lowerChunk->size > chunk.address)
throw exception("InsertChunk: Descriptors are colliding: 0x{:X} - 0x{:X} and 0x{:X} - 0x{:X}", lowerChunk->address, lowerChunk->address + lowerChunk->size, chunk.address, chunk.address + chunk.size);
}
chunkList.insert(upperChunk, chunk);
}
@ -55,24 +63,29 @@ namespace skyline::kernel {
} else if (size > chunk->size) {
auto begin = chunk->blockList.begin();
auto end = std::prev(chunk->blockList.end());
BlockDescriptor block{
.address = (end->address + end->size),
.size = (chunk->address + size) - (end->address + end->size),
.permission = begin->permission,
.attributes = begin->attributes,
};
chunk->blockList.push_back(block);
} else if (size < chunk->size) {
auto endAddress = chunk->address + size;
for (auto block = chunk->blockList.begin(), end = chunk->blockList.end(); block != end;) {
if (block->address > endAddress)
block = chunk->blockList.erase(block);
else
++block;
}
auto end = std::prev(chunk->blockList.end());
end->size = endAddress - end->address;
}
chunk->size = size;
}
@ -87,16 +100,19 @@ namespace skyline::kernel {
auto endBlock = *iter;
endBlock.address = (block.address + block.size);
endBlock.size = (iter->address + iter->size) - endBlock.address;
iter->size = iter->address - block.address;
chunk->blockList.insert(std::next(iter), {block, endBlock});
}
} else if (std::next(iter) != chunk->blockList.end()) {
auto nextIter = std::next(iter);
auto nextEnd = nextIter->address + nextIter->size;
if(nextEnd > block.address) {
iter->size = block.address - iter->address;
nextIter->address = block.address + block.size;
nextIter->size = nextEnd - nextIter->address;
chunk->blockList.insert(nextIter, block);
} else {
throw exception("InsertBlock: Inserting block across more than one block is not allowed");
@ -107,6 +123,7 @@ namespace skyline::kernel {
return;
}
}
throw exception("InsertBlock: Block offset not present within current block list");
}
@ -114,6 +131,7 @@ namespace skyline::kernel {
switch (type) {
case memory::AddressSpaceType::AddressSpace32Bit:
throw exception("32-bit address spaces are not supported");
case memory::AddressSpaceType::AddressSpace36Bit: {
base.address = constant::BaseAddress;
base.size = 0xFF8000000;
@ -131,6 +149,7 @@ namespace skyline::kernel {
tlsIo.size = 0;
break;
}
case memory::AddressSpaceType::AddressSpace39Bit: {
base.address = constant::BaseAddress;
base.size = 0x7FF8000000;
@ -147,6 +166,7 @@ namespace skyline::kernel {
break;
}
}
state.logger->Debug("Region Map:\nCode Region: 0x{:X} - 0x{:X} (Size: 0x{:X})\nAlias Region: 0x{:X} - 0x{:X} (Size: 0x{:X})\nHeap Region: 0x{:X} - 0x{:X} (Size: 0x{:X})\nStack Region: 0x{:X} - 0x{:X} (Size: 0x{:X})\nTLS/IO Region: 0x{:X} - 0x{:X} (Size: 0x{:X})", code.address, code.address + code.size, code.size, alias.address, alias.address + alias.size, alias.size, heap.address, heap
.address + heap.size, heap.size, stack.address, stack.address + stack.size, stack.size, tlsIo.address, tlsIo.address + tlsIo.size, tlsIo.size);
}
@ -155,8 +175,10 @@ namespace skyline::kernel {
std::optional<DescriptorPack> MemoryManager::Get(u64 address) {
auto chunk = GetChunk(address);
if (chunk)
return DescriptorPack{*GetBlock(address, chunk), *chunk};
return std::nullopt;
}
@ -179,8 +201,10 @@ namespace skyline::kernel {
size_t MemoryManager::GetProgramSize() {
size_t size = 0;
for (const auto &chunk : chunkList)
size += chunk.size;
return size;
}
}

View File

@ -4,7 +4,7 @@
namespace skyline::kernel::svc {
void SetHeapSize(DeviceState &state) {
constexpr auto heapSizeAlign = 0x200000; // The heap size has to be a multiple of this value
const u32 size = state.ctx->registers.w1;
auto size = state.ctx->registers.w1;
if (size % heapSizeAlign != 0) {
state.ctx->registers.w0 = constant::status::InvSize;
@ -24,26 +24,30 @@ namespace skyline::kernel::svc {
}
void SetMemoryAttribute(DeviceState &state) {
const u64 address = state.ctx->registers.x0;
auto address = state.ctx->registers.x0;
if (!utils::PageAligned(address)) {
state.ctx->registers.w0 = constant::status::InvAddress;
state.logger->Warn("svcSetMemoryAttribute: 'address' not page aligned: 0x{:X}", address);
return;
}
const u64 size = state.ctx->registers.x1;
auto size = state.ctx->registers.x1;
if (!utils::PageAligned(size)) {
state.ctx->registers.w0 = constant::status::InvSize;
state.logger->Warn("svcSetMemoryAttribute: 'size' {}: 0x{:X}", size ? "not page aligned" : "is zero", size);
return;
}
memory::MemoryAttribute mask{.value = state.ctx->registers.w2};
memory::MemoryAttribute value{.value = state.ctx->registers.w3};
u32 maskedValue = mask.value | value.value;
auto maskedValue = mask.value | value.value;
if (maskedValue != mask.value || !mask.isUncached || mask.isDeviceShared || mask.isBorrowed || mask.isIpcLocked) {
state.ctx->registers.w0 = constant::status::InvCombination;
state.logger->Warn("svcSetMemoryAttribute: 'mask' invalid: 0x{:X}, 0x{:X}", mask.value, value.value);
return;
}
auto chunk = state.os->memory.GetChunk(address);
auto block = state.os->memory.GetBlock(address);
if (!chunk || !block) {
@ -51,37 +55,44 @@ namespace skyline::kernel::svc {
state.logger->Warn("svcSetMemoryAttribute: Cannot find memory region: 0x{:X}", address);
return;
}
if (!chunk->state.attributeChangeAllowed) {
state.ctx->registers.w0 = constant::status::InvState;
state.logger->Warn("svcSetMemoryAttribute: Attribute change not allowed for chunk: 0x{:X}", address);
return;
}
block->attributes.isUncached = value.isUncached;
MemoryManager::InsertBlock(chunk, *block);
state.logger->Debug("svcSetMemoryAttribute: Set caching to {} at 0x{:X} for 0x{:X} bytes", !block->attributes.isUncached, address, size);
state.ctx->registers.w0 = constant::status::Success;
}
void MapMemory(DeviceState &state) {
const u64 destination = state.ctx->registers.x0;
const u64 source = state.ctx->registers.x1;
const u64 size = state.ctx->registers.x2;
auto destination = state.ctx->registers.x0;
auto source = state.ctx->registers.x1;
auto size = state.ctx->registers.x2;
if (!utils::PageAligned(destination) || !utils::PageAligned(source)) {
state.ctx->registers.w0 = constant::status::InvAddress;
state.logger->Warn("svcMapMemory: Addresses not page aligned: Source: 0x{:X}, Destination: 0x{:X} (Size: 0x{:X} bytes)", source, destination, size);
return;
}
if (!utils::PageAligned(size)) {
state.ctx->registers.w0 = constant::status::InvSize;
state.logger->Warn("svcMapMemory: 'size' {}: 0x{:X}", size ? "not page aligned" : "is zero", size);
return;
}
auto stack = state.os->memory.GetRegion(memory::Regions::Stack);
if (!stack.IsInside(destination)) {
state.ctx->registers.w0 = constant::status::InvMemRange;
state.logger->Warn("svcMapMemory: Destination not within stack region: Source: 0x{:X}, Destination: 0x{:X} (Size: 0x{:X} bytes)", source, destination, size);
return;
}
auto descriptor = state.os->memory.Get(source);
if (!descriptor) {
state.ctx->registers.w0 = constant::status::InvAddress;
@ -93,36 +104,44 @@ namespace skyline::kernel::svc {
state.logger->Warn("svcMapMemory: Source doesn't allow usage of svcMapMemory: Source: 0x{:X}, Destination: 0x{:X} (Size: 0x{:X} bytes) 0x{:X}", source, destination, size, descriptor->chunk.state.value);
return;
}
state.process->NewHandle<type::KPrivateMemory>(destination, size, descriptor->block.permission, memory::states::Stack);
state.process->CopyMemory(source, destination, size);
auto object = state.process->GetMemoryObject(source);
if (!object)
throw exception("svcMapMemory: Cannot find memory object in handle table for address 0x{:X}", source);
object->item->UpdatePermission(source, size, {false, false, false});
state.logger->Debug("svcMapMemory: Mapped range 0x{:X} - 0x{:X} to 0x{:X} - 0x{:X} (Size: 0x{:X} bytes)", source, source + size, destination, destination + size, size);
state.ctx->registers.w0 = constant::status::Success;
}
void UnmapMemory(DeviceState &state) {
const u64 source = state.ctx->registers.x0;
const u64 destination = state.ctx->registers.x1;
const u64 size = state.ctx->registers.x2;
auto source = state.ctx->registers.x0;
auto destination = state.ctx->registers.x1;
auto size = state.ctx->registers.x2;
if (!utils::PageAligned(destination) || !utils::PageAligned(source)) {
state.ctx->registers.w0 = constant::status::InvAddress;
state.logger->Warn("svcUnmapMemory: Addresses not page aligned: Source: 0x{:X}, Destination: 0x{:X} (Size: 0x{:X} bytes)", source, destination, size);
return;
}
if (!utils::PageAligned(size)) {
state.ctx->registers.w0 = constant::status::InvSize;
state.logger->Warn("svcUnmapMemory: 'size' {}: 0x{:X}", size ? "not page aligned" : "is zero", size);
return;
}
auto stack = state.os->memory.GetRegion(memory::Regions::Stack);
if (!stack.IsInside(source)) {
state.ctx->registers.w0 = constant::status::InvMemRange;
state.logger->Warn("svcUnmapMemory: Source not within stack region: Source: 0x{:X}, Destination: 0x{:X} (Size: 0x{:X} bytes)", source, destination, size);
return;
}
auto sourceDesc = state.os->memory.Get(source);
auto destDesc = state.os->memory.Get(destination);
if (!sourceDesc || !destDesc) {
@ -130,28 +149,37 @@ namespace skyline::kernel::svc {
state.logger->Warn("svcUnmapMemory: Addresses have no descriptor: Source: 0x{:X}, Destination: 0x{:X} (Size: 0x{:X} bytes)", source, destination, size);
return;
}
if (!destDesc->chunk.state.mapAllowed) {
state.ctx->registers.w0 = constant::status::InvState;
state.logger->Warn("svcUnmapMemory: Destination doesn't allow usage of svcMapMemory: Source: 0x{:X}, Destination: 0x{:X} (Size: 0x{:X} bytes) 0x{:X}", source, destination, size, destDesc->chunk.state.value);
return;
}
auto destObject = state.process->GetMemoryObject(destination);
if (!destObject)
throw exception("svcUnmapMemory: Cannot find destination memory object in handle table for address 0x{:X}", destination);
destObject->item->UpdatePermission(destination, size, sourceDesc->block.permission);
state.process->CopyMemory(destination, source, size);
auto sourceObject = state.process->GetMemoryObject(destination);
if (!sourceObject)
throw exception("svcUnmapMemory: Cannot find source memory object in handle table for address 0x{:X}", source);
state.process->DeleteHandle(sourceObject->handle);
state.logger->Debug("svcUnmapMemory: Unmapped range 0x{:X} - 0x{:X} to 0x{:X} - 0x{:X} (Size: 0x{:X} bytes)", source, source + size, destination, destination + size, size);
state.ctx->registers.w0 = constant::status::Success;
}
void QueryMemory(DeviceState &state) {
u64 address = state.ctx->registers.x2;
memory::MemoryInfo memInfo{};
auto address = state.ctx->registers.x2;
auto descriptor = state.os->memory.Get(address);
if (descriptor) {
memInfo = {
.address = descriptor->block.address,
@ -162,18 +190,23 @@ namespace skyline::kernel::svc {
.deviceRefCount = 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>(descriptor->block.attributes.isUncached), descriptor->block.permission.r ? "R" : "-", descriptor->block.permission.w ? "W" : "-", descriptor->block.permission.x ? "X" : "-");
} else {
auto region = state.os->memory.GetRegion(memory::Regions::Base);
auto baseEnd = region.address + region.size;
memInfo = {
.address = region.address,
.size = ~baseEnd + 1,
.type = static_cast<u32>(memory::MemoryType::Unmapped),
};
state.logger->Debug("svcQueryMemory: Cannot find block of address: 0x{:X}", address);
}
state.process->WriteMemory(memInfo, state.ctx->registers.x0);
state.ctx->registers.w0 = constant::status::Success;
}
@ -187,13 +220,16 @@ namespace skyline::kernel::svc {
u64 entryArgument = state.ctx->registers.x2;
u64 stackTop = state.ctx->registers.x3;
u8 priority = static_cast<u8>(state.ctx->registers.w4);
if ((priority < constant::SwitchPriority.first) || (priority > constant::SwitchPriority.second)) {
state.ctx->registers.w0 = constant::status::InvAddress;
state.logger->Warn("svcCreateThread: 'priority' invalid: {}", priority);
return;
}
auto thread = state.process->CreateThread(entryAddress, entryArgument, stackTop, priority);
state.logger->Debug("svcCreateThread: Created thread with handle 0x{:X} (Entry Point: 0x{:X}, Argument: 0x{:X}, Stack Pointer: 0x{:X}, Priority: {}, PID: {})", thread->handle, entryAddress, entryArgument, stackTop, priority, thread->pid);
state.ctx->registers.w1 = thread->handle;
state.ctx->registers.w0 = constant::status::Success;
}
@ -218,6 +254,7 @@ namespace skyline::kernel::svc {
void SleepThread(DeviceState &state) {
auto in = state.ctx->registers.x0;
switch (in) {
case 0:
case 1:
@ -239,6 +276,7 @@ namespace skyline::kernel::svc {
try {
auto priority = state.process->GetHandle<type::KThread>(handle)->priority;
state.logger->Debug("svcGetThreadPriority: Writing thread priority {}", priority);
state.ctx->registers.w1 = priority;
state.ctx->registers.w0 = constant::status::Success;
} catch (const std::exception &) {
@ -250,6 +288,7 @@ namespace skyline::kernel::svc {
void SetThreadPriority(DeviceState &state) {
auto handle = state.ctx->registers.w0;
auto priority = state.ctx->registers.w1;
try {
state.logger->Debug("svcSetThreadPriority: Setting thread priority to {}", priority);
state.process->GetHandle<type::KThread>(handle)->UpdatePriority(static_cast<u8>(priority));
@ -264,17 +303,20 @@ namespace skyline::kernel::svc {
try {
auto object = state.process->GetHandle<type::KSharedMemory>(state.ctx->registers.w0);
u64 address = state.ctx->registers.x1;
if (!utils::PageAligned(address)) {
state.ctx->registers.w0 = constant::status::InvAddress;
state.logger->Warn("svcMapSharedMemory: 'address' not page aligned: 0x{:X}", address);
return;
}
const u64 size = state.ctx->registers.x2;
auto size = state.ctx->registers.x2;
if (!utils::PageAligned(size)) {
state.ctx->registers.w0 = constant::status::InvSize;
state.logger->Warn("svcMapSharedMemory: 'size' {}: 0x{:X}", size ? "not page aligned" : "is zero", size);
return;
}
u32 perm = state.ctx->registers.w3;
memory::Permission permission = *reinterpret_cast<memory::Permission *>(&perm);
if ((permission.w && !permission.r) || (permission.x && !permission.r)) {
@ -282,8 +324,11 @@ namespace skyline::kernel::svc {
state.ctx->registers.w0 = constant::status::InvPermission;
return;
}
state.logger->Debug("svcMapSharedMemory: Mapping shared memory at 0x{:X} for {} bytes ({}{}{})", address, size, permission.r ? "R" : "-", permission.w ? "W" : "-", permission.x ? "X" : "-");
object->Map(address, size, permission);
state.ctx->registers.w0 = constant::status::Success;
} catch (const std::exception &) {
state.logger->Warn("svcMapSharedMemory: 'handle' invalid: 0x{:X}", state.ctx->registers.w0);
@ -298,12 +343,14 @@ namespace skyline::kernel::svc {
state.logger->Warn("svcCreateTransferMemory: 'address' not page aligned: 0x{:X}", address);
return;
}
u64 size = state.ctx->registers.x2;
if (!utils::PageAligned(size)) {
state.ctx->registers.w0 = constant::status::InvSize;
state.logger->Warn("svcCreateTransferMemory: 'size' {}: 0x{:X}", size ? "not page aligned" : "is zero", size);
return;
}
u32 perm = state.ctx->registers.w3;
memory::Permission permission = *reinterpret_cast<memory::Permission *>(&perm);
if ((permission.w && !permission.r) || (permission.x && !permission.r)) {
@ -311,8 +358,11 @@ namespace skyline::kernel::svc {
state.ctx->registers.w0 = constant::status::InvPermission;
return;
}
state.logger->Debug("svcCreateTransferMemory: Creating transfer memory at 0x{:X} for {} bytes ({}{}{})", address, size, permission.r ? "R" : "-", permission.w ? "W" : "-", permission.x ? "X" : "-");
auto shmem = state.process->NewHandle<type::KTransferMemory>(state.process->pid, address, size, permission);
state.ctx->registers.w0 = constant::status::Success;
state.ctx->registers.w1 = shmem.handle;
}
@ -337,15 +387,18 @@ namespace skyline::kernel::svc {
case (type::KType::KEvent):
std::static_pointer_cast<type::KEvent>(object)->ResetSignal();
break;
case (type::KType::KProcess):
std::static_pointer_cast<type::KProcess>(object)->ResetSignal();
break;
default: {
state.logger->Warn("svcResetSignal: 'handle' type invalid: 0x{:X} ({})", handle, object->objectType);
state.ctx->registers.w0 = constant::status::InvHandle;
return;
}
}
state.logger->Debug("svcResetSignal: Resetting signal: 0x{:X}", handle);
state.ctx->registers.w0 = constant::status::Success;
} catch (const std::out_of_range &) {
@ -357,6 +410,7 @@ namespace skyline::kernel::svc {
void WaitSynchronization(DeviceState &state) {
constexpr auto maxSyncHandles = 0x40; // The total amount of handles that can be passed to WaitSynchronization
auto numHandles = state.ctx->registers.w2;
if (numHandles > maxSyncHandles) {
state.ctx->registers.w0 = constant::status::MaxHandles;
@ -373,7 +427,6 @@ namespace skyline::kernel::svc {
handleStr += fmt::format("* 0x{:X}\n", handle);
auto object = state.process->handles.at(handle);
switch (object->objectType) {
case type::KType::KProcess:
case type::KType::KThread:
@ -394,7 +447,6 @@ namespace skyline::kernel::svc {
state.logger->Debug("svcWaitSynchronization: Waiting on handles:\n{}Timeout: 0x{:X} ns", handleStr, timeout);
auto start = utils::GetTimeNs();
while (true) {
if (state.thread->cancelSync) {
state.thread->cancelSync = false;
@ -437,15 +489,19 @@ namespace skyline::kernel::svc {
state.ctx->registers.w0 = constant::status::InvAddress;
return;
}
auto ownerHandle = state.ctx->registers.w0;
auto requesterHandle = state.ctx->registers.w2;
if (requesterHandle != state.thread->handle)
throw exception("svcWaitProcessWideKeyAtomic: Handle doesn't match current thread: 0x{:X} for thread 0x{:X}", requesterHandle, state.thread->handle);
state.logger->Debug("svcArbitrateLock: Locking mutex at 0x{:X}", address);
if (state.process->MutexLock(address, ownerHandle))
state.logger->Debug("svcArbitrateLock: Locked mutex at 0x{:X}", address);
else
state.logger->Debug("svcArbitrateLock: Owner handle did not match current owner for mutex at 0x{:X}", address);
state.ctx->registers.w0 = constant::status::Success;
}
@ -456,7 +512,9 @@ namespace skyline::kernel::svc {
state.ctx->registers.w0 = constant::status::InvAddress;
return;
}
state.logger->Debug("svcArbitrateUnlock: Unlocking mutex at 0x{:X}", address);
if (state.process->MutexUnlock(address)) {
state.logger->Debug("svcArbitrateUnlock: Unlocked mutex at 0x{:X}", address);
state.ctx->registers.w0 = constant::status::Success;
@ -473,17 +531,21 @@ namespace skyline::kernel::svc {
state.ctx->registers.w0 = constant::status::InvAddress;
return;
}
auto condAddress = state.ctx->registers.x1;
auto handle = state.ctx->registers.w2;
if (handle != state.thread->handle)
throw exception("svcWaitProcessWideKeyAtomic: Handle doesn't match current thread: 0x{:X} for thread 0x{:X}", handle, state.thread->handle);
if (!state.process->MutexUnlock(mtxAddress)) {
state.logger->Debug("WaitProcessWideKeyAtomic: A non-owner thread tried to release a mutex at 0x{:X}", mtxAddress);
state.ctx->registers.w0 = constant::status::InvAddress;
return;
}
auto timeout = state.ctx->registers.x3;
state.logger->Debug("svcWaitProcessWideKeyAtomic: Mutex: 0x{:X}, Conditional-Variable: 0x{:X}, Timeout: {} ns", mtxAddress, condAddress, timeout);
if (state.process->ConditionalVariableWait(condAddress, mtxAddress, timeout)) {
state.logger->Debug("svcWaitProcessWideKeyAtomic: Waited for conditional variable and relocked mutex");
state.ctx->registers.w0 = constant::status::Success;
@ -496,6 +558,7 @@ namespace skyline::kernel::svc {
void SignalProcessWideKey(DeviceState &state) {
auto address = state.ctx->registers.x0;
auto count = state.ctx->registers.w1;
state.logger->Debug("svcSignalProcessWideKey: Signalling Conditional-Variable at 0x{:X} for {}", address, count);
state.process->ConditionalVariableSignal(address, count);
state.ctx->registers.w0 = constant::status::Success;
@ -556,8 +619,10 @@ namespace skyline::kernel::svc {
void OutputDebugString(DeviceState &state) {
auto debug = state.process->GetString(state.ctx->registers.x0, state.ctx->registers.x1);
if (debug.back() == '\n')
debug.pop_back();
state.logger->Info("Debug Output: {}", debug);
state.ctx->registers.w0 = constant::status::Success;
}
@ -567,10 +632,10 @@ namespace skyline::kernel::svc {
auto handle = state.ctx->registers.w2;
auto id1 = state.ctx->registers.x3;
constexpr auto totalPhysicalMemory = 0xF8000000; // ~4 GB of RAM
u64 out{};
constexpr auto totalPhysicalMemory = 0xF8000000; // ~4 GB of RAM
switch (id0) {
case constant::infoState::AllowedCpuIdBitmask:
case constant::infoState::AllowedThreadPriorityMask:

View File

@ -4,6 +4,9 @@
#include "KObject.h"
namespace skyline::kernel::type {
/**
* @brief The base kernel memory object that other memory classes derieve from
*/
class KMemory : public KObject {
public:
KMemory(const DeviceState &state, KType objectType) : KObject(state, objectType) {}

View File

@ -9,12 +9,15 @@ namespace skyline::kernel::type {
KPrivateMemory::KPrivateMemory(const DeviceState &state, u64 address, size_t size, memory::Permission permission, const memory::MemoryState memState) : size(size), KMemory(state, KType::KPrivateMemory) {
if (address && !utils::PageAligned(address))
throw exception("KPrivateMemory was created with non-page-aligned address: 0x{:X}", address);
fd = ASharedMemory_create("KPrivateMemory", size);
if (fd < 0)
throw exception("An error occurred while creating shared memory: {}", fd);
auto host = mmap(nullptr, 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));
Registers fregs{
.x0 = address,
.x1 = size,
@ -23,10 +26,13 @@ namespace skyline::kernel::type {
.x4 = static_cast<u64>(fd),
.x8 = __NR_mmap,
};
state.nce->ExecuteFunction(ThreadCall::Syscall, fregs);
if (fregs.x0 < 0)
throw exception("An error occurred while mapping private memory in child process");
this->address = fregs.x0;
BlockDescriptor block{
.address = fregs.x0,
.size = size,
@ -45,17 +51,21 @@ namespace skyline::kernel::type {
void KPrivateMemory::Resize(size_t nSize) {
if (close(fd) < 0)
throw exception("An error occurred while trying to close shared memory FD: {}", strerror(errno));
fd = ASharedMemory_create("KPrivateMemory", nSize);
if (fd < 0)
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);
if (fregs.x0 < 0)
throw exception("An error occurred while unmapping private memory in child process");
fregs = {
.x0 = address,
.x1 = nSize,
@ -64,11 +74,14 @@ namespace skyline::kernel::type {
.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);
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 = {
@ -77,6 +90,7 @@ namespace skyline::kernel::type {
.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");
@ -84,10 +98,13 @@ namespace skyline::kernel::type {
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;
@ -100,9 +117,11 @@ namespace skyline::kernel::type {
.x2 = static_cast<u64>(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");
auto chunk = state.os->memory.GetChunk(address);
BlockDescriptor block{
.address = address,
@ -124,6 +143,7 @@ namespace skyline::kernel::type {
}
} catch (const std::exception &) {
}
auto chunk = state.os->memory.GetChunk(address);
if (chunk) {
munmap(reinterpret_cast<void *>(chunk->host), chunk->size);

View File

@ -13,6 +13,7 @@ namespace skyline::kernel::type {
u64 KProcess::TlsPage::ReserveSlot() {
if (Full())
throw exception("Trying to get TLS slot from full page");
slot[index] = true;
return Get(index++); // ++ on right will cause increment after evaluation of expression
}
@ -20,6 +21,7 @@ namespace skyline::kernel::type {
u64 KProcess::TlsPage::Get(u8 slotNo) {
if (slotNo >= constant::TlsSlots)
throw exception("TLS slot is out of range");
return address + (constant::TlsSlotSize * slotNo);
}
@ -31,6 +33,7 @@ namespace skyline::kernel::type {
for (auto &tlsPage: tlsPages)
if (!tlsPage->Full())
return tlsPage->ReserveSlot();
u64 address;
if (tlsPages.empty()) {
auto region = state.os->memory.GetRegion(memory::Regions::TlsIo);
@ -38,6 +41,7 @@ namespace skyline::kernel::type {
} else {
address = (*(tlsPages.end() - 1))->address + PAGE_SIZE;
}
auto tlsMem = NewHandle<KPrivateMemory>(address, PAGE_SIZE, memory::Permission(true, true, false), memory::states::ThreadLocal).item;
tlsPages.push_back(std::make_shared<TlsPage>(tlsMem->address));
@ -74,19 +78,24 @@ namespace skyline::kernel::type {
std::shared_ptr<KThread> KProcess::CreateThread(u64 entryPoint, u64 entryArg, u64 stackTop, u8 priority) {
auto size = (sizeof(ThreadContext) + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1);
auto tlsMem = std::make_shared<type::KSharedMemory>(state, 0, size, memory::Permission{true, true, false}, memory::states::Reserved);
Registers fregs{};
fregs.x0 = CLONE_THREAD | CLONE_SIGHAND | CLONE_PTRACE | CLONE_FS | CLONE_VM | CLONE_FILES | CLONE_IO;
fregs.x1 = stackTop;
fregs.x3 = tlsMem->Map(0, size, memory::Permission{true, true, false});
fregs.x8 = __NR_clone;
fregs.x5 = reinterpret_cast<u64>(&guest::GuestEntry);
fregs.x6 = entryPoint;
Registers fregs{
.x0 = CLONE_THREAD | CLONE_SIGHAND | CLONE_PTRACE | CLONE_FS | CLONE_VM | CLONE_FILES | CLONE_IO,
.x1 = stackTop,
.x3 = tlsMem->Map(0, size, memory::Permission{ true, true, false }),
.x8 = __NR_clone,
.x5 = reinterpret_cast<u64>(&guest::GuestEntry),
.x6 = entryPoint,
};
state.nce->ExecuteFunction(ThreadCall::Clone, fregs);
if (static_cast<int>(fregs.x0) < 0)
throw exception("Cannot create thread: Address: 0x{:X}, Stack Top: 0x{:X}", entryPoint, stackTop);
auto pid = static_cast<pid_t>(fregs.x0);
auto process = NewHandle<KThread>(pid, entryPoint, entryArg, stackTop, GetTlsSlot(), priority, this, tlsMem).item;
threads[pid] = process;
return process;
}
@ -98,19 +107,23 @@ namespace skyline::kernel::type {
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{
.iov_base = destination,
.iov_len = size,
};
struct iovec remote{
.iov_base = reinterpret_cast<void *>(offset),
.iov_len = size,
};
if (process_vm_readv(pid, &local, 1, &remote, 1, 0) < 0)
pread64(memFd, destination, size, offset);
}
@ -118,19 +131,23 @@ namespace skyline::kernel::type {
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{
.iov_base = source,
.iov_len = size,
};
struct iovec remote{
.iov_base = reinterpret_cast<void *>(offset),
.iov_len = size,
};
if (process_vm_writev(pid, &local, 1, &remote, 1, 0) < 0)
pwrite64(memFd, source, size, offset);
}
@ -138,18 +155,22 @@ namespace skyline::kernel::type {
void KProcess::CopyMemory(u64 source, u64 destination, size_t size) const {
auto sourceHost = GetHostAddress(source);
auto destinationHost = GetHostAddress(destination);
if (sourceHost && destinationHost) {
memcpy(reinterpret_cast<void *>(destinationHost), reinterpret_cast<const void *>(sourceHost), size);
} else {
if (size <= PAGE_SIZE) {
std::vector<u8> buffer(size);
state.process->ReadMemory(buffer.data(), source, size);
state.process->WriteMemory(buffer.data(), destination, size);
} else {
Registers fregs{};
fregs.x0 = source;
fregs.x1 = destination;
fregs.x2 = size;
Registers fregs{
.x0 = source,
.x1 = destination,
.x2 = size,
};
state.nce->ExecuteFunction(ThreadCall::Memcopy, fregs);
}
}
@ -169,52 +190,64 @@ namespace skyline::kernel::type {
break;
}
}
return std::nullopt;
}
bool KProcess::MutexLock(u64 address, KHandle owner) {
std::unique_lock lock(mutexLock);
auto mtx = GetPointer<u32>(address);
auto &mtxWaiters = mutexes[address];
u32 mtxExpected = 0;
if (__atomic_compare_exchange_n(mtx, &mtxExpected, (constant::MtxOwnerMask & state.thread->handle) | (mtxWaiters.empty() ? 0 : ~constant::MtxOwnerMask), false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST))
return true;
if (owner && (__atomic_load_n(mtx, __ATOMIC_SEQ_CST) != (owner | ~constant::MtxOwnerMask)))
return false;
std::shared_ptr<WaitStatus> status;
for (auto it = mtxWaiters.begin();; ++it) {
if (it != mtxWaiters.end() && (*it)->priority >= state.thread->priority)
continue;
status = std::make_shared<WaitStatus>(state.thread->priority, state.thread->handle);
mtxWaiters.insert(it, status);
break;
}
lock.unlock();
while (!status->flag);
lock.lock();
status->flag = false;
for (auto it = mtxWaiters.begin(); it != mtxWaiters.end(); ++it) {
if ((*it)->handle == state.thread->handle) {
mtxWaiters.erase(it);
break;
}
}
return true;
}
bool KProcess::MutexUnlock(u64 address) {
std::unique_lock lock(mutexLock);
auto mtx = GetPointer<u32>(address);
auto &mtxWaiters = mutexes[address];
u32 mtxDesired{};
if (!mtxWaiters.empty())
mtxDesired = (*mtxWaiters.begin())->handle | ((mtxWaiters.size() > 1) ? ~constant::MtxOwnerMask : 0);
u32 mtxExpected = (constant::MtxOwnerMask & state.thread->handle) | ~constant::MtxOwnerMask;
if (!__atomic_compare_exchange_n(mtx, &mtxExpected, mtxDesired, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) {
mtxExpected = constant::MtxOwnerMask & state.thread->handle;
if (!__atomic_compare_exchange_n(mtx, &mtxExpected, mtxDesired, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST))
return false;
}
if (mtxDesired) {
auto status = (*mtxWaiters.begin());
status->flag = true;
@ -222,52 +255,65 @@ namespace skyline::kernel::type {
while (status->flag);
lock.lock();
}
return true;
}
bool KProcess::ConditionalVariableWait(u64 conditionalAddress, u64 mutexAddress, u64 timeout) {
std::unique_lock lock(conditionalLock);
auto &condWaiters = conditionals[conditionalAddress];
std::shared_ptr<WaitStatus> status;
for (auto it = condWaiters.begin();; ++it) {
if (it != condWaiters.end() && (*it)->priority >= state.thread->priority)
continue;
status = std::make_shared<WaitStatus>(state.thread->priority, state.thread->handle, mutexAddress);
condWaiters.insert(it, status);
break;
}
lock.unlock();
bool timedOut{};
auto start = utils::GetTimeNs();
while (!status->flag)
if ((utils::GetTimeNs() - start) >= timeout)
timedOut = true;
lock.lock();
if (!status->flag)
timedOut = false;
else
status->flag = false;
for (auto it = condWaiters.begin(); it != condWaiters.end(); ++it) {
if ((*it)->handle == state.thread->handle) {
condWaiters.erase(it);
break;
}
}
lock.unlock();
return !timedOut;
}
void KProcess::ConditionalVariableSignal(u64 address, u64 amount) {
std::unique_lock condLock(conditionalLock);
auto &condWaiters = conditionals[address];
u64 count{};
auto iter = condWaiters.begin();
while (iter != condWaiters.end() && count < amount) {
auto &thread = *iter;
auto mtx = GetPointer<u32>(thread->mutexAddress);
u32 mtxValue = __atomic_load_n(mtx, __ATOMIC_SEQ_CST);
while (true) {
u32 mtxDesired{};
if (!mtxValue)
mtxDesired = (constant::MtxOwnerMask & thread->handle);
else if ((mtxValue & constant::MtxOwnerMask) == state.thread->handle)
@ -276,13 +322,16 @@ namespace skyline::kernel::type {
mtxDesired = mtxValue | ~constant::MtxOwnerMask;
else
break;
if (__atomic_compare_exchange_n(mtx, &mtxValue, mtxDesired, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST))
break;
}
if (mtxValue && ((mtxValue & constant::MtxOwnerMask) != state.thread->handle)) {
std::unique_lock mtxLock(mutexLock);
auto &mtxWaiters = mutexes[thread->mutexAddress];
std::shared_ptr<WaitStatus> status;
for (auto it = mtxWaiters.begin();; ++it) {
if (it != mtxWaiters.end() && (*it)->priority >= thread->priority)
continue;
@ -290,21 +339,26 @@ namespace skyline::kernel::type {
mtxWaiters.insert(it, status);
break;
}
mtxLock.unlock();
while (!status->flag);
mtxLock.lock();
status->flag = false;
for (auto it = mtxWaiters.begin(); it != mtxWaiters.end(); ++it) {
if ((*it)->handle == thread->handle) {
mtxWaiters.erase(it);
break;
}
}
mtxLock.unlock();
}
thread->flag = true;
iter++;
count++;
condLock.unlock();
while (thread->flag);
condLock.lock();

View File

@ -9,18 +9,22 @@ namespace skyline::kernel::type {
KSharedMemory::KSharedMemory(const DeviceState &state, u64 address, size_t size, const memory::Permission permission, memory::MemoryState memState, int mmapFlags) : initialState(memState), KMemory(state, KType::KSharedMemory) {
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)
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) | mmapFlags, fd, 0));
if (address == reinterpret_cast<u64>(MAP_FAILED))
throw exception("An occurred while mapping shared memory: {}", strerror(errno));
kernel = {.address = address, .size = size, .permission = permission};
}
u64 KSharedMemory::Map(const u64 address, const u64 size, memory::Permission permission) {
if (address && !utils::PageAligned(address))
throw exception("KSharedMemory was mapped to a non-page-aligned address: 0x{:X}", address);
Registers fregs{
.x0 = address,
.x1 = size,
@ -29,10 +33,13 @@ namespace skyline::kernel::type {
.x4 = static_cast<u64>(fd),
.x8 = __NR_mmap,
};
state.nce->ExecuteFunction(ThreadCall::Syscall, fregs);
if (fregs.x0 < 0)
throw exception("An error occurred while mapping shared memory in guest");
guest = {.address = fregs.x0, .size = size, .permission = permission};
BlockDescriptor block{
.address = fregs.x0,
.size = size,
@ -46,6 +53,7 @@ namespace skyline::kernel::type {
.blockList = {block},
};
state.os->memory.InsertChunk(chunk);
return fregs.x0;
}
@ -53,17 +61,21 @@ namespace skyline::kernel::type {
if (guest.Valid() && kernel.Valid()) {
if (close(fd) < 0)
throw exception("An error occurred while trying to close shared memory FD: {}", strerror(errno));
fd = ASharedMemory_create("KSharedMemory", size);
if (fd < 0)
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);
if (fregs.x0 < 0)
throw exception("An error occurred while unmapping private memory in child process");
fregs = {
.x0 = guest.address,
.x1 = size,
@ -72,10 +84,13 @@ namespace skyline::kernel::type {
.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);
for (const auto &block : chunk->blockList) {
if ((block.address - chunk->address) < guest.size) {
@ -85,6 +100,7 @@ namespace skyline::kernel::type {
.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");
@ -92,25 +108,34 @@ namespace skyline::kernel::type {
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);
} else if (kernel.Valid()) {
if (close(fd) < 0)
throw exception("An error occurred while trying to close shared memory FD: {}", 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;
} else {
@ -126,9 +151,11 @@ namespace skyline::kernel::type {
.x2 = static_cast<u64>(permission.Get()),
.x8 = __NR_mprotect,
};
state.nce->ExecuteFunction(ThreadCall::Syscall, fregs);
if (fregs.x0 < 0)
throw exception("An error occurred while updating shared memory's permissions in guest");
auto chunk = state.os->memory.GetChunk(address);
BlockDescriptor block{
.address = address,
@ -152,6 +179,7 @@ namespace skyline::kernel::type {
.x1 = guest.size,
.x8 = __NR_munmap,
};
state.nce->ExecuteFunction(ThreadCall::Syscall, fregs);
}
} catch (const std::exception &) {

View File

@ -17,6 +17,7 @@ namespace skyline::kernel::type {
if (pid == parent->pid)
parent->status = KProcess::Status::Started;
status = Status::Running;
state.nce->StartThread(entryArg, handle, parent->threads.at(pid));
}
}

View File

@ -7,6 +7,7 @@ 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) {
if (address && !utils::PageAligned(address))
throw exception("KTransferMemory was created with non-page-aligned address: 0x{:X}", address);
BlockDescriptor block{
.size = size,
.permission = permission,
@ -16,10 +17,12 @@ namespace skyline::kernel::type {
.state = memState,
.blockList = {block},
};
if (host) {
address = reinterpret_cast<u64>(mmap(reinterpret_cast<void *>(address), size, permission.Get(), MAP_ANONYMOUS | MAP_PRIVATE | ((address) ? MAP_FIXED : 0), -1, 0));
if (reinterpret_cast<void *>(address) == MAP_FAILED)
throw exception("An error occurred while mapping transfer memory in host");
this->address = address;
chunk.address = address;
chunk.blockList.front().address = address;
@ -33,12 +36,15 @@ namespace skyline::kernel::type {
.x4 = static_cast<u64>(-1),
.x8 = __NR_mmap,
};
state.nce->ExecuteFunction(ThreadCall::Syscall, fregs);
if (fregs.x0 < 0)
throw exception("An error occurred while mapping shared region in child process");
this->address = fregs.x0;
chunk.address = fregs.x0;
chunk.blockList.front().address = fregs.x0;
state.os->memory.InsertChunk(chunk);
}
}
@ -46,13 +52,17 @@ namespace skyline::kernel::type {
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;
ChunkDescriptor chunk = host ? hostChunk : *state.os->memory.GetChunk(address);
chunk.address = nAddress;
chunk.size = nSize;
MemoryManager::ResizeChunk(&chunk, nSize);
for (auto &block : chunk.blockList) {
block.address = nAddress + (block.address - address);
if ((mHost && !host) || (!mHost && !host)) {
Registers fregs{
.x0 = block.address,
@ -62,15 +72,18 @@ namespace skyline::kernel::type {
.x4 = static_cast<u64>(-1),
.x8 = __NR_mmap,
};
state.nce->ExecuteFunction(ThreadCall::Syscall, fregs);
if (fregs.x0 < 0)
throw exception("An error occurred while mapping transfer memory in child process");
nAddress = fregs.x0;
} else if ((!mHost && host) || (mHost && host)) {
nAddress = reinterpret_cast<u64>(mmap(reinterpret_cast<void *>(block.address), block.size, block.permission.Get(), MAP_ANONYMOUS | MAP_PRIVATE | ((nAddress) ? MAP_FIXED : 0), -1, 0));
if (reinterpret_cast<void *>(nAddress) == MAP_FAILED)
throw exception("An error occurred while mapping transfer memory in host");
}
if (block.permission.r) {
if (mHost && !host)
state.process->ReadMemory(reinterpret_cast<void *>(nAddress), address, block.size);
@ -92,12 +105,14 @@ namespace skyline::kernel::type {
.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 transfer memory's permissions in guest");
}
}
}
if (mHost && !host) {
state.os->memory.DeleteChunk(address);
hostChunk = chunk;
@ -109,12 +124,14 @@ namespace skyline::kernel::type {
state.os->memory.DeleteChunk(address);
state.os->memory.InsertChunk(chunk);
}
if ((mHost && !host) || (!mHost && !host)) {
Registers fregs{
.x0 = address,
.x1 = size,
.x8 = __NR_munmap,
};
state.nce->ExecuteFunction(ThreadCall::Syscall, fregs);
if (fregs.x0 < 0)
throw exception("An error occurred while unmapping transfer memory in child process");
@ -122,6 +139,7 @@ namespace skyline::kernel::type {
if (reinterpret_cast<void *>(munmap(reinterpret_cast<void *>(address), size)) == MAP_FAILED)
throw exception("An error occurred while unmapping transfer memory in host: {}");
}
host = mHost;
address = nAddress;
size = nSize;
@ -139,10 +157,13 @@ namespace skyline::kernel::type {
.x2 = nSize,
.x8 = __NR_mremap,
};
state.nce->ExecuteFunction(ThreadCall::Syscall, fregs);
if (fregs.x0 < 0)
throw exception("An error occurred while remapping transfer memory in guest");
size = nSize;
auto chunk = state.os->memory.GetChunk(address);
MemoryManager::ResizeChunk(chunk, size);
}
@ -154,9 +175,11 @@ namespace skyline::kernel::type {
.size = size,
.permission = permission,
};
if (host) {
if (mprotect(reinterpret_cast<void *>(address), size, permission.Get()) == reinterpret_cast<u64>(MAP_FAILED))
throw exception("An occurred while remapping transfer memory: {}", strerror(errno));
MemoryManager::InsertBlock(&hostChunk, block);
} else {
Registers fregs{
@ -165,9 +188,11 @@ namespace skyline::kernel::type {
.x2 = static_cast<u64>(permission.Get()),
.x8 = __NR_mprotect,
};
state.nce->ExecuteFunction(ThreadCall::Syscall, fregs);
if (fregs.x0 < 0)
throw exception("An error occurred while updating transfer memory's permissions in guest");
auto chunk = state.os->memory.GetChunk(address);
MemoryManager::InsertBlock(chunk, block);
}
@ -183,7 +208,9 @@ namespace skyline::kernel::type {
.x1 = size,
.x8 = __NR_munmap,
};
state.nce->ExecuteFunction(ThreadCall::Syscall, fregs);
state.os->memory.DeleteChunk(address);
} catch (const std::exception &) {
}

View File

@ -7,14 +7,17 @@ namespace skyline::kernel {
void OS::Execute(const int romFd, const TitleFormat romType) {
std::shared_ptr<loader::Loader> loader;
if (romType == TitleFormat::NRO) {
loader = std::make_shared<loader::NroLoader>(romFd);
} else
throw exception("Unsupported ROM extension.");
auto process = CreateProcess(constant::BaseAddress, 0, constant::DefStackSize);
loader->LoadProcessData(process, state);
process->InitializeMemory();
process->threads.at(process->pid)->Start(); // The kernel itself is responsible for starting the main thread
state.nce->Execute();
}
@ -23,13 +26,17 @@ namespace skyline::kernel {
stack->guest = stack->kernel;
if (mprotect(reinterpret_cast<void *>(stack->guest.address), PAGE_SIZE, PROT_NONE))
throw exception("Failed to create guard pages");
auto tlsMem = std::make_shared<type::KSharedMemory>(state, 0, (sizeof(ThreadContext) + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1), memory::Permission{true, true, false}, memory::states::Reserved);
tlsMem->guest = tlsMem->kernel;
pid_t pid = clone(reinterpret_cast<int (*)(void *)>(&guest::GuestEntry), reinterpret_cast<void *>(stack->guest.address + stackSize), CLONE_FILES | CLONE_FS | CLONE_SETTLS | SIGCHLD, reinterpret_cast<void *>(entry), nullptr, reinterpret_cast<void *>(tlsMem->guest.address));
if (pid == -1)
throw exception("Call to clone() has failed: {}", strerror(errno));
state.logger->Debug("Successfully created process with PID: {}", pid);
process = std::make_shared<kernel::type::KProcess>(state, pid, argument, stack, tlsMem);
return process;
}