Stratosphere: Add WrapIpcCommandImpl templating.
This commit is contained in:
386
stratosphere/loader/source/ipc_templating.hpp
Normal file
386
stratosphere/loader/source/ipc_templating.hpp
Normal file
@@ -0,0 +1,386 @@
|
||||
#pragma once
|
||||
#include <switch.h>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <tuple>
|
||||
#include <boost/callable_traits.hpp>
|
||||
#include <type_traits>
|
||||
#include <iomanip>
|
||||
|
||||
/* Represents an A descriptor. */
|
||||
template <typename T>
|
||||
struct InBuffer {
|
||||
T *buffer;
|
||||
size_t num_elements;
|
||||
BufferType type;
|
||||
|
||||
InBuffer(void *b, size_t n) : buffer((T *)b), num_elements(n/sizeof(T)) { }
|
||||
};
|
||||
|
||||
/* Represents a B descriptor. */
|
||||
template <typename T>
|
||||
struct OutBuffer {
|
||||
T *buffer;
|
||||
size_t num_elements;
|
||||
|
||||
OutBuffer(void *b, size_t n) : buffer((T *)b), num_elements(n/sizeof(T)) { }
|
||||
};
|
||||
|
||||
/* Represents an X descriptor. */
|
||||
template <typename T>
|
||||
struct InPointer {
|
||||
T *pointer;
|
||||
size_t num_elements;
|
||||
|
||||
InPointer(void *p, size_t n) : pointer((T *)p), num_elements(n/sizeof(T)) { }
|
||||
};
|
||||
|
||||
/* Represents a C descriptor. */
|
||||
struct OutPointerWithServerSizeBase {};
|
||||
|
||||
template <typename T, size_t n>
|
||||
struct OutPointerWithServerSize : OutPointerWithServerSizeBase {
|
||||
T *pointer;
|
||||
static const size_t num_elements = n;
|
||||
|
||||
OutPointerWithServerSize(void *p) : pointer((T *)p) { }
|
||||
};
|
||||
|
||||
/* Represents a C descriptor with size in raw data. */
|
||||
template <typename T>
|
||||
struct OutPointerWithClientSize {
|
||||
T *pointer;
|
||||
size_t num_elements;
|
||||
|
||||
OutPointerWithClientSize(void *p, size_t n) : pointer((T *)p), num_elements(n/sizeof(T)) { }
|
||||
};
|
||||
|
||||
/* Represents an input PID. */
|
||||
struct PidDescriptor {
|
||||
u64 pid;
|
||||
|
||||
PidDescriptor(u64 p) : pid(p) { }
|
||||
};
|
||||
|
||||
/* Represents a moved handle. */
|
||||
struct MovedHandle {
|
||||
Handle handle;
|
||||
|
||||
MovedHandle(Handle h) : handle(h) { }
|
||||
};
|
||||
|
||||
/* Represents a copied handle. */
|
||||
struct CopiedHandle {
|
||||
Handle handle;
|
||||
|
||||
CopiedHandle(Handle h) : handle(h) { }
|
||||
};
|
||||
|
||||
/* Utilities. */
|
||||
template <typename T, template <typename...> class Template>
|
||||
struct is_specialization_of {
|
||||
static const bool value = false;
|
||||
};
|
||||
|
||||
template <template <typename...> class Template, typename... Args>
|
||||
struct is_specialization_of<Template<Args...>, Template> {
|
||||
static const bool value = true;
|
||||
};
|
||||
|
||||
template<typename Tuple>
|
||||
struct pop_front;
|
||||
|
||||
template<typename Head, typename... Tail>
|
||||
struct pop_front<std::tuple<Head, Tail...>> {
|
||||
using type = std::tuple<Tail...>;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct is_ipc_buffer {
|
||||
static const bool value = is_specialization_of<T, InBuffer>::value
|
||||
|| is_specialization_of<T, OutBuffer>::value
|
||||
|| is_specialization_of<T, InPointer>::value
|
||||
|| std::is_base_of<OutPointerWithServerSizeBase, T>::value
|
||||
|| is_specialization_of<T, OutPointerWithClientSize>::value;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct size_in_raw_data {
|
||||
static const size_t value = (is_ipc_buffer<T>::value) ? 0 : ((sizeof(T) < sizeof(u32)) ? sizeof(u32) : (sizeof(T) + 3) & (~3));
|
||||
};
|
||||
|
||||
template <typename ...Args>
|
||||
struct size_in_raw_data_for_arguments {
|
||||
static const size_t value = (size_in_raw_data<Args>::value + ... + 0);
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct size_in_raw_data_with_out_pointers {
|
||||
static const size_t value = is_specialization_of<T, OutPointerWithClientSize>::value ? 2 : size_in_raw_data<T>::value;
|
||||
};
|
||||
|
||||
template <typename ...Args>
|
||||
struct size_in_raw_data_with_out_pointers_for_arguments {
|
||||
static const size_t value = ((size_in_raw_data_with_out_pointers<Args>::value + ... + 0) + 3) & ~3;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct is_ipc_inbuffer {
|
||||
static const size_t value = (is_specialization_of<T, InBuffer>::value) ? 1 : 0;
|
||||
};
|
||||
|
||||
template <typename ...Args>
|
||||
struct num_inbuffers_in_arguments {
|
||||
static const size_t value = (is_ipc_inbuffer<Args>::value + ... + 0);
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct is_ipc_inpointer {
|
||||
static const size_t value = (is_specialization_of<T, InPointer>::value) ? 1 : 0;
|
||||
};
|
||||
|
||||
template <typename ...Args>
|
||||
struct num_inpointers_in_arguments {
|
||||
static const size_t value = (is_ipc_inpointer<Args>::value + ... + 0);
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct is_ipc_outpointer {
|
||||
static const size_t value = (is_specialization_of<T, OutPointerWithClientSize>::value || std::is_base_of<OutPointerWithServerSizeBase, T>::value) ? 1 : 0;
|
||||
};
|
||||
|
||||
template <typename ...Args>
|
||||
struct num_outpointers_in_arguments {
|
||||
static const size_t value = (is_ipc_outpointer<Args>::value + ... + 0);
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct is_ipc_inoutbuffer {
|
||||
static const size_t value = (is_specialization_of<T, InBuffer>::value || is_specialization_of<T, OutBuffer>::value) ? 1 : 0;
|
||||
};
|
||||
|
||||
template <typename ...Args>
|
||||
struct num_inoutbuffers_in_arguments {
|
||||
static const size_t value = (is_ipc_inoutbuffer<Args>::value + ... + 0);
|
||||
};
|
||||
|
||||
|
||||
template <typename T>
|
||||
struct is_ipc_handle {
|
||||
static const size_t value = (std::is_same<T, MovedHandle>::value || std::is_same<T, CopiedHandle>::value) ? 1 : 0;
|
||||
};
|
||||
|
||||
template <typename ...Args>
|
||||
struct num_handles_in_arguments {
|
||||
static const size_t value = (is_ipc_handle<Args>::value + ... + 0);
|
||||
};
|
||||
|
||||
template <typename ...Args>
|
||||
struct num_pids_in_arguments {
|
||||
static const size_t value = ((std::is_same<Args, PidDescriptor>::value ? 1 : 0) + ... + 0);
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
T GetValueFromIpcParsedCommand(IpcParsedCommand& r, IpcCommand& out_c, u8 *pointer_buffer, size_t& pointer_buffer_offset, size_t& cur_rawdata_index, size_t& cur_c_size_offset, size_t& a_index, size_t& b_index, size_t& x_index, size_t& c_index, size_t& h_index) {
|
||||
const size_t old_rawdata_index = cur_rawdata_index;
|
||||
const size_t old_c_size_offset = cur_c_size_offset;
|
||||
const size_t old_pointer_buffer_offset = pointer_buffer_offset;
|
||||
if constexpr (is_specialization_of<T, InBuffer>::value) {
|
||||
return T(r.Buffers[a_index], r.BufferSizes[a_index++]);
|
||||
} else if constexpr (is_specialization_of<T, OutBuffer>::value) {
|
||||
return T(r.Buffers[b_index], r.BufferSizes[b_index++]);
|
||||
} else if constexpr (is_specialization_of<T, InPointer>::value) {
|
||||
return T(r.Statics[x_index], r.StaticSizes[x_index++]);
|
||||
} else if constexpr (std::is_base_of<OutPointerWithServerSizeBase, T>::value) {
|
||||
T t = T(pointer_buffer + old_pointer_buffer_offset);
|
||||
ipcAddSendStatic(&out_c, pointer_buffer + old_pointer_buffer_offset, t.num_elements * sizeof(*t.pointer), c_index++);
|
||||
return t;
|
||||
} else if constexpr (is_specialization_of<T, OutPointerWithClientSize>::value) {
|
||||
cur_c_size_offset += sizeof(u16);
|
||||
u16 sz = *((u16 *)((u8 *)(r.Raw) + old_c_size_offset));
|
||||
pointer_buffer_offset += sz;
|
||||
ipcAddSendStatic(&out_c, pointer_buffer + old_pointer_buffer_offset, sz, c_index++);
|
||||
return T(pointer_buffer + old_pointer_buffer_offset, sz);
|
||||
} else if constexpr (is_ipc_handle<T>::value) {
|
||||
return r.Handles[h_index++];
|
||||
} else if constexpr (std::is_same<T, PidDescriptor>::value) {
|
||||
return PidDescriptor(r.Pid);
|
||||
} else {
|
||||
cur_rawdata_index += size_in_raw_data<T>::value / sizeof(u32);
|
||||
return *((T *)((u32 *)r.Raw + old_rawdata_index));
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool ValidateIpcParsedCommandArgument(IpcParsedCommand& r, size_t& cur_rawdata_index, size_t& cur_c_size_offset, size_t& a_index, size_t& b_index, size_t& x_index, size_t& c_index, size_t& h_index, size_t& total_c_size) {
|
||||
const size_t old_c_size_offset = cur_c_size_offset;
|
||||
if constexpr (is_specialization_of<T, InBuffer>::value) {
|
||||
return r.Buffers[a_index] != NULL && r.BufferDirections[a_index++] == BufferDirection_Send;
|
||||
} else if constexpr (is_specialization_of<T, OutBuffer>::value) {
|
||||
return r.Buffers[b_index] != NULL && r.BufferDirections[b_index++] == BufferDirection_Recv;
|
||||
} else if constexpr (is_specialization_of<T, InPointer>::value) {
|
||||
return r.Statics[x_index] != NULL;
|
||||
} else if constexpr (std::is_base_of<OutPointerWithServerSizeBase, T>::value) {
|
||||
total_c_size += T::num_elements;
|
||||
return true;
|
||||
} else if constexpr (is_specialization_of<T, OutPointerWithClientSize>::value) {
|
||||
cur_c_size_offset += sizeof(u16);
|
||||
u16 sz = *((u16 *)((u8 *)(r.Raw) + old_c_size_offset));
|
||||
total_c_size += sz;
|
||||
return true;
|
||||
} else if constexpr (std::is_same<T, MovedHandle>::value) {
|
||||
return !r.WasHandleCopied[h_index++];
|
||||
} else if constexpr (std::is_same<T, CopiedHandle>::value) {
|
||||
return r.WasHandleCopied[h_index++];
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/* Validator. */
|
||||
template <typename ArgsTuple>
|
||||
struct Validator;
|
||||
|
||||
template<typename... Args>
|
||||
struct Validator<std::tuple<Args...>> {
|
||||
IpcParsedCommand &r;
|
||||
size_t pointer_buffer_size;
|
||||
|
||||
Result operator()() {
|
||||
if (r.RawSize < size_in_raw_data_with_out_pointers_for_arguments<Args... >::value) {
|
||||
return 0xF601;
|
||||
}
|
||||
|
||||
if (r.NumBuffers != num_inoutbuffers_in_arguments<Args... >::value) {
|
||||
return 0xF601;
|
||||
}
|
||||
|
||||
if (r.NumStatics != num_inpointers_in_arguments<Args... >::value) {
|
||||
return 0xF601;
|
||||
}
|
||||
|
||||
if (r.NumStaticsOut != num_outpointers_in_arguments<Args... >::value) {
|
||||
return 0xF601;
|
||||
}
|
||||
|
||||
if (r.NumHandles != num_handles_in_arguments<Args... >::value) {
|
||||
return 0xF601;
|
||||
}
|
||||
|
||||
constexpr size_t num_pids = num_pids_in_arguments<Args... >::value;
|
||||
|
||||
static_assert(num_pids <= 1, "Number of PID descriptors in IpcCommandImpl cannot be > 1");
|
||||
|
||||
if ((r.HasPid && num_pids == 0) || (!r.HasPid && num_pids)) {
|
||||
return 0xF601;
|
||||
}
|
||||
|
||||
size_t a_index = 0, b_index = num_inbuffers_in_arguments<Args ...>::value, x_index = 0, c_index = 0, h_index = 0;
|
||||
size_t cur_rawdata_index = 4;
|
||||
size_t cur_c_size_offset = 8 + size_in_raw_data_for_arguments<Args... >::value;
|
||||
size_t total_c_size = 0;
|
||||
|
||||
if (!(ValidateIpcParsedCommandArgument<Args>(r, cur_rawdata_index, cur_c_size_offset, a_index, b_index, x_index, c_index, h_index, total_c_size) && ...)) {
|
||||
return 0xF601;
|
||||
}
|
||||
|
||||
if (total_c_size > pointer_buffer_size) {
|
||||
return 0xF601;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/* Decoder. */
|
||||
template<typename OutTuple, typename ArgsTuple>
|
||||
struct Decoder;
|
||||
|
||||
template<typename OutTuple, typename... Args>
|
||||
struct Decoder<OutTuple, std::tuple<Args...>> {
|
||||
static std::tuple<Args...> Decode(IpcParsedCommand& r, IpcCommand &out_c, u8 *pointer_buffer) {
|
||||
size_t a_index = 0, b_index = num_inbuffers_in_arguments<Args ...>::value, x_index = 0, c_index = 0, h_index = 0;
|
||||
size_t cur_rawdata_index = 4;
|
||||
size_t cur_c_size_offset = 8 + size_in_raw_data_for_arguments<Args... >::value;
|
||||
size_t pointer_buffer_offset = 0;
|
||||
return std::tuple<Args... > {
|
||||
GetValueFromIpcParsedCommand<Args>(r, out_c, pointer_buffer, pointer_buffer_offset, cur_rawdata_index, cur_c_size_offset, a_index, b_index, x_index, c_index, h_index)
|
||||
...
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
/* Encoder. */
|
||||
template<typename ArgsTuple>
|
||||
struct Encoder;
|
||||
|
||||
template<typename T>
|
||||
constexpr size_t GetAndUpdateOffsetIntoRawData(size_t& offset) {
|
||||
auto old = offset;
|
||||
|
||||
if (old == 0) {
|
||||
offset += sizeof(u64);
|
||||
} else {
|
||||
offset += size_in_raw_data<T>::value;
|
||||
}
|
||||
|
||||
return old;
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
struct Encoder<std::tuple<Args...>> {
|
||||
IpcCommand &out_command;
|
||||
|
||||
auto operator()(Args... args) {
|
||||
static_assert(sizeof...(Args) > 0, "IpcCommandImpls must return std::tuple<Result, ...>");
|
||||
size_t offset = 0;
|
||||
|
||||
u8 *tls = (u8 *)armGetTls();
|
||||
|
||||
std::fill(tls, tls + 0x100, 0x100);
|
||||
|
||||
/* Remove the extra space resulting from first Result type. */
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
} *raw = (decltype(raw))ipcPrepareHeader(&out_command, sizeof(*raw) + size_in_raw_data_for_arguments<Args... >::value - sizeof(Result));
|
||||
|
||||
raw->magic = SFCO_MAGIC;
|
||||
|
||||
u8 *raw_data = (u8 *)&raw->result;
|
||||
|
||||
((*((Args *)(raw_data + GetAndUpdateOffsetIntoRawData<Args>(offset))) = (args)), ...);
|
||||
|
||||
if (R_FAILED(raw->result)) {
|
||||
ipcPrepareHeader(&out_command, sizeof(raw));
|
||||
}
|
||||
|
||||
return raw->result;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<auto IpcCommandImpl, typename Class>
|
||||
Result WrapIpcCommandImpl(Class *myfancypointer, IpcParsedCommand& r, IpcCommand &out_command, u8 *pointer_buffer, size_t pointer_buffer_size) {
|
||||
using InArgs = typename boost::callable_traits::args_t<decltype(IpcCommandImpl)>;
|
||||
using InArgsWithoutThis = typename pop_front<InArgs>::type;
|
||||
using OutArgs = typename boost::callable_traits::return_type_t<decltype(IpcCommandImpl)>;
|
||||
|
||||
static_assert(is_specialization_of<OutArgs, std::tuple>::value, "IpcCommandImpls must return std::tuple<Result, ...>");
|
||||
static_assert(std::is_same_v<std::tuple_element_t<0, OutArgs>, Result>, "IpcCommandImpls must return std::tuple<Result, ...>");
|
||||
|
||||
ipcInitialize(&out_command);
|
||||
|
||||
Result rc = Validator<InArgsWithoutThis>{r, pointer_buffer_size}();
|
||||
|
||||
if (R_FAILED(rc)) {
|
||||
return 0xF601;
|
||||
}
|
||||
|
||||
auto args = Decoder<OutArgs, InArgsWithoutThis>::Decode(r, out_command, pointer_buffer);
|
||||
auto result = std::apply( [=](auto&&... args) { return (myfancypointer->*IpcCommandImpl)(args...); }, args);
|
||||
|
||||
return std::apply(Encoder<OutArgs>{out_command}, result);
|
||||
}
|
||||
@@ -1,8 +1,10 @@
|
||||
#pragma once
|
||||
#include <switch.h>
|
||||
|
||||
#include "ipc_templating.hpp"
|
||||
|
||||
class IServiceObject {
|
||||
public:
|
||||
virtual ~IServiceObject() { }
|
||||
virtual Result dispatch(IpcParsedCommand *r, IpcCommand *out_c, u32 *cmd_buf, u32 cmd_id, u32 *in_rawdata, u32 in_rawdata_size, u32 *out_rawdata, u32 *out_raw_data_count) = 0;
|
||||
virtual Result dispatch(IpcParsedCommand &r, IpcCommand &out_c, u64 cmd_id, u8 *pointer_buffer, size_t pointer_buffer_size) = 0;
|
||||
};
|
||||
@@ -6,50 +6,23 @@
|
||||
#include "ldr_launch_queue.hpp"
|
||||
#include "ldr_registration.hpp"
|
||||
|
||||
Result DebugMonitorService::dispatch(IpcParsedCommand *r, IpcCommand *out_c, u32 *cmd_buf, u32 cmd_id, u32 *in_rawdata, u32 in_rawdata_size, u32 *out_rawdata, u32 *out_raw_data_count) {
|
||||
|
||||
std::tuple<Result> fake_clear_launch_queue() {
|
||||
LaunchQueue::clear();
|
||||
return std::make_tuple(0);
|
||||
}
|
||||
|
||||
Result DebugMonitorService::dispatch(IpcParsedCommand &r, IpcCommand &out_c, u64 cmd_id, u8 *pointer_buffer, size_t pointer_buffer_size) {
|
||||
Result rc = 0xF601;
|
||||
|
||||
switch ((DebugMonitorServiceCmd)cmd_id) {
|
||||
case Dmnt_Cmd_AddTitleToLaunchQueue:
|
||||
/* Validate arguments. */
|
||||
if (in_rawdata_size < 0x10 || r->HasPid || r->NumHandles != 0 || r->NumBuffers != 0 || r->NumStatics != 1) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (r->Statics[0] == NULL) {
|
||||
rc = 0xCE01;
|
||||
break;
|
||||
}
|
||||
|
||||
rc = add_title_to_launch_queue(((u64 *)in_rawdata)[0], (const char *)r->Statics[0], r->StaticSizes[0]);
|
||||
|
||||
*out_raw_data_count = 0;
|
||||
|
||||
rc = WrapIpcCommandImpl<&DebugMonitorService::add_title_to_launch_queue>(this, r, out_c, pointer_buffer, pointer_buffer_size);
|
||||
break;
|
||||
case Dmnt_Cmd_ClearLaunchQueue:
|
||||
if (r->HasPid || r->NumHandles != 0 || r->NumBuffers != 0 || r->NumStatics != 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
rc = clear_launch_queue();
|
||||
*out_raw_data_count = 0;
|
||||
|
||||
rc = WrapIpcCommandImpl<&DebugMonitorService::clear_launch_queue>(this, r, out_c, pointer_buffer, pointer_buffer_size);
|
||||
break;
|
||||
case Dmnt_Cmd_GetNsoInfo:
|
||||
if (in_rawdata_size < 0x8 || r->HasPid || r->NumHandles != 0 || r->NumBuffers != 0 || r->NumStatics != 1) {
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
rc = get_nso_info(((u64 *)in_rawdata)[0], r->Statics[0], r->StaticSizes[0], out_rawdata);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
*out_raw_data_count = 1;
|
||||
} else {
|
||||
*out_raw_data_count = 0;
|
||||
}
|
||||
|
||||
rc = WrapIpcCommandImpl<&DebugMonitorService::get_nso_info>(this, r, out_c, pointer_buffer, pointer_buffer_size);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -57,21 +30,23 @@ Result DebugMonitorService::dispatch(IpcParsedCommand *r, IpcCommand *out_c, u32
|
||||
return rc;
|
||||
}
|
||||
|
||||
Result DebugMonitorService::add_title_to_launch_queue(u64 tid, const char *args, size_t args_size) {
|
||||
return LaunchQueue::add(tid, args, args_size);
|
||||
std::tuple<Result> DebugMonitorService::add_title_to_launch_queue(u64 tid, InPointer<char> args) {
|
||||
fprintf(stderr, "Add to launch queue: %p, %X\n", args.pointer, args.num_elements);
|
||||
return std::make_tuple(LaunchQueue::add(tid, args.pointer, args.num_elements));
|
||||
}
|
||||
|
||||
Result DebugMonitorService::clear_launch_queue() {
|
||||
std::tuple<Result> DebugMonitorService::clear_launch_queue(u64 dat) {
|
||||
fprintf(stderr, "Clear launch queue: %lx\n", dat);
|
||||
LaunchQueue::clear();
|
||||
return 0;
|
||||
return std::make_tuple(0);
|
||||
}
|
||||
|
||||
Result DebugMonitorService::get_nso_info(u64 pid, void *out, size_t out_size, u32 *out_num_nsos) {
|
||||
u32 max_out = out_size / (sizeof(Registration::NsoInfo));
|
||||
std::tuple<Result, u32> DebugMonitorService::get_nso_info(u64 pid, OutPointerWithClientSize<Registration::NsoInfo> out) {
|
||||
u32 out_num_nsos = 0;
|
||||
|
||||
//std::fill(out.pointer, out.pointer + out.num_elements, (const Registration::NsoInfo){0});
|
||||
|
||||
Registration::NsoInfo *nso_out = (Registration::NsoInfo *)out;
|
||||
Result rc = Registration::get_nso_infos_for_process_id(out.pointer, out.num_elements, pid, &out_num_nsos);
|
||||
|
||||
std::fill(nso_out, nso_out + max_out, (const Registration::NsoInfo){0});
|
||||
|
||||
return Registration::get_nso_infos_for_process_id(nso_out, max_out, pid, out_num_nsos);
|
||||
return std::make_tuple(rc, out_num_nsos);
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
#include <switch.h>
|
||||
|
||||
#include "iserviceobject.hpp"
|
||||
#include "ldr_registration.hpp"
|
||||
|
||||
enum DebugMonitorServiceCmd {
|
||||
Dmnt_Cmd_AddTitleToLaunchQueue = 0,
|
||||
@@ -11,11 +12,11 @@ enum DebugMonitorServiceCmd {
|
||||
|
||||
class DebugMonitorService : IServiceObject {
|
||||
public:
|
||||
Result dispatch(IpcParsedCommand *r, IpcCommand *out_c, u32 *cmd_buf, u32 cmd_id, u32 *in_rawdata, u32 in_rawdata_size, u32 *out_rawdata, u32 *out_raw_data_count);
|
||||
Result dispatch(IpcParsedCommand &r, IpcCommand &out_c, u64 cmd_id, u8 *pointer_buffer, size_t pointer_buffer_size);
|
||||
|
||||
private:
|
||||
/* Actual commands. */
|
||||
Result add_title_to_launch_queue(u64 tid, const char *args, size_t args_size);
|
||||
Result clear_launch_queue();
|
||||
Result get_nso_info(u64 pid, void *out, size_t out_size, u32 *out_num_nsos);
|
||||
std::tuple<Result> add_title_to_launch_queue(u64 tid, InPointer<char> args);
|
||||
std::tuple<Result> clear_launch_queue(u64 dat);
|
||||
std::tuple<Result, u32> get_nso_info(u64 pid, OutPointerWithClientSize<Registration::NsoInfo> out);
|
||||
};
|
||||
@@ -3,43 +3,22 @@
|
||||
#include "ldr_registration.hpp"
|
||||
#include "ldr_launch_queue.hpp"
|
||||
|
||||
Result ProcessManagerService::dispatch(IpcParsedCommand *r, IpcCommand *out_c, u32 *cmd_buf, u32 cmd_id, u32 *in_rawdata, u32 in_rawdata_size, u32 *out_rawdata, u32 *out_raw_data_count) {
|
||||
Result ProcessManagerService::dispatch(IpcParsedCommand &r, IpcCommand &out_c, u64 cmd_id, u8 *pointer_buffer, size_t pointer_buffer_size) {
|
||||
|
||||
Result rc = 0xF601;
|
||||
|
||||
switch ((ProcessManagerServiceCmd)cmd_id) {
|
||||
case Pm_Cmd_CreateProcess:
|
||||
/* TODO */
|
||||
rc = WrapIpcCommandImpl<&ProcessManagerService::create_process>(this, r, out_c, pointer_buffer, pointer_buffer_size);
|
||||
break;
|
||||
case Pm_Cmd_GetProgramInfo:
|
||||
/* TODO */
|
||||
rc = WrapIpcCommandImpl<&ProcessManagerService::get_program_info>(this, r, out_c, pointer_buffer, pointer_buffer_size);
|
||||
break;
|
||||
case Pm_Cmd_RegisterTitle:
|
||||
/* Validate arguments. */
|
||||
if (in_rawdata_size < 0x10 || r->HasPid || r->NumHandles != 0 || r->NumBuffers != 0 || r->NumStatics != 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
u64 out_index;
|
||||
rc = register_title((Registration::TidSid *)in_rawdata, &out_index);
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
((u64 *)out_rawdata)[0] = out_index;
|
||||
*out_raw_data_count = 2;
|
||||
} else {
|
||||
((u64 *)out_rawdata)[0] = 0;
|
||||
*out_raw_data_count = 0;
|
||||
}
|
||||
|
||||
case Pm_Cmd_RegisterTitle:
|
||||
rc = WrapIpcCommandImpl<&ProcessManagerService::register_title>(this, r, out_c, pointer_buffer, pointer_buffer_size);
|
||||
break;
|
||||
case Pm_Cmd_UnregisterTitle:
|
||||
/* Validate arguments. */
|
||||
if (in_rawdata_size < 0x8 || r->HasPid || r->NumHandles != 0 || r->NumBuffers != 0 || r->NumStatics != 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
rc = unregister_title(((u64 *)in_rawdata)[0]);
|
||||
*out_raw_data_count = 0;
|
||||
|
||||
rc = WrapIpcCommandImpl<&ProcessManagerService::unregister_title>(this, r, out_c, pointer_buffer, pointer_buffer_size);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -47,28 +26,29 @@ Result ProcessManagerService::dispatch(IpcParsedCommand *r, IpcCommand *out_c, u
|
||||
return rc;
|
||||
}
|
||||
|
||||
Result ProcessManagerService::create_process() {
|
||||
std::tuple<Result> ProcessManagerService::create_process() {
|
||||
/* TODO */
|
||||
return 0xF601;
|
||||
return std::make_tuple(0xF601);
|
||||
}
|
||||
|
||||
Result ProcessManagerService::get_program_info() {
|
||||
std::tuple<Result> ProcessManagerService::get_program_info() {
|
||||
/* TODO */
|
||||
return 0xF601;
|
||||
return std::make_tuple(0xF601);
|
||||
}
|
||||
|
||||
Result ProcessManagerService::register_title(const Registration::TidSid *tid_sid, u64 *out_index) {
|
||||
if (Registration::register_tid_sid(tid_sid, out_index)) {
|
||||
return 0;
|
||||
std::tuple<Result, u64> ProcessManagerService::register_title(Registration::TidSid tid_sid) {
|
||||
u64 out_index = 0;
|
||||
if (Registration::register_tid_sid(&tid_sid, &out_index)) {
|
||||
return std::make_tuple(0, out_index);
|
||||
} else {
|
||||
return 0xE09;
|
||||
return std::make_tuple(0xE09, out_index);
|
||||
}
|
||||
}
|
||||
|
||||
Result ProcessManagerService::unregister_title(u64 index) {
|
||||
std::tuple<Result> ProcessManagerService::unregister_title(u64 index) {
|
||||
if (Registration::unregister_index(index)) {
|
||||
return 0;
|
||||
return std::make_tuple(0);
|
||||
} else {
|
||||
return 0x1009;
|
||||
return std::make_tuple(0x1009);
|
||||
}
|
||||
}
|
||||
@@ -13,12 +13,12 @@ enum ProcessManagerServiceCmd {
|
||||
|
||||
class ProcessManagerService : IServiceObject {
|
||||
public:
|
||||
Result dispatch(IpcParsedCommand *r, IpcCommand *out_c, u32 *cmd_buf, u32 cmd_id, u32 *in_rawdata, u32 in_rawdata_size, u32 *out_rawdata, u32 *out_raw_data_count);
|
||||
Result dispatch(IpcParsedCommand &r, IpcCommand &out_c, u64 cmd_id, u8 *pointer_buffer, size_t pointer_buffer_size);
|
||||
|
||||
private:
|
||||
/* Actual commands. */
|
||||
Result create_process();
|
||||
Result get_program_info();
|
||||
Result register_title(const Registration::TidSid *tid_sid, u64 *out_index);
|
||||
Result unregister_title(u64 index);
|
||||
std::tuple<Result> create_process();
|
||||
std::tuple<Result> get_program_info();
|
||||
std::tuple<Result, u64> register_title(Registration::TidSid tid_sid);
|
||||
std::tuple<Result> unregister_title(u64 index);
|
||||
};
|
||||
@@ -18,20 +18,21 @@ Registration::Process *Registration::get_free_process() {
|
||||
|
||||
Registration::Process *Registration::get_process(u64 index) {
|
||||
unsigned int i;
|
||||
for (i = 0; !g_registration_list.processes[i].in_use || g_registration_list.processes[i].index != index; i++) {
|
||||
if (i >= REGISTRATION_LIST_MAX) {
|
||||
return NULL;
|
||||
}
|
||||
for (i = 0; i < REGISTRATION_LIST_MAX && (!g_registration_list.processes[i].in_use || g_registration_list.processes[i].index != index); i++) {
|
||||
}
|
||||
if (i >= REGISTRATION_LIST_MAX) {
|
||||
return NULL;
|
||||
}
|
||||
return &g_registration_list.processes[i];
|
||||
}
|
||||
|
||||
Registration::Process *Registration::get_process_by_process_id(u64 pid) {
|
||||
unsigned int i;
|
||||
for (i = 0; !g_registration_list.processes[i].in_use || g_registration_list.processes[i].process_id != pid; i++) {
|
||||
if (i >= REGISTRATION_LIST_MAX) {
|
||||
return NULL;
|
||||
}
|
||||
for (i = 0; i < REGISTRATION_LIST_MAX && (!g_registration_list.processes[i].in_use || g_registration_list.processes[i].process_id != pid); i++) {
|
||||
|
||||
}
|
||||
if (i >= REGISTRATION_LIST_MAX) {
|
||||
return NULL;
|
||||
}
|
||||
return &g_registration_list.processes[i];
|
||||
}
|
||||
|
||||
@@ -2,35 +2,16 @@
|
||||
#include "ldr_shell.hpp"
|
||||
#include "ldr_launch_queue.hpp"
|
||||
|
||||
Result ShellService::dispatch(IpcParsedCommand *r, IpcCommand *out_c, u32 *cmd_buf, u32 cmd_id, u32 *in_rawdata, u32 in_rawdata_size, u32 *out_rawdata, u32 *out_raw_data_count) {
|
||||
Result ShellService::dispatch(IpcParsedCommand &r, IpcCommand &out_c, u64 cmd_id, u8 *pointer_buffer, size_t pointer_buffer_size) {
|
||||
|
||||
Result rc = 0xF601;
|
||||
|
||||
switch ((ShellServiceCmd)cmd_id) {
|
||||
case Shell_Cmd_AddTitleToLaunchQueue:
|
||||
/* Validate arguments. */
|
||||
if (in_rawdata_size < 0x10 || r->HasPid || r->NumHandles != 0 || r->NumBuffers != 0 || r->NumStatics != 1) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (r->Statics[0] == NULL) {
|
||||
rc = 0xCE01;
|
||||
break;
|
||||
}
|
||||
|
||||
rc = add_title_to_launch_queue(((u64 *)in_rawdata)[0], (const char *)r->Statics[0], r->StaticSizes[0]);
|
||||
|
||||
*out_raw_data_count = 0;
|
||||
|
||||
rc = WrapIpcCommandImpl<&ShellService::add_title_to_launch_queue>(this, r, out_c, pointer_buffer, pointer_buffer_size);
|
||||
break;
|
||||
rc = WrapIpcCommandImpl<&ShellService::add_title_to_launch_queue>(this, r, out_c, pointer_buffer, pointer_buffer_size);
|
||||
case Shell_Cmd_ClearLaunchQueue:
|
||||
if (r->HasPid || r->NumHandles != 0 || r->NumBuffers != 0 || r->NumStatics != 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
rc = clear_launch_queue();
|
||||
*out_raw_data_count = 0;
|
||||
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -38,11 +19,13 @@ Result ShellService::dispatch(IpcParsedCommand *r, IpcCommand *out_c, u32 *cmd_b
|
||||
return rc;
|
||||
}
|
||||
|
||||
Result ShellService::add_title_to_launch_queue(u64 tid, const char *args, size_t args_size) {
|
||||
return LaunchQueue::add(tid, args, args_size);
|
||||
std::tuple<Result> ShellService::add_title_to_launch_queue(u64 tid, InPointer<char> args) {
|
||||
fprintf(stderr, "Add to launch queue: %p, %X\n", args.pointer, args.num_elements);
|
||||
return std::make_tuple(LaunchQueue::add(tid, args.pointer, args.num_elements));
|
||||
}
|
||||
|
||||
Result ShellService::clear_launch_queue() {
|
||||
std::tuple<Result> ShellService::clear_launch_queue(u64 dat) {
|
||||
fprintf(stderr, "Clear launch queue: %lx\n", dat);
|
||||
LaunchQueue::clear();
|
||||
return 0;
|
||||
return std::make_tuple(0);
|
||||
}
|
||||
@@ -10,10 +10,10 @@ enum ShellServiceCmd {
|
||||
|
||||
class ShellService : IServiceObject {
|
||||
public:
|
||||
Result dispatch(IpcParsedCommand *r, IpcCommand *out_c, u32 *cmd_buf, u32 cmd_id, u32 *in_rawdata, u32 in_rawdata_size, u32 *out_rawdata, u32 *out_raw_data_count);
|
||||
Result dispatch(IpcParsedCommand &r, IpcCommand &out_c, u64 cmd_id, u8 *pointer_buffer, size_t pointer_buffer_size);
|
||||
|
||||
private:
|
||||
/* Actual commands. */
|
||||
Result add_title_to_launch_queue(u64 tid, const char *args, size_t args_size);
|
||||
Result clear_launch_queue();
|
||||
std::tuple<Result> add_title_to_launch_queue(u64 tid, InPointer<char> args);
|
||||
std::tuple<Result> clear_launch_queue(u64 dat);
|
||||
};
|
||||
@@ -3,6 +3,7 @@
|
||||
#include <type_traits>
|
||||
#include <cstdio>
|
||||
|
||||
#include "ipc_templating.hpp"
|
||||
#include "iserviceobject.hpp"
|
||||
#include "iwaitable.hpp"
|
||||
#include "serviceserver.hpp"
|
||||
@@ -83,15 +84,13 @@ class ServiceSession : public IWaitable {
|
||||
/* TODO: Panic? */
|
||||
}
|
||||
u32 *cmdbuf = (u32 *)armGetTls();
|
||||
u32 out_words = 4;
|
||||
u32 extra_rawdata_count = 0;
|
||||
u32 wordcount = 0;
|
||||
Result retval = 0;
|
||||
u32 *rawdata_start = cmdbuf;
|
||||
|
||||
IpcParsedCommand r;
|
||||
IpcCommand c;
|
||||
|
||||
|
||||
fprintf(stderr, "Doing ServiceSession parse...\n");
|
||||
|
||||
ipcInitialize(&c);
|
||||
@@ -100,7 +99,6 @@ class ServiceSession : public IWaitable {
|
||||
|
||||
if (R_SUCCEEDED(retval)) {
|
||||
rawdata_start = (u32 *)r.Raw;
|
||||
wordcount = r.RawSize;
|
||||
switch (r.CommandType) {
|
||||
case IpcCommandType_Close:
|
||||
/* TODO: This should close the session and clean up its resources. */
|
||||
@@ -116,13 +114,11 @@ class ServiceSession : public IWaitable {
|
||||
break;
|
||||
case IpcCommandType_Request:
|
||||
case IpcCommandType_RequestWithContext:
|
||||
retval = this->service_object->dispatch(&r, &c, cmdbuf, rawdata_start[2], &rawdata_start[4], wordcount - 6, &cmdbuf[8], &extra_rawdata_count);
|
||||
out_words += extra_rawdata_count;
|
||||
retval = this->service_object->dispatch(r, c, rawdata_start[2], (u8 *)this->pointer_buffer, sizeof(this->pointer_buffer));
|
||||
break;
|
||||
case IpcCommandType_Control:
|
||||
case IpcCommandType_ControlWithContext:
|
||||
retval = this->dispatch_control_command(&r, &c, cmdbuf, rawdata_start[2], &rawdata_start[4], wordcount - 6, &cmdbuf[8], &extra_rawdata_count);
|
||||
out_words += extra_rawdata_count;
|
||||
retval = this->dispatch_control_command(r, c, rawdata_start[2]);
|
||||
break;
|
||||
case IpcCommandType_Invalid:
|
||||
default:
|
||||
@@ -132,17 +128,7 @@ class ServiceSession : public IWaitable {
|
||||
|
||||
}
|
||||
|
||||
if (retval != 0xF601) {
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 retval;
|
||||
} *raw;
|
||||
|
||||
raw = (decltype(raw))ipcPrepareHeader(&c, out_words * 4);
|
||||
|
||||
raw->magic = SFCO_MAGIC;
|
||||
raw->retval = retval;
|
||||
|
||||
if (retval != 0xF601) {
|
||||
rc = svcReplyAndReceive(&handle_index, &this->server_handle, 1, this->server_handle, 0);
|
||||
} else {
|
||||
rc = retval;
|
||||
@@ -152,30 +138,46 @@ class ServiceSession : public IWaitable {
|
||||
return rc;
|
||||
}
|
||||
|
||||
Result dispatch_control_command(IpcParsedCommand *r, IpcCommand *out_c, u32 *cmd_buf, u32 cmd_id, u32 *in_rawdata, u32 in_rawdata_size, u32 *out_rawdata, u32 *out_raw_data_count) {
|
||||
/* Control commands. */
|
||||
std::tuple<Result> ConvertCurrentObjectToDomain() {
|
||||
/* TODO */
|
||||
return std::make_tuple(0xF601);
|
||||
}
|
||||
std::tuple<Result> CopyFromCurrentDomain() {
|
||||
/* TODO */
|
||||
return std::make_tuple(0xF601);
|
||||
}
|
||||
std::tuple<Result> CloneCurrentObject() {
|
||||
/* TODO */
|
||||
return std::make_tuple(0xF601);
|
||||
}
|
||||
std::tuple<Result, u32> QueryPointerBufferSize() {
|
||||
return std::make_tuple(0x0, (u32)sizeof(this->pointer_buffer));
|
||||
}
|
||||
std::tuple<Result> CloneCurrentObjectEx() {
|
||||
/* TODO */
|
||||
return std::make_tuple(0xF601);
|
||||
}
|
||||
|
||||
Result dispatch_control_command(IpcParsedCommand &r, IpcCommand &out_c, u64 cmd_id) {
|
||||
Result rc = 0xF601;
|
||||
|
||||
/* TODO: Implement. */
|
||||
switch ((IpcControlCommand)cmd_id) {
|
||||
case IpcCtrl_Cmd_ConvertCurrentObjectToDomain:
|
||||
/* TODO */
|
||||
rc = WrapIpcCommandImpl<&ServiceSession::ConvertCurrentObjectToDomain>(this, r, out_c, (u8 *)this->pointer_buffer, sizeof(this->pointer_buffer));
|
||||
break;
|
||||
case IpcCtrl_Cmd_CopyFromCurrentDomain:
|
||||
/* TODO */
|
||||
rc = WrapIpcCommandImpl<&ServiceSession::CopyFromCurrentDomain>(this, r, out_c, (u8 *)this->pointer_buffer, sizeof(this->pointer_buffer));
|
||||
break;
|
||||
case IpcCtrl_Cmd_CloneCurrentObject:
|
||||
/* TODO */
|
||||
rc = WrapIpcCommandImpl<&ServiceSession::CloneCurrentObject>(this, r, out_c, (u8 *)this->pointer_buffer, sizeof(this->pointer_buffer));
|
||||
break;
|
||||
case IpcCtrl_Cmd_QueryPointerBufferSize:
|
||||
if (r->HasPid || r->NumHandles != 0 || r->NumBuffers != 0 || r->NumStatics != 0 || r->NumStaticsOut != 0) {
|
||||
break;
|
||||
}
|
||||
*out_rawdata = sizeof(this->pointer_buffer);
|
||||
*out_raw_data_count = 1;
|
||||
rc = 0;
|
||||
rc = WrapIpcCommandImpl<&ServiceSession::QueryPointerBufferSize>(this, r, out_c, (u8 *)this->pointer_buffer, sizeof(this->pointer_buffer));
|
||||
break;
|
||||
case IpcCtrl_Cmd_CloneCurrentObjectEx:
|
||||
/* TODO */
|
||||
rc = WrapIpcCommandImpl<&ServiceSession::CloneCurrentObjectEx>(this, r, out_c, (u8 *)this->pointer_buffer, sizeof(this->pointer_buffer));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
||||
Reference in New Issue
Block a user