From add52b90c9c1f8a71be1c577b5e5045c3d1f3bfd Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Sat, 19 Jan 2019 17:31:35 -0800 Subject: [PATCH] exosphere: Add support for AMS SMC extensions --- exosphere/src/smc_ams.c | 33 +++++++++++++++++++++++++++++++++ exosphere/src/smc_ams.h | 24 ++++++++++++++++++++++++ exosphere/src/smc_api.c | 40 +++++++++++++++++++++++++++++++++------- exosphere/src/smc_api.h | 15 +++++++++++++-- 4 files changed, 103 insertions(+), 9 deletions(-) create mode 100644 exosphere/src/smc_ams.c create mode 100644 exosphere/src/smc_ams.h diff --git a/exosphere/src/smc_ams.c b/exosphere/src/smc_ams.c new file mode 100644 index 000000000..98e10146b --- /dev/null +++ b/exosphere/src/smc_ams.c @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2018 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 . + */ + +#include +#include +#include + +#include "utils.h" +#include "smc_api.h" +#include "smc_ams.h" + +uint32_t ams_iram_copy(smc_args_t *args) { + /* TODO: Implement a DRAM <-> IRAM copy of up to one page here. */ + /* This operation is necessary to implement reboot-to-payload. */ + /* args->X[1] = DRAM address (translated by kernel). */ + /* args->X[2] = IRAM address. */ + /* args->X[3] = size (must be <= 0x1000). */ + /* args->X[4] = 0 for read, 1 for write. */ + return 2; +} diff --git a/exosphere/src/smc_ams.h b/exosphere/src/smc_ams.h new file mode 100644 index 000000000..ed1cee156 --- /dev/null +++ b/exosphere/src/smc_ams.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2018 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 . + */ + +#ifndef EXOSPHERE_SMC_AMS_H +#define EXOSPHERE_SMC_AMS_H + +#include "smc_api.h" + +uint32_t ams_iram_copy(smc_args_t *args); + +#endif \ No newline at end of file diff --git a/exosphere/src/smc_api.c b/exosphere/src/smc_api.c index 2cb028589..373919162 100644 --- a/exosphere/src/smc_api.c +++ b/exosphere/src/smc_api.c @@ -31,6 +31,7 @@ #include "sealedkeys.h" #include "smc_api.h" #include "smc_user.h" +#include "smc_ams.h" #include "se.h" #include "userpage.h" #include "titlekey.h" @@ -40,6 +41,8 @@ #define SMC_USER_HANDLERS 0x13 #define SMC_PRIV_HANDLERS 0x9 +#define SMC_AMS_HANDLERS 0x2 + #define DEBUG_LOG_SMCS 0 #define DEBUG_PANIC_ON_FAILURE 0 @@ -77,6 +80,9 @@ uint32_t smc_panic(smc_args_t *args); uint32_t smc_configure_carveout(smc_args_t *args); uint32_t smc_read_write_register(smc_args_t *args); +/* Atmosphere SMC prototypes */ +uint32_t smc_ams_iram_copy(smc_args_t *args); + typedef struct { uint32_t id; uint32_t (*handler)(smc_args_t *args); @@ -121,7 +127,13 @@ static smc_table_entry_t g_smc_priv_table[SMC_PRIV_HANDLERS] = { {0xC3000008, smc_read_write_register} }; -static smc_table_t g_smc_tables[2] = { +/* This is a table used for atmosphere-specific SMCs. */ +static smc_table_entry_t g_smc_ams_table[SMC_AMS_HANDLERS] = { + {0, NULL}, + {0xF0000201, smc_ams_iram_copy}, +}; + +static smc_table_t g_smc_tables[SMC_HANDLER_COUNT + 1] = { { /* SMC_HANDLER_USER */ g_smc_user_table, SMC_USER_HANDLERS @@ -129,6 +141,10 @@ static smc_table_t g_smc_tables[2] = { { /* SMC_HANDLER_PRIV */ g_smc_priv_table, SMC_PRIV_HANDLERS + }, + { /* SMC_HANDLER_AMS */ + g_smc_ams_table, + SMC_AMS_HANDLERS } }; @@ -228,19 +244,25 @@ void clear_smc_callback(uint64_t key) { _Atomic uint64_t num_smcs_called = 0; void call_smc_handler(uint32_t handler_id, smc_args_t *args) { - unsigned char smc_id; + unsigned char smc_id, call_range; unsigned int result; unsigned int (*smc_handler)(smc_args_t *args); /* Validate top-level handler. */ - if (handler_id != SMC_HANDLER_USER && handler_id != SMC_HANDLER_PRIV) { + if (handler_id >= SMC_HANDLER_COUNT) { generic_panic(); } - /* Validate core is appropriate for handler. */ - if (handler_id == SMC_HANDLER_USER && get_core_id() != 3) { - /* USER SMCs must be called via svcCallSecureMonitor on core 3 (where spl runs) */ - generic_panic(); + /* If user-handler, detect if talking to Atmosphere/validate calling core. */ + if (handler_id == SMC_HANDLER_USER) { + if ((call_range = (unsigned char)((args->X[0] >> 24) & 0x3F)) == SMC_CALL_RANGE_TRUSTED_APP) { + /* Nintendo's SMCs are all OEM-specific. */ + /* Pending a reason not to, we will treat Trusted Application SMCs as intended to talk to Atmosphere. */ + handler_id = SMC_HANDLER_AMS; + } else if (get_core_id() != 3) { + /* USER SMCs must be called via svcCallSecureMonitor on core 3 (where spl runs) */ + generic_panic(); + } } /* Validate sub-handler index */ @@ -683,3 +705,7 @@ uint32_t smc_panic(smc_args_t *args) { uint32_t color = ((args->X[1] & 0xF) << 8) | ((args->X[1] & 0xF0)) | ((args->X[1] & 0xF00) >> 8); panic((color << 20) | 0x40); } + +uint32_t smc_ams_iram_copy(smc_args_t *args) { + return smc_wrapper_sync(args, ams_iram_copy); +} diff --git a/exosphere/src/smc_api.h b/exosphere/src/smc_api.h index 476d2a4fe..5f95444fc 100644 --- a/exosphere/src/smc_api.h +++ b/exosphere/src/smc_api.h @@ -19,8 +19,19 @@ #include -#define SMC_HANDLER_USER 0 -#define SMC_HANDLER_PRIV 1 +#define SMC_HANDLER_USER 0 +#define SMC_HANDLER_PRIV 1 +#define SMC_HANDLER_COUNT 2 + +#define SMC_HANDLER_AMS (SMC_HANDLER_COUNT) + +#define SMC_CALL_RANGE_ARM_ARCH 0 +#define SMC_CALL_RANGE_CPU 1 +#define SMC_CALL_RANGE_SIP 2 +#define SMC_CALL_RANGE_OEM 3 +#define SMC_CALL_RANGE_STANDARD 4 + +#define SMC_CALL_RANGE_TRUSTED_APP 0x30 typedef struct { uint64_t X[8];