From f77cae48d085cd67baf848eee1f036e2ecfe1b72 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Mon, 19 Feb 2018 00:41:19 -0800 Subject: [PATCH] Skeleton for smcGetConfig and smcSetConfig --- exosphere/configitem.c | 67 ++++++++++++++++++++++++++++++++++++++++++ exosphere/configitem.h | 26 ++++++++++++++++ exosphere/smc_api.c | 20 +++++++++++++ exosphere/utils.h | 2 +- 4 files changed, 114 insertions(+), 1 deletion(-) create mode 100644 exosphere/configitem.c create mode 100644 exosphere/configitem.h diff --git a/exosphere/configitem.c b/exosphere/configitem.c new file mode 100644 index 000000000..9d02e79ab --- /dev/null +++ b/exosphere/configitem.c @@ -0,0 +1,67 @@ +#include + +#include "utils.h" +#include "configitem.h" + +int g_battery_profile = 0; + +uint32_t configitem_set(enum ConfigItem item, uint64_t value) { + if (item != CONFIGITEM_BATTERYPROFILE) { + return 2; + } + + g_battery_profile = ((int)(value != 0)) & 1; +} + +uint32_t configitem_get(enum ConfigItem item, uint64_t *p_outvalue) { + uint32_t result = 0; + switch (item) { + case CONFIGITEM_DISABLEPROGRAMVERIFICATION: + /* TODO: This is loaded from BootConfig on dev units, always zero on retail. How should we support? */ + *p_outvalue = 0; + break; + case CONFIGITEM_MEMORYCONFIGURATION: + /* TODO: Fuse driver */ + break; + case CONFIGITEM_SECURITYENGINEIRQ: + /* SE is interrupt #44. */ + *p_outvalue = 0x2C; + break; + case CONFIGITEM_UNK04: + /* Always returns 2 on hardware. */ + *p_outvalue = 2; + break; + case CONFIGITEM_HARDWARETYPE: + /* TODO: Fuse driver */ + break; + case CONFIGITEM_ISRETAIL: + /* TODO: Fuse driver */ + break; + case CONFIGITEM_ISRECOVERYBOOT: + /* TODO: This is just a constant, hardcoded into TZ on retail. How should we support? */ + *p_outvalue = 0; + break; + case CONFIGITEM_DEVICEID: + /* TODO: Fuse driver */ + break; + case CONFIGITEM_BOOTREASON: + /* TODO: This requires reading values passed to crt0 via NX_Bootloader. TBD pending crt0 implementation. */ + break; + case CONFIGITEM_MEMORYARRANGE: + /* TODO: More BootConfig stuff. */ + break; + case CONFIGITEM_ISDEBUGMODE: + /* TODO: More BootConfig stuff. */ + break; + case CONFIGITEM_KERNELMEMORYCONFIGURATION: + /* TODO: More BootConfig stuff. */ + break; + case CONFIGITEM_BATTERYPROFILE: + *p_outvalue = g_battery_profile; + break; + default: + result = 2; + break; + } + return result; +} diff --git a/exosphere/configitem.h b/exosphere/configitem.h new file mode 100644 index 000000000..e1cd0d3aa --- /dev/null +++ b/exosphere/configitem.h @@ -0,0 +1,26 @@ +#ifndef EXOSPHERE_CFG_ITEM_H +#define EXOSPHERE_CFG_ITEM_H + +#include + + +enum ConfigItem { + CONFIGITEM_DISABLEPROGRAMVERIFICATION = 1, + CONFIGITEM_MEMORYCONFIGURATION = 2, + CONFIGITEM_SECURITYENGINEIRQ = 3, + CONFIGITEM_UNK04 = 4, + CONFIGITEM_HARDWARETYPE = 5, + CONFIGITEM_ISRETAIL = 6, + CONFIGITEM_ISRECOVERYBOOT = 7, + CONFIGITEM_DEVICEID = 8, + CONFIGITEM_BOOTREASON = 9, + CONFIGITEM_MEMORYARRANGE = 10, + CONFIGITEM_ISDEBUGMODE = 11, + CONFIGITEM_KERNELMEMORYCONFIGURATION = 12, + CONFIGITEM_BATTERYPROFILE = 13 +}; + +uint32_t configitem_set(enum ConfigItem item, uint64_t value); +uint32_t configitem_get(enum ConfigItem item, uint64_t *p_outvalue); + +#endif \ No newline at end of file diff --git a/exosphere/smc_api.c b/exosphere/smc_api.c index 573cc3d64..212ccb09a 100644 --- a/exosphere/smc_api.c +++ b/exosphere/smc_api.c @@ -1,6 +1,7 @@ #include #include "utils.h" +#include "configitem.h" #include "cpu_context.h" #include "smc_api.h" #include "smc_user.h" @@ -129,6 +130,12 @@ void call_smc_handler(uint32_t handler_id, smc_args_t *args) { panic(); } + /* Validate core is appropriate for handler. */ + if (handler_id == SMC_HANDLER_USER && get_core_id() != 3) { + /* USER SMCs must be called via svcCallSecureMonitor on core 3 (where spl runs) */ + panic(); + } + /* Validate sub-handler index */ if ((smc_id = (unsigned char)args->X[0]) >= g_smc_tables[handler_id].num_handlers) { panic(); @@ -185,6 +192,19 @@ uint32_t smc_wrapper_async(smc_args_t *args, uint32_t (*handler)(smc_args_t *), return result; } +uint32_t smc_set_config(smc_args_t *args) { + /* Actual value presumed in X3 on hardware. */ + return configitem_set((enum ConfigItem)args->X[1], args->X[3]); +} + +uint32_t smc_get_config(smc_args_t *args) { + uint64_t out_item = 0; + uint32_t result; + result = configitem_get((enum ConfigItem)args->X[1], &out_item); + args->X[1] = out_item; + return result; +} + uint32_t smc_check_status(smc_args_t *args) { if (g_smc_callback_key == 0) { return 4; diff --git a/exosphere/utils.h b/exosphere/utils.h index 13f3e4d62..2b5784cff 100644 --- a/exosphere/utils.h +++ b/exosphere/utils.h @@ -17,7 +17,7 @@ static inline uint32_t read32be(const unsigned char *dword, size_t offset) { static inline unsigned int get_core_id(void) { unsigned int core_id; __asm__ __volatile__ ("mrs %0, MPIDR_EL1" : "=r"(core_id)); - return core_id; + return core_id & 3; } #endif