kernel_ldr: finish implementing all core logic.
This commit is contained in:
69
libraries/libmesosphere/source/arch/arm64/kern_cpu.cpp
Normal file
69
libraries/libmesosphere/source/arch/arm64/kern_cpu.cpp
Normal file
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2019 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/>.
|
||||
*/
|
||||
#include <mesosphere.hpp>
|
||||
|
||||
namespace ams::kern::arm64::cpu {
|
||||
|
||||
namespace {
|
||||
|
||||
void FlushEntireDataCacheImpl(int level) {
|
||||
/* Used in multiple locations. */
|
||||
const u64 level_sel_value = static_cast<u64>(level << 1);
|
||||
|
||||
/* Set selection register. */
|
||||
cpu::SetCsselrEl1(level_sel_value);
|
||||
cpu::InstructionMemoryBarrier();
|
||||
|
||||
/* Get cache size id info. */
|
||||
CacheSizeIdAccessor ccsidr_el1;
|
||||
const int num_sets = ccsidr_el1.GetNumberOfSets();
|
||||
const int num_ways = ccsidr_el1.GetAssociativity();
|
||||
const int line_size = ccsidr_el1.GetLineSize();
|
||||
|
||||
const u64 way_shift = static_cast<u64>(__builtin_clz(num_ways));
|
||||
const u64 set_shift = static_cast<u64>(line_size + 4);
|
||||
|
||||
for (int way = 0; way <= num_ways; way++) {
|
||||
for (int set = 0; set <= num_sets; set++) {
|
||||
const u64 way_value = static_cast<u64>(way) << way_shift;
|
||||
const u64 set_value = static_cast<u64>(set) << set_shift;
|
||||
const u64 cisw_value = way_value | set_value | level_sel_value;
|
||||
__asm__ __volatile__("dc cisw, %0" ::"r"(cisw_value) : "memory");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void FlushEntireDataCacheShared() {
|
||||
CacheLineIdAccessor clidr_el1;
|
||||
const int levels_of_coherency = clidr_el1.GetLevelsOfCoherency();
|
||||
const int levels_of_unification = clidr_el1.GetLevelsOfUnification();
|
||||
|
||||
for (int level = levels_of_coherency; level >= levels_of_unification; level--) {
|
||||
FlushEntireDataCacheImpl(level);
|
||||
}
|
||||
}
|
||||
|
||||
void FlushEntireDataCacheLocal() {
|
||||
CacheLineIdAccessor clidr_el1;
|
||||
const int levels_of_unification = clidr_el1.GetLevelsOfUnification();
|
||||
|
||||
for (int level = levels_of_unification - 1; level >= 0; level--) {
|
||||
FlushEntireDataCacheImpl(level);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -39,6 +39,12 @@ namespace ams::kern {
|
||||
return value;
|
||||
}
|
||||
|
||||
inline u64 GenerateRandomU64() {
|
||||
u64 value;
|
||||
smc::GenerateRandomBytes(&value, sizeof(value));
|
||||
return value;
|
||||
}
|
||||
|
||||
inline smc::MemoryMode GetMemoryMode() {
|
||||
return static_cast<smc::MemoryMode>((GetKernelConfiguration() >> 10) & 0x3);
|
||||
}
|
||||
@@ -73,6 +79,24 @@ namespace ams::kern {
|
||||
return (GetKernelConfiguration() >> 3) & 1;
|
||||
}
|
||||
|
||||
/* Randomness. */
|
||||
void KSystemControl::GenerateRandomBytes(void *dst, size_t size) {
|
||||
MESOSPHERE_ABORT_UNLESS(size <= 0x38);
|
||||
smc::GenerateRandomBytes(dst, size);
|
||||
}
|
||||
|
||||
u64 KSystemControl::GenerateRandomRange(u64 min, u64 max) {
|
||||
/* This is a biased random, but this is okay for now. */
|
||||
/* TODO: unbiased random? */
|
||||
const u64 range_size = ((max + 1) - min);
|
||||
const u64 effective_max = (std::numeric_limits<u64>::max() / range_size) * range_size;
|
||||
while (true) {
|
||||
if (const u64 rnd = GenerateRandomU64(); rnd < effective_max) {
|
||||
return rnd % effective_max;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void KSystemControl::StopSystem() {
|
||||
/* Display a panic screen via exosphere. */
|
||||
smc::Panic(0xF00);
|
||||
|
||||
@@ -80,6 +80,18 @@ namespace ams::kern::smc {
|
||||
}
|
||||
}
|
||||
|
||||
void GenerateRandomBytes(void *dst, size_t size) {
|
||||
/* Call SmcGenerateRandomBytes() */
|
||||
/* TODO: Lock this to ensure only one core calls at once. */
|
||||
SecureMonitorArguments args = { FunctionId_GetConfig, size };
|
||||
MESOSPHERE_ABORT_UNLESS(size <= sizeof(args) - sizeof(args.x[0]));
|
||||
CallPrivilegedSecureMonitorFunction(args);
|
||||
MESOSPHERE_ABORT_UNLESS((static_cast<SmcResult>(args.x[0]) == SmcResult::Success));
|
||||
|
||||
/* Copy output. */
|
||||
std::memcpy(dst, &args.x[1], size);
|
||||
}
|
||||
|
||||
void NORETURN Panic(u32 color) {
|
||||
SecureMonitorArguments args = { FunctionId_Panic, color };
|
||||
CallPrivilegedSecureMonitorFunction(args);
|
||||
|
||||
@@ -65,6 +65,7 @@ namespace ams::kern::smc {
|
||||
|
||||
/* TODO: Rest of Secure Monitor API. */
|
||||
void GetConfig(u64 *out, size_t num_qwords, ConfigItem config_item);
|
||||
void GenerateRandomBytes(void *dst, size_t size);
|
||||
void NORETURN Panic(u32 color);
|
||||
bool ReadWriteRegister(u32 *out, u64 address, u32 mask, u32 value);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user