diff --git a/nx/include/switch.h b/nx/include/switch.h index 800551cb..8006f4ed 100644 --- a/nx/include/switch.h +++ b/nx/include/switch.h @@ -52,6 +52,7 @@ extern "C" { #include "switch/services/csrng.h" #include "switch/services/bpc.h" #include "switch/services/psm.h" +#include "switch/services/spsm.h" //#include "switch/services/bsd.h" Use switch/runtime/devices/socket.h instead #include "switch/services/fatal.h" #include "switch/services/time.h" diff --git a/nx/include/switch/services/spsm.h b/nx/include/switch/services/spsm.h new file mode 100644 index 00000000..3f69c72c --- /dev/null +++ b/nx/include/switch/services/spsm.h @@ -0,0 +1,14 @@ +/** + * @file spsm.h + * @brief SPSM service IPC wrapper. + * @author SciresM + * @copyright libnx Authors + */ +#pragma once +#include "../types.h" + +Result spsmInitialize(void); +void spsmExit(void); + +Result spsmShutdown(bool reboot); +Result spsmPutErrorState(void); diff --git a/nx/source/services/spsm.c b/nx/source/services/spsm.c new file mode 100644 index 00000000..88521610 --- /dev/null +++ b/nx/source/services/spsm.c @@ -0,0 +1,97 @@ +#include "types.h" +#include "result.h" +#include "arm/atomics.h" +#include "kernel/ipc.h" +#include "kernel/detect.h" +#include "services/spsm.h" +#include "services/sm.h" + +static Service g_spsmSrv; +static u64 g_refCnt; + +Result spsmInitialize(void) { + Result rc = 0; + + atomicIncrement64(&g_refCnt); + + if (serviceIsActive(&g_spsmSrv)) + return 0; + + rc = smGetService(&g_spsmSrv, "spsm"); + + if (R_FAILED(rc)) spsmExit(); + + return rc; +} + +void spsmExit(void) { + if (atomicDecrement64(&g_refCnt) == 0) { + serviceClose(&g_spsmSrv); + } +} + +Result spsmShutdown(bool reboot) { + IpcCommand c; + ipcInitialize(&c); + + struct { + u64 magic; + u64 cmd_id; + u32 reboot; + } *raw; + + raw = serviceIpcPrepareHeader(&g_spsmSrv, &c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = 3; + raw->reboot = reboot; + + Result rc = serviceIpcDispatch(&g_spsmSrv); + + if (R_SUCCEEDED(rc)) { + IpcParsedCommand r; + struct { + u64 magic; + u64 result; + } *resp; + + serviceIpcParse(&g_spsmSrv, &r, sizeof(*resp)); + resp = r.Raw; + + rc = resp->result; + } + + return rc; +} + +Result spsmPutErrorState(void) { + IpcCommand c; + ipcInitialize(&c); + + struct { + u64 magic; + u64 cmd_id; + } *raw; + + raw = serviceIpcPrepareHeader(&g_spsmSrv, &c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = 10; + + Result rc = serviceIpcDispatch(&g_spsmSrv); + + if (R_SUCCEEDED(rc)) { + IpcParsedCommand r; + struct { + u64 magic; + u64 result; + } *resp; + + serviceIpcParse(&g_spsmSrv, &r, sizeof(*resp)); + resp = r.Raw; + + rc = resp->result; + } + + return rc; +}