2018-09-07 16:00:13 +01:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2018 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/>.
|
|
|
|
*/
|
|
|
|
|
2018-02-19 08:41:19 +00:00
|
|
|
#include <stdint.h>
|
2018-10-17 01:54:50 +01:00
|
|
|
#include <atmosphere/version.h>
|
2018-02-19 08:41:19 +00:00
|
|
|
|
2018-02-24 15:25:38 +00:00
|
|
|
#include "bootconfig.h"
|
2018-02-19 08:41:19 +00:00
|
|
|
#include "configitem.h"
|
2018-02-24 20:46:57 +00:00
|
|
|
#include "interrupt.h"
|
|
|
|
#include "package2.h"
|
|
|
|
#include "se.h"
|
2018-02-25 19:00:50 +00:00
|
|
|
#include "fuse.h"
|
2018-02-24 20:46:57 +00:00
|
|
|
#include "utils.h"
|
2018-03-09 10:54:36 +00:00
|
|
|
#include "masterkey.h"
|
2018-03-25 22:05:08 +01:00
|
|
|
#include "exocfg.h"
|
2018-02-19 08:41:19 +00:00
|
|
|
|
2018-02-26 10:00:02 +00:00
|
|
|
static bool g_battery_profile = false;
|
2018-11-30 11:10:27 +00:00
|
|
|
static bool g_debugmode_override_user = false, g_debugmode_override_priv = false;
|
2018-02-19 08:41:19 +00:00
|
|
|
|
2018-11-30 11:10:27 +00:00
|
|
|
uint32_t configitem_set(bool privileged, ConfigItem item, uint64_t value) {
|
2018-11-30 12:57:17 +00:00
|
|
|
switch (item) {
|
|
|
|
case CONFIGITEM_BATTERYPROFILE:
|
|
|
|
g_battery_profile = (value != 0);
|
|
|
|
break;
|
2019-01-20 10:50:13 +00:00
|
|
|
case CONFIGITEM_NEEDS_REBOOT:
|
2018-11-30 13:33:35 +00:00
|
|
|
/* Force a reboot to RCM, if requested. */
|
2019-01-20 10:50:13 +00:00
|
|
|
switch (value) {
|
|
|
|
case REBOOT_KIND_NO_REBOOT:
|
|
|
|
return 0;
|
|
|
|
case REBOOT_KIND_TO_RCM:
|
|
|
|
/* Set reboot kind = rcm. */
|
|
|
|
MAKE_REG32(MMIO_GET_DEVICE_ADDRESS(MMIO_DEVID_RTC_PMC) + 0x450ull) = 0x2;
|
|
|
|
break;
|
|
|
|
case REBOOT_KIND_TO_WB_PAYLOAD:
|
|
|
|
/* Set reboot kind = warmboot. */
|
|
|
|
MAKE_REG32(MMIO_GET_DEVICE_ADDRESS(MMIO_DEVID_RTC_PMC) + 0x450ull) = 0x1;
|
|
|
|
/* Patch bootrom to jump to payload. */
|
|
|
|
MAKE_REG32(MMIO_GET_DEVICE_ADDRESS(MMIO_DEVID_RTC_PMC) + 0x118) = 0x40010000; /* Return to start of payload. */
|
|
|
|
MAKE_REG32(MMIO_GET_DEVICE_ADDRESS(MMIO_DEVID_RTC_PMC) + 0x11C) = 0x4000FFA4; /* Overwrite bootrom return address on stack. */
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return 2;
|
2018-11-30 12:57:17 +00:00
|
|
|
}
|
2019-01-20 10:50:13 +00:00
|
|
|
MAKE_REG32(MMIO_GET_DEVICE_ADDRESS(MMIO_DEVID_RTC_PMC) + 0x400ull) = 0x10;
|
2018-11-30 12:57:17 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return 2;
|
2018-02-19 08:41:19 +00:00
|
|
|
}
|
|
|
|
|
2018-02-26 10:00:02 +00:00
|
|
|
return 0;
|
2018-02-19 08:41:19 +00:00
|
|
|
}
|
|
|
|
|
2018-02-23 03:58:39 +00:00
|
|
|
bool configitem_is_recovery_boot(void) {
|
2018-02-20 09:02:01 +00:00
|
|
|
uint64_t is_recovery_boot;
|
2018-11-30 11:10:27 +00:00
|
|
|
if (configitem_get(true, CONFIGITEM_ISRECOVERYBOOT, &is_recovery_boot) != 0) {
|
2018-02-24 14:20:45 +00:00
|
|
|
generic_panic();
|
2018-02-20 09:02:01 +00:00
|
|
|
}
|
2018-02-23 03:58:39 +00:00
|
|
|
|
|
|
|
return is_recovery_boot != 0;
|
2018-02-20 09:02:01 +00:00
|
|
|
}
|
|
|
|
|
2018-02-25 09:21:52 +00:00
|
|
|
bool configitem_is_retail(void) {
|
|
|
|
uint64_t is_retail;
|
2018-11-30 11:10:27 +00:00
|
|
|
if (configitem_get(true, CONFIGITEM_ISRETAIL, &is_retail) != 0) {
|
2018-02-25 09:21:52 +00:00
|
|
|
generic_panic();
|
|
|
|
}
|
|
|
|
|
|
|
|
return is_retail != 0;
|
|
|
|
}
|
|
|
|
|
2018-02-26 10:00:02 +00:00
|
|
|
bool configitem_should_profile_battery(void) {
|
|
|
|
return g_battery_profile;
|
|
|
|
}
|
|
|
|
|
2018-12-04 23:59:30 +00:00
|
|
|
bool configitem_is_debugmode_priv(void) {
|
|
|
|
uint64_t debugmode = 0;
|
|
|
|
if (configitem_get(true, CONFIGITEM_ISDEBUGMODE, &debugmode) != 0) {
|
|
|
|
generic_panic();
|
|
|
|
}
|
|
|
|
|
|
|
|
return debugmode != 0;
|
|
|
|
}
|
|
|
|
|
2018-03-02 20:16:30 +00:00
|
|
|
uint64_t configitem_get_hardware_type(void) {
|
|
|
|
uint64_t hardware_type;
|
2018-11-30 11:10:27 +00:00
|
|
|
if (configitem_get(true, CONFIGITEM_HARDWARETYPE, &hardware_type) != 0) {
|
2018-03-02 20:16:30 +00:00
|
|
|
generic_panic();
|
|
|
|
}
|
|
|
|
return hardware_type;
|
|
|
|
}
|
|
|
|
|
2018-11-30 11:10:27 +00:00
|
|
|
void configitem_set_debugmode_override(bool user, bool priv) {
|
|
|
|
g_debugmode_override_user = user;
|
|
|
|
g_debugmode_override_priv = priv;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t configitem_get(bool privileged, ConfigItem item, uint64_t *p_outvalue) {
|
2018-02-19 08:41:19 +00:00
|
|
|
uint32_t result = 0;
|
|
|
|
switch (item) {
|
|
|
|
case CONFIGITEM_DISABLEPROGRAMVERIFICATION:
|
2018-02-24 15:25:38 +00:00
|
|
|
*p_outvalue = (int)(bootconfig_disable_program_verification());
|
2018-02-19 08:41:19 +00:00
|
|
|
break;
|
2018-02-25 09:21:52 +00:00
|
|
|
case CONFIGITEM_DRAMID:
|
|
|
|
*p_outvalue = fuse_get_dram_id();
|
2018-02-19 08:41:19 +00:00
|
|
|
break;
|
|
|
|
case CONFIGITEM_SECURITYENGINEIRQ:
|
2018-02-24 15:25:38 +00:00
|
|
|
/* SE is interrupt #0x2C. */
|
|
|
|
*p_outvalue = INTERRUPT_ID_USER_SECURITY_ENGINE;
|
2018-02-19 08:41:19 +00:00
|
|
|
break;
|
2018-02-24 20:46:57 +00:00
|
|
|
case CONFIGITEM_VERSION:
|
2018-02-24 15:25:38 +00:00
|
|
|
/* Always returns maxver - 1 on hardware. */
|
2018-04-23 19:07:49 +01:00
|
|
|
*p_outvalue = PACKAGE2_MAXVER_400_410 - 1;
|
2018-02-19 08:41:19 +00:00
|
|
|
break;
|
|
|
|
case CONFIGITEM_HARDWARETYPE:
|
2018-02-25 09:21:52 +00:00
|
|
|
*p_outvalue = fuse_get_hardware_type();
|
2018-02-19 08:41:19 +00:00
|
|
|
break;
|
|
|
|
case CONFIGITEM_ISRETAIL:
|
2018-02-25 09:21:52 +00:00
|
|
|
*p_outvalue = fuse_get_retail_type();
|
2018-02-19 08:41:19 +00:00
|
|
|
break;
|
|
|
|
case CONFIGITEM_ISRECOVERYBOOT:
|
2018-03-08 09:48:57 +00:00
|
|
|
*p_outvalue = (int)(bootconfig_is_recovery_boot());
|
2018-02-19 08:41:19 +00:00
|
|
|
break;
|
|
|
|
case CONFIGITEM_DEVICEID:
|
2018-02-25 09:21:52 +00:00
|
|
|
*p_outvalue = fuse_get_device_id();
|
2018-02-19 08:41:19 +00:00
|
|
|
break;
|
|
|
|
case CONFIGITEM_BOOTREASON:
|
2018-03-09 10:54:36 +00:00
|
|
|
/* For some reason, Nintendo removed it on 4.0 */
|
2018-12-17 20:39:35 +00:00
|
|
|
if (exosphere_get_target_firmware() < ATMOSPHERE_TARGET_FIRMWARE_400) {
|
2018-03-09 10:54:36 +00:00
|
|
|
*p_outvalue = bootconfig_get_boot_reason();
|
|
|
|
} else {
|
|
|
|
result = 2;
|
|
|
|
}
|
2018-02-19 08:41:19 +00:00
|
|
|
break;
|
|
|
|
case CONFIGITEM_MEMORYARRANGE:
|
2018-02-25 09:21:52 +00:00
|
|
|
*p_outvalue = bootconfig_get_memory_arrangement();
|
2018-02-19 08:41:19 +00:00
|
|
|
break;
|
|
|
|
case CONFIGITEM_ISDEBUGMODE:
|
2018-11-30 11:10:27 +00:00
|
|
|
if ((privileged && g_debugmode_override_priv) || (!privileged && g_debugmode_override_user)) {
|
|
|
|
*p_outvalue = 1;
|
|
|
|
} else {
|
|
|
|
*p_outvalue = (int)(bootconfig_is_debug_mode());
|
|
|
|
}
|
2018-02-19 08:41:19 +00:00
|
|
|
break;
|
|
|
|
case CONFIGITEM_KERNELMEMORYCONFIGURATION:
|
2018-02-25 09:21:52 +00:00
|
|
|
*p_outvalue = bootconfig_get_kernel_memory_configuration();
|
2018-02-19 08:41:19 +00:00
|
|
|
break;
|
|
|
|
case CONFIGITEM_BATTERYPROFILE:
|
2018-02-26 10:00:02 +00:00
|
|
|
*p_outvalue = (int)g_battery_profile;
|
2018-02-19 08:41:19 +00:00
|
|
|
break;
|
2018-09-20 21:47:20 +01:00
|
|
|
case CONFIGITEM_ISQUESTUNIT:
|
|
|
|
/* Added on 3.0, used to determine whether console is a kiosk unit. */
|
2018-12-17 20:39:35 +00:00
|
|
|
if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_300) {
|
2018-03-09 10:54:36 +00:00
|
|
|
*p_outvalue = (fuse_get_reserved_odm(4) >> 10) & 1;
|
|
|
|
} else {
|
|
|
|
result = 2;
|
|
|
|
}
|
|
|
|
break;
|
2018-03-25 22:05:08 +01:00
|
|
|
case CONFIGITEM_NEWHARDWARETYPE_5X:
|
|
|
|
/* Added in 5.x, currently hardcoded to 0. */
|
2018-12-17 20:39:35 +00:00
|
|
|
if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_500) {
|
2018-03-25 22:05:08 +01:00
|
|
|
*p_outvalue = 0;
|
|
|
|
} else {
|
|
|
|
result = 2;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case CONFIGITEM_NEWKEYGENERATION_5X:
|
|
|
|
/* Added in 5.x. */
|
2018-12-17 20:39:35 +00:00
|
|
|
if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_500) {
|
2018-03-25 22:05:08 +01:00
|
|
|
*p_outvalue = fuse_get_5x_key_generation();
|
|
|
|
} else {
|
|
|
|
result = 2;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case CONFIGITEM_PACKAGE2HASH_5X:
|
|
|
|
/* Added in 5.x. */
|
2018-12-17 20:39:35 +00:00
|
|
|
if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_500 && bootconfig_is_recovery_boot()) {
|
2018-03-25 22:05:08 +01:00
|
|
|
bootconfig_get_package2_hash_for_recovery(p_outvalue);
|
|
|
|
} else {
|
|
|
|
result = 2;
|
|
|
|
}
|
|
|
|
break;
|
2018-05-09 13:29:56 +01:00
|
|
|
case CONFIGITEM_EXOSPHERE_VERSION:
|
|
|
|
/* UNOFFICIAL: Gets information about the current exosphere version. */
|
2018-10-17 01:54:50 +01:00
|
|
|
*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) |
|
|
|
|
((uint64_t)(mkey_get_revision() & 0xFF) << 0ull);
|
2018-05-09 13:29:56 +01:00
|
|
|
break;
|
2019-01-20 10:50:13 +00:00
|
|
|
case CONFIGITEM_NEEDS_REBOOT:
|
|
|
|
/* UNOFFICIAL: The fact that we are executing means we aren't in the process of rebooting. */
|
2018-11-30 12:57:17 +00:00
|
|
|
*p_outvalue = 0;
|
|
|
|
break;
|
2018-02-19 08:41:19 +00:00
|
|
|
default:
|
|
|
|
result = 2;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|