Remove support for multiple guest processes

This commit removes support for more than one guest processes as it requires a fair bit of extra code to support in addition the HLE service implementations don't support it anyway.
This commit is contained in:
◱ PixelyIon 2020-01-01 18:41:25 +05:30 committed by ◱ PixelyIon
parent 48d47a2b25
commit b84859d352
33 changed files with 457 additions and 459 deletions

View File

@ -91,7 +91,7 @@ namespace skyline {
}
DeviceState::DeviceState(kernel::OS *os, std::shared_ptr<kernel::type::KProcess> &thisProcess, std::shared_ptr<kernel::type::KThread> &thisThread, std::shared_ptr<JvmManager> jvmManager, std::shared_ptr<Settings> settings, std::shared_ptr<Logger> logger)
: os(os), jvmManager(std::move(jvmManager)), settings(std::move(settings)), logger(std::move(logger)), thisProcess(thisProcess), thisThread(thisThread) {
: os(os), jvmManager(std::move(jvmManager)), settings(std::move(settings)), logger(std::move(logger)), process(thisProcess), thread(thisThread) {
// We assign these later as they use the state in their constructor and we don't want null pointers
nce = std::move(std::make_shared<NCE>(*this));
gpu = std::move(std::make_shared<gpu::GPU>(*this));

View File

@ -306,8 +306,8 @@ namespace skyline {
DeviceState(kernel::OS *os, std::shared_ptr<kernel::type::KProcess> &thisProcess, std::shared_ptr<kernel::type::KThread> &thisThread, std::shared_ptr<JvmManager> jvmManager, std::shared_ptr<Settings> settings, std::shared_ptr<Logger> logger);
kernel::OS *os; //!< This holds a reference to the OS class
std::shared_ptr<kernel::type::KProcess> &thisProcess; //!< This holds a reference to the current process object
std::shared_ptr<kernel::type::KThread> &thisThread; //!< This holds a reference to the current thread object
std::shared_ptr<kernel::type::KProcess> &process; //!< This holds a reference to the process object
std::shared_ptr<kernel::type::KThread> &thread; //!< This holds a reference to the current thread object
std::shared_ptr<NCE> nce; //!< This holds a reference to the NCE class
std::shared_ptr<gpu::GPU> gpu; //!< This holds a reference to the GPU class
std::shared_ptr<JvmManager> jvmManager; //!< This holds a reference to the JvmManager class

View File

@ -18,7 +18,7 @@ namespace skyline::gpu {
std::unordered_map<device::NvDeviceType, std::shared_ptr<device::NvDevice>> deviceMap; //!< A map from a NvDeviceType to the NvDevice object
std::unordered_map<u32, std::shared_ptr<device::NvDevice>> fdMap; //!< A map from an FD to a shared pointer to it's NvDevice object
bool surfaceUpdate{}; //!< If the surface needs to be updated
double prevTime{};
double prevTime{}; //!< The time passed from the last frame
public:
DisplayId displayId{DisplayId::Null}; //!< The ID of this display

View File

@ -21,7 +21,7 @@ namespace skyline::gpu::device {
void NvHostChannel::SetErrorNotifier(skyline::gpu::device::IoctlData &buffer) {}
void NvHostChannel::SetPriority(skyline::gpu::device::IoctlData &buffer) {
auto priority = state.thisProcess->ReadMemory<NvChannelPriority>(buffer.input[0].address);
auto priority = state.process->ReadMemory<NvChannelPriority>(buffer.input[0].address);
switch (priority) {
case NvChannelPriority::Low:
timeslice = 1300;

View File

@ -12,7 +12,7 @@ namespace skyline::gpu::device {
void NvHostCtrlGpu::ZCullGetCtxSize(IoctlData &buffer) {
u32 size = 0x1;
state.thisProcess->WriteMemory(size, buffer.output[0].address);
state.process->WriteMemory(size, buffer.output[0].address);
}
void NvHostCtrlGpu::ZCullGetInfo(skyline::gpu::device::IoctlData &buffer) {
@ -28,7 +28,7 @@ namespace skyline::gpu::device {
u32 subregionHeightAlignPixels{0x40};
u32 subregionCount{0x10};
} zCullInfo;
state.thisProcess->WriteMemory(zCullInfo, buffer.output[0].address);
state.process->WriteMemory(zCullInfo, buffer.output[0].address);
}
void NvHostCtrlGpu::GetCharacteristics(IoctlData &buffer) {
@ -73,7 +73,7 @@ namespace skyline::gpu::device {
u64 gpuCharacteristicsBufSize; // InOut
u64 gpuCharacteristicsBufAddr; // In
GpuCharacteristics gpuCharacteristics; // Out
} data = state.thisProcess->ReadMemory<Data>(buffer.input[0].address);
} data = state.process->ReadMemory<Data>(buffer.input[0].address);
data.gpuCharacteristics = {
.arch = 0x120,
.impl = 0xB,
@ -111,7 +111,7 @@ namespace skyline::gpu::device {
.grCompbitStoreBaseHw = 0x0
};
data.gpuCharacteristicsBufSize = 0xA0;
state.thisProcess->WriteMemory(data, buffer.output[0].address);
state.process->WriteMemory(data, buffer.output[0].address);
}
void NvHostCtrlGpu::GetTpcMasks(IoctlData &buffer) {
@ -119,10 +119,10 @@ namespace skyline::gpu::device {
u32 maskBufSize; // In
u32 reserved[3]; // In
u64 maskBuf; // Out
} data = state.thisProcess->ReadMemory<Data>(buffer.input[0].address);
} data = state.process->ReadMemory<Data>(buffer.input[0].address);
if (data.maskBufSize)
data.maskBuf = 0x3;
state.thisProcess->WriteMemory(data, buffer.output[0].address);
state.process->WriteMemory(data, buffer.output[0].address);
}
void NvHostCtrlGpu::GetActiveSlotMask(IoctlData &buffer) {
@ -133,6 +133,6 @@ namespace skyline::gpu::device {
.slot = 0x07,
.mask = 0x01
};
state.thisProcess->WriteMemory(data, buffer.output[0].address);
state.process->WriteMemory(data, buffer.output[0].address);
}
}

View File

@ -17,10 +17,10 @@ namespace skyline::gpu::device {
struct Data {
u32 size; // In
u32 handle; // Out
} data = state.thisProcess->ReadMemory<Data>(buffer.input[0].address);
} data = state.process->ReadMemory<Data>(buffer.input[0].address);
handleTable[handleIndex] = std::make_shared<NvMapObject>(idIndex++, data.size);
data.handle = handleIndex++;
state.thisProcess->WriteMemory(data, buffer.output[0].address);
state.process->WriteMemory(data, buffer.output[0].address);
state.logger->Debug("Create: Input: Size: 0x{:X}, Output: Handle: 0x{:X}, Status: {}", data.size, data.handle, buffer.status);
}
@ -28,7 +28,7 @@ namespace skyline::gpu::device {
struct Data {
u32 id; // In
u32 handle; // Out
} data = state.thisProcess->ReadMemory<Data>(buffer.input[0].address);
} data = state.process->ReadMemory<Data>(buffer.input[0].address);
bool found{};
for (const auto &object : handleTable) {
if (object.second->id == data.id) {
@ -38,7 +38,7 @@ namespace skyline::gpu::device {
}
}
if (found)
state.thisProcess->WriteMemory(data, buffer.output[0].address);
state.process->WriteMemory(data, buffer.output[0].address);
else
buffer.status = NvStatus::BadValue;
state.logger->Debug("FromId: Input: Handle: 0x{:X}, Output: ID: 0x{:X}, Status: {}", data.handle, data.id, buffer.status);
@ -53,7 +53,7 @@ namespace skyline::gpu::device {
u8 kind; // In
u8 _pad0_[7];
u64 address; // InOut
} data = state.thisProcess->ReadMemory<Data>(buffer.input[0].address);
} data = state.process->ReadMemory<Data>(buffer.input[0].address);
auto &object = handleTable.at(data.handle);
object->heapMask = data.heapMask;
object->flags = data.flags;
@ -71,7 +71,7 @@ namespace skyline::gpu::device {
u32 address; // Out
u32 size; // Out
u64 flags; // Out
} data = state.thisProcess->ReadMemory<Data>(buffer.input[0].address);
} data = state.process->ReadMemory<Data>(buffer.input[0].address);
const auto &object = handleTable.at(data.handle);
if (object.use_count() > 1) {
data.address = static_cast<u32>(object->address);
@ -82,7 +82,7 @@ namespace skyline::gpu::device {
}
data.size = object->size;
handleTable.erase(data.handle);
state.thisProcess->WriteMemory(data, buffer.output[0].address);
state.process->WriteMemory(data, buffer.output[0].address);
}
void NvMap::Param(IoctlData &buffer) {
@ -91,7 +91,7 @@ namespace skyline::gpu::device {
u32 handle; // In
Parameter parameter; // In
u32 result; // Out
} data = state.thisProcess->ReadMemory<Data>(buffer.input[0].address);
} data = state.process->ReadMemory<Data>(buffer.input[0].address);
auto &object = handleTable.at(data.handle);
switch (data.parameter) {
case Parameter::Size:
@ -124,7 +124,7 @@ namespace skyline::gpu::device {
buffer.status = NvStatus::NotImplemented;
break;
}
state.thisProcess->WriteMemory(data, buffer.output[0].address);
state.process->WriteMemory(data, buffer.output[0].address);
state.logger->Debug("Param: Input: Handle: 0x{:X}, Parameter: {}, Output: Result: 0x{:X}, Status: {}", data.handle, data.parameter, data.result, buffer.status);
}
@ -132,9 +132,9 @@ namespace skyline::gpu::device {
struct Data {
u32 id; // Out
u32 handle; // In
} data = state.thisProcess->ReadMemory<Data>(buffer.input[0].address);
} data = state.process->ReadMemory<Data>(buffer.input[0].address);
data.id = handleTable.at(data.handle)->id;
state.thisProcess->WriteMemory(data, buffer.output[0].address);
state.process->WriteMemory(data, buffer.output[0].address);
state.logger->Debug("GetId: Input: Handle: 0x{:X}, Output: ID: 0x{:X}, Status: {}", data.handle, data.id, buffer.status);
}
}

View File

@ -31,7 +31,7 @@ namespace skyline::gpu {
}
void Buffer::UpdateBuffer() {
state.thisProcess->ReadMemory(dataBuffer.data(), nvBuffer->address + gbpBuffer.offset, gbpBuffer.size);
state.process->ReadMemory(dataBuffer.data(), nvBuffer->address + gbpBuffer.offset, gbpBuffer.size);
}
BufferQueue::WaitContext::WaitContext(std::shared_ptr<kernel::type::KThread> thread, DequeueIn input, kernel::ipc::OutputBuffer& buffer) : thread(std::move(thread)), input(input), buffer(buffer) {}
@ -59,8 +59,8 @@ namespace skyline::gpu {
}
}
if (slot == -1) {
state.thisThread->Sleep();
waitVec.emplace_back(state.thisThread, *data, buffer);
state.thread->Sleep();
waitVec.emplace_back(state.thread, *data, buffer);
state.logger->Debug("DequeueBuffer: Width: {}, Height: {}, Format: {}, Usage: {}, Timestamps: {}, No Free Buffers", data->width, data->height, data->format, data->usage, data->timestamps);
return true;
}
@ -135,7 +135,7 @@ namespace skyline::gpu {
gpu::Parcel out(state);
DequeueOut output(slotNo);
out.WriteData(output);
out.WriteParcel(context->buffer, context->thread->pid);
out.WriteParcel(context->buffer);
slot->status = BufferStatus::Dequeued;
waitVec.erase(context);
break;

View File

@ -6,22 +6,22 @@ namespace skyline::gpu {
Parcel::Parcel(kernel::ipc::InputBuffer &buffer, const DeviceState &state) : Parcel(buffer.address, buffer.size, state) {}
Parcel::Parcel(u64 address, u64 size, const DeviceState &state) : state(state) {
state.thisProcess->ReadMemory(&header, address, sizeof(ParcelHeader));
state.process->ReadMemory(&header, address, sizeof(ParcelHeader));
if (size < (sizeof(ParcelHeader) + header.dataSize + header.objectsSize))
throw exception("The size of the parcel according to the header exceeds the specified size");
data.resize(header.dataSize);
state.thisProcess->ReadMemory(data.data(), address + header.dataOffset, header.dataSize);
state.process->ReadMemory(data.data(), address + header.dataOffset, header.dataSize);
objects.resize(header.objectsSize);
state.thisProcess->ReadMemory(objects.data(), address + header.objectsOffset, header.objectsSize);
state.process->ReadMemory(objects.data(), address + header.objectsOffset, header.objectsSize);
}
Parcel::Parcel(const DeviceState &state) : state(state) {}
u64 Parcel::WriteParcel(kernel::ipc::OutputBuffer& buffer, pid_t process) {
return WriteParcel(buffer.address, buffer.size, process);
u64 Parcel::WriteParcel(kernel::ipc::OutputBuffer& buffer) {
return WriteParcel(buffer.address, buffer.size);
}
u64 Parcel::WriteParcel(u64 address, u64 maxSize, pid_t process) {
u64 Parcel::WriteParcel(u64 address, u64 maxSize) {
header.dataSize = static_cast<u32>(data.size());
header.dataOffset = sizeof(ParcelHeader);
header.objectsSize = static_cast<u32>(objects.size());
@ -29,16 +29,9 @@ namespace skyline::gpu {
u64 totalSize = sizeof(ParcelHeader) + header.dataSize + header.objectsSize;
if (maxSize < totalSize)
throw exception("The size of the parcel exceeds maxSize");
if (process) {
auto &object = state.os->processMap.at(process);
object->WriteMemory(header, address);
object->WriteMemory(data.data(), address + header.dataOffset, data.size());
object->WriteMemory(objects.data(), address + header.objectsOffset, objects.size());
} else {
state.thisProcess->WriteMemory(header, address);
state.thisProcess->WriteMemory(data.data(), address + header.dataOffset, data.size());
state.thisProcess->WriteMemory(objects.data(), address + header.objectsOffset, objects.size());
}
state.process->WriteMemory(header, address);
state.process->WriteMemory(data.data(), address + header.dataOffset, data.size());
state.process->WriteMemory(objects.data(), address + header.objectsOffset, objects.size());
return totalSize;
}
}

View File

@ -80,18 +80,16 @@ namespace skyline::gpu {
/**
* @brief Writes the Parcel object into a particular output buffer on a process
* @param buffer The buffer to write into
* @param process The process to write the Parcel to
* @return The total size of the message
*/
u64 WriteParcel(kernel::ipc::OutputBuffer& buffer, pid_t process = 0);
u64 WriteParcel(kernel::ipc::OutputBuffer& buffer);
/**
* @brief Writes the Parcel object into the process's memory
* @param address The address to write the Parcel object to
* @param maxSize The maximum size of the Parcel
* @param process The process to write the Parcel to
* @return The total size of the message
*/
u64 WriteParcel(u64 address, u64 maxSize, pid_t process = 0);
u64 WriteParcel(u64 address, u64 maxSize);
};
}

View File

@ -1,8 +1,179 @@
#pragma once
namespace skyline::guest {
constexpr size_t saveCtxSize = 20 * sizeof(u32);
constexpr size_t loadCtxSize = 20 * sizeof(u32);
extern "C" void saveCtx(void);
extern "C" void loadCtx(void);
namespace skyline {
namespace guest {
constexpr size_t saveCtxSize = 20 * sizeof(u32);
constexpr size_t loadCtxSize = 20 * sizeof(u32);
extern "C" void saveCtx(void);
extern "C" void loadCtx(void);
}
namespace instr {
/**
* @brief A bit-field struct that encapsulates a BRK instruction. See https://developer.arm.com/docs/ddi0596/latest/base-instructions-alphabetic-order/brk-breakpoint-instruction.
*/
struct Brk {
/**
* @brief Creates a BRK instruction with a specific immediate value, used for generating BRK opcodes
* @param value The immediate value of the instruction
*/
explicit Brk(u16 value) {
start = 0x0; // First 5 bits of a BRK instruction are 0
this->value = value;
end = 0x6A1; // Last 11 bits of a BRK instruction stored as u16
}
/**
* @brief Returns if the opcode is valid or not
* @return If the opcode represents a valid BRK instruction
*/
inline bool Verify() {
return (start == 0x0 && end == 0x6A1);
}
union {
struct {
u8 start : 5;
u32 value : 16;
u16 end : 11;
};
u32 raw{};
};
};
static_assert(sizeof(Brk) == sizeof(u32));
/**
* @brief A bit-field struct that encapsulates a SVC instruction. See https://developer.arm.com/docs/ddi0596/latest/base-instructions-alphabetic-order/svc-supervisor-call.
*/
struct Svc {
/**
* @brief Returns if the opcode is valid or not
* @return If the opcode represents a valid SVC instruction
*/
inline bool Verify() {
return (start == 0x1 && end == 0x6A0);
}
union {
struct {
u8 start : 5;
u32 value : 16;
u16 end : 11;
};
u32 raw{};
};
};
static_assert(sizeof(Svc) == sizeof(u32));
/**
* @brief A bit-field struct that encapsulates a MRS instruction. See https://developer.arm.com/docs/ddi0596/latest/base-instructions-alphabetic-order/mrs-move-system-register.
*/
struct Mrs {
/**
* @brief Creates a MRS instruction, used for generating BRK opcodes
* @param srcReg The source system register
* @param dstReg The destination Xn register
*/
Mrs(u32 srcReg, u8 dstReg) {
this->srcReg = srcReg;
this->dstReg = dstReg;
end = 0xD53; // Last 12 bits of a MRS instruction stored as u16
}
/**
* @brief Returns if the opcode is valid or not
* @return If the opcode represents a valid MRS instruction
*/
inline bool Verify() {
return (end == 0xD53);
}
union {
struct {
u8 dstReg : 5;
u32 srcReg : 15;
u16 end : 12;
};
u32 raw{};
};
};
static_assert(sizeof(Mrs) == sizeof(u32));
/**
* @brief A bit-field struct that encapsulates a B instruction. See https://developer.arm.com/docs/ddi0596/latest/base-instructions-alphabetic-order/b-branch.
*/
struct B {
public:
explicit B(i64 offset) {
this->offset = static_cast<i32>(offset / 4);
end = 0x5;
}
/**
* @brief Returns the offset of the instruction
* @return The offset encoded within the instruction
*/
inline i32 Offset() {
return offset * 4;
}
/**
* @brief Returns if the opcode is valid or not
* @return If the opcode represents a valid Branch instruction
*/
inline bool Verify() {
return (end == 0x5);
}
union {
struct {
i32 offset : 26;
u8 end : 6;
};
u32 raw{};
};
};
static_assert(sizeof(B) == sizeof(u32));
/**
* @brief A bit-field struct that encapsulates a BL instruction. See https://developer.arm.com/docs/ddi0596/latest/base-instructions-alphabetic-order/b-branch.
*/
struct BL {
public:
explicit BL(i64 offset) {
this->offset = static_cast<i32>(offset / 4);
end = 0x25;
}
/**
* @brief Returns the offset of the instruction
* @return The offset encoded within the instruction
*/
inline i32 Offset() {
return offset * 4;
}
/**
* @brief Returns if the opcode is valid or not
* @return If the opcode represents a valid Branch instruction
*/
inline bool Verify() {
return (end == 0x85);
}
union {
struct {
i32 offset : 26;
u8 end : 6;
};
u32 raw{};
};
};
static_assert(sizeof(BL) == sizeof(u32));
}
}

View File

@ -14,7 +14,7 @@ namespace skyline::kernel::ipc {
IpcRequest::IpcRequest(bool isDomain, const DeviceState &state) : isDomain(isDomain), state(state), tls() {
u8 *currPtr = tls.data();
state.thisProcess->ReadMemory(currPtr, state.thisThread->tls, constant::TlsIpcSize);
state.process->ReadMemory(currPtr, state.thread->tls, constant::TlsIpcSize);
header = reinterpret_cast<CommandHeader *>(currPtr);
currPtr += sizeof(CommandHeader);
@ -184,12 +184,12 @@ namespace skyline::kernel::ipc {
state.logger->Debug("Output: Raw Size: {}, Command ID: 0x{:X}, Copy Handles: {}, Move Handles: {}", u32(header->rawSize), u32(payload->value), copyHandles.size(), moveHandles.size());
state.thisProcess->WriteMemory(tls.data(), state.thisThread->tls, constant::TlsIpcSize);
state.process->WriteMemory(tls.data(), state.thread->tls, constant::TlsIpcSize);
}
std::vector<u8> BufferDescriptorABW::Read(const DeviceState &state) {
std::vector<u8> vec(Size());
state.thisProcess->ReadMemory(vec.data(), Address(), Size());
state.process->ReadMemory(vec.data(), Address(), Size());
return std::move(vec);
}
}

View File

@ -12,12 +12,12 @@ namespace skyline::kernel::svc {
}
std::shared_ptr<type::KPrivateMemory> heap;
try {
heap = state.thisProcess->memoryRegionMap.at(memory::Region::Heap);
heap = state.process->memoryRegionMap.at(memory::Region::Heap);
heap->Resize(size, true);
} catch (const exception &) {
state.logger->Warn("svcSetHeapSize: Falling back to recreating memory");
state.thisProcess->UnmapPrivateRegion(memory::Region::Heap);
heap = state.thisProcess->MapPrivateRegion(constant::HeapAddr, size, {true, true, false}, memory::Type::Heap, memory::Region::Heap).item;
state.process->UnmapPrivateRegion(memory::Region::Heap);
heap = state.process->MapPrivateRegion(constant::HeapAddr, size, {true, true, false}, memory::Type::Heap, memory::Region::Heap).item;
}
state.nce->SetRegister(Wreg::W0, constant::status::Success);
state.nce->SetRegister(Xreg::X1, heap->address);
@ -47,7 +47,7 @@ namespace skyline::kernel::svc {
}
memory::MemoryAttribute attribute = *reinterpret_cast<memory::MemoryAttribute*>(&maskedValue);
bool found = false;
for (const auto&[address, region] : state.thisProcess->memoryMap) {
for (const auto&[address, region] : state.process->memoryMap) {
if (addr >= address && addr < (address + region->size)) {
bool subFound = false;
for (auto &subregion : region->regionInfoVec) {
@ -72,54 +72,53 @@ namespace skyline::kernel::svc {
}
void QueryMemory(DeviceState &state) {
memory::MemoryInfo memInf;
memory::MemoryInfo memInfo{};
u64 addr = state.nce->GetRegister(Xreg::X2);
bool found = false;
for (const auto&[address, region] : state.thisProcess->memoryMap) {
for (const auto&[address, region] : state.process->memoryMap) {
if (addr >= address && addr < (address + region->size)) {
memInf = region->GetInfo(addr);
memInfo = region->GetInfo(addr);
found = true;
break;
}
}
if (!found) {
for (const auto &object : state.thisProcess->handleTable) {
for (const auto &object : state.process->handleTable) {
if (object.second->objectType == type::KType::KSharedMemory) {
const auto &mem = state.thisProcess->GetHandle<type::KSharedMemory>(object.first);
if (mem->procInfMap.count(state.thisProcess->mainThread)) {
const auto &map = mem->procInfMap.at(state.thisProcess->mainThread);
if (addr >= map.address && addr < (map.address + map.size)) {
memInf = mem->GetInfo(state.thisProcess->mainThread);
const auto &mem = state.process->GetHandle<type::KSharedMemory>(object.first);
if (mem->guest.valid()) {
if (addr >= mem->guest.address && addr < (mem->guest.address + mem->guest.size)) {
memInfo = mem->GetInfo();
found = true;
break;
}
}
} else if (object.second->objectType == type::KType::KTransferMemory) {
const auto &mem = state.thisProcess->GetHandle<type::KTransferMemory>(object.first);
const auto &mem = state.process->GetHandle<type::KTransferMemory>(object.first);
if (addr >= mem->cAddress && addr < (mem->cAddress + mem->cSize)) {
memInf = mem->GetInfo();
memInfo = mem->GetInfo();
found = true;
break;
}
}
}
if (!found) {
memInf = {
.baseAddress = constant::BaseEnd,
.size = static_cast<u64>(-constant::BaseEnd + 1),
memInfo = {
.baseAddress = constant::BaseAddr,
.size = static_cast<u64>(constant::BaseEnd),
.type = static_cast<u64>(memory::Type::Unmapped)
};
state.logger->Debug("svcQueryMemory: Cannot find block of address: 0x{:X}", addr);
}
}
state.logger->Debug("svcQueryMemory: Address: 0x{:X}, Size: 0x{:X}, Type: {}, Is Uncached: {}, Permissions: {}{}{}", memInf.baseAddress, memInf.size, memInf.type, static_cast<bool>(memInf.memoryAttribute.isUncached), memInf.perms.r ? "R" : "-", memInf.perms.w ? "W" : "-", memInf.perms.x ? "X" : "-");
state.thisProcess->WriteMemory<memory::MemoryInfo>(memInf, state.nce->GetRegister(Xreg::X0));
state.logger->Debug("svcQueryMemory: Address: 0x{:X}, Size: 0x{:X}, Type: {}, Is Uncached: {}, Permissions: {}{}{}", memInfo.baseAddress, memInfo.size, memInfo.type, static_cast<bool>(memInfo.memoryAttribute.isUncached), memInfo.r ? "R" : "-", memInfo.w ? "W" : "-", memInfo.x ? "X" : "-");
state.process->WriteMemory<memory::MemoryInfo>(memInfo, state.nce->GetRegister(Xreg::X0));
state.nce->SetRegister(Wreg::W0, constant::status::Success);
}
void ExitProcess(DeviceState &state) {
state.logger->Debug("svcExitProcess: Exiting current process: {}", state.thisProcess->mainThread);
state.os->KillThread(state.thisProcess->mainThread);
state.logger->Debug("svcExitProcess: Exiting current process: {}", state.process->pid);
state.os->KillThread(state.process->pid);
}
void CreateThread(DeviceState &state) {
@ -132,7 +131,7 @@ namespace skyline::kernel::svc {
state.logger->Warn("svcCreateThread: 'priority' invalid: {}", priority);
return;
}
auto thread = state.thisProcess->CreateThread(entryAddr, entryArg, stackTop, priority);
auto thread = state.process->CreateThread(entryAddr, entryArg, 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, entryAddr, entryArg, stackTop, priority, thread->pid);
state.nce->SetRegister(Wreg::W1, thread->handle);
state.nce->SetRegister(Wreg::W0, constant::status::Success);
@ -141,7 +140,7 @@ namespace skyline::kernel::svc {
void StartThread(DeviceState &state) {
auto handle = state.nce->GetRegister(Wreg::W0);
try {
auto thread = state.thisProcess->GetHandle<type::KThread>(handle);
auto thread = state.process->GetHandle<type::KThread>(handle);
state.logger->Debug("svcStartThread: Starting thread: 0x{:X}, PID: {}", handle, thread->pid);
thread->Start();
} catch (const std::exception&) {
@ -151,8 +150,8 @@ namespace skyline::kernel::svc {
}
void ExitThread(DeviceState &state) {
state.logger->Debug("svcExitProcess: Exiting current thread: {}", state.thisThread->pid);
state.os->KillThread(state.thisThread->pid);
state.logger->Debug("svcExitProcess: Exiting current thread: {}", state.thread->pid);
state.os->KillThread(state.thread->pid);
}
void SleepThread(DeviceState &state) {
@ -162,19 +161,19 @@ namespace skyline::kernel::svc {
case 1:
case 2:
state.logger->Debug("svcSleepThread: Yielding thread: {}", in);
state.thisThread->status = type::KThread::Status::Runnable; // Will cause the application to awaken on the next iteration of the main loop
state.thread->status = type::KThread::Status::Runnable; // Will cause the application to awaken on the next iteration of the main loop
break;
default:
state.logger->Debug("svcSleepThread: Thread sleeping for {} ns", in);
state.thisThread->timeout = GetCurrTimeNs() + in;
state.thisThread->status = type::KThread::Status::Sleeping;
state.thread->timeout = GetCurrTimeNs() + in;
state.thread->status = type::KThread::Status::Sleeping;
}
}
void GetThreadPriority(DeviceState &state) {
auto handle = state.nce->GetRegister(Wreg::W0);
try {
auto priority = state.thisProcess->GetHandle<type::KThread>(handle)->priority;
auto priority = state.process->GetHandle<type::KThread>(handle)->priority;
state.nce->SetRegister(Wreg::W1, priority);
state.nce->SetRegister(Wreg::W0, constant::status::Success);
state.logger->Debug("svcGetThreadPriority: Writing thread priority {}", priority);
@ -188,7 +187,7 @@ namespace skyline::kernel::svc {
auto handle = state.nce->GetRegister(Wreg::W0);
auto priority = state.nce->GetRegister(Wreg::W1);
try {
state.thisProcess->GetHandle<type::KThread>(handle)->UpdatePriority(static_cast<u8>(priority));
state.process->GetHandle<type::KThread>(handle)->UpdatePriority(static_cast<u8>(priority));
state.nce->SetRegister(Wreg::W0, constant::status::Success);
state.logger->Debug("svcSetThreadPriority: Setting thread priority to {}", priority);
} catch (const std::exception&) {
@ -199,7 +198,7 @@ namespace skyline::kernel::svc {
void MapSharedMemory(DeviceState &state) {
try {
auto object = state.thisProcess->GetHandle<type::KSharedMemory>(state.nce->GetRegister(Wreg::W0));
auto object = state.process->GetHandle<type::KSharedMemory>(state.nce->GetRegister(Wreg::W0));
u64 addr = state.nce->GetRegister(Xreg::X1);
if ((addr & (PAGE_SIZE - 1U))) {
state.nce->SetRegister(Wreg::W0, constant::status::InvAddress);
@ -220,7 +219,7 @@ namespace skyline::kernel::svc {
return;
}
state.logger->Debug("svcMapSharedMemory: Mapping shared memory at 0x{:X} for {} bytes ({}{}{})", addr, size, permission.r ? "R" : "-", permission.w ? "W" : "-", permission.x ? "X" : "-");
object->Map(addr, size, permission, state.thisProcess->mainThread);
object->Map(addr, size, permission);
state.nce->SetRegister(Wreg::W0, constant::status::Success);
} catch (const std::exception &) {
state.logger->Warn("svcMapSharedMemory: 'handle' invalid: 0x{:X}", state.nce->GetRegister(Wreg::W0));
@ -249,7 +248,7 @@ namespace skyline::kernel::svc {
return;
}
state.logger->Debug("svcCreateTransferMemory: Creating transfer memory at 0x{:X} for {} bytes ({}{}{})", addr, size, permission.r ? "R" : "-", permission.w ? "W" : "-", permission.x ? "X" : "-");
auto shmem = state.thisProcess->NewHandle<type::KTransferMemory>(state.thisProcess->mainThread, addr, size, permission);
auto shmem = state.process->NewHandle<type::KTransferMemory>(state.process->pid, addr, size, permission);
state.nce->SetRegister(Wreg::W0, constant::status::Success);
state.nce->SetRegister(Wreg::W1, shmem.handle);
}
@ -257,7 +256,7 @@ namespace skyline::kernel::svc {
void CloseHandle(DeviceState &state) {
auto handle = static_cast<handle_t>(state.nce->GetRegister(Wreg::W0));
try {
state.thisProcess->handleTable.erase(handle);
state.process->handleTable.erase(handle);
state.logger->Debug("svcCloseHandle: Closing handle: 0x{:X}", handle);
state.nce->SetRegister(Wreg::W0, constant::status::Success);
} catch(const std::exception&) {
@ -269,7 +268,7 @@ namespace skyline::kernel::svc {
void ResetSignal(DeviceState &state) {
auto handle = state.nce->GetRegister(Wreg::W0);
try {
auto &object = state.thisProcess->handleTable.at(handle);
auto &object = state.process->handleTable.at(handle);
switch (object->objectType) {
case (type::KType::KEvent):
std::static_pointer_cast<type::KEvent>(object)->ResetSignal();
@ -299,12 +298,12 @@ namespace skyline::kernel::svc {
return;
}
std::vector<handle_t> waitHandles(numHandles);
state.thisProcess->ReadMemory(waitHandles.data(), state.nce->GetRegister(Xreg::X1), numHandles * sizeof(handle_t));
state.process->ReadMemory(waitHandles.data(), state.nce->GetRegister(Xreg::X1), numHandles * sizeof(handle_t));
std::string handleStr;
uint index{};
for (const auto &handle : waitHandles) {
handleStr += fmt::format("* 0x{:X}\n", handle);
auto object = state.thisProcess->handleTable.at(handle);
auto object = state.process->handleTable.at(handle);
switch (object->objectType) {
case type::KType::KProcess:
case type::KType::KThread:
@ -313,7 +312,7 @@ namespace skyline::kernel::svc {
break;
default: {
state.nce->SetRegister(Wreg::W0, constant::status::InvHandle);
state.thisThread->ClearWaitObjects();
state.thread->ClearWaitObjects();
return;
}
}
@ -322,19 +321,19 @@ namespace skyline::kernel::svc {
state.logger->Debug("svcWaitSynchronization: Signalled handle: 0x{:X}", handle);
state.nce->SetRegister(Wreg::W0, constant::status::Success);
state.nce->SetRegister(Wreg::W1, index);
state.thisThread->ClearWaitObjects();
state.thread->ClearWaitObjects();
return;
}
state.thisThread->waitObjects.push_back(syncObject);
syncObject->waitThreads.emplace_back(state.thisThread->pid, index);
state.thread->waitObjects.push_back(syncObject);
syncObject->waitThreads.emplace_back(state.thread->pid, index);
}
auto timeout = state.nce->GetRegister(Xreg::X3);
state.logger->Debug("svcWaitSynchronization: Waiting on handles:\n{}Timeout: 0x{:X} ns", handleStr, timeout);
if (state.nce->GetRegister(Xreg::X3) != std::numeric_limits<u64>::max())
state.thisThread->timeout = GetCurrTimeNs() + timeout;
state.thread->timeout = GetCurrTimeNs() + timeout;
else
state.thisThread->timeout = 0;
state.thisThread->status = type::KThread::Status::WaitSync;
state.thread->timeout = 0;
state.thread->status = type::KThread::Status::WaitSync;
}
void ArbitrateLock(DeviceState &state) {
@ -345,10 +344,10 @@ namespace skyline::kernel::svc {
return;
}
auto handle = state.nce->GetRegister(Wreg::W2);
if (handle != state.thisThread->handle)
if (handle != state.thread->handle)
throw exception("svcArbitrateLock: Called from another thread");
state.logger->Debug("svcArbitrateLock: Locking mutex at 0x{:X} for thread 0x{:X}", addr, handle);
state.thisProcess->MutexLock(addr);
state.process->MutexLock(addr);
state.nce->SetRegister(Wreg::W0, constant::status::Success);
}
@ -360,7 +359,7 @@ namespace skyline::kernel::svc {
return;
}
state.logger->Debug("svcArbitrateUnlock: Unlocking mutex at 0x{:X}", addr);
state.thisProcess->MutexUnlock(addr);
state.process->MutexUnlock(addr);
state.nce->SetRegister(Wreg::W0, constant::status::Success);
}
@ -372,24 +371,24 @@ namespace skyline::kernel::svc {
return;
}
auto handle = state.nce->GetRegister(Wreg::W2);
if (handle != state.thisThread->handle)
if (handle != state.thread->handle)
throw exception("svcWaitProcessWideKeyAtomic: Called from another thread");
state.thisProcess->MutexUnlock(mtxAddr);
state.process->MutexUnlock(mtxAddr);
auto condAddr = state.nce->GetRegister(Xreg::X1);
auto &cvarVec = state.thisProcess->condVarMap[condAddr];
auto &cvarVec = state.process->condVarMap[condAddr];
for (auto thread = cvarVec.begin();; thread++) {
if ((*thread)->priority < state.thisThread->priority) {
cvarVec.insert(thread, state.thisThread);
if ((*thread)->priority < state.thread->priority) {
cvarVec.insert(thread, state.thread);
break;
} else if (thread + 1 == cvarVec.end()) {
cvarVec.push_back(state.thisThread);
cvarVec.push_back(state.thread);
break;
}
}
auto timeout = state.nce->GetRegister(Xreg::X3);
state.logger->Debug("svcWaitProcessWideKeyAtomic: Mutex: 0x{:X}, Conditional-Variable: 0x:{:X}, Timeout: {} ns", mtxAddr, condAddr, timeout);
state.thisThread->status = type::KThread::Status::WaitCondVar;
state.thisThread->timeout = GetCurrTimeNs() + timeout;
state.thread->status = type::KThread::Status::WaitCondVar;
state.thread->timeout = GetCurrTimeNs() + timeout;
state.nce->SetRegister(Wreg::W0, constant::status::Success);
}
@ -397,17 +396,17 @@ namespace skyline::kernel::svc {
auto address = state.nce->GetRegister(Xreg::X0);
auto count = state.nce->GetRegister(Wreg::W1);
state.nce->SetRegister(Wreg::W0, constant::status::Success);
if (!state.thisProcess->condVarMap.count(address)) {
if (!state.process->condVarMap.count(address)) {
state.logger->Debug("svcSignalProcessWideKey: No Conditional-Variable at 0x{:X}", address);
return;
}
auto &cvarVec = state.thisProcess->condVarMap.at(address);
auto &cvarVec = state.process->condVarMap.at(address);
count = std::min(count, static_cast<u32>(cvarVec.size()));
for (uint index = 0; index < count; index++)
cvarVec[index]->status = type::KThread::Status::Runnable;
cvarVec.erase(cvarVec.begin(), cvarVec.begin() + count);
if (cvarVec.empty())
state.thisProcess->condVarMap.erase(address);
state.process->condVarMap.erase(address);
state.logger->Debug("svcSignalProcessWideKey: Signalling Conditional-Variable at 0x{:X} for {}", address, count);
}
@ -426,7 +425,7 @@ namespace skyline::kernel::svc {
void ConnectToNamedPort(DeviceState &state) {
char port[constant::PortSize + 1]{0};
state.os->thisProcess->ReadMemory(port, state.nce->GetRegister(Xreg::X1), constant::PortSize);
state.process->ReadMemory(port, state.nce->GetRegister(Xreg::X1), constant::PortSize);
handle_t handle{};
if (std::strcmp(port, "sm:") == 0)
handle = state.os->serviceManager.NewSession(service::Service::sm);
@ -449,9 +448,9 @@ namespace skyline::kernel::svc {
pid_t pid{};
auto handle = state.nce->GetRegister(Wreg::W1);
if (handle != constant::ThreadSelf) {
pid = state.thisProcess->GetHandle<type::KThread>(handle)->pid;
pid = state.process->GetHandle<type::KThread>(handle)->pid;
} else
pid = state.thisThread->pid;
pid = state.thread->pid;
state.logger->Debug("svcGetThreadId: Handle: 0x{:X}, PID: {}", handle, pid);
state.nce->SetRegister(Xreg::X1, static_cast<u64>(pid));
state.nce->SetRegister(Wreg::W0, constant::status::Success);
@ -459,7 +458,7 @@ namespace skyline::kernel::svc {
void OutputDebugString(DeviceState &state) {
std::string debug(state.nce->GetRegister(Xreg::X1), '\0');
state.os->thisProcess->ReadMemory(debug.data(), state.nce->GetRegister(Xreg::X0), state.nce->GetRegister(Xreg::X1));
state.process->ReadMemory(debug.data(), state.nce->GetRegister(Xreg::X0), state.nce->GetRegister(Xreg::X1));
if(debug.back() == '\n')
debug.pop_back();
state.logger->Info("Debug Output: {}", debug);
@ -485,16 +484,16 @@ namespace skyline::kernel::svc {
out = constant::MapSize;
break;
case constant::infoState::HeapRegionBaseAddr:
out = state.os->thisProcess->memoryRegionMap.at(memory::Region::Heap)->address;
out = state.process->memoryRegionMap.at(memory::Region::Heap)->address;
break;
case constant::infoState::HeapRegionSize:
out = state.os->thisProcess->memoryRegionMap.at(memory::Region::Heap)->size;
out = state.process->memoryRegionMap.at(memory::Region::Heap)->size;
break;
case constant::infoState::TotalMemoryAvailable:
out = constant::TotalPhyMem;
break;
case constant::infoState::TotalMemoryUsage:
out = state.os->thisProcess->memoryRegionMap.at(memory::Region::Heap)->address + state.thisProcess->mainThreadStackSz + state.thisProcess->GetProgramSize();
out = state.process->memoryRegionMap.at(memory::Region::Heap)->address + state.process->mainThreadStackSz + state.process->GetProgramSize();
break;
case constant::infoState::AddressSpaceBaseAddr:
out = constant::BaseAddr;
@ -503,25 +502,25 @@ namespace skyline::kernel::svc {
out = constant::BaseSize;
break;
case constant::infoState::StackRegionBaseAddr:
out = state.thisThread->stackTop;
out = state.thread->stackTop;
break;
case constant::infoState::StackRegionSize:
out = state.thisProcess->mainThreadStackSz;
out = state.process->mainThreadStackSz;
break;
case constant::infoState::PersonalMmHeapSize:
out = constant::TotalPhyMem;
break;
case constant::infoState::PersonalMmHeapUsage:
out = state.os->thisProcess->memoryRegionMap.at(memory::Region::Heap)->address + state.thisProcess->mainThreadStackSz;
out = state.process->memoryRegionMap.at(memory::Region::Heap)->address + state.process->mainThreadStackSz;
break;
case constant::infoState::TotalMemoryAvailableWithoutMmHeap:
out = constant::TotalPhyMem; // TODO: NPDM specifies SystemResourceSize, subtract that from this
break;
case constant::infoState::TotalMemoryUsedWithoutMmHeap:
out = state.os->thisProcess->memoryRegionMap.at(memory::Region::Heap)->address + state.thisProcess->mainThreadStackSz; // TODO: Same as above
out = state.process->memoryRegionMap.at(memory::Region::Heap)->address + state.process->mainThreadStackSz; // TODO: Same as above
break;
case constant::infoState::UserExceptionContextAddr:
out = state.thisProcess->tlsPages[0]->Get(0);
out = state.process->tlsPages[0]->Get(0);
break;
default:
state.logger->Warn("svcGetInfo: Unimplemented case ID0: {}, ID1: {}", id0, id1);

View File

@ -1,4 +1,5 @@
#include "KPrivateMemory.h"
#include "KProcess.h"
#include <nce.h>
namespace skyline::kernel::type {
@ -11,13 +12,13 @@ namespace skyline::kernel::type {
return dstAddress;
}
KPrivateMemory::KPrivateMemory(const DeviceState &state, pid_t pid, u64 dstAddress, u64 srcAddress, size_t size, memory::Permission permission, const memory::Type type) : state(state), owner(pid), address(dstAddress), size(size), permission(permission), type(type), KObject(state, KType::KPrivateMemory) {
KPrivateMemory::KPrivateMemory(const DeviceState &state, u64 dstAddress, u64 srcAddress, size_t size, memory::Permission permission, const memory::Type type, const pid_t pid) : state(state), address(dstAddress), size(size), permission(permission), type(type), KObject(state, KType::KPrivateMemory) {
user_pt_regs fregs = {0};
fregs.regs[0] = dstAddress;
fregs.regs[1] = srcAddress;
fregs.regs[2] = size;
fregs.regs[3] = static_cast<u64>(permission.Get());
state.nce->ExecuteFunction(reinterpret_cast<void *>(MapPrivateFunc), fregs, pid);
state.nce->ExecuteFunction(reinterpret_cast<void *>(MapPrivateFunc), fregs, pid ? pid : state.process->pid);
if (reinterpret_cast<void *>(fregs.regs[0]) == MAP_FAILED)
throw exception("An error occurred while mapping private region in child process");
if (!this->address)
@ -34,7 +35,7 @@ namespace skyline::kernel::type {
fregs.regs[1] = size;
fregs.regs[2] = newSize;
fregs.regs[3] = canMove ? MREMAP_MAYMOVE : 0;
state.nce->ExecuteFunction(reinterpret_cast<void *>(RemapPrivateFunc), fregs, owner);
state.nce->ExecuteFunction(reinterpret_cast<void *>(RemapPrivateFunc), fregs, state.process->pid);
if (reinterpret_cast<void *>(fregs.regs[0]) == MAP_FAILED)
throw exception("An error occurred while remapping private region in child process");
address = fregs.regs[0];
@ -51,7 +52,7 @@ namespace skyline::kernel::type {
fregs.regs[0] = address;
fregs.regs[1] = size;
fregs.regs[2] = static_cast<u64>(permission.Get());
state.nce->ExecuteFunction(reinterpret_cast<void *>(UpdatePermissionPrivateFunc), fregs, owner);
state.nce->ExecuteFunction(reinterpret_cast<void *>(UpdatePermissionPrivateFunc), fregs, state.process->pid);
if (static_cast<int>(fregs.regs[0]) == -1)
throw exception("An error occurred while updating private region's permissions in child process");
this->permission = permission;
@ -61,14 +62,15 @@ namespace skyline::kernel::type {
memory::MemoryInfo info{};
info.baseAddress = address;
info.size = size;
info.type = static_cast<u64>(type);
for (const auto &region : regionInfoVec) {
info.type = static_cast<u32>(type);
for (const auto &region : regionInfoVec)
if ((address >= region.address) && (address < (region.address + region.size)))
info.memoryAttribute.isUncached = region.isUncached;
}
info.memoryAttribute.isIpcLocked = (info.ipcRefCount > 0);
info.memoryAttribute.isDeviceShared = (info.deviceRefCount > 0);
info.perms = permission;
info.r = permission.r;
info.w = permission.w;
info.x = permission.x;
info.ipcRefCount = ipcRefCount;
info.deviceRefCount = deviceRefCount;
return info;
@ -83,7 +85,7 @@ namespace skyline::kernel::type {
user_pt_regs fregs = {0};
fregs.regs[0] = address;
fregs.regs[1] = size;
state.nce->ExecuteFunction(reinterpret_cast<void *>(UnmapPrivateFunc), fregs, owner);
state.nce->ExecuteFunction(reinterpret_cast<void *>(UnmapPrivateFunc), fregs, state.process->pid);
} catch (const std::exception &) {
}
}

View File

@ -12,7 +12,6 @@ namespace skyline::kernel::type {
const DeviceState &state; //!< The state of the device
public:
pid_t owner; //!< The PID of the process owning this memory
u64 address; //!< The address of the allocated memory
size_t size; //!< The size of the allocated memory
u16 ipcRefCount{}; //!< The amount of reference to this memory for IPC
@ -23,14 +22,14 @@ namespace skyline::kernel::type {
/**
* @param state The state of the device
* @param pid The PID of the main
* @param dstAddress The address to map to (If NULL then an arbitrary address is picked)
* @param srcAddress The address to map from (If NULL then no copy is performed)
* @param size The size of the allocation
* @param permission The permissions for the allocated memory
* @param type The type of the memory
* @param pid The PID of the me
*/
KPrivateMemory(const DeviceState &state, pid_t pid, u64 dstAddress, u64 srcAddress, size_t size, memory::Permission permission, const memory::Type type);
KPrivateMemory(const DeviceState &state, u64 dstAddress, u64 srcAddress, size_t size, memory::Permission permission, const memory::Type type, const pid_t pid=0);
/**
* @brief Remap a chunk of memory as to change the size occupied by it

View File

@ -29,7 +29,7 @@ namespace skyline::kernel::type {
if (!tlsPage->Full())
return tlsPage->ReserveSlot();
}
auto tlsMem = NewHandle<KPrivateMemory>(mainThread, 0, 0, PAGE_SIZE, memory::Permission(true, true, false), memory::Type::ThreadLocal).item;
auto tlsMem = NewHandle<KPrivateMemory>(0, 0, PAGE_SIZE, memory::Permission(true, true, false), memory::Type::ThreadLocal, pid).item;
memoryMap[tlsMem->address] = tlsMem;
tlsPages.push_back(std::make_shared<TlsPage>(tlsMem->address));
auto &tlsPage = tlsPages.back();
@ -38,7 +38,7 @@ namespace skyline::kernel::type {
return tlsPage->ReserveSlot();
}
KProcess::KProcess(const DeviceState &state, pid_t pid, u64 entryPoint, u64 stackBase, u64 stackSize) : mainThread(pid), mainThreadStackSz(stackSize), KSyncObject(state, KType::KProcess) {
KProcess::KProcess(const DeviceState &state, pid_t pid, u64 entryPoint, u64 stackBase, u64 stackSize) : pid(pid), mainThreadStackSz(stackSize), KSyncObject(state, KType::KProcess) {
state.nce->WaitRdy(pid);
threadMap[pid] = NewHandle<KThread>(pid, entryPoint, 0x0, stackBase + stackSize, GetTlsSlot(), constant::DefaultPriority, this).item;
MapPrivateRegion(constant::HeapAddr, constant::DefHeapSize, {true, true, false}, memory::Type::Heap, memory::Region::Heap);
@ -68,13 +68,12 @@ namespace skyline::kernel::type {
user_pt_regs fregs = {0};
fregs.regs[0] = entryPoint;
fregs.regs[1] = stackTop;
state.nce->ExecuteFunction((void *) CreateThreadFunc, fregs, mainThread);
state.nce->ExecuteFunction((void *) CreateThreadFunc, fregs, pid);
auto pid = static_cast<pid_t>(fregs.regs[0]);
if (pid == -1)
throw exception("Cannot create thread: Address: 0x{:X}, Stack Top: 0x{:X}", entryPoint, stackTop);
auto process = NewHandle<KThread>(pid, entryPoint, entryArg, stackTop, GetTlsSlot(), priority, this).item;
threadMap[pid] = process;
state.os->processMap[pid] = state.os->processMap[mainThread];
return process;
}
@ -91,7 +90,7 @@ namespace skyline::kernel::type {
}
KProcess::HandleOut<KPrivateMemory> KProcess::MapPrivateRegion(u64 address, size_t size, const memory::Permission perms, const memory::Type type, const memory::Region region) {
auto mem = NewHandle<KPrivateMemory>(mainThread, address, 0, size, perms, type);
auto mem = NewHandle<KPrivateMemory>(address, 0, size, perms, type, pid);
memoryMap[mem.item->address] = mem.item;
memoryRegionMap[region] = mem.item;
return mem;
@ -113,29 +112,29 @@ namespace skyline::kernel::type {
}
void KProcess::MutexLock(u64 address) {
auto mtxVec = state.thisProcess->mutexMap[address];
u32 mtxVal = state.thisProcess->ReadMemory<u32>(address);
auto mtxVec = state.process->mutexMap[address];
u32 mtxVal = state.process->ReadMemory<u32>(address);
if (mtxVec.empty()) {
mtxVal = (mtxVal & ~constant::MtxOwnerMask) | state.thisThread->handle;
state.thisProcess->WriteMemory(mtxVal, address);
mtxVal = (mtxVal & ~constant::MtxOwnerMask) | state.thread->handle;
state.process->WriteMemory(mtxVal, address);
} else {
for (auto thread = mtxVec.begin();; thread++) {
if ((*thread)->priority < state.thisThread->priority) {
mtxVec.insert(thread, state.thisThread);
if ((*thread)->priority < state.thread->priority) {
mtxVec.insert(thread, state.thread);
break;
} else if (thread + 1 == mtxVec.end()) {
mtxVec.push_back(state.thisThread);
mtxVec.push_back(state.thread);
break;
}
}
state.thisThread->status = KThread::Status::WaitMutex;
state.thread->status = KThread::Status::WaitMutex;
}
}
void KProcess::MutexUnlock(u64 address) {
auto mtxVec = state.thisProcess->mutexMap[address];
u32 mtxVal = state.thisProcess->ReadMemory<u32>(address);
if ((mtxVal & constant::MtxOwnerMask) != state.thisThread->pid)
auto mtxVec = state.process->mutexMap[address];
u32 mtxVal = state.process->ReadMemory<u32>(address);
if ((mtxVal & constant::MtxOwnerMask) != state.thread->pid)
throw exception("A non-owner thread tried to release a mutex");
if (mtxVec.empty()) {
mtxVal = 0;
@ -147,7 +146,7 @@ namespace skyline::kernel::type {
if (!mtxVec.empty())
mtxVal |= (~constant::MtxOwnerMask);
}
state.thisProcess->WriteMemory(mtxVal, address);
state.process->WriteMemory(mtxVal, address);
}
void KProcess::ResetSignal() {

View File

@ -63,7 +63,7 @@ namespace skyline::kernel::type {
Exiting //!< The process is exiting
} status = Status::Created; //!< The state of the process
handle_t handleIndex = constant::BaseHandleIndex; //!< This is used to keep track of what to map as an handle
pid_t mainThread; //!< The PID of the main thread
pid_t pid; //!< The PID of the main thread
size_t mainThreadStackSz; //!< The size of the main thread's stack (All other threads map stack themselves so we don't know the size per-se)
int memFd; //!< The file descriptor to the memory of the process
std::unordered_map<u64, std::shared_ptr<KPrivateMemory>> memoryMap; //!< A mapping from every address to a shared pointer of it's corresponding KPrivateMemory, used to keep track of KPrivateMemory instances

View File

@ -1,4 +1,5 @@
#include "KSharedMemory.h"
#include "KProcess.h"
#include <nce.h>
#include <android/sharedmem.h>
#include <unistd.h>
@ -15,19 +16,19 @@ namespace skyline::kernel::type {
address = MapSharedFunc(address, size, static_cast<u64>(permission.Get()), static_cast<u64>(fd));
if (address == reinterpret_cast<u64>(MAP_FAILED)) // NOLINT(hicpp-signed-bitwise)
throw exception("An occurred while mapping shared region: {}", strerror(errno));
procInfMap[0] = {address, size, permission};
kernel = {address, size, permission};
}
u64 KSharedMemory::Map(u64 address, u64 size, memory::Permission permission, pid_t pid) {
u64 KSharedMemory::Map(u64 address, u64 size, memory::Permission permission) {
user_pt_regs fregs = {0};
fregs.regs[0] = address;
fregs.regs[1] = size;
fregs.regs[2] = static_cast<u64>(permission.Get());
fregs.regs[3] = static_cast<u64>(fd);
state.nce->ExecuteFunction(reinterpret_cast<void *>(MapSharedFunc), fregs, pid);
state.nce->ExecuteFunction(reinterpret_cast<void *>(MapSharedFunc), fregs, state.process->pid);
if (reinterpret_cast<void *>(fregs.regs[0]) == MAP_FAILED)
throw exception("An error occurred while mapping shared region in child process");
procInfMap[pid] = {fregs.regs[0], size, permission};
guest = {fregs.regs[0], size, permission};
return fregs.regs[0];
}
@ -36,16 +37,16 @@ namespace skyline::kernel::type {
}
KSharedMemory::~KSharedMemory() {
for (auto[process, procInf] : procInfMap) {
try {
if(process) {
user_pt_regs fregs = {0};
fregs.regs[0] = procInf.address;
fregs.regs[1] = procInf.size;
state.nce->ExecuteFunction(reinterpret_cast<void *>(UnmapSharedFunc), fregs, process);
} else
UnmapSharedFunc(procInf.address, procInf.size);
} catch (const std::exception &) {}
try {
if (guest.valid()) {
user_pt_regs fregs = {0};
fregs.regs[0] = guest.address;
fregs.regs[1] = guest.size;
state.nce->ExecuteFunction(reinterpret_cast<void *>(UnmapSharedFunc), fregs, state.process->pid);
}
if (kernel.valid())
UnmapSharedFunc(kernel.address, kernel.size);
} catch (const std::exception &) {
}
close(fd);
}
@ -54,21 +55,21 @@ namespace skyline::kernel::type {
return reinterpret_cast<u64>(mremap(reinterpret_cast<void *>(address), oldSize, size, 0));
}
void KSharedMemory::Resize(size_t newSize) {
for (auto&[process, procInf] : procInfMap) {
if(process) {
user_pt_regs fregs = {0};
fregs.regs[0] = procInf.address;
fregs.regs[1] = procInf.size;
fregs.regs[2] = newSize;
state.nce->ExecuteFunction(reinterpret_cast<void *>(RemapSharedFunc), fregs, process);
if (reinterpret_cast<void *>(fregs.regs[0]) == MAP_FAILED)
throw exception("An error occurred while remapping shared region in child process");
} else {
if (RemapSharedFunc(procInf.address, procInf.size, newSize) == reinterpret_cast<u64>(MAP_FAILED))
throw exception("An occurred while remapping shared region: {}", strerror(errno));
}
procInf.size = newSize;
void KSharedMemory::Resize(size_t size) {
if (guest.valid()) {
user_pt_regs fregs = {0};
fregs.regs[0] = guest.address;
fregs.regs[1] = guest.size;
fregs.regs[2] = size;
state.nce->ExecuteFunction(reinterpret_cast<void *>(RemapSharedFunc), fregs, state.process->pid);
if (reinterpret_cast<void *>(fregs.regs[0]) == MAP_FAILED)
throw exception("An error occurred while remapping shared region in child process");
guest.size = size;
}
if (kernel.valid()) {
if (RemapSharedFunc(kernel.address, kernel.size, size) == reinterpret_cast<u64>(MAP_FAILED))
throw exception("An occurred while remapping shared region: {}", strerror(errno));
kernel.size = size;
}
}
@ -76,33 +77,34 @@ namespace skyline::kernel::type {
return static_cast<u64>(mprotect(reinterpret_cast<void *>(address), size, static_cast<int>(perms)));
}
void KSharedMemory::UpdatePermission(pid_t pid, memory::Permission permission) {
for (auto&[process, procInf] : procInfMap) {
if(process) {
user_pt_regs fregs = {0};
fregs.regs[0] = procInf.address;
fregs.regs[1] = procInf.size;
fregs.regs[2] = static_cast<u64>(procInf.permission.Get());
state.nce->ExecuteFunction(reinterpret_cast<void *>(UpdatePermissionSharedFunc), fregs, process);
if (static_cast<int>(fregs.regs[0]) == -1)
throw exception("An error occurred while updating shared region's permissions in child process");
} else {
if (UpdatePermissionSharedFunc(procInf.address, procInf.size, static_cast<u64>(permission.Get())) == reinterpret_cast<u64>(MAP_FAILED))
throw exception("An occurred while remapping shared region: {}", strerror(errno));
}
procInf.permission = permission;
void KSharedMemory::UpdatePermission(memory::Permission permission, bool host) {
if (guest.valid() && !host) {
user_pt_regs fregs = {0};
fregs.regs[0] = guest.address;
fregs.regs[1] = guest.size;
fregs.regs[2] = static_cast<u64>(guest.permission.Get());
state.nce->ExecuteFunction(reinterpret_cast<void *>(UpdatePermissionSharedFunc), fregs, state.process->pid);
if (static_cast<int>(fregs.regs[0]) == -1)
throw exception("An error occurred while updating shared region's permissions in child process");
guest.permission = permission;
}
if (kernel.valid() && host) {
if (UpdatePermissionSharedFunc(kernel.address, kernel.size, static_cast<u64>(permission.Get())) == reinterpret_cast<u64>(MAP_FAILED))
throw exception("An occurred while remapping shared region: {}", strerror(errno));
kernel.permission = permission;
}
}
memory::MemoryInfo KSharedMemory::GetInfo(pid_t pid) {
memory::MemoryInfo KSharedMemory::GetInfo() {
memory::MemoryInfo info{};
const auto &procInf = procInfMap.at(pid);
info.baseAddress = procInf.address;
info.size = procInf.size;
info.type = static_cast<u64>(type);
info.baseAddress = guest.address;
info.size = guest.size;
info.type = static_cast<u32>(type);
info.memoryAttribute.isIpcLocked = (info.ipcRefCount > 0);
info.memoryAttribute.isDeviceShared = (info.deviceRefCount > 0);
info.perms = procInf.permission;
info.r = guest.permission.r;
info.w = guest.permission.w;
info.x = guest.permission.x;
info.ipcRefCount = ipcRefCount;
info.deviceRefCount = deviceRefCount;
return info;

View File

@ -15,12 +15,18 @@ namespace skyline::kernel::type {
/**
* @brief This holds the address and size of a process's mapping
*/
struct ProcessInfo {
struct MapInfo {
u64 address;
size_t size;
memory::Permission permission;
};
std::unordered_map<pid_t, ProcessInfo> procInfMap; //!< Maps from a PID to where the memory was mapped to
/**
* @brief Returns if the object is valid
* @return If the MapInfo object is valid
*/
inline bool valid() { return address && size && permission.Get(); }
} kernel, guest;
u16 ipcRefCount{}; //!< The amount of reference to this memory for IPC
u16 deviceRefCount{}; //!< The amount of reference to this memory for IPC
memory::Type type; //!< The type of this memory allocation
@ -35,33 +41,32 @@ namespace skyline::kernel::type {
KSharedMemory(const DeviceState &state, u64 address, size_t size, const memory::Permission permission, memory::Type type);
/**
* @brief Maps the shared memory at an address
* @brief Maps the shared memory at an address in the guest
* @param address The address to map to (If NULL an arbitrary address is picked)
* @param size The amount of shared memory to map
* @param permission The permission of the kernel process
* @param pid The PID of the process
* @return The address of the allocation
*/
u64 Map(const u64 address, const u64 size, memory::Permission permission, pid_t pid);
u64 Map(const u64 address, const u64 size, memory::Permission permission);
/**
* @brief Resize a chunk of memory as to change the size occupied by it
* @param newSize The new size of the memory
* @param size The new size of the memory
*/
void Resize(size_t newSize);
void Resize(size_t size);
/**
* Updates the permissions of a chunk of mapped memory
* @param pid The PID of the requesting process
* @brief Updates the permissions of a chunk of mapped memory
* @param permission The new permissions to be set for the memory
* @param kernel Set the permissions for the kernel rather than the guest
*/
void UpdatePermission(pid_t pid, memory::Permission permission);
void UpdatePermission(memory::Permission permission, bool host=0);
/**
* @param pid The PID of the requesting process
* @brief Creates a MemoryInfo struct from the current instance
* @return A Memory::MemoryInfo struct based on attributes of the memory
*/
memory::MemoryInfo GetInfo(pid_t pid);
memory::MemoryInfo GetInfo();
/**
* @brief The destructor of shared memory, it deallocates the memory from all processes

View File

@ -9,7 +9,7 @@ namespace skyline::kernel::type {
void KSyncObject::Signal() {
for (const auto &info : waitThreads) {
state.nce->SetRegister(Wreg::W1, info.index);
state.os->processMap.at(info.process)->threadMap.at(info.process)->status = KThread::Status::Runnable;
state.process->threadMap.at(info.process)->status = KThread::Status::Runnable;
}
waitThreads.clear();
}

View File

@ -14,7 +14,7 @@ namespace skyline::kernel::type {
void KThread::Start() {
if(status == Status::Created) {
if (pid == parent->mainThread)
if (pid == parent->pid)
parent->status = KProcess::Status::Started;
status = Status::Running;
state.nce->StartProcess(entryPoint, entryArg, stackTop, handle, pid);

View File

@ -45,17 +45,12 @@ namespace skyline::kernel::type {
throw exception("An error occurred while mapping transfer memory in kernel");
}
size_t copySz = std::min(size, cSize);
if (process && owner) {
std::vector<u8> tempBuf(copySz);
state.os->processMap.at(process)->ReadMemory(tempBuf.data(), cAddress, copySz);
state.os->processMap.at(owner)->WriteMemory(tempBuf.data(), address, copySz);
} else if (process && !owner) {
state.os->processMap.at(process)->WriteMemory(reinterpret_cast<void *>(cAddress), address, copySz);
if (process && !owner) {
state.process->WriteMemory(reinterpret_cast<void *>(cAddress), address, copySz);
} else if (!process && owner) {
state.os->processMap.at(owner)->ReadMemory(reinterpret_cast<void *>(address), cAddress, copySz);
} else {
state.process->ReadMemory(reinterpret_cast<void *>(address), cAddress, copySz);
} else
throw exception("Transferring from kernel to kernel is not supported");
}
if (owner) {
user_pt_regs fregs = {0};
fregs.regs[0] = address;
@ -81,7 +76,9 @@ namespace skyline::kernel::type {
info.type = static_cast<u64>(memory::Type::TransferMemory);
info.memoryAttribute.isIpcLocked = (info.ipcRefCount > 0);
info.memoryAttribute.isDeviceShared = (info.deviceRefCount > 0);
info.perms = permission;
info.r = permission.r;
info.w = permission.w;
info.x = permission.x;
info.ipcRefCount = ipcRefCount;
info.deviceRefCount = deviceRefCount;
return info;

View File

@ -30,12 +30,12 @@ namespace skyline::memory {
/**
* @brief Equality operator between two Permission objects
*/
bool operator==(const Permission &rhs) const { return (this->r == rhs.r && this->w == rhs.w && this->x == rhs.x); };
inline bool operator==(const Permission &rhs) const { return (this->r == rhs.r && this->w == rhs.w && this->x == rhs.x); };
/**
* @brief Inequality operator between two Permission objects
*/
bool operator!=(const Permission &rhs) const { return !operator==(rhs); };
inline bool operator!=(const Permission &rhs) const { return !operator==(rhs); };
/**
* @return The value of the permission struct in mmap(2) format
@ -51,18 +51,24 @@ namespace skyline::memory {
return perm;
};
bool r : 1, w : 1, x : 1;
bool r;
bool w;
bool x;
};
/**
* @brief This holds certain attributes of a chunk of memory: https://switchbrew.org/wiki/SVC#MemoryAttribute
*/
struct MemoryAttribute {
bool isBorrowed : 1;
bool isIpcLocked : 1;
bool isDeviceShared : 1;
bool isUncached : 1;
union MemoryAttribute {
struct {
bool isBorrowed : 1;
bool isIpcLocked : 1;
bool isDeviceShared : 1;
bool isUncached : 1;
};
u32 value;
};
static_assert(sizeof(MemoryAttribute) == sizeof(u32));
/**
* @brief This describes the properties of a region of the allocated memory
@ -81,12 +87,17 @@ namespace skyline::memory {
struct MemoryInfo {
u64 baseAddress;
u64 size;
u64 type;
u32 type;
MemoryAttribute memoryAttribute;
Permission perms;
union {
u32 _pad0_;
struct {
bool r : 1, w : 1, x : 1;
};
};
u32 ipcRefCount;
u32 deviceRefCount;
u32 : 32;
u32 : 32;
};
static_assert(sizeof(MemoryInfo) == 0x28);

View File

@ -9,175 +9,6 @@ extern bool Halt;
extern skyline::Mutex jniMtx;
namespace skyline {
namespace instr {
/**
* @brief A bit-field struct that encapsulates a BRK instruction. See https://developer.arm.com/docs/ddi0596/latest/base-instructions-alphabetic-order/brk-breakpoint-instruction.
*/
struct Brk {
/**
* @brief Creates a BRK instruction with a specific immediate value, used for generating BRK opcodes
* @param value The immediate value of the instruction
*/
explicit Brk(u16 value) {
start = 0x0; // First 5 bits of a BRK instruction are 0
this->value = value;
end = 0x6A1; // Last 11 bits of a BRK instruction stored as u16
}
/**
* @brief Returns if the opcode is valid or not
* @return If the opcode represents a valid BRK instruction
*/
inline bool Verify() {
return (start == 0x0 && end == 0x6A1);
}
union {
struct {
u8 start : 5;
u32 value : 16;
u16 end : 11;
};
u32 raw{};
};
};
static_assert(sizeof(Brk) == sizeof(u32));
/**
* @brief A bit-field struct that encapsulates a SVC instruction. See https://developer.arm.com/docs/ddi0596/latest/base-instructions-alphabetic-order/svc-supervisor-call.
*/
struct Svc {
/**
* @brief Returns if the opcode is valid or not
* @return If the opcode represents a valid SVC instruction
*/
inline bool Verify() {
return (start == 0x1 && end == 0x6A0);
}
union {
struct {
u8 start : 5;
u32 value : 16;
u16 end : 11;
};
u32 raw{};
};
};
static_assert(sizeof(Svc) == sizeof(u32));
/**
* @brief A bit-field struct that encapsulates a MRS instruction. See https://developer.arm.com/docs/ddi0596/latest/base-instructions-alphabetic-order/mrs-move-system-register.
*/
struct Mrs {
/**
* @brief Creates a MRS instruction, used for generating BRK opcodes
* @param srcReg The source system register
* @param dstReg The destination Xn register
*/
Mrs(u32 srcReg, u8 dstReg) {
this->srcReg = srcReg;
this->dstReg = dstReg;
end = 0xD53; // Last 12 bits of a MRS instruction stored as u16
}
/**
* @brief Returns if the opcode is valid or not
* @return If the opcode represents a valid MRS instruction
*/
inline bool Verify() {
return (end == 0xD53);
}
union {
struct {
u8 dstReg : 5;
u32 srcReg : 15;
u16 end : 12;
};
u32 raw{};
};
};
static_assert(sizeof(Mrs) == sizeof(u32));
/**
* @brief A bit-field struct that encapsulates a B instruction. See https://developer.arm.com/docs/ddi0596/latest/base-instructions-alphabetic-order/b-branch.
*/
struct B {
public:
explicit B(i64 offset) {
this->offset = static_cast<i32>(offset / 4);
end = 0x5;
}
/**
* @brief Returns the offset of the instruction
* @return The offset encoded within the instruction
*/
inline i32 Offset() {
return offset * 4;
}
/**
* @brief Returns if the opcode is valid or not
* @return If the opcode represents a valid Branch instruction
*/
inline bool Verify() {
return (end == 0x5);
}
union {
struct {
i32 offset : 26;
u8 end : 6;
};
u32 raw{};
};
};
static_assert(sizeof(B) == sizeof(u32));
/**
* @brief A bit-field struct that encapsulates a BL instruction. See https://developer.arm.com/docs/ddi0596/latest/base-instructions-alphabetic-order/b-branch.
*/
struct BL {
public:
explicit BL(i64 offset) {
this->offset = static_cast<i32>(offset / 4);
end = 0x25;
}
/**
* @brief Returns the offset of the instruction
* @return The offset encoded within the instruction
*/
inline i32 Offset() {
return offset * 4;
}
/**
* @brief Returns if the opcode is valid or not
* @return If the opcode represents a valid Branch instruction
*/
inline bool Verify() {
return (end == 0x85);
}
union {
struct {
i32 offset : 26;
u8 end : 6;
};
u32 raw{};
};
};
static_assert(sizeof(BL) == sizeof(u32));
}
void NCE::ReadRegisters(user_pt_regs &registers, pid_t pid) const {
iovec iov = {&registers, sizeof(registers)};
long status = ptrace(PTRACE_GETREGSET, pid ? pid : currPid, NT_PRSTATUS, &iov);
@ -203,15 +34,14 @@ namespace skyline {
void NCE::Execute() {
int status = 0;
while (!Halt && !state.os->processMap.empty()) {
while (!Halt && state.os->process) {
std::lock_guard jniGd(jniMtx);
for (const auto &process : state.os->processMap) {
state.os->thisProcess = process.second;
state.os->thisThread = process.second->threadMap.at(process.first);
currPid = process.first;
for (const auto &thread : state.os->process->threadMap) {
state.os->thisThread = thread.second;
currPid = thread.first;
auto &currRegs = registerMap[currPid];
if (state.thisThread->status == kernel::type::KThread::Status::Running) {
if (waitpid(state.thisThread->pid, &status, WNOHANG) == state.thisThread->pid) {
if (state.thread->status == kernel::type::KThread::Status::Running) {
if (waitpid(state.thread->pid, &status, WNOHANG) == state.thread->pid) {
if (WIFSTOPPED(status) && (WSTOPSIG(status) == SIGTRAP || WSTOPSIG(status) == SIGSTOP)) { // NOLINT(hicpp-signed-bitwise)
ReadRegisters(currRegs);
auto instr = ReadBrk(currRegs.pc);
@ -219,11 +49,11 @@ namespace skyline {
// We store the instruction value as the immediate value in BRK. 0x0 to 0x7F are SVC, 0x80 to 0x9E is MRS for TPIDRRO_EL0.
if (instr.value <= constant::SvcLast) {
state.os->SvcHandler(static_cast<u16>(instr.value));
if (state.thisThread->status != kernel::type::KThread::Status::Running)
if (state.thread->status != kernel::type::KThread::Status::Running)
continue;
} else if (instr.value > constant::SvcLast && instr.value <= constant::SvcLast + constant::NumRegs) {
// Catch MRS that reads the value of TPIDRRO_EL0 (TLS)
SetRegister(static_cast<Xreg>(instr.value - (constant::SvcLast + 1)), state.thisThread->tls);
SetRegister(static_cast<Xreg>(instr.value - (constant::SvcLast + 1)), state.thread->tls);
} else if (instr.value == constant::BrkRdy)
continue;
else {
@ -244,17 +74,18 @@ namespace skyline {
state.os->KillThread(currPid);
}
}
} else if ((state.thisThread->status == kernel::type::KThread::Status::WaitSync || state.thisThread->status == kernel::type::KThread::Status::Sleeping || state.thisThread->status == kernel::type::KThread::Status::WaitCondVar) && state.thisThread->timeout != 0) { // timeout == 0 means sleep forever
if (state.thisThread->timeout <= GetCurrTimeNs()) {
state.logger->Info("An event has timed out: {}", state.thisThread->status);
if (state.thisThread->status == kernel::type::KThread::Status::WaitSync || state.thisThread->status == kernel::type::KThread::Status::WaitCondVar)
} else if ((state.thread->status == kernel::type::KThread::Status::WaitSync || state.thread->status == kernel::type::KThread::Status::Sleeping || state.thread->status == kernel::type::KThread::Status::WaitCondVar) && state.thread->timeout != 0) { // timeout == 0 means sleep forever
if (state.thread->timeout <= GetCurrTimeNs()) {
if(state.thread->status != kernel::type::KThread::Status::Sleeping)
state.logger->Info("An event has timed out: {}", state.thread->status);
if (state.thread->status == kernel::type::KThread::Status::WaitSync || state.thread->status == kernel::type::KThread::Status::WaitCondVar)
SetRegister(Wreg::W0, constant::status::Timeout);
state.thisThread->status = kernel::type::KThread::Status::Runnable;
state.thread->status = kernel::type::KThread::Status::Runnable;
}
}
if (state.thisThread->status == kernel::type::KThread::Status::Runnable) {
state.thisThread->ClearWaitObjects();
state.thisThread->status = kernel::type::KThread::Status::Running;
if (state.thread->status == kernel::type::KThread::Status::Runnable) {
state.thread->ClearWaitObjects();
state.thread->status = kernel::type::KThread::Status::Running;
currRegs.pc += sizeof(u32);
WriteRegisters(currRegs);
ResumeProcess();
@ -263,9 +94,6 @@ namespace skyline {
state.os->serviceManager.Loop();
state.gpu->Loop();
}
for (const auto &process : state.os->processMap) {
state.os->KillThread(process.first);
}
}
void BrkLr() {

View File

@ -12,6 +12,7 @@ namespace skyline {
namespace instr {
struct Brk;
}
/**
* @brief The NCE (Native Code Execution) class is responsible for managing the state of catching instructions and directly controlling processes/threads
*/

View File

@ -3,7 +3,7 @@
#include "loader/nro.h"
namespace skyline::kernel {
OS::OS(std::shared_ptr<JvmManager>& jvmManager, std::shared_ptr<Logger> &logger, std::shared_ptr<Settings> &settings) : state(this, thisProcess, thisThread, jvmManager, settings, logger), serviceManager(state) {}
OS::OS(std::shared_ptr<JvmManager>& jvmManager, std::shared_ptr<Logger> &logger, std::shared_ptr<Settings> &settings) : state(this, process, thisThread, jvmManager, settings, logger), serviceManager(state) {}
void OS::Execute(const int romFd, const TitleFormat romType) {
auto process = CreateProcess(constant::BaseAddr, constant::DefStackSize);
@ -12,7 +12,7 @@ namespace skyline::kernel {
loader.LoadProcessData(process, state);
} else
throw exception("Unsupported ROM extension.");
process->threadMap.at(process->mainThread)->Start(); // The kernel itself is responsible for starting the main thread
process->threadMap.at(process->pid)->Start(); // The kernel itself is responsible for starting the main thread
state.nce->Execute();
}
@ -36,27 +36,22 @@ namespace skyline::kernel {
pid_t pid = clone(&ExecuteChild, stack + stackSize, CLONE_FILES | CLONE_FS | SIGCHLD, nullptr); // NOLINT(hicpp-signed-bitwise)
if (pid == -1)
throw exception("Call to clone() has failed: {}", strerror(errno));
std::shared_ptr<type::KProcess> process = std::make_shared<kernel::type::KProcess>(state, pid, address, reinterpret_cast<u64>(stack), stackSize);
processMap[pid] = process;
processVec.push_back(pid);
process = std::make_shared<kernel::type::KProcess>(state, pid, address, reinterpret_cast<u64>(stack), stackSize);
state.logger->Debug("Successfully created process with PID: {}", pid);
return process;
}
void OS::KillThread(pid_t pid) {
auto process = processMap.at(pid);
if (process->mainThread == pid) {
if (process->pid == pid) {
state.logger->Debug("Killing process with PID: {}", pid);
for (auto&[key, value]: process->threadMap) {
value->Kill();
processMap.erase(key);
}
processVec.erase(std::remove(processVec.begin(), processVec.end(), pid), processVec.end());
process.reset();
} else {
state.logger->Debug("Killing thread with TID: {}", pid);
process->threadMap.at(pid)->Kill();
process->threadMap.erase(pid);
processMap.erase(pid);
}
}

View File

@ -19,9 +19,7 @@ namespace skyline::kernel {
DeviceState state; //!< The state of the device
public:
std::unordered_map<pid_t, std::shared_ptr<type::KProcess>> processMap; //!< A mapping from a threat's PID to it's KProcess object
std::vector<pid_t> processVec; //!< A vector of all processes by their main thread's PID
std::shared_ptr<type::KProcess> thisProcess; //!< The corresponding KProcess object of the process that's called an SVC
std::shared_ptr<type::KProcess> process; //!< The KProcess object for the emulator, representing the guest process
std::shared_ptr<type::KThread> thisThread; //!< The corresponding KThread object of the thread that's called an SVC
service::ServiceManager serviceManager; //!< This manages all of the service functions

View File

@ -20,7 +20,7 @@ namespace skyline::service::am {
}
void ICommonStateGetter::GetEventHandle(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
auto handle = state.thisProcess->InsertItem(messageEvent);
auto handle = state.process->InsertItem(messageEvent);
state.logger->Debug("Event Handle: 0x{:X}", handle);
response.copyHandles.push_back(handle);
}
@ -86,7 +86,7 @@ namespace skyline::service::am {
}) {}
void IWindowController::GetAppletResourceUserId(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
response.Push(static_cast<u64>(state.thisProcess->mainThread));
response.Push(static_cast<u64>(state.process->pid));
}
void IWindowController::AcquireForegroundRights(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {}

View File

@ -8,7 +8,7 @@ namespace skyline::service::hid {
void IAppletResource::GetSharedMemoryHandle(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
hidSharedMemory = std::make_shared<kernel::type::KSharedMemory>(state, NULL, constant::hidSharedMemSize, memory::Permission(true, false, false), memory::Type::SharedMemory);
auto handle = state.thisProcess->InsertItem<type::KSharedMemory>(hidSharedMemory);
auto handle = state.process->InsertItem<type::KSharedMemory>(hidSharedMemory);
state.logger->Debug("HID Shared Memory Handle: {}", handle);
response.copyHandles.push_back(handle);
}
@ -40,7 +40,7 @@ namespace skyline::service::hid {
size_t numId = buffer.size / sizeof(NpadId);
u64 address = buffer.address;
for (size_t i = 0; i < numId; i++) {
auto id = state.thisProcess->ReadMemory<NpadId>(address);
auto id = state.process->ReadMemory<NpadId>(address);
deviceMap[id] = JoyConDevice(id);
address += sizeof(NpadId);
}

View File

@ -14,7 +14,7 @@ namespace skyline::service::nvdrv {
void nvdrv::Open(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
auto buffer = request.inputBuf.at(0);
std::string path(buffer.size, '\0');
state.thisProcess->ReadMemory(path.data(), buffer.address, buffer.size);
state.process->ReadMemory(path.data(), buffer.address, buffer.size);
response.Push<u32>(state.gpu->OpenDevice(path));
response.Push<u32>(constant::status::Success);
}
@ -39,7 +39,7 @@ namespace skyline::service::nvdrv {
auto fd = request.Pop<u32>();
auto eventId = request.Pop<u32>();
auto event = std::make_shared<type::KEvent>(state);
auto handle = state.thisProcess->InsertItem<type::KEvent>(event);
auto handle = state.process->InsertItem<type::KEvent>(event);
state.logger->Debug("QueryEvent: FD: {}, Event ID: {}, Handle: {}", fd, eventId, handle);
response.copyHandles.push_back(handle);
}

View File

@ -64,7 +64,7 @@ namespace skyline::service::nvnflinger {
}
void dispdrv::GetNativeHandle(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
handle_t handle = state.thisProcess->InsertItem(state.gpu->bufferEvent);
handle_t handle = state.process->InsertItem(state.gpu->bufferEvent);
state.logger->Debug("BufferEvent Handle: 0x{:X}", handle);
response.copyHandles.push_back(handle);
response.Push<u32>(constant::status::Success);

View File

@ -120,7 +120,7 @@ namespace skyline::service {
}
handle_t ServiceManager::NewSession(const Service serviceType) {
return state.thisProcess->NewHandle<type::KSession>(GetService(serviceType)).handle;
return state.process->NewHandle<type::KSession>(GetService(serviceType)).handle;
}
std::shared_ptr<BaseService> ServiceManager::NewService(const std::string &serviceName, type::KSession &session, ipc::IpcResponse &response) {
@ -131,7 +131,7 @@ namespace skyline::service {
response.domainObjects.push_back(session.handleIndex);
handle = session.handleIndex;
} else {
handle = state.thisProcess->NewHandle<type::KSession>(serviceObject).handle;
handle = state.process->NewHandle<type::KSession>(serviceObject).handle;
response.moveHandles.push_back(handle);
}
state.logger->Debug("Service has been created: \"{}\" (0x{:X})", serviceName, handle);
@ -145,14 +145,14 @@ namespace skyline::service {
response.domainObjects.push_back(session.handleIndex);
handle = session.handleIndex++;
} else {
handle = state.thisProcess->NewHandle<type::KSession>(serviceObject).handle;
handle = state.process->NewHandle<type::KSession>(serviceObject).handle;
response.moveHandles.push_back(handle);
}
state.logger->Debug("Service has been registered: \"{}\" (0x{:X})", serviceObject->getName(), handle);
}
void ServiceManager::CloseSession(const handle_t handle) {
auto session = state.thisProcess->GetHandle<type::KSession>(handle);
auto session = state.process->GetHandle<type::KSession>(handle);
if (session->serviceStatus == type::KSession::ServiceStatus::Open) {
if (session->isDomain) {
for (const auto &[objectId, service] : session->domainTable)
@ -170,7 +170,7 @@ namespace skyline::service {
}
void ServiceManager::SyncRequestHandler(const handle_t handle) {
auto session = state.thisProcess->GetHandle<type::KSession>(handle);
auto session = state.process->GetHandle<type::KSession>(handle);
state.logger->Debug("----Start----");
state.logger->Debug("Handle is 0x{:X}", handle);
@ -211,7 +211,7 @@ namespace skyline::service {
break;
case ipc::ControlCommand::CloneCurrentObject:
case ipc::ControlCommand::CloneCurrentObjectEx:
response.Push(state.thisProcess->InsertItem(session));
response.Push(state.process->InsertItem(session));
break;
case ipc::ControlCommand::QueryPointerBufferSize:
response.Push<u32>(0x1000);

View File

@ -6,6 +6,6 @@ namespace skyline::service::set {
void sys::GetFirmwareVersion(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
SysVerTitle title{.minor=9, .major=0, .micro=0, .revMajor=4, .platform="NX", .verHash="4de65c071fd0869695b7629f75eb97b2551dbf2f", .dispVer="9.0.0", .dispTitle="NintendoSDK Firmware for NX 9.0.0-4.0"};
state.thisProcess->WriteMemory(title, request.outputBuf.at(0).address);
state.process->WriteMemory(title, request.outputBuf.at(0).address);
}
}

View File

@ -105,7 +105,7 @@ namespace skyline::service::vi {
}
void IApplicationDisplayService::GetDisplayVsyncEvent(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
handle_t handle = state.thisProcess->InsertItem(state.gpu->vsyncEvent);
handle_t handle = state.process->InsertItem(state.gpu->vsyncEvent);
state.logger->Debug("VSync Event Handle: 0x{:X}", handle);
response.copyHandles.push_back(handle);
}