mirror of
https://github.com/skyline-emu/skyline.git
synced 2024-12-28 08:15:29 +03:00
Add Mutexes to Logger, Introduce util::MakeMagic
and Refactor IPC
This commit adds mutexes to the logger so they produce a valid log file rather than breaking due to a race condition. It also introduced `util::MakeMagic` so the magic functions are far more clear. A small refactor of IPC was also done which cleared up some of the for loops.
This commit is contained in:
parent
91644255da
commit
af98455ede
@ -24,7 +24,7 @@ namespace skyline {
|
||||
void GroupMutex::lock(Group group) {
|
||||
auto none = Group::None;
|
||||
constexpr u64 timeout = 100; // The timeout in ns
|
||||
auto end = utils::GetTimeNs() + timeout;
|
||||
auto end = util::GetTimeNs() + timeout;
|
||||
|
||||
while (true) {
|
||||
if (next == group) {
|
||||
@ -41,7 +41,7 @@ namespace skyline {
|
||||
} else {
|
||||
flag.compare_exchange_weak(none, group);
|
||||
}
|
||||
} else if (flag == group && (next == Group::None || utils::GetTimeNs() >= end)) {
|
||||
} else if (flag == group && (next == Group::None || util::GetTimeNs() >= end)) {
|
||||
std::lock_guard lock(mtx);
|
||||
|
||||
if (flag == group) {
|
||||
@ -127,13 +127,14 @@ namespace skyline {
|
||||
|
||||
Logger::~Logger() {
|
||||
WriteHeader("Logging ended");
|
||||
logFile.flush();
|
||||
}
|
||||
|
||||
void Logger::WriteHeader(const std::string &str) {
|
||||
syslog(LOG_ALERT, "%s", str.c_str());
|
||||
|
||||
std::lock_guard guard(mtx);
|
||||
logFile << "0|" << str << "\n";
|
||||
logFile.flush();
|
||||
}
|
||||
|
||||
void Logger::Write(const LogLevel level, std::string str) {
|
||||
@ -143,12 +144,12 @@ namespace skyline {
|
||||
if (character == '\n')
|
||||
character = '\\';
|
||||
|
||||
std::lock_guard guard(mtx);
|
||||
logFile << "1|" << levelStr[static_cast<u8>(level)] << "|" << str << "\n";
|
||||
logFile.flush();
|
||||
}
|
||||
|
||||
DeviceState::DeviceState(kernel::OS *os, std::shared_ptr<kernel::type::KProcess> &process, std::shared_ptr<JvmManager> jvmManager, std::shared_ptr<Settings> settings, std::shared_ptr<Logger> logger)
|
||||
: os(os), jvmManager(std::move(jvmManager)), settings(std::move(settings)), logger(std::move(logger)), process(process) {
|
||||
: os(os), jvm(std::move(jvmManager)), settings(std::move(settings)), logger(std::move(logger)), process(process) {
|
||||
// We assign these later as they use the state in their constructor and we don't want null pointers
|
||||
nce = std::move(std::make_shared<NCE>(*this));
|
||||
gpu = std::move(std::make_shared<gpu::GPU>(*this));
|
||||
|
@ -68,7 +68,7 @@ namespace skyline {
|
||||
NSP, //!< The NSP format from "nspwn" exploit: https://switchbrew.org/wiki/Switch_System_Flaws
|
||||
};
|
||||
|
||||
namespace utils {
|
||||
namespace util {
|
||||
/**
|
||||
* @brief Returns the current time in nanoseconds
|
||||
* @return The current time in nanoseconds
|
||||
@ -93,7 +93,7 @@ namespace skyline {
|
||||
* @return The aligned value
|
||||
*/
|
||||
template<typename TypeVal, typename TypeMul>
|
||||
inline TypeVal AlignUp(TypeVal value, TypeMul multiple) {
|
||||
constexpr inline TypeVal AlignUp(TypeVal value, TypeMul multiple) {
|
||||
static_assert(std::is_integral<TypeVal>() && std::is_integral<TypeMul>());
|
||||
multiple--;
|
||||
return (value + multiple) & ~(multiple);
|
||||
@ -108,7 +108,7 @@ namespace skyline {
|
||||
* @return The aligned value
|
||||
*/
|
||||
template<typename TypeVal, typename TypeMul>
|
||||
inline TypeVal AlignDown(TypeVal value, TypeMul multiple) {
|
||||
constexpr inline TypeVal AlignDown(TypeVal value, TypeMul multiple) {
|
||||
static_assert(std::is_integral<TypeVal>() && std::is_integral<TypeMul>());
|
||||
return value & ~(multiple - 1);
|
||||
}
|
||||
@ -117,7 +117,7 @@ namespace skyline {
|
||||
* @param address The address to check for alignment
|
||||
* @return If the address is page aligned
|
||||
*/
|
||||
inline bool PageAligned(u64 address) {
|
||||
constexpr inline bool PageAligned(u64 address) {
|
||||
return !(address & (PAGE_SIZE - 1U));
|
||||
}
|
||||
|
||||
@ -125,9 +125,26 @@ namespace skyline {
|
||||
* @param address The address to check for alignment
|
||||
* @return If the address is word aligned
|
||||
*/
|
||||
inline bool WordAligned(u64 address) {
|
||||
constexpr inline bool WordAligned(u64 address) {
|
||||
return !(address & 3U);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string The string to create a magic from
|
||||
* @return The magic of the supplied string
|
||||
*/
|
||||
template<typename Type>
|
||||
constexpr Type MakeMagic(std::string_view string) {
|
||||
Type object{};
|
||||
auto offset = 0;
|
||||
|
||||
for(auto& character : string) {
|
||||
object |= static_cast<Type>(character) << offset;
|
||||
offset += sizeof(character) * 8;
|
||||
}
|
||||
|
||||
return object;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -198,6 +215,7 @@ namespace skyline {
|
||||
std::ofstream logFile; //!< An output stream to the log file
|
||||
const char *levelStr[4] = {"0", "1", "2", "3"}; //!< This is used to denote the LogLevel when written out to a file
|
||||
static constexpr int levelSyslog[4] = {LOG_ERR, LOG_WARNING, LOG_INFO, LOG_DEBUG}; //!< This corresponds to LogLevel and provides it's equivalent for syslog
|
||||
Mutex mtx; //!< A mutex to lock before logging anything
|
||||
|
||||
public:
|
||||
enum class LogLevel { Error, Warn, Info, Debug }; //!< The level of a particular log
|
||||
@ -360,7 +378,7 @@ namespace skyline {
|
||||
std::shared_ptr<NCE> nce; //!< This holds a reference to the NCE class
|
||||
std::shared_ptr<gpu::GPU> gpu; //!< This holds a reference to the GPU class
|
||||
std::shared_ptr<audio::Audio> audio; //!< This holds a reference to the Audio class
|
||||
std::shared_ptr<JvmManager> jvmManager; //!< This holds a reference to the JvmManager class
|
||||
std::shared_ptr<JvmManager> jvm; //!< This holds a reference to the JvmManager class
|
||||
std::shared_ptr<Settings> settings; //!< This holds a reference to the Settings class
|
||||
std::shared_ptr<Logger> logger; //!< This holds a reference to the Logger class
|
||||
};
|
||||
|
@ -10,7 +10,7 @@ extern bool Halt;
|
||||
extern jobject Surface;
|
||||
|
||||
namespace skyline::gpu {
|
||||
GPU::GPU(const DeviceState &state) : state(state), window(ANativeWindow_fromSurface(state.jvmManager->GetEnv(), Surface)), vsyncEvent(std::make_shared<kernel::type::KEvent>(state)), bufferEvent(std::make_shared<kernel::type::KEvent>(state)) {
|
||||
GPU::GPU(const DeviceState &state) : state(state), window(ANativeWindow_fromSurface(state.jvm->GetEnv(), Surface)), vsyncEvent(std::make_shared<kernel::type::KEvent>(state)), bufferEvent(std::make_shared<kernel::type::KEvent>(state)) {
|
||||
ANativeWindow_acquire(window);
|
||||
resolution.width = static_cast<u32>(ANativeWindow_getWidth(window));
|
||||
resolution.height = static_cast<u32>(ANativeWindow_getHeight(window));
|
||||
@ -25,7 +25,7 @@ namespace skyline::gpu {
|
||||
if (surfaceUpdate) {
|
||||
if (Surface == nullptr)
|
||||
return;
|
||||
window = ANativeWindow_fromSurface(state.jvmManager->GetEnv(), Surface);
|
||||
window = ANativeWindow_fromSurface(state.jvm->GetEnv(), Surface);
|
||||
ANativeWindow_acquire(window);
|
||||
resolution.width = static_cast<u32>(ANativeWindow_getWidth(window));
|
||||
resolution.height = static_cast<u32>(ANativeWindow_getHeight(window));
|
||||
@ -51,7 +51,7 @@ namespace skyline::gpu {
|
||||
ARect rect;
|
||||
|
||||
ANativeWindow_lock(window, &windowBuffer, &rect);
|
||||
memcpy(windowBuffer.bits, texture->backing.data(), texture->backing.size());
|
||||
std::memcpy(windowBuffer.bits, texture->backing.data(), texture->backing.size());
|
||||
ANativeWindow_unlockAndPost(window);
|
||||
|
||||
vsyncEvent->Signal();
|
||||
|
@ -26,8 +26,8 @@ namespace skyline::gpu {
|
||||
constexpr auto gobHeight = 8; // The height of a GOB in lines
|
||||
|
||||
auto robHeight = gobHeight * guest->tileConfig.blockHeight; // The height of a single ROB (Row of Blocks) in lines
|
||||
auto surfaceHeightRobs = utils::AlignUp(dimensions.height / format.blockHeight, robHeight) / robHeight; // The height of the surface in ROBs (Row Of Blocks)
|
||||
auto robWidthBytes = utils::AlignUp((guest->tileConfig.surfaceWidth / format.blockWidth) * format.bpb, gobWidth); // The width of a ROB in bytes
|
||||
auto surfaceHeightRobs = util::AlignUp(dimensions.height / format.blockHeight, robHeight) / robHeight; // The height of the surface in ROBs (Row Of Blocks)
|
||||
auto robWidthBytes = util::AlignUp((guest->tileConfig.surfaceWidth / format.blockWidth) * format.bpb, gobWidth); // The width of a ROB in bytes
|
||||
auto robWidthBlocks = robWidthBytes / gobWidth; // The width of a ROB in blocks (and GOBs because block width == 1 on the Tegra X1)
|
||||
auto robBytes = robWidthBytes * robHeight; // The size of a ROB in bytes
|
||||
auto gobYOffset = robWidthBytes * gobHeight; // The offset of the next Y-axis GOB from the current one in linear space
|
||||
|
@ -25,17 +25,17 @@ namespace skyline::kernel::ipc {
|
||||
if (header->handleDesc) {
|
||||
handleDesc = reinterpret_cast<HandleDescriptor *>(pointer);
|
||||
pointer += sizeof(HandleDescriptor) + (handleDesc->sendPid ? sizeof(u64) : 0);
|
||||
for (uint index = 0; handleDesc->copyCount > index; index++) {
|
||||
for (u32 index = 0; handleDesc->copyCount > index; index++) {
|
||||
copyHandles.push_back(*reinterpret_cast<KHandle *>(pointer));
|
||||
pointer += sizeof(KHandle);
|
||||
}
|
||||
for (uint index = 0; handleDesc->moveCount > index; index++) {
|
||||
for (u32 index = 0; handleDesc->moveCount > index; index++) {
|
||||
moveHandles.push_back(*reinterpret_cast<KHandle *>(pointer));
|
||||
pointer += sizeof(KHandle);
|
||||
}
|
||||
}
|
||||
|
||||
for (uint index = 0; header->xNo > index; index++) {
|
||||
for (u8 index = 0; header->xNo > index; index++) {
|
||||
auto bufX = reinterpret_cast<BufferDescriptorX *>(pointer);
|
||||
if (bufX->Address()) {
|
||||
inputBuf.emplace_back(bufX);
|
||||
@ -44,7 +44,7 @@ namespace skyline::kernel::ipc {
|
||||
pointer += sizeof(BufferDescriptorX);
|
||||
}
|
||||
|
||||
for (uint index = 0; header->aNo > index; index++) {
|
||||
for (u8 index = 0; header->aNo > index; index++) {
|
||||
auto bufA = reinterpret_cast<BufferDescriptorABW *>(pointer);
|
||||
if (bufA->Address()) {
|
||||
inputBuf.emplace_back(bufA);
|
||||
@ -53,7 +53,7 @@ namespace skyline::kernel::ipc {
|
||||
pointer += sizeof(BufferDescriptorABW);
|
||||
}
|
||||
|
||||
for (uint index = 0; header->bNo > index; index++) {
|
||||
for (u8 index = 0; header->bNo > index; index++) {
|
||||
auto bufB = reinterpret_cast<BufferDescriptorABW *>(pointer);
|
||||
if (bufB->Address()) {
|
||||
outputBuf.emplace_back(bufB);
|
||||
@ -62,7 +62,7 @@ namespace skyline::kernel::ipc {
|
||||
pointer += sizeof(BufferDescriptorABW);
|
||||
}
|
||||
|
||||
for (uint index = 0; header->wNo > index; index++) {
|
||||
for (u8 index = 0; header->wNo > index; index++) {
|
||||
auto bufW = reinterpret_cast<BufferDescriptorABW *>(pointer);
|
||||
if (bufW->Address()) {
|
||||
inputBuf.emplace_back(bufW, IpcBufferType::W);
|
||||
@ -72,9 +72,8 @@ namespace skyline::kernel::ipc {
|
||||
pointer += sizeof(BufferDescriptorABW);
|
||||
}
|
||||
|
||||
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
|
||||
auto offset = reinterpret_cast<u64>(pointer) - reinterpret_cast<u64>(tls); // We calculate the relative offset as the absolute one might differ
|
||||
auto padding = util::AlignUp(offset, constant::IpcPaddingSum) - offset; // Calculate the amount of padding at the front
|
||||
pointer += padding;
|
||||
|
||||
if (isDomain && (header->type == CommandType::Request)) {
|
||||
@ -88,7 +87,7 @@ namespace skyline::kernel::ipc {
|
||||
cmdArgSz = domain->payloadSz - sizeof(PayloadHeader);
|
||||
pointer += domain->payloadSz;
|
||||
|
||||
for (uint index = 0; domain->inputCount > index; index++) {
|
||||
for (u8 index = 0; domain->inputCount > index; index++) {
|
||||
domainObjects.push_back(*reinterpret_cast<KHandle *>(pointer));
|
||||
pointer += sizeof(KHandle);
|
||||
}
|
||||
@ -97,18 +96,16 @@ namespace skyline::kernel::ipc {
|
||||
pointer += sizeof(PayloadHeader);
|
||||
|
||||
cmdArg = pointer;
|
||||
cmdArgSz = (header->rawSize * sizeof(u32)) - (ipcPaddingSum + sizeof(PayloadHeader));
|
||||
cmdArgSz = (header->rawSize * sizeof(u32)) - (constant::IpcPaddingSum + sizeof(PayloadHeader));
|
||||
pointer += cmdArgSz;
|
||||
}
|
||||
|
||||
payloadOffset = cmdArg;
|
||||
|
||||
constexpr auto sfciMagic = 0x49434653; //!< SFCI in reverse, present in received IPC messages
|
||||
|
||||
if (payload->magic != sfciMagic && header->type != CommandType::Control)
|
||||
if (payload->magic != util::MakeMagic<u32>("SFCI") && header->type != CommandType::Control) // SFCI is the magic in received IPC messages
|
||||
state.logger->Debug("Unexpected Magic in PayloadHeader: 0x{:X}", u32(payload->magic));
|
||||
|
||||
pointer += ipcPaddingSum - padding;
|
||||
pointer += constant::IpcPaddingSum - padding;
|
||||
|
||||
if (header->cFlag == BufferCFlag::SingleDescriptor) {
|
||||
auto bufC = reinterpret_cast<BufferDescriptorC *>(pointer);
|
||||
@ -117,7 +114,7 @@ namespace skyline::kernel::ipc {
|
||||
state.logger->Debug("Buf C: AD: 0x{:X} SZ: 0x{:X}", u64(bufC->address), u16(bufC->size));
|
||||
}
|
||||
} else if (header->cFlag > BufferCFlag::SingleDescriptor) {
|
||||
for (uint index = 0; (static_cast<u8>(header->cFlag) - 2) > index; index++) { // (cFlag - 2) C descriptors are present
|
||||
for (u8 index = 0; (static_cast<u8>(header->cFlag) - 2) > index; index++) { // (cFlag - 2) C descriptors are present
|
||||
auto bufC = reinterpret_cast<BufferDescriptorC *>(pointer);
|
||||
if (bufC->address) {
|
||||
outputBuf.emplace_back(bufC);
|
||||
@ -143,13 +140,10 @@ namespace skyline::kernel::ipc {
|
||||
auto tls = state.process->GetPointer<u8>(state.thread->tls);
|
||||
u8 *pointer = tls;
|
||||
|
||||
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
|
||||
memset(tls, 0, constant::TlsIpcSize);
|
||||
|
||||
auto header = reinterpret_cast<CommandHeader *>(pointer);
|
||||
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->rawSize = static_cast<u32>((sizeof(PayloadHeader) + argVec.size() + (domainObjects.size() * sizeof(KHandle)) + constant::IpcPaddingSum + (isDomain ? sizeof(DomainHeaderRequest) : 0)) / sizeof(u32)); // Size is in 32-bit units because Nintendo
|
||||
header->handleDesc = (!copyHandles.empty() || !moveHandles.empty());
|
||||
pointer += sizeof(CommandHeader);
|
||||
|
||||
@ -159,18 +153,19 @@ namespace skyline::kernel::ipc {
|
||||
handleDesc->moveCount = static_cast<u8>(moveHandles.size());
|
||||
pointer += sizeof(HandleDescriptor);
|
||||
|
||||
for (unsigned int copyHandle : copyHandles) {
|
||||
for (auto copyHandle : copyHandles) {
|
||||
*reinterpret_cast<KHandle *>(pointer) = copyHandle;
|
||||
pointer += sizeof(KHandle);
|
||||
}
|
||||
|
||||
for (unsigned int moveHandle : moveHandles) {
|
||||
for (auto moveHandle : moveHandles) {
|
||||
*reinterpret_cast<KHandle *>(pointer) = moveHandle;
|
||||
pointer += sizeof(KHandle);
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
auto offset = reinterpret_cast<u64>(pointer) - reinterpret_cast<u64>(tls); // We calculate the relative offset as the absolute one might differ
|
||||
auto padding = util::AlignUp(offset, constant::IpcPaddingSum) - offset; // Calculate the amount of padding at the front
|
||||
pointer += padding;
|
||||
|
||||
if (isDomain) {
|
||||
@ -179,16 +174,14 @@ 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 = sfcoMagic;
|
||||
payload->magic = util::MakeMagic<u32>("SFCO"); // SFCO is the magic in IPC responses
|
||||
payload->version = 1;
|
||||
payload->value = errorCode;
|
||||
pointer += sizeof(PayloadHeader);
|
||||
|
||||
if (!argVec.empty())
|
||||
memcpy(pointer, argVec.data(), argVec.size());
|
||||
std::memcpy(pointer, argVec.data(), argVec.size());
|
||||
pointer += argVec.size();
|
||||
|
||||
if (isDomain) {
|
||||
|
@ -6,325 +6,332 @@
|
||||
#include <array>
|
||||
#include <common.h>
|
||||
|
||||
namespace skyline::kernel::ipc {
|
||||
/**
|
||||
* @brief This reflects the value in CommandStruct::type
|
||||
*/
|
||||
enum class CommandType : u16 {
|
||||
Invalid = 0, LegacyRequest = 1, Close = 2, LegacyControl = 3, Request = 4, Control = 5, RequestWithContext = 6, ControlWithContext = 7
|
||||
};
|
||||
namespace skyline {
|
||||
namespace constant {
|
||||
constexpr auto IpcPaddingSum = 0x10; // The sum of the padding surrounding the data payload
|
||||
constexpr auto TlsIpcSize = 0x100; // The size of the IPC command buffer in a TLS slot
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This reflects the value in CommandStruct::c_flags
|
||||
*/
|
||||
enum class BufferCFlag : u8 {
|
||||
None = 0, InlineDescriptor = 1, SingleDescriptor = 2
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief This bit-field structure holds the header of an IPC command. (https://switchbrew.org/wiki/IPC_Marshalling#IPC_Command_Structure)
|
||||
*/
|
||||
struct CommandHeader {
|
||||
CommandType type : 16;
|
||||
u8 xNo : 4;
|
||||
u8 aNo : 4;
|
||||
u8 bNo : 4;
|
||||
u8 wNo : 4;
|
||||
u32 rawSize : 10;
|
||||
BufferCFlag cFlag : 4;
|
||||
u32 : 17;
|
||||
bool handleDesc : 1;
|
||||
};
|
||||
static_assert(sizeof(CommandHeader) == 8);
|
||||
|
||||
/**
|
||||
* @brief This bit-field structure holds the handle descriptor of a received IPC command. (https://switchbrew.org/wiki/IPC_Marshalling#Handle_descriptor)
|
||||
*/
|
||||
struct HandleDescriptor {
|
||||
bool sendPid : 1;
|
||||
u32 copyCount : 4;
|
||||
u32 moveCount : 4;
|
||||
u32 : 23;
|
||||
};
|
||||
static_assert(sizeof(HandleDescriptor) == 4);
|
||||
|
||||
/**
|
||||
* @brief This bit-field structure holds the domain's header of an IPC request command. (https://switchbrew.org/wiki/IPC_Marshalling#Domains)
|
||||
*/
|
||||
struct DomainHeaderRequest {
|
||||
u8 command;
|
||||
u8 inputCount;
|
||||
u16 payloadSz;
|
||||
u32 objectId;
|
||||
u32 : 32;
|
||||
u32 token;
|
||||
};
|
||||
static_assert(sizeof(DomainHeaderRequest) == 16);
|
||||
|
||||
/**
|
||||
* @brief This reflects the value of DomainHeaderRequest::command
|
||||
*/
|
||||
enum class DomainCommand : u8 {
|
||||
SendMessage = 1, CloseVHandle = 2
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief This bit-field structure holds the domain's header of an IPC response command. (https://switchbrew.org/wiki/IPC_Marshalling#Domains)
|
||||
*/
|
||||
struct DomainHeaderResponse {
|
||||
u32 outputCount;
|
||||
u32 : 32;
|
||||
u64 : 64;
|
||||
};
|
||||
static_assert(sizeof(DomainHeaderResponse) == 16);
|
||||
|
||||
/**
|
||||
* @brief This bit-field structure holds the data payload of an IPC command. (https://switchbrew.org/wiki/IPC_Marshalling#Data_payload)
|
||||
*/
|
||||
struct PayloadHeader {
|
||||
u32 magic;
|
||||
u32 version;
|
||||
u32 value;
|
||||
u32 token;
|
||||
};
|
||||
static_assert(sizeof(PayloadHeader) == 16);
|
||||
|
||||
|
||||
/**
|
||||
* @brief This reflects which function PayloadHeader::value refers to when a control request is sent (https://switchbrew.org/wiki/IPC_Marshalling#Control)
|
||||
*/
|
||||
enum class ControlCommand : u32 {
|
||||
ConvertCurrentObjectToDomain = 0, CopyFromCurrentDomain = 1, CloneCurrentObject = 2, QueryPointerBufferSize = 3, CloneCurrentObjectEx = 4
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief This is a buffer descriptor for X buffers: https://switchbrew.org/wiki/IPC_Marshalling#Buffer_descriptor_X_.22Pointer.22
|
||||
*/
|
||||
struct BufferDescriptorX {
|
||||
u16 counter0_5 : 6; //!< The first 5 bits of the counter
|
||||
u16 address36_38 : 3; //!< Bit 36-38 of the address
|
||||
u16 counter9_11 : 3; //!< Bit 9-11 of the counter
|
||||
u16 address32_35 : 4; //!< Bit 32-35 of the address
|
||||
u16 size : 16; //!< The 16 bit size of the buffer
|
||||
u32 address0_31 : 32; //!< The first 32-bits of the address
|
||||
|
||||
BufferDescriptorX(u64 address, u16 counter, u16 size) : size(size) {
|
||||
address0_31 = static_cast<u32>(address & 0x7FFFFFFF80000000);
|
||||
address32_35 = static_cast<u16>(address & 0x78000000);
|
||||
address36_38 = static_cast<u16>(address & 0x7000000);
|
||||
counter0_5 = static_cast<u16>(address & 0x7E00);
|
||||
counter9_11 = static_cast<u16>(address & 0x38);
|
||||
}
|
||||
namespace kernel::ipc {
|
||||
/**
|
||||
* @brief This reflects the value in CommandStruct::type
|
||||
*/
|
||||
enum class CommandType : u16 {
|
||||
Invalid = 0, LegacyRequest = 1, Close = 2, LegacyControl = 3, Request = 4, Control = 5, RequestWithContext = 6, ControlWithContext = 7
|
||||
};
|
||||
|
||||
/**
|
||||
* @return The address of the buffer
|
||||
* @brief This reflects the value in CommandStruct::c_flags
|
||||
*/
|
||||
inline u64 Address() const {
|
||||
return static_cast<u64>(address0_31) | static_cast<u64>(address32_35) << 32 | static_cast<u64>(address36_38) << 36;
|
||||
}
|
||||
enum class BufferCFlag : u8 {
|
||||
None = 0, InlineDescriptor = 1, SingleDescriptor = 2
|
||||
};
|
||||
|
||||
/**
|
||||
* @return The buffer counter
|
||||
* @brief This bit-field structure holds the header of an IPC command. (https://switchbrew.org/wiki/IPC_Marshalling#IPC_Command_Structure)
|
||||
*/
|
||||
inline u16 Counter() const {
|
||||
return static_cast<u16>(counter0_5) | static_cast<u16>(counter9_11) << 9;
|
||||
}
|
||||
};
|
||||
static_assert(sizeof(BufferDescriptorX) == 8);
|
||||
|
||||
/**
|
||||
* @brief This is a buffer descriptor for A/B/W buffers: https://switchbrew.org/wiki/IPC_Marshalling#Buffer_descriptor_A.2FB.2FW_.22Send.22.2F.22Receive.22.2F.22Exchange.22
|
||||
*/
|
||||
struct BufferDescriptorABW {
|
||||
u32 size0_31 : 32; //!< The first 32 bits of the size
|
||||
u32 address0_31 : 32; //!< The first 32 bits of the address
|
||||
u8 flags : 2; //!< The buffer flags
|
||||
u8 address36_38 : 3; //!< Bit 36-38 of the address
|
||||
u32 : 19;
|
||||
u8 size32_35 : 4; //!< Bit 32-35 of the size
|
||||
u8 address32_35 : 4; //!< Bit 32-35 of the address
|
||||
|
||||
BufferDescriptorABW(u64 address, u64 size) {
|
||||
address0_31 = static_cast<u32>(address & 0x7FFFFFFF80000000);
|
||||
address32_35 = static_cast<u8>(address & 0x78000000);
|
||||
address36_38 = static_cast<u8>(address & 0x7000000);
|
||||
size0_31 = static_cast<u32>(size & 0x7FFFFFFF80000000);
|
||||
size32_35 = static_cast<u8>(size & 0x78000000);
|
||||
}
|
||||
struct CommandHeader {
|
||||
CommandType type : 16;
|
||||
u8 xNo : 4;
|
||||
u8 aNo : 4;
|
||||
u8 bNo : 4;
|
||||
u8 wNo : 4;
|
||||
u32 rawSize : 10;
|
||||
BufferCFlag cFlag : 4;
|
||||
u32 : 17;
|
||||
bool handleDesc : 1;
|
||||
};
|
||||
static_assert(sizeof(CommandHeader) == 8);
|
||||
|
||||
/**
|
||||
* @return The address of the buffer
|
||||
* @brief This bit-field structure holds the handle descriptor of a received IPC command. (https://switchbrew.org/wiki/IPC_Marshalling#Handle_descriptor)
|
||||
*/
|
||||
inline u64 Address() const {
|
||||
return static_cast<u64>(address0_31) | static_cast<u64>(address32_35) << 32 | static_cast<u64>(address36_38) << 36;
|
||||
}
|
||||
struct HandleDescriptor {
|
||||
bool sendPid : 1;
|
||||
u32 copyCount : 4;
|
||||
u32 moveCount : 4;
|
||||
u32 : 23;
|
||||
};
|
||||
static_assert(sizeof(HandleDescriptor) == 4);
|
||||
|
||||
/**
|
||||
* @return The size of the buffer
|
||||
* @brief This bit-field structure holds the domain's header of an IPC request command. (https://switchbrew.org/wiki/IPC_Marshalling#Domains)
|
||||
*/
|
||||
inline u64 Size() const {
|
||||
return static_cast<u64>(size0_31) | static_cast<u64>(size32_35) << 32;
|
||||
}
|
||||
};
|
||||
static_assert(sizeof(BufferDescriptorABW) == 12);
|
||||
|
||||
/**
|
||||
* @brief This is a buffer descriptor for C buffers: https://switchbrew.org/wiki/IPC_Marshalling#Buffer_descriptor_C_.22ReceiveList.22
|
||||
*/
|
||||
struct BufferDescriptorC {
|
||||
u64 address : 48; //!< The 48-bit address of the buffer
|
||||
u32 size : 16; //!< The 16-bit size of the buffer
|
||||
|
||||
BufferDescriptorC(u64 address, u16 size) : address(address), size(size) {}
|
||||
};
|
||||
static_assert(sizeof(BufferDescriptorC) == 8);
|
||||
|
||||
/**
|
||||
* @brief This enumerates the types of IPC buffers
|
||||
*/
|
||||
enum class IpcBufferType {
|
||||
X, //!< This is a type-X buffer
|
||||
A, //!< This is a type-A buffer
|
||||
B, //!< This is a type-B buffer
|
||||
W, //!< This is a type-W buffer
|
||||
C //!< This is a type-C buffer
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Describes a buffer by holding the address and size
|
||||
*/
|
||||
struct IpcBuffer {
|
||||
u64 address; //!< The address of the buffer
|
||||
size_t size; //!< The size of the buffer
|
||||
IpcBufferType type; //!< The type of the buffer
|
||||
struct DomainHeaderRequest {
|
||||
u8 command;
|
||||
u8 inputCount;
|
||||
u16 payloadSz;
|
||||
u32 objectId;
|
||||
u32 : 32;
|
||||
u32 token;
|
||||
};
|
||||
static_assert(sizeof(DomainHeaderRequest) == 16);
|
||||
|
||||
/**
|
||||
* @param address The address of the buffer
|
||||
* @param size The size of the buffer
|
||||
* @param type The type of the buffer
|
||||
* @brief This reflects the value of DomainHeaderRequest::command
|
||||
*/
|
||||
IpcBuffer(u64 address, size_t size, IpcBufferType type);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief This holds an input IPC buffer
|
||||
*/
|
||||
struct InputBuffer : public IpcBuffer {
|
||||
/**
|
||||
* @param aBuf The X Buffer Descriptor that has contains the input data
|
||||
*/
|
||||
InputBuffer(kernel::ipc::BufferDescriptorX *xBuf);
|
||||
enum class DomainCommand : u8 {
|
||||
SendMessage = 1, CloseVHandle = 2
|
||||
};
|
||||
|
||||
/**
|
||||
* @param aBuf The A or W Buffer Descriptor that has contains the input data
|
||||
* @brief This bit-field structure holds the domain's header of an IPC response command. (https://switchbrew.org/wiki/IPC_Marshalling#Domains)
|
||||
*/
|
||||
InputBuffer(kernel::ipc::BufferDescriptorABW *aBuf, IpcBufferType type = IpcBufferType::A);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief This holds an output IPC buffer
|
||||
*/
|
||||
struct OutputBuffer : public IpcBuffer {
|
||||
/**
|
||||
* @param bBuf The B or W Buffer Descriptor that has to be outputted to
|
||||
*/
|
||||
OutputBuffer(kernel::ipc::BufferDescriptorABW *bBuf, IpcBufferType type = IpcBufferType::B);
|
||||
struct DomainHeaderResponse {
|
||||
u32 outputCount;
|
||||
u32 : 32;
|
||||
u64 : 64;
|
||||
};
|
||||
static_assert(sizeof(DomainHeaderResponse) == 16);
|
||||
|
||||
/**
|
||||
* @param cBuf The C Buffer Descriptor that has to be outputted to
|
||||
* @brief This bit-field structure holds the data payload of an IPC command. (https://switchbrew.org/wiki/IPC_Marshalling#Data_payload)
|
||||
*/
|
||||
OutputBuffer(kernel::ipc::BufferDescriptorC *cBuf);
|
||||
};
|
||||
struct PayloadHeader {
|
||||
u32 magic;
|
||||
u32 version;
|
||||
u32 value;
|
||||
u32 token;
|
||||
};
|
||||
static_assert(sizeof(PayloadHeader) == 16);
|
||||
|
||||
/**
|
||||
* @brief This class encapsulates an IPC Request (https://switchbrew.org/wiki/IPC_Marshalling)
|
||||
*/
|
||||
class IpcRequest {
|
||||
private:
|
||||
const DeviceState &state; //!< The state of the device
|
||||
u8 *payloadOffset; //!< This is the offset of the data read from the payload
|
||||
|
||||
public:
|
||||
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
|
||||
DomainHeaderRequest *domain{}; //!< In case this is a domain request, this holds data regarding it
|
||||
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<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
|
||||
|
||||
/**
|
||||
* @param isDomain If the following request is a domain request
|
||||
* @param state The state of the device
|
||||
* @brief This reflects which function PayloadHeader::value refers to when a control request is sent (https://switchbrew.org/wiki/IPC_Marshalling#Control)
|
||||
*/
|
||||
IpcRequest(bool isDomain, const DeviceState &state);
|
||||
enum class ControlCommand : u32 {
|
||||
ConvertCurrentObjectToDomain = 0, CopyFromCurrentDomain = 1, CloneCurrentObject = 2, QueryPointerBufferSize = 3, CloneCurrentObjectEx = 4
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief This returns a reference to an item from the top of the payload
|
||||
* @tparam ValueType The type of the object to read
|
||||
* @brief This is a buffer descriptor for X buffers: https://switchbrew.org/wiki/IPC_Marshalling#Buffer_descriptor_X_.22Pointer.22
|
||||
*/
|
||||
template<typename ValueType>
|
||||
inline ValueType &Pop() {
|
||||
ValueType &value = *reinterpret_cast<ValueType *>(payloadOffset);
|
||||
payloadOffset += sizeof(ValueType);
|
||||
return value;
|
||||
}
|
||||
struct BufferDescriptorX {
|
||||
u16 counter0_5 : 6; //!< The first 5 bits of the counter
|
||||
u16 address36_38 : 3; //!< Bit 36-38 of the address
|
||||
u16 counter9_11 : 3; //!< Bit 9-11 of the counter
|
||||
u16 address32_35 : 4; //!< Bit 32-35 of the address
|
||||
u16 size : 16; //!< The 16 bit size of the buffer
|
||||
u32 address0_31 : 32; //!< The first 32-bits of the address
|
||||
|
||||
/**
|
||||
* @brief This skips an object to pop off the top
|
||||
* @tparam ValueType The type of the object to skip
|
||||
*/
|
||||
template<typename ValueType>
|
||||
inline void Skip() {
|
||||
payloadOffset += sizeof(ValueType);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief This class encapsulates an IPC Response (https://switchbrew.org/wiki/IPC_Marshalling)
|
||||
*/
|
||||
class IpcResponse {
|
||||
private:
|
||||
std::vector<u8> argVec; //!< This holds all of the contents to be pushed to the payload
|
||||
const DeviceState &state; //!< The state of the device
|
||||
|
||||
public:
|
||||
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<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
|
||||
* @param state The state of the device
|
||||
*/
|
||||
IpcResponse(bool isDomain, const DeviceState &state);
|
||||
|
||||
/**
|
||||
* @brief Writes an object to the payload
|
||||
* @tparam ValueType The type of the object to write
|
||||
* @param value A reference to the object to be written
|
||||
*/
|
||||
template<typename ValueType>
|
||||
inline void Push(const ValueType &value) {
|
||||
argVec.reserve(argVec.size() + sizeof(ValueType));
|
||||
auto item = reinterpret_cast<const u8 *>(&value);
|
||||
for (uint index = 0; sizeof(ValueType) > index; index++) {
|
||||
argVec.push_back(*item);
|
||||
item++;
|
||||
BufferDescriptorX(u64 address, u16 counter, u16 size) : size(size) {
|
||||
address0_31 = static_cast<u32>(address & 0x7FFFFFFF80000000);
|
||||
address32_35 = static_cast<u16>(address & 0x78000000);
|
||||
address36_38 = static_cast<u16>(address & 0x7000000);
|
||||
counter0_5 = static_cast<u16>(address & 0x7E00);
|
||||
counter9_11 = static_cast<u16>(address & 0x38);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The address of the buffer
|
||||
*/
|
||||
inline u64 Address() const {
|
||||
return static_cast<u64>(address0_31) | static_cast<u64>(address32_35) << 32 | static_cast<u64>(address36_38) << 36;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The buffer counter
|
||||
*/
|
||||
inline u16 Counter() const {
|
||||
return static_cast<u16>(counter0_5) | static_cast<u16>(counter9_11) << 9;
|
||||
}
|
||||
};
|
||||
static_assert(sizeof(BufferDescriptorX) == 8);
|
||||
|
||||
/**
|
||||
* @brief Writes this IpcResponse object's contents into TLS
|
||||
* @brief This is a buffer descriptor for A/B/W buffers: https://switchbrew.org/wiki/IPC_Marshalling#Buffer_descriptor_A.2FB.2FW_.22Send.22.2F.22Receive.22.2F.22Exchange.22
|
||||
*/
|
||||
void WriteResponse();
|
||||
};
|
||||
struct BufferDescriptorABW {
|
||||
u32 size0_31 : 32; //!< The first 32 bits of the size
|
||||
u32 address0_31 : 32; //!< The first 32 bits of the address
|
||||
u8 flags : 2; //!< The buffer flags
|
||||
u8 address36_38 : 3; //!< Bit 36-38 of the address
|
||||
u32 : 19;
|
||||
u8 size32_35 : 4; //!< Bit 32-35 of the size
|
||||
u8 address32_35 : 4; //!< Bit 32-35 of the address
|
||||
|
||||
BufferDescriptorABW(u64 address, u64 size) {
|
||||
address0_31 = static_cast<u32>(address & 0x7FFFFFFF80000000);
|
||||
address32_35 = static_cast<u8>(address & 0x78000000);
|
||||
address36_38 = static_cast<u8>(address & 0x7000000);
|
||||
size0_31 = static_cast<u32>(size & 0x7FFFFFFF80000000);
|
||||
size32_35 = static_cast<u8>(size & 0x78000000);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The address of the buffer
|
||||
*/
|
||||
inline u64 Address() const {
|
||||
return static_cast<u64>(address0_31) | static_cast<u64>(address32_35) << 32 | static_cast<u64>(address36_38) << 36;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The size of the buffer
|
||||
*/
|
||||
inline u64 Size() const {
|
||||
return static_cast<u64>(size0_31) | static_cast<u64>(size32_35) << 32;
|
||||
}
|
||||
};
|
||||
static_assert(sizeof(BufferDescriptorABW) == 12);
|
||||
|
||||
/**
|
||||
* @brief This is a buffer descriptor for C buffers: https://switchbrew.org/wiki/IPC_Marshalling#Buffer_descriptor_C_.22ReceiveList.22
|
||||
*/
|
||||
struct BufferDescriptorC {
|
||||
u64 address : 48; //!< The 48-bit address of the buffer
|
||||
u32 size : 16; //!< The 16-bit size of the buffer
|
||||
|
||||
BufferDescriptorC(u64 address, u16 size) : address(address), size(size) {}
|
||||
};
|
||||
static_assert(sizeof(BufferDescriptorC) == 8);
|
||||
|
||||
/**
|
||||
* @brief This enumerates the types of IPC buffers
|
||||
*/
|
||||
enum class IpcBufferType {
|
||||
X, //!< This is a type-X buffer
|
||||
A, //!< This is a type-A buffer
|
||||
B, //!< This is a type-B buffer
|
||||
W, //!< This is a type-W buffer
|
||||
C //!< This is a type-C buffer
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Describes a buffer by holding the address and size
|
||||
*/
|
||||
struct IpcBuffer {
|
||||
u64 address; //!< The address of the buffer
|
||||
size_t size; //!< The size of the buffer
|
||||
IpcBufferType type; //!< The type of the buffer
|
||||
|
||||
/**
|
||||
* @param address The address of the buffer
|
||||
* @param size The size of the buffer
|
||||
* @param type The type of the buffer
|
||||
*/
|
||||
IpcBuffer(u64 address, size_t size, IpcBufferType type);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief This holds an input IPC buffer
|
||||
*/
|
||||
struct InputBuffer : public IpcBuffer {
|
||||
/**
|
||||
* @param aBuf The X Buffer Descriptor that has contains the input data
|
||||
*/
|
||||
InputBuffer(kernel::ipc::BufferDescriptorX *xBuf);
|
||||
|
||||
/**
|
||||
* @param aBuf The A or W Buffer Descriptor that has contains the input data
|
||||
*/
|
||||
InputBuffer(kernel::ipc::BufferDescriptorABW *aBuf, IpcBufferType type = IpcBufferType::A);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief This holds an output IPC buffer
|
||||
*/
|
||||
struct OutputBuffer : public IpcBuffer {
|
||||
/**
|
||||
* @param bBuf The B or W Buffer Descriptor that has to be outputted to
|
||||
*/
|
||||
OutputBuffer(kernel::ipc::BufferDescriptorABW *bBuf, IpcBufferType type = IpcBufferType::B);
|
||||
|
||||
/**
|
||||
* @param cBuf The C Buffer Descriptor that has to be outputted to
|
||||
*/
|
||||
OutputBuffer(kernel::ipc::BufferDescriptorC *cBuf);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief This class encapsulates an IPC Request (https://switchbrew.org/wiki/IPC_Marshalling)
|
||||
*/
|
||||
class IpcRequest {
|
||||
private:
|
||||
const DeviceState &state; //!< The state of the device
|
||||
u8 *payloadOffset; //!< This is the offset of the data read from the payload
|
||||
|
||||
public:
|
||||
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
|
||||
DomainHeaderRequest *domain{}; //!< In case this is a domain request, this holds data regarding it
|
||||
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<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
|
||||
|
||||
/**
|
||||
* @param isDomain If the following request is a domain request
|
||||
* @param state The state of the device
|
||||
*/
|
||||
IpcRequest(bool isDomain, const DeviceState &state);
|
||||
|
||||
/**
|
||||
* @brief This returns a reference to an item from the top of the payload
|
||||
* @tparam ValueType The type of the object to read
|
||||
*/
|
||||
template<typename ValueType>
|
||||
inline ValueType &Pop() {
|
||||
ValueType &value = *reinterpret_cast<ValueType *>(payloadOffset);
|
||||
payloadOffset += sizeof(ValueType);
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This skips an object to pop off the top
|
||||
* @tparam ValueType The type of the object to skip
|
||||
*/
|
||||
template<typename ValueType>
|
||||
inline void Skip() {
|
||||
payloadOffset += sizeof(ValueType);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief This class encapsulates an IPC Response (https://switchbrew.org/wiki/IPC_Marshalling)
|
||||
*/
|
||||
class IpcResponse {
|
||||
private:
|
||||
std::vector<u8> argVec; //!< This holds all of the contents to be pushed to the payload
|
||||
const DeviceState &state; //!< The state of the device
|
||||
|
||||
public:
|
||||
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<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
|
||||
* @param state The state of the device
|
||||
*/
|
||||
IpcResponse(bool isDomain, const DeviceState &state);
|
||||
|
||||
/**
|
||||
* @brief Writes an object to the payload
|
||||
* @tparam ValueType The type of the object to write
|
||||
* @param value A reference to the object to be written
|
||||
*/
|
||||
template<typename ValueType>
|
||||
inline void Push(const ValueType &value) {
|
||||
argVec.reserve(argVec.size() + sizeof(ValueType));
|
||||
auto item = reinterpret_cast<const u8 *>(&value);
|
||||
for (uint index = 0; sizeof(ValueType) > index; index++) {
|
||||
argVec.push_back(*item);
|
||||
item++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Writes this IpcResponse object's contents into TLS
|
||||
*/
|
||||
void WriteResponse();
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -144,8 +144,8 @@ namespace skyline::kernel {
|
||||
case memory::AddressSpaceType::AddressSpace39Bit: {
|
||||
base.address = constant::BaseAddress;
|
||||
base.size = 0x7FF8000000;
|
||||
code.address = utils::AlignDown(address, 0x200000);
|
||||
code.size = utils::AlignUp(address + size, 0x200000) - code.address;
|
||||
code.address = util::AlignDown(address, 0x200000);
|
||||
code.size = util::AlignUp(address + size, 0x200000) - code.address;
|
||||
alias.address = code.address + code.size;
|
||||
alias.size = 0x1000000000;
|
||||
heap.address = alias.address + alias.size;
|
||||
|
@ -28,14 +28,14 @@ namespace skyline::kernel::svc {
|
||||
|
||||
void SetMemoryAttribute(DeviceState &state) {
|
||||
auto address = state.ctx->registers.x0;
|
||||
if (!utils::PageAligned(address)) {
|
||||
if (!util::PageAligned(address)) {
|
||||
state.ctx->registers.w0 = constant::status::InvAddress;
|
||||
state.logger->Warn("svcSetMemoryAttribute: 'address' not page aligned: 0x{:X}", address);
|
||||
return;
|
||||
}
|
||||
|
||||
auto size = state.ctx->registers.x1;
|
||||
if (!utils::PageAligned(size)) {
|
||||
if (!util::PageAligned(size)) {
|
||||
state.ctx->registers.w0 = constant::status::InvSize;
|
||||
state.logger->Warn("svcSetMemoryAttribute: 'size' {}: 0x{:X}", size ? "not page aligned" : "is zero", size);
|
||||
return;
|
||||
@ -77,13 +77,13 @@ namespace skyline::kernel::svc {
|
||||
auto source = state.ctx->registers.x1;
|
||||
auto size = state.ctx->registers.x2;
|
||||
|
||||
if (!utils::PageAligned(destination) || !utils::PageAligned(source)) {
|
||||
if (!util::PageAligned(destination) || !util::PageAligned(source)) {
|
||||
state.ctx->registers.w0 = constant::status::InvAddress;
|
||||
state.logger->Warn("svcMapMemory: Addresses not page aligned: Source: 0x{:X}, Destination: 0x{:X} (Size: 0x{:X} bytes)", source, destination, size);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!utils::PageAligned(size)) {
|
||||
if (!util::PageAligned(size)) {
|
||||
state.ctx->registers.w0 = constant::status::InvSize;
|
||||
state.logger->Warn("svcMapMemory: 'size' {}: 0x{:X}", size ? "not page aligned" : "is zero", size);
|
||||
return;
|
||||
@ -126,13 +126,13 @@ namespace skyline::kernel::svc {
|
||||
auto destination = state.ctx->registers.x1;
|
||||
auto size = state.ctx->registers.x2;
|
||||
|
||||
if (!utils::PageAligned(destination) || !utils::PageAligned(source)) {
|
||||
if (!util::PageAligned(destination) || !util::PageAligned(source)) {
|
||||
state.ctx->registers.w0 = constant::status::InvAddress;
|
||||
state.logger->Warn("svcUnmapMemory: Addresses not page aligned: Source: 0x{:X}, Destination: 0x{:X} (Size: 0x{:X} bytes)", source, destination, size);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!utils::PageAligned(size)) {
|
||||
if (!util::PageAligned(size)) {
|
||||
state.ctx->registers.w0 = constant::status::InvSize;
|
||||
state.logger->Warn("svcUnmapMemory: 'size' {}: 0x{:X}", size ? "not page aligned" : "is zero", size);
|
||||
return;
|
||||
@ -307,14 +307,14 @@ namespace skyline::kernel::svc {
|
||||
auto object = state.process->GetHandle<type::KSharedMemory>(state.ctx->registers.w0);
|
||||
u64 address = state.ctx->registers.x1;
|
||||
|
||||
if (!utils::PageAligned(address)) {
|
||||
if (!util::PageAligned(address)) {
|
||||
state.ctx->registers.w0 = constant::status::InvAddress;
|
||||
state.logger->Warn("svcMapSharedMemory: 'address' not page aligned: 0x{:X}", address);
|
||||
return;
|
||||
}
|
||||
|
||||
auto size = state.ctx->registers.x2;
|
||||
if (!utils::PageAligned(size)) {
|
||||
if (!util::PageAligned(size)) {
|
||||
state.ctx->registers.w0 = constant::status::InvSize;
|
||||
state.logger->Warn("svcMapSharedMemory: 'size' {}: 0x{:X}", size ? "not page aligned" : "is zero", size);
|
||||
return;
|
||||
@ -341,14 +341,14 @@ namespace skyline::kernel::svc {
|
||||
|
||||
void CreateTransferMemory(DeviceState &state) {
|
||||
u64 address = state.ctx->registers.x1;
|
||||
if (!utils::PageAligned(address)) {
|
||||
if (!util::PageAligned(address)) {
|
||||
state.ctx->registers.w0 = constant::status::InvAddress;
|
||||
state.logger->Warn("svcCreateTransferMemory: 'address' not page aligned: 0x{:X}", address);
|
||||
return;
|
||||
}
|
||||
|
||||
u64 size = state.ctx->registers.x2;
|
||||
if (!utils::PageAligned(size)) {
|
||||
if (!util::PageAligned(size)) {
|
||||
state.ctx->registers.w0 = constant::status::InvSize;
|
||||
state.logger->Warn("svcCreateTransferMemory: 'size' {}: 0x{:X}", size ? "not page aligned" : "is zero", size);
|
||||
return;
|
||||
@ -449,7 +449,7 @@ namespace skyline::kernel::svc {
|
||||
auto timeout = state.ctx->registers.x3;
|
||||
state.logger->Debug("svcWaitSynchronization: Waiting on handles:\n{}Timeout: 0x{:X} ns", handleStr, timeout);
|
||||
|
||||
auto start = utils::GetTimeNs();
|
||||
auto start = util::GetTimeNs();
|
||||
while (true) {
|
||||
if (state.thread->cancelSync) {
|
||||
state.thread->cancelSync = false;
|
||||
@ -468,7 +468,7 @@ namespace skyline::kernel::svc {
|
||||
index++;
|
||||
}
|
||||
|
||||
if ((utils::GetTimeNs() - start) >= timeout) {
|
||||
if ((util::GetTimeNs() - start) >= timeout) {
|
||||
state.logger->Debug("svcWaitSynchronization: Wait has timed out");
|
||||
state.ctx->registers.w0 = constant::status::Timeout;
|
||||
return;
|
||||
@ -487,7 +487,7 @@ namespace skyline::kernel::svc {
|
||||
|
||||
void ArbitrateLock(DeviceState &state) {
|
||||
auto address = state.ctx->registers.x1;
|
||||
if (!utils::WordAligned(address)) {
|
||||
if (!util::WordAligned(address)) {
|
||||
state.logger->Warn("svcArbitrateLock: 'address' not word aligned: 0x{:X}", address);
|
||||
state.ctx->registers.w0 = constant::status::InvAddress;
|
||||
return;
|
||||
@ -510,7 +510,7 @@ namespace skyline::kernel::svc {
|
||||
|
||||
void ArbitrateUnlock(DeviceState &state) {
|
||||
auto address = state.ctx->registers.x0;
|
||||
if (!utils::WordAligned(address)) {
|
||||
if (!util::WordAligned(address)) {
|
||||
state.logger->Warn("svcArbitrateUnlock: 'address' not word aligned: 0x{:X}", address);
|
||||
state.ctx->registers.w0 = constant::status::InvAddress;
|
||||
return;
|
||||
@ -529,7 +529,7 @@ namespace skyline::kernel::svc {
|
||||
|
||||
void WaitProcessWideKeyAtomic(DeviceState &state) {
|
||||
auto mtxAddress = state.ctx->registers.x0;
|
||||
if (!utils::WordAligned(mtxAddress)) {
|
||||
if (!util::WordAligned(mtxAddress)) {
|
||||
state.logger->Warn("svcWaitProcessWideKeyAtomic: mutex address not word aligned: 0x{:X}", mtxAddress);
|
||||
state.ctx->registers.w0 = constant::status::InvAddress;
|
||||
return;
|
||||
|
@ -10,7 +10,7 @@
|
||||
|
||||
namespace skyline::kernel::type {
|
||||
KPrivateMemory::KPrivateMemory(const DeviceState &state, u64 address, size_t size, memory::Permission permission, const memory::MemoryState memState) : size(size), KMemory(state, KType::KPrivateMemory) {
|
||||
if (address && !utils::PageAligned(address))
|
||||
if (address && !util::PageAligned(address))
|
||||
throw exception("KPrivateMemory was created with non-page-aligned address: 0x{:X}", address);
|
||||
|
||||
fd = ASharedMemory_create("KPrivateMemory", size);
|
||||
|
@ -112,7 +112,7 @@ namespace skyline::kernel::type {
|
||||
auto source = GetHostAddress(offset);
|
||||
|
||||
if (source) {
|
||||
memcpy(destination, reinterpret_cast<void *>(source), size);
|
||||
std::memcpy(destination, reinterpret_cast<void *>(source), size);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -136,7 +136,7 @@ namespace skyline::kernel::type {
|
||||
auto destination = GetHostAddress(offset);
|
||||
|
||||
if (destination) {
|
||||
memcpy(reinterpret_cast<void *>(destination), source, size);
|
||||
std::memcpy(reinterpret_cast<void *>(destination), source, size);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -160,7 +160,7 @@ namespace skyline::kernel::type {
|
||||
auto destinationHost = GetHostAddress(destination);
|
||||
|
||||
if (sourceHost && destinationHost) {
|
||||
memcpy(reinterpret_cast<void *>(destinationHost), reinterpret_cast<const void *>(sourceHost), size);
|
||||
std::memcpy(reinterpret_cast<void *>(destinationHost), reinterpret_cast<const void *>(sourceHost), size);
|
||||
} else {
|
||||
if (size <= PAGE_SIZE) {
|
||||
std::vector<u8> buffer(size);
|
||||
@ -282,9 +282,9 @@ namespace skyline::kernel::type {
|
||||
lock.unlock();
|
||||
|
||||
bool timedOut{};
|
||||
auto start = utils::GetTimeNs();
|
||||
auto start = util::GetTimeNs();
|
||||
while (!status->flag)
|
||||
if ((utils::GetTimeNs() - start) >= timeout)
|
||||
if ((util::GetTimeNs() - start) >= timeout)
|
||||
timedOut = true;
|
||||
|
||||
lock.lock();
|
||||
|
@ -10,7 +10,7 @@
|
||||
|
||||
namespace skyline::kernel::type {
|
||||
KSharedMemory::KSharedMemory(const DeviceState &state, u64 address, size_t size, const memory::Permission permission, memory::MemoryState memState, int mmapFlags) : initialState(memState), KMemory(state, KType::KSharedMemory) {
|
||||
if (address && !utils::PageAligned(address))
|
||||
if (address && !util::PageAligned(address))
|
||||
throw exception("KSharedMemory was created with non-page-aligned address: 0x{:X}", address);
|
||||
|
||||
fd = ASharedMemory_create("KSharedMemory", size);
|
||||
@ -25,7 +25,7 @@ namespace skyline::kernel::type {
|
||||
}
|
||||
|
||||
u64 KSharedMemory::Map(const u64 address, const u64 size, memory::Permission permission) {
|
||||
if (address && !utils::PageAligned(address))
|
||||
if (address && !util::PageAligned(address))
|
||||
throw exception("KSharedMemory was mapped to a non-page-aligned address: 0x{:X}", address);
|
||||
|
||||
Registers fregs{
|
||||
@ -129,7 +129,7 @@ namespace skyline::kernel::type {
|
||||
throw exception("An error occurred while creating shared memory: {}", fd);
|
||||
|
||||
std::vector<u8> data(std::min(size, kernel.size));
|
||||
memcpy(data.data(), reinterpret_cast<const void *>(kernel.address), std::min(size, kernel.size));
|
||||
std::memcpy(data.data(), reinterpret_cast<const void *>(kernel.address), std::min(size, kernel.size));
|
||||
|
||||
munmap(reinterpret_cast<void *>(kernel.address), kernel.size);
|
||||
|
||||
@ -137,7 +137,7 @@ namespace skyline::kernel::type {
|
||||
if (address == MAP_FAILED)
|
||||
throw exception("An occurred while mapping shared memory: {}", strerror(errno));
|
||||
|
||||
memcpy(address, data.data(), std::min(size, kernel.size));
|
||||
std::memcpy(address, data.data(), std::min(size, kernel.size));
|
||||
|
||||
kernel.address = reinterpret_cast<u64>(address);
|
||||
kernel.size = size;
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
namespace skyline::kernel::type {
|
||||
KTransferMemory::KTransferMemory(const DeviceState &state, bool host, u64 address, size_t size, const memory::Permission permission, memory::MemoryState memState) : host(host), size(size), KMemory(state, KType::KTransferMemory) {
|
||||
if (address && !utils::PageAligned(address))
|
||||
if (address && !util::PageAligned(address))
|
||||
throw exception("KTransferMemory was created with non-page-aligned address: 0x{:X}", address);
|
||||
|
||||
BlockDescriptor block{
|
||||
@ -53,7 +53,7 @@ namespace skyline::kernel::type {
|
||||
}
|
||||
|
||||
u64 KTransferMemory::Transfer(bool mHost, u64 nAddress, u64 nSize) {
|
||||
if (nAddress && !utils::PageAligned(nAddress))
|
||||
if (nAddress && !util::PageAligned(nAddress))
|
||||
throw exception("KTransferMemory was transferred to a non-page-aligned address: 0x{:X}", nAddress);
|
||||
|
||||
nSize = nSize ? nSize : size;
|
||||
@ -95,7 +95,7 @@ namespace skyline::kernel::type {
|
||||
else if (!mHost && !host)
|
||||
state.process->CopyMemory(address, nAddress, block.size);
|
||||
else if (mHost && host)
|
||||
memcpy(reinterpret_cast<void *>(nAddress), reinterpret_cast<void *>(address), block.size);
|
||||
std::memcpy(reinterpret_cast<void *>(nAddress), reinterpret_cast<void *>(address), block.size);
|
||||
}
|
||||
if (!block.permission.w) {
|
||||
if (mHost) {
|
||||
|
@ -9,9 +9,7 @@ namespace skyline::loader {
|
||||
NroLoader::NroLoader(const int romFd) : Loader(romFd) {
|
||||
ReadOffset((u32 *) &header, 0x0, sizeof(NroHeader));
|
||||
|
||||
constexpr auto nroMagic = 0x304F524E; // "NRO0" in reverse, this is written at the start of every NRO file
|
||||
|
||||
if (header.magic != nroMagic)
|
||||
if (header.magic != util::MakeMagic<u32>("NRO0"))
|
||||
throw exception("Invalid NRO magic! 0x{0:X}", header.magic);
|
||||
}
|
||||
|
||||
@ -30,7 +28,7 @@ namespace skyline::loader {
|
||||
u64 rodataSize = rodata.size();
|
||||
u64 dataSize = data.size();
|
||||
u64 patchSize = patch.size() * sizeof(u32);
|
||||
u64 padding = utils::AlignUp(textSize + rodataSize + dataSize + header.bssSize + patchSize, PAGE_SIZE) - (textSize + rodataSize + dataSize + header.bssSize + patchSize);
|
||||
u64 padding = util::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::states::CodeStatic); // R-X
|
||||
state.logger->Debug("Successfully mapped section .text @ 0x{0:X}, Size = 0x{1:X}", constant::BaseAddress, textSize);
|
||||
|
@ -8,7 +8,7 @@
|
||||
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
|
||||
constexpr u32 Rev0Magic = util::MakeMagic<u32>("REV0"); //!< The HOS 1.0 revision magic
|
||||
constexpr u32 RevMagic = Rev0Magic + (SupportedRevision << 24); //!< The revision magic for our supported revision
|
||||
|
||||
namespace supportTags {
|
||||
|
Loading…
Reference in New Issue
Block a user