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="CLASS_CONSTRUCTOR_INIT_LIST_WRAP" value="0" />
<option name="SUPERCLASS_LIST_WRAP" value="0" /> <option name="SUPERCLASS_LIST_WRAP" value="0" />
<option name="ALIGN_INIT_LIST_IN_COLUMNS" value="false" /> <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="HEADER_GUARD_STYLE_PATTERN" value="${PROJECT_NAME}_${PROJECT_REL_PATH}_${FILE_NAME}_${EXT}" />
<option name="MACROS_NAMING_CONVENTION"> <option name="MACROS_NAMING_CONVENTION">
<value prefix="" style="PASCAL_CASE" suffix="" /> <value prefix="" style="PASCAL_CASE" suffix="" />

View File

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

View File

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

View File

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

View File

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

View File

@ -21,7 +21,7 @@ namespace skyline::gpu::device {
void NvHostChannel::SetErrorNotifier(skyline::gpu::device::IoctlData &buffer) {} void NvHostChannel::SetErrorNotifier(skyline::gpu::device::IoctlData &buffer) {}
void NvHostChannel::SetPriority(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) { switch (priority) {
case NvChannelPriority::Low: case NvChannelPriority::Low:
timeslice = 1300; timeslice = 1300;

View File

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

View File

@ -17,7 +17,7 @@ namespace skyline::gpu::device {
struct Data { struct Data {
u32 size; // In u32 size; // In
u32 handle; // Out 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); handleTable[handleIndex] = std::make_shared<NvMapObject>(idIndex++, data.size);
data.handle = handleIndex++; data.handle = handleIndex++;
state.process->WriteMemory(data, buffer.output[0].address); state.process->WriteMemory(data, buffer.output[0].address);
@ -28,7 +28,7 @@ namespace skyline::gpu::device {
struct Data { struct Data {
u32 id; // In u32 id; // In
u32 handle; // Out u32 handle; // Out
} data = state.process->ReadMemory<Data>(buffer.input[0].address); } data = state.process->GetObject<Data>(buffer.input[0].address);
bool found{}; bool found{};
for (const auto &object : handleTable) { for (const auto &object : handleTable) {
if (object.second->id == data.id) { if (object.second->id == data.id) {
@ -53,7 +53,7 @@ namespace skyline::gpu::device {
u8 kind; // In u8 kind; // In
u8 _pad0_[7]; u8 _pad0_[7];
u64 address; // InOut 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); auto &object = handleTable.at(data.handle);
object->heapMask = data.heapMask; object->heapMask = data.heapMask;
object->flags = data.flags; object->flags = data.flags;
@ -71,7 +71,7 @@ namespace skyline::gpu::device {
u32 address; // Out u32 address; // Out
u32 size; // Out u32 size; // Out
u64 flags; // 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); const auto &object = handleTable.at(data.handle);
if (object.use_count() > 1) { if (object.use_count() > 1) {
data.address = static_cast<u32>(object->address); data.address = static_cast<u32>(object->address);
@ -91,7 +91,7 @@ namespace skyline::gpu::device {
u32 handle; // In u32 handle; // In
Parameter parameter; // In Parameter parameter; // In
u32 result; // Out 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); auto &object = handleTable.at(data.handle);
switch (data.parameter) { switch (data.parameter) {
case Parameter::Size: case Parameter::Size:
@ -132,7 +132,7 @@ namespace skyline::gpu::device {
struct Data { struct Data {
u32 id; // Out u32 id; // Out
u32 handle; // In 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; data.id = handleTable.at(data.handle)->id;
state.process->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); 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> #include <gpu.h>
namespace skyline::gpu { 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) if (gbpBuffer.nvmapHandle)
nvBuffer = state.gpu->GetDevice<device::NvMap>(device::NvDeviceType::nvmap)->handleTable.at(gbpBuffer.nvmapHandle); nvBuffer = state.gpu->GetDevice<device::NvMap>(device::NvDeviceType::nvmap)->handleTable.at(gbpBuffer.nvmapHandle);
else { else {
@ -30,8 +30,8 @@ namespace skyline::gpu {
} }
} }
void Buffer::UpdateBuffer() { u8 *Buffer::GetAddress() {
state.process->ReadMemory(dataBuffer.data(), nvBuffer->address + gbpBuffer.offset, gbpBuffer.size); return state.process->GetPointer<u8>(nvBuffer->address + gbpBuffer.offset);
} }
BufferQueue::BufferQueue(const DeviceState &state) : state(state) {} BufferQueue::BufferQueue(const DeviceState &state) : state(state) {}
@ -89,7 +89,6 @@ namespace skyline::gpu {
} *data = reinterpret_cast<Data *>(in.data.data() + constant::TokenLength); } *data = reinterpret_cast<Data *>(in.data.data() + constant::TokenLength);
auto buffer = queue.at(data->slot); auto buffer = queue.at(data->slot);
buffer->status = BufferStatus::Queued; buffer->status = BufferStatus::Queued;
buffer->UpdateBuffer();
displayQueue.emplace(buffer); displayQueue.emplace(buffer);
state.gpu->bufferEvent->Signal(); state.gpu->bufferEvent->Signal();
struct { struct {

View File

@ -104,7 +104,6 @@ namespace skyline::gpu {
Resolution resolution; //!< The resolution of this buffer Resolution resolution; //!< The resolution of this buffer
GbpBuffer gbpBuffer; //!< The information about the underlying buffer GbpBuffer gbpBuffer; //!< The information about the underlying buffer
BufferStatus status{BufferStatus::Free}; //!< The status of this 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 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); 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) {} 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() { IpcRequest::IpcRequest(bool isDomain, const DeviceState &state) : isDomain(isDomain), state(state) {
u8 *currPtr = tls.data(); u8 *tls = state.process->GetPointer<u8>(state.thread->tls);
state.process->ReadMemory(currPtr, state.thread->tls, constant::TlsIpcSize); u8 *pointer = tls;
header = reinterpret_cast<CommandHeader *>(currPtr); header = reinterpret_cast<CommandHeader *>(pointer);
currPtr += sizeof(CommandHeader); pointer += sizeof(CommandHeader);
if (header->handleDesc) { if (header->handleDesc) {
handleDesc = reinterpret_cast<HandleDescriptor *>(currPtr); handleDesc = reinterpret_cast<HandleDescriptor *>(pointer);
currPtr += sizeof(HandleDescriptor) + (handleDesc->sendPid ? sizeof(u64) : 0); pointer += sizeof(HandleDescriptor) + (handleDesc->sendPid ? sizeof(u64) : 0);
for (uint index = 0; handleDesc->copyCount > index; index++) { for (uint index = 0; handleDesc->copyCount > index; index++) {
copyHandles.push_back(*reinterpret_cast<handle_t *>(currPtr)); copyHandles.push_back(*reinterpret_cast<handle_t *>(pointer));
currPtr += sizeof(handle_t); pointer += sizeof(handle_t);
} }
for (uint index = 0; handleDesc->moveCount > index; index++) { for (uint index = 0; handleDesc->moveCount > index; index++) {
moveHandles.push_back(*reinterpret_cast<handle_t *>(currPtr)); moveHandles.push_back(*reinterpret_cast<handle_t *>(pointer));
currPtr += sizeof(handle_t); pointer += sizeof(handle_t);
} }
} }
for (uint index = 0; header->xNo > index; index++) { for (uint index = 0; header->xNo > index; index++) {
auto bufX = reinterpret_cast<BufferDescriptorX *>(currPtr); auto bufX = reinterpret_cast<BufferDescriptorX *>(pointer);
if (bufX->Address()) { if (bufX->Address()) {
inputBuf.emplace_back(bufX); 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())); 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++) { for (uint index = 0; header->aNo > index; index++) {
auto bufA = reinterpret_cast<BufferDescriptorABW *>(currPtr); auto bufA = reinterpret_cast<BufferDescriptorABW *>(pointer);
if (bufA->Address()) { if (bufA->Address()) {
inputBuf.emplace_back(bufA); inputBuf.emplace_back(bufA);
state.logger->Debug("Buf A #{} AD: 0x{:X} SZ: 0x{:X}", index, u64(bufA->Address()), u64(bufA->Size())); 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++) { for (uint index = 0; header->bNo > index; index++) {
auto bufB = reinterpret_cast<BufferDescriptorABW *>(currPtr); auto bufB = reinterpret_cast<BufferDescriptorABW *>(pointer);
if (bufB->Address()) { if (bufB->Address()) {
outputBuf.emplace_back(bufB); outputBuf.emplace_back(bufB);
state.logger->Debug("Buf B #{} AD: 0x{:X} SZ: 0x{:X}", index, u64(bufB->Address()), u64(bufB->Size())); 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++) { for (uint index = 0; header->wNo > index; index++) {
auto bufW = reinterpret_cast<BufferDescriptorABW *>(currPtr); auto bufW = reinterpret_cast<BufferDescriptorABW *>(pointer);
if (bufW->Address()) { if (bufW->Address()) {
inputBuf.emplace_back(bufW, IpcBufferType::W); inputBuf.emplace_back(bufW, IpcBufferType::W);
outputBuf.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())); 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 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
currPtr += padding; pointer += padding;
if (isDomain && (header->type == CommandType::Request)) { if (isDomain && (header->type == CommandType::Request)) {
domain = reinterpret_cast<DomainHeaderRequest *>(currPtr); domain = reinterpret_cast<DomainHeaderRequest *>(pointer);
currPtr += sizeof(DomainHeaderRequest); pointer += sizeof(DomainHeaderRequest);
payload = reinterpret_cast<PayloadHeader *>(currPtr); payload = reinterpret_cast<PayloadHeader *>(pointer);
currPtr += sizeof(PayloadHeader); pointer += sizeof(PayloadHeader);
cmdArg = currPtr; cmdArg = pointer;
cmdArgSz = domain->payloadSz - sizeof(PayloadHeader); cmdArgSz = domain->payloadSz - sizeof(PayloadHeader);
currPtr += domain->payloadSz; pointer += domain->payloadSz;
for (uint index = 0; domain->inputCount > index; index++) { for (uint index = 0; domain->inputCount > index; index++) {
domainObjects.push_back(*reinterpret_cast<handle_t *>(currPtr)); domainObjects.push_back(*reinterpret_cast<handle_t *>(pointer));
currPtr += sizeof(handle_t); pointer += sizeof(handle_t);
} }
} else { } else {
payload = reinterpret_cast<PayloadHeader *>(currPtr); payload = reinterpret_cast<PayloadHeader *>(pointer);
currPtr += sizeof(PayloadHeader); pointer += sizeof(PayloadHeader);
cmdArg = currPtr; cmdArg = pointer;
cmdArgSz = (header->rawSize * sizeof(u32)) - (constant::IpcPaddingSum + sizeof(PayloadHeader)); cmdArgSz = (header->rawSize * sizeof(u32)) - (constant::IpcPaddingSum + sizeof(PayloadHeader));
currPtr += cmdArgSz; pointer += cmdArgSz;
} }
payloadOffset = cmdArg; payloadOffset = cmdArg;
@ -101,22 +101,22 @@ namespace skyline::kernel::ipc {
if (payload->magic != constant::SfciMagic && header->type != CommandType::Control) if (payload->magic != constant::SfciMagic && header->type != CommandType::Control)
state.logger->Debug("Unexpected Magic in PayloadHeader: 0x{:X}", u32(payload->magic)); 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) { if (header->cFlag == BufferCFlag::SingleDescriptor) {
auto bufC = reinterpret_cast<BufferDescriptorC *>(currPtr); auto bufC = reinterpret_cast<BufferDescriptorC *>(pointer);
if (bufC->address) { if (bufC->address) {
outputBuf.emplace_back(bufC); outputBuf.emplace_back(bufC);
state.logger->Debug("Buf C: AD: 0x{:X} SZ: 0x{:X}", u64(bufC->address), u16(bufC->size)); state.logger->Debug("Buf C: AD: 0x{:X} SZ: 0x{:X}", u64(bufC->address), u16(bufC->size));
} }
} else if (header->cFlag > BufferCFlag::SingleDescriptor) { } else if (header->cFlag > BufferCFlag::SingleDescriptor) {
for (uint index = 0; (static_cast<u8>(header->cFlag) - 2) > index; index++) { // (cFlag - 2) C descriptors are present 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) { if (bufC->address) {
outputBuf.emplace_back(bufC); outputBuf.emplace_back(bufC);
state.logger->Debug("Buf C #{} AD: 0x{:X} SZ: 0x{:X}", index, u64(bufC->address), u16(bufC->size)); 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) {} IpcResponse::IpcResponse(bool isDomain, const DeviceState &state) : isDomain(isDomain), state(state) {}
void IpcResponse::WriteResponse() { void IpcResponse::WriteResponse() {
std::array<u8, constant::TlsIpcSize> tls{}; auto tls = state.process->GetPointer<u8>(state.thread->tls);
u8 *currPtr = tls.data(); u8 *pointer = tls;
auto header = reinterpret_cast<CommandHeader *>(currPtr); 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->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()); header->handleDesc = (!copyHandles.empty() || !moveHandles.empty());
currPtr += sizeof(CommandHeader); pointer += sizeof(CommandHeader);
if (header->handleDesc) { if (header->handleDesc) {
auto handleDesc = reinterpret_cast<HandleDescriptor *>(currPtr); auto handleDesc = reinterpret_cast<HandleDescriptor *>(pointer);
handleDesc->copyCount = static_cast<u8>(copyHandles.size()); handleDesc->copyCount = static_cast<u8>(copyHandles.size());
handleDesc->moveCount = static_cast<u8>(moveHandles.size()); handleDesc->moveCount = static_cast<u8>(moveHandles.size());
currPtr += sizeof(HandleDescriptor); pointer += sizeof(HandleDescriptor);
for (unsigned int copyHandle : copyHandles) { for (unsigned int copyHandle : copyHandles) {
*reinterpret_cast<handle_t *>(currPtr) = copyHandle; *reinterpret_cast<handle_t *>(pointer) = copyHandle;
currPtr += sizeof(handle_t); pointer += sizeof(handle_t);
} }
for (unsigned int moveHandle : moveHandles) { for (unsigned int moveHandle : moveHandles) {
*reinterpret_cast<handle_t *>(currPtr) = moveHandle; *reinterpret_cast<handle_t *>(pointer) = moveHandle;
currPtr += sizeof(handle_t); 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 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
currPtr += padding; pointer += padding;
if (isDomain) { if (isDomain) {
auto domain = reinterpret_cast<DomainHeaderResponse *>(currPtr); auto domain = reinterpret_cast<DomainHeaderResponse *>(pointer);
domain->outputCount = static_cast<u32>(domainObjects.size()); 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->magic = constant::SfcoMagic;
payload->version = 1; payload->version = 1;
payload->value = errorCode; payload->value = errorCode;
currPtr += sizeof(PayloadHeader); pointer += sizeof(PayloadHeader);
if (!argVec.empty()) if (!argVec.empty())
memcpy(currPtr, argVec.data(), argVec.size()); memcpy(pointer, argVec.data(), argVec.size());
currPtr += argVec.size(); pointer += argVec.size();
if (isDomain) { if (isDomain) {
for (auto &domainObject : domainObjects) { for (auto &domainObject : domainObjects) {
*reinterpret_cast<handle_t *>(currPtr) = domainObject; *reinterpret_cast<handle_t *>(pointer) = domainObject;
currPtr += sizeof(handle_t); 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.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 * @brief This is a buffer descriptor for X buffers: https://switchbrew.org/wiki/IPC_Marshalling#Buffer_descriptor_X_.22Pointer.22
*/ */
struct BufferDescriptorX { struct BufferDescriptorX {
u16 counter0_5 : 6; u16 counter0_5 : 6; //!< The first 5 bits of the counter
u16 address36_38 : 3; u16 address36_38 : 3; //!< Bit 36-38 of the address
u16 counter9_11 : 3; u16 counter9_11 : 3; //!< Bit 9-11 of the counter
u16 address32_35 : 4; u16 address32_35 : 4; //!< Bit 32-35 of the address
u16 size : 16; u16 size : 16; //!< The 16 bit size of the buffer
u32 address0_31 : 32; u32 address0_31 : 32; //!< The first 32-bits of the address
BufferDescriptorX(u64 address, u16 counter, u16 size) : size(size) { BufferDescriptorX(u64 address, u16 counter, u16 size) : size(size) {
address0_31 = static_cast<u32>(address & 0x7FFFFFFF80000000); address0_31 = static_cast<u32>(address & 0x7FFFFFFF80000000);
@ -113,10 +113,16 @@ namespace skyline::kernel::ipc {
counter9_11 = static_cast<u16>(address & 0x38); counter9_11 = static_cast<u16>(address & 0x38);
} }
/**
* @return The address of the buffer
*/
inline u64 Address() const { inline u64 Address() const {
return static_cast<u64>(address0_31) | static_cast<u64>(address32_35) << 32 | static_cast<u64>(address36_38) << 36; 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 { inline u16 Counter() const {
return static_cast<u16>(counter0_5) | static_cast<u16>(counter9_11) << 9; 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 * @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 { struct BufferDescriptorABW {
u32 size0_31 : 32; u32 size0_31 : 32; //!< The first 32 bits of the size
u32 address0_31 : 32; u32 address0_31 : 32; //!< The first 32 bits of the address
u8 flags : 2; u8 flags : 2; //!< The buffer flags
u8 address36_38 : 3; u8 address36_38 : 3; //!< Bit 36-38 of the address
u32 : 19; u32 : 19;
u8 size32_35 : 4; u8 size32_35 : 4; //!< Bit 32-35 of the size
u8 address32_35 : 4; u8 address32_35 : 4; //!< Bit 32-35 of the address
BufferDescriptorABW(u64 address, u64 size) { BufferDescriptorABW(u64 address, u64 size) {
address0_31 = static_cast<u32>(address & 0x7FFFFFFF80000000); address0_31 = static_cast<u32>(address & 0x7FFFFFFF80000000);
@ -143,12 +149,16 @@ namespace skyline::kernel::ipc {
size32_35 = static_cast<u8>(size & 0x78000000); size32_35 = static_cast<u8>(size & 0x78000000);
} }
std::vector<u8> Read(const DeviceState &state); /**
* @return The address of the buffer
*/
inline u64 Address() const { inline u64 Address() const {
return static_cast<u64>(address0_31) | static_cast<u64>(address32_35) << 32 | static_cast<u64>(address36_38) << 36; 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 { inline u64 Size() const {
return static_cast<u64>(size0_31) | static_cast<u64>(size32_35) << 32; 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 * @brief This is a buffer descriptor for C buffers: https://switchbrew.org/wiki/IPC_Marshalling#Buffer_descriptor_C_.22ReceiveList.22
*/ */
struct BufferDescriptorC { struct BufferDescriptorC {
u64 address : 48; u64 address : 48; //!< The 48-bit address of the buffer
u32 size : 16; u32 size : 16; //!< The 16-bit size of the buffer
BufferDescriptorC(u64 address, u16 size) : address(address), size(size) {} 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 u8 *payloadOffset; //!< This is the offset of the data read from the payload
public: 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 CommandHeader *header{}; //!< The header of the request
HandleDescriptor *handleDesc{}; //!< The handle descriptor in case CommandHeader::handle_desc is true in the header HandleDescriptor *handleDesc{}; //!< The handle descriptor in case CommandHeader::handle_desc is true in the header
bool isDomain{}; //!< If this is a domain request bool isDomain{}; //!< If this is a domain request

View File

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

View File

@ -13,22 +13,14 @@ namespace skyline {
/** /**
* @brief This constructor initializes all permissions to false * @brief This constructor initializes all permissions to false
*/ */
Permission() { Permission() : r(), w(), x() {};
r = 0;
w = 0;
x = 0;
};
/** /**
* @param read If memory has read permission * @param read If memory has read permission
* @param write If memory has write permission * @param write If memory has write permission
* @param execute If memory has execute permission * @param execute If memory has execute permission
*/ */
Permission(bool read, bool write, bool execute) { Permission(bool read, bool write, bool execute) : r(read), w(write), x(execute) {};
r = read;
w = write;
x = execute;
};
/** /**
* @brief Equality operator between two Permission objects * @brief Equality operator between two Permission objects
@ -199,7 +191,8 @@ namespace skyline {
* @brief Checks if the specified address is within the region * @brief Checks if the specified address is within the region
* @param address The address to check * @param address The address to check
* @return If the address is inside the region * @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); 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 size; //!< The size of the current chunk in bytes
u64 host; //!< The address of the chunk in the host u64 host; //!< The address of the chunk in the host
memory::MemoryState state; //!< The MemoryState for the current block 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 { class MemoryManager {
private: private:
const DeviceState &state; //!< The state of the device 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 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 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 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 * @param address The address to find a block at
* @return A pointer to the BlockDescriptor or nullptr in case chunk was not found * @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 * @brief Inserts a chunk into the memory map
@ -310,7 +303,7 @@ namespace skyline {
* @param chunk The chunk to insert the block into * @param chunk The chunk to insert the block into
* @param block The block to insert * @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 * @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; auto handle = state.ctx->registers.w0;
try { try {
auto priority = state.process->GetHandle<type::KThread>(handle)->priority; auto priority = state.process->GetHandle<type::KThread>(handle)->priority;
state.logger->Debug("svcGetThreadPriority: Writing thread priority {}", priority);
state.ctx->registers.w1 = priority; state.ctx->registers.w1 = priority;
state.ctx->registers.w0 = constant::status::Success; state.ctx->registers.w0 = constant::status::Success;
state.logger->Debug("svcGetThreadPriority: Writing thread priority {}", priority);
} catch (const std::exception &) { } catch (const std::exception &) {
state.logger->Warn("svcGetThreadPriority: 'handle' invalid: 0x{:X}", handle); state.logger->Warn("svcGetThreadPriority: 'handle' invalid: 0x{:X}", handle);
state.ctx->registers.w0 = constant::status::InvHandle; state.ctx->registers.w0 = constant::status::InvHandle;
@ -245,9 +245,9 @@ namespace skyline::kernel::svc {
auto handle = state.ctx->registers.w0; auto handle = state.ctx->registers.w0;
auto priority = state.ctx->registers.w1; auto priority = state.ctx->registers.w1;
try { try {
state.logger->Debug("svcSetThreadPriority: Setting thread priority to {}", priority);
state.process->GetHandle<type::KThread>(handle)->UpdatePriority(static_cast<u8>(priority)); state.process->GetHandle<type::KThread>(handle)->UpdatePriority(static_cast<u8>(priority));
state.ctx->registers.w0 = constant::status::Success; state.ctx->registers.w0 = constant::status::Success;
state.logger->Debug("svcSetThreadPriority: Setting thread priority to {}", priority);
} catch (const std::exception &) { } catch (const std::exception &) {
state.logger->Warn("svcSetThreadPriority: 'handle' invalid: 0x{:X}", handle); state.logger->Warn("svcSetThreadPriority: 'handle' invalid: 0x{:X}", handle);
state.ctx->registers.w0 = constant::status::InvHandle; state.ctx->registers.w0 = constant::status::InvHandle;
@ -499,9 +499,9 @@ namespace skyline::kernel::svc {
char port[constant::PortSize + 1]{0}; char port[constant::PortSize + 1]{0};
state.process->ReadMemory(port, state.ctx->registers.x1, constant::PortSize); state.process->ReadMemory(port, state.ctx->registers.x1, constant::PortSize);
handle_t handle{}; handle_t handle{};
if (std::strcmp(port, "sm:") == 0) if (std::strcmp(port, "sm:") == 0) {
handle = state.os->serviceManager.NewSession(service::Service::sm); handle = state.os->serviceManager.NewSession(service::Service::sm);
else { } else {
state.logger->Warn("svcConnectToNamedPort: Connecting to invalid port: '{}'", port); state.logger->Warn("svcConnectToNamedPort: Connecting to invalid port: '{}'", port);
state.ctx->registers.w0 = constant::status::NotFound; state.ctx->registers.w0 = constant::status::NotFound;
return; return;
@ -519,9 +519,9 @@ namespace skyline::kernel::svc {
void GetThreadId(DeviceState &state) { void GetThreadId(DeviceState &state) {
pid_t pid{}; pid_t pid{};
auto handle = state.ctx->registers.w1; auto handle = state.ctx->registers.w1;
if (handle != constant::ThreadSelf) { if (handle != constant::ThreadSelf)
pid = state.process->GetHandle<type::KThread>(handle)->pid; pid = state.process->GetHandle<type::KThread>(handle)->pid;
} else else
pid = state.thread->pid; pid = state.thread->pid;
state.logger->Debug("svcGetThreadId: Handle: 0x{:X}, PID: {}", handle, pid); state.logger->Debug("svcGetThreadId: Handle: 0x{:X}, PID: {}", handle, pid);
state.ctx->registers.x1 = static_cast<u64>(pid); state.ctx->registers.x1 = static_cast<u64>(pid);
@ -529,8 +529,7 @@ namespace skyline::kernel::svc {
} }
void OutputDebugString(DeviceState &state) { void OutputDebugString(DeviceState &state) {
std::string debug(state.ctx->registers.x1, '\0'); auto debug = state.process->GetString(state.ctx->registers.x0, state.ctx->registers.x1);
state.process->ReadMemory(debug.data(), state.ctx->registers.x0, state.ctx->registers.x1);
if (debug.back() == '\n') if (debug.back() == '\n')
debug.pop_back(); debug.pop_back();
state.logger->Info("Debug Output: {}", debug); state.logger->Info("Debug Output: {}", debug);

View File

@ -70,7 +70,7 @@ namespace skyline::kernel::type {
auto chunk = state.os->memory.GetChunk(address); auto chunk = state.os->memory.GetChunk(address);
state.process->WriteMemory(reinterpret_cast<void *>(chunk->host), address, std::min(nSize, size), true); state.process->WriteMemory(reinterpret_cast<void *>(chunk->host), address, std::min(nSize, size), true);
for (const auto &block : chunk->blockList) { for (const auto &block : chunk->blockList) {
if((block.address - chunk->address) < size) { if ((block.address - chunk->address) < size) {
fregs = { fregs = {
.x0 = block.address, .x0 = block.address,
.x1 = std::min(block.size, (chunk->address + nSize) - 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); state.nce->ExecuteFunction(ThreadCall::Syscall, fregs);
if (fregs.x0 < 0) if (fregs.x0 < 0)
throw exception("An error occurred while updating private memory's permissions in child process"); throw exception("An error occurred while updating private memory's permissions in child process");
} else } else {
break; break;
}
} }
munmap(reinterpret_cast<void *>(chunk->host), size); 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); 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()) { if (tlsPages.empty()) {
auto region = state.os->memory.GetRegion(memory::Regions::TlsIo); auto region = state.os->memory.GetRegion(memory::Regions::TlsIo);
address = region.size ? region.address : 0; address = region.size ? region.address : 0;
} else } else {
address = (*(tlsPages.end() - 1))->address + PAGE_SIZE; address = (*(tlsPages.end() - 1))->address + PAGE_SIZE;
}
auto tlsMem = NewHandle<KPrivateMemory>(address, PAGE_SIZE, memory::Permission(true, true, false), memory::MemoryStates::ThreadLocal).item; 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)); tlsPages.push_back(std::make_shared<TlsPage>(tlsMem->address));
auto &tlsPage = tlsPages.back(); auto &tlsPage = tlsPages.back();
@ -72,7 +73,7 @@ namespace skyline::kernel::type {
fregs.x1 = stackTop; fregs.x1 = stackTop;
fregs.x3 = tlsMem->Map(0, size, memory::Permission{true, true, false}); fregs.x3 = tlsMem->Map(0, size, memory::Permission{true, true, false});
fregs.x8 = __NR_clone; fregs.x8 = __NR_clone;
fregs.x5 = reinterpret_cast<u64>(&guest::entry); fregs.x5 = reinterpret_cast<u64>(&guest::GuestEntry);
fregs.x6 = entryPoint; fregs.x6 = entryPoint;
state.nce->ExecuteFunction(ThreadCall::Clone, fregs); state.nce->ExecuteFunction(ThreadCall::Clone, fregs);
if (static_cast<int>(fregs.x0) < 0) if (static_cast<int>(fregs.x0) < 0)
@ -156,7 +157,7 @@ namespace skyline::kernel::type {
case type::KType::KTransferMemory: { case type::KType::KTransferMemory: {
auto mem = std::static_pointer_cast<type::KMemory>(object); auto mem = std::static_pointer_cast<type::KMemory>(object);
if (mem->IsInside(address)) if (mem->IsInside(address))
return std::optional<KProcess::HandleOut<KMemory>>({mem, handle}); return std::make_optional<KProcess::HandleOut<KMemory>>({mem, handle});
} }
default: default:
break; break;
@ -186,11 +187,12 @@ namespace skyline::kernel::type {
while (!status->flag); while (!status->flag);
lock.lock(); lock.lock();
status->flag = false; 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) { if ((*it)->handle == state.thread->handle) {
mtxWaiters.erase(it); mtxWaiters.erase(it);
break; break;
} }
}
return true; return true;
} }
@ -231,20 +233,20 @@ namespace skyline::kernel::type {
lock.unlock(); lock.unlock();
bool timedOut{}; bool timedOut{};
auto start = utils::GetTimeNs(); auto start = utils::GetTimeNs();
while (!status->flag) { while (!status->flag)
if ((utils::GetTimeNs() - start) >= timeout) if ((utils::GetTimeNs() - start) >= timeout)
timedOut = true; timedOut = true;
}
lock.lock(); lock.lock();
if (!status->flag) if (!status->flag)
timedOut = false; timedOut = false;
else else
status->flag = false; 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) { if ((*it)->handle == state.thread->handle) {
condWaiters.erase(it); condWaiters.erase(it);
break; break;
} }
}
lock.unlock(); lock.unlock();
return !timedOut; 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); 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 * @brief This returns the host address for a specific address in guest memory
* @param address The corresponding guest address * @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 destination The address to the location where the process memory is written
* @param offset The address to read from in process memory * @param offset The address to read from in process memory
* @param size The amount of memory to be read * @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; 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 source The address of where the data to be written is present
* @param offset The address to write to in process memory * @param offset The address to write to in process memory
* @param size The amount of memory to be written * @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; 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 source The address of where the data to read is present
* @param destination The address to write the read data to * @param destination The address to write the read data to
* @param size The amount of memory to be copied * @param size The amount of memory to be copied

View File

@ -33,18 +33,18 @@ namespace skyline::kernel::type {
if (fregs.x0 < 0) if (fregs.x0 < 0)
throw exception("An error occurred while mapping shared memory in guest"); throw exception("An error occurred while mapping shared memory in guest");
guest = {.address = fregs.x0, .size = size, .permission = permission}; guest = {.address = fregs.x0, .size = size, .permission = permission};
ChunkDescriptor chunk{
.address = fregs.x0,
.host = kernel.address,
.size = size,
.state = initialState,
};
BlockDescriptor block{ BlockDescriptor block{
.address = fregs.x0, .address = fregs.x0,
.size = size, .size = size,
.permission = permission, .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); state.os->memory.InsertChunk(chunk);
return fregs.x0; 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); state.process->WriteMemory(reinterpret_cast<void *>(kernel.address), guest.address, std::min(guest.size, size), true);
auto chunk = state.os->memory.GetChunk(guest.address); auto chunk = state.os->memory.GetChunk(guest.address);
for (const auto &block : chunk->blockList) { for (const auto &block : chunk->blockList) {
if((block.address - chunk->address) < guest.size) { if ((block.address - chunk->address) < guest.size) {
fregs = { fregs = {
.x0 = block.address, .x0 = block.address,
.x1 = std::min(block.size, (chunk->address + size) - 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); state.nce->ExecuteFunction(ThreadCall::Syscall, fregs);
if (fregs.x0 < 0) if (fregs.x0 < 0)
throw exception("An error occurred while updating private memory's permissions in child process"); throw exception("An error occurred while updating private memory's permissions in child process");
} else } else {
break; break;
}
} }
munmap(reinterpret_cast<void *>(kernel.address), kernel.size); 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); 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 { 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, 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); UpdatePriority(priority);
} }

View File

@ -19,7 +19,7 @@ namespace skyline::kernel::type {
Running, //!< The thread is running currently Running, //!< The thread is running currently
Dead //!< The thread is dead and not running Dead //!< The thread is dead and not running
} status = Status::Created; //!< The state of the thread } 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 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 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]) 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) { if (mHost && !host) {
state.os->memory.DeleteChunk(address); state.os->memory.DeleteChunk(address);
hostChunk = chunk; hostChunk = chunk;
} else if (!mHost && host) } else if (!mHost && host) {
state.os->memory.InsertChunk(chunk); state.os->memory.InsertChunk(chunk);
else if (mHost && host) } else if (mHost && host) {
hostChunk = chunk; hostChunk = chunk;
else if (!mHost && !host) { } else if (!mHost && !host) {
state.os->memory.DeleteChunk(address); state.os->memory.DeleteChunk(address);
state.os->memory.InsertChunk(chunk); state.os->memory.InsertChunk(chunk);
} }
@ -174,9 +174,9 @@ namespace skyline::kernel::type {
} }
KTransferMemory::~KTransferMemory() { KTransferMemory::~KTransferMemory() {
if (host) if (host) {
munmap(reinterpret_cast<void *>(address), size); munmap(reinterpret_cast<void *>(address), size);
else if (state.process) { } else if (state.process) {
try { try {
Registers fregs{ Registers fregs{
.x0 = address, .x0 = address,

View File

@ -33,8 +33,9 @@ namespace skyline {
if (kernel::svc::SvcTable[svc]) { if (kernel::svc::SvcTable[svc]) {
state.logger->Debug("SVC called 0x{:X}", svc); state.logger->Debug("SVC called 0x{:X}", svc);
(*kernel::svc::SvcTable[svc])(state); (*kernel::svc::SvcTable[svc])(state);
} else } else {
throw exception("Unimplemented SVC 0x{:X}", svc); throw exception("Unimplemented SVC 0x{:X}", svc);
}
} catch (const std::exception &e) { } catch (const std::exception &e) {
throw exception("{} (SVC: 0x{:X})", e.what(), svc); throw exception("{} (SVC: 0x{:X})", e.what(), svc);
} }
@ -57,8 +58,9 @@ namespace skyline {
state.os->KillThread(thread); state.os->KillThread(thread);
Halt = true; Halt = true;
jniMtx.unlock(); jniMtx.unlock();
} else } else {
state.os->KillThread(thread); state.os->KillThread(thread);
}
} }
} }
@ -160,29 +162,11 @@ namespace skyline {
state.logger->Debug("Process Trace:{}", trace); state.logger->Debug("Process Trace:{}", trace);
state.logger->Debug("Raw Instructions: 0x{}", raw); state.logger->Debug("Raw Instructions: 0x{}", raw);
state.logger->Debug("CPU Context:{}", regStr); state.logger->Debug("CPU Context:{}", regStr);
} else } else {
state.logger->Debug("CPU Context:{}", regStr); 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) { std::vector<u32> NCE::PatchCode(std::vector<u8> &code, u64 baseAddress, i64 offset) {
u32 *start = reinterpret_cast<u32 *>(code.data()); u32 *start = reinterpret_cast<u32 *>(code.data());
u32 *end = start + (code.size() / sizeof(u32)); 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::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; offset += guest::saveCtxSize;
std::memcpy(reinterpret_cast<u8 *>(patch.data()) + guest::saveCtxSize, std::memcpy(reinterpret_cast<u8 *>(patch.data()) + guest::saveCtxSize, reinterpret_cast<void *>(&guest::LoadCtx), guest::loadCtxSize);
reinterpret_cast<void *>(&guest::loadCtx), guest::loadCtxSize);
offset += guest::loadCtxSize; offset += guest::loadCtxSize;
std::memcpy(reinterpret_cast<u8 *>(patch.data()) + guest::saveCtxSize + guest::loadCtxSize, std::memcpy(reinterpret_cast<u8 *>(patch.data()) + guest::saveCtxSize + guest::loadCtxSize, reinterpret_cast<void *>(&guest::SvcHandler), guest::svcHandlerSize);
reinterpret_cast<void *>(&guest::svcHandler), guest::svcHandlerSize);
offset += guest::svcHandlerSize; offset += guest::svcHandlerSize;
static u64 frequency{}; static u64 frequency{};
@ -276,7 +258,7 @@ namespace skyline {
} else if (frequency != constant::TegraX1Freq) { } else if (frequency != constant::TegraX1Freq) {
if (instrMrs->srcReg == constant::CntpctEl0) { if (instrMrs->srcReg == constant::CntpctEl0) {
instr::B bjunc(offset); instr::B bjunc(offset);
offset += CntpctEl0.size() * sizeof(u32); offset += guest::rescaleClockSize;
instr::Ldr ldr(0xF94003E0); // LDR XOUT, [SP] instr::Ldr ldr(0xF94003E0); // LDR XOUT, [SP]
ldr.destReg = instrMrs->destReg; ldr.destReg = instrMrs->destReg;
offset += sizeof(ldr); offset += sizeof(ldr);
@ -286,8 +268,9 @@ namespace skyline {
offset += sizeof(bret); offset += sizeof(bret);
*address = bjunc.raw; *address = bjunc.raw;
for (const auto &instr : CntpctEl0) auto size = patch.size();
patch.push_back(instr); 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(ldr.raw);
patch.push_back(addSp); patch.push_back(addSp);
patch.push_back(bret.raw); patch.push_back(bret.raw);
@ -316,4 +299,3 @@ namespace skyline {
return patch; return patch;
} }
} }

View File

@ -1,6 +1,6 @@
.text .text
.global saveCtx .global SaveCtx
saveCtx: SaveCtx:
STR LR, [SP, #-16]! STR LR, [SP, #-16]!
MRS LR, TPIDR_EL0 MRS LR, TPIDR_EL0
STP X0, X1, [LR, #16] STP X0, X1, [LR, #16]
@ -19,11 +19,11 @@ saveCtx:
STP X26, X27, [LR, #224] STP X26, X27, [LR, #224]
STP X28, X29, [LR, #240] STP X28, X29, [LR, #240]
LDR LR, [SP], #16 LDR LR, [SP], #16
DSB SY DSB ST
RET RET
.global loadCtx .global LoadCtx
loadCtx: LoadCtx:
STR LR, [SP, #-16]! STR LR, [SP, #-16]!
MRS LR, TPIDR_EL0 MRS LR, TPIDR_EL0
LDP X0, X1, [LR, #16] LDP X0, X1, [LR, #16]
@ -43,3 +43,23 @@ loadCtx:
LDP X28, X29, [LR, #240] LDP X28, X29, [LR, #240]
LDR LR, [SP], #16 LDR LR, [SP], #16
RET 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) #define FORCE_INLINE __attribute__((always_inline)) inline // NOLINT(cppcoreguidelines-macro-usage)
namespace skyline::guest { namespace skyline::guest {
FORCE_INLINE void saveCtxStack() { FORCE_INLINE void SaveCtxStack() {
asm("SUB SP, SP, #240\n\t" asm("SUB SP, SP, #240\n\t"
"STP X0, X1, [SP, #0]\n\t" "STP X0, X1, [SP, #0]\n\t"
"STP X2, X3, [SP, #16]\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" asm("LDP X0, X1, [SP, #0]\n\t"
"LDP X2, X3, [SP, #16]\n\t" "LDP X2, X3, [SP, #16]\n\t"
"LDP X4, X5, [SP, #32]\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" asm("STR LR, [SP, #-16]!\n\t"
"MRS LR, TPIDR_EL0\n\t" "MRS LR, TPIDR_EL0\n\t"
"STP X0, X1, [LR, #16]\n\t" "STP X0, X1, [LR, #16]\n\t"
@ -65,11 +65,12 @@ namespace skyline::guest {
"STP X24, X25, [LR, #208]\n\t" "STP X24, X25, [LR, #208]\n\t"
"STP X26, X27, [LR, #224]\n\t" "STP X26, X27, [LR, #224]\n\t"
"STP X28, X29, [LR, #240]\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" asm("STR LR, [SP, #-16]!\n\t"
"MRS LR, TPIDR_EL0\n\t" "MRS LR, TPIDR_EL0\n\t"
"LDP X0, X1, [LR, #16]\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; volatile ThreadContext *ctx;
asm("MRS %0, TPIDR_EL0":"=r"(ctx)); asm("MRS %0, TPIDR_EL0":"=r"(ctx));
ctx->pc = pc; ctx->pc = pc;
@ -112,7 +116,7 @@ namespace skyline::guest {
"MOV LR, SP\n\t" "MOV LR, SP\n\t"
"SVC #0\n\t" "SVC #0\n\t"
"MOV SP, LR\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; break;
} }
default: { default: {
@ -131,7 +135,7 @@ namespace skyline::guest {
"MOV LR, SP\n\t" "MOV LR, SP\n\t"
"SVC #0\n\t" "SVC #0\n\t"
"MOV SP, LR\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; return;
@ -153,35 +157,35 @@ namespace skyline::guest {
"LDR Q2, [SP], #16\n\t" "LDR Q2, [SP], #16\n\t"
"LDR Q1, [SP], #16\n\t" "LDR Q1, [SP], #16\n\t"
"LDR Q0, [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; return;
} }
while (true) { while (true) {
ctx->state = ThreadState::WaitKernel; ctx->state = ThreadState::WaitKernel;
while (ctx->state == ThreadState::WaitKernel); while (ctx->state == ThreadState::WaitKernel);
if (ctx->state == ThreadState::WaitRun) if (ctx->state == ThreadState::WaitRun) {
break; break;
else if (ctx->state == ThreadState::WaitFunc) { } else if (ctx->state == ThreadState::WaitFunc) {
if (ctx->commandId == static_cast<u32>(ThreadCall::Syscall)) { if (ctx->commandId == static_cast<u32>(ThreadCall::Syscall)) {
saveCtxStack(); SaveCtxStack();
loadCtxTls(); LoadCtxTls();
asm("STR LR, [SP, #-16]!\n\t" asm("STR LR, [SP, #-16]!\n\t"
"MOV LR, SP\n\t" "MOV LR, SP\n\t"
"SVC #0\n\t" "SVC #0\n\t"
"MOV SP, LR\n\t" "MOV SP, LR\n\t"
"LDR LR, [SP], #16"); "LDR LR, [SP], #16");
saveCtxTls(); SaveCtxTls();
loadCtxStack(); LoadCtxStack();
} else if (ctx->commandId == static_cast<u32>(ThreadCall::Memcopy)) { } else if (ctx->commandId == static_cast<u32>(ThreadCall::Memcopy)) {
auto src = reinterpret_cast<u8*>(ctx->registers.x0); auto src = reinterpret_cast<u8 *>(ctx->registers.x0);
auto dest = reinterpret_cast<u8*>(ctx->registers.x1); auto dest = reinterpret_cast<u8 *>(ctx->registers.x1);
auto size = ctx->registers.x2; auto size = ctx->registers.x2;
auto end = src + size; auto end = src + size;
while (src < end) while (src < end)
*(src++) = *(dest++); *(src++) = *(dest++);
} else if (ctx->commandId == static_cast<u32>(ThreadCall::Clone)) { } else if (ctx->commandId == static_cast<u32>(ThreadCall::Clone)) {
saveCtxStack(); SaveCtxStack();
loadCtxTls(); LoadCtxTls();
asm("STR LR, [SP, #-16]!\n\t" asm("STR LR, [SP, #-16]!\n\t"
"MOV LR, SP\n\t" "MOV LR, SP\n\t"
"SVC #0\n\t" "SVC #0\n\t"
@ -221,15 +225,15 @@ namespace skyline::guest {
".parent:\n\t" ".parent:\n\t"
"MOV SP, LR\n\t" "MOV SP, LR\n\t"
"LDR LR, [SP], #16"); "LDR LR, [SP], #16");
saveCtxTls(); SaveCtxTls();
loadCtxStack(); LoadCtxStack();
} }
} }
} }
ctx->state = ThreadState::Running; 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; volatile ThreadContext *ctx;
asm("MRS %0, TPIDR_EL0":"=r"(ctx)); asm("MRS %0, TPIDR_EL0":"=r"(ctx));
for (u8 index = 0; index < 30; index++) 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; volatile ThreadContext *ctx;
asm("MRS %0, TPIDR_EL0":"=r"(ctx)); asm("MRS %0, TPIDR_EL0":"=r"(ctx));
while (true) { while (true) {
ctx->state = ThreadState::WaitInit; ctx->state = ThreadState::WaitInit;
while (ctx->state == ThreadState::WaitInit); while (ctx->state == ThreadState::WaitInit);
if (ctx->state == ThreadState::WaitRun) if (ctx->state == ThreadState::WaitRun) {
break; break;
else if (ctx->state == ThreadState::WaitFunc) { } else if (ctx->state == ThreadState::WaitFunc) {
if (ctx->commandId == static_cast<u32>(ThreadCall::Syscall)) { if (ctx->commandId == static_cast<u32>(ThreadCall::Syscall)) {
saveCtxStack(); SaveCtxStack();
loadCtxTls(); LoadCtxTls();
asm("STR LR, [SP, #-16]!\n\t" asm("STR LR, [SP, #-16]!\n\t"
"MOV LR, SP\n\t" "MOV LR, SP\n\t"
"SVC #0\n\t" "SVC #0\n\t"
"MOV SP, LR\n\t" "MOV SP, LR\n\t"
"LDR LR, [SP], #16"); "LDR LR, [SP], #16");
saveCtxTls(); SaveCtxTls();
loadCtxStack(); LoadCtxStack();
} }
} else if (ctx->commandId == static_cast<u32>(ThreadCall::Memcopy)) { } else if (ctx->commandId == static_cast<u32>(ThreadCall::Memcopy)) {
auto src = reinterpret_cast<u8*>(ctx->registers.x0); auto src = reinterpret_cast<u8 *>(ctx->registers.x0);
auto dest = reinterpret_cast<u8*>(ctx->registers.x1); auto dest = reinterpret_cast<u8 *>(ctx->registers.x1);
auto size = ctx->registers.x2; auto size = ctx->registers.x2;
auto end = src + size; auto end = src + size;
while (src < end) while (src < end)
@ -275,7 +279,7 @@ namespace skyline::guest {
} }
} }
struct sigaction sigact{ 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, .sa_flags = SA_SIGINFO,
}; };
for (int signal : {SIGILL, SIGTRAP, SIGBUS, SIGFPE, SIGSEGV}) for (int signal : {SIGILL, SIGTRAP, SIGBUS, SIGFPE, SIGSEGV})
@ -312,7 +316,7 @@ namespace skyline::guest {
"MOV X27, XZR\n\t" "MOV X27, XZR\n\t"
"MOV X28, XZR\n\t" "MOV X28, XZR\n\t"
"MOV X29, 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(); __builtin_unreachable();
} }
} }

View File

@ -4,17 +4,19 @@ namespace skyline {
namespace guest { namespace guest {
constexpr size_t saveCtxSize = 20 * sizeof(u32); constexpr size_t saveCtxSize = 20 * sizeof(u32);
constexpr size_t loadCtxSize = 20 * sizeof(u32); constexpr size_t loadCtxSize = 20 * sizeof(u32);
constexpr size_t rescaleClockSize = 16 * sizeof(u32);
#ifdef NDEBUG #ifdef NDEBUG
constexpr size_t svcHandlerSize = 225 * sizeof(u32); constexpr size_t svcHandlerSize = 225 * sizeof(u32);
#else #else
constexpr size_t svcHandlerSize = 400 * sizeof(u32); constexpr size_t svcHandlerSize = 400 * sizeof(u32);
#endif #endif
void entry(u64 address); void GuestEntry(u64 address);
extern "C" void saveCtx(void); extern "C" void SaveCtx(void);
extern "C" void loadCtx(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 * @brief This enumeration is used to convey the state of a thread to the kernel
*/ */
enum class ThreadState : u32 { enum class ThreadState : u32 {
NotReady = 0, //!< The thread hasn't yet entered the entry handler NotReady = 0, //!< The thread hasn't yet entered the entry handler
Running = 1, //!< The thread is currently executing code Running = 1, //!< The thread is currently executing code
WaitKernel = 2, //!< The thread is currently waiting on the kernel WaitKernel = 2, //!< The thread is currently waiting on the kernel
WaitRun = 3, //!< The thread should be ready to run WaitRun = 3, //!< The thread should be ready to run
WaitInit = 4, //!< The thread is waiting to be initialized WaitInit = 4, //!< The thread is waiting to be initialized
WaitFunc = 5, //!< The kernel is waiting for the thread to run a function 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 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); 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; 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) if (pid == -1)
throw exception("Call to clone() has failed: {}", strerror(errno)); throw exception("Call to clone() has failed: {}", strerror(errno));
state.logger->Debug("Successfully created process with PID: {}", pid); 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); size_t numId = buffer.size / sizeof(NpadId);
u64 address = buffer.address; u64 address = buffer.address;
for (size_t i = 0; i < numId; i++) { 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); deviceMap[id] = JoyConDevice(id);
address += sizeof(NpadId); 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) { void nvdrv::Open(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
auto buffer = request.inputBuf.at(0); auto buffer = request.inputBuf.at(0);
std::string path(buffer.size, '\0'); auto path = state.process->GetString(buffer.address, buffer.size);
state.process->ReadMemory(path.data(), buffer.address, buffer.size);
response.Push<u32>(state.gpu->OpenDevice(path)); response.Push<u32>(state.gpu->OpenDevice(path));
response.Push<u32>(constant::status::Success); response.Push<u32>(constant::status::Success);
} }

View File

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