2019-06-16 05:37:41 +01:00
|
|
|
/**
|
|
|
|
* @file smc.c
|
|
|
|
* @copyright libnx Authors
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <stddef.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include "smc.h"
|
2020-06-09 02:11:16 +01:00
|
|
|
#include "../utils/fatal.h"
|
2019-06-16 05:37:41 +01:00
|
|
|
|
|
|
|
void smcRebootToRcm(void)
|
|
|
|
{
|
|
|
|
SecmonArgs args;
|
|
|
|
args.X[0] = 0xC3000401; /* smcSetConfig */
|
|
|
|
args.X[1] = SplConfigItem_NeedsReboot; /* Exosphere reboot */
|
|
|
|
args.X[3] = 1; /* Perform reboot to RCM. */
|
|
|
|
svcCallSecureMonitor(&args);
|
|
|
|
}
|
|
|
|
|
|
|
|
void smcRebootToIramPayload(void)
|
|
|
|
{
|
|
|
|
SecmonArgs args;
|
|
|
|
args.X[0] = 0xC3000401; /* smcSetConfig */
|
|
|
|
args.X[1] = SplConfigItem_NeedsReboot; /* Exosphere reboot */
|
|
|
|
args.X[3] = 2; /* Perform reboot to payload at 0x40010000 in IRAM. */
|
|
|
|
svcCallSecureMonitor(&args);
|
|
|
|
}
|
|
|
|
|
|
|
|
void smcPerformShutdown(void)
|
|
|
|
{
|
|
|
|
SecmonArgs args;
|
|
|
|
args.X[0] = 0xC3000401; /* smcSetConfig */
|
|
|
|
args.X[1] = SplConfigItem_NeedsShutdown; /* Exosphere shutdown */
|
|
|
|
args.X[3] = 1; /* Perform shutdown. */
|
|
|
|
svcCallSecureMonitor(&args);
|
|
|
|
}
|
|
|
|
|
|
|
|
Result smcGetConfig(SplConfigItem config_item, u64 *out_config)
|
|
|
|
{
|
|
|
|
SecmonArgs args;
|
|
|
|
args.X[0] = 0xC3000002; /* smcGetConfig */
|
|
|
|
args.X[1] = (u64)config_item; /* config item */
|
|
|
|
Result rc = svcCallSecureMonitor(&args);
|
|
|
|
if (rc == 0)
|
|
|
|
{
|
|
|
|
if (args.X[0] == 0)
|
|
|
|
{
|
|
|
|
if (out_config)
|
|
|
|
{
|
|
|
|
*out_config = args.X[1];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* SPL result n = SMC result n */
|
|
|
|
rc = (26u | ((u32)args.X[0] << 9u));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2020-11-16 06:45:31 +00:00
|
|
|
SplHardwareType splGetHardwareType(void)
|
|
|
|
{
|
|
|
|
u64 value;
|
|
|
|
Result rc = smcGetConfig(SplConfigItem_HardwareType, &value);
|
|
|
|
if (rc != 0)
|
|
|
|
{
|
|
|
|
fatal_abort(Fatal_BadResult);
|
|
|
|
}
|
|
|
|
return (SplHardwareType)value;
|
|
|
|
}
|
|
|
|
|
|
|
|
SplSocType splGetSocType(void)
|
|
|
|
{
|
2020-11-25 07:20:20 +00:00
|
|
|
static SplSocType soc_type;
|
|
|
|
static bool soc_type_set = false;
|
|
|
|
|
|
|
|
if (soc_type_set)
|
|
|
|
return soc_type;
|
|
|
|
|
2020-11-16 06:45:31 +00:00
|
|
|
switch (splGetHardwareType())
|
|
|
|
{
|
|
|
|
case SplHardwareType_Icosa:
|
|
|
|
case SplHardwareType_Copper:
|
2020-11-25 07:20:20 +00:00
|
|
|
soc_type = SplSocType_Erista;
|
|
|
|
break;
|
2020-11-16 06:45:31 +00:00
|
|
|
case SplHardwareType_Hoag:
|
|
|
|
case SplHardwareType_Iowa:
|
|
|
|
case SplHardwareType_Calcio:
|
|
|
|
case SplHardwareType_Five:
|
2020-11-25 07:20:20 +00:00
|
|
|
soc_type = SplSocType_Mariko;
|
|
|
|
break;
|
2020-11-16 06:45:31 +00:00
|
|
|
default:
|
|
|
|
fatal_abort(Fatal_InvalidEnum);
|
|
|
|
}
|
2020-11-25 07:20:20 +00:00
|
|
|
|
|
|
|
soc_type_set = true;
|
|
|
|
|
|
|
|
return soc_type;
|
2020-11-16 06:45:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-06-16 05:37:41 +01:00
|
|
|
Result smcCopyToIram(uintptr_t iram_addr, const void *src_addr, u32 size)
|
|
|
|
{
|
|
|
|
SecmonArgs args;
|
|
|
|
args.X[0] = 0xF0000201; /* smcAmsIramCopy */
|
|
|
|
args.X[1] = (u64)src_addr; /* DRAM address */
|
|
|
|
args.X[2] = (u64)iram_addr; /* IRAM address */
|
|
|
|
args.X[3] = size; /* Amount to copy */
|
|
|
|
args.X[4] = 1; /* 1 = Write */
|
|
|
|
Result rc = svcCallSecureMonitor(&args);
|
|
|
|
if (rc == 0)
|
|
|
|
{
|
|
|
|
if (args.X[0] != 0)
|
|
|
|
{
|
|
|
|
/* SPL result n = SMC result n */
|
|
|
|
rc = (26u | ((u32)args.X[0] << 9u));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
Result smcCopyFromIram(void *dst_addr, uintptr_t iram_addr, u32 size)
|
|
|
|
{
|
|
|
|
SecmonArgs args;
|
|
|
|
args.X[0] = 0xF0000201; /* smcAmsIramCopy */
|
|
|
|
args.X[1] = (u64)dst_addr; /* DRAM address */
|
|
|
|
args.X[2] = (u64)iram_addr; /* IRAM address */
|
|
|
|
args.X[3] = size; /* Amount to copy */
|
|
|
|
args.X[4] = 0; /* 0 = Read */
|
|
|
|
Result rc = svcCallSecureMonitor(&args);
|
|
|
|
if (rc == 0)
|
|
|
|
{
|
|
|
|
if (args.X[0] != 0)
|
|
|
|
{
|
|
|
|
/* SPL result n = SMC result n */
|
|
|
|
rc = (26u | ((u32)args.X[0] << 9u));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
Result smcReadWriteRegister(u32 phys_addr, u32 value, u32 mask)
|
|
|
|
{
|
|
|
|
SecmonArgs args;
|
|
|
|
args.X[0] = 0xF0000002; /* smcAmsReadWriteRegister */
|
|
|
|
args.X[1] = phys_addr; /* MMIO address */
|
|
|
|
args.X[2] = mask; /* mask */
|
|
|
|
args.X[3] = value; /* value */
|
|
|
|
Result rc = svcCallSecureMonitor(&args);
|
|
|
|
if (rc == 0)
|
|
|
|
{
|
|
|
|
if (args.X[0] != 0)
|
|
|
|
{
|
|
|
|
/* SPL result n = SMC result n */
|
|
|
|
rc = (26u | ((u32)args.X[0] << 9u));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2020-06-09 02:11:16 +01:00
|
|
|
Result smcGetEmummcConfig(exo_emummc_mmc_t mmc_id, exo_emummc_config_t *out_cfg, void *out_paths)
|
2019-06-16 05:37:41 +01:00
|
|
|
{
|
|
|
|
SecmonArgs args;
|
2020-06-09 02:11:16 +01:00
|
|
|
args.X[0] = 0xF0000404; /* smcAmsGetEmunandConfig */
|
|
|
|
args.X[1] = mmc_id;
|
|
|
|
args.X[2] = (u64)out_paths; /* out path */
|
2019-06-16 05:37:41 +01:00
|
|
|
Result rc = svcCallSecureMonitor(&args);
|
|
|
|
if (rc == 0)
|
|
|
|
{
|
|
|
|
if (args.X[0] != 0)
|
|
|
|
{
|
|
|
|
/* SPL result n = SMC result n */
|
|
|
|
rc = (26u | ((u32)args.X[0] << 9u));
|
|
|
|
}
|
2020-06-09 02:11:16 +01:00
|
|
|
if (rc == 0)
|
|
|
|
{
|
|
|
|
memcpy(out_cfg, &args.X[1], sizeof(*out_cfg));
|
|
|
|
}
|
2019-06-16 05:37:41 +01:00
|
|
|
}
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2020-06-09 02:11:16 +01:00
|
|
|
Result smcGenerateRandomBytes(void *dst, u32 size)
|
2019-06-16 05:37:41 +01:00
|
|
|
{
|
|
|
|
SecmonArgs args;
|
2020-06-09 02:11:16 +01:00
|
|
|
args.X[0] = 0xC3000006; /* smcGenerateRandomBytes */
|
|
|
|
args.X[1] = size;
|
2019-06-16 05:37:41 +01:00
|
|
|
Result rc = svcCallSecureMonitor(&args);
|
|
|
|
if (rc == 0)
|
|
|
|
{
|
|
|
|
if (args.X[0] != 0)
|
|
|
|
{
|
|
|
|
/* SPL result n = SMC result n */
|
|
|
|
rc = (26u | ((u32)args.X[0] << 9u));
|
|
|
|
}
|
|
|
|
if (rc == 0)
|
|
|
|
{
|
2020-06-09 02:11:16 +01:00
|
|
|
memcpy(dst, &args.X[1], size);
|
2019-06-16 05:37:41 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return rc;
|
2020-06-09 02:11:16 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
u64 smcGenerateRandomU64(void)
|
|
|
|
{
|
|
|
|
u64 random;
|
2019-06-16 05:37:41 +01:00
|
|
|
|
2020-06-09 02:11:16 +01:00
|
|
|
Result rc = smcGenerateRandomBytes(&random, sizeof(random));
|
|
|
|
if (rc != 0)
|
|
|
|
{
|
|
|
|
fatal_abort(Fatal_BadResult);
|
|
|
|
}
|
|
|
|
|
|
|
|
return random;
|
|
|
|
}
|