exo: add smcAmsGetEmummcConfig

This commit is contained in:
Michael Scire 2019-06-04 12:31:23 -07:00
parent 1021b4a455
commit 4f8ab5c599
15 changed files with 156 additions and 39 deletions

View file

@ -37,7 +37,7 @@ ARCH := -march=armv8-a -mtune=cortex-a57 -mgeneral-regs-only #<- important
DEFINES := -D__CCPLEX__ -DATMOSPHERE_GIT_BRANCH=\"$(AMSBRANCH)\" -DATMOSPHERE_GIT_REV=\"$(AMSREV)\" -DATMOSPHERE_RELEASE_VERSION_HASH="0x$(AMSHASH)" DEFINES := -D__CCPLEX__ -DATMOSPHERE_GIT_BRANCH=\"$(AMSBRANCH)\" -DATMOSPHERE_GIT_REV=\"$(AMSREV)\" -DATMOSPHERE_RELEASE_VERSION_HASH="0x$(AMSHASH)"
CFLAGS := \ CFLAGS := \
-g \ -g \
-O2 \ -Os \
-ffunction-sections \ -ffunction-sections \
-fdata-sections \ -fdata-sections \
-fomit-frame-pointer \ -fomit-frame-pointer \

View file

@ -29,7 +29,7 @@ ARCH := -march=armv4t -mtune=arm7tdmi -mthumb -mthumb-interwork
CFLAGS := \ CFLAGS := \
-g \ -g \
-O2 \ -Os \
-ffunction-sections \ -ffunction-sections \
-fdata-sections \ -fdata-sections \
-fomit-frame-pointer \ -fomit-frame-pointer \

View file

@ -29,7 +29,7 @@ ARCH := -march=armv4t -mtune=arm7tdmi -mthumb -mthumb-interwork
CFLAGS := \ CFLAGS := \
-g \ -g \
-O2 \ -Os \
-ffunction-sections \ -ffunction-sections \
-fdata-sections \ -fdata-sections \
-fomit-frame-pointer \ -fomit-frame-pointer \

View file

@ -29,7 +29,7 @@ ARCH := -march=armv4t -mtune=arm7tdmi -mthumb -mthumb-interwork
CFLAGS := \ CFLAGS := \
-g \ -g \
-O2 \ -Os \
-ffunction-sections \ -ffunction-sections \
-fdata-sections \ -fdata-sections \
-fomit-frame-pointer \ -fomit-frame-pointer \

View file

@ -284,10 +284,6 @@ uint32_t configitem_get(bool privileged, ConfigItem item, uint64_t *p_outvalue)
/* UNOFFICIAL: Gets whether this unit has the RCM bug patched. */ /* UNOFFICIAL: Gets whether this unit has the RCM bug patched. */
*p_outvalue = (int)(fuse_has_rcm_bug_patch());; *p_outvalue = (int)(fuse_has_rcm_bug_patch());;
break; break;
case CONFIGITEM_EMUNAND_CONFIG:
/* UNOFFICIAL: Gets configuration meta for emunand. */
*p_outvalue = 1; //exosphere_get_emunand_config();
break;
default: default:
result = 2; result = 2;
break; break;

View file

@ -45,9 +45,6 @@ typedef enum {
CONFIGITEM_NEEDS_SHUTDOWN = 65002, CONFIGITEM_NEEDS_SHUTDOWN = 65002,
CONFIGITEM_EXOSPHERE_VERHASH = 65003, CONFIGITEM_EXOSPHERE_VERHASH = 65003,
CONFIGITEM_HAS_RCM_BUG_PATCH = 65004, CONFIGITEM_HAS_RCM_BUG_PATCH = 65004,
/* These are unofficial, emunand-related. */
CONFIGITEM_EMUNAND_CONFIG = 65100,
} ConfigItem; } ConfigItem;
#define REBOOT_KIND_NO_REBOOT 0 #define REBOOT_KIND_NO_REBOOT 0

View file

@ -0,0 +1,66 @@
/*
* Copyright (c) 2018-2019 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_EMUMMC_CONFIG_H
#define EXOSPHERE_EMUMMC_CONFIG_H
#include <stdint.h>
#include <atmosphere.h>
#include "utils.h"
/* "EFS0" */
#define MAGIC_EMUMMC_CONFIG (0x30534645)
#define EMUMMC_FILE_PATH_MAX (0x80)
typedef enum {
EMUMMC_TYPE_NONE = 0,
EMUMMC_TYPE_PARTITION = 1,
EMUMMC_TYPE_FILES = 2,
} emummc_type_t;
typedef enum {
EMUMMC_MMC_NAND = 0,
EMUMMC_MMC_SD = 1,
EMUMMC_MMC_GC = 2,
} emummc_mmc_t;
typedef struct {
uint32_t magic;
uint32_t type;
uint32_t id;
uint32_t fs_version;
} emummc_base_config_t;
typedef struct {
uint64_t start_sector;
} emummc_partition_config_t;
typedef struct {
char path[EMUMMC_FILE_PATH_MAX];
} emummc_file_config_t;
typedef struct {
emummc_base_config_t base_cfg;
union {
emummc_partition_config_t partition_cfg;
emummc_file_config_t file_cfg;
};
} exo_emummc_config_t;
_Static_assert(sizeof(exo_emummc_config_t) == 0x90, "exo_emummc_config_t definition!");
#endif

View file

@ -84,10 +84,10 @@ unsigned int exosphere_should_disable_usermode_exception_handlers(void) {
return EXOSPHERE_CHECK_FLAG(EXOSPHERE_FLAG_DISABLE_USERMODE_EXCEPTION_HANDLERS); return EXOSPHERE_CHECK_FLAG(EXOSPHERE_FLAG_DISABLE_USERMODE_EXCEPTION_HANDLERS);
} }
uint64_t exosphere_get_emunand_config(void) { const exo_emummc_config_t *exosphere_get_emummc_config(void) {
if (!g_has_loaded_config) { if (!g_has_loaded_config) {
generic_panic(); generic_panic();
} }
return g_exosphere_cfg.emunand_config; return &g_exosphere_cfg.emummc_cfg;
} }

View file

@ -22,6 +22,7 @@
#include "utils.h" #include "utils.h"
#include "memory_map.h" #include "memory_map.h"
#include "emummc_cfg.h"
/* This serves to set configuration for *exosphere itself*, separate from the SecMon Exosphere mimics. */ /* This serves to set configuration for *exosphere itself*, separate from the SecMon Exosphere mimics. */
@ -45,11 +46,11 @@ typedef struct {
uint32_t magic; uint32_t magic;
uint32_t target_firmware; uint32_t target_firmware;
uint32_t flags; uint32_t flags;
uint32_t reserved; uint32_t reserved[5];
uint64_t emunand_config; exo_emummc_config_t emummc_cfg;
} exosphere_config_t; } exosphere_config_t;
_Static_assert(sizeof(exosphere_config_t) == 0x18, "exosphere config definition"); _Static_assert(sizeof(exosphere_config_t) == 0x20 + sizeof(exo_emummc_config_t), "exosphere config definition");
unsigned int exosphere_load_config(void); unsigned int exosphere_load_config(void);
unsigned int exosphere_get_target_firmware(void); unsigned int exosphere_get_target_firmware(void);
@ -58,7 +59,7 @@ unsigned int exosphere_should_override_debugmode_priv(void);
unsigned int exosphere_should_override_debugmode_user(void); unsigned int exosphere_should_override_debugmode_user(void);
unsigned int exosphere_should_disable_usermode_exception_handlers(void); unsigned int exosphere_should_disable_usermode_exception_handlers(void);
uint64_t exosphere_get_emunand_config(void); const exo_emummc_config_t *exosphere_get_emummc_config(void);
static inline unsigned int exosphere_get_target_firmware_for_init(void) { static inline unsigned int exosphere_get_target_firmware_for_init(void) {
const unsigned int magic = MAILBOX_EXOSPHERE_CONFIG_PHYS.magic; const unsigned int magic = MAILBOX_EXOSPHERE_CONFIG_PHYS.magic;

View file

@ -819,7 +819,7 @@ strcpy (char *dst0,
#if defined(PREFER_SIZE_OVER_SPEED) || defined(__OPTIMIZE_SIZE__) #if defined(PREFER_SIZE_OVER_SPEED) || defined(__OPTIMIZE_SIZE__)
char *s = dst0; char *s = dst0;
while (*dst0++ = *src0++) while ((*dst0++ = *src0++))
; ;
return s; return s;

View file

@ -13,8 +13,8 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <stdatomic.h> #include <stdatomic.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
@ -26,6 +26,8 @@
#include "synchronization.h" #include "synchronization.h"
#include "memory_map.h" #include "memory_map.h"
#include "mmu.h" #include "mmu.h"
#include "userpage.h"
#include "exocfg.h"
static atomic_flag g_ams_userpage_mapped = ATOMIC_FLAG_INIT; static atomic_flag g_ams_userpage_mapped = ATOMIC_FLAG_INIT;
static atomic_flag g_ams_iram_page_mapped = ATOMIC_FLAG_INIT; static atomic_flag g_ams_iram_page_mapped = ATOMIC_FLAG_INIT;
@ -94,42 +96,42 @@ uint32_t ams_iram_copy(smc_args_t *args) {
/* args->X[2] = IRAM address, must be 4-byte aligned. */ /* args->X[2] = IRAM address, must be 4-byte aligned. */
/* args->X[3] = size (must be <= 0x1000 and 4-byte aligned). */ /* args->X[3] = size (must be <= 0x1000 and 4-byte aligned). */
/* args->X[4] = 0 for read, 1 for write. */ /* args->X[4] = 0 for read, 1 for write. */
const uintptr_t dram_address = (uintptr_t)args->X[1]; const uintptr_t dram_address = (uintptr_t)args->X[1];
const uintptr_t iram_address = (uintptr_t)args->X[2]; const uintptr_t iram_address = (uintptr_t)args->X[2];
const uintptr_t dram_page_offset = (dram_address & 0xFFFULL); const uintptr_t dram_page_offset = (dram_address & 0xFFFULL);
const uintptr_t iram_page_offset = (iram_address & 0xFFFULL); const uintptr_t iram_page_offset = (iram_address & 0xFFFULL);
const size_t size = args->X[3]; const size_t size = args->X[3];
const uint32_t option = (uint32_t)args->X[4]; const uint32_t option = (uint32_t)args->X[4];
/* Validate addresses. */ /* Validate addresses. */
if (!ams_is_user_addr_valid(dram_address) || !ams_is_iram_addr_valid(iram_address)) { if (!ams_is_user_addr_valid(dram_address) || !ams_is_iram_addr_valid(iram_address)) {
return 2; return 2;
} }
/* Validate size. */ /* Validate size. */
if (size > 0x1000 || (size + dram_page_offset) > 0x1000 || (size + iram_page_offset) > 0x1000) { if (size > 0x1000 || (size + dram_page_offset) > 0x1000 || (size + iram_page_offset) > 0x1000) {
return 2; return 2;
} }
/* Validate alignment. */ /* Validate alignment. */
if (size % sizeof(uint32_t) || dram_page_offset % sizeof(uint32_t) || iram_page_offset % sizeof(uint32_t)) { if (size % sizeof(uint32_t) || dram_page_offset % sizeof(uint32_t) || iram_page_offset % sizeof(uint32_t)) {
return 2; return 2;
} }
/* Validate argument. */ /* Validate argument. */
if (option != 0 && option != 1) { if (option != 0 && option != 1) {
return 2; return 2;
} }
/* Map pages. */ /* Map pages. */
ams_map_userpage(dram_address); ams_map_userpage(dram_address);
ams_map_irampage(iram_address); ams_map_irampage(iram_address);
/* Set source/destination for copy. */ /* Set source/destination for copy. */
volatile uint32_t *dram_ptr = (volatile uint32_t *)(AMS_USER_PAGE_SECURE_MONITOR_ADDR + dram_page_offset); volatile uint32_t *dram_ptr = (volatile uint32_t *)(AMS_USER_PAGE_SECURE_MONITOR_ADDR + dram_page_offset);
volatile uint32_t *iram_ptr = (volatile uint32_t *)(AMS_IRAM_PAGE_SECURE_MONITOR_ADDR + iram_page_offset); volatile uint32_t *iram_ptr = (volatile uint32_t *)(AMS_IRAM_PAGE_SECURE_MONITOR_ADDR + iram_page_offset);
volatile uint32_t *dst; volatile uint32_t *dst;
volatile uint32_t *src; volatile uint32_t *src;
const size_t num_dwords = size / sizeof(uint32_t); const size_t num_dwords = size / sizeof(uint32_t);
@ -140,19 +142,19 @@ uint32_t ams_iram_copy(smc_args_t *args) {
dst = iram_ptr; dst = iram_ptr;
src = dram_ptr; src = dram_ptr;
} }
/* Actually copy data. */ /* Actually copy data. */
for (size_t i = 0; i < num_dwords; i++) { for (size_t i = 0; i < num_dwords; i++) {
dst[i] = src[i]; dst[i] = src[i];
} }
/* Flush! */ /* Flush! */
flush_dcache_range((void *)dst, (void *)(dst + num_dwords)); flush_dcache_range((void *)dst, (void *)(dst + num_dwords));
/* Unmap pages. */ /* Unmap pages. */
ams_unmap_irampage(); ams_unmap_irampage();
ams_unmap_userpage(); ams_unmap_userpage();
return 0; return 0;
} }
@ -222,3 +224,50 @@ uint32_t ams_write_address(smc_args_t *args) {
return 0; return 0;
} }
uint32_t ams_get_emummc_config(smc_args_t *args) {
/* This retrieves configuration for the current emummc context. */
/* args->X[1] = MMC id, must be size-bytes aligned and readable by EL0. */
/* args->X[2] = Pointer to output (for path for filebased), must be at least 0x80 bytes. */
upage_ref_t page_ref;
const uint32_t mmc_id = (uint32_t)args->X[1];
void *user_address = (void *)args->X[2];
const exo_emummc_config_t *emummc_cfg = exosphere_get_emummc_config();
if (mmc_id != EMUMMC_MMC_NAND) {
/* Emummc config for non-NAND storage is not yet implemented. */
return 1;
}
if (emummc_cfg->base_cfg.type == EMUMMC_TYPE_NONE) {
/* Just copy base config. */
memset(args, 0, sizeof(*args));
memcpy(&args->X[1], emummc_cfg, sizeof(emummc_cfg->base_cfg));
_Static_assert(sizeof(emummc_cfg->base_cfg) <= sizeof(*args) - sizeof(args->X[0]), "Emunand base config too big!");
return 0;
} else if (emummc_cfg->base_cfg.type == EMUMMC_TYPE_PARTITION) {
/* Copy base config and partition config. */
memset(args, 0, sizeof(*args));
memcpy(&args->X[1], emummc_cfg, sizeof(emummc_cfg->base_cfg) + sizeof(emummc_cfg->partition_cfg));
_Static_assert(sizeof(emummc_cfg->base_cfg) + sizeof(emummc_cfg->partition_cfg) <= sizeof(*args) - sizeof(args->X[0]), "Emunand partition config too big!");
return 0;
} else if (emummc_cfg->base_cfg.type == EMUMMC_TYPE_FILES) {
/* Copy path to userpage. */
/* Initialize page reference. */
if (upage_init(&page_ref, user_address) == 0) {
return 2;
}
/* Copy result output back to user. */
if (secure_copy_to_user(&page_ref, user_address, &emummc_cfg->file_cfg, sizeof(emummc_cfg->file_cfg)) == 0) {
return 2;
}
/* Copy base config afterwards, since this can't fail. */
memset(args, 0, sizeof(*args));
memcpy(&args->X[1], emummc_cfg, sizeof(emummc_cfg->base_cfg));
_Static_assert(sizeof(emummc_cfg->base_cfg) <= sizeof(*args) - sizeof(args->X[0]), "Emunand base config too big!");
return 0;
} else {
return 2;
}
}

View file

@ -22,6 +22,8 @@
uint32_t ams_iram_copy(smc_args_t *args); uint32_t ams_iram_copy(smc_args_t *args);
uint32_t ams_write_address(smc_args_t *args); uint32_t ams_write_address(smc_args_t *args);
uint32_t ams_get_emummc_config(smc_args_t *args);
void ams_map_irampage(uintptr_t iram_address); void ams_map_irampage(uintptr_t iram_address);
void ams_unmap_irampage(void); void ams_unmap_irampage(void);

View file

@ -78,6 +78,7 @@ uint32_t smc_read_write_register(smc_args_t *args);
/* Atmosphere SMC prototypes */ /* Atmosphere SMC prototypes */
uint32_t smc_ams_iram_copy(smc_args_t *args); uint32_t smc_ams_iram_copy(smc_args_t *args);
uint32_t smc_ams_write_address(smc_args_t *args); uint32_t smc_ams_write_address(smc_args_t *args);
uint32_t smc_ams_get_emummc_config(smc_args_t *args);
/* TODO: Provide a way to set this. It's 0 on non-recovery boot anyway... */ /* TODO: Provide a way to set this. It's 0 on non-recovery boot anyway... */
static uint32_t g_smc_blacklist_mask = 0; static uint32_t g_smc_blacklist_mask = 0;
@ -135,6 +136,7 @@ static smc_table_entry_t g_smc_ams_table[] = {
{0xF0000201, 0, smc_ams_iram_copy}, {0xF0000201, 0, smc_ams_iram_copy},
{0xF0000002, 0, smc_read_write_register}, {0xF0000002, 0, smc_read_write_register},
{0xF0000003, 0, smc_ams_write_address}, {0xF0000003, 0, smc_ams_write_address},
{0xF0000404, 0, smc_ams_get_emummc_config},
}; };
#define SMC_AMS_HANDLERS (sizeof(g_smc_ams_table) / sizeof(g_smc_ams_table[0])) #define SMC_AMS_HANDLERS (sizeof(g_smc_ams_table) / sizeof(g_smc_ams_table[0]))
@ -724,3 +726,7 @@ uint32_t smc_ams_iram_copy(smc_args_t *args) {
uint32_t smc_ams_write_address(smc_args_t *args) { uint32_t smc_ams_write_address(smc_args_t *args) {
return smc_wrapper_sync(args, ams_write_address); return smc_wrapper_sync(args, ams_write_address);
} }
uint32_t smc_ams_get_emummc_config(smc_args_t *args) {
return smc_wrapper_sync(args, ams_get_emummc_config);
}

View file

@ -23,7 +23,7 @@
static uintptr_t g_user_page_user_address = 0ull; static uintptr_t g_user_page_user_address = 0ull;
static inline uintptr_t get_page_for_address(void *address) { static inline uintptr_t get_page_for_address(const void *address) {
return ((uintptr_t)(address)) & ~0xFFFULL; return ((uintptr_t)(address)) & ~0xFFFULL;
} }
@ -56,7 +56,7 @@ bool upage_init(upage_ref_t *upage, void *user_address) {
return upage->secure_monitor_address != 0ull; return upage->secure_monitor_address != 0ull;
} }
bool user_copy_to_secure(upage_ref_t *upage, void *secure_dst, void *user_src, size_t size) { bool user_copy_to_secure(upage_ref_t *upage, void *secure_dst, const void *user_src, size_t size) {
/* Fail if the page doesn't match. */ /* Fail if the page doesn't match. */
if (get_page_for_address(user_src) != upage->user_address) { if (get_page_for_address(user_src) != upage->user_address) {
return false; return false;
@ -67,14 +67,14 @@ bool user_copy_to_secure(upage_ref_t *upage, void *secure_dst, void *user_src, s
return false; return false;
} }
void *secure_src = (void *)(upage->secure_monitor_address + ((uintptr_t)user_src - upage->user_address)); const void *secure_src = (const void *)(upage->secure_monitor_address + ((uintptr_t)user_src - upage->user_address));
if (size != 0) { if (size != 0) {
memcpy(secure_dst, secure_src, size); memcpy(secure_dst, secure_src, size);
} }
return true; return true;
} }
bool secure_copy_to_user(upage_ref_t *upage, void *user_dst, void *secure_src, size_t size) { bool secure_copy_to_user(upage_ref_t *upage, void *user_dst, const void *secure_src, size_t size) {
/* Fail if the page doesn't match. */ /* Fail if the page doesn't match. */
if (get_page_for_address(user_dst) != upage->user_address) { if (get_page_for_address(user_dst) != upage->user_address) {
return false; return false;

View file

@ -33,7 +33,7 @@ typedef struct {
bool upage_init(upage_ref_t *user_page, void *user_address); bool upage_init(upage_ref_t *user_page, void *user_address);
bool user_copy_to_secure(upage_ref_t *user_page, void *secure_dst, void *user_src, size_t size); bool user_copy_to_secure(upage_ref_t *user_page, void *secure_dst, const void *user_src, size_t size);
bool secure_copy_to_user(upage_ref_t *user_page, void *user_dst, void *secure_src, size_t size); bool secure_copy_to_user(upage_ref_t *user_page, void *user_dst, const void *secure_src, size_t size);
#endif #endif