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];