mirror of
https://github.com/Atmosphere-NX/Atmosphere.git
synced 2024-11-05 19:51:45 +00:00
Implement all of sm.
This commit is contained in:
parent
61cbb0f86e
commit
f1cf6dcf97
4 changed files with 313 additions and 10 deletions
|
@ -1,5 +1,6 @@
|
||||||
#include <switch.h>
|
#include <switch.h>
|
||||||
#include "sm_manager_service.hpp"
|
#include "sm_manager_service.hpp"
|
||||||
|
#include "sm_registration.hpp"
|
||||||
|
|
||||||
Result ManagerService::dispatch(IpcParsedCommand &r, IpcCommand &out_c, u64 cmd_id, u8 *pointer_buffer, size_t pointer_buffer_size) {
|
Result ManagerService::dispatch(IpcParsedCommand &r, IpcCommand &out_c, u64 cmd_id, u8 *pointer_buffer, size_t pointer_buffer_size) {
|
||||||
Result rc = 0xF601;
|
Result rc = 0xF601;
|
||||||
|
@ -19,11 +20,9 @@ Result ManagerService::dispatch(IpcParsedCommand &r, IpcCommand &out_c, u64 cmd_
|
||||||
|
|
||||||
|
|
||||||
std::tuple<Result> ManagerService::register_process(u64 pid, InBuffer<u8> acid_sac, InBuffer<u8> aci0_sac) {
|
std::tuple<Result> ManagerService::register_process(u64 pid, InBuffer<u8> acid_sac, InBuffer<u8> aci0_sac) {
|
||||||
/* TODO */
|
return std::make_tuple(Registration::RegisterProcess(pid, acid_sac.buffer, acid_sac.num_elements, aci0_sac.buffer, aci0_sac.num_elements));
|
||||||
return std::make_tuple(0xF601);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::tuple<Result> ManagerService::unregister_process(u64 pid) {
|
std::tuple<Result> ManagerService::unregister_process(u64 pid) {
|
||||||
/* TODO */
|
return std::make_tuple(Registration::UnregisterProcess(pid));
|
||||||
return std::make_tuple(0xF601);
|
|
||||||
}
|
}
|
262
stratosphere/sm/source/sm_registration.cpp
Normal file
262
stratosphere/sm/source/sm_registration.cpp
Normal file
|
@ -0,0 +1,262 @@
|
||||||
|
#include <switch.h>
|
||||||
|
#include <algorithm>
|
||||||
|
#include "sm_registration.hpp"
|
||||||
|
|
||||||
|
static Registration::Process g_process_list[REGISTRATION_LIST_MAX_PROCESS] = {0};
|
||||||
|
static Registration::Service g_service_list[REGISTRATION_LIST_MAX_SERVICE] = {0};
|
||||||
|
|
||||||
|
/* Utilities. */
|
||||||
|
Registration::Process *Registration::GetProcessForPid(u64 pid) {
|
||||||
|
for (unsigned int i = 0; i < REGISTRATION_LIST_MAX_PROCESS; i++) {
|
||||||
|
if (g_process_list[i].pid == pid) {
|
||||||
|
return &g_process_list[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
Registration::Process *Registration::GetFreeProcess() {
|
||||||
|
return GetProcessForPid(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
Registration::Service *Registration::GetService(u64 service) {
|
||||||
|
for (unsigned int i = 0; i < REGISTRATION_LIST_MAX_SERVICE; i++) {
|
||||||
|
if (g_service_list[i].service_name == service) {
|
||||||
|
return &g_service_list[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
Registration::Service *Registration::GetFreeService() {
|
||||||
|
return GetService(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Registration::IsValidForSac(u8 *sac, size_t sac_size, u64 service, bool is_host) {
|
||||||
|
u8 cur_ctrl;
|
||||||
|
u64 cur_service;
|
||||||
|
bool cur_is_host;
|
||||||
|
size_t remaining = sac_size;
|
||||||
|
while (remaining) {
|
||||||
|
cur_ctrl = *sac++;
|
||||||
|
remaining--;
|
||||||
|
size_t cur_size = (cur_ctrl & 7) + 1;
|
||||||
|
if (cur_size > remaining) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
cur_is_host = (cur_ctrl & 0x80) != 0;
|
||||||
|
cur_service = 0;
|
||||||
|
for (unsigned int i = 0; i < cur_size; i++) {
|
||||||
|
cur_service |= ((u64)sac[i]) << (8 * i);
|
||||||
|
}
|
||||||
|
/* Check if the last byte is a wildcard ('*') */
|
||||||
|
if (sac[cur_size - 1] == '*') {
|
||||||
|
/* Mask cur_service, service with 0xFF.. up until the wildcard. */
|
||||||
|
cur_service &= U64_MAX >> (8 * (8 - cur_size - 1));
|
||||||
|
service &= U64_MAX >> (8 * (8 - cur_size - 1));
|
||||||
|
}
|
||||||
|
if (cur_service == service && (!is_host || cur_is_host)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
sac += cur_size;
|
||||||
|
remaining -= cur_size;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Registration::ValidateSacAgainstRestriction(u8 *r_sac, size_t r_sac_size, u8 *sac, size_t sac_size) {
|
||||||
|
u8 cur_ctrl;
|
||||||
|
u64 cur_service;
|
||||||
|
bool cur_is_host;
|
||||||
|
size_t remaining = sac_size;
|
||||||
|
while (remaining) {
|
||||||
|
cur_ctrl = *sac++;
|
||||||
|
remaining--;
|
||||||
|
size_t cur_size = (cur_ctrl & 7) + 1;
|
||||||
|
if (cur_size > remaining) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
cur_is_host = (cur_ctrl & 0x80) != 0;
|
||||||
|
cur_service = 0;
|
||||||
|
for (unsigned int i = 0; i < cur_size; i++) {
|
||||||
|
cur_service |= ((u64)sac[i]) << (8 * i);
|
||||||
|
}
|
||||||
|
if (!IsValidForSac(r_sac, r_sac_size, cur_service, cur_is_host)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
sac += cur_size;
|
||||||
|
remaining -= cur_size;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Process management. */
|
||||||
|
Result Registration::RegisterProcess(u64 pid, u8 *acid_sac, size_t acid_sac_size, u8 *aci0_sac, size_t aci0_sac_size) {
|
||||||
|
Registration::Process *proc = GetFreeProcess();
|
||||||
|
if (aci0_sac_size > REGISTRATION_MAX_SAC_SIZE) {
|
||||||
|
return 0x1215;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (proc == NULL) {
|
||||||
|
return 0x215;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (aci0_sac_size && !ValidateSacAgainstRestriction(acid_sac, acid_sac_size, aci0_sac, aci0_sac_size)) {
|
||||||
|
return 0x1015;
|
||||||
|
}
|
||||||
|
|
||||||
|
proc->pid = pid;
|
||||||
|
proc->sac_size = aci0_sac_size;
|
||||||
|
std::copy(aci0_sac, aci0_sac + aci0_sac_size, proc->sac);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result Registration::UnregisterProcess(u64 pid) {
|
||||||
|
Registration::Process *proc = GetProcessForPid(pid);
|
||||||
|
if (proc == NULL) {
|
||||||
|
return 0x415;
|
||||||
|
}
|
||||||
|
|
||||||
|
proc->pid = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Service management. */
|
||||||
|
bool Registration::HasService(u64 service) {
|
||||||
|
for (unsigned int i = 0; i < REGISTRATION_LIST_MAX_SERVICE; i++) {
|
||||||
|
if (g_service_list[i].service_name == service) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result Registration::GetServiceForPid(u64 pid, u64 service, Handle *out) {
|
||||||
|
if (!service) {
|
||||||
|
return 0xC15;
|
||||||
|
}
|
||||||
|
|
||||||
|
u64 service_name_len = 0;
|
||||||
|
while ((service >> (8 * service_name_len)) & 0xFF) {
|
||||||
|
service_name_len++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If the service has bytes after a null terminator, that's no good. */
|
||||||
|
if ((service >> (8 * service_name_len))) {
|
||||||
|
return 0xC15;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pid >= REGISTRATION_PID_BUILTIN_MAX) {
|
||||||
|
Registration::Process *proc = GetProcessForPid(pid);
|
||||||
|
if (proc == NULL) {
|
||||||
|
return 0x415;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!IsValidForSac(proc->sac, proc->sac_size, service, false)) {
|
||||||
|
return 0x1015;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Registration::Service *target_service = GetService(service);
|
||||||
|
if (target_service == NULL) {
|
||||||
|
/* TODO: This defers the request, somehow? Needs to be RE'd in more detail. */
|
||||||
|
return 0x6580A;
|
||||||
|
}
|
||||||
|
|
||||||
|
*out = 0;
|
||||||
|
Result rc = svcConnectToPort(out, target_service->port_h);
|
||||||
|
if (R_FAILED(rc)) {
|
||||||
|
if ((rc & 0x3FFFFF) == 0xE01) {
|
||||||
|
return 0x615;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result Registration::RegisterServiceForPid(u64 pid, u64 service, u64 max_sessions, bool is_light, Handle *out) {
|
||||||
|
if (!service) {
|
||||||
|
return 0xC15;
|
||||||
|
}
|
||||||
|
|
||||||
|
u64 service_name_len = 0;
|
||||||
|
while ((service >> (8 * service_name_len)) & 0xFF) {
|
||||||
|
service_name_len++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If the service has bytes after a null terminator, that's no good. */
|
||||||
|
if ((service >> (8 * service_name_len))) {
|
||||||
|
return 0xC15;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pid >= REGISTRATION_PID_BUILTIN_MAX) {
|
||||||
|
Registration::Process *proc = GetProcessForPid(pid);
|
||||||
|
if (proc == NULL) {
|
||||||
|
return 0x415;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!IsValidForSac(proc->sac, proc->sac_size, service, true)) {
|
||||||
|
return 0x1015;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (HasService(service)) {
|
||||||
|
return 0x815;
|
||||||
|
}
|
||||||
|
|
||||||
|
Registration::Service *free_service = GetFreeService();
|
||||||
|
if (free_service == NULL) {
|
||||||
|
return 0xA15;
|
||||||
|
}
|
||||||
|
|
||||||
|
*out = 0;
|
||||||
|
*free_service = (const Registration::Service){0};
|
||||||
|
Result rc = svcCreatePort(out, &free_service->port_h, max_sessions, is_light, (char *)&free_service->service_name);
|
||||||
|
|
||||||
|
if (R_SUCCEEDED(rc)) {
|
||||||
|
free_service->service_name = service;
|
||||||
|
free_service->owner_pid = pid;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result Registration::UnregisterServiceForPid(u64 pid, u64 service) {
|
||||||
|
if (!service) {
|
||||||
|
return 0xC15;
|
||||||
|
}
|
||||||
|
|
||||||
|
u64 service_name_len = 0;
|
||||||
|
while ((service >> (8 * service_name_len)) & 0xFF) {
|
||||||
|
service_name_len++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If the service has bytes after a null terminator, that's no good. */
|
||||||
|
if ((service >> (8 * service_name_len))) {
|
||||||
|
return 0xC15;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pid >= REGISTRATION_PID_BUILTIN_MAX) {
|
||||||
|
Registration::Process *proc = GetProcessForPid(pid);
|
||||||
|
if (proc == NULL) {
|
||||||
|
return 0x415;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!IsValidForSac(proc->sac, proc->sac_size, service, true)) {
|
||||||
|
return 0x1015;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Registration::Service *target_service = GetService(service);
|
||||||
|
if (target_service == NULL) {
|
||||||
|
return 0xE15;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (target_service->owner_pid != pid) {
|
||||||
|
return 0x1015;
|
||||||
|
}
|
||||||
|
|
||||||
|
svcCloseHandle(target_service->port_h);
|
||||||
|
*target_service = (const Registration::Service){0};
|
||||||
|
return 0;
|
||||||
|
}
|
40
stratosphere/sm/source/sm_registration.hpp
Normal file
40
stratosphere/sm/source/sm_registration.hpp
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
#pragma once
|
||||||
|
#include <switch.h>
|
||||||
|
|
||||||
|
#define REGISTRATION_LIST_MAX_PROCESS (0x40)
|
||||||
|
#define REGISTRATION_LIST_MAX_SERVICE (0x100)
|
||||||
|
#define REGISTRATION_MAX_SAC_SIZE (0x200)
|
||||||
|
#define REGISTRATION_PID_BUILTIN_MAX 0x7
|
||||||
|
|
||||||
|
class Registration {
|
||||||
|
public:
|
||||||
|
struct Process {
|
||||||
|
u64 pid;
|
||||||
|
u64 sac_size;
|
||||||
|
u8 sac[REGISTRATION_MAX_SAC_SIZE];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Service {
|
||||||
|
u64 service_name;
|
||||||
|
u64 owner_pid;
|
||||||
|
Handle port_h;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Utilities. */
|
||||||
|
static Registration::Process *GetProcessForPid(u64 pid);
|
||||||
|
static Registration::Process *GetFreeProcess();
|
||||||
|
static Registration::Service *GetService(u64 service);
|
||||||
|
static Registration::Service *GetFreeService();
|
||||||
|
static bool IsValidForSac(u8 *sac, size_t sac_size, u64 service, bool is_host);
|
||||||
|
static bool ValidateSacAgainstRestriction(u8 *r_sac, size_t r_sac_size, u8 *sac, size_t sac_size);
|
||||||
|
|
||||||
|
/* Process management. */
|
||||||
|
static Result RegisterProcess(u64 pid, u8 *acid_sac, size_t acid_sac_size, u8 *aci0_sac, size_t aci0_sac_size);
|
||||||
|
static Result UnregisterProcess(u64 pid);
|
||||||
|
|
||||||
|
/* Service management. */
|
||||||
|
static bool HasService(u64 service);
|
||||||
|
static Result GetServiceForPid(u64 pid, u64 service, Handle *out);
|
||||||
|
static Result RegisterServiceForPid(u64 pid, u64 service, u64 max_sessions, bool is_light, Handle *out);
|
||||||
|
static Result UnregisterServiceForPid(u64 pid, u64 service);
|
||||||
|
};
|
|
@ -1,5 +1,6 @@
|
||||||
#include <switch.h>
|
#include <switch.h>
|
||||||
#include "sm_user_service.hpp"
|
#include "sm_user_service.hpp"
|
||||||
|
#include "sm_registration.hpp"
|
||||||
|
|
||||||
Result UserService::dispatch(IpcParsedCommand &r, IpcCommand &out_c, u64 cmd_id, u8 *pointer_buffer, size_t pointer_buffer_size) {
|
Result UserService::dispatch(IpcParsedCommand &r, IpcCommand &out_c, u64 cmd_id, u8 *pointer_buffer, size_t pointer_buffer_size) {
|
||||||
Result rc = 0xF601;
|
Result rc = 0xF601;
|
||||||
|
@ -30,16 +31,17 @@ std::tuple<Result> UserService::initialize(PidDescriptor pid) {
|
||||||
}
|
}
|
||||||
|
|
||||||
std::tuple<Result, MovedHandle> UserService::get_service(u64 service) {
|
std::tuple<Result, MovedHandle> UserService::get_service(u64 service) {
|
||||||
/* TODO */
|
Handle session_h = 0;
|
||||||
return std::make_tuple(0xF601, MovedHandle{0});
|
Result rc = Registration::GetServiceForPid(this->pid, service, &session_h);
|
||||||
|
return std::make_tuple(rc, MovedHandle{session_h});
|
||||||
}
|
}
|
||||||
|
|
||||||
std::tuple<Result, MovedHandle> UserService::register_service(u64 service, u8 is_light, u32 max_sessions) {
|
std::tuple<Result, MovedHandle> UserService::register_service(u64 service, u8 is_light, u32 max_sessions) {
|
||||||
/* TODO */
|
Handle service_h = 0;
|
||||||
return std::make_tuple(0xF601, MovedHandle{0});
|
Result rc = Registration::RegisterServiceForPid(this->pid, service, max_sessions, is_light != 0, &service_h);
|
||||||
|
return std::make_tuple(rc, MovedHandle{service_h});
|
||||||
}
|
}
|
||||||
|
|
||||||
std::tuple<Result> UserService::unregister_service(u64 service) {
|
std::tuple<Result> UserService::unregister_service(u64 service) {
|
||||||
/* TODO */
|
return std::make_tuple(Registration::UnregisterServiceForPid(this->pid, service));
|
||||||
return std::make_tuple(0xF601);
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue