From 7e6ff1f327f6750a08cb25e81d5b16f73c83ceb0 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Sat, 7 Dec 2019 15:35:34 -0800 Subject: [PATCH] exosphere: support enabling usermode pmu regs (closes #703) --- common/defaults/BCT.ini | 2 ++ docs/changelog.md | 2 ++ exosphere/src/configitem.c | 23 ++++++++++++++++------- exosphere/src/configitem.h | 5 +++-- exosphere/src/exocfg.c | 8 ++++++++ exosphere/src/exocfg.h | 2 ++ exosphere/src/package2.c | 3 +++ fusee/fusee-secondary/src/exocfg.h | 4 +++- fusee/fusee-secondary/src/nxboot.c | 7 +++++++ 9 files changed, 46 insertions(+), 10 deletions(-) diff --git a/common/defaults/BCT.ini b/common/defaults/BCT.ini index 66072d982..d483c810e 100644 --- a/common/defaults/BCT.ini +++ b/common/defaults/BCT.ini @@ -12,6 +12,8 @@ debugmode_user = 0 ; Note: Disabling usermode exception handlers will cause atmosphere to not fail gracefully under error conditions. ; Support will not be provided to users who disable these. If you do not know what you are doing, leave them on. disable_user_exception_handlers = 0 +; Note: It's currently unknown what effects enabling the usermode PMU register access may have on official code. +enable_user_pmu_access = 0 [stratosphere] ; To force-enable nogc, add nogc = 1 diff --git a/docs/changelog.md b/docs/changelog.md index 94637bdae..de0f5c3f2 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -47,6 +47,8 @@ + An extension was added to pm:info to allow querying a process's override status. + Thanks to process override capture improvements, hbl html behavior has been greatly improved. + Web applets launched by hbl will now always see the /atmosphere/hbl_html filesystem ++ Support was added to exosphere for enabling usermode access to the PMU registers. + + This can be controlled via exosphere!enable_user_pmu_access in BCT.ini. + An enormous number of minor bugs were fixed. + dmnt's cheat VM had a fix for an inversion in opcode behavior. + An issue was fixed in fs.mitm's management of domain object IDs that could lead to system corruption in rare cases. diff --git a/exosphere/src/configitem.c b/exosphere/src/configitem.c index b53421d6f..84ca86acb 100644 --- a/exosphere/src/configitem.c +++ b/exosphere/src/configitem.c @@ -13,7 +13,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + #include #include @@ -38,6 +38,7 @@ static bool g_hiz_mode_enabled = false; static bool g_debugmode_override_user = false, g_debugmode_override_priv = false; static bool g_enable_usermode_exception_handlers = true; +static bool g_enable_usermode_pmu_access = false; uint32_t configitem_set(bool privileged, ConfigItem item, uint64_t value) { switch (item) { @@ -63,14 +64,14 @@ uint32_t configitem_set(bool privileged, ConfigItem item, uint64_t value) { /* Set SVC handler to jump to reboot stub in IRAM. */ MAKE_REG32(MMIO_GET_DEVICE_ADDRESS(MMIO_DEVID_RTC_PMC) + 0x520ull) = 0x4003F000; MAKE_REG32(MMIO_GET_DEVICE_ADDRESS(MMIO_DEVID_RTC_PMC) + 0x53Cull) = 0x6000F208; - + /* Copy reboot stub payload. */ ams_map_irampage(0x4003F000); for (unsigned int i = 0; i < rebootstub_bin_size; i += 4) { MAKE_REG32(MMIO_GET_DEVICE_ADDRESS(MMIO_DEVID_AMS_IRAM_PAGE) + i) = read32le(rebootstub_bin, i); } ams_unmap_irampage(); - + /* Ensure stub is flushed. */ flush_dcache_all(); break; @@ -95,7 +96,7 @@ uint32_t configitem_set(bool privileged, ConfigItem item, uint64_t value) { /* Set SVC handler to jump to reboot stub in IRAM. */ MAKE_REG32(MMIO_GET_DEVICE_ADDRESS(MMIO_DEVID_RTC_PMC) + 0x520ull) = 0x4003F000; MAKE_REG32(MMIO_GET_DEVICE_ADDRESS(MMIO_DEVID_RTC_PMC) + 0x53Cull) = 0x6000F208; - + /* Copy reboot stub payload. */ ams_map_irampage(0x4003F000); for (unsigned int i = 0; i < rebootstub_bin_size; i += 4) { @@ -104,7 +105,7 @@ uint32_t configitem_set(bool privileged, ConfigItem item, uint64_t value) { /* Tell rebootstub to shut down. */ MAKE_REG32(MMIO_GET_DEVICE_ADDRESS(MMIO_DEVID_AMS_IRAM_PAGE) + 0x10) = 0x0; ams_unmap_irampage(); - + MAKE_REG32(MMIO_GET_DEVICE_ADDRESS(MMIO_DEVID_RTC_PMC) + 0x400ull) = 0x10; while (1) { } } @@ -112,7 +113,7 @@ uint32_t configitem_set(bool privileged, ConfigItem item, uint64_t value) { default: return 2; } - + return 0; } @@ -168,6 +169,10 @@ void configitem_disable_usermode_exception_handlers(void) { g_enable_usermode_exception_handlers = false; } +void configitem_enable_usermode_pmu_access(void) { + g_enable_usermode_pmu_access = true; +} + uint32_t configitem_get(bool privileged, ConfigItem item, uint64_t *p_outvalue) { uint32_t result = 0; switch (item) { @@ -222,6 +227,10 @@ uint32_t configitem_get(bool privileged, ConfigItem item, uint64_t *p_outvalue) if (g_enable_usermode_exception_handlers) { config |= KERNELCONFIGFLAG_ENABLE_USER_EXCEPTION_HANDLERS; } + /* Allow for enabling usermode pmu access. */ + if (g_enable_usermode_pmu_access) { + config |= KERNELCONFIGFLAG_ENABLE_USER_PMU_ACCESS; + } *p_outvalue = config; } break; @@ -262,7 +271,7 @@ uint32_t configitem_get(bool privileged, ConfigItem item, uint64_t *p_outvalue) break; case CONFIGITEM_EXOSPHERE_VERSION: /* UNOFFICIAL: Gets information about the current exosphere version. */ - *p_outvalue = ((uint64_t)(ATMOSPHERE_RELEASE_VERSION_MAJOR & 0xFF) << 32ull) | + *p_outvalue = ((uint64_t)(ATMOSPHERE_RELEASE_VERSION_MAJOR & 0xFF) << 32ull) | ((uint64_t)(ATMOSPHERE_RELEASE_VERSION_MINOR & 0xFF) << 24ull) | ((uint64_t)(ATMOSPHERE_RELEASE_VERSION_MICRO & 0xFF) << 16ull) | ((uint64_t)(exosphere_get_target_firmware() & 0xFF) << 8ull) | diff --git a/exosphere/src/configitem.h b/exosphere/src/configitem.h index b9600c833..4cadc3d71 100644 --- a/exosphere/src/configitem.h +++ b/exosphere/src/configitem.h @@ -13,7 +13,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + #ifndef EXOSPHERE_CFG_ITEM_H #define EXOSPHERE_CFG_ITEM_H @@ -38,7 +38,7 @@ typedef enum { CONFIGITEM_NEWHARDWARETYPE_5X = 15, CONFIGITEM_NEWKEYGENERATION_5X = 16, CONFIGITEM_PACKAGE2HASH_5X = 17, - + /* These are unofficial, for usage by Exosphere. */ CONFIGITEM_EXOSPHERE_VERSION = 65000, CONFIGITEM_NEEDS_REBOOT = 65001, @@ -61,6 +61,7 @@ bool configitem_is_debugmode_priv(void); void configitem_set_debugmode_override(bool user, bool priv); void configitem_disable_usermode_exception_handlers(void); +void configitem_enable_usermode_pmu_access(void); void configitem_set_hiz_mode_enabled(bool enabled); uint64_t configitem_get_hardware_type(void); diff --git a/exosphere/src/exocfg.c b/exosphere/src/exocfg.c index 974766178..00827c69f 100644 --- a/exosphere/src/exocfg.c +++ b/exosphere/src/exocfg.c @@ -84,6 +84,14 @@ unsigned int exosphere_should_disable_usermode_exception_handlers(void) { return EXOSPHERE_CHECK_FLAG(EXOSPHERE_FLAG_DISABLE_USERMODE_EXCEPTION_HANDLERS); } +unsigned int exosphere_should_enable_usermode_pmu_access(void) { + if (!g_has_loaded_config) { + generic_panic(); + } + + return EXOSPHERE_CHECK_FLAG(EXOSPHERE_FLAG_ENABLE_USERMODE_PMU_ACCESS); +} + const exo_emummc_config_t *exosphere_get_emummc_config(void) { if (!g_has_loaded_config) { generic_panic(); diff --git a/exosphere/src/exocfg.h b/exosphere/src/exocfg.h index 16f37ec19..902ab02e0 100644 --- a/exosphere/src/exocfg.h +++ b/exosphere/src/exocfg.h @@ -40,6 +40,7 @@ #define EXOSPHERE_FLAG_IS_DEBUGMODE_PRIV (1 << 1u) #define EXOSPHERE_FLAG_IS_DEBUGMODE_USER (1 << 2u) #define EXOSPHERE_FLAG_DISABLE_USERMODE_EXCEPTION_HANDLERS (1 << 3u) +#define EXOSPHERE_FLAG_ENABLE_USERMODE_PMU_ACCESS (1 << 4u) #define EXOSPHERE_FLAGS_DEFAULT (EXOSPHERE_FLAG_IS_DEBUGMODE_PRIV) typedef struct { @@ -58,6 +59,7 @@ unsigned int exosphere_should_perform_620_keygen(void); 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); +unsigned int exosphere_should_enable_usermode_pmu_access(void); const exo_emummc_config_t *exosphere_get_emummc_config(void); diff --git a/exosphere/src/package2.c b/exosphere/src/package2.c index 6935e8bca..4fe2b6623 100644 --- a/exosphere/src/package2.c +++ b/exosphere/src/package2.c @@ -512,6 +512,9 @@ void load_package2(coldboot_crt0_reloc_list_t *reloc_list) { if (exosphere_should_disable_usermode_exception_handlers() != 0) { configitem_disable_usermode_exception_handlers(); } + if (exosphere_should_enable_usermode_pmu_access()) { + configitem_enable_usermode_pmu_access(); + } /* Setup the Security Engine. */ setup_se(); diff --git a/fusee/fusee-secondary/src/exocfg.h b/fusee/fusee-secondary/src/exocfg.h index dc00de45e..685b15ce8 100644 --- a/fusee/fusee-secondary/src/exocfg.h +++ b/fusee/fusee-secondary/src/exocfg.h @@ -13,7 +13,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + #ifndef FUSEE_EXOSPHERE_CONFIG_H #define FUSEE_EXOSPHERE_CONFIG_H @@ -30,6 +30,7 @@ #define EXOSPHERE_FLAG_IS_DEBUGMODE_PRIV (1 << 1u) #define EXOSPHERE_FLAG_IS_DEBUGMODE_USER (1 << 2u) #define EXOSPHERE_FLAG_DISABLE_USERMODE_EXCEPTION_HANDLERS (1 << 3u) +#define EXOSPHERE_FLAG_ENABLE_USERMODE_PMU_ACCESS (1 << 4u) #define EXOSPHERE_FLAGS_DEFAULT (EXOSPHERE_FLAG_IS_DEBUGMODE_PRIV) typedef struct { @@ -48,5 +49,6 @@ _Static_assert(sizeof(exosphere_config_t) == 0x20 + sizeof(exo_emummc_config_t), #define EXOSPHERE_DEBUGMODE_PRIV_KEY "debugmode" #define EXOSPHERE_DEBUGMODE_USER_KEY "debugmode_user" #define EXOSPHERE_DISABLE_USERMODE_EXCEPTION_HANDLERS_KEY "disable_user_exception_handlers" +#define EXOSPHERE_ENABLE_USERMODE_PMU_ACCESS_KEY "enable_user_pmu_access" #endif \ No newline at end of file diff --git a/fusee/fusee-secondary/src/nxboot.c b/fusee/fusee-secondary/src/nxboot.c index ddc5c32ce..201f2ceeb 100644 --- a/fusee/fusee-secondary/src/nxboot.c +++ b/fusee/fusee-secondary/src/nxboot.c @@ -158,6 +158,13 @@ static int exosphere_ini_handler(void *user, const char *section, const char *na } else { exo_cfg->flags &= ~(EXOSPHERE_FLAG_DISABLE_USERMODE_EXCEPTION_HANDLERS); } + } else if (strcmp(name, EXOSPHERE_ENABLE_USERMODE_PMU_ACCESS_KEY) == 0) { + sscanf(value, "%d", &tmp); + if (tmp) { + exo_cfg->flags |= EXOSPHERE_FLAG_ENABLE_USERMODE_PMU_ACCESS; + } else { + exo_cfg->flags &= ~(EXOSPHERE_FLAG_ENABLE_USERMODE_PMU_ACCESS); + } } else { return 0; }