Merge pull request #2847 from alula/23_support

23.0.0 remaining kernel / loader changes
This commit is contained in:
hexkyz
2026-09-18 21:18:12 +01:00
committed by GitHub
19 changed files with 268 additions and 129 deletions

View File

@@ -56,7 +56,7 @@ RUN dkp-pacman -S switch-tools hactool --noconfirm && dkp-pacman -Syu --noconfir
# rm -rf /tmp/switch-tools # rm -rf /tmp/switch-tools
# Install libnx from Git (optional) # Install libnx from Git (optional)
# ENV LIBNX_REV=dbcc1beafc6b47b5ffbeb8ba82463a7d45da40bb # ENV LIBNX_REV=146c3d1446d35546943c7b6cfcd479bc1f5e9b67
# RUN cd /tmp && \ # RUN cd /tmp && \
# mkdir -p /tmp/libnx && \ # mkdir -p /tmp/libnx && \
# cd /tmp/libnx && \ # cd /tmp/libnx && \
@@ -65,9 +65,8 @@ RUN dkp-pacman -S switch-tools hactool --noconfirm && dkp-pacman -Syu --noconfir
# git fetch --depth 1 origin $LIBNX_REV && \ # git fetch --depth 1 origin $LIBNX_REV && \
# git reset --hard FETCH_HEAD && \ # git reset --hard FETCH_HEAD && \
# make -j$(nproc) && \ # make -j$(nproc) && \
# mkdir -p /opt/devkitpro/libnx && \
# cd nx && \ # cd nx && \
# make DESTDIR=/opt/devkitpro/libnx install && \ # make install && \
# cd /tmp && \ # cd /tmp && \
# rm -rf /tmp/libnx # rm -rf /tmp/libnx

View File

@@ -51,9 +51,7 @@ namespace ams::kern::board::nintendo::nx {
static NOINLINE u32 GetCreateProcessMemoryPool(); static NOINLINE u32 GetCreateProcessMemoryPool();
/* Randomness. */ /* Randomness. */
static void GenerateRandom(u64 *dst, size_t count); static void GenerateRandomBytesForUninitialized(void *dst, size_t size);
static u64 GenerateRandomRange(u64 min, u64 max);
static u64 GenerateRandomU64();
/* Privileged Access. */ /* Privileged Access. */
static void ReadWriteRegisterPrivileged(u32 *out, ams::svc::PhysicalAddress address, u32 mask, u32 value); static void ReadWriteRegisterPrivileged(u32 *out, ams::svc::PhysicalAddress address, u32 mask, u32 value);

View File

@@ -119,6 +119,8 @@ namespace ams::kern {
KMemoryState_Insecure = ams::svc::MemoryState_Insecure | KMemoryState_FlagMapped | KMemoryState_FlagReferenceCounted | KMemoryState_FlagLinearMapped | KMemoryState_FlagCanChangeAttribute KMemoryState_Insecure = ams::svc::MemoryState_Insecure | KMemoryState_FlagMapped | KMemoryState_FlagReferenceCounted | KMemoryState_FlagLinearMapped | KMemoryState_FlagCanChangeAttribute
| KMemoryState_FlagCanDeviceMap | KMemoryState_FlagCanAlignedDeviceMap | KMemoryState_FlagCanQueryPhysical | KMemoryState_FlagCanDeviceMap | KMemoryState_FlagCanAlignedDeviceMap | KMemoryState_FlagCanQueryPhysical
| KMemoryState_FlagCanUseNonSecureIpc | KMemoryState_FlagCanUseNonDeviceIpc, | KMemoryState_FlagCanUseNonSecureIpc | KMemoryState_FlagCanUseNonDeviceIpc,
KMemoryState_ShadowStack = ams::svc::MemoryState_ShadowStack,
}; };
#if 1 #if 1
@@ -147,6 +149,7 @@ namespace ams::kern {
static_assert(KMemoryState_CodeOut == 0x04402015); static_assert(KMemoryState_CodeOut == 0x04402015);
static_assert(KMemoryState_Coverage == 0x00002016); /* TODO: Is this correct? */ static_assert(KMemoryState_Coverage == 0x00002016); /* TODO: Is this correct? */
static_assert(KMemoryState_Insecure == 0x055C3817); static_assert(KMemoryState_Insecure == 0x055C3817);
static_assert(KMemoryState_ShadowStack == 0x0000001A);
#endif #endif
enum KMemoryPermission : u8 { enum KMemoryPermission : u8 {

View File

@@ -37,13 +37,12 @@ namespace ams::kern {
public: public:
/* This can be overridden as needed. */ /* This can be overridden as needed. */
static constexpr size_t SecureAppletMemorySize = 0; static constexpr size_t SecureAppletMemorySize = 0;
protected: private:
/* Nintendo uses std::mt19937_t for randomness. */ /* Randomness helpers. */
/* To save space (and because mt19337_t isn't secure anyway), */ static void InitializeRandomGenerator(const void *seed, size_t size);
/* We will use TinyMT. */ static void ReseedRandomGeneratorInternal();
static constinit inline bool s_uninitialized_random_generator{true}; static u32 GenerateRandomU32();
static constinit inline util::TinyMT s_random_generator{util::ConstantInitialize}; static u64 GenerateRandomU64Internal();
static constinit inline KSpinLock s_random_lock;
public: public:
class Init { class Init {
private: private:
@@ -66,7 +65,7 @@ namespace ams::kern {
static u64 GenerateRandomRange(u64 min, u64 max); static u64 GenerateRandomRange(u64 min, u64 max);
}; };
protected: protected:
static NOINLINE void InitializePhase1Base(u64 seed); static NOINLINE void InitializePhase1Base(const void *seed, size_t size);
public: public:
/* Initialization. */ /* Initialization. */
static NOINLINE void ConfigureKTargetSystem(); static NOINLINE void ConfigureKTargetSystem();
@@ -78,6 +77,10 @@ namespace ams::kern {
static void GenerateRandom(u64 *dst, size_t count); static void GenerateRandom(u64 *dst, size_t count);
static u64 GenerateRandomRange(u64 min, u64 max); static u64 GenerateRandomRange(u64 min, u64 max);
static u64 GenerateRandomU64(); static u64 GenerateRandomU64();
static void ReseedRandomGenerator();
/* Obtains random bytes while the generator is not yet initialized. Board-provided. */
static void GenerateRandomBytesForUninitialized(void *dst, size_t size);
/* Register access Access. */ /* Register access Access. */
static Result ReadWriteRegister(u32 *out, ams::svc::PhysicalAddress address, u32 mask, u32 value); static Result ReadWriteRegister(u32 *out, ams::svc::PhysicalAddress address, u32 mask, u32 value);

View File

@@ -29,6 +29,7 @@ namespace ams::kern {
class KProcess; class KProcess;
class KConditionVariable; class KConditionVariable;
class KAddressArbiter; class KAddressArbiter;
class KPageBuffer;
using KThreadFunction = void (*)(uintptr_t); using KThreadFunction = void (*)(uintptr_t);
@@ -305,6 +306,8 @@ namespace ams::kern {
u32 *m_light_ipc_data; u32 *m_light_ipc_data;
KProcessAddress m_tls_address; KProcessAddress m_tls_address;
void *m_tls_heap_address; void *m_tls_heap_address;
KProcessAddress m_shadow_stack_address;
KPageBuffer *m_shadow_stack_page;
KLightLock m_activity_pause_lock; KLightLock m_activity_pause_lock;
SyncObjectBuffer m_sync_object_buffer; SyncObjectBuffer m_sync_object_buffer;
s64 m_schedule_count; s64 m_schedule_count;
@@ -347,7 +350,7 @@ namespace ams::kern {
: KAutoObjectWithSlabHeapAndContainer<KThread, KWorkerTask>(util::ConstantInitialize), KTimerTask(util::ConstantInitialize), : KAutoObjectWithSlabHeapAndContainer<KThread, KWorkerTask>(util::ConstantInitialize), KTimerTask(util::ConstantInitialize),
m_process_list_node{}, m_condvar_arbiter_tree_node{util::ConstantInitialize}, m_priority{-1}, m_condvar_tree{}, m_condvar_key{}, m_process_list_node{}, m_condvar_arbiter_tree_node{util::ConstantInitialize}, m_priority{-1}, m_condvar_tree{}, m_condvar_key{},
m_caller_save_fpu_registers{}, m_virtual_affinity_mask{}, m_physical_affinity_mask{}, m_thread_id{}, m_cpu_time{0}, m_address_key{Null<KProcessAddress>}, m_parent{}, m_caller_save_fpu_registers{}, m_virtual_affinity_mask{}, m_physical_affinity_mask{}, m_thread_id{}, m_cpu_time{0}, m_address_key{Null<KProcessAddress>}, m_parent{},
m_kernel_stack_top{}, m_light_ipc_data{}, m_tls_address{Null<KProcessAddress>}, m_tls_heap_address{}, m_activity_pause_lock{}, m_sync_object_buffer{util::ConstantInitialize}, m_kernel_stack_top{}, m_light_ipc_data{}, m_tls_address{Null<KProcessAddress>}, m_tls_heap_address{}, m_shadow_stack_address{Null<KProcessAddress>}, m_shadow_stack_page{}, m_activity_pause_lock{}, m_sync_object_buffer{util::ConstantInitialize},
m_schedule_count{}, m_last_scheduled_tick{}, m_per_core_priority_queue_entry{}, m_wait_queue{}, m_held_lock_info_list{}, m_waiting_lock_info{}, m_schedule_count{}, m_last_scheduled_tick{}, m_per_core_priority_queue_entry{}, m_wait_queue{}, m_held_lock_info_list{}, m_waiting_lock_info{},
m_pinned_waiter_list{}, m_debug_params{}, m_closed_object{}, m_address_key_value{}, m_suspend_request_flags{}, m_suspend_allowed_flags{}, m_synced_index{}, m_pinned_waiter_list{}, m_debug_params{}, m_closed_object{}, m_address_key_value{}, m_suspend_request_flags{}, m_suspend_allowed_flags{}, m_synced_index{},
m_wait_result{svc::ResultNoSynchronizationObject()}, m_debug_exception_result{ResultSuccess()}, m_base_priority{}, m_base_priority_on_unpin{}, m_wait_result{svc::ResultNoSynchronizationObject()}, m_debug_exception_result{ResultSuccess()}, m_base_priority{}, m_base_priority_on_unpin{},

View File

@@ -108,6 +108,8 @@ $(OFILES_SRC) : $(HFILES_BIN)
kern_libc_generic.o: CFLAGS += -fno-builtin kern_libc_generic.o: CFLAGS += -fno-builtin
crypto_aes_impl.arch.arm64.o: CXXFLAGS := $(filter-out -mgeneral-regs-only,$(CXXFLAGS))
#--------------------------------------------------------------------------------- #---------------------------------------------------------------------------------
%_bin.h %.bin.o : %.bin %_bin.h %.bin.o : %.bin
#--------------------------------------------------------------------------------- #---------------------------------------------------------------------------------

View File

@@ -196,6 +196,7 @@ namespace ams::kern::arch::arm64 {
case EsrEc_Cp14McrMrc: case EsrEc_Cp14McrMrc:
case EsrEc_Cp14Mrrc: case EsrEc_Cp14Mrrc:
case EsrEc_SystemInstruction64: case EsrEc_SystemInstruction64:
case EsrEc_SveZen:
case EsrEc_BkptInstruction: case EsrEc_BkptInstruction:
case EsrEc_BrkInstruction: case EsrEc_BrkInstruction:
type = ams::svc::ExceptionType_InstructionAbort; type = ams::svc::ExceptionType_InstructionAbort;
@@ -267,6 +268,7 @@ namespace ams::kern::arch::arm64 {
switch (ec) { switch (ec) {
case EsrEc_Unknown: case EsrEc_Unknown:
case EsrEc_IllegalExecution: case EsrEc_IllegalExecution:
case EsrEc_SveZen:
case EsrEc_BkptInstruction: case EsrEc_BkptInstruction:
case EsrEc_BrkInstruction: case EsrEc_BrkInstruction:
{ {
@@ -474,6 +476,7 @@ namespace ams::kern::arch::arm64 {
switch (ec) { switch (ec) {
case EsrEc_Unknown: case EsrEc_Unknown:
case EsrEc_IllegalExecution: case EsrEc_IllegalExecution:
case EsrEc_SveZen:
case EsrEc_BkptInstruction: case EsrEc_BkptInstruction:
case EsrEc_BrkInstruction: case EsrEc_BrkInstruction:
{ {
@@ -564,6 +567,7 @@ namespace ams::kern::arch::arm64 {
switch ((esr >> 26) & 0x3F) { switch ((esr >> 26) & 0x3F) {
case EsrEc_Unknown: case EsrEc_Unknown:
case EsrEc_IllegalExecution: case EsrEc_IllegalExecution:
case EsrEc_SveZen:
case EsrEc_BkptInstruction: case EsrEc_BkptInstruction:
case EsrEc_BrkInstruction: case EsrEc_BrkInstruction:
far = context->pc; far = context->pc;

View File

@@ -74,12 +74,6 @@ namespace ams::kern::board::nintendo::nx {
return value; return value;
} }
ALWAYS_INLINE u64 GenerateRandomU64FromSmc() {
u64 value;
smc::GenerateRandomBytes(std::addressof(value), sizeof(value));
return value;
}
ALWAYS_INLINE u64 GetConfigU64(smc::ConfigItem which) { ALWAYS_INLINE u64 GetConfigU64(smc::ConfigItem which) {
u64 value; u64 value;
smc::GetConfig(&value, 1, which); smc::GetConfig(&value, 1, which);
@@ -477,9 +471,9 @@ namespace ams::kern::board::nintendo::nx {
/* Initialize random and resource limit. */ /* Initialize random and resource limit. */
{ {
u64 seed; u8 seed[32];
smc::GenerateRandomBytes(std::addressof(seed), sizeof(seed)); smc::GenerateRandomBytes(seed, sizeof(seed));
KSystemControlBase::InitializePhase1Base(seed); KSystemControlBase::InitializePhase1Base(seed, sizeof(seed));
} }
/* Configure the Kernel Carveout region. */ /* Configure the Kernel Carveout region. */
@@ -524,32 +518,8 @@ namespace ams::kern::board::nintendo::nx {
} }
/* Randomness. */ /* Randomness. */
void KSystemControl::GenerateRandom(u64 *dst, size_t count) { void KSystemControl::GenerateRandomBytesForUninitialized(void *dst, size_t size) {
MESOSPHERE_INIT_ABORT_UNLESS(count <= 7); smc::GenerateRandomBytes(dst, size);
smc::GenerateRandomBytes(dst, count * sizeof(u64));
}
u64 KSystemControl::GenerateRandomRange(u64 min, u64 max) {
KScopedInterruptDisable intr_disable;
KScopedSpinLock lk(s_random_lock);
if (AMS_LIKELY(!s_uninitialized_random_generator)) {
return KSystemControlBase::GenerateUniformRange(min, max, []() ALWAYS_INLINE_LAMBDA -> u64 { return s_random_generator.GenerateRandomU64(); });
} else {
return KSystemControlBase::GenerateUniformRange(min, max, GenerateRandomU64FromSmc);
}
}
u64 KSystemControl::GenerateRandomU64() {
KScopedInterruptDisable intr_disable;
KScopedSpinLock lk(s_random_lock);
if (AMS_LIKELY(!s_uninitialized_random_generator)) {
return s_random_generator.GenerateRandomU64();
} else {
return GenerateRandomU64FromSmc();
}
} }
void KSystemControl::SleepSystem() { void KSystemControl::SleepSystem() {

View File

@@ -264,6 +264,11 @@ namespace ams::kern {
m_is_default_application_system_resource = false; m_is_default_application_system_resource = false;
m_is_immortal = immortal; m_is_immortal = immortal;
/* Reseed the random generator on application launch. */
if (params.flags & ams::svc::CreateProcessParameterFlag_IsApplication) {
KSystemControl::ReseedRandomGenerator();
}
/* Setup our system resource. */ /* Setup our system resource. */
if (const size_t system_resource_num_pages = params.system_resource_num_pages; system_resource_num_pages != 0) { if (const size_t system_resource_num_pages = params.system_resource_num_pages; system_resource_num_pages != 0) {
/* Create a secure system resource. */ /* Create a secure system resource. */
@@ -332,6 +337,11 @@ namespace ams::kern {
m_is_default_application_system_resource = false; m_is_default_application_system_resource = false;
m_is_immortal = false; m_is_immortal = false;
/* Reseed the random generator on application launch. */
if (params.flags & ams::svc::CreateProcessParameterFlag_IsApplication) {
KSystemControl::ReseedRandomGenerator();
}
/* Get the memory sizes. */ /* Get the memory sizes. */
const size_t code_num_pages = params.code_num_pages; const size_t code_num_pages = params.code_num_pages;
const size_t system_resource_num_pages = params.system_resource_num_pages; const size_t system_resource_num_pages = params.system_resource_num_pages;

View File

@@ -14,6 +14,8 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <mesosphere.hpp> #include <mesosphere.hpp>
#include <vapours/crypto/crypto_aes_encryptor.hpp>
#include <vapours/crypto/impl/crypto_ctr_drbg.hpp>
#if defined(ATMOSPHERE_ARCH_ARM64) #if defined(ATMOSPHERE_ARCH_ARM64)
#include <mesosphere/arch/arm64/kern_secure_monitor_base.hpp> #include <mesosphere/arch/arm64/kern_secure_monitor_base.hpp>
#endif #endif
@@ -27,6 +29,41 @@ namespace ams::kern {
} }
namespace {
/* The kernel is otherwise FP/SIMD-free, but AES instructions require the NEON registers. */
class KScopedFpuEnable {
private:
u64 m_saved_cpacr_el1;
public:
ALWAYS_INLINE KScopedFpuEnable() : m_saved_cpacr_el1(cpu::GetCpacrEl1()) {
cpu::SetCpacrEl1(m_saved_cpacr_el1 | 0x100000);
cpu::InstructionMemoryBarrier();
}
ALWAYS_INLINE ~KScopedFpuEnable() {
cpu::SetCpacrEl1(m_saved_cpacr_el1);
cpu::InstructionMemoryBarrier();
}
};
using RandomGenerator = ::ams::crypto::impl::CtrDrbg<::ams::crypto::AesEncryptor128, 16, false>;
constexpr size_t RandomGeneratorOutputSize = 8 * RandomGenerator::OutSize;
constexpr u32 RandomGeneratorOutputCount = RandomGeneratorOutputSize / sizeof(u32);
constinit util::TypedStorage<RandomGenerator> s_random_generator = {};
constinit bool s_uninitialized_random_generator = true;
constinit u8 s_random_output[RandomGeneratorOutputSize] = {};
constinit u32 s_random_remaining = 0;
constinit KSpinLock s_random_lock;
void GenerateRandomSeed(void *dst, size_t size) {
KSystemControl::GenerateRandomBytesForUninitialized(dst, size);
}
}
/* Initialization. */ /* Initialization. */
size_t KSystemControlBase::Init::GetRealMemorySize() { size_t KSystemControlBase::Init::GetRealMemorySize() {
return ams::kern::MainMemorySize; return ams::kern::MainMemorySize;
@@ -102,25 +139,13 @@ namespace ams::kern {
/* Randomness for Initialization. */ /* Randomness for Initialization. */
void KSystemControlBase::Init::GenerateRandom(u64 *dst, size_t count) { void KSystemControlBase::Init::GenerateRandom(u64 *dst, size_t count) {
if (AMS_UNLIKELY(s_uninitialized_random_generator)) {
const u64 seed = KHardwareTimer::GetTick();
s_random_generator.Initialize(reinterpret_cast<const u32*>(std::addressof(seed)), sizeof(seed) / sizeof(u32));
s_uninitialized_random_generator = false;
}
for (size_t i = 0; i < count; ++i) { for (size_t i = 0; i < count; ++i) {
dst[i] = s_random_generator.GenerateRandomU64(); dst[i] = KSystemControlBase::GenerateRandomU64();
} }
} }
u64 KSystemControlBase::Init::GenerateRandomRange(u64 min, u64 max) { u64 KSystemControlBase::Init::GenerateRandomRange(u64 min, u64 max) {
if (AMS_UNLIKELY(s_uninitialized_random_generator)) { return KSystemControlBase::GenerateRandomRange(min, max);
const u64 seed = KHardwareTimer::GetTick();
s_random_generator.Initialize(reinterpret_cast<const u32*>(std::addressof(seed)), sizeof(seed) / sizeof(u32));
s_uninitialized_random_generator = false;
}
return KSystemControlBase::GenerateUniformRange(min, max, []() ALWAYS_INLINE_LAMBDA -> u64 { return s_random_generator.GenerateRandomU64(); });
} }
/* System Initialization. */ /* System Initialization. */
@@ -135,15 +160,17 @@ namespace ams::kern {
} }
/* Initialize random and resource limit. */ /* Initialize random and resource limit. */
KSystemControlBase::InitializePhase1Base(KHardwareTimer::GetTick()); u64 seed[4];
for (size_t i = 0; i < util::size(seed); ++i) {
seed[i] = KHardwareTimer::GetTick();
}
KSystemControlBase::InitializePhase1Base(seed, sizeof(seed));
} }
void KSystemControlBase::InitializePhase1Base(u64 seed) { void KSystemControlBase::InitializePhase1Base(const void *seed, size_t size) {
/* Initialize the rng, if we somehow haven't already. */ /* Initialize the random generator. */
if (AMS_UNLIKELY(s_uninitialized_random_generator)) { KSystemControlBase::InitializeRandomGenerator(seed, size);
s_random_generator.Initialize(reinterpret_cast<const u32*>(std::addressof(seed)), sizeof(seed) / sizeof(u32)); s_uninitialized_random_generator = false;
s_uninitialized_random_generator = false;
}
/* Initialize debug logging. */ /* Initialize debug logging. */
KDebugLog::Initialize(); KDebugLog::Initialize();
@@ -213,13 +240,77 @@ namespace ams::kern {
R_THROW(svc::ResultNotImplemented()); R_THROW(svc::ResultNotImplemented());
} }
/* Randomness helpers. Assume the caller holds the random lock. */
void KSystemControlBase::InitializeRandomGenerator(const void *seed, size_t size) {
MESOSPHERE_ASSERT(size == RandomGenerator::SeedSize);
KScopedFpuEnable fp_enabled;
/* Construct the generator, and derive the initial state from the seed. */
util::ConstructAt(s_random_generator);
util::GetReference(s_random_generator).Initialize(seed, size, nullptr, 0, nullptr, 0);
s_random_remaining = 0;
}
void KSystemControlBase::ReseedRandomGeneratorInternal() {
KScopedFpuEnable fp_enabled;
/* Pull fresh entropy, then derive a new state from it. */
u8 seed[RandomGenerator::SeedSize];
GenerateRandomSeed(seed, sizeof(seed));
util::GetReference(s_random_generator).Reseed(seed, sizeof(seed), nullptr, 0);
s_random_remaining = 0;
}
u32 KSystemControlBase::GenerateRandomU32() {
if (s_random_remaining == 0) {
KScopedFpuEnable fp_enabled;
auto &drbg = util::GetReference(s_random_generator);
/* Derive the next state, or reseed if we've exhausted this generation's entropy. */
if (AMS_UNLIKELY(!drbg.Generate(s_random_output, sizeof(s_random_output), nullptr, 0))) {
u8 seed[RandomGenerator::SeedSize];
GenerateRandomSeed(seed, sizeof(seed));
drbg.Reseed(seed, sizeof(seed), nullptr, 0);
MESOSPHERE_ABORT_UNLESS(drbg.Generate(s_random_output, sizeof(s_random_output), nullptr, 0));
}
s_random_remaining = RandomGeneratorOutputCount;
}
/* Consume a word from the output buffer, zeroizing it in place for backtracking resistance. */
const size_t index = RandomGeneratorOutputCount - s_random_remaining;
u32 value;
std::memcpy(std::addressof(value), s_random_output + sizeof(value) * index, sizeof(value));
std::memset(s_random_output + sizeof(value) * index, 0, sizeof(value));
--s_random_remaining;
return value;
}
u64 KSystemControlBase::GenerateRandomU64Internal() {
/* Fall back to the board's raw source while the generator is uninitialized. */
if (AMS_UNLIKELY(s_uninitialized_random_generator)) {
u64 value;
KSystemControl::GenerateRandomBytesForUninitialized(std::addressof(value), sizeof(value));
return value;
}
const u64 high = KSystemControlBase::GenerateRandomU32();
const u64 low = KSystemControlBase::GenerateRandomU32();
return (high << 32) | low;
}
/* Randomness. */ /* Randomness. */
void KSystemControlBase::GenerateRandom(u64 *dst, size_t count) { void KSystemControlBase::GenerateRandom(u64 *dst, size_t count) {
KScopedInterruptDisable intr_disable; KScopedInterruptDisable intr_disable;
KScopedSpinLock lk(s_random_lock); KScopedSpinLock lk(s_random_lock);
for (size_t i = 0; i < count; ++i) { for (size_t i = 0; i < count; ++i) {
dst[i] = s_random_generator.GenerateRandomU64(); dst[i] = KSystemControlBase::GenerateRandomU64Internal();
} }
} }
@@ -227,14 +318,46 @@ namespace ams::kern {
KScopedInterruptDisable intr_disable; KScopedInterruptDisable intr_disable;
KScopedSpinLock lk(s_random_lock); KScopedSpinLock lk(s_random_lock);
return KSystemControlBase::GenerateUniformRange(min, max, []() ALWAYS_INLINE_LAMBDA -> u64 { return s_random_generator.GenerateRandomU64(); }); /* While uninitialized, fall back to a raw single-draw modulo. */
if (AMS_UNLIKELY(s_uninitialized_random_generator)) {
u64 value;
KSystemControl::GenerateRandomBytesForUninitialized(std::addressof(value), sizeof(value));
const u64 difference = max - min;
if (difference == std::numeric_limits<u64>::max()) {
return value;
}
return min + (value % (difference + 1));
}
return KSystemControlBase::GenerateUniformRange(min, max, []() ALWAYS_INLINE_LAMBDA -> u64 { return KSystemControlBase::GenerateRandomU64Internal(); });
} }
u64 KSystemControlBase::GenerateRandomU64() { u64 KSystemControlBase::GenerateRandomU64() {
KScopedInterruptDisable intr_disable; KScopedInterruptDisable intr_disable;
KScopedSpinLock lk(s_random_lock); KScopedSpinLock lk(s_random_lock);
return s_random_generator.GenerateRandomU64(); return KSystemControlBase::GenerateRandomU64Internal();
}
void KSystemControlBase::ReseedRandomGenerator() {
/* This must be unreachable while the generator is uninitialized. */
MESOSPHERE_ABORT_UNLESS(!s_uninitialized_random_generator);
KScopedInterruptDisable intr_disable;
KScopedSpinLock lk(s_random_lock);
KSystemControlBase::ReseedRandomGeneratorInternal();
}
void KSystemControlBase::GenerateRandomBytesForUninitialized(void *dst, size_t size) {
/* The default board has no secure monitor; fall back to the hardware timer. */
u8 *dst_8 = static_cast<u8 *>(dst);
for (size_t offset = 0; offset < size; offset += sizeof(u64)) {
const u64 tick = KHardwareTimer::GetTick();
std::memcpy(dst_8 + offset, std::addressof(tick), std::min(sizeof(tick), size - offset));
}
} }
void KSystemControlBase::SleepSystem() { void KSystemControlBase::SleepSystem() {

View File

@@ -214,6 +214,10 @@ namespace ams::kern {
m_tls_address = 0; m_tls_address = 0;
m_tls_heap_address = 0; m_tls_heap_address = 0;
/* Set shadow stack address and page. */
m_shadow_stack_address = Null<KProcessAddress>;
m_shadow_stack_page = nullptr;
/* Set parent and condvar tree. */ /* Set parent and condvar tree. */
m_parent = nullptr; m_parent = nullptr;
m_condvar_tree = nullptr; m_condvar_tree = nullptr;
@@ -281,6 +285,29 @@ namespace ams::kern {
R_TRY(owner->CreateThreadLocalRegion(std::addressof(m_tls_address))); R_TRY(owner->CreateThreadLocalRegion(std::addressof(m_tls_address)));
m_tls_heap_address = owner->GetThreadLocalRegionPointer(m_tls_address); m_tls_heap_address = owner->GetThreadLocalRegionPointer(m_tls_address);
std::memset(m_tls_heap_address, 0, ams::svc::ThreadLocalRegionSize); std::memset(m_tls_heap_address, 0, ams::svc::ThreadLocalRegionSize);
/* If the owning process has a shadow stack, allocate and map a page for this thread. */
if (owner->GetCreateProcessParameterFlags() & ams::svc::CreateProcessParameterFlag_EnableShadowStack) {
/* Allocate the backing page. */
KPageBuffer *page = KPageBuffer::AllocateChecked<PageSize>();
if (page == nullptr) {
owner->DeleteThreadLocalRegion(m_tls_address);
m_tls_address = Null<KProcessAddress>;
R_THROW(svc::ResultOutOfMemory());
}
/* If we fail to map the page, free it and undo the TLS region we just created. */
ON_RESULT_FAILURE {
KPageBuffer::Free(page);
owner->DeleteThreadLocalRegion(m_tls_address);
m_tls_address = Null<KProcessAddress>;
};
/* Map the page into the process's shadow stack region. */
R_TRY(owner->GetPageTable().MapPages(std::addressof(m_shadow_stack_address), 1, PageSize, page->GetPhysicalAddress(), KMemoryState_ShadowStack, KMemoryPermission_UserReadWrite));
m_shadow_stack_page = page;
}
} }
/* Set parent, if relevant. */ /* Set parent, if relevant. */
@@ -390,6 +417,12 @@ namespace ams::kern {
m_parent->UnregisterThread(this); m_parent->UnregisterThread(this);
} }
/* If the thread has a shadow stack, unmap and free its page. */
if (m_shadow_stack_address != Null<KProcessAddress>) {
MESOSPHERE_R_ABORT_UNLESS(m_parent->GetPageTable().UnmapPages(m_shadow_stack_address, 1, KMemoryState_ShadowStack));
KPageBuffer::Free(m_shadow_stack_page);
}
/* If the thread has a local region, delete it. */ /* If the thread has a local region, delete it. */
if (m_tls_address != Null<KProcessAddress>) { if (m_tls_address != Null<KProcessAddress>) {
m_parent->DeleteThreadLocalRegion(m_tls_address); m_parent->DeleteThreadLocalRegion(m_tls_address);

View File

@@ -89,6 +89,12 @@ namespace ams::spl {
return ::ams::spl::GetConfigBool(::ams::spl::ConfigItem::ExosphereForceEnableUsb30); return ::ams::spl::GetConfigBool(::ams::spl::ConfigItem::ExosphereForceEnableUsb30);
} }
inline std::pair<u8, u32> GetLogConfiguration() {
u64 v;
R_ABORT_UNLESS(::ams::spl::GetConfig(std::addressof(v), ::ams::spl::ConfigItem::ExosphereLogConfiguration));
return std::make_pair(static_cast<u8>(v >> 32), static_cast<u32>(v));
}
Result SetBootReason(BootReasonValue boot_reason); Result SetBootReason(BootReasonValue boot_reason);
Result GetBootReason(BootReasonValue *out); Result GetBootReason(BootReasonValue *out);

View File

@@ -14,14 +14,14 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <stratosphere.hpp> #include <stratosphere.hpp>
#include "../spl/impl/spl_ctr_drbg.hpp" #include <vapours/crypto/impl/crypto_ctr_drbg.hpp>
#include <sys/random.h> #include <sys/random.h>
namespace ams::crypto { namespace ams::crypto {
namespace { namespace {
using Drbg = ::ams::spl::impl::CtrDrbg<crypto::AesEncryptor128, crypto::AesEncryptor128::KeySize, false>; using Drbg = ::ams::crypto::impl::CtrDrbg<crypto::AesEncryptor128, crypto::AesEncryptor128::KeySize, false>;
constinit util::TypedStorage<Drbg> g_drbg = {}; constinit util::TypedStorage<Drbg> g_drbg = {};

View File

@@ -17,7 +17,6 @@
#include "pinmux_pad_index.hpp" #include "pinmux_pad_index.hpp"
#include "pinmux_board_driver_api.hpp" #include "pinmux_board_driver_api.hpp"
#include "pinmux_platform_pads.hpp" #include "pinmux_platform_pads.hpp"
#include "pinmux_build_config.hpp"
namespace ams::pinmux::driver::board::nintendo::nx { namespace ams::pinmux::driver::board::nintendo::nx {
@@ -101,30 +100,33 @@ namespace ams::pinmux::driver::board::nintendo::nx {
UpdateSinglePinmuxPad({ PinmuxPadIndex_Sdmmc2Dat7, 0x2000, 0x2000 }); UpdateSinglePinmuxPad({ PinmuxPadIndex_Sdmmc2Dat7, 0x2000, 0x2000 });
} }
#if defined(AMS_PINMUX_CONFIG_RIGHT_RAIL_AS_UART) auto [log_port, log_baud_rate] = spl::GetLogConfiguration();
UpdateSinglePinmuxPad({ AMS_UNUSED(log_baud_rate);
.index = PinmuxPadIndex_Uart2Tx,
.option = (u32)PinmuxPadPm_Pm0 | PinmuxOpt_NoPupd | PinmuxOpt_Output, if (log_port == 1) {
.option_mask = (u32)PinmuxOptBitMask_Pm | PinmuxOptBitMask_Pupd | PinmuxOptBitMask_Dir, UpdateSinglePinmuxPad({
}); .index = PinmuxPadIndex_Uart2Tx,
UpdateSinglePinmuxPad({ .option = (u32)PinmuxPadPm_Pm0 | PinmuxOpt_NoPupd | PinmuxOpt_Output,
.index = PinmuxPadIndex_Uart2Cts, .option_mask = (u32)PinmuxOptBitMask_Pm | PinmuxOptBitMask_Pupd | PinmuxOptBitMask_Dir,
.option = (u32)PinmuxPadPm_Pm0 | PinmuxOpt_NoPupd | PinmuxOpt_Input, });
.option_mask = (u32)PinmuxOptBitMask_Pm | PinmuxOptBitMask_Pupd | PinmuxOptBitMask_Dir, UpdateSinglePinmuxPad({
}); .index = PinmuxPadIndex_Uart2Cts,
#endif .option = (u32)PinmuxPadPm_Pm0 | PinmuxOpt_NoPupd | PinmuxOpt_Input,
#if defined(AMS_PINMUX_CONFIG_LEFT_RAIL_AS_UART) .option_mask = (u32)PinmuxOptBitMask_Pm | PinmuxOptBitMask_Pupd | PinmuxOptBitMask_Dir,
UpdateSinglePinmuxPad({ });
.index = PinmuxPadIndex_Uart3Tx, }
.option = (u32)PinmuxPadPm_Pm0 | PinmuxOpt_NoPupd | PinmuxOpt_Output, if (log_port == 2) {
.option_mask = (u32)PinmuxOptBitMask_Pm | PinmuxOptBitMask_Pupd | PinmuxOptBitMask_Dir, UpdateSinglePinmuxPad({
}); .index = PinmuxPadIndex_Uart3Tx,
UpdateSinglePinmuxPad({ .option = (u32)PinmuxPadPm_Pm0 | PinmuxOpt_NoPupd | PinmuxOpt_Output,
.index = PinmuxPadIndex_Uart3Cts, .option_mask = (u32)PinmuxOptBitMask_Pm | PinmuxOptBitMask_Pupd | PinmuxOptBitMask_Dir,
.option = (u32)PinmuxPadPm_Pm0 | PinmuxOpt_NoPupd | PinmuxOpt_Input, });
.option_mask = (u32)PinmuxOptBitMask_Pm | PinmuxOptBitMask_Pupd | PinmuxOptBitMask_Dir, UpdateSinglePinmuxPad({
}); .index = PinmuxPadIndex_Uart3Cts,
#endif .option = (u32)PinmuxPadPm_Pm0 | PinmuxOpt_NoPupd | PinmuxOpt_Input,
.option_mask = (u32)PinmuxOptBitMask_Pm | PinmuxOptBitMask_Pupd | PinmuxOptBitMask_Dir,
});
}
} }
void SetInitialDrivePadConfig() { void SetInitialDrivePadConfig() {

View File

@@ -1,20 +0,0 @@
/*
* Copyright (c) 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/>.
*/
#pragma once
#include <stratosphere.hpp>
// #define AMS_PINMUX_CONFIG_RIGHT_RAIL_AS_UART
// #define AMS_PINMUX_CONFIG_LEFT_RAIL_AS_UART

View File

@@ -14,7 +14,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <stratosphere.hpp> #include <stratosphere.hpp>
#include "spl_ctr_drbg.hpp" #include <vapours/crypto/impl/crypto_ctr_drbg.hpp>
#include "spl_device_address_mapper.hpp" #include "spl_device_address_mapper.hpp"
#include "spl_key_slot_cache.hpp" #include "spl_key_slot_cache.hpp"
@@ -29,7 +29,7 @@ namespace ams::spl::impl {
namespace { namespace {
/* Drbg type. */ /* Drbg type. */
using Drbg = CtrDrbg<crypto::AesEncryptor128, AesKeySize, false>; using Drbg = crypto::impl::CtrDrbg<crypto::AesEncryptor128, AesKeySize, false>;
/* Convenient defines. */ /* Convenient defines. */
#if defined(ATMOSPHERE_OS_HORIZON) #if defined(ATMOSPHERE_OS_HORIZON)

View File

@@ -33,7 +33,7 @@ namespace ams::crypto::impl {
#ifdef ATMOSPHERE_IS_EXOSPHERE #ifdef ATMOSPHERE_IS_EXOSPHERE
int m_slot; int m_slot;
#endif #endif
#ifdef ATMOSPHERE_IS_STRATOSPHERE #if defined(ATMOSPHERE_IS_STRATOSPHERE) || defined(ATMOSPHERE_IS_MESOSPHERE)
u32 m_round_keys[RoundKeySize / sizeof(u32)]; u32 m_round_keys[RoundKeySize / sizeof(u32)];
#endif #endif
public: public:
@@ -43,7 +43,7 @@ namespace ams::crypto::impl {
void EncryptBlock(void *dst, size_t dst_size, const void *src, size_t src_size) const; void EncryptBlock(void *dst, size_t dst_size, const void *src, size_t src_size) const;
void DecryptBlock(void *dst, size_t dst_size, const void *src, size_t src_size) const; void DecryptBlock(void *dst, size_t dst_size, const void *src, size_t src_size) const;
#ifdef ATMOSPHERE_IS_STRATOSPHERE #if defined(ATMOSPHERE_IS_STRATOSPHERE) || defined(ATMOSPHERE_IS_MESOSPHERE)
const u8 *GetRoundKey() const { const u8 *GetRoundKey() const {
return reinterpret_cast<const u8 *>(m_round_keys); return reinterpret_cast<const u8 *>(m_round_keys);
} }

View File

@@ -14,9 +14,9 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#pragma once #pragma once
#include <stratosphere.hpp> #include <vapours.hpp>
namespace ams::spl::impl { namespace ams::crypto::impl {
constexpr inline int BitsPerByte = BITSIZEOF(u8); constexpr inline int BitsPerByte = BITSIZEOF(u8);

View File

@@ -14,13 +14,16 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <vapours.hpp> #include <vapours.hpp>
#if defined(ATMOSPHERE_IS_STRATOSPHERE) #if defined(ATMOSPHERE_IS_MESOSPHERE)
#include <mesosphere/kern_panic.hpp>
#endif
#if defined(ATMOSPHERE_IS_STRATOSPHERE) || defined(ATMOSPHERE_IS_MESOSPHERE)
#include <arm_neon.h> #include <arm_neon.h>
#endif #endif
namespace ams::crypto::impl { namespace ams::crypto::impl {
#if defined(ATMOSPHERE_IS_STRATOSPHERE) #if defined(ATMOSPHERE_IS_STRATOSPHERE) || defined(ATMOSPHERE_IS_MESOSPHERE)
namespace { namespace {