mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2024-11-09 22:56:35 +00:00
reboot_to_payload: Use ams:bpc API to set payload, reboot safely and prevent usage on Mariko (#1543)
This commit is contained in:
parent
2ab01ad33c
commit
c02f32f1bf
4 changed files with 173 additions and 47 deletions
45
troposphere/reboot_to_payload/source/ams_bpc.c
Normal file
45
troposphere/reboot_to_payload/source/ams_bpc.c
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#include <switch.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "ams_bpc.h"
|
||||||
|
#include "service_guard.h"
|
||||||
|
|
||||||
|
static Service g_amsBpcSrv;
|
||||||
|
|
||||||
|
NX_GENERATE_SERVICE_GUARD(amsBpc);
|
||||||
|
|
||||||
|
Result _amsBpcInitialize(void) {
|
||||||
|
Handle h;
|
||||||
|
Result rc = svcConnectToNamedPort(&h, "bpc:ams"); /* TODO: ams:bpc */
|
||||||
|
if (R_SUCCEEDED(rc)) serviceCreate(&g_amsBpcSrv, h);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _amsBpcCleanup(void) {
|
||||||
|
serviceClose(&g_amsBpcSrv);
|
||||||
|
}
|
||||||
|
|
||||||
|
Service *amsBpcGetServiceSession(void) {
|
||||||
|
return &g_amsBpcSrv;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result amsBpcSetRebootPayload(const void *src, size_t src_size) {
|
||||||
|
return serviceDispatch(&g_amsBpcSrv, 65001,
|
||||||
|
.buffer_attrs = { SfBufferAttr_In | SfBufferAttr_HipcMapAlias },
|
||||||
|
.buffers = { { src, src_size } },
|
||||||
|
);
|
||||||
|
}
|
31
troposphere/reboot_to_payload/source/ams_bpc.h
Normal file
31
troposphere/reboot_to_payload/source/ams_bpc.h
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <switch.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
Result amsBpcInitialize();
|
||||||
|
void amsBpcExit();
|
||||||
|
Service *amsBpcGetServiceSession(void);
|
||||||
|
|
||||||
|
Result amsBpcSetRebootPayload(const void *src, size_t src_size);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
|
@ -3,51 +3,26 @@
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
#include <switch.h>
|
#include <switch.h>
|
||||||
|
#include "ams_bpc.h"
|
||||||
|
|
||||||
#define IRAM_PAYLOAD_MAX_SIZE 0x24000
|
#define IRAM_PAYLOAD_MAX_SIZE 0x24000
|
||||||
#define IRAM_PAYLOAD_BASE 0x40010000
|
static u8 g_reboot_payload[IRAM_PAYLOAD_MAX_SIZE];
|
||||||
|
|
||||||
static alignas(0x1000) u8 g_reboot_payload[IRAM_PAYLOAD_MAX_SIZE];
|
void userAppExit(void)
|
||||||
static alignas(0x1000) u8 g_ff_page[0x1000];
|
{
|
||||||
static alignas(0x1000) u8 g_work_page[0x1000];
|
amsBpcExit();
|
||||||
|
setsysExit();
|
||||||
void do_iram_dram_copy(void *buf, uintptr_t iram_addr, size_t size, int option) {
|
spsmExit();
|
||||||
memcpy(g_work_page, buf, size);
|
|
||||||
|
|
||||||
SecmonArgs args = {0};
|
|
||||||
args.X[0] = 0xF0000201; /* smcAmsIramCopy */
|
|
||||||
args.X[1] = (uintptr_t)g_work_page; /* DRAM Address */
|
|
||||||
args.X[2] = iram_addr; /* IRAM Address */
|
|
||||||
args.X[3] = size; /* Copy size */
|
|
||||||
args.X[4] = option; /* 0 = Read, 1 = Write */
|
|
||||||
svcCallSecureMonitor(&args);
|
|
||||||
|
|
||||||
memcpy(buf, g_work_page, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
void copy_to_iram(uintptr_t iram_addr, void *buf, size_t size) {
|
|
||||||
do_iram_dram_copy(buf, iram_addr, size, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
void copy_from_iram(void *buf, uintptr_t iram_addr, size_t size) {
|
|
||||||
do_iram_dram_copy(buf, iram_addr, size, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void clear_iram(void) {
|
|
||||||
memset(g_ff_page, 0xFF, sizeof(g_ff_page));
|
|
||||||
for (size_t i = 0; i < IRAM_PAYLOAD_MAX_SIZE; i += sizeof(g_ff_page)) {
|
|
||||||
copy_to_iram(IRAM_PAYLOAD_BASE + i, g_ff_page, sizeof(g_ff_page));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void reboot_to_payload(void) {
|
static void reboot_to_payload(void) {
|
||||||
clear_iram();
|
Result rc = amsBpcSetRebootPayload(g_reboot_payload, IRAM_PAYLOAD_MAX_SIZE);
|
||||||
|
if (R_FAILED(rc)) {
|
||||||
for (size_t i = 0; i < IRAM_PAYLOAD_MAX_SIZE; i += 0x1000) {
|
printf("Failed to set reboot payload: 0x%x\n", rc);
|
||||||
copy_to_iram(IRAM_PAYLOAD_BASE + i, &g_reboot_payload[i], 0x1000);
|
}
|
||||||
|
else {
|
||||||
|
spsmShutdown(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
splSetConfig((SplConfigItem)65001, 2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
|
@ -59,12 +34,36 @@ int main(int argc, char **argv)
|
||||||
PadState pad;
|
PadState pad;
|
||||||
padInitializeAny(&pad);
|
padInitializeAny(&pad);
|
||||||
|
|
||||||
|
Result rc = 0;
|
||||||
bool can_reboot = true;
|
bool can_reboot = true;
|
||||||
Result rc = splInitialize();
|
|
||||||
if (R_FAILED(rc)) {
|
if (R_FAILED(rc = setsysInitialize())) {
|
||||||
printf("Failed to initialize spl: 0x%x\n", rc);
|
printf("Failed to initialize set:sys: 0x%x\n", rc);
|
||||||
can_reboot = false;
|
can_reboot = false;
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
|
SetSysProductModel model;
|
||||||
|
setsysGetProductModel(&model);
|
||||||
|
if (model != SetSysProductModel_Nx && model != SetSysProductModel_Copper) {
|
||||||
|
printf("Reboot to payload cannot be used on a Mariko system\n");
|
||||||
|
can_reboot = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (can_reboot && R_FAILED(rc = spsmInitialize())) {
|
||||||
|
printf("Failed to initialize spsm: 0x%x\n", rc);
|
||||||
|
can_reboot = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (can_reboot) {
|
||||||
|
smExit(); //Required to connect to ams:bpc
|
||||||
|
if R_FAILED(rc = amsBpcInitialize()) {
|
||||||
|
printf("Failed to initialize ams:bpc: 0x%x\n", rc);
|
||||||
|
can_reboot = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (can_reboot) {
|
||||||
FILE *f = fopen("sdmc:/atmosphere/reboot_payload.bin", "rb");
|
FILE *f = fopen("sdmc:/atmosphere/reboot_payload.bin", "rb");
|
||||||
if (f == NULL) {
|
if (f == NULL) {
|
||||||
printf("Failed to open atmosphere/reboot_payload.bin!\n");
|
printf("Failed to open atmosphere/reboot_payload.bin!\n");
|
||||||
|
@ -92,11 +91,6 @@ int main(int argc, char **argv)
|
||||||
consoleUpdate(NULL);
|
consoleUpdate(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (can_reboot) {
|
|
||||||
splExit();
|
|
||||||
}
|
|
||||||
|
|
||||||
consoleExit(NULL);
|
consoleExit(NULL);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
56
troposphere/reboot_to_payload/source/service_guard.h
Normal file
56
troposphere/reboot_to_payload/source/service_guard.h
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
#pragma once
|
||||||
|
#include <switch/types.h>
|
||||||
|
#include <switch/result.h>
|
||||||
|
#include <switch/kernel/mutex.h>
|
||||||
|
#include <switch/sf/service.h>
|
||||||
|
#include <switch/services/sm.h>
|
||||||
|
|
||||||
|
typedef struct ServiceGuard {
|
||||||
|
Mutex mutex;
|
||||||
|
u32 refCount;
|
||||||
|
} ServiceGuard;
|
||||||
|
|
||||||
|
NX_INLINE bool serviceGuardBeginInit(ServiceGuard* g)
|
||||||
|
{
|
||||||
|
mutexLock(&g->mutex);
|
||||||
|
return (g->refCount++) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
NX_INLINE Result serviceGuardEndInit(ServiceGuard* g, Result rc, void (*cleanupFunc)(void))
|
||||||
|
{
|
||||||
|
if (R_FAILED(rc)) {
|
||||||
|
cleanupFunc();
|
||||||
|
--g->refCount;
|
||||||
|
}
|
||||||
|
mutexUnlock(&g->mutex);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
NX_INLINE void serviceGuardExit(ServiceGuard* g, void (*cleanupFunc)(void))
|
||||||
|
{
|
||||||
|
mutexLock(&g->mutex);
|
||||||
|
if (g->refCount && (--g->refCount) == 0)
|
||||||
|
cleanupFunc();
|
||||||
|
mutexUnlock(&g->mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define NX_GENERATE_SERVICE_GUARD_PARAMS(name, _paramdecl, _parampass) \
|
||||||
|
\
|
||||||
|
static ServiceGuard g_##name##Guard; \
|
||||||
|
NX_INLINE Result _##name##Initialize _paramdecl; \
|
||||||
|
static void _##name##Cleanup(void); \
|
||||||
|
\
|
||||||
|
Result name##Initialize _paramdecl \
|
||||||
|
{ \
|
||||||
|
Result rc = 0; \
|
||||||
|
if (serviceGuardBeginInit(&g_##name##Guard)) \
|
||||||
|
rc = _##name##Initialize _parampass; \
|
||||||
|
return serviceGuardEndInit(&g_##name##Guard, rc, _##name##Cleanup); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
void name##Exit(void) \
|
||||||
|
{ \
|
||||||
|
serviceGuardExit(&g_##name##Guard, _##name##Cleanup); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define NX_GENERATE_SERVICE_GUARD(name) NX_GENERATE_SERVICE_GUARD_PARAMS(name, (void), ())
|
Loading…
Reference in a new issue