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 17a57ac62..ef38e8262 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 @@ -158,12 +158,12 @@ namespace ams::kern::arch::arm64 { R_RETURN(m_page_table.WriteDebugIoMemory(address, buffer, size)); } - Result LockForMapDeviceAddressSpace(KProcessAddress address, size_t size, KMemoryPermission perm, bool is_aligned) { - R_RETURN(m_page_table.LockForMapDeviceAddressSpace(address, size, perm, is_aligned)); + Result LockForMapDeviceAddressSpace(bool *out_is_io, KProcessAddress address, size_t size, KMemoryPermission perm, bool is_aligned, bool check_heap) { + R_RETURN(m_page_table.LockForMapDeviceAddressSpace(out_is_io, address, size, perm, is_aligned, check_heap)); } - Result LockForUnmapDeviceAddressSpace(KProcessAddress address, size_t size) { - R_RETURN(m_page_table.LockForUnmapDeviceAddressSpace(address, size)); + Result LockForUnmapDeviceAddressSpace(KProcessAddress address, size_t size, bool check_heap) { + R_RETURN(m_page_table.LockForUnmapDeviceAddressSpace(address, size, check_heap)); } Result UnlockForDeviceAddressSpace(KProcessAddress address, size_t size) { diff --git a/libraries/libmesosphere/include/mesosphere/board/generic/kern_k_device_page_table.hpp b/libraries/libmesosphere/include/mesosphere/board/generic/kern_k_device_page_table.hpp index 1a56fb3d8..662708ce9 100644 --- a/libraries/libmesosphere/include/mesosphere/board/generic/kern_k_device_page_table.hpp +++ b/libraries/libmesosphere/include/mesosphere/board/generic/kern_k_device_page_table.hpp @@ -44,8 +44,8 @@ namespace ams::kern::board::generic { R_THROW(ams::kern::svc::ResultNotImplemented()); } - Result ALWAYS_INLINE Map(KProcessPageTable *page_table, KProcessAddress process_address, size_t size, KDeviceVirtualAddress device_address, ams::svc::MemoryPermission device_perm, bool is_aligned) { - MESOSPHERE_UNUSED(page_table, process_address, size, device_address, device_perm, is_aligned); + Result ALWAYS_INLINE Map(KProcessPageTable *page_table, KProcessAddress process_address, size_t size, KDeviceVirtualAddress device_address, ams::svc::MemoryPermission device_perm, bool is_aligned, bool is_io) { + MESOSPHERE_UNUSED(page_table, process_address, size, device_address, device_perm, is_aligned, is_io); R_THROW(ams::kern::svc::ResultNotImplemented()); } diff --git a/libraries/libmesosphere/include/mesosphere/board/nintendo/nx/kern_k_device_page_table.hpp b/libraries/libmesosphere/include/mesosphere/board/nintendo/nx/kern_k_device_page_table.hpp index d5a8e9b3f..5cc4ba003 100644 --- a/libraries/libmesosphere/include/mesosphere/board/nintendo/nx/kern_k_device_page_table.hpp +++ b/libraries/libmesosphere/include/mesosphere/board/nintendo/nx/kern_k_device_page_table.hpp @@ -74,7 +74,7 @@ namespace ams::kern::board::nintendo::nx { Result Attach(ams::svc::DeviceName device_name, u64 space_address, u64 space_size); Result Detach(ams::svc::DeviceName device_name); - Result Map(KProcessPageTable *page_table, KProcessAddress process_address, size_t size, KDeviceVirtualAddress device_address, ams::svc::MemoryPermission device_perm, bool is_aligned); + Result Map(KProcessPageTable *page_table, KProcessAddress process_address, size_t size, KDeviceVirtualAddress device_address, ams::svc::MemoryPermission device_perm, bool is_aligned, bool is_io); Result Unmap(KProcessPageTable *page_table, KProcessAddress process_address, size_t size, KDeviceVirtualAddress device_address); void Unmap(KDeviceVirtualAddress device_address, size_t size) { diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_device_address_space.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_device_address_space.hpp index f80d32855..57766e6af 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_k_device_address_space.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_k_device_address_space.hpp @@ -41,17 +41,17 @@ namespace ams::kern { Result Attach(ams::svc::DeviceName device_name); Result Detach(ams::svc::DeviceName device_name); - Result MapByForce(KProcessPageTable *page_table, KProcessAddress process_address, size_t size, u64 device_address, ams::svc::MemoryPermission device_perm) { - R_RETURN(this->Map(page_table, process_address, size, device_address, device_perm, false)); + Result MapByForce(KProcessPageTable *page_table, KProcessAddress process_address, size_t size, u64 device_address, u32 option) { + R_RETURN(this->Map(page_table, process_address, size, device_address, option, false)); } - Result MapAligned(KProcessPageTable *page_table, KProcessAddress process_address, size_t size, u64 device_address, ams::svc::MemoryPermission device_perm) { - R_RETURN(this->Map(page_table, process_address, size, device_address, device_perm, true)); + Result MapAligned(KProcessPageTable *page_table, KProcessAddress process_address, size_t size, u64 device_address, u32 option) { + R_RETURN(this->Map(page_table, process_address, size, device_address, option, true)); } Result Unmap(KProcessPageTable *page_table, KProcessAddress process_address, size_t size, u64 device_address); private: - Result Map(KProcessPageTable *page_table, KProcessAddress process_address, size_t size, u64 device_address, ams::svc::MemoryPermission device_perm, bool is_aligned); + Result Map(KProcessPageTable *page_table, KProcessAddress process_address, size_t size, u64 device_address, u32 option, bool is_aligned); public: static void Initialize(); }; diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_memory_block.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_memory_block.hpp index 37fd444e4..c2d30753a 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_k_memory_block.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_k_memory_block.hpp @@ -63,7 +63,7 @@ namespace ams::kern { KMemoryState_Free = ams::svc::MemoryState_Free, - KMemoryState_Io = ams::svc::MemoryState_Io | KMemoryState_FlagMapped, + KMemoryState_Io = ams::svc::MemoryState_Io | KMemoryState_FlagMapped | KMemoryState_FlagCanDeviceMap | KMemoryState_FlagCanAlignedDeviceMap, KMemoryState_Static = ams::svc::MemoryState_Static | KMemoryState_FlagMapped | KMemoryState_FlagCanQueryPhysical, KMemoryState_Code = ams::svc::MemoryState_Code | KMemoryState_FlagsCode | KMemoryState_FlagCanMapProcess, KMemoryState_CodeData = ams::svc::MemoryState_CodeData | KMemoryState_FlagsData | KMemoryState_FlagCanMapProcess | KMemoryState_FlagCanCodeMemory, @@ -111,7 +111,7 @@ namespace ams::kern { #if 1 static_assert(KMemoryState_Free == 0x00000000); - static_assert(KMemoryState_Io == 0x00002001); + static_assert(KMemoryState_Io == 0x00182001); static_assert(KMemoryState_Static == 0x00042002); static_assert(KMemoryState_Code == 0x00DC7E03); static_assert(KMemoryState_CodeData == 0x03FEBD04); 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 ae37cdacb..912db722f 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_k_page_table_base.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_k_page_table_base.hpp @@ -393,8 +393,8 @@ namespace ams::kern { Result WriteDebugMemory(KProcessAddress address, const void *buffer, size_t size); Result WriteDebugIoMemory(KProcessAddress address, const void *buffer, size_t size); - Result LockForMapDeviceAddressSpace(KProcessAddress address, size_t size, KMemoryPermission perm, bool is_aligned); - Result LockForUnmapDeviceAddressSpace(KProcessAddress address, size_t size); + Result LockForMapDeviceAddressSpace(bool *out_is_io, KProcessAddress address, size_t size, KMemoryPermission perm, bool is_aligned, bool check_heap); + Result LockForUnmapDeviceAddressSpace(KProcessAddress address, size_t size, bool check_heap); Result UnlockForDeviceAddressSpace(KProcessAddress address, size_t size); Result UnlockForDeviceAddressSpacePartialMap(KProcessAddress address, size_t size); diff --git a/libraries/libmesosphere/source/board/nintendo/nx/kern_k_device_page_table.cpp b/libraries/libmesosphere/source/board/nintendo/nx/kern_k_device_page_table.cpp index 691b9f6a7..0f09886dc 100644 --- a/libraries/libmesosphere/source/board/nintendo/nx/kern_k_device_page_table.cpp +++ b/libraries/libmesosphere/source/board/nintendo/nx/kern_k_device_page_table.cpp @@ -1118,6 +1118,7 @@ namespace ams::kern::board::nintendo::nx { } Result KDevicePageTable::MapImpl(KProcessPageTable *page_table, KProcessAddress process_address, size_t size, KDeviceVirtualAddress device_address, ams::svc::MemoryPermission device_perm, bool is_aligned) { + /* Ensure that the region we're mapping to is free. */ R_UNLESS(this->IsFree(device_address, size), svc::ResultInvalidCurrentMemory()); @@ -1416,11 +1417,15 @@ namespace ams::kern::board::nintendo::nx { return true; } - Result KDevicePageTable::Map(KProcessPageTable *page_table, KProcessAddress process_address, size_t size, KDeviceVirtualAddress device_address, ams::svc::MemoryPermission device_perm, bool is_aligned) { + Result KDevicePageTable::Map(KProcessPageTable *page_table, KProcessAddress process_address, size_t size, KDeviceVirtualAddress device_address, ams::svc::MemoryPermission device_perm, bool is_aligned, bool is_io) { /* Validate address/size. */ MESOSPHERE_ASSERT((device_address & ~DeviceVirtualAddressMask) == 0); MESOSPHERE_ASSERT(((device_address + size - 1) & ~DeviceVirtualAddressMask) == 0); + /* IO is not supported on NX board. */ + MESOSPHERE_ASSERT(!is_io); + MESOSPHERE_UNUSED(is_io); + /* Map the pages. */ R_RETURN(this->MapImpl(page_table, process_address, size, device_address, device_perm, is_aligned)); } diff --git a/libraries/libmesosphere/source/kern_k_device_address_space.cpp b/libraries/libmesosphere/source/kern_k_device_address_space.cpp index 4afba0199..c275dc9c7 100644 --- a/libraries/libmesosphere/source/kern_k_device_address_space.cpp +++ b/libraries/libmesosphere/source/kern_k_device_address_space.cpp @@ -61,10 +61,21 @@ namespace ams::kern { R_RETURN(m_table.Detach(device_name)); } - Result KDeviceAddressSpace::Map(KProcessPageTable *page_table, KProcessAddress process_address, size_t size, u64 device_address, ams::svc::MemoryPermission device_perm, bool is_aligned) { + Result KDeviceAddressSpace::Map(KProcessPageTable *page_table, KProcessAddress process_address, size_t size, u64 device_address, u32 option, bool is_aligned) { /* Check that the address falls within the space. */ R_UNLESS((m_space_address <= device_address && device_address + size - 1 <= m_space_address + m_space_size - 1), svc::ResultInvalidCurrentMemory()); + /* Decode the option. */ + const util::BitPack32 option_pack = { option }; + const auto device_perm = option_pack.Get(); + const auto flags = option_pack.Get(); + const auto reserved = option_pack.Get(); + + /* Validate the option. */ + /* TODO: It is likely that this check for flags == none is only on NX board. */ + R_UNLESS(flags == ams::svc::MapDeviceAddressSpaceFlag_None, svc::ResultInvalidEnumValue()); + R_UNLESS(reserved == 0, svc::ResultInvalidEnumValue()); + /* Lock the address space. */ KScopedLightLock lk(m_lock); @@ -72,15 +83,21 @@ namespace ams::kern { KScopedLightLock pt_lk = page_table->AcquireDeviceMapLock(); /* Lock the pages. */ - R_TRY(page_table->LockForMapDeviceAddressSpace(process_address, size, ConvertToKMemoryPermission(device_perm), is_aligned)); + bool is_io{}; + R_TRY(page_table->LockForMapDeviceAddressSpace(std::addressof(is_io), process_address, size, ConvertToKMemoryPermission(device_perm), is_aligned, true)); /* Ensure that if we fail, we don't keep unmapped pages locked. */ ON_RESULT_FAILURE { MESOSPHERE_R_ABORT_UNLESS(page_table->UnlockForDeviceAddressSpace(process_address, size)); }; + /* Check that the io status is allowable. */ + if (is_io) { + R_UNLESS((flags & ams::svc::MapDeviceAddressSpaceFlag_NotIoRegister) == 0, svc::ResultInvalidCombination()); + } + /* Map the pages. */ { /* Perform the mapping. */ - R_TRY(m_table.Map(page_table, process_address, size, device_address, device_perm, is_aligned)); + R_TRY(m_table.Map(page_table, process_address, size, device_address, device_perm, is_aligned, is_io)); /* Ensure that we unmap the pages if we fail to update the protections. */ /* NOTE: Nintendo does not check the result of this unmap call. */ @@ -105,7 +122,7 @@ namespace ams::kern { KScopedLightLock pt_lk = page_table->AcquireDeviceMapLock(); /* Lock the pages. */ - R_TRY(page_table->LockForUnmapDeviceAddressSpace(process_address, size)); + R_TRY(page_table->LockForUnmapDeviceAddressSpace(process_address, size, true)); /* Unmap the pages. */ { diff --git a/libraries/libmesosphere/source/kern_k_page_table_base.cpp b/libraries/libmesosphere/source/kern_k_page_table_base.cpp index 2b1de2495..92de9b860 100644 --- a/libraries/libmesosphere/source/kern_k_page_table_base.cpp +++ b/libraries/libmesosphere/source/kern_k_page_table_base.cpp @@ -1384,11 +1384,8 @@ namespace ams::kern { TraversalEntry cur_entry = { .phys_addr = Null, .block_size = 0, .sw_reserved_bits = 0 }; R_UNLESS(impl.BeginTraversal(std::addressof(cur_entry), std::addressof(context), address), svc::ResultInvalidCurrentMemory()); - /* The region we're traversing has to be heap. */ - const KPhysicalAddress phys_address = cur_entry.phys_addr; - R_UNLESS(this->IsHeapPhysicalAddress(phys_address), svc::ResultInvalidCurrentMemory()); - /* Traverse until we have enough size or we aren't contiguous any more. */ + const KPhysicalAddress phys_address = cur_entry.phys_addr; size_t contig_size; for (contig_size = cur_entry.block_size - (GetInteger(phys_address) & (cur_entry.block_size - 1)); contig_size < size; contig_size += cur_entry.block_size) { if (!impl.ContinueTraversal(std::addressof(cur_entry), std::addressof(context))) { @@ -1402,11 +1399,11 @@ namespace ams::kern { /* Take the minimum size for our region. */ size = std::min(size, contig_size); - /* Check that the memory is contiguous. */ - R_TRY(this->CheckMemoryStateContiguous(address, size, - state_mask | KMemoryState_FlagReferenceCounted, state | KMemoryState_FlagReferenceCounted, - perm_mask, perm, - attr_mask, attr)); + /* Check that the memory is contiguous (modulo the reference count bit). */ + const u32 test_state_mask = state_mask | KMemoryState_FlagReferenceCounted; + if (R_FAILED(this->CheckMemoryStateContiguous(address, size, test_state_mask, state | KMemoryState_FlagReferenceCounted, perm_mask, perm, attr_mask, attr))) { + R_TRY(this->CheckMemoryStateContiguous(address, size, test_state_mask, state, perm_mask, perm, attr_mask, attr)); + } /* The memory is contiguous, so set the output range. */ *out = { @@ -1913,7 +1910,7 @@ namespace ams::kern { R_TRY(this->Operate(updater.GetPageList(), dst_address, num_pages, phys_addr, true, properties, OperationType_Map, false)); /* Update the blocks. */ - m_memory_block_manager.Update(std::addressof(allocator), dst_address, num_pages, KMemoryState_Io, perm, KMemoryAttribute_None, KMemoryBlockDisableMergeAttribute_Normal, KMemoryBlockDisableMergeAttribute_None); + m_memory_block_manager.Update(std::addressof(allocator), dst_address, num_pages, KMemoryState_Io, perm, KMemoryAttribute_Locked, KMemoryBlockDisableMergeAttribute_Normal, KMemoryBlockDisableMergeAttribute_None); /* We successfully mapped the pages. */ R_SUCCEED(); @@ -1927,7 +1924,7 @@ namespace ams::kern { /* Validate the memory state. */ size_t num_allocator_blocks; - R_TRY(this->CheckMemoryState(std::addressof(num_allocator_blocks), dst_address, size, KMemoryState_All, KMemoryState_Io, KMemoryPermission_None, KMemoryPermission_None, KMemoryAttribute_All, KMemoryAttribute_None)); + R_TRY(this->CheckMemoryState(std::addressof(num_allocator_blocks), dst_address, size, KMemoryState_All, KMemoryState_Io, KMemoryPermission_None, KMemoryPermission_None, KMemoryAttribute_All, KMemoryAttribute_Locked)); /* Validate that the region being unmapped corresponds to the physical range described. */ { @@ -2687,7 +2684,7 @@ namespace ams::kern { R_SUCCEED(); } - Result KPageTableBase::LockForMapDeviceAddressSpace(KProcessAddress address, size_t size, KMemoryPermission perm, bool is_aligned) { + Result KPageTableBase::LockForMapDeviceAddressSpace(bool *out_is_io, KProcessAddress address, size_t size, KMemoryPermission perm, bool is_aligned, bool check_heap) { /* Lightly validate the range before doing anything else. */ const size_t num_pages = size / PageSize; R_UNLESS(this->Contains(address, size), svc::ResultInvalidCurrentMemory()); @@ -2696,9 +2693,10 @@ namespace ams::kern { KScopedLightLock lk(m_general_lock); /* Check the memory state. */ - const u32 test_state = (is_aligned ? KMemoryState_FlagCanAlignedDeviceMap : KMemoryState_FlagCanDeviceMap); + const u32 test_state = (is_aligned ? KMemoryState_FlagCanAlignedDeviceMap : KMemoryState_FlagCanDeviceMap) | (check_heap ? KMemoryState_FlagReferenceCounted : KMemoryState_None); size_t num_allocator_blocks; - R_TRY(this->CheckMemoryState(std::addressof(num_allocator_blocks), address, size, test_state, test_state, perm, perm, KMemoryAttribute_IpcLocked | KMemoryAttribute_Locked, KMemoryAttribute_None, KMemoryAttribute_DeviceShared)); + KMemoryState old_state; + R_TRY(this->CheckMemoryState(std::addressof(old_state), nullptr, nullptr, std::addressof(num_allocator_blocks), address, size, test_state, test_state, perm, perm, KMemoryAttribute_IpcLocked | KMemoryAttribute_Locked, KMemoryAttribute_None, KMemoryAttribute_DeviceShared)); /* Create an update allocator. */ Result allocator_result; @@ -2708,10 +2706,13 @@ namespace ams::kern { /* Update the memory blocks. */ m_memory_block_manager.UpdateLock(std::addressof(allocator), address, num_pages, &KMemoryBlock::ShareToDevice, KMemoryPermission_None); + /* Set whether the locked memory was io. */ + *out_is_io = old_state == KMemoryState_Io; + R_SUCCEED(); } - Result KPageTableBase::LockForUnmapDeviceAddressSpace(KProcessAddress address, size_t size) { + Result KPageTableBase::LockForUnmapDeviceAddressSpace(KProcessAddress address, size_t size, bool check_heap) { /* Lightly validate the range before doing anything else. */ const size_t num_pages = size / PageSize; R_UNLESS(this->Contains(address, size), svc::ResultInvalidCurrentMemory()); @@ -2720,10 +2721,11 @@ namespace ams::kern { KScopedLightLock lk(m_general_lock); /* Check the memory state. */ + const u32 test_state = KMemoryState_FlagCanDeviceMap | (check_heap ? KMemoryState_FlagReferenceCounted : KMemoryState_None); size_t num_allocator_blocks; R_TRY(this->CheckMemoryStateContiguous(std::addressof(num_allocator_blocks), address, size, - KMemoryState_FlagReferenceCounted | KMemoryState_FlagCanDeviceMap, KMemoryState_FlagReferenceCounted | KMemoryState_FlagCanDeviceMap, + test_state, test_state, KMemoryPermission_None, KMemoryPermission_None, KMemoryAttribute_DeviceShared | KMemoryAttribute_Locked, KMemoryAttribute_DeviceShared)); @@ -2798,7 +2800,7 @@ namespace ams::kern { KScopedLightLock lk(m_general_lock); /* Get the range. */ - const u32 test_state = KMemoryState_FlagReferenceCounted | (is_aligned ? KMemoryState_FlagCanAlignedDeviceMap : KMemoryState_FlagCanDeviceMap); + const u32 test_state = (is_aligned ? KMemoryState_FlagCanAlignedDeviceMap : KMemoryState_FlagCanDeviceMap); R_TRY(this->GetContiguousMemoryRangeWithState(out, address, size, test_state, test_state, diff --git a/libraries/libmesosphere/source/svc/kern_svc_device_address_space.cpp b/libraries/libmesosphere/source/svc/kern_svc_device_address_space.cpp index 2fec8f923..55f3c2ace 100644 --- a/libraries/libmesosphere/source/svc/kern_svc_device_address_space.cpp +++ b/libraries/libmesosphere/source/svc/kern_svc_device_address_space.cpp @@ -80,7 +80,12 @@ namespace ams::kern::svc { } } - Result MapDeviceAddressSpaceByForce(ams::svc::Handle das_handle, ams::svc::Handle process_handle, uint64_t process_address, size_t size, uint64_t device_address, ams::svc::MemoryPermission device_perm) { + Result MapDeviceAddressSpaceByForce(ams::svc::Handle das_handle, ams::svc::Handle process_handle, uint64_t process_address, size_t size, uint64_t device_address, u32 option) { + /* Decode the option. */ + const util::BitPack32 option_pack = { option }; + const auto device_perm = option_pack.Get(); + const auto reserved = option_pack.Get(); + /* Validate input. */ R_UNLESS(util::IsAligned(process_address, PageSize), svc::ResultInvalidAddress()); R_UNLESS(util::IsAligned(device_address, PageSize), svc::ResultInvalidAddress()); @@ -90,6 +95,7 @@ namespace ams::kern::svc { R_UNLESS((device_address < device_address + size), svc::ResultInvalidMemoryRegion()); R_UNLESS((process_address == static_cast(process_address)), svc::ResultInvalidCurrentMemory()); R_UNLESS(IsValidDeviceMemoryPermission(device_perm), svc::ResultInvalidNewMemoryPermission()); + R_UNLESS(reserved == 0, svc::ResultInvalidEnumValue()); /* Get the device address space. */ KScopedAutoObject das = GetCurrentProcess().GetHandleTable().GetObject(das_handle); @@ -104,10 +110,15 @@ namespace ams::kern::svc { R_UNLESS(page_table.Contains(process_address, size), svc::ResultInvalidCurrentMemory()); /* Map. */ - R_RETURN(das->MapByForce(std::addressof(page_table), KProcessAddress(process_address), size, device_address, device_perm)); + R_RETURN(das->MapByForce(std::addressof(page_table), KProcessAddress(process_address), size, device_address, option)); } - Result MapDeviceAddressSpaceAligned(ams::svc::Handle das_handle, ams::svc::Handle process_handle, uint64_t process_address, size_t size, uint64_t device_address, ams::svc::MemoryPermission device_perm) { + Result MapDeviceAddressSpaceAligned(ams::svc::Handle das_handle, ams::svc::Handle process_handle, uint64_t process_address, size_t size, uint64_t device_address, u32 option) { + /* Decode the option. */ + const util::BitPack32 option_pack = { option }; + const auto device_perm = option_pack.Get(); + const auto reserved = option_pack.Get(); + /* Validate input. */ R_UNLESS(util::IsAligned(process_address, PageSize), svc::ResultInvalidAddress()); R_UNLESS(util::IsAligned(device_address, PageSize), svc::ResultInvalidAddress()); @@ -118,6 +129,7 @@ namespace ams::kern::svc { R_UNLESS((device_address < device_address + size), svc::ResultInvalidMemoryRegion()); R_UNLESS((process_address == static_cast(process_address)), svc::ResultInvalidCurrentMemory()); R_UNLESS(IsValidDeviceMemoryPermission(device_perm), svc::ResultInvalidNewMemoryPermission()); + R_UNLESS(reserved == 0, svc::ResultInvalidEnumValue()); /* Get the device address space. */ KScopedAutoObject das = GetCurrentProcess().GetHandleTable().GetObject(das_handle); @@ -132,7 +144,7 @@ namespace ams::kern::svc { R_UNLESS(page_table.Contains(process_address, size), svc::ResultInvalidCurrentMemory()); /* Map. */ - R_RETURN(das->MapAligned(std::addressof(page_table), KProcessAddress(process_address), size, device_address, device_perm)); + R_RETURN(das->MapAligned(std::addressof(page_table), KProcessAddress(process_address), size, device_address, option)); } Result UnmapDeviceAddressSpace(ams::svc::Handle das_handle, ams::svc::Handle process_handle, uint64_t process_address, size_t size, uint64_t device_address) { @@ -176,12 +188,12 @@ namespace ams::kern::svc { R_RETURN(DetachDeviceAddressSpace(device_name, das_handle)); } - Result MapDeviceAddressSpaceByForce64(ams::svc::Handle das_handle, ams::svc::Handle process_handle, uint64_t process_address, ams::svc::Size size, uint64_t device_address, ams::svc::MemoryPermission device_perm) { - R_RETURN(MapDeviceAddressSpaceByForce(das_handle, process_handle, process_address, size, device_address, device_perm)); + Result MapDeviceAddressSpaceByForce64(ams::svc::Handle das_handle, ams::svc::Handle process_handle, uint64_t process_address, ams::svc::Size size, uint64_t device_address, u32 option) { + R_RETURN(MapDeviceAddressSpaceByForce(das_handle, process_handle, process_address, size, device_address, option)); } - Result MapDeviceAddressSpaceAligned64(ams::svc::Handle das_handle, ams::svc::Handle process_handle, uint64_t process_address, ams::svc::Size size, uint64_t device_address, ams::svc::MemoryPermission device_perm) { - R_RETURN(MapDeviceAddressSpaceAligned(das_handle, process_handle, process_address, size, device_address, device_perm)); + Result MapDeviceAddressSpaceAligned64(ams::svc::Handle das_handle, ams::svc::Handle process_handle, uint64_t process_address, ams::svc::Size size, uint64_t device_address, u32 option) { + R_RETURN(MapDeviceAddressSpaceAligned(das_handle, process_handle, process_address, size, device_address, option)); } Result UnmapDeviceAddressSpace64(ams::svc::Handle das_handle, ams::svc::Handle process_handle, uint64_t process_address, ams::svc::Size size, uint64_t device_address) { @@ -202,12 +214,12 @@ namespace ams::kern::svc { R_RETURN(DetachDeviceAddressSpace(device_name, das_handle)); } - Result MapDeviceAddressSpaceByForce64From32(ams::svc::Handle das_handle, ams::svc::Handle process_handle, uint64_t process_address, ams::svc::Size size, uint64_t device_address, ams::svc::MemoryPermission device_perm) { - R_RETURN(MapDeviceAddressSpaceByForce(das_handle, process_handle, process_address, size, device_address, device_perm)); + Result MapDeviceAddressSpaceByForce64From32(ams::svc::Handle das_handle, ams::svc::Handle process_handle, uint64_t process_address, ams::svc::Size size, uint64_t device_address, u32 option) { + R_RETURN(MapDeviceAddressSpaceByForce(das_handle, process_handle, process_address, size, device_address, option)); } - Result MapDeviceAddressSpaceAligned64From32(ams::svc::Handle das_handle, ams::svc::Handle process_handle, uint64_t process_address, ams::svc::Size size, uint64_t device_address, ams::svc::MemoryPermission device_perm) { - R_RETURN(MapDeviceAddressSpaceAligned(das_handle, process_handle, process_address, size, device_address, device_perm)); + Result MapDeviceAddressSpaceAligned64From32(ams::svc::Handle das_handle, ams::svc::Handle process_handle, uint64_t process_address, ams::svc::Size size, uint64_t device_address, u32 option) { + R_RETURN(MapDeviceAddressSpaceAligned(das_handle, process_handle, process_address, size, device_address, option)); } Result UnmapDeviceAddressSpace64From32(ams::svc::Handle das_handle, ams::svc::Handle process_handle, uint64_t process_address, ams::svc::Size size, uint64_t device_address) { diff --git a/libraries/libstratosphere/include/stratosphere/svc/svc_stratosphere_shims.hpp b/libraries/libstratosphere/include/stratosphere/svc/svc_stratosphere_shims.hpp index e0d2db28e..8e34756de 100644 --- a/libraries/libstratosphere/include/stratosphere/svc/svc_stratosphere_shims.hpp +++ b/libraries/libstratosphere/include/stratosphere/svc/svc_stratosphere_shims.hpp @@ -351,12 +351,12 @@ R_RETURN(::svcDetachDeviceAddressSpace(static_cast(device_name), das_handle)); } - ALWAYS_INLINE Result MapDeviceAddressSpaceByForce(::ams::svc::Handle das_handle, ::ams::svc::Handle process_handle, uint64_t process_address, ::ams::svc::Size size, uint64_t device_address, ::ams::svc::MemoryPermission device_perm) { - R_RETURN(::svcMapDeviceAddressSpaceByForce(das_handle, process_handle, process_address, size, device_address, static_cast(device_perm))); + ALWAYS_INLINE Result MapDeviceAddressSpaceByForce(::ams::svc::Handle das_handle, ::ams::svc::Handle process_handle, uint64_t process_address, ::ams::svc::Size size, uint64_t device_address, u32 option) { + R_RETURN(::svcMapDeviceAddressSpaceByForce(das_handle, process_handle, process_address, size, device_address, option)); } - ALWAYS_INLINE Result MapDeviceAddressSpaceAligned(::ams::svc::Handle das_handle, ::ams::svc::Handle process_handle, uint64_t process_address, ::ams::svc::Size size, uint64_t device_address, ::ams::svc::MemoryPermission device_perm) { - R_RETURN(::svcMapDeviceAddressSpaceAligned(das_handle, process_handle, process_address, size, device_address, static_cast(device_perm))); + ALWAYS_INLINE Result MapDeviceAddressSpaceAligned(::ams::svc::Handle das_handle, ::ams::svc::Handle process_handle, uint64_t process_address, ::ams::svc::Size size, uint64_t device_address, u32 option) { + R_RETURN(::svcMapDeviceAddressSpaceAligned(das_handle, process_handle, process_address, size, device_address, option)); } ALWAYS_INLINE Result UnmapDeviceAddressSpace(::ams::svc::Handle das_handle, ::ams::svc::Handle process_handle, uint64_t process_address, ::ams::svc::Size size, uint64_t device_address) { diff --git a/libraries/libstratosphere/source/dd/impl/dd_device_address_space_impl.os.horizon.cpp b/libraries/libstratosphere/source/dd/impl/dd_device_address_space_impl.os.horizon.cpp index 255ed85da..1b62ad835 100644 --- a/libraries/libstratosphere/source/dd/impl/dd_device_address_space_impl.os.horizon.cpp +++ b/libraries/libstratosphere/source/dd/impl/dd_device_address_space_impl.os.horizon.cpp @@ -48,7 +48,7 @@ namespace ams::dd::impl { /* Check alignment. */ AMS_ABORT_UNLESS((process_address & (4_MB - 1)) == (device_address & (4_MB - 1))); - R_TRY_CATCH(svc::MapDeviceAddressSpaceAligned(svc::Handle(handle), svc::Handle(process_handle), process_address, process_size, device_address, static_cast(device_perm))) { + R_TRY_CATCH(svc::MapDeviceAddressSpaceAligned(svc::Handle(handle), svc::Handle(process_handle), process_address, process_size, device_address, svc::MapDeviceAddressSpaceOption::Encode(static_cast(device_perm), svc::MapDeviceAddressSpaceFlag_None))) { R_CONVERT(svc::ResultInvalidHandle, dd::ResultInvalidHandle()) R_CONVERT(svc::ResultOutOfMemory, dd::ResultOutOfMemory()) R_CONVERT(svc::ResultOutOfResource, dd::ResultOutOfResource()) @@ -59,7 +59,7 @@ namespace ams::dd::impl { } Result DeviceAddressSpaceImplByHorizon::MapNotAligned(DeviceAddressSpaceHandle handle, ProcessHandle process_handle, u64 process_address, size_t process_size, DeviceVirtualAddress device_address, dd::MemoryPermission device_perm) { - R_TRY_CATCH(svc::MapDeviceAddressSpaceByForce(svc::Handle(handle), svc::Handle(process_handle), process_address, process_size, device_address, static_cast(device_perm))) { + R_TRY_CATCH(svc::MapDeviceAddressSpaceByForce(svc::Handle(handle), svc::Handle(process_handle), process_address, process_size, device_address, svc::MapDeviceAddressSpaceOption::Encode(static_cast(device_perm), svc::MapDeviceAddressSpaceFlag_None))) { R_CONVERT(svc::ResultInvalidHandle, dd::ResultInvalidHandle()) R_CONVERT(svc::ResultOutOfMemory, dd::ResultOutOfMemory()) R_CONVERT(svc::ResultOutOfResource, dd::ResultOutOfResource()) diff --git a/libraries/libvapours/include/vapours/svc/svc_definition_macro.hpp b/libraries/libvapours/include/vapours/svc/svc_definition_macro.hpp index a69db1627..d4668e445 100644 --- a/libraries/libvapours/include/vapours/svc/svc_definition_macro.hpp +++ b/libraries/libvapours/include/vapours/svc/svc_definition_macro.hpp @@ -103,8 +103,8 @@ HANDLER(0x56, Result, CreateDeviceAddressSpace, OUTPUT(::ams::svc::Handle, out_handle), INPUT(uint64_t, das_address), INPUT(uint64_t, das_size)) \ HANDLER(0x57, Result, AttachDeviceAddressSpace, INPUT(::ams::svc::DeviceName, device_name), INPUT(::ams::svc::Handle, das_handle)) \ HANDLER(0x58, Result, DetachDeviceAddressSpace, INPUT(::ams::svc::DeviceName, device_name), INPUT(::ams::svc::Handle, das_handle)) \ - HANDLER(0x59, Result, MapDeviceAddressSpaceByForce, INPUT(::ams::svc::Handle, das_handle), INPUT(::ams::svc::Handle, process_handle), INPUT(uint64_t, process_address), INPUT(::ams::svc::Size, size), INPUT(uint64_t, device_address), INPUT(::ams::svc::MemoryPermission, device_perm)) \ - HANDLER(0x5A, Result, MapDeviceAddressSpaceAligned, INPUT(::ams::svc::Handle, das_handle), INPUT(::ams::svc::Handle, process_handle), INPUT(uint64_t, process_address), INPUT(::ams::svc::Size, size), INPUT(uint64_t, device_address), INPUT(::ams::svc::MemoryPermission, device_perm)) \ + HANDLER(0x59, Result, MapDeviceAddressSpaceByForce, INPUT(::ams::svc::Handle, das_handle), INPUT(::ams::svc::Handle, process_handle), INPUT(uint64_t, process_address), INPUT(::ams::svc::Size, size), INPUT(uint64_t, device_address), INPUT(uint32_t, option)) \ + HANDLER(0x5A, Result, MapDeviceAddressSpaceAligned, INPUT(::ams::svc::Handle, das_handle), INPUT(::ams::svc::Handle, process_handle), INPUT(uint64_t, process_address), INPUT(::ams::svc::Size, size), INPUT(uint64_t, device_address), INPUT(uint32_t, option)) \ HANDLER(0x5C, Result, UnmapDeviceAddressSpace, INPUT(::ams::svc::Handle, das_handle), INPUT(::ams::svc::Handle, process_handle), INPUT(uint64_t, process_address), INPUT(::ams::svc::Size, size), INPUT(uint64_t, device_address)) \ HANDLER(0x5D, Result, InvalidateProcessDataCache, INPUT(::ams::svc::Handle, process_handle), INPUT(uint64_t, address), INPUT(uint64_t, size)) \ HANDLER(0x5E, Result, StoreProcessDataCache, INPUT(::ams::svc::Handle, process_handle), INPUT(uint64_t, address), INPUT(uint64_t, size)) \ diff --git a/libraries/libvapours/include/vapours/svc/svc_types_common.hpp b/libraries/libvapours/include/vapours/svc/svc_types_common.hpp index d1aa25edf..7dcf7c6c5 100644 --- a/libraries/libvapours/include/vapours/svc/svc_types_common.hpp +++ b/libraries/libvapours/include/vapours/svc/svc_types_common.hpp @@ -137,6 +137,27 @@ namespace ams::svc { MemoryRegionType_Count, }; + enum MapDeviceAddressSpaceFlag : u32 { + MapDeviceAddressSpaceFlag_None = (0 << 0), + MapDeviceAddressSpaceFlag_NotIoRegister = (1 << 0), + }; + + struct MapDeviceAddressSpaceOption { + using Permission = util::BitPack32::Field<0, 16, MemoryPermission>; + using Flags = util::BitPack32::Field; + using Reserved = util::BitPack32::Field; + + static constexpr ALWAYS_INLINE u32 Encode(MemoryPermission perm, u32 flags) { + util::BitPack32 pack{}; + + pack.Set(perm); + pack.Set(static_cast(flags)); + pack.Set(0); + + return pack.value; + } + }; + /* Info Types. */ enum InfoType : u32 { InfoType_CoreMask = 0,