diff --git a/exosphere/Makefile b/exosphere/Makefile index 7c638dfab..3b9792116 100644 --- a/exosphere/Makefile +++ b/exosphere/Makefile @@ -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 \ diff --git a/exosphere/lp0fw/Makefile b/exosphere/lp0fw/Makefile index e8afccfd1..b3b032b84 100644 --- a/exosphere/lp0fw/Makefile +++ b/exosphere/lp0fw/Makefile @@ -29,7 +29,7 @@ ARCH := -march=armv4t -mtune=arm7tdmi -mthumb -mthumb-interwork CFLAGS := \ -g \ - -O2 \ + -Os \ -ffunction-sections \ -fdata-sections \ -fomit-frame-pointer \ diff --git a/exosphere/rebootstub/Makefile b/exosphere/rebootstub/Makefile index 0eadd1314..ff265beef 100644 --- a/exosphere/rebootstub/Makefile +++ b/exosphere/rebootstub/Makefile @@ -29,7 +29,7 @@ ARCH := -march=armv4t -mtune=arm7tdmi -mthumb -mthumb-interwork CFLAGS := \ -g \ - -O2 \ + -Os \ -ffunction-sections \ -fdata-sections \ -fomit-frame-pointer \ diff --git a/exosphere/sc7fw/Makefile b/exosphere/sc7fw/Makefile index 0eadd1314..ff265beef 100644 --- a/exosphere/sc7fw/Makefile +++ b/exosphere/sc7fw/Makefile @@ -29,7 +29,7 @@ ARCH := -march=armv4t -mtune=arm7tdmi -mthumb -mthumb-interwork CFLAGS := \ -g \ - -O2 \ + -Os \ -ffunction-sections \ -fdata-sections \ -fomit-frame-pointer \ diff --git a/exosphere/src/configitem.c b/exosphere/src/configitem.c index 4adb878b3..b53421d6f 100644 --- a/exosphere/src/configitem.c +++ b/exosphere/src/configitem.c @@ -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; diff --git a/exosphere/src/configitem.h b/exosphere/src/configitem.h index f727e87f0..b9600c833 100644 --- a/exosphere/src/configitem.h +++ b/exosphere/src/configitem.h @@ -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 diff --git a/exosphere/src/emummc_cfg.h b/exosphere/src/emummc_cfg.h new file mode 100644 index 000000000..3a7f01f5b --- /dev/null +++ b/exosphere/src/emummc_cfg.h @@ -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 . + */ + +#ifndef EXOSPHERE_EMUMMC_CONFIG_H +#define EXOSPHERE_EMUMMC_CONFIG_H + +#include +#include +#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 diff --git a/exosphere/src/exocfg.c b/exosphere/src/exocfg.c index ad782b33d..7cf9488bd 100644 --- a/exosphere/src/exocfg.c +++ b/exosphere/src/exocfg.c @@ -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; } diff --git a/exosphere/src/exocfg.h b/exosphere/src/exocfg.h index d6a12eb22..316aa5646 100644 --- a/exosphere/src/exocfg.h +++ b/exosphere/src/exocfg.h @@ -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; diff --git a/exosphere/src/my_libc.c b/exosphere/src/my_libc.c index 35bd35bbb..2117f2483 100644 --- a/exosphere/src/my_libc.c +++ b/exosphere/src/my_libc.c @@ -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; diff --git a/exosphere/src/smc_ams.c b/exosphere/src/smc_ams.c index f71d947a6..3fc1769ee 100644 --- a/exosphere/src/smc_ams.c +++ b/exosphere/src/smc_ams.c @@ -13,8 +13,8 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - - + + #include #include #include @@ -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; + } +} \ No newline at end of file diff --git a/exosphere/src/smc_ams.h b/exosphere/src/smc_ams.h index cbae64d63..4061dd454 100644 --- a/exosphere/src/smc_ams.h +++ b/exosphere/src/smc_ams.h @@ -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); diff --git a/exosphere/src/smc_api.c b/exosphere/src/smc_api.c index 65762233e..5a5d6cadc 100644 --- a/exosphere/src/smc_api.c +++ b/exosphere/src/smc_api.c @@ -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); +} diff --git a/exosphere/src/userpage.c b/exosphere/src/userpage.c index 3be1d5335..51cdf48b0 100644 --- a/exosphere/src/userpage.c +++ b/exosphere/src/userpage.c @@ -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; diff --git a/exosphere/src/userpage.h b/exosphere/src/userpage.h index 19c140b20..23742db1c 100644 --- a/exosphere/src/userpage.h +++ b/exosphere/src/userpage.h @@ -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