diff --git a/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_process_page_table.hpp b/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_process_page_table.hpp index 2df7f508b..ba5410e87 100644 --- a/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_process_page_table.hpp +++ b/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_process_page_table.hpp @@ -56,6 +56,10 @@ namespace ams::kern::arch::arm64 { return this->page_table.QueryInfo(out_info, out_page_info, addr); } + Result UnmapMemory(uintptr_t dst_address, uintptr_t src_address, size_t size) { + return this->page_table.UnmapMemory(dst_address, src_address, size); + } + Result MapIo(KPhysicalAddress phys_addr, size_t size, KMemoryPermission perm) { return this->page_table.MapIo(phys_addr, size, perm); } @@ -109,6 +113,8 @@ namespace ams::kern::arch::arm64 { size_t GetKernelMapRegionSize() const { return this->page_table.GetKernelMapRegionSize(); } size_t GetAliasCodeRegionSize() const { return this->page_table.GetAliasCodeRegionSize(); } + size_t GetNormalMemorySize() const { return this->page_table.GetNormalMemorySize(); } + KPhysicalAddress GetHeapPhysicalAddress(KVirtualAddress address) const { /* TODO: Better way to convert address type? */ return this->page_table.GetHeapPhysicalAddress(address); diff --git a/libraries/libmesosphere/include/mesosphere/board/nintendo/nx/kern_k_system_control.hpp b/libraries/libmesosphere/include/mesosphere/board/nintendo/nx/kern_k_system_control.hpp index 95372ca5f..569caf964 100644 --- a/libraries/libmesosphere/include/mesosphere/board/nintendo/nx/kern_k_system_control.hpp +++ b/libraries/libmesosphere/include/mesosphere/board/nintendo/nx/kern_k_system_control.hpp @@ -67,6 +67,9 @@ namespace ams::kern::board::nintendo::nx { /* User access. */ static void CallSecureMonitorFromUser(ams::svc::lp64::SecureMonitorArguments *args); + + /* Constant calculations. */ + static size_t CalculateRequiredSecureMemorySize(size_t size, u32 pool); }; } \ No newline at end of file diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_handle_table.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_handle_table.hpp index d6ba17cdc..38be0efc7 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_k_handle_table.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_k_handle_table.hpp @@ -147,7 +147,11 @@ namespace ams::kern { if constexpr (std::is_same::value) { return this->GetObjectImpl(handle); } else { - return this->GetObjectImpl(handle)->DynamicCast(); + if (auto *obj = this->GetObjectImpl(handle); obj != nullptr) { + return obj->DynamicCast(); + } else { + return nullptr; + } } } @@ -177,7 +181,11 @@ namespace ams::kern { if constexpr (std::is_same::value) { return obj; } else { - return obj->DynamicCast(); + if (auto *obj = this->GetObjectImpl(handle); obj != nullptr) { + return obj->DynamicCast(); + } else { + return nullptr; + } } } diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_memory_block.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_memory_block.hpp index 4cb1d5a7b..b9cf1a987 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_k_memory_block.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_k_memory_block.hpp @@ -170,6 +170,8 @@ namespace ams::kern { KMemoryAttribute_IpcLocked = ams::svc::MemoryAttribute_IpcLocked, KMemoryAttribute_DeviceShared = ams::svc::MemoryAttribute_DeviceShared, KMemoryAttribute_Uncached = ams::svc::MemoryAttribute_Uncached, + + KMemoryAttribute_AnyLocked = 0x80, }; struct KMemoryInfo { diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_page_table_base.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_page_table_base.hpp index 2298dd9dd..02e34c359 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_k_page_table_base.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_k_page_table_base.hpp @@ -52,7 +52,6 @@ namespace ams::kern { OperationType_Unmap = 2, OperationType_ChangePermissions = 3, OperationType_ChangePermissionsAndRefresh = 4, - /* TODO: perm/attr operations */ }; static constexpr size_t MaxPhysicalMapAlignment = 1_GB; @@ -134,7 +133,7 @@ namespace ams::kern { KProcessAddress code_region_start; KProcessAddress code_region_end; size_t max_heap_size; - size_t max_physical_memory_size; + size_t mapped_physical_memory_size; size_t mapped_unsafe_physical_memory; mutable KLightLock general_lock; mutable KLightLock map_physical_memory_lock; @@ -157,7 +156,7 @@ namespace ams::kern { address_space_start(), address_space_end(), heap_region_start(), heap_region_end(), current_heap_end(), alias_region_start(), alias_region_end(), stack_region_start(), stack_region_end(), kernel_map_region_start(), kernel_map_region_end(), alias_code_region_start(), alias_code_region_end(), code_region_start(), code_region_end(), - max_heap_size(), max_physical_memory_size(),mapped_unsafe_physical_memory(), general_lock(), map_physical_memory_lock(), + max_heap_size(), mapped_physical_memory_size(), mapped_unsafe_physical_memory(), general_lock(), map_physical_memory_lock(), impl(), memory_block_manager(), allocate_option(), address_space_width(), is_kernel(), enable_aslr(), memory_block_slab_manager(), block_info_manager(), cached_physical_linear_region(), cached_physical_heap_region(), cached_virtual_heap_region(), heap_fill_value(), ipc_fill_value(), stack_fill_value() @@ -251,6 +250,7 @@ namespace ams::kern { Result SetHeapSize(KProcessAddress *out, size_t size); Result SetMaxHeapSize(size_t size); Result QueryInfo(KMemoryInfo *out_info, ams::svc::PageInfo *out_page_info, KProcessAddress addr) const; + Result UnmapMemory(uintptr_t dst_address, uintptr_t src_address, size_t size); Result MapIo(KPhysicalAddress phys_addr, size_t size, KMemoryPermission perm); Result MapStatic(KPhysicalAddress phys_addr, size_t size, KMemoryPermission perm); Result MapRegion(KMemoryRegionType region_type, KMemoryPermission perm); @@ -287,6 +287,13 @@ namespace ams::kern { size_t GetStackRegionSize() const { return this->stack_region_end - this->stack_region_start; } size_t GetKernelMapRegionSize() const { return this->kernel_map_region_end - this->kernel_map_region_start; } size_t GetAliasCodeRegionSize() const { return this->alias_code_region_end - this->alias_code_region_start; } + + size_t GetNormalMemorySize() const { + /* Lock the table. */ + KScopedLightLock lk(this->general_lock); + + return this->GetHeapRegionSize() + this->mapped_physical_memory_size; + } public: static ALWAYS_INLINE KVirtualAddress GetLinearVirtualAddress(KPhysicalAddress addr) { return KMemoryLayout::GetLinearVirtualAddress(addr); diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_process.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_process.hpp index 897be0840..13f3fa802 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_k_process.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_k_process.hpp @@ -126,6 +126,8 @@ namespace ams::kern { constexpr const char *GetName() const { return this->name; } + constexpr ams::svc::ProgramId GetProgramId() const { return this->program_id; } + constexpr u64 GetProcessId() const { return this->process_id; } constexpr u64 GetCoreMask() const { return this->capabilities.GetCoreMask(); } @@ -163,9 +165,14 @@ namespace ams::kern { constexpr KHandleTable &GetHandleTable() { return this->handle_table; } constexpr const KHandleTable &GetHandleTable() const { return this->handle_table; } + size_t GetUsedNonSystemUserPhysicalMemorySize() const; + size_t GetTotalNonSystemUserPhysicalMemorySize() const; + Result CreateThreadLocalRegion(KProcessAddress *out); void *GetThreadLocalRegionPointer(KProcessAddress addr); + constexpr KProcessAddress GetProcessLocalRegionAddress() const { return this->plr_address; } + void AddCpuTime(s64 diff) { this->cpu_time += diff; } void IncrementScheduledCount() { ++this->schedule_count; } diff --git a/libraries/libmesosphere/source/arch/arm64/svc/kern_svc_tables.cpp b/libraries/libmesosphere/source/arch/arm64/svc/kern_svc_tables.cpp index 0455290e5..efec21e63 100644 --- a/libraries/libmesosphere/source/arch/arm64/svc/kern_svc_tables.cpp +++ b/libraries/libmesosphere/source/arch/arm64/svc/kern_svc_tables.cpp @@ -30,7 +30,7 @@ namespace ams::kern::svc { private: \ using Impl = ::ams::svc::codegen::KernelSvcWrapper<::ams::kern::svc::NAME##64, ::ams::kern::svc::NAME##64From32>; \ public: \ - static NOINLINE void Call64() { return Impl::Call64(); } \ + static NOINLINE void Call64() { return Impl::Call64(); } \ static NOINLINE void Call64From32() { return Impl::Call64From32(); } \ }; #else @@ -51,28 +51,45 @@ namespace ams::kern::svc { #pragma GCC pop_options + constexpr const std::array SvcTable64From32Impl = [] { + std::array table = {}; + + #define AMS_KERN_SVC_SET_TABLE_ENTRY(ID, RETURN_TYPE, NAME, ...) \ + table[ID] = NAME::Call64From32; + AMS_SVC_FOREACH_KERN_DEFINITION(AMS_KERN_SVC_SET_TABLE_ENTRY, _) + #undef AMS_KERN_SVC_SET_TABLE_ENTRY + + return table; + }(); + + constexpr const std::array SvcTable64Impl = [] { + std::array table = {}; + + #define AMS_KERN_SVC_SET_TABLE_ENTRY(ID, RETURN_TYPE, NAME, ...) \ + table[ID] = NAME::Call64; + AMS_SVC_FOREACH_KERN_DEFINITION(AMS_KERN_SVC_SET_TABLE_ENTRY, _) + #undef AMS_KERN_SVC_SET_TABLE_ENTRY + + return table; + }(); + + constexpr bool IsValidSvcTable(const std::array &table) { + for (size_t i = 0; i < NumSupervisorCalls; i++) { + if (table[i] != nullptr) { + return true; + } + } + + return false; + } + + static_assert(IsValidSvcTable(SvcTable64Impl)); + static_assert(IsValidSvcTable(SvcTable64From32Impl)); + } - const std::array SvcTable64From32 = [] { - std::array table = {}; + constinit const std::array SvcTable64 = SvcTable64Impl; - #define AMS_KERN_SVC_SET_TABLE_ENTRY(ID, RETURN_TYPE, NAME, ...) \ - table[ID] = NAME::Call64From32; - AMS_SVC_FOREACH_KERN_DEFINITION(AMS_KERN_SVC_SET_TABLE_ENTRY, _) - #undef AMS_KERN_SVC_SET_TABLE_ENTRY - - return table; - }(); - - const std::array SvcTable64 = [] { - std::array table = {}; - - #define AMS_KERN_SVC_SET_TABLE_ENTRY(ID, RETURN_TYPE, NAME, ...) \ - table[ID] = NAME::Call64; - AMS_SVC_FOREACH_KERN_DEFINITION(AMS_KERN_SVC_SET_TABLE_ENTRY, _) - #undef AMS_KERN_SVC_SET_TABLE_ENTRY - - return table; - }(); + constinit const std::array SvcTable64From32 = SvcTable64From32Impl; } diff --git a/libraries/libmesosphere/source/board/nintendo/nx/kern_k_system_control.cpp b/libraries/libmesosphere/source/board/nintendo/nx/kern_k_system_control.cpp index cdeb77909..e8835b43f 100644 --- a/libraries/libmesosphere/source/board/nintendo/nx/kern_k_system_control.cpp +++ b/libraries/libmesosphere/source/board/nintendo/nx/kern_k_system_control.cpp @@ -389,4 +389,12 @@ namespace ams::kern::board::nintendo::nx { } } + /* Constant calculations. */ + size_t KSystemControl::CalculateRequiredSecureMemorySize(size_t size, u32 pool) { + if (pool == KMemoryManager::Pool_Applet) { + return 0; + } + return size; + } + } \ No newline at end of file diff --git a/libraries/libmesosphere/source/kern_k_page_table_base.cpp b/libraries/libmesosphere/source/kern_k_page_table_base.cpp index d7f5701dd..c647129f6 100644 --- a/libraries/libmesosphere/source/kern_k_page_table_base.cpp +++ b/libraries/libmesosphere/source/kern_k_page_table_base.cpp @@ -40,7 +40,7 @@ namespace ams::kern { this->code_region_start = 0; this->code_region_end = 0; this->max_heap_size = 0; - this->max_physical_memory_size = 0; + this->mapped_physical_memory_size = 0; this->mapped_unsafe_physical_memory = 0; this->memory_block_slab_manager = std::addressof(Kernel::GetSystemMemoryBlockManager()); @@ -225,7 +225,7 @@ namespace ams::kern { /* Set heap and fill members. */ this->current_heap_end = this->heap_region_start; this->max_heap_size = 0; - this->max_physical_memory_size = 0; + this->mapped_physical_memory_size = 0; this->mapped_unsafe_physical_memory = 0; const bool fill_memory = KTargetSystem::IsDebugMemoryFillEnabled(); @@ -452,6 +452,68 @@ namespace ams::kern { return ResultSuccess(); } + Result KPageTableBase::UnmapMemory(uintptr_t dst_address, uintptr_t src_address, size_t size) { + /* Lock the table. */ + KScopedLightLock lk(this->general_lock); + + /* Validate that the source address's state is valid. */ + KMemoryState src_state; + R_TRY(this->CheckMemoryState(std::addressof(src_state), nullptr, nullptr, src_address, size, KMemoryState_FlagCanAlias, KMemoryState_FlagCanAlias, KMemoryPermission_All, KMemoryPermission_NotMapped | KMemoryPermission_KernelRead, KMemoryAttribute_All, KMemoryAttribute_AnyLocked | KMemoryAttribute_Locked)); + + /* Validate that the dst address's state is valid. */ + KMemoryPermission dst_perm; + R_TRY(this->CheckMemoryState(nullptr, std::addressof(dst_perm), nullptr, dst_address, size, KMemoryState_All, KMemoryState_Stack, KMemoryPermission_None, KMemoryPermission_None, KMemoryAttribute_All, KMemoryAttribute_None)); + + /* Create an update allocator for the source. */ + KMemoryBlockManagerUpdateAllocator src_allocator(this->memory_block_slab_manager); + R_TRY(src_allocator.GetResult()); + + /* Create an update allocator for the destination. */ + KMemoryBlockManagerUpdateAllocator dst_allocator(this->memory_block_slab_manager); + R_TRY(dst_allocator.GetResult()); + + /* Unmap the memory. */ + { + /* Determine the number of pages being operated on. */ + const size_t num_pages = size / PageSize; + + /* Create page groups for the memory being unmapped. */ + KPageGroup pg(this->block_info_manager); + + /* Create the page group representing the destination. */ + R_TRY(this->MakePageGroup(pg, dst_address, num_pages)); + + /* Ensure the page group is the valid for the source. */ + R_UNLESS(this->IsValidPageGroup(pg, src_address, num_pages), svc::ResultInvalidMemoryRegion()); + + /* We're going to perform an update, so create a helper. */ + KScopedPageTableUpdater updater(this); + + /* Unmap the aliased copy of the pages. */ + const KPageProperties dst_unmap_properties = { KMemoryPermission_None, false, false, false }; + R_TRY(this->Operate(updater.GetPageList(), dst_address, num_pages, Null, false, dst_unmap_properties, OperationType_Unmap, false)); + + /* Ensure that we re-map the aliased pages on failure. */ + auto remap_guard = SCOPE_GUARD { + const KPageProperties dst_remap_properties = { dst_perm, false, false, false }; + MESOSPHERE_R_ABORT_UNLESS(this->MapPageGroupImpl(updater.GetPageList(), dst_address, pg, dst_remap_properties, true)); + }; + + /* Try to set the permissions for the source pages back to what they should be. */ + const KPageProperties src_properties = { KMemoryPermission_UserReadWrite, false, false, false }; + R_TRY(this->Operate(updater.GetPageList(), src_address, num_pages, Null, false, src_properties, OperationType_ChangePermissions, false)); + + /* We successfully changed the permissions for the source pages, so we don't need to re-map the dst pages on failure. */ + remap_guard.Cancel(); + + /* Apply the memory block updates. */ + this->memory_block_manager.Update(std::addressof(src_allocator), src_address, num_pages, src_state, KMemoryPermission_UserReadWrite, KMemoryAttribute_None); + this->memory_block_manager.Update(std::addressof(dst_allocator), dst_address, num_pages, KMemoryState_None, KMemoryPermission_None, KMemoryAttribute_None); + } + + return ResultSuccess(); + } + KProcessAddress KPageTableBase::FindFreeArea(KProcessAddress region_start, size_t region_num_pages, size_t num_pages, size_t alignment, size_t offset, size_t guard_pages) const { KProcessAddress address = Null; diff --git a/libraries/libmesosphere/source/kern_k_process.cpp b/libraries/libmesosphere/source/kern_k_process.cpp index c3dc4320b..1268c1e4d 100644 --- a/libraries/libmesosphere/source/kern_k_process.cpp +++ b/libraries/libmesosphere/source/kern_k_process.cpp @@ -280,6 +280,28 @@ namespace ams::kern { this->thread_list.erase(this->thread_list.iterator_to(*thread)); } + size_t KProcess::GetUsedNonSystemUserPhysicalMemorySize() const { + const size_t norm_size = this->page_table.GetNormalMemorySize(); + const size_t other_size = this->code_size + this->main_thread_stack_size; + const size_t sec_size = KSystemControl::CalculateRequiredSecureMemorySize(this->system_resource_num_pages * PageSize, this->memory_pool); + + return norm_size + other_size + sec_size; + } + + size_t KProcess::GetTotalNonSystemUserPhysicalMemorySize() const { + /* Get the amount of free and used size. */ + const size_t free_size = this->resource_limit->GetFreeValue(ams::svc::LimitableResource_PhysicalMemoryMax); + const size_t used_size = this->GetUsedNonSystemUserPhysicalMemorySize(); + const size_t sec_size = KSystemControl::CalculateRequiredSecureMemorySize(this->system_resource_num_pages * PageSize, this->memory_pool); + const size_t max_size = this->max_process_memory; + + if (used_size + free_size > max_size) { + return max_size - sec_size; + } else { + return free_size + used_size - sec_size; + } + } + Result KProcess::Run(s32 priority, size_t stack_size) { MESOSPHERE_ASSERT_THIS(); diff --git a/libraries/libmesosphere/source/svc/kern_svc_info.cpp b/libraries/libmesosphere/source/svc/kern_svc_info.cpp index 84f330e3b..8f7a560e6 100644 --- a/libraries/libmesosphere/source/svc/kern_svc_info.cpp +++ b/libraries/libmesosphere/source/svc/kern_svc_info.cpp @@ -34,6 +34,10 @@ namespace ams::kern::svc { case ams::svc::InfoType_AslrRegionSize: case ams::svc::InfoType_StackRegionAddress: case ams::svc::InfoType_StackRegionSize: + case ams::svc::InfoType_ProgramId: + case ams::svc::InfoType_InitialProcessIdRange: + case ams::svc::InfoType_UserExceptionContextAddress: + case ams::svc::InfoType_TotalNonSystemMemorySize: { /* These info types don't support non-zero subtypes. */ R_UNLESS(info_subtype == 0, svc::ResultInvalidCombination()); @@ -67,6 +71,18 @@ namespace ams::kern::svc { case ams::svc::InfoType_StackRegionSize: *out = process->GetPageTable().GetStackRegionSize(); break; + case ams::svc::InfoType_ProgramId: + *out = process->GetProgramId(); + break; + case ams::svc::InfoType_InitialProcessIdRange: + /* TODO: Detect exactly 4.0.0 target firmware, do the right thing. */ + return svc::ResultInvalidEnumValue(); + case ams::svc::InfoType_UserExceptionContextAddress: + *out = GetInteger(process->GetProcessLocalRegionAddress()); + break; + case ams::svc::InfoType_TotalNonSystemMemorySize: + *out = process->GetTotalNonSystemUserPhysicalMemorySize(); + break; MESOSPHERE_UNREACHABLE_DEFAULT_CASE(); } } diff --git a/libraries/libmesosphere/source/svc/kern_svc_memory.cpp b/libraries/libmesosphere/source/svc/kern_svc_memory.cpp index a3770ddf5..3de08d0c8 100644 --- a/libraries/libmesosphere/source/svc/kern_svc_memory.cpp +++ b/libraries/libmesosphere/source/svc/kern_svc_memory.cpp @@ -21,7 +21,32 @@ namespace ams::kern::svc { namespace { + Result UnmapMemory(uintptr_t dst_address, uintptr_t src_address, size_t size) { + /* Log the call parameters for debugging. */ + MESOSPHERE_LOG("UnmapMemory(%zx, %zx, %zx)\n", dst_address, src_address, size); + /* Validate that addresses are page aligned. */ + R_UNLESS(util::IsAligned(dst_address, PageSize), svc::ResultInvalidAddress()); + R_UNLESS(util::IsAligned(src_address, PageSize), svc::ResultInvalidAddress()); + + /* Validate that size is positive and page aligned. */ + R_UNLESS(size > 0, svc::ResultInvalidSize()); + R_UNLESS(util::IsAligned(size, PageSize), svc::ResultInvalidSize()); + + /* Ensure that neither mapping overflows. */ + R_UNLESS(src_address < src_address + size, svc::ResultInvalidCurrentMemory()); + R_UNLESS(dst_address < dst_address + size, svc::ResultInvalidCurrentMemory()); + + /* Get the page table we're operating on. */ + auto &page_table = GetCurrentProcess().GetPageTable(); + + /* Ensure that the memory we're unmapping is in range. */ + R_UNLESS(page_table.Contains(src_address, size), svc::ResultInvalidCurrentMemory()); + R_UNLESS(page_table.CanContain(dst_address, size, KMemoryState_Stack), svc::ResultInvalidMemoryRegion()); + + /* Unmap the memory. */ + return page_table.UnmapMemory(dst_address, src_address, size); + } } @@ -40,7 +65,7 @@ namespace ams::kern::svc { } Result UnmapMemory64(ams::svc::Address dst_address, ams::svc::Address src_address, ams::svc::Size size) { - MESOSPHERE_PANIC("Stubbed SvcUnmapMemory64 was called."); + return UnmapMemory(dst_address, src_address, size); } /* ============================= 64From32 ABI ============================= */ @@ -58,7 +83,7 @@ namespace ams::kern::svc { } Result UnmapMemory64From32(ams::svc::Address dst_address, ams::svc::Address src_address, ams::svc::Size size) { - MESOSPHERE_PANIC("Stubbed SvcUnmapMemory64From32 was called."); + return UnmapMemory(dst_address, src_address, size); } } diff --git a/libraries/libvapours/include/vapours/svc/codegen/impl/svc_codegen_impl_kernel_svc_wrapper.hpp b/libraries/libvapours/include/vapours/svc/codegen/impl/svc_codegen_impl_kernel_svc_wrapper.hpp index 6872199b1..de6d25b32 100644 --- a/libraries/libvapours/include/vapours/svc/codegen/impl/svc_codegen_impl_kernel_svc_wrapper.hpp +++ b/libraries/libvapours/include/vapours/svc/codegen/impl/svc_codegen_impl_kernel_svc_wrapper.hpp @@ -514,7 +514,8 @@ namespace ams::svc::codegen::impl { private: using Traits = FunctionTraits; public: - using Impl = KernelSvcWrapperHelperImpl<_SvcAbiType, _UserAbiType, _KernelAbiType, typename Traits::ReturnType, typename Traits::ArgsType>; + using Impl = KernelSvcWrapperHelperImpl<_SvcAbiType, _UserAbiType, _KernelAbiType, typename Traits::ReturnType, typename Traits::ArgsType>; + using ReturnType = typename Traits::ReturnType; static constexpr bool IsAarch64Kernel = std::is_same<_KernelAbiType, Aarch64Lp64Abi>::value; static constexpr bool IsAarch32Kernel = std::is_same<_KernelAbiType, Aarch32Ilp32Abi>::value; @@ -525,17 +526,16 @@ namespace ams::svc::codegen::impl { static constexpr auto BeforeMetaCode = Impl::OptimizedBeforeMetaCode; static constexpr auto AfterMetaCode = Impl::OptimizedAfterMetaCode; - /* Set omit-frame-pointer to prevent GCC from emitting MOV X29, SP instructions. */ #pragma GCC push_options #pragma GCC optimize ("omit-frame-pointer") - static ALWAYS_INLINE void WrapSvcFunction() { + static ALWAYS_INLINE ReturnType WrapSvcFunction() { /* Generate appropriate assembly. */ GenerateCodeForMetaCode(); ON_SCOPE_EXIT { GenerateCodeForMetaCode(); }; - return reinterpret_cast(Function)(); + return reinterpret_cast(Function)(); } #pragma GCC pop_options diff --git a/libraries/libvapours/include/vapours/svc/codegen/svc_codegen_kernel_svc_wrapper.hpp b/libraries/libvapours/include/vapours/svc/codegen/svc_codegen_kernel_svc_wrapper.hpp index bce731284..aa650250d 100644 --- a/libraries/libvapours/include/vapours/svc/codegen/svc_codegen_kernel_svc_wrapper.hpp +++ b/libraries/libvapours/include/vapours/svc/codegen/svc_codegen_kernel_svc_wrapper.hpp @@ -20,7 +20,7 @@ namespace ams::svc::codegen { #if defined(ATMOSPHERE_ARCH_ARM64) || defined(ATMOSPHERE_ARCH_ARM) - template + template class KernelSvcWrapper { private: /* TODO: using Aarch32 = */ @@ -32,11 +32,22 @@ namespace ams::svc::codegen { #pragma GCC optimize ("omit-frame-pointer") static ALWAYS_INLINE void Call64() { - Aarch64::WrapSvcFunction(); + if constexpr (std::is_same::value) { + Aarch64::WrapSvcFunction(); + } else { + const auto &res = Aarch64::WrapSvcFunction(); + __asm__ __volatile__("" :: [res]"r"(res)); + } + } static ALWAYS_INLINE void Call64From32() { - Aarch64From32::WrapSvcFunction(); + if constexpr (std::is_same::value) { + Aarch64From32::WrapSvcFunction(); + } else { + const auto &res = Aarch64From32::WrapSvcFunction(); + __asm__ __volatile__("" :: [res]"r"(res)); + } } #pragma GCC pop_options