mirror of
https://github.com/Atmosphere-NX/Atmosphere.git
synced 2024-12-22 18:32:05 +00:00
exo: add smcAmsGetEmummcConfig
This commit is contained in:
parent
1021b4a455
commit
4f8ab5c599
15 changed files with 156 additions and 39 deletions
|
@ -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)"
|
||||
CFLAGS := \
|
||||
-g \
|
||||
-O2 \
|
||||
-Os \
|
||||
-ffunction-sections \
|
||||
-fdata-sections \
|
||||
-fomit-frame-pointer \
|
||||
|
|
|
@ -29,7 +29,7 @@ ARCH := -march=armv4t -mtune=arm7tdmi -mthumb -mthumb-interwork
|
|||
|
||||
CFLAGS := \
|
||||
-g \
|
||||
-O2 \
|
||||
-Os \
|
||||
-ffunction-sections \
|
||||
-fdata-sections \
|
||||
-fomit-frame-pointer \
|
||||
|
|
|
@ -29,7 +29,7 @@ ARCH := -march=armv4t -mtune=arm7tdmi -mthumb -mthumb-interwork
|
|||
|
||||
CFLAGS := \
|
||||
-g \
|
||||
-O2 \
|
||||
-Os \
|
||||
-ffunction-sections \
|
||||
-fdata-sections \
|
||||
-fomit-frame-pointer \
|
||||
|
|
|
@ -29,7 +29,7 @@ ARCH := -march=armv4t -mtune=arm7tdmi -mthumb -mthumb-interwork
|
|||
|
||||
CFLAGS := \
|
||||
-g \
|
||||
-O2 \
|
||||
-Os \
|
||||
-ffunction-sections \
|
||||
-fdata-sections \
|
||||
-fomit-frame-pointer \
|
||||
|
|
|
@ -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. */
|
||||
*p_outvalue = (int)(fuse_has_rcm_bug_patch());;
|
||||
break;
|
||||
case CONFIGITEM_EMUNAND_CONFIG:
|
||||
/* UNOFFICIAL: Gets configuration meta for emunand. */
|
||||
*p_outvalue = 1; //exosphere_get_emunand_config();
|
||||
break;
|
||||
default:
|
||||
result = 2;
|
||||
break;
|
||||
|
|
|
@ -45,9 +45,6 @@ typedef enum {
|
|||
CONFIGITEM_NEEDS_SHUTDOWN = 65002,
|
||||
CONFIGITEM_EXOSPHERE_VERHASH = 65003,
|
||||
CONFIGITEM_HAS_RCM_BUG_PATCH = 65004,
|
||||
|
||||
/* These are unofficial, emunand-related. */
|
||||
CONFIGITEM_EMUNAND_CONFIG = 65100,
|
||||
} ConfigItem;
|
||||
|
||||
#define REBOOT_KIND_NO_REBOOT 0
|
||||
|
|
66
exosphere/src/emummc_cfg.h
Normal file
66
exosphere/src/emummc_cfg.h
Normal 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
|
|
@ -84,10 +84,10 @@ unsigned int exosphere_should_disable_usermode_exception_handlers(void) {
|
|||
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) {
|
||||
generic_panic();
|
||||
}
|
||||
|
||||
return g_exosphere_cfg.emunand_config;
|
||||
return &g_exosphere_cfg.emummc_cfg;
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include "utils.h"
|
||||
|
||||
#include "memory_map.h"
|
||||
#include "emummc_cfg.h"
|
||||
|
||||
/* 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 target_firmware;
|
||||
uint32_t flags;
|
||||
uint32_t reserved;
|
||||
uint64_t emunand_config;
|
||||
uint32_t reserved[5];
|
||||
exo_emummc_config_t emummc_cfg;
|
||||
} 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_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_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) {
|
||||
const unsigned int magic = MAILBOX_EXOSPHERE_CONFIG_PHYS.magic;
|
||||
|
|
|
@ -819,7 +819,7 @@ strcpy (char *dst0,
|
|||
#if defined(PREFER_SIZE_OVER_SPEED) || defined(__OPTIMIZE_SIZE__)
|
||||
char *s = dst0;
|
||||
|
||||
while (*dst0++ = *src0++)
|
||||
while ((*dst0++ = *src0++))
|
||||
;
|
||||
|
||||
return s;
|
||||
|
|
|
@ -13,8 +13,8 @@
|
|||
* 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 <stdatomic.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
@ -26,6 +26,8 @@
|
|||
#include "synchronization.h"
|
||||
#include "memory_map.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_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[3] = size (must be <= 0x1000 and 4-byte aligned). */
|
||||
/* args->X[4] = 0 for read, 1 for write. */
|
||||
|
||||
|
||||
const uintptr_t dram_address = (uintptr_t)args->X[1];
|
||||
const uintptr_t iram_address = (uintptr_t)args->X[2];
|
||||
const uintptr_t dram_page_offset = (dram_address & 0xFFFULL);
|
||||
const uintptr_t iram_page_offset = (iram_address & 0xFFFULL);
|
||||
const size_t size = args->X[3];
|
||||
const uint32_t option = (uint32_t)args->X[4];
|
||||
|
||||
|
||||
/* Validate addresses. */
|
||||
if (!ams_is_user_addr_valid(dram_address) || !ams_is_iram_addr_valid(iram_address)) {
|
||||
return 2;
|
||||
}
|
||||
|
||||
|
||||
/* Validate size. */
|
||||
if (size > 0x1000 || (size + dram_page_offset) > 0x1000 || (size + iram_page_offset) > 0x1000) {
|
||||
return 2;
|
||||
}
|
||||
|
||||
|
||||
/* Validate alignment. */
|
||||
if (size % sizeof(uint32_t) || dram_page_offset % sizeof(uint32_t) || iram_page_offset % sizeof(uint32_t)) {
|
||||
return 2;
|
||||
}
|
||||
|
||||
|
||||
/* Validate argument. */
|
||||
if (option != 0 && option != 1) {
|
||||
return 2;
|
||||
}
|
||||
|
||||
|
||||
/* Map pages. */
|
||||
ams_map_userpage(dram_address);
|
||||
ams_map_irampage(iram_address);
|
||||
|
||||
|
||||
/* 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 *iram_ptr = (volatile uint32_t *)(AMS_IRAM_PAGE_SECURE_MONITOR_ADDR + iram_page_offset);
|
||||
|
||||
|
||||
volatile uint32_t *dst;
|
||||
volatile uint32_t *src;
|
||||
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;
|
||||
src = dram_ptr;
|
||||
}
|
||||
|
||||
|
||||
/* Actually copy data. */
|
||||
for (size_t i = 0; i < num_dwords; i++) {
|
||||
dst[i] = src[i];
|
||||
}
|
||||
|
||||
|
||||
/* Flush! */
|
||||
flush_dcache_range((void *)dst, (void *)(dst + num_dwords));
|
||||
|
||||
flush_dcache_range((void *)dst, (void *)(dst + num_dwords));
|
||||
|
||||
/* Unmap pages. */
|
||||
ams_unmap_irampage();
|
||||
ams_unmap_userpage();
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -222,3 +224,50 @@ uint32_t ams_write_address(smc_args_t *args) {
|
|||
|
||||
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;
|
||||
}
|
||||
}
|
|
@ -22,6 +22,8 @@
|
|||
uint32_t ams_iram_copy(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_unmap_irampage(void);
|
||||
|
||||
|
|
|
@ -78,6 +78,7 @@ uint32_t smc_read_write_register(smc_args_t *args);
|
|||
/* Atmosphere SMC prototypes */
|
||||
uint32_t smc_ams_iram_copy(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... */
|
||||
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},
|
||||
{0xF0000002, 0, smc_read_write_register},
|
||||
{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]))
|
||||
|
||||
|
@ -724,3 +726,7 @@ uint32_t smc_ams_iram_copy(smc_args_t *args) {
|
|||
uint32_t smc_ams_write_address(smc_args_t *args) {
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -56,7 +56,7 @@ bool upage_init(upage_ref_t *upage, void *user_address) {
|
|||
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. */
|
||||
if (get_page_for_address(user_src) != upage->user_address) {
|
||||
return false;
|
||||
|
@ -67,14 +67,14 @@ bool user_copy_to_secure(upage_ref_t *upage, void *secure_dst, void *user_src, s
|
|||
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) {
|
||||
memcpy(secure_dst, secure_src, size);
|
||||
}
|
||||
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. */
|
||||
if (get_page_for_address(user_dst) != upage->user_address) {
|
||||
return false;
|
||||
|
|
|
@ -33,7 +33,7 @@ typedef struct {
|
|||
|
||||
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 secure_copy_to_user(upage_ref_t *user_page, void *user_dst, void *secure_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, const void *secure_src, size_t size);
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in a new issue