sm: Introduce and use SmServiceName struct (with better codegen)

This commit is contained in:
fincs 2019-10-22 20:10:52 +02:00
parent 7103b08740
commit d025041e3d
No known key found for this signature in database
GPG Key ID: 62C7609ADA219C60
3 changed files with 86 additions and 44 deletions

View File

@ -97,6 +97,55 @@ static inline Result serviceIpcParse(Service* s, IpcParsedCommand* r, size_t siz
#pragma GCC diagnostic pop
/// Structure representing a service name (null terminated, remaining characters set to zero).
typedef struct SmServiceName {
char name[8];
} SmServiceName;
/// Converts a service name into a 64-bit integer.
NX_CONSTEXPR u64 smServiceNameToU64(SmServiceName name)
{
u64 ret = 0;
__builtin_memcpy(&ret, &name, sizeof(u64));
return ret;
}
/// Converts a 64-bit integer into a service name.
NX_CONSTEXPR SmServiceName smServiceNameFromU64(u64 name)
{
SmServiceName ret = {0};
__builtin_memcpy(&ret, &name, sizeof(SmServiceName));
return ret;
}
/**
* @brief Checks whether two service names are equal.
* @param[in] a First name.
* @param[in] b Second name.
* @return Comparison result.
*/
NX_CONSTEXPR bool smServiceNamesAreEqual(SmServiceName a, SmServiceName b)
{
return smServiceNameToU64(a) == smServiceNameToU64(b);
}
/**
* @brief Encodes a service name string as a \ref SmServiceName structure.
* @param[in] name Name of the service.
* @return Encoded name.
*/
NX_CONSTEXPR SmServiceName smEncodeName(const char* name)
{
SmServiceName name_encoded = {};
unsigned len = __builtin_strlen(name);
#define __COPY_CHAR(_n) \
if (len > _n) name_encoded.name[_n] = name[_n]
__COPY_CHAR(0); __COPY_CHAR(1); __COPY_CHAR(2); __COPY_CHAR(3);
__COPY_CHAR(4); __COPY_CHAR(5); __COPY_CHAR(6); __COPY_CHAR(7);
#undef __COPY_CHAR
return name_encoded;
}
/**
* @brief Initializes SM.
* @return Result code.
@ -112,12 +161,12 @@ Result smInitialize(void);
void smExit(void);
/**
* @brief Requests a service from SM.
* @brief Requests a service from SM, allowing overrides.
* @param[out] service_out Service structure which will be filled in.
* @param[in] name Name of the service to request.
* @return Result code.
*/
Result smGetService(Service* service_out, const char* name);
Result smGetServiceWrapper(Service* service_out, SmServiceName name);
/**
* @brief Requests a service from SM, as an IPC session handle directly
@ -125,14 +174,25 @@ Result smGetService(Service* service_out, const char* name);
* @param[in] name Name of the service to request.
* @return Result code.
*/
Result smGetServiceOriginal(Handle* handle_out, u64 name);
Result smGetServiceOriginal(Handle* handle_out, SmServiceName name);
/**
* @brief Requests a service from SM.
* @param[out] service_out Service structure which will be filled in.
* @param[in] name Name of the service to request (as a string).
* @return Result code.
*/
NX_INLINE Result smGetService(Service* service_out, const char* name)
{
return smGetServiceWrapper(service_out, smEncodeName(name));
}
/**
* @brief Retrieves an overriden service in the homebrew environment.
* @param[in] name Name of the service to request (as 64-bit integer).
* @param[in] name Name of the service to request.
* @return IPC session handle.
*/
Handle smGetServiceOverride(u64 name);
Handle smGetServiceOverride(SmServiceName name);
/**
* @brief Creates and registers a new service within SM.
@ -142,14 +202,14 @@ Handle smGetServiceOverride(u64 name);
* @param[in] max_sessions Maximum number of concurrent sessions that the service will accept.
* @return Result code.
*/
Result smRegisterService(Handle* handle_out, const char* name, bool is_light, s32 max_sessions);
Result smRegisterService(Handle* handle_out, SmServiceName name, bool is_light, s32 max_sessions);
/**
* @brief Unregisters a previously registered service in SM.
* @param[in] name Name of the service.
* @return Result code.
*/
Result smUnregisterService(const char* name);
Result smUnregisterService(SmServiceName name);
/**
* @brief Gets the Service session used to communicate with SM.
@ -157,22 +217,9 @@ Result smUnregisterService(const char* name);
*/
Service *smGetServiceSession(void);
/**
* @brief Encodes a service name as a 64-bit integer.
* @param[in] name Name of the service.
* @return Encoded name.
*/
NX_CONSTEXPR u64 smEncodeName(const char* name)
{
u64 name_encoded = 0;
for (unsigned i = 0; name[i] && i < 8; i ++)
name_encoded |= ((u64) name[i]) << (8*i);
return name_encoded;
}
/**
* @brief Overrides a service with a custom IPC service handle.
* @param[in] name Name of the service (as 64-bit integer).
* @param[in] name Name of the service.
* @param[in] handle IPC session handle.
*/
void smAddOverrideHandle(u64 name, Handle handle);
void smAddOverrideHandle(SmServiceName name, Handle handle);

View File

@ -73,7 +73,7 @@ void envSetup(void* ctx, Handle main_thread, LoaderReturnFn saved_lr)
break;
case EntryType_OverrideService:
smAddOverrideHandle(ent->Value[0], ent->Value[1]);
smAddOverrideHandle(smServiceNameFromU64(ent->Value[0]), ent->Value[1]);
break;
case EntryType_Argv:

View File

@ -7,13 +7,13 @@ static Service g_smSrv;
#define MAX_OVERRIDES 32
static struct {
u64 name;
SmServiceName name;
Handle handle;
} g_smOverrides[MAX_OVERRIDES];
static size_t g_smOverridesNum = 0;
void smAddOverrideHandle(u64 name, Handle handle) {
void smAddOverrideHandle(SmServiceName name, Handle handle) {
if (g_smOverridesNum == MAX_OVERRIDES)
fatalSimple(MAKERESULT(Module_Libnx, LibnxError_TooManyOverrides));
@ -25,9 +25,9 @@ void smAddOverrideHandle(u64 name, Handle handle) {
g_smOverridesNum++;
}
Handle smGetServiceOverride(u64 name) {
Handle smGetServiceOverride(SmServiceName name) {
for (size_t i = 0; i < g_smOverridesNum; i++)
if (g_smOverrides[i].name == name)
if (smServiceNamesAreEqual(g_smOverrides[i].name, name))
return g_smOverrides[i].handle;
return INVALID_HANDLE;
@ -48,12 +48,9 @@ Result _smInitialize(void) {
}
Handle tmp;
if (R_SUCCEEDED(rc) && smGetServiceOriginal(&tmp, smEncodeName("")) == 0x415) {
const struct {
u64 pid_placeholder;
} in = { 0 };
rc = serviceDispatchIn(&g_smSrv, 0, in, .in_send_pid = true);
if (R_SUCCEEDED(rc) && smGetServiceOriginal(&tmp, (SmServiceName){}) == 0x415) {
u64 pid_placeholder = 0;
rc = serviceDispatchIn(&g_smSrv, 0, pid_placeholder, .in_send_pid = true);
}
return rc;
@ -67,15 +64,14 @@ Service *smGetServiceSession(void) {
return &g_smSrv;
}
Result smGetService(Service* service_out, const char* name) {
u64 name_encoded = smEncodeName(name);
Handle handle = smGetServiceOverride(name_encoded);
Result smGetServiceWrapper(Service* service_out, SmServiceName name) {
Handle handle = smGetServiceOverride(name);
bool own_handle = false;
Result rc = 0;
if (handle == INVALID_HANDLE) {
own_handle = true;
rc = smGetServiceOriginal(&handle, name_encoded);
rc = smGetServiceOriginal(&handle, name);
}
if (R_SUCCEEDED(rc)) {
@ -86,19 +82,19 @@ Result smGetService(Service* service_out, const char* name) {
return rc;
}
Result smGetServiceOriginal(Handle* handle_out, u64 name) {
Result smGetServiceOriginal(Handle* handle_out, SmServiceName name) {
return serviceDispatchIn(&g_smSrv, 1, name,
.out_handle_attrs = { SfOutHandleAttr_HipcMove },
.out_handles = handle_out,
);
}
Result smRegisterService(Handle* handle_out, const char* name, bool is_light, s32 max_sessions) {
Result smRegisterService(Handle* handle_out, SmServiceName name, bool is_light, s32 max_sessions) {
const struct {
u64 service_name;
SmServiceName service_name;
u8 is_light;
s32 max_sessions;
} in = { smEncodeName(name), is_light!=0, max_sessions };
} in = { name, is_light!=0, max_sessions };
return serviceDispatchIn(&g_smSrv, 2, in,
.out_handle_attrs = { SfOutHandleAttr_HipcMove },
@ -106,7 +102,6 @@ Result smRegisterService(Handle* handle_out, const char* name, bool is_light, s3
);
}
Result smUnregisterService(const char* name) {
u64 service_name = smEncodeName(name);
return serviceDispatchIn(&g_smSrv, 3, service_name);
Result smUnregisterService(SmServiceName name) {
return serviceDispatchIn(&g_smSrv, 3, name);
}