Compare commits

...

10 Commits
1.2.1 ... 1.2.2

Author SHA1 Message Date
Michael Scire
b9c90b9234 git subrepo push libraries
subrepo:
  subdir:   "libraries"
  merged:   "4d0f1b792"
upstream:
  origin:   "https://github.com/Atmosphere-NX/Atmosphere-libs"
  branch:   "master"
  commit:   "4d0f1b792"
git-subrepo:
  version:  "0.4.1"
  origin:   "???"
  commit:   "???"
2021-10-29 17:47:35 -07:00
Michael Scire
94e18b8c93 ams: bump version to 1.2.2 2021-10-29 17:47:01 -07:00
Michael Scire
4e92687cab sprofile: various correctness fixes. 2021-10-29 17:38:44 -07:00
Michael Scire
2a0b99d9f9 sprofile: fix off-by-one in struct definition, fix GetImportableProfileUrls 2021-10-29 15:41:25 -07:00
Michael Scire
d1f3c4904b kern: fix minor assembly bugs, avoid unnecessary function call in KScheduler hotloop 2021-10-28 19:16:23 -07:00
Michael Scire
92321ccbc8 kern: fix 32-bit light ipc svc handler asm
Nintendo used to do what we were doing because the function wasn't directly in the handler table,
but we've always been directly in the handler table, so we were trashing the last four arguments to light ipc
when called from aarch32. Nothing uses this, but needed to be fixed.
2021-10-28 15:42:52 -07:00
Michael Scire
db3004e844 git subrepo push libraries
subrepo:
  subdir:   "libraries"
  merged:   "0a0bd74ca"
upstream:
  origin:   "https://github.com/Atmosphere-NX/Atmosphere-libs"
  branch:   "master"
  commit:   "0a0bd74ca"
git-subrepo:
  version:  "0.4.1"
  origin:   "???"
  commit:   "???"
2021-10-27 22:57:39 -07:00
Michael Scire
3e97e4addf init: disable fsdev cwd to prevent abort on fsdev usage (fsdev should not be used) 2021-10-27 22:57:09 -07:00
Michael Scire
4b7b33809f kern: optimize and bring into line with N our pstate.i management 2021-10-27 15:00:07 -07:00
Michael Scire
e81a1ce5a8 kern: audit (and fix) our hardware maintenance instructions to match official kernel 2021-10-27 12:31:53 -07:00
38 changed files with 270 additions and 284 deletions

View File

@@ -1,4 +1,20 @@
# Changelog # Changelog
## 1.2.2
+ A number of fixes were made to Atmosphère's implementation of the new "sprofile" service added in 13.0.0.
+ Nintendo is finally transmitting data over the internet to certain consoles, which has allowed for validating our service implementation.
+ Unfortunately, there were several problems, and if your console began trying to use the new services atmosphere would show a fatal error with code 0xCAF6 (sprofile::ResultInvalidState()).
+ With actual test data in hand, a test program was written and it was verified that our implementation can successfully import/access profile data now.
+ Hopefully there are no more issues, and I sincerely apologize for anyone who got an 0xCAF6 fatal due to this.
+ A number of minor improvements were made to `mesosphère`, including:
+ KThread::GetContextForSchedulerLoop was implemented in assembly (using static assertions to verify offset-of-context-in-struct is correct).
+ This saves an unnecessary function call in the middle of the scheduler hot loop, replacing it with an addition instruction, which should improve microperformance.
+ Mesosphere's hardware maintenance instructions were audited via a script and now directly match Nintendo's kernels.
+ Notably, this inserts a missing instruction synchronization barrier when validating that slab heaps may be constructed.
+ This missing ISB could cause an abort on certain (see: particularly sensitive) hardware on boot if the relevant codepath was speculatively executed (it normally only executes on game launch...)
+ The SVC handlers for performing light IPC (normally unused) from 32-bit process were fixed in Mesosphere.
+ A bug was fixed that would cause the register x27 to be overwritten with the contents of x26 when returning from a user exception handler.
+ A bug was fixed that would cause the kernel to use the userland stack pointer instead of the kernel stack pointer while generating an error report for a kernel abort.
+ General system stability improvements to enhance the user's experience.
## 1.2.1 ## 1.2.1
+ Support was implemented for 13.1.0. + Support was implemented for 13.1.0.
+ `mesosphère` was updated to reflect the kernel behavioral changes made in 13.1.0. + `mesosphère` was updated to reflect the kernel behavioral changes made in 13.1.0.

View File

@@ -6,7 +6,7 @@
[subrepo] [subrepo]
remote = https://github.com/Atmosphere-NX/Atmosphere-libs remote = https://github.com/Atmosphere-NX/Atmosphere-libs
branch = master branch = master
commit = 13c6987cc43d0b9a874e87e3ce8eaffd1c72fa69 commit = 4d0f1b79246d7d2c19219bc7da153fdfef165f57
parent = cb38b0b929f332a52ceeee5c27cb0fd83ff03433 parent = 94e18b8c93e6013aaa647d31d54cb3f06e391a46
method = merge method = merge
cmdver = 0.4.1 cmdver = 0.4.1

View File

@@ -93,3 +93,4 @@
/* Deferred includes. */ /* Deferred includes. */
#include <mesosphere/kern_k_auto_object_impls.hpp> #include <mesosphere/kern_k_auto_object_impls.hpp>
#include <mesosphere/kern_k_scheduler_impls.hpp>

View File

@@ -279,7 +279,7 @@ namespace ams::kern::arch::arm64::init {
/* Invalidate the entire tlb. */ /* Invalidate the entire tlb. */
cpu::DataSynchronizationBarrierInnerShareable(); cpu::DataSynchronizationBarrierInnerShareable();
cpu::InvalidateEntireTlb(); cpu::InvalidateEntireTlbInnerShareable();
/* Copy data, if we should. */ /* Copy data, if we should. */
const u64 negative_block_size_for_mask = static_cast<u64>(-static_cast<s64>(block_size)); const u64 negative_block_size_for_mask = static_cast<u64>(-static_cast<s64>(block_size));
@@ -350,7 +350,6 @@ namespace ams::kern::arch::arm64::init {
/* If we don't already have an L2 table, we need to make a new one. */ /* If we don't already have an L2 table, we need to make a new one. */
if (!l1_entry->IsTable()) { if (!l1_entry->IsTable()) {
KPhysicalAddress new_table = AllocateNewPageTable(allocator); KPhysicalAddress new_table = AllocateNewPageTable(allocator);
ClearNewPageTable(new_table);
*l1_entry = L1PageTableEntry(PageTableEntry::TableTag{}, new_table, attr.IsPrivilegedExecuteNever()); *l1_entry = L1PageTableEntry(PageTableEntry::TableTag{}, new_table, attr.IsPrivilegedExecuteNever());
cpu::DataSynchronizationBarrierInnerShareable(); cpu::DataSynchronizationBarrierInnerShareable();
} }
@@ -361,12 +360,12 @@ namespace ams::kern::arch::arm64::init {
if (util::IsAligned(GetInteger(virt_addr), L2ContiguousBlockSize) && util::IsAligned(GetInteger(phys_addr), L2ContiguousBlockSize) && size >= L2ContiguousBlockSize) { if (util::IsAligned(GetInteger(virt_addr), L2ContiguousBlockSize) && util::IsAligned(GetInteger(phys_addr), L2ContiguousBlockSize) && size >= L2ContiguousBlockSize) {
for (size_t i = 0; i < L2ContiguousBlockSize / L2BlockSize; i++) { for (size_t i = 0; i < L2ContiguousBlockSize / L2BlockSize; i++) {
l2_entry[i] = L2PageTableEntry(PageTableEntry::BlockTag{}, phys_addr, attr, PageTableEntry::SoftwareReservedBit_None, true); l2_entry[i] = L2PageTableEntry(PageTableEntry::BlockTag{}, phys_addr, attr, PageTableEntry::SoftwareReservedBit_None, true);
cpu::DataSynchronizationBarrierInnerShareable();
virt_addr += L2BlockSize; virt_addr += L2BlockSize;
phys_addr += L2BlockSize; phys_addr += L2BlockSize;
size -= L2BlockSize; size -= L2BlockSize;
} }
cpu::DataSynchronizationBarrierInnerShareable();
continue; continue;
} }
@@ -384,7 +383,6 @@ namespace ams::kern::arch::arm64::init {
/* If we don't already have an L3 table, we need to make a new one. */ /* If we don't already have an L3 table, we need to make a new one. */
if (!l2_entry->IsTable()) { if (!l2_entry->IsTable()) {
KPhysicalAddress new_table = AllocateNewPageTable(allocator); KPhysicalAddress new_table = AllocateNewPageTable(allocator);
ClearNewPageTable(new_table);
*l2_entry = L2PageTableEntry(PageTableEntry::TableTag{}, new_table, attr.IsPrivilegedExecuteNever()); *l2_entry = L2PageTableEntry(PageTableEntry::TableTag{}, new_table, attr.IsPrivilegedExecuteNever());
cpu::DataSynchronizationBarrierInnerShareable(); cpu::DataSynchronizationBarrierInnerShareable();
} }
@@ -395,12 +393,12 @@ namespace ams::kern::arch::arm64::init {
if (util::IsAligned(GetInteger(virt_addr), L3ContiguousBlockSize) && util::IsAligned(GetInteger(phys_addr), L3ContiguousBlockSize) && size >= L3ContiguousBlockSize) { if (util::IsAligned(GetInteger(virt_addr), L3ContiguousBlockSize) && util::IsAligned(GetInteger(phys_addr), L3ContiguousBlockSize) && size >= L3ContiguousBlockSize) {
for (size_t i = 0; i < L3ContiguousBlockSize / L3BlockSize; i++) { for (size_t i = 0; i < L3ContiguousBlockSize / L3BlockSize; i++) {
l3_entry[i] = L3PageTableEntry(PageTableEntry::BlockTag{}, phys_addr, attr, PageTableEntry::SoftwareReservedBit_None, true); l3_entry[i] = L3PageTableEntry(PageTableEntry::BlockTag{}, phys_addr, attr, PageTableEntry::SoftwareReservedBit_None, true);
cpu::DataSynchronizationBarrierInnerShareable();
virt_addr += L3BlockSize; virt_addr += L3BlockSize;
phys_addr += L3BlockSize; phys_addr += L3BlockSize;
size -= L3BlockSize; size -= L3BlockSize;
} }
cpu::DataSynchronizationBarrierInnerShareable();
continue; continue;
} }

View File

@@ -19,6 +19,9 @@
/* TODO: Different header for this? */ /* TODO: Different header for this? */
#define AMS_KERN_NUM_SUPERVISOR_CALLS 0xC0 #define AMS_KERN_NUM_SUPERVISOR_CALLS 0xC0
/* ams::kern::KThread, https://github.com/Atmosphere-NX/Atmosphere/blob/master/libraries/libmesosphere/include/mesosphere/kern_k_thread.hpp */
#define THREAD_THREAD_CONTEXT 0xD0
/* ams::kern::KThread::StackParameters, https://github.com/Atmosphere-NX/Atmosphere/blob/master/libraries/libmesosphere/include/mesosphere/kern_k_thread.hpp */ /* ams::kern::KThread::StackParameters, https://github.com/Atmosphere-NX/Atmosphere/blob/master/libraries/libmesosphere/include/mesosphere/kern_k_thread.hpp */
#define THREAD_STACK_PARAMETERS_SIZE 0x30 #define THREAD_STACK_PARAMETERS_SIZE 0x30
#define THREAD_STACK_PARAMETERS_SVC_PERMISSION 0x00 #define THREAD_STACK_PARAMETERS_SVC_PERMISSION 0x00

View File

@@ -60,6 +60,11 @@ namespace ams::kern::arch::arm64::cpu {
__asm__ __volatile__("isb" ::: "memory"); __asm__ __volatile__("isb" ::: "memory");
} }
ALWAYS_INLINE void EnsureInstructionConsistencyInnerShareable() {
DataSynchronizationBarrierInnerShareable();
InstructionMemoryBarrier();
}
ALWAYS_INLINE void EnsureInstructionConsistency() { ALWAYS_INLINE void EnsureInstructionConsistency() {
DataSynchronizationBarrier(); DataSynchronizationBarrier();
InstructionMemoryBarrier(); InstructionMemoryBarrier();
@@ -177,7 +182,6 @@ namespace ams::kern::arch::arm64::cpu {
NOINLINE void SynchronizeAllCores(); NOINLINE void SynchronizeAllCores();
/* Cache management helpers. */ /* Cache management helpers. */
void ClearPageToZeroImpl(void *);
void StoreEntireCacheForInit(); void StoreEntireCacheForInit();
void FlushEntireCacheForInit(); void FlushEntireCacheForInit();
@@ -190,10 +194,16 @@ namespace ams::kern::arch::arm64::cpu {
void InvalidateEntireInstructionCache(); void InvalidateEntireInstructionCache();
ALWAYS_INLINE void ClearPageToZero(void *page) { ALWAYS_INLINE void ClearPageToZero(void * const page) {
MESOSPHERE_ASSERT(util::IsAligned(reinterpret_cast<uintptr_t>(page), PageSize)); MESOSPHERE_ASSERT(util::IsAligned(reinterpret_cast<uintptr_t>(page), PageSize));
MESOSPHERE_ASSERT(page != nullptr); MESOSPHERE_ASSERT(page != nullptr);
ClearPageToZeroImpl(page);
uintptr_t cur = reinterpret_cast<uintptr_t>(__builtin_assume_aligned(page, PageSize));
const uintptr_t last = cur + PageSize - DataCacheLineSize;
for (/* ... */; cur <= last; cur += DataCacheLineSize) {
__asm__ __volatile__("dc zva, %[cur]" :: [cur]"r"(cur) : "memory");
}
} }
ALWAYS_INLINE void InvalidateTlbByAsid(u32 asid) { ALWAYS_INLINE void InvalidateTlbByAsid(u32 asid) {
@@ -213,6 +223,11 @@ namespace ams::kern::arch::arm64::cpu {
EnsureInstructionConsistency(); EnsureInstructionConsistency();
} }
ALWAYS_INLINE void InvalidateEntireTlbInnerShareable() {
__asm__ __volatile__("tlbi vmalle1is" ::: "memory");
EnsureInstructionConsistencyInnerShareable();
}
ALWAYS_INLINE void InvalidateEntireTlbDataOnly() { ALWAYS_INLINE void InvalidateEntireTlbDataOnly() {
__asm__ __volatile__("tlbi vmalle1is" ::: "memory"); __asm__ __volatile__("tlbi vmalle1is" ::: "memory");
DataSynchronizationBarrier(); DataSynchronizationBarrier();

View File

@@ -105,35 +105,48 @@ namespace ams::kern::arch::arm64 {
Result UnbindLocal(s32 irq); Result UnbindLocal(s32 irq);
Result ClearGlobal(s32 irq); Result ClearGlobal(s32 irq);
Result ClearLocal(s32 irq); Result ClearLocal(s32 irq);
public: private:
static ALWAYS_INLINE u32 DisableInterrupts() { [[nodiscard]] static ALWAYS_INLINE u32 GetInterruptsEnabledState() {
u64 intr_state; u64 intr_state;
__asm__ __volatile__("mrs %[intr_state], daif\n" __asm__ __volatile__("mrs %[intr_state], daif\n"
"msr daifset, #2" "ubfx %[intr_state], %[intr_state], #7, #1"
: [intr_state]"=r"(intr_state) : [intr_state]"=r"(intr_state)
:: "memory"); :: "memory");
return intr_state; return intr_state;
} }
public:
static ALWAYS_INLINE void EnableInterrupts() {
__asm__ __volatile__("msr daifclr, #2" ::: "memory");
}
static ALWAYS_INLINE u32 EnableInterrupts() { static ALWAYS_INLINE void DisableInterrupts() {
u64 intr_state; __asm__ __volatile__("msr daifset, #2" ::: "memory");
__asm__ __volatile__("mrs %[intr_state], daif\n" }
"msr daifclr, #2"
: [intr_state]"=r"(intr_state) [[nodiscard]] static ALWAYS_INLINE u32 GetInterruptsEnabledStateAndDisableInterrupts() {
:: "memory"); const auto intr_state = GetInterruptsEnabledState();
DisableInterrupts();
return intr_state;
}
[[nodiscard]] static ALWAYS_INLINE u32 GetInterruptsEnabledStateAndEnableInterrupts() {
const auto intr_state = GetInterruptsEnabledState();
EnableInterrupts();
return intr_state; return intr_state;
} }
static ALWAYS_INLINE void RestoreInterrupts(u32 intr_state) { static ALWAYS_INLINE void RestoreInterrupts(u32 intr_state) {
u64 cur_state; u64 tmp;
__asm__ __volatile__("mrs %[cur_state], daif" : [cur_state]"=r"(cur_state)); __asm__ __volatile__("mrs %[tmp], daif\n"
__asm__ __volatile__("msr daif, %[intr_state]" :: [intr_state]"r"((cur_state & ~0x80ul) | (intr_state & 0x80))); "bfi %[tmp], %[intr_state], #7, #1\n"
"msr daif, %[tmp]"
: [tmp]"=&r"(tmp)
: [intr_state]"r"(intr_state)
: "memory");
} }
static ALWAYS_INLINE bool AreInterruptsEnabled() { static ALWAYS_INLINE bool AreInterruptsEnabled() {
u64 intr_state; return GetInterruptsEnabledState() == 0;
__asm__ __volatile__("mrs %[intr_state], daif" : [intr_state]"=r"(intr_state));
return (intr_state & 0x80) == 0;
} }
}; };

View File

@@ -219,27 +219,27 @@ namespace ams::kern::arch::arm64 {
Result ChangePermissions(KProcessAddress virt_addr, size_t num_pages, PageTableEntry entry_template, DisableMergeAttribute disable_merge_attr, bool refresh_mapping, PageLinkedList *page_list, bool reuse_ll); Result ChangePermissions(KProcessAddress virt_addr, size_t num_pages, PageTableEntry entry_template, DisableMergeAttribute disable_merge_attr, bool refresh_mapping, PageLinkedList *page_list, bool reuse_ll);
static void PteDataSynchronizationBarrier() { static ALWAYS_INLINE void PteDataSynchronizationBarrier() {
cpu::DataSynchronizationBarrierInnerShareable(); cpu::DataSynchronizationBarrierInnerShareable();
} }
static void ClearPageTable(KVirtualAddress table) { static ALWAYS_INLINE void ClearPageTable(KVirtualAddress table) {
cpu::ClearPageToZero(GetVoidPointer(table)); cpu::ClearPageToZero(GetVoidPointer(table));
} }
void OnTableUpdated() const { ALWAYS_INLINE void OnTableUpdated() const {
cpu::InvalidateTlbByAsid(m_asid); cpu::InvalidateTlbByAsid(m_asid);
} }
void OnKernelTableUpdated() const { ALWAYS_INLINE void OnKernelTableUpdated() const {
cpu::InvalidateEntireTlbDataOnly(); cpu::InvalidateEntireTlbDataOnly();
} }
void OnKernelTableSinglePageUpdated(KProcessAddress virt_addr) const { ALWAYS_INLINE void OnKernelTableSinglePageUpdated(KProcessAddress virt_addr) const {
cpu::InvalidateTlbByVaDataOnly(virt_addr); cpu::InvalidateTlbByVaDataOnly(virt_addr);
} }
void NoteUpdated() const { ALWAYS_INLINE void NoteUpdated() const {
cpu::DataSynchronizationBarrier(); cpu::DataSynchronizationBarrier();
if (this->IsKernel()) { if (this->IsKernel()) {
@@ -249,7 +249,7 @@ namespace ams::kern::arch::arm64 {
} }
} }
void NoteSingleKernelPageUpdated(KProcessAddress virt_addr) const { ALWAYS_INLINE void NoteSingleKernelPageUpdated(KProcessAddress virt_addr) const {
MESOSPHERE_ASSERT(this->IsKernel()); MESOSPHERE_ASSERT(this->IsKernel());
cpu::DataSynchronizationBarrier(); cpu::DataSynchronizationBarrier();

View File

@@ -45,6 +45,7 @@ namespace ams::kern::arch::arm64 {
/* Select L1 cache. */ /* Select L1 cache. */
cpu::SetCsselrEl1(0); cpu::SetCsselrEl1(0);
cpu::InstructionMemoryBarrier();
/* Check that the L1 cache is not direct-mapped. */ /* Check that the L1 cache is not direct-mapped. */
return cpu::CacheSizeIdRegisterAccessor().GetAssociativity() != 0; return cpu::CacheSizeIdRegisterAccessor().GetAssociativity() != 0;

View File

@@ -46,7 +46,7 @@ namespace ams::kern {
return m_slab_heap->Allocate(m_page_allocator); return m_slab_heap->Allocate(m_page_allocator);
} }
void Free(T *t) const { ALWAYS_INLINE void Free(T *t) const {
m_slab_heap->Free(t); m_slab_heap->Free(t);
} }
}; };

View File

@@ -211,18 +211,6 @@ namespace ams::kern {
static consteval bool ValidateAssemblyOffsets(); static consteval bool ValidateAssemblyOffsets();
}; };
consteval bool KScheduler::ValidateAssemblyOffsets() {
static_assert(AMS_OFFSETOF(KScheduler, m_state.needs_scheduling) == KSCHEDULER_NEEDS_SCHEDULING);
static_assert(AMS_OFFSETOF(KScheduler, m_state.interrupt_task_runnable) == KSCHEDULER_INTERRUPT_TASK_RUNNABLE);
static_assert(AMS_OFFSETOF(KScheduler, m_state.highest_priority_thread) == KSCHEDULER_HIGHEST_PRIORITY_THREAD);
static_assert(AMS_OFFSETOF(KScheduler, m_state.idle_thread_stack) == KSCHEDULER_IDLE_THREAD_STACK);
static_assert(AMS_OFFSETOF(KScheduler, m_state.prev_thread) == KSCHEDULER_PREVIOUS_THREAD);
static_assert(AMS_OFFSETOF(KScheduler, m_state.interrupt_task_manager) == KSCHEDULER_INTERRUPT_TASK_MANAGER);
return true;
}
static_assert(KScheduler::ValidateAssemblyOffsets());
class KScopedSchedulerLock : KScopedLock<KScheduler::LockType> { class KScopedSchedulerLock : KScopedLock<KScheduler::LockType> {
public: public:
explicit ALWAYS_INLINE KScopedSchedulerLock() : KScopedLock(KScheduler::s_scheduler_lock) { /* ... */ } explicit ALWAYS_INLINE KScopedSchedulerLock() : KScopedLock(KScheduler::s_scheduler_lock) { /* ... */ }

View File

@@ -0,0 +1,43 @@
/*
* 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 <mesosphere/kern_common.hpp>
#include <mesosphere/kern_k_scheduler.hpp>
#include <mesosphere/kern_select_interrupt_manager.hpp>
namespace ams::kern {
/* NOTE: This header is included after all main headers. */
consteval bool KScheduler::ValidateAssemblyOffsets() {
static_assert(AMS_OFFSETOF(KScheduler, m_state.needs_scheduling) == KSCHEDULER_NEEDS_SCHEDULING);
static_assert(AMS_OFFSETOF(KScheduler, m_state.interrupt_task_runnable) == KSCHEDULER_INTERRUPT_TASK_RUNNABLE);
static_assert(AMS_OFFSETOF(KScheduler, m_state.highest_priority_thread) == KSCHEDULER_HIGHEST_PRIORITY_THREAD);
static_assert(AMS_OFFSETOF(KScheduler, m_state.idle_thread_stack) == KSCHEDULER_IDLE_THREAD_STACK);
static_assert(AMS_OFFSETOF(KScheduler, m_state.prev_thread) == KSCHEDULER_PREVIOUS_THREAD);
static_assert(AMS_OFFSETOF(KScheduler, m_state.interrupt_task_manager) == KSCHEDULER_INTERRUPT_TASK_MANAGER);
return true;
}
static_assert(KScheduler::ValidateAssemblyOffsets());
ALWAYS_INLINE void KScheduler::RescheduleOtherCores(u64 cores_needing_scheduling) {
if (const u64 core_mask = cores_needing_scheduling & ~(1ul << m_core_id); core_mask != 0) {
cpu::DataSynchronizationBarrier();
Kernel::GetInterruptManager().SendInterProcessorInterrupt(KInterruptName_Scheduler, core_mask);
}
}
}

View File

@@ -405,8 +405,6 @@ namespace ams::kern {
constexpr ThreadState GetState() const { return static_cast<ThreadState>(m_thread_state & ThreadState_Mask); } constexpr ThreadState GetState() const { return static_cast<ThreadState>(m_thread_state & ThreadState_Mask); }
constexpr ThreadState GetRawState() const { return m_thread_state; } constexpr ThreadState GetRawState() const { return m_thread_state; }
NOINLINE KThreadContext *GetContextForSchedulerLoop();
constexpr uintptr_t GetConditionVariableKey() const { return m_condvar_key; } constexpr uintptr_t GetConditionVariableKey() const { return m_condvar_key; }
constexpr uintptr_t GetAddressArbiterKey() const { return m_condvar_key; } constexpr uintptr_t GetAddressArbiterKey() const { return m_condvar_key; }
@@ -624,9 +622,7 @@ namespace ams::kern {
void OnTimer(); void OnTimer();
void DoWorkerTaskImpl(); void DoWorkerTaskImpl();
public: public:
static constexpr bool IsConditionVariableThreadTreeValid() { static consteval bool IsKThreadStructurallyValid();
return ConditionVariableThreadTreeTraits::IsValid();
}
static KThread *GetThreadFromId(u64 thread_id); static KThread *GetThreadFromId(u64 thread_id);
static Result GetThreadList(s32 *out_num_threads, ams::kern::svc::KUserPointer<u64 *> out_thread_ids, s32 max_out_count); static Result GetThreadList(s32 *out_num_threads, ams::kern::svc::KUserPointer<u64 *> out_thread_ids, s32 max_out_count);
@@ -634,7 +630,18 @@ namespace ams::kern {
using ConditionVariableThreadTreeType = ConditionVariableThreadTree; using ConditionVariableThreadTreeType = ConditionVariableThreadTree;
}; };
static_assert(alignof(KThread) == 0x10); static_assert(alignof(KThread) == 0x10);
static_assert(KThread::IsConditionVariableThreadTreeValid());
consteval bool KThread::IsKThreadStructurallyValid() {
/* Check that the condition variable tree is valid. */
static_assert(ConditionVariableThreadTreeTraits::IsValid());
/* Check that the assembly offsets are valid. */
static_assert(AMS_OFFSETOF(KThread, m_thread_context) == THREAD_THREAD_CONTEXT);
return true;
}
static_assert(KThread::IsKThreadStructurallyValid());
class KScopedDisableDispatch { class KScopedDisableDispatch {
public: public:

View File

@@ -41,7 +41,7 @@ namespace ams::kern {
private: private:
u32 m_prev_intr_state; u32 m_prev_intr_state;
public: public:
ALWAYS_INLINE KScopedInterruptDisable() : m_prev_intr_state(KInterruptManager::DisableInterrupts()) { /* ... */ } ALWAYS_INLINE KScopedInterruptDisable() : m_prev_intr_state(KInterruptManager::GetInterruptsEnabledStateAndDisableInterrupts()) { /* ... */ }
ALWAYS_INLINE ~KScopedInterruptDisable() { KInterruptManager::RestoreInterrupts(m_prev_intr_state); } ALWAYS_INLINE ~KScopedInterruptDisable() { KInterruptManager::RestoreInterrupts(m_prev_intr_state); }
}; };
@@ -51,7 +51,7 @@ namespace ams::kern {
private: private:
u32 m_prev_intr_state; u32 m_prev_intr_state;
public: public:
ALWAYS_INLINE KScopedInterruptEnable() : m_prev_intr_state(KInterruptManager::EnableInterrupts()) { /* ... */ } ALWAYS_INLINE KScopedInterruptEnable() : m_prev_intr_state(KInterruptManager::GetInterruptsEnabledStateAndEnableInterrupts()) { /* ... */ }
ALWAYS_INLINE ~KScopedInterruptEnable() { KInterruptManager::RestoreInterrupts(m_prev_intr_state); } ALWAYS_INLINE ~KScopedInterruptEnable() { KInterruptManager::RestoreInterrupts(m_prev_intr_state); }
}; };

View File

@@ -61,139 +61,3 @@ _ZN3ams4kern4arch5arm643cpu23SynchronizeAllCoresImplEPii:
5: 5:
stlr wzr, [x0] stlr wzr, [x0]
ret ret
/* ams::kern::arch::arm64::cpu::ClearPageToZero(void *) */
.section .text._ZN3ams4kern4arch5arm643cpu19ClearPageToZeroImplEPv, "ax", %progbits
.global _ZN3ams4kern4arch5arm643cpu19ClearPageToZeroImplEPv
.type _ZN3ams4kern4arch5arm643cpu19ClearPageToZeroImplEPv, %function
_ZN3ams4kern4arch5arm643cpu19ClearPageToZeroImplEPv:
/* Efficiently clear the page using dc zva. */
dc zva, x0
add x8, x0, #0x040
dc zva, x8
add x8, x0, #0x080
dc zva, x8
add x8, x0, #0x0c0
dc zva, x8
add x8, x0, #0x100
dc zva, x8
add x8, x0, #0x140
dc zva, x8
add x8, x0, #0x180
dc zva, x8
add x8, x0, #0x1c0
dc zva, x8
add x8, x0, #0x200
dc zva, x8
add x8, x0, #0x240
dc zva, x8
add x8, x0, #0x280
dc zva, x8
add x8, x0, #0x2c0
dc zva, x8
add x8, x0, #0x300
dc zva, x8
add x8, x0, #0x340
dc zva, x8
add x8, x0, #0x380
dc zva, x8
add x8, x0, #0x3c0
dc zva, x8
add x8, x0, #0x400
dc zva, x8
add x8, x0, #0x440
dc zva, x8
add x8, x0, #0x480
dc zva, x8
add x8, x0, #0x4c0
dc zva, x8
add x8, x0, #0x500
dc zva, x8
add x8, x0, #0x540
dc zva, x8
add x8, x0, #0x580
dc zva, x8
add x8, x0, #0x5c0
dc zva, x8
add x8, x0, #0x600
dc zva, x8
add x8, x0, #0x640
dc zva, x8
add x8, x0, #0x680
dc zva, x8
add x8, x0, #0x6c0
dc zva, x8
add x8, x0, #0x700
dc zva, x8
add x8, x0, #0x740
dc zva, x8
add x8, x0, #0x780
dc zva, x8
add x8, x0, #0x7c0
dc zva, x8
add x8, x0, #0x800
dc zva, x8
add x8, x0, #0x840
dc zva, x8
add x8, x0, #0x880
dc zva, x8
add x8, x0, #0x8c0
dc zva, x8
add x8, x0, #0x900
dc zva, x8
add x8, x0, #0x940
dc zva, x8
add x8, x0, #0x980
dc zva, x8
add x8, x0, #0x9c0
dc zva, x8
add x8, x0, #0xa00
dc zva, x8
add x8, x0, #0xa40
dc zva, x8
add x8, x0, #0xa80
dc zva, x8
add x8, x0, #0xac0
dc zva, x8
add x8, x0, #0xb00
dc zva, x8
add x8, x0, #0xb40
dc zva, x8
add x8, x0, #0xb80
dc zva, x8
add x8, x0, #0xbc0
dc zva, x8
add x8, x0, #0xc00
dc zva, x8
add x8, x0, #0xc40
dc zva, x8
add x8, x0, #0xc80
dc zva, x8
add x8, x0, #0xcc0
dc zva, x8
add x8, x0, #0xd00
dc zva, x8
add x8, x0, #0xd40
dc zva, x8
add x8, x0, #0xd80
dc zva, x8
add x8, x0, #0xdc0
dc zva, x8
add x8, x0, #0xe00
dc zva, x8
add x8, x0, #0xe40
dc zva, x8
add x8, x0, #0xe80
dc zva, x8
add x8, x0, #0xec0
dc zva, x8
add x8, x0, #0xf00
dc zva, x8
add x8, x0, #0xf40
dc zva, x8
add x8, x0, #0xf80
dc zva, x8
add x8, x0, #0xfc0
dc zva, x8
ret

View File

@@ -225,7 +225,7 @@ namespace ams::kern::arch::arm64 {
if (AMS_UNLIKELY(GetCurrentThread().IsSingleStep())) { if (AMS_UNLIKELY(GetCurrentThread().IsSingleStep())) {
GetCurrentThread().ClearSingleStep(); GetCurrentThread().ClearSingleStep();
cpu::MonitorDebugSystemControlRegisterAccessor().SetSoftwareStep(false).Store(); cpu::MonitorDebugSystemControlRegisterAccessor().SetSoftwareStep(false).Store();
cpu::EnsureInstructionConsistency(); cpu::InstructionMemoryBarrier();
} }
#endif #endif

View File

@@ -201,7 +201,7 @@ namespace ams::kern::arch::arm64 {
if (user_mode) { if (user_mode) {
KThread *cur_thread = GetCurrentThreadPointer(); KThread *cur_thread = GetCurrentThreadPointer();
if (cur_thread->IsTerminationRequested()) { if (cur_thread->IsTerminationRequested()) {
KScopedInterruptEnable ei; EnableInterrupts();
cur_thread->Exit(); cur_thread->Exit();
} }
} }
@@ -212,13 +212,14 @@ namespace ams::kern::arch::arm64 {
R_UNLESS(KInterruptController::IsGlobal(irq) || KInterruptController::IsLocal(irq), svc::ResultOutOfRange()); R_UNLESS(KInterruptController::IsGlobal(irq) || KInterruptController::IsLocal(irq), svc::ResultOutOfRange());
KScopedInterruptDisable di;
if (KInterruptController::IsGlobal(irq)) { if (KInterruptController::IsGlobal(irq)) {
KScopedInterruptDisable di;
KScopedSpinLock lk(this->GetGlobalInterruptLock()); KScopedSpinLock lk(this->GetGlobalInterruptLock());
return this->BindGlobal(handler, irq, core_id, priority, manual_clear, level); return this->BindGlobal(handler, irq, core_id, priority, manual_clear, level);
} else { } else {
MESOSPHERE_ASSERT(core_id == GetCurrentCoreId()); MESOSPHERE_ASSERT(core_id == GetCurrentCoreId());
KScopedInterruptDisable di;
return this->BindLocal(handler, irq, priority, manual_clear); return this->BindLocal(handler, irq, priority, manual_clear);
} }
} }
@@ -228,13 +229,16 @@ namespace ams::kern::arch::arm64 {
R_UNLESS(KInterruptController::IsGlobal(irq) || KInterruptController::IsLocal(irq), svc::ResultOutOfRange()); R_UNLESS(KInterruptController::IsGlobal(irq) || KInterruptController::IsLocal(irq), svc::ResultOutOfRange());
KScopedInterruptDisable di;
if (KInterruptController::IsGlobal(irq)) { if (KInterruptController::IsGlobal(irq)) {
KScopedInterruptDisable di;
KScopedSpinLock lk(this->GetGlobalInterruptLock()); KScopedSpinLock lk(this->GetGlobalInterruptLock());
return this->UnbindGlobal(irq); return this->UnbindGlobal(irq);
} else { } else {
MESOSPHERE_ASSERT(core_id == GetCurrentCoreId()); MESOSPHERE_ASSERT(core_id == GetCurrentCoreId());
KScopedInterruptDisable di;
return this->UnbindLocal(irq); return this->UnbindLocal(irq);
} }
} }
@@ -244,13 +248,15 @@ namespace ams::kern::arch::arm64 {
R_UNLESS(KInterruptController::IsGlobal(irq) || KInterruptController::IsLocal(irq), svc::ResultOutOfRange()); R_UNLESS(KInterruptController::IsGlobal(irq) || KInterruptController::IsLocal(irq), svc::ResultOutOfRange());
KScopedInterruptDisable di;
if (KInterruptController::IsGlobal(irq)) { if (KInterruptController::IsGlobal(irq)) {
KScopedInterruptDisable di;
KScopedSpinLock lk(this->GetGlobalInterruptLock()); KScopedSpinLock lk(this->GetGlobalInterruptLock());
return this->ClearGlobal(irq); return this->ClearGlobal(irq);
} else { } else {
MESOSPHERE_ASSERT(core_id == GetCurrentCoreId()); MESOSPHERE_ASSERT(core_id == GetCurrentCoreId());
KScopedInterruptDisable di;
return this->ClearLocal(irq); return this->ClearLocal(irq);
} }
} }

View File

@@ -169,10 +169,10 @@ namespace ams::kern::arch::arm64 {
m_manager = std::addressof(Kernel::GetSystemPageTableManager()); m_manager = std::addressof(Kernel::GetSystemPageTableManager());
/* Allocate a page for ttbr. */ /* Allocate a page for ttbr. */
/* NOTE: It is a postcondition of page table manager allocation that the page is all-zero. */
const u64 asid_tag = (static_cast<u64>(m_asid) << 48ul); const u64 asid_tag = (static_cast<u64>(m_asid) << 48ul);
const KVirtualAddress page = m_manager->Allocate(); const KVirtualAddress page = m_manager->Allocate();
MESOSPHERE_ASSERT(page != Null<KVirtualAddress>); MESOSPHERE_ASSERT(page != Null<KVirtualAddress>);
cpu::ClearPageToZero(GetVoidPointer(page));
m_ttbr = GetInteger(KPageTableBase::GetLinearMappedPhysicalAddress(page)) | asid_tag; m_ttbr = GetInteger(KPageTableBase::GetLinearMappedPhysicalAddress(page)) | asid_tag;
/* Initialize the base page table. */ /* Initialize the base page table. */
@@ -1058,7 +1058,7 @@ namespace ams::kern::arch::arm64 {
auto sw_reserved_bits = PageTableEntry::EncodeSoftwareReservedBits(head_entry->IsHeadMergeDisabled(), head_entry->IsHeadAndBodyMergeDisabled(), tail_entry->IsTailMergeDisabled()); auto sw_reserved_bits = PageTableEntry::EncodeSoftwareReservedBits(head_entry->IsHeadMergeDisabled(), head_entry->IsHeadAndBodyMergeDisabled(), tail_entry->IsTailMergeDisabled());
/* Merge! */ /* Merge! */
PteDataSynchronizationBarrier(); /* NOTE: As of 13.1.0, Nintendo does not do: PteDataSynchronizationBarrier(); */
*l1_entry = L1PageTableEntry(PageTableEntry::BlockTag{}, phys_addr, PageTableEntry(entry_template), sw_reserved_bits, false); *l1_entry = L1PageTableEntry(PageTableEntry::BlockTag{}, phys_addr, PageTableEntry(entry_template), sw_reserved_bits, false);
/* Note that we updated. */ /* Note that we updated. */

View File

@@ -28,7 +28,7 @@ _ZN3ams4kern3svc25CallReturnFromException64Ev:
stp x20, x21, [sp, #(EXCEPTION_CONTEXT_X20_X21)] stp x20, x21, [sp, #(EXCEPTION_CONTEXT_X20_X21)]
stp x22, x23, [sp, #(EXCEPTION_CONTEXT_X22_X23)] stp x22, x23, [sp, #(EXCEPTION_CONTEXT_X22_X23)]
stp x24, x25, [sp, #(EXCEPTION_CONTEXT_X24_X25)] stp x24, x25, [sp, #(EXCEPTION_CONTEXT_X24_X25)]
stp x26, x26, [sp, #(EXCEPTION_CONTEXT_X26_X27)] stp x26, x27, [sp, #(EXCEPTION_CONTEXT_X26_X27)]
stp x28, x29, [sp, #(EXCEPTION_CONTEXT_X28_X29)] stp x28, x29, [sp, #(EXCEPTION_CONTEXT_X28_X29)]
/* Call ams::kern::arch::arm64::ReturnFromException(result). */ /* Call ams::kern::arch::arm64::ReturnFromException(result). */

View File

@@ -50,10 +50,6 @@ _ZN3ams4kern3svc26CallSendSyncRequestLight64Ev:
.global _ZN3ams4kern3svc32CallSendSyncRequestLight64From32Ev .global _ZN3ams4kern3svc32CallSendSyncRequestLight64From32Ev
.type _ZN3ams4kern3svc32CallSendSyncRequestLight64From32Ev, %function .type _ZN3ams4kern3svc32CallSendSyncRequestLight64From32Ev, %function
_ZN3ams4kern3svc32CallSendSyncRequestLight64From32Ev: _ZN3ams4kern3svc32CallSendSyncRequestLight64From32Ev:
/* Load x4-x7 from where the svc handler stores them. */
ldp x4, x5, [sp, #(8 * 0)]
ldp x6, x7, [sp, #(8 * 2)]
/* Allocate space for the light ipc data. */ /* Allocate space for the light ipc data. */
sub sp, sp, #(4 * 8) sub sp, sp, #(4 * 8)
@@ -78,13 +74,8 @@ _ZN3ams4kern3svc32CallSendSyncRequestLight64From32Ev:
/* Free the stack space for the light ipc data. */ /* Free the stack space for the light ipc data. */
add sp, sp, #(4 * 8) add sp, sp, #(4 * 8)
/* Save x4-x7 to where the svc handler stores them. */
stp x4, x5, [sp, #(8 * 0)]
stp x6, x7, [sp, #(8 * 2)]
ret ret
/* ams::kern::svc::CallReplyAndReceiveLight64() */ /* ams::kern::svc::CallReplyAndReceiveLight64() */
.section .text._ZN3ams4kern3svc26CallReplyAndReceiveLight64Ev, "ax", %progbits .section .text._ZN3ams4kern3svc26CallReplyAndReceiveLight64Ev, "ax", %progbits
.global _ZN3ams4kern3svc26CallReplyAndReceiveLight64Ev .global _ZN3ams4kern3svc26CallReplyAndReceiveLight64Ev
@@ -121,10 +112,6 @@ _ZN3ams4kern3svc26CallReplyAndReceiveLight64Ev:
.global _ZN3ams4kern3svc32CallReplyAndReceiveLight64From32Ev .global _ZN3ams4kern3svc32CallReplyAndReceiveLight64From32Ev
.type _ZN3ams4kern3svc32CallReplyAndReceiveLight64From32Ev, %function .type _ZN3ams4kern3svc32CallReplyAndReceiveLight64From32Ev, %function
_ZN3ams4kern3svc32CallReplyAndReceiveLight64From32Ev: _ZN3ams4kern3svc32CallReplyAndReceiveLight64From32Ev:
/* Load x4-x7 from where the svc handler stores them. */
ldp x4, x5, [sp, #(8 * 0)]
ldp x6, x7, [sp, #(8 * 2)]
/* Allocate space for the light ipc data. */ /* Allocate space for the light ipc data. */
sub sp, sp, #(4 * 8) sub sp, sp, #(4 * 8)
@@ -149,8 +136,4 @@ _ZN3ams4kern3svc32CallReplyAndReceiveLight64From32Ev:
/* Free the stack space for the light ipc data. */ /* Free the stack space for the light ipc data. */
add sp, sp, #(4 * 8) add sp, sp, #(4 * 8)
/* Save x4-x7 to where the svc handler stores them. */
stp x4, x5, [sp, #(8 * 0)]
stp x6, x7, [sp, #(8 * 2)]
ret ret

View File

@@ -656,9 +656,8 @@ namespace ams::kern::board::nintendo::nx {
MESOSPHERE_ASSERT(IsValidPhysicalAddress(table_phys_addr)); MESOSPHERE_ASSERT(IsValidPhysicalAddress(table_phys_addr));
Kernel::GetSystemPageTableManager().Open(table_virt_addr, 1); Kernel::GetSystemPageTableManager().Open(table_virt_addr, 1);
/* Clear the page and save it. */ /* Save the page. Note that it is a pre-condition that the page is cleared, when allocated from the system page table manager. */
/* NOTE: Nintendo does not check the result of StoreDataCache. */ /* NOTE: Nintendo does not check the result of StoreDataCache. */
cpu::ClearPageToZero(GetVoidPointer(table_virt_addr));
cpu::StoreDataCache(GetVoidPointer(table_virt_addr), PageDirectorySize); cpu::StoreDataCache(GetVoidPointer(table_virt_addr), PageDirectorySize);
g_reserved_table_phys_addr = table_phys_addr; g_reserved_table_phys_addr = table_phys_addr;

View File

@@ -341,7 +341,9 @@ namespace ams::kern::board::nintendo::nx {
/* Restore pmu registers. */ /* Restore pmu registers. */
cpu::SetPmUserEnrEl0(0); cpu::SetPmUserEnrEl0(0);
cpu::PerformanceMonitorsControlRegisterAccessor().SetEventCounterReset(true).SetCycleCounterReset(true).Store(); cpu::PerformanceMonitorsControlRegisterAccessor(0).SetEventCounterReset(true).SetCycleCounterReset(true).Store();
cpu::EnsureInstructionConsistency();
cpu::SetPmOvsClrEl0(static_cast<u64>(static_cast<u32>(~u32()))); cpu::SetPmOvsClrEl0(static_cast<u64>(static_cast<u32>(~u32())));
cpu::SetPmIntEnClrEl1(static_cast<u64>(static_cast<u32>(~u32()))); cpu::SetPmIntEnClrEl1(static_cast<u64>(static_cast<u32>(~u32())));
cpu::SetPmCntEnClrEl0(static_cast<u64>(static_cast<u32>(~u32()))); cpu::SetPmCntEnClrEl0(static_cast<u64>(static_cast<u32>(~u32())));

View File

@@ -79,13 +79,6 @@ namespace ams::kern {
RescheduleCurrentCore(); RescheduleCurrentCore();
} }
void KScheduler::RescheduleOtherCores(u64 cores_needing_scheduling) {
if (const u64 core_mask = cores_needing_scheduling & ~(1ul << m_core_id); core_mask != 0) {
cpu::DataSynchronizationBarrier();
Kernel::GetInterruptManager().SendInterProcessorInterrupt(KInterruptName_Scheduler, core_mask);
}
}
u64 KScheduler::UpdateHighestPriorityThread(KThread *highest_thread) { u64 KScheduler::UpdateHighestPriorityThread(KThread *highest_thread) {
if (KThread *prev_highest_thread = m_state.highest_priority_thread; AMS_LIKELY(prev_highest_thread != highest_thread)) { if (KThread *prev_highest_thread = m_state.highest_priority_thread; AMS_LIKELY(prev_highest_thread != highest_thread)) {
if (AMS_LIKELY(prev_highest_thread != nullptr)) { if (AMS_LIKELY(prev_highest_thread != nullptr)) {
@@ -254,9 +247,24 @@ namespace ams::kern {
MESOSPHERE_KTRACE_THREAD_SWITCH(next_thread); MESOSPHERE_KTRACE_THREAD_SWITCH(next_thread);
#if defined(MESOSPHERE_ENABLE_HARDWARE_SINGLE_STEP)
/* Ensure the single-step bit in mdscr reflects the correct single-step state for the new thread. */
cpu::MonitorDebugSystemControlRegisterAccessor().SetSoftwareStep(next_thread->IsSingleStep()).Store();
#endif
/* Switch the current process, if we're switching processes. */ /* Switch the current process, if we're switching processes. */
if (KProcess *next_process = next_thread->GetOwnerProcess(); next_process != cur_process) { if (KProcess *next_process = next_thread->GetOwnerProcess(); next_process != cur_process) {
KProcess::Switch(cur_process, next_process); KProcess::Switch(cur_process, next_process);
} else {
/* The single-step bit set up above requires an instruction synchronization barrier, to ensure */
/* the state change takes before we actually perform a return which might break-to-step. */
/* KProcess::Switch performs an isb incidentally, and so when we're changing process we */
/* can piggy-back off of that isb to avoid unnecessarily emptying the pipeline twice. */
/* However, this means that when we're switching to thread in a different process, */
/* we must ensure that we still isb. In practice, gcc will deduplicate into a single isb. */
#if defined(MESOSPHERE_ENABLE_HARDWARE_SINGLE_STEP)
cpu::InstructionMemoryBarrier();
#endif
} }
/* Set the new thread. */ /* Set the new thread. */

View File

@@ -1315,10 +1315,6 @@ namespace ams::kern {
} }
} }
KThreadContext *KThread::GetContextForSchedulerLoop() {
return std::addressof(this->GetContext());
}
KThread *KThread::GetThreadFromId(u64 thread_id) { KThread *KThread::GetThreadFromId(u64 thread_id) {
/* Lock the list. */ /* Lock the list. */
KThread::ListAccessor accessor; KThread::ListAccessor accessor;

View File

@@ -89,9 +89,8 @@ namespace ams::fs {
Result DeleteSystemSaveData(SaveDataSpaceId space_id, SystemSaveDataId id, UserId user_id) { Result DeleteSystemSaveData(SaveDataSpaceId space_id, SystemSaveDataId id, UserId user_id) {
const auto attribute = SaveDataAttribute::Make(ncm::InvalidProgramId, SaveDataType::System, user_id, id); const auto attribute = SaveDataAttribute::Make(ncm::InvalidProgramId, SaveDataType::System, user_id, id);
/* TODO: Libnx binding for DeleteSaveDataFileSystemBySaveDataAttribute */ static_assert(sizeof(attribute) == sizeof(::FsSaveDataAttribute));
AMS_UNUSED(space_id, attribute); return fsDeleteSaveDataFileSystemBySaveDataAttribute(static_cast<::FsSaveDataSpaceId>(space_id), reinterpret_cast<const ::FsSaveDataAttribute *>(std::addressof(attribute)));
AMS_ABORT();
} }
Result GetSaveDataFlags(u32 *out, SaveDataId id) { Result GetSaveDataFlags(u32 *out, SaveDataId id) {

View File

@@ -20,6 +20,8 @@ extern "C" {
constinit u32 __nx_fs_num_sessions = 1; constinit u32 __nx_fs_num_sessions = 1;
constinit u32 __nx_applet_type = AppletType_None; constinit u32 __nx_applet_type = AppletType_None;
constinit bool __nx_fsdev_support_cwd = false;
extern int __system_argc; extern int __system_argc;
extern char** __system_argv; extern char** __system_argv;

View File

@@ -18,9 +18,9 @@
#include "sprofile_srv_i_profile_importer.hpp" #include "sprofile_srv_i_profile_importer.hpp"
#define AMS_SPROFILE_I_SPROFILE_SERVICE_FOR_BG_AGENT_INTERFACE_INFO(C, H) \ #define AMS_SPROFILE_I_SPROFILE_SERVICE_FOR_BG_AGENT_INTERFACE_INFO(C, H) \
AMS_SF_METHOD_INFO(C, H, 100, Result, OpenProfileImporter, (sf::Out<sf::SharedPointer<::ams::sprofile::IProfileImporter>> out), (out)) \ AMS_SF_METHOD_INFO(C, H, 100, Result, OpenProfileImporter, (sf::Out<sf::SharedPointer<::ams::sprofile::IProfileImporter>> out), (out)) \
AMS_SF_METHOD_INFO(C, H, 200, Result, GetMetadataEntryData, (sf::Out<u32> out_count, const sf::OutArray<sprofile::srv::ProfileMetadataEntryData> &out, const sprofile::srv::ProfileMetadataForImportMetadata &arg), (out_count, out, arg)) \ AMS_SF_METHOD_INFO(C, H, 200, Result, GetImportableProfileUrls, (sf::Out<u32> out_count, const sf::OutArray<sprofile::srv::ProfileUrl> &out, const sprofile::srv::ProfileMetadataForImportMetadata &arg), (out_count, out, arg)) \
AMS_SF_METHOD_INFO(C, H, 201, Result, IsUpdateNeeded, (sf::Out<bool> out, sprofile::Identifier revision_key), (out, revision_key)) \ AMS_SF_METHOD_INFO(C, H, 201, Result, IsUpdateNeeded, (sf::Out<bool> out, sprofile::Identifier revision_key), (out, revision_key)) \
AMS_SF_METHOD_INFO(C, H, 2000, Result, Reset, (), ()) AMS_SF_METHOD_INFO(C, H, 2000, Result, Reset, (), ())
AMS_SF_DEFINE_INTERFACE(ams::sprofile, ISprofileServiceForBgAgent, AMS_SPROFILE_I_SPROFILE_SERVICE_FOR_BG_AGENT_INTERFACE_INFO) AMS_SF_DEFINE_INTERFACE(ams::sprofile, ISprofileServiceForBgAgent, AMS_SPROFILE_I_SPROFILE_SERVICE_FOR_BG_AGENT_INTERFACE_INFO)

View File

@@ -26,6 +26,10 @@ namespace ams::sprofile::srv {
ProfileManager *m_manager; ProfileManager *m_manager;
public: public:
ProfileImporterImpl(ProfileManager *manager) : m_manager(manager) { /* ... */ } ProfileImporterImpl(ProfileManager *manager) : m_manager(manager) { /* ... */ }
~ProfileImporterImpl() {
m_manager->CloseProfileImporter();
}
public: public:
Result ImportProfile(const sprofile::srv::ProfileDataForImportData &import); Result ImportProfile(const sprofile::srv::ProfileDataForImportData &import);
Result Commit(); Result Commit();

View File

@@ -151,6 +151,16 @@ namespace ams::sprofile::srv {
return ResultSuccess(); return ResultSuccess();
} }
void ProfileManager::CloseProfileImporter() {
/* Acquire locks. */
std::scoped_lock lk1(m_profile_importer_mutex);
std::scoped_lock lk2(m_general_mutex);
std::scoped_lock lk3(m_fs_mutex);
/* Close our importer. */
m_profile_importer = util::nullopt;
}
Result ProfileManager::ImportProfile(const sprofile::srv::ProfileDataForImportData &import) { Result ProfileManager::ImportProfile(const sprofile::srv::ProfileDataForImportData &import) {
/* Acquire locks. */ /* Acquire locks. */
std::scoped_lock lk1(m_profile_importer_mutex); std::scoped_lock lk1(m_profile_importer_mutex);
@@ -165,6 +175,8 @@ namespace ams::sprofile::srv {
/* Check that the metadata we're importing has a valid hash. */ /* Check that the metadata we're importing has a valid hash. */
{ {
crypto::Md5Generator md5; crypto::Md5Generator md5;
md5.Initialize();
md5.Update(std::addressof(import.header), sizeof(import.header)); md5.Update(std::addressof(import.header), sizeof(import.header));
md5.Update(std::addressof(import.data), sizeof(import.data) - sizeof(import.data.entries[0]) * (util::size(import.data.entries) - std::min<size_t>(import.data.num_entries, util::size(import.data.entries)))); md5.Update(std::addressof(import.data), sizeof(import.data) - sizeof(import.data.entries[0]) * (util::size(import.data.entries) - std::min<size_t>(import.data.num_entries, util::size(import.data.entries))));
@@ -258,9 +270,11 @@ namespace ams::sprofile::srv {
/* Check that the metadata we're importing has a valid hash. */ /* Check that the metadata we're importing has a valid hash. */
{ {
crypto::Md5Generator md5; crypto::Md5Generator md5;
md5.Initialize();
md5.Update(std::addressof(import.header), sizeof(import.header)); md5.Update(std::addressof(import.header), sizeof(import.header));
md5.Update(std::addressof(import.metadata), sizeof(import.metadata)); md5.Update(std::addressof(import.metadata), sizeof(import.metadata));
md5.Update(std::addressof(import.entries), sizeof(import.entries[0]) * std::min<size_t>(import.metadata.num_entries, util::size(import.metadata.entries))); md5.Update(std::addressof(import.profile_urls), sizeof(import.profile_urls[0]) * std::min<size_t>(import.metadata.num_entries, util::size(import.metadata.entries)));
u8 hash[crypto::Md5Generator::HashSize]; u8 hash[crypto::Md5Generator::HashSize];
md5.GetHash(hash, sizeof(hash)); md5.GetHash(hash, sizeof(hash));

View File

@@ -50,6 +50,8 @@ namespace ams::sprofile::srv {
Result ResetSaveData(); Result ResetSaveData();
Result OpenProfileImporter(); Result OpenProfileImporter();
void CloseProfileImporter();
Result ImportProfile(const sprofile::srv::ProfileDataForImportData &data); Result ImportProfile(const sprofile::srv::ProfileDataForImportData &data);
Result Commit(); Result Commit();
Result ImportMetadata(const sprofile::srv::ProfileMetadataForImportMetadata &data); Result ImportMetadata(const sprofile::srv::ProfileMetadataForImportMetadata &data);

View File

@@ -34,7 +34,7 @@ namespace ams::sprofile::srv {
return ResultSuccess(); return ResultSuccess();
} }
Result ServiceForBgAgent::GetMetadataEntryData(sf::Out<u32> out_count, const sf::OutArray<sprofile::srv::ProfileMetadataEntryData> &out, const sprofile::srv::ProfileMetadataForImportMetadata &arg) { Result ServiceForBgAgent::GetImportableProfileUrls(sf::Out<u32> out_count, const sf::OutArray<sprofile::srv::ProfileUrl> &out, const sprofile::srv::ProfileMetadataForImportMetadata &arg) {
/* Check size. */ /* Check size. */
R_UNLESS(out.GetSize() >= arg.metadata.num_entries, sprofile::ResultInvalidArgument()); R_UNLESS(out.GetSize() >= arg.metadata.num_entries, sprofile::ResultInvalidArgument());
@@ -42,25 +42,31 @@ namespace ams::sprofile::srv {
sprofile::srv::ProfileMetadata primary_metadata; sprofile::srv::ProfileMetadata primary_metadata;
R_TRY_CATCH(m_profile_manager->LoadPrimaryMetadata(std::addressof(primary_metadata))) { R_TRY_CATCH(m_profile_manager->LoadPrimaryMetadata(std::addressof(primary_metadata))) {
R_CATCH(fs::ResultPathNotFound) { R_CATCH(fs::ResultPathNotFound) {
/* If we have no metadata, we can't get any entries. */ /* It's okay if we have no primary metadata -- this means that all profiles are importable. */
*out_count = 0; primary_metadata.num_entries = 0;
return ResultSuccess();
} }
} R_END_TRY_CATCH; } R_END_TRY_CATCH;
/* Copy matching entries. */ /* We want to return the set of profiles that can be imported, which is just the profiles we don't already have. */
u32 count = 0; u32 count = 0;
for (u32 i = 0; i < arg.metadata.num_entries; ++i) { for (u32 i = 0; i < arg.metadata.num_entries; ++i) {
const auto &arg_entry = arg.metadata.entries[i]; const auto &arg_entry = arg.metadata.entries[i];
/* Check if we have the entry. */
bool have_entry = false;
for (u32 j = 0; j < primary_metadata.num_entries; ++j) { for (u32 j = 0; j < primary_metadata.num_entries; ++j) {
const auto &pri_entry = primary_metadata.entries[j]; const auto &pri_entry = primary_metadata.entries[j];
if (pri_entry.identifier_0 == arg_entry.identifier_0 && pri_entry.identifier_1 == arg_entry.identifier_1) { if (pri_entry.identifier_0 == arg_entry.identifier_0 && pri_entry.identifier_1 == arg_entry.identifier_1) {
out[count++] = arg.entries[i]; have_entry = true;
break; break;
} }
} }
/* If we don't already have the entry, it's importable -- copy it out. */
if (!have_entry) {
out[count++] = arg.profile_urls[i];
}
} }
/* Set output count. */ /* Set output count. */
@@ -68,6 +74,7 @@ namespace ams::sprofile::srv {
return ResultSuccess(); return ResultSuccess();
} }
Result ServiceForBgAgent::IsUpdateNeeded(sf::Out<bool> out, Identifier revision_key) { Result ServiceForBgAgent::IsUpdateNeeded(sf::Out<bool> out, Identifier revision_key) {
/* Load primary metadata. */ /* Load primary metadata. */
bool loaded_metadata = true; bool loaded_metadata = true;

View File

@@ -29,7 +29,7 @@ namespace ams::sprofile::srv {
constexpr ServiceForBgAgent(MemoryResource *mr, ProfileManager *pm) : m_memory_resource(mr), m_profile_manager(pm) { /* ... */ } constexpr ServiceForBgAgent(MemoryResource *mr, ProfileManager *pm) : m_memory_resource(mr), m_profile_manager(pm) { /* ... */ }
public: public:
Result OpenProfileImporter(sf::Out<sf::SharedPointer<::ams::sprofile::IProfileImporter>> out); Result OpenProfileImporter(sf::Out<sf::SharedPointer<::ams::sprofile::IProfileImporter>> out);
Result GetMetadataEntryData(sf::Out<u32> out_count, const sf::OutArray<sprofile::srv::ProfileMetadataEntryData> &out, const sprofile::srv::ProfileMetadataForImportMetadata &arg); Result GetImportableProfileUrls(sf::Out<u32> out_count, const sf::OutArray<sprofile::srv::ProfileUrl> &out, const sprofile::srv::ProfileMetadataForImportMetadata &arg);
Result IsUpdateNeeded(sf::Out<bool> out, Identifier revision_key); Result IsUpdateNeeded(sf::Out<bool> out, Identifier revision_key);
Result Reset(); Result Reset();
}; };

View File

@@ -46,6 +46,10 @@ namespace ams::sprofile::srv {
static_assert(util::is_pod<ProfileDataEntry>::value); static_assert(util::is_pod<ProfileDataEntry>::value);
static_assert(sizeof(ProfileDataEntry) == 0x10); static_assert(sizeof(ProfileDataEntry) == 0x10);
static_assert(AMS_OFFSETOF(ProfileDataEntry, key) == 0x00);
static_assert(AMS_OFFSETOF(ProfileDataEntry, type) == 0x07);
static_assert(AMS_OFFSETOF(ProfileDataEntry, value_s64) == 0x08);
struct ProfileData { struct ProfileData {
u32 num_entries; u32 num_entries;
u8 unk_04[0x0C]; u8 unk_04[0x0C];
@@ -55,6 +59,11 @@ namespace ams::sprofile::srv {
static_assert(util::is_pod<ProfileData>::value); static_assert(util::is_pod<ProfileData>::value);
static_assert(sizeof(ProfileData) == 0x4000); static_assert(sizeof(ProfileData) == 0x4000);
static_assert(AMS_OFFSETOF(ProfileData, num_entries) == 0x00);
static_assert(AMS_OFFSETOF(ProfileData, unk_04) == 0x04);
static_assert(AMS_OFFSETOF(ProfileData, unk_10) == 0x10);
static_assert(AMS_OFFSETOF(ProfileData, entries) == 0x30);
struct ServiceProfile { struct ServiceProfile {
Identifier name; Identifier name;
ProfileData data; ProfileData data;
@@ -62,6 +71,9 @@ namespace ams::sprofile::srv {
static_assert(util::is_pod<ServiceProfile>::value); static_assert(util::is_pod<ServiceProfile>::value);
static_assert(sizeof(ServiceProfile) == 0x4008); static_assert(sizeof(ServiceProfile) == 0x4008);
static_assert(AMS_OFFSETOF(ServiceProfile, name) == 0x00);
static_assert(AMS_OFFSETOF(ServiceProfile, data) == 0x08);
struct ProfileDataForImportData : public sf::LargeData, public sf::PrefersMapAliasTransferMode { struct ProfileDataForImportData : public sf::LargeData, public sf::PrefersMapAliasTransferMode {
struct { struct {
Identifier identifier_0; Identifier identifier_0;
@@ -77,6 +89,11 @@ namespace ams::sprofile::srv {
static_assert(util::is_pod<ProfileDataForImportData>::value); static_assert(util::is_pod<ProfileDataForImportData>::value);
static_assert(sizeof(ProfileDataForImportData) == 0x4400); static_assert(sizeof(ProfileDataForImportData) == 0x4400);
static_assert(AMS_OFFSETOF(ProfileDataForImportData, header) == 0x00);
static_assert(AMS_OFFSETOF(ProfileDataForImportData, hash) == 0x30);
static_assert(AMS_OFFSETOF(ProfileDataForImportData, data) == 0x40);
static_assert(AMS_OFFSETOF(ProfileDataForImportData, unk_4040) == 0x4040);
struct ProfileMetadataEntry { struct ProfileMetadataEntry {
Identifier identifier_0; Identifier identifier_0;
Identifier identifier_1; Identifier identifier_1;
@@ -85,22 +102,34 @@ namespace ams::sprofile::srv {
static_assert(util::is_pod<ProfileMetadataEntry>::value); static_assert(util::is_pod<ProfileMetadataEntry>::value);
static_assert(sizeof(ProfileMetadataEntry) == 0x40); static_assert(sizeof(ProfileMetadataEntry) == 0x40);
struct ProfileMetadataEntryData : public sf::PrefersMapAliasTransferMode { static_assert(AMS_OFFSETOF(ProfileMetadataEntry, identifier_0) == 0x00);
u8 unk[0x100]; static_assert(AMS_OFFSETOF(ProfileMetadataEntry, identifier_1) == 0x07);
static_assert(AMS_OFFSETOF(ProfileMetadataEntry, unk_0E) == 0x0E);
struct ProfileUrl : public sf::PrefersMapAliasTransferMode {
char url[0x100];
}; };
static_assert(util::is_pod<ProfileMetadataEntryData>::value); static_assert(util::is_pod<ProfileUrl>::value);
static_assert(sizeof(ProfileMetadataEntryData) == 0x100); static_assert(sizeof(ProfileUrl) == 0x100);
struct ProfileMetadata { struct ProfileMetadata {
u32 num_entries; u32 num_entries;
u32 unk_04; u32 unk_04;
Identifier revision_key; Identifier revision_key;
u8 unk_0F[0x1];
u8 unk_10[0x30]; u8 unk_10[0x30];
ProfileMetadataEntry entries[50]; ProfileMetadataEntry entries[50];
}; };
static_assert(util::is_pod<ProfileMetadata>::value); static_assert(util::is_pod<ProfileMetadata>::value);
static_assert(sizeof(ProfileMetadata) == 0xCC0); static_assert(sizeof(ProfileMetadata) == 0xCC0);
static_assert(AMS_OFFSETOF(ProfileMetadata, num_entries) == 0x00);
static_assert(AMS_OFFSETOF(ProfileMetadata, unk_04) == 0x04);
static_assert(AMS_OFFSETOF(ProfileMetadata, revision_key) == 0x08);
static_assert(AMS_OFFSETOF(ProfileMetadata, unk_0F) == 0x0F);
static_assert(AMS_OFFSETOF(ProfileMetadata, unk_10) == 0x10);
static_assert(AMS_OFFSETOF(ProfileMetadata, entries) == 0x40);
struct ProfileMetadataForImportMetadata : public sf::LargeData, public sf::PrefersMapAliasTransferMode { struct ProfileMetadataForImportMetadata : public sf::LargeData, public sf::PrefersMapAliasTransferMode {
struct { struct {
u32 version; u32 version;
@@ -108,10 +137,16 @@ namespace ams::sprofile::srv {
} header; } header;
u8 hash[crypto::Md5Generator::HashSize]; u8 hash[crypto::Md5Generator::HashSize];
ProfileMetadata metadata; ProfileMetadata metadata;
ProfileMetadataEntryData entries[50]; ProfileUrl profile_urls[50];
u8 unk[0x8000 - 0x3EF0]; u8 unk_3EF0[0x8000 - 0x3EF0];
}; };
static_assert(util::is_pod<ProfileMetadataForImportMetadata>::value); static_assert(util::is_pod<ProfileMetadataForImportMetadata>::value);
static_assert(sizeof(ProfileMetadataForImportMetadata) == 0x8000); static_assert(sizeof(ProfileMetadataForImportMetadata) == 0x8000);
static_assert(AMS_OFFSETOF(ProfileMetadataForImportMetadata, header) == 0x00);
static_assert(AMS_OFFSETOF(ProfileMetadataForImportMetadata, hash) == 0x20);
static_assert(AMS_OFFSETOF(ProfileMetadataForImportMetadata, metadata) == 0x30);
static_assert(AMS_OFFSETOF(ProfileMetadataForImportMetadata, profile_urls) == 0xCF0);
static_assert(AMS_OFFSETOF(ProfileMetadataForImportMetadata, unk_3EF0) == 0x3EF0);
} }

View File

@@ -17,7 +17,7 @@
#define ATMOSPHERE_RELEASE_VERSION_MAJOR 1 #define ATMOSPHERE_RELEASE_VERSION_MAJOR 1
#define ATMOSPHERE_RELEASE_VERSION_MINOR 2 #define ATMOSPHERE_RELEASE_VERSION_MINOR 2
#define ATMOSPHERE_RELEASE_VERSION_MICRO 1 #define ATMOSPHERE_RELEASE_VERSION_MICRO 2
#define ATMOSPHERE_RELEASE_VERSION ATMOSPHERE_RELEASE_VERSION_MAJOR, ATMOSPHERE_RELEASE_VERSION_MINOR, ATMOSPHERE_RELEASE_VERSION_MICRO #define ATMOSPHERE_RELEASE_VERSION ATMOSPHERE_RELEASE_VERSION_MAJOR, ATMOSPHERE_RELEASE_VERSION_MINOR, ATMOSPHERE_RELEASE_VERSION_MICRO

View File

@@ -149,7 +149,7 @@ namespace ams::crypto::impl {
/* Copy in any leftover data. */ /* Copy in any leftover data. */
if (const auto left = size % BlockSize; left > 0) { if (const auto left = size % BlockSize; left > 0) {
std::memcpy(m_y, cur_block, size); std::memcpy(m_y, cur_block, left);
} }
} }

View File

@@ -49,10 +49,9 @@ namespace ams::kern::init {
constexpr PageTableEntry KernelRwDataUncachedAttribute(PageTableEntry::Permission_KernelRW, PageTableEntry::PageAttribute_NormalMemoryNotCacheable, PageTableEntry::Shareable_InnerShareable, PageTableEntry::MappingFlag_Mapped); constexpr PageTableEntry KernelRwDataUncachedAttribute(PageTableEntry::Permission_KernelRW, PageTableEntry::PageAttribute_NormalMemoryNotCacheable, PageTableEntry::Shareable_InnerShareable, PageTableEntry::MappingFlag_Mapped);
void StoreDataCache(const void *addr, size_t size) { void StoreDataCache(const void *addr, size_t size) {
uintptr_t start = util::AlignDown(reinterpret_cast<uintptr_t>(addr), cpu::DataCacheLineSize); const uintptr_t start = util::AlignDown(reinterpret_cast<uintptr_t>(addr), cpu::DataCacheLineSize);
uintptr_t end = reinterpret_cast<uintptr_t>(addr) + size; for (size_t stored = 0; stored < size; stored += cpu::DataCacheLineSize) {
for (uintptr_t cur = start; cur < end; cur += cpu::DataCacheLineSize) { __asm__ __volatile__("dc cvac, %[cur]" :: [cur]"r"(start + stored) : "memory");
__asm__ __volatile__("dc cvac, %[cur]" :: [cur]"r"(cur) : "memory");
} }
cpu::DataSynchronizationBarrier(); cpu::DataSynchronizationBarrier();
} }
@@ -594,11 +593,13 @@ namespace ams::kern::init {
switch (num_watchpoints) { switch (num_watchpoints) {
FOR_I_IN_15_TO_1(MESOSPHERE_INITIALIZE_WATCHPOINT_CASE, 0) FOR_I_IN_15_TO_1(MESOSPHERE_INITIALIZE_WATCHPOINT_CASE, 0)
case 0:
cpu::SetDbgWcr0El1(0);
cpu::SetDbgWvr0El1(0);
[[fallthrough]];
default: default:
break; break;
} }
cpu::SetDbgWcr0El1(0);
cpu::SetDbgWvr0El1(0);
switch (num_breakpoints) { switch (num_breakpoints) {
FOR_I_IN_15_TO_1(MESOSPHERE_INITIALIZE_BREAKPOINT_CASE, 0) FOR_I_IN_15_TO_1(MESOSPHERE_INITIALIZE_BREAKPOINT_CASE, 0)

View File

@@ -376,7 +376,7 @@ _ZN3ams4kern4arch5arm6430EL1SynchronousExceptionHandlerEv:
stp x26, x27, [sp, #(EXCEPTION_CONTEXT_X26_X27)] stp x26, x27, [sp, #(EXCEPTION_CONTEXT_X26_X27)]
stp x28, x29, [sp, #(EXCEPTION_CONTEXT_X28_X29)] stp x28, x29, [sp, #(EXCEPTION_CONTEXT_X28_X29)]
mrs x20, sp_el0 ldr x20, [sp]
mrs x21, elr_el1 mrs x21, elr_el1
mrs x22, spsr_el1 mrs x22, spsr_el1
mrs x23, tpidr_el0 mrs x23, tpidr_el0
@@ -529,7 +529,7 @@ _ZN3ams4kern4arch5arm6421EL1SystemErrorHandlerEv:
stp x26, x27, [sp, #(EXCEPTION_CONTEXT_X26_X27)] stp x26, x27, [sp, #(EXCEPTION_CONTEXT_X26_X27)]
stp x28, x29, [sp, #(EXCEPTION_CONTEXT_X28_X29)] stp x28, x29, [sp, #(EXCEPTION_CONTEXT_X28_X29)]
mrs x20, sp_el0 ldr x20, [sp]
mrs x21, elr_el1 mrs x21, elr_el1
mrs x22, spsr_el1 mrs x22, spsr_el1
mrs x23, tpidr_el0 mrs x23, tpidr_el0

View File

@@ -183,9 +183,7 @@ _ZN3ams4kern10KScheduler12ScheduleImplEv:
/* Get the highest priority thread's context, and save it. */ /* Get the highest priority thread's context, and save it. */
/* ams::kern::KThread::GetContextForSchedulerLoop() */ /* ams::kern::KThread::GetContextForSchedulerLoop() */
mov x0, x21 add x22, x21, #(THREAD_THREAD_CONTEXT)
bl _ZN3ams4kern7KThread26GetContextForSchedulerLoopEv
mov x22, x0
/* Prepare to try to acquire the context lock. */ /* Prepare to try to acquire the context lock. */
add x1, x22, #(THREAD_CONTEXT_LOCKED) add x1, x22, #(THREAD_CONTEXT_LOCKED)
@@ -227,26 +225,7 @@ _ZN3ams4kern10KScheduler12ScheduleImplEv:
mov x0, x22 mov x0, x22
RESTORE_THREAD_CONTEXT(x0, x1, x2, 9f) RESTORE_THREAD_CONTEXT(x0, x1, x2, 9f)
9: /* Configure single-step, if we should. */ 9: /* We're done restoring the thread context, and can return safely. */
#if defined(MESOSPHERE_ENABLE_HARDWARE_SINGLE_STEP)
/* Get a reference to the new thread's stack parameters. */
add x2, sp, #0x1000
and x2, x2, #~(0x1000-1)
/* Read the single-step flag. */
ldurb w2, [x2, #-(THREAD_STACK_PARAMETERS_SIZE - THREAD_STACK_PARAMETERS_IS_SINGLE_STEP)]
/* Update the single-step bit in mdscr_el1. */
mrs x1, mdscr_el1
bic x1, x1, #1
orr x1, x1, x2
msr mdscr_el1, x1
isb
#endif
/* We're done restoring the thread context, and can return safely. */
ret ret
10: /* Our switch failed. */ 10: /* Our switch failed. */