diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml
index d51d0e81..8e55800a 100644
--- a/.idea/inspectionProfiles/Project_Default.xml
+++ b/.idea/inspectionProfiles/Project_Default.xml
@@ -1621,7 +1621,7 @@
-
+
@@ -1644,7 +1644,7 @@
-
+
diff --git a/app/src/main/cpp/main.cpp b/app/src/main/cpp/main.cpp
index 716d7eda..cc008f2a 100644
--- a/app/src/main/cpp/main.cpp
+++ b/app/src/main/cpp/main.cpp
@@ -29,7 +29,7 @@ extern "C" JNIEXPORT void Java_emu_skyline_GameActivity_executeRom(JNIEnv *env,
std::signal(SIGABRT, signalHandler);
std::signal(SIGFPE, signalHandler);
- setpriority(PRIO_PROCESS, static_cast(getpid()), skyline::constant::PriorityAn.second);
+ setpriority(PRIO_PROCESS, static_cast(getpid()), skyline::constant::AndroidPriority.second);
auto jvmManager = std::make_shared(env, instance);
auto settings = std::make_shared(preferenceFd);
diff --git a/app/src/main/cpp/skyline/audio/common.h b/app/src/main/cpp/skyline/audio/common.h
index b393309e..4e76ab1f 100644
--- a/app/src/main/cpp/skyline/audio/common.h
+++ b/app/src/main/cpp/skyline/audio/common.h
@@ -3,41 +3,43 @@
#include
#include
-namespace skyline::audio {
- /**
- * @brief The available PCM stream formats
- */
- enum class PcmFormat : u8 {
- Invalid = 0, //!< An invalid PCM format
- Int8 = 1, //!< 8 bit integer PCM
- Int16 = 2, //!< 16 bit integer PCM
- Int24 = 3, //!< 24 bit integer PCM
- Int32 = 4, //!< 32 bit integer PCM
- PcmFloat = 5, //!< Floating point PCM
- AdPcm = 6 //!< Adaptive differential PCM
- };
-
- /**
- * @brief The state of an audio track
- */
- enum class AudioOutState : u8 {
- Started = 0, //!< Stream is started and is playing
- Stopped = 1, //!< Stream is stopped, there are no samples left to play
- Paused = 2 //!< Stream is paused, some samples may not have been played yet
- };
-
- /**
- * @brief Stores various information about pushed buffers
- */
- struct BufferIdentifier {
- u64 tag; //!< The tag of the buffer
- u64 finalSample; //!< The final sample this buffer will be played in
- bool released; //!< Whether the buffer has been released
- };
-
+namespace skyline {
namespace constant {
- constexpr int SampleRate = 48000; //!< The sampling rate to use for the oboe audio output
- constexpr int ChannelCount = 2; //!< The amount of channels to use for the oboe audio output
- constexpr oboe::AudioFormat PcmFormat = oboe::AudioFormat::I16; //!< The pcm data format to use for the oboe audio output
+ constexpr auto SampleRate = 48000; //!< The sampling rate to use for the oboe audio output
+ constexpr auto ChannelCount = 2; //!< The amount of channels to use for the oboe audio output
+ constexpr auto PcmFormat = oboe::AudioFormat::I16; //!< The pcm data format to use for the oboe audio output
};
+
+ namespace audio {
+ /**
+ * @brief The available PCM stream formats
+ */
+ enum class PcmFormat : u8 {
+ Invalid = 0, //!< An invalid PCM format
+ Int8 = 1, //!< 8 bit integer PCM
+ Int16 = 2, //!< 16 bit integer PCM
+ Int24 = 3, //!< 24 bit integer PCM
+ Int32 = 4, //!< 32 bit integer PCM
+ PcmFloat = 5, //!< Floating point PCM
+ AdPcm = 6 //!< Adaptive differential PCM
+ };
+
+ /**
+ * @brief The state of an audio track
+ */
+ enum class AudioOutState : u8 {
+ Started = 0, //!< Stream is started and is playing
+ Stopped = 1, //!< Stream is stopped, there are no samples left to play
+ Paused = 2 //!< Stream is paused, some samples may not have been played yet
+ };
+
+ /**
+ * @brief Stores various information about pushed buffers
+ */
+ struct BufferIdentifier {
+ u64 tag; //!< The tag of the buffer
+ u64 finalSample; //!< The final sample this buffer will be played in
+ bool released; //!< Whether the buffer has been released
+ };
+ }
}
diff --git a/app/src/main/cpp/skyline/audio/resampler.cpp b/app/src/main/cpp/skyline/audio/resampler.cpp
index e86a0fd8..bce079c5 100644
--- a/app/src/main/cpp/skyline/audio/resampler.cpp
+++ b/app/src/main/cpp/skyline/audio/resampler.cpp
@@ -10,7 +10,7 @@ namespace skyline::audio {
i32 d;
};
- constexpr std::array curveLut0 = {{
+ constexpr std::array CurveLut0 = {{
{6600, 19426, 6722, 3}, {6479, 19424, 6845, 9}, {6359, 19419, 6968, 15}, {6239, 19412, 7093, 22},
{6121, 19403, 7219, 28}, {6004, 19391, 7345, 34}, {5888, 19377, 7472, 41}, {5773, 19361, 7600, 48},
{5659, 19342, 7728, 55}, {5546, 19321, 7857, 62}, {5434, 19298, 7987, 69}, {5323, 19273, 8118, 77},
@@ -44,7 +44,7 @@ namespace skyline::audio {
{48, 7600, 19361, 5773}, {41, 7472, 19377, 5888}, {34, 7345, 19391, 6004}, {28, 7219, 19403, 6121},
{22, 7093, 19412, 6239}, {15, 6968, 19419, 6359}, {9, 6845, 19424, 6479}, {3, 6722, 19426, 6600}}};
- constexpr std::array curveLut1 = {{
+ constexpr std::array CurveLut1 = {{
{-68, 32639, 69, -5}, {-200, 32630, 212, -15}, {-328, 32613, 359, -26}, {-450, 32586, 512, -36},
{-568, 32551, 669, -47}, {-680, 32507, 832, -58}, {-788, 32454, 1000, -69}, {-891, 32393, 1174, -80},
{-990, 32323, 1352, -92}, {-1084, 32244, 1536, -103}, {-1173, 32157, 1724, -115}, {-1258, 32061, 1919, -128},
@@ -78,7 +78,7 @@ namespace skyline::audio {
{-80, 1174, 32393, -891}, {-69, 1000, 32454, -788}, {-58, 832, 32507, -680}, {-47, 669, 32551, -568},
{-36, 512, 32586, -450}, {-26, 359, 32613, -328}, {-15, 212, 32630, -200}, {-5, 69, 32639, -68}}};
- constexpr std::array curveLut2 = {{
+ constexpr std::array CurveLut2 = {{
{3195, 26287, 3329, -32}, {3064, 26281, 3467, -34}, {2936, 26270, 3608, -38}, {2811, 26253, 3751, -42},
{2688, 26230, 3897, -46}, {2568, 26202, 4046, -50}, {2451, 26169, 4199, -54}, {2338, 26130, 4354, -58},
{2227, 26085, 4512, -63}, {2120, 26035, 4673, -67}, {2015, 25980, 4837, -72}, {1912, 25919, 5004, -76},
@@ -118,14 +118,13 @@ namespace skyline::audio {
std::vector outputBuffer(static_cast(outputSize));
const std::array &lut = [step] {
- if (step > 0xaaaa) {
- return curveLut0;
- } else if (step <= 0x8000) {
- return curveLut1;
- } else {
- return curveLut2;
- }
- } ();
+ if (step > 0xaaaa)
+ return CurveLut0;
+ else if (step <= 0x8000)
+ return CurveLut1;
+ else
+ return CurveLut2;
+ }();
for (uint outIndex = 0, inIndex = 0; outIndex < outputBuffer.size(); outIndex += channelCount) {
uint lutIndex = (fraction >> 8) << 2;
diff --git a/app/src/main/cpp/skyline/common.cpp b/app/src/main/cpp/skyline/common.cpp
index 26fd5da6..da4cca8b 100644
--- a/app/src/main/cpp/skyline/common.cpp
+++ b/app/src/main/cpp/skyline/common.cpp
@@ -11,6 +11,7 @@ namespace skyline {
for (int i = 0; i < 1000; ++i) {
if (!flag.test_and_set(std::memory_order_acquire))
return;
+
asm volatile("yield");
}
sched_yield();
@@ -21,14 +22,17 @@ namespace skyline {
auto none = Group::None;
constexpr u64 timeout = 100; // The timeout in ns
auto end = utils::GetTimeNs() + timeout;
+
while (true) {
if (next == group) {
if (flag == group) {
std::lock_guard lock(mtx);
+
if (flag == group) {
auto groupT = group;
next.compare_exchange_strong(groupT, Group::None);
num++;
+
return;
}
} else {
@@ -36,6 +40,7 @@ namespace skyline {
}
} else if (flag == group && (next == Group::None || utils::GetTimeNs() >= end)) {
std::lock_guard lock(mtx);
+
if (flag == group) {
num++;
return;
@@ -43,6 +48,7 @@ namespace skyline {
} else {
next.compare_exchange_weak(none, group);
}
+
none = Group::None;
asm volatile("yield");
}
@@ -50,38 +56,44 @@ namespace skyline {
void GroupMutex::unlock() {
std::lock_guard lock(mtx);
+
if (!--num)
flag.exchange(next);
}
Settings::Settings(const int preferenceFd) {
tinyxml2::XMLDocument pref;
+
if (pref.LoadFile(fdopen(preferenceFd, "r")))
throw exception("TinyXML2 Error: " + std::string(pref.ErrorStr()));
+
tinyxml2::XMLElement *elem = pref.LastChild()->FirstChild()->ToElement();
+
while (elem) {
switch (elem->Value()[0]) {
case 's':
stringMap[elem->FindAttribute("name")->Value()] = elem->GetText();
break;
+
case 'b':
- boolMap[elem->FindAttribute("name")->Value()] = elem->FindAttribute(
- "value")->BoolValue();
+ boolMap[elem->FindAttribute("name")->Value()] = elem->FindAttribute("value")->BoolValue();
break;
+
case 'i':
- intMap[elem->FindAttribute("name")->Value()] = elem->FindAttribute(
- "value")->IntValue();
+ intMap[elem->FindAttribute("name")->Value()] = elem->FindAttribute("value")->IntValue();
break;
+
default:
- syslog(LOG_ALERT, "Settings type is missing: %s for %s", elem->Value(),
- elem->FindAttribute("name")->Value());
+ syslog(LOG_ALERT, "Settings type is missing: %s for %s", elem->Value(), elem->FindAttribute("name")->Value());
break;
};
+
if (elem->NextSibling())
elem = elem->NextSibling()->ToElement();
else
break;
}
+
pref.Clear();
}
@@ -100,6 +112,7 @@ namespace skyline {
void Settings::List(const std::shared_ptr &logger) {
for (auto &iter : stringMap)
logger->Info("Key: {}, Value: {}, Type: String", iter.first, GetString(iter.first));
+
for (auto &iter : boolMap)
logger->Info("Key: {}, Value: {}, Type: Bool", iter.first, GetBool(iter.first));
}
@@ -115,15 +128,18 @@ namespace skyline {
void Logger::WriteHeader(const std::string &str) {
syslog(LOG_ALERT, "%s", str.c_str());
+
logFile << "0|" << str << "\n";
logFile.flush();
}
void Logger::Write(const LogLevel level, std::string str) {
syslog(levelSyslog[static_cast(level)], "%s", str.c_str());
+
for (auto &character : str)
if (character == '\n')
character = '\\';
+
logFile << "1|" << levelStr[static_cast(level)] << "|" << str << "\n";
logFile.flush();
}
diff --git a/app/src/main/cpp/skyline/common.h b/app/src/main/cpp/skyline/common.h
index 90e73d56..7dbf2dd2 100644
--- a/app/src/main/cpp/skyline/common.h
+++ b/app/src/main/cpp/skyline/common.h
@@ -19,47 +19,20 @@
#include "nce/guest_common.h"
namespace skyline {
- using handle_t = u32; //!< The type of a kernel handle
+ using KHandle = u32; //!< The type of a kernel handle
namespace constant {
// Memory
- constexpr u64 BaseAddress = 0x8000000; //!< The address space base
- constexpr u64 TotalPhyMem = 0xF8000000; // ~4 GB of RAM
- constexpr size_t DefStackSize = 0x1E8480; //!< The default amount of stack: 2 MB
- constexpr size_t HeapSizeDiv = 0x200000; //!< The amount heap size has to be divisible by
- constexpr size_t DefHeapSize = HeapSizeDiv; //!< The default amount of heap
- constexpr size_t TlsSlotSize = 0x200; //!< The size of a single TLS slot
- constexpr u8 TlsSlots = PAGE_SIZE / TlsSlotSize; //!< The amount of TLS slots in a single page
- // Loader
- constexpr u32 NroMagic = 0x304F524E; //!< "NRO0" in reverse, this is written at the start of every NRO file
- // NCE
- constexpr u8 NumRegs = 30; //!< The amount of registers that ARMv8 has
- constexpr u32 TpidrroEl0 = 0x5E83; //!< ID of TPIDRRO_EL0 in MRS
- constexpr u32 CntfrqEl0 = 0x5F00; //!< ID of CNTFRQ_EL0 in MRS
- constexpr u32 TegraX1Freq = 19200000; //!< The clock frequency of the Tegra X1 (19.2 MHz)
- constexpr u32 CntpctEl0 = 0x5F01; //!< ID of CNTPCT_EL0 in MRS
- constexpr u32 CntvctEl0 = 0x5F02; //!< ID of CNTVCT_EL0 in MRS
+ constexpr auto BaseAddress = 0x8000000; //!< The address space base
+ constexpr auto DefStackSize = 0x1E8480; //!< The default amount of stack: 2 MB
// Kernel
- constexpr u64 MaxSyncHandles = 0x40; //!< The total amount of handles that can be passed to WaitSynchronization
- constexpr handle_t BaseHandleIndex = 0xD000; // The index of the base handle
- constexpr handle_t ThreadSelf = 0xFFFF8000; //!< This is the handle used by threads to refer to themselves
- constexpr u8 DefaultPriority = 44; //!< The default priority of a process
- constexpr std::pair PriorityAn = {19, -8}; //!< The range of priority for Android, taken from https://medium.com/mindorks/exploring-android-thread-priority-5d0542eebbd1
- constexpr std::pair PriorityNin = {0, 63}; //!< The range of priority for the Nintendo Switch
- constexpr u32 MtxOwnerMask = 0xBFFFFFFF; //!< The mask of values which contain the owner of a mutex
- // IPC
- constexpr size_t TlsIpcSize = 0x100; //!< The size of the IPC command buffer in a TLS slot
- constexpr u8 PortSize = 0x8; //!< The size of a port name string
- constexpr u32 SfcoMagic = 0x4F434653; //!< SFCO in reverse, written to IPC messages
- constexpr u32 SfciMagic = 0x49434653; //!< SFCI in reverse, present in received IPC messages
- constexpr u64 IpcPaddingSum = 0x10; //!< The sum of the padding surrounding DataPayload
- constexpr handle_t BaseVirtualHandleIndex = 0x1; // The index of the base virtual handle
- // GPU
- constexpr u32 HandheldResolutionW = 1280; //!< The width component of the handheld resolution
- constexpr u32 HandheldResolutionH = 720; //!< The height component of the handheld resolution
- constexpr u32 DockedResolutionW = 1920; //!< The width component of the docked resolution
- constexpr u32 DockedResolutionH = 1080; //!< The height component of the docked resolution
- constexpr u32 TokenLength = 0x50; //!< The length of the token on BufferQueue parcels
+ constexpr std::pair AndroidPriority = {19, -8}; //!< The range of priority for Android
+ constexpr std::pair SwitchPriority = {0, 63}; //!< The range of priority for the Nintendo Switch
+ // Display
+ constexpr auto HandheldResolutionW = 1280; //!< The width component of the handheld resolution
+ constexpr auto HandheldResolutionH = 720; //!< The height component of the handheld resolution
+ constexpr auto DockedResolutionW = 1920; //!< The width component of the docked resolution
+ constexpr auto DockedResolutionH = 1080; //!< The height component of the docked resolution
// Status codes
namespace status {
constexpr u32 Success = 0x0; //!< "Success"
@@ -98,13 +71,13 @@ namespace skyline {
* @return The current time in nanoseconds
*/
inline u64 GetTimeNs() {
- constexpr uint64_t NsInSecond = 1000000000;
+ constexpr uint64_t nsInSecond = 1000000000;
static u64 frequency{};
if (!frequency)
asm("MRS %0, CNTFRQ_EL0" : "=r"(frequency));
u64 ticks;
asm("MRS %0, CNTVCT_EL0" : "=r"(ticks));
- return ((ticks / frequency) * NsInSecond) + (((ticks % frequency) * NsInSecond + (frequency / 2)) / frequency);
+ return ((ticks / frequency) * nsInSecond) + (((ticks % frequency) * nsInSecond + (frequency / 2)) / frequency);
}
/**
diff --git a/app/src/main/cpp/skyline/kernel/ipc.cpp b/app/src/main/cpp/skyline/kernel/ipc.cpp
index 396b075b..c7954958 100644
--- a/app/src/main/cpp/skyline/kernel/ipc.cpp
+++ b/app/src/main/cpp/skyline/kernel/ipc.cpp
@@ -23,12 +23,12 @@ namespace skyline::kernel::ipc {
handleDesc = reinterpret_cast(pointer);
pointer += sizeof(HandleDescriptor) + (handleDesc->sendPid ? sizeof(u64) : 0);
for (uint index = 0; handleDesc->copyCount > index; index++) {
- copyHandles.push_back(*reinterpret_cast(pointer));
- pointer += sizeof(handle_t);
+ copyHandles.push_back(*reinterpret_cast(pointer));
+ pointer += sizeof(KHandle);
}
for (uint index = 0; handleDesc->moveCount > index; index++) {
- moveHandles.push_back(*reinterpret_cast(pointer));
- pointer += sizeof(handle_t);
+ moveHandles.push_back(*reinterpret_cast(pointer));
+ pointer += sizeof(KHandle);
}
}
@@ -69,7 +69,9 @@ namespace skyline::kernel::ipc {
pointer += sizeof(BufferDescriptorABW);
}
- u64 padding = ((((reinterpret_cast(pointer) - reinterpret_cast(tls)) - 1U) & ~(constant::IpcPaddingSum - 1U)) + constant::IpcPaddingSum + (reinterpret_cast(tls) - reinterpret_cast(pointer))); // Calculate the amount of padding at the front
+ constexpr auto ipcPaddingSum = 0x10; // The sum of the padding surrounding the data payload
+
+ u64 padding = ((((reinterpret_cast(pointer) - reinterpret_cast(tls)) - 1U) & ~(ipcPaddingSum - 1U)) + ipcPaddingSum + (reinterpret_cast(tls) - reinterpret_cast(pointer))); // Calculate the amount of padding at the front
pointer += padding;
if (isDomain && (header->type == CommandType::Request)) {
@@ -84,24 +86,26 @@ namespace skyline::kernel::ipc {
pointer += domain->payloadSz;
for (uint index = 0; domain->inputCount > index; index++) {
- domainObjects.push_back(*reinterpret_cast(pointer));
- pointer += sizeof(handle_t);
+ domainObjects.push_back(*reinterpret_cast(pointer));
+ pointer += sizeof(KHandle);
}
} else {
payload = reinterpret_cast(pointer);
pointer += sizeof(PayloadHeader);
cmdArg = pointer;
- cmdArgSz = (header->rawSize * sizeof(u32)) - (constant::IpcPaddingSum + sizeof(PayloadHeader));
+ cmdArgSz = (header->rawSize * sizeof(u32)) - (ipcPaddingSum + sizeof(PayloadHeader));
pointer += cmdArgSz;
}
payloadOffset = cmdArg;
- if (payload->magic != constant::SfciMagic && header->type != CommandType::Control)
+ constexpr auto sfciMagic = 0x49434653; //!< SFCI in reverse, present in received IPC messages
+
+ if (payload->magic != sfciMagic && header->type != CommandType::Control)
state.logger->Debug("Unexpected Magic in PayloadHeader: 0x{:X}", u32(payload->magic));
- pointer += constant::IpcPaddingSum - padding;
+ pointer += ipcPaddingSum - padding;
if (header->cFlag == BufferCFlag::SingleDescriptor) {
auto bufC = reinterpret_cast(pointer);
@@ -135,10 +139,14 @@ namespace skyline::kernel::ipc {
void IpcResponse::WriteResponse() {
auto tls = state.process->GetPointer(state.thread->tls);
u8 *pointer = tls;
- memset(tls, 0, constant::TlsIpcSize);
+
+ constexpr auto tlsIpcSize = 0x100; // The size of the IPC command buffer in a TLS slot
+ memset(tls, 0, tlsIpcSize);
+
+ constexpr auto ipcPaddingSum = 0x10; // The sum of the padding surrounding the data payload
auto header = reinterpret_cast(pointer);
- header->rawSize = static_cast((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((sizeof(PayloadHeader) + argVec.size() + (domainObjects.size() * sizeof(KHandle)) + ipcPaddingSum + (isDomain ? sizeof(DomainHeaderRequest) : 0)) / sizeof(u32)); // Size is in 32-bit units because Nintendo
header->handleDesc = (!copyHandles.empty() || !moveHandles.empty());
pointer += sizeof(CommandHeader);
@@ -149,17 +157,17 @@ namespace skyline::kernel::ipc {
pointer += sizeof(HandleDescriptor);
for (unsigned int copyHandle : copyHandles) {
- *reinterpret_cast(pointer) = copyHandle;
- pointer += sizeof(handle_t);
+ *reinterpret_cast(pointer) = copyHandle;
+ pointer += sizeof(KHandle);
}
for (unsigned int moveHandle : moveHandles) {
- *reinterpret_cast(pointer) = moveHandle;
- pointer += sizeof(handle_t);
+ *reinterpret_cast(pointer) = moveHandle;
+ pointer += sizeof(KHandle);
}
}
- u64 padding = ((((reinterpret_cast(pointer) - reinterpret_cast(tls)) - 1U) & ~(constant::IpcPaddingSum - 1U)) + constant::IpcPaddingSum + (reinterpret_cast(tls) - reinterpret_cast(pointer))); // Calculate the amount of padding at the front
+ u64 padding = ((((reinterpret_cast(pointer) - reinterpret_cast(tls)) - 1U) & ~(ipcPaddingSum - 1U)) + ipcPaddingSum + (reinterpret_cast(tls) - reinterpret_cast(pointer))); // Calculate the amount of padding at the front
pointer += padding;
if (isDomain) {
@@ -168,19 +176,22 @@ namespace skyline::kernel::ipc {
pointer += sizeof(DomainHeaderResponse);
}
+ constexpr auto sfcoMagic = 0x4F434653; // SFCO in reverse, IPC Response Magic
+
auto payload = reinterpret_cast(pointer);
- payload->magic = constant::SfcoMagic;
+ payload->magic = sfcoMagic;
payload->version = 1;
payload->value = errorCode;
pointer += sizeof(PayloadHeader);
+
if (!argVec.empty())
memcpy(pointer, argVec.data(), argVec.size());
pointer += argVec.size();
if (isDomain) {
for (auto &domainObject : domainObjects) {
- *reinterpret_cast(pointer) = domainObject;
- pointer += sizeof(handle_t);
+ *reinterpret_cast(pointer) = domainObject;
+ pointer += sizeof(KHandle);
}
}
diff --git a/app/src/main/cpp/skyline/kernel/ipc.h b/app/src/main/cpp/skyline/kernel/ipc.h
index 266bf01b..8fbeb805 100644
--- a/app/src/main/cpp/skyline/kernel/ipc.h
+++ b/app/src/main/cpp/skyline/kernel/ipc.h
@@ -242,7 +242,6 @@ namespace skyline::kernel::ipc {
u8 *payloadOffset; //!< This is the offset of the data read from the payload
public:
- //std::array 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
@@ -250,9 +249,9 @@ namespace skyline::kernel::ipc {
PayloadHeader *payload{}; //!< This is the header of the payload
u8 *cmdArg{}; //!< This is a pointer to the data payload (End of PayloadHeader)
u64 cmdArgSz{}; //!< This is the size of the data payload
- std::vector copyHandles; //!< A vector of handles that should be copied from the server to the client process (The difference is just to match application expectations, there is no real difference b/w copying and moving handles)
- std::vector moveHandles; //!< A vector of handles that should be moved from the server to the client process rather than copied
- std::vector domainObjects; //!< A vector of all input domain objects
+ std::vector copyHandles; //!< A vector of handles that should be copied from the server to the client process (The difference is just to match application expectations, there is no real difference b/w copying and moving handles)
+ std::vector moveHandles; //!< A vector of handles that should be moved from the server to the client process rather than copied
+ std::vector domainObjects; //!< A vector of all input domain objects
std::vector inputBuf; //!< This is a vector of input buffers
std::vector outputBuf; //!< This is a vector of output buffers
@@ -295,9 +294,9 @@ namespace skyline::kernel::ipc {
bool nWrite{}; //!< This is to signal the IPC handler to not write this, as it will be manually written
bool isDomain{}; //!< If this is a domain request
u32 errorCode{}; //!< The error code to respond with, it is 0 (Success) by default
- std::vector copyHandles; //!< A vector of handles to copy
- std::vector moveHandles; //!< A vector of handles to move
- std::vector domainObjects; //!< A vector of domain objects to write
+ std::vector copyHandles; //!< A vector of handles to copy
+ std::vector moveHandles; //!< A vector of handles to move
+ std::vector domainObjects; //!< A vector of domain objects to write
/**
* @param isDomain If the following request is a domain request
diff --git a/app/src/main/cpp/skyline/kernel/memory.h b/app/src/main/cpp/skyline/kernel/memory.h
index 50fb666e..4910d540 100644
--- a/app/src/main/cpp/skyline/kernel/memory.h
+++ b/app/src/main/cpp/skyline/kernel/memory.h
@@ -117,24 +117,24 @@ namespace skyline {
struct {
MemoryType type; //!< The MemoryType of this memory block
- bool PermissionChangeAllowed : 1; //!< If the application can use svcSetMemoryPermission on this block
- bool ForceReadWritableByDebugSyscalls : 1; //!< If the application can use svcWriteDebugProcessMemory on this block
- bool IpcSendAllowed : 1; //!< If this block is allowed to be sent as an IPC buffer with flags=0
- bool NonDeviceIpcSendAllowed : 1; //!< If this block is allowed to be sent as an IPC buffer with flags=3
- bool NonSecureIpcSendAllowed : 1; //!< If this block is allowed to be sent as an IPC buffer with flags=1
+ bool permissionChangeAllowed : 1; //!< If the application can use svcSetMemoryPermission on this block
+ bool forceReadWritableByDebugSyscalls : 1; //!< If the application can use svcWriteDebugProcessMemory on this block
+ bool ipcSendAllowed : 1; //!< If this block is allowed to be sent as an IPC buffer with flags=0
+ bool nonDeviceIpcSendAllowed : 1; //!< If this block is allowed to be sent as an IPC buffer with flags=3
+ bool nonSecureIpcSendAllowed : 1; //!< If this block is allowed to be sent as an IPC buffer with flags=1
bool _pad0_ : 1;
- bool ProcessPermissionChangeAllowed : 1; //!< If the application can use svcSetProcessMemoryPermission on this block
- bool MapAllowed : 1; //!< If the application can use svcMapMemory on this block
- bool UnmapProcessCodeMemoryAllowed : 1; //!< If the application can use svcUnmapProcessCodeMemory on this block
- bool TransferMemoryAllowed : 1; //!< If the application can use svcCreateTransferMemory on this block
- bool QueryPhysicalAddressAllowed : 1; //!< If the application can use svcQueryPhysicalAddress on this block
- bool MapDeviceAllowed : 1; //!< If the application can use svcMapDeviceAddressSpace or svcMapDeviceAddressSpaceByForce on this block
- bool MapDeviceAlignedAllowed : 1; //!< If the application can use svcMapDeviceAddressSpaceAligned on this block
- bool IpcBufferAllowed : 1; //!< If the application can use this block with svcSendSyncRequestWithUserBuffer
- bool IsReferenceCounted : 1; //!< If the physical memory blocks backing this region are reference counted
- bool MapProcessAllowed : 1; //!< If the application can use svcMapProcessMemory on this block
- bool AttributeChangeAllowed : 1; //!< If the application can use svcSetMemoryAttribute on this block
- bool CodeMemoryAllowed : 1; //!< If the application can use svcCreateCodeMemory on this block
+ bool processPermissionChangeAllowed : 1; //!< If the application can use svcSetProcessMemoryPermission on this block
+ bool mapAllowed : 1; //!< If the application can use svcMapMemory on this block
+ bool unmapProcessCodeMemoryAllowed : 1; //!< If the application can use svcUnmapProcessCodeMemory on this block
+ bool transferMemoryAllowed : 1; //!< If the application can use svcCreateTransferMemory on this block
+ bool queryPhysicalAddressAllowed : 1; //!< If the application can use svcQueryPhysicalAddress on this block
+ bool mapDeviceAllowed : 1; //!< If the application can use svcMapDeviceAddressSpace or svcMapDeviceAddressSpaceByForce on this block
+ bool mapDeviceAlignedAllowed : 1; //!< If the application can use svcMapDeviceAddressSpaceAligned on this block
+ bool ipcBufferAllowed : 1; //!< If the application can use this block with svcSendSyncRequestWithUserBuffer
+ bool isReferenceCounted : 1; //!< If the physical memory blocks backing this region are reference counted
+ bool mapProcessAllowed : 1; //!< If the application can use svcMapProcessMemory on this block
+ bool attributeChangeAllowed : 1; //!< If the application can use svcSetMemoryAttribute on this block
+ bool codeMemoryAllowed : 1; //!< If the application can use svcCreateCodeMemory on this block
};
u32 value;
};
@@ -143,7 +143,7 @@ namespace skyline {
/**
* @brief The preset states that different regions are set to (https://switchbrew.org/wiki/SVC#MemoryType)
*/
- namespace MemoryStates {
+ namespace states {
constexpr MemoryState Unmapped = 0x00000000;
constexpr MemoryState Io = 0x00002001;
constexpr MemoryState CodeStatic = 0x00DC7E03;
diff --git a/app/src/main/cpp/skyline/kernel/svc.cpp b/app/src/main/cpp/skyline/kernel/svc.cpp
index 34adae3a..fbf2348d 100644
--- a/app/src/main/cpp/skyline/kernel/svc.cpp
+++ b/app/src/main/cpp/skyline/kernel/svc.cpp
@@ -3,17 +3,23 @@
namespace skyline::kernel::svc {
void SetHeapSize(DeviceState &state) {
+ constexpr auto heapSizeAlign = 0x200000; // The heap size has to be a multiple of this value
const u32 size = state.ctx->registers.w1;
- if (size % constant::HeapSizeDiv != 0) {
+
+ if (size % heapSizeAlign != 0) {
state.ctx->registers.w0 = constant::status::InvSize;
state.ctx->registers.x1 = 0;
+
state.logger->Warn("svcSetHeapSize: 'size' not divisible by 2MB: {}", size);
return;
}
+
auto &heap = state.process->heap;
heap->Resize(size);
+
state.ctx->registers.w0 = constant::status::Success;
state.ctx->registers.x1 = heap->address;
+
state.logger->Debug("svcSetHeapSize: Allocated at 0x{:X} for 0x{:X} bytes", heap->address, heap->size);
}
@@ -45,7 +51,7 @@ namespace skyline::kernel::svc {
state.logger->Warn("svcSetMemoryAttribute: Cannot find memory region: 0x{:X}", address);
return;
}
- if (!chunk->state.AttributeChangeAllowed) {
+ if (!chunk->state.attributeChangeAllowed) {
state.ctx->registers.w0 = constant::status::InvState;
state.logger->Warn("svcSetMemoryAttribute: Attribute change not allowed for chunk: 0x{:X}", address);
return;
@@ -82,12 +88,12 @@ namespace skyline::kernel::svc {
state.logger->Warn("svcMapMemory: Source has no descriptor: Source: 0x{:X}, Destination: 0x{:X} (Size: 0x{:X} bytes)", source, destination, size);
return;
}
- if (!descriptor->chunk.state.MapAllowed) {
+ if (!descriptor->chunk.state.mapAllowed) {
state.ctx->registers.w0 = constant::status::InvState;
state.logger->Warn("svcMapMemory: Source doesn't allow usage of svcMapMemory: Source: 0x{:X}, Destination: 0x{:X} (Size: 0x{:X} bytes) 0x{:X}", source, destination, size, descriptor->chunk.state.value);
return;
}
- state.process->NewHandle(destination, size, descriptor->block.permission, memory::MemoryStates::Stack);
+ state.process->NewHandle(destination, size, descriptor->block.permission, memory::states::Stack);
state.process->CopyMemory(source, destination, size);
auto object = state.process->GetMemoryObject(source);
if (!object)
@@ -124,7 +130,7 @@ namespace skyline::kernel::svc {
state.logger->Warn("svcUnmapMemory: Addresses have no descriptor: Source: 0x{:X}, Destination: 0x{:X} (Size: 0x{:X} bytes)", source, destination, size);
return;
}
- if (!destDesc->chunk.state.MapAllowed) {
+ if (!destDesc->chunk.state.mapAllowed) {
state.ctx->registers.w0 = constant::status::InvState;
state.logger->Warn("svcUnmapMemory: Destination doesn't allow usage of svcMapMemory: Source: 0x{:X}, Destination: 0x{:X} (Size: 0x{:X} bytes) 0x{:X}", source, destination, size, destDesc->chunk.state.value);
return;
@@ -181,7 +187,7 @@ namespace skyline::kernel::svc {
u64 entryArgument = state.ctx->registers.x2;
u64 stackTop = state.ctx->registers.x3;
u8 priority = static_cast(state.ctx->registers.w4);
- if ((priority < constant::PriorityNin.first) || (priority > constant::PriorityNin.second)) {
+ if ((priority < constant::SwitchPriority.first) || (priority > constant::SwitchPriority.second)) {
state.ctx->registers.w0 = constant::status::InvAddress;
state.logger->Warn("svcCreateThread: 'priority' invalid: {}", priority);
return;
@@ -312,7 +318,7 @@ namespace skyline::kernel::svc {
}
void CloseHandle(DeviceState &state) {
- auto handle = static_cast(state.ctx->registers.w0);
+ auto handle = static_cast(state.ctx->registers.w0);
try {
state.process->handles.erase(handle);
state.logger->Debug("svcCloseHandle: Closing handle: 0x{:X}", handle);
@@ -350,40 +356,52 @@ namespace skyline::kernel::svc {
}
void WaitSynchronization(DeviceState &state) {
+ constexpr auto maxSyncHandles = 0x40; // The total amount of handles that can be passed to WaitSynchronization
auto numHandles = state.ctx->registers.w2;
- if (numHandles > constant::MaxSyncHandles) {
+ if (numHandles > maxSyncHandles) {
state.ctx->registers.w0 = constant::status::MaxHandles;
return;
}
- std::vector waitHandles(numHandles);
- std::vector> objectTable;
- state.process->ReadMemory(waitHandles.data(), state.ctx->registers.x1, numHandles * sizeof(handle_t));
+
std::string handleStr;
+ std::vector> objectTable;
+ std::vector waitHandles(numHandles);
+
+ state.process->ReadMemory(waitHandles.data(), state.ctx->registers.x1, numHandles * sizeof(KHandle));
+
for (const auto &handle : waitHandles) {
handleStr += fmt::format("* 0x{:X}\n", handle);
+
auto object = state.process->handles.at(handle);
+
switch (object->objectType) {
case type::KType::KProcess:
case type::KType::KThread:
case type::KType::KEvent:
case type::KType::KSession:
break;
+
default: {
state.ctx->registers.w0 = constant::status::InvHandle;
return;
}
}
+
objectTable.push_back(std::static_pointer_cast(object));
}
+
auto timeout = state.ctx->registers.x3;
state.logger->Debug("svcWaitSynchronization: Waiting on handles:\n{}Timeout: 0x{:X} ns", handleStr, timeout);
+
auto start = utils::GetTimeNs();
+
while (true) {
if (state.thread->cancelSync) {
state.thread->cancelSync = false;
state.ctx->registers.w0 = constant::status::Interrupted;
break;
}
+
uint index{};
for (const auto &object : objectTable) {
if (object->signalled) {
@@ -394,6 +412,7 @@ namespace skyline::kernel::svc {
}
index++;
}
+
if ((utils::GetTimeNs() - start) >= timeout) {
state.logger->Debug("svcWaitSynchronization: Wait has timed out");
state.ctx->registers.w0 = constant::status::Timeout;
@@ -496,34 +515,41 @@ namespace skyline::kernel::svc {
}
void ConnectToNamedPort(DeviceState &state) {
- 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) {
+ constexpr auto portSize = 0x8; //!< The size of a port name string
+ std::string_view port(state.process->GetPointer(state.ctx->registers.x1), portSize);
+
+ KHandle handle{};
+ if (port.compare("sm:") >= 0) {
handle = state.os->serviceManager.NewSession(service::Service::sm_IUserInterface);
} else {
state.logger->Warn("svcConnectToNamedPort: Connecting to invalid port: '{}'", port);
state.ctx->registers.w0 = constant::status::NotFound;
return;
}
+
state.logger->Debug("svcConnectToNamedPort: Connecting to port '{}' at 0x{:X}", port, handle);
+
state.ctx->registers.w1 = handle;
state.ctx->registers.w0 = constant::status::Success;
}
void SendSyncRequest(DeviceState &state) {
- state.os->serviceManager.SyncRequestHandler(static_cast(state.ctx->registers.x0));
+ state.os->serviceManager.SyncRequestHandler(static_cast(state.ctx->registers.x0));
state.ctx->registers.w0 = constant::status::Success;
}
void GetThreadId(DeviceState &state) {
- pid_t pid{};
+ constexpr KHandle threadSelf = 0xFFFF8000; // This is the handle used by threads to refer to themselves
auto handle = state.ctx->registers.w1;
- if (handle != constant::ThreadSelf)
+ pid_t pid{};
+
+ if (handle != threadSelf)
pid = state.process->GetHandle(handle)->pid;
else
pid = state.thread->pid;
+
state.logger->Debug("svcGetThreadId: Handle: 0x{:X}, PID: {}", handle, pid);
+
state.ctx->registers.x1 = static_cast(pid);
state.ctx->registers.w0 = constant::status::Success;
}
@@ -540,7 +566,11 @@ namespace skyline::kernel::svc {
auto id0 = state.ctx->registers.w1;
auto handle = state.ctx->registers.w2;
auto id1 = state.ctx->registers.x3;
+
+ constexpr auto totalPhysicalMemory = 0xF8000000; // ~4 GB of RAM
+
u64 out{};
+
switch (id0) {
case constant::infoState::AllowedCpuIdBitmask:
case constant::infoState::AllowedThreadPriorityMask:
@@ -548,57 +578,75 @@ namespace skyline::kernel::svc {
case constant::infoState::TitleId:
case constant::infoState::PrivilegedProcessId:
break;
+
case constant::infoState::AliasRegionBaseAddr:
out = state.os->memory.GetRegion(memory::Regions::Alias).address;
break;
+
case constant::infoState::AliasRegionSize:
out = state.os->memory.GetRegion(memory::Regions::Alias).size;
break;
+
case constant::infoState::HeapRegionBaseAddr:
out = state.os->memory.GetRegion(memory::Regions::Heap).address;
break;
+
case constant::infoState::HeapRegionSize:
out = state.os->memory.GetRegion(memory::Regions::Heap).size;
break;
+
case constant::infoState::TotalMemoryAvailable:
- out = constant::TotalPhyMem;
+ out = totalPhysicalMemory;
break;
+
case constant::infoState::TotalMemoryUsage:
out = state.process->heap->address + constant::DefStackSize + state.os->memory.GetProgramSize();
break;
+
case constant::infoState::AddressSpaceBaseAddr:
out = state.os->memory.GetRegion(memory::Regions::Base).address;
break;
+
case constant::infoState::AddressSpaceSize:
out = state.os->memory.GetRegion(memory::Regions::Base).size;
break;
+
case constant::infoState::StackRegionBaseAddr:
out = state.os->memory.GetRegion(memory::Regions::Stack).address;
break;
+
case constant::infoState::StackRegionSize:
out = state.os->memory.GetRegion(memory::Regions::Stack).size;
break;
+
case constant::infoState::PersonalMmHeapSize:
- out = constant::TotalPhyMem;
+ out = totalPhysicalMemory;
break;
+
case constant::infoState::PersonalMmHeapUsage:
out = state.process->heap->address + constant::DefStackSize;
break;
+
case constant::infoState::TotalMemoryAvailableWithoutMmHeap:
- out = constant::TotalPhyMem; // TODO: NPDM specifies SystemResourceSize, subtract that from this
+ out = totalPhysicalMemory; // TODO: NPDM specifies SystemResourceSize, subtract that from this
break;
+
case constant::infoState::TotalMemoryUsedWithoutMmHeap:
out = state.process->heap->size + constant::DefStackSize; // TODO: Same as above
break;
+
case constant::infoState::UserExceptionContextAddr:
out = state.process->tlsPages[0]->Get(0);
break;
+
default:
state.logger->Warn("svcGetInfo: Unimplemented case ID0: {}, ID1: {}", id0, id1);
state.ctx->registers.w0 = constant::status::Unimpl;
return;
}
+
state.logger->Debug("svcGetInfo: ID0: {}, ID1: {}, Out: 0x{:X}", id0, id1, out);
+
state.ctx->registers.x1 = out;
state.ctx->registers.w0 = constant::status::Success;
}
diff --git a/app/src/main/cpp/skyline/kernel/svc.h b/app/src/main/cpp/skyline/kernel/svc.h
index c5b1d9e0..f78ff39f 100644
--- a/app/src/main/cpp/skyline/kernel/svc.h
+++ b/app/src/main/cpp/skyline/kernel/svc.h
@@ -34,7 +34,8 @@ namespace skyline {
// 6.0.0+
constexpr u8 TotalMemoryAvailableWithoutMmHeap = 0x15;
constexpr u8 TotalMemoryUsedWithoutMmHeap = 0x16;
- };
+ }
+
namespace kernel::svc {
/**
* @brief Sets the process heap to a given Size. It can both extend and shrink the heap. (https://switchbrew.org/wiki/SVC#SetHeapSize)
diff --git a/app/src/main/cpp/skyline/kernel/types/KProcess.cpp b/app/src/main/cpp/skyline/kernel/types/KProcess.cpp
index 9599a400..c27b1534 100644
--- a/app/src/main/cpp/skyline/kernel/types/KProcess.cpp
+++ b/app/src/main/cpp/skyline/kernel/types/KProcess.cpp
@@ -38,23 +38,29 @@ namespace skyline::kernel::type {
} else {
address = (*(tlsPages.end() - 1))->address + PAGE_SIZE;
}
- auto tlsMem = NewHandle(address, PAGE_SIZE, memory::Permission(true, true, false), memory::MemoryStates::ThreadLocal).item;
+ auto tlsMem = NewHandle(address, PAGE_SIZE, memory::Permission(true, true, false), memory::states::ThreadLocal).item;
tlsPages.push_back(std::make_shared(tlsMem->address));
+
auto &tlsPage = tlsPages.back();
if (tlsPages.empty())
tlsPage->ReserveSlot(); // User-mode exception handling
+
return tlsPage->ReserveSlot();
}
void KProcess::InitializeMemory() {
- heap = NewHandle(state.os->memory.GetRegion(memory::Regions::Heap).address, constant::DefHeapSize, memory::Permission{true, true, false}, memory::MemoryStates::Heap).item;
+ constexpr size_t DefHeapSize = 0x200000; // The default amount of heap
+ heap = NewHandle(state.os->memory.GetRegion(memory::Regions::Heap).address, DefHeapSize, memory::Permission{true, true, false}, memory::states::Heap).item;
threads[pid]->tls = GetTlsSlot();
}
KProcess::KProcess(const DeviceState &state, pid_t pid, u64 entryPoint, std::shared_ptr &stack, std::shared_ptr &tlsMemory) : pid(pid), stack(stack), KSyncObject(state, KType::KProcess) {
- auto thread = NewHandle(pid, entryPoint, 0x0, stack->guest.address + stack->guest.size, 0, constant::DefaultPriority, this, tlsMemory).item;
+ constexpr auto DefaultPriority = 44; // The default priority of a process
+
+ auto thread = NewHandle(pid, entryPoint, 0x0, stack->guest.address + stack->guest.size, 0, DefaultPriority, this, tlsMemory).item;
threads[pid] = thread;
state.nce->WaitThreadInit(thread);
+
memFd = open(fmt::format("/proc/{}/mem", pid).c_str(), O_RDWR | O_CLOEXEC);
if (memFd == -1)
throw exception("Cannot open file descriptor to /proc/{}/mem, \"{}\"", pid, strerror(errno));
@@ -67,7 +73,7 @@ namespace skyline::kernel::type {
std::shared_ptr KProcess::CreateThread(u64 entryPoint, u64 entryArg, u64 stackTop, u8 priority) {
auto size = (sizeof(ThreadContext) + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1);
- auto tlsMem = std::make_shared(state, 0, size, memory::Permission{true, true, false}, memory::MemoryStates::Reserved);
+ auto tlsMem = std::make_shared(state, 0, size, memory::Permission{true, true, false}, memory::states::Reserved);
Registers fregs{};
fregs.x0 = CLONE_THREAD | CLONE_SIGHAND | CLONE_PTRACE | CLONE_FS | CLONE_VM | CLONE_FILES | CLONE_IO;
fregs.x1 = stackTop;
@@ -166,7 +172,7 @@ namespace skyline::kernel::type {
return std::nullopt;
}
- bool KProcess::MutexLock(u64 address, handle_t owner) {
+ bool KProcess::MutexLock(u64 address, KHandle owner) {
std::unique_lock lock(mutexLock);
auto mtx = GetPointer(address);
auto &mtxWaiters = mutexes[address];
diff --git a/app/src/main/cpp/skyline/kernel/types/KProcess.h b/app/src/main/cpp/skyline/kernel/types/KProcess.h
index dd6a789e..944221a5 100644
--- a/app/src/main/cpp/skyline/kernel/types/KProcess.h
+++ b/app/src/main/cpp/skyline/kernel/types/KProcess.h
@@ -9,372 +9,381 @@
#include
#include
-namespace skyline::kernel::type {
- /**
- * @brief The KProcess class is responsible for holding the state of a process
- */
- class KProcess : public KSyncObject {
- private:
+namespace skyline {
+ namespace constant {
+ constexpr auto TlsSlotSize = 0x200; //!< The size of a single TLS slot
+ constexpr auto TlsSlots = PAGE_SIZE / TlsSlotSize; //!< The amount of TLS slots in a single page
+ constexpr KHandle BaseHandleIndex = 0xD000; // The index of the base handle
+ constexpr u32 MtxOwnerMask = 0xBFFFFFFF; //!< The mask of values which contain the owner of a mutex
+ }
+
+ namespace kernel::type {
/**
- * @brief This class holds a single TLS page's status
- * @details tls_page_t holds the status of a single TLS page (A page is 4096 bytes on ARMv8).
- * Each TLS page has 8 slots, each 0x200 (512) bytes in size.
- * The first slot of the first page is reserved for user-mode exception handling.
- * Read more about TLS here: https://switchbrew.org/wiki/Thread_Local_Storage
- */
- struct TlsPage {
- u64 address; //!< The address of the page allocated for TLS
- u8 index = 0; //!< The slots are assigned sequentially, this holds the index of the last TLS slot reserved
- bool slot[constant::TlsSlots]{0}; //!< An array of booleans denoting which TLS slots are reserved
+ * @brief The KProcess class is responsible for holding the state of a process
+ */
+ class KProcess : public KSyncObject {
+ private:
+ /**
+ * @brief This class holds a single TLS page's status
+ * @details tls_page_t holds the status of a single TLS page (A page is 4096 bytes on ARMv8).
+ * Each TLS page has 8 slots, each 0x200 (512) bytes in size.
+ * The first slot of the first page is reserved for user-mode exception handling.
+ * Read more about TLS here: https://switchbrew.org/wiki/Thread_Local_Storage
+ */
+ struct TlsPage {
+ u64 address; //!< The address of the page allocated for TLS
+ u8 index = 0; //!< The slots are assigned sequentially, this holds the index of the last TLS slot reserved
+ bool slot[constant::TlsSlots]{0}; //!< An array of booleans denoting which TLS slots are reserved
+
+ /**
+ * @param address The address of the allocated page
+ */
+ TlsPage(u64 address);
+
+ /**
+ * @brief Reserves a single 0x200 byte TLS slot
+ * @return The address of the reserved slot
+ */
+ u64 ReserveSlot();
+
+ /**
+ * @brief Returns the address of a particular slot
+ * @param slotNo The number of the slot to be returned
+ * @return The address of the specified slot
+ */
+ u64 Get(u8 slotNo);
+
+ /**
+ * @brief Returns boolean on if the TLS page has free slots or not
+ * @return If the whole page is full or not
+ */
+ bool Full();
+ };
/**
- * @param address The address of the allocated page
- */
- TlsPage(u64 address);
+ * @brief Returns a TLS slot from an arbitrary TLS page
+ * @return The address of a free TLS slot
+ */
+ u64 GetTlsSlot();
/**
- * @brief Reserves a single 0x200 byte TLS slot
- * @return The address of the reserved slot
- */
- u64 ReserveSlot();
+ * @brief This initializes heap and the initial TLS page
+ */
+ void InitializeMemory();
+
+ public:
+ friend OS;
/**
- * @brief Returns the address of a particular slot
- * @param slotNo The number of the slot to be returned
- * @return The address of the specified slot
- */
- u64 Get(u8 slotNo);
+ * @brief This is used as the output for functions that return created kernel objects
+ * @tparam objectClass The class of the kernel object
+ */
+ template
+ struct HandleOut {
+ std::shared_ptr item; //!< A shared pointer to the object
+ KHandle handle; //!< The handle of the object in the process
+ };
/**
- * @brief Returns boolean on if the TLS page has free slots or not
- * @return If the whole page is full or not
- */
- bool Full();
- };
+ * @brief This enum is used to describe the current status of the process
+ */
+ enum class Status {
+ Created, //!< The process was created but the main thread has not started yet
+ Started, //!< The process has been started
+ Exiting //!< The process is exiting
+ } status = Status::Created; //!< The state of the process
- /**
- * @brief Returns a TLS slot from an arbitrary TLS page
- * @return The address of a free TLS slot
- */
- u64 GetTlsSlot();
+ /**
+ * @brief This is used to hold information about a single waiting thread for mutexes and conditional variables
+ */
+ struct WaitStatus {
+ std::atomic_bool flag{false}; //!< The underlying atomic flag of the thread
+ u8 priority; //!< The priority of the thread
+ KHandle handle; //!< The handle of the thread
+ u64 mutexAddress{}; //!< The address of the mutex
- /**
- * @brief This initializes heap and the initial TLS page
- */
- void InitializeMemory();
+ WaitStatus(u8 priority, KHandle handle) : priority(priority), handle(handle) {}
- public:
- friend OS;
+ WaitStatus(u8 priority, KHandle handle, u64 mutexAddress) : priority(priority), handle(handle), mutexAddress(mutexAddress) {}
+ };
- /**
- * @brief This is used as the output for functions that return created kernel objects
- * @tparam objectClass The class of the kernel object
- */
- template
- struct HandleOut {
- std::shared_ptr item; //!< A shared pointer to the object
- handle_t handle; //!< The handle of the object in the process
- };
+ KHandle handleIndex = constant::BaseHandleIndex; //!< This is used to keep track of what to map as an handle
+ pid_t pid; //!< The PID of the main thread
+ int memFd; //!< The file descriptor to the memory of the process
+ std::unordered_map> handles; //!< A mapping from a handle_t to it's corresponding KObject which is the actual underlying object
+ std::unordered_map> threads; //!< A mapping from a PID to it's corresponding KThread object
+ std::unordered_map>> mutexes; //!< A map from a mutex's address to a vector of Mutex objects for threads waiting on it
+ std::unordered_map>> conditionals; //!< A map from a conditional variable's address to a vector of threads waiting on it
+ std::vector> tlsPages; //!< A vector of all allocated TLS pages
+ std::shared_ptr stack; //!< The shared memory used to hold the stack of the main thread
+ std::shared_ptr heap; //!< The kernel memory object backing the allocated heap
+ Mutex mutexLock; //!< This mutex is to prevent concurrent mutex operations to happen at once
+ Mutex conditionalLock; //!< This mutex is to prevent concurrent conditional variable operations to happen at once
- /**
- * @brief This enum is used to describe the current status of the process
- */
- enum class Status {
- Created, //!< The process was created but the main thread has not started yet
- Started, //!< The process has been started
- Exiting //!< The process is exiting
- } status = Status::Created; //!< The state of the process
+ /**
+ * @brief Creates a KThread object for the main thread and opens the process's memory file
+ * @param state The state of the device
+ * @param pid The PID of the main thread
+ * @param entryPoint The address to start execution at
+ * @param stack The KSharedMemory object for Stack memory allocated by the guest process
+ * @param tlsMemory The KSharedMemory object for TLS memory allocated by the guest process
+ */
+ KProcess(const DeviceState &state, pid_t pid, u64 entryPoint, std::shared_ptr &stack, std::shared_ptr &tlsMemory);
- /**
- * @brief This is used to hold information about a single waiting thread for mutexes and conditional variables
- */
- struct WaitStatus {
- std::atomic_bool flag{false}; //!< The underlying atomic flag of the thread
- u8 priority; //!< The priority of the thread
- handle_t handle; //!< The handle of the thread
- u64 mutexAddress{}; //!< The address of the mutex
+ /**
+ * Close the file descriptor to the process's memory
+ */
+ ~KProcess();
- WaitStatus(u8 priority, handle_t handle) : priority(priority), handle(handle) {}
+ /**
+ * @brief Create a thread in this process
+ * @param entryPoint The address of the initial function
+ * @param entryArg An argument to the function
+ * @param stackTop The top of the stack
+ * @param priority The priority of the thread
+ * @return An instance of KThread class for the corresponding thread
+ */
+ std::shared_ptr CreateThread(u64 entryPoint, u64 entryArg, u64 stackTop, u8 priority);
- WaitStatus(u8 priority, handle_t handle, u64 mutexAddress) : priority(priority), handle(handle), mutexAddress(mutexAddress) {}
- };
+ /**
+ * @brief This returns the host address for a specific address in guest memory
+ * @param address The corresponding guest address
+ * @return The corresponding host address
+ */
+ u64 GetHostAddress(const u64 address) const;
- handle_t handleIndex = constant::BaseHandleIndex; //!< This is used to keep track of what to map as an handle
- pid_t pid; //!< The PID of the main thread
- int memFd; //!< The file descriptor to the memory of the process
- std::unordered_map> handles; //!< A mapping from a handle_t to it's corresponding KObject which is the actual underlying object
- std::unordered_map> threads; //!< A mapping from a PID to it's corresponding KThread object
- std::unordered_map>> mutexes; //!< A map from a mutex's address to a vector of Mutex objects for threads waiting on it
- std::unordered_map>> conditionals; //!< A map from a conditional variable's address to a vector of threads waiting on it
- std::vector> tlsPages; //!< A vector of all allocated TLS pages
- std::shared_ptr stack; //!< The shared memory used to hold the stack of the main thread
- std::shared_ptr heap; //!< The kernel memory object backing the allocated heap
- Mutex mutexLock; //!< This mutex is to prevent concurrent mutex operations to happen at once
- Mutex conditionalLock; //!< This mutex is to prevent concurrent conditional variable operations to happen at once
-
- /**
- * @brief Creates a KThread object for the main thread and opens the process's memory file
- * @param state The state of the device
- * @param pid The PID of the main thread
- * @param entryPoint The address to start execution at
- * @param stack The KSharedMemory object for Stack memory allocated by the guest process
- * @param tlsMemory The KSharedMemory object for TLS memory allocated by the guest process
- */
- KProcess(const DeviceState &state, pid_t pid, u64 entryPoint, std::shared_ptr &stack, std::shared_ptr &tlsMemory);
-
- /**
- * Close the file descriptor to the process's memory
- */
- ~KProcess();
-
- /**
- * @brief Create a thread in this process
- * @param entryPoint The address of the initial function
- * @param entryArg An argument to the function
- * @param stackTop The top of the stack
- * @param priority The priority of the thread
- * @return An instance of KThread class for the corresponding thread
- */
- std::shared_ptr CreateThread(u64 entryPoint, u64 entryArg, u64 stackTop, u8 priority);
-
- /**
- * @brief This returns the host address for a specific address in guest memory
- * @param address The corresponding guest address
- * @return The corresponding host address
- */
- u64 GetHostAddress(const u64 address) const;
-
- /**
- * @tparam Type The type of the pointer to return
- * @param address The address on the guest
- * @return A pointer corresponding to a certain address on the guest
- * @note This can return a nullptr if the address is invalid
- */
- template
- inline Type *GetPointer(const u64 address) const {
- return reinterpret_cast(GetHostAddress(address));
- }
-
- /**
- * @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
- inline Type &GetReference(u64 address) const {
- auto source = GetPointer(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
- inline Type GetObject(u64 address) const {
- auto source = GetPointer(address);
- if (source) {
- return *source;
- } else {
- Type item{};
- ReadMemory(&item, address, sizeof(Type));
- return item;
+ /**
+ * @tparam Type The type of the pointer to return
+ * @param address The address on the guest
+ * @return A pointer corresponding to a certain address on the guest
+ * @note This can return a nullptr if the address is invalid
+ */
+ template
+ inline Type *GetPointer(const u64 address) const {
+ return reinterpret_cast(GetHostAddress(address));
}
- }
- /**
- * @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(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
- inline void WriteMemory(Type &item, u64 address) const {
- auto destination = GetPointer(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
- inline void WriteMemory(const Type &item, u64 address) const {
- auto destination = GetPointer(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
- * @param forceGuest This flag forces the write to be performed in guest address space
- */
- void ReadMemory(void *destination, const u64 offset, const size_t size, const bool forceGuest = false) const;
-
- /**
- * @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
- * @param forceGuest This flag forces the write to be performed in guest address space
- */
- void WriteMemory(void *source, const u64 offset, const size_t size, const bool forceGuest = false) const;
-
- /**
- * @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
- */
- void CopyMemory(const u64 source, const u64 destination, const size_t size) const;
-
- /**
- * @brief Creates a new handle to a KObject and adds it to the process handle_table
- * @tparam objectClass The class of the kernel object to create
- * @param args The arguments for the kernel object except handle, pid and state
- * @return A shared pointer to the corresponding object
- */
- template
- HandleOut NewHandle(objectArgs... args) {
- std::shared_ptr item;
- if constexpr (std::is_same())
- item = std::make_shared(state, handleIndex, args...);
- else
- item = std::make_shared(state, args...);
- handles[handleIndex] = std::static_pointer_cast(item);
- return {item, handleIndex++};
- }
-
- /**
- * @brief Inserts an item into the process handle table
- * @param item The item to insert
- * @return The handle of the corresponding item in the handle table
- */
- template
- handle_t InsertItem(std::shared_ptr &item) {
- handles[handleIndex] = std::static_pointer_cast(item);
- return handleIndex++;
- }
-
- /**
- * @brief Returns the underlying kernel object for a handle
- * @tparam objectClass The class of the kernel object present in the handle
- * @param handle The handle of the object
- * @return A shared pointer to the object
- */
- template
- std::shared_ptr GetHandle(handle_t handle) {
- KType objectType;
- if constexpr(std::is_same())
- objectType = KType::KThread;
- else if constexpr(std::is_same())
- objectType = KType::KProcess;
- else if constexpr(std::is_same())
- objectType = KType::KSharedMemory;
- else if constexpr(std::is_same())
- objectType = KType::KTransferMemory;
- else if constexpr(std::is_same())
- objectType = KType::KPrivateMemory;
- else if constexpr(std::is_same())
- objectType = KType::KSession;
- else if constexpr(std::is_same())
- objectType = KType::KEvent;
- else
- throw exception("KProcess::GetHandle couldn't determine object type");
- try {
- auto item = handles.at(handle);
- if (item->objectType == objectType)
- return std::static_pointer_cast(item);
+ /**
+ * @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
+ inline Type &GetReference(u64 address) const {
+ auto source = GetPointer(address);
+ if (source)
+ return *source;
else
- throw exception("Tried to get kernel object (0x{:X}) with different type: {} when object is {}", handle, objectType, item->objectType);
- } catch (std::out_of_range) {
- throw exception("GetHandle was called with invalid handle: 0x{:X}", handle);
+ throw exception("Cannot retrieve reference to object not in shared guest memory");
}
- }
- /**
- * @brief Retrieves a kernel memory object that owns the specified address
- * @param address The address to look for
- * @return A shared pointer to the corresponding KMemory object
- */
- std::optional> GetMemoryObject(u64 address);
+ /**
+ * @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
+ inline Type GetObject(u64 address) const {
+ auto source = GetPointer(address);
+ if (source) {
+ return *source;
+ } else {
+ Type item{};
+ ReadMemory(&item, address, sizeof(Type));
+ return item;
+ }
+ }
- /**
- * @brief This deletes a certain handle from the handle table
- * @param handle The handle to delete
- */
- inline void DeleteHandle(handle_t handle) {
- handles.erase(handle);
- }
+ /**
+ * @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(address);
+ if (source)
+ return std::string(source, maxSize);
+ std::string debug(maxSize, '\0');
+ ReadMemory(debug.data(), address, maxSize);
+ return debug;
+ }
- /**
- * @brief This locks the Mutex at the specified address
- * @param address The address of the mutex
- * @param owner The handle of the current mutex owner
- * @return If the mutex was successfully locked
- */
- bool MutexLock(u64 address, handle_t owner);
+ /**
+ * @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
+ inline void WriteMemory(Type &item, u64 address) const {
+ auto destination = GetPointer(address);
+ if (destination) {
+ *destination = item;
+ } else {
+ WriteMemory(&item, address, sizeof(Type));
+ }
+ }
- /**
- * @brief This unlocks the Mutex at the specified address
- * @param address The address of the mutex
- * @return If the mutex was successfully unlocked
- */
- bool MutexUnlock(u64 address);
+ /**
+ * @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
+ inline void WriteMemory(const Type &item, u64 address) const {
+ auto destination = GetPointer(address);
+ if (destination) {
+ *destination = item;
+ } else {
+ WriteMemory(&item, address, sizeof(Type));
+ }
+ }
- /**
- * @param conditionalAddress The address of the conditional variable
- * @param mutexAddress The address of the mutex
- * @param timeout The amount of time to wait for the conditional variable
- * @return If the conditional variable was successfully waited for or timed out
- */
- bool ConditionalVariableWait(u64 conditionalAddress, u64 mutexAddress, u64 timeout);
+ /**
+ * @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
+ * @param forceGuest This flag forces the write to be performed in guest address space
+ */
+ void ReadMemory(void *destination, const u64 offset, const size_t size, const bool forceGuest = false) const;
- /**
- * @brief This signals a number of conditional variable waiters
- * @param address The address of the conditional variable
- * @param amount The amount of waiters to signal
- */
- void ConditionalVariableSignal(u64 address, u64 amount);
+ /**
+ * @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
+ * @param forceGuest This flag forces the write to be performed in guest address space
+ */
+ void WriteMemory(void *source, const u64 offset, const size_t size, const bool forceGuest = false) const;
- /**
- * @brief This resets the object to an unsignalled state
- */
- inline void ResetSignal() {
- signalled = false;
- }
- };
+ /**
+ * @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
+ */
+ void CopyMemory(const u64 source, const u64 destination, const size_t size) const;
+
+ /**
+ * @brief Creates a new handle to a KObject and adds it to the process handle_table
+ * @tparam objectClass The class of the kernel object to create
+ * @param args The arguments for the kernel object except handle, pid and state
+ * @return A shared pointer to the corresponding object
+ */
+ template
+ HandleOut NewHandle(objectArgs... args) {
+ std::shared_ptr item;
+ if constexpr (std::is_same())
+ item = std::make_shared(state, handleIndex, args...);
+ else
+ item = std::make_shared(state, args...);
+ handles[handleIndex] = std::static_pointer_cast(item);
+ return {item, handleIndex++};
+ }
+
+ /**
+ * @brief Inserts an item into the process handle table
+ * @param item The item to insert
+ * @return The handle of the corresponding item in the handle table
+ */
+ template
+ KHandle InsertItem(std::shared_ptr &item) {
+ handles[handleIndex] = std::static_pointer_cast(item);
+ return handleIndex++;
+ }
+
+ /**
+ * @brief Returns the underlying kernel object for a handle
+ * @tparam objectClass The class of the kernel object present in the handle
+ * @param handle The handle of the object
+ * @return A shared pointer to the object
+ */
+ template
+ std::shared_ptr GetHandle(KHandle handle) {
+ KType objectType;
+ if constexpr(std::is_same())
+ objectType = KType::KThread;
+ else if constexpr(std::is_same())
+ objectType = KType::KProcess;
+ else if constexpr(std::is_same())
+ objectType = KType::KSharedMemory;
+ else if constexpr(std::is_same())
+ objectType = KType::KTransferMemory;
+ else if constexpr(std::is_same())
+ objectType = KType::KPrivateMemory;
+ else if constexpr(std::is_same())
+ objectType = KType::KSession;
+ else if constexpr(std::is_same())
+ objectType = KType::KEvent;
+ else
+ throw exception("KProcess::GetHandle couldn't determine object type");
+ try {
+ auto item = handles.at(handle);
+ if (item->objectType == objectType)
+ return std::static_pointer_cast(item);
+ else
+ throw exception("Tried to get kernel object (0x{:X}) with different type: {} when object is {}", handle, objectType, item->objectType);
+ } catch (std::out_of_range) {
+ throw exception("GetHandle was called with invalid handle: 0x{:X}", handle);
+ }
+ }
+
+ /**
+ * @brief Retrieves a kernel memory object that owns the specified address
+ * @param address The address to look for
+ * @return A shared pointer to the corresponding KMemory object
+ */
+ std::optional> GetMemoryObject(u64 address);
+
+ /**
+ * @brief This deletes a certain handle from the handle table
+ * @param handle The handle to delete
+ */
+ inline void DeleteHandle(KHandle handle) {
+ handles.erase(handle);
+ }
+
+ /**
+ * @brief This locks the Mutex at the specified address
+ * @param address The address of the mutex
+ * @param owner The handle of the current mutex owner
+ * @return If the mutex was successfully locked
+ */
+ bool MutexLock(u64 address, KHandle owner);
+
+ /**
+ * @brief This unlocks the Mutex at the specified address
+ * @param address The address of the mutex
+ * @return If the mutex was successfully unlocked
+ */
+ bool MutexUnlock(u64 address);
+
+ /**
+ * @param conditionalAddress The address of the conditional variable
+ * @param mutexAddress The address of the mutex
+ * @param timeout The amount of time to wait for the conditional variable
+ * @return If the conditional variable was successfully waited for or timed out
+ */
+ bool ConditionalVariableWait(u64 conditionalAddress, u64 mutexAddress, u64 timeout);
+
+ /**
+ * @brief This signals a number of conditional variable waiters
+ * @param address The address of the conditional variable
+ * @param amount The amount of waiters to signal
+ */
+ void ConditionalVariableSignal(u64 address, u64 amount);
+
+ /**
+ * @brief This resets the object to an unsignalled state
+ */
+ inline void ResetSignal() {
+ signalled = false;
+ }
+ };
+ }
}
diff --git a/app/src/main/cpp/skyline/kernel/types/KSession.h b/app/src/main/cpp/skyline/kernel/types/KSession.h
index 4b1442af..3e386905 100644
--- a/app/src/main/cpp/skyline/kernel/types/KSession.h
+++ b/app/src/main/cpp/skyline/kernel/types/KSession.h
@@ -11,8 +11,8 @@ namespace skyline::kernel::type {
class KSession : public KSyncObject {
public:
const std::shared_ptr serviceObject; //!< A shared pointer to the service class
- std::unordered_map> domainTable; //!< This maps from a virtual handle to it's service
- handle_t handleIndex = constant::BaseVirtualHandleIndex;
+ std::unordered_map> domainTable; //!< This maps from a virtual handle to it's service
+ KHandle handleIndex{0x1}; //!< The currently allocated handle index
const service::Service serviceType; //!< The type of the service
enum class ServiceStatus { Open, Closed } serviceStatus{ServiceStatus::Open}; //!< If the session is open or closed
bool isDomain{}; //!< Holds if this is a domain session or not
@@ -27,7 +27,7 @@ namespace skyline::kernel::type {
* This converts this session into a domain session (https://switchbrew.org/wiki/IPC_Marshalling#Domains)
* @return The virtual handle of this service in the domain
*/
- handle_t ConvertDomain() {
+ KHandle ConvertDomain() {
isDomain = true;
domainTable[handleIndex] = serviceObject;
return handleIndex++;
diff --git a/app/src/main/cpp/skyline/kernel/types/KSharedMemory.cpp b/app/src/main/cpp/skyline/kernel/types/KSharedMemory.cpp
index 286ad94c..888ec1fe 100644
--- a/app/src/main/cpp/skyline/kernel/types/KSharedMemory.cpp
+++ b/app/src/main/cpp/skyline/kernel/types/KSharedMemory.cpp
@@ -50,7 +50,7 @@ namespace skyline::kernel::type {
}
void KSharedMemory::Resize(size_t size) {
- if (guest.valid() && kernel.valid()) {
+ if (guest.Valid() && kernel.Valid()) {
if (close(fd) < 0)
throw exception("An error occurred while trying to close shared memory FD: {}", strerror(errno));
fd = ASharedMemory_create("KSharedMemory", size);
@@ -98,7 +98,7 @@ namespace skyline::kernel::type {
throw exception("An occurred while mapping shared memory: {}", strerror(errno));
guest.size = size;
MemoryManager::ResizeChunk(chunk, size);
- } else if (kernel.valid()) {
+ } else if (kernel.Valid()) {
if (close(fd) < 0)
throw exception("An error occurred while trying to close shared memory FD: {}", strerror(errno));
fd = ASharedMemory_create("KSharedMemory", size);
@@ -119,7 +119,7 @@ namespace skyline::kernel::type {
}
void KSharedMemory::UpdatePermission(u64 address, u64 size, memory::Permission permission, bool host) {
- if (guest.valid() && !host) {
+ if (guest.Valid() && !host) {
Registers fregs{
.x0 = address,
.x1 = size,
@@ -137,7 +137,7 @@ namespace skyline::kernel::type {
};
MemoryManager::InsertBlock(chunk, block);
}
- if (kernel.valid() && host) {
+ if (kernel.Valid() && host) {
if (mprotect(reinterpret_cast(kernel.address), kernel.size, permission.Get()) == reinterpret_cast(MAP_FAILED))
throw exception("An error occurred while remapping shared memory: {}", strerror(errno));
kernel.permission = permission;
@@ -146,7 +146,7 @@ namespace skyline::kernel::type {
KSharedMemory::~KSharedMemory() {
try {
- if (guest.valid() && state.process) {
+ if (guest.Valid() && state.process) {
Registers fregs{
.x0 = guest.address,
.x1 = guest.size,
@@ -156,7 +156,7 @@ namespace skyline::kernel::type {
}
} catch (const std::exception &) {
}
- if (kernel.valid())
+ if (kernel.Valid())
munmap(reinterpret_cast(kernel.address), kernel.size);
state.os->memory.DeleteChunk(guest.address);
close(fd);
diff --git a/app/src/main/cpp/skyline/kernel/types/KSharedMemory.h b/app/src/main/cpp/skyline/kernel/types/KSharedMemory.h
index 8dffee25..9fc19d4d 100644
--- a/app/src/main/cpp/skyline/kernel/types/KSharedMemory.h
+++ b/app/src/main/cpp/skyline/kernel/types/KSharedMemory.h
@@ -24,7 +24,7 @@ namespace skyline::kernel::type {
* @brief Returns if the object is valid
* @return If the MapInfo object is valid
*/
- inline bool valid() { return address && size && permission.Get(); }
+ inline bool Valid() { return address && size && permission.Get(); }
} kernel, guest;
/**
@@ -35,7 +35,7 @@ namespace skyline::kernel::type {
* @param memState The MemoryState of the chunk of memory
* @param mmapFlags Additional flags to pass to mmap
*/
- KSharedMemory(const DeviceState &state, u64 address, size_t size, const memory::Permission permission, memory::MemoryState memState = memory::MemoryStates::SharedMemory, int mmapFlags = 0);
+ KSharedMemory(const DeviceState &state, u64 address, size_t size, const memory::Permission permission, memory::MemoryState memState = memory::states::SharedMemory, int mmapFlags = 0);
/**
* @brief Maps the shared memory in the guest
diff --git a/app/src/main/cpp/skyline/kernel/types/KThread.cpp b/app/src/main/cpp/skyline/kernel/types/KThread.cpp
index dc1d6783..ccac06c1 100644
--- a/app/src/main/cpp/skyline/kernel/types/KThread.cpp
+++ b/app/src/main/cpp/skyline/kernel/types/KThread.cpp
@@ -4,8 +4,7 @@
#include
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 &tlsMemory) : handle(handle), pid(self_pid), entryPoint(entryPoint), entryArg(entryArg), stackTop(stackTop), tls(tls), priority(priority), parent(parent), ctxMemory(tlsMemory), KSyncObject(state,
- KType::KThread) {
+ KThread::KThread(const DeviceState &state, KHandle handle, pid_t selfPid, u64 entryPoint, u64 entryArg, u64 stackTop, u64 tls, u8 priority, KProcess *parent, std::shared_ptr &tlsMemory) : handle(handle), pid(selfPid), entryPoint(entryPoint), entryArg(entryArg), stackTop(stackTop), tls(tls), priority(priority), parent(parent), ctxMemory(tlsMemory), KSyncObject(state, KType::KThread) {
UpdatePriority(priority);
}
@@ -31,8 +30,9 @@ namespace skyline::kernel::type {
void KThread::UpdatePriority(u8 priority) {
this->priority = priority;
- auto liPriority = static_cast(constant::PriorityAn.first + ((static_cast(constant::PriorityAn.second - constant::PriorityAn.first) / static_cast(constant::PriorityNin.second - constant::PriorityNin.first)) * (static_cast(priority) - constant::PriorityNin.first))); // Resize range PriorityNin (Nintendo Priority) to PriorityAn (Android Priority)
- if (setpriority(PRIO_PROCESS, static_cast(pid), liPriority) == -1)
- throw exception("Couldn't set process priority to {} for PID: {}", liPriority, pid);
+ auto linuxPriority = static_cast(constant::AndroidPriority.first + ((static_cast(constant::AndroidPriority.second - constant::AndroidPriority.first) / static_cast(constant::SwitchPriority.second - constant::SwitchPriority.first)) * (static_cast(priority) - constant::SwitchPriority.first))); // Resize range SwitchPriority (Nintendo Priority) to AndroidPriority (Android Priority)
+
+ if (setpriority(PRIO_PROCESS, static_cast(pid), linuxPriority) == -1)
+ throw exception("Couldn't set process priority to {} for PID: {}", linuxPriority, pid);
}
}
diff --git a/app/src/main/cpp/skyline/kernel/types/KThread.h b/app/src/main/cpp/skyline/kernel/types/KThread.h
index 09b4d9ae..1c80ff9b 100644
--- a/app/src/main/cpp/skyline/kernel/types/KThread.h
+++ b/app/src/main/cpp/skyline/kernel/types/KThread.h
@@ -21,7 +21,7 @@ namespace skyline::kernel::type {
} status = Status::Created; //!< The state of the thread
std::atomic cancelSync{false}; //!< This is to flag to a thread to cancel a synchronization call it currently is in
std::shared_ptr 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
+ KHandle 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])
u64 stackTop; //!< The top of the stack (Where it starts growing downwards from)
u64 tls; //!< The address of TLS (Thread Local Storage) slot assigned to the current thread
@@ -30,7 +30,7 @@ namespace skyline::kernel::type {
/**
* @param state The state of the device
* @param handle The handle of the current thread
- * @param self_pid The PID of this thread
+ * @param selfPid The PID of this thread
* @param entryPoint The address to start execution at
* @param entryArg An argument to pass to the process on entry
* @param stackTop The top of the stack
@@ -39,7 +39,7 @@ namespace skyline::kernel::type {
* @param parent The parent process of this thread
* @param tlsMemory The KSharedMemory object for TLS memory allocated by the guest process
*/
- 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 &tlsMemory);
+ KThread(const DeviceState &state, KHandle handle, pid_t selfPid, u64 entryPoint, u64 entryArg, u64 stackTop, u64 tls, u8 priority, KProcess *parent, std::shared_ptr &tlsMemory);
/**
* @brief Kills the thread and deallocates the memory allocated for stack.
diff --git a/app/src/main/cpp/skyline/kernel/types/KTransferMemory.h b/app/src/main/cpp/skyline/kernel/types/KTransferMemory.h
index 4f1ddb56..2e59ac51 100644
--- a/app/src/main/cpp/skyline/kernel/types/KTransferMemory.h
+++ b/app/src/main/cpp/skyline/kernel/types/KTransferMemory.h
@@ -23,7 +23,7 @@ namespace skyline::kernel::type {
* @param type The type of the memory
* @param memState The MemoryState of the chunk of memory
*/
- KTransferMemory(const DeviceState &state, bool host, u64 address, size_t size, const memory::Permission permission, memory::MemoryState memState = memory::MemoryStates::TransferMemory);
+ KTransferMemory(const DeviceState &state, bool host, u64 address, size_t size, const memory::Permission permission, memory::MemoryState memState = memory::states::TransferMemory);
/**
* @brief Transfers this piece of memory to another process
diff --git a/app/src/main/cpp/skyline/loader/nro.cpp b/app/src/main/cpp/skyline/loader/nro.cpp
index 8a3fa874..883648c2 100644
--- a/app/src/main/cpp/skyline/loader/nro.cpp
+++ b/app/src/main/cpp/skyline/loader/nro.cpp
@@ -5,7 +5,10 @@
namespace skyline::loader {
NroLoader::NroLoader(const int romFd) : Loader(romFd) {
ReadOffset((u32 *) &header, 0x0, sizeof(NroHeader));
- if (header.magic != constant::NroMagic)
+
+ constexpr auto nroMagic = 0x304F524E; // "NRO0" in reverse, this is written at the start of every NRO file
+
+ if (header.magic != nroMagic)
throw exception("Invalid NRO magic! 0x{0:X}", header.magic);
}
@@ -26,19 +29,19 @@ namespace skyline::loader {
u64 patchSize = patch.size() * sizeof(u32);
u64 padding = utils::AlignUp(textSize + rodataSize + dataSize + header.bssSize + patchSize, PAGE_SIZE) - (textSize + rodataSize + dataSize + header.bssSize + patchSize);
- process->NewHandle(constant::BaseAddress, textSize, memory::Permission{true, true, true}, memory::MemoryStates::CodeStatic); // R-X
+ process->NewHandle(constant::BaseAddress, textSize, memory::Permission{true, true, true}, memory::states::CodeStatic); // R-X
state.logger->Debug("Successfully mapped section .text @ 0x{0:X}, Size = 0x{1:X}", constant::BaseAddress, textSize);
- process->NewHandle(constant::BaseAddress + textSize, rodataSize, memory::Permission{true, false, false}, memory::MemoryStates::CodeReadOnly); // R--
+ process->NewHandle(constant::BaseAddress + textSize, rodataSize, memory::Permission{true, false, false}, memory::states::CodeReadOnly); // R--
state.logger->Debug("Successfully mapped section .ro @ 0x{0:X}, Size = 0x{1:X}", constant::BaseAddress + textSize, rodataSize);
- process->NewHandle(constant::BaseAddress + textSize + rodataSize, dataSize, memory::Permission{true, true, false}, memory::MemoryStates::CodeStatic); // RW-
+ process->NewHandle(constant::BaseAddress + textSize + rodataSize, dataSize, memory::Permission{true, true, false}, memory::states::CodeStatic); // RW-
state.logger->Debug("Successfully mapped section .data @ 0x{0:X}, Size = 0x{1:X}", constant::BaseAddress + textSize + rodataSize, dataSize);
- process->NewHandle(constant::BaseAddress + textSize + rodataSize + dataSize, header.bssSize, memory::Permission{true, true, true}, memory::MemoryStates::CodeMutable); // RWX
+ process->NewHandle(constant::BaseAddress + textSize + rodataSize + dataSize, header.bssSize, memory::Permission{true, true, true}, memory::states::CodeMutable); // RWX
state.logger->Debug("Successfully mapped section .bss @ 0x{0:X}, Size = 0x{1:X}", constant::BaseAddress + textSize + rodataSize + dataSize, header.bssSize);
- process->NewHandle(constant::BaseAddress + textSize + rodataSize + dataSize + header.bssSize, patchSize + padding, memory::Permission{true, true, true}, memory::MemoryStates::CodeStatic); // RWX
+ process->NewHandle(constant::BaseAddress + textSize + rodataSize + dataSize + header.bssSize, patchSize + padding, memory::Permission{true, true, true}, memory::states::CodeStatic); // RWX
state.logger->Debug("Successfully mapped section .patch @ 0x{0:X}, Size = 0x{1:X}", constant::BaseAddress + textSize + rodataSize + dataSize + header.bssSize, patchSize);
process->WriteMemory(text.data(), constant::BaseAddress, textSize);
diff --git a/app/src/main/cpp/skyline/nce.cpp b/app/src/main/cpp/skyline/nce.cpp
index 72745346..f5bbcdd8 100644
--- a/app/src/main/cpp/skyline/nce.cpp
+++ b/app/src/main/cpp/skyline/nce.cpp
@@ -189,7 +189,9 @@ namespace skyline {
if (ctx->sp)
regStr += fmt::format("\nStack Pointer: 0x{:X}", ctx->sp);
- for (u16 index = 0; index < constant::NumRegs - 1; index += 2) {
+ constexpr auto numRegisters = 31; //!< The amount of general-purpose registers in ARMv8
+
+ for (u16 index = 0; index < numRegisters - 2; index += 2) {
auto xStr = index < 10 ? " X" : "X";
regStr += fmt::format("\n{}{}: 0x{:<16X} {}{}: 0x{:X}", xStr, index, ctx->registers.regs[index], xStr, index + 1, ctx->registers.regs[index + 1]);
}
@@ -204,20 +206,26 @@ namespace skyline {
}
std::vector NCE::PatchCode(std::vector &code, u64 baseAddress, i64 offset) {
+ constexpr auto TpidrroEl0 = 0x5E83; // ID of TPIDRRO_EL0 in MRS
+ constexpr auto CntfrqEl0 = 0x5F00; // ID of CNTFRQ_EL0 in MRS
+ constexpr auto CntpctEl0 = 0x5F01; // ID of CNTPCT_EL0 in MRS
+ constexpr auto CntvctEl0 = 0x5F02; // ID of CNTVCT_EL0 in MRS
+ constexpr auto TegraX1Freq = 19200000; // The clock frequency of the Tegra X1 (19.2 MHz)
+
u32 *start = reinterpret_cast(code.data());
u32 *end = start + (code.size() / sizeof(u32));
i64 patchOffset = offset;
- std::vector patch((guest::saveCtxSize + guest::loadCtxSize + guest::svcHandlerSize) / sizeof(u32));
+ std::vector patch((guest::SaveCtxSize + guest::LoadCtxSize + guest::SvcHandlerSize) / sizeof(u32));
- std::memcpy(patch.data(), reinterpret_cast(&guest::SaveCtx), guest::saveCtxSize);
- offset += guest::saveCtxSize;
+ std::memcpy(patch.data(), reinterpret_cast(&guest::SaveCtx), guest::SaveCtxSize);
+ offset += guest::SaveCtxSize;
- std::memcpy(reinterpret_cast(patch.data()) + guest::saveCtxSize, reinterpret_cast(&guest::LoadCtx), guest::loadCtxSize);
- offset += guest::loadCtxSize;
+ std::memcpy(reinterpret_cast(patch.data()) + guest::SaveCtxSize, reinterpret_cast(&guest::LoadCtx), guest::LoadCtxSize);
+ offset += guest::LoadCtxSize;
- std::memcpy(reinterpret_cast(patch.data()) + guest::saveCtxSize + guest::loadCtxSize, reinterpret_cast(&guest::SvcHandler), guest::svcHandlerSize);
- offset += guest::svcHandlerSize;
+ std::memcpy(reinterpret_cast(patch.data()) + guest::SaveCtxSize + guest::LoadCtxSize, reinterpret_cast(&guest::SvcHandler), guest::SvcHandlerSize);
+ offset += guest::SvcHandlerSize;
static u64 frequency{};
if (!frequency)
@@ -238,10 +246,10 @@ namespace skyline {
offset += sizeof(u32) * movPc.size();
instr::Movz movCmd(regs::W1, static_cast(instrSvc->value));
offset += sizeof(movCmd);
- instr::BL bSvcHandler((patchOffset + guest::saveCtxSize + guest::loadCtxSize) - offset);
+ instr::BL bSvcHandler((patchOffset + guest::SaveCtxSize + guest::LoadCtxSize) - offset);
offset += sizeof(bSvcHandler);
- instr::BL bLdCtx((patchOffset + guest::saveCtxSize) - offset);
+ instr::BL bLdCtx((patchOffset + guest::SaveCtxSize) - offset);
offset += sizeof(bLdCtx);
constexpr u32 ldrLr = 0xF84107FE; // LDR LR, [SP], #16
offset += sizeof(ldrLr);
@@ -259,7 +267,7 @@ namespace skyline {
patch.push_back(ldrLr);
patch.push_back(bret.raw);
} else if (instrMrs->Verify()) {
- if (instrMrs->srcReg == constant::TpidrroEl0) {
+ if (instrMrs->srcReg == TpidrroEl0) {
instr::B bJunc(offset);
u32 strX0{};
if (instrMrs->destReg != regs::X0) {
@@ -291,10 +299,10 @@ namespace skyline {
if (ldrX0)
patch.push_back(ldrX0);
patch.push_back(bret.raw);
- } else if (frequency != constant::TegraX1Freq) {
- if (instrMrs->srcReg == constant::CntpctEl0) {
+ } else if (frequency != TegraX1Freq) {
+ if (instrMrs->srcReg == CntpctEl0) {
instr::B bJunc(offset);
- offset += guest::rescaleClockSize;
+ offset += guest::RescaleClockSize;
instr::Ldr ldr(0xF94003E0); // LDR XOUT, [SP]
ldr.destReg = instrMrs->destReg;
offset += sizeof(ldr);
@@ -305,14 +313,14 @@ namespace skyline {
*address = bJunc.raw;
auto size = patch.size();
- patch.resize(size + (guest::rescaleClockSize / sizeof(u32)));
- std::memcpy(patch.data() + size, reinterpret_cast(&guest::RescaleClock), guest::rescaleClockSize);
+ patch.resize(size + (guest::RescaleClockSize / sizeof(u32)));
+ std::memcpy(patch.data() + size, reinterpret_cast(&guest::RescaleClock), guest::RescaleClockSize);
patch.push_back(ldr.raw);
patch.push_back(addSp);
patch.push_back(bret.raw);
- } else if (instrMrs->srcReg == constant::CntfrqEl0) {
+ } else if (instrMrs->srcReg == CntfrqEl0) {
instr::B bJunc(offset);
- auto movFreq = instr::MoveU32Reg(static_cast(instrMrs->destReg), constant::TegraX1Freq);
+ auto movFreq = instr::MoveU32Reg(static_cast(instrMrs->destReg), TegraX1Freq);
offset += sizeof(u32) * movFreq.size();
instr::B bret(-offset + sizeof(u32));
offset += sizeof(bret);
@@ -323,8 +331,8 @@ namespace skyline {
patch.push_back(bret.raw);
}
} else {
- if (instrMrs->srcReg == constant::CntpctEl0) {
- instr::Mrs mrs(constant::CntvctEl0, regs::X(instrMrs->destReg));
+ if (instrMrs->srcReg == CntpctEl0) {
+ instr::Mrs mrs(CntvctEl0, regs::X(instrMrs->destReg));
*address = mrs.raw;
}
}
diff --git a/app/src/main/cpp/skyline/nce/guest.h b/app/src/main/cpp/skyline/nce/guest.h
index 9cfce6e7..32e400e5 100644
--- a/app/src/main/cpp/skyline/nce/guest.h
+++ b/app/src/main/cpp/skyline/nce/guest.h
@@ -2,13 +2,13 @@
namespace skyline {
namespace guest {
- constexpr size_t saveCtxSize = 20 * sizeof(u32); //!< The size of the SaveCtx function in 32-bit ARMv8 instructions
- constexpr size_t loadCtxSize = 20 * sizeof(u32); //!< The size of the LoadCtx function in 32-bit ARMv8 instructions
- constexpr size_t rescaleClockSize = 16 * sizeof(u32); //!< The size of the RescaleClock function in 32-bit ARMv8 instructions
+ constexpr size_t SaveCtxSize = 20 * sizeof(u32); //!< The size of the SaveCtx function in 32-bit ARMv8 instructions
+ constexpr size_t LoadCtxSize = 20 * sizeof(u32); //!< The size of the LoadCtx function in 32-bit ARMv8 instructions
+ constexpr size_t RescaleClockSize = 16 * sizeof(u32); //!< The size of the RescaleClock function in 32-bit ARMv8 instructions
#ifdef NDEBUG
- constexpr size_t svcHandlerSize = 225 * sizeof(u32); //!< The size of the SvcHandler (Release) function in 32-bit ARMv8 instructions
+ constexpr size_t SvcHandlerSize = 225 * sizeof(u32); //!< The size of the SvcHandler (Release) function in 32-bit ARMv8 instructions
#else
- constexpr size_t svcHandlerSize = 400 * sizeof(u32); //!< The size of the SvcHandler (Debug) function in 32-bit ARMv8 instructions
+ constexpr size_t SvcHandlerSize = 400 * sizeof(u32); //!< The size of the SvcHandler (Debug) function in 32-bit ARMv8 instructions
#endif
/**
diff --git a/app/src/main/cpp/skyline/os.cpp b/app/src/main/cpp/skyline/os.cpp
index 8021c74b..22fdf615 100644
--- a/app/src/main/cpp/skyline/os.cpp
+++ b/app/src/main/cpp/skyline/os.cpp
@@ -19,11 +19,11 @@ namespace skyline::kernel {
}
std::shared_ptr OS::CreateProcess(u64 entry, u64 argument, size_t stackSize) {
- auto stack = std::make_shared(state, 0, stackSize, memory::Permission{true, true, false}, memory::MemoryStates::Reserved, MAP_NORESERVE | MAP_STACK);
+ auto stack = std::make_shared(state, 0, stackSize, memory::Permission{true, true, false}, memory::states::Reserved, MAP_NORESERVE | MAP_STACK);
stack->guest = stack->kernel;
if (mprotect(reinterpret_cast(stack->guest.address), PAGE_SIZE, PROT_NONE))
throw exception("Failed to create guard pages");
- auto tlsMem = std::make_shared(state, 0, (sizeof(ThreadContext) + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1), memory::Permission{true, true, false}, memory::MemoryStates::Reserved);
+ auto tlsMem = std::make_shared(state, 0, (sizeof(ThreadContext) + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1), memory::Permission{true, true, false}, memory::states::Reserved);
tlsMem->guest = tlsMem->kernel;
pid_t pid = clone(reinterpret_cast(&guest::GuestEntry), reinterpret_cast(stack->guest.address + stackSize), CLONE_FILES | CLONE_FS | CLONE_SETTLS | SIGCHLD, reinterpret_cast(entry), nullptr, reinterpret_cast(tlsMem->guest.address));
if (pid == -1)
diff --git a/app/src/main/cpp/skyline/services/audio/IAudioOut.cpp b/app/src/main/cpp/skyline/services/audio/IAudioOut.cpp
index dd3f2f4f..1b375e0f 100644
--- a/app/src/main/cpp/skyline/services/audio/IAudioOut.cpp
+++ b/app/src/main/cpp/skyline/services/audio/IAudioOut.cpp
@@ -11,7 +11,7 @@ namespace skyline::service::audio {
{0x5, SFUNC(IAudioOut::GetReleasedAudioOutBuffer)},
{0x6, SFUNC(IAudioOut::ContainsAudioOutBuffer)}
}) {
- track = state.audio->OpenTrack(channelCount, skyline::audio::constant::SampleRate, [this]() { this->releaseEvent->Signal(); });
+ track = state.audio->OpenTrack(channelCount, constant::SampleRate, [this]() { this->releaseEvent->Signal(); });
}
IAudioOut::~IAudioOut() {
@@ -46,7 +46,7 @@ namespace skyline::service::audio {
tmpSampleBuffer.resize(data.sampleSize / sizeof(i16));
state.process->ReadMemory(tmpSampleBuffer.data(), data.sampleBufferPtr, data.sampleSize);
- resampler.ResampleBuffer(tmpSampleBuffer, static_cast