Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b9c90b9234 | ||
|
|
94e18b8c93 | ||
|
|
4e92687cab | ||
|
|
2a0b99d9f9 | ||
|
|
d1f3c4904b | ||
|
|
92321ccbc8 | ||
|
|
db3004e844 | ||
|
|
3e97e4addf | ||
|
|
4b7b33809f | ||
|
|
e81a1ce5a8 |
@@ -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.
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -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) { /* ... */ }
|
||||||
|
|||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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:
|
||||||
|
|||||||
@@ -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); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
|
||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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. */
|
||||||
|
|||||||
@@ -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). */
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
|
|||||||
@@ -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())));
|
||||||
|
|||||||
@@ -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. */
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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));
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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();
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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. */
|
||||||
|
|||||||
Reference in New Issue
Block a user