mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2024-12-22 20:31:14 +00:00
kernel_ldr: clean up KSystemControl init API
This commit is contained in:
parent
d10621e832
commit
bf5bbfbcef
5 changed files with 102 additions and 62 deletions
|
@ -20,15 +20,17 @@ namespace ams::kern {
|
||||||
|
|
||||||
class KSystemControl {
|
class KSystemControl {
|
||||||
public:
|
public:
|
||||||
|
class Init {
|
||||||
|
public:
|
||||||
/* Initialization. */
|
/* Initialization. */
|
||||||
static KPhysicalAddress GetKernelPhysicalBaseAddress(uintptr_t base_address);
|
static KPhysicalAddress GetKernelPhysicalBaseAddress(uintptr_t base_address);
|
||||||
static bool ShouldIncreaseResourceRegionSize();
|
static bool ShouldIncreaseThreadResourceLimit();
|
||||||
|
|
||||||
/* Randomness. */
|
/* Randomness. */
|
||||||
static void GenerateRandomBytes(void *dst, size_t size);
|
static void GenerateRandomBytes(void *dst, size_t size);
|
||||||
static u64 GenerateRandomRange(u64 min, u64 max);
|
static u64 GenerateRandomRange(u64 min, u64 max);
|
||||||
|
};
|
||||||
|
public:
|
||||||
/* Panic. */
|
/* Panic. */
|
||||||
static NORETURN void StopSystem();
|
static NORETURN void StopSystem();
|
||||||
};
|
};
|
||||||
|
|
|
@ -25,33 +25,32 @@ namespace ams::kern {
|
||||||
constexpr size_t SixGigabytes = 0x180000000ul;
|
constexpr size_t SixGigabytes = 0x180000000ul;
|
||||||
constexpr size_t EightGigabytes = 0x200000000ul;
|
constexpr size_t EightGigabytes = 0x200000000ul;
|
||||||
|
|
||||||
size_t GetRealMemorySize() {
|
ALWAYS_INLINE size_t GetRealMemorySizeForInit() {
|
||||||
/* TODO: Move this into a header for the MC in general. */
|
/* TODO: Move this into a header for the MC in general. */
|
||||||
constexpr u32 MemoryControllerConfigurationRegister = 0x70019050;
|
constexpr u32 MemoryControllerConfigurationRegister = 0x70019050;
|
||||||
u32 config_value;
|
u32 config_value;
|
||||||
MESOSPHERE_ABORT_UNLESS(smc::ReadWriteRegister(&config_value, MemoryControllerConfigurationRegister, 0, 0));
|
MESOSPHERE_ABORT_UNLESS(smc::init::ReadWriteRegister(&config_value, MemoryControllerConfigurationRegister, 0, 0));
|
||||||
return static_cast<size_t>(config_value & 0x3FFF) << 20;
|
return static_cast<size_t>(config_value & 0x3FFF) << 20;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline u64 GetKernelConfiguration() {
|
ALWAYS_INLINE u64 GetKernelConfigurationForInit() {
|
||||||
u64 value = 0;
|
u64 value = 0;
|
||||||
smc::GetConfig(&value, 1, smc::ConfigItem::KernelConfiguration);
|
smc::init::GetConfig(&value, 1, smc::ConfigItem::KernelConfiguration);
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline u64 GenerateRandomU64() {
|
ALWAYS_INLINE u64 GenerateRandomU64ForInit() {
|
||||||
u64 value;
|
u64 value;
|
||||||
smc::GenerateRandomBytes(&value, sizeof(value));
|
smc::init::GenerateRandomBytes(&value, sizeof(value));
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline smc::MemoryMode GetMemoryMode() {
|
ALWAYS_INLINE smc::MemoryMode GetMemoryModeForInit() {
|
||||||
return static_cast<smc::MemoryMode>((GetKernelConfiguration() >> 10) & 0x3);
|
return static_cast<smc::MemoryMode>((GetKernelConfigurationForInit() >> 10) & 0x3);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t GetIntendedMemorySize() {
|
ALWAYS_INLINE size_t GetIntendedMemorySizeForInit() {
|
||||||
const smc::MemoryMode memory_mode = GetMemoryMode();
|
switch (GetMemoryModeForInit()) {
|
||||||
switch (memory_mode) {
|
|
||||||
case smc::MemoryMode_4GB:
|
case smc::MemoryMode_4GB:
|
||||||
default: /* All invalid modes should go to 4GB. */
|
default: /* All invalid modes should go to 4GB. */
|
||||||
return FourGigabytes;
|
return FourGigabytes;
|
||||||
|
@ -65,9 +64,9 @@ namespace ams::kern {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Initialization. */
|
/* Initialization. */
|
||||||
KPhysicalAddress KSystemControl::GetKernelPhysicalBaseAddress(uintptr_t base_address) {
|
KPhysicalAddress KSystemControl::Init::GetKernelPhysicalBaseAddress(uintptr_t base_address) {
|
||||||
const size_t real_dram_size = GetRealMemorySize();
|
const size_t real_dram_size = GetRealMemorySizeForInit();
|
||||||
const size_t intended_dram_size = GetIntendedMemorySize();
|
const size_t intended_dram_size = GetIntendedMemorySizeForInit();
|
||||||
if (intended_dram_size * 2 < real_dram_size) {
|
if (intended_dram_size * 2 < real_dram_size) {
|
||||||
return base_address;
|
return base_address;
|
||||||
} else {
|
} else {
|
||||||
|
@ -75,21 +74,21 @@ namespace ams::kern {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool KSystemControl::ShouldIncreaseResourceRegionSize() {
|
bool KSystemControl::Init::ShouldIncreaseThreadResourceLimit() {
|
||||||
return (GetKernelConfiguration() >> 3) & 1;
|
return (GetKernelConfigurationForInit() >> 3) & 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Randomness. */
|
/* Randomness for Initialization. */
|
||||||
void KSystemControl::GenerateRandomBytes(void *dst, size_t size) {
|
void KSystemControl::Init::GenerateRandomBytes(void *dst, size_t size) {
|
||||||
MESOSPHERE_ABORT_UNLESS(size <= 0x38);
|
MESOSPHERE_ABORT_UNLESS(size <= 0x38);
|
||||||
smc::GenerateRandomBytes(dst, size);
|
smc::init::GenerateRandomBytes(dst, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 KSystemControl::GenerateRandomRange(u64 min, u64 max) {
|
u64 KSystemControl::Init::GenerateRandomRange(u64 min, u64 max) {
|
||||||
const u64 range_size = ((max + 1) - min);
|
const u64 range_size = ((max + 1) - min);
|
||||||
const u64 effective_max = (std::numeric_limits<u64>::max() / range_size) * range_size;
|
const u64 effective_max = (std::numeric_limits<u64>::max() / range_size) * range_size;
|
||||||
while (true) {
|
while (true) {
|
||||||
if (const u64 rnd = GenerateRandomU64(); rnd < effective_max) {
|
if (const u64 rnd = GenerateRandomU64ForInit(); rnd < effective_max) {
|
||||||
return min + (rnd % range_size);
|
return min + (rnd % range_size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,11 +69,43 @@ namespace ams::kern::smc {
|
||||||
args.x[7] = x7;
|
args.x[7] = x7;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CallPrivilegedSecureMonitorFunctionForInit(SecureMonitorArguments &args) {
|
||||||
|
/* Load arguments into registers. */
|
||||||
|
register u64 x0 asm("x0") = args.x[0];
|
||||||
|
register u64 x1 asm("x1") = args.x[1];
|
||||||
|
register u64 x2 asm("x2") = args.x[2];
|
||||||
|
register u64 x3 asm("x3") = args.x[3];
|
||||||
|
register u64 x4 asm("x4") = args.x[4];
|
||||||
|
register u64 x5 asm("x5") = args.x[5];
|
||||||
|
register u64 x6 asm("x6") = args.x[6];
|
||||||
|
register u64 x7 asm("x7") = args.x[7];
|
||||||
|
|
||||||
|
/* Actually make the call. */
|
||||||
|
__asm__ __volatile__("smc #1"
|
||||||
|
: "+r"(x0), "+r"(x1), "+r"(x2), "+r"(x3), "+r"(x4), "+r"(x5), "+r"(x6), "+r"(x7)
|
||||||
|
:
|
||||||
|
: "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15", "x16", "x17", "x18", "cc", "memory"
|
||||||
|
);
|
||||||
|
|
||||||
|
/* Store arguments to output. */
|
||||||
|
args.x[0] = x0;
|
||||||
|
args.x[1] = x1;
|
||||||
|
args.x[2] = x2;
|
||||||
|
args.x[3] = x3;
|
||||||
|
args.x[4] = x4;
|
||||||
|
args.x[5] = x5;
|
||||||
|
args.x[6] = x6;
|
||||||
|
args.x[7] = x7;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* SMC functionality needed for init. */
|
||||||
|
namespace init {
|
||||||
|
|
||||||
void GetConfig(u64 *out, size_t num_qwords, ConfigItem config_item) {
|
void GetConfig(u64 *out, size_t num_qwords, ConfigItem config_item) {
|
||||||
SecureMonitorArguments args = { FunctionId_GetConfig, static_cast<u32>(config_item) };
|
SecureMonitorArguments args = { FunctionId_GetConfig, static_cast<u32>(config_item) };
|
||||||
CallPrivilegedSecureMonitorFunction(args);
|
CallPrivilegedSecureMonitorFunctionForInit(args);
|
||||||
MESOSPHERE_ABORT_UNLESS((static_cast<SmcResult>(args.x[0]) == SmcResult::Success));
|
MESOSPHERE_ABORT_UNLESS((static_cast<SmcResult>(args.x[0]) == SmcResult::Success));
|
||||||
for (size_t i = 0; i < num_qwords && i < 7; i++) {
|
for (size_t i = 0; i < num_qwords && i < 7; i++) {
|
||||||
out[i] = args.x[1 + i];
|
out[i] = args.x[1 + i];
|
||||||
|
@ -85,24 +117,26 @@ namespace ams::kern::smc {
|
||||||
/* TODO: Lock this to ensure only one core calls at once. */
|
/* TODO: Lock this to ensure only one core calls at once. */
|
||||||
SecureMonitorArguments args = { FunctionId_GenerateRandomBytes, size };
|
SecureMonitorArguments args = { FunctionId_GenerateRandomBytes, size };
|
||||||
MESOSPHERE_ABORT_UNLESS(size <= sizeof(args) - sizeof(args.x[0]));
|
MESOSPHERE_ABORT_UNLESS(size <= sizeof(args) - sizeof(args.x[0]));
|
||||||
CallPrivilegedSecureMonitorFunction(args);
|
CallPrivilegedSecureMonitorFunctionForInit(args);
|
||||||
MESOSPHERE_ABORT_UNLESS((static_cast<SmcResult>(args.x[0]) == SmcResult::Success));
|
MESOSPHERE_ABORT_UNLESS((static_cast<SmcResult>(args.x[0]) == SmcResult::Success));
|
||||||
|
|
||||||
/* Copy output. */
|
/* Copy output. */
|
||||||
std::memcpy(dst, &args.x[1], size);
|
std::memcpy(dst, &args.x[1], size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ReadWriteRegister(u32 *out, u64 address, u32 mask, u32 value) {
|
||||||
|
SecureMonitorArguments args = { FunctionId_ReadWriteRegister, address, mask, value };
|
||||||
|
CallPrivilegedSecureMonitorFunctionForInit(args);
|
||||||
|
*out = args.x[1];
|
||||||
|
return static_cast<SmcResult>(args.x[0]) == SmcResult::Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
void NORETURN Panic(u32 color) {
|
void NORETURN Panic(u32 color) {
|
||||||
SecureMonitorArguments args = { FunctionId_Panic, color };
|
SecureMonitorArguments args = { FunctionId_Panic, color };
|
||||||
CallPrivilegedSecureMonitorFunction(args);
|
CallPrivilegedSecureMonitorFunction(args);
|
||||||
while (true) { /* ... */ }
|
while (true) { /* ... */ }
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ReadWriteRegister(u32 *out, u64 address, u32 mask, u32 value) {
|
|
||||||
SecureMonitorArguments args = { FunctionId_ReadWriteRegister, address, mask, value };
|
|
||||||
CallPrivilegedSecureMonitorFunction(args);
|
|
||||||
*out = args.x[1];
|
|
||||||
return static_cast<SmcResult>(args.x[0]) == SmcResult::Success;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
|
@ -36,13 +36,13 @@ namespace ams::kern::smc {
|
||||||
IsRecoveryBoot = 7,
|
IsRecoveryBoot = 7,
|
||||||
DeviceId = 8,
|
DeviceId = 8,
|
||||||
BootReason = 9,
|
BootReason = 9,
|
||||||
MemoryArrange = 10,
|
MemoryMode = 10,
|
||||||
IsDebugMode = 11,
|
IsDebugMode = 11,
|
||||||
KernelConfiguration = 12,
|
KernelConfiguration = 12,
|
||||||
IsChargerHiZModeEnabled = 13,
|
IsChargerHiZModeEnabled = 13,
|
||||||
IsKiosk = 14,
|
IsQuest = 14,
|
||||||
NewHardwareType = 15,
|
RegulatorType = 15,
|
||||||
NewKeyGeneration = 16,
|
DeviceUniqueKeyGeneration = 16,
|
||||||
Package2Hash = 17,
|
Package2Hash = 17,
|
||||||
|
|
||||||
/* Extension config items for exosphere. */
|
/* Extension config items for exosphere. */
|
||||||
|
@ -64,9 +64,14 @@ namespace ams::kern::smc {
|
||||||
};
|
};
|
||||||
|
|
||||||
/* TODO: Rest of Secure Monitor API. */
|
/* TODO: Rest of Secure Monitor API. */
|
||||||
|
void NORETURN Panic(u32 color);
|
||||||
|
|
||||||
|
namespace init {
|
||||||
|
|
||||||
void GetConfig(u64 *out, size_t num_qwords, ConfigItem config_item);
|
void GetConfig(u64 *out, size_t num_qwords, ConfigItem config_item);
|
||||||
void GenerateRandomBytes(void *dst, size_t size);
|
void GenerateRandomBytes(void *dst, size_t size);
|
||||||
void NORETURN Panic(u32 color);
|
|
||||||
bool ReadWriteRegister(u32 *out, u64 address, u32 mask, u32 value);
|
bool ReadWriteRegister(u32 *out, u64 address, u32 mask, u32 value);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -66,7 +66,7 @@ namespace ams::kern::init::loader {
|
||||||
|
|
||||||
void RelocateKernelPhysically(uintptr_t &base_address, KernelLayout *&layout) {
|
void RelocateKernelPhysically(uintptr_t &base_address, KernelLayout *&layout) {
|
||||||
/* TODO: Proper secure monitor call. */
|
/* TODO: Proper secure monitor call. */
|
||||||
KPhysicalAddress correct_base = KSystemControl::GetKernelPhysicalBaseAddress(base_address);
|
KPhysicalAddress correct_base = KSystemControl::Init::GetKernelPhysicalBaseAddress(base_address);
|
||||||
if (correct_base != base_address) {
|
if (correct_base != base_address) {
|
||||||
const uintptr_t diff = GetInteger(correct_base) - base_address;
|
const uintptr_t diff = GetInteger(correct_base) - base_address;
|
||||||
const size_t size = layout->rw_end_offset;
|
const size_t size = layout->rw_end_offset;
|
||||||
|
@ -218,7 +218,7 @@ namespace ams::kern::init::loader {
|
||||||
|
|
||||||
/* Repeatedly generate a random virtual address until we get one that's unmapped in the destination page table. */
|
/* Repeatedly generate a random virtual address until we get one that's unmapped in the destination page table. */
|
||||||
while (true) {
|
while (true) {
|
||||||
const KVirtualAddress random_kaslr_slide = KSystemControl::GenerateRandomRange(KernelBaseRangeMin, KernelBaseRangeEnd);
|
const KVirtualAddress random_kaslr_slide = KSystemControl::Init::GenerateRandomRange(KernelBaseRangeMin, KernelBaseRangeEnd);
|
||||||
const KVirtualAddress kernel_region_start = util::AlignDown(GetInteger(random_kaslr_slide), KernelBaseAlignment);
|
const KVirtualAddress kernel_region_start = util::AlignDown(GetInteger(random_kaslr_slide), KernelBaseAlignment);
|
||||||
const KVirtualAddress kernel_region_end = util::AlignUp(GetInteger(kernel_region_start) + kernel_offset + kernel_size, KernelBaseAlignment);
|
const KVirtualAddress kernel_region_end = util::AlignUp(GetInteger(kernel_region_start) + kernel_offset + kernel_size, KernelBaseAlignment);
|
||||||
const size_t kernel_region_size = GetInteger(kernel_region_end) - GetInteger(kernel_region_start);
|
const size_t kernel_region_size = GetInteger(kernel_region_end) - GetInteger(kernel_region_start);
|
||||||
|
@ -275,7 +275,7 @@ namespace ams::kern::init::loader {
|
||||||
const uintptr_t init_array_end_offset = layout->init_array_end_offset;
|
const uintptr_t init_array_end_offset = layout->init_array_end_offset;
|
||||||
|
|
||||||
/* Decide if Kernel should have enlarged resource region. */
|
/* Decide if Kernel should have enlarged resource region. */
|
||||||
const bool use_extra_resources = KSystemControl::ShouldIncreaseResourceRegionSize();
|
const bool use_extra_resources = KSystemControl::Init::ShouldIncreaseThreadResourceLimit();
|
||||||
const size_t resource_region_size = KernelResourceRegionSize + (use_extra_resources ? ExtraKernelResourceSize : 0);
|
const size_t resource_region_size = KernelResourceRegionSize + (use_extra_resources ? ExtraKernelResourceSize : 0);
|
||||||
|
|
||||||
/* Setup the INI1 header in memory for the kernel. */
|
/* Setup the INI1 header in memory for the kernel. */
|
||||||
|
|
Loading…
Reference in a new issue