Fix CR issues and Game Duplication + Move to Vector for Memory Map

This commit fixed the issues outlined in the CR (Mainly correlated to formatting), moves to a sorted vector from a sorted list for the memory map in addition to using binary search for sorting through rather than iteratively and fixes item duplication in the game list when directory is changed in Settings.
This commit is contained in:
◱ PixelyIon 2020-02-15 15:08:17 +05:30 committed by ◱ PixelyIon
parent 66d20a9429
commit 08bbc66b09
31 changed files with 418 additions and 355 deletions

View File

@ -20,6 +20,7 @@
<option name="CLASS_CONSTRUCTOR_INIT_LIST_WRAP" value="0" />
<option name="SUPERCLASS_LIST_WRAP" value="0" />
<option name="ALIGN_INIT_LIST_IN_COLUMNS" value="false" />
<option name="ADD_BRIEF_TAG" value="true" />
<option name="HEADER_GUARD_STYLE_PATTERN" value="${PROJECT_NAME}_${PROJECT_REL_PATH}_${FILE_NAME}_${EXT}" />
<option name="MACROS_NAMING_CONVENTION">
<value prefix="" style="PASCAL_CASE" suffix="" />

View File

@ -2,14 +2,11 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="emu.skyline">
<uses-permission android:name="android.permission.READ_INTERNAL_STORAGE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-feature
android:glEsVersion="0x00030001"
android:required="true" />
<application
android:allowBackup="true"
android:extractNativeLibs="true"
@ -49,18 +46,15 @@
<activity
android:name="emu.skyline.GameActivity"
android:configChanges="orientation|screenSize"
android:screenOrientation="landscape"
android:launchMode="singleInstance">
android:launchMode="singleInstance"
android:screenOrientation="landscape">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="emu.skyline.MainActivity" />
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.BROWSABLE" />
<category android:name="android.intent.category.DEFAULT" />
<data
android:mimeType="application/nro"
android:pathPattern=".*\\.nro"
@ -70,7 +64,6 @@
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<data
android:mimeType="text/plain"
android:pathPattern=".*\\.nro"
@ -88,5 +81,4 @@
</intent-filter>
</activity>
</application>
</manifest>

View File

@ -30,16 +30,18 @@ namespace skyline {
num++;
return;
}
} else
} else {
flag.compare_exchange_weak(none, group);
}
} else if (flag == group && (next == Group::None || utils::GetTimeNs() >= end)) {
std::lock_guard lock(mtx);
if (flag == group) {
num++;
return;
}
} else
} else {
next.compare_exchange_weak(none, group);
}
none = Group::None;
asm volatile("yield");
}

View File

@ -122,8 +122,7 @@ namespace skyline {
template<typename TypeVal, typename TypeMul>
inline TypeVal AlignUp(TypeVal value, TypeMul multiple) {
static_assert(std::is_integral<TypeVal>() && std::is_integral<TypeMul>());
multiple--;
return (value + multiple) & ~multiple;
return (value + multiple) & ~(multiple - 1);
}
/**
@ -137,8 +136,7 @@ namespace skyline {
template<typename TypeVal, typename TypeMul>
inline TypeVal AlignDown(TypeVal value, TypeMul multiple) {
static_assert(std::is_integral<TypeVal>() && std::is_integral<TypeMul>());
multiple--;
return value & ~multiple;
return value & ~(multiple - 1);
}
/**
@ -212,9 +210,9 @@ namespace skyline {
void unlock();
private:
std::atomic<Group> flag = Group::None; //!< An atomic flag to hold which group holds the mutex
std::atomic<Group> next = Group::None; //!< An atomic flag to hold which group will hold the mutex next
std::atomic<u8> num = 0; //!< An atomic u8 keeping track of how many users are holding the mutex
std::atomic<Group> flag{Group::None}; //!< An atomic flag to hold which group holds the mutex
std::atomic<Group> next{Group::None}; //!< An atomic flag to hold which group will hold the mutex next
std::atomic<u8> num{0}; //!< An atomic u8 keeping track of how many users are holding the mutex
Mutex mtx; //!< A mutex to lock before changing of num and flag
};

View File

@ -44,7 +44,7 @@ namespace skyline::gpu {
resolution = buffer->resolution;
format = buffer->gbpBuffer.format;
}
u8 *inBuffer = buffer->dataBuffer.data();
u8 *inBuffer = buffer->GetAddress();
madvise(inBuffer, buffer->gbpBuffer.size, MADV_SEQUENTIAL);
ANativeWindow_Buffer windowBuffer;
ARect rect;

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.process->ReadMemory<NvChannelPriority>(buffer.input[0].address);
auto priority = state.process->GetObject<NvChannelPriority>(buffer.input[0].address);
switch (priority) {
case NvChannelPriority::Low:
timeslice = 1300;

View File

@ -73,7 +73,7 @@ namespace skyline::gpu::device {
u64 gpuCharacteristicsBufSize; // InOut
u64 gpuCharacteristicsBufAddr; // In
GpuCharacteristics gpuCharacteristics; // Out
} data = state.process->ReadMemory<Data>(buffer.input[0].address);
} data = state.process->GetObject<Data>(buffer.input[0].address);
data.gpuCharacteristics = {
.arch = 0x120,
.impl = 0xB,
@ -119,7 +119,7 @@ namespace skyline::gpu::device {
u32 maskBufSize; // In
u32 reserved[3]; // In
u64 maskBuf; // Out
} data = state.process->ReadMemory<Data>(buffer.input[0].address);
} data = state.process->GetObject<Data>(buffer.input[0].address);
if (data.maskBufSize)
data.maskBuf = 0x3;
state.process->WriteMemory(data, buffer.output[0].address);

View File

@ -17,7 +17,7 @@ namespace skyline::gpu::device {
struct Data {
u32 size; // In
u32 handle; // Out
} data = state.process->ReadMemory<Data>(buffer.input[0].address);
} data = state.process->GetObject<Data>(buffer.input[0].address);
handleTable[handleIndex] = std::make_shared<NvMapObject>(idIndex++, data.size);
data.handle = handleIndex++;
state.process->WriteMemory(data, buffer.output[0].address);
@ -28,7 +28,7 @@ namespace skyline::gpu::device {
struct Data {
u32 id; // In
u32 handle; // Out
} data = state.process->ReadMemory<Data>(buffer.input[0].address);
} data = state.process->GetObject<Data>(buffer.input[0].address);
bool found{};
for (const auto &object : handleTable) {
if (object.second->id == data.id) {
@ -53,7 +53,7 @@ namespace skyline::gpu::device {
u8 kind; // In
u8 _pad0_[7];
u64 address; // InOut
} data = state.process->ReadMemory<Data>(buffer.input[0].address);
} data = state.process->GetObject<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.process->ReadMemory<Data>(buffer.input[0].address);
} data = state.process->GetObject<Data>(buffer.input[0].address);
const auto &object = handleTable.at(data.handle);
if (object.use_count() > 1) {
data.address = static_cast<u32>(object->address);
@ -91,7 +91,7 @@ namespace skyline::gpu::device {
u32 handle; // In
Parameter parameter; // In
u32 result; // Out
} data = state.process->ReadMemory<Data>(buffer.input[0].address);
} data = state.process->GetObject<Data>(buffer.input[0].address);
auto &object = handleTable.at(data.handle);
switch (data.parameter) {
case Parameter::Size:
@ -132,7 +132,7 @@ namespace skyline::gpu::device {
struct Data {
u32 id; // Out
u32 handle; // In
} data = state.process->ReadMemory<Data>(buffer.input[0].address);
} data = state.process->GetObject<Data>(buffer.input[0].address);
data.id = handleTable.at(data.handle)->id;
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

@ -3,7 +3,7 @@
#include <gpu.h>
namespace skyline::gpu {
Buffer::Buffer(const DeviceState &state, u32 slot, GbpBuffer &gbpBuffer) : state(state), slot(slot), gbpBuffer(gbpBuffer), resolution{gbpBuffer.width, gbpBuffer.height}, dataBuffer(gbpBuffer.size) {
Buffer::Buffer(const DeviceState &state, u32 slot, GbpBuffer &gbpBuffer) : state(state), slot(slot), gbpBuffer(gbpBuffer), resolution{gbpBuffer.width, gbpBuffer.height} {
if (gbpBuffer.nvmapHandle)
nvBuffer = state.gpu->GetDevice<device::NvMap>(device::NvDeviceType::nvmap)->handleTable.at(gbpBuffer.nvmapHandle);
else {
@ -30,8 +30,8 @@ namespace skyline::gpu {
}
}
void Buffer::UpdateBuffer() {
state.process->ReadMemory(dataBuffer.data(), nvBuffer->address + gbpBuffer.offset, gbpBuffer.size);
u8 *Buffer::GetAddress() {
return state.process->GetPointer<u8>(nvBuffer->address + gbpBuffer.offset);
}
BufferQueue::BufferQueue(const DeviceState &state) : state(state) {}
@ -89,7 +89,6 @@ namespace skyline::gpu {
} *data = reinterpret_cast<Data *>(in.data.data() + constant::TokenLength);
auto buffer = queue.at(data->slot);
buffer->status = BufferStatus::Queued;
buffer->UpdateBuffer();
displayQueue.emplace(buffer);
state.gpu->bufferEvent->Signal();
struct {

View File

@ -104,7 +104,6 @@ namespace skyline::gpu {
Resolution resolution; //!< The resolution of this buffer
GbpBuffer gbpBuffer; //!< The information about the underlying buffer
BufferStatus status{BufferStatus::Free}; //!< The status of this buffer
std::vector<u8> dataBuffer; //!< The vector holding the actual pixel data
std::shared_ptr<device::NvMap::NvMapObject> nvBuffer{}; //!< A shared pointer to the buffer's nvmap object
/**
@ -115,9 +114,9 @@ namespace skyline::gpu {
Buffer(const DeviceState &state, u32 slot, GbpBuffer &gbpBuffer);
/**
* @brief This reads the buffer from the process into the dataBuffer vector
* @return The address of the buffer on the kernel
*/
void UpdateBuffer();
u8* GetAddress();
};
/**

View File

@ -12,88 +12,88 @@ namespace skyline::kernel::ipc {
OutputBuffer::OutputBuffer(kernel::ipc::BufferDescriptorC *cBuf) : IpcBuffer(cBuf->address, cBuf->size, IpcBufferType::C) {}
IpcRequest::IpcRequest(bool isDomain, const DeviceState &state) : isDomain(isDomain), state(state), tls() {
u8 *currPtr = tls.data();
state.process->ReadMemory(currPtr, state.thread->tls, constant::TlsIpcSize);
IpcRequest::IpcRequest(bool isDomain, const DeviceState &state) : isDomain(isDomain), state(state) {
u8 *tls = state.process->GetPointer<u8>(state.thread->tls);
u8 *pointer = tls;
header = reinterpret_cast<CommandHeader *>(currPtr);
currPtr += sizeof(CommandHeader);
header = reinterpret_cast<CommandHeader *>(pointer);
pointer += sizeof(CommandHeader);
if (header->handleDesc) {
handleDesc = reinterpret_cast<HandleDescriptor *>(currPtr);
currPtr += sizeof(HandleDescriptor) + (handleDesc->sendPid ? sizeof(u64) : 0);
handleDesc = reinterpret_cast<HandleDescriptor *>(pointer);
pointer += sizeof(HandleDescriptor) + (handleDesc->sendPid ? sizeof(u64) : 0);
for (uint index = 0; handleDesc->copyCount > index; index++) {
copyHandles.push_back(*reinterpret_cast<handle_t *>(currPtr));
currPtr += sizeof(handle_t);
copyHandles.push_back(*reinterpret_cast<handle_t *>(pointer));
pointer += sizeof(handle_t);
}
for (uint index = 0; handleDesc->moveCount > index; index++) {
moveHandles.push_back(*reinterpret_cast<handle_t *>(currPtr));
currPtr += sizeof(handle_t);
moveHandles.push_back(*reinterpret_cast<handle_t *>(pointer));
pointer += sizeof(handle_t);
}
}
for (uint index = 0; header->xNo > index; index++) {
auto bufX = reinterpret_cast<BufferDescriptorX *>(currPtr);
auto bufX = reinterpret_cast<BufferDescriptorX *>(pointer);
if (bufX->Address()) {
inputBuf.emplace_back(bufX);
state.logger->Debug("Buf X #{} AD: 0x{:X} SZ: 0x{:X} CTR: {}", index, u64(bufX->Address()), u16(bufX->size), u16(bufX->Counter()));
}
currPtr += sizeof(BufferDescriptorX);
pointer += sizeof(BufferDescriptorX);
}
for (uint index = 0; header->aNo > index; index++) {
auto bufA = reinterpret_cast<BufferDescriptorABW *>(currPtr);
auto bufA = reinterpret_cast<BufferDescriptorABW *>(pointer);
if (bufA->Address()) {
inputBuf.emplace_back(bufA);
state.logger->Debug("Buf A #{} AD: 0x{:X} SZ: 0x{:X}", index, u64(bufA->Address()), u64(bufA->Size()));
}
currPtr += sizeof(BufferDescriptorABW);
pointer += sizeof(BufferDescriptorABW);
}
for (uint index = 0; header->bNo > index; index++) {
auto bufB = reinterpret_cast<BufferDescriptorABW *>(currPtr);
auto bufB = reinterpret_cast<BufferDescriptorABW *>(pointer);
if (bufB->Address()) {
outputBuf.emplace_back(bufB);
state.logger->Debug("Buf B #{} AD: 0x{:X} SZ: 0x{:X}", index, u64(bufB->Address()), u64(bufB->Size()));
}
currPtr += sizeof(BufferDescriptorABW);
pointer += sizeof(BufferDescriptorABW);
}
for (uint index = 0; header->wNo > index; index++) {
auto bufW = reinterpret_cast<BufferDescriptorABW *>(currPtr);
auto bufW = reinterpret_cast<BufferDescriptorABW *>(pointer);
if (bufW->Address()) {
inputBuf.emplace_back(bufW, IpcBufferType::W);
outputBuf.emplace_back(bufW, IpcBufferType::W);
state.logger->Debug("Buf W #{} AD: 0x{:X} SZ: 0x{:X}", index, u64(bufW->Address()), u16(bufW->Size()));
}
currPtr += sizeof(BufferDescriptorABW);
pointer += sizeof(BufferDescriptorABW);
}
u64 padding = ((((reinterpret_cast<u64>(currPtr) - reinterpret_cast<u64>(tls.data())) - 1U) & ~(constant::IpcPaddingSum - 1U)) + constant::IpcPaddingSum + (reinterpret_cast<u64>(tls.data()) - reinterpret_cast<u64>(currPtr))); // Calculate the amount of padding at the front
currPtr += padding;
u64 padding = ((((reinterpret_cast<u64>(pointer) - reinterpret_cast<u64>(tls)) - 1U) & ~(constant::IpcPaddingSum - 1U)) + constant::IpcPaddingSum + (reinterpret_cast<u64>(tls) - reinterpret_cast<u64>(pointer))); // Calculate the amount of padding at the front
pointer += padding;
if (isDomain && (header->type == CommandType::Request)) {
domain = reinterpret_cast<DomainHeaderRequest *>(currPtr);
currPtr += sizeof(DomainHeaderRequest);
domain = reinterpret_cast<DomainHeaderRequest *>(pointer);
pointer += sizeof(DomainHeaderRequest);
payload = reinterpret_cast<PayloadHeader *>(currPtr);
currPtr += sizeof(PayloadHeader);
payload = reinterpret_cast<PayloadHeader *>(pointer);
pointer += sizeof(PayloadHeader);
cmdArg = currPtr;
cmdArg = pointer;
cmdArgSz = domain->payloadSz - sizeof(PayloadHeader);
currPtr += domain->payloadSz;
pointer += domain->payloadSz;
for (uint index = 0; domain->inputCount > index; index++) {
domainObjects.push_back(*reinterpret_cast<handle_t *>(currPtr));
currPtr += sizeof(handle_t);
domainObjects.push_back(*reinterpret_cast<handle_t *>(pointer));
pointer += sizeof(handle_t);
}
} else {
payload = reinterpret_cast<PayloadHeader *>(currPtr);
currPtr += sizeof(PayloadHeader);
payload = reinterpret_cast<PayloadHeader *>(pointer);
pointer += sizeof(PayloadHeader);
cmdArg = currPtr;
cmdArg = pointer;
cmdArgSz = (header->rawSize * sizeof(u32)) - (constant::IpcPaddingSum + sizeof(PayloadHeader));
currPtr += cmdArgSz;
pointer += cmdArgSz;
}
payloadOffset = cmdArg;
@ -101,22 +101,22 @@ namespace skyline::kernel::ipc {
if (payload->magic != constant::SfciMagic && header->type != CommandType::Control)
state.logger->Debug("Unexpected Magic in PayloadHeader: 0x{:X}", u32(payload->magic));
currPtr += constant::IpcPaddingSum - padding;
pointer += constant::IpcPaddingSum - padding;
if (header->cFlag == BufferCFlag::SingleDescriptor) {
auto bufC = reinterpret_cast<BufferDescriptorC *>(currPtr);
auto bufC = reinterpret_cast<BufferDescriptorC *>(pointer);
if (bufC->address) {
outputBuf.emplace_back(bufC);
state.logger->Debug("Buf C: AD: 0x{:X} SZ: 0x{:X}", u64(bufC->address), u16(bufC->size));
}
} else if (header->cFlag > BufferCFlag::SingleDescriptor) {
for (uint index = 0; (static_cast<u8>(header->cFlag) - 2) > index; index++) { // (cFlag - 2) C descriptors are present
auto bufC = reinterpret_cast<BufferDescriptorC *>(currPtr);
auto bufC = reinterpret_cast<BufferDescriptorC *>(pointer);
if (bufC->address) {
outputBuf.emplace_back(bufC);
state.logger->Debug("Buf C #{} AD: 0x{:X} SZ: 0x{:X}", index, u64(bufC->address), u16(bufC->size));
}
currPtr += sizeof(BufferDescriptorC);
pointer += sizeof(BufferDescriptorC);
}
}
@ -133,63 +133,57 @@ namespace skyline::kernel::ipc {
IpcResponse::IpcResponse(bool isDomain, const DeviceState &state) : isDomain(isDomain), state(state) {}
void IpcResponse::WriteResponse() {
std::array<u8, constant::TlsIpcSize> tls{};
u8 *currPtr = tls.data();
auto header = reinterpret_cast<CommandHeader *>(currPtr);
auto tls = state.process->GetPointer<u8>(state.thread->tls);
u8 *pointer = tls;
memset(tls, 0, constant::TlsIpcSize);
auto header = reinterpret_cast<CommandHeader *>(pointer);
header->rawSize = static_cast<u32>((sizeof(PayloadHeader) + argVec.size() + (domainObjects.size() * sizeof(handle_t)) + constant::IpcPaddingSum + (isDomain ? sizeof(DomainHeaderRequest) : 0)) / sizeof(u32)); // Size is in 32-bit units because Nintendo
header->handleDesc = (!copyHandles.empty() || !moveHandles.empty());
currPtr += sizeof(CommandHeader);
pointer += sizeof(CommandHeader);
if (header->handleDesc) {
auto handleDesc = reinterpret_cast<HandleDescriptor *>(currPtr);
auto handleDesc = reinterpret_cast<HandleDescriptor *>(pointer);
handleDesc->copyCount = static_cast<u8>(copyHandles.size());
handleDesc->moveCount = static_cast<u8>(moveHandles.size());
currPtr += sizeof(HandleDescriptor);
pointer += sizeof(HandleDescriptor);
for (unsigned int copyHandle : copyHandles) {
*reinterpret_cast<handle_t *>(currPtr) = copyHandle;
currPtr += sizeof(handle_t);
*reinterpret_cast<handle_t *>(pointer) = copyHandle;
pointer += sizeof(handle_t);
}
for (unsigned int moveHandle : moveHandles) {
*reinterpret_cast<handle_t *>(currPtr) = moveHandle;
currPtr += sizeof(handle_t);
*reinterpret_cast<handle_t *>(pointer) = moveHandle;
pointer += sizeof(handle_t);
}
}
u64 padding = ((((reinterpret_cast<u64>(currPtr) - reinterpret_cast<u64>(tls.data())) - 1U) & ~(constant::IpcPaddingSum - 1U)) + constant::IpcPaddingSum + (reinterpret_cast<u64>(tls.data()) - reinterpret_cast<u64>(currPtr))); // Calculate the amount of padding at the front
currPtr += padding;
u64 padding = ((((reinterpret_cast<u64>(pointer) - reinterpret_cast<u64>(tls)) - 1U) & ~(constant::IpcPaddingSum - 1U)) + constant::IpcPaddingSum + (reinterpret_cast<u64>(tls) - reinterpret_cast<u64>(pointer))); // Calculate the amount of padding at the front
pointer += padding;
if (isDomain) {
auto domain = reinterpret_cast<DomainHeaderResponse *>(currPtr);
auto domain = reinterpret_cast<DomainHeaderResponse *>(pointer);
domain->outputCount = static_cast<u32>(domainObjects.size());
currPtr += sizeof(DomainHeaderResponse);
pointer += sizeof(DomainHeaderResponse);
}
auto payload = reinterpret_cast<PayloadHeader *>(currPtr);
auto payload = reinterpret_cast<PayloadHeader *>(pointer);
payload->magic = constant::SfcoMagic;
payload->version = 1;
payload->value = errorCode;
currPtr += sizeof(PayloadHeader);
pointer += sizeof(PayloadHeader);
if (!argVec.empty())
memcpy(currPtr, argVec.data(), argVec.size());
currPtr += argVec.size();
memcpy(pointer, argVec.data(), argVec.size());
pointer += argVec.size();
if (isDomain) {
for (auto &domainObject : domainObjects) {
*reinterpret_cast<handle_t *>(currPtr) = domainObject;
currPtr += sizeof(handle_t);
*reinterpret_cast<handle_t *>(pointer) = domainObject;
pointer += sizeof(handle_t);
}
}
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.process->WriteMemory(tls.data(), state.thread->tls, constant::TlsIpcSize);
}
std::vector<u8> BufferDescriptorABW::Read(const DeviceState &state) {
std::vector<u8> vec(Size());
state.process->ReadMemory(vec.data(), Address(), Size());
return std::move(vec);
}
}

View File

@ -98,12 +98,12 @@ namespace skyline::kernel::ipc {
* @brief This is a buffer descriptor for X buffers: https://switchbrew.org/wiki/IPC_Marshalling#Buffer_descriptor_X_.22Pointer.22
*/
struct BufferDescriptorX {
u16 counter0_5 : 6;
u16 address36_38 : 3;
u16 counter9_11 : 3;
u16 address32_35 : 4;
u16 size : 16;
u32 address0_31 : 32;
u16 counter0_5 : 6; //!< The first 5 bits of the counter
u16 address36_38 : 3; //!< Bit 36-38 of the address
u16 counter9_11 : 3; //!< Bit 9-11 of the counter
u16 address32_35 : 4; //!< Bit 32-35 of the address
u16 size : 16; //!< The 16 bit size of the buffer
u32 address0_31 : 32; //!< The first 32-bits of the address
BufferDescriptorX(u64 address, u16 counter, u16 size) : size(size) {
address0_31 = static_cast<u32>(address & 0x7FFFFFFF80000000);
@ -113,10 +113,16 @@ namespace skyline::kernel::ipc {
counter9_11 = static_cast<u16>(address & 0x38);
}
/**
* @return The address of the buffer
*/
inline u64 Address() const {
return static_cast<u64>(address0_31) | static_cast<u64>(address32_35) << 32 | static_cast<u64>(address36_38) << 36;
}
/**
* @return The buffer counter
*/
inline u16 Counter() const {
return static_cast<u16>(counter0_5) | static_cast<u16>(counter9_11) << 9;
}
@ -127,13 +133,13 @@ namespace skyline::kernel::ipc {
* @brief This is a buffer descriptor for A/B/W buffers: https://switchbrew.org/wiki/IPC_Marshalling#Buffer_descriptor_A.2FB.2FW_.22Send.22.2F.22Receive.22.2F.22Exchange.22
*/
struct BufferDescriptorABW {
u32 size0_31 : 32;
u32 address0_31 : 32;
u8 flags : 2;
u8 address36_38 : 3;
u32 size0_31 : 32; //!< The first 32 bits of the size
u32 address0_31 : 32; //!< The first 32 bits of the address
u8 flags : 2; //!< The buffer flags
u8 address36_38 : 3; //!< Bit 36-38 of the address
u32 : 19;
u8 size32_35 : 4;
u8 address32_35 : 4;
u8 size32_35 : 4; //!< Bit 32-35 of the size
u8 address32_35 : 4; //!< Bit 32-35 of the address
BufferDescriptorABW(u64 address, u64 size) {
address0_31 = static_cast<u32>(address & 0x7FFFFFFF80000000);
@ -143,12 +149,16 @@ namespace skyline::kernel::ipc {
size32_35 = static_cast<u8>(size & 0x78000000);
}
std::vector<u8> Read(const DeviceState &state);
/**
* @return The address of the buffer
*/
inline u64 Address() const {
return static_cast<u64>(address0_31) | static_cast<u64>(address32_35) << 32 | static_cast<u64>(address36_38) << 36;
}
/**
* @return The size of the buffer
*/
inline u64 Size() const {
return static_cast<u64>(size0_31) | static_cast<u64>(size32_35) << 32;
}
@ -159,8 +169,8 @@ namespace skyline::kernel::ipc {
* @brief This is a buffer descriptor for C buffers: https://switchbrew.org/wiki/IPC_Marshalling#Buffer_descriptor_C_.22ReceiveList.22
*/
struct BufferDescriptorC {
u64 address : 48;
u32 size : 16;
u64 address : 48; //!< The 48-bit address of the buffer
u32 size : 16; //!< The 16-bit size of the buffer
BufferDescriptorC(u64 address, u16 size) : address(address), size(size) {}
};
@ -232,7 +242,7 @@ namespace skyline::kernel::ipc {
u8 *payloadOffset; //!< This is the offset of the data read from the payload
public:
std::array<u8, constant::TlsIpcSize> tls; //!< A static-sized array where TLS data is actually copied to
//std::array<u8, constant::TlsIpcSize> tls; //!< A static-sized array where TLS data is actually copied to
CommandHeader *header{}; //!< The header of the request
HandleDescriptor *handleDesc{}; //!< The handle descriptor in case CommandHeader::handle_desc is true in the header
bool isDomain{}; //!< If this is a domain request

View File

@ -3,87 +3,111 @@
namespace skyline::kernel {
ChunkDescriptor *MemoryManager::GetChunk(u64 address) {
for (auto &chunk : chunkList)
if (chunk.address <= address && (chunk.address + chunk.size) > address)
return &chunk;
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) {
auto chunk = GetChunk(address);
if (chunk)
for (auto &block : chunk->blockList)
if (block.address <= address && (block.address + block.size) > address)
return &block;
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;
}
void MemoryManager::InsertChunk(const ChunkDescriptor &chunk) {
auto it = chunkList.begin();
if (chunkList.empty() || it->address > chunk.address)
chunkList.push_front(chunk);
else {
auto prevIt = it;
while (true) {
if (it == chunkList.end() || (prevIt->address < chunk.address && it->address > chunk.address)) {
if (prevIt->address + prevIt->size > chunk.address)
throw exception("InsertChunk: Descriptors are colliding: 0x{:X} and 0x{:X}", prevIt->address, chunk.address);
chunkList.insert_after(prevIt, chunk);
break;
}
prevIt = it++;
}
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);
}
void MemoryManager::DeleteChunk(u64 address) {
chunkList.remove_if([address](const ChunkDescriptor &chunk) {
return chunk.address <= address && (chunk.address + chunk.size) > address;
});
for (auto chunk = chunkList.begin(), end = chunkList.end(); chunk != end;) {
if (chunk->address <= address && (chunk->address + chunk->size) > address)
chunk = chunkList.erase(chunk);
else
++chunk;
}
}
void MemoryManager::ResizeChunk(ChunkDescriptor *chunk, size_t size) {
if (std::next(chunk->blockList.begin()) == chunk->blockList.end())
if (chunk->blockList.size() == 1) {
chunk->blockList.begin()->size = size;
else if (size > chunk->size) {
auto end = chunk->blockList.begin();
for (; std::next(end) != chunk->blockList.end(); end++);
auto baseBlock = (*chunk->blockList.begin());
} 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 = baseBlock.permission,
.attributes = baseBlock.attributes,
.permission = begin->permission,
.attributes = begin->attributes,
};
chunk->blockList.insert_after(end, block);
} else if (chunk->size < size) {
chunk->blockList.push_back(block);
} else if (size < chunk->size) {
auto endAddress = chunk->address + size;
chunk->blockList.remove_if([endAddress](const BlockDescriptor &block) {
return block.address > endAddress;
});
auto end = chunk->blockList.begin();
for (; std::next(end) != chunk->blockList.end(); end++);
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;
}
void MemoryManager::InsertBlock(ChunkDescriptor *chunk, BlockDescriptor block) {
void MemoryManager::InsertBlock(ChunkDescriptor *chunk, const BlockDescriptor block) {
for (auto iter = chunk->blockList.begin(); iter != chunk->blockList.end(); iter++) {
if (iter->address <= block.address && (iter->address + iter->size) > block.address) {
if (iter->address == block.address && iter->size == block.size) {
iter->attributes = block.attributes;
iter->permission = block.permission;
if (iter->address <= block.address) {
if ((iter->address + iter->size) > block.address) {
if (iter->address == block.address && iter->size == block.size) {
iter->attributes = block.attributes;
iter->permission = block.permission;
} else {
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");
}
} else {
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_after(iter, {block, endBlock});
throw exception("InsertBlock: Inserting block with end past chunk end is not allowed");
}
break;
return;
}
}
throw exception("InsertBlock: Block offset not present within current block list");
}
void MemoryManager::InitializeRegions(u64 address, u64 size, const memory::AddressSpaceType type) {
@ -132,9 +156,7 @@ namespace skyline::kernel {
std::optional<DescriptorPack> MemoryManager::Get(u64 address) {
auto chunk = GetChunk(address);
if (chunk)
for (auto &block : chunk->blockList)
if (block.address <= address && (block.address + block.size) > address)
return DescriptorPack{block, *chunk};
return DescriptorPack{*GetBlock(address, chunk), *chunk};
return std::nullopt;
}

View File

@ -13,22 +13,14 @@ namespace skyline {
/**
* @brief This constructor initializes all permissions to false
*/
Permission() {
r = 0;
w = 0;
x = 0;
};
Permission() : r(), w(), x() {};
/**
* @param read If memory has read permission
* @param write If memory has write permission
* @param execute If memory has execute permission
*/
Permission(bool read, bool write, bool execute) {
r = read;
w = write;
x = execute;
};
Permission(bool read, bool write, bool execute) : r(read), w(write), x(execute) {};
/**
* @brief Equality operator between two Permission objects
@ -199,7 +191,8 @@ namespace skyline {
* @brief Checks if the specified address is within the region
* @param address The address to check
* @return If the address is inside the region
*/inline bool IsInside(u64 address) {
*/
inline bool IsInside(u64 address) {
return (this->address <= address) && ((this->address + this->size) > address);
}
};
@ -249,7 +242,7 @@ namespace skyline {
u64 size; //!< The size of the current chunk in bytes
u64 host; //!< The address of the chunk in the host
memory::MemoryState state; //!< The MemoryState for the current block
std::forward_list<BlockDescriptor> blockList; //!< This linked list holds the block descriptors for all the children blocks of this Chunk
std::vector<BlockDescriptor> blockList; //!< This vector holds the block descriptors for all the children blocks of this Chunk
};
/**
@ -266,7 +259,7 @@ namespace skyline {
class MemoryManager {
private:
const DeviceState &state; //!< The state of the device
std::forward_list<ChunkDescriptor> chunkList; //!< This linked list holds all the chunk descriptors
std::vector<ChunkDescriptor> chunkList; //!< This vector holds all the chunk descriptors
memory::Region base{memory::Regions::Base}; //!< The Region object for the entire address space
memory::Region code{memory::Regions::Code}; //!< The Region object for the code memory region
memory::Region alias{memory::Regions::Alias}; //!< The Region object for the alias memory region
@ -284,7 +277,7 @@ namespace skyline {
* @param address The address to find a block at
* @return A pointer to the BlockDescriptor or nullptr in case chunk was not found
*/
BlockDescriptor *GetBlock(u64 address);
BlockDescriptor *GetBlock(u64 address, ChunkDescriptor* chunk = nullptr);
/**
* @brief Inserts a chunk into the memory map
@ -310,7 +303,7 @@ namespace skyline {
* @param chunk The chunk to insert the block into
* @param block The block to insert
*/
static void InsertBlock(ChunkDescriptor *chunk, BlockDescriptor block);
static void InsertBlock(ChunkDescriptor *chunk, const BlockDescriptor block);
/**
* @brief This initializes all of the regions in the address space

View File

@ -232,9 +232,9 @@ namespace skyline::kernel::svc {
auto handle = state.ctx->registers.w0;
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;
state.logger->Debug("svcGetThreadPriority: Writing thread priority {}", priority);
} catch (const std::exception &) {
state.logger->Warn("svcGetThreadPriority: 'handle' invalid: 0x{:X}", handle);
state.ctx->registers.w0 = constant::status::InvHandle;
@ -245,9 +245,9 @@ namespace skyline::kernel::svc {
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));
state.ctx->registers.w0 = constant::status::Success;
state.logger->Debug("svcSetThreadPriority: Setting thread priority to {}", priority);
} catch (const std::exception &) {
state.logger->Warn("svcSetThreadPriority: 'handle' invalid: 0x{:X}", handle);
state.ctx->registers.w0 = constant::status::InvHandle;
@ -499,9 +499,9 @@ namespace skyline::kernel::svc {
char port[constant::PortSize + 1]{0};
state.process->ReadMemory(port, state.ctx->registers.x1, constant::PortSize);
handle_t handle{};
if (std::strcmp(port, "sm:") == 0)
if (std::strcmp(port, "sm:") == 0) {
handle = state.os->serviceManager.NewSession(service::Service::sm);
else {
} else {
state.logger->Warn("svcConnectToNamedPort: Connecting to invalid port: '{}'", port);
state.ctx->registers.w0 = constant::status::NotFound;
return;
@ -519,9 +519,9 @@ namespace skyline::kernel::svc {
void GetThreadId(DeviceState &state) {
pid_t pid{};
auto handle = state.ctx->registers.w1;
if (handle != constant::ThreadSelf) {
if (handle != constant::ThreadSelf)
pid = state.process->GetHandle<type::KThread>(handle)->pid;
} else
else
pid = state.thread->pid;
state.logger->Debug("svcGetThreadId: Handle: 0x{:X}, PID: {}", handle, pid);
state.ctx->registers.x1 = static_cast<u64>(pid);
@ -529,8 +529,7 @@ namespace skyline::kernel::svc {
}
void OutputDebugString(DeviceState &state) {
std::string debug(state.ctx->registers.x1, '\0');
state.process->ReadMemory(debug.data(), state.ctx->registers.x0, state.ctx->registers.x1);
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);

View File

@ -70,7 +70,7 @@ namespace skyline::kernel::type {
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) {
if ((block.address - chunk->address) < size) {
fregs = {
.x0 = block.address,
.x1 = std::min(block.size, (chunk->address + nSize) - block.address),
@ -80,8 +80,9 @@ namespace skyline::kernel::type {
state.nce->ExecuteFunction(ThreadCall::Syscall, fregs);
if (fregs.x0 < 0)
throw exception("An error occurred while updating private memory's permissions in child process");
} else
} else {
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);

View File

@ -35,8 +35,9 @@ namespace skyline::kernel::type {
if (tlsPages.empty()) {
auto region = state.os->memory.GetRegion(memory::Regions::TlsIo);
address = region.size ? region.address : 0;
} else
} else {
address = (*(tlsPages.end() - 1))->address + PAGE_SIZE;
}
auto tlsMem = NewHandle<KPrivateMemory>(address, PAGE_SIZE, memory::Permission(true, true, false), memory::MemoryStates::ThreadLocal).item;
tlsPages.push_back(std::make_shared<TlsPage>(tlsMem->address));
auto &tlsPage = tlsPages.back();
@ -72,7 +73,7 @@ namespace skyline::kernel::type {
fregs.x1 = stackTop;
fregs.x3 = tlsMem->Map(0, size, memory::Permission{true, true, false});
fregs.x8 = __NR_clone;
fregs.x5 = reinterpret_cast<u64>(&guest::entry);
fregs.x5 = reinterpret_cast<u64>(&guest::GuestEntry);
fregs.x6 = entryPoint;
state.nce->ExecuteFunction(ThreadCall::Clone, fregs);
if (static_cast<int>(fregs.x0) < 0)
@ -156,7 +157,7 @@ namespace skyline::kernel::type {
case type::KType::KTransferMemory: {
auto mem = std::static_pointer_cast<type::KMemory>(object);
if (mem->IsInside(address))
return std::optional<KProcess::HandleOut<KMemory>>({mem, handle});
return std::make_optional<KProcess::HandleOut<KMemory>>({mem, handle});
}
default:
break;
@ -186,11 +187,12 @@ namespace skyline::kernel::type {
while (!status->flag);
lock.lock();
status->flag = false;
for (auto it = mtxWaiters.begin(); it != mtxWaiters.end(); ++it)
for (auto it = mtxWaiters.begin(); it != mtxWaiters.end(); ++it) {
if ((*it)->handle == state.thread->handle) {
mtxWaiters.erase(it);
break;
}
}
return true;
}
@ -231,20 +233,20 @@ namespace skyline::kernel::type {
lock.unlock();
bool timedOut{};
auto start = utils::GetTimeNs();
while (!status->flag) {
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)
for (auto it = condWaiters.begin(); it != condWaiters.end(); ++it) {
if ((*it)->handle == state.thread->handle) {
condWaiters.erase(it);
break;
}
}
lock.unlock();
return !timedOut;
}

View File

@ -137,41 +137,6 @@ namespace skyline::kernel::type {
*/
std::shared_ptr<KThread> CreateThread(u64 entryPoint, u64 entryArg, u64 stackTop, u8 priority);
/**
* @brief Returns an object from process memory
* @tparam Type The type of the object to be read
* @param address The address of the object
* @return An object of type T with read data
*/
template<typename Type>
inline Type ReadMemory(u64 address) const {
Type item{};
ReadMemory(&item, address, sizeof(Type));
return item;
}
/**
* @brief Writes an object to process memory
* @tparam Type The type of the object to be written
* @param item The object to write
* @param address The address of the object
*/
template<typename Type>
inline void WriteMemory(Type &item, u64 address) const {
WriteMemory(&item, address, sizeof(Type));
}
/**
* @brief Writes an object to process memory
* @tparam Type The type of the object to be written
* @param item The object to write
* @param address The address of the object
*/
template<typename Type>
inline void WriteMemory(const Type &item, u64 address) const {
WriteMemory(&item, address, sizeof(Type));
}
/**
* @brief This returns the host address for a specific address in guest memory
* @param address The corresponding guest address
@ -191,7 +156,87 @@ namespace skyline::kernel::type {
}
/**
* @brief Read data from the process's memory
* @brief Returns a reference to an object from guest memory
* @tparam Type The type of the object to be read
* @param address The address of the object
* @return A reference to object with type T
*/
template<typename Type>
inline Type &GetReference(u64 address) const {
auto source = GetPointer<Type>(address);
if (source)
return *source;
else
throw exception("Cannot retrieve reference to object not in shared guest memory");
}
/**
* @brief Returns a copy of an object from guest memory
* @tparam Type The type of the object to be read
* @param address The address of the object
* @return A copy of the object from guest memory
*/
template<typename Type>
inline Type GetObject(u64 address) const {
auto source = GetPointer<Type>(address);
if (source) {
return *source;
} else {
Type item{};
ReadMemory(&item, address, sizeof(Type));
return item;
}
}
/**
* @brief Returns a string from guest memory
* @param address The address of the object
* @param maxSize The maximum size of the string
* @return A copy of a string in guest memory
*/
inline std::string GetString(u64 address, const size_t maxSize) const {
auto source = GetPointer<char>(address);
if (source)
return std::string(source, maxSize);
std::string debug(maxSize, '\0');
ReadMemory(debug.data(), address, maxSize);
return debug;
}
/**
* @brief Writes an object to guest memory
* @tparam Type The type of the object to be written
* @param item The object to write
* @param address The address of the object
*/
template<typename Type>
inline void WriteMemory(Type &item, u64 address) const {
auto destination = GetPointer<Type>(address);
if (destination) {
*destination = item;
} else {
WriteMemory(&item, address, sizeof(Type));
}
}
/**
* @brief Writes an object to guest memory
* @tparam Type The type of the object to be written
* @param item The object to write
* @param address The address of the object
*/
template<typename Type>
inline void WriteMemory(const Type &item, u64 address) const {
auto destination = GetPointer<Type>(address);
if (destination) {
*destination = item;
} else {
WriteMemory(&item, address, sizeof(Type));
}
}
/**
* @brief Read data from the guest's memory
* @param destination The address to the location where the process memory is written
* @param offset The address to read from in process memory
* @param size The amount of memory to be read
@ -200,7 +245,7 @@ namespace skyline::kernel::type {
void ReadMemory(void *destination, const u64 offset, const size_t size, const bool forceGuest = false) const;
/**
* @brief Write to the process's memory
* @brief Write to the guest's memory
* @param source The address of where the data to be written is present
* @param offset The address to write to in process memory
* @param size The amount of memory to be written
@ -209,7 +254,7 @@ namespace skyline::kernel::type {
void WriteMemory(void *source, const u64 offset, const size_t size, const bool forceGuest = false) const;
/**
* @brief Copy one chunk to another in the process's memory
* @brief Copy one chunk to another in the guest's memory
* @param source The address of where the data to read is present
* @param destination The address to write the read data to
* @param size The amount of memory to be copied

View File

@ -33,18 +33,18 @@ namespace skyline::kernel::type {
if (fregs.x0 < 0)
throw exception("An error occurred while mapping shared memory in guest");
guest = {.address = fregs.x0, .size = size, .permission = permission};
ChunkDescriptor chunk{
.address = fregs.x0,
.host = kernel.address,
.size = size,
.state = initialState,
};
BlockDescriptor block{
.address = fregs.x0,
.size = size,
.permission = permission,
};
chunk.blockList.push_front(block);
ChunkDescriptor chunk{
.address = fregs.x0,
.host = kernel.address,
.size = size,
.state = initialState,
.blockList = {block},
};
state.os->memory.InsertChunk(chunk);
return fregs.x0;
}
@ -78,7 +78,7 @@ namespace skyline::kernel::type {
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) {
if ((block.address - chunk->address) < guest.size) {
fregs = {
.x0 = block.address,
.x1 = std::min(block.size, (chunk->address + size) - block.address),
@ -88,8 +88,9 @@ namespace skyline::kernel::type {
state.nce->ExecuteFunction(ThreadCall::Syscall, fregs);
if (fregs.x0 < 0)
throw exception("An error occurred while updating private memory's permissions in child process");
} else
} else {
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);

View File

@ -5,7 +5,7 @@
namespace skyline::kernel::type {
KThread::KThread(const DeviceState &state, handle_t handle, pid_t self_pid, u64 entryPoint, u64 entryArg, u64 stackTop, u64 tls, u8 priority, KProcess *parent, std::shared_ptr<type::KSharedMemory> &tlsMemory) : handle(handle), pid(self_pid), entryPoint(entryPoint), entryArg(entryArg), stackTop(stackTop), tls(tls), priority(priority), parent(parent), ctxMemory(tlsMemory), KSyncObject(state,
KType::KThread) {
KType::KThread) {
UpdatePriority(priority);
}

View File

@ -19,7 +19,7 @@ namespace skyline::kernel::type {
Running, //!< The thread is running currently
Dead //!< The thread is dead and not running
} status = Status::Created; //!< The state of the thread
std::atomic<bool> cancelSync; //!< This is to flag to a thread to cancel a synchronization call it currently is in
std::atomic<bool> cancelSync{false}; //!< This is to flag to a thread to cancel a synchronization call it currently is in
std::shared_ptr<type::KSharedMemory> ctxMemory; //!< The KSharedMemory of the shared memory allocated by the guest process TLS
handle_t handle; // The handle of the object in the handle table
pid_t pid; //!< The PID of the current thread (As in kernel PID and not PGID [In short, Linux implements threads as processes that share a lot of stuff at the kernel level])

View File

@ -101,11 +101,11 @@ namespace skyline::kernel::type {
if (mHost && !host) {
state.os->memory.DeleteChunk(address);
hostChunk = chunk;
} else if (!mHost && host)
} else if (!mHost && host) {
state.os->memory.InsertChunk(chunk);
else if (mHost && host)
} else if (mHost && host) {
hostChunk = chunk;
else if (!mHost && !host) {
} else if (!mHost && !host) {
state.os->memory.DeleteChunk(address);
state.os->memory.InsertChunk(chunk);
}
@ -174,9 +174,9 @@ namespace skyline::kernel::type {
}
KTransferMemory::~KTransferMemory() {
if (host)
if (host) {
munmap(reinterpret_cast<void *>(address), size);
else if (state.process) {
} else if (state.process) {
try {
Registers fregs{
.x0 = address,

View File

@ -33,8 +33,9 @@ namespace skyline {
if (kernel::svc::SvcTable[svc]) {
state.logger->Debug("SVC called 0x{:X}", svc);
(*kernel::svc::SvcTable[svc])(state);
} else
} else {
throw exception("Unimplemented SVC 0x{:X}", svc);
}
} catch (const std::exception &e) {
throw exception("{} (SVC: 0x{:X})", e.what(), svc);
}
@ -57,8 +58,9 @@ namespace skyline {
state.os->KillThread(thread);
Halt = true;
jniMtx.unlock();
} else
} else {
state.os->KillThread(thread);
}
}
}
@ -160,29 +162,11 @@ namespace skyline {
state.logger->Debug("Process Trace:{}", trace);
state.logger->Debug("Raw Instructions: 0x{}", raw);
state.logger->Debug("CPU Context:{}", regStr);
} else
} else {
state.logger->Debug("CPU Context:{}", regStr);
}
}
const std::array<u32, 16> CntpctEl0 = {
0xD10083FF, // SUB SP, SP, #32
0xA90107E0, // STP X0, X1, [SP, #16]
0xD28F0860, // MOV X0, #30787
0xF2AE3680, // MOVK X0, #29108, LSL #16
0xD53BE001, // MRS X1, CNTFRQ_EL0
0xF2CB5880, // MOVK X0, #23236, LSL #32
0xD345FC21, // LSR X1, X1, #5
0xF2E14F80, // MOVK X0, #2684, LSL #48
0x9BC07C21, // UMULH X1, X1, X0
0xD347FC21, // LSR X1, X1, #7
0xD53BE040, // MRS X0, CNTVCT_EL0
0x9AC10801, // UDIV X1, X0, X1
0x8B010421, // ADD X1, X1, X1, LSL #1
0xD37AE420, // LSL X0, X1, #6
0xF90003E0, // STR X0, [SP, #0]
0xA94107E0, // LDP X0, X1, [SP, #16]
};
std::vector<u32> NCE::PatchCode(std::vector<u8> &code, u64 baseAddress, i64 offset) {
u32 *start = reinterpret_cast<u32 *>(code.data());
u32 *end = start + (code.size() / sizeof(u32));
@ -190,15 +174,13 @@ namespace skyline {
std::vector<u32> patch((guest::saveCtxSize + guest::loadCtxSize + guest::svcHandlerSize) / sizeof(u32));
std::memcpy(patch.data(), reinterpret_cast<void *>(&guest::saveCtx), guest::saveCtxSize);
std::memcpy(patch.data(), reinterpret_cast<void *>(&guest::SaveCtx), guest::saveCtxSize);
offset += guest::saveCtxSize;
std::memcpy(reinterpret_cast<u8 *>(patch.data()) + guest::saveCtxSize,
reinterpret_cast<void *>(&guest::loadCtx), guest::loadCtxSize);
std::memcpy(reinterpret_cast<u8 *>(patch.data()) + guest::saveCtxSize, reinterpret_cast<void *>(&guest::LoadCtx), guest::loadCtxSize);
offset += guest::loadCtxSize;
std::memcpy(reinterpret_cast<u8 *>(patch.data()) + guest::saveCtxSize + guest::loadCtxSize,
reinterpret_cast<void *>(&guest::svcHandler), guest::svcHandlerSize);
std::memcpy(reinterpret_cast<u8 *>(patch.data()) + guest::saveCtxSize + guest::loadCtxSize, reinterpret_cast<void *>(&guest::SvcHandler), guest::svcHandlerSize);
offset += guest::svcHandlerSize;
static u64 frequency{};
@ -276,7 +258,7 @@ namespace skyline {
} else if (frequency != constant::TegraX1Freq) {
if (instrMrs->srcReg == constant::CntpctEl0) {
instr::B bjunc(offset);
offset += CntpctEl0.size() * sizeof(u32);
offset += guest::rescaleClockSize;
instr::Ldr ldr(0xF94003E0); // LDR XOUT, [SP]
ldr.destReg = instrMrs->destReg;
offset += sizeof(ldr);
@ -286,8 +268,9 @@ namespace skyline {
offset += sizeof(bret);
*address = bjunc.raw;
for (const auto &instr : CntpctEl0)
patch.push_back(instr);
auto size = patch.size();
patch.resize(size + (guest::rescaleClockSize / sizeof(u32)));
std::memcpy(patch.data() + size, reinterpret_cast<void *>(&guest::RescaleClock), guest::rescaleClockSize);
patch.push_back(ldr.raw);
patch.push_back(addSp);
patch.push_back(bret.raw);
@ -316,4 +299,3 @@ namespace skyline {
return patch;
}
}

View File

@ -1,6 +1,6 @@
.text
.global saveCtx
saveCtx:
.global SaveCtx
SaveCtx:
STR LR, [SP, #-16]!
MRS LR, TPIDR_EL0
STP X0, X1, [LR, #16]
@ -19,11 +19,11 @@ saveCtx:
STP X26, X27, [LR, #224]
STP X28, X29, [LR, #240]
LDR LR, [SP], #16
DSB SY
DSB ST
RET
.global loadCtx
loadCtx:
.global LoadCtx
LoadCtx:
STR LR, [SP, #-16]!
MRS LR, TPIDR_EL0
LDP X0, X1, [LR, #16]
@ -43,3 +43,23 @@ loadCtx:
LDP X28, X29, [LR, #240]
LDR LR, [SP], #16
RET
.global RescaleClock
RescaleClock:
SUB SP, SP, #32
STP X0, X1, [SP, #16]
MOV X0, #30787
MOVK X0, #29108, LSL #16
MOVK X0, #23236, LSL #32
MOVK X0, #2684, LSL #48
MRS X1, CNTFRQ_EL0
LSR X1, X1, #5
UMULH X1, X1, X0
LSR X1, X1, #7
MRS X0, CNTVCT_EL0
UDIV X1, X0, X1
ADD X1, X1, X1, LSL #1
LSL X0, X1, #6
STR X0, [SP, #0]
LDP X0, X1, [SP, #16]

View File

@ -7,7 +7,7 @@
#define FORCE_INLINE __attribute__((always_inline)) inline // NOLINT(cppcoreguidelines-macro-usage)
namespace skyline::guest {
FORCE_INLINE void saveCtxStack() {
FORCE_INLINE void SaveCtxStack() {
asm("SUB SP, SP, #240\n\t"
"STP X0, X1, [SP, #0]\n\t"
"STP X2, X3, [SP, #16]\n\t"
@ -27,7 +27,7 @@ namespace skyline::guest {
);
}
FORCE_INLINE void loadCtxStack() {
FORCE_INLINE void LoadCtxStack() {
asm("LDP X0, X1, [SP, #0]\n\t"
"LDP X2, X3, [SP, #16]\n\t"
"LDP X4, X5, [SP, #32]\n\t"
@ -47,7 +47,7 @@ namespace skyline::guest {
);
}
FORCE_INLINE void saveCtxTls() {
FORCE_INLINE void SaveCtxTls() {
asm("STR LR, [SP, #-16]!\n\t"
"MRS LR, TPIDR_EL0\n\t"
"STP X0, X1, [LR, #16]\n\t"
@ -65,11 +65,12 @@ namespace skyline::guest {
"STP X24, X25, [LR, #208]\n\t"
"STP X26, X27, [LR, #224]\n\t"
"STP X28, X29, [LR, #240]\n\t"
"LDR LR, [SP], #16"
"LDR LR, [SP], #16\n\t"
"DSB ST"
);
}
FORCE_INLINE void loadCtxTls() {
FORCE_INLINE void LoadCtxTls() {
asm("STR LR, [SP, #-16]!\n\t"
"MRS LR, TPIDR_EL0\n\t"
"LDP X0, X1, [LR, #16]\n\t"
@ -91,7 +92,10 @@ namespace skyline::guest {
);
}
void svcHandler(u64 pc, u32 svc) {
/**
* @note Do not use any functions that cannot be inlined from this, as this function is placed at an arbitrary address in the guest. In addition, do not use any static variables or globals as the .bss section is not copied into the guest.
*/
void SvcHandler(u64 pc, u32 svc) {
volatile ThreadContext *ctx;
asm("MRS %0, TPIDR_EL0":"=r"(ctx));
ctx->pc = pc;
@ -112,7 +116,7 @@ namespace skyline::guest {
"MOV LR, SP\n\t"
"SVC #0\n\t"
"MOV SP, LR\n\t"
"LDR LR, [SP], #16" ::: "x0", "x1", "x2", "x3", "x4", "x5", "x8");
"LDR LR, [SP], #16":: : "x0", "x1", "x2", "x3", "x4", "x5", "x8");
break;
}
default: {
@ -131,7 +135,7 @@ namespace skyline::guest {
"MOV LR, SP\n\t"
"SVC #0\n\t"
"MOV SP, LR\n\t"
"LDR LR, [SP], #16" :: "r"(&spec) : "x0", "x1", "x2", "x3", "x4", "x5", "x8");
"LDR LR, [SP], #16"::"r"(&spec) : "x0", "x1", "x2", "x3", "x4", "x5", "x8");
}
}
return;
@ -153,35 +157,35 @@ namespace skyline::guest {
"LDR Q2, [SP], #16\n\t"
"LDR Q1, [SP], #16\n\t"
"LDR Q0, [SP], #16\n\t"
"LDP X1, X2, [SP], #16" :: "r"(ctx->registers.x0));
"LDP X1, X2, [SP], #16"::"r"(ctx->registers.x0));
return;
}
while (true) {
ctx->state = ThreadState::WaitKernel;
while (ctx->state == ThreadState::WaitKernel);
if (ctx->state == ThreadState::WaitRun)
if (ctx->state == ThreadState::WaitRun) {
break;
else if (ctx->state == ThreadState::WaitFunc) {
} else if (ctx->state == ThreadState::WaitFunc) {
if (ctx->commandId == static_cast<u32>(ThreadCall::Syscall)) {
saveCtxStack();
loadCtxTls();
SaveCtxStack();
LoadCtxTls();
asm("STR LR, [SP, #-16]!\n\t"
"MOV LR, SP\n\t"
"SVC #0\n\t"
"MOV SP, LR\n\t"
"LDR LR, [SP], #16");
saveCtxTls();
loadCtxStack();
SaveCtxTls();
LoadCtxStack();
} else if (ctx->commandId == static_cast<u32>(ThreadCall::Memcopy)) {
auto src = reinterpret_cast<u8*>(ctx->registers.x0);
auto dest = reinterpret_cast<u8*>(ctx->registers.x1);
auto src = reinterpret_cast<u8 *>(ctx->registers.x0);
auto dest = reinterpret_cast<u8 *>(ctx->registers.x1);
auto size = ctx->registers.x2;
auto end = src + size;
while (src < end)
*(src++) = *(dest++);
} else if (ctx->commandId == static_cast<u32>(ThreadCall::Clone)) {
saveCtxStack();
loadCtxTls();
SaveCtxStack();
LoadCtxTls();
asm("STR LR, [SP, #-16]!\n\t"
"MOV LR, SP\n\t"
"SVC #0\n\t"
@ -221,15 +225,15 @@ namespace skyline::guest {
".parent:\n\t"
"MOV SP, LR\n\t"
"LDR LR, [SP], #16");
saveCtxTls();
loadCtxStack();
SaveCtxTls();
LoadCtxStack();
}
}
}
ctx->state = ThreadState::Running;
}
void signalHandler(int signal, siginfo_t *info, ucontext_t *ucontext) {
void SignalHandler(int signal, siginfo_t *info, ucontext_t *ucontext) {
volatile ThreadContext *ctx;
asm("MRS %0, TPIDR_EL0":"=r"(ctx));
for (u8 index = 0; index < 30; index++)
@ -245,29 +249,29 @@ namespace skyline::guest {
}
}
void entry(u64 address) {
void GuestEntry(u64 address) {
volatile ThreadContext *ctx;
asm("MRS %0, TPIDR_EL0":"=r"(ctx));
while (true) {
ctx->state = ThreadState::WaitInit;
while (ctx->state == ThreadState::WaitInit);
if (ctx->state == ThreadState::WaitRun)
if (ctx->state == ThreadState::WaitRun) {
break;
else if (ctx->state == ThreadState::WaitFunc) {
} else if (ctx->state == ThreadState::WaitFunc) {
if (ctx->commandId == static_cast<u32>(ThreadCall::Syscall)) {
saveCtxStack();
loadCtxTls();
SaveCtxStack();
LoadCtxTls();
asm("STR LR, [SP, #-16]!\n\t"
"MOV LR, SP\n\t"
"SVC #0\n\t"
"MOV SP, LR\n\t"
"LDR LR, [SP], #16");
saveCtxTls();
loadCtxStack();
SaveCtxTls();
LoadCtxStack();
}
} else if (ctx->commandId == static_cast<u32>(ThreadCall::Memcopy)) {
auto src = reinterpret_cast<u8*>(ctx->registers.x0);
auto dest = reinterpret_cast<u8*>(ctx->registers.x1);
auto src = reinterpret_cast<u8 *>(ctx->registers.x0);
auto dest = reinterpret_cast<u8 *>(ctx->registers.x1);
auto size = ctx->registers.x2;
auto end = src + size;
while (src < end)
@ -275,7 +279,7 @@ namespace skyline::guest {
}
}
struct sigaction sigact{
.sa_sigaction = reinterpret_cast<void (*)(int, struct siginfo *, void *)>(reinterpret_cast<void *>(signalHandler)),
.sa_sigaction = reinterpret_cast<void (*)(int, struct siginfo *, void *)>(reinterpret_cast<void *>(SignalHandler)),
.sa_flags = SA_SIGINFO,
};
for (int signal : {SIGILL, SIGTRAP, SIGBUS, SIGFPE, SIGSEGV})
@ -312,7 +316,7 @@ namespace skyline::guest {
"MOV X27, XZR\n\t"
"MOV X28, XZR\n\t"
"MOV X29, XZR\n\t"
"RET" :: "r"(address), "r"(ctx->registers.x0), "r"(ctx->registers.x1) : "x0", "x1", "lr");
"RET"::"r"(address), "r"(ctx->registers.x0), "r"(ctx->registers.x1) : "x0", "x1", "lr");
__builtin_unreachable();
}
}

View File

@ -4,17 +4,19 @@ namespace skyline {
namespace guest {
constexpr size_t saveCtxSize = 20 * sizeof(u32);
constexpr size_t loadCtxSize = 20 * sizeof(u32);
constexpr size_t rescaleClockSize = 16 * sizeof(u32);
#ifdef NDEBUG
constexpr size_t svcHandlerSize = 225 * sizeof(u32);
#else
constexpr size_t svcHandlerSize = 400 * sizeof(u32);
#endif
void entry(u64 address);
void GuestEntry(u64 address);
extern "C" void saveCtx(void);
extern "C" void loadCtx(void);
extern "C" void SaveCtx(void);
extern "C" void LoadCtx(void);
extern "C" __noreturn void RescaleClock(void);
void svcHandler(u64 pc, u32 svc);
void SvcHandler(u64 pc, u32 svc);
}
}

View File

@ -121,12 +121,12 @@ namespace skyline {
* @brief This enumeration is used to convey the state of a thread to the kernel
*/
enum class ThreadState : u32 {
NotReady = 0, //!< The thread hasn't yet entered the entry handler
Running = 1, //!< The thread is currently executing code
NotReady = 0, //!< The thread hasn't yet entered the entry handler
Running = 1, //!< The thread is currently executing code
WaitKernel = 2, //!< The thread is currently waiting on the kernel
WaitRun = 3, //!< The thread should be ready to run
WaitInit = 4, //!< The thread is waiting to be initialized
WaitFunc = 5, //!< The kernel is waiting for the thread to run a function
WaitRun = 3, //!< The thread should be ready to run
WaitInit = 4, //!< The thread is waiting to be initialized
WaitFunc = 5, //!< The kernel is waiting for the thread to run a function
GuestCrash = 6, //!< This is a notification to the kernel that the guest has crashed
};

View File

@ -28,7 +28,7 @@ namespace skyline::kernel {
}
auto tlsMem = std::make_shared<type::KSharedMemory>(state, 0, (sizeof(ThreadContext) + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1), memory::Permission{true, true, false}, memory::MemoryStates::Reserved);
tlsMem->guest = tlsMem->kernel;
pid_t pid = clone(reinterpret_cast<int (*)(void *)>(&guest::entry), stack + stackSize, CLONE_FILES | CLONE_FS | CLONE_SETTLS | SIGCHLD, reinterpret_cast<void *>(entry), nullptr, reinterpret_cast<void *>(tlsMem->guest.address));
pid_t pid = clone(reinterpret_cast<int (*)(void *)>(&guest::GuestEntry), stack + 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);

View File

@ -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.process->ReadMemory<NpadId>(address);
auto id = state.process->GetObject<NpadId>(address);
deviceMap[id] = JoyConDevice(id);
address += sizeof(NpadId);
}

View File

@ -13,8 +13,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.process->ReadMemory(path.data(), buffer.address, buffer.size);
auto path = state.process->GetString(buffer.address, buffer.size);
response.Push<u32>(state.gpu->OpenDevice(path));
response.Push<u32>(constant::status::Success);
}

View File

@ -181,7 +181,7 @@ class MainActivity : AppCompatActivity(), View.OnClickListener {
override fun onOptionsItemSelected(item: MenuItem): Boolean {
return when (item.itemId) {
R.id.action_settings -> {
startActivity(Intent(this, SettingsActivity::class.java))
startActivityForResult(Intent(this, SettingsActivity::class.java), 3)
true
}
R.id.action_refresh -> {
@ -193,35 +193,33 @@ class MainActivity : AppCompatActivity(), View.OnClickListener {
}
}
override fun onResume() {
super.onResume()
if (sharedPreferences.getBoolean("refresh_required", false))
refreshFiles(false)
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
override fun onActivityResult(requestCode: Int, resultCode: Int, intent: Intent?) {
super.onActivityResult(requestCode, resultCode, intent)
if (resultCode == RESULT_OK) {
when (requestCode) {
1 -> {
val uri = data!!.data!!
val uri = intent!!.data!!
contentResolver.takePersistableUriPermission(uri, Intent.FLAG_GRANT_READ_URI_PERMISSION)
sharedPreferences.edit().putString("search_location", uri.toString()).apply()
refreshFiles(!sharedPreferences.getBoolean("refresh_required", false))
}
2 -> {
try {
val uri = (data!!.data!!)
val intent = Intent(this, GameActivity::class.java)
intent.data = uri
val uri = (intent!!.data!!)
val intentGame = Intent(this, GameActivity::class.java)
intentGame.data = uri
if (resultCode != 0)
startActivityForResult(intent, resultCode)
startActivityForResult(intentGame, resultCode)
else
startActivity(intent)
startActivity(intentGame)
} catch (e: Exception) {
notifyUser(e.message!!)
}
}
3 -> {
if (sharedPreferences.getBoolean("refresh_required", false))
refreshFiles(false)
}
}
}
}