exosphere: Add support for AMS SMC extensions

This commit is contained in:
Michael Scire 2019-01-19 17:31:35 -08:00
parent c42fc16d8e
commit add52b90c9
4 changed files with 103 additions and 9 deletions

33
exosphere/src/smc_ams.c Normal file
View file

@ -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 <http://www.gnu.org/licenses/>.
*/
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#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;
}

24
exosphere/src/smc_ams.h Normal file
View file

@ -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 <http://www.gnu.org/licenses/>.
*/
#ifndef EXOSPHERE_SMC_AMS_H
#define EXOSPHERE_SMC_AMS_H
#include "smc_api.h"
uint32_t ams_iram_copy(smc_args_t *args);
#endif

View file

@ -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,20 +244,26 @@ 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) {
/* 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 */
if ((smc_id = (unsigned char)args->X[0]) >= g_smc_tables[handler_id].num_handlers) {
@ -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);
}

View file

@ -21,6 +21,17 @@
#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];