Refactor Common

This refactored common by:
* Moving out as many constants to class/function local scopes from being declared in `common`
* Spacing out common and any function to which a constant was moved out to
* Fixing comments here and there
In addition, some naming inconsistencies were fixed as well.
This commit is contained in:
◱ PixelyIon 2020-03-25 23:29:37 +05:30 committed by ◱ PixelyIon
parent 618353c1fa
commit 773ee25e5a
44 changed files with 906 additions and 813 deletions

View File

@ -1621,7 +1621,7 @@
<inspection_tool class="NotInHierarchyMessage" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="NotInitializedVariable" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="NotReleasedValue" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="NotSuperclass" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="NotSuperclass" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="NotVisibleClass" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="NotifyCalledOnCondition" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="NotifyWithoutCorrespondingWait" enabled="true" level="WARNING" enabled_by_default="true" />
@ -1644,7 +1644,7 @@
<inspection_tool class="NumericToString" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="OCDFA" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="OCGlobalUnused" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="OCInconsistentNaming" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
<inspection_tool class="OCInconsistentNaming" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="OCLegacyObjCLiteral" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="OCLoopDoesntUseConditionVariable" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="OCNotLocalizedString" enabled="true" level="WARNING" enabled_by_default="true" />

View File

@ -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<id_t>(getpid()), skyline::constant::PriorityAn.second);
setpriority(PRIO_PROCESS, static_cast<id_t>(getpid()), skyline::constant::AndroidPriority.second);
auto jvmManager = std::make_shared<skyline::JvmManager>(env, instance);
auto settings = std::make_shared<skyline::Settings>(preferenceFd);

View File

@ -3,41 +3,43 @@
#include <oboe/Oboe.h>
#include <common.h>
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
};
}
}

View File

@ -10,7 +10,7 @@ namespace skyline::audio {
i32 d;
};
constexpr std::array<LutEntry, 128> curveLut0 = {{
constexpr std::array<LutEntry, 128> 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<LutEntry, 128> curveLut1 = {{
constexpr std::array<LutEntry, 128> 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<LutEntry, 128> curveLut2 = {{
constexpr std::array<LutEntry, 128> 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<i16> outputBuffer(static_cast<size_t>(outputSize));
const std::array<skyline::audio::LutEntry, 128> &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;

View File

@ -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> &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<u8>(level)], "%s", str.c_str());
for (auto &character : str)
if (character == '\n')
character = '\\';
logFile << "1|" << levelStr[static_cast<u8>(level)] << "|" << str << "\n";
logFile.flush();
}

View File

@ -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<int8_t, int8_t> PriorityAn = {19, -8}; //!< The range of priority for Android, taken from https://medium.com/mindorks/exploring-android-thread-priority-5d0542eebbd1
constexpr std::pair<u8, u8> 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<int8_t, int8_t> AndroidPriority = {19, -8}; //!< The range of priority for Android
constexpr std::pair<u8, u8> 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);
}
/**

View File

@ -23,12 +23,12 @@ namespace skyline::kernel::ipc {
handleDesc = reinterpret_cast<HandleDescriptor *>(pointer);
pointer += sizeof(HandleDescriptor) + (handleDesc->sendPid ? sizeof(u64) : 0);
for (uint index = 0; handleDesc->copyCount > index; index++) {
copyHandles.push_back(*reinterpret_cast<handle_t *>(pointer));
pointer += sizeof(handle_t);
copyHandles.push_back(*reinterpret_cast<KHandle *>(pointer));
pointer += sizeof(KHandle);
}
for (uint index = 0; handleDesc->moveCount > index; index++) {
moveHandles.push_back(*reinterpret_cast<handle_t *>(pointer));
pointer += sizeof(handle_t);
moveHandles.push_back(*reinterpret_cast<KHandle *>(pointer));
pointer += sizeof(KHandle);
}
}
@ -69,7 +69,9 @@ namespace skyline::kernel::ipc {
pointer += sizeof(BufferDescriptorABW);
}
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
constexpr auto ipcPaddingSum = 0x10; // The sum of the padding surrounding the data payload
u64 padding = ((((reinterpret_cast<u64>(pointer) - reinterpret_cast<u64>(tls)) - 1U) & ~(ipcPaddingSum - 1U)) + ipcPaddingSum + (reinterpret_cast<u64>(tls) - reinterpret_cast<u64>(pointer))); // Calculate the amount of padding at the front
pointer += padding;
if (isDomain && (header->type == CommandType::Request)) {
@ -84,24 +86,26 @@ namespace skyline::kernel::ipc {
pointer += domain->payloadSz;
for (uint index = 0; domain->inputCount > index; index++) {
domainObjects.push_back(*reinterpret_cast<handle_t *>(pointer));
pointer += sizeof(handle_t);
domainObjects.push_back(*reinterpret_cast<KHandle *>(pointer));
pointer += sizeof(KHandle);
}
} else {
payload = reinterpret_cast<PayloadHeader *>(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<BufferDescriptorC *>(pointer);
@ -135,10 +139,14 @@ namespace skyline::kernel::ipc {
void IpcResponse::WriteResponse() {
auto tls = state.process->GetPointer<u8>(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<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(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<handle_t *>(pointer) = copyHandle;
pointer += sizeof(handle_t);
*reinterpret_cast<KHandle *>(pointer) = copyHandle;
pointer += sizeof(KHandle);
}
for (unsigned int moveHandle : moveHandles) {
*reinterpret_cast<handle_t *>(pointer) = moveHandle;
pointer += sizeof(handle_t);
*reinterpret_cast<KHandle *>(pointer) = moveHandle;
pointer += sizeof(KHandle);
}
}
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
u64 padding = ((((reinterpret_cast<u64>(pointer) - reinterpret_cast<u64>(tls)) - 1U) & ~(ipcPaddingSum - 1U)) + ipcPaddingSum + (reinterpret_cast<u64>(tls) - reinterpret_cast<u64>(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<PayloadHeader *>(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<handle_t *>(pointer) = domainObject;
pointer += sizeof(handle_t);
*reinterpret_cast<KHandle *>(pointer) = domainObject;
pointer += sizeof(KHandle);
}
}

View File

@ -242,7 +242,6 @@ namespace skyline::kernel::ipc {
u8 *payloadOffset; //!< This is the offset of the data read from the payload
public:
//std::array<u8, constant::TlsIpcSize> tls; //!< A static-sized array where TLS data is actually copied to
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<handle_t> 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<handle_t> moveHandles; //!< A vector of handles that should be moved from the server to the client process rather than copied
std::vector<handle_t> domainObjects; //!< A vector of all input domain objects
std::vector<KHandle> 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<KHandle> moveHandles; //!< A vector of handles that should be moved from the server to the client process rather than copied
std::vector<KHandle> domainObjects; //!< A vector of all input domain objects
std::vector<InputBuffer> inputBuf; //!< This is a vector of input buffers
std::vector<OutputBuffer> 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<handle_t> copyHandles; //!< A vector of handles to copy
std::vector<handle_t> moveHandles; //!< A vector of handles to move
std::vector<handle_t> domainObjects; //!< A vector of domain objects to write
std::vector<KHandle> copyHandles; //!< A vector of handles to copy
std::vector<KHandle> moveHandles; //!< A vector of handles to move
std::vector<KHandle> domainObjects; //!< A vector of domain objects to write
/**
* @param isDomain If the following request is a domain request

View File

@ -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;

View File

@ -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<type::KPrivateMemory>(destination, size, descriptor->block.permission, memory::MemoryStates::Stack);
state.process->NewHandle<type::KPrivateMemory>(destination, size, descriptor->block.permission, memory::states::Stack);
state.process->CopyMemory(source, destination, size);
auto object = state.process->GetMemoryObject(source);
if (!object)
@ -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<u8>(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<handle_t>(state.ctx->registers.w0);
auto handle = static_cast<KHandle>(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<handle_t> waitHandles(numHandles);
std::vector<std::shared_ptr<type::KSyncObject>> objectTable;
state.process->ReadMemory(waitHandles.data(), state.ctx->registers.x1, numHandles * sizeof(handle_t));
std::string handleStr;
std::vector<std::shared_ptr<type::KSyncObject>> objectTable;
std::vector<KHandle> 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<type::KSyncObject>(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<char>(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<handle_t>(state.ctx->registers.x0));
state.os->serviceManager.SyncRequestHandler(static_cast<KHandle>(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<type::KThread>(handle)->pid;
else
pid = state.thread->pid;
state.logger->Debug("svcGetThreadId: Handle: 0x{:X}, PID: {}", handle, pid);
state.ctx->registers.x1 = static_cast<u64>(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;
}

View File

@ -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)

View File

@ -38,23 +38,29 @@ namespace skyline::kernel::type {
} else {
address = (*(tlsPages.end() - 1))->address + PAGE_SIZE;
}
auto tlsMem = NewHandle<KPrivateMemory>(address, PAGE_SIZE, memory::Permission(true, true, false), memory::MemoryStates::ThreadLocal).item;
auto tlsMem = NewHandle<KPrivateMemory>(address, PAGE_SIZE, memory::Permission(true, true, false), memory::states::ThreadLocal).item;
tlsPages.push_back(std::make_shared<TlsPage>(tlsMem->address));
auto &tlsPage = tlsPages.back();
if (tlsPages.empty())
tlsPage->ReserveSlot(); // User-mode exception handling
return tlsPage->ReserveSlot();
}
void KProcess::InitializeMemory() {
heap = NewHandle<KPrivateMemory>(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<KPrivateMemory>(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<type::KSharedMemory> &stack, std::shared_ptr<type::KSharedMemory> &tlsMemory) : pid(pid), stack(stack), KSyncObject(state, KType::KProcess) {
auto thread = NewHandle<KThread>(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<KThread>(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<KThread> KProcess::CreateThread(u64 entryPoint, u64 entryArg, u64 stackTop, u8 priority) {
auto size = (sizeof(ThreadContext) + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1);
auto tlsMem = std::make_shared<type::KSharedMemory>(state, 0, size, memory::Permission{true, true, false}, memory::MemoryStates::Reserved);
auto tlsMem = std::make_shared<type::KSharedMemory>(state, 0, size, memory::Permission{true, true, false}, memory::states::Reserved);
Registers fregs{};
fregs.x0 = CLONE_THREAD | CLONE_SIGHAND | CLONE_PTRACE | CLONE_FS | CLONE_VM | CLONE_FILES | CLONE_IO;
fregs.x1 = stackTop;
@ -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<u32>(address);
auto &mtxWaiters = mutexes[address];

View File

@ -9,372 +9,381 @@
#include <kernel/memory.h>
#include <list>
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<typename objectClass>
struct HandleOut {
std::shared_ptr<objectClass> 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<typename objectClass>
struct HandleOut {
std::shared_ptr<objectClass> 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<KHandle, std::shared_ptr<KObject>> handles; //!< A mapping from a handle_t to it's corresponding KObject which is the actual underlying object
std::unordered_map<pid_t, std::shared_ptr<KThread>> threads; //!< A mapping from a PID to it's corresponding KThread object
std::unordered_map<u64, std::vector<std::shared_ptr<WaitStatus>>> mutexes; //!< A map from a mutex's address to a vector of Mutex objects for threads waiting on it
std::unordered_map<u64, std::list<std::shared_ptr<WaitStatus>>> conditionals; //!< A map from a conditional variable's address to a vector of threads waiting on it
std::vector<std::shared_ptr<TlsPage>> tlsPages; //!< A vector of all allocated TLS pages
std::shared_ptr<type::KSharedMemory> stack; //!< The shared memory used to hold the stack of the main thread
std::shared_ptr<KPrivateMemory> 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<type::KSharedMemory> &stack, std::shared_ptr<type::KSharedMemory> &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<KThread> 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<handle_t, std::shared_ptr<KObject>> handles; //!< A mapping from a handle_t to it's corresponding KObject which is the actual underlying object
std::unordered_map<pid_t, std::shared_ptr<KThread>> threads; //!< A mapping from a PID to it's corresponding KThread object
std::unordered_map<u64, std::vector<std::shared_ptr<WaitStatus>>> mutexes; //!< A map from a mutex's address to a vector of Mutex objects for threads waiting on it
std::unordered_map<u64, std::list<std::shared_ptr<WaitStatus>>> conditionals; //!< A map from a conditional variable's address to a vector of threads waiting on it
std::vector<std::shared_ptr<TlsPage>> tlsPages; //!< A vector of all allocated TLS pages
std::shared_ptr<type::KSharedMemory> stack; //!< The shared memory used to hold the stack of the main thread
std::shared_ptr<KPrivateMemory> 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<type::KSharedMemory> &stack, std::shared_ptr<type::KSharedMemory> &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<KThread> 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<typename Type>
inline Type *GetPointer(const u64 address) const {
return reinterpret_cast<Type *>(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<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;
/**
* @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<typename Type>
inline Type *GetPointer(const u64 address) const {
return reinterpret_cast<Type *>(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<char>(address);
if (source)
return std::string(source, maxSize);
std::string debug(maxSize, '\0');
ReadMemory(debug.data(), address, maxSize);
return debug;
}
/**
* @brief Writes an object to guest memory
* @tparam Type The type of the object to be written
* @param item The object to write
* @param address The address of the object
*/
template<typename Type>
inline void WriteMemory(Type &item, u64 address) const {
auto destination = GetPointer<Type>(address);
if (destination) {
*destination = item;
} else {
WriteMemory(&item, address, sizeof(Type));
}
}
/**
* @brief Writes an object to guest memory
* @tparam Type The type of the object to be written
* @param item The object to write
* @param address The address of the object
*/
template<typename Type>
inline void WriteMemory(const Type &item, u64 address) const {
auto destination = GetPointer<Type>(address);
if (destination) {
*destination = item;
} else {
WriteMemory(&item, address, sizeof(Type));
}
}
/**
* @brief Read data from the guest's memory
* @param destination The address to the location where the process memory is written
* @param offset The address to read from in process memory
* @param size The amount of memory to be read
* @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<typename objectClass, typename ...objectArgs>
HandleOut<objectClass> NewHandle(objectArgs... args) {
std::shared_ptr<objectClass> item;
if constexpr (std::is_same<objectClass, KThread>())
item = std::make_shared<objectClass>(state, handleIndex, args...);
else
item = std::make_shared<objectClass>(state, args...);
handles[handleIndex] = std::static_pointer_cast<KObject>(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<typename objectClass>
handle_t InsertItem(std::shared_ptr<objectClass> &item) {
handles[handleIndex] = std::static_pointer_cast<KObject>(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<typename objectClass>
std::shared_ptr<objectClass> GetHandle(handle_t handle) {
KType objectType;
if constexpr(std::is_same<objectClass, KThread>())
objectType = KType::KThread;
else if constexpr(std::is_same<objectClass, KProcess>())
objectType = KType::KProcess;
else if constexpr(std::is_same<objectClass, KSharedMemory>())
objectType = KType::KSharedMemory;
else if constexpr(std::is_same<objectClass, KTransferMemory>())
objectType = KType::KTransferMemory;
else if constexpr(std::is_same<objectClass, KPrivateMemory>())
objectType = KType::KPrivateMemory;
else if constexpr(std::is_same<objectClass, KSession>())
objectType = KType::KSession;
else if constexpr(std::is_same<objectClass, KEvent>())
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<objectClass>(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<typename Type>
inline Type &GetReference(u64 address) const {
auto source = GetPointer<Type>(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<HandleOut<KMemory>> 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<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 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<char>(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<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 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<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));
}
}
/**
* @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<typename objectClass, typename ...objectArgs>
HandleOut<objectClass> NewHandle(objectArgs... args) {
std::shared_ptr<objectClass> item;
if constexpr (std::is_same<objectClass, KThread>())
item = std::make_shared<objectClass>(state, handleIndex, args...);
else
item = std::make_shared<objectClass>(state, args...);
handles[handleIndex] = std::static_pointer_cast<KObject>(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<typename objectClass>
KHandle InsertItem(std::shared_ptr<objectClass> &item) {
handles[handleIndex] = std::static_pointer_cast<KObject>(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<typename objectClass>
std::shared_ptr<objectClass> GetHandle(KHandle handle) {
KType objectType;
if constexpr(std::is_same<objectClass, KThread>())
objectType = KType::KThread;
else if constexpr(std::is_same<objectClass, KProcess>())
objectType = KType::KProcess;
else if constexpr(std::is_same<objectClass, KSharedMemory>())
objectType = KType::KSharedMemory;
else if constexpr(std::is_same<objectClass, KTransferMemory>())
objectType = KType::KTransferMemory;
else if constexpr(std::is_same<objectClass, KPrivateMemory>())
objectType = KType::KPrivateMemory;
else if constexpr(std::is_same<objectClass, KSession>())
objectType = KType::KSession;
else if constexpr(std::is_same<objectClass, KEvent>())
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<objectClass>(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<HandleOut<KMemory>> 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;
}
};
}
}

View File

@ -11,8 +11,8 @@ namespace skyline::kernel::type {
class KSession : public KSyncObject {
public:
const std::shared_ptr<service::BaseService> serviceObject; //!< A shared pointer to the service class
std::unordered_map<handle_t, std::shared_ptr<service::BaseService>> domainTable; //!< This maps from a virtual handle to it's service
handle_t handleIndex = constant::BaseVirtualHandleIndex;
std::unordered_map<KHandle, std::shared_ptr<service::BaseService>> 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++;

View File

@ -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<void *>(kernel.address), kernel.size, permission.Get()) == reinterpret_cast<u64>(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<void *>(kernel.address), kernel.size);
state.os->memory.DeleteChunk(guest.address);
close(fd);

View File

@ -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

View File

@ -4,8 +4,7 @@
#include <nce.h>
namespace skyline::kernel::type {
KThread::KThread(const DeviceState &state, handle_t handle, pid_t self_pid, u64 entryPoint, u64 entryArg, u64 stackTop, u64 tls, u8 priority, KProcess *parent, std::shared_ptr<type::KSharedMemory> &tlsMemory) : handle(handle), pid(self_pid), entryPoint(entryPoint), entryArg(entryArg), stackTop(stackTop), tls(tls), priority(priority), parent(parent), ctxMemory(tlsMemory), KSyncObject(state,
KType::KThread) {
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<type::KSharedMemory> &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<int8_t>(constant::PriorityAn.first + ((static_cast<float>(constant::PriorityAn.second - constant::PriorityAn.first) / static_cast<float>(constant::PriorityNin.second - constant::PriorityNin.first)) * (static_cast<float>(priority) - constant::PriorityNin.first))); // Resize range PriorityNin (Nintendo Priority) to PriorityAn (Android Priority)
if (setpriority(PRIO_PROCESS, static_cast<id_t>(pid), liPriority) == -1)
throw exception("Couldn't set process priority to {} for PID: {}", liPriority, pid);
auto linuxPriority = static_cast<int8_t>(constant::AndroidPriority.first + ((static_cast<float>(constant::AndroidPriority.second - constant::AndroidPriority.first) / static_cast<float>(constant::SwitchPriority.second - constant::SwitchPriority.first)) * (static_cast<float>(priority) - constant::SwitchPriority.first))); // Resize range SwitchPriority (Nintendo Priority) to AndroidPriority (Android Priority)
if (setpriority(PRIO_PROCESS, static_cast<id_t>(pid), linuxPriority) == -1)
throw exception("Couldn't set process priority to {} for PID: {}", linuxPriority, pid);
}
}

View File

@ -21,7 +21,7 @@ namespace skyline::kernel::type {
} status = Status::Created; //!< The state of the thread
std::atomic<bool> cancelSync{false}; //!< This is to flag to a thread to cancel a synchronization call it currently is in
std::shared_ptr<type::KSharedMemory> ctxMemory; //!< The KSharedMemory of the shared memory allocated by the guest process TLS
handle_t handle; // The handle of the object in the handle table
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<type::KSharedMemory> &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<type::KSharedMemory> &tlsMemory);
/**
* @brief Kills the thread and deallocates the memory allocated for stack.

View File

@ -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

View File

@ -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<kernel::type::KPrivateMemory>(constant::BaseAddress, textSize, memory::Permission{true, true, true}, memory::MemoryStates::CodeStatic); // R-X
process->NewHandle<kernel::type::KPrivateMemory>(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<kernel::type::KPrivateMemory>(constant::BaseAddress + textSize, rodataSize, memory::Permission{true, false, false}, memory::MemoryStates::CodeReadOnly); // R--
process->NewHandle<kernel::type::KPrivateMemory>(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<kernel::type::KPrivateMemory>(constant::BaseAddress + textSize + rodataSize, dataSize, memory::Permission{true, true, false}, memory::MemoryStates::CodeStatic); // RW-
process->NewHandle<kernel::type::KPrivateMemory>(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<kernel::type::KPrivateMemory>(constant::BaseAddress + textSize + rodataSize + dataSize, header.bssSize, memory::Permission{true, true, true}, memory::MemoryStates::CodeMutable); // RWX
process->NewHandle<kernel::type::KPrivateMemory>(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<kernel::type::KPrivateMemory>(constant::BaseAddress + textSize + rodataSize + dataSize + header.bssSize, patchSize + padding, memory::Permission{true, true, true}, memory::MemoryStates::CodeStatic); // RWX
process->NewHandle<kernel::type::KPrivateMemory>(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);

View File

@ -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<u32> NCE::PatchCode(std::vector<u8> &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<u32 *>(code.data());
u32 *end = start + (code.size() / sizeof(u32));
i64 patchOffset = offset;
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);
offset += guest::saveCtxSize;
std::memcpy(patch.data(), reinterpret_cast<void *>(&guest::SaveCtx), guest::SaveCtxSize);
offset += guest::SaveCtxSize;
std::memcpy(reinterpret_cast<u8 *>(patch.data()) + guest::saveCtxSize, reinterpret_cast<void *>(&guest::LoadCtx), guest::loadCtxSize);
offset += guest::loadCtxSize;
std::memcpy(reinterpret_cast<u8 *>(patch.data()) + guest::SaveCtxSize, reinterpret_cast<void *>(&guest::LoadCtx), guest::LoadCtxSize);
offset += guest::LoadCtxSize;
std::memcpy(reinterpret_cast<u8 *>(patch.data()) + guest::saveCtxSize + guest::loadCtxSize, reinterpret_cast<void *>(&guest::SvcHandler), guest::svcHandlerSize);
offset += guest::svcHandlerSize;
std::memcpy(reinterpret_cast<u8 *>(patch.data()) + guest::SaveCtxSize + guest::LoadCtxSize, reinterpret_cast<void *>(&guest::SvcHandler), guest::SvcHandlerSize);
offset += guest::SvcHandlerSize;
static u64 frequency{};
if (!frequency)
@ -238,10 +246,10 @@ namespace skyline {
offset += sizeof(u32) * movPc.size();
instr::Movz movCmd(regs::W1, static_cast<u16>(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<void *>(&guest::RescaleClock), guest::rescaleClockSize);
patch.resize(size + (guest::RescaleClockSize / sizeof(u32)));
std::memcpy(patch.data() + size, reinterpret_cast<void *>(&guest::RescaleClock), guest::RescaleClockSize);
patch.push_back(ldr.raw);
patch.push_back(addSp);
patch.push_back(bret.raw);
} else if (instrMrs->srcReg == constant::CntfrqEl0) {
} else if (instrMrs->srcReg == CntfrqEl0) {
instr::B bJunc(offset);
auto movFreq = instr::MoveU32Reg(static_cast<regs::X>(instrMrs->destReg), constant::TegraX1Freq);
auto movFreq = instr::MoveU32Reg(static_cast<regs::X>(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;
}
}

View File

@ -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
/**

View File

@ -19,11 +19,11 @@ namespace skyline::kernel {
}
std::shared_ptr<type::KProcess> OS::CreateProcess(u64 entry, u64 argument, size_t stackSize) {
auto stack = std::make_shared<type::KSharedMemory>(state, 0, stackSize, memory::Permission{true, true, false}, memory::MemoryStates::Reserved, MAP_NORESERVE | MAP_STACK);
auto stack = std::make_shared<type::KSharedMemory>(state, 0, stackSize, memory::Permission{true, true, false}, memory::states::Reserved, MAP_NORESERVE | MAP_STACK);
stack->guest = stack->kernel;
if (mprotect(reinterpret_cast<void *>(stack->guest.address), PAGE_SIZE, PROT_NONE))
throw exception("Failed to create guard pages");
auto tlsMem = std::make_shared<type::KSharedMemory>(state, 0, (sizeof(ThreadContext) + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1), memory::Permission{true, true, false}, memory::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::states::Reserved);
tlsMem->guest = tlsMem->kernel;
pid_t pid = clone(reinterpret_cast<int (*)(void *)>(&guest::GuestEntry), reinterpret_cast<void *>(stack->guest.address + stackSize), CLONE_FILES | CLONE_FS | CLONE_SETTLS | SIGCHLD, reinterpret_cast<void *>(entry), nullptr, reinterpret_cast<void *>(tlsMem->guest.address));
if (pid == -1)

View File

@ -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<double>(sampleRate) / skyline::audio::constant::SampleRate, channelCount);
resampler.ResampleBuffer(tmpSampleBuffer, static_cast<double>(sampleRate) / constant::SampleRate, channelCount);
track->AppendBuffer(tmpSampleBuffer, tag);
}

View File

@ -20,8 +20,8 @@ namespace skyline::service::audio {
state.logger->Debug("audoutU: Opening an IAudioOut with sample rate: {}, channel count: {}", sampleRate, channelCount);
sampleRate = sampleRate ? sampleRate : skyline::audio::constant::SampleRate;
channelCount = channelCount ? channelCount : static_cast<u16>(skyline::audio::constant::ChannelCount);
sampleRate = sampleRate ? sampleRate : constant::SampleRate;
channelCount = channelCount ? channelCount : static_cast<u16>(constant::ChannelCount);
manager.RegisterService(std::make_shared<IAudioOut>(state, manager, channelCount, sampleRate), session, response);
response.Push<u32>(sampleRate);

View File

@ -3,27 +3,28 @@
#include <kernel/types/KEvent.h>
#include <services/base_service.h>
#include <services/serviceman.h>
namespace skyline::service::audio {
namespace skyline {
namespace constant {
constexpr std::string_view DefaultAudioOutName = "DeviceOut"; //!< The default audio output device name
};
/**
* @brief IAudioOutManager or audout:u is used to manage audio outputs (https://switchbrew.org/wiki/Audio_services#audout:u)
*/
class IAudioOutManager : public BaseService {
public:
IAudioOutManager(const DeviceState &state, ServiceManager &manager);
namespace service::audio {
/**
* @brief Returns a list of all available audio outputs (https://switchbrew.org/wiki/Audio_services#ListAudioOuts)
* @brief IAudioOutManager or audout:u is used to manage audio outputs (https://switchbrew.org/wiki/Audio_services#audout:u)
*/
void ListAudioOuts(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);
class IAudioOutManager : public BaseService {
public:
IAudioOutManager(const DeviceState &state, ServiceManager &manager);
/**
* @brief Creates a new audoutU::IAudioOut object and returns a handle to it (https://switchbrew.org/wiki/Audio_services#OpenAudioOut)
*/
void OpenAudioOut(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);
};
/**
* @brief Returns a list of all available audio outputs (https://switchbrew.org/wiki/Audio_services#ListAudioOuts)
*/
void ListAudioOuts(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);
/**
* @brief Creates a new audoutU::IAudioOut object and returns a handle to it (https://switchbrew.org/wiki/Audio_services#OpenAudioOut)
*/
void OpenAudioOut(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);
};
}
}

View File

@ -13,7 +13,7 @@ namespace skyline::service::audio::IAudioRenderer {
{0x6, SFUNC(IAudioRenderer::Stop)},
{0x7, SFUNC(IAudioRenderer::QuerySystemEvent)},
}) {
track = state.audio->OpenTrack(skyline::audio::constant::ChannelCount, params.sampleRate, [this]() { this->releaseEvent->Signal(); });
track = state.audio->OpenTrack(constant::ChannelCount, params.sampleRate, [this]() { this->releaseEvent->Signal(); });
track->Start();
memoryPools.resize(memoryPoolCount);
@ -132,7 +132,7 @@ namespace skyline::service::audio::IAudioRenderer {
void IAudioRenderer::MixFinalBuffer() {
int setIndex = 0;
sampleBuffer.resize(samplesPerBuffer * skyline::audio::constant::ChannelCount);
sampleBuffer.resize(static_cast<size_t>(samplesPerBuffer * constant::ChannelCount));
for (auto &voice : voices) {
if (!voice.Playable())
@ -149,7 +149,7 @@ namespace skyline::service::audio::IAudioRenderer {
if (voiceBufferSize == 0)
break;
pendingSamples -= voiceBufferSize / skyline::audio::constant::ChannelCount;
pendingSamples -= voiceBufferSize / constant::ChannelCount;
for (int i = voiceBufferOffset; i < voiceBufferOffset + voiceBufferSize; i++) {
if (setIndex == bufferOffset) {

View File

@ -9,127 +9,130 @@
#include "voice.h"
#include "revisionInfo.h"
namespace skyline::service::audio::IAudioRenderer {
namespace skyline {
namespace constant {
constexpr int BufferAlignment = 0x40; //!< The alignment for all audren buffers
constexpr auto BufferAlignment = 0x40; //!< The alignment for all audren buffers
}
/**
* @brief The parameters used to configure an IAudioRenderer
*/
struct AudioRendererParams {
u32 sampleRate; //!< The sample rate to use for the renderer
u32 sampleCount; //!< The buffer sample count
u32 mixBufferCount; //!< The amount of mix buffers to use
u32 subMixCount; //!< The amount of sub mixes to use
u32 voiceCount; //!< The amount of voices to use
u32 sinkCount; //!< The amount of sinks to use
u32 effectCount; //!< The amount of effects to use
u32 performanceManagerCount; //!< The amount of performance managers to use
u32 voiceDropEnable; //!< Whether to enable voice drop
u32 splitterCount; //!< The amount of splitters to use
u32 splitterDestinationDataCount; //!< The amount of splitter destination outputs to use
u32 _unk0_;
u32 revision; //!< The revision of audren to use
};
static_assert(sizeof(AudioRendererParams) == 0x34);
/**
* @brief Header containing information about the software side audren implementation
*/
struct UpdateDataHeader {
u32 revision; //!< Revision of the software implementation
u32 behaviorSize; //!< The total size of the behaviour info
u32 memoryPoolSize; //!< The total size of all MemoryPoolIn structs
u32 voiceSize; //!< The total size of all VoiceIn structs
u32 voiceResourceSize; //!< The total size of the voice resources
u32 effectSize; //!< The total size of all EffectIn structs
u32 mixSize; //!< The total size of all mixer descriptors in the input
u32 sinkSize; //!< The total size of all sink descriptors in the input
u32 performanceManagerSize; //!< The total size of all performance manager descriptors in the input
u32 _unk0_;
u32 elapsedFrameCountInfoSize; //!< The total size of all the elapsed frame info
u32 _unk1_[4];
u32 totalSize; //!< The total size of the whole input
};
static_assert(sizeof(UpdateDataHeader) == 0x40);
/**
* @brief IAudioRenderer is used to control an audio renderer output (https://switchbrew.org/wiki/Audio_services#IAudioRenderer)
*/
class IAudioRenderer : public BaseService {
private:
AudioRendererParams rendererParams; //!< The parameters to use for the renderer
RevisionInfo revisionInfo{}; //!< Stores info about supported features for the audren revision used
std::shared_ptr<skyline::audio::AudioTrack> track; //!< The audio track associated with the audio renderer
std::shared_ptr<type::KEvent> releaseEvent; //!< The KEvent that is signalled when a buffer has been released
std::vector<MemoryPool> memoryPools; //!< An vector of all memory pools that the guest may need
std::vector<Effect> effects; //!< An vector of all effects that the guest may need
std::vector<Voice> voices; //!< An vector of all voices that the guest may need
std::vector<i16> sampleBuffer; //!< The final output data that is appended to the stream
skyline::audio::AudioOutState playbackState{skyline::audio::AudioOutState::Stopped}; //!< The current state of playback
const size_t memoryPoolCount; //!< The amount of memory pools the guest may need
const int samplesPerBuffer; //!< The amount of samples each appended buffer should contain
namespace service::audio::IAudioRenderer {
/**
* @brief Obtains new sample data from voices and mixes it together into the sample buffer
* @brief The parameters used to configure an IAudioRenderer
*/
void MixFinalBuffer();
struct AudioRendererParams {
u32 sampleRate; //!< The sample rate to use for the renderer
u32 sampleCount; //!< The buffer sample count
u32 mixBufferCount; //!< The amount of mix buffers to use
u32 subMixCount; //!< The amount of sub mixes to use
u32 voiceCount; //!< The amount of voices to use
u32 sinkCount; //!< The amount of sinks to use
u32 effectCount; //!< The amount of effects to use
u32 performanceManagerCount; //!< The amount of performance managers to use
u32 voiceDropEnable; //!< Whether to enable voice drop
u32 splitterCount; //!< The amount of splitters to use
u32 splitterDestinationDataCount; //!< The amount of splitter destination outputs to use
u32 _unk0_;
u32 revision; //!< The revision of audren to use
};
static_assert(sizeof(AudioRendererParams) == 0x34);
/**
* @brief Appends all released buffers with new mixed sample data
* @brief Header containing information about the software side audren implementation
*/
void UpdateAudio();
public:
/**
* @param params The parameters to use for rendering
*/
IAudioRenderer(const DeviceState &state, ServiceManager &manager, AudioRendererParams &params);
struct UpdateDataHeader {
u32 revision; //!< Revision of the software implementation
u32 behaviorSize; //!< The total size of the behaviour info
u32 memoryPoolSize; //!< The total size of all MemoryPoolIn structs
u32 voiceSize; //!< The total size of all VoiceIn structs
u32 voiceResourceSize; //!< The total size of the voice resources
u32 effectSize; //!< The total size of all EffectIn structs
u32 mixSize; //!< The total size of all mixer descriptors in the input
u32 sinkSize; //!< The total size of all sink descriptors in the input
u32 performanceManagerSize; //!< The total size of all performance manager descriptors in the input
u32 _unk0_;
u32 elapsedFrameCountInfoSize; //!< The total size of all the elapsed frame info
u32 _unk1_[4];
u32 totalSize; //!< The total size of the whole input
};
static_assert(sizeof(UpdateDataHeader) == 0x40);
/**
* @brief Closes the audio track
*/
~IAudioRenderer();
/**
* @brief Returns the sample rate (https://switchbrew.org/wiki/Audio_services#GetSampleRate)
*/
void GetSampleRate(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);
/**
* @brief Returns the sample count (https://switchbrew.org/wiki/Audio_services#GetSampleCount)
* @brief IAudioRenderer is used to control an audio renderer output (https://switchbrew.org/wiki/Audio_services#IAudioRenderer)
*/
void GetSampleCount(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);
class IAudioRenderer : public BaseService {
private:
AudioRendererParams rendererParams; //!< The parameters to use for the renderer
RevisionInfo revisionInfo{}; //!< Stores info about supported features for the audren revision used
std::shared_ptr<skyline::audio::AudioTrack> track; //!< The audio track associated with the audio renderer
std::shared_ptr<type::KEvent> releaseEvent; //!< The KEvent that is signalled when a buffer has been released
std::vector<MemoryPool> memoryPools; //!< An vector of all memory pools that the guest may need
std::vector<Effect> effects; //!< An vector of all effects that the guest may need
std::vector<Voice> voices; //!< An vector of all voices that the guest may need
std::vector<i16> sampleBuffer; //!< The final output data that is appended to the stream
/**
* @brief Returns the number of mix buffers (https://switchbrew.org/wiki/Audio_services#GetMixBufferCount)
*/
void GetMixBufferCount(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);
skyline::audio::AudioOutState playbackState{skyline::audio::AudioOutState::Stopped}; //!< The current state of playback
const size_t memoryPoolCount; //!< The amount of memory pools the guest may need
const int samplesPerBuffer; //!< The amount of samples each appended buffer should contain
/**
* @brief Returns the state of the renderer (https://switchbrew.org/wiki/Audio_services#GetAudioRendererState) (stubbed)?
*/
void GetState(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);
/**
* @brief Obtains new sample data from voices and mixes it together into the sample buffer
*/
void MixFinalBuffer();
/**
* @brief Updates the audio renderer state and appends new data to playback buffers
*/
void RequestUpdate(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);
/**
* @brief Appends all released buffers with new mixed sample data
*/
void UpdateAudio();
/**
* @brief Start the audio stream from the renderer
*/
void Start(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);
public:
/**
* @param params The parameters to use for rendering
*/
IAudioRenderer(const DeviceState &state, ServiceManager &manager, AudioRendererParams &params);
/**
* @brief Stop the audio stream from the renderer
*/
void Stop(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);
/**
* @brief Closes the audio track
*/
~IAudioRenderer();
/**
* @brief Returns a handle to the sample release KEvent
*/
void QuerySystemEvent(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);
};
/**
* @brief Returns the sample rate (https://switchbrew.org/wiki/Audio_services#GetSampleRate)
*/
void GetSampleRate(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);
/**
* @brief Returns the sample count (https://switchbrew.org/wiki/Audio_services#GetSampleCount)
*/
void GetSampleCount(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);
/**
* @brief Returns the number of mix buffers (https://switchbrew.org/wiki/Audio_services#GetMixBufferCount)
*/
void GetMixBufferCount(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);
/**
* @brief Returns the state of the renderer (https://switchbrew.org/wiki/Audio_services#GetAudioRendererState) (stubbed)?
*/
void GetState(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);
/**
* @brief Updates the audio renderer state and appends new data to playback buffers
*/
void RequestUpdate(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);
/**
* @brief Start the audio stream from the renderer
*/
void Start(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);
/**
* @brief Stop the audio stream from the renderer
*/
void Stop(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);
/**
* @brief Returns a handle to the sample release KEvent
*/
void QuerySystemEvent(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);
};
}
}

View File

@ -1,8 +1,7 @@
#pragma once
#include <common.h>
namespace skyline::service::audio::IAudioRenderer {
namespace skyline {
namespace constant {
constexpr u32 SupportedRevision = 7; //!< The audren revision our implementation supports
constexpr u32 Rev0Magic = ('R' << 0) | ('E' << 8) | ('V' << 16) | ('0' << 24); //!< The HOS 1.0 revision magic
@ -17,67 +16,69 @@ namespace skyline::service::audio::IAudioRenderer {
};
}
/**
* @brief Extracts the audren version from a revision magic
* @param revision The revision magic
* @return The revision number from the magic
*/
inline u32 ExtractVersionFromRevision(u32 revision) {
return (revision - constant::Rev0Magic) >> 24;
namespace service::audio::IAudioRenderer {
/**
* @brief Extracts the audren version from a revision magic
* @param revision The revision magic
* @return The revision number from the magic
*/
inline u32 ExtractVersionFromRevision(u32 revision) {
return (revision - constant::Rev0Magic) >> 24;
}
/**
* @brief The RevisionInfo class is used to query the supported features of various audren revisions
*/
class RevisionInfo {
private:
u32 userRevision; //!< The current audren revision of the guest
public:
/**
* @brief Extracts the audren revision from the magic and sets the behaviour revision to it
* @param revision The revision magic from guest
*/
inline void SetUserRevision(u32 revision) {
userRevision = ExtractVersionFromRevision(revision);
if (userRevision > constant::SupportedRevision)
throw exception("Unsupported audren revision: {}", userRevision);
}
/**
* @return Whether the splitter is supported
*/
inline bool SplitterSupported() {
return userRevision >= constant::supportTags::Splitter;
}
/**
* @return Whether the splitter is fixed
*/
inline bool SplitterBugFixed() {
return userRevision >= constant::supportTags::SplitterBugFix;
}
/**
* @return Whether the new performance metrics format is used
*/
inline bool UsesPerformanceMetricDataFormatV2() {
return userRevision >= constant::supportTags::PerformanceMetricsDataFormatV2;
}
/**
* @return Whether varying command buffer sizes are supported
*/
inline bool VaradicCommandBufferSizeSupported() {
return userRevision >= constant::supportTags::VaradicCommandBufferSize;
}
/**
* @return Whether elapsed frame counting is supported
*/
inline bool ElapsedFrameCountSupported() {
return userRevision >= constant::supportTags::ElapsedFrameCount;
}
};
}
/**
* @brief The RevisionInfo class is used to query the supported features of various audren revisions
*/
class RevisionInfo {
private:
u32 userRevision; //!< The current audren revision of the guest
public:
/**
* @brief Extracts the audren revision from the magic and sets the behaviour revision to it
* @param revision The revision magic from guest
*/
inline void SetUserRevision(u32 revision) {
userRevision = ExtractVersionFromRevision(revision);
if (userRevision > constant::SupportedRevision)
throw exception("Unsupported audren revision: {}", userRevision);
}
/**
* @return Whether the splitter is supported
*/
inline bool SplitterSupported() {
return userRevision >= constant::supportTags::Splitter;
}
/**
* @return Whether the splitter is fixed
*/
inline bool SplitterBugFixed() {
return userRevision >= constant::supportTags::SplitterBugFix;
}
/**
* @return Whether the new performance metrics format is used
*/
inline bool UsesPerformanceMetricDataFormatV2() {
return userRevision >= constant::supportTags::PerformanceMetricsDataFormatV2;
}
/**
* @return Whether varying command buffer sizes are supported
*/
inline bool VaradicCommandBufferSizeSupported() {
return userRevision >= constant::supportTags::VaradicCommandBufferSize;
}
/**
* @return Whether elapsed frame counting is supported
*/
inline bool ElapsedFrameCountSupported() {
return userRevision >= constant::supportTags::ElapsedFrameCount;
}
};
}

View File

@ -55,15 +55,15 @@ namespace skyline::service::audio::IAudioRenderer {
throw exception("Unsupported voice PCM format: {}", pcmFormat);
}
if (sampleRate != skyline::audio::constant::SampleRate)
sampleBuffer = resampler.ResampleBuffer(sampleBuffer, static_cast<double>(sampleRate) / skyline::audio::constant::SampleRate, channelCount);
if (sampleRate != constant::SampleRate)
sampleBuffer = resampler.ResampleBuffer(sampleBuffer, static_cast<double>(sampleRate) / constant::SampleRate, channelCount);
if (channelCount == 1 && skyline::audio::constant::ChannelCount != channelCount) {
if (channelCount == 1 && constant::ChannelCount != channelCount) {
size_t originalSize = sampleBuffer.size();
sampleBuffer.resize((originalSize / channelCount) * skyline::audio::constant::ChannelCount);
sampleBuffer.resize((originalSize / channelCount) * constant::ChannelCount);
for (size_t monoIndex = originalSize - 1, targetIndex = sampleBuffer.size(); monoIndex > 0; monoIndex--)
for (uint i = 0; i < skyline::audio::constant::ChannelCount; i++)
for (uint i = 0; i < constant::ChannelCount; i++)
sampleBuffer[--targetIndex] = sampleBuffer[monoIndex];
}
}
@ -82,9 +82,9 @@ namespace skyline::service::audio::IAudioRenderer {
}
outOffset = sampleOffset;
outSize = std::min(maxSamples * skyline::audio::constant::ChannelCount, static_cast<int>(sampleBuffer.size() - sampleOffset));
outSize = std::min(maxSamples * constant::ChannelCount, static_cast<int>(sampleBuffer.size() - sampleOffset));
output.playedSamplesCount += outSize / skyline::audio::constant::ChannelCount;
output.playedSamplesCount += outSize / constant::ChannelCount;
sampleOffset += outSize;
if (sampleOffset == sampleBuffer.size()) {

View File

@ -91,7 +91,7 @@ namespace skyline::service::audio::IAudioRenderer {
bool acquired{false}; //!< If the voice is in use
bool bufferReload{true}; //!< If the buffer needs to be updated
int bufferIndex{}; //!< The index of the wave buffer currently in use
uint bufferIndex{}; //!< The index of the wave buffer currently in use
int sampleOffset{}; //!< The offset in the sample data of the current wave buffer
int sampleRate{}; //!< The sample rate of the sample data
int channelCount{}; //!< The amount of channels in the sample data

View File

@ -25,25 +25,25 @@ namespace skyline::service::audio {
u32 totalMixCount = params.subMixCount + 1;
i64 size = utils::AlignUp(params.mixBufferCount * 4, IAudioRenderer::constant::BufferAlignment) +
i64 size = utils::AlignUp(params.mixBufferCount * 4, constant::BufferAlignment) +
params.subMixCount * 0x400 +
totalMixCount * 0x940 +
params.voiceCount * 0x3F0 +
utils::AlignUp(totalMixCount * 8, 16) +
utils::AlignUp(params.voiceCount * 8, 16) +
utils::AlignUp(((params.sinkCount + params.subMixCount) * 0x3C0 + params.sampleCount * 4) * (params.mixBufferCount + 6), IAudioRenderer::constant::BufferAlignment) +
utils::AlignUp(((params.sinkCount + params.subMixCount) * 0x3C0 + params.sampleCount * 4) * (params.mixBufferCount + 6), constant::BufferAlignment) +
(params.sinkCount + params.subMixCount) * 0x2C0 +
(params.effectCount + params.voiceCount * 4) * 0x30 +
0x50;
if (revisionInfo.SplitterSupported()) {
i32 nodeStateWorkSize = utils::AlignUp(totalMixCount, IAudioRenderer::constant::BufferAlignment);
i32 nodeStateWorkSize = utils::AlignUp(totalMixCount, constant::BufferAlignment);
if (nodeStateWorkSize < 0)
nodeStateWorkSize |= 7;
nodeStateWorkSize = 4 * (totalMixCount * totalMixCount) + 12 * totalMixCount + 2 * (nodeStateWorkSize / 8);
i32 edgeMatrixWorkSize = utils::AlignUp(totalMixCount * totalMixCount, IAudioRenderer::constant::BufferAlignment);
i32 edgeMatrixWorkSize = utils::AlignUp(totalMixCount * totalMixCount, constant::BufferAlignment);
if (edgeMatrixWorkSize < 0)
edgeMatrixWorkSize |= 7;

View File

@ -3,14 +3,19 @@
#include <kernel/types/KProcess.h>
namespace skyline::service {
Parcel::Parcel(kernel::ipc::InputBuffer &buffer, const DeviceState &state) : Parcel(buffer.address, buffer.size, state) {}
Parcel::Parcel(kernel::ipc::InputBuffer &buffer, const DeviceState &state, bool hasToken) : Parcel(buffer.address, buffer.size, state, hasToken) {}
Parcel::Parcel(u64 address, u64 size, const DeviceState &state) : state(state) {
Parcel::Parcel(u64 address, u64 size, const DeviceState &state, bool hasToken) : state(state) {
state.process->ReadMemory(&header, address, sizeof(ParcelHeader));
if (size < (sizeof(ParcelHeader) + header.dataSize + header.objectsSize))
throw exception("The size of the parcel according to the header exceeds the specified size");
data.resize(header.dataSize);
state.process->ReadMemory(data.data(), address + header.dataOffset, header.dataSize);
constexpr auto tokenLength = 0x50; // The length of the token on BufferQueue parcels
data.resize(header.dataSize - (hasToken ? tokenLength : 0));
state.process->ReadMemory(data.data(), address + header.dataOffset + (hasToken ? tokenLength : 0), header.dataSize - (hasToken ? tokenLength : 0));
objects.resize(header.objectsSize);
state.process->ReadMemory(objects.data(), address + header.objectsOffset, header.objectsSize);
}
@ -24,14 +29,19 @@ namespace skyline::service {
u64 Parcel::WriteParcel(u64 address, u64 maxSize) {
header.dataSize = static_cast<u32>(data.size());
header.dataOffset = sizeof(ParcelHeader);
header.objectsSize = static_cast<u32>(objects.size());
header.objectsOffset = sizeof(ParcelHeader) + data.size();
u64 totalSize = sizeof(ParcelHeader) + header.dataSize + header.objectsSize;
auto totalSize = sizeof(ParcelHeader) + header.dataSize + header.objectsSize;
if (maxSize < totalSize)
throw exception("The size of the parcel exceeds maxSize");
state.process->WriteMemory(header, address);
state.process->WriteMemory(data.data(), address + header.dataOffset, data.size());
state.process->WriteMemory(objects.data(), address + header.objectsOffset, objects.size());
return totalSize;
}
}

View File

@ -10,7 +10,7 @@ namespace skyline::service {
class Parcel {
private:
/**
* @brief This holds the header of a parcel
* @brief The header of an Android Parcel structure
*/
struct ParcelHeader {
u32 dataSize;
@ -30,16 +30,18 @@ namespace skyline::service {
* @brief This constructor fills in the Parcel object with data from a IPC buffer
* @param buffer The buffer that contains the parcel
* @param state The state of the device
* @param hasToken If the parcel starts with a token, it is skipped if this flag is true
*/
Parcel(kernel::ipc::InputBuffer &buffer, const DeviceState &state);
Parcel(kernel::ipc::InputBuffer &buffer, const DeviceState &state, bool hasToken = false);
/**
* @brief This constructor fills in the Parcel object with data from a Parcel on a remote process
* @param address The remote address of the parcel
* @param size The size of the parcel
* @param state The state of the device
* @param hasToken If the parcel starts with a token, it is skipped if this flag is true
*/
Parcel(u64 address, u64 size, const DeviceState &state);
Parcel(u64 address, u64 size, const DeviceState &state, bool hasToken = false);
/**
* @brief This constructor is used to create an empty parcel then write to a process

View File

@ -6,7 +6,7 @@ namespace skyline::service::hid {
}) {}
void IAppletResource::GetSharedMemoryHandle(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
hidSharedMemory = std::make_shared<kernel::type::KSharedMemory>(state, NULL, constant::hidSharedMemSize, memory::Permission{true, false, false});
hidSharedMemory = std::make_shared<kernel::type::KSharedMemory>(state, NULL, constant::HidSharedMemSize, memory::Permission{true, false, false});
auto handle = state.process->InsertItem<type::KSharedMemory>(hidSharedMemory);
state.logger->Debug("HID Shared Memory Handle: 0x{:X}", handle);
response.copyHandles.push_back(handle);

View File

@ -3,24 +3,25 @@
#include <kernel/types/KProcess.h>
#include <services/base_service.h>
#include <services/serviceman.h>
namespace skyline::service::hid {
namespace skyline {
namespace constant {
constexpr size_t hidSharedMemSize = 0x40000; //!< The size of HID Shared Memory (https://switchbrew.org/wiki/HID_Shared_Memory)
constexpr auto HidSharedMemSize = 0x40000; //!< The size of HID Shared Memory (https://switchbrew.org/wiki/HID_Shared_Memory)
}
/**
* @brief IAppletResource is used to get a handle to the HID shared memory (https://switchbrew.org/wiki/HID_services#IAppletResource)
*/
class IAppletResource : public BaseService {
public:
std::shared_ptr <type::KSharedMemory> hidSharedMemory; //!< A pointer to HID shared memory
IAppletResource(const DeviceState &state, ServiceManager &manager);
namespace service::hid {
/**
* @brief This opens a handle to HID shared memory (https://switchbrew.org/wiki/HID_services#GetSharedMemoryHandle)
* @brief IAppletResource is used to get a handle to the HID shared memory (https://switchbrew.org/wiki/HID_services#IAppletResource)
*/
void GetSharedMemoryHandle(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);
};
class IAppletResource : public BaseService {
public:
std::shared_ptr<type::KSharedMemory> hidSharedMemory; //!< A pointer to HID shared memory
IAppletResource(const DeviceState &state, ServiceManager &manager);
/**
* @brief This opens a handle to HID shared memory (https://switchbrew.org/wiki/HID_services#GetSharedMemoryHandle)
*/
void GetSharedMemoryHandle(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);
};
}
}

View File

@ -14,7 +14,7 @@ namespace skyline::service::hosbinder {
}) {}
void IHOSBinderDriver::RequestBuffer(Parcel &in, Parcel &out) {
u32 slot = *reinterpret_cast<u32 *>(in.data.data() + constant::TokenLength);
u32 slot = *reinterpret_cast<u32 *>(in.data.data());
out.WriteData<u32>(1);
out.WriteData<u32>(sizeof(GbpBuffer));
out.WriteData<u32>(0);
@ -29,7 +29,7 @@ namespace skyline::service::hosbinder {
u32 height;
u32 timestamps;
u32 usage;
} *data = reinterpret_cast<Data *>(in.data.data() + constant::TokenLength);
} *data = reinterpret_cast<Data *>(in.data.data());
i64 slot{-1};
while (slot == -1) {
@ -66,7 +66,7 @@ namespace skyline::service::hosbinder {
u64 _unk0_;
u32 swapInterval;
Fence fence[4];
} *data = reinterpret_cast<Data *>(in.data.data() + constant::TokenLength);
} *data = reinterpret_cast<Data *>(in.data.data());
auto buffer = queue.at(data->slot);
buffer->status = BufferStatus::Queued;
@ -100,13 +100,13 @@ namespace skyline::service::hosbinder {
struct Data {
u32 slot;
Fence fence[4];
} *data = reinterpret_cast<Data *>(parcel.data.data() + constant::TokenLength);
} *data = reinterpret_cast<Data *>(parcel.data.data());
FreeBuffer(data->slot);
state.logger->Debug("CancelBuffer: Slot: {}", data->slot);
}
void IHOSBinderDriver::SetPreallocatedBuffer(Parcel &parcel) {
auto pointer = parcel.data.data() + constant::TokenLength;
auto pointer = parcel.data.data();
struct Data {
u32 slot;
u32 _unk0_;
@ -159,7 +159,7 @@ namespace skyline::service::hosbinder {
auto layerId = request.Pop<u32>();
auto code = request.Pop<TransactionCode>();
Parcel in(request.inputBuf.at(0), state);
Parcel in(request.inputBuf.at(0), state, true);
Parcel out(state);
state.logger->Debug("TransactParcel: Layer ID: {}, Code: {}", layerId, code);
@ -211,7 +211,7 @@ namespace skyline::service::hosbinder {
}
void IHOSBinderDriver::GetNativeHandle(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
handle_t handle = state.process->InsertItem(state.gpu->bufferEvent);
KHandle handle = state.process->InsertItem(state.gpu->bufferEvent);
state.logger->Debug("Display Buffer Event Handle: 0x{:X}", handle);
response.copyHandles.push_back(handle);
response.Push<u32>(constant::status::Success);
@ -219,7 +219,7 @@ namespace skyline::service::hosbinder {
void IHOSBinderDriver::SetDisplay(const std::string &name) {
try {
const auto type = displayTypeMap.at(name);
const auto type = DisplayTypeMap.at(name);
if (displayId == DisplayId::Null)
displayId = type;
else

View File

@ -17,7 +17,7 @@ namespace skyline::service::hosbinder {
/**
* @brief A mapping from a display's name to it's displayType entry
*/
static const std::unordered_map <std::string, DisplayId> displayTypeMap{
static const std::unordered_map <std::string, DisplayId> DisplayTypeMap{
{"Default", DisplayId::Default},
{"External", DisplayId::External},
{"Edid", DisplayId::Edid},

View File

@ -32,8 +32,8 @@ namespace skyline::service::nvdrv::device {
NvMapObject(u32 id, u32 size);
};
std::unordered_map<handle_t, std::shared_ptr<NvMapObject>> handleTable; //!< A mapping from a handle to it's corresponding NvMapObject
handle_t handleIndex{1}; //!< This is used to keep track of the next handle to allocate
std::unordered_map<KHandle, std::shared_ptr<NvMapObject>> handleTable; //!< A mapping from a handle to it's corresponding NvMapObject
KHandle handleIndex{1}; //!< This is used to keep track of the next handle to allocate
u32 idIndex{1}; //!< This is used to keep track of the next ID to allocate
NvMap(const DeviceState &state);

View File

@ -70,7 +70,7 @@ namespace skyline::service {
return serviceObj;
}
handle_t ServiceManager::NewSession(const Service serviceType) {
KHandle ServiceManager::NewSession(const Service serviceType) {
std::lock_guard serviceGuard(mutex);
return state.process->NewHandle<type::KSession>(CreateService(serviceType)).handle;
}
@ -78,7 +78,7 @@ namespace skyline::service {
std::shared_ptr<BaseService> ServiceManager::NewService(const std::string &serviceName, type::KSession &session, ipc::IpcResponse &response) {
std::lock_guard serviceGuard(mutex);
auto serviceObject = CreateService(ServiceString.at(serviceName));
handle_t handle{};
KHandle handle{};
if (response.isDomain) {
session.domainTable[++session.handleIndex] = serviceObject;
response.domainObjects.push_back(session.handleIndex);
@ -93,7 +93,7 @@ namespace skyline::service {
void ServiceManager::RegisterService(std::shared_ptr<BaseService> serviceObject, type::KSession &session, ipc::IpcResponse &response, bool submodule) { // NOLINT(performance-unnecessary-value-param)
std::lock_guard serviceGuard(mutex);
handle_t handle{};
KHandle handle{};
if (response.isDomain) {
session.domainTable[session.handleIndex] = serviceObject;
response.domainObjects.push_back(session.handleIndex);
@ -107,7 +107,7 @@ namespace skyline::service {
state.logger->Debug("Service has been registered: \"{}\" (0x{:X})", serviceObject->serviceName, handle);
}
void ServiceManager::CloseSession(const handle_t handle) {
void ServiceManager::CloseSession(const KHandle handle) {
std::lock_guard serviceGuard(mutex);
auto session = state.process->GetHandle<type::KSession>(handle);
if (session->serviceStatus == type::KSession::ServiceStatus::Open) {
@ -121,7 +121,7 @@ namespace skyline::service {
}
};
void ServiceManager::SyncRequestHandler(const handle_t handle) {
void ServiceManager::SyncRequestHandler(const KHandle handle) {
auto session = state.process->GetHandle<type::KSession>(handle);
state.logger->Debug("----Start----");
state.logger->Debug("Handle is 0x{:X}", handle);

View File

@ -32,7 +32,7 @@ namespace skyline::service {
* @param serviceType The type of the service
* @return Handle to KService object of the service
*/
handle_t NewSession(const Service serviceType);
KHandle NewSession(const Service serviceType);
/**
* @brief Creates a new service using it's type enum and writes it's handle or virtual handle (If it's a domain request) to IpcResponse
@ -66,12 +66,12 @@ namespace skyline::service {
* @brief Closes an existing session to a service
* @param service The handle of the KService object
*/
void CloseSession(const handle_t handle);
void CloseSession(const KHandle handle);
/**
* @brief Handles a Synchronous IPC Request
* @param handle The handle of the object
*/
void SyncRequestHandler(const handle_t handle);
void SyncRequestHandler(const KHandle handle);
};
}

View File

@ -17,11 +17,11 @@ namespace skyline::service::timesrv {
};
response.Push(calendarTime);
CalendarAdditionalInfo calendarInfo{
.day_week = static_cast<u32>(calender.tm_wday),
.day_month = static_cast<u32>(calender.tm_mday),
.dayWeek = static_cast<u32>(calender.tm_wday),
.dayMonth = static_cast<u32>(calender.tm_mday),
.name = *reinterpret_cast<const u64 *>(calender.tm_zone),
.dst = static_cast<i32>(calender.tm_isdst),
.utc_rel = static_cast<u32>(calender.tm_gmtoff)
.utcRel = static_cast<u32>(calender.tm_gmtoff)
};
response.Push(calendarInfo);
}

View File

@ -27,11 +27,11 @@ namespace skyline::service::timesrv {
* @brief This is passed in addition to CalendarTime
*/
struct CalendarAdditionalInfo {
u32 day_week;
u32 day_month;
u32 dayWeek;
u32 dayMonth;
u64 name;
i32 dst;
u32 utc_rel;
u32 utcRel;
};
static_assert(sizeof(CalendarAdditionalInfo) == 0x18);

View File

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